--- /dev/null
+{
+ "rules": {
+ "color-hex-case": [ "lower" ],
+ "color-hex-length": [ "short" ],
+ "color-named": [ "never" ],
+ "color-no-invalid-hex": true,
+
+ "declaration-bang-space-after": [ "never" ],
+ "declaration-bang-space-before": [ "always" ],
+ "declaration-colon-space-after": [ "always" ],
+ "declaration-colon-space-before": [ "never" ],
+
+ "font-family-name-quotes": [ "single-unless-keyword" ],
+ "font-weight-notation": [ "named-where-possible" ],
+
+ "function-calc-no-unspaced-operator": true,
+ "function-comma-newline-after": "never-multi-line",
+ "function-comma-newline-before": "never-multi-line",
+ "function-comma-space-after": [ "always" ],
+ "function-comma-space-before": [ "never" ],
+ "function-parentheses-newline-inside": [ "never-multi-line" ],
+ "function-parentheses-space-inside": [ "always" ],
+ "function-url-quotes": [ "none" ],
+ "function-whitespace-after": [ "always" ],
+ }
+}
{{int:version-credits-summary}}
<!--
-MediaWiki 1.27 is a collaborative project released under the
+MediaWiki 1.28 is a collaborative project released under the
GNU General Public License v2. We would like to recognize the
following names for their contribution to the product.
-->
module.exports = function ( grunt ) {
grunt.loadNpmTasks( 'grunt-contrib-copy' );
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
+ grunt.loadNpmTasks( 'grunt-stylelint' );
grunt.loadNpmTasks( 'grunt-contrib-watch' );
grunt.loadNpmTasks( 'grunt-banana-checker' );
grunt.loadNpmTasks( 'grunt-jscs' );
api: 'includes/api/i18n/',
installer: 'includes/installer/i18n/'
},
+ stylelint: {
+ options: {
+ syntax: 'less'
+ },
+ src: '{resources/src/*,mw-config/**}/*.{css,less}'
+ },
watch: {
files: [
- '.js*',
+ '.{stylelintrc,jscsrc,jshintignore,jshintrc}',
'**/*',
'!{docs,extensions,node_modules,skins,vendor}/**'
],
return !!( process.env.MW_SERVER && process.env.MW_SCRIPT_PATH );
} );
- grunt.registerTask( 'lint', [ 'jshint', 'jscs', 'jsonlint', 'banana' ] );
+ grunt.registerTask( 'lint', [ 'jshint', 'jscs', 'jsonlint', 'banana', 'stylelint' ] );
grunt.registerTask( 'qunit', [ 'assert-mw-env', 'karma:main' ] );
grunt.registerTask( 'test', [ 'lint' ] );
-Change notes from older releases. For current info see RELEASE-NOTES-1.27.
+Change notes from older releases. For current info see RELEASE-NOTES-1.28.
= MediaWiki 1.26 =
* ctype
* iconv
* json
-* mbstring
+* mbstring (new requirement in 1.27)
* xml
The following PHP extensions are strongly recommended:
* openssl
* Removed configuration option $wgCopyrightIcon (deprecated since 1.18). Use
$wgFooterIcons['copyright']['copyright'] instead.
* If the openssl and mcrypt PHP extensions are both unavailable, secure
- session storage (soon to be used for login) will raise an exception. This
- exception may be bypassed by setting $wgSessionInsecureSecrets = true.
+ session storage (used for login) will raise an exception. This exception may
+ be bypassed by setting $wgSessionInsecureSecrets = true.
+* Massive overhaul to authentication:
+** AuthPlugin and AuthPluginUser are deprecated.
+** LoginForm and associated templates are deprecated. Extensions which called
+ static LoginForm methods should be converted into authentication providers.
+** The following hooks are deprecated:
+*** AbortAutoAccount (create a MediaWiki\Auth\PreAuthenticationProvider instead)
+*** AbortLogin (create a MediaWiki\Auth\PreAuthenticationProvider instead)
+*** AbortNewAccount (create a MediaWiki\Auth\PreAuthenticationProvider instead)
+*** AddNewAccount (use LocalUserCreated instead)
+*** AuthPluginSetup (create a MediaWiki\Auth\PrimaryAuthenticationProvider instead)
+*** ChangePasswordForm (use AuthChangeFormFields instead, or security levels)
+*** LoginUserMigrated (create a MediaWiki\Auth\PreAuthenticationProvider instead)
+*** UserCreateForm (create a MediaWiki\Auth\AuthenticationProvider of some type instead)
+*** UserLoginForm (create a MediaWiki\Auth\AuthenticationProvider of some type instead)
+** The following hooks are removed:
+*** AbortChangePassword
+*** LoginPasswordResetMessage
+*** PrefsPasswordAudit
+** The UserLoginComplete hook will no longer be called for all logins, only for
+ those via the web UI. Use UserLoggedIn if you need to do something on all
+ logins.
+** $wgRequirePasswordforEmailChange is removed.
=== New features in 1.27 ===
* $wgDataCenterUpdateStickTTL was also added. This decides how long a user
* $wgJpegPixelFormat was added to override chroma subsampling for JPEG image
thumbnails created via ImageMagick. Defaults to 'yuv420', providing bandwidth
savings versus the previous behavior on many files.
+* MediaWiki\Auth infrastructure (called "AuthManager") allows for more flexible
+ configuration of multiple authentication pieces that was possible with
+ AuthPlugin. For example, it's now easy to plug in second-factor
+ authentication, or add additional checks to the login process, or to support
+ multiple login methods at once, or to support non-password-based login methods.
+** Providers are configured via the global setting $wgAuthManagerConfig.
+** A global, $wgDisableAuthManager, is temporarily available to disable
+ AuthManager until extensions are ready to support it.
+** New hook, AuthChangeFormFields, to adjust the form fields on
+ AuthManager-related special pages.
+** New hook, AuthManagerLoginAuthenticateAudit, for additional logging of
+ AuthManager-related authentication requests.
+** New hook, ChangeAuthenticationDataAudit, for additional logging of
+ AuthManager-related authentication data changes.
+** New hook, SecuritySensitiveOperationStatus, to work with the new mechanism
+ for requiring a recent login before taking security-sensitive operations
+ like changing a password.
+** Two new globals, $wgChangeCredentialsBlacklist and $wgRemoveCredentialsBlacklist
+ can be used to prevent the web UI and the API changing certain authentication data.
+* The file upload dialog (available if you install WikiEditor or VisualEditor)
+ can now be configured using $wgUploadDialog.
=== External library changes in 1.27 ===
merely need to change the username and password used after setting up a bot
password.
* action=upload no longer understands statuskey, asyncdownload or leavemessage.
+* Several changes when $wgDisableAuthManager is false:
+** action=login is deprecated for uses other than bot passwords.
+** list=users can now indicate if a missing username is creatable.
+** action=createaccount is changed in a non-backwards-compatible manner.
+** Added action=query&meta=authmanagerinfo.
+** Added action=clientlogin to be used to log into the main account instead of
+ action=login.
+** Added action=linkaccount.
+** Added action=unlinkaccount.
+** Added action=changeauthenticationdata.
+** Added action=removeauthenticationdata.
+** Added action=resetpassword.
=== Action API internal changes in 1.27 ===
* ApiQueryORM removed.
* ApiMain::addFormat() was removed (deprecated in 1.21).
* ApiMain::getFormats() was removed (deprecated in 1.21).
* ApiPageSet::finishPageSetGeneration() was removed (deprecated in 1.21).
+* ApiCreateAccount is deprecated, and will be removed soon.
=== Languages updated in 1.27 ===
performance on complex changes. $wgExternalDiffEngine = 'wikidiff3' therefore
makes no difference now. Users are still recommended to use wikidiff2 if possible,
though.
+* User::addNewUserLogEntry() was deprecated.
+* User::addNewUserLogEntryAutoCreate() was deprecated.
+* User::isPasswordReminderThrottled() was deprecated.
+* Bot-oriented parameters to Special:UserLogin (wpCookieCheck, wpSkipCookieCheck)
+ were removed.
== Compatibility ==
* The load.php entry point now enforces the existing policy of not allowing
access to session data, which includes the session user and the session
user's language. If such access is attempted, an exception will be thrown.
+* The number of internal PBKDF2 iterations used to derive the session secret
+ is configurable via $wgSessionPbkdf2Iterations.
=== New features in 1.28 ===
-
+* User::isBot() method for checking if an account is a bot role account.
+* Added a new hook, 'UserIsBot', to aid in determining if a user is a bot.
=== External library changes in 1.28 ===
==== Upgraded external libraries ====
-
+* Updated es5-shim from v4.1.5 to v4.5.8
==== New external libraries ====
regularly. Below only new and removed languages are listed, as well as
changes to languages because of Phabricator reports.
-=== Other changes in 1.27 ===
-
+=== Other changes in 1.28 ===
+* (T128697) Improved handling of large diffs.
== Compatibility ==
'AlterSharedConstraints' => __DIR__ . '/maintenance/oracle/alterSharedConstraints.php',
'AncientPagesPage' => __DIR__ . '/includes/specials/SpecialAncientpages.php',
'AnsiTermColorer' => __DIR__ . '/maintenance/term/MWTerm.php',
+ 'ApiAMCreateAccount' => __DIR__ . '/includes/api/ApiAMCreateAccount.php',
+ 'ApiAuthManagerHelper' => __DIR__ . '/includes/api/ApiAuthManagerHelper.php',
'ApiBase' => __DIR__ . '/includes/api/ApiBase.php',
'ApiBlock' => __DIR__ . '/includes/api/ApiBlock.php',
+ 'ApiChangeAuthenticationData' => __DIR__ . '/includes/api/ApiChangeAuthenticationData.php',
'ApiCheckToken' => __DIR__ . '/includes/api/ApiCheckToken.php',
'ApiClearHasMsg' => __DIR__ . '/includes/api/ApiClearHasMsg.php',
+ 'ApiClientLogin' => __DIR__ . '/includes/api/ApiClientLogin.php',
'ApiComparePages' => __DIR__ . '/includes/api/ApiComparePages.php',
'ApiContinuationManager' => __DIR__ . '/includes/api/ApiContinuationManager.php',
'ApiCreateAccount' => __DIR__ . '/includes/api/ApiCreateAccount.php',
'ApiImageRotate' => __DIR__ . '/includes/api/ApiImageRotate.php',
'ApiImport' => __DIR__ . '/includes/api/ApiImport.php',
'ApiImportReporter' => __DIR__ . '/includes/api/ApiImport.php',
+ 'ApiLinkAccount' => __DIR__ . '/includes/api/ApiLinkAccount.php',
'ApiLogin' => __DIR__ . '/includes/api/ApiLogin.php',
'ApiLogout' => __DIR__ . '/includes/api/ApiLogout.php',
'ApiMain' => __DIR__ . '/includes/api/ApiMain.php',
'ApiQueryAllPages' => __DIR__ . '/includes/api/ApiQueryAllPages.php',
'ApiQueryAllRevisions' => __DIR__ . '/includes/api/ApiQueryAllRevisions.php',
'ApiQueryAllUsers' => __DIR__ . '/includes/api/ApiQueryAllUsers.php',
+ 'ApiQueryAuthManagerInfo' => __DIR__ . '/includes/api/ApiQueryAuthManagerInfo.php',
'ApiQueryBacklinks' => __DIR__ . '/includes/api/ApiQueryBacklinks.php',
'ApiQueryBacklinksprop' => __DIR__ . '/includes/api/ApiQueryBacklinksprop.php',
'ApiQueryBase' => __DIR__ . '/includes/api/ApiQueryBase.php',
'ApiQueryWatchlist' => __DIR__ . '/includes/api/ApiQueryWatchlist.php',
'ApiQueryWatchlistRaw' => __DIR__ . '/includes/api/ApiQueryWatchlistRaw.php',
'ApiRawMessage' => __DIR__ . '/includes/api/ApiMessage.php',
+ 'ApiRemoveAuthenticationData' => __DIR__ . '/includes/api/ApiRemoveAuthenticationData.php',
+ 'ApiResetPassword' => __DIR__ . '/includes/api/ApiResetPassword.php',
'ApiResult' => __DIR__ . '/includes/api/ApiResult.php',
'ApiRevisionDelete' => __DIR__ . '/includes/api/ApiRevisionDelete.php',
'ApiRollback' => __DIR__ . '/includes/api/ApiRollback.php',
'AtomFeed' => __DIR__ . '/includes/Feed.php',
'AtomicSectionUpdate' => __DIR__ . '/includes/deferred/AtomicSectionUpdate.php',
'AttachLatest' => __DIR__ . '/maintenance/attachLatest.php',
+ 'AuthManagerSpecialPage' => __DIR__ . '/includes/specialpage/AuthManagerSpecialPage.php',
'AuthPlugin' => __DIR__ . '/includes/AuthPlugin.php',
'AuthPluginUser' => __DIR__ . '/includes/AuthPlugin.php',
'AutoLoader' => __DIR__ . '/includes/AutoLoader.php',
'BacklinkJobUtils' => __DIR__ . '/includes/jobqueue/utils/BacklinkJobUtils.php',
'BackupDumper' => __DIR__ . '/maintenance/backup.inc',
'BackupReader' => __DIR__ . '/maintenance/importDump.php',
+ 'BadRequestError' => __DIR__ . '/includes/exception/BadRequestError.php',
'BadTitleError' => __DIR__ . '/includes/exception/BadTitleError.php',
'BagOStuff' => __DIR__ . '/includes/libs/objectcache/BagOStuff.php',
'BaseDump' => __DIR__ . '/maintenance/backupPrefetch.inc',
'BitmapMetadataHandler' => __DIR__ . '/includes/media/BitmapMetadataHandler.php',
'Blob' => __DIR__ . '/includes/db/DatabaseUtility.php',
'Block' => __DIR__ . '/includes/Block.php',
+ 'BlockLevelPass' => __DIR__ . '/includes/parser/BlockLevelPass.php',
'BlockListPager' => __DIR__ . '/includes/specials/pagers/BlockListPager.php',
'BlockLogFormatter' => __DIR__ . '/includes/logging/BlockLogFormatter.php',
'BmpHandler' => __DIR__ . '/includes/media/BMP.php',
'DerivativeResourceLoaderContext' => __DIR__ . '/includes/resourceloader/DerivativeResourceLoaderContext.php',
'DescribeFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'Diff' => __DIR__ . '/includes/diff/DairikiDiff.php',
- 'DiffEngine' => __DIR__ . '/includes/diff/DairikiDiff.php',
+ 'DiffEngine' => __DIR__ . '/includes/diff/DiffEngine.php',
'DiffFormatter' => __DIR__ . '/includes/diff/DiffFormatter.php',
'DiffHistoryBlob' => __DIR__ . '/includes/HistoryBlob.php',
'DiffOp' => __DIR__ . '/includes/diff/DairikiDiff.php',
'FSFileOpHandle' => __DIR__ . '/includes/filebackend/FSFileBackend.php',
'FSLockManager' => __DIR__ . '/includes/filebackend/lockmanager/FSLockManager.php',
'FSRepo' => __DIR__ . '/includes/filerepo/FSRepo.php',
+ 'FakeAuthTemplate' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
'FakeConverter' => __DIR__ . '/languages/FakeConverter.php',
'FakeMaintenance' => __DIR__ . '/maintenance/Maintenance.php',
'FakeResultWrapper' => __DIR__ . '/includes/db/DatabaseUtility.php',
'HistoryPager' => __DIR__ . '/includes/actions/HistoryAction.php',
'Hooks' => __DIR__ . '/includes/Hooks.php',
'Html' => __DIR__ . '/includes/Html.php',
+ 'HtmlArmor' => __DIR__ . '/includes/libs/HtmlArmor.php',
'HtmlFormatter' => __DIR__ . '/includes/HtmlFormatter.php',
'Http' => __DIR__ . '/includes/HttpFunctions.php',
'HttpError' => __DIR__ . '/includes/exception/HttpError.php',
'LogPager' => __DIR__ . '/includes/logging/LogPager.php',
'LoggedOutEditToken' => __DIR__ . '/includes/user/LoggedOutEditToken.php',
'LoggedUpdateMaintenance' => __DIR__ . '/maintenance/Maintenance.php',
- 'LoginForm' => __DIR__ . '/includes/specials/SpecialUserlogin.php',
+ 'LoginForm' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
+ 'LoginFormAuthManager' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
+ 'LoginFormPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialUserlogin.php',
+ 'LoginHelper' => __DIR__ . '/includes/specials/helpers/LoginHelper.php',
+ 'LoginSignupSpecialPage' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
'LonelyPagesPage' => __DIR__ . '/includes/specials/SpecialLonelypages.php',
'LongPagesPage' => __DIR__ . '/includes/specials/SpecialLongpages.php',
'MIMEsearchPage' => __DIR__ . '/includes/specials/SpecialMIMEsearch.php',
'MagicWord' => __DIR__ . '/includes/MagicWord.php',
'MagicWordArray' => __DIR__ . '/includes/MagicWordArray.php',
'MailAddress' => __DIR__ . '/includes/mail/MailAddress.php',
+ 'MainConfigDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
'Maintenance' => __DIR__ . '/maintenance/Maintenance.php',
'MaintenanceFormatInstallDoc' => __DIR__ . '/maintenance/formatInstallDoc.php',
'MakeTestEdits' => __DIR__ . '/maintenance/makeTestEdits.php',
'MalformedTitleException' => __DIR__ . '/includes/title/MalformedTitleException.php',
'ManualLogEntry' => __DIR__ . '/includes/logging/LogEntry.php',
'MapCacheLRU' => __DIR__ . '/includes/libs/MapCacheLRU.php',
- 'MappedDiff' => __DIR__ . '/includes/diff/DairikiDiff.php',
'MappedIterator' => __DIR__ . '/includes/libs/MappedIterator.php',
'MarkpatrolledAction' => __DIR__ . '/includes/actions/MarkpatrolledAction.php',
'McTest' => __DIR__ . '/maintenance/mctest.php',
'MediaWikiSite' => __DIR__ . '/includes/site/MediaWikiSite.php',
'MediaWikiTitleCodec' => __DIR__ . '/includes/title/MediaWikiTitleCodec.php',
'MediaWikiVersionFetcher' => __DIR__ . '/includes/MediaWikiVersionFetcher.php',
+ 'MediaWiki\\Auth\\AbstractAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\AbstractPasswordPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractPasswordPrimaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\AbstractPreAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractPreAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\AbstractPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractPrimaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\AbstractSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/AbstractSecondaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\AuthManager' => __DIR__ . '/includes/auth/AuthManager.php',
+ 'MediaWiki\\Auth\\AuthManagerAuthPlugin' => __DIR__ . '/includes/auth/AuthManagerAuthPlugin.php',
+ 'MediaWiki\\Auth\\AuthManagerAuthPluginUser' => __DIR__ . '/includes/auth/AuthManagerAuthPlugin.php',
+ 'MediaWiki\\Auth\\AuthPluginPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/AuthPluginPrimaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\AuthenticationProvider' => __DIR__ . '/includes/auth/AuthenticationProvider.php',
+ 'MediaWiki\\Auth\\AuthenticationRequest' => __DIR__ . '/includes/auth/AuthenticationRequest.php',
+ 'MediaWiki\\Auth\\AuthenticationResponse' => __DIR__ . '/includes/auth/AuthenticationResponse.php',
+ 'MediaWiki\\Auth\\ButtonAuthenticationRequest' => __DIR__ . '/includes/auth/ButtonAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/CheckBlocksSecondaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\ConfirmLinkAuthenticationRequest' => __DIR__ . '/includes/auth/ConfirmLinkAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\ConfirmLinkSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/ConfirmLinkSecondaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\CreateFromLoginAuthenticationRequest' => __DIR__ . '/includes/auth/CreateFromLoginAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\CreatedAccountAuthenticationRequest' => __DIR__ . '/includes/auth/CreatedAccountAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\CreationReasonAuthenticationRequest' => __DIR__ . '/includes/auth/CreationReasonAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/EmailNotificationSecondaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\LegacyHookPreAuthenticationProvider' => __DIR__ . '/includes/auth/LegacyHookPreAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/LocalPasswordPrimaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\PasswordAuthenticationRequest' => __DIR__ . '/includes/auth/PasswordAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\PasswordDomainAuthenticationRequest' => __DIR__ . '/includes/auth/PasswordDomainAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\PreAuthenticationProvider' => __DIR__ . '/includes/auth/PreAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\PrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/PrimaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\RememberMeAuthenticationRequest' => __DIR__ . '/includes/auth/RememberMeAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/ResetPasswordSecondaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\SecondaryAuthenticationProvider' => __DIR__ . '/includes/auth/SecondaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest' => __DIR__ . '/includes/auth/TemporaryPasswordAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => __DIR__ . '/includes/auth/TemporaryPasswordPrimaryAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => __DIR__ . '/includes/auth/ThrottlePreAuthenticationProvider.php',
+ 'MediaWiki\\Auth\\Throttler' => __DIR__ . '/includes/auth/Throttler.php',
+ 'MediaWiki\\Auth\\UserDataAuthenticationRequest' => __DIR__ . '/includes/auth/UserDataAuthenticationRequest.php',
+ 'MediaWiki\\Auth\\UsernameAuthenticationRequest' => __DIR__ . '/includes/auth/UsernameAuthenticationRequest.php',
+ 'MediaWiki\\Diff\\ComplexityException' => __DIR__ . '/includes/diff/ComplexityException.php',
+ 'MediaWiki\\Diff\\WordAccumulator' => __DIR__ . '/includes/diff/WordAccumulator.php',
+ 'MediaWiki\\Interwiki\\ClassicInterwikiLookup' => __DIR__ . '/includes/interwiki/ClassicInterwikiLookup.php',
+ 'MediaWiki\\Interwiki\\InterwikiLookup' => __DIR__ . '/includes/interwiki/InterwikiLookup.php',
'MediaWiki\\Languages\\Data\\Names' => __DIR__ . '/languages/data/Names.php',
'MediaWiki\\Languages\\Data\\ZhConversion' => __DIR__ . '/languages/data/ZhConversion.php',
+ 'MediaWiki\\Linker\\LinkRenderer' => __DIR__ . '/includes/linker/LinkRenderer.php',
+ 'MediaWiki\\Linker\\LinkRendererFactory' => __DIR__ . '/includes/linker/LinkRendererFactory.php',
'MediaWiki\\Linker\\LinkTarget' => __DIR__ . '/includes/linker/LinkTarget.php',
'MediaWiki\\Logger\\LegacyLogger' => __DIR__ . '/includes/debug/logger/LegacyLogger.php',
'MediaWiki\\Logger\\LegacySpi' => __DIR__ . '/includes/debug/logger/LegacySpi.php',
'MediaWiki\\Services\\ContainerDisabledException' => __DIR__ . '/includes/Services/ContainerDisabledException.php',
'MediaWiki\\Services\\DestructibleService' => __DIR__ . '/includes/Services/DestructibleService.php',
'MediaWiki\\Services\\NoSuchServiceException' => __DIR__ . '/includes/Services/NoSuchServiceException.php',
+ 'MediaWiki\\Services\\SalvageableService' => __DIR__ . '/includes/Services/SalvageableService.php',
'MediaWiki\\Services\\ServiceAlreadyDefinedException' => __DIR__ . '/includes/Services/ServiceAlreadyDefinedException.php',
'MediaWiki\\Services\\ServiceContainer' => __DIR__ . '/includes/Services/ServiceContainer.php',
'MediaWiki\\Services\\ServiceDisabledException' => __DIR__ . '/includes/Services/ServiceDisabledException.php',
'PasswordError' => __DIR__ . '/includes/password/PasswordError.php',
'PasswordFactory' => __DIR__ . '/includes/password/PasswordFactory.php',
'PasswordPolicyChecks' => __DIR__ . '/includes/password/PasswordPolicyChecks.php',
+ 'PasswordReset' => __DIR__ . '/includes/user/PasswordReset.php',
'PatchSql' => __DIR__ . '/maintenance/patchSql.php',
'PathRouter' => __DIR__ . '/includes/PathRouter.php',
'PathRouterPatternReplacer' => __DIR__ . '/includes/PathRouter.php',
'RCFeedFormatter' => __DIR__ . '/includes/rcfeed/RCFeedFormatter.php',
'RSSFeed' => __DIR__ . '/includes/Feed.php',
'RandomPage' => __DIR__ . '/includes/specials/SpecialRandompage.php',
- 'RangeDifference' => __DIR__ . '/includes/diff/WikiDiff3.php',
+ 'RangeDifference' => __DIR__ . '/includes/diff/DiffEngine.php',
'RawAction' => __DIR__ . '/includes/actions/RawAction.php',
'RawMessage' => __DIR__ . '/includes/Message.php',
'ReadOnlyError' => __DIR__ . '/includes/exception/ReadOnlyError.php',
'ResourceLoaderSkinModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSkinModule.php',
'ResourceLoaderSpecialCharacterDataModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSpecialCharacterDataModule.php',
'ResourceLoaderStartUpModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderStartUpModule.php',
+ 'ResourceLoaderUploadDialogModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUploadDialogModule.php',
'ResourceLoaderUserCSSPrefsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php',
'ResourceLoaderUserDefaultsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserDefaultsModule.php',
- 'ResourceLoaderUserGroupsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserGroupsModule.php',
'ResourceLoaderUserModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserModule.php',
'ResourceLoaderUserOptionsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserOptionsModule.php',
'ResourceLoaderUserTokensModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserTokensModule.php',
'SavepointPostgres' => __DIR__ . '/includes/db/DatabasePostgres.php',
'ScopedCallback' => __DIR__ . '/includes/libs/ScopedCallback.php',
'ScopedLock' => __DIR__ . '/includes/filebackend/lockmanager/ScopedLock.php',
+ 'SearchApi' => __DIR__ . '/includes/api/SearchApi.php',
'SearchDatabase' => __DIR__ . '/includes/search/SearchDatabase.php',
'SearchDump' => __DIR__ . '/maintenance/dumpIterator.php',
'SearchEngine' => __DIR__ . '/includes/search/SearchEngine.php',
'SpecialCachedPage' => __DIR__ . '/includes/specials/SpecialCachedPage.php',
'SpecialCategories' => __DIR__ . '/includes/specials/SpecialCategories.php',
'SpecialChangeContentModel' => __DIR__ . '/includes/specials/SpecialChangeContentModel.php',
+ 'SpecialChangeCredentials' => __DIR__ . '/includes/specials/SpecialChangeCredentials.php',
'SpecialChangeEmail' => __DIR__ . '/includes/specials/SpecialChangeEmail.php',
+ 'SpecialChangeEmailPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialChangeEmail.php',
'SpecialChangePassword' => __DIR__ . '/includes/specials/SpecialChangePassword.php',
+ 'SpecialChangePasswordPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialChangePassword.php',
'SpecialComparePages' => __DIR__ . '/includes/specials/SpecialComparePages.php',
'SpecialContributions' => __DIR__ . '/includes/specials/SpecialContributions.php',
'SpecialCreateAccount' => __DIR__ . '/includes/specials/SpecialCreateAccount.php',
+ 'SpecialCreateAccountPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialCreateAccount.php',
'SpecialDiff' => __DIR__ . '/includes/specials/SpecialDiff.php',
'SpecialEditTags' => __DIR__ . '/includes/specials/SpecialEditTags.php',
'SpecialEditWatchlist' => __DIR__ . '/includes/specials/SpecialEditWatchlist.php',
'SpecialFilepath' => __DIR__ . '/includes/specials/SpecialFilepath.php',
'SpecialImport' => __DIR__ . '/includes/specials/SpecialImport.php',
'SpecialJavaScriptTest' => __DIR__ . '/includes/specials/SpecialJavaScriptTest.php',
+ 'SpecialLinkAccounts' => __DIR__ . '/includes/specials/SpecialLinkAccounts.php',
'SpecialListAdmins' => __DIR__ . '/includes/specials/SpecialListusers.php',
'SpecialListBots' => __DIR__ . '/includes/specials/SpecialListusers.php',
'SpecialListFiles' => __DIR__ . '/includes/specials/SpecialListfiles.php',
'SpecialPageLanguage' => __DIR__ . '/includes/specials/SpecialPageLanguage.php',
'SpecialPagesWithProp' => __DIR__ . '/includes/specials/SpecialPagesWithProp.php',
'SpecialPasswordReset' => __DIR__ . '/includes/specials/SpecialPasswordReset.php',
+ 'SpecialPasswordResetPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialPasswordReset.php',
'SpecialPermanentLink' => __DIR__ . '/includes/specials/SpecialPermanentLink.php',
'SpecialPreferences' => __DIR__ . '/includes/specials/SpecialPreferences.php',
'SpecialPrefixindex' => __DIR__ . '/includes/specials/SpecialPrefixindex.php',
'SpecialRecentChangesLinked' => __DIR__ . '/includes/specials/SpecialRecentchangeslinked.php',
'SpecialRedirect' => __DIR__ . '/includes/specials/SpecialRedirect.php',
'SpecialRedirectToSpecial' => __DIR__ . '/includes/specialpage/RedirectSpecialPage.php',
+ 'SpecialRemoveCredentials' => __DIR__ . '/includes/specials/SpecialRemoveCredentials.php',
'SpecialResetTokens' => __DIR__ . '/includes/specials/SpecialResetTokens.php',
'SpecialRevisionDelete' => __DIR__ . '/includes/specials/SpecialRevisiondelete.php',
'SpecialRunJobs' => __DIR__ . '/includes/specials/SpecialRunJobs.php',
'SpecialTrackingCategories' => __DIR__ . '/includes/specials/SpecialTrackingCategories.php',
'SpecialUnblock' => __DIR__ . '/includes/specials/SpecialUnblock.php',
'SpecialUndelete' => __DIR__ . '/includes/specials/SpecialUndelete.php',
+ 'SpecialUnlinkAccounts' => __DIR__ . '/includes/specials/SpecialUnlinkAccounts.php',
'SpecialUnlockdb' => __DIR__ . '/includes/specials/SpecialUnlockdb.php',
'SpecialUpload' => __DIR__ . '/includes/specials/SpecialUpload.php',
'SpecialUploadStash' => __DIR__ . '/includes/specials/SpecialUploadStash.php',
'SpecialUploadStashTooLargeException' => __DIR__ . '/includes/specials/SpecialUploadStash.php',
- 'SpecialUserlogout' => __DIR__ . '/includes/specials/SpecialUserlogout.php',
+ 'SpecialUserLogin' => __DIR__ . '/includes/specials/SpecialUserLogin.php',
+ 'SpecialUserLogout' => __DIR__ . '/includes/specials/SpecialUserLogout.php',
+ 'SpecialUserlogoutPreAuthManager' => __DIR__ . '/includes/specials/pre-authmanager/SpecialUserlogout.php',
'SpecialVersion' => __DIR__ . '/includes/specials/SpecialVersion.php',
'SpecialWatchlist' => __DIR__ . '/includes/specials/SpecialWatchlist.php',
'SpecialWhatLinksHere' => __DIR__ . '/includes/specials/SpecialWhatlinkshere.php',
'WebRequestUpload' => __DIR__ . '/includes/WebRequestUpload.php',
'WebResponse' => __DIR__ . '/includes/WebResponse.php',
'WikiCategoryPage' => __DIR__ . '/includes/page/WikiCategoryPage.php',
- 'WikiDiff3' => __DIR__ . '/includes/diff/WikiDiff3.php',
'WikiExporter' => __DIR__ . '/includes/export/WikiExporter.php',
'WikiFilePage' => __DIR__ . '/includes/page/WikiFilePage.php',
'WikiImporter' => __DIR__ . '/includes/import/WikiImporter.php',
'WikitextContentHandler' => __DIR__ . '/includes/content/WikitextContentHandler.php',
'WinCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/WinCacheBagOStuff.php',
'WithoutInterwikiPage' => __DIR__ . '/includes/specials/SpecialWithoutinterwiki.php',
- 'WordLevelDiff' => __DIR__ . '/includes/diff/DairikiDiff.php',
+ 'WordLevelDiff' => __DIR__ . '/includes/diff/WordLevelDiff.php',
'WrapOldPasswords' => __DIR__ . '/maintenance/wrapOldPasswords.php',
'XCFHandler' => __DIR__ . '/includes/media/XCF.php',
'XCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/XCacheBagOStuff.php',
'XMPReader' => __DIR__ . '/includes/media/XMP.php',
'XMPValidate' => __DIR__ . '/includes/media/XMPValidate.php',
'Xhprof' => __DIR__ . '/includes/libs/Xhprof.php',
+ 'XhprofData' => __DIR__ . '/includes/libs/XhprofData.php',
'Xml' => __DIR__ . '/includes/Xml.php',
'XmlDumpWriter' => __DIR__ . '/includes/export/XmlDumpWriter.php',
'XmlJsCode' => __DIR__ . '/includes/Xml.php',
"ext-xml": "*",
"liuggio/statsd-php-client": "1.0.18",
"mediawiki/at-ease": "1.1.0",
- "oojs/oojs-ui": "0.17.1",
+ "oojs/oojs-ui": "0.17.4",
"oyejorge/less.php": "1.7.0.10",
"php": ">=5.5.9",
"psr/log": "1.0.0",
"wikimedia/assert": "0.2.2",
"wikimedia/base-convert": "1.0.1",
- "wikimedia/cdb": "1.4.0",
+ "wikimedia/cdb": "1.4.1",
"wikimedia/cldr-plural-rule-parser": "1.0.0",
"wikimedia/composer-merge-plugin": "1.3.1",
"wikimedia/html-formatter": "1.0.1",
"require-dev": {
"jakub-onderka/php-parallel-lint": "0.9.2",
"justinrainbow/json-schema": "~1.3",
- "mediawiki/mediawiki-codesniffer": "0.6.0",
+ "mediawiki/mediawiki-codesniffer": "0.7.2",
"monolog/monolog": "~1.18.2",
"nikic/php-parser": "1.4.1",
"nmred/kafka-php": "0.1.5",
"type": "object",
"description": "Registry of factory functions to create Config objects"
},
+ "SessionProviders": {
+ "type": "object",
+ "description": "Session providers"
+ },
+ "AuthManagerAutoConfig": {
+ "type": "object",
+ "description": "AuthManager auto-configuration",
+ "additionalProperties": false,
+ "properties": {
+ "preauth": {
+ "type": "object",
+ "description": "Pre-authentication providers"
+ },
+ "primaryauth": {
+ "type": "object",
+ "description": "Primary authentication providers"
+ },
+ "secondaryauth": {
+ "type": "object",
+ "description": "Secondary authentication providers"
+ }
+ }
+ },
"CentralIdLookupProviders": {
"type": "object",
"description": "Central ID lookup providers"
This is a list of known events and parameters; please add to it if you're going
to add events to the MediaWiki code.
-'AbortAutoAccount': Return false to cancel automated local account creation,
-where normally authentication against an external auth plugin would be creating
-a local account.
+'AbortAutoAccount': DEPRECATED! Create a PreAuthenticationProvider instead.
+Return false to cancel automated local account creation, where normally
+authentication against an external auth plugin would be creating a local
+account.
$user: the User object about to be created (read-only, incomplete)
&$abortMsg: out parameter: name of error message to be displayed to user
$autoblockip: The IP going to be autoblocked.
&$block: The block from which the autoblock is coming.
-'AbortChangePassword': Return false to cancel password change.
-$user: the User object to which the password change is occuring
-$mOldpass: the old password provided by the user
-$newpass: the new password provided by the user
-&$abortMsg: the message identifier for abort reason
-
'AbortDiffCache': Can be used to cancel the caching of a diff.
&$diffEngine: DifferenceEngine object
$title: The Title of the page that was edited.
$rc: The current RecentChange object.
-'AbortLogin': Return false to cancel account login.
+'AbortLogin': DEPRECATED! Create a PreAuthenticationProvider instead.
+Return false to cancel account login.
$user: the User object being authenticated against
$password: the password being submitted, not yet checked for validity
&$retval: a LoginForm class constant to return from authenticateUserData();
&$msg: the message identifier for abort reason (new in 1.18, not available
before 1.18)
-'AbortNewAccount': Return false to cancel explicit account creation.
+'AbortNewAccount': DEPRECATED! Create a PreAuthenticationProvider instead.
+Return false to cancel explicit account creation.
$user: the User object about to be created (read-only, incomplete)
&$msg: out parameter: HTML to display on abort
&$status: out parameter: Status object to return, replaces the older $msg param
&$fields: HTMLForm descriptor array
$article: Article object
-'AddNewAccount': After a user account is created.
+'AddNewAccount': DEPRECATED! Use LocalUserCreated.
+After a user account is created.
$user: the User object that was created. (Parameter added in 1.7)
$byEmail: true when account was created "by email" (added in 1.12)
redirect was followed.
&$article: target article (object)
+'AuthChangeFormFields': After converting a field information array obtained
+from a set of AuthenticationRequest classes into a form descriptor; hooks
+can tweak the array to change how login etc. forms should look.
+$requests: array of AuthenticationRequests the fields are created from
+$fieldInfo: field information array (union of all AuthenticationRequest::getFieldInfo() responses).
+&$formDescriptor: HTMLForm descriptor. The special key 'weight' can be set
+ to change the order of the fields.
+$action: one of the AuthManager::ACTION_* constants.
+
+'AuthManagerLoginAuthenticateAudit': A login attempt either succeeded or failed
+for a reason other than misconfiguration or session loss. No return data is
+accepted; this hook is for auditing only.
+$response: The MediaWiki\Auth\AuthenticationResponse in either a PASS or FAIL state.
+$user: The User object being authenticated against, or null if authentication
+ failed before getting that far.
+$username: A guess at the user name being authenticated, or null if we can't
+ even determine that.
+
'AuthPluginAutoCreate': DEPRECATED! Use the 'LocalUserCreated' hook instead.
Called when creating a local account for an user logged in from an external
authentication method.
$user: User object created locally
-'AuthPluginSetup': Update or replace authentication plugin object ($wgAuth).
-Gives a chance for an extension to set it programmatically to a variable class.
+'AuthPluginSetup': DEPRECATED! Extensions should be updated to use AuthManager.
+Update or replace authentication plugin object ($wgAuth). Gives a chance for an
+extension to set it programmatically to a variable class.
&$auth: the $wgAuth object, probably a stub
'AutopromoteCondition': Check autopromote condition for user.
&$link: Returned value. When set to a non-null value by a hook subscriber
this value will be used as the anchor instead of Linker::link
-'ChangePasswordForm': For extensions that need to add a field to the
-ChangePassword form via the Preferences form.
+'ChangeAuthenticationDataAudit': Called when user changes his password.
+No return data is accepted; this hook is for auditing only.
+$req: AuthenticationRequest object describing the change (and target user)
+$status: StatusValue with the result of the action
+
+'ChangePasswordForm': DEPRECATED! Use AuthChangeFormFields or security levels.
+For extensions that need to add a field to the ChangePassword form via the
+Preferences form.
&$extraFields: An array of arrays that hold fields like would be passed to the
pretty function.
$out: The output page.
$cssClassName: CSS class name of the language selector.
-'LinkBegin': Used when generating internal and interwiki links in
+'LinkBegin': DEPRECATED! Use HtmlPageLinkRendererBegin instead.
+Used when generating internal and interwiki links in
Linker::link(), before processing starts. Return false to skip default
processing and return $ret. See documentation for Linker::link() for details on
the expected meanings of parameters.
&$options: array of options. Can include 'known', 'broken', 'noclasses'.
&$ret: the value to return if your hook returns false.
-'LinkEnd': Used when generating internal and interwiki links in Linker::link(),
+'LinkEnd': DEPRECATED! Use HtmlPageLinkRendererEnd hook instead
+Used when generating internal and interwiki links in Linker::link(),
just before the function returns a value. If you return true, an <a> element
with HTML attributes $attribs and contents $html will be returned. If you
return false, $ret will be returned.
&$attribs: the attributes to be applied
&$ret: the value to return if your hook returns false
+'LinkRendererBegin':
+Used when generating internal and interwiki links in
+LinkRenderer, before processing starts. Return false to skip default
+processing and return $ret.
+$linkRenderer: the LinkRenderer object
+$target: the LinkTarget that the link is pointing to
+&$html: the contents that the <a> tag should have (raw HTML); null means
+ "default".
+&$customAttribs: the HTML attributes that the <a> tag should have, in
+ associative array form, with keys and values unescaped. Should be merged
+ with default values, with a value of false meaning to suppress the
+ attribute.
+&$query: the query string to add to the generated URL (the bit after the "?"),
+ in associative array form, with keys and values unescaped.
+&$ret: the value to return if your hook returns false.
+
+'LinkRendererEnd':
+Used when generating internal and interwiki links in LinkRenderer,
+just before the function returns a value. If you return true, an <a> element
+with HTML attributes $attribs and contents $html will be returned. If you
+return false, $ret will be returned.
+$linkRenderer: the LinkRenderer object
+$target: the LinkTarget object that the link is pointing to
+$isKnown: boolean indicating whether the page is known or not
+&$html: the final (raw HTML) contents of the <a> tag, after processing.
+&$attribs: the final HTML attributes of the <a> tag, after processing, in
+ associative array form.
+&$ret: the value to return if your hook returns false.
+
'LinksUpdate': At the beginning of LinksUpdate::doUpdate() just before the
actual update.
&$linksUpdate: the LinksUpdate object
&$messages: Already added messages (inclusive messages from
LoginForm::$validErrorMessages)
-'LoginPasswordResetMessage': User is being requested to reset their password on
-login. Use this hook to change the Message that will be output on
-Special:ChangePassword.
-&$msg: Message object that will be shown to the user
-$username: Username of the user who's password was expired.
-
-'LoginUserMigrated': Called during login to allow extensions the opportunity to
-inform a user that their username doesn't exist for a specific reason, instead
-of letting the login form give the generic error message that the account does
-not exist. For example, when the account has been renamed or deleted.
+'LoginUserMigrated': DEPRECATED! Create a PreAuthenticationProvider instead.
+Called during login to allow extensions the opportunity to inform a user that
+their username doesn't exist for a specific reason, instead of letting the
+login form give the generic error message that the account does not exist. For
+example, when the account has been renamed or deleted.
$user: the User object being authenticated against.
&$msg: the message identifier for abort reason, or an array to pass a message
key and parameters.
since the last visit.
&$modifiedTimes: array of timestamps.
The following keys are set: page, user, epoch
+$out: OutputPage object (since 1.28)
'OutputPageMakeCategoryLinks': Links are about to be generated for the page's
categories. Implementations should return false if they generate the category
$oldaddr: old email address (string)
$newaddr: new email address (string)
-'PrefsPasswordAudit': Called when user changes his password.
-$user: User (object) changing his password
-$newPass: new password
-$error: error (string) 'badretype', 'wrongpassword', 'error' or 'success'
-
'ProtectionForm::buildForm': Called after all protection type fieldsets are made
in the form.
$article: the title being (un)protected
&$skin: A variable reference you may set a Skin instance or string key on to
override the skin that will be used for the context.
+'RequestHasSameOriginSecurity': Called to determine if the request is somehow
+flagged to lack same-origin security. Return false to indicate the lack. Note
+if the "somehow" involves HTTP headers, you'll probably need to make sure
+the header is varied on.
+WebRequest $request: The request.
+
'ResetPasswordExpiration': Allow extensions to set a default password expiration
$user: The user having their password expiration reset
&$newExpire: The new expiration date
&$updates: a list of DataUpdate objects, to be modified or replaced by
the hook handler.
+'SecuritySensitiveOperationStatus': Affect the return value from
+MediaWiki\Auth\AuthManager::securitySensitiveOperationStatus().
+&$status: (string) The status to be returned. One of the AuthManager::SEC_*
+ constants. SEC_REAUTH will be automatically changed to SEC_FAIL if
+ authentication isn't possible for the current session type.
+$operation: (string) The operation being checked.
+$session: (MediaWiki\Session\Session) The current session. The
+ currently-authenticated user may be retrieved as $session->getUser().
+$timeSinceAuth: (int) The time since last authentication. PHP_INT_MAX if
+ the time of last auth is unknown, or -1 if authentication is not possible.
+
'SelfLinkBegin': Called before a link to the current article is displayed to
allow the display of the link to be customized.
$nt: the Title object
representing the problem with the file, where the first element is the message
key and the remaining elements are used as parameters to the message.
+'UserIsBot': when determining whether a user is a bot account
+$user: the user
+&$isBot: whether this is user a bot or not (boolean)
+
'User::mailPasswordInternal': before creation and mailing of a user's new
temporary password
&$user: the user who sent the message out
&$user: User (object) that will clear the message
$oldid: ID of the talk page revision being viewed (0 means the most recent one)
-'UserCreateForm': change to manipulate the login form
+'UserCreateForm': DEPRECATED! Create an AuthenticationProvider instead.
+Manipulate the login form.
&$template: SimpleTemplate instance for the form
'UserEffectiveGroups': Called in User::getEffectiveGroups().
'UserLoggedIn': Called after a user is logged in
$user: User object for the logged-in user
-'UserLoginComplete': After a user has logged in.
+'UserLoginComplete': Show custom content after a user has logged in via the web interface.
+For functionality that needs to run after any login (API or web) use UserLoggedIn.
&$user: the user object that was created on login
&$inject_html: Any HTML to inject after the "logged in" message.
-'UserLoginForm': change to manipulate the login form
-&$template: SimpleTemplate instance for the form
+'UserLoginForm': DEPRECATED! Create an AuthenticationProvider instead.
+Manipulate the login form.
+&$template: QuickTemplate instance for the form
'UserLogout': Before a user logs out.
&$user: the user object that is about to be logged out
* accounts authenticate externally, or use it only as a fallback; also
* you can transparently create internal wiki accounts the first time
* someone logs in who can be authenticated externally.
+ *
+ * @deprecated since 1.27
*/
class AuthPlugin {
/**
}
}
+/**
+ * @deprecated since 1.27
+ */
class AuthPluginUser {
function __construct( $user ) {
# Override this!
return false;
}
+ /**
+ * @deprecated since 1.28, use SessionManager::invalidateSessionForUser() instead.
+ */
public function resetAuthToken() {
# Override this!
return true;
# and should not be kept, and 2) we *probably* don't have to scan many
# rows to obtain the correct figure, so let's risk a one-time recount.
if ( $this->mPages < 0 || $this->mSubcats < 0 || $this->mFiles < 0 ) {
- $this->refreshCounts();
+ $this->mPages = max( $this->mPages, 0 );
+ $this->mSubcats = max( $this->mSubcats, 0 );
+ $this->mFiles = max( $this->mFiles, 0 );
+
+ DeferredUpdates::addCallableUpdate( [ $this, 'refreshCounts' ] );
}
return true;
*/
$wgForeignUploadTargets = [];
+/**
+ * Configuration for file uploads using the embeddable upload dialog
+ * (https://www.mediawiki.org/wiki/Upload_dialog).
+ *
+ * This applies also to foreign uploads to this wiki (the configuration is loaded by remote wikis
+ * using the action=query&meta=siteinfo API).
+ *
+ * See below for documentation of each property. None of the properties may be omitted.
+ */
+$wgUploadDialog = [
+ // Fields to make available in the dialog. `true` means that this field is visible, `false` means
+ // that it is hidden. The "Name" field can't be hidden. Note that you also have to add the
+ // matching replacement to the 'filepage' format key below to make use of these.
+ 'fields' => [
+ 'description' => true,
+ 'date' => false,
+ 'categories' => false,
+ ],
+ // Suffix of localisation messages used to describe the license under which the uploaded file will
+ // be released. The same value may be set for both 'local' and 'foreign' uploads.
+ 'licensemessages' => [
+ // The 'local' messages are used for local uploads on this wiki:
+ // * upload-form-label-own-work-message-generic-local
+ // * upload-form-label-not-own-work-message-generic-local
+ // * upload-form-label-not-own-work-local-generic-local
+ 'local' => 'generic-local',
+ // The 'foreign' messages are used for cross-wiki uploads from other wikis to this wiki:
+ // * upload-form-label-own-work-message-generic-foreign
+ // * upload-form-label-not-own-work-message-generic-foreign
+ // * upload-form-label-not-own-work-local-generic-foreign
+ 'foreign' => 'generic-foreign',
+ ],
+ // Upload comment to use. Available replacements:
+ // * $HOST - domain name from which a cross-wiki upload originates
+ // * $PAGENAME - wiki page name from which an upload originates
+ 'comment' => '',
+ // Format of the file page wikitext to be generated from the fields input by the user.
+ 'format' => [
+ // Wrapper for the whole page. Available replacements:
+ // * $DESCRIPTION - file description, as input by the user (only if the 'description' field is
+ // enabled), wrapped as defined below in the 'description' key
+ // * $DATE - file creation date, as input by the user (only if the 'date' field is enabled)
+ // * $SOURCE - as defined below in the 'ownwork' key, may be extended in the future
+ // * $AUTHOR - linked user name, may be extended in the future
+ // * $LICENSE - as defined below in the 'license' key, may be extended in the future
+ // * $CATEGORIES - file categories wikitext, as input by the user (only if the 'categories'
+ // field is enabled), or if no input, as defined below in the 'uncategorized' key
+ 'filepage' => '$DESCRIPTION',
+ // Wrapped for file description. Available replacements:
+ // * $LANGUAGE - source wiki's content language
+ // * $TEXT - input by the user
+ 'description' => '$TEXT',
+ 'ownwork' => '',
+ 'license' => '',
+ 'uncategorized' => '',
+ ],
+];
+
/**
* File backend structure configuration.
*
* if available
*
* - max lag: (optional) Maximum replication lag before a slave will taken out of rotation
+ * - is static: (optional) Set to true if the dataset is static and no replication is used.
*
* These and any other user-defined properties will be assigned to the mLBInfo member
* variable of the Database object.
*/
$wgPHPSessionHandling = 'enable';
+/**
+ * Number of internal PBKDF2 iterations to use when deriving session secrets.
+ *
+ * @since 1.28
+ */
+$wgSessionPbkdf2Iterations = 10001;
+
/**
* If enabled, will send MemCached debugging information to $wgDebugLogFile
*/
*/
$wgUseMediaWikiUIEverywhere = false;
-/**
- * Should we try to make our HTML output well-formed XML? If set to false,
- * output will be a few bytes shorter, and the HTML will arguably be more
- * readable. If set to true, life will be much easier for the authors of
- * screen-scraping bots, and the HTML will arguably be more readable.
- *
- * Setting this to false may omit quotation marks on some attributes, omit
- * slashes from some self-closing tags, omit some ending tags, etc., where
- * permitted by HTML5. Setting it to true will not guarantee that all pages
- * will be well-formed, although non-well-formed pages should be rare and it's
- * a bug if you find one. Conversely, setting it to false doesn't mean that
- * all XML-y constructs will be omitted, just that they might be.
- *
- * Because of compatibility with screen-scraping bots, and because it's
- * controversial, this is currently left to true by default.
- */
-$wgWellFormedXml = true;
-
/**
* Permit other namespaces in addition to the w3.org default.
*
$wgRawHtml = false;
/**
- * Set a default target for external links, e.g. _blank to pop up a new window
+ * Set a default target for external links, e.g. _blank to pop up a new window.
+ *
+ * This will also set the "noreferrer" and "noopener" link rel to prevent the
+ * attack described at https://mathiasbynens.github.io/rel-noopener/ .
+ * Some older browsers may not support these link attributes, hence
+ * setting $wgExternalLinkTarget to _blank may represent a security risk
+ * to some of your users.
*/
$wgExternalLinkTarget = false;
],
];
+/**
+ * Disable AuthManager
+ * @since 1.27
+ * @deprecated since 1.27, for use during development only
+ */
+$wgDisableAuthManager = false;
+
+/**
+ * Configure AuthManager
+ *
+ * All providers are constructed using ObjectFactory, see that for the general
+ * structure. The array may also contain a key "sort" used to order providers:
+ * providers are stably sorted by this value, which should be an integer
+ * (default is 0).
+ *
+ * Elements are:
+ * - preauth: Array (keys ignored) of specifications for PreAuthenticationProviders
+ * - primaryauth: Array (keys ignored) of specifications for PrimaryAuthenticationProviders
+ * - secondaryauth: Array (keys ignored) of specifications for SecondaryAuthenticationProviders
+ *
+ * @since 1.27
+ * @note If this is null or empty, the value from $wgAuthManagerAutoConfig is
+ * used instead. Local customization should generally set this variable from
+ * scratch to the desired configuration. Extensions that want to
+ * auto-configure themselves should use $wgAuthManagerAutoConfig instead.
+ */
+$wgAuthManagerConfig = null;
+
+/**
+ * @see $wgAuthManagerConfig
+ * @since 1.27
+ */
+$wgAuthManagerAutoConfig = [
+ 'preauth' => [
+ MediaWiki\Auth\LegacyHookPreAuthenticationProvider::class => [
+ 'class' => MediaWiki\Auth\LegacyHookPreAuthenticationProvider::class,
+ 'sort' => 0,
+ ],
+ MediaWiki\Auth\ThrottlePreAuthenticationProvider::class => [
+ 'class' => MediaWiki\Auth\ThrottlePreAuthenticationProvider::class,
+ 'sort' => 0,
+ ],
+ ],
+ 'primaryauth' => [
+ // TemporaryPasswordPrimaryAuthenticationProvider should come before
+ // any other PasswordAuthenticationRequest-based
+ // PrimaryAuthenticationProvider (or at least any that might return
+ // FAIL rather than ABSTAIN for a wrong password), or password reset
+ // won't work right. Do not remove this (or change the key) or
+ // auto-configuration of other such providers in extensions will
+ // probably auto-insert themselves in the wrong place.
+ MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider::class => [
+ 'class' => MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider::class,
+ 'args' => [ [
+ // Fall through to LocalPasswordPrimaryAuthenticationProvider
+ 'authoritative' => false,
+ ] ],
+ 'sort' => 0,
+ ],
+ MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider::class => [
+ 'class' => MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider::class,
+ 'args' => [ [
+ // Last one should be authoritative, or else the user will get
+ // a less-than-helpful error message (something like "supplied
+ // authentication info not supported" rather than "wrong
+ // password") if it too fails.
+ 'authoritative' => true,
+ ] ],
+ 'sort' => 100,
+ ],
+ ],
+ 'secondaryauth' => [
+ MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider::class => [
+ 'class' => MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider::class,
+ 'sort' => 0,
+ ],
+ MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider::class => [
+ 'class' => MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider::class,
+ 'sort' => 100,
+ ],
+ // Linking during login is experimental, enable at your own risk - T134952
+ // MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider::class => [
+ // 'class' => MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider::class,
+ // 'sort' => 100,
+ // ],
+ MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider::class => [
+ 'class' => MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider::class,
+ 'sort' => 200,
+ ],
+ ],
+];
+
+/**
+ * Time frame for re-authentication.
+ *
+ * With only password-based authentication, you'd just ask the user to re-enter
+ * their password to verify certain operations like changing the password or
+ * changing the account's email address. But under AuthManager, the user might
+ * not have a password (you might even have to redirect the browser to a
+ * third-party service or something complex like that), you might want to have
+ * both factors of a two-factor authentication, and so on. So, the options are:
+ * - Incorporate the whole multi-step authentication flow within everything
+ * that needs to do this.
+ * - Consider it good if they used Special:UserLogin during this session within
+ * the last X seconds.
+ * - Come up with a third option.
+ *
+ * MediaWiki currently takes the second option. This setting configures the
+ * "X seconds".
+ *
+ * This allows for configuring different time frames for different
+ * "operations". The operations used in MediaWiki core include:
+ * - LinkAccounts
+ * - UnlinkAccount
+ * - ChangeCredentials
+ * - RemoveCredentials
+ * - ChangeEmail
+ *
+ * Additional operations may be used by extensions, either explicitly by
+ * calling AuthManager::securitySensitiveOperationStatus(),
+ * ApiAuthManagerHelper::securitySensitiveOperation() or
+ * SpecialPage::checkLoginSecurityLevel(), or implicitly by overriding
+ * SpecialPage::getLoginSecurityLevel() or by subclassing
+ * AuthManagerSpecialPage.
+ *
+ * The key 'default' is used if a requested operation isn't defined in the array.
+ *
+ * @since 1.27
+ * @var int[] operation => time in seconds. A 'default' key must always be provided.
+ */
+$wgReauthenticateTime = [
+ 'default' => 300,
+];
+
+/**
+ * Whether to allow security-sensitive operations when re-authentication is not possible.
+ *
+ * If AuthManager::canAuthenticateNow() is false (e.g. the current
+ * SessionProvider is not able to change users, such as when OAuth is in use),
+ * AuthManager::securitySensitiveOperationStatus() cannot sensibly return
+ * SEC_REAUTH. Setting an operation true here will have it return SEC_OK in
+ * that case, while setting it false will have it return SEC_FAIL.
+ *
+ * The key 'default' is used if a requested operation isn't defined in the array.
+ *
+ * @since 1.27
+ * @see $wgReauthenticateTime
+ * @var bool[] operation => boolean. A 'default' key must always be provided.
+ */
+$wgAllowSecuritySensitiveOperationIfCannotReauthenticate = [
+ 'default' => true,
+];
+
+/**
+ * List of AuthenticationRequest class names which are not changeable through
+ * Special:ChangeCredentials and the changeauthenticationdata API.
+ * This is only enforced on the client level; AuthManager itself (e.g.
+ * AuthManager::allowsAuthenticationDataChange calls) is not affected.
+ * Class names are checked for exact match (not for subclasses).
+ * @since 1.27
+ * @var string[]
+ */
+$wgChangeCredentialsBlacklist = [
+ \MediaWiki\Auth\TemporaryPasswordAuthenticationRequest::class
+];
+
+/**
+ * List of AuthenticationRequest class names which are not removable through
+ * Special:RemoveCredentials and the removeauthenticationdata API.
+ * This is only enforced on the client level; AuthManager itself (e.g.
+ * AuthManager::allowsAuthenticationDataChange calls) is not affected.
+ * Class names are checked for exact match (not for subclasses).
+ * @since 1.27
+ * @var string[]
+ */
+$wgRemoveCredentialsBlacklist = [
+ \MediaWiki\Auth\PasswordAuthenticationRequest::class,
+];
+
/**
* For compatibility with old installations set to false
* @deprecated since 1.24 will be removed in future
],
'pbkdf2' => [
'class' => 'Pbkdf2Password',
- 'algo' => 'sha256',
- 'cost' => '10000',
- 'length' => '128',
+ 'algo' => 'sha512',
+ 'cost' => '30000',
+ 'length' => '64',
],
];
MediaWiki\Session\BotPasswordSessionProvider::class => [
'class' => MediaWiki\Session\BotPasswordSessionProvider::class,
'args' => [ [
- 'priority' => 40,
+ 'priority' => 75,
] ],
],
];
# $wgGroupPermissions['sysop']['upload_by_url'] = true;
$wgGroupPermissions['sysop']['mergehistory'] = true;
$wgGroupPermissions['sysop']['managechangetags'] = true;
+$wgGroupPermissions['sysop']['deletechangetags'] = true;
// Permission to change users' group assignments
$wgGroupPermissions['bureaucrat']['userrights'] = true;
/**
* Authentication plugin.
* @var $wgAuth AuthPlugin
+ * @deprecated since 1.27 use $wgAuthManagerConfig instead
*/
$wgAuth = null;
],
'newusers' => [
'create' => [ 'create', 'newusers' ],
- 'create2' => ['create2' ],
+ 'create2' => [ 'create2' ],
'autocreate' => [ 'autocreate' ],
'byemail' => [ 'byemail' ],
],
'protect' => [ 'protect' ],
'modify' => [ 'modify' ],
'unprotect' => [ 'unprotect' ],
- 'move_prot' => ['move_prot'],
+ 'move_prot' => [ 'move_prot' ],
],
'rights' => [
'rights' => [ 'rights' ],
// for future use with the api, and for use by extensions
define( 'CONTENT_FORMAT_XML', 'application/xml' );
/**@}*/
+
+/**@{
+ * Max string length for shell invocations; based on binfmts.h
+ */
+define( 'SHELL_MAX_ARG_STRLEN', '100000' );
+/**@}*/
public function link(
$target,
$html = null,
- $customAttribs = [ ],
- $query = [ ],
- $options = [ ]
+ $customAttribs = [],
+ $query = [],
+ $options = []
) {
return Linker::link(
$target,
public function linkKnown(
$target,
$html = null,
- $customAttribs = [ ],
- $query = [ ],
- $options = [ 'known', 'noclasses' ]
+ $customAttribs = [],
+ $query = [],
+ $options = [ 'known' ]
) {
return Linker::linkKnown(
$target,
Parser $parser,
Title $title,
$file,
- $frameParams = [ ],
- $handlerParams = [ ],
+ $frameParams = [],
+ $handlerParams = [],
$time = false,
$query = "",
$widthOption = null
$label = '',
$alt,
$align = 'right',
- $params = [ ],
+ $params = [],
$framed = false,
$manualthumb = ""
) {
public function makeThumbLink2(
Title $title,
$file,
- $frameParams = [ ],
- $handlerParams = [ ],
+ $frameParams = [],
+ $handlerParams = [],
$time = false,
$query = ""
) {
$text,
$escape = true,
$linktype = '',
- $attribs = [ ],
+ $attribs = [],
$title = null
) {
return Linker::makeExternalLink(
Title $title,
$text,
$wikiId = null,
- $options = [ ]
+ $options = []
) {
return Linker::makeCommentLink(
$title,
return Linker::formatSize( $size );
}
- public function titleAttrib( $name, $options = null, array $msgParams = [ ] ) {
+ public function titleAttrib( $name, $options = null, array $msgParams = [] ) {
return Linker::titleAttrib(
$name,
$options,
);
}
- public function revDeleteLink( $query = [ ], $restricted = false, $delete = true ) {
+ public function revDeleteLink( $query = [], $restricted = false, $delete = true ) {
return Linker::revDeleteLink(
$query,
$restricted,
return Linker::revDeleteLinkDisabled( $delete );
}
- public function tooltipAndAccesskeyAttribs( $name, array $msgParams = [ ] ) {
+ public function tooltipAndAccesskeyAttribs( $name, array $msgParams = [] ) {
return Linker::tooltipAndAccesskeyAttribs(
$name,
$msgParams
"<div id='mw-anon-edit-warning' class='warningbox'>\n$1\n</div>",
[ 'anoneditwarning',
// Log-in link
- '{{fullurl:Special:UserLogin|returnto={{FULLPAGENAMEE}}}}',
+ SpecialPage::getTitleFor( 'Userlogin' )->getFullURL( [
+ 'returnto' => $this->getTitle()->getPrefixedDBkey()
+ ] ),
// Sign-up link
- '{{fullurl:Special:UserLogin/signup|returnto={{FULLPAGENAMEE}}}}' ]
+ SpecialPage::getTitleFor( 'CreateAccount' )->getFullURL( [
+ 'returnto' => $this->getTitle()->getPrefixedDBkey()
+ ] )
+ ]
);
} else {
$wgOut->wrapWikiMsg( "<div id=\"mw-anon-preview-warning\" class=\"warningbox\">\n$1</div>",
$cancelParams = [];
if ( !$this->isConflict && $this->oldid > 0 ) {
$cancelParams['oldid'] = $this->oldid;
+ } elseif ( $this->getContextTitle()->isRedirect() ) {
+ $cancelParams['redirect'] = 'no';
}
$attrs = [ 'id' => 'mw-editform-cancel' ];
],
$showSignature ? [
'id' => 'mw-editbutton-signature',
- 'open' => '--~~~~',
+ 'open' => wfMessage( 'sig-text', '~~~~' )->inContentLanguage()->text(),
'close' => '',
'sample' => '',
'tip' => wfMessage( 'sig_tip' )->text(),
// Hide compatibility functions from Doxygen
/// @cond
-
/**
* Compatibility functions
*
return $tmp;
}
}
+
+ /**
+ * PHP on Windows will detect C:\Windows\Temp as not writable even though PHP can write to it
+ * so create a directory within that called 'mwtmp' with a suffix of the user running the
+ * current process.
+ * The user is included as if various scripts are run by different users they will likely
+ * not be able to access each others temporary files.
+ */
+ if ( wfIsWindows() ) {
+ $tmp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'mwtmp' . '-' . get_current_user();
+ if ( !file_exists( $tmp ) ) {
+ mkdir( $tmp );
+ }
+ if ( file_exists( $tmp ) && is_dir( $tmp ) && is_writable( $tmp ) ) {
+ return $tmp;
+ }
+ }
+
throw new MWException( 'No writable temporary directory could be found. ' .
'Please set $wgTmpDirectory to a writable directory.' );
}
}
wfDebug( "wfShellExec: $cmd\n" );
+ // Don't try to execute commands that exceed Linux's MAX_ARG_STRLEN.
+ // Other platforms may be more accomodating, but we don't want to be
+ // accomodating, because very long commands probably include user
+ // input. See T129506.
+ if ( strlen( $cmd ) > SHELL_MAX_ARG_STRLEN ) {
+ throw new Exception( __METHOD__ .
+ '(): total length of $cmd must not exceed SHELL_MAX_ARG_STRLEN' );
+ }
+
$desc = [
0 => [ 'file', 'php://stdin', 'r' ],
1 => [ 'pipe', 'w' ],
*
* $wgMimeType: If this is set to an xml MIME type then output should be
* valid XHTML5.
- * $wgWellFormedXml: If this is set to true, then all output should be
- * well-formed XML (quotes on attributes, self-closing tags, etc.).
*
* This class is meant to be confined to utility functions that are called from
* trusted code paths. It does not do enforcement of policy like not allowing
* This is quite similar to Xml::tags(), but it implements some useful
* HTML-specific logic. For instance, there is no $allowShortTag
* parameter: the closing tag is magically omitted if $element has an empty
- * content model. If $wgWellFormedXml is false, then a few bytes will be
- * shaved off the HTML output as well.
+ * content model.
*
* @param string $element The element's name, e.g., 'a'
* @param array $attribs Associative array of attributes, e.g., array(
* @return string Raw HTML
*/
public static function rawElement( $element, $attribs = [], $contents = '' ) {
- global $wgWellFormedXml;
$start = self::openElement( $element, $attribs );
if ( in_array( $element, self::$voidElements ) ) {
- if ( $wgWellFormedXml ) {
- // Silly XML.
- return substr( $start, 0, -1 ) . '/>';
- }
- return $start;
+ // Silly XML.
+ return substr( $start, 0, -1 ) . '/>';
} else {
return "$start$contents" . self::closeElement( $element );
}
* 'http://www.mediawiki.org/' ) becomes something like
* ' href="http://www.mediawiki.org"'. Again, this is like
* Xml::expandAttributes(), but it implements some HTML-specific logic.
- * For instance, it will omit quotation marks if $wgWellFormedXml is false,
- * and will treat boolean attributes specially.
*
* Attributes that can contain space-separated lists ('class', 'accesskey' and 'rel') array
* values are allowed as well, which will automagically be normalized
* (starting with a space if at least one attribute is output)
*/
public static function expandAttributes( array $attribs ) {
- global $wgWellFormedXml;
-
$ret = '';
foreach ( $attribs as $key => $value ) {
// Support intuitive array( 'checked' => true/false ) form
throw new MWException( "HTML attribute $key can not contain a list of values" );
}
- // See the "Attributes" section in the HTML syntax part of HTML5,
- // 9.1.2.3 as of 2009-08-10. Most attributes can have quotation
- // marks omitted, but not all. (Although a literal " is not
- // permitted, we don't check for that, since it will be escaped
- // anyway.)
-
- // See also research done on further characters that need to be
- // escaped: http://code.google.com/p/html5lib/issues/detail?id=93
- $badChars = "\\x00- '=<>`/\x{00a0}\x{1680}\x{180e}\x{180F}\x{2000}\x{2001}"
- . "\x{2002}\x{2003}\x{2004}\x{2005}\x{2006}\x{2007}\x{2008}\x{2009}"
- . "\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}";
- if ( $wgWellFormedXml || $value === '' || preg_match( "![$badChars]!u", $value ) ) {
- $quote = '"';
- } else {
- $quote = '';
- }
+ $quote = '"';
if ( in_array( $key, self::$boolAttribs ) ) {
- // In HTML5, we can leave the value empty. If we don't need
- // well-formed XML, we can omit the = entirely.
- if ( !$wgWellFormedXml ) {
- $ret .= " $key";
- } else {
- $ret .= " $key=\"\"";
- }
+ $ret .= " $key=\"\"";
} else {
// Apparently we need to entity-encode \n, \r, \t, although the
// spec doesn't mention that. Since we're doing strtr() anyway,
// don't because we're stubborn and like our marginal savings on
// byte size from not having to encode unnecessary quotes.
// The only difference between this transform and the one by
- // Sanitizer::encodeAttribute() is '<' is only encoded here if
- // $wgWellFormedXml is set, and ' is not encoded.
+ // Sanitizer::encodeAttribute() is ' is not encoded.
$map = [
'&' => '&',
'"' => '"',
'>' => '>',
+ // '<' allegedly allowed per spec
+ // but breaks some tools if not escaped.
+ "<" => '<',
"\n" => ' ',
"\r" => ' ',
"\t" => '	'
];
- if ( $wgWellFormedXml ) {
- // This is allowed per spec: <http://www.w3.org/TR/xml/#NT-AttValue>
- // But reportedly it breaks some XML tools?
- // @todo FIXME: Is this really true?
- $map['<'] = '<';
- }
$ret .= " $key=$quote" . strtr( $value, $map ) . $quote;
}
}
* @return string Raw HTML
*/
public static function inlineScript( $contents ) {
- global $wgWellFormedXml;
-
$attrs = [];
- if ( $wgWellFormedXml && preg_match( '/[<&]/', $contents ) ) {
+ if ( preg_match( '/[<&]/', $contents ) ) {
$contents = "/*<![CDATA[*/$contents/*]]>*/";
}
* @return string Raw HTML
*/
public static function inlineStyle( $contents, $media = 'all' ) {
- global $wgWellFormedXml;
-
- if ( $wgWellFormedXml && preg_match( '/[<&]/', $contents ) ) {
+ if ( preg_match( '/[<&]/', $contents ) ) {
$contents = "/*<![CDATA[*/$contents/*]]>*/";
}
* @file
*/
use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
/**
* Some internal bits split of from Skin.php. These functions are used
* Return the CSS colour of a known link
*
* @since 1.16.3
- * @param Title $t
+ * @param LinkTarget $t
* @param int $threshold User defined threshold
* @return string CSS class
*/
- public static function getLinkColour( $t, $threshold ) {
- $colour = '';
- if ( $t->isRedirect() ) {
+ public static function getLinkColour( LinkTarget $t, $threshold ) {
+ $linkCache = MediaWikiServices::getInstance()->getLinkCache();
+ // Make sure the target is in the cache
+ $id = $linkCache->addLinkObj( $t );
+ if ( $id == 0 ) {
+ // Doesn't exist
+ return '';
+ }
+
+ if ( $linkCache->getGoodLinkFieldObj( $t, 'redirect' ) ) {
# Page is a redirect
- $colour = 'mw-redirect';
- } elseif ( $threshold > 0 && $t->isContentPage() &&
- $t->exists() && $t->getLength() < $threshold
+ return 'mw-redirect';
+ } elseif ( $threshold > 0 && MWNamespace::isContent( $t->getNamespace() )
+ && $linkCache->getGoodLinkFieldObj( $t, 'length' ) < $threshold
) {
# Page is a stub
- $colour = 'stub';
+ return 'stub';
}
- return $colour;
+
+ return '';
}
/**
wfDeprecated( __METHOD__ . ' with parameter $query as string (should be array)', '1.20' );
$query = wfCgiToArray( $query );
}
- $options = (array)$options;
-
- $dummy = new DummyLinker; // dummy linker instance for bc on the hooks
-
- $ret = null;
- if ( !Hooks::run( 'LinkBegin',
- [ $dummy, $target, &$html, &$customAttribs, &$query, &$options, &$ret ] )
- ) {
- return $ret;
- }
- # Normalize the Title if it's a special page
- $target = self::normaliseSpecialPage( $target );
-
- # If we don't know whether the page exists, let's find out.
- if ( !in_array( 'known', $options, true ) && !in_array( 'broken', $options, true ) ) {
- if ( $target->isKnown() ) {
- $options[] = 'known';
- } else {
- $options[] = 'broken';
+ $services = MediaWikiServices::getInstance();
+ $options = (array)$options;
+ if ( $options ) {
+ // Custom options, create new LinkRenderer
+ if ( !isset( $options['stubThreshold'] ) ) {
+ $defaultLinkRenderer = $services->getLinkRenderer();
+ $options['stubThreshold'] = $defaultLinkRenderer->getStubThreshold();
}
+ $linkRenderer = $services->getLinkRendererFactory()
+ ->createFromLegacyOptions( $options );
+ } else {
+ $linkRenderer = $services->getLinkRenderer();
}
- $oldquery = [];
- if ( in_array( "forcearticlepath", $options, true ) && $query ) {
- $oldquery = $query;
- $query = [];
- }
-
- # Note: we want the href attribute first, for prettiness.
- $attribs = [ 'href' => self::linkUrl( $target, $query, $options ) ];
- if ( in_array( 'forcearticlepath', $options, true ) && $oldquery ) {
- $attribs['href'] = wfAppendQuery( $attribs['href'], $oldquery );
- }
-
- $attribs = array_merge(
- $attribs,
- self::linkAttribs( $target, $customAttribs, $options )
- );
- if ( is_null( $html ) ) {
- $html = self::linkText( $target );
- }
-
- $ret = null;
- if ( Hooks::run( 'LinkEnd', [ $dummy, $target, $options, &$html, &$attribs, &$ret ] ) ) {
- $ret = Html::rawElement( 'a', $attribs, $html );
+ if ( $html !== null ) {
+ $text = new HtmlArmor( $html );
+ } else {
+ $text = $html; // null
+ }
+ if ( in_array( 'known', $options, true ) ) {
+ return $linkRenderer->makeKnownLink( $target, $text, $customAttribs, $query );
+ } elseif ( in_array( 'broken', $options, true ) ) {
+ return $linkRenderer->makeBrokenLink( $target, $text, $customAttribs, $query );
+ } elseif ( in_array( 'noclasses', $options, true ) ) {
+ return $linkRenderer->makePreloadedLink( $target, $text, '', $customAttribs, $query );
+ } else {
+ return $linkRenderer->makeLink( $target, $text, $customAttribs, $query );
}
-
- return $ret;
}
/**
*/
public static function linkKnown(
$target, $html = null, $customAttribs = [],
- $query = [], $options = [ 'known', 'noclasses' ]
+ $query = [], $options = [ 'known' ]
) {
return self::link( $target, $html, $customAttribs, $query, $options );
}
- /**
- * Returns the Url used to link to a Title
- *
- * @param LinkTarget $target
- * @param array $query Query parameters
- * @param array $options
- * @return string
- */
- private static function linkUrl( LinkTarget $target, $query, $options ) {
- # We don't want to include fragments for broken links, because they
- # generally make no sense.
- if ( in_array( 'broken', $options, true ) && $target->hasFragment() ) {
- $target = $target->createFragmentTarget( '' );
- }
-
- # If it's a broken link, add the appropriate query pieces, unless
- # there's already an action specified, or unless 'edit' makes no sense
- # (i.e., for a nonexistent special page).
- if ( in_array( 'broken', $options, true ) && empty( $query['action'] )
- && $target->getNamespace() !== NS_SPECIAL ) {
- $query['action'] = 'edit';
- $query['redlink'] = '1';
- }
-
- if ( in_array( 'http', $options, true ) ) {
- $proto = PROTO_HTTP;
- } elseif ( in_array( 'https', $options, true ) ) {
- $proto = PROTO_HTTPS;
- } else {
- $proto = PROTO_RELATIVE;
- }
-
- $title = Title::newFromLinkTarget( $target );
- $ret = $title->getLinkURL( $query, false, $proto );
- return $ret;
- }
-
- /**
- * Returns the array of attributes used when linking to the Title $target
- *
- * @param Title $target
- * @param array $attribs
- * @param array $options
- *
- * @return array
- */
- private static function linkAttribs( $target, $attribs, $options ) {
- global $wgUser;
- $defaults = [];
-
- if ( !in_array( 'noclasses', $options, true ) ) {
- # Now build the classes.
- $classes = [];
-
- if ( in_array( 'broken', $options, true ) ) {
- $classes[] = 'new';
- }
-
- if ( $target->isExternal() ) {
- $classes[] = 'extiw';
- }
-
- if ( !in_array( 'broken', $options, true ) ) { # Avoid useless calls to LinkCache (see r50387)
- $colour = self::getLinkColour(
- $target,
- isset( $options['stubThreshold'] ) ? $options['stubThreshold'] : $wgUser->getStubThreshold()
- );
- if ( $colour !== '' ) {
- $classes[] = $colour; # mw-redirect or stub
- }
- }
- if ( $classes != [] ) {
- $defaults['class'] = implode( ' ', $classes );
- }
- }
-
- # Get a default title attribute.
- if ( $target->getPrefixedText() == '' ) {
- # A link like [[#Foo]]. This used to mean an empty title
- # attribute, but that's silly. Just don't output a title.
- } elseif ( in_array( 'known', $options, true ) ) {
- $defaults['title'] = $target->getPrefixedText();
- } else {
- // This ends up in parser cache!
- $defaults['title'] = wfMessage( 'red-link-title', $target->getPrefixedText() )
- ->inContentLanguage()
- ->text();
- }
-
- # Finally, merge the custom attribs with the default ones, and iterate
- # over that, deleting all "false" attributes.
- $ret = [];
- $merged = Sanitizer::mergeAttributes( $defaults, $attribs );
- foreach ( $merged as $key => $val ) {
- # A false value suppresses the attribute, and we don't want the
- # href attribute to be overridden.
- if ( $key != 'href' && $val !== false ) {
- $ret[$key] = $val;
- }
- }
- return $ret;
- }
-
- /**
- * Default text of the links to the Title $target
- *
- * @param Title $target
- *
- * @return string
- */
- private static function linkText( $target ) {
- if ( !$target instanceof Title ) {
- wfWarn( __METHOD__ . ': Requires $target to be a Title object.' );
- return '';
- }
- // If the target is just a fragment, with no title, we return the fragment
- // text. Otherwise, we return the title text itself.
- if ( $target->getPrefixedText() === '' && $target->hasFragment() ) {
- return htmlspecialchars( $target->getFragment() );
- }
-
- return htmlspecialchars( $target->getPrefixedText() );
- }
-
/**
* Make appropriate markup for a link to the current article. This is
* currently rendered as the bold link text. The calling sequence is the
$redir = RepoGroup::singleton()->getLocalRepo()->checkRedirect( $title );
if ( $redir ) {
- return self::linkKnown( $title, $encLabel, [], wfCgiToArray( $query ) );
+ // We already know it's a redirect, so mark it
+ // accordingly
+ return self::link(
+ $title,
+ $encLabel,
+ [ 'class' => 'mw-redirect' ],
+ wfCgiToArray( $query ),
+ [ 'known', 'noclasses' ]
+ );
}
$href = self::getUploadUrl( $title, $query );
$encLabel . '</a>';
}
- return self::linkKnown( $title, $encLabel, [], wfCgiToArray( $query ) );
+ return self::link( $title, $encLabel, [], wfCgiToArray( $query ), [ 'known', 'noclasses' ] );
}
/**
if ( !$title ) {
$title = $wgTitle;
}
- $attribs['rel'] = Parser::getExternalLinkRel( $url, $title );
+ $newRel = Parser::getExternalLinkRel( $url, $title );
+ if ( !isset( $attribs['rel'] ) || $attribs['rel'] === '' ) {
+ $attribs['rel'] = $newRel;
+ } elseif ( $newRel !== '' ) {
+ // Merge the rel attributes.
+ $newRels = explode( ' ', $newRel );
+ $oldRels = explode( ' ', $attribs['rel'] );
+ $combined = array_unique( array_merge( $newRels, $oldRels ) );
+ $attribs['rel'] = implode( ' ', $combined );
+ }
$link = '';
$success = Hooks::run( 'LinkerMakeExternalLink',
[ &$url, &$text, &$link, &$attribs, $linktype ] );
* work if $wgShowRollbackEditCount is disabled, so this can only function
* as an additional check.
*
- * If the option noBrackets is set the rollback link wont be enclosed in []
+ * If the option noBrackets is set the rollback link wont be enclosed in "[]".
*
* @since 1.16.3. $context added in 1.20. $options added in 1.21
*
$query = [
'action' => 'rollback',
'from' => $rev->getUserText(),
- 'token' => $context->getUser()->getEditToken( [
- $title->getPrefixedText(),
- $rev->getUserText()
- ] ),
+ 'token' => $context->getUser()->getEditToken( 'rollback' ),
];
+ $attrs = [
+ 'data-mw' => 'interface',
+ 'title' => $context->msg( 'tooltip-rollback' )->text(),
+ ];
+ $options = [ 'known', 'noclasses' ];
+
if ( $context->getRequest()->getBool( 'bot' ) ) {
$query['bot'] = '1';
$query['hidediff'] = '1'; // bug 15999
}
if ( $editCount > $wgShowRollbackEditCount ) {
- $editCount_output = $context->msg( 'rollbacklinkcount-morethan' )
+ $html = $context->msg( 'rollbacklinkcount-morethan' )
->numParams( $wgShowRollbackEditCount )->parse();
} else {
- $editCount_output = $context->msg( 'rollbacklinkcount' )->numParams( $editCount )->parse();
+ $html = $context->msg( 'rollbacklinkcount' )->numParams( $editCount )->parse();
}
- return self::link(
- $title,
- $editCount_output,
- [ 'title' => $context->msg( 'tooltip-rollback' )->text() ],
- $query,
- [ 'known', 'noclasses' ]
- );
+ return self::link( $title, $html, $attrs, $query, $options );
} else {
- return self::link(
- $title,
- $context->msg( 'rollbacklink' )->escaped(),
- [ 'title' => $context->msg( 'tooltip-rollback' )->text() ],
- $query,
- [ 'known', 'noclasses' ]
- );
+ $html = $context->msg( 'rollbacklink' )->escaped();
+ return self::link( $title, $html, $attrs, $query, $options );
}
}
$trxProfiler = Profiler::instance()->getTransactionProfiler();
if ( $request->wasPosted() && !$action->doesWrites() ) {
$trxProfiler->setExpectations( $trxLimits['POST-nonwrite'], __METHOD__ );
+ $request->markAsSafeRequest();
}
# Let CDN cache things if we can purge them.
$trxLimits = $this->config->get( 'TrxProfilerLimits' );
$trxProfiler = Profiler::instance()->getTransactionProfiler();
$trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
- if ( $request->wasPosted() ) {
- $trxProfiler->setExpectations( $trxLimits['POST'], __METHOD__ );
- } else {
+ if ( $request->hasSafeMethod() ) {
$trxProfiler->setExpectations( $trxLimits['GET'], __METHOD__ );
+ } else {
+ $trxProfiler->setExpectations( $trxLimits['POST'], __METHOD__ );
}
// If the user has forceHTTPS set to true, or if the user
// isLoggedIn() will do all sorts of weird stuff.
if (
$request->getProtocol() == 'http' &&
+ // switch to HTTPS only when supported by the server
+ preg_match( '#^https://#', wfExpandUrl( $request->getRequestURL(), PROTO_HTTPS ) ) &&
(
$request->getSession()->shouldForceHTTPS() ||
// Check the cookie manually, for paranoia
use Config;
use ConfigFactory;
use EventRelayerGroup;
+use GenderCache;
use GlobalVarConfig;
use Hooks;
use LBFactory;
+use LinkCache;
use Liuggio\StatsdClient\Factory\StatsdDataFactory;
use LoadBalancer;
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Linker\LinkRendererFactory;
+use MediaWiki\Services\SalvageableService;
use MediaWiki\Services\ServiceContainer;
use MWException;
-use ResourceLoader;
+use ObjectCache;
use SearchEngine;
use SearchEngineConfig;
use SearchEngineFactory;
use SiteStore;
use WatchedItemStore;
use SkinFactory;
+use TitleFormatter;
+use TitleParser;
+use MediaWiki\Interwiki\InterwikiLookup;
/**
* Service locator for MediaWiki core services.
/**
* Returns the global default instance of the top level service locator.
*
+ * @since 1.27
+ *
* The default instance is initialized using the service instantiator functions
* defined in ServiceWiring.php.
*
// even if it's just a file name or database credentials to load
// configuration from.
$bootstrapConfig = new GlobalVarConfig();
- self::$instance = self::newInstance( $bootstrapConfig );
+ self::$instance = self::newInstance( $bootstrapConfig, 'load' );
}
return self::$instance;
/**
* Replaces the global MediaWikiServices instance.
*
+ * @since 1.28
+ *
* @note This is for use in PHPUnit tests only!
*
* @throws MWException if called outside of PHPUnit tests.
/**
* Creates a new instance of MediaWikiServices and sets it as the global default
* instance. getInstance() will return a different MediaWikiServices object
- * after every call to resetGlobalServiceLocator().
+ * after every call to resetGlobalInstance().
+ *
+ * @since 1.28
*
* @warning This should not be used during normal operation. It is intended for use
* when the configuration has changed significantly since bootstrap time, e.g.
* during the installation process or during testing.
*
- * @warning Calling resetGlobalServiceLocator() may leave the application in an inconsistent
+ * @warning Calling resetGlobalInstance() may leave the application in an inconsistent
* state. Calling this is only safe under the ASSUMPTION that NO REFERENCE to
* any of the services managed by MediaWikiServices exist. If any service objects
* managed by the old MediaWikiServices instance remain in use, they may INTERFERE
* was no previous instance, a new GlobalVarConfig object will be used to
* bootstrap the services.
*
+ * @param string $quick Set this to "quick" to allow expensive resources to be re-used.
+ * See SalvageableService for details.
+ *
* @throws MWException If called after MW_SERVICE_BOOTSTRAP_COMPLETE has been defined in
* Setup.php (unless MW_PHPUNIT_TEST or MEDIAWIKI_INSTALL or RUN_MAINTENANCE_IF_MAIN
* is defined).
*/
- public static function resetGlobalInstance( Config $bootstrapConfig = null ) {
+ public static function resetGlobalInstance( Config $bootstrapConfig = null, $quick = '' ) {
if ( self::$instance === null ) {
// no global instance yet, nothing to reset
return;
$bootstrapConfig = self::$instance->getBootstrapConfig();
}
- self::$instance->destroy();
+ $oldInstance = self::$instance;
self::$instance = self::newInstance( $bootstrapConfig );
+ self::$instance->importWiring( $oldInstance, [ 'BootstrapConfig' ] );
+
+ if ( $quick === 'quick' ) {
+ self::$instance->salvage( $oldInstance );
+ } else {
+ $oldInstance->destroy();
+ }
+
+ }
+
+ /**
+ * Salvages the state of any salvageable service instances in $other.
+ *
+ * @note $other will have been destroyed when salvage() returns.
+ *
+ * @param MediaWikiServices $other
+ */
+ private function salvage( self $other ) {
+ foreach ( $this->getServiceNames() as $name ) {
+ $oldService = $other->peekService( $name );
+
+ if ( $oldService instanceof SalvageableService ) {
+ /** @var SalvageableService $newService */
+ $newService = $this->getService( $name );
+ $newService->salvage( $oldService );
+ }
+ }
+
+ $other->destroy();
}
/**
* ServiceWiringFiles setting are loaded, and the MediaWikiServices hook is called.
*
* @param Config|null $bootstrapConfig The Config object to be registered as the
- * 'BootstrapConfig' service. This has to contain at least the information
- * needed to set up the 'ConfigFactory' service. If not provided, any call
- * to getBootstrapConfig(), getConfigFactory, or getMainConfig will fail.
- * A MediaWikiServices instance without access to configuration is called
- * "primordial".
+ * 'BootstrapConfig' service.
+ *
+ * @param string $loadWiring set this to 'load' to load the wiring files specified
+ * in the 'ServiceWiringFiles' setting in $bootstrapConfig.
*
* @return MediaWikiServices
* @throws MWException
+ * @throws \FatalError
*/
- private static function newInstance( Config $bootstrapConfig ) {
+ private static function newInstance( Config $bootstrapConfig, $loadWiring = '' ) {
$instance = new self( $bootstrapConfig );
// Load the default wiring from the specified files.
- $wiringFiles = $bootstrapConfig->get( 'ServiceWiringFiles' );
- $instance->loadWiringFiles( $wiringFiles );
+ if ( $loadWiring === 'load' ) {
+ $wiringFiles = $bootstrapConfig->get( 'ServiceWiringFiles' );
+ $instance->loadWiringFiles( $wiringFiles );
+ }
// Provide a traditional hook point to allow extensions to configure services.
Hooks::run( 'MediaWikiServices', [ $instance ] );
* storage layer will result in an error. Use resetGlobalInstance() to restore normal
* operation.
*
+ * @since 1.28
+ *
* @warning This is intended for extreme situations only and should never be used
* while serving normal web requests. Legitimate use cases for this method include
* the installation process. Test fixtures may also use this, if the fixture relies
foreach ( $destroy as $name ) {
$services->disableService( $name );
}
+
+ ObjectCache::clear();
}
/**
* returns from after pcntl_fork(). It's also safe, but generally unnecessary,
* to call this method from the parent process.
*
+ * @since 1.28
+ *
* @note This is intended for use in the context of process forking only!
*
* @see resetGlobalInstance()
/**
* Resets the given service for testing purposes.
*
+ * @since 1.28
+ *
* @warning This is generally unsafe! Other services may still retain references
* to the stale service instance, leading to failures and inconsistencies. Subclasses
* may use this method to reset specific services under specific instances, but
* instances to clean up.
*
* @param string $name
- * @param string $destroy Whether the service instance should be destroyed if it exists.
+ * @param bool $destroy Whether the service instance should be destroyed if it exists.
* When set to false, any existing service instance will effectively be detached
* from the container.
*
* resetting of global services is allowed. In general, services should not be reset
* individually, since that may introduce inconsistencies.
*
+ * @since 1.28
+ *
* This method will throw an exception if:
*
* - self::$resetInProgress is false (to allow all services to be reset together
* when creating the MainConfig service. Application logic should
* use getMainConfig() to get a Config instances.
*
+ * @since 1.27
* @return Config
*/
public function getBootstrapConfig() {
}
/**
+ * @since 1.27
* @return ConfigFactory
*/
public function getConfigFactory() {
* Returns the Config object that provides configuration for MediaWiki core.
* This may or may not be the same object that is returned by getBootstrapConfig().
*
+ * @since 1.27
* @return Config
*/
public function getMainConfig() {
}
/**
+ * @since 1.27
* @return SiteLookup
*/
public function getSiteLookup() {
}
/**
+ * @since 1.27
* @return SiteStore
*/
public function getSiteStore() {
}
/**
+ * @since 1.28
+ * @return InterwikiLookup
+ */
+ public function getInterwikiLookup() {
+ return $this->getService( 'InterwikiLookup' );
+ }
+
+ /**
+ * @since 1.27
* @return StatsdDataFactory
*/
public function getStatsdDataFactory() {
}
/**
+ * @since 1.27
* @return EventRelayerGroup
*/
public function getEventRelayerGroup() {
}
/**
+ * @since 1.27
* @return SearchEngine
*/
public function newSearchEngine() {
}
/**
+ * @since 1.27
* @return SearchEngineFactory
*/
public function getSearchEngineFactory() {
}
/**
+ * @since 1.27
* @return SearchEngineConfig
*/
public function getSearchEngineConfig() {
}
/**
+ * @since 1.27
* @return SkinFactory
*/
public function getSkinFactory() {
}
/**
+ * @since 1.28
* @return LBFactory
*/
public function getDBLoadBalancerFactory() {
}
/**
+ * @since 1.28
* @return LoadBalancer The main DB load balancer for the local wiki.
*/
public function getDBLoadBalancer() {
}
/**
+ * @since 1.28
* @return WatchedItemStore
*/
public function getWatchedItemStore() {
return $this->getService( 'WatchedItemStore' );
}
+ /**
+ * @since 1.28
+ * @return GenderCache
+ */
+ public function getGenderCache() {
+ return $this->getService( 'GenderCache' );
+ }
+
+ /**
+ * @since 1.28
+ * @return LinkCache
+ */
+ public function getLinkCache() {
+ return $this->getService( 'LinkCache' );
+ }
+
+ /**
+ * @since 1.28
+ * @return LinkRendererFactory
+ */
+ public function getLinkRendererFactory() {
+ return $this->getService( 'LinkRendererFactory' );
+ }
+
+ /**
+ * LinkRenderer instance that can be used
+ * if no custom options are needed
+ *
+ * @since 1.28
+ * @return LinkRenderer
+ */
+ public function getLinkRenderer() {
+ return $this->getService( 'LinkRenderer' );
+ }
+
+ /**
+ * @since 1.28
+ * @return TitleFormatter
+ */
+ public function getTitleFormatter() {
+ return $this->getService( 'TitleFormatter' );
+ }
+
+ /**
+ * @since 1.28
+ * @return TitleParser
+ */
+ public function getTitleParser() {
+ return $this->getService( 'TitleParser' );
+ }
+
///////////////////////////////////////////////////////////////////////////
// NOTE: When adding a service getter here, don't forget to add a test
// case for it in MediaWikiServicesTest::provideGetters() and in
public function getTitle() {
global $wgContLang, $wgForceUIMsgAsContentMsg;
- $code = $this->getLanguage()->getCode();
$title = $this->key;
if (
- $wgContLang->getCode() !== $code
+ !$this->language->equals( $wgContLang )
&& in_array( $this->key, (array)$wgForceUIMsgAsContentMsg )
) {
+ $code = $this->language->getCode();
$title .= '/' . $code;
}
*/
function wfMangleFlashPolicy( $s ) {
# Avoid weird excessive memory usage in PCRE on big articles
- if ( preg_match( '/\<\s*cross-domain-policy\s*\>/i', $s ) ) {
- return preg_replace( '/\<\s*cross-domain-policy\s*\>/i', '<NOT-cross-domain-policy>', $s );
+ if ( preg_match( '/\<\s*cross-domain-policy(?=\s|\>)/i', $s ) ) {
+ return preg_replace( '/\<(\s*)(cross-domain-policy(?=\s|\>))/i', '<$1NOT-$2', $s );
} else {
return $s;
}
// bug 44570: the core page itself may not change, but resources might
$modifiedTimes['sepoch'] = wfTimestamp( TS_MW, time() - $config->get( 'SquidMaxage' ) );
}
- Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes ] );
+ Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes, $this ] );
$maxModified = max( $modifiedTimes );
$this->mLastModified = wfTimestamp( TS_RFC2822, $maxModified );
* @return string
*/
public function getVaryHeader() {
+ // If we vary on cookies, let's make sure it's always included here too.
+ if ( $this->getCacheVaryCookies() ) {
+ $this->addVaryHeader( 'Cookie' );
+ }
+
foreach ( SessionManager::singleton()->getVaryHeaders() as $header => $options ) {
$this->addVaryHeader( $header, $options );
}
$links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED );
}
- // Group JS is only enabled if site JS is enabled.
- $links[] = $this->makeResourceLoaderLink(
- 'user.groups',
- ResourceLoaderModule::TYPE_COMBINED
- );
-
return self::getHtmlFromLoaderLinks( $links );
}
// Per-site custom styles
$moduleStyles[] = 'site';
$moduleStyles[] = 'noscript';
- $moduleStyles[] = 'user.groups';
// Per-user custom styles
if ( $this->getConfig()->get( 'AllowUserCss' ) && $this->getTitle()->isCssSubpage()
* version are hardcoded here
*/
function wfEntryPointCheck( $entryPoint ) {
- $mwVersion = '1.27';
+ $mwVersion = '1.28';
$minimumVersionPHP = '5.5.9';
$phpVersion = PHP_VERSION;
*
* @file
*/
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Auth\PasswordAuthenticationRequest;
/**
* We're now using the HTMLForm object with some customisation to generate the
* @return void
*/
static function profilePreferences( $user, IContextSource $context, &$defaultPreferences ) {
- global $wgAuth, $wgContLang, $wgParser;
+ global $wgAuth, $wgContLang, $wgParser, $wgDisableAuthManager;
$config = $context->getConfig();
// retrieving user name for GENDER and misc.
$canEditPrivateInfo = $user->isAllowed( 'editmyprivateinfo' );
// Actually changeable stuff
+ $realnameChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'realname' )
+ : AuthManager::singleton()->allowsPropertyChange( 'realname' );
$defaultPreferences['realname'] = [
// (not really "private", but still shouldn't be edited without permission)
- 'type' => $canEditPrivateInfo && $wgAuth->allowPropChange( 'realname' ) ? 'text' : 'info',
+ 'type' => $canEditPrivateInfo && $realnameChangeAllowed ? 'text' : 'info',
'default' => $user->getRealName(),
'section' => 'personal/info',
'label-message' => 'yourrealname',
'help-message' => 'prefs-help-realname',
];
- if ( $canEditPrivateInfo && $wgAuth->allowPasswordChange() ) {
+ $allowPasswordChange = $wgDisableAuthManager ? $wgAuth->allowPasswordChange()
+ : AuthManager::singleton()->allowsAuthenticationDataChange(
+ new PasswordAuthenticationRequest(), false );
+ if ( $canEditPrivateInfo && $allowPasswordChange ) {
$link = Linker::link( SpecialPage::getTitleFor( 'ChangePassword' ),
$context->msg( 'prefs-resetpass' )->escaped(), [],
[ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] );
'default' => $oldsigHTML,
'section' => 'personal/signature',
];
+ $nicknameChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'nickname' )
+ : AuthManager::singleton()->allowsPropertyChange( 'nickname' );
$defaultPreferences['nickname'] = [
- 'type' => $wgAuth->allowPropChange( 'nickname' ) ? 'text' : 'info',
+ 'type' => $nicknameChangeAllowed ? 'text' : 'info',
'maxlength' => $config->get( 'MaxSigChars' ),
'label-message' => 'yournick',
'validation-callback' => [ 'Preferences', 'validateSignature' ],
}
$emailAddress = $user->getEmail() ? htmlspecialchars( $user->getEmail() ) : '';
- if ( $canEditPrivateInfo && $wgAuth->allowPropChange( 'emailaddress' ) ) {
+ $emailChangeAllowed = $wgDisableAuthManager ? $wgAuth->allowPropChange( 'emailaddress' )
+ : AuthManager::singleton()->allowsPropertyChange( 'emailaddress' );
+ if ( $canEditPrivateInfo && $emailChangeAllowed ) {
$link = Linker::link(
SpecialPage::getTitleFor( 'ChangeEmail' ),
$context->msg( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->escaped(),
* @return bool|Status|string
*/
static function tryFormSubmit( $formData, $form ) {
- global $wgAuth;
-
$user = $form->getModifiedUser();
$hiddenPrefs = $form->getConfig()->get( 'HiddenPrefs' );
$result = true;
// Fortunately, the realname field is MUCH simpler
// (not really "private", but still shouldn't be edited without permission)
+
if ( !in_array( 'realname', $hiddenPrefs )
&& $user->isAllowed( 'editmyprivateinfo' )
&& array_key_exists( 'realname', $formData )
Hooks::run( 'PreferencesFormPreSave', [ $formData, $form, $user, &$result ] );
}
- $wgAuth->updateExternalDB( $user );
+ MediaWiki\Auth\AuthManager::callLegacyAuthPlugin( 'updateExternalDB', [ $user ] );
$user->saveSettings();
return $result;
// Check if the form should be disabled.
// If it is, the form will be available in read-only to show levels.
$this->mPermErrors = $this->mTitle->getUserPermissionsErrors(
- 'protect', $this->mContext->getUser()
+ 'protect',
+ $this->mContext->getUser(),
+ $this->mContext->getRequest()->wasPosted() ? 'secure' : 'full' // T92357
);
if ( wfReadOnly() ) {
$this->mPermErrors[] = [ 'readonlytext', wfReadOnlyReason() ];
}
$text = $cache->get( $key );
if ( is_string( $text ) ) {
- wfDebug( __METHOD__ . ": got id $textId from cache\n" );
$processCache->set( $key, $text );
return $text;
}
* MediaWiki code base.
*/
+use MediaWiki\Interwiki\ClassicInterwikiLookup;
+use MediaWiki\Linker\LinkRendererFactory;
use MediaWiki\MediaWikiServices;
return [
return $services->getConfigFactory()->makeConfig( 'main' );
},
+ 'InterwikiLookup' => function( MediaWikiServices $services ) {
+ global $wgContLang; // TODO: manage $wgContLang as a service
+ $config = $services->getMainConfig();
+ return new ClassicInterwikiLookup(
+ $wgContLang,
+ ObjectCache::getMainWANInstance(),
+ $config->get( 'InterwikiExpiry' ),
+ $config->get( 'InterwikiCache' ),
+ $config->get( 'InterwikiScopes' ),
+ $config->get( 'InterwikiFallbackSite' )
+ );
+ },
+
'StatsdDataFactory' => function( MediaWikiServices $services ) {
return new BufferingStatsdDataFactory(
rtrim( $services->getMainConfig()->get( 'StatsdMetricPrefix' ), '.' )
return $store;
},
+ 'LinkCache' => function( MediaWikiServices $services ) {
+ return new LinkCache(
+ $services->getTitleFormatter()
+ );
+ },
+
+ 'LinkRendererFactory' => function( MediaWikiServices $services ) {
+ return new LinkRendererFactory(
+ $services->getTitleFormatter()
+ );
+ },
+
+ 'LinkRenderer' => function( MediaWikiServices $services ) {
+ global $wgUser;
+
+ if ( defined( 'MW_NO_SESSION' ) ) {
+ return $services->getLinkRendererFactory()->create();
+ } else {
+ return $services->getLinkRendererFactory()->createForUser( $wgUser );
+ }
+ },
+
+ 'GenderCache' => function( MediaWikiServices $services ) {
+ return new GenderCache();
+ },
+
+ '_MediaWikiTitleCodec' => function( MediaWikiServices $services ) {
+ global $wgContLang;
+
+ return new MediaWikiTitleCodec(
+ $wgContLang,
+ $services->getGenderCache(),
+ $services->getMainConfig()->get( 'LocalInterwikis' )
+ );
+ },
+
+ 'TitleFormatter' => function( MediaWikiServices $services ) {
+ return $services->getService( '_MediaWikiTitleCodec' );
+ },
+
+ 'TitleParser' => function( MediaWikiServices $services ) {
+ return $services->getService( '_MediaWikiTitleCodec' );
+ },
+
///////////////////////////////////////////////////////////////////////////
// NOTE: When adding a service here, don't forget to add a getter function
// in the MediaWikiServices class. The convenience getter should just call
--- /dev/null
+<?php
+namespace MediaWiki\Services;
+
+/**
+ * Interface for salvageable services.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ *
+ * @since 1.28
+ */
+
+/**
+ * SalvageableService defines an interface for services that are able to salvage state from a
+ * previous instance of the same class. The intent is to allow new service instances to re-use
+ * resources that would be expensive to re-create, such as cached data or network connections.
+ *
+ * @note There is no expectation that services will be destroyed when the process (or web request)
+ * terminates.
+ */
+interface SalvageableService {
+
+ /**
+ * Re-uses state from $other. $other must not be used after being passed to salvage(),
+ * and should be considered to be destroyed.
+ *
+ * @note Implementations are responsible for determining what parts of $other can be re-used
+ * safely. In particular, implementations should check that the relevant configuration of
+ * $other is the same as in $this before re-using resources from $other.
+ *
+ * @note Implementations must take care to detach any re-used resources from the original
+ * service instance. If $other is destroyed later, resources that are now used by the
+ * new service instance must not be affected.
+ *
+ * @note If $other is a DestructibleService, implementations should make sure that $other
+ * is in destroyed state after salvage finished. This may be done by calling $other->destroy()
+ * after carefully detaching all relevant resources.
+ *
+ * @param SalvageableService $other The object to salvage state from. $other must have the
+ * exact same type as $this.
+ */
+ public function salvage( SalvageableService $other );
+
+}
*/
private $serviceInstantiators = [];
+ /**
+ * @var boolean[] disabled status, per service name
+ */
+ private $disabled = [];
+
/**
* @var array
*/
}
}
+ /**
+ * Imports all wiring defined in $container. Wiring defined in $container
+ * will override any wiring already defined locally. However, already
+ * existing service instances will be preserved.
+ *
+ * @since 1.28
+ *
+ * @param ServiceContainer $container
+ * @param string[] $skip A list of service names to skip during import
+ */
+ public function importWiring( ServiceContainer $container, $skip = [] ) {
+ $newInstantiators = array_diff_key(
+ $container->serviceInstantiators,
+ array_flip( $skip )
+ );
+
+ $this->serviceInstantiators = array_merge(
+ $this->serviceInstantiators,
+ $newInstantiators
+ );
+ }
+
/**
* Returns true if a service is defined for $name, that is, if a call to getService( $name )
* would return a service instance.
}
$this->serviceInstantiators[$name] = $instantiator;
+ unset( $this->disabled[$name] );
}
/**
public function disableService( $name ) {
$this->resetService( $name );
- $this->redefineService( $name, function() use ( $name ) {
- throw new ServiceDisabledException( $name );
- } );
+ $this->disabled[$name] = true;
}
/**
}
unset( $this->services[$name] );
+ unset( $this->disabled[$name] );
}
/**
* @param string $name The service name
*
* @throws NoSuchServiceException if $name is not a known service.
- * @throws ServiceDisabledException if this container has already been destroyed.
+ * @throws ContainerDisabledException if this container has already been destroyed.
+ * @throws ServiceDisabledException if the requested service has been disabled.
*
* @return object The service instance
*/
throw new ContainerDisabledException();
}
+ if ( isset( $this->disabled[$name] ) ) {
+ throw new ServiceDisabledException( $name );
+ }
+
if ( !isset( $this->services[$name] ) ) {
$this->services[$name] = $this->createService( $name );
}
$this->serviceInstantiators[$name],
array_merge( [ $this ], $this->extraInstantiationParams )
);
+ // NOTE: when adding more wiring logic here, make sure copyWiring() is kept in sync!
} else {
throw new NoSuchServiceException( $name );
}
$wgDebugLogFile = '';
}
+// Disable AuthManager API modules if $wgDisableAuthManager
+if ( $wgDisableAuthManager ) {
+ $wgAPIModules += [
+ 'clientlogin' => 'ApiDisabled',
+ 'createaccount' => 'ApiCreateAccount', // Use the non-AuthManager version
+ 'linkaccount' => 'ApiDisabled',
+ 'unlinkaccount' => 'ApiDisabled',
+ 'changeauthenticationdata' => 'ApiDisabled',
+ 'removeauthenticationdata' => 'ApiDisabled',
+ 'resetpassword' => 'ApiDisabled',
+ ];
+ $wgAPIMetaModules += [
+ 'authmanagerinfo' => 'ApiQueryDisabled',
+ ];
+}
+
// Backwards compatibility with old password limits
if ( $wgMinimalPasswordLength !== false ) {
$wgPasswordPolicy['policies']['default']['MinimalPasswordLength'] = $wgMinimalPasswordLength;
// Reset the global service locator, so any services that have already been created will be
// re-created while taking into account any custom settings and extensions.
-MediaWikiServices::resetGlobalInstance( new GlobalVarConfig() );
+MediaWikiServices::resetGlobalInstance( new GlobalVarConfig(), 'quick' );
// Define a constant that indicates that the bootstrapping of the service locator
// is complete.
$wgRequest->interpolateTitle();
if ( !is_object( $wgAuth ) ) {
- $wgAuth = new AuthPlugin;
+ $wgAuth = $wgDisableAuthManager ? new AuthPlugin : new MediaWiki\Auth\AuthManagerAuthPlugin;
Hooks::run( 'AuthPluginSetup', [ &$wgAuth ] );
}
+if ( !$wgDisableAuthManager &&
+ $wgAuth && !$wgAuth instanceof MediaWiki\Auth\AuthManagerAuthPlugin
+) {
+ MediaWiki\Auth\AuthManager::singleton()->forcePrimaryAuthenticationProviders( [
+ new MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider( [
+ 'authoritative' => false,
+ ] ),
+ new MediaWiki\Auth\AuthPluginPrimaryAuthenticationProvider( $wgAuth ),
+ new MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider( [
+ 'authoritative' => true,
+ ] ),
+ ], '$wgAuth is ' . get_class( $wgAuth ) );
+}
// Set up the session
$ps_session = Profiler::instance()->scopedProfileIn( $fname . '-session' );
$sessionUser = MediaWiki\Session\SessionManager::getGlobalSession()->getUser();
if ( $sessionUser->getId() === 0 && User::isValidUserName( $sessionUser->getName() ) ) {
$ps_autocreate = Profiler::instance()->scopedProfileIn( $fname . '-autocreate' );
- MediaWiki\Session\SessionManager::autoCreateUser( $sessionUser );
+ if ( $wgDisableAuthManager ) {
+ $res = MediaWiki\Session\SessionManager::autoCreateUser( $sessionUser );
+ } else {
+ $res = MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
+ $sessionUser,
+ MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
+ true
+ );
+ }
Profiler::instance()->scopedProfileOut( $ps_autocreate );
+ \MediaWiki\Logger\LoggerFactory::getInstance( 'authmanager' )->info( 'Autocreation attempt', [
+ 'event' => 'autocreate',
+ 'status' => $res,
+ ] );
+ unset( $res );
}
unset( $sessionUser );
}
$this->sv->setResult( $ok, $value );
}
+ /**
+ * Returns the wrapped StatusValue object
+ * @return StatusValue
+ * @since 1.27
+ */
+ public function getStatusValue() {
+ return $this->sv;
+ }
+
/**
* Returns whether the operation completed and didn't have any error or
* warnings
* @file
*/
use MediaWiki\Linker\LinkTarget;
-
+use MediaWiki\Interwiki\InterwikiLookup;
use MediaWiki\MediaWikiServices;
/**
* Avoid usage of this singleton by using TitleValue
* and the associated services when possible.
*
- * @return MediaWikiTitleCodec
+ * @return TitleFormatter
*/
- private static function getMediaWikiTitleCodec() {
- global $wgContLang, $wgLocalInterwikis;
-
- static $titleCodec = null;
- static $titleCodecFingerprint = null;
-
- // $wgContLang and $wgLocalInterwikis may change (especially while testing),
- // make sure we are using the right one. To detect changes over the course
- // of a request, we remember a fingerprint of the config used to create the
- // codec singleton, and re-create it if the fingerprint doesn't match.
- $fingerprint = spl_object_hash( $wgContLang ) . '|' . implode( '+', $wgLocalInterwikis );
-
- if ( $fingerprint !== $titleCodecFingerprint ) {
- $titleCodec = null;
- }
-
- if ( !$titleCodec ) {
- $titleCodec = new MediaWikiTitleCodec(
- $wgContLang,
- GenderCache::singleton(),
- $wgLocalInterwikis
- );
- $titleCodecFingerprint = $fingerprint;
- }
-
- return $titleCodec;
+ private static function getTitleFormatter() {
+ return MediaWikiServices::getInstance()->getTitleFormatter();
}
/**
- * B/C kludge: provide a TitleParser for use by Title.
+ * B/C kludge: provide an InterwikiLookup for use by Title.
* Ideally, Title would have no methods that need this.
* Avoid usage of this singleton by using TitleValue
* and the associated services when possible.
*
- * @return TitleFormatter
+ * @return InterwikiLookup
*/
- private static function getTitleFormatter() {
- // NOTE: we know that getMediaWikiTitleCodec() returns a MediaWikiTitleCodec,
- // which implements TitleFormatter.
- return self::getMediaWikiTitleCodec();
+ private static function getInterwikiLookup() {
+ return MediaWikiServices::getInstance()->getInterwikiLookup();
}
+ /**
+ * @access protected
+ */
function __construct() {
}
*/
public function isLocal() {
if ( $this->isExternal() ) {
- $iw = Interwiki::fetch( $this->mInterwiki );
+ $iw = self::getInterwikiLookup()->fetch( $this->mInterwiki );
if ( $iw ) {
return $iw->isLocal();
}
return false;
}
- return Interwiki::fetch( $this->mInterwiki )->isTranscludable();
+ return self::getInterwikiLookup()->fetch( $this->mInterwiki )->isTranscludable();
}
/**
return false;
}
- return Interwiki::fetch( $this->mInterwiki )->getWikiID();
+ return self::getInterwikiLookup()->fetch( $this->mInterwiki )->getWikiID();
}
/**
* @return string Content model id
*/
public function getContentModel( $flags = 0 ) {
- if ( !$this->mContentModel && $this->getArticleID( $flags ) ) {
+ if ( ( !$this->mContentModel || $flags === Title::GAID_FOR_UPDATE ) &&
+ $this->getArticleID( $flags )
+ ) {
$linkCache = LinkCache::singleton();
$linkCache->addLinkObj( $this ); # in case we already had an article ID
$this->mContentModel = $linkCache->getGoodLinkFieldObj( $this, 'model' );
$query = self::fixUrlQueryArgs( $query, $query2 );
- $interwiki = Interwiki::fetch( $this->mInterwiki );
+ $interwiki = self::getInterwikiLookup()->fetch( $this->mInterwiki );
if ( $interwiki ) {
$namespace = $this->getNsText();
if ( $namespace != '' ) {
if ( $url === false
&& $wgVariantArticlePath
- && $wgContLang->getCode() === $this->getPageLanguage()->getCode()
- && $this->getPageLanguage()->hasVariants()
&& preg_match( '/^variant=([^&]*)$/', $query, $matches )
+ && $this->getPageLanguage()->equals( $wgContLang )
+ && $this->getPageLanguage()->hasVariants()
) {
$variant = urldecode( $matches[1] );
if ( $this->getPageLanguage()->hasVariant( $variant ) ) {
/**
* Purge expired restrictions from the page_restrictions table
+ *
+ * This will purge no more than $wgUpdateRowsPerQuery page_restrictions rows
*/
static function purgeExpiredRestrictions() {
if ( wfReadOnly() ) {
wfGetDB( DB_MASTER ),
__METHOD__,
function ( IDatabase $dbw, $fname ) {
- $dbw->delete(
+ $config = MediaWikiServices::getInstance()->getMainConfig();
+ $ids = $dbw->selectFieldValues(
'page_restrictions',
+ 'pr_id',
[ 'pr_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ],
- $fname
+ $fname,
+ [ 'LIMIT' => $config->get( 'UpdateRowsPerQuery' ) ] // T135470
);
+ if ( $ids ) {
+ $dbw->delete( 'page_restrictions', [ 'pr_id' => $ids ], $fname );
+ }
+ }
+ ) );
+
+ DeferredUpdates::addUpdate( new AtomicSectionUpdate(
+ wfGetDB( DB_MASTER ),
+ __METHOD__,
+ function ( IDatabase $dbw, $fname ) {
$dbw->delete(
'protected_titles',
[ 'pt_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ],
// @note: splitTitleString() is a temporary hack to allow MediaWikiTitleCodec to share
// the parsing code with Title, while avoiding massive refactoring.
// @todo: get rid of secureAndSplit, refactor parsing code.
- $titleParser = self::getMediaWikiTitleCodec();
+ // @note: getTitleParser() returns a TitleParser implementation which does not have a
+ // splitTitleString method, but the only implementation (MediaWikiTitleCodec) does
+ $titleCodec = MediaWikiServices::getInstance()->getTitleParser();
// MalformedTitleException can be thrown here
- $parts = $titleParser->splitTitleString( $dbkey, $this->getDefaultNamespace() );
+ $parts = $titleCodec->splitTitleString( $dbkey, $this->getDefaultNamespace() );
# Fill fields
$this->setFragment( '#' . $parts['fragment'] );
* or WatchedItemStore::loadWatchedItem()
*/
public static function fromUserTitle( $user, $title, $checkRights = User::CHECK_USER_RIGHTS ) {
- // wfDeprecated( __METHOD__, '1.27' );
+ wfDeprecated( __METHOD__, '1.27' );
return new self( $user, $title, self::DEPRECATED_USAGE_TIMESTAMP, (bool)$checkRights );
}
* @deprecated since 1.27 Use WatchedItemStore::resetNotificationTimestamp()
*/
public function resetNotificationTimestamp( $force = '', $oldid = 0 ) {
- // wfDeprecated( __METHOD__, '1.27' );
+ wfDeprecated( __METHOD__, '1.27' );
if ( $this->checkRights && !$this->user->isAllowed( 'editmywatchlist' ) ) {
return;
}
* @deprecated since 1.27 Use WatchedItemStore::addWatchBatch()
*/
public static function batchAddWatch( array $items ) {
- // wfDeprecated( __METHOD__, '1.27' );
+ wfDeprecated( __METHOD__, '1.27' );
if ( !$items ) {
return false;
}
* @return bool
*/
public function addWatch() {
- // wfDeprecated( __METHOD__, '1.27' );
+ wfDeprecated( __METHOD__, '1.27' );
$this->user->addWatch( $this->getTitle(), $this->checkRights );
return true;
}
* @return bool
*/
public function removeWatch() {
- // wfDeprecated( __METHOD__, '1.27' );
+ wfDeprecated( __METHOD__, '1.27' );
if ( $this->checkRights && !$this->user->isAllowed( 'editmywatchlist' ) ) {
return false;
}
* @return bool
*/
public function isWatched() {
- // wfDeprecated( __METHOD__, '1.27' );
+ wfDeprecated( __METHOD__, '1.27' );
return $this->user->isWatched( $this->getTitle(), $this->checkRights );
}
* @deprecated since 1.27 Use WatchedItemStore::duplicateAllAssociatedEntries()
*/
public static function duplicateEntries( Title $oldTitle, Title $newTitle ) {
- // wfDeprecated( __METHOD__, '1.27' );
+ wfDeprecated( __METHOD__, '1.27' );
$store = MediaWikiServices::getInstance()->getWatchedItemStore();
$store->duplicateAllAssociatedEntries( $oldTitle, $newTitle );
}
<?php
use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
-use MediaWiki\MediaWikiServices;
use MediaWiki\Linker\LinkTarget;
use Wikimedia\Assert\Assert;
* @return ScopedCallback to reset the overridden value
* @throws MWException
*/
- public function overrideDeferredUpdatesAddCallableUpdateCallback( $callback ) {
+ public function overrideDeferredUpdatesAddCallableUpdateCallback( callable $callback ) {
if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
throw new MWException(
'Cannot override DeferredUpdates::addCallableUpdate callback in operation.'
);
}
- Assert::parameterType( 'callable', $callback, '$callback' );
-
$previousValue = $this->deferredUpdatesAddCallableUpdateCallback;
$this->deferredUpdatesAddCallableUpdateCallback = $callback;
return new ScopedCallback( function() use ( $previousValue ) {
* @return ScopedCallback to reset the overridden value
* @throws MWException
*/
- public function overrideRevisionGetTimestampFromIdCallback( $callback ) {
+ public function overrideRevisionGetTimestampFromIdCallback( callable $callback ) {
if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
throw new MWException(
'Cannot override Revision::getTimestampFromId callback in operation.'
);
}
- Assert::parameterType( 'callable', $callback, '$callback' );
-
$previousValue = $this->revisionGetTimestampFromIdCallback;
$this->revisionGetTimestampFromIdCallback = $callback;
return new ScopedCallback( function() use ( $previousValue ) {
}
private function uncacheLinkTarget( LinkTarget $target ) {
+ $this->stats->increment( 'WatchedItemStore.uncacheLinkTarget' );
if ( !isset( $this->cacheIndex[$target->getNamespace()][$target->getDBkey()] ) ) {
return;
}
- $this->stats->increment( 'WatchedItemStore.uncacheLinkTarget' );
foreach ( $this->cacheIndex[$target->getNamespace()][$target->getDBkey()] as $key ) {
$this->stats->increment( 'WatchedItemStore.uncacheLinkTarget.items' );
$this->cache->delete( $key );
}
}
+ private function uncacheUser( User $user ) {
+ $this->stats->increment( 'WatchedItemStore.uncacheUser' );
+ foreach ( $this->cacheIndex as $ns => $dbKeyArray ) {
+ foreach ( $dbKeyArray as $dbKey => $userArray ) {
+ if ( isset( $userArray[$user->getId()] ) ) {
+ $this->stats->increment( 'WatchedItemStore.uncacheUser.items' );
+ $this->cache->delete( $userArray[$user->getId()] );
+ }
+ }
+ }
+ }
+
/**
* @param User $user
* @param LinkTarget $target
return $success;
}
+ /**
+ * @param User $user The user to set the timestamp for
+ * @param string $timestamp Set the update timestamp to this value
+ * @param LinkTarget[] $targets List of targets to update. Default to all targets
+ *
+ * @return bool success
+ */
+ public function setNotificationTimestampsForUser( User $user, $timestamp, array $targets = [] ) {
+ // Only loggedin user can have a watchlist
+ if ( $user->isAnon() ) {
+ return false;
+ }
+
+ $dbw = $this->getConnection( DB_MASTER );
+
+ $conds = [ 'wl_user' => $user->getId() ];
+ if ( $targets ) {
+ $batch = new LinkBatch( $targets );
+ $conds[] = $batch->constructSet( 'wl', $dbw );
+ }
+
+ $success = $dbw->update(
+ 'watchlist',
+ [ 'wl_notificationtimestamp' => $dbw->timestamp( $timestamp ) ],
+ $conds,
+ __METHOD__
+ );
+
+ $this->reuseConnection( $dbw );
+
+ $this->uncacheUser( $user );
+
+ return $success;
+ }
+
/**
* @param User $editor The editor that triggered the update. Their notification
* timestamp will not be updated(they have already seen it)
$fname = __METHOD__;
$dbw->onTransactionIdle(
function () use ( $dbw, $timestamp, $watchers, $target, $fname ) {
- $dbw->update( 'watchlist',
- [ /* SET */
- 'wl_notificationtimestamp' => $dbw->timestamp( $timestamp )
- ], [ /* WHERE */
- 'wl_user' => $watchers,
- 'wl_namespace' => $target->getNamespace(),
- 'wl_title' => $target->getDBkey(),
- ], $fname
- );
+ global $wgUpdateRowsPerQuery;
+
+ $watchersChunks = array_chunk( $watchers, $wgUpdateRowsPerQuery );
+ foreach ( $watchersChunks as $watchersChunk ) {
+ $dbw->update( 'watchlist',
+ [ /* SET */
+ 'wl_notificationtimestamp' => $dbw->timestamp( $timestamp )
+ ], [ /* WHERE - TODO Use wl_id T130067 */
+ 'wl_user' => $watchersChunk,
+ 'wl_namespace' => $target->getNamespace(),
+ 'wl_title' => $target->getDBkey(),
+ ], $fname
+ );
+ if ( count( $watchersChunks ) > 1 ) {
+ $dbw->commit( __METHOD__, 'flush' );
+ wfGetLBFactory()->waitForReplication( [ 'wiki' => $dbw->getWikiID() ] );
+ }
+ }
$this->uncacheLinkTarget( $target );
}
);
*/
protected $sessionId = null;
+ /** @var bool Whether this HTTP request is "safe" (even if it is an HTTP post) */
+ protected $markedAsSafe = false;
+
public function __construct() {
$this->requestTime = isset( $_SERVER['REQUEST_TIME_FLOAT'] )
? $_SERVER['REQUEST_TIME_FLOAT'] : microtime( true );
*
* @param string $path The URL path given from the client
* @param array $bases One or more URLs, optionally with $1 at the end
- * @param string $key If provided, the matching key in $bases will be
+ * @param string|bool $key If provided, the matching key in $bases will be
* passed on as the value of this URL parameter
* @return array Array of URL variables to interpolate; empty if no match
*/
* @param mixed $data
*/
public function setSessionData( $key, $data ) {
- return $this->getSession()->set( $key, $data );
+ $this->getSession()->set( $key, $data );
}
/**
public function setIP( $ip ) {
$this->ip = $ip;
}
+
+ /**
+ * Check if this request uses a "safe" HTTP method
+ *
+ * Safe methods are verbs (e.g. GET/HEAD/OPTIONS) used for obtaining content. Such requests
+ * are not expected to mutate content, especially in ways attributable to the client. Verbs
+ * like POST and PUT are typical of non-safe requests which often change content.
+ *
+ * @return bool
+ * @see https://tools.ietf.org/html/rfc7231#section-4.2.1
+ * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
+ * @since 1.28
+ */
+ public function hasSafeMethod() {
+ if ( !isset( $_SERVER['REQUEST_METHOD'] ) ) {
+ return false; // CLI mode
+ }
+
+ return in_array( $_SERVER['REQUEST_METHOD'], [ 'GET', 'HEAD', 'OPTIONS', 'TRACE' ] );
+ }
+
+ /**
+ * Whether this request should be identified as being "safe"
+ *
+ * This means that the client is not requesting any state changes and that database writes
+ * are not inherently required. Ideally, no visible updates would happen at all. If they
+ * must, then they should not be publically attributed to the end user.
+ *
+ * In more detail:
+ * - Cache populations and refreshes MAY occur.
+ * - Private user session updates and private server logging MAY occur.
+ * - Updates to private viewing activity data MAY occur via DeferredUpdates.
+ * - Other updates SHOULD NOT occur (e.g. modifying content assets).
+ *
+ * @return bool
+ * @see https://tools.ietf.org/html/rfc7231#section-4.2.1
+ * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
+ * @since 1.28
+ */
+ public function isSafeRequest() {
+ if ( $this->markedAsSafe && $this->wasPosted() ) {
+ return true; // marked as a "safe" POST
+ }
+
+ return $this->hasSafeMethod();
+ }
+
+ /**
+ * Mark this request as identified as being nullipotent even if it is a POST request
+ *
+ * POST requests are often used due to the need for a client payload, even if the request
+ * is otherwise equivalent to a "safe method" request.
+ *
+ * @see https://tools.ietf.org/html/rfc7231#section-4.2.1
+ * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
+ * @since 1.28
+ */
+ public function markAsSafeRequest() {
+ $this->markedAsSafe = true;
+ }
}
* @file
*/
+if ( ini_get( 'mbstring.func_overload' ) ) {
+ die( 'MediaWiki does not support installations where mbstring.func_overload is non-zero.' );
+}
+
# bug 15461: Make IE8 turn off content sniffing. Everybody else should ignore this
# We're adding it here so that it's *always* set, even for alternate entry
# points and when $wgOut gets disabled or overridden.
* the action is disabled, or null if it's not recognised
* @param string $action
* @param array $overrides
- * @return bool|null|string|callable
+ * @return bool|null|string|callable|Action
*/
final private static function getClass( $action, array $overrides ) {
global $wgActions;
if ( $firstRev ) {
$firstRevUser = $firstRev->getUserText( Revision::FOR_THIS_USER );
if ( $firstRevUser !== '' ) {
- $batch->add( NS_USER, $firstRevUser );
- $batch->add( NS_USER_TALK, $firstRevUser );
+ $firstRevUserTitle = Title::makeTitle( NS_USER, $firstRevUser );
+ $batch->addObj( $firstRevUserTitle );
+ $batch->addObj( $firstRevUserTitle->getTalkPage() );
}
}
if ( $lastRev ) {
$lastRevUser = $lastRev->getUserText( Revision::FOR_THIS_USER );
if ( $lastRevUser !== '' ) {
- $batch->add( NS_USER, $lastRevUser );
- $batch->add( NS_USER_TALK, $lastRevUser );
+ $lastRevUserTitle = Title::makeTitle( NS_USER, $lastRevUser );
+ $batch->addObj( $lastRevUserTitle );
+ $batch->addObj( $lastRevUserTitle->getTalkPage() );
}
}
}
}
+ // Set standard Vary headers so cache varies on cookies and such (T125283)
+ $response->header( $this->getOutput()->getVaryHeader() );
+ if ( $config->get( 'UseKeyHeader' ) ) {
+ $response->header( $this->getOutput()->getKeyHeader() );
+ }
+
$response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' );
// Output may contain user-specific data;
// vary generated content for open sessions on private wikis
return 'rollback';
}
+ /**
+ * Temporarily unused message keys due to T88044/T136375:
+ * - confirm-rollback-top
+ * - confirm-rollback-button
+ * - rollbackfailed
+ * - rollback-missingparam
+ */
+
+ /**
+ * @throws ErrorPageError
+ */
public function onView() {
// TODO: use $this->useTransactionalTimeLimit(); when POST only
wfTransactionalTimeLimit();
- $details = null;
-
$request = $this->getRequest();
$user = $this->getUser();
+ $from = $request->getVal( 'from' );
+ $rev = $this->page->getRevision();
+ if ( $from === null || $from === '' ) {
+ throw new ErrorPageError( 'rollbackfailed', 'rollback-missingparam' );
+ }
+ if ( $from !== $rev->getUserText() ) {
+ throw new ErrorPageError( 'rollbackfailed', 'alreadyrolled', [
+ $this->getTitle()->getPrefixedText(),
+ $from,
+ $rev->getUserText()
+ ] );
+ }
- $result = $this->page->doRollback(
- $request->getVal( 'from' ),
+ $data = null;
+ $errors = $this->page->doRollback(
+ $from,
$request->getText( 'summary' ),
$request->getVal( 'token' ),
$request->getBool( 'bot' ),
- $details,
+ $data,
$this->getUser()
);
- if ( in_array( [ 'actionthrottledtext' ], $result ) ) {
+ if ( in_array( [ 'actionthrottledtext' ], $errors ) ) {
throw new ThrottledError;
}
- if ( isset( $result[0][0] ) &&
- ( $result[0][0] == 'alreadyrolled' || $result[0][0] == 'cantrollback' )
+ if ( isset( $errors[0][0] ) &&
+ ( $errors[0][0] == 'alreadyrolled' || $errors[0][0] == 'cantrollback' )
) {
$this->getOutput()->setPageTitle( $this->msg( 'rollbackfailed' ) );
- $errArray = $result[0];
+ $errArray = $errors[0];
$errMsg = array_shift( $errArray );
$this->getOutput()->addWikiMsgArray( $errMsg, $errArray );
- if ( isset( $details['current'] ) ) {
+ if ( isset( $data['current'] ) ) {
/** @var Revision $current */
- $current = $details['current'];
+ $current = $data['current'];
if ( $current->getComment() != '' ) {
$this->getOutput()->addHTML( $this->msg( 'editcomment' )->rawParams(
}
# NOTE: Permission errors already handled by Action::checkExecute.
-
- if ( $result == [ [ 'readonlytext' ] ] ) {
+ if ( $errors == [ [ 'readonlytext' ] ] ) {
throw new ReadOnlyError;
}
# XXX: Would be nice if ErrorPageError could take multiple errors, and/or a status object.
- # Right now, we only show the first error
- foreach ( $result as $error ) {
+ # Right now, we only show the first error
+ foreach ( $errors as $error ) {
throw new ErrorPageError( 'rollbackfailed', $error[0], array_slice( $error, 1 ) );
}
/** @var Revision $current */
- $current = $details['current'];
- $target = $details['target'];
- $newId = $details['newid'];
+ $current = $data['current'];
+ $target = $data['target'];
+ $newId = $data['newid'];
$this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
$this->getOutput()->setRobotPolicy( 'noindex,nofollow' );
);
$de->showDiff( '', '' );
}
+ return;
}
protected function getDescription() {
--- /dev/null
+<?php
+/**
+ * Copyright © 2016 Brad Jorsch <bjorsch@wikimedia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+
+/**
+ * Create an account with AuthManager
+ *
+ * @ingroup API
+ */
+class ApiAMCreateAccount extends ApiBase {
+
+ public function __construct( ApiMain $main, $action ) {
+ parent::__construct( $main, $action, 'create' );
+ }
+
+ public function getFinalDescription() {
+ // A bit of a hack to append 'api-help-authmanager-general-usage'
+ $msgs = parent::getFinalDescription();
+ $msgs[] = ApiBase::makeMessage( 'api-help-authmanager-general-usage', $this->getContext(), [
+ $this->getModulePrefix(),
+ $this->getModuleName(),
+ $this->getModulePath(),
+ AuthManager::ACTION_CREATE,
+ self::needsToken(),
+ ] );
+ return $msgs;
+ }
+
+ public function execute() {
+ $params = $this->extractRequestParams();
+
+ $this->requireAtLeastOneParameter( $params, 'continue', 'returnurl' );
+
+ if ( $params['returnurl'] !== null ) {
+ $bits = wfParseUrl( $params['returnurl'] );
+ if ( !$bits || $bits['scheme'] === '' ) {
+ $encParamName = $this->encodeParamName( 'returnurl' );
+ $this->dieUsage(
+ "Invalid value '{$params['returnurl']}' for url parameter $encParamName",
+ "badurl_{$encParamName}"
+ );
+ }
+ }
+
+ $helper = new ApiAuthManagerHelper( $this );
+ $manager = AuthManager::singleton();
+
+ // Make sure it's possible to log in
+ if ( !$manager->canCreateAccounts() ) {
+ $this->getResult()->addValue( null, 'createaccount', $helper->formatAuthenticationResponse(
+ AuthenticationResponse::newFail(
+ $this->msg( 'userlogin-cannot-' . AuthManager::ACTION_CREATE )
+ )
+ ) );
+ return;
+ }
+
+ // Perform the create step
+ if ( $params['continue'] ) {
+ $reqs = $helper->loadAuthenticationRequests( AuthManager::ACTION_CREATE_CONTINUE );
+ $res = $manager->continueAccountCreation( $reqs );
+ } else {
+ $reqs = $helper->loadAuthenticationRequests( AuthManager::ACTION_CREATE );
+ if ( $params['preservestate'] ) {
+ $req = $helper->getPreservedRequest();
+ if ( $req ) {
+ $reqs[] = $req;
+ }
+ }
+ $res = $manager->beginAccountCreation( $this->getUser(), $reqs, $params['returnurl'] );
+ }
+
+ $this->getResult()->addValue( null, 'createaccount',
+ $helper->formatAuthenticationResponse( $res ) );
+ }
+
+ public function isReadMode() {
+ return false;
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
+ public function needsToken() {
+ return 'createaccount';
+ }
+
+ public function getAllowedParams() {
+ $ret = ApiAuthManagerHelper::getStandardParams( AuthManager::ACTION_CREATE,
+ 'requests', 'messageformat', 'mergerequestfields', 'preservestate', 'returnurl', 'continue'
+ );
+ $ret['preservestate'][ApiBase::PARAM_HELP_MSG_APPEND][] =
+ 'apihelp-createaccount-param-preservestate';
+ return $ret;
+ }
+
+ public function dynamicParameterDocumentation() {
+ return [ 'api-help-authmanagerhelper-additional-params', AuthManager::ACTION_CREATE ];
+ }
+
+ protected function getExamplesMessages() {
+ return [
+ 'action=createaccount&username=Example&password=ExamplePassword&retype=ExamplePassword'
+ . '&createreturnurl=http://example.org/&createtoken=123ABC'
+ => 'apihelp-createaccount-example-create',
+ ];
+ }
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Account_creation';
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright © 2016 Brad Jorsch <bjorsch@wikimedia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @since 1.27
+ */
+
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\CreateFromLoginAuthenticationRequest;
+
+/**
+ * Helper class for AuthManager-using API modules. Intended for use via
+ * composition.
+ *
+ * @ingroup API
+ */
+class ApiAuthManagerHelper {
+
+ /** @var ApiBase API module, for context and parameters */
+ private $module;
+
+ /** @var string Message output format */
+ private $messageFormat;
+
+ /**
+ * @param ApiBase $module API module, for context and parameters
+ */
+ public function __construct( ApiBase $module ) {
+ $this->module = $module;
+
+ $params = $module->extractRequestParams();
+ $this->messageFormat = isset( $params['messageformat'] ) ? $params['messageformat'] : 'wikitext';
+ }
+
+ /**
+ * Static version of the constructor, for chaining
+ * @param ApiBase $module API module, for context and parameters
+ * @return ApiAuthManagerHelper
+ */
+ public static function newForModule( ApiBase $module ) {
+ return new self( $module );
+ }
+
+ /**
+ * Format a message for output
+ * @param array &$res Result array
+ * @param string $key Result key
+ * @param Message $message
+ */
+ private function formatMessage( array &$res, $key, Message $message ) {
+ switch ( $this->messageFormat ) {
+ case 'none':
+ break;
+
+ case 'wikitext':
+ $res[$key] = $message->setContext( $this->module )->text();
+ break;
+
+ case 'html':
+ $res[$key] = $message->setContext( $this->module )->parseAsBlock();
+ $res[$key] = Parser::stripOuterParagraph( $res[$key] );
+ break;
+
+ case 'raw':
+ $res[$key] = [
+ 'key' => $message->getKey(),
+ 'params' => $message->getParams(),
+ ];
+ break;
+ }
+ }
+
+ /**
+ * Call $manager->securitySensitiveOperationStatus()
+ * @param string $operation Operation being checked.
+ * @throws UsageException
+ */
+ public function securitySensitiveOperation( $operation ) {
+ $status = AuthManager::singleton()->securitySensitiveOperationStatus( $operation );
+ switch ( $status ) {
+ case AuthManager::SEC_OK:
+ return;
+
+ case AuthManager::SEC_REAUTH:
+ $this->module->dieUsage(
+ 'You have not authenticated recently in this session, please reauthenticate.', 'reauthenticate'
+ );
+
+ case AuthManager::SEC_FAIL:
+ $this->module->dieUsage(
+ 'This action is not available as your identify cannot be verified.', 'cannotreauthenticate'
+ );
+
+ default:
+ throw new UnexpectedValueException( "Unknown status \"$status\"" );
+ }
+ }
+
+ /**
+ * Filter out authentication requests by class name
+ * @param AuthenticationRequest[] $reqs Requests to filter
+ * @param string[] $blacklist Class names to remove
+ * @return AuthenticationRequest[]
+ */
+ public static function blacklistAuthenticationRequests( array $reqs, array $blacklist ) {
+ if ( $blacklist ) {
+ $blacklist = array_flip( $blacklist );
+ $reqs = array_filter( $reqs, function ( $req ) use ( $blacklist ) {
+ return !isset( $blacklist[get_class( $req )] );
+ } );
+ }
+ return $reqs;
+ }
+
+ /**
+ * Fetch and load the AuthenticationRequests for an action
+ * @param string $action One of the AuthManager::ACTION_* constants
+ * @return AuthenticationRequest[]
+ */
+ public function loadAuthenticationRequests( $action ) {
+ $params = $this->module->extractRequestParams();
+
+ $manager = AuthManager::singleton();
+ $reqs = $manager->getAuthenticationRequests( $action, $this->module->getUser() );
+
+ // Filter requests, if requested to do so
+ $wantedRequests = null;
+ if ( isset( $params['requests'] ) ) {
+ $wantedRequests = array_flip( $params['requests'] );
+ } elseif ( isset( $params['request'] ) ) {
+ $wantedRequests = [ $params['request'] => true ];
+ }
+ if ( $wantedRequests !== null ) {
+ $reqs = array_filter( $reqs, function ( $req ) use ( $wantedRequests ) {
+ return isset( $wantedRequests[$req->getUniqueId()] );
+ } );
+ }
+
+ // Collect the fields for all the requests
+ $fields = [];
+ foreach ( $reqs as $req ) {
+ $fields += (array)$req->getFieldInfo();
+ }
+
+ // Extract the request data for the fields and mark those request
+ // parameters as used
+ $data = array_intersect_key( $this->module->getRequest()->getValues(), $fields );
+ $this->module->getMain()->markParamsUsed( array_keys( $data ) );
+
+ return AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
+ }
+
+ /**
+ * Format an AuthenticationResponse for return
+ * @param AuthenticationResponse $res
+ * @return array
+ */
+ public function formatAuthenticationResponse( AuthenticationResponse $res ) {
+ $params = $this->module->extractRequestParams();
+
+ $ret = [
+ 'status' => $res->status,
+ ];
+
+ if ( $res->status === AuthenticationResponse::PASS && $res->username !== null ) {
+ $ret['username'] = $res->username;
+ }
+
+ if ( $res->status === AuthenticationResponse::REDIRECT ) {
+ $ret['redirecttarget'] = $res->redirectTarget;
+ if ( $res->redirectApiData !== null ) {
+ $ret['redirectdata'] = $res->redirectApiData;
+ }
+ }
+
+ if ( $res->status === AuthenticationResponse::REDIRECT ||
+ $res->status === AuthenticationResponse::UI ||
+ $res->status === AuthenticationResponse::RESTART
+ ) {
+ $ret += $this->formatRequests( $res->neededRequests );
+ }
+
+ if ( $res->status === AuthenticationResponse::FAIL ||
+ $res->status === AuthenticationResponse::UI ||
+ $res->status === AuthenticationResponse::RESTART
+ ) {
+ $this->formatMessage( $ret, 'message', $res->message );
+ }
+
+ if ( $res->status === AuthenticationResponse::FAIL ||
+ $res->status === AuthenticationResponse::RESTART
+ ) {
+ $this->module->getRequest()->getSession()->set(
+ 'ApiAuthManagerHelper::createRequest',
+ $res->createRequest
+ );
+ $ret['canpreservestate'] = $res->createRequest !== null;
+ } else {
+ $this->module->getRequest()->getSession()->remove( 'ApiAuthManagerHelper::createRequest' );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Fetch the preserved CreateFromLoginAuthenticationRequest, if any
+ * @return CreateFromLoginAuthenticationRequest|null
+ */
+ public function getPreservedRequest() {
+ $ret = $this->module->getRequest()->getSession()->get( 'ApiAuthManagerHelper::createRequest' );
+ return $ret instanceof CreateFromLoginAuthenticationRequest ? $ret : null;
+ }
+
+ /**
+ * Format an array of AuthenticationRequests for return
+ * @param AuthenticationRequest[] $reqs
+ * @return array Will have a 'requests' key, and also 'fields' if $module's
+ * params include 'mergerequestfields'.
+ */
+ public function formatRequests( array $reqs ) {
+ $params = $this->module->extractRequestParams();
+ $mergeFields = !empty( $params['mergerequestfields'] );
+
+ $ret = [ 'requests' => [] ];
+ foreach ( $reqs as $req ) {
+ $describe = $req->describeCredentials();
+ $reqInfo = [
+ 'id' => $req->getUniqueId(),
+ 'metadata' => $req->getMetadata() + [ ApiResult::META_TYPE => 'assoc' ],
+ ];
+ switch ( $req->required ) {
+ case AuthenticationRequest::OPTIONAL:
+ $reqInfo['required'] = 'optional';
+ break;
+ case AuthenticationRequest::REQUIRED:
+ $reqInfo['required'] = 'required';
+ break;
+ case AuthenticationRequest::PRIMARY_REQUIRED:
+ $reqInfo['required'] = 'primary-required';
+ break;
+ }
+ $this->formatMessage( $reqInfo, 'provider', $describe['provider'] );
+ $this->formatMessage( $reqInfo, 'account', $describe['account'] );
+ if ( !$mergeFields ) {
+ $reqInfo['fields'] = $this->formatFields( (array)$req->getFieldInfo() );
+ }
+ $ret['requests'][] = $reqInfo;
+ }
+
+ if ( $mergeFields ) {
+ $fields = AuthenticationRequest::mergeFieldInfo( $reqs );
+ $ret['fields'] = $this->formatFields( $fields );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Clean up a field array for output
+ * @param ApiBase $module For context and parameters 'mergerequestfields'
+ * and 'messageformat'
+ * @param array $fields
+ * @return array
+ */
+ private function formatFields( array $fields ) {
+ static $copy = [
+ 'type' => true,
+ 'value' => true,
+ ];
+
+ $module = $this->module;
+ $retFields = [];
+
+ foreach ( $fields as $name => $field ) {
+ $ret = array_intersect_key( $field, $copy );
+
+ if ( isset( $field['options'] ) ) {
+ $ret['options'] = array_map( function ( $msg ) use ( $module ) {
+ return $msg->setContext( $module )->plain();
+ }, $field['options'] );
+ ApiResult::setArrayType( $ret['options'], 'assoc' );
+ }
+ $this->formatMessage( $ret, 'label', $field['label'] );
+ $this->formatMessage( $ret, 'help', $field['help'] );
+ $ret['optional'] = !empty( $field['optional'] );
+
+ $retFields[$name] = $ret;
+ }
+
+ ApiResult::setArrayType( $retFields, 'assoc' );
+
+ return $retFields;
+ }
+
+ /**
+ * Fetch the standard parameters this helper recognizes
+ * @param string $action AuthManager action
+ * @param string $param... Parameters to use
+ * @return array
+ */
+ public static function getStandardParams( $action, $param /* ... */ ) {
+ $params = [
+ 'requests' => [
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_HELP_MSG => [ 'api-help-authmanagerhelper-requests', $action ],
+ ],
+ 'request' => [
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_REQUIRED => true,
+ ApiBase::PARAM_HELP_MSG => [ 'api-help-authmanagerhelper-request', $action ],
+ ],
+ 'messageformat' => [
+ ApiBase::PARAM_DFLT => 'wikitext',
+ ApiBase::PARAM_TYPE => [ 'html', 'wikitext', 'raw', 'none' ],
+ ApiBase::PARAM_HELP_MSG => 'api-help-authmanagerhelper-messageformat',
+ ],
+ 'mergerequestfields' => [
+ ApiBase::PARAM_DFLT => false,
+ ApiBase::PARAM_HELP_MSG => 'api-help-authmanagerhelper-mergerequestfields',
+ ],
+ 'preservestate' => [
+ ApiBase::PARAM_DFLT => false,
+ ApiBase::PARAM_HELP_MSG => 'api-help-authmanagerhelper-preservestate',
+ ],
+ 'returnurl' => [
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_HELP_MSG => 'api-help-authmanagerhelper-returnurl',
+ ],
+ 'continue' => [
+ ApiBase::PARAM_DFLT => false,
+ ApiBase::PARAM_HELP_MSG => 'api-help-authmanagerhelper-continue',
+ ],
+ ];
+
+ $ret = [];
+ $wantedParams = func_get_args();
+ array_shift( $wantedParams );
+ foreach ( $wantedParams as $name ) {
+ if ( isset( $params[$name] ) ) {
+ $ret[$name] = $params[$name];
+ }
+ }
+ return $ret;
+ }
+}
* @return bool
*/
public function lacksSameOriginSecurity() {
- return $this->getMain()->getRequest()->getVal( 'callback' ) !== null;
+ // Main module has this method overridden
+ // Safety - avoid infinite loop:
+ if ( $this->isMain() ) {
+ ApiBase::dieDebug( __METHOD__, 'base method was called on main module.' );
+ }
+
+ return $this->getMain()->lacksSameOriginSecurity();
}
/**
throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
}
- $errors = $status->getErrorsArray();
+ $errors = $status->getErrorsByType( 'error' );
if ( !$errors ) {
// No errors? Assume the warnings should be treated as errors
- $errors = $status->getWarningsArray();
+ $errors = $status->getErrorsByType( 'warning' );
}
if ( !$errors ) {
// Still no errors? Punt
- $errors = [ [ 'unknownerror-nocode' ] ];
+ $errors = [ [ 'message' => 'unknownerror-nocode', 'params' => [] ] ];
}
// Cannot use dieUsageMsg() because extensions might return custom
// error messages.
- if ( $errors[0] instanceof Message ) {
- $msg = $errors[0];
+ if ( $errors[0]['message'] instanceof Message ) {
+ $msg = $errors[0]['message'];
if ( $msg instanceof IApiMessage ) {
$extraData = $msg->getApiData();
$code = $msg->getApiCode();
$code = $msg->getKey();
}
} else {
- $code = array_shift( $errors[0] );
- $msg = wfMessage( $code, $errors[0] );
+ $code = $errors[0]['message'];
+ $msg = wfMessage( $code, $errors[0]['params'] );
}
if ( isset( ApiBase::$messageMap[$code] ) ) {
// Translate message to code, for backwards compatibility
--- /dev/null
+<?php
+/**
+ * Copyright © 2016 Brad Jorsch <bjorsch@wikimedia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Auth\AuthManager;
+
+/**
+ * Change authentication data with AuthManager
+ *
+ * @ingroup API
+ */
+class ApiChangeAuthenticationData extends ApiBase {
+
+ public function __construct( ApiMain $main, $action ) {
+ parent::__construct( $main, $action, 'changeauth' );
+ }
+
+ public function execute() {
+ if ( !$this->getUser()->isLoggedIn() ) {
+ $this->dieUsage( 'Must be logged in to change authentication data', 'notloggedin' );
+ }
+
+ $helper = new ApiAuthManagerHelper( $this );
+ $manager = AuthManager::singleton();
+
+ // Check security-sensitive operation status
+ $helper->securitySensitiveOperation( 'ChangeCredentials' );
+
+ // Fetch the request
+ $reqs = ApiAuthManagerHelper::blacklistAuthenticationRequests(
+ $helper->loadAuthenticationRequests( AuthManager::ACTION_CHANGE ),
+ $this->getConfig()->get( 'ChangeCredentialsBlacklist' )
+ );
+ if ( count( $reqs ) !== 1 ) {
+ $this->dieUsage( 'Failed to create change request', 'badrequest' );
+ }
+ $req = reset( $reqs );
+
+ // Make the change
+ $status = $manager->allowsAuthenticationDataChange( $req, true );
+ if ( !$status->isGood() ) {
+ $this->dieStatus( $status );
+ }
+ $manager->changeAuthenticationData( $req );
+
+ $this->getResult()->addValue( null, 'changeauthenticationdata', [ 'status' => 'success' ] );
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
+ public function needsToken() {
+ return 'csrf';
+ }
+
+ public function getAllowedParams() {
+ return ApiAuthManagerHelper::getStandardParams( AuthManager::ACTION_CHANGE,
+ 'request'
+ );
+ }
+
+ public function dynamicParameterDocumentation() {
+ return [ 'api-help-authmanagerhelper-additional-params', AuthManager::ACTION_CHANGE ];
+ }
+
+ protected function getExamplesMessages() {
+ return [
+ 'action=changeauthenticationdata' .
+ '&changeauthrequest=MediaWiki%5CAuth%5CPasswordAuthenticationRequest' .
+ '&password=ExamplePassword&retype=ExamplePassword&changeauthtoken=123ABC'
+ => 'apihelp-changeauthenticationdata-example-password',
+ ];
+ }
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Manage_authentication_data';
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright © 2016 Brad Jorsch <bjorsch@wikimedia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\CreateFromLoginAuthenticationRequest;
+
+/**
+ * Log in to the wiki with AuthManager
+ *
+ * @ingroup API
+ */
+class ApiClientLogin extends ApiBase {
+
+ public function __construct( ApiMain $main, $action ) {
+ parent::__construct( $main, $action, 'login' );
+ }
+
+ public function getFinalDescription() {
+ // A bit of a hack to append 'api-help-authmanager-general-usage'
+ $msgs = parent::getFinalDescription();
+ $msgs[] = ApiBase::makeMessage( 'api-help-authmanager-general-usage', $this->getContext(), [
+ $this->getModulePrefix(),
+ $this->getModuleName(),
+ $this->getModulePath(),
+ AuthManager::ACTION_LOGIN,
+ self::needsToken(),
+ ] );
+ return $msgs;
+ }
+
+ public function execute() {
+ $params = $this->extractRequestParams();
+
+ $this->requireAtLeastOneParameter( $params, 'continue', 'returnurl' );
+
+ if ( $params['returnurl'] !== null ) {
+ $bits = wfParseUrl( $params['returnurl'] );
+ if ( !$bits || $bits['scheme'] === '' ) {
+ $encParamName = $this->encodeParamName( 'returnurl' );
+ $this->dieUsage(
+ "Invalid value '{$params['returnurl']}' for url parameter $encParamName",
+ "badurl_{$encParamName}"
+ );
+ }
+ }
+
+ $helper = new ApiAuthManagerHelper( $this );
+ $manager = AuthManager::singleton();
+
+ // Make sure it's possible to log in
+ if ( !$manager->canAuthenticateNow() ) {
+ $this->getResult()->addValue( null, 'clientlogin', $helper->formatAuthenticationResponse(
+ AuthenticationResponse::newFail( $this->msg( 'userlogin-cannot-' . AuthManager::ACTION_LOGIN ) )
+ ) );
+ return;
+ }
+
+ // Perform the login step
+ if ( $params['continue'] ) {
+ $reqs = $helper->loadAuthenticationRequests( AuthManager::ACTION_LOGIN_CONTINUE );
+ $res = $manager->continueAuthentication( $reqs );
+ } else {
+ $reqs = $helper->loadAuthenticationRequests( AuthManager::ACTION_LOGIN );
+ if ( $params['preservestate'] ) {
+ $req = $helper->getPreservedRequest();
+ if ( $req ) {
+ $reqs[] = $req;
+ }
+ }
+ $res = $manager->beginAuthentication( $reqs, $params['returnurl'] );
+ }
+
+ // Remove CreateFromLoginAuthenticationRequest from $res->neededRequests.
+ // It's there so a RESTART treated as UI will work right, but showing
+ // it to the API client is just confusing.
+ $res->neededRequests = ApiAuthManagerHelper::blacklistAuthenticationRequests(
+ $res->neededRequests, [ CreateFromLoginAuthenticationRequest::class ]
+ );
+
+ $this->getResult()->addValue( null, 'clientlogin',
+ $helper->formatAuthenticationResponse( $res ) );
+ }
+
+ public function isReadMode() {
+ return false;
+ }
+
+ public function needsToken() {
+ return 'login';
+ }
+
+ public function getAllowedParams() {
+ return ApiAuthManagerHelper::getStandardParams( AuthManager::ACTION_LOGIN,
+ 'requests', 'messageformat', 'mergerequestfields', 'preservestate', 'returnurl', 'continue'
+ );
+ }
+
+ public function dynamicParameterDocumentation() {
+ return [ 'api-help-authmanagerhelper-additional-params', AuthManager::ACTION_LOGIN ];
+ }
+
+ protected function getExamplesMessages() {
+ return [
+ 'action=clientlogin&username=Example&password=ExamplePassword&'
+ . 'loginreturnurl=http://example.org/&logintoken=123ABC'
+ => 'apihelp-clientlogin-example-login',
+ 'action=clientlogin&logincontinue=1&OATHToken=987654&logintoken=123ABC'
+ => 'apihelp-clientlogin-example-login2',
+ ];
+ }
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Login';
+ }
+}
* Unit to authenticate account registration attempts to the current wiki.
*
* @ingroup API
+ * @deprecated since 1.27, only used when $wgDisableAuthManager is true
*/
class ApiCreateAccount extends ApiBase {
public function execute() {
# outside the control of the end user.
# (and do it here because ApiMain::reportUnusedParams() gets called
# before our ::execute())
- $this->getMain()->getCheck( '_' );
+ $this->getMain()->markParamsUsed( '_' );
}
}
// Bug 66776: wfMangleFlashPolicy() is needed to avoid a nasty bug in
// Flash, but what it does isn't friendly for the API, so we need to
// work around it.
- if ( preg_match( '/\<\s*cross-domain-policy\s*\>/i', $json ) ) {
+ if ( preg_match( '/\<\s*cross-domain-policy(?=\s|\>)/i', $json ) ) {
$json = preg_replace(
- '/\<(\s*cross-domain-policy\s*)\>/i', '\\u003C$1\\u003E', $json
+ '/\<(\s*cross-domain-policy(?=\s|\>))/i', '\\u003C$1', $json
);
}
// just be broken in a useful manner.
if ( $this->getConfig()->get( 'MangleFlashPolicy' ) &&
in_array( 'wfOutputHandler', ob_list_handlers(), true ) &&
- preg_match( '/\<\s*cross-domain-policy\s*\>/i', $text )
+ preg_match( '/\<\s*cross-domain-policy(?=\s|\>)/i', $text )
) {
$this->dieUsage(
'This response cannot be represented using format=php. ' .
--- /dev/null
+<?php
+/**
+ * Copyright © 2016 Brad Jorsch <bjorsch@wikimedia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+
+/**
+ * Link an account with AuthManager
+ *
+ * @ingroup API
+ */
+class ApiLinkAccount extends ApiBase {
+
+ public function __construct( ApiMain $main, $action ) {
+ parent::__construct( $main, $action, 'link' );
+ }
+
+ public function getFinalDescription() {
+ // A bit of a hack to append 'api-help-authmanager-general-usage'
+ $msgs = parent::getFinalDescription();
+ $msgs[] = ApiBase::makeMessage( 'api-help-authmanager-general-usage', $this->getContext(), [
+ $this->getModulePrefix(),
+ $this->getModuleName(),
+ $this->getModulePath(),
+ AuthManager::ACTION_LINK,
+ self::needsToken(),
+ ] );
+ return $msgs;
+ }
+
+ public function execute() {
+ if ( !$this->getUser()->isLoggedIn() ) {
+ $this->dieUsage( 'Must be logged in to link accounts', 'notloggedin' );
+ }
+
+ $params = $this->extractRequestParams();
+
+ $this->requireAtLeastOneParameter( $params, 'continue', 'returnurl' );
+
+ if ( $params['returnurl'] !== null ) {
+ $bits = wfParseUrl( $params['returnurl'] );
+ if ( !$bits || $bits['scheme'] === '' ) {
+ $encParamName = $this->encodeParamName( 'returnurl' );
+ $this->dieUsage(
+ "Invalid value '{$params['returnurl']}' for url parameter $encParamName",
+ "badurl_{$encParamName}"
+ );
+ }
+ }
+
+ $helper = new ApiAuthManagerHelper( $this );
+ $manager = AuthManager::singleton();
+
+ // Check security-sensitive operation status
+ $helper->securitySensitiveOperation( 'LinkAccounts' );
+
+ // Make sure it's possible to link accounts
+ if ( !$manager->canLinkAccounts() ) {
+ $this->getResult()->addValue( null, 'linkaccount', $helper->formatAuthenticationResponse(
+ AuthenticationResponse::newFail( $this->msg( 'userlogin-cannot-' . AuthManager::ACTION_LINK ) )
+ ) );
+ return;
+ }
+
+ // Perform the link step
+ if ( $params['continue'] ) {
+ $reqs = $helper->loadAuthenticationRequests( AuthManager::ACTION_LINK_CONTINUE );
+ $res = $manager->continueAccountLink( $reqs );
+ } else {
+ $reqs = $helper->loadAuthenticationRequests( AuthManager::ACTION_LINK );
+ $res = $manager->beginAccountLink( $this->getUser(), $reqs, $params['returnurl'] );
+ }
+
+ $this->getResult()->addValue( null, 'linkaccount',
+ $helper->formatAuthenticationResponse( $res ) );
+ }
+
+ public function isReadMode() {
+ return false;
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
+ public function needsToken() {
+ return 'csrf';
+ }
+
+ public function getAllowedParams() {
+ return ApiAuthManagerHelper::getStandardParams( AuthManager::ACTION_LINK,
+ 'requests', 'messageformat', 'mergerequestfields', 'returnurl', 'continue'
+ );
+ }
+
+ public function dynamicParameterDocumentation() {
+ return [ 'api-help-authmanagerhelper-additional-params', AuthManager::ACTION_LINK ];
+ }
+
+ protected function getExamplesMessages() {
+ return [
+ 'action=linkaccount&provider=Example&linkreturnurl=http://example.org/&linktoken=123ABC'
+ => 'apihelp-linkaccount-example-link',
+ ];
+ }
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Linkaccount';
+ }
+}
* @file
*/
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
use MediaWiki\Logger\LoggerFactory;
/**
parent::__construct( $main, $action, 'lg' );
}
+ protected function getDescriptionMessage() {
+ if ( $this->getConfig()->get( 'DisableAuthManager' ) ) {
+ return 'apihelp-login-description-nonauthmanager';
+ } elseif ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
+ return 'apihelp-login-description';
+ } else {
+ return 'apihelp-login-description-nobotpasswords';
+ }
+ }
+
/**
* Executes the log-in attempt using the parameters passed. If
* the log-in succeeds, it attaches a cookie to the session
$loginType = 'N/A';
// Check login token
- $token = LoginForm::getLoginToken();
+ $token = $session->getToken( '', 'login' );
if ( $token->wasNew() || !$params['token'] ) {
- $authRes = LoginForm::NEED_TOKEN;
+ $authRes = 'NeedToken';
} elseif ( !$token->match( $params['token'] ) ) {
- $authRes = LoginForm::WRONG_TOKEN;
+ $authRes = 'WrongToken';
}
// Try bot passwords
);
if ( $status->isOK() ) {
$session = $status->getValue();
- $authRes = LoginForm::SUCCESS;
+ $authRes = 'Success';
$loginType = 'BotPassword';
} else {
+ $authRes = 'Failed';
+ $message = $status->getMessage();
LoggerFactory::getInstance( 'authmanager' )->info(
'BotPassword login failed: ' . $status->getWikiText( false, false, 'en' )
);
}
}
- // Normal login
if ( $authRes === false ) {
- $context->setRequest( new DerivativeRequest(
- $this->getContext()->getRequest(),
- [
- 'wpName' => $params['name'],
- 'wpPassword' => $params['password'],
- 'wpDomain' => $params['domain'],
- 'wpLoginToken' => $params['token'],
- 'wpRemember' => ''
- ]
- ) );
- $loginForm = new LoginForm();
- $loginForm->setContext( $context );
- $authRes = $loginForm->authenticateUserData();
- $loginType = 'LoginForm';
+ if ( $this->getConfig()->get( 'DisableAuthManager' ) ) {
+ // Non-AuthManager login
+ $context->setRequest( new DerivativeRequest(
+ $this->getContext()->getRequest(),
+ [
+ 'wpName' => $params['name'],
+ 'wpPassword' => $params['password'],
+ 'wpDomain' => $params['domain'],
+ 'wpLoginToken' => $params['token'],
+ 'wpRemember' => ''
+ ]
+ ) );
+ $loginForm = new LoginForm();
+ $loginForm->setContext( $context );
+ $authRes = $loginForm->authenticateUserData();
+ $loginType = 'LoginForm';
+
+ switch ( $authRes ) {
+ case LoginForm::SUCCESS:
+ $authRes = 'Success';
+ break;
+ case LoginForm::NEED_TOKEN:
+ $authRes = 'NeedToken';
+ break;
+ }
+ } else {
+ // Simplified AuthManager login, for backwards compatibility
+ $manager = AuthManager::singleton();
+ $reqs = AuthenticationRequest::loadRequestsFromSubmission(
+ $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN, $this->getUser() ),
+ [
+ 'username' => $params['name'],
+ 'password' => $params['password'],
+ 'domain' => $params['domain'],
+ 'rememberMe' => true,
+ ]
+ );
+ $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS:
+ if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
+ $warn = 'Main-account login via action=login is deprecated and may stop working ' .
+ 'without warning.';
+ $warn .= ' To continue login with action=login, see [[Special:BotPasswords]].';
+ $warn .= ' To safely continue using main-account login, see action=clientlogin.';
+ } else {
+ $warn = 'Login via action=login is deprecated and may stop working without warning.';
+ $warn .= ' To safely log in, see action=clientlogin.';
+ }
+ $this->setWarning( $warn );
+ $authRes = 'Success';
+ $loginType = 'AuthManager';
+ break;
+
+ case AuthenticationResponse::FAIL:
+ // Hope it's not a PreAuthenticationProvider that failed...
+ $authRes = 'Failed';
+ $message = $res->message;
+ \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+ ->info( __METHOD__ . ': Authentication failed: ' . $message->plain() );
+ break;
+
+ default:
+ $authRes = 'Aborted';
+ break;
+ }
+ }
}
+ $result['result'] = $authRes;
switch ( $authRes ) {
- case LoginForm::SUCCESS:
- $user = $context->getUser();
- $this->getContext()->setUser( $user );
- $user->setCookies( $this->getRequest(), null, true );
+ case 'Success':
+ if ( $this->getConfig()->get( 'DisableAuthManager' ) ) {
+ $user = $context->getUser();
+ $this->getContext()->setUser( $user );
+ $user->setCookies( $this->getRequest(), null, true );
+ } else {
+ $user = $session->getUser();
+ }
ApiQueryInfo::resetTokenCache();
- // Run hooks.
- // @todo FIXME: Split back and frontend from this hook.
- // @todo FIXME: This hook should be placed in the backend
+ // Deprecated hook
$injected_html = '';
Hooks::run( 'UserLoginComplete', [ &$user, &$injected_html ] );
- $result['result'] = 'Success';
$result['lguserid'] = intval( $user->getId() );
$result['lgusername'] = $user->getName();
// point (1.28 at the earliest, and see T121527). They were ok
// when the core cookie-based login was the only thing, but
// CentralAuth broke that a while back and
- // SessionManager/AuthManager are *really* going to break it.
+ // SessionManager/AuthManager *really* break it.
$result['lgtoken'] = $user->getToken();
$result['cookieprefix'] = $this->getConfig()->get( 'CookiePrefix' );
$result['sessionid'] = $session->getId();
break;
- case LoginForm::NEED_TOKEN:
- $result['result'] = 'NeedToken';
- $result['token'] = LoginForm::getLoginToken()->toString();
+ case 'NeedToken':
+ $result['token'] = $token->toString();
$this->setWarning( 'Fetching a token via action=login is deprecated. ' .
'Use action=query&meta=tokens&type=login instead.' );
$this->logFeatureUsage( 'action=login&!lgtoken' );
$result['sessionid'] = $session->getId();
break;
+ case 'WrongToken':
+ break;
+
+ case 'Failed':
+ $result['reason'] = $message->useDatabase( 'false' )->inLanguage( 'en' )->text();
+ break;
+
+ case 'Aborted':
+ $result['reason'] = 'Authentication requires user interaction, ' .
+ 'which is not supported by action=login.';
+ if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
+ $result['reason'] .= ' To be able to login with action=login, see [[Special:BotPasswords]].';
+ $result['reason'] .= ' To continue using main-account login, see action=clientlogin.';
+ } else {
+ $result['reason'] .= ' To log in, see action=clientlogin.';
+ }
+ break;
+
+ // Results from LoginForm for when $wgDisableAuthManager is true
case LoginForm::WRONG_TOKEN:
$result['result'] = 'WrongToken';
break;
$this->getResult()->addValue( null, 'login', $result );
+ if ( $loginType === 'LoginForm' && isset( LoginForm::$statusCodes[$authRes] ) ) {
+ $authRes = LoginForm::$statusCodes[$authRes];
+ }
LoggerFactory::getInstance( 'authmanager' )->info( 'Login attempt', [
'event' => 'login',
- 'successful' => $authRes === LoginForm::SUCCESS,
+ 'successful' => $authRes === 'Success',
'loginType' => $loginType,
- 'status' => LoginForm::$statusCodes[$authRes],
+ 'status' => $authRes,
] );
}
+ public function isDeprecated() {
+ return !$this->getConfig()->get( 'DisableAuthManager' ) &&
+ !$this->getConfig()->get( 'EnableBotPasswords' );
+ }
+
public function mustBePosted() {
return true;
}
*/
private static $Modules = [
'login' => 'ApiLogin',
+ 'clientlogin' => 'ApiClientLogin',
'logout' => 'ApiLogout',
- 'createaccount' => 'ApiCreateAccount',
+ 'createaccount' => 'ApiAMCreateAccount',
+ 'linkaccount' => 'ApiLinkAccount',
+ 'unlinkaccount' => 'ApiRemoveAuthenticationData',
+ 'changeauthenticationdata' => 'ApiChangeAuthenticationData',
+ 'removeauthenticationdata' => 'ApiRemoveAuthenticationData',
+ 'resetpassword' => 'ApiResetPassword',
'query' => 'ApiQuery',
'expandtemplates' => 'ApiExpandTemplates',
'parse' => 'ApiParse',
private $mModuleMgr, $mResult, $mErrorFormatter, $mContinuationManager;
private $mAction;
private $mEnableWrite;
- private $mInternalMode, $mSquidMaxage, $mModule;
+ private $mInternalMode, $mSquidMaxage;
+ /** @var ApiBase */
+ private $mModule;
private $mCacheMode = 'private';
private $mCacheControl = [];
private $mParamsUsed = [];
+ /** @var bool|null Cached return value from self::lacksSameOriginSecurity() */
+ private $lacksSameOriginSecurity = null;
+
/**
* Constructs an instance of ApiMain that utilizes the module and format specified by $request.
*
return $this->mResult;
}
+ /**
+ * Get the security flag for the current request
+ * @return bool
+ */
+ public function lacksSameOriginSecurity() {
+ if ( $this->lacksSameOriginSecurity !== null ) {
+ return $this->lacksSameOriginSecurity;
+ }
+
+ $request = $this->getRequest();
+
+ // JSONP mode
+ if ( $request->getVal( 'callback' ) !== null ) {
+ $this->lacksSameOriginSecurity = true;
+ return true;
+ }
+
+ // Header to be used from XMLHTTPRequest when the request might
+ // otherwise be used for XSS.
+ if ( $request->getHeader( 'Treat-as-Untrusted' ) !== false ) {
+ $this->lacksSameOriginSecurity = true;
+ return true;
+ }
+
+ // Allow extensions to override.
+ $this->lacksSameOriginSecurity = !Hooks::run( 'RequestHasSameOriginSecurity', [ $request ] );
+ return $this->lacksSameOriginSecurity;
+ }
+
/**
* Get the ApiErrorFormatter object associated with current request
* @return ApiErrorFormatter
if ( $this->mInternalMode ) {
$this->executeAction();
} else {
- $start = microtime( true );
$this->executeActionWithErrorHandling();
- if ( $this->isWriteMode() && $this->getRequest()->wasPosted() ) {
- $timeMs = 1000 * max( 0, microtime( true ) - $start );
- $this->getStats()->timing(
- 'api.' . $this->getModuleName() . '.executeTiming', $timeMs );
- }
}
}
$isError = false;
try {
$this->executeAction();
- $this->logRequest( microtime( true ) - $t );
-
+ $runTime = microtime( true ) - $t;
+ $this->logRequest( $runTime );
+ if ( $this->mModule->isWriteMode() && $this->getRequest()->wasPosted() ) {
+ $this->getStats()->timing(
+ 'api.' . $this->mModule->getModuleName() . '.executeTiming', 1000 * $runTime
+ );
+ }
} catch ( Exception $e ) {
$this->handleException( $e );
$this->logRequest( microtime( true ) - $t, $e );
$response = $this->getRequest()->response();
$out = $this->getOutput();
+ $out->addVaryHeader( 'Treat-as-Untrusted' );
+
$config = $this->getConfig();
if ( $config->get( 'VaryOnXFP' ) ) {
TS_MW, time() - $this->getConfig()->get( 'SquidMaxage' )
);
}
- Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes ] );
+ Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes, $this->getOutput() ] );
$lastMod = max( $modifiedTimes );
$return304 = wfTimestamp( TS_MW, $lastMod ) <= $ts->getTimestamp( TS_MW );
}
protected function setRequestExpectations( ApiBase $module ) {
$limits = $this->getConfig()->get( 'TrxProfilerLimits' );
$trxProfiler = Profiler::instance()->getTransactionProfiler();
- if ( $this->getRequest()->wasPosted() ) {
- if ( $module->isWriteMode() ) {
- $trxProfiler->setExpectations( $limits['POST'], __METHOD__ );
- } else {
- $trxProfiler->setExpectations( $limits['POST-nonwrite'], __METHOD__ );
- }
- } else {
+ if ( $this->getRequest()->hasSafeMethod() ) {
$trxProfiler->setExpectations( $limits['GET'], __METHOD__ );
+ } elseif ( $this->getRequest()->wasPosted() && !$module->isWriteMode() ) {
+ $trxProfiler->setExpectations( $limits['POST-nonwrite'], __METHOD__ );
+ $this->getRequest()->markAsSafeRequest();
+ } else {
+ $trxProfiler->setExpectations( $limits['POST'], __METHOD__ );
}
}
return array_keys( $this->mParamsUsed );
}
+ /**
+ * Mark parameters as used
+ * @param string|string[] $params
+ */
+ public function markParamsUsed( $params ) {
+ $this->mParamsUsed += array_fill_keys( (array)$params, true );
+ }
+
/**
* Get a request value, and register the fact that it was used, for logging.
* @param string $name
$tocnumber = &$options['tocnumber'];
$header = $this->msg( 'api-help-datatypes-header' )->parse();
+
+ // Add an additional span with sanitized ID
+ if ( !$this->getConfig()->get( 'ExperimentalHtmlIds' ) ) {
+ $header = Html::element( 'span', [ 'id' => Sanitizer::escapeId( 'main/datatypes' ) ] ) .
+ $header;
+ }
$help['datatypes'] .= Html::rawElement( 'h' . min( 6, $level ),
[ 'id' => 'main/datatypes', 'class' => 'apihelp-header' ],
- Html::element( 'span', [ 'id' => Sanitizer::escapeId( 'main/datatypes' ) ] ) .
$header
);
$help['datatypes'] .= $this->msg( 'api-help-datatypes' )->parseAsBlock();
];
}
+ // Add an additional span with sanitized ID
+ if ( !$this->getConfig()->get( 'ExperimentalHtmlIds' ) ) {
+ $header = Html::element( 'span', [ 'id' => Sanitizer::escapeId( 'main/credits' ) ] ) .
+ $header;
+ }
$header = $this->msg( 'api-credits-header' )->parse();
$help['credits'] .= Html::rawElement( 'h' . min( 6, $level ),
[ 'id' => 'main/credits', 'class' => 'apihelp-header' ],
- Html::element( 'span', [ 'id' => Sanitizer::escapeId( 'main/credits' ) ] ) .
$header
);
$help['credits'] .= $this->msg( 'api-credits' )->useDatabase( false )->parseAsBlock();
$params = $this->extractRequestParams();
// make sure the user is allowed
- if ( !$this->getUser()->isAllowed( 'managechangetags' ) ) {
- $this->dieUsage( "You don't have permission to manage change tags", 'permissiondenied' );
+ if ( $params['operation'] !== 'delete'
+ && !$this->getUser()->isAllowed( 'managechangetags' )
+ ) {
+ $this->dieUsage( "You don't have permission to manage change tags",
+ 'permissiondenied' );
+ } elseif ( !$this->getUser()->isAllowed( 'deletechangetags' ) ) {
+ $this->dieUsage( "You don't have permission to delete change tags",
+ 'permissiondenied' );
}
$result = $this->getResult();
}
}
+ // Rate limit
+ if ( $user->pingLimiter( 'move' ) ) {
+ $this->dieUsageMsg( 'actionthrottledtext' );
+ }
+
// Move the page
$toTitleExists = $toTitle->exists();
$status = $this->movePage( $fromTitle, $toTitle, $params['reason'], !$params['noredirect'] );
* @ingroup API
*/
class ApiOpenSearch extends ApiBase {
+ use SearchApi;
private $format = null;
private $fm = null;
+ /** @var array list of api allowed params */
+ private $allowedParams = null;
+
/**
* Get the output format
*
public function execute() {
$params = $this->extractRequestParams();
$search = $params['search'];
- $limit = $params['limit'];
- $namespaces = $params['namespace'];
$suggest = $params['suggest'];
-
- if ( $params['redirects'] === null ) {
- // Backwards compatibility, don't resolve for JSON.
- $resolveRedir = $this->getFormat() !== 'json';
- } else {
- $resolveRedir = $params['redirects'] === 'resolve';
- }
-
$results = [];
-
if ( !$suggest || $this->getConfig()->get( 'EnableOpenSearchSuggest' ) ) {
// Open search results may be stored for a very long time
$this->getMain()->setCacheMaxAge( $this->getConfig()->get( 'SearchSuggestCacheExpiry' ) );
$this->getMain()->setCacheMode( 'public' );
- $this->search( $search, $limit, $namespaces, $resolveRedir, $results );
+ $results = $this->search( $search, $params );
// Allow hooks to populate extracts and images
Hooks::run( 'ApiOpenSearchSuggest', [ &$results ] );
/**
* Perform the search
- *
- * @param string $search Text to search
- * @param int $limit Maximum items to return
- * @param array $namespaces Namespaces to search
- * @param bool $resolveRedir Whether to resolve redirects
- * @param array &$results Put results here. Keys have to be integers.
+ * @param string $search the search query
+ * @param array $params api request params
+ * @return array search results. Keys are integers.
*/
- protected function search( $search, $limit, $namespaces, $resolveRedir, &$results ) {
- $searchEngine = MediaWikiServices::getInstance()->newSearchEngine();
- $searchEngine->setLimitOffset( $limit );
- $searchEngine->setNamespaces( $namespaces );
+ private function search( $search, array $params ) {
+ $searchEngine = $this->buildSearchEngine( $params );
$titles = $searchEngine->extractTitles( $searchEngine->completionSearchWithVariants( $search ) );
+ $results = [];
if ( !$titles ) {
- return;
+ return $results;
}
// Special pages need unique integer ids in the return list, so we just
// always positive articleIds that non-special pages get.
$nextSpecialPageId = -1;
+ if ( $params['redirects'] === null ) {
+ // Backwards compatibility, don't resolve for JSON.
+ $resolveRedir = $this->getFormat() !== 'json';
+ } else {
+ $resolveRedir = $params['redirects'] === 'resolve';
+ }
+
if ( $resolveRedir ) {
// Query for redirects
$redirects = [];
];
}
}
+
+ return $results;
}
/**
}
public function getAllowedParams() {
- return [
+ if ( $this->allowedParams !== null ) {
+ return $this->allowedParams;
+ }
+ $this->allowedParams = [
'search' => null,
'limit' => [
ApiBase::PARAM_DFLT => $this->getConfig()->get( 'OpenSearchDefaultLimit' ),
],
'warningsaserror' => false,
];
+
+ $profileParam = $this->buildProfileApiParam( SearchEngine::COMPLETION_PROFILE_TYPE,
+ 'apihelp-query+prefixsearch-param-profile' );
+ if ( $profileParam ) {
+ $this->allowedParams['profile'] = $profileParam;
+ }
+ return $this->allowedParams;
+ }
+
+ public function getSearchProfileParams() {
+ if ( isset( $this->getAllowedParams()['profile'] ) ) {
+ return [ SearchEngine::COMPLETION_PROFILE_TYPE => 'profile' ];
+ }
+ return [];
}
protected function getExamplesMessages() {
// Prevent warnings from being reported on these parameters
$main = $this->getMain();
foreach ( $generator->extractRequestParams() as $paramName => $param ) {
- $main->getVal( $generator->encodeParamName( $paramName ) );
+ $main->markParamsUsed( $generator->encodeParamName( $paramName ) );
}
}
*/
private static $QueryMetaModules = [
'allmessages' => 'ApiQueryAllMessages',
+ 'authmanagerinfo' => 'ApiQueryAuthManagerInfo',
'siteinfo' => 'ApiQuerySiteinfo',
'userinfo' => 'ApiQueryUserInfo',
'filerepoinfo' => 'ApiQueryFileRepoInfo',
}
public function isReadMode() {
- // We need to make an exception for ApiQueryTokens so login tokens can
- // be fetched on private wikis. Restrict that exception as much as
- // possible: no other modules allowed, and no pageset parameters
- // either. We do allow the 'rawcontinue' and 'indexpageids' parameters
- // since frameworks might add these unconditionally and they can't
- // expose anything here.
+ // We need to make an exception for certain meta modules that should be
+ // accessible even without the 'read' right. Restrict the exception as
+ // much as possible: no other modules allowed, and no pageset
+ // parameters either. We do allow the 'rawcontinue' and 'indexpageids'
+ // parameters since frameworks might add these unconditionally and they
+ // can't expose anything here.
+ $this->mParams = $this->extractRequestParams();
$params = array_filter(
array_diff_key(
- $this->extractRequestParams() + $this->getPageSet()->extractRequestParams(),
+ $this->mParams + $this->getPageSet()->extractRequestParams(),
[ 'rawcontinue' => 1, 'indexpageids' => 1 ]
)
);
- if ( $params === [ 'meta' => [ 'tokens' ] ] ) {
- return false;
+ if ( array_keys( $params ) !== [ 'meta' ] ) {
+ return true;
+ }
+
+ // Ask each module if it requires read mode. Any true => this returns
+ // true.
+ $modules = [];
+ $this->instantiateModules( $modules, 'meta' );
+ foreach ( $modules as $module ) {
+ if ( $module->isReadMode() ) {
+ return true;
+ }
}
- return true;
+ return false;
}
protected function getExamplesMessages() {
$customiseFilterEnabled = $params['customised'] !== 'all';
if ( $customiseFilterEnabled ) {
global $wgContLang;
- $lang = $langObj->getCode();
$customisedMessages = AllMessagesTablePager::getCustomisedStatuses(
array_map(
[ $langObj, 'ucfirst' ],
$messages_target
),
- $lang,
- $lang != $wgContLang->getCode()
+ $langObj->getCode(),
+ !$langObj->equals( $wgContLang )
);
$customised = $params['customised'] === 'modified';
--- /dev/null
+<?php
+/**
+ * Copyright © 2016 Brad Jorsch <bjorsch@wikimedia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @since 1.27
+ */
+
+use MediaWiki\Auth\AuthManager;
+
+/**
+ * A query action to return meta information about AuthManager state.
+ *
+ * @ingroup API
+ */
+class ApiQueryAuthManagerInfo extends ApiQueryBase {
+
+ public function __construct( ApiQuery $query, $moduleName ) {
+ parent::__construct( $query, $moduleName, 'ami' );
+ }
+
+ public function execute() {
+ $params = $this->extractRequestParams();
+ $helper = new ApiAuthManagerHelper( $this );
+
+ $manager = AuthManager::singleton();
+ $ret = [
+ 'canauthenticatenow' => $manager->canAuthenticateNow(),
+ 'cancreateaccounts' => $manager->canCreateAccounts(),
+ 'canlinkaccounts' => $manager->canLinkAccounts(),
+ ];
+
+ if ( $params['securitysensitiveoperation'] !== null ) {
+ $ret['securitysensitiveoperationstatus'] = $manager->securitySensitiveOperationStatus(
+ $params['securitysensitiveoperation']
+ );
+ }
+
+ if ( $params['requestsfor'] ) {
+ $action = $params['requestsfor'];
+
+ $preservedReq = $helper->getPreservedRequest();
+ if ( $preservedReq ) {
+ $ret += [
+ 'haspreservedstate' => $preservedReq->hasStateForAction( $action ),
+ 'hasprimarypreservedstate' => $preservedReq->hasPrimaryStateForAction( $action ),
+ 'preservedusername' => (string)$preservedReq->username,
+ ];
+ } else {
+ $ret += [
+ 'haspreservedstate' => false,
+ 'hasprimarypreservedstate' => false,
+ 'preservedusername' => '',
+ ];
+ }
+
+ $reqs = $manager->getAuthenticationRequests( $action, $this->getUser() );
+
+ // Filter out blacklisted requests, depending on the action
+ switch ( $action ) {
+ case AuthManager::ACTION_CHANGE:
+ $reqs = ApiAuthManagerHelper::blacklistAuthenticationRequests(
+ $reqs, $this->getConfig()->get( 'ChangeCredentialsBlacklist' )
+ );
+ break;
+ case AuthManager::ACTION_REMOVE:
+ $reqs = ApiAuthManagerHelper::blacklistAuthenticationRequests(
+ $reqs, $this->getConfig()->get( 'RemoveCredentialsBlacklist' )
+ );
+ break;
+ }
+
+ $ret += $helper->formatRequests( $reqs );
+ }
+
+ $this->getResult()->addValue( [ 'query' ], $this->getModuleName(), $ret );
+ }
+
+ public function isReadMode() {
+ return false;
+ }
+
+ public function getAllowedParams() {
+ return [
+ 'securitysensitiveoperation' => null,
+ 'requestsfor' => [
+ ApiBase::PARAM_TYPE => [
+ AuthManager::ACTION_LOGIN,
+ AuthManager::ACTION_LOGIN_CONTINUE,
+ AuthManager::ACTION_CREATE,
+ AuthManager::ACTION_CREATE_CONTINUE,
+ AuthManager::ACTION_LINK,
+ AuthManager::ACTION_LINK_CONTINUE,
+ AuthManager::ACTION_CHANGE,
+ AuthManager::ACTION_REMOVE,
+ AuthManager::ACTION_UNLINK,
+ ],
+ ],
+ ] + ApiAuthManagerHelper::getStandardParams( '', 'mergerequestfields', 'messageformat' );
+ }
+
+ protected function getExamplesMessages() {
+ return [
+ 'action=query&meta=authmanagerinfo&amirequestsfor=' . urlencode( AuthManager::ACTION_LOGIN )
+ => 'apihelp-query+filerepoinfo-example-login',
+ 'action=query&meta=authmanagerinfo&amirequestsfor=' . urlencode( AuthManager::ACTION_LOGIN ) .
+ '&amimergerequestfields=1'
+ => 'apihelp-query+filerepoinfo-example-login-merged',
+ 'action=query&meta=authmanagerinfo&amisecuritysensitiveoperation=foo'
+ => 'apihelp-query+filerepoinfo-example-securitysensitiveoperation',
+ ];
+ }
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Authmanagerinfo';
+ }
+}
* @ingroup API
*/
class ApiQueryPrefixSearch extends ApiQueryGeneratorBase {
+ use SearchApi;
+
+ /** @var array list of api allowed params */
+ private $allowedParams;
+
public function __construct( $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'ps' );
}
$params = $this->extractRequestParams();
$search = $params['search'];
$limit = $params['limit'];
- $namespaces = $params['namespace'];
$offset = $params['offset'];
- $searchEngine = MediaWikiServices::getInstance()->newSearchEngine();
- $searchEngine->setLimitOffset( $limit + 1, $offset );
- $searchEngine->setNamespaces( $namespaces );
+ $searchEngine = $this->buildSearchEngine( $params );
$titles = $searchEngine->extractTitles( $searchEngine->completionSearchWithVariants( $search ) );
if ( $resultPageSet ) {
return $current;
} );
if ( count( $titles ) > $limit ) {
- $this->setContinueEnumParameter( 'offset', $offset + $params['limit'] );
+ $this->setContinueEnumParameter( 'offset', $offset + $limit );
array_pop( $titles );
}
$resultPageSet->populateFromTitles( $titles );
$count = 0;
foreach ( $titles as $title ) {
if ( ++$count > $limit ) {
- $this->setContinueEnumParameter( 'offset', $offset + $params['limit'] );
+ $this->setContinueEnumParameter( 'offset', $offset + $limit );
break;
}
$vals = [
}
public function getAllowedParams() {
- return [
- 'search' => [
- ApiBase::PARAM_TYPE => 'string',
- ApiBase::PARAM_REQUIRED => true,
- ],
- 'namespace' => [
- ApiBase::PARAM_DFLT => NS_MAIN,
- ApiBase::PARAM_TYPE => 'namespace',
- ApiBase::PARAM_ISMULTI => true,
- ],
- 'limit' => [
- ApiBase::PARAM_DFLT => 10,
- ApiBase::PARAM_TYPE => 'limit',
- ApiBase::PARAM_MIN => 1,
- // Non-standard value for compatibility with action=opensearch
- ApiBase::PARAM_MAX => 100,
- ApiBase::PARAM_MAX2 => 200,
- ],
- 'offset' => [
- ApiBase::PARAM_DFLT => 0,
- ApiBase::PARAM_TYPE => 'integer',
- ],
- ];
+ if ( $this->allowedParams !== null ) {
+ return $this->allowedParams;
+ }
+ $this->allowedParams = [
+ 'search' => [
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_REQUIRED => true,
+ ],
+ 'namespace' => [
+ ApiBase::PARAM_DFLT => NS_MAIN,
+ ApiBase::PARAM_TYPE => 'namespace',
+ ApiBase::PARAM_ISMULTI => true,
+ ],
+ 'limit' => [
+ ApiBase::PARAM_DFLT => 10,
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MIN => 1,
+ // Non-standard value for compatibility with action=opensearch
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 200,
+ ],
+ 'offset' => [
+ ApiBase::PARAM_DFLT => 0,
+ ApiBase::PARAM_TYPE => 'integer',
+ ],
+ ];
+ $profileParam = $this->buildProfileApiParam( SearchEngine::COMPLETION_PROFILE_TYPE,
+ 'apihelp-query+prefixsearch-param-profile' );
+ if ( $profileParam ) {
+ $this->allowedParams['profile'] = $profileParam;
+ }
+ return $this->allowedParams;
+ }
+
+ public function getSearchProfileParams() {
+ if ( isset( $this->getAllowedParams()['profile'] ) ) {
+ return [ SearchEngine::COMPLETION_PROFILE_TYPE => 'profile' ];
+ }
+ return [];
}
protected function getExamplesMessages() {
return false;
}
- return $wgUser->getEditToken(
- [ $title->getPrefixedText(), $rev->getUserText() ] );
+ return $wgUser->getEditToken( 'rollback' );
}
protected function run( ApiPageSet $resultPageSet = null ) {
* @ingroup API
*/
class ApiQuerySearch extends ApiQueryGeneratorBase {
+ use SearchApi;
+
+ /** @var array list of api allowed params */
+ private $allowedParams;
/**
* When $wgSearchType is null, $wgSearchAlternatives[0] is null. Null isn't
global $wgContLang;
$params = $this->extractRequestParams();
+ if ( isset( $params['backend'] ) && $params['backend'] == self::BACKEND_NULL_PARAM ) {
+ unset( $params['backend'] );
+ }
+
// Extract parameters
- $limit = $params['limit'];
$query = $params['search'];
$what = $params['what'];
$interwiki = $params['interwiki'];
}
// Create search engine instance and set options
- $type = isset( $params['backend'] ) && $params['backend'] != self::BACKEND_NULL_PARAM ?
- $params['backend'] : null;
- $search = MediaWikiServices::getInstance()->getSearchEngineFactory()->create( $type );
- $search->setLimitOffset( $limit + 1, $params['offset'] );
- $search->setNamespaces( $params['namespace'] );
+ $search = $this->buildSearchEngine( $params );
$search->setFeatureData( 'rewrite', (bool)$params['enablerewrites'] );
$query = $search->transformSearchTerm( $query );
$titles = [];
$count = 0;
$result = $matches->next();
+ $limit = $params['limit'];
while ( $result ) {
if ( ++$count > $limit ) {
}
public function getAllowedParams() {
- $params = [
+ if ( $this->allowedParams !== null ) {
+ return $this->allowedParams;
+ }
+
+ $this->allowedParams = [
'search' => [
ApiBase::PARAM_TYPE => 'string',
ApiBase::PARAM_REQUIRED => true
if ( $alternatives[0] === null ) {
$alternatives[0] = self::BACKEND_NULL_PARAM;
}
- $params['backend'] = [
+ $this->allowedParams['backend'] = [
ApiBase::PARAM_DFLT => $searchConfig->getSearchType(),
ApiBase::PARAM_TYPE => $alternatives,
];
+ // @todo: support profile selection when multiple
+ // backends are available. The solution could be to
+ // merge all possible profiles and let ApiBase
+ // subclasses do the check. Making ApiHelp and ApiSandbox
+ // comprehensive might be more difficult.
+ } else {
+ $profileParam = $this->buildProfileApiParam( SearchEngine::FT_QUERY_INDEP_PROFILE_TYPE,
+ 'apihelp-query+search-param-qiprofile' );
+ if ( $profileParam ) {
+ $this->allowedParams['qiprofile'] = $profileParam;
+ }
}
- return $params;
+ return $this->allowedParams;
+ }
+
+ public function getSearchProfileParams() {
+ if ( isset( $this->getAllowedParams()['qiprofile'] ) ) {
+ return [ SearchEngine::FT_QUERY_INDEP_PROFILE_TYPE => 'qiprofile' ];
+ }
+ return [];
}
protected function getExamplesMessages() {
case 'defaultoptions':
$fit = $this->appendDefaultOptions( $p );
break;
+ case 'uploaddialog':
+ $fit = $this->appendUploadDialog( $p );
+ break;
default:
ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
}
$data = [];
$result = $this->getResult();
- $allGroups = User::getAllGroups();
+ $allGroups = array_values( User::getAllGroups() );
foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
$arr = [
'name' => $group,
foreach ( $groupArr as $type => $rights ) {
if ( isset( $rights[$group] ) ) {
- $groups = array_intersect( $rights[$group], $allGroups );
+ if ( $rights[$group] === true ) {
+ $groups = $allGroups;
+ } else {
+ $groups = array_intersect( $rights[$group], $allGroups );
+ }
if ( $groups ) {
$arr[$type] = $groups;
ApiResult::setArrayType( $arr[$type], 'BCarray' );
return $this->getResult()->addValue( 'query', $property, $options );
}
+ public function appendUploadDialog( $property ) {
+ $config = $this->getConfig()->get( 'UploadDialog' );
+ return $this->getResult()->addValue( 'query', $property, $config );
+ }
+
private function formatParserTags( $item ) {
return "<{$item}>";
}
'variables',
'protocols',
'defaultoptions',
+ 'uploaddialog',
],
ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
],
'emailable',
'gender',
'centralids',
+ 'cancreate',
];
public function __construct( ApiQuery $query, $moduleName ) {
}
} else {
$data[$u]['missing'] = true;
+ if ( isset( $this->prop['cancreate'] ) && !$this->getConfig()->get( 'DisableAuthManager' ) ) {
+ $status = MediaWiki\Auth\AuthManager::singleton()->canCreateAccount( $u );
+ $data[$u]['cancreate'] = $status->isGood();
+ if ( !$status->isGood() ) {
+ $data[$u]['cancreateerror'] = $this->getErrorFormatter()->arrayFromStatus( $status );
+ }
+ }
}
} else {
if ( isset( $this->prop['groups'] ) && isset( $data[$u]['groups'] ) ) {
}
public function getAllowedParams() {
- return [
+ $ret = [
'prop' => [
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_TYPE => [
'emailable',
'gender',
'centralids',
+ // When adding a prop, consider whether it should be added
+ // to self::$publicProps
],
ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
],
ApiBase::PARAM_ISMULTI => true
],
];
+ if ( !$this->getConfig()->get( 'DisableAuthManager' ) ) {
+ $ret['prop'][ApiBase::PARAM_TYPE][] = 'cancreate';
+ }
+ return $ret;
}
protected function getExamplesMessages() {
--- /dev/null
+<?php
+/**
+ * Copyright © 2016 Brad Jorsch <bjorsch@wikimedia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Auth\AuthManager;
+
+/**
+ * Remove authentication data from AuthManager
+ *
+ * @ingroup API
+ */
+class ApiRemoveAuthenticationData extends ApiBase {
+
+ private $authAction;
+ private $operation;
+
+ public function __construct( ApiMain $main, $action ) {
+ parent::__construct( $main, $action );
+
+ $this->authAction = $action === 'unlinkaccount'
+ ? AuthManager::ACTION_UNLINK
+ : AuthManager::ACTION_REMOVE;
+ $this->operation = $action === 'unlinkaccount'
+ ? 'UnlinkAccount'
+ : 'RemoveCredentials';
+ }
+
+ public function execute() {
+ if ( !$this->getUser()->isLoggedIn() ) {
+ $this->dieUsage( 'Must be logged in to remove authentication data', 'notloggedin' );
+ }
+
+ $params = $this->extractRequestParams();
+ $manager = AuthManager::singleton();
+
+ // Check security-sensitive operation status
+ ApiAuthManagerHelper::newForModule( $this )->securitySensitiveOperation( $this->operation );
+
+ // Fetch the request. No need to load from the request, so don't use
+ // ApiAuthManagerHelper's method.
+ $blacklist = $this->authAction === AuthManager::ACTION_REMOVE
+ ? array_flip( $this->getConfig()->get( 'RemoveCredentialsBlacklist' ) )
+ : [];
+ $reqs = array_filter(
+ $manager->getAuthenticationRequests( $this->authAction, $this->getUser() ),
+ function ( $req ) use ( $params, $blacklist ) {
+ return $req->getUniqueId() === $params['request'] &&
+ !isset( $blacklist[get_class( $req )] );
+ }
+ );
+ if ( count( $reqs ) !== 1 ) {
+ $this->dieUsage( 'Failed to create change request', 'badrequest' );
+ }
+ $req = reset( $reqs );
+
+ // Perform the removal
+ $status = $manager->allowsAuthenticationDataChange( $req, true );
+ if ( !$status->isGood() ) {
+ $this->dieStatus( $status );
+ }
+ $manager->changeAuthenticationData( $req );
+
+ $this->getResult()->addValue( null, $this->getModuleName(), [ 'status' => 'success' ] );
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
+ public function needsToken() {
+ return 'csrf';
+ }
+
+ public function getAllowedParams() {
+ return ApiAuthManagerHelper::getStandardParams( $this->authAction,
+ 'request'
+ );
+ }
+
+ protected function getExamplesMessages() {
+ $path = $this->getModulePath();
+ $action = $this->getModuleName();
+ return [
+ "action={$action}&request=FooAuthenticationRequest&token=123ABC"
+ => "apihelp-{$path}-example-simple",
+ ];
+ }
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Manage_authentication_data';
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright © 2016 Brad Jorsch <bjorsch@wikimedia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Auth\AuthManager;
+
+/**
+ * Reset password, with AuthManager
+ *
+ * @ingroup API
+ */
+class ApiResetPassword extends ApiBase {
+
+ private $hasAnyRoutes = null;
+
+ /**
+ * Determine whether any reset routes are available.
+ * @return bool
+ */
+ private function hasAnyRoutes() {
+ if ( $this->hasAnyRoutes === null ) {
+ $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
+ $this->hasAnyRoutes = !empty( $resetRoutes['username'] ) || !empty( $resetRoutes['email'] );
+ }
+ return $this->hasAnyRoutes;
+ }
+
+ protected function getDescriptionMessage() {
+ if ( !$this->hasAnyRoutes() ) {
+ return 'apihelp-resetpassword-description-noroutes';
+ }
+ return parent::getDescriptionMessage();
+ }
+
+ public function execute() {
+ if ( !$this->hasAnyRoutes() ) {
+ $this->dieUsage( 'No password reset routes are available.', 'moduledisabled' );
+ }
+
+ $params = $this->extractRequestParams() + [
+ // Make sure the keys exist even if getAllowedParams didn't define them
+ 'user' => null,
+ 'email' => null,
+ ];
+
+ $this->requireOnlyOneParameter( $params, 'user', 'email' );
+
+ $passwordReset = new PasswordReset( $this->getConfig(), AuthManager::singleton() );
+
+ $status = $passwordReset->isAllowed( $this->getUser(), $params['capture'] );
+ if ( !$status->isOK() ) {
+ $this->dieStatus( Status::wrap( $status ) );
+ }
+
+ $status = $passwordReset->execute(
+ $this->getUser(), $params['user'], $params['email'], $params['capture']
+ );
+ if ( !$status->isOK() ) {
+ $status->value = null;
+ $this->dieStatus( Status::wrap( $status ) );
+ }
+
+ $result = $this->getResult();
+ $result->addValue( [ 'resetpassword' ], 'status', 'success' );
+ if ( $params['capture'] ) {
+ $passwords = $status->getValue() ?: [];
+ ApiResult::setArrayType( $passwords, 'kvp', 'user' );
+ ApiResult::setIndexedTagName( $passwords, 'p' );
+ $result->addValue( [ 'resetpassword' ], 'passwords', $passwords );
+ }
+ }
+
+ public function isWriteMode() {
+ return $this->hasAnyRoutes();
+ }
+
+ public function needsToken() {
+ if ( !$this->hasAnyRoutes() ) {
+ return false;
+ }
+ return 'csrf';
+ }
+
+ public function getAllowedParams() {
+ if ( !$this->hasAnyRoutes() ) {
+ return [];
+ }
+
+ $ret = [
+ 'user' => [
+ ApiBase::PARAM_TYPE => 'user',
+ ],
+ 'email' => [
+ ApiBase::PARAM_TYPE => 'string',
+ ],
+ 'capture' => false,
+ ];
+
+ $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
+ if ( empty( $resetRoutes['username'] ) ) {
+ unset( $ret['user'] );
+ }
+ if ( empty( $resetRoutes['email'] ) ) {
+ unset( $ret['email'] );
+ }
+
+ return $ret;
+ }
+
+ protected function getExamplesMessages() {
+ $ret = [];
+ $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
+
+ if ( !empty( $resetRoutes['username'] ) ) {
+ $ret['action=resetpassword&user=Example&token=123ABC'] = 'apihelp-resetpassword-example-user';
+ }
+ if ( !empty( $resetRoutes['email'] ) ) {
+ $ret['action=resetpassword&user=user@example.com&token=123ABC'] =
+ 'apihelp-resetpassword-example-email';
+ }
+
+ return $ret;
+ }
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Manage_authentication_data';
+ }
+}
$user = $this->getUser();
$params = $this->extractRequestParams();
- // WikiPage::doRollback needs a Web UI token, so get one of those if we
- // validated based on an API rollback token.
- $token = $params['token'];
- if ( $user->matchEditToken( $token, 'rollback', $this->getRequest() ) ) {
- $token = $this->getUser()->getEditToken(
- $this->getWebUITokenSalt( $params ),
- $this->getRequest()
- );
- }
-
$titleObj = $this->getRbTitle( $params );
$pageObj = WikiPage::factory( $titleObj );
$summary = $params['summary'];
$retval = $pageObj->doRollback(
$this->getRbUser( $params ),
$summary,
- $token,
+ $params['token'],
$params['markbot'],
$details,
$user,
$params['tags']
);
+ // We don't care about multiple errors, just report one of them
if ( $retval ) {
- // We don't care about multiple errors, just report one of them
+ if ( isset( $retval[0][0] ) &&
+ ( $retval[0][0] == 'alreadyrolled' || $retval[0][0] == 'cantrollback' )
+ ) {
+ $error = $retval[0];
+ $userMessage = $this->msg( $error[0], array_slice( $error, 1 ) );
+ // dieUsageMsg() doesn't support $extraData
+ $errorCode = $error[0];
+ $errorInfo = isset( ApiBase::$messageMap[$errorCode] ) ?
+ ApiBase::$messageMap[$errorCode]['info'] :
+ $errorCode;
+ $this->dieUsage( $errorInfo, $errorCode, 0, [
+ 'messageHtml' => $userMessage->parseAsBlock()
+ ] );
+ }
+
$this->dieUsageMsg( reset( $retval ) );
}
'pageid' => intval( $details['current']->getPage() ),
'summary' => $details['summary'],
'revid' => intval( $details['newid'] ),
+ // The revision being reverted (previously the current revision of the page)
'old_revid' => intval( $details['current']->getID() ),
+ // The revision being restored (the last revision before revision(s) by the reverted user)
'last_revid' => intval( $details['target']->getID() )
];
+ $oldUser = $details['current']->getUserText( Revision::FOR_THIS_USER );
+ $lastUser = $details['target']->getUserText( Revision::FOR_THIS_USER );
+ $diffUrl = $titleObj->getFullURL( [
+ 'diff' => $info['revid'],
+ 'oldid' => $info['old_revid'],
+ 'diffonly' => '1'
+ ] );
+ $info['messageHtml'] = $this->msg( 'rollback-success-notify' )
+ ->params( $oldUser, $lastUser, $diffUrl )
+ ->parseAsBlock();
+
$this->getResult()->addValue( null, $this->getModuleName(), $info );
}
return 'rollback';
}
- protected function getWebUITokenSalt( array $params ) {
- return [
- $this->getRbTitle( $params )->getPrefixedText(),
- $this->getRbUser( $params )
- ];
- }
-
/**
* @param array $params
*
*
* @file
*/
+use MediaWiki\MediaWikiServices;
/**
* API interface for setting the wl_notificationtimestamp field
}
}
+ $watchedItemStore = MediaWikiServices::getInstance()->getWatchedItemStore();
$apiResult = $this->getResult();
$result = [];
if ( $params['entirewatchlist'] ) {
// Entire watchlist mode: Just update the thing and return a success indicator
- $dbw->update( 'watchlist', [ 'wl_notificationtimestamp' => $timestamp ],
- [ 'wl_user' => $user->getId() ],
- __METHOD__
+ $watchedItemStore->setNotificationTimestampsForUser(
+ $user,
+ $timestamp
);
$result['notificationtimestamp'] = is_null( $timestamp )
if ( $pageSet->getTitles() ) {
// Now process the valid titles
- $lb = new LinkBatch( $pageSet->getTitles() );
- $dbw->update( 'watchlist', [ 'wl_notificationtimestamp' => $timestamp ],
- [ 'wl_user' => $user->getId(), $lb->constructSet( 'wl', $dbw ) ],
- __METHOD__
+ $watchedItemStore->setNotificationTimestampsForUser(
+ $user,
+ $timestamp,
+ $pageSet->getTitles()
);
// Query the results of our update
- $timestamps = [];
- $res = $dbw->select(
- 'watchlist',
- [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
- [ 'wl_user' => $user->getId(), $lb->constructSet( 'wl', $dbw ) ],
- __METHOD__
+ $timestamps = $watchedItemStore->getNotificationTimestampsBatch(
+ $user,
+ $pageSet->getTitles()
);
- foreach ( $res as $row ) {
- $timestamps[$row->wl_namespace][$row->wl_title] = $row->wl_notificationtimestamp;
- }
// Now, put the valid titles into the result
/** @var $title Title */
$user = $this->getUser();
$params = $this->extractRequestParams();
+ if ( $user->isBot() ) { // sanity
+ $this->dieUsage( 'This interface is not supported for bots', 'botsnotsupported' );
+ }
+
$page = $this->getTitleOrPageId( $params );
$title = $page->getTitle();
$status = 'busy';
}
+ $this->getStats()->increment( "editstash.cache_stores.$status" );
+
$this->getResult()->addValue( null, $this->getModuleName(), [ 'status' => $status ] );
}
Hooks::run( 'ParserOutputStashForEdit', [ $page, $content, $editInfo->output ] );
list( $stashInfo, $ttl ) = self::buildStashValue(
- $editInfo->pstContent, $editInfo->output, $editInfo->timestamp
+ $editInfo->pstContent,
+ $editInfo->output,
+ $editInfo->timestamp,
+ $user
);
if ( $stashInfo ) {
$ok = $cache->set( $key, $stashInfo, $ttl );
if ( $ok ) {
-
$logger->debug( "Cached parser output for key '$key'." );
return self::ERROR_NONE;
} else {
return false;
}
+ // Set the time the output was generated
+ $pOut->setCacheTime( wfTimestampNow() );
+
// Build a value to cache with a proper TTL
- list( $stashInfo, $ttl ) = self::buildStashValue( $pstContent, $pOut, $timestamp );
+ list( $stashInfo, $ttl ) = self::buildStashValue( $pstContent, $pOut, $timestamp, $user );
if ( !$stashInfo ) {
$logger->info( "Uncacheable parser output for key '$key' (rev/TTL)." );
return false;
* @return stdClass|bool Returns false on cache miss
*/
public static function checkCache( Title $title, Content $content, User $user ) {
+ if ( $user->isBot() ) {
+ return false; // bots never stash - don't pollute stats
+ }
+
$cache = ObjectCache::getLocalClusterInstance();
$logger = LoggerFactory::getInstance( 'StashEdit' );
$stats = RequestContext::getMain()->getStats();
$stats->increment( 'editstash.cache_hits.presumed_fresh' );
$logger->debug( "Timestamp-based cache hit for key '$key' (age: $age sec)." );
return $editInfo; // assume nothing changed
+ } elseif ( isset( $editInfo->edits ) && $editInfo->edits === $user->getEditCount() ) {
+ // Logged-in user made no local upload/template edits in the meantime
+ $stats->increment( 'editstash.cache_hits.presumed_fresh' );
+ $logger->debug( "Edit count based cache hit for key '$key' (age: $age sec)." );
+ return $editInfo;
+ } elseif ( $user->isAnon()
+ && self::lastEditTime( $user ) < $editInfo->output->getCacheTime()
+ ) {
+ // Logged-out user made no local upload/template edits in the meantime
+ $stats->increment( 'editstash.cache_hits.presumed_fresh' );
+ $logger->debug( "Edit check based cache hit for key '$key' (age: $age sec)." );
+ return $editInfo;
}
$dbr = wfGetDB( DB_SLAVE );
return $editInfo;
}
+ /**
+ * @param User $user
+ * @return string|null TS_MW timestamp or null
+ */
+ private static function lastEditTime( User $user ) {
+ $time = wfGetDB( DB_SLAVE )->selectField(
+ 'recentchanges',
+ 'MAX(rc_timestamp)',
+ [ 'rc_user_text' => $user->getName() ],
+ __METHOD__
+ );
+
+ return wfTimestampOrNull( TS_MW, $time );
+ }
+
/**
* Get the temporary prepared edit stash key for a user
*
* @param User $user User to get parser options from
* @return string
*/
- protected static function getStashKey( Title $title, Content $content, User $user ) {
+ private static function getStashKey( Title $title, Content $content, User $user ) {
$hash = sha1( implode( ':', [
+ // Account for the edit model/text
$content->getModel(),
$content->getDefaultFormat(),
sha1( $content->serialize( $content->getDefaultFormat() ) ),
- $user->getId() ?: md5( $user->getName() ), // account for user parser options
- $user->getId() ? $user->getDBTouched() : '-' // handle preference change races
+ // Account for user name related variables like signatures
+ $user->getId(),
+ md5( $user->getName() )
] ) );
return wfMemcKey( 'prepared-edit', md5( $title->getPrefixedDBkey() ), $hash );
* @param Content $pstContent
* @param ParserOutput $parserOutput
* @param string $timestamp TS_MW
+ * @param User $user
* @return array (stash info array, TTL in seconds) or (null, 0)
*/
- protected static function buildStashValue(
- Content $pstContent, ParserOutput $parserOutput, $timestamp
+ private static function buildStashValue(
+ Content $pstContent, ParserOutput $parserOutput, $timestamp, User $user
) {
- // If an item is renewed, mind the cache TTL determined by config and parser functions
+ // If an item is renewed, mind the cache TTL determined by config and parser functions.
+ // Put an upper limit on the TTL for sanity to avoid extreme template/file staleness.
$since = time() - wfTimestamp( TS_UNIX, $parserOutput->getTimestamp() );
$ttl = min( $parserOutput->getCacheExpiry() - $since, 5 * 60 );
$stashInfo = (object)[
'pstContent' => $pstContent,
'output' => $parserOutput,
- 'timestamp' => $timestamp
+ 'timestamp' => $timestamp,
+ 'edits' => $user->getEditCount()
];
return [ $stashInfo, $ttl ];
}
--- /dev/null
+<?php
+use MediaWiki\MediaWikiServices;
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @since 1.28
+ */
+
+/**
+ * Traits for API components that use a SearchEngine.
+ * @ingroup API
+ */
+trait SearchApi {
+ /**
+ * Build the profile api param definitions.
+ *
+ * @param string $profileType type of profile to customize
+ * @param string $helpMsg i18n message
+ * @param string|null $backendType SearchEngine backend type or null for default engine
+ * @return array|null the api param definition or null if profiles are
+ * not supported by the searchEngine implementation.
+ */
+ public function buildProfileApiParam( $profileType, $helpMsg, $backendType = null ) {
+ $searchEngine = null;
+ if ( $backendType !== null ) {
+ $searchEngine = MediaWikiServices::getInstance()
+ ->getSearchEngineFactory()->create( $backendType );
+ } else {
+ $searchEngine = MediaWikiServices::getInstance()->newSearchEngine();
+ }
+
+ $profiles = $searchEngine->getProfiles( $profileType );
+ if ( $profiles ) {
+ $types = [];
+ $helpMessages = [];
+ $defaultProfile = null;
+ foreach ( $profiles as $profile ) {
+ $types[] = $profile['name'];
+ if ( isset ( $profile['desc-message'] ) ) {
+ $helpMessages[$profile['name']] = $profile['desc-message'];
+ }
+ if ( !empty( $profile['default'] ) ) {
+ $defaultProfile = $profile['name'];
+ }
+ }
+ return [
+ ApiBase::PARAM_TYPE => $types,
+ ApiBase::PARAM_HELP_MSG => $helpMsg,
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => $helpMessages,
+ ApiBase::PARAM_DFLT => $defaultProfile,
+ ];
+ }
+ return null;
+ }
+
+ /**
+ * Build the search engine to use.
+ * If $params is provided then the following searchEngine options
+ * will be set:
+ * - limit: mandatory
+ * - offset: optional, if set limit will be incremented by
+ * one ( to support the continue parameter )
+ * - namespace: mandatory
+ * - search engine profiles defined by SearchApi::getSearchProfileParams()
+ * @param string[]|null API request params (must be sanitized by
+ * ApiBase::extractRequestParams() before)
+ * @return SearchEngine the search engine
+ */
+ public function buildSearchEngine( array $params = null ) {
+ if ( $params != null ) {
+ $type = isset( $params['backend'] ) ? $params['backend'] : null;
+ $searchEngine = MediaWikiServices::getInstance()->getSearchEngineFactory()->create( $type );
+ $limit = $params['limit'];
+ $searchEngine->setNamespaces( $params['namespace'] );
+ $offset = null;
+ if ( isset( $params['offset'] ) ) {
+ // If the API supports offset then it probably
+ // wants to fetch limit+1 so it can check if
+ // more results are available to properly set
+ // the continue param
+ $offset = $params['offset'];
+ $limit += 1;
+ }
+ $searchEngine->setLimitOffset( $limit, $offset );
+ foreach ( $this->getSearchProfileParams() as $type => $param ) {
+ if ( isset( $params[$param] ) ) {
+ $searchEngine->setFeatureData( $type, $params[$param] );
+ }
+ }
+ } else {
+ $searchEngine = MediaWikiServices::getInstance()->newSearchEngine();
+ }
+ return $searchEngine;
+ }
+
+ /**
+ * @return string[] the list of supported search profile types. Key is
+ * the profile type and its associated value is the request param.
+ */
+ abstract public function getSearchProfileParams();
+}
"Гульчатай",
"Ilmira",
"Гизатуллина",
- "Танзиля Кутлугильдина"
+ "Танзиля Кутлугильдина",
+ "Ләйсән"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Документация]]\n* [[mw:API:FAQ|ЧаВО]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Почта таратыу]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API яңылыҡтары]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Хаталар һәм яуаптар]\n</div>\n<strong>Статус:</strong> Был биттә күрһәтелгән бар функциялар ҙа эшләргә тейеш, шулай ҙа API әүҙем эшкәртеү хәлендә тора һәм теләгән бер ваҡытта үҙгәрергә мөмкин. Яңыртылыуҙарҙы һәр саҡ белеп торор өсөн [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ почта таратыу mediawiki-api-announce], ошоға яҙыл.\n\n<strong>Хаталы һоратыуҙар:</strong> Әгәр API хаталы һоратыу алһа, HTTP баш һүҙе «MediaWiki-API-Error» асҡысы менән кире ҡайтарыла, бынан һуң баш һүҙҙең мәғәнәһе һәм хата коды кире ебәреләсәк һәм кире шул уҡ мәғәнәлә кире ҡуйыласаҡ. Киңерәк мәғлүмәтте ошонан ҡара [[mw:API:Errors_and_warnings|API:Хаталар һәм иҫкәртеүҙәр]].\n\n<strong>Тестлау:</strong> API-һоратыуҙарҙы тестлау уңайлы булһын өсөн ҡара. [[Special:ApiSandbox]]",
"apihelp-edit-param-appendtext": "Был тексты биттең аҙағынаса өҫтәгеҙ.$1text алмаштыра.\n$1section -ды файҙаланығыҙ = яңы, яңы бүлек өҫтәү өсөн, ә был параметрға түгел.",
"apihelp-edit-param-undo": "Был версияны кире алырға. $1text,$1prependtext,$1appendtext алмаштыра.",
"apihelp-edit-param-undoafter": "$1undo- нан алып барлыҡ үҙгәртеүҙәрҙе кире алырға. Әгәр ул ҡуйылмаған булһа, бер тикшереүҙе кире алыу ҙа етә.",
- "apihelp-edit-param-redirect": "Автоматик йүнәлтәүҙе рөхсәт итергә.",
+ "apihelp-edit-param-redirect": "Автоматик йүнәлтеүҙе рөхсәт итергә.",
"apihelp-edit-param-contentformat": "Текстҡа ҡуйыу өсөн йөкмәткенең сериализация форматы.",
"apihelp-edit-param-contentmodel": "Яңы йөкмәткенең контент моделе.",
"apihelp-edit-param-token": "Маркер һуңғы параметр сифатында ебәрелергә тейеш, йәки, һәрхәлдә $1text параметрынан һуң.",
"apihelp-query+allfileusages-param-dir": "Һанау йүнәлеше.",
"apihelp-query+allfileusages-example-unique": "Атамаларҙың уҙенсәлекле файлдары исемлеге.",
"apihelp-query+allfileusages-example-unique-generator": "Төшөп ҡалғандарҙы айырып, барлыҡ исем-һылтанмаларҙы алырға.",
+ "apihelp-query+allfileusages-example-generator": "Һылтанмалы биттәр бар.",
"apihelp-query+allimages-description": "Бер-бер артлы бөтә образдарҙы һанап сығырға.",
"apihelp-query+allimages-param-sort": "Сортировкалау үҙенсәлектәре.",
"apihelp-query+allimages-param-dir": "Һанау йүнәлеше.",
"apihelp-query+allredirects-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
"apihelp-query+allredirects-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
"apihelp-query+allredirects-param-namespace": "Һанау өсөн исемдәр арауығы.",
+ "apihelp-query+allredirects-param-limit": "Нисә битте тергеҙергә?",
"apihelp-query+allredirects-param-dir": "Һанау йүнәлеше.",
"apihelp-query+allredirects-example-generator": "Һылтанмалы биттәр бар.",
"apihelp-query+allrevisions-param-start": "Иҫәп күсереү башланған ваҡыт билдәһе",
"apihelp-query+allrevisions-param-end": "Иҫәп күсереү башланған ваҡыт билдәһе",
"apihelp-query+allrevisions-param-user": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
"apihelp-query+allrevisions-param-excludeuser": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
+ "apihelp-query+alltransclusions-param-to": "Һанауҙы туҡтатыу һылтанмаһы атамаһы.",
+ "apihelp-query+alltransclusions-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
+ "apihelp-query+alltransclusions-param-namespace": "Һанау өсөн исемдәр арауығы.",
+ "apihelp-query+alltransclusions-param-limit": "Нисә битте тергеҙергә?",
+ "apihelp-query+alltransclusions-param-dir": "Һанау йүнәлеше.",
"apihelp-query+alltransclusions-example-generator": "Һылтанмалы биттәр бар.",
"apihelp-query+allusers-param-from": "Иҫәп күсереү башланған ваҡыт билдәһе",
"apihelp-query+allusers-param-to": "Иҫәп күсереү башланған ваҡыт билдәһе",
"apihelp-query+allusers-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+ "apihelp-query+allusers-param-dir": "Сортлау йүнәлештәре.",
"apihelp-query+allusers-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
"apihelp-query+backlinks-param-title": "Мөхәриррләү өсөн биттең исеме.<var>$1биттәрҙән</var> бергә файҙаланыу мөмкин түгел.",
"apihelp-query+backlinks-param-pageid": "Бит идентифакторын мөхәррирләү өсөн биттәр. <var>$1title</var> менән бергә ҡулланыла алмайҙар",
"apihelp-compare-param-torev": "Zweite zu vergleichende Version.",
"apihelp-compare-example-1": "Unterschied zwischen Version 1 und 2 abrufen",
"apihelp-createaccount-description": "Erstellen eines neuen Benutzerkontos.",
+ "apihelp-createaccount-param-preservestate": "Falls <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> für <samp>hasprimarypreservedstate</samp> wahr ausgegeben hat, sollten Anfragen, die als <samp>primary-required</samp> markiert wurden, ausgelassen werden. Falls ein nicht-leerer Wert für <samp>preservedusername</samp> zurückgegeben wurde, muss dieser Benutzername für den Parameter <var>username</var> verwendet werden.",
"apihelp-createaccount-param-name": "Benutzername.",
"apihelp-createaccount-param-password": "Passwort (wird ignoriert, wenn <var>$1mailpassword</var> angegeben ist).",
"apihelp-createaccount-param-domain": "Domain für die externe Authentifizierung (optional).",
"apihelp-import-param-namespace": "In diesen Namensraum importieren. Kann nicht zusammen mit <var>$1rootpage</var> verwendet werden.",
"apihelp-import-param-rootpage": "Als Unterseite dieser Seite importieren. Kann nicht zusammen mit <var>$1namespace</var> verwendet werden.",
"apihelp-import-example-import": "Importiere [[meta:Help:ParserFunctions]] mit der kompletten Versionsgeschichte in den Namensraum 100.",
- "apihelp-login-description": "Anmelden und Authentifizierungs-Cookies beziehen.\n\nFalls das Anmelden erfolgreich war, werden die benötigten Cookies im Header der HTTP-Antwort des Servers übermittelt. Bei fehlgeschlagenen Anmeldeversuchen können weitere Versuche gedrosselt werden, um automatische Passwortermittlungsattacken zu verhinden.",
+ "apihelp-login-description": "Anmelden und Authentifizierungs-Cookies beziehen.\n\nDiese Aktion sollte nur in Kombination mit [[Special:BotPasswords]] verwendet werden. Die Verwendung für die Anmeldung beim Hauptkonto ist veraltet und kann ohne Warnung fehlschlagen. Um sich sicher beim Hauptkonto anzumelden, verwende <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
"apihelp-login-param-name": "Benutzername.",
"apihelp-login-param-password": "Passwort.",
"apihelp-login-param-domain": "Domain (optional).",
"apihelp-query+pageswithprop-param-limit": "Die maximale Anzahl zurückzugebender Seiten.",
"apihelp-query+prefixsearch-param-search": "Such-Zeichenfolge.",
"apihelp-query+prefixsearch-param-offset": "Anzahl der zu überspringenden Ergebnisse.",
+ "apihelp-query+prefixsearch-param-profile": "Zu verwendendes Suchprofil.",
"apihelp-query+protectedtitles-param-prop": "Zurückzugebende Eigenschaften:",
"apihelp-query+querypage-param-limit": "Anzahl der zurückzugebenden Ergebnisse.",
"apihelp-query+recentchanges-description": "Listet die letzten Änderungen auf.",
"apihelp-query+search-param-what": "Welcher Suchtyp ausgeführt werden soll.",
"apihelp-query+search-param-info": "Welche Metadaten zurückgegeben werden sollen.",
"apihelp-query+search-param-prop": "Eigenschaften zur Rückgabe:",
+ "apihelp-query+search-param-qiprofile": "Zu verwendendes anfrageunabhängiges Profil (wirkt sich auf den Ranking-Algorithmus aus).",
"apihelp-query+search-paramvalue-prop-wordcount": "Ergänzt den Wortzähler der Seite.",
"apihelp-query+search-param-limit": "Wie viele Seiten insgesamt zurückgegeben werden sollen.",
"apihelp-query+search-example-simple": "Nach <kbd>meaning</kbd> suchen.",
"apihelp-query+usercontribs-paramvalue-prop-ids": "Fügt die Seiten- und Versionskennung hinzu.",
"apihelp-query+usercontribs-paramvalue-prop-timestamp": "Ergänzt den Zeitstempel der Bearbeitung.",
"apihelp-query+usercontribs-paramvalue-prop-comment": "Fügt den Kommentar der Bearbeitung hinzu.",
+ "apihelp-query+usercontribs-paramvalue-prop-patrolled": "Markiert kontrollierte Bearbeitungen.",
+ "apihelp-query+usercontribs-paramvalue-prop-tags": "Listet die Markierungen für die Bearbeitung auf.",
"apihelp-query+userinfo-paramvalue-prop-blockinfo": "Markiert, ob der aktuelle Benutzer gesperrt ist, von wem und aus welchem Grund.",
"apihelp-query+userinfo-paramvalue-prop-editcount": "Ergänzt den Bearbeitungszähler des aktuellen Benutzers.",
"apihelp-query+userinfo-paramvalue-prop-realname": "Fügt den bürgerlichen Namen des Benutzers hinzu.",
"apihelp-query+users-paramvalue-prop-implicitgroups": "Listet alle Gruppen auf, bei denen der Benutzer automatisch Mitglied ist.",
"apihelp-query+users-paramvalue-prop-rights": "Listet alle Rechte auf, die jeder Benutzer hat.",
"apihelp-query+users-paramvalue-prop-editcount": "Ergänzt den Bearbeitungszähler des Benutzers.",
+ "apihelp-query+users-param-users": "Eine Liste der Benutzer, für die Informationen abgerufen werden sollen.",
"apihelp-query+users-example-simple": "Gibt Informationen für den Benutzer <kbd>Example</kbd> zurück.",
+ "apihelp-query+watchlist-param-user": "Listet nur Änderungen von diesem Benutzer auf.",
+ "apihelp-query+watchlist-param-excludeuser": "Listet keine Änderungen von diesem Benutzer auf.",
"apihelp-query+watchlist-param-prop": "Zusätzlich zurückzugebende Eigenschaften:",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "Ergänzt die Versions- und Seitenkennungen.",
+ "apihelp-query+watchlist-paramvalue-prop-title": "Ergänzt den Titel der Seite.",
+ "apihelp-query+watchlist-paramvalue-prop-flags": "Ergänzt die Markierungen für die Bearbeitungen.",
"apihelp-query+watchlist-paramvalue-prop-user": "Ergänzt den Benutzer, der die Bearbeitung ausgeführt hat.",
"apihelp-query+watchlist-paramvalue-prop-userid": "Ergänzt die Kennung des Benutzers, der die Bearbeitung ausgeführt hat.",
"apihelp-query+watchlist-paramvalue-prop-comment": "Ergänzt den Kommentar der Bearbeitung.",
"@metadata": {
"authors": [
"Gorizon",
- "Mirzali"
+ "Mirzali",
+ "Kumkumuk"
]
},
+ "apihelp-block-description": "Enê karberi bloqe ke",
"apihelp-createaccount-param-name": "Nameyê karberi.",
"apihelp-delete-description": "Pele bestere.",
"apihelp-disabled-description": "Eno modul aktiv niyo.",
"apihelp-feedrecentchanges-param-hidebots": "Vurnayışanê botan bınımne.",
"apihelp-feedrecentchanges-param-hideanons": "Vurnayışanê karberanê anoniman bınımne.",
"apihelp-feedrecentchanges-param-hideliu": "Vurnayışanê karberanê qeydınan bınımne.",
+ "apihelp-feedrecentchanges-param-tagfilter": "Filtrey etiketi",
+ "apihelp-feedrecentchanges-example-simple": "Vurnayışê peyênan bıvin",
+ "apihelp-feedrecentchanges-example-30days": "Peyni vurnayışanê 30 raco bımosne",
"apihelp-login-param-name": "Nameyê karberi.",
"apihelp-login-param-password": "Parola.",
"apihelp-login-param-domain": "Domain (optional).",
"apihelp-block-example-ip-simple": "Block IP address <kbd>192.0.2.5</kbd> for three days with reason <kbd>First strike</kbd>.",
"apihelp-block-example-user-complex": "Block user <kbd>Vandal</kbd> indefinitely with reason <kbd>Vandalism</kbd>, and prevent new account creation and email sending.",
+ "apihelp-changeauthenticationdata-description": "Change authentication data for the current user.",
+ "apihelp-changeauthenticationdata-example-password": "Attempt to change the current user's password to <kbd>ExamplePassword</kbd>.",
+
"apihelp-checktoken-description": "Check the validity of a token from <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
"apihelp-checktoken-param-type": "Type of token being tested.",
"apihelp-checktoken-param-token": "Token to test.",
"apihelp-clearhasmsg-description": "Clears the <code>hasmsg</code> flag for the current user.",
"apihelp-clearhasmsg-example-1": "Clear the <code>hasmsg</code> flag for the current user.",
+ "apihelp-clientlogin-description": "Log in to the wiki using the interactive flow.",
+ "apihelp-clientlogin-example-login": "Start the process of logging in to the wiki as user <kbd>Example</kbd> with password <kbd>ExamplePassword</kbd>.",
+ "apihelp-clientlogin-example-login2": "Continue logging in after a <samp>UI</samp> response for two-factor auth, supplying an <var>OATHToken</var> of <kbd>987654</kbd>.",
+
"apihelp-compare-description": "Get the difference between 2 pages.\n\nA revision number, a page title, or a page ID for both \"from\" and \"to\" must be passed.",
"apihelp-compare-param-fromtitle": "First title to compare.",
"apihelp-compare-param-fromid": "First page ID to compare.",
"apihelp-compare-example-1": "Create a diff between revision 1 and 2.",
"apihelp-createaccount-description": "Create a new user account.",
+ "apihelp-createaccount-param-preservestate": "If <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> returned true for <samp>hasprimarypreservedstate</samp>, requests marked as <samp>primary-required</samp> should be omitted. If it returned a non-empty value for <samp>preservedusername</samp>, that username must be used for the <var>username</var> parameter.",
+ "apihelp-createaccount-example-create": "Start the process of creating user <kbd>Example</kbd> with password <kbd>ExamplePassword</kbd>.",
"apihelp-createaccount-param-name": "Username.",
"apihelp-createaccount-param-password": "Password (ignored if <var>$1mailpassword</var> is set).",
"apihelp-createaccount-param-domain": "Domain for external authentication (optional).",
"apihelp-import-param-rootpage": "Import as subpage of this page. Cannot be used together with <var>$1namespace</var>.",
"apihelp-import-example-import": "Import [[meta:Help:ParserFunctions]] to namespace 100 with full history.",
- "apihelp-login-description": "Log in and get authentication cookies.\n\nIn the event of a successful log-in, the needed cookies will be included in the HTTP response headers. In the event of a failed log-in, further attempts may be throttled to limit automated password guessing attacks.",
+ "apihelp-linkaccount-description": "Link an account from a third-party provider to the current user.",
+ "apihelp-linkaccount-example-link": "Start the process of linking to an account from <kbd>Example</kbd>.",
+
+ "apihelp-login-description": "Log in and get authentication cookies.\n\nThis action should only be used in combination with [[Special:BotPasswords]]; use for main-account login is deprecated and may fail without warning. To safely log in to the main account, use <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
+ "apihelp-login-description-nobotpasswords": "Log in and get authentication cookies.\n\nThis action is deprecated and may fail without warning. To safely log in, use <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
+ "apihelp-login-description-nonauthmanager": "Log in and get authentication cookies.\n\nIn the event of a successful log-in, the needed cookies will be included in the HTTP response headers. In the event of a failed log-in, further attempts may be throttled to limit automated password guessing attacks.",
"apihelp-login-param-name": "User name.",
"apihelp-login-param-password": "Password.",
"apihelp-login-param-domain": "Domain (optional).",
"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+authmanagerinfo-description": "Retrieve information about the current authentication status.",
+ "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Test whether the user's current authentication status is sufficient for the specified security-sensitive operation.",
+ "apihelp-query+authmanagerinfo-param-requestsfor": "Fetch information about the authentication requests needed for the specified authentication action.",
+ "apihelp-query+filerepoinfo-example-login": "Fetch the requests that may be used when beginning a login.",
+ "apihelp-query+filerepoinfo-example-login-merged": "Fetch the requests that may be used when beginning a login, with form fields merged.",
+ "apihelp-query+filerepoinfo-example-securitysensitiveoperation": "Test whether authentication is sufficient for action <kbd>foo</kbd>.",
+
"apihelp-query+backlinks-description": "Find all pages that link to the given page.",
"apihelp-query+backlinks-param-title": "Title to search. Cannot be used together with <var>$1pageid</var>.",
"apihelp-query+backlinks-param-pageid": "Page ID to search. Cannot be used together with <var>$1title</var>.",
"apihelp-query+prefixsearch-param-limit": "Maximum number of results to return.",
"apihelp-query+prefixsearch-param-offset": "Number of results to skip.",
"apihelp-query+prefixsearch-example-simple": "Search for page titles beginning with <kbd>meaning</kbd>.",
+ "apihelp-query+prefixsearch-param-profile": "Search profile to use.",
"apihelp-query+protectedtitles-description": "List all titles protected from creation.",
"apihelp-query+protectedtitles-param-namespace": "Only list titles in these namespaces.",
"apihelp-query+search-param-what": "Which type of search to perform.",
"apihelp-query+search-param-info": "Which metadata to return.",
"apihelp-query+search-param-prop": "Which properties to return:",
+ "apihelp-query+search-param-qiprofile": "Query independent profile to use (affects ranking algorithm).",
"apihelp-query+search-paramvalue-prop-size": "Adds the size of the page in bytes.",
"apihelp-query+search-paramvalue-prop-wordcount": "Adds the word count of the page.",
"apihelp-query+search-paramvalue-prop-timestamp": "Adds the timestamp of when the page was last edited.",
"apihelp-query+siteinfo-paramvalue-prop-variables": "Returns a list of variable IDs.",
"apihelp-query+siteinfo-paramvalue-prop-protocols": "Returns a list of protocols that are allowed in external links.",
"apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Returns the default values for user preferences.",
+ "apihelp-query+siteinfo-paramvalue-prop-uploaddialog": "Returns the upload dialog configuration.",
"apihelp-query+siteinfo-param-filteriw": "Return only local or only nonlocal entries of the interwiki map.",
"apihelp-query+siteinfo-param-showalldb": "List all database servers, not just the one lagging the most.",
"apihelp-query+siteinfo-param-numberingroup": "Lists the number of users in user groups.",
"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-paramvalue-prop-cancreate": "Indicates whether an account for valid but unregistered usernames can be created.",
"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+watchlistraw-example-simple": "List pages on the current user's watchlist.",
"apihelp-query+watchlistraw-example-generator": "Fetch page info for pages on the current user's watchlist.",
+ "apihelp-removeauthenticationdata-description": "Remove authentication data for the current user.",
+ "apihelp-removeauthenticationdata-example-simple": "Attempt to remove the current user's data for <kbd>FooAuthenticationRequest</kbd>.",
+
+ "apihelp-resetpassword-description": "Send a password reset email to a user.",
+ "apihelp-resetpassword-description-noroutes": "No password reset routes are available.\n\nEnable routes in <var>[[mw:Manual:$wgPasswordResetRoutes|$wgPasswordResetRoutes]]</var> to use this module.",
+ "apihelp-resetpassword-param-user": "User being reset.",
+ "apihelp-resetpassword-param-email": "Email address of the user being reset.",
+ "apihelp-resetpassword-param-capture": "Return the temporary passwords that were sent. Requires the <code>passwordreset</code> user right.",
+ "apihelp-resetpassword-example-user": "Send a password reset email to user <kbd>Example</kbd>.",
+ "apihelp-resetpassword-example-email": "Send a password reset email for all users with email address <kbd>user@example.com</kbd>.",
+
"apihelp-revisiondelete-description": "Delete and undelete revisions.",
"apihelp-revisiondelete-param-type": "Type of revision deletion being performed.",
"apihelp-revisiondelete-param-target": "Page title for the revision deletion, if required for the type.",
"apihelp-undelete-example-page": "Undelete page <kbd>Main Page</kbd>.",
"apihelp-undelete-example-revisions": "Undelete two revisions of page <kbd>Main Page</kbd>.",
+ "apihelp-unlinkaccount-description": "Remove a linked third-party account from the current user.",
+ "apihelp-unlinkaccount-example-simple": "Attempt to remove the current user's link for the provider associated with <kbd>FooAuthenticationRequest</kbd>.",
+
"apihelp-upload-description": "Upload a file, or get the status of pending uploads.\n\nSeveral methods are available:\n* Upload file contents directly, using the <var>$1file</var> parameter.\n* Upload the file in pieces, using the <var>$1filesize</var>, <var>$1chunk</var>, and <var>$1offset</var> parameters.\n* Have the MediaWiki server fetch a file from a URL, using the <var>$1url</var> parameter.\n* Complete an earlier upload that failed due to warnings, using the <var>$1filekey</var> parameter.\nNote that the HTTP POST must be done as a file upload (i.e. using <code>multipart/form-data</code>) when sending the <var>$1file</var>.",
"apihelp-upload-param-filename": "Target filename.",
"apihelp-upload-param-comment": "Upload comment. Also used as the initial page text for new files if <var>$1text</var> is not specified.",
"api-help-right-apihighlimits": "Use higher limits in API queries (slow queries: $1; fast queries: $2). The limits for slow queries also apply to multivalue parameters.",
"api-help-open-in-apisandbox": "<small>[open in sandbox]</small>",
+ "api-help-authmanager-general-usage": "The general procedure to use this module is:\n# Fetch the fields available from <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> with <kbd>amirequestsfor=$4</kbd>, and a <kbd>$5</kbd> token from <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.\n# Present the fields to the user, and obtain their submission.\n# Post to this module, supplying <var>$1returnurl</var> and any relevant fields.\n# Check the <samp>status</samp> in the response.\n#* If you received <samp>PASS</samp> or <samp>FAIL</samp>, you're done. The operation either succeeded or it didn't.\n#* If you received <samp>UI</samp>, present the new fields to the user and obtain their submission. Then post to this module with <var>$1continue</var> and the relevant fields set, and repeat step 4.\n#* If you received <samp>REDIRECT</samp>, direct the user to the <samp>redirecttarget</samp> and wait for the return to <var>$1returnurl</var>. Then post to this module with <var>$1continue</var> and any fields passed to the return URL, and repeat step 4.\n#* If you received <samp>RESTART</samp>, that means the authentication worked but we don't have a linked user account. You might treat this as <samp>UI</samp> or as <samp>FAIL</samp>.",
+ "api-help-authmanagerhelper-requests": "Only use these authentication requests, by the <samp>id</samp> returned from <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> with <kbd>amirequestsfor=$1</kbd> or from a previous response from this module.",
+ "api-help-authmanagerhelper-request": "Use this authentication request, by the <samp>id</samp> returned from <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> with <kbd>amirequestsfor=$1</kbd>.",
+ "api-help-authmanagerhelper-messageformat": "Format to use for returning messages.",
+ "api-help-authmanagerhelper-mergerequestfields": "Merge field information for all authentication requests into one array.",
+ "api-help-authmanagerhelper-preservestate": "Preserve state from a previous failed login attempt, if possible.",
+ "api-help-authmanagerhelper-returnurl": "Return URL for third-party authentication flows, must be absolute. Either this or <var>$1continue</var> is required.\n\nUpon receiving a <samp>REDIRECT</samp> response, you will typically open a browser or web view to the specified <samp>redirecttarget</samp> URL for a third-party authentication flow. When that completes, the third party will send the browser or web view to this URL. You should extract any query or POST parameters from the URL and pass them as a <var>$1continue</var> request to this API module.",
+ "api-help-authmanagerhelper-continue": "This request is a continuation after an earlier <samp>UI</samp> or <samp>REDIRECT</samp> response. Either this or <var>$1returnurl</var> is required.",
+ "api-help-authmanagerhelper-additional-params": "This module accepts additional parameters depending on the available authentication requests. Use <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> with <kbd>amirequestsfor=$1</kbd> (or a previous response from this module, if applicable) to determine the requests available and the fields that they use.",
+
"api-credits-header": "Credits",
"api-credits": "API developers:\n* Yuri Astrakhan (creator, lead developer Sep 2006–Sep 2007)\n* Roan Kattouw (lead developer Sep 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Brad Jorsch (lead developer 2013–present)\n\nPlease send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org\nor file a bug report at https://phabricator.wikimedia.org/."
}
{
"@metadata": {
"authors": [
- "Robin van der Vliet"
+ "Robin van der Vliet",
+ "Renardo"
]
},
+ "apihelp-main-param-format": "La formo de la eligaĵo.",
+ "apihelp-block-description": "Forbari uzulon.",
+ "apihelp-block-param-user": "Salutnomo, IP-adreso aŭ IP-adresa intervalo forbarota.",
+ "apihelp-block-param-expiry": "Eksvalidiĝa tempo. Ĝi povas esti relativa (ekz. <kbd>5 months</kbd> aŭ <kbd>2 weeks</kbd> aŭ absoluta (ekz. <kbd>2014-09-18T12:34:56Z</kbd>). Se vi indikas <kbd>infinite</kbd> (senfine), <kbd>indefinite</kbd> (nedifinite) aŭ <kbd>never</kbd> (neniam), la forbaro neniam eksvalidiĝos.",
"apihelp-createaccount-param-name": "Uzantnomo.",
"apihelp-delete-description": "Forigi paĝon.",
+ "apihelp-edit-param-minor": "Redakteto.",
"apihelp-edit-example-edit": "Redakti paĝon.",
+ "apihelp-feedrecentchanges-param-hideminor": "Kaŝi redaktetojn.",
+ "apihelp-feedrecentchanges-param-hidebots": "Kaŝi robotajn ŝanĝojn.",
+ "apihelp-feedrecentchanges-param-hideanons": "Kaŝi redaktojn de anonimuloj.",
+ "apihelp-feedrecentchanges-param-hideliu": "Kaŝi redaktojn de ensalutintaj uzantoj.",
+ "apihelp-feedrecentchanges-param-hidepatrolled": "Kaŝi reviziitajn ŝanĝojn.",
+ "apihelp-feedrecentchanges-param-hidemyself": "Kaŝi redaktojn de la nun ensalutinta uzulo (= vi).",
+ "apihelp-feedrecentchanges-param-hidecategorization": "Kaŝi ŝanĝojn de kategoria aneco.",
+ "apihelp-feedrecentchanges-example-simple": "Montri ĵusajn ŝanĝojn.",
+ "apihelp-filerevert-description": "Restarigi malnovan version de dosiero.",
+ "apihelp-filerevert-param-comment": "Alŝuta komento.",
"apihelp-login-param-name": "Uzantnomo.",
"apihelp-login-param-password": "Pasvorto.",
"apihelp-login-example-login": "Ensaluti."
"AlvaroMolina",
"Ciencia Al Poder",
"Lemondoge",
- "Mgpena"
+ "Mgpena",
+ "Rubentl134",
+ "2axterix2"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentación]]\n* [[mw:API:FAQ|Preguntas frecuentes]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lista de correos]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API de anuncios]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Errores y peticiones]\n</div>\n<strong>Estado:</strong> Todas las características que se muestran en esta página debería funcionar, pero la API aún está en desarrollo activo y puede cambiar en cualquier momento. Suscríbete a [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la lista de correo de mediawiki-api-announce] para estar al día de las actualizaciones.\n\n<strong>Solicitudes erróneas:</strong> Cuando se envían solicitudes erróneas a la API, se envía un encabezado HTTP con la clave \"MediaWiki-API-Error\" y ambos valores, del encabezado y el código de error, se establecerán en el mismo valor. Para más información, véase [[mw:API:Errors_and_warnings|API: Errores y advertencias]].\n\n<strong>Pruebas:</strong> para facilitar las pruebas de solicitudes a la API, consulta [[Special:ApiSandbox]].",
"apihelp-query+allusers-param-limit": "Cuántos nombres de usuario se devolverán.",
"apihelp-query+allusers-param-activeusers": "Solo listar usuarios activos en {{PLURAL:$1|el último día|los $1 últimos días}}.",
"apihelp-query+allusers-example-Y": "Listar usuarios que empiecen por <kbd>Y</kbd>.",
+ "apihelp-query+filerepoinfo-example-login": "Captura de las solicitudes que puede ser utilizadas al comienzo de inicio de sesión.",
"apihelp-query+backlinks-param-pageid": "Identificador de página que buscar. No puede usarse junto con <var>$1title</var>",
+ "apihelp-query+backlinks-param-filterredir": "Cómo filtrar redirecciones. Si se establece a <kbd>nonredirects</kbd> cuando está activo <var>$1redirect</var>, esto sólo se aplica al segundo nivel.",
"apihelp-query+backlinks-param-limit": "Cuántas páginas en total se devolverán. Si está activo <var>$1redirect</var>, el límite aplica a cada nivel por separado (lo que significa que se pueden devolver hasta 2 * <var>$1limit</var> resultados).",
"apihelp-query+backlinks-example-simple": "Mostrar enlaces a <kbd>Main page</kbd>.",
"apihelp-query+backlinks-example-generator": "Obtener información acerca de las páginas enlazadas a <kbd>Main page</kbd>.",
"apihelp-query+blocks-param-prop": "Qué propiedades se obtendrán:",
"apihelp-query+blocks-paramvalue-prop-userid": "Añade el identificador del usuario bloqueado.",
"apihelp-query+blocks-paramvalue-prop-timestamp": "Añade la fecha y hora de cuando se aplicó el bloque.",
+ "apihelp-query+blocks-paramvalue-prop-reason": "Añade la razón dada para el bloqueo.",
"apihelp-query+blocks-example-simple": "Listar bloques.",
"apihelp-query+categories-param-prop": "Qué propiedades adicionales obtener para cada categoría:",
"apihelp-query+categories-param-show": "Qué tipo de categorías mostrar.",
"apihelp-unblock-description": "Desbloquear un usuario.",
"apihelp-unblock-param-user": "Nombre de usuario, dirección IP o rango de direcciones IP para desbloquear. No se puede utilizar junto con <var>$1id</var>.",
"apihelp-unblock-param-reason": "Motivo del desbloqueo.",
+ "apihelp-unblock-example-id": "Desbloquear el bloqueo de ID #<kbd>105</kbd>",
"apihelp-unblock-example-user": "Desbloquear al usuario <kbd>Bob</kbd> con el motivo <kbd>Sorry Bob</kbd>",
"apihelp-undelete-param-reason": "Motivo de la restauración.",
"apihelp-undelete-example-revisions": "Restaurar dos revisiones de la página <kbd>Main Page</kbd>.",
"Umherirrender",
"Elfix",
"Lbayle",
- "Verdy p"
+ "Verdy p",
+ "Yasten",
+ "Trial"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentation]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Liste de diffusion]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annonces de l’API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bogues et demandes]\n</div>\n<strong>État :</strong> Toutes les fonctionnalités affichées sur cette page devraient fonctionner, mais l’API est encore en cours de développement et peut changer à tout moment. Inscrivez-vous à [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la liste de diffusion mediawiki-api-announce] pour être informé des mises à jour.\n\n<strong>Requêtes erronées :</strong> Si des requêtes erronées sont envoyées à l’API, un en-tête HTTP sera renvoyé avec la clé « MediaWiki-API-Error ». La valeur de cet en-tête et le code d’erreur renvoyé prendront la même valeur. Pour plus d’information, voyez [[mw:API:Errors_and_warnings|API: Errors and warnings]].\n\n<strong>Test :</strong> Pour faciliter le test des requêtes de l’API, voyez [[Special:ApiSandbox]].",
"apihelp-block-param-watchuser": "Surveiller les pages utilisateur et de discussion de l’utilisateur ou de l’adresse IP.",
"apihelp-block-example-ip-simple": "Bloquer l’adresse IP <kbd>192.0.2.5</kbd> pour trois jours avec le motif <kbd>Premier avertissement</kbd>.",
"apihelp-block-example-user-complex": "Bloquer indéfiniment l’utilisateur <kbd>Vandal</kbd> avec le motif <kbd>Vandalism</kbd>, et empêcher la création de nouveau compte et l'envoi de courriel.",
+ "apihelp-changeauthenticationdata-description": "Modifier les données d’authentification pour l’utilisateur actuel.",
+ "apihelp-changeauthenticationdata-example-password": "Tentative de modification du mot de passe de l’utilisateur actuel en <kbd>ExempleMotDePasse</kbd>.",
"apihelp-checktoken-description": "Vérifier la validité d'un jeton de <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
"apihelp-checktoken-param-type": "Type de jeton testé",
"apihelp-checktoken-param-token": "Jeton à tester.",
"apihelp-checktoken-example-simple": "Tester la validité d'un jeton de <kbd>csrf</kbd>.",
"apihelp-clearhasmsg-description": "Efface le drapeau <code>hasmsg</code> pour l’utilisateur courant.",
"apihelp-clearhasmsg-example-1": "Effacer le drapeau <code>hasmsg</code> pour l’utilisateur courant",
+ "apihelp-clientlogin-description": "Se connecter au wiki en utilisant le flux interactif.",
+ "apihelp-clientlogin-example-login": "Commencer le processus de connexion au wiki en tant qu’utilisateur <kbd>Exemple</kbd> avec le mot de passe <kbd>ExempleMotDePasse</kbd>.",
+ "apihelp-clientlogin-example-login2": "Continuer la connexion après une réponse de l’<samp>IHM</samp> pour l’authentification à deux facteurs, en fournissant un <var>OATHToken</var> valant <kbd>987654</kbd>.",
"apihelp-compare-description": "Obtenir la différence entre 2 pages.\n\nVous devez passer un numéro de révision, un titre de page, ou un ID de page, à la fois pour « from » et « to ».",
"apihelp-compare-param-fromtitle": "Premier titre à comparer.",
"apihelp-compare-param-fromid": "ID de la première page à comparer.",
"apihelp-compare-param-torev": "Seconde révision à comparer.",
"apihelp-compare-example-1": "Créer une différence entre les révisions 1 et 2",
"apihelp-createaccount-description": "Créer un nouveau compte utilisateur.",
+ "apihelp-createaccount-param-preservestate": "Si <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> renvoyé true pour <samp>hasprimarypreservedstate</samp>, les demandes marquées comme <samp>primary-required</samp> doivent être omises. Si elle a retourné une valeur non vide pour <samp>preservedusername</samp>, ce nom d'utilisateur doit être utilisé pour le paramètre <var>username</var>.",
+ "apihelp-createaccount-example-create": "Commencer le processus de création d’un utilisateur <kbd>Exemple</kbd> avec le mot de passe <kbd>ExempleMotDePasse</kbd>.",
"apihelp-createaccount-param-name": "Nom d’utilisateur.",
"apihelp-createaccount-param-password": "Mot de passe (ignoré si <var>$1mailpassword</var> est défini).",
"apihelp-createaccount-param-domain": "Domaine pour l’authentification externe (facultatif).",
"apihelp-import-param-namespace": "Importer vers cet espace de noms. Impossible à utiliser avec <var>$1rootpage</var>.",
"apihelp-import-param-rootpage": "Importer comme une sous-page de cette page. Impossible à utiliser avec <var>$1namespace</var>.",
"apihelp-import-example-import": "Importer [[meta:Help:ParserFunctions]] vers l’espace de noms 100 avec tout l’historique.",
- "apihelp-login-description": "Se connecter et obtenir les cookies d’authentification.\n\nDans le cas d’une connexion réussie, les cookies nécessaires seront inclus dans les entêtes de la réponse HTTP. Dans le cas d’une connexion en échec, les essais ultérieurs pourront être réduits afin de limiter les attaques automatisées de découverte du mot de passe.",
+ "apihelp-linkaccount-description": "Lier un compte d’un fournisseur tiers à l’utilisateur actuel.",
+ "apihelp-linkaccount-example-link": "Commencer le processus de liaison d’un compte depuis <kbd>Exemple</kbd>.",
+ "apihelp-login-description": "Se connecter et obtenir les cookies d’authentification.\n\nCette action ne devrait être utilisée qu’en lien avec [[Special:BotPasswords]] ; l’utiliser pour la connexion du compte principal est obsolète et peut échouer sans avertissement. Pour se connecter sans problème au compte principal, utiliser <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
+ "apihelp-login-description-nobotpasswords": "Se connecter et obtenir les cookies d’authentification.\n\nCette action est obsolète et peut échouer sans prévenir. Pour se connecter sans problème, utiliser <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
+ "apihelp-login-description-nonauthmanager": "Se connecter et obtenir les cookies d’authentification.\n\nDans le cas d’une connexion réussie, les cookies nécessaires seront inclus dans les entêtes HTTP de la réponse. Dans le cas d’une connexion en échec, des tentatives ultérieures pourront être limitées pour éviter les attaques automatiques pour deviner les mots de passe.",
"apihelp-login-param-name": "Nom d’utilisateur.",
"apihelp-login-param-password": "Mot de passe.",
"apihelp-login-param-domain": "Domaine (facultatif).",
"apihelp-query+allusers-param-activeusers": "Lister uniquement les utilisateurs actifs durant {{PLURAL:$1|le dernier jour|les $1 derniers jours}}.",
"apihelp-query+allusers-param-attachedwiki": "Avec <kbd>$1prop=centralids</kbd>, indiquer aussi si l’utilisateur est attaché avec le wiki identifié par cet ID.",
"apihelp-query+allusers-example-Y": "Lister les utilisateurs en commençant à <kbd>Y</kbd>.",
+ "apihelp-query+authmanagerinfo-description": "Récupérer les informations concernant l’état d’authentification actuel.",
+ "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Tester si l’état d’authentification actuel de l’utilisateur est suffisant pour l’opération spécifiée comme sensible du point de vue sécurité.",
+ "apihelp-query+authmanagerinfo-param-requestsfor": "Récupérer les informations sur les requêtes d’authentification nécessaires pour l’action d’authentification spécifiée.",
+ "apihelp-query+filerepoinfo-example-login": "Récupérer les requêtes qui peuvent être utilisées en commençant une connexion.",
+ "apihelp-query+filerepoinfo-example-login-merged": "Récupérer les requêtes qui peuvent être utilisées au début de la connexion, avec les champs de formulaire intégrés.",
+ "apihelp-query+filerepoinfo-example-securitysensitiveoperation": "Tester si l’authentification est suffisante pour l’action <kbd>foo</kbd>.",
"apihelp-query+backlinks-description": "Trouver toutes les pages qui ont un lien vers la page donnée.",
"apihelp-query+backlinks-param-title": "Titre à rechercher. Impossible à utiliser avec <var>$1pageid</var>.",
"apihelp-query+backlinks-param-pageid": "ID de la page à chercher. Impossible à utiliser avec <var>$1title</var>.",
"apihelp-query+prefixsearch-param-limit": "Nombre maximal de résultats à renvoyer.",
"apihelp-query+prefixsearch-param-offset": "Nombre de résultats à sauter.",
"apihelp-query+prefixsearch-example-simple": "Rechercher les titres de page commençant par <kbd>meaning</kbd>.",
+ "apihelp-query+prefixsearch-param-profile": "Rechercher le profil à utiliser.",
"apihelp-query+protectedtitles-description": "Lister tous les titres protégés en création.",
"apihelp-query+protectedtitles-param-namespace": "Lister uniquement les titres dans ces espaces de nom.",
"apihelp-query+protectedtitles-param-level": "Lister uniquement les titres avec ces niveaux de protection.",
"apihelp-query+search-param-what": "Quel type de recherche effectuer.",
"apihelp-query+search-param-info": "Quelles métadonnées renvoyer.",
"apihelp-query+search-param-prop": "Quelles propriétés renvoyer :",
+ "apihelp-query+search-param-qiprofile": "Profil indépendant des requêtes à utiliser (affecte algorithme de classement).",
"apihelp-query+search-paramvalue-prop-size": "Ajoute la taille de la page en octets.",
"apihelp-query+search-paramvalue-prop-wordcount": "Ajoute le nombre de mots de la page.",
"apihelp-query+search-paramvalue-prop-timestamp": "Ajoute l’horodatage de la dernière modification de la page.",
"apihelp-query+siteinfo-paramvalue-prop-variables": "Renvoie une liste des IDs de variable.",
"apihelp-query+siteinfo-paramvalue-prop-protocols": "Renvoie une liste des protocoles qui sont autorisés dans les liens externes.",
"apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Renvoie les valeurs par défaut pour les préférences utilisateur.",
+ "apihelp-query+siteinfo-paramvalue-prop-uploaddialog": "Renvoie la configuration du dialogue de téléversement.",
"apihelp-query+siteinfo-param-filteriw": "Renvoyer uniquement les entrées locales ou uniquement les non locales de la correspondance interwiki.",
"apihelp-query+siteinfo-param-showalldb": "Lister tous les serveurs de base de données, pas seulement celui avec la plus grande latence.",
"apihelp-query+siteinfo-param-numberingroup": "Liste le nombre d’utilisateurs dans les groupes.",
"apihelp-query+users-paramvalue-prop-emailable": "Marque si l’utilisateur peut et veut recevoir des courriels via [[Special:Emailuser]].",
"apihelp-query+users-paramvalue-prop-gender": "Marque le sexe de l’utilisateur. Renvoie « male », « female », ou « unknown ».",
"apihelp-query+users-paramvalue-prop-centralids": "Ajoute les IDs centraux et l’état d’attachement de l’utilisateur.",
+ "apihelp-query+users-paramvalue-prop-cancreate": "Indique si un compte peut être créé pour les noms d’utilisateurs valides mais non enregistrés.",
"apihelp-query+users-param-attachedwiki": "Avec <kbd>$1prop=centralids</kbd>, indiquer si l’utilisateur est attaché au wiki identifié par cet ID.",
"apihelp-query+users-param-users": "Une liste des utilisateurs sur lesquels obtenir de l’information.",
"apihelp-query+users-param-token": "Utiliser plutôt <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
"apihelp-query+watchlistraw-param-totitle": "Terminer l'énumération avec ce Titre (inclure le préfixe d'espace de noms) :",
"apihelp-query+watchlistraw-example-simple": "Lister les pages dans la liste de suivi de l’utilisateur actuel",
"apihelp-query+watchlistraw-example-generator": "Chercher l’information sur les pages de la liste de suivi de l’utilisateur actuel",
+ "apihelp-removeauthenticationdata-description": "Supprimer les données d’authentification pour l’utilisateur actuel.",
+ "apihelp-removeauthenticationdata-example-simple": "Tentative de suppression des données de l’utilisateur pour <kbd>FooAuthenticationRequest</kbd>.",
+ "apihelp-resetpassword-description": "Envoyer un courriel de réinitialisation du mot de passe à un utilisateur.",
+ "apihelp-resetpassword-description-noroutes": "Aucun chemin pour réinitialiser le mot de passe n’est disponible.\n\nActiver les chemins dans <var>[[mw:Manual:$wgPasswordResetRoutes|$wgPasswordResetRoutes]]</var> pour utiliser ce module.",
+ "apihelp-resetpassword-param-user": "Utilisateur ayant été réinitialisé.",
+ "apihelp-resetpassword-param-email": "Adresse courriel de l’utilisateur ayant été réinitialisé.",
+ "apihelp-resetpassword-param-capture": "Renvoyer les mots de passe temporaires déjà envoyés. Nécessite le droit utilisateur <code>passwordreset</code>.",
+ "apihelp-resetpassword-example-user": "Envoyer un courriel de réinitialisation du mot de passe à l’utilisateur <kbd>Exemple</kbd>.",
+ "apihelp-resetpassword-example-email": "Envoyer un courriel pour la réinitialisation de mot de passe à tous les utilisateurs avec une adresse email <kbd>user@example.com</kbd>.",
"apihelp-revisiondelete-description": "Supprimer et annuler la suppression des révisions.",
"apihelp-revisiondelete-param-type": "Type de suppression de révision en cours de traitement.",
"apihelp-revisiondelete-param-target": "Titre de page pour la suppression de révision, s’il est nécessaire pour le type.",
"apihelp-undelete-param-watchlist": "Ajouter ou supprimer la page de la liste de suivi de l’utilisateur actuel sans condition, utiliser les préférences ou ne pas modifier le suivi.",
"apihelp-undelete-example-page": "Annuler la suppression de la page <kbd>Main Page</kbd>.",
"apihelp-undelete-example-revisions": "Annuler la suppression de deux révisions de la page <kbd>Main Page</kbd>.",
+ "apihelp-unlinkaccount-description": "Supprimer un compte tiers lié de l’utilisateur actuel.",
+ "apihelp-unlinkaccount-example-simple": "Essayer de supprimer le lien de l’utilisateur actuel pour le fournisseur associé avec <kbd>FooAuthenticationRequest</kbd>.",
"apihelp-upload-description": "Téléverser un fichier, ou obtenir l’état des téléversements en cours.\n\nPlusieurs méthodes sont disponibles :\n* Téléverser directement le contenu du fichier, en utilisant le paramètre <var>$1file</var>.\n* Téléverser le fichier par morceaux, en utilisant les paramètres <var>$1filesize</var>, <var>$1chunk</var>, and <var>$1offset</var>.\n* Pour que le serveur MédiaWiki cherche un fichier depuis une URL, utilisez le paramètre <var>$1url</var>.\n* Terminer un téléversement précédent qui a échoué à cause d’avertissements, en utilisant le paramètre <var>$1filekey</var>.\nNoter que le POST HTTP doit être fait comme un téléversement de fichier (par ex. en utilisant <code>multipart/form-data</code>) en envoyant le <code>multipart/form-data</code>.",
"apihelp-upload-param-filename": "Nom de fichier cible.",
"apihelp-upload-param-comment": "Télécharger le commentaire. Utilisé aussi comme texte de la page initiale pour les nouveaux fichiers si <var>$1text</var> n’est pas spécifié.",
"api-help-permissions-granted-to": "{{PLURAL:$1|Accordé à}} : $2",
"api-help-right-apihighlimits": "Utiliser des valeurs plus hautes dans les requêtes de l’API (requêtes lentes : $1 ; requêtes rapides : $2). Les limites pour les requêtes lentes s’appliquent aussi aux paramètres multivalués.",
"api-help-open-in-apisandbox": "<small>[ouvrir dans le bac à sable]</small>",
+ "api-help-authmanager-general-usage": "La procédure générale pour utiliser ce module est la suivante :\n# Récupérer les champs disponibles avec <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> avec <kbd>amirequestsfor=$4</kbd>, et un jeton <kbd>$5</kbd> avec <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.\n# Présenter les champs à l’utilisateur, et les lui faire soumettre.\n# Faire un envoi à ce module, en fournissant <var>$1returnurl</var> et les champs appropriés.\n# Vérifier le <samp>status</samp> dans la réponse.\n#* Si vous avez reçu <samp>PASS</samp> ou <samp>FAIL</samp>, c’est terminé. L’opération a soit réussi, soit échoué.\n#* Si vous avez reçu <samp>UI</samp>, affichez les nouveaux champs à l’utilisateur et faites-les-lui soumettre. Puis envoyez-les à ce module avec <var>$1continue</var> et l’ensemble des champs appropriés, et recommencez l’étape 4.\n#* Si vous avez reçu <samp>REDIRECT</samp>, envoyez l’utilisateur vers la cible <samp>redirecttarget</samp> et attendez le retour vers <var>$1returnurl</var>. Puis envoyez à ce module avec <var>$1continue</var> et tous les champs passés à l’URL de retour, puis répétez l’étape 4.\n#* Si vous avez reçu <samp>RESTART</samp>, cela veut dire que l’authentification a fonctionné, mais nous n’avons pas de compte utilisateur lié. Vous pouvez traiter cela comme un <samp>UI</samp> ou un <samp>FAIL</samp>.",
+ "api-help-authmanagerhelper-requests": "Utiliser uniquement ces requêtes d’authentification, avec l’<samp>id</samp> renvoyé par <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> avec <kbd>amirequestsfor=$1</kbd> ou depuis une réponse précédente de ce module.",
+ "api-help-authmanagerhelper-request": "Utiliser cette requête d’authentification, avec l’<samp>id</samp> renvoyé par <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> avec <kbd>amirequestsfor=$1</kbd>.",
+ "api-help-authmanagerhelper-messageformat": "Format à utiliser pour retourner les messages.",
+ "api-help-authmanagerhelper-mergerequestfields": "Fusionner dans un tableau le champ information de toutes les demandes d'authentification.",
+ "api-help-authmanagerhelper-preservestate": "Conserver l'état d'une précédente tentative de connexion qui a échoué, si possible.",
+ "api-help-authmanagerhelper-returnurl": "Renvoyer l’URL pour les flux d’authentification tiers, qui doit être absolue. Cela ou <var>$1continue</var> est obligatoire.\n\nDès réception d’une réponse <samp>REDIRECT</samp>, vous ouvrirez typiquement un navigateur ou un affichage web vers l’URL <samp>redirecttarget</samp> spécifiée pour un flux d’authentification tiers. Une fois ceci terminé, le tiers renverra le navigateur ou l’affichage web vers cette URL. Vous devez extraire toute requête ou paramètre POST de l’URL et les passer comme une requête <var>$1continue</var> à ce module de l’API.",
+ "api-help-authmanagerhelper-continue": "Cette requête est une continuation après une précédente réponse <samp>UI</samp> ou <samp>REDIRECT</samp>. Cela ou <var>$1returnurl</var> est obligatoire.",
+ "api-help-authmanagerhelper-additional-params": "Ce module accepte des paramètres supplémentaires selon les requêtes d’authentification disponibles. Utiliser <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> avec <kbd>amirequestsfor=$1</kbd> (ou une réponse précédente de ce module, le cas échéant) pour déterminer les requêtes disponibles et les champs qu’elles utilisent.",
"api-credits-header": "Remerciements",
"api-credits": "Développeurs de l’API :\n* Roan Kattouw (développeur en chef Sept. 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (créateur, développeur en chef Sept. 2006–Sept. 2007)\n* Brad Jorsch (développeur en chef depuis 2013)\n\nVeuillez envoyer vos commentaires, suggestions et questions à mediawiki-api@lists.wikimedia.org\nou remplir un rapport de bogue sur https://phabricator.wikimedia.org/."
}
"apihelp-block-param-watchuser": "Vixiar a páxina de usuario ou direccións IP e a de conversa deste usuario",
"apihelp-block-example-ip-simple": "Bloquear dirección IP <kbd>192.0.2.5</kbd> durante tres días coa razón <kbd>Primeiro aviso</kbd>.",
"apihelp-block-example-user-complex": "Bloquear indefinidamente ó usuario <kbd>Vandal</kbd> coa razón <kbd>Vandalism</kbd>, e impedir a creación de novas contas e envío de correos electrónicos.",
+ "apihelp-changeauthenticationdata-description": "Cambiar os datos de autenticación do usuario actual.",
+ "apihelp-changeauthenticationdata-example-password": "Intento de cambiar o contrasinal do usuario actua a <kbd>ExemploContrasinal</kbd>.",
"apihelp-checktoken-description": "Verificar a validez dun identificador de <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
"apihelp-checktoken-param-type": "Tipo de identificador a probar.",
"apihelp-checktoken-param-token": "Símbolo a testar",
"apihelp-checktoken-example-simple": "Verificar a validez de un identificador <kbd>csrf</kbd>.",
"apihelp-clearhasmsg-description": "Limpar a bandeira <code>hasmsg</code> para o usuario actual",
"apihelp-clearhasmsg-example-1": "Limpar a bandeira <code>hasmsg</code> para o usuario actual",
+ "apihelp-clientlogin-description": "Conectarse á wiki usando o fluxo interactivo.",
+ "apihelp-clientlogin-example-login": "Comezar o proceso de conexión á wiki como o usuario <kbd>Exemplo</kbd> con contrasinal <kbd>ExemploContrasinal</kbd>.",
"apihelp-compare-description": "Obter as diferencias entre dúas páxinas.\n\nDebe indicar un número de revisión, un título de páxina, ou un ID de páxina tanto para \"from\" como para \"to\".",
"apihelp-compare-param-fromtitle": "Primeiro título para comparar.",
"apihelp-compare-param-fromid": "Identificador da primeira páxina a comparar.",
"apihelp-compare-param-torev": "Segunda revisión a comparar.",
"apihelp-compare-example-1": "Mostrar diferencias entre a revisión 1 e a 2",
"apihelp-createaccount-description": "Crear unha nova conta de usuario.",
+ "apihelp-createaccount-example-create": "Comezar o proceso de crear un usuario <kbd>Exemplo</kbd> con contrasinal <kbd>ExemploContrasinal</kbd>.",
"apihelp-createaccount-param-name": "Nome de usuario.",
"apihelp-createaccount-param-password": "Contrasinal (ignorado se <var>$1mailpassword</var> está activo)",
"apihelp-createaccount-param-domain": "Dominio para autenticación externa (opcional)",
"apihelp-import-param-namespace": "Importar a este espazo de nomes. Non se pode usar de forma conxunta con <var>$1rootpage</var>.",
"apihelp-import-param-rootpage": "Importar como subpáxina desta páxina. Non se pode usar de forma conxunta con <var>$1namespace</var>.",
"apihelp-import-example-import": "Importar [[meta:Help:ParserFunctions]] ó espazo de nomes 100 con todo o historial.",
+ "apihelp-linkaccount-description": "Vincular unha conta dun provedor externo ó usuario actual.",
+ "apihelp-linkaccount-example-link": "Comezar o proceso de vincular a unha conta de <kbd>Exemplo</kbd>.",
"apihelp-login-description": "No caso dunha conexión correcta, as cookies necesarias incluiranse nas cabeceiras HTTP de resposta. No caso dunha conexión fallida, os intentos posteriores poden ser reducidos para limitar ataques automaticos de roubo de contrasinais.",
"apihelp-login-param-name": "Nome de usuario.",
"apihelp-login-param-password": "Contrasinal",
"apihelp-query+allusers-param-activeusers": "Só listar usuarios activos {{PLURAL:$1|no último día|nos $1 últimos días}}.",
"apihelp-query+allusers-param-attachedwiki": "Con <kbd>$1prop=centralids</kbd>, \ntamén indica se o usuario está acoplado á wiki identificada por este identificador.",
"apihelp-query+allusers-example-Y": "Listar usuarios que comecen por <kbd>Y</kbd>.",
+ "apihelp-query+authmanagerinfo-description": "Recuperar información sobre o estado de autenticación actual.",
+ "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Comprobar se o estado de autenticación actual do usuario é abondo para a operación especificada como sensible dende o punto de vista da seguridade.",
+ "apihelp-query+authmanagerinfo-param-requestsfor": "Recuperar a información sobre as peticións de autenticación necesarias para a acción de autenticación especificada.",
+ "apihelp-query+filerepoinfo-example-login": "Recuperar as peticións que poden ser usadas ó comezo dunha conexión.",
+ "apihelp-query+filerepoinfo-example-login-merged": "Recuperar as peticións que poden ser usadas ó comezo dunha conexión, xunto cos campos de formulario integrados.",
+ "apihelp-query+filerepoinfo-example-securitysensitiveoperation": "Probar se a autenticación é abondo para a acción <kbd>foo</kbd>.",
"apihelp-query+backlinks-description": "Atopar todas as páxinas que ligan coa páxina dada.",
"apihelp-query+backlinks-param-title": "Título a buscar. Non pode usarse xunto con <var>$1pageid</var>.",
"apihelp-query+backlinks-param-pageid": "Identificador de páxina a buscar. Non pode usarse xunto con <var>$1title</var>.",
"apihelp-query+prefixsearch-param-limit": "Número máximo de resultados a visualizar.",
"apihelp-query+prefixsearch-param-offset": "Número de resultados a saltar.",
"apihelp-query+prefixsearch-example-simple": "Buscar títulos de páxina que comecen con <kbd>meaning</kbd>.",
+ "apihelp-query+prefixsearch-param-profile": "Buscar o perfil a usar.",
"apihelp-query+protectedtitles-description": "Listar todos os títulos protexidos en creación.",
"apihelp-query+protectedtitles-param-namespace": "Só listar títulos nestes espazos de nomes.",
"apihelp-query+protectedtitles-param-level": "Só listar títulos con estos niveis de protección.",
"apihelp-query+search-param-what": "Que tipo de busca lanzar.",
"apihelp-query+search-param-info": "Que metadatos devolver.",
"apihelp-query+search-param-prop": "Que propiedades devolver:",
+ "apihelp-query+search-param-qiprofile": "Perfil independente das consultas a usar (afecta ó algoritmo de clasificación).",
"apihelp-query+search-paramvalue-prop-size": "Engade o tamaño da páxina en bytes.",
"apihelp-query+search-paramvalue-prop-wordcount": "Engade o número de palabras da páxina.",
"apihelp-query+search-paramvalue-prop-timestamp": "Engade o selo de tempo da última vez que foi editada a páxina.",
"apihelp-query+siteinfo-paramvalue-prop-variables": "Devolve unha lista de identificadores de variable.",
"apihelp-query+siteinfo-paramvalue-prop-protocols": "Devolve unha lista de protocolos que están permitidos nas ligazóns externas.",
"apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Devolve os valores por defecto das preferencias de usuario.",
+ "apihelp-query+siteinfo-paramvalue-prop-uploaddialog": "Devolve a configuración do diálogo de subas.",
"apihelp-query+siteinfo-param-filteriw": "Só devolver entradas locais ou só non locais da correspondencia interwiki.",
"apihelp-query+siteinfo-param-showalldb": "Listar todos os servidores de base de datos, non só o que teña máis retardo.",
"apihelp-query+siteinfo-param-numberingroup": "Listar o número de usuarios nos grupos de usuarios.",
"apihelp-query+users-paramvalue-prop-emailable": "Marca se o usuario pode e quere recibir correos usando [[Special:Emailuser]].",
"apihelp-query+users-paramvalue-prop-gender": "Marca o xénero do usuario. Devolve \"home\", \"muller\" ou \"descoñecido\".",
"apihelp-query+users-paramvalue-prop-centralids": "Engade os identificadores centrais e o estado de acoplamento do usuario.",
+ "apihelp-query+users-paramvalue-prop-cancreate": "Indica se unha conta pode ser creada para nomes de usuario válidos pero non rexistrados.",
"apihelp-query+users-param-attachedwiki": "Con <kbd>$1prop=centralids</kbd>, \nindica que o usuario está acoplado á wiki identificada por este identificador.",
"apihelp-query+users-param-users": "Lista de usuarios para os que obter información.",
"apihelp-query+users-param-token": "Usar <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> no canto diso.",
"apihelp-query+watchlistraw-param-totitle": "Título (co prefixo de espazo de nomes) no que rematar de enumerar.",
"apihelp-query+watchlistraw-example-simple": "Listar páxinas na lista de vixiancia do usuario actual.",
"apihelp-query+watchlistraw-example-generator": "Buscar a información de páxina das páxinas da lista de vixiancia do usuario actual.",
+ "apihelp-removeauthenticationdata-description": "Elimina os datos de autenticación do usuario actual.",
+ "apihelp-removeauthenticationdata-example-simple": "Intenta eliminar os datos de usuario actual para <kbd>FooAuthenticationRequest</kbd>.",
+ "apihelp-resetpassword-description": "Envía un correo de inicialización de contrasinal a un usuario.",
+ "apihelp-resetpassword-param-user": "Usuario sendo reinicializado.",
+ "apihelp-resetpassword-param-email": "Está reinicializándose o enderezo de correo electrónico do usuario.",
+ "apihelp-resetpassword-param-capture": "Devolve os contrasinais temporais que se enviaron. Require o dereito de usuario <code>passwordreset</code> .",
+ "apihelp-resetpassword-example-user": "Enviar un correo de reinicialización de contrasinal ó usuario <kbd>Exemplo</kbd>.",
+ "apihelp-resetpassword-example-email": "Enviar un correo de reinicialización de contrasinal a todos os usuarios con enderezo de correo electrónico <kbd>usario@exemplo.com</kbd>.",
"apihelp-revisiondelete-description": "Borrar e restaurar revisións.",
"apihelp-revisiondelete-param-type": "Tipo de borrado de revisión a ser tratada.",
"apihelp-revisiondelete-param-target": "Título de páxina para o borrado da revisión, se requerido para o tipo.",
"apihelp-undelete-param-watchlist": "Engadir ou eliminar a páxina da lista de vixiancia do usuario actual sen condicións, use as preferencias ou non cambie a vixiancia.",
"apihelp-undelete-example-page": "Restaurar a <kbd>Páxina Principal</kbd>.",
"apihelp-undelete-example-revisions": "Restaurar dúas revisións de <kbd>Main Page</kbd>.",
+ "apihelp-unlinkaccount-description": "Elimina unha conta vinculada do usuario actual.",
+ "apihelp-unlinkaccount-example-simple": "Tentar eliminar a ligazón do usuario actual co provedor asociado con <kbd>FooAuthenticationRequest</kbd>.",
"apihelp-upload-description": "Subir un ficheiro, ou obter o estado de subas pedentes.\n\nHai varios métodos dispoñibles:\n*Subir o contido do ficheiro directamente, usando o parámetro <var>$1file</var>.\n*Subir o ficheiro por partes, usando os parámetros <var>$1filesize</var>, <var>$1chunk</var>, e <var>$1offset</var>.\n*Mandar ó servidor MediaWiki que colla un ficheiro dunha URL, usando o parámetro <var>$1url</var>.\n*Completar unha suba anterior que fallou a causa dos avisos, usando o parámetro <var>$1filekey</var>. \nTeña en conta que o HTTP POST debe facerse como suba de ficheiro (p.ex. usando <code>multipart/form-data</code>)cando se envie o <var>$1file</var>.",
"apihelp-upload-param-filename": "Nome de ficheiro obxectivo.",
"apihelp-upload-param-comment": "Subir comentario. Tamén usado como texto da páxina inicial para ficheiros novos se non se especifica <var>$1text</var>.",
"api-help-permissions-granted-to": "{{PLURAL:$1|Concedida a|Concedidas a}}: $2",
"api-help-right-apihighlimits": "Usar os valores superiores das consultas da API (consultas lentas: $1; consultas rápidas: $2). Os límites para as consultas lentas tamén se aplican ós parámetros multivaluados.",
"api-help-open-in-apisandbox": "<small>[abrir en zona de probas]</small>",
+ "api-help-authmanagerhelper-messageformat": "Formato a usar para devolver as mensaxes.",
+ "api-help-authmanagerhelper-mergerequestfields": "Fusionar os campos de información para todas as peticións de autenticación nunha táboa.",
+ "api-help-authmanagerhelper-preservestate": "Conservar o estado dun intento previo de conexión fallida, se é posible.",
"api-credits-header": "Créditos",
"api-credits": "Desenvolvedores da API:\n* Roan Kattouw (desenvolvedor principal, set. 2007-2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (creador e desenvolvedor principal, set. 2006-sep. 2007)\n* Brad Jorsch (desenvolvedor principal, 2013-actualidade)\n\nEnvía comentarios, suxerencias e preguntas a mediawiki-api@lists.wikimedia.org\nou informa dun erro en https://phabricator.wikimedia.org/."
}
"apihelp-block-param-watchuser": "לעקוב אחרי דף המשתמש ודף השיחה של המשתמש או של כתובת ה־IP.",
"apihelp-block-example-ip-simple": "חסימת כתובת ה־IP <kbd>192.0.2.5</kbd> לשלושה ימים עם הסיבה <kbd>First strike</kbd>.",
"apihelp-block-example-user-complex": "חסימת המשתמש <kbd>Vandal</kbd> ללא הגבלת זמן עם הסיבה <kbd>Vandalism</kbd>, ומניעת יצירת חשבונות חדשים ושליחת דוא\"ל.",
+ "apihelp-changeauthenticationdata-description": "שינוי נתוני אימות עבור המשתמש הנוכחי.",
+ "apihelp-changeauthenticationdata-example-password": "ניסיון לשנות את הססמה של המשתמש הנוכחי ל־<kbd>ExamplePassword</kbd>.",
"apihelp-checktoken-description": "בדיקת התקינות של האסימון מ־<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
"apihelp-checktoken-param-type": "סוג האסימון שבבדיקה.",
"apihelp-checktoken-param-token": "איזה אסימון לבדוק.",
"apihelp-checktoken-example-simple": "בדיקת התקינות של אסימון <kbd>csrf</kbd>.",
"apihelp-clearhasmsg-description": "מנקה את דגל <code>hasmsg</code> עבור המשתמש הנוכחי.",
"apihelp-clearhasmsg-example-1": "לנקות את דגל <code>hasmsg</code> עבור המשתמש הנוכחי.",
+ "apihelp-clientlogin-description": "כניסה לוויקי באמצעות זרימה הידודית.",
+ "apihelp-clientlogin-example-login": "תחילת תהליך כניסה לוויקי בתור משתמש <kbd>Example</kbd> עם הססמה <kbd>ExamplePassword</kbd>.",
+ "apihelp-clientlogin-example-login2": "המשך כניסה אחרי תשובת <samp>UI</samp> לאימות דו־גורמי, עם <var>OATHToken</var> של <kbd>987654</kbd>.",
"apihelp-compare-description": "קבלת ההבדל בין 2 דפים.\n\nיש להעביר מספר גרסה, כותרת דף או מזהה דף גם ל־\"from\" וגם ל־\"to\".",
"apihelp-compare-param-fromtitle": "כותרת ראשונה להשוואה.",
"apihelp-compare-param-fromid": "מס׳ זיהוי של העמוד הראשון להשוואה.",
"apihelp-compare-param-torev": "גרסה שנייה להשוואה.",
"apihelp-compare-example-1": "יצירת תיעוד שינוי בין גרסה 1 ל־2.",
"apihelp-createaccount-description": "יצירת חשבון משתמש חדש.",
+ "apihelp-createaccount-param-preservestate": "אם <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> החזיר true עבור <samp>hasprimarypreservedstate</samp>, בקשות שמסומנות בתור <samp>primary-required</samp> אמורות להיות מושמטות. אם מוחזר ערך לא ריק ל־<samp>preservedusername</samp>, שם המשתמש הזה ישמש לפרמטר <var>username</var>.",
+ "apihelp-createaccount-example-create": "תחילת תהליך יצירת המשתמש <kbd>Example</kbd> עם הססמה <kbd>ExamplePassword</kbd>.",
"apihelp-createaccount-param-name": "שם משתמש.",
"apihelp-createaccount-param-password": "ססמה (לא ישפיע אם הוגדר <var>$1mailpassword</var>).",
"apihelp-createaccount-param-domain": "שם מתחם לאימות חיצוני (רשות).",
"apihelp-import-param-namespace": "לייבא למרחב השם הזה. לא ניתן להשתמש בזה יחד עם <var>$1rootpage</var>.",
"apihelp-import-param-rootpage": "לייבא בתור תת־משנה של הדף הזה. לא ניתן להשתמש בזה יחד עם <var>$1namespace</var>.",
"apihelp-import-example-import": "לייבא את [[meta:Help:ParserFunctions]] למרחב השם 100 עם היסטוריה מלאה.",
- "apihelp-login-description": "להיכנס ולקבל עוגיות אימות.\n\nבמקרה של כניסה מוצלחת, העוגיות הדרושות תיכללנה בכותרות תשובות של HTTP. במקרה של כניסה לא מוצלחת, הניסיונות הבאים עשויים להיות חנוקים כדי להגביל תקיפות ניחוש ססמה אוטומטי.",
+ "apihelp-linkaccount-description": "קישור חשבון של ספק צד־שלישי למשתמש הנוכחי.",
+ "apihelp-linkaccount-example-link": "תחילת תהליך הקישור לחשבון מ־<kbd>Example</kbd>.",
+ "apihelp-login-description": "להיכנס ולקבל עוגיות אימות.\n\nהפעולה הזאת צריכה לשמש רק בשילוב [[Special:BotPasswords]]; שימוש לכניסה לחשבון ראשי מיושן ועשוי להיכשל ללא אזהרה. כדי להיכנס בבטחה לחשבון הראשי, יש להשתמש ב־<kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
+ "apihelp-login-description-nobotpasswords": "להיכנס ולקבל עוגיות אימות.\n\nהפעולה הזאת מיושנת ועשויה להיכשל ללא אזהרה. כדי להיכנס בבטחה, יש להשתמש ב־<kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
+ "apihelp-login-description-nonauthmanager": "להיכנס ולקבל עוגיות אימות.\n\nבמקרה של כניסה מוצלחת, העוגיות המקוננות תיכללנה בכותרות תשובות ה־HTTP. במקרה של כניסה כושלת, הניסיונות הבאים יוגבלו למספר ניסויי ניחוש הססמה האוטומטיים.",
"apihelp-login-param-name": "שם משתמש.",
"apihelp-login-param-password": "ססמה.",
"apihelp-login-param-domain": "שם מתחם (רשות).",
"apihelp-query+allusers-param-activeusers": "לרשום רק משתמשים שהיו פעילים {{PLURAL:$1|ביום האחרון|ביומיים האחרונים|ב־$1 הימים האחרונים}}.",
"apihelp-query+allusers-param-attachedwiki": "עם <kbd>$1prop=centralids</kbd>, לציין גם האם המשתמש משויך לוויקי עם המזהה הזה.",
"apihelp-query+allusers-example-Y": "לרשום משתמשים שמתחילים ב־<kbd>Y</kbd>.",
+ "apihelp-query+authmanagerinfo-description": "אחזור מידע אודות מצב האימות הנוכחי.",
+ "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "בדיקה האם מצב האימות הנוכחי של המשתמש מספיק בשביל הפעולה הרגישה מבחינת אבטחה שצוינה.",
+ "apihelp-query+authmanagerinfo-param-requestsfor": "אחזור מידע על בקשות האימות הדרושות לפעולת האימות המבוקשת.",
+ "apihelp-query+filerepoinfo-example-login": "אחזור הבקשות שיכולות לשמש לתחילת הכניסה.",
+ "apihelp-query+filerepoinfo-example-login-merged": "אחזור הבקשות שיכולות לשמש לתחילת הכניסה, עם שדות טופס ממוזגים.",
+ "apihelp-query+filerepoinfo-example-securitysensitiveoperation": "בדיקה האם האימות מספיק בשביל הפעולה <kbd>foo</kbd>.",
"apihelp-query+backlinks-description": "מציאת כל הדפים שמקשרים לדף הנתון.",
"apihelp-query+backlinks-param-title": "איזו כותרת לחפש. לא ניתן להשתמש בזה יחד עם <var>$1pageid</var>.",
"apihelp-query+backlinks-param-pageid": "מזהה דף לחיפוש. לא ניתן להשתמש בזה יחד עם <var>$1title</var>.",
"apihelp-query+prefixsearch-param-limit": "מספר התוצאות המרבי להחזרה.",
"apihelp-query+prefixsearch-param-offset": "מספר תוצאות לדילוג.",
"apihelp-query+prefixsearch-example-simple": "חיפוש שםות דפים שמתחילים ב־<kbd>meaning</kbd>.",
+ "apihelp-query+prefixsearch-param-profile": "באיזה פרופיל חיפוש להשתמש.",
"apihelp-query+protectedtitles-description": "לרשום את כל הכותרות שמוגנות מפני יצירה.",
"apihelp-query+protectedtitles-param-namespace": "לרשום רק כותרות במרחבי השם האלה.",
"apihelp-query+protectedtitles-param-level": "לרשום רק שמות עם רמת ההגנה הזאת.",
"apihelp-query+search-param-what": "איזה סוג חיפוש לבצע.",
"apihelp-query+search-param-info": "אילו מטא־נתונים להחזיר.",
"apihelp-query+search-param-prop": "אילו מאפיינים להחזיר:",
+ "apihelp-query+search-param-qiprofile": "באיזה פרופיל בלתי־תלוי בשאילתה להשתמש (משפיע על אלגוריתם הדירוג).",
"apihelp-query+search-paramvalue-prop-size": "הוספת גודל הדף בבתים.",
"apihelp-query+search-paramvalue-prop-wordcount": "הוספת מניין המילים של הדף.",
"apihelp-query+search-paramvalue-prop-timestamp": "הוספת חותם־הזמן של העריכה האחרונה של הדף.",
"apihelp-query+siteinfo-paramvalue-prop-variables": "החזרת מזהי משתנים.",
"apihelp-query+siteinfo-paramvalue-prop-protocols": "החזרת רשימת הפרוטוקולים המותרים בקישורים חיצוניים.",
"apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "החזרת הערכים ההתחלתיים של העדפות משתמש.",
+ "apihelp-query+siteinfo-paramvalue-prop-uploaddialog": "החזרת הגדרות תיבת ההעלאה.",
"apihelp-query+siteinfo-param-filteriw": "החזרה רק של עיולים מקומיים או רק של עיולים לא מקומיים ממפת הבינוויקי.",
"apihelp-query+siteinfo-param-showalldb": "רשימת כל שרתי מסד הנתונים, לא רק אלה שהכי מתעכבים.",
"apihelp-query+siteinfo-param-numberingroup": "רשימת מספרי משתמשים בקבוצות משתמשים.",
"apihelp-query+users-paramvalue-prop-emailable": "מתייג אם המשתמש יכול ורוצה לקבל דואר אלקטרוני דרך [[Special:Emailuser]].",
"apihelp-query+users-paramvalue-prop-gender": "מתייג את המגדר של המשתמש. מחזיר \"male\", \"female\" או \"unknown\".",
"apihelp-query+users-paramvalue-prop-centralids": "הוספת המזהה המרכזי ומצב השיוך למשתמש.",
+ "apihelp-query+users-paramvalue-prop-cancreate": "ציון האם אפשר ליצור חשבון עבור שמות משתמש תקינים, אבל לא רשומים.",
"apihelp-query+users-param-attachedwiki": "עם <kbd>$1prop=centralids</kbd>, לציין האם המשתמש משויך לוויקי עם המזהה הזה.",
"apihelp-query+users-param-users": "רשימת משתמשים שעליהם צריך לקבל מידע.",
"apihelp-query+users-param-token": "יש להשתמש ב־<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> במקום.",
"apihelp-query+watchlistraw-param-totitle": "באיזו כותרת (עם תחילית מרחב שם) להפסיק למנות.",
"apihelp-query+watchlistraw-example-simple": "לרשום דפים ברשימת המעקב של המשתמש הנוכחי.",
"apihelp-query+watchlistraw-example-generator": "אחזור מידע על הדפים עבור דפים ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-removeauthenticationdata-description": "הסרת נתוני אימות עבור המשתמש הנוכחי.",
+ "apihelp-removeauthenticationdata-example-simple": "לנסות להסיר את נתוני המשתמש הנוכחי בשביל <kbd>FooAuthenticationRequest</kbd>.",
+ "apihelp-resetpassword-description": "שליחת דוא\"ל איפוס סיסמה למשתמש.",
+ "apihelp-resetpassword-description-noroutes": "אין מסלולים לאיפוס ססמה.\n\nכדי להשתמש במודול הזה, יש להפעיל מסלולים ב־<var>[[mw:Manual:$wgPasswordResetRoutes|$wgPasswordResetRoutes]]</var>.",
+ "apihelp-resetpassword-param-user": "המשתמש שמאופס.",
+ "apihelp-resetpassword-param-email": "כתובת הדוא\"ל של המשתמש שהסיסמה שלו מאופסת.",
+ "apihelp-resetpassword-param-capture": "החזרת הססמאות הזמניות שנשלחו. דורש את ההרשאה <code>passwordreset</code>.",
+ "apihelp-resetpassword-example-user": "שליחת מכתב איפוס ססמה למשתמש <kbd>Example</kbd>.",
+ "apihelp-resetpassword-example-email": "שליחת מכתב איפוס ססמה לכל המשתמשים שהכתובת שלהם היא <kbd>user@example.com</kbd>.",
"apihelp-revisiondelete-description": "מחיקה ושחזור ממחיקה של גרסאות.",
"apihelp-revisiondelete-param-type": "סוג מחיקת הגרסה שמתבצע.",
"apihelp-revisiondelete-param-target": "שם הדף למחיקת גרסה, אם זה נחוץ לסוג.",
"apihelp-undelete-param-watchlist": "הוספה או הסרה של הדף ללא תנאי מרשימת המעקב של המשתמש הנוכחי, להשתמש בהעדפות או לא לשנות את המעקב.",
"apihelp-undelete-example-page": "שחזור ממחיקה של הדף <kbd>Main Page</kbd>.",
"apihelp-undelete-example-revisions": "שחזור שתי גרסאות של הדף <kbd>Main Page</kbd>.",
+ "apihelp-unlinkaccount-description": "ביטול קישור של חשבון צד־שלישי מהמשתמש הנוכחי.",
+ "apihelp-unlinkaccount-example-simple": "לנסות להסיר את הקישור של המשתמש הנוכחי לספק המשויך עם <kbd>FooAuthenticationRequest</kbd>.",
"apihelp-upload-description": "העלאת קובץ, או קבלת מצב ההעלאות הממתינות.\n\nיש מספר שיטות:\n* להעלות את הקובץ ישירות, באמצעות הפרמטר <var>$1file</var>.\n* להעלות את הקובץ בחלקים, באמצעות הפרמטרים <var>$1filesize</var>, <var>$1chunk</var> ו־<var>$1offset</var>.\n* לגרום לשרת מדיה־ויקי לאחזר את הקובץ מ־URL באמצעות הפרמטר <var>$1url</var>.\n* להשלים העלאה קודמת שנכשלה בשל אזהרות באמצעות הפרמטר <var>$1filekey</var>.\nלתשומך לבך, יש לעשות את HTTP POST בתור העלאת קובץ (כלומר באמצעות <code>multipart/form-data</code>) בעת שליחת ה־<var>$1file</var>.",
"apihelp-upload-param-filename": "שם קובץ היעד.",
"apihelp-upload-param-comment": "הערת העלאה. משמש גם בתור טקסט הדף ההתחלתי עבור קבצים חדשים אם <var>$1text</var> אינו מצוין.",
"api-help-permissions-granted-to": "{{PLURAL:$1|הוענק ל|הוענקו ל}}: $2",
"api-help-right-apihighlimits": "להשתמש במגבלות גבוהות יותר בשאילתות API (שאילתות אטיות: $1; שאילתות מהירות: $2). המגבלות לשאילתות אטיות חלות גם על פרמטרים מרובי־ערכים.",
"api-help-open-in-apisandbox": "<small>[פתיחה בארגז חול]</small>",
+ "api-help-authmanager-general-usage": "הנוהל הכללי לשימוש במודול הזה הוא:\n# אחזור השדות הזמינים מ־<kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> עם <kbd>amirequestsfor=$4</kbd> ואסימון <kbd>$5</kbd> מתוך <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.\n# הצגת השדות למשתמש וקבלת אישור ממנו.\n# שליחה (Post) למודול הזה עם <var>$1returnurl</var> וכל השדות הרלוונטיים.\n# בדיקת ה־<samp>status</samp> בתשובה.\n#* אם קיבלת <samp>PASS</samp> או <samp>FAIL</samp>, זה הסיום. הפעולה שלך הצליחה או נכשלה.\n#* אם קיבלת <samp>UI</samp>, יש להציג את השדות החדשים למשתמש ולקבל את מה שהוא ישלח. אחר־כך יש לשלוח (post) למודול הזה עם <var>$1continue</var> ועם הגדרות של השדות הרלוונטיים ולחזור על צעד 4.\n#* אם קיבלת <samp>REDIRECT</samp>, יש להפנות את המשתמש ל־<samp>redirecttarget</samp> ולחכות לחזרה אל <var>$1returnurl</var>. אחר־כך לשלוח (post) למודול הזה עם <var>$1continue</var> ועם כל השדות שהועברו ל־URL שחוזרים אליו ולחזור על צעד 4.\n#* אם קיבלת <samp>RESTART</samp>, זה אומר שהאימות עבד אבל אין חשבון משתמש מקושר. באפשרותך לטפל בזה כמו ב־<samp>UI</samp> או ב־<samp>FAIL</samp>.",
+ "api-help-authmanagerhelper-requests": "להשתמש רק בבקשות האימות האלו, מאת <samp>id</samp> שהוחזר מ־<kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> עם <kbd>amirequestsfor=$1</kbd> או מתשובה קודמת למודול הזה.",
+ "api-help-authmanagerhelper-request": "להשתמש בבקשת האימות הזאת, מאת <samp>id</samp> שהוחזר מ־<kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> עם <kbd>amirequestsfor=$1</kbd>.",
+ "api-help-authmanagerhelper-messageformat": "תסדיר לשימוש בהחזרת הודעות.",
+ "api-help-authmanagerhelper-mergerequestfields": "מיזוג מידע של שדות עבור כל בקשות האימות למערך אחד.",
+ "api-help-authmanagerhelper-preservestate": "שימור מצב מניסיון כניסה קודם, אם אפשר.",
+ "api-help-authmanagerhelper-returnurl": "כתובת URL לחזרה עם זרימות אימות צד־שלישי, חייב להיות מוחלט. נדרש או זה או <var>$1continue</var>.\n\nעם קבלת תשובת <samp>REDIRECT</samp>, בדרך־כלל תפתח דפדפן או תצוגת וב בכתובת ה־<samp>redirecttarget</samp> שצוינה בשביל זרימת אימות צד־שלישי. כשזה יושלם, הצד השלישי ישלח את הדפדפן או את תצוגת הווב לכתובת הזאת. יש לחלץ את כל הפרמטרים של שאילתה או בקשת POST מה־URL ולהעביר אותם בתור בקשת <var>$1continue</var> למודול ה־API הזה.",
+ "api-help-authmanagerhelper-continue": "הבקשה הזאת היא המשך אחרי תשובת <samp>UI</samp> או <samp>REDIRECT</samp> קודמת. נדרש זה או <var>$1returnurl</var>.",
+ "api-help-authmanagerhelper-additional-params": "המודול הזה מקבל פרמטרים נוספים בהתאם לבקשות אימות זמינות. יש להשתמש ב־<kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> עם <kbd>amirequestsfor=$1</kbd> (או תגובה קודמת מהמודול הזה, אם זה זמין) כדי להבין מה הבקשות הזמינות ובאילו שדות הן משתמשות.",
"api-credits-header": "קרדיטים",
"api-credits": "מפתחי ה־API:\n* רואן קטאו (מפתח מוביל 2007–2009)\n* ויקטור וסילייב\n* בריאן טונג מין\n* סאם ריד\n* יורי אסטרחן (יוצר, מפתח מוביל מספטמבר 2006 עד ספטמבר 2007)\n* בראד יורש (מפתח מוביל מאז 2013)\n\nאנא שלחו הערות, הצעות ושאלות לכתובת mediawiki-api@lists.wikimedia.org או כתבו דיווח באג באתר https://phabricator.wikimedia.org."
}
"apihelp-checktoken-param-type": "Typo de indicio a testar.",
"apihelp-checktoken-param-token": "Indicio a testar.",
"apihelp-createaccount-param-name": "Nomine de usator.",
+ "apihelp-query+prefixsearch-param-profile": "Le profilo de recerca a usar.",
"apihelp-query+revisions-example-first5-not-localhost": "Obtener le prime 5 versiones del \"Pagina principal\" que non ha essite facite per le usator anonyme \"127.0.0.1\"",
"api-credits": "Programmatores del API:\n* Roan Kattouw (programmator dirigente Sept. 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (creator, programmator dirigente Sept. 2006–Sept. 2007)\n* Brad Jorsch (programmator dirigente 2013–presente)\n\nInvia tu commentos, suggestiones e questiones a mediawiki-api@lists.wikimedia.org\no insere un reportage de bug a https://phabricator.wikimedia.org/."
}
"authors": [
"WongKentir",
"Beeyan",
- "Rachmat.Wahidi"
+ "Rachmat.Wahidi",
+ "Kenrick95"
]
},
"apihelp-block-description": "Blokir pengguna.",
"apihelp-block-param-user": "Nama pengguna, alamat IP, atau rentang alamat IP untuk diblokir.",
"apihelp-createaccount-param-name": "Nama pengguna",
+ "apihelp-login-example-login": "Masuk log.",
"apihelp-revisiondelete-param-ids": "Penanda untuk perubahan yang akan dihapus"
}
"Macofe",
"Nemo bis",
"JackLantern",
- "Urielejh"
+ "Urielejh",
+ "Matteocng"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentazione]] (in inglese)\n* [[mw:API:FAQ|FAQ]] (in inglese)\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailing list]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annunci sull'API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bug & richieste]\n</div>\n<strong>Stato:</strong> tutte le funzioni e caratteristiche mostrate su questa pagina dovrebbero funzionare, ma le API sono ancora in fase attiva di sviluppo, e potrebbero cambiare in qualsiasi momento. Iscriviti alla [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la mailing list sugli annunci delle API MediaWiki] per essere informato sugli aggiornamenti.\n\n<strong>Istruzioni sbagliate:</strong> quando vengono impartite alle API delle istruzioni sbagliate, un'intestazione HTTP verrà inviata col messaggio \"MediaWiki-API-Error\" e, sia il valore dell'intestazione, sia il codice d'errore, verranno impostati con lo stesso valore. Per maggiori informazioni leggi [[mw:API:Errors_and_warnings|API:Errori ed avvertimenti]] (in inglese).\n\n<strong>Test:</strong> per testare facilmente le richieste API, vedi [[Special:ApiSandbox]].",
"apihelp-block-param-watchuser": "Segui la pagina utente e le pagine di discussione utente dell'utente o dell'indirizzo IP.",
"apihelp-block-example-ip-simple": "Blocca l'indirizzo IP <kbd>192.0.2.5</kbd> per tre giorni con motivazione <kbd>First strike</kbd>.",
"apihelp-block-example-user-complex": "Blocca l'utente <kbd>Vandal</kbd> a tempo indeterminato con motivazione <kbd>Vandalism</kbd>, e impediscigli la creazione di nuovi account e l'invio di e-mail.",
+ "apihelp-changeauthenticationdata-description": "Modificare i dati di autenticazione per l'utente corrente.",
+ "apihelp-changeauthenticationdata-example-password": "Tentativo di modificare la password dell'utente corrente a <kbd>ExamplePassword</kbd>.",
"apihelp-checktoken-description": "Verifica la validità di un token da <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
"apihelp-checktoken-param-type": "Tipo di token in corso di test.",
"apihelp-checktoken-param-token": "Token da testare.",
"apihelp-checktoken-example-simple": "Verifica la validità di un token <kbd>csrf</kbd>.",
"apihelp-clearhasmsg-description": "Cancella il flag <code>hasmsg</code> per l'utente corrente.",
"apihelp-clearhasmsg-example-1": "Cancella il flag <code>hasmsg</code> per l'utente corrente.",
+ "apihelp-clientlogin-description": "Accedi al wiki utilizzando il flusso interattivo.",
+ "apihelp-clientlogin-example-login": "Avvia il processo di accesso alla wiki come utente <kbd>Example</kbd> con password <kbd>ExamplePassword</kbd>.",
+ "apihelp-clientlogin-example-login2": "Continua l'accesso dopo una risposta dell'<samp>UI</samp> per l'autenticazione a due fattori, fornendo un <var>OATHToken</var> di <kbd>987654</kbd>.",
"apihelp-compare-description": "Ottieni le differenze tra 2 pagine.\n\nUn numero di revisione, il titolo di una pagina, o un ID di pagina deve essere indicato sia per il \"da\" che per lo \"a\".",
"apihelp-compare-param-fromtitle": "Primo titolo da confrontare.",
"apihelp-compare-param-fromid": "Primo ID di pagina da confrontare.",
"apihelp-compare-param-torev": "Seconda revisione da confrontare.",
"apihelp-compare-example-1": "Crea un diff tra revisione 1 e revisione 2.",
"apihelp-createaccount-description": "Crea un nuovo account utente.",
+ "apihelp-createaccount-param-preservestate": "Se <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> ha restituito true per <samp>hasprimarypreservedstate</samp>, le richieste contrassegnate come <samp>primary-required</samp> dovrebbero essere omesse. Se invece ha restituito un valore non vuoto per <samp>preservedusername</samp>, quel nome utente deve essere utilizzato per il parametro <var>username</var>.",
+ "apihelp-createaccount-example-create": "Avvia il processo di creazione utente <kbd>Example</kbd> con password <kbd>ExamplePassword</kbd>.",
"apihelp-createaccount-param-name": "Nome utente.",
"apihelp-createaccount-param-password": "Password (verrà ignorata se è impostato <var>$1mailpassword</var>).",
"apihelp-createaccount-param-domain": "Dominio per l'autenticazione esterna (opzionale).",
"apihelp-import-param-namespace": "Importa in questo namespace. Non può essere usato insieme a <var>$1rootpage</var>.",
"apihelp-import-param-rootpage": "Importa come sottopagina di questa pagina. Non può essere usato insieme a <var>$1namespace</var>.",
"apihelp-import-example-import": "Importa [[meta:Help:ParserFunctions]] nel namespace 100 con cronologia completa.",
+ "apihelp-linkaccount-description": "Collegamento di un'utenza di un provider di terze parti all'utente corrente.",
+ "apihelp-linkaccount-example-link": "Avvia il processo di collegamento ad un'utenza da <kbd>Example</kbd>.",
+ "apihelp-login-description": "Accedi e ottieni i cookie di autenticazione.\n\nQuesta azione deve essere usata esclusivamente in combinazione con [[Special:BotPasswords]]; utilizzarla per l'accesso all'account principale è deprecato e può fallire senza preavviso. Per accedere in modo sicuro all'utenza principale, usa <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
+ "apihelp-login-description-nobotpasswords": "Accedi e ottieni i cookies di autenticazione.\n\nQuesta azione è deprecata e può fallire senza preavviso. Per accedere in modo sicuro, usa [[Special:ApiHelp/clientlogin|action=clientlogin]].",
+ "apihelp-login-description-nonauthmanager": "Accedi e ottieni i cookie di autenticazione.\n\nIn caso di accesso riuscito, i cookies necessari saranno inclusi nella intestazioni di risposta HTTP. In caso di accesso fallito, ulteriori tentativi potrebbero essere limitati, in modo da contenere gli attacchi automatizzati per indovinare le password.",
"apihelp-login-param-name": "Nome utente.",
"apihelp-login-param-password": "Password.",
"apihelp-login-param-domain": "Dominio (opzionale).",
"apihelp-paraminfo-description": "Ottieni informazioni sui moduli API.",
"apihelp-paraminfo-param-helpformat": "Formato delle stringhe di aiuto.",
"apihelp-parse-param-summary": "Oggetto da analizzare.",
+ "apihelp-parse-param-redirects": "Se <var>$1page</var> o <var>$1pageid</var> è impostato come reindirizzamento, lo risolve.",
"apihelp-parse-param-prop": "Quali pezzi di informazioni ottenere:",
"apihelp-parse-example-text": "Analizza wikitext.",
"apihelp-parse-example-texttitle": "Analizza wikitext, specificando il titolo della pagina.",
"apihelp-query+allusers-param-excludegroup": "Escludi gli utenti nei gruppi indicati.",
"apihelp-query+allusers-param-prop": "Quali pezzi di informazioni includere:",
"apihelp-query+allusers-param-limit": "Quanti nomi utente totali restituire.",
+ "apihelp-query+authmanagerinfo-description": "Recupera informazioni circa l'attuale stato di autenticazione.",
+ "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "Verifica se lo stato di autenticazione dell'utente attuale è sufficiente per la specifica operazione sensibile alla sicurezza.",
+ "apihelp-query+authmanagerinfo-param-requestsfor": "Recupera informazioni circa le richieste di autenticazione necessarie per la specifica azione di autenticazione.",
+ "apihelp-query+filerepoinfo-example-login": "Recupera le richieste che possono essere utilizzate quando si inizia l'accesso.",
+ "apihelp-query+filerepoinfo-example-login-merged": "Recupera le richieste che possono essere utilizzate quando si inizia l'accesso, con i campi del modulo uniti.",
+ "apihelp-query+filerepoinfo-example-securitysensitiveoperation": "Verificare se l'autenticazione è sufficiente per l'azione <kbd>foo</kbd>.",
"apihelp-query+backlinks-description": "Trova tutte le pagine che puntano a quella specificata.",
"apihelp-query+backlinks-param-namespace": "Il namespace da elencare.",
"apihelp-query+backlinks-param-dir": "La direzione in cui elencare.",
"apihelp-query+userinfo-example-simple": "Ottieni informazioni sull'utente attuale.",
"apihelp-query+users-description": "Ottieni informazioni su un elenco di utenti.",
"apihelp-query+users-param-prop": "Quali pezzi di informazioni includere:",
+ "apihelp-query+users-paramvalue-prop-cancreate": "Indica se può essere creata un'utenza per nomi utente validi ma non registrati.",
"apihelp-query+users-param-users": "Un elenco di utenti di cui ottenere informazioni.",
"apihelp-query+watchlist-description": "Ottieni le ultime modifiche alle pagine tra gli osservati speciali dell'utente attuale.",
"apihelp-query+watchlist-param-start": "Il timestamp da cui iniziare l'elenco.",
"apihelp-query+watchlistraw-param-totitle": "Il titolo (con prefisso namespace) al quale interrompere l'elenco.",
"apihelp-query+watchlistraw-example-simple": "Elenca le pagine fra gli osservati speciali dell'utente attuale.",
"apihelp-query+watchlistraw-example-generator": "Recupera le informazioni sulle pagine fra gli osservati speciali dell'utente attuale.",
+ "apihelp-removeauthenticationdata-description": "Rimuove i dati di autenticazione per l'utente corrente.",
+ "apihelp-removeauthenticationdata-example-simple": "Tentativo di rimuovere gli attuali dati utente per <kbd>FooAuthenticationRequest</kbd>.",
+ "apihelp-resetpassword-description": "Invia una mail per reimpostare la password di un utente.",
+ "apihelp-resetpassword-description-noroutes": "Non sono disponibili rotte per la reimpostazione della password.\n\nAbilita le rotte in <var>[[mw:Manual:$wgPasswordResetRoutes|$wgPasswordResetRoutes]]</var> per usare questo modulo.",
+ "apihelp-resetpassword-param-user": "Utente in corso di ripristino.",
+ "apihelp-resetpassword-param-email": "Indirizzo di posta elettronica dell'utente in corso di ripristino.",
+ "apihelp-resetpassword-param-capture": "Restituisce le password temporanee che erano state inviate. Richiede il diritto utente <code>passwordreset</code>.",
+ "apihelp-resetpassword-example-user": "Invia una mail per reimpostare la password all'utente <kbd>Example</kbd>.",
+ "apihelp-resetpassword-example-email": "Invia una mail per reimpostare la password a tutti gli utenti con indirizzo di posta elettronica <kbd>user@example.com</kbd>.",
"apihelp-revisiondelete-description": "Cancella e ripristina le versioni.",
"apihelp-revisiondelete-param-type": "Tipo di cancellazione della versione effettuata.",
"apihelp-revisiondelete-param-hide": "Cosa nascondere per ogni versione.",
"apihelp-undelete-param-title": "Titolo della pagina da ripristinare.",
"apihelp-undelete-param-reason": "Motivo per il ripristino.",
"apihelp-undelete-param-tags": "Modifica etichette da applicare all'elemento del registro delle cancellazioni.",
+ "apihelp-unlinkaccount-description": "Rimuove un'utenza di terze parti collegata all'utente corrente.",
+ "apihelp-unlinkaccount-example-simple": "Tentativo di rimuovere il collegamento dell'utente corrente per il provider associato con <kbd>FooAuthenticationRequest</kbd>.",
"apihelp-upload-param-watch": "Osserva la pagina.",
"apihelp-upload-param-file": "Contenuto del file.",
"apihelp-upload-example-url": "Carica da un URL.",
"api-help-examples": "{{PLURAL:$1|Esempio|Esempi}}:",
"api-help-permissions": "{{PLURAL:$1|Permesso|Permessi}}:",
"api-help-open-in-apisandbox": "<small>[apri in una sandbox]</small>",
+ "api-help-authmanager-general-usage": "La procedura generale per usare questo modulo é:\n# Ottenere i campi disponibili da <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> con <kbd>amirequestsfor=$4</kbd>, e un token <kbd>$5</kbd> da <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.\n# Mostra i campi all'utente e ottieni i dati che invia.\n# Esegui un post a questo modulo, fornendo <var>$1returnurl</var> e ogni campo rilevante.\n# Controlla <samp>status</samp> nella response.\n#* Se hai ricevuto <samp>PASS</samp> o <samp>FAIL</samp>, hai finito. L'operazione nel primo caso è andata a buon fine, nel secondo no.\n#* Se hai ricevuto <samp>UI</samp>, mostra i nuovi campi all'utente e ottieni i dati che invia. Esegui un post a questo modulo con <var>$1continue</var> e i campi rilevanti settati, quindi ripeti il punto 4.\n#* Se hai ricevuto <samp>REDIRECT</samp>, dirigi l'utente a <samp>redirecttarget</samp> e aspetta che ritorni a <var>$1returnurl</var>. A quel punto esegui un post a questo modulo con <var>$1continue</var> e ogni campo passato all'URL di ritorno, e ripeti il punto 4.\n#* Se hai ricevuto <samp>RESTART</samp>, vuol dire che l'autenticazione ha funzionato ma non abbiamo un account collegato. Potresti considerare questo caso come <samp>UI</samp> o come <samp>FAIL</samp>.",
+ "api-help-authmanagerhelper-messageformat": "Formato da utilizzare per per la restituzione dei messaggi.",
+ "api-help-authmanagerhelper-preservestate": "Conserva lo stato da un precedente tentativo di accesso non riuscito, se possibile.",
+ "api-help-authmanagerhelper-returnurl": "URL di ritorno per i flussi di autenticazione di terze parti, deve essere assoluto. E' necessario fornirlo, oppure va fornito <var>$1continue</var>.\n\nAlla ricezione di una risposta <samp>REDIRECT</samp>, in genere si apre un browser o una vista web all'URL specificato <samp>redirecttarget</samp> per un flusso di autenticazione di terze parti. Quando questo è completato, la terza parte invierà il browser o la vista web a questo URL. Dovresti estrarre qualsiasi parametro POST o della richiesta dall'URL e passarli come un request <var>$1continue</var> a questo modulo API.",
+ "api-help-authmanagerhelper-additional-params": "Questo modulo accetta parametri aggiuntivi a seconda delle richieste di autenticazione disponibili. Utilizza <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> con <kbd>amirequestsfor=$1</kbd> (o una precedente risposta da questo modulo, se applicabile) per determinare le richieste disponibili e i campi usati da queste.",
"api-credits-header": "Crediti"
}
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "NoiX180"
+ ]
+ },
+ "apihelp-delete-example-simple": "Busak <kbd>Tepas</kbd>.",
+ "apihelp-query+backlinks-example-simple": "Tuduhaké pranala menyang <kbd>Kaca utama</kbd>.",
+ "apihelp-query+backlinks-example-generator": "Deleng pratélan bab kaca-kaca sing nggayut <kbd>Kaca utama</kbd>.",
+ "apihelp-query+contributors-example-simple": "Tuduhaké para nyumbang <kbd>Kaca Utama</kbd>."
+}
"apihelp-main-param-action": "수행할 동작",
"apihelp-main-param-format": "출력값의 형식.",
"apihelp-main-param-maxlag": "최대 랙은 미디어위키가 데이터베이스 복제된 클러스터에 설치되었을 때 사용될 수 있습니다. 특정한 행동이 사이트 복제 랙을 유발할 때, 이 변수는 클라이언트가 복제 랙이 설정된 숫자 아래로 내려갈 때까지 기다리도록 지시합니다. 과도한 랙의 경우, <samp>maxlag</samp> 오류 코드와 <samp>Waiting for $host: $lag seconds lagged</samp> 메시지가 제공됩니다.<br />[[mw:Manual:Maxlag_parameter|매뉴얼: Maxlag 변수]] 에서 더 많은 정보를 얻을 수 있습니다.",
- "apihelp-main-param-smaxage": "<code>s-maxage</code> HTTP ìº\90ì\8b\9c 컨í\8a¸ë¡¤ í\97¤ë\8d\94를 ì\84¤ì \95í\95©ë\8b\88ë\8b¤. ì\97\90ë\9f¬는 캐시되지 않습니다.",
- "apihelp-main-param-maxage": "<code>max-age</code> HTTP ìº\90ì\8b\9c 컨í\8a¸ë¡¤ í\97¤ë\8d\94를 ì\84¤ì \95í\95©ë\8b\88ë\8b¤. ì\97\90ë\9f¬는 캐시되지 않습니다.",
+ "apihelp-main-param-smaxage": "<code>s-maxage</code> HTTP ìº\90ì\8b\9c 컨í\8a¸ë¡¤ í\97¤ë\8d\94를 ì\84¤ì \95í\95©ë\8b\88ë\8b¤. ì\98¤ë¥\98는 캐시되지 않습니다.",
+ "apihelp-main-param-maxage": "<code>max-age</code> HTTP ìº\90ì\8b\9c 컨í\8a¸ë¡¤ í\97¤ë\8d\94를 ì\84¤ì \95í\95©ë\8b\88ë\8b¤. ì\98¤ë¥\98는 캐시되지 않습니다.",
"apihelp-main-param-assert": "<kbd>user</kbd> 플래그가 설정되어 있다면 로그인 여부를 체크하며, <kbd>bot</kbd> 플래그가 설정되어 있다면 봇 사용자 권한이 설정되어 있는지 확인합니다.",
"apihelp-main-param-requestid": "주어진 요청 값은 응답에 포함됩니다. 요청을 구분하기 위해 사용될 수 있습니다.",
"apihelp-main-param-servedby": "결과에 요청을 처리한 호스트네임을 포함합니다.",
"apihelp-checktoken-example-simple": "<kbd>csrf</kbd> 토큰의 유효성을 테스트합니다.",
"apihelp-clearhasmsg-description": "현재 사용자의 <code>hasmsg</code> 플래그를 비웁니다.",
"apihelp-clearhasmsg-example-1": "현재 계정의 <code>hasmsg</code> 플래그를 삭제합니다.",
+ "apihelp-compare-description": "두 문서 간의 차이를 가져옵니다.\n\n대상이 되는 두 문서의 판 번호나 문서 제목 또는 문서 ID를 지정해야 합니다.",
"apihelp-compare-param-fromtitle": "비교할 첫 이름.",
"apihelp-compare-param-fromid": "비교할 첫 문서 ID.",
"apihelp-compare-param-fromrev": "비교할 첫 판.",
- "apihelp-compare-param-totitle": "비교할 두번째 제목.",
- "apihelp-compare-param-toid": "비교할 두번째 문서 ID.",
- "apihelp-compare-param-torev": "비교할 두번째 판.",
+ "apihelp-compare-param-totitle": "비교할 두 번째 제목.",
+ "apihelp-compare-param-toid": "비교할 두 번째 문서 ID.",
+ "apihelp-compare-param-torev": "비교할 두 번째 판.",
"apihelp-compare-example-1": "판 1과 2의 차이를 생성합니다.",
"apihelp-createaccount-description": "새 사용자 계정을 만듭니다.",
"apihelp-createaccount-param-name": "사용자 이름",
"apihelp-delete-description": "문서 삭제",
"apihelp-delete-param-pageid": "삭제할 문서의 ID. <var>$1title</var>과 함께 사용할 수 없습니다.",
"apihelp-delete-param-reason": "삭제의 이유. 설정하지 않으면 자동 생성되는 이유를 사용합니다.",
+ "apihelp-delete-param-watch": "문서를 현재 사용자의 주시문서 목록에 추가합니다.",
"apihelp-delete-param-unwatch": "문서를 현재 사용자의 주시문서 목록에서 제거합니다.",
"apihelp-delete-example-simple": "<kbd>Main Page</kbd>를 삭제합니다.",
"apihelp-disabled-description": "이 모듈은 해제되었습니다.",
"apihelp-edit-param-minor": "사소한 편집.",
"apihelp-edit-param-notminor": "사소하지 않은 편집.",
"apihelp-edit-param-bot": "이 편집을 봇으로 표시.",
+ "apihelp-edit-param-nocreate": "페이지가 존재하지 않으면 오류를 출력합니다.",
+ "apihelp-edit-param-watch": "문서를 현재 사용자의 주시문서 목록에 추가합니다.",
"apihelp-edit-param-unwatch": "문서를 현재 사용자의 주시문서 목록에서 제거합니다.",
"apihelp-edit-param-redirect": "자동으로 넘겨주기 처리하기.",
"apihelp-edit-param-contentmodel": "새 콘텐츠의 콘텐츠 모델.",
"apihelp-login-param-password": "Senhal.",
"apihelp-login-param-domain": "Domeni (facultatiu).",
"apihelp-login-example-login": "Se connectar.",
- "apihelp-managetags-description": "Efectuar de prètzfaches de gestion relatius a la modificacion de las balisas.",
+ "apihelp-managetags-description": "Efectuar de prètzfaits de gestion relatius a la modificacion de las balisas.",
"apihelp-move-description": "Desplaçar una pagina.",
"apihelp-opensearch-param-search": "Cadena de recèrca.",
"apihelp-parse-example-page": "Analisar una pagina.",
"apihelp-query+watchlist-paramvalue-prop-comment": "Dodaje komentarz do edycji.",
"apihelp-query+watchlist-paramvalue-prop-timestamp": "Dodaje znacznik czasu edycji.",
"apihelp-query+watchlist-paramvalue-prop-sizes": "Dodaje starą i nową długość strony.",
+ "apihelp-resetpassword-description": "Wyślij użytkownikowi e-mail do resetowania hasła.",
+ "apihelp-resetpassword-example-email": "Wyślij e-mail do resetowania hasła do wszystkich użytkowników posiadających adres <kbd>user@example.com</kbd>.",
"apihelp-stashedit-param-title": "Tytuł edytowanej strony.",
"apihelp-stashedit-param-sectiontitle": "Tytuł nowej sekcji.",
"apihelp-stashedit-param-text": "Zawartość strony.",
"apihelp-block-param-nocreate": "د گڼون جوړولو مخ نيول.",
"apihelp-createaccount-param-name": "کارن-نوم.",
"apihelp-delete-description": "يو مخ ړنگول.",
- "apihelp-delete-example-simple": "<kbd>Main Page</kbd> ړنگول.",
+ "apihelp-delete-example-simple": "<kbd>لومړی مخ</kbd> ړنگول.",
"apihelp-edit-description": "مخونه جوړول او سمول.",
"apihelp-edit-param-sectiontitle": "د يوې نوې برخې سرليک.",
"apihelp-edit-param-text": "مخ مېنځپانگه.",
"apihelp-block-param-watchuser": "{{doc-apihelp-param|block|watchuser}}",
"apihelp-block-example-ip-simple": "{{doc-apihelp-example|block}}",
"apihelp-block-example-user-complex": "{{doc-apihelp-example|block}}",
+ "apihelp-changeauthenticationdata-description": "{{doc-apihelp-description|changeauthenticationdata}}",
+ "apihelp-changeauthenticationdata-example-password": "{{doc-apihelp-example|changeauthenticationdata}}",
"apihelp-checktoken-description": "{{doc-apihelp-description|checktoken}}",
"apihelp-checktoken-param-type": "{{doc-apihelp-param|checktoken|type}}",
"apihelp-checktoken-param-token": "{{doc-apihelp-param|checktoken|token}}",
"apihelp-checktoken-example-simple": "{{doc-apihelp-example|checktoken}}",
"apihelp-clearhasmsg-description": "{{doc-apihelp-description|clearhasmsg}}",
"apihelp-clearhasmsg-example-1": "{{doc-apihelp-example|clearhasmsg}}",
+ "apihelp-clientlogin-description": "{{doc-apihelp-description|clientlogin}}",
+ "apihelp-clientlogin-example-login": "{{doc-apihelp-example|clientlogin}}",
+ "apihelp-clientlogin-example-login2": "{{doc-apihelp-example|clientlogin}}",
"apihelp-compare-description": "{{doc-apihelp-description|compare}}",
"apihelp-compare-param-fromtitle": "{{doc-apihelp-param|compare|fromtitle}}",
"apihelp-compare-param-fromid": "{{doc-apihelp-param|compare|fromid}}",
"apihelp-compare-param-torev": "{{doc-apihelp-param|compare|torev}}",
"apihelp-compare-example-1": "{{doc-apihelp-example|compare}}",
"apihelp-createaccount-description": "{{doc-apihelp-description|createaccount}}",
+ "apihelp-createaccount-param-preservestate": "{{doc-apihelp-param|createaccount|preservestate|info=This message is displayed in addition to {{msg-mw|api-help-authmanagerhelper-preservestate}}.}}",
+ "apihelp-createaccount-example-create": "{{doc-apihelp-example|createaccount}}",
"apihelp-createaccount-param-name": "{{doc-apihelp-param|createaccount|name}}\n{{Identical|Username}}",
"apihelp-createaccount-param-password": "{{doc-apihelp-param|createaccount|password}}",
"apihelp-createaccount-param-domain": "{{doc-apihelp-param|createaccount|domain}}",
"apihelp-import-param-namespace": "{{doc-apihelp-param|import|namespace}}",
"apihelp-import-param-rootpage": "{{doc-apihelp-param|import|rootpage}}",
"apihelp-import-example-import": "{{doc-apihelp-example|import}}",
- "apihelp-login-description": "{{doc-apihelp-description|login}}",
+ "apihelp-linkaccount-description": "{{doc-apihelp-description|linkaccount}}",
+ "apihelp-linkaccount-example-link": "{{doc-apihelp-example|linkaccount}}",
+ "apihelp-login-description": "{{doc-apihelp-description|login|info=This message is used when <code>$wgEnableBotPasswords</code> is true.|seealso=* {{msg-mw|apihelp-login-description-nobotpasswords}}}}",
+ "apihelp-login-description-nobotpasswords": "{{doc-apihelp-description|login|info=This message is used when <code>$wgEnableBotPasswords</code> is false.|seealso=* {{msg-mw|apihelp-login-description}}}}",
+ "apihelp-login-description-nonauthmanager": "{{doc-apihelp-description|login|info=This message is used when <code>$wgDisableAuthManager</code> is true.|seealso=* {{msg-mw|apihelp-login-description}}}}",
"apihelp-login-param-name": "{{doc-apihelp-param|login|name}}\n{{Identical|Username}}",
"apihelp-login-param-password": "{{doc-apihelp-param|login|password}}\n{{Identical|Password}}",
"apihelp-login-param-domain": "{{doc-apihelp-param|login|domain}}",
"apihelp-query+allusers-param-activeusers": "{{doc-apihelp-param|query+allusers|activeusers|params=* $1 - Value of [[mw:Manual:$wgActiveUserDays]]|paramstart=2}}",
"apihelp-query+allusers-param-attachedwiki": "{{doc-apihelp-param|query+allusers|attachedwiki}}",
"apihelp-query+allusers-example-Y": "{{doc-apihelp-example|query+allusers}}",
+ "apihelp-query+authmanagerinfo-description": "{{doc-apihelp-description|query+authmanagerinfo}}",
+ "apihelp-query+authmanagerinfo-param-securitysensitiveoperation": "{{doc-apihelp-param|query+authmanagerinfo|securitysensitiveoperation}}",
+ "apihelp-query+authmanagerinfo-param-requestsfor": "{{doc-apihelp-param|query+authmanagerinfo|requestsfor}}",
+ "apihelp-query+filerepoinfo-example-login": "{{doc-apihelp-example|query+filerepoinfo}}",
+ "apihelp-query+filerepoinfo-example-login-merged": "{{doc-apihelp-example|query+filerepoinfo}}",
+ "apihelp-query+filerepoinfo-example-securitysensitiveoperation": "{{doc-apihelp-example|query+filerepoinfo}}",
"apihelp-query+backlinks-description": "{{doc-apihelp-description|query+backlinks}}",
"apihelp-query+backlinks-param-title": "{{doc-apihelp-param|query+backlinks|title}}",
"apihelp-query+backlinks-param-pageid": "{{doc-apihelp-param|query+backlinks|pageid}}",
"apihelp-query+prefixsearch-param-limit": "{{doc-apihelp-param|query+prefixsearch|limit}}",
"apihelp-query+prefixsearch-param-offset": "{{doc-apihelp-param|query+prefixsearch|offset}}",
"apihelp-query+prefixsearch-example-simple": "{{doc-apihelp-example|query+prefixsearch}}",
+ "apihelp-query+prefixsearch-param-profile": "{{doc-apihelp-param|query+prefixsearch|profile|paramvalues=1}}",
"apihelp-query+protectedtitles-description": "{{doc-apihelp-description|query+protectedtitles}}",
"apihelp-query+protectedtitles-param-namespace": "{{doc-apihelp-param|query+protectedtitles|namespace}}",
"apihelp-query+protectedtitles-param-level": "{{doc-apihelp-param|query+protectedtitles|level}}",
"apihelp-query+search-param-what": "{{doc-apihelp-param|query+search|what}}",
"apihelp-query+search-param-info": "{{doc-apihelp-param|query+search|info}}",
"apihelp-query+search-param-prop": "{{doc-apihelp-param|query+search|prop|paramvalues=1}}",
+ "apihelp-query+search-param-qiprofile": "{{doc-apihelp-param|query+search|qiprofile|paramvalues=1}}",
"apihelp-query+search-paramvalue-prop-size": "{{doc-apihelp-paramvalue|query+search|prop|size}}",
"apihelp-query+search-paramvalue-prop-wordcount": "{{doc-apihelp-paramvalue|query+search|prop|wordcount}}",
"apihelp-query+search-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+search|prop|timestamp}}",
"apihelp-query+siteinfo-paramvalue-prop-variables": "{{doc-apihelp-paramvalue|query+siteinfo|prop|variables}}",
"apihelp-query+siteinfo-paramvalue-prop-protocols": "{{doc-apihelp-paramvalue|query+siteinfo|prop|protocols}}",
"apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "{{doc-apihelp-paramvalue|query+siteinfo|prop|defaultoptions}}",
+ "apihelp-query+siteinfo-paramvalue-prop-uploaddialog": "{{doc-apihelp-paramvalue|query+siteinfo|prop|uploaddialog}}",
"apihelp-query+siteinfo-param-filteriw": "{{doc-apihelp-param|query+siteinfo|filteriw}}",
"apihelp-query+siteinfo-param-showalldb": "{{doc-apihelp-param|query+siteinfo|showalldb}}",
"apihelp-query+siteinfo-param-numberingroup": "{{doc-apihelp-param|query+siteinfo|numberingroup}}",
"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-paramvalue-prop-cancreate": "{{doc-apihelp-paramvalue|query+users|prop|cancreate}}",
"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+watchlistraw-param-totitle": "{{doc-apihelp-param|query+watchlistraw|totitle}}",
"apihelp-query+watchlistraw-example-simple": "{{doc-apihelp-example|query+watchlistraw}}",
"apihelp-query+watchlistraw-example-generator": "{{doc-apihelp-example|query+watchlistraw}}",
+ "apihelp-removeauthenticationdata-description": "{{doc-apihelp-description|removeauthenticationdata}}",
+ "apihelp-removeauthenticationdata-example-simple": "{{doc-apihelp-example|removeauthenticationdata}}",
+ "apihelp-resetpassword-description": "{{doc-apihelp-description|resetpassword|seealso=* {{msg-mw|apihelp-resetpassword-description-noroutes}}}}",
+ "apihelp-resetpassword-description-noroutes": "{{doc-apihelp-description|resetpassword|info=This message is used when no known routes are enabled in <var>[[mw:Manual:$wgPasswordResetRoutes|$wgPasswordResetRoutes]]</var>.|seealso={{msg-mw|apihelp-resetpassword-description}}}}",
+ "apihelp-resetpassword-param-user": "{{doc-apihelp-param|resetpassword|user}}",
+ "apihelp-resetpassword-param-email": "{{doc-apihelp-param|resetpassword|email}}",
+ "apihelp-resetpassword-param-capture": "{{doc-apihelp-param|resetpassword|capture}}",
+ "apihelp-resetpassword-example-user": "{{doc-apihelp-example|resetpassword}}",
+ "apihelp-resetpassword-example-email": "{{doc-apihelp-example|resetpassword}}",
"apihelp-revisiondelete-description": "{{doc-apihelp-description|revisiondelete}}",
"apihelp-revisiondelete-param-type": "{{doc-apihelp-param|revisiondelete|type}}",
"apihelp-revisiondelete-param-target": "{{doc-apihelp-param|revisiondelete|target}}",
"apihelp-undelete-param-watchlist": "{{doc-apihelp-param|undelete|watchlist}}",
"apihelp-undelete-example-page": "{{doc-apihelp-example|undelete}}",
"apihelp-undelete-example-revisions": "{{doc-apihelp-example|undelete}}",
+ "apihelp-unlinkaccount-description": "{{doc-apihelp-description|unlinkaccount}}",
+ "apihelp-unlinkaccount-example-simple": "{{doc-apihelp-example|unlinkaccount}}",
"apihelp-upload-description": "{{doc-apihelp-description|upload}}",
"apihelp-upload-param-filename": "{{doc-apihelp-param|upload|filename}}",
"apihelp-upload-param-comment": "{{doc-apihelp-param|upload|comment}}",
"api-help-permissions-granted-to": "Used to introduce the list of groups each permission is assigned to.\n\nParameters:\n* $1 - Number of groups\n* $2 - List of group names, comma-separated",
"api-help-right-apihighlimits": "{{technical}}{{doc-right|apihighlimits|prefix=api-help}}\nThis message is used instead of {{msg-mw|right-apihighlimits}} in the API help to display the actual limits.\n\nParameters:\n* $1 - Limit for slow queries\n* $2 - Limit for fast queries",
"api-help-open-in-apisandbox": "Text for the link to open an API example in [[Special:ApiSandbox]].",
+ "api-help-authmanager-general-usage": "Text giving a brief overview of how to use an AuthManager-using API module. Parameters:\n* $1 - Module parameter prefix, e.g. \"login\"\n* $2 - Module name, e.g. \"clientlogin\"\n* $3 - Module path, e.g. \"clientlogin\"\n* $4 - AuthManager action to use with this module.\n* $5 - Token type needed by the module.",
+ "api-help-authmanagerhelper-requests": "{{doc-apihelp-param|description=the \"requests\" parameter for AuthManager-using API modules|params=* $1 - AuthManager action used by this module|paramstart=2|noseealso=1}}",
+ "api-help-authmanagerhelper-request": "{{doc-apihelp-param|description=the \"request\" parameter for AuthManager-using API modules|params=* $1 - AuthManager action used by this module|paramstart=2|noseealso=1}}",
+ "api-help-authmanagerhelper-messageformat": "{{doc-apihelp-param|description=the \"messageformat\" parameter for AuthManager-using API modules|noseealso=1}}",
+ "api-help-authmanagerhelper-mergerequestfields": "{{doc-apihelp-param|description=the \"mergerequestfields\" parameter for AuthManager-using API modules|noseealso=1}}",
+ "api-help-authmanagerhelper-preservestate": "{{doc-apihelp-param|description=the \"preservestate\" parameter for AuthManager-using API modules|noseealso=1}}",
+ "api-help-authmanagerhelper-returnurl": "{{doc-apihelp-param|description=the \"returnurl\" parameter for AuthManager-using API modules|noseealso=1}}",
+ "api-help-authmanagerhelper-continue": "{{doc-apihelp-param|description=the \"continue\" parameter for AuthManager-using API modules|noseealso=1}}",
+ "api-help-authmanagerhelper-additional-params": "Message to display for AuthManager modules that take additional parameters to populate AuthenticationRequests. Parameters:\n* $1 - AuthManager action used by this module\n* $2 - Module parameter prefix, e.g. \"login\"\n* $3 - Module name, e.g. \"clientlogin\"\n* $4 - Module path, e.g. \"clientlogin\"",
"api-credits-header": "Header for the API credits section in the API help output\n{{Identical|Credit}}",
"api-credits": "API credits text, displayed in the API help output"
}
"apihelp-managetags-example-delete": "Radera <kbd>vandalims</kbd> taggen med andledningen: <kbd>Felstavat</kbd>",
"apihelp-managetags-example-activate": "Aktivera en tagg med namn <kbd>spam</kbd> med anledningen: <kbd>For use in edit patrolling</kbd>",
"apihelp-managetags-example-deactivate": "Inaktivera en tagg vid namn <kbd>spam</kbd> med anledningen: <kbd>No longer required</kbd>",
+ "apihelp-mergehistory-description": "Sammanfoga sidhistoriker.",
+ "apihelp-mergehistory-param-reason": "Orsaken till sammanfogning av historik.",
+ "apihelp-mergehistory-example-merge": "Sammanfoga hela historiken för <kbd>Oldpage</kbd> i <kbd>Newpage</kbd>.",
+ "apihelp-mergehistory-example-merge-timestamp": "Sammanfoga den sidversion av <kbd>Oldpage</kbd> daterad fram till <kbd>2015-12-31T04:37:41Z</kbd> till <kbd>Newpage</kbd>.",
"apihelp-move-description": "Flytta en sida.",
"apihelp-move-param-from": "Titeln på sidan du vill flytta. Kan inte användas tillsammans med <var>$1fromid</var>.",
"apihelp-move-param-fromid": "Sid-ID för sidan att byta namn. Kan inte användas tillsammans med <var>$1from</var>.",
"apihelp-query+allcategories-param-min": "Returnera endast kategorier med minst så här många medlemmar.",
"apihelp-query+allcategories-param-max": "Returnera endast kategorier med som mest så här många medlemmar.",
"apihelp-query+allcategories-param-limit": "Hur många kategorier att returnera.",
+ "apihelp-query+allcategories-paramvalue-prop-size": "Lägger till antal sidor i kategorin.",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "Märker kategorier som är dolda med <code>__HIDDENCAT__</code>.",
"apihelp-query+alldeletedrevisions-description": "Lista alla raderade revisioner av en användare or inom en namnrymd.",
"apihelp-query+alldeletedrevisions-paraminfo-useronly": "Kan endast användas med <var>$3user</var>.",
"apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "Kan inte användas med <var>$3user</var>.",
"@metadata": {
"authors": [
"AntanO",
- "கலைவாணன்"
+ "கலைவாணன்",
+ "Info-farmer"
]
},
+ "apihelp-main-param-action": "எச்செயலை செயற்படுத்த",
+ "apihelp-main-param-format": "பெற விரும்பும் கோப்பு வடிவம்",
+ "apihelp-main-param-requestid": "இங்கு கொடுக்கப்படும் மதிப்பானது, விளைவில் இணையும். கோரிக்கைகளை வேறுபடுத்தப் பயன்படலாம்.",
"apihelp-import-param-namespace": "இதனைப் பெயர்வெளிக்கு இறக்குமதி செய்யவும். <kbd>$1rootpage</kbd> அளவுருவை மீறச்செய்யும்.",
"apihelp-import-param-rootpage": "இப்பக்கத்தின் துணைப்பக்கமாக இறக்குமதி செய்யவும். <kbd>$1namespace</kbd> அளவுரு வழங்கப்பட்டிருந்தால் இது புறக்கணிக்கப்படும்.",
"api-help-source": "மூலம்: $1",
"@metadata": {
"authors": [
"Bharathesha Alasandemajalu",
- "Vishwanatha Badikana"
+ "Vishwanatha Badikana",
+ "VASANTH S.N."
]
},
+ "apihelp-createaccount-param-name": "ಸದಸ್ಯೆರ್ನ ಪುದರ್:",
+ "apihelp-delete-description": "ಪುಟೊಕುಲೆನ್ ಮಾಜಾಲೆ",
+ "apihelp-edit-param-minor": "ಎಲ್ಯೆಲ್ಯ ಬದಲಾವಣೆಲು",
+ "apihelp-edit-example-edit": "ಪುಟೊನ್ ಸಂಪಾದನೆ ಮಲ್ಪುಲೆ",
+ "apihelp-feedcontributions-param-year": "ಈ ಒರ್ಸೊರ್ದು(ಬೊಕ್ಕ ದುಂಬುದ):",
+ "apihelp-feedcontributions-param-month": "ಈ ತಿಂಗೊಲುರ್ದ್ (ಬೊಕ್ಕ ದುಂಬುದ):",
+ "apihelp-feedrecentchanges-example-simple": "ಇಂಚಿಪದ ಬದಲಾವಣೆಲೆನ್ ತೋಜಾಲೆ.",
+ "apihelp-login-param-name": "ಸದಸ್ಯೆರೆನ ಪುದರ್",
+ "apihelp-login-param-password": "ಪ್ರವೇಶ ಪದೊ",
+ "apihelp-login-example-login": "ಲಾಗಿನ್ ಆಲೆ",
"apihelp-query+watchlist-param-type": "ವಾ ನಮೂನೆದ ಬದಲಾವಣೆ ತೊಜವೋಡು",
"apihelp-query+watchlist-paramvalue-type-external": "ಪಿದಯೀದ ಬದಲಾವಣೇ",
"apihelp-query+watchlist-paramvalue-type-new": "ಪುಟೊ ಉಂಡುಮಾನ್ಪುನಾ"
"Macofe",
"Mix Gerder",
"Piramidion",
- "Andriykopanytsia"
+ "Andriykopanytsia",
+ "Максим Підліснюк"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Документація]]\n* [[mw:API:FAQ|ЧаПи]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Список розсилки]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Оголошення API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Баґи і запити]\n</div>\n<strong>Статус:</strong> Усі функції, вказані на цій сторінці, мають працювати, але API далі перебуває в активній розробці і може змінитися у будь-який момент. Підпишіться на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ список розсилки mediawiki-api-announce], щоб помічати оновлення.\n\n<strong>Хибні запити:</strong> Коли до API надсилаються хибні запити, буде відіслано HTTP-шапку з ключем «MediaWiki-API-Error», а тоді і значення шапки, і код помилки, надіслані назад, будуть встановлені з тим же значенням. Більше інформації див. на [[mw:API:Errors_and_warnings|API: Errors and warnings]].\n\n<strong>Тестування:</strong> Для зручності тестування запитів API, див. [[Special:ApiSandbox]].",
"apihelp-block-param-watchuser": "Спостерігати за сторінкою користувача чи IP-адреси і сторінкою обговорення.",
"apihelp-block-example-ip-simple": "Блокувати IP-адресу <kbd>192.0.2.5</kbd> на три дні з причиною <kbd>First strike</kbd>.",
"apihelp-block-example-user-complex": "Блокувати користувача<kbd>Vandal</kbd> на невизначений термін з причиною <kbd>Vandalism</kbd> і заборонити створення нових облікових записів та надсилання електронної пошти.",
+ "apihelp-changeauthenticationdata-description": "Зміна параметрів аутентифікації для поточного користувача.",
"apihelp-checktoken-description": "Перевірити коректність токена з <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
"apihelp-checktoken-param-type": "Тип токена, який тестується.",
"apihelp-checktoken-param-token": "Токен для тесту.",
"apihelp-query+siteinfo-paramvalue-prop-variables": "Видає список змінних ID.",
"apihelp-query+siteinfo-paramvalue-prop-protocols": "Видає список протоколів, дозволених у зовнішніх посиланнях.",
"apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Видає значення налаштувань користувача за замовчуванням.",
+ "apihelp-query+siteinfo-paramvalue-prop-uploaddialog": "Повертає конфігурацію діалогу завантаження.",
"apihelp-query+siteinfo-param-filteriw": "Видати лише локальні або лише нелокальні елементи карти інтервікі.",
"apihelp-query+siteinfo-param-showalldb": "Перелічити усі сервери баз даних, а не лише той, який робить найбільшу затримку.",
"apihelp-query+siteinfo-param-numberingroup": "Перераховує кількість користувачів у групах користувачів.",
"apihelp-block-param-reason": "Lý do cấm.",
"apihelp-block-param-nocreate": "Cấm tạo tài khoản.",
"apihelp-block-param-reblock": "Nếu người dùng này đã bị cấm, ghi đè lên vụ cấm đã tồn tại.",
+ "apihelp-block-param-watchuser": "Xem người dùng hoặc địa chỉ IP của người dùng và trang thảo luận.",
+ "apihelp-block-example-ip-simple": "Khóa địa chỉ IP <kbd>192.0.2.5</kbd> trong ba ngày với lý do <kbd>khiển trách lần đầu</kbd>.",
"apihelp-checktoken-param-type": "Kiểu dấu hiệu được kiểm thử.",
"apihelp-checktoken-param-token": "Dấu hiệu để kiểm thử.",
"apihelp-checktoken-example-simple": "Kiểm thử dấu hiệu <kbd>csrf</kbd> có hợp lệ hay không.",
"apihelp-edit-param-undo": "Hoàn tác sửa đổi này. Ghi đè $1text, $1prependtext và $ 1appendtext.",
"apihelp-edit-param-undoafter": "Hoàn tác tất cả các sửa đổi từ $1undo cho tới sửa đổi này. Nếu không được thiết lập, chỉ cần lùi lại một sửa đổi.",
"apihelp-edit-param-redirect": "Tự động giải quyết các chuyển hướng.",
+ "apihelp-edit-param-contentmodel": "Mô hình nội dung của nội dung mới.",
"apihelp-edit-example-edit": "Sửa đổi trang",
"apihelp-edit-example-prepend": "Đưa <kbd>__NOTOC__</kbd> vào đầu trang",
"apihelp-edit-example-undo": "Lùi sửa các thay đổi 13579–13585 và tự động tóm lược",
"apihelp-login-param-token": "Dấu hiệu đăng nhập được lấy trong yêu cầu đầu tiên.",
"apihelp-login-example-gettoken": "Lấy dấu hiệu đăng nhập",
"apihelp-login-example-login": "Đăng nhập",
+ "apihelp-logout-description": "Thoát ra và xóa dữ liệu phiên làm việc.",
"apihelp-logout-example-logout": "Đăng xuất người dùng hiện tại",
"apihelp-mergehistory-description": "Hợp nhất lịch sử trang.",
"apihelp-mergehistory-param-reason": "Lý do hợp nhất lịch sử.",
"apihelp-move-description": "Di chuyển trang.",
+ "apihelp-move-param-to": "Đặt tiêu đề để đổi tên trang.",
"apihelp-move-param-reason": "Lý do đổi tên.",
+ "apihelp-move-param-movetalk": "Đổi tên trang thảo luận, nếu nó tồn tại.",
"apihelp-move-param-movesubpages": "Đổi tên trang con, nếu có thể áp dụng.",
"apihelp-move-param-noredirect": "Không tạo trang đổi hướng.",
"apihelp-move-param-ignorewarnings": "Bỏ qua tất cả các cảnh báo.",
"apihelp-opensearch-param-search": "Chuỗi tìm kiếm.",
"apihelp-opensearch-param-limit": "Đa số kết quả để cho ra.",
"apihelp-opensearch-param-namespace": "Không gian tên để tìm kiếm.",
+ "apihelp-opensearch-param-suggest": "Không làm gì nếu <var> [[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> sai/lỗi.",
"apihelp-opensearch-param-format": "Định dạng kết quả được cho ra.",
"apihelp-opensearch-example-te": "Tìm trang bắt đầu với <kbd>Te</kbd>.",
"apihelp-options-example-reset": "Mặc định lại các tùy chọn",
"apihelp-paraminfo-description": "Lấy thông tin về các module API.",
"apihelp-paraminfo-param-helpformat": "Định dạng chuỗi trợ giúp.",
"apihelp-parse-param-summary": "Lời tóm lược để phân tích.",
+ "apihelp-parse-param-prop": "Những mẩu thông tin nào muốn có:",
"apihelp-parse-param-section": "Chỉ phân tích nội dung của số phần này.\n\nNếu có <kbd>new</kbd> thì phân tích <var>$1text</var> và <var>$1sectiontitle</var> như thể thêm phần mới vào trang.\n\nPhần <kbd>new</kbd> chỉ được chấp nhận khi định rõ <var>text</var>.",
"apihelp-parse-param-disablelimitreport": "Bỏ qua thông báo bộ tiền xử lý (“NewPP limit report”) khi cho ra kết quả bộ xử lý.",
"apihelp-parse-example-page": "Phân tích trang.",
"apihelp-query-param-prop": "Các thuộc tính để lấy khi truy vấn các trang.",
"apihelp-query-param-list": "Các danh sách để lấy.",
"apihelp-query-param-meta": "Siêu dữ liệu để lấy.",
+ "apihelp-query+allcategories-description": "Liệt kê tất cả các thể loại.",
+ "apihelp-query+allcategories-param-from": "Chọn thể loại để bắt đầu đếm.",
+ "apihelp-query+allcategories-param-to": "Chọn thể loại để dừng đếm.",
"apihelp-query+allcategories-param-dir": "Hướng xếp loại.",
+ "apihelp-query+allcategories-param-limit": "Có bao nhiêu thể loại được trả về.",
+ "apihelp-query+allfileusages-param-limit": "Có bao nhiêu số hạng mục được trả về.",
+ "apihelp-query+allimages-param-limit": "Có bao nhiêu hình ảnh trong tổng số được trả về.",
+ "apihelp-query+alllinks-param-limit": "Có bao nhiêu số hạng mục được trả về.",
+ "apihelp-query+allpages-param-limit": "Có bao nhiêu trang được trả về.",
+ "apihelp-query+allredirects-param-limit": "Có bao nhiêu số hạng mục được trả về.",
+ "apihelp-query+mystashedfiles-param-limit": "Có bao nhiêu tập tin nhận được.",
+ "apihelp-query+alltransclusions-param-limit": "Có bao nhiêu số hạng mục được trả về.",
+ "apihelp-query+allusers-param-limit": "Có bao nhiêu tên người dùng được trả về.",
+ "apihelp-query+backlinks-param-limit": "Tất cả có bao nhiêu trang trả về. Nếu <var>$1redirect</var> được kích hoạt, giới hạn áp dụng cho mỗi cấp độ riêng biệt (có nghĩa là lên đến 2*<var>$1limit</var> kết quả có thể được trả lại).",
+ "apihelp-query+categories-param-limit": "Có bao nhiêu thể loại được trả về.",
+ "apihelp-query+extlinks-param-limit": "Có bao nhiêu liên kết được trả về.",
+ "apihelp-query+exturlusage-param-limit": "Có bao nhiêu trang được trả về.",
+ "apihelp-query+filearchive-param-limit": "Tổng cộng có bao nhiêu hình ảnh được trả về.",
+ "apihelp-query+fileusage-param-limit": "Có bao nhiêu được trả về.",
+ "apihelp-query+images-param-limit": "Có bao nhiêu tập tin được trả về.",
+ "apihelp-query+langbacklinks-param-limit": "Tổng cộng có bao nhiêu trang được trả về.",
+ "apihelp-query+links-param-limit": "Có bao nhiêu liên kết được trả về.",
+ "apihelp-query+linkshere-param-limit": "Có bao nhiêu được trả về.",
+ "apihelp-query+logevents-param-limit": "Tổng cộng có bao nhiêu bài viết sự kiện được trả về.",
+ "apihelp-query+transcludedin-param-limit": "Có bao nhiêu được trả về.",
+ "apihelp-query+watchlist-param-limit": "Cả bao nhiêu kết quả được trả về trên mỗi yêu cầu.",
"apihelp-rollback-description": "Lùi lại sửa đổi cuối cùng của trang này.\n\nNếu người dùng cuối cùng đã sửa đổi trang này nhiều lần, tất cả chúng sẽ được lùi lại cùng một lúc.",
"apihelp-format-example-generic": "Cho ra kết quả truy vấn dưới dạng $1.",
"apihelp-json-description": "Cho ra dữ liệu dưới dạng JSON.",
"apihelp-block-param-watchuser": "监视用户或该 IP 的用户页和讨论页。",
"apihelp-block-example-ip-simple": "封禁IP地址<kbd>192.0.2.5</kbd>三天,原因<kbd>First strike</kbd>。",
"apihelp-block-example-user-complex": "无限期封禁用户<kbd>Vandal</kbd>,原因<kbd>Vandalism</kbd>,并阻止新账户创建和电子邮件发送。",
+ "apihelp-changeauthenticationdata-description": "更改当前用户的身份验证数据。",
+ "apihelp-changeauthenticationdata-example-password": "尝试更改当前用户的密码至<kbd>ExamplePassword</kbd>。",
"apihelp-checktoken-description": "从<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>检查令牌有效性。",
"apihelp-checktoken-param-type": "已开始测试的令牌类型。",
"apihelp-checktoken-param-token": "要测试的令牌。",
"apihelp-checktoken-example-simple": "测试<kbd>csrf</kbd>令牌的有效性。",
"apihelp-clearhasmsg-description": "清除当前用户的<code>hasmsg</code>标记。",
"apihelp-clearhasmsg-example-1": "清除当前用户的<code>hasmsg</code>标记。",
+ "apihelp-clientlogin-description": "使用交互式流登录wiki。",
+ "apihelp-clientlogin-example-login": "开始作为用户<kbd>Example</kbd>和密码<kbd>ExamplePassword</kbd>登录至wiki的过程。",
+ "apihelp-clientlogin-example-login2": "在<samp>UI</samp>响应双因素验证后继续登录,补充<var>OATHToken</var> <kbd>987654</kbd>。",
"apihelp-compare-description": "获取2个页面之间的差别。\n\n用于“from”和“to”的修订版本号、页面标题或页面 ID 必须获得通过。",
"apihelp-compare-param-fromtitle": "要比较的第一个标题。",
"apihelp-compare-param-fromid": "要比较的第一个页面 ID。",
"apihelp-compare-param-torev": "要比较的第二个修订版本。",
"apihelp-compare-example-1": "在版本1和2中创建差异。",
"apihelp-createaccount-description": "创建一个新用户账户。",
+ "apihelp-createaccount-example-create": "开始创建用户<kbd>Example</kbd>和密码<kbd>ExamplePassword</kbd>的过程。",
"apihelp-createaccount-param-name": "用户名。",
"apihelp-createaccount-param-password": "密码(如果设置<var>$1mailpassword</var>则忽略)。",
"apihelp-createaccount-param-domain": "外部身份验证域 (可选)。",
"apihelp-import-param-namespace": "导入至此名字空间。不能与<var>$1rootpage</var>一起使用。",
"apihelp-import-param-rootpage": "作为此页面的子页面导入。不能与<var>$1namespace</var>一起使用。",
"apihelp-import-example-import": "将页面[[meta:Help:ParserFunctions]]连带完整历史导入至100名字空间。",
- "apihelp-login-description": "登录并获得身份验证Cookie。\n\n在成功登录的情况下,所需的Cookie将包含在HTTP响应头中。在登录失败的情况下,进一步的尝试可能会被自动密码猜解攻击的限制所遏制。",
+ "apihelp-linkaccount-description": "将来自第三方提供商的账户链接至当前用户。",
+ "apihelp-linkaccount-example-link": "开始从<kbd>Example</kbd>链接至账户的过程。",
+ "apihelp-login-description": "登录并获取身份验证Cookie。\n\n此操作只应与[[Special:BotPasswords]]一起使用;用于主账户登录的方式已弃用,并可能在没有警告的情况下失败。要安全登录主账户,请使用<kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>。",
+ "apihelp-login-description-nobotpasswords": "登录并获取身份验证Cookie。\n\n此操作已弃用,并可能在没有警告的情况下失败。要安全登录,请使用<kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>。",
+ "apihelp-login-description-nonauthmanager": "登录并获取身份验证Cookie。\n\n在成功登录的情况下,所需的Cookie将包含在HTTP响应头中。在登录失败的情况下,进一步的尝试可能会被自动密码猜解攻击的限制所遏制。",
"apihelp-login-param-name": "用户名。",
"apihelp-login-param-password": "密码。",
"apihelp-login-param-domain": "域名(可选)。",
"apihelp-move-param-watchlist": "无条件地将页面加入至当前用户的监视列表或将其移除,使用设置或不更改监视。",
"apihelp-move-param-ignorewarnings": "忽略任何警告。",
"apihelp-move-example-move": "移动<kbd>Badtitle</kbd>到<kbd>Goodtitle</kbd>,不保留重定向。",
- "apihelp-opensearch-description": "使用OpenSearch协议搜索本wiki。",
+ "apihelp-opensearch-description": "使用OpenSearch协议搜索wiki。",
"apihelp-opensearch-param-search": "搜索字符串。",
"apihelp-opensearch-param-limit": "要返回的结果最大数。",
"apihelp-opensearch-param-namespace": "搜索的名字空间。",
"apihelp-opensearch-param-warningsaserror": "如果警告通过<kbd>format=json</kbd>提升,返回一个API错误而不是忽略它们。",
"apihelp-opensearch-example-te": "查找以<kbd>Te</kbd>开头的页面。",
"apihelp-options-description": "更改当前用户的偏好设置。\n\n只有注册在核心或者已安装扩展中的选项,或者具有<code>userjs-</code>键值前缀(旨在被用户脚本使用)的选项可被设置。",
- "apihelp-options-param-reset": "重置偏好设置到网站默认设置。",
+ "apihelp-options-param-reset": "将参数设置重置为网站默认值。",
"apihelp-options-param-resetkinds": "当<var>$1reset</var>选项被设置时,要重置的选项类型列表。",
"apihelp-options-param-change": "更改列表,以name=value格式化(例如skin=vector)。值不能包含管道字符。如果没提供值(甚至没有等号),例如optionname|otheroption|...,选项将重置为默认值。",
"apihelp-options-param-optionname": "应设置为由<var>$1optionvalue</var>提供值的选项名称。",
"apihelp-parse-description": "解析内容并返回解析器输出。\n\n参见<kbd>[[Special:ApiHelp/query|action=query]]</kbd>的各种prop-module以从页面的当前版本获得信息。\n\n这里有几种方法可以指定解析的文本:\n# 指定一个页面或修订,使用<var>$1page</var>、<var>$1pageid</var>或<var>$1oldid</var>。\n# 明确指定内容,使用<var>$1text</var>、<var>$1title</var>和<var>$1contentmodel</var>。\n# 只指定一段摘要解析。<var>$1prop</var>应提供一个空值。",
"apihelp-parse-param-title": "文本属于的页面标题。如果省略,<var>$1contentmodel</var>就必须被指定,且[[API]]将作为标题使用。",
"apihelp-parse-param-text": "要解析的文本。使用<var>$1title</var>或<var>$1contentmodel</var>以控制内容模型。",
- "apihelp-parse-param-summary": "所要解析的摘要。",
+ "apihelp-parse-param-summary": "要解析的摘要。",
"apihelp-parse-param-page": "解析此页的内容。不能与<var>$1text</var>和<var>$1title</var>一起使用。",
"apihelp-parse-param-pageid": "解析此页的内容。覆盖<var>$1page</var>。",
"apihelp-parse-param-redirects": "如果<var>$1page</var>或<var>$1pageid</var>被设置为一个重定向,则解析它。",
"apihelp-query+allusers-param-activeusers": "只列出最近$1{{PLURAL:$1|天}}内活跃的用户。",
"apihelp-query+allusers-param-attachedwiki": "与<kbd>$1prop=centralids</kbd>一起使用,也表明用户是否附加于此ID定义的wiki。",
"apihelp-query+allusers-example-Y": "列出以<kbd>Y</kbd>开头的用户。",
+ "apihelp-query+authmanagerinfo-description": "检索有关当前身份验证状态的信息。",
+ "apihelp-query+filerepoinfo-example-login": "检索当开始登录时可能使用的请求。",
+ "apihelp-query+filerepoinfo-example-login-merged": "检索当开始登录时可能使用的请求,并合并表单字段。",
+ "apihelp-query+filerepoinfo-example-securitysensitiveoperation": "测试身份验证对操作<kbd>foo</kbd>是否足够。",
"apihelp-query+backlinks-description": "查找所有链接至指定页面的页面。",
"apihelp-query+backlinks-param-title": "要搜索的标题。不能与<var>$1pageid</var>一起使用。",
"apihelp-query+backlinks-param-pageid": "要搜索的页面ID。不能与<var>$1title</var>一起使用。",
"apihelp-query+prefixsearch-param-limit": "要返回的结果最大数。",
"apihelp-query+prefixsearch-param-offset": "跳过的结果数。",
"apihelp-query+prefixsearch-example-simple": "搜索以<kbd>meaning</kbd>开头的页面标题。",
+ "apihelp-query+prefixsearch-param-profile": "搜索要使用的配置文件。",
"apihelp-query+protectedtitles-description": "列出所有被限制创建的标题。",
"apihelp-query+protectedtitles-param-namespace": "只列出这些名字空间的标题。",
"apihelp-query+protectedtitles-param-level": "只列出带这些保护级别的标题。",
"apihelp-query+search-param-what": "要执行的搜索类型。",
"apihelp-query+search-param-info": "要返回的元数据。",
"apihelp-query+search-param-prop": "要返回的属性:",
+ "apihelp-query+search-param-qiprofile": "查询要使用的独立描述(影响排序算法)。",
"apihelp-query+search-paramvalue-prop-size": "添加页面大小,单位为字节。",
"apihelp-query+search-paramvalue-prop-wordcount": "添加页面的字数。",
"apihelp-query+search-paramvalue-prop-timestamp": "添加页面上次编辑时的时间戳。",
"apihelp-query+search-paramvalue-prop-snippet": "Adds a parsed snippet of the page.",
"apihelp-query+search-paramvalue-prop-titlesnippet": "Adds a parsed snippet of the page title.",
- "apihelp-query+search-paramvalue-prop-redirectsnippet": "Adds a parsed snippet of the redirect title.",
+ "apihelp-query+search-paramvalue-prop-redirectsnippet": "添加被解析的重定向标题的片段。",
"apihelp-query+search-paramvalue-prop-redirecttitle": "Adds the title of the matching redirect.",
"apihelp-query+search-paramvalue-prop-sectionsnippet": "Adds a parsed snippet of the matching section title.",
"apihelp-query+search-paramvalue-prop-sectiontitle": "Adds the title of the matching section.",
"apihelp-query+search-paramvalue-prop-categorysnippet": "Adds a parsed snippet of the matching category.",
"apihelp-query+search-paramvalue-prop-isfilematch": "Adds a boolean indicating if the search matched file content.",
"apihelp-query+search-paramvalue-prop-score": "<span class=\"apihelp-deprecated\">已弃用并已忽略。</span>",
- "apihelp-query+search-paramvalue-prop-hasrelated": "<span class=\"apihelp-deprecated\">Deprecated and ignored.</span>",
+ "apihelp-query+search-paramvalue-prop-hasrelated": "<span class=\"apihelp-deprecated\">已弃用并已忽略。</span>",
"apihelp-query+search-param-limit": "返回的总计页面数。",
"apihelp-query+search-param-interwiki": "搜索结果中包含跨wiki结果,如果可用。",
"apihelp-query+search-param-backend": "要使用的搜索后端,如果没有则为默认。",
"apihelp-query+siteinfo-paramvalue-prop-variables": "返回变量ID列表。",
"apihelp-query+siteinfo-paramvalue-prop-protocols": "返回外部链接中允许的协议列表。",
"apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "返回用户设置的默认值。",
+ "apihelp-query+siteinfo-paramvalue-prop-uploaddialog": "返回上传对话框的配置。",
"apihelp-query+siteinfo-param-filteriw": "只返回跨wiki地图中的本地或非本地记录。",
"apihelp-query+siteinfo-param-showalldb": "列出所有数据库服务器,不只是最落后的那个。",
"apihelp-query+siteinfo-param-numberingroup": "列出用户组中的用户数。",
"apihelp-query+watchlistraw-param-totitle": "要列举的最终标题(带名字空间前缀)。",
"apihelp-query+watchlistraw-example-simple": "列出当前用户的监视列表中的页面。",
"apihelp-query+watchlistraw-example-generator": "检索当前用户监视列表上的页面的页面信息。",
+ "apihelp-removeauthenticationdata-description": "从当前用户移除身份验证数据。",
+ "apihelp-removeauthenticationdata-example-simple": "尝试移除当前用户的<kbd>FooAuthenticationRequest</kbd>数据。",
+ "apihelp-resetpassword-description": "向用户发送密码重置邮件。",
+ "apihelp-resetpassword-description-noroutes": "没有密码重置路由可用。\n\n在<var>[[mw:Manual:$wgPasswordResetRoutes|$wgPasswordResetRoutes]]</var>中启用路由以使用此模块。",
+ "apihelp-resetpassword-param-user": "正在重置的用户。",
+ "apihelp-resetpassword-param-email": "正在重置用户的电子邮件地址。",
+ "apihelp-resetpassword-param-capture": "返回已发送的临时密码。需要<code>passwordreset</code>用户权限。",
+ "apihelp-resetpassword-example-user": "向用户<kbd>Example</kbd>发送密码重置邮件。",
+ "apihelp-resetpassword-example-email": "向所有电子邮件地址为<kbd>user@example.com</kbd>的用户发送密码重置邮件。",
"apihelp-revisiondelete-description": "删除和恢复修订版本。",
"apihelp-revisiondelete-param-type": "正在执行的修订版本删除类型。",
"apihelp-revisiondelete-param-target": "要进行修订版本删除的页面标题,如果对某一类型需要。",
"apihelp-undelete-param-watchlist": "无条件地将页面加入至当前用户的监视列表或将其移除,使用设置或不更改监视。",
"apihelp-undelete-example-page": "恢复页面<kbd>Main Page</kbd>。",
"apihelp-undelete-example-revisions": "恢复<kbd>Main Page</kbd>的两个修订。",
+ "apihelp-unlinkaccount-description": "从当前用户移除已连接的第三方账户。",
+ "apihelp-unlinkaccount-example-simple": "尝试移除当前用户的,与<kbd>FooAuthenticationRequest</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* 完成一次由于警告而失败的早前上传,使用<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-sessionkey": "与$1filekey相同,基于向后兼容而维护。",
"apihelp-upload-param-stash": "如果设置,服务器将临时藏匿文件而不是加入存储库。",
"apihelp-upload-param-filesize": "全部上传的文件大小。",
- "apihelp-upload-param-offset": "块的偏移量(字节)。",
+ "apihelp-upload-param-offset": "数据块的偏移量(字节)。",
"apihelp-upload-param-chunk": "大块内容。",
"apihelp-upload-param-async": "在可能的情况下,使潜在的大文件操作异步进行。",
"apihelp-upload-param-checkstatus": "只检索指定文件密钥的上传状态。",
"api-help-permissions-granted-to": "{{PLURAL:$1|授予}}:$2",
"api-help-right-apihighlimits": "在API查询中使用更高的上限(慢查询:$1;快查询:$2)。慢查询的限制也适用于多值参数。",
"api-help-open-in-apisandbox": "<small>[在沙盒中打开]</small>",
+ "api-help-authmanagerhelper-request": "使用此身份验证请求,通过返回自<kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd>的<samp>id</samp>与<kbd>amirequestsfor=$1</kbd>。",
+ "api-help-authmanagerhelper-messageformat": "返回消息使用的格式。",
"api-credits-header": "制作人员",
"api-credits": "API 开发人员:\n* Yuri Astrakhan(创建者,2006年9月~2007年9月的开发组领导)\n* Roan Kattouw(2007年9月~2009年的开发组领导)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Brad Jorsch(2013年至今的开发组领导)\n\n请将您的评论、建议和问题发送至mediawiki-api@lists.wikimedia.org,或提交错误请求至https://phabricator.wikimedia.org/。"
}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use Config;
+use Psr\Log\LoggerInterface;
+
+/**
+ * A base class that implements some of the boilerplate for an AuthenticationProvider
+ * @ingroup Auth
+ * @since 1.27
+ */
+abstract class AbstractAuthenticationProvider implements AuthenticationProvider {
+ /** @var LoggerInterface */
+ protected $logger;
+ /** @var AuthManager */
+ protected $manager;
+ /** @var Config */
+ protected $config;
+
+ public function setLogger( LoggerInterface $logger ) {
+ $this->logger = $logger;
+ }
+
+ public function setManager( AuthManager $manager ) {
+ $this->manager = $manager;
+ }
+
+ public function setConfig( Config $config ) {
+ $this->config = $config;
+ }
+
+ /**
+ * @inheritdoc
+ * @note Override this if it makes sense to support more than one instance
+ */
+ public function getUniqueId() {
+ return static::class;
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use Password;
+use PasswordFactory;
+use Status;
+
+/**
+ * Basic framework for a primary authentication provider that uses passwords
+ * @ingroup Auth
+ * @since 1.27
+ */
+abstract class AbstractPasswordPrimaryAuthenticationProvider
+ extends AbstractPrimaryAuthenticationProvider
+{
+ /** @var bool Whether this provider should ABSTAIN (false) or FAIL (true) on password failure */
+ protected $authoritative;
+
+ private $passwordFactory = null;
+
+ /**
+ * @param array $params Settings
+ * - authoritative: Whether this provider should ABSTAIN (false) or FAIL
+ * (true) on password failure
+ */
+ public function __construct( array $params = [] ) {
+ $this->authoritative = !isset( $params['authoritative'] ) || (bool)$params['authoritative'];
+ }
+
+ /**
+ * Get the PasswordFactory
+ * @return PasswordFactory
+ */
+ protected function getPasswordFactory() {
+ if ( $this->passwordFactory === null ) {
+ $this->passwordFactory = new PasswordFactory();
+ $this->passwordFactory->init( $this->config );
+ }
+ return $this->passwordFactory;
+ }
+
+ /**
+ * Get a Password object from the hash
+ * @param string $hash
+ * @return Password
+ */
+ protected function getPassword( $hash ) {
+ $passwordFactory = $this->getPasswordFactory();
+ try {
+ return $passwordFactory->newFromCiphertext( $hash );
+ } catch ( \PasswordError $e ) {
+ $class = static::class;
+ $this->logger->debug( "Invalid password hash in {$class}::getPassword()" );
+ return $passwordFactory->newFromCiphertext( null );
+ }
+ }
+
+ /**
+ * Return the appropriate response for failure
+ * @param PasswordAuthenticationRequest $req
+ * @return AuthenticationResponse
+ */
+ protected function failResponse( PasswordAuthenticationRequest $req ) {
+ if ( $this->authoritative ) {
+ return AuthenticationResponse::newFail(
+ wfMessage( $req->password === '' ? 'wrongpasswordempty' : 'wrongpassword' )
+ );
+ } else {
+ return AuthenticationResponse::newAbstain();
+ }
+ }
+
+ /**
+ * Check that the password is valid
+ *
+ * This should be called *before* validating the password. If the result is
+ * not ok, login should fail immediately.
+ *
+ * @param string $username
+ * @param string $password
+ * @return Status
+ */
+ protected function checkPasswordValidity( $username, $password ) {
+ return \User::newFromName( $username )->checkPasswordValidity( $password );
+ }
+
+ /**
+ * Check if the password should be reset
+ *
+ * This should be called after a successful login. It sets 'reset-pass'
+ * authentication data if necessary, see
+ * ResetPassSecondaryAuthenticationProvider.
+ *
+ * @param string $username
+ * @param Status $status From $this->checkPasswordValidity()
+ * @param mixed $data Passed through to $this->getPasswordResetData()
+ */
+ protected function setPasswordResetFlag( $username, Status $status, $data = null ) {
+ $reset = $this->getPasswordResetData( $username, $data );
+
+ if ( !$reset && $this->config->get( 'InvalidPasswordReset' ) && !$status->isGood() ) {
+ $reset = (object)[
+ 'msg' => $status->getMessage( 'resetpass-validity-soft' ),
+ 'hard' => false,
+ ];
+ }
+
+ if ( $reset ) {
+ $this->manager->setAuthenticationSessionData( 'reset-pass', $reset );
+ }
+ }
+
+ /**
+ * Get password reset data, if any
+ *
+ * @param string $username
+ * @param mixed $data
+ * @return object|null { 'hard' => bool, 'msg' => Message }
+ */
+ protected function getPasswordResetData( $username, $data ) {
+ return null;
+ }
+
+ /**
+ * Get expiration date for a new password, if any
+ *
+ * @param string $username
+ * @return string|null
+ */
+ protected function getNewPasswordExpiry( $username ) {
+ $days = $this->config->get( 'PasswordExpirationDays' );
+ $expires = $days ? wfTimestamp( TS_MW, time() + $days * 86400 ) : null;
+
+ // Give extensions a chance to force an expiration
+ \Hooks::run( 'ResetPasswordExpiration', [ \User::newFromName( $username ), &$expires ] );
+
+ return $expires;
+ }
+
+ public function getAuthenticationRequests( $action, array $options ) {
+ switch ( $action ) {
+ case AuthManager::ACTION_LOGIN:
+ case AuthManager::ACTION_REMOVE:
+ case AuthManager::ACTION_CREATE:
+ case AuthManager::ACTION_CHANGE:
+ return [ new PasswordAuthenticationRequest() ];
+ default:
+ return [];
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+/**
+ * A base class that implements some of the boilerplate for a PreAuthenticationProvider
+ * @ingroup Auth
+ * @since 1.27
+ */
+abstract class AbstractPreAuthenticationProvider extends AbstractAuthenticationProvider
+ implements PreAuthenticationProvider
+{
+
+ public function getAuthenticationRequests( $action, array $options ) {
+ return [];
+ }
+
+ public function testForAuthentication( array $reqs ) {
+ return \StatusValue::newGood();
+ }
+
+ public function postAuthentication( $user, AuthenticationResponse $response ) {
+ }
+
+ public function testForAccountCreation( $user, $creator, array $reqs ) {
+ return \StatusValue::newGood();
+ }
+
+ public function testUserForCreation( $user, $autocreate ) {
+ return \StatusValue::newGood();
+ }
+
+ public function postAccountCreation( $user, $creator, AuthenticationResponse $response ) {
+ }
+
+ public function testForAccountLink( $user ) {
+ return \StatusValue::newGood();
+ }
+
+ public function postAccountLink( $user, AuthenticationResponse $response ) {
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use User;
+
+/**
+ * A base class that implements some of the boilerplate for a PrimaryAuthenticationProvider
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+abstract class AbstractPrimaryAuthenticationProvider extends AbstractAuthenticationProvider
+ implements PrimaryAuthenticationProvider
+{
+
+ public function continuePrimaryAuthentication( array $reqs ) {
+ throw new \BadMethodCallException( __METHOD__ . ' is not implemented.' );
+ }
+
+ public function postAuthentication( $user, AuthenticationResponse $response ) {
+ }
+
+ public function testUserCanAuthenticate( $username ) {
+ // Assume it can authenticate if it exists
+ return $this->testUserExists( $username );
+ }
+
+ /**
+ * @inheritdoc
+ * @note Reimplement this if you do anything other than
+ * User::getCanonicalName( $req->username ) to determine the user being
+ * authenticated.
+ */
+ public function providerNormalizeUsername( $username ) {
+ $name = User::getCanonicalName( $username );
+ return $name === false ? null : $name;
+ }
+
+ /**
+ * @inheritdoc
+ * @note Reimplement this if self::getAuthenticationRequests( AuthManager::ACTION_REMOVE )
+ * doesn't return requests that will revoke all access for the user.
+ */
+ public function providerRevokeAccessForUser( $username ) {
+ $reqs = $this->getAuthenticationRequests(
+ AuthManager::ACTION_REMOVE, [ 'username' => $username ]
+ );
+ foreach ( $reqs as $req ) {
+ $req->username = $username;
+ $req->action = AuthManager::ACTION_REMOVE;
+ $this->providerChangeAuthenticationData( $req );
+ }
+ }
+
+ public function providerAllowsPropertyChange( $property ) {
+ return true;
+ }
+
+ public function testForAccountCreation( $user, $creator, array $reqs ) {
+ return \StatusValue::newGood();
+ }
+
+ public function continuePrimaryAccountCreation( $user, $creator, array $reqs ) {
+ throw new \BadMethodCallException( __METHOD__ . ' is not implemented.' );
+ }
+
+ public function finishAccountCreation( $user, $creator, AuthenticationResponse $response ) {
+ return null;
+ }
+
+ public function postAccountCreation( $user, $creator, AuthenticationResponse $response ) {
+ }
+
+ public function testUserForCreation( $user, $autocreate ) {
+ return \StatusValue::newGood();
+ }
+
+ public function autoCreatedAccount( $user, $source ) {
+ }
+
+ public function beginPrimaryAccountLink( $user, array $reqs ) {
+ if ( $this->accountCreationType() === self::TYPE_LINK ) {
+ throw new \BadMethodCallException( __METHOD__ . ' is not implemented.' );
+ } else {
+ throw new \BadMethodCallException(
+ __METHOD__ . ' should not be called on a non-link provider.'
+ );
+ }
+ }
+
+ public function continuePrimaryAccountLink( $user, array $reqs ) {
+ throw new \BadMethodCallException( __METHOD__ . ' is not implemented.' );
+ }
+
+ public function postAccountLink( $user, AuthenticationResponse $response ) {
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+/**
+ * A base class that implements some of the boilerplate for a SecondaryAuthenticationProvider
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+abstract class AbstractSecondaryAuthenticationProvider extends AbstractAuthenticationProvider
+ implements SecondaryAuthenticationProvider
+{
+
+ public function continueSecondaryAuthentication( $user, array $reqs ) {
+ throw new \BadMethodCallException( __METHOD__ . ' is not implemented.' );
+ }
+
+ public function postAuthentication( $user, AuthenticationResponse $response ) {
+ }
+
+ public function providerAllowsPropertyChange( $property ) {
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ * @note Reimplement this if self::getAuthenticationRequests( AuthManager::ACTION_REMOVE )
+ * doesn't return requests that will revoke all access for the user.
+ */
+ public function providerRevokeAccessForUser( $username ) {
+ $reqs = $this->getAuthenticationRequests(
+ AuthManager::ACTION_REMOVE, [ 'username' => $username ]
+ );
+ foreach ( $reqs as $req ) {
+ $req->username = $username;
+ $this->providerChangeAuthenticationData( $req );
+ }
+ }
+
+ public function providerAllowsAuthenticationDataChange(
+ AuthenticationRequest $req, $checkData = true
+ ) {
+ return \StatusValue::newGood( 'ignored' );
+ }
+
+ public function providerChangeAuthenticationData( AuthenticationRequest $req ) {
+ }
+
+ public function testForAccountCreation( $user, $creator, array $reqs ) {
+ return \StatusValue::newGood();
+ }
+
+ public function continueSecondaryAccountCreation( $user, $creator, array $reqs ) {
+ throw new \BadMethodCallException( __METHOD__ . ' is not implemented.' );
+ }
+
+ public function postAccountCreation( $user, $creator, AuthenticationResponse $response ) {
+ }
+
+ public function testUserForCreation( $user, $autocreate ) {
+ return \StatusValue::newGood();
+ }
+
+ public function autoCreatedAccount( $user, $source ) {
+ }
+}
--- /dev/null
+<?php
+/**
+ * Authentication (and possibly Authorization in the future) system entry point
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use Config;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use Status;
+use StatusValue;
+use User;
+use WebRequest;
+
+/**
+ * This serves as the entry point to the authentication system.
+ *
+ * In the future, it may also serve as the entry point to the authorization
+ * system.
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+class AuthManager implements LoggerAwareInterface {
+ /** Log in with an existing (not necessarily local) user */
+ const ACTION_LOGIN = 'login';
+ /** Continue a login process that was interrupted by the need for user input or communication
+ * with an external provider */
+ const ACTION_LOGIN_CONTINUE = 'login-continue';
+ /** Create a new user */
+ const ACTION_CREATE = 'create';
+ /** Continue a user creation process that was interrupted by the need for user input or
+ * communication with an external provider */
+ const ACTION_CREATE_CONTINUE = 'create-continue';
+ /** Link an existing user to a third-party account */
+ const ACTION_LINK = 'link';
+ /** Continue a user linking process that was interrupted by the need for user input or
+ * communication with an external provider */
+ const ACTION_LINK_CONTINUE = 'link-continue';
+ /** Change a user's credentials */
+ const ACTION_CHANGE = 'change';
+ /** Remove a user's credentials */
+ const ACTION_REMOVE = 'remove';
+ /** Like ACTION_REMOVE but for linking providers only */
+ const ACTION_UNLINK = 'unlink';
+
+ /** Security-sensitive operations are ok. */
+ const SEC_OK = 'ok';
+ /** Security-sensitive operations should re-authenticate. */
+ const SEC_REAUTH = 'reauth';
+ /** Security-sensitive should not be performed. */
+ const SEC_FAIL = 'fail';
+
+ /** Auto-creation is due to SessionManager */
+ const AUTOCREATE_SOURCE_SESSION = \MediaWiki\Session\SessionManager::class;
+
+ /** @var AuthManager|null */
+ private static $instance = null;
+
+ /** @var WebRequest */
+ private $request;
+
+ /** @var Config */
+ private $config;
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ /** @var AuthenticationProvider[] */
+ private $allAuthenticationProviders = [];
+
+ /** @var PreAuthenticationProvider[] */
+ private $preAuthenticationProviders = null;
+
+ /** @var PrimaryAuthenticationProvider[] */
+ private $primaryAuthenticationProviders = null;
+
+ /** @var SecondaryAuthenticationProvider[] */
+ private $secondaryAuthenticationProviders = null;
+
+ /** @var CreatedAccountAuthenticationRequest[] */
+ private $createdAccountAuthenticationRequests = [];
+
+ /**
+ * Get the global AuthManager
+ * @return AuthManager
+ */
+ public static function singleton() {
+ global $wgDisableAuthManager;
+
+ if ( $wgDisableAuthManager ) {
+ throw new \BadMethodCallException( '$wgDisableAuthManager is set' );
+ }
+
+ if ( self::$instance === null ) {
+ self::$instance = new self(
+ \RequestContext::getMain()->getRequest(),
+ \ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
+ );
+ }
+ return self::$instance;
+ }
+
+ /**
+ * @param WebRequest $request
+ * @param Config $config
+ */
+ public function __construct( WebRequest $request, Config $config ) {
+ $this->request = $request;
+ $this->config = $config;
+ $this->setLogger( \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' ) );
+ }
+
+ /**
+ * @param LoggerInterface $logger
+ */
+ public function setLogger( LoggerInterface $logger ) {
+ $this->logger = $logger;
+ }
+
+ /**
+ * @return WebRequest
+ */
+ public function getRequest() {
+ return $this->request;
+ }
+
+ /**
+ * Force certain PrimaryAuthenticationProviders
+ * @deprecated For backwards compatibility only
+ * @param PrimaryAuthenticationProvider[] $providers
+ * @param string $why
+ */
+ public function forcePrimaryAuthenticationProviders( array $providers, $why ) {
+ $this->logger->warning( "Overriding AuthManager primary authn because $why" );
+
+ if ( $this->primaryAuthenticationProviders !== null ) {
+ $this->logger->warning(
+ 'PrimaryAuthenticationProviders have already been accessed! I hope nothing breaks.'
+ );
+
+ $this->allAuthenticationProviders = array_diff_key(
+ $this->allAuthenticationProviders,
+ $this->primaryAuthenticationProviders
+ );
+ $session = $this->request->getSession();
+ $session->remove( 'AuthManager::authnState' );
+ $session->remove( 'AuthManager::accountCreationState' );
+ $session->remove( 'AuthManager::accountLinkState' );
+ $this->createdAccountAuthenticationRequests = [];
+ }
+
+ $this->primaryAuthenticationProviders = [];
+ foreach ( $providers as $provider ) {
+ if ( !$provider instanceof PrimaryAuthenticationProvider ) {
+ throw new \RuntimeException(
+ 'Expected instance of MediaWiki\\Auth\\PrimaryAuthenticationProvider, got ' .
+ get_class( $provider )
+ );
+ }
+ $provider->setLogger( $this->logger );
+ $provider->setManager( $this );
+ $provider->setConfig( $this->config );
+ $id = $provider->getUniqueId();
+ if ( isset( $this->allAuthenticationProviders[$id] ) ) {
+ throw new \RuntimeException(
+ "Duplicate specifications for id $id (classes " .
+ get_class( $provider ) . ' and ' .
+ get_class( $this->allAuthenticationProviders[$id] ) . ')'
+ );
+ }
+ $this->allAuthenticationProviders[$id] = $provider;
+ $this->primaryAuthenticationProviders[$id] = $provider;
+ }
+ }
+
+ /**
+ * Call a legacy AuthPlugin method, if necessary
+ * @codeCoverageIgnore
+ * @deprecated For backwards compatibility only, should be avoided in new code
+ * @param string $method AuthPlugin method to call
+ * @param array $params Parameters to pass
+ * @param mixed $return Return value if AuthPlugin wasn't called
+ * @return mixed Return value from the AuthPlugin method, or $return
+ */
+ public static function callLegacyAuthPlugin( $method, array $params, $return = null ) {
+ global $wgAuth;
+
+ if ( $wgAuth && !$wgAuth instanceof AuthManagerAuthPlugin ) {
+ return call_user_func_array( [ $wgAuth, $method ], $params );
+ } else {
+ return $return;
+ }
+ }
+
+ /**
+ * @name Authentication
+ * @{
+ */
+
+ /**
+ * Indicate whether user authentication is possible
+ *
+ * It may not be if the session is provided by something like OAuth
+ * for which each individual request includes authentication data.
+ *
+ * @return bool
+ */
+ public function canAuthenticateNow() {
+ return $this->request->getSession()->canSetUser();
+ }
+
+ /**
+ * Start an authentication flow
+ *
+ * In addition to the AuthenticationRequests returned by
+ * $this->getAuthenticationRequests(), a client might include a
+ * CreateFromLoginAuthenticationRequest from a previous login attempt to
+ * preserve state.
+ *
+ * Instead of the AuthenticationRequests returned by
+ * $this->getAuthenticationRequests(), a client might pass a
+ * CreatedAccountAuthenticationRequest from an account creation that just
+ * succeeded to log in to the just-created account.
+ *
+ * @param AuthenticationRequest[] $reqs
+ * @param string $returnToUrl Url that REDIRECT responses should eventually
+ * return to.
+ * @return AuthenticationResponse See self::continueAuthentication()
+ */
+ public function beginAuthentication( array $reqs, $returnToUrl ) {
+ $session = $this->request->getSession();
+ if ( !$session->canSetUser() ) {
+ // Caller should have called canAuthenticateNow()
+ $session->remove( 'AuthManager::authnState' );
+ throw new \LogicException( 'Authentication is not possible now' );
+ }
+
+ $guessUserName = null;
+ foreach ( $reqs as $req ) {
+ $req->returnToUrl = $returnToUrl;
+ // @codeCoverageIgnoreStart
+ if ( $req->username !== null && $req->username !== '' ) {
+ if ( $guessUserName === null ) {
+ $guessUserName = $req->username;
+ } elseif ( $guessUserName !== $req->username ) {
+ $guessUserName = null;
+ break;
+ }
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ // Check for special-case login of a just-created account
+ $req = AuthenticationRequest::getRequestByClass(
+ $reqs, CreatedAccountAuthenticationRequest::class
+ );
+ if ( $req ) {
+ if ( !in_array( $req, $this->createdAccountAuthenticationRequests, true ) ) {
+ throw new \LogicException(
+ 'CreatedAccountAuthenticationRequests are only valid on ' .
+ 'the same AuthManager that created the account'
+ );
+ }
+
+ $user = User::newFromName( $req->username );
+ // @codeCoverageIgnoreStart
+ if ( !$user ) {
+ throw new \UnexpectedValueException(
+ "CreatedAccountAuthenticationRequest had invalid username \"{$req->username}\""
+ );
+ } elseif ( $user->getId() != $req->id ) {
+ throw new \UnexpectedValueException(
+ "ID for \"{$req->username}\" was {$user->getId()}, expected {$req->id}"
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $this->logger->info( 'Logging in {user} after account creation', [
+ 'user' => $user->getName(),
+ ] );
+ $ret = AuthenticationResponse::newPass( $user->getName() );
+ $this->setSessionDataForUser( $user );
+ $this->callMethodOnProviders( 7, 'postAuthentication', [ $user, $ret ] );
+ $session->remove( 'AuthManager::authnState' );
+ \Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $ret, $user, $user->getName() ] );
+ return $ret;
+ }
+
+ $this->removeAuthenticationSessionData( null );
+
+ foreach ( $this->getPreAuthenticationProviders() as $provider ) {
+ $status = $provider->testForAuthentication( $reqs );
+ if ( !$status->isGood() ) {
+ $this->logger->debug( 'Login failed in pre-authentication by ' . $provider->getUniqueId() );
+ $ret = AuthenticationResponse::newFail(
+ Status::wrap( $status )->getMessage()
+ );
+ $this->callMethodOnProviders( 7, 'postAuthentication',
+ [ User::newFromName( $guessUserName ) ?: null, $ret ]
+ );
+ \Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $ret, null, $guessUserName ] );
+ return $ret;
+ }
+ }
+
+ $state = [
+ 'reqs' => $reqs,
+ 'returnToUrl' => $returnToUrl,
+ 'guessUserName' => $guessUserName,
+ 'primary' => null,
+ 'primaryResponse' => null,
+ 'secondary' => [],
+ 'maybeLink' => [],
+ 'continueRequests' => [],
+ ];
+
+ // Preserve state from a previous failed login
+ $req = AuthenticationRequest::getRequestByClass(
+ $reqs, CreateFromLoginAuthenticationRequest::class
+ );
+ if ( $req ) {
+ $state['maybeLink'] = $req->maybeLink;
+ }
+
+ $session = $this->request->getSession();
+ $session->setSecret( 'AuthManager::authnState', $state );
+ $session->persist();
+
+ return $this->continueAuthentication( $reqs );
+ }
+
+ /**
+ * Continue an authentication flow
+ *
+ * Return values are interpreted as follows:
+ * - status FAIL: Authentication failed. If $response->createRequest is
+ * set, that may be passed to self::beginAuthentication() or to
+ * self::beginAccountCreation() to preserve state.
+ * - status REDIRECT: The client should be redirected to the contained URL,
+ * new AuthenticationRequests should be made (if any), then
+ * AuthManager::continueAuthentication() should be called.
+ * - status UI: The client should be presented with a user interface for
+ * the fields in the specified AuthenticationRequests, then new
+ * AuthenticationRequests should be made, then
+ * AuthManager::continueAuthentication() should be called.
+ * - status RESTART: The user logged in successfully with a third-party
+ * service, but the third-party credentials aren't attached to any local
+ * account. This could be treated as a UI or a FAIL.
+ * - status PASS: Authentication was successful.
+ *
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse
+ */
+ public function continueAuthentication( array $reqs ) {
+ $session = $this->request->getSession();
+ try {
+ if ( !$session->canSetUser() ) {
+ // Caller should have called canAuthenticateNow()
+ // @codeCoverageIgnoreStart
+ throw new \LogicException( 'Authentication is not possible now' );
+ // @codeCoverageIgnoreEnd
+ }
+
+ $state = $session->getSecret( 'AuthManager::authnState' );
+ if ( !is_array( $state ) ) {
+ return AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-authn-not-in-progress' )
+ );
+ }
+ $state['continueRequests'] = [];
+
+ $guessUserName = $state['guessUserName'];
+
+ foreach ( $reqs as $req ) {
+ $req->returnToUrl = $state['returnToUrl'];
+ }
+
+ // Step 1: Choose an primary authentication provider, and call it until it succeeds.
+
+ if ( $state['primary'] === null ) {
+ // We haven't picked a PrimaryAuthenticationProvider yet
+ // @codeCoverageIgnoreStart
+ $guessUserName = null;
+ foreach ( $reqs as $req ) {
+ if ( $req->username !== null && $req->username !== '' ) {
+ if ( $guessUserName === null ) {
+ $guessUserName = $req->username;
+ } elseif ( $guessUserName !== $req->username ) {
+ $guessUserName = null;
+ break;
+ }
+ }
+ }
+ $state['guessUserName'] = $guessUserName;
+ // @codeCoverageIgnoreEnd
+ $state['reqs'] = $reqs;
+
+ foreach ( $this->getPrimaryAuthenticationProviders() as $id => $provider ) {
+ $res = $provider->beginPrimaryAuthentication( $reqs );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS;
+ $state['primary'] = $id;
+ $state['primaryResponse'] = $res;
+ $this->logger->debug( "Primary login with $id succeeded" );
+ break 2;
+ case AuthenticationResponse::FAIL;
+ $this->logger->debug( "Login failed in primary authentication by $id" );
+ if ( $res->createRequest || $state['maybeLink'] ) {
+ $res->createRequest = new CreateFromLoginAuthenticationRequest(
+ $res->createRequest, $state['maybeLink']
+ );
+ }
+ $this->callMethodOnProviders( 7, 'postAuthentication',
+ [ User::newFromName( $guessUserName ) ?: null, $res ]
+ );
+ $session->remove( 'AuthManager::authnState' );
+ \Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $res, null, $guessUserName ] );
+ return $res;
+ case AuthenticationResponse::ABSTAIN;
+ // Continue loop
+ break;
+ case AuthenticationResponse::REDIRECT;
+ case AuthenticationResponse::UI;
+ $this->logger->debug( "Primary login with $id returned $res->status" );
+ $this->fillRequests( $res->neededRequests, self::ACTION_LOGIN, $guessUserName );
+ $state['primary'] = $id;
+ $state['continueRequests'] = $res->neededRequests;
+ $session->setSecret( 'AuthManager::authnState', $state );
+ return $res;
+
+ // @codeCoverageIgnoreStart
+ default:
+ throw new \DomainException(
+ get_class( $provider ) . "::beginPrimaryAuthentication() returned $res->status"
+ );
+ // @codeCoverageIgnoreEnd
+ }
+ }
+ if ( $state['primary'] === null ) {
+ $this->logger->debug( 'Login failed in primary authentication because no provider accepted' );
+ $ret = AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-authn-no-primary' )
+ );
+ $this->callMethodOnProviders( 7, 'postAuthentication',
+ [ User::newFromName( $guessUserName ) ?: null, $ret ]
+ );
+ $session->remove( 'AuthManager::authnState' );
+ return $ret;
+ }
+ } elseif ( $state['primaryResponse'] === null ) {
+ $provider = $this->getAuthenticationProvider( $state['primary'] );
+ if ( !$provider instanceof PrimaryAuthenticationProvider ) {
+ // Configuration changed? Force them to start over.
+ // @codeCoverageIgnoreStart
+ $ret = AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-authn-not-in-progress' )
+ );
+ $this->callMethodOnProviders( 7, 'postAuthentication',
+ [ User::newFromName( $guessUserName ) ?: null, $ret ]
+ );
+ $session->remove( 'AuthManager::authnState' );
+ return $ret;
+ // @codeCoverageIgnoreEnd
+ }
+ $id = $provider->getUniqueId();
+ $res = $provider->continuePrimaryAuthentication( $reqs );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS;
+ $state['primaryResponse'] = $res;
+ $this->logger->debug( "Primary login with $id succeeded" );
+ break;
+ case AuthenticationResponse::FAIL;
+ $this->logger->debug( "Login failed in primary authentication by $id" );
+ if ( $res->createRequest || $state['maybeLink'] ) {
+ $res->createRequest = new CreateFromLoginAuthenticationRequest(
+ $res->createRequest, $state['maybeLink']
+ );
+ }
+ $this->callMethodOnProviders( 7, 'postAuthentication',
+ [ User::newFromName( $guessUserName ) ?: null, $res ]
+ );
+ $session->remove( 'AuthManager::authnState' );
+ \Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $res, null, $guessUserName ] );
+ return $res;
+ case AuthenticationResponse::REDIRECT;
+ case AuthenticationResponse::UI;
+ $this->logger->debug( "Primary login with $id returned $res->status" );
+ $this->fillRequests( $res->neededRequests, self::ACTION_LOGIN, $guessUserName );
+ $state['continueRequests'] = $res->neededRequests;
+ $session->setSecret( 'AuthManager::authnState', $state );
+ return $res;
+ default:
+ throw new \DomainException(
+ get_class( $provider ) . "::continuePrimaryAuthentication() returned $res->status"
+ );
+ }
+ }
+
+ $res = $state['primaryResponse'];
+ if ( $res->username === null ) {
+ $provider = $this->getAuthenticationProvider( $state['primary'] );
+ if ( !$provider instanceof PrimaryAuthenticationProvider ) {
+ // Configuration changed? Force them to start over.
+ // @codeCoverageIgnoreStart
+ $ret = AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-authn-not-in-progress' )
+ );
+ $this->callMethodOnProviders( 7, 'postAuthentication',
+ [ User::newFromName( $guessUserName ) ?: null, $ret ]
+ );
+ $session->remove( 'AuthManager::authnState' );
+ return $ret;
+ // @codeCoverageIgnoreEnd
+ }
+
+ if ( $provider->accountCreationType() === PrimaryAuthenticationProvider::TYPE_LINK &&
+ $res->linkRequest &&
+ // don't confuse the user with an incorrect message if linking is disabled
+ $this->getAuthenticationProvider( ConfirmLinkSecondaryAuthenticationProvider::class )
+ ) {
+ $state['maybeLink'][$res->linkRequest->getUniqueId()] = $res->linkRequest;
+ $msg = 'authmanager-authn-no-local-user-link';
+ } else {
+ $msg = 'authmanager-authn-no-local-user';
+ }
+ $this->logger->debug(
+ "Primary login with {$provider->getUniqueId()} succeeded, but returned no user"
+ );
+ $ret = AuthenticationResponse::newRestart( wfMessage( $msg ) );
+ $ret->neededRequests = $this->getAuthenticationRequestsInternal(
+ self::ACTION_LOGIN,
+ [],
+ $this->getPrimaryAuthenticationProviders() + $this->getSecondaryAuthenticationProviders()
+ );
+ if ( $res->createRequest || $state['maybeLink'] ) {
+ $ret->createRequest = new CreateFromLoginAuthenticationRequest(
+ $res->createRequest, $state['maybeLink']
+ );
+ $ret->neededRequests[] = $ret->createRequest;
+ }
+ $this->fillRequests( $ret->neededRequests, self::ACTION_LOGIN, null, true );
+ $session->setSecret( 'AuthManager::authnState', [
+ 'reqs' => [], // Will be filled in later
+ 'primary' => null,
+ 'primaryResponse' => null,
+ 'secondary' => [],
+ 'continueRequests' => $ret->neededRequests,
+ ] + $state );
+ return $ret;
+ }
+
+ // Step 2: Primary authentication succeeded, create the User object
+ // (and add the user locally if necessary)
+
+ $user = User::newFromName( $res->username, 'usable' );
+ if ( !$user ) {
+ throw new \DomainException(
+ get_class( $provider ) . " returned an invalid username: {$res->username}"
+ );
+ }
+ if ( $user->getId() === 0 ) {
+ // User doesn't exist locally. Create it.
+ $this->logger->info( 'Auto-creating {user} on login', [
+ 'user' => $user->getName(),
+ ] );
+ $status = $this->autoCreateUser( $user, $state['primary'], false );
+ if ( !$status->isGood() ) {
+ $ret = AuthenticationResponse::newFail(
+ Status::wrap( $status )->getMessage( 'authmanager-authn-autocreate-failed' )
+ );
+ $this->callMethodOnProviders( 7, 'postAuthentication', [ $user, $ret ] );
+ $session->remove( 'AuthManager::authnState' );
+ \Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $ret, $user, $user->getName() ] );
+ return $ret;
+ }
+ }
+
+ // Step 3: Iterate over all the secondary authentication providers.
+
+ $beginReqs = $state['reqs'];
+
+ foreach ( $this->getSecondaryAuthenticationProviders() as $id => $provider ) {
+ if ( !isset( $state['secondary'][$id] ) ) {
+ // This provider isn't started yet, so we pass it the set
+ // of reqs from beginAuthentication instead of whatever
+ // might have been used by a previous provider in line.
+ $func = 'beginSecondaryAuthentication';
+ $res = $provider->beginSecondaryAuthentication( $user, $beginReqs );
+ } elseif ( !$state['secondary'][$id] ) {
+ $func = 'continueSecondaryAuthentication';
+ $res = $provider->continueSecondaryAuthentication( $user, $reqs );
+ } else {
+ continue;
+ }
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS;
+ $this->logger->debug( "Secondary login with $id succeeded" );
+ // fall through
+ case AuthenticationResponse::ABSTAIN;
+ $state['secondary'][$id] = true;
+ break;
+ case AuthenticationResponse::FAIL;
+ $this->logger->debug( "Login failed in secondary authentication by $id" );
+ $this->callMethodOnProviders( 7, 'postAuthentication', [ $user, $res ] );
+ $session->remove( 'AuthManager::authnState' );
+ \Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $res, $user, $user->getName() ] );
+ return $res;
+ case AuthenticationResponse::REDIRECT;
+ case AuthenticationResponse::UI;
+ $this->logger->debug( "Secondary login with $id returned " . $res->status );
+ $this->fillRequests( $res->neededRequests, self::ACTION_LOGIN, $user->getName() );
+ $state['secondary'][$id] = false;
+ $state['continueRequests'] = $res->neededRequests;
+ $session->setSecret( 'AuthManager::authnState', $state );
+ return $res;
+
+ // @codeCoverageIgnoreStart
+ default:
+ throw new \DomainException(
+ get_class( $provider ) . "::{$func}() returned $res->status"
+ );
+ // @codeCoverageIgnoreEnd
+ }
+ }
+
+ // Step 4: Authentication complete! Set the user in the session and
+ // clean up.
+
+ $this->logger->info( 'Login for {user} succeeded', [
+ 'user' => $user->getName(),
+ ] );
+ $req = AuthenticationRequest::getRequestByClass(
+ $beginReqs, RememberMeAuthenticationRequest::class
+ );
+ $this->setSessionDataForUser( $user, $req && $req->rememberMe );
+ $ret = AuthenticationResponse::newPass( $user->getName() );
+ $this->callMethodOnProviders( 7, 'postAuthentication', [ $user, $ret ] );
+ $session->remove( 'AuthManager::authnState' );
+ $this->removeAuthenticationSessionData( null );
+ \Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $ret, $user, $user->getName() ] );
+ return $ret;
+ } catch ( \Exception $ex ) {
+ $session->remove( 'AuthManager::authnState' );
+ throw $ex;
+ }
+ }
+
+ /**
+ * Whether security-sensitive operations should proceed.
+ *
+ * A "security-sensitive operation" is something like a password or email
+ * change, that would normally have a "reenter your password to confirm"
+ * box if we only supported password-based authentication.
+ *
+ * @param string $operation Operation being checked. This should be a
+ * message-key-like string such as 'change-password' or 'change-email'.
+ * @return string One of the SEC_* constants.
+ */
+ public function securitySensitiveOperationStatus( $operation ) {
+ $status = self::SEC_OK;
+
+ $this->logger->debug( __METHOD__ . ": Checking $operation" );
+
+ $session = $this->request->getSession();
+ $aId = $session->getUser()->getId();
+ if ( $aId === 0 ) {
+ // User isn't authenticated. DWIM?
+ $status = $this->canAuthenticateNow() ? self::SEC_REAUTH : self::SEC_FAIL;
+ $this->logger->info( __METHOD__ . ": Not logged in! $operation is $status" );
+ return $status;
+ }
+
+ if ( $session->canSetUser() ) {
+ $id = $session->get( 'AuthManager:lastAuthId' );
+ $last = $session->get( 'AuthManager:lastAuthTimestamp' );
+ if ( $id !== $aId || $last === null ) {
+ $timeSinceLogin = PHP_INT_MAX; // Forever ago
+ } else {
+ $timeSinceLogin = max( 0, time() - $last );
+ }
+
+ $thresholds = $this->config->get( 'ReauthenticateTime' );
+ if ( isset( $thresholds[$operation] ) ) {
+ $threshold = $thresholds[$operation];
+ } elseif ( isset( $thresholds['default'] ) ) {
+ $threshold = $thresholds['default'];
+ } else {
+ throw new \UnexpectedValueException( '$wgReauthenticateTime lacks a default' );
+ }
+
+ if ( $threshold >= 0 && $timeSinceLogin > $threshold ) {
+ $status = self::SEC_REAUTH;
+ }
+ } else {
+ $timeSinceLogin = -1;
+
+ $pass = $this->config->get( 'AllowSecuritySensitiveOperationIfCannotReauthenticate' );
+ if ( isset( $pass[$operation] ) ) {
+ $status = $pass[$operation] ? self::SEC_OK : self::SEC_FAIL;
+ } elseif ( isset( $pass['default'] ) ) {
+ $status = $pass['default'] ? self::SEC_OK : self::SEC_FAIL;
+ } else {
+ throw new \UnexpectedValueException(
+ '$wgAllowSecuritySensitiveOperationIfCannotReauthenticate lacks a default'
+ );
+ }
+ }
+
+ \Hooks::run( 'SecuritySensitiveOperationStatus', [
+ &$status, $operation, $session, $timeSinceLogin
+ ] );
+
+ // If authentication is not possible, downgrade from "REAUTH" to "FAIL".
+ if ( !$this->canAuthenticateNow() && $status === self::SEC_REAUTH ) {
+ $status = self::SEC_FAIL;
+ }
+
+ $this->logger->info( __METHOD__ . ": $operation is $status" );
+
+ return $status;
+ }
+
+ /**
+ * Determine whether a username can authenticate
+ *
+ * @param string $username
+ * @return bool
+ */
+ public function userCanAuthenticate( $username ) {
+ foreach ( $this->getPrimaryAuthenticationProviders() as $provider ) {
+ if ( $provider->testUserCanAuthenticate( $username ) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Provide normalized versions of the username for security checks
+ *
+ * Since different providers can normalize the input in different ways,
+ * this returns an array of all the different ways the name might be
+ * normalized for authentication.
+ *
+ * The returned strings should not be revealed to the user, as that might
+ * leak private information (e.g. an email address might be normalized to a
+ * username).
+ *
+ * @param string $username
+ * @return string[]
+ */
+ public function normalizeUsername( $username ) {
+ $ret = [];
+ foreach ( $this->getPrimaryAuthenticationProviders() as $provider ) {
+ $normalized = $provider->providerNormalizeUsername( $username );
+ if ( $normalized !== null ) {
+ $ret[$normalized] = true;
+ }
+ }
+ return array_keys( $ret );
+ }
+
+ /**@}*/
+
+ /**
+ * @name Authentication data changing
+ * @{
+ */
+
+ /**
+ * Revoke any authentication credentials for a user
+ *
+ * After this, the user should no longer be able to log in.
+ *
+ * @param string $username
+ */
+ public function revokeAccessForUser( $username ) {
+ $this->logger->info( 'Revoking access for {user}', [
+ 'user' => $username,
+ ] );
+ $this->callMethodOnProviders( 6, 'providerRevokeAccessForUser', [ $username ] );
+ }
+
+ /**
+ * Validate a change of authentication data (e.g. passwords)
+ * @param AuthenticationRequest $req
+ * @param bool $checkData If false, $req hasn't been loaded from the
+ * submission so checks on user-submitted fields should be skipped. $req->username is
+ * considered user-submitted for this purpose, even if it cannot be changed via
+ * $req->loadFromSubmission.
+ * @return Status
+ */
+ public function allowsAuthenticationDataChange( AuthenticationRequest $req, $checkData = true ) {
+ $any = false;
+ $providers = $this->getPrimaryAuthenticationProviders() +
+ $this->getSecondaryAuthenticationProviders();
+ foreach ( $providers as $provider ) {
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, $checkData );
+ if ( !$status->isGood() ) {
+ return Status::wrap( $status );
+ }
+ $any = $any || $status->value !== 'ignored';
+ }
+ if ( !$any ) {
+ $status = Status::newGood( 'ignored' );
+ $status->warning( 'authmanager-change-not-supported' );
+ return $status;
+ }
+ return Status::newGood();
+ }
+
+ /**
+ * Change authentication data (e.g. passwords)
+ *
+ * If $req was returned for AuthManager::ACTION_CHANGE, using $req should
+ * result in a successful login in the future.
+ *
+ * If $req was returned for AuthManager::ACTION_REMOVE, using $req should
+ * no longer result in a successful login.
+ *
+ * @param AuthenticationRequest $req
+ */
+ public function changeAuthenticationData( AuthenticationRequest $req ) {
+ $this->logger->info( 'Changing authentication data for {user} class {what}', [
+ 'user' => is_string( $req->username ) ? $req->username : '<no name>',
+ 'what' => get_class( $req ),
+ ] );
+
+ $this->callMethodOnProviders( 6, 'providerChangeAuthenticationData', [ $req ] );
+
+ // When the main account's authentication data is changed, invalidate
+ // all BotPasswords too.
+ \BotPassword::invalidateAllPasswordsForUser( $req->username );
+ }
+
+ /**@}*/
+
+ /**
+ * @name Account creation
+ * @{
+ */
+
+ /**
+ * Determine whether accounts can be created
+ * @return bool
+ */
+ public function canCreateAccounts() {
+ foreach ( $this->getPrimaryAuthenticationProviders() as $provider ) {
+ switch ( $provider->accountCreationType() ) {
+ case PrimaryAuthenticationProvider::TYPE_CREATE:
+ case PrimaryAuthenticationProvider::TYPE_LINK:
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine whether a particular account can be created
+ * @param string $username
+ * @param int $flags Bitfield of User:READ_* constants
+ * @return Status
+ */
+ public function canCreateAccount( $username, $flags = User::READ_NORMAL ) {
+ if ( !$this->canCreateAccounts() ) {
+ return Status::newFatal( 'authmanager-create-disabled' );
+ }
+
+ if ( $this->userExists( $username, $flags ) ) {
+ return Status::newFatal( 'userexists' );
+ }
+
+ $user = User::newFromName( $username, 'creatable' );
+ if ( !is_object( $user ) ) {
+ return Status::newFatal( 'noname' );
+ } else {
+ $user->load( $flags ); // Explicitly load with $flags, auto-loading always uses READ_NORMAL
+ if ( $user->getId() !== 0 ) {
+ return Status::newFatal( 'userexists' );
+ }
+ }
+
+ // Denied by providers?
+ $providers = $this->getPreAuthenticationProviders() +
+ $this->getPrimaryAuthenticationProviders() +
+ $this->getSecondaryAuthenticationProviders();
+ foreach ( $providers as $provider ) {
+ $status = $provider->testUserForCreation( $user, false );
+ if ( !$status->isGood() ) {
+ return Status::wrap( $status );
+ }
+ }
+
+ return Status::newGood();
+ }
+
+ /**
+ * Basic permissions checks on whether a user can create accounts
+ * @param User $creator User doing the account creation
+ * @return Status
+ */
+ public function checkAccountCreatePermissions( User $creator ) {
+ // Wiki is read-only?
+ if ( wfReadOnly() ) {
+ return Status::newFatal( 'readonlytext', wfReadOnlyReason() );
+ }
+
+ // This is awful, this permission check really shouldn't go through Title.
+ $permErrors = \SpecialPage::getTitleFor( 'CreateAccount' )
+ ->getUserPermissionsErrors( 'createaccount', $creator, 'secure' );
+ if ( $permErrors ) {
+ $status = Status::newGood();
+ foreach ( $permErrors as $args ) {
+ call_user_func_array( [ $status, 'fatal' ], $args );
+ }
+ return $status;
+ }
+
+ $block = $creator->isBlockedFromCreateAccount();
+ if ( $block ) {
+ $errorParams = [
+ $block->getTarget(),
+ $block->mReason ?: wfMessage( 'blockednoreason' )->text(),
+ $block->getByName()
+ ];
+
+ if ( $block->getType() === \Block::TYPE_RANGE ) {
+ $errorMessage = 'cantcreateaccount-range-text';
+ $errorParams[] = $this->getRequest()->getIP();
+ } else {
+ $errorMessage = 'cantcreateaccount-text';
+ }
+
+ return Status::newFatal( wfMessage( $errorMessage, $errorParams ) );
+ }
+
+ $ip = $this->getRequest()->getIP();
+ if ( $creator->isDnsBlacklisted( $ip, true /* check $wgProxyWhitelist */ ) ) {
+ return Status::newFatal( 'sorbs_create_account_reason' );
+ }
+
+ return Status::newGood();
+ }
+
+ /**
+ * Start an account creation flow
+ *
+ * In addition to the AuthenticationRequests returned by
+ * $this->getAuthenticationRequests(), a client might include a
+ * CreateFromLoginAuthenticationRequest from a previous login attempt. If
+ * <code>
+ * $createFromLoginAuthenticationRequest->hasPrimaryStateForAction( AuthManager::ACTION_CREATE )
+ * </code>
+ * returns true, any AuthenticationRequest::PRIMARY_REQUIRED requests
+ * should be omitted. If the CreateFromLoginAuthenticationRequest has a
+ * username set, that username must be used for all other requests.
+ *
+ * @param User $creator User doing the account creation
+ * @param AuthenticationRequest[] $reqs
+ * @param string $returnToUrl Url that REDIRECT responses should eventually
+ * return to.
+ * @return AuthenticationResponse
+ */
+ public function beginAccountCreation( User $creator, array $reqs, $returnToUrl ) {
+ $session = $this->request->getSession();
+ if ( !$this->canCreateAccounts() ) {
+ // Caller should have called canCreateAccounts()
+ $session->remove( 'AuthManager::accountCreationState' );
+ throw new \LogicException( 'Account creation is not possible' );
+ }
+
+ try {
+ $username = AuthenticationRequest::getUsernameFromRequests( $reqs );
+ } catch ( \UnexpectedValueException $ex ) {
+ $username = null;
+ }
+ if ( $username === null ) {
+ $this->logger->debug( __METHOD__ . ': No username provided' );
+ return AuthenticationResponse::newFail( wfMessage( 'noname' ) );
+ }
+
+ // Permissions check
+ $status = $this->checkAccountCreatePermissions( $creator );
+ if ( !$status->isGood() ) {
+ $this->logger->debug( __METHOD__ . ': {creator} cannot create users: {reason}', [
+ 'user' => $username,
+ 'creator' => $creator->getName(),
+ 'reason' => $status->getWikiText( null, null, 'en' )
+ ] );
+ return AuthenticationResponse::newFail( $status->getMessage() );
+ }
+
+ $status = $this->canCreateAccount( $username, User::READ_LOCKING );
+ if ( !$status->isGood() ) {
+ $this->logger->debug( __METHOD__ . ': {user} cannot be created: {reason}', [
+ 'user' => $username,
+ 'creator' => $creator->getName(),
+ 'reason' => $status->getWikiText( null, null, 'en' )
+ ] );
+ return AuthenticationResponse::newFail( $status->getMessage() );
+ }
+
+ $user = User::newFromName( $username, 'creatable' );
+ foreach ( $reqs as $req ) {
+ $req->username = $username;
+ $req->returnToUrl = $returnToUrl;
+ if ( $req instanceof UserDataAuthenticationRequest ) {
+ $status = $req->populateUser( $user );
+ if ( !$status->isGood() ) {
+ $status = Status::wrap( $status );
+ $session->remove( 'AuthManager::accountCreationState' );
+ $this->logger->debug( __METHOD__ . ': UserData is invalid: {reason}', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ 'reason' => $status->getWikiText( null, null, 'en' ),
+ ] );
+ return AuthenticationResponse::newFail( $status->getMessage() );
+ }
+ }
+ }
+
+ $this->removeAuthenticationSessionData( null );
+
+ $state = [
+ 'username' => $username,
+ 'userid' => 0,
+ 'creatorid' => $creator->getId(),
+ 'creatorname' => $creator->getName(),
+ 'reqs' => $reqs,
+ 'returnToUrl' => $returnToUrl,
+ 'primary' => null,
+ 'primaryResponse' => null,
+ 'secondary' => [],
+ 'continueRequests' => [],
+ 'maybeLink' => [],
+ 'ranPreTests' => false,
+ ];
+
+ // Special case: converting a login to an account creation
+ $req = AuthenticationRequest::getRequestByClass(
+ $reqs, CreateFromLoginAuthenticationRequest::class
+ );
+ if ( $req ) {
+ $state['maybeLink'] = $req->maybeLink;
+
+ if ( $req->createRequest ) {
+ $reqs[] = $req->createRequest;
+ $state['reqs'][] = $req->createRequest;
+ }
+ }
+
+ $session->setSecret( 'AuthManager::accountCreationState', $state );
+ $session->persist();
+
+ return $this->continueAccountCreation( $reqs );
+ }
+
+ /**
+ * Continue an account creation flow
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse
+ */
+ public function continueAccountCreation( array $reqs ) {
+ $session = $this->request->getSession();
+ try {
+ if ( !$this->canCreateAccounts() ) {
+ // Caller should have called canCreateAccounts()
+ $session->remove( 'AuthManager::accountCreationState' );
+ throw new \LogicException( 'Account creation is not possible' );
+ }
+
+ $state = $session->getSecret( 'AuthManager::accountCreationState' );
+ if ( !is_array( $state ) ) {
+ return AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-create-not-in-progress' )
+ );
+ }
+ $state['continueRequests'] = [];
+
+ // Step 0: Prepare and validate the input
+
+ $user = User::newFromName( $state['username'], 'creatable' );
+ if ( !is_object( $user ) ) {
+ $session->remove( 'AuthManager::accountCreationState' );
+ $this->logger->debug( __METHOD__ . ': Invalid username', [
+ 'user' => $state['username'],
+ ] );
+ return AuthenticationResponse::newFail( wfMessage( 'noname' ) );
+ }
+
+ if ( $state['creatorid'] ) {
+ $creator = User::newFromId( $state['creatorid'] );
+ } else {
+ $creator = new User;
+ $creator->setName( $state['creatorname'] );
+ }
+
+ // Avoid account creation races on double submissions
+ $cache = \ObjectCache::getLocalClusterInstance();
+ $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $user->getName() ) ) );
+ if ( !$lock ) {
+ // Don't clear AuthManager::accountCreationState for this code
+ // path because the process that won the race owns it.
+ $this->logger->debug( __METHOD__ . ': Could not acquire account creation lock', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ return AuthenticationResponse::newFail( wfMessage( 'usernameinprogress' ) );
+ }
+
+ // Permissions check
+ $status = $this->checkAccountCreatePermissions( $creator );
+ if ( !$status->isGood() ) {
+ $this->logger->debug( __METHOD__ . ': {creator} cannot create users: {reason}', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ 'reason' => $status->getWikiText( null, null, 'en' )
+ ] );
+ $ret = AuthenticationResponse::newFail( $status->getMessage() );
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $ret ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ return $ret;
+ }
+
+ // Load from master for existence check
+ $user->load( User::READ_LOCKING );
+
+ if ( $state['userid'] === 0 ) {
+ if ( $user->getId() != 0 ) {
+ $this->logger->debug( __METHOD__ . ': User exists locally', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $ret = AuthenticationResponse::newFail( wfMessage( 'userexists' ) );
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $ret ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ return $ret;
+ }
+ } else {
+ if ( $user->getId() == 0 ) {
+ $this->logger->debug( __METHOD__ . ': User does not exist locally when it should', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ 'expected_id' => $state['userid'],
+ ] );
+ throw new \UnexpectedValueException(
+ "User \"{$state['username']}\" should exist now, but doesn't!"
+ );
+ }
+ if ( $user->getId() != $state['userid'] ) {
+ $this->logger->debug( __METHOD__ . ': User ID/name mismatch', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ 'expected_id' => $state['userid'],
+ 'actual_id' => $user->getId(),
+ ] );
+ throw new \UnexpectedValueException(
+ "User \"{$state['username']}\" exists, but " .
+ "ID {$user->getId()} != {$state['userid']}!"
+ );
+ }
+ }
+ foreach ( $state['reqs'] as $req ) {
+ if ( $req instanceof UserDataAuthenticationRequest ) {
+ $status = $req->populateUser( $user );
+ if ( !$status->isGood() ) {
+ // This should never happen...
+ $status = Status::wrap( $status );
+ $this->logger->debug( __METHOD__ . ': UserData is invalid: {reason}', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ 'reason' => $status->getWikiText( null, null, 'en' ),
+ ] );
+ $ret = AuthenticationResponse::newFail( $status->getMessage() );
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $ret ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ return $ret;
+ }
+ }
+ }
+
+ foreach ( $reqs as $req ) {
+ $req->returnToUrl = $state['returnToUrl'];
+ $req->username = $state['username'];
+ }
+
+ // Run pre-creation tests, if we haven't already
+ if ( !$state['ranPreTests'] ) {
+ $providers = $this->getPreAuthenticationProviders() +
+ $this->getPrimaryAuthenticationProviders() +
+ $this->getSecondaryAuthenticationProviders();
+ foreach ( $providers as $id => $provider ) {
+ $status = $provider->testForAccountCreation( $user, $creator, $reqs );
+ if ( !$status->isGood() ) {
+ $this->logger->debug( __METHOD__ . ": Fail in pre-authentication by $id", [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $ret = AuthenticationResponse::newFail(
+ Status::wrap( $status )->getMessage()
+ );
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $ret ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ return $ret;
+ }
+ }
+
+ $state['ranPreTests'] = true;
+ }
+
+ // Step 1: Choose a primary authentication provider and call it until it succeeds.
+
+ if ( $state['primary'] === null ) {
+ // We haven't picked a PrimaryAuthenticationProvider yet
+ foreach ( $this->getPrimaryAuthenticationProviders() as $id => $provider ) {
+ if ( $provider->accountCreationType() === PrimaryAuthenticationProvider::TYPE_NONE ) {
+ continue;
+ }
+ $res = $provider->beginPrimaryAccountCreation( $user, $creator, $reqs );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS;
+ $this->logger->debug( __METHOD__ . ": Primary creation passed by $id", [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $state['primary'] = $id;
+ $state['primaryResponse'] = $res;
+ break 2;
+ case AuthenticationResponse::FAIL;
+ $this->logger->debug( __METHOD__ . ": Primary creation failed by $id", [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $res ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ return $res;
+ case AuthenticationResponse::ABSTAIN;
+ // Continue loop
+ break;
+ case AuthenticationResponse::REDIRECT;
+ case AuthenticationResponse::UI;
+ $this->logger->debug( __METHOD__ . ": Primary creation $res->status by $id", [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $this->fillRequests( $res->neededRequests, self::ACTION_CREATE, null );
+ $state['primary'] = $id;
+ $state['continueRequests'] = $res->neededRequests;
+ $session->setSecret( 'AuthManager::accountCreationState', $state );
+ return $res;
+
+ // @codeCoverageIgnoreStart
+ default:
+ throw new \DomainException(
+ get_class( $provider ) . "::beginPrimaryAccountCreation() returned $res->status"
+ );
+ // @codeCoverageIgnoreEnd
+ }
+ }
+ if ( $state['primary'] === null ) {
+ $this->logger->debug( __METHOD__ . ': Primary creation failed because no provider accepted', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $ret = AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-create-no-primary' )
+ );
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $ret ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ return $ret;
+ }
+ } elseif ( $state['primaryResponse'] === null ) {
+ $provider = $this->getAuthenticationProvider( $state['primary'] );
+ if ( !$provider instanceof PrimaryAuthenticationProvider ) {
+ // Configuration changed? Force them to start over.
+ // @codeCoverageIgnoreStart
+ $ret = AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-create-not-in-progress' )
+ );
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $ret ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ return $ret;
+ // @codeCoverageIgnoreEnd
+ }
+ $id = $provider->getUniqueId();
+ $res = $provider->continuePrimaryAccountCreation( $user, $creator, $reqs );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS;
+ $this->logger->debug( __METHOD__ . ": Primary creation passed by $id", [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $state['primaryResponse'] = $res;
+ break;
+ case AuthenticationResponse::FAIL;
+ $this->logger->debug( __METHOD__ . ": Primary creation failed by $id", [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $res ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ return $res;
+ case AuthenticationResponse::REDIRECT;
+ case AuthenticationResponse::UI;
+ $this->logger->debug( __METHOD__ . ": Primary creation $res->status by $id", [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $this->fillRequests( $res->neededRequests, self::ACTION_CREATE, null );
+ $state['continueRequests'] = $res->neededRequests;
+ $session->setSecret( 'AuthManager::accountCreationState', $state );
+ return $res;
+ default:
+ throw new \DomainException(
+ get_class( $provider ) . "::continuePrimaryAccountCreation() returned $res->status"
+ );
+ }
+ }
+
+ // Step 2: Primary authentication succeeded, create the User object
+ // and add the user locally.
+
+ if ( $state['userid'] === 0 ) {
+ $this->logger->info( 'Creating user {user} during account creation', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $status = $user->addToDatabase();
+ if ( !$status->isOk() ) {
+ // @codeCoverageIgnoreStart
+ $ret = AuthenticationResponse::newFail( $status->getMessage() );
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $ret ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ return $ret;
+ // @codeCoverageIgnoreEnd
+ }
+ $this->setDefaultUserOptions( $user, $creator->isAnon() );
+ \Hooks::run( 'LocalUserCreated', [ $user, false ] );
+ $user->saveSettings();
+ $state['userid'] = $user->getId();
+
+ // Update user count
+ \DeferredUpdates::addUpdate( new \SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
+
+ // Watch user's userpage and talk page
+ $user->addWatch( $user->getUserPage(), User::IGNORE_USER_RIGHTS );
+
+ // Inform the provider
+ $logSubtype = $provider->finishAccountCreation( $user, $creator, $state['primaryResponse'] );
+
+ // Log the creation
+ if ( $this->config->get( 'NewUserLog' ) ) {
+ $isAnon = $creator->isAnon();
+ $logEntry = new \ManualLogEntry(
+ 'newusers',
+ $logSubtype ?: ( $isAnon ? 'create' : 'create2' )
+ );
+ $logEntry->setPerformer( $isAnon ? $user : $creator );
+ $logEntry->setTarget( $user->getUserPage() );
+ $req = AuthenticationRequest::getRequestByClass(
+ $state['reqs'], CreationReasonAuthenticationRequest::class
+ );
+ $logEntry->setComment( $req ? $req->reason : '' );
+ $logEntry->setParameters( [
+ '4::userid' => $user->getId(),
+ ] );
+ $logid = $logEntry->insert();
+ $logEntry->publish( $logid );
+ }
+ }
+
+ // Step 3: Iterate over all the secondary authentication providers.
+
+ $beginReqs = $state['reqs'];
+
+ foreach ( $this->getSecondaryAuthenticationProviders() as $id => $provider ) {
+ if ( !isset( $state['secondary'][$id] ) ) {
+ // This provider isn't started yet, so we pass it the set
+ // of reqs from beginAuthentication instead of whatever
+ // might have been used by a previous provider in line.
+ $func = 'beginSecondaryAccountCreation';
+ $res = $provider->beginSecondaryAccountCreation( $user, $creator, $beginReqs );
+ } elseif ( !$state['secondary'][$id] ) {
+ $func = 'continueSecondaryAccountCreation';
+ $res = $provider->continueSecondaryAccountCreation( $user, $creator, $reqs );
+ } else {
+ continue;
+ }
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS;
+ $this->logger->debug( __METHOD__ . ": Secondary creation passed by $id", [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ // fall through
+ case AuthenticationResponse::ABSTAIN;
+ $state['secondary'][$id] = true;
+ break;
+ case AuthenticationResponse::REDIRECT;
+ case AuthenticationResponse::UI;
+ $this->logger->debug( __METHOD__ . ": Secondary creation $res->status by $id", [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+ $this->fillRequests( $res->neededRequests, self::ACTION_CREATE, null );
+ $state['secondary'][$id] = false;
+ $state['continueRequests'] = $res->neededRequests;
+ $session->setSecret( 'AuthManager::accountCreationState', $state );
+ return $res;
+ case AuthenticationResponse::FAIL;
+ throw new \DomainException(
+ get_class( $provider ) . "::{$func}() returned $res->status." .
+ ' Secondary providers are not allowed to fail account creation, that' .
+ ' should have been done via testForAccountCreation().'
+ );
+ // @codeCoverageIgnoreStart
+ default:
+ throw new \DomainException(
+ get_class( $provider ) . "::{$func}() returned $res->status"
+ );
+ // @codeCoverageIgnoreEnd
+ }
+ }
+
+ $id = $user->getId();
+ $name = $user->getName();
+ $req = new CreatedAccountAuthenticationRequest( $id, $name );
+ $ret = AuthenticationResponse::newPass( $name );
+ $ret->loginRequest = $req;
+ $this->createdAccountAuthenticationRequests[] = $req;
+
+ $this->logger->info( __METHOD__ . ': Account creation succeeded for {user}', [
+ 'user' => $user->getName(),
+ 'creator' => $creator->getName(),
+ ] );
+
+ $this->callMethodOnProviders( 7, 'postAccountCreation', [ $user, $creator, $ret ] );
+ $session->remove( 'AuthManager::accountCreationState' );
+ $this->removeAuthenticationSessionData( null );
+ return $ret;
+ } catch ( \Exception $ex ) {
+ $session->remove( 'AuthManager::accountCreationState' );
+ throw $ex;
+ }
+ }
+
+ /**
+ * Auto-create an account, and log into that account
+ * @param User $user User to auto-create
+ * @param string $source What caused the auto-creation? This must be the ID
+ * of a PrimaryAuthenticationProvider or the constant self::AUTOCREATE_SOURCE_SESSION.
+ * @param bool $login Whether to also log the user in
+ * @return Status Good if user was created, Ok if user already existed, otherwise Fatal
+ */
+ public function autoCreateUser( User $user, $source, $login = true ) {
+ if ( $source !== self::AUTOCREATE_SOURCE_SESSION &&
+ !$this->getAuthenticationProvider( $source ) instanceof PrimaryAuthenticationProvider
+ ) {
+ throw new \InvalidArgumentException( "Unknown auto-creation source: $source" );
+ }
+
+ $username = $user->getName();
+
+ // Try the local user from the slave DB
+ $localId = User::idFromName( $username );
+ $flags = User::READ_NORMAL;
+
+ // Fetch the user ID from the master, so that we don't try to create the user
+ // when they already exist, due to replication lag
+ // @codeCoverageIgnoreStart
+ if ( !$localId && wfGetLB()->getReaderIndex() != 0 ) {
+ $localId = User::idFromName( $username, User::READ_LATEST );
+ $flags = User::READ_LATEST;
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ( $localId ) {
+ $this->logger->debug( __METHOD__ . ': {username} already exists locally', [
+ 'username' => $username,
+ ] );
+ $user->setId( $localId );
+ $user->loadFromId( $flags );
+ if ( $login ) {
+ $this->setSessionDataForUser( $user );
+ }
+ $status = Status::newGood();
+ $status->warning( 'userexists' );
+ return $status;
+ }
+
+ // Wiki is read-only?
+ if ( wfReadOnly() ) {
+ $this->logger->debug( __METHOD__ . ': denied by wfReadOnly(): {reason}', [
+ 'username' => $username,
+ 'reason' => wfReadOnlyReason(),
+ ] );
+ $user->setId( 0 );
+ $user->loadFromId();
+ return Status::newFatal( 'readonlytext', wfReadOnlyReason() );
+ }
+
+ // Check the session, if we tried to create this user already there's
+ // no point in retrying.
+ $session = $this->request->getSession();
+ if ( $session->get( 'AuthManager::AutoCreateBlacklist' ) ) {
+ $this->logger->debug( __METHOD__ . ': blacklisted in session {sessionid}', [
+ 'username' => $username,
+ 'sessionid' => $session->getId(),
+ ] );
+ $user->setId( 0 );
+ $user->loadFromId();
+ $reason = $session->get( 'AuthManager::AutoCreateBlacklist' );
+ if ( $reason instanceof StatusValue ) {
+ return Status::wrap( $reason );
+ } else {
+ return Status::newFatal( $reason );
+ }
+ }
+
+ // Is the username creatable?
+ if ( !User::isCreatableName( $username ) ) {
+ $this->logger->debug( __METHOD__ . ': name "{username}" is not creatable', [
+ 'username' => $username,
+ ] );
+ $session->set( 'AuthManager::AutoCreateBlacklist', 'noname', 600 );
+ $user->setId( 0 );
+ $user->loadFromId();
+ return Status::newFatal( 'noname' );
+ }
+
+ // Is the IP user able to create accounts?
+ $anon = new User;
+ if ( !$anon->isAllowedAny( 'createaccount', 'autocreateaccount' ) ) {
+ $this->logger->debug( __METHOD__ . ': IP lacks the ability to create or autocreate accounts', [
+ 'username' => $username,
+ 'ip' => $anon->getName(),
+ ] );
+ $session->set( 'AuthManager::AutoCreateBlacklist', 'authmanager-autocreate-noperm', 600 );
+ $session->persist();
+ $user->setId( 0 );
+ $user->loadFromId();
+ return Status::newFatal( 'authmanager-autocreate-noperm' );
+ }
+
+ // Avoid account creation races on double submissions
+ $cache = \ObjectCache::getLocalClusterInstance();
+ $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $username ) ) );
+ if ( !$lock ) {
+ $this->logger->debug( __METHOD__ . ': Could not acquire account creation lock', [
+ 'user' => $username,
+ ] );
+ $user->setId( 0 );
+ $user->loadFromId();
+ return Status::newFatal( 'usernameinprogress' );
+ }
+
+ // Denied by providers?
+ $providers = $this->getPreAuthenticationProviders() +
+ $this->getPrimaryAuthenticationProviders() +
+ $this->getSecondaryAuthenticationProviders();
+ foreach ( $providers as $provider ) {
+ $status = $provider->testUserForCreation( $user, $source );
+ if ( !$status->isGood() ) {
+ $ret = Status::wrap( $status );
+ $this->logger->debug( __METHOD__ . ': Provider denied creation of {username}: {reason}', [
+ 'username' => $username,
+ 'reason' => $ret->getWikiText( null, null, 'en' ),
+ ] );
+ $session->set( 'AuthManager::AutoCreateBlacklist', $status, 600 );
+ $user->setId( 0 );
+ $user->loadFromId();
+ return $ret;
+ }
+ }
+
+ // Ignore warnings about master connections/writes...hard to avoid here
+ \Profiler::instance()->getTransactionProfiler()->resetExpectations();
+
+ $backoffKey = wfMemcKey( 'AuthManager', 'autocreate-failed', md5( $username ) );
+ if ( $cache->get( $backoffKey ) ) {
+ $this->logger->debug( __METHOD__ . ': {username} denied by prior creation attempt failures', [
+ 'username' => $username,
+ ] );
+ $user->setId( 0 );
+ $user->loadFromId();
+ return Status::newFatal( 'authmanager-autocreate-exception' );
+ }
+
+ // Checks passed, create the user...
+ $from = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : 'CLI';
+ $this->logger->info( __METHOD__ . ': creating new user ({username}) - from: {from}', [
+ 'username' => $username,
+ 'from' => $from,
+ ] );
+
+ try {
+ $status = $user->addToDatabase();
+ if ( !$status->isOk() ) {
+ // double-check for a race condition (T70012)
+ $localId = User::idFromName( $username, User::READ_LATEST );
+ if ( $localId ) {
+ $this->logger->info( __METHOD__ . ': {username} already exists locally (race)', [
+ 'username' => $username,
+ ] );
+ $user->setId( $localId );
+ $user->loadFromId( User::READ_LATEST );
+ if ( $login ) {
+ $this->setSessionDataForUser( $user );
+ }
+ $status = Status::newGood();
+ $status->warning( 'userexists' );
+ } else {
+ $this->logger->error( __METHOD__ . ': {username} failed with message {message}', [
+ 'username' => $username,
+ 'message' => $status->getWikiText( null, null, 'en' )
+ ] );
+ $user->setId( 0 );
+ $user->loadFromId();
+ }
+ return $status;
+ }
+ } catch ( \Exception $ex ) {
+ $this->logger->error( __METHOD__ . ': {username} failed with exception {exception}', [
+ 'username' => $username,
+ 'exception' => $ex,
+ ] );
+ // Do not keep throwing errors for a while
+ $cache->set( $backoffKey, 1, 600 );
+ // Bubble up error; which should normally trigger DB rollbacks
+ throw $ex;
+ }
+
+ $this->setDefaultUserOptions( $user, true );
+
+ // Inform the providers
+ $this->callMethodOnProviders( 6, 'autoCreatedAccount', [ $user, $source ] );
+
+ \Hooks::run( 'AuthPluginAutoCreate', [ $user ], '1.27' );
+ \Hooks::run( 'LocalUserCreated', [ $user, true ] );
+ $user->saveSettings();
+
+ // Update user count
+ \DeferredUpdates::addUpdate( new \SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
+
+ // Watch user's userpage and talk page
+ $user->addWatch( $user->getUserPage(), User::IGNORE_USER_RIGHTS );
+
+ // Log the creation
+ if ( $this->config->get( 'NewUserLog' ) ) {
+ $logEntry = new \ManualLogEntry( 'newusers', 'autocreate' );
+ $logEntry->setPerformer( $user );
+ $logEntry->setTarget( $user->getUserPage() );
+ $logEntry->setComment( '' );
+ $logEntry->setParameters( [
+ '4::userid' => $user->getId(),
+ ] );
+ $logid = $logEntry->insert();
+ }
+
+ if ( $login ) {
+ $this->setSessionDataForUser( $user );
+ }
+
+ return Status::newGood();
+ }
+
+ /**@}*/
+
+ /**
+ * @name Account linking
+ * @{
+ */
+
+ /**
+ * Determine whether accounts can be linked
+ * @return bool
+ */
+ public function canLinkAccounts() {
+ foreach ( $this->getPrimaryAuthenticationProviders() as $provider ) {
+ if ( $provider->accountCreationType() === PrimaryAuthenticationProvider::TYPE_LINK ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Start an account linking flow
+ *
+ * @param User $user User being linked
+ * @param AuthenticationRequest[] $reqs
+ * @param string $returnToUrl Url that REDIRECT responses should eventually
+ * return to.
+ * @return AuthenticationResponse
+ */
+ public function beginAccountLink( User $user, array $reqs, $returnToUrl ) {
+ $session = $this->request->getSession();
+ $session->remove( 'AuthManager::accountLinkState' );
+
+ if ( !$this->canLinkAccounts() ) {
+ // Caller should have called canLinkAccounts()
+ throw new \LogicException( 'Account linking is not possible' );
+ }
+
+ if ( $user->getId() === 0 ) {
+ if ( !User::isUsableName( $user->getName() ) ) {
+ $msg = wfMessage( 'noname' );
+ } else {
+ $msg = wfMessage( 'authmanager-userdoesnotexist', $user->getName() );
+ }
+ return AuthenticationResponse::newFail( $msg );
+ }
+ foreach ( $reqs as $req ) {
+ $req->username = $user->getName();
+ $req->returnToUrl = $returnToUrl;
+ }
+
+ $this->removeAuthenticationSessionData( null );
+
+ $providers = $this->getPreAuthenticationProviders();
+ foreach ( $providers as $id => $provider ) {
+ $status = $provider->testForAccountLink( $user );
+ if ( !$status->isGood() ) {
+ $this->logger->debug( __METHOD__ . ": Account linking pre-check failed by $id", [
+ 'user' => $user->getName(),
+ ] );
+ $ret = AuthenticationResponse::newFail(
+ Status::wrap( $status )->getMessage()
+ );
+ $this->callMethodOnProviders( 3, 'postAccountLink', [ $user, $ret ] );
+ return $ret;
+ }
+ }
+
+ $state = [
+ 'username' => $user->getName(),
+ 'userid' => $user->getId(),
+ 'returnToUrl' => $returnToUrl,
+ 'primary' => null,
+ 'continueRequests' => [],
+ ];
+
+ $providers = $this->getPrimaryAuthenticationProviders();
+ foreach ( $providers as $id => $provider ) {
+ if ( $provider->accountCreationType() !== PrimaryAuthenticationProvider::TYPE_LINK ) {
+ continue;
+ }
+
+ $res = $provider->beginPrimaryAccountLink( $user, $reqs );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS;
+ $this->logger->info( "Account linked to {user} by $id", [
+ 'user' => $user->getName(),
+ ] );
+ $this->callMethodOnProviders( 3, 'postAccountLink', [ $user, $res ] );
+ return $res;
+
+ case AuthenticationResponse::FAIL;
+ $this->logger->debug( __METHOD__ . ": Account linking failed by $id", [
+ 'user' => $user->getName(),
+ ] );
+ $this->callMethodOnProviders( 3, 'postAccountLink', [ $user, $res ] );
+ return $res;
+
+ case AuthenticationResponse::ABSTAIN;
+ // Continue loop
+ break;
+
+ case AuthenticationResponse::REDIRECT;
+ case AuthenticationResponse::UI;
+ $this->logger->debug( __METHOD__ . ": Account linking $res->status by $id", [
+ 'user' => $user->getName(),
+ ] );
+ $this->fillRequests( $res->neededRequests, self::ACTION_LINK, $user->getName() );
+ $state['primary'] = $id;
+ $state['continueRequests'] = $res->neededRequests;
+ $session->setSecret( 'AuthManager::accountLinkState', $state );
+ $session->persist();
+ return $res;
+
+ // @codeCoverageIgnoreStart
+ default:
+ throw new \DomainException(
+ get_class( $provider ) . "::beginPrimaryAccountLink() returned $res->status"
+ );
+ // @codeCoverageIgnoreEnd
+ }
+ }
+
+ $this->logger->debug( __METHOD__ . ': Account linking failed because no provider accepted', [
+ 'user' => $user->getName(),
+ ] );
+ $ret = AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-link-no-primary' )
+ );
+ $this->callMethodOnProviders( 3, 'postAccountLink', [ $user, $ret ] );
+ return $ret;
+ }
+
+ /**
+ * Continue an account linking flow
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse
+ */
+ public function continueAccountLink( array $reqs ) {
+ $session = $this->request->getSession();
+ try {
+ if ( !$this->canLinkAccounts() ) {
+ // Caller should have called canLinkAccounts()
+ $session->remove( 'AuthManager::accountLinkState' );
+ throw new \LogicException( 'Account linking is not possible' );
+ }
+
+ $state = $session->getSecret( 'AuthManager::accountLinkState' );
+ if ( !is_array( $state ) ) {
+ return AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-link-not-in-progress' )
+ );
+ }
+ $state['continueRequests'] = [];
+
+ // Step 0: Prepare and validate the input
+
+ $user = User::newFromName( $state['username'], 'usable' );
+ if ( !is_object( $user ) ) {
+ $session->remove( 'AuthManager::accountLinkState' );
+ return AuthenticationResponse::newFail( wfMessage( 'noname' ) );
+ }
+ if ( $user->getId() != $state['userid'] ) {
+ throw new \UnexpectedValueException(
+ "User \"{$state['username']}\" is valid, but " .
+ "ID {$user->getId()} != {$state['userid']}!"
+ );
+ }
+
+ foreach ( $reqs as $req ) {
+ $req->username = $state['username'];
+ $req->returnToUrl = $state['returnToUrl'];
+ }
+
+ // Step 1: Call the primary again until it succeeds
+
+ $provider = $this->getAuthenticationProvider( $state['primary'] );
+ if ( !$provider instanceof PrimaryAuthenticationProvider ) {
+ // Configuration changed? Force them to start over.
+ // @codeCoverageIgnoreStart
+ $ret = AuthenticationResponse::newFail(
+ wfMessage( 'authmanager-link-not-in-progress' )
+ );
+ $this->callMethodOnProviders( 3, 'postAccountLink', [ $user, $ret ] );
+ $session->remove( 'AuthManager::accountLinkState' );
+ return $ret;
+ // @codeCoverageIgnoreEnd
+ }
+ $id = $provider->getUniqueId();
+ $res = $provider->continuePrimaryAccountLink( $user, $reqs );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS;
+ $this->logger->info( "Account linked to {user} by $id", [
+ 'user' => $user->getName(),
+ ] );
+ $this->callMethodOnProviders( 3, 'postAccountLink', [ $user, $res ] );
+ $session->remove( 'AuthManager::accountLinkState' );
+ return $res;
+ case AuthenticationResponse::FAIL;
+ $this->logger->debug( __METHOD__ . ": Account linking failed by $id", [
+ 'user' => $user->getName(),
+ ] );
+ $this->callMethodOnProviders( 3, 'postAccountLink', [ $user, $res ] );
+ $session->remove( 'AuthManager::accountLinkState' );
+ return $res;
+ case AuthenticationResponse::REDIRECT;
+ case AuthenticationResponse::UI;
+ $this->logger->debug( __METHOD__ . ": Account linking $res->status by $id", [
+ 'user' => $user->getName(),
+ ] );
+ $this->fillRequests( $res->neededRequests, self::ACTION_LINK, $user->getName() );
+ $state['continueRequests'] = $res->neededRequests;
+ $session->setSecret( 'AuthManager::accountLinkState', $state );
+ return $res;
+ default:
+ throw new \DomainException(
+ get_class( $provider ) . "::continuePrimaryAccountLink() returned $res->status"
+ );
+ }
+ } catch ( \Exception $ex ) {
+ $session->remove( 'AuthManager::accountLinkState' );
+ throw $ex;
+ }
+ }
+
+ /**@}*/
+
+ /**
+ * @name Information methods
+ * @{
+ */
+
+ /**
+ * Return the applicable list of AuthenticationRequests
+ *
+ * Possible values for $action:
+ * - ACTION_LOGIN: Valid for passing to beginAuthentication
+ * - ACTION_LOGIN_CONTINUE: Valid for passing to continueAuthentication in the current state
+ * - ACTION_CREATE: Valid for passing to beginAccountCreation
+ * - ACTION_CREATE_CONTINUE: Valid for passing to continueAccountCreation in the current state
+ * - ACTION_LINK: Valid for passing to beginAccountLink
+ * - ACTION_LINK_CONTINUE: Valid for passing to continueAccountLink in the current state
+ * - ACTION_CHANGE: Valid for passing to changeAuthenticationData to change credentials
+ * - ACTION_REMOVE: Valid for passing to changeAuthenticationData to remove credentials.
+ * - ACTION_UNLINK: Same as ACTION_REMOVE, but limited to linked accounts.
+ *
+ * @param string $action One of the AuthManager::ACTION_* constants
+ * @param User|null $user User being acted on, instead of the current user.
+ * @return AuthenticationRequest[]
+ */
+ public function getAuthenticationRequests( $action, User $user = null ) {
+ $options = [];
+ $providerAction = $action;
+
+ // Figure out which providers to query
+ switch ( $action ) {
+ case self::ACTION_LOGIN:
+ case self::ACTION_CREATE:
+ $providers = $this->getPreAuthenticationProviders() +
+ $this->getPrimaryAuthenticationProviders() +
+ $this->getSecondaryAuthenticationProviders();
+ break;
+
+ case self::ACTION_LOGIN_CONTINUE:
+ $state = $this->request->getSession()->getSecret( 'AuthManager::authnState' );
+ return is_array( $state ) ? $state['continueRequests'] : [];
+
+ case self::ACTION_CREATE_CONTINUE:
+ $state = $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' );
+ return is_array( $state ) ? $state['continueRequests'] : [];
+
+ case self::ACTION_LINK:
+ $providers = array_filter( $this->getPrimaryAuthenticationProviders(), function ( $p ) {
+ return $p->accountCreationType() === PrimaryAuthenticationProvider::TYPE_LINK;
+ } );
+ break;
+
+ case self::ACTION_UNLINK:
+ $providers = array_filter( $this->getPrimaryAuthenticationProviders(), function ( $p ) {
+ return $p->accountCreationType() === PrimaryAuthenticationProvider::TYPE_LINK;
+ } );
+
+ // To providers, unlink and remove are identical.
+ $providerAction = self::ACTION_REMOVE;
+ break;
+
+ case self::ACTION_LINK_CONTINUE:
+ $state = $this->request->getSession()->getSecret( 'AuthManager::accountLinkState' );
+ return is_array( $state ) ? $state['continueRequests'] : [];
+
+ case self::ACTION_CHANGE:
+ case self::ACTION_REMOVE:
+ $providers = $this->getPrimaryAuthenticationProviders() +
+ $this->getSecondaryAuthenticationProviders();
+ break;
+
+ // @codeCoverageIgnoreStart
+ default:
+ throw new \DomainException( __METHOD__ . ": Invalid action \"$action\"" );
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $this->getAuthenticationRequestsInternal( $providerAction, $options, $providers, $user );
+ }
+
+ /**
+ * Internal request lookup for self::getAuthenticationRequests
+ *
+ * @param string $providerAction Action to pass to providers
+ * @param array $options Options to pass to providers
+ * @param AuthenticationProvider[] $providers
+ * @param User|null $user
+ * @return AuthenticationRequest[]
+ */
+ private function getAuthenticationRequestsInternal(
+ $providerAction, array $options, array $providers, User $user = null
+ ) {
+ $user = $user ?: \RequestContext::getMain()->getUser();
+ $options['username'] = $user->isAnon() ? null : $user->getName();
+
+ // Query them and merge results
+ $reqs = [];
+ $allPrimaryRequired = null;
+ foreach ( $providers as $provider ) {
+ $isPrimary = $provider instanceof PrimaryAuthenticationProvider;
+ $thisRequired = [];
+ foreach ( $provider->getAuthenticationRequests( $providerAction, $options ) as $req ) {
+ $id = $req->getUniqueId();
+
+ // If it's from a Primary, mark it as "primary-required" but
+ // track it for later.
+ if ( $isPrimary ) {
+ if ( $req->required ) {
+ $thisRequired[$id] = true;
+ $req->required = AuthenticationRequest::PRIMARY_REQUIRED;
+ }
+ }
+
+ if ( !isset( $reqs[$id] ) || $req->required === AuthenticationRequest::REQUIRED ) {
+ $reqs[$id] = $req;
+ }
+ }
+
+ // Track which requests are required by all primaries
+ if ( $isPrimary ) {
+ $allPrimaryRequired = $allPrimaryRequired === null
+ ? $thisRequired
+ : array_intersect_key( $allPrimaryRequired, $thisRequired );
+ }
+ }
+ // Any requests that were required by all primaries are required.
+ foreach ( (array)$allPrimaryRequired as $id => $dummy ) {
+ $reqs[$id]->required = AuthenticationRequest::REQUIRED;
+ }
+
+ // AuthManager has its own req for some actions
+ switch ( $providerAction ) {
+ case self::ACTION_LOGIN:
+ $reqs[] = new RememberMeAuthenticationRequest;
+ break;
+
+ case self::ACTION_CREATE:
+ $reqs[] = new UsernameAuthenticationRequest;
+ $reqs[] = new UserDataAuthenticationRequest;
+ if ( $options['username'] !== null ) {
+ $reqs[] = new CreationReasonAuthenticationRequest;
+ $options['username'] = null; // Don't fill in the username below
+ }
+ break;
+ }
+
+ // Fill in reqs data
+ $this->fillRequests( $reqs, $providerAction, $options['username'], true );
+
+ // For self::ACTION_CHANGE, filter out any that something else *doesn't* allow changing
+ if ( $providerAction === self::ACTION_CHANGE || $providerAction === self::ACTION_REMOVE ) {
+ $reqs = array_filter( $reqs, function ( $req ) {
+ return $this->allowsAuthenticationDataChange( $req, false )->isGood();
+ } );
+ }
+
+ return array_values( $reqs );
+ }
+
+ /**
+ * Set values in an array of requests
+ * @param AuthenticationRequest[] &$reqs
+ * @param string $action
+ * @param string|null $username
+ * @param boolean $forceAction
+ */
+ private function fillRequests( array &$reqs, $action, $username, $forceAction = false ) {
+ foreach ( $reqs as $req ) {
+ if ( !$req->action || $forceAction ) {
+ $req->action = $action;
+ }
+ if ( $req->username === null ) {
+ $req->username = $username;
+ }
+ }
+ }
+
+ /**
+ * Determine whether a username exists
+ * @param string $username
+ * @param int $flags Bitfield of User:READ_* constants
+ * @return bool
+ */
+ public function userExists( $username, $flags = User::READ_NORMAL ) {
+ foreach ( $this->getPrimaryAuthenticationProviders() as $provider ) {
+ if ( $provider->testUserExists( $username, $flags ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine whether a user property should be allowed to be changed.
+ *
+ * Supported properties are:
+ * - emailaddress
+ * - realname
+ * - nickname
+ *
+ * @param string $property
+ * @return bool
+ */
+ public function allowsPropertyChange( $property ) {
+ $providers = $this->getPrimaryAuthenticationProviders() +
+ $this->getSecondaryAuthenticationProviders();
+ foreach ( $providers as $provider ) {
+ if ( !$provider->providerAllowsPropertyChange( $property ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Get a provider by ID
+ * @note This is public so extensions can check whether their own provider
+ * is installed and so they can read its configuration if necessary.
+ * Other uses are not recommended.
+ * @param string $id
+ * @return AuthenticationProvider|null
+ */
+ public function getAuthenticationProvider( $id ) {
+ // Fast version
+ if ( isset( $this->allAuthenticationProviders[$id] ) ) {
+ return $this->allAuthenticationProviders[$id];
+ }
+
+ // Slow version: instantiate each kind and check
+ $providers = $this->getPrimaryAuthenticationProviders();
+ if ( isset( $providers[$id] ) ) {
+ return $providers[$id];
+ }
+ $providers = $this->getSecondaryAuthenticationProviders();
+ if ( isset( $providers[$id] ) ) {
+ return $providers[$id];
+ }
+ $providers = $this->getPreAuthenticationProviders();
+ if ( isset( $providers[$id] ) ) {
+ return $providers[$id];
+ }
+
+ return null;
+ }
+
+ /**@}*/
+
+ /**
+ * @name Internal methods
+ * @{
+ */
+
+ /**
+ * Store authentication in the current session
+ * @protected For use by AuthenticationProviders
+ * @param string $key
+ * @param mixed $data Must be serializable
+ */
+ public function setAuthenticationSessionData( $key, $data ) {
+ $session = $this->request->getSession();
+ $arr = $session->getSecret( 'authData' );
+ if ( !is_array( $arr ) ) {
+ $arr = [];
+ }
+ $arr[$key] = $data;
+ $session->setSecret( 'authData', $arr );
+ }
+
+ /**
+ * Fetch authentication data from the current session
+ * @protected For use by AuthenticationProviders
+ * @param string $key
+ * @param mixed $default
+ * @return mixed
+ */
+ public function getAuthenticationSessionData( $key, $default = null ) {
+ $arr = $this->request->getSession()->getSecret( 'authData' );
+ if ( is_array( $arr ) && array_key_exists( $key, $arr ) ) {
+ return $arr[$key];
+ } else {
+ return $default;
+ }
+ }
+
+ /**
+ * Remove authentication data
+ * @protected For use by AuthenticationProviders
+ * @param string|null $key If null, all data is removed
+ */
+ public function removeAuthenticationSessionData( $key ) {
+ $session = $this->request->getSession();
+ if ( $key === null ) {
+ $session->remove( 'authData' );
+ } else {
+ $arr = $session->getSecret( 'authData' );
+ if ( is_array( $arr ) && array_key_exists( $key, $arr ) ) {
+ unset( $arr[$key] );
+ $session->setSecret( 'authData', $arr );
+ }
+ }
+ }
+
+ /**
+ * Create an array of AuthenticationProviders from an array of ObjectFactory specs
+ * @param string $class
+ * @param array[] $specs
+ * @return AuthenticationProvider[]
+ */
+ protected function providerArrayFromSpecs( $class, array $specs ) {
+ $i = 0;
+ foreach ( $specs as &$spec ) {
+ $spec = [ 'sort2' => $i++ ] + $spec + [ 'sort' => 0 ];
+ }
+ unset( $spec );
+ usort( $specs, function ( $a, $b ) {
+ return ( (int)$a['sort'] ) - ( (int)$b['sort'] )
+ ?: $a['sort2'] - $b['sort2'];
+ } );
+
+ $ret = [];
+ foreach ( $specs as $spec ) {
+ $provider = \ObjectFactory::getObjectFromSpec( $spec );
+ if ( !$provider instanceof $class ) {
+ throw new \RuntimeException(
+ "Expected instance of $class, got " . get_class( $provider )
+ );
+ }
+ $provider->setLogger( $this->logger );
+ $provider->setManager( $this );
+ $provider->setConfig( $this->config );
+ $id = $provider->getUniqueId();
+ if ( isset( $this->allAuthenticationProviders[$id] ) ) {
+ throw new \RuntimeException(
+ "Duplicate specifications for id $id (classes " .
+ get_class( $provider ) . ' and ' .
+ get_class( $this->allAuthenticationProviders[$id] ) . ')'
+ );
+ }
+ $this->allAuthenticationProviders[$id] = $provider;
+ $ret[$id] = $provider;
+ }
+ return $ret;
+ }
+
+ /**
+ * Get the configuration
+ * @return array
+ */
+ private function getConfiguration() {
+ return $this->config->get( 'AuthManagerConfig' ) ?: $this->config->get( 'AuthManagerAutoConfig' );
+ }
+
+ /**
+ * Get the list of PreAuthenticationProviders
+ * @return PreAuthenticationProvider[]
+ */
+ protected function getPreAuthenticationProviders() {
+ if ( $this->preAuthenticationProviders === null ) {
+ $conf = $this->getConfiguration();
+ $this->preAuthenticationProviders = $this->providerArrayFromSpecs(
+ PreAuthenticationProvider::class, $conf['preauth']
+ );
+ }
+ return $this->preAuthenticationProviders;
+ }
+
+ /**
+ * Get the list of PrimaryAuthenticationProviders
+ * @return PrimaryAuthenticationProvider[]
+ */
+ protected function getPrimaryAuthenticationProviders() {
+ if ( $this->primaryAuthenticationProviders === null ) {
+ $conf = $this->getConfiguration();
+ $this->primaryAuthenticationProviders = $this->providerArrayFromSpecs(
+ PrimaryAuthenticationProvider::class, $conf['primaryauth']
+ );
+ }
+ return $this->primaryAuthenticationProviders;
+ }
+
+ /**
+ * Get the list of SecondaryAuthenticationProviders
+ * @return SecondaryAuthenticationProvider[]
+ */
+ protected function getSecondaryAuthenticationProviders() {
+ if ( $this->secondaryAuthenticationProviders === null ) {
+ $conf = $this->getConfiguration();
+ $this->secondaryAuthenticationProviders = $this->providerArrayFromSpecs(
+ SecondaryAuthenticationProvider::class, $conf['secondaryauth']
+ );
+ }
+ return $this->secondaryAuthenticationProviders;
+ }
+
+ /**
+ * @param User $user
+ * @param bool|null $remember
+ */
+ private function setSessionDataForUser( $user, $remember = null ) {
+ $session = $this->request->getSession();
+ $delay = $session->delaySave();
+
+ $session->resetId();
+ $session->resetAllTokens();
+ if ( $session->canSetUser() ) {
+ $session->setUser( $user );
+ }
+ if ( $remember !== null ) {
+ $session->setRememberUser( $remember );
+ }
+ $session->set( 'AuthManager:lastAuthId', $user->getId() );
+ $session->set( 'AuthManager:lastAuthTimestamp', time() );
+ $session->persist();
+
+ \ScopedCallback::consume( $delay );
+
+ \Hooks::run( 'UserLoggedIn', [ $user ] );
+ }
+
+ /**
+ * @param User $user
+ * @param bool $useContextLang Use 'uselang' to set the user's language
+ */
+ private function setDefaultUserOptions( User $user, $useContextLang ) {
+ global $wgContLang;
+
+ $user->setToken();
+
+ $lang = $useContextLang ? \RequestContext::getMain()->getLanguage() : $wgContLang;
+ $user->setOption( 'language', $lang->getPreferredVariant() );
+
+ if ( $wgContLang->hasVariants() ) {
+ $user->setOption( 'variant', $wgContLang->getPreferredVariant() );
+ }
+ }
+
+ /**
+ * @param int $which Bitmask: 1 = pre, 2 = primary, 4 = secondary
+ * @param string $method
+ * @param array $args
+ */
+ private function callMethodOnProviders( $which, $method, array $args ) {
+ $providers = [];
+ if ( $which & 1 ) {
+ $providers += $this->getPreAuthenticationProviders();
+ }
+ if ( $which & 2 ) {
+ $providers += $this->getPrimaryAuthenticationProviders();
+ }
+ if ( $which & 4 ) {
+ $providers += $this->getSecondaryAuthenticationProviders();
+ }
+ foreach ( $providers as $provider ) {
+ call_user_func_array( [ $provider, $method ], $args );
+ }
+ }
+
+ /**
+ * Reset the internal caching for unit testing
+ */
+ public static function resetCache() {
+ if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+ // @codeCoverageIgnoreStart
+ throw new \MWException( __METHOD__ . ' may only be called from unit tests!' );
+ // @codeCoverageIgnoreEnd
+ }
+
+ self::$instance = null;
+ }
+
+ /**@}*/
+
+}
+
+/**
+ * For really cool vim folding this needs to be at the end:
+ * vim: foldmarker=@{,@} foldmethod=marker
+ */
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Auth;
+
+use User;
+
+/**
+ * Backwards-compatibility wrapper for AuthManager via $wgAuth
+ * @since 1.27
+ * @deprecated since 1.27
+ */
+class AuthManagerAuthPlugin extends \AuthPlugin {
+ /** @var string|null */
+ protected $domain = null;
+
+ /** @var \\Psr\\Log\\LoggerInterface */
+ protected $logger = null;
+
+ public function __construct() {
+ $this->logger = \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' );
+ }
+
+ public function userExists( $name ) {
+ return AuthManager::singleton()->userExists( $name );
+ }
+
+ public function authenticate( $username, $password ) {
+ $data = [
+ 'username' => $username,
+ 'password' => $password,
+ ];
+ if ( $this->domain !== null && $this->domain !== '' ) {
+ $data['domain'] = $this->domain;
+ }
+ $reqs = AuthManager::singleton()->getAuthenticationRequests( AuthManager::ACTION_LOGIN );
+ $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
+
+ $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS:
+ return true;
+ case AuthenticationResponse::FAIL:
+ // Hope it's not a PreAuthenticationProvider that failed...
+ $msg = $res->message instanceof \Message ? $res->message : new \Message( $res->message );
+ $this->logger->info( __METHOD__ . ': Authentication failed: ' . $msg->plain() );
+ return false;
+ default:
+ throw new \BadMethodCallException(
+ 'AuthManager does not support such simplified authentication'
+ );
+ }
+ }
+
+ public function modifyUITemplate( &$template, &$type ) {
+ // AuthManager does not support direct UI screwing-around-with
+ }
+
+ public function setDomain( $domain ) {
+ $this->domain = $domain;
+ }
+
+ public function getDomain() {
+ if ( isset( $this->domain ) ) {
+ return $this->domain;
+ } else {
+ return 'invaliddomain';
+ }
+ }
+
+ public function validDomain( $domain ) {
+ $domainList = $this->domainList();
+ return $domainList ? in_array( $domain, $domainList, true ) : $domain === '';
+ }
+
+ public function updateUser( &$user ) {
+ \Hooks::run( 'UserLoggedIn', [ $user ] );
+ return true;
+ }
+
+ public function autoCreate() {
+ return true;
+ }
+
+ public function allowPropChange( $prop = '' ) {
+ return AuthManager::singleton()->allowsPropertyChange( $prop );
+ }
+
+ public function allowPasswordChange() {
+ $reqs = AuthManager::singleton()->getAuthenticationRequests( AuthManager::ACTION_CHANGE );
+ foreach ( $reqs as $req ) {
+ if ( $req instanceof PasswordAuthenticationRequest ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function allowSetLocalPassword() {
+ // There should be a PrimaryAuthenticationProvider that does this, if necessary
+ return false;
+ }
+
+ public function setPassword( $user, $password ) {
+ $data = [
+ 'username' => $user->getName(),
+ 'password' => $password,
+ ];
+ if ( $this->domain !== null && $this->domain !== '' ) {
+ $data['domain'] = $this->domain;
+ }
+ $reqs = AuthManager::singleton()->getAuthenticationRequests( AuthManager::ACTION_CHANGE );
+ $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
+ foreach ( $reqs as $req ) {
+ $status = AuthManager::singleton()->allowsAuthenticationDataChange( $req );
+ if ( !$status->isOk() ) {
+ $this->logger->info( __METHOD__ . ': Password change rejected: {reason}', [
+ 'username' => $data['username'],
+ 'reason' => $status->getWikiText( null, null, 'en' ),
+ ] );
+ return false;
+ }
+ }
+ foreach ( $reqs as $req ) {
+ AuthManager::singleton()->changeAuthenticationData( $req );
+ }
+ return true;
+ }
+
+ public function updateExternalDB( $user ) {
+ // This fires the necessary hook
+ $user->saveSettings();
+ return true;
+ }
+
+ public function updateExternalDBGroups( $user, $addgroups, $delgroups = [] ) {
+ \Hooks::run( 'UserGroupsChanged', [ $user, $addgroups, $delgroups ] );
+ return true;
+ }
+
+ public function canCreateAccounts() {
+ return AuthManager::singleton()->canCreateAccounts();
+ }
+
+ public function addUser( $user, $password, $email = '', $realname = '' ) {
+ global $wgUser;
+
+ $data = [
+ 'username' => $user->getName(),
+ 'password' => $password,
+ 'retype' => $password,
+ 'email' => $email,
+ 'realname' => $realname,
+ ];
+ if ( $this->domain !== null && $this->domain !== '' ) {
+ $data['domain'] = $this->domain;
+ }
+ $reqs = AuthManager::singleton()->getAuthenticationRequests( AuthManager::ACTION_CREATE );
+ $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
+
+ $res = AuthManager::singleton()->beginAccountCreation( $wgUser, $reqs, 'null:' );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS:
+ return true;
+ case AuthenticationResponse::FAIL:
+ // Hope it's not a PreAuthenticationProvider that failed...
+ $msg = $res->message instanceof \Message ? $res->message : new \Message( $res->message );
+ $this->logger->info( __METHOD__ . ': Authentication failed: ' . $msg->plain() );
+ return false;
+ default:
+ throw new \BadMethodCallException(
+ 'AuthManager does not support such simplified account creation'
+ );
+ }
+ }
+
+ public function strict() {
+ // There should be a PrimaryAuthenticationProvider that does this, if necessary
+ return true;
+ }
+
+ public function strictUserAuth( $username ) {
+ // There should be a PrimaryAuthenticationProvider that does this, if necessary
+ return true;
+ }
+
+ public function initUser( &$user, $autocreate = false ) {
+ \Hooks::run( 'LocalUserCreated', [ $user, $autocreate ] );
+ }
+
+ public function getCanonicalName( $username ) {
+ // AuthManager doesn't support restrictions beyond MediaWiki's
+ return $username;
+ }
+
+ public function getUserInstance( User &$user ) {
+ return new AuthManagerAuthPluginUser( $user );
+ }
+
+ public function domainList() {
+ return [];
+ }
+}
+
+/**
+ * @since 1.27
+ * @deprecated since 1.27
+ */
+class AuthManagerAuthPluginUser extends \AuthPluginUser {
+ /** @var User */
+ private $user;
+
+ function __construct( $user ) {
+ $this->user = $user;
+ }
+
+ public function getId() {
+ return $this->user->getId();
+ }
+
+ public function isLocked() {
+ return $this->user->isLocked();
+ }
+
+ public function isHidden() {
+ return $this->user->isHidden();
+ }
+
+ public function resetAuthToken() {
+ \MediaWiki\Session\SessionManager::singleton()->invalidateSessionsForUser( $this->user );
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Primary authentication provider wrapper for AuthPlugin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use AuthPlugin;
+use User;
+
+/**
+ * Primary authentication provider wrapper for AuthPlugin
+ * @warning If anything depends on the wrapped AuthPlugin being $wgAuth, it won't work with this!
+ * @ingroup Auth
+ * @since 1.27
+ * @deprecated since 1.27
+ */
+class AuthPluginPrimaryAuthenticationProvider
+ extends AbstractPasswordPrimaryAuthenticationProvider
+{
+ private $auth;
+ private $hasDomain;
+ private $requestType = null;
+
+ /**
+ * @param AuthPlugin $auth AuthPlugin to wrap
+ * @param string|null $requestType Class name of the
+ * PasswordAuthenticationRequest to use. If $auth->domainList() returns
+ * more than one domain, this must be a PasswordDomainAuthenticationRequest.
+ */
+ public function __construct( AuthPlugin $auth, $requestType = null ) {
+ parent::__construct();
+
+ if ( $auth instanceof AuthManagerAuthPlugin ) {
+ throw new \InvalidArgumentException(
+ 'Trying to wrap AuthManagerAuthPlugin in AuthPluginPrimaryAuthenticationProvider ' .
+ 'makes no sense.'
+ );
+ }
+
+ $need = count( $auth->domainList() ) > 1
+ ? PasswordDomainAuthenticationRequest::class
+ : PasswordAuthenticationRequest::class;
+ if ( $requestType === null ) {
+ $requestType = $need;
+ } elseif ( $requestType !== $need && !is_subclass_of( $requestType, $need ) ) {
+ throw new \InvalidArgumentException( "$requestType is not a $need" );
+ }
+
+ $this->auth = $auth;
+ $this->requestType = $requestType;
+ $this->hasDomain = (
+ $requestType === PasswordDomainAuthenticationRequest::class ||
+ is_subclass_of( $requestType, PasswordDomainAuthenticationRequest::class )
+ );
+ $this->authoritative = $auth->strict();
+
+ // Registering hooks from core is unusual, but is needed here to be
+ // able to call the AuthPlugin methods those hooks replace.
+ \Hooks::register( 'UserSaveSettings', [ $this, 'onUserSaveSettings' ] );
+ \Hooks::register( 'UserGroupsChanged', [ $this, 'onUserGroupsChanged' ] );
+ \Hooks::register( 'UserLoggedIn', [ $this, 'onUserLoggedIn' ] );
+ \Hooks::register( 'LocalUserCreated', [ $this, 'onLocalUserCreated' ] );
+ }
+
+ /**
+ * Create an appropriate AuthenticationRequest
+ * @return PasswordAuthenticationRequest
+ */
+ protected function makeAuthReq() {
+ $class = $this->requestType;
+ if ( $this->hasDomain ) {
+ return new $class( $this->auth->domainList() );
+ } else {
+ return new $class();
+ }
+ }
+
+ /**
+ * Call $this->auth->setDomain()
+ * @param PasswordAuthenticationRequest $req
+ */
+ protected function setDomain( $req ) {
+ if ( $this->hasDomain ) {
+ $domain = $req->domain;
+ } else {
+ // Just grab the first one.
+ $domainList = $this->auth->domainList();
+ $domain = reset( $domainList );
+ }
+
+ // Special:UserLogin does this. Strange.
+ if ( !$this->auth->validDomain( $domain ) ) {
+ $domain = $this->auth->getDomain();
+ }
+ $this->auth->setDomain( $domain );
+ }
+
+ /**
+ * Hook function to call AuthPlugin::updateExternalDB()
+ * @param User $user
+ * @codeCoverageIgnore
+ */
+ public function onUserSaveSettings( $user ) {
+ // No way to know the domain, just hope the provider handles that.
+ $this->auth->updateExternalDB( $user );
+ }
+
+ /**
+ * Hook function to call AuthPlugin::updateExternalDBGroups()
+ * @param User $user
+ * @param array $added
+ * @param array $removed
+ */
+ public function onUserGroupsChanged( $user, $added, $removed ) {
+ // No way to know the domain, just hope the provider handles that.
+ $this->auth->updateExternalDBGroups( $user, $added, $removed );
+ }
+
+ /**
+ * Hook function to call AuthPlugin::updateUser()
+ * @param User $user
+ */
+ public function onUserLoggedIn( $user ) {
+ $hookUser = $user;
+ // No way to know the domain, just hope the provider handles that.
+ $this->auth->updateUser( $hookUser );
+ if ( $hookUser !== $user ) {
+ throw new \UnexpectedValueException(
+ get_class( $this->auth ) . '::updateUser() tried to replace $user!'
+ );
+ }
+ }
+
+ /**
+ * Hook function to call AuthPlugin::initUser()
+ * @param User $user
+ * @param bool $autocreated
+ */
+ public function onLocalUserCreated( $user, $autocreated ) {
+ // For $autocreated, see self::autoCreatedAccount()
+ if ( !$autocreated ) {
+ $hookUser = $user;
+ // No way to know the domain, just hope the provider handles that.
+ $this->auth->initUser( $hookUser, $autocreated );
+ if ( $hookUser !== $user ) {
+ throw new \UnexpectedValueException(
+ get_class( $this->auth ) . '::initUser() tried to replace $user!'
+ );
+ }
+ }
+ }
+
+ public function getUniqueId() {
+ return parent::getUniqueId() . ':' . get_class( $this->auth );
+ }
+
+ public function getAuthenticationRequests( $action, array $options ) {
+ switch ( $action ) {
+ case AuthManager::ACTION_LOGIN:
+ case AuthManager::ACTION_CREATE:
+ return [ $this->makeAuthReq() ];
+
+ case AuthManager::ACTION_CHANGE:
+ case AuthManager::ACTION_REMOVE:
+ // No way to know the domain, just hope the provider handles that.
+ return $this->auth->allowPasswordChange() ? [ $this->makeAuthReq() ] : [];
+
+ default:
+ return [];
+ }
+ }
+
+ public function beginPrimaryAuthentication( array $reqs ) {
+ $req = AuthenticationRequest::getRequestByClass( $reqs, $this->requestType );
+ if ( !$req || $req->username === null || $req->password === null ||
+ ( $this->hasDomain && $req->domain === null )
+ ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $username = User::getCanonicalName( $req->username, 'usable' );
+ if ( $username === false ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $this->setDomain( $req );
+ if ( $this->testUserCanAuthenticateInternal( User::newFromName( $username ) ) &&
+ $this->auth->authenticate( $username, $req->password )
+ ) {
+ return AuthenticationResponse::newPass( $username );
+ } else {
+ $this->authoritative = $this->auth->strict() || $this->auth->strictUserAuth( $username );
+ return $this->failResponse( $req );
+ }
+ }
+
+ public function testUserCanAuthenticate( $username ) {
+ $username = User::getCanonicalName( $username, 'usable' );
+ if ( $username === false ) {
+ return false;
+ }
+
+ // We have to check every domain, because at least LdapAuthentication
+ // interprets AuthPlugin::userExists() as applying only to the current
+ // domain.
+ $curDomain = $this->auth->getDomain();
+ $domains = $this->auth->domainList() ?: [ '' ];
+ foreach ( $domains as $domain ) {
+ $this->auth->setDomain( $domain );
+ if ( $this->testUserCanAuthenticateInternal( User::newFromName( $username ) ) ) {
+ $this->auth->setDomain( $curDomain );
+ return true;
+ }
+ }
+ $this->auth->setDomain( $curDomain );
+ return false;
+ }
+
+ /**
+ * @see self::testUserCanAuthenticate
+ * @note The caller is responsible for calling $this->auth->setDomain()
+ * @param User $user
+ * @return bool
+ */
+ private function testUserCanAuthenticateInternal( $user ) {
+ if ( $this->auth->userExists( $user->getName() ) ) {
+ return !$this->auth->getUserInstance( $user )->isLocked();
+ } else {
+ return false;
+ }
+ }
+
+ public function providerRevokeAccessForUser( $username ) {
+ $username = User::getCanonicalName( $username, 'usable' );
+ if ( $username === false ) {
+ return;
+ }
+ $user = User::newFromName( $username );
+ if ( $user ) {
+ // Reset the password on every domain.
+ $curDomain = $this->auth->getDomain();
+ $domains = $this->auth->domainList() ?: [ '' ];
+ $failed = [];
+ foreach ( $domains as $domain ) {
+ $this->auth->setDomain( $domain );
+ if ( $this->testUserCanAuthenticateInternal( $user ) &&
+ !$this->auth->setPassword( $user, null )
+ ) {
+ $failed[] = $domain === '' ? '(default)' : $domain;
+ }
+ }
+ $this->auth->setDomain( $curDomain );
+ if ( $failed ) {
+ throw new \UnexpectedValueException(
+ "AuthPlugin failed to reset password for $username in the following domains: "
+ . join( ' ', $failed )
+ );
+ }
+ }
+ }
+
+ public function testUserExists( $username, $flags = User::READ_NORMAL ) {
+ $username = User::getCanonicalName( $username, 'usable' );
+ if ( $username === false ) {
+ return false;
+ }
+
+ // We have to check every domain, because at least LdapAuthentication
+ // interprets AuthPlugin::userExists() as applying only to the current
+ // domain.
+ $curDomain = $this->auth->getDomain();
+ $domains = $this->auth->domainList() ?: [ '' ];
+ foreach ( $domains as $domain ) {
+ $this->auth->setDomain( $domain );
+ if ( $this->auth->userExists( $username ) ) {
+ $this->auth->setDomain( $curDomain );
+ return true;
+ }
+ }
+ $this->auth->setDomain( $curDomain );
+ return false;
+ }
+
+ public function providerAllowsPropertyChange( $property ) {
+ // No way to know the domain, just hope the provider handles that.
+ return $this->auth->allowPropChange( $property );
+ }
+
+ public function providerAllowsAuthenticationDataChange(
+ AuthenticationRequest $req, $checkData = true
+ ) {
+ if ( get_class( $req ) !== $this->requestType ) {
+ return \StatusValue::newGood( 'ignored' );
+ }
+
+ // Hope it works, AuthPlugin gives us no way to do this.
+ $curDomain = $this->auth->getDomain();
+ $this->setDomain( $req );
+ try {
+ // If !$checkData the domain might be wrong. Nothing we can do about that.
+ if ( !$this->auth->allowPasswordChange() ) {
+ return \StatusValue::newFatal( 'authmanager-authplugin-setpass-denied' );
+ }
+
+ if ( !$checkData ) {
+ return \StatusValue::newGood();
+ }
+
+ if ( $this->hasDomain ) {
+ if ( $req->domain === null ) {
+ return \StatusValue::newGood( 'ignored' );
+ }
+ if ( !$this->auth->validDomain( $req->domain ) ) {
+ return \StatusValue::newFatal( 'authmanager-authplugin-setpass-bad-domain' );
+ }
+ }
+
+ $username = User::getCanonicalName( $req->username, 'usable' );
+ if ( $username !== false ) {
+ $sv = \StatusValue::newGood();
+ if ( $req->password !== null ) {
+ if ( $req->password !== $req->retype ) {
+ $sv->fatal( 'badretype' );
+ } else {
+ $sv->merge( $this->checkPasswordValidity( $username, $req->password ) );
+ }
+ }
+ return $sv;
+ } else {
+ return \StatusValue::newGood( 'ignored' );
+ }
+ } finally {
+ $this->auth->setDomain( $curDomain );
+ }
+ }
+
+ public function providerChangeAuthenticationData( AuthenticationRequest $req ) {
+ if ( get_class( $req ) === $this->requestType ) {
+ $username = $req->username !== null ? User::getCanonicalName( $req->username, 'usable' ) : false;
+ if ( $username === false ) {
+ return;
+ }
+
+ if ( $this->hasDomain && $req->domain === null ) {
+ return;
+ }
+
+ $this->setDomain( $req );
+ $user = User::newFromName( $username );
+ if ( !$this->auth->setPassword( $user, $req->password ) ) {
+ // This is totally unfriendly and leaves other
+ // AuthenticationProviders in an uncertain state, but what else
+ // can we do?
+ throw new \ErrorPageError(
+ 'authmanager-authplugin-setpass-failed-title',
+ 'authmanager-authplugin-setpass-failed-message'
+ );
+ }
+ }
+ }
+
+ public function accountCreationType() {
+ // No way to know the domain, just hope the provider handles that.
+ return $this->auth->canCreateAccounts() ? self::TYPE_CREATE : self::TYPE_NONE;
+ }
+
+ public function testForAccountCreation( $user, $creator, array $reqs ) {
+ return \StatusValue::newGood();
+ }
+
+ public function beginPrimaryAccountCreation( $user, $creator, array $reqs ) {
+ if ( $this->accountCreationType() === self::TYPE_NONE ) {
+ throw new \BadMethodCallException( 'Shouldn\'t call this when accountCreationType() is NONE' );
+ }
+
+ $req = AuthenticationRequest::getRequestByClass( $reqs, $this->requestType );
+ if ( !$req || $req->username === null || $req->password === null ||
+ ( $this->hasDomain && $req->domain === null )
+ ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $username = User::getCanonicalName( $req->username, 'usable' );
+ if ( $username === false ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $this->setDomain( $req );
+ if ( $this->auth->addUser(
+ $user, $req->password, $user->getEmail(), $user->getRealName()
+ ) ) {
+ return AuthenticationResponse::newPass();
+ } else {
+ return AuthenticationResponse::newFail(
+ new \Message( 'authmanager-authplugin-create-fail' )
+ );
+ }
+ }
+
+ public function autoCreatedAccount( $user, $source ) {
+ $hookUser = $user;
+ // No way to know the domain, just hope the provider handles that.
+ $this->auth->initUser( $hookUser, true );
+ if ( $hookUser !== $user ) {
+ throw new \UnexpectedValueException(
+ get_class( $this->auth ) . '::initUser() tried to replace $user!'
+ );
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Authentication provider interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use Config;
+use Psr\Log\LoggerAwareInterface;
+
+/**
+ * An AuthenticationProvider is used by AuthManager when authenticating users.
+ * @ingroup Auth
+ * @since 1.27
+ */
+interface AuthenticationProvider extends LoggerAwareInterface {
+
+ /**
+ * Set AuthManager
+ * @param AuthManager $manager
+ */
+ public function setManager( AuthManager $manager );
+
+ /**
+ * Set configuration
+ * @param Config $config
+ */
+ public function setConfig( Config $config );
+
+ /**
+ * Return a unique identifier for this instance
+ *
+ * This must be the same across requests. If multiple instances return the
+ * same ID, exceptions will be thrown from AuthManager.
+ *
+ * @return string
+ */
+ public function getUniqueId();
+
+ /**
+ * Return the applicable list of AuthenticationRequests
+ *
+ * Possible values for $action depend on whether the implementing class is
+ * also a PreAuthenticationProvider, PrimaryAuthenticationProvider, or
+ * SecondaryAuthenticationProvider.
+ * - ACTION_LOGIN: Valid for passing to beginAuthentication. Called on all
+ * providers.
+ * - ACTION_CREATE: Valid for passing to beginAccountCreation. Called on
+ * all providers.
+ * - ACTION_LINK: Valid for passing to beginAccountLink. Called on linking
+ * primary providers only.
+ * - ACTION_CHANGE: Valid for passing to AuthManager::changeAuthenticationData
+ * to change credentials. Called on primary and secondary providers.
+ * - ACTION_REMOVE: Valid for passing to AuthManager::changeAuthenticationData
+ * to remove credentials. Must work without additional user input (i.e.
+ * without calling loadFromSubmission). Called on primary and secondary
+ * providers.
+ *
+ * @see AuthManager::getAuthenticationRequests()
+ * @param string $action
+ * @param array $options Options are:
+ * - username: User name related to the action, or null/unset if anon.
+ * - ACTION_LOGIN: The currently logged-in user, if any.
+ * - ACTION_CREATE: The account creator, if non-anonymous.
+ * - ACTION_LINK: The local user being linked to.
+ * - ACTION_CHANGE: The user having data changed.
+ * - ACTION_REMOVE: The user having data removed.
+ * This does not need to be copied into the returned requests, you only
+ * need to pay attention to it if the set of requests differs based on
+ * the user.
+ * @return AuthenticationRequest[]
+ */
+ public function getAuthenticationRequests( $action, array $options );
+
+}
--- /dev/null
+<?php
+/**
+ * Authentication request value object
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use Message;
+
+/**
+ * This is a value object for authentication requests.
+ *
+ * An AuthenticationRequest represents a set of form fields that are needed on
+ * and provided from the login, account creation, or password change forms.
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+abstract class AuthenticationRequest {
+
+ /** Indicates that the request is not required for authentication to proceed. */
+ const OPTIONAL = 0;
+
+ /** Indicates that the request is required for authentication to proceed. */
+ const REQUIRED = 1;
+
+ /** Indicates that the request is required by a primary authentication
+ * provdier, but other primary authentication providers do not require it. */
+ const PRIMARY_REQUIRED = 2;
+
+ /** @var string|null The AuthManager::ACTION_* constant this request was
+ * created to be used for. The *_CONTINUE constants are not used here, the
+ * corresponding "begin" constant is used instead.
+ */
+ public $action = null;
+
+ /** @var int For login, continue, and link actions, one of self::OPTIONAL,
+ * self::REQUIRED, or self::PRIMARY_REQUIRED */
+ public $required = self::REQUIRED;
+
+ /** @var string|null Return-to URL, in case of redirect */
+ public $returnToUrl = null;
+
+ /** @var string|null Username. May not be used by all subclasses. */
+ public $username = null;
+
+ /**
+ * Supply a unique key for deduplication
+ *
+ * When the AuthenticationRequests instances returned by the providers are
+ * merged, the value returned here is used for keeping only one copy of
+ * duplicate requests.
+ *
+ * Subclasses should override this if multiple distinct instances would
+ * make sense, i.e. the request class has internal state of some sort.
+ *
+ * This value might be exposed to the user in web forms so it should not
+ * contain private information.
+ *
+ * @return string
+ */
+ public function getUniqueId() {
+ return get_called_class();
+ }
+
+ /**
+ * Fetch input field info
+ *
+ * The field info is an associative array mapping field names to info
+ * arrays. The info arrays have the following keys:
+ * - type: (string) Type of input. Types and equivalent HTML widgets are:
+ * - string: <input type="text">
+ * - password: <input type="password">
+ * - select: <select>
+ * - checkbox: <input type="checkbox">
+ * - multiselect: More a grid of checkboxes than <select multi>
+ * - button: <input type="submit"> (uses 'label' as button text)
+ * - hidden: Not visible to the user, but needs to be preserved for the next request
+ * - null: No widget, just display the 'label' message.
+ * - options: (array) Maps option values to Messages for the
+ * 'select' and 'multiselect' types.
+ * - value: (string) Value (for 'null' and 'hidden') or default value (for other types).
+ * - label: (Message) Text suitable for a label in an HTML form
+ * - help: (Message) Text suitable as a description of what the field is
+ * - optional: (bool) If set and truthy, the field may be left empty
+ *
+ * @return array As above
+ */
+ abstract public function getFieldInfo();
+
+ /**
+ * Returns metadata about this request.
+ *
+ * This is mainly for the benefit of API clients which need more detailed render hints
+ * than what's available through getFieldInfo(). Semantics are unspecified and left to the
+ * individual subclasses, but the contents of the array should be primitive types so that they
+ * can be transformed into JSON or similar formats.
+ *
+ * @return array A (possibly nested) array with primitive types
+ */
+ public function getMetadata() {
+ return [];
+ }
+
+ /**
+ * Initialize form submitted form data.
+ *
+ * Should always return false if self::getFieldInfo() returns an empty
+ * array.
+ *
+ * @param array $data Submitted data as an associative array
+ * @return bool Whether the request data was successfully loaded
+ */
+ public function loadFromSubmission( array $data ) {
+ $fields = array_filter( $this->getFieldInfo(), function ( $info ) {
+ return $info['type'] !== 'null';
+ } );
+ if ( !$fields ) {
+ return false;
+ }
+
+ foreach ( $fields as $field => $info ) {
+ // Checkboxes and buttons are special. Depending on the method used
+ // to populate $data, they might be unset meaning false or they
+ // might be boolean. Further, image buttons might submit the
+ // coordinates of the click rather than the expected value.
+ if ( $info['type'] === 'checkbox' || $info['type'] === 'button' ) {
+ $this->$field = isset( $data[$field] ) && $data[$field] !== false
+ || isset( $data["{$field}_x"] ) && $data["{$field}_x"] !== false;
+ if ( !$this->$field && empty( $info['optional'] ) ) {
+ return false;
+ }
+ continue;
+ }
+
+ // Multiselect are too, slightly
+ if ( !isset( $data[$field] ) && $info['type'] === 'multiselect' ) {
+ $data[$field] = [];
+ }
+
+ if ( !isset( $data[$field] ) ) {
+ return false;
+ }
+ if ( $data[$field] === '' || $data[$field] === [] ) {
+ if ( empty( $info['optional'] ) ) {
+ return false;
+ }
+ } else {
+ switch ( $info['type'] ) {
+ case 'select':
+ if ( !isset( $info['options'][$data[$field]] ) ) {
+ return false;
+ }
+ break;
+
+ case 'multiselect':
+ $data[$field] = (array)$data[$field];
+ $allowed = array_keys( $info['options'] );
+ if ( array_diff( $data[$field], $allowed ) !== [] ) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ $this->$field = $data[$field];
+ }
+
+ return true;
+ }
+
+ /**
+ * Describe the credentials represented by this request
+ *
+ * This is used on requests returned by
+ * AuthenticationProvider::getAuthenticationRequests() for ACTION_LINK
+ * and ACTION_REMOVE and for requests returned in
+ * AuthenticationResponse::$linkRequest to create useful user interfaces.
+ *
+ * @return Message[] with the following keys:
+ * - provider: A Message identifying the service that provides
+ * the credentials, e.g. the name of the third party authentication
+ * service.
+ * - account: A Message identifying the credentials themselves,
+ * e.g. the email address used with the third party authentication
+ * service.
+ */
+ public function describeCredentials() {
+ return [
+ 'provider' => new \RawMessage( '$1', [ get_called_class() ] ),
+ 'account' => new \RawMessage( '$1', [ $this->getUniqueId() ] ),
+ ];
+ }
+
+ /**
+ * Update a set of requests with form submit data, discarding ones that fail
+ * @param AuthenticationRequest[] $reqs
+ * @param array $data
+ * @return AuthenticationRequest[]
+ */
+ public static function loadRequestsFromSubmission( array $reqs, array $data ) {
+ return array_values( array_filter( $reqs, function ( $req ) use ( $data ) {
+ return $req->loadFromSubmission( $data );
+ } ) );
+ }
+
+ /**
+ * Select a request by class name.
+ * @param AuthenticationRequest[] $reqs
+ * @param string $class Class name
+ * @param bool $allowSubclasses If true, also returns any request that's a subclass of the given
+ * class.
+ * @return AuthenticationRequest|null Returns null if there is not exactly
+ * one matching request.
+ */
+ public static function getRequestByClass( array $reqs, $class, $allowSubclasses = false ) {
+ $requests = array_filter( $reqs, function ( $req ) use ( $class, $allowSubclasses ) {
+ if ( $allowSubclasses ) {
+ return is_a( $req, $class, false );
+ } else {
+ return get_class( $req ) === $class;
+ }
+ } );
+ return count( $requests ) === 1 ? reset( $requests ) : null;
+ }
+
+ /**
+ * Get the username from the set of requests
+ *
+ * Only considers requests that have a "username" field.
+ *
+ * @param AuthenticationRequest[] $requests
+ * @return string|null
+ * @throws \UnexpectedValueException If multiple different usernames are present.
+ */
+ public static function getUsernameFromRequests( array $reqs ) {
+ $username = null;
+ $otherClass = null;
+ foreach ( $reqs as $req ) {
+ $info = $req->getFieldInfo();
+ if ( $info && array_key_exists( 'username', $info ) && $req->username !== null ) {
+ if ( $username === null ) {
+ $username = $req->username;
+ $otherClass = get_class( $req );
+ } elseif ( $username !== $req->username ) {
+ $requestClass = get_class( $req );
+ throw new \UnexpectedValueException( "Conflicting username fields: \"{$req->username}\" from "
+ . "$requestClass::\$username vs. \"$username\" from $otherClass::\$username" );
+ }
+ }
+ }
+ return $username;
+ }
+
+ /**
+ * Merge the output of multiple AuthenticationRequest::getFieldInfo() calls.
+ * @param AuthenticationRequest[] $reqs
+ * @return array
+ * @throws \UnexpectedValueException If fields cannot be merged
+ */
+ public static function mergeFieldInfo( array $reqs ) {
+ $merged = [];
+
+ // fields that are required by some primary providers but not others are not actually required
+ $primaryRequests = array_filter( $reqs, function ( $req ) {
+ return $req->required === AuthenticationRequest::PRIMARY_REQUIRED;
+ } );
+ $sharedRequiredPrimaryFields = array_reduce( $primaryRequests, function ( $shared, $req ) {
+ $required = array_keys( array_filter( $req->getFieldInfo(), function ( $options ) {
+ return empty( $options['optional'] );
+ } ) );
+ if ( $shared === null ) {
+ return $required;
+ } else {
+ return array_intersect( $shared, $required );
+ }
+ }, null );
+
+ foreach ( $reqs as $req ) {
+ $info = $req->getFieldInfo();
+ if ( !$info ) {
+ continue;
+ }
+
+ foreach ( $info as $name => $options ) {
+ if (
+ // If the request isn't required, its fields aren't required either.
+ $req->required === self::OPTIONAL
+ // If there is a primary not requiring this field, no matter how many others do,
+ // authentication can proceed without it.
+ || $req->required === self::PRIMARY_REQUIRED
+ && !in_array( $name, $sharedRequiredPrimaryFields, true )
+ ) {
+ $options['optional'] = true;
+ } else {
+ $options['optional'] = !empty( $options['optional'] );
+ }
+
+ if ( !array_key_exists( $name, $merged ) ) {
+ $merged[$name] = $options;
+ } elseif ( $merged[$name]['type'] !== $options['type'] ) {
+ throw new \UnexpectedValueException( "Field type conflict for \"$name\", " .
+ "\"{$merged[$name]['type']}\" vs \"{$options['type']}\""
+ );
+ } else {
+ if ( isset( $options['options'] ) ) {
+ if ( isset( $merged[$name]['options'] ) ) {
+ $merged[$name]['options'] += $options['options'];
+ } else {
+ // @codeCoverageIgnoreStart
+ $merged[$name]['options'] = $options['options'];
+ // @codeCoverageIgnoreEnd
+ }
+ }
+
+ $merged[$name]['optional'] = $merged[$name]['optional'] && $options['optional'];
+
+ // No way to merge 'value', 'image', 'help', or 'label', so just use
+ // the value from the first request.
+ }
+ }
+ }
+
+ return $merged;
+ }
+
+ /**
+ * Implementing this mainly for use from the unit tests.
+ * @param array $data
+ * @return AuthenticationRequest
+ */
+ public static function __set_state( $data ) {
+ $ret = new static();
+ foreach ( $data as $k => $v ) {
+ $ret->$k = $v;
+ }
+ return $ret;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Authentication response value object
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use Message;
+
+/**
+ * This is a value object to hold authentication response data
+ * @ingroup Auth
+ * @since 1.27
+ */
+class AuthenticationResponse {
+ /** Indicates that the authentication succeeded. */
+ const PASS = 'PASS';
+
+ /** Indicates that the authentication failed. */
+ const FAIL = 'FAIL';
+
+ /** Indicates that third-party authentication succeeded but no user exists.
+ * Either treat this like a UI response or pass $this->createRequest to
+ * AuthManager::beginCreateAccount().
+ */
+ const RESTART = 'RESTART';
+
+ /** Indicates that the authentication provider does not handle this request. */
+ const ABSTAIN = 'ABSTAIN';
+
+ /** Indicates that the authentication needs further user input of some sort. */
+ const UI = 'UI';
+
+ /** Indicates that the authentication needs to be redirected to a third party to proceed. */
+ const REDIRECT = 'REDIRECT';
+
+ /** @var string One of the constants above */
+ public $status;
+
+ /** @var string|null URL to redirect to for a REDIRECT response */
+ public $redirectTarget = null;
+
+ /**
+ * @var mixed Data for a REDIRECT response that a client might use to
+ * query the remote site via its API rather than by following $redirectTarget.
+ * Value must be something acceptable to ApiResult::addValue().
+ */
+ public $redirectApiData = null;
+
+ /**
+ * @var AuthenticationRequest[] Needed AuthenticationRequests to continue
+ * after a UI or REDIRECT response
+ */
+ public $neededRequests = [];
+
+ /** @var Message|null I18n message to display in case of UI or FAIL */
+ public $message = null;
+
+ /**
+ * @var string|null Local user name from authentication.
+ * May be null if the authentication passed but no local user is known.
+ */
+ public $username = null;
+
+ /**
+ * @var AuthenticationRequest|null
+ *
+ * Returned with a PrimaryAuthenticationProvider login FAIL or a PASS with
+ * no username, this holds a request that should result in a PASS when
+ * passed to that provider's PrimaryAuthenticationProvider::beginPrimaryAccountCreation().
+ *
+ * Returned with an AuthManager login FAIL or RESTART, this holds a
+ * CreateFromLoginAuthenticationRequest that may be passed to
+ * AuthManager::beginCreateAccount(), possibly in place of any
+ * "primary-required" requests. It may also be passed to
+ * AuthManager::beginAuthentication() to preserve state.
+ */
+ public $createRequest = null;
+
+ /**
+ * @var AuthenticationRequest|null Returned with a PrimaryAuthenticationProvider
+ * login PASS with no username, this holds a request to pass to
+ * AuthManager::changeAuthenticationData() to link the account once the
+ * local user has been determined.
+ */
+ public $linkRequest = null;
+
+ /**
+ * @var AuthenticationRequest|null Returned with an AuthManager account
+ * creation PASS, this holds a request to pass to AuthManager::beginAuthentication()
+ * to immediately log into the created account.
+ */
+ public $loginRequest = null;
+
+ /**
+ * @param string|null $username Local username
+ * @return AuthenticationResponse
+ */
+ public static function newPass( $username = null ) {
+ $ret = new AuthenticationResponse;
+ $ret->status = AuthenticationResponse::PASS;
+ $ret->username = $username;
+ return $ret;
+ }
+
+ /**
+ * @param Message $msg
+ * @return AuthenticationResponse
+ */
+ public static function newFail( Message $msg ) {
+ $ret = new AuthenticationResponse;
+ $ret->status = AuthenticationResponse::FAIL;
+ $ret->message = $msg;
+ return $ret;
+ }
+
+ /**
+ * @param Message $msg
+ * @return AuthenticationResponse
+ */
+ public static function newRestart( Message $msg ) {
+ $ret = new AuthenticationResponse;
+ $ret->status = AuthenticationResponse::RESTART;
+ $ret->message = $msg;
+ return $ret;
+ }
+
+ /**
+ * @return AuthenticationResponse
+ */
+ public static function newAbstain() {
+ $ret = new AuthenticationResponse;
+ $ret->status = AuthenticationResponse::ABSTAIN;
+ return $ret;
+ }
+
+ /**
+ * @param AuthenticationRequest[] $reqs AuthenticationRequests needed to continue
+ * @param Message $msg
+ * @return AuthenticationResponse
+ */
+ public static function newUI( array $reqs, Message $msg ) {
+ if ( !$reqs ) {
+ throw new \InvalidArgumentException( '$reqs may not be empty' );
+ }
+
+ $ret = new AuthenticationResponse;
+ $ret->status = AuthenticationResponse::UI;
+ $ret->neededRequests = $reqs;
+ $ret->message = $msg;
+ return $ret;
+ }
+
+ /**
+ * @param AuthenticationRequest[] $reqs AuthenticationRequests needed to continue
+ * @param string $redirectTarget URL
+ * @param mixed $redirectApiData Data suitable for adding to an ApiResult
+ * @return AuthenticationResponse
+ */
+ public static function newRedirect( array $reqs, $redirectTarget, $redirectApiData = null ) {
+ if ( !$reqs ) {
+ throw new \InvalidArgumentException( '$reqs may not be empty' );
+ }
+
+ $ret = new AuthenticationResponse;
+ $ret->status = AuthenticationResponse::REDIRECT;
+ $ret->neededRequests = $reqs;
+ $ret->redirectTarget = $redirectTarget;
+ $ret->redirectApiData = $redirectApiData;
+ return $ret;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use Message;
+
+/**
+ * This is an authentication request that just implements a simple button.
+ * @ingroup Auth
+ * @since 1.27
+ */
+class ButtonAuthenticationRequest extends AuthenticationRequest {
+ /** @var string */
+ protected $name;
+
+ /** @var Message */
+ protected $label;
+
+ /** @var Message */
+ protected $help;
+
+ /**
+ * @param string $name Button name
+ * @param Message $label Button label
+ * @param Message $help Button help
+ * @param bool $required The button is required for authentication to proceed.
+ */
+ public function __construct( $name, Message $label, Message $help, $required = false ) {
+ $this->name = $name;
+ $this->label = $label;
+ $this->help = $help;
+ $this->required = $required ? self::REQUIRED : self::OPTIONAL;
+ }
+
+ public function getUniqueId() {
+ return parent::getUniqueId() . ':' . $this->name;
+ }
+
+ public function getFieldInfo() {
+ return [
+ $this->name => [
+ 'type' => 'button',
+ 'label' => $this->label,
+ 'help' => $this->help,
+ ]
+ ];
+ }
+
+ /**
+ * Fetch a ButtonAuthenticationRequest or subclass by name
+ * @param AuthenticationRequest[] $reqs Requests to search
+ * @param string $name Name to look for
+ * @return ButtonAuthenticationRequest|null Returns null if there is not
+ * exactly one matching request.
+ */
+ public static function getRequestByName( array $reqs, $name ) {
+ $requests = array_filter( $reqs, function ( $req ) use ( $name ) {
+ return $req instanceof ButtonAuthenticationRequest && $req->name === $name;
+ } );
+ return count( $requests ) === 1 ? reset( $requests ) : null;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ */
+ public static function __set_state( $data ) {
+ if ( !isset( $data['label'] ) ) {
+ $data['label'] = new \RawMessage( '$1', $data['name'] );
+ } elseif ( is_string( $data['label'] ) ) {
+ $data['label'] = new \Message( $data['label'] );
+ } elseif ( is_array( $data['label'] ) ) {
+ $data['label'] = call_user_func_array( 'Message::newFromKey', $data['label'] );
+ }
+ if ( !isset( $data['help'] ) ) {
+ $data['help'] = new \RawMessage( '$1', $data['name'] );
+ } elseif ( is_string( $data['help'] ) ) {
+ $data['help'] = new \Message( $data['help'] );
+ } elseif ( is_array( $data['help'] ) ) {
+ $data['help'] = call_user_func_array( 'Message::newFromKey', $data['help'] );
+ }
+ $ret = new static( $data['name'], $data['label'], $data['help'] );
+ foreach ( $data as $k => $v ) {
+ $ret->$k = $v;
+ }
+ return $ret;
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use Config;
+use StatusValue;
+use User;
+
+/**
+ * Check if the user is blocked, and prevent authentication if so.
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+class CheckBlocksSecondaryAuthenticationProvider extends AbstractSecondaryAuthenticationProvider {
+
+ /** @var bool */
+ protected $blockDisablesLogin = null;
+
+ /**
+ * @param array $params
+ * - blockDisablesLogin: (bool) Whether blocked accounts can log in,
+ * defaults to $wgBlockDisablesLogin
+ */
+ public function __construct( $params = [] ) {
+ if ( isset( $params['blockDisablesLogin'] ) ) {
+ $this->blockDisablesLogin = (bool)$params['blockDisablesLogin'];
+ }
+ }
+
+ public function setConfig( Config $config ) {
+ parent::setConfig( $config );
+
+ if ( $this->blockDisablesLogin === null ) {
+ $this->blockDisablesLogin = $this->config->get( 'BlockDisablesLogin' );
+ }
+ }
+
+ public function getAuthenticationRequests( $action, array $options ) {
+ return [];
+ }
+
+ public function beginSecondaryAuthentication( $user, array $reqs ) {
+ if ( !$this->blockDisablesLogin ) {
+ return AuthenticationResponse::newAbstain();
+ } elseif ( $user->isBlocked() ) {
+ return AuthenticationResponse::newFail(
+ new \Message( 'login-userblocked', [ $user->getName() ] )
+ );
+ } else {
+ return AuthenticationResponse::newPass();
+ }
+ }
+
+ public function beginSecondaryAccountCreation( $user, $creator, array $reqs ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ public function testUserForCreation( $user, $autocreate ) {
+ $block = $user->isBlockedFromCreateAccount();
+ if ( $block ) {
+ $errorParams = [
+ $block->getTarget(),
+ $block->mReason ?: \Message::newFromKey( 'blockednoreason' )->text(),
+ $block->getByName()
+ ];
+
+ if ( $block->getType() === \Block::TYPE_RANGE ) {
+ $errorMessage = 'cantcreateaccount-range-text';
+ $errorParams[] = $this->manager->getRequest()->getIP();
+ } else {
+ $errorMessage = 'cantcreateaccount-text';
+ }
+
+ return StatusValue::newFatal(
+ new \Message( $errorMessage, $errorParams )
+ );
+ } else {
+ return StatusValue::newGood();
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+class ConfirmLinkAuthenticationRequest extends AuthenticationRequest {
+ /** @var AuthenticationRequest[] */
+ protected $linkRequests;
+
+ /** @var string[] List of unique IDs of the confirmed accounts. */
+ public $confirmedLinkIDs = [];
+
+ /**
+ * @param AuthenticationRequest[] $linkRequests A list of autolink requests
+ * which need to be confirmed.
+ */
+ public function __construct( array $linkRequests ) {
+ if ( !$linkRequests ) {
+ throw new \InvalidArgumentException( '$linkRequests must not be empty' );
+ }
+ $this->linkRequests = $linkRequests;
+ }
+
+ public function getFieldInfo() {
+ $options = [];
+ foreach ( $this->linkRequests as $req ) {
+ $description = $req->describeCredentials();
+ $options[$req->getUniqueId()] = wfMessage(
+ 'authprovider-confirmlink-option',
+ $description['provider']->text(), $description['account']->text()
+ );
+ }
+ return [
+ 'confirmedLinkIDs' => [
+ 'type' => 'multiselect',
+ 'options' => $options,
+ 'label' => wfMessage( 'authprovider-confirmlink-request-label' ),
+ 'help' => wfMessage( 'authprovider-confirmlink-request-help' ),
+ 'optional' => true,
+ ]
+ ];
+ }
+
+ public function getUniqueId() {
+ return parent::getUniqueId() . ':' . implode( '|', array_map( function ( $req ) {
+ return $req->getUniqueId();
+ }, $this->linkRequests ) );
+ }
+
+ /**
+ * Implementing this mainly for use from the unit tests.
+ * @param array $data
+ * @return AuthenticationRequest
+ */
+ public static function __set_state( $data ) {
+ $ret = new static( $data['linkRequests'] );
+ foreach ( $data as $k => $v ) {
+ $ret->$k = $v;
+ }
+ return $ret;
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+use StatusValue;
+use User;
+
+/**
+ * Links third-party authentication to the user's account
+ *
+ * If the user logged into linking provider accounts that aren't linked to a
+ * local user, this provider will prompt the user to link them after a
+ * successful login or account creation.
+ *
+ * To avoid confusing behavior, this provider should be later in the
+ * configuration list than any provider that can abort the authentication
+ * process, so that it is only invoked for successful authentication.
+ */
+class ConfirmLinkSecondaryAuthenticationProvider extends AbstractSecondaryAuthenticationProvider {
+
+ public function getAuthenticationRequests( $action, array $options ) {
+ return [];
+ }
+
+ public function beginSecondaryAuthentication( $user, array $reqs ) {
+ return $this->beginLinkAttempt( $user, 'AuthManager::authnState' );
+ }
+
+ public function continueSecondaryAuthentication( $user, array $reqs ) {
+ return $this->continueLinkAttempt( $user, 'AuthManager::authnState', $reqs );
+ }
+
+ public function beginSecondaryAccountCreation( $user, $creator, array $reqs ) {
+ return $this->beginLinkAttempt( $user, 'AuthManager::accountCreationState' );
+ }
+
+ public function continueSecondaryAccountCreation( $user, $creator, array $reqs ) {
+ return $this->continueLinkAttempt( $user, 'AuthManager::accountCreationState', $reqs );
+ }
+
+ /**
+ * Begin the link attempt
+ * @param User $user
+ * @param string $key Session key to look in
+ * @return AuthenticationResponse
+ */
+ protected function beginLinkAttempt( $user, $key ) {
+ $session = $this->manager->getRequest()->getSession();
+ $state = $session->getSecret( $key );
+ if ( !is_array( $state ) ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $maybeLink = array_filter( $state['maybeLink'], function ( $req ) {
+ return $this->manager->allowsAuthenticationDataChange( $req )->isGood();
+ } );
+ if ( !$maybeLink ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $req = new ConfirmLinkAuthenticationRequest( $maybeLink );
+ return AuthenticationResponse::newUI(
+ [ $req ],
+ wfMessage( 'authprovider-confirmlink-message' )
+ );
+ }
+
+ /**
+ * Continue the link attempt
+ * @param User $user
+ * @param string $key Session key to look in
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse
+ */
+ protected function continueLinkAttempt( $user, $key, array $reqs ) {
+ $req = ButtonAuthenticationRequest::getRequestByName( $reqs, 'linkOk' );
+ if ( $req ) {
+ return AuthenticationResponse::newPass();
+ }
+
+ $req = AuthenticationRequest::getRequestByClass( $reqs, ConfirmLinkAuthenticationRequest::class );
+ if ( !$req ) {
+ // WTF? Retry.
+ return $this->beginLinkAttempt( $user, $key );
+ }
+
+ $session = $this->manager->getRequest()->getSession();
+ $state = $session->getSecret( $key );
+ if ( !is_array( $state ) ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $maybeLink = [];
+ foreach ( $state['maybeLink'] as $linkReq ) {
+ $maybeLink[$linkReq->getUniqueId()] = $linkReq;
+ }
+ if ( !$maybeLink ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $state['maybeLink'] = [];
+ $session->setSecret( $key, $state );
+
+ $statuses = [];
+ $anyFailed = false;
+ foreach ( $req->confirmedLinkIDs as $id ) {
+ if ( isset( $maybeLink[$id] ) ) {
+ $req = $maybeLink[$id];
+ $req->username = $user->getName();
+ if ( !$req->action ) {
+ // Make sure the action is set, but don't override it if
+ // the provider filled it in.
+ $req->action = AuthManager::ACTION_CHANGE;
+ }
+ $status = $this->manager->allowsAuthenticationDataChange( $req );
+ $statuses[] = [ $req, $status ];
+ if ( $status->isGood() ) {
+ $this->manager->changeAuthenticationData( $req );
+ } else {
+ $anyFailed = true;
+ }
+ }
+ }
+ if ( !$anyFailed ) {
+ return AuthenticationResponse::newPass();
+ }
+
+ $combinedStatus = \Status::newGood();
+ foreach ( $statuses as $data ) {
+ list( $req, $status ) = $data;
+ $descriptionInfo = $req->describeCredentials();
+ $description = wfMessage(
+ 'authprovider-confirmlink-option',
+ $descriptionInfo['provider']->text(), $descriptionInfo['account']->text()
+ )->text();
+ if ( $status->isGood() ) {
+ $combinedStatus->error( wfMessage( 'authprovider-confirmlink-success-line', $description ) );
+ } else {
+ $combinedStatus->error( wfMessage(
+ 'authprovider-confirmlink-failed-line', $description, $status->getMessage()->text()
+ ) );
+ }
+ }
+ return AuthenticationResponse::newUI(
+ [
+ new ButtonAuthenticationRequest(
+ 'linkOk', wfMessage( 'ok' ), wfMessage( 'authprovider-confirmlink-ok-help' )
+ )
+ ],
+ $combinedStatus->getMessage( 'authprovider-confirmlink-failed' )
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+/**
+ * This transfers state between the login and account creation flows.
+ *
+ * AuthManager::getAuthenticationRequests() won't return this type, but it
+ * may be passed to AuthManager::beginAuthentication() or
+ * AuthManager::beginAccountCreation() anyway.
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+class CreateFromLoginAuthenticationRequest extends AuthenticationRequest {
+ public $required = self::OPTIONAL;
+
+ /** @var AuthenticationRequest|null */
+ public $createRequest;
+
+ /** @var AuthenticationRequest[] */
+ public $maybeLink = [];
+
+ /**
+ * @param AuthenticationRequest|null $createRequest A request to use to
+ * begin creating the account
+ * @param AuthenticationRequest[] $maybeLink Additional accounts to link
+ * after creation.
+ */
+ public function __construct(
+ AuthenticationRequest $createRequest = null, array $maybeLink = []
+ ) {
+ $this->createRequest = $createRequest;
+ $this->maybeLink = $maybeLink;
+ $this->username = $createRequest ? $createRequest->username : null;
+ }
+
+ public function getFieldInfo() {
+ return [];
+ }
+
+ public function loadFromSubmission( array $data ) {
+ return true;
+ }
+
+ /**
+ * Indicate whether this request contains any state for the specified
+ * action.
+ * @param string $action One of the AuthManager::ACTION_* constants
+ * @return boolean
+ */
+ public function hasStateForAction( $action ) {
+ switch ( $action ) {
+ case AuthManager::ACTION_LOGIN:
+ return (bool)$this->maybeLink;
+ case AuthManager::ACTION_CREATE:
+ return $this->maybeLink || $this->createRequest;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Indicate whether this request contains state for the specified
+ * action sufficient to replace other primary-required requests.
+ * @param string $action One of the AuthManager::ACTION_* constants
+ * @return boolean
+ */
+ public function hasPrimaryStateForAction( $action ) {
+ switch ( $action ) {
+ case AuthManager::ACTION_CREATE:
+ return (bool)$this->createRequest;
+ default:
+ return false;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+/**
+ * Returned from account creation to allow for logging into the created account
+ * @ingroup Auth
+ * @since 1.27
+ */
+class CreatedAccountAuthenticationRequest extends AuthenticationRequest {
+
+ public $required = self::OPTIONAL;
+
+ /** @var int User id */
+ public $id;
+
+ public function getFieldInfo() {
+ return [];
+ }
+
+ /**
+ * @param int $id User id
+ * @param string $name Username
+ */
+ public function __construct( $id, $name ) {
+ $this->id = $id;
+ $this->username = $name;
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * Authentication request for the reason given for account creation.
+ * Used in logs and for notification.
+ */
+class CreationReasonAuthenticationRequest extends AuthenticationRequest {
+ /** @var string Account creation reason (only used when creating for someone else) */
+ public $reason;
+
+ public $required = self::OPTIONAL;
+
+ public function getFieldInfo() {
+ return [
+ 'reason' => [
+ 'type' => 'string',
+ 'label' => wfMessage( 'createacct-reason' ),
+ 'help' => wfMessage( 'createacct-reason-help' ),
+ ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+use Config;
+use StatusValue;
+
+/**
+ * Handles email notification / email address confirmation for account creation.
+ *
+ * Set 'no-email' to true (via AuthManager::setAuthenticationSessionData) to skip this provider.
+ * Primary providers doing so are expected to take care of email address confirmation.
+ */
+class EmailNotificationSecondaryAuthenticationProvider
+ extends AbstractSecondaryAuthenticationProvider
+{
+ /** @var bool */
+ protected $sendConfirmationEmail;
+
+ /**
+ * @param array $params
+ * - sendConfirmationEmail: (bool) send an email asking the user to confirm their email
+ * address after a successful registration
+ */
+ public function __construct( $params = [] ) {
+ if ( isset( $params['sendConfirmationEmail'] ) ) {
+ $this->sendConfirmationEmail = (bool)$params['sendConfirmationEmail'];
+ }
+ }
+
+ public function setConfig( Config $config ) {
+ parent::setConfig( $config );
+
+ if ( $this->sendConfirmationEmail === null ) {
+ $this->sendConfirmationEmail = $this->config->get( 'EnableEmail' )
+ && $this->config->get( 'EmailAuthentication' );
+ }
+ }
+
+ public function getAuthenticationRequests( $action, array $options ) {
+ return [];
+ }
+
+ public function beginSecondaryAuthentication( $user, array $reqs ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ public function beginSecondaryAccountCreation( $user, $creator, array $reqs ) {
+ if (
+ $this->sendConfirmationEmail
+ && $user->getEmail()
+ && !$this->manager->getAuthenticationSessionData( 'no-email' )
+ ) {
+ $status = $user->sendConfirmationMail();
+ $user->saveSettings();
+ if ( $status->isGood() ) {
+ // TODO show 'confirmemail_oncreate' success message
+ } else {
+ // TODO show 'confirmemail_sendfailed' error message
+ $this->logger->warning( 'Could not send confirmation email: ' .
+ $status->getWikiText( false, false, 'en' ) );
+ }
+ }
+
+ return AuthenticationResponse::newPass();
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use LoginForm;
+use StatusValue;
+use User;
+
+/**
+ * A pre-authentication provider to call some legacy hooks.
+ * @ingroup Auth
+ * @since 1.27
+ * @deprecated since 1.27
+ */
+class LegacyHookPreAuthenticationProvider extends AbstractPreAuthenticationProvider {
+
+ public function testForAuthentication( array $reqs ) {
+ $req = AuthenticationRequest::getRequestByClass( $reqs, PasswordAuthenticationRequest::class );
+ if ( $req ) {
+ $user = User::newFromName( $req->username );
+ $password = $req->password;
+ } else {
+ $user = null;
+ foreach ( $reqs as $req ) {
+ if ( $req->username !== null ) {
+ $user = User::newFromName( $req->username );
+ break;
+ }
+ }
+ if ( !$user ) {
+ $this->logger->debug( __METHOD__ . ': No username in $reqs, skipping hooks' );
+ return StatusValue::newGood();
+ }
+
+ // Something random for the 'AbortLogin' hook.
+ $password = wfRandomString( 32 );
+ }
+
+ $msg = null;
+ if ( !\Hooks::run( 'LoginUserMigrated', [ $user, &$msg ] ) ) {
+ return $this->makeFailResponse(
+ $user, null, LoginForm::USER_MIGRATED, $msg, 'LoginUserMigrated'
+ );
+ }
+
+ $abort = LoginForm::ABORTED;
+ $msg = null;
+ if ( !\Hooks::run( 'AbortLogin', [ $user, $password, &$abort, &$msg ] ) ) {
+ return $this->makeFailResponse( $user, null, $abort, $msg, 'AbortLogin' );
+ }
+
+ return StatusValue::newGood();
+ }
+
+ public function testForAccountCreation( $user, $creator, array $reqs ) {
+ $abortError = '';
+ $abortStatus = null;
+ if ( !\Hooks::run( 'AbortNewAccount', [ $user, &$abortError, &$abortStatus ] ) ) {
+ // Hook point to add extra creation throttles and blocks
+ $this->logger->debug( __METHOD__ . ': a hook blocked creation' );
+ if ( $abortStatus === null ) {
+ // Report back the old string as a raw message status.
+ // This will report the error back as 'createaccount-hook-aborted'
+ // with the given string as the message.
+ // To return a different error code, return a StatusValue object.
+ $msg = wfMessage( 'createaccount-hook-aborted' )->rawParams( $abortError );
+ return StatusValue::newFatal( $msg );
+ } else {
+ // For MediaWiki 1.23+ and updated hooks, return the Status object
+ // returned from the hook.
+ $ret = StatusValue::newGood();
+ $ret->merge( $abortStatus );
+ return $ret;
+ }
+ }
+
+ return StatusValue::newGood();
+ }
+
+ public function testUserForCreation( $user, $autocreate ) {
+ if ( $autocreate !== false ) {
+ $abortError = '';
+ if ( !\Hooks::run( 'AbortAutoAccount', [ $user, &$abortError ] ) ) {
+ // Hook point to add extra creation throttles and blocks
+ $this->logger->debug( __METHOD__ . ": a hook blocked auto-creation: $abortError\n" );
+ return $this->makeFailResponse(
+ $user, $user, LoginForm::ABORTED, $abortError, 'AbortAutoAccount'
+ );
+ }
+ } else {
+ $abortError = '';
+ $abortStatus = null;
+ if ( !\Hooks::run( 'AbortNewAccount', [ $user, &$abortError, &$abortStatus ] ) ) {
+ // Hook point to add extra creation throttles and blocks
+ $this->logger->debug( __METHOD__ . ': a hook blocked creation' );
+ if ( $abortStatus === null ) {
+ // Report back the old string as a raw message status.
+ // This will report the error back as 'createaccount-hook-aborted'
+ // with the given string as the message.
+ // To return a different error code, return a StatusValue object.
+ $msg = wfMessage( 'createaccount-hook-aborted' )->rawParams( $abortError );
+ return StatusValue::newFatal( $msg );
+ } else {
+ // For MediaWiki 1.23+ and updated hooks, return the Status object
+ // returned from the hook.
+ $ret = StatusValue::newGood();
+ $ret->merge( $abortStatus );
+ return $ret;
+ }
+ }
+ }
+
+ return StatusValue::newGood();
+ }
+
+ /**
+ * Construct an appropriate failure response
+ * @param User $user
+ * @param User|null $creator
+ * @param int $constant LoginForm constant
+ * @param string|null $msg Message
+ * @param string $hook Hook
+ * @return StatusValue
+ */
+ protected function makeFailResponse( $user, $creator, $constant, $msg, $hook ) {
+ switch ( $constant ) {
+ case LoginForm::SUCCESS:
+ // WTF?
+ $this->logger->debug( "$hook is SUCCESS?!" );
+ return StatusValue::newGood();
+
+ case LoginForm::NEED_TOKEN:
+ return StatusValue::newFatal( $msg ?: 'nocookiesforlogin' );
+
+ case LoginForm::WRONG_TOKEN:
+ return StatusValue::newFatal( $msg ?: 'sessionfailure' );
+
+ case LoginForm::NO_NAME:
+ case LoginForm::ILLEGAL:
+ return StatusValue::newFatal( $msg ?: 'noname' );
+
+ case LoginForm::WRONG_PLUGIN_PASS:
+ case LoginForm::WRONG_PASS:
+ return StatusValue::newFatal( $msg ?: 'wrongpassword' );
+
+ case LoginForm::NOT_EXISTS:
+ return StatusValue::newFatal( $msg ?: 'nosuchusershort', wfEscapeWikiText( $user->getName() ) );
+
+ case LoginForm::EMPTY_PASS:
+ return StatusValue::newFatal( $msg ?: 'wrongpasswordempty' );
+
+ case LoginForm::RESET_PASS:
+ return StatusValue::newFatal( $msg ?: 'resetpass_announce' );
+
+ case LoginForm::THROTTLED:
+ $throttle = $this->config->get( 'PasswordAttemptThrottle' );
+ return StatusValue::newFatal(
+ $msg ?: 'login-throttled',
+ \Message::durationParam( $throttle['seconds'] )
+ );
+
+ case LoginForm::USER_BLOCKED:
+ return StatusValue::newFatal(
+ $msg ?: 'login-userblocked', wfEscapeWikiText( $user->getName() )
+ );
+
+ case LoginForm::ABORTED:
+ return StatusValue::newFatal(
+ $msg ?: 'login-abort-generic', wfEscapeWikiText( $user->getName() )
+ );
+
+ case LoginForm::USER_MIGRATED:
+ $error = $msg ?: 'login-migrated-generic';
+ return call_user_func_array( 'StatusValue::newFatal', (array)$error );
+
+ // @codeCoverageIgnoreStart
+ case LoginForm::CREATE_BLOCKED: // Can never happen
+ default:
+ throw new \DomainException( __METHOD__ . ": Unhandled case value from $hook" );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use User;
+
+/**
+ * A primary authentication provider that uses the password field in the 'user' table.
+ * @ingroup Auth
+ * @since 1.27
+ */
+class LocalPasswordPrimaryAuthenticationProvider
+ extends AbstractPasswordPrimaryAuthenticationProvider
+{
+
+ /** @var bool If true, this instance is for legacy logins only. */
+ protected $loginOnly = false;
+
+ /**
+ * @param array $params Settings
+ * - loginOnly: If true, the local passwords are for legacy logins only:
+ * the local password will be invalidated when authentication is changed
+ * and new users will not have a valid local password set.
+ */
+ public function __construct( $params = [] ) {
+ parent::__construct( $params );
+ $this->loginOnly = !empty( $params['loginOnly'] );
+ }
+
+ protected function getPasswordResetData( $username, $row ) {
+ $now = wfTimestamp();
+ $expiration = wfTimestampOrNull( TS_UNIX, $row->user_password_expires );
+ if ( $expiration === null || $expiration >= $now ) {
+ return null;
+ }
+
+ $grace = $this->config->get( 'PasswordExpireGrace' );
+ if ( $expiration + $grace < $now ) {
+ $data = [
+ 'hard' => true,
+ 'msg' => \Status::newFatal( 'resetpass-expired' )->getMessage(),
+ ];
+ } else {
+ $data = [
+ 'hard' => false,
+ 'msg' => \Status::newFatal( 'resetpass-expired-soft' )->getMessage(),
+ ];
+ }
+
+ return (object)$data;
+ }
+
+ public function beginPrimaryAuthentication( array $reqs ) {
+ $req = AuthenticationRequest::getRequestByClass( $reqs, PasswordAuthenticationRequest::class );
+ if ( !$req ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ if ( $req->username === null || $req->password === null ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $username = User::getCanonicalName( $req->username, 'usable' );
+ if ( $username === false ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $fields = [
+ 'user_id', 'user_password', 'user_password_expires',
+ ];
+
+ $dbw = wfGetDB( DB_MASTER );
+ $row = $dbw->selectRow(
+ 'user',
+ $fields,
+ [ 'user_name' => $username ],
+ __METHOD__
+ );
+ if ( !$row ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ // 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}$/', $row->user_password ) ) {
+ if ( $this->config->get( 'PasswordSalt' ) ) {
+ $row->user_password = ":A:{$row->user_id}:{$row->user_password}";
+ } else {
+ $row->user_password = ":A:{$row->user_password}";
+ }
+ }
+
+ $status = $this->checkPasswordValidity( $username, $req->password );
+ if ( !$status->isOk() ) {
+ // Fatal, can't log in
+ return AuthenticationResponse::newFail( $status->getMessage() );
+ }
+
+ $pwhash = $this->getPassword( $row->user_password );
+ if ( !$pwhash->equals( $req->password ) ) {
+ if ( $this->config->get( 'LegacyEncoding' ) ) {
+ // 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', $req->password );
+ if ( $cp1252Password === $req->password || !$pwhash->equals( $cp1252Password ) ) {
+ return $this->failResponse( $req );
+ }
+ } else {
+ return $this->failResponse( $req );
+ }
+ }
+
+ // @codeCoverageIgnoreStart
+ if ( $this->getPasswordFactory()->needsUpdate( $pwhash ) ) {
+ $pwhash = $this->getPasswordFactory()->newFromPlaintext( $req->password );
+ $dbw->update(
+ 'user',
+ [ 'user_password' => $pwhash->toString() ],
+ [ 'user_id' => $row->user_id ],
+ __METHOD__
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $this->setPasswordResetFlag( $username, $status, $row );
+
+ return AuthenticationResponse::newPass( $username );
+ }
+
+ public function testUserCanAuthenticate( $username ) {
+ $username = User::getCanonicalName( $username, 'usable' );
+ if ( $username === false ) {
+ return false;
+ }
+
+ $dbw = wfGetDB( DB_MASTER );
+ $row = $dbw->selectRow(
+ 'user',
+ [ 'user_password' ],
+ [ 'user_name' => $username ],
+ __METHOD__
+ );
+ if ( !$row ) {
+ return false;
+ }
+
+ // 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}$/', $row->user_password ) ) {
+ return true;
+ }
+
+ return !$this->getPassword( $row->user_password ) instanceof \InvalidPassword;
+ }
+
+ public function testUserExists( $username, $flags = User::READ_NORMAL ) {
+ $username = User::getCanonicalName( $username, 'usable' );
+ if ( $username === false ) {
+ return false;
+ }
+
+ list( $db, $options ) = \DBAccessObjectUtils::getDBOptions( $flags );
+ return (bool)wfGetDB( $db )->selectField(
+ [ 'user' ],
+ [ 'user_id' ],
+ [ 'user_name' => $username ],
+ __METHOD__,
+ $options
+ );
+ }
+
+ public function providerAllowsAuthenticationDataChange(
+ AuthenticationRequest $req, $checkData = true
+ ) {
+ // We only want to blank the password if something else will accept the
+ // new authentication data, so return 'ignore' here.
+ if ( $this->loginOnly ) {
+ return \StatusValue::newGood( 'ignored' );
+ }
+
+ if ( get_class( $req ) === PasswordAuthenticationRequest::class ) {
+ if ( !$checkData ) {
+ return \StatusValue::newGood();
+ }
+
+ $username = User::getCanonicalName( $req->username, 'usable' );
+ if ( $username !== false ) {
+ $row = wfGetDB( DB_MASTER )->selectRow(
+ 'user',
+ [ 'user_id' ],
+ [ 'user_name' => $username ],
+ __METHOD__
+ );
+ if ( $row ) {
+ $sv = \StatusValue::newGood();
+ if ( $req->password !== null ) {
+ if ( $req->password !== $req->retype ) {
+ $sv->fatal( 'badretype' );
+ } else {
+ $sv->merge( $this->checkPasswordValidity( $username, $req->password ) );
+ }
+ }
+ return $sv;
+ }
+ }
+ }
+
+ return \StatusValue::newGood( 'ignored' );
+ }
+
+ public function providerChangeAuthenticationData( AuthenticationRequest $req ) {
+ $username = $req->username !== null ? User::getCanonicalName( $req->username, 'usable' ) : false;
+ if ( $username === false ) {
+ return;
+ }
+
+ $pwhash = null;
+
+ if ( $this->loginOnly ) {
+ $pwhash = $this->getPasswordFactory()->newFromCiphertext( null );
+ $expiry = null;
+ // @codeCoverageIgnoreStart
+ } elseif ( get_class( $req ) === PasswordAuthenticationRequest::class ) {
+ // @codeCoverageIgnoreEnd
+ $pwhash = $this->getPasswordFactory()->newFromPlaintext( $req->password );
+ $expiry = $this->getNewPasswordExpiry( $username );
+ }
+
+ if ( $pwhash ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update(
+ 'user',
+ [
+ 'user_password' => $pwhash->toString(),
+ 'user_password_expires' => $dbw->timestampOrNull( $expiry ),
+ ],
+ [ 'user_name' => $username ],
+ __METHOD__
+ );
+ }
+ }
+
+ public function accountCreationType() {
+ return $this->loginOnly ? self::TYPE_NONE : self::TYPE_CREATE;
+ }
+
+ public function testForAccountCreation( $user, $creator, array $reqs ) {
+ $req = AuthenticationRequest::getRequestByClass( $reqs, PasswordAuthenticationRequest::class );
+
+ $ret = \StatusValue::newGood();
+ if ( !$this->loginOnly && $req && $req->username !== null && $req->password !== null ) {
+ if ( $req->password !== $req->retype ) {
+ $ret->fatal( 'badretype' );
+ } else {
+ $ret->merge(
+ $this->checkPasswordValidity( $user->getName(), $req->password )
+ );
+ }
+ }
+ return $ret;
+ }
+
+ public function beginPrimaryAccountCreation( $user, $creator, array $reqs ) {
+ if ( $this->accountCreationType() === self::TYPE_NONE ) {
+ throw new \BadMethodCallException( 'Shouldn\'t call this when accountCreationType() is NONE' );
+ }
+
+ $req = AuthenticationRequest::getRequestByClass( $reqs, PasswordAuthenticationRequest::class );
+ if ( $req ) {
+ if ( $req->username !== null && $req->password !== null ) {
+ // Nothing we can do besides claim it, because the user isn't in
+ // the DB yet
+ if ( $req->username !== $user->getName() ) {
+ $req = clone( $req );
+ $req->username = $user->getName();
+ }
+ $ret = AuthenticationResponse::newPass( $req->username );
+ $ret->createRequest = $req;
+ return $ret;
+ }
+ }
+ return AuthenticationResponse::newAbstain();
+ }
+
+ public function finishAccountCreation( $user, $creator, AuthenticationResponse $res ) {
+ if ( $this->accountCreationType() === self::TYPE_NONE ) {
+ throw new \BadMethodCallException( 'Shouldn\'t call this when accountCreationType() is NONE' );
+ }
+
+ // Now that the user is in the DB, set the password on it.
+ $this->providerChangeAuthenticationData( $res->createRequest );
+
+ return null;
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+/**
+ * This is a value object for authentication requests with a username and password
+ * @ingroup Auth
+ * @since 1.27
+ */
+class PasswordAuthenticationRequest extends AuthenticationRequest {
+ /** @var string Password */
+ public $password = null;
+
+ /** @var string Password, again */
+ public $retype = null;
+
+ public function getFieldInfo() {
+ if ( $this->action === AuthManager::ACTION_REMOVE ) {
+ return [];
+ }
+
+ // for password change it's nice to make extra clear that we are asking for the new password
+ $forNewPassword = $this->action === AuthManager::ACTION_CHANGE;
+ $passwordLabel = $forNewPassword ? 'newpassword' : 'userlogin-yourpassword';
+ $retypeLabel = $forNewPassword ? 'retypenew' : 'yourpasswordagain';
+
+ $ret = [
+ 'username' => [
+ 'type' => 'string',
+ 'label' => wfMessage( 'userlogin-yourname' ),
+ 'help' => wfMessage( 'authmanager-username-help' ),
+ ],
+ 'password' => [
+ 'type' => 'password',
+ 'label' => wfMessage( $passwordLabel ),
+ 'help' => wfMessage( 'authmanager-password-help' ),
+ ],
+ ];
+
+ switch ( $this->action ) {
+ case AuthManager::ACTION_CHANGE:
+ case AuthManager::ACTION_REMOVE:
+ unset( $ret['username'] );
+ break;
+ }
+
+ if ( $this->action !== AuthManager::ACTION_LOGIN ) {
+ $ret['retype'] = [
+ 'type' => 'password',
+ 'label' => wfMessage( $retypeLabel ),
+ 'help' => wfMessage( 'authmanager-retype-help' ),
+ ];
+ }
+
+ return $ret;
+ }
+
+ public function describeCredentials() {
+ return [
+ 'provider' => wfMessage( 'authmanager-provider-password' ),
+ 'account' => new \RawMessage( '$1', [ $this->username ] ),
+ ];
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+/**
+ * This is a value object for authentication requests with a username, password, and domain
+ * @ingroup Auth
+ * @since 1.27
+ */
+class PasswordDomainAuthenticationRequest extends PasswordAuthenticationRequest {
+ /** @var string[] Domains available */
+ private $domainList;
+
+ /** @var string Domain */
+ public $domain = null;
+
+ /**
+ * @param string[] $domainList List of available domains
+ */
+ public function __construct( array $domainList ) {
+ $this->domainList = $domainList;
+ }
+
+ public function getFieldInfo() {
+ $ret = parent::getFieldInfo();
+
+ // Only add a domain field if we have the username field included
+ if ( isset( $ret['username'] ) ) {
+ $ret['domain'] = [
+ 'type' => 'select',
+ 'options' => [],
+ 'label' => wfMessage( 'yourdomainname' ),
+ 'help' => wfMessage( 'authmanager-domain-help' ),
+ ];
+ foreach ( $this->domainList as $domain ) {
+ $ret['domain']['options'][$domain] = new \RawMessage( '$1', [ $domain ] );
+ }
+ }
+
+ return $ret;
+ }
+
+ public function describeCredentials() {
+ return [
+ 'provider' => wfMessage( 'authmanager-provider-password-domain' ),
+ 'account' => wfMessage(
+ 'authmanager-account-password-domain', [ $this->username, $this->domain ]
+ ),
+ ];
+ }
+
+ /**
+ * @codeCoverageIgnore
+ */
+ public static function __set_state( $data ) {
+ $ret = new static( $data['domainList'] );
+ foreach ( $data as $k => $v ) {
+ if ( $k !== 'domainList' ) {
+ $ret->$k = $v;
+ }
+ }
+ return $ret;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Pre-authentication provider interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use StatusValue;
+use User;
+
+/**
+ * A pre-authentication provider is a check that must pass for authentication
+ * to proceed.
+ *
+ * A PreAuthenticationProvider is used to supply arbitrary checks to be
+ * performed before the PrimaryAuthenticationProviders are consulted during the
+ * login process. Possible uses include checking that a per-IP throttle has not
+ * been reached or that a captcha has been solved.
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+interface PreAuthenticationProvider extends AuthenticationProvider {
+
+ /**
+ * Determine whether an authentication may begin
+ *
+ * Called from AuthManager::beginAuthentication()
+ *
+ * @param AuthenticationRequest[] $reqs
+ * @return StatusValue
+ */
+ public function testForAuthentication( array $reqs );
+
+ /**
+ * Post-login callback
+ * @param User|null $user User that was attempted to be logged in, if known.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param AuthenticationResponse $response Authentication response that will be returned
+ */
+ public function postAuthentication( $user, AuthenticationResponse $response );
+
+ /**
+ * Determine whether an account creation may begin
+ *
+ * Called from AuthManager::beginAccountCreation()
+ *
+ * @note No need to test if the account exists, AuthManager checks that
+ * @param User $user User being created (not added to the database yet).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return StatusValue
+ */
+ public function testForAccountCreation( $user, $creator, array $reqs );
+
+ /**
+ * Determine whether an account may be created
+ *
+ * @param User $user User being created (not added to the database yet).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param bool|string $autocreate False if this is not an auto-creation, or
+ * the source of the auto-creation passed to AuthManager::autoCreateUser().
+ * @return StatusValue
+ */
+ public function testUserForCreation( $user, $autocreate );
+
+ /**
+ * Post-creation callback
+ * @param User $user User that was attempted to be created.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationResponse $response Authentication response that will be returned
+ */
+ public function postAccountCreation( $user, $creator, AuthenticationResponse $response );
+
+ /**
+ * Determine whether an account may linked to another authentication method
+ *
+ * @param User $user User being linked.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @return StatusValue
+ */
+ public function testForAccountLink( $user );
+
+ /**
+ * Post-link callback
+ * @param User $user User that was attempted to be linked.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param AuthenticationResponse $response Authentication response that will be returned
+ */
+ public function postAccountLink( $user, AuthenticationResponse $response );
+
+}
--- /dev/null
+<?php
+/**
+ * Primary authentication provider interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use StatusValue;
+use User;
+
+/**
+ * A primary authentication provider determines which user is trying to log in.
+ *
+ * A PrimaryAuthenticationProvider is used as part of presenting a login form
+ * to authenticate a user. In particular, the PrimaryAuthenticationProvider
+ * takes form data and determines the authenticated user (if any) corresponds
+ * to that form data. It might do this on the basis of a username and password
+ * in that data, or by interacting with an external authentication service
+ * (e.g. using OpenID), or by some other mechanism.
+ *
+ * A PrimaryAuthenticationProvider would not be appropriate for something like
+ * HTTP authentication, OAuth, or SSL client certificates where each HTTP
+ * request contains all the information needed to identify the user. In that
+ * case you'll want to be looking at a \\MediaWiki\\Session\\SessionProvider
+ * instead.
+ *
+ * This interface also provides methods for changing authentication data such
+ * as passwords and for creating new users who can later be authenticated with
+ * this provider.
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+interface PrimaryAuthenticationProvider extends AuthenticationProvider {
+ /** Provider can create accounts */
+ const TYPE_CREATE = 'create';
+ /** Provider can link to existing accounts elsewhere */
+ const TYPE_LINK = 'link';
+ /** Provider cannot create or link to accounts */
+ const TYPE_NONE = 'none';
+
+ /**
+ * Start an authentication flow
+ *
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user is authenticated. Secondary providers will now run.
+ * - FAIL: The user is not authenticated. Fail the authentication process.
+ * - ABSTAIN: These $reqs are not handled. Some other primary provider may handle it.
+ * - UI: The $reqs are accepted, no other primary provider will run.
+ * Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: The $reqs are accepted, no other primary provider will run.
+ * Redirection to a third party is needed to complete the process.
+ */
+ public function beginPrimaryAuthentication( array $reqs );
+
+ /**
+ * Continue an authentication flow
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user is authenticated. Secondary providers will now run.
+ * - FAIL: The user is not authenticated. Fail the authentication process.
+ * - UI: Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: Redirection to a third party is needed to complete the process.
+ */
+ public function continuePrimaryAuthentication( array $reqs );
+
+ /**
+ * Post-login callback
+ * @param User|null $user User that was attempted to be logged in, if known.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param AuthenticationResponse $response Authentication response that will be returned
+ */
+ public function postAuthentication( $user, AuthenticationResponse $response );
+
+ /**
+ * Test whether the named user exists
+ * @param string $username
+ * @param int $flags Bitfield of User:READ_* constants
+ * @return bool
+ */
+ public function testUserExists( $username, $flags = User::READ_NORMAL );
+
+ /**
+ * Test whether the named user can authenticate with this provider
+ * @param string $username
+ * @return bool
+ */
+ public function testUserCanAuthenticate( $username );
+
+ /**
+ * Normalize the username for authentication
+ *
+ * Any two inputs that would result in the same user being authenticated
+ * should return the same string here, while inputs that would result in
+ * different users should return different strings.
+ *
+ * If possible, the best thing to do here is to return the canonicalized
+ * name of the local user account that would be used. If not, return
+ * something that would be invalid as a local username (e.g. wrap an email
+ * address in "<>", or append "#servicename" to the username passed to a
+ * third-party service).
+ *
+ * If the provider doesn't use a username at all in its
+ * AuthenticationRequests, return null. If the name is syntactically
+ * invalid, it's probably best to return null.
+ *
+ * @param string $username
+ * @return string|null
+ */
+ public function providerNormalizeUsername( $username );
+
+ /**
+ * Revoke the user's credentials
+ *
+ * This may cause the user to no longer exist for the provider, or the user
+ * may continue to exist in a "disabled" state.
+ *
+ * The intention is that the named account will never again be usable for
+ * normal login (i.e. there is no way to undo the revocation of access).
+ *
+ * @param string $username
+ */
+ public function providerRevokeAccessForUser( $username );
+
+ /**
+ * Determine whether a property can change
+ * @see AuthManager::allowsPropertyChange()
+ * @param string $property
+ * @return bool
+ */
+ public function providerAllowsPropertyChange( $property );
+
+ /**
+ * Validate a change of authentication data (e.g. passwords)
+ *
+ * Return StatusValue::newGood( 'ignored' ) if you don't support this
+ * AuthenticationRequest type.
+ *
+ * @param AuthenticationRequest $req
+ * @param bool $checkData If false, $req hasn't been loaded from the
+ * submission so checks on user-submitted fields should be skipped.
+ * $req->username is considered user-submitted for this purpose, even
+ * if it cannot be changed via $req->loadFromSubmission.
+ * @return StatusValue
+ */
+ public function providerAllowsAuthenticationDataChange(
+ AuthenticationRequest $req, $checkData = true
+ );
+
+ /**
+ * Change or remove authentication data (e.g. passwords)
+ *
+ * If $req was returned for AuthManager::ACTION_CHANGE, the corresponding
+ * credentials should result in a successful login in the future.
+ *
+ * If $req was returned for AuthManager::ACTION_REMOVE, the corresponding
+ * credentials should no longer result in a successful login.
+ *
+ * @param AuthenticationRequest $req
+ */
+ public function providerChangeAuthenticationData( AuthenticationRequest $req );
+
+ /**
+ * Fetch the account-creation type
+ * @return string One of the TYPE_* constants
+ */
+ public function accountCreationType();
+
+ /**
+ * Determine whether an account creation may begin
+ *
+ * Called from AuthManager::beginAccountCreation()
+ *
+ * @note No need to test if the account exists, AuthManager checks that
+ * @param User $user User being created (not added to the database yet).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return StatusValue
+ */
+ public function testForAccountCreation( $user, $creator, array $reqs );
+
+ /**
+ * Start an account creation flow
+ * @param User $user User being created (not added to the database yet).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user may be created. Secondary providers will now run.
+ * - FAIL: The user may not be created. Fail the creation process.
+ * - ABSTAIN: These $reqs are not handled. Some other primary provider may handle it.
+ * - UI: The $reqs are accepted, no other primary provider will run.
+ * Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: The $reqs are accepted, no other primary provider will run.
+ * Redirection to a third party is needed to complete the process.
+ */
+ public function beginPrimaryAccountCreation( $user, $creator, array $reqs );
+
+ /**
+ * Continue an account creation flow
+ * @param User $user User being created (not added to the database yet).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user may be created. Secondary providers will now run.
+ * - FAIL: The user may not be created. Fail the creation process.
+ * - UI: Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: Redirection to a third party is needed to complete the process.
+ */
+ public function continuePrimaryAccountCreation( $user, $creator, array $reqs );
+
+ /**
+ * Post-creation callback
+ *
+ * Called after the user is added to the database, before secondary
+ * authentication providers are run.
+ *
+ * @param User $user User being created (has been added to the database now).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationResponse $response PASS response returned earlier
+ * @return string|null 'newusers' log subtype to use for logging the
+ * account creation. If null, either 'create' or 'create2' will be used
+ * depending on $creator.
+ */
+ public function finishAccountCreation( $user, $creator, AuthenticationResponse $response );
+
+ /**
+ * Post-creation callback
+ *
+ * Called when the account creation process ends.
+ *
+ * @param User $user User that was attempted to be created.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationResponse $response Authentication response that will be returned
+ */
+ public function postAccountCreation( $user, $creator, AuthenticationResponse $response );
+
+ /**
+ * Determine whether an account may be created
+ *
+ * @param User $user User being created (not added to the database yet).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param bool|string $autocreate False if this is not an auto-creation, or
+ * the source of the auto-creation passed to AuthManager::autoCreateUser().
+ * @return StatusValue
+ */
+ public function testUserForCreation( $user, $autocreate );
+
+ /**
+ * Post-auto-creation callback
+ * @param User $user User being created (has been added to the database now).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param string $source The source of the auto-creation passed to
+ * AuthManager::autoCreateUser().
+ */
+ public function autoCreatedAccount( $user, $source );
+
+ /**
+ * Start linking an account to an existing user
+ * @param User $user User being linked.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user is linked.
+ * - FAIL: The user is not linked. Fail the linking process.
+ * - ABSTAIN: These $reqs are not handled. Some other primary provider may handle it.
+ * - UI: The $reqs are accepted, no other primary provider will run.
+ * Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: The $reqs are accepted, no other primary provider will run.
+ * Redirection to a third party is needed to complete the process.
+ */
+ public function beginPrimaryAccountLink( $user, array $reqs );
+
+ /**
+ * Continue linking an account to an existing user
+ * @param User $user User being linked.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user is linked.
+ * - FAIL: The user is not linked. Fail the linking process.
+ * - UI: Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: Redirection to a third party is needed to complete the process.
+ */
+ public function continuePrimaryAccountLink( $user, array $reqs );
+
+ /**
+ * Post-link callback
+ * @param User $user User that was attempted to be linked.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param AuthenticationResponse $response Authentication response that will be returned
+ */
+ public function postAccountLink( $user, AuthenticationResponse $response );
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use MediaWiki\Session\SessionManager;
+use MediaWiki\Session\SessionProvider;
+
+/**
+ * This is an authentication request added by AuthManager to show a "remember
+ * me" checkbox. When checked, it will take more time for the authenticated session to expire.
+ * @ingroup Auth
+ * @since 1.27
+ */
+class RememberMeAuthenticationRequest extends AuthenticationRequest {
+
+ public $required = self::OPTIONAL;
+
+ /** @var int How long the user will be remembered, in seconds */
+ protected $expiration = null;
+
+ /** @var bool */
+ public $rememberMe = false;
+
+ public function __construct() {
+ /** @var SessionProvider $provider */
+ $provider = SessionManager::getGlobalSession()->getProvider();
+ $this->expiration = $provider->getRememberUserDuration();
+ }
+
+ public function getFieldInfo() {
+ if ( !$this->expiration ) {
+ return [];
+ }
+
+ $expirationDays = ceil( $this->expiration / ( 3600 * 24 ) );
+ return [
+ 'rememberMe' => [
+ 'type' => 'checkbox',
+ 'label' => wfMessage( 'userlogin-remembermypassword' )->numParams( $expirationDays ),
+ 'help' => wfMessage( 'authmanager-userlogin-remembermypassword-help' ),
+ 'optional' => true,
+ ]
+ ];
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+/**
+ * Reset the local password, if signalled via $this->manager->setAuthenticationSessionData()
+ *
+ * The authentication data key is 'reset-pass'; the data is an object with the
+ * following properties:
+ * - msg: Message object to display to the user
+ * - hard: Boolean, if true the reset cannot be skipped.
+ * - req: Optional PasswordAuthenticationRequest to use to actually reset the
+ * password. Won't be displayed to the user.
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+class ResetPasswordSecondaryAuthenticationProvider extends AbstractSecondaryAuthenticationProvider {
+
+ public function getAuthenticationRequests( $action, array $options ) {
+ return [];
+ }
+
+ public function beginSecondaryAuthentication( $user, array $reqs ) {
+ return $this->tryReset( $user, $reqs );
+ }
+
+ public function continueSecondaryAuthentication( $user, array $reqs ) {
+ return $this->tryReset( $user, $reqs );
+ }
+
+ public function beginSecondaryAccountCreation( $user, $creator, array $reqs ) {
+ return $this->tryReset( $user, $reqs );
+ }
+
+ public function continueSecondaryAccountCreation( $user, $creator, array $reqs ) {
+ return $this->tryReset( $user, $reqs );
+ }
+
+ /**
+ * Try to reset the password
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse
+ */
+ protected function tryReset( \User $user, array $reqs ) {
+ $data = $this->manager->getAuthenticationSessionData( 'reset-pass' );
+ if ( !$data ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ if ( is_array( $data ) ) {
+ $data = (object)$data;
+ }
+ if ( !is_object( $data ) ) {
+ throw new \UnexpectedValueException( 'reset-pass is not valid' );
+ }
+
+ if ( !isset( $data->msg ) ) {
+ throw new \UnexpectedValueException( 'reset-pass msg is missing' );
+ } elseif ( !$data->msg instanceof \Message ) {
+ throw new \UnexpectedValueException( 'reset-pass msg is not valid' );
+ } elseif ( !isset( $data->hard ) ) {
+ throw new \UnexpectedValueException( 'reset-pass hard is missing' );
+ } elseif ( isset( $data->req ) && (
+ !$data->req instanceof PasswordAuthenticationRequest ||
+ !array_key_exists( 'retype', $data->req->getFieldInfo() )
+ ) ) {
+ throw new \UnexpectedValueException( 'reset-pass req is not valid' );
+ }
+
+ if ( !$data->hard ) {
+ $req = ButtonAuthenticationRequest::getRequestByName( $reqs, 'skipReset' );
+ if ( $req ) {
+ $this->manager->removeAuthenticationSessionData( 'reset-pass' );
+ return AuthenticationResponse::newPass();
+ }
+ }
+
+ $needReq = isset( $data->req ) ? $data->req : new PasswordAuthenticationRequest();
+ if ( !$needReq->action ) {
+ $needReq->action = AuthManager::ACTION_CHANGE;
+ }
+ $needReq->required = $data->hard ? AuthenticationRequest::REQUIRED
+ : AuthenticationRequest::OPTIONAL;
+ $needReqs = [ $needReq ];
+ if ( !$data->hard ) {
+ $needReqs[] = new ButtonAuthenticationRequest(
+ 'skipReset',
+ wfMessage( 'authprovider-resetpass-skip-label' ),
+ wfMessage( 'authprovider-resetpass-skip-help' )
+ );
+ }
+
+ $req = AuthenticationRequest::getRequestByClass( $reqs, get_class( $needReq ) );
+ if ( !$req || !array_key_exists( 'retype', $req->getFieldInfo() ) ) {
+ return AuthenticationResponse::newUI( $needReqs, $data->msg );
+ }
+
+ if ( $req->password !== $req->retype ) {
+ return AuthenticationResponse::newUI( $needReqs, new \Message( 'badretype' ) );
+ }
+
+ $req->username = $user->getName();
+ $status = $this->manager->allowsAuthenticationDataChange( $req );
+ if ( !$status->isGood() ) {
+ return AuthenticationResponse::newUI( $needReqs, $status->getMessage() );
+ }
+ $this->manager->changeAuthenticationData( $req );
+
+ $this->manager->removeAuthenticationSessionData( 'reset-pass' );
+ return AuthenticationResponse::newPass();
+ }
+}
--- /dev/null
+<?php
+/**
+ * Secondary authentication provider interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use StatusValue;
+use User;
+
+/**
+ * A secondary authentication provider performs additional authentication steps
+ * after a PrimaryAuthenticationProvider has done its thing.
+ *
+ * A SecondaryAuthenticationProvider is used to perform arbitrary checks on an
+ * authentication request after the user itself has been authenticated. For
+ * example, it might implement a password reset, request the second factor for
+ * two-factor auth, or prevent the login if the account is blocked.
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+interface SecondaryAuthenticationProvider extends AuthenticationProvider {
+
+ /**
+ * Start an authentication flow
+ *
+ * Note that this may be called for a user even if
+ * beginSecondaryAccountCreation() was never called. The module should take
+ * the opportunity to do any necessary setup in that case.
+ *
+ * @param User $user User being authenticated. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user is authenticated. Additional secondary providers may run.
+ * - FAIL: The user is not authenticated. Fail the authentication process.
+ * - ABSTAIN: Additional secondary providers may run.
+ * - UI: Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: Redirection to a third party is needed to complete the process.
+ */
+ public function beginSecondaryAuthentication( $user, array $reqs );
+
+ /**
+ * Continue an authentication flow
+ * @param User $user User being authenticated. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user is authenticated. Additional secondary providers may run.
+ * - FAIL: The user is not authenticated. Fail the authentication process.
+ * - ABSTAIN: Additional secondary providers may run.
+ * - UI: Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: Redirection to a third party is needed to complete the process.
+ */
+ public function continueSecondaryAuthentication( $user, array $reqs );
+
+ /**
+ * Post-login callback
+ * @param User|null $user User that was attempted to be logged in, if known.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param AuthenticationResponse $response Authentication response that will be returned
+ */
+ public function postAuthentication( $user, AuthenticationResponse $response );
+
+ /**
+ * Revoke the user's credentials
+ *
+ * This may cause the user to no longer exist for the provider, or the user
+ * may continue to exist in a "disabled" state.
+ *
+ * The intention is that the named account will never again be usable for
+ * normal login (i.e. there is no way to undo the revocation of access).
+ *
+ * @param string $username
+ */
+ public function providerRevokeAccessForUser( $username );
+
+ /**
+ * Determine whether a property can change
+ * @see AuthManager::allowsPropertyChange()
+ * @param string $property
+ * @return bool
+ */
+ public function providerAllowsPropertyChange( $property );
+
+ /**
+ * Validate a change of authentication data (e.g. passwords)
+ *
+ * Return StatusValue::newGood( 'ignored' ) if you don't support this
+ * AuthenticationRequest type.
+ *
+ * @param AuthenticationRequest $req
+ * @param bool $checkData If false, $req hasn't been loaded from the
+ * submission so checks on user-submitted fields should be skipped.
+ * $req->username is considered user-submitted for this purpose, even
+ * if it cannot be changed via $req->loadFromSubmission.
+ * @return StatusValue
+ */
+ public function providerAllowsAuthenticationDataChange(
+ AuthenticationRequest $req, $checkData = true
+ );
+
+ /**
+ * Change or remove authentication data (e.g. passwords)
+ *
+ * If $req was returned for AuthManager::ACTION_CHANGE, the corresponding
+ * credentials should result in a successful login in the future.
+ *
+ * If $req was returned for AuthManager::ACTION_REMOVE, the corresponding
+ * credentials should no longer result in a successful login.
+ *
+ * @param AuthenticationRequest $req
+ */
+ public function providerChangeAuthenticationData( AuthenticationRequest $req );
+
+ /**
+ * Determine whether an account creation may begin
+ *
+ * Called from AuthManager::beginAccountCreation()
+ *
+ * @note No need to test if the account exists, AuthManager checks that
+ * @param User $user User being created (not added to the database yet).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return StatusValue
+ */
+ public function testForAccountCreation( $user, $creator, array $reqs );
+
+ /**
+ * Start an account creation flow
+ * @param User $user User being created (has been added to the database).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user creation is ok. Additional secondary providers may run.
+ * - ABSTAIN: Additional secondary providers may run.
+ * - UI: Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: Redirection to a third party is needed to complete the process.
+ */
+ public function beginSecondaryAccountCreation( $user, $creator, array $reqs );
+
+ /**
+ * Continue an authentication flow
+ * @param User $user User being created (has been added to the database).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationRequest[] $reqs
+ * @return AuthenticationResponse Expected responses:
+ * - PASS: The user creation is ok. Additional secondary providers may run.
+ * - ABSTAIN: Additional secondary providers may run.
+ * - UI: Additional AuthenticationRequests are needed to complete the process.
+ * - REDIRECT: Redirection to a third party is needed to complete the process.
+ */
+ public function continueSecondaryAccountCreation( $user, $creator, array $reqs );
+
+ /**
+ * Post-creation callback
+ * @param User $user User that was attempted to be created.
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param User $creator User doing the creation. This may become a
+ * "UserValue" in the future, or User may be refactored into such.
+ * @param AuthenticationResponse $response Authentication response that will be returned
+ */
+ public function postAccountCreation( $user, $creator, AuthenticationResponse $response );
+
+ /**
+ * Determine whether an account may be created
+ *
+ * @param User $user User being created (not added to the database yet).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param bool|string $autocreate False if this is not an auto-creation, or
+ * the source of the auto-creation passed to AuthManager::autoCreateUser().
+ * @return StatusValue
+ */
+ public function testUserForCreation( $user, $autocreate );
+
+ /**
+ * Post-auto-creation callback
+ * @param User $user User being created (has been added to the database now).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @param string $source The source of the auto-creation passed to
+ * AuthManager::autoCreateUser().
+ */
+ public function autoCreatedAccount( $user, $source );
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+/**
+ * This represents the intention to set a temporary password for the user.
+ * @ingroup Auth
+ * @since 1.27
+ */
+class TemporaryPasswordAuthenticationRequest extends AuthenticationRequest {
+ /** @var string|null Temporary password */
+ public $password;
+
+ /** @var bool Email password to the user. */
+ public $mailpassword = false;
+
+ /**
+ * @var bool Do not fail certain operations if the password cannot be mailed, there is a
+ * backchannel present.
+ */
+ public $hasBackchannel = false;
+
+ /** @var string Username or IP address of the caller */
+ public $caller;
+
+ public function getFieldInfo() {
+ return [
+ 'mailpassword' => [
+ 'type' => 'checkbox',
+ 'label' => wfMessage( 'createaccountmail' ),
+ 'help' => wfMessage( 'createaccountmail-help' ),
+ ],
+ ];
+ }
+
+ /**
+ * @param string|null $password
+ */
+ public function __construct( $password = null ) {
+ $this->password = $password;
+ if ( $password ) {
+ $this->mailpassword = true;
+ }
+ }
+
+ /**
+ * Return an instance with a new, random password
+ * @return TemporaryPasswordAuthenticationRequest
+ */
+ public static function newRandom() {
+ $config = \ConfigFactory::getDefaultInstance()->makeConfig( 'main' );
+
+ // get the min password length
+ $minLength = $config->get( 'MinimalPasswordLength' );
+ $policy = $config->get( 'PasswordPolicy' );
+ foreach ( $policy['policies'] as $p ) {
+ if ( isset( $p['MinimalPasswordLength'] ) ) {
+ $minLength = max( $minLength, $p['MinimalPasswordLength'] );
+ }
+ if ( isset( $p['MinimalPasswordLengthToLogin'] ) ) {
+ $minLength = max( $minLength, $p['MinimalPasswordLengthToLogin'] );
+ }
+ }
+
+ $password = \PasswordFactory::generateRandomPasswordString( $minLength );
+
+ return new self( $password );
+ }
+
+ /**
+ * Return an instance with an invalid password
+ * @return TemporaryPasswordAuthenticationRequest
+ */
+ public static function newInvalid() {
+ $request = new self( null );
+ return $request;
+ }
+
+ public function describeCredentials() {
+ return [
+ 'provider' => wfMessage( 'authmanager-provider-temporarypassword' ),
+ 'account' => new \RawMessage( '$1', [ $this->username ] ),
+ ] + parent::describeCredentials();
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use User;
+
+/**
+ * A primary authentication provider that uses the temporary password field in
+ * the 'user' table.
+ *
+ * A successful login will force a password reset.
+ *
+ * @note For proper operation, this should generally come before any other
+ * password-based authentication providers.
+ * @ingroup Auth
+ * @since 1.27
+ */
+class TemporaryPasswordPrimaryAuthenticationProvider
+ extends AbstractPasswordPrimaryAuthenticationProvider
+{
+ /** @var bool */
+ protected $emailEnabled = null;
+
+ /** @var int */
+ protected $newPasswordExpiry = null;
+
+ /** @var int */
+ protected $passwordReminderResendTime = null;
+
+ /**
+ * @param array $params
+ * - emailEnabled: (bool) must be true for the option to email passwords to be present
+ * - newPasswordExpiry: (int) expiraton time of temporary passwords, in seconds
+ * - passwordReminderResendTime: (int) cooldown period in hours until a password reminder can
+ * be sent to the same user again,
+ */
+ public function __construct( $params = [] ) {
+ parent::__construct( $params );
+
+ if ( isset( $params['emailEnabled'] ) ) {
+ $this->emailEnabled = (bool)$params['emailEnabled'];
+ }
+ if ( isset( $params['newPasswordExpiry'] ) ) {
+ $this->newPasswordExpiry = (int)$params['newPasswordExpiry'];
+ }
+ if ( isset( $params['passwordReminderResendTime'] ) ) {
+ $this->passwordReminderResendTime = $params['passwordReminderResendTime'];
+ }
+ }
+
+ public function setConfig( \Config $config ) {
+ parent::setConfig( $config );
+
+ if ( $this->emailEnabled === null ) {
+ $this->emailEnabled = $this->config->get( 'EnableEmail' );
+ }
+ if ( $this->newPasswordExpiry === null ) {
+ $this->newPasswordExpiry = $this->config->get( 'NewPasswordExpiry' );
+ }
+ if ( $this->passwordReminderResendTime === null ) {
+ $this->passwordReminderResendTime = $this->config->get( 'PasswordReminderResendTime' );
+ }
+ }
+
+ protected function getPasswordResetData( $username, $data ) {
+ // Always reset
+ return (object)[
+ 'msg' => wfMessage( 'resetpass-temp-emailed' ),
+ 'hard' => true,
+ ];
+ }
+
+ public function getAuthenticationRequests( $action, array $options ) {
+ switch ( $action ) {
+ case AuthManager::ACTION_LOGIN:
+ return [ new PasswordAuthenticationRequest() ];
+
+ case AuthManager::ACTION_CHANGE:
+ return [ TemporaryPasswordAuthenticationRequest::newRandom() ];
+
+ case AuthManager::ACTION_CREATE:
+ if ( isset( $options['username'] ) && $this->emailEnabled ) {
+ // Creating an account for someone else
+ return [ TemporaryPasswordAuthenticationRequest::newRandom() ];
+ } else {
+ // It's not terribly likely that an anonymous user will
+ // be creating an account for someone else.
+ return [];
+ }
+
+ case AuthManager::ACTION_REMOVE:
+ return [ new TemporaryPasswordAuthenticationRequest ];
+
+ default:
+ return [];
+ }
+ }
+
+ public function beginPrimaryAuthentication( array $reqs ) {
+ $req = AuthenticationRequest::getRequestByClass( $reqs, PasswordAuthenticationRequest::class );
+ if ( !$req || $req->username === null || $req->password === null ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $username = User::getCanonicalName( $req->username, 'usable' );
+ if ( $username === false ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $dbw = wfGetDB( DB_MASTER );
+ $row = $dbw->selectRow(
+ 'user',
+ [
+ 'user_id', 'user_newpassword', 'user_newpass_time',
+ ],
+ [ 'user_name' => $username ],
+ __METHOD__
+ );
+ if ( !$row ) {
+ return AuthenticationResponse::newAbstain();
+ }
+
+ $status = $this->checkPasswordValidity( $username, $req->password );
+ if ( !$status->isOk() ) {
+ // Fatal, can't log in
+ return AuthenticationResponse::newFail( $status->getMessage() );
+ }
+
+ $pwhash = $this->getPassword( $row->user_newpassword );
+ if ( !$pwhash->equals( $req->password ) ) {
+ return $this->failResponse( $req );
+ }
+
+ if ( !$this->isTimestampValid( $row->user_newpass_time ) ) {
+ return $this->failResponse( $req );
+ }
+
+ $this->setPasswordResetFlag( $username, $status );
+
+ return AuthenticationResponse::newPass( $username );
+ }
+
+ public function testUserCanAuthenticate( $username ) {
+ $username = User::getCanonicalName( $username, 'usable' );
+ if ( $username === false ) {
+ return false;
+ }
+
+ $dbw = wfGetDB( DB_MASTER );
+ $row = $dbw->selectRow(
+ 'user',
+ [ 'user_newpassword', 'user_newpass_time' ],
+ [ 'user_name' => $username ],
+ __METHOD__
+ );
+ if ( !$row ) {
+ return false;
+ }
+
+ if ( $this->getPassword( $row->user_newpassword ) instanceof \InvalidPassword ) {
+ return false;
+ }
+
+ if ( !$this->isTimestampValid( $row->user_newpass_time ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function testUserExists( $username, $flags = User::READ_NORMAL ) {
+ $username = User::getCanonicalName( $username, 'usable' );
+ if ( $username === false ) {
+ return false;
+ }
+
+ list( $db, $options ) = \DBAccessObjectUtils::getDBOptions( $flags );
+ return (bool)wfGetDB( $db )->selectField(
+ [ 'user' ],
+ [ 'user_id' ],
+ [ 'user_name' => $username ],
+ __METHOD__,
+ $options
+ );
+ }
+
+ public function providerAllowsAuthenticationDataChange(
+ AuthenticationRequest $req, $checkData = true
+ ) {
+ if ( get_class( $req ) !== TemporaryPasswordAuthenticationRequest::class ) {
+ // We don't really ignore it, but this is what the caller expects.
+ return \StatusValue::newGood( 'ignored' );
+ }
+
+ if ( !$checkData ) {
+ return \StatusValue::newGood();
+ }
+
+ $username = User::getCanonicalName( $req->username, 'usable' );
+ if ( $username === false ) {
+ return \StatusValue::newGood( 'ignored' );
+ }
+
+ $row = wfGetDB( DB_MASTER )->selectRow(
+ 'user',
+ [ 'user_id', 'user_newpass_time' ],
+ [ 'user_name' => $username ],
+ __METHOD__
+ );
+
+ if ( !$row ) {
+ return \StatusValue::newGood( 'ignored' );
+ }
+
+ $sv = \StatusValue::newGood();
+ if ( $req->password !== null ) {
+ $sv->merge( $this->checkPasswordValidity( $username, $req->password ) );
+
+ if ( $req->mailpassword ) {
+ if ( !$this->emailEnabled && !$req->hasBackchannel ) {
+ return \StatusValue::newFatal( 'passwordreset-emaildisabled' );
+ }
+
+ // We don't check whether the user has an email address;
+ // that information should not be exposed to the caller.
+
+ // do not allow temporary password creation within
+ // $wgPasswordReminderResendTime from the last attempt
+ if (
+ $this->passwordReminderResendTime
+ && $row->user_newpass_time
+ && time() < wfTimestamp( TS_UNIX, $row->user_newpass_time )
+ + $this->passwordReminderResendTime * 3600
+ ) {
+ // Round the time in hours to 3 d.p., in case someone is specifying
+ // minutes or seconds.
+ return \StatusValue::newFatal( 'throttled-mailpassword',
+ round( $this->passwordReminderResendTime, 3 ) );
+ }
+
+ if ( !$req->caller ) {
+ return \StatusValue::newFatal( 'passwordreset-nocaller' );
+ }
+ if ( !\IP::isValid( $req->caller ) ) {
+ $caller = User::newFromName( $req->caller );
+ if ( !$caller ) {
+ return \StatusValue::newFatal( 'passwordreset-nosuchcaller', $req->caller );
+ }
+ }
+ }
+ }
+ return $sv;
+ }
+
+ public function providerChangeAuthenticationData( AuthenticationRequest $req ) {
+ $username = $req->username !== null ? User::getCanonicalName( $req->username, 'usable' ) : false;
+ if ( $username === false ) {
+ return;
+ }
+
+ $dbw = wfGetDB( DB_MASTER );
+
+ $sendMail = false;
+ if ( $req->action !== AuthManager::ACTION_REMOVE &&
+ get_class( $req ) === TemporaryPasswordAuthenticationRequest::class
+ ) {
+ $pwhash = $this->getPasswordFactory()->newFromPlaintext( $req->password );
+ $newpassTime = $dbw->timestamp();
+ $sendMail = $req->mailpassword;
+ } else {
+ // Invalidate the temporary password when any other auth is reset, or when removing
+ $pwhash = $this->getPasswordFactory()->newFromCiphertext( null );
+ $newpassTime = null;
+ }
+
+ $dbw->update(
+ 'user',
+ [
+ 'user_newpassword' => $pwhash->toString(),
+ 'user_newpass_time' => $newpassTime,
+ ],
+ [ 'user_name' => $username ],
+ __METHOD__
+ );
+
+ if ( $sendMail ) {
+ $this->sendPasswordResetEmail( $req );
+ }
+ }
+
+ public function accountCreationType() {
+ return self::TYPE_CREATE;
+ }
+
+ public function testForAccountCreation( $user, $creator, array $reqs ) {
+ /** @var TemporaryPasswordAuthenticationRequest $req */
+ $req = AuthenticationRequest::getRequestByClass(
+ $reqs, TemporaryPasswordAuthenticationRequest::class
+ );
+
+ $ret = \StatusValue::newGood();
+ if ( $req ) {
+ if ( $req->mailpassword && !$req->hasBackchannel ) {
+ if ( !$this->emailEnabled ) {
+ $ret->merge( \StatusValue::newFatal( 'emaildisabled' ) );
+ } elseif ( !$user->getEmail() ) {
+ $ret->merge( \StatusValue::newFatal( 'noemailcreate' ) );
+ }
+ }
+
+ $ret->merge(
+ $this->checkPasswordValidity( $user->getName(), $req->password )
+ );
+ }
+ return $ret;
+ }
+
+ public function beginPrimaryAccountCreation( $user, $creator, array $reqs ) {
+ /** @var TemporaryPasswordAuthenticationRequest $req */
+ $req = AuthenticationRequest::getRequestByClass(
+ $reqs, TemporaryPasswordAuthenticationRequest::class
+ );
+ if ( $req ) {
+ if ( $req->username !== null && $req->password !== null ) {
+ // Nothing we can do yet, because the user isn't in the DB yet
+ if ( $req->username !== $user->getName() ) {
+ $req = clone( $req );
+ $req->username = $user->getName();
+ }
+
+ if ( $req->mailpassword ) {
+ // prevent EmailNotificationSecondaryAuthenticationProvider from sending another mail
+ $this->manager->setAuthenticationSessionData( 'no-email', true );
+ }
+
+ $ret = AuthenticationResponse::newPass( $req->username );
+ $ret->createRequest = $req;
+ return $ret;
+ }
+ }
+ return AuthenticationResponse::newAbstain();
+ }
+
+ public function finishAccountCreation( $user, $creator, AuthenticationResponse $res ) {
+ /** @var TemporaryPasswordAuthenticationRequest $req */
+ $req = $res->createRequest;
+ $mailpassword = $req->mailpassword;
+ $req->mailpassword = false; // providerChangeAuthenticationData would send the wrong email
+
+ // Now that the user is in the DB, set the password on it.
+ $this->providerChangeAuthenticationData( $req );
+
+ if ( $mailpassword ) {
+ $this->sendNewAccountEmail( $user, $creator, $req->password );
+ }
+
+ return $mailpassword ? 'byemail' : null;
+ }
+
+ /**
+ * Check that a temporary password is still valid (hasn't expired).
+ * @param string $timestamp A timestamp in MediaWiki (TS_MW) format
+ * @return bool
+ */
+ protected function isTimestampValid( $timestamp ) {
+ $time = wfTimestampOrNull( TS_MW, $timestamp );
+ if ( $time !== null ) {
+ $expiry = wfTimestamp( TS_UNIX, $time ) + $this->newPasswordExpiry;
+ if ( time() >= $expiry ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Send an email about the new account creation and the temporary password.
+ * @param User $user The new user account
+ * @param User $creatingUser The user who created the account (can be anonymous)
+ * @param string $password The temporary password
+ * @return \Status
+ */
+ protected function sendNewAccountEmail( User $user, User $creatingUser, $password ) {
+ $ip = $creatingUser->getRequest()->getIP();
+ // @codeCoverageIgnoreStart
+ if ( !$ip ) {
+ return \Status::newFatal( 'badipaddress' );
+ }
+ // @codeCoverageIgnoreEnd
+
+ \Hooks::run( 'User::mailPasswordInternal', [ &$creatingUser, &$ip, &$user ] );
+
+ $mainPageUrl = \Title::newMainPage()->getCanonicalURL();
+ $userLanguage = $user->getOption( 'language' );
+ $subjectMessage = wfMessage( 'createaccount-title' )->inLanguage( $userLanguage );
+ $bodyMessage = wfMessage( 'createaccount-text', $ip, $user->getName(), $password,
+ '<' . $mainPageUrl . '>', round( $this->newPasswordExpiry / 86400 ) )
+ ->inLanguage( $userLanguage );
+
+ $status = $user->sendMail( $subjectMessage->text(), $bodyMessage->text() );
+
+ // TODO show 'mailerror' message on error, 'accmailtext' success message otherwise?
+ // @codeCoverageIgnoreStart
+ if ( !$status->isGood() ) {
+ $this->logger->warning( 'Could not send account creation email: ' .
+ $status->getWikiText( false, false, 'en' ) );
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $status;
+ }
+
+ /**
+ * @param TemporaryPasswordAuthenticationRequest $req
+ * @return \Status
+ */
+ protected function sendPasswordResetEmail( TemporaryPasswordAuthenticationRequest $req ) {
+ $user = User::newFromName( $req->username );
+ if ( !$user ) {
+ return \Status::newFatal( 'noname' );
+ }
+ $userLanguage = $user->getOption( 'language' );
+ $callerIsAnon = \IP::isValid( $req->caller );
+ $callerName = $callerIsAnon ? $req->caller : User::newFromName( $req->caller )->getName();
+ $passwordMessage = wfMessage( 'passwordreset-emailelement', $user->getName(),
+ $req->password )->inLanguage( $userLanguage );
+ $emailMessage = wfMessage( $callerIsAnon ? 'passwordreset-emailtext-ip'
+ : 'passwordreset-emailtext-user' )->inLanguage( $userLanguage );
+ $emailMessage->params( $callerName, $passwordMessage->text(), 1,
+ '<' . \Title::newMainPage()->getCanonicalURL() . '>',
+ round( $this->newPasswordExpiry / 86400 ) );
+ $emailTitle = wfMessage( 'passwordreset-emailtitle' )->inLanguage( $userLanguage );
+ return $user->sendMail( $emailTitle->text(), $emailMessage->text() );
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use BagOStuff;
+use Config;
+
+/**
+ * A pre-authentication provider to throttle authentication actions.
+ *
+ * Adding this provider will throttle account creations and primary authentication attempts
+ * (more specifically, any authentication that returns FAIL on failure). Secondary authentication
+ * cannot be easily throttled on a framework level (since it would typically return UI on failure);
+ * secondary providers are expected to do their own throttling.
+ * @ingroup Auth
+ * @since 1.27
+ */
+class ThrottlePreAuthenticationProvider extends AbstractPreAuthenticationProvider {
+ /** @var array */
+ protected $throttleSettings;
+
+ /** @var Throttler */
+ protected $accountCreationThrottle;
+
+ /** @var Throttler */
+ protected $passwordAttemptThrottle;
+
+ /** @var BagOStuff */
+ protected $cache;
+
+ /**
+ * @param array $params
+ * - accountCreationThrottle: (array) Condition array for the account creation throttle; an array
+ * of arrays in a format like $wgPasswordAttemptThrottle, passed to the Throttler constructor.
+ * - passwordAttemptThrottle: (array) Condition array for the password attempt throttle, in the
+ * same format as accountCreationThrottle.
+ * - cache: (BagOStuff) Where to store the throttle, defaults to the local cluster instance.
+ */
+ public function __construct( $params = [] ) {
+ $this->throttleSettings = array_intersect_key( $params,
+ [ 'accountCreationThrottle' => true, 'passwordAttemptThrottle' => true ] );
+ $this->cache = isset( $params['cache'] ) ? $params['cache'] :
+ \ObjectCache::getLocalClusterInstance();
+ }
+
+ public function setConfig( Config $config ) {
+ parent::setConfig( $config );
+
+ // @codeCoverageIgnoreStart
+ $this->throttleSettings += [
+ // @codeCoverageIgnoreEnd
+ 'accountCreationThrottle' => [ [
+ 'count' => $this->config->get( 'AccountCreationThrottle' ),
+ 'seconds' => 86400,
+ ] ],
+ 'passwordAttemptThrottle' => $this->config->get( 'PasswordAttemptThrottle' ),
+ ];
+
+ if ( !empty( $this->throttleSettings['accountCreationThrottle'] ) ) {
+ $this->accountCreationThrottle = new Throttler(
+ $this->throttleSettings['accountCreationThrottle'], [
+ 'type' => 'acctcreate',
+ 'cache' => $this->cache,
+ ]
+ );
+ }
+ if ( !empty( $this->throttleSettings['passwordAttemptThrottle'] ) ) {
+ $this->passwordAttemptThrottle = new Throttler(
+ $this->throttleSettings['passwordAttemptThrottle'], [
+ 'type' => 'password',
+ 'cache' => $this->cache,
+ ]
+ );
+ }
+ }
+
+ public function testForAccountCreation( $user, $creator, array $reqs ) {
+ if ( !$this->accountCreationThrottle || !$creator->isPingLimitable() ) {
+ return \StatusValue::newGood();
+ }
+
+ $ip = $this->manager->getRequest()->getIP();
+
+ if ( !\Hooks::run( 'ExemptFromAccountCreationThrottle', [ $ip ] ) ) {
+ $this->logger->debug( __METHOD__ . ": a hook allowed account creation w/o throttle\n" );
+ return \StatusValue::newGood();
+ }
+
+ $result = $this->accountCreationThrottle->increase( null, $ip, __METHOD__ );
+ if ( $result ) {
+ return \StatusValue::newFatal( 'acct_creation_throttle_hit', $result['count'] );
+ }
+
+ return \StatusValue::newGood();
+ }
+
+ public function testForAuthentication( array $reqs ) {
+ if ( !$this->passwordAttemptThrottle ) {
+ return \StatusValue::newGood();
+ }
+
+ $ip = $this->manager->getRequest()->getIP();
+ try {
+ $username = AuthenticationRequest::getUsernameFromRequests( $reqs );
+ } catch ( \UnexpectedValueException $e ) {
+ $username = '';
+ }
+
+ // Get everything this username could normalize to, and throttle each one individually.
+ // If nothing uses usernames, just throttle by IP.
+ $usernames = $this->manager->normalizeUsername( $username );
+ $result = false;
+ foreach ( $usernames as $name ) {
+ $r = $this->passwordAttemptThrottle->increase( $name, $ip, __METHOD__ );
+ if ( $r && ( !$result || $result['wait'] < $r['wait'] ) ) {
+ $result = $r;
+ }
+ }
+
+ if ( $result ) {
+ $message = wfMessage( 'login-throttled' )->durationParams( $result['wait'] );
+ return \StatusValue::newFatal( $message );
+ } else {
+ $this->manager->setAuthenticationSessionData( 'LoginThrottle',
+ [ 'users' => $usernames, 'ip' => $ip ] );
+ return \StatusValue::newGood();
+ }
+ }
+
+ /**
+ * @param null|\User $user
+ * @param AuthenticationResponse $response
+ */
+ public function postAuthentication( $user, AuthenticationResponse $response ) {
+ if ( $response->status !== AuthenticationResponse::PASS ) {
+ return;
+ } elseif ( !$this->passwordAttemptThrottle ) {
+ return;
+ }
+
+ $data = $this->manager->getAuthenticationSessionData( 'LoginThrottle' );
+ if ( !$data ) {
+ $this->logger->error( 'throttler data not found for {user}', [ 'user' => $user->getName() ] );
+ return;
+ }
+
+ foreach ( $data['users'] as $name ) {
+ $this->passwordAttemptThrottle->clear( $name, $data['ip'] );
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use BagOStuff;
+use Config;
+use MediaWiki\Logger\LoggerFactory;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+use Psr\Log\NullLogger;
+use User;
+
+/**
+ * A helper class for throttling authentication attempts.
+ * @package MediaWiki\Auth
+ * @ingroup Auth
+ * @since 1.27
+ */
+class Throttler implements LoggerAwareInterface {
+ /** @var string */
+ protected $type;
+ /**
+ * See documentation of $wgPasswordAttemptThrottle for format. Old (pre-1.27) format is not
+ * allowed here.
+ * @var array
+ * @see https://www.mediawiki.org/wiki/Manual:$wgPasswordAttemptThrottle
+ */
+ protected $conditions;
+ /** @var BagOStuff */
+ protected $cache;
+ /** @var LoggerInterface */
+ protected $logger;
+ /** @var int|float */
+ protected $warningLimit;
+
+ /**
+ * @param array $conditions An array of arrays describing throttling conditions.
+ * Defaults to $wgPasswordAttemptThrottle. See documentation of that variable for format.
+ * @param array $params Parameters (all optional):
+ * - type: throttle type, used as a namespace for counters,
+ * - cache: a BagOStuff object where throttle counters are stored.
+ * - warningLimit: the log level will be raised to warning when rejecting an attempt after
+ * no less than this many failures.
+ */
+ public function __construct( array $conditions = null, array $params = [] ) {
+ $invalidParams = array_diff_key( $params,
+ array_fill_keys( [ 'type', 'cache', 'warningLimit' ], true ) );
+ if ( $invalidParams ) {
+ throw new \InvalidArgumentException( 'unrecognized parameters: '
+ . implode( ', ', array_keys( $invalidParams ) ) );
+ }
+
+ if ( $conditions === null ) {
+ $config = \ConfigFactory::getDefaultInstance()->makeConfig( 'main' );
+ $conditions = $config->get( 'PasswordAttemptThrottle' );
+ $params += [
+ 'type' => 'password',
+ 'cache' => \ObjectCache::getLocalClusterInstance(),
+ 'warningLimit' => 50,
+ ];
+ } else {
+ $params += [
+ 'type' => 'custom',
+ 'cache' => \ObjectCache::getLocalClusterInstance(),
+ 'warningLimit' => INF,
+ ];
+ }
+
+ $this->type = $params['type'];
+ $this->conditions = static::normalizeThrottleConditions( $conditions );
+ $this->cache = $params['cache'];
+ $this->warningLimit = $params['warningLimit'];
+
+ $this->setLogger( LoggerFactory::getInstance( 'throttler' ) );
+ }
+
+ public function setLogger( LoggerInterface $logger ) {
+ $this->logger = $logger;
+ }
+
+ /**
+ * Increase the throttle counter and return whether the attempt should be throttled.
+ *
+ * Should be called before an authentication attempt.
+ *
+ * @param string|null $username
+ * @param string|null $ip
+ * @param string|null $caller The authentication method from which we were called.
+ * @return array|false False if the attempt should not be throttled, an associative array
+ * with three keys otherwise:
+ * - throttleIndex: which throttle condition was met (a key of the conditions array)
+ * - count: throttle count (ie. number of failed attempts)
+ * - wait: time in seconds until authentication can be attempted
+ */
+ public function increase( $username = null, $ip = null, $caller = null ) {
+ if ( $username === null && $ip === null ) {
+ throw new \InvalidArgumentException( 'Either username or IP must be set for throttling' );
+ }
+
+ $userKey = $username ? md5( $username ) : null;
+ foreach ( $this->conditions as $index => $throttleCondition ) {
+ $ipKey = isset( $throttleCondition['allIPs'] ) ? null : $ip;
+ $count = $throttleCondition['count'];
+ $expiry = $throttleCondition['seconds'];
+
+ // a limit of 0 is used as a disable flag in some throttling configuration settings
+ // throttling the whole world is probably a bad idea
+ if ( !$count || $userKey === null && $ipKey === null ) {
+ continue;
+ }
+
+ $throttleKey = wfGlobalCacheKey( 'throttler', $this->type, $index, $ipKey, $userKey );
+ $throttleCount = $this->cache->get( $throttleKey );
+
+ if ( !$throttleCount ) { // counter not started yet
+ $this->cache->add( $throttleKey, 1, $expiry );
+ } elseif ( $throttleCount < $count ) { // throttle limited not yet reached
+ $this->cache->incr( $throttleKey );
+ } else { // throttled
+ $this->logRejection( [
+ 'type' => $this->type,
+ 'index' => $index,
+ 'ip' => $ipKey,
+ 'username' => $username,
+ 'count' => $count,
+ 'expiry' => $expiry,
+ // @codeCoverageIgnoreStart
+ 'method' => $caller ?: __METHOD__,
+ // @codeCoverageIgnoreEnd
+ ] );
+
+ return [
+ 'throttleIndex' => $index,
+ 'count' => $count,
+ 'wait' => $expiry,
+ ];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Clear the throttle counter.
+ *
+ * Should be called after a successful authentication attempt.
+ *
+ * @param string|null $username
+ * @param string|null $ip
+ * @throws \MWException
+ */
+ public function clear( $username = null, $ip = null ) {
+ $userKey = $username ? md5( $username ) : null;
+ foreach ( $this->conditions as $index => $specificThrottle ) {
+ $ipKey = isset( $specificThrottle['allIPs'] ) ? null : $ip;
+ $throttleKey = wfGlobalCacheKey( 'throttler', $this->type, $index, $ipKey, $userKey );
+ $this->cache->delete( $throttleKey );
+ }
+ }
+
+ /**
+ * Handles B/C for $wgPasswordAttemptThrottle.
+ * @param array $throttleConditions
+ * @return array
+ * @see $wgPasswordAttemptThrottle for structure
+ */
+ protected static function normalizeThrottleConditions( $throttleConditions ) {
+ if ( !is_array( $throttleConditions ) ) {
+ return [];
+ }
+ if ( isset( $throttleConditions['count'] ) ) { // old style
+ $throttleConditions = [ $throttleConditions ];
+ }
+ return $throttleConditions;
+ }
+
+ protected function logRejection( array $context ) {
+ $logMsg = 'Throttle {type} hit, throttled for {expiry} seconds due to {count} attempts '
+ . 'from username {username} and IP {ip}';
+
+ // If we are hitting a throttle for >= warningLimit attempts, it is much more likely to be
+ // an attack than someone simply forgetting their password, so log it at a higher level.
+ $level = $context['count'] >= $this->warningLimit ? LogLevel::WARNING : LogLevel::INFO;
+
+ // It should be noted that once the throttle is hit, every attempt to login will
+ // generate the log message until the throttle expires, not just the attempt that
+ // puts the throttle over the top.
+ $this->logger->log( $level, $logMsg, $context );
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+use StatusValue;
+use User;
+
+/**
+ * This represents additional user data requested on the account creation form
+ *
+ * @ingroup Auth
+ * @since 1.27
+ */
+class UserDataAuthenticationRequest extends AuthenticationRequest {
+ /** @var string|null Email address */
+ public $email;
+
+ /** @var string|null Real name */
+ public $realname;
+
+ public function getFieldInfo() {
+ $config = \ConfigFactory::getDefaultInstance()->makeConfig( 'main' );
+ $ret = [
+ 'email' => [
+ 'type' => 'string',
+ 'label' => wfMessage( 'authmanager-email-label' ),
+ 'help' => wfMessage( 'authmanager-email-help' ),
+ 'optional' => true,
+ ],
+ 'realname' => [
+ 'type' => 'string',
+ 'label' => wfMessage( 'authmanager-realname-label' ),
+ 'help' => wfMessage( 'authmanager-realname-help' ),
+ 'optional' => true,
+ ],
+ ];
+
+ if ( !$config->get( 'EnableEmail' ) ) {
+ unset( $ret['email'] );
+ }
+
+ if ( in_array( 'realname', $config->get( 'HiddenPrefs' ), true ) ) {
+ unset( $ret['realname'] );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Add data to the User object
+ * @param User $user User being created (not added to the database yet).
+ * This may become a "UserValue" in the future, or User may be refactored
+ * into such.
+ * @return StatusValue
+ */
+ public function populateUser( $user ) {
+ if ( $this->email !== null && $this->email !== '' ) {
+ if ( !\Sanitizer::validateEmail( $this->email ) ) {
+ return StatusValue::newFatal( 'invalidemailaddress' );
+ }
+ $user->setEmail( $this->email );
+ }
+ if ( $this->realname !== null && $this->realname !== '' ) {
+ $user->setRealName( $this->realname );
+ }
+ return StatusValue::newGood();
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Auth
+ */
+
+namespace MediaWiki\Auth;
+
+/**
+ * AuthenticationRequest to ensure something with a username is present
+ * @ingroup Auth
+ * @since 1.27
+ */
+class UsernameAuthenticationRequest extends AuthenticationRequest {
+ public function getFieldInfo() {
+ return [
+ 'username' => [
+ 'type' => 'string',
+ 'label' => wfMessage( 'userlogin-yourname' ),
+ 'help' => wfMessage( 'authmanager-username-help' ),
+ ],
+ ];
+ }
+}
* @file
* @ingroup Cache
*/
+use MediaWiki\MediaWikiServices;
/**
* This class stores an arbitrary value along with its dependencies.
}
}
+/**
+ * @ingroup Cache
+ */
+class MainConfigDependency extends CacheDependency {
+ private $name;
+ private $value;
+
+ function __construct( $name ) {
+ $this->name = $name;
+ $this->value = $this->getConfig()->get( $this->name );
+ }
+
+ private function getConfig() {
+ return MediaWikiServices::getInstance()->getMainConfig();
+ }
+
+ /**
+ * @return bool
+ */
+ function isExpired() {
+ if ( !$this->getConfig()->has( $this->name ) ) {
+ return true;
+ }
+
+ return $this->getConfig()->get( $this->name ) != $this->value;
+ }
+}
+
/**
* @ingroup Cache
*/
* @author Niklas Laxström
* @ingroup Cache
*/
+use MediaWiki\MediaWikiServices;
/**
* Caches user genders when needed to use correct namespace aliases.
protected $missLimit = 1000;
/**
+ * @deprecated in 1.28 see MediaWikiServices::getInstance()->getGenderCache()
* @return GenderCache
*/
public static function singleton() {
- static $that = null;
- if ( $that === null ) {
- $that = new self();
- }
-
- return $that;
- }
-
- protected function __construct() {
+ return MediaWikiServices::getInstance()->getGenderCache();
}
/**
$user = $context->getUser();
// Check for non-standard user language; this covers uselang,
// and extensions for auto-detecting user language.
- $ulang = $context->getLanguage()->getCode();
- $clang = $wgContLang->getCode();
+ $ulang = $context->getLanguage();
// Check that there are no other sources of variation
- if ( $user->getId() || $user->getNewtalk() || $ulang != $clang ) {
+ if ( $user->getId() || $user->getNewtalk() || $ulang->equals( $wgContLang ) ) {
return false;
}
// Allow extensions to disable caching
* @ingroup Cache
*/
use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
/**
* Class representing a list of titles
* @param string $dbkey
*/
public function add( $ns, $dbkey ) {
- if ( $ns < 0 ) {
- return;
+ if ( $ns < 0 || $dbkey === '' ) {
+ return; // T137083
}
if ( !array_key_exists( $ns, $this->data ) ) {
$this->data[$ns] = [];
* @return array Mapping PDBK to ID
*/
public function execute() {
- $linkCache = LinkCache::singleton();
+ $linkCache = MediaWikiServices::getInstance()->getLinkCache();
return $this->executeInto( $linkCache );
}
return [];
}
+ $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
// For each returned entry, add it to the list of good links, and remove it from $remaining
$ids = [];
$remaining = $this->data;
foreach ( $res as $row ) {
- $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+ $title = new TitleValue( (int)$row->page_namespace, $row->page_title );
$cache->addGoodLinkObjFromRow( $title, $row );
- $ids[$title->getPrefixedDBkey()] = $row->page_id;
+ $pdbk = $titleFormatter->getPrefixedDBkey( $title );
+ $ids[$pdbk] = $row->page_id;
unset( $remaining[$row->page_namespace][$row->page_title] );
}
// The remaining links in $data are bad links, register them as such
foreach ( $remaining as $ns => $dbkeys ) {
foreach ( $dbkeys as $dbkey => $unused ) {
- $title = Title::makeTitle( $ns, $dbkey );
+ $title = new TitleValue( (int)$ns, (string)$dbkey );
$cache->addBadLinkObj( $title );
- $ids[$title->getPrefixedDBkey()] = 0;
+ $pdbk = $titleFormatter->getPrefixedDBkey( $title );
+ $ids[$pdbk] = 0;
}
}
* @return bool|ResultWrapper
*/
public function doQuery() {
- global $wgContentHandlerUseDB, $wgPageLanguageUseDB;
-
if ( $this->isEmpty() ) {
return false;
}
// This is similar to LinkHolderArray::replaceInternal
$dbr = wfGetDB( DB_SLAVE );
$table = 'page';
- $fields = [ 'page_id', 'page_namespace', 'page_title', 'page_len',
- 'page_is_redirect', 'page_latest' ];
-
- if ( $wgContentHandlerUseDB ) {
- $fields[] = 'page_content_model';
- }
- if ( $wgPageLanguageUseDB ) {
- $fields[] = 'page_lang';
- }
+ $fields = array_merge(
+ LinkCache::getSelectFields(),
+ [ 'page_namespace', 'page_title' ]
+ );
$conds = $this->constructSet( 'page', $dbr );
return false;
}
- $genderCache = GenderCache::singleton();
+ $genderCache = MediaWikiServices::getInstance()->getGenderCache();
$genderCache->doLinkBatch( $this->data, $this->caller );
return true;
* @file
* @ingroup Cache
*/
+use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
/**
* Cache for article titles (prefixed DB keys) and ids linked from one source
private $mForUpdate = false;
/**
- * How many Titles to store. There are two caches, so the amount actually
- * stored in memory can be up to twice this.
+ * @var TitleFormatter
*/
- const MAX_SIZE = 10000;
+ private $titleFormatter;
/**
- * @var LinkCache
+ * How many Titles to store. There are two caches, so the amount actually
+ * stored in memory can be up to twice this.
*/
- protected static $instance;
+ const MAX_SIZE = 10000;
- public function __construct() {
+ public function __construct( TitleFormatter $titleFormatter ) {
$this->mGoodLinks = new HashBagOStuff( [ 'maxKeys' => self::MAX_SIZE ] );
$this->mBadLinks = new HashBagOStuff( [ 'maxKeys' => self::MAX_SIZE ] );
+ $this->titleFormatter = $titleFormatter;
}
/**
* Get an instance of this class.
*
* @return LinkCache
+ * @deprecated since 1.28, use MediaWikiServices instead
*/
public static function singleton() {
- if ( !self::$instance ) {
- self::$instance = new LinkCache;
- }
-
- return self::$instance;
- }
-
- /**
- * Destroy the singleton instance
- *
- * A new one will be created next time singleton() is called.
- *
- * @since 1.22
- */
- public static function destroySingleton() {
- self::$instance = null;
- }
-
- /**
- * Set the singleton instance to a given object.
- *
- * Since we do not have an interface for LinkCache, you have to be sure the
- * given object implements all the LinkCache public methods.
- *
- * @param LinkCache $instance
- * @since 1.22
- */
- public static function setSingleton( LinkCache $instance ) {
- self::$instance = $instance;
+ return MediaWikiServices::getInstance()->getLinkCache();
}
/**
/**
* Get a field of a title object from cache.
* If this link is not a cached good title, it will return NULL.
- * @param Title $title
+ * @param LinkTarget $target
* @param string $field ('length','redirect','revision','model')
* @return string|int|null
*/
- public function getGoodLinkFieldObj( Title $title, $field ) {
- $dbkey = $title->getPrefixedDBkey();
+ public function getGoodLinkFieldObj( LinkTarget $target, $field ) {
+ $dbkey = $this->titleFormatter->getPrefixedDBkey( $target );
$info = $this->mGoodLinks->get( $dbkey );
if ( !$info ) {
return null;
* Add a link for the title to the link cache
*
* @param int $id Page's ID
- * @param Title $title
+ * @param LinkTarget $target
* @param int $len Text's length
* @param int $redir Whether the page is a redirect
* @param int $revision Latest revision's ID
* @param string|null $model Latest revision's content model ID
* @param string|null $lang Language code of the page, if not the content language
*/
- public function addGoodLinkObj( $id, Title $title, $len = -1, $redir = null,
+ public function addGoodLinkObj( $id, LinkTarget $target, $len = -1, $redir = null,
$revision = 0, $model = null, $lang = null
) {
- $dbkey = $title->getPrefixedDBkey();
+ $dbkey = $this->titleFormatter->getPrefixedDBkey( $target );
$this->mGoodLinks->set( $dbkey, [
'id' => (int)$id,
'length' => (int)$len,
/**
* Same as above with better interface.
* @since 1.19
- * @param Title $title
+ * @param LinkTarget $target
* @param stdClass $row Object which has the fields page_id, page_is_redirect,
* page_latest and page_content_model
*/
- public function addGoodLinkObjFromRow( Title $title, $row ) {
- $dbkey = $title->getPrefixedDBkey();
+ public function addGoodLinkObjFromRow( LinkTarget $target, $row ) {
+ $dbkey = $this->titleFormatter->getPrefixedDBkey( $target );
$this->mGoodLinks->set( $dbkey, [
'id' => intval( $row->page_id ),
'length' => intval( $row->page_len ),
}
/**
- * @param Title $title
+ * @param LinkTarget $target
*/
- public function addBadLinkObj( Title $title ) {
- $dbkey = $title->getPrefixedDBkey();
+ public function addBadLinkObj( LinkTarget $target ) {
+ $dbkey = $this->titleFormatter->getPrefixedDBkey( $target );
if ( !$this->isBadLink( $dbkey ) ) {
$this->mBadLinks->set( $dbkey, 1 );
}
}
/**
- * @param Title $title
+ * @param LinkTarget $target
*/
- public function clearLink( Title $title ) {
- $dbkey = $title->getPrefixedDBkey();
+ public function clearLink( LinkTarget $target ) {
+ $dbkey = $this->titleFormatter->getPrefixedDBkey( $target );
$this->mBadLinks->delete( $dbkey );
$this->mGoodLinks->delete( $dbkey );
}
/**
* Add a title to the link cache, return the page_id or zero if non-existent
*
+ * @deprecated since 1.27, unused
* @param string $title Prefixed DB key
* @return int Page ID or zero
*/
}
/**
- * Add a title to the link cache, return the page_id or zero if non-existent
+ * Fields that LinkCache needs to select
*
- * @param Title $nt Title object to add
- * @return int Page ID or zero
+ * @since 1.28
+ * @return array
*/
- public function addLinkObj( Title $nt ) {
+ public static function getSelectFields() {
global $wgContentHandlerUseDB, $wgPageLanguageUseDB;
- $key = $nt->getPrefixedDBkey();
- if ( $this->isBadLink( $key ) || $nt->isExternal() ) {
+ $fields = [ 'page_id', 'page_len', 'page_is_redirect', 'page_latest' ];
+ if ( $wgContentHandlerUseDB ) {
+ $fields[] = 'page_content_model';
+ }
+ if ( $wgPageLanguageUseDB ) {
+ $fields[] = 'page_lang';
+ }
+
+ return $fields;
+ }
+
+ /**
+ * Add a title to the link cache, return the page_id or zero if non-existent
+ *
+ * @param LinkTarget $nt LinkTarget object to add
+ * @return int Page ID or zero
+ */
+ public function addLinkObj( LinkTarget $nt ) {
+ $key = $this->titleFormatter->getPrefixedDBkey( $nt );
+ if ( $this->isBadLink( $key ) || $nt->isExternal()
+ || $nt->inNamespace( NS_SPECIAL )
+ ) {
return 0;
}
$id = $this->getGoodLinkID( $key );
// Some fields heavily used for linking...
$db = $this->mForUpdate ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
- $fields = [ 'page_id', 'page_len', 'page_is_redirect', 'page_latest' ];
- if ( $wgContentHandlerUseDB ) {
- $fields[] = 'page_content_model';
- }
- if ( $wgPageLanguageUseDB ) {
- $fields[] = 'page_lang';
- }
-
- $row = $db->selectRow( 'page', $fields,
+ $row = $db->selectRow( 'page', self::getSelectFields(),
[ 'page_namespace' => $nt->getNamespace(), 'page_title' => $nt->getDBkey() ],
__METHOD__
);
use Cdb\Reader as CdbReader;
use Cdb\Writer as CdbWriter;
use CLDRPluralRuleParser\Evaluator;
+use MediaWiki\MediaWikiServices;
/**
* Class for caching the contents of localisation files, Messages*.php
* @return array
*/
public function getMessagesDirs() {
- global $wgMessagesDirs, $IP;
+ global $IP;
+
+ $config = MediaWikiServices::getInstance()->getMainConfig();
+ $messagesDirs = $config->get( 'MessagesDirs' );
return [
'core' => "$IP/languages/i18n",
'api' => "$IP/includes/api/i18n",
'oojs-ui' => "$IP/resources/lib/oojs-ui/i18n",
- ] + $wgMessagesDirs;
+ ] + $messagesDirs;
}
/**
# Add cache dependencies for any referenced globals
$deps['wgExtensionMessagesFiles'] = new GlobalDependency( 'wgExtensionMessagesFiles' );
- // $wgMessagesDirs is used in LocalisationCache::getMessagesDirs()
- $deps['wgMessagesDirs'] = new GlobalDependency( 'wgMessagesDirs' );
+ // The 'MessagesDirs' config setting is used in LocalisationCache::getMessagesDirs().
+ // We use the key 'wgMessagesDirs' for historical reasons.
+ $deps['wgMessagesDirs'] = new MainConfigDependency( 'MessagesDirs' );
$deps['version'] = new ConstantDependency( 'LocalisationCache::VERSION' );
# Add dependencies to the cache entry
*
* @file
*/
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\MediaWikiServices;
class ChangesList extends ContextSource {
/**
/** @var BagOStuff */
protected $watchMsgCache;
+ /**
+ * @var LinkRenderer
+ */
+ protected $linkRenderer;
+
/**
* Changeslist constructor
*
}
$this->preCacheMessages();
$this->watchMsgCache = new HashBagOStuff( [ 'maxKeys' => 50 ] );
+ $this->linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
}
/**
*/
public function insertLog( &$s, $title, $logtype ) {
$page = new LogPage( $logtype );
- $logname = $page->getName()->setContext( $this->getContext() )->escaped();
- $s .= $this->msg( 'parentheses' )->rawParams( Linker::linkKnown( $title, $logname ) )->escaped();
+ $logname = $page->getName()->setContext( $this->getContext() )->text();
+ $s .= $this->msg( 'parentheses' )->rawParams(
+ $this->linkRenderer->makeKnownLink( $title, $logname )
+ )->escaped();
}
/**
'oldid' => $rc->mAttribs['rc_last_oldid']
];
- $diffLink = Linker::linkKnown(
+ $diffLink = $this->linkRenderer->makeKnownLink(
$rc->getTitle(),
- $this->message['diff'],
- [ 'tabindex' => $rc->counter ],
+ new HtmlArmor( $this->message['diff'] ),
+ [],
$query
);
}
} else {
$diffhist = $diffLink . $this->message['pipe-separator'];
# History link
- $diffhist .= Linker::linkKnown(
+ $diffhist .= $this->linkRenderer->makeKnownLink(
$rc->getTitle(),
- $this->message['hist'],
+ new HtmlArmor( $this->message['hist'] ),
[],
[
'curid' => $rc->mAttribs['rc_cur_id'],
$params = [ 'redirect' => 'no' ];
}
- $articlelink = Linker::link(
+ $articlelink = $this->linkRenderer->makeLink(
$rc->getTitle(),
null,
[ 'class' => 'mw-changeslist-title' ],
// message is set by the parent ChangesList class
$this->cacheEntryFactory = new RCCacheEntryFactory(
$context,
- $this->message
+ $this->message,
+ $this->linkRenderer
);
}
} elseif ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
$link = '<span class="history-deleted">' . $rcObj->timestamp . '</span> ';
} else {
- $link = Linker::linkKnown(
+ $link = $this->linkRenderer->makeKnownLink(
$rcObj->getTitle(),
- $rcObj->timestamp,
+ new HtmlArmor( $rcObj->timestamp ),
[],
$params
);
) {
$links['total-changes'] = $nchanges[$n];
} else {
- $links['total-changes'] = Linker::link(
+ $links['total-changes'] = $this->linkRenderer->makeKnownLink(
$block0->getTitle(),
- $nchanges[$n],
+ new HtmlArmor( $nchanges[$n] ),
[],
$queryParams + [
'diff' => $currentRevision,
'oldid' => $last->mAttribs['rc_last_oldid'],
- ],
- [ 'known', 'noclasses' ]
+ ]
);
if ( $sinceLast > 0 && $sinceLast < $n ) {
- $links['total-changes-since-last'] = Linker::link(
+ $links['total-changes-since-last'] = $this->linkRenderer->makeKnownLink(
$block0->getTitle(),
- $sinceLastVisitMsg[$sinceLast],
+ new HtmlArmor( $sinceLastVisitMsg[$sinceLast] ),
[],
$queryParams + [
'diff' => $currentRevision,
'oldid' => $unvisitedOldid,
- ],
- [ 'known', 'noclasses' ]
+ ]
);
}
}
$params = $queryParams;
$params['action'] = 'history';
- $links['history'] = Linker::linkKnown(
+ $links['history'] = $this->linkRenderer->makeKnownLink(
$block0->getTitle(),
- $this->message['enhancedrc-history'],
+ new HtmlArmor( $this->message['enhancedrc-history'] ),
[],
$params
);
if ( $logType ) {
$logPage = new LogPage( $logType );
$logTitle = SpecialPage::getTitleFor( 'Log', $logType );
- $logName = $logPage->getName()->escaped();
+ $logName = $logPage->getName()->text();
$data['logLink'] = $this->msg( 'parentheses' )
- ->rawParams( Linker::linkKnown( $logTitle, $logName ) )->escaped();
+ ->rawParams(
+ $this->linkRenderer->makeKnownLink( $logTitle, $logName )
+ )->escaped();
} else {
$data['articleLink'] = $this->getArticleLink( $rcObj, $rcObj->unpatrolled, $rcObj->watched );
}
}
$retVal = ' ' . $this->msg( 'parentheses' )
- ->rawParams( $rc->difflink . $this->message['pipe-separator'] . Linker::linkKnown(
+ ->rawParams( $rc->difflink . $this->message['pipe-separator']
+ . $this->linkRenderer->makeKnownLink(
$pageTitle,
- $this->message['hist'],
+ new HtmlArmor( $this->message['hist'] ),
[],
$query
) )->escaped();
*
* @file
*/
+use MediaWiki\Linker\LinkRenderer;
class RCCacheEntryFactory {
/* @var string[] */
private $messages;
+ /**
+ * @var LinkRenderer
+ */
+ private $linkRenderer;
+
/**
* @param IContextSource $context
* @param string[] $messages
+ * @param LinkRenderer $linkRenderer
*/
- public function __construct( IContextSource $context, $messages ) {
+ public function __construct(
+ IContextSource $context, $messages, LinkRenderer $linkRenderer
+ ) {
$this->context = $context;
$this->messages = $messages;
+ $this->linkRenderer = $linkRenderer;
}
/**
// New unpatrolled pages
if ( $cacheEntry->unpatrolled && $type == RC_NEW ) {
- $clink = Linker::linkKnown( $cacheEntry->getTitle() );
+ $clink = $this->linkRenderer->makeKnownLink( $cacheEntry->getTitle() );
// Log entries
} elseif ( $type == RC_LOG ) {
$logType = $cacheEntry->mAttribs['rc_log_type'];
$clink = $this->getLogLink( $logType );
} else {
wfDebugLog( 'recentchanges', 'Unexpected log entry with no log type in recent changes' );
- $clink = Linker::link( $cacheEntry->getTitle() );
+ $clink = $this->linkRenderer->makeLink( $cacheEntry->getTitle() );
}
// Log entries (old format) and special pages
} elseif ( $cacheEntry->mAttribs['rc_namespace'] == NS_SPECIAL ) {
$clink = '';
// Edits
} else {
- $clink = Linker::linkKnown( $cacheEntry->getTitle() );
+ $clink = $this->linkRenderer->makeKnownLink( $cacheEntry->getTitle() );
}
return $clink;
private function getLogLink( $logType ) {
$logtitle = SpecialPage::getTitleFor( 'Log', $logType );
$logpage = new LogPage( $logType );
- $logname = $logpage->getName()->escaped();
+ $logname = $logpage->getName()->text();
$logLink = $this->context->msg( 'parentheses' )
- ->rawParams( Linker::linkKnown( $logtitle, $logname ) )->escaped();
+ ->rawParams(
+ $this->linkRenderer->makeKnownLink( $logtitle, $logname )
+ )->escaped();
return $logLink;
}
$curLink = $curMessage;
} else {
$curUrl = htmlspecialchars( $cacheEntry->getTitle()->getLinkURL( $queryParams ) );
- $curLink = "<a href=\"$curUrl\" tabindex=\"$counter\">$curMessage</a>";
+ $curLink = "<a href=\"$curUrl\">$curMessage</a>";
}
return $curLink;
return $diffMessage;
}
$diffUrl = htmlspecialchars( $pageTitle->getLinkURL( $queryParams ) );
- $diffLink = "<a href=\"$diffUrl\" tabindex=\"$counter\">$diffMessage</a>";
+ $diffLink = "<a href=\"$diffUrl\">$diffMessage</a>";
} else {
$diffUrl = htmlspecialchars( $cacheEntry->getTitle()->getLinkURL( $queryParams ) );
- $diffLink = "<a href=\"$diffUrl\" tabindex=\"$counter\">$diffMessage</a>";
+ $diffLink = "<a href=\"$diffUrl\">$diffMessage</a>";
}
return $diffLink;
if ( !$showDiffLinks || !$lastOldid || in_array( $type, $logTypes ) ) {
$lastLink = $lastMessage;
} else {
- $lastLink = Linker::linkKnown(
+ $lastLink = $this->linkRenderer->makeKnownLink(
$cacheEntry->getTitle(),
- $lastMessage,
+ new HtmlArmor( $lastMessage ),
[],
$this->buildDiffQueryParams( $cacheEntry )
);
$tagUsage = self::tagUsageStatistics();
if ( !is_null( $user ) ) {
- if ( !$user->isAllowed( 'managechangetags' ) ) {
- return Status::newFatal( 'tags-manage-no-permission' );
+ if ( !$user->isAllowed( 'deletechangetags' ) ) {
+ return Status::newFatal( 'tags-delete-no-permission' );
} elseif ( $user->isBlocked() ) {
return Status::newFatal( 'tags-manage-blocked' );
}
'smn' => [ "Á", "Č", "Đ", "Ŋ", "Š", "Ŧ", "Ž", "Æ", "Ø", "Å", "Ä", "Ö" ],
'sq' => [ "Ç", "Dh", "Ë", "Gj", "Ll", "Nj", "Rr", "Sh", "Th", "Xh", "Zh" ],
'sr' => [],
+ 'ta' => [
+ "\xE0\xAE\x82", "ஃ", "க்ஷ", "க்", "ங்", "ச்", "ஞ்", "ட்", "ண்", "த்", "ந்",
+ "ப்", "ம்", "ய்", "ர்", "ல்", "வ்", "ழ்", "ள்", "ற்", "ன்", "ஜ்", "ஶ்", "ஷ்",
+ "ஸ்", "ஹ்", "க்ஷ்"
+ ],
'tk' => [ "Ç", "Ä", "Ž", "Ň", "Ö", "Ş", "Ü", "Ý" ],
'tl' => [ "Ñ", "Ng" ],
'tr' => [ "Ç", "Ğ", "İ", "Ö", "Ş", "Ü" ],
}
public function getSortKey( $string ) {
- // intl extension produces non null-terminated
- // strings. Appending '' fixes it so that it doesn't generate
- // a warning on each access in debug php.
- MediaWiki\suppressWarnings();
- $key = $this->mainCollator->getSortKey( $string ) . '';
- MediaWiki\restoreWarnings();
- return $key;
+ return $this->mainCollator->getSortKey( $string );
}
public function getPrimarySortKey( $string ) {
- MediaWiki\suppressWarnings();
- $key = $this->primaryCollator->getSortKey( $string ) . '';
- MediaWiki\restoreWarnings();
- return $key;
+ return $this->primaryCollator->getSortKey( $string );
}
public function getFirstLetter( $string ) {
/**
* @since 1.16.3
+ * @return array
*/
public function getFirstLetterData() {
- if ( $this->firstLetterData !== null ) {
- return $this->firstLetterData;
- }
-
- $cache = ObjectCache::getLocalServerInstance( CACHE_ANYTHING );
- $cacheKey = $cache->makeKey(
- 'first-letters',
- $this->locale,
- $this->digitTransformLanguage->getCode(),
- self::getICUVersion()
- );
- $cacheEntry = $cache->get( $cacheKey );
-
- if ( $cacheEntry && isset( $cacheEntry['version'] )
- && $cacheEntry['version'] == self::FIRST_LETTER_VERSION
- ) {
- $this->firstLetterData = $cacheEntry;
- return $this->firstLetterData;
+ if ( $this->firstLetterData === null ) {
+ $cache = ObjectCache::getLocalServerInstance( CACHE_ANYTHING );
+ $cacheKey = $cache->makeKey(
+ 'first-letters',
+ $this->locale,
+ $this->digitTransformLanguage->getCode(),
+ self::getICUVersion(),
+ self::FIRST_LETTER_VERSION
+ );
+ $this->firstLetterData = $cache->getWithSetCallback( $cacheKey, $cache::TTL_WEEK, function () {
+ return $this->fetchFirstLetterData();
+ } );
}
+ return $this->firstLetterData;
+ }
+ /**
+ * @return array
+ * @throws MWException
+ */
+ private function fetchFirstLetterData() {
// Generate data from serialized data file
-
if ( isset( self::$tailoringFirstLetters[$this->locale] ) ) {
- $letters = wfGetPrecompiledData( "first-letters-root.ser" );
+ $letters = wfGetPrecompiledData( 'first-letters-root.ser' );
// Append additional characters
$letters = array_merge( $letters, self::$tailoringFirstLetters[$this->locale] );
// Remove unnecessary ones, if any
$data = [
'chars' => array_values( $letterMap ),
'keys' => array_keys( $letterMap ),
- 'version' => self::FIRST_LETTER_VERSION,
];
// Reduce memory usage before caching
unset( $letterMap );
- // Save to cache
- $this->firstLetterData = $data;
- $cache->set( $cacheKey, $data, $cache::TTL_WEEK );
return $data;
}
* @since 1.16.3
*/
public function getLetterByIndex( $index ) {
- if ( $this->firstLetterData === null ) {
- $this->getFirstLetterData();
- }
- return $this->firstLetterData['chars'][$index];
+ return $this->getFirstLetterData()['chars'][$index];
}
/**
* @since 1.16.3
*/
public function getSortKeyByLetterIndex( $index ) {
- if ( $this->firstLetterData === null ) {
- $this->getFirstLetterData();
- }
- return $this->firstLetterData['keys'][$index];
+ return $this->getFirstLetterData()['keys'][$index];
}
/**
* @since 1.16.3
*/
public function getFirstLetterCount() {
- if ( $this->firstLetterData === null ) {
- $this->getFirstLetterData();
- }
- return count( $this->firstLetterData['chars'] );
+ return count( $this->getFirstLetterData()['chars'] );
}
/**
*
* @file
*/
+use MediaWiki\Services\SalvageableService;
+use Wikimedia\Assert\Assert;
/**
* Factory class to create Config objects
*
* @since 1.23
*/
-class ConfigFactory {
+class ConfigFactory implements SalvageableService {
/**
* Map of config name => callback
return \MediaWiki\MediaWikiServices::getInstance()->getConfigFactory();
}
+ /**
+ * Re-uses existing Cache objects from $other. Cache objects are only re-used if the
+ * registered factory function for both is the same. Cache config is not copied,
+ * and only instances of caches defined on this instance with the same config
+ * are copied.
+ *
+ * @see SalvageableService::salvage()
+ *
+ * @param SalvageableService $other The object to salvage state from. $other must have the
+ * exact same type as $this.
+ */
+ public function salvage( SalvageableService $other ) {
+ Assert::parameterType( self::class, $other, '$other' );
+
+ /** @var ConfigFactory $other */
+ foreach ( $other->factoryFunctions as $name => $otherFunc ) {
+ if ( !isset( $this->factoryFunctions[$name] ) ) {
+ continue;
+ }
+
+ // if the callback function is the same, salvage the Cache object
+ // XXX: Closures are never equal!
+ if ( isset( $other->configs[$name] )
+ && $this->factoryFunctions[$name] == $otherFunc
+ ) {
+ $this->configs[$name] = $other->configs[$name];
+ unset( $other->configs[$name] );
+ }
+ }
+
+ // disable $other
+ $other->factoryFunctions = [];
+ $other->configs = [];
+ }
+
/**
* @return string[]
*/
* @throws InvalidArgumentException If an invalid callback is provided
*/
public function register( $name, $callback ) {
- if ( $callback instanceof Config ) {
- $instance = $callback;
-
- // Register a callback anyway, for consistency. Note that getConfigNames()
- // relies on $factoryFunctions to have all config names.
- $callback = function() use ( $instance ) {
- return $instance;
- };
- } else {
- $instance = null;
- }
-
- if ( !is_callable( $callback ) ) {
+ if ( !is_callable( $callback ) && !( $callback instanceof Config ) ) {
throw new InvalidArgumentException( 'Invalid callback provided' );
}
- $this->configs[$name] = $instance;
+ unset( $this->configs[$name] );
$this->factoryFunctions[$name] = $callback;
}
if ( !isset( $this->factoryFunctions[$key] ) ) {
throw new ConfigException( "No registered builder available for $name." );
}
- $conf = call_user_func( $this->factoryFunctions[$key], $this );
+
+ if ( $this->factoryFunctions[$key] instanceof Config ) {
+ $conf = $this->factoryFunctions[$key];
+ } else {
+ $conf = call_user_func( $this->factoryFunctions[$key], $this );
+ }
+
if ( $conf instanceof Config ) {
$this->configs[$name] = $conf;
} else {
*
* @since 1.21
*
- * @return array Always an empty array.
+ * @return array An array mapping action names (typically "view", "edit", "history" etc.) to
+ * either the full qualified class name of an Action class, a callable taking ( Page $page,
+ * IContextSource $context = null ) as parameters and returning an Action object, or an actual
+ * Action object. An empty array in this default implementation.
+ *
+ * @see Action::factory
*/
public function getActionOverrides() {
return [];
throw new InvalidArgumentException( "Position not an instance of MySQLMasterPos" );
}
- if ( $this->lastKnownSlavePos && $this->lastKnownSlavePos->hasReached( $pos ) ) {
- return 0;
+ if ( $this->getLBInfo( 'is static' ) === true ) {
+ return 0; // this is a copy of a read-only dataset with no master DB
+ } elseif ( $this->lastKnownSlavePos && $this->lastKnownSlavePos->hasReached( $pos ) ) {
+ return 0; // already reached this point for sure
}
# Commit any open transactions
}
} );
}
+
+ /**
+ * Close all open database connections on all open load balancers.
+ * @since 1.28
+ */
+ public function closeAll() {
+ $this->forEachLBCallMethod( 'closeAll', [] );
+ }
+
}
/**
$lagTimes = $this->getLagTimes( $wiki );
foreach ( $lagTimes as $i => $lag ) {
- if ( $lag > $maxLag ) {
+ if ( $this->mLoads[$i] > 0 && $lag > $maxLag ) {
$maxLag = $lag;
$host = $this->mServers[$i]['host'];
$maxIndex = $i;
}
$pos = $pos ?: $this->getConnection( DB_MASTER )->getMasterPos();
- if ( !$pos ) {
+ if ( !( $pos instanceof DBMasterPos ) ) {
return false; // something is misconfigured
}
self::$enabled = true;
}
+ /**
+ * Disable the debugger.
+ *
+ * @since 1.28
+ */
+ public static function deinit() {
+ self::$enabled = false;
+ }
+
/**
* Add ResourceLoader modules to the OutputPage object if debugging is
* enabled.
// Reliably broadcast the purge to all edge nodes
$relayer = MediaWikiServices::getInstance()->getEventRelayerGroup()
->getRelayer( 'cdn-url-purges' );
- $relayer->notify(
+ $ts = microtime( true );
+ $relayer->notifyMulti(
'cdn-url-purges',
- [
- 'urls' => array_values( $urlArr ), // JSON array
- 'timestamp' => microtime( true )
- ]
+ array_map(
+ function ( $url ) use ( $ts ) {
+ return [
+ 'url' => $url,
+ 'timestamp' => $ts,
+ ];
+ },
+ $urlArr
+ )
);
// Send lossy UDP broadcasting if enabled
} elseif ( $pageId ) {
$this->pageId = $pageId;
} else {
- throw new MWException( "Page ID not known, perhaps the page doesn't exist?" );
+ throw new InvalidArgumentException( "Page ID not known. Page doesn't exist?" );
}
}
public function doUpdate() {
- # Page may already be deleted, so don't just getId()
+ $config = RequestContext::getMain()->getConfig();
+ $batchSize = $config->get( 'UpdateRowsPerQuery' );
+
+ // Page may already be deleted, so don't just getId()
$id = $this->pageId;
+ // Make sure all links update threads see the changes of each other.
+ // This handles the case when updates have to batched into several COMMITs.
+ $scopedLock = LinksUpdate::acquirePageLock( $this->mDb, $id );
- # Delete restrictions for it
+ // Delete restrictions for it
$this->mDb->delete( 'page_restrictions', [ 'pr_page' => $id ], __METHOD__ );
- # Fix category table counts
+ // Fix category table counts
$cats = $this->mDb->selectFieldValues(
'categorylinks',
'cl_to',
[ 'cl_from' => $id ],
__METHOD__
);
- $this->page->updateCategoryCounts( [], $cats );
+ $catBatches = array_chunk( $cats, $batchSize );
+ foreach ( $catBatches as $catBatch ) {
+ $this->page->updateCategoryCounts( [], $catBatch );
+ if ( count( $catBatches ) > 1 ) {
+ $this->mDb->commit( __METHOD__, 'flush' );
+ wfGetLBFactory()->waitForReplication( [ 'wiki' => $this->mDb->getWikiID() ] );
+ }
+ }
- # If using cascading deletes, we can skip some explicit deletes
+ // If using cascading deletes, we can skip some explicit deletes
if ( !$this->mDb->cascadingDeletes() ) {
- # Delete outgoing links
- $this->mDb->delete( 'pagelinks', [ 'pl_from' => $id ], __METHOD__ );
- $this->mDb->delete( 'imagelinks', [ 'il_from' => $id ], __METHOD__ );
- $this->mDb->delete( 'categorylinks', [ 'cl_from' => $id ], __METHOD__ );
- $this->mDb->delete( 'templatelinks', [ 'tl_from' => $id ], __METHOD__ );
- $this->mDb->delete( 'externallinks', [ 'el_from' => $id ], __METHOD__ );
- $this->mDb->delete( 'langlinks', [ 'll_from' => $id ], __METHOD__ );
- $this->mDb->delete( 'iwlinks', [ 'iwl_from' => $id ], __METHOD__ );
+ // Delete outgoing links
+ $this->batchDeleteByPK(
+ 'pagelinks',
+ [ 'pl_from' => $id ],
+ [ 'pl_from', 'pl_namespace', 'pl_title' ],
+ $batchSize
+ );
+ $this->batchDeleteByPK(
+ 'imagelinks',
+ [ 'il_from' => $id ],
+ [ 'il_from', 'il_to' ],
+ $batchSize
+ );
+ $this->batchDeleteByPK(
+ 'categorylinks',
+ [ 'cl_from' => $id ],
+ [ 'cl_from', 'cl_to' ],
+ $batchSize
+ );
+ $this->batchDeleteByPK(
+ 'templatelinks',
+ [ 'tl_from' => $id ],
+ [ 'tl_from', 'tl_namespace', 'tl_title' ],
+ $batchSize
+ );
+ $this->batchDeleteByPK(
+ 'externallinks',
+ [ 'el_from' => $id ],
+ [ 'el_id' ],
+ $batchSize
+ );
+ $this->batchDeleteByPK(
+ 'langlinks',
+ [ 'il_from' => $id ],
+ [ 'il_from', 'll_lang' ],
+ $batchSize
+ );
+ $this->batchDeleteByPK(
+ 'iwlinks',
+ [ 'il_from' => $id ],
+ [ 'iwl_from', 'iwl_prefix', 'iwl_title' ],
+ $batchSize
+ );
+ // Delete any redirect entry or page props entries
$this->mDb->delete( 'redirect', [ 'rd_from' => $id ], __METHOD__ );
$this->mDb->delete( 'page_props', [ 'pp_page' => $id ], __METHOD__ );
}
- # If using cleanup triggers, we can skip some manual deletes
+ // If using cleanup triggers, we can skip some manual deletes
if ( !$this->mDb->cleanupTriggers() ) {
$title = $this->page->getTitle();
- # Find recentchanges entries to clean up...
- $rcIdsForTitle = $this->mDb->selectFieldValues( 'recentchanges',
+ // Find recentchanges entries to clean up...
+ $rcIdsForTitle = $this->mDb->selectFieldValues(
+ 'recentchanges',
'rc_id',
[
'rc_type != ' . RC_LOG,
],
__METHOD__
);
- $rcIdsForPage = $this->mDb->selectFieldValues( 'recentchanges',
+ $rcIdsForPage = $this->mDb->selectFieldValues(
+ 'recentchanges',
'rc_id',
[ 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ],
__METHOD__
);
- # T98706: delete PK to avoid lock contention with RC delete log insertions
- $rcIds = array_merge( $rcIdsForTitle, $rcIdsForPage );
- if ( $rcIds ) {
- $this->mDb->delete( 'recentchanges', [ 'rc_id' => $rcIds ], __METHOD__ );
+ // T98706: delete by PK to avoid lock contention with RC delete log insertions
+ $rcIdBatches = array_chunk( array_merge( $rcIdsForTitle, $rcIdsForPage ), $batchSize );
+ foreach ( $rcIdBatches as $rcIdBatch ) {
+ $this->mDb->delete( 'recentchanges', [ 'rc_id' => $rcIdBatch ], __METHOD__ );
+ if ( count( $rcIdBatches ) > 1 ) {
+ $this->mDb->commit( __METHOD__, 'flush' );
+ wfGetLBFactory()->waitForReplication( [ 'wiki' => $this->mDb->getWikiID() ] );
+ }
}
}
+
+ $this->mDb->onTransactionIdle( function() use ( &$scopedLock ) {
+ // Release the lock *after* the final COMMIT for correctness
+ ScopedCallback::consume( $scopedLock );
+ } );
+ }
+
+ private function batchDeleteByPK( $table, array $conds, array $pk, $bSize ) {
+ $dbw = $this->mDb; // convenience
+ $res = $dbw->select( $table, $pk, $conds, __METHOD__ );
+
+ $pkDeleteConds = [];
+ foreach ( $res as $row ) {
+ $pkDeleteConds[] = $this->mDb->makeList( (array)$row, LIST_AND );
+ if ( count( $pkDeleteConds ) >= $bSize ) {
+ $dbw->delete( $table, $dbw->makeList( $pkDeleteConds, LIST_OR ), __METHOD__ );
+ $dbw->commit( __METHOD__, 'flush' );
+ wfGetLBFactory()->waitForReplication( [ 'wiki' => $dbw->getWikiID() ] );
+ $pkDeleteConds = [];
+ }
+ }
+
+ if ( $pkDeleteConds ) {
+ $dbw->delete( $table, $dbw->makeList( $pkDeleteConds, LIST_OR ), __METHOD__ );
+ }
}
public function getAsJobSpecification() {
*/
/**
- * See docs/deferred.txt
+ * Class the manages updates of *_link tables as well as similar extension-managed tables
+ *
+ * @note: LinksUpdate is managed by DeferredUpdates::execute(). Do not run this in a transaction.
*
- * @todo document (e.g. one-sentence top-level class description).
+ * See docs/deferred.txt
*/
class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate {
// @todo make members protected, but make sure extensions don't break
* @throws MWException
*/
function __construct( Title $title, ParserOutput $parserOutput, $recursive = true ) {
- parent::__construct( false ); // no implicit transaction
+ // Implicit transactions are disabled as they interfere with batching
+ parent::__construct( false );
$this->mTitle = $title;
$this->mId = $title->getArticleID( Title::GAID_FOR_UPDATE );
/**
* Update link tables with outgoing links from an updated article
+ *
+ * @note: this is managed by DeferredUpdates::execute(). Do not run this in a transaction.
*/
public function doUpdate() {
+ // Make sure all links update threads see the changes of each other.
+ // This handles the case when updates have to batched into several COMMITs.
+ $scopedLock = self::acquirePageLock( $this->mDb, $this->mId );
+
Hooks::run( 'LinksUpdate', [ &$this ] );
$this->doIncrementalUpdate();
- $this->mDb->onTransactionIdle( function() {
+ $this->mDb->onTransactionIdle( function() use ( &$scopedLock ) {
Hooks::run( 'LinksUpdateComplete', [ &$this ] );
+ // Release the lock *after* the final COMMIT for correctness
+ ScopedCallback::consume( $scopedLock );
} );
}
+ /**
+ * Acquire a lock for performing link table updates for a page on a DB
+ *
+ * @param IDatabase $dbw
+ * @param integer $pageId
+ * @return ScopedCallback|null Returns null on failure
+ * @throws RuntimeException
+ * @since 1.27
+ */
+ public static function acquirePageLock( IDatabase $dbw, $pageId ) {
+ $scopedLock = $dbw->getScopedLockAndFlush(
+ "LinksUpdate:pageid:$pageId",
+ __METHOD__,
+ 15
+ );
+ if ( !$scopedLock ) {
+ throw new RuntimeException( "Could not acquire lock on page #$pageId." );
+ }
+
+ return $scopedLock;
+ }
+
protected function doIncrementalUpdate() {
# Page links
$existing = $this->getExistingLinks();
# Image links
$existing = $this->getExistingImages();
-
$imageDeletes = $this->getImageDeletions( $existing );
$this->incrTableUpdate( 'imagelinks', 'il', $imageDeletes,
$this->getImageInsertions( $existing ) );
# Category links
$existing = $this->getExistingCategories();
-
$categoryDeletes = $this->getCategoryDeletions( $existing );
-
$this->incrTableUpdate( 'categorylinks', 'cl', $categoryDeletes,
$this->getCategoryInsertions( $existing ) );
# Page properties
$existing = $this->getExistingProperties();
-
$propertiesDeletes = $this->getPropertyDeletions( $existing );
-
$this->incrTableUpdate( 'page_props', 'pp', $propertiesDeletes,
$this->getPropertyInsertions( $existing ) );
* @param array $deletions
* @param array $insertions Rows to insert
*/
- function incrTableUpdate( $table, $prefix, $deletions, $insertions ) {
- if ( $table == 'page_props' ) {
+ private function incrTableUpdate( $table, $prefix, $deletions, $insertions ) {
+ $bSize = RequestContext::getMain()->getConfig()->get( 'UpdateRowsPerQuery' );
+
+ if ( $table === 'page_props' ) {
$fromField = 'pp_page';
} else {
$fromField = "{$prefix}_from";
}
- $where = [ $fromField => $this->mId ];
- if ( $table == 'pagelinks' || $table == 'templatelinks' || $table == 'iwlinks' ) {
- if ( $table == 'iwlinks' ) {
- $baseKey = 'iwl_prefix';
- } else {
- $baseKey = "{$prefix}_namespace";
+
+ $deleteWheres = []; // list of WHERE clause arrays for each DB delete() call
+ if ( $table === 'pagelinks' || $table === 'templatelinks' || $table === 'iwlinks' ) {
+ $baseKey = ( $table === 'iwlinks' ) ? 'iwl_prefix' : "{$prefix}_namespace";
+
+ $curBatchSize = 0;
+ $curDeletionBatch = [];
+ $deletionBatches = [];
+ foreach ( $deletions as $ns => $dbKeys ) {
+ foreach ( $dbKeys as $dbKey => $unused ) {
+ $curDeletionBatch[$ns][$dbKey] = 1;
+ if ( ++$curBatchSize >= $bSize ) {
+ $deletionBatches[] = $curDeletionBatch;
+ $curDeletionBatch = [];
+ $curBatchSize = 0;
+ }
+ }
}
- $clause = $this->mDb->makeWhereFrom2d( $deletions, $baseKey, "{$prefix}_title" );
- if ( $clause ) {
- $where[] = $clause;
- } else {
- $where = false;
+ if ( $curDeletionBatch ) {
+ $deletionBatches[] = $curDeletionBatch;
+ }
+
+ foreach ( $deletionBatches as $deletionBatch ) {
+ $deleteWheres[] = [
+ $fromField => $this->mId,
+ $this->mDb->makeWhereFrom2d( $deletionBatch, $baseKey, "{$prefix}_title" )
+ ];
}
} else {
- if ( $table == 'langlinks' ) {
+ if ( $table === 'langlinks' ) {
$toField = 'll_lang';
- } elseif ( $table == 'page_props' ) {
+ } elseif ( $table === 'page_props' ) {
$toField = 'pp_propname';
} else {
$toField = $prefix . '_to';
}
- if ( count( $deletions ) ) {
- $where[$toField] = array_keys( $deletions );
- } else {
- $where = false;
+
+ $deletionBatches = array_chunk( array_keys( $deletions ), $bSize );
+ foreach ( $deletionBatches as $deletionBatch ) {
+ $deleteWheres[] = [ $fromField => $this->mId, $toField => $deletionBatch ];
}
}
- if ( $where ) {
- $this->mDb->delete( $table, $where, __METHOD__ );
+
+ foreach ( $deleteWheres as $deleteWhere ) {
+ $this->mDb->delete( $table, $deleteWhere, __METHOD__ );
+ $this->mDb->commit( __METHOD__, 'flush' );
+ wfGetLBFactory()->waitForReplication( [ 'wiki' => $this->mDb->getWikiID() ] );
}
+
+ $insertBatches = array_chunk( $insertions, $bSize );
+ foreach ( $insertBatches as $insertBatch ) {
+ $this->mDb->insert( $table, $insertBatch, __METHOD__, 'IGNORE' );
+ $this->mDb->commit( __METHOD__, 'flush' );
+ wfGetLBFactory()->waitForReplication( [ 'wiki' => $this->mDb->getWikiID() ] );
+ }
+
if ( count( $insertions ) ) {
- $this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' );
Hooks::run( 'LinksUpdateAfterInsert', [ $this, $table, $insertions ] );
}
}
$this->mRevision = $revision;
}
+ /**
+ * @since 1.28
+ * @return null|Revision
+ */
+ public function getRevision() {
+ return $this->mRevision;
+ }
+
/**
* Set the User who triggered this LinksUpdate
*
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup DifferenceEngine
+ */
+
+namespace MediaWiki\Diff;
+
+use Exception;
+
+class ComplexityException extends Exception {
+ public function __construct() {
+ parent::__construct( 'Diff is too complex to generate' );
+ }
+}
}
}
-/**
- * Class used internally by Diff to actually compute the diffs.
- *
- * The algorithm used here is mostly lifted from the perl module
- * Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
- * http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
- *
- * More ideas are taken from:
- * http://www.ics.uci.edu/~eppstein/161/960229.html
- *
- * Some ideas (and a bit of code) are from analyze.c, from GNU
- * diffutils-2.7, which can be found at:
- * ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
- *
- * closingly, some ideas (subdivision by NCHUNKS > 2, and some optimizations)
- * are my own.
- *
- * Line length limits for robustness added by Tim Starling, 2005-08-31
- * Alternative implementation added by Guy Van den Broeck, 2008-07-30
- *
- * @author Geoffrey T. Dairiki, Tim Starling, Guy Van den Broeck
- * @private
- * @ingroup DifferenceEngine
- */
-class DiffEngine {
- const MAX_XREF_LENGTH = 10000;
-
- protected $xchanged, $ychanged;
-
- protected $xv = [], $yv = [];
- protected $xind = [], $yind = [];
-
- protected $seq = [], $in_seq = [];
-
- protected $lcs = 0;
-
- /**
- * @param string[] $from_lines
- * @param string[] $to_lines
- *
- * @return DiffOp[]
- */
- public function diff( $from_lines, $to_lines ) {
-
- // Diff and store locally
- $this->diffLocal( $from_lines, $to_lines );
-
- // Merge edits when possible
- $this->shiftBoundaries( $from_lines, $this->xchanged, $this->ychanged );
- $this->shiftBoundaries( $to_lines, $this->ychanged, $this->xchanged );
-
- // Compute the edit operations.
- $n_from = count( $from_lines );
- $n_to = count( $to_lines );
-
- $edits = [];
- $xi = $yi = 0;
- while ( $xi < $n_from || $yi < $n_to ) {
- assert( $yi < $n_to || $this->xchanged[$xi] );
- assert( $xi < $n_from || $this->ychanged[$yi] );
-
- // Skip matching "snake".
- $copy = [];
- while ( $xi < $n_from && $yi < $n_to
- && !$this->xchanged[$xi] && !$this->ychanged[$yi]
- ) {
- $copy[] = $from_lines[$xi++];
- ++$yi;
- }
- if ( $copy ) {
- $edits[] = new DiffOpCopy( $copy );
- }
-
- // Find deletes & adds.
- $delete = [];
- while ( $xi < $n_from && $this->xchanged[$xi] ) {
- $delete[] = $from_lines[$xi++];
- }
-
- $add = [];
- while ( $yi < $n_to && $this->ychanged[$yi] ) {
- $add[] = $to_lines[$yi++];
- }
-
- if ( $delete && $add ) {
- $edits[] = new DiffOpChange( $delete, $add );
- } elseif ( $delete ) {
- $edits[] = new DiffOpDelete( $delete );
- } elseif ( $add ) {
- $edits[] = new DiffOpAdd( $add );
- }
- }
-
- return $edits;
- }
-
- /**
- * @param string[] $from_lines
- * @param string[] $to_lines
- */
- private function diffLocal( $from_lines, $to_lines ) {
- $wikidiff3 = new WikiDiff3();
- $wikidiff3->diff( $from_lines, $to_lines );
- $this->xchanged = $wikidiff3->removed;
- $this->ychanged = $wikidiff3->added;
- }
-
- /**
- * Adjust inserts/deletes of identical lines to join changes
- * as much as possible.
- *
- * We do something when a run of changed lines include a
- * line at one end and has an excluded, identical line at the other.
- * We are free to choose which identical line is included.
- * `compareseq' usually chooses the one at the beginning,
- * but usually it is cleaner to consider the following identical line
- * to be the "change".
- *
- * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
- */
- private function shiftBoundaries( $lines, &$changed, $other_changed ) {
- $i = 0;
- $j = 0;
-
- assert( count( $lines ) == count( $changed ) );
- $len = count( $lines );
- $other_len = count( $other_changed );
-
- while ( 1 ) {
- /*
- * Scan forwards to find beginning of another run of changes.
- * Also keep track of the corresponding point in the other file.
- *
- * Throughout this code, $i and $j are adjusted together so that
- * the first $i elements of $changed and the first $j elements
- * of $other_changed both contain the same number of zeros
- * (unchanged lines).
- * Furthermore, $j is always kept so that $j == $other_len or
- * $other_changed[$j] == false.
- */
- while ( $j < $other_len && $other_changed[$j] ) {
- $j++;
- }
-
- while ( $i < $len && !$changed[$i] ) {
- assert( $j < $other_len && ! $other_changed[$j] );
- $i++;
- $j++;
- while ( $j < $other_len && $other_changed[$j] ) {
- $j++;
- }
- }
-
- if ( $i == $len ) {
- break;
- }
-
- $start = $i;
-
- // Find the end of this run of changes.
- while ( ++$i < $len && $changed[$i] ) {
- continue;
- }
-
- do {
- /*
- * Record the length of this run of changes, so that
- * we can later determine whether the run has grown.
- */
- $runlength = $i - $start;
-
- /*
- * Move the changed region back, so long as the
- * previous unchanged line matches the last changed one.
- * This merges with previous changed regions.
- */
- while ( $start > 0 && $lines[$start - 1] == $lines[$i - 1] ) {
- $changed[--$start] = 1;
- $changed[--$i] = false;
- while ( $start > 0 && $changed[$start - 1] ) {
- $start--;
- }
- assert( $j > 0 );
- while ( $other_changed[--$j] ) {
- continue;
- }
- assert( $j >= 0 && !$other_changed[$j] );
- }
-
- /*
- * Set CORRESPONDING to the end of the changed run, at the last
- * point where it corresponds to a changed run in the other file.
- * CORRESPONDING == LEN means no such point has been found.
- */
- $corresponding = $j < $other_len ? $i : $len;
-
- /*
- * Move the changed region forward, so long as the
- * first changed line matches the following unchanged one.
- * This merges with following changed regions.
- * Do this second, so that if there are no merges,
- * the changed region is moved forward as far as possible.
- */
- while ( $i < $len && $lines[$start] == $lines[$i] ) {
- $changed[$start++] = false;
- $changed[$i++] = 1;
- while ( $i < $len && $changed[$i] ) {
- $i++;
- }
-
- assert( $j < $other_len && ! $other_changed[$j] );
- $j++;
- if ( $j < $other_len && $other_changed[$j] ) {
- $corresponding = $i;
- while ( $j < $other_len && $other_changed[$j] ) {
- $j++;
- }
- }
- }
- } while ( $runlength != $i - $start );
-
- /*
- * If possible, move the fully-merged run of changes
- * back to a corresponding run in the other file.
- */
- while ( $corresponding < $i ) {
- $changed[--$start] = 1;
- $changed[--$i] = 0;
- assert( $j > 0 );
- while ( $other_changed[--$j] ) {
- continue;
- }
- assert( $j >= 0 && !$other_changed[$j] );
- }
- }
- }
-}
-
/**
* Class representing a 'diff' between two sequences of strings.
* @todo document
*/
public $edits;
+ /**
+ * @var int If this diff complexity is exceeded, a ComplexityException is thrown
+ * 0 means no limit.
+ */
+ protected $bailoutComplexity = 0;
+
/**
* Constructor.
* Computes diff between sequences of strings.
* @param string[] $from_lines An array of strings.
* Typically these are lines from a file.
* @param string[] $to_lines An array of strings.
+ * @throws \MediaWiki\Diff\ComplexityException
*/
public function __construct( $from_lines, $to_lines ) {
$eng = new DiffEngine;
+ $eng->setBailoutComplexity( $this->bailoutComplexity );
$this->edits = $eng->diff( $from_lines, $to_lines );
}
}
/**
- * @todo document, bad name.
- * @private
- * @ingroup DifferenceEngine
- */
-class MappedDiff extends Diff {
- /**
- * Constructor.
- *
- * Computes diff between sequences of strings.
- *
- * This can be used to compute things like
- * case-insensitve diffs, or diffs which ignore
- * changes in white-space.
- *
- * @param string[] $from_lines An array of strings.
- * Typically these are lines from a file.
- * @param string[] $to_lines An array of strings.
- * @param string[] $mapped_from_lines This array should
- * have the same size number of elements as $from_lines.
- * The elements in $mapped_from_lines and
- * $mapped_to_lines are what is actually compared
- * when computing the diff.
- * @param string[] $mapped_to_lines This array should
- * have the same number of elements as $to_lines.
- */
- public function __construct( $from_lines, $to_lines,
- $mapped_from_lines, $mapped_to_lines ) {
-
- assert( count( $from_lines ) == count( $mapped_from_lines ) );
- assert( count( $to_lines ) == count( $mapped_to_lines ) );
-
- parent::__construct( $mapped_from_lines, $mapped_to_lines );
-
- $xi = $yi = 0;
- $editCount = count( $this->edits );
- for ( $i = 0; $i < $editCount; $i++ ) {
- $orig = &$this->edits[$i]->orig;
- if ( is_array( $orig ) ) {
- $orig = array_slice( $from_lines, $xi, count( $orig ) );
- $xi += count( $orig );
- }
-
- $closing = &$this->edits[$i]->closing;
- if ( is_array( $closing ) ) {
- $closing = array_slice( $to_lines, $yi, count( $closing ) );
- $yi += count( $closing );
- }
- }
- }
-}
-
-/**
- * Additions by Axel Boldt follow, partly taken from diff.php, phpwiki-1.3.3
- */
-
-/**
- * @todo document
- * @private
- * @ingroup DifferenceEngine
- */
-class HWLDFWordAccumulator {
- public $insClass = ' class="diffchange diffchange-inline"';
- public $delClass = ' class="diffchange diffchange-inline"';
-
- private $lines = [];
- private $line = '';
- private $group = '';
- private $tag = '';
-
- /**
- * @param string $new_tag
- */
- private function flushGroup( $new_tag ) {
- if ( $this->group !== '' ) {
- if ( $this->tag == 'ins' ) {
- $this->line .= "<ins{$this->insClass}>" .
- htmlspecialchars( $this->group ) . '</ins>';
- } elseif ( $this->tag == 'del' ) {
- $this->line .= "<del{$this->delClass}>" .
- htmlspecialchars( $this->group ) . '</del>';
- } else {
- $this->line .= htmlspecialchars( $this->group );
- }
- }
- $this->group = '';
- $this->tag = $new_tag;
- }
-
- /**
- * @param string $new_tag
- */
- private function flushLine( $new_tag ) {
- $this->flushGroup( $new_tag );
- if ( $this->line != '' ) {
- array_push( $this->lines, $this->line );
- } else {
- # make empty lines visible by inserting an NBSP
- array_push( $this->lines, ' ' );
- }
- $this->line = '';
- }
-
- /**
- * @param string[] $words
- * @param string $tag
- */
- public function addWords( $words, $tag = '' ) {
- if ( $tag != $this->tag ) {
- $this->flushGroup( $tag );
- }
-
- foreach ( $words as $word ) {
- // new-line should only come as first char of word.
- if ( $word == '' ) {
- continue;
- }
- if ( $word[0] == "\n" ) {
- $this->flushLine( $tag );
- $word = substr( $word, 1 );
- }
- assert( !strstr( $word, "\n" ) );
- $this->group .= $word;
- }
- }
-
- /**
- * @return string[]
- */
- public function getLines() {
- $this->flushLine( '~done' );
-
- return $this->lines;
- }
-}
-
-/**
- * @todo document
- * @private
- * @ingroup DifferenceEngine
+ * @deprecated Alias for WordAccumulator, to be soon removed
*/
-class WordLevelDiff extends MappedDiff {
- const MAX_LINE_LENGTH = 10000;
-
- /**
- * @param string[] $orig_lines
- * @param string[] $closing_lines
- */
- public function __construct( $orig_lines, $closing_lines ) {
-
- list( $orig_words, $orig_stripped ) = $this->split( $orig_lines );
- list( $closing_words, $closing_stripped ) = $this->split( $closing_lines );
-
- parent::__construct( $orig_words, $closing_words,
- $orig_stripped, $closing_stripped );
- }
-
- /**
- * @param string[] $lines
- *
- * @return array[]
- */
- private function split( $lines ) {
-
- $words = [];
- $stripped = [];
- $first = true;
- foreach ( $lines as $line ) {
- # If the line is too long, just pretend the entire line is one big word
- # This prevents resource exhaustion problems
- if ( $first ) {
- $first = false;
- } else {
- $words[] = "\n";
- $stripped[] = "\n";
- }
- if ( strlen( $line ) > self::MAX_LINE_LENGTH ) {
- $words[] = $line;
- $stripped[] = $line;
- } else {
- $m = [];
- if ( preg_match_all( '/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs',
- $line, $m )
- ) {
- foreach ( $m[0] as $word ) {
- $words[] = $word;
- }
- foreach ( $m[1] as $stripped_word ) {
- $stripped[] = $stripped_word;
- }
- }
- }
- }
-
- return [ $words, $stripped ];
- }
-
- /**
- * @return string[]
- */
- public function orig() {
- $orig = new HWLDFWordAccumulator;
-
- foreach ( $this->edits as $edit ) {
- if ( $edit->type == 'copy' ) {
- $orig->addWords( $edit->orig );
- } elseif ( $edit->orig ) {
- $orig->addWords( $edit->orig, 'del' );
- }
- }
- $lines = $orig->getLines();
-
- return $lines;
- }
-
- /**
- * @return string[]
- */
- public function closing() {
- $closing = new HWLDFWordAccumulator;
-
- foreach ( $this->edits as $edit ) {
- if ( $edit->type == 'copy' ) {
- $closing->addWords( $edit->closing );
- } elseif ( $edit->closing ) {
- $closing->addWords( $edit->closing, 'ins' );
- }
- }
- $lines = $closing->getLines();
-
- return $lines;
- }
-
+class HWLDFWordAccumulator extends MediaWiki\Diff\WordAccumulator {
}
--- /dev/null
+<?php
+/**
+ * New version of the difference engine
+ *
+ * Copyright © 2008 Guy Van den Broeck <guy@guyvdb.eu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup DifferenceEngine
+ */
+use MediaWiki\Diff\ComplexityException;
+
+/**
+ * This diff implementation is mainly lifted from the LCS algorithm of the Eclipse project which
+ * in turn is based on Myers' "An O(ND) difference algorithm and its variations"
+ * (http://citeseer.ist.psu.edu/myers86ond.html) with range compression (see Wu et al.'s
+ * "An O(NP) Sequence Comparison Algorithm").
+ *
+ * This implementation supports an upper bound on the execution time.
+ *
+ * Some ideas (and a bit of code) are from analyze.c, from GNU
+ * diffutils-2.7, which can be found at:
+ * ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
+ *
+ * Complexity: O((M + N)D) worst case time, O(M + N + D^2) expected time, O(M + N) space
+ *
+ * @author Guy Van den Broeck, Geoffrey T. Dairiki, Tim Starling
+ * @ingroup DifferenceEngine
+ */
+class DiffEngine {
+
+ // Input variables
+ private $from;
+ private $to;
+ private $m;
+ private $n;
+
+ private $tooLong;
+ private $powLimit;
+
+ protected $bailoutComplexity = 0;
+
+ // State variables
+ private $maxDifferences;
+ private $lcsLengthCorrectedForHeuristic = false;
+
+ // Output variables
+ public $length;
+ public $removed;
+ public $added;
+ public $heuristicUsed;
+
+ function __construct( $tooLong = 2000000, $powLimit = 1.45 ) {
+ $this->tooLong = $tooLong;
+ $this->powLimit = $powLimit;
+ }
+
+ /**
+ * Performs diff
+ *
+ * @param string[] $from_lines
+ * @param string[] $to_lines
+ * @throws ComplexityException
+ *
+ * @return DiffOp[]
+ */
+ public function diff( $from_lines, $to_lines ) {
+
+ // Diff and store locally
+ $this->diffInternal( $from_lines, $to_lines );
+
+ // Merge edits when possible
+ $this->shiftBoundaries( $from_lines, $this->removed, $this->added );
+ $this->shiftBoundaries( $to_lines, $this->added, $this->removed );
+
+ // Compute the edit operations.
+ $n_from = count( $from_lines );
+ $n_to = count( $to_lines );
+
+ $edits = [];
+ $xi = $yi = 0;
+ while ( $xi < $n_from || $yi < $n_to ) {
+ assert( $yi < $n_to || $this->removed[$xi] );
+ assert( $xi < $n_from || $this->added[$yi] );
+
+ // Skip matching "snake".
+ $copy = [];
+ while ( $xi < $n_from && $yi < $n_to
+ && !$this->removed[$xi] && !$this->added[$yi]
+ ) {
+ $copy[] = $from_lines[$xi++];
+ ++$yi;
+ }
+ if ( $copy ) {
+ $edits[] = new DiffOpCopy( $copy );
+ }
+
+ // Find deletes & adds.
+ $delete = [];
+ while ( $xi < $n_from && $this->removed[$xi] ) {
+ $delete[] = $from_lines[$xi++];
+ }
+
+ $add = [];
+ while ( $yi < $n_to && $this->added[$yi] ) {
+ $add[] = $to_lines[$yi++];
+ }
+
+ if ( $delete && $add ) {
+ $edits[] = new DiffOpChange( $delete, $add );
+ } elseif ( $delete ) {
+ $edits[] = new DiffOpDelete( $delete );
+ } elseif ( $add ) {
+ $edits[] = new DiffOpAdd( $add );
+ }
+ }
+
+ return $edits;
+ }
+
+ /**
+ * Sets the complexity (in comparison operations) that can't be exceeded
+ * @param int $value
+ */
+ public function setBailoutComplexity( $value ) {
+ $this->bailoutComplexity = $value;
+ }
+
+ /**
+ * Adjust inserts/deletes of identical lines to join changes
+ * as much as possible.
+ *
+ * We do something when a run of changed lines include a
+ * line at one end and has an excluded, identical line at the other.
+ * We are free to choose which identical line is included.
+ * `compareseq' usually chooses the one at the beginning,
+ * but usually it is cleaner to consider the following identical line
+ * to be the "change".
+ *
+ * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
+ *
+ * @param string[] $lines
+ * @param string[] $changed
+ * @param string[] $other_changed
+ */
+ private function shiftBoundaries( array $lines, array &$changed, array $other_changed ) {
+ $i = 0;
+ $j = 0;
+
+ assert( count( $lines ) == count( $changed ) );
+ $len = count( $lines );
+ $other_len = count( $other_changed );
+
+ while ( 1 ) {
+ /*
+ * Scan forwards to find beginning of another run of changes.
+ * Also keep track of the corresponding point in the other file.
+ *
+ * Throughout this code, $i and $j are adjusted together so that
+ * the first $i elements of $changed and the first $j elements
+ * of $other_changed both contain the same number of zeros
+ * (unchanged lines).
+ * Furthermore, $j is always kept so that $j == $other_len or
+ * $other_changed[$j] == false.
+ */
+ while ( $j < $other_len && $other_changed[$j] ) {
+ $j++;
+ }
+
+ while ( $i < $len && !$changed[$i] ) {
+ assert( $j < $other_len && ! $other_changed[$j] );
+ $i++;
+ $j++;
+ while ( $j < $other_len && $other_changed[$j] ) {
+ $j++;
+ }
+ }
+
+ if ( $i == $len ) {
+ break;
+ }
+
+ $start = $i;
+
+ // Find the end of this run of changes.
+ while ( ++$i < $len && $changed[$i] ) {
+ continue;
+ }
+
+ do {
+ /*
+ * Record the length of this run of changes, so that
+ * we can later determine whether the run has grown.
+ */
+ $runlength = $i - $start;
+
+ /*
+ * Move the changed region back, so long as the
+ * previous unchanged line matches the last changed one.
+ * This merges with previous changed regions.
+ */
+ while ( $start > 0 && $lines[$start - 1] == $lines[$i - 1] ) {
+ $changed[--$start] = 1;
+ $changed[--$i] = false;
+ while ( $start > 0 && $changed[$start - 1] ) {
+ $start--;
+ }
+ assert( $j > 0 );
+ while ( $other_changed[--$j] ) {
+ continue;
+ }
+ assert( $j >= 0 && !$other_changed[$j] );
+ }
+
+ /*
+ * Set CORRESPONDING to the end of the changed run, at the last
+ * point where it corresponds to a changed run in the other file.
+ * CORRESPONDING == LEN means no such point has been found.
+ */
+ $corresponding = $j < $other_len ? $i : $len;
+
+ /*
+ * Move the changed region forward, so long as the
+ * first changed line matches the following unchanged one.
+ * This merges with following changed regions.
+ * Do this second, so that if there are no merges,
+ * the changed region is moved forward as far as possible.
+ */
+ while ( $i < $len && $lines[$start] == $lines[$i] ) {
+ $changed[$start++] = false;
+ $changed[$i++] = 1;
+ while ( $i < $len && $changed[$i] ) {
+ $i++;
+ }
+
+ assert( $j < $other_len && ! $other_changed[$j] );
+ $j++;
+ if ( $j < $other_len && $other_changed[$j] ) {
+ $corresponding = $i;
+ while ( $j < $other_len && $other_changed[$j] ) {
+ $j++;
+ }
+ }
+ }
+ } while ( $runlength != $i - $start );
+
+ /*
+ * If possible, move the fully-merged run of changes
+ * back to a corresponding run in the other file.
+ */
+ while ( $corresponding < $i ) {
+ $changed[--$start] = 1;
+ $changed[--$i] = 0;
+ assert( $j > 0 );
+ while ( $other_changed[--$j] ) {
+ continue;
+ }
+ assert( $j >= 0 && !$other_changed[$j] );
+ }
+ }
+ }
+
+ /**
+ * @param string[] $from
+ * @param string[] $to
+ * @throws ComplexityException
+ */
+ protected function diffInternal( array $from, array $to ) {
+ // remember initial lengths
+ $m = count( $from );
+ $n = count( $to );
+
+ $this->heuristicUsed = false;
+
+ // output
+ $removed = $m > 0 ? array_fill( 0, $m, true ) : [];
+ $added = $n > 0 ? array_fill( 0, $n, true ) : [];
+
+ // reduce the complexity for the next step (intentionally done twice)
+ // remove common tokens at the start
+ $i = 0;
+ while ( $i < $m && $i < $n && $from[$i] === $to[$i] ) {
+ $removed[$i] = $added[$i] = false;
+ unset( $from[$i], $to[$i] );
+ ++$i;
+ }
+
+ // remove common tokens at the end
+ $j = 1;
+ while ( $i + $j <= $m && $i + $j <= $n && $from[$m - $j] === $to[$n - $j] ) {
+ $removed[$m - $j] = $added[$n - $j] = false;
+ unset( $from[$m - $j], $to[$n - $j] );
+ ++$j;
+ }
+
+ $this->from = $newFromIndex = $this->to = $newToIndex = [];
+
+ // remove tokens not in both sequences
+ $shared = [];
+ foreach ( $from as $key ) {
+ $shared[$key] = false;
+ }
+
+ foreach ( $to as $index => &$el ) {
+ if ( array_key_exists( $el, $shared ) ) {
+ // keep it
+ $this->to[] = $el;
+ $shared[$el] = true;
+ $newToIndex[] = $index;
+ }
+ }
+ foreach ( $from as $index => &$el ) {
+ if ( $shared[$el] ) {
+ // keep it
+ $this->from[] = $el;
+ $newFromIndex[] = $index;
+ }
+ }
+
+ unset( $shared, $from, $to );
+
+ $this->m = count( $this->from );
+ $this->n = count( $this->to );
+
+ if ( $this->bailoutComplexity > 0 && $this->m * $this->n > $this->bailoutComplexity ) {
+ throw new ComplexityException();
+ }
+
+ $this->removed = $this->m > 0 ? array_fill( 0, $this->m, true ) : [];
+ $this->added = $this->n > 0 ? array_fill( 0, $this->n, true ) : [];
+
+ if ( $this->m == 0 || $this->n == 0 ) {
+ $this->length = 0;
+ } else {
+ $this->maxDifferences = ceil( ( $this->m + $this->n ) / 2.0 );
+ if ( $this->m * $this->n > $this->tooLong ) {
+ // limit complexity to D^POW_LIMIT for long sequences
+ $this->maxDifferences = floor( pow( $this->maxDifferences, $this->powLimit - 1.0 ) );
+ wfDebug( "Limiting max number of differences to $this->maxDifferences\n" );
+ }
+
+ /*
+ * The common prefixes and suffixes are always part of some LCS, include
+ * them now to reduce our search space
+ */
+ $max = min( $this->m, $this->n );
+ for ( $forwardBound = 0; $forwardBound < $max
+ && $this->from[$forwardBound] === $this->to[$forwardBound];
+ ++$forwardBound
+ ) {
+ $this->removed[$forwardBound] = $this->added[$forwardBound] = false;
+ }
+
+ $backBoundL1 = $this->m - 1;
+ $backBoundL2 = $this->n - 1;
+
+ while ( $backBoundL1 >= $forwardBound && $backBoundL2 >= $forwardBound
+ && $this->from[$backBoundL1] === $this->to[$backBoundL2]
+ ) {
+ $this->removed[$backBoundL1--] = $this->added[$backBoundL2--] = false;
+ }
+
+ $temp = array_fill( 0, $this->m + $this->n + 1, 0 );
+ $V = [ $temp, $temp ];
+ $snake = [ 0, 0, 0 ];
+
+ $this->length = $forwardBound + $this->m - $backBoundL1 - 1
+ + $this->lcs_rec(
+ $forwardBound,
+ $backBoundL1,
+ $forwardBound,
+ $backBoundL2,
+ $V,
+ $snake
+ );
+ }
+
+ $this->m = $m;
+ $this->n = $n;
+
+ $this->length += $i + $j - 1;
+
+ foreach ( $this->removed as $key => &$removed_elem ) {
+ if ( !$removed_elem ) {
+ $removed[$newFromIndex[$key]] = false;
+ }
+ }
+ foreach ( $this->added as $key => &$added_elem ) {
+ if ( !$added_elem ) {
+ $added[$newToIndex[$key]] = false;
+ }
+ }
+ $this->removed = $removed;
+ $this->added = $added;
+ }
+
+ function diff_range( $from_lines, $to_lines ) {
+ // Diff and store locally
+ $this->diff( $from_lines, $to_lines );
+ unset( $from_lines, $to_lines );
+
+ $ranges = [];
+ $xi = $yi = 0;
+ while ( $xi < $this->m || $yi < $this->n ) {
+ // Matching "snake".
+ while ( $xi < $this->m && $yi < $this->n
+ && !$this->removed[$xi]
+ && !$this->added[$yi]
+ ) {
+ ++$xi;
+ ++$yi;
+ }
+ // Find deletes & adds.
+ $xstart = $xi;
+ while ( $xi < $this->m && $this->removed[$xi] ) {
+ ++$xi;
+ }
+
+ $ystart = $yi;
+ while ( $yi < $this->n && $this->added[$yi] ) {
+ ++$yi;
+ }
+
+ if ( $xi > $xstart || $yi > $ystart ) {
+ $ranges[] = new RangeDifference( $xstart, $xi, $ystart, $yi );
+ }
+ }
+
+ return $ranges;
+ }
+
+ private function lcs_rec( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake ) {
+ // check that both sequences are non-empty
+ if ( $bottoml1 > $topl1 || $bottoml2 > $topl2 ) {
+ return 0;
+ }
+
+ $d = $this->find_middle_snake( $bottoml1, $topl1, $bottoml2,
+ $topl2, $V, $snake );
+
+ // need to store these so we don't lose them when they're
+ // overwritten by the recursion
+ $len = $snake[2];
+ $startx = $snake[0];
+ $starty = $snake[1];
+
+ // the middle snake is part of the LCS, store it
+ for ( $i = 0; $i < $len; ++$i ) {
+ $this->removed[$startx + $i] = $this->added[$starty + $i] = false;
+ }
+
+ if ( $d > 1 ) {
+ return $len
+ + $this->lcs_rec( $bottoml1, $startx - 1, $bottoml2,
+ $starty - 1, $V, $snake )
+ + $this->lcs_rec( $startx + $len, $topl1, $starty + $len,
+ $topl2, $V, $snake );
+ } elseif ( $d == 1 ) {
+ /*
+ * In this case the sequences differ by exactly 1 line. We have
+ * already saved all the lines after the difference in the for loop
+ * above, now we need to save all the lines before the difference.
+ */
+ $max = min( $startx - $bottoml1, $starty - $bottoml2 );
+ for ( $i = 0; $i < $max; ++$i ) {
+ $this->removed[$bottoml1 + $i] =
+ $this->added[$bottoml2 + $i] = false;
+ }
+
+ return $max + $len;
+ }
+
+ return $len;
+ }
+
+ private function find_middle_snake( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake ) {
+ $from = &$this->from;
+ $to = &$this->to;
+ $V0 = &$V[0];
+ $V1 = &$V[1];
+ $snake0 = &$snake[0];
+ $snake1 = &$snake[1];
+ $snake2 = &$snake[2];
+ $bottoml1_min_1 = $bottoml1 - 1;
+ $bottoml2_min_1 = $bottoml2 - 1;
+ $N = $topl1 - $bottoml1_min_1;
+ $M = $topl2 - $bottoml2_min_1;
+ $delta = $N - $M;
+ $maxabsx = $N + $bottoml1;
+ $maxabsy = $M + $bottoml2;
+ $limit = min( $this->maxDifferences, ceil( ( $N + $M ) / 2 ) );
+
+ // value_to_add_forward: a 0 or 1 that we add to the start
+ // offset to make it odd/even
+ if ( ( $M & 1 ) == 1 ) {
+ $value_to_add_forward = 1;
+ } else {
+ $value_to_add_forward = 0;
+ }
+
+ if ( ( $N & 1 ) == 1 ) {
+ $value_to_add_backward = 1;
+ } else {
+ $value_to_add_backward = 0;
+ }
+
+ $start_forward = -$M;
+ $end_forward = $N;
+ $start_backward = -$N;
+ $end_backward = $M;
+
+ $limit_min_1 = $limit - 1;
+ $limit_plus_1 = $limit + 1;
+
+ $V0[$limit_plus_1] = 0;
+ $V1[$limit_min_1] = $N;
+ $limit = min( $this->maxDifferences, ceil( ( $N + $M ) / 2 ) );
+
+ if ( ( $delta & 1 ) == 1 ) {
+ for ( $d = 0; $d <= $limit; ++$d ) {
+ $start_diag = max( $value_to_add_forward + $start_forward, -$d );
+ $end_diag = min( $end_forward, $d );
+ $value_to_add_forward = 1 - $value_to_add_forward;
+
+ // compute forward furthest reaching paths
+ for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
+ if ( $k == -$d || ( $k < $d
+ && $V0[$limit_min_1 + $k] < $V0[$limit_plus_1 + $k] )
+ ) {
+ $x = $V0[$limit_plus_1 + $k];
+ } else {
+ $x = $V0[$limit_min_1 + $k] + 1;
+ }
+
+ $absx = $snake0 = $x + $bottoml1;
+ $absy = $snake1 = $x - $k + $bottoml2;
+
+ while ( $absx < $maxabsx && $absy < $maxabsy && $from[$absx] === $to[$absy] ) {
+ ++$absx;
+ ++$absy;
+ }
+ $x = $absx - $bottoml1;
+
+ $snake2 = $absx - $snake0;
+ $V0[$limit + $k] = $x;
+ if ( $k >= $delta - $d + 1 && $k <= $delta + $d - 1
+ && $x >= $V1[$limit + $k - $delta]
+ ) {
+ return 2 * $d - 1;
+ }
+
+ // check to see if we can cut down the diagonal range
+ if ( $x >= $N && $end_forward > $k - 1 ) {
+ $end_forward = $k - 1;
+ } elseif ( $absy - $bottoml2 >= $M ) {
+ $start_forward = $k + 1;
+ $value_to_add_forward = 0;
+ }
+ }
+
+ $start_diag = max( $value_to_add_backward + $start_backward, -$d );
+ $end_diag = min( $end_backward, $d );
+ $value_to_add_backward = 1 - $value_to_add_backward;
+
+ // compute backward furthest reaching paths
+ for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
+ if ( $k == $d
+ || ( $k != -$d && $V1[$limit_min_1 + $k] < $V1[$limit_plus_1 + $k] )
+ ) {
+ $x = $V1[$limit_min_1 + $k];
+ } else {
+ $x = $V1[$limit_plus_1 + $k] - 1;
+ }
+
+ $y = $x - $k - $delta;
+
+ $snake2 = 0;
+ while ( $x > 0 && $y > 0
+ && $from[$x + $bottoml1_min_1] === $to[$y + $bottoml2_min_1]
+ ) {
+ --$x;
+ --$y;
+ ++$snake2;
+ }
+ $V1[$limit + $k] = $x;
+
+ // check to see if we can cut down our diagonal range
+ if ( $x <= 0 ) {
+ $start_backward = $k + 1;
+ $value_to_add_backward = 0;
+ } elseif ( $y <= 0 && $end_backward > $k - 1 ) {
+ $end_backward = $k - 1;
+ }
+ }
+ }
+ } else {
+ for ( $d = 0; $d <= $limit; ++$d ) {
+ $start_diag = max( $value_to_add_forward + $start_forward, -$d );
+ $end_diag = min( $end_forward, $d );
+ $value_to_add_forward = 1 - $value_to_add_forward;
+
+ // compute forward furthest reaching paths
+ for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
+ if ( $k == -$d
+ || ( $k < $d && $V0[$limit_min_1 + $k] < $V0[$limit_plus_1 + $k] )
+ ) {
+ $x = $V0[$limit_plus_1 + $k];
+ } else {
+ $x = $V0[$limit_min_1 + $k] + 1;
+ }
+
+ $absx = $snake0 = $x + $bottoml1;
+ $absy = $snake1 = $x - $k + $bottoml2;
+
+ while ( $absx < $maxabsx && $absy < $maxabsy && $from[$absx] === $to[$absy] ) {
+ ++$absx;
+ ++$absy;
+ }
+ $x = $absx - $bottoml1;
+ $snake2 = $absx - $snake0;
+ $V0[$limit + $k] = $x;
+
+ // check to see if we can cut down the diagonal range
+ if ( $x >= $N && $end_forward > $k - 1 ) {
+ $end_forward = $k - 1;
+ } elseif ( $absy - $bottoml2 >= $M ) {
+ $start_forward = $k + 1;
+ $value_to_add_forward = 0;
+ }
+ }
+
+ $start_diag = max( $value_to_add_backward + $start_backward, -$d );
+ $end_diag = min( $end_backward, $d );
+ $value_to_add_backward = 1 - $value_to_add_backward;
+
+ // compute backward furthest reaching paths
+ for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
+ if ( $k == $d
+ || ( $k != -$d && $V1[$limit_min_1 + $k] < $V1[$limit_plus_1 + $k] )
+ ) {
+ $x = $V1[$limit_min_1 + $k];
+ } else {
+ $x = $V1[$limit_plus_1 + $k] - 1;
+ }
+
+ $y = $x - $k - $delta;
+
+ $snake2 = 0;
+ while ( $x > 0 && $y > 0
+ && $from[$x + $bottoml1_min_1] === $to[$y + $bottoml2_min_1]
+ ) {
+ --$x;
+ --$y;
+ ++$snake2;
+ }
+ $V1[$limit + $k] = $x;
+
+ if ( $k >= -$delta - $d && $k <= $d - $delta
+ && $x <= $V0[$limit + $k + $delta]
+ ) {
+ $snake0 = $bottoml1 + $x;
+ $snake1 = $bottoml2 + $y;
+
+ return 2 * $d;
+ }
+
+ // check to see if we can cut down our diagonal range
+ if ( $x <= 0 ) {
+ $start_backward = $k + 1;
+ $value_to_add_backward = 0;
+ } elseif ( $y <= 0 && $end_backward > $k - 1 ) {
+ $end_backward = $k - 1;
+ }
+ }
+ }
+ }
+ /*
+ * computing the true LCS is too expensive, instead find the diagonal
+ * with the most progress and pretend a midle snake of length 0 occurs
+ * there.
+ */
+
+ $most_progress = self::findMostProgress( $M, $N, $limit, $V );
+
+ $snake0 = $bottoml1 + $most_progress[0];
+ $snake1 = $bottoml2 + $most_progress[1];
+ $snake2 = 0;
+ wfDebug( "Computing the LCS is too expensive. Using a heuristic.\n" );
+ $this->heuristicUsed = true;
+
+ return 5; /*
+ * HACK: since we didn't really finish the LCS computation
+ * we don't really know the length of the SES. We don't do
+ * anything with the result anyway, unless it's <=1. We know
+ * for a fact SES > 1 so 5 is as good a number as any to
+ * return here
+ */
+ }
+
+ private static function findMostProgress( $M, $N, $limit, $V ) {
+ $delta = $N - $M;
+
+ if ( ( $M & 1 ) == ( $limit & 1 ) ) {
+ $forward_start_diag = max( -$M, -$limit );
+ } else {
+ $forward_start_diag = max( 1 - $M, -$limit );
+ }
+
+ $forward_end_diag = min( $N, $limit );
+
+ if ( ( $N & 1 ) == ( $limit & 1 ) ) {
+ $backward_start_diag = max( -$N, -$limit );
+ } else {
+ $backward_start_diag = max( 1 - $N, -$limit );
+ }
+
+ $backward_end_diag = -min( $M, $limit );
+
+ $temp = [ 0, 0, 0 ];
+
+ $max_progress = array_fill( 0, ceil( max( $forward_end_diag - $forward_start_diag,
+ $backward_end_diag - $backward_start_diag ) / 2 ), $temp );
+ $num_progress = 0; // the 1st entry is current, it is initialized
+ // with 0s
+
+ // first search the forward diagonals
+ for ( $k = $forward_start_diag; $k <= $forward_end_diag; $k += 2 ) {
+ $x = $V[0][$limit + $k];
+ $y = $x - $k;
+ if ( $x > $N || $y > $M ) {
+ continue;
+ }
+
+ $progress = $x + $y;
+ if ( $progress > $max_progress[0][2] ) {
+ $num_progress = 0;
+ $max_progress[0][0] = $x;
+ $max_progress[0][1] = $y;
+ $max_progress[0][2] = $progress;
+ } elseif ( $progress == $max_progress[0][2] ) {
+ ++$num_progress;
+ $max_progress[$num_progress][0] = $x;
+ $max_progress[$num_progress][1] = $y;
+ $max_progress[$num_progress][2] = $progress;
+ }
+ }
+
+ $max_progress_forward = true; // initially the maximum
+ // progress is in the forward
+ // direction
+
+ // now search the backward diagonals
+ for ( $k = $backward_start_diag; $k <= $backward_end_diag; $k += 2 ) {
+ $x = $V[1][$limit + $k];
+ $y = $x - $k - $delta;
+ if ( $x < 0 || $y < 0 ) {
+ continue;
+ }
+
+ $progress = $N - $x + $M - $y;
+ if ( $progress > $max_progress[0][2] ) {
+ $num_progress = 0;
+ $max_progress_forward = false;
+ $max_progress[0][0] = $x;
+ $max_progress[0][1] = $y;
+ $max_progress[0][2] = $progress;
+ } elseif ( $progress == $max_progress[0][2] && !$max_progress_forward ) {
+ ++$num_progress;
+ $max_progress[$num_progress][0] = $x;
+ $max_progress[$num_progress][1] = $y;
+ $max_progress[$num_progress][2] = $progress;
+ }
+ }
+
+ // return the middle diagonal with maximal progress.
+ return $max_progress[(int)floor( $num_progress / 2 )];
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getLcsLength() {
+ if ( $this->heuristicUsed && !$this->lcsLengthCorrectedForHeuristic ) {
+ $this->lcsLengthCorrectedForHeuristic = true;
+ $this->length = $this->m - array_sum( $this->added );
+ }
+
+ return $this->length;
+ }
+
+}
+
+/**
+ * Alternative representation of a set of changes, by the index
+ * ranges that are changed.
+ *
+ * @ingroup DifferenceEngine
+ */
+class RangeDifference {
+
+ /** @var int */
+ public $leftstart;
+
+ /** @var int */
+ public $leftend;
+
+ /** @var int */
+ public $leftlength;
+
+ /** @var int */
+ public $rightstart;
+
+ /** @var int */
+ public $rightend;
+
+ /** @var int */
+ public $rightlength;
+
+ function __construct( $leftstart, $leftend, $rightstart, $rightend ) {
+ $this->leftstart = $leftstart;
+ $this->leftend = $leftend;
+ $this->leftlength = $leftend - $leftstart;
+ $this->rightstart = $rightstart;
+ $this->rightend = $rightend;
+ $this->rightlength = $rightend - $rightstart;
+ }
+
+}
if ( !$linkInfo ) {
$this->mMarkPatrolledLink = '';
} else {
- $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown(
- $this->mNewPage,
- $this->msg( 'markaspatrolleddiff' )->escaped(),
- [],
- [
- 'action' => 'markpatrolled',
- 'rcid' => $linkInfo['rcid'],
- 'token' => $linkInfo['token'],
- ]
- ) . ']</span>';
+ $this->mMarkPatrolledLink = ' <span class="patrollink" data-mw="interface">[' .
+ Linker::linkKnown(
+ $this->mNewPage,
+ $this->msg( 'markaspatrolleddiff' )->escaped(),
+ [],
+ [
+ 'action' => 'markpatrolled',
+ 'rcid' => $linkInfo['rcid'],
+ 'token' => $linkInfo['token'],
+ ]
+ ) . ']</span>';
}
}
return $this->mMarkPatrolledLink;
* @return bool|string
*/
public function generateTextDiffBody( $otext, $ntext ) {
- $time = microtime( true );
+ $diff = function() use ( $otext, $ntext ) {
+ $time = microtime( true );
- $result = $this->textDiff( $otext, $ntext );
+ $result = $this->textDiff( $otext, $ntext );
- $time = intval( ( microtime( true ) - $time ) * 1000 );
- $this->getStats()->timing( 'diff_time', $time );
- // Log requests slower than 99th percentile
- if ( $time > 100 && $this->mOldPage && $this->mNewPage ) {
- wfDebugLog( 'diff',
- "$time ms diff: {$this->mOldid} -> {$this->mNewid} {$this->mNewPage}" );
+ $time = intval( ( microtime( true ) - $time ) * 1000 );
+ $this->getStats()->timing( 'diff_time', $time );
+ // Log requests slower than 99th percentile
+ if ( $time > 100 && $this->mOldPage && $this->mNewPage ) {
+ wfDebugLog( 'diff',
+ "$time ms diff: {$this->mOldid} -> {$this->mNewid} {$this->mNewPage}" );
+ }
+
+ return $result;
+ };
+
+ $error = function( $status ) {
+ throw new FatalError( $status->getWikiText() );
+ };
+
+ // Use PoolCounter if the diff looks like it can be expensive
+ if ( strlen( $otext ) + strlen( $ntext ) > 20000 ) {
+ $work = new PoolCounterWorkViaCallback( 'diff',
+ md5( $otext ) . md5( $ntext ),
+ [ 'doWork' => $diff, 'error' => $error ]
+ );
+ return $work->execute();
}
- return $result;
+ return $diff();
}
/**
+++ /dev/null
-<?php
-/**
- * New version of the difference engine
- *
- * Copyright © 2008 Guy Van den Broeck <guy@guyvdb.eu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup DifferenceEngine
- */
-
-/**
- * This diff implementation is mainly lifted from the LCS algorithm of the Eclipse project which
- * in turn is based on Myers' "An O(ND) difference algorithm and its variations"
- * (http://citeseer.ist.psu.edu/myers86ond.html) with range compression (see Wu et al.'s
- * "An O(NP) Sequence Comparison Algorithm").
- *
- * This implementation supports an upper bound on the execution time.
- *
- * Complexity: O((M + N)D) worst case time, O(M + N + D^2) expected time, O(M + N) space
- *
- * @author Guy Van den Broeck
- * @ingroup DifferenceEngine
- */
-class WikiDiff3 {
-
- // Input variables
- private $from;
- private $to;
- private $m;
- private $n;
-
- private $tooLong;
- private $powLimit;
-
- // State variables
- private $maxDifferences;
- private $lcsLengthCorrectedForHeuristic = false;
-
- // Output variables
- public $length;
- public $removed;
- public $added;
- public $heuristicUsed;
-
- function __construct( $tooLong = 2000000, $powLimit = 1.45 ) {
- $this->tooLong = $tooLong;
- $this->powLimit = $powLimit;
- }
-
- public function diff( /*array*/ $from, /*array*/ $to ) {
- // remember initial lengths
- $m = count( $from );
- $n = count( $to );
-
- $this->heuristicUsed = false;
-
- // output
- $removed = $m > 0 ? array_fill( 0, $m, true ) : [];
- $added = $n > 0 ? array_fill( 0, $n, true ) : [];
-
- // reduce the complexity for the next step (intentionally done twice)
- // remove common tokens at the start
- $i = 0;
- while ( $i < $m && $i < $n && $from[$i] === $to[$i] ) {
- $removed[$i] = $added[$i] = false;
- unset( $from[$i], $to[$i] );
- ++$i;
- }
-
- // remove common tokens at the end
- $j = 1;
- while ( $i + $j <= $m && $i + $j <= $n && $from[$m - $j] === $to[$n - $j] ) {
- $removed[$m - $j] = $added[$n - $j] = false;
- unset( $from[$m - $j], $to[$n - $j] );
- ++$j;
- }
-
- $this->from = $newFromIndex = $this->to = $newToIndex = [];
-
- // remove tokens not in both sequences
- $shared = [];
- foreach ( $from as $key ) {
- $shared[$key] = false;
- }
-
- foreach ( $to as $index => &$el ) {
- if ( array_key_exists( $el, $shared ) ) {
- // keep it
- $this->to[] = $el;
- $shared[$el] = true;
- $newToIndex[] = $index;
- }
- }
- foreach ( $from as $index => &$el ) {
- if ( $shared[$el] ) {
- // keep it
- $this->from[] = $el;
- $newFromIndex[] = $index;
- }
- }
-
- unset( $shared, $from, $to );
-
- $this->m = count( $this->from );
- $this->n = count( $this->to );
-
- $this->removed = $this->m > 0 ? array_fill( 0, $this->m, true ) : [];
- $this->added = $this->n > 0 ? array_fill( 0, $this->n, true ) : [];
-
- if ( $this->m == 0 || $this->n == 0 ) {
- $this->length = 0;
- } else {
- $this->maxDifferences = ceil( ( $this->m + $this->n ) / 2.0 );
- if ( $this->m * $this->n > $this->tooLong ) {
- // limit complexity to D^POW_LIMIT for long sequences
- $this->maxDifferences = floor( pow( $this->maxDifferences, $this->powLimit - 1.0 ) );
- wfDebug( "Limiting max number of differences to $this->maxDifferences\n" );
- }
-
- /*
- * The common prefixes and suffixes are always part of some LCS, include
- * them now to reduce our search space
- */
- $max = min( $this->m, $this->n );
- for ( $forwardBound = 0; $forwardBound < $max
- && $this->from[$forwardBound] === $this->to[$forwardBound];
- ++$forwardBound
- ) {
- $this->removed[$forwardBound] = $this->added[$forwardBound] = false;
- }
-
- $backBoundL1 = $this->m - 1;
- $backBoundL2 = $this->n - 1;
-
- while ( $backBoundL1 >= $forwardBound && $backBoundL2 >= $forwardBound
- && $this->from[$backBoundL1] === $this->to[$backBoundL2]
- ) {
- $this->removed[$backBoundL1--] = $this->added[$backBoundL2--] = false;
- }
-
- $temp = array_fill( 0, $this->m + $this->n + 1, 0 );
- $V = [ $temp, $temp ];
- $snake = [ 0, 0, 0 ];
-
- $this->length = $forwardBound + $this->m - $backBoundL1 - 1
- + $this->lcs_rec(
- $forwardBound,
- $backBoundL1,
- $forwardBound,
- $backBoundL2,
- $V,
- $snake
- );
- }
-
- $this->m = $m;
- $this->n = $n;
-
- $this->length += $i + $j - 1;
-
- foreach ( $this->removed as $key => &$removed_elem ) {
- if ( !$removed_elem ) {
- $removed[$newFromIndex[$key]] = false;
- }
- }
- foreach ( $this->added as $key => &$added_elem ) {
- if ( !$added_elem ) {
- $added[$newToIndex[$key]] = false;
- }
- }
- $this->removed = $removed;
- $this->added = $added;
- }
-
- function diff_range( $from_lines, $to_lines ) {
- // Diff and store locally
- $this->diff( $from_lines, $to_lines );
- unset( $from_lines, $to_lines );
-
- $ranges = [];
- $xi = $yi = 0;
- while ( $xi < $this->m || $yi < $this->n ) {
- // Matching "snake".
- while ( $xi < $this->m && $yi < $this->n
- && !$this->removed[$xi]
- && !$this->added[$yi]
- ) {
- ++$xi;
- ++$yi;
- }
- // Find deletes & adds.
- $xstart = $xi;
- while ( $xi < $this->m && $this->removed[$xi] ) {
- ++$xi;
- }
-
- $ystart = $yi;
- while ( $yi < $this->n && $this->added[$yi] ) {
- ++$yi;
- }
-
- if ( $xi > $xstart || $yi > $ystart ) {
- $ranges[] = new RangeDifference( $xstart, $xi, $ystart, $yi );
- }
- }
-
- return $ranges;
- }
-
- private function lcs_rec( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake ) {
- // check that both sequences are non-empty
- if ( $bottoml1 > $topl1 || $bottoml2 > $topl2 ) {
- return 0;
- }
-
- $d = $this->find_middle_snake( $bottoml1, $topl1, $bottoml2,
- $topl2, $V, $snake );
-
- // need to store these so we don't lose them when they're
- // overwritten by the recursion
- $len = $snake[2];
- $startx = $snake[0];
- $starty = $snake[1];
-
- // the middle snake is part of the LCS, store it
- for ( $i = 0; $i < $len; ++$i ) {
- $this->removed[$startx + $i] = $this->added[$starty + $i] = false;
- }
-
- if ( $d > 1 ) {
- return $len
- + $this->lcs_rec( $bottoml1, $startx - 1, $bottoml2,
- $starty - 1, $V, $snake )
- + $this->lcs_rec( $startx + $len, $topl1, $starty + $len,
- $topl2, $V, $snake );
- } elseif ( $d == 1 ) {
- /*
- * In this case the sequences differ by exactly 1 line. We have
- * already saved all the lines after the difference in the for loop
- * above, now we need to save all the lines before the difference.
- */
- $max = min( $startx - $bottoml1, $starty - $bottoml2 );
- for ( $i = 0; $i < $max; ++$i ) {
- $this->removed[$bottoml1 + $i] =
- $this->added[$bottoml2 + $i] = false;
- }
-
- return $max + $len;
- }
-
- return $len;
- }
-
- private function find_middle_snake( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake ) {
- $from = &$this->from;
- $to = &$this->to;
- $V0 = &$V[0];
- $V1 = &$V[1];
- $snake0 = &$snake[0];
- $snake1 = &$snake[1];
- $snake2 = &$snake[2];
- $bottoml1_min_1 = $bottoml1 - 1;
- $bottoml2_min_1 = $bottoml2 - 1;
- $N = $topl1 - $bottoml1_min_1;
- $M = $topl2 - $bottoml2_min_1;
- $delta = $N - $M;
- $maxabsx = $N + $bottoml1;
- $maxabsy = $M + $bottoml2;
- $limit = min( $this->maxDifferences, ceil( ( $N + $M ) / 2 ) );
-
- // value_to_add_forward: a 0 or 1 that we add to the start
- // offset to make it odd/even
- if ( ( $M & 1 ) == 1 ) {
- $value_to_add_forward = 1;
- } else {
- $value_to_add_forward = 0;
- }
-
- if ( ( $N & 1 ) == 1 ) {
- $value_to_add_backward = 1;
- } else {
- $value_to_add_backward = 0;
- }
-
- $start_forward = -$M;
- $end_forward = $N;
- $start_backward = -$N;
- $end_backward = $M;
-
- $limit_min_1 = $limit - 1;
- $limit_plus_1 = $limit + 1;
-
- $V0[$limit_plus_1] = 0;
- $V1[$limit_min_1] = $N;
- $limit = min( $this->maxDifferences, ceil( ( $N + $M ) / 2 ) );
-
- if ( ( $delta & 1 ) == 1 ) {
- for ( $d = 0; $d <= $limit; ++$d ) {
- $start_diag = max( $value_to_add_forward + $start_forward, -$d );
- $end_diag = min( $end_forward, $d );
- $value_to_add_forward = 1 - $value_to_add_forward;
-
- // compute forward furthest reaching paths
- for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
- if ( $k == -$d || ( $k < $d
- && $V0[$limit_min_1 + $k] < $V0[$limit_plus_1 + $k] )
- ) {
- $x = $V0[$limit_plus_1 + $k];
- } else {
- $x = $V0[$limit_min_1 + $k] + 1;
- }
-
- $absx = $snake0 = $x + $bottoml1;
- $absy = $snake1 = $x - $k + $bottoml2;
-
- while ( $absx < $maxabsx && $absy < $maxabsy && $from[$absx] === $to[$absy] ) {
- ++$absx;
- ++$absy;
- }
- $x = $absx - $bottoml1;
-
- $snake2 = $absx - $snake0;
- $V0[$limit + $k] = $x;
- if ( $k >= $delta - $d + 1 && $k <= $delta + $d - 1
- && $x >= $V1[$limit + $k - $delta]
- ) {
- return 2 * $d - 1;
- }
-
- // check to see if we can cut down the diagonal range
- if ( $x >= $N && $end_forward > $k - 1 ) {
- $end_forward = $k - 1;
- } elseif ( $absy - $bottoml2 >= $M ) {
- $start_forward = $k + 1;
- $value_to_add_forward = 0;
- }
- }
-
- $start_diag = max( $value_to_add_backward + $start_backward, -$d );
- $end_diag = min( $end_backward, $d );
- $value_to_add_backward = 1 - $value_to_add_backward;
-
- // compute backward furthest reaching paths
- for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
- if ( $k == $d
- || ( $k != -$d && $V1[$limit_min_1 + $k] < $V1[$limit_plus_1 + $k] )
- ) {
- $x = $V1[$limit_min_1 + $k];
- } else {
- $x = $V1[$limit_plus_1 + $k] - 1;
- }
-
- $y = $x - $k - $delta;
-
- $snake2 = 0;
- while ( $x > 0 && $y > 0
- && $from[$x + $bottoml1_min_1] === $to[$y + $bottoml2_min_1]
- ) {
- --$x;
- --$y;
- ++$snake2;
- }
- $V1[$limit + $k] = $x;
-
- // check to see if we can cut down our diagonal range
- if ( $x <= 0 ) {
- $start_backward = $k + 1;
- $value_to_add_backward = 0;
- } elseif ( $y <= 0 && $end_backward > $k - 1 ) {
- $end_backward = $k - 1;
- }
- }
- }
- } else {
- for ( $d = 0; $d <= $limit; ++$d ) {
- $start_diag = max( $value_to_add_forward + $start_forward, -$d );
- $end_diag = min( $end_forward, $d );
- $value_to_add_forward = 1 - $value_to_add_forward;
-
- // compute forward furthest reaching paths
- for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
- if ( $k == -$d
- || ( $k < $d && $V0[$limit_min_1 + $k] < $V0[$limit_plus_1 + $k] )
- ) {
- $x = $V0[$limit_plus_1 + $k];
- } else {
- $x = $V0[$limit_min_1 + $k] + 1;
- }
-
- $absx = $snake0 = $x + $bottoml1;
- $absy = $snake1 = $x - $k + $bottoml2;
-
- while ( $absx < $maxabsx && $absy < $maxabsy && $from[$absx] === $to[$absy] ) {
- ++$absx;
- ++$absy;
- }
- $x = $absx - $bottoml1;
- $snake2 = $absx - $snake0;
- $V0[$limit + $k] = $x;
-
- // check to see if we can cut down the diagonal range
- if ( $x >= $N && $end_forward > $k - 1 ) {
- $end_forward = $k - 1;
- } elseif ( $absy - $bottoml2 >= $M ) {
- $start_forward = $k + 1;
- $value_to_add_forward = 0;
- }
- }
-
- $start_diag = max( $value_to_add_backward + $start_backward, -$d );
- $end_diag = min( $end_backward, $d );
- $value_to_add_backward = 1 - $value_to_add_backward;
-
- // compute backward furthest reaching paths
- for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
- if ( $k == $d
- || ( $k != -$d && $V1[$limit_min_1 + $k] < $V1[$limit_plus_1 + $k] )
- ) {
- $x = $V1[$limit_min_1 + $k];
- } else {
- $x = $V1[$limit_plus_1 + $k] - 1;
- }
-
- $y = $x - $k - $delta;
-
- $snake2 = 0;
- while ( $x > 0 && $y > 0
- && $from[$x + $bottoml1_min_1] === $to[$y + $bottoml2_min_1]
- ) {
- --$x;
- --$y;
- ++$snake2;
- }
- $V1[$limit + $k] = $x;
-
- if ( $k >= -$delta - $d && $k <= $d - $delta
- && $x <= $V0[$limit + $k + $delta]
- ) {
- $snake0 = $bottoml1 + $x;
- $snake1 = $bottoml2 + $y;
-
- return 2 * $d;
- }
-
- // check to see if we can cut down our diagonal range
- if ( $x <= 0 ) {
- $start_backward = $k + 1;
- $value_to_add_backward = 0;
- } elseif ( $y <= 0 && $end_backward > $k - 1 ) {
- $end_backward = $k - 1;
- }
- }
- }
- }
- /*
- * computing the true LCS is too expensive, instead find the diagonal
- * with the most progress and pretend a midle snake of length 0 occurs
- * there.
- */
-
- $most_progress = self::findMostProgress( $M, $N, $limit, $V );
-
- $snake0 = $bottoml1 + $most_progress[0];
- $snake1 = $bottoml2 + $most_progress[1];
- $snake2 = 0;
- wfDebug( "Computing the LCS is too expensive. Using a heuristic.\n" );
- $this->heuristicUsed = true;
-
- return 5; /*
- * HACK: since we didn't really finish the LCS computation
- * we don't really know the length of the SES. We don't do
- * anything with the result anyway, unless it's <=1. We know
- * for a fact SES > 1 so 5 is as good a number as any to
- * return here
- */
- }
-
- private static function findMostProgress( $M, $N, $limit, $V ) {
- $delta = $N - $M;
-
- if ( ( $M & 1 ) == ( $limit & 1 ) ) {
- $forward_start_diag = max( -$M, -$limit );
- } else {
- $forward_start_diag = max( 1 - $M, -$limit );
- }
-
- $forward_end_diag = min( $N, $limit );
-
- if ( ( $N & 1 ) == ( $limit & 1 ) ) {
- $backward_start_diag = max( -$N, -$limit );
- } else {
- $backward_start_diag = max( 1 - $N, -$limit );
- }
-
- $backward_end_diag = -min( $M, $limit );
-
- $temp = [ 0, 0, 0 ];
-
- $max_progress = array_fill( 0, ceil( max( $forward_end_diag - $forward_start_diag,
- $backward_end_diag - $backward_start_diag ) / 2 ), $temp );
- $num_progress = 0; // the 1st entry is current, it is initialized
- // with 0s
-
- // first search the forward diagonals
- for ( $k = $forward_start_diag; $k <= $forward_end_diag; $k += 2 ) {
- $x = $V[0][$limit + $k];
- $y = $x - $k;
- if ( $x > $N || $y > $M ) {
- continue;
- }
-
- $progress = $x + $y;
- if ( $progress > $max_progress[0][2] ) {
- $num_progress = 0;
- $max_progress[0][0] = $x;
- $max_progress[0][1] = $y;
- $max_progress[0][2] = $progress;
- } elseif ( $progress == $max_progress[0][2] ) {
- ++$num_progress;
- $max_progress[$num_progress][0] = $x;
- $max_progress[$num_progress][1] = $y;
- $max_progress[$num_progress][2] = $progress;
- }
- }
-
- $max_progress_forward = true; // initially the maximum
- // progress is in the forward
- // direction
-
- // now search the backward diagonals
- for ( $k = $backward_start_diag; $k <= $backward_end_diag; $k += 2 ) {
- $x = $V[1][$limit + $k];
- $y = $x - $k - $delta;
- if ( $x < 0 || $y < 0 ) {
- continue;
- }
-
- $progress = $N - $x + $M - $y;
- if ( $progress > $max_progress[0][2] ) {
- $num_progress = 0;
- $max_progress_forward = false;
- $max_progress[0][0] = $x;
- $max_progress[0][1] = $y;
- $max_progress[0][2] = $progress;
- } elseif ( $progress == $max_progress[0][2] && !$max_progress_forward ) {
- ++$num_progress;
- $max_progress[$num_progress][0] = $x;
- $max_progress[$num_progress][1] = $y;
- $max_progress[$num_progress][2] = $progress;
- }
- }
-
- // return the middle diagonal with maximal progress.
- return $max_progress[(int)floor( $num_progress / 2 )];
- }
-
- /**
- * @return mixed
- */
- public function getLcsLength() {
- if ( $this->heuristicUsed && !$this->lcsLengthCorrectedForHeuristic ) {
- $this->lcsLengthCorrectedForHeuristic = true;
- $this->length = $this->m - array_sum( $this->added );
- }
-
- return $this->length;
- }
-
-}
-
-/**
- * Alternative representation of a set of changes, by the index
- * ranges that are changed.
- *
- * @ingroup DifferenceEngine
- */
-class RangeDifference {
-
- /** @var int */
- public $leftstart;
-
- /** @var int */
- public $leftend;
-
- /** @var int */
- public $leftlength;
-
- /** @var int */
- public $rightstart;
-
- /** @var int */
- public $rightend;
-
- /** @var int */
- public $rightlength;
-
- function __construct( $leftstart, $leftend, $rightstart, $rightend ) {
- $this->leftstart = $leftstart;
- $this->leftend = $leftend;
- $this->leftlength = $leftend - $leftstart;
- $this->rightstart = $rightstart;
- $this->rightend = $rightend;
- $this->rightlength = $rightend - $rightstart;
- }
-
-}
--- /dev/null
+<?php
+/**
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup DifferenceEngine
+ * @defgroup DifferenceEngine DifferenceEngine
+ */
+
+namespace MediaWiki\Diff;
+
+/**
+ * Stores, escapes and formats the results of word-level diff
+ *
+ * @private
+ * @ingroup DifferenceEngine
+ */
+class WordAccumulator {
+ public $insClass = ' class="diffchange diffchange-inline"';
+ public $delClass = ' class="diffchange diffchange-inline"';
+
+ private $lines = [];
+ private $line = '';
+ private $group = '';
+ private $tag = '';
+
+ /**
+ * @param string $new_tag
+ */
+ private function flushGroup( $new_tag ) {
+ if ( $this->group !== '' ) {
+ if ( $this->tag == 'ins' ) {
+ $this->line .= "<ins{$this->insClass}>" .
+ htmlspecialchars( $this->group ) . '</ins>';
+ } elseif ( $this->tag == 'del' ) {
+ $this->line .= "<del{$this->delClass}>" .
+ htmlspecialchars( $this->group ) . '</del>';
+ } else {
+ $this->line .= htmlspecialchars( $this->group );
+ }
+ }
+ $this->group = '';
+ $this->tag = $new_tag;
+ }
+
+ /**
+ * @param string $new_tag
+ */
+ private function flushLine( $new_tag ) {
+ $this->flushGroup( $new_tag );
+ if ( $this->line != '' ) {
+ array_push( $this->lines, $this->line );
+ } else {
+ # make empty lines visible by inserting an NBSP
+ array_push( $this->lines, ' ' );
+ }
+ $this->line = '';
+ }
+
+ /**
+ * @param string[] $words
+ * @param string $tag
+ */
+ public function addWords( $words, $tag = '' ) {
+ if ( $tag != $this->tag ) {
+ $this->flushGroup( $tag );
+ }
+
+ foreach ( $words as $word ) {
+ // new-line should only come as first char of word.
+ if ( $word == '' ) {
+ continue;
+ }
+ if ( $word[0] == "\n" ) {
+ $this->flushLine( $tag );
+ $word = substr( $word, 1 );
+ }
+ assert( !strstr( $word, "\n" ) );
+ $this->group .= $word;
+ }
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getLines() {
+ $this->flushLine( '~done' );
+
+ return $this->lines;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup DifferenceEngine
+ * @defgroup DifferenceEngine DifferenceEngine
+ */
+
+use MediaWiki\Diff\ComplexityException;
+use MediaWiki\Diff\WordAccumulator;
+
+/**
+ * Performs a word-level diff on several lines
+ *
+ * @ingroup DifferenceEngine
+ */
+class WordLevelDiff extends \Diff {
+ /**
+ * @inheritdoc
+ */
+ protected $bailoutComplexity = 40000000; // Roughly 6K x 6K words changed
+
+ /**
+ * @param string[] $linesBefore
+ * @param string[] $linesAfter
+ */
+ public function __construct( $linesBefore, $linesAfter ) {
+
+ list( $wordsBefore, $wordsBeforeStripped ) = $this->split( $linesBefore );
+ list( $wordsAfter, $wordsAfterStripped ) = $this->split( $linesAfter );
+
+ try {
+ parent::__construct( $wordsBeforeStripped, $wordsAfterStripped );
+ } catch ( ComplexityException $ex ) {
+ // Too hard to diff, just show whole paragraph(s) as changed
+ $this->edits = [ new DiffOpChange( $linesBefore, $linesAfter ) ];
+ }
+
+ $xi = $yi = 0;
+ $editCount = count( $this->edits );
+ for ( $i = 0; $i < $editCount; $i++ ) {
+ $orig = &$this->edits[$i]->orig;
+ if ( is_array( $orig ) ) {
+ $orig = array_slice( $wordsBefore, $xi, count( $orig ) );
+ $xi += count( $orig );
+ }
+
+ $closing = &$this->edits[$i]->closing;
+ if ( is_array( $closing ) ) {
+ $closing = array_slice( $wordsAfter, $yi, count( $closing ) );
+ $yi += count( $closing );
+ }
+ }
+
+ }
+
+ /**
+ * @param string[] $lines
+ *
+ * @return array[]
+ */
+ private function split( $lines ) {
+
+ $words = [];
+ $stripped = [];
+ $first = true;
+ foreach ( $lines as $line ) {
+ if ( $first ) {
+ $first = false;
+ } else {
+ $words[] = "\n";
+ $stripped[] = "\n";
+ }
+ $m = [];
+ if ( preg_match_all( '/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs',
+ $line, $m ) ) {
+ foreach ( $m[0] as $word ) {
+ $words[] = $word;
+ }
+ foreach ( $m[1] as $stripped_word ) {
+ $stripped[] = $stripped_word;
+ }
+ }
+ }
+
+ return [ $words, $stripped ];
+ }
+
+ /**
+ * @return string[]
+ */
+ public function orig() {
+ $orig = new WordAccumulator;
+
+ foreach ( $this->edits as $edit ) {
+ if ( $edit->type == 'copy' ) {
+ $orig->addWords( $edit->orig );
+ } elseif ( $edit->orig ) {
+ $orig->addWords( $edit->orig, 'del' );
+ }
+ }
+ $lines = $orig->getLines();
+
+ return $lines;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function closing() {
+ $closing = new WordAccumulator;
+
+ foreach ( $this->edits as $edit ) {
+ if ( $edit->type == 'copy' ) {
+ $closing->addWords( $edit->closing );
+ } elseif ( $edit->closing ) {
+ $closing->addWords( $edit->closing, 'ins' );
+ }
+ }
+ $lines = $closing->getLines();
+
+ return $lines;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * An error page that emits an HTTP 400 Bad Request status code.
+ *
+ * @since 1.28
+ * @ingroup Exception
+ */
+class BadRequestError extends ErrorPageError {
+
+ public function report() {
+ global $wgOut;
+ $wgOut->setStatusCode( 400 );
+ parent::report();
+ }
+}
/**
* Show an error page on a badtitle.
- * Similar to ErrorPage, but emit a 400 HTTP error code to let mobile
- * browser it is not really a valid content.
+ *
+ * Uses BadRequestError to emit a 400 HTTP error code to ensure caching proxies and
+ * mobile browsers know not to cache it as valid content. (T35646)
*
* @since 1.19
* @ingroup Exception
*/
-class BadTitleError extends ErrorPageError {
+class BadTitleError extends BadRequestError {
/**
* @param string|Message|MalformedTitleException $msg A message key (default: 'badtitletext'), or
* a MalformedTitleException to figure out things from
parent::__construct( 'badtitle', $msg, $params );
}
}
-
- /**
- * Just like ErrorPageError::report() but additionally set
- * a 400 HTTP status code (bug 33646).
- */
- public function report() {
- global $wgOut;
-
- // bug 33646: a badtitle error page need to return an error code
- // to let mobile browser now that it is not a normal page.
- $wgOut->setStatusCode( 400 );
- parent::report();
- }
}
* 'exception-nologin' as a title and 'exception-nologin-text' for the message.
*
* @note In order for this exception to redirect, the error message passed to the
- * constructor has to be explicitly added to LoginForm::validErrorMessages or with
+ * constructor has to be explicitly added to LoginHelper::validErrorMessages or with
* the LoginFormValidErrorMessages hook. Otherwise, the user will just be shown the message
* rather than redirected.
*
public function report() {
// If an unsupported message is used, don't try redirecting to Special:Userlogin,
// since the message may not be compatible.
- if ( !in_array( $this->msg, LoginForm::getValidErrorMessages() ) ) {
+ if ( !in_array( $this->msg, LoginHelper::getValidErrorMessages() ) ) {
parent::report();
}
* @param string $dstZone Destination zone
* @param string $dstRel Destination relative path
* @param int $flags Bitwise combination of the following flags:
- * self::DELETE_SOURCE Delete the source file after upload
* self::OVERWRITE Overwrite an existing destination file instead of failing
* self::OVERWRITE_SAME Overwrite the file if the destination exists and has the
* same contents as the source
*
* @param array $triplets (src, dest zone, dest rel) triplets as per store()
* @param int $flags Bitwise combination of the following flags:
- * self::DELETE_SOURCE Delete the source file after upload
* self::OVERWRITE Overwrite an existing destination file instead of failing
* self::OVERWRITE_SAME Overwrite the file if the destination exists and has the
* same contents as the source
public function storeBatch( array $triplets, $flags = 0 ) {
$this->assertWritableRepo(); // fail out if read-only
+ if ( $flags & self::DELETE_SOURCE ) {
+ throw new InvalidArgumentException( "DELETE_SOURCE not supported in " . __METHOD__ );
+ }
+
$status = $this->newGood();
$backend = $this->backend; // convenience
$operations = [];
- $sourceFSFilesToDelete = []; // cleanup for disk source files
// Validate each triplet and get the store operation...
foreach ( $triplets as $triplet ) {
list( $srcPath, $dstZone, $dstRel ) = $triplet;
// Get the appropriate file operation
if ( FileBackend::isStoragePath( $srcPath ) ) {
- $opName = ( $flags & self::DELETE_SOURCE ) ? 'move' : 'copy';
+ $opName = 'copy';
} else {
$opName = 'store';
- if ( $flags & self::DELETE_SOURCE ) {
- $sourceFSFilesToDelete[] = $srcPath;
- }
}
$operations[] = [
'op' => $opName,
$opts['nonLocking'] = true;
}
$status->merge( $backend->doOperations( $operations, $opts ) );
- // Cleanup for disk source files...
- foreach ( $sourceFSFilesToDelete as $file ) {
- MediaWiki\suppressWarnings();
- unlink( $file ); // FS cleanup
- MediaWiki\restoreWarnings();
- }
return $status;
}
if ( $this->repo ) {
// Defer rendering if a 404 handler is set up...
if ( $this->repo->canTransformVia404() && !( $flags & self::RENDER_NOW ) ) {
- wfDebug( __METHOD__ . " transformation deferred.\n" );
// XXX: Pass in the storage path even though we are not rendering anything
// and the path is supposed to be an FS path. This is due to getScalerType()
// getting called on the path and clobbering $thumb->getUrl() if it's false.
// Also, that would cause contention on INSERT of similarly named rows.
$backend = $this->getRepo()->getBackend();
$lockPaths = [ $this->getPath() ]; // represents all versions of the file
- $status = $backend->lockFiles( $lockPaths, LockManager::LOCK_EX, 5 );
+ $start = microtime( true );
+ $status = $backend->lockFiles( $lockPaths, LockManager::LOCK_EX, 10 );
+ $waited = microtime( true ) - $start;
if ( !$status->isGood() ) {
if ( $this->lockedOwnTrx ) {
$dbw->rollback( __METHOD__ );
}
- throw new LocalFileLockError( "Could not acquire lock for '{$this->getName()}.'" );
+ throw new LocalFileLockError(
+ "Could not acquire lock for '{$this->getName()}' ($waited sec): " .
+ $status->getWikiText( false, false, 'en' )
+ );
}
// Release the lock *after* commit to avoid row-level contention
$this->locked++;
$output .= "\n\t<li class='gallerycaption'>{$this->mCaption}</li>";
}
+ if ( $this->mShowFilename ) {
+ // Preload LinkCache info for when generating links
+ // of the filename below
+ $lb = new LinkBatch();
+ foreach ( $this->mImages as $img ) {
+ $lb->addObj( $img[0] );
+ }
+ $lb->execute();
+ }
+
$lang = $this->getRenderLang();
# Output each image...
foreach ( $this->mImages as $pair ) {
}
$textlink = $this->mShowFilename ?
+ // Preloaded into LinkCache above
Linker::linkKnown(
$nt,
htmlspecialchars( $lang->truncate( $nt->getText(), $this->mCaptionLength ) )
protected $mShowReset = false;
protected $mShowSubmit = true;
protected $mSubmitFlags = [ 'constructive', 'primary' ];
+ protected $mShowCancel = false;
+ protected $mCancelTarget;
protected $mSubmitCallback;
protected $mValidationErrorMessage;
* - id: (string, optional) DOM id for the button.
* - attribs: (array, optional) Additional HTML attributes.
* - flags: (string|string[], optional) OOUI flags.
+ * - framed: (boolean=true, optional) OOUI framed attribute.
* @return HTMLForm $this for chaining calls (since 1.20)
*/
public function addButton( $data ) {
'id' => null,
'attribs' => null,
'flags' => null,
+ 'framed' => true,
];
return $this;
) . "\n";
}
+ if ( $this->mShowCancel ) {
+ $target = $this->mCancelTarget ?: Title::newMainPage();
+ if ( $target instanceof Title ) {
+ $target = $target->getLocalURL();
+ }
+ $buttons .= Html::element(
+ 'a',
+ [
+ 'class' => $useMediaWikiUIEverywhere ? 'mw-ui-button' : null,
+ 'href' => $target,
+ ],
+ $this->msg( 'cancel' )->text()
+ ) . "\n";
+ }
+
// IE<8 has bugs with <button>, so we'll need to avoid them.
$isBadIE = preg_match( '/MSIE [1-7]\./i', $this->getRequest()->getHeader( 'User-Agent' ) );
/**
* Identify that the submit button in the form has a destructive action
* @since 1.24
+ *
+ * @return HTMLForm $this for chaining calls (since 1.28)
*/
public function setSubmitDestructive() {
$this->mSubmitFlags = [ 'destructive', 'primary' ];
+
+ return $this;
}
/**
* Identify that the submit button in the form has a progressive action
* @since 1.25
+ *
+ * @return HTMLForm $this for chaining calls (since 1.28)
*/
public function setSubmitProgressive() {
$this->mSubmitFlags = [ 'progressive', 'primary' ];
+
+ return $this;
}
/**
return $this;
}
+ /**
+ * Show a cancel button (or prevent it). The button is not shown by default.
+ * @param bool $show
+ * @return HTMLForm $this for chaining calls
+ * @since 1.27
+ */
+ public function showCancel( $show = true ) {
+ $this->mShowCancel = $show;
+ return $this;
+ }
+
+ /**
+ * Sets the target where the user is redirected to after clicking cancel.
+ * @param Title|string $target Target as a Title object or an URL
+ * @return HTMLForm $this for chaining calls
+ * @since 1.27
+ */
+ public function setCancelTarget( $target ) {
+ $this->mCancelTarget = $target;
+ return $this;
+ }
+
/**
* Set the id of the \<table\> or outermost \<div\> element.
*
protected function getOneCheckbox( $checked, $attribs, $label ) {
if ( $this->mParent instanceof OOUIHTMLForm ) {
- if ( $this->mOptionsLabelsNotFromMessage ) {
- $label = new OOUI\HtmlSnippet( $label );
- }
- return new OOUI\FieldLayout(
- new OOUI\CheckboxInputWidget( [
- 'name' => "{$this->mName}[]",
- 'selected' => $checked,
- ] + OOUI\Element::configFromHtmlAttributes(
- $attribs
- ) ),
- [
- 'label' => $label,
- 'align' => 'inline',
- ]
- );
+ throw new MWException( 'HTMLMultiSelectField#getOneCheckbox() is not supported' );
} else {
$elementFunc = [ 'Html', $this->mOptionsLabelsNotFromMessage ? 'rawElement' : 'element' ];
$checkbox =
}
}
+ /**
+ * Get the OOUI version of this field.
+ *
+ * @since 1.28
+ * @param string[] $value
+ * @return OOUI\CheckboxMultiselectInputWidget
+ */
+ public function getInputOOUI( $value ) {
+ $attr = $this->getTooltipAndAccessKey();
+ $attr['id'] = $this->mID;
+ $attr['name'] = "{$this->mName}[]";
+
+ $attr['value'] = $value;
+ $attr['options'] = $this->getOptionsOOUI();
+
+ if ( $this->mOptionsLabelsNotFromMessage ) {
+ foreach ( $attr['options'] as &$option ) {
+ $option['label'] = new OOUI\HtmlSnippet( $option['label'] );
+ }
+ }
+
+ $attr += OOUI\Element::configFromHtmlAttributes(
+ $this->getAttributes( [ 'disabled', 'tabindex' ] )
+ );
+
+ if ( $this->mClass !== '' ) {
+ $attr['classes'] = [ $this->mClass ];
+ }
+
+ return new OOUI\CheckboxMultiselectInputWidget( $attr );
+ }
+
/**
* @param WebRequest $request
*
'id' => $this->mID,
'value' => $value,
'options' => $options,
- 'classes' => 'mw-htmlform-flatlist-item',
] + OOUI\Element::configFromHtmlAttributes(
$this->getAttributes( [ 'disabled', 'tabindex' ] )
) );
}
function formatOptions( $options, $value ) {
+ global $wgUseMediaWikiUIEverywhere;
+
$html = '';
$attribs = $this->getAttributes( [ 'disabled', 'tabindex' ] );
$html .= $this->formatOptions( $info, $value );
} else {
$id = Sanitizer::escapeId( $this->mID . "-$info" );
+ $classes = [ 'mw-htmlform-flatlist-item' ];
+ if ( $wgUseMediaWikiUIEverywhere || $this->mParent instanceof VFormHTMLForm ) {
+ $classes[] = 'mw-ui-radio';
+ }
$radio = Xml::radio( $this->mName, $info, $info === $value, $attribs + [ 'id' => $id ] );
$radio .= ' ' . call_user_func( $elementFunc, 'label', [ 'for' => $id ], $label );
$html .= ' ' . Html::rawElement(
'div',
- [ 'class' => 'mw-htmlform-flatlist-item mw-ui-radio' ],
+ [ 'class' => $classes ],
$radio
);
}
] );
}
+ if ( $this->mShowCancel ) {
+ $target = $this->mCancelTarget ?: Title::newMainPage();
+ if ( $target instanceof Title ) {
+ $target = $target->getLocalURL();
+ }
+ $buttons .= new OOUI\ButtonWidget( [
+ 'label' => $this->msg( 'cancel' )->text(),
+ 'href' => $target,
+ ] );
+ }
+
foreach ( $this->mButtons as $button ) {
$attrs = [];
'value' => $button['value'],
'label' => $label,
'flags' => $button['flags'],
+ 'framed' => $button['framed'],
'useInputTag' => $isBadIE,
] + $attrs );
}
// FIXME This only works for forms with no subsections
if ( $fieldset instanceof OOUI\FieldsetLayout ) {
$classes = [ 'mw-htmlform-ooui-header' ];
- if ( !$this->mHeader ) {
- $classes[] = 'mw-htmlform-ooui-header-empty';
- }
if ( $this->oouiErrors ) {
$classes[] = 'mw-htmlform-ooui-header-errors';
}
- $fieldset->addItems( [
- new OOUI\FieldLayout(
- new OOUI\LabelWidget( [ 'label' => new OOUI\HtmlSnippet( $this->mHeader ) ] ),
- [
- 'align' => 'top',
- 'errors' => $this->oouiErrors,
- 'classes' => $classes,
- ]
- )
- ], 0 );
+ if ( $this->mHeader || $this->oouiErrors ) {
+ // if there's no header, don't create an (empty) LabelWidget, simply use a placeholder
+ if ( $this->mHeader ) {
+ $element = new OOUI\LabelWidget( [ 'label' => new OOUI\HtmlSnippet( $this->mHeader ) ] );
+ } else {
+ $element = new OOUI\Widget( [] );
+ }
+ $fieldset->addItems( [
+ new OOUI\FieldLayout(
+ $element,
+ [
+ 'align' => 'top',
+ 'errors' => $this->oouiErrors,
+ 'classes' => $classes,
+ ]
+ )
+ ], 0 );
+ }
}
return $fieldset;
}
) . "\n";
}
+ if ( $this->mShowCancel ) {
+ $target = $this->mCancelTarget ?: Title::newMainPage();
+ if ( $target instanceof Title ) {
+ $target = $target->getLocalURL();
+ }
+ $buttons .= Html::element(
+ 'a',
+ [
+ 'class' => 'mw-ui-button mw-ui-big mw-ui-block',
+ 'href' => $target,
+ ],
+ $this->msg( 'cancel' )->text()
+ ) . "\n";
+ }
+
foreach ( $this->mButtons as $button ) {
$attrs = [
'type' => 'submit',
* @file
* @ingroup Deployment
*/
+use MediaWiki\MediaWikiServices;
/**
* This documentation group collects source code files with deployment functionality.
$configOverrides->set( 'MessagesDirs', $messageDirs );
- return new MultiConfig( [ $configOverrides, $baseConfig ] );
+ $installerConfig = new MultiConfig( [ $configOverrides, $baseConfig ] );
+
+ // make sure we use the installer config as the main config
+ $configRegistry = $baseConfig->get( 'ConfigRegistry' );
+ $configRegistry['main'] = function() use ( $installerConfig ) {
+ return $installerConfig;
+ };
+
+ $configOverrides->set( 'ConfigRegistry', $configRegistry );
+
+ return $installerConfig;
}
/**
* Constructor, always call this from child classes.
*/
public function __construct() {
- global $wgMemc, $wgUser;
+ global $wgMemc, $wgUser, $wgObjectCaches;
$defaultConfig = new GlobalVarConfig(); // all the stuff from DefaultSettings.php
$installerConfig = self::getInstallerConfig( $defaultConfig );
// Disable object cache (otherwise CACHE_ANYTHING will try CACHE_DB and
// SqlBagOStuff will then throw since we just disabled wfGetDB)
+ $wgObjectCaches = MediaWikiServices::getInstance()->getMainConfig()->get( 'ObjectCaches' );
$wgMemc = ObjectCache::getInstance( CACHE_NONE );
// Having a user with id = 0 safeguards us from DB access via User::loadOptions().
$command = $path . DIRECTORY_SEPARATOR . $name;
MediaWiki\suppressWarnings();
- $file_exists = file_exists( $command );
+ $file_exists = is_executable( $command );
MediaWiki\restoreWarnings();
if ( $file_exists ) {
foreach ( $createHostList as $host ) {
$fullName = $this->buildFullUserName( $dbUser, $host );
- if ( !$this->userDefinitelyExists( $dbUser, $host ) ) {
+ if ( !$this->userDefinitelyExists( $host, $dbUser ) ) {
try {
$this->db->begin( __METHOD__ );
$this->db->query( "CREATE USER $fullName IDENTIFIED BY $escPass", __METHOD__ );
public function output() {
$this->flush();
- $this->outputFooter();
+
+ if ( !$this->redirectTarget ) {
+ $this->outputFooter();
+ }
}
/**
wfMessage( "config-$continue" )->text(),
[
'name' => "enter-$continue",
- 'style' => 'visibility:hidden;overflow:hidden;width:1px;margin:0'
+ 'style' => 'width:0;border:0;height:0;padding:0'
]
) . "\n";
}
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Angpradesh"
+ ]
+ },
+ "config-desc": "मिडियाविकि लेली इंस्टॉलर",
+ "config-title": "मीडियाविकी $1 इंस्टॉलेशन",
+ "config-information": "जानकारी",
+ "config-localsettings-upgrade": "<code>LocalSettings.php</code> फ़ाइल पैलऽ गेलै ।\nई स्थापना क॑ अपग्रेड करै लेली , नीचाँ देलऽ गेलऽ बॉक्स म॑ <code>$wgUpgradeKey</code> के मान दर्ज करऽ।\nआपन॑ क॑ <code>LocalSettings.php</code> म॑ मिली जैतै ।",
+ "config-localsettings-cli-upgrade": "<code>LocalSettings.php</code> फ़ाइल पैलऽ गेलऽ छै ।\nई स्थापना क॑ अपग्रेड करै लेली , बदला म॑ कृपया करी क॑ ई चलाबऽ <code>update.php</code>",
+ "config-localsettings-key": "नवीनीकरण कुंजी"
+}
"config-db-wiki-help": "Enter the username and password that will be used to connect to the database during normal wiki operation.\nIf the account does not exist, and the installation account has sufficient privileges, this user account will be created with the minimum privileges required to operate the wiki.",
"config-db-prefix": "Database table prefix:",
"config-db-prefix-help": "If you need to share one database between multiple wikis, or between MediaWiki and another web application, you may choose to add a prefix to all the table names to avoid conflicts.\nDo not use spaces.\n\nThis field is usually left empty.",
- "config-db-charset": "Database character set",
- "config-charset-mysql5-binary": "MySQL 4.1/5.0 binary",
- "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
- "config-charset-mysql4": "MySQL 4.0 backwards-compatible UTF-8",
- "config-charset-help": "<strong>Warning:</strong> If you use <strong>backwards-compatible UTF-8</strong> on MySQL 4.1+, and subsequently back up the database with <code>mysqldump</code>, it may destroy all non-ASCII characters, irreversibly corrupting your backups!\n\nIn <strong>binary mode</strong>, MediaWiki stores UTF-8 text to the database in binary fields.\nThis is more efficient than MySQL's UTF-8 mode, and allows you to use the full range of Unicode characters.\nIn <strong>UTF-8 mode</strong>, MySQL will know what character set your data is in, and can present and convert it appropriately,\nbut it will not let you store characters above the [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Basic Multilingual Plane].",
"config-mysql-old": "MySQL $1 or later is required. You have $2.",
"config-db-port": "Database port:",
"config-db-schema": "Schema for MediaWiki:",
"config-localsettings-upgrade": "Un file <code>LocalSettings.php</code> ha essite detegite.\nPro actualisar iste installation, per favor entra le valor de <code>$wgUpgradeKey</code> in le quadro hic infra.\nIste se trova in <code>LocalSettings.php</code>.",
"config-localsettings-cli-upgrade": "Un file <code>LocalSettings.php</code> file ha essite detegite.\nPro actualisar iste installation, per favor executa <code>update.php</code>.",
"config-localsettings-key": "Clave de actualisation:",
- "config-localsettings-badkey": "Le clave que tu forniva es incorrecte",
+ "config-localsettings-badkey": "Le clave de actualisation fornite es incorrecte.",
"config-upgrade-key-missing": "Un installation existente de MediaWiki ha essite detegite.\nPro actualisar iste installation, es necessari adjunger le sequente linea al fin del file <code>LocalSettings.php</code>:\n\n$1",
"config-localsettings-incomplete": "Le file <code>LocalSettings.php</code> existente pare esser incomplete.\nLe variabile $1 non es definite.\nPer favor cambia <code>LocalSettings.php</code> de sorta que iste variabile es definite, e clicca \"{{int:Config-continue}}\".",
"config-localsettings-connection-error": "Un error ha essite incontrate durante le connexion al base de datos usante le configuration specificate in <code>LocalSettings.php</code>. Per favor corrige iste configuration e reproba.\n\n$1",
"config-ctype": "'''Fatal''': PHP debe esser compilate con supporto pro le [http://www.php.net/manual/en/ctype.installation.php extension Ctype].",
"config-iconv": "<strong>Fatal:</strong> PHP debe esser compilate con supporto pro le [http://www.php.net/manual/en/iconv.installation.php extension iconv].",
"config-json": "'''Fatal:''' PHP ha essite compilate sin supporto de JSON.\nTu debe installar le extension JSON de PHP o le extension [http://pecl.php.net/package/jsonc PECL jsonc] extension ante de installar MediaWiki.\n* Le extension de PHP es includite in Red Hat Enterprise Linux (CentOS) 5 e 6, ma debe esser activate in <code>/etc/php.ini</code> o <code>/etc/php.d/json.ini</code>.\n* Alcun distributiones de Linux liberate post maio 2013 omitte iste extension de PHP, forniente in su loco le extension PECL como <code>php5-json</code> o <code>php-pecl-jsonc</code>.",
+ "config-mbstring-absent": "<strong>Fatal:</strong> PHP debe esser compilate con supporto pro le [http://www.php.net/manual/en/mbstring.setup.php extension mbstring].",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] es installate",
"config-apc": "[http://www.php.net/apc APC] es installate",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] es installate",
+ "config-no-cache-apcu": "<strong>Attention:</strong> Impossibile trovar [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] o [http://www.iis.net/download/WinCacheForPhp WinCache].\nLe cache de objectos non es activate.",
"config-mod-security": "'''Attention''': [http://modsecurity.org/ mod_security] es active in tu servitor web. Si mal configurate, isto pote causar problemas pro MediaWiki o altere software que permitte al usatores de publicar contento arbitrari.\nConsulta le [http://modsecurity.org/documentation/ documentation de mod_security] o contacta le servicio de adjuta de tu host si tu incontra estranie errores.",
"config-diff3-bad": "GNU diff3 non trovate.",
"config-git": "Systema de controlo de version Git trovate: <code>$1</code>",
"config-db-wiki-help": "Entra le nomine de usator e contrasigno que essera usate pro connecter al base de datos durante le operation normal del wiki.\nSi le conto non existe, e si le conto de installation possede sufficiente privilegios, iste conto de usator essera create con le minime privilegios necessari pro operar le wiki.",
"config-db-prefix": "Prefixo de tabella del base de datos:",
"config-db-prefix-help": "Si il es necessari usar un base de datos in commun inter multiple wikis, o inter MediaWiki e un altere application web, tu pote optar pro adder un prefixo a tote le nomines de tabella pro evitar conflictos.\nNon usa spatios.\n\nIste campo usualmente resta vacue.",
- "config-db-charset": "Codification de characteres in le base de datos",
- "config-charset-mysql5-binary": "MySQL 4.1/5.0 binari",
- "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
- "config-charset-mysql4": "MySQL 4.0 retrocompatibile UTF-8",
- "config-charset-help": "'''Aviso:''' Si tu usa '''UTF-8 retrocompatibile''' sur MySQL 4.1+, e postea face un copia de reserva del base de datos con <code>mysqldump</code>, tote le characteres non ASCII pote esser destruite, resultante in corruption irreversibile de tu copias de reserva!\n\nIn '''modo binari''', MediaWiki immagazina texto in UTF-8 in le base de datos in campos binari.\nIsto es plus efficiente que le modo UTF-8 de MySQL, e permitte usar le rango complete de characteres de Unicode.\nIn '''modo UTF-8''', MySQL sapera in qual codification de characteres tu datos es, e pote presentar e converter lo appropriatemente,\nma non te permittera immagazinar characteres supra le [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Plano Multilingue Basic].",
"config-mysql-old": "MySQL $1 o plus recente es requirite, tu ha $2.",
"config-db-port": "Porto de base de datos:",
"config-db-schema": "Schema pro MediaWiki",
"config-ns-site-name": "Mesme nomine que le wiki: $1",
"config-ns-other": "Altere (specifica)",
"config-ns-other-default": "MiWiki",
- "config-project-namespace-help": "Sequente le exemplo de Wikipedia, multe wikis tene lor paginas de politica separate de lor paginas de contento, in un \"'''spatio de nomines de projecto'''\".\nTote le titulos de pagina in iste spatio de nomines comencia con un certe prefixo, le qual tu pote specificar hic.\nTraditionalmente, iste prefixo deriva del nomine del wiki, ma illo non pote continer characteres de punctuation como \"#\" o \":\".",
+ "config-project-namespace-help": "Sequente le exemplo de Wikipedia, multe wikis tene lor paginas de politica separate de lor paginas de contento, in un '''spatio de nomines de projecto'''.\nTote le titulos de pagina in iste spatio de nomines comencia con un certe prefixo, le qual tu pote specificar hic.\nNormalmente, iste prefixo deriva del nomine del wiki, ma illo non pote continer characteres de punctuation como \"#\" o \":\".",
"config-ns-invalid": "Le spatio de nomines specificate \"<nowiki>$1</nowiki>\" es invalide.\nSpecifica un altere spatio de nomines de projecto.",
"config-ns-conflict": "Le spatio de nomines specificate \"<nowiki>$1</nowiki>\" conflige con un spatio de nomines predefinite de MediaWiki.\nSpecifica un altere spatio de nomines pro le projecto.",
"config-admin-box": "Conto de administrator",
"config-install-mainpage": "Crea pagina principal con contento predefinite",
"config-install-extension-tables": "Creation de tabellas pro le extensiones activate",
"config-install-mainpage-failed": "Non poteva inserer le pagina principal: $1",
- "config-install-done": "'''Felicitationes!'''\nTu ha installate MediaWiki con successo.\n\nLe installator ha generate un file <code>LocalSettings.php</code>.\nIste contine tote le configuration.\n\nEs necessari discargar lo e poner lo in le base del installation wiki (le mesme directorio que index.php).\nLe discargamento debe haber comenciate automaticamente.\n\nSi le discargamento non ha comenciate, o si illo esseva cancellate, es possibile recomenciar le discargamento con un clic sur le ligamine sequente:\n\n$3\n\n'''Nota''': Si tu non discarga iste file de configuration ora, illo non essera disponibile plus tarde.\n\nPost facer isto, tu pote '''[$2 entrar in tu wiki]'''.",
+ "config-install-done": "<strong>Felicitationes!</strong>\nTu ha installate MediaWiki.\n\nLe installator ha generate un file <code>LocalSettings.php</code>.\nIste contine tote le configuration.\n\nEs necessari discargar lo e poner lo in le base del installation wiki (le mesme directorio que index.php).\nLe discargamento debe haber comenciate automaticamente.\n\nSi le discargamento non ha comenciate, o si illo esseva cancellate, recomencia le discargamento con un clic sur le ligamine sequente:\n\n$3\n\n<strong>Nota:</strong> Si tu non discarga iste file de configuration ora, illo non essera disponibile plus tarde.\n\nPost facer isto, tu pote <strong>[$2 entrar in tu wiki]</strong>.",
"config-download-localsettings": "Discargar <code>LocalSettings.php</code>",
"config-help": "adjuta",
"config-help-tooltip": "clicca pro displicar",
"config-nofile": "Le file \"$1\" non poteva esser trovate. Ha illo essite delite?",
"config-extension-link": "Sapeva tu que tu wiki supporta [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensiones]?\n\nTu pote explorar le [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category extensiones per category] o le [//www.mediawiki.org/wiki/Extension_Matrix matrice de extensiones] pro vider le lista complete de extensiones.",
"mainpagetext": "<strong>MediaWiki ha essite installate.</strong>",
- "mainpagedocfooter": "Consulta le [//meta.wikimedia.org/wiki/Help:Contents Guida del usator] pro informationes super le uso del software wiki.\n\n== Pro initiar ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista de configurationes]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ a proposito de MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de diffusion pro annuncios de nove versiones de MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Traducer MediaWiki in tu lingua]"
+ "mainpagedocfooter": "Consulta le [//meta.wikimedia.org/wiki/Help:Contents Guida del usator] pro information sur le uso del software wiki.\n\n== Pro initiar ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista de configurationes]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ a proposito de MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de diffusion pro annuncios de nove versiones de MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Traducer MediaWiki in tu lingua]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Como combatter le spam in tu wiki]"
}
{
"@metadata": {
"authors": [
- "Anggoro"
+ "Anggoro",
+ "NoiX180"
]
},
+ "config-install-mainpage-failed": "Ora bisa nglebokaké tepas: $1",
"mainpagetext": "'''Prangkat empuk wiki wis suksès dipasang.'''",
"mainpagedocfooter": "Mangga maca [//meta.wikimedia.org/wiki/Help:Contents User's Guide] kanggo katrangan luwih langkung prakara panggunan prangkat empuk wiki\n== Miwiti panggunan ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Daftar pangaturan préférènsi]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Milis rilis MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]"
}
"config-ctype": "<strong>치명</strong>: PHP는 [http://www.php.net/manual/en/ctype.installation.php Ctype 확장 기능]을 지원하도록 하여 컴파일해야 합니다.",
"config-iconv": "<strong>치명</strong>: PHP는 [http://www.php.net/manual/en/iconv.installation.php iconv 확장 기능]을 지원하도록 하여 컴파일해야 합니다.",
"config-json": "<strong>치명:</strong> PHP가 JSON 지원이 없이 컴파일되었습니다.\n미디어위키를 설치하기 전에 PHP JSON 확장 기능이나 [http://pecl.php.net/package/jsonc PECL jsonc] 확장 기능 중 하나를 설치해야 합니다.\n* PHP 확장 기능은 Red Hat Enterprise Linux (CentOS) 5와 6에 포함되어 있지만, <code>/etc/php.ini</code>나 <code>/etc/php.d/json.ini</code>에서 활성화해야 합니다.\n* 2013년 5월 이후에 출시된 일부 리눅스 배포판은 PHP 확장 기능이 생략된 대신, <code>php5-json</code>이나 <code>php-pecl-jsonc</code>로 PECL 확장 기능이 포장되어 있습니다.",
+ "config-mbstring-absent": "<strong>치명적 오류:</strong> PHP는 [http://www.php.net/manual/en/mbstring.setup.php mbstring 확장]을 지원하도록 컴파일되어야 합니다.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache]가 설치되었습니다",
"config-apc": "[http://www.php.net/apc APC]가 설치되었습니다",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache]가 설치되었습니다",
"config-ctype": "'''Fähler:''' <i lang=\"en\">PHP</i> moß met dä Ongerschtözong för der [http://www.php.net/manual/en/ctype.installation.php <code lang=\"en\">Ctype</code> Zohsaz] övversaz woode sin.",
"config-iconv": "'''Fähler:''' <i lang=\"en\">PHP</i> moß met dä Ongerschtözong för der [http://www.php.net/manual/en/iconv.installation.php <code lang=\"en\">iconv</code> Zohsaz] övversaz woode sin.",
"config-json": "'''Dä!:''' PHP wood der ohne <i lang=\"en\" xml:lang=\"en\">JSON</i> övversaz.\nJäz moß de äntweeder dä PHP-<i lang=\"en\" xml:lang=\"en\">JSON</i>-Zohsaz enschtallere udder der <i lang=\"en\" xml:lang=\"en\">[http://pecl.php.net/package/jsonc PECL jsonc]</i>-Zohsaz, ih dat de MedijaWikki enschtallere kanns.\n* Dä PHP-Zohsaz es em <i lang=\"en\" xml:lang=\"en\">Red Hat Enterprise Linux (CentOS)</i> 5 un 6 änthallde, moß ävver en de <code lang=\"en\" xml:lang=\"en\">/etc/php.ini</code> udder <code lang=\"en\" xml:lang=\"en\">/etc/php.d/json.ini</code> enjeschalldt wääde.\n* E paa Linux Destrebuzjohne lohß zigg_em Mai 2013 dä PHP-Zohsaz fott un packe doför der PECL-Zohsaz als <code lang=\"en\" xml:lang=\"en\">php5-json</code> udder <code lang=\"en\" xml:lang=\"en\">php-pecl-jsonc</code> med ein.",
+ "config-mbstring-absent": "'''Fähler:''' <i lang=\"en\">PHP</i> moß met dä Ongerschtözong för singe Zohsaz [http://www.php.net/manual/en/mbstring.setup.php <code lang=\"en\">mbstring </code>] övversaz woode sin.",
"config-xcache": "Dä <code lang=\"en\">[http://xcache.lighttpd.net/ XCache]</code> es ennjeresht.",
"config-apc": "Dä <code lang=\"en\">[http://www.php.net/apc APC]</code> es ennjeresht.",
"config-wincache": "Dä <code lang=\"en\">[http://www.iis.net/download/WinCacheForPhp WinCache]</code> es ennjeresht.",
"config-db-wiki-help": "Jiv ene Nahme un e Paßwoot aan, för dä Aanwänder för dä Zohjref op de Dahtebangk, wann et Wikki nommahl aam Loufe es.\nWann et dä Nahme en der Dahtebangk noch nit jit, un dä Aanwender för dä Zohjrevv op de Dahtebangk beim Enschtallehre jenohch Berääschtejonge hät, läht dä heh dä Aanwänder en der Dahtebangk aan un jidd_em di Rääschde, di dä nühdesch hät, ävver nit mih.",
"config-db-prefix": "Vörsaz för de Name vun de Tabälle en de Daatebangk:",
"config-db-prefix-help": "Wann ein Daatebangk för mih wi ein Wiki udder e Wiki uns söns jät zosamme jebruch weed, dann kam_mer noch jet vör de Tabälle ier Name säze. Esu ene Vörsaz sull dubblte Tabällename vermeide hälfe.\nDonn kein Zwescheräum enjävve!\n\nJewöhnlesch bliev dat Feld heh ävver läddesch.",
- "config-db-charset": "Dä Daatebangk iere Zeischesaz",
- "config-charset-mysql5-binary": "MySQL (4.1 udder 5.0) binär",
- "config-charset-mysql5": "MySQL (4.1 udder 5.0) UTF-8",
- "config-charset-mysql4": "MySQL 4.0 röckwääts kompatibel UTF-8",
- "config-charset-help": "<strong>Opjepaß:</strong>\nWann De et <strong>röckwääts kompatibel UTF-8 Fommaht</strong> nemmps, met dem <i lang=\"en\">MySQL</i> singe Väsjohn 4.1 udder hüüter, dann künnt dat all di Zeische kappott maache, di nit em <i lang=\"en\" title=\"American Standard Code for Information Interchange\">ASCII</i> sen, un domet all Ding Sescherungskopieje kapott maache, wat mer nieh mieh retuur krijje kann.\n\nBeim Schpeischere em <strong>binäre Fomaat</strong> deiht MediaWiki de Täx, dä em UTF-8 Fommaht küt, en dä Dahtebangk en binähr kodehrte Dahtefälder faßhallde.\nDat es flöcker un spaasahmer wi et UTF-8 Fommaht vum <i lang=\"en\">MySQL</i> un määd_et müjjelesch, jehdes <i lang=\"en\">Unicode</i>-Zeische met faßzehallde.\n\nBeim Schpeischere em <strong>UTF-8 Fomaht</strong> deihd_et <i lang=\"en\">MySQL</i> der Zeischesaz un de Kodehrung vun dä Dahte känne, un kann se akeraht aanzeije un ömwandelle,\nallerdengs künne kein Zeische ußerhalv vum [//de.wikipedia.org/wiki/Basic_Multilingual_Plane#Gliederung_in_Ebenen_und_Bl.C3.B6cke jrondlähje Knubbel för vill Schprohche (<i lang=\"en\">Basic Multilingual Plane — BMP</i>)] afjeschpeischert wähde.",
"config-mysql-old": "Mer bruche <i lang=\"en\">MySQL</i> $1 udder neuer. Em Momang es <i lang=\"en\">MySQL</i> $2 aam Loufe.",
"config-db-port": "De Pooz-Nommer (<i lang=\"en\">port</i>) för de Daatebangk:",
"config-db-schema": "Et Schehma en de Datebangk för MehdijaWikki:",
"config-db-name": "Datubāzes nosaukums:",
"config-db-username": "Datubāzes lietotājvārds:",
"config-db-password": "Datubāzes parole:",
- "config-db-charset": "Datubāzes rakstzīmju kopa",
- "config-charset-mysql5-binary": "MySQL 4.1/5.0 binārs",
- "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
- "config-charset-mysql4": "MySQL 4.0 atpakaļsaderīgs UTF-8",
"config-db-port": "Datubāzes ports:",
"config-db-schema": "MediaWiki shēma:",
"config-db-schema-help": "Šī shēma derēs vairumā gadījumu.\nMainiet to tikai, ja zināt, ka tas nepieciešams.",
"config-mysql-innodb": "InnoDB",
"config-mysql-myisam": "MyISAM",
"config-mysql-utf8": "UTF-8",
+ "config-mssql-windowsauth": "Windows Autentifikācija",
"config-ns-generic": "Projekts",
"config-ns-site-name": "Tāds pats kā viki nosaukums: $1",
"config-ns-other": "Cits (jānorāda)",
"config-admin-password-confirm": "Parole vēlreiz:",
"config-admin-name-blank": "Ievadiet administratora lietotājvārdu.",
"config-admin-email": "E-pasta adrese:",
+ "config-email-settings": "E-pasta iestatījumi",
"config-logo": "Logo URL:",
"config-cc-again": "Izvēlies vēlreiz...",
"config-extensions": "Paplašinājumi",
"config-your-language": "Vòstra lenga :",
"config-your-language-help": "Seleccionatz la lenga d'utilizar pendent lo processus d'installacion.",
"config-wiki-language": "Lenga del wiki :",
- "config-wiki-language-help": "Seleccionar la lenga dins la quala lo wiki serà principalament escrich.",
+ "config-wiki-language-help": "Seleccionar la lenga dins la quala lo wiki serà principalament escrit.",
"config-back": "← Retorn",
"config-continue": "Contunhar →",
"config-page-language": "Lenga",
"config-page-welcome": "Benvenguda sus MediaWiki !",
- "config-page-dbconnect": "Se connectar a la banca de donadas",
+ "config-page-dbconnect": "Se connectar a la basa de donadas",
"config-page-upgrade": "Metre a jorn l’installacion existenta",
- "config-page-dbsettings": "Paramètres de la banca de donadas",
+ "config-page-dbsettings": "Paramètres de la basa de donadas",
"config-page-name": "Nom",
"config-page-options": "Opcions",
"config-page-install": "Installar",
"config-gd": "La bibliotèca grafica GD integrada es estada trobada.\nLa miniaturizacion d'imatges serà activada se activatz lo telecargament de fichièrs.",
"config-using-server": "Utilizacion del nom de servidor \"<nowiki>$1</nowiki>\".",
"config-using-uri": "Utilizacion de l'URL de servidor \"<nowiki>$1$2</nowiki>\".",
- "config-db-type": "Tipe de banca de donadas :",
- "config-db-host": "Nom d’òste de la banca de donadas :",
- "config-db-host-oracle": "Nom TNS de la banca de donadas :",
+ "config-db-type": "Tipe de basa de donadas :",
+ "config-db-host": "Nom d’òste de la basa de donadas :",
+ "config-db-host-oracle": "Nom TNS de la basa de donadas :",
"config-db-wiki-settings": "Identificar aqueste wiki",
- "config-db-name": "Nom de la banca de donadas :",
- "config-db-name-oracle": "Esquèma de banca de donadas :",
+ "config-db-name": "Nom de la basa de donadas :",
+ "config-db-name-oracle": "Esquèma de basa de donadas :",
"config-db-install-account": "Compte d'utilizaire per l'installacion",
- "config-db-username": "Nom d'utilizaire de la banca de donadas :",
- "config-db-password": "Senhal de la banca de donadas :",
+ "config-db-username": "Nom d'utilizaire de la basa de donadas :",
+ "config-db-password": "Senhal de la basa de donadas :",
"config-db-account-lock": "Utilizar lo meteis nom d'utilizaire e lo meteis senhal pendent lo foncionament abitual",
"config-db-wiki-account": "Compte d'utilizaire pel foncionament abitual",
- "config-db-prefix": "Préfix de las taulas de la banca de donadas :",
- "config-db-charset": "Jòc de caractèrs de la banca de donadas",
- "config-charset-mysql5-binary": "MySQL 4.1/5.0 binari",
- "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
- "config-charset-mysql4": "MySQL 4.0 retrocompatible UTF-8",
+ "config-db-prefix": "Prefix de las taulas de la basa de donadas :",
"config-mysql-old": "MySQL $1 o version ulteriora es requesit, avètz $2.",
- "config-db-port": "Pòrt de la banca de donadas :",
+ "config-db-port": "Pòrt de la basa de donadas :",
"config-db-schema": "Esquèma per MediaWiki",
- "config-pg-test-error": "Impossible de se connectar a la banca de donadas '''$1''' : $2",
+ "config-pg-test-error": "Impossible de se connectar a la basa de donadas '''$1''' : $2",
"config-sqlite-dir": "Dorsièr de las donadas SQLite :",
"config-oracle-def-ts": "Espaci d'emmagazinatge (''tablespace'') per defaut :",
"config-oracle-temp-ts": "Espaci d'emmagazinatge (''tablespace'') temporari :",
"config-header-sqlite": "Paramètres de SQLite",
"config-header-oracle": "Paramètres d’Oracle",
"config-header-mssql": "Paramètres de Microsoft SQL Server",
- "config-invalid-db-type": "Tipe de banca de donadas invalid",
+ "config-invalid-db-type": "Tipe de basa de donadas invalid",
"config-missing-db-name": "Vos cal entrar una valor per « {{int:config-db-name}} ».",
"config-missing-db-host": "Vos cal entrar una valor per « {{int:config-db-host}} ».",
"config-missing-db-server-oracle": "Vos cal entrar una valor per « {{int:config-db-oracle}} ».",
"config-postgres-old": "PostgreSQL $1 o version ulteriora es requesit, avètz $2.",
"config-sqlite-readonly": "Lo fichièr <code>$1</code> es pas accessible en escritura.",
- "config-sqlite-cant-create-db": "Impossible de crear lo fichièr de banca de donadas <code>$1</code>.",
+ "config-sqlite-cant-create-db": "Impossible de crear lo fichièr de basa de donadas <code>$1</code>.",
"config-regenerate": "Regenerar LocalSettings.php →",
"config-show-table-status": "Fracàs de la requèsta <code>SHOW TABLE STATUS</code> !",
- "config-db-web-account": "Compte de la banca de donadas per l'accès Web",
+ "config-db-web-account": "Compte de la basa de donadas per l'accès Web",
"config-db-web-account-same": "Utilizatz lo meteis compte que per l'installacion",
"config-db-web-create": "Creatz lo compte se existís pas ja",
"config-mysql-engine": "Motor d'emmagazinatge :",
"config-mysql-innodb": "InnoDB",
"config-mysql-myisam": "MyISAM",
- "config-mysql-charset": "Jòc de caractèrs de la banca de donadas :",
+ "config-mysql-charset": "Jòc de caractèrs de la basa de donadas :",
"config-mysql-binary": "Binari",
"config-mysql-utf8": "UTF-8",
"config-mssql-auth": "Tipe d’autentificacion :",
"config-admin-error-bademail": "Avètz entrat una adreça de corrièr electronic invalida",
"config-optional-continue": "Me pausar mai de questions.",
"config-optional-skip": "N'ai pro, installar simplament lo wiki.",
- "config-profile": "Perfil dels dreches d’utilizaires :",
+ "config-profile": "Perfil dels dreits d’utilizaires :",
"config-profile-wiki": "Wiki dobèrt",
"config-profile-no-anon": "Creacion de compte requesida",
"config-profile-fishbowl": "Editors autorizats solament",
"config-profile-private": "Wiki privat",
- "config-license": "Dreches d'autor e licéncia :",
+ "config-license": "Dreits d'autor e licéncia :",
"config-license-none": "Pas cap de licéncia en bas de pagina",
"config-license-cc-by-sa": "Creative Commons atribucion partiment a l'identic",
"config-license-cc-by": "Creative Commons Atribucion",
"config-instantcommons": "Activar ''InstantCommons''",
"config-cc-again": "Causissètz tornarmai...",
"config-advanced-settings": "Configuracion avançada",
- "config-cache-options": "Paramètres per la mesa en escondedor dels objèctes :",
+ "config-cache-options": "Paramètres per la mesa en cache dels objèctes :",
"config-memcached-servers": "servidors per Memcached :",
"config-extensions": "Extensions",
"config-skins": "Abilhatges",
"config-skins-use-as-default": "Utilizar aqueste abilhatge per defaut",
- "config-install-step-done": "fach",
+ "config-install-step-done": "fait",
"config-install-step-failed": "fracàs",
"config-install-extensions": "Inclusion de las extensions",
- "config-install-database": "Creacion de la banca de donadas",
+ "config-install-database": "Creacion de la basa de donadas",
"config-install-schema": "Creacion d'esquèma",
"config-install-pg-schema-not-exist": "L'esquèma PostgreSQL existís pas",
"config-install-pg-commit": "Validacion de las modificacions",
"config-install-pg-plpgsql": "Verificacion del lengatge PL/pgSQL",
- "config-install-user": "Creacion d'un utilizaire de la banca de donadas",
+ "config-install-user": "Creacion d'un utilizaire de la basa de donadas",
"config-install-user-alreadyexists": "L'utilizaire « $1 » existís ja.",
"config-install-user-create-failed": "Fracàs al moment de la creacion de l'utilizaire « $1 » : $2",
"config-install-user-grant-failed": "Fracàs al moment de l'apondon de permissions a l'utilizaire « $1 » : $2",
"config-db-wiki-help": "Help text for database user information.",
"config-db-prefix": "Field label for database prefix (a piece of text that all tables for a MediaWiki instance are prefixed with).",
"config-db-prefix-help": "Help text for database prefix form field.",
- "config-db-charset": "Fieldset label for MySQL database character set choice.",
- "config-charset-mysql5-binary": "Option for MySQL database character set choice.",
- "config-charset-mysql5": "Option for MySQL database character set choice.",
- "config-charset-mysql4": "Option for MySQL database character set choice.",
- "config-charset-help": "Help text for database character set.",
"config-mysql-old": "Used as error message. Parameters:\n* $1 - minimum version\n* $2 - the version of MySQL that has been installed\n{{Related|Config-old}}",
"config-db-port": "Field label in MediaWiki installer for database port.",
"config-db-schema": "Field label in MediaWiki installer for database schema.",
"Seb35",
"Striking Blue",
"Ильнар",
- "Macofe"
+ "Macofe",
+ "StasR"
]
},
"config-desc": "Инсталлятор MediaWiki",
"config-back": "← Назад",
"config-continue": "Далее →",
"config-page-language": "Язык",
- "config-page-welcome": "MediaWiki проектына рәхим итегез!",
+ "config-page-welcome": "Добро пожаловать в MediaWiki!",
"config-page-dbconnect": "Подключение к базе данных",
"config-page-upgrade": "Обновление существующей установки",
"config-page-dbsettings": "Настройки базы данных",
"config-db-wiki-help": "Введите имя пользователя и пароль, которые будут использоваться для подключения к базе данных во время обычной работы вики.\nЕсли такой учётной записи не существует, а установочная учётная запись имеет достаточно привилегий, то обычная учётная запись будет создана с минимально необходимыми для работы вики привилегиями.",
"config-db-prefix": "Префикс таблиц базы данных:",
"config-db-prefix-help": "Если вам нужно делить одну базу данных между несколькими вики, или между MediaWiki и другими веб-приложениями, вы можете добавить префикс для всех имён таблиц.\nНе используйте пробелы.\n\nЭто поле обычно остаётся пустым.",
- "config-db-charset": "Кодировка базы данных",
- "config-charset-mysql5-binary": "MySQL 4.1/5.0 бинарная",
- "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
- "config-charset-mysql4": "MySQL 4.0 обратно совместимая с UTF-8",
- "config-charset-help": "'''Внимание.''' Если вы используете '''обратно совместый UTF-8''' на MySQL 4.1+ и создаёте резервные копии базы данных с помощью <code>mysqldump</code>, то все не-ASCII символы могут быть искажены, а резервная копия окажется негодной!\n\nВ '''бинарном режиме''' MediaWiki хранит юникодный текст в базе в виде двоичных полей.\nЭто более эффективно, чем MySQL в режиме UTF-8, позволяет использовать полный набор символов Юникода.\nВ '''режиме UTF-8''' MySQL будет знать к какому набору символу относятся ваши данные, сможет представлять и преобразовать их надлежащим образом (буква Ё окажется при сортировке после буквы Е, а не после буквы Я, как в бинарном режиме),\nно не позволит вам сохранять символы, выходящие за пределы [//ru.wikipedia.org/wiki/Символы,_представленные_в_Юникоде#.D0.91.D0.B0.D0.B7.D0.BE.D0.B2.D0.B0.D1.8F_.D0.BC.D0.BD.D0.BE.D0.B3.D0.BE.D1.8F.D0.B7.D1.8B.D0.BA.D0.BE.D0.B2.D0.B0.D1.8F_.D0.BF.D0.BB.D0.BE.D1.81.D0.BA.D0.BE.D1.81.D1.82.D1.8C BMP].",
"config-mysql-old": "Необходим MySQL $1 или более поздняя версия. У вас установлен MySQL $2.",
"config-db-port": "Порт базы данных:",
"config-db-schema": "Схема для MediaWiki",
{
- "@metadata": [],
- "mainpagetext": "'''ಮೀಡಿಯವಿಕಿ ಯಶಸ್ವಿಯಾದ್ ಇನ್’ಸ್ಟಾಲ್ ಆಂಡ್.'''",
+ "@metadata": {
+ "authors": [
+ "VASANTH S.N."
+ ]
+ },
+ "config-title": "ಮೀಡಿಯಾವಿಕಿ ಆವೃತ್ತಿ $1 ರ ಅನುಸ್ಥಾಪನೆ",
+ "config-information": "ಮಾಹಿತಿ",
+ "config-localsettings-key": "ಉನ್ನತೀಕರಣ ಕೀಲಿ",
+ "config-session-error": "ಅವಧಿ ಪ್ರಾರಂಭದ ದೋಷ: $1",
+ "config-your-language": "ಇರೆನಾ ಬಾಸೆ",
+ "config-wiki-language": "ವಿಕಿ ಭಾಷೆ:",
+ "config-back": "← ಪಿರ",
+ "config-continue": "ಮುಂದುವರೆಸಾಲೆ →",
+ "config-page-language": "ಭಾಸೆ",
+ "config-page-welcome": "ಮಾಧ್ಯಮವಿಕಿಗ್ ಸ್ವಾಗತ",
+ "config-page-dbconnect": "ದತ್ತಾಂಶಸಂಚಯಗ್ ಸಂಪರ್ಕಕೊರ್ಲೆ",
+ "config-page-name": "ಪುದರ್",
+ "config-page-options": "ಆಯ್ಕೆಲು",
+ "config-page-install": "ಸ್ಥಾಪಿಸಾಲೆ",
+ "config-page-complete": "ಪೂರ್ಣ!",
+ "config-page-readme": "ಎನನ್ ಓದುಲೇ",
+ "config-page-releasenotes": "ಬುಡುಗೊಡೆದ ಟಿಪ್ಪಣಿಲು",
+ "config-page-copying": "ನಕಲ್ ಮಲ್ತೊಂದುಂಡು",
+ "config-page-upgradedoc": "ಪರಿಷ್ಕರಣೆ ಆವೊಂದುಂಡು",
+ "config-page-existingwiki": "ಪ್ರಸ್ತುತ ವಿಕಿ",
+ "config-restart": "ಸರಿ,ಕುಡ ಪ್ರಾರಂಭ ಮಲ್ಪುಲೆ",
+ "config-db-type": "ದತ್ತಾಂಶಸಂಚಯ ಮಾದರಿ:",
+ "config-db-host-oracle": "ದತ್ತಾಂಶಸಂಚಯ TNS:",
+ "config-db-wiki-settings": "ಈ ವಿಕಿಯನ್ನು ಗುರುತಿಸಾಲೆ",
+ "config-db-name": "ದತ್ತಾಂಶಸಂಚಯ ಪುದರ್:",
+ "config-db-username": "ದತ್ತಾಂಶಸಂಚಯ ಪುದರ್:",
+ "config-db-password": "ದತ್ತಾಂಶಸಂಚಯ ಪ್ರವೇಶಪದ:",
+ "config-ns-generic": "ಯೋಜನೆ",
+ "config-admin-password": "ಪ್ರವೇಶ ಪದೊ",
+ "config-admin-password-confirm": "ಪುನಃ ಪ್ರವೇಶ ಪದೊ:",
+ "config-admin-password-mismatch": "ಈರ್ ಕೊರ್ನ ಪ್ರವೇಶ ಪದೆ ಬೇತೆ ಬೇತೆ ಅತ್ಂಡ್",
+ "config-admin-email": "ಇ-ಅಂಚೆ ವಿಳಾಸೊ",
+ "config-license": "ಕೃತಿಸ್ವಾಮ್ಯ ಬೊಕ್ಕ ಪರವಾನಗಿ:",
+ "config-license-pd": "ಸಾರ್ವಜನಿಕೊ ಕ್ಷೇತ್ರೊ",
+ "config-extensions": "ವಿಸ್ತರಣೆಲು",
+ "config-install-step-failed": "ವಿಫಲವಾತ್ಂಡ್",
+ "config-install-extensions": "ವಿಸ್ತರಣೆಲೆನ್ ಸೇರಾದ್",
+ "config-help": "ಸಹಾಯೊ",
+ "mainpagetext": "'''ಮೀಡಿಯವಿಕಿ ಯಶಸ್ವಿಯಾದ್ ಸ್ಥಾಪನೆ ಆಂಡ್.'''",
"mainpagedocfooter": "ವಿಕಿ ತಂತ್ರಾಂಶನ್ ಉಪಗೋಗ ಮನ್ಪುನ ಬಗ್ಗೆ ಮಾಹಿತಿಗ್ [//meta.wikimedia.org/wiki/Help:Contents ಸದಸ್ಯೆರ್ನ ನಿರ್ದೇಶನ ಪುಟ] ತೂಲೆ.\n\n== ಎಂಚ ಶುರು ಮಲ್ಪುನಿ ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ ಮೀಡಿಯವಿಕಿ FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki release mailing list]"
}
"S8321414",
"LNDDYL",
"NigelSoft",
- "Macofe"
+ "Macofe",
+ "Reke"
]
},
"config-desc": "MediaWiki 安裝程式",
"config-localsettings-upgrade": "已偵測到 <code>LocalSettings.php</code> 檔案。\n要升級目前安裝的版本,請在下方輸入框中輸入 <code>$wgUpgradeKey</code> 的值。\n您可以從 <code>LocalSettings.php</code> 檔案中找到。",
"config-localsettings-cli-upgrade": "已偵測到 <code>LocalSettings.php</code> 檔案。\n要升級目前安裝的版本,請執行 <code>update.php</code>。",
"config-localsettings-key": "升級金鑰:",
- "config-localsettings-badkey": "你提供的金鑰不正確。",
+ "config-localsettings-badkey": "你提供的升級金鑰不正確。",
"config-upgrade-key-missing": "已偵測到先前安裝的 MediaWiki。\n要升級目前安裝的版本,請將下列文字附加到 <code>LocalSettings.php</code> 的檔案最下方:\n\n$1",
"config-localsettings-incomplete": "目前的 <code>LocalSettings.php</code> 檔案不完整。\n未設定參數 $1。\n請將此參數設定至 <code>LocalSettings.php</code> 中,並點選 \"{{int:Config-continue}}\"。",
"config-localsettings-connection-error": "使用 <code>LocalSettings.php</code> 中所指定的資料庫設定連線發生錯誤。 請修復相關設定並再試一次。\n\n$1",
--- /dev/null
+<?php
+namespace MediaWiki\Interwiki;
+
+/**
+ * InterwikiLookup implementing the "classic" interwiki storage (hardcoded up to MW 1.26).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+use \Cdb\Exception as CdbException;
+use \Cdb\Reader as CdbReader;
+use Database;
+use Hooks;
+use Interwiki;
+use Language;
+use MapCacheLRU;
+use WANObjectCache;
+
+/**
+ * InterwikiLookup implementing the "classic" interwiki storage (hardcoded up to MW 1.26).
+ *
+ * This implements two levels of caching (in-process array and a WANObjectCache)
+ * and tree storage backends (SQL, CDB, and plain PHP arrays).
+ *
+ * All information is loaded on creation when called by $this->fetch( $prefix ).
+ * All work is done on slave, because this should *never* change (except during
+ * schema updates etc, which aren't wiki-related)
+ *
+ * @since 1.28
+ */
+class ClassicInterwikiLookup implements InterwikiLookup {
+
+ /**
+ * @var MapCacheLRU
+ */
+ private $localCache;
+
+ /**
+ * @var Language
+ */
+ private $contentLanguage;
+
+ /**
+ * @var WANObjectCache
+ */
+ private $objectCache;
+
+ /**
+ * @var int
+ */
+ private $objectCacheExpiry;
+
+ /**
+ * @var bool|array|string
+ */
+ private $cdbData;
+
+ /**
+ * @var int
+ */
+ private $interwikiScopes;
+
+ /**
+ * @var string
+ */
+ private $fallbackSite;
+
+ /**
+ * @var CdbReader|null
+ */
+ private $cdbReader = null;
+
+ /**
+ * @var string|null
+ */
+ private $thisSite = null;
+
+ /**
+ * @param Language $contentLanguage Language object used to convert prefixes to lower case
+ * @param WANObjectCache $objectCache Cache for interwiki info retrieved from the database
+ * @param int $objectCacheExpiry Expiry time for $objectCache, in seconds
+ * @param bool|array|string $cdbData The path of a CDB file, or
+ * an array resembling the contents of a CDB file,
+ * or false to use the database.
+ * @param int $interwikiScopes Specify number of domains to check for messages:
+ * - 1: Just local wiki level
+ * - 2: wiki and global levels
+ * - 3: site level as well as wiki and global levels
+ * @param string $fallbackSite The code to assume for the local site,
+ */
+ function __construct(
+ Language $contentLanguage,
+ WANObjectCache $objectCache,
+ $objectCacheExpiry,
+ $cdbData,
+ $interwikiScopes,
+ $fallbackSite
+ ) {
+ $this->localCache = new MapCacheLRU( 100 );
+
+ $this->contentLanguage = $contentLanguage;
+ $this->objectCache = $objectCache;
+ $this->objectCacheExpiry = $objectCacheExpiry;
+ $this->cdbData = $cdbData;
+ $this->interwikiScopes = $interwikiScopes;
+ $this->fallbackSite = $fallbackSite;
+ }
+
+ /**
+ * Check whether an interwiki prefix exists
+ *
+ * @param string $prefix Interwiki prefix to use
+ * @return bool Whether it exists
+ */
+ public function isValidInterwiki( $prefix ) {
+ $result = $this->fetch( $prefix );
+
+ return (bool)$result;
+ }
+
+ /**
+ * Fetch an Interwiki object
+ *
+ * @param string $prefix Interwiki prefix to use
+ * @return Interwiki|null|bool
+ */
+ public function fetch( $prefix ) {
+ if ( $prefix == '' ) {
+ return null;
+ }
+
+ $prefix = $this->contentLanguage->lc( $prefix );
+ if ( $this->localCache->has( $prefix ) ) {
+ return $this->localCache->get( $prefix );
+ }
+
+ if ( $this->cdbData ) {
+ $iw = $this->getInterwikiCached( $prefix );
+ } else {
+ $iw = $this->load( $prefix );
+ if ( !$iw ) {
+ $iw = false;
+ }
+ }
+ $this->localCache->set( $prefix, $iw );
+
+ return $iw;
+ }
+
+ /**
+ * Resets locally cached Interwiki objects. This is intended for use during testing only.
+ * This does not invalidate entries in the persistent cache, as invalidateCache() does.
+ * @since 1.27
+ */
+ public function resetLocalCache() {
+ $this->localCache->clear();
+ }
+
+ /**
+ * Purge the in-process and object cache for an interwiki prefix
+ * @param string $prefix
+ */
+ public function invalidateCache( $prefix ) {
+ $this->localCache->clear( $prefix );
+
+ $key = $this->objectCache->makeKey( 'interwiki', $prefix );
+ $this->objectCache->delete( $key );
+ }
+
+ /**
+ * Fetch interwiki prefix data from local cache in constant database.
+ *
+ * @note More logic is explained in DefaultSettings.
+ *
+ * @param string $prefix Interwiki prefix
+ * @return Interwiki
+ */
+ private function getInterwikiCached( $prefix ) {
+ $value = $this->getInterwikiCacheEntry( $prefix );
+
+ if ( $value ) {
+ // Split values
+ list( $local, $url ) = explode( ' ', $value, 2 );
+ return new Interwiki( $prefix, $url, '', '', (int)$local );
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get entry from interwiki cache
+ *
+ * @note More logic is explained in DefaultSettings.
+ *
+ * @param string $prefix Database key
+ * @return bool|string The interwiki entry or false if not found
+ */
+ private function getInterwikiCacheEntry( $prefix ) {
+ wfDebug( __METHOD__ . "( $prefix )\n" );
+ $value = false;
+ try {
+ // Resolve site name
+ if ( $this->interwikiScopes >= 3 && !$this->thisSite ) {
+ $this->thisSite = $this->getCacheValue( '__sites:' . wfWikiID() );
+ if ( $this->thisSite == '' ) {
+ $this->thisSite = $this->fallbackSite;
+ }
+ }
+
+ $value = $this->getCacheValue( wfMemcKey( $prefix ) );
+ // Site level
+ if ( $value == '' && $this->interwikiScopes >= 3 ) {
+ $value = $this->getCacheValue( "_{$this->thisSite}:{$prefix}" );
+ }
+ // Global Level
+ if ( $value == '' && $this->interwikiScopes >= 2 ) {
+ $value = $this->getCacheValue( "__global:{$prefix}" );
+ }
+ if ( $value == 'undef' ) {
+ $value = '';
+ }
+ } catch ( CdbException $e ) {
+ wfDebug( __METHOD__ . ": CdbException caught, error message was "
+ . $e->getMessage() );
+ }
+
+ return $value;
+ }
+
+ private function getCacheValue( $key ) {
+ if ( $this->cdbReader === null ) {
+ if ( is_string( $this->cdbData ) ) {
+ $this->cdbReader = \Cdb\Reader::open( $this->cdbData );
+ } elseif ( is_array( $this->cdbData ) ) {
+ $this->cdbReader = new \Cdb\Reader\Hash( $this->cdbData );
+ } else {
+ $this->cdbReader = false;
+ }
+ }
+
+ if ( $this->cdbReader ) {
+ return $this->cdbReader->get( $key );
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Load the interwiki, trying first memcached then the DB
+ *
+ * @param string $prefix The interwiki prefix
+ * @return Interwiki|bool Interwiki if $prefix is valid, otherwise false
+ */
+ private function load( $prefix ) {
+ $iwData = [];
+ if ( !Hooks::run( 'InterwikiLoadPrefix', [ $prefix, &$iwData ] ) ) {
+ return $this->loadFromArray( $iwData );
+ }
+
+ if ( is_array( $iwData ) ) {
+ $iw = $this->loadFromArray( $iwData );
+ if ( $iw ) {
+ return $iw; // handled by hook
+ }
+ }
+
+ $iwData = $this->objectCache->getWithSetCallback(
+ $this->objectCache->makeKey( 'interwiki', $prefix ),
+ $this->objectCacheExpiry,
+ function ( $oldValue, &$ttl, array &$setOpts ) use ( $prefix ) {
+ $dbr = wfGetDB( DB_SLAVE ); // TODO: inject LoadBalancer
+
+ $setOpts += Database::getCacheSetOptions( $dbr );
+
+ $row = $dbr->selectRow(
+ 'interwiki',
+ ClassicInterwikiLookup::selectFields(),
+ [ 'iw_prefix' => $prefix ],
+ __METHOD__
+ );
+
+ return $row ? (array)$row : '!NONEXISTENT';
+ }
+ );
+
+ if ( is_array( $iwData ) ) {
+ return $this->loadFromArray( $iwData ) ?: false;
+ }
+
+ return false;
+ }
+
+ /**
+ * Fill in member variables from an array (e.g. memcached result, Database::fetchRow, etc)
+ *
+ * @param array $mc Associative array: row from the interwiki table
+ * @return Interwiki|bool Interwiki object or false if $mc['iw_url'] is not set
+ */
+ private function loadFromArray( $mc ) {
+ if ( isset( $mc['iw_url'] ) ) {
+ $url = $mc['iw_url'];
+ $local = isset( $mc['iw_local'] ) ? $mc['iw_local'] : 0;
+ $trans = isset( $mc['iw_trans'] ) ? $mc['iw_trans'] : 0;
+ $api = isset( $mc['iw_api'] ) ? $mc['iw_api'] : '';
+ $wikiId = isset( $mc['iw_wikiid'] ) ? $mc['iw_wikiid'] : '';
+
+ return new Interwiki( null, $url, $api, $wikiId, $local, $trans );
+ }
+
+ return false;
+ }
+
+ /**
+ * Fetch all interwiki prefixes from interwiki cache
+ *
+ * @param null|string $local If not null, limits output to local/non-local interwikis
+ * @return array List of prefixes, where each row is an associative array
+ */
+ private function getAllPrefixesCached( $local ) {
+ wfDebug( __METHOD__ . "()\n" );
+ $data = [];
+ try {
+ /* Resolve site name */
+ if ( $this->interwikiScopes >= 3 && !$this->thisSite ) {
+ $site = $this->getCacheValue( '__sites:' . wfWikiID() );
+
+ if ( $site == '' ) {
+ $this->thisSite = $this->fallbackSite;
+ } else {
+ $this->thisSite = $site;
+ }
+ }
+
+ // List of interwiki sources
+ $sources = [];
+ // Global Level
+ if ( $this->interwikiScopes >= 2 ) {
+ $sources[] = '__global';
+ }
+ // Site level
+ if ( $this->interwikiScopes >= 3 ) {
+ $sources[] = '_' . $this->thisSite;
+ }
+ $sources[] = wfWikiID();
+
+ foreach ( $sources as $source ) {
+ $list = $this->getCacheValue( '__list:' . $source );
+ foreach ( explode( ' ', $list ) as $iw_prefix ) {
+ $row = $this->getCacheValue( "{$source}:{$iw_prefix}" );
+ if ( !$row ) {
+ continue;
+ }
+
+ list( $iw_local, $iw_url ) = explode( ' ', $row );
+
+ if ( $local !== null && $local != $iw_local ) {
+ continue;
+ }
+
+ $data[$iw_prefix] = [
+ 'iw_prefix' => $iw_prefix,
+ 'iw_url' => $iw_url,
+ 'iw_local' => $iw_local,
+ ];
+ }
+ }
+ } catch ( CdbException $e ) {
+ wfDebug( __METHOD__ . ": CdbException caught, error message was "
+ . $e->getMessage() );
+ }
+
+ ksort( $data );
+
+ return array_values( $data );
+ }
+
+ /**
+ * Fetch all interwiki prefixes from DB
+ *
+ * @param string|null $local If not null, limits output to local/non-local interwikis
+ * @return array[] Interwiki rows
+ */
+ private function getAllPrefixesDB( $local ) {
+ $db = wfGetDB( DB_SLAVE ); // TODO: inject DB LoadBalancer
+
+ $where = [];
+
+ if ( $local !== null ) {
+ if ( $local == 1 ) {
+ $where['iw_local'] = 1;
+ } elseif ( $local == 0 ) {
+ $where['iw_local'] = 0;
+ }
+ }
+
+ $res = $db->select( 'interwiki',
+ $this->selectFields(),
+ $where, __METHOD__, [ 'ORDER BY' => 'iw_prefix' ]
+ );
+
+ $retval = [];
+ foreach ( $res as $row ) {
+ $retval[] = (array)$row;
+ }
+
+ return $retval;
+ }
+
+ /**
+ * Returns all interwiki prefixes
+ *
+ * @param string|null $local If set, limits output to local/non-local interwikis
+ * @return array[] Interwiki rows, where each row is an associative array
+ */
+ public function getAllPrefixes( $local = null ) {
+ if ( $this->cdbData ) {
+ return $this->getAllPrefixesCached( $local );
+ }
+
+ return $this->getAllPrefixesDB( $local );
+ }
+
+ /**
+ * Return the list of interwiki fields that should be selected to create
+ * a new Interwiki object.
+ * @return string[]
+ */
+ private static function selectFields() {
+ return [
+ 'iw_prefix',
+ 'iw_url',
+ 'iw_api',
+ 'iw_wikiid',
+ 'iw_local',
+ 'iw_trans'
+ ];
+ }
+
+}
*
* @file
*/
-use \Cdb\Exception as CdbException;
-use \Cdb\Reader as CdbReader;
+use MediaWiki\MediaWikiServices;
/**
- * The interwiki class
- * All information is loaded on creation when called by Interwiki::fetch( $prefix ).
- * All work is done on slave, because this should *never* change (except during
- * schema updates etc, which aren't wiki-related)
+ * Value object for representing interwiki records.
*/
class Interwiki {
- // Cache - removes oldest entry when it hits limit
- protected static $smCache = [];
- const CACHE_LIMIT = 100; // 0 means unlimited, any other value is max number of entries.
/** @var string The interwiki prefix, (e.g. "Meatball", or the language prefix "de") */
protected $mPrefix;
/**
* Check whether an interwiki prefix exists
*
+ * @deprecated since 1.28, use InterwikiLookup instead
+ *
* @param string $prefix Interwiki prefix to use
* @return bool Whether it exists
*/
public static function isValidInterwiki( $prefix ) {
- $result = self::fetch( $prefix );
-
- return (bool)$result;
+ return MediaWikiServices::getInstance()->getInterwikiLookup()->isValidInterwiki( $prefix );
}
/**
* Fetch an Interwiki object
*
+ * @deprecated since 1.28, use InterwikiLookup instead
+ *
* @param string $prefix Interwiki prefix to use
* @return Interwiki|null|bool
*/
public static function fetch( $prefix ) {
- global $wgContLang;
-
- if ( $prefix == '' ) {
- return null;
- }
-
- $prefix = $wgContLang->lc( $prefix );
- if ( isset( self::$smCache[$prefix] ) ) {
- return self::$smCache[$prefix];
- }
-
- global $wgInterwikiCache;
- if ( $wgInterwikiCache ) {
- $iw = Interwiki::getInterwikiCached( $prefix );
- } else {
- $iw = Interwiki::load( $prefix );
- if ( !$iw ) {
- $iw = false;
- }
- }
-
- if ( self::CACHE_LIMIT && count( self::$smCache ) >= self::CACHE_LIMIT ) {
- reset( self::$smCache );
- unset( self::$smCache[key( self::$smCache )] );
- }
-
- self::$smCache[$prefix] = $iw;
-
- return $iw;
- }
-
- /**
- * Resets locally cached Interwiki objects. This is intended for use during testing only.
- * This does not invalidate entries in the persistent cache, as invalidateCache() does.
- * @since 1.27
- */
- public static function resetLocalCache() {
- static::$smCache = [];
+ return MediaWikiServices::getInstance()->getInterwikiLookup()->fetch( $prefix );
}
/**
* Purge the cache (local and persistent) for an interwiki prefix.
+ *
* @param string $prefix
* @since 1.26
*/
public static function invalidateCache( $prefix ) {
- $cache = ObjectCache::getMainWANInstance();
- $key = wfMemcKey( 'interwiki', $prefix );
- $cache->delete( $key );
- unset( static::$smCache[$prefix] );
- }
-
- /**
- * Fetch interwiki prefix data from local cache in constant database.
- *
- * @note More logic is explained in DefaultSettings.
- *
- * @param string $prefix Interwiki prefix
- * @return Interwiki
- */
- protected static function getInterwikiCached( $prefix ) {
- $value = self::getInterwikiCacheEntry( $prefix );
-
- $s = new Interwiki( $prefix );
- if ( $value ) {
- // Split values
- list( $local, $url ) = explode( ' ', $value, 2 );
- $s->mURL = $url;
- $s->mLocal = (bool)$local;
- } else {
- $s = false;
- }
-
- return $s;
- }
-
- /**
- * Get entry from interwiki cache
- *
- * @note More logic is explained in DefaultSettings.
- *
- * @param string $prefix Database key
- * @return bool|string The interwiki entry or false if not found
- */
- protected static function getInterwikiCacheEntry( $prefix ) {
- global $wgInterwikiScopes, $wgInterwikiFallbackSite;
- static $site;
-
- wfDebug( __METHOD__ . "( $prefix )\n" );
- $value = false;
- try {
- // Resolve site name
- if ( $wgInterwikiScopes >= 3 && !$site ) {
- $site = self::getCacheValue( '__sites:' . wfWikiID() );
- if ( $site == '' ) {
- $site = $wgInterwikiFallbackSite;
- }
- }
-
- $value = self::getCacheValue( wfMemcKey( $prefix ) );
- // Site level
- if ( $value == '' && $wgInterwikiScopes >= 3 ) {
- $value = self::getCacheValue( "_{$site}:{$prefix}" );
- }
- // Global Level
- if ( $value == '' && $wgInterwikiScopes >= 2 ) {
- $value = self::getCacheValue( "__global:{$prefix}" );
- }
- if ( $value == 'undef' ) {
- $value = '';
- }
- } catch ( CdbException $e ) {
- wfDebug( __METHOD__ . ": CdbException caught, error message was "
- . $e->getMessage() );
- }
-
- return $value;
- }
-
- private static function getCacheValue( $key ) {
- global $wgInterwikiCache;
- static $reader;
- if ( $reader === null ) {
- $reader = is_array( $wgInterwikiCache ) ? false : CdbReader::open( $wgInterwikiCache );
- }
- if ( $reader ) {
- return $reader->get( $key );
- } else {
- return isset( $wgInterwikiCache[$key] ) ? $wgInterwikiCache[$key] : false;
- }
- }
-
- /**
- * Load the interwiki, trying first memcached then the DB
- *
- * @param string $prefix The interwiki prefix
- * @return Interwiki|bool Interwiki if $prefix is valid, otherwise false
- */
- protected static function load( $prefix ) {
- global $wgInterwikiExpiry;
-
- $iwData = [];
- if ( !Hooks::run( 'InterwikiLoadPrefix', [ $prefix, &$iwData ] ) ) {
- return Interwiki::loadFromArray( $iwData );
- }
-
- if ( is_array( $iwData ) ) {
- $iw = Interwiki::loadFromArray( $iwData );
- if ( $iw ) {
- return $iw; // handled by hook
- }
- }
-
- $iwData = ObjectCache::getMainWANInstance()->getWithSetCallback(
- wfMemcKey( 'interwiki', $prefix ),
- $wgInterwikiExpiry,
- function ( $oldValue, &$ttl, array &$setOpts ) use ( $prefix ) {
- $dbr = wfGetDB( DB_SLAVE );
-
- $setOpts += Database::getCacheSetOptions( $dbr );
-
- $row = $dbr->selectRow(
- 'interwiki',
- Interwiki::selectFields(),
- [ 'iw_prefix' => $prefix ],
- __METHOD__
- );
-
- return $row ? (array)$row : '!NONEXISTENT';
- }
- );
-
- if ( is_array( $iwData ) ) {
- return Interwiki::loadFromArray( $iwData ) ?: false;
- }
-
- return false;
- }
-
- /**
- * Fill in member variables from an array (e.g. memcached result, Database::fetchRow, etc)
- *
- * @param array $mc Associative array: row from the interwiki table
- * @return Interwiki|bool Interwiki object or false if $mc['iw_url'] is not set
- */
- protected static function loadFromArray( $mc ) {
- if ( isset( $mc['iw_url'] ) ) {
- $iw = new Interwiki();
- $iw->mURL = $mc['iw_url'];
- $iw->mLocal = isset( $mc['iw_local'] ) ? (bool)$mc['iw_local'] : false;
- $iw->mTrans = isset( $mc['iw_trans'] ) ? (bool)$mc['iw_trans'] : false;
- $iw->mAPI = isset( $mc['iw_api'] ) ? $mc['iw_api'] : '';
- $iw->mWikiID = isset( $mc['iw_wikiid'] ) ? $mc['iw_wikiid'] : '';
-
- return $iw;
- }
-
- return false;
- }
-
- /**
- * Fetch all interwiki prefixes from interwiki cache
- *
- * @param null|string $local If not null, limits output to local/non-local interwikis
- * @return array List of prefixes
- * @since 1.19
- */
- protected static function getAllPrefixesCached( $local ) {
- global $wgInterwikiScopes, $wgInterwikiFallbackSite;
- static $site;
-
- wfDebug( __METHOD__ . "()\n" );
- $data = [];
- try {
- /* Resolve site name */
- if ( $wgInterwikiScopes >= 3 && !$site ) {
- $site = self::getCacheValue( '__sites:' . wfWikiID() );
-
- if ( $site == '' ) {
- $site = $wgInterwikiFallbackSite;
- }
- }
-
- // List of interwiki sources
- $sources = [];
- // Global Level
- if ( $wgInterwikiScopes >= 2 ) {
- $sources[] = '__global';
- }
- // Site level
- if ( $wgInterwikiScopes >= 3 ) {
- $sources[] = '_' . $site;
- }
- $sources[] = wfWikiID();
-
- foreach ( $sources as $source ) {
- $list = self::getCacheValue( '__list:' . $source );
- foreach ( explode( ' ', $list ) as $iw_prefix ) {
- $row = self::getCacheValue( "{$source}:{$iw_prefix}" );
- if ( !$row ) {
- continue;
- }
-
- list( $iw_local, $iw_url ) = explode( ' ', $row );
-
- if ( $local !== null && $local != $iw_local ) {
- continue;
- }
-
- $data[$iw_prefix] = [
- 'iw_prefix' => $iw_prefix,
- 'iw_url' => $iw_url,
- 'iw_local' => $iw_local,
- ];
- }
- }
- } catch ( CdbException $e ) {
- wfDebug( __METHOD__ . ": CdbException caught, error message was "
- . $e->getMessage() );
- }
-
- ksort( $data );
-
- return array_values( $data );
- }
-
- /**
- * Fetch all interwiki prefixes from DB
- *
- * @param string|null $local If not null, limits output to local/non-local interwikis
- * @return array List of prefixes
- * @since 1.19
- */
- protected static function getAllPrefixesDB( $local ) {
- $db = wfGetDB( DB_SLAVE );
-
- $where = [];
-
- if ( $local !== null ) {
- if ( $local == 1 ) {
- $where['iw_local'] = 1;
- } elseif ( $local == 0 ) {
- $where['iw_local'] = 0;
- }
- }
-
- $res = $db->select( 'interwiki',
- self::selectFields(),
- $where, __METHOD__, [ 'ORDER BY' => 'iw_prefix' ]
- );
-
- $retval = [];
- foreach ( $res as $row ) {
- $retval[] = (array)$row;
- }
-
- return $retval;
+ return MediaWikiServices::getInstance()->getInterwikiLookup()->invalidateCache( $prefix );
}
/**
* Returns all interwiki prefixes
*
+ * @deprecated since 1.28, unused. Use InterwikiLookup instead.
+ *
* @param string|null $local If set, limits output to local/non-local interwikis
* @return array List of prefixes
* @since 1.19
*/
public static function getAllPrefixes( $local = null ) {
- global $wgInterwikiCache;
-
- if ( $wgInterwikiCache ) {
- return self::getAllPrefixesCached( $local );
- }
-
- return self::getAllPrefixesDB( $local );
+ return MediaWikiServices::getInstance()->getInterwikiLookup()->getAllPrefixes( $local );
}
/**
return !$msg->exists() ? '' : $msg->text();
}
- /**
- * Return the list of interwiki fields that should be selected to create
- * a new Interwiki object.
- * @return string[]
- */
- public static function selectFields() {
- return [
- 'iw_prefix',
- 'iw_url',
- 'iw_api',
- 'iw_wikiid',
- 'iw_local',
- 'iw_trans'
- ];
- }
}
--- /dev/null
+<?php
+namespace MediaWiki\Interwiki;
+
+/**
+ * Service interface for looking up Interwiki records.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+use Interwiki;
+
+/**
+ * Service interface for looking up Interwiki records.
+ *
+ * @singe 1.28
+ */
+interface InterwikiLookup {
+
+ /**
+ * Check whether an interwiki prefix exists
+ *
+ * @param string $prefix Interwiki prefix to use
+ * @return bool Whether it exists
+ */
+ public function isValidInterwiki( $prefix );
+
+ /**
+ * Fetch an Interwiki object
+ *
+ * @param string $prefix Interwiki prefix to use
+ * @return Interwiki|null|bool
+ */
+ public function fetch( $prefix );
+
+ /**
+ * Returns all interwiki prefixes
+ *
+ * @param string|null $local If set, limits output to local/non-local interwikis
+ * @return string[] List of prefixes
+ */
+ public function getAllPrefixes( $local = null );
+
+ /**
+ * Purge the in-process and persistent object cache for an interwiki prefix
+ * @param string $prefix
+ */
+ public function invalidateCache( $prefix );
+
+}
DeferredUpdates::doUpdates();
$this->commitMasterChanges( $job );
- $job->teardown();
} catch ( Exception $e ) {
MWExceptionHandler::rollbackMasterChangesAndLog( $e );
$status = false;
$error = get_class( $e ) . ': ' . $e->getMessage();
MWExceptionHandler::logException( $e );
}
+ // Always attempt to call teardown() even if Job throws exception.
+ try {
+ $job->teardown();
+ } catch ( Exception $e ) {
+ MWExceptionHandler::logException( $e );
+ }
+
// Commit all outstanding connections that are in a transaction
// to get a fresh repeatable read snapshot on every connection.
// Note that jobs are still responsible for handling slave lag.
}
public function run() {
- /** @noinspection PhpUnusedLocalVariableInspection */
$scope = RequestContext::importScopedSession( $this->params['session'] );
$this->addTeardownCallback( function () use ( &$scope ) {
ScopedCallback::consume( $scope ); // T126450
}
public function run() {
- /** @noinspection PhpUnusedLocalVariableInspection */
$scope = RequestContext::importScopedSession( $this->params['session'] );
$this->addTeardownCallback( function () use ( &$scope ) {
ScopedCallback::consume( $scope ); // T126450
}
protected function purgeExpiredRows() {
- global $wgRCMaxAge;
+ global $wgRCMaxAge, $wgUpdateRowsPerQuery;
$lockKey = wfWikiID() . ':recentchanges-prune';
return; // already in progress
}
- $batchSize = 100; // avoid slave lag
$cutoff = $dbw->timestamp( time() - $wgRCMaxAge );
do {
$rcIds = $dbw->selectFieldValues( 'recentchanges',
'rc_id',
[ 'rc_timestamp < ' . $dbw->addQuotes( $cutoff ) ],
__METHOD__,
- [ 'LIMIT' => $batchSize ]
+ [ 'LIMIT' => $wgUpdateRowsPerQuery ]
);
if ( $rcIds ) {
$dbw->delete( 'recentchanges', [ 'rc_id' => $rcIds ], __METHOD__ );
// Commit in chunks to avoid slave lag
$dbw->commit( __METHOD__, 'flush' );
- if ( count( $rcIds ) === $batchSize ) {
+ if ( count( $rcIds ) === $wgUpdateRowsPerQuery ) {
// There might be more, so try waiting for slaves
try {
wfGetLBFactory()->waitForReplication( [ 'timeout' => 3 ] );
// Needed by things like Echo notifications which need
// to know which user caused the links update
if ( $update instanceof LinksUpdate ) {
+ $update->setRevision( $revision );
if ( !empty( $this->params['triggeringUser'] ) ) {
$userInfo = $this->params['triggeringUser'];
if ( $userInfo['userId'] ) {
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @license GPL-2.0+
+ * @author Kunal Mehta <legoktm@member.fsf.org>
+ */
+
+/**
+ * Marks HTML that shouldn't be escaped
+ *
+ * @since 1.28
+ */
+class HtmlArmor {
+
+ /**
+ * @var string
+ */
+ private $value;
+
+ /**
+ * @param string $value
+ */
+ public function __construct( $value ) {
+ $this->value = $value;
+ }
+
+ /**
+ * Provide a string or HtmlArmor object
+ * and get safe HTML back
+ *
+ * @param string|HtmlArmor $input
+ * @return string safe for usage in HTML
+ */
+ public static function getHtml( $input ) {
+ if ( $input instanceof HtmlArmor ) {
+ return $input->value;
+ } else {
+ return htmlspecialchars( $input );
+ }
+ }
+}
* @file
*/
-use RunningStat\RunningStat;
-
/**
* Convenience class for working with XHProf
* <https://github.com/phacility/xhprof>. XHProf can be installed as a PECL
* package for use with PHP5 (Zend PHP) and is built-in to HHVM 3.3.0.
*
- * @author Bryan Davis <bd808@wikimedia.org>
- * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
- * @since 1.25
+ * @since 1.28
*/
class Xhprof {
-
- /**
- * @var array $config
- */
- protected $config;
-
- /**
- * Hierarchical profiling data returned by xhprof.
- * @var array $hieraData
- */
- protected $hieraData;
-
/**
- * Per-function inclusive data.
- * @var array $inclusive
+ * @var bool $enabled Whether XHProf is currently running.
*/
- protected $inclusive;
+ protected static $enabled;
/**
- * Per-function inclusive and exclusive data.
- * @var array $complete
+ * Start xhprof profiler
*/
- protected $complete;
-
- /**
- * Configuration data can contain:
- * - flags: Optional flags to add additional information to the
- * profiling data collected.
- * (XHPROF_FLAGS_NO_BUILTINS, XHPROF_FLAGS_CPU,
- * XHPROF_FLAGS_MEMORY)
- * - exclude: Array of function names to exclude from profiling.
- * - include: Array of function names to include in profiling.
- * - sort: Key to sort per-function reports on.
- *
- * Note: When running under HHVM, xhprof will always behave as though the
- * XHPROF_FLAGS_NO_BUILTINS flag has been used unless the
- * Eval.JitEnableRenameFunction option is enabled for the HHVM process.
- *
- * @param array $config
- */
- public function __construct( array $config = [] ) {
- $this->config = array_merge(
- [
- 'flags' => 0,
- 'exclude' => [],
- 'include' => null,
- 'sort' => 'wt',
- ],
- $config
- );
-
- xhprof_enable( $this->config['flags'], [
- 'ignored_functions' => $this->config['exclude']
- ] );
+ public static function isEnabled() {
+ return self::$enabled;
}
/**
- * Stop collecting profiling data.
- *
- * Only the first invocation of this method will effect the internal
- * object state. Subsequent calls will return the data collected by the
- * initial call.
- *
- * @return array Collected profiling data (possibly cached)
+ * Start xhprof profiler
*/
- public function stop() {
- if ( $this->hieraData === null ) {
- $this->hieraData = $this->pruneData( xhprof_disable() );
+ public static function enable( $flags = 0, $options = [] ) {
+ if ( self::isEnabled() ) {
+ throw new Exception( 'Xhprof profiling is already enabled.' );
}
- return $this->hieraData;
- }
-
- /**
- * Load raw data from a prior run for analysis.
- * Stops any existing data collection and clears internal caches.
- *
- * Any 'include' filters configured for this Xhprof instance will be
- * enforced on the data as it is loaded. 'exclude' filters will however
- * not be enforced as they are an XHProf intrinsic behavior.
- *
- * @param array $data
- * @see getRawData()
- */
- public function loadRawData( array $data ) {
- $this->stop();
- $this->inclusive = null;
- $this->complete = null;
- $this->hieraData = $this->pruneData( $data );
- }
-
- /**
- * Get raw data collected by xhprof.
- *
- * If data collection has not been stopped yet this method will halt
- * collection to gather the profiling data.
- *
- * Each key in the returned array is an edge label for the call graph in
- * the form "caller==>callee". There is once special case edge labled
- * simply "main()" which represents the global scope entry point of the
- * application.
- *
- * XHProf will collect different data depending on the flags that are used:
- * - ct: Number of matching events seen.
- * - wt: Inclusive elapsed wall time for this event in microseconds.
- * - cpu: Inclusive elapsed cpu time for this event in microseconds.
- * (XHPROF_FLAGS_CPU)
- * - mu: Delta of memory usage from start to end of callee in bytes.
- * (XHPROF_FLAGS_MEMORY)
- * - pmu: Delta of peak memory usage from start to end of callee in
- * bytes. (XHPROF_FLAGS_MEMORY)
- * - alloc: Delta of amount memory requested from malloc() by the callee,
- * in bytes. (XHPROF_FLAGS_MALLOC)
- * - free: Delta of amount of memory passed to free() by the callee, in
- * bytes. (XHPROF_FLAGS_MALLOC)
- *
- * @return array
- * @see stop()
- * @see getInclusiveMetrics()
- * @see getCompleteMetrics()
- */
- public function getRawData() {
- return $this->stop();
+ self::$enabled = true;
+ xhprof_enable( $flags, $options );
}
/**
- * Convert an xhprof data key into an array of ['parent', 'child']
- * function names.
- *
- * The resulting array is left padded with nulls, so a key
- * with no parent (eg 'main()') will return [null, 'function'].
+ * Stop xhprof profiler
*
- * @return array
+ * @return array|null xhprof data from the run, or null if xhprof was not running.
*/
- public static function splitKey( $key ) {
- return array_pad( explode( '==>', $key, 2 ), -2, null );
- }
-
- /**
- * Remove data for functions that are not included in the 'include'
- * configuration array.
- *
- * @param array $data Raw xhprof data
- * @return array
- */
- protected function pruneData( $data ) {
- if ( !$this->config['include'] ) {
- return $data;
- }
-
- $want = array_fill_keys( $this->config['include'], true );
- $want['main()'] = true;
-
- $keep = [];
- foreach ( $data as $key => $stats ) {
- list( $parent, $child ) = self::splitKey( $key );
- if ( isset( $want[$parent] ) || isset( $want[$child] ) ) {
- $keep[$key] = $stats;
- }
+ public static function disable() {
+ if ( self::isEnabled() ) {
+ self::$enabled = false;
+ return xhprof_disable();
}
- return $keep;
- }
-
- /**
- * Get the inclusive metrics for each function call. Inclusive metrics
- * for given function include the metrics for all functions that were
- * called from that function during the measurement period.
- *
- * If data collection has not been stopped yet this method will halt
- * collection to gather the profiling data.
- *
- * See getRawData() for a description of the metric that are returned for
- * each funcition call. The values for the wt, cpu, mu and pmu metrics are
- * arrays with these values:
- * - total: Cumulative value
- * - min: Minimum value
- * - mean: Mean (average) value
- * - max: Maximum value
- * - variance: Variance (spread) of the values
- *
- * @return array
- * @see getRawData()
- * @see getCompleteMetrics()
- */
- public function getInclusiveMetrics() {
- if ( $this->inclusive === null ) {
- // Make sure we have data to work with
- $this->stop();
-
- $main = $this->hieraData['main()'];
- $hasCpu = isset( $main['cpu'] );
- $hasMu = isset( $main['mu'] );
- $hasAlloc = isset( $main['alloc'] );
-
- $this->inclusive = [];
- foreach ( $this->hieraData as $key => $stats ) {
- list( $parent, $child ) = self::splitKey( $key );
- if ( !isset( $this->inclusive[$child] ) ) {
- $this->inclusive[$child] = [
- 'ct' => 0,
- 'wt' => new RunningStat(),
- ];
- if ( $hasCpu ) {
- $this->inclusive[$child]['cpu'] = new RunningStat();
- }
- if ( $hasMu ) {
- $this->inclusive[$child]['mu'] = new RunningStat();
- $this->inclusive[$child]['pmu'] = new RunningStat();
- }
- if ( $hasAlloc ) {
- $this->inclusive[$child]['alloc'] = new RunningStat();
- $this->inclusive[$child]['free'] = new RunningStat();
- }
- }
-
- $this->inclusive[$child]['ct'] += $stats['ct'];
- foreach ( $stats as $stat => $value ) {
- if ( $stat === 'ct' ) {
- continue;
- }
-
- if ( !isset( $this->inclusive[$child][$stat] ) ) {
- // Ignore unknown stats
- continue;
- }
-
- for ( $i = 0; $i < $stats['ct']; $i++ ) {
- $this->inclusive[$child][$stat]->addObservation(
- $value / $stats['ct']
- );
- }
- }
- }
-
- // Convert RunningStat instances to static arrays and add
- // percentage stats.
- foreach ( $this->inclusive as $func => $stats ) {
- foreach ( $stats as $name => $value ) {
- if ( $value instanceof RunningStat ) {
- $total = $value->m1 * $value->n;
- $percent = ( isset( $main[$name] ) && $main[$name] )
- ? 100 * $total / $main[$name]
- : 0;
- $this->inclusive[$func][$name] = [
- 'total' => $total,
- 'min' => $value->min,
- 'mean' => $value->m1,
- 'max' => $value->max,
- 'variance' => $value->m2,
- 'percent' => $percent,
- ];
- }
- }
- }
-
- uasort( $this->inclusive, self::makeSortFunction(
- $this->config['sort'], 'total'
- ) );
- }
- return $this->inclusive;
- }
-
- /**
- * Get the inclusive and exclusive metrics for each function call.
- *
- * If data collection has not been stopped yet this method will halt
- * collection to gather the profiling data.
- *
- * In addition to the normal data contained in the inclusive metrics, the
- * metrics have an additional 'exclusive' measurement which is the total
- * minus the totals of all child function calls.
- *
- * @return array
- * @see getRawData()
- * @see getInclusiveMetrics()
- */
- public function getCompleteMetrics() {
- if ( $this->complete === null ) {
- // Start with inclusive data
- $this->complete = $this->getInclusiveMetrics();
-
- foreach ( $this->complete as $func => $stats ) {
- foreach ( $stats as $stat => $value ) {
- if ( $stat === 'ct' ) {
- continue;
- }
- // Initialize exclusive data with inclusive totals
- $this->complete[$func][$stat]['exclusive'] = $value['total'];
- }
- // Add sapce for call tree information to be filled in later
- $this->complete[$func]['calls'] = [];
- $this->complete[$func]['subcalls'] = [];
- }
-
- foreach ( $this->hieraData as $key => $stats ) {
- list( $parent, $child ) = self::splitKey( $key );
- if ( $parent !== null ) {
- // Track call tree information
- $this->complete[$child]['calls'][$parent] = $stats;
- $this->complete[$parent]['subcalls'][$child] = $stats;
- }
-
- if ( isset( $this->complete[$parent] ) ) {
- // Deduct child inclusive data from exclusive data
- foreach ( $stats as $stat => $value ) {
- if ( $stat === 'ct' ) {
- continue;
- }
-
- if ( !isset( $this->complete[$parent][$stat] ) ) {
- // Ignore unknown stats
- continue;
- }
-
- $this->complete[$parent][$stat]['exclusive'] -= $value;
- }
- }
- }
-
- uasort( $this->complete, self::makeSortFunction(
- $this->config['sort'], 'exclusive'
- ) );
- }
- return $this->complete;
- }
-
- /**
- * Get a list of all callers of a given function.
- *
- * @param string $function Function name
- * @return array
- * @see getEdges()
- */
- public function getCallers( $function ) {
- $edges = $this->getCompleteMetrics();
- if ( isset( $edges[$function]['calls'] ) ) {
- return array_keys( $edges[$function]['calls'] );
- } else {
- return [];
- }
- }
-
- /**
- * Get a list of all callees from a given function.
- *
- * @param string $function Function name
- * @return array
- * @see getEdges()
- */
- public function getCallees( $function ) {
- $edges = $this->getCompleteMetrics();
- if ( isset( $edges[$function]['subcalls'] ) ) {
- return array_keys( $edges[$function]['subcalls'] );
- } else {
- return [];
- }
- }
-
- /**
- * Find the critical path for the given metric.
- *
- * @param string $metric Metric to find critical path for
- * @return array
- */
- public function getCriticalPath( $metric = 'wt' ) {
- $this->stop();
- $func = 'main()';
- $path = [
- $func => $this->hieraData[$func],
- ];
- while ( $func ) {
- $callees = $this->getCallees( $func );
- $maxCallee = null;
- $maxCall = null;
- foreach ( $callees as $callee ) {
- $call = "{$func}==>{$callee}";
- if ( $maxCall === null ||
- $this->hieraData[$call][$metric] >
- $this->hieraData[$maxCall][$metric]
- ) {
- $maxCallee = $callee;
- $maxCall = $call;
- }
- }
- if ( $maxCall !== null ) {
- $path[$maxCall] = $this->hieraData[$maxCall];
- }
- $func = $maxCallee;
- }
- return $path;
- }
-
- /**
- * Make a closure to use as a sort function. The resulting function will
- * sort by descending numeric values (largest value first).
- *
- * @param string $key Data key to sort on
- * @param string $sub Sub key to sort array values on
- * @return Closure
- */
- public static function makeSortFunction( $key, $sub ) {
- return function ( $a, $b ) use ( $key, $sub ) {
- if ( isset( $a[$key] ) && isset( $b[$key] ) ) {
- // Descending sort: larger values will be first in result.
- // Assumes all values are numeric.
- // Values for 'main()' will not have sub keys
- $valA = is_array( $a[$key] ) ? $a[$key][$sub] : $a[$key];
- $valB = is_array( $b[$key] ) ? $b[$key][$sub] : $b[$key];
- return $valB - $valA;
- } else {
- // Sort datum with the key before those without
- return isset( $a[$key] ) ? -1 : 1;
- }
- };
}
}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use RunningStat\RunningStat;
+
+/**
+ * Convenience class for working with XHProf profiling data
+ * <https://github.com/phacility/xhprof>. XHProf can be installed as a PECL
+ * package for use with PHP5 (Zend PHP) and is built-in to HHVM 3.3.0.
+ *
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
+ * @since 1.28
+ */
+class XhprofData {
+
+ /**
+ * @var array $config
+ */
+ protected $config;
+
+ /**
+ * Hierarchical profiling data returned by xhprof.
+ * @var array $hieraData
+ */
+ protected $hieraData;
+
+ /**
+ * Per-function inclusive data.
+ * @var array $inclusive
+ */
+ protected $inclusive;
+
+ /**
+ * Per-function inclusive and exclusive data.
+ * @var array $complete
+ */
+ protected $complete;
+
+ /**
+ * Configuration data can contain:
+ * - include: Array of function names to include in profiling.
+ * - sort: Key to sort per-function reports on.
+ *
+ * @param array $data Xhprof profiling data, as returned by xhprof_disable()
+ * @param array $config
+ */
+ public function __construct( array $data, array $config = [] ) {
+ $this->config = array_merge( [
+ 'include' => null,
+ 'sort' => 'wt',
+ ], $config );
+
+ $this->hieraData = $this->pruneData( $data );
+ }
+
+ /**
+ * Get raw data collected by xhprof.
+ *
+ * Each key in the returned array is an edge label for the call graph in
+ * the form "caller==>callee". There is once special case edge labled
+ * simply "main()" which represents the global scope entry point of the
+ * application.
+ *
+ * XHProf will collect different data depending on the flags that are used:
+ * - ct: Number of matching events seen.
+ * - wt: Inclusive elapsed wall time for this event in microseconds.
+ * - cpu: Inclusive elapsed cpu time for this event in microseconds.
+ * (XHPROF_FLAGS_CPU)
+ * - mu: Delta of memory usage from start to end of callee in bytes.
+ * (XHPROF_FLAGS_MEMORY)
+ * - pmu: Delta of peak memory usage from start to end of callee in
+ * bytes. (XHPROF_FLAGS_MEMORY)
+ * - alloc: Delta of amount memory requested from malloc() by the callee,
+ * in bytes. (XHPROF_FLAGS_MALLOC)
+ * - free: Delta of amount of memory passed to free() by the callee, in
+ * bytes. (XHPROF_FLAGS_MALLOC)
+ *
+ * @return array
+ * @see getInclusiveMetrics()
+ * @see getCompleteMetrics()
+ */
+ public function getRawData() {
+ return $this->hieraData;
+ }
+
+ /**
+ * Convert an xhprof data key into an array of ['parent', 'child']
+ * function names.
+ *
+ * The resulting array is left padded with nulls, so a key
+ * with no parent (eg 'main()') will return [null, 'function'].
+ *
+ * @return array
+ */
+ public static function splitKey( $key ) {
+ return array_pad( explode( '==>', $key, 2 ), -2, null );
+ }
+
+ /**
+ * Remove data for functions that are not included in the 'include'
+ * configuration array.
+ *
+ * @param array $data Raw xhprof data
+ * @return array
+ */
+ protected function pruneData( $data ) {
+ if ( !$this->config['include'] ) {
+ return $data;
+ }
+
+ $want = array_fill_keys( $this->config['include'], true );
+ $want['main()'] = true;
+
+ $keep = [];
+ foreach ( $data as $key => $stats ) {
+ list( $parent, $child ) = self::splitKey( $key );
+ if ( isset( $want[$parent] ) || isset( $want[$child] ) ) {
+ $keep[$key] = $stats;
+ }
+ }
+ return $keep;
+ }
+
+ /**
+ * Get the inclusive metrics for each function call. Inclusive metrics
+ * for given function include the metrics for all functions that were
+ * called from that function during the measurement period.
+ *
+ * See getRawData() for a description of the metric that are returned for
+ * each funcition call. The values for the wt, cpu, mu and pmu metrics are
+ * arrays with these values:
+ * - total: Cumulative value
+ * - min: Minimum value
+ * - mean: Mean (average) value
+ * - max: Maximum value
+ * - variance: Variance (spread) of the values
+ *
+ * @return array
+ * @see getRawData()
+ * @see getCompleteMetrics()
+ */
+ public function getInclusiveMetrics() {
+ if ( $this->inclusive === null ) {
+ $main = $this->hieraData['main()'];
+ $hasCpu = isset( $main['cpu'] );
+ $hasMu = isset( $main['mu'] );
+ $hasAlloc = isset( $main['alloc'] );
+
+ $this->inclusive = [];
+ foreach ( $this->hieraData as $key => $stats ) {
+ list( $parent, $child ) = self::splitKey( $key );
+ if ( !isset( $this->inclusive[$child] ) ) {
+ $this->inclusive[$child] = [
+ 'ct' => 0,
+ 'wt' => new RunningStat(),
+ ];
+ if ( $hasCpu ) {
+ $this->inclusive[$child]['cpu'] = new RunningStat();
+ }
+ if ( $hasMu ) {
+ $this->inclusive[$child]['mu'] = new RunningStat();
+ $this->inclusive[$child]['pmu'] = new RunningStat();
+ }
+ if ( $hasAlloc ) {
+ $this->inclusive[$child]['alloc'] = new RunningStat();
+ $this->inclusive[$child]['free'] = new RunningStat();
+ }
+ }
+
+ $this->inclusive[$child]['ct'] += $stats['ct'];
+ foreach ( $stats as $stat => $value ) {
+ if ( $stat === 'ct' ) {
+ continue;
+ }
+
+ if ( !isset( $this->inclusive[$child][$stat] ) ) {
+ // Ignore unknown stats
+ continue;
+ }
+
+ for ( $i = 0; $i < $stats['ct']; $i++ ) {
+ $this->inclusive[$child][$stat]->addObservation(
+ $value / $stats['ct']
+ );
+ }
+ }
+ }
+
+ // Convert RunningStat instances to static arrays and add
+ // percentage stats.
+ foreach ( $this->inclusive as $func => $stats ) {
+ foreach ( $stats as $name => $value ) {
+ if ( $value instanceof RunningStat ) {
+ $total = $value->m1 * $value->n;
+ $percent = ( isset( $main[$name] ) && $main[$name] )
+ ? 100 * $total / $main[$name]
+ : 0;
+ $this->inclusive[$func][$name] = [
+ 'total' => $total,
+ 'min' => $value->min,
+ 'mean' => $value->m1,
+ 'max' => $value->max,
+ 'variance' => $value->m2,
+ 'percent' => $percent,
+ ];
+ }
+ }
+ }
+
+ uasort( $this->inclusive, self::makeSortFunction(
+ $this->config['sort'], 'total'
+ ) );
+ }
+ return $this->inclusive;
+ }
+
+ /**
+ * Get the inclusive and exclusive metrics for each function call.
+ *
+ * In addition to the normal data contained in the inclusive metrics, the
+ * metrics have an additional 'exclusive' measurement which is the total
+ * minus the totals of all child function calls.
+ *
+ * @return array
+ * @see getRawData()
+ * @see getInclusiveMetrics()
+ */
+ public function getCompleteMetrics() {
+ if ( $this->complete === null ) {
+ // Start with inclusive data
+ $this->complete = $this->getInclusiveMetrics();
+
+ foreach ( $this->complete as $func => $stats ) {
+ foreach ( $stats as $stat => $value ) {
+ if ( $stat === 'ct' ) {
+ continue;
+ }
+ // Initialize exclusive data with inclusive totals
+ $this->complete[$func][$stat]['exclusive'] = $value['total'];
+ }
+ // Add sapce for call tree information to be filled in later
+ $this->complete[$func]['calls'] = [];
+ $this->complete[$func]['subcalls'] = [];
+ }
+
+ foreach ( $this->hieraData as $key => $stats ) {
+ list( $parent, $child ) = self::splitKey( $key );
+ if ( $parent !== null ) {
+ // Track call tree information
+ $this->complete[$child]['calls'][$parent] = $stats;
+ $this->complete[$parent]['subcalls'][$child] = $stats;
+ }
+
+ if ( isset( $this->complete[$parent] ) ) {
+ // Deduct child inclusive data from exclusive data
+ foreach ( $stats as $stat => $value ) {
+ if ( $stat === 'ct' ) {
+ continue;
+ }
+
+ if ( !isset( $this->complete[$parent][$stat] ) ) {
+ // Ignore unknown stats
+ continue;
+ }
+
+ $this->complete[$parent][$stat]['exclusive'] -= $value;
+ }
+ }
+ }
+
+ uasort( $this->complete, self::makeSortFunction(
+ $this->config['sort'], 'exclusive'
+ ) );
+ }
+ return $this->complete;
+ }
+
+ /**
+ * Get a list of all callers of a given function.
+ *
+ * @param string $function Function name
+ * @return array
+ * @see getEdges()
+ */
+ public function getCallers( $function ) {
+ $edges = $this->getCompleteMetrics();
+ if ( isset( $edges[$function]['calls'] ) ) {
+ return array_keys( $edges[$function]['calls'] );
+ } else {
+ return [];
+ }
+ }
+
+ /**
+ * Get a list of all callees from a given function.
+ *
+ * @param string $function Function name
+ * @return array
+ * @see getEdges()
+ */
+ public function getCallees( $function ) {
+ $edges = $this->getCompleteMetrics();
+ if ( isset( $edges[$function]['subcalls'] ) ) {
+ return array_keys( $edges[$function]['subcalls'] );
+ } else {
+ return [];
+ }
+ }
+
+ /**
+ * Find the critical path for the given metric.
+ *
+ * @param string $metric Metric to find critical path for
+ * @return array
+ */
+ public function getCriticalPath( $metric = 'wt' ) {
+ $func = 'main()';
+ $path = [
+ $func => $this->hieraData[$func],
+ ];
+ while ( $func ) {
+ $callees = $this->getCallees( $func );
+ $maxCallee = null;
+ $maxCall = null;
+ foreach ( $callees as $callee ) {
+ $call = "{$func}==>{$callee}";
+ if ( $maxCall === null ||
+ $this->hieraData[$call][$metric] >
+ $this->hieraData[$maxCall][$metric]
+ ) {
+ $maxCallee = $callee;
+ $maxCall = $call;
+ }
+ }
+ if ( $maxCall !== null ) {
+ $path[$maxCall] = $this->hieraData[$maxCall];
+ }
+ $func = $maxCallee;
+ }
+ return $path;
+ }
+
+ /**
+ * Make a closure to use as a sort function. The resulting function will
+ * sort by descending numeric values (largest value first).
+ *
+ * @param string $key Data key to sort on
+ * @param string $sub Sub key to sort array values on
+ * @return Closure
+ */
+ public static function makeSortFunction( $key, $sub ) {
+ return function ( $a, $b ) use ( $key, $sub ) {
+ if ( isset( $a[$key] ) && isset( $b[$key] ) ) {
+ // Descending sort: larger values will be first in result.
+ // Assumes all values are numeric.
+ // Values for 'main()' will not have sub keys
+ $valA = is_array( $a[$key] ) ? $a[$key][$sub] : $a[$key];
+ $valB = is_array( $b[$key] ) ? $b[$key][$sub] : $b[$key];
+ return $valB - $valA;
+ } else {
+ // Sort datum with the key before those without
+ return isset( $a[$key] ) ? -1 : 1;
+ }
+ };
+ }
+}
abstract public function delete( $key );
/**
- * Merge changes into the existing cache value (possibly creating a new one).
+ * Merge changes into the existing cache value (possibly creating a new one)
+ *
* The callback function returns the new value given the current value
* (which will be false if not present), and takes the arguments:
- * (this BagOStuff, cache key, current value).
+ * (this BagOStuff, cache key, current value, TTL).
+ * The TTL parameter is reference set to $exptime. It can be overriden in the callback.
*
* @param string $key
* @param callable $callback Callback method to be executed
protected function mergeViaCas( $key, $callback, $exptime = 0, $attempts = 10 ) {
do {
$this->clearLastError();
+ $reportDupes = $this->reportDupes;
+ $this->reportDupes = false;
$casToken = null; // passed by reference
$currentValue = $this->getWithToken( $key, $casToken, self::READ_LATEST );
+ $this->reportDupes = $reportDupes;
+
if ( $this->getLastError() ) {
return false; // don't spam retries (retry only on races)
}
// Derive the new value from the old value
- $value = call_user_func( $callback, $this, $key, $currentValue );
+ $value = call_user_func( $callback, $this, $key, $currentValue, $exptime );
$this->clearLastError();
if ( $value === false ) {
}
$this->clearLastError();
+ $reportDupes = $this->reportDupes;
+ $this->reportDupes = false;
$currentValue = $this->get( $key, self::READ_LATEST );
+ $this->reportDupes = $reportDupes;
+
if ( $this->getLastError() ) {
$success = false;
} else {
// Derive the new value from the old value
- $value = call_user_func( $callback, $this, $key, $currentValue );
+ $value = call_user_func( $callback, $this, $key, $currentValue, $exptime );
if ( $value === false ) {
$success = true; // do nothing
} else {
* to avoid collisions with keys that are not wrapped as metadata arrays. The
* prefixes are as follows:
* - a) "WANCache:v" : used for regular value keys
- * - b) "WANCache:s" : used for temporarily storing values of tombstoned keys
+ * - b) "WANCache:i" : used for temporarily storing values of tombstoned keys
* - c) "WANCache:t" : used for storing timestamp "check" keys
*
* @ingroup Cache
/** Cache format version number */
const VERSION = 1;
- const FLD_VERSION = 0;
- const FLD_VALUE = 1;
- const FLD_TTL = 2;
- const FLD_TIME = 3;
- const FLD_FLAGS = 4;
- const FLD_HOLDOFF = 5;
+ const FLD_VERSION = 0; // key to cache version number
+ const FLD_VALUE = 1; // key to the cached value
+ const FLD_TTL = 2; // key to the original TTL
+ const FLD_TIME = 3; // key to the cache time
+ const FLD_FLAGS = 4; // key to the flags bitfield
+ const FLD_HOLDOFF = 5; // key to any hold-off TTL
/** @var integer Treat this value as expired-on-arrival */
const FLG_STALE = 1;
const ERR_RELAY = 4; // relay broadcast failed
const VALUE_KEY_PREFIX = 'WANCache:v:';
- const STASH_KEY_PREFIX = 'WANCache:s:';
+ const INTERIM_KEY_PREFIX = 'WANCache:i:';
const TIME_KEY_PREFIX = 'WANCache:t:';
const PURGE_VAL_PREFIX = 'PURGED:';
+ const VFLD_DATA = 'WOC:d'; // key to the value of versioned data
+ const VFLD_VERSION = 'WOC:v'; // key to the version of the value present
+
const MAX_PC_KEYS = 1000; // max keys to keep in process cache
const DEFAULT_PURGE_CHANNEL = 'wancache-purge';
* That method has cache slam avoiding features for hot/expensive keys.
*
* @param string $key Cache key
- * @param mixed $curTTL Approximate TTL left on the key if present [returned]
+ * @param mixed $curTTL Approximate TTL left on the key if present/tombstoned [returned]
* @param array $checkKeys List of "check" keys
+ * @param float &$asOf UNIX timestamp of cached value; null on failure [returned]
* @return mixed Value of cache key or false on failure
*/
- final public function get( $key, &$curTTL = null, array $checkKeys = [] ) {
+ final public function get( $key, &$curTTL = null, array $checkKeys = [], &$asOf = null ) {
$curTTLs = [];
- $values = $this->getMulti( [ $key ], $curTTLs, $checkKeys );
+ $asOfs = [];
+ $values = $this->getMulti( [ $key ], $curTTLs, $checkKeys, $asOfs );
$curTTL = isset( $curTTLs[$key] ) ? $curTTLs[$key] : null;
+ $asOf = isset( $asOfs[$key] ) ? $asOfs[$key] : null;
return isset( $values[$key] ) ? $values[$key] : false;
}
* @param array $curTTLs Map of (key => approximate TTL left) for existing keys [returned]
* @param array $checkKeys List of check keys to apply to all $keys. May also apply "check"
* keys to specific cache keys only by using cache keys as keys in the $checkKeys array.
+ * @param float[] &$asOfs Map of (key => UNIX timestamp of cached value; null on failure)
* @return array Map of (key => value) for keys that exist
*/
final public function getMulti(
- array $keys, &$curTTLs = [], array $checkKeys = []
+ array $keys, &$curTTLs = [], array $checkKeys = [], array &$asOfs = []
) {
$result = [];
$curTTLs = [];
+ $asOfs = [];
$vPrefixLen = strlen( self::VALUE_KEY_PREFIX );
$valueKeys = self::prefixCacheKeys( $keys, self::VALUE_KEY_PREFIX );
}
}
$curTTLs[$key] = $curTTL;
+ $asOfs[$key] = ( $value !== false ) ? $wrappedValues[$vKey][self::FLD_TIME] : null;
}
return $result;
* @return bool Success
*/
final public function set( $key, $value, $ttl = 0, array $opts = [] ) {
+ $now = microtime( true );
$lockTSE = isset( $opts['lockTSE'] ) ? $opts['lockTSE'] : self::TSE_NONE;
- $age = isset( $opts['since'] ) ? max( 0, microtime( true ) - $opts['since'] ) : 0;
+ $age = isset( $opts['since'] ) ? max( 0, $now - $opts['since'] ) : 0;
$lag = isset( $opts['lag'] ) ? $opts['lag'] : 0;
// Do not cache potentially uncommitted data as it might get rolled back
}
// Wrap that value with time/TTL/version metadata
- $wrapped = $this->wrap( $value, $ttl ) + $wrapExtra;
+ $wrapped = $this->wrap( $value, $ttl, $now ) + $wrapExtra;
$func = function ( $cache, $key, $cWrapped ) use ( $wrapped ) {
return ( is_string( $cWrapped ) )
* higher this is set, the higher the worst-case staleness can be.
* Use WANObjectCache::TSE_NONE to disable this logic.
* Default: WANObjectCache::TSE_NONE.
- * - pcTTL : process cache the value in this PHP instance with this TTL. This avoids
+ * - pcTTL: Process cache the value in this PHP instance with this TTL. This avoids
* network I/O when a key is read several times. This will not cache if the callback
* returns false however. Note that any purges will not be seen while process cached;
* since the callback should use slave DBs and they may be lagged or have snapshot
* isolation anyway, this should not typically matter.
* Default: WANObjectCache::TTL_UNCACHEABLE.
- * @return mixed Value to use for the key
+ * - version: Integer version number. This allows for callers to make breaking changes to
+ * how values are stored while maintaining compatability and correct cache purges. New
+ * versions are stored alongside older versions concurrently. Avoid storing class objects
+ * however, as this reduces compatibility (due to serialization).
+ * Default: null.
+ * @return mixed Value found or written to the key
*/
final public function getWithSetCallback( $key, $ttl, $callback, array $opts = [] ) {
$pcTTL = isset( $opts['pcTTL'] ) ? $opts['pcTTL'] : self::TTL_UNCACHEABLE;
$value = ( $pcTTL >= 0 ) ? $this->procCache->get( $key ) : false;
if ( $value === false ) {
+ unset( $opts['minTime'] ); // not a public feature
+
// Fetch the value over the network
- $value = $this->doGetWithSetCallback( $key, $ttl, $callback, $opts );
+ if ( isset( $opts['version'] ) ) {
+ $version = $opts['version'];
+ $asOf = null;
+ $cur = $this->doGetWithSetCallback(
+ $key,
+ $ttl,
+ function ( $oldValue, &$ttl, &$setOpts ) use ( $callback, $version ) {
+ $oldData = $oldValue ? $oldValue[self::VFLD_DATA] : false;
+ return [
+ self::VFLD_DATA => $callback( $oldData, $ttl, $setOpts ),
+ self::VFLD_VERSION => $version
+ ];
+ },
+ $opts,
+ $asOf
+ );
+ if ( $cur[self::VFLD_VERSION] === $version ) {
+ // Value created or existed before with version; use it
+ $value = $cur[self::VFLD_DATA];
+ } else {
+ // Value existed before with a different version; use variant key.
+ // Reflect purges to $key by requiring that this key value be newer.
+ $value = $this->doGetWithSetCallback(
+ 'cache-variant:' . md5( $key ) . ":$version",
+ $ttl,
+ $callback,
+ // Regenerate value if not newer than $key
+ [ 'version' => null, 'minTime' => $asOf ] + $opts
+ );
+ }
+ } else {
+ $value = $this->doGetWithSetCallback( $key, $ttl, $callback, $opts );
+ }
+
// Update the process cache if enabled
if ( $pcTTL >= 0 && $value !== false ) {
$this->procCache->set( $key, $value, $pcTTL );
* @param string $key
* @param integer $ttl
* @param callback $callback
- * @param array $opts
+ * @param array $opts Options map for getWithSetCallback() which also includes:
+ * - minTime: Treat values older than this UNIX timestamp as not existing. Default: null.
+ * @param float &$asOf Cache generation timestamp of returned value [returned]
* @return mixed
*/
- protected function doGetWithSetCallback( $key, $ttl, $callback, array $opts ) {
+ protected function doGetWithSetCallback( $key, $ttl, $callback, array $opts, &$asOf = null ) {
$lowTTL = isset( $opts['lowTTL'] ) ? $opts['lowTTL'] : min( self::LOW_TTL, $ttl );
$lockTSE = isset( $opts['lockTSE'] ) ? $opts['lockTSE'] : self::TSE_NONE;
$checkKeys = isset( $opts['checkKeys'] ) ? $opts['checkKeys'] : [];
+ $minTime = isset( $opts['minTime'] ) ? $opts['minTime'] : 0.0;
+ $versioned = isset( $opts['version'] );
// Get the current key value
$curTTL = null;
- $cValue = $this->get( $key, $curTTL, $checkKeys ); // current value
+ $cValue = $this->get( $key, $curTTL, $checkKeys, $asOf ); // current value
$value = $cValue; // return value
// Determine if a regeneration is desired
- if ( $value !== false && $curTTL > 0 && !$this->worthRefresh( $curTTL, $lowTTL ) ) {
+ if ( $value !== false
+ && $curTTL > 0
+ && $this->isValid( $value, $versioned, $asOf, $minTime )
+ && !$this->worthRefresh( $curTTL, $lowTTL )
+ ) {
return $value;
}
if ( $this->cache->lock( $key, 0, self::LOCK_TTL ) ) {
// Lock acquired; this thread should update the key
$lockAcquired = true;
- } elseif ( $value !== false ) {
+ } elseif ( $value !== false && $this->isValid( $value, $versioned, $asOf, $minTime ) ) {
// If it cannot be acquired; then the stale value can be used
return $value;
} else {
- // Use the stash value for tombstoned keys to reduce regeneration load.
+ // Use the INTERIM value for tombstoned keys to reduce regeneration load.
// For hot keys, either another thread has the lock or the lock failed;
- // use the stash value from the last thread that regenerated it.
- $value = $this->cache->get( self::STASH_KEY_PREFIX . $key );
- if ( $value !== false ) {
+ // use the INTERIM value from the last thread that regenerated it.
+ $wrapped = $this->cache->get( self::INTERIM_KEY_PREFIX . $key );
+ $value = $this->unwrap( $wrapped, microtime( true ) );
+ if ( $value !== false && $this->isValid( $value, $versioned, $asOf, $minTime ) ) {
+ $asOf = $wrapped[self::FLD_TIME];
+
return $value;
}
}
// Generate the new value from the callback...
$setOpts = [];
$value = call_user_func_array( $callback, [ $cValue, &$ttl, &$setOpts ] );
+ $asOf = microtime( true );
// When delete() is called, writes are write-holed by the tombstone,
- // so use a special stash key to pass the new value around threads.
+ // so use a special INTERIM key to pass the new value around threads.
if ( $useMutex && $value !== false && $ttl >= 0 ) {
$tempTTL = max( 1, (int)$lockTSE ); // set() expects seconds
- $this->cache->set( self::STASH_KEY_PREFIX . $key, $value, $tempTTL );
+ $wrapped = $this->wrap( $value, $tempTTL, $asOf );
+ $this->cache->set( self::INTERIM_KEY_PREFIX . $key, $wrapped, $tempTTL );
}
if ( $lockAcquired ) {
return mt_rand( 1, 1e9 ) <= 1e9 * $chance;
}
+ /**
+ * Check whether $value is appropriately versioned and not older than $minTime (if set)
+ *
+ * @param array $value
+ * @param bool $versioned
+ * @param float $asOf The time $value was generated
+ * @param float $minTime The last time the main value was generated (0.0 if unknown)
+ * @return bool
+ */
+ protected function isValid( $value, $versioned, $asOf, $minTime ) {
+ if ( $versioned && !isset( $value[self::VFLD_VERSION] ) ) {
+ return false;
+ } elseif ( $minTime > 0 && $asOf < $minTime ) {
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Do not use this method outside WANObjectCache
*
* @param mixed $value
* @param integer $ttl [0=forever]
+ * @param float $now Unix Current timestamp just before calling set()
* @return array
*/
- protected function wrap( $value, $ttl ) {
+ protected function wrap( $value, $ttl, $now ) {
return [
self::FLD_VERSION => self::VERSION,
self::FLD_VALUE => $value,
self::FLD_TTL => $ttl,
- self::FLD_TIME => microtime( true )
+ self::FLD_TIME => $now
];
}
* Do not use this method outside WANObjectCache
*
* @param array|string|bool $wrapped
- * @param float $now Unix Current timestamp (preferrable pre-query)
+ * @param float $now Unix Current timestamp (preferrably pre-query)
* @return array (mixed; false if absent/invalid, current time left)
*/
protected function unwrap( $wrapped, $now ) {
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @license GPL-2.0+
+ * @author Kunal Mehta <legoktm@member.fsf.org>
+ */
+namespace MediaWiki\Linker;
+
+use DummyLinker;
+use Hooks;
+use Html;
+use HtmlArmor;
+use Linker;
+use MediaWiki\MediaWikiServices;
+use Sanitizer;
+use Title;
+use TitleFormatter;
+
+/**
+ * Class that generates HTML <a> links for pages.
+ *
+ * @since 1.28
+ */
+class LinkRenderer {
+
+ /**
+ * Whether to force the pretty article path
+ *
+ * @var bool
+ */
+ private $forceArticlePath = false;
+
+ /**
+ * A PROTO_* constant or false
+ *
+ * @var string|bool|int
+ */
+ private $expandUrls = false;
+
+ /**
+ * @var int
+ */
+ private $stubThreshold = 0;
+
+ /**
+ * @var TitleFormatter
+ */
+ private $titleFormatter;
+
+ /**
+ * Whether to run the legacy Linker hooks
+ *
+ * @var bool
+ */
+ private $runLegacyBeginHook = true;
+
+ /**
+ * @param TitleFormatter $titleFormatter
+ */
+ public function __construct( TitleFormatter $titleFormatter ) {
+ $this->titleFormatter = $titleFormatter;
+ }
+
+ /**
+ * @param bool $force
+ */
+ public function setForceArticlePath( $force ) {
+ $this->forceArticlePath = $force;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getForceArticlePath() {
+ return $this->forceArticlePath;
+ }
+
+ /**
+ * @param string|bool|int $expand A PROTO_* constant or false
+ */
+ public function setExpandURLs( $expand ) {
+ $this->expandUrls = $expand;
+ }
+
+ /**
+ * @return string|bool|int a PROTO_* constant or false
+ */
+ public function getExpandURLs() {
+ return $this->expandUrls;
+ }
+
+ /**
+ * @param int $threshold
+ */
+ public function setStubThreshold( $threshold ) {
+ $this->stubThreshold = $threshold;
+ }
+
+ /**
+ * @return int
+ */
+ public function getStubThreshold() {
+ return $this->stubThreshold;
+ }
+
+ /**
+ * @param bool $run
+ */
+ public function setRunLegacyBeginHook( $run ) {
+ $this->runLegacyBeginHook = $run;
+ }
+
+ /**
+ * @param LinkTarget $target
+ * @param string|HtmlArmor|null $text
+ * @param array $extraAttribs
+ * @param array $query
+ * @return string
+ */
+ public function makeLink(
+ LinkTarget $target, $text = null, array $extraAttribs = [], array $query = []
+ ) {
+ $title = Title::newFromLinkTarget( $target );
+ if ( $title->isKnown() ) {
+ return $this->makeKnownLink( $target, $text, $extraAttribs, $query );
+ } else {
+ return $this->makeBrokenLink( $target, $text, $extraAttribs, $query );
+ }
+ }
+
+ /**
+ * Get the options in the legacy format
+ *
+ * @param bool $isKnown Whether the link is known or broken
+ * @return array
+ */
+ private function getLegacyOptions( $isKnown ) {
+ $options = [ 'stubThreshold' => $this->stubThreshold ];
+ if ( $this->forceArticlePath ) {
+ $options[] = 'forcearticlepath';
+ }
+ if ( $this->expandUrls === PROTO_HTTP ) {
+ $options[] = 'http';
+ } elseif ( $this->expandUrls === PROTO_HTTPS ) {
+ $options[] = 'https';
+ }
+
+ $options[] = $isKnown ? 'known' : 'broken';
+
+ return $options;
+ }
+
+ private function runBeginHook( LinkTarget $target, &$text, &$extraAttribs, &$query, $isKnown ) {
+ $ret = null;
+ if ( !Hooks::run( 'HtmlPageLinkRendererBegin',
+ [ $this, $target, &$text, &$extraAttribs, &$query, &$ret ] )
+ ) {
+ return $ret;
+ }
+
+ // Now run the legacy hook
+ return $this->runLegacyBeginHook( $target, $text, $extraAttribs, $query, $isKnown );
+ }
+
+ private function runLegacyBeginHook( LinkTarget $target, &$text, &$extraAttribs, &$query,
+ $isKnown
+ ) {
+ if ( !$this->runLegacyBeginHook || !Hooks::isRegistered( 'LinkBegin' ) ) {
+ // Disabled, or nothing registered
+ return null;
+ }
+
+ $realOptions = $options = $this->getLegacyOptions( $isKnown );
+ $ret = null;
+ $dummy = new DummyLinker();
+ $title = Title::newFromLinkTarget( $target );
+ if ( $text !== null ) {
+ $realHtml = $html = HtmlArmor::getHtml( $text );
+ } else {
+ $realHtml = $html = null;
+ }
+ if ( !Hooks::run( 'LinkBegin',
+ [ $dummy, $title, &$html, &$extraAttribs, &$query, &$options, &$ret ] )
+ ) {
+ return $ret;
+ }
+
+ if ( $html !== null && $html !== $realHtml ) {
+ // &$html was modified, so re-armor it as $text
+ $text = new HtmlArmor( $html );
+ }
+
+ // Check if they changed any of the options, hopefully not!
+ if ( $options !== $realOptions ) {
+ $factory = MediaWikiServices::getInstance()->getLinkRendererFactory();
+ // They did, so create a separate instance and have that take over the rest
+ $newRenderer = $factory->createFromLegacyOptions( $options );
+ // Don't recurse the hook...
+ $newRenderer->setRunLegacyBeginHook( false );
+ if ( in_array( 'known', $options, true ) ) {
+ return $newRenderer->makeKnownLink( $title, $text, $extraAttribs, $query );
+ } elseif ( in_array( 'broken', $options, true ) ) {
+ return $newRenderer->makeBrokenLink( $title, $text, $extraAttribs, $query );
+ } else {
+ return $newRenderer->makeLink( $title, $text, $extraAttribs, $query );
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * If you have already looked up the proper CSS classes using Linker::getLinkColour()
+ * or some other method, use this to avoid looking it up again.
+ *
+ * @param LinkTarget $target
+ * @param string|HtmlArmor|null $text
+ * @param string $classes CSS classes to add
+ * @param array $extraAttribs
+ * @param array $query
+ * @return string
+ */
+ public function makePreloadedLink(
+ LinkTarget $target, $text = null, $classes, array $extraAttribs = [], array $query = []
+ ) {
+ // Run begin hook
+ $ret = $this->runBeginHook( $target, $text, $extraAttribs, $query, true );
+ if ( $ret !== null ) {
+ return $ret;
+ }
+ $target = $this->normalizeTarget( $target );
+ $url = $this->getLinkURL( $target, $query );
+ $attribs = [ 'class' => $classes ];
+ $prefixedText = $this->titleFormatter->getPrefixedText( $target );
+ if ( $prefixedText !== '' ) {
+ $attribs['title'] = $prefixedText;
+ }
+
+ $attribs = [
+ 'href' => $url,
+ ] + $this->mergeAttribs( $attribs, $extraAttribs );
+
+ if ( $text === null ) {
+ $text = $this->getLinkText( $target );
+ }
+
+ return $this->buildAElement( $target, $text, $attribs, true );
+ }
+
+ /**
+ * @param LinkTarget $target
+ * @param string|HtmlArmor|null $text
+ * @param array $extraAttribs
+ * @param array $query
+ * @return string
+ */
+ public function makeKnownLink(
+ LinkTarget $target, $text = null, array $extraAttribs = [], array $query = []
+ ) {
+ $classes = [];
+ if ( $target->isExternal() ) {
+ $classes[] = 'extiw';
+ }
+ $colour = Linker::getLinkColour( $target, $this->stubThreshold );
+ if ( $colour !== '' ) {
+ $classes[] = $colour;
+ }
+
+ return $this->makePreloadedLink(
+ $target,
+ $text,
+ $classes ? implode( ' ', $classes ) : '',
+ $extraAttribs,
+ $query
+ );
+ }
+
+ /**
+ * @param LinkTarget $target
+ * @param string|HtmlArmor|null $text
+ * @param array $extraAttribs
+ * @param array $query
+ * @return string
+ */
+ public function makeBrokenLink(
+ LinkTarget $target, $text = null, array $extraAttribs = [], array $query = []
+ ) {
+ // Run legacy hook
+ $ret = $this->runBeginHook( $target, $text, $extraAttribs, $query, false );
+ if ( $ret !== null ) {
+ return $ret;
+ }
+
+ # We don't want to include fragments for broken links, because they
+ # generally make no sense.
+ if ( $target->hasFragment() ) {
+ $target = $target->createFragmentTarget( '' );
+ }
+ $target = $this->normalizeTarget( $target );
+
+ if ( !isset( $query['action'] ) && $target->getNamespace() !== NS_SPECIAL ) {
+ $query['action'] = 'edit';
+ $query['redlink'] = '1';
+ }
+
+ $url = $this->getLinkURL( $target, $query );
+ $attribs = [ 'class' => 'new' ];
+ $prefixedText = $this->titleFormatter->getPrefixedText( $target );
+ if ( $prefixedText !== '' ) {
+ // This ends up in parser cache!
+ $attribs['title'] = wfMessage( 'red-link-title', $prefixedText )
+ ->inContentLanguage()
+ ->text();
+ }
+
+ $attribs = [
+ 'href' => $url,
+ ] + $this->mergeAttribs( $attribs, $extraAttribs );
+
+ if ( $text === null ) {
+ $text = $this->getLinkText( $target );
+ }
+
+ return $this->buildAElement( $target, $text, $attribs, false );
+ }
+
+ /**
+ * Builds the final <a> element
+ *
+ * @param LinkTarget $target
+ * @param string|HtmlArmor $text
+ * @param array $attribs
+ * @param bool $isKnown
+ * @return null|string
+ */
+ private function buildAElement( LinkTarget $target, $text, array $attribs, $isKnown ) {
+ $ret = null;
+ if ( !Hooks::run( 'HtmlPageLinkRendererEnd',
+ [ $this, $target, $isKnown, &$text, &$attribs, &$ret ] )
+ ) {
+ return $ret;
+ }
+
+ $html = HtmlArmor::getHtml( $text );
+
+ // Run legacy hook
+ if ( Hooks::isRegistered( 'LinkEnd' ) ) {
+ $dummy = new DummyLinker();
+ $title = Title::newFromLinkTarget( $target );
+ $options = $this->getLegacyOptions( $isKnown );
+ if ( !Hooks::run( 'LinkEnd',
+ [ $dummy, $title, $options, &$html, &$attribs, &$ret ] )
+ ) {
+ return $ret;
+ }
+ }
+
+ return Html::rawElement( 'a', $attribs, $html );
+ }
+
+ /**
+ * @param LinkTarget $target
+ * @return string non-escaped text
+ */
+ private function getLinkText( LinkTarget $target ) {
+ $prefixedText = $this->titleFormatter->getPrefixedText( $target );
+ // If the target is just a fragment, with no title, we return the fragment
+ // text. Otherwise, we return the title text itself.
+ if ( $prefixedText === '' && $target->hasFragment() ) {
+ return $target->getFragment();
+ }
+
+ return $prefixedText;
+ }
+
+ private function getLinkURL( LinkTarget $target, array $query = [] ) {
+ // TODO: Use a LinkTargetResolver service instead of Title
+ $title = Title::newFromLinkTarget( $target );
+ $proto = $this->expandUrls !== false
+ ? $this->expandUrls
+ : PROTO_RELATIVE;
+ if ( $this->forceArticlePath ) {
+ $realQuery = $query;
+ $query = [];
+ } else {
+ $realQuery = [];
+ }
+ $url = $title->getLinkURL( $query, false, $proto );
+
+ if ( $this->forceArticlePath && $realQuery ) {
+ $url = wfAppendQuery( $url, $realQuery );
+ }
+
+ return $url;
+ }
+
+ /**
+ * Normalizes the provided target
+ *
+ * @todo move the code from Linker actually here
+ * @param LinkTarget $target
+ * @return LinkTarget
+ */
+ private function normalizeTarget( LinkTarget $target ) {
+ return Linker::normaliseSpecialPage( $target );
+ }
+
+ /**
+ * Merges two sets of attributes
+ *
+ * @param array $defaults
+ * @param array $attribs
+ *
+ * @return array
+ */
+ private function mergeAttribs( $defaults, $attribs ) {
+ if ( !$attribs ) {
+ return $defaults;
+ }
+ # Merge the custom attribs with the default ones, and iterate
+ # over that, deleting all "false" attributes.
+ $ret = [];
+ $merged = Sanitizer::mergeAttributes( $defaults, $attribs );
+ foreach ( $merged as $key => $val ) {
+ # A false value suppresses the attribute
+ if ( $val !== false ) {
+ $ret[$key] = $val;
+ }
+ }
+ return $ret;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @license GPL-2.0+
+ * @author Kunal Mehta <legoktm@member.fsf.org>
+ */
+namespace MediaWiki\Linker;
+
+use TitleFormatter;
+use User;
+
+/**
+ * Factory to create LinkRender objects
+ * @since 1.28
+ */
+class LinkRendererFactory {
+
+ /**
+ * @var TitleFormatter
+ */
+ private $titleFormatter;
+
+ /**
+ * @param TitleFormatter $titleFormatter
+ */
+ public function __construct( TitleFormatter $titleFormatter ) {
+ $this->titleFormatter = $titleFormatter;
+ }
+
+ /**
+ * @return LinkRenderer
+ */
+ public function create() {
+ return new LinkRenderer( $this->titleFormatter );
+ }
+
+ /**
+ * @param User $user
+ * @return LinkRenderer
+ */
+ public function createForUser( User $user ) {
+ $linkRenderer = $this->create();
+ $linkRenderer->setStubThreshold( $user->getStubThreshold() );
+
+ return $linkRenderer;
+ }
+
+ /**
+ * @param array $options
+ * @return LinkRenderer
+ */
+ public function createFromLegacyOptions( array $options ) {
+ $linkRenderer = $this->create();
+
+ if ( in_array( 'forcearticlepath', $options, true ) ) {
+ $linkRenderer->setForceArticlePath( true );
+ }
+
+ if ( in_array( 'http', $options, true ) ) {
+ $linkRenderer->setExpandURLs( PROTO_HTTP );
+ } elseif ( in_array( 'https', $options, true ) ) {
+ $linkRenderer->setExpandURLs( PROTO_HTTPS );
+ }
+
+ if ( isset( $options['stubThreshold'] ) ) {
+ $linkRenderer->setStubThreshold(
+ $options['stubThreshold']
+ );
+ }
+
+ return $linkRenderer;
+ }
+}
/**
* Get the namespace index.
+ * @since 1.27
*
* @return int Namespace index
*/
public function getNamespace();
+ /**
+ * Convenience function to test if it is in the namespace
+ * @since 1.27
+ *
+ * @param int $ns
+ * @return bool
+ */
+ public function inNamespace( $ns );
+
/**
* Get the link fragment (i.e. the bit after the #) in text form.
+ * @since 1.27
*
* @return string link fragment
*/
/**
* Whether the link target has a fragment
+ * @since 1.27
*
* @return bool
*/
/**
* Get the main part with underscores.
+ * @since 1.27
*
* @return string Main part of the link, with underscores (for use in href attributes)
*/
/**
* Returns the link in text form, without namespace prefix or fragment.
- *
* This is computed from the DB key by replacing any underscores with spaces.
+ * @since 1.27
*
* @return string
*/
* Creates a new LinkTarget for a different fragment of the same page.
* It is expected that the same type of object will be returned, but the
* only requirement is that it is a LinkTarget.
+ * @since 1.27
*
* @param string $fragment The fragment name, or "" for the entire page.
*
/**
* Whether this LinkTarget has an interwiki component
+ * @since 1.27
*
* @return bool
*/
/**
* The interwiki component of this LinkTarget
+ * @since 1.27
*
* @return string
*/
// 'filearchive' for file versions, or a comma-separated list of log_ids for log
// entries. $subtype here is 'revision' for page revisions and file
// versions, or 'event' for log entries.
- if ( ( $subtype === 'event' && count( $params ) === 6 )
- || ( $subtype === 'revision' && isset( $params[3] )
- && ( $params[3] === 'revision' || $params[3] === 'oldimage'
- || $params[3] === 'archive' || $params[3] === 'filearchive' )
+ if (
+ ( $subtype === 'event' && count( $params ) === 6 )
+ || (
+ $subtype === 'revision' && isset( $params[3] )
+ && in_array( $params[3], [ 'revision', 'archive', 'oldimage', 'filearchive' ] )
)
) {
+ // See RevDelList::getLogParams()/RevDelLogList::getLogParams()
$paramStart = $subtype === 'revision' ? 4 : 3;
$old = $this->parseBitField( $params[$paramStart + 1] );
foreach ( $hid as $v ) {
$changes[] = $this->msg( "$v-hid" )->plain();
}
- // messages used: revdelete-content-unhid, revdelete-summary-unhid, revdelete-uname-unhid
+ // messages used: revdelete-content-unhid, revdelete-summary-unhid,
+ // revdelete-uname-unhid
foreach ( $unhid as $v ) {
$changes[] = $this->msg( "$v-unhid" )->plain();
}
* - flags Integer display flags (NO_ACTION_LINK,NO_EXTRA_USER_LINKS)
* - useRequestParams boolean Set true to use Pager-related parameters in the WebRequest
* - useMaster boolean Use master DB
+ * - extraUrlParams array|bool Additional url parameters for "full log" link (if it is shown)
* @return int Number of total log items (not limited by $lim)
*/
public static function showLogExtract(
'flags' => 0,
'useRequestParams' => false,
'useMaster' => false,
+ 'extraUrlParams' => false,
];
# The + operator appends elements of remaining keys from the right
# handed array to the left handed, whereas duplicated keys are NOT overwritten.
$msgKey = $param['msgKey'];
$wrap = $param['wrap'];
$flags = $param['flags'];
+ $extraUrlParams = $param['extraUrlParams'];
+
$useRequestParams = $param['useRequestParams'];
if ( !is_array( $msgKey ) ) {
$msgKey = [ $msgKey ];
$urlParam['type'] = $types[0];
}
- $s .= Linker::link(
+ if ( $extraUrlParams !== false ) {
+ $urlParam = array_merge( $urlParam, $extraUrlParams );
+ }
+
+ $s .= Linker::linkKnown(
SpecialPage::getTitleFor( 'Log' ),
$context->msg( 'log-fulllog' )->escaped(),
[],
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
+use MediaWiki\Services\ServiceDisabledException;
/**
* Functions to get cache objects
return self::getInstance( $candidate );
}
}
- return self::getInstance( CACHE_DB );
+
+ try {
+ // Make sure we actually have a DB backend before falling back to CACHE_DB
+ MediaWikiServices::getInstance()->getDBLoadBalancer();
+ $candidate = CACHE_DB;
+ } catch ( ServiceDisabledException $e ) {
+ // The LoadBalancer is disabled, probably because
+ // MediaWikiServices::disableStorageBackend was called.
+ $candidate = CACHE_NONE;
+ }
+
+ return self::getInstance( $candidate );
}
/**
* @return mixed
*/
protected function unserialize( $data ) {
- return ctype_digit( $data ) ? intval( $data ) : unserialize( $data );
+ $int = intval( $data );
+ return $data === (string)$int ? $int : unserialize( $data );
}
/**
);
$outputPage->addHTML(
- "<div class='patrollink'>" .
+ "<div class='patrollink' data-mw='interface'>" .
wfMessage( 'markaspatrolledlink' )->rawParams( $link )->escaped() .
'</div>'
);
/**
* Call to WikiPage function for backwards compatibility.
- * @see WikiPage::getActionOverrides
+ * @see ContentHandler::getActionOverrides
*/
public function getActionOverrides() {
return $this->mPage->getActionOverrides();
}
$title = $this->getTitle();
- if ( NS_CATEGORY == $title->getNamespace() ) {
+ if ( $title->inNamespace( NS_CATEGORY ) ) {
$this->openShowCategory();
}
parent::view();
- if ( NS_CATEGORY == $title->getNamespace() ) {
+ if ( $title->inNamespace( NS_CATEGORY ) ) {
$this->closeShowCategory();
}
}
}
/**
- * Returns overrides for action handlers.
- * Classes listed here will be used instead of the default one when
- * (and only when) $wgActions[$action] === true. This allows subclasses
- * to override the default behavior.
- *
* @todo Move this UI stuff somewhere else
*
- * @return array
+ * @see ContentHandler::getActionOverrides
*/
public function getActionOverrides() {
- $content_handler = $this->getContentHandler();
- return $content_handler->getActionOverrides();
+ return $this->getContentHandler()->getActionOverrides();
}
/**
}
// Get the pre-save transform content and final parser output
- $editInfo = $this->prepareContentForEdit( $content, null, $user, $serialFormat );
+ $useCache = !( $flags & EDIT_FORCE_BOT ); // avoid statsd noise (T136678)
+ $editInfo = $this->prepareContentForEdit( $content, null, $user, $serialFormat, $useCache );
$pstContent = $editInfo->pstContent; // Content object
$meta = [
'bot' => ( $flags & EDIT_FORCE_BOT ),
* to do the dirty work
*
* @todo Separate the business/permission stuff out from backend code
+ * @todo Remove $token parameter. Already verified by RollbackAction and ApiRollback.
*
* @param string $fromP Name of the user whose edits to rollback.
* @param string $summary Custom summary. Set to default summary if empty.
$rollbackErrors = $this->mTitle->getUserPermissionsErrors( 'rollback', $user );
$errors = array_merge( $editErrors, wfArrayDiff2( $rollbackErrors, $editErrors ) );
- if ( !$user->matchEditToken( $token, [ $this->mTitle->getPrefixedText(), $fromP ] ) ) {
+ if ( !$user->matchEditToken( $token, 'rollback' ) ) {
$errors[] = [ 'sessionfailure' ];
}
--- /dev/null
+<?php
+
+/**
+ * This is the part of the wikitext parser which handles automatic paragraphs
+ * and conversion of start-of-line prefixes to HTML lists.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+class BlockLevelPass {
+ private $DTopen = false;
+ private $inPre = false;
+ private $lastSection = '';
+ private $linestart;
+ private $text;
+
+ # State constants for the definition list colon extraction
+ const COLON_STATE_TEXT = 0;
+ const COLON_STATE_TAG = 1;
+ const COLON_STATE_TAGSTART = 2;
+ const COLON_STATE_CLOSETAG = 3;
+ const COLON_STATE_TAGSLASH = 4;
+ const COLON_STATE_COMMENT = 5;
+ const COLON_STATE_COMMENTDASH = 6;
+ const COLON_STATE_COMMENTDASHDASH = 7;
+
+ /**
+ * Make lists from lines starting with ':', '*', '#', etc.
+ *
+ * @param string $text
+ * @param bool $lineStart Whether or not this is at the start of a line.
+ * @return string The lists rendered as HTML
+ */
+ public static function doBlockLevels( $text, $lineStart ) {
+ $pass = new self( $text, $lineStart );
+ return $pass->execute();
+ }
+
+ /**
+ * Private constructor
+ */
+ private function __construct( $text, $lineStart ) {
+ $this->text = $text;
+ $this->lineStart = $lineStart;
+ }
+
+ /**
+ * If a pre or p is open, return the corresponding close tag and update
+ * the state. If no tag is open, return an empty string.
+ * @return string
+ */
+ private function closeParagraph() {
+ $result = '';
+ if ( $this->lastSection !== '' ) {
+ $result = '</' . $this->lastSection . ">\n";
+ }
+ $this->inPre = false;
+ $this->lastSection = '';
+ return $result;
+ }
+
+ /**
+ * getCommon() returns the length of the longest common substring
+ * of both arguments, starting at the beginning of both.
+ *
+ * @param string $st1
+ * @param string $st2
+ *
+ * @return int
+ */
+ private function getCommon( $st1, $st2 ) {
+ $shorter = min( strlen( $st1 ), strlen( $st2 ) );
+
+ for ( $i = 0; $i < $shorter; ++$i ) {
+ if ( $st1[$i] !== $st2[$i] ) {
+ break;
+ }
+ }
+ return $i;
+ }
+
+ /**
+ * Open the list item element identified by the prefix character.
+ *
+ * @param string $char
+ *
+ * @return string
+ */
+ private function openList( $char ) {
+ $result = $this->closeParagraph();
+
+ if ( '*' === $char ) {
+ $result .= "<ul><li>";
+ } elseif ( '#' === $char ) {
+ $result .= "<ol><li>";
+ } elseif ( ':' === $char ) {
+ $result .= "<dl><dd>";
+ } elseif ( ';' === $char ) {
+ $result .= "<dl><dt>";
+ $this->DTopen = true;
+ } else {
+ $result = '<!-- ERR 1 -->';
+ }
+
+ return $result;
+ }
+
+ /**
+ * Close the current list item and open the next one.
+ * @param string $char
+ *
+ * @return string
+ */
+ private function nextItem( $char ) {
+ if ( '*' === $char || '#' === $char ) {
+ return "</li>\n<li>";
+ } elseif ( ':' === $char || ';' === $char ) {
+ $close = "</dd>\n";
+ if ( $this->DTopen ) {
+ $close = "</dt>\n";
+ }
+ if ( ';' === $char ) {
+ $this->DTopen = true;
+ return $close . '<dt>';
+ } else {
+ $this->DTopen = false;
+ return $close . '<dd>';
+ }
+ }
+ return '<!-- ERR 2 -->';
+ }
+
+ /**
+ * Close the current list item identified by the prefix character.
+ * @param string $char
+ *
+ * @return string
+ */
+ private function closeList( $char ) {
+ if ( '*' === $char ) {
+ $text = "</li></ul>";
+ } elseif ( '#' === $char ) {
+ $text = "</li></ol>";
+ } elseif ( ':' === $char ) {
+ if ( $this->DTopen ) {
+ $this->DTopen = false;
+ $text = "</dt></dl>";
+ } else {
+ $text = "</dd></dl>";
+ }
+ } else {
+ return '<!-- ERR 3 -->';
+ }
+ return $text;
+ }
+
+ /**
+ * Execute the pass.
+ * @return string
+ */
+ private function execute() {
+ $text = $this->text;
+ # Parsing through the text line by line. The main thing
+ # happening here is handling of block-level elements p, pre,
+ # and making lists from lines starting with * # : etc.
+ $textLines = StringUtils::explode( "\n", $text );
+
+ $lastPrefix = $output = '';
+ $this->DTopen = $inBlockElem = false;
+ $prefixLength = 0;
+ $pendingPTag = false;
+ $inBlockquote = false;
+
+ foreach ( $textLines as $inputLine ) {
+ # Fix up $lineStart
+ if ( !$this->lineStart ) {
+ $output .= $inputLine;
+ $this->lineStart = true;
+ continue;
+ }
+ # * = ul
+ # # = ol
+ # ; = dt
+ # : = dd
+
+ $lastPrefixLength = strlen( $lastPrefix );
+ $preCloseMatch = preg_match( '/<\\/pre/i', $inputLine );
+ $preOpenMatch = preg_match( '/<pre/i', $inputLine );
+ # If not in a <pre> element, scan for and figure out what prefixes are there.
+ if ( !$this->inPre ) {
+ # Multiple prefixes may abut each other for nested lists.
+ $prefixLength = strspn( $inputLine, '*#:;' );
+ $prefix = substr( $inputLine, 0, $prefixLength );
+
+ # eh?
+ # ; and : are both from definition-lists, so they're equivalent
+ # for the purposes of determining whether or not we need to open/close
+ # elements.
+ $prefix2 = str_replace( ';', ':', $prefix );
+ $t = substr( $inputLine, $prefixLength );
+ $this->inPre = (bool)$preOpenMatch;
+ } else {
+ # Don't interpret any other prefixes in preformatted text
+ $prefixLength = 0;
+ $prefix = $prefix2 = '';
+ $t = $inputLine;
+ }
+
+ # List generation
+ if ( $prefixLength && $lastPrefix === $prefix2 ) {
+ # Same as the last item, so no need to deal with nesting or opening stuff
+ $output .= $this->nextItem( substr( $prefix, -1 ) );
+ $pendingPTag = false;
+
+ if ( substr( $prefix, -1 ) === ';' ) {
+ # The one nasty exception: definition lists work like this:
+ # ; title : definition text
+ # So we check for : in the remainder text to split up the
+ # title and definition, without b0rking links.
+ $term = $t2 = '';
+ if ( $this->findColonNoLinks( $t, $term, $t2 ) !== false ) {
+ $t = $t2;
+ $output .= $term . $this->nextItem( ':' );
+ }
+ }
+ } elseif ( $prefixLength || $lastPrefixLength ) {
+ # We need to open or close prefixes, or both.
+
+ # Either open or close a level...
+ $commonPrefixLength = $this->getCommon( $prefix, $lastPrefix );
+ $pendingPTag = false;
+
+ # Close all the prefixes which aren't shared.
+ while ( $commonPrefixLength < $lastPrefixLength ) {
+ $output .= $this->closeList( $lastPrefix[$lastPrefixLength - 1] );
+ --$lastPrefixLength;
+ }
+
+ # Continue the current prefix if appropriate.
+ if ( $prefixLength <= $commonPrefixLength && $commonPrefixLength > 0 ) {
+ $output .= $this->nextItem( $prefix[$commonPrefixLength - 1] );
+ }
+
+ # Open prefixes where appropriate.
+ if ( $lastPrefix && $prefixLength > $commonPrefixLength ) {
+ $output .= "\n";
+ }
+ while ( $prefixLength > $commonPrefixLength ) {
+ $char = substr( $prefix, $commonPrefixLength, 1 );
+ $output .= $this->openList( $char );
+
+ if ( ';' === $char ) {
+ # @todo FIXME: This is dupe of code above
+ if ( $this->findColonNoLinks( $t, $term, $t2 ) !== false ) {
+ $t = $t2;
+ $output .= $term . $this->nextItem( ':' );
+ }
+ }
+ ++$commonPrefixLength;
+ }
+ if ( !$prefixLength && $lastPrefix ) {
+ $output .= "\n";
+ }
+ $lastPrefix = $prefix2;
+ }
+
+ # If we have no prefixes, go to paragraph mode.
+ if ( 0 == $prefixLength ) {
+ # No prefix (not in list)--go to paragraph mode
+ # @todo consider using a stack for nestable elements like span, table and div
+ $openMatch = preg_match(
+ '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|'
+ . '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS',
+ $t
+ );
+ $closeMatch = preg_match(
+ '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
+ . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
+ . Parser::MARKER_PREFIX
+ . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS',
+ $t
+ );
+
+ if ( $openMatch || $closeMatch ) {
+ $pendingPTag = false;
+ # @todo bug 5718: paragraph closed
+ $output .= $this->closeParagraph();
+ if ( $preOpenMatch && !$preCloseMatch ) {
+ $this->inPre = true;
+ }
+ $bqOffset = 0;
+ while ( preg_match( '/<(\\/?)blockquote[\s>]/i', $t,
+ $bqMatch, PREG_OFFSET_CAPTURE, $bqOffset )
+ ) {
+ $inBlockquote = !$bqMatch[1][0]; // is this a close tag?
+ $bqOffset = $bqMatch[0][1] + strlen( $bqMatch[0][0] );
+ }
+ $inBlockElem = !$closeMatch;
+ } elseif ( !$inBlockElem && !$this->inPre ) {
+ if ( ' ' == substr( $t, 0, 1 )
+ && ( $this->lastSection === 'pre' || trim( $t ) != '' )
+ && !$inBlockquote
+ ) {
+ # pre
+ if ( $this->lastSection !== 'pre' ) {
+ $pendingPTag = false;
+ $output .= $this->closeParagraph() . '<pre>';
+ $this->lastSection = 'pre';
+ }
+ $t = substr( $t, 1 );
+ } else {
+ # paragraph
+ if ( trim( $t ) === '' ) {
+ if ( $pendingPTag ) {
+ $output .= $pendingPTag . '<br />';
+ $pendingPTag = false;
+ $this->lastSection = 'p';
+ } else {
+ if ( $this->lastSection !== 'p' ) {
+ $output .= $this->closeParagraph();
+ $this->lastSection = '';
+ $pendingPTag = '<p>';
+ } else {
+ $pendingPTag = '</p><p>';
+ }
+ }
+ } else {
+ if ( $pendingPTag ) {
+ $output .= $pendingPTag;
+ $pendingPTag = false;
+ $this->lastSection = 'p';
+ } elseif ( $this->lastSection !== 'p' ) {
+ $output .= $this->closeParagraph() . '<p>';
+ $this->lastSection = 'p';
+ }
+ }
+ }
+ }
+ }
+ # somewhere above we forget to get out of pre block (bug 785)
+ if ( $preCloseMatch && $this->inPre ) {
+ $this->inPre = false;
+ }
+ if ( $pendingPTag === false ) {
+ $output .= $t;
+ if ( $prefixLength === 0 ) {
+ $output .= "\n";
+ }
+ }
+ }
+ while ( $prefixLength ) {
+ $output .= $this->closeList( $prefix2[$prefixLength - 1] );
+ --$prefixLength;
+ if ( !$prefixLength ) {
+ $output .= "\n";
+ }
+ }
+ if ( $this->lastSection !== '' ) {
+ $output .= '</' . $this->lastSection . '>';
+ $this->lastSection = '';
+ }
+
+ return $output;
+ }
+
+ /**
+ * Split up a string on ':', ignoring any occurrences inside tags
+ * to prevent illegal overlapping.
+ *
+ * @param string $str The string to split
+ * @param string &$before Set to everything before the ':'
+ * @param string &$after Set to everything after the ':'
+ * @throws MWException
+ * @return string The position of the ':', or false if none found
+ */
+ private function findColonNoLinks( $str, &$before, &$after ) {
+ $colonPos = strpos( $str, ':' );
+ if ( $colonPos === false ) {
+ # Nothing to find!
+ return false;
+ }
+
+ $ltPos = strpos( $str, '<' );
+ if ( $ltPos === false || $ltPos > $colonPos ) {
+ # Easy; no tag nesting to worry about
+ $before = substr( $str, 0, $colonPos );
+ $after = substr( $str, $colonPos + 1 );
+ return $colonPos;
+ }
+
+ # Ugly state machine to walk through avoiding tags.
+ $state = self::COLON_STATE_TEXT;
+ $level = 0;
+ $len = strlen( $str );
+ for ( $i = 0; $i < $len; $i++ ) {
+ $c = $str[$i];
+
+ switch ( $state ) {
+ case self::COLON_STATE_TEXT:
+ switch ( $c ) {
+ case "<":
+ # Could be either a <start> tag or an </end> tag
+ $state = self::COLON_STATE_TAGSTART;
+ break;
+ case ":":
+ if ( $level === 0 ) {
+ # We found it!
+ $before = substr( $str, 0, $i );
+ $after = substr( $str, $i + 1 );
+ return $i;
+ }
+ # Embedded in a tag; don't break it.
+ break;
+ default:
+ # Skip ahead looking for something interesting
+ $colonPos = strpos( $str, ':', $i );
+ if ( $colonPos === false ) {
+ # Nothing else interesting
+ return false;
+ }
+ $ltPos = strpos( $str, '<', $i );
+ if ( $level === 0 ) {
+ if ( $ltPos === false || $colonPos < $ltPos ) {
+ # We found it!
+ $before = substr( $str, 0, $colonPos );
+ $after = substr( $str, $colonPos + 1 );
+ return $i;
+ }
+ }
+ if ( $ltPos === false ) {
+ # Nothing else interesting to find; abort!
+ # We're nested, but there's no close tags left. Abort!
+ break 2;
+ }
+ # Skip ahead to next tag start
+ $i = $ltPos;
+ $state = self::COLON_STATE_TAGSTART;
+ }
+ break;
+ case self::COLON_STATE_TAG:
+ # In a <tag>
+ switch ( $c ) {
+ case ">":
+ $level++;
+ $state = self::COLON_STATE_TEXT;
+ break;
+ case "/":
+ # Slash may be followed by >?
+ $state = self::COLON_STATE_TAGSLASH;
+ break;
+ default:
+ # ignore
+ }
+ break;
+ case self::COLON_STATE_TAGSTART:
+ switch ( $c ) {
+ case "/":
+ $state = self::COLON_STATE_CLOSETAG;
+ break;
+ case "!":
+ $state = self::COLON_STATE_COMMENT;
+ break;
+ case ">":
+ # Illegal early close? This shouldn't happen D:
+ $state = self::COLON_STATE_TEXT;
+ break;
+ default:
+ $state = self::COLON_STATE_TAG;
+ }
+ break;
+ case self::COLON_STATE_CLOSETAG:
+ # In a </tag>
+ if ( $c === ">" ) {
+ $level--;
+ if ( $level < 0 ) {
+ wfDebug( __METHOD__ . ": Invalid input; too many close tags\n" );
+ return false;
+ }
+ $state = self::COLON_STATE_TEXT;
+ }
+ break;
+ case self::COLON_STATE_TAGSLASH:
+ if ( $c === ">" ) {
+ # Yes, a self-closed tag <blah/>
+ $state = self::COLON_STATE_TEXT;
+ } else {
+ # Probably we're jumping the gun, and this is an attribute
+ $state = self::COLON_STATE_TAG;
+ }
+ break;
+ case self::COLON_STATE_COMMENT:
+ if ( $c === "-" ) {
+ $state = self::COLON_STATE_COMMENTDASH;
+ }
+ break;
+ case self::COLON_STATE_COMMENTDASH:
+ if ( $c === "-" ) {
+ $state = self::COLON_STATE_COMMENTDASHDASH;
+ } else {
+ $state = self::COLON_STATE_COMMENT;
+ }
+ break;
+ case self::COLON_STATE_COMMENTDASHDASH:
+ if ( $c === ">" ) {
+ $state = self::COLON_STATE_TEXT;
+ } else {
+ $state = self::COLON_STATE_COMMENT;
+ }
+ break;
+ default:
+ throw new MWException( "State machine error in " . __METHOD__ );
+ }
+ }
+ if ( $level > 0 ) {
+ wfDebug( __METHOD__ . ": Invalid input; not enough close tags (level $level, state $state)\n" );
+ return false;
+ }
+ return false;
+ }
+}
$converter->markNoConversion( wfEscapeWikiText( $text ) )
)->inContentLanguage()->text() .
'</span>';
+ } else {
+ return '';
}
+ } else {
+ $converter = $parser->getConverterLanguage()->getConverter();
+ $parser->getOutput()->addWarning(
+ wfMessage( 'restricted-displaytitle',
+ // Message should be parsed, but this param should only be escaped.
+ $converter->markNoConversion( wfEscapeWikiText( $text ) )
+ )->text()
+ );
+ $parser->addTrackingCategory( 'restricted-displaytitle-ignored' );
}
-
- return '';
}
/**
// fetch revision from cache/database and return the value
$rev = self::getCachedRevisionObject( $parser, $title );
$length = $rev ? $rev->getSize() : 0;
+ if ( $length === null ) {
+ // We've had bugs where rev_len was not being recorded for empty pages, see T135414
+ $length = 0;
+ }
return self::formatRaw( $length, $raw );
}
$content = StringUtils::delimiterReplace( '<nowiki>', '</nowiki>', '$1', $text, 'i' );
$attribs = Sanitizer::validateTagAttributes( $attribs, 'pre' );
- return Xml::openElement( 'pre', $attribs ) .
- Xml::escapeTagsOnly( $content ) .
- '</pre>';
+ // We need to let both '"' and '&' through,
+ // for strip markers and entities respectively.
+ $content = str_replace(
+ [ '>', '<' ],
+ [ '>', '<' ],
+ $content
+ );
+ return Html::rawElement( 'pre', $attribs, $content );
}
/**
* @return array
*/
public static function nowiki( $content, $attributes, $parser ) {
- $content = strtr( $content, [ '-{' => '-{', '}-' => '}-' ] );
- return [ Xml::escapeTagsOnly( $content ), 'markerType' => 'nowiki' ];
+ $content = strtr( $content, [
+ // lang converter
+ '-{' => '-{',
+ '}-' => '}-',
+ // html tags
+ '<' => '<',
+ '>' => '>'
+ // Note: Both '"' and '&' are not converted.
+ // This allows strip markers and entities through.
+ ] );
+ return [ $content, 'markerType' => 'nowiki' ];
}
/**
return;
}
- global $wgContLang, $wgContentHandlerUseDB, $wgPageLanguageUseDB;
+ global $wgContLang;
$colours = [];
$linkCache = LinkCache::singleton();
$output = $this->parent->getOutput();
+ $linkRenderer = $this->parent->getLinkRenderer();
+ $threshold = $linkRenderer->getStubThreshold();
$dbr = wfGetDB( DB_SLAVE );
- $threshold = $this->parent->getOptions()->getStubThreshold();
# Sort by namespace
ksort( $this->internals );
$linkcolour_ids = [];
# Generate query
- $queries = [];
+ $lb = new LinkBatch();
+ $lb->setCaller( __METHOD__ );
+
foreach ( $this->internals as $ns => $entries ) {
foreach ( $entries as $entry ) {
/** @var Title $title */
$colours[$pdbk] = 'new';
} else {
# Not in the link cache, add it to the query
- $queries[$ns][] = $title->getDBkey();
+ $lb->addObj( $title );
}
}
}
}
- if ( $queries ) {
- $where = [];
- foreach ( $queries as $ns => $pages ) {
- $where[] = $dbr->makeList(
- [
- 'page_namespace' => $ns,
- 'page_title' => array_unique( $pages ),
- ],
- LIST_AND
- );
- }
-
- $fields = [ 'page_id', 'page_namespace', 'page_title',
- 'page_is_redirect', 'page_len', 'page_latest' ];
-
- if ( $wgContentHandlerUseDB ) {
- $fields[] = 'page_content_model';
- }
- if ( $wgPageLanguageUseDB ) {
- $fields[] = 'page_lang';
- }
+ if ( !$lb->isEmpty() ) {
+ $fields = array_merge(
+ LinkCache::getSelectFields(),
+ [ 'page_namespace', 'page_title' ]
+ );
$res = $dbr->select(
'page',
$fields,
- $dbr->makeList( $where, LIST_OR ),
+ $lb->constructSet( 'page', $dbr ),
__METHOD__
);
$pdbk = $title->getPrefixedDBkey();
$linkCache->addGoodLinkObjFromRow( $title, $s );
$output->addLink( $title, $s->page_id );
- # @todo FIXME: Convoluted data flow
- # The redirect status and length is passed to getLinkColour via the LinkCache
- # Use formal parameters instead
$colours[$pdbk] = Linker::getLinkColour( $title, $threshold );
// add id to the extension todolist
$linkcolour_ids[$s->page_id] = $pdbk;
}
if ( $displayText === '' ) {
$displayText = null;
+ } else {
+ $displayText = new HtmlArmor( $displayText );
}
if ( !isset( $colours[$pdbk] ) ) {
$colours[$pdbk] = 'new';
if ( $colours[$pdbk] == 'new' ) {
$linkCache->addBadLinkObj( $title );
$output->addLink( $title, 0 );
- $type = [ 'broken' ];
+ $link = $linkRenderer->makeBrokenLink(
+ $title, $displayText, $attribs, $query
+ );
} else {
- if ( $colours[$pdbk] != '' ) {
- $attribs['class'] = $colours[$pdbk];
- }
- $type = [ 'known', 'noclasses' ];
+ $link = $linkRenderer->makePreloadedLink(
+ $title, $displayText, $colours[$pdbk], $attribs, $query
+ );
}
- $replacePairs[$searchkey] = Linker::link( $title, $displayText,
- $attribs, $query, $type );
+
+ $replacePairs[$searchkey] = $link;
}
}
$replacer = new HashtableReplacer( $replacePairs, 1 );
# Make interwiki link HTML
$output = $this->parent->getOutput();
$replacePairs = [];
- $options = [
- 'stubThreshold' => $this->parent->getOptions()->getStubThreshold(),
- ];
+ $linkRenderer = $this->parent->getLinkRenderer();
foreach ( $this->interwikis as $key => $link ) {
- $replacePairs[$key] = Linker::link( $link['title'], $link['text'], [], [], $options );
+ $replacePairs[$key] = $linkRenderer->makeLink(
+ $link['title'],
+ new HtmlArmor( $link['text'] )
+ );
$output->addInterwikiLink( $link['title'] );
}
$replacer = new HashtableReplacer( $replacePairs, 1 );
* @param array $colours
*/
protected function doVariants( &$colours ) {
- global $wgContLang, $wgContentHandlerUseDB, $wgPageLanguageUseDB;
+ global $wgContLang;
$linkBatch = new LinkBatch();
$variantMap = []; // maps $pdbkey_Variant => $keys (of link holders)
$output = $this->parent->getOutput();
}
$variantTitle = Title::makeTitle( $ns, $textVariant );
- if ( is_null( $variantTitle ) ) {
- continue;
- }
// Self-link checking for mixed/different variant titles. At this point, we
// already know the exact title does not exist, so the link cannot be to a
if ( !$linkBatch->isEmpty() ) {
// construct query
$dbr = wfGetDB( DB_SLAVE );
- $fields = [ 'page_id', 'page_namespace', 'page_title',
- 'page_is_redirect', 'page_len', 'page_latest' ];
-
- if ( $wgContentHandlerUseDB ) {
- $fields[] = 'page_content_model';
- }
- if ( $wgPageLanguageUseDB ) {
- $fields[] = 'page_lang';
- }
+ $fields = array_merge(
+ LinkCache::getSelectFields(),
+ [ 'page_namespace', 'page_title' ]
+ );
$varRes = $dbr->select( 'page',
$fields,
$entry['pdbk'] = $varPdbk;
// set pdbk and colour
- # @todo FIXME: Convoluted data flow
- # The redirect status and length is passed to getLinkColour via the LinkCache
- # Use formal parameters instead
$colours[$varPdbk] = Linker::getLinkColour( $variantTitle, $threshold );
$linkcolour_ids[$s->page_id] = $pdbk;
}
* @file
* @ingroup Parser
*/
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\MediaWikiServices;
/**
* @defgroup Parser Parser
# Regular expression for a non-newline space
const SPACE_NOT_NL = '(?:\t| |&\#0*160;|&\#[Xx]0*[Aa]0;|\p{Zs})';
- # State constants for the definition list colon extraction
- const COLON_STATE_TEXT = 0;
- const COLON_STATE_TAG = 1;
- const COLON_STATE_TAGSTART = 2;
- const COLON_STATE_CLOSETAG = 3;
- const COLON_STATE_TAGSLASH = 4;
- const COLON_STATE_COMMENT = 5;
- const COLON_STATE_COMMENTDASH = 6;
- const COLON_STATE_COMMENTDASHDASH = 7;
-
# Flags for preprocessToDom
const PTD_FOR_INCLUSION = 1;
*
* Must not consist of all title characters, or else it will change
* the behavior of <nowiki> in a link.
+ *
+ * Must have a character that needs escaping in attributes, otherwise
+ * someone could put a strip marker in an attribute, to get around
+ * escaping quote marks, and break out of the attribute. Thus we add
+ * `'".
*/
- const MARKER_SUFFIX = "-QINU\x7f";
- const MARKER_PREFIX = "\x7fUNIQ-";
+ const MARKER_SUFFIX = "-QINU`\"'\x7f";
+ const MARKER_PREFIX = "\x7f'\"`UNIQ-";
# Markers used for wrapping the table of contents
const TOC_START = '<mw:toc>';
* @var ParserOutput
*/
public $mOutput;
- public $mAutonumber, $mDTopen;
+ public $mAutonumber;
/**
* @var StripState
*/
public $mStripState;
- public $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
+ public $mIncludeCount;
/**
* @var LinkHolderArray
*/
/** @var SectionProfiler */
protected $mProfiler;
+ /**
+ * @var LinkRenderer
+ */
+ protected $mLinkRenderer;
+
/**
* @param array $conf
*/
$this->mOutput = new ParserOutput;
$this->mOptions->registerWatcher( [ $this->mOutput, 'recordOption' ] );
$this->mAutonumber = 0;
- $this->mLastSection = '';
- $this->mDTopen = false;
$this->mIncludeCount = [];
- $this->mArgStack = false;
- $this->mInPre = false;
$this->mLinkHolders = new LinkHolderArray( $this );
$this->mLinkID = 0;
$this->mRevisionObject = $this->mRevisionTimestamp =
return $this->mPreprocessor;
}
+ /**
+ * Get a LinkRenderer instance to make links with
+ *
+ * @since 1.28
+ * @return LinkRenderer
+ */
+ public function getLinkRenderer() {
+ if ( !$this->mLinkRenderer ) {
+ $this->mLinkRenderer = MediaWikiServices::getInstance()
+ ->getLinkRendererFactory()->create();
+ $this->mLinkRenderer->setStubThreshold(
+ $this->getOptions()->getStubThreshold()
+ );
+ }
+
+ return $this->mLinkRenderer;
+ }
+
/**
* Replaces all occurrences of HTML-style comments and the given tags
* in the text with a random marker and returns the next text. The output
substr( $m[0], 0, 20 ) . '"' );
}
$url = wfMessage( $urlmsg, $id )->inContentLanguage()->text();
- return Linker::makeExternalLink( $url, "{$keyword} {$id}", true, $cssClass );
+ return Linker::makeExternalLink( $url, "{$keyword} {$id}", true, $cssClass, [], $this->mTitle );
} elseif ( isset( $m[6] ) && $m[6] !== '' ) {
# ISBN
$isbn = $m[6];
$text = Linker::makeExternalLink( $url,
$this->getConverterLanguage()->markNoConversion( $url, true ),
true, 'free',
- $this->getExternalLinkAttribs( $url ) );
+ $this->getExternalLinkAttribs( $url ), $this->mTitle );
# Register it in the output object...
# Replace unnecessary URL escape codes with their equivalent characters
$pasteurized = self::normalizeLinkUrl( $url );
# Funny characters like ö aren't valid in URLs anyway
# This was changed in August 2004
$s .= Linker::makeExternalLink( $url, $text, false, $linktype,
- $this->getExternalLinkAttribs( $url ) ) . $dtrail . $trail;
+ $this->getExternalLinkAttribs( $url ), $this->mTitle ) . $dtrail . $trail;
# Register link in the output object.
# Replace unnecessary URL escape codes with the referenced character
* (depending on configuration, namespace, and the URL's domain) and/or a
* target attribute (depending on configuration).
*
- * @param string|bool $url Optional URL, to extract the domain from for rel =>
+ * @param string $url URL to extract the domain from for rel =>
* nofollow if appropriate
* @return array Associative array of HTML attributes
*/
- public function getExternalLinkAttribs( $url = false ) {
+ public function getExternalLinkAttribs( $url ) {
$attribs = [];
- $attribs['rel'] = self::getExternalLinkRel( $url, $this->mTitle );
-
- if ( $this->mOptions->getExternalLinkTarget() ) {
- $attribs['target'] = $this->mOptions->getExternalLinkTarget();
+ $rel = self::getExternalLinkRel( $url, $this->mTitle );
+
+ $target = $this->mOptions->getExternalLinkTarget();
+ if ( $target ) {
+ $attribs['target'] = $target;
+ if ( !in_array( $target, [ '_self', '_parent', '_top' ] ) ) {
+ // T133507. New windows can navigate parent cross-origin.
+ // Including noreferrer due to lacking browser
+ // support of noopener. Eventually noreferrer should be removed.
+ if ( $rel !== '' ) {
+ $rel .= ' ';
+ }
+ $rel .= 'noreferrer noopener';
+ }
}
+ $attribs['rel'] = $rel;
return $attribs;
}
# batch file existence checks for NS_FILE and NS_MEDIA
if ( $iw == '' && $nt->isAlwaysKnown() ) {
$this->mOutput->addLink( $nt );
- $s .= $this->makeKnownLinkHolder( $nt, $text, [], $trail, $prefix );
+ $s .= $this->makeKnownLinkHolder( $nt, $text, $trail, $prefix );
} else {
# Links will be added to the output link list after checking
$s .= $holders->makeHolder( $nt, $text, [], $trail, $prefix );
*
* @param Title $nt
* @param string $text
- * @param array|string $query
* @param string $trail
* @param string $prefix
* @return string HTML-wikitext mix oh yuck
*/
- public function makeKnownLinkHolder( $nt, $text = '', $query = [], $trail = '', $prefix = '' ) {
+ protected function makeKnownLinkHolder( $nt, $text = '', $trail = '', $prefix = '' ) {
list( $inside, $trail ) = Linker::splitTrail( $trail );
- if ( is_string( $query ) ) {
- $query = wfCgiToArray( $query );
- }
if ( $text == '' ) {
$text = htmlspecialchars( $nt->getPrefixedText() );
}
- $link = Linker::linkKnown( $nt, "$prefix$text$inside", [], $query );
+ $link = $this->getLinkRenderer()->makeKnownLink(
+ $nt, new HtmlArmor( "$prefix$text$inside" )
+ );
return $this->armorLinks( $link ) . $trail;
}
return Linker::normalizeSubpageLink( $this->mTitle, $target, $text );
}
- /**#@+
- * Used by doBlockLevels()
- * @private
- *
- * @return string
- */
- public function closeParagraph() {
- $result = '';
- if ( $this->mLastSection != '' ) {
- $result = '</' . $this->mLastSection . ">\n";
- }
- $this->mInPre = false;
- $this->mLastSection = '';
- return $result;
- }
-
- /**
- * getCommon() returns the length of the longest common substring
- * of both arguments, starting at the beginning of both.
- * @private
- *
- * @param string $st1
- * @param string $st2
- *
- * @return int
- */
- public function getCommon( $st1, $st2 ) {
- $fl = strlen( $st1 );
- $shorter = strlen( $st2 );
- if ( $fl < $shorter ) {
- $shorter = $fl;
- }
-
- for ( $i = 0; $i < $shorter; ++$i ) {
- if ( $st1[$i] != $st2[$i] ) {
- break;
- }
- }
- return $i;
- }
-
- /**
- * These next three functions open, continue, and close the list
- * element appropriate to the prefix character passed into them.
- * @private
- *
- * @param string $char
- *
- * @return string
- */
- public function openList( $char ) {
- $result = $this->closeParagraph();
-
- if ( '*' === $char ) {
- $result .= "<ul><li>";
- } elseif ( '#' === $char ) {
- $result .= "<ol><li>";
- } elseif ( ':' === $char ) {
- $result .= "<dl><dd>";
- } elseif ( ';' === $char ) {
- $result .= "<dl><dt>";
- $this->mDTopen = true;
- } else {
- $result = '<!-- ERR 1 -->';
- }
-
- return $result;
- }
-
- /**
- * TODO: document
- * @param string $char
- * @private
- *
- * @return string
- */
- public function nextItem( $char ) {
- if ( '*' === $char || '#' === $char ) {
- return "</li>\n<li>";
- } elseif ( ':' === $char || ';' === $char ) {
- $close = "</dd>\n";
- if ( $this->mDTopen ) {
- $close = "</dt>\n";
- }
- if ( ';' === $char ) {
- $this->mDTopen = true;
- return $close . '<dt>';
- } else {
- $this->mDTopen = false;
- return $close . '<dd>';
- }
- }
- return '<!-- ERR 2 -->';
- }
-
- /**
- * @todo Document
- * @param string $char
- * @private
- *
- * @return string
- */
- public function closeList( $char ) {
- if ( '*' === $char ) {
- $text = "</li></ul>";
- } elseif ( '#' === $char ) {
- $text = "</li></ol>";
- } elseif ( ':' === $char ) {
- if ( $this->mDTopen ) {
- $this->mDTopen = false;
- $text = "</dt></dl>";
- } else {
- $text = "</dd></dl>";
- }
- } else {
- return '<!-- ERR 3 -->';
- }
- return $text;
- }
- /**#@-*/
-
/**
* Make lists from lines starting with ':', '*', '#', etc. (DBL)
*
* @return string The lists rendered as HTML
*/
public function doBlockLevels( $text, $linestart ) {
-
- # Parsing through the text line by line. The main thing
- # happening here is handling of block-level elements p, pre,
- # and making lists from lines starting with * # : etc.
- $textLines = StringUtils::explode( "\n", $text );
-
- $lastPrefix = $output = '';
- $this->mDTopen = $inBlockElem = false;
- $prefixLength = 0;
- $paragraphStack = false;
- $inBlockquote = false;
-
- foreach ( $textLines as $oLine ) {
- # Fix up $linestart
- if ( !$linestart ) {
- $output .= $oLine;
- $linestart = true;
- continue;
- }
- # * = ul
- # # = ol
- # ; = dt
- # : = dd
-
- $lastPrefixLength = strlen( $lastPrefix );
- $preCloseMatch = preg_match( '/<\\/pre/i', $oLine );
- $preOpenMatch = preg_match( '/<pre/i', $oLine );
- # If not in a <pre> element, scan for and figure out what prefixes are there.
- if ( !$this->mInPre ) {
- # Multiple prefixes may abut each other for nested lists.
- $prefixLength = strspn( $oLine, '*#:;' );
- $prefix = substr( $oLine, 0, $prefixLength );
-
- # eh?
- # ; and : are both from definition-lists, so they're equivalent
- # for the purposes of determining whether or not we need to open/close
- # elements.
- $prefix2 = str_replace( ';', ':', $prefix );
- $t = substr( $oLine, $prefixLength );
- $this->mInPre = (bool)$preOpenMatch;
- } else {
- # Don't interpret any other prefixes in preformatted text
- $prefixLength = 0;
- $prefix = $prefix2 = '';
- $t = $oLine;
- }
-
- # List generation
- if ( $prefixLength && $lastPrefix === $prefix2 ) {
- # Same as the last item, so no need to deal with nesting or opening stuff
- $output .= $this->nextItem( substr( $prefix, -1 ) );
- $paragraphStack = false;
-
- if ( substr( $prefix, -1 ) === ';' ) {
- # The one nasty exception: definition lists work like this:
- # ; title : definition text
- # So we check for : in the remainder text to split up the
- # title and definition, without b0rking links.
- $term = $t2 = '';
- if ( $this->findColonNoLinks( $t, $term, $t2 ) !== false ) {
- $t = $t2;
- $output .= $term . $this->nextItem( ':' );
- }
- }
- } elseif ( $prefixLength || $lastPrefixLength ) {
- # We need to open or close prefixes, or both.
-
- # Either open or close a level...
- $commonPrefixLength = $this->getCommon( $prefix, $lastPrefix );
- $paragraphStack = false;
-
- # Close all the prefixes which aren't shared.
- while ( $commonPrefixLength < $lastPrefixLength ) {
- $output .= $this->closeList( $lastPrefix[$lastPrefixLength - 1] );
- --$lastPrefixLength;
- }
-
- # Continue the current prefix if appropriate.
- if ( $prefixLength <= $commonPrefixLength && $commonPrefixLength > 0 ) {
- $output .= $this->nextItem( $prefix[$commonPrefixLength - 1] );
- }
-
- # Open prefixes where appropriate.
- if ( $lastPrefix && $prefixLength > $commonPrefixLength ) {
- $output .= "\n";
- }
- while ( $prefixLength > $commonPrefixLength ) {
- $char = substr( $prefix, $commonPrefixLength, 1 );
- $output .= $this->openList( $char );
-
- if ( ';' === $char ) {
- # @todo FIXME: This is dupe of code above
- if ( $this->findColonNoLinks( $t, $term, $t2 ) !== false ) {
- $t = $t2;
- $output .= $term . $this->nextItem( ':' );
- }
- }
- ++$commonPrefixLength;
- }
- if ( !$prefixLength && $lastPrefix ) {
- $output .= "\n";
- }
- $lastPrefix = $prefix2;
- }
-
- # If we have no prefixes, go to paragraph mode.
- if ( 0 == $prefixLength ) {
- # No prefix (not in list)--go to paragraph mode
- # XXX: use a stack for nestable elements like span, table and div
- $openmatch = preg_match(
- '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|'
- . '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS',
- $t
- );
- $closematch = preg_match(
- '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
- . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
- . self::MARKER_PREFIX
- . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS',
- $t
- );
-
- if ( $openmatch || $closematch ) {
- $paragraphStack = false;
- # @todo bug 5718: paragraph closed
- $output .= $this->closeParagraph();
- if ( $preOpenMatch && !$preCloseMatch ) {
- $this->mInPre = true;
- }
- $bqOffset = 0;
- while ( preg_match( '/<(\\/?)blockquote[\s>]/i', $t,
- $bqMatch, PREG_OFFSET_CAPTURE, $bqOffset )
- ) {
- $inBlockquote = !$bqMatch[1][0]; // is this a close tag?
- $bqOffset = $bqMatch[0][1] + strlen( $bqMatch[0][0] );
- }
- $inBlockElem = !$closematch;
- } elseif ( !$inBlockElem && !$this->mInPre ) {
- if ( ' ' == substr( $t, 0, 1 )
- && ( $this->mLastSection === 'pre' || trim( $t ) != '' )
- && !$inBlockquote
- ) {
- # pre
- if ( $this->mLastSection !== 'pre' ) {
- $paragraphStack = false;
- $output .= $this->closeParagraph() . '<pre>';
- $this->mLastSection = 'pre';
- }
- $t = substr( $t, 1 );
- } else {
- # paragraph
- if ( trim( $t ) === '' ) {
- if ( $paragraphStack ) {
- $output .= $paragraphStack . '<br />';
- $paragraphStack = false;
- $this->mLastSection = 'p';
- } else {
- if ( $this->mLastSection !== 'p' ) {
- $output .= $this->closeParagraph();
- $this->mLastSection = '';
- $paragraphStack = '<p>';
- } else {
- $paragraphStack = '</p><p>';
- }
- }
- } else {
- if ( $paragraphStack ) {
- $output .= $paragraphStack;
- $paragraphStack = false;
- $this->mLastSection = 'p';
- } elseif ( $this->mLastSection !== 'p' ) {
- $output .= $this->closeParagraph() . '<p>';
- $this->mLastSection = 'p';
- }
- }
- }
- }
- }
- # somewhere above we forget to get out of pre block (bug 785)
- if ( $preCloseMatch && $this->mInPre ) {
- $this->mInPre = false;
- }
- if ( $paragraphStack === false ) {
- $output .= $t;
- if ( $prefixLength === 0 ) {
- $output .= "\n";
- }
- }
- }
- while ( $prefixLength ) {
- $output .= $this->closeList( $prefix2[$prefixLength - 1] );
- --$prefixLength;
- if ( !$prefixLength ) {
- $output .= "\n";
- }
- }
- if ( $this->mLastSection != '' ) {
- $output .= '</' . $this->mLastSection . '>';
- $this->mLastSection = '';
- }
-
- return $output;
- }
-
- /**
- * Split up a string on ':', ignoring any occurrences inside tags
- * to prevent illegal overlapping.
- *
- * @param string $str The string to split
- * @param string &$before Set to everything before the ':'
- * @param string &$after Set to everything after the ':'
- * @throws MWException
- * @return string The position of the ':', or false if none found
- */
- public function findColonNoLinks( $str, &$before, &$after ) {
-
- $pos = strpos( $str, ':' );
- if ( $pos === false ) {
- # Nothing to find!
- return false;
- }
-
- $lt = strpos( $str, '<' );
- if ( $lt === false || $lt > $pos ) {
- # Easy; no tag nesting to worry about
- $before = substr( $str, 0, $pos );
- $after = substr( $str, $pos + 1 );
- return $pos;
- }
-
- # Ugly state machine to walk through avoiding tags.
- $state = self::COLON_STATE_TEXT;
- $stack = 0;
- $len = strlen( $str );
- for ( $i = 0; $i < $len; $i++ ) {
- $c = $str[$i];
-
- switch ( $state ) {
- # (Using the number is a performance hack for common cases)
- case 0: # self::COLON_STATE_TEXT:
- switch ( $c ) {
- case "<":
- # Could be either a <start> tag or an </end> tag
- $state = self::COLON_STATE_TAGSTART;
- break;
- case ":":
- if ( $stack == 0 ) {
- # We found it!
- $before = substr( $str, 0, $i );
- $after = substr( $str, $i + 1 );
- return $i;
- }
- # Embedded in a tag; don't break it.
- break;
- default:
- # Skip ahead looking for something interesting
- $colon = strpos( $str, ':', $i );
- if ( $colon === false ) {
- # Nothing else interesting
- return false;
- }
- $lt = strpos( $str, '<', $i );
- if ( $stack === 0 ) {
- if ( $lt === false || $colon < $lt ) {
- # We found it!
- $before = substr( $str, 0, $colon );
- $after = substr( $str, $colon + 1 );
- return $i;
- }
- }
- if ( $lt === false ) {
- # Nothing else interesting to find; abort!
- # We're nested, but there's no close tags left. Abort!
- break 2;
- }
- # Skip ahead to next tag start
- $i = $lt;
- $state = self::COLON_STATE_TAGSTART;
- }
- break;
- case 1: # self::COLON_STATE_TAG:
- # In a <tag>
- switch ( $c ) {
- case ">":
- $stack++;
- $state = self::COLON_STATE_TEXT;
- break;
- case "/":
- # Slash may be followed by >?
- $state = self::COLON_STATE_TAGSLASH;
- break;
- default:
- # ignore
- }
- break;
- case 2: # self::COLON_STATE_TAGSTART:
- switch ( $c ) {
- case "/":
- $state = self::COLON_STATE_CLOSETAG;
- break;
- case "!":
- $state = self::COLON_STATE_COMMENT;
- break;
- case ">":
- # Illegal early close? This shouldn't happen D:
- $state = self::COLON_STATE_TEXT;
- break;
- default:
- $state = self::COLON_STATE_TAG;
- }
- break;
- case 3: # self::COLON_STATE_CLOSETAG:
- # In a </tag>
- if ( $c === ">" ) {
- $stack--;
- if ( $stack < 0 ) {
- wfDebug( __METHOD__ . ": Invalid input; too many close tags\n" );
- return false;
- }
- $state = self::COLON_STATE_TEXT;
- }
- break;
- case self::COLON_STATE_TAGSLASH:
- if ( $c === ">" ) {
- # Yes, a self-closed tag <blah/>
- $state = self::COLON_STATE_TEXT;
- } else {
- # Probably we're jumping the gun, and this is an attribute
- $state = self::COLON_STATE_TAG;
- }
- break;
- case 5: # self::COLON_STATE_COMMENT:
- if ( $c === "-" ) {
- $state = self::COLON_STATE_COMMENTDASH;
- }
- break;
- case self::COLON_STATE_COMMENTDASH:
- if ( $c === "-" ) {
- $state = self::COLON_STATE_COMMENTDASHDASH;
- } else {
- $state = self::COLON_STATE_COMMENT;
- }
- break;
- case self::COLON_STATE_COMMENTDASHDASH:
- if ( $c === ">" ) {
- $state = self::COLON_STATE_TEXT;
- } else {
- $state = self::COLON_STATE_COMMENT;
- }
- break;
- default:
- throw new MWException( "State machine error in " . __METHOD__ );
- }
- }
- if ( $stack > 0 ) {
- wfDebug( __METHOD__ . ": Invalid input; not enough close tags (stack $stack, state $state)\n" );
- return false;
- }
- return false;
+ return BlockLevelPass::doBlockLevels( $text, $linestart );
}
/**
}
// Check the object and lazy-loaded options
return (
- $this->mUserLang->getCode() === $other->mUserLang->getCode() &&
+ $this->mUserLang->equals( $other->mUserLang ) &&
$this->getDateFormat() === $other->getDateFormat()
);
}
'nowiki' => [],
'general' => []
];
- $this->regex = '/' . Parser::MARKER_PREFIX . "([^\x7f]+)" . Parser::MARKER_SUFFIX . '/';
+ $this->regex = '/' . Parser::MARKER_PREFIX . "([^\x7f<>&'\"]+)" . Parser::MARKER_SUFFIX . '/';
$this->circularRefGuard = [];
}
$this->args = [];
$this->hash = md5( $plaintext );
}
+
+ if ( !is_string( $this->hash ) || strlen( $this->hash ) < 32 ) {
+ throw new PasswordError( 'Error when hashing password.' );
+ }
}
}
}
$this->hash = md5( $this->args[0] . '-' . md5( $plaintext ) );
+
+ if ( !is_string( $this->hash ) || strlen( $this->hash ) < 32 ) {
+ throw new PasswordError( 'Error when hashing password.' );
+ }
}
}
$status = Status::newGood();
$username = $user->getName();
- if ( $policyVal
- && isset( $blockedLogins[$username] )
- && $password == $blockedLogins[$username]
- ) {
- $status->error( 'password-login-forbidden' );
+ if ( $policyVal ) {
+ if ( isset( $blockedLogins[$username] ) && $password == $blockedLogins[$username] ) {
+ $status->error( 'password-login-forbidden' );
+ }
+
+ // Example from ApiChangeAuthenticationRequest
+ if ( $password === 'ExamplePassword' ) {
+ $status->error( 'password-login-forbidden' );
+ }
}
return $status;
}
(int)$this->params['length'],
true
);
+ if ( !is_string( $hash ) ) {
+ throw new PasswordError( 'Error when hashing password.' );
+ }
} else {
- $hashLen = strlen( hash( $this->params['algo'], '', true ) );
+ $hashLenHash = hash( $this->params['algo'], '', true );
+ if ( !is_string( $hashLenHash ) ) {
+ throw new PasswordError( 'Error when hashing password.' );
+ }
+ $hashLen = strlen( $hashLenHash );
$blockCount = ceil( $this->params['length'] / $hashLen );
$hash = '';
/**
* @param array $conf
- * @param string $type
+ * @param string $type The class of actions to limit concurrency for (task type)
* @param string $key
*/
protected function __construct( $conf, $type, $key ) {
}
if ( $this->slots ) {
- $key = $this->hashKeyIntoSlots( $key, $this->slots );
+ $key = $this->hashKeyIntoSlots( $type, $key, $this->slots );
}
+
$this->key = $key;
$this->isMightWaitKey = !preg_match( '/^nowait:/', $this->key );
}
/**
* Create a Pool counter. This should only be called from the PoolWorks.
*
- * @param string $type
+ * @param string $type The class of actions to limit concurrency for (task type)
* @param string $key
*
* @return PoolCounter
}
/**
- * Given a key (any string) and the number of lots, returns a slot number (an integer from
- * the [0..($slots-1)] range). This is used for a global limit on the number of instances of
- * a given type that can acquire a lock. The hashing is deterministic so that
+ * Given a key (any string) and the number of lots, returns a slot key (a prefix with a suffix
+ * integer from the [0..($slots-1)] range). This is used for a global limit on the number of
+ * instances of a given type that can acquire a lock. The hashing is deterministic so that
* PoolCounter::$workers is always an upper limit of how many instances with the same key
* can acquire a lock.
*
+ * @param string $type The class of actions to limit concurrency for (task type)
* @param string $key PoolCounter instance key (any string)
* @param int $slots The number of slots (max allowed value is 65536)
- * @return int
+ * @return string Slot key with the type and slot number
*/
- protected function hashKeyIntoSlots( $key, $slots ) {
- return hexdec( substr( sha1( $key ), 0, 4 ) ) % $slots;
+ protected function hashKeyIntoSlots( $type, $key, $slots ) {
+ return $type . ':' . ( hexdec( substr( sha1( $key ), 0, 4 ) ) % $slots );
}
}
protected $cacheable = false; // does this override getCachedWork() ?
/**
- * @param string $type The type of PoolCounter to use
+ * @param string $type The class of actions to limit concurrency for (task type)
* @param string $key Key that identifies the queue this work is placed on
*/
public function __construct( $type, $key ) {
* If a 'doCachedWork' callback is provided, then execute() may wait for any prior
* process in the pool to finish and reuse its cached result.
*
- * @param string $type
+ * @param string $type The class of actions to limit concurrency for
* @param string $key
* @param array $callbacks Map of callbacks
* @throws MWException
*/
class ProfilerXhprof extends Profiler {
/**
- * @var Xhprof $xhprof
+ * @var XhprofData|null $xhprofData
*/
- protected $xhprof;
+ protected $xhprofData;
/**
* Profiler for explicit, arbitrary, frame labels
*/
public function __construct( array $params = [] ) {
parent::__construct( $params );
- $this->xhprof = new Xhprof( $params );
+
+ $flags = isset( $params['flags'] ) ? $params['flags'] : 0;
+ $options = isset( $params['exclude'] )
+ ? [ 'ignored_functions' => $params['exclude'] ] : [];
+ Xhprof::enable( $flags, $options );
$this->sprofiler = new SectionProfiler();
}
+ /**
+ * @return XhprofData
+ */
+ public function getXhprofData() {
+ if ( !$this->xhprofData ) {
+ $this->xhprofData = new XhprofData( Xhprof::disable(), $this->params );
+ }
+ return $this->xhprofData;
+ }
+
public function scopedProfileIn( $section ) {
$key = 'section.' . ltrim( $section, '.' );
return $this->sprofiler->scopedProfileIn( $key );
}
public function getFunctionStats() {
- $metrics = $this->xhprof->getCompleteMetrics();
+ $metrics = $this->getXhprofData()->getCompleteMetrics();
$profile = [];
$main = null; // units in ms
* @return array
*/
public function getRawData() {
- return $this->xhprof->getRawData();
+ return $this->getXhprofData()->getRawData();
}
}
'AvailableRights',
'ContentHandlers',
'ConfigRegistry',
+ 'SessionProviders',
+ 'AuthManagerAutoConfig',
'CentralIdLookupProviders',
'RateLimits',
'RecentChangesFlags',
'wgNamespaceProtection' => 'array_plus',
'wgCapitalLinkOverrides' => 'array_plus',
'wgRateLimits' => 'array_plus_2d',
+ 'wgAuthManagerAutoConfig' => 'array_plus_2d',
];
/**
* Get the possibly-cached User object for the specified username
*
* @since 1.25
- * @return User|bool false if a valid object cannot be created
+ * @return User
*/
public function getUserObj() {
if ( $this->userObj === null ) {
$username = $this->getUser();
if ( $username ) {
- $this->userObj = User::newFromName( $username );
+ // Use provided username if valid, fallback to anonymous user
+ $this->userObj = User::newFromName( $username ) ?: new User;
} else {
- $this->userObj = new User; // Anonymous user
+ // Anonymous user
+ $this->userObj = new User;
}
}
if ( !file_exists( $localPath ) ) {
throw new MWException( __METHOD__ . ": skip function file not found: \"$localPath\"" );
}
- $contents = file_get_contents( $localPath );
+ $contents = $this->stripBom( file_get_contents( $localPath ) );
if ( $this->getConfig()->get( 'ResourceLoaderValidateStaticJS' ) ) {
$contents = $this->validateScriptFile( $localPath, $contents );
}
if ( !file_exists( $localPath ) ) {
throw new MWException( __METHOD__ . ": script file not found: \"$localPath\"" );
}
- $contents = file_get_contents( $localPath );
+ $contents = $this->stripBom( file_get_contents( $localPath ) );
if ( $this->getConfig()->get( 'ResourceLoaderValidateStaticJS' ) ) {
// Static files don't really need to be checked as often; unlike
// on-wiki module they shouldn't change unexpectedly without
$style = $this->compileLessFile( $localPath, $context );
$this->hasGeneratedStyles = true;
} else {
- $style = file_get_contents( $localPath );
+ $style = $this->stripBom( file_get_contents( $localPath ) );
}
if ( $flip ) {
$localPath = $this->getLocalPath( $templatePath );
if ( file_exists( $localPath ) ) {
$content = file_get_contents( $localPath );
- $templates[$alias] = $content;
+ $templates[$alias] = $this->stripBom( $content );
} else {
$msg = __METHOD__ . ": template file not found: \"$localPath\"";
wfDebugLog( 'resourceloader', $msg );
}
return $templates;
}
+
+ /**
+ * Takes an input string and removes the UTF-8 BOM character if present
+ *
+ * We need to remove these after reading a file, because we concatenate our files and
+ * the BOM character is not valid in the middle of a string.
+ * We already assume UTF-8 everywhere, so this should be safe.
+ *
+ * @return string input minus the intial BOM char
+ */
+ protected function stripBom( $input ) {
+ if ( substr_compare( "\xef\xbb\xbf", $input, 0, 3 ) === 0 ) {
+ return substr( $input, 3 );
+ }
+ return $input;
+ }
}
return $this->origin;
}
- /**
- * Set this module's origin. This is called by ResourceLoader::register()
- * when registering the module. Other code should not call this.
- *
- * @param int $origin Origin
- */
- public function setOrigin( $origin ) {
- $this->origin = $origin;
- }
-
/**
* @param ResourceLoaderContext $context
* @return bool
--- /dev/null
+<?php
+/**
+ * ResourceLoader module for the upload dialog configuration data.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * ResourceLoader module for the upload dialog configuration data.
+ *
+ * @since 1.27
+ */
+class ResourceLoaderUploadDialogModule extends ResourceLoaderModule {
+
+ protected $targets = [ 'desktop', 'mobile' ];
+
+ public function getScript( ResourceLoaderContext $context ) {
+ $config = $context->getResourceLoader()->getConfig();
+ return ResourceLoader::makeConfigSetScript( [
+ 'wgUploadDialog' => $config->get( 'UploadDialog' ),
+ ] );
+ }
+
+ public function enableModuleContentVersion() {
+ return true;
+ }
+}
+++ /dev/null
-<?php
-/**
- * ResourceLoader module for user customizations.
- *
- * 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
- */
-
-/**
- * Module for user customizations
- */
-class ResourceLoaderUserGroupsModule extends ResourceLoaderWikiModule {
-
- protected $origin = self::ORIGIN_USER_SITEWIDE;
- protected $targets = [ 'desktop', 'mobile' ];
-
- /**
- * @param ResourceLoaderContext $context
- * @return array
- */
- protected function getPages( ResourceLoaderContext $context ) {
- $useSiteJs = $this->getConfig()->get( 'UseSiteJs' );
- $useSiteCss = $this->getConfig()->get( 'UseSiteCss' );
- if ( !$useSiteJs && !$useSiteCss ) {
- return [];
- }
-
- $user = $context->getUserObj();
- if ( !$user || $user->isAnon() ) {
- return [];
- }
-
- $pages = [];
- foreach ( $user->getEffectiveGroups() as $group ) {
- if ( $group == '*' ) {
- continue;
- }
- if ( $useSiteJs ) {
- $pages["MediaWiki:Group-$group.js"] = [ 'type' => 'script' ];
- }
- if ( $useSiteCss ) {
- $pages["MediaWiki:Group-$group.css"] = [ 'type' => 'style' ];
- }
- }
- return $pages;
- }
-
- /**
- * Get group name
- *
- * @return string
- */
- public function getGroup() {
- return 'user';
- }
-}
class ResourceLoaderUserModule extends ResourceLoaderWikiModule {
protected $origin = self::ORIGIN_USER_INDIVIDUAL;
+ protected $targets = [ 'desktop', 'mobile' ];
/**
* Get list of pages used by this module
* @return array List of pages
*/
protected function getPages( ResourceLoaderContext $context ) {
- $allowUserJs = $this->getConfig()->get( 'AllowUserJs' );
- $allowUserCss = $this->getConfig()->get( 'AllowUserCss' );
- if ( !$allowUserJs && !$allowUserCss ) {
- return [];
- }
-
+ $config = $this->getConfig();
$user = $context->getUserObj();
- if ( !$user || $user->isAnon() ) {
+ if ( $user->isAnon() ) {
return [];
}
- // Needed so $excludepages works
+ // Use localised/normalised variant to ensure $excludepage matches
$userPage = $user->getUserPage()->getPrefixedDBkey();
-
$pages = [];
- if ( $allowUserJs ) {
+
+ if ( $config->get( 'AllowUserJs' ) ) {
$pages["$userPage/common.js"] = [ 'type' => 'script' ];
$pages["$userPage/" . $context->getSkin() . '.js'] = [ 'type' => 'script' ];
}
- if ( $allowUserCss ) {
+
+ if ( $config->get( 'AllowUserCss' ) ) {
$pages["$userPage/common.css"] = [ 'type' => 'style' ];
$pages["$userPage/" . $context->getSkin() . '.css'] = [ 'type' => 'style' ];
}
+ $useSiteJs = $config->get( 'UseSiteJs' );
+ $useSiteCss = $config->get( 'UseSiteCss' );
+ // User group pages are maintained site-wide and enabled with site JS/CSS.
+ if ( $useSiteJs || $useSiteCss ) {
+ foreach ( $user->getEffectiveGroups() as $group ) {
+ if ( $group == '*' ) {
+ continue;
+ }
+ if ( $useSiteJs ) {
+ $pages["MediaWiki:Group-$group.js"] = [ 'type' => 'script' ];
+ }
+ if ( $useSiteCss ) {
+ $pages["MediaWiki:Group-$group.css"] = [ 'type' => 'style' ];
+ }
+ }
+ }
+
// Hack for bug 26283: if we're on a preview page for a CSS/JS page,
// we need to exclude that page from this module. In that case, the excludepage
// parameter will be set to the name of the page we need to exclude.
// just like the keys in $pages[] above
unset( $pages[$excludepage] );
}
+
return $pages;
}
$timestamps[] = $db->timestamp( $id );
}
- return $db->select( 'archive', Revision::selectArchiveFields(),
- [
- 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey(),
- 'ar_timestamp' => $timestamps
- ],
- __METHOD__,
- [ 'ORDER BY' => 'ar_timestamp DESC' ]
- );
+ $tables = [ 'archive' ];
+ $fields = Revision::selectArchiveFields();
+ $conds = [
+ 'ar_namespace' => $this->title->getNamespace(),
+ 'ar_title' => $this->title->getDBkey(),
+ 'ar_timestamp' => $timestamps,
+ ];
+ $join_conds = [];
+ $options = [ 'ORDER BY' => 'ar_timestamp DESC' ];
+
+ ChangeTags::modifyDisplayQuery(
+ $tables,
+ $fields,
+ $conds,
+ $join_conds,
+ $options,
+ ''
+ );
+
+ return $db->select( $tables,
+ $fields,
+ $conds,
+ __METHOD__,
+ $options,
+ $join_conds
+ );
}
public function newItem( $row ) {
$status->itemStatuses = [];
}
+ // For multi-item deletions, set the old/new bitfields in log_params such that "hid X"
+ // shows in logs if field X was hidden from ANY item and likewise for "unhid Y". Note the
+ // form does not let the same field get hidden and unhidden in different items at once.
+ $virtualOldBits = 0;
+ $virtualNewBits = 0;
+ $logType = 'delete';
+
// @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
for ( $this->reset(); $this->current(); $this->next() ) {
// @codingStandardsIgnoreEnd
$newBits = RevisionDeleter::extractBitfield( $bitPars, $oldBits );
if ( $oldBits == $newBits ) {
- $itemStatus->warning( 'revdelete-no-change', $item->formatDate(), $item->formatTime() );
+ $itemStatus->warning(
+ 'revdelete-no-change', $item->formatDate(), $item->formatTime() );
$status->failCount++;
continue;
} elseif ( $oldBits == 0 && $newBits != 0 ) {
if ( $item->isHideCurrentOp( $newBits ) ) {
// Cannot hide current version text
- $itemStatus->error( 'revdelete-hide-current', $item->formatDate(), $item->formatTime() );
+ $itemStatus->error(
+ 'revdelete-hide-current', $item->formatDate(), $item->formatTime() );
$status->failCount++;
continue;
- }
- if ( !$item->canView() ) {
+ } elseif ( !$item->canView() ) {
// Cannot access this revision
$msg = ( $opType == 'show' ) ?
'revdelete-show-no-access' : 'revdelete-modify-no-access';
$itemStatus->error( $msg, $item->formatDate(), $item->formatTime() );
$status->failCount++;
continue;
- }
// Cannot just "hide from Sysops" without hiding any fields
- if ( $newBits == Revision::DELETED_RESTRICTED ) {
- $itemStatus->warning( 'revdelete-only-restricted', $item->formatDate(), $item->formatTime() );
+ } elseif ( $newBits == Revision::DELETED_RESTRICTED ) {
+ $itemStatus->warning(
+ 'revdelete-only-restricted', $item->formatDate(), $item->formatTime() );
$status->failCount++;
continue;
}
if ( $ok ) {
$idsForLog[] = $item->getId();
+ // If any item field was suppressed or unsupressed
+ if ( ( $oldBits | $newBits ) & $this->getSuppressBit() ) {
+ $logType = 'suppress';
+ }
+ // Track which fields where (un)hidden for each item
+ $addedBits = ( $oldBits ^ $newBits ) & $newBits;
+ $removedBits = ( $oldBits ^ $newBits ) & $oldBits;
+ $virtualNewBits |= $addedBits;
+ $virtualOldBits |= $removedBits;
+
$status->successCount++;
if ( $item->getAuthorId() > 0 ) {
$authorIds[] = $item->getAuthorId();
$authorIPs[] = $item->getAuthorName();
}
} else {
- $itemStatus->error( 'revdelete-concurrent-change', $item->formatDate(), $item->formatTime() );
+ $itemStatus->error(
+ 'revdelete-concurrent-change', $item->formatDate(), $item->formatTime() );
$status->failCount++;
}
}
}
// Log it
- // @FIXME: $newBits/$oldBits set in for loop, makes IDE warnings too
- $this->updateLog( [
- 'title' => $this->title,
- 'count' => $successCount,
- 'newBits' => $newBits,
- 'oldBits' => $oldBits,
- 'comment' => $comment,
- 'ids' => $idsForLog,
- 'authorIds' => $authorIds,
- 'authorIPs' => $authorIPs
- ] );
+ $this->updateLog(
+ $logType,
+ [
+ 'title' => $this->title,
+ 'count' => $successCount,
+ 'newBits' => $virtualNewBits,
+ 'oldBits' => $virtualOldBits,
+ 'comment' => $comment,
+ 'ids' => $idsForLog,
+ 'authorIds' => $authorIds,
+ 'authorIPs' => $authorIPs
+ ]
+ );
// Clear caches
$that = $this;
/**
* Record a log entry on the action
+ * @param string $logType One of (delete,suppress)
* @param array $params Associative array of parameters:
* newBits: The new value of the *_deleted bitfield
* oldBits: The old value of the *_deleted bitfield.
* authorsIPs: The array of the IP/anon user offenders
* @throws MWException
*/
- protected function updateLog( $params ) {
+ private function updateLog( $logType, $params ) {
// Get the URL param's corresponding DB field
$field = RevisionDeleter::getRelationType( $this->getType() );
if ( !$field ) {
throw new MWException( "Bad log URL param type!" );
}
- // Put things hidden from sysops in the suppression log
- if ( ( $params['newBits'] | $params['oldBits'] ) & $this->getSuppressBit() ) {
- $logType = 'suppress';
- } else {
- $logType = 'delete';
- }
// Add params for affected page and ids
$logParams = $this->getLogParams( $params );
// Actually add the deletion log entry
return $live;
}
- // Check if any requested revisions are available fully deleted.
- $archived = $db->select( [ 'archive' ], Revision::selectArchiveFields(),
- [
- 'ar_rev_id' => $ids
+ $archiveQueryInfo = [
+ 'tables' => [ 'archive' ],
+ 'fields' => Revision::selectArchiveFields(),
+ 'conds' => [
+ 'ar_rev_id' => $ids,
],
+ 'options' => [ 'ORDER BY' => 'ar_rev_id DESC' ],
+ 'join_conds' => [],
+ ];
+
+ ChangeTags::modifyDisplayQuery(
+ $archiveQueryInfo['tables'],
+ $archiveQueryInfo['fields'],
+ $archiveQueryInfo['conds'],
+ $archiveQueryInfo['join_conds'],
+ $archiveQueryInfo['options'],
+ ''
+ );
+
+ // Check if any requested revisions are available fully deleted.
+ $archived = $db->select(
+ $archiveQueryInfo['tables'],
+ $archiveQueryInfo['fields'],
+ $archiveQueryInfo['conds'],
__METHOD__,
- [ 'ORDER BY' => 'ar_rev_id DESC' ]
+ $archiveQueryInfo['options'],
+ $archiveQueryInfo['join_conds']
);
if ( $archived->numRows() == 0 ) {
/** @var array Feature values */
protected $features = [];
+ /** @const string profile type for completionSearch */
+ const COMPLETION_PROFILE_TYPE = 'completionSearchProfile';
+
+ /** @const string profile type for query independent ranking features */
+ const FT_QUERY_INDEP_PROFILE_TYPE = 'fulltextQueryIndepProfile';
+
/**
* Perform a full text search query and return a result set.
* If full text searches are not supported or disabled, return null.
return MediaWikiServices::getInstance()->getSearchEngineConfig()->getSearchTypes();
}
+ /**
+ * Get a list of supported profiles.
+ * Some search engine implementations may expose specific profiles to fine-tune
+ * its behaviors.
+ * The profile can be passed as a feature data with setFeatureData( $profileType, $profileName )
+ * The array returned by this function contains the following keys:
+ * - name: the profile name to use with setFeatureData
+ * - desc-message: the i18n description
+ * - default: set to true if this profile is the default
+ *
+ * @since 1.28
+ * @param $profileType the type of profiles
+ * @return array|null the list of profiles or null if none available
+ */
+ public function getProfiles( $profileType ) {
+ return null;
+ }
+
}
/**
[ 'prefix' => '' ] + $options
);
- $extendedCookies = $this->config->get( 'ExtendedLoginCookies' );
- $extendedExpiry = $this->config->get( 'ExtendedLoginCookieExpiration' );
-
foreach ( $cookies as $key => $value ) {
if ( $value === false ) {
$response->clearCookie( $key, $options );
} else {
- if ( $extendedExpiry !== null && in_array( $key, $extendedCookies ) ) {
- $expiry = time() + (int)$extendedExpiry;
- } else {
- $expiry = 0; // Default cookie expiration
- }
- $response->setCookie( $key, (string)$value, $expiry, $options );
+ $expirationDuration = $this->getLoginCookieExpiration( $key );
+ $expiration = $expirationDuration ? $expirationDuration + time() : null;
+ $response->setCookie( $key, (string)$value, $expiration, $options );
}
}
) {
$response = $request->response();
if ( $set ) {
- $response->setCookie( 'forceHTTPS', 'true', $backend->shouldRememberUser() ? 0 : null,
+ if ( $backend->shouldRememberUser() ) {
+ $expirationDuration = $this->getLoginCookieExpiration( 'forceHTTPS' );
+ $expiration = $expirationDuration ? $expirationDuration + time() : null;
+ } else {
+ $expiration = null;
+ }
+ $response->setCookie( 'forceHTTPS', 'true', $expiration,
[ 'prefix' => '', 'secure' => false ] + $this->cookieOptions );
} else {
$response->clearCookie( 'forceHTTPS',
return wfMessage( 'sessionprovider-nocookies' );
}
+ public function getRememberUserDuration() {
+ return min( $this->getLoginCookieExpiration( 'UserID' ),
+ $this->getLoginCookieExpiration( 'Token' ) ) ?: null;
+ }
+
+ /**
+ * Returns the lifespan of the login cookies, in seconds. 0 means until the end of the session.
+ * @param string $cookieName
+ * @return int Cookie expiration time in seconds; 0 for session cookies
+ */
+ protected function getLoginCookieExpiration( $cookieName ) {
+ $normalExpiration = $this->config->get( 'CookieExpiration' );
+ $extendedExpiration = $this->config->get( 'ExtendedLoginCookieExpiration' );
+ $extendedCookies = $this->config->get( 'ExtendedLoginCookies' );
+
+ if ( !in_array( $cookieName, $extendedCookies, true ) ) {
+ return (int)$normalExpiration;
+ }
+ return ( $extendedExpiration !== null ) ? (int)$extendedExpiration : (int)$normalExpiration;
+ }
}
$options = $this->sessionCookieOptions;
if ( $session->shouldForceHTTPS() || $session->getUser()->requiresHTTPS() ) {
- $response->setCookie( 'forceHTTPS', 'true', $session->shouldRememberUser() ? 0 : null,
+ $response->setCookie( 'forceHTTPS', 'true', null,
[ 'prefix' => '', 'secure' => false ] + $options );
$options['secure'] = true;
}
* @return string[] Encryption key, HMAC key
*/
private function getSecretKeys() {
- global $wgSessionSecret, $wgSecretKey;
+ global $wgSessionSecret, $wgSecretKey, $wgSessionPbkdf2Iterations;
$wikiSecret = $wgSessionSecret ?: $wgSecretKey;
$userSecret = $this->get( 'wsSessionSecret', null );
$userSecret = \MWCryptRand::generateHex( 32 );
$this->set( 'wsSessionSecret', $userSecret );
}
+ $iterations = $this->get( 'wsSessionPbkdf2Iterations', null );
+ if ( $iterations === null ) {
+ $iterations = $wgSessionPbkdf2Iterations;
+ $this->set( 'wsSessionPbkdf2Iterations', $iterations );
+ }
- $keymats = hash_pbkdf2( 'sha256', $wikiSecret, $userSecret, 10001, 64, true );
+ $keymats = hash_pbkdf2( 'sha256', $wikiSecret, $userSecret, $iterations, 64, true );
return [
substr( $keymats, 0, 32 ),
substr( $keymats, 32, 32 ),
];
}
+ /**
+ * Decide what type of encryption to use, based on system capabilities.
+ * @return array
+ */
+ private function getEncryptionAlgorithm() {
+ global $wgSessionInsecureSecrets;
+
+ if (
+ function_exists( 'openssl_encrypt' )
+ && in_array( 'aes-256-ctr', openssl_get_cipher_methods(), true )
+ ) {
+ return [ 'openssl', 'aes-256-ctr' ];
+ } elseif (
+ function_exists( 'mcrypt_encrypt' )
+ && in_array( 'rijndael-128', mcrypt_list_algorithms(), true )
+ && in_array( 'ctr', mcrypt_list_modes(), true )
+ ) {
+ return [ 'mcrypt', 'rijndael-128', 'ctr' ];
+ } elseif ( $wgSessionInsecureSecrets ) {
+ // @todo: import a pure-PHP library for AES instead of this
+ return [ 'insecure' ];
+ } else {
+ throw new \BadMethodCallException(
+ 'Encryption is not available. You really should install the PHP OpenSSL extension, ' .
+ 'or failing that the mcrypt extension. But if you really can\'t and you\'re willing ' .
+ 'to accept insecure storage of sensitive session data, set ' .
+ '$wgSessionInsecureSecrets = true in LocalSettings.php to make this exception go away.'
+ );
+ }
+
+ }
+
/**
* Set a value in the session, encrypted
*
* @param mixed $value
*/
public function setSecret( $key, $value ) {
- global $wgSessionInsecureSecrets;
-
list( $encKey, $hmacKey ) = $this->getSecretKeys();
$serialized = serialize( $value );
// Encrypt
// @todo: import a pure-PHP library for AES instead of doing $wgSessionInsecureSecrets
$iv = \MWCryptRand::generate( 16, true );
- if ( function_exists( 'openssl_encrypt' ) ) {
- $ciphertext = openssl_encrypt( $serialized, 'aes-256-ctr', $encKey, OPENSSL_RAW_DATA, $iv );
- if ( $ciphertext === false ) {
- throw new UnexpectedValueException( 'Encryption failed: ' . openssl_error_string() );
- }
- } elseif ( function_exists( 'mcrypt_encrypt' ) ) {
- $ciphertext = mcrypt_encrypt( 'rijndael-128', $encKey, $serialized, 'ctr', $iv );
- if ( $ciphertext === false ) {
- throw new UnexpectedValueException( 'Encryption failed' );
- }
- } elseif ( $wgSessionInsecureSecrets ) {
- $ex = new \Exception( 'No encryption is available, storing data as plain text' );
- $this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
- $ciphertext = $serialized;
- } else {
- throw new \BadMethodCallException(
- 'Encryption is not available. You really should install the PHP OpenSSL extension, ' .
- 'or failing that the mcrypt extension. But if you really can\'t and you\'re willing ' .
- 'to accept insecure storage of sensitive session data, set ' .
- '$wgSessionInsecureSecrets = true in LocalSettings.php to make this exception go away.'
- );
+ $algorithm = $this->getEncryptionAlgorithm();
+ switch ( $algorithm[0] ) {
+ case 'openssl':
+ $ciphertext = openssl_encrypt( $serialized, $algorithm[1], $encKey, OPENSSL_RAW_DATA, $iv );
+ if ( $ciphertext === false ) {
+ throw new \UnexpectedValueException( 'Encryption failed: ' . openssl_error_string() );
+ }
+ break;
+ case 'mcrypt':
+ $ciphertext = mcrypt_encrypt( $algorithm[1], $encKey, $serialized, $algorithm[2], $iv );
+ if ( $ciphertext === false ) {
+ throw new \UnexpectedValueException( 'Encryption failed' );
+ }
+ break;
+ case 'insecure':
+ $ex = new \Exception( 'No encryption is available, storing data as plain text' );
+ $this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
+ $ciphertext = $serialized;
+ break;
+ default:
+ throw new \LogicException( 'invalid algorithm' );
}
// Seal
* @return mixed
*/
public function getSecret( $key, $default = null ) {
- global $wgSessionInsecureSecrets;
-
// Fetch
$encrypted = $this->get( $key, null );
if ( $encrypted === null ) {
}
// Decrypt
- // @todo: import a pure-PHP library for AES instead of doing $wgSessionInsecureSecrets
- if ( function_exists( 'openssl_decrypt' ) ) {
- $serialized = openssl_decrypt(
- base64_decode( $ciphertext ), 'aes-256-ctr', $encKey, OPENSSL_RAW_DATA, base64_decode( $iv )
- );
- if ( $serialized === false ) {
- $ex = new \Exception( 'Decyption failed: ' . openssl_error_string() );
- $this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
- return $default;
- }
- } elseif ( function_exists( 'mcrypt_decrypt' ) ) {
- $serialized = mcrypt_decrypt(
- 'rijndael-128', $encKey, base64_decode( $ciphertext ), 'ctr', base64_decode( $iv )
- );
- if ( $serialized === false ) {
- $ex = new \Exception( 'Decyption failed' );
- $this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
- return $default;
- }
- } elseif ( $wgSessionInsecureSecrets ) {
- $ex = new \Exception(
- 'No encryption is available, retrieving data that was stored as plain text'
- );
- $this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
- $serialized = base64_decode( $ciphertext );
- } else {
- throw new \BadMethodCallException(
- 'Encryption is not available. You really should install the PHP OpenSSL extension, ' .
- 'or failing that the mcrypt extension. But if you really can\'t and you\'re willing ' .
- 'to accept insecure storage of sensitive session data, set ' .
- '$wgSessionInsecureSecrets = true in LocalSettings.php to make this exception go away.'
- );
+ $algorithm = $this->getEncryptionAlgorithm();
+ switch ( $algorithm[0] ) {
+ case 'openssl':
+ $serialized = openssl_decrypt( base64_decode( $ciphertext ), $algorithm[1], $encKey,
+ OPENSSL_RAW_DATA, base64_decode( $iv ) );
+ if ( $serialized === false ) {
+ $ex = new \Exception( 'Decyption failed: ' . openssl_error_string() );
+ $this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
+ return $default;
+ }
+ break;
+ case 'mcrypt':
+ $serialized = mcrypt_decrypt( $algorithm[1], $encKey, base64_decode( $ciphertext ),
+ $algorithm[2], base64_decode( $iv ) );
+ if ( $serialized === false ) {
+ $ex = new \Exception( 'Decyption failed' );
+ $this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
+ return $default;
+ }
+ break;
+ case 'insecure':
+ $ex = new \Exception(
+ 'No encryption is available, retrieving data that was stored as plain text'
+ );
+ $this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
+ $serialized = base64_decode( $ciphertext );
+ break;
+ default:
+ throw new \LogicException( 'invalid algorithm' );
}
$value = unserialize( $serialized );
private $remembered = false;
private $forceHTTPS = false;
private $idIsSafe = false;
+ private $forceUse = false;
/** @var array|null */
private $providerMetadata = null;
* - idIsSafe: (bool) Set true if the 'id' did not come from the user.
* Generally you'll use this from SessionProvider::newEmptySession(),
* and not from any other method.
+ * - forceUse: (bool) Set true if the 'id' is from
+ * SessionProvider::hashToSessionId() to delete conflicting session
+ * store data instead of discarding this SessionInfo. Ignored unless
+ * both 'provider' and 'id' are given.
* - copyFrom: (SessionInfo) SessionInfo to copy other data items from.
*/
public function __construct( $priority, array $data ) {
'forceHTTPS' => $from->forceHTTPS,
'metadata' => $from->providerMetadata,
'idIsSafe' => $from->idIsSafe,
+ 'forceUse' => $from->forceUse,
// @codeCoverageIgnoreStart
];
// @codeCoverageIgnoreEnd
'forceHTTPS' => false,
'metadata' => null,
'idIsSafe' => false,
+ 'forceUse' => false,
// @codeCoverageIgnoreStart
];
// @codeCoverageIgnoreEnd
if ( $data['id'] !== null ) {
$this->id = $data['id'];
$this->idIsSafe = $data['idIsSafe'];
+ $this->forceUse = $data['forceUse'] && $this->provider;
} else {
$this->id = $this->provider->getManager()->generateSessionId();
$this->idIsSafe = true;
+ $this->forceUse = false;
}
$this->priority = (int)$priority;
$this->userInfo = $data['userInfo'];
return $this->idIsSafe;
}
+ /**
+ * Force use of this SessionInfo if validation fails
+ *
+ * The normal behavior is to discard the SessionInfo if validation against
+ * the data stored in the session store fails. If this returns true,
+ * SessionManager will instead delete the session store data so this
+ * SessionInfo may still be used.
+ *
+ * @return bool
+ */
+ final public function forceUse() {
+ return $this->forceUse;
+ }
+
/**
* Return the priority
* @return int
return $this->getSessionFromInfo( $infos[0], $request );
}
+ public function invalidateSessionsForUser( User $user ) {
+ $user->setToken();
+ $user->saveSettings();
+
+ $authUser = \MediaWiki\Auth\AuthManager::callLegacyAuthPlugin( 'getUserInstance', [ &$user ] );
+ if ( $authUser ) {
+ $authUser->resetAuthToken();
+ }
+
+ foreach ( $this->getProviders() as $provider ) {
+ $provider->invalidateSessionsForUser( $user );
+ }
+ }
+
public function getVaryHeaders() {
// @codeCoverageIgnoreStart
if ( defined( 'MW_NO_SESSION' ) && MW_NO_SESSION !== 'warn' ) {
/**
* Auto-create the given user, if necessary
* @private Don't call this yourself. Let Setup.php do it for you at the right time.
- * @note This more properly belongs in AuthManager, but we need it now.
- * When AuthManager comes, this will be deprecated and will pass-through
- * to the corresponding AuthManager method.
+ * @deprecated since 1.27, use MediaWiki\Auth\AuthManager::autoCreateUser instead
* @param User $user User to auto-create
* @return bool Success
*/
public static function autoCreateUser( User $user ) {
- global $wgAuth;
+ global $wgAuth, $wgDisableAuthManager;
+
+ // @codeCoverageIgnoreStart
+ if ( !$wgDisableAuthManager ) {
+ wfDeprecated( __METHOD__, '1.27' );
+ return \MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
+ $user,
+ \MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
+ false
+ )->isGood();
+ }
+ // @codeCoverageIgnoreEnd
$logger = self::singleton()->logger;
$key = wfMemcKey( 'MWSession', $info->getId() );
$blob = $this->store->get( $key );
+ // If we got data from the store and the SessionInfo says to force use,
+ // "fail" means to delete the data from the store and retry. Otherwise,
+ // "fail" is just return false.
+ if ( $info->forceUse() && $blob !== false ) {
+ $failHandler = function () use ( $key, &$info, $request ) {
+ $this->store->delete( $key );
+ return $this->loadSessionInfoFromStore( $info, $request );
+ };
+ } else {
+ $failHandler = function () {
+ return false;
+ };
+ }
+
$newParams = [];
if ( $blob !== false ) {
'session' => $info,
] );
$this->store->delete( $key );
- return false;
+ return $failHandler();
}
// Sanity check: blob has data and metadata arrays
'session' => $info,
] );
$this->store->delete( $key );
- return false;
+ return $failHandler();
}
$data = $blob['data'];
'session' => $info,
] );
$this->store->delete( $key );
- return false;
+ return $failHandler();
}
// First, load the provider from metadata, or validate it against the metadata.
]
);
$this->store->delete( $key );
- return false;
+ return $failHandler();
}
} elseif ( $metadata['provider'] !== (string)$provider ) {
$this->logger->warning( 'Session "{session}": Wrong provider ' .
[
'session' => $info,
] );
- return false;
+ return $failHandler();
}
// Load provider metadata from metadata, or validate it against the metadata
'exception' => $ex,
] + $ex->getContext()
);
- return false;
+ return $failHandler();
}
}
}
'session' => $info,
'exception' => $ex,
] );
- return false;
+ return $failHandler();
}
$newParams['userInfo'] = $userInfo;
} else {
'uid_a' => $metadata['userId'],
'uid_b' => $userInfo->getId(),
] );
- return false;
+ return $failHandler();
}
// If the user was renamed, probably best to fail here.
'uname_a' => $metadata['userName'],
'uname_b' => $userInfo->getName(),
] );
- return false;
+ return $failHandler();
}
} elseif ( $metadata['userName'] !== null ) { // Shouldn't happen, but just in case
'uname_a' => $metadata['userName'],
'uname_b' => $userInfo->getName(),
] );
- return false;
+ return $failHandler();
}
} elseif ( !$userInfo->isAnon() ) {
// Metadata specifies an anonymous user, but the passed-in
[
'session' => $info,
] );
- return false;
+ return $failHandler();
}
}
$this->logger->warning( 'Session "{session}": User token mismatch', [
'session' => $info,
] );
- return false;
+ return $failHandler();
}
if ( !$userInfo->isVerified() ) {
$newParams['userInfo'] = $userInfo->verified();
[
'session' => $info,
] );
- return false;
+ return $failHandler();
}
// If no user was provided and no metadata, it must be anon.
[
'session' => $info,
] );
- return false;
+ return $failHandler();
}
} elseif ( !$info->getUserInfo()->isVerified() ) {
$this->logger->warning(
[
'session' => $info,
] );
- return false;
+ return $failHandler();
}
$data = false;
// Allow the provider to check the loaded SessionInfo
$providerMetadata = $info->getProviderMetadata();
if ( !$info->getProvider()->refreshSessionInfo( $info, $request, $providerMetadata ) ) {
- return false;
+ return $failHandler();
}
if ( $providerMetadata !== $info->getProviderMetadata() ) {
$info = new SessionInfo( $info->getPriority(), [
$this->logger->warning( 'Session "{session}": ' . $reason, [
'session' => $info,
] );
- return false;
+ return $failHandler();
}
return true;
*/
public function generateSessionId() {
do {
- $id = wfBaseConvert( \MWCryptRand::generateHex( 40 ), 16, 32, 32 );
+ $id = \Wikimedia\base_convert( \MWCryptRand::generateHex( 40 ), 16, 32, 32 );
$key = wfMemcKey( 'MWSession', $id );
} while ( isset( $this->allSessionIds[$id] ) || is_array( $this->store->get( $key ) ) );
return $id;
namespace MediaWiki\Session;
use Psr\Log\LoggerAwareInterface;
+use User;
use WebRequest;
/**
*/
public function getEmptySession( WebRequest $request = null );
+ /**
+ * Invalidate sessions for a user
+ *
+ * After calling this, existing sessions should be invalid. For mutable
+ * session providers, this generally means the user has to log in again;
+ * for immutable providers, it generally means the loss of session data.
+ *
+ * @param User $user
+ */
+ public function invalidateSessionsForUser( User $user );
+
/**
* Return the HTTP headers that need varying on.
*
use Psr\Log\LoggerInterface;
use Config;
use Language;
+use User;
use WebRequest;
/**
*/
abstract public function canChangeUser();
+ /**
+ * Returns the duration (in seconds) for which users will be remembered when
+ * Session::setRememberUser() is set. Null means setting the remember flag will
+ * have no effect (and endpoints should not offer that option).
+ * @return int|null
+ */
+ public function getRememberUserDuration() {
+ return null;
+ }
+
/**
* Notification that the session ID was reset
*
}
}
+ /**
+ * Invalidate existing sessions for a user
+ *
+ * If the provider has its own equivalent of CookieSessionProvider's Token
+ * cookie (and doesn't use User::getToken() to implement it), it should
+ * reset whatever token it does use here.
+ *
+ * @protected For use by \MediaWiki\Session\SessionManager only
+ * @param User $user;
+ */
+ public function invalidateSessionsForUser( User $user ) {
+ }
+
/**
* Return the HTTP headers that need varying on.
*
*
* Generally this will only be used when self::persistsSessionId() is false and
* the provider has to base the session ID on the verified user's identity
- * or other static data.
+ * or other static data. The SessionInfo should then typically have the
+ * 'forceUse' flag set to avoid persistent session failure if validation of
+ * the stored data fails.
*
* @param string $data
* @param string|null $key Defaults to $this->config->get( 'SecretKey' )
// @codeCoverageIgnoreEnd
}
if ( strlen( $hash ) >= 40 ) {
- $hash = wfBaseConvert( $hash, 16, 32, 32 );
+ $hash = \Wikimedia\base_convert( $hash, 16, 32, 32 );
}
return substr( $hash, -32 );
}
public function linkKnown(
$target,
$html = null,
- $customAttribs = [ ],
- $query = [ ],
+ $customAttribs = [],
+ $query = [],
$options = [ 'known', 'noclasses' ]
) {
wfDeprecated( __METHOD__, '1.21' );
$loginlink = $this->getUser()->isAllowed( 'createaccount' ) && $useCombinedLoginLink
? 'nav-login-createaccount'
: 'pt-login';
- $is_signup = $request->getText( 'type' ) == 'signup';
- $login_url = [
- 'text' => $this->msg( $loginlink )->text(),
- 'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
- 'active' => $title->isSpecial( 'Userlogin' )
- && ( $loginlink == 'nav-login-createaccount' || !$is_signup ),
- ];
- $createaccount_url = [
- 'text' => $this->msg( 'pt-createaccount' )->text(),
- 'href' => self::makeSpecialUrl( 'Userlogin', "$returnto&type=signup" ),
- 'active' => $title->isSpecial( 'Userlogin' ) && $is_signup,
- ];
+ // TODO remove this after AuthManager is stable
+ global $wgDisableAuthManager;
+ if ( $wgDisableAuthManager ) {
+ $is_signup = $request->getText( 'type' ) == 'signup';
+ $login_url = [
+ 'text' => $this->msg( $loginlink )->text(),
+ 'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
+ 'active' => $title->isSpecial( 'Userlogin' )
+ && ( $loginlink == 'nav-login-createaccount' || !$is_signup ),
+ ];
+ $createaccount_url = [
+ 'text' => $this->msg( 'pt-createaccount' )->text(),
+ 'href' => self::makeSpecialUrl( 'Userlogin', "$returnto&type=signup" ),
+ 'active' => $title->isSpecial( 'Userlogin' ) && $is_signup,
+ ];
+ } else {
+ $login_url = [
+ 'text' => $this->msg( $loginlink )->text(),
+ 'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
+ 'active' => $title->isSpecial( 'Userlogin' ) ||
+ $title->isSpecial( 'CreateAccount' ) && $useCombinedLoginLink,
+ ];
+ $createaccount_url = [
+ 'text' => $this->msg( 'pt-createaccount' )->text(),
+ 'href' => self::makeSpecialUrl( 'CreateAccount', $returnto ),
+ 'active' => $title->isSpecial( 'CreateAccount' ),
+ ];
+ }
// 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'] = [
- 'text' => $this->msg( 'notloggedin' )->text()
- ];
-
// 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
--- /dev/null
+<?php
+
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\Session\SessionManager;
+use MediaWiki\Session\Token;
+
+/**
+ * A special page subclass for authentication-related special pages. It generates a form from
+ * a set of AuthenticationRequest objects, submits the result to AuthManager and
+ * partially handles the response.
+ */
+abstract class AuthManagerSpecialPage extends SpecialPage {
+ /** @var string[] The list of actions this special page deals with. Subclasses should override
+ * this. */
+ protected static $allowedActions = [
+ AuthManager::ACTION_LOGIN, AuthManager::ACTION_LOGIN_CONTINUE,
+ AuthManager::ACTION_CREATE, AuthManager::ACTION_CREATE_CONTINUE,
+ AuthManager::ACTION_LINK, AuthManager::ACTION_LINK_CONTINUE,
+ AuthManager::ACTION_CHANGE, AuthManager::ACTION_REMOVE, AuthManager::ACTION_UNLINK,
+ ];
+
+ /** @var array Customized messages */
+ protected static $messages = [];
+
+ /** @var string one of the AuthManager::ACTION_* constants. */
+ protected $authAction;
+
+ /** @var AuthenticationRequest[] */
+ protected $authRequests;
+
+ /** @var string Subpage of the special page. */
+ protected $subPage;
+
+ /** @var bool True if the current request is a result of returning from a redirect flow. */
+ protected $isReturn;
+
+ /** @var WebRequest|null If set, will be used instead of the real request. Used for redirection. */
+ protected $savedRequest;
+
+ /**
+ * Change the form descriptor that determines how a field will look in the authentication form.
+ * Called from fieldInfoToFormDescriptor().
+ * @param AuthenticationRequest[] $requests
+ * @param string $fieldInfo Field information array (union of all
+ * AuthenticationRequest::getFieldInfo() responses).
+ * @param array $formDescriptor HTMLForm descriptor. The special key 'weight' can be set to
+ * change the order of the fields.
+ * @param string $action Authentication type (one of the AuthManager::ACTION_* constants)
+ * @return bool
+ */
+ public function onAuthChangeFormFields(
+ array $requests, array $fieldInfo, array &$formDescriptor, $action
+ ) {
+ return true;
+ }
+
+ protected function getLoginSecurityLevel() {
+ return $this->getName();
+ }
+
+ public function getRequest() {
+ return $this->savedRequest ?: $this->getContext()->getRequest();
+ }
+
+ /**
+ * Override the POST data, GET data from the real request is preserved.
+ *
+ * Used to preserve POST data over a HTTP redirect.
+ *
+ * @param array $data
+ * @param bool $wasPosted
+ */
+ protected function setRequest( array $data, $wasPosted = null ) {
+ $request = $this->getContext()->getRequest();
+ if ( $wasPosted === null ) {
+ $wasPosted = $request->wasPosted();
+ }
+ $this->savedRequest = new DerivativeRequest( $request, $data + $request->getQueryValues(),
+ $wasPosted );
+ }
+
+ protected function beforeExecute( $subPage ) {
+ $this->getOutput()->disallowUserJs();
+
+ return $this->handleReturnBeforeExecute( $subPage )
+ && $this->handleReauthBeforeExecute( $subPage );
+ }
+
+ /**
+ * Handle redirection from the /return subpage.
+ *
+ * This is used in the redirect flow where we need
+ * to be able to process data that was sent via a GET request. We set the /return subpage as
+ * the reentry point so we know we need to treat GET as POST, but we don't want to handle all
+ * future GETs as POSTs so we need to normalize the URL. (Also we don't want to show any
+ * received parameters around in the URL; they are ugly and might be sensitive.)
+ *
+ * Thus when on the /return subpage, we stash the request data in the session, redirect, then
+ * use the session to detect that we have been redirected, recover the data and replace the
+ * real WebRequest with a fake one that contains the saved data.
+ *
+ * @param string $subPage
+ * @return bool False if execution should be stopped.
+ */
+ protected function handleReturnBeforeExecute( $subPage ) {
+ $authManager = AuthManager::singleton();
+ $key = 'AuthManagerSpecialPage:return:' . $this->getName();
+
+ if ( $subPage === 'return' ) {
+ $this->loadAuth( $subPage );
+ $preservedParams = $this->getPreservedParams( false );
+
+ // FIXME save POST values only from request
+ $authData = array_diff_key( $this->getRequest()->getValues(),
+ $preservedParams, [ 'title' => 1 ] );
+ $authManager->setAuthenticationSessionData( $key, $authData );
+
+ $url = $this->getPageTitle()->getFullURL( $preservedParams, false, PROTO_HTTPS );
+ $this->getOutput()->redirect( $url );
+ return false;
+ }
+
+ $authData = $authManager->getAuthenticationSessionData( $key );
+ if ( $authData ) {
+ $authManager->removeAuthenticationSessionData( $key );
+ $this->isReturn = true;
+ $this->setRequest( $authData, true );
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle redirection when the user needs to (re)authenticate.
+ *
+ * Send the user to the login form if needed; in case the request was a POST, stash in the
+ * session and simulate it once the user gets back.
+ *
+ * @param string $subPage
+ * @return bool False if execution should be stopped.
+ * @throws ErrorPageError When the user is not allowed to use this page.
+ */
+ protected function handleReauthBeforeExecute( $subPage ) {
+ $authManager = AuthManager::singleton();
+ $request = $this->getRequest();
+ $key = 'AuthManagerSpecialPage:reauth:' . $this->getName();
+
+ $securityLevel = $this->getLoginSecurityLevel();
+ if ( $securityLevel ) {
+ $securityStatus = AuthManager::singleton()
+ ->securitySensitiveOperationStatus( $securityLevel );
+ if ( $securityStatus === AuthManager::SEC_REAUTH ) {
+ $queryParams = array_diff_key( $request->getQueryValues(), [ 'title' => true ] );
+
+ if ( $request->wasPosted() ) {
+ // unique ID in case the same special page is open in multiple browser tabs
+ $uniqueId = MWCryptRand::generateHex( 6 );
+ $key = $key . ':' . $uniqueId;
+
+ $queryParams = [ 'authUniqueId' => $uniqueId ] + $queryParams;
+ $authData = array_diff_key( $request->getValues(),
+ $this->getPreservedParams( false ), [ 'title' => 1 ] );
+ $authManager->setAuthenticationSessionData( $key, $authData );
+ }
+
+ $title = SpecialPage::getTitleFor( 'Userlogin' );
+ $url = $title->getFullURL( [
+ 'returnto' => $this->getFullTitle()->getPrefixedDBkey(),
+ 'returntoquery' => wfArrayToCgi( $queryParams ),
+ 'force' => $securityLevel,
+ ], false, PROTO_HTTPS );
+
+ $this->getOutput()->redirect( $url );
+ return false;
+ } elseif ( $securityStatus !== AuthManager::SEC_OK ) {
+ throw new ErrorPageError( 'cannotauth-not-allowed-title', 'cannotauth-not-allowed' );
+ }
+ }
+
+ $uniqueId = $request->getVal( 'authUniqueId' );
+ if ( $uniqueId ) {
+ $key = $key . ':' . $uniqueId;
+ $authData = $authManager->getAuthenticationSessionData( $key );
+ if ( $authData ) {
+ $authManager->removeAuthenticationSessionData( $key );
+ $this->setRequest( $authData, true );
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the default action for this special page, if none is given via URL/POST data.
+ * Subclasses should override this (or override loadAuth() so this is never called).
+ * @param string $subPage Subpage of the special page.
+ * @return string an AuthManager::ACTION_* constant.
+ */
+ protected function getDefaultAction( $subPage ) {
+ throw new BadMethodCallException( 'Subclass did not implement getDefaultAction' );
+ }
+
+ /**
+ * Return custom message key.
+ * Allows subclasses to customize messages.
+ * @return string
+ */
+ protected function messageKey( $defaultKey ) {
+ return array_key_exists( $defaultKey, static::$messages )
+ ? static::$messages[$defaultKey] : $defaultKey;
+ }
+
+ /**
+ * Allows blacklisting certain request types.
+ * @return array A list of AuthenticationRequest subclass names
+ */
+ protected function getRequestBlacklist() {
+ return [];
+ }
+
+ /**
+ * Load or initialize $authAction, $authRequests and $subPage.
+ * Subclasses should call this from execute() or otherwise ensure the variables are initialized.
+ * @param string $subPage Subpage of the special page.
+ * @param string $authAction Override auth action specified in request (this is useful
+ * when the form needs to be changed from <action> to <action>_CONTINUE after a successful
+ * authentication step)
+ * @param bool $reset Regenerate the requests even if a cached version is available
+ */
+ protected function loadAuth( $subPage, $authAction = null, $reset = false ) {
+ // Do not load if already loaded, to cut down on the number of getAuthenticationRequests
+ // calls. This is important for requests which have hidden information so any
+ // getAuthenticationRequests call would mean putting data into some cache.
+ if (
+ !$reset && $this->subPage === $subPage && $this->authAction
+ && ( !$authAction || $authAction === $this->authAction )
+ ) {
+ return;
+ }
+
+ $request = $this->getRequest();
+ $this->subPage = $subPage;
+ $this->authAction = $authAction ?: $request->getText( 'authAction' );
+ if ( !in_array( $this->authAction, static::$allowedActions, true ) ) {
+ $this->authAction = $this->getDefaultAction( $subPage );
+ if ( $request->wasPosted() ) {
+ $continueAction = $this->getContinueAction( $this->authAction );
+ if ( in_array( $continueAction, static::$allowedActions, true ) ) {
+ $this->authAction = $continueAction;
+ }
+ }
+ }
+
+ $allReqs = AuthManager::singleton()->getAuthenticationRequests(
+ $this->authAction, $this->getUser() );
+ $this->authRequests = array_filter( $allReqs, function ( $req ) use ( $subPage ) {
+ return !in_array( get_class( $req ), $this->getRequestBlacklist(), true );
+ } );
+ }
+
+ /**
+ * Returns true if this is not the first step of the authentication.
+ * @return bool
+ */
+ protected function isContinued() {
+ return in_array( $this->authAction, [
+ AuthManager::ACTION_LOGIN_CONTINUE,
+ AuthManager::ACTION_CREATE_CONTINUE,
+ AuthManager::ACTION_LINK_CONTINUE,
+ ], true );
+ }
+
+ /**
+ * Gets the _CONTINUE version of an action.
+ * @param string $action An AuthManager::ACTION_* constant.
+ * @return string An AuthManager::ACTION_*_CONTINUE constant.
+ */
+ protected function getContinueAction( $action ) {
+ switch ( $action ) {
+ case AuthManager::ACTION_LOGIN:
+ $action = AuthManager::ACTION_LOGIN_CONTINUE;
+ break;
+ case AuthManager::ACTION_CREATE:
+ $action = AuthManager::ACTION_CREATE_CONTINUE;
+ break;
+ case AuthManager::ACTION_LINK:
+ $action = AuthManager::ACTION_LINK_CONTINUE;
+ break;
+ }
+ return $action;
+ }
+
+ /**
+ * Checks whether AuthManager is ready to perform the action.
+ * ACTION_CHANGE needs special verification (AuthManager::allowsAuthenticationData*) which is
+ * the caller's responsibility.
+ * @param string $action One of the AuthManager::ACTION_* constants in static::$allowedActions
+ * @return bool
+ * @throws LogicException if $action is invalid
+ */
+ protected function isActionAllowed( $action ) {
+ $authManager = AuthManager::singleton();
+ if ( !in_array( $action, static::$allowedActions, true ) ) {
+ throw new InvalidArgumentException( 'invalid action: ' . $action );
+ }
+
+ // calling getAuthenticationRequests can be expensive, avoid if possible
+ $requests = ( $action === $this->authAction ) ? $this->authRequests
+ : $authManager->getAuthenticationRequests( $action );
+ if ( !$requests ) {
+ // no provider supports this action in the current state
+ return false;
+ }
+
+ switch ( $action ) {
+ case AuthManager::ACTION_LOGIN:
+ case AuthManager::ACTION_LOGIN_CONTINUE:
+ return $authManager->canAuthenticateNow();
+ case AuthManager::ACTION_CREATE:
+ case AuthManager::ACTION_CREATE_CONTINUE:
+ return $authManager->canCreateAccounts();
+ case AuthManager::ACTION_LINK:
+ case AuthManager::ACTION_LINK_CONTINUE:
+ return $authManager->canLinkAccounts();
+ case AuthManager::ACTION_CHANGE:
+ case AuthManager::ACTION_REMOVE:
+ case AuthManager::ACTION_UNLINK:
+ return true;
+ default:
+ // should never reach here but makes static code analyzers happy
+ throw new InvalidArgumentException( 'invalid action: ' . $action );
+ }
+ }
+
+ /**
+ * @param string $action One of the AuthManager::ACTION_* constants
+ * @param AuthenticationRequest[] $requests
+ * @return AuthenticationResponse
+ * @throws LogicException if $action is invalid
+ */
+ protected function performAuthenticationStep( $action, array $requests ) {
+ if ( !in_array( $action, static::$allowedActions, true ) ) {
+ throw new InvalidArgumentException( 'invalid action: ' . $action );
+ }
+
+ $authManager = AuthManager::singleton();
+ $returnToUrl = $this->getPageTitle( 'return' )
+ ->getFullURL( $this->getPreservedParams( true ), false, PROTO_HTTPS );
+
+ switch ( $action ) {
+ case AuthManager::ACTION_LOGIN:
+ return $authManager->beginAuthentication( $requests, $returnToUrl );
+ case AuthManager::ACTION_LOGIN_CONTINUE:
+ return $authManager->continueAuthentication( $requests );
+ case AuthManager::ACTION_CREATE:
+ return $authManager->beginAccountCreation( $this->getUser(), $requests,
+ $returnToUrl );
+ case AuthManager::ACTION_CREATE_CONTINUE:
+ return $authManager->continueAccountCreation( $requests );
+ case AuthManager::ACTION_LINK:
+ return $authManager->beginAccountLink( $this->getUser(), $requests, $returnToUrl );
+ case AuthManager::ACTION_LINK_CONTINUE:
+ return $authManager->continueAccountLink( $requests );
+ case AuthManager::ACTION_CHANGE:
+ case AuthManager::ACTION_REMOVE:
+ case AuthManager::ACTION_UNLINK:
+ if ( count( $requests ) > 1 ) {
+ throw new InvalidArgumentException( 'only one auth request can be changed at a time' );
+ } elseif ( !$requests ) {
+ throw new InvalidArgumentException( 'no auth request' );
+ }
+ $req = reset( $requests );
+ $status = $authManager->allowsAuthenticationDataChange( $req );
+ Hooks::run( 'ChangeAuthenticationDataAudit', [ $req, $status ] );
+ if ( !$status->isOK() ) {
+ return AuthenticationResponse::newFail( $status->getMessage() );
+ }
+ $authManager->changeAuthenticationData( $req );
+ return AuthenticationResponse::newPass();
+ default:
+ // should never reach here but makes static code analyzers happy
+ throw new InvalidArgumentException( 'invalid action: ' . $action );
+ }
+ }
+
+ /**
+ * Attempts to do an authentication step with the submitted data.
+ * Subclasses should probably call this from execute().
+ * @return false|Status
+ * - false if there was no submit at all
+ * - a good Status wrapping an AuthenticationResponse if the form submit was successful.
+ * This does not necessarily mean that the authentication itself was successful; see the
+ * response for that.
+ * - a bad Status for form errors.
+ */
+ protected function trySubmit() {
+ $status = false;
+
+ $form = $this->getAuthForm( $this->authRequests, $this->authAction );
+ $form->setSubmitCallback( [ $this, 'handleFormSubmit' ] );
+
+ if ( $this->getRequest()->wasPosted() ) {
+ // handle tokens manually; $form->tryAuthorizedSubmit only works for logged-in users
+ $requestTokenValue = $this->getRequest()->getVal( $this->getTokenName() );
+ $sessionToken = $this->getToken();
+ if ( $sessionToken->wasNew() ) {
+ return Status::newFatal( $this->messageKey( 'authform-newtoken' ) );
+ } elseif ( !$requestTokenValue ) {
+ return Status::newFatal( $this->messageKey( 'authform-notoken' ) );
+ } elseif ( !$sessionToken->match( $requestTokenValue ) ) {
+ return Status::newFatal( $this->messageKey( 'authform-wrongtoken' ) );
+ }
+
+ $form->prepareForm();
+ $status = $form->trySubmit();
+
+ // HTMLForm submit return values are a mess; let's ensure it is false or a Status
+ // FIXME this probably should be in HTMLForm
+ if ( $status === true ) {
+ // not supposed to happen since our submit handler should always return a Status
+ throw new UnexpectedValueException( 'HTMLForm::trySubmit() returned true' );
+ } elseif ( $status === false ) {
+ // form was not submitted; nothing to do
+ } elseif ( $status instanceof Status ) {
+ // already handled by the form; nothing to do
+ } elseif ( $status instanceof StatusValue ) {
+ // in theory not an allowed return type but nothing stops the submit handler from
+ // accidentally returning it so best check and fix
+ $status = Status::wrap( $status );
+ } elseif ( is_string( $status ) ) {
+ $status = Status::newFatal( new RawMessage( '$1', $status ) );
+ } elseif ( is_array( $status ) ) {
+ if ( is_string( reset( $status ) ) ) {
+ $status = call_user_func_array( 'Status::newFatal', $status );
+ } elseif ( is_array( reset( $status ) ) ) {
+ $status = Status::newGood();
+ foreach ( $status as $message ) {
+ call_user_func_array( [ $status, 'fatal' ], $message );
+ }
+ } else {
+ throw new UnexpectedValueException( 'invalid HTMLForm::trySubmit() return value: '
+ . 'first element of array is ' . gettype( reset( $status ) ) );
+ }
+ } else {
+ // not supposed to happen but HTMLForm does not actually verify the return type
+ // from the submit callback; better safe then sorry
+ throw new UnexpectedValueException( 'invalid HTMLForm::trySubmit() return type: '
+ . gettype( $status ) );
+ }
+
+ if ( ( !$status || !$status->isOK() ) && $this->isReturn ) {
+ // This is awkward. There was a form validation error, which means the data was not
+ // passed to AuthManager. Normally we would display the form with an error message,
+ // but for the data we received via the redirect flow that would not be helpful at all.
+ // Let's just submit the data to AuthManager directly instead.
+ LoggerFactory::getInstance( 'authmanager' )
+ ->warning( 'Validation error on return', [ 'data' => $form->mFieldData,
+ 'status' => $status->getWikiText() ] );
+ $status = $this->handleFormSubmit( $form->mFieldData );
+ }
+ }
+
+ $changeActions = [
+ AuthManager::ACTION_CHANGE, AuthManager::ACTION_REMOVE, AuthManager::ACTION_UNLINK
+ ];
+ if ( in_array( $this->authAction, $changeActions, true ) && $status && !$status->isOK() ) {
+ Hooks::run( 'ChangeAuthenticationDataAudit', [ reset( $this->authRequests ), $status ] );
+ }
+
+ return $status;
+ }
+
+ /**
+ * Submit handler callback for HTMLForm
+ * @private
+ * @param $data array Submitted data
+ * @return Status
+ */
+ public function handleFormSubmit( $data ) {
+ $requests = AuthenticationRequest::loadRequestsFromSubmission( $this->authRequests, $data );
+ $response = $this->performAuthenticationStep( $this->authAction, $requests );
+
+ // we can't handle FAIL or similar as failure here since it might require changing the form
+ return Status::newGood( $response );
+ }
+
+ /**
+ * Returns URL query parameters which can be used to reload the page (or leave and return) while
+ * preserving all information that is necessary for authentication to continue. These parameters
+ * will be preserved in the action URL of the form and in the return URL for redirect flow.
+ * @param bool $withToken Include CSRF token
+ * @return array
+ */
+ protected function getPreservedParams( $withToken = false ) {
+ $params = [];
+ if ( $this->authAction !== $this->getDefaultAction( $this->subPage ) ) {
+ $params['authAction'] = $this->getContinueAction( $this->authAction );
+ }
+ if ( $withToken ) {
+ $params[$this->getTokenName()] = $this->getToken()->toString();
+ }
+ return $params;
+ }
+
+ /**
+ * Generates a HTMLForm descriptor array from a set of authentication requests.
+ * @param AuthenticationRequest[] $requests
+ * @param string $action AuthManager action name (one of the AuthManager::ACTION_* constants)
+ * @return array
+ */
+ protected function getAuthFormDescriptor( $requests, $action ) {
+ $fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
+ $formDescriptor = $this->fieldInfoToFormDescriptor( $requests, $fieldInfo, $action );
+
+ $this->addTabIndex( $formDescriptor );
+
+ return $formDescriptor;
+ }
+
+ /**
+ * @param AuthenticationRequest[] $requests
+ * @param string $action AuthManager action name (one of the AuthManager::ACTION_* constants)
+ * @return HTMLForm
+ */
+ protected function getAuthForm( array $requests, $action ) {
+ $formDescriptor = $this->getAuthFormDescriptor( $requests, $action );
+ $context = $this->getContext();
+ if ( $context->getRequest() !== $this->getRequest() ) {
+ // We have overridden the request, need to make sure the form uses that too.
+ $context = new DerivativeContext( $this->getContext() );
+ $context->setRequest( $this->getRequest() );
+ }
+ $form = HTMLForm::factory( 'ooui', $formDescriptor, $context );
+ $form->setAction( $this->getFullTitle()->getFullURL( $this->getPreservedParams() ) );
+ $form->addHiddenField( $this->getTokenName(), $this->getToken()->toString() );
+ $form->addHiddenField( 'authAction', $this->authAction );
+ $form->suppressDefaultSubmit( !$this->needsSubmitButton( $formDescriptor ) );
+
+ return $form;
+ }
+
+ /**
+ * Display the form.
+ * @param false|Status|StatusValue $status A form submit status, as in HTMLForm::trySubmit()
+ */
+ protected function displayForm( $status ) {
+ if ( $status instanceof StatusValue ) {
+ $status = Status::wrap( $status );
+ }
+ $form = $this->getAuthForm( $this->authRequests, $this->authAction );
+ $form->prepareForm()->displayForm( $status );
+ }
+
+ /**
+ * Returns true if the form has fields which take values. If all available providers use the
+ * redirect flow, the form might contain nothing but submit buttons, in which case we should
+ * not add an extra submit button which does nothing.
+ *
+ * @param array $formDescriptor A HTMLForm descriptor
+ * @return bool
+ */
+ protected function needsSubmitButton( $formDescriptor ) {
+ return (bool)array_filter( $formDescriptor, function ( $item ) {
+ $class = false;
+ if ( array_key_exists( 'class', $item ) ) {
+ $class = $item['class'];
+ } elseif ( array_key_exists( 'type', $item ) ) {
+ $class = HTMLForm::$typeMappings[$item['type']];
+ }
+ return !in_array( $class, [ 'HTMLInfoField', 'HTMLSubmitField' ], true );
+ } );
+ }
+
+ /**
+ * Adds a sequential tabindex starting from 1 to all form elements. This way the user can
+ * use the tab key to traverse the form without having to step through all links and such.
+ * @param $formDescriptor
+ */
+ protected function addTabIndex( &$formDescriptor ) {
+ $i = 1;
+ foreach ( $formDescriptor as $field => &$definition ) {
+ $class = false;
+ if ( array_key_exists( 'class', $definition ) ) {
+ $class = $definition['class'];
+ } elseif ( array_key_exists( 'type', $definition ) ) {
+ $class = HTMLForm::$typeMappings[$definition['type']];
+ }
+ if ( $class !== 'HTMLInfoField' ) {
+ $definition['tabindex'] = $i;
+ $i++;
+ }
+ }
+ }
+
+ /**
+ * Returns the CSRF token.
+ * @return Token
+ */
+ protected function getToken() {
+ return $this->getRequest()->getSession()->getToken( 'AuthManagerSpecialPage:'
+ . $this->getName() );
+ }
+
+ /**
+ * Returns the name of the CSRF token (under which it should be found in the POST or GET data).
+ * @return string
+ */
+ protected function getTokenName() {
+ return 'wpAuthToken';
+ }
+
+ /**
+ * Turns a field info array into a form descriptor. Behavior can be modified by the
+ * AuthChangeFormFields hook.
+ * @param AuthenticationRequest[] $requests
+ * @param array $fieldInfo Field information, in the format used by
+ * AuthenticationRequest::getFieldInfo()
+ * @param string $action One of the AuthManager::ACTION_* constants
+ * @return array A form descriptor that can be passed to HTMLForm
+ */
+ protected function fieldInfoToFormDescriptor( array $requests, array $fieldInfo, $action ) {
+ $formDescriptor = [];
+ foreach ( $fieldInfo as $fieldName => $singleFieldInfo ) {
+ $formDescriptor[$fieldName] = self::mapSingleFieldInfo( $singleFieldInfo, $fieldName );
+ }
+
+ $requestSnapshot = serialize( $requests );
+ $this->onAuthChangeFormFields( $requests, $fieldInfo, $formDescriptor, $action );
+ \Hooks::run( 'AuthChangeFormFields', [ $requests, $fieldInfo, &$formDescriptor, $action ] );
+ if ( $requestSnapshot !== serialize( $requests ) ) {
+ LoggerFactory::getInstance( 'authentication' )->warning(
+ 'AuthChangeFormFields hook changed auth requests' );
+ }
+
+ // Process the special 'weight' property, which is a way for AuthChangeFormFields hook
+ // subscribers (who only see one field at a time) to influence ordering.
+ self::sortFormDescriptorFields( $formDescriptor );
+
+ return $formDescriptor;
+ }
+
+ /**
+ * Maps an authentication field configuration for a single field (as returned by
+ * AuthenticationRequest::getFieldInfo()) to a HTMLForm field descriptor.
+ * @param array $singleFieldInfo
+ * @return array
+ */
+ protected static function mapSingleFieldInfo( $singleFieldInfo, $fieldName ) {
+ $type = self::mapFieldInfoTypeToFormDescriptorType( $singleFieldInfo['type'] );
+ $descriptor = [
+ 'type' => $type,
+ // Do not prefix input name with 'wp'. This is important for the redirect flow.
+ 'name' => $fieldName,
+ ];
+
+ if ( $type === 'submit' && isset( $singleFieldInfo['label'] ) ) {
+ $descriptor['default'] = wfMessage( $singleFieldInfo['label'] )->plain();
+ } elseif ( $type !== 'submit' ) {
+ $descriptor += array_filter( [
+ // help-message is omitted as it is usually not really useful for a web interface
+ 'label-message' => self::getField( $singleFieldInfo, 'label' ),
+ ] );
+
+ if ( isset( $singleFieldInfo['options'] ) ) {
+ $descriptor['options'] = array_flip( array_map( function ( $message ) {
+ /** @var $message Message */
+ return $message->parse();
+ }, $singleFieldInfo['options'] ) );
+ }
+
+ if ( isset( $singleFieldInfo['value'] ) ) {
+ $descriptor['default'] = $singleFieldInfo['value'];
+ }
+
+ if ( empty( $singleFieldInfo['optional'] ) ) {
+ $descriptor['required'] = true;
+ }
+ }
+
+ return $descriptor;
+ }
+
+ /**
+ * Sort the fields of a form descriptor by their 'weight' property. (Fields with higher weight
+ * are shown closer to the bottom; weight defaults to 0. Negative weight is allowed.)
+ * Keep order if weights are equal.
+ * @param array $formDescriptor
+ * @return array
+ */
+ protected static function sortFormDescriptorFields( array &$formDescriptor ) {
+ $i = 0;
+ foreach ( $formDescriptor as &$field ) {
+ $field['__index'] = $i++;
+ }
+ uasort( $formDescriptor, function ( $first, $second ) {
+ return self::getField( $first, 'weight', 0 ) - self::getField( $second, 'weight', 0 )
+ ?: $first['__index'] - $second['__index'];
+ } );
+ foreach ( $formDescriptor as &$field ) {
+ unset( $field['__index'] );
+ }
+ }
+
+ /**
+ * Get an array value, or a default if it does not exist.
+ * @param array $array
+ * @param string $fieldName
+ * @param mixed $default
+ * @return mixed
+ */
+ protected static function getField( array $array, $fieldName, $default = null ) {
+ if ( array_key_exists( $fieldName, $array ) ) {
+ return $array[$fieldName];
+ } else {
+ return $default;
+ }
+ }
+
+ /**
+ * Maps AuthenticationRequest::getFieldInfo() types to HTMLForm types
+ * @param string $type
+ * @return string
+ * @throws \LogicException
+ */
+ protected static function mapFieldInfoTypeToFormDescriptorType( $type ) {
+ $map = [
+ 'string' => 'text',
+ 'password' => 'password',
+ 'select' => 'select',
+ 'checkbox' => 'check',
+ 'multiselect' => 'multiselect',
+ 'button' => 'submit',
+ 'hidden' => 'hidden',
+ 'null' => 'info',
+ ];
+ if ( !array_key_exists( $type, $map ) ) {
+ throw new \LogicException( 'invalid field type: ' . $type );
+ }
+ return $map[$type];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Holds shared logic for login and account creation pages.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Auth\Throttler;
+use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\Session\SessionManager;
+use Psr\Log\LogLevel;
+
+/**
+ * Holds shared logic for login and account creation pages.
+ *
+ * @ingroup SpecialPage
+ */
+abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
+ protected $mReturnTo;
+ protected $mPosted;
+ protected $mAction;
+ protected $mLanguage;
+ protected $mReturnToQuery;
+ protected $mToken;
+ protected $mStickHTTPS;
+ protected $mFromHTTP;
+ protected $mEntryError = '';
+ protected $mEntryErrorType = 'error';
+
+ protected $mLoaded = false;
+ protected $mLoadedRequest = false;
+ protected $mSecureLoginUrl;
+
+ /** @var string */
+ protected $securityLevel;
+
+ /** @var bool True if the user if creating an account for someone else. Flag used for internal
+ * communication, only set at the very end. */
+ protected $proxyAccountCreation;
+ /** @var User FIXME another flag for passing data. */
+ protected $targetUser;
+
+ /** @var HTMLForm */
+ protected $authForm;
+
+ /** @var FakeAuthTemplate */
+ protected $fakeTemplate;
+
+ abstract protected function isSignup();
+
+ /**
+ * @param bool $direct True if the action was successful just now; false if that happened
+ * pre-redirection (so this handler was called already)
+ * @param StatusValue|null $extraMessages
+ * @return void
+ */
+ abstract protected function successfulAction( $direct = false, $extraMessages = null );
+
+ /**
+ * Logs to the authmanager-stats channel.
+ * @param bool $success
+ * @param string|null $status Error message key
+ */
+ abstract protected function logAuthResult( $success, $status = null );
+
+ public function __construct( $name ) {
+ global $wgUseMediaWikiUIEverywhere;
+ parent::__construct( $name );
+
+ // Override UseMediaWikiEverywhere to true, to force login and create form to use mw ui
+ $wgUseMediaWikiUIEverywhere = true;
+ }
+
+ protected function setRequest( array $data, $wasPosted = null ) {
+ parent::setRequest( $data, $wasPosted );
+ $this->mLoadedRequest = false;
+ }
+
+ /**
+ * Load basic request parameters for this Special page.
+ * @param $subPage
+ */
+ private function loadRequestParameters( $subPage ) {
+ if ( $this->mLoadedRequest ) {
+ return;
+ }
+ $this->mLoadedRequest = true;
+ $request = $this->getRequest();
+
+ $this->mPosted = $request->wasPosted();
+ $this->mIsReturn = $subPage === 'return';
+ $this->mAction = $request->getVal( 'action' );
+ $this->mFromHTTP = $request->getBool( 'fromhttp', false )
+ || $request->getBool( 'wpFromhttp', false );
+ $this->mStickHTTPS = ( !$this->mFromHTTP && $request->getProtocol() === 'https' )
+ || $request->getBool( 'wpForceHttps', false );
+ $this->mLanguage = $request->getText( 'uselang' );
+ $this->mReturnTo = $request->getVal( 'returnto', '' );
+ $this->mReturnToQuery = $request->getVal( 'returntoquery', '' );
+ }
+
+ /**
+ * Load data from request.
+ * @private
+ * @param string $subPage Subpage of Special:Userlogin
+ */
+ protected function load( $subPage ) {
+ global $wgSecureLogin;
+
+ $this->loadRequestParameters( $subPage );
+ if ( $this->mLoaded ) {
+ return;
+ }
+ $this->mLoaded = true;
+ $request = $this->getRequest();
+
+ $securityLevel = $this->getRequest()->getText( 'force' );
+ if (
+ $securityLevel && AuthManager::singleton()->securitySensitiveOperationStatus(
+ $securityLevel ) === AuthManager::SEC_REAUTH
+ ) {
+ $this->securityLevel = $securityLevel;
+ }
+
+ $this->loadAuth( $subPage );
+
+ $this->mToken = $request->getVal( $this->getTokenName() );
+
+ // Show an error or warning passed on from a previous page
+ $entryError = $this->msg( $request->getVal( 'error', '' ) );
+ $entryWarning = $this->msg( $request->getVal( 'warning', '' ) );
+ // bc: provide login link as a parameter for messages where the translation
+ // was not updated
+ $loginreqlink = Linker::linkKnown(
+ $this->getPageTitle(),
+ $this->msg( 'loginreqlink' )->escaped(),
+ [],
+ [
+ 'returnto' => $this->mReturnTo,
+ 'returntoquery' => $this->mReturnToQuery,
+ 'uselang' => $this->mLanguage,
+ 'fromhttp' => $wgSecureLogin && $this->mFromHTTP ? '1' : null,
+ ]
+ );
+
+ // Only show valid error or warning messages.
+ if ( $entryError->exists()
+ && in_array( $entryError->getKey(), LoginHelper::getValidErrorMessages(), true )
+ ) {
+ $this->mEntryErrorType = 'error';
+ $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
+
+ } elseif ( $entryWarning->exists()
+ && in_array( $entryWarning->getKey(), LoginHelper::getValidErrorMessages(), true )
+ ) {
+ $this->mEntryErrorType = 'warning';
+ $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
+ }
+
+ # 1. When switching accounts, it sucks to get automatically logged out
+ # 2. Do not return to PasswordReset after a successful password change
+ # but goto Wiki start page (Main_Page) instead ( bug 33997 )
+ $returnToTitle = Title::newFromText( $this->mReturnTo );
+ if ( is_object( $returnToTitle )
+ && ( $returnToTitle->isSpecial( 'Userlogout' )
+ || $returnToTitle->isSpecial( 'PasswordReset' ) )
+ ) {
+ $this->mReturnTo = '';
+ $this->mReturnToQuery = '';
+ }
+ }
+
+ protected function getPreservedParams( $withToken = false ) {
+ global $wgSecureLogin;
+
+ $params = parent::getPreservedParams( $withToken );
+ $params += [
+ 'returnto' => $this->mReturnTo ?: null,
+ 'returntoquery' => $this->mReturnToQuery ?: null,
+ ];
+ if ( $wgSecureLogin && !$this->isSignup() ) {
+ $params['fromhttp'] = $this->mFromHTTP ? '1' : null;
+ }
+ return $params;
+ }
+
+ protected function beforeExecute( $subPage ) {
+ // finish initializing the class before processing the request - T135924
+ $this->loadRequestParameters( $subPage );
+ return parent::beforeExecute( $subPage );
+ }
+
+ /**
+ * @param string|null $subPage
+ */
+ public function execute( $subPage ) {
+ $authManager = AuthManager::singleton();
+ $session = SessionManager::getGlobalSession();
+
+ // Session data is used for various things in the authentication process, so we must make
+ // sure a session cookie or some equivalent mechanism is set.
+ $session->persist();
+
+ $this->load( $subPage );
+ $this->setHeaders();
+ $this->checkPermissions();
+
+ // Make sure it's possible to log in
+ if ( !$this->isSignup() && !$session->canSetUser() ) {
+ throw new ErrorPageError( 'cannotloginnow-title', 'cannotloginnow-text', [
+ $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
+ ] );
+ }
+
+ /*
+ * In the case where the user is already logged in, and was redirected to
+ * the login form from a page that requires login, do not show the login
+ * page. The use case scenario for this is when a user opens a large number
+ * of tabs, is redirected to the login page on all of them, and then logs
+ * in on one, expecting all the others to work properly.
+ *
+ * However, do show the form if it was visited intentionally (no 'returnto'
+ * is present). People who often switch between several accounts have grown
+ * accustomed to this behavior.
+ *
+ * Also make an exception when force=<level> is set in the URL, which means the user must
+ * reauthenticate for security reasons.
+ */
+ if ( !$this->isSignup() && !$this->mPosted && !$this->securityLevel &&
+ ( $this->mReturnTo !== '' || $this->mReturnToQuery !== '' ) &&
+ $this->getUser()->isLoggedIn()
+ ) {
+ $this->successfulAction();
+ }
+
+ // If logging in and not on HTTPS, either redirect to it or offer a link.
+ global $wgSecureLogin;
+ if ( $this->getRequest()->getProtocol() !== 'https' ) {
+ $title = $this->getFullTitle();
+ $query = $this->getPreservedParams( false ) + [
+ 'title' => null,
+ ( $this->mEntryErrorType === 'error' ? 'error'
+ : 'warning' ) => $this->mEntryError,
+ ] + $this->getRequest()->getQueryValues();
+ $url = $title->getFullURL( $query, false, PROTO_HTTPS );
+ if ( $wgSecureLogin && !$this->mFromHTTP &&
+ wfCanIPUseHTTPS( $this->getRequest()->getIP() )
+ ) {
+ // Avoid infinite redirect
+ $url = wfAppendQuery( $url, 'fromhttp=1' );
+ $this->getOutput()->redirect( $url );
+ // Since we only do this redir to change proto, always vary
+ $this->getOutput()->addVaryHeader( 'X-Forwarded-Proto' );
+
+ return;
+ } else {
+ // A wiki without HTTPS login support should set $wgServer to
+ // http://somehost, in which case the secure URL generated
+ // above won't actually start with https://
+ if ( substr( $url, 0, 8 ) === 'https://' ) {
+ $this->mSecureLoginUrl = $url;
+ }
+ }
+ }
+
+ if ( !$this->isActionAllowed( $this->authAction ) ) {
+ // FIXME how do we explain this to the user? can we handle session loss better?
+ // messages used: authpage-cannot-login, authpage-cannot-login-continue,
+ // authpage-cannot-create, authpage-cannot-create-continue
+ $this->mainLoginForm( [], 'authpage-cannot-' . $this->authAction );
+ return;
+ }
+
+ $status = $this->trySubmit();
+
+ if ( !$status || !$status->isGood() ) {
+ $this->mainLoginForm( $this->authRequests, $status ? $status->getMessage() : '', 'error' );
+ return;
+ }
+
+ /** @var AuthenticationResponse $response */
+ $response = $status->getValue();
+
+ $returnToUrl = $this->getPageTitle( 'return' )
+ ->getFullURL( $this->getPreservedParams( true ), false, PROTO_HTTPS );
+ switch ( $response->status ) {
+ case AuthenticationResponse::PASS:
+ $this->logAuthResult( true );
+ $this->proxyAccountCreation = $this->isSignup() && !$this->getUser()->isAnon();
+ $this->targetUser = User::newFromName( $response->username );
+
+ if (
+ !$this->proxyAccountCreation
+ && $response->loginRequest
+ && $authManager->canAuthenticateNow()
+ ) {
+ // successful registration; log the user in instantly
+ $response2 = $authManager->beginAuthentication( [ $response->loginRequest ],
+ $returnToUrl );
+ if ( $response2->status !== AuthenticationResponse::PASS ) {
+ LoggerFactory::getInstance( 'login' )
+ ->error( 'Could not log in after account creation' );
+ $this->successfulAction( true, Status::newFatal( 'createacct-loginerror' ) );
+ break;
+ }
+ }
+
+ if ( !$this->proxyAccountCreation ) {
+ // Ensure that the context user is the same as the session user.
+ $this->setSessionUserForCurrentRequest();
+ }
+
+ $this->successfulAction( true );
+ break;
+ case AuthenticationResponse::FAIL:
+ // fall through
+ case AuthenticationResponse::RESTART:
+ unset( $this->authForm );
+ if ( $response->status === AuthenticationResponse::FAIL ) {
+ $action = $this->getDefaultAction( $subPage );
+ $messageType = 'error';
+ } else {
+ $action = $this->getContinueAction( $this->authAction );
+ $messageType = 'warning';
+ }
+ $this->logAuthResult( false, $response->message ? $response->message->getKey() : '-' );
+ $this->loadAuth( $subPage, $action, true );
+ $this->mainLoginForm( $this->authRequests, $response->message, $messageType );
+ break;
+ case AuthenticationResponse::REDIRECT:
+ unset( $this->authForm );
+ $this->getOutput()->redirect( $response->redirectTarget );
+ break;
+ case AuthenticationResponse::UI:
+ unset( $this->authForm );
+ $this->authAction = $this->isSignup() ? AuthManager::ACTION_CREATE_CONTINUE
+ : AuthManager::ACTION_LOGIN_CONTINUE;
+ $this->authRequests = $response->neededRequests;
+ $this->mainLoginForm( $response->neededRequests, $response->message, 'warning' );
+ break;
+ default:
+ throw new LogicException( 'invalid AuthenticationResponse' );
+ }
+ }
+
+ /**
+ * Show the success page.
+ *
+ * @param string $type Condition of return to; see `executeReturnTo`
+ * @param string|Message $title Page's title
+ * @param string $msgname
+ * @param string $injected_html
+ * @param StatusValue|null $extraMessages
+ */
+ protected function showSuccessPage(
+ $type, $title, $msgname, $injected_html, $extraMessages
+ ) {
+ $out = $this->getOutput();
+ $out->setPageTitle( $title );
+ if ( $msgname ) {
+ $out->addWikiMsg( $msgname, wfEscapeWikiText( $this->getUser()->getName() ) );
+ }
+ if ( $extraMessages ) {
+ $extraMessages = Status::wrap( $extraMessages );
+ $out->addWikiText( $extraMessages->getWikiText() );
+ }
+
+ $out->addHTML( $injected_html );
+
+ $helper = new LoginHelper( $this->getContext() );
+ $helper->showReturnToPage( $type, $this->mReturnTo, $this->mReturnToQuery, $this->mStickHTTPS );
+ }
+
+ /**
+ * Add a "return to" link or redirect to it.
+ * Extensions can use this to reuse the "return to" logic after
+ * inject steps (such as redirection) into the login process.
+ *
+ * @param string $type One of the following:
+ * - error: display a return to link ignoring $wgRedirectOnLogin
+ * - signup: display a return to link using $wgRedirectOnLogin if needed
+ * - success: display a return to link using $wgRedirectOnLogin if needed
+ * - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
+ * @param string $returnTo
+ * @param array|string $returnToQuery
+ * @param bool $stickHTTPS Keep redirect link on HTTPS
+ * @since 1.22
+ */
+ public function showReturnToPage(
+ $type, $returnTo = '', $returnToQuery = '', $stickHTTPS = false
+ ) {
+ $helper = new LoginHelper( $this->getContext() );
+ $helper->showReturnToPage( $type, $returnTo, $returnToQuery, $stickHTTPS );
+ }
+
+ /**
+ * Replace some globals to make sure the fact that the user has just been logged in is
+ * reflected in the current request.
+ * @param User $user
+ */
+ protected function setSessionUserForCurrentRequest() {
+ global $wgUser, $wgLang;
+
+ $context = RequestContext::getMain();
+ $localContext = $this->getContext();
+ if ( $context !== $localContext ) {
+ // remove AuthManagerSpecialPage context hack
+ $this->setContext( $context );
+ }
+
+ $user = $context->getRequest()->getSession()->getUser();
+
+ $wgUser = $user;
+ $context->setUser( $user );
+
+ $code = $this->getRequest()->getVal( 'uselang', $user->getOption( 'language' ) );
+ $userLang = Language::factory( $code );
+ $wgLang = $userLang;
+ $context->setLanguage( $userLang );
+ }
+
+ /**
+ * @param AuthenticationRequest[] $requests A list of AuthorizationRequest objects,
+ * used to generate the form fields. An empty array means a fatal error
+ * (authentication cannot continue).
+ * @param string|Message $msg
+ * @param string $msgtype
+ * @throws ErrorPageError
+ * @throws Exception
+ * @throws FatalError
+ * @throws MWException
+ * @throws PermissionsError
+ * @throws ReadOnlyError
+ * @private
+ */
+ protected function mainLoginForm( array $requests, $msg = '', $msgtype = 'error' ) {
+ $titleObj = $this->getPageTitle();
+ $user = $this->getUser();
+ $out = $this->getOutput();
+
+ // FIXME how to handle empty $requests - restart, or no form, just an error message?
+ // no form would be better for no session type errors, restart is better when can* fails.
+ if ( !$requests ) {
+ $this->authAction = $this->getDefaultAction( $this->subPage );
+ $this->authForm = null;
+ $requests = AuthManager::singleton()->getAuthenticationRequests( $this->authAction, $user );
+ }
+
+ // Generic styles and scripts for both login and signup form
+ $out->addModuleStyles( [
+ 'mediawiki.ui',
+ 'mediawiki.ui.button',
+ 'mediawiki.ui.checkbox',
+ 'mediawiki.ui.input',
+ 'mediawiki.special.userlogin.common.styles'
+ ] );
+ if ( $this->isSignup() ) {
+ // XXX hack pending RL or JS parse() support for complex content messages T27349
+ $out->addJsConfigVars( 'wgCreateacctImgcaptchaHelp',
+ $this->msg( 'createacct-imgcaptcha-help' )->parse() );
+
+ // Additional styles and scripts for signup form
+ $out->addModules( [
+ 'mediawiki.special.userlogin.signup.js'
+ ] );
+ $out->addModuleStyles( [
+ 'mediawiki.special.userlogin.signup.styles'
+ ] );
+ } else {
+ // Additional styles for login form
+ $out->addModuleStyles( [
+ 'mediawiki.special.userlogin.login.styles'
+ ] );
+ }
+ $out->disallowUserJs(); // just in case...
+
+ $form = $this->getAuthForm( $requests, $this->authAction, $msg, $msgtype );
+ $form->prepareForm();
+ $formHtml = $form->getHTML( $msg ? Status::newFatal( $msg ) : false );
+
+ $out->addHTML( $this->getPageHtml( $formHtml ) );
+ }
+
+ /**
+ * Add page elements which are outside the form.
+ * FIXME this should probably be a template, but use a sane language (handlebars?)
+ * @param string $formHtml
+ * @return string
+ */
+ protected function getPageHtml( $formHtml ) {
+ global $wgLoginLanguageSelector;
+
+ $loginPrompt = $this->isSignup() ? '' : Html::rawElement( 'div',
+ [ 'id' => 'userloginprompt' ], $this->msg( 'loginprompt' )->parseAsBlock() );
+ $languageLinks = $wgLoginLanguageSelector ? $this->makeLanguageSelector() : '';
+ $signupStartMsg = $this->msg( 'signupstart' );
+ $signupStart = ( $this->isSignup() && !$signupStartMsg->isDisabled() )
+ ? Html::rawElement( 'div', [ 'id' => 'signupstart' ], $signupStartMsg->parseAsBlock() ) : '';
+ if ( $languageLinks ) {
+ $languageLinks = Html::rawElement( 'div', [ 'id' => 'languagelinks' ],
+ Html::rawElement( 'p', [], $languageLinks )
+ );
+ }
+
+ $benefitsContainer = '';
+ if ( $this->isSignup() && $this->showExtraInformation() ) {
+ // messages used:
+ // createacct-benefit-icon1 createacct-benefit-head1 createacct-benefit-body1
+ // createacct-benefit-icon2 createacct-benefit-head2 createacct-benefit-body2
+ // createacct-benefit-icon3 createacct-benefit-head3 createacct-benefit-body3
+ $benefitCount = 3;
+ $benefitList = '';
+ for ( $benefitIdx = 1; $benefitIdx <= $benefitCount; $benefitIdx++ ) {
+ $headUnescaped = $this->msg( "createacct-benefit-head$benefitIdx" )->text();
+ $iconClass = $this->msg( "createacct-benefit-icon$benefitIdx" )->escaped();
+ $benefitList .= Html::rawElement( 'div', [ 'class' => "mw-number-text $iconClass" ],
+ Html::rawElement( 'h3', [],
+ $this->msg( "createacct-benefit-head$benefitIdx" )->escaped()
+ )
+ . Html::rawElement( 'p', [],
+ $this->msg( "createacct-benefit-body$benefitIdx" )->params( $headUnescaped )->escaped()
+ )
+ );
+ }
+ $benefitsContainer = Html::rawElement( 'div', [ 'class' => 'mw-createacct-benefits-container' ],
+ Html::rawElement( 'h2', [], $this->msg( 'createacct-benefit-heading' )->escaped() )
+ . Html::rawElement( 'div', [ 'class' => 'mw-createacct-benefits-list' ],
+ $benefitList
+ )
+ );
+ }
+
+ $html = Html::rawElement( 'div', [ 'class' => 'mw-ui-container' ],
+ $loginPrompt
+ . $languageLinks
+ . $signupStart
+ . Html::rawElement( 'div', [ 'id' => 'userloginForm' ],
+ $formHtml
+ )
+ . $benefitsContainer
+ );
+
+ return $html;
+ }
+
+ /**
+ * Generates a form from the given request.
+ * @param AuthenticationRequest[] $requests
+ * @param string $action AuthManager action name
+ * @param string|Message $msg
+ * @param string $msgType
+ * @return HTMLForm
+ */
+ protected function getAuthForm( array $requests, $action, $msg = '', $msgType = 'error' ) {
+ global $wgSecureLogin, $wgLoginLanguageSelector;
+ // FIXME merge this with parent
+
+ if ( isset( $this->authForm ) ) {
+ return $this->authForm;
+ }
+
+ $usingHTTPS = $this->getRequest()->getProtocol() === 'https';
+
+ // get basic form description from the auth logic
+ $fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
+ $fakeTemplate = $this->getFakeTemplate( $msg, $msgType );
+ $this->fakeTemplate = $fakeTemplate; // FIXME there should be a saner way to pass this to the hook
+ // this will call onAuthChangeFormFields()
+ $formDescriptor = static::fieldInfoToFormDescriptor( $requests, $fieldInfo, $this->authAction );
+ $this->postProcessFormDescriptor( $formDescriptor );
+
+ $context = $this->getContext();
+ if ( $context->getRequest() !== $this->getRequest() ) {
+ // We have overridden the request, need to make sure the form uses that too.
+ $context = new DerivativeContext( $this->getContext() );
+ $context->setRequest( $this->getRequest() );
+ }
+ $form = HTMLForm::factory( 'vform', $formDescriptor, $context );
+
+ $form->addHiddenField( 'authAction', $this->authAction );
+ if ( $wgLoginLanguageSelector ) {
+ $form->addHiddenField( 'uselang', $this->mLanguage );
+ }
+ $form->addHiddenField( 'force', $this->securityLevel );
+ $form->addHiddenField( $this->getTokenName(), $this->getToken()->toString() );
+ if ( $wgSecureLogin ) {
+ // If using HTTPS coming from HTTP, then the 'fromhttp' parameter must be preserved
+ if ( !$this->isSignup() ) {
+ $form->addHiddenField( 'wpForceHttps', (int)$this->mStickHTTPS );
+ $form->addHiddenField( 'wpFromhttp', $usingHTTPS );
+ }
+ }
+
+ // set properties of the form itself
+ $form->setAction( $this->getPageTitle()->getLocalURL( $this->getReturnToQueryStringFragment() ) );
+ $form->setName( 'userlogin' . ( $this->isSignup() ? '2' : '' ) );
+ if ( $this->isSignup() ) {
+ $form->setId( 'userlogin2' );
+ }
+
+ // add pre/post text
+ // header used by ConfirmEdit, CondfirmAccount, Persona, WikimediaIncubator, SemanticSignup
+ // should be above the error message but HTMLForm doesn't support that
+ $form->addHeaderText( $fakeTemplate->html( 'header' ) );
+
+ // FIXME the old form used this for error/warning messages which does not play well with
+ // HTMLForm (maybe it could with a subclass?); for now only display it for signups
+ // (where the JS username validation needs it) and alway empty
+ if ( $this->isSignup() ) {
+ // used by the mediawiki.special.userlogin.signup.js module
+ $statusAreaAttribs = [ 'id' => 'mw-createacct-status-area' ];
+ // $statusAreaAttribs += $msg ? [ 'class' => "{$msgType}box" ] : [ 'style' => 'display: none;' ];
+ $form->addHeaderText( Html::element( 'div', $statusAreaAttribs ) );
+ }
+
+ // header used by MobileFrontend
+ $form->addHeaderText( $fakeTemplate->html( 'formheader' ) );
+
+ // blank signup footer for site customization
+ if ( $this->isSignup() && $this->showExtraInformation() ) {
+ // Use signupend-https for HTTPS requests if it's not blank, signupend otherwise
+ $signupendMsg = $this->msg( 'signupend' );
+ $signupendHttpsMsg = $this->msg( 'signupend-https' );
+ if ( !$signupendMsg->isDisabled() ) {
+ $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
+ ? $signupendHttpsMsg ->parse() : $signupendMsg->parse();
+ $form->addPostText( Html::rawElement( 'div', [ 'id' => 'signupend' ], $signupendText ) );
+ }
+ }
+
+ // warning header for non-standard workflows (e.g. security reauthentication)
+ if ( !$this->isSignup() && $this->getUser()->isLoggedIn() ) {
+ $reauthMessage = $this->securityLevel ? 'userlogin-reauth' : 'userlogin-loggedin';
+ $form->addHeaderText( Html::rawElement( 'div', [ 'class' => 'warningbox' ],
+ $this->msg( $reauthMessage )->params( $this->getUser()->getName() )->parse() ) );
+ }
+
+ if ( !$this->isSignup() && $this->showExtraInformation() ) {
+ $passwordReset = new PasswordReset( $this->getConfig(), AuthManager::singleton() );
+ if ( $passwordReset->isAllowed( $this->getUser() ) ) {
+ $form->addFooterText( Html::rawElement(
+ 'div',
+ [ 'class' => 'mw-ui-vform-field mw-form-related-link-container' ],
+ Linker::link(
+ SpecialPage::getTitleFor( 'PasswordReset' ),
+ $this->msg( 'userlogin-resetpassword-link' )->escaped()
+ )
+ ) );
+ }
+
+ // Don't show a "create account" link if the user can't.
+ if ( $this->showCreateAccountLink() ) {
+ // link to the other action
+ $linkTitle = $this->getTitleFor( $this->isSignup() ? 'Userlogin' :'CreateAccount' );
+ $linkq = $this->getReturnToQueryStringFragment();
+ // Pass any language selection on to the mode switch link
+ if ( $wgLoginLanguageSelector && $this->mLanguage ) {
+ $linkq .= '&uselang=' . $this->mLanguage;
+ }
+
+ $loggedIn = $this->getUser()->isLoggedIn();
+ $createOrLoginHtml = Html::rawElement( 'div',
+ [ 'id' => 'mw-createaccount' . ( !$loggedIn ? '-cta' : '' ),
+ 'class' => ( $loggedIn ? 'mw-form-related-link-container' : 'mw-ui-vform-field' ) ],
+ ( $loggedIn ? '' : $this->msg( 'userlogin-noaccount' )->escaped() )
+ . Html::element( 'a',
+ [
+ 'id' => 'mw-createaccount-join' . ( $loggedIn ? '-loggedin' : '' ),
+ 'href' => $linkTitle->getLocalURL( $linkq ),
+ 'class' => ( $loggedIn ? '' : 'mw-ui-button' ),
+ 'tabindex' => 100,
+ ],
+ $this->msg(
+ ( $this->getUser()->isLoggedIn() ?
+ 'userlogin-createanother' :
+ 'userlogin-joinproject'
+ ) )->escaped()
+ )
+ );
+ $form->addFooterText( $createOrLoginHtml );
+ }
+ }
+
+ $form->suppressDefaultSubmit();
+
+ $this->authForm = $form;
+
+ return $form;
+ }
+
+ /**
+ * Temporary B/C method to handle extensions using the UserLoginForm/UserCreateForm hooks.
+ * @param string|Message $msg
+ * @param string $msgType
+ * @return FakeAuthTemplate
+ */
+ protected function getFakeTemplate( $msg, $msgType ) {
+ global $wgAuth, $wgEnableEmail, $wgHiddenPrefs, $wgEmailConfirmToEdit, $wgEnableUserEmail,
+ $wgSecureLogin, $wgLoginLanguageSelector, $wgPasswordResetRoutes;
+
+ // make a best effort to get the value of fields which used to be fixed in the old login
+ // template but now might or might not exist depending on what providers are used
+ $request = $this->getRequest();
+ $data = (object) [
+ 'mUsername' => $request->getText( 'wpName' ),
+ 'mPassword' => $request->getText( 'wpPassword' ),
+ 'mRetype' => $request->getText( 'wpRetype' ),
+ 'mEmail' => $request->getText( 'wpEmail' ),
+ 'mRealName' => $request->getText( 'wpRealName' ),
+ 'mDomain' => $request->getText( 'wpDomain' ),
+ 'mReason' => $request->getText( 'wpReason' ),
+ 'mRemember' => $request->getCheck( 'wpRemember' ),
+ ];
+
+ // Preserves a bunch of logic from the old code that was rewritten in getAuthForm().
+ // There is no code reuse to make this easier to remove .
+ // If an extension tries to change any of these values, they are out of luck - we only
+ // actually use the domain/usedomain/domainnames, extraInput and extrafields keys.
+
+ $titleObj = $this->getPageTitle();
+ $user = $this->getUser();
+ $template = new FakeAuthTemplate();
+
+ // Pre-fill username (if not creating an account, bug 44775).
+ if ( $data->mUsername == '' && $this->isSignup() ) {
+ if ( $user->isLoggedIn() ) {
+ $data->mUsername = $user->getName();
+ } else {
+ $data->mUsername = $this->getRequest()->getSession()->suggestLoginUsername();
+ }
+ }
+
+ if ( $this->isSignup() ) {
+ // Must match number of benefits defined in messages
+ $template->set( 'benefitCount', 3 );
+
+ $q = 'action=submitlogin&type=signup';
+ $linkq = 'type=login';
+ } else {
+ $q = 'action=submitlogin&type=login';
+ $linkq = 'type=signup';
+ }
+
+ if ( $this->mReturnTo !== '' ) {
+ $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
+ if ( $this->mReturnToQuery !== '' ) {
+ $returnto .= '&returntoquery=' .
+ wfUrlencode( $this->mReturnToQuery );
+ }
+ $q .= $returnto;
+ $linkq .= $returnto;
+ }
+
+ # Don't show a "create account" link if the user can't.
+ if ( $this->showCreateAccountLink() ) {
+ # Pass any language selection on to the mode switch link
+ if ( $wgLoginLanguageSelector && $this->mLanguage ) {
+ $linkq .= '&uselang=' . $this->mLanguage;
+ }
+ // Supply URL, login template creates the button.
+ $template->set( 'createOrLoginHref', $titleObj->getLocalURL( $linkq ) );
+ } else {
+ $template->set( 'link', '' );
+ }
+
+ $resetLink = $this->isSignup()
+ ? null
+ : is_array( $wgPasswordResetRoutes )
+ && in_array( true, array_values( $wgPasswordResetRoutes ), true );
+
+ $template->set( 'header', '' );
+ $template->set( 'formheader', '' );
+ $template->set( 'skin', $this->getSkin() );
+
+ $template->set( 'name', $data->mUsername );
+ $template->set( 'password', $data->mPassword );
+ $template->set( 'retype', $data->mRetype );
+ $template->set( 'createemailset', false ); // no easy way to get that from AuthManager
+ $template->set( 'email', $data->mEmail );
+ $template->set( 'realname', $data->mRealName );
+ $template->set( 'domain', $data->mDomain );
+ $template->set( 'reason', $data->mReason );
+ $template->set( 'remember', $data->mRemember );
+
+ $template->set( 'action', $titleObj->getLocalURL( $q ) );
+ $template->set( 'message', $msg );
+ $template->set( 'messagetype', $msgType );
+ $template->set( 'createemail', $wgEnableEmail && $user->isLoggedIn() );
+ $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs, true ) );
+ $template->set( 'useemail', $wgEnableEmail );
+ $template->set( 'emailrequired', $wgEmailConfirmToEdit );
+ $template->set( 'emailothers', $wgEnableUserEmail );
+ $template->set( 'canreset', $wgAuth->allowPasswordChange() );
+ $template->set( 'resetlink', $resetLink );
+ $template->set( 'canremember', $request->getSession()->getProvider()
+ ->getRememberUserDuration() !== null );
+ $template->set( 'usereason', $user->isLoggedIn() );
+ $template->set( 'cansecurelogin', ( $wgSecureLogin ) );
+ $template->set( 'stickhttps', (int)$this->mStickHTTPS );
+ $template->set( 'loggedin', $user->isLoggedIn() );
+ $template->set( 'loggedinuser', $user->getName() );
+ $template->set( 'token', $this->getToken()->toString() );
+
+ $action = $this->isSignup() ? 'signup' : 'login';
+ $wgAuth->modifyUITemplate( $template, $action );
+
+ $oldTemplate = $template;
+ $hookName = $this->isSignup() ? 'UserCreateForm' : 'UserLoginForm';
+ Hooks::run( $hookName, [ &$template ] );
+ if ( $oldTemplate !== $template ) {
+ wfDeprecated( "reference in $hookName hook", '1.27' );
+ }
+
+ return $template;
+
+ }
+
+ public function onAuthChangeFormFields(
+ array $requests, array $fieldInfo, array &$formDescriptor, $action
+ ) {
+ $coreFieldDescriptors = $this->getFieldDefinitions( $this->fakeTemplate );
+ $specialFields = array_merge( [ 'extraInput', 'linkcontainer', 'entryError' ],
+ array_keys( $this->fakeTemplate->getExtraInputDefinitions() ) );
+
+ // keep the ordering from getCoreFieldDescriptors() where there is no explicit weight
+ foreach ( $coreFieldDescriptors as $fieldName => $coreField ) {
+ $requestField = isset( $formDescriptor[$fieldName] ) ?
+ $formDescriptor[$fieldName] : [];
+
+ // remove everything that is not in the fieldinfo, is not marked as a supplemental field
+ // to something in the fieldinfo, and is not a generic or B/C field or a submit button
+ if (
+ !isset( $fieldInfo[$fieldName] )
+ && (
+ !isset( $coreField['baseField'] )
+ || !isset( $fieldInfo[$coreField['baseField']] )
+ ) && !in_array( $fieldName, $specialFields, true )
+ && $coreField['type'] !== 'submit'
+ ) {
+ $coreFieldDescriptors[$fieldName] = null;
+ continue;
+ }
+
+ // core message labels should always take priority
+ if (
+ isset( $coreField['label'] )
+ || isset( $coreField['label-message'] )
+ || isset( $coreField['label-raw'] )
+ ) {
+ unset( $requestField['label'], $requestField['label-message'], $coreField['label-raw'] );
+ }
+
+ $coreFieldDescriptors[$fieldName] += $requestField;
+ }
+
+ $formDescriptor = array_filter( $coreFieldDescriptors + $formDescriptor );
+ return true;
+ }
+
+ /**
+ * Show extra information such as password recovery information, link from login to signup,
+ * CTA etc? Such information should only be shown on the "landing page", ie. when the user
+ * is at the first step of the authentication process.
+ * @return bool
+ */
+ protected function showExtraInformation() {
+ return $this->authAction !== $this->getContinueAction( $this->authAction )
+ && !$this->securityLevel;
+ }
+
+ /**
+ * Create a HTMLForm descriptor for the core login fields.
+ * @param FakeAuthTemplate $template B/C data (not used but needed by getBCFieldDefinitions)
+ * @return array
+ */
+ protected function getFieldDefinitions( $template ) {
+ global $wgEmailConfirmToEdit;
+
+ $isLoggedIn = $this->getUser()->isLoggedIn();
+ $continuePart = $this->isContinued() ? 'continue-' : '';
+ $anotherPart = $isLoggedIn ? 'another-' : '';
+ $expiration = $this->getRequest()->getSession()->getProvider()
+ ->getRememberUserDuration();
+ $expirationDays = ceil( $expiration / ( 3600 * 24 ) );
+ $secureLoginLink = '';
+ if ( $this->mSecureLoginUrl ) {
+ $secureLoginLink = Html::element( 'a', [
+ 'href' => $this->mSecureLoginUrl,
+ 'class' => 'mw-ui-flush-right mw-secure',
+ ], $this->msg( 'userlogin-signwithsecure' )->text() );
+ }
+
+ if ( $this->isSignup() ) {
+ $fieldDefinitions = [
+ 'username' => [
+ 'label-message' => 'userlogin-yourname',
+ // FIXME help-message does not match old formatting
+ 'help-message' => 'createacct-helpusername',
+ 'id' => 'wpName2',
+ 'placeholder-message' => $isLoggedIn ? 'createacct-another-username-ph'
+ : 'userlogin-yourname-ph',
+ ],
+ 'mailpassword' => [
+ // create account without providing password, a temporary one will be mailed
+ 'type' => 'check',
+ 'label-message' => 'createaccountmail',
+ 'name' => 'wpCreateaccountMail',
+ 'id' => 'wpCreateaccountMail',
+ ],
+ 'password' => [
+ 'id' => 'wpPassword2',
+ 'placeholder-message' => 'createacct-yourpassword-ph',
+ 'hide-if' => [ '===', 'wpCreateaccountMail', '1' ],
+ ],
+ 'domain' => [],
+ 'retype' => [
+ 'baseField' => 'password',
+ 'type' => 'password',
+ 'label-message' => 'createacct-yourpasswordagain',
+ 'id' => 'wpRetype',
+ 'cssclass' => 'loginPassword',
+ 'size' => 20,
+ 'validation-callback' => function ( $value, $alldata ) {
+ if ( empty( $alldata['mailpassword'] ) && !empty( $alldata['password'] ) ) {
+ if ( !$value ) {
+ return $this->msg( 'htmlform-required' );
+ } elseif ( $value !== $alldata['password'] ) {
+ return $this->msg( 'badretype' );
+ }
+ }
+ return true;
+ },
+ 'hide-if' => [ '===', 'wpCreateaccountMail', '1' ],
+ 'placeholder-message' => 'createacct-yourpasswordagain-ph',
+ ],
+ 'email' => [
+ 'type' => 'email',
+ 'label-message' => $wgEmailConfirmToEdit ? 'createacct-emailrequired'
+ : 'createacct-emailoptional',
+ 'id' => 'wpEmail',
+ 'cssclass' => 'loginText',
+ 'size' => '20',
+ // FIXME will break non-standard providers
+ 'required' => $wgEmailConfirmToEdit,
+ 'validation-callback' => function ( $value, $alldata ) {
+ global $wgEmailConfirmToEdit;
+
+ // AuthManager will check most of these, but that will make the auth
+ // session fail and this won't, so nicer to do it this way
+ if ( !$value && $wgEmailConfirmToEdit ) {
+ // no point in allowing registration without email when email is
+ // required to edit
+ return $this->msg( 'noemailtitle' );
+ } elseif ( !$value && !empty( $alldata['mailpassword'] ) ) {
+ // cannot send password via email when there is no email address
+ return $this->msg( 'noemailcreate' );
+ } elseif ( $value && !Sanitizer::validateEmail( $value ) ) {
+ return $this->msg( 'invalidemailaddress' );
+ }
+ return true;
+ },
+ 'placeholder-message' => 'createacct-' . $anotherPart . 'email-ph',
+ ],
+ 'realname' => [
+ 'type' => 'text',
+ 'help-message' => $isLoggedIn ? 'createacct-another-realname-tip'
+ : 'prefs-help-realname',
+ 'label-message' => 'createacct-realname',
+ 'cssclass' => 'loginText',
+ 'size' => 20,
+ 'id' => 'wpRealName',
+ ],
+ 'reason' => [
+ // comment for the user creation log
+ 'type' => 'text',
+ 'label-message' => 'createacct-reason',
+ 'cssclass' => 'loginText',
+ 'id' => 'wpReason',
+ 'size' => '20',
+ 'placeholder-message' => 'createacct-reason-ph',
+ ],
+ 'extrainput' => [], // placeholder for fields coming from the template
+ 'createaccount' => [
+ // submit button
+ 'type' => 'submit',
+ 'default' => $this->msg( 'createacct-' . $anotherPart . $continuePart .
+ 'submit' )->text(),
+ 'name' => 'wpCreateaccount',
+ 'id' => 'wpCreateaccount',
+ 'weight' => 100,
+ ],
+ ];
+ } else {
+ $fieldDefinitions = [
+ 'username' => [
+ 'label-raw' => $this->msg( 'userlogin-yourname' )->escaped() . $secureLoginLink,
+ 'id' => 'wpName1',
+ 'placeholder-message' => 'userlogin-yourname-ph',
+ ],
+ 'password' => [
+ 'id' => 'wpPassword1',
+ 'placeholder-message' => 'userlogin-yourpassword-ph',
+ ],
+ 'domain' => [],
+ 'extrainput' => [],
+ 'rememberMe' => [
+ // option for saving the user token to a cookie
+ 'type' => 'check',
+ 'label-message' => $this->msg( 'userlogin-remembermypassword' )
+ ->numParams( $expirationDays ),
+ 'id' => 'wpRemember',
+ ],
+ 'loginattempt' => [
+ // submit button
+ 'type' => 'submit',
+ 'name' => 'wpRemember',
+ 'default' => $this->msg( 'pt-login-' . $continuePart . 'button' )->text(),
+ 'id' => 'wpLoginAttempt',
+ 'weight' => 100,
+ ],
+ 'linkcontainer' => [
+ // help link
+ 'type' => 'info',
+ 'cssclass' => 'mw-form-related-link-container mw-userlogin-help',
+ // 'id' => 'mw-userlogin-help', // FIXME HTMLInfoField ignores this
+ 'raw' => true,
+ 'default' => Html::element( 'a', [
+ 'href' => Skin::makeInternalOrExternalUrl( wfMessage( 'helplogin-url' )
+ ->inContentLanguage()
+ ->text() ),
+ ], $this->msg( 'userlogin-helplink2' )->text() ),
+ 'weight' => 200,
+ ],
+ ];
+ }
+ $fieldDefinitions['username'] += [
+ 'type' => 'text',
+ 'name' => 'wpName',
+ 'cssclass' => 'loginText',
+ 'size' => 20,
+ // 'required' => true,
+ ];
+ $fieldDefinitions['password'] += [
+ 'type' => 'password',
+ // 'label-message' => 'userlogin-yourpassword', // would override the changepassword label
+ 'name' => 'wpPassword',
+ 'cssclass' => 'loginPassword',
+ 'size' => 20,
+ // 'required' => true,
+ ];
+
+ if ( $this->mEntryError ) {
+ $fieldDefinitions['entryError'] = [
+ 'type' => 'info',
+ 'default' => Html::rawElement( 'div', [ 'class' => $this->mEntryErrorType . 'box', ],
+ $this->mEntryError ),
+ 'raw' => true,
+ 'rawrow' => true,
+ 'weight' => -100,
+ ];
+ }
+
+ if ( !$this->showExtraInformation() ) {
+ unset( $fieldDefinitions['linkcontainer'] );
+ }
+
+ $fieldDefinitions = $this->getBCFieldDefinitions( $fieldDefinitions, $template );
+ $fieldDefinitions = array_filter( $fieldDefinitions );
+
+ return $fieldDefinitions;
+ }
+
+ /**
+ * Adds fields provided via the deprecated UserLoginForm / UserCreateForm hooks
+ * @param $fieldDefinitions array
+ * @param FakeAuthTemplate $template
+ * @return array
+ */
+ protected function getBCFieldDefinitions( $fieldDefinitions, $template ) {
+ if ( $template->get( 'usedomain', false ) ) {
+ // TODO probably should be translated to the new domain notation in AuthManager
+ $fieldDefinitions['domain'] = [
+ 'type' => 'select',
+ 'label-message' => 'yourdomainname',
+ 'options' => array_combine( $template->get( 'domainnames', [] ),
+ $template->get( 'domainnames', [] ) ),
+ 'default' => $template->get( 'domain', '' ),
+ 'name' => 'wpDomain',
+ // FIXME id => 'mw-user-domain-section' on the parent div
+ ];
+ }
+
+ // poor man's associative array_splice
+ $extraInputPos = array_search( 'extrainput', array_keys( $fieldDefinitions ), true );
+ $fieldDefinitions = array_slice( $fieldDefinitions, 0, $extraInputPos, true )
+ + $template->getExtraInputDefinitions()
+ + array_slice( $fieldDefinitions, $extraInputPos + 1, null, true );
+
+ return $fieldDefinitions;
+ }
+
+ /**
+ * Check if a session cookie is present.
+ *
+ * This will not pick up a cookie set during _this_ request, but is meant
+ * to ensure that the client is returning the cookie which was set on a
+ * previous pass through the system.
+ *
+ * @return bool
+ */
+ protected function hasSessionCookie() {
+ global $wgDisableCookieCheck, $wgInitialSessionId;
+
+ return $wgDisableCookieCheck || (
+ $wgInitialSessionId &&
+ $this->getRequest()->getSession()->getId() === (string)$wgInitialSessionId
+ );
+ }
+
+ /**
+ * Returns a string that can be appended to the URL (without encoding) to preserve the
+ * return target. Does not include leading '?'/'&'.
+ */
+ protected function getReturnToQueryStringFragment() {
+ $returnto = '';
+ if ( $this->mReturnTo !== '' ) {
+ $returnto = 'returnto=' . wfUrlencode( $this->mReturnTo );
+ if ( $this->mReturnToQuery !== '' ) {
+ $returnto .= '&returntoquery=' . wfUrlencode( $this->mReturnToQuery );
+ }
+ }
+ return $returnto;
+ }
+
+ /**
+ * Whether the login/create account form should display a link to the
+ * other form (in addition to whatever the skin provides).
+ * @return bool
+ */
+ private function showCreateAccountLink() {
+ if ( $this->isSignup() ) {
+ return true;
+ } elseif ( $this->getUser()->isAllowed( 'createaccount' ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected function getTokenName() {
+ return $this->isSignup() ? 'wpCreateaccountToken' : 'wpLoginToken';
+ }
+
+ /**
+ * Produce a bar of links which allow the user to select another language
+ * during login/registration but retain "returnto"
+ *
+ * @return string
+ */
+ protected function makeLanguageSelector() {
+ $msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage();
+ if ( $msg->isBlank() ) {
+ return '';
+ }
+ $langs = explode( "\n", $msg->text() );
+ $links = [];
+ foreach ( $langs as $lang ) {
+ $lang = trim( $lang, '* ' );
+ $parts = explode( '|', $lang );
+ if ( count( $parts ) >= 2 ) {
+ $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
+ }
+ }
+
+ return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams(
+ $this->getLanguage()->pipeList( $links ) )->escaped() : '';
+ }
+
+ /**
+ * Create a language selector link for a particular language
+ * Links back to this page preserving type and returnto
+ *
+ * @param string $text Link text
+ * @param string $lang Language code
+ * @return string
+ */
+ protected function makeLanguageSelectorLink( $text, $lang ) {
+ if ( $this->getLanguage()->getCode() == $lang ) {
+ // no link for currently used language
+ return htmlspecialchars( $text );
+ }
+ $query = [ 'uselang' => $lang ];
+ if ( $this->mReturnTo !== '' ) {
+ $query['returnto'] = $this->mReturnTo;
+ $query['returntoquery'] = $this->mReturnToQuery;
+ }
+
+ $attr = [];
+ $targetLanguage = Language::factory( $lang );
+ $attr['lang'] = $attr['hreflang'] = $targetLanguage->getHtmlCode();
+
+ return Linker::linkKnown(
+ $this->getPageTitle(),
+ htmlspecialchars( $text ),
+ $attr,
+ $query
+ );
+ }
+
+ protected function getGroupName() {
+ return 'login';
+ }
+
+ /**
+ * @param array $formDescriptor
+ */
+ protected function postProcessFormDescriptor( &$formDescriptor ) {
+ // Pre-fill username (if not creating an account, T46775).
+ if (
+ isset( $formDescriptor['username'] ) &&
+ !isset( $formDescriptor['username']['default'] ) &&
+ !$this->isSignup()
+ ) {
+ $user = $this->getUser();
+ if ( $user->isLoggedIn() ) {
+ $formDescriptor['username']['default'] = $user->getName();
+ } else {
+ $formDescriptor['username']['default'] =
+ $this->getRequest()->getSession()->suggestLoginUsername();
+ }
+ }
+
+ // don't show a submit button if there is nothing to submit (i.e. the only form content
+ // is other submit buttons, for redirect flows)
+ if ( !$this->needsSubmitButton( $formDescriptor ) ) {
+ unset( $formDescriptor['createaccount'], $formDescriptor['loginattempt'] );
+ }
+
+ if ( !$this->isSignup() ) {
+ // FIXME HACK don't focus on non-empty field
+ // maybe there should be an autofocus-if similar to hide-if?
+ if (
+ isset( $formDescriptor['username'] )
+ && empty( $formDescriptor['username']['default'] )
+ && !$this->getRequest()->getCheck( 'wpName' )
+ ) {
+ $formDescriptor['username']['autofocus'] = true;
+ } elseif ( isset( $formDescriptor['password'] ) ) {
+ $formDescriptor['password']['autofocus'] = true;
+ }
+ }
+
+ $this->addTabIndex( $formDescriptor );
+ }
+}
+
+/**
+ * B/C class to try handling login/signup template modifications even though login/signup does not
+ * actually happen through a template anymore. Just collects extra field definitions and allows
+ * some other class to do decide what to do with threm..
+ * TODO find the right place for adding extra fields and kill this
+ */
+class FakeAuthTemplate extends BaseTemplate {
+ public function execute() {
+ throw new LogicException( 'not used' );
+ }
+
+ /**
+ * Extensions (AntiSpoof and TitleBlacklist) call this in response to
+ * UserCreateForm hook to add checkboxes to the create account form.
+ */
+ public function addInputItem( $name, $value, $type, $msg, $helptext = false ) {
+ // use the same indexes as UserCreateForm just in case someone adds an item manually
+ $this->data['extrainput'][] = [
+ 'name' => $name,
+ 'value' => $value,
+ 'type' => $type,
+ 'msg' => $msg,
+ 'helptext' => $helptext,
+ ];
+ }
+
+ /**
+ * Turns addInputItem-style field definitions into HTMLForm field definitions.
+ * @return array
+ */
+ public function getExtraInputDefinitions() {
+ $definitions = [];
+
+ foreach ( $this->get( 'extrainput', [] ) as $field ) {
+ $definition = [
+ 'type' => $field['type'] === 'checkbox' ? 'check' : $field['type'],
+ 'name' => $field['name'],
+ 'value' => $field['value'],
+ 'id' => $field['name'],
+ ];
+ if ( $field['msg'] ) {
+ $definition['label-message'] = $this->getMsg( $field['msg'] );
+ }
+ if ( $field['helptext'] ) {
+ $definition['help'] = $this->msgWiki( $field['helptext'] );
+ }
+
+ // the array key doesn't matter much when name is defined explicitly but
+ // let's try and follow HTMLForm conventions
+ $name = preg_replace( '/^wp(?=[A-Z])/', '', $field['name'] );
+ $definitions[$name] = $definition;
+ }
+
+ if ( $this->haveData( 'extrafields' ) ) {
+ $definitions['extrafields'] = [
+ 'type' => 'info',
+ 'raw' => true,
+ 'default' => $this->get( 'extrafields' ),
+ ];
+ }
+
+ return $definitions;
+ }
+}
+
+/**
+ * A horrible hack to handle AuthManager's feature flag. For other special pages this is done in
+ * SpecialPageFactory, but LoginForm is used directly by some extensions. Will be killed as soon
+ * as AuthManager is stable.
+ */
+class LoginForm extends SpecialPage {
+ private $realLoginForm;
+
+ public function __construct( $request = null ) {
+ global $wgDisableAuthManager;
+ if ( $wgDisableAuthManager ) {
+ $this->realLoginForm = new LoginFormPreAuthManager( $request );
+ } else {
+ $this->realLoginForm = new LoginFormAuthManager( $request );
+ }
+ }
+
+ // proxy everything
+
+ public function __get( $name ) {
+ return $this->realLoginForm->$name;
+ }
+
+ public function __set( $name, $value ) {
+ $this->realLoginForm->$name = $value;
+ }
+
+ public function __call( $name, $args ) {
+ return call_user_func_array( [ $this->realLoginForm, $name ], $args );
+ }
+
+ public static function __callStatic( $name, $args ) {
+ global $wgDisableAuthManager;
+ return call_user_func_array( [ $wgDisableAuthManager ? LoginFormPreAuthManager::class
+ : LoginFormAuthManager::class, $name ], $args );
+ }
+
+ // all public SpecialPage methods need to be proxied explicitly
+
+ public function getName() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getRestriction() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function isListed() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function setListed( $listed ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function listed( $x = null ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function isIncludable() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function including( $x = null ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getLocalName() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function isExpensive() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function isCached() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function isRestricted() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function userCanExecute( User $user ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function displayRestrictionError() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function checkPermissions() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function checkReadOnly() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function requireLogin(
+ $reasonMsg = 'exception-nologin-text', $titleMsg = 'exception-nologin'
+ ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function prefixSearchSubpages( $search, $limit, $offset ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function execute( $subPage ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getDescription() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ function getTitle( $subpage = false ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ function getPageTitle( $subpage = false ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function setContext( $context ) {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getContext() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getRequest() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getOutput() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getUser() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getSkin() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getLanguage() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getConfig() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getFullTitle() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function getFinalGroupName() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+ public function doesWrites() {
+ return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
+ }
+
+ // no way to proxy constants and static properties
+
+ const SUCCESS = 0;
+ const NO_NAME = 1;
+ const ILLEGAL = 2;
+ const WRONG_PLUGIN_PASS = 3;
+ const NOT_EXISTS = 4;
+ const WRONG_PASS = 5;
+ const EMPTY_PASS = 6;
+ const RESET_PASS = 7;
+ const ABORTED = 8;
+ const CREATE_BLOCKED = 9;
+ const THROTTLED = 10;
+ const USER_BLOCKED = 11;
+ const NEED_TOKEN = 12;
+ const WRONG_TOKEN = 13;
+ const USER_MIGRATED = 14;
+
+ public static $statusCodes = [
+ self::SUCCESS => 'success',
+ self::NO_NAME => 'no_name',
+ self::ILLEGAL => 'illegal',
+ self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
+ self::NOT_EXISTS => 'not_exists',
+ self::WRONG_PASS => 'wrong_pass',
+ self::EMPTY_PASS => 'empty_pass',
+ self::RESET_PASS => 'reset_pass',
+ self::ABORTED => 'aborted',
+ self::CREATE_BLOCKED => 'create_blocked',
+ self::THROTTLED => 'throttled',
+ self::USER_BLOCKED => 'user_blocked',
+ self::NEED_TOKEN => 'need_token',
+ self::WRONG_TOKEN => 'wrong_token',
+ self::USER_MIGRATED => 'user_migrated',
+ ];
+
+ public static $validErrorMessages = [
+ 'exception-nologin-text',
+ 'watchlistanontext',
+ 'changeemail-no-info',
+ 'resetpass-no-info',
+ 'confirmemail_needlogin',
+ 'prefsnologintext2',
+ ];
+}
+
+/**
+ * LoginForm as a special page has been replaced by SpecialUserLogin and SpecialCreateAccount,
+ * but some extensions called its public methods directly, so the class is retained as a
+ * B/C wrapper. Anything that used it before should use AuthManager instead.
+ */
+class LoginFormAuthManager extends SpecialPage {
+ const SUCCESS = 0;
+ const NO_NAME = 1;
+ const ILLEGAL = 2;
+ const WRONG_PLUGIN_PASS = 3;
+ const NOT_EXISTS = 4;
+ const WRONG_PASS = 5;
+ const EMPTY_PASS = 6;
+ const RESET_PASS = 7;
+ const ABORTED = 8;
+ const CREATE_BLOCKED = 9;
+ const THROTTLED = 10;
+ const USER_BLOCKED = 11;
+ const NEED_TOKEN = 12;
+ const WRONG_TOKEN = 13;
+ const USER_MIGRATED = 14;
+
+ public static $statusCodes = [
+ self::SUCCESS => 'success',
+ self::NO_NAME => 'no_name',
+ self::ILLEGAL => 'illegal',
+ self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
+ self::NOT_EXISTS => 'not_exists',
+ self::WRONG_PASS => 'wrong_pass',
+ self::EMPTY_PASS => 'empty_pass',
+ self::RESET_PASS => 'reset_pass',
+ self::ABORTED => 'aborted',
+ self::CREATE_BLOCKED => 'create_blocked',
+ self::THROTTLED => 'throttled',
+ self::USER_BLOCKED => 'user_blocked',
+ self::NEED_TOKEN => 'need_token',
+ self::WRONG_TOKEN => 'wrong_token',
+ self::USER_MIGRATED => 'user_migrated',
+ ];
+
+ /**
+ * @param WebRequest $request
+ */
+ public function __construct( $request = null ) {
+ wfDeprecated( 'LoginForm', '1.27' );
+ parent::__construct();
+ }
+
+ /**
+ * @deprecated since 1.27 - call LoginHelper::getValidErrorMessages instead.
+ */
+ public static function getValidErrorMessages() {
+ return LoginHelper::getValidErrorMessages();
+ }
+
+ /**
+ * @deprecated since 1.27 - don't use LoginForm, use AuthManager instead
+ */
+ public static function incrementLoginThrottle( $username ) {
+ wfDeprecated( __METHOD__, "1.27" );
+ global $wgRequest;
+ $username = User::getCanonicalName( $username, 'usable' ) ?: $username;
+ $throttler = new Throttler();
+ return $throttler->increase( $username, $wgRequest->getIP(), __METHOD__ );
+ }
+
+ /**
+ * @deprecated since 1.27 - don't use LoginForm, use AuthManager instead
+ */
+ public static function incLoginThrottle( $username ) {
+ wfDeprecated( __METHOD__, "1.27" );
+ $res = self::incrementLoginThrottle( $username );
+ return is_array( $res ) ? true : 0;
+ }
+
+ /**
+ * @deprecated since 1.27 - don't use LoginForm, use AuthManager instead
+ */
+ public static function clearLoginThrottle( $username ) {
+ wfDeprecated( __METHOD__, "1.27" );
+ global $wgRequest;
+ $username = User::getCanonicalName( $username, 'usable' ) ?: $username;
+ $throttler = new Throttler();
+ return $throttler->clear( $username, $wgRequest->getIP() );
+ }
+
+ /**
+ * @deprecated since 1.27 - don't use LoginForm, use AuthManager instead
+ */
+ public static function getLoginToken() {
+ wfDeprecated( __METHOD__, '1.27' );
+ global $wgRequest;
+ return $wgRequest->getSession()->getToken( '', 'login' )->toString();
+ }
+
+ /**
+ * @deprecated since 1.27 - don't use LoginForm, use AuthManager instead
+ */
+ public static function setLoginToken() {
+ wfDeprecated( __METHOD__, '1.27' );
+ }
+
+ /**
+ * @deprecated since 1.27 - don't use LoginForm, use AuthManager instead
+ */
+ public static function clearLoginToken() {
+ wfDeprecated( __METHOD__, '1.27' );
+ global $wgRequest;
+ $wgRequest->getSession()->resetToken( 'login' );
+ }
+
+ /**
+ * @deprecated since 1.27 - don't use LoginForm, use AuthManager instead
+ */
+ public static function getCreateaccountToken() {
+ wfDeprecated( __METHOD__, '1.27' );
+ global $wgRequest;
+ return $wgRequest->getSession()->getToken( '', 'createaccount' )->toString();
+ }
+
+ /**
+ * @deprecated since 1.27 - don't use LoginForm, use AuthManager instead
+ */
+ public static function setCreateaccountToken() {
+ wfDeprecated( __METHOD__, '1.27' );
+ }
+
+ /**
+ * @deprecated since 1.27 - don't use LoginForm, use AuthManager instead
+ */
+ public static function clearCreateaccountToken() {
+ wfDeprecated( __METHOD__, '1.27' );
+ global $wgRequest;
+ $wgRequest->getSession()->resetToken( 'createaccount' );
+ }
+}
* @ingroup SpecialPage
*/
+use MediaWiki\Auth\AuthManager;
+
/**
* Parent class for all special pages.
*
}
}
+ /**
+ * Tells if the special page does something security-sensitive and needs extra defense against
+ * a stolen account (e.g. a reauthentication). What exactly that will mean is decided by the
+ * authentication framework.
+ * @return bool|string False or the argument for AuthManager::securitySensitiveOperationStatus().
+ * Typically a special page needing elevated security would return its name here.
+ */
+ protected function getLoginSecurityLevel() {
+ return false;
+ }
+
+ /**
+ * Verifies that the user meets the security level, possibly reauthenticating them in the process.
+ *
+ * This should be used when the page does something security-sensitive and needs extra defense
+ * against a stolen account (e.g. a reauthentication). The authentication framework will make
+ * an extra effort to make sure the user account is not compromised. What that exactly means
+ * will depend on the system and user settings; e.g. the user might be required to log in again
+ * unless their last login happened recently, or they might be given a second-factor challenge.
+ *
+ * Calling this method will result in one if these actions:
+ * - return true: all good.
+ * - return false and set a redirect: caller should abort; the redirect will take the user
+ * to the login page for reauthentication, and back.
+ * - throw an exception if there is no way for the user to meet the requirements without using
+ * a different access method (e.g. this functionality is only available from a specific IP).
+ *
+ * Note that this does not in any way check that the user is authorized to use this special page
+ * (use checkPermissions() for that).
+ *
+ * @param string $level A security level. Can be an arbitrary string, defaults to the page name.
+ * @return bool False means a redirect to the reauthentication page has been set and processing
+ * of the special page should be aborted.
+ * @throws ErrorPageError If the security level cannot be met, even with reauthentication.
+ */
+ protected function checkLoginSecurityLevel( $level = null ) {
+ $level = $level ?: $this->getName();
+ $securityStatus = AuthManager::singleton()->securitySensitiveOperationStatus( $level );
+ if ( $securityStatus === AuthManager::SEC_OK ) {
+ return true;
+ } elseif ( $securityStatus === AuthManager::SEC_REAUTH ) {
+ $request = $this->getRequest();
+ $title = SpecialPage::getTitleFor( 'Userlogin' );
+ $query = [
+ 'returnto' => $this->getFullTitle()->getPrefixedDBkey(),
+ 'returntoquery' => wfArrayToCgi( array_diff_key( $request->getQueryValues(),
+ [ 'title' => true ] ) ),
+ 'force' => $level,
+ ];
+ $url = $title->getFullURL( $query, false, PROTO_HTTPS );
+
+ $this->getOutput()->redirect( $url );
+ return false;
+ }
+
+ $titleMessage = wfMessage( 'specialpage-securitylevel-not-allowed-title' );
+ $errorMessage = wfMessage( 'specialpage-securitylevel-not-allowed' );
+ throw new ErrorPageError( $titleMessage, $errorMessage );
+ }
+
/**
* Return an array of subpages beginning with $search that this special page will accept.
*
public function execute( $subPage ) {
$this->setHeaders();
$this->checkPermissions();
+ $this->checkLoginSecurityLevel( $this->getLoginSecurityLevel() );
$this->outputHeader();
}
'PagesWithProp' => 'SpecialPagesWithProp',
'TrackingCategories' => 'SpecialTrackingCategories',
- // Login/create account
- 'Userlogin' => 'LoginForm',
- 'CreateAccount' => 'SpecialCreateAccount',
+ // Authentication
+ 'Userlogin' => 'SpecialUserLogin',
+ 'Userlogout' => 'SpecialUserlogoutPreAuthManager',
+ 'CreateAccount' => 'SpecialCreateAccountPreAuthManager',
+ 'LinkAccounts' => 'SpecialLinkAccounts',
+ 'UnlinkAccounts' => 'SpecialUnlinkAccounts',
+ 'ChangeCredentials' => 'SpecialChangeCredentials',
+ 'RemoveCredentials' => 'SpecialRemoveCredentials',
// Users and rights
+ 'Activeusers' => 'SpecialActiveUsers',
'Block' => 'SpecialBlock',
'Unblock' => 'SpecialUnblock',
'BlockList' => 'SpecialBlockList',
- 'ChangePassword' => 'SpecialChangePassword',
+ 'ChangePassword' => 'SpecialChangePasswordPreAuthManager',
'BotPasswords' => 'SpecialBotPasswords',
- 'PasswordReset' => 'SpecialPasswordReset',
+ 'PasswordReset' => 'SpecialPasswordResetPreAuthManager',
'DeletedContributions' => 'DeletedContributionsPage',
'Preferences' => 'SpecialPreferences',
'ResetTokens' => 'SpecialResetTokens',
'Revisiondelete' => 'SpecialRevisionDelete',
'RunJobs' => 'SpecialRunJobs',
'Specialpages' => 'SpecialSpecialpages',
- 'Userlogout' => 'SpecialUserlogout',
];
private static $list;
global $wgDisableInternalSearch, $wgEmailAuthentication;
global $wgEnableEmail, $wgEnableJavaScriptTest;
global $wgPageLanguageUseDB, $wgContentHandlerUseDB;
+ global $wgDisableAuthManager;
if ( !is_array( self::$list ) ) {
}
if ( $wgEnableEmail ) {
- self::$list['ChangeEmail'] = 'SpecialChangeEmail';
+ self::$list['ChangeEmail'] = 'SpecialChangeEmailPreAuthManager';
}
if ( $wgEnableJavaScriptTest ) {
self::$list['ChangeContentModel'] = 'SpecialChangeContentModel';
}
- self::$list['Activeusers'] = 'SpecialActiveUsers';
+ // horrible hack to allow selection between old and new classes via a feature flag - T110756
+ // will be removed once AuthManager is stable
+ if ( !$wgDisableAuthManager ) {
+ self::$list = array_map( function ( $class ) {
+ return preg_replace( '/PreAuthManager$/', '', $class );
+ }, self::$list );
+ self::$list['Userlogout'] = 'SpecialUserLogout'; // case matters
+ } else {
+ self::$list['Userlogin'] = 'LoginForm';
+ self::$list = array_diff_key( self::$list, array_fill_keys( [
+ 'LinkAccounts', 'UnlinkAccounts', 'ChangeCredentials', 'RemoveCredentials',
+ ], true ) );
+ }
// Add extension special pages
self::$list = array_merge( self::$list, $wgSpecialPages );
$trxProfiler = Profiler::instance()->getTransactionProfiler();
if ( $context->getRequest()->wasPosted() && !$page->doesWrites() ) {
$trxProfiler->setExpectations( $trxLimits['POST-nonwrite'], __METHOD__ );
+ $context->getRequest()->markAsSafeRequest();
}
}
*/
/**
+ * Implements Special:Activeusers
+ *
* @ingroup SpecialPage
*/
class SpecialActiveUsers extends SpecialPage {
* @param string $par Parameter passed to the page or null
*/
public function execute( $par ) {
- $days = $this->getConfig()->get( 'ActiveUserDays' );
+ $out = $this->getOutput();
$this->setHeaders();
$this->outputHeader();
- $out = $this->getOutput();
- $out->wrapWikiMsg( "<div class='mw-activeusers-intro'>\n$1\n</div>",
- [ 'activeusers-intro', $this->getLanguage()->formatNum( $days ) ] );
+ $opts = new FormOptions();
+
+ $opts->add( 'username', '' );
+ $opts->add( 'hidebots', false, FormOptions::BOOL );
+ $opts->add( 'hidesysops', false, FormOptions::BOOL );
+
+ $opts->fetchValuesFromRequest( $this->getRequest() );
+
+ if ( $par !== null ) {
+ $opts->setValue( 'username', $par );
+ }
// Mention the level of cache staleness...
+ $cacheText = '';
$dbr = wfGetDB( DB_SLAVE, 'recentchanges' );
$rcMax = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', '', __METHOD__ );
if ( $rcMax ) {
$secondsOld = time() - wfTimestamp( TS_UNIX, $rcMin );
}
if ( $secondsOld > 0 ) {
- $out->addWikiMsg( 'cachedspecial-viewing-cached-ttl',
- $this->getLanguage()->formatDuration( $secondsOld ) );
+ $cacheTxt = '<br>' . $this->msg( 'cachedspecial-viewing-cached-ttl' )
+ ->durationParams( $secondsOld );
}
}
- $up = new ActiveUsersPager( $this->getContext(), null, $par );
+ $pager = new ActiveUsersPager( $this->getContext(), $opts );
+ $usersBody = $pager->getBody();
+
+ $days = $this->getConfig()->get( 'ActiveUserDays' );
+
+ $formDescriptor = [
+ 'username' => [
+ 'type' => 'user',
+ 'name' => 'username',
+ 'label-message' => 'activeusers-from',
+ ],
+
+ 'hidebots' => [
+ 'type' => 'check',
+ 'name' => 'hidebots',
+ 'label-message' => 'activeusers-hidebots',
+ 'default' => false,
+ ],
+
+ 'hidesysops' => [
+ 'type' => 'check',
+ 'name' => 'hidesysops',
+ 'label-message' => 'activeusers-hidesysops',
+ 'default' => false,
+ ],
+ ];
- # getBody() first to check, if empty
- $usersbody = $up->getBody();
+ $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+ ->setIntro( $this->msg( 'activeusers-intro' )->numParams( $days ) . $cacheText )
+ ->setWrapperLegendMsg( 'activeusers' )
+ ->setSubmitTextMsg( 'activeusers-submit' )
+ ->setMethod( 'get' )
+ ->prepareForm()
+ ->displayForm( false );
- $out->addHTML( $up->getPageHeader() );
- if ( $usersbody ) {
+ if ( $usersBody ) {
$out->addHTML(
- $up->getNavigationBar() .
- Html::rawElement( 'ul', [], $usersbody ) .
- $up->getNavigationBar()
+ $pager->getNavigationBar() .
+ Html::rawElement( 'ul', [], $usersBody ) .
+ $pager->getNavigationBar()
);
} else {
$out->addWikiMsg( 'activeusers-noresult' );
$out = $this->getOutput();
$lang = $this->getLanguage();
$out->setPageTitle( $this->msg( 'ipblocklist' ) );
- $out->addModuleStyles( [ 'mediawiki.special', 'mediawiki.special.blocklist' ] );
+ $out->addModuleStyles( [ 'mediawiki.special' ] );
$request = $this->getRequest();
$par = $request->getVal( 'ip', $par );
/**
* ISBN passed to the page, if any
*/
- private $isbn = '';
+ protected $isbn = '';
public function __construct() {
parent::__construct( 'Booksources' );
* @param string $isbn ISBN passed as a subpage parameter
*/
public function execute( $isbn ) {
+ $out = $this->getOutput();
+
$this->setHeaders();
$this->outputHeader();
+
$this->isbn = self::cleanIsbn( $isbn ?: $this->getRequest()->getText( 'isbn' ) );
- $this->getOutput()->addHTML( $this->makeForm() );
+
+ $this->buildForm();
+
if ( $this->isbn !== '' ) {
if ( !self::isValidISBN( $this->isbn ) ) {
- $this->getOutput()->wrapWikiMsg(
+ $out->wrapWikiMsg(
"<div class=\"error\">\n$1\n</div>",
'booksources-invalid-isbn'
);
}
+
$this->showList();
}
}
/**
* Generate a form to allow users to enter an ISBN
- *
- * @return string
*/
- private function makeForm() {
- $form = Html::openElement( 'fieldset' ) . "\n";
- $form .= Html::element(
- 'legend',
- [],
- $this->msg( 'booksources-search-legend' )->text()
- ) . "\n";
- $form .= Html::openElement( 'form', [ 'method' => 'get', 'action' => wfScript() ] ) . "\n";
- $form .= Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ) . "\n";
- $form .= '<p>' . Xml::inputLabel(
- $this->msg( 'booksources-isbn' )->text(),
- 'isbn',
- 'isbn',
- 20,
- $this->isbn,
- [ 'autofocus' => '', 'class' => 'mw-ui-input-inline' ]
- );
-
- $form .= ' ' . Html::submitButton(
- $this->msg( 'booksources-search' )->text(),
- [], [ 'mw-ui-progressive' ]
- ) . "</p>\n";
-
- $form .= Html::closeElement( 'form' ) . "\n";
- $form .= Html::closeElement( 'fieldset' ) . "\n";
-
- return $form;
+ private function buildForm() {
+ $formDescriptor = [
+ 'isbn' => [
+ 'type' => 'text',
+ 'name' => 'isbn',
+ 'label-message' => 'booksources-isbn',
+ 'default' => $this->isbn,
+ 'autofocus' => true,
+ 'required' => true,
+ ],
+ ];
+
+ $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+ ->setWrapperLegendMsg( 'booksources-search-legend' )
+ ->setSubmitTextMsg( 'booksources-search' )
+ ->setMethod( 'get' )
+ ->prepareForm()
+ ->displayForm( false );
}
/**
* @return bool
*/
private function showList() {
+ $out = $this->getOutput();
+
global $wgContLang;
# Hook to allow extensions to insert additional HTML,
# e.g. for API-interacting plugins and so on
- Hooks::run( 'BookInformation', [ $this->isbn, $this->getOutput() ] );
+ Hooks::run( 'BookInformation', [ $this->isbn, $out ] );
# Check for a local page such as Project:Book_sources and use that if available
$page = $this->msg( 'booksources' )->inContentLanguage()->text();
// XXX: in the future, this could be stored as structured data, defining a list of book sources
$text = $content->getNativeData();
- $this->getOutput()->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $text ) );
+ $out->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $text ) );
return true;
} else {
}
# Fall back to the defaults given in the language file
- $this->getOutput()->addWikiMsg( 'booksources-text' );
- $this->getOutput()->addHTML( '<ul>' );
+ $out->addWikiMsg( 'booksources-text' );
+ $out->addHTML( '<ul>' );
$items = $wgContLang->getBookstoreList();
foreach ( $items as $label => $url ) {
- $this->getOutput()->addHTML( $this->makeListItem( $label, $url ) );
+ $out->addHTML( $this->makeListItem( $label, $url ) );
}
- $this->getOutput()->addHTML( '</ul>' );
+ $out->addHTML( '</ul>' );
return true;
}
--- /dev/null
+<?php
+
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Session\SessionManager;
+
+/**
+ * Special change to change credentials (such as the password).
+ *
+ * Also does most of the work for SpecialRemoveCredentials.
+ */
+class SpecialChangeCredentials extends AuthManagerSpecialPage {
+ protected static $allowedActions = [ AuthManager::ACTION_CHANGE ];
+
+ protected static $messagePrefix = 'changecredentials';
+
+ /** Change action needs user data; remove action does not */
+ protected static $loadUserData = true;
+
+ public function __construct( $name = 'ChangeCredentials' ) {
+ parent::__construct( $name, 'editmyprivateinfo' );
+ }
+
+ protected function getGroupName() {
+ return 'users';
+ }
+
+ public function isListed() {
+ $this->loadAuth( '' );
+ return (bool)$this->authRequests;
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ protected function getDefaultAction( $subPage ) {
+ return AuthManager::ACTION_CHANGE;
+ }
+
+ protected function getPreservedParams( $withToken = false ) {
+ $request = $this->getRequest();
+ $params = parent::getPreservedParams( $withToken );
+ $params += [
+ 'returnto' => $request->getVal( 'returnto' ),
+ 'returntoquery' => $request->getVal( 'returntoquery' ),
+ ];
+ return $params;
+ }
+
+ public function onAuthChangeFormFields(
+ array $requests, array $fieldInfo, array &$formDescriptor, $action
+ ) {
+ // This method is never called for remove actions.
+
+ $extraFields = [];
+ Hooks::run( 'ChangePasswordForm', [ &$extraFields ], '1.27' );
+ foreach ( $extraFields as $extra ) {
+ list( $name, $label, $type, $default ) = $extra;
+ $formDescriptor[$name] = [
+ 'type' => $type,
+ 'name' => $name,
+ 'label-message' => $label,
+ 'default' => $default,
+ ];
+
+ }
+
+ return parent::onAuthChangeFormFields( $requests, $fieldInfo, $formDescriptor, $action );
+ }
+
+ public function execute( $subPage ) {
+ $this->setHeaders();
+ $this->outputHeader();
+
+ $this->loadAuth( $subPage );
+
+ if ( !$subPage ) {
+ $this->showSubpageList();
+ return;
+ }
+
+ if ( !$this->authRequests ) {
+ // messages used: changecredentials-invalidsubpage, removecredentials-invalidsubpage
+ $this->showSubpageList( $this->msg( static::$messagePrefix . '-invalidsubpage', $subPage ) );
+ return;
+ }
+
+ $status = $this->trySubmit();
+
+ if ( $status === false || !$status->isOK() ) {
+ $this->displayForm( $status );
+ return;
+ }
+
+ $response = $status->getValue();
+
+ switch ( $response->status ) {
+ case AuthenticationResponse::PASS:
+ $this->success();
+ break;
+ case AuthenticationResponse::FAIL:
+ $this->displayForm( Status::newFatal( $response->message ) );
+ break;
+ default:
+ throw new LogicException( 'invalid AuthenticationResponse' );
+ }
+ }
+
+ protected function loadAuth( $subPage, $authAction = null, $reset = false ) {
+ parent::loadAuth( $subPage, $authAction );
+ if ( $subPage ) {
+ $this->authRequests = array_filter( $this->authRequests, function ( $req ) use ( $subPage ) {
+ return $req->getUniqueId() === $subPage;
+ } );
+ if ( count( $this->authRequests ) > 1 ) {
+ throw new LogicException( 'Multiple AuthenticationRequest objects with same ID!' );
+ }
+ }
+ }
+
+ protected function getAuthFormDescriptor( $requests, $action ) {
+ if ( !static::$loadUserData ) {
+ return [];
+ } else {
+ return parent::getAuthFormDescriptor( $requests, $action );
+ }
+ }
+
+ protected function getAuthForm( array $requests, $action ) {
+ $form = parent::getAuthForm( $requests, $action );
+ $req = reset( $requests );
+ $info = $req->describeCredentials();
+
+ $form->addPreText(
+ Html::openElement( 'dl' )
+ . Html::element( 'dt', [], wfMessage( 'credentialsform-provider' ) )
+ . Html::element( 'dd', [], $info['provider'] )
+ . Html::element( 'dt', [], wfMessage( 'credentialsform-account' ) )
+ . Html::element( 'dd', [], $info['account'] )
+ . Html::closeElement( 'dl' )
+ );
+
+ // messages used: changecredentials-submit removecredentials-submit
+ $form->setSubmitTextMsg( static::$messagePrefix . '-submit' );
+ $form->showCancel()->setCancelTarget( $this->getReturnUrl() ?: Title::newMainPage() );
+
+ return $form;
+ }
+
+ protected function needsSubmitButton( $formDescriptor ) {
+ // Change/remove forms show are built from a single AuthenticationRequest and do not allow
+ // for redirect flow; they always need a submit button.
+ return true;
+ }
+
+ public function handleFormSubmit( $data ) {
+ // remove requests do not accept user input
+ $requests = $this->authRequests;
+ if ( static::$loadUserData ) {
+ $requests = AuthenticationRequest::loadRequestsFromSubmission( $this->authRequests, $data );
+ }
+
+ $response = $this->performAuthenticationStep( $this->authAction, $requests );
+
+ // we can't handle FAIL or similar as failure here since it might require changing the form
+ return Status::newGood( $response );
+ }
+
+ /**
+ * @param Message|null $error
+ */
+ protected function showSubpageList( $error = null ) {
+ $out = $this->getOutput();
+
+ if ( $error ) {
+ $out->addHTML( $error->parse() );
+ }
+
+ $groupedRequests = [];
+ foreach ( $this->authRequests as $req ) {
+ $info = $req->describeCredentials();
+ $groupedRequests[(string)$info['provider']][] = $req;
+ }
+
+ $out->addHTML( Html::openElement( 'dl' ) );
+ foreach ( $groupedRequests as $group => $members ) {
+ $out->addHTML( Html::element( 'dt', [], $group ) );
+ foreach ( $members as $req ) {
+ /** @var AuthenticationRequest $req */
+ $info = $req->describeCredentials();
+ $out->addHTML( Html::rawElement( 'dd', [],
+ Linker::link( $this->getPageTitle( $req->getUniqueId() ),
+ htmlspecialchars( $info['account'], ENT_QUOTES ) )
+ ) );
+ }
+ }
+ $out->addHTML( Html::closeElement( 'dl' ) );
+ }
+
+ protected function success() {
+ $session = $this->getRequest()->getSession();
+ $user = $this->getUser();
+ $out = $this->getOutput();
+ $returnUrl = $this->getReturnUrl();
+
+ // change user token and update the session
+ SessionManager::singleton()->invalidateSessionsForUser( $user );
+ $session->setUser( $user );
+ $session->resetId();
+
+ if ( $returnUrl ) {
+ $out->redirect( $returnUrl );
+ } else {
+ // messages used: changecredentials-success removecredentials-success
+ $out->wrapWikiMsg( "<div class=\"successbox\">\n$1\n</div>", static::$messagePrefix
+ . '-success' );
+ $out->returnToMain();
+ }
+ }
+
+ /**
+ * @return string|null
+ */
+ protected function getReturnUrl() {
+ $request = $this->getRequest();
+ $returnTo = $request->getText( 'returnto' );
+ $returnToQuery = $request->getText( 'returntoquery', '' );
+
+ if ( !$returnTo ) {
+ return null;
+ }
+
+ $title = Title::newFromText( $returnTo );
+ return $title->getFullURL( $returnToQuery );
+ }
+
+ protected function getRequestBlacklist() {
+ return $this->getConfig()->get( 'ChangeCredentialsBlacklist' );
+ }
+}
* @ingroup SpecialPage
*/
+use MediaWiki\Auth\AuthManager;
+
/**
* Let users change their email address.
*
* @return bool
*/
public function isListed() {
- global $wgAuth;
-
- return $wgAuth->allowPropChange( 'emailaddress' );
+ return AuthManager::singleton()->allowsPropertyChange( 'emailaddress' );
}
/**
* @param string $par
*/
function execute( $par ) {
+ $this->checkLoginSecurityLevel();
+
$out = $this->getOutput();
$out->disallowUserJs();
}
protected function checkExecutePermissions( User $user ) {
- global $wgAuth;
- if ( !$wgAuth->allowPropChange( 'emailaddress' ) ) {
+ if ( !AuthManager::singleton()->allowsPropertyChange( 'emailaddress' ) ) {
throw new ErrorPageError( 'changeemail', 'cannotchangeemail' );
}
],
];
- if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
- $fields['Password'] = [
- 'type' => 'password',
- 'label-message' => 'changeemail-password'
- ];
- }
-
return $fields;
}
$form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
$form->addHeaderText( $this->msg( 'changeemail-header' )->parseAsBlock() );
- if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
- $form->addHeaderText( $this->msg( 'changeemail-passwordrequired' )->parseAsBlock() );
- }
}
public function onSubmit( array $data ) {
- $password = isset( $data['Password'] ) ? $data['Password'] : null;
- $status = $this->attemptChange( $this->getUser(), $password, $data['NewEmail'] );
+ $status = $this->attemptChange( $this->getUser(), $data['NewEmail'] );
$this->status = $status;
/**
* @param User $user
- * @param string $pass
* @param string $newaddr
* @return Status
*/
- private function attemptChange( User $user, $pass, $newaddr ) {
- global $wgAuth;
+ private function attemptChange( User $user, $newaddr ) {
+ $authManager = AuthManager::singleton();
if ( $newaddr != '' && !Sanitizer::validateEmail( $newaddr ) ) {
return Status::newFatal( 'invalidemailaddress' );
return Status::newFatal( 'changeemail-nochange' );
}
- $throttleInfo = LoginForm::incrementLoginThrottle( $user->getName() );
- if ( $throttleInfo ) {
- $lang = $this->getLanguage();
- return Status::newFatal(
- 'changeemail-throttled',
- $lang->formatDuration( $throttleInfo['wait'] )
- );
- }
-
- if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' )
- && !$user->checkTemporaryPassword( $pass )
- && !$user->checkPassword( $pass )
- ) {
- return Status::newFatal( 'wrongpassword' );
- }
-
- LoginForm::clearLoginThrottle( $user->getName() );
-
$oldaddr = $user->getEmail();
$status = $user->setEmailWithConfirmation( $newaddr );
if ( !$status->isGood() ) {
Hooks::run( 'PrefsEmailAudit', [ $user, $oldaddr, $newaddr ] );
$user->saveSettings();
-
- $wgAuth->updateExternalDB( $user );
+ MediaWiki\Auth\AuthManager::callLegacyAuthPlugin( 'updateExternalDB', [ $user ] );
return $status;
}
* @ingroup SpecialPage
*/
+use MediaWiki\Auth\PasswordAuthenticationRequest;
+
/**
* Let users recover their password.
*
* @ingroup SpecialPage
*/
-class SpecialChangePassword extends FormSpecialPage {
- protected $mUserName;
- protected $mDomain;
-
- // Optional Wikitext Message to show above the password change form
- protected $mPreTextMessage = null;
-
- // label for old password input
- protected $mOldPassMsg = null;
-
+class SpecialChangePassword extends SpecialRedirectToSpecial {
public function __construct() {
- parent::__construct( 'ChangePassword', 'editmyprivateinfo' );
- $this->listed( false );
- }
-
- public function doesWrites() {
- return true;
- }
-
- /**
- * Main execution point
- * @param string|null $par
- */
- function execute( $par ) {
- $this->getOutput()->disallowUserJs();
-
- parent::execute( $par );
- }
-
- protected function checkExecutePermissions( User $user ) {
- parent::checkExecutePermissions( $user );
-
- if ( !$this->getRequest()->wasPosted() ) {
- $this->requireLogin( 'resetpass-no-info' );
- }
- }
-
- /**
- * Set a message at the top of the Change Password form
- * @since 1.23
- * @param Message $msg Message to parse and add to the form header
- */
- public function setChangeMessage( Message $msg ) {
- $this->mPreTextMessage = $msg;
- }
-
- /**
- * Set a message at the top of the Change Password form
- * @since 1.23
- * @param string $msg Message label for old/temp password field
- */
- public function setOldPasswordMessage( $msg ) {
- $this->mOldPassMsg = $msg;
- }
-
- protected function getFormFields() {
- $user = $this->getUser();
- $request = $this->getRequest();
-
- $oldpassMsg = $this->mOldPassMsg;
- if ( $oldpassMsg === null ) {
- $oldpassMsg = $user->isLoggedIn() ? 'oldpassword' : 'resetpass-temp-password';
- }
-
- $fields = [
- 'Name' => [
- 'type' => 'info',
- 'label-message' => 'username',
- 'default' => $request->getVal( 'wpName', $user->getName() ),
- ],
- 'Password' => [
- 'type' => 'password',
- 'label-message' => $oldpassMsg,
- ],
- 'NewPassword' => [
- 'type' => 'password',
- 'label-message' => 'newpassword',
- ],
- 'Retype' => [
- 'type' => 'password',
- 'label-message' => 'retypenew',
- ],
- ];
-
- if ( !$this->getUser()->isLoggedIn() ) {
- $fields['LoginOnChangeToken'] = [
- 'type' => 'hidden',
- 'label' => 'Change Password Token',
- 'default' => LoginForm::getLoginToken()->toString(),
- ];
- }
-
- $extraFields = [];
- Hooks::run( 'ChangePasswordForm', [ &$extraFields ] );
- foreach ( $extraFields as $extra ) {
- list( $name, $label, $type, $default ) = $extra;
- $fields[$name] = [
- 'type' => $type,
- 'name' => $name,
- 'label-message' => $label,
- 'default' => $default,
- ];
- }
-
- if ( !$user->isLoggedIn() ) {
- $fields['Remember'] = [
- 'type' => 'check',
- 'label' => $this->msg( 'remembermypassword' )
- ->numParams(
- ceil( $this->getConfig()->get( 'CookieExpiration' ) / ( 3600 * 24 ) )
- )->text(),
- 'default' => $request->getVal( 'wpRemember' ),
- ];
- }
-
- return $fields;
- }
-
- protected function alterForm( HTMLForm $form ) {
- $form->setId( 'mw-resetpass-form' );
- $form->setTableId( 'mw-resetpass-table' );
- $form->setWrapperLegendMsg( 'resetpass_header' );
- $form->setSubmitTextMsg(
- $this->getUser()->isLoggedIn()
- ? 'resetpass-submit-loggedin'
- : 'resetpass_submit'
- );
- $form->addButton( [
- 'name' => 'wpCancel',
- 'value' => $this->msg( 'resetpass-submit-cancel' )->text()
- ] );
- $form->setHeaderText( $this->msg( 'resetpass_text' )->parseAsBlock() );
- if ( $this->mPreTextMessage instanceof Message ) {
- $form->addPreText( $this->mPreTextMessage->parseAsBlock() );
- }
- $form->addHiddenFields(
- $this->getRequest()->getValues( 'wpName', 'wpDomain', 'returnto', 'returntoquery' ) );
- }
-
- public function onSubmit( array $data ) {
- global $wgAuth;
-
- $request = $this->getRequest();
-
- if ( $request->getCheck( 'wpLoginToken' ) ) {
- // This comes from Special:Userlogin when logging in with a temporary password
- return false;
- }
-
- if ( !$this->getUser()->isLoggedIn()
- && !LoginForm::getLoginToken()->match( $request->getVal( 'wpLoginOnChangeToken' ) )
- ) {
- // Potential CSRF (bug 62497)
- return false;
- }
-
- if ( $request->getCheck( 'wpCancel' ) ) {
- $returnto = $request->getVal( 'returnto' );
- $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
- if ( !$titleObj instanceof Title ) {
- $titleObj = Title::newMainPage();
- }
- $query = $request->getVal( 'returntoquery' );
- $this->getOutput()->redirect( $titleObj->getFullURL( $query ) );
-
- return true;
- }
-
- $this->mUserName = $request->getVal( 'wpName', $this->getUser()->getName() );
- $this->mDomain = $wgAuth->getDomain();
-
- if ( !$wgAuth->allowPasswordChange() ) {
- throw new ErrorPageError( 'changepassword', 'resetpass_forbidden' );
- }
-
- $status = $this->attemptReset( $data['Password'], $data['NewPassword'], $data['Retype'] );
-
- return $status;
- }
-
- public function onSuccess() {
- if ( $this->getUser()->isLoggedIn() ) {
- $this->getOutput()->wrapWikiMsg(
- "<div class=\"successbox\">\n$1\n</div>",
- 'changepassword-success'
- );
- $this->getOutput()->returnToMain();
- } else {
- $request = $this->getRequest();
- LoginForm::clearLoginToken();
- $token = LoginForm::getLoginToken()->toString();
- $data = [
- 'action' => 'submitlogin',
- 'wpName' => $this->mUserName,
- 'wpDomain' => $this->mDomain,
- 'wpLoginToken' => $token,
- 'wpPassword' => $request->getVal( 'wpNewPassword' ),
- ] + $request->getValues( 'wpRemember', 'returnto', 'returntoquery' );
- $login = new LoginForm( new DerivativeRequest( $request, $data, true ) );
- $login->setContext( $this->getContext() );
- $login->execute( null );
- }
- }
-
- /**
- * Checks the new password if it meets the requirements for passwords and set
- * it as a current password, otherwise set the passed Status object to fatal
- * and doesn't change anything
- *
- * @param string $oldpass The current (temporary) password.
- * @param string $newpass The password to set.
- * @param string $retype The string of the retype password field to check with newpass
- * @return Status
- */
- protected function attemptReset( $oldpass, $newpass, $retype ) {
- $isSelf = ( $this->mUserName === $this->getUser()->getName() );
- if ( $isSelf ) {
- $user = $this->getUser();
- } else {
- $user = User::newFromName( $this->mUserName );
- }
-
- if ( !$user || $user->isAnon() ) {
- return Status::newFatal( $this->msg( 'nosuchusershort', $this->mUserName ) );
- }
-
- if ( $newpass !== $retype ) {
- Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'badretype' ] );
- return Status::newFatal( $this->msg( 'badretype' ) );
- }
-
- $throttleInfo = LoginForm::incrementLoginThrottle( $this->mUserName );
- if ( $throttleInfo ) {
- return Status::newFatal( $this->msg( 'changepassword-throttled' )
- ->durationParams( $throttleInfo['wait'] )
- );
- }
-
- // @todo Make these separate messages, since the message is written for both cases
- if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) {
- Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'wrongpassword' ] );
- return Status::newFatal( $this->msg( 'resetpass-wrong-oldpass' ) );
- }
-
- // User is resetting their password to their old password
- if ( $oldpass === $newpass ) {
- return Status::newFatal( $this->msg( 'resetpass-recycled' ) );
- }
-
- // Do AbortChangePassword after checking mOldpass, so we don't leak information
- // by possibly aborting a new password before verifying the old password.
- $abortMsg = 'resetpass-abort-generic';
- if ( !Hooks::run( 'AbortChangePassword', [ $user, $oldpass, $newpass, &$abortMsg ] ) ) {
- Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'abortreset' ] );
- return Status::newFatal( $this->msg( $abortMsg ) );
- }
-
- // Please reset throttle for successful logins, thanks!
- LoginForm::clearLoginThrottle( $this->mUserName );
-
- try {
- $user->setPassword( $newpass );
- Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'success' ] );
- } catch ( PasswordError $e ) {
- Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'error' ] );
- return Status::newFatal( new RawMessage( $e->getMessage() ) );
- }
-
- if ( $isSelf ) {
- // This is needed to keep the user connected since
- // changing the password also modifies the user's token.
- $remember = $this->getRequest()->getCookie( 'Token' ) !== null;
- $user->setCookies( null, null, $remember );
- }
- $user->saveSettings();
- $this->resetPasswordExpiration( $user );
- return Status::newGood();
- }
-
- public function requiresUnblock() {
- return false;
- }
-
- protected function getGroupName() {
- return 'users';
- }
-
- /**
- * For resetting user password expiration, until AuthManager comes along
- * @param User $user
- */
- private function resetPasswordExpiration( User $user ) {
- global $wgPasswordExpirationDays;
- $newExpire = null;
- if ( $wgPasswordExpirationDays ) {
- $newExpire = wfTimestamp(
- TS_MW,
- time() + ( $wgPasswordExpirationDays * 24 * 3600 )
- );
- }
- // Give extensions a chance to force an expiration
- Hooks::run( 'ResetPasswordExpiration', [ $this, &$newExpire ] );
- $dbw = wfGetDB( DB_MASTER );
- $dbw->update(
- 'user',
- [ 'user_password_expires' => $dbw->timestampOrNull( $newExpire ) ],
- [ 'user_id' => $user->getId() ],
- __METHOD__
- );
- }
-
- protected function getDisplayFormat() {
- return 'ooui';
+ parent::__construct( 'ChangePassword', 'ChangeCredentials',
+ PasswordAuthenticationRequest::class, [ 'returnto', 'returntoquery' ] );
}
}
<?php
/**
- * Redirect page: Special:CreateAccount --> Special:UserLogin/signup.
+ * Implements Special:CreateAccount
*
* 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
* @ingroup SpecialPage
*/
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Logger\LoggerFactory;
+use Psr\Log\LogLevel;
+
/**
- * Redirect page: Special:CreateAccount --> Special:UserLogin/signup.
- * @todo FIXME: This (and the rest of the login frontend) needs to die a horrible painful death
+ * Implements Special:CreateAccount
*
* @ingroup SpecialPage
*/
-class SpecialCreateAccount extends SpecialRedirectToSpecial {
- function __construct() {
- parent::__construct(
- 'CreateAccount',
- 'Userlogin',
- 'signup',
- [ 'returnto', 'returntoquery', 'uselang' ]
- );
- }
+class SpecialCreateAccount extends LoginSignupSpecialPage {
+ protected static $allowedActions = [
+ AuthManager::ACTION_CREATE,
+ AuthManager::ACTION_CREATE_CONTINUE
+ ];
- public function doesWrites() {
- return true;
+ protected static $messages = [
+ 'authform-newtoken' => 'nocookiesfornew',
+ 'authform-notoken' => 'sessionfailure',
+ 'authform-wrongtoken' => 'sessionfailure',
+ ];
+
+ public function __construct() {
+ parent::__construct( 'CreateAccount' );
}
- // No reason to hide this link on Special:Specialpages
- public function isListed() {
+ public function doesWrites() {
return true;
}
return $user->isAllowed( 'createaccount' );
}
+ public function checkPermissions() {
+ parent::checkPermissions();
+
+ $user = $this->getUser();
+ $status = AuthManager::singleton()->checkAccountCreatePermissions( $user );
+ if ( !$status->isGood() ) {
+ throw new ErrorPageError( 'createacct-error', $status->getMessage() );
+ }
+ }
+
+ protected function getLoginSecurityLevel() {
+ return false;
+ }
+
+ protected function getDefaultAction( $subPage ) {
+ return AuthManager::ACTION_CREATE;
+ }
+
+ public function getDescription() {
+ return $this->msg( 'createaccount' )->text();
+ }
+
+ protected function isSignup() {
+ return true;
+ }
+
+ /**
+ * Run any hooks registered for logins, then display a message welcoming
+ * the user.
+ * @param bool $direct True if the action was successful just now; false if that happened
+ * pre-redirection (so this handler was called already)
+ * @param StatusValue|null $extraMessages
+ */
+ protected function successfulAction( $direct = false, $extraMessages = null ) {
+ $session = $this->getRequest()->getSession();
+ $user = $this->targetUser ?: $this->getUser();
+
+ if ( $direct ) {
+ # Only save preferences if the user is not creating an account for someone else.
+ if ( !$this->proxyAccountCreation ) {
+ Hooks::run( 'AddNewAccount', [ $user, false ] );
+
+ // If the user does not have a session cookie at this point, they probably need to
+ // do something to their browser.
+ if ( !$this->hasSessionCookie() ) {
+ $this->mainLoginForm( [ /*?*/ ], $session->getProvider()->whyNoSession() );
+ // TODO something more specific? This used to use nocookiesnew
+ // FIXME should redirect to login page instead?
+ return;
+ }
+ } else {
+ $byEmail = false; // FIXME no way to set this
+
+ Hooks::run( 'AddNewAccount', [ $user, $byEmail ] );
+
+ $out = $this->getOutput();
+ $out->setPageTitle( $this->msg( $byEmail ? 'accmailtitle' : 'accountcreated' ) );
+ if ( $byEmail ) {
+ $out->addWikiMsg( 'accmailtext', $user->getName(), $user->getEmail() );
+ } else {
+ $out->addWikiMsg( 'accountcreatedtext', $user->getName() );
+ }
+ $out->addReturnTo( $this->getPageTitle() );
+ return;
+ }
+ }
+
+ $this->clearToken();
+
+ # Run any hooks; display injected HTML
+ $injected_html = '';
+ $welcome_creation_msg = 'welcomecreation-msg';
+ Hooks::run( 'UserLoginComplete', [ &$user, &$injected_html ] );
+
+ /**
+ * Let any extensions change what message is shown.
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforeWelcomeCreation
+ * @since 1.18
+ */
+ Hooks::run( 'BeforeWelcomeCreation', [ &$welcome_creation_msg, &$injected_html ] );
+
+ $this->showSuccessPage( 'signup', $this->msg( 'welcomeuser', $this->getUser()->getName() ),
+ $welcome_creation_msg, $injected_html, $extraMessages );
+ }
+
+ protected function getToken() {
+ return $this->getRequest()->getSession()->getToken( '', 'createaccount' );
+ }
+
+ protected function clearToken() {
+ return $this->getRequest()->getSession()->resetToken( 'createaccount' );
+ }
+
+ protected function getTokenName() {
+ return 'wpCreateaccountToken';
+ }
+
protected function getGroupName() {
return 'login';
}
+
+ protected function logAuthResult( $success, $status = null ) {
+ LoggerFactory::getInstance( 'authmanager-stats' )->info( 'Account creation attempt', [
+ 'event' => 'accountcreation',
+ 'successful' => $success,
+ 'status' => $status,
+ ] );
+ }
}
--- /dev/null
+<?php
+
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\AuthManager;
+
+/**
+ * Links/unlinks external accounts to the current user.
+ *
+ * To interact with this page, account providers need to register themselves with AuthManager.
+ */
+class SpecialLinkAccounts extends AuthManagerSpecialPage {
+ protected static $allowedActions = [
+ AuthManager::ACTION_LINK, AuthManager::ACTION_LINK_CONTINUE,
+ ];
+
+ public function __construct() {
+ parent::__construct( 'LinkAccounts' );
+ }
+
+ protected function getGroupName() {
+ return 'users';
+ }
+
+ public function isListed() {
+ return AuthManager::singleton()->canLinkAccounts();
+ }
+
+ protected function getRequestBlacklist() {
+ return $this->getConfig()->get( 'ChangeCredentialsBlacklist' );
+ }
+
+ /**
+ * @param null|string $subPage
+ * @throws MWException
+ * @throws PermissionsError
+ */
+ public function execute( $subPage ) {
+ $this->setHeaders();
+ $this->loadAuth( $subPage );
+
+ if ( !$this->isActionAllowed( $this->authAction ) ) {
+ if ( $this->authAction === AuthManager::ACTION_LINK ) {
+ // looks like no linking provider is installed or willing to take this user
+ $titleMessage = wfMessage( 'cannotlink-no-provider-title' );
+ $errorMessage = wfMessage( 'cannotlink-no-provider' );
+ throw new ErrorPageError( $titleMessage, $errorMessage );
+ } else {
+ // user probably back-button-navigated into an auth session that no longer exists
+ // FIXME would be nice to show a message
+ $this->getOutput()->redirect( $this->getPageTitle()->getFullURL( '', false,
+ PROTO_HTTPS ) );
+ return;
+ }
+ }
+
+ $this->outputHeader();
+
+ $status = $this->trySubmit();
+
+ if ( $status === false || !$status->isOK() ) {
+ $this->displayForm( $status );
+ return;
+ }
+
+ $response = $status->getValue();
+
+ switch ( $response->status ) {
+ case AuthenticationResponse::PASS:
+ $this->success();
+ break;
+ case AuthenticationResponse::FAIL:
+ $this->loadAuth( '', AuthManager::ACTION_LINK, true );
+ $this->displayForm( StatusValue::newFatal( $response->message ) );
+ break;
+ case AuthenticationResponse::REDIRECT:
+ $this->getOutput()->redirect( $response->redirectTarget );
+ break;
+ case AuthenticationResponse::UI:
+ $this->authAction = AuthManager::ACTION_LINK_CONTINUE;
+ $this->authRequests = $response->neededRequests;
+ $this->displayForm( StatusValue::newFatal( $response->message ) );
+ break;
+ default:
+ throw new LogicException( 'invalid AuthenticationResponse' );
+ }
+ }
+
+ protected function getDefaultAction( $subPage ) {
+ return AuthManager::ACTION_LINK;
+ }
+
+ /**
+ * @param AuthenticationRequest[] $requests
+ * @param string $action AuthManager action name, should be ACTION_LINK or ACTION_LINK_CONTINUE
+ * @return HTMLForm
+ */
+ protected function getAuthForm( array $requests, $action ) {
+ $form = parent::getAuthForm( $requests, $action );
+ $form->setSubmitTextMsg( 'linkaccounts-submit' );
+ return $form;
+ }
+
+ /**
+ * Show a success message.
+ */
+ protected function success() {
+ $this->loadAuth( '', AuthManager::ACTION_LINK, true );
+ $this->displayForm( StatusValue::newFatal( $this->msg( 'linkaccounts-success-text' ) ) );
+ }
+}
}
public function doesWrites() {
- return true;
+ return false;
}
public function requiresWrite() {
if ( !is_writable( dirname( $this->getConfig()->get( 'ReadOnlyFile' ) ) ) ) {
throw new ErrorPageError( 'lockdb', 'lockfilenotwritable' );
}
+ if ( file_exists( $this->getConfig()->get( 'ReadOnlyFile' ) ) ) {
+ throw new ErrorPageError( 'lockdb', 'databaselocked' );
+ }
}
protected function getFormFields() {
}
protected function alterForm( HTMLForm $form ) {
- $form->setWrapperLegend( false );
- $form->setHeaderText( $this->msg( 'lockdbtext' )->parseAsBlock() );
- $form->setSubmitTextMsg( 'lockbtn' );
+ $form->setWrapperLegend( false )
+ ->setHeaderText( $this->msg( 'lockdbtext' )->parseAsBlock() )
+ ->setSubmitTextMsg( 'lockbtn' );
}
public function onSubmit( array $data ) {
$out->addWikiMsg( 'lockdbsuccesstext' );
}
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
protected function getGroupName() {
return 'wiki';
}
}
/**
- * Return HTML to put just before the results.
+ * Generate and output the form
*/
function getPageHeader() {
- return Xml::openElement(
- 'form',
- [ 'id' => 'specialmimesearch', 'method' => 'get', 'action' => wfScript() ]
- ) .
- Xml::openElement( 'fieldset' ) .
- Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ) .
- Xml::element( 'legend', null, $this->msg( 'mimesearch' )->text() ) .
- Xml::inputLabel( $this->msg( 'mimetype' )->text(), 'mime', 'mime', 20, $this->mime ) .
- ' ' .
- Xml::submitButton( $this->msg( 'ilsubmit' )->text() ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' );
+ $formDescriptor = [
+ 'mime' => [
+ 'type' => 'text',
+ 'name' => 'mime',
+ 'label-message' => 'mimetype',
+ 'required' => true,
+ 'default' => $this->mime,
+ ],
+ ];
+
+ $form = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+ ->setWrapperLegendMsg( 'mimesearch' )
+ ->setSubmitTextMsg( 'ilsubmit' )
+ ->setAction( $this->getPageTitle()->getLocalURL() )
+ ->setMethod( 'get' )
+ ->prepareForm()
+ ->displayForm( false );
}
public function execute( $par ) {
) {
$this->setHeaders();
$this->outputHeader();
- $this->getOutput()->addHTML( $this->getPageHeader() );
+ $this->getPageHeader();
return;
}
* @ingroup SpecialPage
*/
class SpecialMergeHistory extends SpecialPage {
- /** @var string */
- protected $mAction;
+ /** @var FormOptions */
+ protected $mOpts;
- /** @var string */
- protected $mTarget;
+ /** @var Status */
+ protected $mStatus;
- /** @var string */
- protected $mDest;
-
- /** @var string */
- protected $mTimestamp;
-
- /** @var int */
- protected $mTargetID;
-
- /** @var int */
- protected $mDestID;
-
- /** @var string */
- protected $mComment;
-
- /** @var bool Was posted? */
- protected $mMerge;
-
- /** @var bool Was submitted? */
- protected $mSubmitted;
-
- /** @var Title */
- protected $mTargetObj;
-
- /** @var Title */
- protected $mDestObj;
+ /** @var Title|null */
+ protected $mTargetObj, $mDestObj;
/** @var int[] */
public $prevId;
return true;
}
- /**
- * @return void
- */
- private function loadRequestParams() {
- $request = $this->getRequest();
- $this->mAction = $request->getVal( 'action' );
- $this->mTarget = $request->getVal( 'target' );
- $this->mDest = $request->getVal( 'dest' );
- $this->mSubmitted = $request->getBool( 'submitted' );
-
- $this->mTargetID = intval( $request->getVal( 'targetID' ) );
- $this->mDestID = intval( $request->getVal( 'destID' ) );
- $this->mTimestamp = $request->getVal( 'mergepoint' );
- if ( !preg_match( '/[0-9]{14}/', $this->mTimestamp ) ) {
- $this->mTimestamp = '';
- }
- $this->mComment = $request->getText( 'wpComment' );
-
- $this->mMerge = $request->wasPosted()
- && $this->getUser()->matchEditToken( $request->getVal( 'wpEditToken' ) );
-
- // target page
- if ( $this->mSubmitted ) {
- $this->mTargetObj = Title::newFromText( $this->mTarget );
- $this->mDestObj = Title::newFromText( $this->mDest );
- } else {
- $this->mTargetObj = null;
- $this->mDestObj = null;
- }
- }
-
public function execute( $par ) {
$this->useTransactionalTimeLimit();
$this->checkPermissions();
$this->checkReadOnly();
- $this->loadRequestParams();
-
$this->setHeaders();
$this->outputHeader();
- if ( $this->mTargetID && $this->mDestID && $this->mAction == 'submit' && $this->mMerge ) {
+ $this->addHelpLink( 'Help:Merge history' );
+
+ $opts = new FormOptions();
+
+ $opts->add( 'target', '' );
+ $opts->add( 'dest', '' );
+ $opts->add( 'target', '' );
+ $opts->add( 'mergepoint', '' );
+ $opts->add( 'reason', '' );
+ $opts->add( 'merge', false );
+
+ $opts->fetchValuesFromRequest( $this->getRequest() );
+
+ $target = $opts->getValue( 'target' );
+ $dest = $opts->getValue( 'dest' );
+ $targetObj = Title::newFromText( $target );
+ $destObj = Title::newFromText( $dest );
+ $status = Status::newGood();
+
+ $this->mOpts = $opts;
+ $this->mTargetObj = $targetObj;
+ $this->mDestObj = $destObj;
+
+ if ( $opts->getValue( 'merge' ) && $targetObj &&
+ $destObj && $opts->getValue( 'mergepoint' ) !== '' ) {
$this->merge();
return;
}
- if ( !$this->mSubmitted ) {
+ if ( $target === '' && $dest === '' ) {
$this->showMergeForm();
return;
}
- $errors = [];
- if ( !$this->mTargetObj instanceof Title ) {
- $errors[] = $this->msg( 'mergehistory-invalid-source' )->parseAsBlock();
- } elseif ( !$this->mTargetObj->exists() ) {
- $errors[] = $this->msg( 'mergehistory-no-source',
- wfEscapeWikiText( $this->mTargetObj->getPrefixedText() )
- )->parseAsBlock();
+ if ( !$targetObj instanceof Title ) {
+ $status->merge( Status::newFatal( 'mergehistory-invalid-source' ) );
+ } elseif ( !$targetObj->exists() ) {
+ $status->merge( Status::newFatal( 'mergehistory-no-source',
+ wfEscapeWikiText( $targetObj->getPrefixedText() )
+ ) );
}
- if ( !$this->mDestObj instanceof Title ) {
- $errors[] = $this->msg( 'mergehistory-invalid-destination' )->parseAsBlock();
- } elseif ( !$this->mDestObj->exists() ) {
- $errors[] = $this->msg( 'mergehistory-no-destination',
- wfEscapeWikiText( $this->mDestObj->getPrefixedText() )
- )->parseAsBlock();
+ if ( !$destObj instanceof Title ) {
+ $status->merge( Status::newFatal( 'mergehistory-invalid-destination' ) );
+ } elseif ( !$destObj->exists() ) {
+ $status->merge( Status::newFatal( 'mergehistory-no-destination',
+ wfEscapeWikiText( $destObj->getPrefixedText() )
+ ) );
}
- if ( $this->mTargetObj && $this->mDestObj && $this->mTargetObj->equals( $this->mDestObj ) ) {
- $errors[] = $this->msg( 'mergehistory-same-destination' )->parseAsBlock();
+ if ( $targetObj && $destObj && $targetObj->equals( $destObj ) ) {
+ $status->merge( Status::newFatal( 'mergehistory-same-destination' ) );
}
- if ( count( $errors ) ) {
- $this->showMergeForm();
- $this->getOutput()->addHTML( implode( "\n", $errors ) );
- } else {
+ $this->mStatus = $status;
+
+ $this->showMergeForm();
+
+ if ( $status->isOK() ) {
$this->showHistory();
}
}
function showMergeForm() {
- $out = $this->getOutput();
- $out->addWikiMsg( 'mergehistory-header' );
-
- $out->addHTML(
- Xml::openElement( 'form', [
- 'method' => 'get',
- 'action' => wfScript() ] ) .
- '<fieldset>' .
- Xml::element( 'legend', [],
- $this->msg( 'mergehistory-box' )->text() ) .
- Html::hidden( 'title', $this->getPageTitle()->getPrefixedDBkey() ) .
- Html::hidden( 'submitted', '1' ) .
- Html::hidden( 'mergepoint', $this->mTimestamp ) .
- Xml::openElement( 'table' ) .
- '<tr>
- <td>' . Xml::label( $this->msg( 'mergehistory-from' )->text(), 'target' ) . '</td>
- <td>' . Xml::input( 'target', 30, $this->mTarget, [ 'id' => 'target' ] ) . '</td>
- </tr><tr>
- <td>' . Xml::label( $this->msg( 'mergehistory-into' )->text(), 'dest' ) . '</td>
- <td>' . Xml::input( 'dest', 30, $this->mDest, [ 'id' => 'dest' ] ) . '</td>
- </tr><tr><td>' .
- Xml::submitButton( $this->msg( 'mergehistory-go' )->text() ) .
- '</td></tr>' .
- Xml::closeElement( 'table' ) .
- '</fieldset>' .
- '</form>'
- );
-
- $this->addHelpLink( 'Help:Merge history' );
+ $formDescriptor = [
+ 'target' => [
+ 'type' => 'title',
+ 'name' => 'target',
+ 'label-message' => 'mergehistory-from',
+ 'required' => true,
+ ],
+
+ 'dest' => [
+ 'type' => 'title',
+ 'name' => 'dest',
+ 'label-message' => 'mergehistory-into',
+ 'required' => true,
+ ],
+ ];
+
+ $form = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+ ->setIntro( $this->msg( 'mergehistory-header' ) )
+ ->setWrapperLegendMsg( 'mergehistory-box' )
+ ->setSubmitTextMsg( 'mergehistory-go' )
+ ->setMethod( 'post' )
+ ->prepareForm()
+ ->displayForm( $this->mStatus );
}
private function showHistory() {
- $this->showMergeForm();
-
# List all stored revisions
$revisions = new MergeHistoryPager(
$this, [], $this->mTargetObj, $this->mDestObj
$haveRevisions = $revisions && $revisions->getNumRows() > 0;
$out = $this->getOutput();
- $titleObj = $this->getPageTitle();
- $action = $titleObj->getLocalURL( [ 'action' => 'submit' ] );
- # Start the form here
- $top = Xml::openElement(
- 'form',
- [
- 'method' => 'post',
- 'action' => $action,
- 'id' => 'merge'
- ]
- );
- $out->addHTML( $top );
-
- if ( $haveRevisions ) {
- # Format the user-visible controls (comment field, submission button)
- # in a nice little table
- $table =
- Xml::openElement( 'fieldset' ) .
- $this->msg( 'mergehistory-merge', $this->mTargetObj->getPrefixedText(),
- $this->mDestObj->getPrefixedText() )->parse() .
- Xml::openElement( 'table', [ 'id' => 'mw-mergehistory-table' ] ) .
- '<tr>
- <td class="mw-label">' .
- Xml::label( $this->msg( 'mergehistory-reason' )->text(), 'wpComment' ) .
- '</td>
- <td class="mw-input">' .
- Xml::input( 'wpComment', 50, $this->mComment, [ 'id' => 'wpComment' ] ) .
- '</td>
- </tr>
- <tr>
- <td> </td>
- <td class="mw-submit">' .
- Xml::submitButton(
- $this->msg( 'mergehistory-submit' )->text(),
- [ 'name' => 'merge', 'id' => 'mw-merge-submit' ]
- ) .
- '</td>
- </tr>' .
- Xml::closeElement( 'table' ) .
- Xml::closeElement( 'fieldset' );
-
- $out->addHTML( $table );
- }
-
- $out->addHTML(
- '<h2 id="mw-mergehistory">' .
- $this->msg( 'mergehistory-list' )->escaped() . "</h2>\n"
- );
+ $header = '<h2 id="mw-mergehistory">' .
+ $this->msg( 'mergehistory-list' )->escaped() . "</h2>\n";
if ( $haveRevisions ) {
- $out->addHTML( $revisions->getNavigationBar() );
- $out->addHTML( '<ul>' );
- $out->addHTML( $revisions->getBody() );
- $out->addHTML( '</ul>' );
- $out->addHTML( $revisions->getNavigationBar() );
+ $hiddenFields = [
+ 'merge' => true,
+ 'target' => $this->mOpts->getValue( 'target' ),
+ 'dest' => $this->mOpts->getValue( 'dest' ),
+ ];
+
+ $formDescriptor = [
+ 'reason' => [
+ 'type' => 'text',
+ 'name' => 'reason',
+ 'label-message' => 'mergehistory-reason',
+ ],
+ ];
+
+ $mergeText = $this->msg( 'mergehistory-merge',
+ $this->mTargetObj->getPrefixedText(),
+ $this->mDestObj->getPrefixedText()
+ )->parse();
+
+ $history = $header .
+ $revisions->getNavigationBar() .
+ '<ul>' .
+ $revisions->getBody() .
+ '</ul>' .
+ $revisions->getNavigationBar();
+
+ $form = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+ ->addHiddenFields( $hiddenFields )
+ ->setPreText( $mergeText )
+ ->setFooterText( $history )
+ ->setSubmitTextMsg( 'mergehistory-submit' )
+ ->setMethod( 'post' )
+ ->prepareForm()
+ ->displayForm( false );
} else {
+ $out->addHTML( $header );
$out->addWikiMsg( 'mergehistory-empty' );
}
$mergeLogPage = new LogPage( 'merge' );
$out->addHTML( '<h2>' . $mergeLogPage->getName()->escaped() . "</h2>\n" );
LogEventsList::showLogExtract( $out, 'merge', $this->mTargetObj );
-
- # When we submit, go by page ID to avoid some nasty but unlikely collisions.
- # Such would happen if a page was renamed after the form loaded, but before submit
- $misc = Html::hidden( 'targetID', $this->mTargetObj->getArticleID() );
- $misc .= Html::hidden( 'destID', $this->mDestObj->getArticleID() );
- $misc .= Html::hidden( 'target', $this->mTarget );
- $misc .= Html::hidden( 'dest', $this->mDest );
- $misc .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() );
- $misc .= Xml::closeElement( 'form' );
- $out->addHTML( $misc );
-
- return true;
}
function formatRevisionRow( $row ) {
$last = $this->msg( 'last' )->escaped();
$ts = wfTimestamp( TS_MW, $row->rev_timestamp );
- $checkBox = Xml::radio( 'mergepoint', $ts, ( $this->mTimestamp === $ts ) );
+ $checkBox = Xml::radio( 'mergepoint', $ts, ( $this->mOpts->getValue( 'mergepoint' ) === $ts ) );
$user = $this->getUser();
* @return bool Success
*/
function merge() {
+ $opts = $this->mOpts;
+
# Get the titles directly from the IDs, in case the target page params
# were spoofed. The queries are done based on the IDs, so it's best to
# keep it consistent...
- $targetTitle = Title::newFromID( $this->mTargetID );
- $destTitle = Title::newFromID( $this->mDestID );
- if ( is_null( $targetTitle ) || is_null( $destTitle ) ) {
- return false; // validate these
- }
- if ( $targetTitle->getArticleID() == $destTitle->getArticleID() ) {
+ $targetObj = $this->mTargetObj;
+ $destObj = $this->mDestObj;
+
+ if ( is_null( $targetObj ) || is_null( $destObj ) ||
+ $targetObj->getArticleID() == $destObj->getArticleID() ) {
return false;
}
// MergeHistory object
- $mh = new MergeHistory( $targetTitle, $destTitle, $this->mTimestamp );
+ $mh = new MergeHistory( $targetObj, $destObj, $opts->getValue( 'mergepoint' ) );
// Merge!
- $mergeStatus = $mh->merge( $this->getUser(), $this->mComment );
+ $mergeStatus = $mh->merge( $this->getUser(), $opts->getValue( 'reason' ) );
if ( !$mergeStatus->isOK() ) {
// Failed merge
$this->getOutput()->addWikiMsg( $mergeStatus->getMessage() );
}
$targetLink = Linker::link(
- $targetTitle,
+ $targetObj,
null,
[],
[ 'redirect' => 'no' ]
$this->getOutput()->addWikiMsg( $this->msg( 'mergehistory-done' )
->rawParams( $targetLink )
- ->params( $destTitle->getPrefixedText() )
+ ->params( $destObj->getPrefixedText() )
->numParams( $mh->getMergedRevisionCount() )
);
* @ingroup SpecialPage
*/
+use MediaWiki\Auth\AuthManager;
+
/**
- * Special page for requesting a password reset email
+ * Special page for requesting a password reset email.
+ *
+ * Requires the TemporaryPasswordPrimaryAuthenticationProvider and the
+ * EmailNotificationSecondaryAuthenticationProvider (or something providing equivalent
+ * functionality) to be enabled.
*
* @ingroup SpecialPage
*/
class SpecialPasswordReset extends FormSpecialPage {
- /**
- * @var Message
- */
- private $email;
+ /** @var PasswordReset */
+ private $passwordReset;
/**
- * @var User
+ * @var string[] Temporary storage for the passwords which have been sent out, keyed by username.
*/
- private $firstUser;
+ private $passwords = [];
/**
* @var Status
public function __construct() {
parent::__construct( 'PasswordReset', 'editmyprivateinfo' );
+ $this->passwordReset = new PasswordReset( $this->getConfig(), AuthManager::singleton() );
}
public function doesWrites() {
}
public function userCanExecute( User $user ) {
- return $this->canChangePassword( $user ) === true && parent::userCanExecute( $user );
+ return $this->passwordReset->isAllowed( $user )->isGood();
}
public function checkExecutePermissions( User $user ) {
- $error = $this->canChangePassword( $user );
- if ( is_string( $error ) ) {
- throw new ErrorPageError( 'internalerror', $error );
- } elseif ( !$error ) {
- throw new ErrorPageError( 'internalerror', 'resetpass_forbidden' );
+ $status = Status::wrap( $this->passwordReset->isAllowed( $user ) );
+ if ( !$status->isGood() ) {
+ throw new ErrorPageError( 'internalerror', $status->getMessage() );
}
parent::checkExecutePermissions( $user );
}
protected function getFormFields() {
- global $wgAuth;
$resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
$a = [];
if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) {
];
}
- if ( isset( $resetRoutes['domain'] ) && $resetRoutes['domain'] ) {
- $domains = $wgAuth->domainList();
- $a['Domain'] = [
- 'type' => 'select',
- 'options' => $domains,
- 'label-message' => 'passwordreset-domain',
- ];
- }
-
if ( $this->getUser()->isAllowed( 'passwordreset' ) ) {
$a['Capture'] = [
'type' => 'check',
if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) {
$i++;
}
- if ( isset( $resetRoutes['domain'] ) && $resetRoutes['domain'] ) {
- $i++;
- }
$message = ( $i > 1 ) ? 'passwordreset-text-many' : 'passwordreset-text-one';
* @param array $data
* @throws MWException
* @throws ThrottledError|PermissionsError
- * @return bool|array
+ * @return Status
*/
public function onSubmit( array $data ) {
- global $wgAuth, $wgMinimalPasswordLength;
-
- if ( isset( $data['Domain'] ) ) {
- if ( $wgAuth->validDomain( $data['Domain'] ) ) {
- $wgAuth->setDomain( $data['Domain'] );
- } else {
- $wgAuth->setDomain( 'invaliddomain' );
- }
- }
-
if ( isset( $data['Capture'] ) && !$this->getUser()->isAllowed( 'passwordreset' ) ) {
// The user knows they don't have the passwordreset permission,
// but they tried to spoof the form. That's naughty
throw new PermissionsError( 'passwordreset' );
}
- /**
- * @var $firstUser User
- * @var $users User[]
- */
-
- if ( isset( $data['Username'] ) && $data['Username'] !== '' ) {
- $method = 'username';
- $users = [ User::newFromName( $data['Username'] ) ];
- } elseif ( isset( $data['Email'] )
- && $data['Email'] !== ''
- && Sanitizer::validateEmail( $data['Email'] )
- ) {
- $method = 'email';
- $res = wfGetDB( DB_SLAVE )->select(
- 'user',
- User::selectFields(),
- [ 'user_email' => $data['Email'] ],
- __METHOD__
- );
-
- if ( $res ) {
- $users = [];
-
- foreach ( $res as $row ) {
- $users[] = User::newFromRow( $row );
- }
- } else {
- // Some sort of database error, probably unreachable
- throw new MWException( 'Unknown database error in ' . __METHOD__ );
- }
- } else {
- // The user didn't supply any data
- return false;
- }
-
- // Check for hooks (captcha etc), and allow them to modify the users list
- $error = [];
- if ( !Hooks::run( 'SpecialPasswordResetOnSubmit', [ &$users, $data, &$error ] ) ) {
- return [ $error ];
- }
-
- $this->method = $method;
-
- if ( count( $users ) == 0 ) {
- if ( $method == 'email' ) {
- // Don't reveal whether or not an email address is in use
- return true;
- } else {
- return [ 'noname' ];
- }
- }
-
- $firstUser = $users[0];
+ $username = isset( $data['Username'] ) ? $data['Username'] : null;
+ $email = isset( $data['Email'] ) ? $data['Email'] : null;
+ $capture = !empty( $data['Capture'] );
- if ( !$firstUser instanceof User || !$firstUser->getId() ) {
- // Don't parse username as wikitext (bug 65501)
- return [ [ 'nosuchuser', wfEscapeWikiText( $data['Username'] ) ] ];
+ $this->method = $username ? 'username' : 'email';
+ $this->result = Status::wrap(
+ $this->passwordReset->execute( $this->getUser(), $username, $email, $capture ) );
+ if ( $capture && $this->result->isOK() ) {
+ $this->passwords = $this->result->getValue();
}
- // Check against the rate limiter
- if ( $this->getUser()->pingLimiter( 'mailpassword' ) ) {
+ if ( $this->result->hasMessage( 'actionthrottledtext' ) ) {
throw new ThrottledError;
}
- // Check against password throttle
- foreach ( $users as $user ) {
- if ( $user->isPasswordReminderThrottled() ) {
-
- # Round the time in hours to 3 d.p., in case someone is specifying
- # minutes or seconds.
- return [ [
- 'throttled-mailpassword',
- round( $this->getConfig()->get( 'PasswordReminderResendTime' ), 3 )
- ] ];
- }
- }
-
- // All the users will have the same email address
- if ( $firstUser->getEmail() == '' ) {
- // This won't be reachable from the email route, so safe to expose the username
- return [ [ 'noemail', wfEscapeWikiText( $firstUser->getName() ) ] ];
- }
-
- // We need to have a valid IP address for the hook, but per bug 18347, we should
- // send the user's name if they're logged in.
- $ip = $this->getRequest()->getIP();
- if ( !$ip ) {
- return [ 'badipaddress' ];
- }
- $caller = $this->getUser();
- Hooks::run( 'User::mailPasswordInternal', [ &$caller, &$ip, &$firstUser ] );
- $username = $caller->getName();
- $msg = IP::isValid( $username )
- ? 'passwordreset-emailtext-ip'
- : 'passwordreset-emailtext-user';
-
- // Send in the user's language; which should hopefully be the same
- $userLanguage = $firstUser->getOption( 'language' );
-
- $passwords = [];
- foreach ( $users as $user ) {
- $password = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
- $user->setNewpassword( $password );
- $user->saveSettings();
- $passwords[] = $this->msg( 'passwordreset-emailelement', $user->getName(), $password )
- ->inLanguage( $userLanguage )->text(); // We'll escape the whole thing later
- }
- $passwordBlock = implode( "\n\n", $passwords );
-
- $this->email = $this->msg( $msg )->inLanguage( $userLanguage );
- $this->email->params(
- $username,
- $passwordBlock,
- count( $passwords ),
- '<' . Title::newMainPage()->getCanonicalURL() . '>',
- round( $this->getConfig()->get( 'NewPasswordExpiry' ) / 86400 )
- );
-
- $title = $this->msg( 'passwordreset-emailtitle' )->inLanguage( $userLanguage );
-
- $this->result = $firstUser->sendMail( $title->text(), $this->email->text() );
-
- if ( isset( $data['Capture'] ) && $data['Capture'] ) {
- // Save the user, will be used if an error occurs when sending the email
- $this->firstUser = $firstUser;
- } else {
- // Blank the email if the user is not supposed to see it
- $this->email = null;
- }
-
- if ( $this->result->isGood() ) {
- return true;
- } elseif ( isset( $data['Capture'] ) && $data['Capture'] ) {
- // The email didn't send, but maybe they knew that and that's why they captured it
- return true;
- } else {
- // @todo FIXME: The email wasn't sent, but we have already set
- // the password throttle timestamp, so they won't be able to try
- // again until it expires... :(
- return [ [ 'mailerror', $this->result->getMessage() ] ];
- }
+ return $this->result;
}
public function onSuccess() {
- if ( $this->getUser()->isAllowed( 'passwordreset' ) && $this->email != null ) {
+ if ( $this->getUser()->isAllowed( 'passwordreset' ) && $this->passwords ) {
// @todo Logging
if ( $this->result->isGood() ) {
- $this->getOutput()->addWikiMsg( 'passwordreset-emailsent-capture' );
+ $this->getOutput()->addWikiMsg( 'passwordreset-emailsent-capture2',
+ count( $this->passwords ) );
} else {
- $this->getOutput()->addWikiMsg( 'passwordreset-emailerror-capture',
- $this->result->getMessage(), $this->firstUser->getName() );
+ $this->getOutput()->addWikiMsg( 'passwordreset-emailerror-capture2',
+ $this->result->getMessage(), key( $this->passwords ), count( $this->passwords ) );
}
- $this->getOutput()->addHTML( Html::rawElement( 'pre', [], $this->email->escaped() ) );
+ $this->getOutput()->addHTML( Html::openElement( 'ul' ) );
+ foreach ( $this->passwords as $username => $pwd ) {
+ $this->getOutput()->addHTML( Html::rawElement( 'li', [],
+ htmlspecialchars( $username, ENT_QUOTES )
+ . $this->msg( 'colon-separator' )->text()
+ . htmlspecialchars( $pwd, ENT_QUOTES )
+ ) );
+ }
+ $this->getOutput()->addHTML( Html::closeElement( 'ul' ) );
}
if ( $this->method === 'email' ) {
$this->getOutput()->returnToMain();
}
- protected function canChangePassword( User $user ) {
- global $wgAuth;
- $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
-
- // Maybe password resets are disabled, or there are no allowable routes
- if ( !is_array( $resetRoutes ) ||
- !in_array( true, array_values( $resetRoutes ) )
- ) {
- return 'passwordreset-disabled';
- }
-
- // Maybe the external auth plugin won't allow local password changes
- if ( !$wgAuth->allowPasswordChange() ) {
- return 'resetpass_forbidden';
- }
-
- // Maybe email features have been disabled
- if ( !$this->getConfig()->get( 'EnableEmail' ) ) {
- return 'passwordreset-emaildisabled';
- }
-
- // Maybe the user is blocked (check this here rather than relying on the parent
- // method as we have a more specific error message to use here
- if ( $user->isBlocked() ) {
- return 'blocked-mailpassword';
- }
-
- return true;
- }
-
/**
* Hide the password reset page if resets are disabled.
* @return bool
*/
- function isListed() {
- if ( $this->canChangePassword( $this->getUser() ) === true ) {
+ public function isListed() {
+ if ( $this->passwordReset->isAllowed( $this->getUser() )->isGood() ) {
return parent::isListed();
}
* @file
* @ingroup SpecialPage
*/
+use MediaWiki\MediaWikiServices;
/**
* Implements Special:Prefixindex
$prefixList = $this->getNamespaceKeyAndText( $namespace, $prefix );
$namespaces = $wgContLang->getNamespaces();
$res = null;
+ $n = 0;
+ $nextRow = null;
if ( !$prefixList || !$fromList ) {
$out = $this->msg( 'allpagesbadtitle' )->parseAsBlock();
}
$res = $dbr->select( 'page',
- [ 'page_namespace', 'page_title', 'page_is_redirect' ],
+ array_merge(
+ [ 'page_namespace', 'page_title' ],
+ LinkCache::getSelectFields()
+ ),
$conds,
__METHOD__,
[
// @todo FIXME: Side link to previous
- $n = 0;
if ( $res->numRows() > 0 ) {
$out = Html::openElement( 'ul', [ 'class' => 'mw-prefixindex-list' ] );
+ $linkCache = MediaWikiServices::getInstance()->getLinkCache();
$prefixLength = strlen( $prefix );
- while ( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
- $t = Title::makeTitle( $s->page_namespace, $s->page_title );
- if ( $t ) {
- $displayed = $t->getText();
- // Try not to generate unclickable links
- if ( $this->stripPrefix && $prefixLength !== strlen( $displayed ) ) {
- $displayed = substr( $displayed, $prefixLength );
- }
- $link = ( $s->page_is_redirect ? '<div class="allpagesredirect">' : '' ) .
- Linker::linkKnown(
- $t,
- htmlspecialchars( $displayed ),
- $s->page_is_redirect ? [ 'class' => 'mw-redirect' ] : []
- ) .
- ( $s->page_is_redirect ? '</div>' : '' );
- } else {
- $link = '[[' . htmlspecialchars( $s->page_title ) . ']]';
+ foreach ( $res as $row ) {
+ if ( $n >= $this->maxPerPage ) {
+ $nextRow = $row;
+ break;
}
+ $title = Title::newFromRow( $row );
+ // Make sure it gets into LinkCache
+ $linkCache->addGoodLinkObjFromRow( $title, $row );
+ $displayed = $title->getText();
+ // Try not to generate unclickable links
+ if ( $this->stripPrefix && $prefixLength !== strlen( $displayed ) ) {
+ $displayed = substr( $displayed, $prefixLength );
+ }
+ $link = ( $title->isRedirect() ? '<div class="allpagesredirect">' : '' ) .
+ Linker::linkKnown(
+ $title,
+ htmlspecialchars( $displayed )
+ ) .
+ ( $title->isRedirect() ? '</div>' : '' );
$out .= "<li>$link</li>\n";
$n++;
$topOut = $this->namespacePrefixForm( $namespace, $prefix );
- if ( $res && ( $n == $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
+ if ( $res && ( $n == $this->maxPerPage ) && $nextRow ) {
$query = [
- 'from' => $s->page_title,
+ 'from' => $nextRow->page_title,
'prefix' => $prefix,
'hideredirects' => $this->hideRedirects,
'stripprefix' => $this->stripPrefix,
$nextLink = Linker::linkKnown(
$this->getPageTitle(),
- $this->msg( 'nextpage', str_replace( '_', ' ', $s->page_title ) )->escaped(),
+ $this->msg( 'nextpage', str_replace( '_', ' ', $nextRow->page_title ) )->escaped(),
[],
$query
);
--- /dev/null
+<?php
+
+use MediaWiki\Auth\AuthManager;
+
+/**
+ * Special change to remove credentials (such as a two-factor token).
+ */
+class SpecialRemoveCredentials extends SpecialChangeCredentials {
+ protected static $allowedActions = [ AuthManager::ACTION_REMOVE ];
+
+ protected static $messagePrefix = 'removecredentials';
+
+ protected static $loadUserData = false;
+
+ public function __construct() {
+ parent::__construct( 'RemoveCredentials' );
+ }
+
+ protected function getDefaultAction( $subPage ) {
+ return AuthManager::ACTION_REMOVE;
+ }
+
+ protected function getRequestBlacklist() {
+ return $this->getConfig()->get( 'RemoveCredentialsBlacklist' );
+ }
+}
$out = $this->getOutput();
$out->allowClickjacking();
$out->addModuleStyles( [
- 'mediawiki.special', 'mediawiki.special.search', 'mediawiki.ui', 'mediawiki.ui.button',
+ 'mediawiki.special', 'mediawiki.special.search.styles', 'mediawiki.ui', 'mediawiki.ui.button',
'mediawiki.ui.input', 'mediawiki.widgets.SearchInputWidget.styles',
] );
$this->addHelpLink( 'Help:Searching' );
'name' => 'search',
'autofocus' => trim( $term ) === '',
'value' => $term,
+ 'dataLocation' => 'content',
+ ] );
+
+ $layout = new OOUI\ActionFieldLayout( $searchWidget, new OOUI\ButtonInputWidget( [
+ 'type' => 'submit',
+ 'label' => $this->msg( 'searchbutton' )->text(),
+ 'flags' => [ 'progressive', 'primary' ],
+ ] ), [
+ 'align' => 'top',
] );
$out =
Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ) .
Html::hidden( 'profile', $this->profile ) .
Html::hidden( 'fulltext', 'Search' ) .
- $searchWidget .
- new OOUI\ButtonInputWidget( [
- 'type' => 'submit',
- 'label' => $this->msg( 'searchbutton' )->text(),
- 'flags' => [ 'progressive', 'primary' ],
- ] );
+ $layout;
// Results-info
if ( $totalNum > 0 && $this->offset < $totalNum ) {
$user = $this->getUser();
$userCanManage = $user->isAllowed( 'managechangetags' );
+ $userCanDelete = $user->isAllowed( 'deletechangetags' );
$userCanEditInterface = $user->isAllowed( 'editinterface' );
// Show form to create a tag
// Insert tags that have been applied at least once
foreach ( $tagStats as $tag => $hitcount ) {
- $html .= $this->doTagRow( $tag, $hitcount, $userCanManage, $userCanEditInterface );
+ $html .= $this->doTagRow( $tag, $hitcount, $userCanManage,
+ $userCanDelete, $userCanEditInterface );
}
// Insert tags defined somewhere but never applied
foreach ( $definedTags as $tag ) {
if ( !isset( $tagStats[$tag] ) ) {
- $html .= $this->doTagRow( $tag, 0, $userCanManage, $userCanEditInterface );
+ $html .= $this->doTagRow( $tag, 0, $userCanManage, $userCanDelete, $userCanEditInterface );
}
}
) );
}
- function doTagRow( $tag, $hitcount, $showActions, $showEditLinks ) {
+ function doTagRow( $tag, $hitcount, $showManageActions, $showDeleteActions, $showEditLinks ) {
$newRow = '';
$newRow .= Xml::tags( 'td', null, Xml::element( 'code', null, $tag ) );
$newRow .= Xml::tags( 'td', [ 'data-sort-value' => $hitcount ], $hitcountLabel );
// actions
- if ( $showActions ) { // we've already checked that the user had the requisite userright
- $actionLinks = [];
+ $actionLinks = [];
- // delete
- if ( ChangeTags::canDeleteTag( $tag )->isOK() ) {
- $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'delete' ),
- $this->msg( 'tags-delete' )->escaped(),
- [],
- [ 'tag' => $tag ] );
- }
+ // delete
+ if ( $showDeleteActions && ChangeTags::canDeleteTag( $tag )->isOK() ) {
+ $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'delete' ),
+ $this->msg( 'tags-delete' )->escaped(),
+ [],
+ [ 'tag' => $tag ] );
+ }
+
+ if ( $showManageActions ) { // we've already checked that the user had the requisite userright
// activate
if ( ChangeTags::canActivateTag( $tag )->isOK() ) {
[ 'tag' => $tag ] );
}
+ }
+
+ if ( $actionLinks ) {
$newRow .= Xml::tags( 'td', null, $this->getLanguage()->pipeList( $actionLinks ) );
}
protected function showDeleteTagForm( $tag ) {
$user = $this->getUser();
- if ( !$user->isAllowed( 'managechangetags' ) ) {
- throw new PermissionsError( 'managechangetags' );
+ if ( !$user->isAllowed( 'deletechangetags' ) ) {
+ throw new PermissionsError( 'deletechangetags' );
}
$out = $this->getOutput();
'broken-file-category',
'node-count-exceeded-category',
'expansion-depth-exceeded-category',
+ 'restricted-displaytitle-ignored',
];
function execute( $par ) {
"ids" => $revisions,
"target" => $this->mTargetObj->getPrefixedText()
];
- $url = SpecialPage::getTitleFor( "RevisionDelete" )->getFullURL( $query );
+ $url = SpecialPage::getTitleFor( 'Revisiondelete' )->getFullURL( $query );
$this->getOutput()->redirect( $url );
}
--- /dev/null
+<?php
+
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Session\SessionManager;
+
+class SpecialUnlinkAccounts extends AuthManagerSpecialPage {
+ protected static $allowedActions = [ AuthManager::ACTION_UNLINK ];
+
+ public function __construct() {
+ parent::__construct( 'UnlinkAccounts' );
+ }
+
+ protected function getLoginSecurityLevel() {
+ return 'UnlinkAccount';
+ }
+
+ protected function getDefaultAction( $subPage ) {
+ return AuthManager::ACTION_UNLINK;
+ }
+
+ /**
+ * Under which header this special page is listed in Special:SpecialPages.
+ */
+ protected function getGroupName() {
+ return 'users';
+ }
+
+ public function isListed() {
+ return AuthManager::singleton()->canLinkAccounts();
+ }
+
+ protected function getRequestBlacklist() {
+ return $this->getConfig()->get( 'RemoveCredentialsBlacklist' );
+ }
+
+ public function execute( $subPage ) {
+ $this->setHeaders();
+ $this->loadAuth( $subPage );
+ $this->outputHeader();
+
+ $status = $this->trySubmit();
+
+ if ( $status === false || !$status->isOK() ) {
+ $this->displayForm( $status );
+ return;
+ }
+
+ /** @var AuthenticationResponse $response */
+ $response = $status->getValue();
+
+ if ( $response->status === AuthenticationResponse::FAIL ) {
+ $this->displayForm( StatusValue::newFatal( $response->message ) );
+ return;
+ }
+
+ $status = StatusValue::newGood();
+ $status->warning( wfMessage( 'unlinkaccounts-success' ) );
+ $this->loadAuth( $subPage, null, true ); // update requests so the unlinked one doesn't show up
+
+ // Reset sessions - if the user unlinked an account because it was compromised,
+ // log attackers out from sessions obtained via that account.
+ $session = $this->getRequest()->getSession();
+ $user = $this->getUser();
+ SessionManager::singleton()->invalidateSessionsForUser( $user );
+ $session->setUser( $user );
+ $session->resetId();
+
+ $this->displayForm( $status );
+ }
+
+ public function handleFormSubmit( $data ) {
+ // unlink requests do not accept user input so repeat parent code but skip call to
+ // AuthenticationRequest::loadRequestsFromSubmission
+ $response = $this->performAuthenticationStep( $this->authAction, $this->authRequests );
+ return Status::newGood( $response );
+ }
+}
}
public function doesWrites() {
- return true;
+ return false;
}
public function requiresWrite() {
}
protected function alterForm( HTMLForm $form ) {
- $form->setWrapperLegend( false );
- $form->setHeaderText( $this->msg( 'unlockdbtext' )->parseAsBlock() );
- $form->setSubmitTextMsg( 'unlockbtn' );
+ $form->setWrapperLegend( false )
+ ->setHeaderText( $this->msg( 'unlockdbtext' )->parseAsBlock() )
+ ->setSubmitTextMsg( 'unlockbtn' );
}
public function onSubmit( array $data ) {
$out->addWikiMsg( 'unlockdbsuccesstext' );
}
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
protected function getGroupName() {
return 'wiki';
}
$sessionKey = $this->mUpload->stashSession();
// Add styles for the warning, reused from the live preview
- $this->getOutput()->addModuleStyles( 'mediawiki.special.upload' );
+ $this->getOutput()->addModuleStyles( 'mediawiki.special.upload.styles' );
$warningHtml = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . "</h2>\n"
. '<div class="mw-destfile-warning"><ul>';
--- /dev/null
+<?php
+/**
+ * Implements Special:UserLogin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Logger\LoggerFactory;
+use Psr\Log\LogLevel;
+
+/**
+ * Implements Special:UserLogin
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialUserLogin extends LoginSignupSpecialPage {
+ protected static $allowedActions = [
+ AuthManager::ACTION_LOGIN,
+ AuthManager::ACTION_LOGIN_CONTINUE
+ ];
+
+ protected static $messages = [
+ 'authform-newtoken' => 'nocookiesforlogin',
+ 'authform-notoken' => 'sessionfailure',
+ 'authform-wrongtoken' => 'sessionfailure',
+ ];
+
+ public function __construct() {
+ parent::__construct( 'Userlogin' );
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ protected function getLoginSecurityLevel() {
+ return false;
+ }
+
+ protected function getDefaultAction( $subPage ) {
+ return AuthManager::ACTION_LOGIN;
+ }
+
+ public function getDescription() {
+ return $this->msg( 'login' )->text();
+ }
+
+ public function setHeaders() {
+ // override the page title if we are doing a forced reauthentication
+ parent::setHeaders();
+ if ( $this->securityLevel && $this->getUser()->isLoggedIn() ) {
+ $this->getOutput()->setPageTitle( $this->msg( 'login-security' ) );
+ }
+ }
+
+ protected function isSignup() {
+ return false;
+ }
+
+ protected function beforeExecute( $subPage ) {
+ if ( $subPage === 'signup' || $this->getRequest()->getText( 'type' ) === 'signup' ) {
+ // B/C for old account creation URLs
+ $title = SpecialPage::getTitleFor( 'CreateAccount' );
+ $query = array_diff_key( $this->getRequest()->getValues(),
+ array_fill_keys( [ 'type', 'title' ], true ) );
+ $url = $title->getFullURL( $query, false, PROTO_CURRENT );
+ $this->getOutput()->redirect( $url );
+ return false;
+ }
+ return parent::beforeExecute( $subPage );
+ }
+
+ /**
+ * Run any hooks registered for logins, then HTTP redirect to
+ * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a
+ * nice message here, but that's really not as useful as just being sent to
+ * wherever you logged in from. It should be clear that the action was
+ * successful, given the lack of error messages plus the appearance of your
+ * name in the upper right.
+ * @param bool $direct True if the action was successful just now; false if that happened
+ * pre-redirection (so this handler was called already)
+ * @param StatusValue|null $extraMessages
+ */
+ protected function successfulAction( $direct = false, $extraMessages = null ) {
+ global $wgSecureLogin;
+
+ $user = $this->targetUser ?: $this->getUser();
+ $session = $this->getRequest()->getSession();
+
+ if ( $direct ) {
+ $user->touch();
+
+ $this->clearToken();
+
+ if ( $user->requiresHTTPS() ) {
+ $this->mStickHTTPS = true;
+ }
+ $session->setForceHTTPS( $wgSecureLogin && $this->mStickHTTPS );
+
+ // If the user does not have a session cookie at this point, they probably need to
+ // do something to their browser.
+ if ( !$this->hasSessionCookie() ) {
+ $this->mainLoginForm( [ /*?*/ ], $session->getProvider()->whyNoSession() );
+ // TODO something more specific? This used to use nocookieslogin
+ return;
+ }
+ }
+
+ # Run any hooks; display injected HTML if any, else redirect
+ $injected_html = '';
+ Hooks::run( 'UserLoginComplete', [ &$user, &$injected_html ] );
+
+ if ( $injected_html !== '' || $extraMessages ) {
+ $this->showSuccessPage( 'success', $this->msg( 'loginsuccesstitle' ),
+ 'loginsuccess', $injected_html, $extraMessages );
+ } else {
+ $helper = new LoginHelper( $this->getContext() );
+ $helper->showReturnToPage( 'successredirect', $this->mReturnTo, $this->mReturnToQuery,
+ $this->mStickHTTPS );
+ }
+ }
+
+ protected function getToken() {
+ return $this->getRequest()->getSession()->getToken( '', 'login' );
+ }
+
+ protected function clearToken() {
+ return $this->getRequest()->getSession()->resetToken( 'login' );
+ }
+
+ protected function getTokenName() {
+ return 'wpLoginToken';
+ }
+
+ protected function getGroupName() {
+ return 'login';
+ }
+
+ protected function logAuthResult( $success, $status = null ) {
+ LoggerFactory::getInstance( 'authmanager-stats' )->info( 'Login attempt', [
+ 'event' => 'login',
+ 'successful' => $success,
+ 'status' => $status,
+ ] );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements Special:Userlogout
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Implements Special:Userlogout
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialUserLogout extends UnlistedSpecialPage {
+ function __construct() {
+ parent::__construct( 'Userlogout' );
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ function execute( $par ) {
+ /**
+ * Some satellite ISPs use broken precaching schemes that log people out straight after
+ * they're logged in (bug 17790). Luckily, there's a way to detect such requests.
+ */
+ if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '&' ) !== false ) {
+ wfDebug( "Special:UserLogout request {$_SERVER['REQUEST_URI']} looks suspicious, denying.\n" );
+ throw new HttpError( 400, $this->msg( 'suspicious-userlogout' ), $this->msg( 'loginerror' ) );
+ }
+
+ $this->setHeaders();
+ $this->outputHeader();
+
+ // Make sure it's possible to log out
+ $session = MediaWiki\Session\SessionManager::getGlobalSession();
+ if ( !$session->canSetUser() ) {
+ throw new ErrorPageError(
+ 'cannotlogoutnow-title',
+ 'cannotlogoutnow-text',
+ [
+ $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
+ ]
+ );
+ }
+
+ $user = $this->getUser();
+ $oldName = $user->getName();
+
+ $user->logout();
+
+ $loginURL = SpecialPage::getTitleFor( 'Userlogin' )->getFullURL(
+ $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
+
+ $out = $this->getOutput();
+ $out->addWikiMsg( 'logouttext', $loginURL );
+
+ // Hook.
+ $injected_html = '';
+ Hooks::run( 'UserLogoutComplete', [ &$user, &$injected_html, $oldName ] );
+ $out->addHTML( $injected_html );
+
+ $out->returnToMain();
+ }
+
+ protected function getGroupName() {
+ return 'login';
+ }
+}
+++ /dev/null
-<?php
-/**
- * Implements Special:UserLogin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-use MediaWiki\Logger\LoggerFactory;
-use Psr\Log\LogLevel;
-use MediaWiki\Session\SessionManager;
-
-/**
- * Implements Special:UserLogin
- *
- * @ingroup SpecialPage
- */
-class LoginForm extends SpecialPage {
- const SUCCESS = 0;
- const NO_NAME = 1;
- const ILLEGAL = 2;
- const WRONG_PLUGIN_PASS = 3;
- const NOT_EXISTS = 4;
- const WRONG_PASS = 5;
- const EMPTY_PASS = 6;
- const RESET_PASS = 7;
- const ABORTED = 8;
- const CREATE_BLOCKED = 9;
- const THROTTLED = 10;
- const USER_BLOCKED = 11;
- const NEED_TOKEN = 12;
- const WRONG_TOKEN = 13;
- const USER_MIGRATED = 14;
-
- public static $statusCodes = [
- self::SUCCESS => 'success',
- self::NO_NAME => 'no_name',
- self::ILLEGAL => 'illegal',
- self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
- self::NOT_EXISTS => 'not_exists',
- self::WRONG_PASS => 'wrong_pass',
- self::EMPTY_PASS => 'empty_pass',
- self::RESET_PASS => 'reset_pass',
- self::ABORTED => 'aborted',
- self::CREATE_BLOCKED => 'create_blocked',
- self::THROTTLED => 'throttled',
- self::USER_BLOCKED => 'user_blocked',
- self::NEED_TOKEN => 'need_token',
- self::WRONG_TOKEN => 'wrong_token',
- self::USER_MIGRATED => 'user_migrated',
- ];
-
- /**
- * Valid error and warning messages
- *
- * Special:Userlogin can show an error or warning message on the form when
- * coming from another page. This is done via the ?error= or ?warning= GET
- * parameters.
- *
- * This array is the list of valid message keys. All other values will be
- * ignored.
- *
- * @since 1.24
- * @var string[]
- */
- public static $validErrorMessages = [
- 'exception-nologin-text',
- 'watchlistanontext',
- 'changeemail-no-info',
- 'resetpass-no-info',
- 'confirmemail_needlogin',
- 'prefsnologintext2',
- ];
-
- public $mAbortLoginErrorMsg = null;
- /**
- * @var int How many seconds user is throttled for
- * @since 1.27
- */
- public $mThrottleWait = '?';
-
- protected $mUsername;
- protected $mPassword;
- protected $mRetype;
- protected $mReturnTo;
- protected $mCookieCheck;
- protected $mPosted;
- protected $mAction;
- protected $mCreateaccount;
- protected $mCreateaccountMail;
- protected $mLoginattempt;
- protected $mRemember;
- protected $mEmail;
- protected $mDomain;
- protected $mLanguage;
- protected $mSkipCookieCheck;
- protected $mReturnToQuery;
- protected $mToken;
- protected $mStickHTTPS;
- protected $mType;
- protected $mReason;
- protected $mRealName;
- protected $mEntryError = '';
- protected $mEntryErrorType = 'error';
-
- private $mTempPasswordUsed;
- private $mLoaded = false;
- private $mSecureLoginUrl;
-
- /** @var WebRequest */
- private $mOverrideRequest = null;
-
- /** @var WebRequest Effective request; set at the beginning of load */
- private $mRequest = null;
-
- /**
- * @param WebRequest $request
- */
- public function __construct( $request = null ) {
- global $wgUseMediaWikiUIEverywhere;
- parent::__construct( 'Userlogin' );
-
- $this->mOverrideRequest = $request;
- // Override UseMediaWikiEverywhere to true, to force login and create form to use mw ui
- $wgUseMediaWikiUIEverywhere = true;
- }
-
- public function doesWrites() {
- return true;
- }
-
- /**
- * Returns an array of all valid error messages.
- *
- * @return array
- */
- public static function getValidErrorMessages() {
- static $messages = null;
- if ( !$messages ) {
- $messages = self::$validErrorMessages;
- Hooks::run( 'LoginFormValidErrorMessages', [ &$messages ] );
- }
-
- return $messages;
- }
-
- /**
- * Loader
- */
- function load() {
- global $wgAuth, $wgHiddenPrefs, $wgEnableEmail;
-
- if ( $this->mLoaded ) {
- return;
- }
- $this->mLoaded = true;
-
- if ( $this->mOverrideRequest === null ) {
- $request = $this->getRequest();
- } else {
- $request = $this->mOverrideRequest;
- }
- $this->mRequest = $request;
-
- $this->mType = $request->getText( 'type' );
- $this->mUsername = $request->getText( 'wpName' );
- $this->mPassword = $request->getText( 'wpPassword' );
- $this->mRetype = $request->getText( 'wpRetype' );
- $this->mDomain = $request->getText( 'wpDomain' );
- $this->mReason = $request->getText( 'wpReason' );
- $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
- $this->mPosted = $request->wasPosted();
- $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
- && $wgEnableEmail;
- $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' ) && !$this->mCreateaccountMail;
- $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
- $this->mAction = $request->getVal( 'action' );
- $this->mRemember = $request->getCheck( 'wpRemember' );
- $this->mFromHTTP = $request->getBool( 'fromhttp', false )
- || $request->getBool( 'wpFromhttp', false );
- $this->mStickHTTPS = ( !$this->mFromHTTP && $request->getProtocol() === 'https' )
- || $request->getBool( 'wpForceHttps', false );
- $this->mLanguage = $request->getText( 'uselang' );
- $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
- $this->mToken = $this->mType == 'signup'
- ? $request->getVal( 'wpCreateaccountToken' )
- : $request->getVal( 'wpLoginToken' );
- $this->mReturnTo = $request->getVal( 'returnto', '' );
- $this->mReturnToQuery = $request->getVal( 'returntoquery', '' );
-
- // Show an error or warning passed on from a previous page
- $entryError = $this->msg( $request->getVal( 'error', '' ) );
- $entryWarning = $this->msg( $request->getVal( 'warning', '' ) );
- // bc: provide login link as a parameter for messages where the translation
- // was not updated
- $loginreqlink = Linker::linkKnown(
- $this->getPageTitle(),
- $this->msg( 'loginreqlink' )->escaped(),
- [],
- [
- 'returnto' => $this->mReturnTo,
- 'returntoquery' => $this->mReturnToQuery,
- 'uselang' => $this->mLanguage,
- 'fromhttp' => $this->mFromHTTP ? '1' : '0',
- ]
- );
-
- // Only show valid error or warning messages.
- if ( $entryError->exists()
- && in_array( $entryError->getKey(), self::getValidErrorMessages() )
- ) {
- $this->mEntryErrorType = 'error';
- $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
-
- } elseif ( $entryWarning->exists()
- && in_array( $entryWarning->getKey(), self::getValidErrorMessages() )
- ) {
- $this->mEntryErrorType = 'warning';
- $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
- }
-
- if ( $wgEnableEmail ) {
- $this->mEmail = $request->getText( 'wpEmail' );
- } else {
- $this->mEmail = '';
- }
- if ( !in_array( 'realname', $wgHiddenPrefs ) ) {
- $this->mRealName = $request->getText( 'wpRealName' );
- } else {
- $this->mRealName = '';
- }
-
- if ( !$wgAuth->validDomain( $this->mDomain ) ) {
- $this->mDomain = $wgAuth->getDomain();
- }
- $wgAuth->setDomain( $this->mDomain );
-
- # 1. When switching accounts, it sucks to get automatically logged out
- # 2. Do not return to PasswordReset after a successful password change
- # but goto Wiki start page (Main_Page) instead ( bug 33997 )
- $returnToTitle = Title::newFromText( $this->mReturnTo );
- if ( is_object( $returnToTitle )
- && ( $returnToTitle->isSpecial( 'Userlogout' )
- || $returnToTitle->isSpecial( 'PasswordReset' ) )
- ) {
- $this->mReturnTo = '';
- $this->mReturnToQuery = '';
- }
- }
-
- function getDescription() {
- if ( $this->mType === 'signup' ) {
- return $this->msg( 'createaccount' )->text();
- } else {
- return $this->msg( 'login' )->text();
- }
- }
-
- /**
- * @param string|null $subPage
- */
- public function execute( $subPage ) {
- // Make sure session is persisted
- $session = SessionManager::getGlobalSession();
- $session->persist();
-
- $this->load();
-
- // Check for [[Special:Userlogin/signup]]. This affects form display and
- // page title.
- if ( $subPage == 'signup' ) {
- $this->mType = 'signup';
- }
- $this->setHeaders();
-
- // Make sure it's possible to log in
- if ( $this->mType !== 'signup' && !$session->canSetUser() ) {
- throw new ErrorPageError(
- 'cannotloginnow-title',
- 'cannotloginnow-text',
- [
- $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
- ]
- );
- }
-
- /**
- * In the case where the user is already logged in, and was redirected to
- * the login form from a page that requires login, do not show the login
- * page. The use case scenario for this is when a user opens a large number
- * of tabs, is redirected to the login page on all of them, and then logs
- * in on one, expecting all the others to work properly.
- *
- * However, do show the form if it was visited intentionally (no 'returnto'
- * is present). People who often switch between several accounts have grown
- * accustomed to this behavior.
- */
- if (
- $this->mType !== 'signup' &&
- !$this->mPosted &&
- $this->getUser()->isLoggedIn() &&
- ( $this->mReturnTo !== '' || $this->mReturnToQuery !== '' )
- ) {
- $this->successfulLogin();
- }
-
- // If logging in and not on HTTPS, either redirect to it or offer a link.
- global $wgSecureLogin;
- if ( $this->mRequest->getProtocol() !== 'https' ) {
- $title = $this->getFullTitle();
- $query = [
- 'returnto' => $this->mReturnTo !== '' ? $this->mReturnTo : null,
- 'returntoquery' => $this->mReturnToQuery !== '' ?
- $this->mReturnToQuery : null,
- 'title' => null,
- ( $this->mEntryErrorType === 'error' ? 'error' : 'warning' ) => $this->mEntryError,
- ] + $this->mRequest->getQueryValues();
- $url = $title->getFullURL( $query, false, PROTO_HTTPS );
- if ( $wgSecureLogin
- && wfCanIPUseHTTPS( $this->getRequest()->getIP() )
- && !$this->mFromHTTP ) // Avoid infinite redirect
- {
- $url = wfAppendQuery( $url, 'fromhttp=1' );
- $this->getOutput()->redirect( $url );
- // Since we only do this redir to change proto, always vary
- $this->getOutput()->addVaryHeader( 'X-Forwarded-Proto' );
-
- return;
- } else {
- // A wiki without HTTPS login support should set $wgServer to
- // http://somehost, in which case the secure URL generated
- // above won't actually start with https://
- if ( substr( $url, 0, 8 ) === 'https://' ) {
- $this->mSecureLoginUrl = $url;
- }
- }
- }
-
- if ( !is_null( $this->mCookieCheck ) ) {
- $this->onCookieRedirectCheck( $this->mCookieCheck );
-
- return;
- } elseif ( $this->mPosted ) {
- if ( $this->mCreateaccount ) {
- $this->addNewAccount();
-
- return;
- } elseif ( $this->mCreateaccountMail ) {
- $this->addNewAccountMailPassword();
-
- return;
- } elseif ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
- $this->processLogin();
-
- return;
- }
- }
- $this->mainLoginForm( $this->mEntryError, $this->mEntryErrorType );
- }
-
- /**
- * @private
- */
- function addNewAccountMailPassword() {
- if ( $this->mEmail == '' ) {
- $this->mainLoginForm( $this->msg( 'noemailcreate' )->escaped() );
-
- return;
- }
-
- $status = $this->addNewAccountInternal();
- LoggerFactory::getInstance( 'authmanager' )->info(
- 'Account creation attempt with mailed password',
- [ 'event' => 'accountcreation', 'status' => $status ]
- );
- if ( !$status->isGood() ) {
- $error = $status->getMessage();
- $this->mainLoginForm( $error->toString() );
-
- return;
- }
-
- /** @var User $u */
- $u = $status->getValue();
-
- // Wipe the initial password and mail a temporary one
- $u->setPassword( null );
- $u->saveSettings();
- $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
-
- Hooks::run( 'AddNewAccount', [ $u, true ] );
- $u->addNewUserLogEntry( 'byemail', $this->mReason );
-
- $out = $this->getOutput();
- $out->setPageTitle( $this->msg( 'accmailtitle' ) );
-
- if ( !$result->isGood() ) {
- $this->mainLoginForm( $this->msg( 'mailerror', $result->getWikiText() )->text() );
- } else {
- $out->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
- $this->executeReturnTo( 'success' );
- }
- }
-
- /**
- * @private
- * @return bool
- */
- function addNewAccount() {
- global $wgContLang, $wgUser, $wgEmailAuthentication, $wgLoginLanguageSelector;
-
- # Create the account and abort if there's a problem doing so
- $status = $this->addNewAccountInternal();
- LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt', [
- 'event' => 'accountcreation',
- 'status' => $status,
- ] );
-
- if ( !$status->isGood() ) {
- $error = $status->getMessage();
- $this->mainLoginForm( $error->toString() );
-
- return false;
- }
-
- $u = $status->getValue();
-
- # Only save preferences if the user is not creating an account for someone else.
- if ( $this->getUser()->isAnon() ) {
- # If we showed up language selection links, and one was in use, be
- # smart (and sensible) and save that language as the user's preference
- if ( $wgLoginLanguageSelector && $this->mLanguage ) {
- $u->setOption( 'language', $this->mLanguage );
- } else {
-
- # Otherwise the user's language preference defaults to $wgContLang,
- # but it may be better to set it to their preferred $wgContLang variant,
- # based on browser preferences or URL parameters.
- $u->setOption( 'language', $wgContLang->getPreferredVariant() );
- }
- if ( $wgContLang->hasVariants() ) {
- $u->setOption( 'variant', $wgContLang->getPreferredVariant() );
- }
- }
-
- $out = $this->getOutput();
-
- # Send out an email authentication message if needed
- if ( $wgEmailAuthentication && Sanitizer::validateEmail( $u->getEmail() ) ) {
- $status = $u->sendConfirmationMail();
- if ( $status->isGood() ) {
- $out->addWikiMsg( 'confirmemail_oncreate' );
- } else {
- $out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) );
- }
- }
-
- # Save settings (including confirmation token)
- $u->saveSettings();
-
- # If not logged in, assume the new account as the current one and set
- # session cookies then show a "welcome" message or a "need cookies"
- # message as needed
- if ( $this->getUser()->isAnon() ) {
- $u->setCookies();
- $wgUser = $u;
- // This should set it for OutputPage and the Skin
- // which is needed or the personal links will be
- // wrong.
- $this->getContext()->setUser( $u );
- Hooks::run( 'AddNewAccount', [ $u, false ] );
- $u->addNewUserLogEntry( 'create' );
- if ( $this->hasSessionCookie() ) {
- $this->successfulCreation();
- } else {
- $this->cookieRedirectCheck( 'new' );
- }
- } else {
- # Confirm that the account was created
- $out->setPageTitle( $this->msg( 'accountcreated' ) );
- $out->addWikiMsg( 'accountcreatedtext', $u->getName() );
- $out->addReturnTo( $this->getPageTitle() );
- Hooks::run( 'AddNewAccount', [ $u, false ] );
- $u->addNewUserLogEntry( 'create2', $this->mReason );
- }
-
- return true;
- }
-
- /**
- * Make a new user account using the loaded data.
- * @private
- * @throws PermissionsError|ReadOnlyError
- * @return Status
- */
- public function addNewAccountInternal() {
- global $wgAuth, $wgAccountCreationThrottle, $wgEmailConfirmToEdit;
-
- // If the user passes an invalid domain, something is fishy
- if ( !$wgAuth->validDomain( $this->mDomain ) ) {
- return Status::newFatal( 'wrongpassword' );
- }
-
- // If we are not allowing users to login locally, we should be checking
- // to see if the user is actually able to authenticate to the authenti-
- // cation server before they create an account (otherwise, they can
- // create a local account and login as any domain user). We only need
- // to check this for domains that aren't local.
- if ( 'local' != $this->mDomain && $this->mDomain != '' ) {
- if (
- !$wgAuth->canCreateAccounts() &&
- (
- !$wgAuth->userExists( $this->mUsername ) ||
- !$wgAuth->authenticate( $this->mUsername, $this->mPassword )
- )
- ) {
- return Status::newFatal( 'wrongpassword' );
- }
- }
-
- if ( wfReadOnly() ) {
- throw new ReadOnlyError;
- }
-
- # Request forgery checks.
- $token = self::getCreateaccountToken();
- if ( $token->wasNew() ) {
- return Status::newFatal( 'nocookiesfornew' );
- }
-
- # The user didn't pass a createaccount token
- if ( !$this->mToken ) {
- return Status::newFatal( 'sessionfailure' );
- }
-
- # Validate the createaccount token
- if ( !$token->match( $this->mToken ) ) {
- return Status::newFatal( 'sessionfailure' );
- }
-
- # Check permissions
- $currentUser = $this->getUser();
- $creationBlock = $currentUser->isBlockedFromCreateAccount();
- if ( !$currentUser->isAllowed( 'createaccount' ) ) {
- throw new PermissionsError( 'createaccount' );
- } elseif ( $creationBlock instanceof Block ) {
- // Throws an ErrorPageError.
- $this->userBlockedMessage( $creationBlock );
-
- // This should never be reached.
- return false;
- }
-
- # Include checks that will include GlobalBlocking (Bug 38333)
- $permErrors = $this->getPageTitle()->getUserPermissionsErrors(
- 'createaccount',
- $currentUser,
- true
- );
-
- if ( count( $permErrors ) ) {
- throw new PermissionsError( 'createaccount', $permErrors );
- }
-
- $ip = $this->getRequest()->getIP();
- if ( $currentUser->isDnsBlacklisted( $ip, true /* check $wgProxyWhitelist */ ) ) {
- return Status::newFatal( 'sorbs_create_account_reason' );
- }
-
- # Now create a dummy user ($u) and check if it is valid
- $u = User::newFromName( $this->mUsername, 'creatable' );
- if ( !$u ) {
- return Status::newFatal( 'noname' );
- }
-
- $cache = ObjectCache::getLocalClusterInstance();
- # Make sure the user does not exist already
- $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $this->mUsername ) ) );
- if ( !$lock ) {
- return Status::newFatal( 'usernameinprogress' );
- } elseif ( $u->idForName( User::READ_LOCKING ) ) {
- return Status::newFatal( 'userexists' );
- }
-
- if ( $this->mCreateaccountMail ) {
- # do not force a password for account creation by email
- # set invalid password, it will be replaced later by a random generated password
- $this->mPassword = null;
- } else {
- if ( $this->mPassword !== $this->mRetype ) {
- return Status::newFatal( 'badretype' );
- }
-
- # check for password validity, return a fatal Status if invalid
- $validity = $u->checkPasswordValidity( $this->mPassword, 'create' );
- if ( !$validity->isGood() ) {
- $validity->ok = false; // make sure this Status is fatal
- return $validity;
- }
- }
-
- # if you need a confirmed email address to edit, then obviously you
- # need an email address.
- if ( $wgEmailConfirmToEdit && strval( $this->mEmail ) === '' ) {
- return Status::newFatal( 'noemailtitle' );
- }
-
- if ( strval( $this->mEmail ) !== '' && !Sanitizer::validateEmail( $this->mEmail ) ) {
- return Status::newFatal( 'invalidemailaddress' );
- }
-
- # Set some additional data so the AbortNewAccount hook can be used for
- # more than just username validation
- $u->setEmail( $this->mEmail );
- $u->setRealName( $this->mRealName );
-
- $abortError = '';
- $abortStatus = null;
- if ( !Hooks::run( 'AbortNewAccount', [ $u, &$abortError, &$abortStatus ] ) ) {
- // Hook point to add extra creation throttles and blocks
- wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
- if ( $abortStatus === null ) {
- // Report back the old string as a raw message status.
- // This will report the error back as 'createaccount-hook-aborted'
- // with the given string as the message.
- // To return a different error code, return a Status object.
- $abortError = new Message( 'createaccount-hook-aborted', [ $abortError ] );
- $abortError->text();
-
- return Status::newFatal( $abortError );
- } else {
- // For MediaWiki 1.23+ and updated hooks, return the Status object
- // returned from the hook.
- return $abortStatus;
- }
- }
-
- // Hook point to check for exempt from account creation throttle
- if ( !Hooks::run( 'ExemptFromAccountCreationThrottle', [ $ip ] ) ) {
- wfDebug( "LoginForm::exemptFromAccountCreationThrottle: a hook " .
- "allowed account creation w/o throttle\n" );
- } else {
- if ( ( $wgAccountCreationThrottle && $currentUser->isPingLimitable() ) ) {
- $key = wfGlobalCacheKey( 'acctcreate', 'ip', $ip );
- $value = $cache->get( $key );
- if ( !$value ) {
- $cache->set( $key, 0, $cache::TTL_DAY );
- }
- if ( $value >= $wgAccountCreationThrottle ) {
- return Status::newFatal( 'acct_creation_throttle_hit', $wgAccountCreationThrottle );
- }
- $cache->incr( $key );
- }
- }
-
- if ( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
- return Status::newFatal( 'externaldberror' );
- }
-
- self::clearCreateaccountToken();
-
- return $this->initUser( $u, false );
- }
-
- /**
- * Actually add a user to the database.
- * Give it a User object that has been initialised with a name.
- *
- * @param User $u
- * @param bool $autocreate True if this is an autocreation via auth plugin
- * @return Status Status object, with the User object in the value member on success
- * @private
- */
- function initUser( $u, $autocreate ) {
- global $wgAuth;
-
- $status = $u->addToDatabase();
- if ( !$status->isOK() ) {
- return $status;
- }
-
- if ( $wgAuth->allowPasswordChange() ) {
- $u->setPassword( $this->mPassword );
- }
-
- $u->setEmail( $this->mEmail );
- $u->setRealName( $this->mRealName );
- $u->setToken();
-
- Hooks::run( 'LocalUserCreated', [ $u, $autocreate ] );
- $oldUser = $u;
- $wgAuth->initUser( $u, $autocreate );
- if ( $oldUser !== $u ) {
- wfWarn( get_class( $wgAuth ) . '::initUser() replaced the user object' );
- }
-
- $u->saveSettings();
-
- // Update user count
- DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
-
- // Watch user's userpage and talk page
- $u->addWatch( $u->getUserPage(), User::IGNORE_USER_RIGHTS );
-
- return Status::newGood( $u );
- }
-
- /**
- * Internally authenticate the login request.
- *
- * This may create a local account as a side effect if the
- * authentication plugin allows transparent local account
- * creation.
- * @return int
- */
- public function authenticateUserData() {
- global $wgUser, $wgAuth;
-
- $this->load();
-
- if ( $this->mUsername == '' ) {
- return self::NO_NAME;
- }
-
- // We require a login token to prevent login CSRF
- // Handle part of this before incrementing the throttle so
- // token-less login attempts don't count towards the throttle
- // but wrong-token attempts do.
-
- // If the user doesn't have a login token yet, set one.
- $token = self::getLoginToken();
- if ( $token->wasNew() ) {
- return self::NEED_TOKEN;
- }
- // If the user didn't pass a login token, tell them we need one
- if ( !$this->mToken ) {
- return self::NEED_TOKEN;
- }
-
- $throttleCount = self::incrementLoginThrottle( $this->mUsername );
- if ( $throttleCount ) {
- $this->mThrottleWait = $throttleCount['wait'];
- return self::THROTTLED;
- }
-
- // Validate the login token
- if ( !$token->match( $this->mToken ) ) {
- return self::WRONG_TOKEN;
- }
-
- // Load the current user now, and check to see if we're logging in as
- // the same name. This is necessary because loading the current user
- // (say by calling getName()) calls the UserLoadFromSession hook, which
- // potentially creates the user in the database. Until we load $wgUser,
- // checking for user existence using User::newFromName($name)->getId() below
- // will effectively be using stale data.
- if ( $this->getUser()->getName() === $this->mUsername ) {
- wfDebug( __METHOD__ . ": already logged in as {$this->mUsername}\n" );
-
- return self::SUCCESS;
- }
-
- $u = User::newFromName( $this->mUsername );
- if ( $u === false ) {
- return self::ILLEGAL;
- }
-
- $msg = null;
- // Give extensions a way to indicate the username has been updated,
- // rather than telling the user the account doesn't exist.
- if ( !Hooks::run( 'LoginUserMigrated', [ $u, &$msg ] ) ) {
- $this->mAbortLoginErrorMsg = $msg;
- return self::USER_MIGRATED;
- }
-
- if ( !User::isUsableName( $u->getName() ) ) {
- return self::ILLEGAL;
- }
-
- $isAutoCreated = false;
- if ( $u->getId() == 0 ) {
- $status = $this->attemptAutoCreate( $u );
- if ( $status !== self::SUCCESS ) {
- return $status;
- } else {
- $isAutoCreated = true;
- }
- } else {
- $u->load();
- }
-
- // Give general extensions, such as a captcha, a chance to abort logins
- $abort = self::ABORTED;
- if ( !Hooks::run( 'AbortLogin', [ $u, $this->mPassword, &$abort, &$msg ] ) ) {
- if ( !in_array( $abort, array_keys( self::$statusCodes ), true ) ) {
- throw new Exception( 'Invalid status code returned from AbortLogin hook: ' . $abort );
- }
- $this->mAbortLoginErrorMsg = $msg;
- return $abort;
- }
-
- global $wgBlockDisablesLogin;
- if ( !$u->checkPassword( $this->mPassword ) ) {
- if ( $u->checkTemporaryPassword( $this->mPassword ) ) {
- /**
- * The e-mailed temporary password should not be used for actu-
- * al logins; that's a very sloppy habit, and insecure if an
- * attacker has a few seconds to click "search" on someone's
- * open mail reader.
- *
- * Allow it to be used only to reset the password a single time
- * to a new value, which won't be in the user's e-mail ar-
- * chives.
- *
- * For backwards compatibility, we'll still recognize it at the
- * login form to minimize surprises for people who have been
- * logging in with a temporary password for some time.
- *
- * As a side-effect, we can authenticate the user's e-mail ad-
- * dress if it's not already done, since the temporary password
- * was sent via e-mail.
- */
- if ( !$u->isEmailConfirmed() && !wfReadOnly() ) {
- $u->confirmEmail();
- $u->saveSettings();
- }
-
- // At this point we just return an appropriate code/ indicating
- // that the UI should show a password reset form; bot inter-
- // faces etc will probably just fail cleanly here.
- $this->mAbortLoginErrorMsg = 'resetpass-temp-emailed';
- $this->mTempPasswordUsed = true;
- $retval = self::RESET_PASS;
- } else {
- $retval = ( $this->mPassword == '' ) ? self::EMPTY_PASS : self::WRONG_PASS;
- }
- } elseif ( $wgBlockDisablesLogin && $u->isBlocked() ) {
- // If we've enabled it, make it so that a blocked user cannot login
- $retval = self::USER_BLOCKED;
- } elseif ( $this->checkUserPasswordExpired( $u ) == 'hard' ) {
- // Force reset now, without logging in
- $retval = self::RESET_PASS;
- $this->mAbortLoginErrorMsg = 'resetpass-expired';
- } else {
- Hooks::run( 'UserLoggedIn', [ $u ] );
- $oldUser = $u;
- $wgAuth->updateUser( $u );
- if ( $oldUser !== $u ) {
- wfWarn( get_class( $wgAuth ) . '::updateUser() replaced the user object' );
- }
- $wgUser = $u;
- // This should set it for OutputPage and the Skin
- // which is needed or the personal links will be
- // wrong.
- $this->getContext()->setUser( $u );
-
- // Please reset throttle for successful logins, thanks!
- self::clearLoginThrottle( $this->mUsername );
-
- if ( $isAutoCreated ) {
- // Must be run after $wgUser is set, for correct new user log
- Hooks::run( 'AuthPluginAutoCreate', [ $u ] );
- }
-
- $retval = self::SUCCESS;
- }
- Hooks::run( 'LoginAuthenticateAudit', [ $u, $this->mPassword, $retval ] );
-
- return $retval;
- }
-
- /**
- * Increment the login attempt throttle hit count for the (username,current IP)
- * tuple unless the throttle was already reached.
- *
- * @since 1.27 Return value changed.
- * @param string $username The user name
- * @return bool|array false if below limit or an array if above limit
- * Array contains keys wait, count, and throttleIndex
- */
- public static function incrementLoginThrottle( $username ) {
- global $wgPasswordAttemptThrottle, $wgRequest;
- $username = User::getCanonicalName( $username, 'usable' ) ?: $username;
-
- $throttleCount = 0;
- if ( is_array( $wgPasswordAttemptThrottle ) ) {
- $throttleConfig = $wgPasswordAttemptThrottle;
- if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
- // old style. Convert for backwards compat.
- $throttleConfig = [ $wgPasswordAttemptThrottle ];
- }
- foreach ( $throttleConfig as $index => $specificThrottle ) {
- if ( isset( $specificThrottle['allIPs'] ) ) {
- $ip = 'All';
- } else {
- $ip = $wgRequest->getIP();
- }
- $throttleKey = wfGlobalCacheKey( 'password-throttle',
- $index, $ip, md5( $username )
- );
- $count = $specificThrottle['count'];
- $period = $specificThrottle['seconds'];
-
- $cache = ObjectCache::getLocalClusterInstance();
- $throttleCount = $cache->get( $throttleKey );
- if ( !$throttleCount ) {
- $cache->add( $throttleKey, 1, $period ); // start counter
- } elseif ( $throttleCount < $count ) {
- $cache->incr( $throttleKey );
- } elseif ( $throttleCount >= $count ) {
- $logMsg = 'Login attempt rejected because logins to '
- . '{acct} from IP {ip} have been throttled for '
- . '{period} seconds due to {count} failed attempts';
- // If we are hitting a throttle for >= 50 attempts,
- // it is much more likely to be an attack than someone
- // simply forgetting their password, so log it at a
- // higher level.
- $level = $count >= 50 ? LogLevel::WARNING : LogLevel::INFO;
- // It should be noted that once the throttle is hit,
- // every attempt to login will generate the log message
- // until the throttle expires, not just the attempt that
- // puts the throttle over the top.
- LoggerFactory::getInstance( 'password-throttle' )->log(
- $level,
- $logMsg,
- [
- 'ip' => $ip,
- 'period' => $period,
- 'acct' => $username,
- 'count' => $count,
- 'throttleIdentifier' => $index,
- 'method' => __METHOD__
- ]
- );
-
- return [
- 'throttleIndex' => $index,
- 'wait' => $period,
- 'count' => $count
- ];
- }
- }
- }
- return false;
- }
-
- /**
- * Increment the login attempt throttle hit count for the (username,current IP)
- * tuple unless the throttle was already reached.
- *
- * @deprecated Use LoginForm::incrementLoginThrottle instead
- * @param string $username The user name
- * @return bool|int true if above throttle, or 0 (prior to 1.27, returned current count)
- */
- public static function incLoginThrottle( $username ) {
- wfDeprecated( __METHOD__, "1.27" );
- $res = self::incrementLoginThrottle( $username );
- return is_array( $res ) ? true : 0;
- }
-
- /**
- * Clear the login attempt throttle hit count for the (username,current IP) tuple.
- * @param string $username The user name
- * @return void
- */
- public static function clearLoginThrottle( $username ) {
- global $wgRequest, $wgPasswordAttemptThrottle;
- $username = User::getCanonicalName( $username, 'usable' ) ?: $username;
-
- if ( is_array( $wgPasswordAttemptThrottle ) ) {
- $throttleConfig = $wgPasswordAttemptThrottle;
- if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
- // old style. Convert for backwards compat.
- $throttleConfig = [ $wgPasswordAttemptThrottle ];
- }
- foreach ( $throttleConfig as $index => $specificThrottle ) {
- if ( isset( $specificThrottle['allIPs'] ) ) {
- $ip = 'All';
- } else {
- $ip = $wgRequest->getIP();
- }
- $throttleKey = wfGlobalCacheKey( 'password-throttle', $index,
- $ip, md5( $username )
- );
- ObjectCache::getLocalClusterInstance()->delete( $throttleKey );
- }
- }
- }
-
- /**
- * Attempt to automatically create a user on login. Only succeeds if there
- * is an external authentication method which allows it.
- *
- * @param User $user
- *
- * @return int Status code
- */
- function attemptAutoCreate( $user ) {
- global $wgAuth;
-
- if ( $this->getUser()->isBlockedFromCreateAccount() ) {
- wfDebug( __METHOD__ . ": user is blocked from account creation\n" );
-
- return self::CREATE_BLOCKED;
- }
-
- if ( !$wgAuth->autoCreate() ) {
- return self::NOT_EXISTS;
- }
-
- if ( !$wgAuth->userExists( $user->getName() ) ) {
- wfDebug( __METHOD__ . ": user does not exist\n" );
-
- return self::NOT_EXISTS;
- }
-
- if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
- wfDebug( __METHOD__ . ": \$wgAuth->authenticate() returned false, aborting\n" );
-
- return self::WRONG_PLUGIN_PASS;
- }
-
- $abortError = '';
- if ( !Hooks::run( 'AbortAutoAccount', [ $user, &$abortError ] ) ) {
- // Hook point to add extra creation throttles and blocks
- wfDebug( "LoginForm::attemptAutoCreate: a hook blocked creation: $abortError\n" );
- $this->mAbortLoginErrorMsg = $abortError;
-
- return self::ABORTED;
- }
-
- wfDebug( __METHOD__ . ": creating account\n" );
- $status = $this->initUser( $user, true );
-
- if ( !$status->isOK() ) {
- $errors = $status->getErrorsByType( 'error' );
- $this->mAbortLoginErrorMsg = $errors[0]['message'];
-
- return self::ABORTED;
- }
-
- return self::SUCCESS;
- }
-
- function processLogin() {
- global $wgLang, $wgSecureLogin, $wgInvalidPasswordReset;
-
- $authRes = $this->authenticateUserData();
- switch ( $authRes ) {
- case self::SUCCESS:
- # We've verified now, update the real record
- $user = $this->getUser();
- $user->touch();
-
- if ( $user->requiresHTTPS() ) {
- $this->mStickHTTPS = true;
- }
-
- if ( $wgSecureLogin && !$this->mStickHTTPS ) {
- $user->setCookies( $this->mRequest, false, $this->mRemember );
- } else {
- $user->setCookies( $this->mRequest, null, $this->mRemember );
- }
- self::clearLoginToken();
-
- // Reset the throttle
- self::clearLoginThrottle( $this->mUsername );
-
- $request = $this->getRequest();
- if ( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
- /* Replace the language object to provide user interface in
- * correct language immediately on this first page load.
- */
- $code = $request->getVal( 'uselang', $user->getOption( 'language' ) );
- $userLang = Language::factory( $code );
- $wgLang = $userLang;
- RequestContext::getMain()->setLanguage( $userLang );
- $this->getContext()->setLanguage( $userLang );
- // Reset SessionID on Successful login (bug 40995)
- $this->renewSessionId();
- if ( $this->checkUserPasswordExpired( $this->getUser() ) == 'soft' ) {
- $this->resetLoginForm( $this->msg( 'resetpass-expired-soft' ) );
- } elseif ( $wgInvalidPasswordReset
- && !$user->isValidPassword( $this->mPassword )
- ) {
- $status = $user->checkPasswordValidity(
- $this->mPassword,
- 'login'
- );
- $this->resetLoginForm(
- $status->getMessage( 'resetpass-validity-soft' )
- );
- } else {
- $this->successfulLogin();
- }
- } else {
- $this->cookieRedirectCheck( 'login' );
- }
- break;
-
- case self::NEED_TOKEN:
- $error = $this->mAbortLoginErrorMsg ?: 'nocookiesforlogin';
- $this->mainLoginForm( $this->msg( $error )->parse() );
- break;
- case self::WRONG_TOKEN:
- $error = $this->mAbortLoginErrorMsg ?: 'sessionfailure';
- $this->mainLoginForm( $this->msg( $error )->text() );
- break;
- case self::NO_NAME:
- case self::ILLEGAL:
- $error = $this->mAbortLoginErrorMsg ?: 'noname';
- $this->mainLoginForm( $this->msg( $error )->text() );
- break;
- case self::WRONG_PLUGIN_PASS:
- $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
- $this->mainLoginForm( $this->msg( $error )->text() );
- break;
- case self::NOT_EXISTS:
- if ( $this->getUser()->isAllowed( 'createaccount' ) ) {
- $error = $this->mAbortLoginErrorMsg ?: 'nosuchuser';
- $this->mainLoginForm( $this->msg( $error,
- wfEscapeWikiText( $this->mUsername ) )->parse() );
- } else {
- $error = $this->mAbortLoginErrorMsg ?: 'nosuchusershort';
- $this->mainLoginForm( $this->msg( $error,
- wfEscapeWikiText( $this->mUsername ) )->text() );
- }
- break;
- case self::WRONG_PASS:
- $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
- $this->mainLoginForm( $this->msg( $error )->text() );
- break;
- case self::EMPTY_PASS:
- $error = $this->mAbortLoginErrorMsg ?: 'wrongpasswordempty';
- $this->mainLoginForm( $this->msg( $error )->text() );
- break;
- case self::RESET_PASS:
- $error = $this->mAbortLoginErrorMsg ?: 'resetpass_announce';
- $this->resetLoginForm( $this->msg( $error ) );
- break;
- case self::CREATE_BLOCKED:
- $this->userBlockedMessage( $this->getUser()->isBlockedFromCreateAccount() );
- break;
- case self::THROTTLED:
- $error = $this->mAbortLoginErrorMsg ?: 'login-throttled';
- $this->mainLoginForm( $this->msg( $error )
- ->durationParams( $this->mThrottleWait )->text()
- );
- break;
- case self::USER_BLOCKED:
- $error = $this->mAbortLoginErrorMsg ?: 'login-userblocked';
- $this->mainLoginForm( $this->msg( $error, $this->mUsername )->escaped() );
- break;
- case self::ABORTED:
- $error = $this->mAbortLoginErrorMsg ?: 'login-abort-generic';
- $this->mainLoginForm( $this->msg( $error,
- wfEscapeWikiText( $this->mUsername ) )->text() );
- break;
- case self::USER_MIGRATED:
- $error = $this->mAbortLoginErrorMsg ?: 'login-migrated-generic';
- $params = [];
- if ( is_array( $error ) ) {
- $error = array_shift( $this->mAbortLoginErrorMsg );
- $params = $this->mAbortLoginErrorMsg;
- }
- $this->mainLoginForm( $this->msg( $error, $params )->text() );
- break;
- default:
- throw new MWException( 'Unhandled case value' );
- }
-
- LoggerFactory::getInstance( 'authmanager' )->info( 'Login attempt', [
- 'event' => 'login',
- 'successful' => $authRes === self::SUCCESS,
- 'status' => LoginForm::$statusCodes[$authRes],
- ] );
- }
-
- /**
- * Show the Special:ChangePassword form, with custom message
- * @param Message $msg
- */
- protected function resetLoginForm( Message $msg ) {
- // Allow hooks to explain this password reset in more detail
- Hooks::run( 'LoginPasswordResetMessage', [ &$msg, $this->mUsername ] );
- $reset = new SpecialChangePassword();
- $derivative = new DerivativeContext( $this->getContext() );
- $derivative->setTitle( $reset->getPageTitle() );
- $reset->setContext( $derivative );
- if ( !$this->mTempPasswordUsed ) {
- $reset->setOldPasswordMessage( 'oldpassword' );
- }
- $reset->setChangeMessage( $msg );
- $reset->execute( null );
- }
-
- /**
- * @param User $u
- * @param bool $throttle
- * @param string $emailTitle Message name of email title
- * @param string $emailText Message name of email text
- * @return Status
- */
- function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle',
- $emailText = 'passwordremindertext'
- ) {
- global $wgNewPasswordExpiry, $wgMinimalPasswordLength;
-
- if ( $u->getEmail() == '' ) {
- return Status::newFatal( 'noemail', $u->getName() );
- }
- $ip = $this->getRequest()->getIP();
- if ( !$ip ) {
- return Status::newFatal( 'badipaddress' );
- }
-
- $currentUser = $this->getUser();
- Hooks::run( 'User::mailPasswordInternal', [ &$currentUser, &$ip, &$u ] );
-
- $np = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
- $u->setNewpassword( $np, $throttle );
- $u->saveSettings();
- $userLanguage = $u->getOption( 'language' );
-
- $mainPage = Title::newMainPage();
- $mainPageUrl = $mainPage->getCanonicalURL();
-
- $m = $this->msg( $emailText, $ip, $u->getName(), $np, '<' . $mainPageUrl . '>',
- round( $wgNewPasswordExpiry / 86400 ) )->inLanguage( $userLanguage )->text();
- $result = $u->sendMail( $this->msg( $emailTitle )->inLanguage( $userLanguage )->text(), $m );
-
- return $result;
- }
-
- /**
- * Run any hooks registered for logins, then HTTP redirect to
- * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a
- * nice message here, but that's really not as useful as just being sent to
- * wherever you logged in from. It should be clear that the action was
- * successful, given the lack of error messages plus the appearance of your
- * name in the upper right.
- *
- * @private
- */
- function successfulLogin() {
- # Run any hooks; display injected HTML if any, else redirect
- $currentUser = $this->getUser();
- $injected_html = '';
- Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html ] );
-
- if ( $injected_html !== '' ) {
- $this->displaySuccessfulAction( 'success', $this->msg( 'loginsuccesstitle' ),
- 'loginsuccess', $injected_html );
- } else {
- $this->executeReturnTo( 'successredirect' );
- }
- }
-
- /**
- * Run any hooks registered for logins, then display a message welcoming
- * the user.
- *
- * @private
- */
- function successfulCreation() {
- # Run any hooks; display injected HTML
- $currentUser = $this->getUser();
- $injected_html = '';
- $welcome_creation_msg = 'welcomecreation-msg';
-
- Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html ] );
-
- /**
- * Let any extensions change what message is shown.
- * @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforeWelcomeCreation
- * @since 1.18
- */
- Hooks::run( 'BeforeWelcomeCreation', [ &$welcome_creation_msg, &$injected_html ] );
-
- $this->displaySuccessfulAction(
- 'signup',
- $this->msg( 'welcomeuser', $this->getUser()->getName() ),
- $welcome_creation_msg, $injected_html
- );
- }
-
- /**
- * Display a "successful action" page.
- *
- * @param string $type Condition of return to; see `executeReturnTo`
- * @param string|Message $title Page's title
- * @param string $msgname
- * @param string $injected_html
- */
- private function displaySuccessfulAction( $type, $title, $msgname, $injected_html ) {
- $out = $this->getOutput();
- $out->setPageTitle( $title );
- if ( $msgname ) {
- $out->addWikiMsg( $msgname, wfEscapeWikiText( $this->getUser()->getName() ) );
- }
-
- $out->addHTML( $injected_html );
-
- $this->executeReturnTo( $type );
- }
-
- /**
- * Output a message that informs the user that they cannot create an account because
- * there is a block on them or their IP which prevents account creation. Note that
- * User::isBlockedFromCreateAccount(), which gets this block, ignores the 'hardblock'
- * setting on blocks (bug 13611).
- * @param Block $block The block causing this error
- * @throws ErrorPageError
- */
- function userBlockedMessage( Block $block ) {
- # Let's be nice about this, it's likely that this feature will be used
- # for blocking large numbers of innocent people, e.g. range blocks on
- # schools. Don't blame it on the user. There's a small chance that it
- # really is the user's fault, i.e. the username is blocked and they
- # haven't bothered to log out before trying to create an account to
- # evade it, but we'll leave that to their guilty conscience to figure
- # out.
- $errorParams = [
- $block->getTarget(),
- $block->mReason ? $block->mReason : $this->msg( 'blockednoreason' )->text(),
- $block->getByName()
- ];
-
- if ( $block->getType() === Block::TYPE_RANGE ) {
- $errorMessage = 'cantcreateaccount-range-text';
- $errorParams[] = $this->getRequest()->getIP();
- } else {
- $errorMessage = 'cantcreateaccount-text';
- }
-
- throw new ErrorPageError(
- 'cantcreateaccounttitle',
- $errorMessage,
- $errorParams
- );
- }
-
- /**
- * Add a "return to" link or redirect to it.
- * Extensions can use this to reuse the "return to" logic after
- * inject steps (such as redirection) into the login process.
- *
- * @param string $type One of the following:
- * - error: display a return to link ignoring $wgRedirectOnLogin
- * - signup: display a return to link using $wgRedirectOnLogin if needed
- * - success: display a return to link using $wgRedirectOnLogin if needed
- * - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
- * @param string $returnTo
- * @param array|string $returnToQuery
- * @param bool $stickHTTPs Keep redirect link on HTTPs
- * @since 1.22
- */
- public function showReturnToPage(
- $type, $returnTo = '', $returnToQuery = '', $stickHTTPs = false
- ) {
- $this->mReturnTo = $returnTo;
- $this->mReturnToQuery = $returnToQuery;
- $this->mStickHTTPS = $stickHTTPs;
- $this->executeReturnTo( $type );
- }
-
- /**
- * Add a "return to" link or redirect to it.
- *
- * @param string $type One of the following:
- * - error: display a return to link ignoring $wgRedirectOnLogin
- * - signup: display a return to link using $wgRedirectOnLogin if needed
- * - success: display a return to link using $wgRedirectOnLogin if needed
- * - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
- */
- private function executeReturnTo( $type ) {
- global $wgRedirectOnLogin, $wgSecureLogin;
-
- if ( $type != 'error' && $wgRedirectOnLogin !== null ) {
- $returnTo = $wgRedirectOnLogin;
- $returnToQuery = [];
- } else {
- $returnTo = $this->mReturnTo;
- $returnToQuery = wfCgiToArray( $this->mReturnToQuery );
- }
-
- // Allow modification of redirect behavior
- Hooks::run( 'PostLoginRedirect', [ &$returnTo, &$returnToQuery, &$type ] );
-
- $returnToTitle = Title::newFromText( $returnTo );
- if ( !$returnToTitle ) {
- $returnToTitle = Title::newMainPage();
- }
-
- if ( $wgSecureLogin && !$this->mStickHTTPS ) {
- $options = [ 'http' ];
- $proto = PROTO_HTTP;
- } elseif ( $wgSecureLogin ) {
- $options = [ 'https' ];
- $proto = PROTO_HTTPS;
- } else {
- $options = [];
- $proto = PROTO_RELATIVE;
- }
-
- if ( $type == 'successredirect' ) {
- $redirectUrl = $returnToTitle->getFullURL( $returnToQuery, false, $proto );
- $this->getOutput()->redirect( $redirectUrl );
- } else {
- $this->getOutput()->addReturnTo( $returnToTitle, $returnToQuery, null, $options );
- }
- }
-
- /**
- * @param string $msg
- * @param string $msgtype
- * @throws ErrorPageError
- * @throws Exception
- * @throws FatalError
- * @throws MWException
- * @throws PermissionsError
- * @throws ReadOnlyError
- * @private
- */
- function mainLoginForm( $msg, $msgtype = 'error' ) {
- global $wgEnableEmail, $wgEnableUserEmail;
- global $wgHiddenPrefs, $wgLoginLanguageSelector;
- global $wgAuth, $wgEmailConfirmToEdit;
- global $wgSecureLogin, $wgPasswordResetRoutes;
- global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
-
- $titleObj = $this->getPageTitle();
- $user = $this->getUser();
- $out = $this->getOutput();
-
- if ( $this->mType == 'signup' ) {
- // Block signup here if in readonly. Keeps user from
- // going through the process (filling out data, etc)
- // and being informed later.
- $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $user, true );
- if ( count( $permErrors ) ) {
- throw new PermissionsError( 'createaccount', $permErrors );
- } elseif ( $user->isBlockedFromCreateAccount() ) {
- $this->userBlockedMessage( $user->isBlockedFromCreateAccount() );
-
- return;
- } elseif ( wfReadOnly() ) {
- throw new ReadOnlyError;
- }
- }
-
- // Pre-fill username (if not creating an account, bug 44775).
- if ( $this->mUsername == '' && $this->mType != 'signup' ) {
- if ( $user->isLoggedIn() ) {
- $this->mUsername = $user->getName();
- } else {
- $this->mUsername = $this->getRequest()->getSession()->suggestLoginUsername();
- }
- }
-
- // Generic styles and scripts for both login and signup form
- $out->addModuleStyles( [
- 'mediawiki.ui',
- 'mediawiki.ui.button',
- 'mediawiki.ui.checkbox',
- 'mediawiki.ui.input',
- 'mediawiki.special.userlogin.common.styles'
- ] );
-
- if ( $this->mType == 'signup' ) {
- // Additional styles and scripts for signup form
- $out->addModules( [
- 'mediawiki.special.userlogin.signup.js'
- ] );
- $out->addModuleStyles( [
- 'mediawiki.special.userlogin.signup.styles'
- ] );
-
- $template = new UsercreateTemplate( $this->getConfig() );
-
- // Must match number of benefits defined in messages
- $template->set( 'benefitCount', 3 );
-
- $q = 'action=submitlogin&type=signup';
- $linkq = 'type=login';
- } else {
- // Additional styles for login form
- $out->addModuleStyles( [
- 'mediawiki.special.userlogin.login.styles'
- ] );
-
- $template = new UserloginTemplate( $this->getConfig() );
-
- $q = 'action=submitlogin&type=login';
- $linkq = 'type=signup';
- }
-
- if ( $this->mReturnTo !== '' ) {
- $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
- if ( $this->mReturnToQuery !== '' ) {
- $returnto .= '&returntoquery=' .
- wfUrlencode( $this->mReturnToQuery );
- }
- $q .= $returnto;
- $linkq .= $returnto;
- }
-
- # Don't show a "create account" link if the user can't.
- if ( $this->showCreateOrLoginLink( $user ) ) {
- # Pass any language selection on to the mode switch link
- if ( $wgLoginLanguageSelector && $this->mLanguage ) {
- $linkq .= '&uselang=' . $this->mLanguage;
- }
- // Supply URL, login template creates the button.
- $template->set( 'createOrLoginHref', $titleObj->getLocalURL( $linkq ) );
- } else {
- $template->set( 'link', '' );
- }
-
- $resetLink = $this->mType == 'signup'
- ? null
- : is_array( $wgPasswordResetRoutes ) && in_array( true, array_values( $wgPasswordResetRoutes ) );
-
- $template->set( 'header', '' );
- $template->set( 'formheader', '' );
- $template->set( 'skin', $this->getSkin() );
- $template->set( 'name', $this->mUsername );
- $template->set( 'password', $this->mPassword );
- $template->set( 'retype', $this->mRetype );
- $template->set( 'createemailset', $this->mCreateaccountMail );
- $template->set( 'email', $this->mEmail );
- $template->set( 'realname', $this->mRealName );
- $template->set( 'domain', $this->mDomain );
- $template->set( 'reason', $this->mReason );
-
- $template->set( 'action', $titleObj->getLocalURL( $q ) );
- $template->set( 'message', $msg );
- $template->set( 'messagetype', $msgtype );
- $template->set( 'createemail', $wgEnableEmail && $user->isLoggedIn() );
- $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) );
- $template->set( 'useemail', $wgEnableEmail );
- $template->set( 'emailrequired', $wgEmailConfirmToEdit );
- $template->set( 'emailothers', $wgEnableUserEmail );
- $template->set( 'canreset', $wgAuth->allowPasswordChange() );
- $template->set( 'resetlink', $resetLink );
- $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ?
- ( $wgCookieExpiration > 0 ) :
- ( $wgExtendedLoginCookieExpiration > 0 ) );
- $template->set( 'usereason', $user->isLoggedIn() );
- $template->set( 'remember', $this->mRemember );
- $template->set( 'cansecurelogin', ( $wgSecureLogin === true ) );
- $template->set( 'stickhttps', (int)$this->mStickHTTPS );
- $template->set( 'loggedin', $user->isLoggedIn() );
- $template->set( 'loggedinuser', $user->getName() );
-
- if ( $this->mType == 'signup' ) {
- $template->set( 'token', self::getCreateaccountToken()->toString() );
- } else {
- $template->set( 'token', self::getLoginToken()->toString() );
- }
-
- # Prepare language selection links as needed
- if ( $wgLoginLanguageSelector ) {
- $template->set( 'languages', $this->makeLanguageSelector() );
- if ( $this->mLanguage ) {
- $template->set( 'uselang', $this->mLanguage );
- }
- }
-
- $template->set( 'secureLoginUrl', $this->mSecureLoginUrl );
- // Use signupend-https for HTTPS requests if it's not blank, signupend otherwise
- $usingHTTPS = $this->mRequest->getProtocol() == 'https';
- $signupendHTTPS = $this->msg( 'signupend-https' );
- if ( $usingHTTPS && !$signupendHTTPS->isBlank() ) {
- $template->set( 'signupend', $signupendHTTPS->parse() );
- } else {
- $template->set( 'signupend', $this->msg( 'signupend' )->parse() );
- }
-
- // If using HTTPS coming from HTTP, then the 'fromhttp' parameter must be preserved
- if ( $usingHTTPS ) {
- $template->set( 'fromhttp', $this->mFromHTTP );
- }
-
- // Give authentication and captcha plugins a chance to modify the form
- $wgAuth->modifyUITemplate( $template, $this->mType );
- if ( $this->mType == 'signup' ) {
- Hooks::run( 'UserCreateForm', [ &$template ] );
- } else {
- Hooks::run( 'UserLoginForm', [ &$template ] );
- }
-
- $out->disallowUserJs(); // just in case...
- $out->addTemplate( $template );
- }
-
- /**
- * Whether the login/create account form should display a link to the
- * other form (in addition to whatever the skin provides).
- *
- * @param User $user
- * @return bool
- */
- private function showCreateOrLoginLink( &$user ) {
- if ( $this->mType == 'signup' ) {
- return true;
- } elseif ( $user->isAllowed( 'createaccount' ) ) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Check if a session cookie is present.
- *
- * This will not pick up a cookie set during _this_ request, but is meant
- * to ensure that the client is returning the cookie which was set on a
- * previous pass through the system.
- *
- * @private
- * @return bool
- */
- function hasSessionCookie() {
- global $wgDisableCookieCheck, $wgInitialSessionId;
-
- return $wgDisableCookieCheck || (
- $wgInitialSessionId &&
- $this->getRequest()->getSession()->getId() === (string)$wgInitialSessionId
- );
- }
-
- /**
- * Get the login token from the current session
- * @since 1.27 returns a MediaWiki\Session\Token instead of a string
- * @return MediaWiki\Session\Token
- */
- public static function getLoginToken() {
- global $wgRequest;
- return $wgRequest->getSession()->getToken( '', 'login' );
- }
-
- /**
- * Formerly randomly generated a login token that would be returned by
- * $this->getLoginToken().
- *
- * Since 1.27, this is a no-op. The token is generated as necessary by
- * $this->getLoginToken().
- *
- * @deprecated since 1.27
- */
- public static function setLoginToken() {
- wfDeprecated( __METHOD__, '1.27' );
- }
-
- /**
- * Remove any login token attached to the current session
- */
- public static function clearLoginToken() {
- global $wgRequest;
- $wgRequest->getSession()->resetToken( 'login' );
- }
-
- /**
- * Get the createaccount token from the current session
- * @since 1.27 returns a MediaWiki\Session\Token instead of a string
- * @return MediaWiki\Session\Token
- */
- public static function getCreateaccountToken() {
- global $wgRequest;
- return $wgRequest->getSession()->getToken( '', 'createaccount' );
- }
-
- /**
- * Formerly randomly generated a createaccount token that would be returned
- * by $this->getCreateaccountToken().
- *
- * Since 1.27, this is a no-op. The token is generated as necessary by
- * $this->getCreateaccountToken().
- *
- * @deprecated since 1.27
- */
- public static function setCreateaccountToken() {
- wfDeprecated( __METHOD__, '1.27' );
- }
-
- /**
- * Remove any createaccount token attached to the current session
- */
- public static function clearCreateaccountToken() {
- global $wgRequest;
- $wgRequest->getSession()->resetToken( 'createaccount' );
- }
-
- /**
- * Renew the user's session id, using strong entropy
- */
- private function renewSessionId() {
- global $wgSecureLogin, $wgCookieSecure;
- if ( $wgSecureLogin && !$this->mStickHTTPS ) {
- $wgCookieSecure = false;
- }
-
- SessionManager::getGlobalSession()->resetId();
- }
-
- /**
- * @param string $type
- * @private
- */
- function cookieRedirectCheck( $type ) {
- $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
- $query = [ 'wpCookieCheck' => $type ];
- if ( $this->mReturnTo !== '' ) {
- $query['returnto'] = $this->mReturnTo;
- $query['returntoquery'] = $this->mReturnToQuery;
- }
- $check = $titleObj->getFullURL( $query );
-
- $this->getOutput()->redirect( $check );
- }
-
- /**
- * @param string $type
- * @private
- */
- function onCookieRedirectCheck( $type ) {
- if ( !$this->hasSessionCookie() ) {
- if ( $type == 'new' ) {
- $this->mainLoginForm( $this->msg( 'nocookiesnew' )->parse() );
- } elseif ( $type == 'login' ) {
- $this->mainLoginForm( $this->msg( 'nocookieslogin' )->parse() );
- } else {
- # shouldn't happen
- $this->mainLoginForm( $this->msg( 'error' )->text() );
- }
- } else {
- $this->successfulLogin();
- }
- }
-
- /**
- * Produce a bar of links which allow the user to select another language
- * during login/registration but retain "returnto"
- *
- * @return string
- */
- function makeLanguageSelector() {
- $msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage();
- if ( $msg->isBlank() ) {
- return '';
- }
- $langs = explode( "\n", $msg->text() );
- $links = [];
- foreach ( $langs as $lang ) {
- $lang = trim( $lang, '* ' );
- $parts = explode( '|', $lang );
- if ( count( $parts ) >= 2 ) {
- $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
- }
- }
-
- return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams(
- $this->getLanguage()->pipeList( $links ) )->escaped() : '';
- }
-
- /**
- * Create a language selector link for a particular language
- * Links back to this page preserving type and returnto
- *
- * @param string $text Link text
- * @param string $lang Language code
- * @return string
- */
- function makeLanguageSelectorLink( $text, $lang ) {
- if ( $this->getLanguage()->getCode() == $lang ) {
- // no link for currently used language
- return htmlspecialchars( $text );
- }
- $query = [ 'uselang' => $lang ];
- if ( $this->mType == 'signup' ) {
- $query['type'] = 'signup';
- }
- if ( $this->mReturnTo !== '' ) {
- $query['returnto'] = $this->mReturnTo;
- $query['returntoquery'] = $this->mReturnToQuery;
- }
-
- $attr = [];
- $targetLanguage = Language::factory( $lang );
- $attr['lang'] = $attr['hreflang'] = $targetLanguage->getHtmlCode();
-
- return Linker::linkKnown(
- $this->getPageTitle(),
- htmlspecialchars( $text ),
- $attr,
- $query
- );
- }
-
- protected function getGroupName() {
- return 'login';
- }
-
- /**
- * Private function to check password expiration, until AuthManager comes
- * along to handle that.
- * @param User $user
- * @return string|bool
- */
- private function checkUserPasswordExpired( User $user ) {
- global $wgPasswordExpireGrace;
- $dbr = wfGetDB( DB_SLAVE );
- $ts = $dbr->selectField( 'user', 'user_password_expires', [ 'user_id' => $user->getId() ] );
-
- $expired = false;
- $now = wfTimestamp();
- $expUnix = wfTimestamp( TS_UNIX, $ts );
- if ( $ts !== null && $expUnix < $now ) {
- $expired = ( $expUnix + $wgPasswordExpireGrace < $now ) ? 'hard' : 'soft';
- }
- return $expired;
- }
-
- protected function getSubpagesForPrefixSearch() {
- return [ 'signup' ];
- }
-}
+++ /dev/null
-<?php
-/**
- * Implements Special:Userlogout
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * Implements Special:Userlogout
- *
- * @ingroup SpecialPage
- */
-class SpecialUserlogout extends UnlistedSpecialPage {
- function __construct() {
- parent::__construct( 'Userlogout' );
- }
-
- public function doesWrites() {
- return true;
- }
-
- function execute( $par ) {
- /**
- * Some satellite ISPs use broken precaching schemes that log people out straight after
- * they're logged in (bug 17790). Luckily, there's a way to detect such requests.
- */
- if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '&' ) !== false ) {
- wfDebug( "Special:Userlogout request {$_SERVER['REQUEST_URI']} looks suspicious, denying.\n" );
- throw new HttpError( 400, $this->msg( 'suspicious-userlogout' ), $this->msg( 'loginerror' ) );
- }
-
- $this->setHeaders();
- $this->outputHeader();
-
- // Make sure it's possible to log out
- $session = MediaWiki\Session\SessionManager::getGlobalSession();
- if ( !$session->canSetUser() ) {
- throw new ErrorPageError(
- 'cannotlogoutnow-title',
- 'cannotlogoutnow-text',
- [
- $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
- ]
- );
- }
-
- $user = $this->getUser();
- $oldName = $user->getName();
- $user->logout();
-
- $loginURL = SpecialPage::getTitleFor( 'Userlogin' )->getFullURL(
- $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
-
- $out = $this->getOutput();
- $out->addWikiMsg( 'logouttext', $loginURL );
-
- // Hook.
- $injected_html = '';
- Hooks::run( 'UserLogoutComplete', [ &$user, &$injected_html, $oldName ] );
- $out->addHTML( $injected_html );
-
- $out->returnToMain();
- }
-
- protected function getGroupName() {
- return 'login';
- }
-}
* @return array Tuple of added, then removed groups
*/
function doSaveUserGroups( $user, $add, $remove, $reason = '' ) {
- global $wgAuth;
-
// Validate input set...
$isself = $user->getName() == $this->getUser()->getName();
$groups = $user->getGroups();
// update groups in external authentication database
Hooks::run( 'UserGroupsChanged', [ $user, $add, $remove, $this->getUser(), $reason ] );
- $wgAuth->updateExternalDBGroups( $user, $add, $remove );
+ MediaWiki\Auth\AuthManager::callLegacyAuthPlugin(
+ 'updateExternalDBGroups', [ $user, $add, $remove ]
+ );
wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) . "\n" );
wfDebug( 'newGroups: ' . print_r( $newGroups, true ) . "\n" );
]
];
- $htmlForm = HTMLForm::factory( 'inline', $formDescriptor, $this->getContext() );
- $htmlForm->setWrapperLegendMsg( 'withoutinterwiki-legend' )
+ $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() );
+ $htmlForm->setWrapperLegend( '' )
->setSubmitTextMsg( 'withoutinterwiki-submit' )
->setMethod( 'get' )
->prepareForm()
--- /dev/null
+<?php
+
+/**
+ * Helper functions for the login form that need to be shared with other special pages
+ * (such as CentralAuth's SpecialCentralLogin).
+ * @since 1.27
+ */
+class LoginHelper extends ContextSource {
+ /**
+ * Valid error and warning messages
+ *
+ * Special:Userlogin can show an error or warning message on the form when
+ * coming from another page. This is done via the ?error= or ?warning= GET
+ * parameters.
+ *
+ * This array is the list of valid message keys. Further keys can be added by the
+ * LoginFormValidErrorMessages hook. All other values will be ignored.
+ *
+ * @var string[]
+ */
+ public static $validErrorMessages = [
+ 'exception-nologin-text',
+ 'watchlistanontext',
+ 'changeemail-no-info',
+ 'resetpass-no-info',
+ 'confirmemail_needlogin',
+ 'prefsnologintext2',
+ ];
+
+ /**
+ * Returns an array of all valid error messages.
+ *
+ * @return array
+ * @see LoginHelper::$validErrorMessages
+ */
+ public static function getValidErrorMessages() {
+ static $messages = null;
+ if ( !$messages ) {
+ $messages = self::$validErrorMessages;
+ Hooks::run( 'LoginFormValidErrorMessages', [ &$messages ] );
+ }
+
+ return $messages;
+ }
+
+ public function __construct( IContextSource $context ) {
+ $this->setContext( $context );
+ }
+
+ /**
+ * Show a return link or redirect to it.
+ * Extensions can change where the link should point or inject content into the page
+ * (which will change it from redirect to link mode).
+ *
+ * @param string $type One of the following:
+ * - error: display a return to link ignoring $wgRedirectOnLogin
+ * - success: display a return to link using $wgRedirectOnLogin if needed
+ * - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
+ * @param string $returnTo
+ * @param array|string $returnToQuery
+ * @param bool $stickHTTPS Keep redirect link on HTTPS
+ */
+ public function showReturnToPage(
+ $type, $returnTo = '', $returnToQuery = '', $stickHTTPS = false
+ ) {
+ global $wgRedirectOnLogin, $wgSecureLogin;
+
+ if ( $type !== 'error' && $wgRedirectOnLogin !== null ) {
+ $returnTo = $wgRedirectOnLogin;
+ $returnToQuery = [];
+ } elseif ( is_string( $returnToQuery ) ) {
+ $returnToQuery = wfCgiToArray( $returnToQuery );
+ }
+
+ // Allow modification of redirect behavior
+ Hooks::run( 'PostLoginRedirect', [ &$returnTo, &$returnToQuery, &$type ] );
+
+ $returnToTitle = Title::newFromText( $returnTo ) ?: Title::newMainPage();
+
+ if ( $wgSecureLogin && !$stickHTTPS ) {
+ $options = [ 'http' ];
+ $proto = PROTO_HTTP;
+ } elseif ( $wgSecureLogin ) {
+ $options = [ 'https' ];
+ $proto = PROTO_HTTPS;
+ } else {
+ $options = [];
+ $proto = PROTO_RELATIVE;
+ }
+
+ if ( $type === 'successredirect' ) {
+ $redirectUrl = $returnToTitle->getFullURL( $returnToQuery, false, $proto );
+ $this->getOutput()->redirect( $redirectUrl );
+ } else {
+ $this->getOutput()->addReturnTo( $returnToTitle, $returnToQuery, null, $options );
+ }
+ }
+}
/**
* @param IContextSource $context
- * @param null $group Unused
- * @param string $par Parameter passed to the page
+ * @param FormOptions $opts
*/
- function __construct( IContextSource $context = null, $group = null, $par = null ) {
+ function __construct( IContextSource $context = null, FormOptions $opts ) {
parent::__construct( $context );
$this->RCMaxAge = $this->getConfig()->get( 'ActiveUserDays' );
- $un = $this->getRequest()->getText( 'username', $par );
$this->requestedUser = '';
+
+ $un = $opts->getValue( 'username' );
if ( $un != '' ) {
$username = Title::makeTitleSafe( NS_USER, $un );
if ( !is_null( $username ) ) {
}
}
- $this->setupOptions();
- }
-
- public function setupOptions() {
- $this->opts = new FormOptions();
-
- $this->opts->add( 'hidebots', false, FormOptions::BOOL );
- $this->opts->add( 'hidesysops', false, FormOptions::BOOL );
-
- $this->opts->fetchValuesFromRequest( $this->getRequest() );
-
- if ( $this->opts->getValue( 'hidebots' ) == 1 ) {
+ if ( $opts->getValue( 'hidebots' ) == 1 ) {
$this->hideRights[] = 'bot';
}
- if ( $this->opts->getValue( 'hidesysops' ) == 1 ) {
+ if ( $opts->getValue( 'hidesysops' ) == 1 ) {
$this->hideGroups[] = 'sysop';
}
}
return Html::rawElement( 'li', [], "{$item} [{$count}]{$blocked}" );
}
- function getPageHeader() {
- $self = $this->getTitle();
- $limit = $this->mLimit ? Html::hidden( 'limit', $this->mLimit ) : '';
-
- # Form tag
- $out = Xml::openElement( 'form', [ 'method' => 'get', 'action' => wfScript() ] );
- $out .= Xml::fieldset( $this->msg( 'activeusers' )->text() ) . "\n";
- $out .= Html::hidden( 'title', $self->getPrefixedDBkey() ) . $limit . "\n";
-
- # Username field (with autocompletion support)
- $this->getOutput()->addModules( 'mediawiki.userSuggest' );
- $out .= Xml::inputLabel(
- $this->msg( 'activeusers-from' )->text(),
- 'username',
- 'offset',
- 20,
- $this->requestedUser,
- [
- 'class' => 'mw-ui-input-inline mw-autocomplete-user',
- 'tabindex' => 1,
- ] + (
- // Set autofocus on blank input
- $this->requestedUser === '' ? [ 'autofocus' => '' ] : []
- )
- ) . '<br />';
-
- $out .= Xml::checkLabel( $this->msg( 'activeusers-hidebots' )->text(),
- 'hidebots', 'hidebots', $this->opts->getValue( 'hidebots' ), [ 'tabindex' => 2 ] );
-
- $out .= Xml::checkLabel(
- $this->msg( 'activeusers-hidesysops' )->text(),
- 'hidesysops',
- 'hidesysops',
- $this->opts->getValue( 'hidesysops' ),
- [ 'tabindex' => 3 ]
- ) . '<br />';
-
- # Submit button and form bottom
- $out .= Xml::submitButton(
- $this->msg( 'activeusers-submit' )->text(),
- [ 'tabindex' => 4 ]
- ) . "\n";
- $out .= Xml::closeElement( 'fieldset' );
- $out .= Xml::closeElement( 'form' );
-
- return $out;
- }
-
}
$this->lang = ( $langObj ? $langObj : $wgContLang );
$this->langcode = $this->lang->getCode();
- $this->foreign = $this->langcode !== $wgContLang->getCode();
+ $this->foreign = !$this->lang->equals( $wgContLang );
$request = $this->getRequest();
--- /dev/null
+This directory temporarily hosts pre-AuthManager code as a way of feature-flagging.
+Class names are postfixed with 'PreAuthManager' and SpecialPageFactory adds/removes
+that postfix based on the feature flag.
+
+This is a horrible hack that will only be in place for a few weeks, to allow instant
+rollback while AuthManager is tested in WMF production and major problems are ironed
+out. In the past such issues have been handled via deployment branches, but that
+meant blocking the work of all WMF developers from being deployed. This is hoped
+to be a less disruptive method.
+
--- /dev/null
+<?php
+/**
+ * Implements Special:ChangeEmail
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Let users change their email address.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialChangeEmailPreAuthManager extends FormSpecialPage {
+ /**
+ * @var Status
+ */
+ private $status;
+
+ public function __construct() {
+ parent::__construct( 'ChangeEmail', 'editmyprivateinfo' );
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isListed() {
+ global $wgAuth;
+
+ return $wgAuth->allowPropChange( 'emailaddress' );
+ }
+
+ /**
+ * Main execution point
+ * @param string $par
+ */
+ function execute( $par ) {
+ $out = $this->getOutput();
+ $out->disallowUserJs();
+
+ parent::execute( $par );
+ }
+
+ protected function checkExecutePermissions( User $user ) {
+ global $wgAuth;
+
+ if ( !$wgAuth->allowPropChange( 'emailaddress' ) ) {
+ throw new ErrorPageError( 'changeemail', 'cannotchangeemail' );
+ }
+
+ $this->requireLogin( 'changeemail-no-info' );
+
+ // This could also let someone check the current email address, so
+ // require both permissions.
+ if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) {
+ throw new PermissionsError( 'viewmyprivateinfo' );
+ }
+
+ parent::checkExecutePermissions( $user );
+ }
+
+ protected function getFormFields() {
+ $user = $this->getUser();
+
+ $fields = [
+ 'Name' => [
+ 'type' => 'info',
+ 'label-message' => 'username',
+ 'default' => $user->getName(),
+ ],
+ 'OldEmail' => [
+ 'type' => 'info',
+ 'label-message' => 'changeemail-oldemail',
+ 'default' => $user->getEmail() ?: $this->msg( 'changeemail-none' )->text(),
+ ],
+ 'NewEmail' => [
+ 'type' => 'email',
+ 'label-message' => 'changeemail-newemail',
+ 'autofocus' => true,
+ 'help-message' => 'changeemail-newemail-help',
+ ],
+ ];
+
+ if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
+ $fields['Password'] = [
+ 'type' => 'password',
+ 'label-message' => 'changeemail-password'
+ ];
+ }
+
+ return $fields;
+ }
+
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
+ protected function alterForm( HTMLForm $form ) {
+ $form->setId( 'mw-changeemail-form' );
+ $form->setTableId( 'mw-changeemail-table' );
+ $form->setSubmitTextMsg( 'changeemail-submit' );
+ $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
+
+ $form->addHeaderText( $this->msg( 'changeemail-header' )->parseAsBlock() );
+ if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
+ $form->addHeaderText( $this->msg( 'changeemail-passwordrequired' )->parseAsBlock() );
+ }
+ }
+
+ public function onSubmit( array $data ) {
+ $password = isset( $data['Password'] ) ? $data['Password'] : null;
+ $status = $this->attemptChange( $this->getUser(), $password, $data['NewEmail'] );
+
+ $this->status = $status;
+
+ return $status;
+ }
+
+ public function onSuccess() {
+ $request = $this->getRequest();
+
+ $returnto = $request->getVal( 'returnto' );
+ $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
+ if ( !$titleObj instanceof Title ) {
+ $titleObj = Title::newMainPage();
+ }
+ $query = $request->getVal( 'returntoquery' );
+
+ if ( $this->status->value === true ) {
+ $this->getOutput()->redirect( $titleObj->getFullURL( $query ) );
+ } elseif ( $this->status->value === 'eauth' ) {
+ # Notify user that a confirmation email has been sent...
+ $this->getOutput()->wrapWikiMsg( "<div class='error' style='clear: both;'>\n$1\n</div>",
+ 'eauthentsent', $this->getUser()->getName() );
+ // just show the link to go back
+ $this->getOutput()->addReturnTo( $titleObj, wfCgiToArray( $query ) );
+ }
+ }
+
+ /**
+ * @param User $user
+ * @param string $pass
+ * @param string $newaddr
+ * @return Status
+ */
+ private function attemptChange( User $user, $pass, $newaddr ) {
+ global $wgAuth;
+
+ if ( $newaddr != '' && !Sanitizer::validateEmail( $newaddr ) ) {
+ return Status::newFatal( 'invalidemailaddress' );
+ }
+
+ if ( $newaddr === $user->getEmail() ) {
+ return Status::newFatal( 'changeemail-nochange' );
+ }
+
+ $throttleInfo = LoginForm::incrementLoginThrottle( $user->getName() );
+ if ( $throttleInfo ) {
+ $lang = $this->getLanguage();
+ return Status::newFatal(
+ 'changeemail-throttled',
+ $lang->formatDuration( $throttleInfo['wait'] )
+ );
+ }
+
+ if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' )
+ && !$user->checkTemporaryPassword( $pass )
+ && !$user->checkPassword( $pass )
+ ) {
+ return Status::newFatal( 'wrongpassword' );
+ }
+
+ LoginForm::clearLoginThrottle( $user->getName() );
+
+ $oldaddr = $user->getEmail();
+ $status = $user->setEmailWithConfirmation( $newaddr );
+ if ( !$status->isGood() ) {
+ return $status;
+ }
+
+ Hooks::run( 'PrefsEmailAudit', [ $user, $oldaddr, $newaddr ] );
+
+ $user->saveSettings();
+
+ $wgAuth->updateExternalDB( $user );
+
+ return $status;
+ }
+
+ public function requiresUnblock() {
+ return false;
+ }
+
+ protected function getGroupName() {
+ return 'users';
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements Special:ChangePassword
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Let users recover their password.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialChangePasswordPreAuthManager extends FormSpecialPage {
+ protected $mUserName;
+ protected $mDomain;
+
+ // Optional Wikitext Message to show above the password change form
+ protected $mPreTextMessage = null;
+
+ // label for old password input
+ protected $mOldPassMsg = null;
+
+ public function __construct() {
+ parent::__construct( 'ChangePassword', 'editmyprivateinfo' );
+ $this->listed( false );
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ /**
+ * Main execution point
+ * @param string|null $par
+ */
+ function execute( $par ) {
+ $this->getOutput()->disallowUserJs();
+
+ parent::execute( $par );
+ }
+
+ protected function checkExecutePermissions( User $user ) {
+ parent::checkExecutePermissions( $user );
+
+ if ( !$this->getRequest()->wasPosted() ) {
+ $this->requireLogin( 'resetpass-no-info' );
+ }
+ }
+
+ /**
+ * Set a message at the top of the Change Password form
+ * @since 1.23
+ * @param Message $msg Message to parse and add to the form header
+ */
+ public function setChangeMessage( Message $msg ) {
+ $this->mPreTextMessage = $msg;
+ }
+
+ /**
+ * Set a message at the top of the Change Password form
+ * @since 1.23
+ * @param string $msg Message label for old/temp password field
+ */
+ public function setOldPasswordMessage( $msg ) {
+ $this->mOldPassMsg = $msg;
+ }
+
+ protected function getFormFields() {
+ $user = $this->getUser();
+ $request = $this->getRequest();
+
+ $oldpassMsg = $this->mOldPassMsg;
+ if ( $oldpassMsg === null ) {
+ $oldpassMsg = $user->isLoggedIn() ? 'oldpassword' : 'resetpass-temp-password';
+ }
+
+ $fields = [
+ 'Name' => [
+ 'type' => 'info',
+ 'label-message' => 'username',
+ 'default' => $request->getVal( 'wpName', $user->getName() ),
+ ],
+ 'Password' => [
+ 'type' => 'password',
+ 'label-message' => $oldpassMsg,
+ ],
+ 'NewPassword' => [
+ 'type' => 'password',
+ 'label-message' => 'newpassword',
+ ],
+ 'Retype' => [
+ 'type' => 'password',
+ 'label-message' => 'retypenew',
+ ],
+ ];
+
+ if ( !$this->getUser()->isLoggedIn() ) {
+ $fields['LoginOnChangeToken'] = [
+ 'type' => 'hidden',
+ 'label' => 'Change Password Token',
+ 'default' => LoginForm::getLoginToken()->toString(),
+ ];
+ }
+
+ $extraFields = [];
+ Hooks::run( 'ChangePasswordForm', [ &$extraFields ] );
+ foreach ( $extraFields as $extra ) {
+ list( $name, $label, $type, $default ) = $extra;
+ $fields[$name] = [
+ 'type' => $type,
+ 'name' => $name,
+ 'label-message' => $label,
+ 'default' => $default,
+ ];
+ }
+
+ if ( !$user->isLoggedIn() ) {
+ $fields['Remember'] = [
+ 'type' => 'check',
+ 'label' => $this->msg( 'remembermypassword' )
+ ->numParams(
+ ceil( $this->getConfig()->get( 'CookieExpiration' ) / ( 3600 * 24 ) )
+ )->text(),
+ 'default' => $request->getVal( 'wpRemember' ),
+ ];
+ }
+
+ return $fields;
+ }
+
+ protected function alterForm( HTMLForm $form ) {
+ $form->setId( 'mw-resetpass-form' );
+ $form->setTableId( 'mw-resetpass-table' );
+ $form->setWrapperLegendMsg( 'resetpass_header' );
+ $form->setSubmitTextMsg(
+ $this->getUser()->isLoggedIn()
+ ? 'resetpass-submit-loggedin'
+ : 'resetpass_submit'
+ );
+ $form->addButton( [
+ 'name' => 'wpCancel',
+ 'value' => $this->msg( 'resetpass-submit-cancel' )->text()
+ ] );
+ $form->setHeaderText( $this->msg( 'resetpass_text' )->parseAsBlock() );
+ if ( $this->mPreTextMessage instanceof Message ) {
+ $form->addPreText( $this->mPreTextMessage->parseAsBlock() );
+ }
+ $form->addHiddenFields(
+ $this->getRequest()->getValues( 'wpName', 'wpDomain', 'returnto', 'returntoquery' ) );
+ }
+
+ public function onSubmit( array $data ) {
+ global $wgAuth;
+
+ $request = $this->getRequest();
+
+ if ( $request->getCheck( 'wpLoginToken' ) ) {
+ // This comes from Special:Userlogin when logging in with a temporary password
+ return false;
+ }
+
+ if ( !$this->getUser()->isLoggedIn()
+ && !LoginForm::getLoginToken()->match( $request->getVal( 'wpLoginOnChangeToken' ) )
+ ) {
+ // Potential CSRF (bug 62497)
+ return false;
+ }
+
+ if ( $request->getCheck( 'wpCancel' ) ) {
+ $returnto = $request->getVal( 'returnto' );
+ $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
+ if ( !$titleObj instanceof Title ) {
+ $titleObj = Title::newMainPage();
+ }
+ $query = $request->getVal( 'returntoquery' );
+ $this->getOutput()->redirect( $titleObj->getFullURL( $query ) );
+
+ return true;
+ }
+
+ $this->mUserName = $request->getVal( 'wpName', $this->getUser()->getName() );
+ $this->mDomain = $wgAuth->getDomain();
+
+ if ( !$wgAuth->allowPasswordChange() ) {
+ throw new ErrorPageError( 'changepassword', 'resetpass_forbidden' );
+ }
+
+ $status = $this->attemptReset( $data['Password'], $data['NewPassword'], $data['Retype'] );
+
+ return $status;
+ }
+
+ public function onSuccess() {
+ if ( $this->getUser()->isLoggedIn() ) {
+ $this->getOutput()->wrapWikiMsg(
+ "<div class=\"successbox\">\n$1\n</div>",
+ 'changepassword-success'
+ );
+ $this->getOutput()->returnToMain();
+ } else {
+ $request = $this->getRequest();
+ LoginForm::clearLoginToken();
+ $token = LoginForm::getLoginToken()->toString();
+ $data = [
+ 'action' => 'submitlogin',
+ 'wpName' => $this->mUserName,
+ 'wpDomain' => $this->mDomain,
+ 'wpLoginToken' => $token,
+ 'wpPassword' => $request->getVal( 'wpNewPassword' ),
+ ] + $request->getValues( 'wpRemember', 'returnto', 'returntoquery' );
+ $login = new LoginForm( new DerivativeRequest( $request, $data, true ) );
+ $login->setContext( $this->getContext() );
+ $login->execute( null );
+ }
+ }
+
+ /**
+ * Checks the new password if it meets the requirements for passwords and set
+ * it as a current password, otherwise set the passed Status object to fatal
+ * and doesn't change anything
+ *
+ * @param string $oldpass The current (temporary) password.
+ * @param string $newpass The password to set.
+ * @param string $retype The string of the retype password field to check with newpass
+ * @return Status
+ */
+ protected function attemptReset( $oldpass, $newpass, $retype ) {
+ $isSelf = ( $this->mUserName === $this->getUser()->getName() );
+ if ( $isSelf ) {
+ $user = $this->getUser();
+ } else {
+ $user = User::newFromName( $this->mUserName );
+ }
+
+ if ( !$user || $user->isAnon() ) {
+ return Status::newFatal( $this->msg( 'nosuchusershort', $this->mUserName ) );
+ }
+
+ if ( $newpass !== $retype ) {
+ Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'badretype' ] );
+ return Status::newFatal( $this->msg( 'badretype' ) );
+ }
+
+ $throttleInfo = LoginForm::incrementLoginThrottle( $this->mUserName );
+ if ( $throttleInfo ) {
+ return Status::newFatal( $this->msg( 'changepassword-throttled' )
+ ->durationParams( $throttleInfo['wait'] )
+ );
+ }
+
+ // @todo Make these separate messages, since the message is written for both cases
+ if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) {
+ Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'wrongpassword' ] );
+ return Status::newFatal( $this->msg( 'resetpass-wrong-oldpass' ) );
+ }
+
+ // User is resetting their password to their old password
+ if ( $oldpass === $newpass ) {
+ return Status::newFatal( $this->msg( 'resetpass-recycled' ) );
+ }
+
+ // Do AbortChangePassword after checking mOldpass, so we don't leak information
+ // by possibly aborting a new password before verifying the old password.
+ $abortMsg = 'resetpass-abort-generic';
+ if ( !Hooks::run( 'AbortChangePassword', [ $user, $oldpass, $newpass, &$abortMsg ] ) ) {
+ Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'abortreset' ] );
+ return Status::newFatal( $this->msg( $abortMsg ) );
+ }
+
+ // Please reset throttle for successful logins, thanks!
+ LoginForm::clearLoginThrottle( $this->mUserName );
+
+ try {
+ $user->setPassword( $newpass );
+ Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'success' ] );
+ } catch ( PasswordError $e ) {
+ Hooks::run( 'PrefsPasswordAudit', [ $user, $newpass, 'error' ] );
+ return Status::newFatal( new RawMessage( $e->getMessage() ) );
+ }
+
+ if ( $isSelf ) {
+ // This is needed to keep the user connected since
+ // changing the password also modifies the user's token.
+ $remember = $this->getRequest()->getCookie( 'Token' ) !== null;
+ $user->setCookies( null, null, $remember );
+ }
+ $user->saveSettings();
+ $this->resetPasswordExpiration( $user );
+ return Status::newGood();
+ }
+
+ public function requiresUnblock() {
+ return false;
+ }
+
+ protected function getGroupName() {
+ return 'users';
+ }
+
+ /**
+ * For resetting user password expiration, until AuthManager comes along
+ * @param User $user
+ */
+ private function resetPasswordExpiration( User $user ) {
+ global $wgPasswordExpirationDays;
+ $newExpire = null;
+ if ( $wgPasswordExpirationDays ) {
+ $newExpire = wfTimestamp(
+ TS_MW,
+ time() + ( $wgPasswordExpirationDays * 24 * 3600 )
+ );
+ }
+ // Give extensions a chance to force an expiration
+ Hooks::run( 'ResetPasswordExpiration', [ $this, &$newExpire ] );
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update(
+ 'user',
+ [ 'user_password_expires' => $dbw->timestampOrNull( $newExpire ) ],
+ [ 'user_id' => $user->getId() ],
+ __METHOD__
+ );
+ }
+
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+}
--- /dev/null
+<?php
+/**
+ * Redirect page: Special:CreateAccount --> Special:UserLogin/signup.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Redirect page: Special:CreateAccount --> Special:UserLogin/signup.
+ * @todo FIXME: This (and the rest of the login frontend) needs to die a horrible painful death
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialCreateAccountPreAuthManager extends SpecialRedirectToSpecial {
+ function __construct() {
+ parent::__construct(
+ 'CreateAccount',
+ 'Userlogin',
+ 'signup',
+ [ 'returnto', 'returntoquery', 'uselang' ]
+ );
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ // No reason to hide this link on Special:Specialpages
+ public function isListed() {
+ return true;
+ }
+
+ public function isRestricted() {
+ return !User::groupHasPermission( '*', 'createaccount' );
+ }
+
+ public function userCanExecute( User $user ) {
+ return $user->isAllowed( 'createaccount' );
+ }
+
+ protected function getGroupName() {
+ return 'login';
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements Special:PasswordReset
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Special page for requesting a password reset email
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialPasswordResetPreAuthManager extends FormSpecialPage {
+ /**
+ * @var Message
+ */
+ private $email;
+
+ /**
+ * @var User
+ */
+ private $firstUser;
+
+ /**
+ * @var Status
+ */
+ private $result;
+
+ /**
+ * @var string $method Identifies which password reset field was specified by the user.
+ */
+ private $method;
+
+ public function __construct() {
+ parent::__construct( 'PasswordReset', 'editmyprivateinfo' );
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ public function userCanExecute( User $user ) {
+ return $this->canChangePassword( $user ) === true && parent::userCanExecute( $user );
+ }
+
+ public function checkExecutePermissions( User $user ) {
+ $error = $this->canChangePassword( $user );
+ if ( is_string( $error ) ) {
+ throw new ErrorPageError( 'internalerror', $error );
+ } elseif ( !$error ) {
+ throw new ErrorPageError( 'internalerror', 'resetpass_forbidden' );
+ }
+
+ parent::checkExecutePermissions( $user );
+ }
+
+ protected function getFormFields() {
+ global $wgAuth;
+ $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
+ $a = [];
+ if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) {
+ $a['Username'] = [
+ 'type' => 'text',
+ 'label-message' => 'passwordreset-username',
+ ];
+
+ if ( $this->getUser()->isLoggedIn() ) {
+ $a['Username']['default'] = $this->getUser()->getName();
+ }
+ }
+
+ if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) {
+ $a['Email'] = [
+ 'type' => 'email',
+ 'label-message' => 'passwordreset-email',
+ ];
+ }
+
+ if ( isset( $resetRoutes['domain'] ) && $resetRoutes['domain'] ) {
+ $domains = $wgAuth->domainList();
+ $a['Domain'] = [
+ 'type' => 'select',
+ 'options' => $domains,
+ 'label-message' => 'passwordreset-domain',
+ ];
+ }
+
+ if ( $this->getUser()->isAllowed( 'passwordreset' ) ) {
+ $a['Capture'] = [
+ 'type' => 'check',
+ 'label-message' => 'passwordreset-capture',
+ 'help-message' => 'passwordreset-capture-help',
+ ];
+ }
+
+ return $a;
+ }
+
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
+ public function alterForm( HTMLForm $form ) {
+ $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
+
+ $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
+
+ $i = 0;
+ if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) {
+ $i++;
+ }
+ if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) {
+ $i++;
+ }
+ if ( isset( $resetRoutes['domain'] ) && $resetRoutes['domain'] ) {
+ $i++;
+ }
+
+ $message = ( $i > 1 ) ? 'passwordreset-text-many' : 'passwordreset-text-one';
+
+ $form->setHeaderText( $this->msg( $message, $i )->parseAsBlock() );
+ $form->setSubmitTextMsg( 'mailmypassword' );
+ }
+
+ /**
+ * Process the form. At this point we know that the user passes all the criteria in
+ * userCanExecute(), and if the data array contains 'Username', etc, then Username
+ * resets are allowed.
+ * @param array $data
+ * @throws MWException
+ * @throws ThrottledError|PermissionsError
+ * @return bool|array
+ */
+ public function onSubmit( array $data ) {
+ global $wgAuth, $wgMinimalPasswordLength;
+
+ if ( isset( $data['Domain'] ) ) {
+ if ( $wgAuth->validDomain( $data['Domain'] ) ) {
+ $wgAuth->setDomain( $data['Domain'] );
+ } else {
+ $wgAuth->setDomain( 'invaliddomain' );
+ }
+ }
+
+ if ( isset( $data['Capture'] ) && !$this->getUser()->isAllowed( 'passwordreset' ) ) {
+ // The user knows they don't have the passwordreset permission,
+ // but they tried to spoof the form. That's naughty
+ throw new PermissionsError( 'passwordreset' );
+ }
+
+ /**
+ * @var $firstUser User
+ * @var $users User[]
+ */
+
+ if ( isset( $data['Username'] ) && $data['Username'] !== '' ) {
+ $method = 'username';
+ $users = [ User::newFromName( $data['Username'] ) ];
+ } elseif ( isset( $data['Email'] )
+ && $data['Email'] !== ''
+ && Sanitizer::validateEmail( $data['Email'] )
+ ) {
+ $method = 'email';
+ $res = wfGetDB( DB_SLAVE )->select(
+ 'user',
+ User::selectFields(),
+ [ 'user_email' => $data['Email'] ],
+ __METHOD__
+ );
+
+ if ( $res ) {
+ $users = [];
+
+ foreach ( $res as $row ) {
+ $users[] = User::newFromRow( $row );
+ }
+ } else {
+ // Some sort of database error, probably unreachable
+ throw new MWException( 'Unknown database error in ' . __METHOD__ );
+ }
+ } else {
+ // The user didn't supply any data
+ return false;
+ }
+
+ // Check for hooks (captcha etc), and allow them to modify the users list
+ $error = [];
+ if ( !Hooks::run( 'SpecialPasswordResetOnSubmit', [ &$users, $data, &$error ] ) ) {
+ return [ $error ];
+ }
+
+ $this->method = $method;
+
+ if ( count( $users ) == 0 ) {
+ if ( $method == 'email' ) {
+ // Don't reveal whether or not an email address is in use
+ return true;
+ } else {
+ return [ 'noname' ];
+ }
+ }
+
+ $firstUser = $users[0];
+
+ if ( !$firstUser instanceof User || !$firstUser->getId() ) {
+ // Don't parse username as wikitext (bug 65501)
+ return [ [ 'nosuchuser', wfEscapeWikiText( $data['Username'] ) ] ];
+ }
+
+ // Check against the rate limiter
+ if ( $this->getUser()->pingLimiter( 'mailpassword' ) ) {
+ throw new ThrottledError;
+ }
+
+ // Check against password throttle
+ foreach ( $users as $user ) {
+ if ( $user->isPasswordReminderThrottled() ) {
+
+ # Round the time in hours to 3 d.p., in case someone is specifying
+ # minutes or seconds.
+ return [ [
+ 'throttled-mailpassword',
+ round( $this->getConfig()->get( 'PasswordReminderResendTime' ), 3 )
+ ] ];
+ }
+ }
+
+ // All the users will have the same email address
+ if ( $firstUser->getEmail() == '' ) {
+ // This won't be reachable from the email route, so safe to expose the username
+ return [ [ 'noemail', wfEscapeWikiText( $firstUser->getName() ) ] ];
+ }
+
+ // We need to have a valid IP address for the hook, but per bug 18347, we should
+ // send the user's name if they're logged in.
+ $ip = $this->getRequest()->getIP();
+ if ( !$ip ) {
+ return [ 'badipaddress' ];
+ }
+ $caller = $this->getUser();
+ Hooks::run( 'User::mailPasswordInternal', [ &$caller, &$ip, &$firstUser ] );
+ $username = $caller->getName();
+ $msg = IP::isValid( $username )
+ ? 'passwordreset-emailtext-ip'
+ : 'passwordreset-emailtext-user';
+
+ // Send in the user's language; which should hopefully be the same
+ $userLanguage = $firstUser->getOption( 'language' );
+
+ $passwords = [];
+ foreach ( $users as $user ) {
+ $password = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
+ $user->setNewpassword( $password );
+ $user->saveSettings();
+ $passwords[] = $this->msg( 'passwordreset-emailelement', $user->getName(), $password )
+ ->inLanguage( $userLanguage )->text(); // We'll escape the whole thing later
+ }
+ $passwordBlock = implode( "\n\n", $passwords );
+
+ $this->email = $this->msg( $msg )->inLanguage( $userLanguage );
+ $this->email->params(
+ $username,
+ $passwordBlock,
+ count( $passwords ),
+ '<' . Title::newMainPage()->getCanonicalURL() . '>',
+ round( $this->getConfig()->get( 'NewPasswordExpiry' ) / 86400 )
+ );
+
+ $title = $this->msg( 'passwordreset-emailtitle' )->inLanguage( $userLanguage );
+
+ $this->result = $firstUser->sendMail( $title->text(), $this->email->text() );
+
+ if ( isset( $data['Capture'] ) && $data['Capture'] ) {
+ // Save the user, will be used if an error occurs when sending the email
+ $this->firstUser = $firstUser;
+ } else {
+ // Blank the email if the user is not supposed to see it
+ $this->email = null;
+ }
+
+ if ( $this->result->isGood() ) {
+ return true;
+ } elseif ( isset( $data['Capture'] ) && $data['Capture'] ) {
+ // The email didn't send, but maybe they knew that and that's why they captured it
+ return true;
+ } else {
+ // @todo FIXME: The email wasn't sent, but we have already set
+ // the password throttle timestamp, so they won't be able to try
+ // again until it expires... :(
+ return [ [ 'mailerror', $this->result->getMessage() ] ];
+ }
+ }
+
+ public function onSuccess() {
+ if ( $this->getUser()->isAllowed( 'passwordreset' ) && $this->email != null ) {
+ // @todo Logging
+
+ if ( $this->result->isGood() ) {
+ $this->getOutput()->addWikiMsg( 'passwordreset-emailsent-capture' );
+ } else {
+ $this->getOutput()->addWikiMsg( 'passwordreset-emailerror-capture',
+ $this->result->getMessage(), $this->firstUser->getName() );
+ }
+
+ $this->getOutput()->addHTML( Html::rawElement( 'pre', [], $this->email->escaped() ) );
+ }
+
+ if ( $this->method === 'email' ) {
+ $this->getOutput()->addWikiMsg( 'passwordreset-emailsentemail' );
+ } else {
+ $this->getOutput()->addWikiMsg( 'passwordreset-emailsentusername' );
+ }
+
+ $this->getOutput()->returnToMain();
+ }
+
+ protected function canChangePassword( User $user ) {
+ global $wgAuth;
+ $resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
+
+ // Maybe password resets are disabled, or there are no allowable routes
+ if ( !is_array( $resetRoutes ) ||
+ !in_array( true, array_values( $resetRoutes ) )
+ ) {
+ return 'passwordreset-disabled';
+ }
+
+ // Maybe the external auth plugin won't allow local password changes
+ if ( !$wgAuth->allowPasswordChange() ) {
+ return 'resetpass_forbidden';
+ }
+
+ // Maybe email features have been disabled
+ if ( !$this->getConfig()->get( 'EnableEmail' ) ) {
+ return 'passwordreset-emaildisabled';
+ }
+
+ // Maybe the user is blocked (check this here rather than relying on the parent
+ // method as we have a more specific error message to use here
+ if ( $user->isBlocked() ) {
+ return 'blocked-mailpassword';
+ }
+
+ return true;
+ }
+
+ /**
+ * Hide the password reset page if resets are disabled.
+ * @return bool
+ */
+ function isListed() {
+ if ( $this->canChangePassword( $this->getUser() ) === true ) {
+ return parent::isListed();
+ }
+
+ return false;
+ }
+
+ protected function getGroupName() {
+ return 'users';
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements Special:UserLogin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+use MediaWiki\Logger\LoggerFactory;
+use Psr\Log\LogLevel;
+use MediaWiki\Session\SessionManager;
+
+/**
+ * Implements Special:UserLogin
+ *
+ * @ingroup SpecialPage
+ */
+class LoginFormPreAuthManager extends SpecialPage {
+ const SUCCESS = 0;
+ const NO_NAME = 1;
+ const ILLEGAL = 2;
+ const WRONG_PLUGIN_PASS = 3;
+ const NOT_EXISTS = 4;
+ const WRONG_PASS = 5;
+ const EMPTY_PASS = 6;
+ const RESET_PASS = 7;
+ const ABORTED = 8;
+ const CREATE_BLOCKED = 9;
+ const THROTTLED = 10;
+ const USER_BLOCKED = 11;
+ const NEED_TOKEN = 12;
+ const WRONG_TOKEN = 13;
+ const USER_MIGRATED = 14;
+
+ public static $statusCodes = [
+ self::SUCCESS => 'success',
+ self::NO_NAME => 'no_name',
+ self::ILLEGAL => 'illegal',
+ self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
+ self::NOT_EXISTS => 'not_exists',
+ self::WRONG_PASS => 'wrong_pass',
+ self::EMPTY_PASS => 'empty_pass',
+ self::RESET_PASS => 'reset_pass',
+ self::ABORTED => 'aborted',
+ self::CREATE_BLOCKED => 'create_blocked',
+ self::THROTTLED => 'throttled',
+ self::USER_BLOCKED => 'user_blocked',
+ self::NEED_TOKEN => 'need_token',
+ self::WRONG_TOKEN => 'wrong_token',
+ self::USER_MIGRATED => 'user_migrated',
+ ];
+
+ /**
+ * Valid error and warning messages
+ *
+ * Special:Userlogin can show an error or warning message on the form when
+ * coming from another page. This is done via the ?error= or ?warning= GET
+ * parameters.
+ *
+ * This array is the list of valid message keys. All other values will be
+ * ignored.
+ *
+ * @since 1.24
+ * @var string[]
+ */
+ public static $validErrorMessages = [
+ 'exception-nologin-text',
+ 'watchlistanontext',
+ 'changeemail-no-info',
+ 'resetpass-no-info',
+ 'confirmemail_needlogin',
+ 'prefsnologintext2',
+ ];
+
+ public $mAbortLoginErrorMsg = null;
+ /**
+ * @var int How many seconds user is throttled for
+ * @since 1.27
+ */
+ public $mThrottleWait = '?';
+
+ protected $mUsername;
+ protected $mPassword;
+ protected $mRetype;
+ protected $mReturnTo;
+ protected $mCookieCheck;
+ protected $mPosted;
+ protected $mAction;
+ protected $mCreateaccount;
+ protected $mCreateaccountMail;
+ protected $mLoginattempt;
+ protected $mRemember;
+ protected $mEmail;
+ protected $mDomain;
+ protected $mLanguage;
+ protected $mSkipCookieCheck;
+ protected $mReturnToQuery;
+ protected $mToken;
+ protected $mStickHTTPS;
+ protected $mType;
+ protected $mReason;
+ protected $mRealName;
+ protected $mEntryError = '';
+ protected $mEntryErrorType = 'error';
+
+ private $mTempPasswordUsed;
+ private $mLoaded = false;
+ private $mSecureLoginUrl;
+
+ /** @var WebRequest */
+ private $mOverrideRequest = null;
+
+ /** @var WebRequest Effective request; set at the beginning of load */
+ private $mRequest = null;
+
+ /**
+ * @param WebRequest $request
+ */
+ public function __construct( $request = null ) {
+ global $wgUseMediaWikiUIEverywhere;
+ parent::__construct( 'Userlogin' );
+
+ $this->mOverrideRequest = $request;
+ // Override UseMediaWikiEverywhere to true, to force login and create form to use mw ui
+ $wgUseMediaWikiUIEverywhere = true;
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ /**
+ * Returns an array of all valid error messages.
+ *
+ * @return array
+ */
+ public static function getValidErrorMessages() {
+ static $messages = null;
+ if ( !$messages ) {
+ $messages = self::$validErrorMessages;
+ Hooks::run( 'LoginFormValidErrorMessages', [ &$messages ] );
+ }
+
+ return $messages;
+ }
+
+ /**
+ * Loader
+ */
+ function load() {
+ global $wgAuth, $wgHiddenPrefs, $wgEnableEmail;
+
+ if ( $this->mLoaded ) {
+ return;
+ }
+ $this->mLoaded = true;
+
+ if ( $this->mOverrideRequest === null ) {
+ $request = $this->getRequest();
+ } else {
+ $request = $this->mOverrideRequest;
+ }
+ $this->mRequest = $request;
+
+ $this->mType = $request->getText( 'type' );
+ $this->mUsername = $request->getText( 'wpName' );
+ $this->mPassword = $request->getText( 'wpPassword' );
+ $this->mRetype = $request->getText( 'wpRetype' );
+ $this->mDomain = $request->getText( 'wpDomain' );
+ $this->mReason = $request->getText( 'wpReason' );
+ $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
+ $this->mPosted = $request->wasPosted();
+ $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
+ && $wgEnableEmail;
+ $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' ) && !$this->mCreateaccountMail;
+ $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
+ $this->mAction = $request->getVal( 'action' );
+ $this->mRemember = $request->getCheck( 'wpRemember' );
+ $this->mFromHTTP = $request->getBool( 'fromhttp', false )
+ || $request->getBool( 'wpFromhttp', false );
+ $this->mStickHTTPS = ( !$this->mFromHTTP && $request->getProtocol() === 'https' )
+ || $request->getBool( 'wpForceHttps', false );
+ $this->mLanguage = $request->getText( 'uselang' );
+ $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
+ $this->mToken = $this->mType == 'signup'
+ ? $request->getVal( 'wpCreateaccountToken' )
+ : $request->getVal( 'wpLoginToken' );
+ $this->mReturnTo = $request->getVal( 'returnto', '' );
+ $this->mReturnToQuery = $request->getVal( 'returntoquery', '' );
+
+ // Show an error or warning passed on from a previous page
+ $entryError = $this->msg( $request->getVal( 'error', '' ) );
+ $entryWarning = $this->msg( $request->getVal( 'warning', '' ) );
+ // bc: provide login link as a parameter for messages where the translation
+ // was not updated
+ $loginreqlink = Linker::linkKnown(
+ $this->getPageTitle(),
+ $this->msg( 'loginreqlink' )->escaped(),
+ [],
+ [
+ 'returnto' => $this->mReturnTo,
+ 'returntoquery' => $this->mReturnToQuery,
+ 'uselang' => $this->mLanguage,
+ 'fromhttp' => $this->mFromHTTP ? '1' : '0',
+ ]
+ );
+
+ // Only show valid error or warning messages.
+ if ( $entryError->exists()
+ && in_array( $entryError->getKey(), self::getValidErrorMessages() )
+ ) {
+ $this->mEntryErrorType = 'error';
+ $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
+
+ } elseif ( $entryWarning->exists()
+ && in_array( $entryWarning->getKey(), self::getValidErrorMessages() )
+ ) {
+ $this->mEntryErrorType = 'warning';
+ $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
+ }
+
+ if ( $wgEnableEmail ) {
+ $this->mEmail = $request->getText( 'wpEmail' );
+ } else {
+ $this->mEmail = '';
+ }
+ if ( !in_array( 'realname', $wgHiddenPrefs ) ) {
+ $this->mRealName = $request->getText( 'wpRealName' );
+ } else {
+ $this->mRealName = '';
+ }
+
+ if ( !$wgAuth->validDomain( $this->mDomain ) ) {
+ $this->mDomain = $wgAuth->getDomain();
+ }
+ $wgAuth->setDomain( $this->mDomain );
+
+ # 1. When switching accounts, it sucks to get automatically logged out
+ # 2. Do not return to PasswordReset after a successful password change
+ # but goto Wiki start page (Main_Page) instead ( bug 33997 )
+ $returnToTitle = Title::newFromText( $this->mReturnTo );
+ if ( is_object( $returnToTitle )
+ && ( $returnToTitle->isSpecial( 'Userlogout' )
+ || $returnToTitle->isSpecial( 'PasswordReset' ) )
+ ) {
+ $this->mReturnTo = '';
+ $this->mReturnToQuery = '';
+ }
+ }
+
+ function getDescription() {
+ if ( $this->mType === 'signup' ) {
+ return $this->msg( 'createaccount' )->text();
+ } else {
+ return $this->msg( 'login' )->text();
+ }
+ }
+
+ /**
+ * @param string|null $subPage
+ */
+ public function execute( $subPage ) {
+ // Make sure session is persisted
+ $session = SessionManager::getGlobalSession();
+ $session->persist();
+
+ $this->load();
+
+ // Check for [[Special:Userlogin/signup]]. This affects form display and
+ // page title.
+ if ( $subPage == 'signup' ) {
+ $this->mType = 'signup';
+ }
+ $this->setHeaders();
+
+ // Make sure it's possible to log in
+ if ( $this->mType !== 'signup' && !$session->canSetUser() ) {
+ throw new ErrorPageError(
+ 'cannotloginnow-title',
+ 'cannotloginnow-text',
+ [
+ $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
+ ]
+ );
+ }
+
+ /**
+ * In the case where the user is already logged in, and was redirected to
+ * the login form from a page that requires login, do not show the login
+ * page. The use case scenario for this is when a user opens a large number
+ * of tabs, is redirected to the login page on all of them, and then logs
+ * in on one, expecting all the others to work properly.
+ *
+ * However, do show the form if it was visited intentionally (no 'returnto'
+ * is present). People who often switch between several accounts have grown
+ * accustomed to this behavior.
+ */
+ if (
+ $this->mType !== 'signup' &&
+ !$this->mPosted &&
+ $this->getUser()->isLoggedIn() &&
+ ( $this->mReturnTo !== '' || $this->mReturnToQuery !== '' )
+ ) {
+ $this->successfulLogin();
+ }
+
+ // If logging in and not on HTTPS, either redirect to it or offer a link.
+ global $wgSecureLogin;
+ if ( $this->mRequest->getProtocol() !== 'https' ) {
+ $title = $this->getFullTitle();
+ $query = [
+ 'returnto' => $this->mReturnTo !== '' ? $this->mReturnTo : null,
+ 'returntoquery' => $this->mReturnToQuery !== '' ?
+ $this->mReturnToQuery : null,
+ 'title' => null,
+ ( $this->mEntryErrorType === 'error' ? 'error' : 'warning' ) => $this->mEntryError,
+ ] + $this->mRequest->getQueryValues();
+ $url = $title->getFullURL( $query, false, PROTO_HTTPS );
+ if ( $wgSecureLogin
+ && wfCanIPUseHTTPS( $this->getRequest()->getIP() )
+ && !$this->mFromHTTP ) // Avoid infinite redirect
+ {
+ $url = wfAppendQuery( $url, 'fromhttp=1' );
+ $this->getOutput()->redirect( $url );
+ // Since we only do this redir to change proto, always vary
+ $this->getOutput()->addVaryHeader( 'X-Forwarded-Proto' );
+
+ return;
+ } else {
+ // A wiki without HTTPS login support should set $wgServer to
+ // http://somehost, in which case the secure URL generated
+ // above won't actually start with https://
+ if ( substr( $url, 0, 8 ) === 'https://' ) {
+ $this->mSecureLoginUrl = $url;
+ }
+ }
+ }
+
+ if ( !is_null( $this->mCookieCheck ) ) {
+ $this->onCookieRedirectCheck( $this->mCookieCheck );
+
+ return;
+ } elseif ( $this->mPosted ) {
+ if ( $this->mCreateaccount ) {
+ $this->addNewAccount();
+
+ return;
+ } elseif ( $this->mCreateaccountMail ) {
+ $this->addNewAccountMailPassword();
+
+ return;
+ } elseif ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
+ $this->processLogin();
+
+ return;
+ }
+ }
+ $this->mainLoginForm( $this->mEntryError, $this->mEntryErrorType );
+ }
+
+ /**
+ * @private
+ */
+ function addNewAccountMailPassword() {
+ if ( $this->mEmail == '' ) {
+ $this->mainLoginForm( $this->msg( 'noemailcreate' )->escaped() );
+
+ return;
+ }
+
+ $status = $this->addNewAccountInternal();
+ LoggerFactory::getInstance( 'authmanager' )->info(
+ 'Account creation attempt with mailed password',
+ [ 'event' => 'accountcreation', 'status' => $status ]
+ );
+ if ( !$status->isGood() ) {
+ $error = $status->getMessage();
+ $this->mainLoginForm( $error->toString() );
+
+ return;
+ }
+
+ /** @var User $u */
+ $u = $status->getValue();
+
+ // Wipe the initial password and mail a temporary one
+ $u->setPassword( null );
+ $u->saveSettings();
+ $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
+
+ Hooks::run( 'AddNewAccount', [ $u, true ] );
+ $u->addNewUserLogEntry( 'byemail', $this->mReason );
+
+ $out = $this->getOutput();
+ $out->setPageTitle( $this->msg( 'accmailtitle' ) );
+
+ if ( !$result->isGood() ) {
+ $this->mainLoginForm( $this->msg( 'mailerror', $result->getWikiText() )->text() );
+ } else {
+ $out->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
+ $this->executeReturnTo( 'success' );
+ }
+ }
+
+ /**
+ * @private
+ * @return bool
+ */
+ function addNewAccount() {
+ global $wgContLang, $wgUser, $wgEmailAuthentication, $wgLoginLanguageSelector;
+
+ # Create the account and abort if there's a problem doing so
+ $status = $this->addNewAccountInternal();
+ LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt', [
+ 'event' => 'accountcreation',
+ 'status' => $status,
+ ] );
+
+ if ( !$status->isGood() ) {
+ $error = $status->getMessage();
+ $this->mainLoginForm( $error->toString() );
+
+ return false;
+ }
+
+ $u = $status->getValue();
+
+ # Only save preferences if the user is not creating an account for someone else.
+ if ( $this->getUser()->isAnon() ) {
+ # If we showed up language selection links, and one was in use, be
+ # smart (and sensible) and save that language as the user's preference
+ if ( $wgLoginLanguageSelector && $this->mLanguage ) {
+ $u->setOption( 'language', $this->mLanguage );
+ } else {
+
+ # Otherwise the user's language preference defaults to $wgContLang,
+ # but it may be better to set it to their preferred $wgContLang variant,
+ # based on browser preferences or URL parameters.
+ $u->setOption( 'language', $wgContLang->getPreferredVariant() );
+ }
+ if ( $wgContLang->hasVariants() ) {
+ $u->setOption( 'variant', $wgContLang->getPreferredVariant() );
+ }
+ }
+
+ $out = $this->getOutput();
+
+ # Send out an email authentication message if needed
+ if ( $wgEmailAuthentication && Sanitizer::validateEmail( $u->getEmail() ) ) {
+ $status = $u->sendConfirmationMail();
+ if ( $status->isGood() ) {
+ $out->addWikiMsg( 'confirmemail_oncreate' );
+ } else {
+ $out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) );
+ }
+ }
+
+ # Save settings (including confirmation token)
+ $u->saveSettings();
+
+ # If not logged in, assume the new account as the current one and set
+ # session cookies then show a "welcome" message or a "need cookies"
+ # message as needed
+ if ( $this->getUser()->isAnon() ) {
+ $u->setCookies();
+ $wgUser = $u;
+ // This should set it for OutputPage and the Skin
+ // which is needed or the personal links will be
+ // wrong.
+ $this->getContext()->setUser( $u );
+ Hooks::run( 'AddNewAccount', [ $u, false ] );
+ $u->addNewUserLogEntry( 'create' );
+ if ( $this->hasSessionCookie() ) {
+ $this->successfulCreation();
+ } else {
+ $this->cookieRedirectCheck( 'new' );
+ }
+ } else {
+ # Confirm that the account was created
+ $out->setPageTitle( $this->msg( 'accountcreated' ) );
+ $out->addWikiMsg( 'accountcreatedtext', $u->getName() );
+ $out->addReturnTo( $this->getPageTitle() );
+ Hooks::run( 'AddNewAccount', [ $u, false ] );
+ $u->addNewUserLogEntry( 'create2', $this->mReason );
+ }
+
+ return true;
+ }
+
+ /**
+ * Make a new user account using the loaded data.
+ * @private
+ * @throws PermissionsError|ReadOnlyError
+ * @return Status
+ */
+ public function addNewAccountInternal() {
+ global $wgAuth, $wgAccountCreationThrottle, $wgEmailConfirmToEdit;
+
+ // If the user passes an invalid domain, something is fishy
+ if ( !$wgAuth->validDomain( $this->mDomain ) ) {
+ return Status::newFatal( 'wrongpassword' );
+ }
+
+ // If we are not allowing users to login locally, we should be checking
+ // to see if the user is actually able to authenticate to the authenti-
+ // cation server before they create an account (otherwise, they can
+ // create a local account and login as any domain user). We only need
+ // to check this for domains that aren't local.
+ if ( 'local' != $this->mDomain && $this->mDomain != '' ) {
+ if (
+ !$wgAuth->canCreateAccounts() &&
+ (
+ !$wgAuth->userExists( $this->mUsername ) ||
+ !$wgAuth->authenticate( $this->mUsername, $this->mPassword )
+ )
+ ) {
+ return Status::newFatal( 'wrongpassword' );
+ }
+ }
+
+ if ( wfReadOnly() ) {
+ throw new ReadOnlyError;
+ }
+
+ # Request forgery checks.
+ $token = self::getCreateaccountToken();
+ if ( $token->wasNew() ) {
+ return Status::newFatal( 'nocookiesfornew' );
+ }
+
+ # The user didn't pass a createaccount token
+ if ( !$this->mToken ) {
+ return Status::newFatal( 'sessionfailure' );
+ }
+
+ # Validate the createaccount token
+ if ( !$token->match( $this->mToken ) ) {
+ return Status::newFatal( 'sessionfailure' );
+ }
+
+ # Check permissions
+ $currentUser = $this->getUser();
+ $creationBlock = $currentUser->isBlockedFromCreateAccount();
+ if ( !$currentUser->isAllowed( 'createaccount' ) ) {
+ throw new PermissionsError( 'createaccount' );
+ } elseif ( $creationBlock instanceof Block ) {
+ // Throws an ErrorPageError.
+ $this->userBlockedMessage( $creationBlock );
+
+ // This should never be reached.
+ return false;
+ }
+
+ # Include checks that will include GlobalBlocking (Bug 38333)
+ $permErrors = $this->getPageTitle()->getUserPermissionsErrors(
+ 'createaccount',
+ $currentUser,
+ true
+ );
+
+ if ( count( $permErrors ) ) {
+ throw new PermissionsError( 'createaccount', $permErrors );
+ }
+
+ $ip = $this->getRequest()->getIP();
+ if ( $currentUser->isDnsBlacklisted( $ip, true /* check $wgProxyWhitelist */ ) ) {
+ return Status::newFatal( 'sorbs_create_account_reason' );
+ }
+
+ # Now create a dummy user ($u) and check if it is valid
+ $u = User::newFromName( $this->mUsername, 'creatable' );
+ if ( !$u ) {
+ return Status::newFatal( 'noname' );
+ }
+
+ $cache = ObjectCache::getLocalClusterInstance();
+ # Make sure the user does not exist already
+ $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $this->mUsername ) ) );
+ if ( !$lock ) {
+ return Status::newFatal( 'usernameinprogress' );
+ } elseif ( $u->idForName( User::READ_LOCKING ) ) {
+ return Status::newFatal( 'userexists' );
+ }
+
+ if ( $this->mCreateaccountMail ) {
+ # do not force a password for account creation by email
+ # set invalid password, it will be replaced later by a random generated password
+ $this->mPassword = null;
+ } else {
+ if ( $this->mPassword !== $this->mRetype ) {
+ return Status::newFatal( 'badretype' );
+ }
+
+ # check for password validity, return a fatal Status if invalid
+ $validity = $u->checkPasswordValidity( $this->mPassword, 'create' );
+ if ( !$validity->isGood() ) {
+ $validity->ok = false; // make sure this Status is fatal
+ return $validity;
+ }
+ }
+
+ # if you need a confirmed email address to edit, then obviously you
+ # need an email address.
+ if ( $wgEmailConfirmToEdit && strval( $this->mEmail ) === '' ) {
+ return Status::newFatal( 'noemailtitle' );
+ }
+
+ if ( strval( $this->mEmail ) !== '' && !Sanitizer::validateEmail( $this->mEmail ) ) {
+ return Status::newFatal( 'invalidemailaddress' );
+ }
+
+ # Set some additional data so the AbortNewAccount hook can be used for
+ # more than just username validation
+ $u->setEmail( $this->mEmail );
+ $u->setRealName( $this->mRealName );
+
+ $abortError = '';
+ $abortStatus = null;
+ if ( !Hooks::run( 'AbortNewAccount', [ $u, &$abortError, &$abortStatus ] ) ) {
+ // Hook point to add extra creation throttles and blocks
+ wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
+ if ( $abortStatus === null ) {
+ // Report back the old string as a raw message status.
+ // This will report the error back as 'createaccount-hook-aborted'
+ // with the given string as the message.
+ // To return a different error code, return a Status object.
+ $abortError = new Message( 'createaccount-hook-aborted', [ $abortError ] );
+ $abortError->text();
+
+ return Status::newFatal( $abortError );
+ } else {
+ // For MediaWiki 1.23+ and updated hooks, return the Status object
+ // returned from the hook.
+ return $abortStatus;
+ }
+ }
+
+ // Hook point to check for exempt from account creation throttle
+ if ( !Hooks::run( 'ExemptFromAccountCreationThrottle', [ $ip ] ) ) {
+ wfDebug( "LoginForm::exemptFromAccountCreationThrottle: a hook " .
+ "allowed account creation w/o throttle\n" );
+ } else {
+ if ( ( $wgAccountCreationThrottle && $currentUser->isPingLimitable() ) ) {
+ $key = wfGlobalCacheKey( 'acctcreate', 'ip', $ip );
+ $value = $cache->get( $key );
+ if ( !$value ) {
+ $cache->set( $key, 0, $cache::TTL_DAY );
+ }
+ if ( $value >= $wgAccountCreationThrottle ) {
+ return Status::newFatal( 'acct_creation_throttle_hit', $wgAccountCreationThrottle );
+ }
+ $cache->incr( $key );
+ }
+ }
+
+ if ( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
+ return Status::newFatal( 'externaldberror' );
+ }
+
+ self::clearCreateaccountToken();
+
+ return $this->initUser( $u, false );
+ }
+
+ /**
+ * Actually add a user to the database.
+ * Give it a User object that has been initialised with a name.
+ *
+ * @param User $u
+ * @param bool $autocreate True if this is an autocreation via auth plugin
+ * @return Status Status object, with the User object in the value member on success
+ * @private
+ */
+ function initUser( $u, $autocreate ) {
+ global $wgAuth;
+
+ $status = $u->addToDatabase();
+ if ( !$status->isOK() ) {
+ return $status;
+ }
+
+ if ( $wgAuth->allowPasswordChange() ) {
+ $u->setPassword( $this->mPassword );
+ }
+
+ $u->setEmail( $this->mEmail );
+ $u->setRealName( $this->mRealName );
+ $u->setToken();
+
+ Hooks::run( 'LocalUserCreated', [ $u, $autocreate ] );
+ $oldUser = $u;
+ $wgAuth->initUser( $u, $autocreate );
+ if ( $oldUser !== $u ) {
+ wfWarn( get_class( $wgAuth ) . '::initUser() replaced the user object' );
+ }
+
+ $u->saveSettings();
+
+ // Update user count
+ DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
+
+ // Watch user's userpage and talk page
+ $u->addWatch( $u->getUserPage(), User::IGNORE_USER_RIGHTS );
+
+ return Status::newGood( $u );
+ }
+
+ /**
+ * Internally authenticate the login request.
+ *
+ * This may create a local account as a side effect if the
+ * authentication plugin allows transparent local account
+ * creation.
+ * @return int
+ */
+ public function authenticateUserData() {
+ global $wgUser, $wgAuth;
+
+ $this->load();
+
+ if ( $this->mUsername == '' ) {
+ return self::NO_NAME;
+ }
+
+ // We require a login token to prevent login CSRF
+ // Handle part of this before incrementing the throttle so
+ // token-less login attempts don't count towards the throttle
+ // but wrong-token attempts do.
+
+ // If the user doesn't have a login token yet, set one.
+ $token = self::getLoginToken();
+ if ( $token->wasNew() ) {
+ return self::NEED_TOKEN;
+ }
+ // If the user didn't pass a login token, tell them we need one
+ if ( !$this->mToken ) {
+ return self::NEED_TOKEN;
+ }
+
+ $throttleCount = self::incrementLoginThrottle( $this->mUsername );
+ if ( $throttleCount ) {
+ $this->mThrottleWait = $throttleCount['wait'];
+ return self::THROTTLED;
+ }
+
+ // Validate the login token
+ if ( !$token->match( $this->mToken ) ) {
+ return self::WRONG_TOKEN;
+ }
+
+ // Load the current user now, and check to see if we're logging in as
+ // the same name. This is necessary because loading the current user
+ // (say by calling getName()) calls the UserLoadFromSession hook, which
+ // potentially creates the user in the database. Until we load $wgUser,
+ // checking for user existence using User::newFromName($name)->getId() below
+ // will effectively be using stale data.
+ if ( $this->getUser()->getName() === $this->mUsername ) {
+ wfDebug( __METHOD__ . ": already logged in as {$this->mUsername}\n" );
+
+ return self::SUCCESS;
+ }
+
+ $u = User::newFromName( $this->mUsername );
+ if ( $u === false ) {
+ return self::ILLEGAL;
+ }
+
+ $msg = null;
+ // Give extensions a way to indicate the username has been updated,
+ // rather than telling the user the account doesn't exist.
+ if ( !Hooks::run( 'LoginUserMigrated', [ $u, &$msg ] ) ) {
+ $this->mAbortLoginErrorMsg = $msg;
+ return self::USER_MIGRATED;
+ }
+
+ if ( !User::isUsableName( $u->getName() ) ) {
+ return self::ILLEGAL;
+ }
+
+ $isAutoCreated = false;
+ if ( $u->getId() == 0 ) {
+ $status = $this->attemptAutoCreate( $u );
+ if ( $status !== self::SUCCESS ) {
+ return $status;
+ } else {
+ $isAutoCreated = true;
+ }
+ } else {
+ $u->load();
+ }
+
+ // Give general extensions, such as a captcha, a chance to abort logins
+ $abort = self::ABORTED;
+ if ( !Hooks::run( 'AbortLogin', [ $u, $this->mPassword, &$abort, &$msg ] ) ) {
+ if ( !in_array( $abort, array_keys( self::$statusCodes ), true ) ) {
+ throw new Exception( 'Invalid status code returned from AbortLogin hook: ' . $abort );
+ }
+ $this->mAbortLoginErrorMsg = $msg;
+ return $abort;
+ }
+
+ global $wgBlockDisablesLogin;
+ if ( !$u->checkPassword( $this->mPassword ) ) {
+ if ( $u->checkTemporaryPassword( $this->mPassword ) ) {
+ /**
+ * The e-mailed temporary password should not be used for actu-
+ * al logins; that's a very sloppy habit, and insecure if an
+ * attacker has a few seconds to click "search" on someone's
+ * open mail reader.
+ *
+ * Allow it to be used only to reset the password a single time
+ * to a new value, which won't be in the user's e-mail ar-
+ * chives.
+ *
+ * For backwards compatibility, we'll still recognize it at the
+ * login form to minimize surprises for people who have been
+ * logging in with a temporary password for some time.
+ *
+ * As a side-effect, we can authenticate the user's e-mail ad-
+ * dress if it's not already done, since the temporary password
+ * was sent via e-mail.
+ */
+ if ( !$u->isEmailConfirmed() && !wfReadOnly() ) {
+ $u->confirmEmail();
+ $u->saveSettings();
+ }
+
+ // At this point we just return an appropriate code/ indicating
+ // that the UI should show a password reset form; bot inter-
+ // faces etc will probably just fail cleanly here.
+ $this->mAbortLoginErrorMsg = 'resetpass-temp-emailed';
+ $this->mTempPasswordUsed = true;
+ $retval = self::RESET_PASS;
+ } else {
+ $retval = ( $this->mPassword == '' ) ? self::EMPTY_PASS : self::WRONG_PASS;
+ }
+ } elseif ( $wgBlockDisablesLogin && $u->isBlocked() ) {
+ // If we've enabled it, make it so that a blocked user cannot login
+ $retval = self::USER_BLOCKED;
+ } elseif ( $this->checkUserPasswordExpired( $u ) == 'hard' ) {
+ // Force reset now, without logging in
+ $retval = self::RESET_PASS;
+ $this->mAbortLoginErrorMsg = 'resetpass-expired';
+ } else {
+ Hooks::run( 'UserLoggedIn', [ $u ] );
+ $oldUser = $u;
+ $wgAuth->updateUser( $u );
+ if ( $oldUser !== $u ) {
+ wfWarn( get_class( $wgAuth ) . '::updateUser() replaced the user object' );
+ }
+ $wgUser = $u;
+ // This should set it for OutputPage and the Skin
+ // which is needed or the personal links will be
+ // wrong.
+ $this->getContext()->setUser( $u );
+
+ // Please reset throttle for successful logins, thanks!
+ self::clearLoginThrottle( $this->mUsername );
+
+ if ( $isAutoCreated ) {
+ // Must be run after $wgUser is set, for correct new user log
+ Hooks::run( 'AuthPluginAutoCreate', [ $u ] );
+ }
+
+ $retval = self::SUCCESS;
+ }
+ Hooks::run( 'LoginAuthenticateAudit', [ $u, $this->mPassword, $retval ] );
+
+ return $retval;
+ }
+
+ /**
+ * Increment the login attempt throttle hit count for the (username,current IP)
+ * tuple unless the throttle was already reached.
+ *
+ * @since 1.27 Return value changed.
+ * @param string $username The user name
+ * @return bool|array false if below limit or an array if above limit
+ * Array contains keys wait, count, and throttleIndex
+ */
+ public static function incrementLoginThrottle( $username ) {
+ global $wgPasswordAttemptThrottle, $wgRequest;
+ $canUsername = User::getCanonicalName( $username, 'usable' );
+ $username = $canUsername !== false ? $canUsername : $username;
+
+ $throttleCount = 0;
+ if ( is_array( $wgPasswordAttemptThrottle ) ) {
+ $throttleConfig = $wgPasswordAttemptThrottle;
+ if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
+ // old style. Convert for backwards compat.
+ $throttleConfig = [ $wgPasswordAttemptThrottle ];
+ }
+ foreach ( $throttleConfig as $index => $specificThrottle ) {
+ if ( isset( $specificThrottle['allIPs'] ) ) {
+ $ip = 'All';
+ } else {
+ $ip = $wgRequest->getIP();
+ }
+ $throttleKey = wfGlobalCacheKey( 'password-throttle',
+ $index, $ip, md5( $username )
+ );
+ $count = $specificThrottle['count'];
+ $period = $specificThrottle['seconds'];
+
+ $cache = ObjectCache::getLocalClusterInstance();
+ $throttleCount = $cache->get( $throttleKey );
+ if ( !$throttleCount ) {
+ $cache->add( $throttleKey, 1, $period ); // start counter
+ } elseif ( $throttleCount < $count ) {
+ $cache->incr( $throttleKey );
+ } elseif ( $throttleCount >= $count ) {
+ $logMsg = 'Login attempt rejected because logins to '
+ . '{acct} from IP {ip} have been throttled for '
+ . '{period} seconds due to {count} failed attempts';
+ // If we are hitting a throttle for >= 50 attempts,
+ // it is much more likely to be an attack than someone
+ // simply forgetting their password, so log it at a
+ // higher level.
+ $level = $count >= 50 ? LogLevel::WARNING : LogLevel::INFO;
+ // It should be noted that once the throttle is hit,
+ // every attempt to login will generate the log message
+ // until the throttle expires, not just the attempt that
+ // puts the throttle over the top.
+ LoggerFactory::getInstance( 'password-throttle' )->log(
+ $level,
+ $logMsg,
+ [
+ 'ip' => $ip,
+ 'period' => $period,
+ 'acct' => $username,
+ 'count' => $count,
+ 'throttleIdentifier' => $index,
+ 'method' => __METHOD__
+ ]
+ );
+
+ return [
+ 'throttleIndex' => $index,
+ 'wait' => $period,
+ 'count' => $count
+ ];
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Increment the login attempt throttle hit count for the (username,current IP)
+ * tuple unless the throttle was already reached.
+ *
+ * @deprecated Use LoginForm::incrementLoginThrottle instead
+ * @param string $username The user name
+ * @return bool|int true if above throttle, or 0 (prior to 1.27, returned current count)
+ */
+ public static function incLoginThrottle( $username ) {
+ wfDeprecated( __METHOD__, "1.27" );
+ $res = self::incrementLoginThrottle( $username );
+ return is_array( $res ) ? true : 0;
+ }
+
+ /**
+ * Clear the login attempt throttle hit count for the (username,current IP) tuple.
+ * @param string $username The user name
+ * @return void
+ */
+ public static function clearLoginThrottle( $username ) {
+ global $wgRequest, $wgPasswordAttemptThrottle;
+ $canUsername = User::getCanonicalName( $username, 'usable' );
+ $username = $canUsername !== false ? $canUsername : $username;
+
+ if ( is_array( $wgPasswordAttemptThrottle ) ) {
+ $throttleConfig = $wgPasswordAttemptThrottle;
+ if ( isset( $wgPasswordAttemptThrottle['count'] ) ) {
+ // old style. Convert for backwards compat.
+ $throttleConfig = [ $wgPasswordAttemptThrottle ];
+ }
+ foreach ( $throttleConfig as $index => $specificThrottle ) {
+ if ( isset( $specificThrottle['allIPs'] ) ) {
+ $ip = 'All';
+ } else {
+ $ip = $wgRequest->getIP();
+ }
+ $throttleKey = wfGlobalCacheKey( 'password-throttle', $index,
+ $ip, md5( $username )
+ );
+ ObjectCache::getLocalClusterInstance()->delete( $throttleKey );
+ }
+ }
+ }
+
+ /**
+ * Attempt to automatically create a user on login. Only succeeds if there
+ * is an external authentication method which allows it.
+ *
+ * @param User $user
+ *
+ * @return int Status code
+ */
+ function attemptAutoCreate( $user ) {
+ global $wgAuth;
+
+ if ( $this->getUser()->isBlockedFromCreateAccount() ) {
+ wfDebug( __METHOD__ . ": user is blocked from account creation\n" );
+
+ return self::CREATE_BLOCKED;
+ }
+
+ if ( !$wgAuth->autoCreate() ) {
+ return self::NOT_EXISTS;
+ }
+
+ if ( !$wgAuth->userExists( $user->getName() ) ) {
+ wfDebug( __METHOD__ . ": user does not exist\n" );
+
+ return self::NOT_EXISTS;
+ }
+
+ if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
+ wfDebug( __METHOD__ . ": \$wgAuth->authenticate() returned false, aborting\n" );
+
+ return self::WRONG_PLUGIN_PASS;
+ }
+
+ $abortError = '';
+ if ( !Hooks::run( 'AbortAutoAccount', [ $user, &$abortError ] ) ) {
+ // Hook point to add extra creation throttles and blocks
+ wfDebug( "LoginForm::attemptAutoCreate: a hook blocked creation: $abortError\n" );
+ $this->mAbortLoginErrorMsg = $abortError;
+
+ return self::ABORTED;
+ }
+
+ wfDebug( __METHOD__ . ": creating account\n" );
+ $status = $this->initUser( $user, true );
+
+ if ( !$status->isOK() ) {
+ $errors = $status->getErrorsByType( 'error' );
+ $this->mAbortLoginErrorMsg = $errors[0]['message'];
+
+ return self::ABORTED;
+ }
+
+ return self::SUCCESS;
+ }
+
+ function processLogin() {
+ global $wgLang, $wgSecureLogin, $wgInvalidPasswordReset;
+
+ $authRes = $this->authenticateUserData();
+ switch ( $authRes ) {
+ case self::SUCCESS:
+ # We've verified now, update the real record
+ $user = $this->getUser();
+ $user->touch();
+
+ if ( $user->requiresHTTPS() ) {
+ $this->mStickHTTPS = true;
+ }
+
+ if ( $wgSecureLogin && !$this->mStickHTTPS ) {
+ $user->setCookies( $this->mRequest, false, $this->mRemember );
+ } else {
+ $user->setCookies( $this->mRequest, null, $this->mRemember );
+ }
+ self::clearLoginToken();
+
+ // Reset the throttle
+ self::clearLoginThrottle( $this->mUsername );
+
+ $request = $this->getRequest();
+ if ( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
+ /* Replace the language object to provide user interface in
+ * correct language immediately on this first page load.
+ */
+ $code = $request->getVal( 'uselang', $user->getOption( 'language' ) );
+ $userLang = Language::factory( $code );
+ $wgLang = $userLang;
+ RequestContext::getMain()->setLanguage( $userLang );
+ $this->getContext()->setLanguage( $userLang );
+ // Reset SessionID on Successful login (bug 40995)
+ $this->renewSessionId();
+ if ( $this->checkUserPasswordExpired( $this->getUser() ) == 'soft' ) {
+ $this->resetLoginForm( $this->msg( 'resetpass-expired-soft' ) );
+ } elseif ( $wgInvalidPasswordReset
+ && !$user->isValidPassword( $this->mPassword )
+ ) {
+ $status = $user->checkPasswordValidity(
+ $this->mPassword,
+ 'login'
+ );
+ $this->resetLoginForm(
+ $status->getMessage( 'resetpass-validity-soft' )
+ );
+ } else {
+ $this->successfulLogin();
+ }
+ } else {
+ $this->cookieRedirectCheck( 'login' );
+ }
+ break;
+
+ case self::NEED_TOKEN:
+ $error = $this->mAbortLoginErrorMsg ?: 'nocookiesforlogin';
+ $this->mainLoginForm( $this->msg( $error )->parse() );
+ break;
+ case self::WRONG_TOKEN:
+ $error = $this->mAbortLoginErrorMsg ?: 'sessionfailure';
+ $this->mainLoginForm( $this->msg( $error )->text() );
+ break;
+ case self::NO_NAME:
+ case self::ILLEGAL:
+ $error = $this->mAbortLoginErrorMsg ?: 'noname';
+ $this->mainLoginForm( $this->msg( $error )->text() );
+ break;
+ case self::WRONG_PLUGIN_PASS:
+ $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
+ $this->mainLoginForm( $this->msg( $error )->text() );
+ break;
+ case self::NOT_EXISTS:
+ if ( $this->getUser()->isAllowed( 'createaccount' ) ) {
+ $error = $this->mAbortLoginErrorMsg ?: 'nosuchuser';
+ $this->mainLoginForm( $this->msg( $error,
+ wfEscapeWikiText( $this->mUsername ) )->parse() );
+ } else {
+ $error = $this->mAbortLoginErrorMsg ?: 'nosuchusershort';
+ $this->mainLoginForm( $this->msg( $error,
+ wfEscapeWikiText( $this->mUsername ) )->text() );
+ }
+ break;
+ case self::WRONG_PASS:
+ $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword';
+ $this->mainLoginForm( $this->msg( $error )->text() );
+ break;
+ case self::EMPTY_PASS:
+ $error = $this->mAbortLoginErrorMsg ?: 'wrongpasswordempty';
+ $this->mainLoginForm( $this->msg( $error )->text() );
+ break;
+ case self::RESET_PASS:
+ $error = $this->mAbortLoginErrorMsg ?: 'resetpass_announce';
+ $this->resetLoginForm( $this->msg( $error ) );
+ break;
+ case self::CREATE_BLOCKED:
+ $this->userBlockedMessage( $this->getUser()->isBlockedFromCreateAccount() );
+ break;
+ case self::THROTTLED:
+ $error = $this->mAbortLoginErrorMsg ?: 'login-throttled';
+ $this->mainLoginForm( $this->msg( $error )
+ ->durationParams( $this->mThrottleWait )->text()
+ );
+ break;
+ case self::USER_BLOCKED:
+ $error = $this->mAbortLoginErrorMsg ?: 'login-userblocked';
+ $this->mainLoginForm( $this->msg( $error, $this->mUsername )->escaped() );
+ break;
+ case self::ABORTED:
+ $error = $this->mAbortLoginErrorMsg ?: 'login-abort-generic';
+ $this->mainLoginForm( $this->msg( $error,
+ wfEscapeWikiText( $this->mUsername ) )->text() );
+ break;
+ case self::USER_MIGRATED:
+ $error = $this->mAbortLoginErrorMsg ?: 'login-migrated-generic';
+ $params = [];
+ if ( is_array( $error ) ) {
+ $error = array_shift( $this->mAbortLoginErrorMsg );
+ $params = $this->mAbortLoginErrorMsg;
+ }
+ $this->mainLoginForm( $this->msg( $error, $params )->text() );
+ break;
+ default:
+ throw new MWException( 'Unhandled case value' );
+ }
+
+ LoggerFactory::getInstance( 'authmanager' )->info( 'Login attempt', [
+ 'event' => 'login',
+ 'successful' => $authRes === self::SUCCESS,
+ 'status' => LoginForm::$statusCodes[$authRes],
+ ] );
+ }
+
+ /**
+ * Show the Special:ChangePassword form, with custom message
+ * @param Message $msg
+ */
+ protected function resetLoginForm( Message $msg ) {
+ // Allow hooks to explain this password reset in more detail
+ Hooks::run( 'LoginPasswordResetMessage', [ &$msg, $this->mUsername ] );
+ $reset = new SpecialChangePasswordPreAuthManager();
+ $derivative = new DerivativeContext( $this->getContext() );
+ $derivative->setTitle( $reset->getPageTitle() );
+ $reset->setContext( $derivative );
+ if ( !$this->mTempPasswordUsed ) {
+ $reset->setOldPasswordMessage( 'oldpassword' );
+ }
+ $reset->setChangeMessage( $msg );
+ $reset->execute( null );
+ }
+
+ /**
+ * @param User $u
+ * @param bool $throttle
+ * @param string $emailTitle Message name of email title
+ * @param string $emailText Message name of email text
+ * @return Status
+ */
+ function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle',
+ $emailText = 'passwordremindertext'
+ ) {
+ global $wgNewPasswordExpiry, $wgMinimalPasswordLength;
+
+ if ( $u->getEmail() == '' ) {
+ return Status::newFatal( 'noemail', $u->getName() );
+ }
+ $ip = $this->getRequest()->getIP();
+ if ( !$ip ) {
+ return Status::newFatal( 'badipaddress' );
+ }
+
+ $currentUser = $this->getUser();
+ Hooks::run( 'User::mailPasswordInternal', [ &$currentUser, &$ip, &$u ] );
+
+ $np = PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
+ $u->setNewpassword( $np, $throttle );
+ $u->saveSettings();
+ $userLanguage = $u->getOption( 'language' );
+
+ $mainPage = Title::newMainPage();
+ $mainPageUrl = $mainPage->getCanonicalURL();
+
+ $m = $this->msg( $emailText, $ip, $u->getName(), $np, '<' . $mainPageUrl . '>',
+ round( $wgNewPasswordExpiry / 86400 ) )->inLanguage( $userLanguage )->text();
+ $result = $u->sendMail( $this->msg( $emailTitle )->inLanguage( $userLanguage )->text(), $m );
+
+ return $result;
+ }
+
+ /**
+ * Run any hooks registered for logins, then HTTP redirect to
+ * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a
+ * nice message here, but that's really not as useful as just being sent to
+ * wherever you logged in from. It should be clear that the action was
+ * successful, given the lack of error messages plus the appearance of your
+ * name in the upper right.
+ *
+ * @private
+ */
+ function successfulLogin() {
+ # Run any hooks; display injected HTML if any, else redirect
+ $currentUser = $this->getUser();
+ $injected_html = '';
+ Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html ] );
+
+ if ( $injected_html !== '' ) {
+ $this->displaySuccessfulAction( 'success', $this->msg( 'loginsuccesstitle' ),
+ 'loginsuccess', $injected_html );
+ } else {
+ $this->executeReturnTo( 'successredirect' );
+ }
+ }
+
+ /**
+ * Run any hooks registered for logins, then display a message welcoming
+ * the user.
+ *
+ * @private
+ */
+ function successfulCreation() {
+ # Run any hooks; display injected HTML
+ $currentUser = $this->getUser();
+ $injected_html = '';
+ $welcome_creation_msg = 'welcomecreation-msg';
+
+ Hooks::run( 'UserLoginComplete', [ &$currentUser, &$injected_html ] );
+
+ /**
+ * Let any extensions change what message is shown.
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforeWelcomeCreation
+ * @since 1.18
+ */
+ Hooks::run( 'BeforeWelcomeCreation', [ &$welcome_creation_msg, &$injected_html ] );
+
+ $this->displaySuccessfulAction(
+ 'signup',
+ $this->msg( 'welcomeuser', $this->getUser()->getName() ),
+ $welcome_creation_msg, $injected_html
+ );
+ }
+
+ /**
+ * Display a "successful action" page.
+ *
+ * @param string $type Condition of return to; see `executeReturnTo`
+ * @param string|Message $title Page's title
+ * @param string $msgname
+ * @param string $injected_html
+ */
+ private function displaySuccessfulAction( $type, $title, $msgname, $injected_html ) {
+ $out = $this->getOutput();
+ $out->setPageTitle( $title );
+ if ( $msgname ) {
+ $out->addWikiMsg( $msgname, wfEscapeWikiText( $this->getUser()->getName() ) );
+ }
+
+ $out->addHTML( $injected_html );
+
+ $this->executeReturnTo( $type );
+ }
+
+ /**
+ * Output a message that informs the user that they cannot create an account because
+ * there is a block on them or their IP which prevents account creation. Note that
+ * User::isBlockedFromCreateAccount(), which gets this block, ignores the 'hardblock'
+ * setting on blocks (bug 13611).
+ * @param Block $block The block causing this error
+ * @throws ErrorPageError
+ */
+ function userBlockedMessage( Block $block ) {
+ # Let's be nice about this, it's likely that this feature will be used
+ # for blocking large numbers of innocent people, e.g. range blocks on
+ # schools. Don't blame it on the user. There's a small chance that it
+ # really is the user's fault, i.e. the username is blocked and they
+ # haven't bothered to log out before trying to create an account to
+ # evade it, but we'll leave that to their guilty conscience to figure
+ # out.
+ $errorParams = [
+ $block->getTarget(),
+ $block->mReason ? $block->mReason : $this->msg( 'blockednoreason' )->text(),
+ $block->getByName()
+ ];
+
+ if ( $block->getType() === Block::TYPE_RANGE ) {
+ $errorMessage = 'cantcreateaccount-range-text';
+ $errorParams[] = $this->getRequest()->getIP();
+ } else {
+ $errorMessage = 'cantcreateaccount-text';
+ }
+
+ throw new ErrorPageError(
+ 'cantcreateaccounttitle',
+ $errorMessage,
+ $errorParams
+ );
+ }
+
+ /**
+ * Add a "return to" link or redirect to it.
+ * Extensions can use this to reuse the "return to" logic after
+ * inject steps (such as redirection) into the login process.
+ *
+ * @param string $type One of the following:
+ * - error: display a return to link ignoring $wgRedirectOnLogin
+ * - signup: display a return to link using $wgRedirectOnLogin if needed
+ * - success: display a return to link using $wgRedirectOnLogin if needed
+ * - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
+ * @param string $returnTo
+ * @param array|string $returnToQuery
+ * @param bool $stickHTTPs Keep redirect link on HTTPs
+ * @since 1.22
+ */
+ public function showReturnToPage(
+ $type, $returnTo = '', $returnToQuery = '', $stickHTTPs = false
+ ) {
+ $this->mReturnTo = $returnTo;
+ $this->mReturnToQuery = $returnToQuery;
+ $this->mStickHTTPS = $stickHTTPs;
+ $this->executeReturnTo( $type );
+ }
+
+ /**
+ * Add a "return to" link or redirect to it.
+ *
+ * @param string $type One of the following:
+ * - error: display a return to link ignoring $wgRedirectOnLogin
+ * - signup: display a return to link using $wgRedirectOnLogin if needed
+ * - success: display a return to link using $wgRedirectOnLogin if needed
+ * - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed
+ */
+ private function executeReturnTo( $type ) {
+ global $wgRedirectOnLogin, $wgSecureLogin;
+
+ if ( $type != 'error' && $wgRedirectOnLogin !== null ) {
+ $returnTo = $wgRedirectOnLogin;
+ $returnToQuery = [];
+ } else {
+ $returnTo = $this->mReturnTo;
+ $returnToQuery = wfCgiToArray( $this->mReturnToQuery );
+ }
+
+ // Allow modification of redirect behavior
+ Hooks::run( 'PostLoginRedirect', [ &$returnTo, &$returnToQuery, &$type ] );
+
+ $returnToTitle = Title::newFromText( $returnTo );
+ if ( !$returnToTitle ) {
+ $returnToTitle = Title::newMainPage();
+ }
+
+ if ( $wgSecureLogin && !$this->mStickHTTPS ) {
+ $options = [ 'http' ];
+ $proto = PROTO_HTTP;
+ } elseif ( $wgSecureLogin ) {
+ $options = [ 'https' ];
+ $proto = PROTO_HTTPS;
+ } else {
+ $options = [];
+ $proto = PROTO_RELATIVE;
+ }
+
+ if ( $type == 'successredirect' ) {
+ $redirectUrl = $returnToTitle->getFullURL( $returnToQuery, false, $proto );
+ $this->getOutput()->redirect( $redirectUrl );
+ } else {
+ $this->getOutput()->addReturnTo( $returnToTitle, $returnToQuery, null, $options );
+ }
+ }
+
+ /**
+ * @param string $msg
+ * @param string $msgtype
+ * @throws ErrorPageError
+ * @throws Exception
+ * @throws FatalError
+ * @throws MWException
+ * @throws PermissionsError
+ * @throws ReadOnlyError
+ * @private
+ */
+ function mainLoginForm( $msg, $msgtype = 'error' ) {
+ global $wgEnableEmail, $wgEnableUserEmail;
+ global $wgHiddenPrefs, $wgLoginLanguageSelector;
+ global $wgAuth, $wgEmailConfirmToEdit;
+ global $wgSecureLogin, $wgPasswordResetRoutes;
+ global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
+
+ $titleObj = $this->getPageTitle();
+ $user = $this->getUser();
+ $out = $this->getOutput();
+
+ if ( $this->mType == 'signup' ) {
+ // Block signup here if in readonly. Keeps user from
+ // going through the process (filling out data, etc)
+ // and being informed later.
+ $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $user, true );
+ if ( count( $permErrors ) ) {
+ throw new PermissionsError( 'createaccount', $permErrors );
+ } elseif ( $user->isBlockedFromCreateAccount() ) {
+ $this->userBlockedMessage( $user->isBlockedFromCreateAccount() );
+
+ return;
+ } elseif ( wfReadOnly() ) {
+ throw new ReadOnlyError;
+ }
+ }
+
+ // Pre-fill username (if not creating an account, bug 44775).
+ if ( $this->mUsername == '' && $this->mType != 'signup' ) {
+ if ( $user->isLoggedIn() ) {
+ $this->mUsername = $user->getName();
+ } else {
+ $this->mUsername = $this->getRequest()->getSession()->suggestLoginUsername();
+ }
+ }
+
+ // Generic styles and scripts for both login and signup form
+ $out->addModuleStyles( [
+ 'mediawiki.ui',
+ 'mediawiki.ui.button',
+ 'mediawiki.ui.checkbox',
+ 'mediawiki.ui.input',
+ 'mediawiki.special.userlogin.common.styles'
+ ] );
+
+ if ( $this->mType == 'signup' ) {
+ // Additional styles and scripts for signup form
+ $out->addModules( [
+ 'mediawiki.special.userlogin.signup.js'
+ ] );
+ $out->addModuleStyles( [
+ 'mediawiki.special.userlogin.signup.styles'
+ ] );
+
+ $template = new UsercreateTemplate( $this->getConfig() );
+
+ // Must match number of benefits defined in messages
+ $template->set( 'benefitCount', 3 );
+
+ $q = 'action=submitlogin&type=signup';
+ $linkq = 'type=login';
+ } else {
+ // Additional styles for login form
+ $out->addModuleStyles( [
+ 'mediawiki.special.userlogin.login.styles'
+ ] );
+
+ $template = new UserloginTemplate( $this->getConfig() );
+
+ $q = 'action=submitlogin&type=login';
+ $linkq = 'type=signup';
+ }
+
+ if ( $this->mReturnTo !== '' ) {
+ $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
+ if ( $this->mReturnToQuery !== '' ) {
+ $returnto .= '&returntoquery=' .
+ wfUrlencode( $this->mReturnToQuery );
+ }
+ $q .= $returnto;
+ $linkq .= $returnto;
+ }
+
+ # Don't show a "create account" link if the user can't.
+ if ( $this->showCreateOrLoginLink( $user ) ) {
+ # Pass any language selection on to the mode switch link
+ if ( $wgLoginLanguageSelector && $this->mLanguage ) {
+ $linkq .= '&uselang=' . $this->mLanguage;
+ }
+ // Supply URL, login template creates the button.
+ $template->set( 'createOrLoginHref', $titleObj->getLocalURL( $linkq ) );
+ } else {
+ $template->set( 'link', '' );
+ }
+
+ $resetLink = $this->mType == 'signup'
+ ? null
+ : is_array( $wgPasswordResetRoutes ) && in_array( true, array_values( $wgPasswordResetRoutes ) );
+
+ $template->set( 'header', '' );
+ $template->set( 'formheader', '' );
+ $template->set( 'skin', $this->getSkin() );
+ $template->set( 'name', $this->mUsername );
+ $template->set( 'password', $this->mPassword );
+ $template->set( 'retype', $this->mRetype );
+ $template->set( 'createemailset', $this->mCreateaccountMail );
+ $template->set( 'email', $this->mEmail );
+ $template->set( 'realname', $this->mRealName );
+ $template->set( 'domain', $this->mDomain );
+ $template->set( 'reason', $this->mReason );
+
+ $template->set( 'action', $titleObj->getLocalURL( $q ) );
+ $template->set( 'message', $msg );
+ $template->set( 'messagetype', $msgtype );
+ $template->set( 'createemail', $wgEnableEmail && $user->isLoggedIn() );
+ $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) );
+ $template->set( 'useemail', $wgEnableEmail );
+ $template->set( 'emailrequired', $wgEmailConfirmToEdit );
+ $template->set( 'emailothers', $wgEnableUserEmail );
+ $template->set( 'canreset', $wgAuth->allowPasswordChange() );
+ $template->set( 'resetlink', $resetLink );
+ $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ?
+ ( $wgCookieExpiration > 0 ) :
+ ( $wgExtendedLoginCookieExpiration > 0 ) );
+ $template->set( 'usereason', $user->isLoggedIn() );
+ $template->set( 'remember', $this->mRemember );
+ $template->set( 'cansecurelogin', ( $wgSecureLogin === true ) );
+ $template->set( 'stickhttps', (int)$this->mStickHTTPS );
+ $template->set( 'loggedin', $user->isLoggedIn() );
+ $template->set( 'loggedinuser', $user->getName() );
+
+ if ( $this->mType == 'signup' ) {
+ $template->set( 'token', self::getCreateaccountToken()->toString() );
+ } else {
+ $template->set( 'token', self::getLoginToken()->toString() );
+ }
+
+ # Prepare language selection links as needed
+ if ( $wgLoginLanguageSelector ) {
+ $template->set( 'languages', $this->makeLanguageSelector() );
+ if ( $this->mLanguage ) {
+ $template->set( 'uselang', $this->mLanguage );
+ }
+ }
+
+ $template->set( 'secureLoginUrl', $this->mSecureLoginUrl );
+ // Use signupend-https for HTTPS requests if it's not blank, signupend otherwise
+ $usingHTTPS = $this->mRequest->getProtocol() == 'https';
+ $signupendHTTPS = $this->msg( 'signupend-https' );
+ if ( $usingHTTPS && !$signupendHTTPS->isBlank() ) {
+ $template->set( 'signupend', $signupendHTTPS->parse() );
+ } else {
+ $template->set( 'signupend', $this->msg( 'signupend' )->parse() );
+ }
+
+ // If using HTTPS coming from HTTP, then the 'fromhttp' parameter must be preserved
+ if ( $usingHTTPS ) {
+ $template->set( 'fromhttp', $this->mFromHTTP );
+ }
+
+ // Give authentication and captcha plugins a chance to modify the form
+ $wgAuth->modifyUITemplate( $template, $this->mType );
+ if ( $this->mType == 'signup' ) {
+ Hooks::run( 'UserCreateForm', [ &$template ] );
+ } else {
+ Hooks::run( 'UserLoginForm', [ &$template ] );
+ }
+
+ $out->disallowUserJs(); // just in case...
+ $out->addTemplate( $template );
+ }
+
+ /**
+ * Whether the login/create account form should display a link to the
+ * other form (in addition to whatever the skin provides).
+ *
+ * @param User $user
+ * @return bool
+ */
+ private function showCreateOrLoginLink( &$user ) {
+ if ( $this->mType == 'signup' ) {
+ return true;
+ } elseif ( $user->isAllowed( 'createaccount' ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Check if a session cookie is present.
+ *
+ * This will not pick up a cookie set during _this_ request, but is meant
+ * to ensure that the client is returning the cookie which was set on a
+ * previous pass through the system.
+ *
+ * @private
+ * @return bool
+ */
+ function hasSessionCookie() {
+ global $wgDisableCookieCheck, $wgInitialSessionId;
+
+ return $wgDisableCookieCheck || (
+ $wgInitialSessionId &&
+ $this->getRequest()->getSession()->getId() === (string)$wgInitialSessionId
+ );
+ }
+
+ /**
+ * Get the login token from the current session
+ * @since 1.27 returns a MediaWiki\Session\Token instead of a string
+ * @return MediaWiki\Session\Token
+ */
+ public static function getLoginToken() {
+ global $wgRequest;
+ return $wgRequest->getSession()->getToken( '', 'login' );
+ }
+
+ /**
+ * Formerly randomly generated a login token that would be returned by
+ * $this->getLoginToken().
+ *
+ * Since 1.27, this is a no-op. The token is generated as necessary by
+ * $this->getLoginToken().
+ *
+ * @deprecated since 1.27
+ */
+ public static function setLoginToken() {
+ wfDeprecated( __METHOD__, '1.27' );
+ }
+
+ /**
+ * Remove any login token attached to the current session
+ */
+ public static function clearLoginToken() {
+ global $wgRequest;
+ $wgRequest->getSession()->resetToken( 'login' );
+ }
+
+ /**
+ * Get the createaccount token from the current session
+ * @since 1.27 returns a MediaWiki\Session\Token instead of a string
+ * @return MediaWiki\Session\Token
+ */
+ public static function getCreateaccountToken() {
+ global $wgRequest;
+ return $wgRequest->getSession()->getToken( '', 'createaccount' );
+ }
+
+ /**
+ * Formerly randomly generated a createaccount token that would be returned
+ * by $this->getCreateaccountToken().
+ *
+ * Since 1.27, this is a no-op. The token is generated as necessary by
+ * $this->getCreateaccountToken().
+ *
+ * @deprecated since 1.27
+ */
+ public static function setCreateaccountToken() {
+ wfDeprecated( __METHOD__, '1.27' );
+ }
+
+ /**
+ * Remove any createaccount token attached to the current session
+ */
+ public static function clearCreateaccountToken() {
+ global $wgRequest;
+ $wgRequest->getSession()->resetToken( 'createaccount' );
+ }
+
+ /**
+ * Renew the user's session id, using strong entropy
+ */
+ private function renewSessionId() {
+ global $wgSecureLogin, $wgCookieSecure;
+ if ( $wgSecureLogin && !$this->mStickHTTPS ) {
+ $wgCookieSecure = false;
+ }
+
+ SessionManager::getGlobalSession()->resetId();
+ SessionManager::getGlobalSession()->resetAllTokens();
+ }
+
+ /**
+ * @param string $type
+ * @private
+ */
+ function cookieRedirectCheck( $type ) {
+ $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
+ $query = [ 'wpCookieCheck' => $type ];
+ if ( $this->mReturnTo !== '' ) {
+ $query['returnto'] = $this->mReturnTo;
+ $query['returntoquery'] = $this->mReturnToQuery;
+ }
+ $check = $titleObj->getFullURL( $query );
+
+ $this->getOutput()->redirect( $check );
+ }
+
+ /**
+ * @param string $type
+ * @private
+ */
+ function onCookieRedirectCheck( $type ) {
+ if ( !$this->hasSessionCookie() ) {
+ if ( $type == 'new' ) {
+ $this->mainLoginForm( $this->msg( 'nocookiesnew' )->parse() );
+ } elseif ( $type == 'login' ) {
+ $this->mainLoginForm( $this->msg( 'nocookieslogin' )->parse() );
+ } else {
+ # shouldn't happen
+ $this->mainLoginForm( $this->msg( 'error' )->text() );
+ }
+ } else {
+ $this->successfulLogin();
+ }
+ }
+
+ /**
+ * Produce a bar of links which allow the user to select another language
+ * during login/registration but retain "returnto"
+ *
+ * @return string
+ */
+ function makeLanguageSelector() {
+ $msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage();
+ if ( $msg->isBlank() ) {
+ return '';
+ }
+ $langs = explode( "\n", $msg->text() );
+ $links = [];
+ foreach ( $langs as $lang ) {
+ $lang = trim( $lang, '* ' );
+ $parts = explode( '|', $lang );
+ if ( count( $parts ) >= 2 ) {
+ $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
+ }
+ }
+
+ return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams(
+ $this->getLanguage()->pipeList( $links ) )->escaped() : '';
+ }
+
+ /**
+ * Create a language selector link for a particular language
+ * Links back to this page preserving type and returnto
+ *
+ * @param string $text Link text
+ * @param string $lang Language code
+ * @return string
+ */
+ function makeLanguageSelectorLink( $text, $lang ) {
+ if ( $this->getLanguage()->getCode() == $lang ) {
+ // no link for currently used language
+ return htmlspecialchars( $text );
+ }
+ $query = [ 'uselang' => $lang ];
+ if ( $this->mType == 'signup' ) {
+ $query['type'] = 'signup';
+ }
+ if ( $this->mReturnTo !== '' ) {
+ $query['returnto'] = $this->mReturnTo;
+ $query['returntoquery'] = $this->mReturnToQuery;
+ }
+
+ $attr = [];
+ $targetLanguage = Language::factory( $lang );
+ $attr['lang'] = $attr['hreflang'] = $targetLanguage->getHtmlCode();
+
+ return Linker::linkKnown(
+ $this->getPageTitle(),
+ htmlspecialchars( $text ),
+ $attr,
+ $query
+ );
+ }
+
+ protected function getGroupName() {
+ return 'login';
+ }
+
+ /**
+ * Private function to check password expiration, until AuthManager comes
+ * along to handle that.
+ * @param User $user
+ * @return string|bool
+ */
+ private function checkUserPasswordExpired( User $user ) {
+ global $wgPasswordExpireGrace;
+ $dbr = wfGetDB( DB_SLAVE );
+ $ts = $dbr->selectField( 'user', 'user_password_expires', [ 'user_id' => $user->getId() ] );
+
+ $expired = false;
+ $now = wfTimestamp();
+ $expUnix = wfTimestamp( TS_UNIX, $ts );
+ if ( $ts !== null && $expUnix < $now ) {
+ $expired = ( $expUnix + $wgPasswordExpireGrace < $now ) ? 'hard' : 'soft';
+ }
+ return $expired;
+ }
+
+ protected function getSubpagesForPrefixSearch() {
+ return [ 'signup' ];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Implements Special:Userlogout
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Implements Special:Userlogout
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialUserlogoutPreAuthManager extends UnlistedSpecialPage {
+ function __construct() {
+ parent::__construct( 'Userlogout' );
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ function execute( $par ) {
+ /**
+ * Some satellite ISPs use broken precaching schemes that log people out straight after
+ * they're logged in (bug 17790). Luckily, there's a way to detect such requests.
+ */
+ if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '&' ) !== false ) {
+ wfDebug( "Special:Userlogout request {$_SERVER['REQUEST_URI']} looks suspicious, denying.\n" );
+ throw new HttpError( 400, $this->msg( 'suspicious-userlogout' ), $this->msg( 'loginerror' ) );
+ }
+
+ $this->setHeaders();
+ $this->outputHeader();
+
+ // Make sure it's possible to log out
+ $session = MediaWiki\Session\SessionManager::getGlobalSession();
+ if ( !$session->canSetUser() ) {
+ throw new ErrorPageError(
+ 'cannotlogoutnow-title',
+ 'cannotlogoutnow-text',
+ [
+ $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
+ ]
+ );
+ }
+
+ $user = $this->getUser();
+ $oldName = $user->getName();
+ $user->logout();
+
+ $loginURL = SpecialPage::getTitleFor( 'Userlogin' )->getFullURL(
+ $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
+
+ $out = $this->getOutput();
+ $out->addWikiMsg( 'logouttext', $loginURL );
+
+ // Hook.
+ $injected_html = '';
+ Hooks::run( 'UserLogoutComplete', [ &$user, &$injected_html, $oldName ] );
+ $out->addHTML( $injected_html );
+
+ $out->returnToMain();
+ }
+
+ protected function getGroupName() {
+ return 'login';
+ }
+}
*
* @file
* @ingroup Templates
+ * @deprecated Will be removed when AuthManager lands.
+ * The signup form will be generated via HTMLForm.
*/
class UsercreateTemplate extends BaseTemplate {
*
* @file
* @ingroup Templates
+ * @deprecated Will be removed when AuthManager lands.
+ * The login form will be generated via HTMLForm.
*/
class UserloginTemplate extends BaseTemplate {
*/
public function formatTitle( $namespace, $text, $fragment = '', $interwiki = '' ) {
if ( $namespace !== false ) {
- $namespace = $this->getNamespaceName( $namespace, $text );
+ // Try to get a namespace name, but fallback
+ // to empty string if it doesn't exist
+ try {
+ $nsName = $this->getNamespaceName( $namespace, $text );
+ } catch ( InvalidArgumentException $e ) {
+ $nsName = '';
+ }
- if ( $namespace !== '' ) {
- $text = $namespace . ':' . $text;
+ if ( $namespace !== 0 ) {
+ $text = $nsName . ':' . $text;
}
}
);
}
+ /**
+ * @since 1.27
+ * @see TitleFormatter::getPrefixedDBkey()
+ * @param LinkTarget $target
+ * @return string
+ */
+ public function getPrefixedDBkey( LinkTarget $target ) {
+ $key = '';
+ if ( $target->isExternal() ) {
+ $key .= $target->getInterwiki() . ':';
+ }
+ // Try to get a namespace name, but fallback
+ // to empty string if it doesn't exist
+ try {
+ $nsName = $this->getNamespaceName(
+ $target->getNamespace(),
+ $target->getText()
+ );
+ } catch ( InvalidArgumentException $e ) {
+ $nsName = '';
+ }
+
+ if ( $target->getNamespace() !== 0 ) {
+ $key .= $nsName . ':';
+ }
+
+ $key .= $target->getText();
+
+ return strtr( $key, ' ', '_' );
+ }
+
/**
* @see TitleFormatter::getText()
*
*/
public function getPrefixedText( LinkTarget $title );
+ /**
+ * Return the title in prefixed database key form, with interwiki
+ * and namespace.
+ *
+ * @since 1.27
+ *
+ * @param LinkTarget $target
+ *
+ * @return string
+ */
+ public function getPrefixedDBkey( LinkTarget $target );
+
/**
* Returns the title formatted for display, with namespace and fragment.
*
return $this->namespace;
}
+ /**
+ * @since 1.27
+ * @param int $ns
+ * @return bool
+ */
+ public function inNamespace( $ns ) {
+ return $this->namespace == $ns;
+ }
+
/**
* @return string
*/
&& strpos( $value, '#' ) !== 0
) {
if ( !( $strippedElement === 'a'
- && preg_match( '!^https?://!im', $value ) )
+ && preg_match( '!^https?://!i', $value ) )
) {
wfDebug( __METHOD__ . ": Found href attribute <$strippedElement "
. "'$attrib'='$value' in uploaded file.\n" );
--- /dev/null
+<?php
+/**
+ * User password reset helper for MediaWiki.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Auth\TemporaryPasswordAuthenticationRequest;
+
+/**
+ * Helper class for the password reset functionality shared by the web UI and the API.
+ *
+ * Requires the TemporaryPasswordPrimaryAuthenticationProvider and the
+ * EmailNotificationSecondaryAuthenticationProvider (or something providing equivalent
+ * functionality) to be enabled.
+ */
+class PasswordReset {
+ /** @var Config */
+ protected $config;
+
+ /** @var AuthManager */
+ protected $authManager;
+
+ /**
+ * In-process cache for isAllowed lookups, by username. Contains pairs of StatusValue objects
+ * (for false and true value of $displayPassword, respectively).
+ * @var HashBagOStuff
+ */
+ private $permissionCache;
+
+ public function __construct( Config $config, AuthManager $authManager ) {
+ $this->config = $config;
+ $this->authManager = $authManager;
+ $this->permissionCache = new HashBagOStuff( [ 'maxKeys' => 1 ] );
+ }
+
+ /**
+ * Check if a given user has permission to use this functionality.
+ * @param User $user
+ * @param bool $displayPassword If set, also check whether the user is allowed to reset the
+ * password of another user and see the temporary password.
+ * @return StatusValue
+ */
+ public function isAllowed( User $user, $displayPassword = false ) {
+ $statuses = $this->permissionCache->get( $user->getName() );
+ if ( $statuses ) {
+ list ( $status, $status2 ) = $statuses;
+ } else {
+ $resetRoutes = $this->config->get( 'PasswordResetRoutes' );
+ $status = StatusValue::newGood();
+
+ if ( !is_array( $resetRoutes ) ||
+ !in_array( true, array_values( $resetRoutes ), true )
+ ) {
+ // Maybe password resets are disabled, or there are no allowable routes
+ $status = StatusValue::newFatal( 'passwordreset-disabled' );
+ } elseif (
+ ( $providerStatus = $this->authManager->allowsAuthenticationDataChange(
+ new TemporaryPasswordAuthenticationRequest(), false ) )
+ && !$providerStatus->isGood()
+ ) {
+ // Maybe the external auth plugin won't allow local password changes
+ $status = StatusValue::newFatal( 'resetpass_forbidden-reason',
+ $providerStatus->getMessage() );
+ } elseif ( !$this->config->get( 'EnableEmail' ) ) {
+ // Maybe email features have been disabled
+ $status = StatusValue::newFatal( 'passwordreset-emaildisabled' );
+ } elseif ( !$user->isAllowed( 'editmyprivateinfo' ) ) {
+ // Maybe not all users have permission to change private data
+ $status = StatusValue::newFatal( 'badaccess' );
+ } elseif ( $user->isBlocked() ) {
+ // Maybe the user is blocked (check this here rather than relying on the parent
+ // method as we have a more specific error message to use here
+ $status = StatusValue::newFatal( 'blocked-mailpassword' );
+ }
+
+ $status2 = StatusValue::newGood();
+ if ( !$user->isAllowed( 'passwordreset' ) ) {
+ $status2 = StatusValue::newFatal( 'badaccess' );
+ }
+
+ $this->permissionCache->set( $user->getName(), [ $status, $status2 ] );
+ }
+
+ if ( !$displayPassword || !$status->isGood() ) {
+ return $status;
+ } else {
+ return $status2;
+ }
+ }
+
+ /**
+ * Do a password reset. Authorization is the caller's responsibility.
+ *
+ * Process the form. At this point we know that the user passes all the criteria in
+ * userCanExecute(), and if the data array contains 'Username', etc, then Username
+ * resets are allowed.
+ * @param User $performingUser The user that does the password reset
+ * @param string $username The user whose password is reset
+ * @param string $email Alternative way to specify the user
+ * @param bool $displayPassword Whether to display the password
+ * @return StatusValue Will contain the passwords as a username => password array if the
+ * $displayPassword flag was set
+ * @throws LogicException When the user is not allowed to perform the action
+ * @throws MWException On unexpected DB errors
+ */
+ public function execute(
+ User $performingUser, $username = null, $email = null, $displayPassword = false
+ ) {
+ if ( !$this->isAllowed( $performingUser, $displayPassword )->isGood() ) {
+ $action = $this->isAllowed( $performingUser )->isGood() ? 'display' : 'reset';
+ throw new LogicException( 'User ' . $performingUser->getName()
+ . ' is not allowed to ' . $action . ' passwords' );
+ }
+
+ $resetRoutes = $this->config->get( 'PasswordResetRoutes' )
+ + [ 'username' => false, 'email' => false ];
+ if ( $resetRoutes['username'] && $username ) {
+ $method = 'username';
+ $users = [ User::newFromName( $username ) ];
+ } elseif ( $resetRoutes['email'] && $email ) {
+ if ( !Sanitizer::validateEmail( $email ) ) {
+ return StatusValue::newFatal( 'passwordreset-invalidemail' );
+ }
+ $method = 'email';
+ $users = $this->getUsersByEmail( $email );
+ } else {
+ // The user didn't supply any data
+ return StatusValue::newFatal( 'passwordreset-nodata' );
+ }
+
+ // Check for hooks (captcha etc), and allow them to modify the users list
+ $error = [];
+ $data = [
+ 'Username' => $username,
+ 'Email' => $email,
+ 'Capture' => $displayPassword ? '1' : null,
+ ];
+ if ( !Hooks::run( 'SpecialPasswordResetOnSubmit', [ &$users, $data, &$error ] ) ) {
+ return StatusValue::newFatal( wfMessage( $error ) );
+ }
+
+ if ( !$users ) {
+ if ( $method === 'email' ) {
+ // Don't reveal whether or not an email address is in use
+ return StatusValue::newGood( [] );
+ } else {
+ return StatusValue::newFatal( 'noname' );
+ }
+ }
+
+ $firstUser = $users[0];
+
+ if ( !$firstUser instanceof User || !$firstUser->getId() ) {
+ // Don't parse username as wikitext (bug 65501)
+ return StatusValue::newFatal( wfMessage( 'nosuchuser', wfEscapeWikiText( $username ) ) );
+ }
+
+ // Check against the rate limiter
+ if ( $performingUser->pingLimiter( 'mailpassword' ) ) {
+ return StatusValue::newFatal( 'actionthrottledtext' );
+ }
+
+ // All the users will have the same email address
+ if ( !$firstUser->getEmail() ) {
+ // This won't be reachable from the email route, so safe to expose the username
+ return StatusValue::newFatal( wfMessage( 'noemail',
+ wfEscapeWikiText( $firstUser->getName() ) ) );
+ }
+
+ // We need to have a valid IP address for the hook, but per bug 18347, we should
+ // send the user's name if they're logged in.
+ $ip = $performingUser->getRequest()->getIP();
+ if ( !$ip ) {
+ return StatusValue::newFatal( 'badipaddress' );
+ }
+
+ Hooks::run( 'User::mailPasswordInternal', [ &$performingUser, &$ip, &$firstUser ] );
+
+ $result = StatusValue::newGood();
+ $reqs = [];
+ foreach ( $users as $user ) {
+ $req = TemporaryPasswordAuthenticationRequest::newRandom();
+ $req->username = $user->getName();
+ $req->mailpassword = true;
+ $req->hasBackchannel = $displayPassword;
+ $req->caller = $performingUser->getName();
+ $status = $this->authManager->allowsAuthenticationDataChange( $req, true );
+ if ( $status->isGood() && $status->getValue() !== 'ignored' ) {
+ $reqs[] = $req;
+ } elseif ( $result->isGood() ) {
+ // only record the first error, to avoid exposing the number of users having the
+ // same email address
+ if ( $status->getValue() === 'ignored' ) {
+ $status = StatusValue::newFatal( 'passwordreset-ignored' );
+ }
+ $result->merge( $status );
+ }
+ }
+
+ if ( !$result->isGood() ) {
+ return $result;
+ }
+
+ $passwords = [];
+ foreach ( $reqs as $req ) {
+ $this->authManager->changeAuthenticationData( $req );
+ // TODO record mail sending errors
+ if ( $displayPassword ) {
+ $passwords[$req->username] = $req->password;
+ }
+ }
+
+ return StatusValue::newGood( $passwords );
+ }
+
+ /**
+ * @param string $email
+ * @return User[]
+ * @throws MWException On unexpected database errors
+ */
+ protected function getUsersByEmail( $email ) {
+ $res = wfGetDB( DB_SLAVE )->select(
+ 'user',
+ User::selectFields(),
+ [ 'user_email' => $email ],
+ __METHOD__
+ );
+
+ if ( !$res ) {
+ // Some sort of database error, probably unreachable
+ throw new MWException( 'Unknown database error in ' . __METHOD__ );
+ }
+
+ $users = [];
+ foreach ( $res as $row ) {
+ $users[] = User::newFromRow( $row );
+ }
+ return $users;
+ }
+}
use MediaWiki\MediaWikiServices;
use MediaWiki\Session\SessionManager;
use MediaWiki\Session\Token;
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\AuthenticationRequest;
/**
* String Some punctuation to prevent editing from broken text-mangling proxies.
'createpage',
'createtalk',
'delete',
+ 'deletechangetags',
'deletedhistory',
'deletedtext',
'deletelogentry',
*/
protected static $mAllRights = false;
- /**
- * An in-process cache for user data lookup
- * @var HashBagOStuff
- */
- protected static $inProcessCache;
-
/** Cache variables */
// @{
/** @var int */
*/
public function loadFromId( $flags = self::READ_NORMAL ) {
if ( $this->mId == 0 ) {
+ // Anonymous users are not in the database (don't need cache)
$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 ( $latest ) {
if ( !$this->loadFromDatabase( $flags ) ) {
- // Can't load from ID, user is anonymous
+ // Can't load from ID
return false;
}
- $this->saveToCache();
+ } else {
+ $this->loadFromCache();
}
$this->mLoadedItems = true;
*/
public static function purge( $wikiId, $userId ) {
$cache = ObjectCache::getMainWANInstance();
- $processCache = self::getInProcessCache();
$key = $cache->makeGlobalKey( 'user', 'id', $wikiId, $userId );
$cache->delete( $key );
- $processCache->delete( $key );
}
/**
return $cache->makeGlobalKey( 'user', 'id', wfWikiID(), $this->mId );
}
- /**
- * @since 1.27
- * @return HashBagOStuff
- */
- protected static function getInProcessCache() {
- if ( !self::$inProcessCache ) {
- self::$inProcessCache = new HashBagOStuff( ['maxKeys' => 10] );
- }
- return self::$inProcessCache;
- }
-
/**
* 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
+ * @return bool True
* @since 1.25
*/
protected function loadFromCache() {
- if ( $this->mId == 0 ) {
- $this->loadDefaults();
- return false;
- }
-
$cache = ObjectCache::getMainWANInstance();
- $processCache = self::getInProcessCache();
- $key = $this->getCacheKey( $cache );
- $data = $processCache->get( $key );
- if ( !is_array( $data ) ) {
- $data = $cache->get( $key );
- if ( !is_array( $data ) || $data['mVersion'] < self::VERSION ) {
- // Object is expired
- return false;
- }
- $processCache->set( $key, $data );
- }
- wfDebug( "User: got user {$this->mId} from cache\n" );
+ $data = $cache->getWithSetCallback(
+ $this->getCacheKey( $cache ),
+ $cache::TTL_HOUR,
+ function ( $oldValue, &$ttl, array &$setOpts ) {
+ $setOpts += Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) );
+ wfDebug( "User: cache miss for user {$this->mId}\n" );
- // Restore from cache
- foreach ( self::$mCacheVars as $name ) {
- $this->$name = $data[$name];
- }
+ $this->loadFromDatabase();
+ $this->loadGroups();
+ $this->loadOptions();
- return true;
- }
+ $data = [];
+ foreach ( self::$mCacheVars as $name ) {
+ $data[$name] = $this->$name;
+ }
- /**
- * 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();
+ return $data;
- if ( $this->isAnon() ) {
- // Anonymous users are uncached
- return;
- }
+ },
+ [ 'pcTTL' => $cache::TTL_PROC_LONG, 'version' => self::VERSION ]
+ );
- $data = [];
+ // Restore from cache
foreach ( self::$mCacheVars as $name ) {
- $data[$name] = $this->$name;
+ $this->$name = $data[$name];
}
- $data['mVersion'] = self::VERSION;
- $opts = Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) );
- $cache = ObjectCache::getMainWANInstance();
- $processCache = self::getInProcessCache();
- $key = $this->getCacheKey( $cache );
- $cache->set( $key, $data, $cache::TTL_HOUR, $opts );
- $processCache->set( $key, $data );
+ return true;
}
/** @name newFrom*() static factory methods */
* This can optionally create the user if it doesn't exist, and "steal" the
* account if it does exist.
*
+ * "Stealing" an existing user is intended to make it impossible for normal
+ * authentication processes to use the account, effectively disabling the
+ * account for normal use:
+ * - Email is invalidated, to prevent account recovery by emailing a
+ * temporary password and to disassociate the account from the existing
+ * human.
+ * - The token is set to a magic invalid value, to kill existing sessions
+ * and to prevent $this->setToken() calls from resetting the token to a
+ * valid value.
+ * - SessionManager is instructed to prevent new sessions for the user, to
+ * do things like deauthorizing OAuth consumers.
+ * - AuthManager is instructed to revoke access, to invalidate or remove
+ * passwords and other credentials.
+ *
* @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
+ * - steal: Whether to "disable" the account for normal use if it already
+ * exists, default false
* @return User|null
+ * @since 1.27
*/
public static function newSystemUser( $name, $options = [] ) {
+ global $wgDisableAuthManager;
+
$options += [
'validate' => 'valid',
'create' => true,
return null;
}
+ $fields = self::selectFields();
+ if ( $wgDisableAuthManager ) {
+ $fields = array_merge( $fields, [ 'user_password', 'user_newpassword' ] );
+ }
+
$dbw = wfGetDB( DB_MASTER );
$row = $dbw->selectRow(
'user',
- array_merge(
- self::selectFields(),
- [ 'user_password', 'user_newpassword' ]
- ),
+ $fields,
[ 'user_name' => $name ],
__METHOD__
);
}
$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, or a
- // non-invalid token.
- $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->mToken !== self::INVALID_TOKEN
- ) {
+ // A user is considered to exist as a non-system user if it can
+ // authenticate, or has an email set, or has a non-invalid token.
+ if ( !$user->mEmail && $user->mToken === self::INVALID_TOKEN ) {
+ if ( $wgDisableAuthManager ) {
+ $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();
+ }
+ $canAuthenticate = !$password instanceof InvalidPassword ||
+ !$newpassword instanceof InvalidPassword;
+ } else {
+ $canAuthenticate = AuthManager::singleton()->userCanAuthenticate( $name );
+ }
+ }
+ if ( $user->mEmail || $user->mToken !== self::INVALID_TOKEN || $canAuthenticate ) {
// User exists. Steal it?
if ( !$options['steal'] ) {
return null;
}
- $nopass = PasswordFactory::newInvalidPassword()->toString();
+ if ( $wgDisableAuthManager ) {
+ $nopass = PasswordFactory::newInvalidPassword()->toString();
+ $dbw->update(
+ 'user',
+ [
+ 'user_password' => $nopass,
+ 'user_newpassword' => $nopass,
+ 'user_newpass_time' => null,
+ ],
+ [ 'user_id' => $user->getId() ],
+ __METHOD__
+ );
+ } else {
+ AuthManager::singleton()->revokeAccessForUser( $name );
+ }
- $dbw->update(
- 'user',
- [
- 'user_password' => $nopass,
- 'user_newpassword' => $nopass,
- 'user_newpass_time' => null,
- ],
- [ 'user_id' => $user->getId() ],
- __METHOD__
- );
$user->invalidateEmail();
$user->mToken = self::INVALID_TOKEN;
$user->saveSettings();
}
// Reject various classes of invalid names
- global $wgAuth;
- $name = $wgAuth->getCanonicalName( $t->getText() );
+ $name = AuthManager::callLegacyAuthPlugin(
+ 'getCanonicalName', [ $t->getText() ], $t->getText()
+ );
switch ( $validate ) {
case false:
// Paranoia
$this->mId = intval( $this->mId );
- // Anonymous user
if ( !$this->mId ) {
+ // Anonymous users are not in the database
$this->loadDefaults();
return false;
}
* @see $wgAutopromoteOnce
*/
public function addAutopromoteOnceGroups( $event ) {
- global $wgAutopromoteOnceLogInRC, $wgAuth;
+ global $wgAutopromoteOnceLogInRC;
if ( wfReadOnly() || !$this->getId() ) {
return [];
}
// update groups in external authentication database
Hooks::run( 'UserGroupsChanged', [ $this, $toPromote, [], false, false ] );
- $wgAuth->updateExternalDBGroups( $this, $toPromote );
+ AuthManager::callLegacyAuthPlugin( 'updateExternalDBGroups', [ $this, $toPromote ] );
$newGroups = array_merge( $oldGroups, $toPromote ); // all groups
return $toPromote;
}
+ /**
+ * Builds update conditions. Additional conditions may be added to $conditions to
+ * protected against race conditions using a compare-and-set (CAS) mechanism
+ * based on comparing $this->mTouched with the user_touched field.
+ *
+ * @param DatabaseBase $db
+ * @param array $conditions WHERE conditions for use with DatabaseBase::update
+ * @return array WHERE conditions for use with DatabaseBase::update
+ */
+ protected function makeUpdateConditions( DatabaseBase $db, array $conditions ) {
+ if ( $this->mTouched ) {
+ // CAS check: only update if the row wasn't changed sicne it was loaded.
+ $conditions['user_touched'] = $db->timestamp( $this->mTouched );
+ }
+
+ return $conditions;
+ }
+
/**
* Bump user_touched if it didn't change since this object was loaded
*
}
// 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',
[ 'user_touched' => $dbw->timestamp( $newTouched ) ],
- [
+ $this->makeUpdateConditions( $dbw, [
'user_id' => $this->mId,
- 'user_touched' => $dbw->timestamp( $oldTouched ) // CAS check
- ],
+ ] ),
__METHOD__
);
$success = ( $dbw->affectedRows() > 0 );
if ( $this->mLocked !== null ) {
return $this->mLocked;
}
- global $wgAuth;
- $authUser = $wgAuth->getUserInstance( $this );
- $this->mLocked = (bool)$authUser->isLocked();
+ $authUser = AuthManager::callLegacyAuthPlugin( 'getUserInstance', [ &$this ], null );
+ $this->mLocked = $authUser && $authUser->isLocked();
Hooks::run( 'UserIsLocked', [ $this, &$this->mLocked ] );
return $this->mLocked;
}
}
$this->getBlockedStatus();
if ( !$this->mHideName ) {
- global $wgAuth;
- $authUser = $wgAuth->getUserInstance( $this );
- $this->mHideName = (bool)$authUser->isHidden();
+ $authUser = AuthManager::callLegacyAuthPlugin( 'getUserInstance', [ &$this ], null );
+ $this->mHideName = $authUser && $authUser->isHidden();
Hooks::run( 'UserIsHidden', [ $this, &$this->mHideName ] );
}
return $this->mHideName;
}
$cache = ObjectCache::getMainWANInstance();
- $processCache = self::getInProcessCache();
$key = $this->getCacheKey( $cache );
if ( $mode === 'refresh' ) {
$cache->delete( $key, 1 );
- $processCache->delete( $key );
} else {
wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle(
- function() use ( $cache, $processCache, $key ) {
+ function() use ( $cache, $key ) {
$cache->delete( $key );
- $processCache->delete( $key );
}
);
}
* 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.
+ * @deprecated since 1.27, use AuthManager instead
* @param string $str New password to set
* @throws PasswordError On failure
* @return bool
*/
public function setPassword( $str ) {
- global $wgAuth;
+ global $wgAuth, $wgDisableAuthManager;
+
+ if ( !$wgDisableAuthManager ) {
+ return $this->setPasswordInternal( $str );
+ }
if ( $str !== null ) {
if ( !$wgAuth->allowPasswordChange() ) {
throw new PasswordError( wfMessage( 'externaldberror' )->text() );
}
- $this->setToken();
$this->setOption( 'watchlisttoken', false );
$this->setPasswordInternal( $str );
/**
* Set the password and reset the random token unconditionally.
*
- * @deprecated since 1.27. AuthManager is coming.
+ * @deprecated since 1.27, use AuthManager instead
* @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;
+ global $wgAuth, $wgDisableAuthManager;
+
+ if ( !$wgDisableAuthManager ) {
+ $this->setPasswordInternal( $str );
+ }
if ( $wgAuth->allowSetLocalPassword() ) {
- $this->setToken();
$this->setOption( 'watchlisttoken', false );
$this->setPasswordInternal( $str );
}
* @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.
+ * @return bool Success
*/
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.' );
+ global $wgDisableAuthManager;
+
+ if ( $wgDisableAuthManager ) {
+ $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',
+ [
+ 'user_password' => $passwordFactory->newFromPlaintext( $str )->toString(),
+ 'user_newpassword' => PasswordFactory::newInvalidPassword()->toString(),
+ 'user_newpass_time' => $dbw->timestampOrNull( null ),
+ ],
+ [
+ 'user_id' => $id,
+ ],
+ __METHOD__
+ );
+
+ // When the main password is changed, invalidate all bot passwords too
+ BotPassword::invalidateAllPasswordsForUser( $this->getName() );
+ } else {
+ $manager = AuthManager::singleton();
+
+ // If the user doesn't exist yet, fail
+ if ( !$manager->userExists( $this->getName() ) ) {
+ throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
+ }
+
+ $data = [
+ 'username' => $this->getName(),
+ 'password' => $str,
+ 'retype' => $str,
+ ];
+ $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
+ $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
+ foreach ( $reqs as $req ) {
+ $status = $manager->allowsAuthenticationDataChange( $req );
+ if ( !$status->isOk() ) {
+ \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+ ->info( __METHOD__ . ': Password change rejected: ' . $status->getWikiText() );
+ return false;
+ }
+ }
+ foreach ( $reqs as $req ) {
+ $manager->changeAuthenticationData( $req );
+ }
+
+ $this->setOption( 'watchlisttoken', false );
}
- $passwordFactory = new PasswordFactory();
- $passwordFactory->init( RequestContext::getMain()->getConfig() );
- $dbw = wfGetDB( DB_MASTER );
- $dbw->update(
- 'user',
- [
- 'user_password' => $passwordFactory->newFromPlaintext( $str )->toString(),
- 'user_newpassword' => PasswordFactory::newInvalidPassword()->toString(),
- 'user_newpass_time' => $dbw->timestampOrNull( null ),
- ],
- [
- 'user_id' => $id,
- ],
- __METHOD__
- );
+ SessionManager::singleton()->invalidateSessionsForUser( $this );
- // When the main password is changed, invalidate all bot passwords too
- BotPassword::invalidateAllPasswordsForUser( $this->getName() );
+ return true;
}
/**
/**
* Set the password for a password reminder or new account email
*
- * @deprecated since 1.27, AuthManager is coming
+ * @deprecated Removed in 1.27. Use PasswordReset instead.
* @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.' );
- }
+ global $wgDisableAuthManager;
- $dbw = wfGetDB( DB_MASTER );
+ if ( $wgDisableAuthManager ) {
+ $id = $this->getId();
+ if ( $id == 0 ) {
+ throw new LogicException( 'Cannot set new password for a user that is not in the database.' );
+ }
- $passwordFactory = new PasswordFactory();
- $passwordFactory->init( RequestContext::getMain()->getConfig() );
- $update = [
- 'user_newpassword' => $passwordFactory->newFromPlaintext( $str )->toString(),
- ];
+ $dbw = wfGetDB( DB_MASTER );
- if ( $str === null ) {
- $update['user_newpass_time'] = null;
- } elseif ( $throttle ) {
- $update['user_newpass_time'] = $dbw->timestamp();
- }
+ $passwordFactory = new PasswordFactory();
+ $passwordFactory->init( RequestContext::getMain()->getConfig() );
+ $update = [
+ 'user_newpassword' => $passwordFactory->newFromPlaintext( $str )->toString(),
+ ];
- $dbw->update( 'user', $update, [ 'user_id' => $id ], __METHOD__ );
+ if ( $str === null ) {
+ $update['user_newpass_time'] = null;
+ } elseif ( $throttle ) {
+ $update['user_newpass_time'] = $dbw->timestamp();
+ }
+
+ $dbw->update( 'user', $update, [ 'user_id' => $id ], __METHOD__ );
+ } else {
+ throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
+ }
}
/**
* Has password reminder email been sent within the last
* $wgPasswordReminderResendTime hours?
+ * @deprecated Removed in 1.27. See above.
* @return bool
*/
public function isPasswordReminderThrottled() {
- global $wgPasswordReminderResendTime;
+ global $wgPasswordReminderResendTime, $wgDisableAuthManager;
- if ( !$wgPasswordReminderResendTime ) {
- return false;
- }
+ if ( $wgDisableAuthManager ) {
+ if ( !$wgPasswordReminderResendTime ) {
+ return false;
+ }
- $this->load();
+ $this->load();
- $db = ( $this->queryFlagsUsed & self::READ_LATEST )
- ? wfGetDB( DB_MASTER )
- : wfGetDB( DB_SLAVE );
- $newpassTime = $db->selectField(
- 'user',
- 'user_newpass_time',
- [ 'user_id' => $this->getId() ],
- __METHOD__
- );
+ $db = ( $this->queryFlagsUsed & self::READ_LATEST )
+ ? wfGetDB( DB_MASTER )
+ : wfGetDB( DB_SLAVE );
+ $newpassTime = $db->selectField(
+ 'user',
+ 'user_newpass_time',
+ [ 'user_id' => $this->getId() ],
+ __METHOD__
+ );
- if ( $newpassTime === null ) {
- return false;
+ if ( $newpassTime === null ) {
+ return false;
+ }
+ $expiry = wfTimestamp( TS_UNIX, $newpassTime ) + $wgPasswordReminderResendTime * 3600;
+ return time() < $expiry;
+ } else {
+ throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
}
- $expiry = wfTimestamp( TS_UNIX, $newpassTime ) + $wgPasswordReminderResendTime * 3600;
- return time() < $expiry;
}
/**
return !$this->isLoggedIn();
}
+ /**
+ * @return bool Whether this user is flagged as being a bot role account
+ * @since 1.28
+ */
+ public function isBot() {
+ if ( in_array( 'bot', $this->getGroups() ) && $this->isAllowed( 'bot' ) ) {
+ return true;
+ }
+
+ $isBot = false;
+ Hooks::run( "UserIsBot", [ $this, &$isBot ] );
+
+ return $isBot;
+ }
+
/**
* Check if user is allowed to access a feature / make an action
*
if ( !$session->canSetUser() ) {
\MediaWiki\Logger\LoggerFactory::getInstance( 'session' )
->warning( __METHOD__ . ": Cannot log out of an immutable session" );
+ $error = 'immutable';
} elseif ( !$session->getUser()->equals( $this ) ) {
\MediaWiki\Logger\LoggerFactory::getInstance( 'session' )
->warning( __METHOD__ .
);
// But we still may as well make this user object anon
$this->clearInstanceCache( 'defaults' );
+ $error = 'wronguser';
} else {
$this->clearInstanceCache( 'defaults' );
$delay = $session->delaySave();
$session->setLoggedOutTimestamp( time() );
$session->setUser( new User );
$session->set( 'wsUserID', 0 ); // Other code expects this
+ $session->resetAllTokens();
ScopedCallback::consume( $delay );
+ $error = false;
}
+ \MediaWiki\Logger\LoggerFactory::getInstance( 'authmanager' )->info( 'Logout', [
+ 'event' => 'logout',
+ 'successful' => $error === false,
+ 'status' => $error ?: 'success',
+ ] );
}
/**
// 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 );
'user_token' => strval( $this->mToken ),
'user_email_token' => $this->mEmailToken,
'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
- ], [ /* WHERE */
+ ], $this->makeUpdateConditions( $dbw, [ /* WHERE */
'user_id' => $this->mId,
- 'user_touched' => $dbw->timestamp( $oldTouched ) // CAS check
- ], __METHOD__
+ ] ), __METHOD__
);
if ( !$dbw->affectedRows() ) {
/**
* Check to see if the given clear-text password is one of the accepted passwords
- * @deprecated since 1.27. AuthManager is coming.
+ * @deprecated since 1.27, use AuthManager instead
* @param string $password User password
* @return bool True if the given password is correct, otherwise False
*/
public function checkPassword( $password ) {
- global $wgAuth, $wgLegacyEncoding;
+ global $wgAuth, $wgLegacyEncoding, $wgDisableAuthManager;
- $this->load();
+ if ( $wgDisableAuthManager ) {
+ $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;
- }
+ // 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;
- }
+ // 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 );
+ $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', [ 'user_id' => $this->getId() ], __METHOD__
- ) );
- } catch ( PasswordError $e ) {
- wfDebug( 'Invalid password hash found in database.' );
- $mPassword = PasswordFactory::newInvalidPassword();
- }
+ try {
+ $mPassword = $passwordFactory->newFromCiphertext( $db->selectField(
+ 'user', 'user_password', [ '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 ) ) {
+ 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;
}
- } else {
- return false;
}
- }
- if ( $passwordFactory->needsUpdate( $mPassword ) && !wfReadOnly() ) {
- $this->setPasswordInternal( $password );
- }
+ if ( $passwordFactory->needsUpdate( $mPassword ) && !wfReadOnly() ) {
+ $this->setPasswordInternal( $password );
+ }
- return true;
+ return true;
+ } else {
+ $manager = AuthManager::singleton();
+ $reqs = AuthenticationRequest::loadRequestsFromSubmission(
+ $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ),
+ [
+ 'username' => $this->getName(),
+ 'password' => $password,
+ ]
+ );
+ $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
+ switch ( $res->status ) {
+ case AuthenticationResponse::PASS:
+ return true;
+ case AuthenticationResponse::FAIL:
+ // Hope it's not a PreAuthenticationProvider that failed...
+ \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+ ->info( __METHOD__ . ': Authentication failed: ' . $res->message->plain() );
+ return false;
+ default:
+ throw new BadMethodCallException(
+ 'AuthManager returned a response unsupported by ' . __METHOD__
+ );
+ }
+ }
}
/**
* 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.
+ * @deprecated since 1.27, use AuthManager instead
* @param string $plaintext
* @return bool True if matches, false otherwise
*/
public function checkTemporaryPassword( $plaintext ) {
- global $wgNewPasswordExpiry;
+ global $wgNewPasswordExpiry, $wgDisableAuthManager;
- $this->load();
+ if ( $wgDisableAuthManager ) {
+ $this->load();
- $passwordFactory = new PasswordFactory();
- $passwordFactory->init( RequestContext::getMain()->getConfig() );
- $db = ( $this->queryFlagsUsed & self::READ_LATEST )
- ? wfGetDB( DB_MASTER )
- : wfGetDB( DB_SLAVE );
+ $passwordFactory = new PasswordFactory();
+ $passwordFactory->init( RequestContext::getMain()->getConfig() );
+ $db = ( $this->queryFlagsUsed & self::READ_LATEST )
+ ? wfGetDB( DB_MASTER )
+ : wfGetDB( DB_SLAVE );
- $row = $db->selectRow(
- 'user',
- [ 'user_newpassword', 'user_newpass_time' ],
- [ '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();
- }
+ $row = $db->selectRow(
+ 'user',
+ [ 'user_newpassword', 'user_newpass_time' ],
+ [ '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;
+ 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;
}
- $expiry = wfTimestamp( TS_UNIX, $row->user_newpass_time ) + $wgNewPasswordExpiry;
- return ( time() < $expiry );
} else {
- return false;
+ // Can't check the temporary password individually.
+ return $this->checkPassword( $plaintext );
}
}
* Add a newuser log entry for this user.
* Before 1.19 the return value was always true.
*
+ * @deprecated since 1.27, AuthManager handles logging
* @param string|bool $action Account creation type.
* - String, one of the following values:
* - 'create' for an anonymous user creating an account for himself.
* - 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
+ * @return int|bool True if not $wgNewUserLog or not $wgDisableAuthManager;
+ * otherwise ID of log item or 0 on failure
*/
public function addNewUserLogEntry( $action = false, $reason = '' ) {
- global $wgUser, $wgNewUserLog;
- if ( empty( $wgNewUserLog ) ) {
+ global $wgUser, $wgNewUserLog, $wgDisableAuthManager;
+ if ( !$wgDisableAuthManager || empty( $wgNewUserLog ) ) {
return true; // disabled
}
* Used by things like CentralAuth and perhaps other authplugins.
* Consider calling addNewUserLogEntry() directly instead.
*
+ * @deprecated since 1.27, AuthManager handles logging
* @return bool
*/
public function addNewUserLogEntryAutoCreate() {
*/
public function extractPrimaryKeys( $row ) {
$pk = [];
- foreach ( $this->primaryKey as $column ) {
- $pk[$column] = $row->$column;
+ foreach ( $this->primaryKey as $alias => $column ) {
+ $name = is_numeric( $alias ) ? $column : $alias;
+ $pk[$name] = $row->{$name};
}
return $pk;
}
$maxRow = end( $this->current );
$maximumValues = [];
- foreach ( $this->primaryKey as $column ) {
- $maximumValues[$column] = $this->db->addQuotes( $maxRow->$column );
+ foreach ( $this->primaryKey as $alias => $column ) {
+ $name = is_numeric( $alias ) ? $column : $alias;
+ $maximumValues[$column] = $this->db->addQuotes( $maxRow->{$name} );
}
$pkConditions = [];
protected $performSearchOnClick = true;
protected $validateTitle = false;
protected $highlightFirst = false;
+ protected $dataLocation = 'header';
/**
* @param array $config Configuration options
* @param boolean|null $config['performSearchOnClick'] If true, the script will start a search
* whenever a user hits a suggestion. If false, the text of the suggestion is inserted into the
* text field only (default: true)
+ * @param string $config['dataLocation'] Where the search input field will be
+ * used (header or content, default: header)
*/
public function __construct( array $config = [] ) {
$config = array_merge( [
'maxLength' => null,
'type' => 'search',
'icon' => 'search',
- 'dataLocation' => 'content',
], $config );
// Parent constructor
"--builtin-classes": true,
"--processes": "0",
"--warnings-exit-nonzero": true,
- "--external": "HTMLElement,HTMLDocument,Window,Blob,File,MouseEvent,KeyboardEvent,HTMLIframeElement,HTMLInputElement,XMLDocument",
+ "--external": "Blob,File,HTMLDocument,HTMLElement,HTMLIframeElement,HTMLInputElement,KeyboardEvent,MouseEvent,Node,Window,XMLDocument",
"--output": "docs/js",
"--": [
"maintenance/jsduck/external.js",
return $lang;
}
+ /**
+ * Compare with an other language object
+ *
+ * @since 1.28
+ * @param Language $lang
+ * @return boolean
+ */
+ public function equals( Language $lang ) {
+ return $lang->getCode() === $this->mCode;
+ }
+
/**
* Get the internal language code for this language object
*
"noname": "Nan ureuëng ngui nyang Droënueh peutamöng hana sah.",
"loginsuccesstitle": "Meuhasé tamöng",
"loginsuccess": "'''Droëneuh jinoë ka neutamöng di {{SITENAME}} sibagoë \"$1\".'''",
- "nosuchuser": "Hana ureuëng ngui ngön nan \"$1\".\nNan ureuëng ngui jipeubida haraih rayek.\nTulông neuparéksa keulayi neuija Droëneuh, atawa [[Special:UserLogin/signup|neudapeuta barô]].",
+ "nosuchuser": "Hana ureuëng ngui ngön nan \"$1\".\nNan ureuëng ngui jipeubida haraih rayek.\nTulông neuparéksa keulayi neuija Droëneuh, atawa [[Special:CreateAccount|neudapeuta barô]].",
"nosuchusershort": "Hana ureuëng ngui ngön nan \"$1\".\nPréksa keulayi neu’ija Droëneuh.",
"nouserspecified": "Neupasoë nan Droëneuh.",
"login-userblocked": "Ureuëng ngui nyoë ka teublokir, hana idin/hanjeut tamöng.",
"accmailtitle": "Lageuem rahsia ka meukirém",
"newarticle": "(Barô)",
"newarticletext": "Droëneuh ka neuseutöt peunawôt u laman nyang goh na.\nKeu neupeugöt laman nyan, neukeutik lam plôk di yup (eu [$1 laman beunantu] keu haba leubèh le).\nMeunyö droëneuh trôk keunoë hana neusaja, neuteugön tèk '''back''' bak ''browser'''droëneuh.",
- "anontalkpagetext": "----''Nyoe nakeuh ôn marit ureueng ngui nyang hana tamöng atawa hana geungui.''\nSaweub nyan, kamoe payah meukubah alamat IP-geuh keu meuparéksa. \nAlamat IP mungkén jingui lé padum-padum droe ureueng.\nMeunyoe droeneuh ureueng nyang hana tamöng nyan, tulông [[Special:UserLogin/signup|peugöt nan ureueng ngui]] atawa [[Special:UserLogin|tamöng log]] mangat meuteugah nibak bhah nyang hana meuphôm bak uroe la'én.",
+ "anontalkpagetext": "----''Nyoe nakeuh ôn marit ureueng ngui nyang hana tamöng atawa hana geungui.''\nSaweub nyan, kamoe payah meukubah alamat IP-geuh keu meuparéksa. \nAlamat IP mungkén jingui lé padum-padum droe ureueng.\nMeunyoe droeneuh ureueng nyang hana tamöng nyan, tulông [[Special:CreateAccount|peugöt nan ureueng ngui]] atawa [[Special:UserLogin|tamöng log]] mangat meuteugah nibak bhah nyang hana meuphôm bak uroe la'én.",
"noarticletext": "Hana naseukah jinoë lam laman nyoë.\nJi Droëneuh jeuët [[Special:Search/{{PAGENAME}}|neumita keu nan ôn nyoë]] bak ôn-ôn la’én, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} log nyang na hubôngan], atawa [{{fullurl:{{FULLPAGENAME}}|action=edit}} neu'andam ôn nyoë]</span>.",
"noarticletext-nopermission": "Hana asoë bak laman nyoë jinoë.\nDroëneuh jeuët [[Special:Search/{{PAGENAME}}|neumita keu nan ôn nyoë]] bak laman-laman la'én,\natawa <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} neumita log nyang na meuhubông]</span>, tapi Droëneuh hana idin keu neupeugöt laman nyoë",
"userpage-userdoesnotexist-view": "Ureueng ngui \"$1\" hana teudapeuta.",
"allpagesprefix": "Peuleumah laman ngön harah phôn:",
"allpages-hide-redirects": "Peusom peuninah",
"categories": "Dapeuta kawan",
- "special-categories-sort-count": "atôe meunurôt jumeulah",
- "special-categories-sort-abc": "atôe meunurôt seunurat",
"deletedcontributions": "Beuneuri nyang geusampôh",
"deletedcontributions-title": "Beuneuri nyang geusampôh",
"sp-deletedcontributions-contribs": "beuneuri",
"noname": "Ongeldige gebruikersnaam.",
"loginsuccesstitle": "Suksesvolle aanmelding",
"loginsuccess": "U is nou by {{SITENAME}} as \"$1\" ingeteken.",
- "nosuchuser": "Die gebruiker \"$1\" bestaan nie.\nGebruikersname is gevoelig vir hoofletters.\nMaak seker dit is reg gespel of [[Special:UserLogin/signup|skep 'n nuwe rekening]].",
+ "nosuchuser": "Die gebruiker \"$1\" bestaan nie.\nGebruikersname is gevoelig vir hoofletters.\nMaak seker dit is reg gespel of [[Special:CreateAccount|skep 'n nuwe rekening]].",
"nosuchusershort": "Daar is geen gebruikersnaam \"$1\" nie. Maak seker dit is reg gespel.",
"nouserspecified": "U moet 'n gebruikersnaam spesifiseer.",
"login-userblocked": "Hierdie gebruiker is geblokkeer.\nIntekening word verbied.",
"accmailtext": "'n Lukrake wagwoord vir [[User talk:$1|$1]] is na $2 gestuur.\n\nDie wagwoord vir hierdie nuwe gebruiker kan op die ''[[Special:ChangePassword|verander wagwoord]]''-bladsy verander word nadat ingeteken is.",
"newarticle": "(Nuut)",
"newarticletext": "Hierdie bladsy bestaan nie.\nTik iets in die invoerboks hier onder om 'n nuwe bladsy te skep. Meer inligting is op die [$1 hulpbladsy] beskikbaar.\nAs u per ongeluk hier uitgekom het, gebruik u blaaier se '''terug'''-knoppie.",
- "anontalkpagetext": "----''Hierdie is die besprekingsblad vir 'n anonieme gebruiker wat nog nie 'n gebruiker geskep het nie, of wat dit nie gebruik nie.\nDaarom moet ons sy/haar numeriese IP-adres vir identifikasie gebruik.\nSó 'n adres kan deur verskeie gebruikers gedeel word.\nIndien u 'n anonieme gebruiker is wat voel dat ontoepaslike kommentaar teen u gerig is, [[Special:UserLogin/signup|skep 'n gebruiker]] of [[Special:UserLogin|meld aan]] om verwarring met ander anonieme gebruikers te voorkom.''",
+ "anontalkpagetext": "----''Hierdie is die besprekingsblad vir 'n anonieme gebruiker wat nog nie 'n gebruiker geskep het nie, of wat dit nie gebruik nie.\nDaarom moet ons sy/haar numeriese IP-adres vir identifikasie gebruik.\nSó 'n adres kan deur verskeie gebruikers gedeel word.\nIndien u 'n anonieme gebruiker is wat voel dat ontoepaslike kommentaar teen u gerig is, [[Special:CreateAccount|skep 'n gebruiker]] of [[Special:UserLogin|meld aan]] om verwarring met ander anonieme gebruikers te voorkom.''",
"noarticletext": "Hierdie bladsy bevat geen teks nie.\nU kan [[Special:Search/{{PAGENAME}}|vir die bladsytitel in ander bladsye soek]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} die verwante logboeke deursoek]\nof [{{fullurl:{{FULLPAGENAME}}|action=edit}} hierdie bladsy wysig]</span>.",
"noarticletext-nopermission": "Hierdie bladsy bevat geen teks nie.\nU kan vir die term [[Special:Search/{{PAGENAME}}|in ander bladsye soek]] of\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} die verwante logboeke deursoek]</span>, maar u kan nie die bladsy skep nie.",
"missing-revision": "Die weergawe #$1 van die bladsy \"{{FULLPAGENAME}} bestaan nie.\n\nDit word meestal veroorsaak deur die volg van 'n verouderde verwysing na 'n bladsy wat verwyder is.\nMeer gegewens kan moontlik in die [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} skraplogboek] gevind word.",
"noname": "Nuk ke dhânë nofkë valide.",
"loginsuccesstitle": "Kyçje e suksesshme",
"loginsuccess": "'''Je kyçë në {{SITENAME}} si \"$1\".'''",
- "nosuchuser": "Nuk ka përdorues me emnin \"$1\".\nEmnat janë senzitiv në madhësi të germës.\nKontrollo drejtshkrimin ose [[Special:UserLogin/signup|krijo llogari]].",
+ "nosuchuser": "Nuk ka përdorues me emnin \"$1\".\nEmnat janë senzitiv në madhësi të germës.\nKontrollo drejtshkrimin ose [[Special:CreateAccount|krijo llogari]].",
"nosuchusershort": "Nuk ka përdorues me emnin \"$1\".\nKontrollo drejtshkrimin.",
"nouserspecified": "Duhesh me dhânë nji nofkë.",
"login-userblocked": "Ky përdorues është bllokuar. Identifikohu nuk lejohet",
"accmailtext": "Nji fjalëkalim i krijuem rastësisht për [[User talk:$1|$1]] u dërgue në $2.\n\nFjalëkalimi për këtë llogari mundet me u ndryshue në faqen ''[[Special:ChangePassword|ndrysho fjalëkalimin]]'' mbas kyçjes.",
"newarticle": "(I ri)",
"newarticletext": "Ke ndjekë nji vegëz për te nji faqe që nuk ekziston.\nMe krijue kët faqe, shkruej në kutinë ma poshtë (shih [$1 faqen e ndihmës] për ma shum udhzime).\nNëse ke hy këtu gabimisht, klikoje sustën '''mbrapa''' në shfletues.",
- "anontalkpagetext": "<em>Kjo është faqe diskutimi e një përdoruesi anonim, i cili nuk ka krijuar llogari, apo nuk e përdor atë.</em>\nPrandaj ne do të përdorim adresën numerike të IP së tij për ta identifikuar.\nAdresa IP mund të shfrytëzohet prej disa përdoruesve.\nNëse jeni përdorues anonim dhe keni përshtypjen se po ju drejtohen komente jorelevante, ju lutemi [[Special:UserLogin/signup|krijoni një llogari]] apo [[Special:UserLogin|identifikohuni]] për të ju shmangur ngatërrimev me përdorues të tjerë anonim.",
+ "anontalkpagetext": "<em>Kjo është faqe diskutimi e një përdoruesi anonim, i cili nuk ka krijuar llogari, apo nuk e përdor atë.</em>\nPrandaj ne do të përdorim adresën numerike të IP së tij për ta identifikuar.\nAdresa IP mund të shfrytëzohet prej disa përdoruesve.\nNëse jeni përdorues anonim dhe keni përshtypjen se po ju drejtohen komente jorelevante, ju lutemi [[Special:CreateAccount|krijoni një llogari]] apo [[Special:UserLogin|identifikohuni]] për të ju shmangur ngatërrimev me përdorues të tjerë anonim.",
"noarticletext": "Momentalisht nuk ka tekst në këtë faqe.\nJu mundeni [[Special:Search/{{PAGENAME}}|me kërkue këtë titull]] në faqe tjera,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} me kërkue në regjistrat tematikisht të afërm],\napo [{{fullurl:{{FULLPAGENAME}}|action=edit}} me redaktue këtë faqe]</span>.",
"userpage-userdoesnotexist": "Llogaria e përdoruesit \"<nowiki>$1</nowiki>\" nuk âsht regjistrue.\nJu lutemi kontrolloni nëse doni me krijue/redaktue këtë faqe.",
"clearyourcache": "'''Shenim - Mbas ruejtjes, ka mundësi që duheni me shmângë memorizimin në cache për me i pâ ndryshimet.'''\n'''Mozilla / Firefox / Safari:''' mbani ''Shift'' tue klikue në ''Reload'', ose trusni ''Ctrl-F5'' ose ''Ctrl-R'' (''Command-R'' në Mac);\n'''Konqueror: '''klikoni ''Reload'' ose trusni ''F5'';\n'''Opera:''' fshini cachein në ''Tools → Preferences'';\n'''Internet Explorer:''' mbani ''Ctrl'' tue klikue në ''Refresh,'' ose trusni ''Ctrl-F5''.",
"noname": "የተወሰነው ብዕር ስም ትክክለኛ አይደለም።",
"loginsuccesstitle": "መግባትዎ ተከናወነ!",
"loginsuccess": "እንደ «$1» ሆነው አሁን {{SITENAME}}ን ገብተዋል።",
- "nosuchuser": "«$1» የሚል ብዕር ስም አልተገኘም። አጻጻፉን ይመልከቱ ወይም [[Special:UserLogin/signup|አዲስ ብዕር ስም ያውጡ]]።",
+ "nosuchuser": "«$1» የሚል ብዕር ስም አልተገኘም። አጻጻፉን ይመልከቱ ወይም [[Special:CreateAccount|አዲስ ብዕር ስም ያውጡ]]።",
"nosuchusershort": "«$1» የሚል ብዕር ስም አልተገኘም። አጻጻፉን ይመልከቱ።",
"nouserspecified": "አንድ ብዕር ስም መጠቆም ያስፈልጋል።",
"login-userblocked": "ተጠቃሚው አሁን የታገደ ነው። መግባት አልተፈቀደም።",
"noname": "No ha escrito un nombre d'usuario correcto.",
"loginsuccesstitle": "S'ha identificato correctament",
"loginsuccess": "Ha encetato una sesión en {{SITENAME}} como \"$1\".",
- "nosuchuser": "No bi ha garra usuario clamato \"$1\".\nOs nombres d'usuario son sensibles a las mayusclas.\nComprebe si ha escrito bien o nombre u [[Special:UserLogin/signup|creye una nueva cuenta d'usuario]].",
+ "nosuchuser": "No bi ha garra usuario clamato \"$1\".\nOs nombres d'usuario son sensibles a las mayusclas.\nComprebe si ha escrito bien o nombre u [[Special:CreateAccount|creye una nueva cuenta d'usuario]].",
"nosuchusershort": "No bi ha garra usuario con o nombre \"$1\". Comprebe si o nombre ye bien escrito.",
"nouserspecified": "Ha d'escribir un nombre d'usuario.",
"login-userblocked": "Iste usuario ye bloqueyau. No se permite l'inicio de sesión.",
"accmailtext": "S'ha ninviato a $2 una clau ta [[User talk:$1|$1]] chenerata aliatoriament.\n\nA clau ta ista nueva cuenta la puet cambiar en a pachina ''[[Special:ChangePassword|Cambiar a clau]]'' dimpués d'haber dentrato en ella.",
"newarticle": "(Nuevo)",
"newarticletext": "Ha siguito un vinclo ta una pachina que encara no existe.\nTa creyar a pachina, prencipie a escribir en a caixa d'abaixo (mire-se l'[$1 aduya] ta más información).\nSi ye plegau por error, punche o botón \"enta zaga\" d'o suyo navegador.",
- "anontalkpagetext": "----''Ista ye a pachina de descusión d'un usuario anonimo que encara no ha creyato una cuenta, u no l'ha feito servir. Por ixo, hemos d'emplegar a suya adreza IP ta identificar-lo/a.\nDiferents usuarios pueden compartir una mesma adreza IP.\nSi vusté ye un usuario anonimo y creye que l'han escrito comentarios no relevants, [[Special:UserLogin/signup|creye una cuenta]] u [[Special:UserLogin/signup|identifique-se]] ta privar confusions futuras con atros usuarios anonimos.''",
+ "anontalkpagetext": "----''Ista ye a pachina de descusión d'un usuario anonimo que encara no ha creyato una cuenta, u no l'ha feito servir. Por ixo, hemos d'emplegar a suya adreza IP ta identificar-lo/a.\nDiferents usuarios pueden compartir una mesma adreza IP.\nSi vusté ye un usuario anonimo y creye que l'han escrito comentarios no relevants, [[Special:CreateAccount|creye una cuenta]] u [[Special:CreateAccount|identifique-se]] ta privar confusions futuras con atros usuarios anonimos.''",
"noarticletext": "Por agora no bi ha garra texto en ista pachina. Puet [[Special:Search/{{PAGENAME}}|mirar o títol d'ista pachina]] en atras pachinas, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mirar os rechistros relacionatos] u [{{fullurl:{{FULLPAGENAME}}|action=edit}} escribir ista pachina]</span>.",
"noarticletext-nopermission": "Por l'inte no i hai garra texto en ista pachina.\nPuede [[Special:Search/{{PAGENAME}}|mirar iste titol]] en atras pachinas,\nu bien <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mirar en os rechistros relacionatos]</span>, pero no tien permiso ta creyar ista pachina.",
"userpage-userdoesnotexist": "A cuenta d'usuario \"<nowiki>$1</nowiki>\" no ye rechistrada. Piense si quiere creyar u editar ista pachina.",
"noname": "Þū nafast gewriten gengne brūcendes naman.",
"loginsuccesstitle": "Inmeldung gesǣlde",
"loginsuccess": "'''Þu eart nū inmeldod tō {{SITENAME}} tō \"$1\".'''",
- "nosuchuser": "Þǣr nis nān brūcend þe hæfþ þone naman \"$1\".\nStafena micelnessa sind hefiga and ānlica on brūcendnamum.\nScēawa þīne wrītunge eft, oþþe [[Special:UserLogin/signup|sciepp nīwe reccinge]].",
+ "nosuchuser": "Þǣr nis nān brūcend þe hæfþ þone naman \"$1\".\nStafena micelnessa sind hefiga and ānlica on brūcendnamum.\nScēawa þīne wrītunge eft, oþþe [[Special:CreateAccount|sciepp nīwe reccinge]].",
"nosuchusershort": "Þǣr nis nān brūcend mid þǣm naman \"$1\". Scēawa þīne wrītunge.",
"nouserspecified": "Þū scealt wrītan brūcendes naman.",
"login-userblocked": "Þes brūcend is fortȳned. Inmeldung nis gelīfed.",
"Vinitutpal",
"아라",
"Samyo",
- "Macofe"
+ "Macofe",
+ "Matma Rex"
]
},
"tog-underline": " कड़ी अधोरेखित करना:",
"loginreqlink": "लॉग-इन",
"newarticle": "(नया)",
"newarticletext": "आपनॆ जे लेख चाहै छियै वू अखनी तलक लिखलॊ नै गेलॊ छै. इ लेख लिखै लेली नीचे टाइप करॊ. सहायता लेली [$1 ऐन्जां] क्लीक करॊ.\n\nजों आपनॆ यहां पर गलती सॆं आबी गेलॊ छियै तॆ आपनॊ ब्राउज़र कॆ बॅक (back) पर क्लीक करॊ.",
- "noarticletext": "\nHindi (hi)फ़िलहाल इ पन्ना पर कोनो सामग्री नै छै.\nआपन॑ अन्य पन्ना मं॑ [[Special:Search/{{PAGENAME}}|इ सामग्री के खोज]] कर॑ सकै छियै,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} संबंधित चिट्ठा मं॑ खोज कर॑ सकै छियै],\nया [{{fullurl:{{FULLPAGENAME}}|action=edit}} इ पन्ना क॑ संपादित कर॑ सक॑ छियै]</span>.",
+ "noarticletext": "फ़िलहाल ई पन्ना पर कोनो सामग्री नै छै.\nआपन॑ अन्य पन्ना मं॑ [[Special:Search/{{PAGENAME}}|ई सामग्री के खोज]] कर॑ सकै छियै,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} संबंधित चिट्ठा मं॑ खोज कर॑ सकै छियै],\nया [{{fullurl:{{FULLPAGENAME}}|action=edit}} इ पन्ना क॑ संपादित कर॑ सक॑ छियै]</span>.",
"noarticletext-nopermission": "\nफ़िलहाल इ पन्ना पर कोय सामग्री नै छै.\nआपने अन्य पन्ना म॑ [[Special:Search/{{PAGENAME}}|इ सामग्री केरऽ खोज]] कर॑ सकै छियै,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} संबंधित चिट्ठा मं॑ खोज कर॑ सकै छियै],\nया फेरू [{{fullurl:{{FULLPAGENAME}}|action=edit}} इ पन्ना क॑ संपादित कर॑ सकै छियै]</span>.",
"previewnote": "'''याद रखॊ, इ केवल एगॊ झलक छेकै आरू अभी तलक सुरक्षित नै करलॊ गेलॊ छै!'''",
"editing": "$1 केरऽ सम्पादन चली रहलऽ छै.",
"contributions": "{{GENDER:$1|सदस्य}} योगदान",
"contributions-title": "$1 लेली सदस्यॊ के योगदान",
"mycontris": "योगदान",
+ "anoncontribs": "योगदान",
"contribsub2": "$1 लेली ($2)",
"uctop": "(उपर)",
"month": "इ महिना स॑ (आरू पुरान॑):",
"revertmove": "पुरानॊ अवतरण पर लॆ चलॊ (रिवर्ट)",
"export": "पन्ना क॑ निर्यात करऽ",
"thumbnail-more": "बड़ा करऽ",
- "tooltip-pt-userpage": "आपन॑ के प्रयोक्ता पन्ना",
- "tooltip-pt-mytalk": "आपन॑ के वार्ता पन्ना",
- "tooltip-pt-preferences": "आपन॑ के वरीयता",
+ "tooltip-pt-userpage": "{{GENDER:|आपन॑ के प्रयोक्ता}} पन्ना",
+ "tooltip-pt-mytalk": "{{GENDER:|आपन॑ के}} वार्ता पृष्ठ",
+ "tooltip-pt-preferences": "{{GENDER:|आपन॑ के}} वरीयता",
"tooltip-pt-watchlist": "आपन॑ के ध्यान देलऽ पन्ना के सूची",
- "tooltip-pt-mycontris": "आपन॑ के योगदानऽ के सूची",
+ "tooltip-pt-mycontris": "{{GENDER:|आपन॑ के}} योगदान",
"tooltip-pt-login": "आपन॑ सं॑ सत्रारंभ करै के गुज़ारिश छै; लेकिन इ अनिवार्य नै छै.",
"tooltip-pt-logout": "सत्रांत",
"tooltip-pt-createaccount": "हमरऽ सुझाव छै कि तोंय खाता बनाबऽ आरू लॉगिन करऽ, हालाँकि अंदर प्रवेश करै लेली इ अनिवार्य नै छै",
"tooltip-t-recentchangeslinked": "इ पन्ना स॑ जुड़लऽ पन्ना पर होलऽ हाल केरऽ बदलाव",
"tooltip-feed-rss": "इ पन्ना के आरएसएस फ़ीड",
"tooltip-feed-atom": "इ पन्ना के अणु फ़ीड",
- "tooltip-t-contributions": "इ सदस्य के योगदान केरऽ सूची देखियै",
+ "tooltip-t-contributions": "{{GENDER:$1| केरऽ ई साल}} म॑ सदस्य के योगदान केरऽ सूची देखियै",
"tooltip-t-emailuser": "इस सदस्य कॆ इमेल भेजॊ",
"tooltip-t-upload": "फाईल लादऽ (अपलोड )",
"tooltip-t-specialpages": "ख़ास पन्ना केरऽ सूची",
"noname": "لم تحدد اسم مستخدم صحيح.",
"loginsuccesstitle": "تم الدخول",
"loginsuccess": "'''لقد سجلت الدخول ل{{SITENAME}} باسم \"$1\".'''",
- "nosuchuser": "لا يوجد مستخدم بالاسم \"$1\".\nأسماء المستخدمين حساسة لحالة الحروف.\nتأكد من إملاء الاسم، أو [[Special:UserLogin/signup|قم بإنشاء حساب جديد]].",
+ "nosuchuser": "لا يوجد مستخدم بالاسم \"$1\".\nأسماء المستخدمين حساسة لحالة الحروف.\nتأكد من إملاء الاسم، أو [[Special:CreateAccount|قم بإنشاء حساب جديد]].",
"nosuchusershort": "لا يوجد مستخدم باسم $1\".\nتأكد من إملاء الاسم.",
"nouserspecified": "يجب عليك تحديد اسم مستخدم.",
"login-userblocked": "هذا المستخدم ممنوع. لا يسمح بالولوج.",
"createacct-another-realname-tip": "الاسم الحقيقي اختياري.\nإذا اخترت توفيره فسيستخدم لنسبة عمل المستخدم إليه.",
"pt-login": "دخول",
"pt-login-button": "دخول",
+ "pt-login-continue-button": "مواصلة تسجيل الدخول",
"pt-createaccount": "إنشاء حساب",
"pt-userlogout": "خروج",
"php-mail-error-unknown": "خطأ غير معروف في وظيفة البريد PHP's mail()",
"botpasswords-no-provider": "BotPasswordsSessionProvider غير متاح.",
"botpasswords-restriction-failed": "قيود كلمة مرور البوت تمنع هذا الولوج.",
"resetpass_forbidden": "كلمات السر لا يمكن تغييرها",
+ "resetpass_forbidden-reason": "لا يمكن تغيير كلمة المرور: $1",
"resetpass-no-info": "يجب أن تكون مسجل الدخول للوصول إلى هذه الصفحة مباشرة.",
"resetpass-submit-loggedin": "تغيير كلمة السر",
"resetpass-submit-cancel": "إلغاء",
"passwordreset-emailsentusername": "إذا كان هناك عنوان بريد إلكتروني مرتبط بهذا المستخدم، ثم سيتم إرسال بريد إلكتروني لإعادة تعيين كلمة السر.",
"passwordreset-emailsent-capture": "أُرسل بريد إلكتروني لإعادة ضبط كلمة السر، وهو معروض بالأسفل.",
"passwordreset-emailerror-capture": "تم توليد رسالة بريد إلكتروني لتصفير كلمة السر نصّه التالي، إلا أنه تعذّر إرسال الرّسالة إلى {{GENDER:$2|المستخدم|المستخدمة}}: $1",
+ "passwordreset-invalideamil": "عنوان بريد إلكتروني غير صالح",
"changeemail": "تغيير أو إزالة عنوان البريد الإلكتروني",
"changeemail-header": "إكمال هذا النموذج لتغيير عنوان البريد الإلكتروني الخاص بك. إذا كنت ترغب في إزالة جمعية أي عنوان البريد الإلكتروني من حسابك، وترك الفراغ عنوان البريد الإلكتروني الجديد عند تقديم النموذج",
"changeemail-passwordrequired": "تحتاج إلى إدخال كلمة السر الخاصة بك لتأكيد هذا التغيير.",
"accmailtext": "أُرسِلت كلمة سر مولدة عشوائيا ل[[User talk:$1|$1]] إلى $2. يمكن تغييرها في صفحة ''[[Special:ChangePassword|تغيير كلمة السر]]'' بعد تسجيل الدخول.",
"newarticle": "(جديد)",
"newarticletext": "لقد تبعت وصلة لصفحة لم يتم إنشائها بعد.\nلإنشاء هذه الصفحة ابدأ الكتابة في الصندوق بالأسفل (انظر في [$1 صفحة المساعدة] للمزيد من المعلومات).\nإذا كانت زيارتك لهذه الصفحة بالخطأ، اضغط على زر ''رجوع'' في متصفح الإنترنت لديك.",
- "anontalkpagetext": "----''هذه صفحة نقاش لمستخدم مجهول لم يقم بإنشاء حساب بعد أو لا يستعمل ذلك الحساب.\nلذا فيجب علينا استعمال رقم الأيبي للتعرف عليه/عليها.\nمثل هذا العنوان يمكن أن يشترك فيه عدة مستخدمين.\nلو كنت مستخدما مجهولا وتشعر بأن تعليقات لا تخصك تم توجيهها إليك، من فضلك [[Special:UserLogin/signup|أنشئ حسابا]] أو [[Special:UserLogin|سجل الدخول]] لتجنب الارتباك المستقبلي مع مستخدمين مجهولين آخرين.''",
- "noarticletext": "لا يوجد حاليا أي نص في هذه الصفحة.\nيمكنك [[Special:Search/{{PAGENAME}}|البحث عن عنوان هذه الصفحة]] في الصفحات الأخرى،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} البحث في السجلات المتعلقة]،\nأو [{{fullurl:{{FULLPAGENAME}}|action=edit}} تعديل هذه الصفحة]</span>.",
+ "anontalkpagetext": "----''هذه صفحة نقاش لمستخدم مجهول لم يقم بإنشاء حساب بعد أو لا يستعمل ذلك الحساب.\nلذا فيجب علينا استعمال رقم الأيبي للتعرف عليه/عليها.\nمثل هذا العنوان يمكن أن يشترك فيه عدة مستخدمين.\nلو كنت مستخدما مجهولا وتشعر بأن تعليقات لا تخصك تم توجيهها إليك، من فضلك [[Special:CreateAccount|أنشئ حسابا]] أو [[Special:UserLogin|سجل الدخول]] لتجنب الارتباك المستقبلي مع مستخدمين مجهولين آخرين.''",
+ "noarticletext": "الصفحة خالية. يمكنك [[Special:Search/{{PAGENAME}}|البحث عن عنوانها]] في الصفحات الأخرى أو\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} البحث في السجلات] (لتعرف إذا حذفت)،\nأو '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} إنشاؤها بنفسك]'''</span>.",
"noarticletext-nopermission": "لا يوجد حاليا أي نص في هذه الصفحة.\nيمكنك [[Special:Search/{{PAGENAME}}|البحث عن عنوان هذه الصفحة]] في الصفحات الأخرى، أو <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} البحث في السجلات المتعلقة بها]</span>، لكنك لست مخولاً لإنشاء هذه الصفحة.",
"missing-revision": "المراجعة #$1 من الصفحة المسماة \"{{FULLPAGENAME}}\" غير موجودة.\n\nهذا يحدث عادة عن طريق اتباع وصلة تاريخ قديمة لصفحة تم حذفها.\nالتفاصيل يمكن إيجادها في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].",
"userpage-userdoesnotexist": "حساب المستخدم \"<nowiki>$1</nowiki>\" غير مسجل.\nمن فضلك تأكد أنك تريد إنشاء/تعديل هذه الصفحة.",
"rollback": "استرجاع التعديلات",
"rollbacklink": "استرجع",
"rollbacklinkcount": "استرجع {{PLURAL:$1|لا تعديلات|تعديلا واحدا|تعديلين|$1 تعديلات|$1 تعديلاً|تعديل}}",
- "rollbacklinkcount-morethan": "استرجاع أكثر من {{PLURAL:$1||تعديل|تعديلين|$1 تعديلات|$1 تعديلاً|$1 تعديل}}",
+ "rollbacklinkcount-morethan": "استرجاع أكثر من {{PLURAL:$1|تعديل|تعديل|تعديلين|$1 تعديلات|$1 تعديلاً|$1 تعديل}}",
"rollbackfailed": "لم ينجح الاسترجاع",
"cantrollback": "لم يمكن استرجاع التعديل؛\nآخر مساهم هو المؤلف الوحيد لهذه الصفحة.",
"alreadyrolled": "لم يمكن استرجاع آخر تعديل ل[[$1]] بواسطة [[User:$2|$2]] ([[User talk:$2|نقاش]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]])؛\nشخص آخر عدل أو استرجع الصفحة بالفعل.\n\nآخر تعديل كان بواسطة [[User:$3|$3]] ([[User talk:$3|نقاش]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"watchlistedit-raw-done": "قائمة مراقبتك تم تحديثها.",
"watchlistedit-raw-added": "تمت إضافة {{PLURAL:$1||عنوان واحد|عنوانين|$1 عناوين|$1 عنوانا|$1 عنوان}}:",
"watchlistedit-raw-removed": "تمت إزالة {{PLURAL:$1||عنوان واحد|عنوانين|$1 عناوين|$1 عنوانا|$1 عنوان}}:",
- "watchlistedit-clear-title": "قائمة مراقبة ممسوحة",
+ "watchlistedit-clear-title": "امسح قائمة المراقبة",
"watchlistedit-clear-legend": "امسح قائمة المراقبة",
"watchlistedit-clear-explain": "ستحذف جميع الصفحات من قائمة مراقبتك",
"watchlistedit-clear-titles": "العناوين:",
"log-action-filter-delete-event": "حذف السجلات",
"log-action-filter-delete-revision": "حذف المراجعات",
"log-action-filter-import-interwiki": "استيراد عابر للويكي",
+ "log-action-filter-managetags-create": "إنشاء الوسوم",
+ "log-action-filter-managetags-delete": "حذف الوسوم",
"log-action-filter-newusers-autocreate": "إنشاء آلي",
"log-action-filter-newusers-byemail": "الإنشاء بكلمة مرور مرسلة عبر البريد الإلكتروني",
"log-action-filter-protect-protect": "حماية",
"log-action-filter-protect-unprotect": "رفع الحماية",
"log-action-filter-rights-rights": "تغيير يدوي",
"log-action-filter-upload-upload": "رفع جديد",
- "log-action-filter-upload-overwrite": "إعادة الرفع"
+ "log-action-filter-upload-overwrite": "إعادة الرفع",
+ "authmanager-email-label": "البريد الإلكتروني",
+ "authmanager-email-help": "عنوان البريد الإلكتروني",
+ "authmanager-realname-label": "الاسم الحقيقي",
+ "authmanager-realname-help": "الاسم الحقيقي للمستخدم",
+ "authmanager-provider-password": "توثيق مبني على كلمة المرور",
+ "authmanager-provider-password-domain": "توثيق مبني على كلمة المرور والنطاق",
+ "authmanager-provider-temporarypassword": "كلمة مرور مؤقتة",
+ "authprovider-resetpass-skip-label": "تخطى",
+ "authprovider-resetpass-skip-help": "تخطي إعادة تعيين كلمة المرور",
+ "cannotauth-not-allowed-title": "الإذن مرفوض",
+ "credentialsform-account": "اسم الحساب:",
+ "cannotlink-no-provider-title": "لا توجد حسابات قابلة للربط",
+ "cannotlink-no-provider": "لا توجد حسابات قابلة للربط",
+ "linkaccounts": "ربط الحسابات",
+ "linkaccounts-submit": "اربط الحسابات",
+ "unlinkaccounts": "إزالة ربط الحسابات"
}
"noname": "ما مدّيتش سميّت` مستعملي مقبولة.",
"loginsuccesstitle": "التوصال راه نجَح.",
"loginsuccess": "<strong>راك مسجّل داخل ف {{SITENAME}} ب`السميّة \"$1\".</strong>",
- "nosuchuser": "ما كاين حتا مستعملي ب`السميّة \"$1\".\nالسميّة تاع المستعملي راه حسّاسة ف تكسار الحروف (majuscule - minuscule).\nعاود أكّد على كيفاش كتبت الكلمات ولا [[Special:UserLogin/signup|اخلق حساب جديد]].",
+ "nosuchuser": "ما كاين حتا مستعملي ب`السميّة \"$1\".\nالسميّة تاع المستعملي راه حسّاسة ف تكسار الحروف (majuscule - minuscule).\nعاود أكّد على كيفاش كتبت الكلمات ولا [[Special:CreateAccount|اخلق حساب جديد]].",
"nosuchusershort": "ما كاين حتا مستعملي ب` السميّة \"$1\".\nأكّد على الكتيبة تاعك.",
"nouserspecified": "لازم لك تمدّ السميّة تاع المستعملي.",
"login-userblocked": "هاد السميّة تاع المستعملي راهي مطرودة. تسجال` الدخول ماشي مسموح.",
"accmailtext": "راهي انخلقت كلمت` سرّ مختارة على الزهَر لل مستعملي [[User talk:$1|$1]] و و انبعتت ل $2.\nتنجم تبدّلها فل پاجة<em>[[Special:ChangePassword|بدّل كلمت` السرّ]]</em> كي تتسجّل داخل.",
"newarticle": "(جديد)",
"newarticletext": "راك تبعت وصيلة لباجه لم ما تخدمتش بعد.\nباش تصنع هاذ الباجه ابدا الكتبه فالصندوق التحت (شوف في [$1 زياده باجه المساعده] لمعلومات).\nإذا كانت زيارتك لهاذ الباجه غلطه، ادرك على بوطون''ولى'' في نافيقاتور الإنترنت نتاعك.",
- "anontalkpagetext": "----''هاذ الباجة نقاش لمستخدم مجهول ما قامش بإنشاء حساب بعد و الا ما يستعملش ذاك الحساب.\nلذا لازم علينا استعمال رقم الأيبي باش نتعرفو عليه/عليها.\nمثل هذا العنوان يمكنلو يشترك فيه مستخدمين بزاف.\nإذا كنت مستخدم مجهول وتشعر بلي التعليقات ما تخصكش وصلتلك ، من فضلك [[Special:UserLogin/signup|أصنع حساب]] ولا [[Special:UserLogin|سجل الدخول]] باش تتجنب الارتباك فالمستقبل مع مستخدمين مجهولين آخرين.''",
+ "anontalkpagetext": "----''هاذ الباجة نقاش لمستخدم مجهول ما قامش بإنشاء حساب بعد و الا ما يستعملش ذاك الحساب.\nلذا لازم علينا استعمال رقم الأيبي باش نتعرفو عليه/عليها.\nمثل هذا العنوان يمكنلو يشترك فيه مستخدمين بزاف.\nإذا كنت مستخدم مجهول وتشعر بلي التعليقات ما تخصكش وصلتلك ، من فضلك [[Special:CreateAccount|أصنع حساب]] ولا [[Special:UserLogin|سجل الدخول]] باش تتجنب الارتباك فالمستقبل مع مستخدمين مجهولين آخرين.''",
"noarticletext": "حتا لضركا، ما كاين حتا نصّ ف هاذ الپاجة.\nتقدرو [[Special:Search/{{PAGENAME}}ترميو تفتيشة على هاذ العلوان]] فل پاجات لخرين,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} فتش فل عمليات المربوطة]\n ولا[{{fullurl:{{FULLPAGENAME}}|action=edit}} اصنع هاذ الپاجة]</span>.",
"noarticletext-nopermission": "لحد الساعه ما كانش حتى نص في هاذ الباجه.\nتقدرو [[Special:Search/{{PAGENAME}}|ترميو تفتيشه على هاذ العنوان]] فالباجات لخرين,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} فتش فالعمليات المربوطه]\nو إلا[{{fullurl:{{FULLPAGENAME}}|action=edit}} أصنع هاذ الباجه]</span>.",
"missing-revision": "المراجعة #$1 من الباجة اللي سموها \"{{FULLPAGENAME}}\" ما هيش كاينة.\n\nهذا يصرا فالعادة منين نتبعو وصيلة تاريخها قديم لباجة تنحات.\nالتفاصيل يمكن نصيبوها في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل المسح].",
"noname": "Ma kṫebṫiċ ċi smiyṫ l-mosṫeĥdim mqadda.",
"loginsuccesstitle": "dkhlti mzyan",
"loginsuccess": "Dĥelṫi mezyan fe {{SITENAME}} be smiyṫ \"$1\".",
- "nosuchuser": "ma kayn-ċ ċi mosṫĥdim smiṫo \"$1\".\ns-smiyyaṫ l-mosṫĥdimin raha ḫssasa lla caz (yĝni majuscule o-minuscule).\nċof l-kṫaḅa waċ hia hadik, wlla [[Special:UserLogin/signup|ṣayb ċi ḫisab jdid]].",
+ "nosuchuser": "ma kayn-ċ ċi mosṫĥdim smiṫo \"$1\".\ns-smiyyaṫ l-mosṫĥdimin raha ḫssasa lla caz (yĝni majuscule o-minuscule).\nċof l-kṫaḅa waċ hia hadik, wlla [[Special:CreateAccount|ṣayb ċi ḫisab jdid]].",
"nosuchusershort": "ma kayn-ċ ċi mosṫĥdim smiṫo \"$1\".\nċof l-kṫaḅa waċ hia hadik.",
"nouserspecified": "khassk tdkhl ism lmostakhdim.",
"login-userblocked": "Had l-mosṫeĥdim meḫbos. Konnéksyon memnoĝa.",
"accmailtext": "waḫd klmṫ s-srr mṣayba ĝċwa'iyyn ĝla ḫsab [[User talk:$1|$1]] ṫsiftaṫ l-$2.\n\nṫqdr ṫbddal klmṫ s-srr dialt had l-ḫisab j-jdid f-ṣṣfḫa ṫaĝ ''[[Special:ChangePassword|bḍḍel klmṫ s-srr]]'' mn bĝdmma ṫdĥol.",
"newarticle": "(jdid)",
"newarticletext": "Ṫbeĝṫi waḫed l-lyan li kayddi le waḫed ṣ-ṣefḫa li ṫṫemḫaṫ.\nBaċ ṫsayeb had ṣ-ṣefḫa, bda ṫekṫeb fe ṣ-ṣendoq li l-ṫeḫṫ (ċof ila bġiṫi [$1 ṣ-ṣefḫa de l-mosaĝada] le l-mazid de l-meĝlomaṫ).\nIla wṣelṫi hnaya ĝla ġefla, brek ĝla l-boton '''rjeĝ''' dyal n-navigaṫør internet dyalek.",
- "anontalkpagetext": "----''hada niqaċ ṫaĝ waḫd l-mosṫĥdim anonim lli mazal ma ṣayb-ċ ċi ḫisab, wlla ma kayĥdam-ċ bih.\ndakċċi ĝlaċ raḫna ĥddamin b-ĝonwan l-IP ṛ-ṛqmi baċ nĝaṛṛfoh.\nbḫal had ĝanawin l-IP ymkn iṫċarko fiha bẓẓaf dl-mosṫĥdimin.\nina konṫi ḫṫṫa nṫa mosṫĥdim anonim o-ḫssiṫi billa wjjah lik ċi ḫadd ċi ṫĝalq ġalat,[[Special:UserLogin/signup|ṣayb ċi ḫisab]] wlla [[Special:UserLogin|dĥol]] baċ ṫqil raṣk mn ay ġalat fl-mosṫqbal.''",
+ "anontalkpagetext": "----''hada niqaċ ṫaĝ waḫd l-mosṫĥdim anonim lli mazal ma ṣayb-ċ ċi ḫisab, wlla ma kayĥdam-ċ bih.\ndakċċi ĝlaċ raḫna ĥddamin b-ĝonwan l-IP ṛ-ṛqmi baċ nĝaṛṛfoh.\nbḫal had ĝanawin l-IP ymkn iṫċarko fiha bẓẓaf dl-mosṫĥdimin.\nina konṫi ḫṫṫa nṫa mosṫĥdim anonim o-ḫssiṫi billa wjjah lik ċi ḫadd ċi ṫĝalq ġalat,[[Special:CreateAccount|ṣayb ċi ḫisab]] wlla [[Special:UserLogin|dĥol]] baċ ṫqil raṣk mn ay ġalat fl-mosṫqbal.''",
"noarticletext": "Ma kayen fe had s-saĝa ḫṫa neṣ fe had ṣ-ṣefḫa.\nImken lek [[Special:Search/{{PAGENAME}}|ṫqelleb ĝla ṣefḫa be had l-ĝonwan]] fe ṣ-ṣefḫaṫ l-ĥrin,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ṫqelleb fe l-ĝamaliyaṫ l-mlaqyin]\nola [{{fullurl:{{FULLPAGENAME}}|action=edit}} ṫsayeb ṣ-ṣefḫa]</span>.",
"noarticletext-nopermission": "Ma kayen fe had s-saĝa ḫṫa neṣ fe had ṣ-ṣefḫa.\nImken lek [[Special:Search/{{PAGENAME}}|ṫqelleb ĝla ṣefḫa be had l-ĝonwan]] fe ṣ-ṣefḫaṫ l-ĥrin,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ṫqelleb fe l-ĝamaliyaṫ l-mlaqyin]\nola [{{fullurl:{{FULLPAGENAME}}|action=edit}} ṫsayeb ṣ-ṣefḫa]</span>.",
"userpage-userdoesnotexist": "ḫisab l-mosṫĥdim \"$1\" ma msjjal-ċ.\nċof waċ baġi ṫṣayb/ṫĝddal had ṣfḫa.",
"noname": "انت ما حددتش اسم يوزر صحيح.",
"loginsuccesstitle": "تم الدخول بشكل صحيح",
"loginsuccess": "'''دخولك {{SITENAME}} إتسجل بإسم \"$1\".'''",
- "nosuchuser": "مافيش يوزر اسمه \"$1\".\nاسامى اليوزر بتبقى حساسه لحالة الحرف.\nاتأكد من التهجيه, او [[Special:UserLogin/signup|افتح حساب جديد]].",
+ "nosuchuser": "مافيش يوزر اسمه \"$1\".\nاسامى اليوزر بتبقى حساسه لحالة الحرف.\nاتأكد من التهجيه, او [[Special:CreateAccount|افتح حساب جديد]].",
"nosuchusershort": "مافيش يوزر باسم $1\".\nاتاكد من تهجية الاسم.",
"nouserspecified": "لازم تحدد اسم يوزر.",
"login-userblocked": "اليوزر دا ممنوع من الدخول.",
"accmailtext": "الباسورد العشوائيه اللى اتعملت لـ[[User talk:$1|$1]] اتبعتت لـ $2.\n\nالباسورد بتاعة الحساب الجديد دا ممكن تتغير فى صفحة ''[[Special:ChangePassword|تغيير الباسورد]]'' بعد تسجيل الدخول.",
"newarticle": "(جديد)",
"newarticletext": "انت وصلت لصفحه مابتدتش لسه.\nعلشان تبتدى الصفحة ابتدى الكتابه فى الصندوق اللى تحت.\n(بص على [$1 صفحة المساعده] علشان معلومات اكتر)\nلو كانت زيارتك للصفحه دى بالغلط، دوس على زرار ''رجوع'' فى متصفح الإنترنت عندك.",
- "anontalkpagetext": "----'' صفحة النقاش دى بتاعة يوزر مجهول لسة ما فتحش لنفسه حساب أو عنده واحد بس ما بيستعملوش.\nعلشان كدا لازم تستعمل رقم الأيبى علشان تتعرف عليه/عليها.\nالعنوان دا ممكن اكتر من واحد يكونو بيستعملوه.\nلو انت يوزر مجهول و حاسس ان فى تعليقات بتتوجهلك مع انك مالكش دعوة بيها، من فضلك [[Special:UserLogin/signup|افتحلك حساب]] أو [[Special:UserLogin|سجل الدخول]] علشان تتجنب اللخبطة اللى ممكن تحصل فى المستقبل مع يوزرز مجهولين تانيين.''",
+ "anontalkpagetext": "----'' صفحة النقاش دى بتاعة يوزر مجهول لسة ما فتحش لنفسه حساب أو عنده واحد بس ما بيستعملوش.\nعلشان كدا لازم تستعمل رقم الأيبى علشان تتعرف عليه/عليها.\nالعنوان دا ممكن اكتر من واحد يكونو بيستعملوه.\nلو انت يوزر مجهول و حاسس ان فى تعليقات بتتوجهلك مع انك مالكش دعوة بيها، من فضلك [[Special:CreateAccount|افتحلك حساب]] أو [[Special:UserLogin|سجل الدخول]] علشان تتجنب اللخبطة اللى ممكن تحصل فى المستقبل مع يوزرز مجهولين تانيين.''",
"noarticletext": "مافيش دلوقتى اى نص فى الصفحه دى.\nممكن [[Special:Search/{{PAGENAME}}|تدور على عنوان الصفحه دى]] فى صفح تانيه,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} تدور فى السجلات اللى ليها علاقه],\nاو [{{fullurl:{{FULLPAGENAME}}|action=edit}} تعدل الصفحه دى]</span>.",
"noarticletext-nopermission": "مافيش دلوقتى اى نص فى الصفحه دى.\nممكن [[Special:Search/{{PAGENAME}}|تدور على عنوان الصفحه دى]] فى صفح تانيه,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} تدور فى السجلات اللى ليها علاقه],\nاو [{{fullurl:{{FULLPAGENAME}}|action=edit}} تعدل الصفحه دى]</span>.",
"userpage-userdoesnotexist": "حساب اليوزر \"<nowiki>$1</nowiki>\" مش متسجل. لو سمحت تشوف لو عايز تبتدي/تعدل الصفحة دي.",
"noname": "আপুনি বৈধ সদস্যনাম এটা দিয়া নাই।",
"loginsuccesstitle": "প্ৰৱেশ অনুমোদিত হ'ল",
"loginsuccess": "''' আপুনি {{SITENAME}}ত \"$1\" নামেৰে প্ৰৱেশ কৰিলে '''",
- "nosuchuser": "\"$1\" নামৰ কোনো সদস্য নাই।\nসদস্য নাম আকাৰ সংবেদনশীল।\nআপোনাৰ বানানতো চাওক, বা [[Special:UserLogin/signup|নতুন সদস্যভুক্তি কৰক]]।",
+ "nosuchuser": "\"$1\" নামৰ কোনো সদস্য নাই।\nসদস্য নাম আকাৰ সংবেদনশীল।\nআপোনাৰ বানানতো চাওক, বা [[Special:CreateAccount|নতুন সদস্যভুক্তি কৰক]]।",
"nosuchusershort": "\"$1\" এই নামৰ কোনো সদস্য নাই ।\nবানানতো আকৌ এবাৰ ভালদৰে চাওক ।",
"nouserspecified": "সদস্যনাম দিয়া বাধ্যতামূলক।",
"login-userblocked": "এই সদস্যক নিষেধ কৰা হৈছে। প্ৰৱেশ অসম্ভৱ।",
"accmailtext": "[[User talk:$1|$1]]-ৰ কাৰণে যাদৃচ্ছিকভাৱে উৎপন্ন কৰা গুপ্তশব্দ $2লৈ পঠোৱা হ'ল । \nএই নতুন একাউন্টত প্ৰৱেশ কৰি ''[[Special:ChangePassword|গুপ্তশব্দ সলনি কৰক]]'' পৃষ্ঠাখনত শব্দতো সলনি কৰি ল’ব পাৰিব ।",
"newarticle": "(নতুন)",
"newarticletext": "আপুনি বিচৰা প্ৰবন্ধটো বিচাৰি পোৱা নগ'ল।\n\nইচ্ছা কৰিলে আপুনিয়েই এই প্ৰবন্ধটো লিখা আৰম্ভ কৰিব পাৰে। [$1 ইয়াত] সহায় পাব।\n\nআপুনি যদি ইয়ালৈ ভুলতে আহিছে, তেনেহলে আপোনাৰ ব্ৰাওজাৰৰ '''BACK''' বুটামত টিপা মাৰক।",
- "anontalkpagetext": "----''এইখন আলোচনা পৃষ্ঠা বেনামী সদস্যৰ বাবে, যিয়ে নিজা একাউণ্ট সৃষ্টি কৰা নাই বা যিয়ে সেই একাউণ্ট ব্যৱহাৰ নকৰে।\nএতেকে আমি তেখেতসকলক আই-পি ঠিকনাৰে চিনাক্ত কৰিবলৈ বাধ্য।\nসেই একেই আই-পি ঠিকনা অনেকেই ব্যৱহাৰ কৰিব পাৰে।\nআপুনি যদি এজন বেনামী সদস্য আৰু যদি আপুনি অনুভৱ কৰে যে আপোনাৰ প্ৰতি অপ্ৰাসঙ্গিক মন্তব্য কৰা হৈছে, তেনেহলে আন বেনামী সদস্যৰ পৰা পৃথক কৰিবলৈ \n[[Special:UserLogin/signup|একাউন্ট সৃষ্টি কৰক]] বা [[Special:UserLogin|প্ৰৱেশ কৰক]] ।''",
+ "anontalkpagetext": "----''এইখন আলোচনা পৃষ্ঠা বেনামী সদস্যৰ বাবে, যিয়ে নিজা একাউণ্ট সৃষ্টি কৰা নাই বা যিয়ে সেই একাউণ্ট ব্যৱহাৰ নকৰে।\nএতেকে আমি তেখেতসকলক আই-পি ঠিকনাৰে চিনাক্ত কৰিবলৈ বাধ্য।\nসেই একেই আই-পি ঠিকনা অনেকেই ব্যৱহাৰ কৰিব পাৰে।\nআপুনি যদি এজন বেনামী সদস্য আৰু যদি আপুনি অনুভৱ কৰে যে আপোনাৰ প্ৰতি অপ্ৰাসঙ্গিক মন্তব্য কৰা হৈছে, তেনেহলে আন বেনামী সদস্যৰ পৰা পৃথক কৰিবলৈ \n[[Special:CreateAccount|একাউন্ট সৃষ্টি কৰক]] বা [[Special:UserLogin|প্ৰৱেশ কৰক]] ।''",
"noarticletext": "এই পৃষ্ঠাত বৰ্তমান কোনো পাঠ্য নাই ।\nআপুনি আন পৃষ্ঠাত [[Special:Search/{{PAGENAME}}| এই শিৰোনামা সন্ধান কৰিব পাৰে]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} সম্পৰ্কীয় অভিলেখ সন্ধান কৰিব পাৰে],\nবা [{{fullurl:{{FULLPAGENAME}}|action=edit}} এই পৃষ্ঠা সম্পাদনা কৰিব পাৰে]</span>",
"noarticletext-nopermission": "এই পৃষ্ঠাত বৰ্তমান কোনো পাঠ্য নাই।\nআপুনি আন পৃষ্ঠাত [[Special:Search/{{PAGENAME}}|এই শিৰোনামা সন্ধান কৰিব পাৰে]],\nবা <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} সম্পৰ্কীয় অভিলেখ সন্ধান কৰিব পাৰে]</span>, কিন্তু এই পৃষ্ঠা সৃষ্টি কৰিবলৈ আপোনাৰ অনুমতি নাই।",
"missing-revision": "\"{{FULLPAGENAME}}\" নামৰ পৃষ্ঠাৰ #$1 সংশোধনৰ অস্তিত্ব নাই।\n\nসাধাৰণতে বিলোপ কৰা এখন পৃষ্ঠাৰ পুৰণা ইতিহাস লিংক অনুসৰণ কৰিলে এনে হয়।\n[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} বিলোপন ল'গ]ত অধিক তথ্য পাব।",
"לערי ריינהארט",
"아라",
"Fitoschido",
- "Macofe"
+ "Macofe",
+ "Matma Rex"
]
},
"tog-underline": "Sorrayar enllaces:",
"tog-watchdefault": "Amestar les páxines y ficheros qu'edite a la mio llista de siguimientu",
"tog-watchmoves": "Amestar les páxines y ficheros que tresllade a la mio llista de siguimientu",
"tog-watchdeletion": "Amestar les páxines y ficheros que desanicie a la mio llista de siguimientu",
+ "tog-watchuploads": "Amestar los nuevos ficheros que xuba a la mio llista de siguimientu",
"tog-watchrollback": "Amestar les páxines onde fici una reversión a la mio llista de siguimientu",
"tog-minordefault": "Marcar toles ediciones como menores de mou predetermináu",
"tog-previewontop": "Amosar previsualización enantes del cuadru d'edición",
"tog-ccmeonemails": "Mandame copies de los correos qu'unvio a otros usuarios",
"tog-diffonly": "Nun amosar el conteníu de la páxina embaxo de les diferencies",
"tog-showhiddencats": "Amosar categoríes anubríes",
- "tog-norollbackdiff": "Desaniciar les diferencies depués de facer una restauración",
+ "tog-norollbackdiff": "Nun amosar diferencies depués de facer una restauración",
"tog-useeditwarning": "Avisame cuando salga d'una páxina d'edición con cambios ensin guardar",
"tog-prefershttps": "Usar siempre una conexón segura en aniciando sesión",
"underline-always": "Siempre",
"noname": "Nun conseñasti un nome d'usuariu válidu.",
"loginsuccesstitle": "Identificáu",
"loginsuccess": "'''Aniciasti sesión en {{SITENAME}} como «$1».'''",
- "nosuchuser": "Nun hai nengún usuariu col nome «$1».\nLos nomes d'usuariu distinguen mayúscules y minúscules.\nMira que tea bien escritu o [[Special:UserLogin/signup|crea una cuenta nueva]].",
+ "nosuchuser": "Nun hai nengún usuariu col nome «$1».\nLos nomes d'usuariu distinguen mayúscules y minúscules.\nMira que tea bien escritu o [[Special:CreateAccount|crea una cuenta nueva]].",
"nosuchusershort": "Nun hai nengún usuariu col nome «$1».\nMira que tea bien escritu.",
"nouserspecified": "Has d'especificar un nome d'usuariu.",
"login-userblocked": "Esti usuariu ta bloquiáu. Nun se permite l'aniciu de sesión.",
"minoredit": "Esta ye una edición menor",
"watchthis": "Vixilar esta páxina",
"savearticle": "Guardar la páxina",
+ "publishpage": "Publicar la páxina",
"preview": "Vista previa",
"showpreview": "Amosar previsualización",
"showdiff": "Amosar cambeos",
"accmailtext": "Unvióse a $2 una contraseña xenerada al debalu pal usuariu [[User talk:$1|$1]]. Pue camudase na páxina ''[[Special:ChangePassword|camudar contraseña]]'' depués d'aniciar sesión.",
"newarticle": "(Nuevu)",
"newarticletext": "Siguisti un enllaz a un artículu qu'inda nun esiste.\nPa crear la páxina, empecipia a escribir nel cuadru d'embaxo (mira la [$1 páxina d'ayuda] pa más información).\nSi llegasti equí por enquivocu, calca nel botón <strong>atrás</strong> del to restolador.",
- "anontalkpagetext": "----\n''Esta ye la páxina d'alderique pa un usuariu anónimu qu'inda nun creó una cuenta o que nun la usa.''\nPola mor d'ello ha usase la direición numbérica IP pa identificalu/la.\nTala IP pue compartise por varios usuarios.\nSi yes un usuariu anónimu y notes qu'hai comentarios irrelevantes empobinaos pa ti, por favor [[Special:UserLogin/signup|crea una cuenta]] o [[Special:UserLogin/signup|identifícate]] pa torgar futures confusiones con otros usuarios anónimos.",
+ "anontalkpagetext": "----\n''Esta ye la páxina d'alderique pa un usuariu anónimu qu'inda nun creó una cuenta o que nun la usa.''\nPola mor d'ello ha usase la direición numbérica IP pa identificalu/la.\nTala IP pue compartise por varios usuarios.\nSi yes un usuariu anónimu y notes qu'hai comentarios irrelevantes empobinaos pa ti, por favor [[Special:CreateAccount|crea una cuenta]] o [[Special:CreateAccount|identifícate]] pa torgar futures confusiones con otros usuarios anónimos.",
"noarticletext": "Nestos momentos nun hai testu nesta páxina.\nPuedes [[Special:Search/{{PAGENAME}}|buscar esti títulu de páxina]] n'otres páxines,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar los rexistros rellacionaos],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} crear esta páxina]</span>.",
"noarticletext-nopermission": "Nestos momentos nun hai testu nesta páxina.\nPue [[Special:Search/{{PAGENAME}}|buscar esti títulu de páxina]] n'otres páxines o <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar los rexistros rellacionaos]</span>, pero nun tiene permisu pa crear esta páxina.",
"missing-revision": "La revisión #$1 de la páxina llamada \"{{FULLPAGENAME}}\" nun esiste.\n\nDe vezu la causa d'esto ye siguir un enllaz antiguu del historial a una páxina que se desanició.\nSe puen alcontrar más detalles nel [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} rexistru de desanicios].",
"right-override-export-depth": "Esportar páxines, incluyendo páxines enllazaes fasta una fondura de 5",
"right-sendemail": "Unviar corréu a otros usuarios",
"right-passwordreset": "Ver los correos de reestablecimientu de conseña",
- "right-managechangetags": "Crear y desaniciar [[Special:Tags|etiquetes]] dende la base de datos",
+ "right-managechangetags": "Crear y (des)activar [[Special:Tags|etiquetes]]",
"right-applychangetags": "Aplicar [[Special:Tags|etiquetes]] xunto colos cambios propios",
"right-changetags": "Amestar y desaniciar [[Special:Tags|etiquetes]] arbitraries en revisiones individuales y entraes del rexistru",
+ "right-deletechangetags": "Desaniciar [[Special:Tags|etiquetes]] de la base de datos",
"grant-generic": "Conxuntu de drechos «$1»",
"grant-group-page-interaction": "Interactuar con páxines",
"grant-group-file-interaction": "Interactuar con multimedia",
"action-viewmyprivateinfo": "ver la so información privada",
"action-editmyprivateinfo": "editar la so información privada",
"action-editcontentmodel": "editar el modelu de conteníu d'una páxina",
- "action-managechangetags": "crear y desaniciar etiquetes dende la base de datos",
+ "action-managechangetags": "crear y (des)activar etiquetes",
"action-applychangetags": "aplicar etiquetes xunto colos cambios",
"action-changetags": "amestar y desaniciar etiquetes arbitraries en revisiones individuales y entraes del rexistru",
+ "action-deletechangetags": "desaniciar etiquetes de la base de datos",
"nchanges": "{{PLURAL:$1|un cambiu|$1 cambios}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|dende la última visita}}",
"enhancedrc-history": "historial",
"recentchangeslinked-page": "Nome de la páxina:",
"recentchangeslinked-to": "Amosar los cambios de les páxines qu'enllacen en cuenta de los de la páxina dada",
"recentchanges-page-added-to-category": "[[:$1]] amestóse a la categoría",
- "recentchanges-page-added-to-category-bundled": "[[:$1]] y [[Special:WhatLinksHere/$1|{{PLURAL:$2|otra páxina|otres $2 páxines}}]] amestaes a la categoría",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] amestada a la categoría [[Special:WhatLinksHere/$1|esta páxina ta incluyida dientro d'otres páxines]]",
"recentchanges-page-removed-from-category": "[[:$1]] desanicióse de la categoría",
- "recentchanges-page-removed-from-category-bundled": "[[:$1]] y [[Special:WhatLinksHere/$1|{{PLURAL:$2|otra páxina|otres $2 páxines}}]] desaniciaes de la categoría",
+ "recentchanges-page-removed-from-category-bundled": "[[:$1]] desaniciada de la categoría [[Special:WhatLinksHere/$1|esta páxina ta incluyida dientro d'otres páxines]]",
"autochange-username": "Cambiu automáticu de MediaWiki",
"upload": "Xubir ficheru",
"uploadbtn": "Xubir ficheru",
"upload-form-label-own-work": "Esti ye'l mio propiu trabayu",
"upload-form-label-infoform-categories": "Categoríes",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-own-work-message-local": "Confirmo que xubo esti ficheru siguiendo les condiciones de serviciu y les polítiques de llicencies de {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Si nun puedes xubir esti ficheru baxo les polítiques de {{SITENAME}}, zarra esti diálogu y prueba otru métodu.",
- "upload-form-label-not-own-work-local-local": "Quiciabes quieras probar tamién [[Special:Upload|la páxina predeterminada de xubíes]].",
- "upload-form-label-own-work-message-default": "Entiendo que toi xubiendo esti ficheru a un depósitu compartíu. Confirmo que toi faciéndolo cumpliendo les condiciones de serviciu y les polítiques de llicencies d'esi sitiu.",
- "upload-form-label-not-own-work-message-default": "Si nun puedes xubir esti ficheru baxo les polítiques del depósitu compartíu, zarra esti diálogu y prueba otru métodu.",
- "upload-form-label-not-own-work-local-default": "Tamién pué interesate usar [[Special:Upload|la páxina de carga de {{SITENAME}}]] si esti ficheru pué xubise allí baxo les sos polítiques.",
- "upload-form-label-own-work-message-shared": "Certifico que tengo los drechos d'autor d'esti ficheru, y aceuto irrevocablemente lliberalu a Wikimedia Commons baxo la llicencia [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], y aceuto les [https://wikimediafoundation.org/wiki/Terms_of_Use Condiciones d'usu].",
- "upload-form-label-not-own-work-message-shared": "Si nun tienes los drechos d'autor d'esti ficheru, o quieres lliberalu baxo una llicencia diferente, considera usar el [https://commons.wikimedia.org/wiki/Special:UploadWizard Asistente de carga en Commons Upload].",
- "upload-form-label-not-own-work-local-shared": "Tamién pué interesate usar [[Special:Upload|la páxina de carga de {{SITENAME}}]] si esti ficheru pué xubise allí baxo les sos polítiques.",
+ "upload-form-label-own-work-message-generic-local": "Confirmo que xubo esti ficheru siguiendo les condiciones de serviciu y les polítiques de llicencies de {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Si nun puedes xubir esti ficheru baxo les polítiques de {{SITENAME}}, zarra esti diálogu y prueba otru métodu.",
+ "upload-form-label-not-own-work-local-generic-local": "Quiciabes quieras probar tamién [[Special:Upload|la páxina predeterminada de xubíes]].",
+ "upload-form-label-own-work-message-generic-foreign": "Entiendo que toi xubiendo esti ficheru a un depósitu compartíu. Confirmo que toi faciéndolo cumpliendo les condiciones de serviciu y les polítiques de llicencies d'esi sitiu.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Si nun puedes xubir esti ficheru baxo les polítiques del depósitu compartíu, zarra esti diálogu y prueba otru métodu.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Tamién pué interesate usar [[Special:Upload|la páxina de carga de {{SITENAME}}]] si esti ficheru pué xubise allí baxo les sos polítiques.",
"backend-fail-stream": "Nun se pudo tresmitir el ficheru $1.",
"backend-fail-backup": "Nun se pudo facer copia de seguridá del ficheru $1.",
"backend-fail-notexists": "El ficheru $1 nun esiste.",
"changecontentmodel-success-text": "Cambióse'l tipu de conteníu de [[:$1]].",
"changecontentmodel-cannot-convert": "El conteníu de [[:$1]] nun puede convertise a un tipu de $2.",
"changecontentmodel-nodirectediting": "El modelu de conteníu $1 nun tien encontu pa edición direuta",
+ "changecontentmodel-emptymodels-title": "Nun hai modelos de conteníu disponibles",
+ "changecontentmodel-emptymodels-text": "El conteníu de [[:$1]] nun pue convertise a nengún tipu.",
"log-name-contentmodel": "Rexistru de cambios del modelu de conteníu",
"log-description-contentmodel": "Socesos rellacionaos colos modelos de conteníu d'una páxina",
"logentry-contentmodel-new": "$1 {{GENDER:$2|creó}} la páxina $3 usando un modelu de conteníu non predetermináu «$5»",
"lockdbsuccesstext": "Candóse la base de datos.\n<br />Alcuérdate de [[Special:UnlockDB|descandala]] depués d'acabar el so mantenimientu.",
"unlockdbsuccesstext": "La base de datos foi descandada.",
"lockfilenotwritable": "L'archivu de candáu de la base de datos nun ye escribible. Pa candar o descandar la base de datos esti tien que poder ser modificáu pol sirvidor.",
+ "databaselocked": "La base de datos yá ta bloquiada.",
"databasenotlocked": "La base de datos nun ta candada.",
"lockedbyandtime": "(por $1 el $2 a les $3)",
"move-page": "Treslladar $1",
"tooltip-ca-nstab-category": "Ver la páxina de categoría",
"tooltip-minoredit": "Marcar como una edición menor",
"tooltip-save": "Guardar los cambios",
+ "tooltip-publish": "Publicar los cambeos",
"tooltip-preview": "Vista previa de los cambios, ¡usa esto enantes de guardar!",
"tooltip-diff": "Amuesa los cambios que fixisti nel testu.",
"tooltip-compareselectedversions": "Ver les diferencies ente les dos revisiones seleicionaes d'esta páxina.",
"confirmemail_body_set": "Dalguién, vusté posiblemente, dende la IP $1, configuró el corréu de\nla cuenta \"$2\" a esta direición de corréu en {{SITENAME}}.\n\nPa confirmar qu'esta cuenta ye suya daveres y activar les funciones\nde corréu en {{SITENAME}}, abra esti enllaz nel navegador:\n\n$3\n\nSi la cuenta *nun* ye de so, siga esti enllaz pa encaboxar\nla confirmación de les señes de corréu electrónicu:\n\n$5\n\nEsti códigu de confirmación caducará el $4.",
"confirmemail_invalidated": "Confirmación de direición de corréu electrónicu encaboxada",
"invalidateemail": "Encaboxar confirmación de corréu electrónicu",
+ "notificationemail_subject_changed": "Camudó la dirección de corréu electrónicu rexistrada de {{SITENAME}}",
+ "notificationemail_subject_removed": "Desanicióse la dirección de corréu electrónicu rexistrada de {{SITENAME}}",
+ "notificationemail_body_changed": "Daquién, probablemente tu, dende la dirección IP $1,\ncamudó la dirección de corréu electrónicu de la cuenta \"$2\" a \"$3\" en {{SITENAME}}.\n\nSi nun fuisti tu, comunícate darréu con un alministrador del sitiu.",
+ "notificationemail_body_removed": "Daquién, probablemente tu, dende la dirección IP $1,\ndesanició la dirección de corréu electrónicu de la cuenta \"$2\" en {{SITENAME}}.\n\nSi nun fuisti tu, comunícate darréu con un alministrador del sitiu.",
"scarytranscludedisabled": "[La tresclusión interwiki ta desactivada]",
"scarytranscludefailed": "[Falló la recuperación de la plantía pa $1]",
"scarytranscludefailed-httpstatus": "[Falló la recuperación de la plantía pa $1: HTTP $2]",
"timezone-local": "Llocal",
"duplicate-defaultsort": "Avisu: La clave d'ordenación predeterminada \"$2\" anula la clave d'ordenación anterior \"$1\".",
"duplicate-displaytitle": "<strong>Avisu:</strong> El títulu a amosar \"$2\" anula el títulu anterior \"$1\".",
+ "restricted-displaytitle": "<strong>Atención:</strong> El títulu a amosar \"$1\" inoróse porque nun ye equivaliente al títulu real de la páxina.",
"invalid-indicator-name": "<strong>Error:</strong> L'atributu <code>name</code> de los indicadores d'estáu de la páxina nun pue tar baleru.",
"version": "Versión",
"version-extensions": "Estensiones instalaes",
"tags-delete-not-found": "La etiqueta «$1» nun esiste.",
"tags-delete-too-many-uses": "La etiqueta «$1» aplícase a más {{PLURAL:$2|d'una revisión|de $2 revisiones}}, lo que quier dicir que nun pue desaniciase.",
"tags-delete-warnings-after-delete": "Desanicióse la etiqueta «$1», pero {{PLURAL:$2|alcontróse'l siguiente avisu|alcontráronse los siguientes avisos}}:",
+ "tags-delete-no-permission": "Nun tienes permisu pa desaniciar etiquetes de cambiu.",
"tags-activate-title": "Activar etiqueta",
"tags-activate-question": "Tas a piques d'activar la etiqueta «$1».",
"tags-activate-reason": "Motivu:",
"feedback-useragent": "Axente d'usuariu:",
"searchsuggest-search": "Buscar",
"searchsuggest-containing": "que contien...",
+ "api-error-autoblocked": "La to dirección IP bloquióse automáticamente porque la usó un usuariu bloquiáu.",
"api-error-badaccess-groups": "Nun tienes permisu pa xubir ficheros a esta wiki.",
"api-error-badtoken": "Fallu internu: token incorreutu.",
+ "api-error-blocked": "Tas bloquiáu pa editar.",
"api-error-copyuploaddisabled": "Xubir d'una URL ta desactivao nesti sirvidor.",
"api-error-duplicate": "Yá hai {{PLURAL:$1|otru ficheru|otros ficheros}} nesti sitiu col mesmu conteníu.",
"api-error-duplicate-archive": "Había {{PLURAL:$1|otru ficheru|otros ficheros}} nesti sitiu col mesmu conteníu, pero se {{PLURAL:$1|desanició|desaniciaron}}.",
"api-error-nomodule": "Fallu internu: nun se configuró dengún módulu de xubíes.",
"api-error-ok-but-empty": "Fallu internu: nun hai respuesta del sirvidor.",
"api-error-overwrite": "Nun ta permitío sobroscribir un ficheru esistente.",
+ "api-error-ratelimited": "Tas tentando xubir más ficheros nun espaciu de tiempu más pequeñu del que permite esta wiki.\nTéntalo otra vuelta en dellos minutos.",
"api-error-stashfailed": "Fallu internu: el sirvidor nun pudo guardar el ficheru temporal.",
"api-error-publishfailed": "Fallu internu: el sirvidor nun pudo espublizar el ficheru temporal.",
"api-error-stasherror": "Hebo un error al xubir el ficheru al almacén.",
"sessionprovider-nocookies": "Les cookies puen tar desactivaes. Asegúrate de tener activaes les cookies y vuelve a principiar.",
"randomrootpage": "Páxina raíz al debalu",
"log-action-filter-block": "Tipu de bloquéu:",
+ "log-action-filter-contentmodel": "Tipu de cambéu de modelu de conteníu:",
"log-action-filter-delete": "Tipu de desaniciu:",
+ "log-action-filter-import": "Tipu d'importación:",
+ "log-action-filter-managetags": "Tipu d'acción d'alministración d'etiquetes:",
+ "log-action-filter-move": "Tipu de movimientu:",
+ "log-action-filter-newusers": "Tipu de creación de cuenta:",
"log-action-filter-patrol": "Tipu de patrulla:",
"log-action-filter-protect": "Tipu de proteición:",
+ "log-action-filter-rights": "Tipu de cambéu de permisos",
+ "log-action-filter-suppress": "Tipu de supresión",
"log-action-filter-upload": "Tipu de carga:",
"log-action-filter-all": "Too",
"log-action-filter-block-block": "Bloquéu",
"log-action-filter-block-reblock": "Cambiu de bloquéu",
"log-action-filter-block-unblock": "Desbloquéu",
+ "log-action-filter-contentmodel-change": "Cambéu de modelu de conteníu",
+ "log-action-filter-contentmodel-new": "Creación de páxina con modelu de conteníu non estándar",
"log-action-filter-delete-delete": "Desaniciu de páxines",
"log-action-filter-delete-restore": "Restauración de páxines",
"log-action-filter-delete-event": "Desaniciu de rexistros",
"log-action-filter-delete-revision": "Desaniciu de revisión",
+ "log-action-filter-import-interwiki": "Importación ente wikis",
+ "log-action-filter-import-upload": "Importar cargando XML",
+ "log-action-filter-managetags-create": "Creación d'etiquetes",
+ "log-action-filter-managetags-delete": "Desaniciu d'etiquetes",
+ "log-action-filter-managetags-activate": "Activación d'etiquetes",
+ "log-action-filter-managetags-deactivate": "Desactivación d'etiquetes",
+ "log-action-filter-move-move": "Treslladar ensin sobreescribir les redireiciones",
+ "log-action-filter-move-move_redir": "Treslladar sobreescribiendo les redireiciones",
+ "log-action-filter-newusers-create": "Creación por usuariu anónimu",
+ "log-action-filter-newusers-create2": "Creación por usuariu rexistráu",
+ "log-action-filter-newusers-autocreate": "Creación automática",
+ "log-action-filter-newusers-byemail": "Creación cola contraseña unviada per corréu",
"log-action-filter-patrol-patrol": "Patrulláu manual",
"log-action-filter-patrol-autopatrol": "Patrulláu automáticu",
"log-action-filter-protect-protect": "Proteición",
"log-action-filter-protect-modify": "Cambiu na proteición",
"log-action-filter-protect-unprotect": "Desproteición",
+ "log-action-filter-protect-move_prot": "Proteición treslladada",
+ "log-action-filter-rights-rights": "Cambéu manual",
+ "log-action-filter-rights-autopromote": "Cambéu automáticu",
+ "log-action-filter-suppress-event": "Supresión de rexistru",
+ "log-action-filter-suppress-revision": "Supresión de revisión",
+ "log-action-filter-suppress-delete": "Supresión de páxina",
+ "log-action-filter-suppress-block": "Supresión d'usuariu por bloquéu",
+ "log-action-filter-suppress-reblock": "Supresión d'usuariu por rebloquéu",
"log-action-filter-upload-upload": "Nueva carga",
"log-action-filter-upload-overwrite": "Recargar"
}
"noname": "Va favesikyolt gobazel.",
"loginsuccesstitle": "Pilkomodanhara.",
"loginsuccess": "Rin wetce « $1 » moe {{SITENAME}} til dogluyarakiraf.",
- "nosuchuser": "« $1 » favesik me krulder.\nSutera va favesikyolt gotir eltaykoranhafa.\nAgeltal va rinaf suteks oke [[Special:UserLogin/signup|pataredura]].",
+ "nosuchuser": "« $1 » favesik me krulder.\nSutera va favesikyolt gotir eltaykoranhafa.\nAgeltal va rinaf suteks oke [[Special:CreateAccount|pataredura]].",
"nosuchusershort": "Me tir favesik digis va « $1 » yolt. Va sutekaks ageltal.",
"nouserspecified": "Va favesikyolt gobazel !",
"login-userblocked": "Bat webesik tir elekayan. Dogluyara menovena.",
"noname": "आप सही सदस्यनाम नाइ दिहा गा है।",
"loginsuccesstitle": "लॉग इन होइ गवा",
"loginsuccess": "'''आप {{SITENAME}} में \"$1\" सदस्यनाम से लॉग इन होई {{GENDER:$1|चुके|चुकी|चुके}} हव।'''",
- "nosuchuser": "\"$1\" नावँ कय कवनो सदस्य नाइ है।\nसदस्यनावँ में लघु औ दीर्घ अक्षरन् से फ़रक परत है।\nआपन अक्षर जाँचा जाय, या [[Special:UserLogin/signup|नवाँ खाता खोला जाय]]।",
+ "nosuchuser": "\"$1\" नावँ कय कवनो सदस्य नाइ है।\nसदस्यनावँ में लघु औ दीर्घ अक्षरन् से फ़रक परत है।\nआपन अक्षर जाँचा जाय, या [[Special:CreateAccount|नवाँ खाता खोला जाय]]।",
"nosuchusershort": "\"$1\" नावँ कय कवनो सदस्य नाई है।\nकृपया आपन शब्द फिरसे जाँचा जाय।",
"nouserspecified": "सदस्यनावँ देब जरुरी है।",
"login-userblocked": "ई सदस्य प्रतिबन्धित है। सत्रारम्भ कय अनुमति नाई है।",
"accmailtext": "[[User talk:$1|$1]] कय लिए एक यंत्र जनित गुप्त कुंजी $2 कय भेज दिहा गा है। लॉगिन करेक बाद एका '''[[Special:ChangePassword|गुप्त कुंजी बदला जाय]]'' वाला पन्नन् पे बदल सका जात है।",
"newarticle": "(नँवा)",
"newarticletext": "आप अईसन पन्ना पे आवा गा है जवन अभीन तक नाई बनावा है।\nपन्ना बनावेक लिये नीचे कय बौक्स में पाठ लिखा जाय। ढेर जानकारी कय लिये [$1 सहायता पन्ना] देखा जाय।\nअगर आप हिँया गलती से आवा गा हैं तव आपन ब्राउज़र कय बैक ('''back''') बटन पे क्लिक करा जाय।",
- "anontalkpagetext": "----''ई बातचीत पन्ना उ बेनामी सदस्यन् कय खर्तीन होय जे या तव खाता नाई खोलें है या खाता कय प्रयोग नाइ करत हैं।\nइहिकै नाते वय लोगन कय पहिचान कय खर्तीन हम्मन कय वय लोगन कय आइ॰पी ठहर कय प्रयोग करेक परत है।\nआइ॰पी ठहर कयु सदस्यन् कय एक्कय होइ सकत है।\nयदि आप कवनो बेनामी सदस्य होआ जाय अव आप कय लागत है कि आप कय बारे में अप्रासंगिक टीका टिप्पणी कई गा है तव कृपया [[Special:UserLogin/signup|सदस्यता लिहा जाय]] या [[Special:UserLogin|सत्रारंभ करा जाय]] ताकि अउर बेनामी सदस्यन् में से आप कय अलग से पहिचान सका जाय।''",
+ "anontalkpagetext": "----''ई बातचीत पन्ना उ बेनामी सदस्यन् कय खर्तीन होय जे या तव खाता नाई खोलें है या खाता कय प्रयोग नाइ करत हैं।\nइहिकै नाते वय लोगन कय पहिचान कय खर्तीन हम्मन कय वय लोगन कय आइ॰पी ठहर कय प्रयोग करेक परत है।\nआइ॰पी ठहर कयु सदस्यन् कय एक्कय होइ सकत है।\nयदि आप कवनो बेनामी सदस्य होआ जाय अव आप कय लागत है कि आप कय बारे में अप्रासंगिक टीका टिप्पणी कई गा है तव कृपया [[Special:CreateAccount|सदस्यता लिहा जाय]] या [[Special:UserLogin|सत्रारंभ करा जाय]] ताकि अउर बेनामी सदस्यन् में से आप कय अलग से पहिचान सका जाय।''",
"noarticletext": "अभीन इ पन्ना पे कवनो सामग्री नाई है।\nआप अउर पन्नन् में [[Special:Search/{{PAGENAME}}|इ शीर्षक कय खोज]] कई सका जात है,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} सम्बन्धित लॉग खोज सका जात है],\nया इस पृष्ठ को [{{fullurl:{{FULLPAGENAME}}|action=edit}} सम्पादित] कर सकते हैं</span>।",
"noarticletext-nopermission": "अभीन इ पन्ना पे कवनो चिज नाई है।\nआप अउर पन्नन् में [[Special:Search/{{PAGENAME}}|इ शीर्षक कय खोज]] कई सका जात है,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} से सम्बन्धित लॉग खोज सका जात है] </span>लेकिन आप कय इ पन्ना बनावे कय अनुमति नाई है ।",
"missing-revision": "\"{{FULLPAGENAME}}\" पन्ना कय अवतरण #$1 नाई है।\n\nखास कइकै ई एकठु मेटावल पन्ना कय पुरान लिंक पे क्लिक करय से होत है।\nढेर जानकारी कय खर्तिन आप [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} हटावे कय लॉग] देख सका जात है।",
"noname": "Siz mövcud olan istifadəçi adı daxil etməmisiniz.",
"loginsuccesstitle": "Daxil oldunuz",
"loginsuccess": "'''\"$1\" adı ilə sistemə daxil oldunuz.'''",
- "nosuchuser": "\"$1\" adlı istifadəçi mövcud deyil.\nİstifadəçi adları hərflərin böyük və ya kiçik olmasına həssasdırlar.\nDüzgün yazdığınıza əmin olun, yaxud [[Special:UserLogin/signup|yeni hesab açın]].",
+ "nosuchuser": "\"$1\" adlı istifadəçi mövcud deyil.\nİstifadəçi adları hərflərin böyük və ya kiçik olmasına həssasdırlar.\nDüzgün yazdığınıza əmin olun, yaxud [[Special:CreateAccount|yeni hesab açın]].",
"nosuchusershort": "\"$1\" adında istifadəçi mövcud deyil.\nDüzgün yazdığına əmin ol.",
"nouserspecified": "İstifadəçi adı daxil etməlisiniz.",
"login-userblocked": "Bu istifadəçi bloklanıb. Sistemə giriş üçün icazə verilmir.",
"accmailtext": "[[User talk:$1|$1]] üçün təsadüfi yolla yaradılmış parol $2 ünvanına göndərildi.\nHesabınıza daxil olduqdan sonra, parolunuzu ''[[Special:ChangePassword|parolu dəyiş]]'' səhifəsində dəyişdirə bilərsiniz.",
"newarticle": "(Yeni)",
"newarticletext": "Mövcud olmayan səhifəyə olan keçidi izlədiniz. Aşağıdakı sahəyə məzmununu yazaraq bu səhifəni '''siz''' yarada bilərsiniz. (əlavə məlumat üçün [$1 kömək səhifəsinə] baxın). Əgər bu səhifəyə səhvən gəlmisinizsə sadəcə olaraq brauzerin '''geri''' düyməsinə vurun.",
- "anontalkpagetext": "----''Bu səhifə qeydiyyatdan keçməmiş və ya daxil olmamış anonim istifadəçiyə aid müzakirə səhifəsidir.\nOna görə bu istifadəçini rəqəmlərdən ibarət IP ünvanı ilə müəyyən etmək məcburiyyətindəyik.\nBelə IP ünvan bir neçə fərd tərəfindən istifadədə ola bilər.\nƏgər siz anonim istifadəçisinizsə və bu mesajın sizə aid olmadığını düşünürsünüzsə, onda [[Special:UserLogin/signup|qeydiyyatdan keçin]] və ya [[Special:UserLogin|daxi olun]].''",
+ "anontalkpagetext": "----''Bu səhifə qeydiyyatdan keçməmiş və ya daxil olmamış anonim istifadəçiyə aid müzakirə səhifəsidir.\nOna görə bu istifadəçini rəqəmlərdən ibarət IP ünvanı ilə müəyyən etmək məcburiyyətindəyik.\nBelə IP ünvan bir neçə fərd tərəfindən istifadədə ola bilər.\nƏgər siz anonim istifadəçisinizsə və bu mesajın sizə aid olmadığını düşünürsünüzsə, onda [[Special:CreateAccount|qeydiyyatdan keçin]] və ya [[Special:UserLogin|daxi olun]].''",
"noarticletext": "Hal-hazırda bu səhifə boşdur. Başqa səhifələrdə eyni adda səhifəni [[Special:Search/{{PAGENAME}}| axtara]], əlaqəli qeydlərə\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} baxa] və ya səhifəni [{{fullurl:{{FULLPAGENAME}}|action=edit}} redaktə]</span> edə bilərsiniz.",
"noarticletext-nopermission": "Hal-hazırda bu səhifə boşdur. Başqa səhifələrdə eyni adlı səhifəni [[Special:Search/{{PAGENAME}}| axtara]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} əlaqəli qeydlərə baxa] və ya səhifəni [{{fullurl:{{FULLPAGENAME}}|action=edit}} redaktə edə bilərsiniz]</span>, lakin sizin bu məqaləni yaratmaq hüququnuz yoxdur.",
"userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" istifadəçi adı qeydiyyata alınmayıb.\nƏgər siz bu səhifəni yaratmaq/redaktə etmək istəyirsinizsə, xahiş edirik bunu yoxlayın.",
"Sadiqr",
"Mjbmr",
"Alp Er Tunqa",
- "Matma Rex"
+ "Matma Rex",
+ "Ilğım"
]
},
"tog-underline": "باغلانتیلارین آلتینی خطله:",
"tog-hidepatrolled": "سوْن دییشیکلیکلرده نظارتلنمیش دَییشیکلیکلری گیزلت",
"tog-newpageshidepatrolled": "یوْخلانمیش صفحهلری یئنی صفحهلر لیستیندن گیزلت",
"tog-extendwatchlist": "ایزلهدیکلری، یالنیز یئنیلر اۆچون یوْخ، بۆتون دییشیکلیکلری گؤرستمک اۆچون، گنیشلندیر.",
- "tog-usenewrc": "دَییشیکلیکلری سوْن دَییشیکلیکلر صفحهسینده ایزلهدیکلر صفحهسینده گروپلا (جاوااسکریپت گرکدیر)",
+ "tog-usenewrc": "دَییشیکلیکلری سوْن دَییشیکلیکلر صفحهسینده ایزلهدیکلر صفحهسینده قروپلا (جاوااسکریپت گرکدیر)",
"tog-numberheadings": "باشلیقلاری اوْتوماتیک نۆمرهله",
- "tog-showtoolbar": "دَییشدیرمک آراج-چۇبوغونو گؤرست",
+ "tog-showtoolbar": "دَییشدیرمه آراج-چۇبوغونو گؤستر",
"tog-editondblclick": "صفحهلری ایکی کیلیکده دَییشدیر",
"tog-editsectiononrightclick": "بؤلوملرین دَییشدیرمهسینی، باشلیقلارین اۆستونده ساغکلیک ائتمکله ایجازه وئر",
"tog-watchcreations": "ياراتدیغیم صفحهلری و يۆکلهدیگیم فايللاری، ایزلهدیکلریمه آرتیر",
"tog-watchdefault": "دَییشدیردیگیم صفحهلری و فايللاری، ایزلهدیکلریمه آرتیر",
"tog-watchmoves": "داشیدیغیم صفحهلری و فايللاری ایزلهدیکلریمه آرتیر",
"tog-watchdeletion": "سیلدیگیم صفحهلری و فايللاری ایزلهدیکلریمه آرتیر",
- "tog-watchrollback": "قایتاریلمیش صفحه لری ایزلدیکلریمه آرتیر",
- "tog-minordefault": "دفالت اوْلاراق، بۆتون دَییشدیرمهلری کیچیک کیمی علامتله",
- "tog-previewontop": "اؤÙ\86â\80\8cگؤسترÛ\8cØ´Û\8cØ\8c Ù\8aازÙ\85اÙ\82 Ù\82Û\87تÙ\88سÙ\88Ù\86داÙ\86 Ù\82اباÙ\82 گؤرست",
- "tog-previewonfirst": "اÛ\8cÙ\84Ú© دÙ\8eÛ\8cÛ\8cشدÛ\8cرÙ\85Ù\87â\80\8cدÙ\87 اؤÙ\86â\80\8cگؤسترÛ\8cØ´Û\8c گؤرست",
- "tog-enotifwatchlistpages": "اÛ\8cزÙ\84Ù\87â\80\8cدÛ\8cÚ©Ù\84رÛ\8cÙ\85â\80\8cدÙ\87 اÙ\88Ù\84اÙ\86 بÛ\8cر صÙ\81ØÙ\87 Û\8cا Ù\81اÛ\8cÙ\84 دÙ\8eÛ\8cÛ\8cشدÛ\8cرÛ\8cÙ\84Ù\86â\80\8cدÙ\87Ø\8c Ù\85Ù\86Ù\87 اÛ\8cÙ\85یل گؤندر",
- "tog-enotifusertalkpages": "دانیشیق صحیفهم دَییشدیریلنده منه ایمیل گؤندر",
- "tog-enotifminoredits": "صحیفهلرده و فایللاردا کیچیک دَییشیکلیکلر اولسا دا منه ایمیل گؤندر",
- "tog-enotifrevealaddr": "منیم ایمیل آدرسیمی بیلدیریش ایمیللرینده گؤستر",
- "tog-shownumberswatching": "گؤزلهین ایستیفادهچیلرین سایینی گؤستر",
+ "tog-watchrollback": "قایتاریلمیش صفحهلری ایزلهدیکلریمه آرتیر",
+ "tog-minordefault": "دیفالت اوْلاراق، بۆتون دَییشدیرمهلری کیچیک کیمی علامتله",
+ "tog-previewontop": "اؤÙ\86â\80\8cگؤسترÛ\8cØ´Û\8cØ\8c Ù\8aازÙ\85اÙ\82 Ù\82Û\87تÙ\88سÙ\88Ù\86داÙ\86 Ù\82اباÙ\82 گؤستر",
+ "tog-previewonfirst": "اÛ\8cÙ\84Ú© دÙ\8eÛ\8cÛ\8cشدÛ\8cرÙ\85Ù\87â\80\8cدÙ\87 اؤÙ\86â\80\8cگؤسترÛ\8cØ´Û\8c گؤستر",
+ "tog-enotifwatchlistpages": "اÛ\8cزÙ\84Ù\87â\80\8cدÛ\8cÚ©Ù\84رÛ\8cÙ\85â\80\8cدÙ\87 اÙ\88Ù\92Ù\84اÙ\86 بÛ\8cر صÙ\81ØÙ\87 Ù\88 Û\8cا Ù\81اÛ\8cÙ\84 دÙ\8eÛ\8cÛ\8cشدÛ\8cرÛ\8cÙ\84Ù\86دÙ\87Ø\8c Ù\85Ù\86Ù\87 اÛ\8cÙ\85ئیل گؤندر",
+ "tog-enotifusertalkpages": "دانیشیق صفحهم دَییشدیریلنده منه ایمئیل گؤندر",
+ "tog-enotifminoredits": "صفحهلرده و فایللاردا کیچیک دَییشیکلیکلر اوْلسا دا منه ایمئیل گؤندر",
+ "tog-enotifrevealaddr": "منیم ایمئیل آدرسیمی بیلدیریش ایمئیللرینده گؤستر",
+ "tog-shownumberswatching": "گؤزلهین ایستیفادهچیلرین ساییسینی گؤستر",
"tog-oldsig": "ایندیکی ایمضا:",
"tog-fancysig": "ایمضانی ویکی-متن کیمی نظره آل (اوْتوماتیک باغلانتیسیز)",
"tog-uselivepreview": "دیری اؤنگؤستریش ایشلت (تِست مرحلهسینده)",
- "tog-forceeditsummary": "دَییشیکلیک قیساسی بوْش قالاندا منه بیلیندیر",
+ "tog-forceeditsummary": "دَییشیکلیک قیساسی بوْش قالمیشسا منه بیلیندیر",
"tog-watchlisthideown": "منیم دَییشیکلیکلریمی ایزلهدیکلردن گیزلت",
"tog-watchlisthidebots": "بوْت دَییشیکلیکلرینی ایزلهدیکلردن گیزلت",
"tog-watchlisthideminor": "کیچیک دَییشیکلیکلری ایزلهدیکلردن گیزلت",
- "tog-watchlisthideliu": "گیرمیش ایشلدنلرین دَییشیکلیکلرینی ایزلهدیکلردن گیزلت",
+ "tog-watchlisthideliu": "گیریش ائتمیش ایشلدنلرین دَییشیکلیکلرینی ایزلهدیکلردن گیزلت",
"tog-watchlisthideanons": "تانینمامیش ایشلدنلرین دَییشیکلیکلرینی ایزلهدیکلردن گیزلت",
"tog-watchlisthidepatrolled": "نظارتلنمیش دَییشیکلیکلری گؤزلهدیکلردن گیزلت",
- "tog-ccmeonemails": "باشقا ایشلدنلره گؤندردیگیم ایمیللرین کوْپیلرینی منه گؤندر",
- "tog-diffonly": "مقایسهلر آلیتندا صفحهلرین ایچیندهکیلرینی گؤرستمه",
- "tog-showhiddencats": "Ú¯Û\8cزÙ\84Û\8c بؤÙ\84Ù\85Ù\87â\80\8cÙ\84رÛ\8c گؤرست",
- "tog-norollbackdiff": "Ù\82اÛ\8cتاراÙ\86داÙ\86 سÙ\88Ù\92Ù\86را Ù\85Ù\82اÛ\8cسÙ\87 گؤرستمه",
- "tog-useeditwarning": "دَییشدیرمه صفحهسیندن چیخاندا، ذخیره اولونمامیش دَییشدیرمه اوْلسا، منه تذکر وئر",
- "tog-prefershttps": "هر زامان گیریش ائتمگه امن باغلانتی ایشلت",
+ "tog-ccmeonemails": "باشقا ایشلدنلره گؤندردیگیم ایمئیللرین کوْپیلرینی منه گؤندر",
+ "tog-diffonly": "مۆقایسهلر آلتیندا صفحهنین ایچیندهکیلرینی گؤسترمه",
+ "tog-showhiddencats": "Ú¯Û\8cزÙ\84Û\8c بؤÙ\84Ù\85Ù\87â\80\8cÙ\84رÛ\8c گؤستر",
+ "tog-norollbackdiff": "Ù\82اÛ\8cتاراÙ\86داÙ\86 سÙ\88Ù\92Ù\86را Ù\81رÙ\82Û\8c گؤسترمه",
+ "tog-useeditwarning": "دَییشدیرمه صفحهسیندن چیخاندا، قئید اوْلونمامیش دَییشدیرمه اوْلسا، منه بیلدیر",
+ "tog-prefershttps": "هر زامان گیریش ائتمهیه امنیتلی باغلانتی ایشلت",
"underline-always": "هر زامان",
"underline-never": "هئچ واخت",
"underline-default": "وارساییلان قابیق یا براوزِر",
- "editfont-style": "دَییشدیرمه قۇتوسونون فوْنتی:",
+ "editfont-style": "دَییشدیرمه قۇتوسونون فوْنتو:",
"editfont-default": "براوزِر وارساییلانی",
"editfont-monospace": "ثابیت آرالی فوْنت",
"editfont-sansserif": "بۇجاقسیز فوْنت",
"fri": "آینیگون (جۆمعه)",
"sat": "يئلگونو (شنبه)",
"january": "ژانویه",
- "february": "فئوریه",
+ "february": "فوریه",
"march": "مارس",
"april": "آوریل",
"may_long": "مئی",
"june": "ژوئن",
- "july": "ژولای",
+ "july": "جولای",
"august": "آقوست",
"september": "سپتامبر",
"october": "اوْکتوبر",
"november": "نوْوامبر",
- "december": "دئساÙ\85بر",
+ "december": "دسامبر",
"january-gen": "ژانویه",
- "february-gen": "فئوریه",
+ "february-gen": "فوریه",
"march-gen": "مارس",
"april-gen": "آوریل",
"may-gen": "مئی",
"july-gen": "جولای",
"august-gen": "آقوست",
"september-gen": "سپتامبر",
- "october-gen": "اوکتوبر",
- "november-gen": "نووامبر",
- "december-gen": "دئساÙ\85بر",
+ "october-gen": "اوْکتوبر",
+ "november-gen": "Ù\86Ù\88Ù\92Ù\88اÙ\85بر",
+ "december-gen": "دسامبر",
"jan": "ژانویه",
- "feb": "فئوریه",
+ "feb": "فوریه",
"mar": "مارس",
"apr": "آوریل",
"may": "مئی",
"jun": "ژوئن",
- "jul": "ژولای",
+ "jul": "جولای",
"aug": "آقوست",
"sep": "سپتامبر",
"oct": "اوْکتوبر",
"nov": "نوْوامبر",
- "dec": "دئساÙ\85بر",
+ "dec": "دسامبر",
"january-date": "ژانویهنین $1-ی",
- "february-date": "فئوریهنین $1-ی",
+ "february-date": "فوریهنین $1-ی",
"march-date": "مارسین $1-ی",
"april-date": "آوریلین $1-ی",
"may-date": "مئیین $1-ی",
"june-date": "ژوئنین $1-ی",
- "july-date": "ژولایین $1-ی",
+ "july-date": "جولایین $1-ی",
"august-date": "آقوستون $1-ی",
- "september-date": "سئپتامبرین $1-ی",
+ "september-date": "سپتامبرین $1-ی",
"october-date": "اوْکتوبرون $1-ی",
"november-date": "نوْوامبرین $1-ی",
- "december-date": "دئساÙ\85برÛ\8cÙ\86 $1-Û\8c",
+ "december-date": "دسامبرین $1-ی",
"pagecategories": "{{PLURAL:$1|بؤلمه|بؤلمهلر}}",
"category_header": "«$1» بؤلمهسینده صفحهلر",
"subcategories": "آلتبؤلمهلر",
- "category-media-header": "«$1» بؤلمهسینده مئدیا",
- "category-empty": "<em>بÙ\88 بؤÙ\84Ù\85Ù\87â\80\8cدÙ\87 اÛ\8cÙ\86دÛ\8c Ù\81اÛ\8cÙ\84 Û\8cا Ù\85ئدیا یوْخدور.</em>",
+ "category-media-header": "«$1» بؤلمهسینده مدیا",
+ "category-empty": "<em>اÛ\8cÙ\86دÛ\8c بÛ\87 بؤÙ\84Ù\85Ù\87â\80\8cدÙ\87 Ù\81اÛ\8cÙ\84 Ù\88 Û\8cا Ù\85دیا یوْخدور.</em>",
"hidden-categories": "{{PLURAL:$1|گیزلی بؤلمه|گیزلی بؤلمهلر}}",
"hidden-category-category": "گیزلی بؤلمهلر",
"category-subcat-count": "{{PLURAL:$2|بۇ بؤلمهده تکجه آشاغیداکی آلتبؤلمه واردیر.|بۇ بؤلمهده، جمعی $2-دن، آشاغیداکی {{PLURAL:$1|آلتبؤلمه|$1 آلتبؤلمه}} واردیر.}}",
"viewhelppage": "یاردیم صحیفهسینه باخ",
"categorypage": "بؤلمه صحیفهسینه باخ",
"viewtalkpage": "دانیشیغا باخ",
- "otherlanguages": "Ø¢Û\8cرÛ\8c دیللرده",
+ "otherlanguages": "باشÙ\82ا دیللرده",
"redirectedfrom": "($1-دن يوْللاندیریلمیش)",
"redirectpagesub": "یوْللاندیرما صفحهسی",
"redirectto": "مسیزپرین دَییشیب:",
"currentevents": "ایندیکی حادیثهلر",
"currentevents-url": "Project:ایندیکی اولایلار",
"disclaimers": "یالانلامالار",
- "disclaimerpage": "Project:گنل یالانلاما",
+ "disclaimerpage": "Project:گئنل یالانلاما",
"edithelp": "ديَیشتیرمک یاردیمی",
"helppage-top-gethelp": "کؤمک",
"mainpage": "آنا صفحه",
"toc": "ایچیندهکیلر",
"showtoc": "گؤستر",
"hidetoc": "گیزلت",
- "collapsible-collapse": "ییغیشلات",
- "collapsible-expand": "گئÙ\86Û\8cØ´Ù\84ت",
+ "collapsible-collapse": "گیزلت",
+ "collapsible-expand": "گؤستر",
"confirmable-confirm": "{{GENDER:$1|سیز}} اطمینانیز وار می؟",
"confirmable-yes": "هن",
"confirmable-no": "یوْخ",
"noname": "گئچرلی ایستیفادهچی آدی وئرمهدینیز.",
"loginsuccesstitle": "گیریش اوغورلو",
"loginsuccess": "'''سیز ایندی {{SITENAME}} سایتینا، «$1» آدیله گیرمیسینیز.'''",
- "nosuchuser": "«$1» آدلا ایستیفادهچی یوخدور.\nایستیفادهچی آدلاری، حرفلرین بؤیوک/کیچیکلیگینه حساسدیلار.\nیازدیغینیزا یئنیدن باخین، یوخسا [[Special:UserLogin/signup|یئنی بیر حساب آچین]].",
+ "nosuchuser": "«$1» آدلا ایستیفادهچی یوخدور.\nایستیفادهچی آدلاری، حرفلرین بؤیوک/کیچیکلیگینه حساسدیلار.\nیازدیغینیزا یئنیدن باخین، یوخسا [[Special:CreateAccount|یئنی بیر حساب آچین]].",
"nosuchusershort": "\"$1\" آدلا ایستیفادهچی یوخدور.\nدوزگون یازدیغینیزدان آرخایین اولون.",
"nouserspecified": "بیر ایستیفادهچی آدی وئرمهلیسینیز.",
"login-userblocked": "بو ایستیفاده چی باغلانیبدیر. گیریشه ایجازه یوخدور.",
"noemail": "«$1» ایستیفادهچییه ایمیل آدرسی قئید اولماییبدیر.",
"noemailcreate": "دوزگون بیر ایمیل آدرسی وئرمهلیسینیز",
"passwordsent": "«$1»-نا قئید اولونان ایمیل آدرسینه، یئنی بیر رمز گؤندریلدی.\nاونا آلاندان سونرا یئنیدن گیرین.",
- "blocked-mailpassword": "سیزین آیپی آدرسینیز دَییشیک وئرمهیه باغلانیب و سوءاستفاده قاباغی آلماق اوچون، رمزی یئنیدن اله گتیرمک ایمکانینا ایجازهنیز یوخدور.",
+ "blocked-mailpassword": "سیزین آیپی آدرسینیزین دییشدیرمه ائده بیلمهسی باغلانمیشدیر. سوءایستیفاده قارشیسینی آلماق اۆچون، رمزی یئنیدن اله گتیرمک ایمکانینا ایجازهنیز یوْخدور.",
"eauthentsent": "سیزین سئچیلمیش ایمیل آدرسینه، دوغرولاماق اوچون بیر ایمیل گؤندریلدی.\nهر یئنی بیر ایمیل گؤندرمکدن اؤنجه، بو حسابین دوغرودان سیزین اولدوغونو گؤسترمک اوچون، او ایمیلدهکی ایشلری گؤرمهلیسینیز.",
"throttled-mailpassword": "سون {{PLURAL:$1|ساعات|$1 ساعات}}دا سیزه بیر رمز یئنیلهمه ایمیلی گؤندریلیبدیر.\nسوءاستفاده قاباغین آلماق اوچون، هر {{PLURAL:$1|ساعات|$1 ساعات}}دا یالنیز بیر رمز یئنیلهمه ایمیلی گؤندریلر.",
"mailerror": "ایمیل گؤندرمه خطاسی: $1",
"createaccount-title": "{{SITENAME}} اوچون حساب یارادیلماسی",
"createaccount-text": "بیر کس، سیزین ایمیل آدرسینیزه {{SITENAME}} ($4) سایتیندا «$2» آدی و «$3» رمزی ایله بیر حساب آچیبدیر. سیز گرک گیریش ائدیب و رمزینیزی ایندی دَییشدیرهسیز.\n\nبو حساب یانلیش دوزلیبسه، بو مئساژا محل قویمایابیلرسیز.",
"login-throttled": "سیزین چوخ گیریش چالیشماغینیز اولوبدور.\nلوطفاً یئنیدن چالیشماقدان اؤنجه بیر آز $1 دؤزون.",
- "login-abort-generic": "سÛ\8cزÛ\8cÙ\86 Ú¯Û\8cرÛ\8cØ´Û\8cÙ\86Û\8cز باشارÛ\8câ\80\8cسÛ\8cز اÙ\88لدو - دایاندیریلدی",
+ "login-abort-generic": "سÛ\8cزÛ\8cÙ\86 Ú¯Û\8cرÛ\8cØ´Û\8cÙ\86Û\8cز باجارÛ\8câ\80\8cسÛ\8cز اÙ\88Ù\92لدو - دایاندیریلدی",
"login-migrated-generic": "ایستفادچی حسابینیز آختاریلمیش دیر و آدینیز داها بو ویکی ده یوخدور",
"loginlanguagelabel": "دیل: $1",
"suspicious-userlogout": "سیزین چیخیش ایستگینیز رد اولوندو. بو، براوزرین یا پروکسی-کَشلمهسینین دوزگون ایشلهمهمهسیندن قایناقلانیر.",
"newpassword": "یئنی رمز",
"retypenew": "یئنی رمزی یئنیدن یازین:",
"resetpass_submit": "رمز یارادین و گیریش ائدین",
- "changepassword-success": "رÙ\85زÛ\8cÙ\86Û\8cز باشارÛ\8câ\80\8cÙ\84ا دÙ\8eÛ\8cÛ\8cشدÛ\8cرÙ\84دÛ\8c!",
+ "changepassword-success": "رÙ\85زÛ\8cÙ\86Û\8cز باجارÛ\8cÛ\8cÙ\84ا دÙ\8eÛ\8cÛ\8cشدÛ\8cرÙ\84دÛ\8c!",
"changepassword-throttled": "سیزین چوخ گیریش چالیشماغینیز اولوبدور.\nلوطفاً یئنیدن چالیشماقدان اؤنجه $1 دؤزون.",
"botpasswords-label-create": "یارات",
"botpasswords-label-cancel": "وازگئچ",
"resetpass-no-info": "بو صحیفهنی دوغرو گؤردوگونوز اوچون سیستمه گیرمهلیسینیز.",
"resetpass-submit-loggedin": "رمزی دَییشدیر",
"resetpass-submit-cancel": "وازگئچ",
- "resetpass-wrong-oldpass": "یانلیش گئچیجی یا ایندیکی رمز.\nاولا بیلر سیز باشاریلیقلا رمزینیزی دَییشمیسینیز یوخسا یئنی گئچرلی رمز ایستهمیسینیز.",
+ "resetpass-wrong-oldpass": "یانلیش گئچیجی و یا ایندیکی رمز.\nسیز باجارییلا رمزینیزی دَییشدیریب یوخسا یئنی گئچرلی رمز ایستهمیش اوْلدوغونوز مؤحتملدیر.",
"resetpass-recycled": "لوطفا گیریش رمزینیزی ایندیکی اولمایان بیر ایری گیریش رمزینه دَییشین",
"resetpass-temp-emailed": "سیز بیر کدلانمیش موقت ایمیل له گیریش ائدیب سیز.\nگیریشینیزه سون وئرمک اوچون یئنی دن بیر گیریش رمزی وئرمه لی سیز:",
"resetpass-temp-password": "گئچیجی رمز:",
"passwordreset-emailtext-ip": "بیر کس (احتیمالاً سیز، $1 آیپی آدرسیله)، {{SITENAME}} ($4) سایتینداکی حسابینیز اوچون رمزی یئنیلهمک ایستهییبدیر. آشاغیداکی ایستیفادهچی {{PLURAL:$3|حسابی|حسابلاری}} بو ایمیل ایله ایلگیلیدیرلر:\n\n$2\n\nبو گئچیجی {{PLURAL:$3|رمز|رمزلر}}، {{PLURAL:$5|بیر گون|$5 گون}}ده {{PLURAL:$3|واختی|واختلاری}} قورتاراجاقدیر.\nسیز گرک ایندی سایتا گیریب و یئنی بیر رمز سئچهسینیز. باشقا آدام بو ایستَگی وئرمیشسه، یوخسا سیز اسکی رمزینیزی یادا گتیرمیشسینیزسه، و داها اونو چئویرمک ایستهمیرسینیزسه، بو مئساژی سایماییب و اسکی رمزینیزی ایشلدمگه داوام ائده بیلرسینیز.",
"passwordreset-emailtext-user": "{{SITENAME}} سایتیندا، $1 ایستیفادهچی، سیزین اوردا ($4) حسابینیزین رمزینی یئنیلهمک ایستگی وئریبدیر. آشاغیداکی {{PLURAL:$3|ایستیفادهچی|ایستیفادهچیلر}} بو ایمیل ایله ایلگیلیدیرلر:\n\n$2\n\nبو گئچیجی {{PLURAL:$3|رمز|رمزلر}}، {{PLURAL:$5|بیر|$5گون}} سونرا واختلاری قورتاراجاقدیر. \nسیز گرک ایندی گیریب و بیر یئنی رمز سئچهسینیز. باشقا آدام بو ایستَگی وئرمیشسه، یوخسا سیز اسکی رمزینیزی یادا گتیرمیشسینیزسه، و داها اونو چئویرمک ایستهمیرسینیزسه، بو مئساژی سایماییب و اسکی رمزینیزی ایشلدمگه داوام ائده بیلرسینیز.",
"passwordreset-emailelement": "ایشلدن آدی: \n$1\n\nگئچیجی رمز: \n$2",
- "passwordreset-emailsentemail": "بÛ\8cر رÙ\85ز Û\8cئÙ\86Û\8cÙ\84Ù\87â\80\8cÙ\85Ù\87 اÛ\8cÙ\85Û\8cÙ\84Û\8c گؤÙ\86درÛ\8cÙ\84Û\8cبâ\80\8cدیر.",
+ "passwordreset-emailsentemail": "بÛ\87 اÛ\8cÙ\85ئÛ\8cÙ\84 آدرسÛ\8c ØسابÛ\8cÙ\86Û\8cزا ثبت اÙ\88Ù\92Ù\84Ù\88Ù\86Ù\85Ù\88شسا٬ بÛ\8cر رÙ\85ز Û\8cئÙ\86Û\8cÙ\84Ù\87â\80\8cÙ\85Ù\87 اÛ\8cÙ\85ئÛ\8cÙ\84Û\8c گؤÙ\86درÛ\8cÙ\84Ù\87â\80\8cجکدیر.",
"passwordreset-emailsent-capture": "آشاغیدا گؤستریلن کیمی بیر رمز یئنیلهمه ایمیلی گؤندریلیبدیر.",
"passwordreset-emailerror-capture": "آشاغیدا گؤستریلن کیمی بیر رمز یئنیلهمه ایمیلی یارادیلیبدیر، اما {{GENDER:$2ایستیفادهچی}}یه گؤندرمگی باشاریلی اولمادی: $1",
"changeemail": "ایمیل آدرسینی دَییشدیر یا سیل",
"accmailtext": "[[User talk:$1|$1]] اوچون بیر راستگله رمز یارادیلیب و $2-ه گؤندریلدی.\n\nبو یئنی حسابین رمزی، گیرندن سونرا <em>[[Special:ChangePassword|رمز دَییشدیرمه]]</em> صحیفهسیندن دَییشیله بیلر.",
"newarticle": "(یئنی)",
"newarticletext": "مؤوجود اوْلمايان صحیفهيه اوْلان کئچیدی ایزلهدینیز. \nآشاغیداکی ساحهيه مظمونونو يازاراق بۇ صحیفهنی '''سیز''' يارادا بیلرسینیز. (علاوه معلومات اۆچون [$1 کؤمک صحیفهسینه] باخین). اگر بۇ صحیفهيه سهون گلمیسینیزسه سادهجه اوْلاراق براوزئرین '''گئری''' دۆيمهسینه وۇرون.",
- "anontalkpagetext": "''بو صحیفه قئیدیاتدان کئچممیش و یا داخیل اولمامیش آنونیم ایستیفادچییه عایید موذاکیره صحیفهسیدیر.\nاونا گؤره بو ایستیفادچینی رقملردن عبارت ایپ اونوانی ایله معین ائتمک مجبوریتیندییک.\nبئله ایپ اونوان بیر نئچه فرد طرفیندن ایستیفادهده اولا بیلر.\nاگر سیز آنونیم ایستیفادچیسینیزسه و بو مئساژین سیزه عایید اولمادیغینی دوشونورسونوزسه، اوندا [[Special:UserLogin/signup|قئیدیاتدان کئچین]] و یا [[Special:UserLogin|داخی اولون]].''",
+ "anontalkpagetext": "''بو صحیفه قئیدیاتدان کئچممیش و یا داخیل اولمامیش آنونیم ایستیفادچییه عایید موذاکیره صحیفهسیدیر.\nاونا گؤره بو ایستیفادچینی رقملردن عبارت ایپ اونوانی ایله معین ائتمک مجبوریتیندییک.\nبئله ایپ اونوان بیر نئچه فرد طرفیندن ایستیفادهده اولا بیلر.\nاگر سیز آنونیم ایستیفادچیسینیزسه و بو مئساژین سیزه عایید اولمادیغینی دوشونورسونوزسه، اوندا [[Special:CreateAccount|قئیدیاتدان کئچین]] و یا [[Special:UserLogin|داخی اولون]].''",
"noarticletext": "ایندی بو صفحهده یازی یوخدور.\nسیز آیری صفحهلرده [[Special:Search/{{PAGENAME}}|بو باشلیق اوچون آختارا بیلرسیز]]،\nیا دا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} باغلی قئیدلری آختارا بیلرسیز]،\nیا دا [{{fullurl:{{FULLPAGENAME}}|action=edit}} بو صفحهنی دَییشدیره بیلرسیز]</span>.",
"noarticletext-nopermission": "بو صحیفه ایندی بوشدور. \nباشقا صحیفهلرده عینی آددا صحیفهنی [[Special:Search/{{PAGENAME}}| آختار]], علاقهلی قئيدلره \n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} باخا],\nو يا صحیفهنی [{{fullurl:{{FULLPAGENAME}}|action=edit}} redaktə]</span> ائده بیلرسینیز.",
"missing-revision": "«{{FULLPAGENAME}}» صحیفهسی اوچون $1 نومرهلی نوسخه یوخدور.\n\nعموماُ بو ایشکال، واختی گئچمیش بیر باغلانتی ایله سیلینمیش بیر صحیفهیه گلنده، قاباغا گلر.\n[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیلمک سیاهی]سینده باشقا بیلگیلر اولا بیلر.",
"previewnote": "'''بونون سادهجه بیر سیناق گؤستریشی اولدوغونو نظرده آلین.'''\nسیزین دییشیکلرینیز هله قئید اولونماییب!",
"continue-editing": "دَییشدیرمه یئرینه گئت",
"previewconflict": "بو سیناق گؤستریشیدیر و یادداشدا ساخلایاجاغینیز تقدیرده متنین دییشدیر صحیفهسینین یوخاری حیسهسینده نتیجهنین نئجه اولاجاغینی گؤستریر.",
- "session_fail_preview": "'''اÙ\88زر اÛ\8cستÛ\8cÛ\8cرÛ\8cÚ©! سÛ\8cزÛ\8cÙ\86 دÛ\8cÛ\8cشتÛ\8cرÛ\8cÙ\86Û\8cزâ\80\8c ساخÙ\84اÙ\86Û\8cÙ\84Ù\85ادÛ\8c. Ù\84Ø·Ù\81اÙ\8b بÛ\8cر داÙ\87ا تکرار ائدÛ\8cÙ\86. پرÙ\88بÙ\84ئÙ\85 ØÙ\84 اÙ\88Ù\84Ù\88Ù\86Ù\85اسا ØسابÛ\8cÙ\86Û\8cزداÙ\86 [[Special:UserLogout|Ú\86Û\8cØ®Û\8cÙ\86]] Ù\88 Û\8cئÙ\86Û\8câ\80\8cدÙ\86 داخÛ\8cÙ\84 اÙ\88لون.'''",
+ "session_fail_preview": "'''عÛ\86ذر اÛ\8cستÙ\87â\80\8cÛ\8cÛ\8cرÛ\8cÚ©! سÛ\8cزÛ\8cÙ\86 دÛ\8cÛ\8cشدÛ\8cرÙ\85Ù\87â\80\8cÙ\86Û\8cز Û\8cازدÛ\8cرÛ\8cÙ\84Ù\85ادÛ\8c. \nسÛ\8cستÙ\85دÙ\86 Ú\86Û\8cØ®Ù\85Û\8cØ´ اÙ\88Ù\92Ù\84دÙ\88غÙ\88Ù\86Ù\88ز Ù\85ؤØتÙ\85Ù\84â\80\8cدÛ\8cر. Ù\84Û\86Ø·Ù\81اÙ\8b سÛ\8cستÙ\85Ù\87 Ú¯Û\8cرÙ\85Û\8cØ´ اÙ\88Ù\92Ù\84دÙ\88غÙ\88Ù\86Ù\88زداÙ\86 آرخاÛ\8cÛ\8cÙ\86 اÙ\88Ù\92Ù\84Ù\88ب بÛ\8cر داÙ\87ا تکرار ائدÛ\8cÙ\86. \nÙ\85Û\86Ø´Ú©Ù\88Ù\84 ØÙ\84 اÙ\88Ù\92Ù\84Ù\88Ù\86Ù\85اسا ØسابÛ\8cÙ\86Û\8cزداÙ\86 [[Special:UserLogout|Ú\86Û\8cØ®Û\8cب]] Û\8cئÙ\86Û\8câ\80\8cدÙ\86 Ú¯Û\8cرÛ\8cØ´ ائدÛ\8cÙ\86Ù¬ براÙ\88زرÛ\8cÙ\86Û\8cزÛ\8cÙ\86 بÛ\87 ساÛ\8cتا Ú©Ù\88Ú©Û\8c Ù\88ئرÙ\85Ù\87 اÛ\8cجازÙ\87â\80\8cسÛ\8cÙ\86Û\8c Ù\88ئردÛ\8cÚ¯Û\8cÙ\86دÙ\86 دÙ\87 آرخاÛ\8cÛ\8cÙ\86 اÙ\88Ù\92لون.'''",
"session_fail_preview_html": "'''اوزر ایستییریک! داخیل وئریسینین ایتمهسیندن گؤره تنظیملمهنیزی اعمال کئچیره بیلمیجیی.' '\n\n' چونکی {{SITENAME}} سایتیندا raw هتمل تأثیریندیر،تا جاوااسکریپت هوجوملارینا تدبیر اولاراق گیزلنمیشدیر.'\n\n' 'گر بو حاقلی بیر تنظیملمه گیریش میسئ، لطفاً یئنیدن جهد ائدین. اگر هله چالیشمازسا، [[Special:UserLogout|خارج شوید]] یئنیدن ایجلاس آچماغی یوخلایین.' '",
"token_suffix_mismatch": "'' ' ديَیشیکلیگینین گئری چئوریلدی، چونکی آلیجینین تنزیملهمه کوتوجوغونداکی دورغو ایشارهلرینی پوزدو. \nديَیشیکلیگینین، صحیفه متنینده پوزولماغی اؤنلهمک اوچون گئری چئوریلدی. \nاگر پروبلئملی بیر wئب-باسئد آنونیم پروکسی خیدمتی ایستیفاده بو حادثه بضا رئاللاشا بیلر.'' '",
"edit_form_incomplete": "'''دییشیکلیک فورماسی اوچون بعضی سئروئرلره ایشلمهدی؛ ائتدیگینیز دییشیکلیکلر بوزولمامیشتیر، نظردن کئچیریب یئنیدن سینایین.'",
"uploadstash-summary": "بو صحیفه يوکلنمیش(و يا يوکلنمکده دیر) آمما هله ویکیده نشر اولونمامیش فايللارا چاتماغی تعمین ائدر. بو فايللار يالنیز يوکلهيهنی طرفیندن گؤروله بیلر.",
"uploadstash-clear": "مووققتی فايللاری تمیزله",
"uploadstash-nofiles": "سیزین هئچ آمبار اولموش فایلینیز یوخدور.",
- "uploadstash-badtoken": "Ú\86اÙ\84Û\8cØ´Ù\85اÙ\86Û\8cÙ\86 ØÛ\8cاتا کئÚ\86Û\8cرÛ\8cÙ\84Ù\85Ù\87â\80\8cسÛ\8c باشارÛ\8cسÛ\8cز اÙ\88Ù\84دÙ\88Ø\8c اØتÛ\8cÙ\85اÙ\84Ù\84ا تÙ\86زیملهمه قايدالاری زامان آشیمینا معروض قالدی. يئنیدن چالیشین.",
+ "uploadstash-badtoken": "Ú\86اÙ\84Û\8cØ´Ù\85اÙ\86Û\8cÙ\86 ØÛ\8cاتا کئÚ\86Û\8cرÛ\8cÙ\84Ù\85Ù\87â\80\8cسÛ\8c باشارÛ\8cسÛ\8cز اÙ\88Ù\84دÙ\88Ø\8c اØتÛ\8cÙ\85اÙ\84Ù\84ا تÙ\86ظیملهمه قايدالاری زامان آشیمینا معروض قالدی. يئنیدن چالیشین.",
"uploadstash-errclear": "فايللارین سیلینمهسی باشاریسیز اولدو.",
"uploadstash-refresh": "فايل سیياهیسینی يئنیله",
"invalid-chunk-offset": "اعتبارسیز یئربهیئر",
"unblock": "ایستیفادهچینین باغلانماسین گؤتور",
"blockip": " {{GENDER:$1|ایشلدن}}ی باغلا",
"blockip-legend": "ایستیفادچی نی باغلا",
- "blockiptext": "آشاغیداکی فورمو ایستیفاده ائدهرک مویین بیر ایپنین و یا قئیدیاتدان کئچمیش ایستیفادهچینین دییشیکلیک ائتمهسینی مانعه تؤرهده بیلرسینیز. بو یالنیز واندالیزمی قارشیسینی آلماق اوچون و [[{{MediaWiki:Policy-url}}|قایدالارا]] اویغون اولاراق ائدیلمهلی. آشاغییا موتلق قاداغا ایله علاقهدار بیر شرح یازین. (نومونه:-بو-صحیفهلرده واندالیزم ائتمیشدیر).",
+ "blockiptext": "آشاغیداکی فورمو ایستیفاده ائدهرک مۆعیّن بیر آیپینین و یا قئیدیاتدان کئچمیش ایستیفادهچینین دییشیکلیک ائتمهسینی مانعه تؤرهده بیلرسینیز. بۇ یالنیز واندالیزمین قارشیسینی آلماق اۆچون و [[{{MediaWiki:Policy-url}}|قایدالارا]] اۇیغون اوْلاراق ائدیلمهلی. آشاغییا مۆطلق قاداغا ایله علاقهدار بیر شرح یازین. (اؤرنک:-بۇ-صفحهلرده واندالیزم ائتمیشدیر).",
"ipaddressorusername": "آی-پی عونوانی و یا ایستیفادهچی آدی",
"ipbexpiry": "بیتمه مدتی:",
"ipbreason": "ندن:",
"unblock-hideuser": "ایستیفادهچی آدی گیزلی اولدوغو اوچون، بی باغلامانی گؤتوره بیلمزسینیز.",
"ipb_cant_unblock": "ختا: باغلاما آی دی سی $1 تاپیلمادی. باغلامانین گؤتورولمهسی مومکوندور.",
"ipb_blocked_as_range": "خطا: $1 ای پی عنوانی بیرباشا مانعه و مانعه تؤرتمه آزالدیلماسینا یول وئریلمیر.\nآنجاق، بو عنوان $2 آرالیغینین پارچاسی اولاراق مانعه تؤردیلمیش، دئکابر مانعه تؤرتمهسینی قالدیرا.",
- "ip_range_invalid": "یانلیش ای پی",
+ "ip_range_invalid": "گئچرسیز آیپی آرالیغی.",
"ip_range_toolarge": "/ $1 بلوکدان داها بؤیوک بازه باغلانمالارینا ایجازه وئریلمیر.",
"proxyblocker": "پروکسی باغلییان",
"proxyblockreason": "ای پی آدرئسینیز آچیق بیر پروکسی اولدوغو اوچون مانعه تؤردیلدی.\nخاهیش ائدیریک اینتئرنئت سئویش تعمین ایله یا دا تئکنیکی دستک ایله علاقه قورون و بو جدی تهلوکهسیزلیک پروبلئمیندن خبردار ائدین.",
"tooltip-pt-preferences": "{{GENDER:|سیزین}} ترجیحلرینیز",
"tooltip-pt-watchlist": "دییشمکلرینی ایزلهدیگینیز صفحهلرین سیاهیسی",
"tooltip-pt-mycontris": "{{GENDER:|سیزین}} چالیشمالارینیزین لیستی",
- "tooltip-pt-login": "گیریش ائتمهیینیز توصیه اولونور؛ اما گرکلی دئییل",
+ "tooltip-pt-login": "گیریش ائتمهنیز تؤوصیه اوْلونور؛ آنجاق گرکلی دئییلدیر",
"tooltip-pt-logout": "چیخیش",
- "tooltip-pt-createaccount": "سیزدن دعوت اولونور ایشلدن حسابی آچیب و گیریش ائدهسیز؛ آنجاق حساب یاراتماق ایستگه باغلیدیر",
+ "tooltip-pt-createaccount": "سیزی ایشلدن حسابی آچیب گیریش ائتمهیه چاغیریریق؛ آنجاق حساب یاراتماق ایستگینیزه باغلیدیر",
"tooltip-ca-talk": "ایچیندهکیلره گؤره دانیشیق",
"tooltip-ca-edit": "بۇ صفحهنی دَییشدیر",
"tooltip-ca-addsection": "یئنی بؤلوم یارات",
"tooltip-ca-unwatch": "بو صفحهنی ایزلهدیگینیز صفحهلردن قالدیرین",
"tooltip-search": "{{SITENAME}}-دا آختار",
"tooltip-search-go": "اولورسا بو آددا بیر صفحهیه گئت",
- "tooltip-search-fulltext": "بو یازی اولان صفحهلری آختار",
+ "tooltip-search-fulltext": "بو یازینی صفحهلرده آختار",
"tooltip-p-logo": "آنا صفحهیه باخ",
"tooltip-n-mainpage": "آنا صفحهیه باخین",
"tooltip-n-mainpage-description": "آنا صفحهیه باخ",
- "tooltip-n-portal": "پروژه یه گؤره، سیز نه ایش گوره بیلرسیز، هاردا نهلری تاپا بیلرسیز",
- "tooltip-n-currentevents": "اÛ\8cÙ\86دÛ\8cÚ©Û\8c اÙ\88Ù\84اÛ\8câ\80\8cÙ\84ارا اÛ\8cÙ\84Ú¯Û\8cÙ\84Û\8c بÛ\8cÙ\84Ú¯Û\8câ\80\8cÙ\84ر تاپ",
- "tooltip-n-recentchanges": "بÙ\88 Ù\88Û\8cÚ©Û\8câ\80\8cدÙ\87 سÙ\88Ù\86 دÙ\8eÛ\8cÛ\8cØ´Û\8cÚ©لرین لیستی",
+ "tooltip-n-portal": "پروژهیه گؤره، سیز نه ایش گؤره بیلرسینیز، هاردا نهلری تاپا بیلرسینیز",
+ "tooltip-n-currentevents": "اÛ\8cÙ\86دÛ\8cÚ©Û\8c اÙ\88Ù\92Ù\84اÛ\8cÙ\84ارا اÛ\8cÙ\84Ú¯Û\8cÙ\84Û\8c بÛ\8cÙ\84Ú¯Û\8cÙ\84ر تاپ",
+ "tooltip-n-recentchanges": "بÙ\88 Ù\88Û\8cÚ©Û\8câ\80\8cدÙ\87 سÙ\88Ù\92Ù\86 دÙ\8eÛ\8cÛ\8cØ´Û\8cÚ©â\80\8cÙ\84Û\8cÚ©â\80\8cلرین لیستی",
"tooltip-n-randompage": "بیر تصادوفی صفحه گتیر",
"tooltip-n-help": "آنلاماق یئری",
- "tooltip-t-whatlinkshere": "بورایا باغلانان بوتون ویکی صفحهلرین لیستی",
- "tooltip-t-recentchangeslinked": "بو صفحهدن باغلانان صفحهلرین سون دَییشیکلیکلری",
+ "tooltip-t-whatlinkshere": "بۇرا باغلانان بۆتون ویکی صفحهلرین لیستی",
+ "tooltip-t-recentchangeslinked": "بۇ صفحه اوْنلارا باغلانان صفحهلرین سوْن دَییشیکلیکلری",
"tooltip-feed-rss": "بو صحیفه اوچون آراساس يايیمی",
"tooltip-feed-atom": "بو صحیفه اوچون آتوم يايیمی",
"tooltip-t-contributions": "{{GENDER:$1|بۇ ایشلدنین}} وئردیگی دییشیکلر لیستی",
"logentry-newusers-byemail": "$3 ایستیفادهچی حسابی، $1 ایله {{GENDER:$2|یارادیلیب}} و رمز، ایمیل ایله گؤندریلیبدیر",
"logentry-newusers-autocreate": "$1 ایشلدن حسابی اوْتوماتیک {{GENDER:$2|یارادیلدی}}",
"logentry-protect-protect": "$1 $3-ی/و {{GENDER:$2|قوْرودو}} $4",
- "logentry-rights-rights": "$1، $3-ین قروپ عوضولوگونو $4-دن $5-ه {{GENDER:$2|دَییشدیردی}}",
+ "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|آرتیریلدی}}",
"logentry-upload-upload": "$1 $3 را {{GENDER:$2|یوکلندیردی}}",
"Айсар",
"Lizalizaufa",
"Кутлубаева Кунсулу Закиевна",
- "Вильданова Гюзель"
+ "Вильданова Гюзель",
+ "Ilmira"
]
},
"tog-underline": "Һылтанмалар аҫтына һыҙыу:",
"noname": "Ғәмәлдә булған ҡатнашыусы исемен керетмәнегеҙ.",
"loginsuccesstitle": "Танышыу уңышлы үтте",
"loginsuccess": "Хәҙер һеҙ $1 исеме менән эшләйһегеҙ.",
- "nosuchuser": "$1 исемле ҡулланыусы юҡ.\nҠулланыусы исеме хәреф регистрына һиҙгер.\nИсемде тикшерегеҙ йәки [[Special:UserLogin/signup|яңы иҫәп яҙыуы асығыҙ]].",
+ "nosuchuser": "$1 исемле ҡулланыусы юҡ.\nҠулланыусы исеме хәреф регистрына һиҙгер.\nИсемде тикшерегеҙ йәки [[Special:CreateAccount|яңы иҫәп яҙыуы асығыҙ]].",
"nosuchusershort": "$1 исемле ҡулланыусы юҡ. Исемде тикшерегеҙ.",
"nouserspecified": "Һеҙ ҡатнашыусы исемен күрһәтергә тейеш.",
"login-userblocked": "Был ҡатнашыусыға рөхсәт юҡ. Исеме тыйылған.",
"accmailtext": "[[User talk:$1|$1]] өсөн осраҡлы яһалған серһүҙ $2 адресына ебәрелде.\n\nТанылғандан һуң был иҫәп яҙмаһы өсөн серһүҙҙе ''[[Special:ChangePassword|серһүҙҙе үҙгәртеү өсөн махсус биттә үҙгәртә алаһығыҙ]]''.",
"newarticle": "(Яңы)",
"newarticletext": "Һеҙ һылтанма буйынса әлегә яһалмаған биткә күстегеҙ.\nЯңы бит яһар өсөн аҫтағы тәҙрәгә текст керетегеҙ (тулыраҡ мәғлүмәт өсөн [$1 ярҙам битен] ҡарағыҙ).\nӘгәр был биткә яңылыш килеп эләккән булһағыҙ, браузерығыҙҙың '''артҡа''' төймәһенә баҫығыҙ.",
- "anontalkpagetext": "----\n<em>Был фекер алышыу бите, иҫәп яҙыуы булдырмаған йәки уны ҡулланмаған аноним ҡатнашыусының бите.</em>\nШуның өсөн ҡулланыусыны таныу өсөн IP-адресы ҡулланыла.\nӘгәр һеҙ аноним ҡулланыусы булһағыҙ һәм һеҙгә ебәрелмәгән хәбәрҙәр алдым тиһәгеҙ (бер IP-адрес күп ҡулланыусы өсөн булырға мөмкин) һәм башҡа бындай аңлашылмаусанлыҡтар килеп сыҡмаһын өсөн, зинар, [[Special:UserLogin|системаға керегеҙ]] йәки [[Special:UserLogin/signup|теркәлегеҙ]].",
+ "anontalkpagetext": "----\n<em>Был фекер алышыу бите, иҫәп яҙыуы булдырмаған йәки уны ҡулланмаған аноним ҡатнашыусының бите.</em>\nҠулланыусыны таныу өсөн IP-адресы ҡулланыла.\nӘгәр һеҙ аноним ҡулланыусы булһағыҙ һәм һеҙгә ебәрелмәгән хәбәрҙәр алдым тиһәгеҙ (бер IP-адрес күп ҡулланыусы өсөн булырға мөмкин), һәм башҡа бындай аңлашылмаусанлыҡтар килеп сыҡмаһын өсөн, [[Special:UserLogin|системаға керегеҙ]] йәки [[Special:CreateAccount|теркәлегеҙ]].",
"noarticletext": "Хәҙерге ваҡытта был биттә текст юҡ.\nҺеҙ [[Special:Search/{{PAGENAME}}|был исемде башҡа биттәрҙә эҙләй]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} тап килгән журнал яҙмаларын таба]\nйәки '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} бындай исемле яңы бит яһай]'''</span> алаһығыҙ.",
"noarticletext-nopermission": "Хәҙерге ваҡытта был биттә текст юҡ.\nҺеҙ башҡа биттәрҙә [[Special:Search/{{PAGENAME}}|был исемде]] йәки\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} журналдағы яҙмаларҙы] эҙләй алаһығыҙ, тик һеҙҙең бит яһау хоҡуғығыҙ юҡ.</span>",
"missing-revision": "\"{{FULLPAGENAME}}\" исемле биттең $1 номерлы өлгөһө юҡ.\n\nБыл хәл, ғәҙәттә, юйылған биткә яһалған һылтанманын ваҡыты үтеүенән барлыҡҡа килә.\nТулыраҡ мәғлүмәт өсөн ҡарағыҙ: [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} юйыу яҙмалары].",
"parser-unstrip-loop-warning": "Ябылмаған pre табылды",
"parser-unstrip-recursion-limit": "($1) рекурсия сиге үтеп кителгән",
"converter-manual-rule-error": "Тел әйлендереү ҡағиҙәһендә хата табылды",
- "undo-success": "Был үҙгәртеүҙе кире алып була. Зинһар, улар һеҙҙе ҡыҙыҡһындырған үҙгәртеүҙәр булыуынан шикләнмәҫ өсөн версияларҙы сағыштырыуҙы ҡарағыҙ һәм үҙгәртеүҙәрҙе ғәмәлғә керетер өсөн «Битте һаҡларға» төймәһенә баҫығыҙ.",
+ "undo-success": "Был үҙгәртеүҙе кире алып була. Үҙгәртеүҙәр нәҡ һеҙ теләгәнсә булһа, версияларҙы сағыштырып ҡарағыҙ, ғәмәлгә индерер өсөн, «Битте һаҡларға» төймәһенә баҫығыҙ.",
"undo-failure": "Ара үҙгәртеүҙәр тура килмәү сәбәпле төҙәтеүҙе кире алып булмай.",
"undo-norev": "Үҙгәртеүҙе кире алып булмай, сөнки юҡ йәки юйылған.",
"undo-nochange": "Төҙәтеү кире ҡайтарылған.",
"right-managechangetags": "[[Special:Tags|билдәләр]] мәғлүмәттәр базаһында төҙөү һәм юйыу",
"right-applychangetags": " [[Special:Tags|тамғаһын]] үҙегеҙҙең төҙөтеү менән ҡулланырға",
"right-changetags": "Айырым үҙгәртеүҙәрҙә һәм журнал яҙмаланыда[[Special:Tags|тамғаһын]] өҫтәү һәм юйыу",
+ "right-deletechangetags": "[[Special:Tags|билдәләр]] мәғлүмәттәр базаһында төҙөү һәм юйыу",
"grant-generic": "Хоҡуҡтар йыйынтығы «$1»",
"grant-group-page-interaction": "Башҡа биттәр менән бәйләнеш",
"grant-group-file-interaction": "Медиафайлдар менән бәйләнеш",
"grant-blockusers": "Иҫәп яҙмаларын блоклау һәм блоклауҙы асыу",
"grant-createaccount": "Иҫәп яҙмаһын булдырырға",
"grant-createeditmovepage": "Биттәрҙе булдырыу,мөхәррирләү һәм исемен үҙгәртеү",
- "grant-delete": "Журналдағы биттәрҙе юйыу, төҙәтеү",
+ "grant-delete": "Журналдағы биттәрҙе, яҙмаларҙы юйыу һәм төҙәтеү",
"grant-editinterface": "MediaWiki исеме арауығында төҙәтеү һәм ҡулланыусы CSS/JavaScript",
"grant-editmycssjs": "CSS/JavaScript ҡулланыусы кодын төҙәтеү",
"grant-editmyoptions": "Һеҙҙең ҡулланыусы көйләүҙәрен мөхәррирләү",
"upload-form-label-own-work": "Был минең эш",
"upload-form-label-infoform-categories": "Категориялар",
"upload-form-label-infoform-date": "Дата",
- "upload-form-label-own-work-message-local": "Тейәлгән файл {{SITENAME}} лицензия сәйәсәтенә ярашлы икәнен раҫлайым.",
- "upload-form-label-not-own-work-message-local": "{{SITENAME}} ҡағиҙәләренә ярашлы файлды тейәй алмаһағыҙ, диалог теҙерәһен ябығыҙ ҙа тейәү !с!н башҡа ысулды һайлағыҙ.",
- "upload-form-label-not-own-work-local-local": "Ошонда эшләп ҡарағыҙ[[Special:Upload|килешеү буйынса тейәү бите]].",
- "upload-form-label-own-work-message-default": "Был файлды дөйөм репозиторийға күсереүемде аңлайым. Быны ҡулланыусы килешеүе һәм лицензия сәйәсәтенә ярашлы эшләүемде раҫлайым.",
- "upload-form-label-not-own-work-message-default": "{{SITENAME}} ҡағиҙәләренә ярашлы файлды тейәй алмаһағыҙ, диалог теҙерәһен ябығыҙ ҙа тейәү өсөн башҡа ысулды һайлағыҙ.",
- "upload-form-label-not-own-work-local-default": "{{SITENAME}} талаптарына ярашлы файлы тейәп булһа, [[Special:Upload|тейәү битен]] ҡарағыҙ.",
- "upload-form-label-own-work-message-shared": "Мин ошо файлдың авторы икәнемде раҫлайым һәм был файлды Викискладта [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] лицензияһы аҫтынан кире алмаҫҡа урынлаштырырға ризалы! бирәм, шулай уҡ [https://wikimediafoundation.org/wiki/ҡулланыу шарттары] менән килешәм.",
- "upload-form-label-not-own-work-message-shared": "Әгәр ошо файлдың авторы түгелһегеҙ һәм уны икенсе лицензия аҫтында сығарырға теләйһегеҙ икән, [https://commons.wikimedia.org/wiki/Special:UploadWizard Викискладҡа күсереү оҫталары] мөмкинлеген файҙаланығыҙ.",
- "upload-form-label-not-own-work-local-shared": "{{SITENAME}} талаптарына ярашлы файлы тейәп булһа, [[Special:Upload|тейәү битен]] ҡарағыҙ.",
+ "upload-form-label-own-work-message-generic-local": "Тейәлгән файл {{SITENAME}} лицензия сәйәсәтенә ярашлы икәнен раҫлайым.",
+ "upload-form-label-not-own-work-message-generic-local": "{{SITENAME}} ҡағиҙәләренә ярашлы файлды тейәй алмаһағыҙ, диалог теҙерәһен ябығыҙ ҙа тейәү !с!н башҡа ысулды һайлағыҙ.",
+ "upload-form-label-not-own-work-local-generic-local": "Ошонда эшләп ҡарағыҙ[[Special:Upload|килешеү буйынса тейәү бите]].",
+ "upload-form-label-own-work-message-generic-foreign": "Был файлды дөйөм репозиторийға күсереүемде аңлайым. Быны ҡулланыусы килешеүе һәм лицензия сәйәсәтенә ярашлы эшләүемде раҫлайым.",
+ "upload-form-label-not-own-work-message-generic-foreign": "{{SITENAME}} ҡағиҙәләренә ярашлы файлды тейәй алмаһағыҙ, диалог теҙерәһен ябығыҙ ҙа тейәү өсөн башҡа ысулды һайлағыҙ.",
+ "upload-form-label-not-own-work-local-generic-foreign": "{{SITENAME}} талаптарына ярашлы файлы тейәп булһа, [[Special:Upload|тейәү битен]] ҡарағыҙ.",
"backend-fail-stream": "$1 файлын трансляциялап булмай.",
"backend-fail-backup": "$1 файлының резерв күсермәһен эшләп булмай.",
"backend-fail-notexists": "$1 файлы юҡ.",
"pageinfo-not-current": "Ғәфү итегеҙ, был мәғлүмәтте иҫке версиялар өсөн күрһәтеп булмай.",
"pageinfo-header-basic": "Төп мәғлүмәт",
"pageinfo-header-edits": "Үҙгәртеүҙәр тарихы",
- "pageinfo-header-restrictions": "Бите һаҡлау",
+ "pageinfo-header-restrictions": "Битте һаҡлау",
"pageinfo-header-properties": "Биттең үҙенсәлектәре",
"pageinfo-display-title": "Күренгән исем",
"pageinfo-default-sort": "Ғәҙәттәге сортлау асҡысы",
"metadata-help": "Файл, ғәҙәттә һанлы камералар йәки сканерҙар өҫтәгән мәғлүмәттәргә эйә. Әгәр файл яһалғандан һуң төҙәтелгән булһа, ҡайһы бер параметрҙар ағымдағы рәсем менән тап килмәҫкә мөмкин.",
"metadata-expand": "Өҫтәмә мәғлүмәттәрҙе күрһәт",
"metadata-collapse": "Өҫтәмә мәғлүмәттәрҙе йәшер",
- "metadata-fields": "Был исемлектә һанап кителгән мета мәғлүмәт юлдары рәсем битендә күрһәтеләсәктәр, ҡалғандары иһә төрөлгән буласаҡ.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+ "metadata-fields": "Был исемлектә һанап кителгән метамәғлүмәт юлдары рәсем битендә күрһәтеләсәк, ҡалғандары төрөләсәк.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
"exif-imagewidth": "Киңлек",
"exif-imagelength": "Бейеклек",
"exif-bitspersample": "Төҫтәрҙең тәрәнлеге",
"confirm-watch-top": "Был битте күҙәтеү исемлегенә өҫтәргәме?",
"confirm-unwatch-button": "Тамам",
"confirm-unwatch-top": "Был битте күҙәтеү исемлегенән сығарырғамы?",
+ "confirm-rollback-button": "Яҡшы",
+ "confirm-rollback-top": "Был биттәге үҙгәртеүҙе кире алырғамы?",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← алдағы бит",
"imgmultipagenext": "киләһе бит →",
"log-action-filter-protect-modify": "Яңынан тейәү",
"log-action-filter-protect-unprotect": "Һаҡты алып ташлау",
"log-action-filter-upload-upload": "Яңы күсереү",
- "log-action-filter-upload-overwrite": "Ҡабаттан тейәү"
+ "log-action-filter-upload-overwrite": "Ҡабаттан тейәү",
+ "authmanager-userdoesnotexist": "\"$1\" иҫәп яҙмаһы теркәлмәгән.",
+ "authmanager-email-label": "Электрон почта адресы",
+ "authmanager-email-help": "Электрон почта адресы",
+ "authmanager-realname-label": "Ысын исемегеҙ",
+ "authprovider-resetpass-skip-label": "Ҡалдырып торорға",
+ "cannotauth-not-allowed": "Һеҙ был битте ҡуллана алмайһығыҙ.",
+ "changecredentials": "Иҫәп мәғлүмәттәрен үҙгәртеү",
+ "changecredentials-submit": "Иҫәп мәғлүмәттәрен үҙгәртеү",
+ "removecredentials": "Иҫәп мәғлүмәттәрен юйырға",
+ "removecredentials-submit": "Иҫәп мәғлүмәттәрен юйырға",
+ "credentialsform-account": "Иҫәп хужаһы"
}
"noname": "شما یک معتبرین نام کاربر مشخص نه کتت.",
"loginsuccesstitle": "ورود موفقیت آمیز",
"loginsuccess": "''''شما الان وارد {{SITENAME}} په عنوان \"$1\".'''",
- "nosuchuser": "هچ کاربری گون نام \"$1\" نیستن.\nکاربری نام حرفش په هور و مزنی حساس انت.\nوتی املايا چک کنیت یا [[Special:UserLogin/signup|نوکین حسابی شرکنیت]].",
+ "nosuchuser": "هچ کاربری گون نام \"$1\" نیستن.\nکاربری نام حرفش په هور و مزنی حساس انت.\nوتی املايا چک کنیت یا [[Special:CreateAccount|نوکین حسابی شرکنیت]].",
"nosuchusershort": "هچ کاربری گون نام \"$1\"نیستن.\nوتی املايا کنترل کنیت",
"nouserspecified": "شما باید یک نام کاربری مشخص کنیت.",
"login-userblocked": "ائ کابر بلاک بیتگ. لاگین مان سیستمء اجازت نه انت.",
"accmailtext": "یک پسوردء [[User talk:$1|$1]] پر $2 راهیگ بوت. بیت آئرا چه پیجء ''[[Special:ChangePassword|پسوردء ٹگل]]'' که لاگینء درگتء پیش دارگ بیت ٹگل دئیت.",
"newarticle": "(نوکین)",
"newarticletext": "شما رند چه یک لینکی په یک صفحه ی که هنو نیستند اتکگیت.\nپه شر کتن صفحه، شروع کن نوشتن ته جعبه جهلی(بچار [$1 صفحه کمک] په گیشترین اطلاعات).\nاگر شما اشتباهی ادانیت ته وتی بروزر دکمه ''Back'' بجن.",
- "anontalkpagetext": "----'' ای صفحه بحث انت په یک ناشناس کاربری که هنگت یک حسابی شر نه کتت یا آی ا ستفاده نه کتت. اچه ما بایدن آدرس آی پی عددی په پچاه آرگ آیی استفاده کنین.\nچوشن آدرس آی پی گون چندین کاربر استفاده بیت.\nاگه شما یک کاربر ناشناس ایت وی حس کنیت بی ربطین نظر مربوط شمی هست، لطفا [[Special:UserLogin|وارد بیت ]] یا [[Special:UserLogin/signup|حسابی شرکن]] دان چه هور بییگ گون ناسناسین کاربران پرهیز بیت.''",
+ "anontalkpagetext": "----'' ای صفحه بحث انت په یک ناشناس کاربری که هنگت یک حسابی شر نه کتت یا آی ا ستفاده نه کتت. اچه ما بایدن آدرس آی پی عددی په پچاه آرگ آیی استفاده کنین.\nچوشن آدرس آی پی گون چندین کاربر استفاده بیت.\nاگه شما یک کاربر ناشناس ایت وی حس کنیت بی ربطین نظر مربوط شمی هست، لطفا [[Special:UserLogin|وارد بیت ]] یا [[Special:CreateAccount|حسابی شرکن]] دان چه هور بییگ گون ناسناسین کاربران پرهیز بیت.''",
"noarticletext": "هنو هچ متنی ته ای صفحه نیست.\nشما تونیت [[Special:Search/{{PAGENAME}}|گردیت په عنوان صفحه]] ته دگه صفحات یا<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} گردگ په مربوطین آمار],\nیا [{{fullurl:{{FULLPAGENAME}}|action=edit}} اصلاح ای صفحه]</span>.",
"noarticletext-nopermission": "ائ تاکء رء انیگ هچ سیاهگء نه انت .\nشما توانت مان ادگر تاکان [[Special:Search/{{PAGENAME}}|ائ عنوانء رء پٹوپول بکن ات]]،\nیانکه <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} مان یکپیمیگین سیاهگان شوهاز بکن ات]</span> بلئ شما رء پر ائ پیجء اڈ کتنء اجازت نه انت.",
"missing-revision": "ویرایش #$1 چه پیجء «{{FULLPAGENAME}}» موجود نه انت.\n\nبلکین چه نوک نکتنء بابتء هزپ بیتگ انت.\nتوان ات گیشترین جزئیات رء مان [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} هزپانی سیاهگ] ودی بکن ات.",
"noname": "Ika dae tabi nakapagkaag nin sarong balidong pangaran nin paragamit.",
"loginsuccesstitle": "Matrayumpo an saimong paglaog",
"loginsuccess": "'''Ika ngunyan nakalaog na sa {{SITENAME}} bilang si \"$1\".'''",
- "nosuchuser": "Dae pang paragamit na ginagamit an pangaran na \"$1\".\nAn mga ngaran nin paragamit sensitibo gayo sa tipahan.\nPakireparo kan saimong espeling, o [[Special:UserLogin/signup|Magmukna nin bagong panindog]].",
+ "nosuchuser": "Dae pang paragamit na ginagamit an pangaran na \"$1\".\nAn mga ngaran nin paragamit sensitibo gayo sa tipahan.\nPakireparo kan saimong espeling, o [[Special:CreateAccount|Magmukna nin bagong panindog]].",
"nosuchusershort": "Mayo po tabing paragamit na an pangaran \"$1\".\nPaki-tsek an saimong espeling.",
"nouserspecified": "Kaipuhan mong magkaag nin sarong pangaran nin paragamit.",
"login-userblocked": "An paragamit na ini pinagkubkob. An paglaog dae pinagtutugutan.",
"accmailtext": "An purak na pinagpuyos na pasa-taramon para ki [[User talk:$1|$1]] ipinagpadara na sa $2. Ini mapupuwedeng pagribayan sa ''[[Special:ChangePassword|change password]]'' na pahina matapos na ika nakalaog na.",
"newarticle": "(Bàgo)",
"newarticletext": "Ika nakapagsunod sa sarong sugpon pasiring sa sarong pahina na bako pang eksistido. Tanganing makapagmukna nin pahina, magpoon sa pagpindot sa laog nin kahon sa ibaba (hilngon an [$1 pahina nin katabangan] para sa kadugangan na impormasyon).\nKun ika napasalang nakadigde, i-klik an '''ibalik''' na pindutan kan saimong kilyawan.",
- "anontalkpagetext": "----''Ini iyo an pahina kan orolayan para an sarong dae bistadong paragamit na dae pa nakapagmukna nin panindog, o dae pa nakapaggamit kaini.\nKaya kami kaipong gumamit nin numerikal na IP address sa pagbisto saiya.\nAn arog kaining IP address puwedeng maikapagheras sa nagkapirang mga paragamit.\nKun ika sarong dae pa bistadong paragamit asin mati mo na igwang irelebanteng sambit na pinanungod saimo, tabi paki [[Special:UserLogin/signup|mukna nin panindog]] or [[Special:UserLogin|maglaog ka]] tanganing malikayan an pagkaribong sa pag-iriba kan iba pang mga paragamit.''",
+ "anontalkpagetext": "----''Ini iyo an pahina kan orolayan para an sarong dae bistadong paragamit na dae pa nakapagmukna nin panindog, o dae pa nakapaggamit kaini.\nKaya kami kaipong gumamit nin numerikal na IP address sa pagbisto saiya.\nAn arog kaining IP address puwedeng maikapagheras sa nagkapirang mga paragamit.\nKun ika sarong dae pa bistadong paragamit asin mati mo na igwang irelebanteng sambit na pinanungod saimo, tabi paki [[Special:CreateAccount|mukna nin panindog]] or [[Special:UserLogin|maglaog ka]] tanganing malikayan an pagkaribong sa pag-iriba kan iba pang mga paragamit.''",
"noarticletext": "Mayo tabi sa presente nin teksto sa pahinang ini.\nIka mapuwedeng [[Special:Search/{{PAGENAME}}|maghanap para sa titulo kan pahinang ini]] sa iba pang mga pahina,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} maghanap sa magkasurundong mga talaan],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} liwaton ining pahina]</span>.",
"noarticletext-nopermission": "Mayong sa presente nin teksto an pahinang ini.\nIka mapuwedeng [[Special:Search/{{PAGENAME}}|hanapa para kaining titulo kan pahina]] sa iba pang mga pahina,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} maghanap sa magkasurundong mga talaan]</span>.",
"missing-revision": "An rebisyon #$1 kan pahina pinagngaranan na \"{{FULLPAGENAME}}\" bakong eksistido.\n\nIni pirmihan na pinagkakausa sa paagi nin pagsusunod nin luwas na petsang historiya nin kasugpunan pasiring sa sarong pahinang pinagpura na.\nAn mga detalye matatagboan sa [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} pinagpura na talaan].",
"tog-ccmeonemails": "Адпраўляць мне копіі лістоў, якія я дасылаю іншым удзельнікам",
"tog-diffonly": "Не паказваць зьмест старонкі пад параўнаньнем зьменаў",
"tog-showhiddencats": "Паказваць схаваныя катэгорыі",
- "tog-norollbackdiff": "Не паказваць зьмены пасьля выкарыстаньня функцыі адкату",
+ "tog-norollbackdiff": "Не паказваць зьмены пасьля выкананьня адкату",
"tog-useeditwarning": "Папярэджваць мяне, калі я буду пакідаць старонку рэдагаваньня зь незахаванымі зьменамі",
"tog-prefershttps": "Заўсёды карыстацца бясьпечным злучэньнем па ўваходзе ў сыстэму",
"underline-always": "Заўсёды",
"password-change-forbidden": "Вы ня можаце зьмяняць паролі ў гэтай вікі.",
"externaldberror": "Адбылася памылка аўтэнтыфікацыі з дапамогай вонкавай базы зьвестак, ці Вам не дазволена абнаўляць свой рахунак.",
"login": "Увайсьці",
+ "login-security": "Пацьвердзіце вашую асобу",
"nav-login-createaccount": "Уваход / стварэньне рахунку",
"userlogin": "Увайсьці ў сыстэму / стварыць рахунак",
"userloginnocreate": "Увайсьці",
"userlogin-resetpassword-link": "Забылі пароль?",
"userlogin-helplink2": "Дапамога з уваходам у сыстэму",
"userlogin-loggedin": "Вы ўжо ўвайшлі як {{GENDER:$1|$1}}.\nДля ўваходу пад іншым удзельнікам скарыстайцеся формай унізе.",
+ "userlogin-reauth": "Вы мусіце ўвайсьці яшчэ раз, каб пацьвердзіць, што вы — гэта {{GENDER:$1|$1}}.",
"userlogin-createanother": "Стварыць іншы рахунак",
"createacct-emailrequired": "Адрас электроннай пошты",
"createacct-emailoptional": "Адрас электроннай пошты (неабавязкова)",
"createacct-email-ph": "Увядзіце ваш адрас электроннай пошты",
"createacct-another-email-ph": "Увядзіце адрас электроннай пошты",
"createaccountmail": "Стварыць часовы адвольны пароль і даслаць яго на пазначаны адрас электроннай пошты",
+ "createaccountmail-help": "Можа выкарыстоўвацца для стварэньня рахунку для іншага чалавека бязь веданьня паролю.",
"createacct-realname": "Сапраўднае імя (неабавязкова)",
"createaccountreason": "Прычына:",
"createacct-reason": "Прычына",
"createacct-reason-ph": "Зь якой мэтай вы ствараеце іншы рахунак",
+ "createacct-reason-help": "Паведамленьне, якое паказваецца ў журнале стварэньня рахункаў",
"createacct-submit": "Стварыць рахунак",
"createacct-another-submit": "Стварыць рахунак",
+ "createacct-continue-submit": "Працягнуць стварэньне рахунку",
+ "createacct-another-continue-submit": "Працягнуць стварэньне рахунку",
"createacct-benefit-heading": "{{SITENAME}} створаная людзьмі, такімі як вы.",
"createacct-benefit-body1": "{{PLURAL:$1|праўка|праўкі|правак}}",
"createacct-benefit-body2": "{{PLURAL:$1|старонка|старонкі|старонак}}",
"nocookiesnew": "Рахунак быў створаны, але ў сыстэму Вы не ўвайшлі.\n{{SITENAME}} выкарыстоўвае файлы-кукі для ўваходу ў сыстэму.\nУ Вашым браўзэры файлы-кукі адключаныя.\nКалі ласка, дазвольце іх, а потым ўвайдзіце з новым іменем удзельніка і паролем.",
"nocookieslogin": "{{SITENAME}} выкарыстоўвае файлы-кукі для ўваходу ў сыстэму.\nУ Вашым браўзэры файлы-кукі адключаныя.\nКалі ласка, уключыце іх і паспрабуйце яшчэ раз.",
"nocookiesfornew": "Рахунак удзельніка ня быў створаны, таму што мы не змаглі пацьвердзіць яго крыніцу. \nУпэўніцеся, што ў Вас уключаныя файлы-кукі, перазагрузіце гэтую старонку і паспрабуйце зноў.",
+ "createacct-loginerror": "Рахунак быў пасьпяхова створаны, але вы ня можаце ўвайсьці аўтаматычна. Калі ласка, [[Special:UserLogin|увайдзіце ўручную]].",
"noname": "Вы пазначылі няслушнае імя ўдзельніка.",
"loginsuccesstitle": "Увайшлі ў сыстэму",
"loginsuccess": "<strong>Цяпер Вы ўвайшлі ў {{GRAMMAR:вінавальны|{{SITENAME}}}} як «$1».</strong>",
- "nosuchuser": "Удзельніка «$1» не існуе.\nВялікія і малыя літары адрозьніваюцца ў імёнах удзельнікаў.\nПраверце напісаньне альбо [[Special:UserLogin/signup|стварыце новы рахунак]].",
+ "nosuchuser": "Удзельніка «$1» не існуе.\nВялікія і малыя літары адрозьніваюцца ў імёнах удзельнікаў.\nПраверце напісаньне альбо [[Special:CreateAccount|стварыце новы рахунак]].",
"nosuchusershort": "Удзельніка зь іменем «$1» не існуе. Праверце напісаньне.",
"nouserspecified": "Вы мусіце пазначыць імя ўдзельніка.",
"login-userblocked": "{{GENDER:$1|Гэты ўдзельнік заблякаваны|Гэтая ўдзельніца заблякаваная}}. Уваход у сыстэму забаронены.",
"mailmypassword": "Скінуць пароль",
"passwordremindertitle": "Новы часовы пароль для {{GRAMMAR:родны|{{SITENAME}}}}",
"passwordremindertext": "Нехта (магчыма Вы, з IP-адрасу $1) запытаў нас даслаць новы пароль для {{GRAMMAR:родны|{{SITENAME}}}} ($4). Для ўдзельніка «$2» быў створаны часовы пароль і ён цяпер «$3». Калі гэта была Вашая ініцыятыва, Вам трэба ўвайсьці ў сыстэму і адразу зьмяніць пароль. Тэрмін дзеяньня Вашага часовага паролю — $5 {{PLURAL:$5|дзень|дні|дзён}}.\n\nКалі гэты запыт адправіў нехта іншы, альбо Вы ўзгадалі свой пароль і ўжо не жадаеце яго зьмяніць, Вы можаце праігнараваць гэты ліст і працягваць карыстацца старым паролем.",
- "noemail": "{{GENDER:$1|УдзелÑ\8cнÑ\96к «$1» не пазнаÑ\87Ñ\8bÑ\9e|УдзелÑ\8cнÑ\96Ñ\86а «$1» не пазнаÑ\87Ñ\8bла}} нÑ\96Ñ\8fкага адÑ\80аÑ\81Ñ\83 электроннай пошты.",
- "noemailcreate": "Вы павінны пазначыць слушны адрас электроннай пошты",
+ "noemail": "{{GENDER:$1|УдзелÑ\8cнÑ\96к «$1» не пазнаÑ\87Ñ\8bÑ\9e|УдзелÑ\8cнÑ\96Ñ\86а «$1» не пазнаÑ\87Ñ\8bла}} адÑ\80аÑ\81 электроннай пошты.",
+ "noemailcreate": "Вы павінныя пазначыць слушны адрас электроннай пошты.",
"passwordsent": "Новы пароль быў дасланы на адрас электроннай пошты ўдзельніка «$1».\nКалі ласка, увайдзіце ў сыстэму пасьля яго атрыманьня.",
"blocked-mailpassword": "З Вашага IP-адрасу забароненыя рэдагаваньні. Каб пазьбегнуць злоўжываньняў, з гэтага IP-адрасу забаронена аднаўляць пароль.",
"eauthentsent": "Пацьверджаньне было дасланае на пазначаны адрас электроннай пошты.\nУ лісьце ўтрымліваюцца інструкцыі, па выкананьні якіх Вы зможаце пацьвердзіць, што адрас сапраўды належыць Вам, і на гэты адрас будзе дасылацца пошта адсюль.",
- "throttled-mailpassword": "Ліст пра скіданьне паролю ўжо было даслана за {{PLURAL:$1|$1 апошнюю гадзіну|$1 апошнія гадзіны|$1 апошніх гадзінаў}}.\nДля прадухіленьня злоўжываньняў напамін будзе дасылацца не часьцей як аднойчы ў $1 {{PLURAL:$1|гадзіну|гадзіны|гадзінаў}}.",
+ "throttled-mailpassword": "Ліст пра скіданьне паролю ўжо быў дасланы за $1 {{PLURAL:$1|апошнюю гадзіну|апошнія гадзіны|апошніх гадзінаў}}.\nКаб пазьбегнуць злоўжываньняў напамін будзе дасылацца не часьцей як аднойчы за $1 {{PLURAL:$1|гадзіну|гадзіны|гадзінаў}}.",
"mailerror": "Памылка пры адпраўцы электроннай пошты: $1",
"acct_creation_throttle_hit": "Наведвальнікі гэтай вікі, якія карысталіся Вашым ІР-адрасам, ужо стварылі $1 {{PLURAL:$1|рахунак у|рахункі ў|рахункаў у}} апошнія дні, што перавышае максымальную дазволеную колькасьць за гэты пэрыяд.\nУ выніку, наведвальнікі, якія карыстаюцца гэтым ІР-адрасам, ня могуць стварыць зараз болей рахункаў.",
"emailauthenticated": "Ваш адрас электроннай пошты быў пацьверджаны $2 у $3.",
"createacct-another-realname-tip": "Сапраўднае імя паведамляць неабавязкова.\nКалі Вы яго пазначыце, яно будзе выкарыстоўвацца для пазначэньня Вашай працы.",
"pt-login": "Увайсьці",
"pt-login-button": "Увайсьці",
+ "pt-login-continue-button": "Працягваць уваход",
"pt-createaccount": "Стварыць рахунак",
"pt-userlogout": "Выйсьці",
"php-mail-error-unknown": "Узьнікла невядомая памылка ў функцыі PHP mail()",
"botpasswords-invalid-name": "Пададзенае імя ўдзельніка ня ўтрымлівае падзяляльнік для паролю робата («$1»).",
"botpasswords-not-exist": "Удзельнік «$1» ня мае паролю для робата з назвай «$2».",
"resetpass_forbidden": "Пароль ня можа быць зьменены",
+ "resetpass_forbidden-reason": "Паролі ня могуць быць зьмененыя: $1",
"resetpass-no-info": "Для непасрэднага доступу да гэтай старонкі Вам неабходна ўвайсьці ў сыстэму.",
"resetpass-submit-loggedin": "Зьмяніць пароль",
"resetpass-submit-cancel": "Скасаваць",
"accmailtext": "Створаны адвольны пароль для [[User talk:$1|$1]] быў адасланы па адрасе $2. Яго можна зьмяніць на старонцы ''[[Special:ChangePassword|зьмены паролю]]'' пасьля ўваходу.",
"newarticle": "(Новая)",
"newarticletext": "Вы прыйшлі па спасылцы на старонку, якая яшчэ не існуе.\nКаб стварыць яе, напішыце тэкст у полі ніжэй (глядзіце [$1 старонку дапамогі] для дадатковай інфармацыі).\nКалі Вы трапілі сюды памылкова, націсьніце кнопку «<strong>назад</strong>» у вашым браўзэры.",
- "anontalkpagetext": "----''Гэта старонка гутарак ананімнага ўдзельніка, які яшчэ не стварыў сабе рахунак альбо не ўжывае яго. Таму мы вымушаныя ўжываць лічбавы IP-адрас дзеля ягонай ідэнтыфікацыі. Адзін IP-адрас можа выкарыстоўвацца некалькімі ўдзельнікамі. Калі Вы — ананімны ўдзельнік і лічыце, што атрымалі не прызначаныя Вам камэнтары, калі ласка, [[Special:UserLogin/signup|стварыце рахунак]] альбо [[Special:UserLogin|увайдзіце ў сыстэму]], каб у будучыні пазьбегнуць магчымай блытаніны зь іншымі ананімнымі ўдзельнікамі.''",
+ "anontalkpagetext": "----\n<em>Гэта старонка гутарак ананімнага ўдзельніка, які яшчэ не стварыў сабе рахунак альбо не ўжывае яго.</em>\nТаму мы вымушаныя ўжываць лічбавы IP-адрас дзеля ягонай ідэнтыфікацыі. Адзін IP-адрас можа выкарыстоўвацца некалькімі ўдзельнікамі. Калі Вы — ананімны ўдзельнік і лічыце, што атрымалі не прызначаныя Вам камэнтары, калі ласка, [[Special:CreateAccount|стварыце рахунак]] альбо [[Special:UserLogin|ўвайдзіце ў сыстэму]], каб у будучыні пазьбегнуць магчымай блытаніны зь іншымі ананімнымі ўдзельнікамі.",
"noarticletext": "Цяпер тэкст на гэтай старонцы адсутнічае.\nВы можаце [[Special:Search/{{PAGENAME}}|пашукаць гэтую назву]] сярод іншых старонак, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} пашукаць у адпаведных журналах падзеяў]\nальбо [{{fullurl:{{FULLPAGENAME}}|action=edit}} стварыць гэтую старонку]</span>.",
"noarticletext-nopermission": "Цяпер на гэтай старонцы тэкст адсутнічае.\nВы можаце [[Special:Search/{{PAGENAME}}|пашукаць назву гэтай старонкі]] на іншых старонках, альбо <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} пашукаць зьвязаныя запісы ў журналах]</span>, але ў вас няма дазволу ствараць гэтую старонку.",
"missing-revision": "Вэрсія старонкі №$1 з назвай «{{FULLPAGENAME}}» не існуе.\n\nЗвычайна гэта здараецца з-за перахода па састарэлай спасылцы на старонку, якая была выдаленая.\nПадрабязнасьці можна знайсьці ў [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале выдаленьняў].",
"userpage-userdoesnotexist": "Рахунак удзельніка «<nowiki>$1</nowiki>» не зарэгістраваны. Калі ласка, удакладніце, ці жадаеце Вы стварыць/рэдагаваць гэтую старонку.",
"userpage-userdoesnotexist-view": "Рахунак «$1» ня створаны.",
"blocked-notice-logextract": "Гэты ўдзельнік у дадзены момант заблякаваны.\nАпошні запіс з журналу блякаваньняў пададзены ніжэй для даведкі:",
- "clearyourcache": "'''Заўвага:''' Каб пабачыць зьмены пасьля захаваньня, Вам можа спатрэбіцца ачысьціць кэш Вашага браўзэра. \n* '''Firefox / Safari:''' Трымайце ''Shift'' і націсьніце ''Reload'', ці націсьніце ''Ctrl-F5'' ці ''Ctrl-R'' (''⌘-R'' на Mac)\n* '''Google Chrome:''' Націсьніце ''Ctrl-Shift-R'' (''⌘-Shift-R'' на Mac)\n* '''Internet Explorer:''' Трымайце ''Ctrl'' і націсьніце ''Refresh'', ці націсьніце ''Ctrl-F5''\n* '''Opera:''' Ачысьціце кэш праз ''Tools → Preferences''",
+ "clearyourcache": "<strong>Заўвага:</strong> каб пабачыць зьмены пасьля захаваньня, Вам можа спатрэбіцца ачысьціць кэш Вашага браўзэра. \n* <strong>Firefox / Safari:</strong> трымайце <em>Shift</em> і націсьніце <em>Reload</em>, ці націсьніце <em>Ctrl-F5</em> ці <em>Ctrl-R</em> (<em>⌘-R</em> на Mac)\n* <strong>Google Chrome:</strong> націсьніце <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> на Mac)\n* <strong>Internet Explorer:</strong> трымайце <em>Ctrl</em> і націсьніце <em>Refresh</em>, ці націсьніце <em>Ctrl-F5</em>\n* <strong>Opera:</strong> перайдзіце ў <em>Menu → Settings</em> (<em>Opera → Preferences</em> на Mac), а потым у <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
"usercssyoucanpreview": "'''Падказка:''' выкарыстоўвайце кнопку «{{int:showpreview}}», каб паспрабаваць новы код CSS перад тым як яго запісаць.",
"userjsyoucanpreview": "'''Падказка:''' выкарыстоўвайце кнопку «{{int:showpreview}}», каб паспрабаваць новы код JavaScript перад тым, як яго запісаць.",
"usercsspreview": "'''Памятайце, што гэта толькі папярэдні прагляд Вашага CSS. Ён яшчэ не запісаны!'''",
"right-override-export-depth": "экспартаваньне старонак, уключаючы зьвязаныя старонкі з глыбінёй да 5",
"right-sendemail": "адпраўка электронных лістоў іншым удзельнікам",
"right-passwordreset": "прагляд электронных лістоў з ачысткай паролю",
- "right-managechangetags": "ствараць і выдаляць [[Special:Tags|меткі]] з базы зьвестак",
+ "right-managechangetags": "стварэньне і (дэ)актывацыя [[Special:Tags|метак]]",
"right-applychangetags": "дадаваць [[Special:Tags|меткі]] пры рэдагаваньні",
"right-changetags": "дадаваць і выдаляць адвольныя [[Special:Tags|меткі]] да асобных вэрсіяў і запісаў у журнале падзеяў",
+ "right-deletechangetags": "выдаленьне [[Special:Tags|метак]] з базы зьвестак",
"grant-generic": "Набор правоў «$1»",
"grant-group-page-interaction": "Узаемадзеяньне з старонкамі",
"grant-group-file-interaction": "Узаемадзеяньне з мэдыяфайламі",
"action-viewmyprivateinfo": "прагляд вашых прыватных зьвестак",
"action-editmyprivateinfo": "рэдагаваньне вашых прыватных зьвестак",
"action-editcontentmodel": "рэдагаваньне мадэлі зьместу старонкі",
- "action-managechangetags": "стварэньне і выдаленьне метак з базы зьвестак",
+ "action-managechangetags": "стварэньне і (дэ)актывацыю метак",
"action-applychangetags": "дадаваньне метак пры рэдагаваньні",
"action-changetags": "дадаваньне і выдаленьне адвольных метак да асобных вэрсіяў і запісаў у журнале падзеяў",
"nchanges": "$1 {{PLURAL:$1|зьмена|зьмены|зьменаў}}",
"upload-form-label-own-work": "Гэта мая ўласная праца",
"upload-form-label-infoform-categories": "Катэгорыі",
"upload-form-label-infoform-date": "Дата",
- "upload-form-label-own-work-message-local": "Я пацьвярджаю, што загружаю гэты файл згодна з правіламі і ліцэнзійнай палітыкай {{GRAMMAR:родны|{{SITENAME}}}}.",
- "upload-form-label-not-own-work-message-local": "Калі вы ня можаце загрузіць файл у адпаведнасьці з правіламі {{GRAMMAR:родны|{{SITENAME}}}}, калі ласка, закрыйце гэтае акно і паспрабуйце іншы мэтад.",
- "upload-form-label-not-own-work-local-local": "Вы таксама можаце паспрабаваць [[Special:Upload|старонку загрузкі па змоўчаньні]].",
- "upload-form-label-own-work-message-default": "Я разумею, што загружаю гэты файл у агульнае сховішча. Я пацьвярджаю, што раблю гэта ў адпаведнасьці з умовамі выкарыстаньня і ліцэнзійнай палітыкай.",
- "upload-form-label-not-own-work-message-default": "Калі вы ня можаце загрузіць гэты файл паводле правілаў агульнага сховішча, калі ласка, закрыйце гэты дыялёг і паспрабуйце іншы мэтад.",
- "upload-form-label-not-own-work-local-default": "Вы можаце паспрабаваць скарыстацца [[Special:Upload|старонкай загрузкі {{GRAMMAR:родны|{{SITENAME}}}}]], калі гэты файл можна туды загрузіць згодна з правіламі.",
- "upload-form-label-own-work-message-shared": "Я пацьвярджаю, што зьяўляюся ўласьнікам аўтарскіх правоў на гэты файл, і згодны незваротна перадаць гэты файл ў Вікісховішча на ўмовах ліцэнзіі [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], а таксама згодны з [https://wikimediafoundation.org/wiki/Terms_of_Use умовамі выкарыстаньня].",
- "upload-form-label-not-own-work-message-shared": "Калі вы не зьяўляецеся ўласьнікам аўтарскіх правоў на гэты файл, або вы жадаеце распаўсюджваць яго пад іншай ліцэнзіяй, можаце скарыстацца [https://commons.wikimedia.org/wiki/Special:UploadWizard Майстарам загрузкі ў Вікісховішча].",
- "upload-form-label-not-own-work-local-shared": "Вы таксама можаце скарыстацца [[Special:Upload|старонкай загрузкі {{GRAMMAR:родны|{{SITENAME}}}}]], калі правілы сайту дазваляюць загрузку такога файлу.",
+ "upload-form-label-own-work-message-generic-local": "Я пацьвярджаю, што загружаю гэты файл згодна з правіламі і ліцэнзійнай палітыкай {{GRAMMAR:родны|{{SITENAME}}}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Калі вы ня можаце загрузіць файл у адпаведнасьці з правіламі {{GRAMMAR:родны|{{SITENAME}}}}, калі ласка, закрыйце гэтае акно і паспрабуйце іншы мэтад.",
+ "upload-form-label-not-own-work-local-generic-local": "Вы таксама можаце паспрабаваць [[Special:Upload|старонку загрузкі па змоўчаньні]].",
+ "upload-form-label-own-work-message-generic-foreign": "Я разумею, што загружаю гэты файл у агульнае сховішча. Я пацьвярджаю, што раблю гэта ў адпаведнасьці з умовамі выкарыстаньня і ліцэнзійнай палітыкай.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Калі вы ня можаце загрузіць гэты файл паводле правілаў агульнага сховішча, калі ласка, закрыйце гэты дыялёг і паспрабуйце іншы мэтад.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Вы можаце паспрабаваць скарыстацца [[Special:Upload|старонкай загрузкі {{GRAMMAR:родны|{{SITENAME}}}}]], калі гэты файл можна туды загрузіць згодна з правіламі.",
"backend-fail-stream": "Немагчыма накіраваць файл $1.",
"backend-fail-backup": "Немагчыма зрабіць рэзэрвовую копію файла $1.",
"backend-fail-notexists": "Файл $1 не існуе.",
"apisandbox-dynamic-parameters-add-placeholder": "Назва парамэтру",
"apisandbox-dynamic-error-exists": "Парамэтар з назвай «$1» ужо існуе.",
"apisandbox-deprecated-parameters": "Састарэлыя парамэтры",
+ "apisandbox-fetch-token": "Аўтазапаўненьне токену",
"apisandbox-submit-invalid-fields-title": "Некаторыя палі няслушныя",
"apisandbox-submit-invalid-fields-message": "Калі ласка, выпраўце пазначаныя палі і паспрабуйце яшчэ раз.",
"apisandbox-results": "Вынікі",
"apisandbox-results-error": "Адбылася памылка пры загрузцы адказу на API-запыт: $1.",
"apisandbox-request-url-label": "URL-адрас запыту:",
"apisandbox-request-time": "Час запыту: {{PLURAL:$1|$1 мс}}",
+ "apisandbox-results-fixtoken": "Выпраўце токен і паўтарыце адпраўку",
+ "apisandbox-results-fixtoken-fail": "Памылка пры атрыманьні токену «$1».",
"apisandbox-alert-page": "Палі на гэтай старонцы няслушныя.",
"apisandbox-alert-field": "Значэньне гэтага поля зьяўляецца няслушным.",
"booksources": "Крыніцы кніг",
"changecontentmodel-title-label": "Назва старонкі",
"changecontentmodel-model-label": "Новая мадэль зьместу",
"changecontentmodel-reason-label": "Прычына:",
+ "changecontentmodel-submit": "Зьмяніць",
"changecontentmodel-success-title": "Мадэль зьместу была зьмененая",
"changecontentmodel-success-text": "Тып зьместу [[:$1]] быў зьменены.",
"changecontentmodel-cannot-convert": "Зьмест [[:$1]] ня можа быць ператвораны ў тып $2.",
"whatlinkshere-hideredirs": "$1 перанакіраваньні",
"whatlinkshere-hidetrans": "$1 уключэньні",
"whatlinkshere-hidelinks": "$1 спасылкі",
- "whatlinkshere-hideimages": "$1 спасылкі на выявы",
+ "whatlinkshere-hideimages": "$1 спасылкі на файлы",
"whatlinkshere-filters": "Фільтры",
"whatlinkshere-submit": "Перайсьці",
"autoblockid": "Аўтаматычнае блякаваньне №$1",
"Matma Rex",
"Goshaproject",
"Nemo bis",
- "SamGold"
+ "SamGold",
+ "Liashko"
]
},
"tog-underline": "Падкрэсліваць спасылкі:",
"createacct-reason-ph": "Чаму вы ствараеце іншы ўліковы запіс",
"createacct-submit": "Стварыць уліковы запіс",
"createacct-another-submit": "Стварыць уліковы запіс",
+ "createacct-continue-submit": "Працягнуць стварэнне ўліковага запісу",
"createacct-benefit-heading": "{{SITENAME}} зроблены такімі ж людзьмі, як вы.",
"createacct-benefit-body1": "{{PLURAL:$1|праўка|праўкі|правак}}",
"createacct-benefit-body2": "{{PLURAL:$1|старонка|старонкі|старонак}}",
"noname": "Вы не вызначылі правільнага імя ўдзельніка.",
"loginsuccesstitle": "Паспяховы ўваход у сістэму",
"loginsuccess": "<strong>Цяпер Вы ўвайшлі на {{SITENAME}} як \"$1\".</strong>",
- "nosuchuser": "Няма ўдзельніка з імем \"$1\". Праверце правільнасць напісання або [[Special:UserLogin/signup|стварыце новы рахунак]]. Вялікія і малыя літары ў такіх імёнах лічацца рознымі.",
+ "nosuchuser": "Няма ўдзельніка з імем \"$1\". Праверце правільнасць напісання або [[Special:CreateAccount|стварыце новы рахунак]]. Вялікія і малыя літары ў такіх імёнах лічацца рознымі.",
"nosuchusershort": "Удзельніка з імем \"$1\" не існуе. Праверце яго напісанне.",
"nouserspecified": "Вы мусіце вызначыць імя ўдзельніка.",
"login-userblocked": "Гэты карыстальнік заблакаваны. Лагін не дапускаецца.",
"createacct-another-realname-tip": "Сапраўднае імя паведамляць неабавязкова.\nКалі вы паведаміце яго, яно будзе выкарыстоўвацца для пазначэння вашага ўкладу.",
"pt-login": "Увайсці",
"pt-login-button": "Увайсці",
+ "pt-login-continue-button": "Працягнуць уваход",
"pt-createaccount": "Стварыць уліковы запіс",
"pt-userlogout": "Выйсці",
"php-mail-error-unknown": "Невядомая памылка ў функцыі PHP-пошты",
"botpasswords-invalid-name": "Паказанае імя ўдзельніка не ўтрымлівае падзяляльнік паролю робата (\"$1\").",
"botpasswords-not-exist": "Удзельнік \"$1\" не мае паролю для робата з назвай \"$2\".",
"resetpass_forbidden": "Не дазволена мяняць паролі",
+ "resetpass_forbidden-reason": "Не дазволена мяняць паролі: $1",
"resetpass-no-info": "Трэба ўвайсці ў сістэму, каб звяртацца да гэтай старонкі наўпрост.",
"resetpass-submit-loggedin": "Змяніць пароль",
"resetpass-submit-cancel": "Нічога",
"passwordreset-emailsentusername": "Калі ёсць адрас электроннай пошты, злучаны з гэтым імем удзельніка, то будзе дасланы ліст пра скід пароля.",
"passwordreset-emailsent-capture": "Ніжэй прыведзены адпраўлены ліст пра скід пароля.",
"passwordreset-emailerror-capture": "Ніжэй прыведзены створаны ліст пра скід пароля, яго адпраўка не атрымалася па прычыне: $1",
+ "passwordreset-invalideamil": "Няслушны адрас электроннай пошты",
"changeemail": "Змяніць або выдаліць адрас электроннай пошты",
"changeemail-header": "Запоўніце гэтую форму, каб змяніць свой адрас электроннай пошты. Калі хочаце выдаліць адрас электроннай пошты, злучаны з вашым уліковым запісам, пакіньце поле новага адраса электроннай пошты пустым пры адпраўцы формы.",
"changeemail-passwordrequired": "Вам трэба будзе ўвесці свой пароль, каб пацвердзіць гэта змяненне.",
"minoredit": "Дробная праўка",
"watchthis": "Назіраць за гэтай старонкай",
"savearticle": "Запісаць",
+ "publishpage": "Апублікаваць старонку",
"preview": "Перадпаказ",
"showpreview": "Як будзе",
"showdiff": "Розніца",
"accmailtext": "На адрас $2 быў дасланы згенераваны пароль для [[User talk:$1|$1]]. Ён можа быць зменены на <em>[[Special:ChangePassword|старонцы змены пароля]]</em> пасля ўваходу ў сістэму.",
"newarticle": "(Новы)",
"newarticletext": "Вы перайшлі па спасылцы на старонку, якой яшчэ няма.\nКаб яе стварыць, набярыце яе тэкст у ніжэйпаказаным акне рэдагавання (падрабязнасці гл. ў [$1 даведцы]).\nКалі вы тут выпадкова, проста націсніце <strong>назад</strong> у браўзеры.",
- "anontalkpagetext": "----''Гэта старонка размовы з ананімным удзельнікам, які або не мае свайго рахунка, або ім не карыстаўся. Таму дзеля яго ці яе ідэнтыфікацыі мы мусім выкарыстаць лічбавы IP-адрас. Такі адрас IP могуць дзяліць між сабою некалькі асоб. Калі вы ананімны ўдзельнік, і лічыце, што атрымліваеце няслушныя заўвагі,[[Special:UserLogin/signup|стварыце рахунак]] або [[Special:UserLogin|зайдзіце ў сістэму]], каб вас больш не блыталі з іншымі ананімнымі ўдзельнікамі.''",
+ "anontalkpagetext": "----\n<em>Гэта старонка размовы з ананімным удзельнікам, які або не мае свайго рахунка, або ім не карыстаўся.</em>\nТаму дзеля яго ці яе ідэнтыфікацыі мы мусім выкарыстаць лічбавы IP-адрас.\nТакі адрас IP могуць дзяліць між сабою некалькі асоб.\nКалі вы ананімны ўдзельнік, і лічыце, што атрымліваеце няслушныя заўвагі,[[Special:CreateAccount|стварыце рахунак]] або [[Special:UserLogin|зайдзіце ў сістэму]], каб вас больш не блыталі з іншымі ананімнымі ўдзельнікамі.",
"noarticletext": "Старонка не ўтрымлівае тэксту. Вы можаце [[Special:Search/{{PAGENAME}}|пашукаць гэткую назву]] ў іншых старонках ці <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ў журналах],\nабо [{{fullurl:{{FULLPAGENAME}}|action=edit}} папрацаваць з гэтай старонкай]</span>.",
"noarticletext-nopermission": "Старонка не ўтрымлівае тэксту.\nВы можаце [[Special:Search/{{PAGENAME}}|пашукаць гэткую назву]] ў іншых старонках,\nці <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ў журналах]</span>, але вы не маеце дазволу на стварэнне гэтай старонкі.",
"missing-revision": "Няма версіі #$1 у старонкі з назвай \"{{FULLPAGENAME}}\".\n\nЗвычайна такое здараецца, калі прайсці па састарэлай спасылцы з гісторыі на старонку, якая была сцёрта.\nПадрабязнасці можна пабачыць у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале сціранняў].",
"right-managechangetags": "Ствараць і выдаляць [[Special:Tags|біркі]] з базы даных",
"right-applychangetags": "Прымяняць [[Special:Tags|біркі]] са сваімі праўкамі",
"right-changetags": "Дадаваць і выдаляць адвольныя [[Special:Tags|біркі]] да асобных версій і запісаў у журнале падзей",
+ "right-deletechangetags": "Выдаляць [[Special:Tags|біркі]] з базы даных",
"grant-generic": "Набор дазволаў \"$1\"",
"grant-group-page-interaction": "Узаемадзейнічаць з старонкамі",
"grant-group-file-interaction": "Узаемадзейнічаць з медыяфайламі",
"action-viewmyprivateinfo": "бачыць свае асабістыя звесткі",
"action-editmyprivateinfo": "правіць свае асабістыя звесткі",
"action-editcontentmodel": "правіць мадэль змесціва старонкі",
- "action-managechangetags": "ствараць і выдаляць біркі з базы даных",
+ "action-managechangetags": "ствараць і (дэ)актываваць біркі",
"action-applychangetags": "прымяняць біркі з сваімі праўкамі",
"action-changetags": "дадаваць і выдаляць адвольныя біркі да асобных версій і запісаў у журнале падзей",
+ "action-deletechangetags": "выдаляць біркі з базы даных",
"nchanges": "$1 {{PLURAL:$1|змена|змены|змен}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|з часу апошняга наведвання}}",
"enhancedrc-history": "гісторыя",
"upload-form-label-own-work": "Гэта мая ўласная праца",
"upload-form-label-infoform-categories": "Катэгорыі",
"upload-form-label-infoform-date": "Дата",
- "upload-form-label-own-work-message-local": "Я пацвярджаю, што ўкладваю гэты файл згодна з правіламі і ліцэнзійнай палітыкай {{GRAMMAR:родны|{{SITENAME}}}}.",
- "upload-form-label-not-own-work-message-local": "Калі вы не можаце ўкладваць гэты файл згодна з правіламі пляцоўкі {{SITENAME}}, калі ласка, закрыйце гэта акно і паспрабуйце іншы метад.",
- "upload-form-label-not-own-work-local-local": "Вы таксама можаце паспрабаваць [[Special:Upload|прадвызначаную старонку ўкладвання]].",
- "upload-form-label-own-work-message-default": "Я разумею, што ўкладваю гэты файл у агульнае сховішча. Я пацвярджаю, што раблю гэта ў адпаведнасці з умовамі выкарыстання і ліцэнзійнай палітыкай.",
- "upload-form-label-not-own-work-message-default": "Калі вы не можаце ўкладваць гэты файл згодна з правіламі агульнага сховішча, калі ласка, закрыйце гэта акно і паспрабуйце іншы метад.",
- "upload-form-label-not-own-work-local-default": "Вы таксама можаце паспрабаваць скарыстацца [[Special:Upload|старонкай укладанняў пляцоўкі {{SITENAME}}]], калі гэты файл можна укладваць туды згодна з іх палітыкай.",
+ "upload-form-label-own-work-message-generic-local": "Я пацвярджаю, што ўкладваю гэты файл згодна з правіламі і ліцэнзійнай палітыкай {{GRAMMAR:родны|{{SITENAME}}}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Калі вы не можаце ўкладваць гэты файл згодна з правіламі пляцоўкі {{SITENAME}}, калі ласка, закрыйце гэта акно і паспрабуйце іншы метад.",
+ "upload-form-label-not-own-work-local-generic-local": "Вы таксама можаце паспрабаваць [[Special:Upload|прадвызначаную старонку ўкладвання]].",
+ "upload-form-label-own-work-message-generic-foreign": "Я разумею, што ўкладваю гэты файл у агульнае сховішча. Я пацвярджаю, што раблю гэта ў адпаведнасці з умовамі выкарыстання і ліцэнзійнай палітыкай.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Калі вы не можаце ўкладваць гэты файл згодна з правіламі агульнага сховішча, калі ласка, закрыйце гэта акно і паспрабуйце іншы метад.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Вы таксама можаце паспрабаваць скарыстацца [[Special:Upload|старонкай укладанняў пляцоўкі {{SITENAME}}]], калі гэты файл можна укладваць туды згодна з іх палітыкай.",
"backend-fail-stream": "Не атрымалася трансляваць файл $1.",
"backend-fail-backup": "Немагчыма зрабіць рэзервную копію $1.",
"backend-fail-notexists": "Файл $1 не існуе.",
"apisandbox-dynamic-parameters-add-placeholder": "Назва параметра",
"apisandbox-dynamic-error-exists": "Параметр з назвай \"$1\" ужо існуе.",
"apisandbox-deprecated-parameters": "Састарэлыя параметры",
+ "apisandbox-submit-invalid-fields-title": "Некаторыя палі недапушчальныя",
+ "apisandbox-submit-invalid-fields-message": "Калі ласка, выпраўце адзначаныя палі і паспрабуйце ізноў.",
"apisandbox-results": "Вынікі",
"apisandbox-alert-page": "Палі на гэтай старонцы недапушчальныя.",
"apisandbox-alert-field": "Значэнне гэтага поля недапушчальнае.",
"log-edit-tags": "Правіць біркі да выбраных запісаў журнала",
"checkbox-select": "Выбраць: $1",
"checkbox-all": "Усе",
+ "checkbox-none": "Нічога",
+ "checkbox-invert": "Інвертаваць",
"allpages": "Усе старонкі",
"nextpage": "Наступная старонка ($1)",
"prevpage": "Папярэдняя старонка ($1)",
"listgrouprights-namespaceprotection-header": "Абмежаванні прасторы назваў",
"listgrouprights-namespaceprotection-namespace": "Прастора назваў",
"listgrouprights-namespaceprotection-restrictedto": "Дазвол(ы), неабходныя для праўкі",
+ "listgrants-rights": "Правы",
"trackingcategories": "Катэгорыі для асочвання",
"trackingcategories-summary": "На гэтай старонцы пералічаны катэгорыі для асочвання, якія аўтаматычна напаўняюцца праграмным забеспячэннем MediaWiki. Іх можна перайменаваць, змяніўшы адпаведныя сістэмныя паведамленні ў прасторы назваў {{ns:8}}.",
"trackingcategories-msg": "Катэгорыя для асочвання",
"whatlinkshere-prev": "{{PLURAL:$1|папярэдняя|папярэднія $1}}",
"whatlinkshere-next": "{{PLURAL:$1|наступная|наступныя $1}}",
"whatlinkshere-links": "← спасылкі",
- "whatlinkshere-hideredirs": "$1 перасылак",
- "whatlinkshere-hidetrans": "$1 Ñ\83лÑ\83Ñ\87Ñ\8dннÑ\8fÑ\9e",
- "whatlinkshere-hidelinks": "$1 Ñ\81паÑ\81Ñ\8bлак",
- "whatlinkshere-hideimages": "$1 Ñ\81паÑ\81Ñ\8bлак на выявы",
+ "whatlinkshere-hideredirs": "$1 перанакіраваньні",
+ "whatlinkshere-hidetrans": "$1 Ñ\83клÑ\8eÑ\87Ñ\8dнÑ\8cнÑ\96",
+ "whatlinkshere-hidelinks": "$1 Ñ\81паÑ\81Ñ\8bлкÑ\96",
+ "whatlinkshere-hideimages": "$1 Ñ\81паÑ\81Ñ\8bлкÑ\96 на выявы",
"whatlinkshere-filters": "Фільтры",
"autoblockid": "Аўтаблакіроўка #$1",
"block": "Заблакаваць удзельніка",
"confirm-watch-top": "Дабавіць старонку ў спіс назірання",
"confirm-unwatch-button": "ОК",
"confirm-unwatch-top": "Выняць гэту старонку з вашага спіса назірання?",
+ "confirm-rollback-top": "Адкаціць праўкі гэтай старонкі?",
"quotation-marks": "«$1»",
"imgmultipageprev": "← папярэдняя старонка",
"imgmultipagenext": "наступная старонка →",
"revdelete-restricted": "пастаўленыя абмежаванні на адміністратараў",
"revdelete-unrestricted": "знятыя абмежаванні з адміністратараў",
"logentry-block-block": "$1 заблакірава{{GENDER:$2|ў|ла}} {{GENDER:$4|$3}} на перыяд $5 $6",
+ "logentry-block-unblock": "$1 {{GENDER:$2|разблакаваў|разблакавала}} {{GENDER:$4|$3}}",
"logentry-block-reblock": "$1 {{GENDER:$2|памяняў|памяняла}} настройкі блакіроўкі {{GENDER:$4|$3}} на перыяд $5 $6",
"logentry-suppress-reblock": "$1 {{GENDER:$2|памяняў|памяняла}} параметры блакіроўкі {{GENDER:$4|$3}} на перыяд $5 $6",
+ "logentry-import-interwiki": "$1 {{GENDER:$2|імпартаваў|імпартавала}} $3 з іншай вікі",
"logentry-move-move": "$1 {{GENDER:$2|перанёс|перанесла}} старонку $3 у $4",
"logentry-move-move-noredirect": "$1 {{GENDER:$2|перанёс|перанесла}} старонку $3 у $4, не пакінуўшы перасылкі",
"logentry-move-move_redir": "$1 {{GENDER:$2|перанёс|перанесла}} старонку $3 у $4 па-над перасылкаю",
"policy-url": "Project:Политика",
"portal": "Портал на общността",
"portal-url": "Проект:Портал на общността",
- "privacy": "Ð\97аÑ\89иÑ\82а на лиÑ\87ниÑ\82е данни",
+ "privacy": "Ð\9fовеÑ\80иÑ\82елноÑ\81Ñ\82",
"privacypage": "Проект:Защита на личните данни",
"badaccess": "Грешка при достъп",
"badaccess-group0": "Нямате права да извършите исканото действие.",
"noname": "Не указахте валидно потребителско име.",
"loginsuccesstitle": "Успешно влизане",
"loginsuccess": "'''Влязохте в {{SITENAME}} като „$1“.'''",
- "nosuchuser": "Не съществува потребител с име „$1“.\nПотребителските имена са чувствителни на малки и главни букви.\nПроверете изписването или [[Special:UserLogin/signup|създайте нова сметка]].",
+ "nosuchuser": "Не съществува потребител с име „$1“.\nПотребителските имена са чувствителни на малки и главни букви.\nПроверете изписването или [[Special:CreateAccount|създайте нова сметка]].",
"nosuchusershort": "Не съществува потребител с името „$1“. Проверете изписването.",
"nouserspecified": "Необходимо е да се посочи потребителско име.",
"login-userblocked": "Този потребител е блокиран. Влизането в системата не е позволено.",
"accmailtext": "Случайно генерирана парола за [[User talk:$1|$1]] беше изпратена на $2. Паролата може да бъде променена от страницата ''[[Special:ChangePassword|„Промяна на паролата“]]'' след влизане в системата.",
"newarticle": "(нова)",
"newarticletext": "Последвахте препратка към страница, която все още не съществува.\nЗа да я създадете, просто започнете да пишете в долната текстова кутия\n(вижте [$1 помощната страница] за повече информация).",
- "anontalkpagetext": "----''Това е дискусионната страница на анонимен потребител, който все още няма регистрирана сметка или не я използва, затова се налага да използваме IP-адрес, за да го идентифицираме. Такъв адрес може да се споделя от няколко потребители.''\n\n''Ако сте анонимен потребител и мислите, че тези неуместни коментари са отправени към вас, [[Special:UserLogin/signup|регистрирайте се]] или [[Special:UserLogin|влезте в системата]], за да избегнете евентуално бъдещо объркване с други анонимни потребители.''",
+ "anontalkpagetext": "----''Това е дискусионната страница на анонимен потребител, който все още няма регистрирана сметка или не я използва, затова се налага да използваме IP-адрес, за да го идентифицираме. Такъв адрес може да се споделя от няколко потребители.''\n\n''Ако сте анонимен потребител и мислите, че тези неуместни коментари са отправени към вас, [[Special:CreateAccount|регистрирайте се]] или [[Special:UserLogin|влезте в системата]], за да избегнете евентуално бъдещо объркване с други анонимни потребители.''",
"noarticletext": "Понастоящем няма текст на тази страница. Можете да [[Special:Search/{{PAGENAME}}|потърсите за заглавието на страницата]] в други страници, да <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} потърсите в съответните дневници] или [{{fullurl:{{FULLPAGENAME}}|action=edit}} да я създадете]</span>.",
"noarticletext-nopermission": "Текущо в тази страница няма текст.\nМожете да [[Special:Search/{{PAGENAME}}|потърсите заглавието на тази страница ]] в други страници или да <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} потърсите в съответните дневници]</span>, но нямате права да създадете тази страница.",
"missing-revision": "Версия #$1 на страницата „{{FULLPAGENAME}}“ не съществува.\n\nТова обикновено се дължи на препратка от историята на страницата, която е била изтрита.\nПодробности могат да бъдат открити в [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневника на изтриванията].",
"revdelete-show-file-submit": "Да",
"revdelete-selected-text": "{{PLURAL:$1|Избрана версия|Избрани версии}} от [[:$2]]:",
"logdelete-selected": "{{PLURAL:$1|Избрано събитие|Избрани събития}}:",
+ "revdelete-text-text": "Изтритите редакции ще продължат да се виждат в историята на страницата, но части от съдържанието ще бъдат публично недостъпни.",
+ "revdelete-text-others": "Другите администратори ще продължат да имат достъп до скритото съдържание и могат да го възстановят, освен ако не бъдат наложени допълнителни ограничения.",
"revdelete-confirm": "Необходимо е да потвърдите, че желаете да извършите действието, разбирате последствията и го правите според [[{{MediaWiki:Policy-url}}|политиката]].",
"revdelete-suppress-text": "Премахването трябва да се използва '''само''' при следните случаи:\n* Потенциално уязвима в правно отношение информация\n* Неподходяща лична информация\n*: ''домашни адреси и телефонни номера, номера за социално осигуряване и др.''",
"revdelete-legend": "Задаване на ограничения:",
"upload-form-label-own-work": "Това е моя собствена творба",
"upload-form-label-infoform-categories": "Категории",
"upload-form-label-infoform-date": "Дата",
- "upload-form-label-own-work-message-local": "Потвърждавам, че качвам този файл в съответствие с правилата и лицензионната политика на сайта {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Ако не можете да заредите този файл в съответствие с правилата на сайта {{SITENAME}}, моля, затворете този прозорец и опитайте друг метод.",
+ "upload-form-label-own-work-message-generic-local": "Потвърждавам, че качвам този файл в съответствие с правилата и лицензионната политика на сайта {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Ако не можете да заредите този файл в съответствие с правилата на сайта {{SITENAME}}, моля, затворете този прозорец и опитайте друг метод.",
"backend-fail-notexists": "Файлът $1 не съществува.",
"backend-fail-delete": "Файлът $1 не може да бъде изтрит.",
"backend-fail-alreadyexists": "Файлът $1 вече съществува.",
"logempty": "Дневникът не съдържа записи, отговарящи на избрания критерий.",
"log-title-wildcard": "Търсене на заглавия, започващи със",
"showhideselectedlogentries": "Промяна на видимостта на избраните записи",
- "checkbox-all": "Всички",
- "checkbox-none": "Никои",
+ "checkbox-select": "Избери: $1",
+ "checkbox-all": "всички",
+ "checkbox-none": "никои",
+ "checkbox-invert": "обърни избора",
"allpages": "Всички страници",
"nextpage": "Следваща страница ($1)",
"prevpage": "Предходна страница ($1)",
"delete-toobig": "Тази страница има голяма редакционна история с над $1 {{PLURAL:$1|версия|версии}}. Изтриването на такива страници е ограничено, за да се предотвратят евентуални поражения на {{SITENAME}}.",
"delete-warning-toobig": "Тази страница има голяма редакционна история с над $1 {{PLURAL:$1|версия|версии}}. Възможно е изтриването да наруши някои операции в базата данни на {{SITENAME}}; необходимо е особено внимание при продължаване на действието.",
"deleteprotected": "Не можете да изтриете страницата, защото е защитена.",
+ "deleting-backlinks-warning": "<strong>Внимание:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Други страници]] сочат към или включват като шаблон страницата, която се опитвате да изтриете.",
"rollback": "Отмяна на промените",
"rollbacklink": "отмяна",
"rollbacklinkcount": "отмяна на $1 {{PLURAL:$1|редакция|редакции}}",
"protect-othertime": "Друг срок:",
"protect-othertime-op": "друг срок",
"protect-existing-expiry": "Оставащо време: $2, $3",
+ "protect-existing-expiry-infinity": "Existing expiration time: безсрочно",
"protect-otherreason": "Друга/допълнителна причина:",
"protect-otherreason-op": "Друга причина",
"protect-dropdown": "* Стандартни причини за защита на страници\n** Чест обект на вандализъм\n** Чест обект на спам\n** Редакторска война\n** Страница, изискваща много сървърни ресурси",
"delete_and_move_text": "== Наложително изтриване ==\n\nЦелевата страница „[[:$1]]“ вече съществува. Искате ли да я изтриете, за да освободите място за преместването?",
"delete_and_move_confirm": "Да, искам да изтрия тази страница.",
"delete_and_move_reason": "Изтрита, за да се освободи място за преместване от „[[$1]]“",
- "selfmove": "Страницата не може да бъде преместена, тъй като целевото име съвпада с първоначалното й заглавие.",
+ "selfmove": "Страницата не може да бъде преместена, тъй като целевото име съвпада с първоначалното ѝ заглавие.",
"immobile-source-namespace": "Не могат да се местят страници в именно пространство „$1“",
"immobile-target-namespace": "Не е възможно преместването на страници в именното пространство „$1“",
"immobile-target-namespace-iw": "Страницата не може да бъде преместена под заглавие, оформено като междууики препратка.",
"sqlite-no-fts": "$1 без поддръжка на пълнотекстово търсене",
"logentry-delete-delete": "$1 {{GENDER:$2|изтри}} страницата $3",
"logentry-delete-restore": "$1 {{GENDER:$2|възстанови}} страницата $3",
+ "logentry-delete-revision": "$1 {{GENDER:$2|промени}} видимостта на {{PLURAL:$5|една редакция|$5 редакции}} в страница $3: $4",
+ "logentry-delete-event-legacy": "$1 {{GENDER:$2|промени}} видимостта на събитията от дневниците за страница $3",
"logentry-delete-revision-legacy": "$1 {{GENDER:$2|промени}} видимостта на версиите на страница $3",
"logentry-suppress-revision": "$1 тайно {{GENDER:$2|промени}} видимостта на {{PLURAL:$5|една версия|$5 версии}} на страницата $3: $4",
"logentry-suppress-revision-legacy": "$1 тайно {{GENDER:$2|промени}} видимостта на версиите на страница $3",
"revdelete-uname-hid": "скрито потребителско име",
"revdelete-restricted": "добавени ограничения за администраторите",
"revdelete-unrestricted": "премахнати ограничения за администраторите",
- "logentry-suppress-block": "$1 {{GENDER:$2|блокира}} {{GENDER:$4|$3}} за срок от $5 $6",
- "logentry-suppress-reblock": "$1 {{GENDER:$2|промени}} настройките на блокиране на {{GENDER:$4|$3}} за срок от $5 $6",
+ "logentry-block-block": "$1 блокира {{GENDER:$4|$3}} със срок на изтичане $5 $6",
+ "logentry-block-reblock": "$1 промени настройките на блокиране на {{GENDER:$4|$3}} със срок на изтичане $5 $6",
+ "logentry-suppress-block": "$1 {{GENDER:$2|блокира}} {{GENDER:$4|$3}} със срок на изтичане $5 $6",
+ "logentry-suppress-reblock": "$1 {{GENDER:$2|промени}} настройките на блокиране на {{GENDER:$4|$3}} със срок на изтичане $5 $6",
"logentry-move-move": "$1 {{GENDER:$2|премести}} страница „$3“ като „$4“",
"logentry-move-move-noredirect": "$1 {{GENDER:$2|премести}} страницата „$3“ като „$4“ без пренасочване",
"logentry-move-move_redir": "$1 {{GENDER:$2|премести}} страницата $3 като $4 (върху пренасочване)",
"Mjbmr",
"Macofe",
"Hosseinblue",
- "Dalba"
+ "Dalba",
+ "Matma Rex"
]
},
"tog-underline": "لینکانی جهلگا خط کشیتین",
"noname": "شما یک موتبرین کار زوروکی ئین نامی ئا مشخص نه کورته ئیت.",
"loginsuccesstitle": "کامیابین لوگین",
"loginsuccess": "'''شما انون گو «$1» ئی نا بی {{SITENAME}} ئی تا داخل بوته ایت.'''",
- "nosuchuser": "کار زوروکئ گۆ «$1» ئی ناما موجود نه اینت.\nکار زورکئ نام گۆ گۆنڈی یا توُهی ئا هوروپ ئان هساس اینت.\nنامی املا ئا بگنیدیت، یا [[Special:UserLogin/signup|یک نوکین کار زورکی هسابئ جۆڑ بکنیت]].",
+ "nosuchuser": "کار زوروکئ گۆ «$1» ئی ناما موجود نه اینت.\nکار زورکئ نام گۆ گۆنڈی یا توُهی ئا هوروپ ئان هساس اینت.\nنامی املا ئا بگنیدیت، یا [[Special:CreateAccount|یک نوکین کار زورکی هسابئ جۆڑ بکنیت]].",
"nosuchusershort": "هیچ کار زوروکئ بی نامئ ''$1'' ئا وجود نداریت.\nوتئ املا ئا چیک بکنیت.",
"nouserspecified": "باید یک کار زوروکئ نام مشخص بکنیت.",
"login-userblocked": "ای کار زوروک بلاک بوته، په داخل بوتینا اجازه نه اینت.",
"upload-form-label-own-work": "ائ ني جیندئ کار اینت",
"upload-form-label-infoform-categories": "تهرئان",
"upload-form-label-infoform-date": "تاریخ",
- "upload-form-label-own-work-message-local": "من ایشیرا قبولا کنین که من ائ فایلا بُرزا کنین گۆ استفاده ئی شرایطان شه جوازئ شینک بوتینا و خدماتئ سیاستان به {{SITENAME}} تا.",
+ "upload-form-label-own-work-message-generic-local": "من ایشیرا قبولا کنین که من ائ فایلا بُرزا کنین گۆ استفاده ئی شرایطان شه جوازئ شینک بوتینا و خدماتئ سیاستان به {{SITENAME}} تا.",
"backend-fail-stream": "نه توانن $1 ئی فایلا دیم دهین.",
"backend-fail-backup": "نتنوانن پُشتوانی نخسه یی په $1 فایلا جۆڑ کنن.",
"backend-fail-notexists": " $1 ئی فایل وجود نداریت.",
"logentry-delete-delete": "$1 ، $3 تاکدیما {{GENDER:$2|پاک کورت}}",
"logentry-delete-restore": "$1 ، $3 ئی تاکدیما {{GENDER:$2|پدا جۆڑ کورت}}",
"logentry-delete-event": "$1 پیدایی {{PLURAL:$5|یک مورد سیاه چال|$5 مورد سیاه چال}} ئا بئ $3 {{GENDER:$2|تا تغیر دات}}: $4",
- "logentry-delete-revision": "$1 پیدایی {{PLURAL:$5|یک نخسه|$5 نخسه}} تاکدیم $3 ئا {{GENDER:$2|تغییر دات}}: $4",
+ "logentry-delete-revision": "$1 ، $3 تاکدیمئ {{PLURAL:$5|یک نخسه|$5 نخسه}}ئی پیدایيئا {{GENDER:$2|تغییر دات}}: $4",
"logentry-suppress-delete": "$1 $3 ئی تاکدیما {{GENDER:$2| سرکوب کورت}}",
"logentry-suppress-event": "$1 پیدایی {{PLURAL:$5|یک مورد سیاه چال|$5 مورد سیاه چال}} ئا بئ $3 {{GENDER:$2|تا چیهر دات}}: $4",
- "logentry-suppress-revision": "$1 پیدایی {{PLURAL:$5|یک نخسه|$5 نخسه}} تاکدیم $3 ئا چیهراکائی {{GENDER:$2|تغییر دات}}: $4",
+ "logentry-suppress-revision": "$1 ، $3 تاکدیمئ {{PLURAL:$5|یک نخسه|$5 نخسه}}ئی پیدایيئا چیهراکائی {{GENDER:$2|تغییر دات}}: $4",
"revdelete-content-hid": "محتوائانه چیهر کورت",
"revdelete-summary-hid": "ایڈیٹ ئی خلاصه ئا چیهر کورت",
"revdelete-uname-hid": "چیهرین کار زوروکئ نام",
"tog-ccmeonemails": "हमरा द्वारा अन्य सदस्यन के भेजल गइल ईमेल के कॉपी हमरो के भेजल जाय",
"tog-diffonly": "अन्तर देखावत समय अंतर की नीचे पन्ना के सामग्री मत देखावल जाव।",
"tog-showhiddencats": "छिपल श्रेणियन के भी देखावल जाय",
- "tog-norollbackdiff": "सà¤\82पादन रà¥\8bलबà¥\88à¤\95 à¤\95à¤\87ला à¤\95à¥\87 बाद à¤\85नà¥\8dतर मत देखावल जाव",
+ "tog-norollbackdiff": "रà¥\8bलबà¥\88à¤\95 à¤\95à¤\87ला à¤\95à¥\87 बाद à¤\85à¤\82तर मत देखावल जाव",
"tog-useeditwarning": "जो हम कौनों पन्ना पर संपादन करत घरी परिवर्तन के बिना सहेजले छोड़ देईं त हमके खबर कइल जाव",
"tog-prefershttps": "जब खाता में लॉगिन करीं त हमेशा सुरक्षित कनेक्शन के प्रयोग कइल जाय",
"underline-always": "हमेशा",
"morenotlisted": "इ सूची पूर्ण नइखे।",
"mypage": "पन्ना",
"mytalk": "हमार बातचीत पन्ना",
- "anontalk": "à¤\87 à¤\86à¤\87॰पà¥\80 à¤\96ातिर वारà¥\8dता",
+ "anontalk": "बातà¤\9aà¥\80त",
"navigation": "नेविगेशन",
"and": " अउर",
"qbfind": "खोज",
"nstab-template": "टेम्पलेट",
"nstab-help": "मदद पन्ना",
"nstab-category": "श्रेणी",
+ "mainpage-nstab": "मुख्य पन्ना",
"nosuchaction": "अईसन कौनो कार्रवाई नाहि",
"nosuchactiontext": "इ यू॰आर॰एल द्वारा निर्दिष्ट क्रिया अवैध बा।\nरउआ यू॰आर॰एल गलत लिखले होखब, या कउनो गलत कड़ी के प्रयोग कइले होखब।\nइ {{SITENAME}} के सॉफ़्टवेयर में त्रुटि भी हो सकत बा।",
"nosuchspecialpage": "अईसन कौनो ख़ाश पन्ना नाहि",
"laggedslavemode": "'''चेतावनी:''' इ पन्ना पर हाल के बदलाव ना होखे के आशंका बा।",
"readonly": "डेटाबेस लॉक बा",
"enterlockreason": "लॉक करे के कारण दिहीं, साथे लॉक खुले के समय के लगभग आकलन दिहीं।",
- "readonlytext": "शायद मà¥\87à¤\82à¤\9fà¥\87ननà¥\8dस à¤\95à¥\87 à¤\9aलतà¥\87 डाà¤\9fाबà¥\87स नया सà¤\82पादन à¤\86 à¤\85नà¥\8dय बदलाव सà¥\87 लà¥\89à¤\95 à¤\95रल à¤\97à¤\88ल बा, à¤\9cà¥\87à¤\95रा बाद à¤\87 à¤\95à¥\87 सामानà¥\8dय सà¥\8dथितà¥\80 मà¥\87à¤\82 à¤\86 à¤\9cायà¥\87 à¤\95à¥\87 à¤\9aाहà¥\80à¤\82।\n\nà¤\9cà¤\89न पà¥\8dरबनà¥\8dधà¤\95 à¤\87 à¤\95à¥\87 लà¥\89à¤\95 à¤\95à¤\87लà¥\87 रहलन à¤\89 हà¤\87 à¤\95ारण दà¥\87हलà¥\87 बाड़न: $1",
+ "readonlytext": "डाà¤\9fाबà¥\87स नया सà¤\82पादन à¤\86 à¤\85नà¥\8dय बदलाव à¤\96ातिर लà¥\89à¤\95 à¤\95रल à¤\97à¤\87ल बा, शायद रà¥\81à¤\9fà¥\80न मà¥\87à¤\82à¤\9fà¥\87ननà¥\8dस à¤\95à¥\87 à¤\9aलतà¥\87, à¤\9cà¥\87à¤\95रा बाद à¤\8f à¤\95à¥\87 सामानà¥\8dय सà¥\8dथितà¥\80 मà¥\87à¤\82 à¤\86 à¤\9cायà¥\87 à¤\95à¥\87 à¤\9aाहà¥\80à¤\82।\n\nà¤\9cà¤\89न सिसà¥\8dà¤\9fम पà¥\8dरबà¤\82धà¤\95 à¤\8fह à¤\95à¥\87 लà¥\89à¤\95 à¤\95à¤\87लà¥\87 रहलन à¤\95ारण दà¥\87हलà¥\87 बाड़न à¤\95ि: $1",
"missing-article": "डेटाबास ऊ पन्ना के पाठ्य के ना खोज पाईल जौन ई के खोजे के रहल, नामित \"$1\" $2.\nई सब साधारणत: निम्नलिखीत अप्रचलित अन्तर अथवा एगो पन्ना पर इतिहास के लिंक जौन मिटा दिहल गईल बा के कारण भईल।\n\nयदि ई बात नईखे, त हो सकत बा सॉफ्टवेयर में बग पावत होखब।\nकृपया ई एगो [[Special:ListUsers/sysop|प्रबन्धक]] के यू आर एल के बारे में एगो नोट बनाके खबर करीं।",
"missingarticle-rev": "(संशोधन#: $1)",
"missingarticle-diff": "(अंतर: $1, $2)",
"nocookieslogin": "{{SITENAME}} प्रयोगकर्ता लोग के खाता में प्रवेश करावे खातिर कुकिज के प्रयोग करेला।\nराउर कुकिज असक्षम बा।\nकृपया उ के सक्षम करीं आ फिर से कोशिश करीं",
"nocookiesfornew": "स्रोत के पुष्टि ना हो पावे के कारण इ खाता निर्मित ना करल गइल। \nसुनिश्चित करीं कि रउआ कुकीज़ सक्षम कइले बानी, पृष्ठ के पुनः लोड करीं आ पुनः प्रयास करीं।",
"noname": "रउआ उपयुक्त प्रयोगकर्ता नाम नईखीं निर्दिष्ट कईले।",
- "loginsuccesstitle": "à¤\96ाता पà¥\8dरवà¥\87श मà¥\87à¤\82 सफल",
+ "loginsuccesstitle": "लà¥\89à¤\97िन पà¥\82रा",
"loginsuccess": "''' \"$1\" के रुप में रउआ {{SITENAME}} में अब प्रवेश कर चुकल बानी।'''",
- "nosuchuser": "\"$1\" नाम सà¥\87 à¤\95à¥\8cनà¥\8b पà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dता नà¤\88à¤\96न।\nपà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dता नाम सà¤\82वà¥\87दनशà¥\80ल मामला बा।\nशबà¥\8dद-वरà¥\8dतनà¥\80 à¤\95à¥\87 à¤\9cाà¤\81à¤\9a à¤\95रà¥\80à¤\82, à¤\86 à¤\9aाहà¥\87 [[Special:UserLogin/signup|एगो नया खाता बनाईं]]।",
+ "nosuchuser": "\"$1\" नाà¤\81व à¤\95à¥\87 à¤\95à¥\8cनà¥\8b पà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dता नà¤\87à¤\96न।\nपà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dता नाम सà¤\82वà¥\87दनशà¥\80ल मामला बा।\nशबà¥\8dद à¤\86 à¤\87सà¥\8dपà¥\87लिà¤\82à¤\97 à¤\95à¥\87 à¤\9cाà¤\81à¤\9a à¤\95रà¥\80à¤\82, या [[Special:CreateAccount|एगो नया खाता बनाईं]]।",
"nosuchusershort": "ई नाम से कौनो प्रयोगकर्ता नईखन \"$1\".\nआपन शब्द-वर्तनी के जाँच करीं।",
"nouserspecified": "रउआ एगो प्रयोगकर्ता नाम निर्दिष्ट करे के बा।",
"login-userblocked": "ई प्रयोगकर्ता के खाता निष्क्रिय हो चुकल बा। प्रवेश के आज्ञा नईखे।",
"wrongpasswordempty": "गुप्त-शब्द खाली बा। कृपया फिर से कोशिश करीं।",
"passwordtooshort": "गुप्त-शब्द कम से कम {{PLURAL:$1|1 अक्षर|$1 अक्षर}} के होवे के चाहीं।",
"passwordtoolong": "गुप्त-शब्द {{PLURAL:$1|$1 अक्षर}} से अधिक लमहर नइखे हो सकत।",
+ "passwordtoopopular": "अक्सरहा बीछल जाए वाला पासवर्ड ना इस्तेमाल होखी। कौनों अउरी खास अलग टाइप के पासवर्ड चुनीं।",
"password-name-match": "राउर गुप्त-शब्द राउर प्रयोगकर्ता नाम से अलग होवे के चाहीं।",
"password-login-forbidden": "इस सदस्यनाम आ गुप्तशब्द के प्रयोग वर्जित बा।",
"mailmypassword": "गुप्तशब्द रिसेट करीं",
"accmailtext": "[[User talk:$1|$1]] खातिर एगो यंत्र जनित गुप्तशब्द $2 के भेज दिहल गइल बा। खाता में प्रवेश कइला के बाद इ '''[[Special:ChangePassword|गुप्तशब्द बदल लीं]]'' वाला पन्ना पर बदलल जा सकत बा।",
"newarticle": "(नया)",
"newarticletext": "रउआ एगो अइसन कड़ी के पन्ना के अनुसरण कइले बानी जवन अभी तक उपलब्ध नइखे।\nपन्ना बनावे खातिर, नीचे के बाकस में टाइप करे के शुरु करीं (ज्यादा जानकारी खातिर देखीं [$1 मदद पन्ना])।\nयदि रउआ अहिजा गलती से आ गइल बानी त, आपन ब्राउजर के '''बैक''' (Back) बटन दबाईं!",
- "anontalkpagetext": "----''इ वार्ता पन्ना उन अनाम सदस्यन खातिर बा जिन्हन के या त खाता नइखे खोलल गइल या खाता के प्रयोग नइखन करत।\nएहि खातिर उन्हन के पहिचान खातिर हमनी के उनकर आइ॰पी पता के प्रयोग करे के पड़ेला।\nआइ॰पी पता कई सदस्यन खातिर साझा हो सकत बा।\nयदि आप एगो अनाम सदस्य बानी अउर आपके लागत बा कि आपके बारे में अप्रासंगिक टीका टिप्पणी करल गइल बा त कृपया [[Special:UserLogin/signup|सदस्यता लिहीं]] या [[Special:UserLogin|सत्रारंभ करीं]] ताकि अन्य अनाम सदस्यन में से आपके अलग से पहिचानल जा सके।''",
+ "anontalkpagetext": "----''इ वार्ता पन्ना उन अनाम सदस्यन खातिर बा जिन्हन के या त खाता नइखे खोलल गइल या खाता के प्रयोग नइखन करत।\nएहि खातिर उन्हन के पहिचान खातिर हमनी के उनकर आइ॰पी पता के प्रयोग करे के पड़ेला।\nआइ॰पी पता कई सदस्यन खातिर साझा हो सकत बा।\nयदि आप एगो अनाम सदस्य बानी अउर आपके लागत बा कि आपके बारे में अप्रासंगिक टीका टिप्पणी करल गइल बा त कृपया [[Special:CreateAccount|सदस्यता लिहीं]] या [[Special:UserLogin|सत्रारंभ करीं]] ताकि अन्य अनाम सदस्यन में से आपके अलग से पहिचानल जा सके।''",
"noarticletext": "ए पन्ना मे अभी ले कौनों सामग्री नइखे। \nरउआ दुसरा पन्ना में [[Special:Search/{{PAGENAME}}|ए टाइटिल के खोज]] कर सकत बानीं।",
"noarticletext-nopermission": "ए पन्ना मे अभी कौनों सामग्री नइखे।\nरउआँ दुसरा पन्ना में [[Special:Search/{{PAGENAME}}|ए टाइटिल के खोज]] कर सकत बानीं,\nया <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} या संबंधित लॉग खोज सकत बानी]</span>, बाकी रउआ के ई पन्ना बनावे के परमीशन नइखे।",
"missing-revision": "\"{{FULLPAGENAME}}\" पन्ना के संशोधन #$1 उपलब्ध नइखे।\n\nसाधारण रुप से इ एगो हटावल गइल पन्ना के पुरान लिंक पर क्लिक कइला से होखेला।\nअधिक जानकारी खातिर आप [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} हटावे के लॉग] देख सकत बानी।",
"noname": "Ngaran pamakai nang Pian ajuakan kada sah.",
"loginsuccesstitle": "Kulihan babuat log",
"loginsuccess": "'''Pian parhatan ni babuat log dalam {{SITENAME}} sawagai \"$1\".'''",
- "nosuchuser": "Kadada pamakai bangaran \"$1\".\nNgaran pamakai adalah kasus marinci.\nLihati pulang ijaan Pian, atawa [[Special:UserLogin/signup|ulah sabuting akun hanyar]]",
+ "nosuchuser": "Kadada pamakai bangaran \"$1\".\nNgaran pamakai adalah kasus marinci.\nLihati pulang ijaan Pian, atawa [[Special:CreateAccount|ulah sabuting akun hanyar]]",
"nosuchusershort": "Kadada pamakai bangaran \"$1\".\nLihati pulang ijaan Pian.",
"nouserspecified": "Pian harus ma'ajuakan sabuting ngaran pamakai.",
"login-userblocked": "Pamakai naya diblukir. Babuat log kada dibulihakan.",
"accmailtext": "Sabuting katasunduk babarang gasan [[User talk:$1|$1]] sudah dikirim ka $2.\n\nKatasunduk gasan pamakai hanyar nangini kawa diubah pintang tungkaran ''[[Special:ChangePassword|ubah katasunduk]]'' wayah babuat log.",
"newarticle": "(Hanyar)",
"newarticletext": "Pian maumpati sabuah tautan ka tungkaran nang baluman ada lagi. Gasan maulah tungkaran, mulai ja mangatik pada kutak di bawah (lihati [$1 tungkaran patulung] gasan panjalasan labih). Amun Pian ka sia cagaran tasalah, klik picikan '''back''' di panjalajah web Pian.",
- "anontalkpagetext": "----''Ngini adalah tungkaran pamandiran gasan pamakai kada bangaran nang baluman ma-ulah akun pulang, atawa kada mamakainya. Kami tapaksa mamakai numurik alamat IP hagan maminanduinya.\nAlamat IP nangkaini kawaai dipuruk ulih babarapa pamakai.\nAmun Pian adalah pamuruk kada bangaran wan marasa kumin nang kada pas ta ka Pian, muhun [[Special:UserLogin/signup|ulah sabuah akun]] or [[Special:UserLogin|babuat log]] hagan mahindari kabingungan awan pamuruk kada bangaran lain kaina.",
+ "anontalkpagetext": "----''Ngini adalah tungkaran pamandiran gasan pamakai kada bangaran nang baluman ma-ulah akun pulang, atawa kada mamakainya. Kami tapaksa mamakai numurik alamat IP hagan maminanduinya.\nAlamat IP nangkaini kawaai dipuruk ulih babarapa pamakai.\nAmun Pian adalah pamuruk kada bangaran wan marasa kumin nang kada pas ta ka Pian, muhun [[Special:CreateAccount|ulah sabuah akun]] or [[Special:UserLogin|babuat log]] hagan mahindari kabingungan awan pamuruk kada bangaran lain kaina.",
"noarticletext": "Parhatan ni kadada naskah di tungkaran ngini.\nPian kawa [[Special:Search/{{PAGENAME}}|manggagai gasan judul ngini]] pintang tungkaran lain,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} manggagai log barait].</span>,\natawa [{{fullurl:{{FULLPAGENAME}}|action=edit}} mambabak tungkaran ngini]</span>.",
"noarticletext-nopermission": "Parhatan ni kadada naskah di tungkaran ngini.\nPian kawa [[Special:Search/{{PAGENAME}}|manggagai gasan judul ngini]] pintang tungkaran lain,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} manggagai log barait].</span>.",
"userpage-userdoesnotexist": "Akun pamakai \"<nowiki>$1</nowiki>\" kada tadaptar.\nMuhun pariksa/ditukui amun Pian handak maulah/mambabak tungkaran ngini.",
"Aashaa",
"Sayma Jahan",
"Macofe",
- "Bodhisattwa"
+ "Bodhisattwa",
+ "Matma Rex"
]
},
"tog-underline": "সংযোগগুলির নিচে দাগ দেখানো হোক:",
"tog-watchdefault": "আমার সম্পাদিত পাতা এবং ফাইলগুলো আমার নজরতালিকায় যোগ করা হোক",
"tog-watchmoves": "আমার স্থানান্তরিত পাতা এবং ফাইলগুলো আমার নজরতালিকায় যোগ করা হোক",
"tog-watchdeletion": "আমার অপসারিত পাতা এবং ফাইলগুলো আমার নজর তালিকায় যোগ করা হোক",
+ "tog-watchuploads": "আমার নজরতালিকায় আমার আপলোড করা নতুন ফাইল যোগ কর",
"tog-watchrollback": "আমার দ্বারা রোলব্যাক করা পাতা আমার নজরতালিকায় যোগ করা হোক",
"tog-minordefault": "শুরুতেই সব সম্পাদনাকে অনুল্লেখ্য বলে চিহ্নিত করা হোক",
"tog-previewontop": "সম্পাদনা বাক্সের আগে প্রাকদর্শন দেখানো হোক",
"filereadonlyerror": "\"$1\" ফাইলটিকে পরিবর্তন করা সম্ভব হচ্ছে না কারণ \"$2\" ফাইল সংগ্রহস্থল শুধুমাত্র-পঠন মোডে আছে।\n\nসিস্টেম প্রশাসক যিনি এটি বন্ধ করেছেন তিনি এই ব্যাখ্যা দিয়েছেন: \"$3\"।",
"invalidtitle-knownnamespace": "অবৈধ শিরোনাম, যেখানে নামস্থান \"$2\" এবং লেখা হয়েছে \"$3\"",
"invalidtitle-unknownnamespace": "অবৈধ শিরোনাম, যেখানে ব্যবহৃত হয়েছে অপরিচিত নামস্থান সংখ্যা $1 এবং লেখা হয়েছে \"$2\"",
- "exception-nologin": "লà¦\97à¦\87ন à¦\95রা হয়নি",
+ "exception-nologin": "পà§\8dরবà§\87শ à¦\95রà§\87ন নি",
"exception-nologin-text": "এই কাজ করা বা পাতাটি দেখার জন্য অনুগ্রহ করে প্রবেশ করুন।",
"exception-nologin-text-manual": "অনুগ্রহ করে এই পাতা দেখতে অথবা পরিবর্তন করতে $1 করুন।",
"virus-badscanner": "ভুল কনফিগারেশন: অজ্ঞাত ভাইরাস স্কেনার: ''$1''",
"password-change-forbidden": "আপনি এই উইকিতে পাসওয়ার্ড পরিবর্তন করতে পারবেন না।",
"externaldberror": "হয় কোন বহিঃস্থ যাচাইকরণ ডাটাবেজ ত্রুটি ঘটেছে অথবা আপনার বহিঃস্থ অ্যাকাউন্ট হালনাগাদ করার অনুমতি নেই।",
"login": "প্রবেশ",
+ "login-security": "আপনার পরিচয় যাচাই করুন",
"nav-login-createaccount": "প্রবেশ/নতুন অ্যাকাউন্ট",
"userlogin": "প্রবেশ/নতুন অ্যাকাউন্ট",
"userloginnocreate": "প্রবেশ",
"createaccount": "নতুন অ্যাকাউন্ট খুলুন",
"gotaccount": "আপনার কি ইতিমধ্যে একটি অ্যাকাউন্ট তৈরি করা আছে? '''$1''' করুন।",
"gotaccountlink": "প্রবেশ",
- "userlogin-resetlink": "à¦\86পনার লà¦\97à¦\87নà§\87র বিসà§\8dতারিত তথ্যাদি ভুলে গেছেন?",
+ "userlogin-resetlink": "à¦\86পনার পà§\8dরবà§\87শà¦\95রণà§\87র তথ্যাদি ভুলে গেছেন?",
"userlogin-resetpassword-link": "পাসওয়ার্ড ভুলে গেছেন?",
- "userlogin-helplink2": "লগইন সংক্রান্ত সাহায্য",
- "userlogin-loggedin": "আপনি বর্তমানে {{GENDER:$1|$1}} হিসাবে লগইন আছেন।\nঅন্য ব্যবহারকারী নামে লগইন করতে চাইলে নিচের ফর্মটি ব্যবহার করুন।",
+ "userlogin-helplink2": "প্রবেশ সংক্রান্ত সাহায্য",
+ "userlogin-loggedin": "আপনি বর্তমানে {{GENDER:$1|$1}} হিসাবে প্রবেশরত আছেন।\nঅন্য ব্যবহারকারী নামে প্রবেশ করতে চাইলে নিচের ফর্মটি ব্যবহার করুন।",
+ "userlogin-reauth": "আপনি যে {{GENDER:$1|$1}} তা যাচাই করতে আপনাকে আবার অবশ্যই প্রবেশ করতে হবে।",
"userlogin-createanother": "আরেকটি অ্যাকাউন্ট তৈরি করুন",
"createacct-emailrequired": "ইমেইল ঠিকানা",
"createacct-emailoptional": "ইমেইল ঠিকানা (ঐচ্ছিক)",
"noname": "আপনি সঠিক ব্যবহারকারী নাম নির্দিষ্ট করেননি।",
"loginsuccesstitle": "প্রবেশ করেছেন",
"loginsuccess": "<strong>আপনি এইমাত্র \"$1\" নামে {{SITENAME}}-তে প্রবেশ করেছেন।</strong>",
- "nosuchuser": "\"$1\" নামে কোন ব্যবহারকারী নেই।\nব্যবহারকারী নামের আকার সংবেদনশীল।\nআপনার বানান পরীক্ষা করে দেখুন, অথবা [[Special:UserLogin/signup|নতুন একটি অ্যাকাউন্ট খুলুন]]।",
+ "nosuchuser": "\"$1\" নামে কোন ব্যবহারকারী নেই।\nব্যবহারকারী নামের আকার সংবেদনশীল।\nআপনার বানান পরীক্ষা করে দেখুন, অথবা [[Special:CreateAccount|নতুন একটি অ্যাকাউন্ট খুলুন]]।",
"nosuchusershort": "\"$1\" নামের কোন ব্যবহারকারী নেই। নামের বানান পরীক্ষা করুন।",
"nouserspecified": "আপনাকে অবশ্যই ব্যবহারকারী নাম নির্দিষ্ট করতে হবে।",
"login-userblocked": "এই ব্যবহারকারীকে বাধা দেওয়া হয়েছে। প্রবেশ সম্ভব নয়।",
"user-mail-no-addy": "কোনো ইমেইল ঠিকানা ছাড়াই ইমেইল করার চেষ্টা করা হয়েছে।",
"user-mail-no-body": "অত্যান্ত সংক্ষিপ্ত অথবা কোনো তথ্য ছাড়াই ইমেইল পাঠানোর চেষ্টা করা হয়েছিল।",
"changepassword": "পাসওয়ার্ড পরিবর্তন",
- "resetpass_announce": "লà¦\97à¦\87ন করার জন্য আপনাকে অবশ্যই এনটি নতুন পাসওয়ার্ড নির্ধারণ করতে হবে।",
+ "resetpass_announce": "পà§\8dরবà§\87শ করার জন্য আপনাকে অবশ্যই এনটি নতুন পাসওয়ার্ড নির্ধারণ করতে হবে।",
"resetpass_text": "<!-- এখানে লেখা যোগ করুন -->",
"resetpass_header": "পাসওয়ার্ড পরিবর্তন করো",
"oldpassword": "পুরনো পাসওয়ার্ড:",
"botpasswords-deleted-body": "ব্যবহারকারী \"$2\"-এর \"$1\" নামের বটের জন্য বট পাসওয়ার্ড মুছে ফেলা হয়েছিল।",
"botpasswords-no-provider": "BotPasswordsSessionProvider উপলব্ধ নয়।",
"resetpass_forbidden": "পাসওয়ার্ড পরিবর্তন করা সম্ভব নয়",
- "resetpass-no-info": "এই পাতাটিতে সরাসরি প্রবেশাধিকার পেতে আপনাকে অবশ্যই লগইন করতে হবে।",
+ "resetpass_forbidden-reason": "পাসওয়ার্ড পরিবর্তন করা যাবে না: $1",
+ "resetpass-no-info": "এই পাতাটিতে সরাসরি প্রবেশাধিকার পেতে আপনাকে অবশ্যই প্রবেশ করতে হবে।",
"resetpass-submit-loggedin": "পাসওয়ার্ড পরিবর্তন",
"resetpass-submit-cancel": "বাতিল",
"resetpass-wrong-oldpass": "ভুল অস্থায়ী অথবা বর্তমান পাসওয়ার্ড।\nসম্ভবতঃ আপনি ইতোমধ্যেই আপনার পাসওয়ার্ডটি পরিবর্তন করেছেন অথবা একটি নতুন অস্থায়ী পাসওয়ার্ডের জন্য অনুরোধ করেছেন।",
"resetpass-recycled": "অনুগ্রহ করে বর্তমানে ব্যবহার করছেন এমন পাসওয়ার্ডের পরিবর্তে নতুন একটি পাসওয়ার্ড নির্ধারণ করুন।",
- "resetpass-temp-emailed": "সাময়িà¦\95à¦à¦¾à¦¬à§\87 বà§\8dযবহার à¦\95রার à¦\95à§\8bড দিয়à§\87 à¦\86পনি লà¦\97à¦\87ন à¦\95রà§\87à¦\9bà§\87ন।\nলà¦\97à¦\87ন করার জন্য আপনাকে অবশ্যই একটি নতুন পাসওয়ার্ড নির্ধারন করতে হবে:",
+ "resetpass-temp-emailed": "à¦\86পনি à¦\87মà§\87à¦\87লà¦\95à§\83ত সাময়িà¦\95 à¦\95à§\8bড দিয়à§\87 পà§\8dরবà§\87শ à¦\95রà§\87à¦\9bà§\87ন।\nপà§\8dরবà§\87শ করার জন্য আপনাকে অবশ্যই একটি নতুন পাসওয়ার্ড নির্ধারন করতে হবে:",
"resetpass-temp-password": "অস্থায়ী পাসওয়ার্ড:",
"resetpass-abort-generic": "পাসওয়ার্ড পরিবর্তন একটি এক্সটেনশনের কারণে স্থগিত করা হয়েছে।",
"resetpass-expired": "আপনার পাসওয়ার্ডের মেয়াদ উত্তীর্ণ হয়েছে। অনুগ্রহ করে নতুন পাসওয়ার্ড নির্ধারণ করুন।",
"passwordreset-emailsentusername": "যদি এই ব্যবহারকারী নামের সাথে ই-মেইল ঠিকানা সংযুক্ত করা থাকে, তাহলে একটি পাসওয়ার্ড বদলের ইমেইল পাঠানো হবে।",
"passwordreset-emailsent-capture": "স্মরণ করিয়ে দেয়ার জন্য একটি ইমেইল করা হয়েছে, যা নিচে দেখানো হচ্ছে।",
"passwordreset-emailerror-capture": "স্মরণ করিয়ে দেয়ার জন্য একটি ইমেইল তৈরী করা হয়েছিল, যা নিচে দেখানো হচ্ছে, তবে $1 {{GENDER:$2|ব্যবহারকারীকে}} এটি পাঠানো যায়নি!",
+ "passwordreset-invalideamil": "ভুল ইমেইল ঠিকানা",
"changeemail": "ই-মেইল ঠিকানা পরিবর্তন বা বাতিল",
"changeemail-header": "আপনার ইমেল ঠিকানা পরিবর্তন করতে এই ফরমটি পূরণ করুন। আপনি যদি আপনার একাউন্ট থেকে যে কোন ইমেল ঠিকানার এসোসিয়েশন অপসারণ করতে চান, তাহলে ফরমটি জমা দেওয়ার সময় নতুন ইমেইল ঠিকানা খালি রাখুন।",
"changeemail-passwordrequired": "এই পরিবর্তন নিশ্চিত করতে আপনাকে আপনার পাসওয়ার্ড লিখতে হবে।",
- "changeemail-no-info": "à¦\8fà¦\87 পাতাà¦\9fিতà§\87 সরাসরি পà§\8dরবà§\87শাধিà¦\95ার পà§\87তà§\87 à¦\86পনাà¦\95à§\87 à¦\85বশà§\8dযà¦\87 লà¦\97à¦\87ন করতে হবে।",
+ "changeemail-no-info": "à¦\8fà¦\87 পাতাà¦\9fিতà§\87 সরাসরি পà§\8dরবà§\87শাধিà¦\95ার পà§\87তà§\87 à¦\86পনাà¦\95à§\87 à¦\85বশà§\8dযà¦\87 পà§\8dরবà§\87শ করতে হবে।",
"changeemail-oldemail": "বর্তমান ই-মেইল ঠিকানা:",
"changeemail-newemail": "নতুন ই-মেইল ঠিকানা:",
"changeemail-none": "(কিছু নাই)",
"changeemail-submit": "ই-মেইল পরিবর্তন",
"changeemail-throttled": "আপনি পরপর বেশ কয়েকবার প্রবেশের চেষ্টা করেছেন। পুনরায় চেষ্টা করার পূর্বে অনুগ্রহ করে $1 অপেক্ষা করুন।",
"changeemail-nochange": "দয়া করে একটি ভিন্ন নতুন ইমেইল ঠিকানা লিখুন।",
- "resettokens": "রিসà§\87à¦\9f à¦\9fà§\8bà¦\95à§\87ন",
- "resettokens-text": "à¦\86পনি à¦\9fà§\8bà¦\95à§\87ন রিসà§\87à¦\9f করতে পারেন, যা অ্যাকাউন্টের সাথে সম্পর্কিত আপনার ব্যক্তিগত তথ্য দেখার কাজে ব্যবহার করা হয়।",
- "resettokens-no-tokens": "রিসà§\87à¦\9f করার মত কোনো টোকেন নেই।",
+ "resettokens": "à¦\9fà§\8bà¦\95à§\87ন পà§\81নà¦\83সà§\8dথাপন à¦\95রà§\81ন",
+ "resettokens-text": "à¦\86পনি à¦\9fà§\8bà¦\95à§\87ন পà§\81নà¦\83সà§\8dথাপন করতে পারেন, যা অ্যাকাউন্টের সাথে সম্পর্কিত আপনার ব্যক্তিগত তথ্য দেখার কাজে ব্যবহার করা হয়।",
+ "resettokens-no-tokens": "পà§\81নà¦\83সà§\8dথাপন করার মত কোনো টোকেন নেই।",
"resettokens-tokens": "টোকেন:",
"resettokens-token-label": "$1 (বর্তমান: $2)",
"resettokens-watchlist-token": "ওয়েব ফিড (Atom/RSS) টোকেন পরিবর্তনের জন্য [[Special:Watchlist|নজরতালিকায় থাকা পাতাগুলোতে পরিবর্তন এসেছে]]",
"minoredit": "এটি একটি অনুল্লেখ্য সম্পাদনা",
"watchthis": "এই পাতাটি নজরে রাখুন",
"savearticle": "সংরক্ষণ",
+ "publishpage": "পাতা প্রকাশ করুন",
"preview": "প্রাকদর্শন",
"showpreview": "প্রাকদর্শন",
"showdiff": "পরিবর্তনসমূহ",
"blankarticle": "<strong>সতর্ক বার্তা:</strong> আপনি একটি খালি পাতা তৈরী করতে যাচ্ছেন।\nআপনি যদি পুনরায় \"{{int:savearticle}}\" বাটন ক্লিক করেন তাহলে, পাতাটি তৈরী হবে যেখানে কোনো তথ্য লেখা নেই।",
"anoneditwarning": "<strong>সতর্কতা:</strong> আপনি বর্তমানে প্রবেশ করেননি। যদি আপনি সম্পাদনা করেন এই পাতার সম্পাদনার ইতিহাসে আপনার আইপি ঠিকানা সার্বজনীনভাবে সংরক্ষিত হবে। যদি আপনি <strong>[$1 প্রবেশ করেন]</strong> বা <strong>[$2 একটি অ্যাকাউন্ট তৈরি করেন]</strong>, তাহলে আপনি আপনার আইপি ঠিকানা গোপন রাখতে পারবেন ও অন্যান্য অনেক কিছু সুবিধা পাবেন।",
- "anonpreviewwarning": "আপনি লগ ইন করেননি। এই পাতার সম্পাদনার ইতিহাসে আপনার আইপি সংখ্যা সংরক্ষিত হবে।",
+ "anonpreviewwarning": "<em>আপনি প্রবেশ করেননি। সম্পাদনা করলে এই পাতার সম্পাদনার ইতিহাসে আপনার আইপি ঠিকানা সংরক্ষিত হবে।</em>",
"missingsummary": "'''খেয়াল করুন''': আপনি কিন্তু সম্পাদনার সারাংশ দেননি। আবার যদি \"সংরক্ষণ\" বোতামে ক্লিক করেন, তাহলে ঐ সারাংশ বাক্যটি ছাড়াই আপনার সম্পাদনা সংরক্ষিত হবে।",
"selfredirect": "<strong>সতর্কতা:</strong> আপনি এই পাতাকে এর নিজের দিকে পুনঃনির্দেশিত করছেন।\nআপনাকে পুনঃনির্দেশিত করার জন্য হয় ভুল লক্ষ্য নির্দিষ্ট করেছেন, অথবা আপনি ভুল পাতা সম্পাদনা করছেন।\nআপনি যদি আবার \"{{int:savearticle}}\" ক্লিক করেন, পুনর্নির্দেশ যেকোনোভাবেই হোক তৈরি করা হবে।",
"missingcommenttext": "দয়া করে নিচে মন্তব্য যোগ করুন।",
"accmailtext": "[[User talk:$1|$1]] এর জন্য দৈব ভাবে উৎপন্ন শব্দ চাবি $2 এ পাঠানো হয়েছে।\nলগ-ইন করার পর ''[[Special:ChangePassword|পাসওয়ার্ড পরিবর্তন]]'' পাতা থেকে এটি পরিবর্তন করা যাব।",
"newarticle": "(নতুন)",
"newarticletext": "আপনি এমন একটি লিংক অনুসরণ করছেন, যা নেই।\nপাতাটি তৈরি করতে, নিচের বাক্সে তা টাইপ করা শুরু করুন (আরও তথ্য জানতে [$1 সহায়িকা পাতা] দেখুন)।\nআপনি যদি ভুল করে এখানে এসে থাকেন, তাহলে আপনার ব্রাউজারের '''back''' বোতাম ক্লিক করুন।",
- "anontalkpagetext": "----''এটি একটি বেনামী ব্যবহারকারীর আলাপের পাতা, যিনি এখনও কোন অ্যাকাউন্ট তৈরি করেননি, কিংবা তিনি অ্যাকাউন্টটি ব্যবহার করছেন না।\nআমরা তাই সাংখ্যিক আইপি ঠিকানা ব্যবহার করে তাঁকে শনাক্ত করছি।\nএকাধিক ব্যবহারকারী এরকম একটি আইপি ঠিকানা ব্যবহার করতে পারেন।\nআপনি যদি একজন বেনামী ব্যবহারকারী হয়ে থাকেন এবং যদি অনুভব করেন যে আপনার প্রতি অপ্রাসঙ্গিক মন্তব্য করা হয়েছে, তাহলে অন্যান্য বেনামী ব্যবহারকারীর সাথে ভবিষ্যতে বিভ্রান্তি এড়াতে অনুগ্রহ করে [[Special:UserLogin/signup|একটি অ্যাকাউন্ট তৈরি করুন]] অথবা [[Special:UserLogin|অ্যাকাউন্টে প্রবেশ করুন]]।''",
+ "anontalkpagetext": "----\n<em>এটি একটি বেনামী ব্যবহারকারীর আলাপের পাতা, যিনি এখনও কোন অ্যাকাউন্ট তৈরি করেননি, কিংবা তিনি অ্যাকাউন্টটি ব্যবহার করছেন না।</em>\nআমরা তাই সাংখ্যিক আইপি ঠিকানা ব্যবহার করে তাঁকে শনাক্ত করছি।\nএকাধিক ব্যবহারকারী এরকম একটি আইপি ঠিকানা ব্যবহার করতে পারেন।\nআপনি যদি একজন বেনামী ব্যবহারকারী হয়ে থাকেন এবং যদি অনুভব করেন যে আপনার প্রতি অপ্রাসঙ্গিক মন্তব্য করা হয়েছে, তাহলে অন্যান্য বেনামী ব্যবহারকারীর সাথে ভবিষ্যতে বিভ্রান্তি এড়াতে অনুগ্রহ করে [[Special:CreateAccount|একটি অ্যাকাউন্ট তৈরি করুন]] অথবা [[Special:UserLogin|অ্যাকাউন্টে প্রবেশ করুন]]।",
"noarticletext": "বর্তমানে এই পাতায় কোন লেখা নেই।\nআপনি চাইলে অন্যান্য পাতায় [[Special:Search/{{PAGENAME}}| এই শিরোনামটি অনুসন্ধান করতে পারেন]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} এ সম্পর্কিত লগ অনুসন্ধান করতে পারেন], \nকিংবা [{{fullurl:{{FULLPAGENAME}}|action=edit}} এই পাতাটি তৈরি করতে পারেন]</span>।",
"noarticletext-nopermission": "বর্তমানে এই পাতায় কোন লেখা নেই।\nআপনি চাইলে অন্য পাতায় [[Special:Search/{{PAGENAME}}| শিরোনামটি অনুসন্ধান করতে পারেন]], অথবা <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} সম্পর্কিত লগ অনুসন্ধান করতে পারেন]</span>, কিন্তু আপনার এই পাতাটি তৈরী করার অনুমতি নেই।",
"missing-revision": "\"{{FULLPAGENAME}}\" এর #$1তম সংস্করণটি প্রদর্শন সম্ভব নয়।\n\nসাধারণত মুছে ফেলা হয়েছে এমন পাতার মেয়াদ উত্তীর্ণ ইতিহাস পাতার লিংক ওপেন করার কারণে এটি হতে পারে। \n[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} অপসারণ লগে] বিস্তারিত তথ্য জানা যাবে।",
"userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" নামের কোন ব্যবহারকারী অ্যাকাউন্ট নিবন্ধিত হয়নি। অনুগ্রহ করে পরীক্ষা করে দেখুন আপনি এই পাতাটি সৃষ্টি/সম্পাদনা করতে চান কি না।",
"userpage-userdoesnotexist-view": "ব্যবহারকারী অ্যাকাউন্ট \"$1\" অনিবন্ধিত।",
"blocked-notice-logextract": "এই ব্যবহারকারী বর্তমানে ব্লক রয়েছে।\nরেফারেন্সের জন্য সাম্প্রতিক ব্লক লগ ভুক্তি নিচে দেওয়া হল:",
- "clearyourcache": "<strong>লà¦\95à§\8dষà§\8dয à¦\95রà§\81ন:</strong> সà¦\82রà¦\95à§\8dষণà§\87র পর, পরিবরà§\8dতনà¦\97à§\81লà§\8b দà§\87à¦\96তà§\87 à¦\86পনাà¦\95à§\87 à¦\86পনার বà§\8dরাà¦\89à¦\9cারà§\87র à¦\95à§\8dযাশà§\87 পরিষà§\8dà¦\95ার à¦\95রার পà§\8dরয়à§\8bà¦\9cন হতà§\87 পারà§\87।\n* <strong>ফায়ারফà¦\95à§\8dস / সাফারি:</strong> <em>Shift</em> ধরà§\87 রাà¦\96া à¦\85বসà§\8dথায়<em>পà§\81নà¦\83লà§\8bড à¦\95রà§\81ন</em>-à¦\8f à¦\95à§\8dলিà¦\95 à¦\95রà§\81ন, à¦\85থবা <em>Ctrl-F5</em> বা <em>Ctrl-R</em> (মà§\8dযাà¦\95-à¦\8f <em>â\8c\98-R</em>) à¦\9aাপà§\81ন\n* <strong>à¦\97à§\81à¦\97ল à¦\95à§\8dরà§\8bম:</strong> <em>Ctrl-Shift-R</em> (মà§\8dযাà¦\95-à¦\8f <em>â\8c\98-Shift-R</em>) à¦\9aাপà§\81ন\n* <strong>à¦\87নà§\8dà¦\9fারনà§\87à¦\9f à¦\8fà¦\95à§\8dসপà§\8dলà§\8bরার:</strong> <em>Ctrl</em> ধরà§\87 রাà¦\96া à¦\85বসà§\8dথায় <em>Refresh</em>-à¦\8f à¦\95à§\8dলিà¦\95 à¦\95রà§\81ন, à¦\85থবা <em>Ctrl-F5</em> à¦\9aাপà§\81ন\n* <strong>à¦\85পà§\87রা:</strong> <em>সরà¦\9eà§\8dà¦\9cাম â\86\92 পà¦\9bনà§\8dদসমà§\82হ</em>-à¦\8f à¦\97িয়à§\87 à¦\95à§\8dযাশà§\87 পরিষà§\8dà¦\95ার à¦\95রà§\87 নিন",
+ "clearyourcache": "<strong>লà¦\95à§\8dষà§\8dয à¦\95রà§\81ন:</strong> সà¦\82রà¦\95à§\8dষণà§\87র পর, পরিবরà§\8dতনà¦\97à§\81লà§\8b দà§\87à¦\96তà§\87 à¦\86পনাà¦\95à§\87 à¦\86পনার বà§\8dরাà¦\89à¦\9cারà§\87র à¦\95à§\8dযাশà§\87 পরিষà§\8dà¦\95ার à¦\95রার পà§\8dরয়à§\8bà¦\9cন হতà§\87 পারà§\87।\n* <strong>ফায়ারফà¦\95à§\8dস / সাফারি:</strong> <em>Shift</em> ধরà§\87 রাà¦\96া à¦\85বসà§\8dথায়<em>পà§\81নà¦\83লà§\8bড à¦\95রà§\81ন</em>-à¦\8f à¦\95à§\8dলিà¦\95 à¦\95রà§\81ন, à¦\85থবা <em>Ctrl-F5</em> বা <em>Ctrl-R</em> (মà§\8dযাà¦\95-à¦\8f <em>â\8c\98-R</em>) à¦\9aাপà§\81ন\n* <strong>à¦\97à§\81à¦\97ল à¦\95à§\8dরà§\8bম:</strong> <em>Ctrl-Shift-R</em> (মà§\8dযাà¦\95-à¦\8f <em>â\8c\98-Shift-R</em>) à¦\9aাপà§\81ন\n* <strong>à¦\87নà§\8dà¦\9fারনà§\87à¦\9f à¦\8fà¦\95à§\8dসপà§\8dলà§\8bরার:</strong> <em>Ctrl</em> ধরà§\87 রাà¦\96া à¦\85বসà§\8dথায় <em>Refresh</em>-à¦\8f à¦\95à§\8dলিà¦\95 à¦\95রà§\81ন, à¦\85থবা <em>Ctrl-F5</em> à¦\9aাপà§\81ন\n* <strong>à¦\85পà§\87রা:</strong> <em>মà§\87নà§\81 â\86\92 বà§\8dযবসà§\8dথাপনাসমà§\82হ</em>-à¦\8f যান (মà§\8dযাà¦\95à§\87 <em>à¦\85পà§\87রা â\86\92 পà¦\9bনà§\8dদসমà§\82হ</em>) à¦\8fবà¦\82 à¦\8fরপর <em>à¦\97à§\8bপনà§\80য়তা à¦\93 সà§\81রà¦\95à§\8dষা â\86\92 বà§\8dরাà¦\89à¦\9cিà¦\82-à¦\8fর তথà§\8dয পরিষà§\8dà¦\95ার à¦\95রà§\81ন â\86\92 à¦\95à§\8dযাশà§\87 à¦\95রা à¦\9bবি à¦\93 ফাà¦\87লà¦\97à§\81লি</em>।",
"usercssyoucanpreview": "'''পরামর্শ:''' \"{{int:showpreview}}\" বোতাম ব্যবহার করে সংরক্ষণের আগে আপনার নতুন CSS পরীক্ষা করুন।",
"userjsyoucanpreview": "'''পরামর্শ:''' \"{{int:showpreview}}\" বোতাম ব্যবহার করে সংরক্ষণের আগে আপনার নতুন JavaScript পরীক্ষা করুন।",
"usercsspreview": "'''মনে রাখবেন আপনি আপনার জন্য বরাদ্ধকৃত সিএসএস প্রাকদর্শন করছেন।\nএটা এখনও সংরক্ষণ করা হয়নি!'''",
"continue-editing": "সম্পাদনা করুন",
"previewconflict": "এই প্রাকদর্শনটি সম্পাদনা ক্ষেত্রের উপরের অংশটির টেক্সট সংরক্ষণ করলে যেরকম দেখাবে, তা দেখাচ্ছে।",
"session_fail_preview": "দুঃখিত! সেশন ডাটা হারিয়ে যাওয়ার কারণে আপনার সম্পাদনাটি সংরক্ষণ করা সম্ভব হয়নি।\n\nআপনি সম্ভবত সংযোগ হারিয়েছন। <strong>দয়া করে যাচাই করুন যে আপনি এখনও প্রবেশরত রয়েছেন এবং আবার চেষ্টা করুন</strong>। যদি এটি এখনও কাজ না করে, তাহলে দয়া করে [[Special:UserLogout|অ্যাকাউন্ট থেকে প্রস্থান করুন]] এবং আবার অ্যাকাউন্টে প্রবেশ করে চেষ্টা করুন এবং এবং পরীক্ষা করুন যে আপনার ব্রাউজার এই সাইটে কুকি ব্যবহারের অনুমতি দেয়।",
- "session_fail_preview_html": "'''দুঃখিত! সেশন উপাত্ত হারিয়ে যাওয়ার কারণে আমরা আপনার সম্পাদনাটি প্রক্রিয়া করতে পারিনি।'''\n\n''{{SITENAME}}-এ raw HTML সক্রিয় আছে বলে জাভাস্ক্রিপ্টভিত্তিক আক্রমণ থেকে প্রতিরক্ষার জন্য প্রাকদর্শনটি দেখানো হচ্ছে না।''\n\n'''যদি এটি সম্পাদনার একটি বৈধ প্রচেষ্টা হয়, তবে অনুগ্রহ করে আবার চেষ্টা করুন। যদি তারপরেও কাজ না হয়, তবে অ্যাকাউন্ট থেকে বেরিয়ে গিয়ে আবার প্রবেশ করে চেষ্টা করুন।'''",
+ "session_fail_preview_html": "দুঃখিত! সেশন উপাত্ত হারিয়ে যাওয়ার কারণে আমরা আপনার সম্পাদনাটি প্রক্রিয়া করতে পারিনি।\n\n<em>{{SITENAME}}-এ raw HTML সক্রিয় আছে বলে জাভাস্ক্রিপ্ট ভিত্তিক আক্রমণ থেকে প্রতিরক্ষার জন্য প্রাকদর্শনটি দেখানো হচ্ছে না।</em>\n\n<strong>যদি এটি সম্পাদনার একটি বৈধ প্রচেষ্টা হয়, তবে অনুগ্রহ করে আবার চেষ্টা করুন।</strong>\nযদি তারপরেও কাজ না হয়, তবে অ্যাকাউন্ট থেকে [[Special:UserLogout|বেরিয়ে গিয়ে]] আবার প্রবেশ করুন, এবং পরীক্ষা করে দেখুন যে আপনার ব্রাউজারে এই সাইট থেকে কুকি অনুমতি দেয়।",
"token_suffix_mismatch": "'''আপনার সম্পাদনাটি প্রত্যাখ্যান করা হয়েছে, কারণ আপনার ক্লায়েন্ট প্রোগ্রামটি সম্পাদনা টেক্সটের বিরামচিহ্নগুলি গুলিয়ে ফেলেছে। পাতাটির টেক্সটে যাতে ক্ষতি না হয় সেজন্য সম্পাদনাটি প্রত্যাখ্যান করা হয়েছে। আপনি কোন ত্রুটিপূর্ণ ওয়েব-ভিত্তিক বেনামী প্রক্সি সেবা ব্যবহার করলে এরকম হতে পারে।'''",
"edit_form_incomplete": "'''আপনার সম্পাদনার কিছু অংশ সার্ভারে পৌছায় নি; আপনার সম্পাদনা সম্পূর্ণরুপে আছে কিনা নিশ্চিত হয়ে আবার চেষ্টা করুন'''",
"editing": "সম্পাদনা করছেন: $1",
"content-failed-to-parse": "$1 মডেলের জন্য $2 কন্টেন্ট পার্স করা যাচ্ছে না: $3",
"invalid-content-data": "ভুল কন্টেন্ট ডাটা",
"content-not-allowed-here": "\"$1\" কন্টেন্টটি [[$2]] পাতায় অনুমোদিত নয়",
- "editwarning-warning": "à¦\8fà¦\87 পাতাà¦\9fি তà§\8dযাà¦\97 à¦\95রলà§\87 à¦\86পনার à¦\86পনার à¦\95রা পরিবরà§\8dতনà¦\97à§\81লà§\8b হারিয়à§\87 যà§\87তà§\87 পারà§\87।\nà¦\86পনি যদি লà¦\97à¦\87ন করা থাকেন, আপনি এই সতর্কীকরণ বার্তাটি আপনার পছন্দের \"সম্পাদনা\" অনুচ্ছেদ থেকে নিস্ক্রিয় করতে পারেন।",
+ "editwarning-warning": "à¦\8fà¦\87 পাতাà¦\9fি তà§\8dযাà¦\97 à¦\95রলà§\87 à¦\86পনার à¦\86পনার à¦\95রা পরিবরà§\8dতনà¦\97à§\81লà§\8b হারিয়à§\87 যà§\87তà§\87 পারà§\87।\nà¦\86পনি যদি পà§\8dরবà§\87শ করা থাকেন, আপনি এই সতর্কীকরণ বার্তাটি আপনার পছন্দের \"সম্পাদনা\" অনুচ্ছেদ থেকে নিস্ক্রিয় করতে পারেন।",
"editpage-notsupportedcontentformat-title": "উল্লেখিত পদ্ধতি সমর্থনযোগ্য নয়।",
"editpage-notsupportedcontentformat-text": "$1 লেখার ফরম্যাট, $2 কন্টেন্ট মডেলের উপযোগী নয়।",
"content-model-wikitext": "উইকিটেক্সট",
"undo-summary-username-hidden": "একজন লুকানো ব্যবহারকারী $1 সংশোধন পুনরায় ফিরিয়ে এনেছেন",
"cantcreateaccounttitle": "অ্যাকাউন্ট তৈরি করা যাবে না",
"cantcreateaccount-text": "[[User:$3|$3]] এই আইপি ঠিকানা('''$1''') থেকে অ্যাকাউন্ট সৃষ্টিতে বাধা দিয়েছেন।\n\n$3-এর দেয়া কারণ হল ''$2''",
- "cantcreateaccount-range-text": "[[User:$3|$3]] কর্তৃক আইপি ঠিকানা <strong>$1</strong> ব্যাপ্তির মধ্য থেকে অ্যাকাউন্ট তৈরি করা অবরুদ্ধ করা হয়েছে। যাতে আপনার আইপি ঠিকানা (<strong>$4</strong>) রয়েছে। \n\n$3 কর্তৃক <em>$2</em> কারণ দেখানো হয়েছে।",
+ "cantcreateaccount-range-text": "[[User:$3|$3]] কর্তৃক আইপি ঠিকানার ব্যাপ্তি <strong>$1</strong>-এর মধ্যে অ্যাকাউন্ট তৈরি করা অবরুদ্ধ করা হয়েছে। যাতে আপনার আইপি ঠিকানাও (<strong>$4</strong>) রয়েছে। \n\n$3 কর্তৃক <em>$2</em> কারণ দেখানো হয়েছে।",
"viewpagelogs": "এই পাতার জন্য লগগুলো দেখুন",
"nohistory": "এই পাতার কোন সম্পাদনার ইতিহাস নেই।",
"currentrev": "সর্বশেষ সংস্করণ",
"prefs-displaywatchlist": "প্রদর্শনী অপশন",
"prefs-tokenwatchlist": "টোকেন",
"prefs-diffs": "পার্থক্য",
- "prefs-help-prefershttps": "পরবরà§\8dতà§\80 লà¦\97à¦\87নের পর থেকে এই পরিবর্তনগুলো কার্যকর হবে।",
+ "prefs-help-prefershttps": "পরবরà§\8dতà§\80 পà§\8dরবà§\87শের পর থেকে এই পরিবর্তনগুলো কার্যকর হবে।",
"prefswarning-warning": "আপানি পছন্দসমূহ পাতায় পাতায় পরিবর্তন করেছেন যেগুলো সংরক্ষণ করা হয়নি। আপনি যদি এই পাতাটি ছেড়ে যাওয়ার আগে \"$1\" ক্লিক না করেন তবে পছন্দসমূহ হালনাগাদ হবে না।",
"prefs-tabs-navigation-hint": "সাহায্য: আপনি ডান এবং বাম অ্যারো বাটন ব্যবহার করে বিভিন্ন ট্যাবগুলোতে যেতে পারবেন।",
"userrights": "ব্যবহারকারী অধিকার ব্যবস্থাপনা",
"right-siteadmin": "ডাটাবেজ বন্ধ এবং খুলুন",
"right-override-export-depth": "৫ম স্তর পর্যন্ত সংযুক্তিসহ একটি পাতা রপ্তানী করুন",
"right-sendemail": "অন্য ব্যবহারকারীকে ইমেইল পাঠান",
- "right-passwordreset": "পাসà¦\93য়ারà§\8dড রিসà§\87à¦\9f ইমেইল দেখুন",
+ "right-passwordreset": "পাসà¦\93য়ারà§\8dড পà§\81নà¦\83সà§\8dথাপনà§\87র ইমেইল দেখুন",
"right-managechangetags": "ডাটাবেস থেকে [[Special:Tags|ট্যাগ]] তৈরি ও অপসারণ করুন",
"right-applychangetags": "সম্পাদনার সাথে [[Special:Tags|ট্যাগ]] যুক্ত করুন",
"right-changetags": "নির্দিষ্ট সংস্করণ এবং দীর্ঘ সম্পাদনাগুলোতে [[Special:Tags|ট্যাগ]] সংযোজন ও অপসারণ করুন",
"recentchangeslinked-page": "পাতার নাম:",
"recentchangeslinked-to": "প্রদত্ত পাতায় সংযুক্ত আছে এমন পাতাগুলোর পরিবর্তন দেখাও",
"recentchanges-page-added-to-category": "বিষয়শ্রেণীতে [[:$1]] যোগ করা হয়েছে",
- "recentchanges-page-added-to-category-bundled": "বিষয়শà§\8dরà§\87ণà§\80তà§\87 [[:$1]] à¦\93 [[Special:WhatLinksHere/$1|{{PLURAL:$2|à¦\8fà¦\95à¦\9fি পাতা|$2à¦\9fি পাতা}}]] যà§\8bà¦\97 à¦\95রা হয়à§\87à¦\9bà§\87",
+ "recentchanges-page-added-to-category-bundled": "বিষয়শà§\8dরà§\87ণà§\80তà§\87 [[:$1]] যà§\8bà¦\97 হয়à§\87à¦\9bà§\87, [[Special:WhatLinksHere/$1|à¦\8fà¦\87 পাতাà¦\9fি à¦\85নà§\8dয পাতাà¦\97à§\81লির মধà§\8dযà§\87 à¦\85নà§\8dতরà§\8dà¦à§\81à¦\95à§\8dতà¦\95à§\83ত]]",
"recentchanges-page-removed-from-category": "বিষয়শ্রেণী থেকে [[:$1]] সরানো হয়েছে",
- "recentchanges-page-removed-from-category-bundled": "বিষয়শ্রেণী থেকে [[:$1]] ও [[Special:WhatLinksHere/$1|{{PLURAL:$2|একটি পাতা|$2টি পাতা}}]] সরানো হয়েছে",
+ "recentchanges-page-removed-from-category-bundled": "বিষয়শ্রেণীতে [[:$1]] সরানো হয়েছে, [[Special:WhatLinksHere/$1|এই পাতাটি অন্য পাতাগুলির মধ্যে অন্তর্ভুক্তকৃত]]",
"autochange-username": "মিডিয়াউইকি স্বয়ংক্রিয় পরিবর্তন",
"upload": "আপলোড",
"uploadbtn": "ফাইল আপলোড করুন",
"upload-form-label-own-work": "এটি আমার নিজের কাজ",
"upload-form-label-infoform-categories": "বিষয়শ্রেণীসমূহ",
"upload-form-label-infoform-date": "তারিখ",
- "upload-form-label-not-own-work-local-local": "এছাড়াও আপনি [[Special:Upload|ডিফল্ট আপলোডের পাতা]] চেষ্টা করতে পারেন।",
- "upload-form-label-not-own-work-local-default": "এছাড়াও আপনি [[Special:Upload|{{SITENAME}}-এর আপলোডের পাতা]] ব্যবহার করার চেষ্টা করতে পারেন, যদি এই ফাইলটি তাদের নীতিমালা অধীনে সেখানে আপলোড করা যায়।",
- "upload-form-label-own-work-message-shared": "আমি প্রত্যয়ন করছি যে আমি এই ফাইলের স্বত্তাধিকারী, এবং [https://creativecommons.org/licenses/by-sa/4.0/deed.bn ক্রিয়েটিভ কমন্স অ্যাট্রিবিউশন-শেয়ার অ্যালাইক ৪.০] লাইসেন্সের অধীনে এই ফাইলটি উইকিমিডিয়া কমন্সে অপরিবর্তনীয় প্রকাশে সম্মত হচ্ছি, এবং আমি [https://wikimediafoundation.org/wiki/Terms_of_Use ব্যবহারের শর্তাবলীর] সাথে সম্মত।",
- "upload-form-label-not-own-work-message-shared": "যদি আপনি এই ফাইলের স্বত্তাধিকারী না হন, বা আপনি একটি ভিন্ন লাইসেন্সের আওতায় প্রকাশ করতে ইচ্ছুক থাকেন, তাহলে [https://commons.wikimedia.org/wiki/Special:UploadWizard?uselang=bn কমন্স আপলোড উইজার্ড] ব্যবহার করতে বিবেচনা করুন।",
- "upload-form-label-not-own-work-local-shared": "এছাড়াও আপনি [[Special:Upload|{{SITENAME}}-এর আপলোডের পাতা]] ব্যবহার করার চেষ্টা করতে পারেন, যদি সাইটটি তাদের নীতিমালার অধীনে এই ফাইল আপলোড করার অনুমতি দেয়।",
+ "upload-form-label-not-own-work-local-generic-local": "এছাড়াও আপনি [[Special:Upload|ডিফল্ট আপলোডের পাতা]] চেষ্টা করতে পারেন।",
+ "upload-form-label-not-own-work-local-generic-foreign": "এছাড়াও আপনি [[Special:Upload|{{SITENAME}}-এর আপলোডের পাতা]] ব্যবহার করার চেষ্টা করতে পারেন, যদি এই ফাইলটি তাদের নীতিমালা অধীনে সেখানে আপলোড করা যায়।",
"backend-fail-stream": "\"$1\" ফাইলের স্ট্রিম দেখানো যাচ্ছে না।",
"backend-fail-backup": "\"$1\" ফাইলের ব্যাকআপ তৈরী সম্ভব নয়।",
"backend-fail-notexists": "\"$1\" নামের কোনো ফাইল নেই।",
"img-auth-nopathinfo": "PATH_INFO পাওয়া যাচ্ছে না।\nআপনার সার্ভার থেকে এই তথ্য পাঠানোর জন্য কনফিগার করা হয়নি।\nএটি হয়তো CGI ভিত্তিক এবং img_auth সমর্থন করে না।\nবিস্তারিত দেখুন https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization।",
"img-auth-notindir": "অনুরোধকৃত পাথটি কনফিগার করা আপলোড ডিরেক্টরী নয়।",
"img-auth-badtitle": "\"$1\" থেকে একটি সঠিক শিরনাম তৈরী করা যাচ্ছে না।",
- "img-auth-nologinnWL": "à¦\86পনি লà¦\97à¦\87ন à¦\95রà§\87ননি à¦\8fবà¦\82 \"$1\" নà¦\9cরতালিà¦\95ায় নাই।",
+ "img-auth-nologinnWL": "à¦\86পনি পà§\8dরবà§\87শ à¦\95রà§\87ননি à¦\8fবà¦\82 \"$1\" নà¦\9cরতালিà¦\95ায় নà§\87ই।",
"img-auth-nofile": "ফাইল \"$1\" নাই।",
"img-auth-isdir": "আপনি \"$1\" ডিরেক্টরী দেখতে চেষ্ঠা করছেন।\nশুধুমাত্র ফাইল দেখার অনুমতি রয়েছে।",
"img-auth-streaming": "স্ট্রিমিং \"$1\"।",
"mimesearch-summary": "এই পাতা তাদের MIME-এর ধরণের জন্য ফাইল ফিল্টার করা সক্ষম করে। ইনপুট: contenttype/subtype বা contenttype/*, উদা: <code>image/jpeg</code>।",
"mimetype": "MIME ধরন:",
"download": "ডাউনলোড",
- "unwatchedpages": "নà¦\9cরà§\87 না রাà¦\96া পাতাà¦\97à§\81লি",
+ "unwatchedpages": "নà¦\9cরà§\87 না রাà¦\96া পাতাসমà§\82হ",
"listredirects": "তালিকা পুনর্নির্দেশগুলি",
"listduplicatedfiles": "সদৃশ ফাইলের তালিকা",
"listduplicatedfiles-summary": "এটি ফাইলসমূহের একটি তালিকা যেখানে একটি ফাইলের সাম্প্রতিকতম সংস্করণ অন্য আরেকটি ফাইলের সাম্প্রতিকতম সংস্করণের প্রতিলিপি। শুধু স্থানীয় ফাইল বিবেচনা করা হয়েছে।",
"trackingcategories-msg": "বিষয়শ্রেণী অনুসরণ করা হচ্ছে",
"trackingcategories-name": "বার্তা নাম",
"trackingcategories-desc": "বিষয়শ্রেণী অন্তর্ভুক্তির মানদণ্ড",
+ "restricted-displaytitle-ignored": "উপেক্ষিত প্রদর্শন শিরোনামসহ পাতা",
+ "restricted-displaytitle-ignored-desc": "পাতাটি একটি <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> উপেক্ষা করেছে কারণ এটা পাতাটির আসল শিরোনামের সাথে সমতুল্য নয়।",
"broken-file-category-desc": "এই পাতায় একটি ভাঙ্গা ফাইলের লিঙ্ক রয়েছে (একটি ফাইল এম্বেড করার জন্য একটি লিঙ্ক যখন ফাইলটির অস্তিত্ব নেই)",
"trackingcategories-nodesc": "কোন বর্ণনা নেই।",
"trackingcategories-disabled": "বিষয়শ্রেণীটি বিকল",
"enotif_lastvisited": "আপনার শেষ আগমনের পরে সংঘটিত সমস্ত পরিবর্তনের জন্য $1 দেখুন।",
"enotif_lastdiff": "এই পরিবর্তনটি দেখার জন্য $1 দেখুন।",
"enotif_anon_editor": "বেনামী ব্যবহারকারী $1",
- "enotif_body": "পà§\8dরিয় $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nসমà§\8dপাদà¦\95à§\87র সারাà¦\82শ: $PAGESUMMARY $PAGEMINOREDIT\n\nসমà§\8dপাদà¦\95à§\87র সাথà§\87 যà§\8bà¦\97াযà§\8bà¦\97à§\87র à¦\89পায়:\nà¦\87মà§\87à¦\87ল: $PAGEEDITOR_EMAIL\nà¦\89à¦\87à¦\95ি: $PAGEEDITOR_WIKI\n\nপাতাà¦\9fির পরবরà§\8dতà§\80 পরিবরà§\8dতনà¦\97à§\81লà§\8b à¦\9cনà§\8dয à¦\86র à¦\95à§\8bন বিà¦\9cà§\8dà¦\9eপà§\8dতি পাঠানà§\8b হবà§\87 না, যতà¦\95à§\8dষণ না à¦\86পনি লà¦\97 à¦\87ন à¦\95রার সময় à¦\8fà¦\87 পাতায় বà§\8dরাà¦\89à¦\9c à¦\95রবà§\87ন। à¦\8fà¦\9bাড়া à¦\86পনি à¦\86পনার নà¦\9cরতালিà¦\95ায় রাà¦\96া সবà¦\97à§\81লি পাতা à¦\9cনà§\8dয বিà¦\9cà§\8dà¦\9eপà§\8dতি ফà§\8dলà§\8dযাà¦\97 শà§\81রà§\81র à¦\85বসà§\8dথায় ফিরিয়à§\87 নিতà§\87 পারà§\87ন।\n\nà¦\86পনার বনà§\8dধà§\81তà§\8dবপà§\82রà§\8dণ {{SITENAME}} বিà¦\9cà§\8dà¦\9eপà§\8dতি সিসà§\8dà¦\9fà§\87ম\n\n--\nইমেইল বিজ্ঞপ্তি সেটিং পরিবর্তনের জন্য দেখুন\n{{canonicalurl:{{#special:Preferences}}}}\n\nআপনার নজরতালিকা সেটিংস পরিবর্তন করতে চাইলে দেখুন, \n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nনজরতালিকা থেকে কোন পাতা অপসারণ করতে চাইলে এখানে যান:\n$UNWATCHURL\n\nপ্রতিক্রিয়া জানাতে ও আরও সহযোগিতার জন্য:\n$HELPPAGE",
+ "enotif_body": "পà§\8dরিয় $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nসমà§\8dপাদà¦\95à§\87র সারাà¦\82শ: $PAGESUMMARY $PAGEMINOREDIT\n\nসমà§\8dপাদà¦\95à§\87র সাথà§\87 যà§\8bà¦\97াযà§\8bà¦\97à§\87র à¦\89পায়:\nà¦\87মà§\87à¦\87ল: $PAGEEDITOR_EMAIL\nà¦\89à¦\87à¦\95ি: $PAGEEDITOR_WIKI\n\nপাতাà¦\9fির পরবরà§\8dতà§\80 পরিবরà§\8dতনà¦\97à§\81লà§\8b à¦\9cনà§\8dয à¦\86র à¦\95à§\8bন বিà¦\9cà§\8dà¦\9eপà§\8dতি পাঠানà§\8b হবà§\87 না, যতà¦\95à§\8dষণ না à¦\86পনি পà§\8dরবà§\87শ à¦\95রার সময় à¦\8fà¦\87 পাতায় বà§\8dরাà¦\89à¦\9c à¦\95রবà§\87ন। à¦\8fà¦\9bাড়া à¦\86পনি à¦\86পনার নà¦\9cরতালিà¦\95ায় রাà¦\96া সবà¦\97à§\81লি পাতা à¦\9cনà§\8dয বিà¦\9cà§\8dà¦\9eপà§\8dতি ফà§\8dলà§\8dযাà¦\97 শà§\81রà§\81র à¦\85বসà§\8dথায় ফিরিয়à§\87 নিতà§\87 পারà§\87ন।\n\nà¦\86পনার বনà§\8dধà§\81তà§\8dবপà§\82রà§\8dণ {{SITENAME}} বিà¦\9cà§\8dà¦\9eপà§\8dতি বà§\8dযবসà§\8dথা\n\n--\nইমেইল বিজ্ঞপ্তি সেটিং পরিবর্তনের জন্য দেখুন\n{{canonicalurl:{{#special:Preferences}}}}\n\nআপনার নজরতালিকা সেটিংস পরিবর্তন করতে চাইলে দেখুন, \n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nনজরতালিকা থেকে কোন পাতা অপসারণ করতে চাইলে এখানে যান:\n$UNWATCHURL\n\nপ্রতিক্রিয়া জানাতে ও আরও সহযোগিতার জন্য:\n$HELPPAGE",
"created": "তৈরী হয়েছিল",
"changed": "পরিবর্তিত",
"deletepage": "পাতাটি মুছে ফেলা হোক",
"revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|আলাপ]]) এর সম্পাদিত সংস্করণ হতে [[User:$1|$1]] এর সম্পাদিত সর্বশেষ সংস্করণে ফেরত যাওয়া হয়েছে।",
"revertpage-nouser": "একজন গোপন ব্যবহারকারী কর্তৃক সম্পাদিত সম্পাদনাটি বাতিলপূর্বক {{GENDER:$1|[[User:$1|$1]]}}-এর সর্বশেষ সম্পাদনায় ফেরত যাওয়া হয়েছে।",
"rollback-success": "$1-এর সম্পাদনাগুলি পূর্বাবস্থায় ফিরিয়ে নেওয়া হয়েছে; $2-এর করা শেষ সংস্করণে পাতাটি ফেরত নেওয়া হয়েছে।",
+ "rollback-success-notify": "$1-এর সম্পাদনাগুলি বাতিল করা হয়েছে; \n$2-এর করা শেষ সংস্করণে ফেরত নেওয়া হয়েছে। [$3 পরিবর্তন দেখুন]",
"sessionfailure-title": "সেশন পরিত্যক্ত",
"sessionfailure": "আপনার প্রবেশ সেশনে একটি সমস্যা হয়েছে বলে মনে হচ্ছে;\nসেশন হাইজ্যাক প্রতিরোধের উপায় হিসেবে এই কাজটি বাতিল করা হয়েছে।\nঅনুগ্রহ ব্রাউজারের \"পিছনে\" বোতাম চাপুন এবং যে পাতা থেকে এসেছিলেন, তা পুনঃলোড করুন এবং আবার চেষ্টা করুন।",
+ "changecontentmodel": "একটি পাতার বিষয়বস্তুর মডেল পরিবর্তন",
"changecontentmodel-legend": "বিষয়বস্তুর মডেল পরিবর্তন করুন",
"changecontentmodel-title-label": "পাতার শিরোনাম",
"changecontentmodel-model-label": "পাতার বিষয়বস্তুর প্রতিরূপ",
"sp-contributions-logs": "লগসমূহ",
"sp-contributions-talk": "আলোচনা",
"sp-contributions-userrights": "ব্যবহারকারী অধিকার ব্যবস্থাপনা",
- "sp-contributions-blocked-notice": "এই ব্যবহারকারী বর্তমানে বাধাদানকৃত অবস্থায় রয়েছেন।\nতথ্যসূত্র হিসেবে সাম্প্রতিক বাধাদান লগে ভুক্তিটি নিচে দেওয়া হলো:",
+ "sp-contributions-blocked-notice": "এই ব্যবহারকারী বর্তমানে বাধাদানকৃত অবস্থায় রয়েছেন।\nতথ্যসূত্র হিসেবে সাম্প্রতিক বাধাদান লগের ভুক্তিটি নিচে দেওয়া হলো:",
"sp-contributions-blocked-notice-anon": "এই আইপি ঠিকানাটি বর্তমানে বাধাদানকৃত অবস্থায় রয়েছে।\nতথ্যসূত্র হিসেবে সাম্প্রতিক বাধাদান লগের ভুক্তিটি নিচে দেওয়া হলো:",
"sp-contributions-search": "অবদানসমূহের জন্য অনুসন্ধান",
"sp-contributions-username": "আইপি (IP) ঠিকানা অথবা ব্যবহারকারীর নাম:",
"whatlinkshere-hideredirs": "পুননির্দেশনা $1",
"whatlinkshere-hidetrans": "অন্তর্ভুক্তকরণ $1",
"whatlinkshere-hidelinks": "সংযোগ $1",
- "whatlinkshere-hideimages": "$1 ফাইল সংযোগ",
+ "whatlinkshere-hideimages": "ফাইল সংযোগ $1",
"whatlinkshere-filters": "ছাকনী",
"whatlinkshere-submit": "চলো",
"autoblockid": "স্বয়ংক্রিয় বাধা #$1",
"lockdbsuccesstext": "ডাটাবেজ বন্ধ করা হয়েছে\n<br />আপনার রক্ষণাবেক্ষণ সম্পন্ন হবার পর [[Special:UnlockDB|ডাটাবেজ খুলে দিতে]] ভুলবেন না।",
"unlockdbsuccesstext": "ডাটাবেজ খুলে দেওয়া হয়েছে।",
"lockfilenotwritable": "ডাটাবেজ বন্ধ করার ফাইলটি লিখনযোগ্য নয়। ডাটাবেজ বন্ধ করতে বা খুলতে চাইলে ফাইলটিকে ওয়েব সার্ভার কর্তৃক লিখনযোগ্য হতে হবে।",
+ "databaselocked": "ডাটাবেসটি ইতিমধ্যেই তালাবদ্ধ।",
"databasenotlocked": "ডাটাবেজ বন্ধ নয়।",
"lockedbyandtime": "({{GENDER:$1|$1}} $2 এর $3 সময়ে)",
"move-page": "$1 স্থানান্তর",
"tooltip-ca-nstab-category": "বিষয়শ্রেণী পাতাটি দেখুন",
"tooltip-minoredit": "এটিকে অনুল্লেখ্য সম্পাদনা হিসেবে চিহ্নিত করা হোক",
"tooltip-save": "আপনার পরিবর্তনগুলি সংরক্ষিত হোক",
+ "tooltip-publish": "আপনার পরিবর্তন প্রকাশ করুন",
"tooltip-preview": "অনুগ্রহ করে সংরক্ষণের আগে আপনার পরিবর্তনগুলি প্রাকদর্শন করুন!",
"tooltip-diff": "আপনি টেক্সটে কী কী পরিবর্তন করেছেন, তা দেখানো হোক।",
"tooltip-compareselectedversions": "এই পাতার দুইটি নির্বাচিত সংস্করণের মধ্যে তুলনা দেখুন।",
"confirm-watch-top": "এই পাতাটি আপনার নজরতালিকায় যুক্ত করা হবে?",
"confirm-unwatch-button": "ঠিক আছে",
"confirm-unwatch-top": "এই পাতাটি আপনার নজরতালিকা থেকে সরিয়ে ফেলতে ইচ্ছুক?",
+ "confirm-rollback-button": "ঠিক আছে",
+ "confirm-rollback-top": "এই পাতায় করা সম্পাদনাগুলি প্রত্যাবর্তন করবেন?",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← পূর্ববর্তী পাতা",
"imgmultipagenext": "পরবর্তী পাতা →",
"watchlistedit-raw-done": "আপনার নজর তালিকা হালনাগাদ করা হয়েছে।",
"watchlistedit-raw-added": "{{PLURAL:$1|1 শিরোনাম|$1 শিরোনামসমূহ}} যোগ করা হয়েছে:",
"watchlistedit-raw-removed": "{{PLURAL:$1|1 শিরোনাম|$1 শিরোনামসমূহ}} মুছে ফেলা হয়েছে:",
- "watchlistedit-clear-title": "নà¦\9cরতালিà¦\95া পরিসà§\8dà¦\95ার à¦\95রা হয়à§\87à¦\9bà§\87",
+ "watchlistedit-clear-title": "নà¦\9cরতালিà¦\95া পরিষà§\8dà¦\95ার à¦\95রà§\81ন",
"watchlistedit-clear-legend": "নজরতালিকা পরিস্কার",
"watchlistedit-clear-explain": "সকল শিরোনামসমূহ আপনার নজরতালিকা থেকে সরিয়ে নেয়া হয়েছে।",
"watchlistedit-clear-titles": "শিরোনামসমূহ:",
"timezone-local": "স্থানীয়",
"duplicate-defaultsort": "<strong>সতর্কীকরণ:</strong> পূর্বনির্ধারিত সাজানোর চাবি \"$2\" পূর্বের পূর্বনির্ধারিত সাজানোর চাবি \"$1\" কে অগ্রাহ্য করে।",
"duplicate-displaytitle": "<strong>সতর্কীকরণ:</strong> প্রদর্শন শিরোনাম \"$2\" আগের প্রদর্শন শিরোনাম \"$1\" অগ্রাহ্য করবে।",
+ "restricted-displaytitle": "<strong>সতর্কবার্তা:</strong> প্রদর্শন শিরোনাম \"$1\" উপেক্ষা করা হয়েছে যেহেতু এটি পাতার আসল শিরোনামের সাথে সমতুল্য নয়।",
"invalid-indicator-name": "<strong>ত্রুটি:</strong> পাতার অবস্থা নির্দেশক <code>name</code> অ্যাট্রিবিউট খালি হতে পারবে না।",
"version": "সংস্করণ",
"version-extensions": "ইন্সটলকৃত এক্সটেনশনসমূহ",
"blankpage": "খালি পাতা",
"intentionallyblankpage": "এই পাতাটি ইচ্ছা করে খালি রাখা হয়েছে",
"external_image_whitelist": " #এই লাইন ঠিক যেমন আছে<প্রাক> তেমন রাখুন<pre>\n #রেগুলার এক্সপ্রেশনের টুকরা নীচে (শুধুমাত্র অংশ / / মধ্যে যে যায়) বসান\n#এইগুলি এক্সটার্নাল (hotlinked) ইমেজের URL-এর সাথে মেলানো হবে\n#যেগুলি মিলবে, সেগুলি চিত্র হিসাবে প্রদর্শিত হবে, অন্যথায় শুধুমাত্র ইমেজ লিঙ্ক প্রদর্শিত হবে\n#যে লাইনের প্রারম্ভে # আছে সেই লাইনগুলি মন্তব্যসমূহ হিসাবে ব্যবহার করা হয়\n#এটি কেস-অসংবেদী\n\n#এই রেখার উপরের regex টুকরা বসান. এই লাইন ঠিক যেমন আছে তেমন রাখুন</pre>",
- "tags": "সঠিà¦\95 à¦\9aà§\87à¦\9eà§\8dà¦\9c ট্যাগ",
+ "tags": "বà§\88ধ পরিবরà§\8dতন ট্যাগ",
"tag-filter": "[[Special:Tags|ট্যাগ]] ছাকনী:",
"tag-filter-submit": "ছাকনী",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ট্যাগ}}]]: $2)",
"logentry-protect-protect-cascade": "$1 $3 {{GENDER:$2|সুরক্ষিত করেছেন}} $4 [প্রপাতাকার]",
"logentry-protect-modify": "$1 $3-এর জন্য সুরক্ষা স্তর {{GENDER:$2|পরিবর্তন করেছেন}} $4",
"logentry-protect-modify-cascade": "$1 $3-এর জন্য সুরক্ষা স্তর {{GENDER:$2|পরিবর্তন করেছেন}} $4 [প্রপাতাকার]",
- "logentry-rights-rights": "$1 ব্যবহারকারী, $3 এর দলগত সদস্যপদ $4 থেকে $5 এ {{GENDER:$2|পরিবর্তন}} করেছেন",
+ "logentry-rights-rights": "$1 ব্যবহারকারী, {{GENDER:$6|$3}}-এর দলগত সদস্যপদ $4 থেকে $5 এ {{GENDER:$2|পরিবর্তন}} করেছেন",
"logentry-rights-rights-legacy": "$1 দলের সদস্যপদ পরিবর্তন করেছেন {{GENDER:$2|changed}} এর জন্য $3",
"logentry-rights-autopromote": "$1 স্বয়ংক্রিয়ভাবে $4 থেকে $5-এ {{GENDER:$2|উন্নীত}} হয়েছেন",
"logentry-upload-upload": "$1 $3 {{GENDER:$2|আপলোড করেছেন}}",
"searchsuggest-containing": "যা আছে...",
"api-error-badaccess-groups": "আপনার এই উইকিতে ফাইল আপলোডের অনুমতি নেই।",
"api-error-badtoken": "অভ্যন্তরীণ ত্রুটি: খারাপ টোকেন।",
+ "api-error-blocked": "আপনাকে সম্পাদনা করা থেকে বাধা দেয়া হয়েছে।",
"api-error-copyuploaddisabled": "এই সার্ভারে ইউআরএল-এর মাধ্যমে আপলোড করার সুবিধা নিস্ক্রিয় রয়েছে।",
"api-error-duplicate": "ইতোমধ্যে এই সাইটে একই রকমের বিষয় সমৃদ্ধ {{PLURAL:$1|অন্য ফাইল|কিছু অন্য ফাইল}} রয়েছে।",
"api-error-duplicate-archive": "একই নাম ও বিষয়বস্তু বিশিষ্ট {{PLURAL:$1|অপর একটি ফাইল|কয়েকটি ফাইল}} পূর্বে এই উইকিতে ছিলো, এবং {{PLURAL:$1|সেটিকে|সেগুলোকে}} অপসারণ করা হয়েছে।",
"api-error-invalid-file-key": "অভ্যন্তরীণ ত্রুটি: অস্থায়ী সংরক্ষণশালায় ফাইলটি খুঁজে পাওয়া যায়নি।",
"api-error-missingparam": "অভ্যন্তরীণ ত্রুটি: অনুরোধে কিছু প্যারামিটারের ঘাটতি রয়েছে।",
"api-error-missingresult": "অভ্যন্তরীণ ত্রুটি: সফলভাবে অনুলিপি করা হয়েছে কিনা তা নিশ্চিত করা সম্ভব হয়নি।",
- "api-error-mustbeloggedin": "ফাà¦\87ল à¦\86পলà§\8bড à¦\95রার à¦\9cনà§\8dয à¦\86পনাà¦\95à§\87 à¦\85বশà§\8dযà¦\87 à¦\8fà¦\87 à¦\89à¦\87à¦\95িতà§\87 পà§\8dরবà§\87শ বা লà¦\97à¦\87ন à¦\95রতà§\87 হবà§\87।",
+ "api-error-mustbeloggedin": "ফাইল আপলোড করার জন্য আপনাকে অবশ্যই এই উইকিতে প্রবেশ করতে হবে।",
"api-error-mustbeposted": "অভ্যন্তরীণ ত্রুটি: এই অনুরোধের জন্য এইচটিটিপি পোস্ট প্রয়োজন।",
"api-error-noimageinfo": "আপলোড সফল হয়েছে, কিন্তু ফাইলটি সম্পর্কে সার্ভার কোন তথ্য প্রদান করে নি।",
"api-error-nomodule": "অভ্যন্তরীণ ত্রুটি: কোন আপলোড মডিউল সেট করা হয়নি।",
"randomrootpage": "অজানা মূল পাতা",
"log-action-filter-block": "বাধাদানের ধরন:",
"log-action-filter-delete": "অপসারণের ধরন:",
+ "log-action-filter-import": "আমদানির ধরন:",
"log-action-filter-patrol": "টহলের ধরন:",
"log-action-filter-protect": "সুরক্ষার ধরন:",
"log-action-filter-upload": "আপলোডের ধরন:",
"log-action-filter-protect-protect": "সুরক্ষা",
"log-action-filter-protect-modify": "সুরক্ষা পরিমার্জন",
"log-action-filter-protect-unprotect": "অসুরক্ষা",
+ "log-action-filter-rights-autopromote": "স্বয়ংক্রিয় পরিবর্তন",
"log-action-filter-upload-upload": "নতুন আপলোড",
- "log-action-filter-upload-overwrite": "পুনঃআপলোড"
+ "log-action-filter-upload-overwrite": "পুনঃআপলোড",
+ "authmanager-userdoesnotexist": "ব্যবহারকারী অ্যাকাউন্ট \"$1\" অনিবন্ধিত।",
+ "authmanager-email-help": "ইমেইল ঠিকানা",
+ "authprovider-resetpass-skip-label": "উপেক্ষা করো",
+ "authprovider-resetpass-skip-help": "পাসওয়ার্ড পুনঃস্থাপন করা উপেক্ষা করুন।",
+ "authform-wrongtoken": "ভুল টোকেন",
+ "removecredentials-submit": "পরিচয়পত্র সরান",
+ "credentialsform-account": "অ্যাকাউন্টের নাম:",
+ "linkaccounts": "অ্যাকাউন্ট সংযোগ করুন"
}
"noname": "তি চুম্পা আতাকুরার নাঙহান না লেপ করিসত।",
"loginsuccesstitle": "লগইনহান চুমিল",
"loginsuccess": "'''এরে {{SITENAME}}ত তি \"$1\" হিসাবে না হমাসত।'''",
- "nosuchuser": "এরে \"$1\" নাঙর কোন আতাকুরা নেই।\nআতাকুরার নাঙ কেইস সংবেদনশীল।\nতর বানানহান খিয়াল কর, নাইলে [[Special:UserLogin/signup|আরাক নুৱা একাউন্ট]]আহান হঙকর।",
+ "nosuchuser": "এরে \"$1\" নাঙর কোন আতাকুরা নেই।\nআতাকুরার নাঙ কেইস সংবেদনশীল।\nতর বানানহান খিয়াল কর, নাইলে [[Special:CreateAccount|আরাক নুৱা একাউন্ট]]আহান হঙকর।",
"nosuchusershort": "এরে \"$1\" নাঙর কোন আতাকুরা নেই।\nতর বানানহান খিয়াল কর।",
"nouserspecified": "তি আতাকুরার নাঙ আহান থনা লাগতই।",
"login-userblocked": "আতাকুরাগরে থেপকরানি অসে। লগইন করে নারবে।",
"accmailtext": "[[User talk:$1|$1]]র কা খন্তাচাবি(password) $2-রাঙ দিয়াপেঠুৱাদেনা ইল।\nলগ-ইন করানির পিসে তর নুৱা অ্যাকাউন্টর কা ''[[Special:ChangePassword|খন্তাচাবি সিলকরানি]]''র পাতাত্ব সালকরানি একরতই।",
"newarticle": "(নুৱা)",
"newarticletext": "তি বিসারার মিলাপ অহান নেয়সে।\nতি চেইলে তলর বক্সগত বিষয়হানর বারে খানি ইকরিয়া ইতুকরে পারর বারো নিবন্ধহান অকরে পারর (আরাকউ হারপানিরকা [$1 পাঙলাক পাতা] চা) পারর।\nযদি হারনাপেয়া এহাত আহিয়া থার অতা ইলে ব্রাউজারর ব্যাক গুতমগত ক্লিক করিয়া আগর পাতাত আল পারর।",
- "anontalkpagetext": "----''এহান অচিনা অতার য়্যারির পাতাহান, যেগই কোন অ্যাকাউন্ট না খুলিসে, নাইলে ব্যবহার নাকরের।\nঅহানে আমি আইপি ঠিকানা (IP Address)ল অগরে দেখাদেরাঙতা।\nআক্কুসে এসাদে আকহান আইপি ব্যবহার করতে পারে।\nঅহানে তি নিশ্চকে এরে আইপি এহাত্ত উইকিপিডিয়াত হমিয়া কোন হবানেই য়্যারী দেখর, অহান তরে নিঙকরিয়া নাউ ইতে পারে। অহানে হাবিত্ত হবা অর, তি যদি [[Special:UserLogin|লগ-ইন]] করর, নাইলে [[Special:UserLogin/signup|নুৱা একাউন্ট খুলর]] অতা ইলে এসাদে ভুল বুঝাবুঝি নাইব।''",
+ "anontalkpagetext": "----''এহান অচিনা অতার য়্যারির পাতাহান, যেগই কোন অ্যাকাউন্ট না খুলিসে, নাইলে ব্যবহার নাকরের।\nঅহানে আমি আইপি ঠিকানা (IP Address)ল অগরে দেখাদেরাঙতা।\nআক্কুসে এসাদে আকহান আইপি ব্যবহার করতে পারে।\nঅহানে তি নিশ্চকে এরে আইপি এহাত্ত উইকিপিডিয়াত হমিয়া কোন হবানেই য়্যারী দেখর, অহান তরে নিঙকরিয়া নাউ ইতে পারে। অহানে হাবিত্ত হবা অর, তি যদি [[Special:UserLogin|লগ-ইন]] করর, নাইলে [[Special:CreateAccount|নুৱা একাউন্ট খুলর]] অতা ইলে এসাদে ভুল বুঝাবুঝি নাইব।''",
"noarticletext": "এপাগা এরে পাতাত কোন লেখা নেই। তি মনেইলে হের পাতাহান [[Special:Search/{{PAGENAME}}|এরে চিঙনাঙল বিসারা পারর]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} এহানর বারে লগ বিসারা পারর], নাইলে [{{fullurl:{{FULLPAGENAME}}|action=edit}} এরে পাতা এহান পতা পারর।]",
"noarticletext-nopermission": "এপাগাউ কোন মেয়েক নেই পাতা এহাত।\nতি [[Special:Search/{{PAGENAME}}|এরে পাতার চিঙনাঙ এহানল বিসারা]] হের পাতা অতাত,\nনাইলে <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} মিল আসে লগ অতাত বিসারা]</span>।",
"userpage-userdoesnotexist": "আতাকুরা \"<nowiki>$1</nowiki>\"র অ্যাকাউন্টহান না হঙিসে।\nতি পাতা এহান হঙকরানি/পতানি চারাতানা কিতা খালকরিয়া চা।",
"tog-hideminor": "Kuzhat ar c'hemmoù nevez dister",
"tog-hidepatrolled": "Kuzhat ar c'hemmoù evezhiet e-touez ar c'hemmoù diwezhañ",
"tog-newpageshidepatrolled": "Kuzhat ar pajennoù evezhiet diouzh roll ar pajennoù nevez",
+ "tog-hidecategorization": "Kuzhat rummatadur ar pajennoù",
"tog-extendwatchlist": "Astenn ar roll evezhiañ a-benn diskouez an holl gemmoù ha neket ar re ziwezhañ hepken.",
"tog-usenewrc": "Diskouez ar c'hemmoù nevez en ur feson kempennoc'h",
"tog-numberheadings": "Niverenniñ emgefre an titloù",
"noname": "N'hoc'h eus lakaet anv implijer ebet.",
"loginsuccesstitle": "Kevreet oc'h.",
"loginsuccess": "'''Kevreet oc'h bremañ ouzh {{SITENAME}} evel \"$1\".'''",
- "nosuchuser": "N'eus ket eus an implijer \"$1\".\nKizidik eo anv an implijer ouzh ar pennlizherennoù\nGwiriit eo bet skrivet mat an anv ganeoc'h pe [[Special:UserLogin/signup|krouit ur gont nevez]].",
+ "nosuchuser": "N'eus ket eus an implijer \"$1\".\nKizidik eo anv an implijer ouzh ar pennlizherennoù\nGwiriit eo bet skrivet mat an anv ganeoc'h pe [[Special:CreateAccount|krouit ur gont nevez]].",
"nosuchusershort": "N'eus perzhiad ebet gantañ an anv « $1 ». Gwiriit ar reizhskrivadur.",
"nouserspecified": "Ret eo deoc'h spisaat un anv implijer.",
"login-userblocked": "Stanket eo an implijer-mañ. N'eo ket aotret da gevreañ.",
"accmailtext": "Kaset ez eus bet ur ger-tremen dargouezhek evit [[User talk:$1|$1]] da $2. Cheñchet e c'hall ar ger-tremen evit ar gont nevez-mañ bezañ war ar bajenn ''[[Special:ChangePassword|cheñch ger-tremen]]'', ur wezh kevreet.",
"newarticle": "(Nevez)",
"newarticletext": "Heuliet hoc'h eus ul liamm a gas d'ur bajenn n'eo ket bet savet evit c'hoazh.\nA-benn krouiñ ar bajenn-se, krogit da skrivañ er prenestr skridaozañ dindan (gwelet ar [$1 bajenn skoazell] evit gouzout hiroc'h).\nM'emaoc'h en em gavet amañ dre fazi, klikit war bouton '''kent''' ho merdeer evit mont war ho kiz.",
- "anontalkpagetext": "---- ''Homañ eo ar bajenn gaozeal evit un implijer(ez) dizanv n'eus ket krouet kont ebet evit c'hoazh pe na implij ket anezhi.\nSetu perak e rankomp ober gant ar chomlec'h IP niverel evit anavezout anezhañ/i.\nGallout a ra ur chomlec'h a seurt-se bezañ rannet etre meur a implijer(ez).\nMa'z oc'h un implijer(ez) dizanv ha ma stadit ez eus bet kaset deoc'h kemennadennoù na sellont ket ouzhoc'h, gallout a rit [[Special:UserLogin/signup|krouiñ ur gont]]pe [[Special:UserLogin|kevreañ]] kuit a vagañ muioc'h a gemmesk gant implijerien dizanv all.",
+ "anontalkpagetext": "---- ''Homañ eo ar bajenn gaozeal evit un implijer(ez) dizanv n'eus ket krouet kont ebet evit c'hoazh pe na implij ket anezhi.\nSetu perak e rankomp ober gant ar chomlec'h IP niverel evit anavezout anezhañ/i.\nGallout a ra ur chomlec'h a seurt-se bezañ rannet etre meur a implijer(ez).\nMa'z oc'h un implijer(ez) dizanv ha ma stadit ez eus bet kaset deoc'h kemennadennoù na sellont ket ouzhoc'h, gallout a rit [[Special:CreateAccount|krouiñ ur gont]]pe [[Special:UserLogin|kevreañ]] kuit a vagañ muioc'h a gemmesk gant implijerien dizanv all.",
"noarticletext": "N'eus tamm skrid ebet war ar bajenn-mañ evit poent.\nGallout a rit [[Special:Search/{{PAGENAME}}|klask an titl anezhi]] e pajennoù all,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} klask en oberiadennoù liammet], pe [{{fullurl:{{FULLPAGENAME}}|action=edit}} krouiñ ar bajenn]</span>.",
"noarticletext-nopermission": "N'eus, evit ar mare, tamm testenn ebet war ar bajenn-mañ.\nGallout a rit [[Special:Search/{{PAGENAME}}|klask titl ar bajenn-mañ]] war pajennoù all,\npe <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} klask er marilhoù kar]</span>, met n'oc'h ket aotreet da grouiñ ar bajenn-mañ.",
"missing-revision": "N'eus ket eus adwel niv. $1 eus ar bajenn anvet « {{FULLPAGENAME}} ».\n\nC'hoarvezout a ra peurliesañ pa vez heuliet ul liamm istorel dispredet war-zu ur bajenn zo bet dilamet.\nGallout a reot kavout muioc'h a vunudoù e [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} renabl an dilamadurioù].",
"rows": "Linennoù :",
"columns": "Bannoù",
"searchresultshead": "Klask",
- "stub-threshold": "Bevenn uhelañ evit al <a href=\"#\" class=\"stub\">liammoù war-du an danvez pennadoù</a> (okted) :",
+ "stub-threshold": "Bevenn uhelañ evit al liammoù war-du an danvez pennadoù ($1) :",
"stub-threshold-disabled": "Diweredekaet",
"recentchangesdays": "Niver a zevezhioù da ziskouez er c'hemmoù diwezhañ :",
"recentchangesdays-max": "D'ar muiañ $1 {{PLURAL:$1|deiz|deiz}}",
"prefs-emailconfirm-label": "Kadarnaat ar postel :",
"youremail": "Postel :",
"username": "{{GENDER:$1|Anv implijer|Anv implijerez}}:",
- "prefs-memberingroups": "{{GENDER:$2|Ezel}} eus {{PLURAL:$1|ar strollad|ar strolladoù}} :",
+ "prefs-memberingroups": "{{GENDER:$2|Ezel}} eus {{PLURAL:$1|ar strollad|ar strolladoù}}:",
"prefs-registration": "Deiziad enskrivañ :",
"yourrealname": "Anv gwir*",
"yourlanguage": "Yezh an etrefas ",
"delete-confirm": "Diverkañ \"$1\"",
"delete-legend": "Diverkañ",
"historywarning": "<strong>Diwallit :</strong> Emaoc'h war-nes diverkañ ur bajenn dezhi un istor gant {{PLURAL:$1|adweladenn}} :",
+ "historyaction-submit": "Diskouez",
"confirmdeletetext": "War-nes diverkañ da viken ur bajenn pe ur skeudenn eus ar bank roadennoù emaoc'h. Diverket e vo ivez an holl stummoù kozh stag outi.\nKadarnait, mar plij, eo mat an dra-se hoc'h eus c'hoant da ober, e komprenit mat an heuliadoù, hag e rit se diouzh ar [[{{MediaWiki:Policy-url}}]].",
"actioncomplete": "Diverkadenn kaset da benn",
"actionfailed": "Ober c'hwitet",
"noname": "Niste izabrali ispravno korisničko ime.",
"loginsuccesstitle": "Prijavljen",
"loginsuccess": "'''Sad ste prijavljeni na {{SITENAME}} kao \"$1\".'''",
- "nosuchuser": "Ne postoji korisnik s imenom \"$1\".\nKorisnička imena razlikuju velika i mala slova.\nProvjerite Vaš unos ili [[Special:UserLogin/signup|napravite novi korisnički račun]].",
+ "nosuchuser": "Ne postoji korisnik s imenom \"$1\".\nKorisnička imena razlikuju velika i mala slova.\nProvjerite Vaš unos ili [[Special:CreateAccount|napravite novi korisnički račun]].",
"nosuchusershort": "Ne postoji korisnik s imenom \"$1\".\nProvjerite jeste li dobro ukucali.",
"nouserspecified": "Morate izabrati korisničko ime.",
"login-userblocked": "Ovaj korisnik je blokiran. Prijava nije dopuštena.",
"accmailtext": "Nasumično odabrana šifra za [[User talk:$1|$1]] je poslata na adresu $2.\n\nŠifra/lozinka za ovaj novi račun može biti promijenjena na stranici ''[[Special:ChangePassword|izmjene šifre]]'' nakon prijave.",
"newarticle": "(Novi)",
"newarticletext": "Došli ste na stranicu koja još nema sadržaja.\n*Ako želite unijeti sadržaj, počnite tipkati u prozor ispod ovog teksta.\n*Ako Vam treba pomoć, idite na [$1 stranicu za pomoć].\n*Ako ste ovamo dospjeli slučajno, kliknite na dugme \"Nazad\" (''Back'') u Vašem internetskom pregledniku.",
- "anontalkpagetext": "----''Ovo je stranica za razgovor za anonimnog korisnika koji još nije napravio nalog ili ga ne koristi.\nZbog toga moramo da koristimo brojčanu IP adresu kako bismo identifikovali njega ili nju.\nTakvu adresu može dijeliti više korisnika.\nAko ste anonimni korisnik i mislite da su vam upućene nebitne primjedbe, molimo Vas da [[Special:UserLogin/signup|napravite nalog]] ili se [[Special:UserLogin|prijavite]] da biste izbjegli buduću zabunu sa ostalim anonimnim korisnicima.''",
+ "anontalkpagetext": "----''Ovo je stranica za razgovor za anonimnog korisnika koji još nije napravio nalog ili ga ne koristi.\nZbog toga moramo da koristimo brojčanu IP adresu kako bismo identifikovali njega ili nju.\nTakvu adresu može dijeliti više korisnika.\nAko ste anonimni korisnik i mislite da su vam upućene nebitne primjedbe, molimo Vas da [[Special:CreateAccount|napravite nalog]] ili se [[Special:UserLogin|prijavite]] da biste izbjegli buduću zabunu sa ostalim anonimnim korisnicima.''",
"noarticletext": "Na ovoj stranici trenutno nema teksta.\nMožete [[Special:Search/{{PAGENAME}}|tražiti naslov ove stranice]] na drugim stranicama,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tražiti u povezanim zapisnicima] ili [{{fullurl:{{FULLPAGENAME}}|action=edit}} napraviti ovu stranicu]</span>.",
"noarticletext-nopermission": "Trenutno nema teksta na ovoj stranici.\nMožete [[Special:Search/{{PAGENAME}}|tražiti ovaj naslov stranice]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane zapisnike]</span>, ali nemate dozvolu da napravite ovu stranicu.",
"missing-revision": "Uređivanje broj $1 na stranici \"{{FULLPAGENAME}}\" ne postoji.\n\nOvo se obično dešava kad pratite zastarjelu vezu na stranicu koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} protokolu brisanja].",
"upload-form-label-own-work": "Ovo je moje djelo",
"upload-form-label-infoform-categories": "Kategorije",
"upload-form-label-infoform-date": "Datum",
- "upload-form-label-own-work-message-local": "Potvrđujem da postavljam ovu datoteku u skladu s uslovima korištenja i pravilima o licenciranju na {{GRAMMAR:dativ|{{SITENAME}}}}.",
- "upload-form-label-not-own-work-message-local": "Ako niste u stanju postaviti ovu datoteku pod pravilima {{GRAMMAR:genitiv|{{SITENAME}}}}, molimo zatvorite ovaj prozor i pokušajte drugom metodom.",
- "upload-form-label-not-own-work-local-local": "Također možete pokušati [[Special:Upload|na standardnoj stranici za postavljanje]].",
- "upload-form-label-own-work-message-default": "Shvatam da postavljam ovu datoteku na zajedničko spremište. Potvrđujem da to činim u skladu s uslovima korištenja i ovdašnjim pravilima licenciranja.",
- "upload-form-label-not-own-work-message-default": "Ako niste u stanju postaviti ovu datoteku pod pravilima zajedničkog skladišta, molimo zatvorite ovaj prozor i pokušajte drugom metodom.",
- "upload-form-label-not-own-work-local-default": "Možete također pokušati koristeći [[Special:Upload|stranicu za postavljanje na {{GRAMMAR:dativ|{{SITENAME}}}}]], ako se ova datoteka može postaviti pod tamošnjim pravilima.",
- "upload-form-label-own-work-message-shared": "Potvrđujem da posjedujem autorska prava za ovu datoteku i slažem se da ću je neopozivo postaviti na Wikimedia Commons pod licencom [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], te se slažem s [https://wikimediafoundation.org/wiki/Terms_of_Use uslovima korištenja].",
- "upload-form-label-not-own-work-message-shared": "Ako ne posjedujete autorska prava za ovu datoteku ili je želite postaviti pod drugom licencom, imajte na umu da možete koristiti [https://commons.wikimedia.org/wiki/Special:UploadWizard čarobnjak za postavljanje datoteka na Commonsu].",
- "upload-form-label-not-own-work-local-shared": "Također možete koristiti [[Special:Upload|stranicu za postavljanje datoteka na {{GRAMMAR:dativ|{{SITENAME}}}}]] ako pravila te stranice dozvoljavaju postavljanje ove datoteke.",
+ "upload-form-label-own-work-message-generic-local": "Potvrđujem da postavljam ovu datoteku u skladu s uslovima korištenja i pravilima o licenciranju na {{GRAMMAR:dativ|{{SITENAME}}}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Ako niste u stanju postaviti ovu datoteku pod pravilima {{GRAMMAR:genitiv|{{SITENAME}}}}, molimo zatvorite ovaj prozor i pokušajte drugom metodom.",
+ "upload-form-label-not-own-work-local-generic-local": "Također možete pokušati [[Special:Upload|na standardnoj stranici za postavljanje]].",
+ "upload-form-label-own-work-message-generic-foreign": "Shvatam da postavljam ovu datoteku na zajedničko spremište. Potvrđujem da to činim u skladu s uslovima korištenja i ovdašnjim pravilima licenciranja.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Ako niste u stanju postaviti ovu datoteku pod pravilima zajedničkog skladišta, molimo zatvorite ovaj prozor i pokušajte drugom metodom.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Možete također pokušati koristeći [[Special:Upload|stranicu za postavljanje na {{GRAMMAR:dativ|{{SITENAME}}}}]], ako se ova datoteka može postaviti pod tamošnjim pravilima.",
"backend-fail-stream": "Ne mogu emitirati datoteku $1.",
"backend-fail-backup": "Ne može sigurnosno kopirati datoteku $1.",
"backend-fail-notexists": "Datoteka $1 ne postoji.",
"mw-widgets-titleinput-description-new-page": "stranica još ne postoji",
"mw-widgets-titleinput-description-redirect": "preusmjerava na $1",
"api-error-blacklisted": "Molimo izaberite drugačiji, deskriptivniji naziv.",
- "randomrootpage": "Slučajna root stranica"
+ "randomrootpage": "Slučajna root stranica",
+ "log-action-filter-block": "Vrsta blokiranja:",
+ "log-action-filter-delete": "Vrsta brisanja:",
+ "log-action-filter-all": "Sve",
+ "log-action-filter-block-block": "Blokiranje",
+ "log-action-filter-block-reblock": "Izmjena blokiranja",
+ "log-action-filter-block-unblock": "Deblokiranje",
+ "log-action-filter-delete-delete": "Brisanje stranice",
+ "log-action-filter-delete-restore": "Vraćanje obrisane stranice",
+ "log-action-filter-delete-event": "Brisanje unosa u zapisniku",
+ "log-action-filter-delete-revision": "Brisanje izmjene"
}
"Matma Rex",
"KRLS",
"Jaumeortola",
- "Kippelboy"
+ "Kippelboy",
+ "Syum90"
]
},
"tog-underline": "Subratlla els enllaços:",
"tog-ccmeonemails": "Envia’m còpies dels missatges que enviï als altres usuaris",
"tog-diffonly": "Amaga el contingut de la pàgina davall de la taula de diferències",
"tog-showhiddencats": "Mostra les categories ocultes",
- "tog-norollbackdiff": "Omet la pàgina de diferències després de realitzar una reversió",
+ "tog-norollbackdiff": "No mostris les diferències després de realitzar una reversió",
"tog-useeditwarning": "Avisa'm quan surti d'una pàgina d'edició amb canvis sense desar",
"tog-prefershttps": "Utilitza sempre una connexió segura en iniciar una sessió",
"underline-always": "Sempre",
"userlogin-resetpassword-link": "Heu oblidat la contrasenya?",
"userlogin-helplink2": "Ajuda amb el registre",
"userlogin-loggedin": "Heu iniciat una sessió com {{GENDER:$1|$1}}.\nFeu servir el formulari de sota per iniciar la sessió com un altre usuari.",
+ "userlogin-reauth": "Heu d'iniciar sessió de nou per comprovar que sou {{GENDER:$1|$1}}.",
"userlogin-createanother": "Crea un altre compte",
"createacct-emailrequired": "Adreça electrònica",
"createacct-emailoptional": "Adreça electrònica (opcional)",
"noname": "No heu especificat un nom vàlid d'usuari.",
"loginsuccesstitle": "Sessió iniciada",
"loginsuccess": "Heu iniciat la sessió a {{SITENAME}} com a «$1».",
- "nosuchuser": "No hi ha cap usuari anomenat «$1».\nReviseu-ne l'ortografia (recordeu que es distingeixen les majúscules i minúscules), o [[Special:UserLogin/signup|creeu un compte d'usuari nou]].",
+ "nosuchuser": "No hi ha cap usuari anomenat «$1».\nEls noms d'usuari distingeixen majúscules i minúscules.\nComproveu l'ortografia o [[Special:CreateAccount|creeu un compte nou]].",
"nosuchusershort": "No hi ha cap usuari anomenat «$1». Comproveu que ho hàgiu escrit correctament.",
"nouserspecified": "Heu d'especificar un nom d'usuari.",
"login-userblocked": "Aquest usuari està bloquejat. Inici de sessió no permès.",
"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ó",
+ "pt-login-continue-button": "Continua l'inici de sessió",
"pt-createaccount": "Crea un compte",
"pt-userlogout": "Finalitza la sessió",
"php-mail-error-unknown": "Error desconegut en la funció mail() de PHP",
"botpasswords-created-title": "S'ha creat la contrasenya del bot",
"botpasswords-created-body": "S'ha creat la contrasenya per al bot «$1» de l'usuari «$2».",
"botpasswords-updated-title": "Contrasenya de bot actualitzada",
+ "botpasswords-not-exist": "L'usuari «$1» no té una contrasenya de bot anomenada «$2».",
"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",
"passwordreset-emailsentemail": "Si aquesta adreça electrònica està associada al vostre compte, s’enviarà un missatge de restabliment de contrasenya.",
"passwordreset-emailsent-capture": "S'ha enviat un correu electrònic de reinicialització de contrasenya, tal com es mostra a continuació.",
"passwordreset-emailerror-capture": "S'ha generat un correu electrònic de renovació de contrasenya, que es mostra a continuació, però ha fallat l'enviament a {{GENDER:$2:l'usuari|la usuària}}: $1",
+ "passwordreset-emailsent-capture2": "{{PLURAL:$1|S'ha enviat el correu|S'han enviat els correus}} de restabliment de {{PLURAL:$1|contrasenya|contrasenyes}}. A continuació es mostra {{PLURAL:$1|l'usuari i contrasenya|la llista d'usuaris i contrasenyes}}.",
+ "passwordreset-invalideamil": "Adreça de correu electrònic no vàlida",
"changeemail": "Canvia o elimina l’adreça electrònica",
"changeemail-header": "Empleneu aquest formulari per canviar la vostra adreça electrònica. Si voleu eliminar qualssevol associacions d’adreces electròniques del vostre compte, deixeu en blanc el camp i envieu el formulari.",
"changeemail-passwordrequired": "Cal que introduïu la vostra contrasenya per confirmar el canvi.",
"minoredit": "Aquesta és una modificació menor",
"watchthis": "Vigila aquesta pàgina",
"savearticle": "Desa la pàgina",
+ "publishpage": "Publica la pàgina",
"preview": "Previsualització",
"showpreview": "Mostra una previsualització",
"showdiff": "Mostra els canvis",
"accmailtext": "S'ha enviat una contrasenya aleatòria a $2 per a {{GENDER:$1|l'usuari|la usuària}} [[User talk:$1|$1]].\n\nLa contrasenya per aquest nou compte pot ser canviada a la pàgina de ''[[Special:ChangePassword|canvi de contrasenya]]'' un cop connectat.",
"newarticle": "(Nou)",
"newarticletext": "Heu seguit un enllaç a una pàgina que encara no existeix.\nPer a crear-la, comenceu a escriure en l'espai de sota\n(vegeu l'[$1 ajuda] per a més informació).\nSi sou ací per error, simplement cliqueu al botó «Enrere» del vostre navegador.",
- "anontalkpagetext": "----''Aquesta és la pàgina de discussió d'un usuari anònim que encara no ha creat un compte o que no fa servir el seu nom registrat. Per tant, hem de fer servir la seua adreça IP numèrica per a identificar-lo. Una adreça IP pot ser compartida per molts usuaris. Si sou un usuari anònim, i trobeu que us han adreçat comentaris inoportuns, si us plau, [[Special:UserLogin/signup|creeu-vos un compte]], o [[Special:UserLogin|entreu en el vostre compte]] si ja en teniu un, per a evitar futures confusions amb altres usuaris anònims.''",
+ "anontalkpagetext": "----\n<em>Aquesta és la pàgina de discussió d'un usuari anònim que encara no ha creat un compte o que no fa servir el seu nom registrat. Per tant, hem de fer servir la seua adreça IP numèrica per a identificar-lo. Una adreça IP pot ser compartida per diversos usuaris. Si sou un usuari anònim i trobeu que us han adreçat comentaris no apropiats, [[Special:CreateAccount|creeu un compte]] o [[Special:UserLogin|inicieu sessió]] per a evitar futures confusions amb altres usuaris anònims.",
"noarticletext": "Actualment no hi ha text en aquesta pàgina.\nPodeu [[Special:Search/{{PAGENAME}}|cercar aquest títol]] en altres pàgines,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cercar en els registres]\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} crear-la ara]</span>.",
"noarticletext-nopermission": "Actualment no hi ha text en aquesta pàgina.\nPodeu [[Special:Search/{{PAGENAME}}|cercar aquest títol]] en altres pàgines o bé <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cercar en els registres relacionats]</span>, però no teniu permisos per crear la pàgina.",
"missing-revision": "La revisió núm. $1 de la pàgina anomenada «{{FULLPAGENAME}}» no existeix.\n\nNormalment això ocorre quan seguiu un enllaç d’historial desactualitzat que apunta a una pàgina que s’ha suprimit.\nPodeu trobar detalls en el [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registre de supressions].",
"userpage-userdoesnotexist": "Atenció: El compte d'usuari «<nowiki>$1</nowiki>» no està registrat. En principi no hauríeu de crear ni editar aquesta pàgina.",
"userpage-userdoesnotexist-view": "El compte d'usuari \"$1\" no està registrat.",
"blocked-notice-logextract": "En aquests moments aquest compte d'usuari es troba blocat.\nPer més detalls, la darrera entrada del registre es mostra a continuació:",
- "clearyourcache": "'''Nota:''' Després de desar, possiblement necessiteu refrescar la memòria cau del vostre navegador per a veure'n els canvis.\n* '''Firefox / Safari:''' Premeu ''Shift'' mentre cliqueu el botó ''Actualitzar'', o pressioneu ''Ctrl+F5'' o ''Ctrl+R'' (''⌘+R'' a Mac)\n* '''Google Chrome:''' Premeu ''Ctrl+Shift+R'' (''⌘+Shift+R'' a Mac)\n* '''Internet Explorer:''' Premeu la tecla ''Ctrl'' mentre cliqueu a ''Actualitzar'' o pressioneu ''Ctrl+F5''\n* '''Opera:''' Netegeu la memòria cau ''Eines → Preferències''",
+ "clearyourcache": "<strong>Nota:</strong> Després de desar, possiblement necessitareu refrescar la memòria cau del vostre navegador per a veure'n els canvis.\n* <strong>Firefox / Safari:</strong> Premeu <em>Shift</em> i alhora cliqueu el botó <em>Actualitza</em>, o pressioneu <em>Ctrl+F5</em> o <em>Ctrl+R</em> (<em>⌘+R</em> en un Mac)\n* <strong>Google Chrome:</strong> Premeu <em>Ctrl+Shift+R</em> (<em>⌘+Shift+R</em> en un Mac)\n* <strong>Internet Explorer:</strong> Premeu <em>Ctrl</em> i alhora cliqueu a <em>Actualitza</em> o pressioneu <em>Ctrl+F5</em>\n* <strong>Opera:</strong> Aneu a <em>Menú → Preferències</em> (<em>Opera → Preferències</em> en un Mac) i llavors a <em>Privadesa i seguretat → Neteja dades de navegació → Imatges i fitxers en memòria cau</em>.",
"usercssyoucanpreview": "'''Consell:''' Utilitzeu el botó \"{{int:showpreview}}\" per provar el vostre nou CSS abans de desar-lo.",
"userjsyoucanpreview": "'''Consell:''' Utilitzeu el botó \"{{int:showpreview}}\" per provar el vostre nou JavaScript abans de desar-lo.",
"usercsspreview": "'''Recordeu que esteu previsualitzant el vostre CSS d'usuari.'''\n'''Encara no s'ha desat!'''",
"group-bot": "Bots",
"group-sysop": "Administradors",
"group-bureaucrat": "Buròcrates",
- "group-suppress": "Supressors",
+ "group-suppress": "Supressors de Flow",
"group-all": "(tots)",
"group-user-member": "{{GENDER:$1|usuari|usuària}}",
"group-autoconfirmed-member": "{{GENDER:$1|usuari autoconfirmat|usuària autoconfirmada}}",
"group-bot-member": "{{GENDER:$1|bot}}",
"group-sysop-member": "{{GENDER:$1|administrador|administradora}}",
"group-bureaucrat-member": "{{GENDER:$1|buròcrata}}",
- "group-suppress-member": "{{GENDER:$1|supressor|supressora}}",
+ "group-suppress-member": "{{GENDER:$1|supressor|supressora}} de Flow",
"grouppage-user": "{{ns:project}}:Usuaris",
"grouppage-autoconfirmed": "{{ns:project}}:Usuaris autoconfirmats",
"grouppage-bot": "{{ns:project}}:Bots",
"grouppage-sysop": "{{ns:project}}:Administradors",
"grouppage-bureaucrat": "{{ns:project}}:Buròcrates",
- "grouppage-suppress": "{{ns:project}}:Supressió",
+ "grouppage-suppress": "{{ns:project}}:Supressors de Flow",
"right-read": "Llegir pàgines",
"right-edit": "Modificar pàgines",
"right-createpage": "Crear pàgines (que no són de discussió)",
"grant-editprotected": "Modifica pàgines protegides",
"grant-highvolume": "Edició d'alt volum",
"grant-oversight": "Amaga usuaris i suprimeix revisions",
+ "grant-protect": "Protecció i desprotecció de pàgines",
+ "grant-rollback": "Reversió de canvis en pàgines",
+ "grant-sendemail": "Enviament de correus a altres usuaris",
+ "grant-uploadeditmovefile": "Penjar, substituir i reanomenar fitxers",
"grant-uploadfile": "Carrega fitxers nous",
"grant-basic": "Permisos bàsics",
"grant-viewdeleted": "Mostra fitxers eliminats i pàgines",
"action-viewmyprivateinfo": "mostra la informació personal",
"action-editmyprivateinfo": "edita la informació personal",
"action-editcontentmodel": "editar el model de contingut d'una pàgina",
- "action-managechangetags": "crear i suprimir etiquetes de la base de dades",
+ "action-managechangetags": "crear i (des)activar etiquetes",
"action-applychangetags": "aplica les etiquetes juntament amb els canvis",
"action-changetags": "afegeix i elimina etiquetes a les revisions i les entrades de registre individuals",
"nchanges": "$1 {{PLURAL:$1|canvi|canvis}}",
"upload-options": "Opcions de càrrega",
"watchthisupload": "Vigila aquest fitxer",
"filewasdeleted": "Prèviament es va carregar un fitxer d'aquest nom i després va ser esborrat. Hauríeu de verificar $1 abans de procedir a carregar-lo una altra vegada.",
+ "filename-thumb-name": "Aquest títol sembla que és d'una miniatura. No pengeu versions en miniatura en el mateix wiki. Si no és el cas, corregiu el nom del fitxer per a que sigui més descriptiu i que no tingui un prefix de miniatura.",
"filename-bad-prefix": "El nom del fitxer que esteu penjant comença amb '''«$1»''', que és un nom no descriptiu que les càmeres digitals normalment assignen de forma automàtica. Trieu un de més descriptiu per al vostre fitxer.",
"upload-proto-error": "El protocol és incorrecte",
"upload-proto-error-text": "Per a les càrregues remotes cal que els URL comencin amb <code>http://</code> o <code>ftp://</code>.",
"upload-form-label-own-work": "Això és el meu propi treball",
"upload-form-label-infoform-categories": "Categories",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-not-own-work-local-local": "També podeu provar [[Special:Upload|la pàgina de càrrega per defecte]].",
- "upload-form-label-own-work-message-default": "Entenc que esteu carregant el fitxer en un repositori compartit. Confirmo que ho estic fent seguint les condicions d'ús i les polítiques de llicenciament que s'hi apliquen.",
+ "upload-form-label-not-own-work-local-generic-local": "També podeu provar [[Special:Upload|la pàgina de càrrega per defecte]].",
+ "upload-form-label-own-work-message-generic-foreign": "Entenc que esteu carregant el fitxer en un repositori compartit. Confirmo que ho estic fent seguint les condicions d'ús i les polítiques de llicenciament que s'hi apliquen.",
"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.",
"apisandbox-dynamic-parameters": "Paràmetres adicionals",
"apisandbox-dynamic-parameters-add-label": "Afegeix un paràmetre:",
"apisandbox-dynamic-parameters-add-placeholder": "Nom del paràmetre",
+ "apisandbox-dynamic-error-exists": "Ja existeix un paràmetre anomenat \"$1\".",
"apisandbox-deprecated-parameters": "Paràmetres obsolets",
"apisandbox-submit-invalid-fields-title": "Alguns camps no són vàlids",
"apisandbox-results": "Resultats",
"lockedbyandtime": "(per $1 el $2 a les $3)",
"move-page": "Reanomena $1",
"move-page-legend": "Reanomena la pàgina",
- "movepagetext": "Amb el formulari següent reanomenareu una pàgina, movent tot el seu historial al nou nom.\nEl títol anterior es convertirà en una pàgina de redirecció al nou títol.\nPodeu actualitzar automàticament les redireccions que apuntin al títol original.\nSi no ho feu, assegureu-vos de verificar les redireccions [[Special:DoubleRedirects|dobles]] o [[Special:BrokenRedirects|trencades]].\nSerà de la vostra responsabilitat verificar que els enllaços segueixin apuntant cap a on se suposa que ho han de fer.\n\nTingueu en compte que la pàgina '''no''' serà traslladada si ja existeix una pàgina amb el títol nou, tret que sigui una redirecció sense més historial.\nAixò significa que podeu reanomenar de nou una pàgina al seu títol original si cometeu un error, i que no podeu sobreescriure una pàgina existent.\n\n'''Atenció!'''\nAçò pot ser un canvi dràstic i inesperat en una pàgina que sigui popular; \nassegureu-vos d'entendre les conseqüències que comporta abans de seguir endavant.",
+ "movepagetext": "Amb el formulari següent reanomenareu una pàgina, movent tot el seu historial al nou nom.\nEl títol anterior es convertirà en una pàgina de redirecció al nou títol.\nPodeu actualitzar automàticament les redireccions que apuntin al títol original.\nSi no ho feu, assegureu-vos de verificar les redireccions [[Special:DoubleRedirects|dobles]] o [[Special:BrokenRedirects|trencades]].\nSerà de la vostra responsabilitat verificar que els enllaços segueixin apuntant cap a on se suposa que ho han de fer.\n\nTingueu en compte que la pàgina <strong>no</strong> serà traslladada si ja existeix una pàgina amb el títol nou, tret que sigui una redirecció sense més historial.\nAixò significa que podeu reanomenar de nou una pàgina al seu títol original si cometeu un error, i que no podeu sobreescriure una pàgina existent.\n\n<strong>Nota:</strong>\nAçò pot ser un canvi dràstic i inesperat en una pàgina que sigui popular; \nassegureu-vos d'entendre les conseqüències que comporta abans de seguir endavant.",
"movepagetext-noredirectfixer": "Amb el formulari següent podeu reanomenar una pàgina movent tot el seu historial al nom nou.\nEl títol anterior es convertirà en una pàgina de redirecció al nou títol. \nAssegureu-vos de verificar les redireccions [[Special:DoubleRedirects|dobles]] o [[Special:BrokenRedirects|trencades]].\nÉs responsabilitat vostra assegurar que els enllaços continuen apuntant cap a on se suposa que han d'anar. \n\nTingueu en compte que la pàgina '''no''' serà traslladada si ja existeix una pàgina amb el títol nou, tret que sigui una redirecció i no tingui més historial. \nAixò significa que podeu reanomenar de nou una pàgina al seu títol original si cometeu un error, i que no podeu sobreescriure una pàgina existent.\n \n'''Atenció!''' \nAixò pot ser un canvi dràstic i inesperat per una pàgina popular; \nassegureu-vos que sabeu el que feu abans de continuar.",
"movepagetalktext": "La pàgina de discussió associada també serà traslladada automàticament '''tret que''':\n* Ja existeixi una pàgina de discussió no buida amb el nou nom, o\n* Desactiveu l'opció de més avall.\n\nEn aquests casos, haureu de traslladar o fusionar la pàgina manualment si ho desitgeu.",
"moveuserpage-warning": "'''Atenció:''' Esteu a punt de moure una pàgina d'usuari. Tingueu en compte que només la pàgina es desplaçarà i que el compte d'usuari ''no'' canviarà de nom.",
"tooltip-pt-preferences": "{{GENDER:|Les vostres}} preferències",
"tooltip-pt-watchlist": "La llista de pàgines de les quals vigileu els canvis.",
"tooltip-pt-mycontris": "Llista de {{GENDER:|les vostres}} contribucions",
+ "tooltip-pt-anoncontribs": "Una llista de les modificacions fetes des d'aquesta adreça IP",
"tooltip-pt-login": "Us animem a registrar-vos, però no és obligatori",
"tooltip-pt-logout": "Finalitza la sessió d'usuari",
"tooltip-pt-createaccount": "Us animem a què creeu un compte i inicieu sessió, encara que no és obligatori",
"exif-compression-6": "JPEG (antic)",
"exif-copyrighted-true": "Sotmesa a drets d'autor",
"exif-copyrighted-false": "No s'ha definit l'estat de copyright",
+ "exif-photometricinterpretation-1": "Negra i blanc (negre és 0)",
"exif-unknowndate": "Data desconeguda",
"exif-orientation-1": "Normal",
"exif-orientation-2": "Invertit horitzontalment",
"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 cancel·lada",
"invalidateemail": "Cancel·lació d'adreça electrònica",
+ "notificationemail_subject_changed": "L'adreça registrada de {{SITENAME}} ha canviat",
+ "notificationemail_subject_removed": "L'adreça registrada de {{SITENAME}} ha estat suprimida",
"scarytranscludedisabled": "[S'ha inhabilitat la transclusió interwiki]",
"scarytranscludefailed": "[Ha fallat la recuperació de la plantilla per a $1]",
"scarytranscludefailed-httpstatus": "[Ha fallat la recuperació de la plantilla per a $1: HTTP $2]",
"log-action-filter-protect-modify": "Modificació de la protecció",
"log-action-filter-protect-unprotect": "Desprotecció",
"log-action-filter-upload-upload": "Nova càrrega",
- "log-action-filter-upload-overwrite": "Torna a carregar"
+ "log-action-filter-upload-overwrite": "Torna a carregar",
+ "authmanager-realname-label": "Nom real",
+ "authmanager-realname-help": "Nom real de l'usuari"
}
"noname": "汝未指定蜀萆合法其用戶名。",
"loginsuccesstitle": "躒入成功",
"loginsuccess": "'''汝現在已經「$1」其成功躒入{{SITENAME}}了。'''",
- "nosuchuser": "無總款其用戶名「$1」。\n用户名是大小写敏感其。\n检查汝其拼写,或者覷蜀覷[[Special:UserLogin/signup|開新賬戶]]。",
+ "nosuchuser": "無總款其用戶名「$1」。\n用户名是大小写敏感其。\n检查汝其拼写,或者覷蜀覷[[Special:CreateAccount|開新賬戶]]。",
"nosuchusershort": "無總款其用戶名「$1」。\n檢查汝其拼寫。",
"nouserspecified": "汝著指定蜀萆用戶名。",
"login-userblocked": "茲隻用戶已經乞封鎖去了。登錄是𣍐允許其。",
"accmailtext": "共[[User talk:$1|$1]]用戶隨機生成其密碼已經發遘$2了。汝登錄以後會使敆[[Special:ChangePassword|修改密碼]]頁面修改茲蜀萆密碼。",
"newarticle": "(新)",
"newarticletext": "汝已經跟鏈接跟遘無存在其頁面了。\n卜想創建頁面,敆下底其框框𡅏拍字(覷蜀覷[$1 幫助頁面]有無更更価其幫助)。\n如果汝是無注意來遘茲蜀萆頁面,篤囇汝其瀏覽器上其「返回」按鈕。",
- "anontalkpagetext": "<em>茲是未登錄其用戶討論頁面。</em>\n故此儂家著使數字IP來確定伊。\n總款其IP地址會乞雅価用戶共享。\n如果蜀隻未登錄其用戶見覺無關係其評論指向汝,起動[[Special:UserLogin/signup|開賬戶]]或者[[Special:UserLogin|登錄]]來避免以後共其它未登錄其用戶混蜀堆。",
+ "anontalkpagetext": "<em>茲是未登錄其用戶討論頁面。</em>\n故此儂家著使數字IP來確定伊。\n總款其IP地址會乞雅価用戶共享。\n如果蜀隻未登錄其用戶見覺無關係其評論指向汝,起動[[Special:CreateAccount|開賬戶]]或者[[Special:UserLogin|登錄]]來避免以後共其它未登錄其用戶混蜀堆。",
"noarticletext": "現在敆茲蜀頁𡅏無文字。汝會使敆其它其頁面𡅏[[Special:Search/{{PAGENAME}}|討蜀討茲蜀萆標題]],<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 討相關其記錄],或者[{{fullurl:{{FULLPAGENAME}}|action=edit}}編輯茲蜀頁]</span>。",
"clearyourcache": "'''注意:'''保存以後,汝可能固著刷新汝其瀏覽器緩存來看遘變化。\n* '''火狐/Safari:'''擪下''Shift''篤蜀篤''重新載入'',或者擪蜀擪''Ctrl+F5''或者''Ctrl+R'' (''⌘-R''敆Mac懸頂)\n* '''Google Chrome:'''擪''Ctrl+Shift+R''(敆Mac𡅏使''⌘-Shift-R'')\n* '''Internet Explorer:'''擪''Ctrl''其時候篤蜀篤''刷新'',或者擪''Ctrl+F5''\n* '''Opera:'''敆''工具→首選項''𡅏清除緩存",
"note": "<strong>注意:</strong>",
"noname": "Ахьа декъашхочун цӀе лартӀахь язйина яц.",
"loginsuccesstitle": "Хьан пароль тӀеэца, марша догӀила Википеди чу!",
"loginsuccess": "Хlинца ахьа болх бó оцу цlарца $1.",
- "nosuchuser": "Иштта $1 цӀе йолуш декъашхочун дӀаяздар дац.\nДекъашхой цӀерш хаалуш ю дӀаяздарца элпаш.\nНийса юьй хьажа цӀе я [[Special:UserLogin/signup|дӀаяздар кхолла керла]].",
+ "nosuchuser": "Иштта $1 цӀе йолуш декъашхочун дӀаяздар дац.\nДекъашхой цӀерш хаалуш ю дӀаяздарца элпаш.\nНийса юьй хьажа цӀе я [[Special:CreateAccount|дӀаяздар кхолла керла]].",
"nosuchusershort": "Ишта «$1» цӀе йолу декъашхо вац/яц. Хьажа цӀе нийса язйина юй.",
"nouserspecified": "Ахьа декъашхочун цӀе язъян езаш ю.",
"login-userblocked": "ХӀара декъашхо блоктоьхна ву/ю. Системин чувала/яла магийна дац.",
"accmailtext": "Пароль декъашхочуьнан [[User talk:$1|$1]], йина ша шех хитта делла чу элпашах, дӀаяхийтина хьокху $2 адрес тӀе.\n\nЧуваьлла/яла чул тӀехьа , кху гӀирса чохь шуьга хийцалур ю ''[[Special:ChangePassword|шай пароль]]''.",
"newarticle": "(Kерла)",
"newarticletext": "ХӀара агӀо хӀинца йоцаш ю.\nНагахь иза кхолла лаахь, хӀотта де лахо гуш долу корехь йоза (мадарра хьажа. [$1 гӀон агӀон чу]).\nНагахь гӀалат даьлла цахууш кхечехь кхузе, атта тӀе тӀаӀа йе '''юха йоккхуриг''' хьай браузеран тӀехь.",
- "anontalkpagetext": "----''ХӀара дийцаре агӀо къайлаха декъашхочуьна ю, хӀинца дӀаяздар доцу, я лелош воцуш/йоцуш.\nЦундела иза вовзийта/йовзийта лелош ду терахьца IP-адрес.\nИза терахь долу меттиг хила мега кхечу декъашхойчух терра.\nНагахь хьо къайлах волу декъашхо валахь хьайна хаам кхаьчна аьлла хеташн, хьуна хьажийна доцуш, дехар до, кхолла хьай меттиг кху чохь[[Special:UserLogin/signup|дӀаяздар кхоллар]] я [[Special:UserLogin|системин чугӀо]],",
+ "anontalkpagetext": "----''ХӀара дийцаре агӀо къайлаха декъашхочуьна ю, хӀинца дӀаяздар доцу, я лелош воцуш/йоцуш.\nЦундела иза вовзийта/йовзийта лелош ду терахьца IP-адрес.\nИза терахь долу меттиг хила мега кхечу декъашхойчух терра.\nНагахь хьо къайлах волу декъашхо валахь хьайна хаам кхаьчна аьлла хеташн, хьуна хьажийна доцуш, дехар до, кхолла хьай меттиг кху чохь[[Special:CreateAccount|дӀаяздар кхоллар]] я [[Special:UserLogin|системин чугӀо]],",
"noarticletext": "ХӀокху хан чохь кху агӀонца йоза дац.\nШуьга далундерг [[Special:Search/{{PAGENAME}}|лахар ишта хьехош йолу цӀе]] кхечу яззамашкахь,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} лахар кхечу тептаршкахь],\nя '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} кхолла ишта цӀе йолу агӀо]'''</span>.",
"noarticletext-nopermission": "ХӀокху хан чохь кху агӀонца йоза дац.\nШуьга далундерг [[Special:Search/{{PAGENAME}}|лахар ишта хьехош йолу цӀе]] кхечу яззамашкахь,\nя <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} лаха оцуьнах терадерг кхечу тептаршкахь].</span>",
"missing-revision": "АгӀона «{{FULLPAGENAME}}» верси $1 яц.\n\nИшта хуьйла ширелла дӀаяьккхина агӀонан хьажораган дихьа делча.\nМа-дара хила мега [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дӀайаьхарш йолу тептар] чохь.",
"upload-form-label-own-work": "ХӀара сан долара болх бу",
"upload-form-label-infoform-categories": "Категореш",
"upload-form-label-infoform-date": "Терахь",
- "upload-form-label-not-own-work-local-default": "ХӀара файл {{SITENAME}} сайтан бакъонашца чуйоккхила делахь, хьайн таро ю [[Special:Upload|хӀара агӀо]] лелаян.",
- "upload-form-label-own-work-message-shared": "Аса со хӀокху файлан авторан бакъонаш долахь ерг хилар бакъдо, цундела хӀара файл [https://creativecommons.org/licenses/by-sa/4.0/deed.ru Creative Commons Attribution-ShareAlike 4.0] лицензица Викигуламан чуяккха бакъо ю, цул совнах [https://wikimediafoundation.org/wiki/ хӀокху хьолаца лело] а мега.",
- "upload-form-label-not-own-work-message-shared": "ХӀокху файлан авторан бакъонаш хьай яцахь, я хьайна кхечу лицензица яржо лууш делахь хьажа [https://commons.wikimedia.org/wiki/Special:UploadWizard Викигуламера чуяхаран говзанча] лелон тароне.",
- "upload-form-label-not-own-work-local-shared": "ХӀара файл {{SITENAME}} сайтан бакъонашца чуйоккхила делахь, хьайн таро ю [[Special:Upload|хӀара агӀо]] лелаян.",
+ "upload-form-label-not-own-work-local-generic-foreign": "ХӀара файл {{SITENAME}} сайтан бакъонашца чуйоккхила делахь, хьайн таро ю [[Special:Upload|хӀара агӀо]] лелаян.",
"backend-fail-stream": "ДӀаяккха цатарло файл «$1».",
"backend-fail-backup": "Таро яц файлан $1 тӀаьхьалонан копиян.",
"backend-fail-notexists": "Файл $1 яц.",
"noname": "Wala ikaw mag-specify og valid nga user name.",
"loginsuccesstitle": "Malamposon ang pagpaila",
"loginsuccess": "'''Nailhan ka na sa {{SITENAME}} isip \"$1\".'''",
- "nosuchuser": "Walay gumagamit nga may pangalang \"$1\".\nCase sensitive ang mga user name.\nI-tsek ang imong espeling, o [[Special:UserLogin/signup|paghimo og bag-ong akawnt]].",
+ "nosuchuser": "Walay gumagamit nga may pangalang \"$1\".\nCase sensitive ang mga user name.\nI-tsek ang imong espeling, o [[Special:CreateAccount|paghimo og bag-ong akawnt]].",
"nosuchusershort": "Walay gumagamit nga may pangalang \"$1\".\nI-tsek ang imong espeling.",
"nouserspecified": "Kinahanglan mag-specify ka og username.",
"wrongpassword": "Sayop nga pasword ang naentra.\nPalihog sulayi'g usab.",
"allpagessubmit": "Sige",
"categories": "Mga kategoriya",
"categoriespagetext": "Ang mosunod nga mga kategoriya adunay sulod nga panid o medya.\n[[Special:UnusedCategories|Unused categories]] are not shown here.\nAlso see [[Special:WantedCategories|wanted categories]].",
- "special-categories-sort-abc": "han-aya nga paalpabetikal",
"linksearch": "Mga sumpay sa gawas",
"listgrouprights-members": "(talaan sa mga miyembro)",
"emailuser": "I-email kaning gumagamit",
"noname": "ناوی بەکارهێنەرییەکی گۆنجاوت دیاری نەکردووه.",
"loginsuccesstitle": "چوویە ناوەوە",
"loginsuccess": "'''ئێستا بە ناوی «$1»ەوە لە {{SITENAME}} چوویتەتەژوورەوە.'''",
- "nosuchuser": "بەکارھێنەرێک بە ناوی «$1» نیە.\nناوی بەکارھێنەر بە گەورە و بچووک بوونی پیتەکان ھەستیارە.\nڕێنووسەکەت چاولێکەرەوە، یان [[Special:UserLogin/signup|ھەژمارێکی نوێ دروست بکە]].",
+ "nosuchuser": "بەکارھێنەرێک بە ناوی «$1» نیە.\nناوی بەکارھێنەر بە گەورە و بچووک بوونی پیتەکان ھەستیارە.\nڕێنووسەکەت چاولێکەرەوە، یان [[Special:CreateAccount|ھەژمارێکی نوێ دروست بکە]].",
"nosuchusershort": "بەکارھێنەرێک بە ناوی «$1»ەوە نیە.\nبە نووسراوەکەتدا بچۆرەوە.",
"nouserspecified": "دەبێت ناوێکی بەکارھێنەری دەستنیشان بکەیت.",
"login-userblocked": "ئەم بەکارهێنەرە بڵۆک کراوە. چوونەژوورەوە ڕێگەپێنەدراوە.",
"accmailtext": "تێپەڕوشەیەک کە بە هەڕەمەکی بۆ [[User talk:$1|$1]] دروست کرا، نێررا بۆ $2. دەتوانیت لە پەڕەی <em>[[Special:ChangePassword|گۆڕینی تێپەڕوشەدا]]</em> لە کاتی چوونەژوورەوەدا بیگۆڕی.",
"newarticle": "(نوێ)",
"newarticletext": "بە دوای بەستەری پەڕەیەک کەوتووی کە ھێشتا دروست نەکراوە.\nبۆ دروست کردنی پەڕەکە، لە چوارچێوەکەی خوارەوە دەست بکە بە تایپ کردن. (بۆ زانیاری زورتر\n[$1 یارمەتی] ببینە).\nئەگەر بە ھەڵەوە ھاتویتە ئێرە، لە سەر دوگمەی '''back'''ی وێبگەڕەکەت کلیک بکە.",
- "anontalkpagetext": "----''ئەمە لاپەڕەی وتووێژە بۆ بەکارهێنەرێکی نەناسراوە کە هێشتا هەژمارەی درووستنەکردووه یان کەڵکی لێ وەرناگرێ .\nلەبەر ئەوە مەجبوورین ئایپی ئەدرەسەکی ژمارەیی بۆ ناساندنی بەکار بێنین.\nئایپی ئەدرەسی وا لەوانەیه لە لایەن چەندین بەکارهێنەروە بەکاربێت.\nئەگەر تۆ بەکارهێنەرێکی نەناسراوی و هەست ئەکەی ئەم لێدوانە پەیوەندی بە تۆوە نیە تکایە [[Special:UserLogin/signup|ھەژمارێکی نوێ دروست بکە]] یان [[Special:UserLogin|بچۆ ژوورەوە]] لەبەر ئەوەی لەداهاتوودا دەگەڵ بەکارهێنەرانی نەناسراوی دی تێکەڵ نەکرێیت. ''",
+ "anontalkpagetext": "----''ئەمە لاپەڕەی وتووێژە بۆ بەکارهێنەرێکی نەناسراوە کە هێشتا هەژمارەی درووستنەکردووه یان کەڵکی لێ وەرناگرێ .\nلەبەر ئەوە مەجبوورین ئایپی ئەدرەسەکی ژمارەیی بۆ ناساندنی بەکار بێنین.\nئایپی ئەدرەسی وا لەوانەیه لە لایەن چەندین بەکارهێنەروە بەکاربێت.\nئەگەر تۆ بەکارهێنەرێکی نەناسراوی و هەست ئەکەی ئەم لێدوانە پەیوەندی بە تۆوە نیە تکایە [[Special:CreateAccount|ھەژمارێکی نوێ دروست بکە]] یان [[Special:UserLogin|بچۆ ژوورەوە]] لەبەر ئەوەی لەداهاتوودا دەگەڵ بەکارهێنەرانی نەناسراوی دی تێکەڵ نەکرێیت. ''",
"noarticletext": "ھەنووکە ھیچ دەقێک لەم پەڕەیەدا نییە.\nدەتوانیت لە پەڕەکانی تردا [[Special:Search/{{PAGENAME}}|بۆ ئەم سەرناوە بگەڕێیت]]،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} لە لۆگە پەیوەندیدارەکاندا بگەڕێیت]،\nیان [{{fullurl:{{FULLPAGENAME}}|action=edit}} ئەم پەڕەیە دروست بکەیت]</span>.",
"noarticletext-nopermission": "ھەنووکە ھیچ دەقێک لەم پەڕەیەدا نییە.\nدەتوانی لە پەڕەکانی تردا [[Special:Search/{{PAGENAME}}|بۆ ئەم ناوە بگەڕێی]]، یان <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} لە لۆگە پەیوەندیدارەکاندا بگەڕێی]</span>، بەڵام ناتوانی ئەم پەڕەیە دروست بکەی.",
"userpage-userdoesnotexist": "ھەژماری بەکارھێنەریی «$1» تۆمار نەکراوە.\nتکایە دڵنیا ببەرەوە ئەگەر دەتھەوێت ئەم پەڕەیە دروست یان دەستکاری بکەیت.",
"noname": "Догъру къулланыджы адыны кирсетмединъиз.",
"loginsuccesstitle": "Кириш япылды",
"loginsuccess": "'''$1 адынен {{SITENAME}} сайтында чалышып оласынъыз.'''",
- "nosuchuser": "«$1» адлы къулланыджы ёкъ.\nКъулланыджы адларында буюк ве кичик арифлер арасында фаркъ бар.\nДогъру язгъанынъызны тешкеринъиз я да [[Special:UserLogin/signup|янъы къулланыджы эсабыны ачынъыз]].",
+ "nosuchuser": "«$1» адлы къулланыджы ёкъ.\nКъулланыджы адларында буюк ве кичик арифлер арасында фаркъ бар.\nДогъру язгъанынъызны тешкеринъиз я да [[Special:CreateAccount|янъы къулланыджы эсабыны ачынъыз]].",
"nosuchusershort": "«$1» адлы къулланыджы тапыламады. Адынъызны догъру язгъанынъыздан эмин олунъыз.",
"nouserspecified": "Къулланыджы адыны кирсетмек керексинъиз.",
"login-userblocked": "Бу къулланыджы блок этильген. Кирмеге рухсет этильмей.",
"accmailtext": "[[User talk:$1|$1]] ичюн тесадуфий ишаретлерден яратылгъан пароль $2 адресине ёлланды.\n\nБу янъы эсап ичюн пароль, кириш япкъандан сонъ ''[[Special:ChangePassword|парольни денъиштир]]'' болюгинде денъиштирилип олур.",
"newarticle": "(Янъы)",
"newarticletext": "Сиз бу багълантынен шимдилик ёкъ олгъан саифеге авуштынъыз. Янъы бир саифе яратмакъ ичюн ашагъыда булунгъан пенджереге метин язынъыз (тафсилятлы малюмат алмакъ ичюн [$1 ярдым саифесине] бакъынъыз). Бу саифеге тесадюфен авушкъан олсанъыз, браузеринъиздеки '''кери''' дёгмесине басынъыз.",
- "anontalkpagetext": "----''Бу музакере саифеси шимдилик къайд олунмагъан я да отурымыны ачмагъан адсыз (аноним) къулланыджыгъа менсюптир. Идентификация ичюн IP адрес ишлетиле. Бир IP адресинден бир къач къулланыджы файдаланып ола.\nЭгер сиз аноним къулланыджы олсанъыз ве сизге кельген беянатларны янълыштан кельгенини беллесенъиз, лютфен, артыкъ бунынъ киби къарышыкълыкъ олмасын деп [[Special:UserLogin/signup|къайд олунъыз]] я да [[Special:UserLogin|отурым ачынъыз]].''",
+ "anontalkpagetext": "----''Бу музакере саифеси шимдилик къайд олунмагъан я да отурымыны ачмагъан адсыз (аноним) къулланыджыгъа менсюптир. Идентификация ичюн IP адрес ишлетиле. Бир IP адресинден бир къач къулланыджы файдаланып ола.\nЭгер сиз аноним къулланыджы олсанъыз ве сизге кельген беянатларны янълыштан кельгенини беллесенъиз, лютфен, артыкъ бунынъ киби къарышыкълыкъ олмасын деп [[Special:CreateAccount|къайд олунъыз]] я да [[Special:UserLogin|отурым ачынъыз]].''",
"noarticletext": "Бу саифе шимди боштыр. Бу серлеваны башкъа саифелерде [[Special:Search/{{PAGENAME}}|къыдырып оласынъыз]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} багълы журнал къайдларыны къыдырып оласынъыз] я да бу саифени озюнъиз [{{fullurl:{{FULLPAGENAME}}|action=edit}} язып оласынъыз]</span>.",
"noarticletext-nopermission": "Бу саифе шимди боштыр. Бу серлеваны башкъа саифелерде [[Special:Search/{{PAGENAME}}|къыдыра биле]] я да <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} багълы журналларны козьден кечире билесинъиз]</span>.",
"userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" адлы къулланыджы ёкътыр. Тамам бу саифени денъиштирмеге истегенинъизни тешкеринъиз.",
"allpages-bad-ns": "{{SITENAME}} сайтында «$1» исим фезасы ёкътыр.",
"categories": "Саифе категориялары",
"categoriespagetext": "Ашагъыдаки {{PLURAL:$1|1=категорияда|категорияларда}} саифе я да медиа файллар бар.\n[[Special:UnusedCategories|Къулланылмагъан категориялар]] мында косьтерильмеген.\nАйрыджа [[Special:WantedCategories|талап этильген категорияларнынъ джедвелине]] де бакъынъыз.",
- "special-categories-sort-count": "сайыларына коре сырала",
- "special-categories-sort-abc": "элифбе сырасынен сырала",
"linksearch": "Тыш багълантылар",
"linksearch-pat": "Къыдырув ичюн шаблон:",
"linksearch-ns": "Исим фезасы:",
"watchlisttools-raw": "Козетюв джедвелини адий метин оларакъ денъиштир",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|музакере]])",
"version": "Версия",
- "fileduplicatesearch-legend": "Дубликатны къыдыр",
"fileduplicatesearch-filename": "Файл ады:",
"fileduplicatesearch-submit": "Къыдыр",
"fileduplicatesearch-info": "$1 × $2 пиксел<br />Файл буюклиги: $3<br />MIME чешити: $4",
"noname": "Doğru qullanıcı adını kirsetmediñiz.",
"loginsuccesstitle": "Kiriş yapıldı",
"loginsuccess": "'''$1 adınen {{SITENAME}} saytında çalışıp olasıñız.'''",
- "nosuchuser": "\"$1\" adlı qullanıcı yoq.\nQullanıcı adlarında büyük ve kiçik arifler arasında farq bar.\nDoğru yazğanıñıznı teşkeriñiz ya da [[Special:UserLogin/signup|yañı qullanıcı esabını açıñız]].",
+ "nosuchuser": "\"$1\" adlı qullanıcı yoq.\nQullanıcı adlarında büyük ve kiçik arifler arasında farq bar.\nDoğru yazğanıñıznı teşkeriñiz ya da [[Special:CreateAccount|yañı qullanıcı esabını açıñız]].",
"nosuchusershort": "\"$1\" adlı qullanıcı tapılamadı. Adıñıznı doğru yazğanıñızdan emin oluñız.",
"nouserspecified": "Qullanıcı adını kirsetmek kereksiñiz.",
"login-userblocked": "Bu qullanıcı blok etilgen. Kirmege ruhset etilmey.",
"accmailtext": "[[User talk:$1|$1]] içün tesadufiy işaretlerden yaratılğan parol $2 adresine yollandı.\n\nBu yañı esap içün parol, kiriş yapqandan soñ ''[[Special:ChangePassword|parolni deñiştir]]'' bölüginde deñiştirilip olur.",
"newarticle": "(Yañı)",
"newarticletext": "Siz bu bağlantınen şimdilik yoq olğan saifege avuştıñız. Yañı bir saife yaratmaq içün aşağıda bulunğan pencerege metin yazıñız (tafsilâtlı malümat almaq içün [$1 yardım saifesine] baqıñız). Bu saifege tesadüfen avuşqan olsañız, brauzeriñizdeki '''keri''' dögmesine basıñız.",
- "anontalkpagetext": "----''Bu muzakere saifesi şimdilik qayd olunmağan ya da oturımını açmağan adsız (anonim) qullanıcığa mensüptir. İdentifikatsiya içün IP adres işletile.\nBir IP adresinden bir qaç qullanıcı faydalanıp ola.\nEger siz anonim qullanıcı olsañız ve sizge kelgen beyanatlarnı yañlıştan kelgenini belleseñiz, lütfen, artıq bunıñ kibi qarışıqlıq olmasın dep [[Special:UserLogin/signup|qayd oluñız]] ya da [[Special:UserLogin|oturım açıñız]].''",
+ "anontalkpagetext": "----''Bu muzakere saifesi şimdilik qayd olunmağan ya da oturımını açmağan adsız (anonim) qullanıcığa mensüptir. İdentifikatsiya içün IP adres işletile.\nBir IP adresinden bir qaç qullanıcı faydalanıp ola.\nEger siz anonim qullanıcı olsañız ve sizge kelgen beyanatlarnı yañlıştan kelgenini belleseñiz, lütfen, artıq bunıñ kibi qarışıqlıq olmasın dep [[Special:CreateAccount|qayd oluñız]] ya da [[Special:UserLogin|oturım açıñız]].''",
"noarticletext": "Bu saife şimdi boştır. Bu serlevanı başqa saifelerde [[Special:Search/{{PAGENAME}}|qıdırıp olasıñız]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} bağlı jurnal qaydlarını qıdırıp olasıñız] ya da bu saifeni özüñiz [{{fullurl:{{FULLPAGENAME}}|action=edit}} yazıp olasıñız]</span>.",
"noarticletext-nopermission": "Bu saife şimdi boştır. Bu serlevanı başqa saifelerde [[Special:Search/{{PAGENAME}}|qıdıra bile]] ya da <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} bağlı jurnallarnı közden keçire bilesiñiz]</span>.",
"userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" adlı qullanıcı yoqtır. Tamam bu saifeni deñiştirmege istegeniñizni teşkeriñiz.",
"allpages-bad-ns": "{{SITENAME}} saytında \"$1\" isim fezası yoqtır.",
"categories": "Saife kategoriyaları",
"categoriespagetext": "Aşağıdaki {{PLURAL:$1|kategoriyada|kategoriyalarda}} saife ya da media fayllar bar.\n[[Special:UnusedCategories|Qullanılmağan kategoriyalar]] mında kösterilmegen.\nAyrıca [[Special:WantedCategories|talap etilgen kategoriyalarnıñ cedveline]] de baqıñız.",
- "special-categories-sort-count": "sayılarına köre sırala",
- "special-categories-sort-abc": "elifbe sırasınen sırala",
"linksearch": "Tış bağlantılar",
"linksearch-pat": "Qıdıruv içün şablon:",
"linksearch-ns": "İsim fezası:",
"watchlisttools-raw": "Közetüv cedvelini adiy metin olaraq deñiştir",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|muzakere]])",
"version": "Versiya",
- "fileduplicatesearch-legend": "Dublikatnı qıdır",
"fileduplicatesearch-filename": "Fayl adı:",
"fileduplicatesearch-submit": "Qıdır",
"fileduplicatesearch-info": "$1 × $2 piksel<br />Fayl büyükligi: $3<br />MIME çeşiti: $4",
"Cvanca",
"Macofe",
"Urbanecm",
- "LordMsz"
+ "LordMsz",
+ "Matma Rex"
]
},
"tog-underline": "Podtrhávat odkazy:",
"password-change-forbidden": "Na této wiki nemůžete měnit hesla.",
"externaldberror": "Buď nastala chyba externí autentizační databáze, nebo nemáte dovoleno měnit svůj externí účet.",
"login": "Přihlaste se",
+ "login-security": "Ověřte svou identitu",
"nav-login-createaccount": "Přihlášení / vytvoření účtu",
"userlogin": "Přihlášení / vytvoření účtu",
"userloginnocreate": "Přihlášení",
"userlogin-resetpassword-link": "Zapomněli jste heslo?",
"userlogin-helplink2": "Nápověda k přihlašování",
"userlogin-loggedin": "Již jste {{GENDER:$1|přihlášen|přihlášena}} jako $1.\nPomocí formuláře níže se můžete přihlásit jako jiný uživatel.",
+ "userlogin-reauth": "Abyste {{GENDER:$1|prokázal|prokázala|prokázali}}, že jste $1, musíte se znovu přihlásit.",
"userlogin-createanother": "Vytvořit jiný účet",
"createacct-emailrequired": "E-mailová adresa",
"createacct-emailoptional": "E-mailová adresa (nepovinné)",
"createacct-email-ph": "Zadejte svou e-mailovou adresu",
"createacct-another-email-ph": "Zadejte e-mailovou adresu",
"createaccountmail": "Použít dočasné náhodné heslo a odeslat ho na uvedenou e-mailovou adresu",
+ "createaccountmail-help": "Lze využít k založení účtu pro jinou osobu bez prozrazení hesla.",
"createacct-realname": "Skutečné jméno (nepovinné)",
"createaccountreason": "Důvod:",
"createacct-reason": "Důvod",
"createacct-reason-ph": "Proč si vytváříte další účet",
+ "createacct-reason-help": "Zpráva zobrazená v knize nových uživatelů",
"createacct-submit": "Vytvořit účet",
"createacct-another-submit": "Vytvořit účet",
+ "createacct-continue-submit": "Pokračovat v zakládání účtu",
+ "createacct-another-continue-submit": "Pokračovat v zakládání účtu",
"createacct-benefit-heading": "{{grammar:4sg|{{SITENAME}}}} tvoří lidé jako vy.",
"createacct-benefit-body1": "{{PLURAL:$1|editace|editace|editací}}",
"createacct-benefit-body2": "{{PLURAL:$1|stránka|stránky|stránek}}",
"nocookiesnew": "Uživatelský účet byl vytvořen, ale nejste přihlášeni. {{SITENAME}} používá cookies k přihlášení uživatelů. Vy máte cookies vypnuty. Prosím, zapněte je a poté se přihlaste svým novým uživatelským jménem a heslem.",
"nocookieslogin": "{{SITENAME}} používá cookies k přihlášení uživatelů. Vy máte cookies vypnuty. Prosím zapněte je a zkuste znovu.",
"nocookiesfornew": "Uživatelský účet nebyl založen, neboť jsme nebyli schopni potvrdit jeho původ.\nUjistěte se, že máte povoleny cookies, obnovte tuto stránku a zkuste to znovu.",
+ "createacct-loginerror": "Účet byl úspěšně vytvořen, ale nemohli jste být automaticky přihlášeni. Pokračujte prosím na [[Special:UserLogin|ruční přihlášení]].",
"noname": "{{GENDER:|Nezadal|Nezadala|Nezadali}} jste platné uživatelské jméno.",
"loginsuccesstitle": "Přihlášení bylo úspěšné",
"loginsuccess": "<strong>Nyní jste na {{grammar:6sg|{{SITENAME}}}} {{GENDER:$1|přihlášen jako uživatel|přihlášena jako uživatelka}} „$1“.</strong>",
- "nosuchuser": "Neexistuje uživatel se jménem „$1“. U uživatelských jmen se rozlišují malá/velká písmena. Zkontrolujte zápis, nebo si [[Special:UserLogin/signup|vytvořte nový účet]].",
+ "nosuchuser": "Neexistuje uživatel se jménem „$1“.\nU uživatelských jmen se rozlišují malá/velká písmena.\nZkontrolujte zápis, nebo si [[Special:CreateAccount|vytvořte nový účet]].",
"nosuchusershort": "Neexistuje uživatel se jménem „$1“. Zkontrolujte zápis.",
"nouserspecified": "Musíte zadat uživatelské jméno.",
"login-userblocked": "{{GENDER:$1|Tento uživatel je zablokován|Tato uživatelka je zablokována}}. Přihlášení není dovoleno.",
"createacct-another-realname-tip": "Skutečné jméno je nepovinné.\nPokud se ho rozhodnete uvést, bude použito pro označení autorství vaší práce.",
"pt-login": "Přihlášení",
"pt-login-button": "Přihlásit se",
+ "pt-login-continue-button": "Pokračovat v přihlášení",
"pt-createaccount": "Vytvoření účtu",
"pt-userlogout": "Odhlásit se",
"php-mail-error-unknown": "Neznámá chyba v PHP funkci mail()",
"changepassword-success": "Vaše heslo bylo změněno!",
"changepassword-throttled": "Provedli jste příliš mnoho pokusů o přihlášení.\nČekejte prosím $1 a zkuste to znovu.",
"botpasswords": "Hesla pro boty",
- "botpasswords-summary": "<em>Hesla pro boty</em> umožňují přistupovat k uživatelskému účtu prostřednictví API bez použití hlavních přihlašovacích údajů účtu. Uživatelská oprávnění dostupná po přihlášení pomocí hesla pro boty mohou být omezena.\n\nPokud nevíte, k čemu byste to {{GENDER:|chtěl|chtěla|chtěli}} použít, pravděpodobně byste to používat {{GENDER:|neměl|neměla|neměli}}. Nikdo by vás nikdy neměl žádat, abyste si zde vygenerovali heslo a dali mu ho.",
+ "botpasswords-summary": "<em>Hesla pro boty</em> umožňují přistupovat k uživatelskému účtu prostřednictví API bez použití hlavních přihlašovacích údajů účtu. Uživatelská oprávnění dostupná po přihlášení pomocí hesla pro boty mohou být omezena.\n\nPokud nevíte, k čemu byste to {{GENDER:|chtěl|chtěla|chtěli}} použít, pravděpodobně byste to používat {{GENDER:|neměl|neměla|neměli}}. Nikdo by vás nikdy neměl žádat, abyste si zde {{GENDER:|vygeneroval heslo a dal|vygenerovala heslo a dala|vygenerovali heslo a dali}} mu ho.",
"botpasswords-disabled": "Hesla pro boty jsou zakázána.",
"botpasswords-no-central-id": "Abyste {{GENDER:|mohl|mohla|mohl(a)}} použít hesla pro boty, musíte být {{GENDER:|přihlášen|přihlášena|přihlášen(a)}} k centrálnímu účtu.",
"botpasswords-existing": "Stávající hesla pro boty",
"botpasswords-invalid-name": "Uvedené uživatelské jméno neobsahuje oddělovač hesel pro boty („$1“).",
"botpasswords-not-exist": "Uživatel „$1“ nemá heslo pro bota nazvaného „$2“.",
"resetpass_forbidden": "Hesla nelze změnit.",
+ "resetpass_forbidden-reason": "Hesla nelze změnit: $1",
"resetpass-no-info": "K této stránce mají přímý přístup jen přihlášení uživatelé.",
"resetpass-submit-loggedin": "Změnit heslo",
"resetpass-submit-cancel": "Storno",
"passwordreset-emailsentusername": "Pokud je u tohoto účtu nastavena e-mailová adresa, bude vám zaslán e-mail pro získání nového hesla.",
"passwordreset-emailsent-capture": "Byl odeslán e-mail pro získání nového hesla, který je zobrazen níže.",
"passwordreset-emailerror-capture": "Byl vygenerován e-mail pro získání nového hesla, který je zobrazen níže, ale {{GENDER:$2|uživateli|uživatelce}} se ho nepodařilo odeslat: $1",
+ "passwordreset-emailsent-capture2": "{{PLURAL:$1|Byl odeslán e-mail|Byly odeslány e-maily}} pro získání nového hesla. {{PLURAL:$1|Uživatelské jméno a heslo jsou zobrazeny|Seznam uživatelských jmen a hesel je zobrazen}} níže.",
+ "passwordreset-emailerror-capture2": "{{GENDER:$2|Uživateli|Uživatelce}} se nepodařilo odeslat e-mail: $1 {{PLURAL:$3|Uživatelské jméno a heslo jsou zobrazeny|Seznam uživatelských jmen a hesel je zobrazen}} níže.",
+ "passwordreset-nocaller": "Musí být uveden volající",
+ "passwordreset-nosuchcaller": "Volající neexistuje: $1",
+ "passwordreset-ignored": "Žádost o nové heslo nebyla zpracována. Možná není nakonfigurován žádný poskytovatel?",
+ "passwordreset-invalideamil": "Neplatná e-mailová adresa",
+ "passwordreset-nodata": "Nebylo zadáno uživatelské jméno ani e-mailová adresa",
"changeemail": "Změna nebo odstranění e-mailové adresy",
"changeemail-header": "Vyplněním tohoto formuláře můžete změnit svou e-mailovou adresu. Pokud chcete ze svého účtu odstranit vazbu na všechny e-mailové adresy, ponechte při odeslání formuláře novou e-mailovou adresu prázdnou.",
"changeemail-passwordrequired": "Pro potvrzení této změny musíte zadat své heslo.",
"accmailtext": "Náhodně vygenerované heslo pro uživatele [[User talk:$1|$1]] bylo odesláno na $2. Po přihlášení ho bude možno změnit na [[Special:ChangePassword|stránce pro změnu hesla]].",
"newarticle": "(Nový)",
"newarticletext": "Následovali jste odkaz na stránku, která dosud neexistuje.\nPokud ji chcete vytvořit, začněte psát do rámečku níže (více informací najdete v [$1 nápovědě]).\nPokud jste zde omylem, stiskněte ve svém prohlížeči tlačítko <strong>Zpět</strong>.",
- "anontalkpagetext": "----\n<em>Toto je diskusní stránka anonymního uživatele, který si dosud nevytvořil účet nebo ho nepoužívá.</em>\nK jeho identifikaci proto musíme používat číselnou IP adresu. Takovou IP adresu může sdílet několik uživatelů. Pokud jste anonymní uživatel a máte za to, že jsou vám adresovány irelevantní komentáře, prosíme, [[Special:UserLogin/signup|vytvořte si účet]] nebo [[Special:UserLogin|se přihlaste]], vyhnete se tím budoucí záměně s jinými anonymními uživateli.",
+ "anontalkpagetext": "----\n<em>Toto je diskusní stránka anonymního uživatele, který si dosud nevytvořil účet nebo ho nepoužívá.</em>\nK jeho identifikaci proto musíme používat číselnou IP adresu. Takovou IP adresu může sdílet několik uživatelů. Pokud jste anonymní uživatel a máte za to, že jsou vám adresovány irelevantní komentáře, prosíme, [[Special:CreateAccount|vytvořte si účet]] nebo [[Special:UserLogin|se přihlaste]], vyhnete se tím budoucí záměně s jinými anonymními uživateli.",
"noarticletext": "Tato stránka zatím neobsahuje žádný text.\nMůžete [[Special:Search/{{PAGENAME}}|zkusit tento název vyhledat]] na jiných stránkách, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} prohlédnout si příslušné protokolovací záznamy] nebo [{{fullurl:{{FULLPAGENAME}}|action=edit}} tuto stránku založit]</span>.",
"noarticletext-nopermission": "Tato stránka zatím neobsahuje žádný text.\nMůžete [[Special:Search/{{PAGENAME}}|zkusit tento název vyhledat]] na jiných stránkách nebo <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} si prohlédnout příslušné protokolovací záznamy]</span>, ale na založení této stránky nemáte oprávnění.",
"missing-revision": "Revize #$1 stránky s názvem „{{FULLPAGENAME}}“ neexistuje.\n\nToto je obvykle způsobeno tím, že jste následovali zastaralý odkaz na historickou verzi stránky, jež byla smazána.\nPodrobnosti mohou být uvedeny v [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} knize smazaných stránek].",
"userpage-userdoesnotexist": "Uživatelský účet „$1“ není zaregistrován.\nZkontrolujte, zda skutečně chcete tuto stránku vytvořit či editovat.",
"userpage-userdoesnotexist-view": "Uživatelský účet „$1“ není zaregistrován.",
"blocked-notice-logextract": "{{GENDER:$1|Tento uživatel|Tato uživatelka}} je momentálně {{GENDER:$1|zablokován|zablokována}}.\nZde je pro přehled zobrazen nejnovější záznam z knihy zablokování:",
- "clearyourcache": "<strong>Poznámka:</strong> Po uložení musíte smazat cache vašeho prohlížeče, jinak změny neuvidíte.\n* <strong>Firefox / Safari:</strong> Při kliknutí na <em>Aktualizovat</em> držte <em>Shift</em> nebo stiskněte <em>Ctrl-F5</em> nebo <em>Ctrl-R</em> (na Macu <em>⌘-R</em>)\n* <strong>Google Chrome:</strong> Stiskněte <em>Ctrl-Shift-R</em> (na Macu <em>⌘-Shift-R</em>)\n* <strong>Internet Explorer:</strong> Při kliknutí na <em>Aktualizovat</em> držte <em>Ctrl</em> nebo stiskněte <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Smažte obsah cache v menu <em>Nástroje → Nastavení</em>",
+ "clearyourcache": "<strong>Poznámka:</strong> Po uložení musíte smazat cache vašeho prohlížeče, jinak změny neuvidíte.\n* <strong>Firefox / Safari:</strong> Při kliknutí na <em>Aktualizovat</em> držte <em>Shift</em> nebo stiskněte <em>Ctrl-F5</em> nebo <em>Ctrl-R</em> (na Macu <em>⌘-R</em>)\n* <strong>Google Chrome:</strong> Stiskněte <em>Ctrl-Shift-R</em> (na Macu <em>⌘-Shift-R</em>)\n* <strong>Internet Explorer:</strong> Při kliknutí na <em>Aktualizovat</em> držte <em>Ctrl</em> nebo stiskněte <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Jděte do <em>Menu → Nastavení</em> (na Macu <em>Opera → Nastavení</em>) a tam pak <em>Soukromí & bezpečnost → Vymazat údaje o prohlížení → Obrázky a soubory z cache</em>",
"usercssyoucanpreview": "<strong>Tip:</strong> Použijte tlačítko „{{int:showpreview}}“ k testování vašeho nového CSS před uložením.",
"userjsyoucanpreview": "<strong>Tip:</strong> Použijte tlačítko „{{int:showpreview}}“ k testování vašeho nového JavaScriptu před uložením.",
"usercsspreview": "<strong>Pamatujte, že si prohlížíte jen náhled vašeho uživatelského CSS, jelikož dosud nebyl uložen!</strong>",
"right-override-export-depth": "Exportovat stránky včetně odkazovaných stránek až do hloubky 5",
"right-sendemail": "Odesílání e-mailů ostatním uživatelům",
"right-passwordreset": "Prohlížení e-mailů pro znovunastavení hesla",
- "right-managechangetags": "Vytváření [[Special:Tags|značek]] a jejich mazání z databáze",
+ "right-managechangetags": "Vytváření a (de)aktivace [[Special:Tags|značek]]",
"right-applychangetags": "Přidávání [[Special:Tags|značek]] k vlastním změnám",
"right-changetags": "Přidávání libovolných [[Special:Tags|značek]] na jednotlivé revize a protokolovací záznamy a jejich odebírání",
+ "right-deletechangetags": "Mazání [[Special:Tags|značek]] z databáze",
"grant-generic": "Balíček oprávnění „$1“",
"grant-group-page-interaction": "Interakce se stránkami",
"grant-group-file-interaction": "Interakce se soubory",
"action-viewmyprivateinfo": "prohlížet si své soukromé údaje",
"action-editmyprivateinfo": "změnit své soukromé údaje",
"action-editcontentmodel": "editovat model obsahu stránky",
- "action-managechangetags": "vytvářet a mazat značky z databáze",
+ "action-managechangetags": "vytvářet a (de)aktivovat značky",
"action-applychangetags": "přidávat značky k vlastním změnám",
"action-changetags": "přidávat libovolné značky na jednotlivé revize a protokolovací záznamy a odebírat je",
+ "action-deletechangetags": "mazat značky z databáze",
"nchanges": "$1 {{PLURAL:$1|změna|změny|změn}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od poslední návštěvy}}",
"enhancedrc-history": "historie",
"upload-form-label-own-work": "Je to mé vlastní dílo",
"upload-form-label-infoform-categories": "Kategorie",
"upload-form-label-infoform-date": "Datum",
- "upload-form-label-own-work-message-local": "Potvrzuji, že tento soubor načítám v souladu s podmínkami užití a licenčními pravidly na {{grammar:6sg|{{SITENAME}}}}.",
- "upload-form-label-not-own-work-message-local": "Pokud nemůžete tento soubor načíst v souladu s pravidly {{grammar:2sg|{{SITENAME}}}}, zavřete prosím tento dialog a zkuste jiný způsob.",
- "upload-form-label-not-own-work-local-local": "Také můžete zkusit [[Special:Upload|standardní stránku pro načítání souborů]].",
- "upload-form-label-own-work-message-default": "Chápu, že soubor načítám na sdílené úložiště. Potvrzuji, že tak činím v souladu s tamními podmínkami užití a licenčními pravidly.",
- "upload-form-label-not-own-work-message-default": "Pokud nemůžete tento soubor načíst v souladu s pravidly sdíleného úložiště, zavřete prosím tento dialog a zkuste jiný způsob.",
- "upload-form-label-not-own-work-local-default": "Také můžete zkusit [[Special:Upload|stránku pro načítání souborů na {{grammar:6sg|{{SITENAME}}}}]], pokud tam lze soubor podle tamních pravidel načíst.",
- "upload-form-label-own-work-message-shared": "Potvrzuji, že jsem držitelem autorských práv k tomuto souboru a neodvolatelně souhlasím s jeho zveřejněním na Wikimedia Commons pod licencí [https://creativecommons.org/licenses/by-sa/4.0/deed.cs Creative Commons Uveďte původ – Zachovejte licenci 4.0] a souhlasím s [https://wikimediafoundation.org/wiki/Terms_of_Use/cs Podmínkami užití].",
- "upload-form-label-not-own-work-message-shared": "Pokud nejste držiteli autorských práv k tomuto souboru nebo si ho přejete zveřejnit pod jinou licencí, zvažte použití [https://commons.wikimedia.org/wiki/Special:UploadWizard Průvodce načítáním souborů na Commons].",
- "upload-form-label-not-own-work-local-shared": "Také můžete zkusit [[Special:Upload|stránku pro načítání souborů na {{grammar:6sg|{{SITENAME}}}}]], pokud tamní pravidla načtení tohoto souboru dovolují.",
+ "upload-form-label-own-work-message-generic-local": "Potvrzuji, že tento soubor načítám v souladu s podmínkami užití a licenčními pravidly na {{grammar:6sg|{{SITENAME}}}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Pokud nemůžete tento soubor načíst v souladu s pravidly {{grammar:2sg|{{SITENAME}}}}, zavřete prosím tento dialog a zkuste jiný způsob.",
+ "upload-form-label-not-own-work-local-generic-local": "Také můžete zkusit [[Special:Upload|standardní stránku pro načítání souborů]].",
+ "upload-form-label-own-work-message-generic-foreign": "Chápu, že soubor načítám na sdílené úložiště. Potvrzuji, že tak činím v souladu s tamními podmínkami užití a licenčními pravidly.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Pokud nemůžete tento soubor načíst v souladu s pravidly sdíleného úložiště, zavřete prosím tento dialog a zkuste jiný způsob.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Také můžete zkusit [[Special:Upload|stránku pro načítání souborů na {{grammar:6sg|{{SITENAME}}}}]], pokud tam lze soubor podle tamních pravidel načíst.",
"backend-fail-stream": "Soubor $1 nelze streamovat.",
"backend-fail-backup": "Soubor $1 nelze zazálohovat.",
"backend-fail-notexists": "Soubor $1 neexistuje.",
"trackingcategories-msg": "Sledovací kategorie",
"trackingcategories-name": "Název hlášení",
"trackingcategories-desc": "Kritéria pro vložení do kategorie",
+ "restricted-displaytitle-ignored": "Stránky s ignorovanými zobrazovanými názvy",
+ "restricted-displaytitle-ignored-desc": "Stránka obsahuje příkaz <code><nowiki>{{DISPLAYTITLE}}</nowiki></code>, který se ignoruje, protože není ekvivalentní skutečnému názvu stránky.",
"noindex-category-desc": "Stránka není indexována roboty, protože obsahuje kouzelné slovo <code><nowiki>__NOINDEX__</nowiki></code> a je ve jmenném prostoru, ve kterém je tento příznak dovolen.",
"index-category-desc": "Stránka obsahuje kouzelné slovo <code><nowiki>__INDEX__</nowiki></code> (a je ve jmenném prostoru, ve kterém je tento příznak dovolen), takže je indexována roboty, přestože by normálně nebyla.",
"post-expand-template-inclusion-category-desc": "Stránka je po rozbalení všech šablon větší než <code>$wgMaxArticleSize</code>, takže některé šablony rozbaleny nebyly.",
"rollbacklinkcount": "vrácení $1 {{PLURAL:$1|editace|editací}} zpět",
"rollbacklinkcount-morethan": "vrácení více než $1 {{PLURAL:$1|editace|editací}} zpět",
"rollbackfailed": "Nešlo vrátit zpět",
+ "rollback-missingparam": "V požadavku chybí povinné parametry.",
"cantrollback": "Nelze vrátit zpět poslední editaci, neboť poslední přispěvatel je jediným autorem této stránky.",
"alreadyrolled": "Nelze vrátit zpět poslední editaci [[:$1]] od uživatele [[User:$2|$2]] ([[User talk:$2|diskuse]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]), protože někdo jiný již stránku editoval nebo vrátil tuto změnu zpět.\n\nPoslední editaci této stránky {{GENDER:$3|provedl|provedla|provedl uživatel}} [[User:$3|$3]] ([[User talk:$3|diskuse]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "Shrnutí editace bylo: <em>$1</em>.",
"revertpage": "Editace uživatele „[[Special:Contributions/$2|$2]]“ ([[User talk:$2|diskuse]]) vráceny do předchozího stavu, jehož autorem je „[[User:$1|$1]]“",
"revertpage-nouser": "Editace skrytého uživatele vráceny do předchozího stavu, jehož {{GENDER:$1|autorem|autorkou}} je „[[User:$1|$1]]“",
"rollback-success": "Editace uživatele $1 byly vráceny na poslední verzi od uživatele $2.",
+ "rollback-success-notify": "Editace uživatele $1 byly vráceny;\nobnovena poslední verze od uživatele $2. [$3 Zobrazit změny]",
"sessionfailure-title": "Chyba relace",
"sessionfailure": "Zřejmě je nějaký problém s vaším přihlášením;\nvámi požadovaná činnost byla stornována jako prevence před neoprávněným přístupem.\nStiskněte tlačítko „zpět“, obnovte stránku, ze které jste přišli, a zkuste činnost znovu.",
"changecontentmodel": "Změna modelu obsahu stránky",
"changecontentmodel-success-text": "Model obsahu stránky [[:$1]] byl změněn.",
"changecontentmodel-cannot-convert": "Obsah stránky [[:$1]] nelze zkonvertovat na typ $2.",
"changecontentmodel-nodirectediting": "Model obsahu $1 nepodporuje přímou editaci",
+ "changecontentmodel-emptymodels-title": "Nejsou k dispozici žádné modely obsahu",
+ "changecontentmodel-emptymodels-text": "Obsah stránky [[:$1]] nelze zkonvertovat na žádný typ.",
"log-name-contentmodel": "Kniha změny modelů obsahu",
"log-description-contentmodel": "Události týkající se modelů obsahu stránek",
"logentry-contentmodel-new": "$1 {{GENDER:$2|založil|založila}} stránku $3 za použití nestandardního modelu obsahu „$5“",
"locknoconfirm": "Nebylo zaškrtnuto políčko potvrzení.",
"lockdbsuccesssub": "Databáze uzamčena",
"unlockdbsuccesssub": "Databáze odemčena",
- "lockdbsuccesstext": "Databáze {{grammar:2sg|{{SITENAME}}}} byla úspěšně uzamčena.\n<br />Nezapomeňte ji po dokončení údržby [[Special:UnlockDB|odemknout]].",
+ "lockdbsuccesstext": "Databáze {{grammar:2sg|{{SITENAME}}}} byla uzamčena.<br />\nNezapomeňte ji po dokončení údržby [[Special:UnlockDB|odemknout]].",
"unlockdbsuccesstext": "Databáze {{grammar:2sg|{{SITENAME}}}} je odemčena.",
"lockfilenotwritable": "Do souboru zámku databáze nelze zapisovat. Pro zamčení či odemčení databáze musí mít webový server právo zápisu do tohoto souboru.",
+ "databaselocked": "Databáze je již zamčená.",
"databasenotlocked": "Databáze není uzamčena.",
"lockedbyandtime": "({{gender:$1|zamkl|zamkla|zamkl}} $1 $2 v $3)",
"move-page": "Přesunout „$1“",
"confirm-watch-top": "Přidat tuto stránku mezi sledované?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Vyjmout tuto stránku ze sledovaných?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Vrátit editace této stránky?",
"ellipsis": "…",
"percent": "$1 %",
"quotation-marks": "„$1“",
"timezone-local": "místní čas",
"duplicate-defaultsort": "Upozornění: Implicitní klíč řazení (DEFAULTSORTKEY) „$2“ přepisuje dříve nastavenou hodnotu „$1“.",
"duplicate-displaytitle": "<strong>Upozornění:</strong> Předchozí zobrazovaný název „$1“ je nahrazen zobrazovaným názvem „$2“.",
+ "restricted-displaytitle": "<strong>Upozornění:</strong> Zobrazovaný název „$1“ byl ignorován, neboť není ekvivalentní skutečnému názvu stránky.",
"invalid-indicator-name": "<strong>Chyba:</strong> Atribut <code>name</code> indikátoru stavu stránky nesmí být prázdný.",
"version": "Verze",
"version-extensions": "Nainstalovaná rozšíření",
"tags-delete-not-found": "Značka „$1“ neexistuje.",
"tags-delete-too-many-uses": "Značkou „$1“ {{PLURAL:$2|je označena více než $2 revize|jsou označeny více než $2 revize|je označeno více než $2 revizí}}, což znamená, že ji nelze smazat.",
"tags-delete-warnings-after-delete": "Značka „$1“ byla smazána, ale {{PLURAL:$2|bylo zjištěno|byla zjištěna}} následující varování:",
+ "tags-delete-no-permission": "Nemáte oprávnění mazat značky pro změny.",
"tags-activate-title": "Aktivovat značku",
"tags-activate-question": "Chystáte se aktivovat značku „$1“.",
"tags-activate-reason": "Důvod:",
"log-action-filter-suppress-block": "Utajení uživatele zablokováním",
"log-action-filter-suppress-reblock": "Utajení uživatele novým zablokováním",
"log-action-filter-upload-upload": "Nové načtení",
- "log-action-filter-upload-overwrite": "Znovunačtení"
+ "log-action-filter-upload-overwrite": "Znovunačtení",
+ "authmanager-authn-not-in-progress": "Autentizace neprobíhá nebo se ztratila data sezení. Začněte prosím znovu od začátku.",
+ "authmanager-authn-no-primary": "Uvedené přihlašovací údaje se nepodařilo autentizovat.",
+ "authmanager-authn-no-local-user": "Uvedené přihlašovací údaje neodpovídají žádnému uživateli této wiki.",
+ "authmanager-authn-no-local-user-link": "Uvedené přihlašovací údaje jsou platné, ale nejsou přiřazeny žádnému uživateli na této wiki. Přihlašte se jiným způsobem nebo si založte nový uživatelský účet a budete mít možnost s tímto účtem propojit vaše stávající přihlašovací údaje.",
+ "authmanager-authn-autocreate-failed": "Automatické založení lokálního účtu se nezdařilo: $1",
+ "authmanager-change-not-supported": "Uvedené přihlašovací údaje nelze změnit, protože by je nikdo nepoužíval.",
+ "authmanager-create-disabled": "Zakládání účtů je zakázáno.",
+ "authmanager-create-from-login": "Pro založení účtu vyplňte níže uvedená pole.",
+ "authmanager-create-not-in-progress": "Zakládání účtu neprobíhá nebo se ztratila data sezení. Začněte prosím znovu od začátku.",
+ "authmanager-create-no-primary": "Uvedené přihlašovací údaje nelze použít pro založení účtu.",
+ "authmanager-link-no-primary": "Uvedené přihlašovací údaje nelze použít pro propojení účtů.",
+ "authmanager-link-not-in-progress": "Propojování účtů neprobíhá nebo se ztratila data sezení. Začněte prosím znovu od začátku.",
+ "authmanager-authplugin-setpass-failed-title": "Změna hesla se nezdařila",
+ "authmanager-authplugin-setpass-failed-message": "Autentizační modul změnu hesla zamítl.",
+ "authmanager-authplugin-create-fail": "Autentizační modul založení účtu zamítl.",
+ "authmanager-authplugin-setpass-denied": "Autentizační modul neumožňuje měnit hesla.",
+ "authmanager-authplugin-setpass-bad-domain": "Neplatná doména.",
+ "authmanager-autocreate-noperm": "Automatické zakládání účtů není povoleno.",
+ "authmanager-autocreate-exception": "Automatické založení účtu je dočasně zakázáno kvůli předchozím chybám.",
+ "authmanager-userdoesnotexist": "Uživatelský účet „$1“ není zaregistrován.",
+ "authmanager-userlogin-remembermypassword-help": "Zda se má heslo zapamatovat déle než jen po dobu tohoto sezení.",
+ "authmanager-username-help": "Uživatelské jméno pro autentizaci.",
+ "authmanager-password-help": "Heslo pro autentizaci.",
+ "authmanager-domain-help": "Doména pro externí autentizaci.",
+ "authmanager-retype-help": "Heslo znovu pro potvrzení.",
+ "authmanager-email-label": "E-mail",
+ "authmanager-email-help": "E-mailová adresa",
+ "authmanager-realname-label": "Skutečné jméno",
+ "authmanager-realname-help": "Skutečné jméno uživatele",
+ "authmanager-provider-password": "Autentizace pomocí hesla",
+ "authmanager-provider-password-domain": "Autentizace pomocí hesla a domény",
+ "authmanager-provider-temporarypassword": "Dočasné heslo",
+ "authprovider-confirmlink-message": "Na základě vašich nedávných pokusů o přihlášení mohou být s vaším účtem na wiki propojeny následující účty. Propojením umožníte přihlášení pomocí těchto účtů. Vyberte účty, se kterými chcete svůj účet propojit.",
+ "authprovider-confirmlink-request-label": "Účty, se kterými chcete svůj účet propojit",
+ "authprovider-confirmlink-success-line": "$1: Úspěšně propojeno.",
+ "authprovider-confirmlink-failed": "Propojení účtů se nezdařilo zcela: $1",
+ "authprovider-confirmlink-ok-help": "Pokračovat po zobrazení hlášení o chybách propojení.",
+ "authprovider-resetpass-skip-label": "Přeskočit",
+ "authprovider-resetpass-skip-help": "Přeskočit nastavení nového hesla.",
+ "authform-nosession-login": "Autentizace byla úspěšná, ale váš prohlížeč si neumí „zapamatovat“, že je přihlášený.\n\n$1",
+ "authform-nosession-signup": "Účet byl založen, ale váš prohlížeč si neumí „zapamatovat“, že je přihlášený.\n\n$1",
+ "authform-newtoken": "Chybí token. $1",
+ "authform-notoken": "Chybí token",
+ "authform-wrongtoken": "Chybný token",
+ "specialpage-securitylevel-not-allowed-title": "Není povoleno",
+ "specialpage-securitylevel-not-allowed": "Je nám líto, ale nemáte povolení použít tuto stránku, protože se nepodařilo ověřit vaši totožnost.",
+ "authpage-cannot-login": "Nepodařilo se zahájit přihlašování.",
+ "authpage-cannot-login-continue": "Nepodařilo se pokračovat v přihlašování. Patrně vypršela platnost vašeho sezení.",
+ "authpage-cannot-create": "Nepodařilo se zahájit zakládání účtu.",
+ "authpage-cannot-create-continue": "Nepodařilo se pokračovat v zakládání účtu. Patrně vypršela platnost vašeho sezení.",
+ "authpage-cannot-link": "Nepodařilo se zahájit propojování účtů.",
+ "authpage-cannot-link-continue": "Nepodařilo se pokračovat v propojování účtů. Patrně vypršela platnost vašeho sezení.",
+ "cannotauth-not-allowed-title": "Přístup odmítnut",
+ "cannotauth-not-allowed": "Nemáte oprávnění použít tuto stránku",
+ "changecredentials": "Změna přihlašovacích údajů",
+ "changecredentials-submit": "Změnit přihlašovací údaje",
+ "changecredentials-invalidsubpage": "$1 není platný typ přihlašovacích údajů.",
+ "changecredentials-success": "Vaše přihlašovací údaje byly změněny.",
+ "removecredentials": "Odstranění přihlašovacích údajů",
+ "removecredentials-submit": "Odstranit přihlašovací údaje",
+ "removecredentials-invalidsubpage": "$1 není platný typ přihlašovacích údajů.",
+ "removecredentials-success": "Vaše přihlašovací údaje byly odstraněny.",
+ "credentialsform-provider": "Typ přihlašovacích údajů:",
+ "credentialsform-account": "Název účtu:",
+ "cannotlink-no-provider-title": "Neexistují účty k propojení",
+ "cannotlink-no-provider": "Neexistují účty k propojení.",
+ "linkaccounts": "Propojení účtů",
+ "linkaccounts-success-text": "Účet byl propojen.",
+ "linkaccounts-submit": "Propojit účty",
+ "unlinkaccounts": "Zrušení propojení účtů",
+ "unlinkaccounts-success": "Propojení účtu bylo zrušeno."
}
"loginerror": "Fela logòwaniô",
"loginsuccesstitle": "ùdałé logòwanié",
"loginsuccess": "Të jes wlogòwóny do {{SITENAME}} jakno \"$1\".",
- "nosuchuser": "Nie dô brëkòwnika ò mionie \"$1\".\nSprôwdzë pisënk abò [[Special:UserLogin/signup|ùsôdzë nowé kònto]].",
+ "nosuchuser": "Nie dô brëkòwnika ò mionie \"$1\".\nSprôwdzë pisënk abò [[Special:CreateAccount|ùsôdzë nowé kònto]].",
"nouserspecified": "Mùszisz pòdac miono brëkòwnika.",
"wrongpassword": "Lëchô parola.\nSpróbùjë znowa.",
"wrongpasswordempty": "Wpisónô parola je pùstô\nSpróbùjë znowa.",
"accmailtext": "Przëtrôfkòwò wëgenerowónô parola dlô [[User talk:$1|$1]] òsta wësłónô do $2.\n\nParolã dlô negò nowégò kònta mòże zmienic pò wlogòwaniu na starnie ''[[Special:ChangePassword|zjinaka parolë]]''.",
"newarticle": "(Nowi)",
"newarticletext": "Môsz przëszłi z lënkù do starnë jaka jesz nie òbstoji.\nBë ùsôdzëc artikel, naczni pisac w kastce niżi (òb. [$1 starnã pòmòcë]\ndlô wicy wëdowiédzë).\nJeżlë jes të tuwò bez zmiłkã, le klëkni w swòjim przezérnikù knąpã '''nazôd'''.",
- "anontalkpagetext": "----''To je starna dyskùsëji anonimòwiégò brëkòwnika, chtëren nie ùsôdzëł jesz swòjegò kòntae, abò gò nie brëkùje.\nAbë gò rozpòznac, ùżëwómë adresów IP.\nTakô adresa IP, mòże bëc równak brëkòwónô przez wiele lëdzy.\nJeżlë jes anonimòwim brëkòwnikã ë ùwôżôsz, że ne wiadła nie są do ce sczerowóne, tedë [[Special:UserLogin/signup|ùsôdzë nowé kònto]] abò [[Special:UserLogin|wlogùjë sã]], bë niechac niezrozmeiniô z jinyma anonimòwima brëkòwnikama.''",
+ "anontalkpagetext": "----''To je starna dyskùsëji anonimòwiégò brëkòwnika, chtëren nie ùsôdzëł jesz swòjegò kòntae, abò gò nie brëkùje.\nAbë gò rozpòznac, ùżëwómë adresów IP.\nTakô adresa IP, mòże bëc równak brëkòwónô przez wiele lëdzy.\nJeżlë jes anonimòwim brëkòwnikã ë ùwôżôsz, że ne wiadła nie są do ce sczerowóne, tedë [[Special:CreateAccount|ùsôdzë nowé kònto]] abò [[Special:UserLogin|wlogùjë sã]], bë niechac niezrozmeiniô z jinyma anonimòwima brëkòwnikama.''",
"noarticletext": "Felëje starna ò tim titlu.\nMòżesz [[Special:Search/{{PAGENAME}}|szëkac za {{PAGENAME}} na jinych starnach]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} szëkac w logù] abò [{{fullurl:{{FULLPAGENAME}}|action=edit}} ùsôdzëc nã starnã]</span>",
"clearyourcache": "'''Bôczë: Pò zapisanim, mòże bãdzesz mùszôł òminąc pamiãc przezérnika bë òbaczëc zmianë.'''\n'''Mozilla / Firefox / Safari:''' przëtrzëmôj ''Shift'' òbczas klëkaniô na ''Zladëjë znowa'', abò wcësni ''Ctrl-F5'' abò ''Ctrl-R'' (''Command-R'' na kòmpùtrach Mac);\n'''Konqueror:''': klëkni na knąpã ''Zladëjë znowa'', abò wcësni ''F5'';\n'''Opera:''' wëczëszczë pòdrãczną pamiãc w ''Tools→Preferences'';\n'''Internet Explorer:'''przëtrzëmôj ''Ctrl'' òbczas klëkaniô na ''Zladëjë znowa'', abò wcësni ''Ctrl-F5''.",
"updated": "(Zaktualnioné)",
"uploadwarning": "Òstrzega ò wladënkù",
"savefile": "Zapiszë lôpk",
"uploaddisabled": "Przeprôszómë! Mòżlëwòta wladënkù lopków na nen serwer òsta wëłączonô.",
- "upload-success-subj": "Wladënk darzëł sã",
"listfiles": "Lësta òbrôzków",
"listfiles_user": "Brëkòwnik",
"file-anchor-link": "Òbrôzk",
"linksearch": "Bùtnowé lënczi",
"listgrouprights-members": "(lësta nôlëżników karna)",
"emailuser": "Wëslë e-maila do negò brëkòwnika",
- "emailpage": "Sélajë e-mail do brëkòwnika",
"defemailsubject": "E-mail òd {{SITENAME}}",
"noemailtitle": "Felënk email-adresë",
"emailfrom": "Òd:",
"move-page-legend": "Przeniesë starnã",
"movepagetext": "Z pòmòcą ùiższegò fòrmùlôra zjinaczisz miono starnë, przenosząc równoczasno ji historëjã.\nPòd stôrim titlã bãdze ùsôdzonô przeczérowùjącô starna.\nMòżesz aùtomatno zaktualniac przeczérowania wskazëwôjące titel przed zjinaką.\nJeżlë nie wëbiérzesz ti òptacëji, ùgwësni sã pò przenieseniu starnë, czë nie òstałé ùsôdzoné [[Special:DoubleRedirects|dëbeltné]] abò [[Special:BrokenRedirects|zerwóné przeczérowania]].\nJes òdpòwiedzalny za to, abë lënczi dali robiłë tam dze mają.\n\nStarna '''ni''' bãdze przeniosłô, jeżlë starna ò nowim mionie ju je, chòba że je òna pùstô abò je przeczérowaniém ë mô pùstą historëjã edicëji.\nTo òznôczô, że lëchą òperacëjã zjinaczi miona mòże doprowôdzëc bezpieczno nazôd, zjinaczając nowé miono starnë nawczasniészą, ë że ni mòże nadpisac stranë chtërną ju dô.\n\n'''BÔCZËNK!'''\nTo mòże bëc drasticznô abò nieprzewidëwólnô zjinaka w przëtrôfkù pòpùlarnych starnów.\nÙgwësni sã co do skùtków ti òperacëji, niglë to zrobisz.",
"movepagetalktext": "Sparłãczonô starna diskùsëji, jeżlë ju je, to bãdze przeniosłô aùtomatno, chòba że:\n*niepùstô starna diskùsëji ju je z nowim mionã\n*rëmniész nacéchòwanié z niższegò pòla wëbiérkù\n\nW taczich przëtrôfkach zamkłosc diskùsëji mòże przeniesc blós rãczno.",
- "movearticle": "Przeniesë artikel",
"newtitle": "Nowi titel:",
"move-watch": "Ùzérôj tã starnã",
"movepagebtn": "Przeniesë starnã",
"movelogpage": "Przeniosłé",
"movereason": "Przëczëna:",
"revertmove": "copnij",
- "delete_and_move": "Rëmôj ë przeniesë",
"delete_and_move_confirm": "Jo, rëmôj ną starnã",
"export": "Ekspòrt starnów",
"allmessages": "Wszëtczé systemòwé ògłosë",
"specialpages": "Specjalné starnë",
"revdelete-restricted": "nastôwi ògrańczenia dlô sprôwników",
"revdelete-unrestricted": "rëmôj ògrańczenia dlô sprôwników",
- "revdelete-summary": "òpisënk zjinaczi"
+ "revdelete-summary": "òpisënk zjinaczi",
+ "special-characters-group-ipa": "IPA",
+ "special-characters-group-symbols": "Céchë",
+ "special-characters-group-greek": "Grecczi",
+ "special-characters-group-cyrillic": "Cërylica",
+ "special-characters-group-arabic": "Arabsczi",
+ "special-characters-group-hebrew": "Hebrajsczi"
}
"missingcommenttext": "Аяларах, тархасшăн, хăвар пĕлтерĕве çырăр.",
"summary-preview": "Ăнлантару çапла пулĕ:",
"subject-preview": "Статья ячĕ çапла пулĕ:",
- "blockedtitle": "Хутшăнакана ĕçлеме чарнă",
+ "blockedtitle": "Хутшăнакана чарса хунă",
"blockedtext": "'''Ку аккаунта е IP-адреса ĕçлеме чарнă.'''\n\n$1 администратор ĕçлеме чарнă. Сăлтавĕ çакă: ''«$2»''.\n\n* Чарнă вăхăт: $8\n* Çак вăхăтчен чарнă: $6\n* Çакна чарнă: $7\n\n$1 хутшăнакан патне, е ытти [[{{MediaWiki:Grouppage-sysop}}|администраторсем]] патне эсир çыру ярса меншĕн ĕçлеме чарнине сӳтсе явма пултаратăр.\n\nАсăрхар: [[Special:Preferences|хăвăрăн ĕнерлевсенче]] эл. почта адресне çирĕплетмен пулсан, е сайта кĕмен пулсан — администратор патне çыру яраймастăр. Администратор сире çыру яма чарнă пулсан — ку хутĕнче те çыру яраймăр.\n\nСирĕн IP-адрес — $3, чару идентификаторĕ — #$5. Çырусенче, тархасшăн, вĕсене пĕлтерĕр.",
"blockednoreason": "сăлтавне пĕлтермен",
"loginreqtitle": "Сайта кĕмелле",
"suppressionlog": "Пытару журналĕ",
"history-title": "\"$1\" улшăннисен историйĕ",
"lineno": "$1-мĕш йĕрке:",
- "editundo": "пăрахăçла",
+ "editundo": "унчченхи",
"searchresults": "Шыранă результачĕсем",
"textmatches": "Статьясенчи текст пĕрпеклĕхĕ",
"prevn": "унчченхи {{PLURAL:$1|$1}}",
"categories": "Категорисем",
"categories-submit": "Кăтарт",
"categoriespagetext": "Викинче çак категорисем пур.\n[[Special:UnusedCategories|Unused categories]] are not shown here.\nAlso see [[Special:WantedCategories|wanted categories]].",
- "special-categories-sort-count": "шучĕ тăрăх йĕркеле",
- "special-categories-sort-abc": "алфавит тăрăх йĕркеле",
"deletedcontributions": "Тулашран тунă ӳсĕм",
"linksearch-ns": "Ят хушши:",
"linksearch-ok": "Шырамалли",
"listusers-submit": "Кăтарт",
"listusers-noresult": "Хутшăнакансем тупăнмарĕç.",
+ "listusers-blocked": "(чарса хунă)",
+ "activeusers-count": "$1 {{PLURAL:$1|тӳрлетни|тӳрлетнисем}} юлашки {{PLURAL:$3|кун|$3 кунсенче}}",
"activeusers-hidesysops": "Администраторĕсене пытар",
"listgrouprights-group": "Ушкăн",
"listgrouprights-helppage": "Help:Ушкăн прависем",
"ipaddressorusername": "IP адрес е усă куракан ят:",
"ipbreason": "Сăлтавĕ",
"ipbother": "Урăх вăхăт:",
- "ipboptions": "2 Ñ\81еÑ\85еÑ\82:2 hours,1 кÑ\83н:1 day,3 кÑ\83н:3 days,1 Ñ\8dÑ\80не:1 week,2 Ñ\8dÑ\80не:2 weeks,1 Ñ\83йÄ\83Ñ\85:1 month,3 Ñ\83йÄ\83Ñ\85:3 months,6 Ñ\83йÄ\83Ñ\85:6 months,1 çÑ\83л:1 year,Ñ\8fванлÄ\83Ñ\85а:infinite",
+ "ipboptions": "2 Ñ\81еÑ\85еÑ\82:2 hours,1 кÑ\83н:1 day,3 кÑ\83н:3 days,1 Ñ\8dÑ\80не:1 week,2 Ñ\8dÑ\80не:2 weeks,1 Ñ\83йÄ\83Ñ\85:1 month,3 Ñ\83йÄ\83Ñ\85:3 months,6 Ñ\83йÄ\83Ñ\85:6 months,1 çÑ\83л:1 year,Ñ\8fлана:infinite",
"badipaddress": "IP-адрес формачĕ тĕрĕс мар, е ку ятлă хутшăнакан кунта çук.",
"blockipsuccesssub": "Ĕçлеме чартăмăр",
"blockipsuccesstext": "[[Special:Contributions/$1|«$1»]] ĕçлеме чарнă.\n<br />[[Special:BlockList|ĕçлеме чарнă IP-адрессен списокне]] пăх.",
"version": "Верси",
"redirect-submit": "Куç",
"fileduplicatesearch": "Пĕр пек файлсен шыравĕ",
- "fileduplicatesearch-legend": "Дубликатсен шыравĕ",
"fileduplicatesearch-filename": "Файл ячĕ:",
"fileduplicatesearch-submit": "Туп",
"specialpages": "Ятарлă страницăсем",
"tog-hideminor": "Cuddio golygiadau bychain yn rhestr y newidiadau diweddar",
"tog-hidepatrolled": "Cuddio golygiadau sydd wedi derbyn ymweliad patrôl rhag y rhestr newidiadau diweddar",
"tog-newpageshidepatrolled": "Cuddio tudalennau a batroliwyd o'r rhestr y tudalennau newydd",
- "tog-hidecategorization": "Cuddiwych y categoriau",
+ "tog-hidecategorization": "Cuddiwch y categoriau",
"tog-extendwatchlist": "Ehangu'r rhestr wylio i ddangos pob golygiad yn hytrach na'r diweddaraf yn unig",
"tog-usenewrc": "Grwpio'r newidiadau bob yn ddalen yn y 'newidiadau diweddar' a'r 'rhestr wylio'",
"tog-numberheadings": "Rhifo penawdau'n awtomatig",
"tog-watchlistreloadautomatically": "Ail-lwyther y Rhestr wylio yn otomatigpan newider ffiltr (angen JavaScript)",
"tog-watchlisthideanons": "Cuddio golygiadau gan ddefnyddwyr anhysbys rhag y rhestr wylio",
"tog-watchlisthidepatrolled": "Cuddio golygiadau sydd wedi derbyn ymweliad patrôl rhag y rhestr wylio",
- "tog-watchlisthidecategorization": "Cuddiwych y categoriau",
+ "tog-watchlisthidecategorization": "Cuddiwch y categoriau",
"tog-ccmeonemails": "Anfon copi ataf pan anfonaf e-bost at ddefnyddiwr arall",
"tog-diffonly": "Peidio â dangos cynnwys y dudalen islaw'r gymhariaeth ar dudalennau cymharu",
"tog-showhiddencats": "Dangos categorïau cuddiedig",
"noname": "Dydych chi ddim wedi cynnig enw defnyddiwr dilys.",
"loginsuccesstitle": "Llwyddodd y mewngofnodi",
"loginsuccess": "'''Yr ydych wedi mewngofnodi i {{SITENAME}} fel \"$1\".'''",
- "nosuchuser": "Does dim defnyddiwr o'r enw \"$1\".\nMae'r rhaglen yn gwahaniaethu rhwng llythrennau bach a mawr.\nSicrhewch eich bod chi wedi sillafu'r enw'n gywir, neu [[Special:UserLogin/signup|crëwch gyfrif newydd]].",
+ "nosuchuser": "Does dim defnyddiwr o'r enw \"$1\".\nMae'r rhaglen yn gwahaniaethu rhwng llythrennau bach a mawr.\nSicrhewch eich bod chi wedi sillafu'r enw'n gywir, neu [[Special:CreateAccount|crëwch gyfrif newydd]].",
"nosuchusershort": "Does dim defnyddiwr o'r enw \"$1\". Gwiriwch eich sillafu.",
"nouserspecified": "Mae'n rhaid nodi enw defnyddiwr.",
"login-userblocked": "Mae'r defnyddiwr hwn wedi ei flocio. Ni ellir mewngofnodi.",
"accmailtext": "Anfonwyd cyfrinair a grewyd ar hap ar gyfer [[User talk:$1|$1]] at $2. Gellir newid y cyfrinair hwn ar y dudalen ''[[Special:ChangePassword|newid cyfrinair]]'', wrth fewngofnodi.",
"newarticle": "(Newydd)",
"newarticletext": "Rydych chi wedi dilyn cysylltiad i dudalen sydd heb gael ei chreu eto.\nI greu'r dudalen, dechreuwch deipio yn y blwch isod (gweler y [$1 dudalen gymorth] am fwy o wybodaeth).\nOs daethoch yma ar ddamwain, cliciwch botwm '''nôl''' y porwr.",
- "anontalkpagetext": "----''Dyma dudalen sgwrs ar gyfer defnyddiwr anhysbys sydd heb greu cyfrif eto, neu nad yw'n ei ddefnyddio. Felly mae'n rhaid inni ddefnyddio'r cyfeiriad IP i'w (h)adnabod. Mae cyfeiriadau IP yn gallu cael eu rhannu rhwng nifer o ddefnyddwyr. Os ydych chi'n ddefnyddiwr anhysbys ac yn teimlo'ch bod wedi derbyn sylwadau amherthnasol, [[Special:UserLogin/signup|crëwch gyfrif]] neu [[Special:UserLogin|mewngofnodwch]] i osgoi cael eich drysu gyda defnyddwyr anhysbys eraill o hyn ymlaen.''",
+ "anontalkpagetext": "----''Dyma dudalen sgwrs ar gyfer defnyddiwr anhysbys sydd heb greu cyfrif eto, neu nad yw'n ei ddefnyddio. Felly mae'n rhaid inni ddefnyddio'r cyfeiriad IP i'w (h)adnabod. Mae cyfeiriadau IP yn gallu cael eu rhannu rhwng nifer o ddefnyddwyr. Os ydych chi'n ddefnyddiwr anhysbys ac yn teimlo'ch bod wedi derbyn sylwadau amherthnasol, [[Special:CreateAccount|crëwch gyfrif]] neu [[Special:UserLogin|mewngofnodwch]] i osgoi cael eich drysu gyda defnyddwyr anhysbys eraill o hyn ymlaen.''",
"noarticletext": "Mae'r dudalen hon yn wag ar hyn o bryd.\nGallwch [[Special:Search/{{PAGENAME}}|chwilio am y teitl hwn]] ar ddalennau eraill, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} chwilio drwy'r logiau perthnasol], neu [{{fullurl:{{FULLPAGENAME}}|action=edit}} fe allwch greu'r ddalen hon]</span>.",
"noarticletext-nopermission": "Mae'r dudalen hon yn wag ar hyn o bryd.\nGallwch [[Special:Search/{{PAGENAME}}|chwilio am y teitl hwn]] ar dudalennau eraill, neu gallwch <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} chwilio drwy'r logiau perthnasol]</span>, ond nid yw'r gallu gennych i ddechrau'r dudalen o'r dechrau cyntaf.",
"missing-revision": "Nid yw'r diwygiad #$1 o'r dudalen \"{{FULLPAGENAME}}\" ar gael.\n\nFel arfer, fe ddigwydd hyn wrth ddilyn hen gyswllt i dudalen sydd wedi ei dileu.\nGallwch weld y manylion yn y [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} lòg dileu].",
"rcshowhidemine": "$1 fy ngolygiadau",
"rcshowhidemine-show": "Dangoser",
"rcshowhidemine-hide": "Cuddier",
- "rcshowhidecategorization": "Categorieiddio tudalen $1",
+ "rcshowhidecategorization": "Categoreiddio tudalen $1",
"rcshowhidecategorization-show": "Dangos",
"rcshowhidecategorization-hide": "Cuddio",
"rclinks": "Dangos y $1 newid diweddaraf yn ystod y(r) $2 diwrnod diwethaf<br />$3",
"upload-form-label-own-work": "Dyma fy ngwaith fy hun",
"upload-form-label-infoform-categories": "Categoriau",
"upload-form-label-infoform-date": "Dyddiad",
- "upload-form-label-own-work-message-local": "Rwy'n cadarnhau fy mod yn uwchlwytho'r ffeil yma gan ddilyn amodau a pholisiau trwyddedu {{SITENAME}}.",
- "upload-form-label-not-own-work-local-local": "Efallai y carwch hefyd roi gynnig ar [[Special:Upload|y ddalen uwchlwytho diofyn]].",
- "upload-form-label-own-work-message-default": "Rwy'n cadarnhau fy mod yn uwchlwytho'r ffeil yma i fan sy'n cael ei rannu gan nifer. Rwy'n cadarnhau hefyd y gwnaf hyn gan ddilyn yr amodau a'r polisiau trwyddedu sydd yno.",
- "upload-form-label-own-work-message-shared": "Cadarnhaf mai fi yw perchennog hawlfraint y ffeil hon, a chytunaf yn ddi-droi'n ôl i ryddhau'r ffeil hon i Gomin Wicimedia dan drwydded [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], a chytunaf gyda'r[https://wikimediafoundation.org/wiki/Terms_of_Use Amodau Defnyddio].",
+ "upload-form-label-own-work-message-generic-local": "Rwy'n cadarnhau fy mod yn uwchlwytho'r ffeil yma gan ddilyn amodau a pholisiau trwyddedu {{SITENAME}}.",
+ "upload-form-label-not-own-work-local-generic-local": "Efallai y carwch hefyd roi gynnig ar [[Special:Upload|y ddalen uwchlwytho diofyn]].",
+ "upload-form-label-own-work-message-generic-foreign": "Rwy'n cadarnhau fy mod yn uwchlwytho'r ffeil yma i fan sy'n cael ei rannu gan nifer. Rwy'n cadarnhau hefyd y gwnaf hyn gan ddilyn yr amodau a'r polisiau trwyddedu sydd yno.",
"backend-fail-stream": "Wedi methu ffrydio'r ffeil $1.",
"backend-fail-backup": "Wedi methu gwneud copi wrth gefn o'r ffeil $1.",
"backend-fail-notexists": "Nid yw'r ffeil $1 ar gael.",
"Stefan2",
"Ribewiki",
"Jens Jensen",
- "Nemo bis"
+ "Nemo bis",
+ "Anders Feder"
]
},
"tog-underline": "Understreg henvisninger:",
"tog-watchdefault": "Tilføj sider og filer, jeg redigerer, til min overvågningsliste",
"tog-watchmoves": "Tilføj sider og filer, jeg flytter, til min overvågningsliste",
"tog-watchdeletion": "Tilføj sider og filer, jeg sletter, til min overvågningsliste",
+ "tog-watchuploads": "Tilføj nye filer jeg uploader til min overvågningsliste",
"tog-watchrollback": "Tilføj sider, hvor jeg har udført en tilbagerulning til min overvågningsliste",
"tog-minordefault": "Markér som standard alle redigeringer som mindre",
"tog-previewontop": "Vis forhåndsvisning over redigeringsboksen",
"october-date": "$1. oktober",
"november-date": "$1. november",
"december-date": "$1. december",
+ "period-am": "AM",
+ "period-pm": "PM",
"pagecategories": "{{PLURAL:$1|Kategori|Kategorier}}",
"category_header": "Sider i kategorien \"$1\"",
"subcategories": "Underkategorier",
"databaseerror-query": "Forespørgsel: $1",
"databaseerror-function": "Funktion: $1",
"databaseerror-error": "Fejl: $1",
+ "transaction-duration-limit-exceeded": "For at undgå høje replikationsforsinkelser blev denne transaktion afbrudt fordi tiden det tog at lagre ($1) oversteg maksimumsgrænsen på $2 {{PLURAL:$2|sekund|sekunder}}.\nHvis du er ved at ændre mange emner på en gang, så prøv at udføre flere mindre operationer i stedet.",
"laggedslavemode": "'''Bemærk:''' Den viste side indeholder muligvis ikke de nyeste ændringer.",
"readonly": "Databasen er skrivebeskyttet",
"enterlockreason": "Skriv en begrundelse for skrivebeskyttelsen, med samt en vurdering af, hvornår skrivebeskyttelsen ophæves igen",
- "readonlytext": "Databasen er i øjeblikket låst for nye poster og andre ændringer, sandsynligvis for rutinemæssig databasevedligeholdelse, hvorefter den vil være tilbage til normal.\n\nDen administrator som har låst, gav denne forklaring: $1",
+ "readonlytext": "Databasen er i øjeblikket låst for nye poster og andre ændringer, formentlig pga. rutinemæssig databasevedligeholdelse, hvorefter den vil være tilbage til normalen.\n\nSystemadministratoren som låste den, gav denne forklaring: $1",
"missing-article": "Databasen burde indeholde siden \"$1\" $2, men det gør den ikke.\n\nDen sandsynlige årsag er at du har fulgt et forældet link til en forskel eller en gammel version af en side der er blevet slettet.\n\nHvis det ikke er tilfældet, har du muligvis fundet en software-fejl.\nGør venligst en [[Special:ListUsers/sysop|administrator]] opmærksom på det, og husk at fortælle hvilken URL du har fulgt.",
"missingarticle-rev": "(versionsnummer: $1)",
"missingarticle-diff": "(Forskel: $1, $2)",
"readonly_lag": "Databasen er automatisk blevet låst mens slave database serverne synkronisere med master databasen",
+ "nonwrite-api-promise-error": "HTTP-headeren 'Promise-Non-Write-API-Action' blev sendt, men forespørgslen var til et API skrivemodul.",
"internalerror": "Intern fejl",
"internalerror_info": "Intern fejl: $1",
"internalerror-fatal-exception": "Alvorlig undtagelse af typen \"$1\"",
"mypreferencesprotected": "Du har ikke rettigheder til at redigere dine indstillinger.",
"ns-specialprotected": "Sider i navnerummet {{ns:special}} kan ikke redigeres.",
"titleprotected": "Dette sidenavn er blevet beskyttet mod oprettelse af [[User:$1|$1]]. Begrundelsen for beskyttelsen er <em>$2</em>.",
- "filereadonlyerror": "Ude af stand til at redigere filen \"$1\", fordi fildatabasen \"$2\" er skrivebeskyttet.\n\nAdministratoren, som skrivebeskyttede den, gav følgende begrundelse: \"$3\".",
+ "filereadonlyerror": "Ude af stand til at redigere filen \"$1\", fordi fildatabasen \"$2\" er skrivebeskyttet.\n\nSystemadministratoren, som skrivebeskyttede den, gav denne begrundelse: \"$3\".",
"invalidtitle-knownnamespace": "Ugyldig titel med navnerummet \"$2\" og teksten \"$3\"",
"invalidtitle-unknownnamespace": "Ugyldig titel med ukendt navnerum nummer $1 og tekst \"$2\"",
"exception-nologin": "Ikke logget på",
"password-change-forbidden": "Du kan ikke ændre adgangskoder på denne wiki.",
"externaldberror": "Der er opstået en fejl i en ekstern adgangsdatabase, eller du har ikke rettigheder til at opdatere denne.",
"login": "Log på",
+ "login-security": "Bekræft din identitet",
"nav-login-createaccount": "Opret en konto eller log på",
"userlogin": "Opret en konto eller log på",
"userloginnocreate": "Log på",
"userlogin-resetpassword-link": "Glemt din adgangskode?",
"userlogin-helplink2": "Hjælp med at logge på",
"userlogin-loggedin": "Du er allerede logget på som {{GENDER:$1|$1}}.\nBrug formularen nedenfor til at logge på som en anden bruger.",
+ "userlogin-reauth": "Du skal logge på igen for at bekræfte, at du er {{GENDER:$1|$1}}.",
"userlogin-createanother": "Opret en anden konto",
"createacct-emailrequired": "E-mailadresse",
"createacct-emailoptional": "E-mailadresse (valgfri)",
"createacct-email-ph": "Indtast din e-mailadresse",
"createacct-another-email-ph": "Indtast e-mailadresse",
"createaccountmail": "Brug en midlertidig tilfældig adgangskode og send den til den angivne e-mailadresse",
+ "createaccountmail-help": "Kan bruges til at oprette konto til en anden person uden at lære deres adgangskode.",
"createacct-realname": "Dit rigtige navn (valgfrit)",
"createaccountreason": "Begrundelse:",
"createacct-reason": "Årsag",
"noname": "Du har ikke angivet et gyldigt brugernavn.",
"loginsuccesstitle": "Du er nu logget på",
"loginsuccess": "'''Du er nu logget på {{SITENAME}} som \"$1\".'''",
- "nosuchuser": "Der er ingen bruger med navnet \"$1\".\nDer skelnes mellem store og bogstaver i brugernavne.\nKontrollér stavemåden, eller [[Special:UserLogin/signup|opret en ny konto]].",
+ "nosuchuser": "Der er ingen bruger med navnet \"$1\".\nDer skelnes mellem store og bogstaver i brugernavne.\nKontrollér stavemåden, eller [[Special:CreateAccount|opret en ny konto]].",
"nosuchusershort": "Der er ingen bruger ved navn \"$1\". Tjek din stavning.",
"nouserspecified": "Angiv venligst et brugernavn.",
"login-userblocked": "Denne bruger er blokeret. Det er ikke tilladt at logge på.",
"accmailtext": "En tilfældigt dannet adgangskode for [[User talk:$1|$1]] er sendt til $2. Den kan ændres på siden ''[[Special:ChangePassword|skift adgangskode]]'', når du logger på.",
"newarticle": "(Ny)",
"newarticletext": "Du har fulgt en henvisning til en side som endnu ikke findes.\nFor at oprette siden skal du begynde at skrive i boksen nedenfor\n(se [$1 hjælpesiden] for yderligere information).\nHvis du er her ved en fejl, så tryk på din browsers '''tilbage'''-knap.",
- "anontalkpagetext": "---- ''Dette er en diskussionsside for en anonym bruger, der ikke har oprettet en konto endnu eller ikke bruger den.\nVi er derfor nødt til at bruge den numeriske IP-adresse til at identificere ham eller hende.\nEn IP-adresse kan være delt mellem flere brugere.\nHvis du er en anonym bruger og synes, at du har fået irrelevante kommentarer på sådan en side, så vær venlig at [[Special:UserLogin/signup|oprette en brugerkonto]] og [[Special:UserLogin|logge på]], så vi undgår fremtidige forvekslinger med andre anonyme brugere.''",
+ "anontalkpagetext": "---- ''Dette er en diskussionsside for en anonym bruger, der ikke har oprettet en konto endnu eller ikke bruger den.\nVi er derfor nødt til at bruge den numeriske IP-adresse til at identificere ham eller hende.\nEn IP-adresse kan være delt mellem flere brugere.\nHvis du er en anonym bruger og synes, at du har fået irrelevante kommentarer på sådan en side, så vær venlig at [[Special:CreateAccount|oprette en brugerkonto]] og [[Special:UserLogin|logge på]], så vi undgår fremtidige forvekslinger med andre anonyme brugere.''",
"noarticletext": "Der er i øjeblikket ikke nogen tekst på denne side.\nDu kan [[Special:Search/{{PAGENAME}}|søge efter sidenavnet]] på andre sider,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søge i relaterede logger]\neller [{{fullurl:{{FULLPAGENAME}}|action=edit}} oprette siden]</span>.",
"noarticletext-nopermission": "Der er i øjeblikket ikke nogen tekst på denne side.\nDu kan [[Special:Search/{{PAGENAME}}|søge efter sidenavnet]] på andre sider,\neller <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søge i relaterede loglister]</span>,\nmen du har ikke tilladelse til at oprette denne side.",
"missing-revision": "Revision #$1 af siden med navnet \"{{FULLPAGENAME}}\" eksisterer ikke.\n\nDette skyldes normalt at et forældet historik-link er fulgt til en side der er slettet.\nDetaljer kan findes i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} sletningsloggen].",
"recentchanges-legend-heading": "<strong>Forklaring:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (se også [[Special:NewPages|listen over nye sider]])",
"recentchanges-legend-plusminus": "(''±123'')",
+ "recentchanges-submit": "Vis",
"rcnotefrom": "Nedenfor er op til '''$1''' {{PLURAL:$5|ændring|ændringer}} siden '''$2''' vist.",
"rclistfrom": "Vis nye ændringer startende fra den $3 kl. $2",
"rcshowhideminor": "$1 mindre ændringer",
"upload-form-label-usage-filename": "Filnavn",
"upload-form-label-infoform-categories": "Kategorier",
"upload-form-label-infoform-date": "Dato",
- "upload-form-label-own-work-message-local": "Jeg bekræfter at jeg uploader filen i overenstemmelse med betingelser for brug og licenseringspoltikken på {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Hvis du ikke kan uploade filen under politikerne på {{SITENAME}}, skal du lukke dialogboksen og prøve en anden metode.",
- "upload-form-label-not-own-work-local-local": "Du kan også vælge at prøve [[Special:Upload|den almindelige uploadside]].",
+ "upload-form-label-own-work-message-generic-local": "Jeg bekræfter at jeg uploader filen i overenstemmelse med betingelser for brug og licenseringspoltikken på {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Hvis du ikke kan uploade filen under politikerne på {{SITENAME}}, skal du lukke dialogboksen og prøve en anden metode.",
+ "upload-form-label-not-own-work-local-generic-local": "Du kan også vælge at prøve [[Special:Upload|den almindelige uploadside]].",
"backend-fail-stream": "Kunne ikke streame filen $1.",
"backend-fail-backup": "Kunne ikke lave sikkerhedskopi af filen $1.",
"backend-fail-notexists": "Filen $1 findes ikke.",
"apisandbox": "API-sandkassen",
"apisandbox-api-disabled": "API er deaktiveret på dette websted.",
"apisandbox-intro": "Brug denne side til at eksperimentere med '''MediaWiki web service API'''.\nVi henviser til [//www.mediawiki.org/wiki/API:Main_page dokumentationen af API] for yderligere oplysninger om brug af API. Eksempel: [//www.mediawiki.org/wiki/API#A_simple_example få indholdet af en forside]. Vælg en handling at se flere eksempler.\n\nBemærk, at selv om dette er en sandkasse, vil handlinger du udfører på denne side redigere wikien.",
+ "apisandbox-unfullscreen": "Vis side",
"apisandbox-submit": "Lav forespørgsel",
"apisandbox-reset": "Ryd",
"apisandbox-examples": "Eksempler",
"specialloguserlabel": "Udført af:",
"speciallogtitlelabel": "Mål (titel eller {{ns:user}}:brugernavn for bruger):",
"log": "Loglister",
+ "logeventslist-submit": "Vis",
"all-logs-page": "Alle offentlige logger",
"alllogstext": "Samlet visning af alle loggene på {{SITENAME}}.\nDu kan afgrænse visningen ved at vælge en logtype, brugernavn eller påvirket side. Der skelnes mellem små og store bogstaver for både bruger- og sidenavne.",
"logempty": "Intet passende fundet.",
"cachedspecial-viewing-cached-ts": "Du ser en hengemt version af denne side, som måske ikke er helt aktuel.",
"cachedspecial-refresh-now": "Vis seneste.",
"categories": "Kategorier",
+ "categories-submit": "Vis",
"categoriespagetext": "Følgende {{PLURAL:$1|kategori|kategorier}} indeholder sider eller media.\n[[Special:UnusedCategories|Ubrugte kategorier]] vises ikke her.\nSe også [[Special:WantedCategories|ønskede kategorier]].",
"categoriesfrom": "Vis kategorier startende med:",
"deletedcontributions": "Slettede brugerbidrag",
"wlnote": "Nedenfor ses {{PLURAL:$1|den seneste ændring|de seneste <strong>$1</strong> ændringer}} i {{PLURAL:$2|den sidste time|de sidste <strong>$2</strong> timer}} op til den $3 kl. $4.",
"wlshowlast": "Vis de seneste $1 timer $2 dage",
"watchlist-hide": "Skjul",
+ "watchlist-submit": "Vis",
"wlshowtime": "Vis seneste:",
"wlshowhideminor": "mindre ændringer",
"wlshowhidebots": "robotter",
"delete-confirm": "Slet \"$1\"",
"delete-legend": "Slet",
"historywarning": "<strong>Advarsel:</strong> Siden du er ved at slette har en historie med $1 {{PLURAL:$1|version|versioner}}:",
+ "historyaction-submit": "Vis",
"confirmdeletetext": "Du er ved at slette en side sammen med hele dens tilhørende historik.\nBekræft venligst at du virkelig vil gøre dette, at du forstår konsekvenserne, og at du gør det i overensstemmelse med [[{{MediaWiki:Policy-url}}|retningslinjerne]].",
"actioncomplete": "Gennemført",
"actionfailed": "Handlingen mislykkedes",
"revdelete-restricted": "tilføjede begrænsninger for administratorer",
"revdelete-unrestricted": "fjernede begrænsninger for administratorer",
"logentry-block-block": "$1 {{GENDER:$2|blokerede}} {{GENDER:$4|$3}} med en udløbstid på $5 $6",
+ "logentry-block-unblock": "$1 {{GENDER:$2|ophævede blokering af}} {{GENDER:$4|$3}}",
"logentry-block-reblock": "$1 {{GENDER:$2|ændrede}} blokeringsindstillinger for {{GENDER:$4|$3}} med en udløbstid på $5 $6",
"logentry-suppress-reblock": "$1 {{GENDER:$2|ændrede}} blokeringsindstillinger for {{GENDER:$4|$3}} med en udløbstid på $5 $6",
"logentry-move-move": "$1 {{GENDER:$2|flyttede}} siden $3 til $4",
"mw-widgets-titleinput-description-new-page": "side eksisterer ikke endnu",
"mw-widgets-titleinput-description-redirect": "omdiriger til $1",
"api-error-blacklisted": "Vælg venligst en anden, beskrivende titel.",
- "randomrootpage": "Tilfældig stamside"
+ "randomrootpage": "Tilfældig stamside",
+ "log-action-filter-block": "Blokeringstype:",
+ "log-action-filter-move": "Flyttetype:",
+ "log-action-filter-patrol": "Patruljeringstype:",
+ "log-action-filter-protect": "Beskyttelsestype:",
+ "log-action-filter-block-block": "Blokering",
+ "log-action-filter-block-reblock": "Ændring af blokering",
+ "log-action-filter-delete-delete": "Sidesletning",
+ "log-action-filter-delete-restore": "Sidegendannelse",
+ "log-action-filter-delete-event": "Logsletning",
+ "log-action-filter-delete-revision": "Revisionssletning",
+ "log-action-filter-move-move": "Flytning uden overskrivelse af omdirigeringer",
+ "log-action-filter-move-move_redir": "Flytning med overskrivelse af omdirigeringer",
+ "log-action-filter-patrol-patrol": "Manuel patruljering",
+ "log-action-filter-patrol-autopatrol": "Automatisk patruljering",
+ "log-action-filter-protect-protect": "Beskyttelse",
+ "log-action-filter-protect-modify": "Ændring af beskyttelse",
+ "log-action-filter-protect-unprotect": "Fjernede beskyttelse",
+ "log-action-filter-protect-move_prot": "Flyttede beskyttelse"
}
"MGChecker",
"FriedhelmW",
"Schniggendiller",
- "Predatorix"
+ "Predatorix",
+ "Matma Rex"
]
},
"tog-underline": "Links unterstreichen:",
"tog-ccmeonemails": "Schicke mir Kopien der E-Mails, die ich anderen Benutzern sende",
"tog-diffonly": "Beim Versionsvergleich nur die Unterschiede und nicht die vollständige Seite anzeigen",
"tog-showhiddencats": "Versteckte Kategorien anzeigen",
- "tog-norollbackdiff": "Unterschied nach dem Zurücksetzen unterdrücken",
+ "tog-norollbackdiff": "Unterschied nach dem Zurücksetzen nicht anzeigen",
"tog-useeditwarning": "Warnen, sofern eine zur Bearbeitung geöffnete Seite verlassen wird, die nicht gespeicherte Änderungen enthält",
"tog-prefershttps": "Wenn angemeldet, immer eine sichere Verbindung benutzen.",
"underline-always": "immer",
"databaseerror-query": "Abfrage: $1",
"databaseerror-function": "Funktion: $1",
"databaseerror-error": "Fehler: $1",
- "transaction-duration-limit-exceeded": "Um eine hohe Nachbildungsverzögerung zu vermeiden, wurde diese Transaktion abgebrochen, da die Schreibdauer ($1) die Grenze von {{PLURAL:$2|einer Sekunde|$2 Sekunden}} überschritten hat. Falls du viele Objekte auf einmal änderst, versuche stattdessen, mehrere kleine Operationen auszuführen.",
+ "transaction-duration-limit-exceeded": "Um eine große Verzögerung in der Datenreplikation zu vermeiden, wurde diese Transaktion abgebrochen. Die Schreibdauer ($1) hat die Grenze von {{PLURAL:$2|einer Sekunde|$2 Sekunden}} überschritten. Falls du viele Objekte auf einmal änderst, versuche stattdessen, die Änderungen auf mehrere Operationen aufzuteilen.",
"laggedslavemode": "<strong>Achtung:</strong> Die angezeigte Seite könnte unter Umständen nicht die letzten Bearbeitungen enthalten.",
"readonly": "Datenbank gesperrt",
"enterlockreason": "Bitte gib einen Grund ein, warum die Datenbank gesperrt werden soll und eine Abschätzung über die Dauer der Sperrung",
"password-change-forbidden": "Du kannst auf diesem Wiki keine Passwörter ändern.",
"externaldberror": "Entweder liegt ein Fehler bei der externen Authentifizierung vor oder du darfst dein externes Benutzerkonto nicht aktualisieren.",
"login": "Anmelden",
+ "login-security": "Verifiziere deine Identität",
"nav-login-createaccount": "Anmelden / Benutzerkonto erstellen",
"userlogin": "Anmelden / Benutzerkonto anlegen",
"userloginnocreate": "Anmelden",
"userlogin-resetpassword-link": "Passwort vergessen?",
"userlogin-helplink2": "Hilfe beim Anmelden",
"userlogin-loggedin": "Du bist bereits als {{GENDER:$1|$1}} angemeldet.\nBenutze das unten stehende Formular, um dich unter einem anderen Benutzernamen anzumelden.",
+ "userlogin-reauth": "Du musst dich erneut anmelden, um zu verifizieren, dass du {{GENDER:$1|$1}} bist.",
"userlogin-createanother": "Ein weiteres Benutzerkonto erstellen",
"createacct-emailrequired": "E-Mail-Adresse",
"createacct-emailoptional": "E-Mail-Adresse (optional)",
"createacct-email-ph": "Gib deine E-Mail-Adresse ein",
"createacct-another-email-ph": "E-Mail-Adresse",
"createaccountmail": "Ein temporäres Zufallspasswort verwenden und an die angegebene E-Mail-Adresse versenden",
+ "createaccountmail-help": "Kann verwendet werden, um für eine andere Person ein Benutzerkonto zu erstellen, ohne das Passwort zu erfahren.",
"createacct-realname": "Bürgerlicher Name (optional)",
"createaccountreason": "Grund:",
"createacct-reason": "Begründung",
"createacct-reason-ph": "Warum erstellst du ein anderes Benutzerkonto?",
+ "createacct-reason-help": "Im Neuanmeldungs-Logbuch angezeigte Nachricht",
"createacct-submit": "Benutzerkonto erstellen",
"createacct-another-submit": "Benutzerkonto erstellen",
+ "createacct-continue-submit": "Benutzerkontenerstellung fortfahren",
+ "createacct-another-continue-submit": "Benutzerkontenerstellung fortfahren",
"createacct-benefit-heading": "{{SITENAME}} wird von Menschen wie dir geschaffen.",
"createacct-benefit-body1": "{{PLURAL:$1|Bearbeitung|Bearbeitungen}}",
"createacct-benefit-body2": "{{PLURAL:$1|Seite|Seiten}}",
"nocookiesnew": "Der Benutzerzugang wurde erstellt, aber du bist nicht angemeldet. {{SITENAME}} benötigt für diese Funktion Cookies, bitte aktiviere diese und melde dich dann mit deinem neuen Benutzernamen und dem zugehörigen Passwort an.",
"nocookieslogin": "{{SITENAME}} benutzt Cookies zur Anmeldung der Benutzer. Du hast Cookies deaktiviert, bitte aktiviere diese und versuche es erneut.",
"nocookiesfornew": "Das Benutzerkonto wurde nicht erstellt, da die Datenherkunft nicht ermittelt werden konnte.\nBitte stelle sicher, dass du Cookies aktiviert hast. Lade diese Seite danach erneut und versuche es noch einmal.",
+ "createacct-loginerror": "Das Benutzerkonto wurde erfolgreich erstellt, aber du konntest nicht automatisch angemeldet werden. Bitte fahre mit der [[Special:UserLogin|manuellen Anmeldung]] fort.",
"noname": "Du musst einen gültigen Benutzernamen angeben.",
"loginsuccesstitle": "Angemeldet",
"loginsuccess": "<strong>Du bist jetzt als „$1“ bei {{SITENAME}} angemeldet.</strong>",
- "nosuchuser": "Der Benutzername „$1“ existiert nicht.\nÜberprüfe die Schreibweise (Groß-/Kleinschreibung beachten) oder [[Special:UserLogin/signup|lege ein neues Benutzerkonto an]].",
+ "nosuchuser": "Der Benutzername „$1“ existiert nicht.\nÜberprüfe die Schreibweise (Groß-/Kleinschreibung beachten) oder [[Special:CreateAccount|lege ein neues Benutzerkonto an]].",
"nosuchusershort": "Der Benutzername „$1“ ist nicht vorhanden. Bitte überprüfe die Schreibweise.",
"nouserspecified": "Bitte gib einen Benutzernamen an.",
"login-userblocked": "{{GENDER:$1|Dieser Benutzer|Diese Benutzerin}} ist gesperrt. Die Anmeldung ist nicht erlaubt.",
"createacct-another-realname-tip": "Der bürgerliche Name ist optional.\nWenn du ihn angibst, wird er für die Zuordnung der Beiträge verwendet.",
"pt-login": "Anmelden",
"pt-login-button": "Anmelden",
+ "pt-login-continue-button": "Anmeldung fortfahren",
"pt-createaccount": "Benutzerkonto erstellen",
"pt-userlogout": "Abmelden",
"php-mail-error-unknown": "Unbekannter Fehler in der PHP-Funktion mail().",
"botpasswords-invalid-name": "Der angegebene Benutzername enthält keinen Botpassworttrenner („$1“).",
"botpasswords-not-exist": "Der Benutzer „$1“ hat kein Botpasswort mit dem Namen „$2“.",
"resetpass_forbidden": "Das Passwort kann nicht geändert werden.",
+ "resetpass_forbidden-reason": "Die Passwörter können nicht geändert werden: $1",
"resetpass-no-info": "Du musst dich anmelden, um auf diese Seite direkt zuzugreifen.",
"resetpass-submit-loggedin": "Passwort ändern",
"resetpass-submit-cancel": "Abbrechen",
"passwordreset-emailsentusername": "Falls es eine E-Mail-Adresse gibt, die mit diesem Benutzernamen verknüpft ist, wird eine Passwort-Zurücksetzungs-E-Mail versandt.",
"passwordreset-emailsent-capture": "Eine Passwortzurücksetzungs-E-Mail wurde versandt, die unten angezeigt wird.",
"passwordreset-emailerror-capture": "Die unten angezeigte Passwortzurücksetzungs-E-Mail wurde generiert, allerdings ist der Versand an {{GENDER:$2|den Benutzer|die Benutzerin}} gescheitert: $1",
+ "passwordreset-emailsent-capture2": "Die Passwort-Zurücksetzungs-{{PLURAL:$1|E-Mail wurde|E-Mails wurden}} versandt. {{PLURAL:$1|Der Benutzername und das Passwort|Die Liste der Benutzernamen und Passwörter}} wird unten angezeigt.",
+ "passwordreset-emailerror-capture2": "Das Senden der E-Mail an {{GENDER:$2|den Benutzer|die Benutzerin}} ist fehlgeschlagen: $1 {{PLURAL:$3|Der Benutzername und das Passwort|Die Liste der Benutzernamen und Passwörter}} wird unten angezeigt.",
+ "passwordreset-nocaller": "Es muss ein Rufer angegeben werden",
+ "passwordreset-nosuchcaller": "Rufer ist nicht vorhanden: $1",
+ "passwordreset-ignored": "Die Passwortzurücksetzung konnte nicht verarbeitet werden. Vielleicht wurde kein Dienstanbieter konfiguriert?",
+ "passwordreset-invalideamil": "Ungültige E-Mail-Adresse",
+ "passwordreset-nodata": "Weder ein Benutzername noch eine E-Mail-Adresse wurde angegeben",
"changeemail": "E-Mail-Adresse ändern oder entfernen",
"changeemail-header": "Fülle dieses Formular vollständig aus, um deine E-Mail-Adresse zu ändern. Falls du die Zuweisung einer E-Mail-Adresse zu deinem Benutzerkonto entfernen möchtest, lasse beim Übermitteln des Formulars das Feld für die neue E-Mail-Adresse leer.",
"changeemail-passwordrequired": "Du musst dein Passwort eingeben, um diese Änderung zu bestätigen.",
"blankarticle": "<strong>Warnung:</strong> Die Seite, die du erstellst, ist leer.\nWenn du erneut auf „{{int:savearticle}}“ klickst, wird die Seite ohne Inhalt erstellt.",
"anoneditwarning": "<strong>Warnung:</strong> Du bist nicht angemeldet. Deine IP-Adresse wird öffentlich sichtbar, falls du Bearbeitungen durchführst. Sofern du dich <strong>[$1 anmeldest]</strong> oder <strong>[$2 ein Benutzerkonto erstellst]</strong>, werden deine Bearbeitungen zusammen mit anderen Beiträgen deinem Benutzernamen zugeordnet.",
"anonpreviewwarning": "''Du bist nicht angemeldet. Beim Speichern wird deine IP-Adresse in der Versionsgeschichte aufgezeichnet.''",
- "missingsummary": "'''Hinweis:''' Du hast keine Zusammenfassung angegeben. Wenn du erneut auf „{{int:savearticle}}“ klickst, wird deine Änderung ohne Zusammenfassung übernommen.",
+ "missingsummary": "<strong>Hinweis:</strong> Du hast keine Zusammenfassung angegeben. Wenn du erneut auf „{{int:savearticle}}“ klickst, wird deine Änderung ohne Zusammenfassung übernommen.",
"selfredirect": "<strong>Warnung:</strong> Du leitest auf diese Seite selbst weiter.\nDu hast vermutlich das falsche Weiterleitungsziel angegeben oder du bearbeitest die falsche Seite.\nWenn du erneut auf „{{int:savearticle}}“ klickst, wird die Weiterleitung dennoch erstellt.",
"missingcommenttext": "Bitte gib unten einen Kommentar ein.",
"missingcommentheader": "<strong>Achtung:</strong> Du hast keinen Betreff eingegeben. Wenn du erneut auf „{{int:savearticle}}“ klickst, wird deine Bearbeitung ohne Überschrift gespeichert.",
"accmailtext": "Ein zufällig generiertes Passwort für [[User talk:$1|$1]] wurde an $2 versandt. Es kann auf der Seite ''[[Special:ChangePassword|Passwort ändern]]'' nach der Anmeldung geändert werden.",
"newarticle": "(Neu)",
"newarticletext": "Du bist einem Link zu einer Seite gefolgt, die nicht vorhanden ist.\nUm diese Seite anzulegen, trage deinen Text in das untenstehende Bearbeitungsfeld ein (weitere Informationen auf der [$1 Hilfeseite]).\nSofern du fälschlicherweise hier bist, klicke auf die Schaltfläche '''Zurück''' deines Browsers.",
- "anontalkpagetext": "----''Diese Seite dient dazu, einem nicht angemeldeten Benutzer Nachrichten zu hinterlassen. Es wird seine IP-Adresse zur Identifizierung verwendet. IP-Adressen können von mehreren Benutzern gemeinsam verwendet werden. Wenn du mit den Kommentaren auf dieser Seite nichts anfangen kannst, richten sie sich vermutlich an einen früheren Inhaber deiner IP-Adresse und du kannst sie ignorieren. Du kannst dir auch ein [[Special:UserLogin/signup|Benutzerkonto erstellen]] oder dich [[Special:UserLogin|anmelden]], um künftig Verwechslungen mit anderen anonymen Benutzern zu vermeiden.''",
+ "anontalkpagetext": "----\n<em>Diese Seite dient dazu, einem nicht angemeldeten Benutzer Nachrichten zu hinterlassen.</em>\nEs wird seine IP-Adresse zur Identifizierung verwendet.\nIP-Adressen können von mehreren Benutzern gemeinsam verwendet werden.\nWenn du mit den Kommentaren auf dieser Seite nichts anfangen kannst, richten sie sich vermutlich an einen früheren Inhaber deiner IP-Adresse und du kannst sie ignorieren.\nDu kannst dir auch ein [[Special:CreateAccount|Benutzerkonto erstellen]] oder dich [[Special:UserLogin|anmelden]], um künftig Verwechslungen mit anderen anonymen Benutzern zu vermeiden.",
"noarticletext": "Diese Seite enthält momentan noch keinen Text.\nDu kannst sie <span class=\"plainlinks\">[{{fullurl:{{FULLPAGENAME}}|action=edit}} erstellen]</span>,\nihren Titel auf anderen Seiten [[Special:Search/{{PAGENAME}}|suchen]]\noder die zugehörigen <span class=\"plainlinks\">[{{fullurl:{{#special:Log}}|page={{FULLPAGENAMEE}}}} Logbücher betrachten]</span>.",
"noarticletext-nopermission": "Diese Seite enthält momentan noch keinen Text und du bist auch nicht dazu berechtigt, diese Seite zu erstellen.\nDu kannst ihren Titel auf anderen Seiten [[Special:Search/{{PAGENAME}}|suchen]] oder die zugehörigen <span class=\"plainlinks\">[{{fullurl:{{#special:Log}}|page={{FULLPAGENAMEE}}}} Logbücher betrachten].</span>",
"missing-revision": "Die Version $1 der Seite namens „{{FULLPAGENAME}}“ ist nicht vorhanden.\n\nDieser Fehler wird normalerweise von einem veralteten Link zur Versionsgeschichte einer Seite verursacht, die zwischenzeitlich gelöscht wurde.\nEinzelheiten sind im [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Lösch-Logbuch] einsehbar.",
"editpage-cannot-use-custom-model": "Das Inhaltsmodell dieser Seite kann nicht geändert werden.",
"longpageerror": "'''Fehler: Der Text, den du zu speichern versuchst, ist {{PLURAL:$1|ein Kilobyte|$1 Kilobyte}} groß. Dies ist größer als das erlaubte Maximum von {{PLURAL:$2|ein Kilobyte|$2 Kilobyte}}.'''\nEr kann nicht gespeichert werden.",
"readonlywarning": "<strong>Achtung: Die Datenbank wurde für Wartungsarbeiten gesperrt, so dass deine Änderungen derzeit nicht gespeichert werden können.\nSichere den Text bitte lokal auf deinem Computer und versuche zu einem späteren Zeitpunkt, die Änderungen zu übertragen.</strong>\n\nGrund für die Sperre: $1",
- "protectedpagewarning": "'''Achtung: Diese Seite wurde geschützt. Nur Benutzer mit Administratorrechten können die Seite bearbeiten.'''\nZur Information folgt der aktuelle Logbucheintrag:",
+ "protectedpagewarning": "<strong>Achtung: Diese Seite wurde geschützt. Nur Benutzer mit Administratorrechten können die Seite bearbeiten.</strong>\nZur Information folgt der aktuelle Logbucheintrag:",
"semiprotectedpagewarning": "'''Halbsperrung:''' Die Seite wurde so geschützt, dass nur registrierte Benutzer diese ändern können.\nZur Information folgt der aktuelle Logbucheintrag:",
"cascadeprotectedwarning": "<strong>Achtung:</strong> Diese Seite wurde so geschützt, dass sie nur durch Benutzer mit Administratorrechten bearbeitet werden kann. Sie ist in die {{PLURAL:$1|folgende Seite|folgenden Seiten}} eingebunden, die mittels der Kaskadensperroption geschützt {{PLURAL:$1|ist|sind}}:",
"titleprotectedwarning": "'''Achtung: Die Seitenerstellung wurde so geschützt, dass nur Benutzer mit [[Special:ListGroupRights|speziellen Rechten]] diese Seite erstellen können.'''\nZur Information folgt der aktuelle Logbucheintrag:",
"permissionserrorstext": "Du bist nicht berechtigt, die Aktion auszuführen. {{PLURAL:$1|Grund|Gründe}}:",
"permissionserrorstext-withaction": "Du bist aus {{PLURAL:$1|dem folgenden Grund|den folgenden Gründen}} nicht berechtigt, $2:",
"contentmodelediterror": "Du kannst diese Version nicht bearbeiten, da das Inhaltsmodell <code>$1</code> vom aktuellen Inhaltsmodell der Seite <code>$2</code> abweicht.",
- "recreate-moveddeleted-warn": "'''Achtung: Du erstellst eine Seite, die bereits früher gelöscht wurde.'''\n\nBitte prüfe sorgfältig, ob die erneute Seitenerstellung den Richtlinien entspricht.\nZu deiner Information folgt das Lösch- und Verschiebungs-Logbuch mit der Begründung für die vorhergehende Löschung:",
+ "recreate-moveddeleted-warn": "<strong>Achtung: Du erstellst eine Seite, die bereits früher gelöscht wurde.</strong>\n\nBitte prüfe sorgfältig, ob die erneute Seitenerstellung den Richtlinien entspricht.\nZu deiner Information folgt das Lösch- und Verschiebungs-Logbuch mit der Begründung für die vorhergehende Löschung:",
"moveddeleted-notice": "Diese Seite wurde gelöscht. Zur Information folgt das Lösch- und Verschiebungs-Logbuch dieser Seite.",
"moveddeleted-notice-recent": "Leider wurde diese Seite kürzlich gelöscht (innerhalb der letzten 24 Stunden).\nZur Information wird das Lösch- und Verschiebungs-Logbuch für die Seite unten angezeigt.",
"log-fulllog": "Alle Logbucheinträge ansehen",
"right-override-export-depth": "Exportiere Seiten einschließlich verlinkter Seiten bis zu einer Tiefe von 5",
"right-sendemail": "E-Mails an andere Benutzer senden",
"right-passwordreset": "Passwort eines Benutzers zurücksetzen und die dazu verschickte E-Mail einsehen",
- "right-managechangetags": "[[Special:Tags|Markierungen]] erstellen und aus der Datenbank löschen",
+ "right-managechangetags": "[[Special:Tags|Markierungen]] erstellen und (de)aktivieren",
"right-applychangetags": "[[Special:Tags|Markierungen]] zusammen mit den Änderungen anwenden",
"right-changetags": "Beliebige [[Special:Tags|Markierungen]] zu einzelnen Versionen und Logbucheinträgen hinzufügen und entfernen",
+ "right-deletechangetags": "[[Special:Tags|Markierungen]] aus der Datenbank löschen",
"grant-generic": "Rechtegruppe „$1“",
"grant-group-page-interaction": "Mit Seiten interagieren",
"grant-group-file-interaction": "Mit Medien interagieren",
"action-viewmyprivateinfo": "deine privaten Informationen einzusehen",
"action-editmyprivateinfo": "deine privaten Informationen zu bearbeiten",
"action-editcontentmodel": "das Inhaltsmodell einer Seite zu bearbeiten",
- "action-managechangetags": "Markierungen zu erstellen und aus der Datenbank zu löschen",
+ "action-managechangetags": "Markierungen zu erstellen und zu (de)aktivieren",
"action-applychangetags": "Markierungen zusammen mit deinen Änderungen anzuwenden",
"action-changetags": "beliebige Markierungen zu einzelnen Versionen und Logbucheinträgen hinzuzufügen und zu entfernen",
+ "action-deletechangetags": "Markierungen aus der Datenbank zu löschen",
"nchanges": "$1 {{PLURAL:$1|Änderung|Änderungen}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|seit dem letzten Besuch}}",
"enhancedrc-history": "Versionsgeschichte",
"upload-form-label-own-work": "Dies ist mein eigenes Werk",
"upload-form-label-infoform-categories": "Kategorien",
"upload-form-label-infoform-date": "Datum",
- "upload-form-label-own-work-message-local": "Ich bestätige, dass ich diese Datei gemäß den Nutzungsbedingungen und Lizenzrichtlinien von {{SITENAME}} hochlade.",
- "upload-form-label-not-own-work-message-local": "Wenn du diese Datei nicht unter den Richtlinien von {{SITENAME}} hochladen kannst, schließe bitte diesen Dialog und versuche eine andere Methode.",
- "upload-form-label-not-own-work-local-local": "Du kannst auch [[Special:Upload|die Standard-Hochladeseite]] ausprobieren.",
- "upload-form-label-own-work-message-default": "Ich verstehe, dass ich diese Datei auf ein gemeinsames Repositorium hochlade. Ich bestätige, dass ich dies gemäß den dortigen Nutzungs- und Lizenzbedingungen tue.",
- "upload-form-label-not-own-work-message-default": "Falls du diese Datei nicht unter den Bedingungen des gemeinsamen Repositoriums hochladen kannst, schließe bitte diesen Dialog und versuche eine andere Methode.",
- "upload-form-label-not-own-work-local-default": "Du kannst auch [[Special:Upload|die Hochladeseite auf {{SITENAME}}]] ausprobieren, falls diese Datei dort unter ihren Richtlinien hochgeladen werden kann.",
- "upload-form-label-own-work-message-shared": "Ich bestätige, dass ich das Urheberrecht für diese Datei besitze und stimme unwiderruflich der Veröffentlichung dieser Datei auf Wikimedia Commons unter der Lizenz [https://creativecommons.org/licenses/by-sa/4.0/deed.de „Creative Commons Namensnennung – Weitergabe unter gleichen Bedingungen 4.0 International“] sowie den [https://wikimediafoundation.org/wiki/Terms_of_Use/de Nutzungsbedingungen] zu.",
- "upload-form-label-not-own-work-message-shared": "Falls du nicht das Urheberrecht für diese Datei besitzt oder du diese Datei unter einer anderen Lizenz veröffentlichen möchtest, ziehe [https://commons.wikimedia.org/wiki/Special:UploadWizard den Hochladeassistenten auf Wikimedia Commons] in Erwägung.",
- "upload-form-label-not-own-work-local-shared": "Du kannst auch [[Special:Upload|die Hochladeseite auf {{SITENAME}}]] ausprobieren, falls die Website das Hochladen dieser Datei unter ihren Richtlinien erlaubt.",
+ "upload-form-label-own-work-message-generic-local": "Ich bestätige, dass ich diese Datei gemäß den Nutzungsbedingungen und Lizenzrichtlinien von {{SITENAME}} hochlade.",
+ "upload-form-label-not-own-work-message-generic-local": "Wenn du diese Datei nicht unter den Richtlinien von {{SITENAME}} hochladen kannst, schließe bitte diesen Dialog und versuche eine andere Methode.",
+ "upload-form-label-not-own-work-local-generic-local": "Du kannst auch [[Special:Upload|die Standard-Hochladeseite]] ausprobieren.",
+ "upload-form-label-own-work-message-generic-foreign": "Ich verstehe, dass ich diese Datei auf ein gemeinsames Repositorium hochlade. Ich bestätige, dass ich dies gemäß den dortigen Nutzungs- und Lizenzbedingungen tue.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Falls du diese Datei nicht unter den Bedingungen des gemeinsamen Repositoriums hochladen kannst, schließe bitte diesen Dialog und versuche eine andere Methode.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Du kannst auch [[Special:Upload|die Hochladeseite auf {{SITENAME}}]] ausprobieren, falls diese Datei dort unter ihren Richtlinien hochgeladen werden kann.",
"backend-fail-stream": "Die Datei $1 konnte nicht übertragen werden.",
"backend-fail-backup": "Die Datei $1 konnte nicht gesichert werden.",
"backend-fail-notexists": "Die Datei $1 ist nicht vorhanden.",
"trackingcategories-msg": "Tracking-Kategorie",
"trackingcategories-name": "Name der Nachricht",
"trackingcategories-desc": "Kategorieeinbindungskriterien",
+ "restricted-displaytitle-ignored": "Seiten mit ignorierten Anzeigetiteln",
+ "restricted-displaytitle-ignored-desc": "Die Seite hat einen ignorierten <code><nowiki>{{DISPLAYTITLE}}</nowiki></code>, da er nicht mit dem tatsächlichen Seitentitel äquivalent ist.",
"noindex-category-desc": "Die Seite wird nicht von Bots indexiert, da sie das magische Wort <code><nowiki>__NOINDEX__</nowiki></code> enthält und sich in einem Namensraum befindet, wo dieses Flag erlaubt ist.",
"index-category-desc": "Die Seite enthält ein <code><nowiki>__INDEX__</nowiki></code> und befindet sich in einem Namensraum, in dem dieses Flag erlaubt ist. Daher wird sie ausnahmsweise von Bots indiziert.",
"post-expand-template-inclusion-category-desc": "Die Seitengröße ist nach dem Expandieren aller Vorlagen größer als <code>$wgMaxArticleSize</code>, so dass einige Vorlagen nicht expandiert wurden.",
"rollbacklinkcount": "{{PLURAL:$1|Eine Version|$1 Versionen}} zurücksetzen",
"rollbacklinkcount-morethan": "Mehr als {{PLURAL:$1|eine Version|$1 Versionen}} zurücksetzen",
"rollbackfailed": "Zurücksetzen gescheitert",
+ "rollback-missingparam": "In der Anfrage fehlen erforderliche Parameter.",
"cantrollback": "Die Änderung kann nicht zurückgesetzt werden, da es keine früheren Autoren gibt.",
"alreadyrolled": "Das Zurücksetzen der Änderungen von [[User:$2|$2]] ([[User talk:$2|Diskussion]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) an [[:$1]] ist gescheitert, da in der Zwischenzeit ein anderer Benutzer die Seite geändert hat.\n\nDie letzte Änderung stammt von [[User:$3|$3]] ([[User talk:$3|Diskussion]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "Die Änderungszusammenfassung lautet: <em>$1</em>.",
"revertpage": "Änderungen von [[Special:Contributions/$2|$2]] ([[User talk:$2|Diskussion]]) wurden auf die letzte Version von [[User:$1|$1]] zurückgesetzt",
"revertpage-nouser": "Änderungen von einem versteckten Benutzer rückgängig gemacht und letzte Version von {{GENDER:$1|[[User:$1|$1]]}} wiederhergestellt",
"rollback-success": "Die Änderungen von $1 wurden rückgängig gemacht und die letzte Version von $2 wurde wiederhergestellt.",
+ "rollback-success-notify": "Bearbeitungen von $1 rückgängig gemacht;\nzurückgeändert auf die letzte Version von $2. [$3 Änderungen zeigen]",
"sessionfailure-title": "Sitzungsfehler",
"sessionfailure": "Es gab ein Problem bei der Übertragung deiner Benutzerdaten.\nDiese Aktion wurde daher sicherheitshalber abgebrochen, um eine falsche Zuordnung deiner Änderungen zu einem anderen Benutzer zu verhindern.\nBitte gehe zurück zur vorherigen Seite, lade sie erneut und versuche, den Vorgang erneut auszuführen.",
"changecontentmodel": "Inhaltsmodell einer Seite ändern",
"changecontentmodel-success-text": "Der Inhaltstyp von [[:$1]] wurde geändert.",
"changecontentmodel-cannot-convert": "Der Inhalt von [[:$1]] kann nicht zum Typ $2 konvertiert werden.",
"changecontentmodel-nodirectediting": "Das Inhaltsmodell „$1“ unterstützt keine direkten Bearbeitungen",
+ "changecontentmodel-emptymodels-title": "Keine Inhaltsmodelle verfügbar",
+ "changecontentmodel-emptymodels-text": "Der Inhalt auf [[:$1]] kann zu keinem Typ konvertiert werden.",
"log-name-contentmodel": "Inhaltsmodell-Änderungs-Logbuch",
"log-description-contentmodel": "Ereignisse bezüglich den Inhaltsmodellen einer Seite",
"logentry-contentmodel-new": "$1 {{GENDER:$2|erstellte}} die Seite $3 mit einem Nicht-Standard-Inhaltsmodell „$5“",
"lockdbsuccesstext": "Die {{SITENAME}}-Datenbank wurde gesperrt.<br />Bitte gib die Datenbank [[Special:UnlockDB|wieder frei]], sobald die Wartung abgeschlossen ist.",
"unlockdbsuccesstext": "Die {{SITENAME}}-Datenbank wurde freigegeben.",
"lockfilenotwritable": "Die Datenbank-Sperrdatei ist nicht beschreibbar. Zum Sperren oder Freigeben der Datenbank muss diese für den Webserver beschreibbar sein.",
+ "databaselocked": "Die Datenbank ist bereits gesperrt.",
"databasenotlocked": "Die Datenbank ist nicht gesperrt.",
"lockedbyandtime": "(von $1 am $2 um $3 Uhr)",
"move-page": "Verschieben von „$1“",
"movepagetext": "Mit untenstehendem Formular kannst du eine Seite umbenennen, indem du sie mitsamt allen Versionen auf einen neuen Titel verschiebst.\nDer alte Titel wird danach zum neuen weiterleiten.\nDu kannst Weiterleitungen, die auf den Originaltitel verlinken, automatisch korrigieren lassen.\nStelle sicher, dass du im Anschluss alle [[Special:DoubleRedirects|doppelten]] oder [[Special:BrokenRedirects|defekten Weiterleitungen]] überprüfst.\nDu bist dafür verantwortlich, dass Links weiterhin auf das korrekte Ziel verweisen.\n\nDie Seite wird <strong>nicht</strong> verschoben, sofern es bereits eine Seite mit dem vorgesehenen Titel gibt, es sei denn, letztere ist eine Weiterleitung ohne Versionsgeschichte.\nDies bedeutet, dass du die Umbenennung rückgängig machen kannst, sofern du einen Fehler gemacht hast. Du kannst hingegen keine existierende Seite überschreiben.\n\n<strong>Hinweis:</strong>\nDie Verschiebung kann weitreichende und unerwartete Folgen für häufig besuchte Seiten haben.\nDu solltest daher die Konsequenzen verstanden haben, bevor du jetzt fortfährst.",
"movepagetext-noredirectfixer": "Mit untenstehendem Formular kannst du eine Seite umbenennen, indem du sie mitsamt allen Versionen auf einen neuen Titel verschiebst.\nDer alte Titel wird danach zum neuen weiterleiten.\nStelle sicher, dass du im Anschluss alle [[Special:DoubleRedirects|doppelten]] oder [[Special:BrokenRedirects|defekten Weiterleitungen]] überprüfst.\nDu bist dafür verantwortlich, dass Links weiterhin auf das korrekte Ziel verweisen.\n\nDie Seite wird <strong>nicht</strong> verschoben, sofern es bereits eine Seite mit dem vorgesehenen Titel gibt, es sei denn, diese ist eine Weiterleitung ohne Versionsgeschichte.\nDies bedeutet, dass du die Umbenennung rückgängig machen kannst, sofern du einen Fehler gemacht hast. Du kannst hingegen keine existierende Seite überschreiben.\n\n<strong>Hinweis:</strong>\nDie Verschiebung kann weitreichende und unerwartete Folgen für häufig besuchte Seiten haben.\nDu solltest daher die Konsequenzen verstanden haben, bevor du jetzt fortfährst.",
"movepagetalktext": "Falls du dieses Kästchen aktivierst, wird die dazugehörige Diskussionsseite automatisch auf den neuen Titel verschoben, sofern nicht bereits eine nicht-leere Diskussionsseite dort vorhanden ist.\n\nIn diesem Fall musst du die Seite manuell verschieben oder zusammenführen, falls erforderlich.",
- "moveuserpage-warning": "'''Warnung:''' Du bist dabei, eine Benutzerseite zu verschieben. Bitte bedenke, dass dadurch nur die Benutzerseite verschoben, '''nicht''' aber der Benutzer umbenannt wird.",
+ "moveuserpage-warning": "<strong>Warnung:</strong> Du bist dabei, eine Benutzerseite zu verschieben. Bitte bedenke, dass dadurch nur die Benutzerseite verschoben, <em>nicht</em> aber der Benutzer umbenannt wird.",
"movecategorypage-warning": "<strong>Warnung:</strong> Du bist gerade dabei, eine Kategorieseite zu verschieben. Bitte sei dir bewusst, dass nur die Seite verschoben wird. Alle der alten Kategorie zugeordneten Seiten werden <em>nicht</em> neu kategorisiert.",
"movenologintext": "Du musst ein registrierter Benutzer und [[Special:UserLogin|angemeldet]] sein, um eine Seite zu verschieben.",
"movenotallowed": "Du hast nicht die erforderliche Berechtigung, um Seiten verschieben zu können.",
"imageinvalidfilename": "Der Ziel-Dateiname ist ungültig",
"fix-double-redirects": "Nach dem Verschieben alle Weiterleitungen auf die Ursprungsseite bereinigen",
"move-leave-redirect": "Weiterleitung erstellen",
- "protectedpagemovewarning": "'''Warnung:''' Diese Seite wurde so geschützt, dass sie nur von Benutzern mit Administratorenrechten verschoben werden kann.\nZur Information folgt der aktuelle Logbucheintrag:",
+ "protectedpagemovewarning": "<strong>Warnung:</strong> Diese Seite wurde so geschützt, dass sie nur von Benutzern mit Administratorenrechten verschoben werden kann.\nZur Information folgt der aktuelle Logbucheintrag:",
"semiprotectedpagemovewarning": "'''Hinweis:''' Diese Seite wurde so geschützt, dass sie nur von angemeldeten Benutzern verschoben werden kann.\nZur Information folgt der aktuelle Logbucheintrag:",
"move-over-sharedrepo": "[[:$1]] existiert in einem gemeinsam genutzten Repositorium. Das Verschieben einer Datei zu diesem Titel überschreibt die gemeinsam genutzte Datei.",
"file-exists-sharedrepo": "Der gewählte Dateiname wird bereits in einem gemeinsam genutzten Repositorium verwendet.\nBitte wähle einen anderen Namen.",
"filedelete-archive-read-only": "Das Archiv-Verzeichnis „$1“ ist für den Webserver nicht beschreibbar.",
"previousdiff": "← Zum vorherigen Versionsunterschied",
"nextdiff": "Zum nächsten Versionsunterschied →",
- "mediawarning": "'''Warnung:''' Dieser Dateityp kann böswilligen Programmcode enthalten.\nDurch das Herunterladen und Öffnen der Datei kann dein Computer beschädigt werden.",
+ "mediawarning": "<strong>Warnung:</strong> Dieser Dateityp kann böswilligen Programmcode enthalten.\nDurch das Herunterladen und Öffnen der Datei kann dein Computer beschädigt werden.",
"imagemaxsize": "Maximale Bildgröße:<br />''(für Dateibeschreibungsseiten)''",
"thumbsize": "Standardgröße der Vorschaubilder:",
"widthheightpage": "$1 × $2, {{PLURAL:$3|1 Seite|$3 Seiten}}",
"confirm-watch-top": "Diese Seite zur persönlichen Beobachtungsliste hinzufügen?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Diese Seite von der persönlichen Beobachtungsliste entfernen?",
+ "confirm-rollback-button": "Okay",
+ "confirm-rollback-top": "Bearbeitungen an dieser Seite zurücksetzen?",
"ellipsis": "…",
"percent": "$1 %",
"quotation-marks": "„$1“",
"size-megabytes": "$1 MB",
"size-gigabytes": "$1 GB",
"lag-warn-normal": "Bearbeitungen der letzten {{PLURAL:$1|Sekunde|$1 Sekunden}} werden in dieser Liste noch nicht angezeigt.",
- "lag-warn-high": "Auf Grund hoher Datenbankauslastung werden die Bearbeitungen der letzten {{PLURAL:$1|Sekunde|$1 Sekunden}} noch nicht in dieser Liste angezeigt.",
+ "lag-warn-high": "Aufgrund hoher Datenbankauslastung werden die Bearbeitungen der letzten {{PLURAL:$1|Sekunde|$1 Sekunden}} noch nicht in dieser Liste angezeigt.",
"watchlistedit-normal-title": "Beobachtungsliste bearbeiten",
"watchlistedit-normal-legend": "Einträge von der Beobachtungsliste entfernen",
"watchlistedit-normal-explain": "Dies sind die Einträge deiner Beobachtungsliste. Um Einträge zu entfernen, markiere die Kästchen neben den Einträgen und klicke am Ende der Seite auf „{{int:Watchlistedit-normal-submit}}“. Du kannst deine Beobachtungsliste auch im [[Special:EditWatchlist/raw|Listenformat bearbeiten]].",
"timezone-local": "Lokal",
"duplicate-defaultsort": "Achtung: Der Sortierungsschlüssel „$2“ überschreibt den vorher verwendeten Schlüssel „$1“.",
"duplicate-displaytitle": "<strong>Warnung:</strong> Der Anzeigetitel „$2“ überschreibt den früheren Anzeigetitel „$1“.",
+ "restricted-displaytitle": "<strong>Warnung:</strong> Der Anzeigetitel „$1“ wurde ignoriert, da er nicht mit dem tatsächlichen Seitentitel gleichwertig ist.",
"invalid-indicator-name": "<strong>Fehler:</strong> Das Attribut <code>name</code> des Seitenstatusindikators darf nicht leer sein.",
"version": "Version",
"version-extensions": "Installierte Erweiterungen",
"tags-delete-not-found": "Die Markierung „$1“ ist nicht vorhanden.",
"tags-delete-too-many-uses": "Die Markierung „$1“ wird bei mehr als {{PLURAL:$2|einer Version|$2 Versionen}} verwendet und kann deshalb nicht gelöscht werden.",
"tags-delete-warnings-after-delete": "Die Markierung „$1“ wurde gelöscht, aber die {{PLURAL:$2|folgende Warnung ist|folgenden Warnungen sind}} aufgetreten:",
+ "tags-delete-no-permission": "Du hast keine Berechtigung, Änderungsmarkierungen zu löschen.",
"tags-activate-title": "Markierung aktivieren",
"tags-activate-question": "Du bist dabei, die Markierung „$1“ zu aktivieren.",
"tags-activate-reason": "Grund:",
"log-action-filter-suppress-block": "Benutzerunterdrückung durch Sperre",
"log-action-filter-suppress-reblock": "Benutzerunterdrückung durch Neusperre",
"log-action-filter-upload-upload": "Neue Hochladung",
- "log-action-filter-upload-overwrite": "Wiederhochladung"
+ "log-action-filter-upload-overwrite": "Wiederhochladung",
+ "authmanager-authn-not-in-progress": "Die Authentifizierung ist nicht im Gang oder es sind Sitzungsdaten verloren gegangen. Bitte beginne von vorn.",
+ "authmanager-authn-no-primary": "Die angegebenen Anmeldeinformationen konnten nicht überprüft werden.",
+ "authmanager-authn-no-local-user": "Die angegebenen Anmeldeinformationen sind mit keinem Benutzer auf diesem Wiki verknüpft.",
+ "authmanager-authn-no-local-user-link": "Die angegebenen Anmeldeinformationen sind gültig, aber sind mit keinem Benutzer auf diesem Wiki verknüpft. Melde dich auf andere Weise an oder erstelle ein neues Benutzerkonto und du wirst die Möglichkeit haben, deine früheren Anmeldeinformationen mit diesem Konto zu verknüpfen.",
+ "authmanager-authn-autocreate-failed": "Die automatische Erstellung des lokalen Benutzerkontos ist fehlgeschlagen: $1",
+ "authmanager-change-not-supported": "Die angegebenen Anmeldeinformationen konnten nicht geändert werden, da sie von nichts genutzt werden würden.",
+ "authmanager-create-disabled": "Die Benutzerkontenerstellung ist deaktiviert.",
+ "authmanager-create-from-login": "Um dein Benutzerkonto zu erstellen, fülle bitte die unten stehenden Felder aus.",
+ "authmanager-create-not-in-progress": "Die Benutzerkontenerstellung ist nicht im Gang oder es sind Sitzungsdaten verloren gegangen. Bitte beginne von vorn.",
+ "authmanager-create-no-primary": "Die angegebenen Anmeldeinformationen konnten nicht für die Benutzerkontenerstellung verwendet werden.",
+ "authmanager-link-no-primary": "Die angegebenen Anmeldeinformationen konnten nicht für die Benutzerkontenverknüpfung verwendet werden.",
+ "authmanager-link-not-in-progress": "Die Benutzerkontenverknüpfung ist nicht im Gang oder es sind Sitzungsdaten verloren gegangen. Bitte beginne von vorn.",
+ "authmanager-authplugin-setpass-failed-title": "Passwortänderung fehlgeschlagen",
+ "authmanager-authplugin-setpass-failed-message": "Das Authentifizierungs-Plugin hat die Passwortänderung abgelehnt.",
+ "authmanager-authplugin-create-fail": "Das Authentifizierungs-Plugin hat die Benutzerkontenerstellung abgelehnt.",
+ "authmanager-authplugin-setpass-denied": "Das Authentifizierungs-Plugin erlaubt keine Passwortänderungen.",
+ "authmanager-authplugin-setpass-bad-domain": "Ungültige Domain.",
+ "authmanager-autocreate-noperm": "Die automatische Benutzerkontenerstellung ist nicht erlaubt.",
+ "authmanager-autocreate-exception": "Die automatische Benutzerkontenerstellung ist aufgrund früherer Fehler vorübergehend deaktiviert.",
+ "authmanager-userdoesnotexist": "Das Benutzerkonto „$1“ ist nicht registriert.",
+ "authmanager-userlogin-remembermypassword-help": "Ob das Passwort länger als die Sitzungslänge behalten werden soll.",
+ "authmanager-username-help": "Benutzername für die Authentifizierung.",
+ "authmanager-password-help": "Passwort für die Authentifizierung.",
+ "authmanager-domain-help": "Domain für die externe Authentifizierung.",
+ "authmanager-retype-help": "Passwort erneut zur Bestätigung eingeben.",
+ "authmanager-email-label": "E-Mail",
+ "authmanager-email-help": "E-Mail-Adresse",
+ "authmanager-realname-label": "Bürgerlicher Name",
+ "authmanager-realname-help": "Bürgerlicher Name des Benutzers",
+ "authmanager-provider-password": "Passwortbasierte Authentifizierung",
+ "authmanager-provider-password-domain": "Passwort- und domainbasierte Authentifizierung",
+ "authmanager-provider-temporarypassword": "Temporäres Passwort",
+ "authprovider-confirmlink-message": "Basierend auf deinen letzten Anmeldeversuchen können die folgenden Benutzerkonten mit deinem Wiki-Benutzerkonto verknüpft werden. Das Verknüpfen ermöglicht die Anmeldung über diese Konten. Bitte wähle das Benutzerkonto aus, das verknüpft werden soll.",
+ "authprovider-confirmlink-request-label": "Benutzerkonten, die verknüpft werden sollen",
+ "authprovider-confirmlink-success-line": "$1: Erfolgreich verknüpft.",
+ "authprovider-confirmlink-failed": "Die Benutzerkontenverknüpfung war nicht vollständig erfolgreich: $1",
+ "authprovider-confirmlink-ok-help": "Nach der Anzeige von Verknüpfungsfehlermeldungen fortfahren.",
+ "authprovider-resetpass-skip-label": "Überspringen",
+ "authprovider-resetpass-skip-help": "Das Zurücksetzen des Passworts überspringen.",
+ "authform-nosession-login": "Die Authentifizierung war erfolgreich, aber dein Browser kann sich deine Anmeldung nicht „merken“.\n\n$1",
+ "authform-nosession-signup": "Das Benutzerkonto wurde erstellt, aber dein Browser kann sich deine Anmeldung nicht „merken“.\n\n$1",
+ "authform-newtoken": "Fehlender Token. $1",
+ "authform-notoken": "Fehlender Token",
+ "authform-wrongtoken": "Falscher Token",
+ "specialpage-securitylevel-not-allowed-title": "Nicht erlaubt",
+ "specialpage-securitylevel-not-allowed": "Leider bist du nicht berechtigt, diese Seite zu benutzen, da deine Identität nicht verifiziert werden konnte.",
+ "authpage-cannot-login": "Anmeldung konnte nicht gestartet werden.",
+ "authpage-cannot-login-continue": "Anmeldung konnte nicht fortgeführt werden. Vielleicht liegt bei deiner Sitzung eine Zeitüberschreitung vor.",
+ "authpage-cannot-create": "Benutzerkontenerstellung konnte nicht gestartet werden.",
+ "authpage-cannot-create-continue": "Die Benutzerkontenerstellung konnte nicht fortgeführt werden. Vielleicht liegt bei deiner Sitzung eine Zeitüberschreitung vor.",
+ "authpage-cannot-link": "Die Benutzerkontenverknüpfung konnte nicht gestartet werden.",
+ "authpage-cannot-link-continue": "Die Benutzerkontenverknüpfung konnte nicht fortgeführt werden. Vielleicht liegt bei deiner Sitzung eine Zeitüberschreitung vor.",
+ "cannotauth-not-allowed-title": "Zugriff verweigert",
+ "cannotauth-not-allowed": "Du bist nicht berechtigt, diese Seite zu verwenden.",
+ "changecredentials": "Anmeldeinformationen ändern",
+ "changecredentials-submit": "Anmeldeinformationen ändern",
+ "changecredentials-invalidsubpage": "$1 ist kein gültiger Typ für Anmeldeinformationen.",
+ "changecredentials-success": "Deine Anmeldeinformationen wurden geändert.",
+ "removecredentials": "Anmeldeinformationen entfernen",
+ "removecredentials-submit": "Anmeldeinformationen entfernen",
+ "removecredentials-invalidsubpage": "$1 ist kein gültiger Typ für Anmeldeinformationen.",
+ "removecredentials-success": "Deine Anmeldeinformationen wurden entfernt.",
+ "credentialsform-provider": "Typ der Anmeldeinformationen:",
+ "credentialsform-account": "Benutzername:",
+ "cannotlink-no-provider-title": "Es gibt keine verknüpfbaren Benutzerkonten",
+ "cannotlink-no-provider": "Es gibt keine verknüpfbaren Benutzerkonten.",
+ "linkaccounts": "Benutzerkonten verknüpfen",
+ "linkaccounts-success-text": "Das Benutzerkonto wurde verknüpft.",
+ "linkaccounts-submit": "Benutzerkonten verknüpfen",
+ "unlinkaccounts": "Benutzerkonten trennen",
+ "unlinkaccounts-success": "Das Benutzerkonto wurde getrennt."
}
"아라",
"Calak",
"Macofe",
- "Matma Rex"
+ "Matma Rex",
+ "Kumkumuk"
]
},
"tog-underline": "Bınê gırey de xete bance:",
"tog-ccmeonemails": "E-posteyanê ke ez karberanê binan rê rışenan, mı rê kopya inan bırışe",
"tog-diffonly": "Qıyasê versiyonan de tek ferqan bımocne, pela butıne nê",
"tog-showhiddencats": "Kategoriyanê dızdiye bımocne",
- "tog-norollbackdiff": "Peyserardışi ra dıme ferqi caverde",
+ "tog-norollbackdiff": "Peyser ardışi ra dıme ferqi measne",
"tog-useeditwarning": "Wexto ke mı yew pela nizami be vurnayışanê nêqeydbiyayeyan caverdê, hay be mı ser de",
"tog-prefershttps": "Ronışten akerden de greyo itimadın bıkarne",
"underline-always": "Tım",
"december-date": "Kanun $1",
"period-am": "AM",
"period-pm": "PM",
- "pagecategories": "{{PLURAL:$1|Kategoriye|Kategoriyi}}",
+ "pagecategories": "{{PLURAL:$1|Kategori|Kategoriy}}",
"category_header": "Pelê ke kategoriya \"$1\" derê",
"subcategories": "Kategoriyê bınêni",
"category-media-header": "Dosyeyê ke kategoriya \"$1\" derê",
"hidden-category-category": "Kategoriyê nımıtey",
"category-subcat-count": "{{PLURAL:$2|Na kategoriya de $1 bınkategoriyay estê.|$2 kategoriyan ra $1 bınkategoriyay asenê.}}",
"category-subcat-count-limited": "Na kategoriye de {{PLURAL:$1|ena kategoriya bınêne esta|enê $1 kategoriyê bınêni estê}}.",
- "category-article-count": "{{PLURAL:$2|Na kategoriye de teyna ena pele esta.|Na kategoriye de $2 tenan ra, {{PLURAL:$1|ena pele esta|$1 peli}}, ena kategoriye miyan derê}}",
+ "category-article-count": "{{PLURAL:$2|Na kategoriye de teyna ena pele esta.|Ebe $2 ra pêro piya {{PLURAL:$1|ena pela na kategoriye dera|$1 enê peli na kategoriye derê.}}}}",
"category-article-count-limited": "{{PLURAL:$1|Pela cêrêne|$1 Pelê cêrêni}} na kategoriye derê.",
"category-file-count": "<noinclude>{{PLURAL:$2|Na kategoriye tenya dosyayanê cêrênan muhtewa kena.}}</noinclude>\n*Na kategoriye de $2 dosyayan ra {{PLURAL:$1|yew dosya tenêka esta| $1 dosyey asenê}}.",
"category-file-count-limited": "{{PLURAL:$1|Dosya cêrêne|$1 Dosyê cêrêni}} na kategoriye derê.",
"qbedit": "Bıvurne",
"qbpageoptions": "Ena pele",
"qbmyoptions": "Pelê mı",
- "faq": "PZP (Persê ke zehf persiyenê)",
+ "faq": "PZP",
"faqpage": "Project: PZP",
"actions": "Hereketi",
"namespaces": "Heruna naman",
"search": "Cı geyre",
"searchbutton": "Cı geyre",
"go": "Şo",
- "searcharticle": "Şo",
+ "searcharticle": "So",
"history": "Tarixê pele",
"history_short": "Tarix",
"updatedmarker": "cıkewtena mına peyêne ra dıme biyo rocane",
- "printableversion": "Asayışê çapkerdışi",
+ "printableversion": "Versiyonê nusterin",
"permalink": "Gıreyo jûqere",
"print": "Çap ke",
"view": "Bıvêne",
"unprotectthispage": "Starkerdışe ena peler bıvurne",
"newpage": "Pela newiye",
"talkpage": "Ena pele sero werêne",
- "talkpagelinktext": "vaten",
+ "talkpagelinktext": "werênayış",
"specialpage": "Pela xısusiye",
"personaltools": "Hacetê şexsiy",
"articlepage": "Pela zerreki bıvêne",
- "talk": "Vaten",
+ "talk": "Werênayış",
"views": "Asayışi",
"toolbox": "Haceti",
"userpage": "Pela karberi bıvêne",
"lastmodifiedat": "Ena pele tewr peyên roca $2, $1 de biya rocaniye.",
"viewcount": "Ena pele {{PLURAL:$1|rae|$1 rey}} vêniya.",
"protectedpage": "Pela pawıtiye",
- "jumpto": "Şo:",
+ "jumpto": "Şo be:",
"jumptonavigation": "Pusula",
"jumptosearch": "cı geyre",
"view-pool-error": "Qaytê qısuri mekerên, serverê ma enıka zêde bar gırewto xo ser.\nHedê xo ra zêde karberi kenê ke seyrê na pele bıkerê.\nŞıma rê zehmet, tenê vınderên, heta ke reyna kenê ke ena pele kewê.\n\n$1",
"pool-errorunknown": "Xeta nêzanıtiye",
"poolcounter-usage-error": "Xırab karyayış:$1",
"aboutsite": "Heqa {{SITENAME}} de",
- "aboutpage": "Project:Heqa {{SITENAME}} de",
+ "aboutpage": "Project:Heqa",
"copyright": "Zerrekacı $1 bındı not biya.",
"copyrightpage": "{{ns:project}}:Heqa telifi",
- "currentevents": "Veng û vac",
+ "currentevents": "Hediseyê rocaneyi",
"currentevents-url": "Project:Rocani hadisey",
"disclaimers": "Redê mesuliyeti",
"disclaimerpage": "Project:Reddê mesuliyetê bıngey",
"policy-url": "Project:Terzê hereketi",
"portal": "Portalê cemaeti",
"portal-url": "Project:Portalê cemaeti",
- "privacy": "Madeyê dızdiye",
+ "privacy": "Politikay Nımnayışi",
"privacypage": "Project:Xısusiyetê nımtışi",
"badaccess": "Xeta mısadey",
"badaccess-group0": "Heqa şıma çıniya, karo ke şıma waşt, bıkerê.",
"viewsourcelink": "çımey bıvêne",
"editsectionhint": "Leteyo ke bıvuriyo: $1",
"toc": "Sernameyê meselan",
- "showtoc": "bımocne",
+ "showtoc": "bıasene",
"hidetoc": "bınımne",
"collapsible-collapse": "Teng ke",
"collapsible-expand": "Hera ke",
"red-link-title": "$1 (pele çıniya)",
"sort-descending": "Rêzkerdışo kêmbiyaye",
"sort-ascending": "Rêzkerdışo zêdiyaye",
- "nstab-main": "Wesiqe",
+ "nstab-main": "Pele",
"nstab-user": "Pela karberi",
"nstab-media": "Pela medya",
"nstab-special": "Pela xase",
"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}}",
+ "createacct-benefit-body2": "{{PLURAL:$1|wesiqe|wesiqey}}",
"createacct-benefit-body3": "{{PLURAL:$1|iştıraqkerdoğo nıkayên|iştıraqkerdoğê nıkayêni}}",
"badretype": "Parolayê ke şıma nuşti yewbini nêtepışneni.",
"userexists": "Jewna karber enê nami karneno.\nMara reca xorê jewna name bınusnê.",
"noname": "Yew nameyo maqbul bınuse.",
"loginsuccesstitle": "Hesab abıya",
"loginsuccess": "'''{{SITENAME}} dı name dê \"$1\" şıma hesab akerdo.'''",
- "nosuchuser": "Ebe namey \"$1\"i yew karber çıniyo.\nNuştışê namanê karberan de herfa pil u qıce rê diqet kerên.\nNuştışê xo qonrol kerên, ya zi [[Special:UserLogin/signup|yew hesabo newe akerên]].",
+ "nosuchuser": "Ebe namey \"$1\"i yew karber çıniyo.\nNuştışê namanê karberan de herfa pil u qıce rê diqet kerên.\nNuştışê xo qonrol kerên, ya zi [[Special:CreateAccount|yew hesabo newe akerên]].",
"nosuchusershort": "No \"$1\" name de yew ten çino. Kontrolê nuştışi bıkere.",
"nouserspecified": "Şıma gani yew name bıde.",
"login-userblocked": "No karber/na karbere blokekerdeyo/blokekerdiya. Cıkewtışi rê musade çıniyo.",
"createaccount-text": "Kesê, be e-posteyê şıma ra {{SITENAME}} ($4) de, ebe nameyê \"$2\" u parola \"$3\" ra yew hesab vıraşto.\nŞıma gani cı kewê u parola xo nıka bıvurnê.",
"login-throttled": "Demekê $1 cıwa ver de şıma zah teşebbusê hesab akerdış kerd.\nBıne vındere u newe ra dest pê bıkere.",
"login-abort-generic": "Dekewtışê şıma xırabo-terkneyayo",
+ "login-migrated-generic": "Hesabê şıma wedatiya yo u ena wiki de bamey şıma çıni yo.",
"loginlanguagelabel": "Zıwan: $1",
"suspicious-userlogout": "Waştişê tu ya veciyayişi kebul nibiya cunki ihtimal o ke waştiş yew browser ya zi proksiyê heripiyaye ra ameya.",
"createacct-another-realname-tip": "Nameyo raştıkên keyfiyo.\nŞıma nameyo xoyo raştıkên ke bımocnê, seba iştırakanê karberi be ney ra istıfade beno.",
"pt-login": "Cı kewe",
"pt-login-button": "Cı kewe",
+ "pt-login-continue-button": "Cıkewten rê dewam ke",
"pt-createaccount": "Hesab vıraze",
"pt-userlogout": "Veciyayış",
"php-mail-error-unknown": "PHP's mail() fonksiyoni de xırabin vıcyê.",
"newpassword": "Parola newiye:",
"retypenew": "Parola newiye tekrar ke:",
"resetpass_submit": "Parola eyar kere u newe ra dekewe",
- "changepassword-success": "Parola şıma be serkewtış vuriye!",
+ "changepassword-success": "Parolay şıma vuryaya!",
"changepassword-throttled": "Şıma zaf ronıştış akerdış ke.Kerem ke verdi dekewten $1 bıpawe.",
- "botpasswords-label-appid": "Bot name:",
+ "botpasswords": "Paroleyê botan",
+ "botpasswords-createnew": "Newe Paroleyê boti vıraze",
+ "botpasswords-editexisting": "Mewcud parolaye boti timar ke",
+ "botpasswords-label-appid": "Nameyê boti:",
"botpasswords-label-create": "Vıraze",
"botpasswords-label-update": "Rocane ke",
"botpasswords-label-cancel": "Bıtexelne",
"botpasswords-label-delete": "Bestere",
- "botpasswords-label-resetpassword": "Parola reset ke",
+ "botpasswords-label-resetpassword": "Parola raçarne",
"botpasswords-label-grants-column": "Dayen",
+ "botpasswords-created-title": "Parolay boti vırazi yê",
+ "botpasswords-updated-title": "Parolay boti rocane yê",
+ "botpasswords-deleted-title": "Parolay boti esteri yê",
"resetpass_forbidden": "parolayi nêvuryayi",
"resetpass-no-info": "şıma gani hesab akere u hona bıeşke bırese cı",
"resetpass-submit-loggedin": "Parola bıvurne",
"passwordreset-emailsentemail": "Eke na seba hesabê şıma yew adresa e-posteyê qeydına, yew e-posteyê parola nênkerdışi rışiyeno.",
"passwordreset-emailsent-capture": "Yew e-posteyê esterıtışê parolayo ke rışiya, no cêr mocniyayo.",
"passwordreset-emailerror-capture": "Yew e-posteyê esterıtışê parolayo ke rışiya, no cêr mocniyayo, ema {{GENDER:$2|karber}}i rê rıştış de mıwefeq nêbi: $1",
- "changeemail": "E-posta adresa xo bıvurnê",
+ "changeemail": "E-posta adresa xo wedarne",
"changeemail-header": "E-posya adresta hesabdê xo bıvurnê",
"changeemail-no-info": "Şıma gani bıkewê pele ke derdest bıresê na pele.",
"changeemail-oldemail": "E-postay şımawa nıkaêne:",
"sig_tip": "İmzay şıma be morê zemani",
"hr_tip": "Xeta verardiye (teserrufın bıgureyne/bıxebetne)",
"summary": "Xulasa:",
- "subject": "Mewzu/sernuşte:",
+ "subject": "Mewzu:",
"minoredit": "No yew vurnayışo werdiyo",
"watchthis": "Ena pele seyr ke",
"savearticle": "Pele qeyd ke",
+ "publishpage": "Perer bıhesırne",
"preview": "Verqayt",
"showpreview": "Verqayti bımocne",
"showdiff": "Vurnayışan bımocne",
"missingcommenttext": "Cêr de jû fıkır bınusên, şıma rê zehmet.",
"missingcommentheader": "'''Diqet:''' Şıma seba nê fıkrvaci yew mewzu/sernuşte nênuşt.\nEke şıma reyna \"{{int:savearticle}}\" bıtıknê, vırnayışê şıa bê mewzu/sernuşte do qeyd bo.",
"summary-preview": "Verqaytê xulasa:",
- "subject-preview": "Verqaytê mewzu/sernuştey:",
+ "subject-preview": "Verqaytê mewzu:",
+ "previewerrortext": "Verqaytê vurnayış de şıma dı xırabin amê meydan",
"blockedtitle": "Karber blokekerdeo",
"blockedtext": "<strong>No nameyê karberi ya zi na adresa IP blokekerdeya.</strong>\n\nVıraştoğê blokeyi: $1\nSebebê blokeyi: <em>$2</em>.\n\n* Sıftekerdena blokeyi: $8\n* Qediyayışê blokeyi: $6\n* Blokebiyaye: $7\n\nŞıma şenê $1 de ya zi yewna [[{{MediaWiki:Grouppage-sysop}}|administrator]]i de irtıbat kewê ke na mesela sero werênê, cemaet vırazê. \nŞıma nêşenê xısusiyetê \"karberi rê e-posta bırışe\" bıgureynê/bıxebetnê heta ke [[Special:Preferences|Tercihanê hesabi]] de yew e-posteyo ke vêreno, beli bi û şıma gureynayışê cı ra mehrum nêbiyê.\nIP adresa şımaya nıkayêne $3o û numreyê bloki #$5.\nŞıma rê zehmet, eke kewnê ra dıme, teferruatanê corênan not kerên.",
"autoblockedtext": "IP adresê şıma otomotikmen kerda kılit, çıkı $1 verniya nê hesabi grota.\nSebebê cı zi:\n\n:''$2''\n\n* Dest pê kerdışê verni grotışi: $8\n* Qedyayişê verni grotışi: $6\n* Qayile ke bloqe bıbo: $7\n\nŞıma qayile qey weri kewtışê na mesela, $1 ya na [[{{MediaWiki:Grouppage-sysop}}|serkaran ra]] yewi ra şenê irtibat kewê.\n\nNot, [[Special:Preferences|Tercihê karberi]] eke şıma yew e-postayo raşt nênuşt se şıma nêşenê na xususiyet ra \"karber rê e-posta bırışê\" istifade bıkeri.\n\nIP adresiya şıma yo nıkayên $3 u ID şıma yo ke musade nêdaye #$5. Eke şıma yew tehqiqat vırazeni malumatê corênan xo vira mekerê.",
"accmailtext": "[[User talk:$1|$1]] parolayo ke raşt ameyo şırawiyo na adres $2.\n\nQey na hesabê newe parola, cıkewtış dıma şıma eşkeni na qısım de ''[[Special:ChangePassword|parola bıvurn]]'' bıvurni.",
"newarticle": "(Newe)",
"newarticletext": "To yew gıre tıkna be ra yew pela ke hewna çıniya.\nSeba afernayışê pele ra, qutiya metnê cêrêni bıgurene (seba melumati qaytê [$1 pela peşti] ke).\nEke be ğeletine ameya tiya, wa gocega <strong>peyser</strong>i programê xo de bıtıkne.",
- "anontalkpagetext": "----''No pel, pel o karbero hesab a nêkerdeyan o, ya zi karbero hesab akerdeyan o labele pê hesabê xo nêkewto de. No sebeb ra ma IP adres şuxulneni û ney IP adresan herkes eşkeno bıvino. Eke şıma qayil niye ina bo xo ri [[Special:UserLogin/signup|yew hesab bıvıraze]] veyaxut [[Special:UserLogin|hesab akere]].''",
- "noarticletext": "Ena pele de hewna theba çıniyo.\nTı şenay zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|seba sernameyê ena pele cı geyre]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre],\nya zi [{{fullurl:{{FULLPAGENAME}}|action=edit}} ena pele vıraze]</span>.",
+ "anontalkpagetext": "----''No pel, pel o karbero hesab a nêkerdeyan o, ya zi karbero hesab akerdeyan o labele pê hesabê xo nêkewto de. No sebeb ra ma IP adres şuxulneni û ney IP adresan herkes eşkeno bıvino. Eke şıma qayil niye ina bo xo ri [[Special:CreateAccount|yew hesab bıvıraze]] veyaxut [[Special:UserLogin|hesab akere]].''",
+ "noarticletext": "Ena pele de hewna theba çıni yo.\nTı şenê zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|qandê sernameyê ena pele cı geyre]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre],\nya zi [{{fullurl:{{FULLPAGENAME}}|action=edit}} ena pele vıraze]</span>.",
"noarticletext-nopermission": "Ena pele de hewna theba çıniyo.\nTı şenay zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|seba sernameyê na pele cı geyre]], ya zi <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre]</span>, ema destur çıniyo ke na pele vırazê.",
"missing-revision": "Rewizyonê name dê pela da #$1 \"{{FULLPAGENAME}}\" dı çıniyo.\n\nNo normal de tarix dê pelanê besterneyan dı ena xırabin asena.\nDetayê besternayışi [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} tiya dı] aseno.",
"userpage-userdoesnotexist": "Hesabê karberi \"<nowiki>$1</nowiki>\" qeyd nêbiyo.\nKerem ke, tı ke wazenay na pele bafernê/bıvurnê, qontrol ke.",
"userpage-userdoesnotexist-view": "Hesabê karberi \"$1\" qeyd nêbiyo.",
"blocked-notice-logextract": "No karber/na karbere emanet blokekerdeyo/blokekediya.\nCıkewtışo tewr peyêno ke bloke biyo, cêr seba referansi belikerdeyo:",
- "clearyourcache": "'''Not:''' Bahde sazkerdışi, gani hafızayê cı gerayoğ pak bıbo.\n*'''Mozilla / Firefox / Safari:''' ''Shift'' ri gıştê şıma ser nayi pel newe ra bar kere yana zi''Ctrl-Shift-R'' bıkere u (qey Apple Mac ''Cmd-Shift-R'');,\n*'''IE:''' ''Ctrl-F5' piya pıploxnê ke wa newe bo', \n* '''Operar:'''hacetan ra şı rê →tercihan ra bıvurnen",
+ "clearyourcache": "'''Not:''' Bahde sazkerdışi, gani hafızayê cı gerayoğ pak bıbo.\n*'''Mozilla / Firefox / Safari:''' ''Shift'' ri gıştê şıma ser nayi pel newe ra bar kere yana zi''Ctrl-Shift-R'' bıkere u (qey Apple Mac ''Cmd-Shift-R'');,\n*'''IE:''' ''Ctrl-F5' piya pıploxnê ke wa newe bo', \n* '''Opera:'''hacetan ra şı rê →tercihan ra bıvurnen",
"usercssyoucanpreview": "'''Yardim:''' Ser \"{{int:showpreview}}\" sima eskeni CSSe newe test bikeri.",
"userjsyoucanpreview": "'''Yardim:''' Ser \"{{int:showpreview}}\" sima eskeni CSSe newe test bikeri.",
"usercsspreview": "'''şıma tena verqaydê dosyayê CSS vineni.''' '''Dosyayê Karberi CSS hema qayd nebiyo!'''",
"userinvalidcssjstitle": "'''Teme:''' Mewzuyê \"$1\" çıniyo.\nDosyanê be namey .css u .js'i de herfa werdiye bıgurêne, mesela herında {{ns:user}}:Foo/Vector.css'i de {{ns:user}}:Foo/vector.css bınuse.",
"updated": "(Rozeneya)",
"note": "'''Not:'''",
- "previewnote": "'''Şıma bızanê ke ena yew verqayta.'''\nVurnayışê şıma hona qeyd nêbiyo!",
+ "previewnote": "'''Şıma bızanê ke eno yew verqayto.'''\nVurnayışê şıma hewna qeyd nêbiyê!",
"continue-editing": "Şo herunda vurnayışi",
"previewconflict": "No seyrkerdışê verqaydi serê qutiyê nuşte tezim kerdış de yo, eke şıma qayile vurnayişê maddeyi seyino bıvini, no mocneno şıma.",
"session_fail_preview": "Ma ef kere. Vindibiyayişê tayê datay ra a kerdışê hesabê şıma de ma vurnayişê şıma qayd nêkerd. Newe ra tesel (cereb) bıkere. Eke no qayde zi nêbo, [[Special:UserLogout|hesabê xo bıqefelne]] u newera a kere.",
"yourdiff": "pêverronayiş",
"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).",
+ "editpage-cannot-use-custom-model": "Zerrekê modelê ena peler şıma nêşenê bıvurnê",
"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:",
"permissionserrorstext": "Qey {{PLURAL:$1|sebebê|sebebê}} cêrini ra icazeyê şıma çin o:",
"permissionserrorstext-withaction": "{{PLURAL:$1|Sebeba|Sebeb da}} cêri ra icazetê $2 çıniyo:",
"recreate-moveddeleted-warn": "'''Hişyari: no pel o ke şıma vırazeni vere cû vırazyayo.'''\n\nDiqet bıkeri no vurnayişê şıma re gerek esto:",
- "moveddeleted-notice": "Na per besternyaya.\nQeydé besternayışi uq hewadayışi cér dé deyayo.",
+ "moveddeleted-notice": "Ena pela esteriya ya.\nQeydé esternayışi u wedarnayışi cér dé deya yo.",
"log-fulllog": "Temamê rocaneyi bıvine",
"edit-hook-aborted": "Vurnayiş vınderiya.\nYew sebeb beyan nibı.",
"edit-gone-missing": "Pel rocanebiyaye niyo.\nHewna kerde aseno.",
"undo-success": "No vurnayiş tepeye geryeno. pêverronayişêyê cêrıni kontrol bıkeri.",
"undo-failure": "Sebayê pêverameyişê vurnayişan karo tepêya gırewtış nêbı.",
"undo-norev": "Vurnayiş tepêya nêgeryeno çunke ya vere cû hewna biyo ya zi ca ra çino.",
- "undo-summary": "Vırnayışê $1'i [[Special:Contributions/$2|$2i]] ([[User talk:$2|Werênayış]]) peyser gırewt",
+ "undo-summary": "Vırnayışê $1'i [[Special:Contributions/$2|$2i]] ([[User talk:$2|Werênayış]]) peyser gırot",
"undo-summary-username-hidden": "Rewizyona veri $1'i hewada",
"cantcreateaccounttitle": "Nêşenay hesab rakerê",
"cantcreateaccount-text": "Hesabvıraştışê na IP adrese ('''$1''') terefê [[User:$3|$3]] kılit biyo.\n\nSebebo ke terefê $3 ra diyao ''$2''",
"last": "peyên",
"page_first": "verên",
"page_last": "peyên",
- "histlegend": "Ferqê weçinıtışi: Qutiya versiyonan seba pêver sanayış işaret ke û dest be ''enter''i ya zi gocega cêrêne ro ne.<br />\nCetwel: <strong>({{int:ferq}})</strong> = ferqê verziyonê peyêni, <strong>({{int:peyên}})</strong> = ferqê versiyonê verêni, <strong>{{int:q}}</strong> = vurnayışo werdi.",
+ "histlegend": "Ferqê weçinıtışi: Qutiya versiyonan seba têversanayış işaret ke û dest be ''enter''i ya zi gocega cêrêne ro ne.<br />\nCedwel: <strong>({{int:ferq}})</strong> = ferqê verziyonê peyêni, <strong>({{int:peyên}})</strong> = ferqê versiyonê verêni, <strong>{{int:q}}</strong> = vurnayışo werdi.",
"history-fieldset-title": "Tarixi bıvêne",
"history-show-deleted": "Tenya esterıtey",
"histfirst": "Verênêr",
"rev-deleted-event": "(fealiyetê cıkewtışi esteriyo)",
"rev-deleted-user-contribs": "[nameyê karberi ya zi adresa IPy esteriya - vurnayış iştırakan ra nımniyo]",
"rev-deleted-text-permission": "Çımraviyarnayışê ena pele '''esteriyo'''.\nBeno ke [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] de teferruat esto.",
+ "rev-suppressed-text-permission": "Çımraviyarnayışê ena pele '''degusneyayo'''.\nŞıma be idarekerina xo ra şenê ey bıvênê; beno ke [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} degusnayış] de teferruat esto.",
"rev-deleted-text-unhide": "Çımra viyarnayışê ena pele '''besterêno'''.\nBeno ke [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} besternayış] de teferruat esto.\nŞıma be idarekerina xo ra şenê hewna [$1 nê çımra viyarnayışi bıvinê], eke wazenê dewam kerê.",
"rev-suppressed-text-unhide": "Çımra viyarnayışê ena pele '''Degusneyayo'''.\nBeno ke [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} degustış] de teferruat esto.\nŞıma be idarekerina xo ra şenê hewna [$1 nê çımraviyarnayışi bıvênê], eke wazenê dewam kerê.",
"rev-deleted-text-view": "Çımra viyarnayışê ena pele '''besternêno'''.\nŞıma be idarekerina xo ra şenê ey bıvênê; beno ke [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} besternayış] de teferruat esto.",
"rev-deleted-diff-view": "Jew timarkerdışê ena versiyon '''wedariyayo''.\nÎdarekarî şenê ena versiyon bivîne; belki tiya de [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} wedarnayişî] de teferruat esto.",
"rev-suppressed-diff-view": "Jew timarkerdışê ena versiyon '''Ploxneyış'' biyo.\nÎdarekarî eşkeno ena dif bivîne; belki tiya de [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ploxnayış] de teferruat esto.",
"rev-delundel": "bımocne/bınımne",
- "rev-showdeleted": "bımocne",
+ "rev-showdeleted": "bıasene",
"revisiondelete": "Çımraviyarnayışan bestere/peyser biya",
"revdelete-nooldid-title": "Çımraviyarnayışo waşte nêvêreno",
"revdelete-nooldid-text": "Şıma vıraştışê nê fonksiyoni rê ya yew çımraviyarnayışo waşte diyar nêkerdo, çımraviyarnayışo diyarkerde çıniyo, ya ki şıma wazenê ke çımraviyarnayışê nıkayêni bınımnê.",
"revdelete-legend": "Şertanê vênayışi rone",
"revdelete-hide-text": "Nuştey revizyoni",
"revdelete-hide-image": "zerreyê dosyay bınımnê",
- "revdelete-hide-name": "hedef u vaqa' bınımne",
+ "revdelete-hide-name": "hedef u parametreyan bınımne",
"revdelete-hide-comment": "Xulasa bıvurne",
"revdelete-hide-user": "IP asresa/namey vırnoği",
"revdelete-hide-restricted": "Malumatan pa serkaran u karberan ra bınım.",
"revdelete-unsuppress": "reizyonê ke tepiya anciye serbest ker",
"revdelete-log": "Sebeb:",
"revdelete-submit": "Cewab be {{PLURAL:$1|çımraviyarnayışi|çımraviyarnayışan}} de",
- "revdelete-success": "''''Esayişê revizyoni bi muvaffaqi eyar bi.'''",
+ "revdelete-success": "Asayişê revizyoni rocaneya",
"revdelete-failure": "'''Esayişê revizyoni eyar nibeno:'''\n$1",
"logdelete-success": "'''Esayişê rocaneyi bı muvaffaqi eyar bı.'''",
"logdelete-failure": "'''Esayişê rocaneyi eyar nêbı:'''\n$1",
"notextmatches": "tekê (zewcê) nuştey pele çıniyê",
"prevn": "{{PLURAL:$1|$1}} verên",
"nextn": "{{PLURAL:$1|$1}} peyên",
+ "prev-page": "Pela verên",
+ "next-page": "Pela peyên",
"prevn-title": "$1o verên {{PLURAL:$1|netice|neticeyan}}",
"nextn-title": "$1o ke yeno {{PLURAL:$1|netice|neticey}}",
"shown-title": "bimocne $1î {{PLURAL:$1|netice|neticeyan}} ser her pel",
"searchprofile-images-tooltip": "Dosya cı geyr",
"searchprofile-everything-tooltip": "Tedeesteyan hemine cı geyre (pelanê mınaqeşeyi zi tey)",
"searchprofile-advanced-tooltip": "qe cayê nimeyî bigêre",
- "search-result-size": "$1 ({{PLURAL:$2|1 çekuyo|$2 çekuyê}})",
+ "search-result-size": "$1 ({{PLURAL:$2|1 çeku|$2 çekuy}})",
"search-result-category-size": "{{PLURAL:$1|1 eza|$1 ezayan}} ({{PLURAL:$2|1 kategoriyê bini|$2 kategirayanê binan}}, {{PLURAL:$3|1 dosya|$3 dosyayan}})",
"search-redirect": "($1 ra ardış)",
"search-section": "(qısmê $1)",
"search-category": "(kategori $1)",
"search-file-match": "(zerreyê dosya yewbini gêno)",
"search-suggest": "To va: $1",
+ "search-rewritten": "Neticey $ asenê. Herunda ney wa neticey $2 bıasê",
"search-interwiki-caption": "Proceyê bıray",
"search-interwiki-default": "$1 ra neticey:",
"search-interwiki-more": "(véşi)",
"showingresultsinrange": "{{PLURAL:$1|<strong>1</strong> netice|<strong>$1</strong> neticey}} be mabeynê #<strong>$2</strong> ra be #<strong>$3</strong> cêr asenê.",
"search-showingresults": "{{PLURAL:$4|Netice <strong>$1</strong> be <strong>$3</strong>|Neticeyi <strong>$1 - $2</strong> be <strong>$3</strong>}}",
"search-nonefound": "Zey perskerdışê şıma netice nêvêniya.",
+ "search-nonefound-thiswiki": "Ena sita dı zey waşten da şıma theba nêvineya",
"powersearch-legend": "Cıgeyrayışo hera",
"powersearch-ns": "Cayanê nameyan de cıgeyrayış:",
"powersearch-togglelabel": "Kontrol ke:",
"prefs-labs": "Xacetê labs",
"prefs-user-pages": "Pela Karberi",
"prefs-personal": "Pela karberi",
- "prefs-rc": "Vurnayışê peyêni",
+ "prefs-rc": "Vurriyayışê peyêni",
"prefs-watchlist": "Lista seyrkerdışi",
"prefs-watchlist-days": "Rocê ke lista seyrkerdışi de bêrê ramocnaene",
"prefs-watchlist-days-max": "tewr vêşi $1 {{PLURAL:$1|roci|roci}}",
"group": "Grube:",
"group-user": "Karberi",
"group-autoconfirmed": "Karberê ke otomatikmen biyê araşt",
- "group-bot": "Boti",
+ "group-bot": "Roboti",
"group-sysop": "İdarekari",
- "group-bureaucrat": "Burokrati",
- "group-suppress": "Çımpawıteni",
- "group-all": "(pêron)",
+ "group-bureaucrat": "Buroqrati",
+ "group-suppress": "Çımpawıtoği",
+ "group-all": "(pêro)",
"group-user-member": "{{GENDER:$1|karber}}",
"group-autoconfirmed-member": "{{GENDER:$1|Karberê ke otomatikmen biyê araşt}}",
"group-bot-member": "{{GENDER:$1|bot}}",
"nchanges": "$1 {{PLURAL:$1|fın vurna|fıni vurna}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ra yok wazino}}",
"enhancedrc-history": "tarix",
- "recentchanges": "Vurnayışê peyêni",
+ "recentchanges": "Vurriyayışê peyêni",
"recentchanges-legend": "Tercihê vurnayışanê peyênan",
- "recentchanges-summary": "Wiki sero vurnayışanê peyênan ena pele de teqib kerê.",
+ "recentchanges-summary": "Ena pele de wiki sero vurnayışanê peyênan teqib ke.",
"recentchanges-noresult": "Goreyê kriteranê kıfşkerdeyan ra qet yew vurnayış nêvêniya.",
"recentchanges-feed-description": "Ena feed dı vurnayişanê tewr peniyan teqip bık.",
"recentchanges-label-newpage": "Enê vurnayışi ra yew pela newiye vıraziye",
"recentchanges-legend-heading": "<strong>Kıtabek:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|Lista pelanê neweyan]] zi bıvêne)",
"recentchanges-legend-plusminus": "''(±123)''",
+ "recentchanges-submit": "Bıasene",
"rcnotefrom": "Cêr de <strong>$2</strong> ra nata vurnayışiyê asenê (tewr vêşi <strong>$1</strong> asenê).",
- "rclistfrom": "$3 u seate $2 ra tepiya vurnayışanê neweyan bımocne",
- "rcshowhideminor": "vurnayışanê werdiyan $1",
- "rcshowhideminor-show": "Bımocne",
+ "rclistfrom": "$3 $2 ra tepiya vurnayışanê neweyan bımocne",
+ "rcshowhideminor": "vurnayışê werdiyi $1",
+ "rcshowhideminor-show": "Bıasene",
"rcshowhideminor-hide": "Bınımne",
- "rcshowhidebots": "Vurnayışanê botan $1",
- "rcshowhidebots-show": "Bımocne",
+ "rcshowhidebots": "botan $1",
+ "rcshowhidebots-show": "Bıasene",
"rcshowhidebots-hide": "Bınımne",
"rcshowhideliu": "karberê qeydbiyayeyi $1",
- "rcshowhideliu-show": "Bımocne",
+ "rcshowhideliu-show": "Bıasene",
"rcshowhideliu-hide": "Bınımne",
- "rcshowhideanons": "Bêname karberan $1",
- "rcshowhideanons-show": "Bımocne",
+ "rcshowhideanons": "karberê bênameyi $1",
+ "rcshowhideanons-show": "Bıasene",
"rcshowhideanons-hide": "Bınımne",
"rcshowhidepatr": "$1 vurnayışê ke dewriya geyrayê",
- "rcshowhidepatr-show": "Bımocne",
+ "rcshowhidepatr-show": "Bıasene",
"rcshowhidepatr-hide": "Bınımne",
- "rcshowhidemine": "Vurnayışanê êdê mı $1",
- "rcshowhidemine-show": "Bımocne",
+ "rcshowhidemine": "vurnayışanê mı $1",
+ "rcshowhidemine-show": "Bıasene",
"rcshowhidemine-hide": "Bınımne",
"rcshowhidecategorization": "kategorizasyonê pele $1",
- "rcshowhidecategorization-show": "Bımocne",
+ "rcshowhidecategorization-show": "Bıasne",
"rcshowhidecategorization-hide": "Bınımne",
- "rclinks": "Peyên $2 rocan de $1 vurnayışan bımocne <br />$3",
+ "rclinks": "Peyniya $2 rocan de $1 vurnayışan bımocne <br />$3",
"diff": "ferq",
"hist": "verên",
"hide": "Bınımne",
- "show": "Bımocne",
+ "show": "Bıasne",
"minoreditletter": "q",
"newpageletter": "N",
"boteditletter": "b",
"uploadbtn": "Dosya bar ke",
"reuploaddesc": "Barkerdışi iptal ke u peyser şo formê barkerdışi",
"upload-tryagain": "Deskripyonê dosyayî ke vurîya ey qeyd bike",
- "uploadnologin": "Şıma cıkewtış nêvıraşt o",
+ "uploadnologin": "Şıma cıkewtış nêvıraşto",
"uploadnologintext": "Ti şeni $1 dosya bar bikere.",
"upload_directory_missing": "Direktorê dosyayê ($1)î biyo vînî u webserver de nieşkeno viraziye.",
"upload_directory_read_only": "Direktorê dosyayê ($1)î webserver de nieşkeno binuse.",
"statistics-header-hooks": "Yewbina istatistiki",
"statistics-articles": "Pelê zerreki",
"statistics-pages": "Peli",
- "statistics-pages-desc": "Pelanê hemî ke wîkî de estê, pelanê mineqeşeyî, redireksiyon ucb... dehil o.",
+ "statistics-pages-desc": "Wiki de peley pêro, kategoriy, hetenayışi wesaire...",
"statistics-files": "Dosyayê bar biye",
- "statistics-edits": "{{SITENAME}} saz kerdış ra hetana newke amora vırnayışan",
+ "statistics-edits": "Ronayen da {{SITENAME}} ra newke amora vıryayışan",
"statistics-edits-average": "Her pele sero nısbi vurnayış",
"statistics-users": "[[Special:ListUsers|Karber]]ê qeydıni",
"statistics-users-active": "Karberê aktifi",
"pageswithprop-submit": "Şo",
"pageswithprop-prophidden-long": "Erca metinda derger nımneya ($1)",
"pageswithprop-prophidden-binary": "Erca dıdıyına ($1) nımneyé",
- "doubleredirects": "Serşıkıtışê dıleti",
+ "doubleredirects": "Hetenayışê dıleti",
"doubleredirectstext": "no pel pelê ray motışani liste keno.\ngıreyê her satıri de gıreyi; raş motışê yewın u dıyıni esto.\n<del>serê ey nuşteyi</del> safi biye.",
"double-redirect-fixed-move": "[[$1]] kırışiye.\nNa otomatikmen biye rocaniye û nıka [[$2]] ser şıknena.",
"double-redirect-fixed-maintenance": "Serkışışteno dıletê [[$1]] ra pela da [[$2]] vuriyeno.",
"withoutinterwiki": "Pelê ke zıwananê binan rê gıreyê cı çıniyo",
"withoutinterwiki-summary": "Enê pelî ke versiyonê ziwanî binî ra link nidano.",
"withoutinterwiki-legend": "Verole",
- "withoutinterwiki-submit": "Bımocne",
+ "withoutinterwiki-submit": "Bıasene",
"fewestrevisions": "Pelê be senık çımraviyarnayışi",
"nbytes": "$1 {{PLURAL:$1|bayt|bayti}}",
- "ncategories": "$1 {{PLURAL:$1|Kategoriye|Kategoriyi}}",
+ "ncategories": "$1 {{PLURAL:$1|Kategori|Kategoriy}}",
"ninterwikis": "$1 {{PLURAL:$1|interwiki|interwikiy}}",
"nlinks": "$1 {{PLURAL:$1|link|linkî}}",
"nmembers": "$1 {{PLURAL:$1|eza|ezayan}}",
"mostrevisions": "Pelan ke tewr zaf revizyonî biyê.",
"prefixindex": "Veroleya peley pêro",
"prefixindex-namespace": "Peleyê Veroleyıni ($1 cay nami)",
+ "prefixindex-submit": "Bıasene",
"prefixindex-strip": "Listeya réz bıyayışi",
"shortpages": "Pelê kılmeki",
"longpages": "Pelê dergeki",
"protectedpages-performer": "Şeveknayışê karberi",
"protectedpages-params": "Parametreyê şeveknayışi",
"protectedpages-reason": "Sebeb",
+ "protectedpages-submit": "Asayışê pela",
"protectedpages-unknown-timestamp": "Nêzanaye",
"protectedpages-unknown-performer": "Karbero nêzanaye",
"protectedtitles": "Sernameyê pawıteyi",
"usereditcount": "$1 {{PLURAL:$1|vurnayîş|vurnayîşî}}",
"usercreated": "$2 de $1 {{GENDER:$3|viraziya}}",
"newpages": "Pelê newey",
+ "newpages-submit": "Bıasene",
"newpages-username": "Nameyê karberi:",
"ancientpages": "Pelê kehenêri",
- "move": "Bere",
- "movethispage": "Ena pele bere",
+ "move": "Wegi",
+ "movethispage": "Ena peler wegi",
"unusedimagestext": "Enê dosyey estê, feqet zerrey yew pele de wedardey niyê.\nXo vira mekerê ke, sıteyê webiê bini şenê direkt ebe URLi yew dosya ra gırê bê, u wına şenê verba gurênayışo feal de tiya hewna lista bê.",
"unusedcategoriestext": "Kategoriyê ke cêr derê, nê bıbê zi, terefê qet madeyan ya zi kategoriyan ra nêgureniyenê.",
"notargettitle": "Hedef çini yo",
"apisandbox": "API qumdor",
"apisandbox-submit": "Bıwazê",
"apisandbox-reset": "Bestere",
- "apisandbox-examples": "Misal",
- "apisandbox-results": "Netice",
+ "apisandbox-examples": "Misali",
+ "apisandbox-dynamic-parameters": "Parametreya debyayi",
+ "apisandbox-dynamic-parameters-add-label": "Parametre dek:",
+ "apisandbox-dynamic-parameters-add-placeholder": "Nmaey parametrey",
+ "apisandbox-results": "Neticey",
+ "apisandbox-sending-request": "API waştış rışêno...",
"apisandbox-request-url-label": "URL waştış:",
"apisandbox-request-time": "Demê waştışi: $1",
"booksources": "Çımeyê kıtaban",
"specialloguserlabel": "Kerdoğ:",
"speciallogtitlelabel": "Meqsed (sername ya zi {{ns:user}}:karberi rê nameyê karberi):",
"log": "Qeydi",
+ "logeventslist-submit": "Bıasene",
"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ê.",
- "logempty": "qaydi de weina yew malumat çino",
+ "logempty": "Qeydan dı malumato unasin çıni yo.",
"log-title-wildcard": "sername yê ke pê ney nuşteyi destkenêpê bıgêr.",
"showhideselectedlogentries": "Qeydê weçinayışê bımocne/bınımne dekerê",
+ "log-edit-tags": "Etiketanê weçinayê qeydan bıvurnê",
+ "checkbox-select": "Weçinaye: $1",
+ "checkbox-all": "Pêro",
+ "checkbox-none": "Temam",
"allpages": "Peli pêro",
"nextpage": "Pela badê cû ($1)",
"prevpage": "Pela verêne ($1)",
"cachedspecial-viewing-cached-ts": "Na pela raşt niya, şımayê enewke versiyonê verhafızada na pela vinenê.",
"cachedspecial-refresh-now": "Peyêni bıvin.",
"categories": "Kategoriy",
+ "categories-submit": "Bıasene",
"categoriespagetext": "{{PLURAL:$1|Kategoriya cêrene|Kategoriyanê cêrênan}} de peli ya zi medya estê.\n[[Special:UnusedCategories|Kategoriyê ke nêxebetiyenê]] tiya de nêmocniyayê.\n[[Special:WantedCategories|Kategoriyanê waşteyeyan]] de zi bıvêne.",
"categoriesfrom": "Kategoriyê ke be ninan dest pêkenê, bımocne:",
"deletedcontributions": "İştırakê karberi esterdi",
"linksearch-line": "$1, $2 ra link biya",
"linksearch-error": "jokeri têna nameyê makina ya serekini de aseni/eseni.",
"listusersfrom": "karber ê ke pey ıney detpêkeni ramocın:",
- "listusers-submit": "Bımocne",
+ "listusers-submit": "Bıasene",
"listusers-noresult": "karber nêdiyayo/a.",
"listusers-blocked": "(blok biy)",
"activeusers": "Listey karberan de aktivan",
"activeusers-intro": "Ena yew listeya karberê ke $1 {{PLURAL:$1|roc|rocan}} ra tepya iştiraq kerdo ênan mocneno.",
- "activeusers-count": "$1 peyni {{PLURAL:$3|roz de|$3 rozan de}} $1 {{PLURAL:$1|hereket|hereketi}} kerdê",
+ "activeusers-count": "Peyni {{PLURAL:$3|roc de|$3 rocan de}} $1 {{PLURAL:$1|hereket kerdo|hereketi kerdê}}",
"activeusers-from": "Enê karberi ra tepya bımocne:",
"activeusers-hidebots": "Botan bınımne",
"activeusers-hidesysops": "İdarekaran bınımne",
"activeusers-noresult": "Karberi nêdiyayê.",
+ "activeusers-submit": "Karberanê aktivan bıasene",
"listgrouprights": "heqê grubê karberi",
"listgrouprights-summary": "wikiya cêrın a ke tede grubê karberi nişane biyê, listeya heqê cıresayişê inan o.\nqey heqê şexsi de [[{{MediaWiki:Listgrouprights-helppage}}|hema malumato ziyed]] belka esto.",
"listgrouprights-key": "* <span class=\"listgrouprights-granted\">Heqa daiye</span>\n* <span class=\"listgrouprights-revoked\">Heqa gıreti</span>",
"listgrouprights-group": "Grube",
"listgrouprights-rights": "Heqqî",
"listgrouprights-helppage": "Help:Heqqanê gruban",
- "listgrouprights-members": "[listeya ezayan]",
+ "listgrouprights-members": "[listey ezayan]",
"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|Grube|Gruban}} cı kerê: $1",
"listgrouprights-removegroup-self": "Hesabê xo ra {{PLURAL:$2|grube|gruban}} bıvecê: $1",
"listgrouprights-addgroup-self-all": "şıma eşkeni hesabê xo re heme gruban têare bıkerî",
"listgrouprights-removegroup-self-all": "şıma hesabê xo ra eşkeni heme gruban bıveci",
+ "listgrouprights-namespaceprotection-header": "Kılm kerdena nameyan",
"listgrouprights-namespaceprotection-namespace": "Heruna nami",
"trackingcategories": "Kategoriyê teqibi",
"trackingcategories-msg": "Kategoriya teqibi",
"watchlist-details": "{{PLURAL:$1|$1 pele|$1 peleyan}} listeyê seyr-kerdışi şıma dı, peleyanê vurnayışi dahil niyo.",
"wlheader-enotif": "E-mail xeber dayiş abiyo.",
"wlheader-showupdated": "ziyaretê şıma ye peyini de vuryayişê peli pê '''nuşteyo qalıni''' mocyayo.",
- "wlnote": "$3 seate u $4 deqa dıma {{PLURAL:$2|ju seate dı|'''$2''' ju seate dı}} {{PLURAL:$1|vurnayışe peyeni|vurnayışe '''$1''' peyeni}} cêrdeyê",
+ "wlnote": "$3 saete $4 ra dıme {{PLURAL:$2|yew saete de|'''$2''' saetan de}} {{PLURAL:$1|vurnayışo peyên|vurnayışê '''$1''' peyêni}} cêrderê.",
"wlshowlast": "Peyni de vurnayışan ra $1 seata u $2 roca bımocnê",
"watchlist-hide": "Bınımne",
+ "watchlist-submit": "Bıasene",
"wlshowtime": "Peyênan bımocne:",
- "wlshowhideminor": "vurnayışanê werdiyan",
+ "wlshowhideminor": "vurnayışê werdiyi",
"wlshowhidebots": "boti",
"wlshowhideliu": "karberê qeydıni",
"wlshowhideanons": "karberê anonimi",
"delete-confirm": "\"$1\" bestere",
"delete-legend": "Bestere",
"historywarning": "'''Teme:''' Pela ke şıma esterenê tede yew viyarte be teqriben $1 {{PLURAL:$1|versiyon esto|versiyoni estê}}:",
+ "historyaction-submit": "Bıasene",
"confirmdeletetext": "Tı ho yew pele u tarixê pele wederneno.\nTı ra rica keno, tı zani tı ho sekeno, tı zani neticeyanê eno wedarnayışi u tı zani tı ser [[{{MediaWiki:Policy-url}}|poliçe]] kar keno.",
"actioncomplete": "Kar bi temam",
"actionfailed": "kar nêbı",
"deletedtext": "\"$1\" biya wedariya.\nQe qeydê wedarnayışi, $2 bevinin.",
- "dellogpage": "Qeydê esternayışi",
+ "dellogpage": "Qeydê esterıtışi",
"dellogpagetext": "listeya cêrıni heme qaydê hewn a kerdeyan o.",
- "deletionlog": "Qeydê esternayışi",
+ "deletionlog": "qeydê esterıtışi",
"reverted": "revizyono verin tepiya anciyayo",
"deletecomment": "Sebeb:",
"deleteotherreason": "Sebebo bin:",
"changecontentmodel-title-label": "Sernameyê pele",
"changecontentmodel-model-label": "Modelê zerrekiyo newe",
"changecontentmodel-reason-label": "Sebeb:",
+ "changecontentmodel-submit": "Bıvurne",
"log-name-contentmodel": "Qeydê vurnayışanê modelê zerreki",
+ "logentry-contentmodel-change-revertlink": "peyser biya",
+ "logentry-contentmodel-change-revert": "peyser biya",
"protectlogpage": "Qeydê staryayan",
"protectlogtext": "Şıma vurnayişê gırewtışê/wedarnayışê pawıtişi vinenê.\nQey malumato ziyede [[Special:ProtectedPages|Peleyê ke star biye]] bewni rê êna .",
"protectedarticle": "\"[[$1]]\" kılit biyo",
"protect-othertime": "Wextê binî:",
"protect-othertime-op": "wextê binî",
"protect-existing-expiry": "wextê qediyayişi yê mewcudi: $3, $2",
+ "protect-existing-expiry-infinity": "Mewcud drmê qedyayışi:Bewext",
"protect-otherreason": "sebebo bin/sebebê ilaveyi",
"protect-otherreason-op": "Sebebo bin",
"protect-dropdown": "*sebebê pawıtışi ye pêroyiye\n** vandalizmo hed ra vecaye\n** spamo hed ra vecaye\n** şêrê/herbê vurnayişi\n** pel o ke zaf wayirê trafiki yo",
"maximum-size": "Ebatê maximumî",
"pagesize": "(bitî)",
"restriction-edit": "Bıvurne",
- "restriction-move": "Bere",
+ "restriction-move": "Berr",
"restriction-create": "Vıraze",
"restriction-upload": "Bar ke",
"restriction-level-sysop": "tam pawiyayo",
"namespace_association": "Heruna nameyanê elaqedaran",
"tooltip-namespace_association": "Herunda canemiya elekeyın nışan kerdışi sero qıse kerdışi yana zerre dekerdışi rê ena dora tesdiqi nışan kerê",
"blanknamespace": "(Ser)",
- "contributions": "İştıraqê {{GENDER:$1|karber}}i",
+ "contributions": "Dekerdışê {{GENDER:$1|karber}}i",
"contributions-title": "Dekerdenê karber de $1",
"mycontris": "İştıraqi",
"anoncontribs": "İştıraqi",
"sp-contributions-newbies": "Tenya iştıraqanê karberanê neweyan bımocne",
"sp-contributions-newbies-sub": "Qe hesebê newe",
"sp-contributions-newbies-title": "Îştîrakê karberî ser hesabê neweyî",
- "sp-contributions-blocklog": "Qeydê meni",
+ "sp-contributions-blocklog": "qeydê kılitbiyayeyi",
"sp-contributions-deleted": "iştırakê karberi esterdi",
"sp-contributions-uploads": "barkerdey",
"sp-contributions-logs": "qeydi",
"sp-contributions-username": "Adresa IPy ya zi nameyê karberi:",
"sp-contributions-toponly": "Tenya rewizyonanê tewr peyniyan bimocne",
"sp-contributions-submit": "Cı geyre",
- "whatlinkshere": "Pele rê gırey",
+ "whatlinkshere": "Pele rê gıreyi",
"whatlinkshere-title": "Per da \"$1\" rê perê ke gre danê",
"whatlinkshere-page": "Pele:",
"linkshere": "Ena peleyan grey biya '''[[:$1]]''':",
"whatlinkshere-hidelinks": "Greyê $1",
"whatlinkshere-hideimages": "Gıreyê dosya $1",
"whatlinkshere-filters": "Avrêci",
+ "whatlinkshere-submit": "Şo",
"autoblockid": "Otomatik vındarnayış #$1",
"block": "Karberi vındarne",
"unblock": "Hesabê karberi akerê",
- "blockip": "Karberi kılit ke",
+ "blockip": "{{GENDER:$1|Karberi}} kılit ke",
"blockip-legend": "Karber blok bike",
- "blockiptext": "pê şuxulnayişê formê cêrıni, şıma eşkeni verniyê vurnayişkerdışê yew karberi ya zi yew IPyi bıgêrî. No têna qey verni-gırewtışê vandalizmiyo u gani şıma [[{{MediaWiki:Policy-url}}|qaydeyan]] re diqqet bıkeri. cêr de muheqqeq sebebê verni-grewtışi bınusi. (mesela: -nê- pelani de vandalizm kerdo).",
+ "blockiptext": "pê şuxulnayişê formê cêrıni, şıma eşkeni verniyê vurnayişkerdışê yew karberi ya zi yew IPyi bıgêrî. No têna qey verni-gırewtışê vandalizmiyo u gani şıma [[{{MediaWiki:Policy-url}}|qaydeyan]] re diqqet bıkeri. cêr de muheqqeq sebebê verni-grewtışi bınusi. (mesela: -nê- pelani de vandalizm kerdo)",
"ipaddressorusername": "Adresa IPy ya zi nameyê karberi:",
"ipbexpiry": "Qedyayış:",
"ipbreason": "Sebeb:",
"ipb-unblock": "Yew adresê IPî ya zi nameyê karberî blok bike",
"ipb-blocklist": "Blokî ke hama estê ey bivîne",
"ipb-blocklist-contribs": "Qandê {{GENDER:$1|}} ra iştıraqi",
+ "ipb-blocklist-duration-left": "$1 vet",
"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",
"contribslink": "iştıraqi",
"emaillink": "e-poste bırışe",
"autoblocker": "Şıma otomatikmen kılit biy, çıke adresa şımaya ''IP''y terefê \"[[User:$1|$1]]\" gureniyena.\nSebebê kılitbiyayışê $1'i \"$2\"o",
- "blocklogpage": "Qeydê meni",
+ "blocklogpage": "Qeydê astengi",
"blocklog-showlog": "verniyê no/na karberi cıwa ver geriyayo/ya.",
"blocklog-showsuppresslog": "verniyê no/na karberi cıwa ver geriyayo/ya.",
"blocklogentry": "[[$1]] biyo bloqe, sebeb: $3, hetana $2 do bıramo.",
"movepage-page-moved": "pelê $1i kırışiya pelê $2i.",
"movepage-page-unmoved": "pelê $1i nêkırışiyeno sernameyê $2i.",
"movepage-max-pages": "tewr ziyed $1 {{PLURAL:$1|peli|peli}} kırışiya u hıni ziyedê ıney otomotikmen nêkırışiyeno.",
- "movelogpage": "Qeydê berdışi",
+ "movelogpage": "Qeydê wegrotışi",
"movelogpagetext": "nameyê liste ya ke cêr de yo, pelê vuriyayeyani mocneno",
"movesubpage": "{{PLURAL:$1|Subpage|pelê bınıni}}",
"movesubpagetext": "{{PLURAL:$1|pelê bınıni yê|pelê bınıni yê}} no $1 peli cer de yo.",
"import": "Peleyi import bik",
"importinterwiki": "Zewbina wiki ra ard",
"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-sourcewiki": "Çıme wiki:",
+ "import-interwiki-sourcepage": "Çıme pela:",
"import-interwiki-history": "Qeydanê pele pêrune kopya ke",
"import-interwiki-templates": "Şablonan pêro zerre ke",
"import-interwiki-submit": "Zerre ke",
+ "import-mapping-default": "Hesıbyaye lokasyonan miyan ke",
+ "import-mapping-namespace": "Dek yu canamey miyan",
+ "import-mapping-subpage": "Bınnpeley ena peler deyne azere ke",
"import-upload-filename": "Nameyê dosyayi:",
"import-comment": "Mışewre:",
"importtext": "Kerem ke dosyay, çımeyê wiki ra pê [[Special:Export|kırıştışê teberdayişi]] bıdê teber, Komputerê xo de qeyd kerê u bar kerê tiya.",
"tooltip-ca-unprotect": "Starkerdışe ena peler bıvurne",
"tooltip-ca-delete": "Ena pele bestere",
"tooltip-ca-undelete": "peli biyarê halê ver hewnakerdışi",
- "tooltip-ca-move": "Ena pele bere",
+ "tooltip-ca-move": "Ena peler wegi",
"tooltip-ca-watch": "Ena pele lista xoya seyrkerdışi ke",
"tooltip-ca-unwatch": "Ena pele lista xoya seyrkerdışi ra vece",
- "tooltip-search": "{{SITENAME}} miyan de bıvin",
+ "tooltip-search": "{{SITENAME}} de cı geyre",
"tooltip-search-go": "Ebe nê namey tami şo yew pela ke esta",
- "tooltip-search-fulltext": "Nê metni peran dı cı geyre",
- "tooltip-p-logo": "Şo pela seri",
+ "tooltip-search-fulltext": "Pelan miyan de nê metıni cı geyre",
+ "tooltip-p-logo": "Pela seri bıvêne",
"tooltip-n-mainpage": "Şo pela seri",
"tooltip-n-mainpage-description": "Şo pela seri",
"tooltip-n-portal": "Heqa proceyi de, çı şenay bıkerê, çı koti vêniyeno",
"tooltip-feed-atom": "Qe ena pele atom feed",
"tooltip-t-contributions": "Yew lista iştırakanê {{GENDER:$1|nê karberi}}",
"tooltip-t-emailuser": "Ena karber ri yew email bışırav",
- "tooltip-t-upload": "Dosya bar ke",
+ "tooltip-t-upload": "Dosyeyan bar ke",
"tooltip-t-specialpages": "Yew lista pelanê xasanê pêroyinan",
"tooltip-t-print": "Hewl versiyona ploğnayışa na perer",
"tooltip-t-permalink": "Gırêyo daimi be ena versiyonê pele",
"tooltip-preferences-save": "Terciha qeyd ke",
"tooltip-summary": "Yew xulasaya kilm binuse",
"interlanguage-link-title": "$1 - $2",
+ "common.css": "/************************************************\n * COMMON CSS\n *\n * Any CSS placed in this page will be used on \n * all skins, please think carefully about if it\n * belongs here (and not in one of the skin CSS\n * pages) before adding it. Thanks.\n ************************************************/\n\n/* <table class=\"highlighthovertable\"> */\ntable.highlighthovertable tr:hover,\ntable.highlighthovertable tr:hover td,\ntable.mw-ext-translate-groupstatistics tr:hover,\ntable.mw-ext-translate-groupstatistics tr:hover td {\n background-color: white;\n}\n\n\n/* Babel wrapper layout. */\n/* XXX: This is either redundant or should be in-core */\n/* @noflip */table.mw-babel-wrapper {\n\twidth: 238px;\n\tfloat: right;\n\tclear: right;\n\tmargin: 1em;\n\tborder-style: solid;\n\tborder-width: 1px;\n\tborder-color: #99B3FF;\n}\n\n/* Babel box layout. */\n/* @noflip */div.mw-babel-box {\n\tfloat: left;\n\tclear: left;\n\tmargin: 1px;\n}\n\ndiv.mw-babel-box table {\n\twidth: 238px;\n}\n\ndiv.mw-babel-box table th {\n\twidth: 238px;\n\twidth: 45px;\n\theight: 45px;\n\tfont-size: 14pt;\n\tfont-family: monospace;\n}\n\ndiv.mw-babel-box table td {\n\tfont-size: 8pt;\n\tpadding: 4pt;\n\tline-height: 1.25em;\n}\n\n/* Babel box colours. */\ndiv.mw-babel-box-0 {\n\tborder: solid #B7B7B7 1px;\n}\n\ndiv.mw-babel-box-1 {\n\tborder: solid #C0C8FF 1px;\n}\n\ndiv.mw-babel-box-2 {\n\tborder: solid #77E0E8 1px;\n}\n\ndiv.mw-babel-box-3 {\n\tborder: solid #99B3FF 1px;\n}\n\ndiv.mw-babel-box-4 {\n\tborder: solid #CCCC00 1px;\n}\n\ndiv.mw-babel-box-5 {\n\tborder: solid #F99C99 1px;\n}\n\ndiv.mw-babel-box-N {\n\tborder: solid #6EF7A7 1px;\n}\n\ndiv.mw-babel-box-0 table th {\n\tbackground-color: #B7B7B7;\n}\n\ndiv.mw-babel-box-1 table th {\n\tbackground-color: #C0C8FF;\n}\n\ndiv.mw-babel-box-2 table th {\n\tbackground-color: #77E0E8;\n}\n\ndiv.mw-babel-box-3 table th {\n\tbackground-color: #99B3FF;\n}\n\ndiv.mw-babel-box-4 table th {\n\tbackground-color: #CCCC00;\n}\n\ndiv.mw-babel-box-5 table th {\n\tbackground-color: #F99C99;\n}\n\ndiv.mw-babel-box-N table th{\n\tbackground-color: #6EF7A7;\n}\n\ndiv.mw-babel-box-0 table {\n\tbackground-color: #E8E8E8;\n}\n\ndiv.mw-babel-box-1 table {\n\tbackground-color: #F0F8FF;\n}\n\ndiv.mw-babel-box-2 table {\n\tbackground-color: #D0F8FF;\n}\n\ndiv.mw-babel-box-3 table {\n\tbackground-color: #E0E8FF;\n}\n\ndiv.mw-babel-box-4 table {\n\tbackground-color: #FFFF99;\n}\n\ndiv.mw-babel-box-5 table {\n\tbackground-color: #F9CBC9;\n}\n\ndiv.mw-babel-box-N table {\n\tbackground-color: #C5FCDC;\n}\n\n.babel-box td.babel-footer {\n\ttext-align: center;\n}\n\n/* Styling for portals. */\ndiv.table {\n display: table;\n vertical-align: top;\n width: 100%;\n}\n\ndiv.table-row {\n display: table-row;\n vertical-align: top;\n}\n\ndiv.table-cell {\n display: table-cell;\n vertical-align: top;\n}\n\nbody.ns-100 table.mw-babel-wrapper {\n border: solid 1px #bbbbbb;\n background-color: #f0f0f0;\n margin-left: 1em;\n}\n\n.graytext {\n color: #aaa;\n}\n\n/* On [[Special:RecentChanges]] and [[Special:Watchlist]] make the new pages symbol bold green and the minor edit symbol gray. */\n.newpage {\n color: green;\n font-weight: bold\n}\n\n.minoredit,\n.minor {\n color: gray;\n}\n\n/* Monospace diffs, this makes more sense since diffs show what would be seen in the edit box. */\n/* Note: Anno 2012 many browsers don't use monospace in the textarea anymore by default, notably Chrome and Safari don't (unless the user overrides this in the preferences) */\n.diff-context,\n.diff-deletedline,\n.diff-addedline {\n font-family: monospace, \"Courier New\";\n/* Just guess does the stupid wikidiff2 extensions add extra whitespace around..... */\n white-space: -moz-pre-wrap;\n white-space: pre-wrap;\n}\n \n.diffchange {\n border: 1px dotted rgb( 170, 170, 170 );\n}\n\n/* It is unclear what the following CSS does, please add comments if you can clarify. */\n/* The box which is 400px high and if its content is longer, it gets the scrollbar */\n.scrollme {\n overflow: scroll;\n width: 100%;\n height: 400px;\n}\n\n/* Standard Navigationsleisten, aka box hiding thingy from .de. Documentation at [[Wikipedia:NavFrame]]. */\ndiv.Boxmerge, div.NavFrame { margin: 0; padding: 4px; border-collapse: collapse;}\ndiv.Boxmerge div.NavFrame { border-style: none; border-style: hidden; }\ndiv.NavFrame + div.NavFrame { border-top-style: none; border-top-style: hidden; }\ndiv.NavFrame div.NavHead { height: 1.6em; position:relative; }\ndiv.NavEnd { margin: 0; padding: 0; line-height: 1px; clear: both; }\na.NavToggle { position: absolute; top: 0; right: 5px; }\n.note-flaggedrevs * a.NavToggle { right: 12px; } /* For [[Template:Flagged Revs]] */\n\n/* Template:Languages */\n.bw-languages {\n border: 1px solid #aaaaaa;\n padding: 0.2em;\n border-collapse: collapse;\n line-height: 1.2;\n font-size: 95%;\n margin: 1px 1px;\n}\n.bw-languages-title {\n width: 180px;\n border: 1px solid #aaaaaa;\n background: #EEF3E2;\n padding: 0.5em;\n font-weight: bold;\n}\n.bw-languages-links { padding:0.5em; background:#F6F9ED; }\n\n/* Senseless in this project */\n#editpage-copywarn { display: none; }\n\n/* Hide warnings about bad links on MediaWiki:Common.css */\n.page-MediaWiki_Common_css .mw-translate-messagechecks { display: none; }\n\n/*******************\n** Faciliate RTL translation\n*******************/\n/* @noflip */\n#bodyContent .arabic a {\n\tpadding-right:0;\n\tbackground:none;\n}\n\n.vatop tr, tr.vatop, .vatop td, .vatop th {\n vertical-align: top;\n}\n\n.bw-languages {\n direction: ltr;\n}\n\n/* prevent wrapping of lines in LQT TOC if not necessary */\ntable.lqt_toc {\n\twidth: auto;\n}\n\n/* [[m:MediaZilla:35337]] */\n@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx) {\n #p-logo a {\n background-image: url(\"//translatewiki.net/images/thumb/7/7c/Translatewiki-logo-bare.svg/152px-Translatewiki-logo-bare.svg.png\") !important;\n background-size: auto 135px;\n }\n}\n@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {\n #p-logo a {\n background-image: url(\"//translatewiki.net/images/thumb/7/7c/Translatewiki-logo-bare.svg/202px-Translatewiki-logo-bare.svg.png\") !important;\n background-size: auto 135px;\n }\n}\n\n/* qqq visibility, [[Thread:Support/Suggestion: Add this CSS to MediaWiki:Common.css]] */\n \n.mw-sp-translate-edit-info .mw-content-ltr {\n background-position:left center;\n padding-left:45px;\n}\nfieldset.mw-sp-translate-edit-info .mw-centent-rtl {\n background-position:right center;\n padding-right:45px;\n}\n\n/* Semantic MediaWiki - make special properties easier to identify */\n\n.smwbuiltin a,\n.smwbuiltin a.new {\n\tcolor: #FF8000;\n}\n\n/* Recentchangestext toggle link */\n.white-link a {\n color: #fff;\n}",
"common.js": "/* Any JavaScript here will be loaded for all users on every page load. */",
"anonymous": "{{PLURAL:$1|karberê|karberê}} anonimi yê keyepelê {{SITENAME}}i",
"siteuser": "karberê {{SITENAME}}i $1",
"file-info-png-frames": "$1 {{PLURAL:$1|çerçeve|çerçeveyi}}",
"file-no-thumb-animation": "'''Not: Dılet tekniko limit, gırd agozneya resm de qıckek de animasyoni miyan dı nêbo.'''",
"file-no-thumb-animation-gif": "'''Not: Dılet tekniko limit, gırd agozneya resm de qıckek de GIF imaci de animasyon do nêbo.'''",
- "newimages": "Galeriya dosyayan dê newan",
+ "newimages": "Galeriye Dosyan dê newan",
"imagelisttext": "Cêr de yew listeyê '''$1''' esto {{PLURAL:$1|dosya|dosyayi}} veçiniya $2.",
"newimages-summary": "Ena pela xasi dosyayi ke peni de bar biyayeyi mocnane.",
"newimages-legend": "Avrêc",
"confirm-watch-top": "Ena pele lista xoya seyrkerdışi ke",
"confirm-unwatch-button": "TEMAM",
"confirm-unwatch-top": "Ena pele lista xoya seyirkerdışi ra bıvece?",
+ "confirm-rollback-button": "TEMAM",
"semicolon-separator": " ",
"comma-separator": ", ",
"colon-separator": ": ",
"version-hook-name": "Nameyê çengelî",
"version-hook-subscribedby": "Eza biyayoğ",
"version-version": "($1)",
+ "version-no-ext-name": "[namr çıno]",
"version-license": "Lisansê MediaWiki",
"version-ext-license": "Lisans",
"version-ext-colheader-name": "Dergiye",
+ "version-skin-colheader-name": "Çerme",
"version-ext-colheader-version": "Versiyon",
"version-ext-colheader-license": "Lisans",
"version-ext-colheader-description": "Şınasnayış",
"version-entrypoints-header-url": "GRE",
"version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath Article path]",
"version-entrypoints-scriptpath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgScriptPath Script path]",
+ "version-libraries-library": "Kıtıbxane",
+ "version-libraries-version": "Versiyon",
+ "version-libraries-license": "Lisans",
+ "version-libraries-description": "Şınasnayış",
+ "version-libraries-authors": "Nuştekari",
"redirect": "Serşıkıtena dosya, karberi, pele ya ki revizyonê kamiya dosya",
"redirect-summary": "Na pela xase to hetê yew dosya (nameyê dosya dayeyo), yew pele (kamiya revizyoni ya zi pele dayiya) ya zi yew pela karberi (kamiya karberiya reqemkiye dayiya) ser şıknena. Gurenayış: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], ya zi [[{{#Special:Redirect}}/user/101]].",
"redirect-submit": "Şo",
"redirect-page": "Kamiya pele",
"redirect-revision": "Çımraviyarnayışê pele",
"redirect-file": "Namey dosya",
+ "redirect-logid": "Qeydé ID",
"redirect-not-exists": "Erc nêvineyê",
"fileduplicatesearch": "Dosyayanê zey pêyan cı geyrê",
"fileduplicatesearch-summary": "Dosyanê çıftan bınê têmiyankewteyan de bıgeyre.",
"fileduplicatesearch-result-1": "Dosyayê ''$1î'' de hem-kopya çini yo.",
"fileduplicatesearch-result-n": "Dosyayê ''$1î'' de {{PLURAL:$2|1 hem-kopya|$2 hem-kopyayî'}} esto.",
"fileduplicatesearch-noresults": "Ebe namey \"$1\" ra dosya nêdiyayê.",
- "specialpages": "Pelê xısusiyi",
+ "specialpages": "Peleyê xısusiy",
"specialpages-note-top": "Kıtabek",
"specialpages-note": "* Pelê xasê normali.\n* <span class=\"mw-specialpagerestricted\">Pelê xasê nımıtey.</span>",
"specialpages-group-maintenance": "Raporê pawıtışi",
"blankpage": "Pela venge",
"intentionallyblankpage": "Ena pel bi zanayişî weng mendo.",
"external_image_whitelist": " #no satır zey xo verde/raverde<pre>\n#parçeyê ifadeya rêzbiyayeyani (têna zerreyê ıney de // ) u çıtayo/çiyo zi mende cêr de têare kerê.\n#ney URL ya (hotlink) resmê teberi de hemcıta benî.\n#Ê yê ke hemcıt (eşleşmek-hemçift) biyê zey resımi asenî, eqsê hal de zi zey gıreyê resmi aseno.\nsatır ê ke pê ney # # destpêkenê zey mışore/mıjore muamele vineno.\n#herfa gırd û qıci ferq nêkeno\n\n#parçeyê ifadeya rêzbiyayeyani bıerzê serê ney satıri. no satır zey xo verde/raverde </pre>",
- "tags": "Etiketê vurnayîşê raştî",
+ "tags": "Ravêrde vurnayışanê etiketa",
"tag-filter": "Parzûnê [[Special:Tags|etiketi]]:",
"tag-filter-submit": "Avrêc",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Etiket|Etiketi}}]]: $2)",
"tags-description-header": "Tam arezekerdışê maneyê cı",
"tags-active-header": "Activ o?",
"tags-hitcount-header": "Vurnayîşî ke etiket biyê",
+ "tags-actions-header": "Kerdışi",
"tags-active-yes": "Eya",
"tags-active-no": "Nê",
+ "tags-source-extension": "Teref dê yo dergeneki ra şınasiyayo",
"tags-edit": "bıvurne",
+ "tags-delete": "bestere",
+ "tags-activate": "Aktiv ke",
+ "tags-deactivate": "Aktiv mek",
"tags-hitcount": "$1 {{PLURAL:$1|vurnayış|vurnayışi}}",
+ "tags-create-tag-name": "Nameyê etiketi:",
+ "tags-create-reason": "Sebeb:",
+ "tags-create-submit": "Vıraze",
"comparepages": "Pela miqeyese ke",
"compare-page1": "Pele 1",
"compare-page2": "Pele 2",
"htmlform-cloner-delete": "Wedare",
"sqlite-has-fts": "$1 tam-metn destegê cı geyrayışiya piya",
"sqlite-no-fts": "$1 tam-metn bê destegê cı geyrayışi",
- "logentry-delete-delete": "Karber $1 pela $3 {{GENDER:$2|besternê}}",
+ "logentry-delete-delete": "$1 pela $3 {{GENDER:$2|esterıte}}",
"logentry-delete-restore": "$1 pela $3 {{GENDER:$2|peyser arde}}",
"logentry-delete-event": "$1 $3: $4 de asayışê {{PLURAL:$5|cıkerdışi|cıkerdışan}} {{GENDER:$2|vurna}}",
"logentry-delete-revision": "$1 pela $3: $4 de asayışê {{PLURAL:$5|yew revizyoni|$5 revizyonan}} {{GENDER:$2|vurna}}",
"noname": "Njejsy žedno płaśece wužywarske mě zapódał.",
"loginsuccesstitle": "Pśizjawjenje wuspěšne",
"loginsuccess": "'''Sy něnto ako „$1” w {{GRAMMAR:lokatiw|{{SITENAME}}}} pśizjawjony.'''",
- "nosuchuser": "Wužywaŕ z mjenim „$1“ njeeksistěrujo. Wužywarske mjenja źiwaju na wjelikopisanje.\nPśeglěduj pšawopis abo [[Special:UserLogin/signup|załož nowe konto]].",
+ "nosuchuser": "Wužywaŕ z mjenim „$1“ njeeksistěrujo. Wužywarske mjenja źiwaju na wjelikopisanje.\nPśeglěduj pšawopis abo [[Special:CreateAccount|załož nowe konto]].",
"nosuchusershort": "Wužywarske mě „$1“ njeeksistěrujo. Pśeglěduj pšawopis.",
"nouserspecified": "Pšosym pódaj wužywarske mě.",
"login-userblocked": "Toś ten wužywaŕ jo blokěrowany. Pśizjawjenje njejo dowólone.",
"accmailtext": "Pśipadnje napórane gronidło za [[User talk:$1|$1]] jo se pósłało k $2. Dajo se na boku ''[[Special:ChangePassword|Gronidło změniś]]'' pśi pśizjawjenju změniś.",
"newarticle": "(Nowy nastawk)",
"newarticletext": "Sy slědował wótkaz na bok, kótaryž hyšći njeeksistěrujo.\nAby bok napórał, zapiš do kašćika dołojce (glědaj [$1 bok pomocy] za dalšne informacije). Jolic sy zamólnje how, klikni na tłocašk '''Slědk''' w swójom wobglědowaku.",
- "anontalkpagetext": "---- ''Toś jo diskusijny bok za anonymnego wužywarja, kótaryž njejo dotychměst žedno wužywarske konto załožył abo swójo konto njewužywa. Togodla dejmy numerisku IP-adresu wužywaś, aby jogo/ju identificěrowali. Taka IP-adresa dajo se wót wšakich wužywarjow wužywaś. Jolic sy anonymny wužywaŕ a se mysliš, až su se njerelewantne komentary na tebje měrili, [[Special:UserLogin/signup|załož konto]] abo [[Special:UserLogin|pśizjaw se]], aby se w pśichoźe zmuśenje z drugimi anonymnymi wužywarjami wobinuł.''",
+ "anontalkpagetext": "---- ''Toś jo diskusijny bok za anonymnego wužywarja, kótaryž njejo dotychměst žedno wužywarske konto załožył abo swójo konto njewužywa. Togodla dejmy numerisku IP-adresu wužywaś, aby jogo/ju identificěrowali. Taka IP-adresa dajo se wót wšakich wužywarjow wužywaś. Jolic sy anonymny wužywaŕ a se mysliš, až su se njerelewantne komentary na tebje měrili, [[Special:CreateAccount|załož konto]] abo [[Special:UserLogin|pśizjaw se]], aby se w pśichoźe zmuśenje z drugimi anonymnymi wužywarjami wobinuł.''",
"noarticletext": "Dotychměst toś ten bok hyšći njewopśimujo žeden tekst. Móžoš w drugich bokach [[Special:Search/{{PAGENAME}}|titel togo boka pytaś]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} wótpowědne protokole pytaś] abo [{{fullurl:{{FULLPAGENAME}}|action=edit}} toś ten bok wobźěłaś]</span>.",
"noarticletext-nopermission": "Tuchylu njejo žeden tekst na toś tom boku.\nMóžoš [[Special:Search/{{PAGENAME}}|toś ten bokowy titel]] na drugich bokach pytaś\nabo <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} wótpowědne protokole pytaś]</span>, ale njamaš pšawo, toś ten bok napóraś.",
"missing-revision": "Wersija #$1 boka z mjenim \"{{FULLPAGENAME}}\" njeeksistěrujo.\n\nPśicyna jo zwětšego zestarjony wótkaz w historiji k bokoju, kótaryž jo se wulašował.\nDrobnostki móžoš w [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} protokolu wulašowanjow] namakaś.",
"noname": "Awu nu pinosuang ngaran momomoguno di pasagaon.",
"loginsuccesstitle": "Nokosuang log.",
"loginsuccess": "'''Nokosuang log ko noh id {{SITENAME}} sobaagi do \"$1\".'''",
- "nosuchuser": "Ingaa momoguno pinungaranan \"$1\".\nNgaran momoguno nopo nga kowoyo pimato.\nIntaai ijaannu, toi [[Special:UserLogin/signup|pomonsoi do takaun kawawagu]].",
+ "nosuchuser": "Ingaa momoguno pinungaranan \"$1\".\nNgaran momoguno nopo nga kowoyo pimato.\nIntaai ijaannu, toi [[Special:CreateAccount|pomonsoi do takaun kawawagu]].",
"nosuchusershort": "Ingaa momoguno kingaran \"$1\".\nIntaai ijaannu.",
"nouserspecified": "Maai posuango ngaran momoguno.",
"login-userblocked": "Nantaban momoguno diti. Oduhan do sumuang log.",
"accmailtext": "Kaatalib somporimonsoi montok [[User talk:$1|$1]] nakaatod no hilo $2.\n\nKaatalib montok akaun wagu milo do alanan hilo id bolikon ''[[Special:ChangePassword|pangalanan kaatalib]]'' soira do kosuang log.",
"newarticle": "(Wagu)",
"newarticletext": "Nakatanudko di noputan kumaa di bolikon di awu po nokosuang.\nMomonsoi ko nopo do bolikon diti, timpuun do manaip id kutak siriba (intaai [$1 bolikon ponokodung] montok lobi gumu kointalangan).\nNung nakaansau ko do hiti, tonsoko ot butang '''gumuli''' id pogigihumnu.",
- "anontalkpagetext": "----''Iti nopo nga bolikon pogibabarasan montok di momomoguno poinlisok it awu poh nokopomonsoi do takaun, toi it awu momoguno dilo.\nMantad dilo, asansagan yahai do poposurat numbur kinoyonon IP do mongintutun dau.\nKinoyonon IP pogialasan do pipiro momomoguno.\nNung momomoguno koh do ingaa ngaran om karamit koh do komin di awu kapadan, mangai [[Special:UserLogin/signup|wonsoyo takaun]] toi [[Special:UserLogin|sumuang log]] do magalai kounsuhan di momomoguno suai di tingaa ngaran.''",
+ "anontalkpagetext": "----''Iti nopo nga bolikon pogibabarasan montok di momomoguno poinlisok it awu poh nokopomonsoi do takaun, toi it awu momoguno dilo.\nMantad dilo, asansagan yahai do poposurat numbur kinoyonon IP do mongintutun dau.\nKinoyonon IP pogialasan do pipiro momomoguno.\nNung momomoguno koh do ingaa ngaran om karamit koh do komin di awu kapadan, mangai [[Special:CreateAccount|wonsoyo takaun]] toi [[Special:UserLogin|sumuang log]] do magalai kounsuhan di momomoguno suai di tingaa ngaran.''",
"noarticletext": "Maso po do ingaa tik id bolikon diti.\nMilo ko nogi do [[Special:Search/{{PAGENAME}}|mogihum do tuluhon bolikon diti]] id bolikon suai,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mogihum kokomoi log-log],\ntoi [{{fullurl:{{FULLPAGENAME}}|action=edit}} mongidit bolikon diti]</span>.",
"noarticletext-nopermission": "Maso po do ingaa tik id bolikon diti.\nMilo ko nogi do [[Special:Search/{{PAGENAME}}|mogihum do tuluhon bolikon diti]] id bolikon suai, toi\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mogihum kokomoi log-log] </span>, nga ingaa kapasagaannu do momonsoi do bolikon diti.",
"userpage-userdoesnotexist": "Akaun momomoguno \"<nowiki>$1</nowiki>\" awu nokorijisto.\nMangai intangai nung mumang ko pomonsoi/mongidit do bolikon diti.",
"allpages-bad-ns": "{{SITENAME}} aiso pinungaranan do \"$1\"",
"categories": "Kakatogori",
"categoriesfrom": "Pokitono kakatogori tinimpuun do:",
- "special-categories-sort-abc": "uludo mompimato",
"deletedcontributions": "Pugaso pinototoluod do momoguno",
"deletedcontributions-title": "Pugaso pinototoluod do momoguno",
"sp-deletedcontributions-contribs": "Totoluod",
"tog-hideminor": "अहिलका मामूली सम्पादनलाई लुकाउन्या",
"tog-hidepatrolled": "गस्ती(patrolled)सम्पादनलाई लुकाउन्या",
"tog-newpageshidepatrolled": "गस्ती गरिया पानानलाई नयाँ पाना सूचीबठेई लुकाउन्या",
+ "tog-hidecategorization": "पृष्ठहरुको श्रेणीकरण हटाया",
"tog-extendwatchlist": "निगरानी सूचीलाई सबै परिवर्तन धेकुन्या गरी बढुन्या , ऐईलका बाहेक",
"tog-usenewrc": "पानाका अहिलका परिवर्तन र अवलोकन सूचीका आधारमी सामूहिक परिवर्तनहरू",
"tog-numberheadings": "शीर्षकहरूलाई स्वत:अङ्कित गर",
"tog-watchdefault": "मुइले सम्पादन गरयाको पाना र फाइल ध्यान सूचीमाई थप्दया",
"tog-watchmoves": "मुइले सार्या पानाहरू र फाइलहरूलाई ध्यान सूचीमी थप्द्या",
"tog-watchdeletion": "मुइले हटायाका पानाहरू र चित्रहरूलाई ध्यान सूचीमी थप्द्या",
+ "tog-watchuploads": "नयाँ फाईल थप|मेरा अवलोकसुचिमी अपलोड गर",
"tog-watchrollback": "मुइले रोलब्याक गर्याका पानाहरू मेरो ध्यानसूचीमी थप्द्या ।",
"tog-minordefault": "सबै सम्पादनहरूलाई पहिल्लई निर्धारित रुपमी सामान्य चिनो लगाउन्या",
"tog-previewontop": "सम्पादन बाकस अगि पहिलाकोरूप देखाउन्या",
"tog-watchlisthideliu": "प्रवेश गरेका प्रयोगकर्ताहरूको सम्पादन ध्यान सूचीबठेई लुकाउन्या",
"tog-watchlisthideanons": "अज्ञात प्रयोगकर्ताहरूबाट गरिएको सम्पादन ध्यान सूचीबठेई लुकाउन्या",
"tog-watchlisthidepatrolled": "बोट सम्पादनहरू ध्यान सूचीबठेई लुकाउन्या",
+ "tog-watchlisthidecategorization": "पृष्ठहरुको श्रेणीकरण लुकौन्या",
"tog-ccmeonemails": "मुईले अन्य प्रयोगकर्ताहरूलाई पठाउन्या इ-मेलको प्रतिलिपि मुईलाई पठाउन्या",
"tog-diffonly": "तलका पानाहरुको भिन्नहरू सामग्री नदेखाउन्या",
"tog-showhiddencats": "लुकाइएका श्रेणीहरू धेखाउन्या",
- "tog-norollbackdiff": "पà¥\88लासà¥\8dथितिमà¥\80 फरà¥\8dà¤\95ाà¤\8fपà¤\9bि भिन्नता हटाउन्या",
+ "tog-norollbackdiff": "पà¥\88लासà¥\8dथितिमà¥\80 फरà¥\8dà¤\95ाà¤\8fपà¤\9bा भिन्नता हटाउन्या",
"tog-useeditwarning": "सम्पादनहरू सङ्ग्रह नगरिएका अवस्थामी अर्को पानामी जान खोज्या चेतावनी धेखाउन्या",
"tog-prefershttps": "प्रवेश गर्दा जबलै सुरक्षित जडानको प्रयोग गर्न्या",
"underline-always": "सधैं",
"october-date": "अक्टोबर $1",
"november-date": "नोभेम्बर $1",
"december-date": "डिसेम्बर $1",
+ "period-am": "रात १२ बज्या बठे छाकला सम्म",
+ "period-pm": "छाकला बठे रात १२ बज्या सम्म",
"pagecategories": "{{PLURAL:$1|श्रेणी|श्रेणीहरू}}",
"category_header": "\"$1\" श्रेणीमी भया लेखहरू",
"subcategories": "उपश्रेणीहरू",
"versionrequiredtext": "ये पाना प्रयोग गर्नका लागि MediaWiki $1 संस्करण चाहिन्छ ।\nहेर [[Special:Version|version page]]",
"ok": "भयो",
"retrievedfrom": " \"$1\" बठे निकालिया",
- "youhavenewmessages": "तमखी लेखा($2)मी $1 छ।",
+ "youhavenewmessages": "तमखी लेखा($3)मी $1 ($2) छ ।",
"youhavenewmessagesfromusers": "तमखी लेखा {{PLURAL:$3|प्रयोगकर्ता|$3 प्रयोगकर्तान}}($2)बठे$1",
"youhavenewmessagesmanyusers": "तमलाई धेरै प्रयोगकर्ताहरू($2) बठे $1 छ ।",
"newmessageslinkplural": "{{PLURAL:$1|एक नौलो रैबार|999=नौला रैबारहरू}}",
"nstab-template": "ढाँचा",
"nstab-help": "सहायता पानो",
"nstab-category": "श्रेणी",
+ "mainpage-nstab": "मुख्य पानो",
"nosuchaction": "यसो काम हैन",
"nosuchactiontext": "URL ले खुलाएको काम मान्य छैन ।\nतमीले URL गलत टाइपगरेका हौ , वा गलत लिंकक पछाडी लागेका हुनसक्देहौ ।\nयो {{SITENAME}}ले सफ्टवेयरमी भयाको गल्ति देखायाको लै हुनसक्छ ।",
"nosuchspecialpage": "तसो विशेष पानो छैन",
"viewsource-title": " $1 को स्रोत हेर",
"actionthrottled": "कार्य रोकिईयो",
"actionthrottledtext": "स्पामको रोकथामको लागि , तमीलाई यो कार्य नापै समयमी मैथै पटक गद्दाबठे सिमित गरियाको छ, र तमीले आफ्नो सिमा पार गरिसक्याछौ ।\nकृपया केही मिनेट पछि पुन: प्रयास गर ।",
+ "protectedpagetext": "यो पृष्ठ सम्पादन हुनबठे बचाउन सम्पादनमी तथा अन्य कार्यमी रोक लगाइया छ।",
+ "viewsourcetext": "तम ये पृष्ठको स्रोत हेद्दु सकुन्छौ और उईको नक्कल उताद्दु सकुन्छौ |",
"viewyourtext": "यै पानामी रह्याका '''तमरा सम्पादनहरू''' हेद्द या प्रतिलिपी गद्द सक्द्या हौ :",
"editinginterface": "<strong>चेतावनी:</strong> तमी यै पानालाई सम्पादन गद्द लाग्याछौ, जनले सफ्टवेयरको लागि \nइन्टरफेस सामग्रीहरू प्रदान गरन्छ।\nयै पानामी गरियाको परिवर्तनले यै विकिमी अरु प्रयोगकर्तानको इन्टरफेसको प्रदर्शनमी प्रभाव पडन्छ ।",
"namespaceprotected": "तमलाई '''$1''' नेमस्पेसमी रह्याका पानाहरू सम्पादन गद्या अनुमति छैन ।",
"customcssprotected": "तमलाई यो पानो सम्पादन गद्दे अनुमति छैन, किनकी यैमी कुनै अर्को प्रयोगकर्ताको व्यक्तिगत अभिरुचीहरू संग्रहित छन् ।",
"customjsprotected": "तमलाई यो जाभास्कृप्ट पानो सम्पादन गद्दे अनुमति छैन, किनकी यैमी कुनै अर्को प्रयोगकर्ताको व्यक्तिगत अभिरुचीहरू संग्रहित छन् ।",
+ "mycustomcssprotected": "ये CSS पृष्ठ सम्पादन गद्दका लागि तमलाइ अनुमति छैन ।",
+ "mycustomjsprotected": "ये JavaScript पृष्ठ सम्पादन गद्द लागि तमलाई अनुमति छैन।",
+ "myprivateinfoprotected": "तमसँग तमरो निजी जानकारीहरू सम्पादन ग्द्दे अनुमती छैन |",
+ "mypreferencesprotected": "तमसंग तमरो अभिरुचीहरू सम्पादन ग्द्दे अनुमती छैन |",
"ns-specialprotected": "विशेष पृष्ठहरू सम्पादन अद्दु नाइँ सकिनो।",
"titleprotected": "[[User:$1|$1]]द्वारा ये शीर्षक निर्माणहुनबठे जोगाइया छ।\nकारण <em>$2</em> हो ।",
"filereadonlyerror": "फाइल \"$1\" लाई परिवर्तन अद्दु नाइँ सकिनो क्याईकि फाइल भण्डार \"$2\" केवल पढ्ने स्थिति (read-only mode)मी छ।\n\nयेलाई सुरक्षित गर्ने प्रवन्धकले यो कारण दियाकाछन् : ''$3''।",
"virus-scanfailed": "जँचाई असफल(कोड $1)",
"virus-unknownscanner": "थानभया एन्टीभाइरस:",
"logouttext": "<strong>तमी अहिल बाहिर निस्क्याका छौ।</strong>\n\nयाद राख्या तमीले ब्राउजरको क्याच खालि नगर्यासम्म कुनै पानाहरूमी तमी अझैं प्रवेश गरिरख्याको धेकाउन सक्छ।",
+ "cannotlogoutnow-title": "अईल भाईर निकल्ल नाइँ पाईनो",
+ "cannotlogoutnow-text": "भाईर निकल्ल असंभव छ जब प्रयोग $1",
"welcomeuser": "$1स्वागत छ!",
"welcomecreation-msg": "तमरो खाता तयार भयो । \nतमले चाहेको खण्डमी {{SITENAME}} [[Special:Preferences|रोजाइहरू]] परिवर्तन गद्द सक्द्याहौ ।",
"yourname": "प्रयोगकर्ता नाम:",
"yourdomainname": "तमरो ज्ञानक्षेत्र(डोमेन):",
"password-change-forbidden": "ये विकिमी पासवर्ड परिवर्तन गर्न सक्नुहुन्न।",
"login": "प्रवेश (लगईन)",
+ "login-security": "तमरो पहिचान जाचँ गर",
"nav-login-createaccount": "प्रवेश गर्ने/नयाँ खाता बनाउन्या",
"userlogin": "प्रवेश गर्ने / नयाँ खाता बनाउन्या",
"userloginnocreate": "प्रवेश",
"nologin": "तमरो खाता छैन? $1।",
"nologinlink": "नयाँ खाता खोल",
"createaccount": "खाता खोल",
+ "gotaccount": "तमरो खाता छनोई छ? $1।",
"gotaccountlink": "प्रवेश",
"userlogin-resetlink": "प्रवेश सम्बन्धी विवरणहरू बिसरया भयो?",
"userlogin-resetpassword-link": "पासवर्ड भुलिगया?",
"createacct-reason-ph": "क्याई तम नयाँ खाता खोल्ला छौ?",
"createacct-submit": "तमरो खाता सिर्जना गर",
"createacct-another-submit": "दोसरो खाता सिर्जना गर",
+ "createacct-continue-submit": "खाता खोल्लु जारि राख",
+ "createacct-another-continue-submit": "खाता खोल्लु जारि राख",
"createacct-benefit-heading": "{{SITENAME}} तम जसाई मान्सुनले सिर्जना गरिया हो ।",
"createacct-benefit-body1": "{{PLURAL:$1|सम्पादन|सम्पादनहरू}}",
"createacct-benefit-body2": "{{PLURAL:$1|पाना|पानाहरू}}",
"loginsuccesstitle": "प्रवेश सफल",
"loginsuccess": "'''तमले {{SITENAME}}मी \"$1\" को रुपमी प्रवेश गरया छौ।'''",
"nouserspecified": "प्रयोगकर्ता नाम दिनु अनिवार्य छ।",
+ "login-userblocked": "ये प्रयोगकर्तालाई रोक लगाया छ। प्रवेश गददु अनुमति छैन।",
+ "wrongpassword": "पासवर्ड गलत हालियो।\nकृपया आजी प्रयास गरया।",
+ "wrongpasswordempty": "हालिएया पासवर्ड खालि थ्यो।\nकृपया आजी प्रयास गरया।",
+ "password-name-match": "तमरो प्रवेशशव्द प्रयोगकर्ता नाम है फरक हुनपडन्छ ।",
+ "password-login-forbidden": "ये प्रयोगकर्ता नाम र प्रवेश शव्द वर्जित गरिया छ।",
"mailmypassword": "पासवर्ड पूर्वनिर्धारित गर",
"passwordremindertitle": "{{SITENAME}}का लागि नयाँ अस्थायी पासवर्ड",
"passwordremindertext": "कसैले (सायद तमी, IP ठेगाना $1 बाट), {{SITENAME}}($4) को लागि नौलो पासवर्ड अनुरोध गर्या छ । प्रयोगकर्ता \"$2\" को लागि नौलो अस्थायी पासवर्ड \"$3\"तयार पारिया छ । यदि यो तमरो इच्छामी भयाको भया अहिले तमीले लगइन गरीबर नौलो पासवर्ड छान्नु पड्ड्या हुन्छ ।\nतमरो अस्थायी पासवर्ड {{PLURAL:$5|एक दिन|$5 दिनहरू पछि}} अमान्य हुन्याछ ।\n\nयदि कोही अरुले नै अनुरोध गर्याको हो भण्या , या तमीले आफ्नो पासवर्ड सम्झ्यौ भण्या, अथवा\nत्यैलाई परिवर्तन गर्न चाहन्नौ भण्या, तमीले यो सन्देसको वेवास्ता गद्दसक्द्याहौ र पुरानै पासवर्ड प्रयोग गरिरहन सक्द्याहौ ।",
"createacct-another-realname-tip": "वास्तविक नाम ऐच्छिक हो ।\nतमले यो खुलायौ भण्या तमरो काममी प्रयोगकर्ता श्रेय दिनका निउती यैको प्रयोग गरिन्या छ ।",
"pt-login": "प्रवेश (लग ईन)",
"pt-login-button": "प्रवेश",
+ "pt-login-continue-button": "प्रवेश जारी राख",
"pt-createaccount": "नयाँ खाता खोल",
"pt-userlogout": "बाहिर निस्कन्या (लग आउट)",
"php-mail-error-unknown": "PHP मेल() क्रियामा अज्ञात गल्ती",
"resetpass_submit": "पासवर्ड व्यवस्थित गरी र प्रवेशगर्ने",
"changepassword-success": "तमरो पासवर्ड सफलतापूर्वक परिवर्तन भयो!",
"changepassword-throttled": "तमले अलै भौत फेर प्रवेशका निम्ति प्रयास गरया छौ।\nकृपया $1 थोक्कै जागी मात्र प्रयास गर।",
+ "botpasswords": "बोट पासवर्ड",
+ "botpasswords-label-appid": "बोट नाम:",
+ "botpasswords-label-create": "सृजना गर",
+ "botpasswords-label-update": "नयाँ बनाउनु",
+ "botpasswords-label-cancel": "रद्द",
+ "botpasswords-label-delete": "मेट्न्या",
+ "botpasswords-label-resetpassword": "पासवर्ड पूर्वनिर्धारित गर",
+ "botpasswords-label-grants": "अनुदान आवेदन:",
+ "botpasswords-label-grants-column": "प्रदान भयो",
+ "botpasswords-created-title": "बोट को पासवर्ड बन्यो",
+ "botpasswords-updated-title": "बोट को पासवर्ड अपडेट भयो",
+ "botpasswords-deleted-title": "बोट को पासवर्ड मेटियो",
"resetpass_forbidden": "पासवर्ड परिवर्तन गर्न नाइँमिल्लो",
+ "resetpass_forbidden-reason": "पासवर्ड परिवर्तन गद्दु नाइँमिल्लो:$1",
"resetpass-no-info": "ये पाना सिधाई हेद्दाई तमले प्रवेश गद्दु पडून्छ ।",
"resetpass-submit-loggedin": "पासवर्ड परिवर्तन गर",
"resetpass-submit-cancel": "रद्द",
"passwordreset-emailtitle": "{{SITENAME}}मा खाता विवरण",
"passwordreset-emailelement": "प्रयोगकर्ताको नाम: \n$1\n\nअस्थाई पासवर्ड: \n$2",
"passwordreset-emailsentemail": "पासवर्ड परिवर्तनका लागि इमेल पठाइया छ।",
- "changeemail": "इमेल ठेगाना बदेल",
+ "passwordreset-invalideamil": "अबैध ई-मेल ठेगाना",
+ "changeemail": "इमेल ठेगाना बदेल वा हटा",
"changeemail-header": "आफ्नो इमेल ठेगाना परिवर्तन गद्द यो फारम भर । यैलाई पुष्टि गद्द तमीले आफ्नो पासवर्ड हाल्नु पडन्छ।",
"changeemail-oldemail": "अईलको इमेल-ठेगाना:",
"changeemail-newemail": "नयाँ इमेल-ठेगाना:",
"sig_tip": "तमरो समयछाप सहितको दस्तखत",
"hr_tip": "क्षितिजिय रेखा (कम प्रयोग गर्नुहोस्)",
"summary": "सारांश:",
- "subject": "विषय/शीर्षक:",
+ "subject": "विषय:",
"minoredit": "यो नानो सम्पादन हो",
"watchthis": "यै पानाको ध्यान राख",
"savearticle": "सङ्ग्रह गर",
+ "publishpage": "प्रकाशित पृष्ठ",
"preview": "पूर्वावलोकन",
"showpreview": "पूर्वालोकन धेकाउन्या",
"showdiff": "परिवर्तन धेकाउन्या",
"selfredirect": "<strong>चेतावनी:</strong> तम यै पानालाई आफुमी पुनः निर्देशित गद्द लाग्याछौ ।\nहुनसक्छ तम अनुप्रेषितको लागि गलत लक्ष्य निर्दिष्ट गद्द लाग्याछौ, वा गलत पानाको सम्पादन गद्द लाग्याछौ ।\nतम पुनः एकपल्ट \"{{int:savearticle}}\" क्लिक गद्दाछौ, पुनः निर्देशित तसै लै बनाइन्याछ।",
"missingcommentheader": "'''याद गर :''' तमीले टिप्पणीमी विषय /शीर्ष पंक्ति दियाका छैनौ ।\nतमीले फेरि \"{{int:savearticle}}\" थिच्यौ भण्या , तमरो सम्पादन यसै रुपमी संग्रहित हुन्याछ ।",
"summary-preview": "सारांश पूर्वालोकन:",
- "subject-preview": "विषय/शीर्षपंक्ति पूर्वरुप:",
+ "subject-preview": "विषय पूर्वरुप:",
"previewerrortext": "तमरो परिवर्तनको पूर्वावलोकन बनाउन खोज्दा समस्या आयाको छ ।",
"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 ठेगानामी रोक लगाइयाकोछ किन भण्या यो अर्को प्रयोगकर्ताले प्रयोग गर्याको थ्यो, जैलाई $1ले रोक लगायाका थ्या । \nरोक लगाउनाको कारण:\n:''$2'' \n\n* रोकावट सुरु: $8\n* रोकावट सकिन्या: $6\n* रोकावटको प्रयोजन: $7\n\nतम $1 सित सम्पर्क गर्न सकन्छौ अथवा कुनै [[{{MediaWiki:Grouppage-sysop}}|प्रबन्धक]]सँग रोकबारे चर्चा गर्न सकन्छौ ।\n\nध्यान दिया कि तमले यै प्रयोगकर्ताकी लेखा ई-मेलको प्रयोग तबसम्म गद्द नाइसक्दा जबसम्म तमरो [[Special:Preferences|रोजाई]] दर्ता गद्दाइनौ वा यो ई-मेलको प्रयोगमी रोक लगाइयाको हुँदैन । \n\nतमरो वर्तमान IP ठेगाना हो- $3, अनि रोक लगाइयाको ID हो- #$5.\nकृपया कुनै बेला सोधनी गद्दु पड्या उपर्युक्त विवरण दर्शाया ।",
"blockednoreason": "कारण दिइईया नाइँथिन",
"whitelistedittext": "पाना सम्पादन गर्न तमले $1 गद्दु पडन्छ।",
+ "nosuchsectiontitle": " खण्ड फेला नाइँपडयो",
"nosuchsectiontext": "तमले तसो खण्डको सम्पादन गद्या प्रयास गर्यौ जो अस्तित्वमी छैन।\nयैको नाम बदलियाको अथवा मेटाइयाको हुनुपडन्छ जब तमी यै पानालाई हेद्द लाग्याका छियौ ।",
"loginreqtitle": "प्रवेशगर्नु जरुरी छ।",
"loginreqlink": "प्रवेश (लग ईन)",
"accmailtitle": "पासवर्ड पठाइयो",
"newarticle": "(नयाँ)",
"newarticletext": "तमले अहिलसम्म नभयाका पानाको लिंङ्क पहिल्यायाका छौ ।\nयो पानो बनौनाखी तल्तिरको कोष्ठमी टाइप गरि । (और जाण्णाखीलेखा [$1 help page] हेर )।\nताखाइ सुधिसार आइपुग्या हौ भण्या, ब्राउजरको '''back''' बटन थिचिहाल ।",
- "anontalkpagetext": "----''यो कुरडी पानो अज्ञात प्रयोगकर्ताको हो जनले अहिलसम्म खाता बनायाकै छैन, अथवा जनले यै पानाको उपयोग गर्दैन।\nयस कारण हामीले उनलाई उनरो आइ पी (IP) ठेगानाले चिन्न सकन्छौ। \nयस्तो आइ पी (IP) ठेगाना धेरै प्रयोगकर्तानको साझा हुनसकन्छ ।\nयदि तमी अज्ञात प्रयोगकर्ता हौ र तमलाई अचाहिँदो टिप्पणी भयाको अनुभव गद्दा छौ भण्या भविष्यमी अन्य अज्ञात प्रयोगकर्तासँगको भ्रमबाट बाँच्न कृपया [[Special:UserLogin/signup|खाता खोल]] अथवा [[Special:UserLogin|प्रवेश गर]] ''",
+ "anontalkpagetext": "----''यो कुरडी पानो अज्ञात प्रयोगकर्ताको हो जनले अहिलसम्म खाता बनायाकै छैन, अथवा जनले यै पानाको उपयोग गर्दैन।\nयस कारण हामीले उनलाई उनरो आइ पी (IP) ठेगानाले चिन्न सकन्छौ। \nयस्तो आइ पी (IP) ठेगाना धेरै प्रयोगकर्तानको साझा हुनसकन्छ ।\nयदि तमी अज्ञात प्रयोगकर्ता हौ र तमलाई अचाहिँदो टिप्पणी भयाको अनुभव गद्दा छौ भण्या भविष्यमी अन्य अज्ञात प्रयोगकर्तासँगको भ्रमबाट बाँच्न कृपया [[Special:CreateAccount|खाता खोल]] अथवा [[Special:UserLogin|प्रवेश गर]] ''",
"noarticletext": "यै लेखमी अहिल क्यै पन पाठ नाइथी ।\nतमले और पृष्ठमी\n[[Special:Search/{{PAGENAME}}|यस पृष्ठको शीर्षककी लेखा खोज]] गद्द सकन्छौ ।\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} पाना सम्बन्धित ढड्डामी खोज],\nवा [{{fullurl:{{FULLPAGENAME}}|action=edit}} यै पानालाई सम्पादन गद्या]</span>.",
"noarticletext-nopermission": "यै लेखमी अहिल केइ पन पाठ नाइथी ।\nतमले और पानामी\n[[Special:Search/{{PAGENAME}}|यै पानाको शीर्षककी लेखा खोज]] गद्द सकन्छौ ।\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} पाना सम्बन्धित ढड्डामी खोज्न],\nवा [{{fullurl:{{FULLPAGENAME}}|action=edit}} यै पानालाई सम्पादन गद्द] सकन्छौ</span>.",
+ "userpage-userdoesnotexist-view": "प्रयोगकर्ता खाता \"$1\" दर्ता गरिया छैन।",
"userinvalidcssjstitle": "<strong>चेतावनी:</strong> यहाँ कोइपनि \"$1\" नामको खोल नाइथिन् ।\nप्रचलित .css तथा .js पानाहरूले निम्नपद शीर्षक प्रयोग गद्दान्, जस्तै {{ns:user}}:Foo/Vector.css को सट्टामी {{ns:user}}:Foo/vector.css",
"updated": "नौला",
"note": "'''सूचना:'''",
"template-protected": "(सुरक्षित)",
"template-semiprotected": "(अर्ध-सुरक्षित)",
"hiddencategories": "यो पानो निम्न {{PLURAL:$1|1 लुकाइयाको श्रेणी|$1 लुकाइयाका श्रेणीहरू}}को हिस्सादार(सदस्य) हो :",
+ "sectioneditnotsupported-title": "खण्ड सम्पादन असमर्थित",
+ "sectioneditnotsupported-text": "ये पृष्ठमी खण्ड सम्पादन असमर्थित",
"permissionserrors": "अधिकारमी त्रुटी",
"permissionserrorstext-withaction": "$2 कि लेखा तमलाईँ अनुमति नाइथिन , यिन {{PLURAL:$1|कारणले|कारणहरुले}} गद्दा :",
"moveddeleted-notice": "पानो मेटियाको छ।\nमेटियाका और सारियाका पानाहरूको सूची तल्तिर सन्दर्भखी लेखा दियाको छ।",
"invalid-content-data": "अमान्य सामग्री डेटा",
"content-not-allowed-here": "सामग्री \"$1\" [[$2]] पानामी राख्न अनुमती छैन ।",
"editwarning-warning": "यै पानाबठे बाहिर जाँदा तमले गर्याको कुनै पनि परिवर्तन हराउन्याछ ।\nयदि तमले लग इन गर्याको छ भण्या तमी यै सूचनालाई धेकाउन आफ्नो रोजाईहरूको \"{{int:prefs-editing}}\" भागमी गइबर बन्द गद्द सक्द्याहौ।",
+ "editpage-notsupportedcontentformat-title": "सामग्री प्रकार समर्थित नाइँथिन",
"content-model-wikitext": "विकिपाठ",
"content-model-text": "साधारण पाठ",
"content-model-javascript": "जाभास्क्रिप्ट",
"converter-manual-rule-error": "म्यानुअल भाषा अनुवाद सिध्दान्तमी समस्या धेखियो",
"cantcreateaccounttitle": "खाता बनाउन सकिएन",
"viewpagelogs": "यै पानाका लगहरू हेर",
+ "nohistory": "ये पृष्ठका लागी कोइ सम्पादन इतिहास छैन।",
"currentrev": "अहिलको पुनरावलोकन",
"currentrev-asof": "$1को रुपमी अहिलको पुनरावलोकनहरू",
"revisionasof": "$1 जस्तै गरी पुनरावलोकन",
"revdelete-submit": "{{PLURAL:$1|छानिया संशोधन|छान्निया संशोधनहरू}}मी प्रयोग गर्न्या",
"revdelete-success": "'''संशोधन दृश्यता सफलतापूर्वक अद्यतन भयो।'''",
"revdelete-failure": "'''संशोधन दृश्यता अद्यतन गर्न सकिएन:'''\n$1",
- "logdelete-success": "'''लग दृष्टि सफलतापूर्वक मिलाइयो ।'''",
+ "logdelete-success": "लग दृष्टि मिलाइयो ।",
"logdelete-failure": "'''लग दृष्टि मिलाउन सकिएन :'''\n$1",
"revdel-restore": "दृष्टि परिवर्तन गर्न्या",
"pagehist": "पाना इतिहास",
"mergehistory-submit": "पुनरावलोकहरू जोड",
"mergehistory-empty": "कोइलै पुनरावलोकनहरू जोड्ड नाइँमिल्लो ।",
"mergehistory-done": "$3 {{PLURAL:$3|संस्करण|संस्करणहरू}} $1बठे सफलतापूर्वक [[:$2]]मी थपियो ।",
+ "mergehistory-fail-bad-timestamp": "समय संख्या अस्विकार",
+ "mergehistory-fail-invalid-source": "अस्विकार स्रोत पृष्ठ",
+ "mergehistory-fail-invalid-dest": "अस्विकार लक्ष्य पृष्ठ",
+ "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": "स्रोत र गन्तव्य पाना एउटै हुनसक्दैनन्",
"prefs-rc": "नौला परिवर्तनहरू",
"prefs-watchlist": "मेरो ध्यान सूची",
"prefs-editwatchlist": "अवलोकनसूची सम्पादन",
+ "prefs-editwatchlist-raw": "कच्चा अवलोकनसूची सम्पादन गद्दा",
+ "prefs-editwatchlist-clear": "तमरो अवलोकनसूची मेटा",
"prefs-watchlist-days": "ध्यान सूचीमी धेकाउने दिनहरू:",
"prefs-watchlist-edits-max": "सबै है ज्यादा संख्या : १०००",
"prefs-watchlist-token": "अवलोकन सूची टोकन:",
"columns": "स्तम्भहरू :",
"searchresultshead": "खोज",
"stub-threshold": "<a href=\"#\" class=\"stub\">ठूटो</a> को लागि थ्रेसहोल्ड स्वरूपण (बाइट):",
+ "stub-threshold-sample-link": "उदाहरण",
"stub-threshold-disabled": "निष्क्रिय",
"recentchangesdays": "हालको परिवर्तनमी धेकाउने दिनहरू:",
"recentchangesdays-max": "अधिकतम $1 {{PLURAL:$1|दिन|दिन}}",
"timezoneregion-australia": "अष्ट्रेलिया",
"timezoneregion-indian": "हिन्द महासागर",
"prefs-files": "फाइलहरू",
+ "youremail": "ईमेल",
+ "yourrealname": "वास्तविक नाम:",
+ "yourlanguage": "भाषा",
+ "yournick": "नयाँ हस्ताक्षर:",
"prefs-help-signature": "कुरडी पानाका टिप्पणीहरू \"<nowiki>~~~~</nowiki>\" द्वारा दस्तखत गरिनुपडन्छ ,त्यो पछि तमरो दस्तखत र समयरेखामी रुपान्तरित हुनेछ ।",
"badsiglength": "तमरो दस्तखत मैथै लामो छ।\nयो $1 {{PLURAL:$1|अक्षर|अक्षरहरू}} भन्दा लामो हुनु हुँदैन ।",
+ "email": "ईमेल",
"prefs-help-realname": "वास्तविक नाम ऐच्छिक हो ।\nतमीले खुलायौ भण्या तमरो कामको श्रेय दिनको लेखा यैको प्रयोग गरिन्या छ ।",
+ "prefs-help-email-required": "इमेल ठेगाना चाहिन्छ ।",
+ "prefs-info": "साधारण जानकारी",
+ "prefs-i18n": "अन्तर्राष्ट्रियकरण",
+ "prefs-signature": "हस्ताक्षर",
+ "prefs-dateformat": "मिति ढाँचा",
+ "prefs-timeoffset": "समय अफसेट",
+ "prefs-advancedediting": "सामान्य विकल्पहरू",
+ "prefs-editor": "सम्पादक",
+ "prefs-preview": "पूर्वावलोकन",
+ "prefs-advancedrc": "उन्नत विकल्पहरू",
+ "prefs-advancedrendering": "उन्नत विकल्पहरु",
+ "prefs-advancedsearchoptions": "उन्नत विकल्पहरू",
+ "prefs-advancedwatchlist": "उन्नत विकल्पहरू",
+ "prefs-displayrc": "धेकिन्या विकल्पहरू",
+ "prefs-displaywatchlist": "धेकिन्या विकल्पहरू",
+ "prefs-tokenwatchlist": "टोकन",
+ "prefs-diffs": "फरक",
"prefs-help-prefershttps": "यो रोजाई तमरो अर्को लग इन बठे लागु हुन्याछ ।",
+ "userrights": "प्रयोगकर्ता अधिकार व्यवस्थापन",
+ "userrights-lookup-user": "प्रयोगकर्ता समूह व्यवस्थापन गर",
+ "userrights-user-editname": "प्रयोगकर्ता नाम दिय:",
+ "editusergroup": "सम्पादन{{लिंग:$1}}समूहहरु",
+ "userrights-editusergroup": "प्रयोगकर्ता समूह सम्पादन गर",
+ "saveusergroups": "सुरक्षित{{लिंग:$1}}समूहहरु",
+ "userrights-groupsmember": "को सदस्य:",
+ "userrights-groupsmember-auto": "अंतर्निहित सदस्य:",
+ "userrights-reason": "कारण:",
"userrights-unchangeable-col": "तमीले परिवर्तन गद्द नसक्ने समूहहरू",
"userrights-conflict": "प्रयोगकर्ताको अधिकार परिवर्तनमी मतभेद भयो ! कृपया तमरो परिवर्तन पुनरावलोकन तथा पुष्टि गर ।",
"userrights-removed-self": "तमीले सफलतापूर्वक आफ्नो अधिकारहरूलाई मेटायौ । त्यै कारण तमी अब यो पानो हेद्द नाइसक्दा ।",
+ "group": "समूह:",
"group-user": "प्रयोगकर्ताहरू",
"group-autoconfirmed": "स्वत स्थापित प्रयोगकर्ताहरू",
+ "group-bot": "बोटहरू",
+ "group-sysop": "प्रवन्धकहरू",
+ "group-bureaucrat": "प्रशासकहरू",
+ "group-suppress": "लुकौन्या वाला",
+ "group-all": "(सबै)",
+ "group-user-member": "{{लिङग:$1|प्रयोगकर्ता}}",
+ "group-autoconfirmed-member": "{{लिङग:$1|स्वनिर्धारित प्रयोगकर्ता}}",
+ "group-bot-member": "{{लिङग:$1|बोट}}",
+ "group-sysop-member": "{{लिङग:$1|प्रबन्धक}}",
+ "group-bureaucrat-member": "{{लिङग:$1|प्रशासक}}",
+ "group-suppress-member": "{{लिङग:$1|दबाउन्या}}",
+ "grouppage-user": "{{एनयस:आयोजना}}:प्रयोगकर्ताहरू",
+ "grouppage-autoconfirmed": "{{एनयस:आयोजना}}:स्वनिर्धारित प्रयोगकर्ताहरू",
+ "grouppage-bot": "{{एनयस:आयोजना}}:बोटहरु",
+ "grouppage-sysop": "{{एनयस:आयोजना}}:प्रबन्धकहरु",
+ "grouppage-bureaucrat": "{{एनयस:आयोजना}}:प्रशासकहरु",
+ "grouppage-suppress": "{{एनयस:आयोजना}}:लुकौन्या",
+ "right-read": "पृष्ठहरू पढ",
+ "right-edit": "पृष्ठहरू सम्पादन गर",
+ "right-createpage": "पृष्ठ निर्माण गर(छलफल पृष्ठहरू बाहेक)",
+ "right-createtalk": "छलफल पृष्ठ सृजना गर",
+ "right-createaccount": "नयाँ प्रयोगकर्ता खाता सृजना गर।",
+ "right-minoredit": "सम्पादनलाई सामान्य चिनो लगाउन्या",
+ "right-move": "पृष्ठहरू साददे",
"right-move-subpages": "तिनीहरूको उपपाना सहित पानाको नाम बदल्ने",
"right-move-rootuserpages": "मूल(root) प्रयोगकर्ताको पानाहरू साद्या",
+ "right-move-categorypages": "श्रेणी पृष्ठ सार",
"right-movefile": "फाइलहरूको नाम बदल्न्या",
+ "right-suppressredirect": "पृष्ठ सार्दा स्रोत पृष्ठबठेई पठाउने लिंक नबनाउन्या",
"right-upload": "फाइलहरू अपलोड गर्न्या",
+ "right-reupload": "रहेका फाइललाई अधिलेखन गर्न्या",
+ "right-reupload-own": "आफैले अपलोड गरया रई आया फाइल अधिलेखन गर्न्या",
"right-reupload-shared": "साझा मिडिया भण्डारमी स्थानियरुपमी फाइलहरू अधिक्रमण गर्न्या",
+ "right-upload_by_url": "URL बठे फाइल उर्ध्वभरण गर्ने",
+ "right-purge": "साइटको क्याश( cache) निश्चित नगरिकनै पर्ज(Purge) गर्ने",
"right-writeapi": "लेखन API प्रयोग गद्य्या",
"right-bigdelete": "लामो इतिहास भयाका पानाहरू मेट्ट्या",
"right-deleterevision": "खुलाइयाको पानाहरू मेटाउन्या र मेटायाको रद्द गद्या",
"noname": "Al nòm utèint scrét an n'é mìa vâlid.",
"loginsuccesstitle": "Ingrès fât.",
"loginsuccess": "''' T'é stê coleghê al terminêl {{SITENAME}} cun al nòm utèint '''$1'''.",
- "nosuchuser": "An n'é mìa registrê nisûn utèint cun al nòm \"$1\". I nòm utèin în sensébil al lètri grândi. Veréfica al nòm scrét o [[Special:UserLogin/signup|fà un nōv ingrès]].",
+ "nosuchuser": "An n'é mìa registrê nisûn utèint cun al nòm \"$1\". I nòm utèin în sensébil al lètri grândi. Veréfica al nòm scrét o [[Special:CreateAccount|fà un nōv ingrès]].",
"nosuchusershort": "An gh'é mìa registrê un utèint ciamê ''$1''. Veréfica al nòm scrét.",
"nouserspecified": "L'é necesâri precişêr un nòm utèint.",
"login-userblocked": "Cl'utèinsa ché l'é bluchêda. An n'é pusébil fêr l'ingrès.",
"accmailtext": "'Na cêva 'd ingrés l'è stêda fâta a chêş per [[User talk:$1|$1]] e l'è stêda spidîda a $2. Cla cêva 'd ingrès ché la pōl èser cambiêda int la pàgina per ''[[Special:ChangePassword|cambiêr la cêva 'd ingrès]]'' subét dôp avèir fât l'ingrès.",
"newarticle": "(Nōv)",
"newarticletext": "Al colegamèint apèina fât al cumbîna cun 'na pàgina ch' an n'é mìa incòra stêda fâta. S'ét vō fêr la pàgina adès, l'é asê cumincêr a scréver al tèst int la caşèla ché sòt (per vedèr infurmasiòun pió precîşi guêrda la [$1 pàgina 'd ajót]). Se al colegamèint l'é stê avêrt per erōr, l'é asê clichêr al pulsânt \"Indrē\" dal tó navigadōr.",
- "anontalkpagetext": "----'' Còsta l'è la pàgina 'd discusiòun ed 'n utèint sèinsa nòm, ch' an n' à mìa incòra fât 'n' utèinsa o in tót al manēri an n'è mìa drē druvêrla. Per arcgnòsrel l'è dòunca necesâri druvê al só indirés IP. J indirés IP a pōlen èser spartî cun êter utèint. Se t'è un utèint sèinsa nòm e 't pèins che i cumèint in cla pàgina ché an riguêrden mìa tè, [[Special:UserLogin/signup|fa 'n' utèinsa nōva]] o [[Special:UserLogin|vîn dèinter cun còla ch' ét gh'ê bèle]] per schivşêr, in futûr, 'd èser cunfûş cun 'd j êter utèint sèinsa nòm.''",
+ "anontalkpagetext": "----'' Còsta l'è la pàgina 'd discusiòun ed 'n utèint sèinsa nòm, ch' an n' à mìa incòra fât 'n' utèinsa o in tót al manēri an n'è mìa drē druvêrla. Per arcgnòsrel l'è dòunca necesâri druvê al só indirés IP. J indirés IP a pōlen èser spartî cun êter utèint. Se t'è un utèint sèinsa nòm e 't pèins che i cumèint in cla pàgina ché an riguêrden mìa tè, [[Special:CreateAccount|fa 'n' utèinsa nōva]] o [[Special:UserLogin|vîn dèinter cun còla ch' ét gh'ê bèle]] per schivşêr, in futûr, 'd èser cunfûş cun 'd j êter utèint sèinsa nòm.''",
"noarticletext": "In cól mumèint ché la pàgina serchêda l'é vōda. L'é pusébil [[Special:Search/{{PAGENAME}}|serchêr sté tétol]] int al j êtri pàgini dal sît, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serchêr int i regéster coleghê] opór [{{fullurl:{{FULLPAGENAME}}|action=edit}} mudifichêr la pàgina adèsa]</span>.",
"noarticletext-nopermission": "In cól mumèint ché la pàgina serchêda l'é vōda. L'é pusébil [[Special:Search/{{PAGENAME}}|serchêr sté tétol]] int al j êtri pàgini dal sît o<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serchêr int i regéster coleghê] <span>, mó an 't gh'ê mìa al permès ed fêr cla pàgina ché.",
"missing-revision": "La revişiòun #$1 'd la pagina \"{{FULLPAGENAME}}\" l' an gh'è mìa. Còst, ed sôlit, a sucēd mèint'r as va drē a 'n colegamèint a 'na pàgina scanşlêda, in 'na stòria, di lavōr fât, mìa arnuvêda. I particulêr a 's pōlen catêr int al [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} regéster dal scanşladûri].",
"Giorgos456",
"SucreRouge",
"Gts-tg",
- "Nemo bis"
+ "Nemo bis",
+ "Αντιγόνη",
+ "Matma Rex"
]
},
"tog-underline": "Υπογράμμιση συνδέσμων:",
"site-atom-feed": "$1 ροή Atom",
"page-rss-feed": "Ροή RSS «$1»",
"page-atom-feed": "Ροή Atom «$1»",
- "feed-atom": "Άτομο",
+ "feed-atom": "Atom",
"red-link-title": "$1 (η σελίδα δεν υπάρχει)",
"sort-descending": "Φθίνουσα ταξινόμηση",
"sort-ascending": "Αύξουσα ταξινόμηση",
"noname": "Το όνομα χρήστη που έχετε καθορίσει δεν είναι έγκυρο.",
"loginsuccesstitle": "Επιτυχής σύνδεση",
"loginsuccess": "Είστε συνδεδεμένος(-η) στο {{SITENAME}} ως \"$1\".",
- "nosuchuser": "Δεν υπάρχει χρήστης με το όνομα \"$1\".\nΤα ονόματα χρηστών είναι ευαίσθητα σε κεφαλαιογράμματη και μικρογράμματη γραφή.\nΕλέγξτε την ορθογραφία ή [[Special:UserLogin/signup|δημιουργήστε ένα νέο λογαριασμό]].",
+ "nosuchuser": "Δεν υπάρχει χρήστης με το όνομα \"$1\".\nΤα ονόματα χρηστών είναι ευαίσθητα σε κεφαλαιογράμματη και μικρογράμματη γραφή.\nΕλέγξτε την ορθογραφία ή [[Special:CreateAccount|δημιουργήστε ένα νέο λογαριασμό]].",
"nosuchusershort": "Δεν υπάρχει χρήστης με το όνομα \"$1\". Παρακαλούμε ελέγξτε την ορθογραφία.",
"nouserspecified": "Πρέπει να ορίσετε ένα όνομα χρήστη.",
"login-userblocked": "Αυτός ο χρήστης έχει αποκλειστεί. Δεν επιτρέπεται σύνδεση.",
"resetpass-abort-generic": "Η αλλαγή του κωδικού έχει απορριφθεί από μια προέκταση.",
"resetpass-expired": "Ο κωδικός πρόσβασης έχει λήξει. Ορίστε έναν νέο κωδικό πρόσβασης για να συνδεθείτε.",
"resetpass-expired-soft": "Ο κωδικός πρόσβασης έχει λήξει και πρέπει να γίνει επαναφορά του. Επιλέξτε έναν νέο κωδικό πρόσβασης τώρα ή πατήστε «{{int:resetpass-submit-cancel}}» για τον επαναφέρετε αργότερα.",
- "resetpass-validity-soft": "Î\9f κÏ\89δικÏ\8cÏ\82 Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82 δεν είναι ÎγκÏ\85Ï\81οÏ\82: $1\n\nÎ\95Ï\80ιλÎξÏ\84ε Îναν νÎο κÏ\89δικÏ\8c Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82 Ï\84Ï\8eÏ\81α ή πατήστε «{{int:resetpass-submit-cancel}}» για να τον επαναφέρετε αργότερα.",
+ "resetpass-validity-soft": "Î\9f κÏ\89δικÏ\8cÏ\82 Ï\80Ï\81Ï\8cÏ\83βαÏ\83ήÏ\82 Ï\83αÏ\82 δεν είναι ÎγκÏ\85Ï\81οÏ\82: $1\n\nΠαÏ\81ακαλοÏ\8dμε εÏ\80ιλÎξÏ\84ε Îναν νÎο κÏ\89δικÏ\8c Ï\80Ï\81Ï\8cÏ\83βαÏ\83ηÏ\82 Ï\84Ï\8eÏ\81α, ή πατήστε «{{int:resetpass-submit-cancel}}» για να τον επαναφέρετε αργότερα.",
"passwordreset": "Επαναφορά κωδικού",
"passwordreset-text-one": "Συμπληρώστε την παρακάτω φόρμα για να επαναφέρετε τον κωδικό πρόσβασής σας.",
"passwordreset-text-many": "{{PLURAL:$1|Συμπληρώστε ένα από τα πεδία για να λάβετε προσωρινό κωδικό πρόσβαση μέσω ηλεκτρονικού ταχυδρομείου.}}",
"accmailtext": "Ένας τυχαία παρηγμένος κωδικός για {{GENDER:$1|τον|την}} [[User talk:$1|$1]] έχει σταλεί στο $2.\n\nΜπορεί να αλλαχθεί από την σελίδα ''[[Special:ChangePassword|αλλαγή κωδικού]]'' μετά τη σύνδεση.",
"newarticle": "(Νέο)",
"newarticletext": "Ακολουθήσατε ένα σύνδεσμο προς μια σελίδα που δεν υπάρχει ακόμα. \nΓια να δημιουργήσετε τη σελίδα, αρχίστε να πληκτρολογείτε στο παρακάτω πλαίσιο (δείτε τη [$1 σελίδα βοήθειας] για περισσότερες πληροφορίες).\nΑν έχετε βρεθεί εδώ κατά λάθος, πατήστε το κουμπί '''πίσω''' στον περιηγητή σας.",
- "anontalkpagetext": "----''Αυτή η σελίδα συζήτησης προορίζεται για ανώνυμο χρήστη που δεν έχει δημιουργήσει ακόμα λογαριασμό ή που δεν τον χρησιμοποιεί. Έτσι για την ταυτοποίηση ενός ανώνυμου χρήστη χρησιμοποιείται η διεύθυνση IP του. Είναι όμως πιθανόν η διεύθυνση αυτή να είναι κοινή για πολλούς διαφορετικούς χρήστες. Αν είστε ανώνυμος χρήστης και νομίζετε ότι άσχετα σχόλια απευθύνθηκαν σε σας, παρακαλούμε να [[Special:UserLogin/signup|δημιουργήσετε ένα λογαριασμό]] ή να [[Special:UserLogin|συνδεθείτε]] για να αποφεύγεται η μελλοντική σύγχυση με άλλους ανώνυμους χρήστες.''",
+ "anontalkpagetext": "----''Αυτή η σελίδα συζήτησης προορίζεται για ανώνυμο χρήστη που δεν έχει δημιουργήσει ακόμα λογαριασμό ή που δεν τον χρησιμοποιεί. Έτσι για την ταυτοποίηση ενός ανώνυμου χρήστη χρησιμοποιείται η διεύθυνση IP του. Είναι όμως πιθανόν η διεύθυνση αυτή να είναι κοινή για πολλούς διαφορετικούς χρήστες. Αν είστε ανώνυμος χρήστης και νομίζετε ότι άσχετα σχόλια απευθύνθηκαν σε σας, παρακαλούμε να [[Special:CreateAccount|δημιουργήσετε ένα λογαριασμό]] ή να [[Special:UserLogin|συνδεθείτε]] για να αποφεύγεται η μελλοντική σύγχυση με άλλους ανώνυμους χρήστες.''",
"noarticletext": "Δεν υπάρχει προς το παρόν κείμενο σε αυτή τη σελίδα. \nΜπορείτε να [[Special:Search/{{PAGENAME}}|αναζητήσετε αυτόν τον τίτλο σελίδας]] σε άλλες σελίδες,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} να αναζητήσετε τις σχετικές καταγραφές],\nή να [{{fullurl:{{FULLPAGENAME}}|action=edit}} δημιουργήσετε αυτή τη σελίδα]</span>.",
"noarticletext-nopermission": "Δεν υπάρχει προς το παρόν κείμενο σε αυτή τη σελίδα.\nΜπορείτε να [[Special:Search/{{PAGENAME}}|αναζητήσετε αυτόν τον τίτλο σελίδας]] σε άλλες σελίδες, ή <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} να ψάξετε στις σχετικές καταγραφές]</span>, αλλά δεν έχετε την άδεια να δημιουργήσετε αυτή τη σελίδα.",
"missing-revision": "Δεν υπάρχει αναθεώρηση με αριθμό $1 για τη σελίδα με όνομα «{{FULLPAGENAME}}».\n\nΑυτό συνήθως προκαλείται από παλιό σύνδεσμο ιστορικού προς σελίδα που έχει διαγραφεί.\nΛεπτομέρειες θα βρείτε στο [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ημερολόγιο καταγραφής διαγραφών].",
"upload-form-label-own-work": "Αυτό είναι το δικό μου έργο",
"upload-form-label-infoform-categories": "Κατηγορίες",
"upload-form-label-infoform-date": "Ημερομηνία",
- "upload-form-label-own-work-message-local": "Επιβεβαιώνω ότι επιφορτώνω αυτό το αρχείο κατά τους όρους της υπηρεσίας και πολιτικές αδειοδότησης για τον ιστότοπο {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Εάν δεν είστε σε θέση να ανεβάσετε αυτό το αρχείο στο πλαίσιο των πολιτικών της {{SITENAME}}, παρακαλώ κλείστε αυτό το παράθυρο διαλόγου και να επιχειρήσετε μια άλλη μέθοδος.",
- "upload-form-label-not-own-work-local-local": "Επίσης, μπορεί να θέλετε να δοκιμάσετε [[Special:Upload|την προεπιλεγμένη σελίδα επιφόρτωσης]].",
- "upload-form-label-own-work-message-default": "Καταλαβαίνω ότι είμαι φόρτωμα αυτό το αρχείο σε ένα κοινόχρηστο αρχείο. Επιβεβαιώνω ότι είμαι τόσο ακόλουθες τους όρους της υπηρεσίας και πολιτικές αδειοδότησης.",
- "upload-form-label-not-own-work-message-default": "Εάν δεν είστε σε θέση να ανεβάσετε αυτό το αρχείο στο πλαίσιο των πολιτικών της shared repository, παρακαλώ κλείστε αυτό το παράθυρο διαλόγου και να επιχειρήσετε μια άλλη μέθοδος.",
- "upload-form-label-not-own-work-local-default": "Επίσης, μπορεί να θέλετε να δοκιμάσετε χρησιμοποιώντας το [[Special:Upload|τη σελίδα ανεβάσματος για το {{SITENAME}}]], αν αυτό το αρχείο μπορεί να φορτωθεί κάτω σύμφωνα με τις πολιτικές τους.",
- "upload-form-label-own-work-message-shared": "Δηλώνω ότι κατέχω τα πνευματικά δικαιώματα για αυτό το αρχείο, και συμφωνώ αμετάκλητα στην απελευθέρωση αυτού του αρχείου στο Wikimedia Commons με άδεια [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], και συμφωνώ με την [https://wikimediafoundation.org/wiki/Terms_of_Use Όρους Χρήσης].",
- "upload-form-label-not-own-work-message-shared": "Αν δεν κατέχει τα πνευματικά δικαιώματα για αυτό το αρχείο, ή επιθυμείτε να το δημοσιεύσετε υπό μια διαφορετική άδεια χρήσης, μπορείτε να χρησιμοποιήσετε τον [https://commons.wikimedia.org/wiki/Special:UploadWizard Οδηγό Ανεβάσματος των Wikimedia Commons].",
- "upload-form-label-not-own-work-local-shared": "Επίσης, μπορεί να θέλετε να δοκιμάσετε να χρησιμοποιήσετε το [[Special:Upload|τη σελίδα ανεβάσματος για το {{SITENAME}}]], αν αυτό το αρχείο μπορεί να φορτωθεί σύμφωνα με τις πολιτικές τους.",
+ "upload-form-label-own-work-message-generic-local": "Επιβεβαιώνω ότι επιφορτώνω αυτό το αρχείο κατά τους όρους της υπηρεσίας και πολιτικές αδειοδότησης για τον ιστότοπο {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Εάν δεν είστε σε θέση να ανεβάσετε αυτό το αρχείο στο πλαίσιο των πολιτικών της {{SITENAME}}, παρακαλώ κλείστε αυτό το παράθυρο διαλόγου και να επιχειρήσετε μια άλλη μέθοδος.",
+ "upload-form-label-not-own-work-local-generic-local": "Επίσης, μπορεί να θέλετε να δοκιμάσετε [[Special:Upload|την προεπιλεγμένη σελίδα επιφόρτωσης]].",
+ "upload-form-label-own-work-message-generic-foreign": "Καταλαβαίνω ότι είμαι φόρτωμα αυτό το αρχείο σε ένα κοινόχρηστο αρχείο. Επιβεβαιώνω ότι είμαι τόσο ακόλουθες τους όρους της υπηρεσίας και πολιτικές αδειοδότησης.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Εάν δεν είστε σε θέση να ανεβάσετε αυτό το αρχείο στο πλαίσιο των πολιτικών της shared repository, παρακαλώ κλείστε αυτό το παράθυρο διαλόγου και να επιχειρήσετε μια άλλη μέθοδος.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Επίσης, μπορεί να θέλετε να δοκιμάσετε χρησιμοποιώντας το [[Special:Upload|τη σελίδα ανεβάσματος για το {{SITENAME}}]], αν αυτό το αρχείο μπορεί να φορτωθεί κάτω σύμφωνα με τις πολιτικές τους.",
"backend-fail-stream": "Αδύνατη η μετάδοση του αρχείου $1.",
"backend-fail-backup": "Αδύνατη η δημιουργία αντίγραφου ασφαλείας του αρχείου $1.",
"backend-fail-notexists": "Το αρχείο $1 δεν υπάρχει.",
"wantedtemplates": "Ζητούμενα πρότυπα",
"mostlinked": "Σελίδες με τους περισσότερους συνδέσμους προς αυτές",
"mostlinkedcategories": "Κατηγορίες με τους περισσότερους συνδέσμους προς αυτές",
- "mostlinkedtemplates": "ΣελίδεÏ\82 Ï\80οÏ\85 ÎÏ\87οÏ\85ν ενÏ\83Ï\89μαÏ\84Ï\89θεί Ï\80εÏ\81ιÏ\83Ï\83Ï\8cÏ\84εÏ\81ο αÏ\80Ï\8c Ï\8cλεÏ\82 Ï\84ιÏ\82 άλλες",
+ "mostlinkedtemplates": "ΠεÏ\81ιÏ\83Ï\83Ï\8cÏ\84εÏ\81ο ενÏ\83Ï\89μαÏ\84Ï\89μÎνεÏ\82 Ï\83ελίδες",
"mostcategories": "Σελίδες με τις περισσότερες κατηγορίες",
"mostimages": "Αρχεία με τους περισσότερους συνδέσμους προς αυτά",
"mostinterwikis": "Σελίδες με τους περισσότερους διαγλωσσικούς συνδέσμους",
"apisandbox-dynamic-parameters-add-placeholder": "Ονομασία παραμέτρου",
"apisandbox-dynamic-error-exists": "Η παράμετρος με την ονομασία \"$1\" υπάρχει ήδη",
"apisandbox-submit-invalid-fields-title": "Κάποια από τα πεδία δεν είναι έγκυρα",
- "apisandbox-submit-invalid-fields-message": "ΠαÏ\81ακαλÏ\8e διοÏ\81θÏ\8eÏ\83Ï\84ε Ï\84α Ï\83ημειÏ\89μÎνα Ï\80εδία και Ï\80Ï\81οÏ\83Ï\80αθείστε ξανά.",
+ "apisandbox-submit-invalid-fields-message": "ΠαÏ\81ακαλÏ\8e διοÏ\81θÏ\8eÏ\83Ï\84ε Ï\84α Ï\83ημειÏ\89μÎνα Ï\80εδία και Ï\80Ï\81οÏ\83Ï\80αθήστε ξανά.",
"apisandbox-results": "Αποτελέσματα",
"apisandbox-sending-request": "Αποστολή αιτήματος API...",
"apisandbox-loading-results": "Λήψη αποτελεσμάτων API...",
"timezone-local": "Τοπικό",
"duplicate-defaultsort": "'''Προειδοποίηση:''' Το προεπιλεγμένο κλειδί ταξινόμησης «$2» υπερισχύει του προηγούμενου προεπιλεγμένου κλειδιού «$1».",
"duplicate-displaytitle": "<strong>Προειδοποίηση:</strong> Ο εμφανιζόμενος τίτλος «$2» παρακάμπτει τον προηγούμενο «$1».",
+ "restricted-displaytitle": "<strong>Προειδοποίηση:</strong> Η εμφάνιση τίτλου \"$1\" αγνοήθηκε καθώς δεν είναι αντίστοιχη με τον πραγματικό τίτλο της σελίδας.",
"invalid-indicator-name": "<strong>Σφάλμα:</strong> Η ιδιότητα <code>name</code> των δεικτών κατάστασης σελίδων δεν πρέπει να είναι κενή.",
"version": "Έκδοση",
"version-extensions": "Εγκαταστημένες επεκτάσεις",
"logentry-protect-protect": "$1 {{GENDER:$2|προστατευμένος|προστατευμένη}} $3 $4",
"logentry-protect-modify": "$1 {{GENDER:$2|άλλαξε}} επίπεδο προστασίας για $3 $4",
"logentry-protect-modify-cascade": "$1 {{GENDER:$2|άλλαξε}} επίπεδο προστασίας για $3 $4 [διαδοχική]",
- "logentry-rights-rights": "{{GENDER:$2|Ο|Η}} $1 άλλαξε την ιδιότητα μέλους ομάδας για {{GENDER:$3|τον|την}} $3 από $4 σε $5",
+ "logentry-rights-rights": "{{GENDER:$2|Ο|Η}} $1 άλλαξε την ιδιότητα μέλους ομάδας για {{GENDER:$6|τον|την}} $3 από $4 σε $5",
"logentry-rights-rights-legacy": "{{GENDER:$2|Ο|Η}} $1 άλλαξε την ιδιότητα μέλους ομάδας {{GENDER:$1|του|της}} $3",
"logentry-rights-autopromote": "$1 {{GENDER:$2|προωθήθηκε}} αυτόματα από το $4 στο $5",
"logentry-upload-upload": "{{GENDER:$2|Ο|Η}} $1 ανέβασε το $3",
"password-change-forbidden": "You cannot change passwords on this wiki.",
"externaldberror": "There was either an authentication database error or you are not allowed to update your external account.",
"login": "Log in",
+ "login-security": "Verify your identity",
"nav-login-createaccount": "Log in / create account",
"loginprompt": "",
"userlogin": "Log in / create account",
"helplogin-url": "https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Logging_in",
"userlogin-helplink2": "Help with logging in",
"userlogin-loggedin": "You are already logged in as {{GENDER:$1|$1}}.\nUse the form below to log in as another user.",
+ "userlogin-reauth": "You must log in again to verify that you are {{GENDER:$1|$1}}.",
"userlogin-createanother": "Create another account",
"createacct-emailrequired": "Email address",
"createacct-emailoptional": "Email address (optional)",
"createacct-email-ph": "Enter your email address",
"createacct-another-email-ph": "Enter email address",
"createaccountmail": "Use a temporary random password and send it to the specified email address",
+ "createaccountmail-help": "Can be used to create account for another person without learning the password.",
"createacct-realname": "Real name (optional)",
"createaccountreason": "Reason:",
"createacct-reason": "Reason",
"createacct-reason-ph": "Why you are creating another account",
+ "createacct-reason-help": "Message shown in the account creation log",
"createacct-imgcaptcha-help": "",
"createacct-submit": "Create your account",
"createacct-another-submit": "Create account",
+ "createacct-continue-submit": "Continue account creation",
+ "createacct-another-continue-submit": "Continue account creation",
"createacct-benefit-heading": "{{SITENAME}} is made by people like you.",
"createacct-benefit-icon1": "icon-edits",
"createacct-benefit-head1": "{{NUMBEROFEDITS}}",
"nocookieslogin": "{{SITENAME}} uses cookies to log in users.\nYou have cookies disabled.\nPlease enable them and try again.",
"nocookiesfornew": "The user account was not created, as we could not confirm its source.\nEnsure you have cookies enabled, reload this page and try again.",
"nocookiesforlogin": "{{int:nocookieslogin}}",
+ "createacct-loginerror": "The account was successfully created but you could not be logged in automatically. Please proceed to [[Special:UserLogin|manual login]].",
"noname": "You have not specified a valid username.",
"loginsuccesstitle": "Logged in",
"loginsuccess": "<strong>You are now logged in to {{SITENAME}} as \"$1\".</strong>",
- "nosuchuser": "There is no user by the name \"$1\".\nUsernames are case sensitive.\nCheck your spelling, or [[Special:UserLogin/signup|create a new account]].",
+ "nosuchuser": "There is no user by the name \"$1\".\nUsernames are case sensitive.\nCheck your spelling, or [[Special:CreateAccount|create a new account]].",
"nosuchusershort": "There is no user by the name \"$1\".\nCheck your spelling.",
"nouserspecified": "You have to specify a username.",
"login-userblocked": "This user is blocked. Login not allowed.",
"createacct-another-realname-tip": "Real name is optional.\nIf you choose to provide it, this will be used for giving the user attribution for their work.",
"pt-login": "Log in",
"pt-login-button": "Log in",
+ "pt-login-continue-button": "Continue login",
"pt-createaccount": "Create account",
"pt-userlogout": "Log out",
"pear-mail-error": "$1",
"botpasswords-invalid-name": "The username specified does not contain the bot password separator (\"$1\").",
"botpasswords-not-exist": "User \"$1\" does not have a bot password named \"$2\".",
"resetpass_forbidden": "Passwords cannot be changed",
+ "resetpass_forbidden-reason": "Passwords cannot be changed: $1",
"resetpass-no-info": "You must be logged in to access this page directly.",
"resetpass-submit-loggedin": "Change password",
"resetpass-submit-cancel": "Cancel",
"passwordreset-emailsentusername": "If there is an email address associated with this username, then a password reset email will be sent.",
"passwordreset-emailsent-capture": "A password reset email has been sent, which is shown below.",
"passwordreset-emailerror-capture": "A password reset email was generated, which is shown below, but sending it to the {{GENDER:$2|user}} failed: $1",
+ "passwordreset-emailsent-capture2": "The password reset {{PLURAL:$1|email has|emails have}} been sent. The {{PLURAL:$1|username and password|list of usernames and passwords}} is shown below.",
+ "passwordreset-emailerror-capture2": "Emailing the {{GENDER:$2|user}} failed: $1 The {{PLURAL:$3|username and password|list of usernames and passwords}} is shown below.",
+ "passwordreset-nocaller": "A caller must be provided",
+ "passwordreset-nosuchcaller": "Caller does not exist: $1",
+ "passwordreset-ignored": "The password reset was not handled. Maybe no provider was configured?",
+ "passwordreset-invalideamil": "Invalid email address",
+ "passwordreset-nodata": "Neither a username nor an email address was supplied",
"changeemail": "Change or remove email address",
"changeemail-summary": "",
"changeemail-header": "Complete this form to change your email address. If you would like to remove the association of any email address from your account, leave the new email address blank when submitting the form.",
"image_tip": "Embedded file",
"media_sample": "Example.ogg",
"media_tip": "File link",
+ "sig-text": "--$1",
"sig_tip": "Your signature with timestamp",
"hr_tip": "Horizontal line (use sparingly)",
"summary": "Summary:",
"newarticletext": "You have followed a link to a page that does not exist yet.\nTo create the page, start typing in the box below (see the [$1 help page] for more info).\nIf you are here by mistake, click your browser's <strong>back</strong> button.",
"newarticletextanon": "{{int:newarticletext|$1}}",
"talkpagetext": "<!-- MediaWiki:talkpagetext -->",
- "anontalkpagetext": "----\n<em>This is the discussion page for an anonymous user who has not created an account yet, or who does not use it.</em>\nWe therefore have to use the numerical IP address to identify him/her.\nSuch an IP address can be shared by several users.\nIf you are an anonymous user and feel that irrelevant comments have been directed at you, please [[Special:UserLogin/signup|create an account]] or [[Special:UserLogin|log in]] to avoid future confusion with other anonymous users.",
+ "anontalkpagetext": "----\n<em>This is the discussion page for an anonymous user who has not created an account yet, or who does not use it.</em>\nWe therefore have to use the numerical IP address to identify him/her.\nSuch an IP address can be shared by several users.\nIf you are an anonymous user and feel that irrelevant comments have been directed at you, please [[Special:CreateAccount|create an account]] or [[Special:UserLogin|log in]] to avoid future confusion with other anonymous users.",
"noarticletext": "There is currently no text in this page.\nYou can [[Special:Search/{{PAGENAME}}|search for this page title]] in other pages,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs],\nor [{{fullurl:{{FULLPAGENAME}}|action=edit}} create this page]</span>.",
"noarticletext-nopermission": "There is currently no text in this page.\nYou can [[Special:Search/{{PAGENAME}}|search for this page title]] in other pages, or <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs]</span>, but you do not have permission to create this page.",
"noarticletextanon": "{{int:noarticletext}}",
"right-override-export-depth": "Export pages including linked pages up to a depth of 5",
"right-sendemail": "Send email to other users",
"right-passwordreset": "View password reset emails",
- "right-managechangetags": "Create and delete [[Special:Tags|tags]] from the database",
+ "right-managechangetags": "Create and (de)activate [[Special:Tags|tags]]",
"right-applychangetags": "Apply [[Special:Tags|tags]] along with one's changes",
"right-changetags": "Add and remove arbitrary [[Special:Tags|tags]] on individual revisions and log entries",
+ "right-deletechangetags": "Delete [[Special:Tags|tags]] from the database",
"grant-generic": "\"$1\" rights bundle",
"grant-group-page-interaction": "Interact with pages",
"grant-group-file-interaction": "Interact with media",
"action-viewmyprivateinfo": "view your private information",
"action-editmyprivateinfo": "edit your private information",
"action-editcontentmodel": "edit the content model of a page",
- "action-managechangetags": "create and delete tags from the database",
+ "action-managechangetags": "create and (de)activate tags",
"action-applychangetags": "apply tags along with your changes",
"action-changetags": "add and remove arbitrary tags on individual revisions and log entries",
+ "action-deletechangetags": "delete tags from the database",
"nchanges": "$1 {{PLURAL:$1|change|changes}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|since last visit}}",
"enhancedrc-history": "history",
"upload-form-label-own-work": "This is my own work",
"upload-form-label-infoform-categories": "Categories",
"upload-form-label-infoform-date": "Date",
- "upload-form-label-own-work-message-local": "I confirm that I am uploading this file following the terms of service and licensing policies on {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "If you are not able to upload this file under the policies of {{SITENAME}}, please close this dialog and try another method.",
- "upload-form-label-not-own-work-local-local": "You may also want to try [[Special:Upload|the default upload page]].",
- "upload-form-label-own-work-message-default": "I understand that I am uploading this file to a shared repository. I confirm that I am doing so following the terms of service and licensing policies there.",
- "upload-form-label-not-own-work-message-default": "If you are not able to upload this file under the policies of the shared repository, please close this dialog and try another method.",
- "upload-form-label-not-own-work-local-default": "You may also want to try using [[Special:Upload|the upload page on {{SITENAME}}]], if this file can be uploaded there under their policies.",
- "upload-form-label-own-work-message-shared": "I attest that I own the copyright on this file, and agree to irrevocably release this file to Wikimedia Commons under the [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] license, and I agree to the [https://wikimediafoundation.org/wiki/Terms_of_Use Terms of Use].",
- "upload-form-label-not-own-work-message-shared": "If you do not own the copyright on this file, or you wish to release it under a different license, consider using the [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons Upload Wizard].",
- "upload-form-label-not-own-work-local-shared": "You may also want to try using [[Special:Upload|the upload page on {{SITENAME}}]], if the site allows the upload of this file under their policies.",
+ "upload-form-label-own-work-message-generic-local": "I confirm that I am uploading this file following the terms of service and licensing policies on {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "If you are not able to upload this file under the policies of {{SITENAME}}, please close this dialog and try another method.",
+ "upload-form-label-not-own-work-local-generic-local": "You may also want to try [[Special:Upload|the default upload page]].",
+ "upload-form-label-own-work-message-generic-foreign": "I understand that I am uploading this file to a shared repository. I confirm that I am doing so following the terms of service and licensing policies there.",
+ "upload-form-label-not-own-work-message-generic-foreign": "If you are not able to upload this file under the policies of the shared repository, please close this dialog and try another method.",
+ "upload-form-label-not-own-work-local-generic-foreign": "You may also want to try using [[Special:Upload|the upload page on {{SITENAME}}]], if this file can be uploaded there under their policies.",
"backend-fail-stream": "Could not stream file \"$1\".",
"backend-fail-backup": "Could not backup file \"$1\".",
"backend-fail-notexists": "The file $1 does not exist.",
"trackingcategories-msg": "Tracking category",
"trackingcategories-name": "Message name",
"trackingcategories-desc": "Category inclusion criteria",
+ "restricted-displaytitle-ignored": "Pages with ignored display titles",
+ "restricted-displaytitle-ignored-desc": "The page has an ignored <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> because it is not equivalent to the page's actual title.",
"noindex-category-desc": "The page is not indexed by robots because it has the magic word <code><nowiki>__NOINDEX__</nowiki></code> on it and is in a namespace where that flag is allowed.",
"index-category-desc": "The page has a <code><nowiki>__INDEX__</nowiki></code> on it (and is in a namespace where that flag is allowed), and hence is indexed by robots where it normally wouldn't be.",
"post-expand-template-inclusion-category-desc": "The page size is bigger than <code>$wgMaxArticleSize</code> after expanding all the templates, so some templates were not expanded.",
"rollbacklinkcount": "rollback $1 {{PLURAL:$1|edit|edits}}",
"rollbacklinkcount-morethan": "rollback more than $1 {{PLURAL:$1|edit|edits}}",
"rollbackfailed": "Rollback failed",
+ "rollback-missingparam": "Missing required parameters on request.",
"cantrollback": "Cannot revert edit;\nlast contributor is only author of this page.",
"alreadyrolled": "Cannot rollback last edit of [[:$1]] by [[User:$2|$2]] ([[User talk:$2|talk]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nsomeone else has edited or rolled back the page already.\n\nThe last edit to the page was by [[User:$3|$3]] ([[User talk:$3|talk]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "The edit summary was: <em>$1</em>.",
"revertpage": "Reverted edits by [[Special:Contributions/$2|$2]] ([[User talk:$2|talk]]) to last revision by [[User:$1|$1]]",
"revertpage-nouser": "Reverted edits by a hidden user to last revision by {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Reverted edits by $1;\nchanged back to last revision by $2.",
+ "rollback-success-notify": "Reverted edits by $1;\nchanged back to last revision by $2. [$3 Show changes]",
"sessionfailure-title": "Session failure",
"sessionfailure": "There seems to be a problem with your login session;\nthis action has been canceled as a precaution against session hijacking.\nGo back to the previous page, reload that page and then try again.",
"changecontentmodel" : "Change content model of a page",
"lockdbsuccesstext": "The database has been locked.<br />\nRemember to [[Special:UnlockDB|remove the lock]] after your maintenance is complete.",
"unlockdbsuccesstext": "The database has been unlocked.",
"lockfilenotwritable": "The database lock file is not writable.\nTo lock or unlock the database, this needs to be writable by the web server.",
+ "databaselocked": "The database is already locked.",
"databasenotlocked": "The database is not locked.",
"lockedbyandtime": "(by {{GENDER:$1|$1}} on $2 at $3)",
"move-page": "Move $1",
"confirm-watch-top": "Add this page to your watchlist?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Remove this page from your watchlist?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Revert edits to this page?",
"semicolon-separator": "; ",
"comma-separator": ", ",
"colon-separator": ": ",
"timezone-local": "Local",
"duplicate-defaultsort": "<strong>Warning:</strong> Default sort key \"$2\" overrides earlier default sort key \"$1\".",
"duplicate-displaytitle": "<strong>Warning:</strong> Display title \"$2\" overrides earlier display title \"$1\".",
+ "restricted-displaytitle": "<strong>Warning:</strong> Display title \"$1\" was ignored since it is not equivalent to the page's actual title.",
"invalid-indicator-name": "<strong>Error:</strong> Page status indicators' <code>name</code> attribute must not be empty.",
"version": "Version",
"version-summary": "",
"tags-delete-not-found": "The tag \"$1\" does not exist.",
"tags-delete-too-many-uses": "The tag \"$1\" is applied to more than $2 {{PLURAL:$2|revision|revisions}}, which means it cannot be deleted.",
"tags-delete-warnings-after-delete": "The tag \"$1\" was deleted, but the following {{PLURAL:$2|warning was|warnings were}} encountered:",
+ "tags-delete-no-permission": "You do not have permission to delete change tags.",
"tags-activate-title": "Activate tag",
"tags-activate-question": "You are about to activate the tag \"$1\".",
"tags-activate-reason": "Reason:",
"log-action-filter-suppress-block": "User supppression by block",
"log-action-filter-suppress-reblock": "User suppression by reblock",
"log-action-filter-upload-upload": "New upload",
- "log-action-filter-upload-overwrite": "Reupload"
+ "log-action-filter-upload-overwrite": "Reupload",
+ "authmanager-authn-not-in-progress": "Authentication is not in progress or session data has been lost. Please start again from the beginning.",
+ "authmanager-authn-no-primary": "The supplied credentials could not be authenticated.",
+ "authmanager-authn-no-local-user": "The supplied credentials are not associated with any user on this wiki.",
+ "authmanager-authn-no-local-user-link": "The supplied credentials are valid but are not associated with any user on this wiki. Login in a different way, or create a new user, and you will have an option to link your previous credentials to that account.",
+ "authmanager-authn-autocreate-failed": "Auto-creation of a local account failed: $1",
+ "authmanager-change-not-supported": "The supplied credentials cannot be changed, as nothing would use them.",
+ "authmanager-create-disabled": "Account creation is disabled.",
+ "authmanager-create-from-login": "To create your account, please fill in the fields below.",
+ "authmanager-create-not-in-progress": "Account creation is not in progress or session data has been lost. Please start again from the beginning.",
+ "authmanager-create-no-primary": "The supplied credentials could not be used for account creation.",
+ "authmanager-link-no-primary": "The supplied credentials could not be used for account linking.",
+ "authmanager-link-not-in-progress": "Account linking is not in progress or session data has been lost. Please start again from the beginning.",
+ "authmanager-authplugin-setpass-failed-title": "Password change failed",
+ "authmanager-authplugin-setpass-failed-message": "The authentication plugin denied the password change.",
+ "authmanager-authplugin-create-fail": "The authentication plugin denied the account creation.",
+ "authmanager-authplugin-setpass-denied": "The authentication plugin does not allow changing passwords.",
+ "authmanager-authplugin-setpass-bad-domain": "Invalid domain.",
+ "authmanager-autocreate-noperm": "Automatic account creation is not allowed.",
+ "authmanager-autocreate-exception": "Automatic account creation temporarily disabled due to prior errors.",
+ "authmanager-userdoesnotexist": "User account \"$1\" is not registered.",
+ "authmanager-userlogin-remembermypassword-help": "Whether the password should be remembered for longer than the length of the session.",
+ "authmanager-username-help": "Username for authentication.",
+ "authmanager-password-help": "Password for authentication.",
+ "authmanager-domain-help": "Domain for external authentication.",
+ "authmanager-retype-help": "Password again to confirm.",
+ "authmanager-email-label": "Email",
+ "authmanager-email-help": "Email address",
+ "authmanager-realname-label": "Real name",
+ "authmanager-realname-help": "Real name of the user",
+ "authmanager-provider-password": "Password-based authentication",
+ "authmanager-provider-password-domain": "Password- and domain-based authentication",
+ "authmanager-account-password-domain": "$1@$2",
+ "authmanager-provider-temporarypassword": "Temporary password",
+ "authprovider-confirmlink-message": "Based on your recent login attempts, the following accounts can be linked to your wiki account. Linking them enables logging in via those accounts. Please select which ones should be linked.",
+ "authprovider-confirmlink-option": "$1 ($2)",
+ "authprovider-confirmlink-request-label": "Accounts which should be linked",
+ "authprovider-confirmlink-request-help": "",
+ "authprovider-confirmlink-success-line": "$1: Linked successfully.",
+ "authprovider-confirmlink-failed-line": "$1: $2",
+ "authprovider-confirmlink-failed": "Account linking did not fully succeed: $1",
+ "authprovider-confirmlink-ok-help": "Continue after displaying linking failure messages.",
+ "authprovider-resetpass-skip-label": "Skip",
+ "authprovider-resetpass-skip-help": "Skip resetting the password.",
+ "authform-nosession-login": "The authentication was successful, but your browser cannot \"remember\" being logged in.\n\n$1",
+ "authform-nosession-signup": "The account was created, but your browser cannot \"remember\" being logged in.\n\n$1",
+ "authform-newtoken": "Missing token. $1",
+ "authform-notoken": "Missing token",
+ "authform-wrongtoken": "Wrong token",
+ "specialpage-securitylevel-not-allowed-title": "Not allowed",
+ "specialpage-securitylevel-not-allowed": "Sorry, you are not allowed to use this page because your identity could not be verified.",
+ "authpage-cannot-login": "Unable to start login.",
+ "authpage-cannot-login-continue": "Unable to continue login. Your session most likely timed out.",
+ "authpage-cannot-create": "Unable to start account creation.",
+ "authpage-cannot-create-continue": "Unable to continue account creation. Your session most likely timed out.",
+ "authpage-cannot-link": "Unable to start account linking.",
+ "authpage-cannot-link-continue": "Unable to continue account linking. Your session most likely timed out.",
+ "cannotauth-not-allowed-title": "Permission denied",
+ "cannotauth-not-allowed": "You are not allowed to use this page",
+ "changecredentials" : "Change credentials",
+ "changecredentials-submit": "Change credentials",
+ "changecredentials-invalidsubpage": "$1 is not a valid credential type.",
+ "changecredentials-success": "Your credentials have been changed.",
+ "removecredentials" : "Remove credentials",
+ "removecredentials-submit": "Remove credentials",
+ "removecredentials-invalidsubpage": "$1 is not a valid credential type.",
+ "removecredentials-success": "Your credentials have been removed.",
+ "credentialsform-provider": "Credentials type:",
+ "credentialsform-account": "Account name:",
+ "cannotlink-no-provider-title": "There are no linkable accounts",
+ "cannotlink-no-provider": "There are no linkable accounts.",
+ "linkaccounts": "Link accounts",
+ "linkaccounts-success-text": "The account was linked.",
+ "linkaccounts-submit": "Link accounts",
+ "unlinkaccounts": "Unlink accounts",
+ "unlinkaccounts-success": "The account was unlinked."
}
"tog-ccmeonemails": "Sendi al mi kopiojn de retpoŝtaĵoj, kiujn mi sendis al aliaj uzantoj.",
"tog-diffonly": "Ne montri paĝan enhavon sub la ŝanĝmontrilo",
"tog-showhiddencats": "Montri kaŝitajn kategoriojn",
- "tog-norollbackdiff": "Preterlasi ŝanĝoelmontron post malfaro",
+ "tog-norollbackdiff": "Nemontri diferencon post plenumado de ŝanĝomalfaro",
"tog-useeditwarning": "Averti min kiam mi forlasas redaktan paĝon kun nekonservitaj ŝanĝoj",
"tog-prefershttps": "Ĉiam uzu sekuran konekton ensalutite",
"underline-always": "Ĉiam",
"talk": "Diskuto",
"views": "Vidoj",
"toolbox": "Iloj",
- "userpage": "Vidi uzantan paĝon",
+ "userpage": "Vidi uzulan paĝon",
"projectpage": "Rigardi projektopaĝon",
"imagepage": "Vidi dosieropaĝon",
"mediawikipage": "Vidi mesaĝopaĝon",
"missingarticle-rev": "(versio#: $1)",
"missingarticle-diff": "(Diferenco inter versioj: $1, $2)",
"readonly_lag": "La datumbazo estis aŭtomate ŝlosita dum la subdatumbazo atingas la ĉefan datumbazon.",
+ "nonwrite-api-promise-error": "La 'Promeso-Ne-Skribi-API-Ago' HTTPa titolo estis sendita sed la peto estis al API skriba modulo.",
"internalerror": "Interna eraro",
"internalerror_info": "Interna eraro: $1",
"internalerror-fatal-exception": "Neriparebla escepto de la tipo \"$1\"",
"password-change-forbidden": "Ve ne povas ŝanĝi pasvortojn en ĉi tiu vikio.",
"externaldberror": "Aŭ estis datenbaza eraro rilate al ekstera aŭtentikigado, aŭ vi ne rajtas ĝisdatigi vian eksteran konton.",
"login": "Ensaluti",
+ "login-security": "Kontrolu vian identecon",
"nav-login-createaccount": "Ensaluti / Krei novan konton",
"userlogin": "Ensaluti / Krei novan konton",
"userloginnocreate": "Ensaluti",
"userlogin-resetpassword-link": "Ĉu vi forgesis vian pasvorton?",
"userlogin-helplink2": "Helpo pri ensaluto",
"userlogin-loggedin": "Vi jam estas ensalutita kiel {{GENDER:$1|$1}}.\nUzu la formularon suben por ensaluti kiel alia uzanto.",
+ "userlogin-reauth": "Vi devas ensaluti denove por konfirmi ke vi estas {{GENDER:$1|$1}}.",
"userlogin-createanother": "Krei alian konton",
"createacct-emailrequired": "Retpoŝta adreso",
"createacct-emailoptional": "Retpoŝta adreso (nedeviga)",
"createacct-email-ph": "Enigu vian retpoŝtan adreson",
"createacct-another-email-ph": "Enigu la retpoŝtan adreson",
"createaccountmail": "Uzi provizoran hazardsignan pasvorton kaj sendi ĝin al la retpoŝta adreso ĉi-suba",
+ "createaccountmail-help": "Uzebla por krei konton de alia persono sen lerni la pasvorton.",
"createacct-realname": "Vera nomo (nedeviga)",
"createaccountreason": "Kialo:",
"createacct-reason": "Kialo",
"createacct-reason-ph": "Kial vi kreas plian konton",
+ "createacct-reason-help": "Mesaĝo vidigita en la protokolo pri kreado de konto",
"createacct-submit": "Krei konton",
"createacct-another-submit": "Krei konton",
+ "createacct-continue-submit": "Daŭri kreadon de konto",
+ "createacct-another-continue-submit": "Daŭri kreadon de konto",
"createacct-benefit-heading": "{{SITENAME}} estas kreata de homoj kiel vi.",
"createacct-benefit-body1": "{{PLURAL:$1|redakto|redaktoj}}",
"createacct-benefit-body2": "{{PLURAL:$1|paĝo|paĝoj}}",
"nocookiesnew": "La uzantokonto estis kreita sed vi ne estas ensalutinta. {{SITENAME}} uzas kuketojn por akcepti uzantojn. Kuketoj esta malaktivigitaj ĉe vi. Bonvolu aktivigi ilin kaj ensalutu per viaj novaj salutnomo kaj pasvorto.",
"nocookieslogin": "{{SITENAME}} uzas kuketojn por akcepti uzantojn. Kuketoj esta malaktivigitaj ĉe vi. Bonvolu aktivigi ilin kaj provu denove.",
"nocookiesfornew": "La uzantokonto ne estis kreita, ĉar ne konfirmeblas ĝia fonto. Certiginte ke kuketoj estas ebligitaj, reŝargu tiun ĉi paĝon kaj reprovu.",
+ "createacct-loginerror": "La konto estis sukcese kreita sed vi ne povus esti ensalutita aŭtomate. Bonvolu procedi [[Special:UserLogin|malaŭtomatan ensaluton]].",
"noname": "Vi ne tajpis validan salutnomon.",
"loginsuccesstitle": "Ensalutis",
"loginsuccess": "Vi ensalutis ĉe {{SITENAME}} kiel uzanto \"$1\".",
- "nosuchuser": "Neniu uzanto havas nomon \"$1\".\nNomoj por uzantoj estas usklecodistingaj.\nKontrolu vian literumadon, aŭ [[Special:UserLogin/signup|kreu novan konton]].",
+ "nosuchuser": "Neniu uzanto havas nomon \"$1\".\nNomoj por uzantoj estas usklecodistingaj.\nKontrolu vian literumadon, aŭ [[Special:CreateAccount|kreu novan konton]].",
"nosuchusershort": "Ne ekzistas uzanto kun la nomo \"$1\". Bonvolu kontroli vian ortografion.",
"nouserspecified": "Vi devas entajpi salutnomon.",
"login-userblocked": "Ĉi tiu uzanto estas forbarita. Ensalutado ne estas permesita.",
"noemail": "Retpoŝtadreso ne estas registrita por uzanto \"$1\".",
"noemailcreate": "Vi devas provizi validan retadreson",
"passwordsent": "Oni sendis novan pasvorton al la retpoŝtadreso\nregistrita por \"$1\".\nBonvolu ensaluti denove ricevinte ĝin.",
- "blocked-mailpassword": "Via IP-adreso estas forbarita de redaktado. Por preventi fiuzojn, la pasvorto-restaŭron estas malpermesita per tiu IP-adreso.",
+ "blocked-mailpassword": "Via IP-adreso estas forbarita de redaktado. Por preventi fiuzojn, la pasvorto-restaŭro per tiu IP-adreso estas malpermesita.",
"eauthentsent": "Konfirma retmesaĝo estis sendita al la nomita retadreso. Antaŭ ol iu ajn alia mesaĝo estos sendita al la konto, vi devos sekvi la instrukciojn en la mesaĝo por konfirmi ke la konto ja estas via.",
"throttled-mailpassword": "Retpoŝto kun reŝargita pasvorto estis jam sendita ene de la {{PLURAL:$1|lasta horo|lastaj $1 horoj}}.\nPor preventi misuzon, nur unu reŝargita pasvorto estos sendita dum {{PLURAL:$1|horo|$1 horoj}}.",
"mailerror": "Okazis eraro sendante retpoŝtaĵon: $1",
"createacct-another-realname-tip": "La vera nomo estas nenecesa.\nSe vi decidas indiki ĝin, ĝi estos uzata por montri atribuadon de viaj kontribuoj.",
"pt-login": "Ensaluti",
"pt-login-button": "Ensaluti",
+ "pt-login-continue-button": "Daŭri ensaluton",
"pt-createaccount": "Krei konton",
"pt-userlogout": "Elsaluti",
"php-mail-error-unknown": "Nekonata eraro en la funkcio mail() de PHP",
"botpasswords-label-grants": "Uzeblaj permesdonoj:",
"botpasswords-help-grants": "Ĉiu permesdono provizas aliron al listitaj uzantaj permisoj, kiujn uzantkonto jam havas. Vidu la [[Special:ListGrants|tabelon de permisdonoj]] por pli da informo.",
"botpasswords-label-restrictions": "Limigoj de uzado:",
- "botpasswords-label-grants-column": "Permisdonita",
+ "botpasswords-label-grants-column": "Permeso donita",
"botpasswords-bad-appid": "La robota nomo \"$1\" estas malvalida.",
"botpasswords-insert-failed": "Aldono de la robota nomo \"$1\" ne sukcesis. Ĉu ĝi jam estis aldonita?",
"botpasswords-update-failed": "Ĝisdatigo de la robota nomo \"$1\" ne sukcesis. Ĉu ĝi estis forigita?",
"botpasswords-updated-body": "La robota pasvorto por robota nomo \"$1\" de la uzanto \"$2\" estis ĝisdatigita.",
"botpasswords-deleted-title": "Robota pasvorto forigita",
"botpasswords-deleted-body": "La robota pasvorto por robota nomo \"$1\" de la uzanto \"$2\" estis forigita.",
- "botpasswords-newpassword": "La nova pasvorto por ensaluti kun <strong>$1</strong> estas <strong>$2</strong>. <em>Bonvolu registri tiun por referenconto.",
+ "botpasswords-newpassword": "La nova pasvorto por ensaluti per <strong>$1</strong> estas <strong>$2</strong>. <em>Bonvolu noti ĝin por estonta konsultado.",
"botpasswords-no-provider": "Robotopasvortensalutoprovizilo (''BotPasswordsSessionProvider'') maldisponeblas.",
- "botpasswords-restriction-failed": "Limigoj pri robota pasvorto maleblas tiun uzantonomon.",
+ "botpasswords-restriction-failed": "Limigoj pri robota pasvorto malebligas tiun ensalutadon.",
"botpasswords-invalid-name": "La difinita uzantnomo malenhavas la robotopasvortan disigilon (\"$1\").",
"botpasswords-not-exist": "Uzanto \"$1\" ne havas robotopasvorton, kiu nomiĝas \"$2\".",
"resetpass_forbidden": "Pasvortoj ne estas ŝanĝeblaj",
+ "resetpass_forbidden-reason": "Pasvortoj ne povas esti ŝanĝita: $1",
"resetpass-no-info": "Vi devas ensaluti por atingi ĉi tiun paĝon rekte.",
"resetpass-submit-loggedin": "Ŝanĝi pasvorton",
"resetpass-submit-cancel": "Nuligi",
"passwordreset-emailtext-user": "Uzanto $1 de {{SITENAME}} petis restarigo de via pasvorto por {{SITENAME}}\n($4). La {{PLURAL:$3|jena uzanto-konto estas asociita|jenaj uzanto-kontoj estas asociitaj}} kun ĉi tiu retpoŝtadreso:\n\n$2\n\nĈi {{PLURAL:$3|tiu provizora pasvorto|tiuj provizoraj pasvortoj}} findatiĝos {{PLURAL:$5|unu tagon|$5 tagojn}}.\nVi devas ensaluti kaj elekti novan pasvorton nun. Se iu alia petis ĉi tion,\naŭ se vi memoris vian originalan pasvorton, kaj vi ne plu volas ŝanĝi\nĝin, vi povas ignori ĉi tiun mesaĝon kaj uzi vian malnovan pasvorton.",
"passwordreset-emailelement": "Salutnomo: \n$1\n\nProvizora pasvorto: \n$2",
"passwordreset-emailsentemail": "Se tiu ĉu retpoŝta adreso estas kunligita kun via konto, tiam al ĉi tiu adreso estos sendita retpoŝto por renovigi pasvorton.",
- "passwordreset-emailsentusername": "Se estas retpoŝta adreso, kiu estas asocigita kun tiu uzantnomo, tiam sendos retpôstan mesaĝon pri reasigno de pasvorto.",
+ "passwordreset-emailsentusername": "Se estas retpoŝta adreso, kiu estas asociita kun tiu uzantnomo, tiam ni sendos retpoŝtan mesaĝon pri reagordado de la pasvorto.",
"passwordreset-emailsent-capture": "Retpoŝto kun renovigita pasvorto estis sendita, kiu estas montrata malsupre.",
"passwordreset-emailerror-capture": "Retpoŝto kun renovigita pasvorto estis generita, montrata sube, sed sendado al la {{GENDER:$2|uzanto}} malsukcesis: $1",
+ "passwordreset-emailsent-capture2": "La {{PLURAL:$1|retpoŝto|retpoŝtojn}} de pasvorta reensignado estis sendita. La {{PLURAL:$1|salutnomo kaj pasvorto|listo de salutnomoj kaj pasvortoj}} estas vidigita sube.",
+ "passwordreset-emailerror-capture2": "Retpoŝtado al la {{GENDER:$2|uzantiĉo|uzantino|uzanto}} malsukcesis: $1 La {{PLURAL:$3|salutnomo kaj pasvorta|listo de salutnomoj kaj pasvortoj}} estas vidigita sube.",
+ "passwordreset-nocaller": "Vokanto devas esti provizita",
+ "passwordreset-nosuchcaller": "Vokanto ne ekzistas: $1",
+ "passwordreset-ignored": "La pasvorta reensignado ne estis pritraktita. Eble neniu provizanto estis formita?",
+ "passwordreset-invalideamil": "Nevalida retpoŝta adreso",
+ "passwordreset-nodata": "Nek salutnomo nek retpoŝta adreso estis provizita",
"changeemail": "Ŝanĝi aŭ forigi retpoŝtadreson",
"changeemail-header": "Plenigu ĉi tiun formularon por ŝanĝi vian retpoŝtadreson. Se vi volas forigi la difinon de retpoŝtadreso por via uzantokonto, lasu la kampon por la nova retpoŝtadreso malplena ĉe la transigo.",
"changeemail-passwordrequired": "Vi devas entajpi vian pasvorton, por konfirmi ĉi tiun ŝanĝon.",
"accmailtext": "Hazarde generita pasvorto por [[User talk:$1|$1]] estis sendita al $2.\n\nLa pasvorto por ĉi tiu nova konto povas esti ŝanĝita en la paĝo ''[[Special:ChangePassword|ŝanĝi pasvorton]]'' dum ensalutado.",
"newarticle": "(Nova)",
"newarticletext": "Vi sekvis ligilon al paĝo ankoraŭ ne ekzistanta. Se vi volas krei ĝin, ektajpu malsupre (vidu la [$1 helpopaĝon] por klarigoj.) Se vi malintence alvenis ĉi tien, simple alklaku la retrobutonon de via retumilo.",
- "anontalkpagetext": "---- ''Jen diskutopaĝo por anonima kontribuanto kiu ne jam kreis konton aŭ ne uzas ĝin.\nNi tial devas uzi la cifran IP-adreson por identigi lin/ŝin.\nĈi tia IP-adreso povas esti uzata de pluraj uzantoj.\nSe vi estas anonimulo kaj preferus eviti tiajn mistrafajn komentojn al vi, bonvolu [[Special:UserLogin/signup|krei konton]] aŭ [[Special:UserLogin|ensaluti]] por eviti estontan konfuzon pro aliaj anonimaj uzantoj.''",
+ "anontalkpagetext": "---- ''Jen diskutopaĝo por anonima kontribuanto kiu ne jam kreis konton aŭ ne uzas ĝin.\nNi tial devas uzi la cifran IP-adreson por identigi lin/ŝin.\nĈi tia IP-adreso povas esti uzata de pluraj uzantoj.\nSe vi estas anonimulo kaj preferus eviti tiajn mistrafajn komentojn al vi, bonvolu [[Special:CreateAccount|krei konton]] aŭ [[Special:UserLogin|ensaluti]] por eviti estontan konfuzon pro aliaj anonimaj uzantoj.''",
"noarticletext": "Mankas teksto en ĉi tiu paĝo.\nVi povas [[Special:Search/{{PAGENAME}}|serĉi ĉi tiun paĝtitolon]] en aliaj paĝoj,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serĉi la rilatajn protokolojn],\naŭ [{{fullurl:{{FULLPAGENAME}}|action=edit}} krei ĉi tiun paĝon]</span>.",
"noarticletext-nopermission": "Estas neniom da teksto en ĉi tiu paĝo.\nVi povas [[Special:Search/{{PAGENAME}}|serĉi ĉi tiun paĝan titolon]] en aliaj paĝoj,\naŭ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serĉi la rilatajn protokolojn]</span>, sed vi ne rajtas krei ĉi tiun paĝon.",
"missing-revision": "La revizio n-ro $1 de la paĝo nomata \"{{FULLPAGENAME}}\" ne ekzistas.\n\nTio kutime estas kaŭzata per sekvado de malaktuala historio-ligilo al paĝo forigita.\nDetaloj troveblos en la [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de forigoj].",
"permissionserrors": "Eraro pri permeso",
"permissionserrorstext": "Vi ne rajtas fari tion pro la {{PLURAL:$1|sekva kialo|sekvaj kialoj}}:",
"permissionserrorstext-withaction": "Vi ne rajtas $2, pro la {{PLURAL:$1|jena kialo|jenaj kialoj}}:",
- "contentmodelediterror": "Vi ne povas prilabori ĉi tiun reviziaĵo, ĉar ĝia enhavoŝablono estas <code>$1</code>, kiu malsamas la aktualan enhavoŝablonon de la paĝo <code>$2</code>.",
+ "contentmodelediterror": "Vi ne povas prilabori ĉi tiun version, ĉar ĝia enhavomodelo estas <code>$1</code>, kiu malsamas la aktualan enhavomodelon de la paĝo <code>$2</code>.",
"recreate-moveddeleted-warn": "'''Averto: Vi rekreas paĝon, kiu estis antaŭe forigita.'''\n\nVi konsideru, ĉu konvenas daŭre redakti ĉi tiun paĝon.\nJen la protokolo de forigoj kaj alinomigado por via oportuno:",
"moveddeleted-notice": "Ĉi tiu paĝo estis forigita.\nPliaj detaloj estas en protokolo pri forigado kaj alinomado de tiu ĉi paĝo.",
- "moveddeleted-notice-recent": "Pardonon, tiu paĝo freŝdate estis forigita (en la dauro de la lasta 24 horoj).\nLa forigo kaj la movprotokolo pri la paĝo estas provizitaj sube por referenco.",
+ "moveddeleted-notice-recent": "Pardonon, tiu ĉi paĝo freŝdate estis forigita (en la daŭro de la lastaj 24 horoj).\nLa foriga kaj la nomŝanĝa protokoloj pri la paĝo estas provizitaj sube por referenco.",
"log-fulllog": "Vidi kompletan protokolon",
"edit-hook-aborted": "Redakto estis ĉesigita per etendaĵo de la Vikia softvaro.\nĜi ne donis eksplikon.",
"edit-gone-missing": "Ne eblis ĝisdatigi la paĝon.\nVerŝajne ĝi estis forigita.",
"content-model-css": "CSS",
"content-json-empty-object": "Malplena objeto",
"content-json-empty-array": "Malplena tabelo",
- "duplicate-args-warning": "'''Averto:''' [[:$1]] vokas je [[:$2]] kun pli ol unu valoro por la parametro \"$3\". Nur la lasta liverita valoro estas uzonta.",
+ "duplicate-args-warning": "'''Averto:''' [[:$1]] vokas al [[:$2]] kun pli ol unu valoro por la parametro \"$3\". Nur la lasta liverita valoro estos uzata.",
"duplicate-args-category": "Paĝoj kun pluroblaj argumentoj en ŝablonvokoj",
"duplicate-args-category-desc": "La paĝo enhavas uzon de ŝablono kun pluroble uzitaj argumentoj, kiel ekzemple <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> aŭ <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
"expensive-parserfunction-warning": "Averto: Ĉi tiu paĝo enhavas tro da multekostaj sintaksaj funkcio-vokoj.\n\nĜi havu malpli ol $2 {{PLURAL:$2|vokon|vokojn}}, sed nun estas $1 {{PLURAL:$1|voko|vokoj}}.",
"revdelete-submit": "Apliki al {{PLURAL:$1|elektita revizio|elektitaj revizioj}}",
"revdelete-success": "'''Revizivideblecon ĝisdatigis.'''",
"revdelete-failure": "'''Videblecon de revizio ne eblis ĝisdatigi:'''\n$1",
- "logdelete-success": "'''Protokolovideblecon ensignitan.'''",
+ "logdelete-success": "'''Protokolovidebleco agordita.'''",
"logdelete-failure": "'''Protokola videbleco ne estis akordebla:'''\n$1",
"revdel-restore": "Ŝanĝi videblecon",
"pagehist": "Paĝa historio",
"mergehistory-fail-invalid-source": "Fonta paĝo estas malvalida.",
"mergehistory-fail-invalid-dest": "Cela paĝo estas malvalida.",
"mergehistory-fail-no-change": "Historio-kunfandado kunfandis neniun revizion. Bonvolu rekontroli la paĝon kaj la tempo-parametrojn.",
- "mergehistory-fail-permission": "Nesufiĉa permesoj por kunfadi historion.",
+ "mergehistory-fail-permission": "Nesufiĉaj permesoj por kunfandi historion.",
"mergehistory-fail-self-merge": "Fonta kaj cela paĝoj samas.",
- "mergehistory-fail-timestamps-overlap": "Fonta revizio surkunigas aŭ postokuras la celan revizion.",
+ "mergehistory-fail-timestamps-overlap": "Fontaj modifoj okazis dum aŭ post la celaj modifoj.",
"mergehistory-fail-toobig": "Ne eblas kunigi historiojn ĉar pli ol sojlo de $1 {{PLURAL:$1|revizio|revizioj}} estus {{PLURAL:$1|movita|movitaj}}.",
"mergehistory-no-source": "Fontpaĝo $1 ne ekzistas.",
"mergehistory-no-destination": "Celpaĝo $1 ne ekzistas.",
"search-category": "(kategorio $1)",
"search-file-match": "(kongruas kun dosiera enhavo)",
"search-suggest": "Ĉu vi intenciis: $1",
- "search-rewritten": "Montru rezultojn por $1. Serĉita anstataŭ $2.",
+ "search-rewritten": "Ni montras rezultojn por $1. Serĉi anstataŭe pri $2.",
"search-interwiki-caption": "Kunprojektoj",
"search-interwiki-default": "Rezultoj de $1:",
"search-interwiki-more": "(plu)",
"prefs-help-recentchangescount": "Ĉi tiu inkluzivas lastajn ŝanĝojn, paĝajn historiojn, kaj protokolojn.",
"prefs-help-watchlist-token2": "Tio estas la sekreta ŝlosilo al la retfluo de via atentaro.\nĈiu, kiu konas ĝin, povas legi vian atentaron. Do, ne kunhavigu ĝin.\nSe vi devas, [[Special:ResetTokens|vi povas rekomencigi ĝin]].",
"savedprefs": "Viaj preferoj estas konservitaj.",
- "savedrights": "La uzanto-rajtojn de {{GENDER:$1|$1}} konservigis.",
+ "savedrights": "La uzanto-rajtoj de {{GENDER:$1|$1}} estis konservitaj.",
"timezonelegend": "Horzono:",
"localtime": "Loka tempo:",
"timezoneuseserverdefault": "Uzi defaŭlton de servilo ($1)",
"right-createpage": "Kreu paĝojn (kiuj ne estas diskuto-paĝoj)",
"right-createtalk": "Krei diskuto-paĝojn",
"right-createaccount": "Krei novajn uzanto-kontojn",
- "right-autocreateaccount": "Aŭtomate ensaluti eksteruzantan konton",
+ "right-autocreateaccount": "Aŭtomate ensaluti per ekstera uzokonto",
"right-minoredit": "Marki redaktojn kiel etajn",
"right-move": "Movi paĝojn",
"right-move-subpages": "Alinomigi paĝojn kun ĝiaj subpaĝoj",
"right-bigdelete": "Forigi paĝojn kun grandaj historioj",
"right-deletelogentry": "Forigi kaj malforigi specifajn enmetojn en la registro.",
"right-deleterevision": "Forigi kaj malforigi specifajn versiojn de paĝoj",
- "right-deletedhistory": "Vidi forigitajn historieroj, sen ties asociaj tekstoj",
+ "right-deletedhistory": "Vidi forigitajn historierojn, sen iliaj ligita teksto",
"right-deletedtext": "Rigardi forigitan tekston kaj ŝanĝojn inter forigitaj revizioj.",
"right-browsearchive": "Serĉi forigitajn paĝojn",
"right-undelete": "Restarigi paĝon",
"right-managechangetags": "Kreado kaj forigado de [[Special:Tags|etikedoj]] de datumbazo",
"right-applychangetags": "Aldoni [[Special:Tags|etikedojn]] al propraj ŝanĝoj",
"right-changetags": "Aldoni kaj forigi arbitrajn [[Special:Tags|etikedojn]] ĉe unuopaj revizioj kaj protokoleroj",
+ "right-deletechangetags": "Forigi [[Special:Tags|etikedojn]] de la datenbazo",
"grant-generic": "\"$1\" rajtaro",
"grant-group-page-interaction": "Interagi paĝojn",
"grant-group-file-interaction": "Interagi aŭdvidaĵajn dosierojn",
"grant-group-watchlist-interaction": "Interagi vian atentaron",
"grant-group-email": "Sendi retpoŝton",
- "grant-group-high-volume": "Efektivigi ampleksege aktivecon",
+ "grant-group-high-volume": "Efektivigi ampleksegajn agojn",
"grant-group-customization": "Personecigoj kaj preferoj",
"grant-group-administration": "Efektivigi administrajn agojn",
"grant-group-other": "Diversaj aktivecoj",
"grant-createeditmovepage": "Krei, redakti kaj alinomi paĝojn",
"grant-delete": "Forigi paĝojn, reviziaĵojn kaj protokolerojn",
"grant-editinterface": "Redakti la MediaVikian nomspacon kaj la CSS/Ĝavoskripto de uzanto",
- "grant-editmycssjs": "Redakti vian uzantan CSS/Ĝavoskripton",
- "grant-editmyoptions": "Redakti vian uzantan preferojn",
+ "grant-editmycssjs": "Redakti viajn personajn CSS-kodon / Ĝavoskripton",
+ "grant-editmyoptions": "Redakti viajn personajn agordojn",
"grant-editmywatchlist": "Redakti vian atentaron",
"grant-editpage": "Redakti ekzistantajn paĝojn",
"grant-editprotected": "Redakti protektitajn paĝojn",
- "grant-highvolume": "Ampleksegaj redaktado",
+ "grant-highvolume": "Ampleksega redaktado",
"grant-oversight": "Kaŝi uzantojn kaj forigi reviziaĵojn",
"grant-patrol": "Patroli ŝanĝojn al pâgoj",
"grant-protect": "Protekti kaj malprotekti paĝojn",
- "grant-rollback": "Malvalidi ŝanĝojn al paĝoj",
+ "grant-rollback": "Malfari ŝanĝojn de paĝoj",
"grant-sendemail": "Retpoŝti al aliaj uzantoj",
"grant-uploadeditmovefile": "Alŝuti, anstataŭigi kaj alinomi dosierojn",
"grant-uploadfile": "Alŝuti novajn dosierojn",
"action-viewmyprivateinfo": "vidi viajn privatajn informojn",
"action-editmyprivateinfo": "redakti viajn privatajn informojn",
"action-editcontentmodel": "redakti paĝan enhavmodelon",
- "action-managechangetags": "krei kaj forigi etikedojn de datumbazo",
+ "action-managechangetags": "Krei kaj (mal)aktivigi etikedojn",
"action-applychangetags": "aldoni etikedojn al viaj propraj ŝanĝoj",
"action-changetags": "aldoni kaj forigi arbitrajn etikedojn ĉe unuopaj revizioj kaj protokoleroj",
+ "action-deletechangetags": "Forigi etikedojn de la datenbazo.",
"nchanges": "$1 {{PLURAL:$1|ŝanĝo|ŝanĝoj}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ekde lasta vizito}}",
"enhancedrc-history": "historio",
"rcshowhidemine": "$1 miajn redaktojn",
"rcshowhidemine-show": "Montri",
"rcshowhidemine-hide": "Kaŝi",
- "rcshowhidecategorization": "$1 paĝokategoriadon",
+ "rcshowhidecategorization": "$1 paĝa enkategoriigo",
"rcshowhidecategorization-show": "Montri",
"rcshowhidecategorization-hide": "Kaŝi",
"rclinks": "Montri $1 lastajn ŝanĝojn dum la $2 lastaj tagoj.<br />$3",
"recentchangeslinked-summary": "Jen listo de ŝanĝoj faritaj lastatempe al paĝoj ligitaj el specifa paĝo (aŭ al membroj de specifa kategorio).\nPaĝoj en [[Special:Watchlist|via atentaro]] estas '''grasaj'''.",
"recentchangeslinked-page": "Nomo de paĝo:",
"recentchangeslinked-to": "Montru ŝanĝojn al paĝoj ligitaj al la specifa paĝo anstataŭe.",
- "recentchanges-page-added-to-category": "[[:$1]] kategorialdonita",
+ "recentchanges-page-added-to-category": "[[:$1]] aldonita al la kategorio",
"recentchanges-page-added-to-category-bundled": "[[:$1]] kategorialdonita, [[Special:WhatLinksHere/$1|tiu paĝo estas inkluzivita ene de aliaj paĝoj]]",
"recentchanges-page-removed-from-category": "[[:$1]] kategoriforigita",
"recentchanges-page-removed-from-category-bundled": "[[:$1]] kategoriforigita, [[Special:WhatLinksHere/$1|tiu paĝo estas inkluzivita ene de aliaj paĝoj]]",
"uploadscripted": "HTML-aĵo aŭ skriptokodaĵo troviĝas en tiu ĉi tiu dosiero, kiun TTT-foliumilo eble interpretus erare.",
"upload-scripted-pi-callback": "Malalŝuteblas dosieron, kiu enhavas instrukcion de XML-stilfolia traktado",
"uploaded-script-svg": "Trovis skriptelbero \"$1\" en la alŝutita SVGa dosiero.",
- "uploaded-hostile-svg": "Trovis malsekura CSS en la stilero de alŝutita SVGa dosiero.",
+ "uploaded-hostile-svg": "Trovis malsekuran CSS-kodon en la stila elemento de alŝutita SVG-a dosiero.",
"uploaded-event-handler-on-svg": "Ensigni eventotraktilajn atributojn <code>$1=\"$2\"</code> estas malpermisita en SVGaj dosieroj.",
"uploaded-href-attribute-svg": "Atributoj je \"href\" en SVGaj dosieroj nur povas ligi al \"http://\" aŭ \"https://\" celoj, trovis <code><$1 $2=\"$3\"></code>.",
"uploaded-href-unsafe-target-svg": "Trovis je \"href\" ligita al malsekuraj datenoj: URIa celo <code><$1 $2=\"$3\"></code> en la alŝuta SVGa dosiero.",
"uploaded-setting-href-svg": "Uzi la markon je \"set\" por aldoni atributon je \"href\" al ujero estas blokita.",
"uploaded-wrong-setting-svg": "Uzi la ''ensigni'' (''<span lang=\"en\">set</span>'') markon por aldoni foran/datenan/skriptan celon al ajn atributon estas blokita. Trovis <code><set to=\"$1\"></code> en la alŝutita SVGan dosieron.",
"uploaded-setting-handler-svg": "SVGa dosiero kiu ensignas la traktilan atributon (''<span lang=\"en\">handler</span>'') kun fora/datena/skripta estas blokita. Trovis <code>$1=\"$2\"</code> en la alsûtita SVGa dosiero.",
- "uploaded-remote-url-svg": "SVGa dosiero kiu ensignas ajn stilan atributon kun fora URL estas blokita. Trovis <code>$1=\"$2\"</code> en la alsûtita SVGa dosiero.",
+ "uploaded-remote-url-svg": "SVG-a dosiero kiu asignas ajnan stilan atributon kun fora URL estas blokita. Ni trovis <code>$1=\"$2\"</code> en la alsûtita SVG-a dosiero.",
"uploaded-image-filter-svg": "Trovis bildan filtrilon kun URL: <code><$1 $2=\"$3\"></code> en la alŝutita SVGa dosiero.",
"uploadscriptednamespace": "Ĉi tiu SVG-dosiero enhavas nevalidan nomspacon \"$1\"",
"uploadinvalidxml": "Ne eblas interpreti la XML-sintakson en la alŝutita dosiero",
"upload-options": "Alŝutaj agordoj",
"watchthisupload": "Atenti ĉi tiun dosieron",
"filewasdeleted": "Dosiero de ĉi tiu nomo estis antaŭe alŝutita kaj poste forigita. Bonvolu kontroli en la $1 antaŭ alŝuti ĝin denove.",
- "filename-thumb-name": "Ĉi tiu aspektas kiel titolo de etigita versio de plena bildo. Bonvolu ne alŝuti etigitajn versiojn de bildoj en la sama vikio. Alimaniere, bonvolu modifi la dosiernomon pli signife, kaj ne plu havas la eta-versian prefikson.",
+ "filename-thumb-name": "Ĉi tiu aspektas kiel titolo de etigita versio de plena bildo. Bonvolu ne alŝuti etigitajn versiojn de bildoj al la sama vikio. Alimaniere, bonvolu modifi la dosiernomon al pli signifa, kiu ne havas la eta-versian prefikson.",
"filename-bad-prefix": "La nomo de la dosiero kiun vi alŝutas komencas kun '''\"$1\"''', kiu estas nepriskriba nomo ofte aŭtomate donata de ciferecaj fotiloj. Bonvolu elekti pli priskriban nomon por via bildo.",
"upload-proto-error": "Malvalida protokolo",
"upload-proto-error-text": "Fora alŝuto devas URL-on komence de <code>http://</code> aŭ <code>ftp://</code>.",
"upload-form-label-infoform-name": "Nomo",
"upload-form-label-infoform-name-tooltip": "Unika priskriba titolo por tiu ĉi dosiero, kiu servos kiel dosiernomo. Eblas uzi normalan lingvaĵon kun interspacoj. Ne aldonu la dosieran aldonaĵon.",
"upload-form-label-infoform-description": "Priskribo",
- "upload-form-label-infoform-description-tooltip": "Bonvolu koncize priskribi ĉion noteblan pri la verko.\nPor foto, menciu la esencaj aĵoj bildigitaj, la okazon, aŭ la lokon.",
+ "upload-form-label-infoform-description-tooltip": "Bonvolu koncize priskribi ĉion notindan pri la verko.\nPri foto, menciu la esencajn aĵojn bildigitajn, la okazon, aŭ la lokon.",
"upload-form-label-usage-title": "Uzo",
"upload-form-label-usage-filename": "Dosiernomo",
"upload-form-label-own-work": "Tio estas mia propra laboro",
"upload-form-label-infoform-categories": "Kategorioj",
"upload-form-label-infoform-date": "Dato",
- "upload-form-label-own-work-message-local": "Mi konfirmas ke mi alŝutas tiun dosieron respektante pri la uzadokondiĉoj kaj permesopolitikoj de {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Se vi ne eblas alŝuti tiun dosieron respektante de politikoj de {{SITENAME}}, bonvolu fermi tiun dialogon kaj provi denove kun alia metodo.",
- "upload-form-label-not-own-work-local-local": "Vi eble ŝatu egale pravi [[Special:Upload|la defaŭltan paĝon]].",
- "upload-form-label-own-work-message-default": "Mi komprenas ke mi alŝutas tiun dosieron al komunigita deponejo. Mi konfirmas ke mi faras tiun respektante de la uzadtermoj kaj de la permisilopolitikoj tie.",
+ "upload-form-label-own-work-message-generic-local": "Mi konfirmas ke mi alŝutas tiun dosieron respektante pri la uzadokondiĉoj kaj permesopolitikoj de {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Se vi ne eblas alŝuti tiun dosieron respektante de politikoj de {{SITENAME}}, bonvolu fermi tiun dialogon kaj provi denove kun alia metodo.",
+ "upload-form-label-not-own-work-local-generic-local": "Vi eble ŝatu egale pravi [[Special:Upload|la defaŭltan paĝon]].",
+ "upload-form-label-own-work-message-generic-foreign": "Mi komprenas ke mi alŝutas tiun dosieron al komunigita deponejo. Mi konfirmas ke mi faras tiun respektante de la uzadtermoj kaj de la permisilopolitikoj tie.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Se vi ne eblas alŝuti tiun dosieron respektante de politikoj de komuna deponejo, bonvolu fermi tiun dialogon kaj provi denove kun alia metodo.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Vi ankaŭ eble dezirus provi per uzi [[Special:Upload|la alŝutan paĝon sur {{SITENAME}}]], se ĉi tiu dosiero povas esti alŝutita tie respektante de iliaj politikoj.",
"backend-fail-stream": "Ne povis fluigi dosieron $1.",
"backend-fail-backup": "Ne povis enarkivigi dosieron $1.",
"backend-fail-notexists": "La dosiero $1 ne ekzistas.",
"uploadstash-summary": "Tiu ĉi paĝo alirebligas la dosierojn alŝutitajn (aŭ alŝutatajn), kiuj ne jam estas publikigitaj per la vikio. Tiujn ĉi dosierojn ne povas vidi iu ajn, krom la alŝutinto mem.",
"uploadstash-clear": "Malplenigi la dosierkonversejon.",
"uploadstash-nofiles": "Mankas dosieroj en la konservejo.",
- "uploadstash-badtoken": "Malsukcesis tiu ago, eble pro tio ke viaj ensalutiloj senvalidiĝis. Bonvolu reprovi.",
+ "uploadstash-badtoken": "Malsukcesis tiu ago, eble pro tio ke viaj ensalutiloj eksvalidiĝis. Bonvolu reprovi.",
"uploadstash-errclear": "Malsukcesis la forigo de la dosieroj.",
"uploadstash-refresh": "Aktualigi la dosierliston.",
- "uploadstash-thumbnail": "Vidi bildetigon",
+ "uploadstash-thumbnail": "Vidi bildeton",
"invalid-chunk-offset": "Malvalida deŝovo de dosierpeco",
"img-auth-accessdenied": "Atingo malpermisita",
"img-auth-nopathinfo": "Mankas PATH_INFO (informo pri dosiervojo).\nVia servilo ne estas konfigurita por sendi ĉi tiun informon.\nEble ĝi estas CGI-bazita kaj ne subtenas img_auth.\nVidu https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization (angle).",
"listfiles-latestversion-no": "Ne",
"file-anchor-link": "Dosiero",
"filehist": "Dosiera historio",
- "filehist-help": "Klaku daton/tempon por vidi la dosieron kiel ĝin ŝajnitan tiame.",
+ "filehist-help": "Klaku daton/tempon por vidi la dosieron kia ĝi aspektis tiam.",
"filehist-deleteall": "forigi ĉiujn",
"filehist-deleteone": "forigi",
"filehist-revert": "restarigi",
"apihelp": "Helpo pri API",
"apihelp-no-such-module": "Modulo \"$1\" ne estis trovita.",
"apisandbox": "API testejo",
+ "apisandbox-jsonly": "JavaScript estas postulita por uzi la API provejon.",
"apisandbox-api-disabled": "API estas malŝalta en ĉi tiu retejo.",
- "apisandbox-intro": "Uzu tiun ĉi paĝon por eksperimenti kun '''MediaWiki API'''.\nVidu [//www.mediawiki.org/wiki/API:Main_page la API-dokumentadon] por pli da detaloj pri la uzo de API. Ekz-e: [//www.mediawiki.org/wiki/API#A_simple_example atingi la enhavon de la Ĉefpaĝo]. Elektu agon por vidi pliajn ekzemplojn.\n\nNotu ke, kvankam ĉi tiu estas provejo, agoj kiun vi faros en ĉi tiu paĝo povas modifi la vikion.",
+ "apisandbox-intro": "Uzu tiun ĉi paĝon por eksperimenti kun <strong>Mediavikia retserva API</strong>.\nVidu [[mw:API:Main page|la API-dokumentadon]] por pli da detaloj pri la uzo de API. Ekz-e: [//www.mediawiki.org/wiki/API#A_simple_example atingi la enhavon de la Ĉefpaĝo]. Elektu agon por vidi pliajn ekzemplojn.\n\nNotu ke, kvankam ĉi tiu estas provejo, agoj kiun vi faros en ĉi tiu paĝo povas modifi la vikion.",
+ "apisandbox-fullscreen": "Etendi panelon",
+ "apisandbox-fullscreen-tooltip": "Etendi la proveja panelo por plenigi la retumilan fenestron.",
"apisandbox-unfullscreen": "Montri paĝon",
+ "apisandbox-unfullscreen-tooltip": "Maletendi la provejan panelon, tiel Mediavikiaj navigadaj ligoj estas haveblaj.",
"apisandbox-submit": "Fari mendon",
"apisandbox-reset": "Nuligi",
"apisandbox-retry": "Reprovi",
+ "apisandbox-loading": "Ŝutas informon de la APIa modulo je \"$1\"…",
+ "apisandbox-load-error": "Eraro okazis dum ŝutis informon por APIa modulo je \"$1\": $2",
+ "apisandbox-no-parameters": "Ĉi tiu APIa modulo ne havas parametron.",
"apisandbox-helpurls": "Ligiloj pri helpo",
"apisandbox-examples": "Ekzemploj",
"apisandbox-dynamic-parameters": "Aldonaj parametroj",
"apisandbox-dynamic-parameters-add-label": "Aldoni parametron:",
"apisandbox-dynamic-parameters-add-placeholder": "Nomo de parametro",
"apisandbox-dynamic-error-exists": "Parametro nomata \"$1\" jam ekzistas.",
+ "apisandbox-deprecated-parameters": "Evitindajn parametrojn",
+ "apisandbox-fetch-token": "Aŭtoplenigu ĵetonon",
"apisandbox-submit-invalid-fields-title": "Iuj kampoj estas malvalidaj.",
+ "apisandbox-submit-invalid-fields-message": "Bonvolu ĝustigi la markitajn kampojn kaj provi denove.",
"apisandbox-results": "Rezultoj",
+ "apisandbox-sending-request": "Sendanta aplikprograminterfacan peton…",
+ "apisandbox-loading-results": "Ricevas APIajn rezultojn…",
+ "apisandbox-results-error": "Eraro okazis dum ŝutis la APIan petan respondon: $1.",
"apisandbox-request-url-label": "Mendi URL-on.",
"apisandbox-request-time": "Tempo de peto:{{PLURAL:$1|$1 ms}}",
+ "apisandbox-results-fixtoken": "Korekti ĵetonon kaj resendi",
+ "apisandbox-results-fixtoken-fail": "Malsukcese venigis ĵetonon je \"$1\".",
+ "apisandbox-alert-page": "Kampoj de ĉi tiu paĝo ne estas validaj.",
+ "apisandbox-alert-field": "La valoro de ĉi tiu kampo ne estas valida.",
"booksources": "Librofontoj",
"booksources-search-legend": "Serĉi librofontojn",
"booksources-search": "Serĉi",
"activeusers-hidebots": "kaŝi robotojn",
"activeusers-hidesysops": "Kaŝi administrantojn",
"activeusers-noresult": "Neniuj uzantoj trovitaj.",
+ "activeusers-submit": "Montri la agemajn uzantojn",
"listgrouprights": "Gruprajtoj de uzantoj",
"listgrouprights-summary": "Jen listo de uzanto-grupoj difinitaj en ĉi tiu vikio, kun ties asociaj atingrajtoj.\nEstas [[{{MediaWiki:Listgrouprights-helppage}}|aldona informo]] pri individuaj rajtoj.",
"listgrouprights-key": "* <span class=\"listgrouprights-granted\">Donita rajto</span>\n* <span class=\"listgrouprights-revoked\">Forigita rajto</span>",
"listgrouprights-namespaceprotection-header": "Nomspacaj restriktoj",
"listgrouprights-namespaceprotection-namespace": "Nomspaco",
"listgrouprights-namespaceprotection-restrictedto": "Rajtoj, kiuj permesas al uzanto redakti",
- "listgrants": "Rajdonaro",
+ "listgrants": "Rajtoj donitaj",
+ "listgrants-grant": "Aljuĝoj",
+ "listgrants-rights": "Rajtoj",
"trackingcategories": "Kategorioj por kontrolado",
"trackingcategories-summary": "Ĉi tiu paĝo listigas kategoriojn por kontrolado, aŭtomate farita de la Mediavikia programaro. Ties nomoj estas ŝanĝebla, ŝanĝante la paran sistemmesaĝon en la nomspaco {{ns:8}}.",
"trackingcategories-msg": "Kategorio pri kontrolado",
"trackingcategories-name": "Nomo de mesaĝo",
"trackingcategories-desc": "Kriterio por inkluzivi kategorion",
+ "restricted-displaytitle-ignored": "Paĝoj kun malatentaj vidigaj titoloj",
+ "restricted-displaytitle-ignored-desc": "La paĝo enhavas ignoritan <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> ĉar ĝi ne ekvivalentas la efektivan titolon de la paĝo.",
"noindex-category-desc": "La paĝo ne estas indeksata de robotoj ĉar ĝi enhavas la magian vorton <code><nowiki>__NOINDEX__</nowiki></code> kaj estas en nomspaco, kie la flago estas permesita.",
"index-category-desc": "La paĝo enhavas <code><nowiki>__INDEX__</nowiki></code> (kaj estas en nomspaco, kie la flago estas permesita), do ĝi estas indeksata de robotoj, kvankam normale ĝi ne estus.",
"post-expand-template-inclusion-category-desc": "La paĝo post etendo de ĉiuj ŝablonoj estas pli granda ol <code>$wgMaxArticleSize</code>, do kelkaj ŝablonoj ne estis etenditaj.",
"emailccsubject": "Kopio de via mesaĝo al $1: $2",
"emailsent": "Retmesaĝo sendita",
"emailsenttext": "Via retmesaĝo estas sendita.",
- "emailuserfooter": "Ĉi tiun retpoŝton sendis $1 al $2 per la funkcio \"{{int:emailuser}}\" ĉe {{SITENAME}}.",
+ "emailuserfooter": "Ĉi tiun retpoŝton estis sendita far $1 al $2 per la funkcio \"{{int:emailuser}}\" el {{SITENAME}}.",
"usermessage-summary": "Lasanta sisteman mesaĝon.",
"usermessage-editor": "Mesaĝanto de sistemo",
"watchlist": "Mia atentaro",
"watchlistanontext": "Bonvolu ensaluti por vidi aŭ redakti vian atentaron.",
"watchnologin": "Ne ensalutinta",
"addwatch": "Aldoniĝi al atentaro",
- "addedwatchtext": "La paĝo \"[[:$1]]\" aldoniĝis al via [[Special:Watchlist|atentaro]]. Estontaj ŝanĝoj de tiu paĝo kaj de ĝia rilata diskutpaĝo aperos tie.",
+ "addedwatchtext": "\"[[:$1]]\" kaj ĝia diskutpaĝo estis aldonitaj al via [[Special:Watchlist|atentaro]].",
"addedwatchtext-short": "La paĝo \"$1\" estis aldonita al via atento-listo.",
"removewatch": "Forigi el atentaro",
- "removedwatchtext": "La paĝo \"[[:$1]]\" estas forigita el via [[Special:Watchlist|atentaro]].",
+ "removedwatchtext": "\"[[:$1]]\" kaj ĝia diskutpaĝo estis forigita el via [[Special:Watchlist|atentaro]].",
"removedwatchtext-short": "La paĝo \"$1\" estis forigita el via atento-listo.",
"watch": "Atenti",
"watchthispage": "Priatenti paĝon",
"wlshowlast": "Montri el lastaj $1 horoj $2 tagoj",
"watchlist-hide": "Kaŝi",
"watchlist-submit": "Montri",
+ "wlshowtime": "Vidigenda tempodaŭro:",
"wlshowhideminor": "Etaj redaktoj",
"wlshowhidebots": "robotoj",
"wlshowhideliu": "registritaj uzantoj",
"wlshowhideanons": "anonimaj uzantoj",
"wlshowhidepatr": "patrolitaj redaktoj",
"wlshowhidemine": "miaj redaktoj",
- "wlshowhidecategorization": "paĝokategoriado",
+ "wlshowhidecategorization": "paĝa enkategoriigo.",
"watchlist-options": "Opcioj por atentaro",
"watching": "Aldonata al la atentaro...",
"unwatching": "Malatentante...",
"deleteprotected": "Vi ne povas forigi ĉi tiun paĝon ĉar ĝi estis protektita.",
"deleting-backlinks-warning": "<strong>Atentigo:</strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|Aliaj paĝoj]] ligas al aŭ transkludas tiun ĉi forigotan paĝon.",
"rollback": "Restarigi antaŭan redakton",
- "rollbacklink": "malvalidi",
+ "rollbacklink": "malfari",
"rollbacklinkcount": "nuligi $1 {{PLURAL:$1|redakton|redaktojn}}",
"rollbacklinkcount-morethan": "nuligi pli ol $1 {{PLURAL:$1|redakton|redaktojn}}",
"rollbackfailed": "Malfaro malsukcesis",
+ "rollback-missingparam": "Mankas neprajn parametrojn de peto.",
"cantrollback": "Ne povas restarigi antaŭan redakton; la redaktinto lasta estas la sola aŭtoro de la paĝo.",
"alreadyrolled": "Ne povas restarigi la lastan redakton de [[:$1]] de la [[User:$2|$2]] ([[User talk:$2|diskuto]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\npro tio, ke oni intertempe redaktis aŭ restarigis la paĝon.\nLa lasta redaktinto estis [[User:$3|$3]] ([[User talk:$3|diskuto]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "La resumo de la redakto estis: <em>$1</em>.",
"revertpage": "Malfaris redaktojn de [[Special:Contributions/$2|$2]] ([[User talk:$2|diskuto]]) al la lasta versio de [[User:$1|$1]]",
"revertpage-nouser": "Restarigis redaktojn de (salutnomo forigita) al lasta revizio de {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Restaris redaktojn de $1; ŝanĝis al lasta versio de $2.",
+ "rollback-success-notify": "Malfaritis redaktojn far $1;\nŝanĝis al la lasta reviziaĵo far $2. [$3 Prezenti ŝanĝojn]",
"sessionfailure-title": "Seanco malsukcesis",
"sessionfailure": "Ŝajnas, ke estas problemo kun via ensalutado;\nĈi ago estis nuligita por malhelpi fiensalutadon.\nBonvolu alklaki la reirbutonon kaj reŝargi la paĝon el kiu vi venas, kaj provu denove.",
+ "changecontentmodel": "Ŝanĝi la enhavomodelon de paĝo",
+ "changecontentmodel-legend": "Ŝanĝi la enhavomodelon",
"changecontentmodel-title-label": "Titolo de paĝo",
+ "changecontentmodel-model-label": "Nova enhavomodelo",
"changecontentmodel-reason-label": "Kialo:",
"changecontentmodel-submit": "Ŝanĝi",
+ "changecontentmodel-success-title": "Enhavomodelo estis ŝanĝigita",
+ "changecontentmodel-success-text": "La enhavotipo de [[:$1]] estis ŝanĝigita.",
+ "changecontentmodel-cannot-convert": "La enhavo en [[:$1]] ne transtipeblas al $2.",
+ "changecontentmodel-nodirectediting": "La enhavomodelo $1 ne permesas la rektan redaktadon",
+ "changecontentmodel-emptymodels-title": "Neniu disponebla enhavomodelo",
+ "changecontentmodel-emptymodels-text": "La enhavo en [[:$1]] ne transtipeblas al iu ajn tipo.",
+ "log-name-contentmodel": "Ŝanĝprotokolo de enhavomodelo",
+ "log-description-contentmodel": "Eventoj rilataj kun la enhavomodeloj de paĝo",
+ "logentry-contentmodel-new": "$1 {{GENDER:$2|kreis}} la paĝo $3 per uzado de ne-defaŭlta enhavomodelo \"$5\"",
+ "logentry-contentmodel-change": "$1 {{GENDER:$2|ŝanĝis}} la enhavomodelon de la paĝo $3 el \"$4\" al \"$5\"",
"logentry-contentmodel-change-revertlink": "restarigi",
"logentry-contentmodel-change-revert": "restarigi",
"protectlogpage": "Protokolo pri protektoj",
"protect-locked-blocked": "Vi ne povas ŝanĝi prokekto-nivelojn dum forbarita. Jen la nunaj ecoj de la paĝo '''$1''':",
"protect-locked-dblock": "Ne povas ŝanĝi nivelojn de protekto pro aktiva datumbaza ŝlosado.\nJen la nunaj agordoj de la paĝo '''$1''':",
"protect-locked-access": "Via konto ne havas rajton ŝanĝi protekto-nivelojn.\nJen la aktualaj valoroj por la paĝo '''$1''':",
- "protect-cascadeon": "Ĉi paĝo estas nun protektita kontraŭ redaktado ĉar ĝi estas inkluzivita en {{PLURAL:$1|jena paĝo, kiu mem estas protektita|jenaj paĝoj, kiuj mem estas protektitaj}} per kaskada protekto.\nŜanĝoj de ĝia protektonivelo ne influos la kaskadan protekton.",
+ "protect-cascadeon": "Ĉi paĝo estas nun protektita kontraŭ redaktado ĉar ĝi estas transenhavigita en {{PLURAL:$1|jena paĝo, kiu mem estas protektita|jenaj paĝoj, kiuj mem estas protektitaj}} per kaskada protekto.\nŜanĝoj de ĝia protektonivelo ne influos la kaskadan protekton.",
"protect-default": "Permesigi ĉiujn uzantojn",
"protect-fallback": "Permesi nur uzantojn kun la rajto \"$1\"",
"protect-level-autoconfirmed": "Permesi nur aŭtomate konfirmitajn uzantojn",
"undeletepagetext": "La {{PLURAL:$1|jena paĝo estis forigita|jenaj paĝoj estis forigitaj}}, sed ankoraŭ restas {{PLURAL:$1|arkivita|arkivitaj}} kaj {{PLURAL:$1|restarigebla|restarigeblaj}}.\nLa arkivo povas esti malplenigita periode.",
"undelete-fieldset-title": "Malforigi versiojn",
"undeleteextrahelp": "Por restarigi la tutan kronologion de la paĝo, lasu ĉiujn markobutonoj malŝaltitaj kaj klaku la butonon '''''{{int:undeletebtn}}'''''.\nPor restarigi selektitajn versiojn de la paĝo, marku la butonojn konformajn al la dezirataj versioj, kaj klaku la butonon '''''{{int:undeletebtn}}'''''.",
- "undeleterevisions": "$1 {{PLURAL:$1|versio arkivita|versioj arkivitaj}}",
+ "undeleterevisions": "$1 {{PLURAL:$1|versio forigita|versioj forigitaj}}",
"undeletehistory": "Se vi restarigos la paĝon, ĉiuj versioj estos restarigitaj en la historio.\nSe nova paĝo kun la sama nomo estis kreita post la forigo, la restarigitaj versioj aperos antaŭe en la antaŭa historio.",
"undeleterevdel": "Restarigo ne estos farita se ĝi rezultos en la supera paĝa aŭ dosiera versio estonte parte forigita. Tiuzake, vi malmarku aŭ malkaŝu la plej novajn forigitajn versiojn.",
"undeletehistorynoadmin": "Ĉi tiu artikolo estis forigita. La kaŭzo por la forigo estas montrata en la malsupra resumo, kune kun detaloj pri la uzantoj, kiuj redaktis ĉi tiun paĝon antaŭ la forigo. La aktuala teksto de ĉi tiuj forigitaj versioj estas atingebla nur de administrantoj.",
"whatlinkshere-hideredirs": "$1 alidirektilojn",
"whatlinkshere-hidetrans": "$1 transinkluzivaĵojn",
"whatlinkshere-hidelinks": "$1 ligilojn",
- "whatlinkshere-hideimages": "$1 ligiloj al bildo",
+ "whatlinkshere-hideimages": "$1 dosieraj ligoj",
"whatlinkshere-filters": "Filtriloj",
"whatlinkshere-submit": "Ek",
"autoblockid": "Aŭtomata forbaro #$1",
"unblock": "Malforbari uzanton",
"blockip": "Forbari {{GENDER:$1|uzanton}}",
"blockip-legend": "Forbari uzanton",
- "blockiptext": "Per jena formularo vi povas forpreni de ajna nomo aŭ IP-adreso la rajton skribi en la vikio. Oni faru tion ''nur'' por eviti vandalismon, kaj sekvante la [[{{MediaWiki:Policy-url}}|regulojn pri forbarado]]. Klarigu la precizan kialon malsupre (ekzemple, citu paĝojn, kiuj estis vandaligitaj).",
+ "blockiptext": "Uzu la sube formularon por forbari skribpermison de specifa uzantnomo aŭ IP-adreso. Tiu endus ''nur'' por eviti vandalismon, kaj laŭe la [[{{MediaWiki:Policy-url}}|politiko]].\nKlarigu la precizan kialon sube (ekzemple, citu paĝojn, kiuj estis vandaligitaj).\nVi povas forbari IP-adresan intervalon per la [https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing CIDR]a sintakso; la plej ampleksa intervalo estas /$1 por IPv4 kaj /$2 por IPv6.",
"ipaddressorusername": "IP-adreso aŭ salutnomo:",
"ipbexpiry": "Blokdaŭro",
"ipbreason": "Kialo:",
"block-log-flags-hiddenname": "salutnomo kaŝita",
"range_block_disabled": "La ebleco de administranto krei forbaritajn intervalojn da IP-adresoj estas malebligita.",
"ipb_expiry_invalid": "Nevalida blokdaŭro.",
+ "ipb_expiry_old": "Limdato antaŭas la nuntempon.",
"ipb_expiry_temp": "Kaŝitaj salutnomaj blokoj estu daŭraj.",
"ipb_hide_invalid": "Ne povas subpremi ĉi tiun konton; ĝi havas {{PLURAL:$1|unu redakton|$1 redaktojn}}.",
"ipb_already_blocked": "\"$1\" estas jam forbarita",
"lockdbsuccesstext": "La datumaro de {{SITENAME}} estas ŝlosita.\n<br />Ne forgesu malŝlosi ĝin post kiam vi finos la riparadon.",
"unlockdbsuccesstext": "La datumaro de {{SITENAME}} estas malŝlosita.",
"lockfilenotwritable": "La datumbaza dosiero pri ŝlosado ne estas skribebla. Por ŝlosi aŭ malŝlosi la datumbazon, ĉi devas esti skribebla de la TTT-servilo.",
+ "databaselocked": "Datenbazo jam estas ŝlosita.",
"databasenotlocked": "La datumbazo ne estas ŝlosita.",
"lockedbyandtime": "(de {{GENDER:$1|$1}} je $2, $3)",
"move-page": "Alinomi $1",
"export-download": "Konservi kiel dosieron",
"export-templates": "Inkluzivi ŝablonojn",
"export-pagelinks": "Inkluzivi ligitajn paĝoj al profundo de:",
+ "export-manual": "Aldoni paĝojn per uzanta efiko",
"allmessages": "Ĉiuj mesaĝoj",
"allmessagesname": "Nomo",
"allmessagesdefault": "Defaŭlta teksto",
"tooltip-pt-preferences": "{{GENDER:|Viaj}} preferoj",
"tooltip-pt-watchlist": "Listo de paĝoj kies ŝanĝojn vi priatentas.",
"tooltip-pt-mycontris": "Listo de viaj kontribuoj",
+ "tooltip-pt-anoncontribs": "Listo de redaktoj faritaj el ĉi tiu IPa adreso",
"tooltip-pt-login": "Vi estas invitita ensaluti, tamen ne estas devige.",
"tooltip-pt-logout": "Elsaluti",
"tooltip-pt-createaccount": "Ni rekomendas al vi kreon de uzantokonto kaj ensaluto; tamen, tio ne estas deviga",
"tooltip-feed-rss": "RSS-fonto por tiu ĉi paĝo",
"tooltip-feed-atom": "Atom-fonto por ĉi tiu paĝo",
"tooltip-t-contributions": "Listo de kontribuoj de {{GENDER:$1|ĉi tiu uzanto}}",
- "tooltip-t-emailuser": "Sendi retmesaĝon al tiu ĉi uzanto",
+ "tooltip-t-emailuser": "Sendi retmesaĝon al {{GENDER:$1|tiu ĉi uzantiĉo|tiu ĉi uzantino|tiu ĉi uzanto}}",
"tooltip-t-info": "Pli da informo pri ĉi tiu paĝo",
"tooltip-t-upload": "Alŝuti dosierojn",
"tooltip-t-specialpages": "Listo de ĉiuj specialaj paĝoj",
"tooltip-ca-nstab-category": "Vidi la paĝon de la kategorio",
"tooltip-minoredit": "Marki tiun ŝanĝon kiel etan",
"tooltip-save": "Konservi viajn ŝanĝojn",
+ "tooltip-publish": "Publikigi viajn ŝanĝojn",
"tooltip-preview": "Antaŭrigardi viajn ŝanĝojn. Bonvolu uzi tion antaŭ ol konservi ilin!",
"tooltip-diff": "Montri la ŝanĝojn kiujn vi faris de la teksto.",
"tooltip-compareselectedversions": "Rigardi la malsamojn inter ambaŭ selektitaj versioj de ĉi tiu paĝo.",
"tooltip-watchlistedit-raw-submit": "Ĝisdatigi atentaron",
"tooltip-recreate": "Rekrei la paĝon malgraŭ ĝi estis forigita",
"tooltip-upload": "Ekalŝuti",
- "tooltip-rollback": "\"Malvalidi\" malfaras redakto(j)n al ĉi tiu paĝo de la lasta kontribuanto per unu klako.",
+ "tooltip-rollback": "\"Malfari\" per unu klako nuligas redakto(j)n de la lasta kontribuanto al ĉi tiu paĝo.",
"tooltip-undo": "\"Malfari\" malfaris ĉi tiun redakton kaj malfermas la redakto-paĝon en antaŭvida reĝimo. Permesas aldoni kialon en la resumo.",
"tooltip-preferences-save": "Konservi preferojn",
"tooltip-summary": "Enigu mallongan resumon",
"lastmodifiedatby": "Ĉi paĝo estis laste ŝanĝita je $2, $1 de $3.",
"othercontribs": "Bazita sur la laboro de $1.",
"others": "aliaj",
- "siteusers": "{{PLURAL:$2|uzanto|uzantoj}} de {{SITENAME}} $1",
+ "siteusers": "{{GENDER:$2|uzantiĉo|uzantino|uzanto}}{{PLURAL:$2||j}} $1 de {{SITENAME}}",
"anonusers": "{{SITENAME}}-{{PLURAL:$2|anonimulo|anonimuloj}} $1",
"creditspage": "Atribuoj de paĝo",
"nocredits": "Ne estas informo pri atribuoj por ĉi paĝo.",
"pageinfo-robot-index": "Permesata",
"pageinfo-robot-noindex": "Malpermesata",
"pageinfo-watchers": "Nombro de paĝatentantoj",
+ "pageinfo-visiting-watchers": "Nombro de paĝoatendantoj kiuj vizitis la ĵusajn redaktitojn",
"pageinfo-few-watchers": "Malpli ol $1 {{PLURAL:$1|atentanto|atentantoj}}",
+ "pageinfo-few-visiting-watchers": "Eble estas aŭ eble eble ne estas paĝatendanta uzanto kiu vizitas ĵusajn redaktitojn",
"pageinfo-redirects-name": "Nombro da alidirektiloj al ĉi tiu paĝo",
"pageinfo-subpages-name": "Subpaĝoj de ĉi tiu paĝo",
"pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|alidirektilo|alidirektiloj}}; $3 {{PLURAL:$3|ne-alidirektilo|ne-alidirektiloj}})",
"pageinfo-category-files": "Nombro de dosieroj",
"markaspatrolleddiff": "Marki kiel patrolitan",
"markaspatrolledtext": "Marki ĉi tiun paĝon patrolita",
+ "markaspatrolledtext-file": "Marki ĉi tiu versio de dosiero kiel patrolita",
"markedaspatrolled": "Markita kiel patrolita",
"markedaspatrolledtext": "La elektita versio [[:$1]] estas markita kiel patrolita.",
"rcpatroldisabled": "Patrolado de lastaj ŝanĝoj malaktivigita",
"svg-long-error": "Malvalida SVG-dosiero: $1",
"show-big-image": "Fonta dosiero",
"show-big-image-preview": "Grandeco de ĉi antaŭvido: $1.",
+ "show-big-image-preview-differ": "Grando de tiu $3 antaŭprezento de tiu $2a dosiero: $1.",
"show-big-image-other": "{{PLURAL:$2|Alia distingivo|Aliaj distingivoj}}: $1.",
"show-big-image-size": "$1 × $2 rastrumeroj",
"file-info-gif-looped": "ripeta GIF",
"newimages-legend": "Dosiernomo",
"newimages-label": "Dosiernomo (aŭ parto de ĝi):",
"newimages-showbots": "Montri alŝutojn per robotoj",
+ "newimages-hidepatrolled": "Malvidigi la patrolitajn alŝutitojn",
"noimages": "Nenio videbla.",
"ilsubmit": "Serĉi",
"bydate": "laŭ dato",
"confirmemail_body_set": "Iu, supozeble vi mem, de IP-adreso $1,\nagordis la retpoŝadreson de konto \"$2\" al ĉi tiu adreso je {{SITENAME}}.\n\nPor konfirmi ke ĉi tiu konto vere apertenas al vi kaj refunkciigi la retpoŝtfunkciojn je {{SITENAME}}, bonvolu\nmalfermi la jenon ligon per via foliumilo:\n\n$3\n\nSe ĉi tiu konto *ne* apertenas al vi, bonvolu sekvi jenan ligon por nuligi la konfirmon pir la retpoŝadreso:\n\n$5\n\nĈi tiu konfirma kodo eksvalidiĝos je $4",
"confirmemail_invalidated": "Konfirmado de retadreso estas nuligita",
"invalidateemail": "Nuligi konfirmadon de retadreso",
+ "notificationemail_subject_changed": "La retpôstadreso registrita de {{SITENAME}} estis ŝanĝita",
+ "notificationemail_subject_removed": "La retpôstadreso registrita de {{SITENAME}} estis forigita",
+ "notificationemail_body_changed": "Iu, verŝajne vi, el IPa adreso $1, ŝanĝis la retpoŝtan adreson de la konto \"$2\" al \"$3\" por {{SITENAME}}.\n\nSe tio ne estis vi, kontaktu retejan administranton tuj.",
+ "notificationemail_body_removed": "Iu, verŝajne vi, el IPa adreso $1, forigis la retpoŝtan adreson de la konto \"$2\" por {{SITENAME}}.\n\nSe tio ne estis vi, kontaktu retejan administranton tuj.",
"scarytranscludedisabled": "[Intervikia transinkluzivado estas malebligita.]",
"scarytranscludefailed": "[Akiro de ŝablono $1 malsukcesis.]",
"scarytranscludefailed-httpstatus": "[Malsukcesis akiri la ŝablonon $1 : HTTP $2 ]",
"scarytranscludetoolong": "[URL-o estas tro longa]",
"deletedwhileediting": "'''Averto''': Ĉi tiu paĝo estis forigita post vi ekredaktis!",
- "confirmrecreate": "Uzanto [[User:$1|$1]] ([[User talk:$1|diskuto]]) forigis ĉi tiun paĝon post vi ekredaktis ĝin kun kialo:\n: ''$2''\nBonvolu konfirmi ke vi ja volas rekrei la paĝon.",
+ "confirmrecreate": "Uzanto [[User:$1|$1]] ([[User talk:$1|diskuto]]) forigis ĉi tiun paĝon post vi ekredaktis ĝin pro kialo:\n: <em>$2</em>\nBonvolu konfirmi ke vi ja volas rekrei la paĝon.",
"confirmrecreate-noreason": "Uzanto [[User:$1|$1]] ([[User talk:$1|diskuto-paĝo]]) forigis ĉi tiun paĝon post vi ekredaktis ĝin.\nBonvolu konfirmi ke vi ja volas rekrei la paĝon.",
"recreate": "Rekrei",
"confirm_purge_button": "Ek!",
"confirm-watch-top": "Ĉu aldoni tiun ĉi paĝon al via atentaro?",
"confirm-unwatch-button": "Ek!",
"confirm-unwatch-top": "Ĉu forigi tiun ĉi paĝon el via atentaro?",
+ "confirm-rollback-button": "Bone",
+ "confirm-rollback-top": "Malfaru redaktojn al ĉi tiu paĝo?",
"quotation-marks": "„$1“",
"imgmultipageprev": "← antaŭa paĝo",
"imgmultipagenext": "sekva paĝo →",
"timezone-local": "Loka",
"duplicate-defaultsort": "'''Averto:''' Defaŭlta ordiga ŝlosilo \"$2\" anstataŭigas pli fruan defaŭltan ordigan ŝlosilon \"$1\".",
"duplicate-displaytitle": "<strong>Atentigo:</strong> La montrata titolo \"$2\" transpasas la antaŭan titolon \"$1\".",
+ "restricted-displaytitle": "<strong>Averto:</strong> Vidiga titolo \"$1\" estis ignorita pro tio ke ĝi ne estas ekvivalenta al la efektiva titolo de la paĝo.",
"invalid-indicator-name": "<strong>Eraro:</strong> Atributo de la paĝstata indikilo <code>name</code> maldevas esti malplena.",
"version": "Versio",
"version-extensions": "Instalitaj kromprogramoj",
"version-libraries-license": "Permesilo",
"version-libraries-description": "Priskribo",
"version-libraries-authors": "Aŭtoroj",
- "redirect": "Alidirektilo laŭ dosiero, uzanto, paĝo aŭ identigilo de revizio.",
+ "redirect": "Alidirektilo laŭ dosiera, uzanta, paĝa, revizia aŭ protokola identigilo.",
"redirect-summary": "Tiu ĉi paĝo alidirektas al dosiero (laŭ ĝia nomo), paĝo (laŭ ĝia revizio-numero aŭ paĝo-identigilo) aŭ al uzantopaĝo (laŭ numera uzanto-identigilo). Uzado: [[{{#Special:Redirect}}/file/Ekzemplo.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], aŭ [[{{#Special:Redirect}}/user/101]].",
"redirect-submit": "Ek",
"redirect-lookup": "Traserĉi:",
"redirect-page": "Paĝa identigo",
"redirect-revision": "Revizio de la paĝo",
"redirect-file": "Dosiernomo",
+ "redirect-logid": "Protokola identigilo",
"redirect-not-exists": "Valoro ne trovita",
"fileduplicatesearch": "Serĉu duplikatajn dosierojn",
"fileduplicatesearch-summary": "Serĉi duplikatajn dosierojn bazite de haketvaloro.",
"tags-deactivate": "malaktivigi",
"tags-hitcount": "$1 {{PLURAL:$1|ŝanĝo|ŝanĝoj}}",
"tags-manage-no-permission": "Vi ne havas la rajton prilabori markilojn.",
+ "tags-manage-blocked": "Vi ne povas administri ŝanĝajn etikedojn dum blokita.",
"tags-create-heading": "Krei novan markilon",
"tags-create-explanation": "Nove kreitaj etikedoj estos defaŭlte disponeblaj por uzado de uzantoj kaj robotoj.",
"tags-create-tag-name": "Nomo de etikedo:",
"tags-delete-not-allowed": "Ne eblas forigi etikedojn difinitajn de etendaĵoj, krom se la etendaĵo eksplice permesas tion.",
"tags-delete-not-found": "La etikedo \"$1\" ne ekzistas.",
"tags-delete-too-many-uses": "La etikedo \"$1\" estas aldonita al pli ol $2 {{PLURAL:$2|revizio|revizioj}}, kio signifas, ke ĝi ne povas esti forigita.",
- "tags-delete-warnings-after-delete": "LA etikedo \"$1\" estis sukcese forigita, sed estis {{PLURAL:$2|trafita jena atentigo|trafitaj jenaj atentigoj}}:",
+ "tags-delete-warnings-after-delete": "La etikedo \"$1\" estis forigita, sed trafis {{PLURAL:$2|jenan averton|jenajn avertojn}}:",
+ "tags-delete-no-permission": "Vi ne havas permeson por forigi tiujn etikedojn de ŝanĝo.",
"tags-activate-title": "Aktivigi markilon",
"tags-activate-question": "Vi estas aktivigonta la markilon \"$1\".",
"tags-activate-reason": "Kialo:",
"tags-deactivate-not-allowed": "Ne eblas malaktivigi la etikedon \"$1\".",
"tags-deactivate-submit": "Malaktivigi",
"tags-apply-no-permission": "Vi ne havas permeson por aldoni ŝanĝo-etikedojn al viaj ŝanĝoj.",
+ "tags-apply-blocked": "Vi ne povas apliki etikedojn de ŝanĝo kune kun viaj ŝanĝoj dum blokita.",
"tags-apply-not-allowed-one": "La etikedon \"$1\" ne eblas aldoni permane.",
"tags-apply-not-allowed-multi": "Ne estas permesite permane aldoni {{PLURAL:$2|jenan etikedon|jenajn etikedojn}}: $1",
"tags-update-no-permission": "Vi ne havas permeson por aldoni aŭ forigi ŝanĝo-etikedojn de unuopaj revizioj aŭ protokoleroj.",
+ "tags-update-blocked": "Vi ne povas aldoni aŭ forigi etikedojn de ŝanĝo dum blokita.",
"tags-update-add-not-allowed-one": "Ne estas permesite permane aldoni la etikedon \"$1\".",
"tags-update-add-not-allowed-multi": "Ne estas permesite permane aldoni {{PLURAL:$2|jenan etikedon|jenajn etikedojn}}: $1",
"tags-update-remove-not-allowed-one": "Ne estas permesite permane forigi la etikedon \"$1\".",
"tags-edit-reason": "Kialo:",
"tags-edit-revision-submit": "Apliki ŝanĝojn al {{PLURAL:$1|tiu ĉi revizio|$1 revizioj}}",
"tags-edit-logentry-submit": "Apliki ŝanĝojn al {{PLURAL:$1|tiu ĉi protokolero|$1 protokoleroj}}",
- "tags-edit-success": "La ŝanĝoj estis sukcese aplikitaj.",
+ "tags-edit-success": "Aplikis la ŝanĝojn.",
"tags-edit-failure": "La ŝanĝojn ne eblis apliki:\n$1",
"tags-edit-nooldid-title": "Nevalida cela revizio",
"tags-edit-nooldid-text": "Vi specifis neniun celan revizion por efektivigi la funkcion aŭ la specifita revizio ne ekzistas.",
"htmlform-cloner-create": "Aldoni plian",
"htmlform-cloner-delete": "Forigi",
"htmlform-cloner-required": "Almenaŭ unu valoro estas nepra.",
+ "htmlform-title-badnamespace": "[[:$1]] ne estas en \"{{ns:$2}}\" nomspaco.",
+ "htmlform-title-not-creatable": "\"$1\" estas nekreebla titolo por paĝo",
"htmlform-title-not-exists": "$1 ne ekzistas.",
"htmlform-user-not-exists": "<strong>$1</strong> ne ekzistas.",
"htmlform-user-not-valid": "<strong>$1</strong> ne estas valida salutnomo.",
"feedback-useragent": "Klienta aplikaĵo:",
"searchsuggest-search": "Serĉi",
"searchsuggest-containing": "enhavas...",
+ "api-error-autoblocked": "Via IPa adreso estis blokita aŭtomate, ĉar ĝi estis uzita far forbara uzanto.",
"api-error-badaccess-groups": "Vi ne havas permeson alŝuti dosierojn al tiu ĉi vikio.",
"api-error-badtoken": "Interna eraro: fuŝaĵo.",
+ "api-error-blocked": "Vi estis blokita pri redakto.",
"api-error-copyuploaddisabled": "Alŝuto per URL-adreso estas malebligata en tiu ĉi servilo.",
- "api-error-duplicate": "Jam estas {{PLURAL:$1|alia dosiero|pluraj aliaj dosieroj}} de sama enhavo en la retejo.",
+ "api-error-duplicate": "Jam estas {{PLURAL:$1|alia dosiero|pluraj aliaj dosieroj}} en la retejo kun la sama enhavo.",
"api-error-duplicate-archive": "Jam estis {{PLURAL:$1|alia dosiero|pluraj aliaj dosieroj}} de sama enhavo en la retejo, sed {{PLURAL:$1|ĝi estis forigita|ili estis forigitaj}}.",
"api-error-empty-file": "La dosiero kiun vi sendis estis malplena.",
"api-error-emptypage": "Kreo de novaj malplenaj paĝoj ne estas permesita.",
"api-error-nomodule": "Interna eraro: ne troveblas alŝuta helpilaro.",
"api-error-ok-but-empty": "Interna eraro: nenia respondo de la servilo.",
"api-error-overwrite": "Anstataŭigo de ekzistanta dosiero ne permesatas.",
+ "api-error-ratelimited": "Vi provas alŝuti pli da dosieroj dum mallonga periodo ol ĉi tiu vikio permesas.\nBonvolu provi denove en kelkaj minutoj.",
"api-error-stashfailed": "Interna eraro: la servilo malsukcesis stoki provizoran dosieron.",
"api-error-publishfailed": "Interna eraro: Servilo malsukcesis eldoni provizoran dosieron.",
"api-error-stasherror": "Eraro okazis dum alŝutado de la dosiero al dosierujo.",
"api-error-unknownerror": "Nekonata eraro: \"$1\"",
"api-error-uploaddisabled": "Alŝutato estas malebligata en tiu ĉi vikio.",
"api-error-verification-error": "Tiu ĉi dosiero eble estas difektita, aŭ havas la malĝustan dosieran finaĵon.",
+ "api-error-was-deleted": "Dosiero kun ĉi tiu nomo estis antaŭe alŝutita kaj sekvente forigita.",
"duration-seconds": "$1 {{PLURAL:$1|sekundo|sekundoj}}",
"duration-minutes": "$1 {{PLURAL:$1|minuto|minutoj}}",
"duration-hours": "$1 {{PLURAL:$1|horo|horoj}}",
"expand_templates_preview": "Antaŭrigardo",
"expand_templates_preview_fail_html": "<em>Ĉar {{SITENAME}} ebligas enmeton de kruda HTML kaj sesiaj datumoj estis perditaj, antaŭvido estas kaŝita kiel protekto kontraŭ Ĝavoskriptaj atakoj.</em>\n\n<strong>Se tio estis legitima provo antaŭvidi, bonvolu reprovi.</strong>\nSe tio daŭre ne funkcias, provu [[Special:UserLogout|elsaluti]] kaj ree ensaluti.",
"expand_templates_preview_fail_html_anon": "<em>Ĉar {{SITENAME}} ebligas enmeton de kruda HTML kaj vi ne estas ensalutinta, antaŭvido estas kaŝita kiel protekto kontraŭ Ĝavoskriptaj atakoj.</em>\n\n<strong>Se tio estis legitima provo antaŭvidi, bonvolu [[Special:UserLogin|ensaluti]] kaj reprovi.</strong>",
- "pagelanguage": "Elektilo de lingvo de paĝo",
+ "expand_templates_input_missing": "Vi nepras provizi almenaŭ iom da eniga teksto.",
+ "pagelanguage": "Ŝanĝi paĝan lingvon",
"pagelang-name": "Paĝo",
"pagelang-language": "Lingvo",
"pagelang-use-default": "Uzi defaŭltan lingvon",
"pagelang-select-lang": "Elekti la lingvon",
+ "pagelang-submit": "Ek!",
"right-pagelang": "Ŝanĝi paĝan lingvon",
"action-pagelang": "ŝanĝi la lingvon de la paĝo",
- "log-name-pagelang": "Ŝanĝi la lingvan protokolon",
+ "log-name-pagelang": "Protokolo pri lingvajn ŝanĝojn",
"log-description-pagelang": "Jen protokolo pri ŝanĝoj de paĝaj lingvoj.",
- "logentry-pagelang-pagelang": "$1 {{GENDER:$2|ŝanĝis}} la paĝan lingvon por $3 de $4 al $5.",
+ "logentry-pagelang-pagelang": "$1 {{GENDER:$2|ŝanĝis}} paĝan lingvon pri $3 el $4 al $5.",
"default-skin-not-found": "Ups! La defaŭlta etoso por via vikio, difinita en <code dir=\"ltr\">$wgDefaultSkin</code> kiel <code>$1</code> ne estas disponebla.\n\nŜajnas, ke via instalaĵo enhavas {{PLURAL:$4|jenan etoson|jenajn etosojn}}. Vidu [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manlibro:Agordado de etosoj] por informoj kiel {{PLURAL:$4|ĝin ŝalti|ilin ŝalti kaj elekti la defaŭltan}}.\n\n$2\n\n; Se vi ĵus instalis MediaWiki:\n: Vi probable instalis de git aŭ rekte de fontokodo per alia metodo. Tio estas antaŭsupozata. MediaWiki 1.24 kaj pli novaj versioj enhavas neniun etoson en la ĉefa deponejo. Provu instali iujn etosojn de [https://www.mediawiki.org/wiki/Category:All_skins etosa dosierujo en mediawiki.org] per jenaj metodoj:\n:* Elŝutu [https://www.mediawiki.org/wiki/Download pakitan instalilon], kiu enhavas kelkajn etosojn kaj etendaĵojn. Vi povas de ĝi kopii kaj alglui la dosierujon <code>skins/</code>.\n:* Elŝutu unuopajn pakitajn etosojn de [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Uzu Git por elŝuti etosojn].\n: Tio maldevus interkolizii kun via git-deponejo se vi estas evoluiganto de MediaWiki.\n\n; Se vi ĵus promociis MediaWiki:\n: MediaWiki 1.24 kaj pli novaj ne plu aŭtomate ŝaltas instalitajn etosojn (vidu [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manlibro:Aŭtomata malkovrado de etosoj]). Vi povas alglui {{PLURAL:$5|jenan linion|jenajn liniojn}} al <code>LocalSettings.php</code> por ŝalti {{PLURAL:$5|la instalitan etoson|ĉiujn instalitajn etosojn}}:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Se vi ĵus modifis <code>LocalSettings.php</code>:\n: Denove kontrolu nomon de etosoj pro eblaj mistajpoj.",
"default-skin-not-found-no-skins": "Ups! La defaŭlta etoso por via vikio, difinita en <code>$wgDefaultSkin</code> kiel <code>$1</code> ne estas disponebla.\n\nVi havas neniun instalitan etson.\n\n; Se vi ĵus instalis aŭ promocii MediaWiki:\n: Vi probable instalis de git aŭ rekte de fontokodo per alia metodo. Tio estas antaŭspozata. MediaWiki 1.24 kaj pli novaj versioj enhavas neniun etoson en la ĉefa deponejo. Provu instali iujn etosojn de [https://www.mediawiki.org/wiki/Category:All_skins etosa dosierujo en mediawiki.org] per jenaj metodoj:\n:* Elŝutu [https://www.mediawiki.org/wiki/Download pakitan instalilon], kiu enhavas kelkajn eosojn kaj etendaĵojn. Vi povas de ĝi kopii kaj alglui la dosierujon <code>skins/</code>.\n:* Elŝutu unuopajn pakitajn etosojn de [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Uzu Git por elŝuti etosojn].\n: Tio maldevus interkolizii kun via git-deponejo se vi estas evoluiganto de MediaWiki. Vidu [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manlibro:Agordado de etosoj] por informoj kiel ŝalti etosojn kaj elekti la defaŭltan.",
"default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (ŝalta)",
"mediastatistics": "Statistikoj pri dosieroj",
"mediastatistics-summary": "Statistiko pri tipoj de alŝutitaj dosieroj. Tio ĉi inkludas nur aktualajn versiojn de dosiero. Malnovaj aŭ forigitaj versioj de dosieroj estas ekskluditaj.",
"mediastatistics-nbytes": "{{PLURAL:$1|$1 bitoko|$1 bitokoj}} ($2; $3%)",
+ "mediastatistics-allbytes": "Totala dosiera grandeco por ĉiuj dosieroj: {{PLURALO:$1|$1 okumo|$1 okumoj}} ($2).",
"mediastatistics-table-mimetype": "MIME-tipo",
"mediastatistics-table-extensions": "Eblaj dosier-sufiksoj",
"mediastatistics-table-count": "Nombro de dosieroj",
"mediastatistics-header-text": "Tekstaj",
"mediastatistics-header-executable": "Plenumeblaj dosieroj",
"mediastatistics-header-archive": "Densigitaj formoj",
+ "mediastatistics-header-total": "Ĉiuj dosieroj",
"json-warn-trailing-comma": "De JSON estis {{PLURAL:$1|forigita fina komo|forigitaj finaj komoj}}",
"json-error-unknown": "Okazis problemo pri JSON. Eraro: $1",
"json-error-depth": "Maksimuma profundeco de stako estis superita",
"special-characters-group-ipa": "IPA",
"special-characters-group-symbols": "Simboloj",
"special-characters-group-greek": "Greka",
+ "special-characters-group-greekextended": "Greka etendita",
"special-characters-group-cyrillic": "Cirila",
"special-characters-group-arabic": "Araba",
"special-characters-group-arabicextended": "araba etendite",
"special-characters-title-endash": "mallonga streketo",
"special-characters-title-emdash": "longa streketo",
"special-characters-title-minus": "minus-signo",
+ "mw-widgets-dateinput-no-date": "Neniu dato elektita",
"mw-widgets-dateinput-placeholder-day": "JJJJ-MM-TT",
"mw-widgets-dateinput-placeholder-month": "JJJJ-MM",
"mw-widgets-titleinput-description-new-page": "paĝo ankoraŭ ne ekzistas",
- "mw-widgets-titleinput-description-redirect": "alidirektas al $1",
+ "mw-widgets-titleinput-description-redirect": "alidirekti al $1",
"api-error-blacklisted": "Bonvolu elekti alian, priskriban titolon.",
+ "sessionmanager-tie": "Kombini diversajn tipojn de ensaluta peto ne estas permisita: $1.",
"sessionprovider-generic": "$1 seancoj",
"sessionprovider-mediawiki-session-cookiesessionprovider": "kuketaj seancoj",
+ "sessionprovider-nocookies": "Kuketojn eble maluzpermisas. Certigu ke vi uzpermisas kuketojn kaj pravu denove.",
"randomrootpage": "Hazarda radika paĝo",
+ "log-action-filter-block": "Tipo de forbaro:",
+ "log-action-filter-contentmodel": "Tipo de enhavomodela ŝanĝo:",
+ "log-action-filter-delete": "Tipo de forviŝigado:",
+ "log-action-filter-import": "Tipo de importado:",
+ "log-action-filter-managetags": "Tipo de administrada ago pri etikedo:",
+ "log-action-filter-move": "Tipo de alinomado:",
+ "log-action-filter-newusers": "Tipo de konta kreado:",
+ "log-action-filter-patrol": "Tipo de patrolado:",
+ "log-action-filter-protect": "Tipo de protektad:",
+ "log-action-filter-rights": "Tipo de rajta ŝanĝo",
+ "log-action-filter-suppress": "Tipo de forigado",
+ "log-action-filter-upload": "Tipo de alŝutado:",
"log-action-filter-all": "Ĉia",
"log-action-filter-block-block": "Forbari",
+ "log-action-filter-block-reblock": "Forbari ŝanĝon",
+ "log-action-filter-block-unblock": "Malforbari",
+ "log-action-filter-contentmodel-change": "Ŝanĝo de enhavomodelon",
+ "log-action-filter-contentmodel-new": "Kreo de paĝo kun ne-norma enhavomodelo",
+ "log-action-filter-delete-delete": "Forviŝigado de paĝo",
+ "log-action-filter-delete-restore": "Malforviŝigado de paĝo",
+ "log-action-filter-delete-event": "Forviŝigado de protokolo",
+ "log-action-filter-delete-revision": "Forviŝigado de rivizio",
+ "log-action-filter-import-interwiki": "Importado de Transwiki",
+ "log-action-filter-import-upload": "Importaĵo per XMLa alŝuto",
+ "log-action-filter-managetags-create": "Etikeda kreo",
+ "log-action-filter-managetags-delete": "Etikeda forviŝigado",
+ "log-action-filter-managetags-activate": "Etikeda ekebligado",
+ "log-action-filter-managetags-deactivate": "Etikeda malekebligado",
+ "log-action-filter-move-move": "Alinomi sen anstataŭigi alidirektojn",
+ "log-action-filter-newusers-create2": "Kreo de registrita uzanton",
+ "log-action-filter-newusers-autocreate": "Aŭtomata kreo",
+ "log-action-filter-newusers-byemail": "Kreo kun pasvorto sendita per retpoŝto",
+ "log-action-filter-patrol-patrol": "Malaŭtomata patrolo",
+ "log-action-filter-patrol-autopatrol": "Aŭtomata patrolo",
+ "log-action-filter-protect-protect": "Protekto",
+ "log-action-filter-protect-modify": "Modifo de la protekto",
"log-action-filter-protect-unprotect": "Malprotektado",
+ "log-action-filter-rights-rights": "Malaŭtomata ŝanĝo",
+ "log-action-filter-rights-autopromote": "Aŭtomata ŝanĝo",
"log-action-filter-upload-upload": "Novalŝuta",
- "log-action-filter-upload-overwrite": "Realŝuta"
+ "log-action-filter-upload-overwrite": "Realŝuta",
+ "authmanager-authplugin-setpass-bad-domain": "Malvalida domajno.",
+ "authmanager-autocreate-noperm": "Aŭtomata kreo de konto ne estas permesita.",
+ "authmanager-autocreate-exception": "Aŭtomata kreo de konto estas provizore malfunkciigita pro antaŭaj eraroj.",
+ "authmanager-userdoesnotexist": "Uzanto-konto \"$1\" ne estas registrita.",
+ "authmanager-username-help": "Salutnomo por aŭtentikado.",
+ "authmanager-email-help": "Retpoŝtadreso",
+ "authmanager-realname-label": "Vera nomo",
+ "authmanager-realname-help": "Vera nomo de la uzanto",
+ "changecredentials-submit": "Ŝanĝi",
+ "removecredentials-submit": "Forigi",
+ "linkaccounts": "Ligi kontojn",
+ "linkaccounts-submit": "Ligi kontojn"
}
"Transonlohk",
"Eloy",
"Lemondoge",
- "Jdforrester"
+ "Jdforrester",
+ "Indiralena",
+ "Rubentl134",
+ "Codynguyen1116",
+ "2axterix2",
+ "Matma Rex"
]
},
"tog-underline": "Subrayar los enlaces:",
"tog-watchdefault": "Añadir las páginas y archivos que edite a mi lista de seguimiento",
"tog-watchmoves": "Añadir las páginas y archivos que mueva a mi lista de seguimiento",
"tog-watchdeletion": "Añadir las páginas y archivos que borre a mi lista de seguimiento",
- "tog-watchuploads": "Agregar nuevos archivos puedo subir a mi lista de favoritos",
+ "tog-watchuploads": "Agregar los archivos nuevos que suba a mi lista de seguimiento",
"tog-watchrollback": "Añadir las páginas donde haya realizado una reversión a mi lista de seguimiento",
"tog-minordefault": "Marcar todas las ediciones como menores de manera predeterminada",
"tog-previewontop": "Mostrar previsualización antes del cuadro de edición",
"tog-ccmeonemails": "Recibir copias de los correos electrónicos que envíe a otros usuarios",
"tog-diffonly": "No mostrar el contenido de la página debajo de la lista de diferencias",
"tog-showhiddencats": "Mostrar categorías ocultas",
- "tog-norollbackdiff": "Omitir la lista de diferencias después de revertir",
+ "tog-norollbackdiff": "No mostrar la lista de diferencias después de revertir",
"tog-useeditwarning": "Avisarme cuando abandone una página en edición con cambios sin guardar",
"tog-prefershttps": "Utilizar siempre conexiones seguras en mis sesiones",
"underline-always": "Siempre",
"password-change-forbidden": "No puedes cambiar las contraseñas en este wiki.",
"externaldberror": "Hubo un error de autenticación en la base de datos, o bien no tienes autorización para actualizar tu cuenta externa.",
"login": "Acceder",
+ "login-security": "Verifica tu identidad",
"nav-login-createaccount": "Acceder/crear cuenta",
"userlogin": "Acceder/crear cuenta",
"userloginnocreate": "Acceder",
"userlogin-resetpassword-link": "¿Has olvidado tu contraseña?",
"userlogin-helplink2": "Ayuda con el acceso",
"userlogin-loggedin": "Ya estás {{GENDER:$1|conectado|conectada}} como $1.\nUsa el formulario de abajo para iniciar sesión como otro usuario.",
+ "userlogin-reauth": "Debes iniciar sesión de nuevo para verificar que eres {{GENDER:$1|$1}}.",
"userlogin-createanother": "Crear otra cuenta",
"createacct-emailrequired": "Dirección de correo electrónico",
"createacct-emailoptional": "Dirección de correo electrónico (opcional)",
"createacct-email-ph": "Escribe tu dirección de correo electrónico",
"createacct-another-email-ph": "Escribe la dirección de correo electrónico",
"createaccountmail": "Utilizar una contraseña aleatoria temporal y enviarla a la dirección de correo electrónico especificada",
+ "createaccountmail-help": "Puede usarse para crear una cuenta para otra persona sin revelar la contraseña.",
"createacct-realname": "Nombre real (opcional)",
"createaccountreason": "Motivo:",
"createacct-reason": "Motivo",
"createacct-reason-ph": "Por qué estás creando otra cuenta",
+ "createacct-reason-help": "Mensaje que se muestra en el registro de creación de cuentas",
"createacct-submit": "Crea tu cuenta",
"createacct-another-submit": "Crear cuenta",
+ "createacct-continue-submit": "Continuar con la creación de la cuenta",
+ "createacct-another-continue-submit": "Continuar con la creación de la cuenta",
"createacct-benefit-heading": "Personas como tú son las que construyen {{SITENAME}}.",
"createacct-benefit-body1": "{{PLURAL:$1|edición|ediciones}}",
"createacct-benefit-body2": "{{PLURAL:$1|página|páginas}}",
"nocookiesnew": "Se ha creado la cuenta de usuario, pero aún no has iniciado sesión.\n{{SITENAME}} usa <em>cookies</em> para identificar a los usuarios registrados.\nTu navegador tiene desactivadas las cookies.\nPor favor, actívalas e inicia sesión con tu nuevo nombre de usuario y contraseña.",
"nocookieslogin": "{{SITENAME}} utiliza <em>cookies</em> para la autenticación de usuarios. Las <em>cookies</em> están desactivadas en tu navegador. Por favor, actívalas e inténtalo de nuevo.",
"nocookiesfornew": "No se pudo crear la cuenta de usuario, porque no pudimos confirmar su origen.\nAsegúrate de que tienes las cookies activadas, luego recarga esta página e inténtalo de nuevo.",
+ "createacct-loginerror": "La cuenta se ha creado correctamente, pero no se pudo ingresar automáticamente. Procede al [[Special:UserLogin|acceso manual]].",
"noname": "No se ha especificado un nombre de usuario válido.",
"loginsuccesstitle": "Has accedido",
"loginsuccess": "<strong>Has accedido a {{SITENAME}} como «$1».</strong>",
- "nosuchuser": "No existe ningún usuario llamado «$1».\nLos nombres de usuario son sensibles a las mayúsculas.\nRevisa tu ortografía, o [[Special:UserLogin/signup|crea una cuenta nueva]].",
+ "nosuchuser": "No existe ningún usuario llamado «$1».\nLos nombres de usuario son sensibles a las mayúsculas.\nRevisa tu ortografía, o [[Special:CreateAccount|crea una cuenta nueva]].",
"nosuchusershort": "No existe ningún usuario llamado «$1». Comprueba que lo has escrito correctamente.",
"nouserspecified": "Debes especificar un nombre de usuario.",
"login-userblocked": "No puedes iniciar sesión porque tu cuenta está bloqueada.",
"createacct-another-realname-tip": "El nombre real es opcional.\nSi lo proporcionas, se usará para dar atribución al trabajo del usuario.",
"pt-login": "Acceder",
"pt-login-button": "Acceder",
+ "pt-login-continue-button": "Continuar inicio de sesión",
"pt-createaccount": "Crear una cuenta",
"pt-userlogout": "Salir",
"php-mail-error-unknown": "Error desconocido en la función mail() de PHP.",
"botpasswords-invalid-name": "El nombre de usuario especificado no contiene el separador de contraseña de bot (\"$1\").",
"botpasswords-not-exist": "El usuario \"$1\" no tiene una contraseña de bot llamada \"$2\".",
"resetpass_forbidden": "No se pueden cambiar las contraseñas",
+ "resetpass_forbidden-reason": "Las contraseñas no pueden cambiarse: $1",
"resetpass-no-info": "Debes iniciar sesión para acceder directamente a esta página.",
"resetpass-submit-loggedin": "Cambiar contraseña",
"resetpass-submit-cancel": "Cancelar",
"passwordreset-emailsentusername": "Si existe una dirección de correo electrónico asociada a este nombre de usuario, entonces se enviará un correo para restablecer la contraseña.",
"passwordreset-emailsent-capture": "Se ha enviado un correo para el restablecimiento de la contraseña, el cual se muestra a continuación.",
"passwordreset-emailerror-capture": "Se ha generado un correo electrónico de restablecimiento de contraseña, que se muestra a continuación, pero ha fallado el envío {{GENDER:$2|al usuario|a la usuaria}}: $1",
+ "passwordreset-emailsent-capture2": "{{PLURAL:$1|El e-mail de restablecimiento de contraseña ha sido enviado|Los e-mails de restablecimiento de contraseña han sido enviados}}. {{PLURAL:$1|El nombre de usuario y la contraseña se muestra a continuación|La lista de nombres de usuarios y contraseñas se muestra a continuación}}.",
+ "passwordreset-emailerror-capture2": "No fue posible mandar un correo electrónico {{Gender:$2|al usuario|a la usuaria}}: $1 {{PLURAL:$3|El nombre de usuario y la contraseña|La lista de nombres de usuarios y contraseñas}} se muestra a continuación.",
+ "passwordreset-invalideamil": "Dirección de correo electrónico no válida.",
+ "passwordreset-nodata": "No se ha proporcionado ni un nombre de usuario ni una dirección de correo electrónico",
"changeemail": "Cambiar o eliminar la dirección de correo electrónico",
"changeemail-header": "Completa este formulario para cambiar tu dirección de correo electrónico. Si quieres eliminar la asociación de cualquier dirección de correo electrónico con tu cuenta, deja en blanco la nueva dirección de correo electrónico cuando envíes el formulario.",
"changeemail-passwordrequired": "Tendrás que escribir tu contraseña para confirmar este cambio.",
"accmailtext": "Se ha enviado a $2 una contraseña generada aleatoriamente para [[User talk:$1|$1]]. Una vez iniciada la sesión, se puede cambiar en la página [[Special:ChangePassword|destinada para ello]].",
"newarticle": "(Nuevo)",
"newarticletext": "Has seguido un enlace a una página que aún no existe.\nPara crear esta página, escribe en el cuadro que aparece a continuación. Para más información, consulta la [$1 página de ayuda].\nSi llegaste aquí por error, vuelve a la página anterior.",
- "anontalkpagetext": "---- ''Esta es la página de discusión de un usuario anónimo que aún no ha creado una cuenta, o no la usa. Por lo tanto, tenemos que usar su dirección IP para identificarlo. Puede que varios usuarios compartan una misma dirección IP. Si eres un usuario anónimo y crees que se han dirigido a ti con comentarios improcedentes, por favor [[Special:UserLogin/signup|crea una cuenta]] o, si ya la tienes, [[Special:UserLogin|identifícate]] para evitar confusiones futuras con otros usuarios anónimos.''",
+ "anontalkpagetext": "----\n<em>Esta es la página de discusión de un usuario anónimo que aún no ha creado una cuenta, o no la usa.</em>\nPor lo tanto, tenemos que usar su dirección IP para identificarlo.\nPuede que varios usuarios compartan una misma dirección IP.\nSi eres un usuario anónimo y crees que se han dirigido a ti con comentarios improcedentes, [[Special:CreateAccount|crea una cuenta]] o [[Special:UserLogin|inicia sessión]] para evitar confusiones futuras con otros usuarios anónimos.",
"noarticletext": "En este momento no hay texto en esta página.\nPuedes [[Special:Search/{{PAGENAME}}|buscar el título de esta página]] en otras páginas,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar en los registros relacionados],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} crear esta página]</span>.",
"noarticletext-nopermission": "Actualmente no hay texto en esta página.\nPuedes [[Special:Search/{{PAGENAME}}|buscar este título de página]] en otras páginas, o <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar en los registros relacionados]</span>, pero no tienes permiso para crear esta página.",
"missing-revision": "La revisión n.º $1 de la página «{{FULLPAGENAME}}» no existe.\n\nEsto suele ocurrir cuando se sigue un enlace de historial obsoleto que apunta a una página ya borrada.\nPuedes encontrar detalles en el [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de borrados].",
"group-bot": "Bots",
"group-sysop": "Administradores",
"group-bureaucrat": "Burócratas",
- "group-suppress": "Supresores",
+ "group-suppress": "Supresores de Flow",
"group-all": "(todos)",
"group-user-member": "{{GENDER:$1|usuario|usuaria}}",
"group-autoconfirmed-member": "{{GENDER:$1|autoconfirmado|autoconfirmada}}",
"group-bot-member": "{{GENDER:$1|bot}}",
"group-sysop-member": "{{GENDER:$1|administrador|administradora}}",
"group-bureaucrat-member": "{{GENDER:$1|burócrata}}",
- "group-suppress-member": "{{GENDER:$1|supresor|supresora}}",
+ "group-suppress-member": "{{GENDER:$1|supresor|supresora}} de Flow",
"grouppage-user": "{{ns:project}}:Usuarios",
"grouppage-autoconfirmed": "{{ns:project}}:Autoconfirmados",
"grouppage-bot": "{{ns:project}}:Bots",
"grouppage-sysop": "{{ns:project}}:Administradores",
"grouppage-bureaucrat": "{{ns:project}}:Burócratas",
- "grouppage-suppress": "{{ns:project}}:Supresores",
+ "grouppage-suppress": "{{ns:project}}:Supresores de Flow",
"right-read": "Leer páginas",
"right-edit": "Editar páginas",
"right-createpage": "Crear páginas que no sean de discusión",
"right-override-export-depth": "Exportar páginas, incluyendo aquellas enlazadas hasta una profundidad de 5",
"right-sendemail": "Enviar correo electrónico a otros usuarios",
"right-passwordreset": "Ver los mensajes de restablecimiento de contraseña",
- "right-managechangetags": "Crear y eliminar [[Special:Tags|etiquetas]] en la base de datos",
+ "right-managechangetags": "Crear y (des)activar [[Special:Tags|etiquetas]]",
"right-applychangetags": "Aplicar [[Special:Tags|etiquetas]] junto con los cambios propios",
"right-changetags": "Agregar y quitar [[Special:Tags|etiquetas]] arbitrarias a revisiones individuales y entradas del registro",
+ "right-deletechangetags": "Eliminar [[Special:Tags|tags]] de la base de datos",
"grant-generic": "Paquete de permisos \"$1\"",
"grant-group-page-interaction": "Interactuar con páginas",
"grant-group-file-interaction": "Interactuar con multimedia",
"action-viewmyprivateinfo": "ver tu información privada",
"action-editmyprivateinfo": "editar tu información privada",
"action-editcontentmodel": "editar el modelo de contenido de una página",
- "action-managechangetags": "crear y eliminar etiquetas en la base de datos",
+ "action-managechangetags": "crear y (des)activar etiquetas",
"action-applychangetags": "aplicar etiquetas junto con los cambios",
"action-changetags": "agregar y quitar etiquetas arbitrarias a revisiones individuales y entradas del registro",
+ "action-deletechangetags": "eliminar etiquetas de la base de datos",
"nchanges": "$1 {{PLURAL:$1|cambio|cambios}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde la última visita}}",
"enhancedrc-history": "historial",
"upload-form-label-own-work": "Esto es mi trabajo propio",
"upload-form-label-infoform-categories": "Categorías",
"upload-form-label-infoform-date": "Fecha",
- "upload-form-label-own-work-message-local": "Confirmo que estoy subiendo este archivo siguiendo los términos del servicio y las políticas de concesión de licencias en {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Si no es capaz de subir este archivo bajo las políticas de {{SITENAME}}, por favor cierre este cuadro de diálogo e intente otro método.",
- "upload-form-label-not-own-work-local-local": "Quizás también quieras probar [[Special:Upload|la página predeterminada de subidas]].",
- "upload-form-label-own-work-message-default": "Entiendo que voy a subir este archivo a un repositorio compartido. Confirmo que estoy haciéndolo que siguiendo los términos de servicio y políticas de licenciamiento de allí.",
- "upload-form-label-not-own-work-message-default": "Si usted no es capaz de cargar este archivo en virtud de las políticas del repositorio compartido, por favor cierre este cuadro de diálogo y probar con otro método.",
- "upload-form-label-not-own-work-local-default": "Puede que también quieras usar [[Special:Upload|la página de subidas en {{SITENAME}}]], si se puede subir este archivo bajo sus políticas.",
- "upload-form-label-own-work-message-shared": "Doy fe que soy dueño de los derechos de autor de este archivo, y acepto irrevocablemente liberar este archivo a Wikimedia Commons bajo la licencia [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], y acepto los [https://wikimediafoundation.org/wiki/Terms_of_Use Términos de Uso].",
- "upload-form-label-not-own-work-message-shared": "Si no es dueño de los derechos de autor de este archivo, o desea publicarlo bajo una licencia diferentes, considere usar el [https://commons.wikimedia.org/wiki/Special:UploadWizard Asistente de Carga de Commons].",
- "upload-form-label-not-own-work-local-shared": "Puede que también quieras usar [[Special:Upload|la página de subidas en {{SITENAME}}]], si el sitio permite la subida de este archivo bajo sus políticas.",
+ "upload-form-label-own-work-message-generic-local": "Confirmo que estoy subiendo este archivo siguiendo los términos del servicio y las políticas de concesión de licencias en {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Si no es capaz de subir este archivo bajo las políticas de {{SITENAME}}, por favor cierre este cuadro de diálogo e intente otro método.",
+ "upload-form-label-not-own-work-local-generic-local": "Quizás también quieras probar [[Special:Upload|la página predeterminada de subidas]].",
+ "upload-form-label-own-work-message-generic-foreign": "Entiendo que voy a subir este archivo a un repositorio compartido. Confirmo que estoy haciéndolo que siguiendo los términos de servicio y políticas de licenciamiento de allí.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Si usted no es capaz de cargar este archivo en virtud de las políticas del repositorio compartido, por favor cierre este cuadro de diálogo y probar con otro método.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Puede que también quieras usar [[Special:Upload|la página de subidas en {{SITENAME}}]], si se puede subir este archivo bajo sus políticas.",
"backend-fail-stream": "No se pudo transmitir el archivo «$1».",
"backend-fail-backup": "No se pudo hacer copia de seguridad del archivo «$1».",
"backend-fail-notexists": "El archivo $1 no existe.",
"trackingcategories-msg": "Categoría de seguimiento",
"trackingcategories-name": "Nombre del mensaje",
"trackingcategories-desc": "Criterios de inclusión de categoría",
+ "restricted-displaytitle-ignored-desc": "Esta página tiene una plantilla <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> ignorada porque no es equivalente al título verdadero de la página.",
"noindex-category-desc": "La página contiene la palabra mágica <code><nowiki>__NOINDEX__</nowiki></code> (y está en un espacio de nombres donde la función está activada); y por ello los robots no la indizan.",
"index-category-desc": "La página contiene la palabra mágica <code><nowiki>__INDEX__</nowiki></code> (y está en un espacio de nombres donde la función está activada); y por ello los robots la indizarán.",
"post-expand-template-inclusion-category-desc": "Después de expandir todas las plantillas, el tamaño de la página es más grande que <code>$wgMaxArticleSize</code>, así que algunas plantillas no se expandieron.",
"revertpage": "Revertidos los cambios de [[Special:Contributions/$2|$2]] ([[User talk:$2|disc.]]) a la última edición de [[User:$1|$1]]",
"revertpage-nouser": "Revertidas las ediciones hechas por un usuario oculto a la última revisión hecha por {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Revertidas las ediciones de $1; recuperada la última versión de $2.",
+ "rollback-success-notify": "Revertidas las ediciones de $1 hasta la última revisión de $2. [$3 Ver cambios]",
"sessionfailure-title": "Error de sesión",
"sessionfailure": "Parece que hay un problema con tu sesión;\nesta acción ha sido cancelada como medida de precaución contra secuestros de sesión.\nPor favor, pulsa «Atrás», recarga la página de la que viniste e inténtalo de nuevo.",
"changecontentmodel": "Cambiar el modelo de contenido de una página",
"changecontentmodel-success-text": "Se ha cambiado el tipo de contenido de [[:$1]].",
"changecontentmodel-cannot-convert": "El contenido de [[:$1]] no se puede convertir a un tipo de $2.",
"changecontentmodel-nodirectediting": "El modelo de contenido $1 no admite la edición directa",
+ "changecontentmodel-emptymodels-title": "No hay modelos de contenido disponibles",
"log-name-contentmodel": "Registro de cambios del modelo de contenido",
"log-description-contentmodel": "Eventos relacionados con los modelos de contenido de una página",
"logentry-contentmodel-new": "$1 {{GENDER:$2|creó}} la página $3 usando un modelo de contenido no predeterminado \"$5\"",
"whatlinkshere-next": "{{PLURAL:$1|siguiente|siguientes $1}}",
"whatlinkshere-links": "← enlaces",
"whatlinkshere-hideredirs": "$1 redirecciones",
- "whatlinkshere-hidetrans": "$1 inclusiones",
+ "whatlinkshere-hidetrans": "$1 transclusiones",
"whatlinkshere-hidelinks": "$1 enlaces",
"whatlinkshere-hideimages": "$1 enlaces a archivos",
"whatlinkshere-filters": "Filtros",
"lockdbsuccesstext": "La base de datos de {{SITENAME}} ha sido bloqueada.\n<br />Recuerde retirar el bloqueo después de completar las tareas de mantenimiento.",
"unlockdbsuccesstext": "La base de datos de {{SITENAME}} ha sido desbloqueada.",
"lockfilenotwritable": "El archivo-cerrojo de la base de datos no tiene permiso de escritura. Para bloquear o desbloquear la base de datos, este archivo tiene que ser escribible por el servidor web.",
+ "databaselocked": "La base de datos ya está bloqueada.",
"databasenotlocked": "La base de datos no está bloqueada.",
"lockedbyandtime": "(por {{GENDER:$1|$1}} el $2 a las $3)",
"move-page": "Trasladar $1",
"confirm-watch-top": "¿Añadir esta página a tu lista de seguimiento?",
"confirm-unwatch-button": "Aceptar",
"confirm-unwatch-top": "¿Quitar esta página de tu lista de seguimiento?",
+ "confirm-rollback-button": "Aceptar",
+ "confirm-rollback-top": "¿Revertir las ediciones a esta página?",
"comma-separator": ", ",
"percent": "$1 %",
"quotation-marks": "«$1»",
"tags-delete-not-found": "La etiqueta «$1» no existe.",
"tags-delete-too-many-uses": "No se puede borrar la etiqueta \"$1\" porque se ha aplicado a más de {{PLURAL:$2|una revisión|$2 revisiones}}.",
"tags-delete-warnings-after-delete": "La etiqueta \"$1\" se borró, pero con {{PLURAL:$2|la siguiente advertencia|las siguientes advertencias}}:",
+ "tags-delete-no-permission": "No tienes permiso para eliminar las etiquetas de cambios.",
"tags-activate-title": "Activar etiqueta",
"tags-activate-question": "Estás a punto de activar la etiqueta «$1».",
"tags-activate-reason": "Motivo:",
"log-action-filter-suppress-block": "Usuario supppression por bloque",
"log-action-filter-suppress-reblock": "Usuario supresión de rebloqueo",
"log-action-filter-upload-upload": "Subida nueva",
- "log-action-filter-upload-overwrite": "Volver a subir"
+ "log-action-filter-upload-overwrite": "Volver a subir",
+ "authmanager-authn-no-local-user": "Las credenciales suministradas no están asociadas con ningún usuario en este wiki.",
+ "authmanager-authn-autocreate-failed": "Falló la creación automática de una cuenta local: $1",
+ "authmanager-create-disabled": "Está desactivada la creación de cuentas.",
+ "authmanager-create-from-login": "Para crear tu cuenta, completa los campos a continuación.",
+ "authmanager-create-not-in-progress": "El proceso de creación de la cuenta no está en progreso o se perdieron los datos de la sesión. Empieza de nuevo desde el principio.",
+ "authmanager-create-no-primary": "Las credenciales suministradas no pueden usarse para la creación de la cuenta.",
+ "authmanager-authplugin-setpass-failed-message": "El complemento de autenticación denegó el cambio de contraseña.",
+ "authmanager-authplugin-create-fail": "El complemento de autenticación denegó la creación de la cuenta.",
+ "authmanager-authplugin-setpass-denied": "El complemento de autenticación no permite el cambio de contraseñas.",
+ "authmanager-authplugin-setpass-bad-domain": "Dominio inválido.",
+ "authmanager-autocreate-noperm": "La creación automática de cuentas no está permitida.",
+ "authmanager-autocreate-exception": "La creación automática de cuentas ha sido temporalmente desactivada debido a errores previos.",
+ "authmanager-userdoesnotexist": "El usuario «$1» no está registrado.",
+ "authmanager-password-help": "Contraseña para autenticación.",
+ "authmanager-retype-help": "La contraseña de nuevo para confirmar.",
+ "authmanager-email-label": "Correo electrónico",
+ "authmanager-email-help": "Dirección de correo electrónico",
+ "authmanager-realname-label": "Nombre real",
+ "authmanager-realname-help": "Nombre real del usuario",
+ "authmanager-provider-password": "Autenticación basada en contraseña",
+ "authmanager-provider-temporarypassword": "Contraseña temporal",
+ "authprovider-confirmlink-success-line": "$1: vinculado exitosamente.",
+ "authprovider-resetpass-skip-label": "Omitir",
+ "authform-nosession-login": "La autenticación fue exitosa, pero tu navegador no puede \"recordar\" haber iniciado sesión.\n\n$1",
+ "authform-nosession-signup": "La cuenta ha sido creada, pero tu navegador no \"recuerda\" haber iniciado sesión.\n\n$1",
+ "specialpage-securitylevel-not-allowed-title": "No está permitido",
+ "specialpage-securitylevel-not-allowed": "Lo siento, no tienes permitido usar esta página, porque tu identidad no pudo verificarse.",
+ "authpage-cannot-login-continue": "No se puede continuar con el inicio de sesión. Lo más probable es que tu sesión haya expirado.",
+ "authpage-cannot-create": "No se puede iniciar la creación de la cuenta.",
+ "authpage-cannot-link-continue": "No se puede continuar con la vinculación de la cuenta. Lo más probable es que tu sesión haya expirado.",
+ "cannotauth-not-allowed-title": "Permiso denegado",
+ "cannotauth-not-allowed": "No tienes permiso para usar esta página.",
+ "changecredentials": "Cambiar las credenciales",
+ "changecredentials-submit": "Cambiar credenciales",
+ "changecredentials-success": "Tus credenciales han sido cambiadas.",
+ "removecredentials": "Eliminar credenciales",
+ "removecredentials-submit": "Eliminar credenciales",
+ "removecredentials-success": "Tus credenciales han sido eliminadas.",
+ "credentialsform-account": "Nombre de la cuenta:",
+ "cannotlink-no-provider": "No hay cuentas vinculables.",
+ "linkaccounts": "Vincular cuentas",
+ "linkaccounts-success-text": "La cuenta fue vinculada.",
+ "linkaccounts-submit": "Vincular cuentas",
+ "unlinkaccounts": "Desvincular cuentas"
}
"viewsource": "Vaata lähteteksti",
"viewsource-title": "Lehekülje $1 lähteteksti vaatamine",
"actionthrottled": "Toiming nurjus",
- "actionthrottledtext": "Väärtarvituse vastase meetmena pole sul lühikse aja jooksul seda toimingut liiga palju kordi lubatud sooritada. Sa oled lühikse aja jooskul seda toimingut liiga palju kordi sooritanud.\nPalun proovi mõne minuti pärast uuesti.",
+ "actionthrottledtext": "Väärtarvituse vastase meetmena pole sul lubatud lühikese aja jooksul seda toimingut liiga palju kordi sooritada. Oled piirangu ületanud. Palun proovi mõne aja pärast uuesti.",
"protectedpagetext": "See lehekülg on lukustatud, et ei tehtaks muudatusi ega sooritataks muid toiminguid.",
"viewsourcetext": "Saad vaadata ja kopeerida selle lehekülje lähteteksti.",
"viewyourtext": "Saad vaadata ja kopeerida sellel leheküljel tehtud <strong>enda muudatuste</strong> lähteteksti.",
"noname": "Sa ei sisestanud kasutajanime lubataval kujul.",
"loginsuccesstitle": "Sisselogimine õnnestus",
"loginsuccess": "Oled sisse loginud. Sinu kasutajanimi on \"$1\".",
- "nosuchuser": "Kasutajat \"$1\" pole.\nKasutajanimed on tõstutundlikud.\nKontrolli kirjapilti või [[Special:UserLogin/signup|loo uus konto]].",
+ "nosuchuser": "Kasutajat \"$1\" pole.\nKasutajanimed on tõstutundlikud.\nKontrolli kirjapilti või [[Special:CreateAccount|loo uus konto]].",
"nosuchusershort": "Kasutajat nimega \"$1\" pole.\nKontrolli kirjapilti.",
"nouserspecified": "Kasutajanimi puudub.",
"login-userblocked": "See kasutaja on blokeeritud. Sisselogimine pole lubatud.",
"accmailtext": "Kasutajale [[User talk:$1|$1]] genereeritud juhuslik parool saadeti aadressile $2.\n\nSeda saab pärast sisselogimist muuta ''[[Special:ChangePassword|parooli muutmise]]'' leheküljel.",
"newarticle": "(Uus)",
"newarticletext": "Lehekülge, kuhu link sind suunas, pole veel.\nEt lehekülg luua, alusta allolevas kastis kirjutamist (lisateave [$1 juhendist]).\nKui sattusid siia kogemata, klõpsa veebilehitseja ''tagasi''-nupule.",
- "anontalkpagetext": "----''See on anonüümse kasutaja arutelulehekülg. See kasutaja pole kontot loonud või ei kasuta seda. Sellepärast tuleb meil kasutaja tuvastamiseks kasutada tema IP-aadressi. Sellist IP-aadressi võib kasutada mitu kasutajat. Kui oled osutatud IP-aadressi kasutaja ning leiad, et siinsed kommentaarid ei puutu kuidagi sinusse, [[Special:UserLogin/signup|loo palun kasutajakonto]] või [[Special:UserLogin|logi sisse]], et sind edaspidi teiste anonüümsete kasutajatega segi ei aetaks.''",
+ "anontalkpagetext": "----''See on anonüümse kasutaja arutelulehekülg. See kasutaja pole kontot loonud või ei kasuta seda. Sellepärast tuleb meil kasutaja tuvastamiseks kasutada tema IP-aadressi. Sellist IP-aadressi võib kasutada mitu kasutajat. Kui oled osutatud IP-aadressi kasutaja ning leiad, et siinsed kommentaarid ei puutu kuidagi sinusse, [[Special:CreateAccount|loo palun kasutajakonto]] või [[Special:UserLogin|logi sisse]], et sind edaspidi teiste anonüümsete kasutajatega segi ei aetaks.''",
"noarticletext": "Käesoleval leheküljel hetkel teksti ei ole.\nVõid [[Special:Search/{{PAGENAME}}|otsida pealkirjaks olevat fraasi]] teistelt lehtedelt,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} uurida asjassepuutuvaid logisid] või [{{fullurl:{{FULLPAGENAME}}|action=edit}} puuduva lehekülje ise luua]</span>.",
"noarticletext-nopermission": "Sellel leheküljel pole praegu teksti.\nSaad [[Special:Search/{{PAGENAME}}|otsida selle lehekülje pealkirja]] teistelt lehekülgedelt või <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} otsida seonduvatest logidest]</span>, aga sul pole õigust seda lehekülge alustada.",
"missing-revision": "Lehekülje \"{{FULLPAGENAME}}\" redaktsiooni $1 pole.\n\nHarilikult tähendab see seda, et sind siia juhatanud link on vananenud ja siin asunud lehekülg on kustutatud.\nÜksikasjad leiad [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} kustutamislogist].",
"upload-form-label-own-work": "See on minu enda töö",
"upload-form-label-infoform-categories": "Kategooriad",
"upload-form-label-infoform-date": "Kuupäev",
- "upload-form-label-own-work-message-local": "Kinnitan, et seda faili üles laadides järgin saidi {{SITENAME}} kasutustingimusi ja litsentsipõhimõtteid.",
- "upload-form-label-not-own-work-message-local": "Kui sul pole võimalik laadida seda faili üles kooskõlas saidi {{SITENAME}} reeglitega, siis palun sule see dialoog ja proovi teisiti toimida.",
- "upload-form-label-not-own-work-local-local": "Võimalik, et soovid kasutada [[Special:Upload|harilikku üleslaadimislehekülge]].",
- "upload-form-label-own-work-message-default": "Saan aru, et laadin selle faili jagatud varamusse. Kinnitan, et teen seda kooskõlas sealsete kasutustingimuste ja litsentsipõhimõtetega.",
- "upload-form-label-not-own-work-message-default": "Kui sul pole võimalik laadida seda faili üles kooskõlas jagatud varamu reeglitega, siis palun sule see dialoog ja proovi teisiti toimida.",
- "upload-form-label-not-own-work-local-default": "Võimalik, et soovid [[Special:Upload|laadida selle faili üles saidil {{SITENAME}}]], kui seda on võimalik teha kooskõlas siinsete reeglitega.",
- "upload-form-label-own-work-message-shared": "Kinnitan, et olen selle faili autoriõiguse valdaja ja nõustun faili avaldamisega Wikimedia Commonsis pöördumatult Creative Commonsi litsentsi \"[https://creativecommons.org/licenses/by-sa/4.0/deed.et Autorile viitamine + jagamine samadel tingimustel 4.0]\" all. Samuti nõustun [https://wikimediafoundation.org/wiki/Terms_of_Use kasutustingimustega].",
- "upload-form-label-not-own-work-message-shared": "Kui sa pole selle faili autoriõiguse valdaja või kui soovid avaldada seda teise litsentsi all, siis on sul võimalik kasutada [https://commons.wikimedia.org/wiki/Special:UploadWizard Commonsi üleslaadimisviisardit].",
- "upload-form-label-not-own-work-local-shared": "Võimalik, et soovid kasutada [[Special:Upload|saidi {{SITENAME}} üleslaadimislehekülge]], kui seda faili on lubatud üles laadida kooskõlas siinsete reeglitega.",
+ "upload-form-label-own-work-message-generic-local": "Kinnitan, et seda faili üles laadides järgin saidi {{SITENAME}} kasutustingimusi ja litsentsipõhimõtteid.",
+ "upload-form-label-not-own-work-message-generic-local": "Kui sul pole võimalik laadida seda faili üles kooskõlas saidi {{SITENAME}} reeglitega, siis palun sule see dialoog ja proovi teisiti toimida.",
+ "upload-form-label-not-own-work-local-generic-local": "Võimalik, et soovid kasutada [[Special:Upload|harilikku üleslaadimislehekülge]].",
+ "upload-form-label-own-work-message-generic-foreign": "Saan aru, et laadin selle faili jagatud varamusse. Kinnitan, et teen seda kooskõlas sealsete kasutustingimuste ja litsentsipõhimõtetega.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Kui sul pole võimalik laadida seda faili üles kooskõlas jagatud varamu reeglitega, siis palun sule see dialoog ja proovi teisiti toimida.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Võimalik, et soovid [[Special:Upload|laadida selle faili üles saidil {{SITENAME}}]], kui seda on võimalik teha kooskõlas siinsete reeglitega.",
"backend-fail-stream": "Faili $1 ei saanud edastada.",
"backend-fail-backup": "Faili $1 ei saanud varundada.",
"backend-fail-notexists": "Faili $1 pole olemas.",
"Sator",
"Macofe",
"Xð",
- "Asierog"
+ "Asierog",
+ "Matma Rex"
]
},
"tog-underline": "Azpimarratu loturak:",
"noname": "Ez duzu baliozko erabiltzaile izen bat zehaztu.",
"loginsuccesstitle": "Saio hasiera egina",
"loginsuccess": "'''Saioa hasi duzu {{SITENAME}}(e)n \"$1\" izenarekin.'''",
- "nosuchuser": "Ez dago \"$1\" izena duen lankiderik.\nLankide izenak zehatza izan behar du.\nEgiaztatu ondo idatzi duzun, edo [[Special:UserLogin/signup|kontu berria sor ezazu]].",
+ "nosuchuser": "Ez dago \"$1\" izena duen lankiderik.\nLankide izenak zehatza izan behar du.\nEgiaztatu ondo idatzi duzun, edo [[Special:CreateAccount|kontu berria sor ezazu]].",
"nosuchusershort": "Ez dago \"$1\" izena duen erabiltzailerik. Egiaztatu ongi idatzi duzula.",
"nouserspecified": "Erabiltzaile izena zehaztu beharra daukazu.",
"login-userblocked": "Erabiltzailea blokeatua dago. Ezin du saioa hasi.",
"accmailtext": "[[User talk:$1|$1]]-entzako ausaz sortutako pasahitza $2-(r)a bidali da.\n\n''[[Special:ChangePassword|pasahitz aldaketa]]'' orrialdean alda daiteke, behin barruan sartuta.",
"newarticle": "(Berria)",
"newarticletext": "Orrialde hau ez da existitzen oraindik. Orrialde sortu nahi baduzu, beheko koadroan idazten hasi zaitezke (ikus [$1 laguntza orrialdea] informazio gehiagorako). Hona nahi gabe etorri bazara, nabigatzaileko '''atzera''' botoian klik egin.",
- "anontalkpagetext": "----''Orrialde hau konturik sortu ez edo erabiltzen ez duen erabiltzaile anonimo baten eztabaida orria da.\nBere IP helbidea erabili beharko da beraz identifikatzeko.\nErabiltzaile batek baino gehiagok IP bera erabil dezakete ordea.\nErabiltzaile anonimoa bazara eta zurekin zerikusirik ez duten mezuak jasotzen badituzu, mesedez [[Special:UserLogin/signup|Izena eman]] edo [[Special:UserLogin|saioa hasi]] etorkizunean horrelakoak gerta ez daitezen.''",
+ "anontalkpagetext": "----''Orrialde hau konturik sortu ez edo erabiltzen ez duen erabiltzaile anonimo baten eztabaida orria da.\nBere IP helbidea erabili beharko da beraz identifikatzeko.\nErabiltzaile batek baino gehiagok IP bera erabil dezakete ordea.\nErabiltzaile anonimoa bazara eta zurekin zerikusirik ez duten mezuak jasotzen badituzu, mesedez [[Special:CreateAccount|Izena eman]] edo [[Special:UserLogin|saioa hasi]] etorkizunean horrelakoak gerta ez daitezen.''",
"noarticletext": "Oraindik ez dago testurik orri honetan.\nEdukiz hornitzeko, aukera hauek dituzu: beste orri batzuetan [[Special:Search/{{PAGENAME}}|orri izenburu hau bilatzea]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} lotutako logak bilatzea],\nedo [{{fullurl:{{FULLPAGENAME}}|action=edit}} orri hau sortzea]</span>.",
"noarticletext-nopermission": "Une honetan ez dago testurik orrialde honetan.\nBeste orrialdeetan [[Special:Search/{{PAGENAME}}|izenburu hau bilatu dezakezu]],\nedo <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} erlazionatutako erregistroak bilatu]</span>, baina ez duzu orrialde hau sortzeko baimenik.",
"userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" lankidea ez dago erregistatuta. Mesedez, konprobatu orri hau editatu/sortu nahi duzun.",
"noname": "Nu as escrebiu un nombri d'usuáriu corretu.",
"loginsuccesstitle": "Yeu, lo cúmu va esu?",
"loginsuccess": "'''Acabihas d'entral en {{SITENAME}} con el nombri \"$1\".'''",
- "nosuchuser": "Nu dessisti dengún usuáriu anombrau \"$1\".\nCompreba que lo aigas escritu bien, u [[Special:UserLogin/signup|cria una cuenta nueva]].",
+ "nosuchuser": "Nu dessisti dengún usuáriu anombrau \"$1\".\nCompreba que lo aigas escritu bien, u [[Special:CreateAccount|cria una cuenta nueva]].",
"nosuchusershort": "Nu ai dengún usuáriu llamau \"$1\". Compreba qu'esté bien escritu.",
"nouserspecified": "Ebis escribil un nombri d'usuáriu.",
"wrongpassword": "La consínia escrebia nu es correta. Pol favol, preba otra vezi.",
"Arian Ar",
"Ms96",
"Freshman404",
- "Hamisun"
+ "Hamisun",
+ "Matma Rex"
]
},
"tog-underline": "خط کشیدن زیر پیوندها:",
"tog-watchdefault": "افزودن صفحهها و پروندههایی که ویرایش میکنم به فهرست پیگیریهای من",
"tog-watchmoves": "افزودن صفحهها و پروندههایی که منتقل میکنم به فهرست پیگیریهای من",
"tog-watchdeletion": "افزودن صفحات و پروندههایی که حذف میکنم به فهرست پیگیریهای من",
+ "tog-watchuploads": "افزودن پروندههای جدید به فهرست پیگیری من",
"tog-watchrollback": "افزودن صفحاتی که واگردانی میکنم به فهرست پیگیریهای من",
"tog-minordefault": "علامت زدن همهٔ ویرایشها به عنوان «جزئی» به طور پیشفرض",
"tog-previewontop": "نمایش دادن پیشنمایش بالای جعبهٔ ویرایش",
"noname": "شما نام کاربری معتبری مشخص نکردهاید.",
"loginsuccesstitle": "ورود به سامانه",
"loginsuccess": "'''شما اکنون با نام «$1» به {{SITENAME}} وارد شدهاید.'''",
- "nosuchuser": "کاربری با نام «$1» وجود ندارد.\nنام کاربری به بزرگی و کوچکی حروف حساس است.\nاملای نام را بررسی کنید، یا [[Special:UserLogin/signup|یک حساب کاربری تازه بسازید]].",
+ "nosuchuser": "کاربری با نام «$1» وجود ندارد.\nنام کاربری به بزرگی و کوچکی حروف حساس است.\nاملای نام را بررسی کنید، یا [[Special:CreateAccount|یک حساب کاربری تازه بسازید]].",
"nosuchusershort": "هیچ کاربری با نام ''$1'' وجود ندارد.\nاملایتان را وارسی کنید.",
"nouserspecified": "باید یک نام کاربری مشخص کنید.",
"login-userblocked": "این کاربر بسته شدهاست. ورود به سامانه مجاز نیست.",
"minoredit": "این ویرایش، جزئی است",
"watchthis": "پیگیری این صفحه",
"savearticle": "صفحه ذخیره شود",
+ "publishpage": "انتشار صفحه",
"preview": "پیشنمایش",
"showpreview": "پیشنمایش",
"showdiff": "نمایش تغییرات",
"accmailtext": "یک گذرواژهٔ تصادفی برای [[User talk:$1|$1]] به $2 فرستاده شد. میتوان آن را از صفحهٔ ''[[Special:ChangePassword|تغییر گذرواژه]]'' که هنگام ثبت ورود نمایش مییابد تغییر داد.",
"newarticle": "(تازه)",
"newarticletext": "شما پیوندی را دنبال کردهاید و به صفحهای رسیدهاید که هنوز وجود ندارد.\nبرای ایجاد صفحه، در مستطیل زیر شروع به نوشتن کنید (برای اطلاعات بیشتر به [$1 صفحهٔ راهنما] مراجعه کنید).\nاگر به اشتباه اینجا آمدهاید، دکمهٔ «بازگشت» مرورگرتان را بزنید.",
- "anontalkpagetext": "----''این صفحهٔ بحث برای کاربر گمنامی است که هنوز حسابی درست نکرده است یا از آن استفاده نمیکند.\nبنا بر این برای شناساییاش مجبوریم از نشانی آیپی عددی استفاده کنیم.\nچنین نشانیهای آیپی ممکن است توسط چندین کاربر به شکل مشترک استفاده شود.\nاگر شما کاربر گمنامی هستید و تصور میکنید اظهار نظرات نامربوط به شما صورت گرفته است، لطفاً برای پیشگیری از اشتباه گرفته شدن با کاربران گمنام دیگر در آینده [[Special:UserLogin/signup|حسابی ایجاد کنید]] یا [[Special:UserLogin|به سامانه وارد شوید]].''",
+ "anontalkpagetext": "----''این صفحهٔ بحث برای کاربر گمنامی است که هنوز حسابی درست نکرده است یا از آن استفاده نمیکند.\nبنا بر این برای شناساییاش مجبوریم از نشانی آیپی عددی استفاده کنیم.\nچنین نشانیهای آیپی ممکن است توسط چندین کاربر به شکل مشترک استفاده شود.\nاگر شما کاربر گمنامی هستید و تصور میکنید اظهار نظرات نامربوط به شما صورت گرفته است، لطفاً برای پیشگیری از اشتباه گرفته شدن با کاربران گمنام دیگر در آینده [[Special:CreateAccount|حسابی ایجاد کنید]] یا [[Special:UserLogin|به سامانه وارد شوید]].''",
"noarticletext": "این صفحه هماکنون دارای هیچ متنی نیست.\nشما میتوانید در صفحههای دیگر [[Special:Search/{{PAGENAME}}|عنوان این صفحه را جستجو کنید]]،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} سیاهههای مرتبط را جستجو کنید]،\nیا [{{fullurl:{{FULLPAGENAME}}|action=edit}} این صفحه را ایجاد کنید]</span>.",
"noarticletext-nopermission": "این صفحه هماکنون متنی ندارد.\nشما میتوانید در دیگر صفحات [[Special:Search/{{PAGENAME}}|این عنوان را جستجو کنید]]،\nیا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} سیاهههای مرتبط را بگردید]</span> ولی شما اجازه ایجاد این صفحه را ندارید.",
"missing-revision": "ویرایش #$1 از صفحهٔ «{{FULLPAGENAME}}» موجود نیست.\n\nمعمولاً در اثر پیوند به تاریخچهٔ بهروز نشدهٔ صفحهٔ حذف شده است.\nمیتوانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.",
"rev-suppressed-unhide-diff": "یکی از نسخههای این تفاوت '''فرونشانی شدهاست'''.\nممکن است جزئیاتی در [{{fullurl:{{#Special:Log}}/suppress|page=سیاههٔ فرونشانی{{FULLPAGENAMEE}}}}] موجود باشد.\nشما کماکان میتوانید در صورت تمایل [$1 این تفاوت را ببینید].",
"rev-deleted-diff-view": "یکی از نسخههای این تفاوت '''حذف شدهاست'''.\nشما میتوانید این تفاوت را ببینید؛ ممکن است جزئیاتی در [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] موجود باشد.",
"rev-suppressed-diff-view": "یکی از نسخههای این تفاوت '''فرونشانی شدهاست'''.\nشما میتوانید این تفاوت را ببینید؛ ممکن است جزئیاتی در [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} سیاههٔ فرونشانی] موجود باشد.",
- "rev-delundel": "نمایش/نهفتن",
+ "rev-delundel": "تغییر پیدایی",
"rev-showdeleted": "نمایش",
"revisiondelete": "حذف/احیای نسخهها",
"revdelete-nooldid-title": "نسخهٔ هدف نامجاز",
"right-managechangetags": "ایجاد و حذف [[Special:Tags|برچسبها]] از پایگاه داده",
"right-applychangetags": "تائید [[Special:Tags|برچسب]] بر روی تغییرات یک نفر",
"right-changetags": "افزودن یا حذف [[Special:Tags|برچسب]] قراردادی بر روی نسخه یا سیاهه ورودیها",
+ "right-deletechangetags": "حذف [[Special:Tags|برچسبها]] از پایگاه داده",
"grant-generic": "\" $1 \" حقوق بسته",
"grant-group-page-interaction": "تعامل با صفحات",
"grant-group-file-interaction": "تعامل با رسانه",
"action-viewmyprivateinfo": "اطلاعات خصوصی خود را ببینید",
"action-editmyprivateinfo": "اطلاعات خصوصی خود را ویرایش کنید",
"action-editcontentmodel": "ویرایش مدل محتوای یک صفحه",
- "action-managechangetags": "ایجاد و حذف تگها از پایگاه داده",
+ "action-managechangetags": "ایجاد و (غیر)فعالسازی برچسبها",
"action-applychangetags": "اعمال برچسب بر روی تغییرات شما",
"action-changetags": "افزودن یا حذف برچسب قراردادی بر روی نسخه یا سیاهه ورودیها",
+ "action-deletechangetags": "حذف برچسبها از پایگاه داده",
"nchanges": "$1 تغییر",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|از آخرین بازدید}}",
"enhancedrc-history": "تاریخچه",
"recentchangeslinked-page": "نام صفحه:",
"recentchangeslinked-to": "نمایش تغییرات صفحههایی که به صفحهٔ دادهشده پیوند دارند",
"recentchanges-page-added-to-category": "[[:$1]] به رده اضافه شد",
- "recentchanges-page-added-to-category-bundled": "[[:$1]] و [[Special:WhatLinksHere/$1|{{PLURAL:$2|یک صفحه|$2 صفحه}}]]دیگر به رده اضافه شدند",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] به رده افزوده شد، [[Special:WhatLinksHere/$1|این صفحه در صفحههای دیگر قرار گرفته است.]]",
"recentchanges-page-removed-from-category": "[[:$1]] از رده حذف شد",
"recentchanges-page-removed-from-category-bundled": "[[:$1]] و [[Special:WhatLinksHere/$1|{{PLURAL:$2|یک صفحه|$2 صفحه}}]] دیگر از رده حذف شدند",
"autochange-username": "تغییرات خودکار مدیاویکی",
"upload-form-label-own-work": "این کار خودم است",
"upload-form-label-infoform-categories": "ردهها",
"upload-form-label-infoform-date": "تاریخ",
- "upload-form-label-own-work-message-local": "تائید می کنم که این پرونده را تحت مجوزها و سیاستهای {{SITENAME}} بارگذاری میکنم.",
- "upload-form-label-not-own-work-message-local": "اگر امکان بارگذاری پرونده تحت سیاستهای {{SITENAME}} را ندارید، لطفاً این پنجره را ببندید و از روشهای دیگر استفاده کنید.",
- "upload-form-label-not-own-work-local-local": "ممکن بخواهید از [[Special:Upload|پنجرهٔ بارگذاری پیشفرض]] استفاده کنید.",
- "upload-form-label-own-work-message-default": "متوجهم که این پرونده را بر روی مخزن مشترک بارگذاری میکنم و تائید میکنم که تحت سیاستها و مجوزهای آنجا عمل میکنم.",
- "upload-form-label-not-own-work-message-default": "اگر امکان بارگذاری پرونده تحت سیاستها و مجوزهای مخزن اشتراکگذاری را ندارید، لطفاً این پنجره را ببندید و از روشهای دیگر استفاده کنید.",
- "upload-form-label-not-own-work-local-default": "در صورتی که نمیشود پرونده را تحت سیاستها بارگذاری کنید ممکن است بخواهید از [[Special:Upload|پنجرهٔ بارگذاری در {{SITENAME}}]] استفاده کنید.",
- "upload-form-label-own-work-message-shared": "تصدیق میکنم که مالک حق تکثیر این پرونده هستم و موافق اشتراکگذاری آن تحت مجوز [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] هستم و موافق [https://wikimediafoundation.org/wiki/Terms_of_Use سیاست نحوهٔ استفاده] هستم.",
- "upload-form-label-not-own-work-message-shared": "اگر مالک حق تکثیر این پرونده نیستید یا قصد بارگذاری تحت مجوز دیگری دارید، از [https://commons.wikimedia.org/wiki/Special:UploadWizard جادوگر بارگذاری ویکیانبار] استفاده کنید.",
- "upload-form-label-not-own-work-local-shared": "در صورتی که سایت امکان بارگذاری پرونده را تحت سیاستها بارگذاری میدهد ممکن است بخواهید از [[Special:Upload|پنجرهٔ بارگذاری در {{SITENAME}}]] استفاده کنید.",
+ "upload-form-label-own-work-message-generic-local": "تائید می کنم که این پرونده را تحت مجوزها و سیاستهای {{SITENAME}} بارگذاری میکنم.",
+ "upload-form-label-not-own-work-message-generic-local": "اگر امکان بارگذاری پرونده تحت سیاستهای {{SITENAME}} را ندارید، لطفاً این پنجره را ببندید و از روشهای دیگر استفاده کنید.",
+ "upload-form-label-not-own-work-local-generic-local": "ممکن بخواهید از [[Special:Upload|پنجرهٔ بارگذاری پیشفرض]] استفاده کنید.",
+ "upload-form-label-own-work-message-generic-foreign": "متوجهم که این پرونده را بر روی مخزن مشترک بارگذاری میکنم و تائید میکنم که تحت سیاستها و مجوزهای آنجا عمل میکنم.",
+ "upload-form-label-not-own-work-message-generic-foreign": "اگر امکان بارگذاری پرونده تحت سیاستها و مجوزهای مخزن اشتراکگذاری را ندارید، لطفاً این پنجره را ببندید و از روشهای دیگر استفاده کنید.",
+ "upload-form-label-not-own-work-local-generic-foreign": "در صورتی که نمیشود پرونده را تحت سیاستها بارگذاری کنید ممکن است بخواهید از [[Special:Upload|پنجرهٔ بارگذاری در {{SITENAME}}]] استفاده کنید.",
"backend-fail-stream": "نمیتوان پروندهٔ $1 را ارسال کرد.",
"backend-fail-backup": "نمیتوان نسخهٔ پشتیبان برای پروندهٔ $1 ایجاد کرد.",
"backend-fail-notexists": "پروندهٔ $1 وجود ندارد.",
"revertpage": "ویرایش [[Special:Contributions/$2|$2]] ([[User talk:$2|بحث]]) به آخرین تغییری که [[User:$1|$1]] انجام داده بود واگردانده شد",
"revertpage-nouser": "ویرایشهای انجامشده توسط (نام کاربری حذف شده) به آخرین ویرایش [[User:$1|$1]] واگردانی شد.",
"rollback-success": "ویرایشهای $1 واگردانی شد؛\nصفحه به آخرین ویرایش $2 برگردانده شد.",
+ "rollback-success-notify": "ویرایشهای توسط $1 واگردانی شد؛\nبه آخرین نسخه توسط $2 بازگردانی شد. [$3 نمایش تغییرات]",
"sessionfailure-title": "خطای نشست کاربری",
"sessionfailure": "به نظر میرسد مشکلی در مورد نشست کاربری شما وجود دارد؛\nعمل درخواست شده در اقدامی پیشگیرانه در برابر ربودهشدن اطلاعات نشست کاربری، لغو شد.\nلطفاً دکمهٔ «بازگشت» را در مرورگر خود بفشارید و صفحهای که از آن به اینجا رسیدهاید را دوباره فراخوانی کنید، سپس مجدداً سعی کنید.",
"changecontentmodel": "ویرایش نمونه محتوای یک صفحه",
"lockdbsuccesstext": "پایگاه داده قفل شد.\n<br />فراموش نکنید که پس از اتمام نگهداری قفل را بردارید.",
"unlockdbsuccesstext": "پایگاه داده از قفل در آمد.",
"lockfilenotwritable": "قفل پایگاه داده نوشتنی نیست. برای این که بتوانید پایگاه داده را قفل یا باز کنید، باید این پرونده نوشتنی باشد.",
+ "databaselocked": "در حال حاضر، پایگاه داده قفل است.",
"databasenotlocked": "پایگاه داده قفل نیست.",
"lockedbyandtime": "(به وسیلهٔ $1 در $2 ساعت $3)",
"move-page": "انتقال $1",
"tooltip-ca-nstab-category": "دیدن صفحهٔ رده",
"tooltip-minoredit": "این ویرایش را ویرایش جزئی نشانهگذاری کن",
"tooltip-save": "تغییرات خود را ذخیره کنید",
+ "tooltip-publish": "انتشار تغییراتتان",
"tooltip-preview": "پیشنمایش تغییرات شما، لطفاً قبل از ذخیره کردن صفحه از این کلید استفاده کنید.",
"tooltip-diff": "نمایش تغییراتی که شما در متن دادهاید.",
"tooltip-compareselectedversions": "دیدن تفاوتهای دو نسخهٔ انتخابشده از این صفحه",
"confirmemail_body_set": "یک نفر، احتمالاً خود شما، از نشانی آیپی $1,\nآدرس ایمیل حساب «$2» در {{SITENAME}} را به این آدرس تغییر داده است.\n\nبرای تأیید این که این حساب واقعاً به شما تعلق دارد و فعال کردن دوبارهٔ قابلیت ایمیل در {{SITENAME}}، پیوند زیر را در مرورگرتان باز کنید:\n\n$3\n\nاگر این حساب متعلق به شما نیست، پیوند زیر را باز تا تغییر آدرس ایمیل، لغو شود:\n\n$5\n\nاین تأییدیه در $4 منقضی میگردد.",
"confirmemail_invalidated": "تأیید نشانی ایمیل لغو شد",
"invalidateemail": "لغو تأیید نشانی ایمیل",
+ "notificationemail_subject_changed": "نشانی ایمیل ثبت شدهٔ {{SITENAME}} تغییر یافته است",
+ "notificationemail_subject_removed": "نشانی ایمیل ثبت شدهٔ {{SITENAME}} حذف شده است",
"scarytranscludedisabled": "[تراگنجانش بینویکیانه فعال نیست]",
"scarytranscludefailed": "[فراخوانی الگو برای $1 میسر نشد]",
"scarytranscludefailed-httpstatus": "[فراخوانی الگو برای $1 میسر نشد: خطای اچتیتیپی $2]",
"confirm-watch-top": "این صفحه به فهرست پیگیریهای شما افزوده شود؟",
"confirm-unwatch-button": "تأیید",
"confirm-unwatch-top": "این صفحه از فهرست پیگیریهای شما حذف شود؟",
+ "confirm-rollback-button": "باشد",
+ "confirm-rollback-top": "خنثیسازی ویرایشهای این صفحه؟",
"semicolon-separator": "؛ ",
"comma-separator": "، ",
"percent": "$1٪",
"tags-delete-not-found": "تگ «$1» وجود ندارد.",
"tags-delete-too-many-uses": "برچسب \"$1\" در بیش از $2 نسخه اعمال شده است و نمیتوان آن را حذف نمود.",
"tags-delete-warnings-after-delete": "برچسب \"$1\" حذف شد، اما با {{PLURAL:$2|خطای|خطاهای}} زیر همراه بود:",
+ "tags-delete-no-permission": "شما اجازهٔ حذف برچسبهای تغییر را ندارید.",
"tags-activate-title": "فعالسازی برچسب",
"tags-activate-question": "شما در حال فعالسازی تگ «$1» هستید.",
"tags-activate-reason": "دلیل:",
"logentry-protect-protect-cascade": "$1 $3 $4 {{GENDER:$2|محافظت کرد}} [آبشاری]",
"logentry-protect-modify": "$1 سطح محافظت $3 را {{GENDER:$2|تغییر داد}} $4",
"logentry-protect-modify-cascade": "$1 سطح حفاظت برای $3 $4 را {{GENDER:$2|تغییر داد}}[آبشاری]",
- "logentry-rights-rights": "$1 عضÙ\88Û\8cت $3 را از گرÙ\88Ù\87 $4 بÙ\87 $5 {{GENDER:$2|تغÛ\8cÛ\8cر داد}}",
+ "logentry-rights-rights": "$1 دسترسÛ\8c $3 را از گرÙ\88Ù\87 $4 بÙ\87 $5 تغÛ\8cÛ\8cر داد",
"logentry-rights-rights-legacy": "$1 گروه عضویت $3 را {{GENDER:$2|تغییر داد}}",
"logentry-rights-autopromote": "$1 به طور خودکار از $4 به $5 {{GENDER:$2|ارتقاء داد}}",
"logentry-upload-upload": "$1 $3 را {{GENDER:$2|بارگذاری کرد}}",
"feedback-useragent": "رابط کاربر:",
"searchsuggest-search": "جستجو",
"searchsuggest-containing": "صفحههای دربردارنده...",
+ "api-error-autoblocked": "نشانی آیپی شما به صورت خودکار بسته شدهاست، چون توسط یک کاربر بستهشده استفاده میشد.",
"api-error-badaccess-groups": "شما اجازهٔ بارگذاری پروندهها را در این ویکی ندارید.",
"api-error-badtoken": "خطای داخلی: کد امنیتی اشتباه (Bad token).",
+ "api-error-blocked": "شما از ویرایش بسته شدهاید.",
"api-error-copyuploaddisabled": "بارگذاری با استفاده از نشانی اینترنتی در این کارساز غیرفعال است.",
"api-error-duplicate": "{{PLURAL:$1|پروندهٔ دیگری|چند پروندهٔ دیگر}} در تارنما با محتوای یکسان وجود داشت.",
"api-error-duplicate-archive": "{{PLURAL:$1| پروندهٔ دیگری|چند پروندهٔ دیگر}} در تارنما با محتوای یکسان وجود داشت، ولی حذف {{PLURAL:$1|شده است|شدهاند}}.",
"sessionprovider-nocookies": "کوکیها ممکن است غیر فعال شده باشند. اطمینان کسب کنید که کوکیها را فعال کردهاید و دوباره آغاز کنید.",
"randomrootpage": "صفحهٔ ریشهٔ تصادفی",
"log-action-filter-block": "نوع بسته شدن:",
+ "log-action-filter-contentmodel": "تغییر نوع contentmodel:",
"log-action-filter-delete": "نوع حذف:",
"log-action-filter-import": "نوع واردات",
"log-action-filter-managetags": "نوع مدیریت",
"log-action-filter-block-reblock": "تصحیح بلاک",
"log-action-filter-block-unblock": "باز شدن",
"log-action-filter-contentmodel-change": "تغییر نوع محتوا",
+ "log-action-filter-contentmodel-new": "ایجاد صفحه با contentmodel غیر استاندارد",
"log-action-filter-delete-delete": "حذف صفحه",
"log-action-filter-delete-restore": "احیای صفحه",
"log-action-filter-delete-event": "حذف سیاهه",
"log-action-filter-managetags-delete": "حذف کردن تگ",
"log-action-filter-managetags-activate": "فعالسازی تگ",
"log-action-filter-managetags-deactivate": "تغییر تگ",
+ "log-action-filter-move-move": "انتقال بدون بازنویسی تغییر مسیرها",
+ "log-action-filter-move-move_redir": "انتقال با بازنویسی تغییر مسیرها",
"log-action-filter-newusers-create": "ایجاد شده توسط کاربر ناشناس",
"log-action-filter-newusers-create2": "ایجاد شده توسط کاربر ثبت نام شده",
"log-action-filter-newusers-autocreate": "ایجاد خودکار",
"log-action-filter-newusers-byemail": "ایجاد پسورد با ارسال به ایمیل",
+ "log-action-filter-patrol-patrol": "گشت غیرخودکار",
"log-action-filter-patrol-autopatrol": "گشت خودکار",
"log-action-filter-protect-protect": "محافظت",
"log-action-filter-protect-modify": "اصلاح حفاظت",
"log-action-filter-suppress-event": "جلوگیری از ورود",
"log-action-filter-suppress-revision": "جلوگیری از ویرایش",
"log-action-filter-suppress-delete": "متوقف سازی صفحه",
+ "log-action-filter-suppress-block": "مخفیسازی کاربر با بستن",
+ "log-action-filter-suppress-reblock": "مخفیسازی کاربر با بستن مجدد",
"log-action-filter-upload-upload": "بارگذاری جدید",
"log-action-filter-upload-overwrite": "بارگذاری دوباره"
}
"Pyscowicz",
"Olimar",
"Mikahama",
- "01miki10"
+ "01miki10",
+ "Matma Rex",
+ "BiscuitMan"
]
},
"tog-underline": "Linkkien alleviivaus:",
"noname": "Et ole määritellyt kelvollista käyttäjänimeä.",
"loginsuccesstitle": "Olet kirjautunut sisään",
"loginsuccess": "'''Olet kirjautunut sivustolle {{SITENAME}} käyttäjänä $1.'''",
- "nosuchuser": "Käyttäjää ”$1” ei ole olemassa. Nimet ovat kirjainkoosta riippuvaisia. Tarkista kirjoititko nimen oikein, tai [[Special:UserLogin/signup|luo uusi käyttäjätunnus]].",
+ "nosuchuser": "Käyttäjää \"$1\" ei ole olemassa.\nNimet ovat kirjainkoosta riippuvaisia. \nTarkista kirjoititko nimen oikein, tai [[Special:CreateAccount|luo uusi käyttäjätunnus]].",
"nosuchusershort": "Käyttäjää nimeltä ”$1” ei ole. Kirjoititko nimen oikein?",
"nouserspecified": "Käyttäjätunnusta ei ole määritelty.",
"login-userblocked": "Tämä käyttäjä on estetty. Kirjautuminen ei ole sallittua.",
"createacct-another-realname-tip": "Vapaaehtoinen.\nNimesi näytetään käyttäjätunnuksesi sijasta sivun tekijäluettelossa.",
"pt-login": "Kirjaudu sisään",
"pt-login-button": "Kirjaudu sisään",
+ "pt-login-continue-button": "Jatka kirjautumista",
"pt-createaccount": "Luo tunnus",
"pt-userlogout": "Kirjaudu ulos",
"php-mail-error-unknown": "Tuntematon virhe PHP:n mail()-funktiossa",
"accmailtext": "Satunnaisesti generoitu salasana käyttäjälle [[User talk:$1|$1]] on lähetetty osoitteeseen $2. Sen voi vaihtaa kirjautumisen jälkeen [[Special:ChangePassword|asetussivulla]].",
"newarticle": "(Uusi)",
"newarticletext": "Linkki toi sivulle, jota ei vielä ole.\nVoit luoda sivun kirjoittamalla alla olevaan kenttään (katso [$1 ohjesivulta] lisätietoja).\nJos et halua luoda sivua, käytä selaimen paluutoimintoa.",
- "anontalkpagetext": "----''Tämä on nimettömän käyttäjän keskustelusivu. Hän ei ole joko luonut itselleen käyttäjätunnusta tai ei käytä sitä. Siksi hänet tunnistetaan nyt numeerisella IP-osoitteella. Kyseinen IP-osoite voi olla useamman henkilön käytössä. Jos olet nimetön käyttäjä, ja sinusta tuntuu, että aiheettomia kommentteja on ohjattu sinulle, [[Special:UserLogin/signup|luo itsellesi käyttäjätunnus]] tai [[Special:UserLogin|kirjaudu sisään]] välttääksesi jatkossa sekaannukset muiden nimettömien käyttäjien kanssa.''",
+ "anontalkpagetext": "----''Tämä on nimettömän käyttäjän keskustelusivu. Hän ei ole joko luonut itselleen käyttäjätunnusta tai ei käytä sitä. Siksi hänet tunnistetaan nyt numeerisella IP-osoitteella. Kyseinen IP-osoite voi olla useamman henkilön käytössä. Jos olet nimetön käyttäjä, ja sinusta tuntuu, että aiheettomia kommentteja on ohjattu sinulle, [[Special:CreateAccount|luo itsellesi käyttäjätunnus]] tai [[Special:UserLogin|kirjaudu sisään]] välttääksesi jatkossa sekaannukset muiden nimettömien käyttäjien kanssa.''",
"noarticletext": "Tällä hetkellä tällä sivulla ei ole tekstiä.\nVoit [[Special:Search/{{PAGENAME}}|etsiä sivun nimellä]] muilta sivuilta,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} hakea aiheeseen liittyviä lokeja]\ntai [{{fullurl:{{FULLPAGENAME}}|action=edit}} luoda tämän sivun]</span>.",
"noarticletext-nopermission": "Tällä hetkellä tällä sivulla ei ole tekstiä.\nVoit [[Special:Search/{{PAGENAME}}|etsiä sivun nimellä]] muilta sivuilta tai <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} hakea aiheeseen liittyviä lokeja]</span>, mutta sinulla ei ole oikeutta luoda tätä sivua.",
"missing-revision": "Sivusta \"{{FULLPAGENAME}}\" ei ole olemassa versiota $1.\n\nYleensä tämä johtuu vanhentuneesta historialinkistä sivulle, joka on poistettu.\nTarkempia tietoja löytyy [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} poistolokista].",
"right-override-export-depth": "Viedä sivuja sisältäen viitatut sivut viiden syvyydellä",
"right-sendemail": "Lähettää sähköpostia muille käyttäjille",
"right-passwordreset": "Tarkastella salasanan alustusviestejä",
- "right-managechangetags": "Luoda ja poistaa [[Special:Tags|merkkauksia]] tietokannasta",
+ "right-managechangetags": "Luoda ja ottaa käyttöön [[Special:Tags|merkkauksia]]",
"right-applychangetags": "Asettaa [[Special:Tags|merkkauksia]] omien muutosten yhteyteen",
"right-changetags": "Lisätä ja poistaa satunnaisia [[Special:Tags|merkkauksia]] yksittäisissä sivuversioissa tai lokimerkinnöissä",
+ "right-deletechangetags": "Poistaa [[Special:Tags|merkkauksia]] tietokannasta",
"grant-generic": "\"$1\" oikeuksien joukko",
"grant-group-page-interaction": "Ole vuorovaikutuksessa sivujen kanssa",
"grant-group-file-interaction": "Ole vuorovaikutuksessa mediatiedostojen kanssa",
"action-viewmyprivateinfo": "katsoa omia yksityisiä tietojasi",
"action-editmyprivateinfo": "muokata omia yksityisiä tietojasi",
"action-editcontentmodel": "muokata sivun sisältömallia",
- "action-managechangetags": "luoda ja poistaa merkkauksia tietokannasta",
+ "action-managechangetags": "luoda ja ottaa käyttöön merkkauksia",
"action-applychangetags": "käyttää merkkauksia muutostesi yhteydessä",
"action-changetags": "lisätä ja poistaa satunnaisia merkkauksia yksittäisissä sivuversioissa ja lokimerkinnöissä",
+ "action-deletechangetags": "poistaa merkkauksia tietokannasta",
"nchanges": "$1 {{PLURAL:$1|muutos|muutosta}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|viimeisen käynnin jälkeen}}",
"enhancedrc-history": "historia",
"upload-form-label-own-work": "Tämä on oma työni",
"upload-form-label-infoform-categories": "Luokat",
"upload-form-label-infoform-date": "Päivämäärä",
- "upload-form-label-own-work-message-local": "Vakuutan, että tallennan tämän tiedoston noudattaen sivustolla {{SITENAME}} voimassa olevia käyttöehtoja sekä lisenssejä koskevia käytäntöjä.",
- "upload-form-label-not-own-work-message-local": "Jos et kykene tallentamaan tätä tiedostoa noudattaen niitä käytäntöjä, jotka ovat voimassa sivustolla {{SITENAME}}, sulje tämä dialogi ja kokeile jotain toista menetelmää.",
- "upload-form-label-not-own-work-local-local": "Voit myös kokeilla [[Special:Upload|yleistä tallentamista]].",
- "upload-form-label-own-work-message-default": "Ymmärrän, että olen tallentamassa tätä tiedostoa yhteiseen mediasäilöön. Vakuutan, että teen tämän noudattaen asiaankuuluvia käyttöehtoja ja lisenssejä koskevia käytäntöjä.",
- "upload-form-label-not-own-work-message-default": "Jos et kykene tallentamaan tätä tiedostoa noudattaen niitä käytäntöjä, jotka ovat voimassa yhteisessä mediasäilössä, sulje tämä dialogi ja kokeile jotain toista menetelmää.",
- "upload-form-label-not-own-work-local-default": "Voit myös kokeilla [[Special:Upload|tallennussivua sivustolla {{SITENAME}}]]. Saattaa olla, että tämän tiedoston tallentaminen sinne on mahdollista siellä voimassa olevien käytäntöjen mukaisesti.",
- "upload-form-label-own-work-message-shared": "Vakuutan, että minä omistan tämän tiedoston tekijänoikeudet, ja sitoudun siihen, että luovutan peruuttamattomasti tämän tiedoston kohteeseen Wikimedia Commons niillä ehdoilla, jotka liittyvät lisenssiin [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0]. Sitoudun myös noudattamaan [https://wikimediafoundation.org/wiki/Terms_of_Use käyttöehtoja].",
- "upload-form-label-not-own-work-message-shared": "Jos sinulla ei ole tähän tiedostoon tekijänoikeutta tai jos haluat luovuttaa tiedoston käyttäen jotain toista lisenssiä, voit käyttää erityistä [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons Upload Wizard] -toimintoa.",
- "upload-form-label-not-own-work-local-shared": "Voit myös kokeilla [[Special:Upload|tallennussivua sivustolla {{SITENAME}}]]. Saattaa olla, että sivusto antaa tallentaa tämän tiedoston sinne siellä voimassa olevien käytäntöjen mukaisesti.",
+ "upload-form-label-own-work-message-generic-local": "Vakuutan, että tallennan tämän tiedoston noudattaen sivustolla {{SITENAME}} voimassa olevia käyttöehtoja sekä lisenssejä koskevia käytäntöjä.",
+ "upload-form-label-not-own-work-message-generic-local": "Jos et kykene tallentamaan tätä tiedostoa noudattaen niitä käytäntöjä, jotka ovat voimassa sivustolla {{SITENAME}}, sulje tämä dialogi ja kokeile jotain toista menetelmää.",
+ "upload-form-label-not-own-work-local-generic-local": "Voit myös kokeilla [[Special:Upload|yleistä tallentamista]].",
+ "upload-form-label-own-work-message-generic-foreign": "Ymmärrän, että olen tallentamassa tätä tiedostoa yhteiseen mediasäilöön. Vakuutan, että teen tämän noudattaen asiaankuuluvia käyttöehtoja ja lisenssejä koskevia käytäntöjä.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Jos et kykene tallentamaan tätä tiedostoa noudattaen niitä käytäntöjä, jotka ovat voimassa yhteisessä mediasäilössä, sulje tämä dialogi ja kokeile jotain toista menetelmää.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Voit myös kokeilla [[Special:Upload|tallennussivua sivustolla {{SITENAME}}]]. Saattaa olla, että tämän tiedoston tallentaminen sinne on mahdollista siellä voimassa olevien käytäntöjen mukaisesti.",
"backend-fail-stream": "Tiedoston $1 virtauttaminen epäonnistui.",
"backend-fail-backup": "Tiedostoa $1 ei voitu varmuuskopioida.",
"backend-fail-notexists": "Tiedostoa $1 ei ole olemassa.",
"changecontentmodel-success-text": "Sisältötyyppiä kohteessa [[:$1]] on muutettu.",
"changecontentmodel-cannot-convert": "Sisältöä sivulla [[:$1]] ei voida muuntaa tyypiksi $2.",
"changecontentmodel-nodirectediting": "Sisältömalli $1 ei tue suoraa muokkaamista",
+ "changecontentmodel-emptymodels-title": "Mitään sisältömallia ei ole saatavilla",
+ "changecontentmodel-emptymodels-text": "Sisältöä sivulla [[:$1]] ei voida muuntaa mihinkään muotoon.",
"log-name-contentmodel": "Sisältömallin muutosloki",
"log-description-contentmodel": "Tapahtumat, jotka liittyvät sivun sisältömalleihin",
"logentry-contentmodel-new": "$1 {{GENDER:$2|loi}} sivun $3 käyttäen normaalista poikkeavaa sisältömallia \"$5\"",
"lockdbsuccesstext": "Tietokanta on lukittu.<br />\nMuista [[Special:UnlockDB|poistaa tietokannan lukitus]] kun huolto on tehty.",
"unlockdbsuccesstext": "Tietokannan lukitus on poistettu.",
"lockfilenotwritable": "Tietokannan lukitustiedostoa ei voi kirjoittaa. Tarkista oikeudet.",
+ "databaselocked": "Tietokanta on jo lukittu.",
"databasenotlocked": "Tietokantaa ei ole lukittu.",
"lockedbyandtime": "(lukinnut {{GENDER:$1|$1}} $2 kello $3)",
"move-page": "Siirrä $1",
"tags-delete-not-found": "Merkkausta \"$1\" ei ole olemassa.",
"tags-delete-too-many-uses": "Tämä merkkaus \"$1\" on käytössä useammassa kuin $2 sivuversiossa, joten sitä ei voi poistaa.",
"tags-delete-warnings-after-delete": "Merkkaus \"$1\" poistettiin, mutta toimenpide sai aikaan {{PLURAL:$2|seuraavan varoituksen|seuraavat varoitukset}}:",
+ "tags-delete-no-permission": "Sinulla ei ole oikeutta poistaa muutoksien yhteydessä olevia merkkauksia.",
"tags-activate-title": "Aktivoi merkkaus",
"tags-activate-question": "Olet nyt aktivoimassa merkkausta \"$1\".",
"tags-activate-reason": "Syy:",
"feedback-useragent": "User agent:",
"searchsuggest-search": "Hae",
"searchsuggest-containing": "sisältää...",
+ "api-error-autoblocked": "Sinun IP-osoitteesi on estetty automaattisesti, koska sitä on käyttänyt estetty käyttäjätunnus.",
"api-error-badaccess-groups": "Sinulla ei ole oikeutta tallentaa tiedostoja tähän wikiin.",
"api-error-badtoken": "Sisäinen virhe: virheellinen tarkistussumma.",
+ "api-error-blocked": "Sinut on estetty muokkaamasta.",
"api-error-copyuploaddisabled": "Tallentaminen URL-osoitteesta ei ole käytössä.",
"api-error-duplicate": "Samansisältöisiä tiedostoja löytyi {{PLURAL:$1|yksi kappale|useampia kappaleita}}.",
"api-error-duplicate-archive": "Sivustolla oli aiemmin {{PLURAL:$1|toinen samansisältöinen tiedosto|toisia samansisältöisiä tiedostoja}}, mutta {{PLURAL:$1|se|ne}} poistettiin.",
"log-action-filter-suppress-block": "Käyttäjätunnuksen häivyttäminen estämällä se",
"log-action-filter-suppress-reblock": "Käyttäjätunnuksen häivyttäminen uudella estolla",
"log-action-filter-upload-upload": "Uusi tallennus",
- "log-action-filter-upload-overwrite": "Päälletallennus"
+ "log-action-filter-upload-overwrite": "Päälletallennus",
+ "authmanager-provider-temporarypassword": "Väliaikainen salasana",
+ "authprovider-resetpass-skip-label": "Ohita"
}
"noname": "Tú hevur ikki skrivað eitt gyldugt brúkaranavn.",
"loginsuccesstitle": "Innritan væleydnað",
"loginsuccess": "'''Tú hevur nú ritað inn í {{SITENAME}} sum \"$1\".'''",
- "nosuchuser": "Eingin brúkari er við navninum \"$1\". \nBrúkaranøvn eru følsom fyri stórum og lítlum bókstavum.\nEftirkanna um tú hevur stavað rætt, ella [[Special:UserLogin/signup|stovna eina nýggja konto]].",
+ "nosuchuser": "Eingin brúkari er við navninum \"$1\". \nBrúkaranøvn eru følsom fyri stórum og lítlum bókstavum.\nEftirkanna um tú hevur stavað rætt, ella [[Special:CreateAccount|stovna eina nýggja konto]].",
"nosuchusershort": "Eingin brúkari er við navninum \"$1\". Kanna stavseting.",
"nouserspecified": "Tú mást skriva eitt brúkaranavn.",
"login-userblocked": "Hesin brúkarin er blokkaður. Tað er ikki loyvt at logga á.",
"accmailtext": "Eitt tilvildarliga valt loyniorð fyri brúkaran [[User talk:$1|$1]] er blivið sent til $2.\nTað kann broytast á ''[[Special:ChangePassword|broyt loyniorð]]'' síðuni tá tú ritar inn.",
"newarticle": "(Nýggj)",
"newarticletext": "Tú ert komin eftir eini slóð til eina síðu, ið ikki er til enn. Skriva í kassan niðanfyri, um tú vilt byrja uppá hesa síðuna.\n(Sí [$1 hjálparsíðuna] um tú ynskir fleiri upplýsingar).\nErt tú komin higar av einum mistaki, kanst tú trýsta á '''aftur'''-knøttin á kagaranum.",
- "anontalkpagetext": "----''Hetta er ein kjaksíða hjá einum dulnevndum brúkara, sum ikki hevur stovnað eina kontu enn, ella ikki brúkar hana. \nTí noyðast vit at brúka nummerisku IP-adressuna hjá honum ella henni.\nEin slík IP-adressa kann verða brúkt av fleiri brúkarum.\nErt tú ein dulnevndur brúkari, og meinar, at óviðkomandi viðmerkingar eru vendar til tín, so er best fyri teg at [[Special:UserLogin/signup|stovna eina kontu]] ella [[Special:UserLogin|rita inn]] fyri at sleppa undan samanblanding við aðrar dulnevndar brúkarar í framtíðini.''",
+ "anontalkpagetext": "----''Hetta er ein kjaksíða hjá einum dulnevndum brúkara, sum ikki hevur stovnað eina kontu enn, ella ikki brúkar hana. \nTí noyðast vit at brúka nummerisku IP-adressuna hjá honum ella henni.\nEin slík IP-adressa kann verða brúkt av fleiri brúkarum.\nErt tú ein dulnevndur brúkari, og meinar, at óviðkomandi viðmerkingar eru vendar til tín, so er best fyri teg at [[Special:CreateAccount|stovna eina kontu]] ella [[Special:UserLogin|rita inn]] fyri at sleppa undan samanblanding við aðrar dulnevndar brúkarar í framtíðini.''",
"noarticletext": "Tað er í løtuni ongin tekstur á hesi síðu.\nTú kanst [[Special:Search/{{PAGENAME}}|leita eftir hesum síðu heitinum]] á øðrum síðum,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} leita í líknandi loggum],\nella [{{fullurl:{{FULLPAGENAME}}|action=edit}} rætta hesa síðu]</span>.",
"noarticletext-nopermission": "Tað er í løtuni ongin tekstur á hesi síðu.\nTú kanst [[Special:Search/{{PAGENAME}}|leita eftir hesum síðuheiti]] á øðrum síðum, \nella <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} leita eftir viðkomandi loggum]</span>, men tú hevur ikki loyvi til at stovna hesa síðu.",
"missing-revision": "Endurskoðan #$1 av síðuni við heitinum \"{{FULLPAGENAME}}\" er ikki til.\n\nHetta skyldast vanliga tað, at tú fylgir einari gamlari søguslóð til eina síðu, sum er blivin slettað. \nNærri frágreiðing kanst tú finna í [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} strikingar logginum].",
"categories": "Bólkar",
"categoriespagetext": "Fylgjandi {{PLURAL:$1|bólkur inniheldur|bólkar innihalda}} síður ella miðlar (media).\n[[Special:UnusedCategories|Ikki brúktir bólkar]] eru ikki vístar her.\nSí eisini [[Special:WantedCategories|ynsktir bólkar]].",
"categoriesfrom": "Vís bólkar, byrja við:",
- "special-categories-sort-count": "sortera eftir stødd",
- "special-categories-sort-abc": "uppdeil í bókstavarøð",
"deletedcontributions": "Slettaði brúkaraíkøst",
"deletedcontributions-title": "Slettaði brúkaraíkøst",
"sp-deletedcontributions-contribs": "íkøst",
"import-logentry-upload-detail": "$1 {{PLURAL:$1|versjón|versjónir}}",
"import-logentry-interwiki-detail": "$1 {{PLURAL:$1|versjón|versjónir}} frá $2",
"javascripttest": "Royndarkoyring av JavaScript",
- "javascripttest-pagetext-noframework": "Henda síðan er løgd av til at koyra JavaScript royndir.",
- "javascripttest-pagetext-skins": "Vel eina útsjónd at koyra royndirnar við:",
"tooltip-pt-userpage": "Tín brúkarasíða",
"tooltip-pt-anonuserpage": "Brúkarasíðan fyri IP adressuna, sum tú rættar frá",
"tooltip-pt-mytalk": "Tín kjaksíða",
"Gnangbade",
"Frigory",
"Lemondoge",
- "Jdforrester"
+ "Jdforrester",
+ "Yasten",
+ "Psychoslave",
+ "Trial",
+ "Matma Rex",
+ "Dcausse"
]
},
"tog-underline": "Soulignement des liens :",
"tog-editsectiononrightclick": "Activer la modification des sections par un clic droit sur les titres de section",
"tog-watchcreations": "Ajouter à ma liste de suivi les pages que je crée et les fichiers que j’importe",
"tog-watchdefault": "Ajouter à ma liste de suivi les pages et les fichiers que je modifie",
- "tog-watchmoves": "Ajouter à ma liste de suivi les pages et les fichiers que je renomme",
+ "tog-watchmoves": "Ajouter les pages et les fichiers que je déplace dans ma liste de suivi",
"tog-watchdeletion": "Ajouter à ma liste de suivi les pages et les fichiers que je supprime",
"tog-watchuploads": "Ajouter les nouveaux fichiers que j’importe à ma liste de suivi",
"tog-watchrollback": "Ajouter à ma liste de suivi les pages sur lesquelles j’ai effectué une révocation",
"tog-enotifusertalkpages": "M’avertir par courriel si ma page de discussion est modifiée",
"tog-enotifminoredits": "M’avertir par courriel également lors des modifications mineures des pages ou des fichiers",
"tog-enotifrevealaddr": "Afficher mon adresse électronique dans les courriels de notification",
- "tog-shownumberswatching": "Afficher le nombre d’utilisateurs qui suivent la page",
+ "tog-shownumberswatching": "Afficher le nombre d’utilisateurs en cours",
"tog-oldsig": "Signature existante :",
"tog-fancysig": "Traiter la signature comme du wikitexte (sans lien automatique)",
"tog-uselivepreview": "Utiliser l’aperçu rapide",
"category-empty": "<em>Cette catégorie ne contient actuellement aucune page ni fichier multimédia.</em>",
"hidden-categories": "{{PLURAL:$1|Catégorie cachée|Catégories cachées}}",
"hidden-category-category": "Catégories cachées",
- "category-subcat-count": "Cette catégorie {{PLURAL:$2|0=ne comprend aucune sous-catégorie|1=comprend seulement la sous-catégorie ci-dessous|comprend les $2 sous-catégories, dont {{PLURAL:$1|0=aucune|1=celle|les $1}} ci-dessous}}.",
+ "category-subcat-count": "Cette catégorie {{PLURAL:$2|0=ne comprend aucune sous-catégorie|1=comprend seulement la sous-catégorie ci-dessous|comprend $2 sous-catégories, dont {{PLURAL:$1|0=aucune|1=celle|les $1}} ci-dessous}}.",
"category-subcat-count-limited": "Cette catégorie comprend {{PLURAL:$1|la sous-catégorie|les $1 sous-catégories}} ci-dessous.",
"category-article-count": "Cette catégorie {{PLURAL:$2|0=ne comprend aucune page|1=comprend seulement la page ci-dessous|comprend $2 pages, dont {{PLURAL:$1|0=aucune|1=celle|les $1}} ci-dessous}}.",
"category-article-count-limited": "{{PLURAL:$1|0=Aucune page ne figure|1=La page suivante figure|Les $1 pages suivantes figurent}} dans la présente catégorie.",
"viewhelppage": "Voir la page d'aide",
"categorypage": "Voir la page de catégorie",
"viewtalkpage": "Voir la page de discussion",
- "otherlanguages": "Autres langues",
+ "otherlanguages": "Dans d'autres langues",
"redirectedfrom": "(Redirigé depuis $1)",
"redirectpagesub": "Page de redirection",
"redirectto": "Rediriger vers :",
"confirmable-no": "Non",
"thisisdeleted": "Désirez-vous afficher ou restaurer $1 ?",
"viewdeleted": "Voir $1 ?",
- "restorelink": "{{PLURAL:$1|la modification effacée|les $1 modifications effacées}}",
+ "restorelink": "{{PLURAL:$1|une modification effacée|$1 modifications effacées}}",
"feedlinks": "Flux :",
- "feed-invalid": "Type de flux invalide.",
+ "feed-invalid": "Type de flux invalide pour abonnement.",
"feed-unavailable": "Les flux de syndication ne sont pas disponibles",
"site-rss-feed": "Flux RSS de $1",
"site-atom-feed": "Flux Atom de $1",
"password-change-forbidden": "Vous ne pouvez pas modifier les mots de passe sur ce wiki.",
"externaldberror": "Soit une erreur s’est produite sur la base de données d’authentification, soit vous n’êtes pas autorisé à mettre à jour votre compte externe.",
"login": "Connexion",
+ "login-security": "Vérifier votre identité",
"nav-login-createaccount": "Créer un compte ou se connecter",
"userlogin": "Créer un compte ou se connecter",
"userloginnocreate": "Connexion",
"userlogin-resetpassword-link": "Mot de passe oublié ?",
"userlogin-helplink2": "Aide pour se connecter",
"userlogin-loggedin": "Vous êtes déjà connecté{{GENDER:$1||e|(e)}} en tant que $1.\nUtilisez le formulaire ci-dessous pour vous connecter avec un autre compte utilisateur.",
+ "userlogin-reauth": "Vous devez vous reconnecter pour vérifier que vous êtes {{GENDER:$1|$1}}.",
"userlogin-createanother": "Créer un autre compte",
"createacct-emailrequired": "Adresse de courriel",
"createacct-emailoptional": "Adresse de courriel (facultative)",
"createacct-email-ph": "Entrez votre adresse de courriel",
"createacct-another-email-ph": "Entrez l’adresse de courriel",
"createaccountmail": "Utiliser un mot de passe aléatoire temporaire et l’envoyer à l’adresse de courriel spécifiée",
+ "createaccountmail-help": "Peut être utilisé pour créer un compte pour une autre personne sans connaître le mot de passe.",
"createacct-realname": "Nom réel (facultatif)",
"createaccountreason": "Motif :",
"createacct-reason": "Motif",
"createacct-reason-ph": "Pourquoi créez-vous un autre compte",
+ "createacct-reason-help": "Message affiché dans le journal de création de compte",
"createacct-submit": "Créez votre compte",
"createacct-another-submit": "Créer le compte",
+ "createacct-continue-submit": "Continuer la création de compte",
+ "createacct-another-continue-submit": "Continuer la création de compte",
"createacct-benefit-heading": "{{SITENAME}} est écrit par des gens comme vous.",
"createacct-benefit-body1": "modification{{PLURAL:$1||s}}",
"createacct-benefit-body2": "page{{PLURAL:$1||s}}",
"nocookiesnew": "Le compte utilisateur a été créé, mais vous n’êtes pas connecté{{GENDER:||e|(e)}}.\n{{SITENAME}} utilise des cookies pour conserver la connexion mais vous les avez désactivés.\nVeuillez les activer et vous reconnecter avec le même nom et le même mot de passe.",
"nocookieslogin": "{{SITENAME}} utilise des cookies pour conserver la connexion mais vous les avez désactivés.\nVeuillez les activer et vous reconnecter.",
"nocookiesfornew": "Le compte utilisateur n’a pas été créé, car nous n’avons pas pu identifier son origine.\nVérifiez que vous avez activé les cookies, rechargez la page et essayez à nouveau.",
+ "createacct-loginerror": "Le compte a bien été créé mais vous ne pouvez pas vous connecter automatiquement? Veuillez vous [[Special:UserLogin|connecter manuellement]].",
"noname": "Vous n’avez pas saisi un nom d’utilisateur valide.",
"loginsuccesstitle": "Connecté",
"loginsuccess": "<strong>Vous êtes maintenant connecté{{GENDER:$1||e|(e)}} à {{SITENAME}} en tant que « $1 ».</strong>",
- "nosuchuser": "L'utilisateur « $1 » n’existe pas.\nLes noms d’utilisateurs sont sensibles à la casse.\nVérifiez l’orthographe, ou [[Special:UserLogin/signup|créez un nouveau compte]].",
+ "nosuchuser": "L’utilisateur « $1 » n’existe pas.\nLes noms d’utilisateurs sont sensibles à la casse.\nVérifiez l’orthographe, ou [[Special:CreateAccount|créez un nouveau compte]].",
"nosuchusershort": "Il n’y a pas de contributeur avec le nom « $1 ».\nVeuillez vérifier l’orthographe.",
"nouserspecified": "Vous devez saisir un nom d’utilisateur.",
"login-userblocked": "Cet utilisateur est bloqué. Connexion non autorisée.",
"noemail": "Aucune adresse de courriel n’a été enregistrée pour l'utilisateur « $1 ».",
"noemailcreate": "Vous devez fournir une adresse de courriel valide",
"passwordsent": "Un nouveau mot de passe a été envoyé à l’adresse de courriel de l’utilisateur « $1 ».\nVeuillez vous reconnecter après l’avoir reçu.",
- "blocked-mailpassword": "Votre adresse IP est bloquée pour la modification. Pour éviter les abus, il n’est pas autorisé d’utiliser la récupération de mot de passe à partir de cette adresse IP.",
+ "blocked-mailpassword": "Votre adresse IP est bloquée en modification. Pour éviter les abus, il n’est pas autorisé d’utiliser la récupération de mot de passe à partir de cette adresse IP.",
"eauthentsent": "Un courriel de confirmation a été envoyé à l’adresse indiquée.\nAvant qu’un autre courriel ne soit envoyé à ce compte, vous devrez suivre les instructions du courriel et confirmer que le compte est bien le vôtre.",
"throttled-mailpassword": "Un courriel de réinitialisation de votre mot de passe a déjà été envoyé durant {{PLURAL:$1|la dernière heure|les $1 dernières heures}}. \nAfin d’éviter les abus, un seul courriel de réinitialisation de votre mot de passe sera envoyé par {{PLURAL:$1|heure|intervalle de $1 heures}}.",
"mailerror": "Erreur lors de l’envoi du courriel : $1",
"createacct-another-realname-tip": "Le véritable nom est optionnel.\nSi vous décidez de le fournir, il sera utilisé pour créditer l’auteur de ses travaux.",
"pt-login": "Se connecter",
"pt-login-button": "Se connecter",
+ "pt-login-continue-button": "Continuer la connexion",
"pt-createaccount": "Créer un compte",
"pt-userlogout": "Se déconnecter",
"php-mail-error-unknown": "Erreur inconnue dans la fonction <code>mail()</code> de PHP.",
"botpasswords-invalid-name": "Le nom d’utilisateur spécifié ne contient pas de séparateur de mot de passe de robots (« $1 »).",
"botpasswords-not-exist": "L’utilisateur « $1 » n’a pas de nom de mot de passe de robots appelé « $2 ».",
"resetpass_forbidden": "Les mots de passe ne peuvent pas être changés",
+ "resetpass_forbidden-reason": "Les mots de passe ne peuvent pas être modifiés : $1",
"resetpass-no-info": "Vous devez être connecté pour avoir accès à cette page.",
"resetpass-submit-loggedin": "Changer de mot de passe",
"resetpass-submit-cancel": "Annuler",
"passwordreset-emailsentusername": "S’il y a une adresse de courriel associée à ce nom d’utilisateur, alors un courriel de réinitialisation de mot de passe sera envoyé.",
"passwordreset-emailsent-capture": "Un courriel de réinitialisation de mot de passe a été envoyé, qui est affiché ci-dessous.",
"passwordreset-emailerror-capture": "Un courriel de réinitialisation de mot de passe a été généré, qui est affiché ci-dessous, mais l'envoi à l'{{GENDER:$2|utilisateur|utilisatrice}} a échoué : $1",
+ "passwordreset-emailsent-capture2": "The password reset {{PLURAL:$1|Le courriel de réinitialisation du mot de passe a été envoyé|Les courriels de réinitialisation du mot de passe ont été envoyés}}. {{PLURAL:$1|Le nom d’utilisateur et le mot de passe sont affichés|La liste des noms d’utilisateur et mots de passe est affichée}} ci-dessous.",
+ "passwordreset-emailerror-capture2": "L’envoi de courriel à {{GENDER:$2|l’utilisateur|l’utilisatrice}} a échoué : $1 {{PLURAL:$3|Le nom d’utilisateur et le mot de passe sont affichés|La liste des noms d’utilisateur et des mots de passe est affichée}} ci-dessous.",
+ "passwordreset-nocaller": "Un appelant doit être fourni",
+ "passwordreset-nosuchcaller": "L’appelant n’existe pas : $1",
+ "passwordreset-ignored": "La réinitialisation du mot de passe n’a pas été gérée. Peut-être qu'aucun fournisseur n’a été configuré ?",
+ "passwordreset-invalideamil": "Adresse de messagerie non valide",
+ "passwordreset-nodata": "Ni nom d’utilisateur ni adresse de messagerie n’ont été fournis",
"changeemail": "Changer ou supprimer l’adresse de courriel",
"changeemail-header": "Complétez ce formulaire pour modifier votre adresse de courriel. Si vous voulez supprimer l’association d’une adresse de courriel avec votre compte, laissez la nouvelle adresse de courriel vide lors de la soumission du formulaire.",
"changeemail-passwordrequired": "Vous devrez saisir votre mot de passe pour confirmer cette modification.",
"accmailtext": "Un mot de passe généré aléatoirement pour [[User talk:$1|$1]] a été envoyé à $2.\nIl peut être modifié sur la page ''[[Special:ChangePassword|Changement de mot de passe]]'' après connexion.",
"newarticle": "(Nouveau)",
"newarticletext": "Vous avez suivi un lien vers une page qui n’existe pas encore. \nAfin de créer cette page, entrez votre texte dans la boîte ci-après (vous pouvez consulter [$1 la page d’aide] pour plus d’informations). \nSi vous êtes arrivé{{GENDER:||e}} ici par erreur, cliquez sur le bouton '''retour''' de votre navigateur.",
- "anontalkpagetext": "---- ''Vous êtes sur la page de discussion d'un utilisateur anonyme qui n'a pas encore créé de compte ou qui n'en utilise pas. Pour cette raison, nous devons utiliser son adresse IP pour l'identifier. Une adresse IP peut être partagée par plusieurs utilisateurs. Si vous êtes un{{GENDER:||e|}} utilisat{{GENDER:|eur|rice|eur}} anonyme et si vous constatez que des commentaires qui ne vous concernent pas vous ont été adressés, vous pouvez [[Special:UserLogin/signup|créer un compte]] ou [[Special:UserLogin|vous connecter]] afin d'éviter toute confusion future avec d'autres contributeurs anonymes.''",
+ "anontalkpagetext": "----\n<em>Vous êtes sur la page de discussion d’un utilisateur anonyme qui n’a pas encore créé de compte ou qui n’en utilise pas</em>.\nPour cette raison, nous devons utiliser son adresse IP pour l’identifier.\nUne adresse IP peut être partagée par plusieurs utilisateurs.\nSi vous êtes un{{GENDER:||e|}} utilisat{{GENDER:|eur|rice|eur}} anonyme et si vous constatez que des commentaires qui ne vous concernent pas vous ont été adressés, vous pouvez [[Special:CreateAccount|créer un compte]] ou [[Special:UserLogin|vous connecter]] afin d’éviter toute confusion future avec d’autres contributeurs anonymes.",
"noarticletext": "Il n’y a pour l’instant aucun texte sur cette page.\nVous pouvez [[Special:Search/{{PAGENAME}}|lancer une recherche sur ce titre]] dans les autres pages,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rechercher dans les opérations liées]\nou [{{fullurl:{{FULLPAGENAME}}|action=edit}} créer cette page]</span>.",
"noarticletext-nopermission": "Il n'y a pour l'instant aucun texte sur cette page.\nVous pouvez [[Special:Search/{{PAGENAME}}|faire une recherche sur ce titre]] dans les autres pages,\nou <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rechercher dans les journaux associés]</span>.",
"missing-revision": "La révision n° $1 de la page intitulée « {{FULLPAGENAME}} » n'existe pas.\n\nCela survient en général en suivant un lien historique obsolète vers une page qui a été supprimée.\nVous pouvez trouver plus de détails dans le [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} journal des suppressions].",
"right-override-export-depth": "Exporter les pages en incluant les pages liées jusqu'à une profondeur de 5 niveaux",
"right-sendemail": "Envoyer un courriel aux autres utilisateurs",
"right-passwordreset": "Voir les courriels de réinitialisation des mots de passe",
- "right-managechangetags": "Créer et supprimer des [[Spécial:Balises|balises]] de la base de données",
+ "right-managechangetags": "Créer et (dés)activer des [[Special:Tags|balises]]",
"right-applychangetags": "Appliquer [[Special:Tags|les balises]] avec ses propres modifications",
"right-changetags": "Ajouter et supprimer de façon arbitraire [[Special:Tags|des balises]] sur des révisions individuelles et des entrées de journal",
+ "right-deletechangetags": "Supprimer des [[Special:Tags|balises]] de la base de données",
"grant-generic": "ensemble de droits « $1 »",
"grant-group-page-interaction": "Interagir avec des pages",
"grant-group-file-interaction": "Interagir avec des médias",
"action-viewmyprivateinfo": "voir vos informations personnelles",
"action-editmyprivateinfo": "modifier vos informations personnelles",
"action-editcontentmodel": "modifier le modèle de contenu d’une page",
- "action-managechangetags": "créer et supprimer des balises de la base de données",
+ "action-managechangetags": "créer et (dés)activer des balises",
"action-applychangetags": "appliquer les balises avec vos modifications",
"action-changetags": "ajouter et supprimer de façon arbitraire des balises sur des révisions individuelles et des entrées de journal",
+ "action-deletechangetags": "supprimer des balises de la base de données",
"nchanges": "$1 modification{{PLURAL:$1||s}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|depuis la dernière visite}}",
"enhancedrc-history": "historique",
"upload-form-label-own-work": "Je suis l’auteur de cette œuvre",
"upload-form-label-infoform-categories": "Catégories",
"upload-form-label-infoform-date": "Date",
- "upload-form-label-own-work-message-local": "Je confirme que je télécharge ce fichier suivant les conditions et les politiques de licence de {{SITENAME}}",
- "upload-form-label-not-own-work-message-local": "Si vous ne pouvez pas télécharger ce fichier d’après les politiques de {{SITENAME}}, veuillez fermer cette boîte de dialogue et essayer une autre méthode.",
- "upload-form-label-not-own-work-local-local": "Vous pouvez aussi essayer [[Special:Upload|la page de téléchargement par défaut]].",
- "upload-form-label-own-work-message-default": "Je comprends que je téléverse ce fichier vers un dépôt partagé. Je confirme agir en accord avec les conditions d’utilisation et les règles relatives aux licences de celui-ci.",
- "upload-form-label-not-own-work-message-default": "Si vous n’êtes pas en mesure de téléverser ce fichier de façon conforme aux règles de ce dépôt partagé, veuillez fermer cette boîte de dialogue et essayer une autre méthode.",
- "upload-form-label-not-own-work-local-default": "Vous pouvez également essayer d’utiliser [[Special:Upload|la page de téléversement de {{SITENAME}}]], si les règles du site autorisent le téléversement du fichier.",
- "upload-form-label-own-work-message-shared": "Je certifie être le détenteur des droits d’auteur sur ce fichier, j’accepte de publier ce fichier sur Wikimedia Commons en le plaçant irrévocablement sous licence [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] et j’accepte les [https://wikimediafoundation.org/wiki/Terms_of_Use conditions d’utilisation].",
- "upload-form-label-not-own-work-message-shared": "Si vous n’êtes pas le détenteur des droits d’auteur sur ce fichier ou que vous voulez le publier sous une licence différente, vous pouvez utiliser l’[https://commons.wikimedia.org/wiki/Special:UploadWizard assistant d’import].",
- "upload-form-label-not-own-work-local-shared": "Vous pouvez également essayer d’utiliser [[Special:Upload|la page de téléversement de {{SITENAME}}]], si les règles du site autorisent le téléversement du fichier.",
+ "upload-form-label-own-work-message-generic-local": "Je confirme que je télécharge ce fichier suivant les conditions et les politiques de licence de {{SITENAME}}",
+ "upload-form-label-not-own-work-message-generic-local": "Si vous ne pouvez pas télécharger ce fichier d’après les politiques de {{SITENAME}}, veuillez fermer cette boîte de dialogue et essayer une autre méthode.",
+ "upload-form-label-not-own-work-local-generic-local": "Vous pouvez aussi essayer [[Special:Upload|la page de téléchargement par défaut]].",
+ "upload-form-label-own-work-message-generic-foreign": "Je comprends que je téléverse ce fichier vers un dépôt partagé. Je confirme agir en accord avec les conditions d’utilisation et les règles relatives aux licences de celui-ci.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Si vous n’êtes pas en mesure de téléverser ce fichier de façon conforme aux règles de ce dépôt partagé, veuillez fermer cette boîte de dialogue et essayer une autre méthode.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Vous pouvez également essayer d’utiliser [[Special:Upload|la page de téléversement de {{SITENAME}}]], si les règles du site autorisent le téléversement du fichier.",
"backend-fail-stream": "Impossible de lire le fichier $1.",
"backend-fail-backup": "Impossible de sauvegarder le fichier $1.",
"backend-fail-notexists": "Le fichier $1 n’existe pas.",
"trackingcategories-msg": "Catégorie de suivi",
"trackingcategories-name": "Nom du message",
"trackingcategories-desc": "Critère d’inclusion de la catégorie",
+ "restricted-displaytitle-ignored": "Pages avec des titres d'affichage ignorés",
+ "restricted-displaytitle-ignored-desc": "La page a un <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> ignoré parce qu'il n'est pas équivalent au titre actuel de la page.",
"noindex-category-desc": "La page contient <code><nowiki>__NOINDEX__</nowiki></code> et est dans un espace de noms où ce marquage est autorisé ; elle ne sera donc pas indexée par les robots.",
"index-category-desc": "La page contient <code><nowiki>__INDEX__</nowiki></code> et est dans un espace de noms où ce marquage est autorisé ; elle sera donc indexée par les robots alors qu’elle ne l’aurait pas été normalement.",
"post-expand-template-inclusion-category-desc": "La taille de la page dépasse <code>$wgMaxArticleSize</code> après le développement de tous ses modèles ; certains n’ont donc pas été développés.",
"rollbacklinkcount": "révoquer $1 {{PLURAL:$1|modification|modifications}}",
"rollbacklinkcount-morethan": "révoquer plus de $1 {{PLURAL:$1|modification|modifications}}",
"rollbackfailed": "La révocation a échoué",
+ "rollback-missingparam": "Paramètres nécessaires à la demande manquants.",
"cantrollback": "Impossible de révoquer la modification ;\nle dernier contributeur est le seul auteur de cette page.",
"alreadyrolled": "Impossible de révoquer la dernière modification de la page « [[:$1]] » effectuée par [[User:$2|$2]] ([[User talk:$2|Discuter]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) ;\nquelqu'un d'autre a déjà modifié ou révoqué la page.\n\nLa dernière modification de la page a été effectuée par [[User:$3|$3]] ([[User talk:$3|Discuter]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "Le résumé de la modification était : <em>$1</em>.",
"revertpage": "Révocation des modifications de [[Special:Contributions/$2|$2]] ([[User talk:$2|discussion]]) vers la dernière version de [[User:$1|$1]]",
"revertpage-nouser": "Révocation des modifications par un utilisateur masqué à la dernière version par {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Révocation des modifications effectuées par $1 ;\nrétablissement de la dernière version par $2.",
+ "rollback-success-notify": "Modifications annulées par $1 ;\nretour à la dernière révision par $2. [$3 Voir les changements]",
"sessionfailure-title": "Erreur de session",
"sessionfailure": "Votre session de connexion semble avoir des problèmes ;\ncette action a été annulée en prévention d'un piratage de session.\nVeuillez cliquer sur « Précédent », rechargez la page d'où vous venez, puis réessayez.",
"changecontentmodel": "Modifier le modèle de contenu d’une page",
"changecontentmodel-success-text": "Le modèle de contenu de [[:$1]] a été modifié.",
"changecontentmodel-cannot-convert": "Le contenu sur [[:$1]] n’a pas pu être converti en un type de $2.",
"changecontentmodel-nodirectediting": "Le modèle de contenu $1 ne permet pas la modification directe",
+ "changecontentmodel-emptymodels-title": "Aucun modèle de contenu disponible",
+ "changecontentmodel-emptymodels-text": "Le contenu sur [[:$1]] ne peut être converti en aucun type.",
"log-name-contentmodel": "Journal de modification de modèle de contenu",
"log-description-contentmodel": "Événements relatifs aux modèles de contenu d’une page",
"logentry-contentmodel-new": "$1 {{GENDER:$2|a créé}} la page $3 en utilisant un modèle de contenu « $5 » autre que celui par défaut",
"whatlinkshere-links": "← liens",
"whatlinkshere-hideredirs": "$1 les redirections",
"whatlinkshere-hidetrans": "$1 les inclusions",
- "whatlinkshere-hidelinks": "$1 les liens",
+ "whatlinkshere-hidelinks": "$1 liens",
"whatlinkshere-hideimages": "$1 les liens vers le fichier",
"whatlinkshere-filters": "Filtres",
"whatlinkshere-submit": "Lister",
"lockdbsuccesstext": "La base de données a été verrouillée.<br />\nN'oubliez pas de la [[Special:UnlockDB|déverrouiller]] lorsque vous aurez terminé votre opération de maintenance.",
"unlockdbsuccesstext": "La base de données a été déverrouillée.",
"lockfilenotwritable": "Le fichier de verrouillage de la base de données n'est pas inscriptible.\nPour bloquer ou débloquer la base de données, il doit être accessible par le serveur web.",
+ "databaselocked": "La base de données est déjà verrouillée.",
"databasenotlocked": "La base de données n'est pas verrouillée.",
"lockedbyandtime": "(par $1 le $2 à $3)",
"move-page": "Renommer $1",
"invalidateemail": "Annuler la confirmation de l'adresse de courriel",
"notificationemail_subject_changed": "L’adresse courriel enregistrée sur {{SITENAME}} a été changée",
"notificationemail_subject_removed": "L’adresse courriel enregistrée sur {{SITENAME}} a été supprimée",
- "notificationemail_body_changed": "Quelqu’un, probablement vous, connecté depuis l’adresse IP $1,\na changé l’adresse courriel associée au compte « $2 » sur {{SITENAME}}\nen « $3 ».\n\nSi ce n’était pas vous, contactez un administrateur du site immédiatement.",
+ "notificationemail_body_changed": "Quelqu’un, probablement vous, connecté depuis l’adresse IP $1, a changé l’adresse courriel\nassociée au compte « $2 » sur {{SITENAME}} en « $3 ».\n\nSi ce n’était pas vous, contactez un administrateur du site immédiatement.",
"notificationemail_body_removed": "Quelqu’un, probablement vous, connecté depuis l’adresse IP $1,\na suprrimé l’adresse courriel associée au compte « $2 » sur {{SITENAME}}.\n\nSi ce n’était pas vous, contactez un administrateur du site immédiatement.",
"scarytranscludedisabled": "[La transclusion interwiki est désactivée]",
"scarytranscludefailed": "[La récupération de modèle a échoué pour $1]",
"confirm-watch-top": "Ajouter cette page à votre liste de suivi ?",
"confirm-unwatch-button": "Valider",
"confirm-unwatch-top": "Supprimer cette page de votre liste de suivi ?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Révoquer les modifications de cette page ?",
"semicolon-separator": " ; ",
"colon-separator": " : ",
"percent": "$1 %",
"timezone-local": "Local",
"duplicate-defaultsort": "Attention : la clé de tri par défaut « $2 » écrase la précédente clé « $1 ».",
"duplicate-displaytitle": "<strong>Attention :</strong> Le titre d'affichage « $2 » remplace l'ancien titre d'affichage « $1 ».",
+ "restricted-displaytitle": "<strong>Avertissement :</strong> le titre d’affichage \"$1\" a été ignoré car il n'est pas équivalent au titre effectif de la page.",
"invalid-indicator-name": "<strong>Erreur :</strong> L’attribut <code>name</code> des indicateurs d’état de la page ne doit pas être vide.",
"version": "Version",
"version-extensions": "Extensions installées",
"tags-delete-not-found": "La balise « $1 » n’existe pas.",
"tags-delete-too-many-uses": "La balise « $1 » est appliquée à plus de $2 {{PLURAL:$2|révision|révisions}}, ce qui signifie qu'elle ne peut pas être supprimée.",
"tags-delete-warnings-after-delete": "La balise « $1 » a été supprimée, mais {{PLURAL:$2|l’avertissement suivant a|les avertissements suivants ont}} été rencontré{{PLURAL:$2||s}} :",
+ "tags-delete-no-permission": "Vous n’avez pas le droit de supprimer des balises de changement.",
"tags-activate-title": "Activer la balise",
"tags-activate-question": "Vous êtes sur le point d'activer la balise « $1 ».",
"tags-activate-reason": "Motif :",
"api-error-nomodule": "Erreur interne : aucun module de versement défini.",
"api-error-ok-but-empty": "Erreur interne : Le serveur n'a pas répondu.",
"api-error-overwrite": "Écraser un fichier existant n'est pas autorisé.",
- "api-error-ratelimited": "Vous essayez de télécharger plus de fichiers dans un court espace de temps que ce que ce wiki autorise.\nVeuillez réessayer dans quelques minutes.",
+ "api-error-ratelimited": "Vous essayez de téléverser plus de fichiers dans un court espace de temps que ce que ce wiki peut accepter.\nVeuillez réessayer dans quelques minutes.",
"api-error-stashfailed": "Erreur interne : le serveur n'a pas pu enregistrer le fichier temporaire.",
"api-error-publishfailed": "Erreur interne : Le serveur n'a pas pu publier le fichier temporaire.",
"api-error-stasherror": "Une erreur s'est produite lors du téléchargement du fichier pour le dissimuler.",
"log-action-filter-suppress-block": "Suppression d’utilisateur par blocage",
"log-action-filter-suppress-reblock": "Suppression d’utilisateur par blocage réitéré",
"log-action-filter-upload-upload": "Nouveau téléversement",
- "log-action-filter-upload-overwrite": "Réitérer le téléversement"
+ "log-action-filter-upload-overwrite": "Réitérer le téléversement",
+ "authmanager-authn-not-in-progress": "L’authentification n’est pas en cours ou les données de session ont été perdues. Veuillez recommencer depuis le début.",
+ "authmanager-authn-no-primary": "Les informations d’identification fournies n’ont pas pu être authentifiées.",
+ "authmanager-authn-no-local-user": "Les informations d’identification ne sont associées à aucun utilisateur sur ce wiki.",
+ "authmanager-authn-no-local-user-link": "Les informations d’authentification sont valides mais ne sont associées à aucun utilisateur sur ce wiki. Connectez-vous d’une autre manière, ou créez un nouvel utilisateur, et vous aurez la possibilité de lier vos informations précédentes à ce compte.",
+ "authmanager-authn-autocreate-failed": "La création automatique d’un compte local a échoué : $1",
+ "authmanager-change-not-supported": "Les informations d’identification fournies ne peuvent pas être modifiées, car rien ne les utiliserait.",
+ "authmanager-create-disabled": "La création de compte est désactivée.",
+ "authmanager-create-from-login": "Pour créer votre compte, veuillez remplir les champs ci-dessous.",
+ "authmanager-create-not-in-progress": "La création de compte n’est pas en cours, ou les données de session ont été perdues. Veuillez recommencer depuis le début.",
+ "authmanager-create-no-primary": "Les informations d’identification fournies n’ont pas pu être utilisées pour la création de compte.",
+ "authmanager-link-no-primary": "Les informations d’identification fournies n’ont pas pu être utilisées pour lier un compte.",
+ "authmanager-link-not-in-progress": "La liaison de compte n’est pas en cours ou les données de session ont été perdues. Veuillez recommencer depuis le début.",
+ "authmanager-authplugin-setpass-failed-title": "Échec du changement de mot de passe",
+ "authmanager-authplugin-setpass-failed-message": "Le module d’authentification a refusé le changement de mot de passe.",
+ "authmanager-authplugin-create-fail": "Le module d’authentification a refusé la création de compte.",
+ "authmanager-authplugin-setpass-denied": "Le module d’authentification ne permet pas la modification des mots de passe.",
+ "authmanager-authplugin-setpass-bad-domain": "Domaine non valide.",
+ "authmanager-autocreate-noperm": "La création automatique de compte n’est pas autorisée.",
+ "authmanager-autocreate-exception": "La création automatique de compte est désactivée temporairement, du fait d’erreurs antérieures.",
+ "authmanager-userdoesnotexist": "Le compte utilisateur « $1 » n’est pas inscrit.",
+ "authmanager-userlogin-remembermypassword-help": "Indique si le mot de passe doit être mémorisé au-delà de la durée de la session.",
+ "authmanager-username-help": "Nom d’utilisateur pour l’authentification.",
+ "authmanager-password-help": "Mot de passe pour l’authentification.",
+ "authmanager-domain-help": "Domaine pour l’authentification externe.",
+ "authmanager-retype-help": "Mot de passe de nouveau pour confirmation.",
+ "authmanager-email-label": "Courriel",
+ "authmanager-email-help": "Adresse de messagerie",
+ "authmanager-realname-label": "Nom réel",
+ "authmanager-realname-help": "Nom réel de l’utilisateur",
+ "authmanager-provider-password": "Authentification par mot de passe",
+ "authmanager-provider-password-domain": "Authentification par mot de passe et domaine",
+ "authmanager-provider-temporarypassword": "Mot de passe temporaire",
+ "authprovider-confirmlink-message": "D’après vos dernières tentatives de connexion, les comptes suivants peuvent être liés à votre compte wiki. Les lier vous permettra de se connecter via ces comptes. Veuillez sélectionner lesquels doivent être liés.",
+ "authprovider-confirmlink-request-label": "Comptes qui doivent être liés",
+ "authprovider-confirmlink-success-line": "$1 : Liés avec succès.",
+ "authprovider-confirmlink-failed": "La liaison du compte n’a pas bien réussi : $1",
+ "authprovider-confirmlink-ok-help": "Continuer après l’affichage des messages d’échec de liaison.",
+ "authprovider-resetpass-skip-label": "Sauter",
+ "authprovider-resetpass-skip-help": "Sauter la réinitialisation du mot de passe.",
+ "authform-nosession-login": "L’authentification a réussi, mais votre navigateur ne peut pas se « souvenir » d’avoir été connecté.\n\n$1",
+ "authform-nosession-signup": "Le compte a été créé, mais votre navigateur ne peut pas se « souvenir » avoir été connecté.\n\n$1",
+ "authform-newtoken": "Jeton manquant. $1",
+ "authform-notoken": "Jeton manquant",
+ "authform-wrongtoken": "Mauvais jeton",
+ "specialpage-securitylevel-not-allowed-title": "Interdit",
+ "specialpage-securitylevel-not-allowed": "Désolé, vous n’êtes pas autorisé à utiliser cette page car votre identité n’a pu être vérifiée.",
+ "authpage-cannot-login": "Impossible de démarrer la connexion.",
+ "authpage-cannot-login-continue": "Impossible de continuer la connexion. Votre session a certainement expiré.",
+ "authpage-cannot-create": "Impossible de commencer la création de compte.",
+ "authpage-cannot-create-continue": "Impossible de poursuivre la création du compte. Votre session a sans doute expiré.",
+ "authpage-cannot-link": "Impossible de commencer la liaison du compte.",
+ "authpage-cannot-link-continue": "Impossible de continuer la liaison du compte. Votre session a sans doute expiré.",
+ "cannotauth-not-allowed-title": "Autorisation refusée",
+ "cannotauth-not-allowed": "Vous n’êtes pas autorisé à utiliser cette page",
+ "changecredentials": "Modifier les informations d’identification",
+ "changecredentials-submit": "Modifier les informations d’identification",
+ "changecredentials-invalidsubpage": "$1 n’est pas un type d’information d’identification valide.",
+ "changecredentials-success": "Vos informations d’identification ont été modifiées.",
+ "removecredentials": "Supprimer les informations d’identification",
+ "removecredentials-submit": "Supprimer les informations d'identification",
+ "removecredentials-invalidsubpage": "$1 n’est pas un type d’information d’identification valide.",
+ "removecredentials-success": "Vos informations d’identification ont été supprimées.",
+ "credentialsform-provider": "Type d’information d’identification :",
+ "credentialsform-account": "Nom de compte :",
+ "cannotlink-no-provider-title": "Il n’y a pas de comptes pouvant être liés",
+ "cannotlink-no-provider": "Il n’y a pas de compte pouvant être lié.",
+ "linkaccounts": "Lier les comptes",
+ "linkaccounts-success-text": "Le compte a été lié.",
+ "linkaccounts-submit": "Lier les comptes",
+ "unlinkaccounts": "Dissocier les comptes",
+ "unlinkaccounts-success": "Le compte a été dissocié."
}
"noname": "Vos éd pas spècifiâ un nom d’utilisator justo.",
"loginsuccesstitle": "Branchiê",
"loginsuccess": "<strong>Ora vos éte branchiê{{GENDER:$1||e}} a {{SITENAME}} coment « $1 ».</strong>",
- "nosuchuser": "Y at gins d’utilisator avouéc lo nom « $1 ».\nLos noms d’utilisator sont sensiblos a la câssa.\nSe vos plét, controlâd l’ortografia ou ben [[Special:UserLogin/signup|féte un comptio novél]].",
+ "nosuchuser": "Y at gins d’utilisator avouéc lo nom « $1 ».\nLos noms d’utilisator sont sensiblos a la câssa.\nSe vos plét, controlâd l’ortografia ou ben [[Special:CreateAccount|féte un comptio novél]].",
"nosuchusershort": "Y at gins d’utilisator avouéc lo nom « $1 ».\nSe vos plét, controlâd l’ortografia.",
"nouserspecified": "Vos dête spècifiar un nom d’utilisator.",
"login-userblocked": "Cél utilisator est blocâ. Branchement pas ôtorisâ.",
"accmailtext": "Un contresegno fêt a l’hasârd por [[User talk:$1|$1]] est étâ mandâ a $2. Pôt étre changiê dessus la pâge de <em>[[Special:ChangePassword|changement de contresegno]]</em> aprés branchement.",
"newarticle": "(Novél)",
"newarticletext": "Vos éd siuvu un lim de vers na pâge qu’ègziste p’oncor.\nPor fâre cela pâge, buchiéd voutron tèxto dedens la bouèta ce-desot (vêde la [$1 pâge d’éde] por més d’enformacions).\nSe vos éte arrevâ{{GENDER:||ye}} ique per fôta, cllicâd dessus lo boton <strong>Devant</strong> de voutron navegator.",
- "anontalkpagetext": "----\n<em>O est la pâge de discussion d’un utilisator anonimo qu’at p’oncor fêt un comptio ou ben que nen emplèye pas.</em>\nPor cen, nos devens empleyér son adrèce IP numerica por o identifiar.\nUn’adrèce IP d’ense pôt étre partagiêe per un mouél d’utilisators.\nSe vos éte {{GENDER:|un utilisator|un’utilisatrice}} anonim{{GENDER:|o|a}} et pués se vos constatâd que de comentèros que vos regârdont pas vos sont étâs adrèciês, se vos plét [[Special:UserLogin/signup|féte un comptio]] ou ben [[Special:UserLogin|branchiéd-vos]] por èvitar tota confusion que vint avouéc d’ôtros utilisators anonimos.",
+ "anontalkpagetext": "----\n<em>O est la pâge de discussion d’un utilisator anonimo qu’at p’oncor fêt un comptio ou ben que nen emplèye pas.</em>\nPor cen, nos devens empleyér son adrèce IP numerica por o identifiar.\nUn’adrèce IP d’ense pôt étre partagiêe per un mouél d’utilisators.\nSe vos éte {{GENDER:|un utilisator|un’utilisatrice}} anonim{{GENDER:|o|a}} et pués se vos constatâd que de comentèros que vos regârdont pas vos sont étâs adrèciês, se vos plét [[Special:CreateAccount|féte un comptio]] ou ben [[Special:UserLogin|branchiéd-vos]] por èvitar tota confusion que vint avouéc d’ôtros utilisators anonimos.",
"noarticletext": "Ora y at gins de tèxto dedens cela pâge.\nVos pouede [[Special:Search/{{PAGENAME}}|fâre na rechèrche sur cél titro]] dedens les ôtres pâges,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rechèrchiér dedens los jornâls liyês]\nou ben [{{fullurl:{{FULLPAGENAME}}|action=edit}} fâre cela pâge]</span>.",
"noarticletext-nopermission": "Ora y at gins de tèxto dedens cela pâge.\nVos pouede [[Special:Search/{{PAGENAME}}|fâre na rechèrche sur cél titro]] dedens les ôtres pâges ou ben <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rechèrchiér dedens los jornâls liyês]</span>, mas vos éd pas la pèrmission de fâre cela pâge.",
"missing-revision": "La vèrsion n° $1 de la pâge apelâye « {{FULLPAGENAME}} » ègziste pas.\n\nEn g·ènèrâl cen arreve en siuvent un lim dèpassâ d’un historico de vers na pâge qu’est étâye suprimâye.\nVos pouede trovar més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
"upload-form-label-own-work": "Su l’ôtor de cel’ôvra",
"upload-form-label-infoform-categories": "Catègories",
"upload-form-label-infoform-date": "Dâta",
- "upload-form-label-own-work-message-local": "Confirmo que tèlèchârjo cél fichiér d’aprés les condicions d’usâjo et les politiques de licence de {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Se vos pouede pas tèlèchargiér cél fichiér d’aprés les politiques de {{SITENAME}}, se vos plét cllôde cela bouèta de dialogo et pués èprovâd un’ôtra mètoda.",
- "upload-form-label-not-own-work-local-local": "Vos pouede asse-ben èprovar la [[Special:Upload|pâge de tèlèchargement per dèfôt]].",
- "upload-form-label-own-work-message-default": "Compregno que tèlèchârjo cél fichiér vers un dèpôt partagiê. Confirmo qu’o fé d’aprés les condicions d’usâjo et les politiques de licence de ceti.",
- "upload-form-label-not-own-work-message-default": "Se vos pouede pas tèlèchargiér cél fichiér d’aprés les politiques du dèpôt partagiê, se vos plét cllôde cela bouèta de dialogo et pués èprovâd un’ôtra mètoda.",
- "upload-form-label-not-own-work-local-default": "Vos pouede asse-ben èprovar d’empleyér la [[Special:Upload|pâge de tèlèchargement de {{SITENAME}}]], se cél fichiér y pôt étre tèlèchargiê d’aprés lors politiques.",
- "upload-form-label-own-work-message-shared": "Cèrtifio étre lo dètentior des drêts d’ôtor sur cél fichiér, et j’accèpto de publeyér cél fichiér dessus Wikimedia Commons en lo betent irrèvocâblament desot licence [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Atribucion - Partâjo dens les Mémes Condicions 4.0] et pués j’accèpto les [https://wikimediafoundation.org/wiki/Terms_of_Use condicions d’usâjo].",
- "upload-form-label-not-own-work-message-shared": "Se vos éte pas lo dètentior des drêts d’ôtor sur cél fichiér ou ben que vos lo voléd publeyér desot na licence difèrenta, vos pouede empleyér l’[https://commons.wikimedia.org/wiki/Special:UploadWizard assistent de tèlèchargement de Commons].",
- "upload-form-label-not-own-work-local-shared": "Vos pouede asse-ben èprovar d’empleyér la [[Special:Upload|pâge de tèlèchargement de {{SITENAME}}]], se cél fichiér y pôt étre tèlèchargiê d’aprés lors politiques.",
+ "upload-form-label-own-work-message-generic-local": "Confirmo que tèlèchârjo cél fichiér d’aprés les condicions d’usâjo et les politiques de licence de {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Se vos pouede pas tèlèchargiér cél fichiér d’aprés les politiques de {{SITENAME}}, se vos plét cllôde cela bouèta de dialogo et pués èprovâd un’ôtra mètoda.",
+ "upload-form-label-not-own-work-local-generic-local": "Vos pouede asse-ben èprovar la [[Special:Upload|pâge de tèlèchargement per dèfôt]].",
+ "upload-form-label-own-work-message-generic-foreign": "Compregno que tèlèchârjo cél fichiér vers un dèpôt partagiê. Confirmo qu’o fé d’aprés les condicions d’usâjo et les politiques de licence de ceti.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Se vos pouede pas tèlèchargiér cél fichiér d’aprés les politiques du dèpôt partagiê, se vos plét cllôde cela bouèta de dialogo et pués èprovâd un’ôtra mètoda.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Vos pouede asse-ben èprovar d’empleyér la [[Special:Upload|pâge de tèlèchargement de {{SITENAME}}]], se cél fichiér y pôt étre tèlèchargiê d’aprés lors politiques.",
"backend-fail-stream": "Y at pas moyen de tramandar lo fichiér « $1 ».",
"backend-fail-backup": "Y at pas moyen d’encartar lo fichiér « $1 ».",
"backend-fail-notexists": "Lo fichiér $1 ègziste pas.",
"noname": "Dü skel en rochten brükernööm uundu.",
"loginsuccesstitle": "Uunmeldin hää loket.",
"loginsuccess": "'''Dü beest nü üs „$1“ bi {{SITENAME}} uunmeldet.'''",
- "nosuchuser": "Di brükernööm „$1“ jaft at ei. Aachte üüb det skriiwwiis (an uk üüb grat- an letjskriiwang), an do [[Special:UserLogin/signup|melde di nei uun]].",
+ "nosuchuser": "Di brükernööm „$1“ jaft at ei. Aachte üüb det skriiwwiis (an uk üüb grat- an letjskriiwang), an do [[Special:CreateAccount|melde di nei uun]].",
"nosuchusershort": "Diar as nään brüker mä di nööm \"$1\".\nHeest dü ham uk rocht skrewen?",
"nouserspecified": "Dü skel en brükernööm uundu.",
"login-userblocked": "Didiar brüker as speret wurden. Hi mut ham ei uunmelde.",
"accmailtext": "En tufelag iinracht paaswurd för [[User talk:$1|$1]] as tu $2 ferschüürd wurden. Det koon üüb det spezial-sidj ''[[Special:ChangePassword|Paaswurd anre]]'' feranert wurd, wan dü uunmeldet beest.",
"newarticle": "(Nei)",
"newarticletext": "Dü beest en ferwisang tu en sidj fulagt, diar't noch ei jaft.\nAm det sidj iinturachten, skriiw dan tekst uun det fial för't bewerkin iin.\nÜüb det [$1 halepsidj] fanjst dü halep.\nWan dü ütj fersen heer beest, trak ianfach üüb di <strong>turag</strong>-knoop faan dan browser.",
- "anontalkpagetext": "----''Üüb detheer sidj könst dü en ünbekäänden brüker en nooracht du. Det lääpt auer sin IP adres. IP adresen kön faan flook brükern brükt wurd. Wan dü mä detheer nooracht niks began könst, do as det ferlicht för hoker ööders mend weesen. Dü säärst niks widjer onernem. Wan dü en aanj [[Special:UserLogin/signup|brükerkonto iinrachst]] of di [[Special:UserLogin|uunmeldest]], komt sowat ei weder föör.",
+ "anontalkpagetext": "----''Üüb detheer sidj könst dü en ünbekäänden brüker en nooracht du. Det lääpt auer sin IP adres. IP adresen kön faan flook brükern brükt wurd. Wan dü mä detheer nooracht niks began könst, do as det ferlicht för hoker ööders mend weesen. Dü säärst niks widjer onernem. Wan dü en aanj [[Special:CreateAccount|brükerkonto iinrachst]] of di [[Special:UserLogin|uunmeldest]], komt sowat ei weder föör.",
"noarticletext": "Üüb detdiar sidj stäänt noch niks.\nDü könst didiar tiitel üüb ööder sidjen [[Special:Search/{{PAGENAME}}|schük]],\n<span class=\"plainlinks\">uun [{{fullurl:{{#special:Log}}|page={{FULLPAGENAMEE}}}} logbuken schük] of detdiar sidj [{{fullurl:{{FULLPAGENAME}}|action=edit}} bewerke]</span>.",
"noarticletext-nopermission": "Üüb detdiar sidj stäänt noch niks, oober dü mutst diar uk niks iinskriiw.\nDü könst diar üüb ööder sidjen efter [[Special:Search/{{PAGENAME}}|schük]] of a <span class=\"plainlinks\">[{{fullurl:{{#special:Log}}|page={{FULLPAGENAME}}}} logbuken uunluke].</span>",
"missing-revision": "Det werjuun #$1 faan det sidj \"{{FULLPAGENAME}}\" jaft at ei.\n\nDet komt diar miast faan, dat en ual ferwisang stregen wurden as.\nDü könst det uun't [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} logbuk faan stregen sidjen] efterlees.",
"noname": "No tu âs inserît un non utent valit.",
"loginsuccesstitle": "Jentrât cun sucès",
"loginsuccess": "Cumò tu sês jentrât te {{SITENAME}} sicu \"$1\".",
- "nosuchuser": "Non è registrato alcun utente di nome \"$1\".\nI nomi utente sono sensibili alle maiuscole.\nVerificare il nome inserito o [[Special:UserLogin/signup|creare una nuova utenza]].",
+ "nosuchuser": "Non è registrato alcun utente di nome \"$1\".\nI nomi utente sono sensibili alle maiuscole.\nVerificare il nome inserito o [[Special:CreateAccount|creare una nuova utenza]].",
"nosuchusershort": "Nol esist nissun utent cul non \"$1\". Controle di no vê sbaliât di scrivi.",
"nouserspecified": "Tu scugnis specificâ un non utent.",
"wrongpassword": "La peraule clâf zontade no je juste. Torne par plasê a provâ.",
"categories": "Categoriis",
"categoriespagetext": "Lis categoriis ca sot a àn dentri pagjinis o elements multimediâi.\nLis [[Special:UnusedCategories|categoriis no dopradis]] no son mostradis culì.\nCjale ancje lis [[Special:WantedCategories|categoriis desideradis]].",
"categoriesfrom": "Mostre lis categoriis scomençant di:",
- "special-categories-sort-count": "met in ordin par numar",
- "special-categories-sort-abc": "met in ordin alfabetichementri",
"deletedcontributions": "Contribûts dal utent eliminâts",
"deletedcontributions-title": "Contribûts dal utent eliminâts",
"sp-deletedcontributions-contribs": "contribûts",
"noname": "Jo moatte in meidognamme opjaan.",
"loginsuccesstitle": "Oanmelden slagge.",
"loginsuccess": "<strong>Jo binne no oanmelden op de {{SITENAME}} as: \"$1.\"</strong>",
- "nosuchuser": "Der is gjin meidogger \"$1\".\nKontrolearje de stavering, of [[Special:UserLogin/signup|meitsje in nije meidogger oan]].",
+ "nosuchuser": "Der is gjin meidogger \"$1\".\nKontrolearje de stavering, of [[Special:CreateAccount|meitsje in nije meidogger oan]].",
"nosuchusershort": "Der is gjin meidogger mei de namme \"$1\". It is goed skreaun?",
"nouserspecified": "Jo moatte in brûkersnamme opjaan.",
"wrongpassword": "Meidochnamme en wachtwurd hearre net by elkoar. Besykje op 'e nij, of fier it wachtwurd twa kear yn en meitsje nije meidoggersynstellings.",
"accmailtext": "It wachtwurd foar \"$1\" is ferstjoerd nei $2.",
"newarticle": "(Nij)",
"newarticletext": "Jo hawwe in keppeling folge nei in side dêr't noch gjin tekst op stiet.\nOm sels tekst te meistjsen kinne jo dy gewoan yntype in dit bewurkingsfjild\n([$1 Mear ynformaasje oer bewurkjen].)\nOars kinne jo tebek mei de tebek-knop fan jo blêder.",
- "anontalkpagetext": "----''Dit is de oerlisside fan in ûnbekende meidogger; in meidogger dy't him/har net oanmeld hat. Om't der gjin namme bekend is, wurdt it ynternet-adres brûkt om oan te jaan wa. Mar faak is it sa dat sa'n adres net altyd troch deselde persoan brûkt wurdt. As jo it idee hawwe dat jo as ûnbekende meidogger opmerkings foar in oar krije, dan kinne jo jo [[Special:UserLogin/signup|registrearje]], of jo [[Special:UserLogin|oanmelde]]. Fan in oanmelde meidogger is it ynternet-adres net sichtber, en as oanmelde meidogger krije jo allinnich opmerkings dy't foar josels bedoeld binne.''",
+ "anontalkpagetext": "----''Dit is de oerlisside fan in ûnbekende meidogger; in meidogger dy't him/har net oanmeld hat. Om't der gjin namme bekend is, wurdt it ynternet-adres brûkt om oan te jaan wa. Mar faak is it sa dat sa'n adres net altyd troch deselde persoan brûkt wurdt. As jo it idee hawwe dat jo as ûnbekende meidogger opmerkings foar in oar krije, dan kinne jo jo [[Special:CreateAccount|registrearje]], of jo [[Special:UserLogin|oanmelde]]. Fan in oanmelde meidogger is it ynternet-adres net sichtber, en as oanmelde meidogger krije jo allinnich opmerkings dy't foar josels bedoeld binne.''",
"noarticletext": "Der stjit noch gjin tekst op dizze side. Jo kinne\n[[Special:Search/{{PAGENAME}}|hjirboppe nei dy tekst sykje]], of [{{fullurl:{{FULLPAGENAME}}|action=edit}} de side skriuwe].",
"userpage-userdoesnotexist": "Jo bewurkje in brûkersside fan in brûker dy't net bestiet (brûker \"<nowiki>$1</nowiki>\").\nKontrolearje oft jo dizze side wol oanmeitsje/bewurkje wolle.",
"clearyourcache": "<strong>Opmerking:</strong> Nei it fêstlizzen kin it nedich wêze de oerslach fan dyn blêder te leegjen foardat de wizigings te sjen binne.\n* <strong>Firefox / Safari:</strong> Hâld <em>Shift</em> yntreaun wylst jo op <em>Dizze side fernije</em> klikke, of typ <em>Ctrl-F5</em> of <em>Ctrl-R</em> (<em>⌘-R</em> op in Mac)\n* <strong>Google Chrome:</strong> Typ <em>CTRL-Shift-R</em> (<em>⌘-Shift-R</em> op in Mac)\n* <strong>Internet Explorer:</strong> Hâld <em>Ctrl</em> yntreaun wylst jo <em>Vernieuwen'' klikke of typ <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Leegje jo cache yn <em>Extra → Voorkeuren</em>",
"noname": "Níor thug tú ainm úsáideora bailí.",
"loginsuccesstitle": "Logáladh isteach thú",
"loginsuccess": "'''Tá tú logáilte isteach anois sa {{SITENAME}} mar \"<nowiki>$1</nowiki>\".'''",
- "nosuchuser": "Níl aon úsáideoir ann leis an ainm \"$1\".\nTá ainmneacha úsáideoir cásíogair.\nCinntigh do litriú, nó [[Special:UserLogin/signup|bain úsáid as an foirm thíos]] chun cuntas úsáideora nua a chruthú.",
+ "nosuchuser": "Níl aon úsáideoir ann leis an ainm \"$1\".\nTá ainmneacha úsáideoir cásíogair.\nCinntigh do litriú, nó [[Special:CreateAccount|bain úsáid as an foirm thíos]] chun cuntas úsáideora nua a chruthú.",
"nosuchusershort": "Níl aon úsáideoir ann leis an ainm \"$1\". Cinntigh do litriú.",
"nouserspecified": "Caithfidh ainm úsáideoir a shonrú.",
"login-userblocked": "Tá an t-úsáideoir seo faoi bhac. Níl cead aige/aici logáil isteach.",
"noname": "Cha do thagh thu ainm-cleachdaiche dligheach.",
"loginsuccesstitle": "Rinn thu logadh a-steach",
"loginsuccess": "<strong>Rinn thu logadh a-steach air {{SITENAME}} mar \"$1\".</strong>",
- "nosuchuser": "Chan eil cleachdaiche ann air a bheil \"$1\".\nTha ainmean chleachdaichean mothaichail do litrichean mòra 's beaga.\nThoir sùil air an litreachadh no [[Special:UserLogin/signup|cruthaich cunntas ùr]].",
+ "nosuchuser": "Chan eil cleachdaiche ann air a bheil \"$1\".\nTha ainmean chleachdaichean mothachail do litrichean mòra 's beaga.\nThoir sùil air an litreachadh no [[Special:CreateAccount|cruthaich cunntas ùr]].",
"nosuchusershort": "Chan eil cleachdaiche ann leis an ainm \"$1\".\nCuir sùil air an litreachadh.",
"nouserspecified": "Tha agad ri ainm-cleachdaiche a chur ann.",
"login-userblocked": "Chaidh an cleachdaiche seo a chasgadh. Chan eil logadh a-steach ceadaichte dhaibh.",
"accmailtext": "Chaidh facal-faire a chruthachadh air thuaiream airson [[User talk:$1|$1]] 's a chur gu $2.\n\nGabhaidh am facal-faire airson a' chunntais ùir seo atharrachadh air an fo <em>[[Special:ChangePassword|atharraich facal-faire]]</em> às dèidh dhan chleachdaiche logadh a-steach.",
"newarticle": "(Ùr)",
"newarticletext": "Lean thu ri ceangal gu duilleag nach eil ann fhathast.\nCuir teacs sa bhogsa gu h-ìosal gus an duilleag seo a chruthachadh (seall air [$1 duilleag na cobharach] airson barrachd fiosrachaidh).\nMura robh dùil agad ris an duilleag seo a ruigsinn, briog air a' phutan <strong>air ais</strong> 'nad bhrabhsair.",
- "anontalkpagetext": "----\n<em>Seo an duilleag deasbaireachd aig cleachdaiche gun urra nach do chruthaich cunntas fhathast no nach eil 'ga chleachdadh.</em>\nFeumaidh sinn an àireamh IP aca a chleachdadh air sgàth sin.\nFaodadh grunn chleachdaichean seòladh IP mar a chleachdadh còmhla.\nMas e cleachdaiche gun urra a tha annad 's ma tha thu dhen bheachd nach eil na beachdan seo a' buntainn riut, nach [[Special:UserLogin/signup|clàraich thu]] no nach dèan thu [[Special:UserLogin|logadh a-steach]] gus bùrach mar seo a sheachnadh san àm ri teachd?",
+ "anontalkpagetext": "----\n<em>Seo an duilleag deasbaireachd aig cleachdaiche gun urra nach do chruthaich cunntas fhathast no nach eil 'ga chleachdadh.</em>\nFeumaidh sinn àireamh an t-seòlaidh IP aca a chleachdadh air sgàth sin.\nFaodadh grunn chleachdaichean seòladh IP mar sin a chleachdadh còmhla.\nMas e cleachdaiche gun urra a tha annad 's ma tha thu dhen bheachd nach eil na beachdan seo a' buntainn riut, nach [[Special:CreateAccount|clàraich thu]] no nach dèan thu [[Special:UserLogin|logadh a-steach]] gus bùrach mar seo a sheachnadh san àm ri teachd?",
"noarticletext": "Chan eil teacsa sam bith anns an duilleag seo an-dràsta.\n'S urrainn dhut [[Special:Search/{{PAGENAME}}|an tiotal seo a lorg]] ann an duilleagan eile,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} na logaichean co-cheangailte a rannsachadh],\nno [{{fullurl:{{FULLPAGENAME}}|action=edit}} an duilleag seo a chruthachadh]</span>.",
"noarticletext-nopermission": "Chan eil teacsa sam bith san duilleag seo an-dràsta.\n'S urrainn dhut [[Special:Search/{{PAGENAME}}|tiotal na duilleige seo a lorg]] ann an duilleagan eile, no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} na logaichean co-cheangailte a rannsachadh]</span> ach chan eil cead agad an duilleag seo a chruthachadh.",
"missing-revision": "Chan eil mùthadh #$1 na duilleige \"{{FULLPAGENAME}}\" ann.\n\nMar is trice, tachraidh seo ma leanas tu ceangal san eachdraidh a tha fìor aosta 's a tha a' dol gu duilleag a chaidh a sguabadh às.\nGheibh thu mion-fhiosrachadh ann an [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} loga nan duilleagan a chaidh a sguabadh às].",
"right-override-export-depth": "Cead gus duilleagan às-phortadh, a' gabhail a-seach duilleagan ceangailte suas ri doimhneachd de 5",
"right-sendemail": "Cead gus puist-d a chur gu cleachdaichean eile",
"right-passwordreset": "Cead gus puist-d ath-shuidheachadh nam facal-faire a shealltainn",
- "right-managechangetags": "Cruthaich is toir air falbh [[Special:Tags|tagaichean]] on stòr-dàta",
+ "right-managechangetags": "Cruthaich is gnìomhaich no neo-ghnìomhaich [[Special:Tags|tagaichean]]",
"newuserlogpage": "Loga cruthachadh nan cleachdaichean",
"newuserlogpagetext": "Seo loga nan cleachdaichean a chaidh a chruthachadh.",
"rightslog": "Loga ceadan a' chleachdaiche",
"action-viewmyprivateinfo": "seall am fiosrachadh prìobhaideach agad",
"action-editmyprivateinfo": "deasaich am fiosrachadh prìobhaideach agad",
"action-editcontentmodel": "deasaich modail susbaint duilleige",
- "action-managechangetags": "cruthaich is thoir air falbh tagaichean on stòr-dàta",
+ "action-managechangetags": "cruthaich is gnìomhaich no neo-ghnìomhaich tagaichean",
"nchanges": "$1 {{PLURAL:$1|mhùthadh|mhùthadh|mùthaidhean|mùthadh}}",
"enhancedrc-since-last-visit": "$1 on tadhal mu dheireadh",
"enhancedrc-history": "eachdraidh",
"rcshowhidemine-hide": "Falaich",
"rclinks": "Seall {{PLURAL:$1|an $1 mhùthadh|an $1 mhùthadh|na $1 mùthaidhean|am $1 mùthadh}} mu dheireadh thairis air {{PLURAL:$2|an $2 latha|an $2 latha|na $2 làithean|am $2 latha}} mu dheireadh<br />$3",
"diff": "diofar",
- "hist": "eachd",
+ "hist": "eachdr",
"hide": "Falaich",
"show": "Seall",
"minoreditletter": "b",
"emailccsubject": "Lethbhreac dhen teachdaireachd agad gu $1: $2",
"emailsent": "Post-d air a chur",
"emailsenttext": "Chaidh an teachdaireachd puist-d agad a chur.",
- "emailuserfooter": "Chaidh am post-d seo a chur o $1 gu $2 leis an fheart \"cuir post-d gu cleachdaiche\" air {{SITENAME}}.",
+ "emailuserfooter": "Chaidh am post-d seo a chur o $1 gu $2 leis an fheart \"{{int:emailuser}}\" air {{SITENAME}}.",
"usermessage-summary": "A' fàgail teachdaireachd an t-siostaim.",
"usermessage-editor": "Teachdaire an t-siostaim",
"usermessage-template": "MediaWiki:UserMessage",
"watchlistanontext": "Log a-steach gus nithean air a' chlàr-fhaire agad a shealltainn no a dheasachadh.",
"watchnologin": "Chan eil thu air logadh a-steach",
"addwatch": "Cuir air a' chlàr-fhaire",
- "addedwatchtext": "Chaidh an duilleag \"[[:$1]]\" a chur ris a' [[Special:Watchlist|chlàr-fhaire]] agad.\nNochdaidh mùthaidhean a nithear air an duilleag seo 's air an duilleag deasbaireachd a tha co-cheangailte ris an-seo san àm ri teachd.",
+ "addedwatchtext": "Chaidh \"[[:$1]]\" agus duilleag na deasbaireachd aige a chur ris a' [[Special:Watchlist|chlàr-fhaire]] agad.",
"addedwatchtext-short": "Chaidh an duilleag \"$1\" a chur ris a' chlàr-fhaire agad.",
"removewatch": "Thoir air falbh on chlàr-fhaire",
- "removedwatchtext": "Chaidh an duilleag \"[[:$1]]\" a thoirt air falbh on [[Special:Watchlist|chlàr-fhaire]] agad.",
+ "removedwatchtext": "Chaidh \"[[:$1]]\" agus duilleag na deasbaireachd aige a thoirt air falbh on [[Special:Watchlist|chlàr-fhaire]] agad.",
"removedwatchtext-short": "Chaidh an duilleag \"$1\" a thoirt ait falbh on chlàr-fhaire agad.",
"watch": "Cum sùil air",
"watchthispage": "Cum sùil air an duilleag seo",
"deletepage": "Sguab às duilleag",
"confirm": "Daingnich",
"excontent": "stuth a bh' ann: '$1'",
- "excontentauthor": "b' e: \"$1\" an t-susbaint (is \"[[Special:Contributions/$2|$2]]\" an aon deasaiche)",
+ "excontentauthor": "b' e: \"$1\" an t-susbaint agus \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|talk]]) an aon deasaiche",
"exbeforeblank": "an t-susbaint mus deach a bànachadh: \"$1\"",
"delete-confirm": "Sguab às \"$1\"",
"delete-legend": "Sguab às",
"delete-toobig": "Tha eachdraidh deasachaidh mòr aig an duilleag seo sa bheil barrachd air $1 {{PLURAL:$1|mhùthadh|mhùthadh|mùthaidhean|mùthadh}}.\nChaidh sguabadh às nan duilleagan dhen leithid a chuingeachadh ach na dèid cron a dhèanamh air {{SITENAME}} le mearachd.",
"delete-warning-toobig": "Tha eachdraidh deasachaidh mòr aig an duilleag seo sa bheil barrachd air $1 {{PLURAL:$1|mhùthadh|mhùthadh|mùthaidhean|mùthadh}}.\nMa sguabas tu às dhi, dh'fhaoidte gun dèan thu cron air na gnìomhan stòr-dàta aig {{SITENAME}}; mar sin, thoir an aire.",
"deleteprotected": "Chan urrainn dhut an duilleag seo a sguabadh às on a chaidh a dìon.",
- "deleting-backlinks-warning": "'''Rabhadh:''' Tha [[Special:WhatLinksHere/{{FULLPAGENAME}}|duilleag eile]] a' ceangal ris an duilleag a tha thu airson sguabadh às no 'ga gabhail a-steach 'na h-iomradh.",
+ "deleting-backlinks-warning": "<strong>Rabhadh:</strong> Tha [[Special:WhatLinksHere/{{FULLPAGENAME}}|duilleag eile]] a' ceangal ris an duilleag a tha thu airson sguabadh às no 'ga gabhail a-steach 'na h-iomradh.",
"rollback": "Roilig atharraichean air ais",
"rollbacklink": "roilig air ais",
"rollbacklinkcount": "roilig $1 {{PLURAL:$1|deasachadh|dheasachadh|deasachaidhean|deasachadh}} air ais",
"protect-locked-blocked": "Chan urrainn dhut ìre an dìon atharrachadh rè bacaidh.\nSeo na roghainnean aig an duilleag <strong>$1</strong>:",
"protect-locked-dblock": "Chan urrainn dhut ìre an dìon atharrachadh on a tha an stòr-dàta glaiste an-dràsta.\nSeo na roghainnean aig an duilleag <strong>$1</strong>:",
"protect-locked-access": "Chan eil cead aig a' chunntas agad an ìre dìon de dhuilleag atharrachadh.\nSeo roghainnean làithreach na duilleige <strong>$1</strong>:",
- "protect-cascadeon": "Tha an duilleag seo fo dhìon an-dràsta a chionn 's gu bheil e air a ghabhail a-steach {{PLURAL:$1|$1 duilleag|$1 dhuilleag|$1 duilleagan|$1 duilleag}} a leanas aig a bheil dìon o bhith mar eas air.\n'S urrainn dhut ìre dìon na duilleige seo atharrachadh ach cha bhi buaidh air an dìon o bhith mar eas.",
+ "protect-cascadeon": "Tha an duilleag seo fo dhìon an-dràsta a chionn 's gu bheil i air a tar-ghabhail {{PLURAL:$1|san duilleag|sna duilleagan}} a leanas aig a bheil dìon o bhith mar eas air.\n'S urrainn dhut ìre dìon na duilleige seo atharrachadh ach cha bhi buaidh air an dìon o bhith mar eas.",
"protect-default": "Ceadaich a h-uile cleachdaiche",
"protect-fallback": "Na ceadaich ach do chleachdaichean aig a bheil cead \"$1\"",
"protect-level-autoconfirmed": "Na ceadaich ach cleachdaichean a chaidh an dearbhadh gu fèin-obrachail",
"undeletepagetext": "Chaidh {{PLURAL:$1|an $1 duilleag|an $1 dhuilleag|na $1 duilleagan|am $1 duilleag}} a sguabadh às ach tha {{PLURAL:$1|i|iad}} san tasglann fhathast 's gabhaidh {{PLURAL:$1|a h-aiseag|an aiseag}}.\nDh'fhaoidte gun dèid an tasglann a ghlanadh gu cunbhalach.",
"undelete-fieldset-title": "Aisig mùthaidhean",
"undeleteextrahelp": "Gus eachdraidh shlàn na duilleige aiseag, fàg gach bogsa bàn 's briog air <strong><em>{{int:undeletebtn}}</em></strong>.\nGus cuid dheth aiseag, cuir cromag sna bogsaichean airson nam mùthaidhean a tha thu airson aiseag 's briog air <strong><em>{{int:undeletebtn}}</em></strong>.",
- "undeleterevisions": "Chaidh {{PLURAL:$1|$1 mhùthadh|$1 mhùthadh|$1 mùthaidhean|$1 mùthadh}} a chur san tasg-lann",
+ "undeleterevisions": "Chaidh {{PLURAL:$1|$1 mhùthadh|$1 mhùthadh|$1 mùthaidhean|$1 mùthadh}} a sguabadh às",
"undeletehistory": "Ma dh'aisigeas tu an duilleag, thèid gach mùthadh aiseag dhan eachdraidh.\nMa chaidh duilleag air a bheil an aon ainm a chruthachadh às dèidh an sguabaidh às, nochdaidh na mùthaidhean air an aiseag san eachdraidh roimhpe.",
"undeleterevdel": "Cha dèid an sguabadh às a neo-dhèanamh ma sguabadh seo às pàirt de mhùthadh na duilleige no an fhaidhle as ùire.\nMas e seo na thachradh, feumaidh tu a' chromag a thoirt far a' mhùthaidh as ùire a chaidh a sguabadh às no gun a bhith 'ga fhalach tuilleadh.",
"undeletehistorynoadmin": "Chaidh an duilleag seo a sguabadh às.\nChì thu adhbhar an sguabaidh às sa ghearr-chunntas gu h-ìosal cho math ri fiosrachadh mu na chleachdaichean a dheasaich an duilleag seo mus deach a sguabadh às.\nChan fhaic ach rianairean an teacsa fhèin aig na mùthaidhean air an sguabadh às.",
"whatlinkshere-next": "{{PLURAL:$1|an ath $1|an ath $1|na ath $1|an ath $1}}",
"whatlinkshere-links": "← ceanglaichean",
"whatlinkshere-hideredirs": "$1 ath-sheòlaidhean",
- "whatlinkshere-hidetrans": "$1 transclusions",
+ "whatlinkshere-hidetrans": "$1 tar-ghabhalaichean",
"whatlinkshere-hidelinks": "$1 ceanglaichean",
- "whatlinkshere-hideimages": "$1 ceanglaichean nam faidhlichean",
+ "whatlinkshere-hideimages": "$1 ceanglaichean fhaidhlichean",
"whatlinkshere-filters": "Criathairean",
"autoblockid": "Fèin-bhacadh $1",
"block": "Bac an cleachdaiche",
"unblock": "Neo-bhac an cleachdaiche",
"blockip": "Bac an cleachdaiche",
"blockip-legend": "Bac an cleachdaiche",
- "blockiptext": "Cleachd am foirm gu h-ìosal gus seòladh IP no cleachdaiche sònraichte a bhacadh o sgrìobhadh.\nNa dèan seo ach gus dìon o bhandalachd agus a-rèir [[{{MediaWiki:Policy-url}}|a' phoileasaidh]].\nLìon an t-adhbhar sònraichte gu h-ìosal (mar eisimpleir le iomradh air na duilleagan le bhandalachd orra).",
+ "blockiptext": "Cleachd am foirm gu h-ìosal gus seòladh IP no cleachdaiche sònraichte a bhacadh o sgrìobhadh.\nNa dèan seo ach gus dìon o bhandalachd agus a-rèir [[{{MediaWiki:Policy-url}}|a' phoileasaidh]].\nLìon an t-adhbhar sònraichte gu h-ìosal (mar eisimpleir le iomradh air na duilleagan le bhandalachd orra).\n'S urrainn dhut rainsean dhe sheòlaidhean IP a bhacadh le co-chàradh [https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing CIDR]; is /$1 an rainse as motha a tha ceadaichte airson IPv4 agus /$2 airson IPv6.",
"ipaddressorusername": "Seòladh IP no ainm-cleachdaiche:",
"ipbexpiry": "Falbhaidh an ùine air:",
"ipbreason": "Adhbhar:",
"lockedbyandtime": "(le $1 $2 $3)",
"move-page": "Gluais $1",
"move-page-legend": "Gluais duilleag",
- "movepagetext": "Ma chleachdas tu am foirm gu h-ìosal, cuiridh tu ainm ùr air 's gluaisidh tu a h-eachdraidh gu lèir dhan ainm ùr.\nBidh an seann tiotal 'na ath-sheòladh dhan tiotal ùr an uairsin.\n'S urrainn dhut ath-sheòladh sam bith a tha a' dol dhan tiotal tùsail ùrachadh leis fhèin.\nMura dèan thu sin, dèan cinnteach gun cuir thu sùil air eagal 's gum bi [[Special:DoubleRedirects|ath-sheòlaidhean dùbailte]] no [[Special:BrokenRedirects|briste]] ann.\n'S ann ort-sa a tha an t-uallach airson dèanamh cinntach gu bheil na ceanglaichean a' dol dha na h-àitichean ceart.\n\nThoir an aire <strong>nach dèid</strong> an duilleag a ghluasad ma tha duilleag air an tiotal ùr mu thràth ach ma bhios e falamh no 'na ath-sheòladh 's mur eil eachdraidh deasachaidh ann.\n'S ciall dha seo gun urrainn dhut ainm duilleige a thilleadh dhan ainm a bha air roimhe ma rinn thu mearachd agus nach urrainn dhut sgrìobhadh thairis air duilleag a tha ann.\n\n<strong>Rabhadh!</strong>\nFaodaidh seo a bhith 'na atharrachadh mòr ris nach bi dùil air duilleag air a bheil fèill mhòr;\ndèan cinnteach gu bheil thu a' tuigsinn dè a' bhuaidh a bhios agad mus dèid thu air adhart.",
- "movepagetext-noredirectfixer": "Ma chleachdas tu am foirm gu h-ìosal, cuiridh tu ainm ùr air 's gluaisidh tu a h-eachdraidh gu lèir dhan ainm ùr.\nBidh an seann tiotal 'na ath-stiùireadh dhan tiotal ùr an uairsin.\nDearbhaich nach bi ath-sheòlaidhean [[Special:DoubleRedirects|dùbailte]] no [[Special:BrokenRedirects|briste]] ann.\n'S ann ort-sa a tha an t-uallach airson dèanamh cinnteach gu bheil na ceanglaichean a' dol dha na h-àitichean a bu chòir.\n\nThoir an aire <strong>nach dèid</strong> an duilleag a ghluasad ma tha duilleag air an tiotal ùr mu thràth ach ma bhios e falamh no 'na ath-sheòladh 's mur eil eachdraidh deasachaidh ann.\n'S ciall dha seo gur urrainn dhut ainm duilleige a thilleadh dhan ainm a bha air roimhe ma rinn thu mearachd agus nach urrainn dhut sgrìobhadh thairis air duilleag a tha ann.\n\n<strong>Rabhadh!</strong>\nFaodaidh seo a bhith 'na atharrachadh mòr ris nach bi dùil air duilleag air a bheil fèill mhòr;\ndèan cinnteach gu bheil thu a' tuigsinn dè a' bhuaidh a bhios agad mus dèid thu air adhart.",
- "movepagetalktext": "Thèid an duilleag deasbaireachd a tha co-cheangailte ris a ghluasad 'na cois <strong>ach:</strong>\n*Ma tha duilleag deasbaireachd nach eil falamh aig an ainm ùr mu thràth, no\n*Ma bheir thu air falbh a' chromag on bhogsa gu h-ìosal\n\nMa thachras seo, feumaidh to an duilleag a ghluasad no cho-aonachadh a làimh, ma tha sin fa-near dhut.",
+ "movepagetext": "Ma chleachdas tu am foirm gu h-ìosal, cuiridh tu ainm ùr air 's gluaisidh tu a h-eachdraidh gu lèir dhan ainm ùr.\nBidh an seann tiotal 'na ath-sheòladh dhan tiotal ùr an uairsin.\n'S urrainn dhut ath-sheòladh sam bith a tha a' dol dhan tiotal tùsail ùrachadh leis fhèin.\nMura dèan thu sin, dèan cinnteach gun cuir thu sùil air eagal 's gum bi [[Special:DoubleRedirects|ath-sheòlaidhean dùbailte]] no [[Special:BrokenRedirects|briste]] ann.\n'S ann ort-sa a tha an t-uallach airson dèanamh cinntach gu bheil na ceanglaichean a' dol dha na h-àitichean ceart.\n\nThoir an aire <strong>nach dèid</strong> an duilleag a ghluasad ma tha duilleag air an tiotal ùr mu thràth ach ma bhios e falamh no 'na ath-sheòladh 's mur eil eachdraidh deasachaidh ann.\n'S ciall dha seo gun urrainn dhut ainm duilleige a thilleadh dhan ainm a bha air roimhe ma rinn thu mearachd agus nach urrainn dhut sgrìobhadh thairis air duilleag a tha ann.\n\n<strong>An aire:</strong>\nFaodaidh seo a bhith 'na atharrachadh mòr ris nach bi dùil air duilleag air a bheil fèill mhòr;\ndèan cinnteach gu bheil thu a' tuigsinn dè a' bhuaidh a bhios agad mus dèid thu air adhart.",
+ "movepagetext-noredirectfixer": "Ma chleachdas tu am foirm gu h-ìosal, cuiridh tu ainm ùr air 's gluaisidh tu a h-eachdraidh gu lèir dhan ainm ùr.\nBidh an seann tiotal 'na ath-stiùireadh dhan tiotal ùr an uairsin.\nDearbhaich nach bi ath-sheòlaidhean [[Special:DoubleRedirects|dùbailte]] no [[Special:BrokenRedirects|briste]] ann.\n'S ann ort-sa a tha an t-uallach airson dèanamh cinnteach gu bheil na ceanglaichean a' dol dha na h-àitichean a bu chòir.\n\nThoir an aire <strong>nach dèid</strong> an duilleag a ghluasad ma tha duilleag air an tiotal ùr mu thràth ach ma bhios e falamh no 'na ath-sheòladh 's mur eil eachdraidh deasachaidh ann.\n'S ciall dha seo gur urrainn dhut ainm duilleige a thilleadh dhan ainm a bha air roimhe ma rinn thu mearachd agus nach urrainn dhut sgrìobhadh thairis air duilleag a tha ann.\n\n<strong>An aire:</strong>\nFaodaidh seo a bhith 'na atharrachadh mòr ris nach bi dùil air duilleag air a bheil fèill mhòr;\ndèan cinnteach gu bheil thu a' tuigsinn dè a' bhuaidh a bhios agad mus dèid thu air adhart.",
+ "movepagetalktext": "Ma chuireas tu cromag sa bhogsa seo, thèid duilleag na deasbaireachd a tha co-cheangailte ris a ghluasad dhan tiotal ùr gu fèin-obrachail ach ma tha duilleag na deasbaireachd nach eil falamh ann a shiud mar-thà.\n\nMa thachras seo, feumaidh tu an duilleag a ghluasad no cho-aonachadh a làimh ma tha sin fa-near dhut.",
"moveuserpage-warning": "<strong>Rabhadh:</strong> Tha thu airson duilleag cleachdaiche a ghluasad. Thoir an aire nach dèid ach an duilleag a ghluasad 's <em>gur ann nach dèid</em> ainm ùr a thoirt air a' chleachdaiche.",
"movecategorypage-warning": "<strong>Rabhadh:</strong> Tha thu airson duilleag roinn-seòrsa a ghluasad. Thoir an aire nach dèid ach an duilleag a ghluasad 's <em>gur ann nach dèid</em> gach duilleag a tha san t-seann roinn-seòrsa a chur ris an roinn-seòrsa ùr.",
"movenologintext": "Feumaidh tu a bhith 'nad bhall clàraichte 's air [[Special:UserLogin|logadh a-steach]] mus gluais thu duilleag.",
"cant-move-to-user-page": "Chan eil cead agad duilleag a ghluasad gu duilleag cleachdaiche (ach gu fo-dhuilleag cleachdaiche).",
"cant-move-category-page": "Chan eil cead agad duilleagan roinn-seòrsa a ghluasad.",
"cant-move-to-category-page": "Chan eil cead agad duilleag a ghluasad gu duilleag roinn-seòrsa.",
- "newtitle": "Dhan tiotal ùr:",
+ "newtitle": "An tiotal ùr:",
"move-watch": "Cum sùil air an duilleag thùsail agus an duilleag thairgaideach",
"movepagebtn": "Gluais duilleag",
"pagemovedsub": "Shoirbhich leat leis a' ghluasad",
"movenosubpage": "Chan eil fo-dhuilleag aig an duilleag seo.",
"movereason": "Adhbhar:",
"revertmove": "till",
- "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_text": "Tha 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",
"selfmove": "Tha tiotalan an tùis a' chinn-uidhe co-ionnann;\nchan urrainn dhut duilleag a ghluasad dhan ionad aice fhèin.",
"move-leave-redirect": "Fàg ath-stiùireadh ann",
"protectedpagemovewarning": "<strong>Rabhadh: Chaidh an duilleag seo a dhìon 's chan urrainn ach dhan fheadhainn aig a bheil ùghdarras rianaire a ghluasad.</strong>\nChì thu an clàr mu dheireadh san loga mar fhiosrachadh dhut gu h-ìosal:",
"semiprotectedpagemovewarning": "<strong>An aire:</strong> Chaidh an duilleag seo a dhìon 's chan fhaod ach cleachdaichean clàraichte a ghluasad.\nSeo an rud mu dheireadh san loga mar fhiosrachadh dhut:",
- "move-over-sharedrepo": "== Tha am faidhle ann ==\nTha [[:$1]] ann an ionad-tasgaidh co-roinnte. Thèid tar-àithneadh air an fhaidhle cho-roinnte ma ghluaiseas tu faidhle gun tiotal seo.",
+ "move-over-sharedrepo": "Tha [[:$1]] ann an ionad-tasgaidh co-roinnte. Thèid tar-àithneadh air an fhaidhle cho-roinnte ma ghluaiseas tu faidhle gun tiotal seo.",
"file-exists-sharedrepo": "Tha ainm an fhaidhle a thagh thu 'ga chleachdadh ann an ionad-tasgaidh co-roinnte mar-thà.\nFeuch an tagh thu ainm eile.",
"export": "Às-phortaich duilleagan",
"exporttext": "'S urrainn dhut teacsa is eachdraidh an deasachaidh aig duilleag no duilleagan sònraichte às-phortachadh le XML timcheall air.\nGabhaidh seo ion-phortachadh gu uicidh eile a chleachdas MediaWiki air an [[Special:Import|duilleag ion-phortachaidh]].\n\nGus duilleagan às-phortachadh, cuir a-steach na tiotalan sa bhogsa-teacsa gu h-ìosal, gach tiotal air loidhne fa leth, agus tagh a bheil thu ag iarraidh am mùthadh làithreach cho math ri seann mhùthaidhean le loidhnichean eachdraidh nan duilleagan no a bheil thu ag iarraidh am mùthadh làithreach le fiosrachadh mun deasachadh mu dheireadh.\n\nMa chuir thu an roghainn eile romhad, 's urrainn dhut ceangal a chleachdadh cuideachd, mar eisimpleir [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] airson na duilleige \"[[{{MediaWiki:Mainpage}}]]\".",
"thumbnail_image-missing": "Tha faidhle a dhìth a-rèit coltais: $1",
"thumbnail_image-failure-limit": "Chaidh feuchainn cus tursan ($1 no a bharrachd) o chionn goirid gus an dealbhag seo a reandaradh. Feuch ris a-rithist uaireigin eile.",
"import": "Ion-phortaich duilleagan",
- "importinterwiki": "Ion-phortachadh tar-uicidh",
- "import-interwiki-text": "Tagh uicidh 's tiotal na duilleige airson ion-phortachadh.\nThèid cinn-là nam mùthaidhean 's ainmean nan deasaichean a ghlèidheadh.\nThèid gach gnìomh ion-phortachadh tar-uicidh a chur ris an [[Special:Log/import|loga ion-phortachaidh]].",
+ "importinterwiki": "Ion-phortachadh o uicidh eile",
+ "import-interwiki-text": "Tagh uicidh 's tiotal na duilleige airson ion-phortachadh.\nThèid cinn-là nam mùthaidhean 's ainmean nan deasaichean a ghlèidheadh.\nThèid gach ion-phortachadh o uicidh eile a chur ris an [[Special:Log/import|loga ion-phortachaidh]].",
"import-interwiki-sourcewiki": "An uicidh thùsail:",
"import-interwiki-sourcepage": "An duilleag thùsail:",
"import-interwiki-history": "Dèan lethbhreac de dh'eachdraidh nam mùthaidhean slàna airson na duilleige seo",
"importcantopen": "Cha deach leinn am faidhle ion-phortachaidh fhosgladh.",
"importbadinterwiki": "Droch cheangal eadar-uicodh",
"importsuccess": "Tha an t-ion-phortachadh coileanta!",
- "importnosources": "Cha deach tùs ion-phortachadh tar-uicidh a mhìneachadh agus tha luchdadh suas dìreach nan eachdraidhean à comas.",
+ "importnosources": "Cha deach uicidh gus ion-phortadh uaipe a shònrachadh agus tha luchdadh suas dìreach nan eachdraidhean à comas.",
"importnofile": "Cha deach faidhle ion-phortachaidh a luchdadh suas.",
"importuploaderrorsize": "Dh'fhàillig le luchdadh suas an fhaidhle ion-phortachaidh.\nTha am faidhle nas motha na tha ceadaichte.",
"importuploaderrorpartial": "Dh'fhàillig le luchdadh suas an fhaidhle ion-phortachaidh.\nCha deach ach pàirt dhen fhaidhle a luchdadh suas.",
"import-nonewrevisions": "Cha deach mùthadh ion-phortachadh (bha iad uile ann roimhe no chaidh an leigeil seachad ri linn mhearachdan).",
"xml-error-string": "$1 air loidhne $2, colbh $3 (baidht $4): $5",
"import-upload": "Luchdaich suas dàta XML",
- "import-token-mismatch": "Chaidh dàta an t-seisein air chall.\nFeuch ris a-rithist.",
+ "import-token-mismatch": "Dh'fhaoidte gun deach do logadh a-mach. <strong>Dearbhaich gu bheil thu air do chlàradh a-steach fhathast agus feuch ris a-rithist</strong>.\nMur obraich e fhathast, feuch [[Special:UserLogout|clàradh a-mach]] is a-steach a-rithist agus dearbhaich gun ceadaich am brabhsair agad briosgaidean on bhrabhsair seo.",
"import-invalid-interwiki": "Cha ghabh ion-phortachadh in uicidh a shònraich thu.",
"import-error-edit": "Cha deach an duilleag \"$1\" ion-phortachadh o nach fhaod thu a deasachadh.",
"import-error-create": "Cha deach an duilleag \"$1\" ion-phortachadh o nach fhaod thu a cruthachadh.",
"tooltip-feed-rss": "Inbhir RSS airson na duilleige seo",
"tooltip-feed-atom": "Inbhir Atom airson na duilleige seo",
"tooltip-t-contributions": "Seall liosta na h-obrach a rinn {{GENDER:$1|an cleachdaiche}} seo",
- "tooltip-t-emailuser": "Cuir post-dealain dhan chleachdaiche seo",
+ "tooltip-t-emailuser": "Cuir post-dealain dhan {{GENDER:$1|chleachdaiche seo}}",
"tooltip-t-upload": "Luchdaich suas faidhle",
"tooltip-t-specialpages": "Liosta de gach duilleag shònraichte",
"tooltip-t-print": "Tionndadh dhen duilleag a ghabhas a chlò-bhualadh",
"watchlistedit-raw-done": "Chaidh an clàr-faire agad ùrachadh.",
"watchlistedit-raw-added": "Chaidh $1 {{PLURAL:$1|tiotal|thiotal|tiotalan|tiotal}} a chur ris:",
"watchlistedit-raw-removed": "Chaidh $1 {{PLURAL:$1|tiotal|thiotal|tiotalan|tiotal}} a thoirt air falbh:",
- "watchlistedit-clear-title": "Clàr-faire air a ghlanadh",
+ "watchlistedit-clear-title": "Glan an clàr-faire",
"watchlistedit-clear-legend": "Glan an clàr-faire",
"watchlistedit-clear-explain": "Thèid a h-uile tiotal a thoirt far a' chlàr-fhaire agad",
"watchlistedit-clear-titles": "Tiotalan:",
"version-entrypoints-header-url": "URL",
"version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath Slighe artaigil]",
"version-entrypoints-scriptpath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgScriptPath slighe sgriobt]",
- "redirect": "Ath-stiùireadh le faidhle, cleachdaiche, duilleag no ID a' mhùthaidh",
- "redirect-summary": "Nì an duilleag shònraichte seo ath-stiùireadh gu faidhle (le ainm faidhle), duilleag (le ID a' mhùthaidh no ID na duilleige) no duilleag cleachdaiche (le àireamh ID a' chleachdaiche). Seo mar a chleachdas tu e: [[{{#Special:Redirect}}/file/Ball-eisimpleir.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]] no [[{{#Special:Redirect}}/user/101]].",
+ "redirect": "Ath-stiùireadh le faidhle, cleachdaiche, duilleag, mhùthadh no ID loga",
+ "redirect-summary": "Nì an duilleag shònraichte seo ath-stiùireadh gu faidhle (le ainm faidhle), duilleag (le ID a' mhùthaidh no ID na duilleige) no duilleag cleachdaiche (le àireamh ID a' chleachdaiche) no innteart an loga (le ID an loga). Seo mar a chleachdas tu e: [[{{#Special:Redirect}}/file/Ball-eisimpleir.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] no [[{{#Special:Redirect}}/logid/186]].",
"redirect-submit": "Siuthad",
"redirect-lookup": "Rannsaich:",
"redirect-value": "Luach:",
"compare-revision-not-exists": "Chan eil am mùthadh a shònraich thu ann.",
"dberr-problems": "Duilich! Tha trioblaid teicnigeach aig an làrach seo.",
"dberr-again": "Feitheamh mionaid no dhà 's ath-luchdaich i.",
- "dberr-info": "(Chan obraich an conaltradh ri frithealaiche an stòir-dhàta: $1)",
- "dberr-info-hidden": "(Chan obraich an conaltradh ri frithealaiche an stòir-dhàta)",
+ "dberr-info": "(Chan urrainn dhuinn an stòr-dàta inntrigeadh: $1)",
+ "dberr-info-hidden": "(Chan urrainn duinn an stòr-dàta inntrigeadh)",
"dberr-usegoogle": "Feuch lorg le Google san eadar-àm.",
"dberr-outofdate": "Thoir an aire nach eil an clàr acasan air an t-susbaint againn cho ùr sa ghabhas ma dh'fhaoidte.",
"dberr-cachederror": "Seo lethbhreac dhen duilleag a dh'iarr thu on tasgadan 's chan eil e cho ùr 's a ghabhas, ma dh'fhaoidte.",
"api-error-badaccess-groups": "Chan eil cead agad gus faidhlichean a luchdadh suas dhan uicidh seo.",
"api-error-badtoken": "Mearachd taobh a-staigh: Droch thòcan.",
"api-error-copyuploaddisabled": "Tha luchdadh suas le URL à comas air an fhrithealaiche seo.",
- "api-error-duplicate": "Tha {{PLURAL:$1|faidhle eile|are faidhlichean eile}} air an làrach seo mar-thà sa bheil an aon susbaint.",
+ "api-error-duplicate": "Tha {{PLURAL:$1|faidhle eile|faidhlichean eile}} air an làrach seo mar-thà sa bheil an aon susbaint.",
"api-error-duplicate-archive": "Tha {{PLURAL:$1|faidhle eile|faidhlichean eile}} air an làrach seo mar-thà sa bheil an aon susbaint ach chaidh {{PLURAL:$1|a sguabadh|an sguabadh}} às.",
"api-error-empty-file": "Tha am faidhle a chuir thu a-null falamh.",
"api-error-emptypage": "Chan fhaodar duilleagan falamh ùra a chruthachadh.",
"expand_templates_generate_xml": "Seall craobh parsaidh an XML",
"expand_templates_generate_rawhtml": "Seall bun-tùs an HTML",
"expand_templates_preview": "Ro-sheall",
- "pagelanguage": "Roghnaichear cànan nan duilleag",
+ "pagelanguage": "Atharraich cànan na duilleige",
"pagelang-name": "Duilleag",
"pagelang-language": "Cànan",
"pagelang-use-default": "Cleachd an cànan tùsail",
"action-pagelang": "atharraich cànan nan duilleagan",
"log-name-pagelang": "Loga air atharrachadh nan cànan",
"log-description-pagelang": "Seo loga dhe na h-atharraichean air cànanan nan duilleagan.",
- "logentry-pagelang-pagelang": "Dh'atharraich $1 cànan nan duilleagan airson $3 o $4 gu $5.",
+ "logentry-pagelang-pagelang": "{{GENDER:$2|Dh'atharraich}} $1 an cànan aig $3 o $4 gu $5",
"default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (an comas)",
"default-skin-not-found-row-disabled": "* <code>$1</code> / $2 (<strong>à comas</strong>)",
"mediastatistics": "Stadastaireachd nam meadhanan",
"tog-watchdefault": "Engadir as páxinas e os ficheiros que edite á miña lista de vixilancia",
"tog-watchmoves": "Engadir as páxinas e os ficheiros que mova á miña lista de vixilancia",
"tog-watchdeletion": "Engadir as páxinas e os ficheiros que borre á miña lista de vixilancia",
- "tog-watchuploads": "Engadir os novos ficheiros que subín á miña lista de vixilancia",
+ "tog-watchuploads": "Engadir os ficheiros novos que suba á miña lista de vixilancia",
"tog-watchrollback": "Engadir as páxinas nas que realice unha reversión á miña lista de vixilancia",
"tog-minordefault": "Marcar todas as edicións como pequenas por defecto",
"tog-previewontop": "Mostrar a vista previa antes da caixa de edición",
"tog-watchlisthidebots": "Agochar as edicións dos bots na lista de vixilancia",
"tog-watchlisthideminor": "Agochar as edicións pequenas na lista de vixilancia",
"tog-watchlisthideliu": "Agochar as edicións dos usuarios rexistrados na lista de vixilancia",
- "tog-watchlistreloadautomatically": "Recargar a lista de vixilancia automaticamente cando se produce un cambio nun filtro (require JavaScript)",
+ "tog-watchlistreloadautomatically": "Recargar a lista de vixilancia automaticamente cando se produza un cambio nun filtro (necesítase JavaScript)",
"tog-watchlisthideanons": "Agochar as edicións dos usuarios anónimos na lista de vixilancia",
"tog-watchlisthidepatrolled": "Agochar as edicións patrulladas na lista de vixilancia",
"tog-watchlisthidecategorization": "Agochar a categorización das páxinas",
"password-change-forbidden": "Non pode mudar os contrasinais neste wiki.",
"externaldberror": "Ou ben se produciu un erro da base de datos na autenticación externa ou ben non se lle permite actualizar a súa conta externa.",
"login": "Acceder ao sistema",
+ "login-security": "Verifique a súa identidade",
"nav-login-createaccount": "Rexistro",
"userlogin": "Rexistro",
"userloginnocreate": "Rexistro",
"userlogin-resetpassword-link": "Esqueceu o contrasinal?",
"userlogin-helplink2": "Axuda co rexistro",
"userlogin-loggedin": "Xa accedeu ao sistema como {{GENDER:$1|$1}}.\nUtilice o formulario inferior para acceder como outro usuario.",
+ "userlogin-reauth": "Debe conectarse de novo para verificar que é {{GENDER:$1|$1}}.",
"userlogin-createanother": "Crear outra conta",
"createacct-emailrequired": "Enderezo de correo electrónico",
"createacct-emailoptional": "Enderezo de correo electrónico (opcional)",
"createacct-email-ph": "Insira o seu enderezo de correo electrónico",
"createacct-another-email-ph": "Insira o enderezo de correo electrónico",
"createaccountmail": "Utilizar un contrasinal aleatorio temporal e envialo ao enderezo de correo electrónico especificado",
+ "createaccountmail-help": "Pode usarse para crear unha conta para outra persoa sen coñecer o contrasinal.",
"createacct-realname": "Nome real (opcional)",
"createaccountreason": "Motivo:",
"createacct-reason": "Motivo",
"createacct-reason-ph": "Por que crea outra conta?",
+ "createacct-reason-help": "Mensaxe que se mostra no rexistro de creación de contas",
"createacct-submit": "Crear a conta",
"createacct-another-submit": "Crear conta",
+ "createacct-continue-submit": "Continuar a creación da conta",
+ "createacct-another-continue-submit": "Continuar a creación da conta",
"createacct-benefit-heading": "Xente coma vostede elabora {{SITENAME}}.",
"createacct-benefit-body1": "{{PLURAL:$1|edición|edicións}}",
"createacct-benefit-body2": "{{PLURAL:$1|páxina|páxinas}}",
"nocookiesnew": "A conta de usuario foi creada, pero non accedeu ao sistema.\n{{SITENAME}} para rexistrar os usuarios.\nVostede ten as cookies deshabilitadas.\nPor favor, habilíteas e logo acceda ao sistema co seu novo nome de usuario e contrasinal.",
"nocookieslogin": "{{SITENAME}} usa cookies para rexistrar os usuarios.\nVostede ten as cookies deshabilitadas.\nPor favor, habilíteas e inténteo de novo.",
"nocookiesfornew": "Non se creou a conta de usuario porque non puidemos confirmar a súa orixe.\nAsegúrese de que ten as cookies habilitadas, volva cargar a páxina e inténteo de novo.",
+ "createacct-loginerror": "A conta creouse correctamente, pero non se puido conectar automaticamente. Proceda ó [[Special:UserLogin|acceso manual]].",
"noname": "Non especificou un nome de usuario válido.",
"loginsuccesstitle": "Conectado",
"loginsuccess": "<strong>Accedeu ao sistema de {{SITENAME}} como \"$1\".</strong>",
- "nosuchuser": "Non existe ningún usuario chamado \"$1\".\nOs nomes de usuario diferencian entre maiúsculas e minúsculas.\nVerifique o nome que inseriu ou [[Special:UserLogin/signup|cree unha nova conta]].",
+ "nosuchuser": "Non existe ningún usuario chamado \"$1\".\nOs nomes de usuario diferencian entre maiúsculas e minúsculas.\nVerifique a ortografía ou [[Special:CreateAccount|cree unha nova conta]].",
"nosuchusershort": "Non existe ningún usuario chamado \"$1\".\nVerifique o nome que inseriu.",
"nouserspecified": "Cómpre especificar un nome de usuario.",
"login-userblocked": "Este usuario está bloqueado. Acceso non autorizado.",
"createacct-another-realname-tip": "O nome real é opcional.\nSe escolle dalo utilizarase para atribuír ao usuario o seu traballo.",
"pt-login": "Acceder ao sistema",
"pt-login-button": "Acceder ao sistema",
+ "pt-login-continue-button": "Continuar a conexión",
"pt-createaccount": "Crear unha conta",
"pt-userlogout": "Saír",
"php-mail-error-unknown": "Erro descoñecido na función mail() do PHP.",
"botpasswords-invalid-name": "O nome de usuario especificado non contén o separador de contrasinal de bot (\"$1\").",
"botpasswords-not-exist": "O usuario \"$1\" non ten un contrasinal de bot de nome \"$2\".",
"resetpass_forbidden": "Non se poden mudar os contrasinais",
+ "resetpass_forbidden-reason": "Os contrasinais non poden cambiarse: $1",
"resetpass-no-info": "Debe rexistrarse para acceder directamente a esta páxina.",
"resetpass-submit-loggedin": "Cambiar o contrasinal",
"resetpass-submit-cancel": "Cancelar",
"passwordreset-emailsentusername": "Se hai unha dirección de correo electrónico asociada con este nome de usuario, entón enviarase un correo electrónico para o restablecemento do contrasinal.",
"passwordreset-emailsent-capture": "Enviouse un correo electrónico de restablecemento do contrasinal, mostrado a continuación.",
"passwordreset-emailerror-capture": "Xerouse un correo electrónico de restablecemento do contrasinal, mostrado a continuación, pero o envío {{GENDER:$2|ao usuario|á usuaria}} fallou: $1",
+ "passwordreset-emailsent-capture2": "{{PLURAL:$1|O correo de reinicialización do contrasinal foi enviado|Os correos de reinicialización do contrasinal foron enviados}}. {{PLURAL:$1|O nome de usuario e contrasinal móstrase abaixo|A lista de nomes de usuarios e contrasinais móstranse abaixo}}.",
+ "passwordreset-emailerror-capture2": "O envío do correo {{GENDER:$2|ó usuario|á usuaria}} fallou: $1 {{PLURAL:$3|O nome de usuario e contrasinal móstrase abaixo|A lista de usuarios e contrasinais móstranse abaixo}}.",
+ "passwordreset-nocaller": "Cómpre proporcionar un chamador",
+ "passwordreset-nosuchcaller": "O chamador non existe: $1",
+ "passwordreset-ignored": "A reinicialización do contrasinal non puido realizarse. Quizais non configurou o provedor?",
+ "passwordreset-invalideamil": "O enderezo de correo electrónico non é válido",
+ "passwordreset-nodata": "Non se indicou o nome de usuario ou a dirección de correo electrónico",
"changeemail": "Cambiar ou eliminar o enderezo de correo electrónico",
"changeemail-header": "Encha este formulario para cambiar o seu enderezo de correo electrónico. Se vostede quere eliminar a asociación da dirección de correo electrónico da súa conta, deixe en branco a nova dirección de correo electrónico cando envíe o formulario.",
"changeemail-passwordrequired": "Terá que escribir o seu contrasinal para confirmar este cambio.",
"changeemail-password": "O seu contrasinal en {{SITENAME}}:",
"changeemail-submit": "Cambiar o correo electrónico",
"changeemail-throttled": "Fixo demasiados intentos de acceder ao sistema.\nPor favor, agarde $1 antes de probar outra vez.",
- "changeemail-nochange": "Por favor, indique unha nova dirección de correo diferente.",
+ "changeemail-nochange": "Por favor, indique un enderezo de correo novo diferente.",
"resettokens": "Restablecer os pases",
"resettokens-text": "Aquí pode restablecer os pases que permiten acceder a certos datos privados asociados á súa conta.\n\nDebería facelo se os compartiu accidentalmente con alguén ou se a súa conta foi comprometida.",
"resettokens-no-tokens": "Non hai ningún pase que restablecer.",
"minoredit": "Esta é unha edición pequena",
"watchthis": "Vixiar esta páxina",
"savearticle": "Gardar a páxina",
- "publishpage": "Publicar páxina",
+ "publishpage": "Publicar a páxina",
"preview": "Vista previa",
"showpreview": "Mostrar a vista previa",
"showdiff": "Mostrar os cambios",
"missingcommentheader": "<strong>Aviso:</strong> Non escribiu ningún texto no asunto deste comentario.\nSe preme sobre \"{{int:savearticle}}\", a súa edición gardarase sen el.",
"summary-preview": "Vista previa do resumo:",
"subject-preview": "Vista previa do asunto:",
- "previewerrortext": "Houbo un erro ó tentar previsualizar os cambios.",
+ "previewerrortext": "Produciuse un erro ao intentar previsualizar os cambios.",
"blockedtitle": "O usuario está bloqueado",
"blockedtext": "'''O seu nome de usuario ou enderezo IP foi bloqueado.'''\n\nO bloqueo foi realizado por $1.\nA razón que deu foi ''$2''.\n\n* Inicio do bloqueo: $8\n* Caducidade do bloqueo: $6\n* Pretendeuse bloquear: $7\n\nPode contactar con $1 ou con calquera outro [[{{MediaWiki:Grouppage-sysop}}|administrador]] para discutir este bloqueo.\nNon pode empregar a característica \"Enviar un correo electrónico a este usuario\" a non ser que dispoña dun enderezo electrónico válido rexistrado nas súas [[Special:Preferences|preferencias de usuario]] e que o seu uso non fose bloqueado.\nO seu enderezo IP actual é $3 e o ID do bloqueo é #$5.\nPor favor, inclúa eses datos nas consultas que faga.",
"autoblockedtext": "O seu enderezo IP foi bloqueado automaticamente porque foi empregado por outro usuario que foi bloqueado por $1.\nA razón que deu foi a seguinte:\n\n:''$2''\n\n* Inicio do bloqueo: $8\n* Caducidade do bloqueo: $6\n* Pretendeuse bloquear: $7\n\nPode contactar con $1 ou con calquera outro [[{{MediaWiki:Grouppage-sysop}}|administrador]] para discutir este bloqueo.\n\nTeña en conta que non pode empregar a característica \"Enviar un correo electrónico a este usuario\" a non ser que dispoña dun enderezo electrónico válido rexistrado nas súas [[Special:Preferences|preferencias de usuario]] e e que o seu uso non fose bloqueado.\n\nO seu enderezo IP actual é $3 e o ID do bloqueo é #$5.\nPor favor, inclúa eses datos nas consultas que faga.",
"accmailtext": "Un contrasinal xerado ao chou para [[User talk:$1|$1]] foi enviado a $2. Pode modificarse na páxina de [[Special:ChangePassword|cambio de contrasinais]] tras acceder ao sistema.",
"newarticle": "(Novo)",
"newarticletext": "Seguiu unha ligazón a unha páxina que aínda non existe.\nPara crear a páxina, comece a escribir na caixa inferior (consulte a [$1 páxina de axuda] para obter máis información).\nSe chegou aquí por erro, simplemente prema no botón '''atrás''' do seu navegador.",
- "anontalkpagetext": "----''Esta é a páxina de conversa dun usuario anónimo que aínda non creou unha conta ou que non a usa. Polo tanto, empregamos o enderezo IP para a súa identificación. Este enderezo IP pódeno compartir varios usuarios distintos. Se pensa que foron dirixidos contra a súa persoa comentarios inadecuados, por favor, [[Special:UserLogin/signup|cree unha conta]] ou [[Special:UserLogin|acceda ao sistema]] para evitar futuras confusións con outros usuarios anónimos.''",
+ "anontalkpagetext": "----\n<em>Esta é a páxina de conversa dun usuario anónimo que aínda non creou unha conta ou que non a usa.</em> Polo tanto, empregamos o enderezo IP para a súa identificación. Este enderezo IP pódeno compartir varios usuarios distintos. Se pensa que foron dirixidos contra a súa persoa comentarios inadecuados, por favor, [[Special:CreateAccount|cree unha conta]] ou [[Special:UserLogin|acceda ao sistema]] para evitar futuras confusións con outros usuarios anónimos.",
"noarticletext": "Actualmente non hai ningún texto nesta páxina.\nPode [[Special:Search/{{PAGENAME}}|procurar polo título desta páxina]] noutras páxinas,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ollar os rexistros relacionados]\nou [{{fullurl:{{FULLPAGENAME}}|action=edit}} crear a páxina]</span>.",
"noarticletext-nopermission": "Actualmente non hai ningún texto nesta páxina.\nPode [[Special:Search/{{PAGENAME}}|procurar polo título desta páxina]] noutras páxinas ou <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ollar os rexistros relacionados]</span>, pero non ten os permisos necesarios para crear esta páxina.",
"missing-revision": "A revisión nº$1 da páxina chamada \"{{FULLPAGENAME}}\" non existe.\n\nA miúdo, isto está provocado por seguir unha ligazón de historial obsoleta cara a unha páxina que foi borrada.\nO [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} rexistro de borrados] contén máis detalles.",
"right-override-export-depth": "Exportar páxinas incluíndo as páxinas ligadas ata unha profundidade de 5",
"right-sendemail": "Enviar correos electrónicos a outros usuarios",
"right-passwordreset": "Ver os correos electrónicos de restablecemento de contrasinais",
- "right-managechangetags": "Crear e borrar [[Special:Tags|tags]] da base de datos",
+ "right-managechangetags": "Crear e (des)activar [[Special:Tags|tags]]",
"right-applychangetags": "Aplicar [[Special:Tags|etiquetas]] xunto cos cambios propios",
"right-changetags": "Engadir e quitar [[Special:Tags|etiquetas]] arbitrarias a revisións individuais e entradas do rexistro",
+ "right-deletechangetags": "Suprimir as [[Special:Tags|etiquetas]] da base de datos",
"grant-generic": "conxunto de dereitos \"$1\"",
"grant-group-page-interaction": "Interactuar con páxinas",
"grant-group-file-interaction": "Interactuar con ficheiros multimedia",
"action-viewmyprivateinfo": "ver a súa información privada",
"action-editmyprivateinfo": "editar a súa información privada",
"action-editcontentmodel": "editar o modelo de contido dunha páxina",
- "action-managechangetags": "crear e borrar etiquetas da base de datos",
+ "action-managechangetags": "crear e (des)activar etiquetas",
"action-applychangetags": "aplicar etiquetas xunto cos cambios",
"action-changetags": "engadir e quitar etiquetas arbitrarias a revisións individuais e entradas do rexistro",
+ "action-deletechangetags": "borrar etiquetas da base de datos",
"nchanges": "$1 {{PLURAL:$1|modificación|modificacións}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde a última visita}}",
"enhancedrc-history": "historial",
"upload-form-label-own-work": "Isto é o meu propio traballo",
"upload-form-label-infoform-categories": "Categorías",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-own-work-message-local": "Confirmo que estou a cargar este ficheiro seguindo os termos de uso e políticas de licenza de {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Se non é capaz de cargar este ficheiro baixo as políticas de {{SITENAME}}, por favor peche este diálogo e intente outro método.",
- "upload-form-label-not-own-work-local-local": "Quizais tamén queira probar [[Special:Upload|a páxina predeterminada de subidas]].",
- "upload-form-label-own-work-message-default": "Comprendo que estou a cargar este ficheiro nun repositorio compartido. Confirmo que fago isto seguindo os termos de uso e políticas de licenza existentes alí.",
- "upload-form-label-not-own-work-message-default": "Se non é capaz de cargar este ficheiro baixo as políticas do repositorio compartido, por favor peche este diálogo e intente outro método.",
- "upload-form-label-not-own-work-local-default": "Tamén pode interesarlle usar [[Special:Upload|a páxina de carga en {{SITENAME}}]], se este ficheiro pode ser cargado alí baixo as súas políticas.",
- "upload-form-label-own-work-message-shared": "Certifico que son o propietario dos dereitos de autor deste ficheiro, e que concordo a liberar irrevocablemente este ficheiro a Wikimedia Commons baixo a licenza [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], e que concordo cos [https://wikimediafoundation.org/wiki/Terms_of_Use Termos de uso].",
- "upload-form-label-not-own-work-message-shared": "Se non posúe os dereitos de autor deste ficheiro, ou quere liberalo baixo unha licenza diferente, considere usar o [https://commons.wikimedia.org/wiki/Special:UploadWizard Asistente de subas de Commons].",
- "upload-form-label-not-own-work-local-shared": "Tamén pode interesarlle usar [[Special:Upload|a páxina de carga en {{SITENAME}}]], se o sitio permite a suba deste ficheiro nas súas políticas.",
+ "upload-form-label-own-work-message-generic-local": "Confirmo que estou a cargar este ficheiro seguindo os termos de uso e políticas de licenza de {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Se non é capaz de cargar este ficheiro baixo as políticas de {{SITENAME}}, por favor peche este diálogo e intente outro método.",
+ "upload-form-label-not-own-work-local-generic-local": "Quizais tamén queira probar [[Special:Upload|a páxina predeterminada de subidas]].",
+ "upload-form-label-own-work-message-generic-foreign": "Comprendo que estou a cargar este ficheiro nun repositorio compartido. Confirmo que fago isto seguindo os termos de uso e políticas de licenza existentes alí.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Se non é capaz de cargar este ficheiro baixo as políticas do repositorio compartido, por favor peche este diálogo e intente outro método.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Tamén pode interesarlle usar [[Special:Upload|a páxina de carga en {{SITENAME}}]], se este ficheiro pode ser cargado alí baixo as súas políticas.",
"backend-fail-stream": "Non se puido transmitir o ficheiro \"$1\".",
"backend-fail-backup": "Non se puido facer unha copia de seguridade do ficheiro \"$1\".",
"backend-fail-notexists": "O ficheiro \"$1\" non existe.",
"trackingcategories-msg": "Categoría de seguimento",
"trackingcategories-name": "Nome da mensaxe",
"trackingcategories-desc": "Criterio de inclusión da categoría",
+ "restricted-displaytitle-ignored": "Páxinas co título que se mostra ignorado",
+ "restricted-displaytitle-ignored-desc": "Esta páxina ten un <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> ignorado porque non é equivalente ao título real da páxina.",
"noindex-category-desc": "A páxina non está indexada polos bots porque contén a palabra máxica <code><nowiki>__NOINDEX__</nowiki></code> e está nun espazo de nomes no que esa marca está permitida.",
"index-category-desc": "A páxina contén a palabra máxica <code><nowiki>__INDEX__</nowiki></code> (e está nun espazo de nomes no que esa marca está permitida) e, polo tanto, será indexada polos bots cando non debera selo normalmente.",
"post-expand-template-inclusion-category-desc": "O tamaño da páxina é maior que <code>$wgMaxArticleSize</code> despois de expandir todos os modelos; algúns modelos non se expandiron.",
"rollbacklinkcount": "reverter $1 {{PLURAL:$1|edición|edicións}}",
"rollbacklinkcount-morethan": "reverter máis de $1 {{PLURAL:$1|edición|edicións}}",
"rollbackfailed": "Houbo un erro ao reverter as edicións",
+ "rollback-missingparam": "Faltan parámetros obrigatorios na solicitude.",
"cantrollback": "Non se pode desfacer a edición; o último colaborador é o único autor desta páxina.",
"alreadyrolled": "Non se pode desfacer a edición en \"[[:$1]]\" feita por [[User:$2|$2]] ([[User talk:$2|conversa]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]); alguén máis editou ou desfixo os cambios desta páxina.\n\nA última edición fíxoa [[User:$3|$3]] ([[User talk:$3|conversa]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "O resumo de edición foi: <em>$1</em>.",
"revertpage": "Desfixéronse as edicións de [[Special:Contributions/$2|$2]] ([[User talk:$2|conversa]]); cambiado á última versión feita por [[User:$1|$1]]",
"revertpage-nouser": "Desfixéronse as edicións dun usuario agochado; cambiado á última versión feita por {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Desfixéronse as edicións de $1;\nvolveuse á última edición, feita por $2.",
+ "rollback-success-notify": "Modificacións anuladas por $1; restaurado á última revisión de $2. [$3 Mostrar os cambios]",
"sessionfailure-title": "Erro de sesión",
"sessionfailure": "Parece que hai un problema co rexistro da súa sesión;\nesta acción cancelouse como precaución fronte ao secuestro de sesións.\nPrema no botón \"atrás\", volva cargar a páxina da que proviña e inténteo de novo.",
"changecontentmodel": "Cambiar o modelo do contido dunha páxina",
"changecontentmodel-success-text": "O tipo de contido de [[:$1]] foi modificado.",
"changecontentmodel-cannot-convert": "O contido en [[:$1]] non pode converterse ó tipo de $2.",
"changecontentmodel-nodirectediting": "O modelo de contido $1 non permite a modificación directa",
+ "changecontentmodel-emptymodels-title": "Non hai modelos de contido dispoñibles",
+ "changecontentmodel-emptymodels-text": "O contido de [[:$1]] non pode converterse a ningún tipo.",
"log-name-contentmodel": "Rexistro de cambios de modelo de contido",
"log-description-contentmodel": "Eventos relacinados cos modelos de contido dunha páxina",
"logentry-contentmodel-new": "$1 {{GENDER:$2|creou}} a páxina $3 usando un modelo de contido non predeterminado \"$5\"",
"whatlinkshere-hideredirs": "$1 as redireccións",
"whatlinkshere-hidetrans": "$1 as inclusións",
"whatlinkshere-hidelinks": "$1 as ligazóns",
- "whatlinkshere-hideimages": "$1 as ligazóns ao ficheiro",
+ "whatlinkshere-hideimages": "$1 ligazóns ao ficheiro",
"whatlinkshere-filters": "Filtros",
"whatlinkshere-submit": "Ir",
"autoblockid": "Bloqueo automático nº$1",
"lockdbsuccesstext": "Pechouse a base de datos.<br />\nLembre [[Special:UnlockDB|eliminar o bloqueo]] unha vez completado o seu mantemento.",
"unlockdbsuccesstext": "A base de datos foi desbloqueada.",
"lockfilenotwritable": "Non se pode escribir no ficheiro de bloqueo da base de datos. Para bloquear ou desbloquear a base de datos, o servidor web ten que poder escribir neste ficheiro.",
+ "databaselocked": "A base de datos xa está bloqueada.",
"databasenotlocked": "A base de datos non está bloqueada.",
"lockedbyandtime": "(por $1 o $2 ás $3)",
"move-page": "Mover \"$1\"",
"tooltip-pt-anonuserpage": "A páxina de usuario do enderezo IP desde o que está a editar",
"tooltip-pt-mytalk": "A súa páxina de conversa",
"tooltip-pt-anontalk": "Conversa acerca de edicións feitas desde este enderezo IP",
- "tooltip-pt-preferences": "As súas preferencias",
+ "tooltip-pt-preferences": "{{GENDER:|As sú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",
"confirm-watch-top": "Quere engadir esta páxina á lista de vixilancia?",
"confirm-unwatch-button": "Aceptar",
"confirm-unwatch-top": "Quere eliminar esta páxina da lista de vixilancia?",
+ "confirm-rollback-button": "Aceptar",
+ "confirm-rollback-top": "Reverter as edicións desta páxina?",
"colon-separator": ": ",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← páxina anterior",
"timezone-local": "Local",
"duplicate-defaultsort": "<strong>Aviso:</strong> A clave de ordenación por defecto \"$2\" anula a clave de ordenación anterior por defecto \"$1\".",
"duplicate-displaytitle": "'''Aviso:''' O título mostrado \"$2\" anula o título anterior \"$1\".",
+ "restricted-displaytitle": "<strong>Atención:</strong> O título mostrado \"$1\" ignorouse porque non é equivalente ao título real da páxina.",
"invalid-indicator-name": "<strong>Erro:</strong> O atributo <code>name</code> dos indicadores do estado da páxina non pode estar baleiro.",
"version": "Versión",
"version-extensions": "Extensións instaladas",
"tags-delete-not-found": "A páxina \"$1\" non existe.",
"tags-delete-too-many-uses": "A etiqueta \"$1\" aplícase a máis de $2 {{PLURAL:$2|revisión|revisións}}; isto significa que non se pode borrar.",
"tags-delete-warnings-after-delete": "A etiqueta \"$1\" borrouse; con todo, {{PLURAL:$2|atopouse o seguinte aviso|atopáronse os seguintes avisos}}:",
+ "tags-delete-no-permission": "Non ten permisos para borrar etiquetas de cambio.",
"tags-activate-title": "Activar unha etiqueta",
"tags-activate-question": "Está a piques de activar a etiqueta\"$1\".",
"tags-activate-reason": "Motivo:",
"log-action-filter-suppress-block": "Supresión de usuario por bloqueo",
"log-action-filter-suppress-reblock": "Supresión de usuario por bloqueo reiterado",
"log-action-filter-upload-upload": "Nova subida",
- "log-action-filter-upload-overwrite": "Resubida"
+ "log-action-filter-upload-overwrite": "Resubida",
+ "authmanager-authn-not-in-progress": "O proceso de autenticación non está en progreso ou perdéronse os datos da sesión. Empece de novo desde o principio.",
+ "authmanager-authn-no-primary": "A información de identificación proporcionada non pode ser autenticada.",
+ "authmanager-authn-no-local-user": "As credenciais proporcionadas non están asociadas con ningún usuario neste wiki.",
+ "authmanager-authn-no-local-user-link": "As credenciais proporcionadas son válidas, pero non están asociadas a ningún usuario deste wiki. Acceda dun xeito diferente ou cree un usuario novo e terá unha opción para vincular as súas credenciais anteriores a aquela conta.",
+ "authmanager-authn-autocreate-failed": "A creación automatica dunha conta local fallou: $1",
+ "authmanager-change-not-supported": "As credenciais proporcionadas non se poden modificar, xa que ninguén as utilizará.",
+ "authmanager-create-disabled": "A creación de contas está desactivada.",
+ "authmanager-create-from-login": "Para crear a súa conta, complete os campos a continuación.",
+ "authmanager-create-not-in-progress": "O proceso de creación da conta non está en progreso ou perdéronse os datos da sesión. Empece de novo desde o principio.",
+ "authmanager-create-no-primary": "As credenciais subministradas non poden usarse para a creación da conta.",
+ "authmanager-link-no-primary": "As credenciais subministradas non poden usarse para a ligazón da conta.",
+ "authmanager-link-not-in-progress": "A vinculación da conta non está en progreso ou perdéronse os datos da sesión. Empece de novo desde o principio.",
+ "authmanager-authplugin-setpass-failed-title": "Fallou o cambio do contrasinal",
+ "authmanager-authplugin-setpass-failed-message": "O complemento de autenticación denegou o cambio de contrasinal.",
+ "authmanager-authplugin-create-fail": "O complemento de autenticación denegou a creación da conta.",
+ "authmanager-authplugin-setpass-denied": "O complemento de autenticación non permite o cambio de contrasinais.",
+ "authmanager-authplugin-setpass-bad-domain": "Dominio non válido.",
+ "authmanager-autocreate-noperm": "A creación automatica de contas non está permitida.",
+ "authmanager-autocreate-exception": "A creación automatica de contas foi desactivada temporalmente debido a erros previos.",
+ "authmanager-userdoesnotexist": "O usuario \"$1\" non está rexistrado.",
+ "authmanager-userlogin-remembermypassword-help": "Indique se o contrasinal debe lembrarse máis alá da duración da sesión.",
+ "authmanager-username-help": "Nome de usuario para autenticación.",
+ "authmanager-password-help": "Contrasinal para autenticación.",
+ "authmanager-domain-help": "Dominio para autenticación externa.",
+ "authmanager-retype-help": "O contrasinal de novo para confirmar.",
+ "authmanager-email-label": "Correo electrónico",
+ "authmanager-email-help": "Enderezo de correo electrónico",
+ "authmanager-realname-label": "Nome real",
+ "authmanager-realname-help": "Nome real do usuario",
+ "authmanager-provider-password": "Autenticación baseada en contrasinal",
+ "authmanager-provider-password-domain": "Autenticación por contrasinal e dominio",
+ "authmanager-provider-temporarypassword": "Contrasinal temporal",
+ "authprovider-confirmlink-message": "En función dos seus últimos accesos, as seguintes contas poden vincularse coa súa conta no wiki. A vinculación permite acceder a través desas contas. Seleccione aquelas que queira vincular.",
+ "authprovider-confirmlink-request-label": "Contas que deben ser ligadas",
+ "authprovider-confirmlink-success-line": "$1: ligado correctamente.",
+ "authprovider-confirmlink-failed": "A ligazón das contas non foi correctamente: $1",
+ "authprovider-confirmlink-ok-help": "Continuar despois de mostrar as mensaxes de erro na vinculación.",
+ "authprovider-resetpass-skip-label": "Omitir",
+ "authprovider-resetpass-skip-help": "Saltar a reinicialización do contrasinal.",
+ "authform-nosession-login": "A autenticación foi correcta, pero o seu navegador non pode \"lembrar\" ter iniciado sesión.\n\n$1",
+ "authform-nosession-signup": "A conta foi creada, pero o seu navegador non \"lembra\" ter iniciado sesión.\n\n$1",
+ "authform-newtoken": "Identificador perdido. $1",
+ "authform-notoken": "Identificador perdido",
+ "authform-wrongtoken": "Identificador incorrecto",
+ "specialpage-securitylevel-not-allowed-title": "Non permitido",
+ "specialpage-securitylevel-not-allowed": "Sentímolo, non ten permitido usar esta páxina porque a súa identidade non puido verificarse.",
+ "authpage-cannot-login": "Imposible comezar a conexión.",
+ "authpage-cannot-login-continue": "Imposible continuar a conexión. O máis probable é que a súa sesión teña expirado.",
+ "authpage-cannot-create": "Non se pode iniciar a creación da conta.",
+ "authpage-cannot-create-continue": "Imposible continua a creación da conta. A súa sesión semella ter expirado.",
+ "authpage-cannot-link": "Imposible comezar a vinculación da conta.",
+ "authpage-cannot-link-continue": "Imposible continuar coa vinculación da conta. Semella que a súa sesión expirou.",
+ "cannotauth-not-allowed-title": "Permiso rexeitado",
+ "cannotauth-not-allowed": "Non ten permiso para usar esta páxina",
+ "changecredentials": "Cambiar as credenciais",
+ "changecredentials-submit": "Cambiar credenciais",
+ "changecredentials-invalidsubpage": "$1 non é un tipo de información de identificación válido.",
+ "changecredentials-success": "As súas credenciais foron cambiadas.",
+ "removecredentials": "Eliminar credenciais",
+ "removecredentials-submit": "Eliminar credenciais",
+ "removecredentials-invalidsubpage": "$1 non é un tipo de información de identificación válido.",
+ "removecredentials-success": "As súas credenciais foron eliminadas.",
+ "credentialsform-provider": "Tipo de información de identificación:",
+ "credentialsform-account": "Nome da conta:",
+ "cannotlink-no-provider-title": "Non hai contas vinculables",
+ "cannotlink-no-provider": "Non hai contas vinculables.",
+ "linkaccounts": "Vincular contas",
+ "linkaccounts-success-text": "A conta foi vinculada.",
+ "linkaccounts-submit": "Vincular contas",
+ "unlinkaccounts": "Desvincular contas",
+ "unlinkaccounts-success": "A conta foi desvinculada."
}
"compareselectedversions": "वेंचिल्ल्या पुनर्नियाळांची तुळा करात",
"editundo": "केल्लें परतावचें",
"diff-multi-sameuser": "(ह्या वांगड्या सयत {{PLURAL:$1|केल्लें मदलें एक अवतरण दाखोवंक ना|केल्लें मदलें $1 अवतरण दाखोवंक ना}})",
- "searchresults": "सà¥\8bदाà¤\9aà¥\87 परिणामाà¤\82",
+ "searchresults": "सà¥\8bदाà¤\9aà¥\8b निà¤\95ाल",
"searchresults-title": "\"$1\" हाच्या सोदाचे परिणामां",
"prevn": "आदलें{{PLURAL:$1|$1}}",
"nextn": "दुसरें {{PLURAL:$1|$1}}",
"exif-orientation-1": "सामान्य",
"namespacesall": "सगळें",
"monthsall": "सगळे",
+ "confirm-rollback-button": "बरें",
+ "confirm-rollback-top": "ह्या पाना वयलें संपादन आशिल्ले तशें करात?",
"watchlisttools-view": "प्रस्तूत बदल पळयात.",
"watchlisttools-edit": "सादुरवळेरी पळय आनी संपादीत करात",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|उलयात]])",
"newpassword": "Novem gupitutor:",
"retypenew": "Novem gupitutor portun boroi:",
"resetpass_submit": "Gupitutor tharai ani sotrorombh kor",
- "changepassword-success": "Tujem gupitutor bodlop yoshosvi tharlam.",
+ "changepassword-success": "Tujem gupitutor bodol'lam!",
"resetpass_forbidden": "Gupitutram bodlunk zaina",
"resetpass-submit-loggedin": "Gupitutoor bodol",
"resetpass-submit-cancel": "Roddh kor",
"whatlinkshere-prev": "{{PLURAL:$1|adlem|adlem $1}}",
"whatlinkshere-next": "{{PLURAL:$1|fuddlem|fuddlim $1}}",
"whatlinkshere-links": "← zoddnio",
- "whatlinkshere-hideredirs": "$1 punornirdexon",
- "whatlinkshere-hidetrans": "$1 durasth-somaves",
+ "whatlinkshere-hideredirs": "$1 punornirdexonam",
+ "whatlinkshere-hidetrans": "$1 durasth-somaveso",
"whatlinkshere-hidelinks": "$1 zoddnio",
"whatlinkshere-hideimages": "Failinchim zoddpam $1",
"whatlinkshere-filters": "Challnio",
"exif-orientation-1": "Samanya",
"namespacesall": "sogllem",
"monthsall": "sogllem",
+ "confirm-rollback-button": "Borem",
+ "confirm-rollback-top": "Hea pana voile somadon asle toxe porot kor?",
"watchlisttools-view": "Sombondhi bodlopam polloi",
"watchlisttools-edit": "Sadurvolleri polloi ani sudar",
"watchlisttools-raw": "Sadurvollerichi mull-an bodol kor",
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Ilham",
+ "Lukman Tomayahu",
+ "Marwan Mohamad",
+ "Matma Rex",
+ "NoiX180",
+ "Zhoelyakin"
+ ]
+ },
+ "tog-underline": "Garisiyi totibawa pranala",
+ "tog-hideminor": "Wanto'a u iluba ngo'idi to'u bohu",
+ "tog-hidepatrolled": "Wanto'a u iluba patroli to'u bohu",
+ "tog-newpageshidepatrolled": "Wanto'a halaamani patroli lonto daputari halaamani bohu",
+ "tog-hidecategorization": "Wanto'a tayadu halaamani",
+ "tog-extendwatchlist": "Duhengi daputari he'awasiyalo u mopobilohu nga'amila ulo ubawa, dila bo ubohu",
+ "tog-usenewrc": "Popotayade u iluba to bibilohu lu'ubawa baharu wawu daputari he awasiyalo berdasarkan halaamani",
+ "tog-numberheadings": "Otomatis modulade nomoro",
+ "tog-showtoolbar": "Mopobilohe pilakasi ponguba",
+ "tog-editondblclick": "Monguba halaamani mo klik po'oluwo",
+ "tog-editsectiononrightclick": "Popohunawa monguba tayadu wolo mengeklik olowala to judul lo tayadu",
+ "tog-watchcreations": "Duhengi halamani u pilohutu'u wawu berkas u diletohu'u ode daputari he awasiya'u",
+ "tog-watchdefault": "Duhengi halamani wawu berkas u iluba'u ode daputari he awasiya'u",
+ "tog-watchmoves": "Duhengi halamani wawu berkas u pilinda'u ode daputari he awasiya'u",
+ "tog-watchdeletion": "Duhengi halamani wawu berkas u yilulutu'u ode daputari he awasiya'u",
+ "tog-watchuploads": "Duhengi berkas bohu u diletohu'u to daputari he'awasiyalo",
+ "tog-watchrollback": "Duhengi halamani u pilohuwalingu'u ode daputari he awasiya'u",
+ "tog-minordefault": "Tandai nga'amila odelo iluba keke'ingo secara baku",
+ "tog-previewontop": "Popobilohe po'olo to'udiipo dosi monguba",
+ "tog-previewonfirst": "Popobilohe po'olo to'u monguba bohuliyo",
+ "tog-enotifwatchlistpages": "Lawoli wa'u surel wonu halamani tuwawu u awasiya'u lo'ubawa",
+ "tog-enotifusertalkpages": "Lawoli wa'u surel wonu halaamani tombilu'u lo'ubawa",
+ "tog-enotifminoredits": "Lawoli surel olo wa'u to'u lo'ubawa ngo'idi halaamani wawu berkas",
+ "tog-enotifrevealaddr": "Popobilohe alamati lo surel ola'u to surel lopo'ota",
+ "tog-shownumberswatching": "Popobilohe jumula lo ta he'awasiyalo",
+ "tog-oldsig": "Pali lo ulu'u masatiya",
+ "tog-fancysig": "Popopasiya pali lo'ulu'u odelo tuladuwiki (diyalu tuwawu pranala otomatis)",
+ "tog-uselivepreview": "Popohunawa mopobilohu langsung",
+ "tog-forceeditsummary": "Popo'eelawa wa'u wonu dosi monguba diipo otuwa",
+ "tog-watchlisthideown": "Wantoa u iluba'u to daputari lo he'awasiyalo",
+ "tog-watchlisthidebots": "Wanto'a u iluba lo bot to daputari lo he'awasiyalo",
+ "tog-watchlisthideminor": "Wanto'a u iluba ngo'idi to daputari lo he'awasiyalo",
+ "tog-watchlisthideliu": "Wanto'a u iluba pengguna maso log to daputari he awasiyalo",
+ "tog-watchlistreloadautomatically": "Muwatiya ulangi daputari he awasiyalo secara otomatis timi'idu saringan lo'ubawa (JavaScript paraluwolo)",
+ "tog-watchlisthideanons": "Wanto'a u iluba lo pengguna anonim monto daputari he awasiyalo",
+ "tog-watchlisthidepatrolled": "Wanto'a u iluba patroli monto daputari he'awasiyalo",
+ "tog-watchlisthidecategorization": "Wanto'a kategori halaman",
+ "tog-ccmeonemails": "Lawoli wa'u wami lo surel u yilawou to tawu",
+ "tog-diffonly": "Ja popobilohe tuwango halaman iluba u bebedawa",
+ "tog-showhiddencats": "Popobilehe kategori u hewanto'a",
+ "tog-norollbackdiff": "Japopobilohe u beda yilapato pilopohalingo",
+ "tog-useeditwarning": "Popo'ingatiya wa'u wonu molola halaman he'ubalo wonu dipo tilahu",
+ "tog-prefershttps": "Layito momake koneksi amaani wonu mo maso log",
+ "underline-always": "Layito",
+ "underline-never": "Dila ta",
+ "underline-default": "Alipo meyalo browser dudelo",
+ "editfont-style": "Ubawa area gaya lo tuladu",
+ "editfont-default": "Browser dudelo",
+ "editfont-monospace": "Tuladu Monospaced",
+ "editfont-sansserif": "Tuladu San-serif",
+ "editfont-serif": "Tuladu Serif",
+ "sunday": "Ahadi",
+ "monday": "Isinini",
+ "tuesday": "Salaasa",
+ "wednesday": "Araba'a",
+ "thursday": "Hamisi",
+ "friday": "Juma'ati",
+ "saturday": "Sahutu",
+ "sun": "Aha",
+ "mon": "Isi",
+ "tue": "Sal",
+ "wed": "Ara",
+ "thu": "Ham",
+ "fri": "Jum",
+ "sat": "Sah",
+ "january": "Januwari",
+ "february": "Peburuari",
+ "march": "Maret",
+ "april": "April",
+ "may_long": "Mei",
+ "june": "Juni",
+ "july": "Juli",
+ "august": "Agustus",
+ "september": "September",
+ "october": "Oktober",
+ "november": "Nopember",
+ "december": "Desember",
+ "january-gen": "Januwari",
+ "february-gen": "Peburuwari",
+ "march-gen": "Maret",
+ "april-gen": "April",
+ "may-gen": "Meyi",
+ "june-gen": "Juni",
+ "july-gen": "Juli",
+ "august-gen": "Agustus",
+ "september-gen": "September",
+ "october-gen": "Oktober",
+ "november-gen": "Nopember",
+ "december-gen": "Desember",
+ "jan": "Jan",
+ "feb": "Peb",
+ "mar": "Mar",
+ "apr": "Apr",
+ "may": "Mei",
+ "jun": "Jun",
+ "jul": "Jul",
+ "aug": "Agt",
+ "sep": "Sep",
+ "oct": "Okt",
+ "nov": "Nop",
+ "dec": "Des",
+ "january-date": "$1 Yanuari",
+ "february-date": "$1 Peburuari",
+ "march-date": "$1 Maret",
+ "april-date": "$1 April",
+ "may-date": "$1 Mei",
+ "june-date": "$1 Yuni",
+ "july-date": "$1 Yuli",
+ "august-date": "$1 Agustus",
+ "september-date": "$1 September",
+ "october-date": "$1 Oktober",
+ "november-date": "$1 Nopember",
+ "december-date": "$1 Desember",
+ "period-am": "AM",
+ "period-pm": "PM",
+ "pagecategories": "{{PLURAL:$1|Tayadu}}",
+ "category_header": "Halaman to delomo kategori \"$1\"",
+ "subcategories": "Subkategori",
+ "category-media-header": "Media to delomo kategori \"$1\"",
+ "category-empty": "<em>Kategori botiye ja o halaman meyalo media.<em>",
+ "hidden-categories": "{{PLURAL:$1|Tayadu wanto-wanto'o}}",
+ "hidden-category-category": "Kategori u wanto-wanto'o",
+ "category-subcat-count": "{{PLURAL:$2|Kategori boti woluwo subkategori|Kategori boti woluwo {{PLURAL:$1|subkategori|$1 subkategori}} lonto nga'amila $2.}}",
+ "category-subcat-count-limited": "Kategori boti woluwo {{PLURAL:$1|subkategori|$1 subkategori}}",
+ "category-article-count": "{{PLURAL:$2|Kategori botiye o tuwango halaman.|Woluwo {{PLURAL:$|$1 halaman}} to delomo kategori, lonto $2 nga'amila.}}",
+ "category-article-count-limited": "Kategori boti woluwo {{PLURAL:$1|halaman|$1 halaman}} to delomo kategori",
+ "category-file-count": "{{PLURAL:$2|To kategori boti woluwo berkas {{PLURAL:$1|berkas|$1 berkas}} to delomo kategori, lonto nga'amila $2}}",
+ "category-file-count-limited": "Woluwo {{PLURAL:$1|berkas|S1 berkas}} to delomo kategori.",
+ "listingcontinuesabbrev": "wumb",
+ "index-category": "Halaman to indeks",
+ "noindex-category": "Haalaman dila to indeks",
+ "broken-file-category": "Halaamani wolo pranala berkas ma lorusa",
+ "about": "Tomimbihu",
+ "article": "Tuwango halaman",
+ "newwindow": "hu'owa to janela bohu",
+ "cancel": "Batali",
+ "moredotdotdot": "Uweewo",
+ "morenotlisted": "Daputari boti dipo ganapu",
+ "mypage": "Halaamani",
+ "mytalk": "Lo'iya",
+ "anontalk": "Bisala",
+ "navigation": "Navigasi",
+ "and": " wawu",
+ "qbfind": "Lolohe",
+ "qbbrowse": "Momilohu",
+ "qbedit": "Monguba",
+ "qbpageoptions": "Halaman botiya",
+ "qbmyoptions": "Halamani'u",
+ "faq": "FAQ",
+ "faqpage": "Project:FAQ",
+ "actions": "Huhutu",
+ "namespaces": "Huwali lo tanggulo",
+ "variants": "Varian",
+ "navigation-heading": "Menu navigasi",
+ "errorpagetitle": "Lotaalawa",
+ "returnto": "Mohuwalingo ode $1",
+ "tagline": "Lonto {{SITENAME}}",
+ "help": "Wubodu",
+ "search": "Lolohe",
+ "searchbutton": "Lolohe",
+ "go": "Ntali",
+ "searcharticle": "Ntali",
+ "history": "Riwayati lo halaman",
+ "history_short": "Riwayati",
+ "updatedmarker": "iluba to'u nila'o'u pulitiyo",
+ "printableversion": "Persi cetak",
+ "permalink": "Wumbuta kakali",
+ "print": "Cetaki",
+ "view": "Bilohi",
+ "view-foreign": "Bilohi to $1",
+ "edit": "Momoli'o",
+ "edit-local": "Ubawa deskripsi lokal",
+ "create": "Mohutu",
+ "create-local": "Duhengi deskripsi lokal",
+ "editthispage": "Ubawa halaamani boti",
+ "create-this-page": "Pohutuwa halaamani boti",
+ "delete": "Luluta",
+ "deletethispage": "Luluta halaamani boti",
+ "undeletethispage": "Bataliya moluluto",
+ "undelete_short": "Batali moluluto {{PLURAL:$1|tuwawu uba|$1 ubawa}}",
+ "viewdeleted_short": "Bilohi {{PLURAL:$1|tuwawu yiluluto uba|$1 yiluluto ubawa}}",
+ "protect": "Dahawa",
+ "protect_change": "gantiyi",
+ "protectthispage": "Dahawa halaman boti",
+ "unprotect": "dudaha ubaalo",
+ "unprotectthispage": "ubawa dudaha halaman botiye",
+ "newpage": "Halaman bohu",
+ "talkpage": "Bisalayi halaman boti",
+ "talkpagelinktext": "lo'iya",
+ "specialpage": "Halaman uda'a",
+ "personaltools": "Pilaakasi lo hihilawo",
+ "articlepage": "Bilohi tuango halaman",
+ "talk": "Biisalawa",
+ "views": "Bibilohu",
+ "toolbox": "Pilaakasi",
+ "userpage": "Bilohi halaman pengguna",
+ "projectpage": "Bilohi halaman proyek",
+ "imagepage": "Bilohi halaman berkas",
+ "mediawikipage": "Bilohi halaman tahuli",
+ "templatepage": "Bilohi halaman templat",
+ "viewhelppage": "Bilohi halaman wubodu",
+ "categorypage": "Bilohi kategori halaman",
+ "viewtalkpage": "Bilohi u bilisala",
+ "otherlanguages": "To bahasa uweewo",
+ "redirectedfrom": "Pilobale lonto $1",
+ "redirectpagesub": "Halaman pilobaleyalo",
+ "redirectto": "Mobale ode",
+ "lastmodifiedat": "Halaman botiye biloli'o pulitiyo $1, $2.",
+ "viewcount": "Halaman botiye ma hilu'o {{PLURAL:$1|$1 kali}}.<br />",
+ "protectedpage": "Halaman udaha-daha",
+ "jumpto": "Lumanti'a ode",
+ "jumptonavigation": "Navigasi",
+ "jumptosearch": "lolohe",
+ "view-pool-error": "Ma'apu, server onggo sibuk sa'ati boti.\nNgohuntuwa pengguna mocoba momilehe halaman boti.\nWulatipo ngope'e to'u yi'o dipo mocoba momilehe halaman boti pooli.\n\n\n$1",
+ "generic-pool-error": "Ma'apu, server onggo sibuk sa'ati boti.\nNgohuntuwa pengguna mocoba momilohe halaman boti.\nWulatipo ngope'e to'u yi'u dipo mocoba momilehe halaman boti pooli.",
+ "pool-timeout": "Mohile wakutu mohulata u'unti",
+ "pool-queuefull": "Tahe'ambuwa hepohulata polu-polu",
+ "pool-errorunknown": "Tilala u ja'otawa",
+ "pool-servererror": "Ta hemorekeni pool botiye diya'a: $1",
+ "poolcounter-usage-error": "Tilala lopohuna:$1",
+ "aboutsite": "Tomimbihu {{SITENAME}}",
+ "aboutpage": "Proyek:Tomimbihu",
+ "copyright": "Tuwango woluwo sadi-sadia odelo to tibawa $1",
+ "copyrightpage": "{{ns:project}}:Haku lohutu",
+ "currentevents": "U yilowali baharu",
+ "currentevents-url": "Project:U yilowali baharu",
+ "disclaimers": "Momaahu",
+ "disclaimerpage": "Project:Momaahu umum",
+ "edithelp": "Wubodu momoli'o",
+ "helppage-top-gethelp": "Tuulungi",
+ "mainpage": "Halaman Bungaliyo",
+ "mainpage-description": "Halaman bungaliyo",
+ "policy-url": "Project:Kebijakan",
+ "portal": "Buubu'a leembo'a",
+ "portal-url": "Project:Buubu'a lembo'a",
+ "privacy": "Tinepo privasi",
+ "privacypage": "Project:Tinepo privasi",
+ "badaccess": "Tilala haku momu'o",
+ "badaccess-group0": "Yi'o diya o iijini mohutu kalaja u hepohilemu",
+ "badaccess-groups": "Huhutu hepohilemu bilatasiyaliyo to pengguna {{PLURAL:$2|lembo'a}}$1.",
+ "versionrequired": "Paralu MediaWiki persi $1",
+ "versionrequiredtext": "MediaWiki versi $1 paraluwolo wonu mopohuna lo halaman botiye.\nBilohi [[Special:Version|halaman versi]]",
+ "ok": "OK",
+ "retrievedfrom": "Yilotapu lonto \"$1\"",
+ "youhavenewmessages": "{{PLURAL:$3|woluwo ulemu}} $1 ($2)",
+ "youhavenewmessagesfromusers": "{{PURAL:$4|woluwo ulemu}} $1 lonto {{PLURAL:$3|pengguna uwewo|$3 pengguna}} ($2)",
+ "youhavenewmessagesmanyusers": "Wolumo ulemu $1 lonto pengguna uwewo ($2)",
+ "newmessageslinkplural": "{{PLURAL:$1|tuwawu tahuli bohu|999=tahuli bohu}}",
+ "newmessagesdifflinkplural": "{{PLURAL:$1|iluba|999=u iluba}} pulitiyo",
+ "youhavenewmessagesmulti": "Yio lootapu tahuli bohu to $1",
+ "editsection": "boli'a",
+ "editold": "boli'a",
+ "viewsourceold": "Bilohi bungoliyo",
+ "editlink": "boli'a",
+ "viewsourcelink": "Bilohi bungoliyo",
+ "editsectionhint": "Momoli'o tayadu:$1",
+ "toc": "Tuwango",
+ "showtoc": "popobilehe",
+ "hidetoc": "wanto'a",
+ "collapsible-collapse": "Lolohubu",
+ "collapsible-expand": "Duhengi",
+ "confirmable-confirm": "Delo {{GENDER:$1|yi'o}} yakini?",
+ "confirmable-yes": "Jo",
+ "confirmable-no": "De'e",
+ "thisisdeleted": "Bilohi meyalo pohuwalinga $1",
+ "viewdeleted": "Bilohi $1",
+ "restorelink": "{{PLURAL:$1|tuwawu yiluluto ubawa}}",
+ "feedlinks": "Paalo",
+ "feed-invalid": "Hihile tayadu paalo dila banari.",
+ "feed-unavailable": "Paalo sindikasi diyaluwo",
+ "site-rss-feed": "Palo $1 RSS",
+ "site-atom-feed": "Paalo $1 Atom",
+ "page-rss-feed": "Paalo $1 RSS",
+ "page-atom-feed": "Paalo $1 Atom",
+ "red-link-title": "$1 (halaman diila sadi-sadia)",
+ "sort-descending": "Urutiya detibawa",
+ "sort-ascending": "Urutiya deyitaato",
+ "nstab-main": "Halaman",
+ "nstab-user": "Pengguna",
+ "nstab-media": "Halaman media",
+ "nstab-special": "Halaman spesial",
+ "nstab-project": "Halaman poroyek",
+ "nstab-image": "Berkas",
+ "nstab-mediawiki": "Tahuli",
+ "nstab-template": "Templat",
+ "nstab-help": "Halaman tulungi",
+ "nstab-category": "Kategori",
+ "mainpage-nstab": "Halamani bungaliyo",
+ "nosuchaction": "Diya'a huhutu boyito",
+ "nosuchactiontext": "Huhutu u hepohile lo URL ja valid.\nYi'o lotalawa lopomaso lo URL, meyalo lodudu'a pranala u ja banari.\nUtiye olo kira-kira tuwotiyo woluwo bug to pilaakasi u hepomake {{SITENAME}}",
+ "nosuchspecialpage": "Diya'a halaman istimewa boyito",
+ "nospecialpagetext": "<molotolo>Yi'o hemohile halaman istimewa u ja sah.<molotolo>\n\nDaputari halaman istimewa mowali bilehela to [[Special:SpecialPages| {{int:specialpages}}]]",
+ "error": "Lotaalawa",
+ "databaseerror": "Lotaalawa tuwango data",
+ "databaseerror-text": "Ma tilala tuwawu basis kueri.\nUtiya kira-kira tuwotiyo woluwo bug to pilaakasi moluluhi'o.",
+ "databaseerror-textcl": "Ma tilala tuwawu basis kueri.",
+ "databaseerror-query": "Kueri $1",
+ "databaseerror-function": "Huna: $1",
+ "databaseerror-error": "Lotaalawa: $1",
+ "laggedslavemode": "<strong>Warning:</strong> Halaman kira ja o tuwanga lo'ubawa bohu",
+ "readonly": "Basis data unti-unti",
+ "enterlockreason": "Masowa alasani longunti wawu omoluwa u'unti hu'oolo",
+ "missingarticle-rev": "(iluba#1:$1)",
+ "missingarticle-diff": "(Beda:$1,$2)",
+ "readonly_lag": "Basis data ma iluntiya otomatis to'u basis data sekunder hemosinkronisasi wolo basis data utama",
+ "nonwrite-api-promise-error": "Lunggongo HTTP 'Promise-Non-Write-API-Action' ma yilawo dabo hihile pilohutu ode modul loluladu API.",
+ "internalerror": "Tilala todelomiyo",
+ "internalerror_info": "Tilala todelomiyo:$1",
+ "internalerror-fatal-exception": "Ja wayitiyo fatal mengetik \"$1\"",
+ "filecopyerror": "Jamowali mohemi tuwango \"$1\" de \"$2\"",
+ "filerenameerror": "Jamowali moganti tanggulo tuwango \"$1\" de \"$2\"",
+ "filedeleteerror": "Jamowali moluluta tuwango \"$1\"",
+ "directorycreateerror": "Jamowali mohutu direktori \"$1\"",
+ "directoryreadonlyerror": "Direktori \"$1\" bo pobaca.",
+ "directorynotreadableerror": "Direktori \"$1\" jamowali pobaca.",
+ "filenotfound": "Jamotapu tuwango \"$1\"",
+ "unexpected": "Nilai ja o'aata: \"$1\"=\"$2\".",
+ "formerror": "Tilala: Ja mowali molawo formulir",
+ "badarticleerror": "Huhutu boti ja mowali pohutuwola to halaman boti.",
+ "cannotdelete": "Halaman meyalo berkas \"$1\" jamowali lulutolo.\nKira-kira ma yiluluto tawu weewo.",
+ "cannotdelete-title": "Ja mowali moluluta halaman \"$1\"",
+ "delete-hook-aborted": "Moluluto bilatali lo kokayito.\nDiyaalu kataraangani.",
+ "no-null-revision": "Ja mowali mohutu revisi noolo bohu lo halaman \"$1\"",
+ "badtitle": "Judul moleeto",
+ "badtitletext": "Judul halaman pilohile ja sah, ja otuwa, meyalo judul wolota lo bahasa meyalo wolota lo wiki u tilala lo humbuto.\nUtiye kira otuwa tuwawu meyalo limbata watade u ja mowali pomake to judul.",
+ "title-invalid-empty": "Judul halaman pilohile ja otuwa meyalo bo otuwa tuwawu huwali lo tanggulo.",
+ "title-invalid-utf8": "Judul halaman pilohile otuwa ayita UTF-8 u ja sah.",
+ "title-invalid-interwiki": "Judul otuwa wumbuta wolota lo wiki u ja mowali pomake to judul.",
+ "title-invalid-talk-namespace": "Judul situs pilohile letalu ode halaman posilitawa u diya'a.",
+ "title-invalid-characters": "Judul halaman pilohile otuwa watade ja sah: $1.",
+ "title-invalid-too-long": "Judul halaman u pilohile ma tilalalebe haya'iyo. Ja mowali limbata $1 {{PLURAL:$1|bita}} momake kode UTF-8.",
+ "title-invalid-leading-colon": "Judul halaman u pilohile tilumula lo tuwoto titik duluwo u ja sah.",
+ "querypage-no-updates": "Hemopobohu lo data to halaman botiye donggo pilateyaliyo. Data u woluwo masatiya ja muatiyolo.",
+ "viewsource": "Bilohi bungoliyo",
+ "viewsource-title": "Bilohi bungoliyo $1",
+ "actionthrottled": "Huhutu babaatasi",
+ "protectedpagetext": "Halaman botiye ma iluntiya alihu diya'a ta momoli'o meyalo huhutu uweewo.",
+ "viewsourcetext": "Yi'o mowali momilohu wawu mohemi monto bungoliyo lo halaman botiye.",
+ "viewyourtext": "Yi'o mowali momilohu wawu mohemi bungo monto <strong>biloli'umu</strong> to halaman botiye.",
+ "namespaceprotected": "Yi'o ja o haku momoli'a halaman botiye to <strong>$1</strong> huwali tanggulo.",
+ "mycustomcssprotected": "Yi'o ja o iijini monguba halaman CSS boti.",
+ "mycustomjsprotected": "Yi'o ja o iijini monguba halaman JavaScript boti.",
+ "myprivateinfoprotected": "Yi'o ja o iijini monguba informasi pribadi olemu.",
+ "mypreferencesprotected": "Yi'o ja o iijini monguba preferensi olemu.",
+ "ns-specialprotected": "Halaman spesial ja mowali ubaalo.",
+ "titleprotected": "Judul botiya daha-daya monto ta mohutu oleh [[User:$1|$1]].\nAlasani u yilohiliyo de'uwito <em>$2</em>.",
+ "invalidtitle-knownnamespace": "Judul u ja sah wolo huwali tanggulo \"$2\" wawu teks \"$3\"",
+ "exception-nologin": "Diipo tilumuwoto log",
+ "exception-nologin-text": "Toduwolo tumuwoto log alihu mowali mokalaja to halaman botiye meyalo huhutu botiye.",
+ "exception-nologin-text-manual": "Toduwolo tumuwoto alihu mowali mohutu halaman meyalo huhutu uweewo.",
+ "virus-badscanner": "Tilala konfigurasi: pemindai virus ja iloonuhe: ''$1''",
+ "virus-scanfailed": "Pemindaian ja lowali (kode $1)",
+ "virus-unknownscanner": "antivirus ja'otaawa",
+ "cannotlogoutnow-title": "Ja mowali lumuwalo masatiya",
+ "cannotlogoutnow-text": "Lumuwalo log ja mowali to'u mopohuna $1.",
+ "welcomeuser": "Toduwoolo, $1!",
+ "welcomecreation-msg": "Akun olemu ma pilohutu. Ja lipata mongaturu konfigurasi [[Special:Preferences|preferensi {{SITENAME}}]] olemu.",
+ "yourname": "Ta ohu'uwo tanggulo",
+ "userlogin-yourname": "Ta ohu'uwo tanggulo",
+ "userlogin-yourname-ph": "Tuwota ta ohu'uwo lo tanggulo",
+ "createacct-another-username-ph": "Tuwota ta ohu'uwo lo tanggulo",
+ "yourpassword": "Tahe u'unti",
+ "userlogin-yourpassword": "Tahe u'unti",
+ "userlogin-yourpassword-ph": "Tuwota tahe u'unti",
+ "createacct-yourpassword-ph": "Tuwota tahe u'unti",
+ "yourpasswordagain": "Ulangiya tahe u'unti",
+ "createacct-yourpasswordagain": "Konfirmasi tahe u'unti",
+ "createacct-yourpasswordagain-ph": "Tuwota pooli tahe u'unti",
+ "remembermypassword": "Eelayi tahe u'unti'u to komputer botiye (to delomo $1 {{PLURAL:$1|huyi}})",
+ "userlogin-remembermypassword": "Hulima'o wa'u tuwo-tuwoto",
+ "userlogin-signwithsecure": "Popohunawa server aamani",
+ "cannotloginnow-title": "Ja mowali tumuwoto log sa'ati botiya",
+ "cannotloginnow-text": "Tumuwoto log ja mowali to'umopohuna $1.",
+ "yourdomainname": "Domain Ulemu:",
+ "password-change-forbidden": "Ja mowali momoli'a tahe u'unti to wiki botiye.",
+ "login": "Tumuwoto log",
+ "login-security": "Po'opatata tita yi'o",
+ "nav-login-createaccount": "Tumuwoto log / mohutu akun",
+ "userlogin": "Tumuwoto log / mohutu akun",
+ "userloginnocreate": "Tumuwoto log",
+ "logout": "Lumuwalo log",
+ "userlogout": "Lumuwalo log",
+ "notloggedin": "Diipo tilumuwoto log",
+ "userlogin-noaccount": "Diipo o akun",
+ "userlogin-joinproject": "Motiwayito {{SITENAME}}",
+ "nologin": "Diipo o akun? $1",
+ "nologinlink": "Mohutu akun bohu",
+ "createaccount": "Mohutu akun",
+ "gotaccount": "Ma yilohutu akun? $1",
+ "gotaccountlink": "Tumuwoto log",
+ "userlogin-resetlink": "Ilolipata detail habari tumuwotumu?",
+ "userlogin-resetpassword-link": "Ilolipata tahe u'unti?",
+ "userlogin-helplink2": "Wubodu tumuwoto log",
+ "userlogin-loggedin": "Yi'o ma tilumuwoto odelo {{GENDER:$1|$1}}\nPopohunawa formulir formulir to tibawa botiye odelo pengguna uweewo.",
+ "userlogin-reauth": "Yi'o musti tumuwota pooli u mopopatato yi'o odelo {{GENDER:$1|$1}}",
+ "userlogin-createanother": "Mohutu akun uweewo",
+ "createacct-emailrequired": "Alaamati surel",
+ "createacct-emailoptional": "Alamat tuladu email (paralu tuwangalo)",
+ "createacct-email-ph": "Tuwanga alamat tuladu email",
+ "createacct-another-email-ph": "Tuwanga alamat tuladu email",
+ "createaccountmail": "Popohunawa tahu u'unti ja kakali wawu lawola ode tuladu elektronik u pilohile",
+ "createacct-realname": "Tanggula banari (tulawoto)",
+ "createaccountreason": "Alaasani",
+ "createacct-reason": "Alaasani",
+ "createacct-reason-ph": "Longola Y'io mohutu akun uweewo.",
+ "createacct-reason-help": "Tahuli u pilopobilohu to delomo log mohutu akun",
+ "createacct-submit": "Mohutu akun bohu",
+ "createacct-another-submit": "Mohutu akun",
+ "createacct-continue-submit": "Turusi mohutu akun",
+ "createacct-another-continue-submit": "Turusi mohutu akun",
+ "createacct-benefit-heading": "{{SITEMAP}} pilohutu lotawu odelo yi'o",
+ "createacct-benefit-body1": "{{PLURAL:$1|momoli'o}}",
+ "createacct-benefit-body2": "{{PLURAL:$1|halaman}}",
+ "createacct-benefit-body3": "{{PLURAL:$1|kontributor}}pulitiyo",
+ "badretype": "Tahe u'unti pilopotuwoto tilala.",
+ "usernameinprogress": "Mohutu akun wolo tanggula botiye donggo na'o-na'o. Wulatipo ngope'e.",
+ "userexists": "Ta ohu'uwo lo tanggulo pilopotuwoto ma pilomake lo tawu. Toduwolo molulawota tanggula uweewo.",
+ "loginerror": "Lotaalawa tilumuwato log",
+ "createacct-error": "Lotaalawa lohutu akun",
+ "createaccounterror": "Diya mowali mohutu akun: $1",
+ "nocookiesnew": "Akun pengguna ma pilohutu, dabo Yi'o diipo tilumuwoto. {{SITENAME}} popohunawa kuki log pengguna.\nToduwolo mopo'aktif wawu tumuwota pooli wolo tanggulu ta ohu'uwo wawu tahe u'unti.",
+ "noname": "Tanggulo ta ohu'uwo u pilopotuwotumu ja sah.",
+ "loginsuccesstitle": "Ma tilumuwoto",
+ "loginsuccess": "<strong>Yi'o ma tilumuwoto to {{SITENAME}} odelo \"$1\".</strong>",
+ "nosuchuser": "Diya'a ta ohu'uwo wolo tanggula \"$1\".\nTanggulo ta ohu'uwo mopohiihede hurupu kiki'o wawu damango hurupu. Parakisayi po'olo eja'an meyalo [[Special:CreateAccount|mohutu akun bohu]].",
+ "nosuchusershort": "Diya'a ta ohu'uwo wolo tanggula \"$1\".\nParakisayi eja'an olemu.",
+ "nouserspecified": "Yi'o musti mopotuwoto tanggulo ta ohu'uwo.",
+ "login-userblocked": "Ta ohu'uwo botiye diblokir. Ja mowali tumuwoto.",
+ "wrongpassword": "Tahe u'unti tilala. \nToduwoolo mocoba pe'eentapo.",
+ "wrongpasswordempty": "Yi'o diipo lopotuwoto tahe u'unti.\nToduwoolo mocoba pe'eentapo.",
+ "passwordtooshort": "Tahu u'unti musti mohelu {{PLURAL:$1|1 karakterter|$1 karakter}}.",
+ "passwordtoolong": "Tahe u'unti ja mowali limbata to {{PLURAL:$1|1 karakter|$1 karakter}}.",
+ "passwordtoopopular": "Tahe u'unti biasa u ja mowali pomake. Toduwoolo molulawota u ngopohiya.",
+ "password-name-match": "Tahe u'unti musti hihihede monto tanggulo ta ohu'uwo.",
+ "password-login-forbidden": "Tanggulo ta ohu'uwo wau tahe u'unti botiye ja mowali pomake.",
+ "mailmypassword": "Popobohuwa tahe u'unti",
+ "passwordremindertitle": "Taahe u'unti ja kakali monto {{SITENAME}}",
+ "passwordremindertext": "Tawu ngota (meyalo Yi'o, lonto alamat IP $1) mohile tahe u'unti bohu {{SITENAME}} ($4). Tahe u'unti ja kakali lo ta ohu'uwo \"$2\" ma pilohutu wawu ma pilopowali \"$3\". \nWonu Yi'o ta lohile utiye, Yi'o paralu tumuwoto log wawu molulawota tahe u'unti bohu masatiya. Tahe u'unti ja kakali ma mololante to delomo wakutu {{PLURAL:$5|ngohuyi|$5 huyi}}.\n\nWonu Yi'o morasa ja lohile tahe u'unti bohu, meyalo ma lo eela tahe u'unti wawu debo mopphuna leeto, pelehiyama'o tahuli botiya wawu debo mopohuna tahe u'unti muloolo.",
+ "noemail": "Diya'a alamat tuladu elektronik u tula-tulade to ta ohu'uwo botiye \"$1\".",
+ "noemailcreate": "Yi'o musti moposadiya alamat tuladu elektronik u sah.",
+ "passwordsent": "Tahe u'unti bohu ma yilawo ode alamat tuladu elektronik u to daputari lo \"$1\".\nToduwoolo tumuwoto wonu ma lololimo tulade boyito.",
+ "blocked-mailpassword": "Alamat IP olemu ma diblokir monto u momoli'o. Modaha u mopotalawa, Yi'o diipo mowali mopobohu lo tahe u'unti moli alamat IP botiye.",
+ "eauthentsent": "Tuladu elektronik u pokonfirmasi ma yilawo ode alamat lo tuladu. To'udiipo tuladu elektronik uweewo lawololo ode akun botiye, Yi'o musti modudu'a potunu to delomo tuladu boyito, u mokonformasi tutu liyo tutu alamat boyito banari ulemu.",
+ "throttled-mailpassword": "Tahe u'unti bohu ma yilawo to delomo {{PLURAL:$1|$1 jam}}botiye.\nModaha ta mopotalawa, bo tuwawu tahe u'unti u lawololo timi'idu {{PLURAL:$1|jam|$1 jam}}.",
+ "mailerror": "Tilala lo lawo tuladu elektronik:$1",
+ "emailauthenticated": "Alamat tuladu elektronikmu ma dikonfirmasi to $3, $2.",
+ "emailnotauthenticated": "Alamat tuldu elektronikmu diipo dikonformasi.\nWonu diipo dikonfirmasi, Yi'o dila ta mololimo tulade elektronik monto fitur botiya.",
+ "noemailprefs": "Yi'o musti mopomasu alamat surel to preferensimu alihu mowali mopohuna lo fitur-fitur botiye.",
+ "emailconfirmlink": "Konfirmasi alamat surel olemu",
+ "invalidemailaddress": "Alamat surel botiye ja mowali tolimolo sababu tatalawa format.\nHarapuwolo mopotuwoto alamat surel wolo format u banari meyalo lawodima'o uwito.",
+ "cannotchangeemail": "Alamat surel akun botiye ja mowali boli'ola to wiki botiya.",
+ "emaildisabled": "Situs botiye ja mowali molawo surel.",
+ "accountcreated": "Akun ma pilohutu",
+ "accountcreatedtext": "Akun ta ohu'uwo lo [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|lo'iya]]) ma pilohutu.",
+ "createaccount-title": "Ma yilohutu akun lo {{SITENAME}}",
+ "createaccount-text": "Tawu ngota ma lohutu akun lopohuna alamat surel olemu {{SITENAME}} ($4) wolo tanggulo \"$2\" wawu tahe u'unti \"$3\". Yi'o musti tumuwoto wawu momoli'a tahe u'unti masatiya.\n\nPelehiya ma'o tahuli wonu akun botiye pilohutu sababu u tilala.",
+ "login-throttled": "Yi'o ma tilala lebe he mocoba tumuwoto log.\nToduwoolo mohuato $1 to'udiipo mocoba pooli.",
+ "login-abort-generic": "Yi'o ja lowali tilumuwoto - Pilopobatali",
+ "loginlanguagelabel": "Bahasa: $1",
+ "pt-login": "Tumuwoto log",
+ "pt-login-button": "Tumuwoto log",
+ "pt-createaccount": "Mohutu akun",
+ "pt-userlogout": "Lumuwalo log",
+ "botpasswords-label-create": "Mohutu",
+ "botpasswords-label-update": "Mopobohu",
+ "botpasswords-label-cancel": "Bataliya",
+ "botpasswords-label-delete": "Luluta",
+ "passwordreset": "Ubawa tahe u'unti",
+ "bold_sample": "Teks botiye ma cetakiyolo mohulodu",
+ "bold_tip": "Teks mohulodu",
+ "italic_sample": "Teks botiye ma cetakiyolo yinti-yintili",
+ "italic_tip": "Teks yinti-yintili",
+ "link_sample": "Judul wumbuta",
+ "link_tip": "Wumbuta to delomiyo",
+ "extlink_sample": "http://www.example.com judul wumbuta",
+ "extlink_tip": "Wumbuta to diluwari (eelayi awalan http://)",
+ "headline_sample": "Judul teks",
+ "headline_tip": "Lenggota 2 Judul",
+ "nowiki_sample": "Tuwota teks u ja format teeye",
+ "nowiki_tip": "Pelehiya moformat wiki",
+ "image_tip": "Dembinga berkas",
+ "media_tip": "Wumbuta lo berkas",
+ "sig_tip": "Pali lo ulu'umu wawu tuwoto wakutu",
+ "hr_tip": "Garisi bula-bulawahu",
+ "summary": "Limbu'o",
+ "minoredit": "Utiye biloli'o ngo'idi",
+ "watchthis": "Dahayi halaman botiye",
+ "savearticle": "Tahuwa halaman",
+ "showpreview": "Bilohi pratayang",
+ "showdiff": "Popobilohe u loboli'a",
+ "anoneditwarning": "<strong>Mopo'eela:</strong> Yi'o diipo tilumuwo. Alamat IP olemu ma ontonga lo tawu daata wonu yi'o momoli'o. Wonu Yi'o <strong>[$1 tumuwoto log]</strong> meyalo <strong>[$2 mohutu akun]</strong>, u biloli'umu madiatribusikan ode tanggulumu, wolo huna uweewoliyo.",
+ "loginreqlink": "tumuwoto log",
+ "newarticletext": "Yi'o lodudu'a wumbuta ode halaman diya'a. \nWonu mohutu halaman botiye, ketik tuwango halaman to kotak to tibawa botiye (bilohi [$1 halaman wubodu] ode habari wumbutiyo). \nWonu Yi'o ja sangaja tilumuwota ode halaman botiye, kutiya tombol <strong>mohuwalingo</strong>.",
+ "noarticletext": "Sa'ati botiye diya'a teks to halaman botiye.\nYi'o mowali [[Special:Search/{{PAGENAME}}|mololohu judul halaman botiye]] to halaman-halaman uweewo, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mololohu log a'ayita], meyalo [{{fullurl:{{FULLPAGENAME}}|action=edit}} mohutu halaman botiye]</span>.",
+ "noarticletext-nopermission": "!Sa'ati botiye diya'a teks to halaman boptiye.\nYi'o mowali [[Special:Search/{{PAGENAME}}|mololohu judul halaman botiye]] to halaman-halaman uweewo, meyalo <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mololohu log a'ayita]</span>, dabo Yi'o ja o ijin mohutu halaman botiye.",
+ "editing": "Momoli'o $1",
+ "creating": "Mohutu $1",
+ "editingsection": "Momoli'o $1 (tayadu)",
+ "templatesused": "{{PLURAL:$1|Template}} pilopohuna to halaman botiye:",
+ "template-protected": "(he dahalo)",
+ "template-semiprotected": "(dahalo-ngowa)",
+ "hiddencategories": "Halaman botiye woluwo anggota {{PLURAL:$1|1 kategori wanto-wanto'o $1}}:",
+ "permissionserrorstext-withaction": "Yi'o ja haku akses $2, sababu {{PLURAL:$1|alasani}} botiya:",
+ "moveddeleted-notice": "Halaman botiye ma yiluluto.\nSebagai referensi, botiya log piloluluta wawu piloheyiya halaman botiye.",
+ "viewpagelogs": "Bilohi log lo halaman botiye",
+ "currentrev-asof": "Biloli'o pulitiyo to $1",
+ "revisionasof": "Biloli'o to $1",
+ "revision-info": "Biloli'o per $1 oleh {{GENDER:$6|$2}}$7",
+ "previousrevision": "Biloli'o yilaluma'o",
+ "nextrevision": "Biloli'o lapatiyoma'o →",
+ "currentrevisionlink": "Biloli'o pulitiyo",
+ "cur": "mst",
+ "last": "diipo",
+ "rev-delundel": "popobilohe/wanto'a",
+ "history-title": "Riwayati lo'u loboli'a lonto \"$1\"",
+ "difference-title": "$1 hihede revisi",
+ "lineno": "Baarisi $1:",
+ "editundo": "pohuwalinga",
+ "diff-multi-sameuser": "({{PLURAL:$1|$1 revisi wolota}} pilohutu lo tawu ngota ja pilopobilohu)",
+ "searchresults": "U yilotapu",
+ "searchresults-title": "U yilotapu lololohe \"$1\"",
+ "prevn": "{{PLURAL:$1|$1}} to'udiipo",
+ "nextn": "{{PLURAL:$1|$1}} lapatiyoma'o",
+ "nextn-title": "$1 {{PLURAL:$1|hasili}}lapatiyoma'o",
+ "shown-title": "Popobilohe $1 {{PLURAL:$1|haasili}} per halaman",
+ "viewprevnext": "Bilohi ($1 {{int:pipe-separator}} $2) ($3)",
+ "searchmenu-new": "<strong>mohutu halaman \"[[:$1]]\" to wiki botiya! {{PLURAL:$2|0=Bilohi halaman u yilotapu yilolohumu.|Bilohi hasili u yilotapu to'u yilolohu}}",
+ "searchprofile-articles": "Tuwango halaman",
+ "searchprofile-images": "Multimedia",
+ "searchprofile-everything": "Nga'amila",
+ "searchprofile-advanced": "Wumbuto",
+ "searchprofile-articles-tooltip": "Mololohu to $1",
+ "searchprofile-images-tooltip": "Mololohe berkas",
+ "searchprofile-everything-tooltip": "Mololohe nga'amila tuwango situs (wolo halaman polo'iyalo)",
+ "searchprofile-advanced-tooltip": "Mololohu to huwali lo tanggulo biasa",
+ "search-result-size": "$1 ({{PLURAL:$2|1 tahe|$2 tahe}})",
+ "search-redirect": "(mopobale $1)",
+ "search-section": "(tayadu) $1",
+ "search-suggest": "Patujumu yito:$1",
+ "searchall": "nga'amila",
+ "search-showingresults": "{{PLURAL:$4|hASIL <strong>$1</strong> of <strong>$3</strong>|Hasil <strong>$1 - $2</strong> lonto <strong>$3</strong>}}",
+ "search-nonefound": "Diya'a hasili mohumayawa lo kriteria",
+ "mypreferences": "Preperensi",
+ "right-writeapi": "Mopohuna API moluladu",
+ "newuserlogpage": "Log ta ohu'uwo bohu",
+ "enhancedrc-history": "riwayati",
+ "recentchanges": "Boheli loboli'a mola",
+ "recentchanges-legend": "Tulawotolo boheli loboli'a mola",
+ "recentchanges-summary": "Mololohe u yilo'ubawa bohu to halaman wiki botiye.",
+ "recentchanges-label-newpage": "Momoli'a utiye mohutu halaman bohu",
+ "recentchanges-label-minor": "Utiye biloli'o ngo'idi",
+ "recentchanges-label-bot": "Lomoli'a utiye kilaraja lo bot",
+ "recentchanges-label-unpatrolled": "U biloli'a botiye diipo pilatroli",
+ "recentchanges-label-plusminus": "Loboli'o tu'udu halaman boti to delomo bita",
+ "recentchanges-legend-heading": "<strong>Keterangan:</strong>",
+ "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (bilohi olo [[Special:NewPages|list of new pages]])",
+ "rclistfrom": "Popobilohe u loboli'a lonto $2, $3",
+ "rcshowhideminor": "$1 biloli'o ngo'idi",
+ "rcshowhideminor-show": "Popobilohe",
+ "rcshowhideminor-hide": "Wanto'a",
+ "rcshowhidebots": "$1 bot",
+ "rcshowhidebots-show": "Popobilohe",
+ "rcshowhidebots-hide": "Wanto'a",
+ "rcshowhideliu": "$1 ta ohu'uwo to daputari",
+ "rcshowhideliu-hide": "Wanto'a",
+ "rcshowhideanons": "$1 biloli'o lo tawu weewo",
+ "rcshowhideanons-show": "Popobilohe",
+ "rcshowhideanons-hide": "Wanto'a",
+ "rcshowhidemine": "$1 biloli'u'u",
+ "rcshowhidemine-show": "Popobilohe",
+ "rcshowhidemine-hide": "Wanto'a",
+ "rclinks": "Popobilohe $1 u yilo'boli'a pulitiyo to delomo $2 dulahu pulitiyo<br />$3",
+ "diff": "ngopohiya",
+ "hist": "riwayati",
+ "hide": "Wanto'a",
+ "show": "Popobilohe",
+ "minoreditletter": "k",
+ "newpageletter": "B",
+ "boteditletter": "b",
+ "rc-change-size-new": "$1 {{PLURAL:$1|bita}} lapato biloli'o",
+ "recentchangeslinked": "Loboli'a wayitiyo",
+ "recentchangeslinked-toolbox": "Loboli'o wayitiyo",
+ "recentchangeslinked-title": "Loboli'a a'aayita wolo $1",
+ "recentchangeslinked-summary": "Utiye daputari lo'ubawa to halaman a'ayita wolo halaman tuwawu (meyalo tayadu to kategori tuwawu)\nHalaman to [[Special:Watchlist|he'awasiyamu]] ontonga <strong>cetakiya mohulodu</strong>.",
+ "recentchangeslinked-page": "Tanggulo halaman:",
+ "recentchangeslinked-to": "Poppobilohe loboli'a to halaman wayitiyo wolo halaman hepoposadiyalo",
+ "upload": "Detohe berkas",
+ "filedesc": "Limbu'o",
+ "license-header": "Tayadu lisensi",
+ "imgfile": "berkas",
+ "file-anchor-link": "Berkas",
+ "filehist": "Riwaayati lo berkas",
+ "filehist-help": "Klik to tanggal/wakutu momilohe berkas to saa'ati botiye.",
+ "filehist-current": "baharu",
+ "filehist-datetime": "Tanggal/Wakutu",
+ "filehist-thumb": "Kiki'o",
+ "filehist-thumbtext": "u kiki'o versi lo $1",
+ "filehist-user": "Ta ohu'uwo",
+ "filehist-dimensions": "Dimensi",
+ "filehist-comment": "Lo'iya",
+ "imagelinks": "Berkas u pilopohuna",
+ "linkstoimage": "{{PLURAL:$1|halaman lapatiyoma'o}} o wumbuta ode berkas botiye:",
+ "nolinkstoimage": "Diya'a halaman u owumbuta ode berkas botiye",
+ "sharedupload-desc-here": "Berkas botiye lonto $1 wawu hepohunaliyo to poroyek uweewo.\nDeskripsi lonto [$2 halaman deskripsiliyo] woluwo to tibawa botiya.",
+ "upload-disallowed-here": "Yi'o diila mowali modeehe berkas botiye",
+ "randompage": "Halaman totonula",
+ "nbytes": "$1 {{PLURAL:$1|bita}}",
+ "nmembers": "$1 {{PLURAL:$1|tuwango}}",
+ "newpages": "Halaman bohu",
+ "pager-older-n": "{{PLURAL:$1|$1 mohihewo}}",
+ "booksources": "Bungo buku",
+ "booksources-search-legend": "Lolohe to bungo lo buku",
+ "booksources-search": "Lolohe",
+ "log": "Log",
+ "allarticles": "Nga'amila halaman",
+ "allpagessubmit": "Ntali",
+ "categories": "Kategori",
+ "mywatchlist": "Daputari he'awasiyalo",
+ "watch": "Dahayi",
+ "dellogpage": "Log loluluto",
+ "rollbacklink": "wuwalinga",
+ "rollbacklinkcount": "pohuwalinga $1 {{PLURAL:$1|biloli'o}}",
+ "protectlogpage": "Log mopo'aamani",
+ "namespace": "Huwali lo tanggulo",
+ "invert": "Pohuwalinga tilulawoto",
+ "tooltip-invert": "Centang kotak botiye u mopowanto'o halaman yiloboli'a to delomo huwali lo tanggulo tilulawoto (wawu huwali lo tanggulo a'ayita wanu dicentang)",
+ "namespace_association": "Huwali lo tanggulo a'aayita",
+ "tooltip-namespace_association": "Centang halaman botiye u mopowayito huwali lo tanggulo lo'iyawa meyalo subjek u a'ayita wolo huwali lo tanggulo u tilulawoto.",
+ "blanknamespace": "Bungaliyo",
+ "contributions": "Kontribusi {{GENDER:$1|Ta ohu'uwo}}",
+ "mycontris": "Kontribusi",
+ "anoncontribs": "Kontribusi",
+ "month": "Lonto hulalo (wawu to'udiipo)",
+ "year": "Lonto taawunu (wawu to'udiipo)",
+ "whatlinkshere": "Wumbuta",
+ "whatlinkshere-title": "Halaman botiye o wumbuta ode \"$1\"",
+ "whatlinkshere-page": "Halaman",
+ "linkshere": "Halaman botiye woluwo wumbuta ode <strong>[[:$1]]<strong>:",
+ "isredirect": "halaman pilobaleyalo",
+ "istemplate": "tranklusi",
+ "isimage": "wumbuta lo berkas",
+ "whatlinkshere-prev": "{{PLURAL:$1|to'udiipo $1}}",
+ "whatlinkshere-next": "{{PLURAL:$1|lapatiyo $1}}",
+ "whatlinkshere-links": "← wumbuta",
+ "whatlinkshere-hideredirs": "$1 mopobale",
+ "whatlinkshere-hidetrans": "$1 tansklusi",
+ "whatlinkshere-hidelinks": "$1 wumbuta",
+ "whatlinkshere-filters": "U'ayahu",
+ "blocklink": "tangguwalo",
+ "contribslink": "kontrib",
+ "movelogpage": "Log piloheyiya",
+ "export": "Ekspor halaman",
+ "thumbnail-more": "Po'odamanga",
+ "tooltip-pt-userpage": "Halaman {{GENDER:|Yi'o ta ohu'uwo}}",
+ "tooltip-pt-mytalk": "Halaman {{GENDER:|posilitamu}}",
+ "tooltip-pt-preferences": "Preferensi{{GENDER:|Yi'o}}",
+ "tooltip-pt-watchlist": "Daputari halaman u he'awasiyalo",
+ "tooltip-pt-mycontris": "Daputari kontribusi {{GENDER:|Yi'o}}",
+ "tooltip-pt-login": "Yi'o popoyingowaliyo tumuwoto log, openu utiye ja wajibu",
+ "tooltip-pt-logout": "Lumuwalo log",
+ "tooltip-pt-createaccount": "Yi'o popoyingowaliyo mohutu akun wawu tumuwoto log; openu utiye ja wajibu",
+ "tooltip-ca-talk": "Tombilu tomimbihu tuwango halaman",
+ "tooltip-ca-edit": "Boli'a halaman botiye",
+ "tooltip-ca-addsection": "Mulai tayade bohu",
+ "tooltip-ca-viewsource": "Halaman botiye daha-daha. Yi'o bo mowali momilohe bungo",
+ "tooltip-ca-history": "Biloli'o pulitiyo to halaman botiye",
+ "tooltip-ca-move": "Heyiya halaman botiye",
+ "tooltip-ca-watch": "Popoduhengama'o halaman botiye to daputari he'awasiyalo",
+ "tooltip-search": "Lolohe {{SITENAME}}",
+ "tooltip-search-go": "Lolohe halaman tuwawu wolo tanggula delo odiye wonu woluwo",
+ "tooltip-search-fulltext": "Lolohe halaman o tulade odiye",
+ "tooltip-p-logo": "Bilohi halaman bungaliyo",
+ "tooltip-n-mainpage": "Bilohi halaman bungaliyo",
+ "tooltip-n-mainpage-description": "Bilohi halaman bungaliyo",
+ "tooltip-n-portal": "Tomimbihu poroyek, wolo u mowali pohutuwomu, to'utonu mololohe u tuwawu",
+ "tooltip-n-currentevents": "Lolohe habari tomimbihu u yilowali baharu",
+ "tooltip-n-recentchanges": "Daputari boheli loboli'a mola to delomo wiki botiye",
+ "tooltip-n-randompage": "Popobilohe totonula halaman",
+ "tooltip-n-help": "Taambati pololohela wubodu",
+ "tooltip-t-whatlinkshere": "Daputari nga'amila halaman wiki owumbuta ode halaman botiye",
+ "tooltip-t-recentchangeslinked": "Boheli loboli'a mola to halaman owumbuta ode halaman botiye",
+ "tooltip-feed-atom": "Paalo atom ode halaman botiya",
+ "tooltip-t-contributions": "Daputari kontribusi {{GENDER:$1|ta ohu'uwo botiye}}",
+ "tooltip-t-upload": "Detohe berkas-berkas",
+ "tooltip-t-specialpages": "Daputari nga'amila halaman spesial",
+ "tooltip-t-print": "Persi ciletaki halaman botiye",
+ "tooltip-t-permalink": "Wumbuta kakali u mopo'opiyohe halaman botiye",
+ "tooltip-ca-nstab-main": "Bilohi tuwango halaman",
+ "tooltip-ca-nstab-user": "Bilohi halaman pengguna",
+ "tooltip-ca-nstab-special": "Utiye halaman istimewa, wawu ja mowali boli'olo",
+ "tooltip-ca-nstab-project": "Bilohi halaman poroyek",
+ "tooltip-ca-nstab-image": "Bilohi berkas lo halaman",
+ "tooltip-ca-nstab-template": "Bilohi template",
+ "tooltip-ca-nstab-category": "Bilohi kategori halaman",
+ "tooltip-save": "Tahuwa u biloli'umu",
+ "tooltip-preview": "Bilohipo u biloli'umu. Popopasiya utiye to'u diipo molahu.",
+ "tooltip-diff": "Bilohi u loboli'o pilohutumu",
+ "tooltip-rollback": "\"Wuwalingo\" lopobatali u pilo'opiyohu to halaman botiye ode kontributor pulitiyo pe'enta lo klik.",
+ "tooltip-undo": "\"wuwalingo\" lopobatali u biloli'a botiye wawu lomu'o kotak momoli'o wolo mode pratayang. Alasani mowali duhengalo to kotak limbu-limbu'o.",
+ "tooltip-summary": "Tuwota tulade limbu-limbu'o",
+ "simpleantispam-label": "Momarakisa anti-spam.\n<strong>kekeya</strong> tuwangalo!",
+ "pageinfo-toolboxlink": "Halaman habari",
+ "previousdiff": "← Biloli'o to'udiipo",
+ "nextdiff": "Biloli'o lapatiyoma'o →",
+ "file-info-size": "$1 x $2 piksel, tu'udu berkas:$3, MIME tipe: $4",
+ "file-nohires": "Diya'a resolusi damango",
+ "svg-long-desc": "Berkas SGV, nominal $1 x $2 piksel, damango berkas:$3",
+ "show-big-image": "Berkas asli",
+ "show-big-image-preview": "Tu'udu lo'u diipo mopobilohu: $1",
+ "show-big-image-other": "{{PLURAL:$2|resolusi}} uweewo:$1",
+ "show-big-image-size": "$1 x $2 piksel",
+ "metadata": "Metadata",
+ "metadata-help": "Berkas botiya otuwa habari duhengiyo u kira lonto kamera digital meyalo pemindai u pilokalaja meyalo mendigitalisasi berkas.\nWonu berkas botiye ma yiloboli'a, katarangani u woluwo kira ja mopopatato dudutu lo habari lo teekeni u ma yiloboli'a botiye.",
+ "metadata-fields": "Tanggalo metadata lo gambari to tahuli ma popotuwotolo to bibilohu halaman gambari to'u tabel metadata po'okiki'olo.\nData uweewo ma wanto'olo odelo dudelo.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+ "exif-orientation": "Orientasi",
+ "exif-xresolution": "Resolusi bula-bulawahu",
+ "exif-yresolution": "Resolusi bula-bulalingo",
+ "exif-datetime": "Tanggal wawu wakutu lomoli'o berkas",
+ "exif-make": "Pabiriki lo kamera",
+ "exif-model": "Model lo kamera",
+ "exif-software": "Pilakasi moluluhi'o",
+ "exif-exifversion": "Versi exif",
+ "exif-colorspace": "Ruang lo laku",
+ "exif-datetimeoriginal": "Tanggal wawu wakutu pilohutuwa data",
+ "exif-datetimedigitized": "Tanggal wawu wakutu digitalisassi",
+ "exif-orientation-1": "Normal",
+ "namespacesall": "nga'amila",
+ "monthsall": "nga'amila",
+ "signature": "[[{{ns:user}}:$1|$2]]\n([[{{ns:user_talk}}:$1|bisala]])",
+ "specialpages": "Halaman Spesial",
+ "tag-filter": "[[Special:Tags|Tag]]filter:",
+ "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag}}]]: $2)",
+ "logentry-delete-delete": "$1 {{GENDER:$2|moluluto}}halaman $3",
+ "logentry-move-move": "$1 {{GENDER:$2|moheyi}} halaman $3 ode $4",
+ "logentry-newusers-create": "Ta ohu'uwo akun $1 {{GENDER:$2|mohutu}}",
+ "logentry-upload-upload": "$1 {{GENDER:$2|mengunggah}} $3",
+ "searchsuggest-search": "Lolohe"
+}
"noname": "Οὐ καθὠρισας ἔγκυρόν τι ὄνομα χρωμένου.",
"loginsuccesstitle": "Ἐπιτυχῶς συνεδέθης",
"loginsuccess": "'''συνδέδεσαι ἤδη τῷ {{SITENAME}} ὡς \"$1\".'''",
- "nosuchuser": "Οὐκ ἐστὶ χρώμενος ὀνόματι \"$1\".\nΤὰ γράμματα τῶν ὀνομάτων χρωμένων διακρίνονται εἰς κεφαλαῖα καὶ μικρά.\nΣκόπει τὴν τῶν γραμμάτων ἀκριβείαν ἢ [[Special:UserLogin/signup|λογισμὸν νέον ποίει]].",
+ "nosuchuser": "Οὐκ ἐστὶ χρώμενος ὀνόματι \"$1\".\nΤὰ γράμματα τῶν ὀνομάτων χρωμένων διακρίνονται εἰς κεφαλαῖα καὶ μικρά.\nΣκόπει τὴν τῶν γραμμάτων ἀκριβείαν ἢ [[Special:CreateAccount|λογισμὸν νέον ποίει]].",
"nosuchusershort": "Οὐκ ἐστὶ χρώμενος ἔχων τὸ ὄνομα \"$1\".\nἜλεγξον τὴν ὀρθογραφίαν σου.",
"nouserspecified": "Ὄνομα χρωμένου καθοριστέον ὑποχρεωτικώς.",
"wrongpassword": "Εἰσηγμένον σύνθημα ἐσφαλμένον. Πείρασον πάλιν.",
"noname": "Du muesch e Benutzername aagee.",
"loginsuccesstitle": "Aamäldig erfolgrych",
"loginsuccess": "'''Du bisch jetz als \"$1\" bi {{SITENAME}} aagmäldet.'''",
- "nosuchuser": "Dr Benutzername \"$1\" git s nit.\n\nIberprief d Schrybwys, oder mäld Di as [[Special:UserLogin/signup|neje Benutzer aa]].",
+ "nosuchuser": "Dr Benutzername \"$1\" git s nit.\n\nIberprief d Schrybwys, oder mäld Di as [[Special:CreateAccount|neje Benutzer aa]].",
"nosuchusershort": "S git kei Benutzername „$1“. Bitte iberprief d Schrybwys.",
"nouserspecified": "Bitte gib e Benutzername yy.",
"login-userblocked": "Dää Benutzer isch gsperrt. Aamäldig nit erlaubt.",
"accmailtext": "E zuefällig generiert Passwort fir [[User talk:$1|$1]] isch an $2 gschickt wore.\n\nS Passwort fir des nej Benutzerkonto cha uf dr Spezialsyte „[[Special:ChangePassword|Passwort ändere]]“ gänderet wäre.",
"newarticle": "(Nej)",
"newarticletext": "Du bisch eme Link nogange zuen ere Syte, wu s nid git.\nZum die Syte aalege, chasch do in däm Chaschte unte aafange schrybe (lueg [$1 Hilfe] fir meh Informatione).\nWänn do nid hesch welle aane goh, no druck in Dyynem Browser uf '''Zruck'''.",
- "anontalkpagetext": "----''Des isch e Diskussionssyte vun eme anonyme Benutzer, wu kei Zuegang aagleit het oder wu ne nit bruucht. Sälleweg mien mir di numerisch IP-Adräss bruuche zum ihn oder si z identifiziere. So ne IP-Adräss cha au vu mehrere Benutzer teilt wäre. Wenn Du ne anonyme Benutzer bisch un s Gfiel hesch, ass do irrelevanti Kommentar an di grichtet wäre, derno [[Special:UserLogin/signup|leg e Konto aa]] oder [[Special:UserLogin|mäld di aa]] zum in Zuekumft Verwirrige mit andere anonyme Benutzer z vermyyde.''",
+ "anontalkpagetext": "----''Des isch e Diskussionssyte vun eme anonyme Benutzer, wu kei Zuegang aagleit het oder wu ne nit bruucht. Sälleweg mien mir di numerisch IP-Adräss bruuche zum ihn oder si z identifiziere. So ne IP-Adräss cha au vu mehrere Benutzer teilt wäre. Wenn Du ne anonyme Benutzer bisch un s Gfiel hesch, ass do irrelevanti Kommentar an di grichtet wäre, derno [[Special:CreateAccount|leg e Konto aa]] oder [[Special:UserLogin|mäld di aa]] zum in Zuekumft Verwirrige mit andere anonyme Benutzer z vermyyde.''",
"noarticletext": "Uf däre Syte het s no kei Täxt. Du chasch uf andere Syte [[Special:Search/{{PAGENAME}}|dä Yytrag sueche]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} dr Logbuechyytrag sueche, wo dezue ghert],\noder [{{fullurl:{{FULLPAGENAME}}|action=edit}} die Syte bearbeite]</span>.",
"noarticletext-nopermission": "In däre Syte het s zur Zyt no kei Text.\nDu chasch dää Titel uf andre Syte [[Special:Search/{{PAGENAME}}|sueche]]\noder <span class=\"plainlinks\">in dr zuegherige [{{fullurl:{{#special:Log}}|page={{FULLPAGENAMEE}}}} Logbiecher sueche].</span> Du derfsch aber die Syte nit aalege.",
"missing-revision": "D Version $1 vu dr Syte mit Name „{{FULLPAGENAME}}“ git s nit.\n\nDää Fähler chunnt normalerwyys dur e veraltete Link zue dr Versionsgschicht vun ere Syte, wu in dr Zwischezyt glescht woren isch.\nEinzelheite chasch im [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Lesch-Logbuech] bschaue.",
"upload-form-label-own-work": "Das han i sälber gmacht.",
"upload-form-label-infoform-categories": "Kategorië",
"upload-form-label-infoform-date": "Datum",
- "upload-form-label-own-work-message-local": "I bestätige, das i die Datei under de Nutzigsbedingigen und Lizänzrichtlinje vo {{SITENAME}} ufelade.",
- "upload-form-label-not-own-work-message-local": "We du die Datei nid under de Nutzigsbedingigen und Lizänzrichtlinje vo {{SITENAME}} chasch ufelade, de schliess bitte dä Dialog u probier’s uf’nen anderi Art.",
- "upload-form-label-not-own-work-local-local": "Du chasch es ou mit der [[Special:Upload|Standardsyte zum Ufelade]] probiere.",
- "upload-form-label-own-work-message-default": "I bi mer bewusst, das i die Datei in es gmeinsams Repository ufelade. I bestätige, das mi derby a d Nutzigs- und Lizänzbedingige dört halte.",
- "upload-form-label-not-own-work-message-default": "Bitte schliess dä Dialog und versuech’s mit eren andere Methode, falls du die Datei nid under de Bedingige vom gmeinsame Repository chasch ufelade.",
- "upload-form-label-not-own-work-local-default": "Du chasch es ou mit der [[Special:Upload|Syte zum Ufeladen uf {{SITENAME}}]] probiere, falls du die Datei dört under denen irne Bedingige chasch ufelade.",
- "upload-form-label-own-work-message-shared": "I bestätige, das ds Copyright vo dere Datei mir ghört. I stimmen unwiderruefflech zue, das die Datei uf Wikimedia Commons under der Lizänz [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] veröffentlecht wird. I bi mit de [https://wikimediafoundation.org/wiki/Terms_of_Use/de Nutzigsbedingigen] yverstande.",
- "upload-form-label-not-own-work-message-shared": "Falls ds Copyright vo dere Datei nid dir ghört oder falls du sen under eren andere Lizänz wosch veröffentleche, de chönntsch der [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons Upload Wizard] bruuche.",
- "upload-form-label-not-own-work-local-shared": "Du chasch es ou mit der [[Special:Upload|Syte zum Ufeladen uf {{SITENAME}}]] probiere, falls dä Website ds Ufelade vo der Datei under syne Bedingige zuelat.",
+ "upload-form-label-own-work-message-generic-local": "I bestätige, das i die Datei under de Nutzigsbedingigen und Lizänzrichtlinje vo {{SITENAME}} ufelade.",
+ "upload-form-label-not-own-work-message-generic-local": "We du die Datei nid under de Nutzigsbedingigen und Lizänzrichtlinje vo {{SITENAME}} chasch ufelade, de schliess bitte dä Dialog u probier’s uf’nen anderi Art.",
+ "upload-form-label-not-own-work-local-generic-local": "Du chasch es ou mit der [[Special:Upload|Standardsyte zum Ufelade]] probiere.",
+ "upload-form-label-own-work-message-generic-foreign": "I bi mer bewusst, das i die Datei in es gmeinsams Repository ufelade. I bestätige, das mi derby a d Nutzigs- und Lizänzbedingige dört halte.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Bitte schliess dä Dialog und versuech’s mit eren andere Methode, falls du die Datei nid under de Bedingige vom gmeinsame Repository chasch ufelade.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Du chasch es ou mit der [[Special:Upload|Syte zum Ufeladen uf {{SITENAME}}]] probiere, falls du die Datei dört under denen irne Bedingige chasch ufelade.",
"backend-fail-stream": "D Datei $1 het nit chenne ibertrait wäre.",
"backend-fail-backup": "D Datei $1 het nit chenne gsicheret wäre.",
"backend-fail-notexists": "D Datei $1 git s nit.",
"versionrequired": "મીડીયાવિકિનું $1 સંસ્કરણ જરૂરી",
"versionrequiredtext": "આ પાનાના વપરાશ માટે મીડિયાવિકિનું $1 સંસ્કરણ જરૂરી.\n\nજુઓ [[Special:Version|સંસ્કરણ પાનું]].",
"ok": "મંજૂર",
- "retrievedfrom": "\"$1\"થી લીધેલું",
+ "retrievedfrom": "\"$1\" થી મેળવેલ",
"youhavenewmessages": "{{PLURAL:$3|તમારી પાસે}} $1 ($2).",
"youhavenewmessagesfromusers": "આપને માટે {{PLURAL:$3|અન્ય સભ્ય|$3 અન્ય સભ્યો}} તરફથી $1 છે. ($2).",
"youhavenewmessagesmanyusers": "આપને માટે ઘણાં સભ્યો તરફથી $1 છે ($2).",
"noname": "તમે પ્રમાણભૂત સભ્યનામ જણાવેલ નથી.",
"loginsuccesstitle": "પ્રવેશ સફળ",
"loginsuccess": "'''તમે હવે {{SITENAME}}માં \"$1\" તરીકે પ્રવેશી ચુક્યા છો.'''",
- "nosuchuser": "\"$1\" નામ ધરાવતો કોઇ સભ્ય અસ્તિત્વમાં નથી.\n\nસભ્યનામો અક્ષરસંવેદી (કેસ સેન્સિટીવ) હોય છે.\n\nકૃપા કરી સ્પેલીંગ/જોડણી ચકાસો અથવા [[Special:UserLogin/signup|નવું ખાતુ ખોલો]].",
+ "nosuchuser": "\"$1\" નામ ધરાવતો કોઇ સભ્ય અસ્તિત્વમાં નથી.\n\nસભ્યનામો અક્ષરસંવેદી (કેસ સેન્સિટીવ) હોય છે.\n\nકૃપા કરી સ્પેલીંગ/જોડણી ચકાસો અથવા [[Special:CreateAccount|નવું ખાતુ ખોલો]].",
"nosuchusershort": "\"$1\" નામનો કોઇ સભ્ય નથી, તમારી જોડણી તપાસો.",
"nouserspecified": "તમારે સભ્ય નામ દર્શાવવાની જરૂર છે.",
"login-userblocked": "આ યુઝર પ્રતિબંધિત છે. પ્રવેશ વર્જીત.",
"accmailtitle": "ગુપ્તસંજ્ઞા મોકલવામાં આવી છે.",
"accmailtext": "[[User talk:$1|$1]] માટે રચેલ ગુપ્તસંજ્ઞા $2 ને મોકલાવી દેવાઇ છે. આ નવા ખાતાનીગુપ્તસંજ્ઞા પ્રવેશ કર્યા બાદ ''[[Special:ChangePassword|ગુપ્તસંજ્ઞા બદલો]]'' વાપરીને બદલી શકાશે.",
"newarticle": "(નવીન)",
- "newarticletext": "<div style=\"background: #F9F9F9; margin-top: 1em; padding: 1em; border: 1px solid #ccc; border-right: 2px solid #ccc; border-bottom: 2px solid #ccc\"><center>'''આ વિકિ પ્રકલ્પ પર આ પ્રકારનો લેખ હાલમાં નથી'''</center>\n----\n* [[Image:Searchtool.svg|25px|alt=|link=]] '''[[{{ns:special}}:Search/{{PAGENAME}}|“{{PAGENAME}}”]]''' માટે શોધો.\n* [[Image:Nuvola apps fonts.png|25px|alt=|link=]] જે લેખોનું શીર્ષક આ પ્રત્યય સાથે શરુ થાય છે તેનો [[{{ns:special}}:Prefixindex/{{FULLPAGENAME}}|ઉપસર્ગ]] જૂઓ.\n* [[Image:Nuvola apps ksig.png|25px|alt=|link=]] <span class=\"plainlinks\">'''[{{SERVER}}{{localurl:{{NAMESPACE}}:{{PAGENAME}}|action=edit}} આ શીર્ષકનું નવું પૃષ્ઠ બનાવો.]'''</span> \n* [[Image:WP-TranslationProject TwoFlags.svg|25px|alt=|link=]] ''વૈશ્વિક લેખ યોજના'' દ્વારા આ લેખને [//vs.aka-online.de/cgi-bin/globalwpsearch.pl?search={{PAGENAMEE}} અન્ય ભાષાઓમાં શોધો.]\n<div style=\"margin: 1em 2em 1em 3em; font-size: 90%;\">\nયોગદાનકર્તાઓ માટે:\n* જો આપ હાલમાં આ લેખ બનાવી રહ્યા છો તો પોતાના બ્રાઉઝરની <span class=\"plainlinks\">[{{SERVER}}{{localurl:{{NAMESPACE}}:{{PAGENAME}}|action=purge}} કૈશ ખાલી]</span> કરો, અથવા થોડી વધુ રાહ જૂઓ, પછી કામ આગળ વધારો.\n* કદાચ આ પાનું દૂર કરાયું છે, આ જોવા માટે કૃપા કરીને <span class=\"plainlinks\">[{{fullurl:Special:Log|type=delete&page={{FULLPAGENAMEE}}}} આ પાનાનો વિલોપન ઇતિહાસ]</span> જૂઓ.\n* આપ આ લેખ બનાવવા માગો છો તો ક્રુપા કરીને નીચે આપેલા ખાનામાં લખવાનું શરુ કરો.\n* જો આપ ભૂલમાં અહીં આવી ગયા છો તો આપના બ્રાઉઝરના બૅક બટન પર ક્લિક કરીને પરત ફરો.</div></div>",
- "anontalkpagetext": "----\n<em>આ એક અજ્ઞાત સભ્યનું ચર્ચા પાનું છે જેમણે ક્યાં તો પોતાનું ખાતું ખોલ્યું નથી અથવા તો તેને વાપરતા નથી.</em>\nઆથી તેમને ઓળખવા માટે અમારે સાંખ્યિક IP સરનામાની મદદ લેવી પડી છે.\nઆવું IP સરનામું ઘણાં અન્ય સભ્યો પણ વાપરતા હોઇ શકે.\nજો તમે અજ્ઞાત સભ્ય હોવ અને માનતા હોવ કે અસંધિત ટિપ્પણીઓ તમારી તરફ વાળવામાં આવી છે, તો કૃપયા [[Special:UserLogin/signup|create an account]] અથવા [[Special:UserLogin|log in]]નો ઉપયોગ કરશો જેથી તમને કોઈ અજ્ઞાત સભ્ય સમજવાની ભૂલ ભવિષ્યમાં ટાળી શકાય.",
- "noarticletext": "àª\86 પાનામાàª\82 હાલમાàª\82 àª\95à«\8bàª\87 માહિતિ નથà«\80.\nતમà«\87 [[Special:Search/{{PAGENAME}}|àª\86 શબà«\8dદ]] ધરાવતાàª\82 àª\85નà«\8dય લà«\87àª\96à«\8b શà«\8bધà«\80 શàª\95à«\8b àª\9bà«\8b, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} સàª\82લàª\97à«\8dન માહિતિ પતà«\8dરàª\95à«\8bમાàª\82 શà«\8bધà«\80 શàª\95à«\8b àª\9bà«\8b],\nàª\85થવા [{{fullurl:{{FULLPAGENAME}}|action=edit}} àª\86 પાનામાàª\82 ફà«\87રફાર àª\95રà«\80] માહિતિ àª\89મà«\87રવાનà«\81àª\82 શરà«\82 àª\95રà«\80 શàª\95à«\8b àª\9bà«\8b</span>.",
+ "newarticletext": "તમે અસ્તિત્વ ન ધરાવતા પાનાંની કડી ખોલી છે.\nપાનું બનાવવા માટે, નીચેની જગ્યામાં લખવાનું શરૂ કરો (વધુ માહિતી માટે જુઓ [$1 મદદ પાનું]).\nજો તમે ભૂલથી અહીં આવી ગયા હોવ તો, તમારા બ્રાઉઝરનું <strong>પાછાં જાવ</strong> બટન ક્લિક કરી પાછાં જાવ.",
+ "anontalkpagetext": "----\n<em>આ એક અજ્ઞાત સભ્યનું ચર્ચા પાનું છે જેમણે ક્યાં તો પોતાનું ખાતું ખોલ્યું નથી અથવા તો તેને વાપરતા નથી.</em>\nઆથી તેમને ઓળખવા માટે અમારે સાંખ્યિક IP સરનામાની મદદ લેવી પડી છે.\nઆવું IP સરનામું ઘણાં અન્ય સભ્યો પણ વાપરતા હોઇ શકે.\nજો તમે અજ્ઞાત સભ્ય હોવ અને માનતા હોવ કે અસંધિત ટિપ્પણીઓ તમારી તરફ વાળવામાં આવી છે, તો કૃપયા [[Special:CreateAccount|create an account]] અથવા [[Special:UserLogin|log in]]નો ઉપયોગ કરશો જેથી તમને કોઈ અજ્ઞાત સભ્ય સમજવાની ભૂલ ભવિષ્યમાં ટાળી શકાય.",
+ "noarticletext": "àª\86 પાનામાàª\82 હાલમાàª\82 àª\95à«\8bàª\87 લàª\96ાણ નથà«\80.\nતમà«\87 બà«\80àª\9cાàª\82 પાનાàª\82માàª\82 [[Special:Search/{{PAGENAME}}|àª\86 પાનાàª\82ના શà«\80રà«\8dષàª\95 માàª\9fà«\87 શà«\8bધà«\80 શàª\95à«\8b àª\9bà«\8b]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} સàª\82લàª\97à«\8dન માહિતિ પતà«\8dરàª\95à«\8bમાàª\82 શà«\8bધà«\80 શàª\95à«\8b àª\9bà«\8b],\nàª\85થવા [{{fullurl:{{FULLPAGENAME}}|action=edit}} àª\86 પાનà«\81àª\82 બનાવà«\80 શàª\95à«\8b àª\9bà«\8b]</span>.",
"noarticletext-nopermission": "આ પાનામાં હાલમાં કોઇ માહિતિ નથી.\nતમે [[Special:Search/{{PAGENAME}}|આ શબ્દ]] ધરાવતાં અન્ય લેખો શોધી શકો છો, અથવા <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} સંલગ્ન માહિતિ પત્રકોમાં શોધી શકો છો], પરંતુ તમને આ પાનું બનાવવાની મંજૂરી નથી.",
"userpage-userdoesnotexist": "સભ્ય ખાતું \"<nowiki>$1</nowiki>\"ની નોંધણીનથી થઈ.\nશું તમે ખરેખર આ પાનાની રચના કે ફેરફાર કરવા માંગો છો",
"userpage-userdoesnotexist-view": "સભ્યના ખાતા $1 ની નોંધણી નથી થઈ",
"editingsection": "$1 (પરિચ્છેદ)નો ફેરફાર કરી રહ્યા છો",
"editingcomment": "$1 (પરિચ્છેદ)નો ફેરફાર કરી રહ્યા છો",
"editconflict": "ફેરફારમાં વિસંગતતા: $1",
- "explainconflict": "તમà«\87 ફà«\87રફાર àª\95રવાનà«\80 શરà«\82àª\86ત àª\95રà«\80 તà«\87 દરમà«\8dયાન àª\85મà«\81àª\95 àª\95à«\8bàª\87àª\95à«\87 પણ તà«\87માàª\82 ફà«\87રફાર àª\95રà«\8dયાàª\82 àª\9bà«\87.\nàª\89પરનà«\8b àª\85àª\95à«\8dષર દà«\87હ àª\85તà«\8dયરનà«\8b વિહરમાન સà«\8dથિતિ બતાવà«\87 àª\9bà«\87.\nતમારા દà«\8dવારા àª\95રાયà«\87લ ફà«\87રફાર નà«\80àª\9aà«\87ના àª\95à«\8dષà«\87તà«\8dરમાàª\82 દà«\87àª\96ાય àª\9bà«\87.\nતમારà«\87 તમારા ફà«\87રફારà«\8b વિહરમાન હયાત લà«\87àª\96માàª\82 વિલિન àª\95રવà«\8b પડશà«\87. \n àª\9cà«\8b તમà«\87 \"{{int:savearticle}}\" àª\86 બાન દબાવશà«\8b તà«\8b '''ફàª\95à«\8dત''' ઉપરનો લેખ સચવાશે.",
+ "explainconflict": "તમà«\87 ફà«\87રફાર àª\95રવાનà«\80 શરà«\82àª\86ત àª\95રà«\80 તà«\87 દરમà«\8dયાન àª\85મà«\81àª\95 àª\95à«\8bàª\87àª\95à«\87 પણ તà«\87માàª\82 ફà«\87રફાર àª\95રà«\8dયાàª\82 àª\9bà«\87.\nàª\89પરનà«\8b àª\85àª\95à«\8dષર દà«\87હ àª\85તà«\8dયારનà«\8b વિહરમાન સà«\8dથિતિ બતાવà«\87 àª\9bà«\87.\nતમારા દà«\8dવારા àª\95રાયà«\87લ ફà«\87રફાર નà«\80àª\9aà«\87ના àª\95à«\8dષà«\87તà«\8dરમાàª\82 દà«\87àª\96ાય àª\9bà«\87.\nતમારà«\87 તમારા ફà«\87રફારà«\8b વિહરમાન હયાત લà«\87àª\96માàª\82 વિલિન àª\95રવા પડશà«\87. \nàª\9cà«\8b તમà«\87 \"{{int:savearticle}}\" àª\86 બàª\9fન દબાવશà«\8b તà«\8b <strong>ફàª\95à«\8dત</strong> ઉપરનો લેખ સચવાશે.",
"yourtext": "તમારું લખાણ",
"storedversion": "સંગ્રહેલ પુનરાવર્તન",
"nonunicodebrowser": "'''ચેતવણી: તમારું બ્રાઉઝર યુનિકોડ ઉકેલવા સક્ષમ નથી.'''\nઅહીં તમે સુરક્ષિત રીતે ફેરફારો નહીં કરી શકો: ASCII સિવાયના અક્ષરો સંપાદન ચોકઠામાં હેક્સાડેસિમલ સ્વરૂપે દેખાશે.",
"whatlinkshere-prev": "{{PLURAL:$1|પહેલાનું|પહેલાનાં $1}}",
"whatlinkshere-next": "{{PLURAL:$1|પછીનું|પછીનાં $1}}",
"whatlinkshere-links": "← કડીઓ",
- "whatlinkshere-hideredirs": "અન્યત્ર વાળેલાં પાનાં $1",
- "whatlinkshere-hidetrans": "$1 àª\86રપાર સમાવà«\87શનો",
- "whatlinkshere-hidelinks": "કડીઓ $1",
+ "whatlinkshere-hideredirs": "$1 અન્યત્ર વાળેલ",
+ "whatlinkshere-hidetrans": "$1 સમાવà«\87શો",
+ "whatlinkshere-hidelinks": "$1 કડીઓ",
"whatlinkshere-hideimages": "$1 ફાઇલની કડીઓ",
"whatlinkshere-filters": "ચાળણીઓ",
"autoblockid": "ઓટોબ્લોક #$1",
"noname": "Cha honree uss ennym ymmydeyr fondagh.",
"loginsuccesstitle": "T'ou loggit stiagh",
"loginsuccess": "'''T'ou loggit stiagh ayns {{SITENAME}} myr \"$1\".'''",
- "nosuchuser": "Cha nel ymmydeyr ayn lesh yn ennym \"$1\".<br />\nTa case ny lettyryn ayns enmyn ymmydeyr dendeaysagh.<br />\nCur streean er dty lettraghey, ny [[Special:UserLogin/signup|croo coontys noa]].",
+ "nosuchuser": "Cha nel ymmydeyr ayn lesh yn ennym \"$1\".<br />\nTa case ny lettyryn ayns enmyn ymmydeyr dendeaysagh.<br />\nCur streean er dty lettraghey, ny [[Special:CreateAccount|croo coontys noa]].",
"nosuchusershort": "Cha nel ymmydeyr ayn lesh yn ennym \"$1\".\nCur streean er dty lettraghey.",
"nouserspecified": "Shegin diu ennym ymmydeyr y honraghey.",
"login-userblocked": "Ta'n ymmydeyr shoh fo ghlass. Cha lowit {{GENDER:|da|jee|da}} loggal stiagh.",
"allpagessubmit": "Gow",
"allpagesprefix": "Taishbyn ny duillagyn lesh roie-ockle:",
"categories": "Ronnaghyn",
- "special-categories-sort-count": "sorçhaghey rere coontey",
- "special-categories-sort-abc": "sorçhaghey rere lettyr",
"linksearch": "Ronsaghey kianglaghyn çheumooie",
"linksearch-ok": "Ronsee",
"linksearch-line": "Ta kiangley ayn veih $2 gys $1",
"noname": "汝還吂輸入一隻有效嘅用戶名。",
"loginsuccesstitle": "登入成功",
"loginsuccess": "汝今下以\"$1\"嘅身份在{{SITENAME}}登入。",
- "nosuchuser": "尋毋到用戶 \"$1\"。\n用戶名稱係有大小寫區分嘅。\n檢查汝嘅拼寫,或者用下面嘅表格[[Special:UserLogin/signup|建立一隻新賬號]]。",
+ "nosuchuser": "尋毋到用戶 \"$1\"。\n用戶名稱係有大小寫區分嘅。\n檢查汝嘅拼寫,或者用下面嘅表格[[Special:CreateAccount|建立一隻新賬號]]。",
"nosuchusershort": "無有喊做“$1”嘅用戶。請檢查汝輸入嘅文字係毋係有差錯。",
"nouserspecified": "汝愛指定一隻用戶名。",
"login-userblocked": "邇隻用戶已分封鎖。毋做得登入。",
"createaccountreason": "Kumu:",
"createacct-reason": "Kumu",
"createacct-reason-ph": "No ke aha mai ke kāinoa nei i kekahi moʻokāki ʻē aʻe",
- "createacct-captcha": "Hōʻoiana palekana",
- "createacct-imgcaptcha-ph": "E kikokiko i ke kikokikona i luna",
"createacct-submit": "Kāinoa",
"createacct-another-submit": "Kāinoa hou",
"createacct-benefit-heading": "Hana ʻia ʻo {{SITENAME}} e nā kanaka e like me ʻoe.",
"noname": "ʻAʻole hana ʻoe i kekahi inoa mea hoʻohana pono.",
"loginsuccesstitle": "ʻEʻe kūleʻa",
"loginsuccess": "<strong>Ua ʻeʻe ʻo \"$1\" iā {{SITENAME}}.</strong>",
- "nosuchuser": "Loaʻa ʻole i ka inoa mea hoʻohana ʻo \"$1\".\nMakaʻala maʻaka ka inoa mea hoʻohana.\nHōʻoia i kāu kepela ʻana, aiʻole [[Special:UserLogin/signup|kāinoa i kekahi mōʻaukaki hou]].",
+ "nosuchuser": "Loaʻa ʻole i ka inoa mea hoʻohana ʻo \"$1\".\nMakaʻala maʻaka ka inoa mea hoʻohana.\nHōʻoia i kāu kepela ʻana, aiʻole [[Special:CreateAccount|kāinoa i kekahi mōʻaukaki hou]].",
"nosuchusershort": "Loaʻa ʻole i ka Loaʻa ʻole i ka inoa mea hoʻohana ʻo \"$1\".\nHōʻoia i kāu kepela ʻana.",
"nouserspecified": "Pono ʻoe e kāhuakomo i ka inoa mea hoʻohana.",
"login-userblocked": "Pale ʻia kēia mea hoʻohana. ʻAʻole hiki ke ʻeʻe.",
"resetpass-temp-password": "ʻŌlelo hūnā kūikawā:",
"resetpass-expired": "Ua pau kāu ʻōlelo hūnā. E ʻoluʻolu, e loaʻa kahi ʻōlelo hūnā hou no ka ʻeʻe ʻana.",
"passwordreset": "Kāinoa hou i ka ʻōlelo hūnā",
- "passwordreset-legend": "Kāinoa hou i ka ʻōlelo hūnā",
"passwordreset-username": "Inoa mea ho'ohana:",
"passwordreset-email": "Wahinoho lekauila:",
"changeemail": "Hoʻololi i ka wahinoho lekauila",
+ "changeemail-header": "Hoʻololi i ka wahinoho lekauila moʻokāki",
"changeemail-oldemail": "Wahinoho lekauila hananei:",
"changeemail-newemail": "Wahinoho lekauila hou:",
"changeemail-none": "(ʻaʻohe)",
"accmailtitle": "Ua ho‘ouna ‘ia ka ‘ōlelo hūnā",
"newarticle": "(Hou)",
"newarticletext": "Ua hāhai ʻoe i kekahi loulou i kekahi ʻaoʻao e haku ʻole.\nNo ka haku ʻana i ka ʻaoʻao, kikokiko i loko o ka pahu i lalo (ʻike i ka [$1 ʻaoʻao kōkua] no nā ʻike ʻē aʻe).\nInā hewa kou hele ʻana, kāomi i ka pihi <strong>hoʻi</strong>.",
- "anontalkpagetext": "----\n<em>ʻO kēia ka ʻaoʻao kūkākūkā no kekahi mea ho‘ohana me ka inoa ʻole.</em>\nNo laila, pono mākou e ho‘ohana i ka IP no ka hōʻoia ʻana iā ia a hiki i kekahi mau mea hoʻohana ke hoʻokaʻana i kēia IP.\nInā he mea ho‘ohana inoa ʻole ʻoe a loaʻa kekahi mau manaʻo nāuʻole, e ʻoluʻolu [[Special:UserLogin/signup|e kāinoa]] a i ʻole [[Special:UserLogin|e ʻeʻe]].''",
+ "anontalkpagetext": "----\n<em>ʻO kēia ka ʻaoʻao kūkākūkā no kekahi mea ho‘ohana me ka inoa ʻole.</em>\nNo laila, pono mākou e ho‘ohana i ka IP no ka hōʻoia ʻana iā ia a hiki i kekahi mau mea hoʻohana ke hoʻokaʻana i kēia IP.\nInā he mea ho‘ohana inoa ʻole ʻoe a loaʻa kekahi mau manaʻo nāuʻole, e ʻoluʻolu [[Special:CreateAccount|e kāinoa]] a i ʻole [[Special:UserLogin|e ʻeʻe]].''",
"noarticletext": "ʻAʻohe kikokikona a kēia ʻaoʻao.\nHiki iā ʻoe ke [[Special:Search/{{PAGENAME}}|huli no kēia inoa ʻaoʻao]] i nā ʻaoʻao ʻē aʻe, <span class=\"plainlinks\">[{{fullurl:SpecialLog|page={{FULLPAGENAMEE}}}} huli i nā moʻolelo pili], a i ʻole [{{fullurl:{{FULLPAGENAME}}|action=edit}} hoʻololi i kēia ʻaoʻao]</span>.",
"noarticletext-nopermission": "ʻAʻohe kikokikona a kēia ʻaoʻao.\nHiki iā ʻoe ke [[Special:Search/{{PAGENAME}}|huli no kēia inoa ʻaoʻao]] i nā ʻaoʻao ʻē aʻe aiʻole <span class=\"plainlinks\">[{{fullurl:SpecialLog|page={{FULLPAGENAMEE}}}} huli i nā moʻolelo pili]</span>, akā hiki ʻole iā ʻoe ke hoʻololi i kēia ʻaoʻao.",
"userpage-userdoesnotexist-view": "ʻAʻole kāinoa ʻia ka moʻokāki mea hoʻohana ʻo \"$1\".",
"upload-description": "Hōʻike ʻano waihona",
"upload-options": "Koho hoʻouka",
"watchthisupload": "E kiaʻi i kēia waihona",
- "upload-warning-subj": "Akahele hoʻouka",
"upload-file-error": "Hewa kūloko",
"upload-http-error": "Ua loaʻa kekahi hewa HTTP: $1",
"license": "Laikini:",
"blocklogentry": "ua hoʻopale ʻia ʻo [[$1]] no ka manawa o $2 $3",
"block-log-flags-nocreate": "ua hoʻopale ʻia ke kāinoa moʻokāki ʻana",
"move-page-legend": "Hoʻoneʻe i ka ʻaoʻao",
- "movearticle": "E hoʻoneʻe i ka ʻaoʻao:",
"newtitle": "I ka inoa hou:",
"move-watch": "Kiaʻi i ka ʻaoʻao kumu a me ka ʻaoʻao māka",
"movepagebtn": "Hoʻoneʻe i ka ʻaoʻao",
"movelogpage": "Hoʻoneʻe i ka moʻolelo",
"movereason": "Kumu:",
"revertmove": "hoʻihoʻi",
- "delete_and_move": "Holoi a hoʻoneʻe",
"delete_and_move_confirm": "‘Ae, e holoi i ka ‘ao‘ao",
"export": "Kāpuka ʻaoʻao",
"export-addcat": "Ho‘ohui",
"version-poweredby-translators": "nā mea unuhi ma translatewiki.net",
"version-software-version": "Mana",
"redirect": "Kiahou e ka waihona, ka mea hoʻohana, ka ʻaoʻao aiʻole ka ID loihape",
- "redirect-legend": "Kiahou i kekahi waihona aiʻole kekahi ʻaoʻao",
"redirect-summary": "Kiahou kēia ʻaoʻao kūikawā i kekahi waihona (inā hāʻawi ʻia kekahi inoa waihona), kekahi ʻaoʻao (inā hāʻawi ʻia kekahi ID loihape aiʻole ID ʻaoʻao) aiʻole kekahi ʻaoʻao mea hoʻohana (inā hāʻawi ʻia ka ID mea hoʻohana helu). Ka hana ʻana: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], aiʻole [[{{#Special:Redirect}}/user/101]].",
"redirect-submit": "Huli",
"redirect-lookup": "Huli no:",
"Geagea",
"פוילישער",
"DatGuy",
- "IKhitron"
+ "IKhitron",
+ "Matma Rex"
]
},
"tog-underline": "סימון קישורים בקו תחתי:",
"tog-hideminor": "הסתרת עריכות משניות בדף השינויים האחרונים",
- "tog-hidepatrolled": "×\94סתרת ש×\99× ×\95×\99×\99×\9d ×\91×\93×\95ק×\99×\9d בדף השינויים האחרונים",
+ "tog-hidepatrolled": "×\94סתרת ער×\99×\9b×\95ת ×\91×\93×\95ק×\95ת בדף השינויים האחרונים",
"tog-newpageshidepatrolled": "הסתרת דפים בדוקים ברשימת הדפים החדשים",
"tog-hidecategorization": "הסתרת שינויים בקטגוריות של דפים",
"tog-extendwatchlist": "הרחבת רשימת המעקב כך שתציג את כל השינויים, לא רק את השינויים האחרונים בכל דף",
"tog-showtoolbar": "הצגת סרגל העריכה",
"tog-editondblclick": "עריכת דפים בלחיצה כפולה",
"tog-editsectiononrightclick": "עריכת פסקאות באמצעות לחיצה ימנית על כותרות הפסקאות",
- "tog-watchcreations": "×\94×\95ספת ×\93פ×\99×\9d ש×\99צרת×\99 ×\95ק×\91צ×\99×\9d ש×\94×¢×\9c×\99ת×\99 לרשימת המעקב שלי",
- "tog-watchdefault": "×\94×\95ספת ×\93פ×\99×\9d ×\95ק×\91צ×\99×\9d שער×\9bת×\99 לרשימת המעקב שלי",
- "tog-watchmoves": "×\94×\95ספת ×\93פ×\99×\9d ×\95ק×\91צ×\99×\9d ש×\94×¢×\91רת×\99 לרשימת המעקב שלי",
- "tog-watchdeletion": "×\94×\95ספת ×\93פ×\99×\9d ×\95ק×\91צ×\99×\9d ש×\9e×\97קת×\99 לרשימת המעקב שלי",
- "tog-watchuploads": "×\94×\95ספת ק×\91צ×\99×\9d ×\97×\93ש×\99×\9d ש×\94×¢×\9c×\99ת×\99 לרשימת המעקב שלי",
- "tog-watchrollback": "×\94×\95ספת ×\93פ×\99×\9d ש×\91×\99צעת×\99 בהם שחזור מהיר לרשימת המעקב שלי",
+ "tog-watchcreations": "×\94×\95ספת ×\93פ×\99×\9d ש×\90× ×\99 {{GENDER:|×\99×\95צר|×\99×\95צרת}} ×\95ק×\91צ×\99×\9d ש×\90× ×\99 ×\9e×¢×\9c×\94 לרשימת המעקב שלי",
+ "tog-watchdefault": "×\94×\95ספת ×\93פ×\99×\9d ×\95ק×\91צ×\99×\9d ש×\90× ×\99 {{GENDER:|×¢×\95ר×\9a|×¢×\95ר×\9bת}} לרשימת המעקב שלי",
+ "tog-watchmoves": "×\94×\95ספת ×\93פ×\99×\9d ×\95ק×\91צ×\99×\9d ש×\90× ×\99 {{GENDER:|×\9e×¢×\91×\99ר|×\9e×¢×\91×\99ר×\94}} לרשימת המעקב שלי",
+ "tog-watchdeletion": "×\94×\95ספת ×\93פ×\99×\9d ×\95ק×\91צ×\99×\9d ש×\90× ×\99 {{GENDER:|×\9e×\95×\97ק|×\9e×\95×\97קת}} לרשימת המעקב שלי",
+ "tog-watchuploads": "×\94×\95ספת ק×\91צ×\99×\9d ×\97×\93ש×\99×\9d ש×\90× ×\99 ×\9e×¢×\9c×\94 לרשימת המעקב שלי",
+ "tog-watchrollback": "×\94×\95ספת ×\93פ×\99×\9d ש×\90× ×\99 {{GENDER:|×\9e×\91צע|×\9e×\91צעת}} בהם שחזור מהיר לרשימת המעקב שלי",
"tog-minordefault": "סימון כל עריכה כמשנית כברירת מחדל",
"tog-previewontop": "הצגת תצוגה מקדימה לפני תיבת העריכה",
"tog-previewonfirst": "הצגת תצוגה מקדימה בעריכה הראשונה",
"tog-fancysig": "התייחסות לחתימה כקוד ויקי (ללא קישור אוטומטי)",
"tog-uselivepreview": "שימוש בתצוגה מקדימה מהירה",
"tog-forceeditsummary": "הצגת אזהרה בעת הכנסת תקציר עריכה ריק",
- "tog-watchlisthideown": "×\94סתרת ×\94ער×\99×\9b×\95ת ש×\9c×\99 ×\91רש×\99×\9eת ×\94×\9eעק×\91",
+ "tog-watchlisthideown": "הסתרת עריכות שלי ברשימת המעקב",
"tog-watchlisthidebots": "הסתרת עריכות של בוטים ברשימת המעקב",
"tog-watchlisthideminor": "הסתרת עריכות משניות ברשימת המעקב",
"tog-watchlisthideliu": "הסתרת עריכות של משתמשים רשומים ברשימת המעקב",
"tog-watchlisthideanons": "הסתרת עריכות של משתמשים אנונימיים ברשימת המעקב",
"tog-watchlisthidepatrolled": "הסתרת עריכות בדוקות ברשימת המעקב",
"tog-watchlisthidecategorization": "הסתרת שינויים בקטגוריות של דפים",
- "tog-ccmeonemails": "×\9cש×\9c×\95×\97 ×\90×\9c×\99×\99 ×\94עתק×\99×\9d ש×\9c ×\94×\95×\93×¢×\95ת ×\93×\95×\90\"×\9c שש×\9c×\97ת×\99 ×\9c×\9eשת×\9eש×\99×\9d ×\90×\97רים",
- "tog-diffonly": "×\91×\99×\98×\95×\9c ×\94צ×\92ת ת×\95×\9b×\9f ×\94×\93×£ ×\9eת×\97ת ×\9c×\94ש×\95×\95×\90ת הגרסאות",
+ "tog-ccmeonemails": "×\9cש×\9c×\95×\97 ×\90×\9c×\99×\99 ×\94עתק×\99×\9d ש×\9c ×\94×\95×\93×¢×\95ת ×\93×\95×\90\"×\9c ש×\90× ×\99 {{GENDER:|ש×\95×\9c×\97|ש×\95×\9c×\97ת}} ×\9c×\9eשת×\9eשים",
+ "tog-diffonly": "×\9c×\90 ×\9c×\94צ×\99×\92 ×\90ת ת×\95×\9b×\9f ×\94×\93×£ ×\9eת×\97ת ×\9c×\94×\91×\93×\9c×\99×\9d ×\91×\99×\9f הגרסאות",
"tog-showhiddencats": "הצגת קטגוריות מוסתרות",
- "tog-norollbackdiff": "×\94ש×\9e×\98ת ההבדלים בין הגרסאות לאחר ביצוע שחזור",
+ "tog-norollbackdiff": "×\9c×\90 ×\9c×\94צ×\99×\92 ×\90ת ההבדלים בין הגרסאות לאחר ביצוע שחזור",
"tog-useeditwarning": "הצגת אזהרה בעת עזיבת דף עריכה עם שינויים שטרם נשמרו",
"tog-prefershttps": "תמיד להשתמש בתקשורת מאובטחת לאחר הכניסה לחשבון",
"underline-always": "תמיד",
"underline-never": "לעולם לא",
- "underline-default": "×\91ר×\99רת ×\94×\9e×\97×\93×\9c ש×\9c ×\94×¢×\99צ×\95×\91 ×\90×\95 ש×\9c ×\94×\93פ×\93פ×\9f",
+ "underline-default": "ברירת המחדל של העיצוב או הדפדפן",
"editfont-style": "הגופן בתיבת העריכה:",
"editfont-default": "ברירת המחדל של הדפדפן",
"editfont-monospace": "גופן ברוחב קבוע (monospace)",
"mar": "מרץ",
"apr": "אפר'",
"may": "מאי",
- "jun": "יונ'",
- "jul": "יול'",
+ "jun": "יוני",
+ "jul": "יולי",
"aug": "אוג'",
"sep": "ספט'",
"oct": "אוק'",
"category_header": "דפים בקטגוריה \"$1\"",
"subcategories": "קטגוריות משנה",
"category-media-header": "קובצי מדיה בקטגוריה \"$1\"",
- "category-empty": "'''קטגוריה זו אינה כוללת דפים או קובצי מדיה.'''",
+ "category-empty": "<strong>קטגוריה זו אינה כוללת דפים או קובצי מדיה.</strong>",
"hidden-categories": "{{PLURAL:$1|קטגוריה מוסתרת|קטגוריות מוסתרות}}",
"hidden-category-category": "קטגוריות מוסתרות",
"category-subcat-count": "{{PLURAL:$2|קטגוריה זו כוללת את קטגוריית המשנה הבאה בלבד.|קטגוריה זו כוללת את {{PLURAL:$1|קטגוריית המשנה המוצגת להלן|$1 קטגוריות המשנה המוצגות להלן}}, וכוללת בסך־הכול $2 קטגוריות משנה.}}",
"navigation": "ניווט",
"and": " וגם",
"qbfind": "חיפוש",
- "qbbrowse": "×\93פ×\93×\95×£",
+ "qbbrowse": "× ×\99×\95×\95×\98",
"qbedit": "עריכה",
"qbpageoptions": "אפשרויות דף",
"qbmyoptions": "האפשרויות שלי",
"searchbutton": "חיפוש",
"go": "הצגה",
"searcharticle": "לדף",
- "history": "היסטוריית הדף",
+ "history": "×\94×\99ס×\98×\95ר×\99×\99ת ×\94×\92רס×\90×\95ת ש×\9c ×\94×\93×£",
"history_short": "היסטוריה",
"updatedmarker": "עודכן מאז ביקורך האחרון",
- "printableversion": "×\92רסת הדפסה",
+ "printableversion": "×\92רס×\94 ×\9cהדפסה",
"permalink": "קישור קבוע",
"print": "גרסה להדפסה",
"view": "צפייה",
"redirectedfrom": "(הופנה מהדף $1)",
"redirectpagesub": "דף הפניה",
"redirectto": "הפניה ל:",
- "lastmodifiedat": "×\93×£ ×\96×\94 ש×\81×\95Ö¼× ×\94 ×\9c×\90×\97ר×\95× ×\94 ×\91Ö¾$1, ×\91שע×\94 $2.",
+ "lastmodifiedat": "דף זה שוּנה לאחרונה ב־$1, בשעה $2.",
"viewcount": "דף זה נצפה {{PLURAL:$1|פעם אחת|פעמיים|$1 פעמים}}.",
"protectedpage": "דף מוגן",
"jumpto": "קפיצה אל:",
"currentevents-url": "Project:אקטואליה",
"disclaimers": "הבהרה משפטית",
"disclaimerpage": "Project:הבהרה משפטית",
- "edithelp": "×¢×\96ר×\94 ×\9cעריכה",
+ "edithelp": "×¢×\96ר×\94 ×\91עריכה",
"helppage-top-gethelp": "עזרה",
"mainpage": "עמוד ראשי",
"mainpage-description": "עמוד ראשי",
"viewsourceold": "הצגת מקור",
"editlink": "עריכה",
"viewsourcelink": "הצגת מקור",
- "editsectionhint": "עריכת פסקה: $1",
+ "editsectionhint": "עריכת פסקה: \"$1\"",
"toc": "תוכן עניינים",
"showtoc": "הצגה",
"hidetoc": "הסתרה",
"confirmable-confirm": "האם {{GENDER:$1|ברצונך}} להמשיך?",
"confirmable-yes": "כן",
"confirmable-no": "לא",
- "thisisdeleted": "×\9cש×\97×\96ר ×\90×\95 ×\9c×\94צ×\99×\92 $1?",
+ "thisisdeleted": "×\9c×\94צ×\99×\92 ×\90×\95 ×\9cש×\97×\96ר $1?",
"viewdeleted": "להציג $1?",
"restorelink": "{{PLURAL:$1|גרסה מחוקה אחת|$1 גרסאות מחוקות}}",
"feedlinks": "הזנה:",
"filenotfound": "הקובץ \"$1\" לא נמצא.",
"unexpected": "ערך לא צפוי: \"$1\"=\"$2\"",
"formerror": "שגיאה: לא ניתן היה לשלוח את הטופס.",
- "badarticleerror": "×\9c×\90 × ×\99ת×\9f ×\9c×\91צע פע×\95×\9c×\94 ×\96×\95 בדף זה.",
+ "badarticleerror": "×\9c×\90 × ×\99ת×\9f ×\9c×\91צע ×\90ת ×\94פע×\95×\9c×\94 ×\94×\96×\90ת בדף זה.",
"cannotdelete": "לא ניתן היה למחוק את הדף או הקובץ \"$1\".\nייתכן שהוא כבר נמחק על־ידי משתמש אחר.",
"cannotdelete-title": "לא ניתן למחוק את הדף \"$1\"",
"delete-hook-aborted": "המחיקה הופסקה על־ידי מבנה Hook.\nלא ניתן הסבר.",
"perfcachedts": "המידע הבא הוא עותק שמור בזיכרון המטמון של המידע, שעודכן לאחרונה ב־$1. לכל היותר {{PLURAL:$4|תוצאה אחת נשמרת|$4 תוצאות נשמרות}} בזיכרון המטמון.",
"querypage-no-updates": "העדכונים לדף זה כרגע מופסקים, והמידע לא יעודכן באופן שוטף.",
"viewsource": "הצגת מקור",
- "viewsource-title": "הצגת המקור של $1",
+ "viewsource-title": "הצגת המקור של הדף \"$1\"",
"actionthrottled": "הפעולה הוגבלה",
"actionthrottledtext": "כאמצעי נגד שימוש לרעה, קיימת מגבלה על ביצוע פעולה זו פעמים רבות מדי בזמן קצר, וחרגת מהמגבלה הזאת.\nנא לנסות שוב בעוד מספר דקות.",
"protectedpagetext": "דף זה מוגן כדי למנוע עריכה ופעולות אחרות.",
"viewsourcetext": "באפשרותכם לצפות בטקסט המקור של הדף ולהעתיקו.",
"viewyourtext": "באפשרותך לצפות בטקסט המקור של <strong>העריכות שלך</strong> בדף הזה ולהעתיקו.",
- "protectedinterface": "×\93×£ ×\96×\94 ×\94×\95×\90 ×\90×\97×\93 ×\9eס×\93רת ×\93פ×\99×\9d ×\94×\9eספק×\99×\9d ×\94×\95×\93×¢×\95ת ×\9eער×\9bת ×\9cת×\95×\9b× ×\94 ×\91×\90תר ×\95×\99ק×\99 ×\96×\94, ×\95×\9e×\95×\92×\9f ×\9b×\93×\99 ×\9c×\9e× ×\95×¢ ×\94ש×\97ת×\95ת.\n×\9b×\93×\99 ×\9c×\94×\95ס×\99×£ ×\90×\95 ×\9c×©× ×\95ת תר×\92×\95×\9e×\99×\9d ×\91×\9b×\9c ×\90תר×\99 ×\94×\95×\95×\99ק×\99, ×\90× ×\90 ×\94שת×\9eש×\95 ב־[//translatewiki.net/ translatewiki.net], פרויקט התרגום של מדיה־ויקי.",
- "editinginterface": "<strong>אזהרה:</strong> הדף שאתם עורכים הוא אחד הדפים המספקים הודעות מערכת לתוכנה.\nשינויים בדף זה ישפיעו על תצוגת ממשק המשתמש של משתמשים אחרים באתר ויקי זה.",
- "translateinterface": "כדי להוסיף או לשנות תרגומים עבור כל אתרי הוויקי, יש להשתמש ב־[//translatewiki.net/ translatewiki.net], פרויקט התרגום של מדיה־ויקי.",
+ "protectedinterface": "×\93×£ ×\96×\94 ×\94×\95×\90 ×\90×\97×\93 ×\9eס×\93רת ×\93פ×\99×\9d ×\94×\9eספק×\99×\9d ×\94×\95×\93×¢×\95ת ×\9eער×\9bת ×\9cת×\95×\9b× ×\94 ש×\9eפע×\99×\9c×\94 ×\90ת {{SITENAME}}, ×\95×\94×\95×\90 ×\9e×\95×\92×\9f ×\9b×\93×\99 ×\9c×\9e× ×\95×¢ ×\94ש×\97ת×\95ת.\n×\9b×\93×\99 ×\9c×\94×\95ס×\99×£ ×\90×\95 ×\9c×©× ×\95ת תר×\92×\95×\9e×\99×\9d ש×\9c ×\94×\95×\93×¢×\95ת ×\9eער×\9bת ×¢×\91×\95ר ×\9b×\9c ×\90תר×\99 ×\94×\95×\95×\99ק×\99, ×\99ש ×\9c×\94שת×\9eש ב־[//translatewiki.net/ translatewiki.net], פרויקט התרגום של מדיה־ויקי.",
+ "editinginterface": "<strong>אזהרה:</strong> הדף ש{{GENDER:|אתה עורך|את עורכת|אתם עורכים}} הוא אחד הדפים המספקים הודעות מערכת לתוכנה שמפעילה את {{SITENAME}}.\nשינויים בדף הזה ישפיעו על תצוגת ממשק המשתמש של משתמשים אחרים באתר.",
+ "translateinterface": "×\9b×\93×\99 ×\9c×\94×\95ס×\99×£ ×\90×\95 ×\9c×©× ×\95ת תר×\92×\95×\9e×\99×\9d ש×\9c ×\94×\95×\93×¢×\95ת ×\9eער×\9bת ×¢×\91×\95ר ×\9b×\9c ×\90תר×\99 ×\94×\95×\95×\99ק×\99, ×\99ש ×\9c×\94שת×\9eש ×\91Ö¾[//translatewiki.net/ translatewiki.net], פר×\95×\99ק×\98 ×\94תר×\92×\95×\9d ש×\9c ×\9e×\93×\99×\94Ö¾×\95×\99ק×\99.",
"cascadeprotected": "דף זה מוגן מעריכה כי הוא מוכלל {{PLURAL:$1|בדף הבא, שמופעלת עליו|בדפים הבאים, שמופעלת עליהם}} הגנה מדורגת:\n$2",
"namespaceprotected": "אין לך הרשאה לערוך דפים במרחב השם <strong>$1</strong>.",
"customcssprotected": "אינך מורשה לערוך דף CSS זה כיוון שהוא כולל הגדרות אישיות של משתמש אחר.",
"virus-badscanner": "הגדרות שגויות: סורק הווירוסים אינו ידוע: ''$1''",
"virus-scanfailed": "הסריקה נכשלה (קוד: $1)",
"virus-unknownscanner": "אנטי־וירוס בלתי ידוע:",
- "logouttext": "<strong>×\99צ×\90ת×\9d ×\96×\94 עת×\94 ×\9e×\94×\97ש×\91×\95×\9f.</strong>\n\nש×\99×\9e×\95 ×\9c×\91 ×\9b×\99 ×\99×\99ת×\9b×\9f ש×\93פ×\99×\9d ×\90×\97×\93×\99×\9d ×\99×\9eש×\99×\9b×\95 ×\9c×\94×\99×\95ת ×\9e×\95צ×\92×\99×\9d ×\9b×\90×\99×\9c×\95 ×\90ת×\9d ×¢×\93×\99×\99×\9f ×\9e×\97×\95×\91ר×\99×\9d ×\9c×\97ש×\91×\95×\9f עד שתנקו את המטמון של הדפדפן שלכם.",
+ "logouttext": "<strong>×\99צ×\90ת×\9d ×\9e×\94×\97ש×\91×\95×\9f.</strong>\n\nש×\99×\9e×\95 ×\9c×\91 ש×\99×\99ת×\9b×\9f ש×\93פ×\99×\9d ×\9eס×\95×\99×\9e×\99×\9d ×\99×\9eש×\99×\9b×\95 ×\9c×\94×\99×\95ת ×\9e×\95צ×\92×\99×\9d ×\9b×\90×\99×\9c×\95 ×\90ת×\9d ×¢×\93×\99×\99×\9f ×\9e×\97×\95×\91ר×\99×\9d ×\9c×\97ש×\91×\95×\9f, עד שתנקו את המטמון של הדפדפן שלכם.",
"cannotlogoutnow-title": "לא ניתן לצאת מהחשבון עכשיו",
"cannotlogoutnow-text": "היציאה אינה אפשרית בעת שימוש ב{{GRAMMAR:תחילית|$1}}.",
"welcomeuser": "ברוך בואך, $1!",
"password-change-forbidden": "אין באפשרותך לשנות סיסמאות באתר זה.",
"externaldberror": "אירעה שגיאת אימות בבסיס הנתונים, או שאינך מורשה לעדכן את החשבון החיצוני שלך.",
"login": "כניסה לחשבון",
+ "login-security": "אימות הזהות שלך",
"nav-login-createaccount": "כניסה לחשבון / הרשמה",
"userlogin": "כניסה לחשבון / הרשמה",
"userloginnocreate": "כניסה לחשבון",
"userlogin-resetpassword-link": "שכחת את הסיסמה?",
"userlogin-helplink2": "עזרה בכניסה לחשבון",
"userlogin-loggedin": "אתם כבר מחוברים לחשבון {{GENDER:$1|$1}}.\nהשתמשו בטופס שלהלן כדי להתחבר לחשבון אחר.",
+ "userlogin-reauth": "עליכם להיכנס לחשבון כדי לאמת שאתם באמת {{GENDER:$1|$1}}.",
"userlogin-createanother": "יצירת חשבון אחר",
"createacct-emailrequired": "כתובת דוא\"ל",
"createacct-emailoptional": "כתובת דוא\"ל (לא חובה)",
"createacct-email-ph": "יש להקליד את כתובת הדוא\"ל שלך",
"createacct-another-email-ph": "יש להקליד כתובת דוא\"ל",
"createaccountmail": "שימוש בסיסמה זמנית אקראית ושליחתה לכתובת הדוא\"ל שצוינה",
+ "createaccountmail-help": "יכול לשמש ליצירת חשבון לאדם אחר בלי לברר מה הססמה.",
"createacct-realname": "שם אמיתי (לא חובה)",
"createaccountreason": "סיבה:",
"createacct-reason": "סיבה",
"createacct-reason-ph": "סיבה ליצירת חשבון נוסף",
+ "createacct-reason-help": "הודעה שמוצגת ביומן רישום המשתמשים",
"createacct-submit": "יצירת החשבון שלך",
"createacct-another-submit": "יצירת חשבון",
+ "createacct-continue-submit": "המשך ביצירת החשבון",
+ "createacct-another-continue-submit": "המשך ביצירת החשבון",
"createacct-benefit-heading": "אנשים כמוך יוצרים את {{SITENAME}}.",
"createacct-benefit-body1": "{{PLURAL:$1|עריכה|עריכות}}",
"createacct-benefit-body2": "{{PLURAL:$1|דף|דפים}}",
"badretype": "הסיסמאות שהזנת אינן מתאימות.",
"usernameinprogress": "יצירת חשבון עבור שם המשתמש הזה כבר התחילה.\nנא להמתין.",
"userexists": "שם המשתמש שבחרתם כבר נמצא בשימוש.\nאנא בחרו שם אחר.",
- "loginerror": "ש×\92×\99×\90×\94 ×\91×\9b× ×\99ס×\94 ×\9c×\90תר",
+ "loginerror": "ש×\92×\99×\90×\94 ×\91×\9b× ×\99ס×\94 ×\9c×\97ש×\91×\95×\9f",
"createacct-error": "שגיאה ביצירת חשבון",
"createaccounterror": "לא ניתן היה ליצור את החשבון: $1",
- "nocookiesnew": "חשבון המשתמש שלכם נוצר, אך לא נכנסתם כמשתמשים רשומים.\nכדי להכניס משתמשים למערכת עושה {{SITENAME}} שימוש בעוגיות.\nבדפדפן שלכם העוגיות מבוטלות.\nאנא הפעילו אותן מחדש, ולאחר מכן תוכלו להיכנס למערכת עם שם המשתמש והסיסמה החדשים שלכם.",
- "nocookieslogin": "{{SITENAME}} משתמש בעוגיות כדי להכניס משתמשים למערכת.\nבדפדפן שלכם העוגיות מבוטלות.\nאנא הפעילו אותן מחדש ונסו שוב.",
- "nocookiesfornew": "חשבון המשתמש לא נוצר, כיוון שלא יכולנו לוודא את מקורו.\nודאו שהעוגיות מופעלות בדפדפן שלכם, העלו מחדש דף זה ונסו שוב.",
- "noname": "לא הכנסת שם משתמש תקין",
+ "nocookiesnew": "החשבון שלך נוצר, אבל לא נכנסת לחשבון.\n{{SITENAME}} עושה שימוש בעוגיות (cookies) כדי להכניס משתמשים למערכת.\nבדפדפן שלך העוגיות מבוטלות.\nיש להפעיל אותן, ורק לאחר מכן להיכנס לחשבון עם שם המשתמש והסיסמה שלך.",
+ "nocookieslogin": "{{SITENAME}} עושה שימוש בעוגיות (cookies) כדי להכניס משתמשים למערכת.\nבדפדפן שלך העוגיות מבוטלות.\nיש להפעיל אותן ולאחר מכן לנסות שוב.",
+ "nocookiesfornew": "חשבון המשתמש לא נוצר, משום שלא יכולנו לאמת את המקור שלו.\nנא לוודא שהעוגיות (cookies) בדפדפן שלך מופעלות, ורק לאחר מכן לטעון מחדש את הדף הזה ולנסות שוב.",
+ "createacct-loginerror": "החשבון נוצר בהצלחה, אבל לא ניתן היה להיכנס אליו באופן אוטומטי. נא [[Special:UserLogin|להיכנס באופן ידני]].",
+ "noname": "לא הזנת שם משתמש תקין.",
"loginsuccesstitle": "נכנסת לחשבון",
"loginsuccess": "'''נכנסת ל{{grammar:תחילית|{{SITENAME}}}} בשם \"$1\".'''",
- "nosuchuser": "×\90×\99×\9f ×\9eשת×\9eש ×\91ש×\9d \"$1\".\n×\90× ×\90 ×\95×\93×\90×\95 ש×\94×\90×\99×\95ת × ×\9b×\95×\9f (×\9b×\95×\9c×\9c ×\90×\95ת×\99×\95ת ר×\99ש×\99×\95ת ×\95ק×\98× ×\95ת), ×\90×\95 [[Special:UserLogin/signup|צרו חשבון חדש]].",
- "nosuchusershort": "×\90×\99×\9f ×\9eשת×\9eש ×\91ש×\9d \"$1\".\n×\90× ×\90 ×\95×\93×\90×\95 שהאיות נכון.",
+ "nosuchuser": "×\90×\99×\9f ×\9eשת×\9eש ×\91ש×\9d \"$1\".\nש×\99×\9e×\95 ×\9c×\91 שש×\9e×\95ת ×\9eשת×\9eש×\99×\9d ×\94×\9d ת×\9c×\95×\99×\99־ר×\99ש×\99×\95ת.\n×\90× ×\90 ×\91Ö´×\93ק×\95 ×\90ת ×\94×\90×\99×\95ת ש×\9c ש×\9d ×\94×\9eשת×\9eש, ×\90×\95 [[Special:CreateAccount|צרו חשבון חדש]].",
+ "nosuchusershort": "×\90×\99×\9f ×\9eשת×\9eש ×\91ש×\9d \"$1\".\n× ×\90 ×\9c×\95×\95×\93×\90 שהאיות נכון.",
"nouserspecified": "יש לציין שם משתמש.",
"login-userblocked": "משתמש זה חסום. אינכם מורשים להיכנס לחשבון.",
- "wrongpassword": "×\94ס×\99ס×\9e×\94 ש×\94ק×\9c×\93ת×\9d ש×\92×\95×\99×\94.\n×\90× ×\90 × ×¡×\95 שוב.",
- "wrongpasswordempty": "×\94ס×\99ס×\9e×\94 ש×\94ק×\9c×\93ת×\9d ר×\99ק×\94.\n×\90× ×\90 × ×¡×\95 שוב.",
+ "wrongpassword": "×\94ס×\99ס×\9e×\94 ש×\94×\96× ×ª ש×\92×\95×\99×\94.\n× ×\90 ×\9c× ×¡×\95ת שוב.",
+ "wrongpasswordempty": "×\94ס×\99ס×\9e×\94 ש×\94×\96× ×ª ר×\99ק×\94.\n× ×\90 ×\9c× ×¡×\95ת שוב.",
"passwordtooshort": "סיסמאות חייבות להיות באורך {{PLURAL:$1|תו אחד|$1 תווים}} לפחות.",
"passwordtoolong": "סיסמאות אינן יכולות להיות ארוכות {{PLURAL:$1|מתו אחד|מ־$1 תווים}}.",
"passwordtoopopular": "לא ניתן להשתמש בסיסמאות נפוצות. יש לבחור סיסמה ייחודית יותר.",
"login-migrated-generic": "חשבון המשתמש שלך הועבר, ושם המשתמש שלך כבר לא קיים באתר ויקי זה.",
"loginlanguagelabel": "שפה: $1",
"suspicious-userlogout": "בקשתך לצאת מהחשבון נדחתה כיוון שנראה שהיא נשלחה על־ידי דפדפן שבור או שרת פרוקסי עם זיכרון מטמון.",
- "createacct-another-realname-tip": "×\94ש×\9d ×\94×\90×\9e×\99ת×\99 ×\94×\95×\90 ×\90×\95פצ×\99×\95× ×\90×\9c×\99.\n×\90×\9d ת×\91×\97ר×\95 ×\9cספק×\95, ×\94×\95×\90 ×\99ש×\9eש ×\9c×\99×\99×\97×\95ס ×¢×\91×\95×\93ת ×\94×\9eשת×\9eש ×\90×\9c×\99×\95.",
+ "createacct-another-realname-tip": "×\9c×\90 ×\97×\95×\91×\94 ×\9c×\9e×\9c×\90 ×\90ת ×\94ש×\9d ×\94×\90×\9e×\99ת×\99.\n×\90×\9d ס×\95פק, ×\94×\95×\90 עש×\95×\99 ×\9cש×\9eש ×\9b×\93×\99 ×\9c×\99×\99×\97ס ×\9c×\9a ×\90ת ×¢×\91×\95×\93ת×\9a.",
"pt-login": "כניסה לחשבון",
"pt-login-button": "כניסה לחשבון",
+ "pt-login-continue-button": "המשך כניסה לחשבון",
"pt-createaccount": "יצירת חשבון",
"pt-userlogout": "יציאה מהחשבון",
"php-mail-error-unknown": "שגיאה לא ידועה בפונקציה mail() של PHP",
"botpasswords-invalid-name": "שם המשתמש שניתן אינו מכיל את תו הפרדת ססמאות הבוט (\"$1\").",
"botpasswords-not-exist": "למשתמש \"$1\" אין ססמת בוט בשם \"$2\".",
"resetpass_forbidden": "לא ניתן לשנות סיסמאות.",
+ "resetpass_forbidden-reason": "לא ניתן לשנות את הסיסמאות: $1",
"resetpass-no-info": "נדרשת כניסה לחשבון כדי לגשת לדף זה באופן ישיר.",
"resetpass-submit-loggedin": "שינוי סיסמה",
"resetpass-submit-cancel": "ביטול",
"passwordreset-emailsentusername": "אם יש כתובת דואר אלקטרוני שמשויכת לשם המשתמש הזה, אז יישלח דואר אלקטרוני לאיפוס הסיסמה.",
"passwordreset-emailsent-capture": "נשלח דואר אלקטרוני לאיפוס הסיסמה, והוא מוצג להלן.",
"passwordreset-emailerror-capture": "נוצר דואר אלקטרוני לאיפוס הסיסמה, והוא מוצג להלן, אך שליחתו ל{{GENDER:$2|משתמש|משתמשת}} נכשלה: $1",
+ "passwordreset-emailsent-capture2": "{{PLURAL:$1|דוא\"ל איפוס הסיסמה נשלח|הודעות דוא\"ל של איפוס הסיסמה נשלחו}}. {{PLURAL:$1|שם המשתמשים והסיסמה מוצגים|רשימה של שמות המשתמשים והסיסמאות מוצגת}} להלן.",
+ "passwordreset-emailerror-capture2": "לא ניתן היה לשלוח דוא\"ל ל{{GENDER:$2|משתמש|משתמשת}}: $1 {{PLURAL:$3|שם המשתמש והסיסמה מוצגים|רשימה של שמות המשתמשים והסיסמאות מוצגת}} להלן.",
+ "passwordreset-nocaller": "לא סופק הקורא הנדרש",
+ "passwordreset-nosuchcaller": "הקורא אינו קיים: $1",
+ "passwordreset-ignored": "איפוס הסיסמה לא בוצע. ייתכן שלא הוגדר ספק.",
+ "passwordreset-invalideamil": "כתובת דוא\"ל לא תקינה",
+ "passwordreset-nodata": "לא סופק שם משתמש או כתובת דוא\"ל",
"changeemail": "שינוי או הסרת כתובת דוא\"ל",
"changeemail-header": "יש למלא את הטופס הזה כדי לשנות את כתובת הדוא\"ל שלך. אם ברצונך להימנע משיוך כתובת דוא\"ל כלשהי לחשבון שלך, יש להשאיר את שדה כתובת הדוא\"ל החדשה ריק בעת שליחת הטופס.",
"changeemail-passwordrequired": "יש להקליד את הסיסמה שלך כדי לאשר את השינוי.",
"subject": "נושא:",
"minoredit": "זוהי עריכה משנית",
"watchthis": "מעקב אחרי דף זה",
- "savearticle": "ש×\9e×\99ר×\94",
+ "savearticle": "ש×\9e×\99רת ×\94×\93×£",
"publishpage": "פרסום הדף",
"preview": "תצוגה מקדימה",
"showpreview": "תצוגה מקדימה",
"accmailtitle": "הסיסמה נשלחה",
"accmailtext": "סיסמה אקראית עבור [[User talk:$1|$1]] נשלחה אל $2. ניתן לשנותה בדף '''[[Special:ChangePassword|שינוי הסיסמה]]''' לאחר הכניסה.",
"newarticle": "(חדש)",
- "newarticletext": "הגעתם לדף שעדיין אינו קיים.\nכדי ליצור את הדף הזה, התחילו להקליד בתיבת הטקסט שלמטה (ראו את [$1 דף העזרה] למידע נוסף).\nאם הגעתם לכאן בטעות, לחצו על כפתור ה<strong>חזרה</strong> (Back) בדפדפן שלכם.",
- "anontalkpagetext": "----\n<em>זהו דף שיחה של משתמש אנונימי שעדיין לא יצר חשבון במערכת, או שהוא לא משתמש בו.</em>\nלכן עלינו להשתמש בכתובת ה־IP המספרית כדי לזהותו.\nייתכן שכתובת IP זו תהיה משותפת למספר משתמשים.\nאם אתם משתמשים אנונימיים ומרגישים שקיבלתם הודעות בלתי רלוונטיות, אנא [[Special:UserLogin/signup|צרו חשבון]] או [[Special:UserLogin|היכנסו לחשבון]] כדי להימנע מבלבול עתידי עם משתמשים אנונימיים נוספים.",
+ "newarticletext": "{{GENDER:|הגעת|הגעת|הגעתם}} לדף שעדיין אינו קיים.\nכדי ליצור את הדף הזה, {{GENDER:|התחל|התחילי|התחילו}} להקליד בתיבת הטקסט שלמטה ({{GENDER:|ראה|ראי|ראו}} את [$1 דף העזרה] למידע נוסף).\nאם {{GENDER:|הגעת|הגעת|הגעתם}} לכאן בטעות, {{GENDER:|לחץ|לחצי|לחצו}} על כפתור ה<strong>חזרה</strong> (Back) בדפדפן {{GENDER:|שלך|שלך|שלכם}}.",
+ "anontalkpagetext": "----\n<em>זהו דף שיחה של משתמש אנונימי שעדיין לא יצר חשבון במערכת, או שהוא לא משתמש בו.</em>\nלכן עלינו להשתמש בכתובת ה־IP המספרית כדי לזהותו.\nייתכן שכתובת IP זו תהיה משותפת למספר משתמשים.\nאם אתם משתמשים אנונימיים ומרגישים שקיבלתם הודעות בלתי רלוונטיות, אנא [[Special:CreateAccount|צרו חשבון]] או [[Special:UserLogin|היכנסו לחשבון]] כדי להימנע מבלבולים עתידיים עם משתמשים אנונימיים נוספים.",
"noarticletext": "אין כרגע טקסט בדף הזה.\nבאפשרותך [[Special:Search/{{PAGENAME}}|לחפש את כותרת הדף]] בדפים אחרים,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} לחפש את הדף ביומנים],\nאו [{{fullurl:{{FULLPAGENAME}}|action=edit}} ליצור את הדף]</span>.",
"noarticletext-nopermission": "אין כרגע טקסט בדף הזה.\nבאפשרותך [[Special:Search/{{PAGENAME}}|לחפש את כותרת הדף]] בדפים אחרים או <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} לחפש את הדף ביומנים]</span>, אך אין לך הרשאה ליצור את הדף.",
- "missing-revision": "גרסה #$1 של הדף \"{{FULLPAGENAME}}\" אינה קיימת.\n\nזה נגרם בדרך כלל על־ידי לחיצה על קישור ישן לגרסה קודמת של דף שנמחק.\nאפשר למצוא פרטים ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
- "userpage-userdoesnotexist": "×\97ש×\91×\95×\9f ×\94×\9eשת×\9eש \"$1\" ×\90×\99× ×\95 רש×\95×\9d.\n×\90× ×\90 ×\91Ö´Ö¼×\93ק×\95 ×\90×\9d ×\91רצ×\95× ×\9b×\9d ליצור/לערוך את הדף הזה.",
+ "missing-revision": "גרסה #$1 של הדף \"{{FULLPAGENAME}}\" אינה קיימת.\n\nזה נגרם בדרך־כלל עקב לחיצה על קישור ישן לגרסה של דף שנמחק.\nאפשר למצוא פרטים ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
+ "userpage-userdoesnotexist": "×\97ש×\91×\95×\9f ×\94×\9eשת×\9eש \"$1\" ×\90×\99× ×\95 רש×\95×\9d.\n× ×\90 ×\9c×\91×\93×\95ק ×\90×\9d ×\91רצ×\95× ×\9a ליצור/לערוך את הדף הזה.",
"userpage-userdoesnotexist-view": "חשבון המשתמש \"$1\" אינו רשום.",
"blocked-notice-logextract": "{{GENDER:$1|המשתמש הזה חסום|המשתמשת הזו חסומה}} כרגע.\nהפעולה האחרונה ביומן החסימות מוצגת להלן:",
"clearyourcache": "<strong>הערה:</strong> לאחר השמירה, ייתכן שיהיה צורך לנקות את זיכרון המטמון (cache) של הדפדפן כדי להבחין בשינויים.\n* <strong>פיירפוקס / ספארי:</strong> להחזיק את המקש <em>Shift</em> בעת לחיצה על <strong>טעינה מחדש</strong> (Reload), או ללחוץ על צירוף המקשים <em>Ctrl-F5</em> או <em>Ctrl-R</em> (במחשב מק: <em dir=\"ltr\">⌘-R</em>)\n* <strong>גוגל כרום:</strong> ללחוץ על צירוף המקשים <em>Ctrl-Shift-R</em> (במחשב מק: <em dir=\"ltr\">⌘-Shift-R</em>)\n* <strong>אינטרנט אקספלורר:</strong> ללחוץ ולהחזיק את המקש <em>Ctrl</em> בעת לחיצה על <strong>רענן</strong> (Refresh), או ללחוץ על צירוף המקשים <em>Ctrl-F5</em>\n* <strong>אופרה:</strong> לפתוח <em>תפריט ← הגדרות</em> (במחשב מק <em>Opera ← העדפות</em>) ואז ללחוץ על <em>פרטיות ואבטחה ← מחק היסטוריית גלישה ← Cached images and files</em>.",
"userinvalidcssjstitle": "'''אזהרה:''' העיצוב \"$1\" אינו קיים.\nדפי .css ו־.js מותאמים אישית משתמשים בכותרת עם אותיות קטנות – למשל, {{ns:user}}:דוגמה/vector.css ולא {{ns:user}}:דוגמה/Vector.css.",
"updated": "(מעודכן)",
"note": "'''הערה:'''",
- "previewnote": "<strong>זִכרו שזו רק תצוגה מקדימה.</strong>\nהשינויים שלכם עדיין לא נשמרו!",
+ "previewnote": "<strong>{{GENDER:|זכור|זִכרי|זִכרו}} שזו רק תצוגה מקדימה.</strong>\nהשינויים {{GENDER:|שלך|שלך|שלכם}} עדיין לא נשמרו!",
"continue-editing": "מעבר לאזור העריכה",
"previewconflict": "תצוגה מקדימה זו מציגה כיצד ייראה הטקסט בחלון העריכה העליון, אם תבחרו לשמור אותו.",
"session_fail_preview": "מצטערים! לא ניתן לבצע את עריכתכם עקב אובדן מידע הכניסה.\n\nייתכן שנותקתם מהחשבון. <strong>אנא ודאו שאתם עדיין מחוברים לחשבון ונסו שוב.</strong>\nאם זה עדיין לא עובד, נסו [[Special:UserLogout|לצאת מהחשבון]] ולהיכנס אליו שנית, וודאו שהדפדפן שלכם מאפשר קבלת עוגיות מאתר זה.",
"session_fail_preview_html": "מצטערים! לא ניתן לבצע את עריכתם עקב אובדן מידע הכניסה.\n\n<em>כיוון שב{{grammar:תחילית|{{SITENAME}}}} אפשרות השימוש ב־HTML גולמי מופעלת, התצוגה המקדימה מוסתרת כדי למנוע התקפות JavaScript.</em>\n\n<strong>אם זהו ניסיון עריכה לגיטימי, אנא נסו שוב.</strong>\nאם זה עדיין לא עובד, נסו [[Special:UserLogout|לצאת מהחשבון]] ולהיכנס אליו שנית, וודאו שהדפדפן שלכם מאפשר קבלת עוגיות מאתר זה.",
"token_suffix_mismatch": "'''עריכתך נדחתה כיוון שהדפדפן שלך מחק את תווי הפיסוק באסימון העריכה.'''\nהעריכה נדחתה כדי למנוע בעיות כאלה בטקסט של הדף.\nלעתים התקלה מתרחשת עקב שימוש בשירות פרוקסי אנונימי פגום.",
- "edit_form_incomplete": "'''כמה חלקים מטופס העריכה לא הגיעו לשרת; בדקו היטב שעריכותיכם לא נפגעו ונסו שוב.'''",
- "editing": "עריכת הדף $1",
- "creating": "יצירת הדף $1",
- "editingsection": "עריכת הדף $1 (פסקה)",
- "editingcomment": "עריכת הדף $1 (פסקה חדשה)",
+ "edit_form_incomplete": "<strong>חלקים מסוימים מטופס העריכה לא הגיעו לשרת; אנא {{GENDER:|בדוק|בִדקי|בִדקו}} שהעריכה לא נפגעה ו{{GENDER:|נסה|נסי|נסו}} שוב.</strong>",
+ "editing": "עריכת הדף \"$1\"",
+ "creating": "יצירת הדף \"$1\"",
+ "editingsection": "עריכת הדף \"$1\" (פסקה)",
+ "editingcomment": "עריכת הדף \"$1\" (פסקה חדשה)",
"editconflict": "התנגשות עריכה: $1",
- "explainconflict": "×\9eשת×\9eש ×\90×\97ר ש×\99× ×\94 ×\90ת ×\94×\93×£ ×\9e×\90×\96 ש×\94ת×\97×\9cת×\9d ×\9cער×\95×\9a ×\90×\95ת×\95.\n×\97×\9c×\95×\9f ×\94ער×\99×\9b×\94 ×\94×¢×\9c×\99×\95×\9f ×\9e×\9b×\99×\9c ×\90ת ×\94×\98קס×\98 ×\91×\93×£ ×\9bפ×\99 ש×\94×\95×\90 עת×\94.\n×\94ש×\99× ×\95×\99×\99×\9d ש×\9c×\9b×\9d ×\9e×\95צ×\92×\99×\9d ×\91×\97×\9c×\95×\9f ×\94ער×\99×\9b×\94 ×\94ת×\97ת×\95×\9f.\n×¢×\9c×\99×\9b×\9d ×\9c×\9e×\96×\92 ×\90ת ×\94ש×\99× ×\95×\99×\99×\9d ש×\9c×\9b×\9d ×\9cת×\95×\9a ×\94×\98קס×\98 ×\94ק×\99×\99×\9d.\n'''רק''' הטקסט בחלון העריכה העליון יישמר כשתלחצו על \"{{int:savearticle}}\".",
+ "explainconflict": "×\9eשת×\9eש ×\90×\97ר ש×\99× ×\94 ×\90ת ×\94×\93×£ ×\9e×\90×\96 ש×\94ת×\97×\9cת×\9d ×\9cער×\95×\9a ×\90×\95ת×\95.\n×\97×\9c×\95×\9f ×\94ער×\99×\9b×\94 ×\94×¢×\9c×\99×\95×\9f ×\9eצ×\99×\92 ×\90ת ×\94×\98קס×\98 ×\91×\93×£ ×\9bפ×\99 ש×\94×\95×\90 ×\9bר×\92×¢.\n×\94ש×\99× ×\95×\99×\99×\9d ש×\9c×\9b×\9d ×\9e×\95צ×\92×\99×\9d ×\91×\97×\9c×\95×\9f ×\94ער×\99×\9b×\94 ×\94ת×\97ת×\95×\9f.\n×¢×\9c×\99×\9b×\9d ×\9c×\9e×\96×\92 ×\90ת ×\94ש×\99× ×\95×\99×\99×\9d ש×\9c×\9b×\9d ×\9cת×\95×\9a ×\94×\98קס×\98 ×\94ק×\99×\99×\9d.\n<strong>רק</strong> הטקסט בחלון העריכה העליון יישמר כשתלחצו על \"{{int:savearticle}}\".",
"yourtext": "הטקסט שלך",
"storedversion": "גרסה שמורה",
"nonunicodebrowser": "'''אזהרה: הדפדפן שלך אינו תואם לתקן יוניקוד.'''\nכדי למנוע בעיות הנוצרות כתוצאה מכך ולאפשר לך לערוך דפים בבטחה, תווים שאינם ב־ASCII יוצגו בתיבת העריכה כקודים הקסדצימליים.",
- "editingold": "'''אזהרה: אתם עורכים גרסה לא עדכנית של דף זה.'''\nאם תשמרו את הדף, כל השינויים שנעשו מאז גרסה זו יאבדו.",
+ "editingold": "<strong>אזהרה: אתם עורכים גרסה לא עדכנית של דף זה.</strong>\nאם תשמרו את הדף, כל השינויים שנעשו מאז גרסה זו יאבדו.",
"yourdiff": "הבדלים",
"copyrightwarning": "'''שימו לב:''' תרומתכם ל{{grammar:תחילית|{{SITENAME}}}} תפורסם תחת תנאי הרישיון $2 (ראו $1 לפרטים נוספים). אם אינכם רוצים שעבודתכם תהיה זמינה לעריכה על־ידי אחרים, שתופץ לעיני כול, ושאחרים יוכלו להעתיק ממנה בציון המקור – אל תפרסמו אותה פה. כמו־כן, אתם מבטיחים לנו כי כתבתם את הטקסט הזה בעצמכם, או העתקתם אותו ממקור שאינו מוגן בזכויות יוצרים. '''אל תעשו שימוש בחומר המוגן בזכויות יוצרים ללא רשות!'''",
"copyrightwarning2": "'''שימו לב:''' תורמים אחרים עשויים לערוך או אף להסיר את תרומתכם ל{{grammar:תחילית|{{SITENAME}}}}. אם אינכם רוצים שעבודתכם תהיה זמינה לעריכה על־ידי אחרים, אל תפרסמו אותה פה. כמו־כן, אתם מבטיחים לנו כי כתבתם את הטקסט הזה בעצמכם, או העתקתם אותו ממקור שאינו מוגן בזכויות יוצרים (ראו $1 לפרטים נוספים). '''אל תעשו שימוש בחומר המוגן בזכויות יוצרים ללא רשות!'''",
"edit-no-change": "המערכת התעלמה מעריכתך כיוון שלא נעשה שינוי בטקסט.",
"postedit-confirmation-created": "הדף נוצר.",
"postedit-confirmation-restored": "הדף שוחזר.",
- "postedit-confirmation-saved": "ער×\99×\9bתך נשמרה.",
+ "postedit-confirmation-saved": "×\94ער×\99×\9b×\94 ש×\9cך נשמרה.",
"edit-already-exists": "לא ניתן ליצור דף חדש.\nהוא כבר קיים.",
"defaultmessagetext": "טקסט ההודעה המקורי",
"content-failed-to-parse": "פענוח $2 כתוכן מסוג $1 נכשל: $3",
"invalid-content-data": "מידע שגוי על התוכן",
"content-not-allowed-here": "תוכן מסוג \"$1\" אינו מותר בדף [[$2]]",
- "editwarning-warning": "×¢×\96×\99×\91ת ×\93×£ ×\96×\94 עש×\95×\99×\94 ×\9c×\92ר×\95×\9d ×\9c×\90×\95×\91×\93×\9f ×\9b×\9c ×\94ש×\99× ×\95×\99×\99×\9d ש×\91×\99צעת×\9d.\n×\90×\9d ×\90ת×\9d ×\9e×\97×\95×\91ר×\99×\9d ×\9c×\97ש×\91×\95×\9f, ת×\95×\9b×\9c×\95 ×\9c×\91×\98×\9c ×\90×\96×\94ר×\94 ×\96×\95 ×\91×\97×\9cק \"{{int:prefs-editing}}\" ש×\91×\94×¢×\93פ×\95ת ש×\9c×\9b×\9d.",
+ "editwarning-warning": "×¢×\96×\99×\91ת ×\94×\93×£ ×\94×\96×\94 ×¢×\9c×\95×\9c×\94 ×\9c×\92ר×\95×\9d ×\9c×\9a ×\9c×\90×\91×\93 ×\90ת ×\9b×\9c ×\94ש×\99× ×\95×\99×\99×\9d ש×\91×\99צעת. ×\90×\9d ×\99ש ×\9c×\9a ×\97ש×\91×\95×\9f ×\91×\90תר, ×\91×\90פשר×\95ת×\9a ×\9c×\91×\98×\9c ×\90ת ×\94×\90×\96×\94ר×\94 ×\94×\96×\90ת ×\91×\97×\9cק \"{{int:prefs-editing}}\" ש×\91×\94×¢×\93פ×\95ת ש×\9c×\9a.",
"editpage-notsupportedcontentformat-title": "סוג התוכן אינו נתמך",
"editpage-notsupportedcontentformat-text": "תוכן מסוג $1 אינו נתמך על־ידי מודל התוכן $2.",
"content-model-wikitext": "קוד ויקי",
"parser-unstrip-loop-warning": "נמצאה לולאה בפריסה",
"parser-unstrip-recursion-limit": "עומק הרקורסיה של הפריסה עבר את המגבלה ($1)",
"converter-manual-rule-error": "התגלתה שגיאה בכלל המרת שפה ידני",
- "undo-success": "ניתן לבטל את העריכה.\nאנא בִּדקו את השוואת הגרסאות למטה כדי לוודא שזה אכן מה שאתם רוצים לעשות, ואז שִׁמרו את השינויים למטה כדי לסיים את ביטול העריכה.",
+ "undo-success": "ניתן לבטל את העריכה.\nאנא {{GENDER:|בדוק|בִדקי|בִדקו}} את השוואת הגרסאות שלהלן כדי לוודא שזה אכן מה ש{{GENDER:|אתה רוצה|את רוצה|אתם רוצים}} לעשות, ולאחר מכן {{GENDER:|שמור|שִמרי|שִמרו}} את השינויים למטה כדי לסיים את ביטול העריכה.",
"undo-failure": "לא ניתן היה לבטל את העריכה עקב התנגשות עם עריכות מאוחרות יותר.",
"undo-norev": "לא ניתן היה לבטל את העריכה כי היא אינה קיימת או כי היא נמחקה.",
"undo-nochange": "נראה שהעריכה כבר בוטלה.",
"history-feed-item-nocomment": "$1 ב־$2",
"history-feed-empty": "הדף המבוקש לא נמצא.\nייתכן שהוא נמחק, או ששמו שונה.\nבאפשרותך לנסות [[Special:Search|לחפש]] דפים רלוונטיים חדשים.",
"history-edit-tags": "עריכת התגיות של הגרסאות שנבחרו",
- "rev-deleted-comment": "(תקציר העריכה הוסר)",
- "rev-deleted-user": "(שם המשתמש הוסר)",
- "rev-deleted-event": "(פר×\98×\99×\9d ×\9e×\94×\99×\95×\9e×\9f ×\94×\95סר×\95)",
- "rev-deleted-user-contribs": "[שם המשתמש או כתובת ה־IP הוסרו – העריכה הוסתרה מדף התרומות]",
- "rev-deleted-text-permission": "×\92רסת ×\94×\93×£ ×\94×\96×\90ת <strong>× ×\9e×\97ק×\94</strong>.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ×¢×\9c ×\9b×\9a ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
- "rev-suppressed-text-permission": "×\92רסת ×\94×\93×£ ×\94×\96×\90ת <strong>×\94×\95×¢×\9c×\9e×\94</strong>.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ×¢×\9c ×\9b×\9a ב[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} יומן ההעלמות].",
- "rev-deleted-text-unhide": "×\92רסת ×\94×\93×£ ×\94×\96×\90ת <strong>× ×\9e×\97ק×\94</strong>.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ×¢×\9c ×\9b×\9a ×\91[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ×\99×\95×\9e×\9f ×\94×\9e×\97×\99ק×\95ת].\n×\90ת×\9d ×¢×\93×\99×\99×\9f ×\99×\9b×\95×\9c×\99×\9d [$1 ×\9cצפ×\95ת ×\91×\92רס×\94 ×\94×\96×\90ת] ×\90×\9d ×\91רצ×\95× ×\9b×\9d להמשיך.",
- "rev-suppressed-text-unhide": "×\92רסת ×\94×\93×£ ×\94×\96×\90ת <strong>×\94×\95×¢×\9c×\9e×\94</strong>.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ×¢×\9c ×\9b×\9a ×\91[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ×\99×\95×\9e×\9f ×\94×\94×¢×\9c×\9e×\95ת].\n×\90ת×\9d ×¢×\93×\99×\99×\9f ×\99×\9b×\95×\9c×\99×\9d [$1 ×\9cצפ×\95ת ×\91×\92רס×\94 ×\94×\96×\90ת] ×\90×\9d ×\91רצ×\95× ×\9b×\9d להמשיך.",
- "rev-deleted-text-view": "×\92רסת ×\94×\93×£ ×\94×\96×\90ת <strong>× ×\9e×\97ק×\94</strong>.\n×\90ת×\9d ×\99×\9b×\95×\9c×\99×\9d ×\9cצפ×\95ת ×\91×\94; × ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ×¢×\9c ×\9b×\9a ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
- "rev-suppressed-text-view": "×\92רסת ×\94×\93×£ ×\94×\96×\90ת <strong>×\94×\95×¢×\9c×\9e×\94</strong>.\n×\90ת×\9d ×\99×\9b×\95×\9c×\99×\9d ×\9cצפ×\95ת ×\91×\94; × ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ×¢×\9c ×\9b×\9a ב[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} יומן ההעלמות].",
- "rev-deleted-no-diff": "×\90×\99× ×\9b×\9d ×\99×\9b×\95×\9c×\99×\9d ×\9cצפ×\95ת ×\91×\94×\91×\93×\9c×\99×\9d ×\91×\99×\9f ×\94×\92רס×\90×\95ת שצ×\99×\99× ×ª×\9d ×\9eש×\95×\9d ש×\90×\97ת ×\9e×\94×\9f '''× ×\9e×\97ק×\94'''.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ×¢×\9c ×\9b×\9a ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
- "rev-suppressed-no-diff": "×\90×\99× ×\9b×\9d ×\99×\9b×\95×\9c×\99×\9d ×\9cצפ×\95ת ×\91×\94×\91×\93×\9c×\99×\9d ×\91×\99×\9f ×\94×\92רס×\90×\95ת שצ×\99×\99× ×ª×\9d ×\9eש×\95×\9d ש×\90×\97ת ×\9e×\94×\9f '''× ×\9e×\97ק×\94'''.",
- "rev-deleted-unhide-diff": "אחת מהגרסאות שביקשתם להשוות '''נמחקה'''.\nניתן למצוא פרטים על כך ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].\nאתם עדיין יכולים [$1 לצפות בהבדלים בין הגרסאות] אם ברצונכם להמשיך.",
- "rev-suppressed-unhide-diff": "אחת מהגרסאות שביקשתם להשוות <strong>הועלמה</strong>.\nניתן למצוא פרטים על כך ב[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} יומן ההעלמות].\nאתם עדיין יכולים [$1 לצפות בהבדלים בין הגרסאות] אם ברצונכם להמשיך.",
- "rev-deleted-diff-view": "אחת מהגרסאות שביקשתם להשוות '''נמחקה'''.\nאתם עדיין יכולים לצפות בהבדלים בין הגרסאות; ניתן למצוא פרטים על כך ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
- "rev-suppressed-diff-view": "אחת מהגרסאות שביקשתם להשוות <strong>הועלמה</strong>.\nאתם יכולים לצפות בהבדלים בין הגרסאות; ניתן למצוא פרטים על כך ב[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} יומן ההעלמות].",
+ "rev-deleted-comment": "(תקצ×\99ר ×\94ער×\99×\9b×\94 ×\94×\95סתר)",
+ "rev-deleted-user": "(ש×\9d ×\94×\9eשת×\9eש ×\94×\95סתר)",
+ "rev-deleted-event": "(פע×\95×\9cת ×\94×\99×\95×\9e×\9f ×\94×\95סתר×\94)",
+ "rev-deleted-user-contribs": "[ש×\9d ×\94×\9eשת×\9eש ×\90×\95 ×\9bת×\95×\91ת ×\94Ö¾IP ×\94×\95סתר×\95 â\80\93 ×\94ער×\99×\9b×\94 ×\94×\95סתר×\94 ×\9e×\93×£ ×\94תר×\95×\9e×\95ת]",
+ "rev-deleted-text-permission": "×\92רס×\94 ×\96×\95 ש×\9c ×\94×\93×£ <strong>×\94×\95סתר×\94</strong>.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
+ "rev-suppressed-text-permission": "×\92רס×\94 ×\96×\95 ש×\9c ×\94×\93×£ <strong>×\94×\95×¢×\9c×\9e×\94</strong>.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ב[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} יומן ההעלמות].",
+ "rev-deleted-text-unhide": "×\92רס×\94 ×\96×\95 ש×\9c ×\94×\93×£ <strong>×\94×\95סתר×\94</strong>.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ×\91[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ×\99×\95×\9e×\9f ×\94×\9e×\97×\99ק×\95ת].\n×¢×\93×\99×\99×\9f ×\91×\90פשר×\95ת×\9a [$1 ×\9cצפ×\95ת ×\91×\92רס×\94 ×\94×\96×\90ת] ×\90×\9d ×\91רצ×\95× ×\9a להמשיך.",
+ "rev-suppressed-text-unhide": "×\92רס×\94 ×\96×\95 ש×\9c ×\94×\93×£ <strong>×\94×\95×¢×\9c×\9e×\94</strong>.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ×\91[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ×\99×\95×\9e×\9f ×\94×\94×¢×\9c×\9e×\95ת].\n×¢×\93×\99×\99×\9f ×\91×\90פשר×\95ת×\9a [$1 ×\9cצפ×\95ת ×\91×\92רס×\94 ×\94×\96×\90ת] ×\90×\9d ×\91רצ×\95× ×\9a להמשיך.",
+ "rev-deleted-text-view": "×\92רס×\94 ×\96×\95 ש×\9c ×\94×\93×£ <strong>×\94×\95סתר×\94</strong>.\n×¢×\93×\99×\99×\9f ×\91×\90פשר×\95ת×\9a ×\9cצפ×\95ת ×\91×\94; × ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
+ "rev-suppressed-text-view": "×\92רס×\94 ×\96×\95 ש×\9c ×\94×\93×£ <strong>×\94×\95×¢×\9c×\9e×\94</strong>.\n×¢×\93×\99×\99×\9f ×\91×\90פשר×\95ת×\9a ×\9cצפ×\95ת ×\91×\94; × ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ב[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} יומן ההעלמות].",
+ "rev-deleted-no-diff": "×\90×\99×\9f ×\91×\90פשר×\95ת×\9a ×\9cצפ×\95ת ×\91×\94×\91×\93×\9c×\99×\9d ×\91×\99×\9f ×\94×\92רס×\90×\95ת ×\94×\90×\9c×\94 ×\9eש×\95×\9d ש×\90×\97ת ×\9e×\94×\9f <strong>×\94×\95סתר×\94</strong>.\n× ×\99ת×\9f ×\9c×\9eצ×\95×\90 פר×\98×\99×\9d ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
+ "rev-suppressed-no-diff": "×\90×\99×\9f ×\91×\90פשר×\95ת×\9a ×\9cצפ×\95ת ×\91×\94×\91×\93×\9c×\99×\9d ×\91×\99×\9f ×\94×\92רס×\90×\95ת ×\94×\90×\9c×\94 ×\9eש×\95×\9d ש×\90×\97ת ×\9e×\94×\9f <strong>×\94×\95×¢×\9c×\9e×\94</strong>.",
+ "rev-deleted-unhide-diff": "אחת מהגרסאות שביקשת להשוות <strong>הוסתרה</strong>.\nניתן למצוא פרטים ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].\nעדיין באפשרותך [$1 לצפות בהבדלים בין הגרסאות] אם ברצונך להמשיך.",
+ "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-showdeleted": "הצגה",
"revisiondelete": "מחיקה ושחזור של גרסאות",
- "revdelete-nooldid-title": "×\92רסת ×\9e×\98ר×\94 ×\91×\9cת×\99 תקינה",
- "revdelete-nooldid-text": "×\90×\95 שלא ציינת שום גרסה שהפעולה תבוצע עליה, או שהגרסה שציינת אינה קיימת, או שניסית להסתיר את הגרסה הנוכחית.",
- "revdelete-no-file": "×\94ק×\95×\91×¥ שצ×\99×\99× ×ª אינו קיים.",
- "revdelete-show-file-confirm": "×\94×\90×\9d ×\90ת×\9d ×\91×\98×\95×\97×\99×\9d ש×\91רצ×\95× ×\9b×\9d ×\9cצפ×\95ת ×\91×\92רס×\94 ×\94×\9e×\97×\95ק×\94 ש×\9c ×\94ק×\95×\91×¥ \"<nowiki>$1</nowiki>\" ×\9eת×\90ר×\99×\9a $3, $2?",
+ "revdelete-nooldid-title": "×\92רסת ×\94×\99×¢×\93 ×\90×\99× ×\94 תקינה",
+ "revdelete-nooldid-text": "×\99×\99ת×\9b×\9f שלא ציינת שום גרסה שהפעולה תבוצע עליה, או שהגרסה שציינת אינה קיימת, או שניסית להסתיר את הגרסה הנוכחית.",
+ "revdelete-no-file": "×\94ק×\95×\91×¥ שצ×\95×\99×\9f אינו קיים.",
+ "revdelete-show-file-confirm": "×\94×\90×\9d ×\91רצ×\95× ×\9a ×\9cצפ×\95ת ×\91×\92רס×\94 ×\9e×\97×\95ק×\94 ש×\9c ×\94ק×\95×\91×¥ \"<nowiki>$1</nowiki>\" ×\9eÖ¾$3, $2?",
"revdelete-show-file-submit": "כן",
- "revdelete-selected-text": "{{PLURAL:$1|הגרסה שנבחרה|הגרסאות שנבחרו}} מתוך [[:$2]]:",
+ "revdelete-selected-text": "{{PLURAL:$1|הגרסה שנבחרה|הגרסאות שנבחרו}} מתוך הדף [[:$2]]:",
"revdelete-selected-file": "{{PLURAL:$1|גרסת הקובץ שנבחרה|גרסאות הקובץ שנבחרו}} מתוך [[:$2]]:",
"logdelete-selected": "{{PLURAL:$1|פעולת היומן שנבחרה|פעולות היומן שנבחרו}}:",
- "revdelete-text-text": "×\92רס×\90×\95ת ×©× ×\9e×\97ק×\95 ×¢×\93×\99×\99×\9f ת×\95×¤×¢× ×\94 ×\91×\94×\99ס×\98×\95ר×\99×\99ת ×\94×\93×£, ×\90×\9a ×\97×\9cק×\99×\9d ×\9e×\94ת×\95×\9b×\9f ש×\9c×\94×\9f ×\9c×\90 ×\99×\94×\99×\95 ×\96×\9e×\99× ×\99×\9d לציבור.",
- "revdelete-text-file": "×\92רס×\90×\95ת ק×\91צ×\99×\9d ×©× ×\9e×\97ק×\95 ×¢×\93×\99×\99×\9f ת×\95×¤×¢× ×\94 ×\91×\94×\99ס×\98×\95ר×\99×\99ת ×\94ק×\95×\91×¥, ×\90×\9a ×\97×\9cק×\99×\9d ×\9e×\94ת×\95×\9b×\9f ש×\9c×\94×\9f ×\9c×\90 ×\99×\94×\99×\95 ×\96×\9e×\99× ×\99×\9d לציבור.",
- "logdelete-text": "פע×\95×\9c×\95ת ×\99×\95×\9e×\9f ×©× ×\9e×\97ק×\95 ×¢×\93×\99×\99×\9f ת×\95×¤×¢× ×\94 ×\91×\93פ×\99 ×\94×\99×\95×\9e× ×\99×\9d, ×\90×\9a ×\97×\9cק×\99×\9d ×\9e×\94ת×\95×\9b×\9f ש×\9c×\94×\9f ×\9c×\90 ×\99×\94×\99×\95 ×\96×\9e×\99× ×\99×\9d לציבור.",
- "revdelete-text-others": "×\9eפע×\99×\9c×\99 ×\9eער×\9bת ×\90×\97ר×\99×\9d ×¢×\93×\99×\99×\9f ×\99×\95×\9b×\9c×\95 ×\9c×\92שת ×\9cת×\95×\9b×\9f ×\94× ×¡×ª×¨ ×\9b×\93×\99 לשחזר אותו, אלא אם כן תוגדרנה הגבלות נוספות.",
+ "revdelete-text-text": "×\92רס×\90×\95ת ש×\94×\95סתר×\95 ×¢×\93×\99×\99×\9f ×\99×\95פ×\99×¢×\95 ×\91×\94×\99ס×\98×\95ר×\99×\99ת ×\94×\93×£, ×\90×\91×\9c ×\94ת×\95×\9b×\9f ש×\9c×\94×\9f ×\9c×\90 ×\99×\94×\99×\94 ×\96×\9e×\99×\9f לציבור.",
+ "revdelete-text-file": "×\92רס×\90×\95ת ק×\91צ×\99×\9d ש×\94×\95סתר×\95 ×¢×\93×\99×\99×\9f ×\99×\95פ×\99×¢×\95 ×\91×\94×\99ס×\98×\95ר×\99×\99ת ×\94ק×\95×\91×¥, ×\90×\91×\9c ×\94ת×\95×\9b×\9f ש×\9c×\94×\9f ×\9c×\90 ×\99×\94×\99×\94 ×\96×\9e×\99×\9f לציבור.",
+ "logdelete-text": "פע×\95×\9c×\95ת ×\99×\95×\9e×\9f ש×\94×\95סתר×\95 ×¢×\93×\99×\99×\9f ×\99×\95פ×\99×¢×\95 ×\91×\93פ×\99 ×\94×\99×\95×\9e× ×\99×\9d, ×\90×\91×\9c ×\94ת×\95×\9b×\9f ש×\9c×\94×\9f ×\9c×\90 ×\99×\94×\99×\94 ×\96×\9e×\99×\9f לציבור.",
+ "revdelete-text-others": "×\9eפע×\99×\9c×\99 ×\9eער×\9bת ×\90×\97ר×\99×\9d ×¢×\93×\99×\99×\9f ×\99×\95×\9b×\9c×\95 ×\9c×\92שת ×\9cת×\95×\9b×\9f ×\94×\9e×\95סתר ×\95×\90×£ לשחזר אותו, אלא אם כן תוגדרנה הגבלות נוספות.",
"revdelete-confirm": "אנא אשרו שזה אכן מה שאתם מתכוונים לעשות, שאתם מבינים את התוצאות של מעשה כזה, ושהמעשה מבוצע בהתאם ל[[{{MediaWiki:Policy-url}}|נוהלי האתר]].",
- "revdelete-suppress-text": "יש להשתמש בהעלמה '''אך ורק''' במקרים הבאים:\n* מידע שעלול להיות לשון הרע\n* חשיפת מידע אישי\n*: <em>כתובות בתים ומספרי טלפון, מספרי זהות, וכו'</em>",
+ "revdelete-suppress-text": "יש להשתמש בהעלמה <strong>אך ורק</strong> במקרים הבאים:\n* מידע שעלול להיות לשון הרע\n* חשיפת מידע אישי\n*: <em>כתובות בתים ומספרי טלפון, מספרי זהות, וכו'</em>",
"revdelete-legend": "הגדרת הגבלות התצוגה",
- "revdelete-hide-text": "תוכן הגרסה",
+ "revdelete-hide-text": "×\94סתרת ת×\95×\9b×\9f ×\94×\92רס×\94",
"revdelete-hide-image": "הסתרת תוכן הקובץ",
- "revdelete-hide-name": "×\94סתרת ×\93×£ ×\94×\99×¢×\93 ×\95×\94פר×\9e×\98ר×\99×\9d",
- "revdelete-hide-comment": "תקציר העריכה",
- "revdelete-hide-user": "שם המשתמש או כתובת ה־IP של העורך",
- "revdelete-hide-restricted": "×\94×¢×\9c×\9eת ×\94×\9e×\99×\93×¢ ×\92×\9d ×\9e×\9eפע×\99×\9c×\99 ×\94×\9eער×\9bת",
+ "revdelete-hide-name": "הסתרת היעד והפרמטרים",
+ "revdelete-hide-comment": "×\94סתרת תקצ×\99ר ×\94ער×\99×\9b×\94",
+ "revdelete-hide-user": "×\94סתרת ש×\9d ×\94×\9eשת×\9eש ×\90×\95 ×\9bת×\95×\91ת ×\94Ö¾IP ש×\9c ×\94×¢×\95ר×\9a",
+ "revdelete-hide-restricted": "העלמת המידע גם ממפעילי מערכת",
"revdelete-radio-same": "(ללא שינוי)",
- "revdelete-radio-set": "×\9e×\95סתר",
- "revdelete-radio-unset": "×\92×\9c×\95×\99",
- "revdelete-suppress": "×\94×¢×\9c×\9eת ×\94×\9e×\99×\93×¢ ×\92×\9d ×\9e×\9eפע×\99×\9c×\99 ×\94×\9eער×\9bת",
+ "revdelete-radio-set": "×\9b×\9f",
+ "revdelete-radio-unset": "×\9c×\90",
+ "revdelete-suppress": "העלמת המידע גם ממפעילי מערכת",
"revdelete-unsuppress": "הסרת הגבלות בגרסאות המשוחזרות",
"revdelete-log": "סיבה:",
"revdelete-submit": "ביצוע על {{PLURAL:$1|הגרסה שנבחרה|הגרסאות שנבחרו}}",
- "revdelete-success": "×\9eצ×\91 ×\94תצ×\95×\92×\94 ש×\9c ×\94×\92רס×\94 ש×\81×\95Ö¼× ×\94.",
+ "revdelete-success": "מצב התצוגה של הגרסה שוּנה.",
"revdelete-failure": "לא ניתן היה לשנות את מצב התצוגה של הגרסה:\n$1",
- "logdelete-success": "×\9eצ×\91 ×\94תצ×\95×\92×\94 ש×\9c פע×\95×\9cת ×\94×\99×\95×\9e×\9f ש×\81×\95Ö¼× ×\94.",
+ "logdelete-success": "מצב התצוגה של פעולת היומן שוּנה.",
"logdelete-failure": "לא ניתן היה לשנות את מצב התצוגה של היומן:\n$1",
"revdel-restore": "שינוי מצב התצוגה",
- "pagehist": "היסטוריית הדף",
+ "pagehist": "×\94×\99ס×\98×\95ר×\99×\99ת ×\94×\92רס×\90×\95ת ש×\9c ×\94×\93×£",
"deletedhist": "הגרסאות המחוקות",
- "revdelete-hide-current": "שגיאה בהסתרת הפריט מתאריך $2, $1: זו הגרסה הנוכחית.\nלא ניתן להסתיר אותה.",
- "revdelete-show-no-access": "שגיאה בהצגת הפריט מתאריך $2, $1: פריט זה סומן כ\"מוגבל\".\nאין לך גישה אליו.",
- "revdelete-modify-no-access": "שגיאה בשינוי הפריט מתאריך $2, $1: פריט זה סומן כ\"מוגבל\".\nאין לכם גישה אליו.",
+ "revdelete-hide-current": "שגיאה בהסתרת הפריט מ־$2, $1: זו הגרסה הנוכחית.\nלא ניתן להסתיר אותה.",
+ "revdelete-show-no-access": "שגיאה בהצגת הפריט מ־$2, $1: פריט זה סומן כ\"מוגבל\".\nאין לך גישה אליו.",
+ "revdelete-modify-no-access": "שגיאה בשינוי הפריט מ־$2, $1: פריט זה סומן כ\"מוגבל\".\nאין לך גישה אליו.",
"revdelete-modify-missing": "שגיאה בשינוי פריט מספר $1: הוא אינו נמצא בבסיס הנתונים!",
"revdelete-no-change": "<strong>אזהרה:</strong> לפריט מ־$2, $1 כבר היו הגדרות התצוגה שביקשת.",
- "revdelete-concurrent-change": "שגיאה בשינוי הפריט מתאריך $2, $1: נראה שמצבו שונה על־ידי מישהו אחר בזמן שאתם ניסיתם לשנות אותו.\nאנא בדקו ביומנים.",
- "revdelete-only-restricted": "שגיאה בהסתרת הפריט מתאריך $2, $1: אין באפשרותך להעלים פריטים ממפעילי המערכת מבלי לבחור גם באחת מאפשרויות הנראוּת האחרות.",
+ "revdelete-concurrent-change": "שגיאה בשינוי הפריט מ־$2, $1: נראה שמצב התצוגה שלו כבר שוּנה על־ידי מישהו אחר בזמן שניסית לשנות אותו.\nבאפשרותך למצוא פרטים ביומנים.",
+ "revdelete-only-restricted": "שגיאה בהסתרת הפריט מ־$2, $1: לא ניתן להעלים פריטים ממפעילי מערכת מבלי לבחור גם באחת מהאפשרויות האחרות.",
"revdelete-reason-dropdown": "* סיבות מחיקה נפוצות\n** הפרת זכויות יוצרים\n** תקציר עריכה או מידע אישי לא הולמים\n** שם משתמש לא הולם\n** מידע שעלול להיות לשון הרע",
"revdelete-otherreason": "סיבה אחרת/נוספת:",
"revdelete-reasonotherlist": "סיבה אחרת",
- "revdelete-edit-reasonlist": "ער×\99×\9bת ס×\99×\91×\95ת ×\94×\9e×\97×\99קה",
+ "revdelete-edit-reasonlist": "ער×\99×\9bת ס×\99×\91×\95ת ×\94×\94סתרה",
"revdelete-offender": "מחבר הגרסה:",
"suppressionlog": "יומן העלמות",
"suppressionlogtext": "להלן רשימת המחיקות והחסימות הכוללות תוכן המוסתר ממפעילי המערכת.\nראו את [[Special:BlockList|רשימת החסומים]] לרשימת החסימות הפעילות כעת.",
"mergehistory-no-destination": "דף היעד $1 אינו קיים.",
"mergehistory-invalid-source": "דף המקור חייב להיות בעל כותרת תקינה.",
"mergehistory-invalid-destination": "דף היעד חייב להיות בעל כותרת תקינה.",
- "mergehistory-autocomment": "הדף [[:$1]] מוזג לתוך [[:$2]]",
- "mergehistory-comment": "הדף [[:$1]] מוזג לתוך [[:$2]]: $3",
+ "mergehistory-autocomment": "הדף [[:$1]] מוזג לתוך הדף [[:$2]]",
+ "mergehistory-comment": "הדף [[:$1]] מוזג לתוך הדף [[:$2]]: $3",
"mergehistory-same-destination": "דפי המקור והיעד זהים",
"mergehistory-reason": "סיבה:",
"mergelog": "יומן מיזוגים",
"diff-multi-sameuser": "({{PLURAL:$1|גרסת ביניים אחת|$1 גרסאות ביניים}} של אותו משתמש {{PLURAL:$1|אינה מוצגת|אינן מוצגות}})",
"diff-multi-otherusers": "({{PLURAL:$1|גרסת ביניים אחת|$1 גרסאות ביניים}} של {{PLURAL:$2|משתמש אחר אחד|$2 משתמשים}} {{PLURAL:$1|אינה מוצגת|אינן מוצגות}})",
"diff-multi-manyusers": "({{PLURAL:$1|גרסת ביניים אחת|$1 גרסאות ביניים}} של יותר {{PLURAL:$2|ממשתמש אחד|מ־$2 משתמשים}} {{PLURAL:$1|אינה מוצגת|אינן מוצגות}})",
- "difference-missing-revision": "{{PLURAL:$2|×\92רס×\94 ×\90×\97ת|$2 ×\92רס×\90×\95ת}} ש×\9c ×\94×\94×\91×\93×\9c ×\94×\96×\94 ×\91×\99×\9f שת×\99 ×\92רס×\90×\95ת ($1) {{PLURAL:$2|×\9c×\90 × ×\9eצ×\90×\94|×\9c×\90 × ×\9eצ×\90×\95}}.\n\n×\96×\94 × ×\92ר×\9d ×\91×\93ר×\9a ×\9b×\9c×\9c ×¢×\9cÖ¾×\99×\93×\99 ×\9c×\97×\99צ×\94 ×¢×\9c ק×\99ש×\95ר ×\99ש×\9f ×\9c×\94×\91×\93×\9c בין גרסאות של דף שנמחק.\nאפשר למצוא פרטים ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
+ "difference-missing-revision": "{{PLURAL:$2|×\92רס×\94 ×\90×\97ת|$2 ×\92רס×\90×\95ת}} ×\9eת×\95×\9a ×\94×\92רס×\90×\95ת ש×\91×\99קשת ×\9c×\94ש×\95×\95ת ($1) {{PLURAL:$2|×\9c×\90 × ×\9eצ×\90×\94|×\9c×\90 × ×\9eצ×\90×\95}}.\n\n×\96×\94 × ×\92ר×\9d ×\91×\93ר×\9aÖ¾×\9b×\9c×\9c עק×\91 ×\9c×\97×\99צ×\94 ×¢×\9c ק×\99ש×\95ר ×\99ש×\9f ×\9c×\94×\91×\93×\9c×\99×\9d בין גרסאות של דף שנמחק.\nאפשר למצוא פרטים ב[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} יומן המחיקות].",
"searchresults": "תוצאות החיפוש",
"searchresults-title": "תוצאות החיפוש \"$1\"",
"titlematches": "כותרות דפים תואמות",
"search-error": "אירעה שגיאה במהלך החיפוש: $1",
"preferences": "העדפות",
"mypreferences": "העדפות",
- "prefs-edits": "מספר עריכות:",
+ "prefs-edits": "×\9eספר ×\94ער×\99×\9b×\95ת:",
"prefsnologintext2": "נדרשת כניסה לחשבון כדי לשנות העדפות משתמש.",
"prefs-skin": "עיצוב",
"skin-preview": "תצוגה מקדימה",
"prefs-watchlist": "רשימת המעקב",
"prefs-editwatchlist": "עריכת רשימת המעקב",
"prefs-editwatchlist-label": "עריכת דפים ברשימת המעקב שלך:",
- "prefs-editwatchlist-edit": "הצגה או הסרה של דפים מרשימת המעקב שלך",
+ "prefs-editwatchlist-edit": "הצגה או הסרה של דפים מרשימת המעקב",
"prefs-editwatchlist-raw": "עריכת רשימת המעקב הגולמית",
- "prefs-editwatchlist-clear": "ניקוי רשימת המעקב שלך",
+ "prefs-editwatchlist-clear": "ניקוי רשימת המעקב",
"prefs-watchlist-days": "מספר הימים שמוצגים ברשימת המעקב:",
"prefs-watchlist-days-max": "לכל היותר {{PLURAL:$1|יום אחד|יומיים|$1 ימים}}",
"prefs-watchlist-edits": "המספר המרבי של העריכות שמוצגות ברשימת המעקב המורחבת:",
- "prefs-watchlist-edits-max": "לכל היותר: 1000",
+ "prefs-watchlist-edits-max": "לכל היותר: 1,000",
"prefs-watchlist-token": "אסימון לרשימת המעקב:",
"prefs-misc": "שונות",
"prefs-resetpass": "שינוי סיסמה",
"recentchangesdays-max": "לכל היותר {{PLURAL:$1|יום אחד|יומיים|$1 ימים}}",
"recentchangescount": "מספר העריכות שמוצגות כברירת מחדל:",
"prefs-help-recentchangescount": "ההעדפה הזאת כוללת את דף השינויים האחרונים, דפי היסטוריית גרסאות ויומנים.",
- "prefs-help-watchlist-token2": "×\96×\94×\95 ×\94×\9eפת×\97 ×\94ס×\95×\93×\99 ×\9c×\94×\96× ×\94 ש×\9c רש×\99×\9eת ×\94×\9eעק×\91 ש×\9c×\9a.\n×\9b×\9c ×\9e×\99 ש×\99×\95×\93×¢ ×\90×\95ת×\95 ×\99×\95×\9b×\9c ×\9cקר×\95×\90 ×\90ת רש×\99×\9eת ×\94×\9eעק×\91 ש×\9c×\9a, ×\9c×\9b×\9f ×\90×\99×\9f ×\9cשתף ×\90×\95ת×\95.\n[[Special:ResetTokens|×\90×\9d ×\99ש ×\91×\9b×\9a צ×\95ר×\9a, ×\90פשר ×\9c×\90פס ×\90×\95ת×\95 ×\9b×\90ן]].",
+ "prefs-help-watchlist-token2": "×\96×\94×\95 ×\94×\9eפת×\97 ×\94ס×\95×\93×\99 ×\9c×\94×\96× ×\94 ש×\9c רש×\99×\9eת ×\94×\9eעק×\91 ש×\9c×\9a.\n×\9b×\9c ×\9e×\99 ש×\99×\95×\93×¢ ×\90×\95ת×\95 ×\99×\9b×\95×\9c ×\9cקר×\95×\90 ×\90ת רש×\99×\9eת ×\94×\9eעק×\91 ש×\9c×\9a, ×\9c×\9b×\9f ×\90×\99×\9f ×\9cשתף ×\90×\95ת×\95.\n×\91×\9eקר×\94 ×\94צ×\95ר×\9a, ×\90פשר [[Special:ResetTokens|×\9c×\90פס ×\90ת ×\94×\90ס×\99×\9e×\95ן]].",
"savedprefs": "ההעדפות שלך נשמרו.",
- "savedrights": "×\94רש×\90×\95ת {{GENDER:$1|×\94×\9eשת×\9eש|×\94×\9eשת×\9eשת}} ש×\9c $1 נשמרו.",
+ "savedrights": "×\94×\94רש×\90×\95ת ש×\9c {{GENDER:$1|×\94×\9eשת×\9eש|×\94×\9eשת×\9eשת}} \"$1\" נשמרו.",
"timezonelegend": "אזור זמן:",
"localtime": "זמן מקומי:",
"timezoneuseserverdefault": "ברירת המחדל של האתר ($1)",
"timezoneregion-europe": "אירופה",
"timezoneregion-indian": "האוקיינוס ההודי",
"timezoneregion-pacific": "האוקיינוס השקט",
- "allowemail": "×\9c×\90פשר ק×\91×\9cת ×\93×\95×\90\"×\9c ×\9e×\9eשת×\9eש×\99×\9d ×\90×\97ר×\99×\9d",
+ "allowemail": "×\9c×\90פשר ×\9c×\9eשת×\9eש×\99×\9d ×\9cש×\9c×\95×\97 ×\9c×\99 ×\93×\95×\90ר ×\90×\9cק×\98ר×\95× ×\99",
"prefs-searchoptions": "חיפוש",
"prefs-namespaces": "מרחבי שם",
- "default": "ברירת מחדל",
+ "default": "×\91ר×\99רת ×\94×\9e×\97×\93×\9c",
"prefs-files": "קבצים",
"prefs-custom-css": "קובץ CSS מותאם אישית",
"prefs-custom-js": "קובץ JavaScript מותאם אישית",
"gender-unknown": "באזכורים שלך בממשק, המערכת תשתמש במידת האפשר בלשון שאינה תלוית־מגדר",
"gender-male": "הוא עורך דפים בוויקי",
"gender-female": "היא עורכת דפים בוויקי",
- "prefs-help-gender": "×\90×\99×\9f ×\97×\95×\91×\94 ×\9c×\9e×\9c×\90 ×\94×¢×\93פ×\94 ×\96×\95.\n×\94×\9eער×\9bת ×\9eשת×\9eשת ×\91×\9e×\99×\93×¢ זה כדי לפנות אליך/אלייך ולציין את שם המשתמש שלך במין הדקדוקי הנכון.\nהמידע יהיה ציבורי.",
+ "prefs-help-gender": "×\9c×\90 ×\97×\95×\91×\94 ×\9c×\9e×\9c×\90 ×\94×¢×\93פ×\94 ×\96×\95.\n×\94×\9eער×\9bת ×\9eשת×\9eשת ×\91×\9e×\99×\93×¢ ×\94זה כדי לפנות אליך/אלייך ולציין את שם המשתמש שלך במין הדקדוקי הנכון.\nהמידע יהיה ציבורי.",
"email": "דוא\"ל",
- "prefs-help-realname": "×\90×\99×\9f ×\97×\95×\91×\94 ×\9c×\9e×\9c×\90 ×\90ת ×\94ש×\9d ×\94×\90×\9e×\99ת×\99.\n×\94ש×\9d ×\94×\90×\9e×\99ת×\99 עשוי לשמש כדי לייחס לך את עבודתך.",
+ "prefs-help-realname": "×\9c×\90 ×\97×\95×\91×\94 ×\9c×\9e×\9c×\90 ×\90ת ×\94ש×\9d ×\94×\90×\9e×\99ת×\99.\n×\90×\9d ס×\95פק, ×\94×\95×\90 עשוי לשמש כדי לייחס לך את עבודתך.",
"prefs-help-email": "כתובת דואר אלקטרוני היא אופציונלית, אבל היא חיונית לאיפוס הסיסמה במקרה ש{{GENDER:|תשכח|תשכחי}} אותה.",
- "prefs-help-email-others": "×\91×\90פשר×\95ת×\9a ×\92×\9d ×\9c×\91×\97×\95ר ×\9c×\90פשר ×\9c×\90×\97ר×\99×\9d ×\9c×\99צ×\95ר ×\90×\99ת×\9a קשר ×\91×\90×\9eצע×\95ת ×\93×\95×\90\"×\9c ×\93ר×\9a ק×\99ש×\95ר ×\91×\93×£ ×\94×\9eשת×\9eש ×\90×\95 ×\91×\93×£ ×\94ש×\99×\97×\94 ש×\9c×\9a.\n×\9bת×\95×\91ת ×\94×\93×\95×\90\"×\9c ש×\9c×\9a ×\9c×\90 ת×\99×\97שף ×\9bש×\9eשת×\9eש×\99×\9d ×\90×\97רים ייצרו איתך קשר.",
+ "prefs-help-email-others": "×\91×\90פשר×\95ת×\9a ×\92×\9d ×\9c×\91×\97×\95ר ×\9c×\90פשר ×\9c×\9eשת×\9eש×\99×\9d ×\9c×\99צ×\95ר ×\90×\99ת×\9a קשר ×\91×\90×\9eצע×\95ת ×\93×\95×\90\"×\9c ×\93ר×\9a ק×\99ש×\95ר ×\91×\93×£ ×\94×\9eשת×\9eש ×\90×\95 ×\91×\93×£ ×\94ש×\99×\97×\94 ש×\9c×\9a.\n×\9bת×\95×\91ת ×\94×\93×\95×\90\"×\9c ש×\9c×\9a ×\9c×\90 ת×\99×\97שף ×\9bש×\9eשת×\9eשים ייצרו איתך קשר.",
"prefs-help-email-required": "כתובת דואר אלקטרוני נדרשת לכתיבה באתר.",
"prefs-info": "מידע בסיסי",
"prefs-i18n": "בינאום",
"prefs-help-prefershttps": "העדפה זו תיכנס לתוקף בכניסה הבאה לחשבון.",
"prefswarning-warning": "ביצעת שינויים בהעדפות שלך, והם עדיין לא נשמרו.\nעזיבת דף זה ללא לחיצה על \"$1\" תגרום לכך שההעדפות שלך לא יעודכנו.",
"prefs-tabs-navigation-hint": "טיפ: ניתן להשתמש במקשי החצים הימני והשמאלי כדי לנווט בין הלשוניות ברשימת הלשוניות.",
- "userrights": "ניהול הרשאות משתמש",
+ "userrights": "ניהול הרשאות {{GENDER:{{BASEPAGENAME}}|משתמש|משתמשת}}",
"userrights-lookup-user": "ניהול קבוצות משתמש",
"userrights-user-editname": "שם משתמש:",
- "editusergroup": "ער×\99×\9bת ק×\91×\95צ×\95ת {{GENDER:$1|×\9eשת×\9eש×\99×\9d}}",
+ "editusergroup": "ער×\99×\9bת ×\94ק×\91×\95צ×\95ת ש×\9c ×\94{{GENDER:$1|×\9eשת×\9eש}}",
"editinguser": "שינוי ההרשאות של {{GENDER:$1|המשתמש|המשתמשת}} <strong>[[User:$1|$1]]</strong> $2",
"userrights-editusergroup": "עריכת קבוצות משתמש",
- "saveusergroups": "ש×\9e×\99רת ק×\91×\95צ×\95ת {{GENDER:$1|×\9eשת×\9eש}}",
+ "saveusergroups": "ש×\9e×\99רת ×\94ק×\91×\95צ×\95ת ש×\9c ×\94{{GENDER:$1|×\9eשת×\9eש|×\9eשת×\9eשת}}",
"userrights-groupsmember": "{{GENDER:$2|חבר|חברה}} ב{{PLURAL:$1|קבוצה|קבוצות}}:",
"userrights-groupsmember-auto": "{{GENDER:$2|חבר|חברה}} אוטומטית ב{{PLURAL:$1|קבוצה|קבוצות}}:",
- "userrights-groups-help": "×\91×\90פשר×\95ת×\9b×\9d ×\9c×©× ×\95ת ×\90ת ×\94ק×\91×\95צ×\95ת ש×\9eשת×\9eש ×\96×\94 ×\97×\91ר ×\91×\94×\9f:\n* ת×\99×\91×\94 ×\9eס×\95×\9e× ×ª פ×\99ר×\95ש×\94 ש×\94×\9eשת×\9eש ×\97×\91ר ×\91ק×\91×\95צ×\94.\n* ת×\99×\91×\94 ×\91×\9cת×\99 ×\9eס×\95×\9e× ×ª פ×\99ר×\95ש×\94 ש×\94×\9eשת×\9eש ×\90×\99× ×\95 ×\97×\91ר ×\91ק×\91×\95צ×\94.\n* ס×\99×\9e×\95×\9f * פ×\99ר×\95ש×\95 ש×\9c×\90 ת×\95×\9b×\9c×\95 ×\9c×\94ס×\99ר ×\9eשת×\9eש ×\9e×\94ק×\91×\95צ×\94 ×\9eר×\92×¢ ש×\94×\95ספת×\9d ×\90×\95ת×\95 אליה, או להפך.",
+ "userrights-groups-help": "×\91×\90פשר×\95ת×\9a ×\9c×©× ×\95ת ×\90ת ×\94ק×\91×\95צ×\95ת ש{{GENDER:$1|×\9eשת×\9eש ×\96×\94 ×\97×\91ר|×\9eשת×\9eשת ×\96×\95 ×\97×\91ר×\94}} ×\91×\94×\9f:\n* ת×\99×\91×\94 ×\9eס×\95×\9e× ×ª פ×\99ר×\95ש×\94 ש×\94{{GENDER:$1|×\9eשת×\9eש ×\9b×\91ר ×\97×\91ר|×\9eשת×\9eשת ×\9b×\91ר ×\97×\91ר×\94}} ×\91ק×\91×\95צ×\94.\n* ת×\99×\91×\94 ×\91×\9cת×\99 ×\9eס×\95×\9e× ×ª פ×\99ר×\95ש×\94 ש×\94{{GENDER:$1|×\9eשת×\9eש ×\90×\99× ×\95 ×\97×\91ר|×\9eשת×\9eשת ×\90×\99× ×\94 ×\97×\91ר×\94}} ×\91ק×\91×\95צ×\94.\n* ס×\99×\9e×\95×\9f * פ×\99ר×\95ש×\95 ש×\9c×\90 ×\99×\94×\99×\94 ×\91×\90פשר×\95ת×\9a ×\9c×\94ס×\99ר ×\90ת ×\94{{GENDER:$1|×\9eשת×\9eש|×\9eשת×\9eשת}} ×\9e×\94ק×\91×\95צ×\94 ×\9c×\90×\97ר ש×\94×\95ספת {{GENDER:$1|×\90×\95ת×\95|×\90×\95ת×\94}} אליה, או להפך.",
"userrights-reason": "סיבה:",
"userrights-no-interwiki": "אין לך הרשאה לערוך הרשאות משתמש באתרים אחרים.",
"userrights-nodatabase": "בסיס הנתונים $1 אינו קיים או אינו מקומי.",
"userrights-nologin": "עליכם [[Special:UserLogin|להיכנס לחשבון]] עם הרשאות מתאימות כדי לשנות הרשאות של משתמשים.",
"userrights-notallowed": "אין לך הרשאה להוסיף או להסיר הרשאות של משתמשים.",
- "userrights-changeable-col": "קבוצות שבאפשרותכם לשנות",
- "userrights-unchangeable-col": "קבוצות שאין באפשרותכם לשנות",
+ "userrights-changeable-col": "{{PLURAL:$1|קבוצה|קבוצות}} שבאפשרותך לשנות",
+ "userrights-unchangeable-col": "{{PLURAL:$1|קבוצה|קבוצות}} שאין באפשרותך לשנות",
"userrights-conflict": "התנגשות בין שינויי הרשאות משתמש! אנא בִּדקו את השינויים שלכם ואשרו אותם.",
"userrights-removed-self": "הסרת את הרשאות המשתמש של עצמך. לכן אין לך כעת אפשרות לגשת לדף זה.",
"group": "קבוצה:",
"right-reupload-shared": "דריסה מקומית של קבצים מאתר קובצי המדיה המשותף",
"right-upload_by_url": "העלאת קובץ מכתובת אינטרנט",
"right-purge": "רענון זיכרון המטמון של האתר ללא מעבר לדף אישור",
- "right-autoconfirmed": "עק×\99פת הגבלת קצב העריכות המבוססת על כתובת IP",
- "right-bot": "×\98×\99פ×\95×\9c ×\91עריכות כאוטומטיות",
+ "right-autoconfirmed": "עק×\99פ×\94 ש×\9c הגבלת קצב העריכות המבוססת על כתובת IP",
+ "right-bot": "×\94ת×\99×\99×\97ס×\95ת ×\9cעריכות כאוטומטיות",
"right-nominornewtalk": "ביטול שליחת התראה על הודעה חדשה למשתמש בעת עריכה משנית בדף שיחתו",
"right-apihighlimits": "שימוש ב־API עם פחות הגבלות",
"right-writeapi": "שימוש ב־API לשינוי דפים",
"right-delete": "מחיקת דפים",
- "right-bigdelete": "×\9e×\97×\99קת ×\93פ×\99×\9d ×¢×\9d ×\94×\99ס×\98×\95ר×\99×\99ת ×\93×£ ×\90ר×\95×\9b×\94",
- "right-deletelogentry": "×\9e×\97×\99קת ×\95ש×\97×\96×\95ר פע×\95×\9c×\95ת ×\9eס×\95×\99×\9e×\95ת ×\91יומן",
- "right-deleterevision": "×\9e×\97×\99קת ×\95ש×\97×\96×\95ר ×\92רס×\90×\95ת ×\9eס×\95×\99×\9e×\95ת ש×\9c דפים",
- "right-deletedhistory": "צפ×\99×\99×\94 ×\91×\92רס×\90×\95ת ×\9e×\97×\95ק×\95ת ללא הטקסט השייך להן",
- "right-deletedtext": "צפ×\99×\99×\94 ×\91×\98קס×\98 ×\9e×\97×\95ק ×\95×\91×\94×\91×\93×\9c×\99×\9d ×\91×\99×\9f ×\92רס×\90×\95ת ×\9e×\97×\95ק×\95ת",
+ "right-bigdelete": "×\9e×\97×\99קת ×\93פ×\99×\9d ×\94×\9e×\9b×\99×\9c×\99×\9d ×\9b×\9e×\95ת ×\92×\93×\95×\9c×\94 ש×\9c ער×\99×\9b×\95ת ×\91×\94×\99ס×\98×\95ר×\99×\99ת ×\94×\92רס×\90×\95ת",
+ "right-deletelogentry": "×\9e×\97×\99ק×\94 ×\95ש×\97×\96×\95ר ש×\9c פע×\95×\9c×\95ת יומן",
+ "right-deleterevision": "×\9e×\97×\99ק×\94 ×\95ש×\97×\96×\95ר ש×\9c ×\92רס×\90×\95ת ×\91דפים",
+ "right-deletedhistory": "צפ×\99×\99×\94 ×\91פר×\98×\99×\9d ש×\9c ×\92רס×\90×\95ת ×\9e×\97×\95ק×\95ת, ללא הטקסט השייך להן",
+ "right-deletedtext": "צפ×\99×\99×\94 ×\91ת×\95×\9b×\9f ×©× ×\9e×\97ק ×\95×\91×\94×\91×\93×\9c×\99×\9d ×\91×\99×\9f ×\92רס×\90×\95ת ×©× ×\9e×\97ק×\95",
"right-browsearchive": "חיפוש דפים מחוקים",
"right-undelete": "שחזור דף מחוק",
"right-suppressrevision": "הצגה, הסתרה וביטול הסתרה של גרסאות מסוימות של דפים מכל המשתמשים",
"right-viewsuppressed": "הצגת גרסאות שמוסתרות מכל המשתמשים",
"right-suppressionlog": "צפייה ביומנים פרטיים",
"right-block": "חסימת משתמשים אחרים מעריכה",
- "right-blockemail": "חסימת משתמש משליחת דואר אלקטרוני",
+ "right-blockemail": "חסימת משתמשים משליחת דואר אלקטרוני",
"right-hideuser": "חסימת שם משתמש תוך הסתרתו מהציבור",
"right-ipblock-exempt": "עקיפת חסימות של כתובת IP, חסימות אוטומטיות וחסימות טווח",
"right-unblockself": "שחרור חסימה של המשתמש עצמו",
"right-import": "ייבוא דפים מאתרי ויקי אחרים",
"right-importupload": "ייבוא דפים באמצעות העלאת קובץ",
"right-patrol": "סימון עריכות של אחרים כבדוקות",
- "right-autopatrol": "ס×\99×\9e×\95×\9f ×\90×\95×\98×\95×\9e×\98×\99 ש×\9c ער×\99×\9b×\95ת ש×\9c ×\94×\9eשת×\9eש כבדוקות",
+ "right-autopatrol": "ס×\99×\9e×\95×\9f ×\90×\95×\98×\95×\9e×\98×\99 ש×\9c ער×\99×\9b×\95ת ×\94×\9eשת×\9eש עצ×\9e×\95 כבדוקות",
"right-patrolmarks": "הבחנה בין עריכות שנבדקו לעריכות שטרם נבדקו בדף השינויים האחרונים",
"right-unwatchedpages": "הצגת רשימה של דפים שאינם במעקב",
"right-mergehistory": "מיזוג היסטוריית גרסאות של דפים",
"right-override-export-depth": "ייצוא דפים כולל דפים מקושרים עד עומק של חמישה",
"right-sendemail": "שליחת דואר אלקטרוני למשתמשים אחרים",
"right-passwordreset": "צפייה בדואר אלקטרוני של איפוס סיסמה",
- "right-managechangetags": "×\99צ×\99רת ×\95×\9e×\97×\99קת [[Special:Tags|ת×\92×\99×\95ת]] ×\9e×\91ס×\99ס ×\94× ×ª×\95× ×\99×\9d",
+ "right-managechangetags": "×\99צ×\99ר×\94, ×\94פע×\9c×\94 ×\95×\91×\99×\98×\95×\9c ש×\9c [[Special:Tags|ת×\92×\99×\95ת]]",
"right-applychangetags": "החלת [[Special:Tags|תגיות]] יחד עם שינויים",
- "right-changetags": "הוספת והסרה של [[Special:Tags|תגיות]] כלשהן לגרסאות מסוימות ולרשומות יומן",
+ "right-changetags": "הוספה והסרה של [[Special:Tags|תגיות]] לגרסאות ולרשומות יומן",
+ "right-deletechangetags": "מחיקת [[Special:Tags|תגיות]] מבסיס הנתונים",
"grant-generic": "חבילת ההרשאות \"$1\"",
"grant-group-page-interaction": "אינטראקציה עם דפים",
"grant-group-file-interaction": "אינטראקציה עם קבצים",
"grant-viewmywatchlist": "צפייה ברשימת המעקב שלך",
"newuserlogpage": "יומן רישום משתמשים",
"newuserlogpagetext": "זהו יומן המכיל הרשמות של משתמשים.",
- "rightslog": "×\99×\95×\9e×\9f תפק×\99×\93×\99×\9d",
- "rightslogtext": "×\96×\94×\95 ×\99×\95×\9e×\9f ×\94ש×\99× ×\95×\99×\99×\9d ×\91תפק×\99×\93×\99 המשתמשים.",
+ "rightslog": "×\99×\95×\9e×\9f ×\94רש×\90×\95ת",
+ "rightslogtext": "×\99×\95×\9e×\9f ×\96×\94 ×\9eצ×\99×\92 ×\90ת ×\94ש×\99× ×\95×\99×\99×\9d ×\91×\94רש×\90×\95ת ש×\9c המשתמשים.",
"action-read": "לקרוא דף זה",
"action-edit": "לערוך דף זה",
"action-createpage": "ליצור דפים",
"action-viewmyprivateinfo": "לצפות במידע הפרטי שלך",
"action-editmyprivateinfo": "לערוך את המידע הפרטי שלך",
"action-editcontentmodel": "לערוך את מודל התוכן של דף",
- "action-managechangetags": "ליצור ולמחוק תגיות מבסיס הנתונים",
+ "action-managechangetags": "ליצור, להפעיל ולבטל תגיות",
"action-applychangetags": "להחיל תגיות יחד עם השינויים שלכם",
"action-changetags": "להוסיף ולהסיר תגיות כלשהן לגרסאות מסוימות ולרשומות יומן",
+ "action-deletechangetags": "למחוק תגיות מבסיס הנתונים",
"nchanges": "{{PLURAL:$1|שינוי אחד|$1 שינויים}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|מאז ביקורך האחרון}}",
"enhancedrc-history": "היסטוריה",
"recentchanges-label-unpatrolled": "עריכה זו טרם נבדקה",
"recentchanges-label-plusminus": "גודל הדף השתנה במספר זה של בתים",
"recentchanges-legend-heading": "<strong>מקרא:</strong>",
- "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (ראו גם [[Special:NewPages|רשימת דפים חדשים]])",
+ "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (ראו גם את [[Special:NewPages|רשימת הדפים החדשים]])",
"recentchanges-legend-plusminus": "(''±123'')",
"recentchanges-submit": "הצגה",
"rcnotefrom": "להלן {{PLURAL:$5|השינוי שבוצע|השינויים שבוצעו}} מאז <strong>$3, $4</strong> (מוצגים עד <strong>$1</strong>).",
"recentchangeslinked": "שינויים בדפים המקושרים",
"recentchangeslinked-feed": "שינויים בדפים המקושרים",
"recentchangeslinked-toolbox": "שינויים בדפים המקושרים",
- "recentchangeslinked-title": "שינויים בדפים המקושרים מהדף $1",
+ "recentchangeslinked-title": "שינויים בדפים המקושרים מהדף \"$1\"",
"recentchangeslinked-summary": "בדף מיוחד זה רשומים השינויים האחרונים בדפים המקושרים מתוך הדף (או בדפים הכלולים בקטגוריה).\nדפים ב[[Special:Watchlist|רשימת המעקב שלכם]] מוצגים ב'''הדגשה'''.",
"recentchangeslinked-page": "שם הדף:",
"recentchangeslinked-to": "הצגת השינויים בדפים המקשרים לדף הנתון במקום זאת",
"recentchanges-page-removed-from-category": "הדף [[:$1]] הוסר מקטגוריה",
"recentchanges-page-removed-from-category-bundled": "הדף [[:$1]] הוסר מקטגוריה, [[Special:WhatLinksHere/$1|והוא מוכלל בדפים אחרים]]",
"autochange-username": "שינוי אוטומטי של מדיה־ויקי",
- "upload": "העלאת קובץ לשרת",
- "uploadbtn": "×\94×¢×\9c×\90×\94",
+ "upload": "העלאת קובץ",
+ "uploadbtn": "×\94×¢×\9c×\90ת ×\94ק×\95×\91×¥",
"reuploaddesc": "ביטול ההעלאה וחזרה לטופס העלאת קבצים לשרת",
"upload-tryagain": "שליחת התיאור החדש של הקובץ",
"uploadnologin": "לא נכנסת לחשבון",
"upload-form-label-own-work": "אני יצרתי את הקובץ",
"upload-form-label-infoform-categories": "קטגוריות",
"upload-form-label-infoform-date": "תאריך",
- "upload-form-label-own-work-message-local": "ההעלאה מבוצעת בהתאם לתנאי השירות ולמדיניות הרישיונות ב{{grammar:תחילית|{{SITENAME}}}}.",
- "upload-form-label-not-own-work-message-local": "אם אין באפשרותך להעלות את הקובץ הזה לפי המדיניות של {{SITENAME}}, עליך לסגור את התיבה הנוכחית ולנסות שיטה אחרת.",
- "upload-form-label-not-own-work-local-local": "באפשרותך לנסות להשתמש ב[[Special:Upload|דף ברירת המחדל להעלאת קבצים]].",
- "upload-form-label-own-work-message-default": "ידוע לי שאני מעלה את הקובץ הזה למאגר משותף. ההעלאה מבוצעת בהתאם לתנאי השירות ולמדיניות הרישיונות שם.",
- "upload-form-label-not-own-work-message-default": "אם אין באפשרותך להעלות את הקובץ הזה לפי המדיניות של המאגר המשותף, עליך לסגור את התיבה הנוכחית ולנסות שיטה אחרת.",
- "upload-form-label-not-own-work-local-default": "באפשרותך לנסות להשתמש ב[[Special:Upload|דף העלאת הקבצים ב{{grammar:תחילית|{{SITENAME}}}}]], אם ניתן להעלות את הקובץ הזה לשם לפי מדיניות האתר.",
- "upload-form-label-own-work-message-shared": "אני מאשר שאני מחזיק בזכויות היוצרים על הקובץ הזה, ואני מסכים לשחרר אותו באופן בלתי הפיך עבור ויקישיתוף תחת רישיון [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], ומסכים ל[https://wikimediafoundation.org/wiki/Terms_of_Use תנאי השימוש].",
- "upload-form-label-not-own-work-message-shared": "אם זכויות היוצרים על הקובץ הזה אינן בבעלותך, או שברצונך לשחרר אותו תחת רישיון אחר, באפשרותך להשתמש ב[https://commons.wikimedia.org/wiki/Special:UploadWizard אשף ההעלאה לוויקישיתוף].",
- "upload-form-label-not-own-work-local-shared": "באפשרותך לנסות להשתמש ב[[Special:Upload|דף העלאת הקבצים ב{{grammar:תחילית|{{SITENAME}}}}]], אם ניתן להעלות את הקובץ הזה לשם לפי מדיניות האתר.",
+ "upload-form-label-own-work-message-generic-local": "ההעלאה מבוצעת בהתאם לתנאי השירות ולמדיניות הרישיונות ב{{grammar:תחילית|{{SITENAME}}}}.",
+ "upload-form-label-not-own-work-message-generic-local": "אם אין באפשרותך להעלות את הקובץ הזה לפי המדיניות של {{SITENAME}}, עליך לסגור את התיבה הנוכחית ולנסות שיטה אחרת.",
+ "upload-form-label-not-own-work-local-generic-local": "באפשרותך לנסות להשתמש ב[[Special:Upload|דף ברירת המחדל להעלאת קבצים]].",
+ "upload-form-label-own-work-message-generic-foreign": "ידוע לי שאני מעלה את הקובץ הזה למאגר משותף. ההעלאה מבוצעת בהתאם לתנאי השירות ולמדיניות הרישיונות שם.",
+ "upload-form-label-not-own-work-message-generic-foreign": "אם אין באפשרותך להעלות את הקובץ הזה לפי המדיניות של המאגר המשותף, עליך לסגור את התיבה הנוכחית ולנסות שיטה אחרת.",
+ "upload-form-label-not-own-work-local-generic-foreign": "באפשרותך לנסות להשתמש ב[[Special:Upload|דף העלאת הקבצים ב{{grammar:תחילית|{{SITENAME}}}}]], אם ניתן להעלות את הקובץ הזה לשם לפי מדיניות האתר.",
"backend-fail-stream": "לא הייתה אפשרות להזרים את הקובץ \"$1\".",
"backend-fail-backup": "לא הייתה אפשרות לגבות את הקובץ \"$1\".",
"backend-fail-notexists": "הקובץ \"$1\" אינו קיים.",
"ntransclusions": "בשימוש {{PLURAL:$1|בדף אחד|ב־$1 דפים}}",
"specialpage-empty": "אין תוצאות.",
"lonelypages": "דפים יתומים",
- "lonelypagestext": "×\94×\93פ×\99×\9d ×\94×\91×\90×\99×\9d ×\90×\99× ×\9d ×\9eק×\95שר×\99×\9d ×\9e×\93פ×\99×\9d ×\90×\97ר×\99×\9d ×\91×\90תר ×\96×\94 ×\95×\90×\99× ×\9d ×\9e×\95×\9b×\9c×\9c×\99×\9d ×\91×\94×\9d.",
+ "lonelypagestext": "×\94×\93פ×\99×\9d ×\94×\91×\90×\99×\9d ×\90×\99× ×\9d ×\9eק×\95שר×\99×\9d ×\95×\90×\99× ×\9d ×\9e×\95×\9b×\9c×\9c×\99×\9d ×\91×\93פ×\99×\9d ×\90×\97ר×\99×\9d ×\91×\90תר {{SITENAME}}.",
"uncategorizedpages": "דפים חסרי קטגוריה",
"uncategorizedcategories": "קטגוריות חסרות קטגוריה",
"uncategorizedimages": "קבצים חסרי קטגוריה",
"deadendpages": "דפים ללא קישורים",
"deadendpagestext": "הדפים הבאים אינם מקשרים לדפים אחרים באתר {{SITENAME}}.",
"protectedpages": "דפים מוגנים",
- "protectedpages-indef": "×\94×\92× ×\95ת ×\9c×\96×\9e×\9f ×\91×\9cת×\99 ×\9e×\95×\92×\91×\9c בלבד",
+ "protectedpages-indef": "×\94×\92× ×\95ת ×\9c×\9c×\90 ×\94×\92×\91×\9cת ×\96×\9e×\9f בלבד",
"protectedpages-summary": "בדף זה רשומים הדפים הקיימים שמוגנים כרגע. לרשימת הכותרות שמוגנות מפני יצירה, ראו [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
"protectedpages-cascade": "הגנות מדורגות בלבד",
"protectedpages-noredirect": "הסתרת הפניות",
"protectedpages-page": "דף",
"protectedpages-expiry": "זמן פקיעה",
"protectedpages-performer": "הוגן על־ידי",
- "protectedpages-params": "פר×\9e×\98ר×\99×\9d ×\9cהגנה",
+ "protectedpages-params": "ר×\9eת ×\94הגנה",
"protectedpages-reason": "סיבה",
- "protectedpages-submit": "הצגת דפים",
+ "protectedpages-submit": "×\94צ×\92ת ×\94×\93פ×\99×\9d",
"protectedpages-unknown-timestamp": "לא ידוע",
"protectedpages-unknown-performer": "משתמש לא ידוע",
"protectedtitles": "כותרות מוגנות",
"protectedtitles-summary": "בדף זה רשומות הכותרות שמוגנות כעת מפני יצירה. לרשימת הדפים הקיימים שמוגנים, ראו [[{{#special:ProtectedPages}}|{{int:protectedpages}}]].",
"protectedtitlesempty": "אין כרגע כותרות מוגנות עם הפרמטרים האלה.",
- "protectedtitles-submit": "×\94צ×\92ת ×\9b×\95תר×\95ת",
+ "protectedtitles-submit": "×\94צ×\92ת ×\94×\93פ×\99×\9d",
"listusers": "רשימת משתמשים",
"listusers-editsonly": "הצגת משתמשים עם עריכות בלבד",
- "listusers-creationsort": "מיון לפי תאריך היצירה",
+ "listusers-creationsort": "מיון לפי תאריך היצירה של החשבון",
"listusers-desc": "מיון בסדר יורד",
"usereditcount": "{{PLURAL:$1|עריכה אחת|$1 עריכות}}",
"usercreated": "{{GENDER:$3|נוצר|נוצרה}} ב־$2, $1",
"booksources-text": "להלן רשימת קישורים לאתרים אחרים המוכרים ספרים חדשים ויד־שנייה, ושבהם עשוי להיות מידע נוסף לגבי ספרים שאתם מחפשים:",
"booksources-invalid-isbn": "המסת\"ב שניתן כנראה אינו תקין; אנא בדקו אם ביצעתם טעויות בהעתקה מהמידע המקורי.",
"specialloguserlabel": "בוצעו על־ידי המשתמש:",
- "speciallogtitlelabel": "×\99×¢×\93 (×\9b×\95תרת ×\90×\95 {{ns:user}}:ש×\9d עבור משתמש):",
+ "speciallogtitlelabel": "×\99×¢×\93 (ש×\9d ×\94×\93×£, ×\90×\95 \"{{ns:user}}:ש×\9d\" עבור משתמש):",
"log": "יומנים",
"logeventslist-submit": "הצגה",
"all-logs-page": "כל היומנים הציבוריים",
"trackingcategories-msg": "קטגוריית מעקב",
"trackingcategories-name": "שם ההודעה",
"trackingcategories-desc": "הקריטריון להכללה בקטגוריה",
+ "restricted-displaytitle-ignored": "דפים שכותרת התצוגה שלהם אינה מופעלת",
+ "restricted-displaytitle-ignored-desc": "בדף הזה מוגדרת כותרת תצוגה (<code><nowiki>{{DISPLAYTITLE}}</nowiki></code>) שאינה מופעלת, כי היא אינה תואמת לכותרת האמיתית של הדף.",
"noindex-category-desc": "הדף אינו מאונדקס על־ידי רובוטים כיוון שהוא כולל את מילת הקסם <code><nowiki>__NOINDEX__</nowiki></code> והוא במרחב שם שבו דגל כזה מותר לשימוש.",
"index-category-desc": "הדף כולל את מילת הקסם <code><nowiki>__INDEX__</nowiki></code> (והוא במרחב שם שבו דגל כזה מותר לשימוש), ולכן הוא מאונדקס על֫־ידי רובוטים אף שכברירת מחדל הוא לא היה מאונדקס על ידם.",
"post-expand-template-inclusion-category-desc": "גודל הדף גדול מ־<code>$wgMaxArticleSize</code> לאחר הרחבת כל התבניות, ולכן כמה תבניות לא הורחבו.",
"trackingcategories-disabled": "הקטגוריה מבוטלת",
"mailnologin": "אין כתובת לשליחה",
"mailnologintext": "יש [[Special:UserLogin|להיכנס לחשבון]] ולהגדיר כתובת דואר אלקטרוני תקינה ב[[Special:Preferences|העדפות המשתמש]] כדי לשלוח דואר אלקטרוני למשתמשים אחרים.",
- "emailuser": "שליחת דואר אלקטרוני למשתמש זה",
- "emailuser-title-target": "שליחת דוא\"ל {{GENDER:$1|למשתמש זה|למשתמשת זו}}",
- "emailuser-title-notarget": "שליחת דוא\"ל למשתמש",
- "emailpagetext": "× ×\99ת×\9f ×\9c×\94שת×\9eש ×\91×\98×\95פס ×\9b×\93×\99 ×\9cש×\9c×\95×\97 ×\94×\95×\93עת ×\93×\95×\90ר ×\90×\9cק×\98ר×\95× ×\99 {{GENDER:$1|×\9c×\9eשת×\9eש ×\96×\94|×\9c×\9eשת×\9eשת ×\96×\95}}.\n×\9bת×\95×\91ת ×\94×\93×\95×\90ר ×\94×\90×\9cק×\98ר×\95× ×\99 ש×\9bת×\91ת ב[[Special:Preferences|העדפות המשתמש שלך]] תופיע ככתובת שההודעה נשלחה ממנה, כדי לאפשר תגובה ישירה.",
- "defemailsubject": "דוא\"ל מ{{grammar:תחילית|{{SITENAME}}}} מהמשתמש \"$1\"",
+ "emailuser": "שליחת דוא\"ל ל{{GENDER:{{BASEPAGENAME}}|משתמש|משתמשת}}",
+ "emailuser-title-target": "שליחת דואר אלקטרוני {{GENDER:$1|למשתמש זה|למשתמשת זו}}",
+ "emailuser-title-notarget": "שליחת דואר אלקטרוני למשתמש",
+ "emailpagetext": "× ×\99ת×\9f ×\9c×\94שת×\9eש ×\91×\98×\95פס ש×\9c×\94×\9c×\9f ×\9b×\93×\99 ×\9cש×\9c×\95×\97 ×\94×\95×\93עת ×\93×\95×\90ר ×\90×\9cק×\98ר×\95× ×\99 {{GENDER:$1|×\9c×\9eשת×\9eש ×\96×\94|×\9c×\9eשת×\9eשת ×\96×\95}}.\n×\9bת×\95×\91ת ×\94×\93×\95×\90ר ×\94×\90×\9cק×\98ר×\95× ×\99 ש×\94×\96× ת ב[[Special:Preferences|העדפות המשתמש שלך]] תופיע ככתובת שההודעה נשלחה ממנה, כדי לאפשר תגובה ישירה.",
+ "defemailsubject": "דוא\"ל מ{{GRAMMAR:תחילית|{{SITENAME}}}} מה{{GENDER:$1|משתמש|משתמשת}} \"$1\"",
"usermaildisabled": "שליחת דוא\"ל למשתמשים מבוטלת",
"usermaildisabledtext": "אינכם מורשים לשלוח דואר אלקטרוני למשתמשים אחרים באתר זה",
"noemailtitle": "אין כתובת דואר אלקטרוני",
"emailtarget": "יש להקליד את שם המשתמש של הנמען",
"emailusername": "שם משתמש:",
"emailusernamesubmit": "שליחה",
- "email-legend": "ש×\9c×\99×\97ת ×\93×\95×\90ר ×\90×\9cק×\98ר×\95× ×\99 ×\9c×\9eשת×\9eש ×\90×\97ר ש×\9c {{SITENAME}}",
+ "email-legend": "ש×\9c×\99×\97ת ×\93×\95×\90ר ×\90×\9cק×\98ר×\95× ×\99 ×\9c×\9eשת×\9eש ×\91{{GRAMMAR:ת×\97×\99×\9c×\99ת|{{SITENAME}}}}",
"emailfrom": "מאת:",
"emailto": "אל:",
"emailsubject": "נושא:",
"emailmessage": "הודעה:",
"emailsend": "שליחה",
- "emailccme": "× ×\90 ×\9cש×\9c×\95×\97 ×\9c×\99 ×\91×\93×\95×\90ר ×\90×\9cק×\98ר×\95× ×\99 ×\94עתק ש×\9c ×\94×\95×\93עתי.",
+ "emailccme": "שִ×\9c×\97×\95 ×\9c×\99 ×\94עתק ש×\9c ×\94×\94×\95×\93×¢×\94 ש×\9cי.",
"emailccsubject": "העתק של הודעתך למשתמש $1: $2",
"emailsent": "הדואר נשלח",
"emailsenttext": "הודעת הדואר האלקטרוני שלך נשלחה.",
- "emailuserfooter": "$1 {{GENDER:$1|ש×\9c×\97|ש×\9c×\97×\94}} ×\90ת ×\94×\93×\95×\90\"×\9c ×\94×\96×\94 ×\9c{{GRAMMAR:ת×\97×\99×\9c×\99ת|$2}} ×\91×\90×\9eצע×\95ת פע×\95×\9cת \"{{int:emailuser}}\" ב{{GRAMMAR:תחילית|{{SITENAME}}}}.",
+ "emailuserfooter": "$1 {{GENDER:$1|ש×\9c×\97|ש×\9c×\97×\94}} ×\90ת ×\94×\93×\95×\90\"×\9c ×\94×\96×\94 ×\9c{{GRAMMAR:ת×\97×\99×\9c×\99ת|$2}} ×\91×\90×\9eצע×\95ת ×\94ת×\9b×\95× ×\94 \"{{int:emailuser}}\" ב{{GRAMMAR:תחילית|{{SITENAME}}}}.",
"usermessage-summary": "השארת הודעת מערכת.",
"usermessage-editor": "שולח הודעות המערכת",
"watchlist": "רשימת המעקב",
"wlheader-showupdated": "דפים שהשתנו מאז ביקורך האחרון בהם מוצגים ב'''הדגשה'''.",
"wlnote": "להלן {{PLURAL:$1|השינוי האחרון|<strong>$1</strong> השינויים האחרונים}} {{PLURAL:$2|בשעה האחרונה|בשעתיים האחרונות|ב־<strong>$2</strong> השעות האחרונות}}, עד $4, $3.",
"wlshowlast": "הצגת $1 שעות אחרונות $2 ימים אחרונים",
- "watchlist-hide": "×\94סתר×\94",
+ "watchlist-hide": "×\94סתרת",
"watchlist-submit": "הצגה",
"wlshowtime": "תקופת זמן לצפייה:",
"wlshowhideminor": "עריכות משניות",
"enotif_body": "לכבוד $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nתקציר העריכה: $PAGESUMMARY $PAGEMINOREDIT\n\nבאפשרותכם ליצור קשר עם העורך:\nבדואר האלקטרוני: $PAGEEDITOR_EMAIL\nבאתר: $PAGEEDITOR_WIKI\n\nלא תהיינה הודעות על פעולות נוספות עד שתבקרו בדף כשאתם מחוברים לחשבון. באפשרותכם גם לאפס את דגלי ההודעות בכל הדפים שברשימת המעקב.\n\nמערכת ההודעות של {{SITENAME}}\n\n--\nכדי לשנות את ההגדרות של הודעות הדוא\"ל הנשלחות אליכם, בקרו בדף\n{{canonicalurl:{{#special:Preferences}}}}\n\nכדי לשנות את הגדרות רשימת המעקב, בקרו בדף\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nכדי למחוק את הדף מרשימת המעקב שלכם, בקרו בדף\n$UNWATCHURL\n\nלמשוב ולעזרה נוספת:\n$HELPPAGE",
"created": "נוצר",
"changed": "שונה",
- "deletepage": "×\9e×\97×\99ק×\94",
+ "deletepage": "×\9e×\97×\99קת ×\94×\93×£",
"confirm": "אישור",
"excontent": "התוכן היה: \"$1\"",
"excontentauthor": "התוכן היה: \"$1\", {{GENDER:$2|והתורם היחיד היה|והתורמת היחידה הייתה}} \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|שיחה]])",
"exbeforeblank": "התוכן לפני שרוקן היה: \"$1\"",
- "delete-confirm": "מחיקת \"$1\"",
+ "delete-confirm": "מחיקת הדף \"$1\"",
"delete-legend": "מחיקה",
- "historywarning": "<strong>אזהרה:</strong> לדף שאתם עומדים למחוק יש היסטוריית שינויים של {{PLURAL:$1|גרסה אחת|$1 גרסאות}}:",
+ "historywarning": "<strong>אזהרה:</strong> לדף ש{{GENDER:|אתה עומד|את עומדת|אתם עומדים}} למחוק יש היסטוריית שינויים של {{PLURAL:$1|גרסה אחת|$1 גרסאות}}:",
"historyaction-submit": "הצגה",
"confirmdeletetext": "אתם עומדים למחוק דף יחד עם כל ההיסטוריה שלו.\n\nאנא אשרו שזה אכן מה שאתם מתכוונים לעשות, שאתם מבינים את התוצאות של מעשה כזה, ושהמעשה מבוצע בהתאם ל[[{{MediaWiki:Policy-url}}|נוהלי האתר]].",
"actioncomplete": "הפעולה בוצעה",
"delete-toobig": "דף זה כולל מעל {{PLURAL:$1|גרסה אחת|$1 גרסאות}} בהיסטוריית העריכות שלו. מחיקת דפים כאלה הוגבלה כדי למנוע פגיעה בביצועי האתר.",
"delete-warning-toobig": "דף זה כולל מעל {{PLURAL:$1|גרסה אחת|$1 גרסאות}} בהיסטוריית העריכות שלו. מחיקה שלו עלולה להפריע לפעולות בבסיס הנתונים; אנא שקלו שנית את המחיקה.",
"deleteprotected": "אין באפשרותך למחוק את הדף כי הוא מוגן.",
- "deleting-backlinks-warning": "<strong>אזהרה:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|דפים אחרים]] מקשרים לדף שאתם עומדים למחוק או מכלילים אותו.",
+ "deleting-backlinks-warning": "<strong>אזהרה:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|דפים אחרים]] מקשרים לדף ש{{GENDER:|אתה עומד|את עומדת|אתם עומדים}} למחוק או מכלילים אותו.",
"rollback": "שחזור עריכות",
"rollbacklink": "שחזור",
"rollbacklinkcount": "שחזור {{PLURAL:$1|עריכה אחת|$1 עריכות}}",
"rollbacklinkcount-morethan": "שחזור יותר מ{{PLURAL:$1|עריכה אחת|־$1 עריכות}}",
"rollbackfailed": "השחזור נכשל",
+ "rollback-missingparam": "חסרים פרמטרים נדרשים להגשת הבקשה.",
"cantrollback": "לא ניתן לשחזר את העריכה;\nהתורם האחרון הוא היחיד שכתב בדף זה.",
"alreadyrolled": "לא ניתן לשחזר את העריכה של [[User:$2|$2]] ([[User talk:$2|שיחה]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) בדף [[:$1]]; הדף כבר נערך או שוחזר.\n\nהעריכה האחרונה הייתה של [[User:$3|$3]] ([[User talk:$3|שיחה]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "תקציר העריכה היה: <em>$1</em>.",
"revertpage": "שוחזר מעריכות של [[Special:Contributions/$2|$2]] ([[User talk:$2|שיחה]]) לעריכה האחרונה של [[User:$1|$1]]",
"revertpage-nouser": "שוחזר מעריכות של משתמש מוסתר לעריכה האחרונה של {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "שוחזר מעריכות של $1 לעריכה האחרונה של $2",
+ "rollback-success-notify": "שוחזר מעריכות של $1 לעריכה האחרונה של $2. [$3 הצגת שינויים]",
"sessionfailure-title": "בעיה בחיבור",
"sessionfailure": "נראה שיש בעיה בחיבורכם לאתר;\nפעולתכם בוטלה כאמצעי זהירות נגד התחזות לתקשורת ממחשבכם.\nאנא חזרו לדף הקודם, העלו אותו מחדש ונסו שוב.",
"changecontentmodel": "שינוי מודל התוכן של דף",
"changecontentmodel-legend": "שינוי מודל התוכן",
- "changecontentmodel-title-label": "×\9b×\95תרת הדף",
+ "changecontentmodel-title-label": "ש×\9d הדף",
"changecontentmodel-model-label": "מודל התוכן החדש",
"changecontentmodel-reason-label": "סיבה:",
"changecontentmodel-submit": "שינוי",
"changecontentmodel-success-title": "מודל התוכן שוּנה",
- "changecontentmodel-success-text": "מודל התוכן של [[:$1]] שוּנה.",
- "changecontentmodel-cannot-convert": "×\94ת×\95×\9b×\9f ×\91×\93×£ [[:$1]] ×\90×\99× ×\95 ×\99×\9b×\95×\9c ×\9c×\94×\99×\95ת ×\9e×\95×\9eר ×\9cס×\95×\92 ש×\9c $2.",
+ "changecontentmodel-success-text": "מודל התוכן של הדף [[:$1]] שוּנה.",
+ "changecontentmodel-cannot-convert": "×\9c×\90 × ×\99ת×\9f ×\9c×\94×\9e×\99ר ×\90ת ×\94ת×\95×\9b×\9f ש×\9c [[:$1]] ×\9cס×\95×\92 $2.",
"changecontentmodel-nodirectediting": "מודל התוכן $1 אינו תומך בעריכה ישירה",
+ "changecontentmodel-emptymodels-title": "לא קיים מודל תוכן מתאים",
+ "changecontentmodel-emptymodels-text": "לא ניתן להמיר את התוכן של [[:$1]] לאף סוג.",
"log-name-contentmodel": "יומן שינויי מודל תוכן",
"log-description-contentmodel": "אירועים שקשורים למודל תוכן של דפים",
"logentry-contentmodel-new": "$1 {{GENDER:$2|יצר|יצרה}} את הדף $3 תוך שימוש במודל התוכן \"$5\" השונה ממודל ברירת המחדל",
"protect-fallback": "רק משתמשים בעלי הרשאת \"$1\" מורשים",
"protect-level-autoconfirmed": "רק משתמשים ותיקים מורשים",
"protect-level-sysop": "רק מפעילי מערכת מורשים",
- "protect-summary-cascade": "מדורג",
- "protect-expiring": "פוקעת $1 (UTC)",
- "protect-expiring-local": "פוקעת $1",
+ "protect-summary-cascade": "מדורגת",
+ "protect-expiring": "פוקעת ב{{GRAMMAR:תחילית|$1}} (UTC)",
+ "protect-expiring-local": "פוקעת ב{{GRAMMAR:תחילית|$1}}",
"protect-expiry-indefinite": "בלתי מוגבלת בזמן",
"protect-cascade": "הגנה על כל הדפים המוכללים בדף זה (הגנה מדורגת)",
"protect-cantedit": "אין באפשרותך לשנות את רמת ההגנה על דף זה כיוון שאין לך הרשאה לערוך אותו.",
"protect-edit-reasonlist": "עריכת סיבות ההגנה",
"protect-expiry-options": "שעה:1 hour,יום:1 day,שבוע:1 week,שבועיים:2 weeks,חודש:1 month,שלושה חודשים:3 months,שישה חודשים:6 months,שנה:1 year,זמן בלתי מוגבל:infinite",
"restriction-type": "הרשאה:",
- "restriction-level": "ר×\9eת ×\94×\94×\92×\91×\9cה:",
+ "restriction-level": "ר×\9eת ×\94×\94×\92× ה:",
"minimum-size": "גודל מינימלי",
"maximum-size": "גודל מרבי:",
"pagesize": "(בבתים)",
"restriction-level-all": "כל רמה",
"undelete": "הצגה של דפים מחוקים",
"undeletepage": "הצגה ושחזור של דפים מחוקים",
- "undeletepagetitle": "'''זוהי רשימת הגרסאות המחוקות של [[:$1]]'''.",
+ "undeletepagetitle": "<strong>זוהי רשימת הגרסאות המחוקות של הדף [[:$1|$1]]</strong>.",
"viewdeletedpage": "הצגה של דפים מחוקים",
"undeletepagetext": "{{PLURAL:$1|הדף שלהלן נמחק, אך הוא עדיין בארכיון וניתן לשחזר אותו|הדפים שלהלן נמחקו, אך הם עדיין בארכיון וניתן לשחזר אותם}}.\nייתכן שהארכיון ינוקה מעת לעת.",
"undelete-fieldset-title": "שחזור גרסאות",
- "undeleteextrahelp": "×\9cש×\97×\96×\95ר ×\94×\99ס×\98×\95ר×\99×\99ת ×\94×\92רס×\90×\95ת ×\94×\9e×\9c×\90×\94 ש×\9c ×\94×\93×£, ×\90×\9c תס×\9e× ×\95 ש×\95×\9d ת×\99×\91ת ס×\99×\9e×\95×\9f ×\95×\9c×\97צ×\95 ×¢×\9c '''{{int:undeletebtn}}'''.\n×\9cש×\97×\96×\95ר ש×\9c ×\92רס×\90×\95ת ×\9eס×\95×\99×\9e×\95ת ×\91×\9c×\91×\93, ס×\9e× ×\95 ×\90ת ת×\99×\91×\95ת ×\94ס×\99×\9e×\95×\9f ש×\9c ×\94×\92רס×\90×\95ת ×\94×\9c×\9c×\95, ×\95×\9c×\97צ×\95 ×¢×\9c '''{{int:undeletebtn}}'''.",
+ "undeleteextrahelp": "×\9b×\93×\99 ×\9cש×\97×\96ר ×\90ת ×\94×\99ס×\98×\95ר×\99×\99ת ×\94×\92רס×\90×\95ת ×\94×\9e×\9c×\90×\94 ש×\9c ×\94×\93×£, ×\90×\9c {{GENDER:|תס×\9e×\9f|תס×\9e× ×\99|תס×\9e× ×\95}} ש×\95×\9d ת×\99×\91ת ס×\99×\9e×\95×\9f; פש×\95×\98 {{GENDER:|×\9c×\97×¥|×\9c×\97צ×\99|×\9c×\97צ×\95}} ×¢×\9c <strong><em>{{int:undeletebtn}}</em></strong>.\n×\9b×\93×\99 ×\9cש×\97×\96ר ×\92רס×\90×\95ת ×\9eס×\95×\99×\9e×\95ת ×\91×\9c×\91×\93, {{GENDER:|ס×\9e×\9f|ס×\9e× ×\99|ס×\9e× ×\95}} ×\90ת ×\94×\92רס×\90×\95ת ש{{GENDER:|×\91רצ×\95× ×\9a|×\91רצ×\95× ×\9a|×\91רצ×\95× ×\9b×\9d}} ×\9cש×\97×\96ר ×\95×\9c×\90×\97ר ×\9e×\9b×\9f {{GENDER:|×\9c×\97×¥|×\9c×\97צ×\99|×\9c×\97צ×\95}} ×¢×\9c <strong><em>{{int:undeletebtn}}</em></strong>.",
"undeleterevisions": "{{PLURAL:$1|גרסה אחת נמחקה|$1 גרסאות נמחקו}}",
- "undeletehistory": "אם תשחזרו את הדף, כל הגרסאות תשוחזרנה להיסטוריית השינויים שלו.\nאם יש כבר דף חדש באותו השם, הגרסאות והשינויים יופיעו רק בדף ההיסטוריה שלו.",
- "undeleterevdel": "×\94ש×\97×\96×\95ר ×\9c×\90 ×\99×\91×\95צע ×\90×\9d ×\94×\92רס×\94 ×\94× ×\95×\9b×\97×\99ת ש×\9c ×\94×\93×£ ×\9e×\97×\95ק×\94 ×\91×\97×\9cק×\94. ×\91×\9eקר×\94 ×\9b×\96×\94, ×¢×\9c×\99×\9b×\9d ×\9c×\91×\98×\9c ×\90ת ×\94×\94סתר×\94 ש×\9c ×\94×\92רס×\90×\95ת ×\94×\9e×\97×\95ק×\95ת ×\94×\97×\93ש×\95ת ×\91×\99×\95תר.",
- "undeletehistorynoadmin": "דף זה נמחק. הסיבה למחיקה מוצגת בתקציר מטה, ביחד עם פרטים על המשתמשים שערכו את הדף לפני מחיקתו. הטקסט של גרסאות אלו זמין למפעילי מערכת בלבד.",
+ "undeletehistory": "אם {{GENDER:|תשחזר|תשחזרי|תשחזרו}} את הדף, כל הגרסאות ישוחזרו להיסטוריית השינויים שלו.\nאם הדף הזה נמחק בעבר ולאחר מכן נוצר מחדש, הגרסאות ש{{GENDER:|תשחזר|תשחזרי|תשחזרו}} ימוזגו להיסטוריית השינויים של הדף ויופיעו בתור הגרסאות הישנות ביותר שלו.",
+ "undeleterevdel": "×\94ש×\97×\96×\95ר ×\9c×\90 ×\99×\9b×\95×\9c ×\9c×\94ת×\91צע ×\90×\9d ×\94×\92רס×\94 ×\94×\90×\97ר×\95× ×\94 ש×\9c ×\94×\93×£ ×\9e×\97×\95ק×\94 ×\90×\95 ×\9e×\95סתרת.\n×\91×\9eקר×\94 ×\9b×\96×\94, ×\99ש ×\9c×\91×\98×\9c ק×\95×\93×\9d ×\90ת ×\94×\94סתר×\94 ש×\9c ×\94×\92רס×\94 ×\94×\90×\97ר×\95× ×\94.",
+ "undeletehistorynoadmin": "דף זה נמחק.\nהסיבה למחיקה מוצגת בתקציר שלמטה, וגם פרטים על המשתמשים שערכו את הדף לפני שהוא נמחק.\nהטקסט של הגרסאות הללו זמין למפעילי מערכת בלבד.",
"undelete-revision": "גרסה שנמחקה מהדף $1 (מ־$5, $4) מאת $3:",
"undeleterevision-missing": "הגרסה שגויה או חסרה. ייתכן שמדובר בקישור שבור, או שהגרסה שוחזרה או הוסרה מהארכיון.",
"undelete-nodiff": "לא נמצאה גרסה קודמת.",
"undeletedfiles": "{{PLURAL:$1|שוחזר קובץ אחד|שוחזרו $1 קבצים}}",
"cannotundelete": "השחזור נכשל:\n$1",
"undeletedpage": "<strong>הדף $1 שוחזר</strong>\n\nראו את [[Special:Log/delete|יומן המחיקות]] לרשימה של המחיקות והשחזורים שבוצעו לאחרונה.",
- "undelete-header": "ראו את [[Special:Log/delete|יומן המחיקות]] לדפים שנמחקו לאחרונה.",
+ "undelete-header": "{{GENDER:|ראה|ראי|ראו}} את [[Special:Log/delete|יומן המחיקות]] לרשימה של דפים שנמחקו לאחרונה.",
"undelete-search-title": "חיפוש דפים שנמחקו",
"undelete-search-box": "חיפוש דפים שנמחקו",
"undelete-search-prefix": "הצגת דפים החל מ:",
"mycontris": "תרומות",
"anoncontribs": "תרומות",
"contribsub2": "עבור {{GENDER:$3|$1}} ($2)",
- "contributions-userdoesnotexist": "×\94×\97ש×\91×\95×\9f \"$1\" אינו רשום.",
+ "contributions-userdoesnotexist": "×\97ש×\91×\95×\9f ×\94×\9eשת×\9eש \"$1\" אינו רשום.",
"nocontribs": "לא נמצאו שינויים המתאימים לקריטריונים אלו.",
"uctop": "(נוכחי)",
"month": "עד החודש:",
"sp-contributions-blocked-notice": "{{GENDER:$1|המשתמש הזה חסום|המשתמשת הזו חסומה}} כרגע.\nהפעולה האחרונה ביומן החסימות מוצגת להלן:",
"sp-contributions-blocked-notice-anon": "כתובת IP זו חסומה כרגע.\nהפעולה האחרונה ביומן החסימות מוצגת להלן:",
"sp-contributions-search": "חיפוש תרומות",
- "sp-contributions-username": "ש×\9d ×\9eשת×\9eש ×\90×\95 ×\9bת×\95×\91ת IP:",
+ "sp-contributions-username": "×\9bת×\95×\91ת IP ×\90×\95 ש×\9d ×\9eשת×\9eש:",
"sp-contributions-toponly": "הצגת עריכות שהן הגרסאות האחרונות בלבד",
"sp-contributions-newonly": "הצגת עריכות שהן יצירות של דפים בלבד",
"sp-contributions-submit": "חיפוש",
"whatlinkshere": "דפים המקושרים לכאן",
- "whatlinkshere-title": "דפים המקשרים לדף $1",
+ "whatlinkshere-title": "דפים המקשרים לדף \"$1\"",
"whatlinkshere-page": "דף:",
"linkshere": "הדפים שלהלן מקושרים לדף '''[[:$1]]''':",
"nolinkshere": "אין דפים המקושרים לדף '''[[:$1]]'''.",
"ipb-hardblock": "ביטול האפשרות של משתמשים רשומים לערוך מכתובת IP זו",
"ipbcreateaccount": "חסימה של יצירת חשבונות",
"ipbemailban": "חסימה של שליחת דואר אלקטרוני",
- "ipbenableautoblock": "×\97ס×\99×\9e×\94 ×\90×\95×\98×\95×\9e×\98×\99ת ×\92×\9d ש×\9c ×\9bת×\95×\91ת ×\94Ö¾IP ×\94×\90×\97ר×\95× ×\94 ש×\94שת×\9eש ×\91×\94 ×\95של כל כתובת IP שינסה להשתמש בה בעתיד",
- "ipbsubmit": "×\97ס×\99×\9e×\94",
+ "ipbenableautoblock": "×\97ס×\99×\9e×\94 ×\90×\95×\98×\95×\9e×\98×\99ת ש×\9c ×\9bת×\95×\91ת ×\94Ö¾IP ×\94×\90×\97ר×\95× ×\94 ש×\94×\9eשת×\9eש עש×\94 ×\91×\94 ש×\99×\9e×\95ש, ×\95×\92×\9d של כל כתובת IP שינסה להשתמש בה בעתיד",
+ "ipbsubmit": "×\97ס×\99×\9eת ×\94×\9eשת×\9eש",
"ipbother": "זמן אחר:",
"ipboptions": "שעתיים:2 hours,יום:1 day,שלושה ימים:3 days,שבוע:1 week,שבועיים:2 weeks,חודש:1 month,שלושה חודשים:3 months,שישה חודשים:6 months,שנה:1 year,זמן בלתי מוגבל:infinite",
"ipbhidename": "הסתרת שם המשתמש מהעריכות ומהרשימות",
"badipaddress": "משתמש או כתובת IP שגויים.",
"blockipsuccesssub": "החסימה הושלמה בהצלחה",
"blockipsuccesstext": "{{GENDER:$1|המשתמש|המשתמשת}} [[Special:Contributions/$1|$1]] {{GENDER:$1|נחסם|נחסמה}}.\n\nראו את [[Special:BlockList|רשימת החסומים]] כדי לצפות בחסימות.",
- "ipb-blockingself": "אתם עומדים לחסום את עצמכם! האם אתם בטוחים שברצונכם לעשות זאת?",
- "ipb-confirmhideuser": "אתם עומדים לחסום משתמש עם האפשרות \"הסתרת משתמש\". זה יעלים את שם המשתמש בכל הרשימות ופעולות היומן. האם אתם בטוחים שברצונכם לעשות זאת?",
- "ipb-confirmaction": "אם אתם באמת בטוחים שברצונכם לעשות זאת, אנא סמנו את השדה \"{{int:ipb-confirm}}\" שבתחתית.",
+ "ipb-blockingself": "{{GENDER:|אתה עומד|את עומדת|אתם עומדים}} לחסום את {{GENDER:|עצמך|עצמך|עצמכם}}! האם {{GENDER:|אתה בטוח שאתה רוצה|את בטוחה שאת רוצה|אתם בטוחים שאתם רוצים}} לעשות את זה?",
+ "ipb-confirmhideuser": "{{GENDER:|אתה עומד|את עומדת|אתם עומדים}} לחסום משתמש עם האפשרות \"הסתרת משתמש\". זה יעלים את שם המשתמש בכל הרשימות ופעולות היומן. האם {{GENDER:|אתה בטוח שברצונך|את בטוחה שברצונך|אתם בטוחים שברצונכם}} לעשות את זה?",
+ "ipb-confirmaction": "אם {{GENDER:|אתה בטוח שברצונך|את בטוחה שברצונך|אתם בטוחים שברצונכם}} לעשות זאת, אנא {{GENDER:|סמן|סמני|סמנו}} את השדה \"{{int:ipb-confirm}}\" שמופיע למטה.",
"ipb-edit-dropdown": "עריכת סיבות החסימה",
- "ipb-unblock-addr": "×\94סרת חסימה של $1",
- "ipb-unblock": "×\94סרת ×\97ס×\99×\9e×\94 ש×\9c ש×\9d משתמש או כתובת IP",
+ "ipb-unblock-addr": "ש×\97ר×\95ר חסימה של $1",
+ "ipb-unblock": "ש×\97ר×\95ר ×\97ס×\99×\9e×\94 ש×\9c משתמש או כתובת IP",
"ipb-blocklist": "הצגת החסימות הנוכחיות",
- "ipb-blocklist-contribs": "×\94תר×\95×\9e×\95ת ש×\9c {{GENDER:$1|$1}}",
+ "ipb-blocklist-contribs": "תרומות של {{GENDER:$1|$1}}",
"ipb-blocklist-duration-left": "נותרו $1",
- "unblockip": "שחרור חסימה",
+ "unblockip": "שחרור חסימה של משתמש",
"unblockiptext": "השתמשו בטופס שלהלן כדי להחזיר את הרשאות הכתיבה למשתמש או כתובת IP חסומים.",
- "ipusubmit": "ש×\97ר×\95ר ×\97ס×\99×\9e×\94",
+ "ipusubmit": "×\94סרת ×\97ס×\99×\9e×\94 ×\96×\95",
"unblocked": "[[User:$1|$1]] {{GENDER:$1|שוחרר מחסימתו|שוחררה מחסימתה}}.",
"unblocked-range": "$1 שוחרר מחסימתו.",
"unblocked-id": "חסימה מספר $1 שוחררה.",
"blocklist": "משתמשים חסומים",
"ipblocklist": "משתמשים חסומים",
"ipblocklist-legend": "מציאת משתמש חסום",
- "blocklist-userblocks": "×\94סתרת ×\97ס×\99×\9eת ×\97ש×\91×\95× ×\95ת",
+ "blocklist-userblocks": "×\94סתרת ×\97ס×\99×\9e×\95ת ש×\9c ×\9eשת×\9eש×\99×\9d רש×\95×\9e×\99×\9d",
"blocklist-tempblocks": "הסתרת חסימות זמניות",
- "blocklist-addressblocks": "הסתרת חסימות IP בודד",
+ "blocklist-addressblocks": "הסתרת חסימות של כתובות IP בודדות",
"blocklist-rangeblocks": "הסתרת חסימות טווחים",
- "blocklist-timestamp": "×\96×\9e×\9f",
- "blocklist-target": "×\99×¢×\93",
- "blocklist-expiry": "פקיעה",
- "blocklist-by": "×\9eפע×\99×\9c ×\97×\95ס×\9d",
- "blocklist-params": "הגדרות חסימה",
+ "blocklist-timestamp": "ת×\90ר×\99×\9a ×\95שע×\94",
+ "blocklist-target": "×\94×\9eשת×\9eש ×©× ×\97ס×\9d",
+ "blocklist-expiry": "×\96×\9e×\9f פק×\99×¢×\94",
+ "blocklist-by": "× ×\97ס×\9d ×¢×\9cÖ¾×\99×\93×\99",
+ "blocklist-params": "×\94×\92×\93ר×\95ת ×\94×\97ס×\99×\9e×\94",
"blocklist-reason": "סיבה",
"ipblocklist-submit": "חיפוש",
"ipblocklist-localblock": "חסימה מקומית",
"ipblocklist-otherblocks": "{{PLURAL:$1|חסימה אחרת|חסימות אחרות}}",
- "infiniteblock": "×\91×\9cת×\99 ×\9e×\95×\92×\91×\9c ×\91זמן",
- "expiringblock": "פ×\95קע ×\91Ö¾$2, $1",
+ "infiniteblock": "×\9c×\9c×\90 ×\94×\92×\91×\9cת זמן",
+ "expiringblock": "×\94×\97ס×\99×\9e×\94 פ×\95קעת ×\91{{GRAMMAR:ת×\97×\99×\9c×\99ת|$1}} ×\91שע×\94 $2",
"anononlyblock": "משתמשים אנונימיים בלבד",
"noautoblockblock": "חסימה אוטומטית מבוטלת",
"createaccountblock": "יצירת חשבונות נחסמה",
"ipblocklist-empty": "רשימת המשתמשים החסומים ריקה.",
"ipblocklist-no-results": "שם המשתמש או כתובת ה־IP המבוקשים אינם חסומים.",
"blocklink": "חסימה",
- "unblocklink": "שחרור חסימה",
- "change-blocklink": "שינוי חסימה",
+ "unblocklink": "ש×\97ר×\95ר ×\94×\97ס×\99×\9e×\94",
+ "change-blocklink": "ש×\99× ×\95×\99 ×\94×\97ס×\99×\9e×\94",
"contribslink": "תרומות",
"emaillink": "שליחת דוא\"ל",
"autoblocker": "נחסמתם באופן אוטומטי משום שאתם חולקים את כתובת ה־IP שלכם עם [[User:$1|$1]].\nהסיבה שניתנה לחסימת $1 היא \"$2\"",
"blocklogpage": "יומן חסימות",
- "blocklog-showlog": "משתמש זה נחסם בעבר.\nיומן החסימות מוצג להלן:",
- "blocklog-showsuppresslog": "משתמש זה נחסם והוסתר בעבר.\nיומן ההעלמות מוצג להלן:",
+ "blocklog-showlog": "{{GENDER:$1|משתמש זה נחסם|משתמשת זו נחסמה}} בעבר.\nיומן החסימות מוצג להלן:",
+ "blocklog-showsuppresslog": "{{GENDER:$1|משתמש זה נחסם והוסתר|משתמשת זו נחסמה והוסתרה}} בעבר.\nיומן ההעלמות מוצג להלן:",
"blocklogentry": "חסם את [[$1]] למשך $2 $3",
"reblock-logentry": "שינה את הגדרות החסימה של [[$1]] עם זמן פקיעה של $2 $3",
"blocklogtext": "זהו יומן פעולות החסימה והשחרור של משתמשים.\nכתובות IP שנחסמו אוטומטית אינן מופיעות.\nראו גם את [[Special:BlockList|רשימת החסומים]] לרשימה של החרמות וחסימות פעילות כעת.",
"block-log-flags-noautoblock": "חסימה אוטומטית מבוטלת",
"block-log-flags-noemail": "שליחת דוא\"ל נחסמה",
"block-log-flags-nousertalk": "עריכת דף השיחה האישי נחסמה",
- "block-log-flags-angry-autoblock": "×\97ס×\99×\9e×\94 ×\90×\95×\98×\95×\9e×\98×\99ת ×\9eש×\95×\9b×\9c×\9cת מופעלת",
+ "block-log-flags-angry-autoblock": "×\97ס×\99×\9e×\94 ×\90×\95×\98×\95×\9e×\98×\99ת ×\9eתק×\93×\9eת מופעלת",
"block-log-flags-hiddenname": "שם המשתמש הוסתר",
"range_block_disabled": "האפשרות לחסום טווח כתובות אינה פעילה.",
"ipb_expiry_invalid": "זמן פקיעת החסימה אינו תקין.",
"ipb_expiry_temp": "חסימות הכוללות הסתרת שם משתמש חייבות להיות לזמן בלתי מוגבל.",
"ipb_hide_invalid": "לא ניתן להעלים את החשבון הזה; {{PLURAL:$1|בוצעה ממנו יותר מעריכה אחת|בוצעו ממנו יותר מ֫־$1 עריכות}}.",
"ipb_already_blocked": "המשתמש \"$1\" כבר נחסם.",
- "ipb-needreblock": "$1 כבר נחסם. האם ברצונך לשנות את הגדרות החסימה?",
+ "ipb-needreblock": "ה{{GENDER:$1|משתמש|משתמשת}} \"$1\" כבר {{GENDER:$1|חסום|חסומה}}. האם ברצונך לשנות את הגדרות החסימה?",
"ipb-otherblocks-header": "{{PLURAL:$1|חסימה אחרת|חסימות אחרות}}",
"unblock-hideuser": "אין באפשרותך לשחרר את החסימה של המשתמש הזה, כיוון ששם המשתמש שלו הוסתר.",
"ipb_cant_unblock": "שגיאה: חסימה מספר $1 לא נמצאה. ייתכן שהיא כבר שוחררה.",
"lockdbsuccesstext": "בסיס הנתונים ננעל.<br />\nיש לזכור [[Special:UnlockDB|לשחרר את הנעילה]] לאחר שפעולת התחזוקה תסתיים.",
"unlockdbsuccesstext": "שוחררה הנעילה של בסיס הנתונים",
"lockfilenotwritable": "קובץ נעילת בסיס הנתונים אינו ניתן לכתיבה. כדי שאפשר יהיה לנעול את בסיס הנתונים או לבטל את נעילתו, שרת האינטרנט צריך לקבל הרשאות לכתוב אליו.",
+ "databaselocked": "בסיס הנתונים כבר נעול.",
"databasenotlocked": "בסיס הנתונים אינו נעול.",
"lockedbyandtime": "(על־ידי $1 ב־$3, $2)",
- "move-page": "העברת $1",
+ "move-page": "העברת הדף \"$1\"",
"move-page-legend": "העברת דף",
- "movepagetext": "שימוש בטופס שלהלן ישנה את שמו של דף, ויעביר את כל ההיסטוריה שלו לשם חדש.\nהשם הישן יהפוך לדף הפניה אל הדף עם השם החדש.\nבאפשרותכם לעדכן אוטומטית דפי הפניה לכותרת המקורית.\nאם תבחרו לא לעשות זאת, אנא ודאו שאין [[Special:DoubleRedirects|הפניות כפולות]] או [[Special:BrokenRedirects|שבורות]].\nאתם אחראים לוודא שכל הקישורים ימשיכו להצביע למקום שאליו הם אמורים להצביע.\n\nשימו לב: הדף <strong>לא</strong> יועבר אם כבר יש דף תחת השם החדש, אלא אם הדף השני הוא הפניה ואין לו היסטוריית עריכות קודמות.\nפירוש הדבר שאפשר לשנות חזרה את שמו של דף לשם המקורי אם נעשתה טעות, ושלא ניתן לדרוס דף קיים.\n\n<strong>לתשומת לבכם:</strong>\nשינוי זה עשוי להיות שינוי דרסטי ובלתי צפוי לדף פופולרי;\nאנא ודאו שאתם מבינים את השלכות המעשה לפני שאתם ממשיכים.",
- "movepagetext-noredirectfixer": "שימוש בטופס שלהלן ישנה את שמו של דף, ויעביר את כל ההיסטוריה שלו לשם חדש.\nהשם הישן יהפוך לדף הפניה אל הדף עם השם החדש.\nאנא ודאו שאין [[Special:DoubleRedirects|הפניות כפולות]] או [[Special:BrokenRedirects|שבורות]].\nאתם אחראים לוודא שכל הקישורים ימשיכו להצביע למקום שאליו הם אמורים להצביע.\n\nשימו לב: הדף <strong>לא</strong> יועבר אם כבר יש דף תחת השם החדש, אלא אם הדף הזה הוא הפניה ואין לו היסטוריית עריכות קודמות.\nפירוש הדבר שאפשר לשנות חזרה את שמו של דף לשם המקורי אם נעשתה טעות, ושלא ניתן לדרוס דף קיים.\n\n<strong>לתשומת לבכם:</strong>\nשינוי זה עשוי להיות שינוי דרסטי ובלתי צפוי לדף פופולרי;\nאנא ודאו שאתם מבינים את השלכות המעשה לפני שאתם ממשיכים.",
+ "movepagetext": "{{GENDER:|השתמש|השתמשי|השתמשו}} בטופס שלהן כדי לשנות את השם של הדף הזה, ולהעביר את כל היסטוריית העריכות שלו לשם החדש.\nהשם הישן יהפוך לדף הפניה אל השם החדש.\n{{GENDER:|באפשרותך|באפשרותך|באפשרותכם}} לעדכן באופן אוטומטי דפי הפניה שכרגע מפנים לשם הנוכחי של הדף.\nאם {{GENDER:|תבחר|תבחרי|תבחרו}} לא לעשות זאת, אנא {{GENDER:|ודא|ודאי|ודאו}} לאחר ההעברה שאין [[Special:DoubleRedirects|הפניות כפולות]] או [[Special:BrokenRedirects|הפניות שבורות]].\nב{{GENDER:|אחריותך|אחריותך|אחריותכם}} לוודא שכל הקישורים ימשיכו לקשר למקומות שאליהם הם אמורים לקשר.\n\n{{GENDER:|שים|שימי|שימו}} לב שהדף <strong>לא</strong> יועבר אם כבר יש דף תחת השם החדש ש{{GENDER:|תבחר|תבחרי|תבחרו}}, אלא אם כן הדף עם השם החדש הוא הפניה ואין לו עריכות קודמות.\nזה אומר ש{{GENDER:|תוכל|תוכלי|תוכלו}} להחזיר את הדף לשם המקורי במקרה שתיעשה טעות, אבל לא ניתן \"לדרוס\" דף קיים.\n\n<strong>לתשומת {{GENDER:|לבך|לבך|לבכם}}:</strong>\nהעברה זו עלולה להיות שינוי דרסטי ומהותי לדף פופולרי;\nאנא {{GENDER:|ודא שאתה מבין|ודאי שאת מבינה|ודאו שאתם מבינים}} את התוצאות של הפעולה הזאת לפני ביצוע ההעברה.",
+ "movepagetext-noredirectfixer": "{{GENDER:|השתמש|השתמשי|השתמשו}} בטופס שלהן כדי לשנות את השם של הדף הזה, ולהעביר את כל היסטוריית העריכות שלו לשם החדש.\nהשם הישן יהפוך לדף הפניה אל השם החדש.\nאנא {{GENDER:|ודא|ודאי|ודאו}} לאחר ההעברה שאין [[Special:DoubleRedirects|הפניות כפולות]] או [[Special:BrokenRedirects|הפניות שבורות]].\nב{{GENDER:|אחריותך|אחריותך|אחריותכם}} לוודא שכל הקישורים ימשיכו לקשר למקומות שאליהם הם אמורים לקשר.\n\n{{GENDER:|שים|שימי|שימו}} לב שהדף <strong>לא</strong> יועבר אם כבר יש דף תחת השם החדש ש{{GENDER:|תבחר|תבחרי|תבחרו}}, אלא אם כן הדף עם השם החדש הוא הפניה ואין לו עריכות קודמות.\nזה אומר ש{{GENDER:|תוכל|תוכלי|תוכלו}} להחזיר את הדף לשם המקורי במקרה שתיעשה טעות, אבל לא ניתן \"לדרוס\" דף קיים.\n\n<strong>לתשומת {{GENDER:|לבך|לבך|לבכם}}:</strong>\nהעברה זו עלולה להיות שינוי דרסטי ומהותי לדף פופולרי;\nאנא {{GENDER:|ודא שאתה מבין|ודאי שאת מבינה|ודאו שאתם מבינים}} את התוצאות של הפעולה הזאת לפני ביצוע ההעברה.",
"movepagetalktext": "אם התיבה הזאת מסומנת, דף השיחה של דף זה יועבר אוטומטית לכותרת החדשה, אלא אם קיים שם דף שיחה שאינו ריק.\n\nבמקרה הזה, תצטרכו להעביר או לשלב את הדפים באופן ידני, אם תרצו.",
"moveuserpage-warning": "'''אזהרה:''' אתם עומדים להעביר דף משתמש. שימו לב שרק הדף יועבר וששם המשתמש '''לא''' ישתנה.",
"movecategorypage-warning": "<strong>אזהרה:</strong> אתם עומדים להעביר דף קטגוריה. שימו לב שרק הדף יועבר ושכל הדפים בקטגוריה הישנה <strong>לא</strong> יסווגו לקטגוריה החדשה.",
"cant-move-to-category-page": "אין לך הרשאה להעביר דף לדף קטגוריה.",
"newtitle": "השם החדש:",
"move-watch": "מעקב אחרי דף המקור ואחרי דף היעד",
- "movepagebtn": "×\94×¢×\91ר×\94",
+ "movepagebtn": "×\94×¢×\91רת ×\94×\93×£",
"pagemovedsub": "ההעברה הושלמה בהצלחה",
"movepage-moved": "הדף \"$1\" הועבר לשם \"$2\".",
"movepage-moved-redirect": "נוצרה הפניה.",
"tooltip-pt-userpage": "דף {{GENDER:|המשתמש|המשתמשת}} שלך",
"tooltip-pt-anonuserpage": "דף המשתמש של משתמש אנונימי זה",
"tooltip-pt-mytalk": "דף השיחה שלך",
- "tooltip-pt-anontalk": "ש×\99×\97×\94 ×¢×\9c תר×\95×\9e×\95ת ×\94×\9eשת×\9eש ×\94×\90× ×\95× ×\99×\9e×\99",
+ "tooltip-pt-anontalk": "×\93×\99×\95×\9f ×¢×\9c ×\94ער×\99×\9b×\95ת ×©× ×¢×©×\95 ×\9e×\9b×\95ת×\91ת ×\94Ö¾IP ×\94×\96×\90ת",
"tooltip-pt-preferences": "ההעדפות שלך",
- "tooltip-pt-watchlist": "רשימת הדפים שאתם עוקבים אחרי השינויים בהם",
+ "tooltip-pt-watchlist": "רשימת הדפים ש{{GENDER:|אתה עוקב|את עוקבת}} אחרי השינויים בהם",
"tooltip-pt-mycontris": "רשימת התרומות שלך",
"tooltip-pt-anoncontribs": "רשימת העריכות שנעשו מכתובת ה־IP הזאת",
- "tooltip-pt-login": "מומלץ להיכנס לחשבון; עם זאת, אין חובה לעשות זאת",
+ "tooltip-pt-login": "מומלץ להיכנס לחשבון, אבל לא חובה לעשות זאת",
"tooltip-pt-logout": "יציאה מהחשבון",
- "tooltip-pt-createaccount": "מומלץ ליצור חשבון ולהיכנס אליו; עם זאת, אין חובה לעשות זאת",
+ "tooltip-pt-createaccount": "מומלץ ליצור חשבון ולהיכנס אליו, אבל לא חובה לעשות זאת",
"tooltip-ca-talk": "שיחה על דף זה",
- "tooltip-ca-edit": "עריכת דף זה באמצעות קוד ויקי",
+ "tooltip-ca-edit": "עריכת דף זה",
"tooltip-ca-addsection": "הוספת פסקה חדשה",
- "tooltip-ca-viewsource": "×\93×£ ×\96×\94 ×\9e×\95×\92×\9f.\n×\91×\90פשר×\95ת×\9a ×\9cצפ×\95ת ×\91×\98קס×\98 המקור שלו",
+ "tooltip-ca-viewsource": "×\93×£ ×\96×\94 ×\9e×\95×\92×\9f.\n×\91×\90פשר×\95ת×\9a ×\9cצפ×\95ת ×\91ק×\95×\93 המקור שלו",
"tooltip-ca-history": "גרסאות קודמות של דף זה",
- "tooltip-ca-protect": "הגנה על דף זה",
+ "tooltip-ca-protect": "×\94פע×\9cת ×\94×\92× ×\94 ×¢×\9c ×\93×£ ×\96×\94",
"tooltip-ca-unprotect": "שינוי ההגנה על דף זה",
"tooltip-ca-delete": "מחיקת דף זה",
"tooltip-ca-undelete": "שחזור עריכות שנעשו בדף זה לפני שנמחק",
- "tooltip-ca-move": "×\94×¢×\91רת דף זה",
- "tooltip-ca-watch": "הוספת דף זה לרשימת המעקב",
- "tooltip-ca-unwatch": "הסרת דף זה מרשימת המעקב",
+ "tooltip-ca-move": "ש×\99× ×\95×\99 ×\94ש×\9d ש×\9c דף זה",
+ "tooltip-ca-watch": "הוספת דף זה לרשימת המעקב שלך",
+ "tooltip-ca-unwatch": "הסרת דף זה מרשימת המעקב שלך",
"tooltip-search": "חיפוש ב{{grammar:תחילית|{{SITENAME}}}}",
"tooltip-search-go": "מעבר לדף בשם הזה בדיוק, אם הוא קיים",
"tooltip-search-fulltext": "חיפוש טקסט זה בדפים",
"tooltip-t-recentchangeslinked": "השינויים האחרונים שבוצעו בדפים המקושרים מדף זה",
"tooltip-feed-rss": "הזנת RSS עבור דף זה",
"tooltip-feed-atom": "הזנת Atom עבור דף זה",
- "tooltip-t-contributions": "{{GENDER:$1|תרומותיו של משתמש זה|תרומותיה של משתמשת זו}}",
+ "tooltip-t-contributions": "רשימת העריכות שנעשו על־ידי {{GENDER:$1|משתמש זה|משתמשת זו}}",
"tooltip-t-emailuser": "שליחת דואר אלקטרוני {{GENDER:$1|למשתמש זה|למשתמשת זו}}",
"tooltip-t-info": "מידע נוסף על דף זה",
"tooltip-t-upload": "העלאת קבצים",
"tooltip-save": "שמירת השינויים שלך",
"tooltip-publish": "פרסום השינויים שלך",
"tooltip-preview": "תצוגה מקדימה של השינויים שלך. נא להשתמש באפשרות זו לפני השמירה.",
- "tooltip-diff": "צפ×\99×\99×\94 ×\91ש×\99× ×\95×\99×\99×\9d שער×\9bת×\9d בטקסט",
- "tooltip-compareselectedversions": "צפ×\99×\99×\94 ×\91×\94ש×\95×\95×\90ת שת×\99 ×\92רס×\90×\95ת ש×\9c ×\93×£ ×\96×\94",
+ "tooltip-diff": "×\94צ×\92ת ×\94ש×\99× ×\95×\99×\99×\9d ש×\91×\99צעת בטקסט",
+ "tooltip-compareselectedversions": "×\94צ×\92ת ×\94×\94×\91×\93×\9c×\99×\9d ×\91×\99×\9f שת×\99 ×\94×\92רס×\90×\95ת ×©× ×\91×\97ר×\95",
"tooltip-watch": "הוספת דף זה לרשימת המעקב שלך",
"tooltip-watchlistedit-normal-submit": "הסרת הדפים",
"tooltip-watchlistedit-raw-submit": "עדכון רשימת המעקב",
"tooltip-rollback": "שחזור בלחיצה אחת של העריכה או העריכות של התורם האחרון לדף זה",
"tooltip-undo": "פתיחת חלון העריכה במצב תצוגה מקדימה כדי לשחזר את העריכה, תוך אפשרות להוספת סיבה בתקציר העריכה",
"tooltip-preferences-save": "שמירת ההעדפות",
- "tooltip-summary": "×\9c×\94×\9b× ×¡×ª תקצ×\99ר קצר",
+ "tooltip-summary": "ת×\99×\90×\95ר קצר ש×\9c ×\94ש×\99× ×\95×\99×\99×\9d ש×\91×\99צעת",
"common.css": "/* הסגנונות הנכתבים כאן ישפיעו על כל העיצובים */",
"print.css": "/* הסגנונות הנכתבים כאן ישפיעו על הפלט בהדפסה בלבד */",
- "noscript.css": "/* הסגנונות הנכתבים כאן ישפיעו על משתמשים עם JavaScript מבוטל */",
+ "noscript.css": "/* הסגנונות הנכתבים כאן ישפיעו על משתמשים עם ג'אווה-סקריפט מבוטל */",
"group-autoconfirmed.css": "/* הסגנונות הנכתבים כאן ישפיעו על משתמשים ותיקים בלבד */",
"group-user.css": "/* הסגנונות הנכתבים כאן ישפיעו על משתמשים רשומים בלבד */",
"group-bot.css": "/* הסגנונות הנכתבים כאן ישפיעו על בוטים בלבד */",
"group-sysop.css": "/* הסגנונות הנכתבים כאן ישפיעו על מפעילי מערכת בלבד */",
"group-bureaucrat.css": "/* הסגנונות הנכתבים כאן ישפיעו על ביורוקרטים בלבד */",
- "common.js": "/* ×\9b×\9c סקר×\99פ×\98 JavaScript ×©× ×\9bת×\91 ×\9b×\90×\9f ×\99ר×\95×¥ ×¢×\91×\95ר ×\9b×\9c ×\94×\9eשת×\9eש×\99×\9d ×\91×\9b×\9c ×\98×¢×\99× ×ª ×¢×\9e×\95×\93 */",
- "group-autoconfirmed.js": "/* ×\9b×\9c סקר×\99פ×\98 JavaScript ×©× ×\9bת×\91 ×\9b×\90×\9f ×\99ר×\95×¥ עבור משתמשים ותיקים בלבד */",
- "group-user.js": "/* ×\9b×\9c סקר×\99פ×\98 JavaScript ×©× ×\9bת×\91 ×\9b×\90×\9f ×\99ר×\95×¥ עבור משתמשים רשומים בלבד */",
- "group-bot.js": "/* ×\9b×\9c סקר×\99פ×\98 JavaScript ×©× ×\9bת×\91 ×\9b×\90×\9f ×\99ר×\95×¥ עבור בוטים בלבד */",
- "group-sysop.js": "/* ×\9b×\9c סקר×\99פ×\98 JavaScript ×©× ×\9bת×\91 ×\9b×\90×\9f ×\99ר×\95×¥ עבור מפעילי מערכת בלבד */",
- "group-bureaucrat.js": "/* ×\9b×\9c סקר×\99פ×\98 JavaScript ×©× ×\9bת×\91 ×\9b×\90×\9f ×\99ר×\95×¥ עבור ביורוקרטים בלבד */",
+ "common.js": "/* ×\9b×\9c ×\94סקר×\99פ×\98×\99×\9d ×©× ×\9bת×\91×\99×\9d ×\9b×\90×\9f ×\99×\99×\98×¢× ×\95 ×¢×\91×\95ר ×\9b×\9c ×\94×\9eשת×\9eש×\99×\9d ×\91×\9b×\9c ×\98×¢×\99× ×ª ×¢×\9e×\95×\93. */",
+ "group-autoconfirmed.js": "/* ×\9b×\9c ×\94סקר×\99פ×\98×\99×\9d ×\94× ×\9bת×\91×\99×\9d ×\9b×\90×\9f ×\99×\99×\98×¢× ×\95 עבור משתמשים ותיקים בלבד */",
+ "group-user.js": "/* ×\9b×\9c ×\94סקר×\99פ×\98×\99×\9d ×\94× ×\9bת×\91×\99×\9d ×\9b×\90×\9f ×\99×\99×\98×¢× ×\95 עבור משתמשים רשומים בלבד */",
+ "group-bot.js": "/* ×\9b×\9c ×\94סקר×\99פ×\98×\99×\9d ×\94× ×\9bת×\91×\99×\9d ×\9b×\90×\9f ×\99×\99×\98×¢× ×\95 עבור בוטים בלבד */",
+ "group-sysop.js": "/* ×\9b×\9c ×\94סקר×\99פ×\98×\99×\9d ×\94× ×\9bת×\91×\99×\9d ×\9b×\90×\9f ×\99×\99×\98×¢× ×\95 עבור מפעילי מערכת בלבד */",
+ "group-bureaucrat.js": "/* ×\9b×\9c ×\94סקר×\99פ×\98×\99×\9d ×\94× ×\9bת×\91×\99×\9d ×\9b×\90×\9f ×\99×\99×\98×¢× ×\95 עבור ביורוקרטים בלבד */",
"anonymous": "{{PLURAL:$1|משתמש אנונימי|משתמשים אנונימיים}} של {{SITENAME}}",
"siteuser": "משתמש {{SITENAME}} $1",
"anonuser": "משתמש אנונימי של {{SITENAME}} $1",
- "lastmodifiedatby": "דף זה שונה לאחרונה ב־$2, $1 על־ידי $3.",
+ "lastmodifiedatby": "דף זה שוּנה לאחרונה ב־$2, $1 על־ידי $3.",
"othercontribs": "מבוסס על העבודה של $1.",
"others": "אחרים",
"siteusers": "{{PLURAL:$2|{{GENDER:$1|משתמש}}|משתמשי}} {{SITENAME}} $1",
"spam_blanking": "כל הגרסאות כוללות קישורים ל־$1, מרוקן את הדף",
"spam_deleting": "כל הגרסאות כוללות קישורים ל־$1, מוחק את הדף",
"simpleantispam-label": "בדיקת אנטי־ספאם.\n<strong>אל</strong> תמלאו שדה זה!",
- "pageinfo-title": "מידע על \"$1\"",
+ "pageinfo-title": "מידע על הדף \"$1\"",
"pageinfo-not-current": "מצטערים, לא ניתן להציג את המידע הזה לגרסאות ישנות.",
"pageinfo-header-basic": "מידע בסיסי",
"pageinfo-header-edits": "היסטוריית עריכות",
"markedaspatrollederror": "לא ניתן לסמן כבדוק",
"markedaspatrollederrortext": "יש לציין גרסה שברצונך לסמן כבדוקה.",
"markedaspatrollederror-noautopatrol": "אינך מורשה לסמן שינויים של עצמך כבדוקים.",
- "markedaspatrollednotify": "ש×\99× ×\95×\99 ×\96×\94 ×\9c\"$1\" סומן כבדוק.",
+ "markedaspatrollednotify": "ש×\99× ×\95×\99 ×\96×\94 ×\91×\93×£ \"$1\" סומן כבדוק.",
"markedaspatrollederrornotify": "סימון השינוי כבדוק נכשל.",
"patrol-log-page": "יומן שינויים בדוקים",
"patrol-log-header": "יומן זה מציג גרסאות שנבדקו.",
"log-show-hide-patrol": "$1 יומן שינויים בדוקים",
"log-show-hide-tag": "$1 יומן תגיות",
- "deletedrevision": "×\9e×\97ק ×\92רס×\94 ×\99×©× ×\94 $1",
+ "deletedrevision": "×\9e×\97×\99קת ×\92רס×\94 ×\99×©× ×\94 ($1)",
"filedeleteerror-short": "שגיאה במחיקת הקובץ: $1",
"filedeleteerror-long": "שגיאות שאירעו בעת מחיקת הקובץ:\n\n$1",
"filedelete-missing": "מחיקת הקובץ \"$1\" נכשלה, כיוון שהוא אינו קיים.",
"confirm-purge-top": "לנקות את המטמון של דף זה?",
"confirm-purge-bottom": "ניקוי המטמון של דף גורם לגרסה החדשה ביותר להופיע.",
"confirm-watch-button": "אישור",
- "confirm-watch-top": "×\9c×\94×\95ס×\99×£ ×\93×£ זה לרשימת המעקב שלך?",
+ "confirm-watch-top": "×\9c×\94×\95ס×\99×£ ×\90ת ×\94×\93×£ ×\94זה לרשימת המעקב שלך?",
"confirm-unwatch-button": "אישור",
- "confirm-unwatch-top": "להסיר דף זה מרשימת המעקב שלך?",
+ "confirm-unwatch-top": "להסיר את הדף הזה מרשימת המעקב שלך?",
+ "confirm-rollback-button": "אישור",
+ "confirm-rollback-top": "לשחזור את השינויים לדף הזה?",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "→ לדף הקודם",
"imgmultipagenext": "לדף הבא ←",
"autoredircomment": "הפניה לדף [[$1]]",
"autosumm-new": "יצירת דף עם התוכן \"$1\"",
"autosumm-newblank": "יצירת דף ריק",
- "size-bytes": "{{PLURAL:$1|בייט אחד|$1 בייט}}",
+ "size-bytes": "{{PLURAL:$1|בייט אחד|$1 בייטים}}",
"size-kilobytes": "$1 קילו־בייט",
"size-megabytes": "$1 מגה־בייט",
"size-gigabytes": "$1 ג'יגה־בייט",
"watchlisttools-clear": "ניקוי רשימת המעקב",
"watchlisttools-view": "הצגת השינויים הרלוונטיים",
"watchlisttools-edit": "הצגה ועריכה של רשימת המעקב",
- "watchlisttools-raw": "ער×\99×\9bת ×\94רש×\99×\9e×\94 הגולמית",
+ "watchlisttools-raw": "ער×\99×\9bת רש×\99×\9eת ×\94×\9eעק×\91 הגולמית",
"iranian-calendar-m1": "פרברדין",
"iranian-calendar-m2": "אורדיבהשט",
"iranian-calendar-m3": "חורדאד",
"timezone-local": "מקומי",
"duplicate-defaultsort": "'''אזהרה:''' המיון הרגיל \"$2\" דורס את המיון הרגיל המוקדם ממנו \"$1\".",
"duplicate-displaytitle": "<strong>אזהרה:</strong> כותרת התצוגה \"$2\" דורסת את כותרת התצוגה הקודמת \"$1\".",
+ "restricted-displaytitle": "<strong>אזהרה:</strong> כותרת התצוגה \"$1\" לא הופעלה כי היא אינה תואמת לכותרת האמיתית של הדף.",
"invalid-indicator-name": "<strong>שגיאה:</strong> התכונה <code>name</code> של מצייני מצב הדף אינה יכולה להיות ריקה.",
"version": "גרסת התוכנה",
"version-extensions": "הרחבות מותקנות",
"tags-delete-not-found": "התגית \"$1\" אינה קיימת.",
"tags-delete-too-many-uses": "התגית \"$1\" מוחלת על יותר {{PLURAL:$2|מגרסה אחת|מ־$2 גרסאות}}, ולכן לא ניתן למחוק אותה.",
"tags-delete-warnings-after-delete": "התגית \"$1\" נמחקה, אבל {{PLURAL:$2|התקבלה האזהרה הבאה|התקבלו האזהרות הבאות}}:",
+ "tags-delete-no-permission": "אין לך הרשאה למחוק תגיות שינויים.",
"tags-activate-title": "הפעלת תגית",
"tags-activate-question": "אתם עומדים להפעיל את התגית \"$1\".",
"tags-activate-reason": "הסבר:",
"tags-edit-success": "השינויים הוחלו.",
"tags-edit-failure": "החלת השינויים נכשלה:\n$1",
"tags-edit-nooldid-title": "גרסת היעד אינה תקינה",
- "tags-edit-nooldid-text": "×\90×\95 שלא ציינת שום גרסה שהפעולה תבוצע עליה, או שהגרסה שציינת אינה קיימת.",
+ "tags-edit-nooldid-text": "×\99×\99ת×\9b×\9f שלא ציינת שום גרסה שהפעולה תבוצע עליה, או שהגרסה שציינת אינה קיימת.",
"tags-edit-none-selected": "יש לבחור לפחות תגית אחת להוספה או להסרה.",
"comparepages": "השוואת דפים",
"compare-page1": "דף 1",
"dberr-usegoogle": "באפשרותך לנסות לחפש באמצעות גוגל בינתיים.",
"dberr-outofdate": "שימו לב שהתוכן שלנו כפי שנשמר במאגר שם עשוי שלא להיות מעודכן.",
"dberr-cachederror": "זהו עותק שמור של המידע, והוא עשוי שלא להיות מעודכן.",
- "htmlform-invalid-input": "×\99ש ×\91×¢×\99×\95ת ×¢×\9d ×\97×\9cק ×\9e×\94ק×\9c×\98 ש×\94×\9b× ×¡×ª",
+ "htmlform-invalid-input": "×\99ש ×\91×¢×\99×\95ת ×¢×\9d ×\97×\9cק ×\9e×\94ק×\9c×\98 ש×\94×\95×\9b× ×¡.",
"htmlform-select-badoption": "הערך שציינת אינו אפשרות תקינה.",
"htmlform-int-invalid": "הערך שציינת אינו מספר שלם.",
"htmlform-float-invalid": "הערך שציינת אינו מספר.",
"htmlform-int-toolow": "הערך שציינת הוא מתחת למינימום, $1",
"htmlform-int-toohigh": "הערך שציינת הוא מעל למקסימום, $1",
- "htmlform-required": "ער×\9a ×\96×\94 ×\93ר×\95ש",
+ "htmlform-required": "ש×\93×\94 ×\96×\94 ×\93ר×\95ש.",
"htmlform-submit": "שליחה",
"htmlform-reset": "ביטול השינויים",
"htmlform-selectorother-other": "אחר",
"logentry-block-reblock": "$1 {{GENDER:$2|שינה|שינתה}} את הגדרות החסימה של {{GENDER:$4|$3}} עם זמן פקיעה של $5 $6",
"logentry-suppress-block": "$1 {{GENDER:$2|חסם|חסמה}} את {{GENDER:$4|$3}} עם זמן פקיעה של $5 $6",
"logentry-suppress-reblock": "$1 {{GENDER:$2|שינה|שינתה}} את הגדרות החסימה של {{GENDER:$4|$3}} עם זמן פקיעה של $5 $6",
- "logentry-import-upload": "$1 {{GENDER:$2|ייבא|ייבאה}} את $3 באמצעות העלאת קובץ",
+ "logentry-import-upload": "$1 {{GENDER:$2|ייבא|ייבאה}} את הדף $3 באמצעות העלאת קובץ",
"logentry-import-upload-details": "$1 {{GENDER:$2|ייבא|ייבאה}} את $3 באמצעות העלאת קובץ ({{PLURAL:$4|גרסה אחת|$4 גרסאות}})",
- "logentry-import-interwiki": "$1 {{GENDER:$2|ייבא|ייבאה}} את $3 מאתר ויקי אחר",
- "logentry-import-interwiki-details": "$1 {{GENDER:$2|ייבא|ייבאה}} את $3 מ־$5‏ ({{PLURAL:$4|גרסה אחת|$4 גרסאות}})",
- "logentry-merge-merge": "$1 {{GENDER:$2|מיזג|מיזגה}} את $3 לתוך $4 (גרסאות עד $5)",
+ "logentry-import-interwiki": "$1 {{GENDER:$2|ייבא|ייבאה}} את הדף $3 מאתר ויקי אחר",
+ "logentry-import-interwiki-details": "$1 {{GENDER:$2|ייבא|ייבאה}} את הדף $3 מ־$5‏ ({{PLURAL:$4|גרסה אחת|$4 גרסאות}})",
+ "logentry-merge-merge": "$1 {{GENDER:$2|מיזג|מיזגה}} את הדף $3 לתוך הדף $4 (גרסאות עד $5)",
"logentry-move-move": "$1 {{GENDER:$2|העביר|העבירה}} את הדף $3 לשם $4",
"logentry-move-move-noredirect": "$1 {{GENDER:$2|העביר|העבירה}} את הדף $3 לשם $4 בלי להשאיר הפניה",
"logentry-move-move_redir": "$1 {{GENDER:$2|העביר|העבירה}} את הדף $3 לשם $4 תוך דריסת הפניה",
"sessionprovider-nocookies": "ייתכן שאפשרות השימוש בעוגיות כבויה. יש לוודא שאפשרות השימוש בעוגיות מופעלת ולהתחיל מחדש.",
"randomrootpage": "דף שורש אקראי",
"log-action-filter-block": "סוג החסימות:",
- "log-action-filter-contentmodel": "סוג השינויים במודל תוכן:",
+ "log-action-filter-contentmodel": "ס×\95×\92 ×\94ש×\99× ×\95×\99×\99×\9d ×\91×\9e×\95×\93×\9c ×\94ת×\95×\9b×\9f:",
"log-action-filter-delete": "סוג המחיקות:",
"log-action-filter-import": "סוג פעולות הייבוא:",
- "log-action-filter-managetags": "ס×\95×\92 פע×\95×\9c×\95ת × ×\99×\94×\95×\9c ×\94תגיות:",
+ "log-action-filter-managetags": "ס×\95×\92 ×\94ש×\99× ×\95×\99×\99×\9d ×\91תגיות:",
"log-action-filter-move": "סוג ההעברות:",
- "log-action-filter-newusers": "ס×\95×\92 ×\99צ×\99ר×\95ת ×\94×\97ש×\91×\95×\9f:",
- "log-action-filter-patrol": "ס×\95×\92 ×\94ש×\99× ×\95×\99×\99×\9d ×\94בדוקים:",
+ "log-action-filter-newusers": "ס×\95×\92 פע×\95×\9c×\95ת ×\94×\94רש×\9e×\94:",
+ "log-action-filter-patrol": "ס×\95×\92 ×\94ס×\99×\9e×\95× ×\99×\9d ש×\9c ×\94ש×\99× ×\95×\99×\99×\9d ×\9bבדוקים:",
"log-action-filter-protect": "סוג ההגנות:",
- "log-action-filter-rights": "ס×\95×\92 ש×\99× ×\95×\99×\99 ×\94×\94רש×\90×\94",
+ "log-action-filter-rights": "ס×\95×\92 ש×\99× ×\95×\99×\99 ×\94×\94רש×\90×\95ת:",
"log-action-filter-suppress": "סוג ההעלמות",
"log-action-filter-upload": "סוג ההעלאות:",
"log-action-filter-all": "הכול",
"log-action-filter-block-block": "חסימות",
- "log-action-filter-block-reblock": "שינויי חסימה",
- "log-action-filter-block-unblock": "שחרורי חסימה",
- "log-action-filter-contentmodel-change": "ש×\99× ×\95×\99×\99×\9d ×\91×\9e×\95×\93×\9c ת×\95×\9b×\9f",
- "log-action-filter-contentmodel-new": "×\99צ×\99ר×\95ת ×\93פ×\99×\9d ×¢×\9d ×\9e×\95×\93×\9c ת×\95×\9b×\9f ×\9c×\90־ס×\98× ×\93ר×\98×\99",
- "log-action-filter-delete-delete": "×\9e×\97×\99קת דפים",
- "log-action-filter-delete-restore": "שחזור דפים מחוקים",
- "log-action-filter-delete-event": "×\9e×\97×\99קת פעולות יומן",
- "log-action-filter-delete-revision": "×\9e×\97×\99קת גרסאות",
- "log-action-filter-import-interwiki": "פע×\95×\9c×\95ת ×\99×\99×\91×\95×\90 מאתרי ויקי אחרים",
- "log-action-filter-import-upload": "פע×\95×\9c×\95ת ×\99×\99×\91×\95×\90 ×¢×\9cÖ¾×\99×\93×\99 העלאת XML",
+ "log-action-filter-block-reblock": "שינויים של חסימות",
+ "log-action-filter-block-unblock": "שחרורים של חסימות",
+ "log-action-filter-contentmodel-change": "ש×\99× ×\95×\99×\99×\9d ×\91×\9e×\95×\93×\9c ×\94ת×\95×\9b×\9f ש×\9c ×\93פ×\99×\9d ק×\99×\99×\9e×\99×\9d",
+ "log-action-filter-contentmodel-new": "×\99צ×\99ר×\95ת ש×\9c ×\93פ×\99×\9d ×¢×\9d ×\9e×\95×\93×\9c ת×\95×\9b×\9f ש×\95× ×\94 ×\9e×\91ר×\99רת ×\94×\9e×\97×\93×\9c",
+ "log-action-filter-delete-delete": "×\9e×\97×\99ק×\95ת ש×\9c דפים",
+ "log-action-filter-delete-restore": "שחזורים של דפים מחוקים",
+ "log-action-filter-delete-event": "×\9e×\97×\99ק×\95ת ש×\9c פעולות יומן",
+ "log-action-filter-delete-revision": "×\9e×\97×\99ק×\95ת ש×\9c גרסאות",
+ "log-action-filter-import-interwiki": "×\99×\99×\91×\95×\90 ×\93פ×\99×\9d מאתרי ויקי אחרים",
+ "log-action-filter-import-upload": "×\99×\99×\91×\95×\90 ×\93פ×\99×\9d ×\91×\90×\9eצע×\95ת העלאת XML",
"log-action-filter-managetags-create": "יצירות של תגיות",
"log-action-filter-managetags-delete": "מחיקות של תגיות",
"log-action-filter-managetags-activate": "הפעלות של תגיות",
"log-action-filter-managetags-deactivate": "ביטול הפעלות של תגיות",
"log-action-filter-move-move": "העברות ללא דריסת הפניות",
"log-action-filter-move-move_redir": "העברות עם דריסת הפניות",
- "log-action-filter-newusers-create": "×\99צ×\99רות על־ידי משתמשים אנונימיים",
- "log-action-filter-newusers-create2": "יצירות על־ידי משתמשים רשומים",
- "log-action-filter-newusers-autocreate": "יצירות אוטומטיות",
- "log-action-filter-newusers-byemail": "יצירות עם סיסמה שנשלחה בדוא\"ל",
- "log-action-filter-patrol-patrol": "ס×\99×\9e×\95× ×\99×\99×\9d ×\99×\93× ×\99×\99×\9d ×\9b×\91×\93×\95ק",
- "log-action-filter-patrol-autopatrol": "סימונים אוטומטיים כבדוק",
- "log-action-filter-protect-protect": "הגנות",
- "log-action-filter-protect-modify": "שינויי הגנה",
- "log-action-filter-protect-unprotect": "×\94סר×\95ת ×\94×\92× ×\94",
- "log-action-filter-protect-move_prot": "×\94×¢×\91ר×\95ת ש×\9c ×\94×\92× ×\94",
+ "log-action-filter-newusers-create": "×\94רש×\9eות על־ידי משתמשים אנונימיים",
+ "log-action-filter-newusers-create2": "×\99צ×\99ר×\95ת ש×\9c ×\97ש×\91×\95× ×\95ת ×¢×\9cÖ¾×\99×\93×\99 ×\9eשת×\9eש×\99×\9d רש×\95×\9e×\99×\9d",
+ "log-action-filter-newusers-autocreate": "יצירות אוטומטיות של חשבונות",
+ "log-action-filter-newusers-byemail": "×\99צ×\99ר×\95ת ש×\9c ×\97ש×\91×\95× ×\95ת ×¢×\9d ס×\99ס×\9e×\94 ×©× ×©×\9c×\97×\94 ×\91×\93×\95×\90\"×\9c",
+ "log-action-filter-patrol-patrol": "ס×\99×\9e×\95× ×\99×\9d ×\99×\93× ×\99×\99×\9d",
+ "log-action-filter-patrol-autopatrol": "סימונים אוטומטיים",
+ "log-action-filter-protect-protect": "×\94פע×\9c×\95ת ש×\9c ×\94×\92× ×\95ת",
+ "log-action-filter-protect-modify": "שינויים של הגנות",
+ "log-action-filter-protect-unprotect": "×\94סר×\95ת ש×\9c ×\94×\92× ×\95ת",
+ "log-action-filter-protect-move_prot": "×\94×¢×\91ר×\95ת ש×\9c ×\94×\92× ×\95ת",
"log-action-filter-rights-rights": "שינויים ידניים",
"log-action-filter-rights-autopromote": "שינויים אוטומטיים",
"log-action-filter-suppress-event": "העלמות של פעולות יומן",
"log-action-filter-suppress-block": "העלמות של משתמשים באמצעות חסימה",
"log-action-filter-suppress-reblock": "העלמות של משתמשים באמצעות חסימה מחדש",
"log-action-filter-upload-upload": "העלאות חדשות",
- "log-action-filter-upload-overwrite": "דריסת קבצים קיימים"
+ "log-action-filter-upload-overwrite": "דריסות של קבצים קיימים",
+ "authmanager-authn-not-in-progress": "האימות נכשל או שנתוני הפעולה נאבדו. נא להתחיל את התהליך מחדש.",
+ "authmanager-authn-no-primary": "לא ניתן היה לאמת את האישורים שסופקו.",
+ "authmanager-authn-no-local-user": "האישורים שסופקו אינם שייכים לשום משתמש באתר זה.",
+ "authmanager-authn-no-local-user-link": "נתוני ההאמנה שניתנו תקינים, אבל אינם משויכים לשום משתמש בוויקי הזה. נא להיכנס לחשבון באופן שונה, או ליצור משתמש חדש ואז תהיה לך אפשרות לקשר את נתוני ההאמנה הקודמים שלך לחשבון ההוא.",
+ "authmanager-authn-autocreate-failed": "יצירה אוטומטית של חשבון מקומי נכשלה: $1",
+ "authmanager-change-not-supported": "לא ניתן לשנות את נתוני ההאמנה שניתנו, כי שום דבר לא ישתמש בהם.",
+ "authmanager-create-disabled": "אפשרות יצירת החשבונות מבוטלת.",
+ "authmanager-create-from-login": "כדי ליצור את החשבון, נא למלא את השדות שלהלן.",
+ "authmanager-create-not-in-progress": "יצירת החשבון נכשלה או שנתוני הפעולה נאבדו. נא להתחיל את התהליך מחדש.",
+ "authmanager-create-no-primary": "האישורים שסופקו לא יכולים להיות בשימוש ביצירת חשבון.",
+ "authmanager-link-no-primary": "האישורים שסופקו לא יכולים להיות בשימוש בקישור חשבונות.",
+ "authmanager-link-not-in-progress": "קישור החשבונות נכשל או שנתוני הפעולה נאבדו. נא להתחיל את התהליך מחדש.",
+ "authmanager-authplugin-setpass-failed-title": "שינוי הסיסמה נכשל",
+ "authmanager-authplugin-setpass-failed-message": "תוסף האימות דחה את שינוי הסיסמה.",
+ "authmanager-authplugin-create-fail": "תוסף האימות דחה את יצירת החשבון.",
+ "authmanager-authplugin-setpass-denied": "תוסף האימות אינו מאפשר לשנות סיסמאות.",
+ "authmanager-authplugin-setpass-bad-domain": "דומיין לא תקין.",
+ "authmanager-autocreate-noperm": "אין אפשרות ליצור חשבונות באופן אוטומטי.",
+ "authmanager-autocreate-exception": "יצירת חשבונות אוטומטית מבוטלת באופן אוטומטי בשל שגיאות קודמות.",
+ "authmanager-userdoesnotexist": "חשבון המשתמש \"$1\" אינו רשום.",
+ "authmanager-userlogin-remembermypassword-help": "האם לזכור את הסיסמה למשך זמן ארוך יותר מאורך הפעולה.",
+ "authmanager-username-help": "שם המשתמש לאימות.",
+ "authmanager-password-help": "הסיסמה לאימות.",
+ "authmanager-domain-help": "שם מתחם לאימות חיצוני.",
+ "authmanager-retype-help": "חזרה על הסיסמה.",
+ "authmanager-email-label": "דוא\"ל",
+ "authmanager-email-help": "כתובת דוא\"ל",
+ "authmanager-realname-label": "שם אמיתי",
+ "authmanager-realname-help": "השם האמיתי של המשתמש",
+ "authmanager-provider-password": "אימות שמבוסס על סיסמה",
+ "authmanager-provider-password-domain": "אימות מבוסס מתחם וססמה.",
+ "authmanager-provider-temporarypassword": "סיסמה זמנית",
+ "authprovider-confirmlink-message": "בהתבסס על ניסיונות הכניסה האחרונים שלך, ניתן לקשר את החשבונות הבאים לחשבון שלך. לאחר שהחשבונות יקושרו, ניתן יהיה להיכנס לחשבון באמצעותם. נא לבחור את החשבונות שברצונך לקשר.",
+ "authprovider-confirmlink-request-label": "החשבונות שיקושרו",
+ "authprovider-confirmlink-success-line": "$1: הקישור בוצע בהצלחה.",
+ "authprovider-confirmlink-failed": "קישור החשבונות לא הושלם: $1",
+ "authprovider-confirmlink-ok-help": "להמשיך אחרי הודעות שגיאת קישור.",
+ "authprovider-resetpass-skip-label": "דילוג",
+ "authprovider-resetpass-skip-help": "לדלג על איפוס הסיסמה.",
+ "authform-nosession-login": "האימות הושלם בהצלחה, אבל הדפדפן שלך אינו \"זוכר\" את הכניסה שלך לחשבון.\n\n$1",
+ "authform-nosession-signup": "החשבון נוצר, אבל הדפדפן שלך אינו \"זוכר\" את הכניסה שלך לחשבון.\n\n$1",
+ "authform-newtoken": "אסימון חסר. $1",
+ "authform-notoken": "אסימון חסר",
+ "authform-wrongtoken": "אסימון שגוי",
+ "specialpage-securitylevel-not-allowed-title": "הגישה נדחתה",
+ "specialpage-securitylevel-not-allowed": "מצטערים, אין באפשרותך להשתמש בדף זה כי הזהות שלך לא אומתה.",
+ "authpage-cannot-login": "לא ניתן להתחיל את תהליך הכניסה לחשבון.",
+ "authpage-cannot-login-continue": "לא ניתן היה להיכנס לחשבון. כנראה שזמן ההמתנה של הפעולה חלף.",
+ "authpage-cannot-create": "לא ניתן להתחיל את תהליך יצירת החשבון.",
+ "authpage-cannot-create-continue": "לא ניתן להמשיך בתהליך יצירת החשבון. כנראה שזמן ההמתנה של הפעולה חלף.",
+ "authpage-cannot-link": "לא ניתן להתחיל את תהליך קישור החשבונות.",
+ "authpage-cannot-link-continue": "לא ניתן להמשיך בתהליך קישור החשבונות. כנראה שזמן ההמתנה של הפעולה חלף.",
+ "cannotauth-not-allowed-title": "הגישה נדחתה",
+ "cannotauth-not-allowed": "אינך מורשה להשתמש בדף זה",
+ "changecredentials": "שינוי האישורים",
+ "changecredentials-submit": "שינוי האישורים",
+ "changecredentials-invalidsubpage": "$1 אינו סוג אישור תקין.",
+ "changecredentials-success": "האישורים שלך שונו.",
+ "removecredentials": "הסרת האישורים",
+ "removecredentials-submit": "הסרת האישורים",
+ "removecredentials-invalidsubpage": "$1 אינו סוג אישור תקין.",
+ "removecredentials-success": "האישורים שלך הוסרו.",
+ "credentialsform-provider": "סוג האישורים:",
+ "credentialsform-account": "שם החשבון:",
+ "cannotlink-no-provider-title": "אין חשבונות שניתן לקשר",
+ "cannotlink-no-provider": "אין חשבונות שניתן לקשר.",
+ "linkaccounts": "קישור חשבונות",
+ "linkaccounts-success-text": "החשבון קושר.",
+ "linkaccounts-submit": "קישור החשבונות",
+ "unlinkaccounts": "ביטול הקישור של החשבונות",
+ "unlinkaccounts-success": "קישור החשבון בוטל."
}
"tog-watchdefault": "मेरे द्वारा सम्पादित पृष्ठों और फ़ाइलों को मेरी ध्यानसूची में जोड़ें",
"tog-watchmoves": "मेरे द्वारा स्थानांतरित पृष्ठों एवं फ़ाइलों को मेरी ध्यानसूची में जोड़ें",
"tog-watchdeletion": "मेरे द्वारा हटाए गए पृष्ठों एवं फ़ाइलों को मेरी ध्यानसूची में जोड़ें",
+ "tog-watchuploads": "मेरे नए फ़ाइलों को मेरे ध्यानसूची में डालें।",
"tog-watchrollback": "मेरे द्वारा प्रत्यापन्न (रोलबैक) किये हुये पृष्ठों को मेरी ध्यानसूची में जोड़ें।",
"tog-minordefault": "मेरे सभी सम्पादनों को छोटे बदलाव के रूप में चिह्नित करें",
"tog-previewontop": "सम्पादन सन्दूक से पहले झलक दिखायें",
"password-change-forbidden": "आप इस विकि पर कूटशब्द नहीं बदल सकते हैं।",
"externaldberror": "या तो प्रमाणिकरण डाटाबेस में त्रुटि हुई है या फिर आपको अपना बाह्य खाता अपडेट करने की अनुमति नहीं है।",
"login": "प्रवेश",
+ "login-security": "अपनी पहचान सत्यापित करें",
"nav-login-createaccount": "सत्रारंभ / खाता खोलें",
"userlogin": "सत्रारंभ / खाता खोलें",
"userloginnocreate": "लॉग इन",
"userlogin-resetpassword-link": "अपना पासवर्ड भूल गए?",
"userlogin-helplink2": "लॉग इन करने में सहायता",
"userlogin-loggedin": "आप {{GENDER:$1|$1}} के रूप में पहले से लॉग्ड इन हैं।\nकिसी अन्य सदस्य के रूप में लॉग इन करने के लिए निम्नलिखित फ़ॉर्म का प्रयोग करें।",
+ "userlogin-reauth": "आप {{GENDER:$1|$1}} हो, इसके लिए आपको एक और बार खाते में प्रवेश करना होगा।",
"userlogin-createanother": "एक अन्य खाता खोलें",
"createacct-emailrequired": "ई-मेल पता",
"createacct-emailoptional": "ई-मेल पता (वैकल्पिक)",
"createacct-email-ph": "अपना ई-मेल पता लिखें",
"createacct-another-email-ph": "ईमेल पता प्रदान करें",
"createaccountmail": "एक अस्थायी यादृच्छिक (रैंडम) कूटशब्द चुनें और उसे निर्दिष्ट ई-मेल पते पर भेजें",
+ "createaccountmail-help": "इसका उपयोग बिना पासवर्ड जाने किसी और के लिए खाता खोलने के लिए उपयोग किया जाता है।",
"createacct-realname": "असली नाम (वैकल्पिक)",
"createaccountreason": "कारण:",
"createacct-reason": "कारण",
"createacct-reason-ph": "आप एक अन्य खाता क्यों बना रहे हैं",
+ "createacct-reason-help": "खाता निर्माण लॉग में यह सन्देश दिखाई देगा।",
"createacct-submit": "अपना खाता बनाएँ",
"createacct-another-submit": "खाता बनाएँ",
+ "createacct-continue-submit": "खाता निर्माण जारी रखें",
+ "createacct-another-continue-submit": "खाता निर्माण जारी रखें",
"createacct-benefit-heading": "{{SITENAME}} आपके जैसे लोगों द्वारा बनायी गई है।",
"createacct-benefit-body1": "{{PLURAL:$1|सम्पादन}}",
"createacct-benefit-body2": "{{PLURAL:$1|पृष्ठ}}",
"noname": "आपने वैध सदस्यनाम नहीं दिया है।",
"loginsuccesstitle": "प्रवेश हुआ",
"loginsuccess": "'''आप {{SITENAME}} में \"$1\" सदस्यनाम से लॉग इन हो {{GENDER:$1|चुके|चुकी|चुके}} हैं।'''",
- "nosuchuser": "\"$1\" नाम का कोई सदस्य नहीं है।\nसदस्यनाम में लघु और दीर्घ अक्षरों से फ़र्क पड़ता है।\nअपनी वर्तनी जाँचें, या [[Special:UserLogin/signup|नया खाता खोलें]]।",
+ "nosuchuser": "यहाँ \"$1\" नाम का कोई सदस्य नहीं है।\nसदस्यनाम में लघु और दीर्घ अक्षरों से फ़र्क पड़ता है।\nअपनी वर्तनी जाँचें, या [[Special:CreateAccount|नया खाता खोलें]]।",
"nosuchusershort": "\"$1\" नाम का कोई सदस्य नहीं है।\nकृपया अपनी दी हुई वर्तनी जाँचें।",
"nouserspecified": "सदस्यनाम देना अनिवार्य है।",
"login-userblocked": "यह सदस्य प्रतिबन्धित है। सत्रारम्भ की अनुमति नहीं है।",
"createacct-another-realname-tip": "असली नाम देना आवश्यक नहीं है।\nयदि आप प्रदान करते हैं तो इसका प्रयोग सदस्य के योगदानों के लिये उनको श्रेय (attribution) देने के लिये किया जायेगा।",
"pt-login": "लॉग इन",
"pt-login-button": "लॉग इन",
+ "pt-login-continue-button": "प्रवेश जारी रखें",
"pt-createaccount": "खाता बनाएँ",
"pt-userlogout": "लॉगआउट",
"php-mail-error-unknown": "PHP के mail() फ़ंक्शन में अज्ञात त्रुटि हुई।",
"botpasswords-invalid-name": "जो सदस्य नाम आप बता रहे हो, उसमें बॉट पासवर्ड अलग करने वाला (\"$1\") नहीं है।",
"botpasswords-not-exist": "सदस्य \"$1\" के आप बॉट पासवर्ड नहीं है, जिसका नाम \"$2\" है।",
"resetpass_forbidden": "कूटशब्द बदले नहीं जा सकते",
+ "resetpass_forbidden-reason": "पासवर्ड नहीं बदला : $1",
"resetpass-no-info": "इस पृष्ठ का सीधे प्रयोग करने के लिए आपको लॉग इन करना होगा।",
"resetpass-submit-loggedin": "कूटशब्द बदलें",
"resetpass-submit-cancel": "रद्द करें",
"passwordreset-emailsentusername": "यदि कोई ईमेल इस खाते से जुड़ी है तो पासवर्ड आपके ईमेल में भेज दिया जाएगा।",
"passwordreset-emailsent-capture": "नीचे दिखाया गया कूटशब्द रीसेट ई-मेल भेज दिया गया है।",
"passwordreset-emailerror-capture": "नीचे दृष्टित कूटशब्द रीसेट ई-मेल उत्पन्न किया गया था, परंतु उसे {{GENDER:$2|सदस्य}} को भेजना असफल रहा।\nत्रुटि: $1",
+ "passwordreset-emailerror-capture2": "{{GENDER:$2|सदस्य}} को ईमेल भेजना विफल : $1 {{PLURAL:$3|सदस्य नाम और पासवर्ड|सदस्य नाम और पासवर्ड की सूची}} नीचे दिया गया है।",
+ "passwordreset-invalideamil": "अवैध ईमेल पता",
"changeemail": "ई-मेल पता परिवर्तित करें",
"changeemail-header": "अपना ईमेल पता परिवर्तन हेतु इसे पूरा करें। यदि आप अपना वर्तमान ईमेल पता हटाना चाहते हैं, तो इसे खाली छोड़ दें और इसे भेजें।",
"changeemail-passwordrequired": "आपको इस परिवर्तन हेतु पासवर्ड (कूटशब्द) डालना होगा।",
"minoredit": "यह एक छोटा बदलाव है",
"watchthis": "इस पृष्ठ को ध्यानसूची में डालें",
"savearticle": "पृष्ठ सहेजें",
+ "publishpage": "पृष्ठ प्रकाशित करें",
"preview": "झलक",
"showpreview": "झलक दिखाएँ",
"showdiff": "बदलाव दिखाएँ",
"accmailtext": "[[User talk:$1|$1]] के लिए एक यंत्र जनित कूटशब्द $2 को भेज दिया गया है। लॉगिन करने के बाद इसे '''[[Special:ChangePassword|कूटशब्द बदलें]]'' वाले पृष्ठ पर बदला जा सकता है।",
"newarticle": "(नया)",
"newarticletext": "आप ऐसे पृष्ठ पर आए हैं जो अभी तक बनाया नहीं गया है।\nपृष्ठ बनाने के लिये नीचे के बौक्स में पाठ लिखें। अधिक जानकारी के लिये [$1 सहायता पृष्ठ] देखें।\nअगर आप यहाँ पर गलती से आए हैं तो अपने ब्राउज़र के बैक ('''back''') बटन पर क्लिक करें।",
- "anontalkpagetext": "----''यह वार्ता पृष्ठ उन बेनामी सदस्यों के लिये है जिन्होंने या तो खाता नहीं खोला है या खाते का प्रयोग नहीं कर रहे हैं।\nइसलिये उनकी पहचान के लिये हमें उनका आइ॰पी पता प्रयोग करना पड़ता है।\nआइ॰पी पता कई सदस्यों के लिए साझा हो सकता है।\nयदि आप एक बेनामी सदस्य हैं और आपको लगता है कि आपके बारे में अप्रासंगिक टीका टिप्पणी की गई है तो कृपया [[Special:UserLogin/signup|सदस्यता लें]] या [[Special:UserLogin|सत्रारंभ करें]] ताकि अन्य बेनामी सदस्यों में से आपको अलग से पहचाना जा सके।''",
+ "anontalkpagetext": "----\n<em>यह वार्ता पृष्ठ उन बेनामी सदस्यों के लिये है जिन्होंने या तो खाता नहीं खोला है या खाते का प्रयोग नहीं कर रहे हैं।</em>\nइसलिये उनकी पहचान के लिये हमें उनका संख्यात्मक आई॰पी॰ पता प्रयोग करना पड़ता है।\nऐसा आई॰पी॰ पता कई सदस्यों के लिए साझा हो सकता है।\nयदि आप एक बेनामी सदस्य हैं और आपको लगता है कि आपके बारे में अप्रासंगिक टीका टिप्पणी की गई है तो कृपया [[Special:CreateAccount|सदस्यता लें]] या [[Special:UserLogin|सत्रारंभ करें]] ताकि अन्य बेनामी सदस्यों में से आपको अलग से पहचाना जा सके।",
"noarticletext": "फ़िलहाल इस पृष्ठ पर कोई सामग्री नहीं है।\nआप अन्य पृष्ठों में [[Special:Search/{{PAGENAME}}|इस शीर्षक की खोज]] कर सकते हैं,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} सम्बन्धित लॉग खोज सकते हैं],\nया इस पृष्ठ को [{{fullurl:{{FULLPAGENAME}}|action=edit}} सम्पादित] कर सकते हैं</span>।",
"noarticletext-nopermission": "फ़िलहाल इस पृष्ठ पर कोई सामग्री नहीं है।\nआप अन्य पृष्ठों में [[Special:Search/{{PAGENAME}}|इस शीर्षक की खोज]] कर सकते हैं,\nया <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} संबंधित लॉग खोज सकते हैं]</span>, परन्तु आपको यह पृष्ठ बनाने की अनुमति नहीं है।",
"missing-revision": "\"{{FULLPAGENAME}}\" पृष्ठ का अवतरण #$1 मौजूद नहीं है।\n\nआम तौर पर यह एक हटाए गए पृष्ठ के पुराने लिंक पर क्लिक करने से होता है।\nअधिक जानकारी के लिए आप [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} हटाने का लॉग] देख सकते हैं।",
"upload-form-label-own-work": "यह मेरा कार्य है",
"upload-form-label-infoform-categories": "श्रेणियाँ",
"upload-form-label-infoform-date": "दिनांक",
- "upload-form-label-own-work-message-local": "मैं यह सत्यापित करता हूँ कि मेरे द्वारा डाला गया फ़ाइल {{SITENAME}} सेवा के शर्तों और अधिकार नियम के अनुकूल है।",
- "upload-form-label-not-own-work-message-local": "यदि आप {{SITENAME}} के नियमों के अंतर्गत फ़ाइल नहीं डाल सकते, तो आप इसे हटा कर किसी दूसरे विधि का उपयोग करें।",
- "upload-form-label-not-own-work-local-local": "आप [[Special:Upload|मूल डालने वाले पृष्ठ]] का भी उपयोग कर सकते हो।",
- "upload-form-label-own-work-message-default": "मैं यह समझता हूँ कि यहाँ सभी फ़ाइल सांझा होते हैं। मैं यह सत्यापित करता हूँ कि में सेवा के शर्तों और नियम के अनुरूप ही कार्य कर रहा हूँ।",
- "upload-form-label-not-own-work-message-default": "यदि आप इस नियम के अंतर्गत फ़ाइल नहीं डालना चाहते तो अभी इसे बन्द कर दें और कोई दूसरे विधि को खोजें।",
- "upload-form-label-not-own-work-local-default": "यदि आप चाहें तो आप [[Special:Upload|{{SITENAME}} के पृष्ठ]] पर फ़ाइल डाल सकते हैं, यदि यह फ़ाइल वहाँ के नियम के अंतर्गत हो तो।",
- "upload-form-label-own-work-message-shared": "कम से कम इस फ़ाइल का प्रतिकृति अधिकार मेरे पास है और यह [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] के अंतर्गत है, व [https://wikimediafoundation.org/wiki/Terms_of_Use विकि उपयोग की शर्तों] का भी पालन करता है।",
- "upload-form-label-not-own-work-message-shared": "यदि आपके पास इस फ़ाइल का प्रतिकृति अधिकार नहीं है और आप इसे किसी और अधिकार के तहत प्रदर्शित करना चाहते हैं तो आप [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons Upload Wizard] का उपयोग करें।",
- "upload-form-label-not-own-work-local-shared": "यदि आप चाहें तो आप [[Special:Upload|{{SITENAME}} के पृष्ठ]] पर फ़ाइल डाल सकते हैं, यदि यह फ़ाइल वहाँ के नियम के अंतर्गत हो तो।",
+ "upload-form-label-own-work-message-generic-local": "मैं यह सत्यापित करता हूँ कि मेरे द्वारा डाला गया फ़ाइल {{SITENAME}} सेवा के शर्तों और अधिकार नियम के अनुकूल है।",
+ "upload-form-label-not-own-work-message-generic-local": "यदि आप {{SITENAME}} के नियमों के अंतर्गत फ़ाइल नहीं डाल सकते, तो आप इसे हटा कर किसी दूसरे विधि का उपयोग करें।",
+ "upload-form-label-not-own-work-local-generic-local": "आप [[Special:Upload|मूल डालने वाले पृष्ठ]] का भी उपयोग कर सकते हो।",
+ "upload-form-label-own-work-message-generic-foreign": "मैं यह समझता हूँ कि यहाँ सभी फ़ाइल सांझा होते हैं। मैं यह सत्यापित करता हूँ कि में सेवा के शर्तों और नियम के अनुरूप ही कार्य कर रहा हूँ।",
+ "upload-form-label-not-own-work-message-generic-foreign": "यदि आप इस नियम के अंतर्गत फ़ाइल नहीं डालना चाहते तो अभी इसे बन्द कर दें और कोई दूसरे विधि को खोजें।",
+ "upload-form-label-not-own-work-local-generic-foreign": "यदि आप चाहें तो आप [[Special:Upload|{{SITENAME}} के पृष्ठ]] पर फ़ाइल डाल सकते हैं, यदि यह फ़ाइल वहाँ के नियम के अंतर्गत हो तो।",
"backend-fail-stream": "फ़ाइल $1 स्ट्रीम नहीं हो पाई।",
"backend-fail-backup": "फ़ाइल $1 बैकअप नहीं हो पाई।",
"backend-fail-notexists": "फ़ाइल $1 मौजूद नहीं है।",
"changecontentmodel-success-text": "[[:$1]] के सामग्री का प्रकार परिवर्तित हुआ।",
"changecontentmodel-cannot-convert": "[[:$1]] की सामग्री का प्रकार $2 में नहीं बदल सकता है।",
"changecontentmodel-nodirectediting": "$1 सामग्री सीधे सम्पादन समर्थित नहीं करता है",
+ "changecontentmodel-emptymodels-title": "कोई सामग्री प्रारूप उपलब्ध नहीं",
+ "changecontentmodel-emptymodels-text": "[[:$1]] में सामग्री किसी और प्रकार में परिवर्तित नहीं हो सकती।",
"log-name-contentmodel": "सामाग्री परिवर्तन लॉग",
"log-description-contentmodel": "आयोजन जो इस पृष्ठ के सामग्री से मिलते जुलते हैं",
"logentry-contentmodel-new": "$1 ने $3 पृष्ठ का {{GENDER:$2|निर्माण}} किया बिना मूल सामग्री प्रारूप के \"$5\"",
"whatlinkshere-hideredirs": "$1 पुनर्निर्देश",
"whatlinkshere-hidetrans": "$1 ट्रान्स्क्ल्युजन्स",
"whatlinkshere-hidelinks": "$1 कड़ियाँ",
- "whatlinkshere-hideimages": "$1 फ़ाà¤\87ल लिà¤\82à¤\95",
+ "whatlinkshere-hideimages": "$1 फ़ाà¤\87ल à¤\95ड़à¥\80",
"whatlinkshere-filters": "छन्ने",
"whatlinkshere-submit": "जायें",
"autoblockid": "स्वतः अवरोध #$1",
"lockdbsuccesstext": "डाटाबेस को ताला लगाया गया हैं।<br />\nआपके द्वारा मेंटेनन्स पूरा होने के बाद [[Special:UnlockDB|ताला खोलना]] याद रखें।",
"unlockdbsuccesstext": "डाटाबेसका ताला खोल दिया गया हैं।",
"lockfilenotwritable": "डाटाबेस के लॉक फ़ाईलमें लिख नहीं पा रहें हैं।\nडाटाबेस का ताला लगाने या खोलनेके लिये, इस फ़ाईलपर लिखा जाना जरूरी हैं।",
+ "databaselocked": "डाटाबेस पहले से बंद है।",
"databasenotlocked": "डाटाबेस को ताला नहीं लगाया गया हैं।",
"lockedbyandtime": "(द्वारा {{GENDER:$1|$1}} पर $2 यहां $3)",
"move-page": "$1 ले जाएं",
"tooltip-ca-nstab-category": "श्रेणियाँ पृष्ठ देखियें",
"tooltip-minoredit": "इसे छोटे बदलाव के तौर पर दर्ज करें",
"tooltip-save": "अपने बदलाव सँजोएँ",
+ "tooltip-publish": "आपके परिवर्तक प्रकाशित करें",
"tooltip-preview": "अपने बदलावों की झलक देखें, कृपया सँजोने से पहले इसका इस्तेमाल करें!",
"tooltip-diff": "इस पाठ्यमें आपने किये हुए बदलाव देखें।",
"tooltip-compareselectedversions": "इस पृष्ठ के चुने हुए अवतरणों में अन्तर देखें।",
"confirmemail_body_set": "किसी ने, शायद आपने ही, आई॰पी पते $1 से,\n{{SITENAME}} पर \"$2\" सदस्य खाते का ई-मेल पता यह ईमेल पता निर्दिष्ट किया है।\n\nइस बात की पुष्टि करने के लिए कि यह सदस्य खाता आपका ही है,\nऔर {{SITENAME}} पर ईमेल सुविधाएँ शुरू करने के लिए निम्न लिंक अपने ब्राउज़र में खोलें:\n\n$3\n\nयदि यह सदस्य खाता आपका नहीं है, ई-मेल पुष्टि रद्द करने के लिए निम्न लिंक पर जाएँ:\n\n$5\n\nयह पुष्टिकरण लिंक $6 को $7 के बाद काम नहीं करेंगे।",
"confirmemail_invalidated": "इ-मेल एड्रेस प्रमाणिकरण रद्द कर दिया गया हैं",
"invalidateemail": "इ-मेल प्रमाणिकरण रद्द करें",
+ "notificationemail_subject_changed": "{{SITENAME}} पंजीकृत ईमेल खाता बदला गया।",
+ "notificationemail_subject_removed": "{{SITENAME}} पंजीकृत ईमेल खाता हटाया गया।",
"scarytranscludedisabled": "[आंतरविकि ट्रान्स्क्लुडिंग बंद हैं]",
"scarytranscludefailed": "[$1 के लिये साँचा मँगा नहीं पाए]",
"scarytranscludefailed-httpstatus": "[$1 के लिये साँचा मँगा नहीं पाए, त्रुटि: HTTP $2]",
"confirm-watch-top": "इस पृष्ठ को अपने ध्यानसूची में जोड़ें?",
"confirm-unwatch-button": "ठीक है",
"confirm-unwatch-top": "यह पृष्ठ अपने ध्यानसूचीसे हटाएं?",
+ "confirm-rollback-button": "ठीक है",
+ "confirm-rollback-top": "इस पृष्ठ के सम्पादन पूर्ववत करें?",
"semicolon-separator": ";",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← पिछला पृष्ठ",
"watchlistedit-raw-done": "आपकी ध्यानसूची अपडेट कर दी गई हैं",
"watchlistedit-raw-added": "{{PLURAL:$1|1शीर्षक|$1 शीर्षक}} बढा दिये:",
"watchlistedit-raw-removed": "{{PLURAL:$1|1शीर्षक|$1 शीर्षक}} हटा दिये:",
- "watchlistedit-clear-title": "धà¥\8dयानसà¥\82à¤\9aà¥\80 à¤\96ालà¥\80 à¤\95à¥\80",
+ "watchlistedit-clear-title": "धà¥\8dयानसà¥\82à¤\9aà¥\80 à¤\96ालà¥\80 à¤\95रà¥\87à¤\82",
"watchlistedit-clear-legend": "ध्यानसूची खाली करें",
"watchlistedit-clear-explain": "आपकी ध्यानसूची से सभी पृष्ठ हटा दिये जायेंगे",
"watchlistedit-clear-titles": "खिताब:",
"timezone-local": "स्थानीय",
"duplicate-defaultsort": "'''Warning:''' पुरानी मूल क्रमांकन कुंजी \"$1\" के बजाय अब मूल क्रमांकन कुंजी \"$2\" होगी।",
"duplicate-displaytitle": "<strong>चेतावनी:</strong> शीर्षक दिखाएँ \"$2\" पूर्व दिखाए गए शीर्षक \"$1\" पर छा रहा है।",
+ "restricted-displaytitle": "<strong>चेतावनी :</strong> प्रदर्शित शीर्षक \"$1\" को नजरअंदाज किया गया है, क्योंकि यह वास्तविक शीर्षक से मिलता नहीं है।",
"invalid-indicator-name": "<strong>त्रुटि:</strong> पृष्ठ स्थिति सांकेतक <code>नाम</code> गुण खाली नहीं रहना चाहिए।",
"version": "रूपान्तर",
"version-extensions": "इन्स्टॉल की हुई एक्स्टेंशन",
"version-libraries-license": "अनुज्ञापत्र",
"version-libraries-description": "विवरण",
"version-libraries-authors": "लेखक",
- "redirect": "à¤\85नà¥\81पà¥\8dरà¥\87षित à¤\95रà¥\87à¤\82 फ़ाà¤\87ल, à¤\89पयà¥\8bà¤\97à¤\95रà¥\8dता, या सà¤\82शà¥\8bधन पहà¤\9aान à¤\95à¥\87 à¤\86धार पर",
+ "redirect": "फ़ाà¤\87ल, सदसà¥\8dय, पà¥\83षà¥\8dठ, à¤\85वतरण या लà¥\89à¤\97 à¤\86à¤\88डà¥\80 दà¥\8dवारा à¤\85नà¥\81पà¥\8dरà¥\87षित",
"redirect-summary": "यह विशेष पृष्ठ फ़ाइलनाम प्रदान करने पर फ़ाइल नाम को, पृष्ठ आइ॰दी अथवा अवतरण आइ॰दी देने पर पृष्ठ को, और सदस्य आइ॰दी देने पर सदस्य पृष्ठ को पुनर्प्रेषित करता है। उदाहरण: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], या [[{{#Special:Redirect}}/user/101]]।",
"redirect-submit": "जायें",
"redirect-lookup": "ढूँढें:",
"tags-delete-not-found": "टैग \"$1\" मौजूद नहीं है।",
"tags-delete-too-many-uses": "टैग \"$1\" का प्रयोग $2 के {{PLURAL:$2|संशोधन|संशोधनों}} से अधिक है, जिसका अर्थ यह है कि उसे हटाया नहीं जा सकता है।",
"tags-delete-warnings-after-delete": "टैग \"$1\" को सफलतापूर्वक हटाया गया, परन्तु निम्न लिखित {{PLURAL:$2|चेतावनी|चेतावनियाँ}} पाई गई:",
+ "tags-delete-no-permission": "आपको बदलाव टैग हटाने की अनुमति नहीं है।",
"tags-activate-title": "टैग सक्रिय करें",
"tags-activate-question": "आप टैग \"$1\" को सक्रिय करने जा रहे हैं।",
"tags-activate-reason": "कारण:",
"feedback-useragent": "सदस्य कर्ता:",
"searchsuggest-search": "खोज",
"searchsuggest-containing": "...से युक्त",
+ "api-error-autoblocked": "आपका आईपी पता अपने आप अवरोधित हो गया, क्योंकि यह किसी अवरोधित सदस्य द्वारा उपयोग किया गया था।",
"api-error-badaccess-groups": "आपको इस विकि के लिए फ़ाइलें अपलोड करने की अनुमति नहीं है.",
"api-error-badtoken": "आंतरिक त्रुटि: बुरी टोकन।",
+ "api-error-blocked": "आपको सम्पादन से अवरोधित किया गया है।",
"api-error-copyuploaddisabled": "URL द्वारा इस सर्वर पर अपलोड अक्षम है।",
"api-error-duplicate": "वहाँ {{PLURAL:$1| अन्य फ़ाइल | रहे हैं कुछ अन्य फ़ाइलों}} एक ही सामग्री के साथ साइट पर पहले से ही है.",
"api-error-duplicate-archive": "वहाँ {{PLURAL:$1|था कुछ अन्य फ़ाइल |were कुछ अन्य फ़ाइलें}}, पहले से ही {{PLURAL:$1|यह was|they थे}} परन्तु हटा दिये गये",
"randomrootpage": "अविशिष्ट मूल पृष्ठ",
"log-action-filter-block": "प्रतिबंध के प्रकार:",
"log-action-filter-delete": "हटाने के प्रकार:",
+ "log-action-filter-import": "आयात के प्रकार:",
+ "log-action-filter-move": "स्थानांतरण के प्रकार:",
+ "log-action-filter-newusers": "खाता निर्माण के प्रकार:",
"log-action-filter-patrol": "परीक्षण के प्रकार:",
"log-action-filter-protect": "सुरक्षा के प्रकार:",
+ "log-action-filter-rights": "अधिकार बदलाव के प्रकार",
"log-action-filter-upload": "अपलोड के प्रकार:",
"log-action-filter-all": "सभी",
"log-action-filter-block-block": "अवरोध",
"log-action-filter-delete-restore": "पृष्ठ न हटाना",
"log-action-filter-delete-event": "पृष्ठ हटाने का लॉग",
"log-action-filter-delete-revision": "अवतरण हटाना",
+ "log-action-filter-managetags-create": "चिप्पि निर्मित",
+ "log-action-filter-newusers-create": "अज्ञात सदस्य द्वारा निर्मित",
+ "log-action-filter-newusers-create2": "पंजीकृत सदस्य द्वारा निर्मित",
+ "log-action-filter-newusers-autocreate": "स्वतः निर्मित",
+ "log-action-filter-newusers-byemail": "पासवर्ड ईमेल द्वारा भेजा गया के साथ निर्मित",
"log-action-filter-patrol-patrol": "अपने से परीक्षण",
"log-action-filter-patrol-autopatrol": "स्वतः पुनरीक्षण",
"log-action-filter-protect-protect": "सुरक्षा",
"log-action-filter-protect-modify": "सुरक्षा परिवर्तन",
"log-action-filter-protect-unprotect": "असुरक्षा",
+ "log-action-filter-protect-move_prot": "सुरक्षा स्थानांतरण",
+ "log-action-filter-rights-autopromote": "स्वतः परिवर्तन",
"log-action-filter-upload-upload": "नया अपलोड",
- "log-action-filter-upload-overwrite": "फिर से अपलोड"
+ "log-action-filter-upload-overwrite": "फिर से अपलोड",
+ "authmanager-create-disabled": "खाता निर्माण निष्क्रिय है।",
+ "authmanager-authplugin-setpass-failed-title": "पासवर्ड बदलाव विफल हुआ।",
+ "authmanager-authplugin-setpass-bad-domain": "अमान्य जालस्थल।",
+ "authmanager-autocreate-noperm": "स्वचालित खाता निर्माण की अनुमति नहीं है।",
+ "authmanager-autocreate-exception": "स्वचालित खाता निर्माण को पहले के कुछ त्रुटियों के कारण कुछ समय के लिए निष्क्रिय किया गया है।",
+ "authmanager-userdoesnotexist": "सदस्य खाता \"$1\" पंजीकृत नहीं है।",
+ "authmanager-email-label": "ईमेल",
+ "authmanager-email-help": "ईमेल पता",
+ "authmanager-realname-label": "वास्तविक नाम",
+ "authmanager-realname-help": "सदस्य का वास्तविक नाम",
+ "authmanager-provider-temporarypassword": "अस्थाई पासवर्ड",
+ "authprovider-confirmlink-request-label": "खाते जो जोड़ने हैं।",
+ "authprovider-confirmlink-success-line": "$1 : सफलतापूर्वक जुड़ा।",
+ "authprovider-confirmlink-failed": "खाता जोड़ने का काम पूरी तरह से नहीं हो पाया : $1",
+ "authprovider-resetpass-skip-label": "छोड़ें",
+ "authform-newtoken": "टोकन लापता है $1",
+ "authform-notoken": "टोकन लापता है",
+ "authform-wrongtoken": "गलत टोकन",
+ "specialpage-securitylevel-not-allowed-title": "अनुमति नहीं है",
+ "specialpage-securitylevel-not-allowed": "क्षमा करें, आप इस पृष्ठ का उपयोग नहीं कर सकते हैं, क्योंकि आपकी जानकारी सत्यापित नहीं है।",
+ "authpage-cannot-login": "प्रवेश करने में अक्षम।",
+ "authpage-cannot-login-continue": "प्रवेश करने में अक्षम। हो सकता है कि आपका सत्र समय समाप्त हो गया।",
+ "authpage-cannot-create": "खाता निर्माण में अक्षम है।",
+ "authpage-cannot-create-continue": "खाता निर्माण में अक्षम है। हो सकता है कि आपका सत्र समाप्त हो गया हो।",
+ "authpage-cannot-link": "खाता जोड़ना शुरू नहीं कर सकते।",
+ "authpage-cannot-link-continue": "खाता जोड़ने में विफल रहा। हो सकता है कि आपका सत्र समय समाप्त हो गया।",
+ "cannotauth-not-allowed-title": "अनुमति नहीं मिली।",
+ "cannotauth-not-allowed": "आपको इस पृष्ठ के उपयोग की अनुमति नहीं है।",
+ "changecredentials": "साख बदलें",
+ "changecredentials-submit": "साख बदलें",
+ "changecredentials-invalidsubpage": "$1 सही परिचय प्रकार नहीं है।",
+ "changecredentials-success": "आपका परिचय बदला गया।",
+ "removecredentials": "परिचय निकालें",
+ "removecredentials-submit": "परिचय निकालें",
+ "removecredentials-invalidsubpage": "$1 सही परिचय प्रकार नहीं है।",
+ "removecredentials-success": "आपका परिचय निकाल दिया गया है।",
+ "credentialsform-provider": "परिचय प्रकार :",
+ "credentialsform-account": "खाते का नाम:",
+ "cannotlink-no-provider-title": "कोई जुड़ा खाता नहीं है।",
+ "cannotlink-no-provider": "कोई जुड़ा खाता नहीं है।",
+ "linkaccounts": "खाता जोड़ें",
+ "linkaccounts-success-text": "खाता जुड़ गया।",
+ "linkaccounts-submit": "खाता जोड़ें",
+ "unlinkaccounts": "खाता अलग करें",
+ "unlinkaccounts-success": "खाता अलग हो गया।"
}
"noname": "Aap achchha user name ke nai specify karaa hai.",
"loginsuccesstitle": "Login safal bhais",
"loginsuccess": "'''Aap \"$1\" ke naam pe {{SITENAME}} me logged in hai.'''",
- "nosuchuser": "\"$1\" naam ke koi sadasya nai hai.\nSadasya ke naam case sensitive hai.\nAapan spelling check karo nai to [[Special:UserLogin/signup|nawaa account banao]].",
+ "nosuchuser": "\"$1\" naam ke koi sadasya nai hai.\nSadasya ke naam case sensitive hai.\nAapan spelling check karo nai to [[Special:CreateAccount|nawaa account banao]].",
"nosuchusershort": "\"$1\" naam ke koi sadasya nai hai.\nAapan spelling check karo.",
"nouserspecified": "Aap ke aapan username de ke parri.",
"login-userblocked": "Ii sadasya ke rok dewa gais hae. Login kare ke ijajat nai hae.",
"accmailtext": "Ek randomly banawal password ke [[User talk:$1|$1]] ke khatir $2 ke lage bhaja gais hai.\nIi nawa account ke password ke ''[[Special:ChangePassword|change password]]'' panna pe badla jaae sake hai jab aap login karta hai.",
"newarticle": "(Nawaa)",
"newarticletext": "Aap ek panna ke jorr ke follow kara hae jon ki abhi nai hae.\nIi panna banae khatir, niche box me type karo (see the [$1 help page] for more info).\nAgar jo aap hian par galti se aae hai tab aapan browser ke '''back''' button pe click karo.",
- "anontalkpagetext": "----''Ii salah kare waala panna uu anonymous sadasya ke baare me jon abhi account nai banais hai, nai to account ke kaam me nai lawe hai.\nIi kaaran se ham log ke IP address kaam me lae ke ii sadasya ke jaana jae hai.\n\nIi rakam ke IP address ke dher sadasya kaam me lae sake hai.\nAgar aap ek anonymous user hai aur ii sochta hai ki bekar baat aap ke baare me karaa gais hai, tab\n[[Special:UserLogin/signup|create an account]] or [[Special:UserLogin|log in]] aage ke garrbarri roke khatir aur duusra anonymous users se mistake nai kare ke khatir .''",
+ "anontalkpagetext": "----''Ii salah kare waala panna uu anonymous sadasya ke baare me jon abhi account nai banais hai, nai to account ke kaam me nai lawe hai.\nIi kaaran se ham log ke IP address kaam me lae ke ii sadasya ke jaana jae hai.\n\nIi rakam ke IP address ke dher sadasya kaam me lae sake hai.\nAgar aap ek anonymous user hai aur ii sochta hai ki bekar baat aap ke baare me karaa gais hai, tab\n[[Special:CreateAccount|create an account]] or [[Special:UserLogin|log in]] aage ke garrbarri roke khatir aur duusra anonymous users se mistake nai kare ke khatir .''",
"noarticletext": "Abhi ii panna me kuchh likhaa nai hai.\nAap saktaa hai [[Special:Search/{{PAGENAME}}|ii panna ke title khoje]] duusra panna me,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs],\nnai to [{{fullurl:{{FULLPAGENAME}}|action=edit}} ii panna ke badlo]</span>.",
"noarticletext-nopermission": "Abhi ii panna me koi chij likha nai hae.\nAap sakta hae [[Special:Search/{{PAGENAME}}|ii panna ke title ke khoje]] duusra panna me,\nnai to <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs]</span>, lekin aap ke ii panna ke banae ke ijaaja tnai hae.",
"missing-revision": "Panna \"{{FULLPAGENAME}}\" me #$1 badlao nai hae.\nIske kaaran ii hoe sake hae ki ek mitawa gais panna se link karaa jaawe hae.\nIske baare me aur jaankari [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] me paawa jaae sake hae.",
"noname": "Wala ka nagbutang sang tood-tood nga gamit-pangalan.",
"loginsuccesstitle": "Madinalag-on nga pagsulod",
"loginsuccess": "'''Nakasulod ka na subong sa {{SITENAME}} bilang si \"$1\".'''",
- "nosuchuser": "Wala sang manug-gamit nga iya pangalan \"$1\".\nAng mga gamit-pangalan sensitibo sa kadakoon sang letra.\nSiguradoha ang pagbaybay sang pumolongon, ukon [[Special:UserLogin/signup|magbuhat sang bag-o nga akawnt]].",
+ "nosuchuser": "Wala sang manug-gamit nga iya pangalan \"$1\".\nAng mga gamit-pangalan sensitibo sa kadakoon sang letra.\nSiguradoha ang pagbaybay sang pumolongon, ukon [[Special:CreateAccount|magbuhat sang bag-o nga akawnt]].",
"nosuchusershort": "Wala sang manug-gamit nga iya pangalan \"$1\".\nSiguradoha ang pagbaybay sang pumolongon.",
"nouserspecified": "Kinahanglan mo magbutang sa gamit-pangalan.",
"login-userblocked": "Ang ini nga manug-gamit ginapungga. Indi ka mahimo nga magsulod.",
"accmailtext": "May pasword nga wala ginpilian nga ginhimo para kay [[User talk:$1|$1]] nga ginpadala sa $2.\n\nAng pasword para sa sini nga bag-o nga akawnt mahimo ma-ilisan sa ''[[Special:ChangePassword|ilisan ang pasword]]'' nga panid pagkatapos magsulod.",
"newarticle": "(Bag-o)",
"newarticletext": "Nagbukas ka sang isa ka tabid padulong sa isa ka panid nga wala pa nahimo.\nAgud mahimo ang panid, magsugod ka lang sa pagsulat sa sulod sang kahon nga makit-an mo sa idalum (tan-awa ang [$1 bulig nga pahina] para sa dugang nga ihibalo).\nUgaling kon ikaw nagtalang lamang diri, palihog lang tum-uka ang pityong nga <strong>balik</strong> sa imo nga palalayagan.",
- "anontalkpagetext": "----''Ini ang panid para sa pagtalakay sa wala makilala-an nga manuggamit nga wala pa nakatuga sang akawnt, ukon wala nagagamit sang isa.\nAmo nga kinahanglan naton mag-gamit sang IP adres nga de numero agod nga mahibaluan naton siya.\nAng amo sini nga adres sang IP mahimo nga pagasaluhan sang madamo nga manuggamit.\nKon ikaw manuggamit nga wala makilal-i kag nabatyagan mo nga may mga komento nga wala man sing labot nga ginapakadto sa imo, palihog [[Special:UserLogin/signup|maghimo ka sang akawnt]] ukon [[Special:UserLogin|magsulod]] para malikawan ang iban pa nga pagsala sa iban pa nga wala makilal-an nga manuggamit.''",
+ "anontalkpagetext": "----''Ini ang panid para sa pagtalakay sa wala makilala-an nga manuggamit nga wala pa nakatuga sang akawnt, ukon wala nagagamit sang isa.\nAmo nga kinahanglan naton mag-gamit sang IP adres nga de numero agod nga mahibaluan naton siya.\nAng amo sini nga adres sang IP mahimo nga pagasaluhan sang madamo nga manuggamit.\nKon ikaw manuggamit nga wala makilal-i kag nabatyagan mo nga may mga komento nga wala man sing labot nga ginapakadto sa imo, palihog [[Special:CreateAccount|maghimo ka sang akawnt]] ukon [[Special:UserLogin|magsulod]] para malikawan ang iban pa nga pagsala sa iban pa nga wala makilal-an nga manuggamit.''",
"noarticletext": "Wala unod ining panid.\nSarang ka [[Special:Search/{{PAGENAME}}|magpangita sining panig-ulo]] sa iban nga mga panid,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pangitaa sa nagakaangot nga pagkitan],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} ilisan ining panid]</span>.",
"noarticletext-nopermission": "Wala unod ining panid.\nSarang ka mag-[[Special:Search/{{PAGENAME}}|pangitaa ang ini nga panig-ulo]] sa iban nga mga panid,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pangitaa sa nagakaangot nga pagkitan],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} ilisan ining panid]</span>, ugaling wala ka ginapahanugutan nga maghimo sining panid.",
"missing-revision": "Ang ini nga pag-ilis nga #$1 sang panid nga ginhinanglan nga \"{{FULLPAGENAME}}\" wala naga-eksister.\n\nIni kalabanan ginabuhat sang nagasunod nga wala na mabag-o nga link sang hisayranay sa isa ka panid nga gindula na.\nAng mga detalye mahimo nga makita sa [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log].",
"import-rootpage-nosubpage": "Ang espasyo sang ngalan nga \"$1\" nga gingikanang panid indi ginapasugtan ang kaupod nga mga panid.",
"importlogpage": "Listahan sang mga importe",
"importlogpagetext": "Mga importeng administratibo sang mga panid nga may maragtas sang pagbag-o halin sa iban nga wiki.",
- "javascripttest-pagetext-frameworks": "Palihug pilion ang isa sa mga masunod nga mga testing frameworks: $1",
- "javascripttest-pagetext-skins": "Pilion ang isa ka panit para magdalagan sa imo nga eksamin:",
"tooltip-pt-userpage": "Ang imo kaugalingon nga pahina",
"tooltip-pt-anonuserpage": "Ang panid sang tiggamit para sa IP address imo ginbag-o bilang",
"tooltip-pt-mytalk": "Ang imo pahina sang paghisayranay",
"tog-watchdefault": "Dodaj svaku stranicu koju uredim na moj popis praćenja",
"tog-watchmoves": "Dodaj stranice i datoteke koje premjestim na moj popis praćenja",
"tog-watchdeletion": "Dodaj stranice i datoteke koje izbrišem na popis praćenja",
+ "tog-watchuploads": "Dodaj datoteke koje postavim na moj popis praćenja",
"tog-watchrollback": "Dodaj stranice na kojima sam vratio uređivanja na popis praćenja",
"tog-minordefault": "Normalno označavaj sve moje izmjene kao manje",
"tog-previewontop": "Prikaži kako će stranica izgledati iznad okvira za uređivanje",
"title-invalid-talk-namespace": "Traženi naziv stranice odnosi se na stranicu rasprave koja ne može postojati.",
"title-invalid-characters": "Traženi naziv stranice sadrži nevažeće znakove: \"$1\"",
"perfcached": "Sljedeći podaci su iz međuspremnika i možda nisu najsvježiji. Međuspremnik sadrži $1 {{PLURAL:$1|rezultat|rezultata}} pretraživanja.",
- "perfcachedts": "Sljedeći podaci su iz međuspremnika i posljednji puta su ažurirani u $1. Međuspremnik sadrži $4 {{PLURAL:$4|rezultat|rezultata}} pretraživanja.\n\nViše o ovoj [[Wikipedija:Posebne stranice|posebnoj stranici]] na [[Razgovor Wikipedija:Special:{{PAGENAME}}]].",
+ "perfcachedts": "Sljedeći podaci su iz međuspremnika i posljednji puta su ažurirani u $1. Međuspremnik sadrži $4 {{PLURAL:$4|rezultat|rezultata}} pretraživanja.",
"querypage-no-updates": "Osvježavanje ove stranice je trenutačno onemogućeno. Nove promjene neće biti vidljive.",
"viewsource": "Vidi izvornik",
"viewsource-title": "Vidi kôd stranice $1",
"actionthrottled": "Uređivanje je usporeno",
"actionthrottledtext": "Kao anti-spam mjeru, ograničeni ste u broju ovih radnji u određenom vremenu, i trenutačno ste dosegli to ograničenje. Pokušajte opet za koju minutu.",
"protectedpagetext": "Ova stranica je zaključana da bi se onemogućile izmjene.",
- "viewsourcetext": "Možete pogledati i kopirati izvorni sadržaj ove stranice:",
- "viewyourtext": "Možete vidjeti i kopirati tekst '''vaših uređivanja''' na ovoj stranici:",
+ "viewsourcetext": "Možete pogledati i kopirati izvorni sadržaj ove stranice.",
+ "viewyourtext": "Možete vidjeti i kopirati tekst <strong>vaših uređivanja</strong> na ovoj stranici.",
"protectedinterface": "Ova stranica je zaštićena od izmjena jer sadrži tekst MediaWiki softvera.\nAko želite prevesti neprevedenu poruku ili popraviti prijevod neke druge poruke za sve MediaWiki wikije, posjetite [//translatewiki.net/ translatewiki.net], projekt za lokalizaciju MediaWiki softvera.",
"editinginterface": "<strong>Upozorenje:</strong> Uređujete stranicu koja se rabi za prikaz teksta u sučelju softvera. Promjene učinjene na ovoj stranici odrazit će se na izgled korisničkog sučelja kod drugih suradnika na ovoj wiki.",
"translateinterface": "Za dodavanje ili promjenu prijevoda za sve wikije koristite [//translatewiki.net/ translatewiki.net], projekt za lokalizaciju MediaWikija.",
- "cascadeprotected": "Ova je stranica zaključana za uređivanja jer je uključena u {{PLURAL:$1|slijedeću stranicu|slijedeće stranice}}, koje su zaštićene \"prenosivom zaštitom\":\n$2",
+ "cascadeprotected": "Ova je stranica zaključana za uređivanja jer je uključena u {{PLURAL:$1|sljedeću stranicu|sljedeće stranice}}, koje su zaštićene \"prenosivom zaštitom\":\n$2",
"namespaceprotected": "Ne možete uređivati stranice u imenskom prostoru '''$1'''.",
"customcssprotected": "Ne možete uređivati ovu CSS stranicu zato što ona sadrži osobne postavke drugog suradnika.",
"customjsprotected": "Ne možete uređivati ovu JavaScript stranicu zato što ona sadrži osobne postavke drugog suradnika.",
"noname": "Niste unijeli valjano suradničko ime.",
"loginsuccesstitle": "Prijava uspješna",
"loginsuccess": "Prijavili ste se na wiki kao \"$1\".",
- "nosuchuser": "Ne postoji suradnik s imenom \"$1\".\nSuradnička imena su osjetljiva na veličinu slova.\nProvjerite jeste li točno upisali, ili [[Special:UserLogin/signup|otvorite novi suradnički račun]].",
+ "nosuchuser": "Ne postoji suradnik s imenom \"$1\".\nSuradnička imena su osjetljiva na veličinu slova.\nProvjerite jeste li točno upisali, ili [[Special:CreateAccount|otvorite novi suradnički račun]].",
"nosuchusershort": "Ne postoji suradnik s imenom \"$1\". Provjerite Vaš unos.",
"nouserspecified": "Molimo navedite suradničko ime.",
"login-userblocked": "Ovaj je suradnik blokiran. Prijava nije dopuštena.",
"passwordreset-emailtext-ip": "Netko (vjerojatno Vi, s IP adrese $1) zatražio je podsjetnik za Vaše detalje računa\nza {{SITENAME}} ($4). Sljedeći {{PLURAL:$3|račun suradnika je|računi suradnika su}}\npovezani s ovom e-mail adresom:\n\n$2\n\n{{PLURAL:$3|Ova privremena lozinka|Ove privremene lozinke}} će isteći u {{PLURAL:$5|jedan dan|$5 dana}}.\nTrebate se prijaviti i odabrati novu lozinku. Ukoliko je netko drugi napravio ovaj\nzahtjev, ili ako ste sjeti Vaše izvorne lozinke, a vi je više ne želite promijeniti, \nmožete zanemariti ovu poruku i nastavite koristiti staru lozinku.",
"passwordreset-emailtext-user": "Suradnik $1 na {{SITENAME}} zatražio podsjetnik o pojedinostima vašeg računa za {{SITENAME}}\n($4). Sljedeći {{PLURAL:$3|račun suradnika je|računi suradnika su}} povezani s ovom e-mail adresom:\n\n$2\n\n{{PLURAL:$3|Ova privremena lozinka|Ove privremene lozinke}} će isteći u {{PLURAL:$5|jedan dan|$5 dana}}.\nTrebate se prijaviti i odabrati novu lozinku. Ukoliko je netko drugi napravio ovaj\nzahtjev, ili ako ste sjeti Vaše izvorne lozinke, a vi je više ne želite promijeniti, \nmožete zanemariti ovu poruku i nastavite koristiti staru lozinku.",
"passwordreset-emailelement": "Suradničko ime: \n$1\n\nPrivremena lozinka: \n$2",
- "passwordreset-emailsentemail": "E-mail podsjetnik zaporke je poslan.",
+ "passwordreset-emailsentemail": "Ako je ova adresa povezana s Vašim suradničkim računom, na nju će biti poslan podsjetnik na zaporku.",
"passwordreset-emailsent-capture": "Poslan Vam je podsjetnik kao e-pošta (tekst je prikazan dolje).",
"passwordreset-emailerror-capture": "Napravljena je e-poruka za ponovno postavljanje zaporke (prikazana ispod), ali njeno slanje suradniku nije uspjelo: $1",
"changeemail": "Promijeni ili izbriši e-mail adresu",
"showdiff": "Prikaži promjene",
"blankarticle": "<strong>Upozorenje:</strong> Stvorili ste stranicu koja je prazna.\nAko iznova pritisnete na \"{{int:savearticle}}\", stranica će biti stvorena bez ikakvog sadržaja.",
"anoneditwarning": "<strong>Upozorenje:</strong> niste prijavljeni. Ako napravite uređivanje, Vaša IP adresa će biti javno vidljiva. Ako se <strong>[$1 prijavite]</strong> ili <strong>[$2 stvorite račun]</strong>, Vaša uređivanja će biti pridružena suradničkom imenu, zajedno s ostalim pogodnostima.",
- "anonpreviewwarning": "''Niste prijavljeni. Spremanjem će Vaše IP adrese ostati zabilježene u starim izmjenama ove stranice.''",
+ "anonpreviewwarning": "<em>Niste prijavljeni. Spremanjem izmjena Vaša će IP adresa ostati zabilježena u povijesti uređivanja ove stranice.</em>",
"missingsummary": "'''Podsjetnik:''' Niste unijeli sažetak promjena. Ako ponovno kliknete na \"Sačuvaj stranicu\", Vaše će promjene biti snimljene bez sažetka.",
"selfredirect": "<strong>Upozorenje:</strong> Stvarate preusmjeravanje na isti članak.\nMožda ste izabrali pogrješnu odredišnu stranicu za preusmjeravanje ili uređujete pogrješnu stranicu.\nAko pritisnete na \"{{int:savearticle}}\" još jednom, preusmjeravanje će svejedno biti stvoreno.",
"missingcommenttext": "Molim unesite sažetak.",
"accmailtext": "Nova lozinka za [[User talk:$1|$1]] je poslana na $2.\n\nNakon prijave, lozinka za ovaj novi račun može biti promijenjena na stranici ''[[Special:ChangePassword|promijeni lozinku]]'' nakon prijave.",
"newarticle": "(Novo)",
"newarticletext": "Došli ste na stranicu koja još ne postoji.\nAko želite stvoriti tu stranicu, počnite tipkati u prozor ispod ovog teksta (pogledajte [$1 stranicu za pomoć]).\nAko ste ovamo dospjeli slučajno, kliknite gumb '''natrag''' (back) u svom pregledniku.",
- "anontalkpagetext": "----''Ovo je stranica za razgovor s neprijavljenim suradnikom koji još nije otvorio suradnički račun ili se njime ne koristi. Zbog toga se moramo služiti brojčanom IP adresom kako bismo ga identificirali. Takvu adresu često može dijeliti više ljudi. Ako ste neprijavljeni suradnik i smatrate da su Vam upućeni irelevantni komentari, molimo Vas da [[Special:UserLogin/signup|otvorite suradnički račun]] ili [[Special:UserLogin|se prijavite]] te tako u budućnosti izbjegnete zamjenu s drugim neprijavljenim suradnicima.''",
+ "anontalkpagetext": "----''Ovo je stranica za razgovor s neprijavljenim suradnikom koji još nije otvorio suradnički račun ili se njime ne koristi. Zbog toga se moramo služiti brojčanom IP adresom kako bismo ga identificirali. Takvu adresu često može dijeliti više ljudi. Ako ste neprijavljeni suradnik i smatrate da su Vam upućeni irelevantni komentari, molimo Vas da [[Special:CreateAccount|otvorite suradnički račun]] ili [[Special:UserLogin|se prijavite]] te tako u budućnosti izbjegnete zamjenu s drugim neprijavljenim suradnicima.''",
"noarticletext": "Na ovoj stranici trenutačno nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|potražiti ovaj naslov]] na drugim stranicama,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane evidencije]\nili [{{fullurl:{{FULLPAGENAME}}|action=edit}} stvoriti ovu stranicu]</span>.",
"noarticletext-nopermission": "Ova stranica nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|tražiti naslov ove stranice]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane evidencije]</span>, ali ne možete stvoriti ovu stranicu.",
"missing-revision": "Uređivanje broj $1 na stranici \"{{FULLPAGENAME}}\" ne postoji.\n\nOvo je obično uzrokovano kada kliknete na zastarjelu poveznicu na stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
"upload-form-label-own-work": "Ovo je moje djelo",
"upload-form-label-infoform-categories": "Kategorije",
"upload-form-label-infoform-date": "Datum",
- "upload-form-label-not-own-work-local-default": "Možete pokušati [[Special:Upload|postaviti datoteku na projektu {{SITENAME}}]], pod uvjetom da može biti tamo postavljena, sukladno pravilima projekta.",
- "upload-form-label-own-work-message-shared": "Potvrđujem da posjedujem autorska prava ove datoteke i slažem se da je nepozivo postavljam na Zajednički poslužitelj pod licencijom [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], i pristajem na [https://wikimediafoundation.org/wiki/Terms_of_Use Uvjete uporabe].",
- "upload-form-label-not-own-work-message-shared": "Ako ne posjedujete autorska prava za ovu datoteku, ili je želite objaviti pod drugom licencijom, razmislite o uporabi [https://commons.wikimedia.org/wiki/Special:UploadWizard Čarobnjaka za postavljanje] na Zajedničkom poslužitelju.",
- "upload-form-label-not-own-work-local-shared": "Možete pokušati [[Special:Upload|postaviti datoteku na projektu {{SITENAME}}]], pod uvjetom da je dopušteno postavljanje ove datoteke, sukladno pravilima projekta.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Možete pokušati [[Special:Upload|postaviti datoteku na projektu {{SITENAME}}]], pod uvjetom da može biti tamo postavljena, sukladno pravilima projekta.",
"backend-fail-stream": "Ne mogu prikazati datoteku $1.",
"backend-fail-backup": "Izrada sigurnosne kopije datoteke \"$1\" nije uspjela.",
"backend-fail-notexists": "Datoteka $1 ne postoji.",
"import-logentry-interwiki-detail": "$1 {{PLURAL:$1|promjena|promjene|promjena}} od $2",
"javascripttest": "Testiranje JavaScripta",
"javascripttest-qunit-intro": "Pogledajte [$1 testnu dokumentaciju] na mediawiki.org.",
- "tooltip-pt-userpage": "Stranica suradnika {{GENDER:|Your user}}",
+ "tooltip-pt-userpage": "Moja suradnička stranica",
"tooltip-pt-anonuserpage": "Suradnička stranica za IP adresu pod kojom uređujete",
"tooltip-pt-mytalk": "Vaša stranica za razgovor",
"tooltip-pt-anontalk": "Razgovor o suradnicima s ove IP adrese",
"mw-widgets-dateinput-placeholder-day": "GGGG-MM-DD",
"mw-widgets-dateinput-placeholder-month": "GGGG-MM",
"mw-widgets-titleinput-description-new-page": "stranica još ne postoji",
- "mw-widgets-titleinput-description-redirect": "preusmjeravanje na $1"
+ "mw-widgets-titleinput-description-redirect": "preusmjeravanje na $1",
+ "log-action-filter-upload": "Vrsta postavljanja:",
+ "log-action-filter-all": "sve",
+ "log-action-filter-upload-upload": "novo postavljanje",
+ "log-action-filter-upload-overwrite": "ponovno postavljanje"
}
"Paul Beppler",
"Midnight Gambler",
"Macofe",
- "Matma Rex"
+ "Matma Rex",
+ "Ghiutun"
]
},
"tog-underline": "Links (Verbinnunge) unnerstreiche:",
"noname": "Du musst en gültiche Benutzernoome oongewe.",
"loginsuccesstitle": "Oonmeldung erfollichgreich",
"loginsuccess": "Du bist jetzt als \"$1\" bei {{SITENAME}} oongemeldt.",
- "nosuchuser": "Der Benutzernoome „$1“ existiert net.\nÜwerprüf die Schreibweis (Gross-/Klenschreibung beachte) orrer [[Special:UserLogin/signup|meld dich als neier Benutzer an]].",
+ "nosuchuser": "Der Benutzernoome „$1“ existiert net.\nÜwerprüf die Schreibweis (Gross-/Klenschreibung beachte) orrer [[Special:CreateAccount|meld dich als neier Benutzer an]].",
"nosuchusershort": "Der Benutzernoome \"$1\" ist net voarhand. Bitte üwerprüf die Schreibweis.",
"nouserspecified": "Bittschön geb en Benutzernoome an.",
"login-userblocked": "{{GENDER:$1|Der Benutzer|Die Benutzrin|Der Benutzer}} ist gesperrt. Die Oonmeldung ist net erlaubt.",
"accmailtext": "En zufällich generiertes Passwort für [[User talk:$1|$1]] woard an $2 versandt. Es kann uff der Seit ''[[Special:ChangePassword|Passwort ännre]]'' noh der Oonmeldung geännert sin.",
"newarticle": "(Nei)",
"newarticletext": "Du bist en Link zu en Seit noh gang, wo net voarhand ist.\nUm die Seit oonzulehn, trooh dein Text in das unnestehend Beoorbeitungsfeld ren (weitre Informatione uff der [$1 Hellefseit]).\nSoweit du fälschlicherweise hier bist, klick uff dein Browser sein Schaltfläch '''Retuar'''.",
- "anontalkpagetext": "----''Dies Seit dient dozu, enem net oongemeldete Benutzer Nachrichte zu hinnerlosse. Es weard sein IP-Adress zur Identifizierung verwenndt. IP-Adresse könne von mehrere Benutzer gemeinsam verwendt sin. Wenn du mit den Kommentare uff der Seit nix oonfänge kannst, richte die sich vermutlich an en frühre Inhaber von deiner IP-Adresse und du kannst se ignoriere. Du kannst dir ooch en [[Special:UserLogin/signup|Benutzerkonto erstelle]] orrer dich [[Special:UserLogin|oonmelde]], um künftich Verwechslunge mit annre anonyme Benutzer zu vermeide.''",
+ "anontalkpagetext": "----''Dies Seit dient dozu, enem net oongemeldete Benutzer Nachrichte zu hinnerlosse. Es weard sein IP-Adress zur Identifizierung verwenndt. IP-Adresse könne von mehrere Benutzer gemeinsam verwendt sin. Wenn du mit den Kommentare uff der Seit nix oonfänge kannst, richte die sich vermutlich an en frühre Inhaber von deiner IP-Adresse und du kannst se ignoriere. Du kannst dir ooch en [[Special:CreateAccount|Benutzerkonto erstelle]] orrer dich [[Special:UserLogin|oonmelde]], um künftich Verwechslunge mit annre anonyme Benutzer zu vermeide.''",
"noarticletext": "Die Seit dohie enthält momentan noch ken Text.\nDu kannst sie <span class=\"plainlinks\">[{{fullurl:{{FULLPAGENAME}}|action=edit}} beoorbeite]</span>,\nehre Titel uff annre Seite [[Special:Search/{{PAGENAME}}|suche]]\norrer die zugehöriche <span class=\"plainlinks\">[{{fullurl:{{#special:Log}}|page={{FULLPAGENAMEE}}}} Logbücher betrachte]</span>.",
"noarticletext-nopermission": "Die Seit dohie enthält momentan noch ken Text.\nDu kannst sie <span class=\"plainlinks\">[{{fullurl:{{FULLPAGENAME}}|action=edit}} beoorbeite]</span>,\nehre Titel uff annre Seite [[Special:Search/{{PAGENAME}}|suche]]\norrer die zugehöriche <span class=\"plainlinks\">[{{fullurl:{{#special:Log}}|page={{FULLPAGENAMEE}}}} Logbücher betrachte]</span>.",
"missing-revision": "Die Version $1 von der Seit mit der noomen \"{{FULLPAGENAME}}\" ist net voarhand.\n\nDer Fehler weard normalerweis von enem veraltete Link zur Versionsgeschicht von en Seit verursacht, wo zwischichzeitlich gelöscht woard.\nEnzelheite sind im [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Lösch-Logbuch] einsehbar (visibel).",
"spam_reverting": "Letzte Version ohne Links zu $1 wiederheargestellt.",
"spam_blanking": "Alle Versione mit enem Link zu $1 woorre bereinicht.",
"spam_deleting": "Alle Versione mit enem Link zu $1 woorre abgewischt.",
- "simpleantispam-label": "Spamschutzprüfung.\nHier '''NIX''' introohn!",
+ "simpleantispam-label": "Spamschutzprüfung.\nHier <strong>NIX</strong> introohn!",
"pageinfo-title": "Informatione zu \"$1\"",
"pageinfo-not-current": "Die Information kann leider net für alte Versione zur Verfüchung gestellt sin.",
"pageinfo-header-basic": "Basisinformatione",
"noname": "Njejsy płaćiwe wužiwarske mjeno podał.",
"loginsuccesstitle": "Přizjewjenje wuspěšne",
"loginsuccess": "'''Sy nětko jako \"$1\" w {{GRAMMAR:lokatiw|{{SITENAME}}}} {{GENDER:|přizjewjeny|přizjewjena|přizjewjene}}.'''",
- "nosuchuser": "Njeje wužiwar z mjenom \"$1\".\nWužiwarske mjena wobkedźbuja wulkopisanje.\nPřepruwuj swój prawopis abo [[Special:UserLogin/signup|wutwor nowe konto]].",
+ "nosuchuser": "Njeje wužiwar z mjenom \"$1\".\nWužiwarske mjena wobkedźbuja wulkopisanje.\nPřepruwuj swój prawopis abo [[Special:CreateAccount|wutwor nowe konto]].",
"nosuchusershort": "Wužiwarske mjeno „$1” njeeksistuje. Prošu skontroluj prawopis.",
"nouserspecified": "Dyrbiš wužiwarske mjeno podać",
"login-userblocked": "Tutón wužiwar je zablokowany. Přizjewjenje njedowolene.",
"accmailtext": "Připadnje spłodźene hesło za [[User talk:$1|$1]] bu na $2 pósłane. Daj so na stronje ''[[Special:ChangePassword|hesło změnić]]'' při přizjewjenju změnić.",
"newarticle": "(Nowy)",
"newarticletext": "Sy wotkaz k stronje slědował, kotraž hišće njeeksistuje. Zo by stronu wutworił, wupjelń slědowace tekstowe polo (hlej [$1 stronu pomocy] za dalše informacije). Jeli sy zmylnje tu, klikń prosće na tłóčatko <b>Wróćo</b> we swojim wobhladowaku.",
- "anontalkpagetext": "---- ''To je diskusijna strona za anonymneho wužiwarja, kiž hišće konto wutworił njeje abo je njewužiwa. Dyrbimy tohodla numerisku IP-adresu wužiwać, zo bychmy jeho/ju identifikowali. Tajka IP-adresa hodźi so wot wjacorych wužiwarjow zhromadnje wužiwać. Jeli sy anonymny wužiwar a měniš, zo buchu irelewantne komentary k tebi pósłane, [[Special:UserLogin/signup|wutwor prošu konto]] abo [[Special:UserLogin|přizjew so]], zo by přichodnu šmjatańcu z anonymnymi wužiwarjemi wobešoł.''",
+ "anontalkpagetext": "---- ''To je diskusijna strona za anonymneho wužiwarja, kiž hišće konto wutworił njeje abo je njewužiwa. Dyrbimy tohodla numerisku IP-adresu wužiwać, zo bychmy jeho/ju identifikowali. Tajka IP-adresa hodźi so wot wjacorych wužiwarjow zhromadnje wužiwać. Jeli sy anonymny wužiwar a měniš, zo buchu irelewantne komentary k tebi pósłane, [[Special:CreateAccount|wutwor prošu konto]] abo [[Special:UserLogin|přizjew so]], zo by přichodnu šmjatańcu z anonymnymi wužiwarjemi wobešoł.''",
"noarticletext": "Tuchwilu tuta strona žadyn tekst njewobsahuje. Móžeš [[Special:Search/{{PAGENAME}}|tutón titul strony na druhich stronach pytać]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} wotpowědne protokole pytać] abo [{{fullurl:{{FULLPAGENAME}}|action=edit}} tutu stronu wobdźěłać]</span>.",
"noarticletext-nopermission": "Tuchwilu žadyn tekst na tutej stronje njeje.\nMóžeš [[Special:Search/{{PAGENAME}}|tutón titul strony]] na druhich stronach pytać abo <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pytaj wotpowědne protokole]</span>, ale nimaš prawo, strou wutworić.",
"missing-revision": "Wersija #$1 strony z mjenom \"{{FULLPAGENAME}}\" njeeksistuje.\n\nPřičina je zwjetša zestarjeny wotkaz w stawiznach k stronje, kotraž je so zhašała.\nPodrobnosće móžeš w [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} protokolu wušmórnjenjow] namakać.",
"otherlanguages": "Nan lòt lang yo",
"redirectedfrom": "(Redirije depi $1)",
"redirectpagesub": "Paj pou redireksyon",
- "redirectto": "Voye sou:",
+ "redirectto": "Redireksyon sou :",
"lastmodifiedat": "Paj sa te modifye pou dènye fwa $1 a $2.<br />",
"viewcount": "Paj sa te konsilte {{PLURAL:$1|yon fwa|$1 fwa}}.",
"protectedpage": "Paj pwoteje",
"noname": "Ou pa bay sistèm an yon non itilizatè ki bon.",
"loginsuccesstitle": "Ou byen konekte nan sistèm la",
"loginsuccess": "Ou konekte kounye a nan {{SITENAME}} ak idantifyan sa a « $1 ».",
- "nosuchuser": "Itilizatè \"$1\" pa ekziste.\nMajiskil ak miniskil chanje non itilizatè.\nByen gade ke ou te byen ekri non ou, oubyen [[Special:UserLogin/signup|kreye yon nouvo kont]].",
+ "nosuchuser": "Itilizatè \"$1\" pa ekziste.\nMajiskil ak miniskil chanje non itilizatè.\nByen gade ke ou te byen ekri non ou, oubyen [[Special:CreateAccount|kreye yon nouvo kont]].",
"nosuchusershort": "Pa genyen itilizatè ak non « $1 » sa a. Byen gade lòtograf ou an.",
"nouserspecified": "Ou dwe mete non itilizatè ou an.",
"login-userblocked": "Itilizatè sa bloke. Li pa gendwa konekte.",
"accmailtext": "Nou fè yon mopas o aza pou [[User talk:$1|$1]] epi nou voye l nan adrès $2.\nOu ka chanje mopas pou kont sa a nan paj ''[[Special:ChangePassword|chanje mopas]]'' aprè ou konekte ou.",
"newarticle": "(Nouvo)",
"newarticletext": "Ou swiv on lyen pou yon paj ki poko egziste.\nPou ou kapab kreye paj sa a, komanse ekri nan bwat ki anba (gade [$1 paj èd nan] pou konnen plis, pou plis enfòmasyon).\nSi se paske ou fè yon erè ke ou rive nan paj sa a, klike anlè bouton '''fè back''' nan navigatè ou a.",
- "anontalkpagetext": "---- ''Ou nan paj diskisyon yon itilizatè anonim, ki pa gen non, ki poko kreye yon kont oubyen ki pa itilize pyès kont nan sistèm sa. Pou rezon sa, nou dwe itilize adrès IP l pou nou kapab lokalize l, sitye l, montre kote l rete, idantifye l. Yon adrès IP kapab pataje ant plizyè moun, plizyè itilizatè. Si ou se yon itilizatè anonim e si ou wè ke ou resevwa komantè ki pa t pou ou, ou mèt [[Special:UserLogin/signup|kreye yon kont]] oubyen [[Special:UserLogin|konekte ou]] pou ou kapab anpeche konfizyon ak kontribitè anonim yo.''",
+ "anontalkpagetext": "---- ''Ou nan paj diskisyon yon itilizatè anonim, ki pa gen non, ki poko kreye yon kont oubyen ki pa itilize pyès kont nan sistèm sa. Pou rezon sa, nou dwe itilize adrès IP l pou nou kapab lokalize l, sitye l, montre kote l rete, idantifye l. Yon adrès IP kapab pataje ant plizyè moun, plizyè itilizatè. Si ou se yon itilizatè anonim e si ou wè ke ou resevwa komantè ki pa t pou ou, ou mèt [[Special:CreateAccount|kreye yon kont]] oubyen [[Special:UserLogin|konekte ou]] pou ou kapab anpeche konfizyon ak kontribitè anonim yo.''",
"noarticletext": "Poko genyen tèks nan paj sa a.\nOu mèt [[Special:Search/{{PAGENAME}}|fè yon rechèch, fouye ak non paj sa a]] nan lòt paj yo, oubyen <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} chache jounal modifikasyon yo ki an relasyon ak paj sa] oubyen tou [{{fullurl:{{FULLPAGENAME}}|action=edit}} modifye paj sa]</span>.",
"noarticletext-nopermission": "Poko genyen tèks nan paj sa a.\nOu mèt [[Special:Search/{{PAGENAME}}|fè yon rechèch, fouye ak non paj sa a]] nan lòt paj yo, oubyen <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} chache jounal modifikasyon yo ki an relasyon ak paj sa].",
"userpage-userdoesnotexist": "Kont itilizatè « <nowiki>$1</nowiki> » sa pa anrejistre. Verifye toutbon ke ou vle kreye paj sa.",
"whatlinkshere-page": "Paj :",
"linkshere": "Paj yo ki anba ap mene nan <b>[[:$1]]</b> :",
"nolinkshere": "Pyès paj genyen lyen pou paj sa a <b>[[:$1]]</b>.",
- "isredirect": "Paj redireksyon",
+ "isredirect": "paj redireksyon",
"istemplate": "anndan",
"isimage": "lyen fichye a",
"whatlinkshere-prev": "{{PLURAL:$1|presedan|$1 presedan yo}}",
"noname": "Érvénytelen szerkesztőnevet adtál meg.",
"loginsuccesstitle": "Sikeres bejelentkezés",
"loginsuccess": "'''Sikeresen bejelentkeztél a(z) {{SITENAME}} wikibe „$1” néven.'''",
- "nosuchuser": "Nem létezik „$1” nevű szerkesztő.\nA szerkesztőnevek kis- és nagybetű-érzékenyek.\nEllenőrizd, hogy helyesen írtad-e be, vagy [[Special:UserLogin/signup|hozz létre egy új fiókot]].",
+ "nosuchuser": "Nem létezik „$1” nevű szerkesztő.\nA szerkesztőnevek kis- és nagybetű-érzékenyek.\nEllenőrizd, hogy helyesen írtad-e be, vagy [[Special:CreateAccount|hozz létre egy új fiókot]].",
"nosuchusershort": "Nem létezik „$1” nevű szerkesztő.\nEllenőrizd, hogy helyesen írtad-e be.",
"nouserspecified": "Meg kell adnod a felhasználói nevet.",
"login-userblocked": "Ez a szerkesztő blokkolva van, a bejelentkezés nem engedélyezett.",
"accmailtext": "A(z) [[User talk:$1|$1]] fiókhoz egy véletlenszerűen generált jelszót küldünk a(z) $2 címre.\n\nAz új fiók jelszava a ''[[Special:ChangePassword|jelszó megváltoztatása]]'' lapon módosítható a bejelentkezés után.",
"newarticle": "(Új)",
"newarticletext": "Egy olyan lapra mutató hivatkozást követtél, ami még nem létezik.\nA lap létrehozásához csak gépeld be a szövegét a lenti szövegdobozba. Ha kész vagy, az „Előnézet megtekintése” gombbal ellenőrizheted, hogy úgy fog-e kinézni, ahogy szeretnéd, és a „Lap mentése” gombbal tudod elmenteni. (További információkat a [$1 súgólapon] találsz).\nHa tévedésből jutottál ide, kattints a böngésződ '''vissza''' vagy '''back''' gombjára.",
- "anontalkpagetext": "----''Ez egy olyan anonim szerkesztő vitalapja, aki még nem regisztrált, vagy csak nem jelentkezett be.\nEzért az IP-címét használjuk az azonosítására.\nUgyanazon az IP-címen számos szerkesztő osztozhat az idők folyamán.\nHa úgy látod, hogy az üzenetek, amiket ide kapsz, nem neked szólnak, [[Special:UserLogin/signup|regisztrálj]] vagy ha már regisztráltál, [[Special:UserLogin|jelentkezz be]], hogy ne keverjenek össze másokkal.''",
+ "anontalkpagetext": "----''Ez egy olyan anonim szerkesztő vitalapja, aki még nem regisztrált, vagy csak nem jelentkezett be.\nEzért az IP-címét használjuk az azonosítására.\nUgyanazon az IP-címen számos szerkesztő osztozhat az idők folyamán.\nHa úgy látod, hogy az üzenetek, amiket ide kapsz, nem neked szólnak, [[Special:CreateAccount|regisztrálj]] vagy ha már regisztráltál, [[Special:UserLogin|jelentkezz be]], hogy ne keverjenek össze másokkal.''",
"noarticletext": "Ez a lap jelenleg nem tartalmaz szöveget.\n[[Special:Search/{{PAGENAME}}|Rákereshetsz erre a címszóra]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} megtekintheted a kapcsolódó naplókat],\nvagy [{{fullurl:{{FULLPAGENAME}}|action=edit}} létrehozhatod a lapot].</span>",
"noarticletext-nopermission": "Ez a lap jelenleg nem tartalmaz szöveget.\n[[Special:Search/{{PAGENAME}}|Rákereshetsz a lap címére]] más lapok tartalmában, vagy <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} megtekintheted a kapcsolódó naplófájlokat]</span>.",
"missing-revision": "A(z) \"{{FULLPAGENAME}}\" nevű oldal #$1 változata nem létezik.\n\nEzt általában egy elavult, törölt oldalra mutató laptörténeti hivatkozás használata okozza. Részletek a [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} törlési naplóban] találhatóak.",
"recentchangeslinked-page": "Lap neve:",
"recentchangeslinked-to": "Inkább az erre linkelő lapok változtatásait mutasd",
"recentchanges-page-added-to-category": "[[:$1]] hozzáadva a kategóriához",
- "recentchanges-page-added-to-category-bundled": "[[:$1]] és [[Special:WhatLinksHere/$1|{{PLURAL:$2|egy oldal|$2 oldal}}]] hozzáadva a kategóriához",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] hozzáadva a kategóriához, [[Special:WhatLinksHere/$1|ez a lap be van illesztve más lapokra]]",
"recentchanges-page-removed-from-category": "[[:$1]] eltávolítva a kategóriából",
"recentchanges-page-removed-from-category-bundled": "[[:$1]] és {{PLURAL:$2|egy oldal|$2 oldal}} eltávolítva a kategóriából",
"upload": "Fájl feltöltése",
"upload-form-label-own-work": "Ez a saját munkám",
"upload-form-label-infoform-categories": "Kategóriák",
"upload-form-label-infoform-date": "Dátum",
- "upload-form-label-own-work-message-local": "Kijelentem, hogy a fájlt a(z) {{SITENAME}} következő felhasználási feltételei és licencirányelvei alapján töltöm fel.",
- "upload-form-label-not-own-work-message-local": "Ha nem tudod feltölteni a fájlt a(z) {{SITENAME}} irányelvei értelmében, zárd be ezt a panelt és próbálkozz egy másik módszerrel.",
- "upload-form-label-not-own-work-local-local": "Az [[Special:Upload|alapértelmezett feltöltőoldalt]] is kipróbálhatod.",
- "upload-form-label-own-work-message-default": "Megértettem, hogy a megosztott tárhelyre töltöm fel a fájlt. Kijelentem, hogy az ottani felhasználási feltételek és licencirányelvek szerint teszem ezt.",
- "upload-form-label-not-own-work-message-default": "Ha nem tudod feltölteni a fájlt a megosztott tárhely irányelvei értelmében, zárd be ezt a panelt és próbálkozz egy másik módszerrel.",
- "upload-form-label-not-own-work-local-default": "Megpróbálhatod használni [[Special:Upload|a(z) {{SITENAME}} feltöltési lapját]] is, ha ezt a fájlt fel lehet tölteni az itteni irányelvek szerint.",
- "upload-form-label-own-work-message-shared": "Igazolom, hogy én birtoklom a fájl szerzői jogait, és egyetértek azzal, hogy visszavonhatatlanul közzéteszem a fájlt a Wikimédia Commonson a [https://creativecommons.org/licenses/by-sa/4.0/deed.hu Creative Commons Nevezd meg! – Így add tovább! 4.0] licenc alatt, és egyetértek a [https://wikimediafoundation.org/wiki/Terms_of_Use felhasználási feltételekkel].",
- "upload-form-label-not-own-work-message-shared": "Ha nem birtoklod a fájl szerzői jogait vagy más licenc alatt szeretnéd közzétenni, fontold meg a [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons Feltöltésvarázslójának] használatát.",
- "upload-form-label-not-own-work-local-shared": "Megpróbálhatod használni [[Special:Upload|a(z) {{SITENAME}} feltöltési lapját]] is, ha ezt a fájlt fel lehet tölteni az itteni irányelvek szerint.",
+ "upload-form-label-own-work-message-generic-local": "Kijelentem, hogy a fájlt a(z) {{SITENAME}} következő felhasználási feltételei és licencirányelvei alapján töltöm fel.",
+ "upload-form-label-not-own-work-message-generic-local": "Ha nem tudod feltölteni a fájlt a(z) {{SITENAME}} irányelvei értelmében, zárd be ezt a panelt és próbálkozz egy másik módszerrel.",
+ "upload-form-label-not-own-work-local-generic-local": "Az [[Special:Upload|alapértelmezett feltöltőoldalt]] is kipróbálhatod.",
+ "upload-form-label-own-work-message-generic-foreign": "Megértettem, hogy a megosztott tárhelyre töltöm fel a fájlt. Kijelentem, hogy az ottani felhasználási feltételek és licencirányelvek szerint teszem ezt.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Ha nem tudod feltölteni a fájlt a megosztott tárhely irányelvei értelmében, zárd be ezt a panelt és próbálkozz egy másik módszerrel.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Megpróbálhatod használni [[Special:Upload|a(z) {{SITENAME}} feltöltési lapját]] is, ha ezt a fájlt fel lehet tölteni az itteni irányelvek szerint.",
"backend-fail-stream": "Nem sikerült sugározni ezt a fájlt: $1.",
"backend-fail-backup": "Nem lehet elmenteni ezt a fájlt: $1.",
"backend-fail-notexists": "Ez a fájl nem létezik: $1 .",
"confirmemail_success": "Az e-mail címed megerősítve. Most már beléphetsz a wikibe.",
"confirmemail_loggedin": "E-mail címed megerősítve.",
"confirmemail_subject": "{{SITENAME}} e-mail cím megerősítés",
- "confirmemail_body": "Valaki, valószínűleg te, ezzel az e-mail címmel regisztrált\n„$2” néven a(z) {{SITENAME}} wikin, a(z) $1 IP-címről.\n\nAnnak érdekében, hogy megerősítsd, ez az azonosító valóban hozzád tartozik,\nés hogy aktiváld az e-mail címedet, nyisd meg az alábbi linket a böngésződben:\n\n$3\n\nHa ez *nem* te vagy, kattints erre a linkre az\ne-mail cím megerősíthetőségének visszavonásához:\n\n$5\n\nA megerősítésre szánt kód felhasználhatósági idejének lejárata: $4.",
+ "confirmemail_body": "Valaki, valószínűleg te, ezzel az e-mail-címmel regisztrált\n„$2” néven a(z) {{SITENAME}} wikin, a(z) $1 IP-címről.\n\nAnnak érdekében, hogy megerősítsd, ez az azonosító valóban hozzád tartozik,\nés aktiváld az e-mail-címedet, nyisd meg az alábbi linket a böngésződben:\n\n$3\n\nHa ez *nem* te vagy, kattints erre a linkre az\ne-mail-cím megerősíthetőségének visszavonásához:\n\n$5\n\nA megerősítésre szánt kód felhasználhatósági idejének lejárata: $4.",
"confirmemail_body_changed": "Valaki (vélhetően te, a(z) $1 IP-címről) megváltoztatta a(z) „$2” felhasználói fiók email címét a {{SITENAME}} wikin erre a címre.\n\nAnnak érdekében, hogy megerősítsd, ez az azonosító valóban hozzád tartozik,\nés hogy újra aktiváld az e-mail címedet, nyisd meg az alábbi linket a böngésződben:\n\n$3\n\nHa ez *nem* te vagy, kattints erre a linkre az\ne-mail cím megerősíthetőségének visszavonásához:\n\n$5\n\nA megerősítésre szánt kód felhasználhatósági idejének lejárata: $4.",
"confirmemail_body_set": "Valaki, valószínűleg te, ezt az email címet adta meg\n„$2” nevű {{SITENAME}}-fiókjához a következő IP-címről: $1.\n\nHa meg szeretnéd erősíteni, hogy a fiók valóban hozzád tartozik, így aktiválva a(z) {{SITENAME}} e-mailes funkcióit, nyisd meg az alábbi linket a böngésződben:\n\n$3\n\nHa a fiók *nem* hozzád tartozik, kövesd az alábbi linket a\nmegerősítés visszavonásához:\n\n$5\n\nEz a megerősítő e-mail $4-ig érvényes.",
"confirmemail_invalidated": "E-mail-cím megerősíthetősége visszavonva",
"timezone-local": "Helyi",
"duplicate-defaultsort": "Figyelem: a(z) „$2” rendezőkulcs felülírja a korábbit („$1”).",
"duplicate-displaytitle": "<strong>Figyelmeztetés:</strong> A lapcímváltoztató (<tt>DISPLAYTITLE</tt>) „$2” felülírja a korábbi „$1”-t.",
+ "restricted-displaytitle": "<strong>Figyelmeztetés:</strong> A megjelenítendő cím „$1” figyelmen kívül lett hagyva, mert nem egyezik a lap tényleges címével.",
"invalid-indicator-name": "<strong>Hiba:</strong> A lapstátuszjelző <code>name</code> attribútuma nem lehet üres.",
"version": "Névjegy",
"version-extensions": "Telepített kiterjesztések",
"noname": "Դուք չեք նշել թույլատրելի մասնակցային անուն։",
"loginsuccesstitle": "Բարեհաջող մուտք",
"loginsuccess": "'''Դուք մուտք գործեցիք {{SITENAME}}, որպես \"$1\"։'''",
- "nosuchuser": "$1 անունով մասնակից գոյություն չունի։\nՄասնակիցների անունները զգայուն են մեծատառերի նկատմամբ։\nՍտուգեք ձեր ուղղագրությունը կամ [[Special:UserLogin/signup|ստեղծեք նոր մասնակցի հաշիվ]]։",
+ "nosuchuser": "$1 անունով մասնակից գոյություն չունի։\nՄասնակիցների անունները զգայուն են մեծատառերի նկատմամբ։\nՍտուգեք ձեր ուղղագրությունը կամ [[Special:CreateAccount|ստեղծեք նոր մասնակցի հաշիվ]]։",
"nosuchusershort": "$1 անունով մասնակից գոյություն չունի։ Ստուգեք ձեր ուղղագրությունը։",
"nouserspecified": "Հարկավոր է նշել մասնակցային անուն։",
"login-userblocked": "Այս մասնակիցը արգելափակված է: Մուտքը արգելված է:",
"accmailtext": "[[User talk:$1|$1]] մասնակցի համար պատահական նշերից կազմված գաղտնաբառը ուղարկված է $2 հասցեին։\n\nՀամակարգ մուտք գործելուն պես կարող եք ''[[Special:ChangePassword|փոխել գաղտնաբառը]]''։",
"newarticle": "(Նոր)",
"newarticletext": "Դուք հղվել եք դեռևս գոյություն չունեցող էջի։ \nՆոր էջ ստեղծելու համար ստորև գտնվող խմբագրման դաշտում ավելացրեք տեքստ, այնուհետև սեղմեք '''Հիշել էջը''' (այցելեք [$1 օգնության էջը]՝ մանրամասն տեղեկությունների համար)։ \n\nԵթե դուք սխալմամբ եք այստեղ հայտնվել, ապա սեղմեք ձեր դիտարկչի '''հետ''' (back) կոճակը։",
- "anontalkpagetext": "----\n''Այս քննարկման էջը պատկանում է անանուն մասնակցին, որը դեռ չի ստեղծել մասնակցային հաշիվ կամ չի մտել համակարգ մասնակցի անունով։''\nԱյդ իսկ պատճառով օգտագործվում է թվային IP-հասցեն։\nՆման IP-հասցեից կարող են օգտվել մի քանի մասնակիցներ։\nԵթե դուք անանուն մասնակից եք, բայց կարծում եք, որ ուրիշներին վերաբերող դիտողությունները արվում են ձեր հասցեով, ապա խնդրում ենք պարզապես [[Special:UserLogin/signup|գրանցվել]] կամ [[Special:UserLogin|մտնել համակարգ]], որպեսզի հետագայում ձեզ չշփոթեն այլ անանուն մասնակիցների հետ։",
+ "anontalkpagetext": "----\n''Այս քննարկման էջը պատկանում է անանուն մասնակցին, որը դեռ չի ստեղծել մասնակցային հաշիվ կամ չի մտել համակարգ մասնակցի անունով։''\nԱյդ իսկ պատճառով օգտագործվում է թվային IP-հասցեն։\nՆման IP-հասցեից կարող են օգտվել մի քանի մասնակիցներ։\nԵթե դուք անանուն մասնակից եք, բայց կարծում եք, որ ուրիշներին վերաբերող դիտողությունները արվում են ձեր հասցեով, ապա խնդրում ենք պարզապես [[Special:CreateAccount|գրանցվել]] կամ [[Special:UserLogin|մտնել համակարգ]], որպեսզի հետագայում ձեզ չշփոթեն այլ անանուն մասնակիցների հետ։",
"noarticletext": "Ներկայումս այս էջում որևէ տեքստ չկա։\nԴուք կարող եք [[Special:Search/{{PAGENAME}}|որոնել այս անվանումը]] այլ էջերում, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} որոնել համապատասխան տեղեկամատյանները] կամ [{{fullurl:{{FULLPAGENAME}}|action=edit}} ստեղծել նոր էջ այս անվանմամբ]</span>։",
"noarticletext-nopermission": "Ներկայումս այս էջում որևէ տեքստ չկա։\nԴուք կարող եք [[Special:Search/{{PAGENAME}}|որոնել այս անվանունը]] այլ էջերում կամ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} որոնել այն տեղեկամատյաններում]</span>։ Դուք չունեք թույլտվություն ստեղծել այս էջը։",
"userpage-userdoesnotexist": "«<nowiki>$1</nowiki>» անվանմամբ մասնակից գոյություն չունի։\nԽնդրում ենք հավաստիանալ նրանում, թե արդյոք ուզում եք ստեղծել/խմբագրել այս էջը։",
"sp-contributions-search": "Որոնել ներդրումները",
"sp-contributions-username": "IP-հասցե կամ մասնակցի անուն.",
"sp-contributions-toponly": "Ցույց տալ միայն այն խմբագրումները, որոնք վերջին փոփոխություն են",
- "sp-contributions-newonly": "Õ\91Õ¸Ö\82ÕµÖ\81 Õ¿Õ¡Õ¬ Õ´Õ«Õ¡ÕµÕ¶ Õ¡ÕµÕ¶ ÕÕ´Õ¢Õ¡Õ£Ö\80Õ¸Ö\82Õ´Õ¶Õ¥Ö\80Õ¨, Õ¸Ö\80Õ¸Õ¶Ö\84 Õ§Õ» Õ¥Õ¶ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬",
+ "sp-contributions-newonly": "Õ\91Õ¸Ö\82ÕµÖ\81 Õ¿Õ¡Õ¬ Õ´Õ«Õ¡ÕµÕ¶ Õ¶Õ¸Ö\80 Õ§Õ»Õ¥Ö\80Õ« ÕÕ´Õ¢Õ¡Õ£Ö\80Õ¸Ö\82Õ´Õ¶Õ¥Ö\80Õ¨",
"sp-contributions-submit": "Որոնել",
"whatlinkshere": "Այստեղ հղվող էջերը",
"whatlinkshere-title": "Էջեր, որոնք հղում են դեպի «$1»",
"아라",
"Carlosedepaula",
"Macofe",
- "Karmwiki"
+ "Karmwiki",
+ "Matma Rex"
]
},
"tog-underline": "Sublinear ligamines:",
"tog-watchdefault": "Adder le paginas e files que io modifica a mi observatorio",
"tog-watchmoves": "Adder le paginas e files que io renomina a mi observatorio",
"tog-watchdeletion": "Adder le paginas e files que io dele a mi observatorio",
+ "tog-watchuploads": "Adder le nove files que io incarga a mi observatorio",
"tog-watchrollback": "Adder a mi observatorio le paginas in que io ha effectuate un revocation",
"tog-minordefault": "Marcar omne modificationes initialmente como minor",
"tog-previewontop": "Monstrar previsualisation ante le quadro de modification",
"tog-ccmeonemails": "Inviar me copias del messages de e-mail que io invia a altere usatores",
"tog-diffonly": "Non monstrar le contento del pagina sub le comparation de duo versiones",
"tog-showhiddencats": "Monstrar categorias celate",
- "tog-norollbackdiff": "Omitter le diff post le execution de un revocation",
+ "tog-norollbackdiff": "Non monstrar differentias post exequer un revocation",
"tog-useeditwarning": "Advertir me quando io quita un pagina de modification sin publicar le cambiamentos",
"tog-prefershttps": "Sempre usar un connexion secur in session aperte",
"underline-always": "Sempre",
"password-change-forbidden": "Non es possibile cambiar le contrasigno in iste wiki.",
"externaldberror": "O il occurreva un error in le base de datos de authentication, o tu non ha le autorisation de actualisar tu conto externe.",
"login": "Aperir session",
+ "login-security": "Verifica tu identitate",
"nav-login-createaccount": "Aperir session / crear conto",
"userlogin": "Aperir session / crear conto",
"userloginnocreate": "Aperir session",
"userlogin-resetpassword-link": "Contrasigno oblidate?",
"userlogin-helplink2": "Adjuta al accesso",
"userlogin-loggedin": "Tu ha jam aperite session como {{GENDER:$1|$1}}.\nUsa le formulario sequente pro aperir session como altere usator.",
+ "userlogin-reauth": "Tu debe reaperir session pro verificar que tu es {{GENDER:$1|$1}}.",
"userlogin-createanother": "Crear un altere conto",
"createacct-emailrequired": "Adresse de e-mail",
"createacct-emailoptional": "Adresse de e-mail (optional)",
"createacct-email-ph": "Entra tu adresse de e-mail",
"createacct-another-email-ph": "Entra adresse de e-mail",
"createaccountmail": "Usar un contrasigno aleatori temporari e inviar lo al adresse de e-mail specificate",
+ "createaccountmail-help": "Pro crear un conto pro un altere persona sin cognoscer le contrasigno.",
"createacct-realname": "Nomine real (optional)",
"createaccountreason": "Motivo:",
"createacct-reason": "Motivo",
"createacct-reason-ph": "Proque crea tu un altere conto?",
+ "createacct-reason-help": "Message pro le registro de creation de contos",
"createacct-submit": "Crear tu conto",
"createacct-another-submit": "Crear conto",
+ "createacct-continue-submit": "Continuar creation de conto",
+ "createacct-another-continue-submit": "Continuar creation de conto",
"createacct-benefit-heading": "{{SITENAME}} es facite per gente como tu.",
"createacct-benefit-body1": "{{PLURAL:$1|modification|modificationes}}",
"createacct-benefit-body2": "{{PLURAL:$1|pagina|paginas}}",
"nocookiesnew": "Le conto de usator ha essite create, sed tu non ha aperite un session.\n{{SITENAME}} usa ''cookies'' pro mantener le sessiones del usatores.\nTu ha disactivate le functionalitate del ''cookies''.\nPer favor activa lo, postea aperi un session con tu nove nomine de usator e contrasigno.",
"nocookieslogin": "{{SITENAME}} usa ''cookies'' pro mantener le sessiones del usatores.\nTu ha disactivate le functionalitate del ''cookies''.\nPer favor activa lo e reprova.",
"nocookiesfornew": "Le conto de usator non esseva create, proque nos non poteva confirmar su origine.\nVerifica que tu ha activate le \"cookies\", recarga iste pagina e reproba.",
+ "createacct-loginerror": "Le conto ha essite create, ma le systema non ha potite aperir session automaticamente. Per favor, [[Special:UserLogin|aperi session manualmente]].",
"noname": "Tu non specificava un nomine de usator valide.",
"loginsuccesstitle": "Session aperite",
"loginsuccess": "'''Tu es ora authenticate in {{SITENAME}} como \"$1\".'''",
- "nosuchuser": "Non existe un usator con le nomine \"$1\".\nIn le nomines de usator se distingue inter majusculas e minusculas.\nVerifica le orthographia, o [[Special:UserLogin/signup|crea un nove conto]].",
+ "nosuchuser": "Non existe un usator con le nomine \"$1\".\nLe nomines de usator distingue inter majusculas e minusculas.\nVerifica le orthographia, o [[Special:CreateAccount|crea un nove conto]].",
"nosuchusershort": "Non existe un usator con le nomine \"$1\".\nVerifica le orthographia.",
"nouserspecified": "Tu debe specificar un nomine de usator.",
"login-userblocked": "Iste usator es blocate. Apertura de session non permittite.",
"createacct-another-realname-tip": "Le nomine real es optional.\nSi tu opta pro dar lo, isto essera usate pro dar al usator attribution pro su contributiones.",
"pt-login": "Aperir session",
"pt-login-button": "Aperir session",
+ "pt-login-continue-button": "Continuar apertura de session",
"pt-createaccount": "Crear conto",
"pt-userlogout": "Clauder session",
"php-mail-error-unknown": "Error incognite in le function mail() de PHP",
"botpasswords-invalid-name": "Iste nomine de usator non contine le separator pro contrasigno de robot (\"$1\").",
"botpasswords-not-exist": "Le usator \"$1\" non ha un contrasigno de robot del nomine \"$2\".",
"resetpass_forbidden": "Le contrasignos non pote esser cambiate",
+ "resetpass_forbidden-reason": "Le contrasignos non pote esser cambiate: $1",
"resetpass-no-info": "Tu debe aperir un session pro poter acceder directemente a iste pagina.",
"resetpass-submit-loggedin": "Cambiar contrasigno",
"resetpass-submit-cancel": "Cancellar",
"passwordreset-emailsentusername": "Si il ha un adresse de e-mail associate a iste conto, alora un e-mail pro reinitialisar le contrasigno essera inviate.",
"passwordreset-emailsent-capture": "Un message de e-mail pro le reinitialisation del contrasigno ha essite inviate; iste message es monstrate hic infra.",
"passwordreset-emailerror-capture": "Un e-mail pro le reinitialisation del contrasigno ha essite generate; iste message es monstrate hic infra, ma le invio al {{GENDER:$2|usator}} ha fallite: $1",
+ "passwordreset-emailsent-capture2": "Le {{PLURAL:$1|message|messages}} de e-mail pro reinitialisation de contrasigno ha essite inviate. Le {{PLURAL:$1|nomine de usator e contrasigno|lista de nomines de usator e contrasignos}} appare hic infra.",
+ "passwordreset-emailerror-capture2": "Le invio de e-mail al {{GENDER:$2|usator}} ha fallite: $1 Le {{PLURAL:$3|nomine de usator e contrasigno|lista de nomines de usator e contrasignos}} appare hic infra.",
+ "passwordreset-nocaller": "Un appellator debe esser fornite",
+ "passwordreset-nosuchcaller": "Appellator non existe: $1",
+ "passwordreset-ignored": "Le reinitialisation del contrasigno non ha essite realisate. Es possibile que nulle fornitor ha essite configurate?",
+ "passwordreset-invalideamil": "Adresse de e-mail invalide",
+ "passwordreset-nodata": "Ni un nomine de usator ni un adresse de e-mail ha essite fornite",
"changeemail": "Cambiar o remover adresse de e-mail",
"changeemail-header": "Completa iste formulario pro cambiar tu adresse de e-mail. Si tu vole remover le association de omne adresse de e-mail ab tu conto, lassa le campo pro le nove adresse de e-mail vacue quando tu submitte le formulario.",
"changeemail-passwordrequired": "Essera necessari entrar tu contrasigno pro confirmar iste cambiamento.",
"minoredit": "Isto es un modification minor",
"watchthis": "Observar iste pagina",
"savearticle": "Publicar pagina",
+ "publishpage": "Publicar pagina",
"preview": "Previsualisation",
"showpreview": "Monstrar previsualisation",
"showdiff": "Detaliar modificationes",
"accmailtext": "Un contrasigno generate aleatorimente pro [[User talk:$1|$1]] ha essite inviate a $2. Illo pote esser cambiate in le pagina ''[[Special:ChangePassword|Cambiar contrasigno]]'' post que tu ha aperite un session.",
"newarticle": "(Nove)",
"newarticletext": "Tu ha sequite un ligamine verso un pagina que non existe ancora.\nPro crear iste pagina, comencia a scriber in le quadro infra (consulta le [$1 pagina de adjuta] pro plus informationes).\nSi tu ha arrivate a iste pagina per error, clicca le button '''Retornar''' de tu navigator.",
- "anontalkpagetext": "---- ''Isto es le pagina de discussion pro un usator anonyme qui non ha ancora create un conto, o qui non lo usa. Consequentemente nos debe usar le adresse IP numeric pro identificar le/la.\nUn tal adresse IP pote esser usate in commun per varie personas.\nSi tu es un usator anonyme e pensa que commentos irrelevante ha essite dirigite a te, per favor [[Special:UserLogin/signup|crea un conto]] o [[Special:UserLogin|aperi un session]] pro evitar futur confusiones con altere usatores anonyme.''",
+ "anontalkpagetext": "----\n<em>Isto es le pagina de discussion pro un usator anonyme qui non ha ancora create un conto, o qui non lo usa.</em>\nConsequentemente nos debe usar le adresse IP numeric como identification.\nUn tal adresse IP pote esser usate in commun per varie personas.\nSi tu es un usator anonyme e pensa que commentos irrelevante ha essite dirigite a te, per favor [[Special:CreateAccount|crea un conto]] o [[Special:UserLogin|aperi un session]] pro evitar futur confusiones con altere usatores anonyme.",
"noarticletext": "Al momento il non ha texto in iste pagina.\nTu pote [[Special:Search/{{PAGENAME}}|cercar le titulo de iste pagina]] in altere paginas,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cercar in le registros pertinente],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} crear iste pagina]</span>.",
"noarticletext-nopermission": "In iste momento il non ha texto in iste pagina.\nTu pote [[Special:Search/{{PAGENAME}}|cercar le titulo de iste pagina]] in altere paginas,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cercar in le registros pertinente], ma tu non ha le permission de crear iste pagina.</span>",
"missing-revision": "Le version №$1 del pagina nominate \"{{FULLPAGENAME}}\" non existe.\n\nIsto es generalmente causate per sequer un ligamine de historia obsolete a un pagina que ha essite delite.\nDetalios se trova in le [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de deletiones].",
"userpage-userdoesnotexist": "Le conto de usator \"<nowiki>$1</nowiki>\" non es registrate. Per favor verifica que tu vole crear/modificar iste pagina.",
"userpage-userdoesnotexist-view": "Le conto de usator \"$1\" non es registrate.",
"blocked-notice-logextract": "Iste usator es actualmente blocate.\nLe ultime entrata del registro de blocadas es reproducite ci infra pro information:",
- "clearyourcache": "'''Nota:''' Post confirmar, il pote esser necessari refrescar le ''cache'' de tu navigator pro vider le cambiamentos.\n* '''Firefox / Safari:''' Tenente ''Shift'' clicca ''Reload (Recargar)'', o preme ''Ctrl-F5'' o ''Ctrl-R'' (''⌘-R'' sur Mac)\n* '''Google Chrome:''' Preme ''Ctrl-Shift-R'' (''⌘-Shift-R'' sur Mac)\n* '''Internet Explorer:''' Tenente ''Ctrl'' clicca ''Refresh (Refrescar)'', o preme ''Ctrl-F5'' \n* '''Opera:''' Vacua le ''cache'' in ''Tools → Preferences (Utensiles → Preferentias)''",
+ "clearyourcache": "<strong>Nota:</strong> Post confirmar, il pote esser necessari refrescar le <em>cache</em> de tu navigator pro vider le cambiamentos.\n* <strong>Firefox / Safari:</strong> Tenente <em>Shift</em> clicca <em>Reload (Recargar)</em>, o preme <em>Ctrl-F5</em> o <em>Ctrl-R</em> (<em>⌘-R</em> sur Mac)\n* <strong>Google Chrome:</strong> Preme <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> sur Mac)\n* <strong>Internet Explorer:</strong> Tenente <em>Ctrl</em> clicca <em>Refresh (Refrescar)</em>, o preme <em>Ctrl-F5</em> \n* <strong>Opera:</strong> Vade a <em>Menu → Configurationes</em> (<em>Opera → Preferentias</em> sur un Mac) e alora a <em>Privacy & securitate → Rader datos de navigation → Files e imagines in cache</em>.",
"usercssyoucanpreview": "'''Consilio:''' Usa le button \"{{int:showpreview}}\" pro testar tu nove CSS ante de salveguardar lo.",
"userjsyoucanpreview": "'''Consilio:''' Usa le button \"{{int:showpreview}}\" pro testar tu nove JavaScript ante de salveguardar lo.",
"usercsspreview": "'''Non oblida que isto es solmente un previsualisation de tu CSS personalisate.'''\n'''Le modificationes non ha ancora essite salveguardate!'''",
"right-override-export-depth": "Exportar paginas includente paginas ligate usque a un profunditate de 5",
"right-sendemail": "Inviar e-mail a altere usatores",
"right-passwordreset": "Vider le e-mails pro reinitialisar le contrasigno",
- "right-managechangetags": "Crear e deler [[Special:Tags|etiquettas]] in le base de datos",
+ "right-managechangetags": "Crear e (de)activar [[Special:Tags|etiquettas]]",
"right-applychangetags": "Applicar [[Special:Tags|etiquettas]] al proprie modificationes",
"right-changetags": "Adder e remover qualcunque [[Special:Tags|etiquettas]] sur individual versiones e entratas de registro",
+ "right-deletechangetags": "Deler [[Special:Tags|etiquettas]] del base de datos",
"grant-generic": "Gruppo de derectos \"$1\"",
"grant-group-page-interaction": "Interager con paginas",
"grant-group-file-interaction": "Interager con multimedia",
"action-viewmyprivateinfo": "vider le proprie information private",
"action-editmyprivateinfo": "modificar le proprie information private",
"action-editcontentmodel": "modificar le modello de contento de un pagina",
- "action-managechangetags": "crear e deler etiquettas in le base de datos",
+ "action-managechangetags": "crear e (de)activar etiquettas",
"action-applychangetags": "applicar etiquettas al proprie modificationes",
"action-changetags": "adder e remover qualcunque etiquettas sur individual versiones e entratas de registro",
+ "action-deletechangetags": "deler etiquettas del base de datos",
"nchanges": "$1 {{PLURAL:$1|modification|modificationes}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde le ultime visita}}",
"enhancedrc-history": "historia",
"recentchangeslinked-page": "Nomine del pagina:",
"recentchangeslinked-to": "Monstrar modificationes in paginas con ligamines al pagina specificate",
"recentchanges-page-added-to-category": "[[:$1]] addite al categoria",
- "recentchanges-page-added-to-category-bundled": "[[:$1]] e [[Special:WhatLinksHere/$1|{{PLURAL:$2|un pagina|$2 paginas}}]] addite al categoria",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] addite al categoria, [[Special:WhatLinksHere/$1|iste pagina es includite in altere paginas]]",
"recentchanges-page-removed-from-category": "[[:$1]] removite del categoria",
- "recentchanges-page-removed-from-category-bundled": "[[:$1]] e [[Special:WhatLinksHere/$1|{{PLURAL:$2|un pagina|$2 paginas}}]] removite del categoria",
+ "recentchanges-page-removed-from-category-bundled": "[[:$1]] removite del categoria, [[Special:WhatLinksHere/$1|iste pagina es includite in altere paginas]]",
"autochange-username": "Cambiamento automatic de MediaWiki",
"upload": "Incargar file",
"uploadbtn": "Incargar file",
"upload-form-label-own-work": "Iste es mi proprie obra",
"upload-form-label-infoform-categories": "Categorias",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-own-work-message-local": "Io confirma que io incarga iste file secundo le conditiones de servicio e politicas de licentia de {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Si tu non pote incargar iste file in concordantia con le politicas de {{SITENAME}}, per favor claude iste dialogo e essaya un altere methodo.",
- "upload-form-label-not-own-work-local-local": "Tu pote etiam essayar [[Special:Upload|le pagina de incargamento normal]].",
- "upload-form-label-own-work-message-default": "Io comprende que io incarga iste file in un repositorio commun. Io confirma que io lo face secundo le conditiones de servicio e politicas de licentia de illo.",
- "upload-form-label-not-own-work-message-default": "Si tu non pote incargar iste file in concordantia con le politicas del repositorio commun, per favor claude iste dialogo e essaya un altere methodo.",
- "upload-form-label-not-own-work-local-default": "Tu pote anque probar [[Special:Upload|le pagina de incargamento in {{SITENAME}}]], si le politicas de ille sito permitte incargar iste file.",
- "upload-form-label-own-work-message-shared": "Io certifica que io possede le derecto de autor sur iste file, io consenti le publication irrevocabile de iste file a Wikimedia Commons sub le licentia [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], e io accepta le [https://wikimediafoundation.org/wiki/Terms_of_Use conditiones de uso].",
- "upload-form-label-not-own-work-message-shared": "Si tu non possede le derecto de autor sur iste file, o si tu prefere publicar lo sub un altere licentia, considera usar le [https://commons.wikimedia.org/wiki/Special:UploadWizard assistente de incargamento de Commons].",
- "upload-form-label-not-own-work-local-shared": "Tu pote anque probar [[Special:Upload|le pagina de incargamento in {{SITENAME}}]], si le politicas de ille sito permitte incargar iste file.",
+ "upload-form-label-own-work-message-generic-local": "Io confirma que io incarga iste file secundo le conditiones de servicio e politicas de licentia de {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Si tu non pote incargar iste file in concordantia con le politicas de {{SITENAME}}, per favor claude iste dialogo e essaya un altere methodo.",
+ "upload-form-label-not-own-work-local-generic-local": "Tu pote etiam essayar [[Special:Upload|le pagina de incargamento normal]].",
+ "upload-form-label-own-work-message-generic-foreign": "Io comprende que io incarga iste file in un repositorio commun. Io confirma que io lo face secundo le conditiones de servicio e politicas de licentia de illo.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Si tu non pote incargar iste file in concordantia con le politicas del repositorio commun, per favor claude iste dialogo e essaya un altere methodo.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Tu pote anque probar [[Special:Upload|le pagina de incargamento in {{SITENAME}}]], si le politicas de ille sito permitte incargar iste file.",
"backend-fail-stream": "Non poteva transmitter le file $1.",
"backend-fail-backup": "Non poteva facer un copia de reserva del file $1.",
"backend-fail-notexists": "Le file $1 non existe.",
"trackingcategories-msg": "Categoria de sequimento",
"trackingcategories-name": "Nomine del message",
"trackingcategories-desc": "Criterios pro inclusion in categoria",
+ "restricted-displaytitle-ignored": "Paginas con titulos a monstrar ignorate",
+ "restricted-displaytitle-ignored-desc": "Le pagina ha un <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> ignorate perque illo non es equivalente al titulo real del pagina.",
"noindex-category-desc": "Iste pagina es excludite del indice perque illo contine le marca <code><nowiki>__NOINDEX__</nowiki></code> e es in un spatio de nomines ubi le uso de iste marca es permittite.",
"index-category-desc": "Iste pagina contine le marca <code><nowiki>__INDEX__</nowiki></code> (e es in un spatio de nomines ubi le uso de iste marca es permittite), e dunque es includite in le indice mesmo si illo normalmente non lo esserea.",
"post-expand-template-inclusion-category-desc": "Le dimension del pagina es plus grande de <code>$wgMaxArticleSize</code> post le expansion de tote le patronos, dunque alcun patronos non ha essite expandite.",
"rollbacklinkcount": "revocar $1 {{PLURAL:$1|modification|modificationes}}",
"rollbacklinkcount-morethan": "revocar plus de $1 {{PLURAL:$1|modification|modificationes}}",
"rollbackfailed": "Revocation fallite",
+ "rollback-missingparam": "Manca parametros obligatori in le requesta.",
"cantrollback": "Impossibile revocar le modification;\nle ultime contributor es le sol autor de iste pagina.",
"alreadyrolled": "Non pote revocar le ultime modification de [[:$1]] per [[User:$2|$2]] ([[User talk:$2|discussion]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nun altere persona ha ja modificate o revocate le pagina.\n\nLe ultime modification esseva facite per [[User:$3|$3]] ([[User talk:$3|discussion]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "Le summario del modification esseva: <em>$1</em>.",
"revertpage": "Reverteva modificationes per [[Special:Contributions/$2|$2]] ([[User talk:$2|Discussion]]) al ultime version per [[User:$1|$1]]",
"revertpage-nouser": "Reverteva modificationes per un usator celate al ultime version per {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Revocava modificationes per $1;\nretornava al version per $2.",
+ "rollback-success-notify": "Modificationes de $1 revertite;\nultime version de $2 restaurate. [$3 Monstrar cambiamentos]",
"sessionfailure-title": "Error de session",
"sessionfailure": "Il pare haber un problema con tu session de conto;\niste action ha essite cancellate como precaution contra le sequestramento de sessiones.\nPer favor preme \"retro\" e recarga le pagina de ubi tu ha venite, postea reprova.",
"changecontentmodel": "Cambiar le modello de contento de un pagina",
"changecontentmodel-success-text": "Le typo de contento de [[:$1]] ha essite cambiate.",
"changecontentmodel-cannot-convert": "Le contento de [[:$1]] non pote esser convertite a un typo de $2.",
"changecontentmodel-nodirectediting": "Le modello de contento $1 non supporta le modification directe",
+ "changecontentmodel-emptymodels-title": "Nulle modello de contento disponibile",
+ "changecontentmodel-emptymodels-text": "Le contento in [[:$1]] non pote esser convertite in alcun typo.",
"log-name-contentmodel": "Registro de cambiamentos de modello de contento",
"log-description-contentmodel": "Eventos relative al modellos de contento de un pagina",
"logentry-contentmodel-new": "$1 {{GENDER:$2|creava}} le pagina $3 con le modello de contento non predefinite \"$5\"",
"lockdbsuccesstext": "Le base de datos de {{SITENAME}} ha essite blocate.\n<br />Rememora te de disblocar lo post completar tu mantenentia.",
"unlockdbsuccesstext": "Le base de datos de {{SITENAME}} ha essite disblocate.",
"lockfilenotwritable": "Impossibile scriber al file de blocada del base de datos.\nPro blocar o disblocar le base de datos, le servitor web debe poter scriber a iste file.",
+ "databaselocked": "Le base de datos es jam blocate.",
"databasenotlocked": "Le base de datos non es blocate.",
"lockedbyandtime": "(per $1 le $2 a $3)",
"move-page": "Renominar $1",
"tooltip-ca-nstab-category": "Vider le pagina del categoria",
"tooltip-minoredit": "Marcar iste modification como minor",
"tooltip-save": "Confirmar tu modificationes",
+ "tooltip-publish": "Publicar tu cambiamentos",
"tooltip-preview": "Per favor verifica tu modificationes ante que tu los publica!",
"tooltip-diff": "Detaliar le modificationes que tu ha facite in le texto.",
"tooltip-compareselectedversions": "Vider le differentias inter le seligite duo versiones de iste pagina.",
"exif-sublocationcreated": "Sublocalitate del citate ubi le photo esseva prendite",
"exif-worldregiondest": "Region del mundo monstrate",
"exif-countrydest": "Pais monstrate",
- "exif-countrycodedest": "Codice pro pais monstrate",
+ "exif-countrycodedest": "Codice del pais monstrate",
"exif-provinceorstatedest": "Provincia o stato monstrate",
"exif-citydest": "Citate monstrate",
"exif-sublocationdest": "Sublocalitate del citate monstrate",
"confirmemail_body_set": "Un persona, probabilemente tu, usante le adresse IP $1,\nha specificate que iste adresse de e-mail pertine al conto \"$2\" in {{SITENAME}}.\n\nPro confirmar que iste conto vermente pertine a te, e pro activar le functionalitate\nde e-mail in {{SITENAME}}, visita iste ligamine in tu navigator:\n\n$3\n\nSi le conto *non* pertine a te, seque iste ligamine\npro cancellar le confirmation del adresse de e-mail:\n\n$5\n\nIste codice de confirmation expirara le $6 a $7.",
"confirmemail_invalidated": "Confirmation del adresse de e-mail cancellate",
"invalidateemail": "Cancellar confirmation del adresse de e-mail",
+ "notificationemail_subject_changed": "Le adresse de e-mail registrate sur {{SITENAME}} ha essite cambiate",
+ "notificationemail_subject_removed": "Le adresse de e-mail registrate sur {{SITENAME}} ha essite removite",
+ "notificationemail_body_changed": "Qualcuno, probabilemente tu, ab le adresse IP $1, ha cambiate le adresse de e-mail del conto \"$2\" in \"$3\" sur {{SITENAME}}.\n\nSi isto non esseva tu, contacta immediatemente un administrator del sito.",
+ "notificationemail_body_removed": "Qualcuno, probabilemente tu, ab le adresse IP $1, ha removite le adresse de e-mail del conto \"$2\" sur {{SITENAME}}.\n\nSi isto non esseva tu, contacta immediatemente un administrator del sito.",
"scarytranscludedisabled": "[Le transclusion interwiki es disactivate]",
"scarytranscludefailed": "[Falleva de obtener le patrono pro $1]",
"scarytranscludefailed-httpstatus": "[Obtention de patrono fallite pro $1: HTTP $2]",
"confirm-watch-top": "Adder iste pagina a tu observatorio?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Remover iste pagina de tu observatorio?",
+ "confirm-rollback-top": "Reverter le modificationes a iste pagina?",
"quotation-marks": "“$1”",
"imgmultipageprev": "← precedente pagina",
"imgmultipagenext": "sequente pagina →",
"watchlistedit-raw-done": "Tu observatorio ha essite actualisate.",
"watchlistedit-raw-added": "{{PLURAL:$1|1 titulo|$1 titulos}} ha essite addite:",
"watchlistedit-raw-removed": "{{PLURAL:$1|1 titulo|$1 titulos}} ha essite removite:",
- "watchlistedit-clear-title": "Observatorio radite",
+ "watchlistedit-clear-title": "Rader observatorio",
"watchlistedit-clear-legend": "Rader observatorio",
"watchlistedit-clear-explain": "Tote le titulos essera removite de tu observatorio",
"watchlistedit-clear-titles": "Titulos:",
"timezone-local": "Local",
"duplicate-defaultsort": "Attention: Le clave de ordination predefinite \"$2\" supplanta le anterior clave de ordination predefinite \"$1\".",
"duplicate-displaytitle": "<strong>Attention:</strong> Le titulo a monstrar \"$2\" supplanta le ancian titulo a monstrar \"$1\".",
+ "restricted-displaytitle": "<strong>Attention:</strong> Le titulo a monstrar \"$1\" ha essite ignorate perque illo non es equivalente al titulo real del pagina.",
"invalid-indicator-name": "<strong>Error:</strong> Le attributo <code>name</code> del indicatores del stato del pagina non pote esser vacue.",
"version": "Version",
"version-extensions": "Extensiones installate",
"version-libraries-description": "Description",
"version-libraries-authors": "Autores",
"redirect": "Rediriger per ID de file, usator, pagina, version o registro",
- "redirect-summary": "Iste pagina special redirige a un file (si es date le nomine de un file), a un pagina (si es date un ID de version o ID de pagina) o a un pagina de usator (si es date un ID de usator numeric). Usage: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]] o [[{{#Special:Redirect}}/user/101]].",
+ "redirect-summary": "Iste pagina special redirige a un file (si es date le nomine de un file), a un pagina (si es date un ID de version o ID de pagina), a un pagina de usator (si es date un ID de usator numeric) o a un entrata de registro (si es date le ID de un registro). Usage: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] o [[{{#Special:Redirect}}/logid/186]].",
"redirect-submit": "Va",
"redirect-lookup": "Cercar:",
"redirect-value": "Valor:",
"redirect-page": "ID del pagina",
"redirect-revision": "Version de pagina",
"redirect-file": "Nomine de file",
+ "redirect-logid": "ID de registro",
"redirect-not-exists": "Valor non trovate",
"fileduplicatesearch": "Cercar files duplicate",
"fileduplicatesearch-summary": "Cercar files duplicate a base de lor summas de verification ''(hash).''",
"tags-deactivate": "disactivar",
"tags-hitcount": "$1 {{PLURAL:$1|modification|modificationes}}",
"tags-manage-no-permission": "Tu non ha le permission de gerer le etiquettas de modification.",
+ "tags-manage-blocked": "Tu non pote gerer etiquettas de cambiamento durante que tu es blocate.",
"tags-create-heading": "Crear un nove etiquetta",
"tags-create-explanation": "Per configuration predefinite, le etiquettas novemente create essera disponibile pro le uso per usatores e robots.",
"tags-create-tag-name": "Nomine del etiquetta:",
"tags-delete-not-found": "Le etiquetta \"$1\" non existe.",
"tags-delete-too-many-uses": "Le etiquetta \"$1\" es applicate a plus de $2 {{PLURAL:$2|version|versiones}}, e per isto non pote esser delite.",
"tags-delete-warnings-after-delete": "Le etiquetta \"$1\" ha essite delite, ma le sequente {{PLURAL:$2|advertimento|advertimentos}} ha essite incontrate:",
+ "tags-delete-no-permission": "Tu non ha le permission de deler etiquettas de modification.",
"tags-activate-title": "Activar etiquetta",
"tags-activate-question": "Tu es sur le puncto de activar le etiquetta \"$1\".",
"tags-activate-reason": "Motivo:",
"tags-deactivate-not-allowed": "Non es possibile disactivar le etiquetta \"$1\".",
"tags-deactivate-submit": "Disactivar",
"tags-apply-no-permission": "Tu non ha le permission de adjunger etiquettas de cambiamento a tu cambiamentos.",
+ "tags-apply-blocked": "Tu non pote applicar etiquettas de cambiamento con tu cambiamentos durante que tu es blocate.",
"tags-apply-not-allowed-one": "Non es permittite applicar le etiquetta \"$1\" manualmente.",
"tags-apply-not-allowed-multi": "Le sequente {{PLURAL:$2|etiquetta|etiquettas}} non es autorisate a esser manualmente applicate: $1",
"tags-update-no-permission": "Tu non ha le permission de adder o remover etiquettas de cambiamento sur individual versiones o entratas de registro.",
+ "tags-update-blocked": "Tu non pote adder o remover etiquettas de cambiamento durante que tu es blocate.",
"tags-update-add-not-allowed-one": "Non es permittite adjunger le etiquetta \"$1\" manualmente.",
"tags-update-add-not-allowed-multi": "Le sequente {{PLURAL:$2|etiquetta|etiquettas}} non es autorisate a esser manualmente adjungite: $1",
"tags-update-remove-not-allowed-one": "Non es permittite remover le etiquetta \"$1\".",
"tags-edit-revision-legend": "Adder o remover etiquettas de {{PLURAL:$1|iste version|tote le $1 versiones}}",
"tags-edit-logentry-legend": "Adder o remover etiquettas de {{PLURAL:$1|iste entrata|tote le $1 entratas}} de registro",
"tags-edit-existing-tags": "Etiquettas existente:",
- "tags-edit-existing-tags-none": "\"Nulle\"",
+ "tags-edit-existing-tags-none": "<em>Nulle</em>",
"tags-edit-new-tags": "Nove etiquettas:",
"tags-edit-add": "Adder iste etiquettas:",
"tags-edit-remove": "Remover iste etiquettas:",
"logentry-protect-protect-cascade": "$1 {{GENDER:$2|protegeva}} $3 $4 [in cascada]",
"logentry-protect-modify": "$1 {{GENDER:$2|cambiava}} le nivello de protection de $3 $4",
"logentry-protect-modify-cascade": "$1 {{GENDER:$2|cambiava}} le nivello de protection de $3 $4 [in cascada]",
- "logentry-rights-rights": "$1 {{GENDER:$2|cambiava}} le appertinentia a gruppos pro $3 de $4 a $5",
+ "logentry-rights-rights": "$1 {{GENDER:$2|cambiava}} le appertinentia a gruppos pro {{GENDER:$6|$3}} de $4 a $5",
"logentry-rights-rights-legacy": "$1 {{GENDER:$2|cambiava}} le appertinentia a gruppos pro $3",
"logentry-rights-autopromote": "$1 ha essite automaticamente {{GENDER:$2|promovite}} de $4 a $5",
"logentry-upload-upload": "$1 {{GENDER:$2|ha incargate}} $3",
"feedback-useragent": "Agente usator:",
"searchsuggest-search": "Cercar",
"searchsuggest-containing": "continente...",
+ "api-error-autoblocked": "Tu adresse IP ha essite blocate automaticamente, perque illo ha essite usate per un usator blocate.",
"api-error-badaccess-groups": "Tu non ha le permission de incargar files in iste wiki.",
"api-error-badtoken": "Error interne: indicio invalide.",
+ "api-error-blocked": "Le modification ha essite blocate pro te.",
"api-error-copyuploaddisabled": "Le incargamentos per URL es disactivate in iste servitor.",
"api-error-duplicate": "Existe jam {{PLURAL:$1|un altere file|altere files}} in le wiki con le mesme contento.",
"api-error-duplicate-archive": "Il habeva jam {{PLURAL:$1|un altere file|altere files}} in le sito con le mesme contento, ma {{PLURAL:$1|illo|illos}} ha essite delite.",
"api-error-nomodule": "Error interne: nulle modulo de incargamento definite.",
"api-error-ok-but-empty": "Error interne: nulle responsa del servitor.",
"api-error-overwrite": "Superscriber un file existente non es permittite.",
+ "api-error-ratelimited": "Tu tenta incargar plus files in curte tempore que iste wiki permitte.\nPer favor, reproba in alcun minutas.",
"api-error-stashfailed": "Error interne: le servitor non poteva immagazinar le file temporari.",
"api-error-publishfailed": "Error interne: le servitor non poteva publicar le file temporari.",
"api-error-stasherror": "Un error ha occurrite durante le incargamento del file in \"stash\".",
"api-error-unknownerror": "Error incognite: \"$1\".",
"api-error-uploaddisabled": "Le incargamento es disactivate in iste wiki.",
"api-error-verification-error": "Le file pote esser corrumpite o su nomine pote haber un extension errate.",
+ "api-error-was-deleted": "Un file con iste nomine ha jam essite incargate e postea delite.",
"duration-seconds": "$1 {{PLURAL:$1|secunda|secundas}}",
"duration-minutes": "$1 {{PLURAL:$1|minuta|minutas}}",
"duration-hours": "$1 {{PLURAL:$1|hora|horas}}",
"expand_templates_generate_xml": "Monstrar arbore syntactic XML",
"expand_templates_generate_rawhtml": "Monstrar HTML brute",
"expand_templates_preview": "Previsualisation",
- "expand_templates_preview_fail_html": "<em>Perque {{SITENAME}} ha HTML crude activate e il habeva un perdita de datos de session, le previsualisation es celate como precaution contra attaccos con JavaScript.</em>\n\n<strong>Si isto es un tentativa de previsualisation legitime, per favor essaya lo de novo.</strong>\nSi illo ancora non functiona, essaya [[Special:UserLogout|clauder le session]] e aperir un nove session.",
+ "expand_templates_preview_fail_html": "<em>Perque {{SITENAME}} ha HTML crude activate e il habeva un perdita de datos de session, le previsualisation es celate como precaution contra attaccos con JavaScript.</em>\n\n<strong>Si isto es un tentativa de previsualisation legitime, per favor essaya lo de novo.</strong>\nSi illo ancora non functiona, essaya [[Special:UserLogout|clauder le session]] e aperir un nove session, e verifica que tu navigator permitte le cookies de iste sito.",
"expand_templates_preview_fail_html_anon": "<em>Perque {{SITENAME}} ha HTML crude activate e tu non ha aperite session, le previsualisation es celate como precaution contra attaccos con JavaScript.</em>\n\n<strong>Si isto es un tentativa de previsualisation legitime, per favor [[Special:UserLogin|aperi session]] e essaya lo de novo.</strong>",
- "pagelanguage": "Selector de lingua de pagina",
+ "expand_templates_input_missing": "Tu debe scriber alcun texto de entrata.",
+ "pagelanguage": "Cambiar lingua del pagina",
"pagelang-name": "Pagina",
"pagelang-language": "Lingua",
"pagelang-use-default": "Usar lingua predefinite",
"pagelang-select-lang": "Selige lingua",
+ "pagelang-submit": "Submitter",
"right-pagelang": "Cambiar lingua del pagina",
"action-pagelang": "cambiar le lingua del pagina",
"log-name-pagelang": "Registro de cambios de lingua",
"log-description-pagelang": "Isto es un registro de cambios de lingua in paginas.",
- "logentry-pagelang-pagelang": "$1 {{GENDER:$2|cambiava}} le lingua del pagina $3 de $4 a $5.",
+ "logentry-pagelang-pagelang": "$1 {{GENDER:$2|cambiava}} le lingua de $3 de $4 a $5.",
"default-skin-not-found": "Attention! Le apparentia predefinite de tu wiki, definite in <code dir=\"ltr\">$wgDefaultSkin</code> como <code>$1</code>, non es disponibile.\n\nLe installation pare includer le sequente {{PLURAL:$4|apparentia|apparentias}}. Vide [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] pro saper como activar {{PLURAL:$4|lo|los e seliger le predefinite}}.\n\n$2\n\n; Si tu ha justo installate MediaWiki:\n: Tu lo ha probabilemente installate a partir de git, o directemente del codice fonte con un altere methodo. Isto es normal. Essaya installar alcun apparentias desde [https://www.mediawiki.org/wiki/Category:All_skins le directorio de apparentias de mediawiki.org], per:\n:* Discargar le [https://www.mediawiki.org/wiki/Download archivo tar del installator], que include plure apparentias e extensiones. Tu pote copiar e collar le directorio <code>skins/</code> de illo.\n:* Discargar archivos tar con apparentias indidivual ab [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Usar Git pro discargar apparentias].\n: Facer isto non deberea interferer con tu repositorio git si tu es un disveloppator de MediaWiki.\n\n; Si tu ha justo actualisate MediaWiki:\n: MediaWiki a partir del version 1.24 non plus activa automaticamente le apparentias installate (vide [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). Tu pote collar le sequente {{PLURAL:$5|linea|lineas}} in <code>LocalSettings.php</code> pro activar {{PLURAL:$5|le apparentia|tote le apparentias}} actualmente installate:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Si tu ha justo modificate <code>LocalSettings.php</code>:\n: Verifica meticulosemente que le nomines del apparentias non ha errores.",
"default-skin-not-found-no-skins": "Attention! Le apparentia predefinite de tu wiki, definite in <code>$wgDefaultSkin</code> como <code>$1</code>, non es disponibile.\n\nTu non ha apparentias installate.\n\n; Si tu ha justo installate o actualisate MediaWiki:\n: Tu lo ha probabilemente installate a partir de git, o directemente del codice fonte con un altere methodo. Isto es normal. Essaya installar alcun apparentias desde [https://www.mediawiki.org/wiki/Category:All_skins le directorio de apparentias de mediawiki.org], per:\n:* Discargar le [https://www.mediawiki.org/wiki/Download archivo tar del installator], que include plure apparentias e extensiones. Tu pote copiar e collar le directorio <code>skins/</code> de illo.\n:* Discargar archivos tar con apparentias individual ab [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Using_Git_to_download_MediaWiki_skins Usar Git pro discargar apparentias].\n: Facer isto non deberea interferer con tu repositorio git si tu es un disveloppator de MediaWiki. Vide [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] pro saper como activar apparentias e seliger le predefinite.",
"default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (activate)",
"mediastatistics": "Statisticas de multimedia",
"mediastatistics-summary": "Statisticas sur le typos de file incargate. Isto include solmente le version le plus recente de un file. Versiones ancian o delite de files es excludite.",
"mediastatistics-nbytes": "{{PLURAL:$1|$1 byte|$1 bytes}} ($2; $3%)",
+ "mediastatistics-bytespertype": "Dimension total de files pro iste section: {{PLURAL:$1|$1 byte|$1 bytes}} ($2; $3%).",
+ "mediastatistics-allbytes": "Dimension total de tote le files: {{PLURAL:$1|$1 byte|$1 bytes}} ($2).",
"mediastatistics-table-mimetype": "Typo MIME",
"mediastatistics-table-extensions": "Extensiones possibile",
"mediastatistics-table-count": "Numero de files",
"mediastatistics-header-text": "Textual",
"mediastatistics-header-executable": "Executabiles",
"mediastatistics-header-archive": "Formatos comprimite",
+ "mediastatistics-header-total": "Tote le files",
"json-warn-trailing-comma": "$1 {{PLURAL:$1|comma|commas}} final ha essite removite de JSON",
"json-error-unknown": "Il habeva un problema con le JSON. Error: $1",
"json-error-depth": "Le profunditate maxime del pila ha essite excedite",
"special-characters-group-ipa": "IPA",
"special-characters-group-symbols": "Symbolos",
"special-characters-group-greek": "Greco",
+ "special-characters-group-greekextended": "Greco extense",
"special-characters-group-cyrillic": "Cyrillic",
"special-characters-group-arabic": "Arabe",
"special-characters-group-arabicextended": "Arabe extendite",
"mw-widgets-titleinput-description-new-page": "pagina non existe ancora",
"mw-widgets-titleinput-description-redirect": "redirection a $1",
"api-error-blacklisted": "Per favor elige un altere titulo, plus descriptive.",
- "randomrootpage": "Pagina-radice aleatori"
+ "sessionmanager-tie": "Impossibile combinar plure typos de authentication de requesta: $1.",
+ "sessionprovider-generic": "sessiones $1",
+ "sessionprovider-mediawiki-session-cookiesessionprovider": "sessiones basate sur cookies",
+ "sessionprovider-nocookies": "Le cookies pote esser disactivate. Assecura te de haber activate le cookies e recomencia.",
+ "randomrootpage": "Pagina radice aleatori",
+ "log-action-filter-block": "Typo de blocada:",
+ "log-action-filter-contentmodel": "Typo de modification de modello de contento:",
+ "log-action-filter-delete": "Typo de deletion:",
+ "log-action-filter-import": "Typo de importation:",
+ "log-action-filter-managetags": "Typo de action de gestion de etiquettas:",
+ "log-action-filter-move": "Typo de renomination:",
+ "log-action-filter-newusers": "Typo de creation de conto:",
+ "log-action-filter-patrol": "Typo de patrulia:",
+ "log-action-filter-protect": "Typo de protection:",
+ "log-action-filter-rights": "Typo de cambio de derecto",
+ "log-action-filter-suppress": "Typo de suppression",
+ "log-action-filter-upload": "Typo de incargamento:",
+ "log-action-filter-all": "Toto",
+ "log-action-filter-block-block": "Blocar",
+ "log-action-filter-block-reblock": "Modification de blocada",
+ "log-action-filter-block-unblock": "Disblocar",
+ "log-action-filter-contentmodel-change": "Cambio de modello de contento",
+ "log-action-filter-contentmodel-new": "Creation de pagina con modello de contento non standard",
+ "log-action-filter-delete-delete": "Deletion de pagina",
+ "log-action-filter-delete-restore": "Restauration de pagina",
+ "log-action-filter-delete-event": "Deletion de registro",
+ "log-action-filter-delete-revision": "Deletion de version",
+ "log-action-filter-import-interwiki": "Importation trans wiki",
+ "log-action-filter-import-upload": "Importation per incargamento XML",
+ "log-action-filter-managetags-create": "Creation de etiquetta",
+ "log-action-filter-managetags-delete": "Deletion de etiquetta",
+ "log-action-filter-managetags-activate": "Activation de etiquetta",
+ "log-action-filter-managetags-deactivate": "Disactivation de etiquetta",
+ "log-action-filter-move-move": "Renomination sin superscriber redirectiones",
+ "log-action-filter-move-move_redir": "Renomination superscribente redirectiones",
+ "log-action-filter-newusers-create": "Creation per usator anonyme",
+ "log-action-filter-newusers-create2": "Creation per usator registrate",
+ "log-action-filter-newusers-autocreate": "Creation automatic",
+ "log-action-filter-newusers-byemail": "Creation con contrasigno inviate per e-mail",
+ "log-action-filter-patrol-patrol": "Patrulia manual",
+ "log-action-filter-patrol-autopatrol": "Patrulia automatic",
+ "log-action-filter-protect-protect": "Protection",
+ "log-action-filter-protect-modify": "Modification de protection",
+ "log-action-filter-protect-unprotect": "Disprotection",
+ "log-action-filter-protect-move_prot": "Protection displaciate",
+ "log-action-filter-rights-rights": "Cambiamento manual",
+ "log-action-filter-rights-autopromote": "Cambiamento automatic",
+ "log-action-filter-suppress-event": "Suppression de registro",
+ "log-action-filter-suppress-revision": "Suppression de version",
+ "log-action-filter-suppress-delete": "Suppression de pagina",
+ "log-action-filter-suppress-block": "Suppression de usator per blocada",
+ "log-action-filter-suppress-reblock": "Suppression de usator per re-blocada",
+ "log-action-filter-upload-upload": "Nove file incargate",
+ "log-action-filter-upload-overwrite": "File re-incargate",
+ "authmanager-authn-not-in-progress": "Le authentication non es in curso o le datos del session ha essite perdite. Per favor, recomencia ab initio.",
+ "authmanager-authn-no-primary": "Le credentiales fornite non poteva esse authenticate.",
+ "authmanager-authn-no-local-user": "Le credentiales fornite non es associate a alcun usator in iste wiki.",
+ "authmanager-authn-no-local-user-link": "Le credentiales fornite es in ordine, ma non es associate a alcun usator in iste wiki. Aperi session de altere maniera, o crea un nove conto, e tu haberea le possibilitate de ligar tu credentiales anterior a ille conto.",
+ "authmanager-authn-autocreate-failed": "Le creation automatic de un conto local ha fallite: $1",
+ "authmanager-change-not-supported": "Le credentiales fornite non pote esser cambiate perque nihil los usarea.",
+ "authmanager-create-disabled": "Le creation de contos es disactivate.",
+ "authmanager-create-from-login": "Pro crear tu conto, completa le campos hic infra.",
+ "authmanager-create-not-in-progress": "Nulle creation de conto es in curso, o le datos del session ha essite perdite. Per favor, recomencia ab initio.",
+ "authmanager-create-no-primary": "Le credentiales fornite non pote esser usate pro crear un conto.",
+ "authmanager-link-no-primary": "Le credentiales fornite non pote esser usate pro ligar un conto.",
+ "authmanager-link-not-in-progress": "Nulle ligation de conto es in curso, o le datos del session ha essite perdite. Per favor, recomencia ab initio.",
+ "authmanager-authplugin-setpass-failed-title": "Cambio de contrasigno fallite",
+ "authmanager-authplugin-setpass-failed-message": "Le modulo de authentication ha refusate le cambio de contrasigno.",
+ "authmanager-authplugin-create-fail": "Le modulo de authentication ha refusate le creation de conto.",
+ "authmanager-authplugin-setpass-denied": "Le modulo de authentication non permitte cambiar contrasignos.",
+ "authmanager-authplugin-setpass-bad-domain": "Dominio non valide.",
+ "authmanager-autocreate-noperm": "Le creation automatic de contos non es permittite.",
+ "authmanager-autocreate-exception": "Le creation automatic de contos ha essite temporarimente disactivate a causa de errores previe.",
+ "authmanager-userdoesnotexist": "Le conto de usator \"$1\" non es registrate.",
+ "authmanager-userlogin-remembermypassword-help": "Indica si le contrasigno debe esser memorisate ultra le durata del session.",
+ "authmanager-username-help": "Nomine de usator pro authentication.",
+ "authmanager-password-help": "Contrasigno pro authentication.",
+ "authmanager-domain-help": "Dominio pro authentication externe.",
+ "authmanager-retype-help": "Repetition del contrasigno pro confirmar.",
+ "authmanager-email-label": "E-mail",
+ "authmanager-email-help": "Adresse de e-mail",
+ "authmanager-realname-label": "Nomine real",
+ "authmanager-realname-help": "Le nomine real del usator",
+ "authmanager-provider-password": "Authentication per contrasigno",
+ "authmanager-provider-password-domain": "Authentication per contrasigno e dominio",
+ "authmanager-provider-temporarypassword": "Contrasigno temporari",
+ "authprovider-confirmlink-message": "Secundo tu recente aperturas de session, le sequente contos pote esser ligate a tu conto wiki. Ligar les te permittera aperir session per medio de ille contos. Per favor selige le contos que debe esser ligate.",
+ "authprovider-confirmlink-request-label": "Contos que debe esser ligate",
+ "authprovider-confirmlink-success-line": "$1: Ligation succedite.",
+ "authprovider-confirmlink-failed": "Le ligation del conto non ha ben succedite: $1",
+ "authprovider-confirmlink-ok-help": "Continuar post monstrar le messages de fallimento de ligation.",
+ "authprovider-resetpass-skip-label": "Saltar",
+ "authprovider-resetpass-skip-help": "Saltar le reinitialisation del contrasigno.",
+ "authform-nosession-login": "Le authentication ha succedite, ma tu navigator non pote \"memorisar\" que tu ha aperite session.\n\n$1",
+ "authform-nosession-signup": "Le conto ha essite create, ma tu navigator non pote \"memorisar\" que tu ha aperite session.\n\n$1",
+ "authform-newtoken": "Indicio mancante. $1",
+ "authform-notoken": "Indicio mancante",
+ "authform-wrongtoken": "Indicio incorrecte",
+ "specialpage-securitylevel-not-allowed-title": "Non permittite",
+ "specialpage-securitylevel-not-allowed": "Regrettabilemente, tu non pote usar iste pagina perque tu identitate non poteva esser verificate.",
+ "authpage-cannot-login": "Impossibile comenciar a aperir session.",
+ "authpage-cannot-login-continue": "Impossibile continuar a aperir session. Le session ha probabilemente expirate.",
+ "authpage-cannot-create": "Impossibile comenciar le creation de conto.",
+ "authpage-cannot-create-continue": "Impossibile continuar le creation de conto. Le session ha probabilemente expirate.",
+ "authpage-cannot-link": "Impossibile comenciar le ligation de conto.",
+ "authpage-cannot-link-continue": "Impossibile continuar le ligation de conto. Le session ha probabilemente expirate.",
+ "cannotauth-not-allowed-title": "Permission refusate",
+ "cannotauth-not-allowed": "Tu non es autorisate a usar iste pagina",
+ "changecredentials": "Cambiar credentiales",
+ "changecredentials-submit": "Cambiar credentiales",
+ "changecredentials-invalidsubpage": "$1 non es un typo de credential valide.",
+ "changecredentials-success": "Tu credentiales ha essite cambiate.",
+ "removecredentials": "Remover credentiales",
+ "removecredentials-submit": "Remover credentiales",
+ "removecredentials-invalidsubpage": "$1 non es un typo de credential valide.",
+ "removecredentials-success": "Tu credentiales ha essite removite.",
+ "credentialsform-provider": "Typo de credentiales:",
+ "credentialsform-account": "Nomine de conto:",
+ "cannotlink-no-provider-title": "Il non ha contos ligabile",
+ "cannotlink-no-provider": "Il non ha contos que pote esser ligate.",
+ "linkaccounts": "Ligar contos",
+ "linkaccounts-success-text": "Le conto ha essite ligate.",
+ "linkaccounts-submit": "Ligar contos",
+ "unlinkaccounts": "Disligar contos",
+ "unlinkaccounts-success": "Le conto ha essite disligate."
}
"WongKentir",
"Rachmat.Wahidi",
"Arief",
- "Nemo bis"
+ "Nemo bis",
+ "Mbrt",
+ "Beeyan"
]
},
"tog-underline": "Garis bawahi pranala:",
"tog-watchlisthidebots": "Sembunyikan suntingan bot di daftar pantauan",
"tog-watchlisthideminor": "Sembunyikan suntingan kecil di daftar pantauan",
"tog-watchlisthideliu": "Sembunyikan suntingan pengguna masuk log di daftar pantauan",
- "tog-watchlistreloadautomatically": "Muat ulang daftar pantauan secara otomatis ketika sebuah penyaring berubah (JavaScript diperlukan)",
+ "tog-watchlistreloadautomatically": "Muat ulang daftar pantauan secara otomatis ketika sebuah tapis berubah (JavaScript diperlukan)",
"tog-watchlisthideanons": "Sembunyikan suntingan pengguna anonim di daftar pantauan",
"tog-watchlisthidepatrolled": "Sembunyikan suntingan terpatroli di daftar pantauan",
"tog-watchlisthidecategorization": "Sembunyikan pengategorian halaman",
"password-change-forbidden": "Anda tidak dapat mengubah kata sandi pada wiki ini.",
"externaldberror": "Telah terjadi kesalahan otentikasi basis data eksternal atau Anda tidak diizinkan melakukan kemaskini terhadap akun eksternal Anda.",
"login": "Masuk log",
+ "login-security": "Buktikan identitas Anda",
"nav-login-createaccount": "Masuk log / buat akun",
"userlogin": "Masuk log / buat akun",
"userloginnocreate": "Masuk log",
"userlogin-resetpassword-link": "Lupa kata sandi?",
"userlogin-helplink2": "Bantuan masuk log",
"userlogin-loggedin": "Andan telah masuk log sebagai $1.\nGunakan formulir di bawah untuk masuk log sebagai pengguna lain.",
+ "userlogin-reauth": "Anda harus masuk log lagi untuk memeriksa bahwa Anda adalah {{GENDER:$1|$1}}",
"userlogin-createanother": "Buat akun lain",
"createacct-emailrequired": "Alamat surel",
"createacct-emailoptional": "Alamat surel/email (sebaiknya diisi)",
"createacct-email-ph": "Masukkan alamat surel Anda",
"createacct-another-email-ph": "Masukkan alamat surel",
"createaccountmail": "Gunakan kata sandi acak sementara dan kirimkan ke surel yang diinginkan",
+ "createaccountmail-help": "Dapat digunakan untuk membuat akun untuk orang lain tanpa mengetahui kata sandinya.",
"createacct-realname": "Nama asli (opsional)",
"createaccountreason": "Alasan:",
"createacct-reason": "Alasan",
"createacct-reason-ph": "Mengapa Anda membuat akun lain",
+ "createacct-reason-help": "Pesan yang ditunjukkan dalam log pembuatan akun",
"createacct-submit": "Buat akun Anda",
"createacct-another-submit": "Buat akun",
+ "createacct-continue-submit": "Lanjutkan pembuatan akun",
+ "createacct-another-continue-submit": "Lanjutkan pembuatan akun",
"createacct-benefit-heading": "{{SITENAME}} dibuat oleh orang-orang seperti Anda.",
"createacct-benefit-body1": "{{PLURAL:$1|suntingan}}",
"createacct-benefit-body2": "{{PLURAL:$1|halaman}}",
"nocookieslogin": "{{SITENAME}} menggunakan kuki untuk log penggunanya. Kuki pada peramban web Anda dimatikan. Silakan aktifkan dan coba lagi.",
"nocookiesfornew": "Akun pengguna tidak dibuat karena kami tidak dapat memastikan sumbernya.\nPastikan Anda telah mengaktifkan kuki, lalu muat ulang halaman ini dan coba lagi.",
"nocookiesforlogin": "{{int:nocookieslogin}}",
+ "createacct-loginerror": "Akun telah berhasil dibuat, namun Anda tidak dapat langsung masuk log secara otomatis. Silakan meneruskan ke [[Special:UserLogin|masuk log manual]].",
"noname": "Nama pengguna yang Anda masukkan tidak sah.",
"loginsuccesstitle": "Berhasil masuk log",
"loginsuccess": "'''Anda sekarang masuk log di {{SITENAME}} sebagai \"$1\".'''",
- "nosuchuser": "Tidak ada pengguna dengan nama \"$1\".\nNama pengguna membedakan kapitalisasi.\nPeriksa kembali ejaan Anda, atau [[Special:UserLogin/signup|buat akun baru]].",
+ "nosuchuser": "Tidak ada pengguna dengan nama \"$1\".\nNama pengguna membedakan kapitalisasi.\nPeriksa kembali ejaan Anda, atau [[Special:CreateAccount|buat akun baru]].",
"nosuchusershort": "Tidak ada pengguna dengan nama \"$1\".\nSilakan periksa kembali ejaan Anda.",
"nouserspecified": "Anda harus memasukkan nama pengguna.",
"login-userblocked": "Pengguna ini diblokir. Tidak diizinkan/diperbolehkan untuk masuk log.",
"createacct-another-realname-tip": "Nama asli bersifat opsional.\nJika Anda memberikannya, nama asli Anda akan digunakan untuk memberi pengenalan atas hasil kerja Anda.",
"pt-login": "Masuk log",
"pt-login-button": "Masuk log",
+ "pt-login-continue-button": "Lanjutkan masuk log",
"pt-createaccount": "Buat akun baru",
"pt-userlogout": "Keluar log",
"php-mail-error-unknown": "Kesalahan yang tidak dikenal dalam fungsi mail() PHP",
"changepassword-success": "Kata sandi Anda telah diubah!",
"changepassword-throttled": "Anda terlalu sering mencoba masuk log.\nMohon tunggu $1 sebelum mencoba lagi.",
"botpasswords": "Kata sandi bot",
+ "botpasswords-summary": "<em>Kata sandi bot</em> memungkinkan akses ke akun pengguna menggunakan API tanpa menggunakan kredensial masuk log utama akun tersebut. Hak pengguna yang tersedia ketika masuk log dengan kata sandi bot mungkin akan dibatasi.\n\nJika Anda tidak tahu kenapa Anda ingin melakukan hal ini, sebaiknya jangan lakukan. Semestinya tidak ada orang lain yang boleh meminta Anda untuk menciptakan dan menyerahkan kata sandi bot ini kepadanya.",
"botpasswords-disabled": "Kata sandi bot dinonaktifkan.",
"botpasswords-no-central-id": "Untuk menggunakan kata sandi bot, Anda harus masuk log ke akun yang telah tersentralisasi.",
"botpasswords-existing": "Kata sandi bot tersedia",
"botpasswords-label-delete": "Hapus",
"botpasswords-label-resetpassword": "Setel ulang kata sandi",
"botpasswords-label-grants": "Akses yang dapat diberikan:",
+ "botpasswords-help-grants": "Tiap izin memberikan akses ke hak-hak pengguna yang telah dimiliki suatu akun pengguna. Lihat [[Special:ListGrants|tabel izin]] untuk informasi lebih lanjut.",
"botpasswords-label-restrictions": "Batasan penggunaan:",
"botpasswords-label-grants-column": "Izin diberikan",
"botpasswords-bad-appid": "Nama bot \"$1\" tidak valid.",
"botpasswords-insert-failed": "Gagal menambah nama bot \"$1\". Apakah sudah ditambahkan sebelum ini?",
"botpasswords-update-failed": "Gagal memperbarui nama bot \"$1\". Apakah sebelumnya sudah pernah dihapus?",
"botpasswords-created-title": "Kata sandi bot dibuat",
- "botpasswords-created-body": "Kata sandi bot \"$1\" sukses dibuat.",
+ "botpasswords-created-body": "Kata sandi bot \"$1\" dari pengguna \"$2\" berhasil dibuat.",
"botpasswords-updated-title": "Kata sandi bot diperbarui",
- "botpasswords-updated-body": "Kata sandi bot \"$1\" sukses diperbarui.",
+ "botpasswords-updated-body": "Kata sandi bot \"$1\" dari pengguna \"$2\" berhasil diperbarui.",
"botpasswords-deleted-title": "Kata sandi bot dihapus",
- "botpasswords-deleted-body": "Kata sandi bot \"$1\" telah dihapus.",
+ "botpasswords-deleted-body": "Kata sandi bot \"$1\" dari pengguna \"$2\" telah dihapus.",
"botpasswords-newpassword": "Kata sandi baru untuk masuk log dengan '''$1''' adalah '''$2'''. ''Mohon simpan untuk referensi di kemudian hari.''",
"botpasswords-no-provider": "BotPasswordsSessionProvider tidak tersedia.",
"botpasswords-restriction-failed": "Batasan kata sandi menghalangi masuk log ini.",
"botpasswords-invalid-name": "Nama pengguna yang diberikan tidak mengandung pemisah kata sandi bot (\"$1\").",
"botpasswords-not-exist": "Pengguna \"$1\" tidak memiliki kata sandi bot bernama \"$2\".",
"resetpass_forbidden": "Kata sandi tidak dapat diubah",
+ "resetpass_forbidden-reason": "Kata sandi tidak dapat dubah: $1",
"resetpass-no-info": "Anda harus masuk log untuk mengakses halaman ini secara langsung.",
"resetpass-submit-loggedin": "Ganti kata sandi",
"resetpass-submit-cancel": "Batalkan",
- "resetpass-wrong-oldpass": "Kata sandi tidak sah.\nAnda mungkin telah berhasil mengganti kata sandi Anda atau telah meminta kata sandi sementara yang baru.",
+ "resetpass-wrong-oldpass": "Kata sandi tidak sah.\nAnda mungkin telah mengganti kata sandi Anda atau telah meminta kata sandi sementara yang baru.",
"resetpass-recycled": "Mohon menyetel ulang kata sandi Anda ke sesuatu yang berbeda dari kata sandi Anda sekarang.",
"resetpass-temp-emailed": "Anda masuk log dengan kode sementara yang disurel.\nUntuk menyelesaikan masuk log, Anda harus mengatur sandi baru di sini:",
"resetpass-temp-password": "Kata sandi sementara:",
"passwordreset-emailsentusername": "Jika ada alamat surel yang berkaitan dengan nama pengguna ini, maka surel untuk menyetel ulang kata sandi akan dikirim.",
"passwordreset-emailsent-capture": "Surel setel ulang kata sandi telah dikirim, yang ditampilkan di bawah.",
"passwordreset-emailerror-capture": "Surel setel ulang kata sandi telah dibuat, yang ditampilkan di bawah, namun pengiriman pada {{GENDER:$2|pengguna}} gagal: $1",
+ "passwordreset-emailsent-capture2": "Pemulihan kata sandi {{PLURAL:$1|surel|surel}} telah dikirim. {{PLURAL:$1|Nama pengguna dan kata sandi|Daftar nama pengguna dan kata sandi}} ditampilkan di bawah.",
+ "passwordreset-emailerror-capture2": "Pengiriman surel kepada {{GENDER:$2|pengguna}} gagal: $1 {{PLURAL:$3|Nama pengguna dan kata sandi|Daftar nama pengguna dan kata sandi}} ditampilkan di bawah.",
+ "passwordreset-nocaller": "Pemanggil harus diberikan",
+ "passwordreset-nosuchcaller": "Pemanggil tidak ada: $1",
+ "passwordreset-ignored": "Pemulihan kata sandi tidak tertangani. Mungkin penyedia tidak diatur?",
+ "passwordreset-invalideamil": "Alamat surel tidak sah",
+ "passwordreset-nodata": "Nama pengguna ataupun alamat surel tidak diberikan",
"changeemail": "Ubah atau hapus alamat surel",
"changeemail-header": "Lengkapi formulir ini untuk mengubah alamat surel Anda. Jika Anda ingin menghapus seluruh alamat surel yang berkaitan dengan akun Anda, kosongkan alamat surel ketika mengirim formulir.",
"changeemail-passwordrequired": "Anda diharuskan memasukkan kata sandi untuk mengonfirmasikan perubahan ini.",
"minoredit": "Ini adalah suntingan kecil.",
"watchthis": "Pantau halaman ini",
"savearticle": "Simpan halaman",
+ "publishpage": "Terbitkan halaman",
"preview": "Pratayang",
"showpreview": "Lihat pratayang",
"showdiff": "Lihat perubahan",
"accmailtext": "Sebuah kata sandi acak untuk [[User talk:$1|$1]] telah dikirimkan ke $2.\n\nKata sandi untuk akun baru ini dapat diubah di halaman ''[[Special:ChangePassword|pengubahan kata sandi]]'' setelah masuk log.",
"newarticle": "(Baru)",
"newarticletext": "Anda mengikuti pranala ke halaman yang belum tersedia. Untuk membuat halaman tersebut, ketiklah isi halaman di kotak di bawah ini (lihat [$1 halaman bantuan] untuk informasi lebih lanjut). Jika Anda tanpa sengaja sampai ke halaman ini, klik tombol '''back''' di penjelajah web Anda.",
- "anontalkpagetext": "----''Ini adalah halaman pembicaraan seorang pengguna anonim yang belum membuat akun atau tidak menggunakannya.\nDengan demikian, kami terpaksa harus memakai alamat IP yang bersangkutan untuk mengidentifikasikannya.\nAlamat IP seperti ini mungkin dipakai bersama oleh beberapa pengguna yang berbeda.\nJika Anda adalah seorang pengguna anonim dan merasa mendapatkan komentar-komentar yang tidak relevan yang ditujukan langsung kepada Anda, silakan [[Special:UserLogin/signup|membuat akun]] atau [[Special:UserLogin|masuk log]] untuk menghindari kerancuan dengan pengguna anonim lainnya di lain waktu.''",
+ "anontalkpagetext": "----''Ini adalah halaman pembicaraan seorang pengguna anonim yang belum membuat akun atau tidak menggunakannya.\nDengan demikian, kami terpaksa harus memakai alamat IP yang bersangkutan untuk mengidentifikasikannya.\nAlamat IP seperti ini mungkin dipakai bersama oleh beberapa pengguna yang berbeda.\nJika Anda adalah seorang pengguna anonim dan merasa mendapatkan komentar-komentar yang tidak relevan yang ditujukan langsung kepada Anda, silakan [[Special:CreateAccount|membuat akun]] atau [[Special:UserLogin|masuk log]] untuk menghindari kerancuan dengan pengguna anonim lainnya di lain waktu.''",
"noarticletext": "Saat ini tidak ada teks di halaman ini.\nAnda dapat [[Special:Search/{{PAGENAME}}|melakukan pencarian untuk judul halaman ini]] di halaman-halaman lain, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mencari log terkait], atau [{{fullurl:{{FULLPAGENAME}}|action=edit}} membuat halaman ini]</span>.",
"noarticletext-nopermission": "!Saat ini tidak ada teks di halaman ini.\nAnda dapat [[Special:Search/{{PAGENAME}}|melakukan pencarian untuk judul halaman ini]] di halaman-halaman lain, atau <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mencari log terkait]</span>, tapi Anda tidak memiliki izin untuk membuat halaman ini",
"missing-revision": "Revisi #$1 halaman berjudul \"{{FULLPAGENAME}}\" tidak eksis.\n\nHal ini biasanya disebabkan oleh tautan versi terdahulu menuju halaman yang sudah dihapus.\nRinciannya dapat ditemukan di [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log penghapusan].",
"userpage-userdoesnotexist": "Akun pengguna \"<nowiki>$1</nowiki>\" tidak terdaftar.",
"userpage-userdoesnotexist-view": "Pengguna \"$1\" tidak terdaftar.",
"blocked-notice-logextract": "Pengguna ini sedang diblokir.\nEntri log pemblokiran terakhir tersedia di bawah ini sebagai rujukan:",
- "clearyourcache": "'''Catatan:''' Setelah menyimpan, Anda mungkin harus memintas singgahan peramban Anda untuk melihat perubahan.\n* '''Firefox / Safari:''' Tahan ''Shift'' sambil mengeklik ''Reload'', atau tekan ''Ctrl-F5'' atau ''Ctrl-R'' (''⌘-R'' di Mac)\n* '''Google Chrome:''' Tekan ''Ctrl-Shift-R'' (''⌘-Shift-R'' di Mac)\n* '''Internet Explorer:''' Tahan ''Ctrl'' sambl mengeklik ''Refresh'', atau tekan ''Ctrl-F5''\n* '''Opera:''' Bersihkan tembolok di ''Tools → Preferences''",
+ "clearyourcache": "<strong>Catatan:</strong>Setelah disimpan, Anda mungkin perlu melewati tembolok peramban web untuk melihat perubahan.\n* <strong>Firefox/Safari:</strong> Tahan <em>Shift</em> ketika diklik <em>Reload</em>, atau tekan <em>Ctrl-F5</em> atau <em>Ctrl-R</em> (<em>⌘-R</em> di Mac)\n* <strong>Google Chrome:</strong> Tekan <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> di Mac)\n* <strong>Internet Explorer:</strong> Tekan <em>Ctrl</em> ketika diklik <em>Refresh</em>, atau tekan <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Pergi ke <em>Menu → Settings </em> (<em>Opera → Preferences</em> di Mac) lalu ke <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
"usercssyoucanpreview": "'''Tips:''' Gunakan tombol \"{{int:showpreview}}\" untuk menguji CSS baru Anda sebelum menyimpannya.",
"userjsyoucanpreview": "'''Tips:''' Gunakan tombol \"{{int:showpreview}}\" untuk menguji JS baru Anda sebelum menyimpannya.",
"usercsspreview": "'''Ingatlah bahwa Anda sedang menampilkan pratayang dari CSS Anda.\nPratayang ini belum disimpan!'''",
"userrights-unchangeable-col": "Kelompok yang tidak dapat Anda ubah",
"userrights-irreversible-marker": "$1*",
"userrights-conflict": "Konflik perubahan hak pengguna! Silakan tinjau ulang dan konfirmasi perubahan Anda.",
- "userrights-removed-self": "Anda berhasil mencabut hak-hak Anda. Anda tidak bisa lagi mengakses halaman ini.",
+ "userrights-removed-self": "Anda telah mencabut hak-hak Anda sendiri. Anda tidak bisa lagi mengakses halaman ini.",
"group": "Kelompok:",
"group-user": "Pengguna",
"group-autoconfirmed": "Pengguna terkonfirmasi otomatis",
"right-override-export-depth": "Ekspor halaman termasuk halaman-halaman terkait hingga kedalaman 5",
"right-sendemail": "Mengirim surel ke pengguna lain",
"right-passwordreset": "Lihat surel pengaturulangan kata sandi",
- "right-managechangetags": "Membuat dan menghapus [[Special:Tags|tag]] dari basis data",
+ "right-managechangetags": "Buat dan matikan [[Special:Tags|tag]]",
"right-applychangetags": "Terapkan [[Special:Tags|tags]] bersamaan dengan perubahan pengguna",
+ "right-changetags": "Tambah dan hapus [[Special:Tags|tag]] arbitrari pada revisi masing-masing dan entri log",
+ "right-deletechangetags": "Hapus [[Special:Tags|tag]] dari basisdata",
"grant-generic": "\"$1\" bundel hak akses",
"grant-group-page-interaction": "Berinteraksi dengan halaman",
"grant-group-file-interaction": "Berinteraksi dengan media",
"action-viewmyprivateinfo": "lihat informasi pribadi Anda",
"action-editmyprivateinfo": "sunting informasi pribadi Anda",
"action-editcontentmodel": "mengedit model konten sebuah halaman",
- "action-managechangetags": "Membuat dan menghapus tag dari basis data",
+ "action-managechangetags": "buat dan matikan tag",
"action-applychangetags": "terapkan tag bersamaan dengan perubahan Anda",
"action-changetags": "menambah dan menghapus tag semaunya pada revisi individu dan entri log",
+ "action-deletechangetags": "hapus tag dari basis data",
"nchanges": "$1 {{PLURAL:$1|perubahan|perubahan}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sejak kunjungan terakhir}}",
"enhancedrc-history": "riwayat",
"recentchangeslinked-page": "Nama halaman:",
"recentchangeslinked-to": "Perlihatkan perubahan dari halaman-halaman yang terhubung dengan halaman yang disajikan",
"recentchanges-page-added-to-category": "[[:$1]] ditambahkan pada kategori",
- "recentchanges-page-added-to-category-bundled": "[[:$1]] dan [[Special:WhatLinksHere/$1|{{PLURAL:$2|satu halaman|$2 halaman-halaman}}]] lagi halaman ditambahkan pada kategori",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] ditambahkan ke dalam kategori, [[Special:WhatLinksHere/$1|halaman ini dimasukkan bersama-sama halaman lain]]",
"recentchanges-page-removed-from-category": "[[:$1]] dihapus dari kategori",
- "recentchanges-page-removed-from-category-bundled": "[[:$1]] dan {{PLURAL:$2|satu halaman|$2 halaman-halaman}} lagi halaman dihapus dari kategori",
+ "recentchanges-page-removed-from-category-bundled": "[[:$1]] dihapus dari kategori, [[Special:WhatLinksHere/$1|halaman ini dimasukkan bersama halaman lain]]",
"autochange-username": "Perubahan otomatis MediaWiki",
"upload": "Pengunggahan berkas",
"uploadbtn": "Muatkan berkas",
"uploaded-script-svg": "Terdapat elemen terskrip \"$1\" dalam berkas SVG yang diunggah.",
"uploaded-hostile-svg": "Terdapat CSS yang tidak aman dalam elemen gaya berkas SVG yang diunggah.",
"uploaded-event-handler-on-svg": "Penetapan atribut <i>event-handler</i> $1=\"$2\" tidak diizinkan dalam berkas SVG.",
+ "uploaded-href-attribute-svg": "Atribut href pada berkas SVG hanya dibolehkan untuk ditautkan ke target http:// atau https://, ditemukan <code><$1 $2=\"$3\"></code>.",
+ "uploaded-href-unsafe-target-svg": "Menemukan href ke data tidak aman: URI menarget <code><$1 $2=\"$3\"></code> dalam berkas SVG yang diunggah.",
+ "uploaded-animate-svg": "Ditemukan tag \"animasi\" yang mungkin dapat mengubah href, menggunakan atribut \"from\" <code><$1 $2=\"$3\"></code> dalam berkas SVG yang diunggah.",
"uploaded-setting-event-handler-svg": "Penyetelan atribut event-handler diblokir, menemukan <code><$1 $2=\"$3\"></code> dalam berkas SVG yang diunggah.",
+ "uploaded-setting-href-svg": "Menggunakan tag \"set\" untuk menambahkan atribut \"href\" ke elemen utama diblokir.",
"uploadscriptednamespace": "Berkas SVG ini memuat ruang nama ilegal \"$1\"",
"uploadinvalidxml": "XML dalam berkas yang diunggah tidak bisa diuraikan.",
"uploadvirus": "Berkas tersebut mengandung virus! Rincian: $1",
"upload-options": "Opsi pengunggahan",
"watchthisupload": "Pantau berkas ini",
"filewasdeleted": "Suatu berkas dengan nama ini pernah dimuat dan selanjutnya dihapus. Harap cek $1 sebelum memuat lagi berkas tersebut.",
+ "filename-thumb-name": "Tampaknya ini adalah judul gambar mini. Mohon jangan mengunggah gambar mini kembali ke wiki yang sama. Bila tidak, silakan perbaiki nama berkas sehingga lebih bermakna, dan tidak memiliki awalan seperti judul gambar mini.",
"filename-bad-prefix": "Nama berkas yang Anda muat diawali dengan '''\"$1\"''', yang merupakan nama non-deskriptif yang biasanya diberikan secara otomatis oleh kamera digital. Harap pilih nama lain yang lebih deskriptif untuk berkas Anda.",
"filename-prefix-blacklist": " #<!-- biarkan baris ini seperti adanya --> <pre>\n# Contohnya sebagai berikut:\n# * Semuanya dari karekter \"#\" sampai akhir baris ini adalah komentar\n# * Setiap garis \"_\" adalah awalan untuk nama file khas yang diberikan secara otomatis oleh kamera digital\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # beberapa model telpon seluler\nIMG # generik\nJD # Jenoptik\nMGP # Pentax\nPICT # lainnya.\n #</pre> <!-- biarkan baris ini seperti adanya -->",
"upload-proto-error": "Protokol tak tepat",
"upload-too-many-redirects": "URL mengandung terlalu banyak pengalihan",
"upload-http-error": "Kesalahan HTTP terjadi: $1",
"upload-copy-upload-invalid-domain": "Unggahan salinan tidak tersedia dari domain ini.",
+ "upload-foreign-cant-upload": "Wiki ini tidak diatur untuk mengunggah berkas ke gudang penyimpangan asing.",
"upload-dialog-title": "Unggah berkas",
"upload-dialog-button-cancel": "Batalkan",
"upload-dialog-button-done": "Selesai",
"upload-form-label-own-work": "Ini adalah karya saya sendiri",
"upload-form-label-infoform-categories": "Kategori",
"upload-form-label-infoform-date": "Tanggal",
+ "upload-form-label-own-work-message-generic-local": "Saya menyatakan bahwa saya mengunggah berkas ini dengan mengikuti syarat layanan dan aturan lisensi di {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Jika Anda tidak dapat mengunggah berkas ini di bawah kebijakan {{SITENAME}}, silakan tutup dialog ini dan cobalah metode lainnya.",
+ "upload-form-label-not-own-work-local-generic-local": "Anda mungkin ingin mencoba [[Special:Upload|halaman pengunggahan baku]].",
+ "upload-form-label-own-work-message-generic-foreign": "Saya mengerti bahwa saya mengunggah berkas ini ke gudang berkas bersama. Saya menyatakan bahwa saya telah menyetujui syarat layanan dan kebijakan lisensi di sana.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Jika Anda tidak dapat mengunggah berkas ini di bawah kebijakan di gudang penyimpanan bersama, silakan tutup dialog ini dan cobalah metode lainnya.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Anda juga mungkin ingin mencoba menggunakan [[Special:Upload|halaman pengunggahan di {{SITENAME}}]], jika situs tersebut mengizinkan pengunggahan berkas ini menurut kebijakan di situs tersebut.",
"backend-fail-stream": "Tidak bisa mengalikan berkas $1.",
"backend-fail-backup": "Tidak dapat mencadangkan berkas $1.",
"backend-fail-notexists": "Berkas $1 tidak ada.",
"uploadstash-summary": "Halaman ini memberikan akses terhadap berkas yang diunggah (atau dalam proses pengunggahan), namun belum diterbitkan ke wiki. Berkas-berkas ini tidak dapat dilihat oleh siapa pun kecuali pengunggahnya.",
"uploadstash-clear": "Hapus berkas simpanan",
"uploadstash-nofiles": "Anda tidak memiliki berkas simpanan.",
- "uploadstash-badtoken": "Pelaksanaan tindakan tersebut gagal. Mungkin karena hak penyuntingan Anda telah kedaluwarsa. Coba lagi.",
+ "uploadstash-badtoken": "Pelaksanaan tindakan tersebut gagal. Mungkin karena hak penyuntingan Anda telah kedaluwarsa. Silakan coba lagi.",
"uploadstash-errclear": "Penghapusan berkas gagal.",
"uploadstash-refresh": "Segarkan daftar berkas.",
+ "uploadstash-thumbnail": "lihat miniatur",
"invalid-chunk-offset": "Ofset potongan tidak valid",
"img-auth-accessdenied": "Akses ditolak",
"img-auth-nopathinfo": "PATH_INFO hilang.\nServer Anda tidak diatur untuk melewatkan informasi ini.\nServer tersebut mungkin berbasis CGI dan tidak dapat mendukung img_auth.\nLihat https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
"apisandbox": "Bak pasir API",
"apisandbox-jsonly": "JavaScript dibutuhkan untuk menggunakan kotak pasir API.",
"apisandbox-api-disabled": "API dinonaktifkan pada situs ini.",
- "apisandbox-intro": "Gunakan halaman ini untuk bereksperimen dengan '''API layanan web MediaWiki'''.\nLihat [//www.mediawiki.org/wiki/API:Main_page dokumentasi API] untuk perincian lanjut penggunaan API. Contoh: [//www.mediawiki.org/wiki/API#A_simple_example dapatkan konten Halaman Utama]. Pilih sebuah tindakan untuk melihat contoh lain.\n\nPerhatikan bahwa, meskipun ini adalah bak pasir, tindakan yang Anda lakukan pada halaman ini mungkin dapat mengubah wiki.",
+ "apisandbox-intro": "Gunakan halaman ini untuk bereksperimen dengan <strong>API layanan web MediaWiki</strong>.\nLihat [[mw:API:Main page|dokumentasi API]] untuk perincian lanjut penggunaan API. Contoh: [//www.mediawiki.org/wiki/API#A_simple_example dapatkan konten Halaman Utama]. Pilih sebuah tindakan untuk melihat contoh lain.\n\nPerhatikan bahwa, meskipun ini adalah bak pasir, tindakan yang Anda lakukan pada halaman ini mungkin dapat mengubah wiki.",
"apisandbox-fullscreen": "Kembangkan panel",
"apisandbox-fullscreen-tooltip": "Kembangkan panel kotak pasir untuk mengisi jendela peramban.",
"apisandbox-unfullscreen": "Tampilkan halaman",
"listgrouprights-namespaceprotection-namespace": "Ruang nama",
"listgrouprights-namespaceprotection-restrictedto": "Hak yang mengizinkan pengguna untuk menyunting",
"listgrants": "Izin",
+ "listgrants-summary": "Berikut ini adalah daftar hak dengan akses terkait kepada hak penggunanya. Pengguna dapat mengizinkan aplikasi untuk menggunakan akun mereka, namun dengan izin terbatas berdasarkan hak yang diberikan oleh pengguna. Aplikasi yang berjalan yang mewakili seorang pengguna tidak dapat menggunakan hak yang tidak dimiliki oleh pengguna tersebut.\nMungkin nanti terdapat [[{{MediaWiki:Listgrouprights-helppage}}|informasi tambahan]] mengenai hak-hak individual.",
"listgrants-grant": "Izin",
"listgrants-rights": "Hak",
"trackingcategories": "Kategori pelacak",
"trackingcategories-msg": "Kategori pelacak",
"trackingcategories-name": "Nama pesan",
"trackingcategories-desc": "Kriteria inklusi kategori",
+ "restricted-displaytitle-ignored": "Halaman-halaman dengan pengabaian tampilan judul",
+ "restricted-displaytitle-ignored-desc": "Halaman ini memiliki pengabaian <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> karena tidak sesuai dengan judul halaman aslinya.",
"noindex-category-desc": "Halaman tidak diindeks oleh robot karena ini mempunyai kata khusus <code><nowiki>__NOINDEX__</nowiki></code> padanya dan berada dalam ruang nama yang mengizinkan penanda itu.",
"index-category-desc": "Halaman ini memiliki <code><nowiki>__INDEX__</nowiki></code> di atasnya (dan dalam ruang nama yang mana bendera yang diperbolehkan), dan karenanya diindeks oleh robot di mana itu biasanya tidak akan.",
"post-expand-template-inclusion-category-desc": "Ukuran laman lebih besar dari <code>$wgMaxArticleSize</code> setelah memperluas semua templat, sehingga beberapa templat tidak diperluas.",
"rollbacklinkcount": "kembalikan $1 {{PLURAL:$1|suntingan}}",
"rollbacklinkcount-morethan": "kembalikan lebih dari $1 {{PLURAL:$1|suntingan|suntingan}}",
"rollbackfailed": "Pengembalian gagal dilakukan",
+ "rollback-missingparam": "Parameter dibutuhkan ketika diminta tidak tersedia.",
"cantrollback": "Tidak dapat membatalkan suntingan;\nkontributor terakhir adalah satu-satunya penulis halaman ini.",
"alreadyrolled": "Tidak dapat melakukan pengembalian ke revisi terakhir [[:$1]] oleh [[User:$2|$2]] ([[User talk:$2|bicara]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\npengguna lain telah menyunting atau melakukan pengembalian terhadap halaman ini.\n\nSuntingan terakhir dilakukan oleh [[User:$3|$3]] ([[User talk:$3|bicara]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "Komentar penyuntingan adalah: <em>$1</em>.",
"revertpage": "←Suntingan [[Special:Contributions/$2|$2]] ([[User talk:$2|bicara]]) dibatalkan ke versi terakhir oleh [[User:$1|$1]]",
"revertpage-nouser": "Mengembalikan suntingan oleh (nama pengguna dihapus) ke suntingan terakhir oleh [[User:$1|$1]]",
"rollback-success": "Pembatalan suntingan oleh $1; dibatalkan ke versi terakhir oleh $2.",
+ "rollback-success-notify": "Mengembalikan suntingan oleh $1; rubah kembali untuk revisi terakhir oleh $2. [$3 Lihat perubahan]",
"sessionfailure-title": "Kegagalan sesi",
"sessionfailure": "Sepertinya ada masalah dengan sesi log Anda; log Anda telah dibatalkan untuk mencegah pembajakan. Silakan tekan tombol \"kembali\" dan muat kembali halaman sebelum Anda masuk, lalu coba lagi.",
"changecontentmodel": "Ubah model isi sebuah halaman",
"changecontentmodel-title-label": "Judul halaman",
"changecontentmodel-model-label": "Model konten baru",
"changecontentmodel-reason-label": "Alasan:",
+ "changecontentmodel-submit": "Ubah",
"changecontentmodel-success-title": "Model konten ini telah diubah",
"changecontentmodel-success-text": "Jenis konten [[:$1]] telah diubah",
"changecontentmodel-cannot-convert": "Isi pada [[:$1]] tidak dapat ditukar kepada jenis $2.",
"changecontentmodel-nodirectediting": "Model isi $1 tidak mendukung suntingan langsung",
+ "changecontentmodel-emptymodels-title": "Tidak tersedia model konten",
+ "changecontentmodel-emptymodels-text": "Konten dalam [[:$1]] tidak dapat diubah ke dalam jenis lain.",
"log-name-contentmodel": "Log perubahan model konten",
"log-description-contentmodel": "Peristiwa terkait model konten sebuah halaman",
+ "logentry-contentmodel-new": "$1 {{GENDER:$2|membuat}} halaman $3 menggunakan model konten tak baku \"$5\"",
"logentry-contentmodel-change": "$1 {{GENDER:$2|mengubah}} model konten halaman $3 dari \"$4\" ke \"$5\"",
"logentry-contentmodel-change-revertlink": "batalkan",
"logentry-contentmodel-change-revert": "batalkan",
"ipb-unblock": "Hilangkan blokir seorang pengguna atau suatu alamat IP",
"ipb-blocklist": "Lihat blokir yang diterapkan",
"ipb-blocklist-contribs": "Kontribusi untuk {{GENDER:$1|$1}}",
+ "ipb-blocklist-duration-left": "Tersisa $1",
"unblockip": "Buka blokir pengguna",
"unblockiptext": "Gunakan formulir di bawah untuk mengembalikan kemampuan menulis sebuah alamat IP atau pengguna yang sebelumnya telah diblokir.",
"ipusubmit": "Hilangkan blokir ini",
"lockdbsuccesstext": "Basis data telah dikunci.<br />\nPastikan Anda [[Special:UnlockDB|membuka kuncinya]] setelah pemeliharaan selesai.",
"unlockdbsuccesstext": "Kunci basis data telah dibuka.",
"lockfilenotwritable": "Berkas kunci basis data tidak dapat ditulis. Untuk mengunci atau membuka basis data, berkas ini harus dapat ditulis oleh server web.",
+ "databaselocked": "Basis data telah terkunci.",
"databasenotlocked": "Basis data tidak terkunci.",
"lockedbyandtime": "(oleh $1 pada $2 $3)",
"move-page": "Pindahkan $1",
"tooltip-ca-nstab-category": "Lihat halaman kategori",
"tooltip-minoredit": "Tandai ini sebagai suntingan kecil",
"tooltip-save": "Simpan perubahan Anda",
+ "tooltip-publish": "Terbitkan perubahan Anda",
"tooltip-preview": "Pratayang perubahan Anda, harap gunakan ini sebelum menyimpan!",
"tooltip-diff": "Lihat perubahan yang telah Anda lakukan.",
"tooltip-compareselectedversions": "Lihat perbedaan antara dua versi halaman yang dipilih.",
"confirmemail_body_set": "Seseorang, mungkin Anda, dari alamat IP $1,\ntelah mengubah surel dari akun \"$2\" pada alamat ini di {{SITENAME}}.\n\nUntuk mengonfirmasi bahwa akun ini adalah milik Anda sekaligus mengaktifkan\nkembali fitur surel pada {{SITENAME}}, ikuti pranala berikut pada browser Anda:\n\n$3\n\nJika akun ini *bukan* milik Anda, ikuti pranala berikut\nuntuk membatalkan konfirmasi alamat surel:\n\n$5\n\nKode konfirmasi ini akan kedaluwarsa pada $4.",
"confirmemail_invalidated": "Konfirmasi alamat surel dibatalkan",
"invalidateemail": "Batalkan konfirmasi surel",
+ "notificationemail_subject_changed": "Alamat surel terdaftar {{SITENAME}} telah diganti",
+ "notificationemail_subject_removed": "Alamat surel terdaftar {{SITENAME}} telah dihapus",
+ "notificationemail_body_changed": "Seseorang, mungkin Anda, dari alamat IP $1,\ntelah mengganti alamat surel akun \"$2\" menjadi \"$3\" di {{SITENAME}}",
+ "notificationemail_body_removed": "Seseorang, mungkin Anda, dari alamat IP $1,\ntelah menghapus alamat surel akun \"$2\" di {{SITENAME}}.",
"scarytranscludedisabled": "[Transklusi interwiki dimatikan]",
"scarytranscludefailed": "[Pengambilan templat $1 gagal]",
"scarytranscludefailed-httpstatus": "[Pengambilan templat $1 gagal: HTTP $2]",
"confirm-watch-top": "Tambahkan halaman ini ke daftar pantauan Anda?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Hapus halaman ini dari daftar pantauan Anda?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Kembalikan suntingan ke halaman ini?",
"semicolon-separator": "; ",
"comma-separator": ", ",
"colon-separator": ": ",
"watchlistedit-raw-done": "Daftar pantauan Anda telah diperbarui.",
"watchlistedit-raw-added": "{{PLURAL:$1|$1 judul telah}} ditambahkan:",
"watchlistedit-raw-removed": "{{PLURAL:$1|$1 judul telah}} dikeluarkan:",
- "watchlistedit-clear-title": "Daftar pantauan dihapus",
+ "watchlistedit-clear-title": "Hapus daftar pantauan",
"watchlistedit-clear-legend": "Hapus daftar pantauan",
"watchlistedit-clear-explain": "Semua judul akan dihapus dari daftar pantauan Anda",
"watchlistedit-clear-titles": "Judul:",
"timezone-local": "Lokal",
"duplicate-defaultsort": "Peringatan: Kunci pengurutan baku \"$2\" mengabaikan kunci pengurutan baku \"$1\" sebelumnya.",
"duplicate-displaytitle": "<strong>Peringatan:</strong> Menampilkan judul \"$2\" menimpa judul tampilan \"$1\" sebelumnya.",
+ "restricted-displaytitle": "<strong>Perhatian:</strong> Tampilan judul \"$1\" diabaikan karena tidak sesuai dengan judul halaman asli.",
"invalid-indicator-name": "'''Galat:''' Atribut ''nama'' indikator status halaman tidak boleh kosong.",
"version": "Versi",
"version-extensions": "Ekstensi terinstal",
"tags-create-invalid-chars": "Nama tag tidak boleh mengandung koma (<code>,</code>) atau garis miring (<code>/</code>).",
"tags-create-invalid-title-chars": "Nama tag tidak boleh mengandung karakter yang tidak bisa digunakan dalam judul halaman.",
"tags-create-already-exists": "Tag \"$1\" sudah ada.",
+ "tags-create-warnings-above": "{{PLURAL:$2|Peringatan|Peringatan}} berikut ditemukan ketika mencoba membuat tag \"$1\":",
+ "tags-create-warnings-below": "Apakah Anda ingin melanjutkan pembuatan tanda ini?",
+ "tags-delete-title": "Hapus tag",
+ "tags-delete-explanation-initial": "Anda akan menghapus tag \"$1\" dari basisdata.",
"tags-delete-reason": "Alasan:",
"tags-activate-reason": "Alasan:",
"tags-activate-submit": "Aktifkan",
"logentry-protect-move_prot": "$1 {{GENDER:$2|memindahkan}} setelan perlindungan dari $4 ke $3",
"logentry-protect-protect": "$1 {{GENDER:$2|melindungi}} $3 $4",
"logentry-protect-modify": "$1 {{GENDER:$2|mengubah}} tingkat perlindungan untuk $3 $4",
- "logentry-rights-rights": "$1 {{GENDER:$2|mengubah}} keanggotaan grup $3 dari $4 menjadi $5",
+ "logentry-rights-rights": "$1 {{GENDER:$2|mengubah}} keanggotaan grup {{GENDER:$6|$3}} dari $4 ke $5",
"logentry-rights-rights-legacy": "$1 {{GENDER:$2|mengubah}} keanggotaan grup $3",
"logentry-rights-autopromote": "$1 secara otomatis {{GENDER:$2|dipromosikan}} dari $4 menjadi $5",
"logentry-upload-upload": "$1 {{GENDER:$2|mengunggah}} $3",
"feedback-bugornote": "Jika Anda sudah siap untuk mendeskripsikan masalah teknis secara rinci silakan [$1 melaporkan bug].\nJika tidak, Anda dapat menggunakan formulir mudah di bawah ini. Komentar Anda akan ditambahkan ke halaman \"[$3 $2]\", bersama dengan nama pengguna Anda dan apa browser yang Anda gunakan.",
"feedback-cancel": "Batal",
"feedback-close": "Selesai",
+ "feedback-dialog-title": "Kirimkan saran dan tanggapan",
+ "feedback-dialog-intro": "Anda bisa menggunakan formulir sederhana di bawah untuk mengirimkan saran dan masukan. Komentar Anda akan ditambahkan pada laman \"$1\" bersama nama pengguna Anda.",
"feedback-error-title": "Kesalahan",
"feedback-error1": "Galat: Hasil tidak dikenal dari API",
"feedback-error2": "Galat: Penyuntingan gagal",
"feedback-thanks-title": "Terima kasih!",
"searchsuggest-search": "Cari",
"searchsuggest-containing": "berisi...",
+ "api-error-autoblocked": "Alamat IP Anda telah diblokir secara otomatis, karena sebelumnya digunakan oleh pengguna yang diblokir.",
"api-error-badaccess-groups": "Anda tidak diizinkan mengunggah berkas ke wiki ini.",
"api-error-badtoken": "Kesalahan internal: token buruk.",
+ "api-error-blocked": "Anda telah diblokir dari penyuntingan.",
"api-error-copyuploaddisabled": "Mengunggah melalui URL dilarang pada peladen ini.",
"api-error-duplicate": "Sudah ada {{PLURAL:$1|berkas lain|berkas lain}} dengan isi yang sama di situs ini.",
"api-error-duplicate-archive": "Ada {{PLURAL:$1|berkas lain|berkas lain}} di situs dengan konten yang sama, namun {{PLURAL:$1|berkas|berkas-berkas}} itu telah dihapus.",
"expand_templates_generate_xml": "Tampilkan pohon parser XML",
"expand_templates_generate_rawhtml": "Tampilkan HTML mentah",
"expand_templates_preview": "Pratayang",
+ "expand_templates_input_missing": "Anda perlu memasukkan paling sedikit beberapa teks masukan.",
"pagelanguage": "Ubah bahasa halaman",
"pagelang-name": "Halaman",
"pagelang-language": "Bahasa",
"pagelang-use-default": "Gunakan bahasa baku",
"pagelang-select-lang": "Pilih bahasa",
+ "pagelang-submit": "Kirim",
"right-pagelang": "Ubah bahasa halaman",
"action-pagelang": "mengubah bahasa halaman",
"log-name-pagelang": "Log perubahan bahasa",
"mediastatistics-header-drawing": "Gambar vektor",
"mediastatistics-header-audio": "Audio",
"mediastatistics-header-video": "Video",
+ "mediastatistics-header-multimedia": "Media kaya",
"mediastatistics-header-office": "Aplikasi Office",
"mediastatistics-header-text": "Tekstual",
"mediastatistics-header-executable": "Program",
"mediastatistics-header-archive": "Format terkompresi",
+ "mediastatistics-header-total": "Semua berkas",
+ "json-warn-trailing-comma": "$1 {{PLURAL:$1|koma|koma}} pengekor telah digugurkan dari JSON",
+ "json-error-unknown": "Ada masalah dengan JSON. Kesalahan: $1",
"json-error-depth": "Kedalaman tumpukan maksimal telah terlewati",
+ "json-error-state-mismatch": "JSON tidak sah atau cacat",
+ "json-error-ctrl-char": "Kesalahan aksara kontrol, mungkin salah dikodkan",
"json-error-syntax": "Kesalahan sintaks",
+ "json-error-utf8": "Aksara UTF-8 cacat, mungkin salah dikodkan",
+ "json-error-recursion": "Setidaknya satu atau lebih referensi rekursif untuk dikodkan di dalam nilai tersebut",
+ "json-error-inf-or-nan": "Setidaknya satu nilai NAN atau INF untuk dikodkan di dalam nilai tersebut",
+ "json-error-unsupported-type": "Sebuah nilai dari tipe yang tidak dapat dikodkan diberikan",
+ "headline-anchor-title": "Pranala ke bagian ini",
"special-characters-group-latin": "Latin",
"special-characters-group-latinextended": "Ekstensi Latin",
"special-characters-group-ipa": "IPA",
"special-characters-group-symbols": "Simbol",
"special-characters-group-greek": "Yunani",
+ "special-characters-group-greekextended": "Latin tambahan",
"special-characters-group-cyrillic": "Sirilik",
"special-characters-group-arabic": "Arab",
"special-characters-group-arabicextended": "Arab tambahan",
"special-characters-title-endash": "en dash",
"special-characters-title-emdash": "em dash",
"special-characters-title-minus": "tanda kurang",
+ "mw-widgets-dateinput-no-date": "Tanggal tidak ada yang terpilih",
"mw-widgets-dateinput-placeholder-day": "TTTT-BB-HH",
"mw-widgets-dateinput-placeholder-month": "TTTT-BB",
+ "mw-widgets-titleinput-description-new-page": "halaman belum ada",
+ "mw-widgets-titleinput-description-redirect": "mengalihkan ke $1",
"api-error-blacklisted": "Pilih judul lain yang deskriptif",
+ "sessionmanager-tie": "Tidak dapat menggabungkan banyak jenis otentikasi permintaan: $1.",
+ "sessionprovider-generic": "sesi $1",
+ "sessionprovider-mediawiki-session-cookiesessionprovider": "sesi berdasarkan kuki",
+ "sessionprovider-nocookies": "Kuki mungkin dimatikan. Pastikan Anda telah mengaktifkan kuki dan coba mulai kembali.",
"randomrootpage": "Halaman dasar sembarang",
"log-action-filter-block": "Jenis pemblokiran:",
+ "log-action-filter-contentmodel": "Jenis modifikasi modelkonten:",
+ "log-action-filter-delete": "Jenis penghapusan:",
+ "log-action-filter-import": "Jenis impor:",
+ "log-action-filter-managetags": "Jenis tindakan manajemen tag:",
+ "log-action-filter-move": "Jenis pemindahan:",
+ "log-action-filter-newusers": "Jenis pembuatan akun:",
+ "log-action-filter-patrol": "Jenis patroli:",
+ "log-action-filter-protect": "Jenis perlindungan:",
+ "log-action-filter-rights": "Jenis penggantian hak",
+ "log-action-filter-suppress": "Jenis penyembunyian",
+ "log-action-filter-upload": "Jenis pengunggahan:",
+ "log-action-filter-all": "Semua",
"log-action-filter-block-block": "Blokir",
- "log-action-filter-suppress-block": "Perahasiaan pengguna menurut pemblokiran"
+ "log-action-filter-block-reblock": "Modifikasi blokir",
+ "log-action-filter-block-unblock": "Batalkan pemblokiran",
+ "log-action-filter-contentmodel-change": "Ubah Modelkonten",
+ "log-action-filter-contentmodel-new": "Pembuatan halaman dengan Modelkonten yang tak baku",
+ "log-action-filter-delete-delete": "Penghapusan halaman",
+ "log-action-filter-delete-restore": "Pembatalan penghapusan halaman",
+ "log-action-filter-delete-event": "Log penghapusan",
+ "log-action-filter-delete-revision": "Penghapusan revisi",
+ "log-action-filter-import-interwiki": "Impor transwiki",
+ "log-action-filter-import-upload": "Impor dengan unggahan XML",
+ "log-action-filter-managetags-create": "Pembuatan tag",
+ "log-action-filter-managetags-delete": "Penghapusan tag",
+ "log-action-filter-managetags-activate": "Pengaktifan tag",
+ "log-action-filter-managetags-deactivate": "Penonaktifan tag",
+ "log-action-filter-move-move": "Pindahkan tanpa menimpa pengalihan",
+ "log-action-filter-move-move_redir": "Pindahkan dengan menimpa pengalihan",
+ "log-action-filter-newusers-create": "Pembuatan oleh pengguna anonim",
+ "log-action-filter-newusers-create2": "Pembuatan oleh pengguna terdaftar",
+ "log-action-filter-newusers-autocreate": "Pembuatan otomatis",
+ "log-action-filter-newusers-byemail": "Pembuatan dengan kata sandi yang dikirimkan melalui surel",
+ "log-action-filter-patrol-patrol": "Patroli manual",
+ "log-action-filter-patrol-autopatrol": "Patroli otomatis",
+ "log-action-filter-protect-protect": "Perlindungan",
+ "log-action-filter-protect-modify": "Modifikasi perlindungan",
+ "log-action-filter-protect-unprotect": "Pembatalan perlindungan",
+ "log-action-filter-protect-move_prot": "Pemindahan perlindungan",
+ "log-action-filter-rights-rights": "Penggantian manual",
+ "log-action-filter-rights-autopromote": "Penggantian otomatis",
+ "log-action-filter-suppress-event": "Log penyembunyian",
+ "log-action-filter-suppress-revision": "Penyembunyian revisi",
+ "log-action-filter-suppress-delete": "Penyembunyian halaman",
+ "log-action-filter-suppress-block": "Perahasiaan pengguna menurut pemblokiran",
+ "log-action-filter-suppress-reblock": "Penyembunyian oleh pengguna menurut pemblokiran",
+ "log-action-filter-upload-upload": "Unggahan baru",
+ "log-action-filter-upload-overwrite": "Unggah kembali",
+ "authmanager-authn-not-in-progress": "Otentikasi tidak dilanjutkan atau data sesi telah hilang. Ulang kembali dari awal.",
+ "authmanager-authn-no-primary": "Kredensial yang diberikan tidak dapat diotentikasi.",
+ "authmanager-authn-no-local-user": "Kredensial yang diberikan tidak terkait dengan satu orang pun pengguna di wiki ini.",
+ "authmanager-authn-no-local-user-link": "Kredensial yang diberikan sah namun tidak terkait dengan satu orang pengguna pun di wiki ini. Silakan masuk log dengan cara lain, atau buat akun baru, dan Anda akan diberikan opsi untuk mengaitkan kredensial sebelumnya ke akun tersebut.",
+ "authmanager-authn-autocreate-failed": "Pembuatan otomatis dari akun lokal gagal: $1",
+ "authmanager-change-not-supported": "Kredensial yang diberikan tidak dapat diganti, karena tidak ada yang akan menggunakannya.",
+ "authmanager-create-disabled": "Pembuatan akun dimatikan.",
+ "authmanager-create-from-login": "Untuk membuat akun Anda, silakan isi kolom di bawah.",
+ "authmanager-create-not-in-progress": "Pembuatan akun tidak dilanjutkan atau data sesi telah hilang. Ulang kembali dari awal.",
+ "authmanager-create-no-primary": "Kredensial yang diberikan tidak dapat digunakan untuk pembuatan akun.",
+ "authmanager-link-no-primary": "Kredensial yang diberikan tidak dapat digunakan untuk menautkan akun.",
+ "authmanager-link-not-in-progress": "Penautan akun tidak dilanjutkan atau data sesi telah hilang. Ulang kembali dari awal.",
+ "authmanager-authplugin-setpass-failed-title": "Penggantian kata sandi gagal",
+ "authmanager-authplugin-setpass-bad-domain": "Domain tidak sah.",
+ "authmanager-autocreate-noperm": "Pembuatan akun otomatis tidak diizinkan.",
+ "authmanager-autocreate-exception": "Pembuatan akun otomatis dimatikan sementara karena galat sebelumnya.",
+ "authmanager-userdoesnotexist": "Pengguna \"$1\" tidak terdaftar.",
+ "authmanager-userlogin-remembermypassword-help": "Kata sandi harus diingat selama lebih dari lamanya sesi tersebut.",
+ "authmanager-username-help": "Nama pengguna untuk otentikasi.",
+ "authmanager-password-help": "Kata sandi untuk otentikasi.",
+ "authmanager-domain-help": "Domain untuk otentikasi eksternal.",
+ "authmanager-retype-help": "Ketik kata sandi lagi untuk mengonfirmasikan.",
+ "authmanager-email-label": "Surel",
+ "authmanager-email-help": "Alamat surel",
+ "authmanager-realname-label": "Nama asli",
+ "authmanager-realname-help": "Nama asli pengguna",
+ "authmanager-provider-password": "Otentikasi menurut kata sandi",
+ "authmanager-provider-password-domain": "Otentikasi menurut kata sandi dan domain",
+ "authmanager-provider-temporarypassword": "Kata sandi sementara",
+ "unlinkaccounts-success": "Akun berikut telah dilepastautkan."
}
"noname": "Saanmo a nainaganan ti umisu a nagan ti agar-aramat.",
"loginsuccesstitle": "Nakastrek",
"loginsuccess": "<strong>Nakastrekkan iti {{SITENAME}} a kas ni \"$1\".</strong>",
- "nosuchuser": "Awan ti agar-aramat nga agnagan iti \"$1\". \n\nDagiti nagan ti agar-aramat ket sensitibo ti kadakkel ti letra.\n\nKitaem ti panangiletram, wenno [[Special:UserLogin/signup|agpartuat iti baro a pakabilangan]].",
+ "nosuchuser": "Awan ti agar-aramat nga agnagan iti \"$1\". \n\nDagiti nagan ti agar-aramat ket sensitibo ti kadakkel ti letra.\n\nKitaem ti panangiletram, wenno [[Special:CreateAccount|agpartuat iti baro a pakabilangan]].",
"nosuchusershort": "Awan ti agar-aramat nga agnagan iti \"$1\".\nKitaem ti panangiletram.",
"nouserspecified": "Nasken nga inaganam ti nagan ti agar-aramat.",
"login-userblocked": "Naserraan daytoy nga agar-aramat. Saan a mapalubosan ti sumrek.",
"accmailtext": "Ti pugto a napartuat a kontrasenias para kenni [[User talk:$1|$1]] ket naipatuloden iti $2. Mabalin a masukatan iti\n<em>[[Special:ChangePassword|pagsukatan ti kontrasenias]]</em> a panid no sumrekka.",
"newarticle": "(Baro)",
"newarticletext": "Nasurotmo ti silpo ti awan pay a panid. \nTi mangpartuat ti panid, rugiamon ti agmakinilia iti kahon dita baba (kitaen ti [$1 panid ti tulong] para iti adu pay a pakaammo). \nNo addaka ditoy babaen ti biddut, pindutem ti buton ti <strong>back</strong> ti pagbasabasam.",
- "anontalkpagetext": "----\n<em>Daytoy ti pakitungtungan a panid para iti di ammo nga agar-aramat a saan pay a nakapartuat iti pakabilangan, wenno saanna nga us-usaren.</em>\nIsu nga agusarkami ti numero nga IP a pagtaengan tapno mailasin isuda a lalaki/babai.\nTi kastoy nga IP a pagtaengan ket us-usaren a bingayan babaen ti nadumaduma nga agar-aramat.\nNo sika ket maysa a di ammo nga agar-aramat ken dagiti awan ti pategna a komentario ket napaitudo kenka, pangngaasi nga [[Special:UserLogin/signup|agpartuatka iti pakabilangam]] wenno [[Special:UserLogin|sumrekka]] \ntapno maliklikan ti pannakaiyallilaw kadagiti sabali a di ammo nga agar-aramat.",
+ "anontalkpagetext": "----\n<em>Daytoy ti pakitungtungan a panid para iti di ammo nga agar-aramat a saan pay a nakapartuat iti pakabilangan, wenno saanna nga us-usaren.</em>\nIsu nga agusarkami ti numero nga IP a pagtaengan tapno mailasin isuda a lalaki/babai.\nTi kastoy nga IP a pagtaengan ket us-usaren a bingayan babaen ti nadumaduma nga agar-aramat.\nNo sika ket maysa a di ammo nga agar-aramat ken dagiti awan ti pategna a komentario ket napaitudo kenka, pangngaasi nga [[Special:CreateAccount|agpartuatka iti pakabilangam]] wenno [[Special:UserLogin|sumrekka]] \ntapno maliklikan ti pannakaiyallilaw kadagiti sabali a di ammo nga agar-aramat.",
"noarticletext": "Awan ti agdama a teksto iti daytoy a panid.\nMabalinmo ti [[Special:Search/{{PAGENAME}}|agbiruk iti kastoy a titulo ti panid]] kadagiti sabali a panid,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} agbiruk kadagiti mainaig a listaan],\nwenno [{{fullurl:{{NAMESPACE}}:{{PAGENAME}}|action=edit}} partuaten daytoy a panid]</span>.",
"noarticletext-nopermission": "Awan ti agdama a linaon daytoy a panid.\nMabalinmo ti [[Special:Search/{{PAGENAME}}|agbiruk para iti titulo ti daytoy a panid]] kadagiti sabali a panid, wenno <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} agbiruk kadagiti mainaig a listaan]</span>, ngem awan ti pammalubosmo a mangpartuat iti daytoy a panid.",
"missing-revision": "Ti panagbalbaliw ti #$1 iti daytoy a panid a nanaganan ti \"{{FULLPAGENAME}}\" ket awan.\n\nDaytoy ket kadawyan a gapuanan babaen ti sumaganad a silpo ti baak a pakasaritaan iti maysa a naikkaten a panid.\nDagiti salaysay ket mabalin a mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].",
"upload-form-label-own-work": "Daytoy ket bukodko nga obra",
"upload-form-label-infoform-categories": "Katkategoria",
"upload-form-label-infoform-date": "Petsa",
- "upload-form-label-not-own-work-local-local": "Mabalinmo pay a padasen [[Special:Upload|ti kasisigud a pagikargaan a panid]].",
+ "upload-form-label-not-own-work-local-generic-local": "Mabalinmo pay a padasen [[Special:Upload|ti kasisigud a pagikargaan a panid]].",
"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.",
"아라",
"Shirayuki",
"ElizaMag",
- "Adam-Yourist"
+ "Adam-Yourist",
+ "Matma Rex"
]
},
- "tog-underline": "Ð¥Ñ\8cожадеÑ\80га |ок|алÑ\82акадар:",
- "tog-hideminor": "Ð¥Ñ\8cаÑ\82|аÑ\8fздаÑ\80а Ñ\87Ñ\83 кеÑ\80даÑ\87а Ñ\85Ñ\83вÑ\86амаÑ\88a з|амига дола Ñ\85Ñ\83вÑ\86амаÑ\88 кÑ\8aайладаккÑ\85а",
- "tog-hidepatrolled": "Ð¥Ñ\8cаÑ\82|аÑ\8fздаÑ\80а Ñ\87Ñ\83 кеÑ\80даÑ\87а Ñ\85Ñ\83вÑ\86амаÑ\88a д|анийÑ\81адаÑ\8c дола Ñ\85Ñ\83вÑ\86амаÑ\88 кÑ\8aайладаккÑ\85а",
- "tog-newpageshidepatrolled": "Ð¥Ñ\8cаÑ\82|аÑ\8fздаÑ\80а Ñ\87Ñ\83 кеÑ\80даÑ\87а Ñ\85Ñ\83вÑ\86амаÑ\88a Ñ\85Ñ\8cанийÑ\81адаÑ\8c дола оаг|онаÑ\88 кÑ\8aайлаÑ\8fккÑ\85а",
- "tog-hidecategorization": "Къайлаяккха оагӀонай категореш",
- "tog-extendwatchlist": "ШеÑ\80адаÑ\8c Ñ\82еÑ\80кама Ñ\85Ñ\8cаÑ\82|аÑ\8fздаÑ\80, маÑ\81Ñ\81адола Ñ\85Ñ\83вÑ\86амаÑ\88 Ñ\87Ñ\83лоаÑ\86аÑ\88 дола, алÑ\85Ñ\85а Ñ\82|еÑ\85Ñ\8cаÑ\80а даÑ\8cÑ\80аÑ\88 маÑ\80а а доаÑ\86аÑ\88",
- "tog-usenewrc": "Ð\9aеÑ\80да Ñ\85Ñ\83вÑ\86амаÑ\88ка а Ñ\85Ñ\8cаÑ\82|аÑ\8fздаÑ\80а зембаккÑ\85аÑ\80га а Ñ\8dÑ\80гадаккÑ\85аÑ\80аÑ\88 Ñ\82оабаде (JavaScript Ñ\8dÑ\88а)",
- "tog-numberheadings": "Ð\9aеÑ\80Ñ\82аÑ\88каÑ\88Ñ\82а аланза Ñ\82аÑ\8cÑ\80аÑ\85Ñ\8cа Ñ\85оÑ\82та",
- "tog-showtoolbar": "Г|алатнийcдара г|ирсагартакх хьахьокха (JavaScript)",
- "tog-editondblclick": "Шозза д|аÑ\82о|амÑ\86a oаг|Ñ\83в Ñ\85Ñ\83вÑ\86а (JavaScript)",
- "tog-editsectiononrightclick": "РалÑ\81декÑ\8aаÑ\80аÑ\88 Ñ\85Ñ\83вÑ\86а даÑ\85каÑ\86а аÑ\8cÑ\82Ñ\82а д|аÑ\82о|амÑ\86а кеÑ\80Ñ\82аÑ\88ка Ñ\82|а (JavaScript)",
- "tog-watchcreations": "Tеркама хьат|аяздар т|а аз яь оаг|онаши чуяьккха паьлаши т|атоха",
- "tog-watchdefault": "Tеркама хьат|аяздар т|а аз хийца оаг|онаши паьлаша кустяздараши т|атоха",
- "tog-watchmoves": "Tеркама хьат|аяздар т|а аз ц|ихийца оагӀонаши паьлаши т|атоха",
- "tog-watchdeletion": "Tеркама хьат|аяздар т|а аз д|аяьккха оагӀонаши паьлаши т|атоха",
- "tog-minordefault": "ТеÑ\80камза Ñ\85Ñ\83вÑ\86амаÑ\88Ñ\82а лоаÑ\80Ñ\85Ó\80амза мо белгало Ñ\85оÑ\82Ñ\82а",
- "tog-previewontop": "Ð\93Ó\80алаÑ\82нийÑ\81даÑ\80а коÑ\80а Ñ\85Ñ\8cалÑ\85е бÓ\80аÑ\80гÑ\82аÑ\81Ñ\81ам оÑ\82Ñ\82ае",
- "tog-previewonfirst": "Ð\93Ó\80алаÑ\82нийÑ\81даÑ\80е деÑ\85Ñ\8cавоалаÑ\88/йоалаÑ\88 бÓ\80аÑ\80гÑ\82аÑ\81Ñ\81ам гойта",
- "tog-enotifwatchlistpages": "Tеркама хьат|аяздар чура оаг|онаши паьлаши хувцамаех лаьца д-хоамне т|а дайта хьа",
- "tog-enotifusertalkpages": "Са дÑ\83вÑ\86ама оаг|он Ñ\82|а Ñ\85Ñ\83вÑ\86амаÑ\88 Ñ\85илÑ\87а, д-Ñ\85оамнеÑ\86 Ñ\85Ñ\8cаÑ\85оам бе",
- "tog-enotifminoredits": "Ð\93еÑ\82Ñ\82аÑ\80а з|амига Ñ\85Ñ\83вÑ\86амаÑ\88 Ñ\85илÑ\87а а, д-Ñ\85оамнеÑ\86 Ñ\85Ñ\8cаÑ\85оам бе",
- "tog-enotifrevealaddr": "Ð\97|Ñ\8b Ñ\85оамаÑ\88 Ñ\82|а Ñ\81а д-Ñ\85оамни Ñ\86|ей-меÑ\82Ñ\82иг гойÑ\82а",
- "tog-shownumberswatching": "Шоай теркама хьат|аяздар чу оаг|ув чуяьккха доакьошхоша таьрахь гойта",
- "tog-oldsig": "Ð\94ола кÑ\83лгайоазÑ\83в:",
- "tog-fancysig": "Ший кÑ\83лгаÑ\8fздаÑ\80а маÑ\81Ñ\81аÑ\85оамбаккÑ\85аÑ\80 (Ñ\88ий ло|ама Ñ\85Ñ\8cожадерг йоацаш)",
- "tog-uselivepreview": "СиÑ\85а б|аÑ\80аÑ\85Ñ\8cажаÑ\80 (JavaScript)",
- "tog-forceeditsummary": "Ð¥Ñ\8cаÑ\85оам бе, наггаÑ\85Ñ\8c Ñ\81анна Ñ\85Ñ\83вÑ\86ама кÑ\83Ñ\81Ñ\82Ñ\8fздаÑ\80а меÑ\82Ñ\82ига Ñ\85Ñ\8cалайиза еÑ\86е",
- "tog-watchlisthideown": "Са теркама xьат|аяздара хувцамаш къайладаха",
- "tog-watchlisthidebots": "ТеÑ\80кама xÑ\8cаÑ\82|аÑ\8fздаÑ\80 Ñ\87Ñ\83Ñ\80а б|аÑ\82а хувцамаш къайладаха",
- "tog-watchlisthideminor": "Са теркама xьат|аяздара з|амига хувцамаш къайладаха",
- "tog-watchlisthideliu": "ТеÑ\80кама xÑ\8cаÑ\82|аÑ\8fздаÑ\80 Ñ\87Ñ\83Ñ\80а Ñ\85Ñ\8cабайза доакÑ\8aоÑ\88Ñ\85оÑ\88а Ñ\85Ñ\83вÑ\86амаÑ\88 кÑ\8aайладаÑ\85а",
- "tog-watchlisthideanons": "ТеÑ\80кама xÑ\8cаÑ\82|аÑ\8fздаÑ\80 Ñ\87Ñ\83Ñ\80а Ñ\86|ийоаÑ\86аÑ\87а доакÑ\8aоÑ\88Ñ\85оÑ\88а Ñ\85Ñ\83вÑ\86амаÑ\88 кÑ\8aайладаÑ\85а",
- "tog-watchlisthidepatrolled": "ТеÑ\80кама xÑ\8cаÑ\82|аÑ\8fздаÑ\80 Ñ\87Ñ\83Ñ\80а д|анийÑ\81даÑ\8c Ñ\85Ñ\83вÑ\86амаÑ\88 кÑ\8aайладаÑ\85а",
+ "tog-underline": "ТIаÑ\85Ñ\8cожаÑ\8fÑ\80га кIала Ñ\82ака Ñ\85Ñ\8cакÑ\85ар:",
+ "tog-hideminor": "Ð\9aÑ\8aайладаккÑ\85а з|амига дола Ñ\85Ñ\83вÑ\86амаÑ\88 кеÑ\80да Ñ\85Ñ\83вÑ\86амаÑ\88Ñ\82а Ñ\8eкÑ\8aеÑ\80а",
+ "tog-hidepatrolled": "Ð\9aÑ\8aайладаккÑ\85а Ñ\85а деÑ\80а Ñ\87акÑ\85даÑ\8cнна дола (паÑ\82Ñ\80Ñ\83лиÑ\80ованнÑ\8bе) Ñ\85Ñ\83вÑ\86амаÑ\88 кеÑ\80да Ñ\85Ñ\83вÑ\86амаÑ\88Ñ\82а Ñ\8eкÑ\8aеÑ\80а",
+ "tog-newpageshidepatrolled": "Ð\9aÑ\8aайлаÑ\8fÑ\8cккÑ\85а Ñ\85а деÑ\80а Ñ\87акÑ\85Ñ\8aÑ\8fнна йола (паÑ\82Ñ\80Ñ\83лиÑ\80ованнÑ\8bе) оагIонаÑ\88 кеÑ\80да оагIонаÑ\88Ñ\82а Ñ\8eкÑ\8aеÑ\80а",
+ "tog-hidecategorization": "Къайлаяха оагӀонай категореш",
+ "tog-extendwatchlist": "Ð¥Ñ\8cаÑ\88еÑ\80Ñ\8aÑ\8fÑ\8c йола зем баÑ\80а Ñ\81пиÑ\81ок, маÑ\81Ñ\81адола Ñ\85Ñ\83вÑ\86амаÑ\88 Ñ\88е Ñ\87Ñ\83лоаÑ\86аÑ\88, Ñ\82IеÑ\85Ñ\85Ñ\8cаÑ\80а даÑ\8c Ñ\85Ñ\83вÑ\86амаÑ\88 Ñ\85инна Ñ\86а IеÑ\88.",
+ "tog-usenewrc": "Ð¥Ñ\83вÑ\86амаÑ\88 Ñ\82оабаÑ\88 еÑ\88 леладе кеÑ\80да нийÑ\81даÑ\80аÑ\88ка а, зем баÑ\80а Ñ\81пиÑ\81ка Ñ\87Ñ\83 а",
+ "tog-numberheadings": "Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81ки нÑ\83меÑ\80аÑ\86и Ñ\85Ñ\8cае доакÑ\8aой Ñ\86IеÑ\80аÑ\88та",
+ "tog-showtoolbar": "ГIирсий панель хьахьокха хувцам беч хана",
+ "tog-editondblclick": "Ð\9dиÑ\81Ñ\8aе оагÓ\80онаÑ\88 Ñ\88озза IоÑ\82Ó\80аÑ\82оÓ\80аеÑ\87а (JavaScript)",
+ "tog-editsectiononrightclick": "Ð\9dийÑ\81де дáкÑ\8aа Ñ\88озза даÑ\85ка аÑ\8cÑ\82Ñ\82еÑ\85Ñ\8cаÑ\80а Ñ\82оIаеÑ\80 Ñ\82Ó\80аÑ\82оÓ\80айиÑ\87а дáкÑ\8aа Ñ\86IеÑ\80а Ñ\82Iа (JavaScript)",
+ "tog-watchcreations": "Зем беш йола оагIонашта а файлашта а тIатоха аз хьаяь оагIонаши чуяьккха файлаши",
+ "tog-watchdefault": "Зем беш йола оагIонашта а файлашта а тIатоха аз хийца оагIонаши файлай йоазонца сурташ оттадари",
+ "tog-watchmoves": "Зем беш йола оагIонашта а файлашта а тIатоха аз цIи хийца оагIонаши файлаши",
+ "tog-watchdeletion": "Зем беш йола оагIонашта а файлашта а тIатоха аз дIаяьккха оагIонаши файлаши",
+ "tog-minordefault": "Ð\9cаÑ\81Ñ\81аза зIамига долаÑ\88 Ñ\81анна белгалде Ñ\85Ñ\83вÑ\86амаÑ\88.",
+ "tog-previewontop": "Ð¥Ñ\8cалÑ\85Ñ\85е бÓ\80аÑ\80гÑ\82оÑ\85аÑ\80 Ñ\85Ñ\8cагойÑ\82а Ñ\85Ñ\83вÑ\86ама коÑ\80а Ñ\85Ñ\8cалÑ\85аÑ\88каÑ\85Ñ\8c",
+ "tog-previewonfirst": "Ð¥Ñ\83вÑ\86ама деÑ\85Ñ\8cавоалаÑ\88 Ñ\85ан Ñ\85Ñ\8cалÑ\85Ñ\85е бÓ\80аÑ\80гÑ\82оÑ\85аÑ\80 Ñ\85Ñ\8cагойта",
+ "tog-enotifwatchlistpages": "Электронни почте гIолла сога хоам бе зем беш йола оагIонаш а файлаш хувцарах",
+ "tog-enotifusertalkpages": "ÐлекÑ\82Ñ\80онни поÑ\87Ñ\82е гIолла Ñ\81ога Ñ\85оам бе Ñ\81а дÑ\83вÑ\86а оÑ\82Ñ\82адаÑ\80а оагIÑ\83в Ñ\85ийÑ\86аÑ\87а",
+ "tog-enotifminoredits": "Ð\9eагIонаÑ\88Ñ\82а а Ñ\84айлаÑ\88Ñ\82а даÑ\8c Ñ\85Ñ\83вÑ\86амаÑ\88 геÑ\82Ñ\82аÑ\80а зIамига дале а Ñ\85оам бе Ñ\81ога",
+ "tog-enotifrevealaddr": "Ð\94IаÑ\85айÑ\82а Ñ\85оамбаÑ\80аÑ\88 Ñ\87Ñ\83 бIаÑ\80гадейÑ\82а Ñ\81а поÑ\87Ñ\82а адÑ\80еÑ\81",
+ "tog-shownumberswatching": "Шоаш зем бу оагIонашта юкъе ер оагIув чуяьккха доакьошхоша таьрахь гойта",
+ "tog-oldsig": "Ð¥IанзаÑ\80а Ñ\8fздаÑ\8c кÑ\83лг:",
+ "tog-fancysig": "Ð\9aÑ\83лг Ñ\8fздаÑ\80а Ñ\88ий йола вики-Ñ\80азмеÑ\82ка (авÑ\82омаÑ\82иÑ\87еÑ\81ки Ñ\82IаÑ\85Ñ\8cожаÑ\8fрг йоацаш)",
+ "tog-uselivepreview": "Ð\9fайда Ñ\8dÑ\86а Ñ\81иÑ\85а дола Ñ\85Ñ\8cалÑ\85Ñ\85е бIаÑ\80гÑ\82оÑ\85аÑ\80",
+ "tog-forceeditsummary": "Ð\94IаÑ\85Ñ\8cалÑ\85адаккÑ\85а, нагаÑ\85Ñ\8cа Ñ\81анна Ñ\85Ñ\83вÑ\86ама йоазонÑ\86а Ñ\81Ñ\83Ñ\80Ñ\82 оÑ\82Ñ\82адаÑ\80а моÑ\82Ñ\82иг Ñ\85Ñ\8cалÑ\8aйизанза Ñ\8fле",
+ "tog-watchlisthideown": "Са зем бара хьаязъяьр чура хувцамаш къайладаха",
+ "tog-watchlisthidebots": "Ð\97ем баÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80 Ñ\87Ñ\83Ñ\80а боÑ\82ий хувцамаш къайладаха",
+ "tog-watchlisthideminor": "Са зем бара хьаязъяьр чура зIамига хувцамаш къайладаха",
+ "tog-watchlisthideliu": "ШоаÑ\88 Ñ\85Ñ\8cабайзийÑ\82а доакÑ\8aоÑ\88Ñ\85оÑ\88а Ñ\85Ñ\83вÑ\86амаÑ\88 кÑ\8aайладаÑ\85а зем баÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80 Ñ\87Ñ\83Ñ\80а",
+ "tog-watchlisthideanons": "ЦIийоаÑ\86аÑ\87а доакÑ\8aоÑ\88Ñ\85оÑ\88а Ñ\85Ñ\83вÑ\86амаÑ\88 кÑ\8aайладаÑ\85а зем баÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80 Ñ\87Ñ\83Ñ\80а",
+ "tog-watchlisthidepatrolled": "Ха даÑ\8c дола Ñ\85Ñ\83вÑ\86амаÑ\88 кÑ\8aайладаÑ\85а зем баÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80 Ñ\87Ñ\83Ñ\80а",
"tog-watchlisthidecategorization": "Къайлаяккха оагӀонай категореш",
- "tog-ccmeonemails": "Ð\90з д|аÑ\85ийÑ\82аÑ\88 дола доакÑ\8aоÑ\88Ñ\85оÑ\88оа каÑ\8cÑ\85аÑ\82аÑ\88 Ñ\81а д-Ñ\85оамни Ñ\82|а дайÑ\82а Ñ\85Ñ\8cа",
+ "tog-ccmeonemails": "Сона Ñ\85Ñ\8cаÑ\82|ааÑ\85ийÑ\82а аз доакÑ\8aаÑ\88Ñ\85оÑ\88Ñ\82а д|адаÑ\85ийÑ\82а дола каÑ\8cÑ\85аÑ\82ий кепаÑ\88",
"tog-diffonly": "Шин нийсхьале в|ашинийсдара к|ала бола оаг|он чулоацам ма гойта",
- "tog-showhiddencats": "Ð\9aÑ\8aайла каÑ\82агаÑ\88 гойÑ\82а",
+ "tog-showhiddencats": "Ð\93ойÑ\82а кÑ\8aайла каÑ\82егоÑ\80еÑ\88",
"tog-useeditwarning": "Хоамбе хьадаь хувцамаш дӀа ца яздеш аз болх дӀаберзабеча ханахь",
"underline-always": "Даиман",
- "underline-never": "Ц|аккха",
- "underline-default": "Ð\9cазаб|аÑ\80глокÑ\85аÑ\80a оÑ\82Ñ\82амаÑ\88 Ñ\85айÑ\80аде",
- "editfont-style": "Ð\9dийÑ\81даÑ\80а меÑ\82Ñ\82ига Ñ\87Ñ\83 йола заÑ\80ба б|аÑ\80маÑ\82:",
+ "underline-never": "ЦIаккха",
+ "underline-default": "Ð\91Ñ\80аÑ\83зеÑ\80а гIиÑ\80Ñ\81аÑ\88 Ñ\82оаÑ\8fÑ\80аÑ\88 лелае",
+ "editfont-style": "Ð¥Ñ\83вÑ\86ама моÑ\82Ñ\82иге Ñ\88Ñ\80иÑ\84Ñ\82а Ñ\82айпа:",
"editfont-default": "Браузерен гӀирса чура шрифт",
- "editfont-monospace": "Ð\91аÑ\88Ñ\85алон заÑ\80ба",
+ "editfont-monospace": "ЦÑ\85Ñ\8cаÑ\82аÑ\80Ñ\80а йоаÑ\86а Ñ\88Ñ\80иÑ\84Ñ\82",
"editfont-sansserif": "Белгало йоаца шрифт",
"editfont-serif": "Белгало йола шрифт",
"sunday": "кIиранди",
"monday": "оршот",
"tuesday": "шинара",
"wednesday": "Кхаьра",
- "thursday": "ера",
+ "thursday": "éра",
"friday": "пӀаьраска",
"saturday": "шоатта",
"sun": "КIиранди",
"mon": "Ор",
"tue": "Шин",
- "wed": "Кха",
+ "wed": "Кх",
"thu": "Ер",
- "fri": "П|аь",
+ "fri": "ПI",
"sat": "Шоа",
- "january": "АгIой бутт",
- "february": "Саь-кур бутт",
- "march": "Мутт-хьал бутт",
- "april": "Тушоли бутт",
- "may_long": "Села бутт",
- "june": "Этинга бутт",
- "july": "Баьцамеа бутт",
- "august": "Мяцхали бутт",
- "september": "Тов\\Ð\9cиÑ\85ий бÑ\83Ñ\82Ñ\82",
- "october": "Ð\90Ñ\80даÑ\80ий\\Ð\90Ñ\8cÑ\80Ñ\85Iий бÑ\83Ñ\82Ñ\82",
- "november": "Лай чилла бутт",
- "december": "Чан-тар бутт",
- "january-gen": "АгIой бетт",
- "february-gen": "Саь-кур бетт",
- "march-gen": "Муттхьол бетт",
- "april-gen": "Тушоли бетт",
- "may-gen": "Села бетт",
- "june-gen": "Этинга бетт",
- "july-gen": "Баьцамеа бетт",
- "august-gen": "Мецхали бетт",
- "september-gen": "Тов\\Ð\9cиÑ\85ий беÑ\82Ñ\82",
- "october-gen": "Ð\90Ñ\80даÑ\80ий\\Ð\90Ñ\8cÑ\80Ñ\85Iий беÑ\82Ñ\82",
- "november-gen": "Лай чилла бетт",
- "december-gen": "Чантар бетт",
+ "january": "АгIой",
+ "february": "Саь-кур",
+ "march": "Мутт-хьал",
+ "april": "Тушоли",
+ "may_long": "Села",
+ "june": "Этинга",
+ "july": "Баьцамеа",
+ "august": "Мяцхали",
+ "september": "Ð\9cиÑ\85ий",
+ "october": "Ð\90Ñ\8cÑ\80Ñ\85Iий",
+ "november": "Лай чилла",
+ "december": "Чан-тар",
+ "january-gen": "АгIой",
+ "february-gen": "Саь-кур",
+ "march-gen": "Мутт-хьал",
+ "april-gen": "Тушоли",
+ "may-gen": "Села",
+ "june-gen": "Этинга",
+ "july-gen": "Баьцамеа",
+ "august-gen": "Мяцхали",
+ "september-gen": "Ð\9cиÑ\85ий",
+ "october-gen": "Ð\90Ñ\8cÑ\80Ñ\85Iий",
+ "november-gen": "Лай чилла",
+ "december-gen": "Чан-тар",
"jan": "АгIой",
"feb": "Саь-кур",
"mar": "Мутт-хьал",
"apr": "Tушоли",
"may": "Села",
- "jun": "Ð\9cангал\\ÐÑ\82инга",
- "jul": "Баьцамеа\\Меа",
+ "jun": "Этинга",
+ "jul": "Баьцамеа",
"aug": "Мяцхали",
- "sep": "Тов\\Ð\9cиÑ\85ий",
- "oct": "Ð\90Ñ\80даÑ\80ий\\Ð\90Ñ\8cÑ\80Ñ\85Iий",
+ "sep": "Михий",
+ "oct": "АьрхIий",
"nov": "Лай чилла",
"dec": "Чан-тар",
- "january-date": "АгIой бутт $1",
- "february-date": "Саь-кур бутт $1",
- "march-date": "Муттхьол $1",
+ "january-date": "АгIой $1",
+ "february-date": "Саь-кур $1",
+ "march-date": "Мутт-хьал $1",
"april-date": "Тушоли $1",
- "may-date": "Села бутт $1",
- "june-date": "Ð\90Ñ\8cÑ\82инг $1",
- "july-date": "Ð\9a|имаÑ\80Ñ\81 $1",
- "august-date": "Мангал $1",
- "september-date": "Ð\9cоажол $1",
- "october-date": "Тов $1",
- "november-date": "Лай чилла бутт $1",
- "december-date": "Чантар $1",
+ "may-date": "Села $1",
+ "june-date": "ÐÑ\82инга $1",
+ "july-date": "Ð\91аÑ\8cÑ\86амеа $1",
+ "august-date": "Мяцхали $1",
+ "september-date": "Ð\9cиÑ\85ий $1",
+ "october-date": "Ð\90Ñ\8cÑ\80Ñ\85Iий $1",
+ "november-date": "Лай чилла $1",
+ "december-date": "Чан-тар $1",
"period-am": "ДЦ",
"period-pm": "ДТ",
"pagecategories": "{{PLURAL:$1|1=Категори|Категореш}}",
"category_header": "«$1» категори чура оагIонаш",
- "subcategories": "ЧÑ\83Ñ\80акаÑ\82агаш",
+ "subcategories": "Ð\9aIалкаÑ\82егоÑ\80еш",
"category-media-header": "\"$1\" Категори чура файлаш",
- "category-empty": "''УкÑ\85 каÑ\82ага Ñ\87Ñ\83 Ñ\86Ñ\85Ñ\8cаккÑ\85а оаг|онаÑ\88 е паÑ\8cлаÑ\88 Ñ\8fÑ\86.''",
+ "category-empty": "''Ð\95Ñ\80 каÑ\82егоÑ\80и Ñ\85Ó\80анза Ñ\8fÑ\8cÑ\81Ñ\81а Ñ\8f (Ñ\86Ñ\85Ñ\8cаккÑ\85а оагIонаÑ\88 е Ñ\84айлаÑ\88 йоаÑ\86аÑ\88).''",
"hidden-categories": "{{PLURAL:$1|1=Къайла категори|Къайла категореш}}",
- "hidden-category-category": "Ð\9aÑ\8aайла каÑ\82агаш",
- "category-subcat-count": "{{PLURAL:$2|УкÑ\85 каÑ\82агa Ñ\82|еÑ\85Ñ\8cаÑ\80а бÑ\83Ñ\85каÑ\82аг Ñ\87Ñ\83лоаÑ\86.|{{PLURAL:$1|1=$1 бÑ\83Ñ\85каÑ\82аг Ñ\85Ñ\8cаÑ\85Ñ\8cекÑ\85а Ñ\8f|$1 бÑ\83Ñ\85каÑ\82агаÑ\88 Ñ\85Ñ\8cаÑ\85Ñ\8cекÑ\85а Ñ\8f}} $2 йолаÑ\87аÑ\80ex.}}",
- "category-subcat-count-limited": "УкÑ\85 каÑ\82агa Ñ\87Ñ\83 {{PLURAL:$1|1=$1 к|алкаÑ\82аг|$1 к|алкаÑ\82агаÑ\88}}.",
- "category-article-count": "{{PLURAL:$2|УкÑ\85 каÑ\82ага Ñ\86Ñ\85Ñ\8cа оаг|Ñ\83в маÑ\80а Ñ\87Ñ\83лоаÑ\86аÑ\86.|{{PLURAL:$1|1=$1 оаг|Ñ\83в Ñ\85Ñ\8cаÑ\85екÑ\85а Ñ\8f|$1 оаг|oнаÑ\88 Ñ\85Ñ\8cаÑ\85екÑ\85а Ñ\8f}} Ñ\83кÑ\85 каÑ\82ага $2 йолаÑ\87аÑ\80eÑ\85.}}",
- "category-article-count-limited": "УкÑ\85 каÑ\82ага Ñ\87Ñ\83 {{PLURAL:$1|1=$1 оаг|Ñ\83в|$1 оаг|oнаÑ\88}}.",
+ "hidden-category-category": "Ð\9aÑ\8aайла каÑ\82егоÑ\80еш",
+ "category-subcat-count": "{{PLURAL:$2|УкÑ\85 каÑ\82егоÑ\80и Ñ\87Ñ\83 Ñ\8f алÑ\85Ñ\85а еÑ\80 кIалÑ\85аÑ\80а каÑ\82егоÑ\80и.|УкÑ\85 каÑ\82егоÑ\80и Ñ\87Ñ\83 $2-нен Ñ\8eкÑ\8aе $1 {{PLURAL:$1|кIалÑ\85аÑ\80а каÑ\82егоÑ\80и|кIалÑ\85аÑ\80а каÑ\82егоÑ\80еÑ\88}} Ñ\8f}}",
+ "category-subcat-count-limited": "УкÑ\85 каÑ\82егоÑ\80и Ñ\87Ñ\83 {{PLURAL:$1|кIалÑ\85аÑ\80а каÑ\82егоÑ\80и|$1 кIалÑ\85аÑ\80а каÑ\82егоÑ\80еÑ\88}} Ñ\8f.",
+ "category-article-count": "{{PLURAL:$2|УкÑ\85 каÑ\82егоÑ\80и Ñ\87Ñ\83 Ñ\86аI маÑ\80а оагIÑ\83в Ñ\8fÑ\86.|УкÑ\85 каÑ\82егоÑ\80и Ñ\87Ñ\83 Ñ\8f $2 оагÓ\80Ñ\83в, Ñ\86аÑ\80еÑ\85 оагÓ\80онгаÑ\85Ñ\8c {{PLURAL:$1|Ñ\85Ñ\8cагойÑ\82а $1 оагÓ\80Ñ\83в}}}}",
+ "category-article-count-limited": "УкÑ\85 каÑ\82егоÑ\80и Ñ\87Ñ\83 {{PLURAL:$1|$1 оагÓ\80Ñ\83в Ñ\8f|1=Ñ\86аI оагÓ\80Ñ\83в маÑ\80а Ñ\8fÑ\86}}.",
"category-file-count": "{{PLURAL:$2|Укх катагори чу цаI мара файл яц.|{{PLURAL:$1|1=$1 файл хьахьокхаш я|$1 файл хьахьокхаш я}} укх категори $2 долачарeх.}}",
- "category-file-count-limited": "УкÑ\85 каÑ\82ага Ñ\87Ñ\83 {{PLURAL:$1|1=$1 лÑ\83Ñ\80даÑ\80|$1 лÑ\83Ñ\80даÑ\80аÑ\88}}.",
+ "category-file-count-limited": "УкÑ\85 каÑ\82егоÑ\80и Ñ\87Ñ\83 {{PLURAL:$1|$1 Ñ\84айл|$1 Ñ\84айлаÑ\88|1=Ñ\86аI маÑ\80а Ñ\84айл Ñ\8fÑ\86}}.",
"listingcontinuesabbrev": "(дIахо)",
- "index-category": "Ð\94|аÑ\85Ñ\8cожама оаг|онаш",
- "noindex-category": "Ð\94|аÑ\85Ñ\8cожаманза оаг|онаш",
- "broken-file-category": "Ð\9fаÑ\8cла Ñ\85Ñ\8cожадеÑ\80гаÑ\88Ñ\86а болÑ\85беÑ\88 йоаÑ\86а оаг|онаш",
- "about": "Ð\9bоаÑ\86ам",
- "article": "Ð\99оазÑ\83в",
- "newwindow": "(кердача коре)",
- "cancel": "ÐÑ\88аÑ\86",
- "moredotdotdot": "Д|ахо",
- "morenotlisted": "Ер |ояздар хьалдиззанз да.",
- "mypage": "Oаг|ув",
- "mytalk": "Дувцам",
- "anontalk": "Дувцар",
+ "index-category": "Ð\98ндекÑ\81 оÑ\82Ñ\82аеÑ\88 оагIонаш",
+ "noindex-category": "Ð\98ндекÑ\81 Ñ\86а оÑ\82Ñ\82аеÑ\88 оагIонаш",
+ "broken-file-category": "Файла Ñ\82IаÑ\85Ñ\8cожаÑ\8fÑ\80гаÑ\88 болÑ\85беÑ\88 йоаÑ\86а оагIонаш",
+ "about": "СÑ\83Ñ\80Ñ\82 оÑ\82Ñ\82адаÑ\80",
+ "article": "СÑ\82аÑ\82Ñ\8cÑ\8f",
+ "newwindow": " (керда кора чу)",
+ "cancel": "ЮÑ\85адаккÑ\85а",
+ "moredotdotdot": "ДIахо...",
+ "morenotlisted": "Ер список хьалйиза яц.",
+ "mypage": "ОагIув",
+ "mytalk": "Дувца оттадар",
+ "anontalk": "Дувца оттадар",
"navigation": "Навигаци",
"and": " а",
"qbfind": "Лахар",
- "qbbrowse": "Б|аргтасса",
- "qbedit": "Ð¥Ñ\83вÑ\86а",
- "qbpageoptions": "Оаг|он оттамаш",
- "qbmyoptions": "Са оÑ\82Ñ\82амаш",
+ "qbbrowse": "БIаргтохар",
+ "qbedit": "Ð\9dийÑ\81де",
+ "qbpageoptions": "ОагIон оттамаш",
+ "qbmyoptions": "Ð¥Ñ\8cа гIиÑ\80Ñ\81аÑ\88 Ñ\82оаÑ\8fÑ\80аш",
"faq": "КТХ",
"faqpage": "Project:КТХ",
- "actions": "Ð¥|амдаÑ\80аш",
- "namespaces": "ЦIеÑ\80ий моÑ\82Ñ\82аш",
- "variants": "Ð\9aеÌ\81паш",
+ "actions": "Ð\90Ñ\80дамаш",
+ "namespaces": "ЦIеÑ\80ий аÑ\80енаш",
+ "variants": "Ð\92аÑ\80ианÑ\82аш",
"navigation-heading": "Навигацен меню",
- "errorpagetitle": "Г|алат",
- "returnto": "цу $1 оаг|он т|а юхаг|о",
+ "errorpagetitle": "ГӀалат",
+ "returnto": "Укх $1 оагIона тIа юхагӀо.",
"tagline": "Кечал укхазара: {{grammar:genitive|{{SITENAME}}}}",
- "help": "Ð\93Ó\80о",
+ "help": "Ð\9dовкÑ\8aoÑ\81Ñ\82ал",
"search": "Лахаp",
"searchbutton": "Хьалáха",
- "go": "Дехьа г|о",
+ "go": "Дехьавала",
"searcharticle": "Дехьавала",
"history": "Истори",
"history_short": "Истори",
- "updatedmarker": "Со Ñ\85анаÑ\87а денÑ\86а Ñ\85Ñ\83вÑ\86амаÑ\88 Ñ\85иннaд",
+ "updatedmarker": "Со Ñ\82IеÑ\85Ñ\85Ñ\8cаÑ\80а Ñ\83кÑ\85аз Ñ\85иннаÑ\87Ñ\83л Ñ\82IеÑ\85Ñ\8cагIа кеÑ\80дадаÑ\8cккÑ\85ад",
"printableversion": "Зарба тохара верси",
- "permalink": "Даиман латташ йола хьожаярг",
- "print": "Ð\9aепаÑ\82оÑ\85аÑ\80",
+ "permalink": "Ð\94аиман лаÑ\82Ñ\82аÑ\88 йола Ñ\82IаÑ\85Ñ\8cожаÑ\8fÑ\80г",
+ "print": "Ð\97аÑ\80ба Ñ\82оÑ\85а",
"view": "Хьажар",
- "view-foreign": "УкÑ\85 $1 Ñ\8fÑ\85 Ñ\81айÑ\82а Ñ\87Ñ\83 Ñ\85Ñ\8cажа",
+ "view-foreign": "Укх $1 сайта чу хьажа",
"edit": "Нийсде",
"edit-local": "Хувца локальни йоазонца сурт оттадар",
- "create": "Ð¥Ñ\8cаде",
+ "create": "Ð¥Ñ\8cакÑ\85олла",
"create-local": "ТIатоха локальни йоазонца сурт оттадар",
- "editthispage": "Ð\95Ñ\80 оаг|Ñ\83в Ñ\85Ñ\83вÑ\86а",
- "create-this-page": "Ep oаг|ув хьае",
- "delete": "Д|аяккха",
- "deletethispage": "Ð\95Ñ\80 оаг|Ñ\83в д|аÑ\8fÑ\8cккÑ\85а",
- "undeletethispage": "Ð\95Ñ\80 оаг|Ñ\83в д|аÑ\8fккÑ\85анз йиÑ\82а",
- "undelete_short": "Ð\9cеÑ\82Ñ\82аоÑ\82Ñ\82ае {{PLURAL:$1|1=Ñ\85Ñ\83вÑ\86ам|$1 Ñ\85Ñ\83вÑ\86амаш}}",
- "viewdeleted_short": "Б|аргтасса {{PLURAL:$1|1=д|адаьккха хувцам|$1 д|адаьккха хувцамаш}}",
- "protect": "Ð\9bоÑ\80аде",
+ "editthispage": "Ð\9dийÑ\81Ñ\8aе еÑ\80 оагIÑ\83в",
+ "create-this-page": "Хьакхолла ер оагӀув",
+ "delete": "ДӀаяккха",
+ "deletethispage": "Ð\94Ó\80аÑ\8fккÑ\85а еÑ\80 оагÓ\80Ñ\83в",
+ "undeletethispage": "ЮÑ\85амеÑ\82Ñ\82аоÑ\82Ñ\82ае еÑ\80 оагÓ\80Ñ\83в",
+ "undelete_short": "ЮÑ\85амеÑ\82Ñ\82аоÑ\82Ñ\82де {{PLURAL:$1|$1 нийÑ\81даÑ\80|$1 нийÑ\81даÑ\80аш}}",
+ "viewdeleted_short": "{{PLURAL:$1|$1 дIадаьккха нийсдарга|дIадаьккха нийсдарга|$1 дIадаьккха нийсдарашга}} хьажар",
+ "protect": "Ð\93Iо де",
"protect_change": "хувца",
- "protectthispage": "Ð\9bоÑ\80ае еÑ\80 оаг|Ñ\83в",
- "unprotect": "Ð\9bоÑ\80ам хувца",
- "unprotectthispage": "Ð\9bоÑ\80ам хувца",
+ "protectthispage": "Ð\93Iо (лоÑ\80адаÑ\80) де Ñ\83кÑ\85 оагIон",
+ "unprotect": "Ð\93Iо хувца",
+ "unprotectthispage": "УкÑ\85 оагIон гIо (лоÑ\80адаÑ\80) хувца",
"newpage": "Керда оагӀув",
- "talkpage": "УкÑ\85 оаг|он Ñ\82|а дÑ\83вÑ\86ам бе",
+ "talkpage": "Ð\95Ñ\80 оагIÑ\83в Ñ\8eвÑ\86а",
"talkpagelinktext": "дувца оттадар",
- "specialpage": "Г|улакхадара оаг|ув",
+ "specialpage": "ГIулакха оагӀув",
"personaltools": "Доакъашхочун гӀирсаш",
- "articlepage": "Ð\99оазон Ñ\82|а б|аÑ\80гÑ\82аÑ\81Ñ\81а",
+ "articlepage": "Ð\91IаÑ\80гÑ\82оÑ\85а оагIонга",
"talk": "Дувца оттадар",
"views": "Хьажараш",
"toolbox": "ГӀирсаш",
- "userpage": "Ð\94оакÑ\8aоÑ\88Ñ\85оÑ\87Ñ\83н оаг|он Ñ\82|а б|аÑ\80гÑ\82аÑ\81Ñ\81а",
- "projectpage": "Ð¥Ñ\8cаÑ\85Ñ\8cоадайÑ\82ама оаг|oн Ñ\82|а б|аÑ\80гÑ\82аÑ\81Ñ\81а",
- "imagepage": "Ð\9bÑ\83Ñ\80даÑ\80а оаг|oн Ñ\82|а б|аÑ\80гÑ\82аÑ\81Ñ\81а",
- "mediawikipage": "Xоаман оаг|ув хьахьокха",
- "templatepage": "Ч|абала оаг|oн Ñ\82|а б|аÑ\80гÑ\82аÑ\81Ñ\81а",
+ "userpage": "Ð\94оакÑ\8aаÑ\88Ñ\85оÑ\87Ñ\83н оагIон бIаÑ\80гÑ\82оÑ\85а",
+ "projectpage": "Ð\9fÑ\80оекÑ\82а оагIон бIаÑ\80гÑ\82оÑ\85а",
+ "imagepage": "Файла оагIон бIаÑ\80гÑ\82оÑ\85а",
+ "mediawikipage": "Хьахьокха хоам бара оагIув",
+ "templatepage": "Ð\9bеÑ\80а оагIон бIаÑ\80гÑ\82оÑ\85а",
"viewhelppage": "ГӀо хьаэцар",
- "categorypage": "Ð\9aаÑ\82ага оаг|oн Ñ\82|а б|аÑ\80гÑ\82аÑ\81Ñ\81а",
- "viewtalkpage": "Дувцамага б|аргтасса",
+ "categorypage": "Ð\9aаÑ\82егоÑ\80ен оагIон бIаÑ\80гÑ\82оÑ\85а",
+ "viewtalkpage": "Дувца оттадара бIаргтоха",
"otherlanguages": "Кхыча меттаех",
- "redirectedfrom": "($1 тIaра хьахьожадаь да)",
- "redirectpagesub": "Ð\94|а-Ñ\85Ñ\8cа дайÑ\82а оаг|Ñ\83в",
- "redirectto": "ТIахьожадар укхаза:",
+ "redirectedfrom": "($1 дIа-сахьожаяьй укхаз)",
+ "redirectpagesub": "Ð\9eагIÑ\83в-дIа-Ñ\81аÑ\85Ñ\8cожадаÑ\80",
+ "redirectto": "Ð\94Iа-Ñ\81ахьожадар укхаза:",
"lastmodifiedat": "Укх оагIoн тIеххьара хувцам: $2, $1.",
- "viewcount": "Укх оаг|oн т|а б|аргтассаб {{PLURAL:$1|цхьааца\n|$1 times}}. {{PLURAL:$1|1=цхьазза|$1за}}.",
- "protectedpage": "Ð\9bоÑ\80ама оаг|ув",
+ "viewcount": "Укх оагIонга хьежа хиннаб $1{{PLURAL:$1|-зза}}.",
+ "protectedpage": "Ð\93Iо оÑ\82Ñ\82адаÑ\8c лоÑ\80аÑ\8fÑ\8c оагIув",
"jumpto": "Дехьавала укхаза:",
"jumptonavigation": "навигаци",
"jumptosearch": "лахар",
- "pool-timeout": "ЧIегатохара сабаран ха чакхаяьннай",
- "pool-queuefull": "ХаÑ\82Ñ\82аÑ\80ий Ñ\86Ó\80а хьалдизад",
+ "pool-timeout": "ЧIега тохара сабардара ха чакхаяьннай",
+ "pool-queuefull": "Ð\94IаÑ\85аÑ\82Ñ\82аÑ\80ий гÑ\83лдеÑ\80 хьалдизад",
"pool-errorunknown": "Довзаш доаца гӀалат",
"poolcounter-usage-error": "Лелдара г|алат: $1",
- "aboutsite": "{{grammar:genitive|{{SITENAME}}}} лаьца",
- "aboutpage": "Project:Ð\9bоаÑ\86ам",
+ "aboutsite": "{{grammar:genitive|{{SITENAME}}}} лаьца дар",
+ "aboutpage": "Project:СÑ\83Ñ\80Ñ\82 оÑ\82Ñ\82адаÑ\80",
"copyright": "$1 чулоацамаца тIакхоачаш да.",
"copyrightpage": "{{ns:project}}:Автора бокъонаш",
"currentevents": "ХӀанзара хинна хIамаш",
"currentevents-url": "Project:ХӀанзара хинна хIамаш",
- "disclaimers": "Ð\91еÑ\85кÑ\82окÑ\85ам Ñ\85Ñ\8cацаэцар",
- "disclaimerpage": "Project:Ð\91еÑ\85кÑ\82окÑ\85ам Ñ\85Ñ\8cацаэцар",
+ "disclaimers": "Ð\91еÑ\85кÑ\82окÑ\85ам Ñ\82Iацаэцар",
+ "disclaimerpage": "Project:Ð\91еÑ\85кÑ\82окÑ\85ам Ñ\82Iацаэцар",
"edithelp": "Хувцам бара новкъостал",
"helppage-top-gethelp": "ГӀо",
- "mainpage": "Кертера оагӀув",
- "mainpage-description": "Кертера оагӀув",
+ "mainpage": "Керттера оагӀув",
+ "mainpage-description": "Керттера оагӀув",
"policy-url": "Project:Бокъонаш",
"portal": "Юкъара ков",
"portal-url": "Project:Юкъара ков",
"editlink": "хувца",
"viewsourcelink": "Хьажа дIадолалу ко́дага",
"editsectionhint": "Дáкъа хувца: $1",
- "toc": "ЧÑ\83лоаÑ\86ам",
+ "toc": "ЧÑ\83даÑ\80",
"showtoc": "хьахьокха",
"hidetoc": "къайладаккха",
"collapsible-collapse": "чудерзаде",
"page-rss-feed": "\"$1\" RSS мугӀ",
"page-atom-feed": "«$1» — Atom-мугI",
"red-link-title": "$1 (укх тайпара оагӀув яц)",
- "nstab-main": "Ð\99оазÑ\83в",
- "nstab-user": "Ð\94акÑ\8aалаÑ\8cÑ\86аÑ\80хо",
+ "nstab-main": "СÑ\82аÑ\82Ñ\8cÑ\8f",
+ "nstab-user": "Ð\94оакÑ\8aаÑ\88хо",
"nstab-media": "Медифаг",
- "nstab-special": "ГӀулакха оагӀув",
+ "nstab-special": "ГIулакха оагӀув",
"nstab-project": "Проектах лаьца",
"nstab-image": "Файл",
"nstab-mediawiki": "Хоам",
"nstab-template": "Ло",
"nstab-help": "ГӀо",
"nstab-category": "Категори",
- "mainpage-nstab": "Кертера оагӀув",
+ "mainpage-nstab": "Керттера",
"nosuchaction": "Цу тайпара дулархIам бац",
"nosuchspecialpage": "Изза мо гӀон оагӀув яц",
"error": "ГӀалат",
"internalerror_info": "Чура гӀалат: $1",
"cannotdelete-title": "ОагIув дIаяккха йиш яц \"$1\"",
"badtitle": "Мегаш йоаца цӀи",
- "badtitletext": "Ð\95заÑ\88 йола оагÓ\80он Ñ\86Ó\80и нийÑ\81а Ñ\8fÑ\86, Ñ\8fÑ\8cÑ\81Ñ\81а Ñ\8f, е Ñ\85аÑ\80Ñ\86аÑ\85Ñ\8c йоалаÑ\8fй меÑ\82Ñ\82ай Ñ\8eкÑ\8aеÑ\80а Ñ\86Iи е инÑ\82еÑ\80вики Ñ\86Ó\80и. Ð\98Ñ\88Ñ\82Ñ\82а, Ñ\86Ó\80еÑ\80а Ñ\8eкÑ\8aе оÑ\82Ñ\82аде мегаÑ\88 доаÑ\86а Ñ\85Ñ\8cаÑ\80акÑ\8aаÑ\88 нийÑ\81аденна Ñ\85ила Ñ\82аÑ\80лÑ\83ш да.",
+ "badtitletext": "Ð\95заÑ\88 йола оагÓ\80он Ñ\86Ó\80и нийÑ\81а Ñ\8fÑ\86, Ñ\8fÑ\8cÑ\81Ñ\81а Ñ\8f, е Ñ\85аÑ\80Ñ\86аÑ\85Ñ\8c йоалаÑ\8fй меÑ\82Ñ\82ий Ñ\8eкÑ\8aеÑ\80а Ñ\86Iи е инÑ\82еÑ\80вики Ñ\86Ó\80и. Ð\98Ñ\88Ñ\82Ñ\82а, Ñ\86Ó\80еÑ\80а Ñ\8eкÑ\8aе оÑ\82Ñ\82аде мегаÑ\88 доаÑ\86а Ñ\85Ñ\8cаÑ\80акаÑ\88 нийÑ\81аденна Ñ\85ила мегаш да.",
"viewsource": "Хьажар",
"actionthrottled": "Сихален овзамал",
"protectedpagetext": "Ер оаг|ув къайла я хувцамаш дергдоацаш е кхы дола х|амдараш.",
"virus-unknownscanner": "довзашдоаца мазаундохьалург:",
"welcomeuser": "Маьрша доаг|алд, $1!",
"yourname": "Дакъалаьцархочунна цӀи:",
- "userlogin-yourname": "Доакъашхочунна цӀи",
- "userlogin-yourname-ph": "Чуйоалае доакъашхочун цӀи",
+ "userlogin-yourname": "Доакъашхочун цӀи",
+ "userlogin-yourname-ph": "Iочуязъе хьай учёта яздара (доакъашхочун) цӀи",
"createacct-another-username-ph": "Чуйоалае доакъашхочун цӀи",
"yourpassword": "КъайладIоагӀа:",
"userlogin-yourpassword": "Пароль",
+ "userlogin-yourpassword-ph": "Iочуязъе хьа пароль",
+ "createacct-yourpassword-ph": "Iочуязъе пароль",
"yourpasswordagain": "КъайладIоагӀа юха Ӏоязаде:",
+ "createacct-yourpasswordagain": "Бакъйе пароль",
+ "createacct-yourpasswordagain-ph": "Кхы цхьаькхаза Iочуязъе пароль",
"remembermypassword": "(укх $1 {{PLURAL:$1|1=ден|деношкахь}}) мара са чувалара/чуялара дагалоаца дезаш дац",
+ "userlogin-remembermypassword": "Система чу виса",
"yourdomainname": "Шун цӀеноагӀув:",
"login": "Чувала/яла",
"nav-login-createaccount": "ЦӀи яьккха/Ший oагӀув ела",
"logout": "Аравала/яла",
"userlogout": "Аравала/яла",
"notloggedin": "Оаш шоай цӀи хьааьннадац",
+ "userlogin-noaccount": "Доакъашхочун учета яздар дице хьа?",
+ "userlogin-joinproject": "ДIахоттале {{SITENAME}}аца",
"nologin": "Леламе дIаяздар дац? '''$1'''.",
- "nologinlink": "Ð\9bеламе дIаÑ\8fздаÑ\80 кхолла",
- "createaccount": "УÑ\87Ñ\91Ñ\82а Ñ\8fздаÑ\80 кхолла",
+ "nologinlink": "Ð\94агаÑ\80а йоазÑ\83в Ñ\85Ñ\8cакхолла",
+ "createaccount": "Ð\94агаÑ\80а йоазÑ\83в Ñ\85Ñ\8cакхолла",
"gotaccount": "Укхаза дӀаязабенна дий шо? '''$1'''.",
"gotaccountlink": "Чувала/яла",
"userlogin-resetlink": "Чувала/яла цӀии дIоагӀаи дийцаденнадий?",
+ "userlogin-resetpassword-link": "ТIеракхосс хьа пароль?",
+ "userlogin-helplink2": "Система чуваларах новкъостал",
+ "userlogin-createanother": "Кхыдола дагара йоазув хьакхолла",
+ "createacct-emailoptional": "Электронни почта адрес (ца яздича мегаш да)",
+ "createacct-email-ph": "Iочуязде хьа электронни почта адрес",
"createaccountmail": "КъайладIоагIа д-хоамнец хьадайта",
"createaccountreason": "Бахьан:",
"createacct-reason": "Бахьан",
+ "createacct-submit": "Хьакхолла учета яздар",
+ "createacct-another-submit": "Дагара йоазув хьакхолла",
+ "createacct-benefit-heading": "{{SITENAME}} — хьо санна болача наха цхьан беш бола къахьегам ба.",
+ "createacct-benefit-body1": "{{PLURAL:$1|нийсдар|нийсдараш}}",
+ "createacct-benefit-body2": "{{PLURAL:$1|статья|статьяш}}",
+ "createacct-benefit-body3": "{{PLURAL:$1|доакъашхо|доакъашхой}} тӀеххьара хан",
"badretype": "Оаша яьккха дIоагIий цIераш шоайл таралуш яц.",
"loginerror": "Дакъалаьцархочун цIи нийса яц",
"mailmypassword": "Керда къайлад|оаг|а эца",
"emailconfirmlink": "Доаржален хоамни хьожадорг дIачIоагIаде",
"loginlanguagelabel": "Мотт: $1",
"pt-login": "Чувала/яла",
- "pt-createaccount": "Учёта яздар кхолла",
+ "pt-login-button": "Чувала/яла",
+ "pt-createaccount": "Дагара йоазув хьакхолла",
"pt-userlogout": "Аравала/яла",
"changepassword": "КъайладIоaгIа дIахувцар",
"oldpassword": "Къаьна къайладIоагӀа:",
"retypenew": "Керда къайладIоагӀа юха Ӏоязаде:",
"resetpass-submit-loggedin": "КъайладIоагӀа дӀахувца",
"resetpass-submit-cancel": "Юхавал/ялa",
+ "passwordreset": "Пароль тIеракхоссар",
"passwordreset-username": "Дакъалаьцархочунна цӀи:",
"passwordreset-email": "Д-хоамни моттиг:",
- "bold_sample": "Сома яздам",
- "bold_tip": "Сома яздам",
- "italic_sample": "Ð\9aÑ\83лга Ñ\8fздам",
- "italic_tip": "Ð\9aÑ\83лга Ñ\8fздам",
- "link_sample": "Ӏинка кортале",
- "link_tip": "Чура хьожаярг",
- "extlink_sample": "Ӏинка кортале http://www.example.com",
- "extlink_tip": "Ð\90Ñ\80ен Ó\80инка (http:// Ñ\82амагÓ\80аÑ\85 дийÑ\86а ма ле)",
- "headline_sample": "Ð\9aоÑ\80Ñ\82ален Ñ\8fздам",
- "headline_tip": "2-гÓ\80а лагÓ\80аÑ\80лен коÑ\80Ñ\82але",
- "nowiki_sample": "Укхаза кийчаде дезаш доаца яздам оттаде",
- "nowiki_tip": "Ð\9cаÑ\81Ñ\81а-бÑ\83Ñ\81Ñ\82амлоÑ\80г Ñ\82еÑ\80камза диÑ\82а",
- "image_tip": "Чуяьккха паьла",
- "media_tip": "Файлан тIахьожавар",
- "sig_tip": "ШÑ\83н кулгаяздар а, хӀанзара ха а",
- "hr_tip": "Ð\9cÑ\83Ñ\85ала мÑ\83гÓ\80 (могаÑ\88 Ñ\82айпаÑ\80а к|еззига Ñ\85айÑ\80аде)",
- "summary": "Хувцамий белгалдер",
+ "bold_sample": "Сома йоазон текст",
+ "bold_tip": "Сома йоазон текст",
+ "italic_sample": "СиÑ\85а йоазон Ñ\82екÑ\81Ñ\82",
+ "italic_tip": "СиÑ\85а йоазон Ñ\82екÑ\81Ñ\82",
+ "link_sample": "ТIахьожаярга дáкъа цIи",
+ "link_tip": "ЧÑ\83Ñ\80а Ñ\82IаÑ\85Ñ\8cожаÑ\8fÑ\80г",
+ "extlink_sample": "http://www.example.com тIахьожаярга дáкъа цIи",
+ "extlink_tip": "Ð\90Ñ\80аÑ\85Ñ\8cаÑ\80а Ñ\82IаÑ\85Ñ\8cожаÑ\8fÑ\80г (йиÑ\86 ма Ñ\8fлийÑ\82Ñ\82а пÑ\80еÑ\84икÑ\81 http://)",
+ "headline_sample": "Ð\94áкÑ\8aа Ñ\86IеÑ\80а Ñ\82екÑ\81Ñ\82",
+ "headline_tip": "2-гÓ\80а лагÓ\80аÑ\80а дáкÑ\8aа Ñ\86Iи",
+ "nowiki_sample": "Укхаза хувца езаш йоаца текст хьачуоттае",
+ "nowiki_tip": "ТеÑ\80кал ма е вики-Ñ\84оÑ\80маÑ\82иÑ\80овани",
+ "image_tip": "Чуоттаяь файл",
+ "media_tip": "Файла тIахьожавар",
+ "sig_tip": "Ð¥Ñ\8cа кулгаяздар а, хӀанзара ха а",
+ "hr_tip": "Ð\9fÑ\85Ñ\8cоÑ\80агIен Ñ\82ака (Ñ\86оÑ\85 пайда Ñ\8dÑ\86аÑ\80 Ñ\82IеÑ\85даÑ\8cнна каÑ\81Ñ\82Ñ\82а ма де)",
+ "summary": "Хувцамий сурт оттадар",
"subject": "БӀагал/кортале:",
"minoredit": "ЗӀамига хувцам",
"watchthis": "Зем бе укх оагӀон",
"savearticle": "ОагӀув дIаязъе",
"preview": "Хьалхе бӀаргтассар",
- "showpreview": "Хьалххе хьажар",
- "showdiff": "Даь хувцамаш",
- "anoneditwarning": "<strong>Теркам бе!</strong> Хьо автор хинна система чуваьннавац. Нагахьа санна Iа моллагIа хувцам бой, Хьа IP-адрес дийла массанен бIаргагуш хургда. Нагахьа санна Хьо <strong>[$1 хьачувоале]</strong> е <strong>[$2 учёта яздар хьакхолле]</strong>, нийсдараш (хувцамаш) бувзам болаш хургда Хьа доакъашхой цIерца, иштта кхыдола толажагIи гIойленагIи дола дикаьш хургда Хьона.",
+ "showpreview": "Хьалххе бIаргтохар",
+ "showdiff": "Даь дола хувцамаш",
+ "anoneditwarning": "<strong>Теркам бе!</strong> Хьо автор хинна система чуваьннавац. Нагахьа санна Iа моллагIа хувцам бой, Хьа IP-адрес дийла массанен бIаргагуш хургда. Нагахьа санна Хьо <strong>[$1 хьачувоале]</strong> е <strong>[$2 дагара йоазув хьакхолле]</strong>, нийсдараш (хувцамаш) бувзам болаш хургда Хьа доакъашхой цIерца, иштта кхыдола толажагIи гIойленагIи дола дикаьш хургда Хьона.",
"summary-preview": "Лоацам ба:",
"subject-preview": "Кортале хургья:",
"blockedtitle": "Дакъалаьцархо чӀега бела ва/я",
"loginreqpagetext": "Кхыйола оагӀувнашка хьожаргдолаш, оаш $1 де деза.",
"accmailtitle": "КъайладIоагӀа дӀадахьийтад",
"newarticle": "(Kерда)",
- "newarticletext": "Шо Ñ\85Ñ\8cожаÑ\8fÑ\80гаÑ\86а деÑ\85Ñ\8cадаÑ\8cннад йоаÑ\86а оагÓ\80он Ñ\82Ó\80а.\nÐ\98з кÑ\85оллаÑ\80гÑ\8cйолаÑ\88 кÓ\80алÑ\85агÓ\80а доала коÑ\80аÑ\87Ñ\83 Ñ\82екÑ\81Ñ\82 IоÑ\87Ñ\83Ñ\8fзаде (нагаÑ\85Ñ\8cа кÑ\85еÑ\82аде Ñ\85ала дале [$1 новкÑ\8aоÑ\81Ñ\82алан оагÓ\80онга] Ñ\85Ñ\8cажа).\nЦа Ñ\85овÑ\88 Ñ\83кÑ\85аза нийÑ\81деннадале, Ñ\88оай бÑ\80аÑ\83зеÑ\80а '''ЮÑ\85а''' (назад) кнопка Ñ\82Ó\80а пÓ\80елга тоӀабе.",
- "noarticletext": "ХIанз укх оагӀув тӀа текст яц.\nШун аьттув ба [[Special:Search/{{PAGENAME}}|цу тайпара цӀи хьоаяр кораде]] кхыйола йоазуваш чу, иштта\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} тара дола тептарий яздаьраш], е\n'''[{{fullurl:{{FULLPAGENAME}}|action=edit}} изза мо цӀи йолаш оагӀув кхолла]'''</span>.",
- "noarticletext-nopermission": "ХIанз укх оагӀув тӀа яздам дац.\nШун йиш я, кхыдола йоазувнашках [[Special:Search/{{PAGENAME}}|дола цӀерий хаттам корае]] е <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} нийсамий тептара йоазувнаш корае].</span>",
+ "newarticletext": "Шо Ñ\82IаÑ\85Ñ\8cожаÑ\8fÑ\80гаÑ\86а деÑ\85Ñ\8cадаÑ\8cннад йоаÑ\86а оагÓ\80он Ñ\82Ó\80а.\nÐ\98з Ñ\85Ñ\8cакÑ\85оллаÑ\80гÑ\8cйолаÑ\88 кÓ\80алÑ\85агÓ\80а доала коÑ\80аÑ\87Ñ\83 Ñ\82екÑ\81Ñ\82 IоÑ\87Ñ\83Ñ\8fзде (нагаÑ\85Ñ\8cа Ñ\81анна кÑ\85еÑ\82аде Ñ\85ала дале [$1 новкÑ\8aоÑ\81Ñ\82алаÑ\80а оагÓ\80онга] Ñ\85Ñ\8cажа).\nЦа Ñ\85овÑ\88 Ñ\83кÑ\85аза нийÑ\81деннадале, Ñ\88оай бÑ\80аÑ\83зеÑ\80а '''ЮÑ\85а''' (назад) Ñ\82оIаеÑ\80 Ñ\82Ó\80а пÓ\80елг тоӀабе.",
+ "noarticletext": "ХIанза укх оагӀон тӀа текст яц.\nШун аьттув ба [[Special:Search/{{PAGENAME}}|цу тайпара цӀи хьоаяр кораде]] кхыйола оагIонаш тIа, иштта\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} тара дола тептарий дIаяздаьраш], е\n'''[{{fullurl:{{FULLPAGENAME}}|action=edit}} изза мо цӀи йолаш оагӀув хьакхолла]'''</span>.",
+ "noarticletext-nopermission": "ХIанз укх оагӀон тӀа текст яц.\nШун аьттув ба [[Special:Search/{{PAGENAME}}|цу тайпара цӀи белгалъяр хьалаха]] кхыйола оагIонаш тIа, иштта\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} тара дола тептарай дIаяздаьраш].</span> Ер оагӀув хьакхолла Хьа бокъо яц.",
"note": "'''ХӀамоалар:'''",
"previewnote": "'''Хьалхе б|аргтассам мара бац.'''\nЯздам кхы яздаь дац!",
"editing": "Хувцам: $1",
+ "creating": "«$1» оагIув хьакхоллар",
"editingsection": "Хувцам: $1 (оагӀон дáкъа)",
"editingcomment": "ГӀалатнийсдар $1 (керда декъам)",
"editconflict": "ГӀалатнийсдара къовсам: $1",
"yourtext": "Хьа яздам",
"copyrightwarning": "Теркам бе, $2 ($1 хьажа) бокъонаца лорадеш, тӀахьежама кӀала уллаш, оаш мел чуяккхаш дола хоамаш, яздамаш долга.\nНаггахь санна шоай яздамаш пурам доацаш мала волашву саго хувца е кхы дола моттиге яздердолаш, безам беци, укхаз Ӏочуцаяздеча, дикаьгӀа да.<br />\nОаш дош лу, даь дола хувцама да волга/йолга, е оаш пурам долаш Ӏочуяздеш да кхычера меттигара шоай яздамаш/хоамаш.\n'''Яздархой бокъоца лорадеш дола хӀамаш, цара пурам доацаш, Ӏочумаязаде!'''",
- "templatesused": "УкÑ\85 оагIон Ñ\82Iа {{PLURAL:$1|1=пайда Ñ\8dÑ\86а Ð\9bо|пайда Ñ\8dÑ\86а Ð\9bонаш}}:",
+ "templatesused": "УкÑ\85 оагIон Ñ\82Iа {{PLURAL:$1|1=пайда Ñ\8dÑ\86а ло|пайда Ñ\8dÑ\86а леÑ\80аш}}:",
"templatesusedpreview": "Хьалхе бӀаргтассама оагӀув тӀа леладеш дола {{PLURAL:$1|1=Куцкеп|Куцкепаш}}:",
"template-protected": "(лорадаь да)",
"template-semiprotected": "(цхьа долча даькъе гIо оттадаь да)",
"hiddencategories": "Ер оагIув {{PLURAL:$1|$1 къайла категориех|1=цаI къайла категорех}} я:",
"permissionserrorstext-withaction": "Ер $2 де Хьа бокъо яц {{PLURAL:$1|1=из бахьан долаш|из бахьанаш долаш}}:",
"recreate-moveddeleted-warn": "'''Зем бе! Шо хьалххе дIайоаккхаш хинна оагӀув хьае гӀерта.'''\n\nХьажа, бокъонцахь езаш йолга.\nКӀалхагIа укх оагӀуви дӀадаккхами цӀи хувцами тептараш хьекха да.",
- "moveddeleted-notice": "Ер оагӀув дӀаяккха хиннай.\nНовкъостала, кӀалха хьахьекха да дӀадаккхама а хувцама а тептарашкара дIаяздараш.",
+ "moveddeleted-notice": "Ð\95Ñ\80 оагÓ\80Ñ\83в дÓ\80аÑ\8fккÑ\85а Ñ\85иннай.\nÐ\9dовкÑ\8aоÑ\81Ñ\82ала, кÓ\80алÑ\85а Ñ\85Ñ\8cаÑ\85Ñ\8cекÑ\85а да дÓ\80адаккÑ\85ама а Ñ\85Ñ\83вÑ\86ама а Ñ\82епÑ\82аÑ\80аÑ\88каÑ\80а дIаÑ\8fздаÑ\8cÑ\80аÑ\88.",
"log-fulllog": "Деррига таптара бӀаргтасса",
"edit-conflict": "Хувцамий къовсам.",
"post-expand-template-inclusion-warning": "Зембаккхам: жамIан чIабалаш чулоаца дустам геттара доккха да.\nЦхьадола чIабалаш чулоацалургдац.",
"post-expand-template-inclusion-category": "Чулоаца чIабала мегаш дола дустам дукхалена тӀехьайоала оагӀувнаш",
"post-expand-template-argument-warning": "Зем бе! Ер оагӀув цаӀ куцкепа |аьлдош мара чулоацац, юхадастара сел доккха дустам йолаш.\nЦу тайпара |аьлдешаш ӀокӀаладаькха да.",
"post-expand-template-argument-category": "Куцкепий теркамза |аьлдешаш чулоаца оагӀувнаш",
- "viewpagelogs": "Укх оагӀон тептараш хьокха",
+ "viewpagelogs": "УкÑ\85 оагÓ\80он Ñ\82епÑ\82аÑ\80аÑ\88 Ñ\85Ñ\8cаÑ\85Ñ\8cокÑ\85а",
"currentrev-asof": "тӀеххьара верси $1",
"revisionasof": "Верси $1",
"revision-info": "Верси $1; {{GENDER:$6|$2}}$7",
"mergehistory-reason": "Бахьан:",
"revertmerge": "Декъа",
"history-title": "\"$1\" — хувцамай истори",
+ "difference-title": "$1 — версешта юкъе йола башхало",
"lineno": "МугI $1:",
"compareselectedversions": "Хьаржа доржамаша тарона тIа хьажа",
- "editundo": "юхавала/яла",
+ "editundo": "юхадаккха",
+ "diff-multi-sameuser": "({{PLURAL:$1|цхьа юкъ хулаш йола верси|$1 юкъ хулаш йола версеш}} гуш яц цу доакъашхочун)",
"searchresults": "Лахар чакхдоалаш корадаьр",
"searchresults-title": "«$1» лахар",
"notextmatches": "ОагIувнаша яздамий вIашагIакхетараш дац",
"nextn": "{{PLURAL:$1|1=тIехьайоагIар|тIехьайоагIараш}} $1",
"prevn-title": "{{PLURAL:$1|1=$1 хьалхара йоазув|$1 хьалхара йоазувнаш}}",
"nextn-title": "{{PLURAL:$1|ТIадоагIа $1 яздар|ТIадоагIа $1 яздараш}}",
- "shown-title": "Ð¥Ñ\8cóкÑ\85а $1 {{PLURAL:$1|даÑ\8c йоазо|даÑ\8c йоазонаÑ\88}} Ñ\83кÑ\85 оáгIÑ\83вна тIа",
+ "shown-title": "Ð\93ойÑ\82а $1 {{PLURAL:$1|Ñ\8fздаÑ\8cÑ\80|Ñ\8fздаÑ\8cÑ\80аÑ\88}} Ñ\83кÑ\85 оáгIон тIа",
"viewprevnext": "ДIахьажа ($1 {{int:pipe-separator}} $2) ($3)",
"searchmenu-exists": "'''Укх масса-хьахьоадайтамач ер оаг|ув \"[[:$1]]\" я'''",
- "searchmenu-new": "<strong>Ð\9aÑ\85олла оагIÑ\83в «[[:$1]]» Ñ\83кÑ\85 вики-пÑ\80оекÑ\82е!</strong>\n{{PLURAL:$2|0=|Ð\98Ñ\88Ñ\82Ñ\82а Ñ\85Ñ\8cажа Ñ\85Ñ\8cай лийÑ\85а оагIÑ\83внага.|Иштта хьажа хьай лахара хьахиннарашка.}}",
+ "searchmenu-new": "<strong>Ð¥Ñ\8cакÑ\85олла оагIÑ\83в «[[:$1]]» Ñ\83кÑ\85 вики-пÑ\80оекÑ\82е!</strong>\n{{PLURAL:$2|0=|Ð\98Ñ\88Ñ\82Ñ\82а Ñ\85Ñ\8cажа IайÑ\85а лийÑ\85а оагIонга.|Иштта хьажа хьай лахара хьахиннарашка.}}",
"searchprofile-articles": "Кертера оагIонаш",
"searchprofile-images": "Мультимедиа",
"searchprofile-everything": "Массанахьа",
"searchprofile-articles-tooltip": "$1 чу лахар",
"searchprofile-images-tooltip": "Файлаш лахар",
"searchprofile-everything-tooltip": "Массайола оагIонаш тIа лахар (дувцар оттадара оагIонаш чулоацаш)",
- "searchprofile-advanced-tooltip": "IоÑ\87Ñ\83Ñ\8fзаÑ\8fÑ\8c Ñ\86IеÑ\80аÑ\80енаÑ\88каÑ\85 лаха",
+ "searchprofile-advanced-tooltip": "IоÑ\87Ñ\83Ñ\8fзаÑ\8fÑ\8c Ñ\86IеÑ\80ий аÑ\80енаÑ\88ка лаха",
"search-result-size": "$1 ({{PLURAL:$2|$2 дош|$2 дешаш}})",
"search-result-category-size": "{{PLURAL:$1|1=$1 дакъа|$1 дакъаш}} ({{PLURAL:$2|1=$2 кIалцатег|$2 кIалцатегаш}}, {{PLURAL:$3|1=$3 паьла|$3 паьлий}})",
"search-redirect": "(дIа-сахьожадар $1 тIара)",
- "search-section": " (дакъа $1)",
+ "search-section": "(дáкъа «$1»)",
"search-suggest": "Хьона эшар ер хила мега: $1",
"search-interwiki-caption": "Гаргалон хьахьоадайтамаш",
"search-interwiki-default": "$1 хьахиннараш:",
"search-relatedarticle": "шоайл дола",
"searchrelated": "гаргара",
"searchall": "деррига",
- "search-nonefound": "Хьа дехар дара вIаши нийса доагIаш хилар корадаьдац.",
+ "search-showingresults": "{{PLURAL:$4|Кораяьй <strong>$1</strong> — цхьа оагӀув|Из дош корадаьд <strong>$3</strong> оагӀонашка, царех гойта $2 оагӀув}}",
+ "search-nonefound": "Хьа дехар дара вIаши нийса доагIаш дар корадаьдац.",
"powersearch-legend": " Доккха тахкар",
"powersearch-ns": " ЦIерий аренашкахь лахар",
"powersearch-toggleall": "Деррига",
"powersearch-togglenone": "Цхьаккха",
"preferences": "Оттамаш",
- "mypreferences": "Ð\9eÑ\82Ñ\82амаш",
+ "mypreferences": "Ð\93IиÑ\80Ñ\81аш",
"prefs-skin": "БIагала куц",
"skin-preview": "Хьажа",
"prefs-personal": "Хьа хьай далам",
"prefs-rc": "Керда хувцамаш",
- "prefs-watchlist": "ТеÑ\80кама дагаÑ\80Ñ\87е",
+ "prefs-watchlist": "Ð\97ем баÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80",
"prefs-watchlist-days": "Ден дукхал",
"prefs-resetpass": "КъайладIоагIа хувца",
"prefs-rendering": "ТIера бIаса",
"timezoneregion-indian": "ХIинда форд",
"timezoneregion-pacific": "Тийна форд",
"prefs-searchoptions": "Лахар",
+ "prefs-namespaces": "ЦIерий аренаш",
"prefs-files": "Паьлаш",
"youremail": "Д-хоамни:",
"username": "{{GENDER:$1|Доакъошхочун ц|и}}:",
"right-createtalk": "дувцама оагIувний хьакхоллам",
"right-move": "ОагIувний цIи хувца",
"right-movefile": "Паьлий цIи хувца",
+ "right-writeapi": "ДIаяздара лаьрххIа API пайда эцар",
"newuserlogpage": "Доакъашхой дIаязбаь таптар",
"rightslog": "Дакъалаьцархочунна бокъона тептар",
"action-read": "Укх оагIуви дешам",
"nchanges": "$1 {{PLURAL:$1|1=хувцам|хувцамаш}}",
"enhancedrc-history": "истори",
"recentchanges": "Керда хувцамаш",
- "recentchanges-legend": "Ð\9aеÑ\80да Ñ\85Ñ\83вÑ\86амай оÑ\82Ñ\82амаш",
- "recentchanges-summary": "КIалхагIа лоарамий доаламе тIехьара оагIувний хувцамаш дIаязадаь да {{grammar:genitive|{{SITENAME}}}}.",
+ "recentchanges-legend": "Ð\9aеÑ\80да Ñ\85Ñ\83вÑ\86амий гIиÑ\80Ñ\81аÑ\88 Ñ\82оаÑ\8fÑ\80аш",
+ "recentchanges-summary": "КIалхагIа ханашца нийсдаь дIаяьздаь да {{grammar:genitive|{{SITENAME}}}} оагIонай тIеххьара хувцамаш.",
"recentchanges-feed-description": "Укх ларамца тIехьара массахувцамашт теркам бе.",
"recentchanges-label-newpage": "Укх хувцамаца керда оагIув кхелла хиннай",
"recentchanges-label-minor": "Ер зIамига хувцам ба",
"rcnotefrom": "КIалхагIа хувцамаш хьахьекха я <strong>$2</strong> денза (<strong>$1</strong> кхачалца).",
"rclistfrom": "$3 $2 денза даь хувцамаш хьахьокха",
"rcshowhideminor": "$1 зIамига нийсдараш",
- "rcshowhideminor-hide": "Къайлдаккха",
+ "rcshowhideminor-show": "Хьахьокха",
+ "rcshowhideminor-hide": "Къайладаккха",
"rcshowhidebots": "$1 боташ",
"rcshowhidebots-show": "Хьахьокха",
+ "rcshowhidebots-hide": "Къайладаккха",
"rcshowhideliu": "$1 бовзийтарчара доакъашхой",
"rcshowhideliu-hide": "Къайлабаха",
"rcshowhideanons": "$1 цIияккханза доакъашхой",
"rcshowhideanons-hide": "Къайлабаха",
"rcshowhidepatr": "$1 теркам даь хувцамаш",
"rcshowhidemine": "$1 хьа нийсдараш",
- "rcshowhidemine-hide": "Къайлдаккха",
+ "rcshowhidemine-show": "Хьахьокха",
+ "rcshowhidemine-hide": "Къайладаккха",
"rclinks": "Хьахьокха $2 дийнахь даь хинна тIеххьара $1 хувцамаш\n<br />$3",
"diff": "башхало",
"hist": "истори",
- "hide": "Къайлдаккха",
+ "hide": "Ð\9aÑ\8aайладаккÑ\85а",
"show": "Хьахьокха",
"minoreditletter": "зI",
"newpageletter": "К",
"rc-change-size-new": "Хувцам баьнначул тӀехьагIа бола боарам: $1 {{PLURAL:$1|байт}}",
"rc-enhanced-expand": "Ма дарра чулоацамаш хьахьокха (JavaScriptаца)",
"rc-enhanced-hide": "Ма дарра чулоацамаш къайладаккха",
- "recentchangeslinked": "Ð\93аÑ\80галон Ñ\85Ñ\83вÑ\86амаш",
+ "recentchangeslinked": "Ð\92IаÑ\88агIдÑ\83взаденна нийÑ\81даÑ\80аш",
"recentchangeslinked-feed": "Гаргалон хувцамаш",
- "recentchangeslinked-toolbox": "УкÑ\85анÑ\86а вIашагIдувзаденна хувцамаш",
+ "recentchangeslinked-toolbox": "Ð\92IашагIдувзаденна хувцамаш",
"recentchangeslinked-title": "$1ца вIашидувзаденна хувцамаш",
- "recentchangeslinked-summary": "Ð\95Ñ\80, Iинк Ñ\8fÑ\8c йола оагIÑ\83в (е Ñ\83кÑ\85 Ñ\86аÑ\82егаÑ\87Ñ\83 Ñ\87Ñ\83йоагIаÑ\80аÑ\88), дÑ\83кÑ\85а Ñ\85а йоаÑ\86аÑ\88 Ñ\85Ñ\8cийÑ\86а оагIÑ\83внаÑ\88кий дагаÑ\80ле Ñ\8f.\n[[Special:Watchlist|ШÑ\83н Ñ\82еÑ\80кама дагаÑ\80ленаÑ\88каÑ\85]] Ñ\87Ñ\83йоагIа оагIÑ\83внаÑ\88 '''белгалаÑ\8fÑ\8c Ñ\8f'''.",
- "recentchangeslinked-page": "ОагIува цIи",
- "recentchangeslinked-to": "Ð\9eагIÑ\83внаÑ\88 Ñ\82Iа Ñ\85Ñ\83вÑ\86амаÑ\88 Ñ\85Ñ\8cаÑ\85Ñ\8cокÑ\85а, Ñ\85Ñ\8cаÑ\85Ñ\8cекÑ\85а йола оагIÑ\83в Ñ\82Iа IинкаÑ\88 еÑ\88 йола.",
+ "recentchangeslinked-summary": "Ð\91елгалаÑ\8fÑ\8c йола оагIÑ\83в Ñ\82IаÑ\85Ñ\8cожавеÑ\88 (е белгалаÑ\8fÑ\8c йола каÑ\82егоÑ\80ен Ñ\8eкÑ\8aейоагIаÑ\88) йолÑ\87а оагIонаÑ\88Ñ\82а даÑ\8c Ñ\85Ñ\83вÑ\86амаÑ\88 да еÑ\80аÑ\88.\n[[Special:Watchlist|Ð¥Ñ\8cа зем баÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80а]] Ñ\8eкÑ\8aейоагIаÑ\88 оагIонаÑ\88 '''белгалаÑ\8fÑ\8cй'''.",
+ "recentchangeslinked-page": "ОагIон цIи",
+ "recentchangeslinked-to": "Ð\92еÑ\88Ñ\82а, белгалÑ\8fÑ\8cккÑ\85а оагIон Ñ\82IаÑ\85Ñ\8cожавеÑ\88 дола оагIонаÑ\88Ñ\82а даÑ\8c Ñ\85Ñ\83вÑ\86амаÑ\88 Ñ\85Ñ\8cаÑ\85Ñ\8cокÑ\85а.",
"upload": "Файл чуяккха",
"uploadbtn": "Паьл чуяьккха",
"uploadlogpage": "Чуяьккхамий тептар",
- "filedesc": "Ð\9bоаÑ\86а лоаÑ\86ам",
+ "filedesc": "Ð\9bоаÑ\86а йоазонÑ\86а Ñ\81Ñ\83Ñ\80Ñ\82 оÑ\82Ñ\82адаÑ\80",
"fileuploadsummary": "Лоаца лоацам:",
"license": "ЦIийяздар",
- "license-header": "ЦIийÑ\8fздаÑ\80",
+ "license-header": "Ð\9bиÑ\86ензиÑ\80овани",
"imgfile": "файл",
"listfiles": "Паьлий дагарче",
"listfiles_date": "Денха",
"listfiles_description": "Лоацам",
"listfiles_count": "Доржамаш",
"file-anchor-link": "Файл",
- "filehist": "Файлан истори",
- "filehist-help": "Ð\9aнопка Ñ\82аÑ\8cÑ\80аÑ\85Ñ\8c/Ñ\85а Ñ\82оIае Ñ\86Ñ\83 Ñ\85ан Ñ\84айл миÑ\88Ñ\82а Ñ\85иннай Ñ\85Ñ\8cожаpгволаÑ\88/йолаш",
+ "filehist": "Файла истори",
+ "filehist-help": "ТаÑ\8cÑ\80аÑ\85Ñ\8c/Ñ\85а Ñ\82Iа Ñ\82оIабе Ñ\86Ñ\83 Ñ\85ан Ñ\84айл миÑ\88Ñ\82а Ñ\85иннай Ñ\85Ñ\8cожаpгдолаш",
"filehist-revert": "юхаяьккха",
"filehist-current": "xIанзара",
"filehist-datetime": "Таьрахь/Ха",
"filehist-thumb": "ЗIамигасурт",
"filehist-thumbtext": "ЗIамига сурт укх версин $1",
"filehist-user": "Доакъашхо",
- "filehist-dimensions": "Файлан боарам",
+ "filehist-dimensions": "Файла боарам",
"filehist-filesize": "Паьла юстарал",
"filehist-comment": "Белгалдаккхар",
- "imagelinks": "Файла пайда эцар",
- "linkstoimage": "{{PLURAL:$1|1=ТIехьайоагIача $1 оагIуво тIахьожаву|ТIехьайоагIача $1 оагIувнаша тIахьожаву}} укх файла тIа:",
- "nolinkstoimage": "Ð\99ола паÑ\8cла Ñ\82Iа Iинк Ñ\8e оагIÑ\83внаÑ\88 даÑ\86",
+ "imagelinks": "Файлах пайда эцар",
+ "linkstoimage": "{{PLURAL:$1|1=ТIехьайоагIача $1 оагIо тIахьожаву|ТIехьайоагIача $1 оагIонаш тIахьожаву}} укх файла тIа:",
+ "nolinkstoimage": "УкÑ\85 Ñ\84айла Ñ\82IаÑ\85Ñ\8cожавеÑ\88 йола оагIонаÑ\88 Ñ\8fÑ\86.",
"sharedupload": "Ер паьла $1чера я, кхыча хьахьоадайтамча хьахайраде йийшайолаш я.",
- "sharedupload-desc-here": "Ер файл $1 чура я, иштта кхыйола проекташ чу пайда эца аьттув болаш я.\nЦун [$2 йоазонца сурт оттадара оагIон] информаци кIалхахь хьайоалаяй.",
+ "sharedupload-desc-here": "Ер файл $1 чура я, иштта кхыйола проекташ чу пайда эца аьттув болаш я.\nЦун [$2 сурт оттадара оагIон] хоам кIалхахь хьабоалабаьб.",
"uploadnewversion-linktext": "Укх паьлий керда бIаса чуяьккха",
+ "upload-disallowed-here": "Хьа бокъо яц ер файл юха дӀаязъе.",
"filerevert-comment": "Бахьан:",
"filedelete-comment": "Бахьан:",
"filedelete-submit": "ДIадаккха",
"filedelete-reason-otherlist": "Кхыдола бахьан",
"download": "хьачуяьккха",
"unwatchedpages": "Теркамза оагIувнаш",
- "randompage": "Ца ховш нийсъенна йоазув",
+ "randompage": "Ца ховш нийсъенна статья",
"statistics": "Дагара куц",
- "statistics-pages": "ОагIувнаш",
+ "statistics-articles": "Статьяш",
+ "statistics-pages": "ОагIонаш",
"brokenredirects-edit": "хувца",
"brokenredirects-delete": "дIадаккха",
"withoutinterwiki-submit": "Хьахьокха",
"prefixindex": "ОагIувнаший хьалхера цIи хьагойтар",
"shortpages": "Лоаца оагIувнаш",
"longpages": "Доккхий оагIувнаш",
+ "protectedpages-page": "ОагIув",
"usercreated": "{{GENDER:$3|Чуваьннав|Чуяьннай}} $1 $2",
"newpages": "Керда оагIонаш",
"move": "ЦIи хувца",
"allpagessubmit": "Кхоачашде",
"categories": "Категореш",
"linksearch": "Т|ера|инкаш лахар",
+ "linksearch-ns": "ЦIерий аренаш:",
"linksearch-ok": "Хьалáха",
"linksearch-line": "$1 тIа Iинк $2 юкъера",
"listgrouprights-members": "(тоабий дагарче)",
+ "listgrouprights-namespaceprotection-namespace": "ЦIерий аре",
"emailuser": "Дакъалаьцархочоа д-хоамни:",
- "watchlist": "ТеÑ\80кама дагаÑ\80Ñ\87е",
- "mywatchlist": "ТеÑ\80кама дагаÑ\80ле",
+ "watchlist": "Ð\97ем баÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80",
+ "mywatchlist": "Ð\97ем баÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80",
"watchlistfor2": "$1 $2 царна",
"addedwatchtext": "\"[[:$1]]\" оагIув, шун [[Special:Watchlist|теркама дагаршкахь]] чуяккха я. \nТехьара мел йола укх оагIувни хувцамаш цу дагаршкахь хоам беш хургья. Вешта [[Special:RecentChanges|керда хувцама дагаршкаехь]] сома къоалмаца хьакъоастлуш хургья.",
"removedwatchtext": "\"[[:$1]]\" оагIув, шун [[Special:Watchlist|теркама дарагчера]] дIаяккха хиннай.",
- "watch": "Зе",
+ "watch": "Зем бе",
"watchthispage": "Укх оагIува теркам бе",
"unwatch": "Лора ма де",
+ "notanarticle": "Статья яц",
"watchlist-details": "Шун теркама дагарченгахь йола $1 {{PLURAL:$1|1=оагIув|оагIувнаш}}, дувцама оагIувнаш ца лоархIаш.",
"wlshowlast": "Тlехьара $1 сахьаташ $2 денош хьахьокха",
"watchlist-options": "Зем баккха дагарена хувцамаш",
"deleteotherreason": "Кхыдола бахьан/тIатохар:",
"deletereasonotherlist": "Кхыдола бахьан",
"rollbacklink": "юхаяккха",
- "protectlogpage": "Лорадара тептар",
+ "rollbacklinkcount": "юхататта $1 {{PLURAL:$1|нийсдар}}",
+ "protectlogpage": "ГIон тептар",
"protectedarticle": "\"[[$1]]\" оагIув лорам деж я",
"modifiedarticleprotection": "\"[[$1]]\" оагIувни лорама лагIа хувцаяьннай",
"protectcomment": "Бахьан:",
"restriction-level": "Чувоала лагIа:",
"restriction-edit": "ГIалатнийсдар",
"restriction-move": "ЦIи хувцаp",
- "restriction-create": "Ð\9aÑ\85оллам",
+ "restriction-create": "Ð¥Ñ\8cакÑ\85оллаÑ\80",
"restriction-upload": "Чудаккхар",
"undeletelink": "БIаргтасса/юхаметтаоттаде",
"undeleteviewlink": "хьажа",
"undelete-search-submit": "Хьалáха",
- "namespace": "ЦIерий мотт",
- "invert": "Харжар юхадаккха",
- "namespace_association": "Ювзаенна мотт",
+ "namespace": "ЦIерий аренаш:",
+ "invert": "Хержар юхадаккха",
+ "tooltip-invert": "Оттае ер белгало, хержа цIерий аре чу а (белгалъяь яле вIашагIъювзаенна цIерий аре чу а), оагIонаш тIа а даь хувцамаш къайладоахаргдолаш",
+ "namespace_association": "Ювзаенна аре",
+ "tooltip-namespace_association": "Оттае ер белгало, иштта хержа цIерий ареца вIашагIъювзаенна дувца оттадара цIерий аре (е кхыяр) юкъейоаккхаргйолаш",
"blanknamespace": "(Кертера)",
"contributions": "{{GENDER:$1|Доакъашхочун}} къахьегам",
"contributions-title": "$1 дакъалаьцархочунна къахьегам",
"sp-contributions-username": "IP-моттиг е цIи:",
"sp-contributions-toponly": "ТIехьара доржамаш лоархаш дола хувцамаш мара ма хьокха",
"sp-contributions-submit": "Хьалáха",
- "whatlinkshere": "Ð¥ьожаяргаш укхаза",
- "whatlinkshere-title": "\"$1\" тIа Iинкаш еш йола оагIувнаш",
- "whatlinkshere-page": "ОагIув",
- "linkshere": "ТIехьайоагIа оагIувнаш тIахьожаву «'''[[:$1]]'''»:",
+ "whatlinkshere": "ТIаÑ\85ьожаяргаш укхаза",
+ "whatlinkshere-title": "\"$1а\" тIахьожавеш йола оагIонаш",
+ "whatlinkshere-page": "ОагIув:",
+ "linkshere": "ТIехьайоагIа оагIонаш тIахьожаву «'''[[:$1]]'''»:",
"nolinkshere": "'''[[:$1]]''' оагIув тIа, кхыдола оагIувашкара Iинкаш йоацаш я",
- "isredirect": "ТIаÑ\85Ñ\8cожадаÑ\80ан оагIÑ\83в",
+ "isredirect": "оагIÑ\83в-дIа-Ñ\81аÑ\85Ñ\8cожадаÑ\80",
"istemplate": "юкъейоалаяр",
- "isimage": "Файлан хьожаярг",
+ "isimage": "Файлови Ñ\82Iахьожаярг",
"whatlinkshere-prev": "{{PLURAL:$1|1=хьалхайоагIа|хьалхайоагIараш}} $1",
"whatlinkshere-next": "{{PLURAL:$1|1=тIехьайоагIар|тIехьайоагIараш}} $1",
- "whatlinkshere-links": "← хьожаяргаш",
- "whatlinkshere-hideredirs": "$1 дIа-Ñ\85Ñ\8cа Ñ\87Ñ\83Ñ\8fÑ\8cккÑ\85амаш",
- "whatlinkshere-hidetrans": "$1 Ñ\87Ñ\83Ñ\8fÑ\8cккÑ\85амаш",
- "whatlinkshere-hidelinks": "$1 Iинкаш",
+ "whatlinkshere-links": "â\86\90 Ñ\82IаÑ\85Ñ\8cожаÑ\8fÑ\80гаÑ\88",
+ "whatlinkshere-hideredirs": "$1 дIа-Ñ\81аÑ\85Ñ\8cожадаÑ\80аш",
+ "whatlinkshere-hidetrans": "$1 Ñ\8eкÑ\8aейоалаÑ\8fÑ\80аш",
+ "whatlinkshere-hidelinks": "$1 тIахьожаяргаш",
"whatlinkshere-hideimages": "$1 суртIинкаш",
- "whatlinkshere-filters": "ЦIенÑ\8aераш",
+ "whatlinkshere-filters": "ФилÑ\8cÑ\82раш",
"blockip": "Укх {{GENDER:$1|доакъошхочоа}} ч|ега бола",
"ipboptions": "2 сахьат:2 hours,1 ди:1 day,3 ди:3 days,1 кIира:1 week,2 кIира:2 weeks,1 бутт:1 month,3 бутт:3 months,6 бутт:6 months,1 шу:1 year,сиха ца луш:infinite",
"ipblocklist": "ЧIега бела дакъалаьцархой",
"movelogpage": "ЦIи хувцара тептар",
"movereason": "Бахьан",
"revertmove": "юхаяьккха",
- "export": "ОагIувий эхфортам",
+ "export": "ОагIонай экспорт",
"allmessagesname": "ЦIи",
"allmessagesdefault": "Сатийна улла яздам",
"allmessages-filter-all": "Дерригаш",
"allmessages-language": "Мотт:",
"allmessages-filter-submit": "Дехьа гӀо",
- "thumbnail-more": "Ð\94оккÑ\85а де",
+ "thumbnail-more": "Ð¥Ñ\8cадоаккÑ\85аде",
"thumbnail_error": "ЗIамигасуртанчий кхеллама гIалат: $1",
"import-upload-filename": "ПаьлацIи:",
- "tooltip-pt-userpage": "{{GENDER:|Хьа}} доакъашхочунна оагIув",
+ "tooltip-pt-userpage": "{{GENDER:|Хьа}} доакъашхочун оагIув",
"tooltip-pt-mytalk": "{{GENDER:|Хьа}} дувца оттадара оагIув",
- "tooltip-pt-preferences": "{{GENDER:|Ð¥Ñ\8cа оÑ\82Ñ\82амаш}}",
- "tooltip-pt-watchlist": "ОоагIувна дагарле, шо бIаргалокхаш йола",
+ "tooltip-pt-preferences": "{{GENDER:|Ð¥Ñ\8cа гIиÑ\80Ñ\81аш}}",
+ "tooltip-pt-watchlist": "Iа зем бу оагIонаш",
"tooltip-pt-mycontris": "{{GENDER:|хьа}} хувцамаш",
"tooltip-pt-login": "Укхаза хьай цIи аьле чувала/яла йиша я, амма из параз дац",
"tooltip-pt-logout": "Аравала/яла",
- "tooltip-pt-createaccount": "Хьа бокъо я учёта яздар кхелла система чу вала, амма параз долаш дац из.",
- "tooltip-ca-talk": "Ð\9eагIон Ñ\87Ñ\83лоаÑ\86ам дувца оттадар",
+ "tooltip-pt-createaccount": "Хьа бокъо я дагара йоазув кхелла система чувала, амма параз долаш дац из.",
+ "tooltip-ca-talk": "Ð\9eагIон Ñ\87Ñ\83даÑ\80 дувца оттадар",
"tooltip-ca-edit": "Нийсъе ер оагIув",
- "tooltip-ca-addsection": "Керда дакъа хьаде",
+ "tooltip-ca-addsection": "Керда дáкъа хьаде",
"tooltip-ca-viewsource": "Ер оагIув хувцамбарах гIо теха (лорая) я, амма цунна дIадолалу текстага хьажа а, из тIерхьаязъе а бокъо я.",
"tooltip-ca-history": "Укх оагIон даь хувцамаш тIа дола тептар",
"tooltip-ca-protect": "Eр оагIув лорае",
"tooltip-ca-delete": "Ер оагIув дIаяькха",
"tooltip-ca-move": "Укх оагIон цIи хувца",
- "tooltip-ca-watch": "Ð\95Ñ\80 оагIÑ\83в Ñ\85Ñ\8cай Ñ\82еÑ\80кам беÑ\87а каÑ\8cÑ\85аÑ\82а Ñ\82Iа Ñ\82IаÑ\8fÑ\8cккÑ\85а",
+ "tooltip-ca-watch": "ТIаÑ\82оÑ\85а еÑ\80 оагIÑ\83в Ñ\85Ñ\8cа зем баÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80а",
"tooltip-ca-unwatch": "Ер оагIув теркам беча каьхата тIара дIаяькха",
"tooltip-search": "Хьалáха {{grammar:prepositional|{{SITENAME}}}} чу",
- "tooltip-search-go": "Изза мо цӀи йолаш оагӀув тӀa дехьавала",
- "tooltip-search-fulltext": "Ð\98зза мо Ñ\8fздаÑ\80 долаÑ\88 оагÓ\80Ñ\83внаш лаха",
- "tooltip-p-logo": "Кертера оагIув тIа дехьавала",
- "tooltip-n-mainpage": "Кертера оагIув тIа дехьавала",
- "tooltip-n-mainpage-description": "Кертера оагIув тIа дехьавала",
- "tooltip-n-portal": "Ð\93IалгIай Ð\92икипедех лаьца дар а, укхаза де мегаш дар а, малагIа фуд а, мича да а",
+ "tooltip-search-go": "Изза мо цӀи йолаш оагӀон тӀa дехьавала",
+ "tooltip-search-fulltext": "Ð\98зза мо Ñ\82екÑ\81Ñ\82 йолаÑ\88 оагÓ\80онаш лаха",
+ "tooltip-p-logo": "Керттера оагIон тIа дехьавала",
+ "tooltip-n-mainpage": "Керттера оагIон тIа дехьавала",
+ "tooltip-n-mainpage-description": "Керттера оагIон тIа дехьавала",
+ "tooltip-n-portal": "Ð\93IалгIай Ð\92икипейдах лаьца дар а, укхаза де мегаш дар а, малагIа фуд а, мича да а",
"tooltip-n-currentevents": "ХIанзара хинна хIамах бола хоам",
- "tooltip-n-recentchanges": "ТÓ\80еÑ\85Ñ\85Ñ\8cаÑ\80а Ñ\85Ñ\83вÑ\86амай Ñ\81пиÑ\81ок",
+ "tooltip-n-recentchanges": "ТÓ\80еÑ\85Ñ\85Ñ\8cаÑ\80а Ñ\85Ñ\83вÑ\86амий Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80",
"tooltip-n-randompage": "Башхало йоаца ца ховш нийсъенна оагӀув хьаела",
"tooltip-n-help": "Новкъостал лаха мегаш йола моттиг",
- "tooltip-t-whatlinkshere": "Укхаза тIахьожавеш йола оагIонай список",
- "tooltip-t-recentchangeslinked": "Укх оагIуво тIахьожавеш йолча оагIонай тIеххьара хувцамаш",
+ "tooltip-t-whatlinkshere": "Укхаза тIахьожавеш йола оагIонаш",
+ "tooltip-t-recentchangeslinked": "Укх оагIо тIахьожавеш йолча оагIонай тIеххьара хувцамаш",
"tooltip-feed-rss": "Укх оагIувна RSSчу гойтар",
- "tooltip-feed-atom": "Укх оаг|увна Atomчу гойтар",
- "tooltip-t-contributions": "{{GENDER:$1|Укх доакъашхочо хийца}} йола оагIувнаш",
+ "tooltip-feed-atom": "Укх оагIонна лаьрххIа Atom чу трансляци яр",
+ "tooltip-t-contributions": "{{GENDER:$1|Укх доакъашхочо хийца}} йола оагIонаш",
"tooltip-t-emailuser": "Укх дакъалаьцархочоа зIы яхьийта",
"tooltip-t-upload": "Файлаш чуяккха",
- "tooltip-t-specialpages": "ГIулакха оагIувнаш",
+ "tooltip-t-specialpages": "ГIулакха оагIонаш",
"tooltip-t-print": "Укх оагIон зарба тохара верси",
- "tooltip-t-permalink": "ОагIон укх версин тIахьожавеш йола даим латташ йола хьожаярг",
- "tooltip-ca-nstab-main": "ОагIон чурадар",
- "tooltip-ca-nstab-user": "Ð\94акÑ\8aалаÑ\8cÑ\86аÑ\80Ñ\85оÑ\87Ñ\83нна Ñ\88ий оагIув",
+ "tooltip-t-permalink": "Ð\9eагIон Ñ\83кÑ\85 веÑ\80Ñ\81ин Ñ\82IаÑ\85Ñ\8cожавеÑ\88 йола даим лаÑ\82Ñ\82аÑ\88 йола Ñ\82IаÑ\85Ñ\8cожаÑ\8fÑ\80г",
+ "tooltip-ca-nstab-main": "ОагIон чударга хьажар",
+ "tooltip-ca-nstab-user": "Ð\94оакÑ\8aаÑ\88Ñ\85оÑ\87Ñ\83н Ñ\88е доалаÑ\85Ñ\8c йола оагIув",
"tooltip-ca-nstab-special": "Ер гIулакха оагIув я, из хувца бокъо яц",
"tooltip-ca-nstab-project": "Проектан оагIув",
- "tooltip-ca-nstab-image": "Файлан оагӀув",
- "tooltip-ca-nstab-template": "Ð\9bон оагIув",
+ "tooltip-ca-nstab-image": "Файла оагӀув",
+ "tooltip-ca-nstab-template": "Ð\9bеÑ\80а оагIув",
"tooltip-ca-nstab-help": "ГӀон оагIув",
- "tooltip-ca-nstab-category": "Ð\9aаÑ\82егоÑ\80ий оагӀув",
+ "tooltip-ca-nstab-category": "Ð\9aаÑ\82егоÑ\80ен оагӀув",
"tooltip-minoredit": "Ер хувцар башха доаца санна белгалде",
- "tooltip-save": "Хьай хувцамаш лорадеш дIаязаде",
- "tooltip-preview": "Дехар да, оагӀув лораешь дIаязаелехь из мишта я тахка хьалххе хьажарах пайда эцаш!",
+ "tooltip-save": "Хьа хувцамаш лорадеш дIаязде",
+ "tooltip-preview": "Дехар да, оагӀув лораешь дIаязъелехь из мишта я тахка хьалххе бIаргтохарах пайда эцаш!",
"tooltip-diff": "ДIадолалу текстаца даь хувцамаш хьахьокха",
"tooltip-compareselectedversions": "Укх оагIувни шин доржамаш тIа юкъера хувцамаш зе.",
"tooltip-watch": "Ер оагIув теркам беча каьхата тIа яькха",
"tooltip-rollback": "Цкъа пIелг тоIабе дIадаккха тIехьара редакторас даь хувцамаш",
- "tooltip-undo": "Даь хувцар дIадаьккха, хьалххе хьажар хьахьокха, дIадаккхара бахьан Iочуязаде аьттув болаш.",
- "tooltip-summary": "Лоаца йоазонца сурт оттадар Iочуязаде",
+ "tooltip-undo": "Даь хувцар дIадаьккха, хьалххе бIаргтохар хьахьокха, дIадаккхара бахьан Iочуязде аьттув болаш.",
+ "tooltip-summary": "Лоаца сурт оттадар Iочуязде",
+ "simpleantispam-label": "Анти-спам тахкар.\n<strong>Цхьа</strong> хIама ма язъе укхаз!",
+ "pageinfo-hidden-categories": "{{PLURAL:$1|1=Къайла категори|Къайла категореш}} ($1)",
"pageinfo-toolboxlink": "ОагIонах бола хоам",
"previousdiff": "← Хьалхара нийсдар",
"nextdiff": "ТIайоагIа нийсъар",
- "file-info-size": "$1 × $2 {{PLURAL:$2|пиксель}}, файлан боарам: $3, MIME-тайпа: $4",
+ "file-info-size": "$1 × $2 {{PLURAL:$2|пиксель}}, файла боарам: $3, MIME-тайпа: $4",
"file-nohires": "Укхал дуккхагIа доккхал долаш верси яц",
"svg-long-desc": "SVG-файл, номинально $1 × $2 {{PLURAL:$2|пиксель}}, файлан боарам: $3",
"show-big-image": "ДIадолалу файл",
+ "show-big-image-preview": "Боарам хьалххе бIаргтохач хан: $1.",
+ "show-big-image-other": "{{PLURAL:$2|1=Кхыбола тIера боарам|Кхыбола тIера боарам}}: $1.",
"show-big-image-size": "$1 × $2 пиксель",
"noimages": "Суртaш бIаргагуш дац.",
"ilsubmit": "Хьалáха",
"bad_image_list": "Бустам цу тайпара хила беза:\n\nДагарлен хьаракъаш мара лоарх|аш хургьяц (укх тамагIалгацa * дувлашду мугIараш).\nМугIарен хьалхара Iинк, сурт Iоттае пурам доаца Iинка, хила еза. \nЦу мугIара тIехьайоагIа Iинкаш, арадаккхар мо лоарх|аш хургья, вешта аьлча, йоазувашка чуIоттаде мегаш дола сурт санна ларх|а мега.",
- "metadata": "Метахоамаш",
- "metadata-help": "ФайлаÑ\81 кÑ\85Ñ\8bдола Ñ\85оамаÑ\88 Ñ\87Ñ\83лоаÑ\86а, Ñ\86иÑ\84Ñ\80овой Ñ\81Ñ\83Ñ\80Ñ\82доакÑ\85аÑ\80го е Ñ\81канеÑ\80о Ñ\82IаÑ\82оÑ\85аÑ\88 дола. Ð\9dагаÑ\85Ñ\8cа Ñ\84айл Ñ\87Ñ\83Ñ\8fкÑ\85аÑ\87Ñ\83л Ñ\82IеÑ\85Ñ\8cа Ñ\85ийÑ\86а Ñ\85инна дале, Ñ\86Ñ\85Ñ\8cаÑ\86Ñ\86айола паÑ\80амеÑ\82Ñ\80аÑ\88 Ñ\85IанзаÑ\80а Ñ\81Ñ\83Ñ\80Ñ\82а Ñ\82ара йоацаш хила мегаш я.",
+ "metadata": "Мета-дараш",
+ "metadata-help": "Файло кÑ\85Ñ\8bдола даÑ\80аÑ\88 Ñ\87Ñ\83лоаÑ\86а, Ñ\86иÑ\84Ñ\80овой Ñ\81Ñ\83Ñ\80Ñ\82доакÑ\85аÑ\80го е Ñ\81канеÑ\80о Ñ\82IаÑ\82оÑ\85аÑ\88 дола. Ð\9dагаÑ\85Ñ\8cа Ñ\84айл Ñ\87Ñ\83Ñ\8fкÑ\85аÑ\87Ñ\83л Ñ\82IеÑ\85Ñ\8cа Ñ\85ийÑ\86а Ñ\85инна дале, Ñ\86Ñ\85Ñ\8cаÑ\86Ñ\86айола паÑ\80амеÑ\82Ñ\80аÑ\88 Ñ\85IанзаÑ\80а Ñ\81Ñ\83Ñ\80Ñ\82а Ñ\82Iара йоацаш хила мегаш я.",
"metadata-expand": "Кхыдола хIамаш хьахьокха",
"metadata-collapse": "Кхыдола хIамаш къайладаккха",
- "metadata-fields": "УкÑ\85 Ñ\81пиÑ\81ке дагaÑ\80адаÑ\8c Ñ\81Ñ\83Ñ\80Ñ\82ай меÑ\82аÑ\85оамай йиÑ\81Ñ\82оÑ\88, Ñ\85Ñ\8cаÑ\85Ñ\8cекÑ\85а Ñ\85Ñ\83Ñ\80гда Ñ\81Ñ\83Ñ\80Ñ\82ан оагIон Ñ\82Iа, меÑ\82аÑ\85оамай Ñ\82аблиÑ\86а Ñ\85Ñ\8cоаÑ\80Ñ\87аÑ\8f йолаш. Юхедиса йистош къайла хургда.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+ "metadata-fields": "УкÑ\85 Ñ\85Ñ\8cаÑ\8fÑ\8cзÑ\8aÑ\8fÑ\80а Ñ\87Ñ\83 дагaÑ\80адаÑ\8c Ñ\81Ñ\83Ñ\80Ñ\82ий меÑ\82аÑ\85оамий йиÑ\81Ñ\82оÑ\88, Ñ\85Ñ\8cаÑ\85Ñ\8cекÑ\85а Ñ\85Ñ\83Ñ\80гда Ñ\81Ñ\83Ñ\80Ñ\82а оагIон Ñ\82Iа, Ñ\85Ñ\8cоаÑ\80Ñ\87адаÑ\8c меÑ\82аÑ\85оамий илÑ\8cг долаш. Юхедиса йистош къайла хургда.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
"exif-imagewidth": "Шерал",
"exif-imagelength": "Лакхал",
- "exif-orientation": "Суртан белгало",
+ "exif-orientation": "Сурта белгало",
+ "exif-xresolution": "ПхьорагIа тIера боарам",
+ "exif-yresolution": "УрагIа тIера боарам",
+ "exif-datetime": "Файл хийца хинна таьрахьи хаи",
"exif-imagedescription": "Сурта цIи",
+ "exif-make": "Камера кийчъяь арахийцар",
"exif-model": "Камера модель",
"exif-software": "Программни Iалашдар",
"exif-artist": "Яздархо",
"exif-exifversion": "Верси Exif",
- "exif-colorspace": "Ð\91аÑ\81аÑ\80а аÑ\80е",
+ "exif-colorspace": "Ð\91еÑ\81ай моÑ\82Ñ\82",
"exif-pixelxdimension": "Сурта шорал",
"exif-pixelydimension": "Сурта лакхал",
+ "exif-datetimeoriginal": "Оригинальни таьрахьи хаи",
"exif-datetimedigitized": "Оцифровк яь таьрахь а, ха а",
"exif-writer": "Яздама да",
"exif-languagecode": "Мотт",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|дувца оттадар]])",
"duplicate-defaultsort": "Зем бе. Сатийна дIа-хьа хьоржама доагI \"$2\" хьалхара сатийна дIа-хьа хьоржама доагI \"$1\" хьахьоржа.",
"version": "Доржам",
- "version-specialpages": "Ð\93IÑ\83лакÑ\85ий оагIÑ\83внаш",
+ "version-specialpages": "Ð\93IÑ\83лакÑ\85а оагÓ\80онаш",
"version-version": "($1)",
"version-software-version": "Доржам",
"fileduplicatesearch-filename": "ПаьлацIи:",
"fileduplicatesearch-submit": "Хьалáха",
- "specialpages": "ЛаьрххIа йола оагIувнаш",
+ "specialpages": "ЛаьрххIа йола оагIонаш",
"specialpages-group-users": "Дакъалаьцархой, цара бокъо",
"specialpages-group-pages": "ОагIувний дагарченаш",
"specialpages-group-pagetools": "ОагIувнаша гIирсаш",
"external_image_whitelist": "#Ер мугI ший долаш тайпара дита<pre>\n#Каст-каста оаламаш укхаза дIаязаде(юкъе дола дакъа //)\n#арара суртий URLца дIанийсалургда уш.\n#Пайдан дола, сурташ мо хьахьекха хургья, дахIодараш, сурта тIа Iинкаш мо хуpгья хьахьекха.\n#Укх # тамагIалгаца дIадувлаш дола мугIанаш, оалам мо лоархаш да.\n#МугIанаш яздaтакха каьда да\n\n#Каст-каста оаламаш укх мугIа лакхе дIаязаде. Из мугI ший долаш тайпара дита</pre>",
- "tag-filter": "[[Special:Tags|белгалонай]] лÑ\83Ñ\82Ñ\82аÑ\80г:",
+ "tag-filter": "[[Special:Tags|Ð\91елгалонай]] Ñ\84илÑ\8cÑ\82Ñ\80:",
"tag-filter-submit": "ЦIенъе",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|1=Белгало|Белгалонаш}}]]: $2)",
"tags-title": "Йоазонаш",
"tags-hitcount-header": "Белгалаяь хувцамаш",
"tags-edit": "хувца",
"tags-hitcount": "$1 {{PLURAL:$1|1=хувцам|хувцамаш}}",
- "compare-page1": "1. ОагIув",
- "compare-page2": "2. ОагIув",
+ "tags-create-submit": "Хьакхолла",
+ "compare-page1": "ЦхьоаллагIа оагIув",
+ "compare-page2": "ШоллагIа оагӀув",
"compare-rev1": "1. Доржам",
"compare-rev2": "2. Доржам",
"htmlform-submit": "ДIадахьийта",
"htmlform-reset": "Хувцамаш юхадаккха",
"htmlform-selectorother-other": "Кхыдола",
"logentry-delete-delete": "$1 {{GENDER:$2|дIаяккхай}} оагIув $3",
- "logentry-newusers-create": "{{GENDER:$2|Доакъашхочо кхеллай}} учёта яздар $1",
+ "logentry-move-move": "$1 {{GENDER:$2|цӀи хийцай}} $3 → $4",
+ "logentry-newusers-create": "{{GENDER:$2|Доакъашхочо хьакхеллад}} дагара йоазув $1",
+ "logentry-upload-upload": "$1 {{GENDER:$2|чуяьккхай}} $3",
"rightsnone": "(а)",
"revdelete-summary": "хувцамий лоацам",
"searchsuggest-search": "Лахар",
+ "pagelang-name": "ОагIув",
"special-characters-group-latin": "Лаьтмий",
"special-characters-group-greek": "Джелтий",
"special-characters-group-cyrillic": "Цырилиций",
"noname": "Vu ne donis valida uzantonomo.",
"loginsuccesstitle": "Eniro sucesoza",
"loginsuccess": "'''Vu eniris a {{SITENAME}} kom \"$1\".'''",
- "nosuchuser": "Ne existas uzanto \"$1\".\nUzanto-nomi esas mayu/minuskulo-distingenda.\nKontrolez vua espelado, o [[Special:UserLogin/signup|krear nova konto]].",
+ "nosuchuser": "Ne existas uzanto \"$1\".\nUzanto-nomi esas mayu/minuskulo-distingenda.\nKontrolez vua espelado, o [[Special:CreateAccount|krear nova konto]].",
"nosuchusershort": "Esas nula uzanto \"$1\".\nKontrolez la espelado.",
"nouserspecified": "Vu mustas specigar uzantonomo.",
"wrongpassword": "La skribita pasovorto esis nekorekta. Voluntez probar itere.",
"tog-ccmeonemails": "Senda mér afrit af tölvupóstum sem ég sendi öðrum notendum",
"tog-diffonly": "Ekki sýna síðuefni undir mismunum",
"tog-showhiddencats": "Sýna falda flokka",
- "tog-norollbackdiff": "Sleppa breytingu eftir að endurvakning síðu hefur verið gerð.",
+ "tog-norollbackdiff": "Ekki sýna breytingu eftir að endurvakning síðu hefur verið gerð.",
"tog-useeditwarning": "Vara mig við þegar ég fer frá breytingarsíðu með óvistaðar breytingar",
"tog-prefershttps": "Alltaf nota örugga tengingu við innskráningu",
"underline-always": "Alltaf",
"noname": "Þú hefur ekki tilgreint gilt notandanafn.",
"loginsuccesstitle": "Innskráning tókst",
"loginsuccess": "'''Þú ert nú innskráð(ur) á {{SITENAME}} sem „$1“.'''",
- "nosuchuser": "Það er enginn notandi með þetta nafn: \"$1\".\nGerður er greinarmunur á há- og lágstöfum.\nAthugaðu hvort um innsláttavillu er að ræða eða [[Special:UserLogin/signup|búðu til nýtt notandanafn]].",
+ "nosuchuser": "Það er enginn notandi með þetta nafn: „$1“.\nGerður er greinarmunur á há- og lágstöfum.\nAthugaðu hvort um innsláttavillu er að ræða eða [[Special:CreateAccount|búðu til nýtt notandanafn]].",
"nosuchusershort": "Það er enginn notandi með nafnið „$1“. Athugaðu hvort nafnið sé ritað rétt.",
"nouserspecified": "Þú verður að taka fram notandanafn.",
"login-userblocked": "Þessi notandi hefur verið settur í bann. Innskráning ekki leyfð.",
"noemail": "Það er ekkert netfang skráð fyrir notandan \"$1\".",
"noemailcreate": "Þú verður að skrá gilt netfang",
"passwordsent": "Nýtt lykilorð var sent á netfangið sem er skráð á „$1“.\nSkráðu þig inn á ný þegar þú hefur móttekið það.",
- "blocked-mailpassword": "Þér er ekki heimilt að gera breytingar frá þessu netfangi og því getur þú ekki fengið nýtt lykilorð í pósti. Þetta er gert til þess að koma í veg fyrir skemmdarverk.",
+ "blocked-mailpassword": "IP-vistfangið þitt hefur verið útilokað frá því að gera breytingar. Til þess að koma í veg fyrir misnotkun er því ekki hægt að nýta sér endurheimtingu lykilorðs frá þessu IP-vistfangi.",
"eauthentsent": "Staðfestingarpóstur hefur verið sendur á uppgefið netfang. Þú verður að fylgja leiðbeiningunum í póstinum til þess að virkja netfangið og staðfesta að það sé örugglega þitt.",
"throttled-mailpassword": "Tölvupóstur til að endursetja lykilorðið hefur þegar verið sent, innan við $1 {{PLURAL:$1|síðasta klukkutímans|síðustu klukkutímanna}}.\nTil að koma í veg fyrir misnotkun, er aðeins einn tölvupóstur sendur {{PLURAL:$1|hvern $1 klukkutíma|hverja $1 klukkutíma}}.",
"mailerror": "Upp kom villa við sendingu tölvupósts: $1",
"resetpass_submit": "Skrifaðu aðgangsorðið og skráðu þig inn",
"changepassword-success": "Það tókst að breyta lykilorðinu þínu!",
"changepassword-throttled": "Þú hefur gert of margar tilraunir til innskráningar að undanförnu.\nBíddu í $1 áður en þú reynir aftur.",
+ "botpasswords": "Lykilorð róbóta",
"botpasswords-label-create": "Búa til",
"botpasswords-label-update": "Uppfæra",
"botpasswords-label-cancel": "Hætta við",
"minoredit": "Þetta er minniháttar breyting",
"watchthis": "Vakta þessa síðu",
"savearticle": "Vista síðu",
+ "publishpage": "Gefa út síðu",
"preview": "Forskoða",
"showpreview": "Forskoða",
"showdiff": "Sýna breytingar",
"accmailtext": "Lykilorðið fyrir [[User talk:$1|$1]] hefur verið sent á $2. Hægt er að breyta því á síðunni ''[[Special:ChangePassword|breyta lykilorði]]'' þegar notandinn hefur skráð sig inn.",
"newarticle": "(Ný)",
"newarticletext": "Þú hefur fylgt tengli á síðu sem ekki er til ennþá.\nÞú getur búið til síðu með þessu nafni með því að skrifa í formið fyrir neðan\n(meiri upplýsingar í [$1 hjálpinni]).\nEf þú hefur óvart villst hingað geturðu notað '''til baka'''-hnappinn í vafranum þínum.",
- "anontalkpagetext": "----''Þetta er spjallsíða fyrir óþekktan notanda sem hefur ekki búið til aðgang ennþá, eða notar hann ekki.\nÞar af leiðandi þurfum við að nota vistfang til að bera kennsli á hann/hana.\nNokkrir notendur geta deilt sama vistfangi.\nEf þú ert óþekktur notandi og finnst að óviðkomandi athugasemdum hafa verið beint að þér, gjörðu svo vel og [[Special:UserLogin/signup|búðu til aðgang]] eða [[Special:UserLogin|skráðu þig inn]] til þess að koma í veg fyrir þennan rugling við aðra óþekkta notendur í framtíðinni.''",
+ "anontalkpagetext": "----\n<em>Þetta er spjallsíða fyrir óþekktan notanda sem hefur ekki búið til aðgang ennþá, eða notar hann ekki.</em>\nÞar af leiðandi þurfum við að nota vistfang til að bera kennsli á hann/hana.\nNokkrir notendur geta deilt sama vistfangi.\nEf þú ert óþekktur notandi og finnst að óviðkomandi athugasemdum hafa verið beint að þér, gjörðu svo vel og [[Special:CreateAccount|búðu til aðgang]] eða [[Special:UserLogin|skráðu þig inn]] til þess að koma í veg fyrir þennan rugling við aðra óþekkta notendur í framtíðinni.",
"noarticletext": "Enginn texti er á þessari síðu enn sem komið er.\nÞú getur [[Special:Search/{{PAGENAME}}|leitað að þessum titli]], í öðrum síðum,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} leitað í tengdum skrám], eða [{{fullurl:{{FULLPAGENAME}}|action=edit}} búið hana til]</span>.",
"noarticletext-nopermission": "Það er enginn texti á þessari síðu eins og er.\nÞú getur [[Special:Search/{{PAGENAME}}|leitað að þessum titli]] í öðrum síðum, eða <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} leitað í tengdum skrám]</span>, en þú hefur ekki réttindi til þess að stofna þessa síðu.",
"missing-revision": "Útgáfa #$1 síðunnar „{{FULLPAGENAME}}\" er ekki til.\n\nÞetta gerist oftast þegar úreld breytingaskrá tengir á síðu sem hefur verið eytt. Frekari upplýsingar eru í [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} eyðingarskránni].",
"userpage-userdoesnotexist": "Notandaaðgangurinn „<nowiki>$1</nowiki>“ er ekki skráður.\nGjörðu svo vel og athugaðu hvort að þú viljir skapa/breyta þessari síðu.",
"userpage-userdoesnotexist-view": "Notandinn \"$1\" er ekki skráður.",
"blocked-notice-logextract": "Þessi notandi er í banni.\nSíðasta færsla notandans úr bannskrá er birt hér fyrir neðan til skýringar:",
- "clearyourcache": "'''Athugaðu:''' Eftir vistun kann að vera að þú þurfir að komast hjá skyndiminni vafrans þíns til að sjá breytingarnar.\n* '''Firefox / Safari:''' Haltu ''Shift'' samtímis og þú smellir á ''Endurhlaða (Reload)'', eða ýttu á annaðhvort ''Ctrl-F5'' eða ''Ctrl-R'' (''⌘-R'' á Mac)\n* '''Google Chrome:''' Ýttu á ''Ctrl-Shift-R'' (''⌘-Shift-R'' á Mac)\n* '''Internet Explorer:''' Haltu ''Ctrl'' samtímis og þú smellir á ''Endurnýja (Refresh)'', eða ýttu á ''Ctrl-F5''\n* '''Opera:''' Hreinsaðu skyndiminnið í ''Verkfæri (Tools) → Stillingar (Preferences)''",
+ "clearyourcache": "<strong>Athugaðu:</strong> Eftir vistun kann að vera að þú þurfir að komast hjá skyndiminni vafrans þíns til að sjá breytingarnar.\n* <strong>Firefox / Safari:</strong> Haltu <em>Shift</em> samtímis og þú smellir á <em>Endurhlaða (Reload)</em>, eða ýttu á annaðhvort <em>Ctrl-F5</em> eða <em>Ctrl-R</em> (<em>⌘-R</em> á Mac)\n* <strong>Google Chrome:</strong> Ýttu á <em>Ctrl-Shift-R </em>(<em>⌘-Shift-R</em> á Mac)\n* <strong>Internet Explorer:</strong> Haltu <em>Ctrl</em> samtímis og þú smellir á <em>Endurnýja (Refresh)</em>, eða ýttu á <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Farðu í <em>Verkfæri (Tools) → Stillingar (Preferences)</em> og svo <em>Friðhelgi og öryggi (Privacy & security) → Hreinsa vafragögn (Clear browsing data) → Myndir og skrár í skyndiminni (Chached images and files)</em>",
"usercssyoucanpreview": "'''Ath:''' Hægt er að nota „{{int:showpreview}}“ hnappinn til að prófa CSS-kóða áður en hann er vistaður.",
"userjsyoucanpreview": "'''Ath:''' Hægt er að nota \"{{int:showpreview}}\" hnappinn til að prófa JavaScript-kóða áður en hann er vistaður.",
"usercsspreview": "'''Mundu að þú ert aðeins að forskoða CSS-kóðann þinn.'''\n'''Hann hefur ekki enn verið vistaður!'''",
"right-override-export-depth": "Flytja út síður með greinum þar sem allt að 5 greinar tengja þær saman.",
"right-sendemail": "Senda tölvupóst til annara notenda",
"right-passwordreset": "Skoða tölvupósta um endurstillingu lykilorðs",
- "right-managechangetags": "Búa til og eyða [[Special:Tags|merkjum]] úr gagnagrunni",
+ "right-managechangetags": "Búa til og (af)virkja [[Special:Tags|merki]] úr gagnagrunni",
"right-applychangetags": "Virkja [[Special:Tags|merki]] ásamt öðrum breytingum",
"grant-group-email": "Senda tölvupóst",
"grant-group-high-volume": "Framkvæma magnaðgerðir",
"action-viewmywatchlist": "skoða vaktlistann þinn",
"action-viewmyprivateinfo": "skoða persónuupplýsingar þínar",
"action-editmyprivateinfo": "breyta persónuupplýsingum þínum",
- "action-managechangetags": "búa til og eyða merkjum úr gagnagrunni",
+ "action-managechangetags": "búa til og (af)virkja merki úr gagnagrunni",
"action-applychangetags": "virkja merki ásamt öðrum breytingum",
"nchanges": "$1 {{PLURAL:$1|breyting|breytingar}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|síðan síðustu heimsókn}}",
"recentchangeslinked-page": "Síðutitill:",
"recentchangeslinked-to": "Sýna breytingar á síðum sem tengjast uppgefinni síðu í staðinn",
"recentchanges-page-added-to-category": "[[:$1]] bætt við flokk",
- "recentchanges-page-added-to-category-bundled": "[[:$1]] og $2 [[Special:WhatLinksHere/$1|{{PLURAL:$2|síðu|síðum}}]] bætt við flokk",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] var bætt við flokk, [[Special:WhatLinksHere/$1|þessi síða innifalin í öðrum síðum]]",
"recentchanges-page-removed-from-category": "[[:$1]] fjarlægð úr flokki",
- "recentchanges-page-removed-from-category-bundled": "[[:$1]] og $2 {{PLURAL:$2|síðu|síðum}} fjarlægð úr flokki",
+ "recentchanges-page-removed-from-category-bundled": "[[:$1]] var fjarlægð úr flokki, [[Special:WhatLinksHere/$1|þessi síða innifalin í öðrum síðum]]",
"autochange-username": "Sjálfvirk MediaWiki-breyting",
"upload": "Hlaða inn skrá",
"uploadbtn": "Hlaða inn skrá",
"upload-form-label-own-work": "Það er mitt eigið verk",
"upload-form-label-infoform-categories": "Flokkar",
"upload-form-label-infoform-date": "Dagsetning",
- "upload-form-label-own-work-message-local": "Ég skil að ég sé að hlaða inn skrá samkvæmt notkunarskilmálum og leyfisskilmálum {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Ef þú getur ekki hlaðið inn þessari skrá samkvæmt reglum {{SITENAME}}, lokaðu þá þessum glugga og reyndu aðra aðferð.",
- "upload-form-label-not-own-work-local-local": "Þú gætir einnig prófað að nota [[Special:Upload|sjálfgefnu innhleðslusíðuna]].",
- "upload-form-label-own-work-message-default": "Ég skil að ég sé að hlaða inn skrá á sameiginlegt vefsvæði. Ég staðfesti að ég sé að gera það samkvæmt notkunarskilmálum og leyfisskilmálum þess.",
- "upload-form-label-not-own-work-message-default": "Ef þú getur ekki hlaðið inn þessari skrá samkvæmt reglum sameiginlega vefsvæðisins, lokaðu þá þessum glugga og reyndu aðra aðferð.",
- "upload-form-label-not-own-work-local-default": "Þú gætir einnig prófað að nota [[Special:Upload|innhleðslusíðuna á {{SITENAME}}]], ef það má hlaða þessari skrá inn samkvæmt reglum þeirra.",
- "upload-form-label-own-work-message-shared": "Ég staðfesti að ég eigi höfundarréttinn að þessari skrá og samþykki óafturkræft að gefa þessa skrá til Wikimedia Commons undir [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] leyfi. Ég samþykki [https://wikimediafoundation.org/wiki/Terms_of_Use notendaskilmálana].",
- "upload-form-label-not-own-work-message-shared": "Ef þú átt ekki höfundarréttinn að þessari skrá, eða þú vilt gefa það út undir öðru leyfi, prófaðu [https://commons.wikimedia.org/wiki/Special:UploadWizard Innsendingaálfinn á Commons].",
- "upload-form-label-not-own-work-local-shared": "Þú gætir einnig prófað að nota [[Special:Upload|innhleðslusíðuna á {{SITENAME}}]], ef það má hlaða þessari skrá inn samkvæmt reglum þeirra.",
+ "upload-form-label-own-work-message-generic-local": "Ég skil að ég sé að hlaða inn skrá samkvæmt notkunarskilmálum og leyfisskilmálum {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Ef þú getur ekki hlaðið inn þessari skrá samkvæmt reglum {{SITENAME}}, lokaðu þá þessum glugga og reyndu aðra aðferð.",
+ "upload-form-label-not-own-work-local-generic-local": "Þú gætir einnig prófað að nota [[Special:Upload|sjálfgefnu innhleðslusíðuna]].",
+ "upload-form-label-own-work-message-generic-foreign": "Ég skil að ég sé að hlaða inn skrá á sameiginlegt vefsvæði. Ég staðfesti að ég sé að gera það samkvæmt notkunarskilmálum og leyfisskilmálum þess.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Ef þú getur ekki hlaðið inn þessari skrá samkvæmt reglum sameiginlega vefsvæðisins, lokaðu þá þessum glugga og reyndu aðra aðferð.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Þú gætir einnig prófað að nota [[Special:Upload|innhleðslusíðuna á {{SITENAME}}]], ef það má hlaða þessari skrá inn samkvæmt reglum þeirra.",
"backend-fail-stream": "Gat ekki streymt skránni „$1“.",
"backend-fail-backup": "Öryggisafritun skrárinnar $1 mistókst.",
"backend-fail-notexists": "Skráin $1 er ekki til.",
"watchlistedit-raw-done": "Vaktlistinn þinn hefur verið uppfærður.",
"watchlistedit-raw-added": "$1 {{PLURAL:$1|síðu|síðum}} var bætt við:",
"watchlistedit-raw-removed": "$1 {{PLURAL:$1|síða var fjarlægð|síður voru fjarlægðar}}:",
- "watchlistedit-clear-title": "Hreinsaður vaktlisti",
+ "watchlistedit-clear-title": "Hreinsa vaktlista",
"watchlistedit-clear-legend": "Hreinsa vaktlista",
"watchlistedit-clear-explain": "Allar síður verða fjarlægðar af vaktlistanum þínum",
"watchlistedit-clear-titles": "Síður:",
"timezone-local": "Staðartími",
"duplicate-defaultsort": "<strong>Viðvörun:</strong> Sjálfgefni röðunarlykillinn \"$2\" er rétthærri en eldri sjálfgefinn röðunarlykill \"$1\".",
"duplicate-displaytitle": "<strong>Viðvörun:</strong> Birtingartitillinn \"$2\" er rétthærri en eldri sjálfgefinn birtingartitill \"$1\".",
+ "restricted-displaytitle": "<strong>Viðvörun:</strong> Sýndi titillinn „$1“ var hunsaður þar sem hann samsvarast ekki raunverulegum titli síðunnar.",
"version": "Útgáfa",
"version-extensions": "Uppsettar viðbætur",
"version-skins": "Uppsett skinn",
"logentry-protect-unprotect": "$1 {{GENDER:$2|fjarlægði}} verndun af $3",
"logentry-protect-protect": "$1 {{GENDER:$2|verndaði}} $3 $4",
"logentry-protect-modify": "$1 {{GENDER:$2|breytti}} verndunarstigi fyrir $3 $4",
- "logentry-rights-rights": "$1 {{GENDER:$2|breytti}} réttindum $3 frá $4 í $5",
+ "logentry-rights-rights": "$1 {{GENDER:$2|breytti}} réttindum {{GENDER:$6|$3}} frá $4 í $5",
"logentry-rights-rights-legacy": "$1 {{GENDER:$2|breytti}} réttindum $3",
"logentry-rights-autopromote": "$1 fékk sjálfvirkt {{GENDER:$2|aukin}} réttindi frá $4 til $5",
"logentry-upload-upload": "$1 {{GENDER:$2|hlóð inn}} $3",
"V6rg",
"JackLantern",
"Mpiva",
- "Urielejh"
+ "Urielejh",
+ "Matma Rex",
+ "Matteocng"
]
},
"tog-underline": "Sottolinea i collegamenti:",
"password-change-forbidden": "Non è possibile modificare le password su questo wiki.",
"externaldberror": "Si è verificato un errore con il server di autenticazione esterno, oppure non si dispone delle autorizzazioni necessarie per aggiornare il proprio accesso esterno.",
"login": "Entra",
+ "login-security": "Verifica la tua identità",
"nav-login-createaccount": "Entra / registrati",
"userlogin": "Entra / registrati",
"userloginnocreate": "Entra",
"userlogin-resetpassword-link": "Hai dimenticato la password?",
"userlogin-helplink2": "Aiuto con l'accesso",
"userlogin-loggedin": "Sei già connesso come {{GENDER:$1|$1}}.\nUsa il modulo sottostante per accedere come altro utente.",
+ "userlogin-reauth": "Devi accedere di nuovo per verificare che sei {{GENDER:$1|$1}}.",
"userlogin-createanother": "Crea un'altra utenza",
"createacct-emailrequired": "Indirizzo email",
"createacct-emailoptional": "Indirizzo di posta elettronica (opzionale)",
"createacct-email-ph": "Inserisci il tuo indirizzo email",
"createacct-another-email-ph": "Inserisci l'indirizzo di posta elettronica",
"createaccountmail": "Usa una password casuale temporanea e inviala all'indirizzo di posta elettronica specificato",
+ "createaccountmail-help": "Può essere utilizzato per creare un'utenza per un'altra persona senza doverne conoscere la password.",
"createacct-realname": "Nome reale (opzionale)",
"createaccountreason": "Motivo:",
"createacct-reason": "Motivo",
"createacct-reason-ph": "Perché stai creando un'altra utenza",
+ "createacct-reason-help": "Messaggio visualizzato nel registro della creazione dell'utenza",
"createacct-submit": "Crea la tua utenza",
"createacct-another-submit": "Crea utenza",
+ "createacct-continue-submit": "Continua la creazione dell'utenza",
+ "createacct-another-continue-submit": "Continua la creazione dell'utenza",
"createacct-benefit-heading": "{{SITENAME}} cresce grazie a persone come te.",
"createacct-benefit-body1": "{{PLURAL:$1|modifica|modifiche}}",
"createacct-benefit-body2": "{{PLURAL:$1|pagina|pagine}}",
"nocookiesnew": "La registrazione è stata completata, ma non è stato possibile accedere a {{SITENAME}} perché i cookie sono disattivati. Riprovare l'accesso con il nome utente e la password appena creati dopo aver attivato i cookie nel proprio browser.",
"nocookieslogin": "L'accesso a {{SITENAME}} richiede l'uso dei cookie, che risultano disattivati. Riprovare l'accesso dopo aver attivato i cookie nel proprio browser.",
"nocookiesfornew": "L'account utente non è stato creato, poiché non abbiamo potuto confermare la sua fonte.\nAssicurati di avere attivato i cookie, ricarica questa pagina e riprova.",
+ "createacct-loginerror": "L'utenza è stata creata correttamente, ma non è stato possibile farti accedere in modo automatico. Procedi con l'[[Special:UserLogin|accesso manuale]].",
"noname": "Il nome utente indicato non è valido.",
"loginsuccesstitle": "Accesso effettuato",
"loginsuccess": "'''Sei stato connesso al server di {{SITENAME}} con il nome utente di \"$1\".'''",
- "nosuchuser": "Non è registrato alcun utente di nome \"$1\".\nI nomi utente sono sensibili alle maiuscole.\nVerificare il nome inserito o [[Special:UserLogin/signup|creare una nuova utenza]].",
+ "nosuchuser": "Non è registrato alcun utente di nome \"$1\".\nI nomi utente sono sensibili alle maiuscole.\nVerificare il nome inserito o [[Special:CreateAccount|creare una nuova utenza]].",
"nosuchusershort": "Non è registrato alcun utente di nome \"$1\". Verificare il nome inserito.",
"nouserspecified": "È necessario specificare un nome utente.",
"login-userblocked": "Questa utenza è bloccata. Non è possibile effettuare il login.",
"createacct-another-realname-tip": "L'indicazione del proprio nome vero è opzionale; se si sceglie di inserirlo, verrà utilizzato per attribuire la paternità dei contenuti inviati.",
"pt-login": "Entra",
"pt-login-button": "Entra",
+ "pt-login-continue-button": "Continua l'accesso",
"pt-createaccount": "Registrati",
"pt-userlogout": "esci",
"php-mail-error-unknown": "Errore sconosciuto nella funzione PHP mail()",
"botpasswords-invalid-name": "Il nome utente indicato non contiene il separatore per password bot (\"$1\").",
"botpasswords-not-exist": "L'utente \"$1\" non dispone di una password bot chiamata \"$2\".",
"resetpass_forbidden": "Non è possibile modificare le password",
+ "resetpass_forbidden-reason": "Non è possibile modificare le password: $1",
"resetpass-no-info": "Devi aver effettuato l'accesso per accedere a questa pagina direttamente.",
"resetpass-submit-loggedin": "Cambia password",
"resetpass-submit-cancel": "Annulla",
"passwordreset-emailsentusername": "Se c'è un indirizzo di posta elettronica associato con questo nome utente, allora verrà inviata una email per reimpostare la password.",
"passwordreset-emailsent-capture": "È stata inviata una email di reimpostazione della password, il contenuto è riportato di seguito.",
"passwordreset-emailerror-capture": "È stata generata una email di reimpostazione della password, riportata di seguito. L'invio {{GENDER:$2|all'utente}} non è riuscito: $1",
+ "passwordreset-emailsent-capture2": "L'email di reimpostazione della password {{PLURAL:$1|è stata inviata|sono state inviate}}. {{PLURAL:$1|Il nome|L'elenco di nomi}} utente e password è mostrato di seguito.",
+ "passwordreset-emailerror-capture2": "Invio di email {{GENDER:$2|all'utente}} non riuscito: $1. {{PLURAL:$3|Il nome|L'elenco di nomi}} utente e password è mostrato di seguito.",
+ "passwordreset-nocaller": "Un chiamante deve essere fornito",
+ "passwordreset-nosuchcaller": "Chiamante non esiste: $1",
+ "passwordreset-ignored": "La reimpostazione della password non è stata gestita. Forse nessun provider è configurato?",
+ "passwordreset-invalideamil": "Indirizzo di posta elettronica non valido",
+ "passwordreset-nodata": "Non è stato fornito né un nome utente né un indirizzo di posta elettronica",
"changeemail": "Modifica o rimuovi indirizzo di posta elettronica",
"changeemail-header": "Completa questo modulo per cambiare il tuo indirizzo email. Se vuoi rimuovere l'associazione di qualsiasi indirizzo email dalla tua utenza, lascia il nuovo indirizzo email vuoto quando invii il modulo.",
"changeemail-passwordrequired": "Sarà necessario inserire la password per confermare la modifica.",
"accmailtext": "Una password generata casualmente per [[User talk:$1|$1]] è stata inviata a $2. Questa password può essere modificata nella pagina per ''[[Special:ChangePassword|cambiare la password]]'' subito dopo l'accesso.",
"newarticle": "(Nuovo)",
"newarticletext": "Il collegamento appena seguito corrisponde ad una pagina non ancora esistente.\nSe vuoi creare la pagina ora, basta cominciare a scrivere il testo nella casella qui sotto (vedi la [$1 pagina di aiuto] per maggiori informazioni).\nSe il collegamento è stato aperto per errore, è sufficiente fare clic sul pulsante <strong>Indietro</strong> del proprio browser.",
- "anontalkpagetext": "----\n''Questa è la pagina di discussione di un utente anonimo, che non ha ancora creato un'utenza o comunque non la sta usando. Per identificarlo è quindi necessario usare il numero del suo indirizzo IP. Gli indirizzi IP possono però essere condivisi da più utenti. Se sei un utente anonimo e ritieni che i commenti presenti in questa pagina non si riferiscano a te, [[Special:UserLogin/signup|crea una nuova utenza]] o [[Special:UserLogin|entra con quella che già hai]] per evitare di essere confuso con altri utenti anonimi in futuro.''",
+ "anontalkpagetext": "----\n<em>Questa è la pagina di discussione di un utente anonimo, che non ha ancora creato un'utenza o comunque non la sta usando.</em>\nPer identificarlo è quindi necessario usare il numero del suo indirizzo IP.\nGli indirizzi IP possono però essere condivisi da più utenti.\nSe sei un utente anonimo e ritieni che i commenti presenti in questa pagina non si riferiscano a te, [[Special:CreateAccount|crea una nuova utenza]] o [[Special:UserLogin|entra con quella che già hai]] per evitare di essere confuso con altri utenti anonimi in futuro.",
"noarticletext": "In questo momento la pagina richiesta è vuota.\nPuoi [[Special:Search/{{PAGENAME}}|cercare questo titolo]] nelle altre pagine del sito, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cercare nei registri correlati] oppure [{{fullurl:{{FULLPAGENAME}}|action=edit}} creare questa pagina]</span>.",
"noarticletext-nopermission": "In questo momento la pagina richiesta è vuota. È possibile [[Special:Search/{{PAGENAME}}|cercare questo titolo]] nelle altre pagine del sito o <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cercare nei registri correlati]</span>, ma non hai i permessi per creare questa pagina.",
"missing-revision": "La versione #$1 della pagina \"{{FULLPAGENAME}}\" non esiste.\n\nQuesto si verifica solitamente seguendo un collegamento a una pagina cancellata, in una cronologia non aggiornata.\nI dettagli possono essere trovati nel [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro delle cancellazioni].",
"right-override-export-depth": "Esporta le pagine includendo le pagine collegate fino ad una profondità di 5",
"right-sendemail": "Invia email ad altri utenti",
"right-passwordreset": "Vede i messaggi di reimpostazione della password",
- "right-managechangetags": "Crea ed elimina dal database i [[Special:Tags|tag]]",
+ "right-managechangetags": "Crea e attiva/disattiva le [[Special:Tags|etichette]]",
"right-applychangetags": "Applica delle [[Special:Tags|etichette]] alle proprie modifiche",
"right-changetags": "Aggiunge e rimuove specifiche [[Special:Tags|etichette]] su singole versioni o voci di registro",
+ "right-deletechangetags": "Cancella le [[Special:Tags|etichette]] dal database",
"grant-generic": "Pacchetto diritti \"$1\"",
"grant-group-page-interaction": "Interagisce con le pagine",
"grant-group-file-interaction": "Interagisce con i file multimediali",
"action-viewmyprivateinfo": "vedere i propri dati personali",
"action-editmyprivateinfo": "modificare i propri dati personali",
"action-editcontentmodel": "modificare il modello di contenuto di una pagina",
- "action-managechangetags": "crea ed elimina i tag dal database",
+ "action-managechangetags": "creare e attivare/disattivare le etichette",
"action-applychangetags": "applicare delle etichette alle tue modifiche",
"action-changetags": "aggiungere o rimuovere specifiche etichette su singole versioni o voci di registro",
+ "action-deletechangetags": "cancellare le etichette dal database",
"nchanges": "$1 {{PLURAL:$1|modifica|modifiche}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|dall'ultima visita}}",
"enhancedrc-history": "cronologia",
"upload-form-label-infoform-description-tooltip": "Descrivi sinteticamente tutto quanto sia degno di nota a proposito di quest'opera.\nPer le foto, indica le cose principali che vi sono rappresentate, l'occasione e/o il luogo in cui sono state scattate.",
"upload-form-label-usage-title": "Utilizzo",
"upload-form-label-usage-filename": "Nome del file",
- "upload-form-label-own-work": "Questo è un mio lavoro",
+ "upload-form-label-own-work": "Questa è una mia opera creativa",
"upload-form-label-infoform-categories": "Categorie",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-own-work-message-local": "Confermo che sto caricando questo file seguendo le condizioni di servizio e le politiche sulle license di {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Se non si è in grado di caricare il file in base alle politiche di {{SITENAME}}, chiudi questa finestra e prova un altro metodo.",
- "upload-form-label-not-own-work-local-local": "Puoi anche provare la [[Special:Upload|pagina di caricamento predefinita]].",
- "upload-form-label-own-work-message-default": "Ho capito che sto caricando questo file in un archivio condiviso. Confermo che lo sto facendo secondo le condizioni di servizio e le politiche sulle license di lì.",
- "upload-form-label-not-own-work-message-default": "Se non si è in grado di caricare il file in base alle politiche dell'archivio condiviso, chiudi questa finestra e prova un altro metodo.",
- "upload-form-label-not-own-work-local-default": "Puoi anche provare ad usare la [[Special:Upload|pagina di caricamento su {{SITENAME}}]], se questo file può essere caricato in base alle sue politiche.",
- "upload-form-label-own-work-message-shared": "Attesto che possiedo i diritti d'autore su questo file, e accetto irrevocabilmente il rilascio di questo file su Wikimedia Commons in base alla licenza [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribuzione-Condividi allo stesso modo 4.0], e accetto le [https://wikimediafoundation.org/wiki/Terms_of_Use Condizioni d'uso].",
- "upload-form-label-not-own-work-message-shared": "Se non possiedi i diritti d'autore su questo file, o se lo vuoi rilasciare con una licenza diversa, usa il [https://commons.wikimedia.org/wiki/Special:UploadWizard caricamento guidato di Commons].",
- "upload-form-label-not-own-work-local-shared": "Puoi anche provare ad usare la [[Special:Upload|pagina di caricamento su {{SITENAME}}]], se il sito consente il caricamento di questo file in base alle sue politiche.",
+ "upload-form-label-own-work-message-generic-local": "Confermo che sto caricando questo file seguendo le condizioni di servizio e le politiche sulle license di {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Se non si è in grado di caricare il file in base alle politiche di {{SITENAME}}, chiudi questa finestra e prova un altro metodo.",
+ "upload-form-label-not-own-work-local-generic-local": "Puoi anche provare la [[Special:Upload|pagina di caricamento predefinita]].",
+ "upload-form-label-own-work-message-generic-foreign": "Ho capito che sto caricando questo file in un archivio condiviso. Confermo che lo sto facendo secondo le condizioni di servizio e le politiche sulle license di lì.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Se non si è in grado di caricare il file in base alle politiche dell'archivio condiviso, chiudi questa finestra e prova un altro metodo.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Puoi anche provare ad usare la [[Special:Upload|pagina di caricamento su {{SITENAME}}]], se questo file può essere caricato in base alle sue politiche.",
"backend-fail-stream": "Impossibile trasmettere il file $1.",
"backend-fail-backup": "Impossibile eseguire il backup del file $1 .",
"backend-fail-notexists": "Il file $1 non esiste.",
"trackingcategories-msg": "Categoria di monitoraggio",
"trackingcategories-name": "Nome del messaggio",
"trackingcategories-desc": "Criteri per l'inclusione nella categoria",
+ "restricted-displaytitle-ignored": "Pagine con titoli da visualizzare ignorati.",
+ "restricted-displaytitle-ignored-desc": "La pagina ha un <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> ignorato perché non è equivalente all'effettivo titolo della pagina.",
"noindex-category-desc": "La pagina non è indicizzata dai robot perché contiene la parola magica <code><nowiki>__NOINDEX__</nowiki></code> e si trova in un namespace dove tale flag è consentito.",
"index-category-desc": "La pagina contiene <code><nowiki>__INDEX__</nowiki></code> (e si trova in un namespace dove tale flag è consentito) e quindi è indicizzata dai robot, anche se normalmente non lo sarebbe.",
"post-expand-template-inclusion-category-desc": "La dimensione della pagina sarà più grande di <code>$wgMaxArticleSize</code> dopo aver espanso tutti i template, e dunque alcuni non si espanderanno.",
"rollbacklinkcount": "rollback di {{PLURAL:$1|una modifica|$1 modifiche}}",
"rollbacklinkcount-morethan": "rollback di più di {{PLURAL:$1|una modifica|$1 modifiche}}",
"rollbackfailed": "Rollback fallito",
+ "rollback-missingparam": "Parametri obbligatori mancanti nella richiesta.",
"cantrollback": "Impossibile annullare le modifiche; l'utente che le ha effettuate è l'unico ad aver contribuito alla pagina.",
"alreadyrolled": "Non è possibile annullare le modifiche apportate alla pagina [[:$1]] da parte di [[User:$2|$2]] ([[User talk:$2|discussione]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]); un altro utente ha già modificato la pagina oppure ha effettuato il rollback.\n\nLa modifica più recente alla pagina è stata apportata da [[User:$3|$3]] ([[User talk:$3|discussione]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "L'oggetto della modifica era: <em>$1</em>.",
"revertpage": "Annullate le modifiche di [[Special:Contributions/$2|$2]] ([[User talk:$2|discussione]]), riportata alla versione precedente di [[User:$1|$1]]",
"revertpage-nouser": "Annullate le modifiche di un utente nascosto, riportata alla versione precedente di {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Annullate le modifiche di $1; pagina riportata all'ultima versione di $2.",
+ "rollback-success-notify": "Annullate le modifiche di $1;\npagina riportata all'ultima revisione di $2. [$3 Mostra le modifiche]",
"sessionfailure-title": "Sessione fallita",
"sessionfailure": "Si è verificato un problema nella sessione che identifica l'accesso; il sistema non ha eseguito il comando impartito per precauzione. Tornare alla pagina precedente con il tasto 'Indietro' del proprio browser, ricaricare la pagina e riprovare.",
"changecontentmodel": "Modifica il modello di contenuto di una pagina",
"changecontentmodel-success-text": "Il tipo di contenuto di [[:$1]] è stato modificato.",
"changecontentmodel-cannot-convert": "Il contenuto di [[:$1]] non può essere convertito in tipo $2.",
"changecontentmodel-nodirectediting": "Il modello di contenuto $1 non supporta la modifica diretta",
+ "changecontentmodel-emptymodels-title": "Nessun modello di contenuto disponibile",
+ "changecontentmodel-emptymodels-text": "Il contenuto di [[:$1]] non può essere convertito in alcun tipo.",
"log-name-contentmodel": "Modifiche del modello contenuti",
"log-description-contentmodel": "Eventi relativi al modello di contenuto di una pagina",
"logentry-contentmodel-new": "$1 {{GENDER:$2|ha creato}} la pagina $3 utilizzando un modello di contenuto non predefinito \"$5\"",
"whatlinkshere-hideredirs": "$1 redirect",
"whatlinkshere-hidetrans": "$1 inclusioni",
"whatlinkshere-hidelinks": "$1 collegamenti",
- "whatlinkshere-hideimages": "$1 link da file",
+ "whatlinkshere-hideimages": "$1 collegamenti da file",
"whatlinkshere-filters": "Filtri",
"whatlinkshere-submit": "Vai",
"autoblockid": "Autoblocco #$1",
"lockdbsuccesstext": "Il database è stato bloccato.<br />\nRicordare di [[Special:UnlockDB|rimuovere il blocco]] dopo aver terminato le operazioni di manutenzione.",
"unlockdbsuccesstext": "Il database è stato sbloccato.",
"lockfilenotwritable": "Impossibile scrivere sul file di ''lock'' del database. L'accesso in scrittura a tale file da parte del server web è necessario per bloccare e sbloccare il database.",
+ "databaselocked": "Il database è già bloccato.",
"databasenotlocked": "Il database non è bloccato.",
"lockedbyandtime": "(da $1 il $2 alle $3)",
"move-page": "Spostamento di $1",
"confirm-watch-top": "Aggiungi questa pagina alla tua lista degli osservati speciali?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Elimina questa pagina dalla tua lista degli osservati speciali?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Ripristinare le modifiche a questa pagina?",
"percent": "$1 %",
"quotation-marks": "«$1»",
"imgmultipageprev": "← pagina precedente",
"autoredircomment": "Redirect alla pagina [[$1]]",
"autosumm-new": "Creata pagina con \"$1\"",
"autosumm-newblank": "Creata pagina vuota",
- "size-bytes": "$1 byte",
+ "size-bytes": "$1 {{PLURAL:$1|byte}}",
"lag-warn-normal": "Le modifiche apportate {{PLURAL:$1|nell'ultimo secondo|negli ultimi $1 secondi}} potrebbero non apparire in questa lista.",
"lag-warn-high": "A causa di un eccessivo ritardo nell'aggiornamento del server di database, le modifiche apportate {{PLURAL:$1|nell'ultimo secondo|negli ultimi $1 secondi}} potrebbero non apparire in questa lista.",
"watchlistedit-normal-title": "Modifica osservati speciali",
"timezone-local": "Locale",
"duplicate-defaultsort": "Attenzione: la chiave di ordinamento predefinita \"$2\" sostituisce la precedente \"$1\".",
"duplicate-displaytitle": "<strong>Attenzione:</strong> il titolo visualizzato \"$2\" sostituisce il precedente titolo \"$1\".",
+ "restricted-displaytitle": "<strong>Attenzione:</strong> Il titolo visualizzato \"$1\" è stato ignorato poiché non equivalente al titolo attuale della pagina.",
"invalid-indicator-name": "<strong>Errore:</strong> attributo <code>name</code> degli indicatori dello stato della pagina non può essere vuoto.",
"version": "Versione",
"version-extensions": "Estensioni installate",
"tags-activate": "attiva",
"tags-deactivate": "disattiva",
"tags-hitcount": "$1 {{PLURAL:$1|modifica|modifiche}}",
- "tags-manage-no-permission": "Non hai il permesso di gestire il cambiamento tag.",
+ "tags-manage-no-permission": "Non si dispone dei permessi necessari per gestire le etichette di modifica.",
"tags-manage-blocked": "Non puoi gestire le etichette alle modifiche mentre sei bloccato.",
"tags-create-heading": "Crea un nuovo tag",
"tags-create-explanation": "Per impostazione predefinita, i tag appena creati saranno disponibili per l'utilizzo di utenti e bot.",
"tags-delete-not-found": "Il tag \"$1\" non esiste.",
"tags-delete-too-many-uses": "Il tag \"$1\" è applicato a più di $2 {{PLURAL:$2|revisione|revisioni}}, il che significa che non può essere eliminato.",
"tags-delete-warnings-after-delete": "L'etichetta \"$1\" è stata cancellata, ma fai attenzione {{PLURAL:$2|al seguente avviso|ai seguenti avvisi}}:",
+ "tags-delete-no-permission": "Non si dispone dei permessi necessari per cancellare le etichette di modifica.",
"tags-activate-title": "Attiva tag",
"tags-activate-question": "Stai per attivare il tag \"$1\".",
"tags-activate-reason": "Motivo:",
"tags-apply-blocked": "Non puoi applicare le etichette alle modifiche mentre sei bloccato.",
"tags-apply-not-allowed-one": "L'etichetta \"$1\" non può essere applicata manualmente.",
"tags-apply-not-allowed-multi": "{{PLURAL:$2|La seguente etichetta non può essere applicata|Le seguenti etichette non possono essere applicate}} manualmente: $1",
- "tags-update-no-permission": "Non hai il permesso di aggiungere o rimuovere modifiche di tag dalle singole revisioni o voci di registro.",
+ "tags-update-no-permission": "Non si dispone dei permessi necessari per aggiungere o rimuovere le etichette di modifica dalle singole versioni o voci di registro.",
"tags-update-blocked": "Non puoi aggiungere o rimuovere le etichette alle modifiche mentre sei bloccato.",
"tags-update-add-not-allowed-one": "Il tag \"$1\" non può essere aggiunto manualmente.",
"tags-update-add-not-allowed-multi": "{{PLURAL:$2|Il seguente tag non può essere aggiunto|I seguenti tag non possono essere aggiunti}} manualmente: $1",
"api-error-nomodule": "Errore interno: non è stato impostato il modulo di caricamento.",
"api-error-ok-but-empty": "Errore interno: nessuna risposta dal server.",
"api-error-overwrite": "Sovrascrivere un file esistente non è consentito.",
+ "api-error-ratelimited": "Stai cercando di caricare più file in meno tempo di quanto questo wiki permette.\nRiprova tra pochi minuti.",
"api-error-stashfailed": "Errore interno: il server non è riuscito a memorizzare il documento temporaneo.",
"api-error-publishfailed": "Errore interno: il server non è riuscito a pubblicare il documento temporaneo.",
"api-error-stasherror": "Si è verificato un errore durante il caricamento del file in stash.",
"log-action-filter-suppress-block": "Soppressione utente da blocco",
"log-action-filter-suppress-reblock": "Soppressione utente da ri-blocco",
"log-action-filter-upload-upload": "Nuovo caricamento",
- "log-action-filter-upload-overwrite": "Ricaricamento"
+ "log-action-filter-upload-overwrite": "Ricaricamento",
+ "authmanager-authn-not-in-progress": "L'autenticazione non è in corso o i dati della sessione sono andati persi. Si prega di ricominciare dall'inizio.",
+ "authmanager-authn-no-primary": "Le credenziali fornite non possono essere autenticate.",
+ "authmanager-authn-no-local-user": "Le credenziali fornite non sono associate a nessun utente di questo wiki.",
+ "authmanager-authn-no-local-user-link": "Le credenziali fornite sono valide ma non sono associate a nessun utente di questa wiki. Accedi in un modo diverso o crea un nuovo utente, e avrai un'opzione per collegare le tue credenziali precedenti a quell'utenza.",
+ "authmanager-authn-autocreate-failed": "Creazione automatica di un'utenza locale fallita: $1",
+ "authmanager-change-not-supported": "Le credenziali fornite non possono essere modificate, dato che non verrebbero usate da nulla.",
+ "authmanager-create-disabled": "La creazione di utenze è disabilitata.",
+ "authmanager-create-from-login": "Per creare la tua utenza, completa i campi qui sotto.",
+ "authmanager-create-not-in-progress": "La creazione di un'utenza non è in corso o i dati della sessione sono andati persi. Si prega di ricominciare nuovamente dall'inizio.",
+ "authmanager-create-no-primary": "Le credenziali fornite non possono essere utilizzate per la creazione dell'utenza.",
+ "authmanager-link-no-primary": "Le credenziali fornite non possono essere utilizzate per il collegamento dell'utenza.",
+ "authmanager-link-not-in-progress": "Il collegamento dell'utenza non è in corso o i dati della sessione sono andati persi. Si prega di ricominciare dall'inizio.",
+ "authmanager-authplugin-setpass-failed-title": "Modifica della password fallita",
+ "authmanager-authplugin-setpass-failed-message": "Il plugin di autenticazione ha impedito la modifica della password.",
+ "authmanager-authplugin-create-fail": "Il plugin di autenticazione ha impedito la creazione dell'utenza.",
+ "authmanager-authplugin-setpass-denied": "Il plugin di autenticazione non consente di cambiare le password.",
+ "authmanager-authplugin-setpass-bad-domain": "Dominio non valido.",
+ "authmanager-autocreate-noperm": "La creazione automatica dell'utenza non è permessa.",
+ "authmanager-autocreate-exception": "La creazione automatica di utenze è temporaneamente disabilitata a causa di errori precedenti.",
+ "authmanager-userdoesnotexist": "L'utenza \"$1\" non è registrata.",
+ "authmanager-userlogin-remembermypassword-help": "Se la password deve essere ricordata più a lungo rispetto alla durata della sessione.",
+ "authmanager-username-help": "Nome utente per l'autenticazione.",
+ "authmanager-password-help": "Password per l'autenticazione.",
+ "authmanager-domain-help": "Dominio per l'autenticazione esterna.",
+ "authmanager-retype-help": "Conferma nuovamente la password.",
+ "authmanager-email-label": "Email",
+ "authmanager-email-help": "Indirizzo email",
+ "authmanager-realname-label": "Nome reale",
+ "authmanager-realname-help": "Nome reale dell'utente",
+ "authmanager-provider-password": "Autenticazione basata su password",
+ "authmanager-provider-password-domain": "Autenticazione con password o basata su dominio",
+ "authmanager-provider-temporarypassword": "Password temporanea",
+ "authprovider-confirmlink-message": "Basandosi sui recenti tentativi di accesso, le seguenti utenze possono essere collegate al tuo account wiki. Collegarle ti consente di effettuare l'accesso tramite di esse. Si prega di selezionare quelle che devono essere collegate.",
+ "authprovider-confirmlink-request-label": "Utenze che dovrebbero essere collegate",
+ "authprovider-confirmlink-success-line": "$1: collegato correttamente.",
+ "authprovider-confirmlink-failed": "Il collegamento dell'utenza non è pienamente riuscito: $1",
+ "authprovider-confirmlink-ok-help": "Continua dopo la visualizzazione di messaggi di errore di collegamento.",
+ "authprovider-resetpass-skip-label": "Salta",
+ "authprovider-resetpass-skip-help": "Salta reimpostazione della password.",
+ "authform-nosession-login": "L'autenticazione ha avuto successo, ma il tuo browser non è in grado di \"ricordare\" che ti sei collegato.\n\n$1",
+ "authform-nosession-signup": "L'utenza è stata creata, ma il tuo browser non è in grado di \"ricordare\" che ti sei collegato.\n\n$1",
+ "authform-newtoken": "Token mancante. $1",
+ "authform-notoken": "Token mancante",
+ "authform-wrongtoken": "Token errato",
+ "specialpage-securitylevel-not-allowed-title": "Non consentito",
+ "specialpage-securitylevel-not-allowed": "Siamo spiacenti, non sei autorizzato ad utilizzare questa pagina perché la tua identità non può essere verificata.",
+ "authpage-cannot-login": "Impossibile avviare l'accesso.",
+ "authpage-cannot-login-continue": "Impossibile continuare l'accesso. La tua sessione è probabilmente scaduta.",
+ "authpage-cannot-create": "Impossibile iniziare la creazione dell'utenza.",
+ "authpage-cannot-create-continue": "Impossibile continuare la creazione dell'utenza. La tua sessione è probabilmente scaduta.",
+ "authpage-cannot-link": "Impossibile avviare il collegamento dell'utenza.",
+ "authpage-cannot-link-continue": "Impossibile continuare il collegamento dell'utenza. La tua sessione è probabilmente scaduta.",
+ "cannotauth-not-allowed-title": "Permesso negato",
+ "cannotauth-not-allowed": "Non sei autorizzato a utilizzare questa pagina",
+ "changecredentials": "Modifica credenziali",
+ "changecredentials-submit": "Modifica credenziali",
+ "changecredentials-invalidsubpage": "$1 non è una tipologia di credenziale valida.",
+ "changecredentials-success": "Le tue credenziali sono state modificate.",
+ "removecredentials": "Rimuovi credenziali",
+ "removecredentials-submit": "Rimuovi credenziali",
+ "removecredentials-invalidsubpage": "$1 non è una tipologia di credenziale valida.",
+ "removecredentials-success": "Le tue credenziali sono state eliminate.",
+ "credentialsform-provider": "Tipo di credenziali:",
+ "credentialsform-account": "Nome utenza:",
+ "cannotlink-no-provider-title": "Non ci sono utenze collegabili",
+ "cannotlink-no-provider": "Non ci sono utenze collegabili.",
+ "linkaccounts": "Collega utenze",
+ "linkaccounts-success-text": "L'utenza è stata collegata.",
+ "linkaccounts-submit": "Collega utenze",
+ "unlinkaccounts": "Scollega utenze",
+ "unlinkaccounts-success": "L'utenza è stata scollegata."
}
"Sujiniku",
"Azeha",
"Kana Higashikawa",
- "Shield-9"
+ "Shield-9",
+ "Waiesu",
+ "Matma Rex"
]
},
"tog-underline": "リンクの下線:",
"tog-ccmeonemails": "他の利用者に送信したメールの控えを自分にも送信",
"tog-diffonly": "差分の下にページ内容を表示しない",
"tog-showhiddencats": "隠しカテゴリを表示",
- "tog-norollbackdiff": "巻き戻し後の差分を表示しない",
+ "tog-norollbackdiff": "ロールバック後の差分を表示しない",
"tog-useeditwarning": "変更を保存せずに編集画面から離れようとしたら警告",
"tog-prefershttps": "ログインする際、常に安全な接続を使用する",
"underline-always": "常に付ける",
"mytalk": "トーク",
"anontalk": "トーク",
"navigation": "案内",
- "and": " ã\81¨",
+ "and": " ã\81\8aã\82\88ã\81³",
"qbfind": "検索",
"qbbrowse": "閲覧",
"qbedit": "編集",
"noname": "有効な利用者名が指定されていません。",
"loginsuccesstitle": "ログイン済み",
"loginsuccess": "<strong>{{SITENAME}}に「$1」としてログインしました。</strong>",
- "nosuchuser": "「$1」という名前の利用者は見当たりません。\n利用者名では大文字と小文字を区別します。\n綴りが正しいことを確認するか、[[Special:UserLogin/signup|新たにアカウントを作成]]してください。",
+ "nosuchuser": "「$1」という名前の利用者は見当たりません。\n利用者名では大文字と小文字を区別します。\n綴りが正しいことを確認するか、[[Special:CreateAccount|新たにアカウントを作成]]してください。",
"nosuchusershort": "「$1」という名前の利用者は存在しません。\n綴りを確認してください。",
"nouserspecified": "利用者名を指定してください。",
"login-userblocked": "この利用者はブロックされています。ログインは拒否されます。",
"minoredit": "細部の編集",
"watchthis": "このページをウォッチ",
"savearticle": "ページを保存",
+ "publishpage": "ページを公開",
"preview": "プレビュー",
"showpreview": "プレビューを表示",
"showdiff": "差分を表示",
"accmailtext": "[[User talk:$1|$1]]のために無作為に生成したパスワードを、$2に送信しました。パスワードは、ログインした際に<em>[[Special:ChangePassword|パスワード変更]]</em>ページで変更できます。",
"newarticle": "(新)",
"newarticletext": "まだ存在しないページへのリンクをたどりました。\nこのページを新規作成するには、ページの内容を以下のボックスに記入してください (詳しくは[$1 ヘルプページ]を参照してください)。\n誤ってこのページにたどり着いた場合には、ブラウザーの<strong>戻る</strong>ボタンで前のページに戻ってください。",
- "anontalkpagetext": "----\n<em>このページはアカウントをまだ作成していないか使用していない匿名利用者のための議論ページです。</em>\n\n匿名利用者を識別するために、利用者名の代わりにIPアドレスが使用されています。IP アドレスは複数の利用者で共有されている場合があります。もし、あなたが匿名利用者であり、自分に関係のないコメントが寄せられていると考えられる場合は、[[Special:UserLogin/signup|アカウントを作成する]]か[[Special:UserLogin|ログインして]]他の匿名利用者と間違えられないようにしてください。",
+ "anontalkpagetext": "----\n<em>このページはアカウントをまだ作成していないか使用していない匿名利用者のための議論ページです。</em>\n\n匿名利用者を識別するために、利用者名の代わりにIPアドレスが使用されています。IP アドレスは複数の利用者で共有されている場合があります。もし、あなたが匿名利用者であり、自分に関係のないコメントが寄せられていると考えられる場合は、[[Special:CreateAccount|アカウントを作成する]]か[[Special:UserLogin|ログインして]]他の匿名利用者と間違えられないようにしてください。",
"noarticletext": "現在このページには内容がありません。\n他のページ内で[[Special:Search/{{PAGENAME}}|このページ名を検索]]、\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 関連する記録を検索]、\nまたは[{{fullurl:{{FULLPAGENAME}}|action=edit}} このページを作成]</span>できます。",
"noarticletext-nopermission": "現在このページには内容がありません。\n他のページ内で[[Special:Search/{{PAGENAME}}|このページ名を検索]]、または<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 関連する記録を検索]</span>できますが、あなたにはこのページを作成する権限がありません。",
"missing-revision": "「{{FULLPAGENAME}}」というページの版番号 $1 の版は存在しません。\n\n通常、削除されたページの版への古い差分表示や固定リンクをたどった際に、このようなことが起きます。 \n詳細は[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 削除記録]を参照してください。",
"yourdiff": "差分",
"copyrightwarning": "{{SITENAME}}への投稿はすべて、$2 (詳細は$1を参照)のもとで公開したと見なされることにご注意ください。\n自分が書いたものが他の人に容赦なく編集され、自由に配布されるのを望まない場合は、ここに投稿しないでください。<br />\nまた、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください。\n<strong>著作権保護されている作品は、許諾なしに投稿しないでください!</strong>",
"copyrightwarning2": "{{SITENAME}}への投稿はすべて、他の投稿者によって編集、変更、除去される場合があります。\n自分が書いたものが他の人に容赦なく編集されるのを望まない場合は、ここに投稿しないでください。<br />\nまた、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細は$1を参照)。\n<strong>著作権保護されている作品は、許諾なしに投稿しないでください!</strong>",
- "editpage-cannot-use-custom-model": "ã\81\93ã\81®ã\83\9aã\83¼ã\82¸ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\88ã\83»ã\83¢ã\83\87ã\83«(content model)ã\82\92å¤\89æ\9b´ã\81\99ã\82\8bã\81\93ã\81¨ã\81¯ã\80\81できません。",
+ "editpage-cannot-use-custom-model": "ã\81\93ã\81®ã\83\9aã\83¼ã\82¸ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\84ã\83»ã\83¢ã\83\87ã\83«ã\81¯å¤\89æ\9b´できません。",
"longpageerror": "<strong>エラー: 投稿された文章は {{PLURAL:$1|$1 KB}} の長さがあります。これは投稿できる最大の長さ {{PLURAL:$2|$2 KB}} を超えています。</strong>\nこの編集内容は保存できません。",
"readonlywarning": "<strong>警告: データベースがメンテナンスのためロックされており、現在は編集内容を保存できません。</strong>\n必要であれば文章をコピー&ペーストしてテキストファイルとして保存し、後ほど保存をやり直してください。\n\nデータベースをロックしたシステム管理者による説明は以下の通りです: $1",
"protectedpagewarning": "<strong>警告: このページは保護されているため、管理者権限を持つ利用者のみが編集できます。</strong>\n参考として以下に最後の記録を表示します:",
"content-model-css": "CSS",
"content-json-empty-object": "空のオブジェクト",
"content-json-empty-array": "空の配列",
- "duplicate-args-warning": "<strong>警告:</strong> [[:$1]]は「$3」パラメータの値が複数存在する[[:$2]]を呼び出しています。提供されている最後の値のみが使用されます。",
+ "duplicate-args-warning": "<strong>警告:</strong> [[:$1]]は複数の「$3」パラメータを伴って[[:$2]]を呼び出しています。提供されている最後の値のみが使用されます。",
"duplicate-args-category": "テンプレート呼び出しで引数が重複しているページ",
"duplicate-args-category-desc": "引数が重複したテンプレート呼び出しを含むページ。例: <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code>、<code><nowiki>{{foo|bar|1=baz}}</nowiki></code>",
"expensive-parserfunction-warning": "<strong>警告:</strong> このページでは、高負荷なパーサー関数の呼び出し回数が多過ぎます。\n\n{{PLURAL:$2|呼び出しを $2 回}}未満にしてください ({{PLURAL:$1|現在は $1 回}})。",
"right-override-export-depth": "リンク先ページを5階層まで含めて書き出す",
"right-sendemail": "他の利用者にメールを送信",
"right-passwordreset": "パスワード再設定メールを閲覧",
- "right-managechangetags": "[[Special:Tags|タグ]]のデータベースにおける作成および削除",
+ "right-managechangetags": "[[Special:Tags|タグ]]の作成、有効化および無効化",
"right-applychangetags": "自分の編集に[[Special:Tags|タグ]]を適用する",
"right-changetags": "個々の版と記録項目の任意の[[Special:Tags|タグ]]の追加と削除",
"grant-group-email": "メールの送信",
"action-viewmyprivateinfo": "自分の非公開情報の閲覧",
"action-editmyprivateinfo": "自分の非公開情報の編集",
"action-editcontentmodel": "ページのコンテンツモデルを編集",
- "action-managechangetags": "タグのデータベースにおける作成および削除",
+ "action-managechangetags": "タグの作成、有効化および無効化",
"action-applychangetags": "自分の編集にタグを適用する",
"action-changetags": "個々の版および記録項目への任意のタグの追加と除去",
"nchanges": "$1 {{PLURAL:$1|回の変更}}",
"upload-form-label-own-work": "これはあなた自身による作業です",
"upload-form-label-infoform-categories": "カテゴリ",
"upload-form-label-infoform-date": "日付",
- "upload-form-label-own-work-message-local": "私は {{SITENAME}} 上での以下の利用規約とライセンス方針で、このファイルをアップロードしていることを確認します。",
- "upload-form-label-not-own-work-message-local": "もし、あなたは {{SITENAME}} の方針の下で、このファイルをアップロードすることができない場合には、このダイアログを閉じて、別の方法をお試しください。",
- "upload-form-label-not-own-work-local-local": "また、[[Special:Upload|デフォルトのアップロードページ]]を試してみてください。",
- "upload-form-label-own-work-message-default": "私は共有リポジトリにこのファイルをアップロードしていることを理解しています。私は、そこにサービスやライセンス方針を以下のようにやっていることを、確認します。",
- "upload-form-label-not-own-work-message-default": "もし、あなたは共有リポジトリの方針の下で、このファイルをアップロードすることができない場合には、このダイアログを閉じて、別の方法をお試しください。",
- "upload-form-label-not-own-work-local-default": "このファイルはその方針の下でそこにアップロードすることができれば、また、 [[Special:Upload|the upload page on {{SITENAME}}]]を使用してみてください",
- "upload-form-label-own-work-message-shared": "私は、このファイルの著作権を所有していることを宣誓し、取消し不能な形で [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] ライセンスのもとでウィキメディア・コモンズに、このファイルを解放することに同意します。そして私は、 [https://wikimediafoundation.org/wiki/Terms_of_Use Terms of Use] に同意します。",
- "upload-form-label-not-own-work-message-shared": "このファイルの著作権を所有していない場合、または別のライセンスの下でそれをリリースしたい場合には、 [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons Upload Wizard] を使用することを検討してください。",
- "upload-form-label-not-own-work-local-shared": "もしサイトが、それらの方針の下にて、このファイルのアップロードを許可している場合は、[[Special:Upload|{{SITENAME}}上でのアップロードページ]]の利用も検討できます。",
+ "upload-form-label-own-work-message-generic-local": "私は {{SITENAME}} 上での以下の利用規約とライセンス方針で、このファイルをアップロードしていることを確認します。",
+ "upload-form-label-not-own-work-message-generic-local": "もし、あなたは {{SITENAME}} の方針の下で、このファイルをアップロードすることができない場合には、このダイアログを閉じて、別の方法をお試しください。",
+ "upload-form-label-not-own-work-local-generic-local": "また、[[Special:Upload|デフォルトのアップロードページ]]を試してみてください。",
+ "upload-form-label-own-work-message-generic-foreign": "私は共有リポジトリにこのファイルをアップロードしていることを理解しています。私は、そこにサービスやライセンス方針を以下のようにやっていることを、確認します。",
+ "upload-form-label-not-own-work-message-generic-foreign": "もし、あなたは共有リポジトリの方針の下で、このファイルをアップロードすることができない場合には、このダイアログを閉じて、別の方法をお試しください。",
+ "upload-form-label-not-own-work-local-generic-foreign": "このファイルはその方針の下でそこにアップロードすることができれば、また、 [[Special:Upload|the upload page on {{SITENAME}}]]を使用してみてください",
"backend-fail-stream": "ファイル $1 をストリームできませんでした。",
"backend-fail-backup": "ファイル $1 をバックアップできませんでした。",
"backend-fail-notexists": "ファイル $1 は存在しません。",
"revertpage": "[[Special:Contributions/$2|$2]] ([[User talk:$2|トーク]]) による編集を [[User:$1|$1]] による直前の版へ差し戻しました",
"revertpage-nouser": "非表示の利用者による編集を {{GENDER:$1|[[User:$1|$1]]}} による直前の版へ差し戻しました",
"rollback-success": "$1による編集を差し戻しました。\n$2による直前の版へ変更されました。",
+ "rollback-success-notify": "$1による編集を差し戻しました。\n$2による直前の版へ変更されました。[$3 変更を表示]",
"sessionfailure-title": "セッションの失敗",
"sessionfailure": "ログインのセッションに問題が発生しました。\nセッション乗っ取りを防ぐため、操作を取り消しました。\n前のページへ戻って再度読み込んだ後に、もう一度試してください。",
"changecontentmodel": "ページのコンテンツ・モデルの変更",
"changecontentmodel-success-title": "コンテンツ・モデルは変更されました",
"changecontentmodel-success-text": "[[:$1]]のコンテンツ・タイプは変更されました。",
"changecontentmodel-cannot-convert": "[[:$1]]上のコンテントは$2の型には変換できません。",
- "changecontentmodel-nodirectediting": "$1 ã\82³ã\83³ã\83\86ã\83³ã\83\88・モデルは、ダイレクト編集をサポートしていません。",
- "log-name-contentmodel": "ã\82³ã\83³ã\83\86ã\83³ã\83\88・モデル変更記録",
+ "changecontentmodel-nodirectediting": "$1 ã\82³ã\83³ã\83\86ã\83³ã\83\84・モデルは、ダイレクト編集をサポートしていません。",
+ "log-name-contentmodel": "ã\82³ã\83³ã\83\86ã\83³ã\83\84・モデル変更記録",
"log-description-contentmodel": "ページのコンテンツ・モデルに関連する出来事",
"logentry-contentmodel-change": "$1 がページ $3 のコンテンツ・モデルを \"$4\" から \"$5\" に{{GENDER:$2|変更しました}}",
"logentry-contentmodel-change-revertlink": "差し戻し",
"ipb-unblock": "利用者またはIPアドレスのブロックを解除",
"ipb-blocklist": "現在有効なブロックを表示",
"ipb-blocklist-contribs": "{{GENDER:$1|$1}}の投稿の一覧",
+ "ipb-blocklist-duration-left": "残り $1",
"unblockip": "ブロックを解除",
"unblockiptext": "以下のフォームで利用者またはIPアドレスのブロックを解除できます。",
"ipusubmit": "このブロックを解除",
"lockdbsuccesstext": "データベースをロックしました。<br />\nメンテナンスが完了したら、忘れずに[[Special:UnlockDB|ロックを除去]]してください。",
"unlockdbsuccesstext": "データベースのロックを解除しました。",
"lockfilenotwritable": "データベースのロック ファイルが書き込み禁止です。\nデータベースをロックまたはロック解除するには、ウェブ サーバーがこれに書き込める必要があります。",
+ "databaselocked": "データベースは既にロックされています。",
"databasenotlocked": "データベースはロックされていません。",
"lockedbyandtime": "($1 が $2 $3 から)",
"move-page": "「$1」の移動",
"tags-delete-not-found": "タグ「$1」は存在しません。",
"tags-delete-too-many-uses": "タグ「$1」は少なくとも$2版に付与されており、削除できません。",
"tags-delete-warnings-after-delete": "タグ「$1」の削除しましたが、以下の{{PLURAL:$2|警告}}が発生しました:",
+ "tags-delete-no-permission": "変更タグを削除する権限がありません。",
"tags-activate-title": "タグの有効化",
"tags-activate-question": "タグ「$1」を有効化しようとしています。",
"tags-activate-reason": "理由:",
"sessionprovider-generic": "$1 セッション",
"randomrootpage": "おまかせルートページ",
"log-action-filter-block": "ブロックの種類",
+ "log-action-filter-delete": "削除の種類:",
+ "log-action-filter-import": "取り込みの種類:",
+ "log-action-filter-managetags": "タグ管理の種類:",
"log-action-filter-move": "移動の種類:",
"log-action-filter-newusers": "アカウント作成の種類:",
+ "log-action-filter-patrol": "巡回の種類:",
"log-action-filter-protect": "保護の種類:",
"log-action-filter-upload": "アップロードの種類",
"log-action-filter-all": "すべて",
"log-action-filter-block-unblock": "ブロック解除",
"log-action-filter-delete-delete": "ページの削除",
"log-action-filter-delete-restore": "ページの復帰",
+ "log-action-filter-delete-event": "記録の削除",
+ "log-action-filter-delete-revision": "版指定削除",
+ "log-action-filter-import-interwiki": "ウィキ間の取り込み",
+ "log-action-filter-import-upload": "XML アップロードによる取り込み",
+ "log-action-filter-managetags-create": "タグの作成",
+ "log-action-filter-managetags-delete": "タグの削除",
+ "log-action-filter-managetags-activate": "タグの有効化",
+ "log-action-filter-managetags-deactivate": "タグの無効化",
"log-action-filter-move-move": "転送を上書きしない移動",
"log-action-filter-move-move_redir": "転送を上書きする移動",
"log-action-filter-newusers-create": "匿名利用者による作成",
"log-action-filter-newusers-create2": "登録利用者による作成",
"log-action-filter-newusers-autocreate": "自動的な作成",
+ "log-action-filter-patrol-patrol": "手動巡回",
+ "log-action-filter-patrol-autopatrol": "自動巡回",
"log-action-filter-protect-protect": "保護",
- "log-action-filter-protect-modify": "保護の設定変更",
+ "log-action-filter-protect-modify": "保護設定の変更",
"log-action-filter-protect-unprotect": "保護解除",
+ "log-action-filter-protect-move_prot": "保護設定の移動",
+ "log-action-filter-suppress-event": "記録の秘匿",
+ "log-action-filter-suppress-revision": "版の秘匿",
+ "log-action-filter-suppress-delete": "ページの秘匿",
"log-action-filter-upload-upload": "新規アップロード",
- "log-action-filter-upload-overwrite": "再アップロード"
+ "log-action-filter-upload-overwrite": "再アップロード",
+ "authmanager-authn-autocreate-failed": "ローカルアカウントの自動作成が失敗しました: $1",
+ "authmanager-userdoesnotexist": "利用者アカウント「$1」は登録されていません。"
}
"아라",
"Chabi1",
"Katxis",
- "Macofe"
+ "Macofe",
+ "Dcljr"
]
},
"tog-underline": "Lingk andalainin",
"noname": "Yu no spesifai no valid yuuza niem.",
"loginsuccesstitle": "Lagiin soksesful",
"loginsuccess": "'''Yu nou lag iin tu {{SITENAME}} az \"$1\".'''",
- "nosuchuser": "No yuuza no de bai di niem \"$1\".\nYuuza niem kies sensitiv.\nChek yu spelin, ar [[Special:UserLogin/signup|kriet a nyuu akount]].",
+ "nosuchuser": "No yuuza no de bai di niem \"$1\".\nYuuza niem kies sensitiv.\nChek yu spelin, ar [[Special:CreateAccount|kriet a nyuu akount]].",
"nosuchusershort": "No yuuza no de bai di niem \"$1\".\nChek yu spelin.",
"nouserspecified": "Yu afi spesifai a yuuzaniem.",
"login-userblocked": "Dis yuuza blak. No lagiin no lou.",
"accmailtext": "A random jinariet paaswod fi [[User talk:$1|$1]] sen tu $2.\n\nDi paaswod fi dis nyuu akount kiahn chienj a di ''[[Special:ChangePassword|chienj paaswod]]'' piej afta yu lag iin.",
"newarticle": "(Nyuu)",
"newarticletext": "Yu fala lingk tu piej we no egzis yet.\nFi kriet di piej, taat taip ina di bax biluo (si di [$1 elp piej] fi muo infamieshan).\nEf yu de ya by mistiek, klik yu brouza '''bak''' botn.",
- "anontalkpagetext": "----''Dis a di diskoshan piej fi ananimos yuuza uu no kriet no akount yet, ar uu no yuuzi.\nWi dierfuor afi yuuz di nyuumerikal IP ajres fi aidentifai im/ar.\nSoch a IP ajres kiahn shier bai sebral yuuza.\nEf yu a ananimos yuuza ahn fiil se irelivant kament dairek tu yu, begyu [[Special:UserLogin/signup|kriet a akount]] ar [[Special:UserLogin|lag iin]] fi avaid fyuucha kanfyuujan wid ada ananimos yuuza.''",
+ "anontalkpagetext": "----''Dis a di diskoshan piej fi ananimos yuuza uu no kriet no akount yet, ar uu no yuuzi.\nWi dierfuor afi yuuz di nyuumerikal IP ajres fi aidentifai im/ar.\nSoch a IP ajres kiahn shier bai sebral yuuza.\nEf yu a ananimos yuuza ahn fiil se irelivant kament dairek tu yu, begyu [[Special:CreateAccount|kriet a akount]] ar [[Special:UserLogin|lag iin]] fi avaid fyuucha kanfyuujan wid ada ananimos yuuza.''",
"noarticletext": "Korentli no tex no de ina dis piej.\nYu kiahn [[Special:Search/{{PAGENAME}}|saach fi dis piej taikl]] ina ada piej,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} saach di rilietid lagdem],\nar [{{fullurl:{{FULLPAGENAME}}|action=edit}} edit dis piej]</span>.",
"noarticletext-nopermission": "Korantli no tex no de ina dis piej.\nYu kiah [[Special:Search/{{PAGENAME}}|saach fi dis piej taikl]] ina ada piej, ar <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} saach di rilietid lagdem]</span>, bot yu not ab pomishan fi kriet dis piej.",
"userpage-userdoesnotexist": "Yuuza akount \"<nowiki>$1</nowiki>\" no rejista.\nBegyu chek ef yu waahn fi kriet/edit dis piej.",
"watchlisttools-view": "Vyuu rilivant chienjdem",
"watchlisttools-edit": "Vyuu ahn edit wachlis",
"watchlisttools-raw": "Edit raa wachlis",
- "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1| talk]])",
+ "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|diskoshan]])",
"specialpages": "Peshal piej",
"tag-filter": "[[Special:Tags|Tag]] filta:",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag|Tags}}]]: $2)",
"Midnight Gambler",
"아라",
"Jyllanj",
- "Ghiutun"
+ "Ghiutun",
+ "Matma Rex"
]
},
"tog-underline": "Unjestreg henwisnenge:",
"morenotlisted": "Listen ä ett komplett.",
"mypage": "Siid",
"mytalk": "Diskusjon",
- "anontalk": "Diskusjonssiid for denn IP-adress",
+ "anontalk": "Diskusjonssiid",
"navigation": "Navigasjon",
"and": " å",
"qbfind": "Syeg",
"viewsource-title": "Sie tjeljkoden te $1",
"actionthrottled": "Begrænsneng å hånjleng",
"viewsourcetext": "Du ken dog se og åfskreve'n keldekode til æ side:",
+ "exception-nologin": "Ikke loggen på",
"welcomeuser": "Wælkomen, $1!",
"welcomecreation-msg": "Det konto ä bløwen opretten.\nGlæmm ett å ønda din [[Special:Preferences|instellenge for {{SITENAME}}]].",
"yourname": "Det brugenaun:",
"createacct-emailoptional": "E-mailadress (walgfri)",
"createacct-email-ph": "Intast dej e-mailadress",
"createacct-another-email-ph": "Intast e-mailadress",
+ "createaccountreason": "Begrunjels:",
"createacct-submit": "Oprett det konto",
+ "createacct-another-submit": "Oprett konto",
"createacct-benefit-heading": "{{SITENAME}} laws å menske som du.",
"createacct-benefit-body1": "{{PLURAL:$1|redigiireng|redigiirenge}}",
"createacct-benefit-body2": "{{PLURAL:$1|siid|side}}",
"pt-createaccount": "Oprett konto",
"pt-userlogout": "Logg å",
"retypenew": "Djentast ny adgångskode",
+ "botpasswords-label-delete": "Slett",
"resetpass-submit-cancel": "Åbryd",
"passwordreset": "Nullstell adgångskode",
+ "passwordreset-username": "Brugenaun:",
"bold_sample": "Fied tekst",
"bold_tip": "Fied tekst",
"italic_sample": "Kursiw tekst",
"history-feed-title": "Versjonshistori",
"history-feed-item-nocomment": "$1 mä $2",
"rev-delundel": "ønda sijtbarhed",
+ "revdelete-show-file-submit": "Ja",
+ "revdelete-log": "Begrunjels:",
"history-title": "$1: Versjonshistorik",
"difference-title": "Forskell mellem versjone å \"$1\"",
"lineno": "Linje $1:",
"badsig": "Syntaksi i signaturen ä udjylji; kontrolliir wenlist den brugtje HTML.",
"badsiglength": "Din signatur ä for lång. Den ma hyest inholj $1 {{PLURAL:$1|tejn}}.",
"yourgender": "Hwant forträkke du å blyw beskriiwen?",
+ "email": "E-mail",
"prefs-help-realname": "Åndjiels å rijti naun ä walgfritj.\nHwes du wælge å oplys det naun, wil dä blyw brugtj te å tilskriiw dej det arbejt.",
"prefs-editor": "Redigiirengsprogramme",
"prefs-preview": "Forhånjswisneng",
"rcshowhideminor-show": "Wis",
"rcshowhideminor-hide": "Sjul",
"rcshowhidebots": "$1 robotte",
- "rcshowhidebots-show": "Sjul",
+ "rcshowhidebots-show": "Wis",
"rcshowhidebots-hide": "Sjul",
"rcshowhideliu": "$1 registriirtje bruga",
"rcshowhideliu-show": "Wis",
"rcshowhidemine": "$1 ejne bidraw",
"rcshowhidemine-show": "Wis",
"rcshowhidemine-hide": "Sjul",
+ "rcshowhidecategorization-show": "Wis",
+ "rcshowhidecategorization-hide": "Sjul",
"rclinks": "Wis siensti $1 øndrenge i di sisti $2 daw<br />$3",
"diff": "forskell",
"hist": "historik",
"Matma Rex"
]
},
- "tog-underline": "Garisen ngisoré pranala:",
- "tog-hideminor": "Dhelikaké besutan cilik ing owah-owahan pungkasan",
- "tog-hidepatrolled": "Dhelikaké besutan awasan ing owah-owahan pungkasan",
- "tog-newpageshidepatrolled": "Dhelikaké kaca kapanto saka daptar kaca anyar",
- "tog-hidecategorization": "Dhelikaké kategorisasi kaca",
- "tog-extendwatchlist": "Jembaraké daptar pangawasan kanggo nuduhaké kabèh owahan, ora mung sing paling anyar",
- "tog-usenewrc": "Owah-owahané paguyuban miturut kaca nèng owah-owahan anyar lan daptar panto",
- "tog-numberheadings": "Wènèhana nomer judul secara otomatis",
+ "tog-underline": "Nggaris ngisori pranala:",
+ "tog-hideminor": "Dhelikaké besutan cilik saka owah-owahan pungkasan",
+ "tog-hidepatrolled": "Dhelikaké besutan ingawasan saka owah-owahan pungkasan",
+ "tog-newpageshidepatrolled": "Dhelikaké kaca ingawasan saka pratélaning kaca anyar",
+ "tog-hidecategorization": "Dhelikaké gegebengan kaca",
+ "tog-extendwatchlist": "Ambakaké pawawangan nedya nuduhaké kabèh owahan, ora mung sing paling anyar",
+ "tog-usenewrc": "Golongaké owah-owahan miturut kaca ing owah-owahan anyar lan pawawangan",
+ "tog-numberheadings": "Wènèhi angkaning sesirah kanthi otomatis",
"tog-showtoolbar": "Tuduhaké wilah piranti sarana besut",
"tog-editondblclick": "Besut kaca sarana ngeklik pindho",
- "tog-editsectiononrightclick": "Fungsèkna panyuntingan sub-bagian mawa klik-tengen ing judul bagian (mbutuhaké JavaScript)",
- "tog-watchcreations": "Tambahaké kaca sing tak gawé lan berkas sing tak unggah nèng daptar pangawasan",
- "tog-watchdefault": "Tambahaké kaca lan barkas sing tak sunting nyang pawawanganku",
- "tog-watchmoves": "Tambahaké kaca lan berkas sing tak pindhahaké nèng daptar pangawasan",
- "tog-watchdeletion": "Tambahaké kaca lan berkas sing tak busak nèng daptar pangawasan",
- "tog-watchuploads": "Tambahaké barkas anyar sing tak unggah nyang pawawanganku",
- "tog-watchrollback": "Tambahaké kaca sing tak wurungaké nyang pawawanganku",
- "tog-minordefault": "Tandhanana kabèh suntingan dadi suntingan cilik secara baku",
- "tog-previewontop": "Deleng prawuryan sadurungé besut kothak",
- "tog-previewonfirst": "Tuduhna pratayang ing suntingan kapisan",
- "tog-enotifwatchlistpages": "Kirimi kula layang èlèktronik yèn ana kaca utawa berkas nèng daptar pangawasanku sing diowah",
- "tog-enotifusertalkpages": "Kirimana aku layang e-mail yèn kaca dhiskusiku owah",
- "tog-enotifminoredits": "Kirimi kula layang èlèktronik uga yèn ana suntingan cilik saka kaca lan berkas",
- "tog-enotifrevealaddr": "Kirimana aku layang e-mail ing layang notifikasi",
- "tog-shownumberswatching": "Tuduhna cacahé pangawas",
- "tog-oldsig": "Tapak asma sing ana:",
- "tog-fancysig": "Anggepen tapak asta minangka teks wiki (tanpa pranala otomatis)",
- "tog-uselivepreview": "Trapaké prawuryan langsung",
+ "tog-editsectiononrightclick": "Idinaké mbesut pérangan sarana klik tengen ing sesirahing pérangan",
+ "tog-watchcreations": "Wuwuh kaca gawéanku lan barkas unggahanku nyang pawawanganku",
+ "tog-watchdefault": "Wuwuh kaca lan barkas besutanku nyang pawawanganku",
+ "tog-watchmoves": "Wuwuh kaca lan barkas lih-lihanku nyang pawawanganku",
+ "tog-watchdeletion": "Wuwuh kaca lan barkas busakanku nyang pawawanganku",
+ "tog-watchuploads": "Wuwuh barkas anyar unggahanku nyang pawawanganku",
+ "tog-watchrollback": "Wuwuh kaca sing tak wurungaké nyang pawawanganku",
+ "tog-minordefault": "Tengeri kabèh besutan minangka besutan cilik sacara baku",
+ "tog-previewontop": "Deleng pratuduh sadurungé mbesut kothak",
+ "tog-previewonfirst": "Delelng pratuduh nalika mbesut pisanan",
+ "tog-enotifwatchlistpages": "Kirimi aku layangtronik yèn ana kaca utawa barkas ing pawawanganku sing diowah",
+ "tog-enotifusertalkpages": "Kirimi aku layangtronik yèn kaca gegunemanku diowah",
+ "tog-enotifminoredits": "Uga kirimi aku layangtronik yèn ana besutan cilik ing kaca lan barkas",
+ "tog-enotifrevealaddr": "Singkab alamat layangtronikku ing layang pawarta",
+ "tog-shownumberswatching": "Tuduhaké cacah wong sing ngawasi",
+ "tog-oldsig": "Tandha tangan sing ana:",
+ "tog-fancysig": "Anggep tandha tangan minangka tulisan wiki (tanpa pranala otomatis)",
+ "tog-uselivepreview": "Nganggo pratuduh langsung",
"tog-forceeditsummary": "Élingna aku menawa kothak ringkesan suntingan isih kosong",
- "tog-watchlisthideown": "Delikna suntinganku ing daftar pangawasan",
+ "tog-watchlisthideown": "Dhelikaké besutanku saka pawawangan",
"tog-watchlisthidebots": "Dhelikaké besutan bot saka pangawasan",
- "tog-watchlisthideminor": "Delikna suntingan kecil di daftar pangawasan",
- "tog-watchlisthideliu": "Ngumpetaké suntingan panganggo sing mlebu log seka daftar pangawasan",
+ "tog-watchlisthideminor": "Dhelikaké besutan cilik saka pawawangan",
+ "tog-watchlisthideliu": "Dhelikaké saka pawawangan besutaning wong sing mlebu",
"tog-watchlistreloadautomatically": "Mot manèh pawawangan kanthi otomanis samangsa panyaring diowah (butuh JavaScript)",
- "tog-watchlisthideanons": "Ngumpetaké suntingan panganggo anonim seka daftar pangawasan",
- "tog-watchlisthidepatrolled": "Delikna suntingan sing wis dipatroli saka daftar pangawasan",
+ "tog-watchlisthideanons": "Dhelikaké saka pawawangan besutaning para anonim",
+ "tog-watchlisthidepatrolled": "Dhelikaké besutan ingawasan saka pawawangan",
"tog-watchlisthidecategorization": "Dhelikaké kategorisasi kaca",
- "tog-ccmeonemails": "Kirimana aku salinan layang e-mail sing tak-kirimaké menyang wong liya",
- "tog-diffonly": "Aja dituduhaké isi kaca ing ngisor bédané suntingan",
- "tog-showhiddencats": "Tuduhna kategori sing didelikaké",
- "tog-norollbackdiff": "Lirwaaké prabédan sawusé nglakokaké sawijining pambalikan.",
- "tog-useeditwarning": "Ã\88lingaké kula yèn kula ninggalaké suntingan sing durung kasimpen",
- "tog-prefershttps": "Panggah sarana sambungan aman nalika mlebu",
- "underline-always": "Mesthi",
+ "tog-ccmeonemails": "Kirimi aku salinan layangtronik sing tak kirim nyang wong liya",
+ "tog-diffonly": "Aja dituduhaké isining kaca ing ngisor bédané suntingan",
+ "tog-showhiddencats": "Tuduhaké kategori sing didhelikaké",
+ "tog-norollbackdiff": "Aja tuduhaké prabédan sawisé mbalèkaké.",
+ "tog-useeditwarning": "Ã\89lingaké kula yèn kula ninggalaké suntingan sing durung kasimpen",
+ "tog-prefershttps": "Tansah nganggo sambungan aman nalika mlebu",
+ "underline-always": "Tansah",
"underline-never": "Ora tau",
- "underline-default": "Kulit atau penjelajah bawaan",
- "editfont-style": "Modhèl aksara (font) ing kotak suntingan:",
- "editfont-default": "Standar panjelajah wèb",
+ "underline-default": "Baku kulit utawa pangluron",
+ "editfont-style": "Gagrag fon ing pambesutan:",
+ "editfont-default": "Baku pangluron",
"editfont-monospace": "Fon monospasi",
"editfont-sansserif": "Fon tansèrif",
"editfont-serif": "Fon sèrif",
"september": "Sèptèmber",
"october": "Oktober",
"november": "Nopèmber",
- "december": "Désèmber",
+ "december": "Dhésèmber",
"january-gen": "Januari",
- "february-gen": "Fèbruari",
+ "february-gen": "Pébruari",
"march-gen": "Maret",
"april-gen": "April",
"may-gen": "Mèi",
"september-gen": "Sèptèmber",
"october-gen": "Oktober",
"november-gen": "Nopèmber",
- "december-gen": "Désèmber",
+ "december-gen": "Dhésèmber",
"jan": "Jan",
"feb": "Pèb",
"mar": "Mar",
"sep": "Sèp",
"oct": "Okt",
"nov": "Nop",
- "dec": "Dès",
+ "dec": "Dhé",
"january-date": "Januari $1",
"february-date": "Pèbruari $1",
"march-date": "Maret $1",
"august-date": "Agustus $1",
"september-date": "$1 Sèptèmber",
"october-date": "Oktober $1",
- "november-date": "$1 Novèmber",
- "december-date": "$1 Dèsèmber",
+ "november-date": "$1 Nopèmber",
+ "december-date": "$1 Dhésèmber",
"period-am": "Isuk-Awan",
"period-pm": "Soré-Wengi",
"pagecategories": "{{PLURAL:$1|Kategori|Kategori}}",
"category_header": "Kaca sajeroning kategori \"$1\"",
- "subcategories": "Subkategori",
+ "subcategories": "Anak kategori",
"category-media-header": "Médhia sajeroning kategori \"$1\"",
- "category-empty": "''Kategori iki saiki ora ngandhut artikel utawa média.''",
- "hidden-categories": "{{PLURAL:$1|Kategori kadhelikaké|Kategori kadhelikaké}}",
+ "category-empty": "<em>Kategori iki lagi ora ngandhut artikel utawa médhia.</em>",
+ "hidden-categories": "{{PLURAL:$1|Kategori kadhelikan}}",
"hidden-category-category": "Kategori kadhelikan",
- "category-subcat-count": "{{PLURAL:$2|Kategori iki mung ngandhut subkategori ngisor iki.|Kategori iki ngandhut {{PLURAL:$1|subkategori|$1 subkategori}} ngisor iki saka gunggung $2 subkategori.}}",
- "category-subcat-count-limited": "Kategori iki ora duwé {{PLURAL:$1|subkategori|$1 subkategori}} ''berikut''.",
+ "category-subcat-count": "{{PLURAL:$2|Kategori iki mung ngandhut saanak kategori ngisor iki.|Kategori iki ngandhut {{PLURAL:$1|anak kategori|$1 anak kategori}} ngisor iki saka gunggung $2 anak kategori.}}",
+ "category-subcat-count-limited": "Kategori iki duwé {{PLURAL:$1|anak kategori|$1 anak kategori}} kaya ngisor iki.",
"category-article-count": "{{PLURAL:$2|Kategori iki mung ngandhut kaca ngisor iki.|{{PLURAL:$1|Kaca|$1 kaca}} ngisor iki ana ing kategori iki saka gunggung $2 kaca.}}",
"category-article-count-limited": "Kategori iki ngandhut {{PLURAL:$1|kaca|$1 kaca-kaca}} sing kapacak ing ngisor iki.",
"category-file-count": "{{PLURAL:$2|Kategori iki mung isi barkas iki.|{{PLURAL:$1|Barkas|$1 barkas}} iki ana sajeroning kategori iki saka $2 gunggungé.}}",
"moredotdotdot": "Liyané...",
"morenotlisted": "Pratélan iki ora jangkep.",
"mypage": "Kaca",
- "mytalk": "Wicara",
- "anontalk": "Rembug",
+ "mytalk": "Parembugan",
+ "anontalk": "Parembugan",
"navigation": "Napigasi",
"and": " lan",
"qbfind": "Golèk",
"searchbutton": "Golèk",
"go": "Menyang",
"searcharticle": "Menyang",
- "history": "Sajarah kaca",
+ "history": "Babading kaca",
"history_short": "Babad",
"updatedmarker": "wis inganyaran kawit tekaku sing pungkasan",
"printableversion": "Cara cithakan",
"deletethispage": "Busak kaca iki",
"undeletethispage": "Wurungaké pambusaking kaca iki",
"undelete_short": "Batal busak {{PLURAL:$1|sabesutan|$1 besutan}}",
- "viewdeleted_short": "Pirsani {{PLURAL:$1|suntingan|suntingan}} ingkang sampun kabusak",
+ "viewdeleted_short": "Deleng {{PLURAL:$1|sabesutan sing kabusak|$1 besutan sing kabusak}}",
"protect": "Reksa",
"protect_change": "owah",
"protectthispage": "Reksa kaca iki",
"unprotectthispage": "Owah rereksan kaca iki",
"newpage": "Kaca anyar",
"talkpage": "Rembug kaca iki",
- "talkpagelinktext": "gunem",
+ "talkpagelinktext": "rembugan",
"specialpage": "Kaca mirunggan",
- "personaltools": "Piranti pribadi",
+ "personaltools": "Piranti priangga",
"articlepage": "Deleng kaca isi",
- "talk": "Rembug",
+ "talk": "Parembugan",
"views": "Praèn",
"toolbox": "Piranti",
"userpage": "Deleng kaca panganggo",
"otherlanguages": "Ing basa liya",
"redirectedfrom": "(Dilih saka $1)",
"redirectpagesub": "Alih kaca",
- "redirectto": "Malih nyang:",
+ "redirectto": "Ngalih menyang:",
"lastmodifiedat": "Kaca iki pungkasan diowah kala $1, tabuh $2.",
- "viewcount": "Kaca iki wis tau diaksès cacahé ping {{PLURAL:$1|siji|$1}}.",
+ "viewcount": "Kaca iki wis diaksès ping {{PLURAL:$1|siji|$1}}.",
"protectedpage": "Kaca kareksa",
"jumpto": "Jujug:",
"jumptonavigation": "napigasi",
"aboutpage": "Project:Bab",
"copyright": "Kabèh isi kasedyakaké miturut $1.",
"copyrightpage": "{{ns:project}}:Hak cipta",
- "currentevents": "Kadadéan saiki",
- "currentevents-url": "Project:Kadadéan saiki",
+ "currentevents": "Kadadian saiki",
+ "currentevents-url": "Project:Kadadian saiki",
"disclaimers": "Sélakan",
"disclaimerpage": "Project:Sélakan umum",
"edithelp": "Pitulung besut",
"helppage-top-gethelp": "Pitulung",
- "mainpage": "Kaca Pokok",
- "mainpage-description": "Kaca pokok",
+ "mainpage": "Tepas",
+ "mainpage-description": "Tepas",
"policy-url": "Project:Kabijakan",
"portal": "Gapura paguyuban",
"portal-url": "Project:Garupa paguyuban",
- "privacy": "Niti pripasi",
+ "privacy": "Niti priangga",
"privacypage": "Project:Niti pripasi",
"badaccess": "Aksès ora olèh",
"badaccess-group0": "Panjenengan ora pareng nglakokaké tindhakan sing panjenengan gayuh.",
"youhavenewmessagesmanyusers": "Sampéyang nduwé $1 saka akèh panganggo ($2).",
"newmessageslinkplural": "{{PLURAL:$1|layang anyar|999=layang anyar}}",
"newmessagesdifflinkplural": "{{PLURAL:$1|owahan|999=owahan}} pungkasan",
- "youhavenewmessagesmulti": "Panjenengan olèh pesen-pesen anyar $1",
+ "youhavenewmessagesmulti": "Sampéyan éntuk nawala anyar ing $1",
"editsection": "besut",
"editold": "besut",
"viewsourceold": "deleng sumber",
"nstab-template": "Cithakan",
"nstab-help": "Kaca pitulung",
"nstab-category": "Kategori",
- "mainpage-nstab": "Kaca pokok",
+ "mainpage-nstab": "Tepas",
"nosuchaction": "Ora ana lelakon mangkono",
"nosuchactiontext": "Pratingkah sing dirinci déning URL ora sah.\nPanjenengan manawa salah ketik nalika ngisi URL, utawa salah ngisi pranala.\nIki manawa uga nuduhaké anané kesalahan ing piranti alus sing dipigunakaké déning {{SITENAME}}.",
"nosuchspecialpage": "Ora ana kaca mirunggan mangkono",
"laggedslavemode": "Pènget: Kaca iki mbokmenawa isiné dudu pangowahan pungkasan.",
"readonly": "Umpak data kagembok",
"enterlockreason": "Lebokna alesan panguncèn, kalebu uga prakiran kapan kunci bakal dibuka",
- "readonlytext": "Database lagi dikunci marang panampan anyar. Pangurus sing ngunci mènèhi katrangan kaya mangkéné: <p>$1",
+ "readonlytext": "Juru administrasi sistem sing ngunci iku medhar mangkéné: $1",
"missing-article": "Basis data ora bisa nemokaké tèks kaca sing kuduné ana, yaiku \"$1\" $2.\nBab iki bisasané disebabaké déning pranala daluwarsa menyang revisi sadurungé kaca sing wis dibusak.\nYèn dudu iki panyebabé, panjenengan manawa bisa nemokaké kasalahan (''bug'') jroning piranti alus (''software''). Mangga dilapuraké bab iki menyang [[Special:ListUsers/sysop|administrator]], kanthi nyebutaké alamat URL sing dituju",
"missingarticle-rev": "(owahan#: $1)",
"missingarticle-diff": "(Béda: $1, $2)",
"cannotdelete-title": "Ora bisa mbusak kaca \"$1\"",
"delete-hook-aborted": "Pambusakan dibatalaké déning ''hook''.\nOra ana alesané.",
"no-null-revision": "Ora isa nggawe revisi 'null' anyar kanggo kaca \"$1\"",
- "badtitle": "Sésirah ala",
- "badtitletext": "Judhul kaca sing panjenengan ora bisa dituduhaké, kosong, utawa dadi judhul antar-basa utawa judhul antar-wiki. Iku bisa uga ana sawijining utawa luwih aksara sing ora bisa didadèkaké judhul.",
+ "badtitle": "Sesirah ala",
+ "badtitletext": "Sesirahing kaca sing dikarepaké ora sah, suwung, utawa salah nggayut nyang sesirah antarabasa utawa antarawiki.\nIku mungkin ngandhut pralambang siji utawa luwih sing ora kena dianggo tumrap sesirah iki.",
"perfcached": "Data iki mung dijupuk saka papan singgahan lan mungkin ora kaanyaran. Maksimum {{PLURAL:$1|sak asil|$1 asil}} sumadhiya nèng papan singgahan.",
"perfcachedts": "Data iki mung dijupuk saka papan singgahan lan mungkin dianyari pungkasan $1. Maksimum {{PLURAL:$4|sak asil|$4 asil}} sumadhiya nèng papan singgahan.",
"querypage-no-updates": "Update saka kaca iki lagi dipatèni. Data sing ana ing kéné saiki ora bisa bakal dibalèni unggah manèh.",
"actionthrottled": "Tindakan diwatesi",
"actionthrottledtext": "Minangka sawijining pepesthèn anti-spam, panjenengan diwatesi nglakoni tindhakan iki sing cacahé kakèhan ing wektu cendhak.\nMangga dicoba manèh ing sawetara menit.",
"protectedpagetext": "Kaca iki wis digembok supaya ora bisa disunting lan diapa-apakaké.",
- "viewsourcetext": "Panjenengan bisa mirsani utawa nulad sumber kaca iki:",
- "viewyourtext": "Sampéyan bisa ndelok lan nyalin sumber '''suntingan Sampéyan''' nèng kaca iki:",
+ "viewsourcetext": "Sampéyan bisa ndeleng lan nyalin sumbering kaca iki.",
+ "viewyourtext": "Sampéyan bisa ndeleng lan nyalin sumbering <strong>besutaning sampéyan</strong> ing kaca iki.",
"protectedinterface": "Kaca iki isiné tèks antarmuka sing dienggo software lan wis dikunci kanggo menghindari kasalahan.",
"editinginterface": "'''Pènget:''' Panjenengan nyunting kaca sing dianggo nyedyakaké tèks antarmuka kanggo piranti alus.\nPangowahan kaca iki bakal awèh pangaruh marang tampilan antarmuka panganggo kanggoné panganggo liya.\nKanggo terjemahan, mangga nganggo [//translatewiki.net/wiki/Main_Page?setlang=en translatewiki.net], proyèk lokalisasi MediaWiki.",
"cascadeprotected": "Kaca iki wis direksa saka panyuntingan amerga disertakaké ing {{PLURAL:$1|kaca|kaca-kaca}} ngisor iki sing wis direksa mawa opsi \"runtun\" diaktifaké:\n$2",
"welcomecreation-msg": "Akun panjenengan wis kacipta. Aja lali nata konfigurasi [[Special:Preferences|preferensi {{SITENAME}}]] panjenengan.",
"yourname": "Jeneng panganggo:",
"userlogin-yourname": "Jeneng panganggo",
- "userlogin-yourname-ph": "Isi jeneng panganggo Sampéyan",
+ "userlogin-yourname-ph": "Isi jeneng panganggoning sampéyan",
"createacct-another-username-ph": "Isi jeneng panganggo",
"yourpassword": "Tembung wadi:",
"userlogin-yourpassword": "Tembung wadi",
"createacct-submit": "Gawé akun sampéyan",
"createacct-another-submit": "Gawé akun",
"createacct-benefit-heading": "{{SITENAME}} digawé déning wong-wong kaya déné sampéyan.",
- "createacct-benefit-body1": "{{PLURAL:$1|besutan|besutan}}",
- "createacct-benefit-body2": "{{PLURAL:$1|kaca|kaca}}",
- "createacct-benefit-body3": "{{PLURAL:$1|panyumbang|panyumbang}} pungkasan",
+ "createacct-benefit-body1": "{{PLURAL:$1|besutan}}",
+ "createacct-benefit-body2": "{{PLURAL:$1|kaca}}",
+ "createacct-benefit-body3": "{{PLURAL:$1|sing nyumbang}} pungkasan",
"badretype": "Sandhi panjenengan ora gathuk",
"usernameinprogress": "Panggawéning akun tumrap jeneng panganggo iki tembé lumaku.\nEntèni sadhéla.",
"userexists": "Jeneng panganggo sing dilebokaké lagi dianggo.\nMangga pilih jeneng liya.",
"noname": "Asma panganggo sing panjenengan pilih ora sah.",
"loginsuccesstitle": "Kasil mlebu",
"loginsuccess": "'''Panjenengan saiki mlebu ing {{SITENAME}} kanthi asma \"$1\".'''",
- "nosuchuser": "Ora ana panganggo mawa asma \"$1\".\nJeneng panganggo iku mbédakaké kapitalisasi.\nCoba dipriksa manèh pasang aksarané, utawa [[Special:UserLogin/signup|gawé akun anyar]].",
+ "nosuchuser": "Ora ana panganggo mawa asma \"$1\".\nJeneng panganggo iku mbédakaké kapitalisasi.\nCoba dipriksa manèh pasang aksarané, utawa [[Special:CreateAccount|gawé akun anyar]].",
"nosuchusershort": "Ora ana panganggo mawa asma \"$1\". Coba dipriksa manèh pasang aksarané (éjaané).",
"nouserspecified": "Panjenengan kudu milih asma panganggo.",
"login-userblocked": "Panganggo iki pinalangan. Ora kena mbelu.",
"createaccount-title": "Gawé rékening kanggo {{SITENAME}}",
"createaccount-text": "Ana wong sing nggawé sawijining akun utawa rékening kanggo alamat e-mail panjenengan ing {{SITENAME}} ($4) mawa jeneng \"$2\" lan tembung sandi \"$3\". Panjenengan disaranaké kanggo mlebu log lan ngganti tembung sandi panjenengan saiki.\n\nPanjenengan bisa nglirwakaké pesen iki yèn akun utawa rékening iki digawé déné sawijining kaluputan.",
"login-throttled": "Panjenengan wis kakèhan njajal mlebu log.\nTulung nunggu dhisik $1 sadurungé njajal manèh.",
- "login-abort-generic": "Sampéyan ora suksès mlebu log - Dibatalaké",
+ "login-abort-generic": "Sampéyan ora bisa mlebu - Kawurungan",
"loginlanguagelabel": "Basa: $1",
"suspicious-userlogout": "Panjaluk panjenengan supaya metu ditolak amarga katoné panjlajah internt utawa proksi panyinggah.",
"createacct-another-realname-tip": "Jeneng asli ora kudu dilebokake.\n\nYen sampeyan milih nglebokake jeneng asli, jeneng kuwi bakal dinggo ngwenehi atribusi kanggo karya-karyane.",
"user-mail-no-addy": "Njajal ngirim layang èlèktronik tanpa alamat layang èlèktronik.",
"user-mail-no-body": "Nyoba ngirim layang e-mail, tapi isine kosong.",
"changepassword": "Ganti tembung wadi",
- "resetpass_announce": "Panjenengan wis mlebu log mawa kodhe sementara sing dikirim mawa e-mail. Menawa kersa nglanjutaké, panjenengan kudu milih tembung sandhi anyar ing kéné:",
+ "resetpass_announce": "Kanggo ngrampungaké lelakoning lumebu, sampéyan kudu masang tembung wadi anyar.",
"resetpass_text": "<!-- Tambahaké teks ing kéné -->",
"resetpass_header": "Ganti tembung wadining akun",
"oldpassword": "Tembung wadi lawas:",
"newpassword": "Tembung wadi anyar:",
"retypenew": "Tik manèh tembung wadi anyaré:",
"resetpass_submit": "Nata tembung sandhi lan mlebu log",
- "changepassword-success": "Tembung sandhi panjenengan wis suksès diowahi!",
+ "changepassword-success": "Tembung wadining sampéyan kasil diowah!",
"botpasswords": "Tembung wadi bot",
"botpasswords-label-appid": "Jeneng bot:",
"botpasswords-label-create": "Gawé",
"passwordreset-emailtext-ip": "Ana uwong (mbok menawa Sampéyan, mawa angka IP $1) njaluk ganti tembung sandhiné Sampéyan ana ing {{SITENAME}} ($4). {{PLURAL:$3|Rèkèning|Rèkèning-rèkèning}} ngisor iki magepokan karo padunungané layang èlèktronik iki:\n\n$2\n\n{{PLURAL:$3|Tembung sandhi sawetara iki}} bakal kedaluwarsa ing {{PLURAL:$5|sak dina|$5 dina}}.\nSampéyan kudu mlebu log lan milih siji tembung sandhi anyar saiki. Yèn wong liya sing njaluk iki, utawa yèn Sampéyan jebul wis kèlingan tembung sandhiné sing lawas saéngga ora ana niyat kanggo ngganti, Sampéyan bisa ngejaraké wara-wara iki lan bacutaké nganggo tembung sandhiné lawas Sampéyan.",
"passwordreset-emailtext-user": "Panganggo $1 seka {{SITENAME}} njaluk ganti tembung sandhiné Sampéyan ana ing {{SITENAME}} ($4). {{PLURAL:$3|Rèkèning|Rèkèning-rèkèning}} ngisor iki magepokan karo padunungané layang èlèktronik iki:\n\n$2\n\n{{PLURAL:$3|Tembung sandhi sawetara iki}} bakal kedaluwarsa ing {{PLURAL:$5|sak dina|$5 dina}}.\nSampéyan kudu mlebu log lan milih siji tembung sandhi anyar saiki. Yèn wong liya sing njaluk iki, utawa yèn Sampéyan jebul wis kèlingan tembung sandhiné sing lawas saéngga ora ana niyat kanggo ngganti, Sampéyan bisa ngejaraké wara-wara iki lan bacutaké nganggo tembung sandhiné lawas Sampéyan.",
"passwordreset-emailelement": "Jeneng panganggo: \n$1\n\nTembung wadi sauntara: \n$2",
- "passwordreset-emailsentemail": "Layang èlèktronik kanggo mbalèkaké tembung sandhi wis dikirim.",
+ "passwordreset-emailsentemail": "Yèn layang èlèktronik iki nggayut akuning sampéyan, layang kanggo salin tembung wadi bakal dikirim.",
"passwordreset-emailsent-capture": "Layang èlèktronik kanggo mbalèkaké tembung sandhi wis dikirim, bisa didelok ngisor iki.",
"passwordreset-emailerror-capture": "Layang èlèktronik pangèling tembung sandhi wis digawe, yaiku sing ditampilaké nèng ngisor iki, nanging ora kasil dikirim ing {{GENDER:$2|panganggo}}: $1",
- "changeemail": "Ganti alamat layang èlèktronik",
+ "changeemail": "Owah utawa busak alamat layang èlèktronik",
"changeemail-header": "Ganti alamat layang èlèktronik akun",
"changeemail-no-info": "Sampéyan kudu mlebu log kanggo ngaksès kaca iki langsung.",
"changeemail-oldemail": "Alamat layang èlèktronik saiki:",
"resettokens-done": "Reset token.",
"resettokens-resetbutton": "Reset token sing dipilih",
"bold_sample": "Tulisan kandel",
- "bold_tip": "Tulisann kandel",
- "italic_sample": "Tulisan miring",
+ "bold_tip": "Tulisan kandel",
+ "italic_sample": "Tulisan dhoyong",
"italic_tip": "Tulisan dhoyong",
"link_sample": "Sesirah pranala",
"link_tip": "Pranala njero",
"extlink_tip": "Pranala jaba (élinga ater-ater http://)",
"headline_sample": "Tulisan sesirah",
"headline_tip": "Sesirah tataran 2",
- "nowiki_sample": "Tèks iki ora bakal diformat",
+ "nowiki_sample": "Isi nganggo tulisan tanpa format ing kéné",
"nowiki_tip": "Aja nganggo format wiki",
"image_sample": "Conto.jpg",
- "image_tip": "Mènèhi gambar/berkas",
+ "image_tip": "Barkas sisipan",
"media_sample": "Conto.ogg",
"media_tip": "Pranala barkas",
"sig_tip": "Tandha tangan sampéyan mawa tandha wayah",
"hr_tip": "Garis horisontal",
"summary": "Tingkesan:",
- "subject": "Subyek/judhul:",
+ "subject": "Jejer:",
"minoredit": "Iki besutan cilik",
"watchthis": "Awasi kaca iki",
"savearticle": "Simpen kaca",
- "preview": "Prawuryan",
- "showpreview": "Tuduhaké prawuryan",
+ "preview": "Pratuduh",
+ "showpreview": "Deleng pratuduh",
"showdiff": "Tuduhaké owahan",
"anoneditwarning": "<strong>Penget:</strong> Panjenengan boten mlebet log. Alamat IP Panjenengan badhe katingal dening publik manawi Panjenengan ngayahi ewah-ewahan. Manawi Panjenengan <strong>[$1 mlebet log]</strong> utawai <strong>[$2 damel akun]</strong>, suntingan Panjenengan badhe kaatribusekaken dhumateng nama pangangge Panjenengan, lan rupi-rupi kauntungan sanesipun.",
"anonpreviewwarning": "''Sampéyan durung mlebu log. Nyimpen bakal nyathet alamat IP Sampéyan nèng riwayat sunting kaca iki.''",
"missingsummary": "'''Pènget:''' Panjenengan ora nglebokaké ringkesan panyuntingan. Menawa panjenengan mencèt tombol Simpen manèh, suntingan panjenengan bakal kasimpen tanpa ringkesan panyuntingan.",
"missingcommenttext": "Tulung lebokna komentar ing ngisor iki.",
"missingcommentheader": "'''Pangéling:''' Sampéyan durung nyadhiyakaké judhul/jejer kanggo tanggepan iki.\nYèn Sampéyan klik \"{{int:savearticle}}\" manèh, suntingan Sampéyan bakal kasimpen tanpa kuwi.",
- "summary-preview": "Prawuryan tingkesan:",
- "subject-preview": "Pratayang subyèk/judhul:",
+ "summary-preview": "Pratuduh tingkesan:",
+ "subject-preview": "Prawuryaning jejer:",
"blockedtitle": "Panganggo kapalangan",
- "blockedtext": "'''Asma panganggo utawa alamat IP panjenengan diblokir.'''\n\nBlokir iki sing nglakoni $1.\nAlesané ''$2''.\n\n* Diblokir wiwit: $8\n* Kadaluwarsa pemblokiran ing: $6\n* Sing arep diblokir: $7\n\nPanjenengan bisa ngubungi $1 utawa [[{{MediaWiki:Grouppage-sysop}}|pangurus liyané]] kanggo ngomongaké prakara iki.\n\nPanjenengan ora bisa nggunakaké fitur 'Kirim layang e-mail panganggo iki' kejaba panjenengan wis nglebokaké alamat e-mail sing sah ing [[Special:Preferences|préferènsi]] panjenengan.\n\nAlamat IP panjenengan iku $3, lan ID pamblokiran iku #$5.\nTulung kabèh informasi ing ndhuwur iki disertakaké ing saben pitakon panjenengan.",
- "autoblockedtext": "Alamat IP panjenangan wis diblokir minangka otomatis amerga dienggo déning panganggo liyané. Pamblokiran dilakoni déning $1 mawa alesan:\n\n:''$2''\n\n* Diblokir wiwit: $8\n* Blokir kadaluwarsa ing: $6\n* Sing dikarepaké diblokir: $7\n\nPanjenengan bisa ngubungi $1 utawa [[{{MediaWiki:Grouppage-sysop}}|pangurus liyané]] kanggo ngomongaké perkara iki.\n\nPanjenengan ora bisa nganggo fitur \"kirim e-mail panganggo iki\" kejaba panjenengan wis nglebokaké alamat e-mail sing sah ing [[Special:Preferences|préferènsi]] panjenengan lan panjenengan wis diblokir kanggo nggunakaké.\n\nID pamblokiran panjenengan iku #$5 lan alamat IP panjenengan iku $3. Tulung sertakna informasi ing dhuwur kabèh iki saben ngajokaké pitakonan panjenengan. Matur nuwun.",
+ "blockedtext": "<b>Asma panganggo utawa alamat IP panjenengan diblokir.</b>\n\nBlokir iki sing nglakoni $1.\nAlesané <i>$2</i>.\n\n* Diblokir wiwit: $8\n* Kadaluwarsa pemblokiran ing: $6\n* Sing arep diblokir: $7\n\nPanjenengan bisa ngubungi $1 utawa [[{{MediaWiki:Grouppage-sysop}}|pangurus liyané]] kanggo ngomongaké prakara iki.\n\nPanjenengan ora bisa nggunakaké fitur 'Kirim layang é-mail panganggo iki' kejaba panjenengan wis nglebokaké alamat é-mail sing sah ing [[Special:Preferences|prèferènsi]] panjenengan.\n\nAlamat IP panjenengan iku $3, lan ID pamblokiran iku #$5.\nTulung kabèh informasi ing ndhuwur iki disertakaké ing saben pitakon panjenengan.",
+ "autoblockedtext": "Alamat IP panjenangan wis diblokir minangka otomatis amerga dienggo déning panganggo liyané. Pamblokiran dilakoni déning $1 mawa alesan:\n\n:''$2''\n\n* Diblokir wiwit: $8\n* Blokir kadaluwarsa ing: $6\n* Sing dikarepaké diblokir: $7\n\nPanjenengan bisa ngubungi $1 utawa [[{{MediaWiki:Grouppage-sysop}}|pangurus liyané]] kanggo ngomongaké perkara iki.\n\nPanjenengan ora bisa nganggo fitur \"kirim e-mail panganggo iki\" kejaba panjenengan wis nglebokaké alamat e-mail sing sah ing [[Special:Preferences|prèferènsi]] panjenengan lan panjenengan wis diblokir kanggo nggunakaké.\n\nID pamblokiran panjenengan iku #$5 lan alamat IP panjenengan iku $3. Tulung sertakna informasi ing dhuwur kabèh iki saben ngajokaké pitakonan panjenengan. Matur nuwun.",
"blockednoreason": "ora ana alesan sing diwènèhaké",
- "whitelistedittext": "Panjenengan kudu $1 supaya bisa nyunting artikel.",
+ "whitelistedittext": "Sampéyan kudu $1 murih bisa mbesut kaca.",
"confirmedittext": "Panjenengan kudu ndhedhes alamat e-mail dhisik sadurungé pareng nyunting sawijining kaca. Mangga nglebokaké lan validasi alamat e-mail panjenengan sadurungé nglakoni panyuntingan. Alamat e-mail sawisé bisa diowahi liwat [[Special:Preferences|kaca préférènsi]]",
"nosuchsectiontitle": "Pérangan ora katemu",
"nosuchsectiontext": "Panjenengan nyoba nyunting sawijining bagéan sing ora ana.\nBagéan iki manawa wis dipindhah utawa dibusak nalika panjenengan buka.",
"accmailtext": "Sawijining tembung sandi sembarang kanggo [[User talk:$1|$1]] wis dikirim menyang $2.\n\nTembung sandi kanggo panganggo anyar iki isa diganti ing kaca ''[[Special:ChangePassword|ganti tembung sandi]]'' sawisé mlebu log.",
"newarticle": "(Anyar)",
"newarticletext": "Katonané panjenengan ngetutaké pranala artikel sing durung ana.\nManawa kersa manulis artikel iki, manggaa. (Mangga mirsani [$1 Pitulung] kanggo informasi sabanjuré).\nYèn ora sengaja tekan kéné, bisa ngeklik pencètan '''back''' waé ing panjlajah wèb panjenengan.",
- "anontalkpagetext": "---- ''Iki yaiku kaca dhiskusi sawijining panganggo anonim sing durung kagungan akun utawa ora nganggo akuné, dadi kita keeksa kudu nganggo alamat IP-né kanggo nepangi. Alamat IP kaya mengkéné iki bisa dienggo déning panganggo sing séjé-séjé. Yèn panjenengan pancèn panganggo anonim lan olèh komentar-komentar miring, mangga [[Special:UserLogin/signup|nggawé akun]] utawa [[Special:UserLogin|log mlebu]] supaya ora rancu karo panganggo anonim liyané ing mangsa ngarep.''",
+ "anontalkpagetext": "---- ''Iki yaiku kaca dhiskusi sawijining panganggo anonim sing durung kagungan akun utawa ora nganggo akuné, dadi kita keeksa kudu nganggo alamat IP-né kanggo nepangi. Alamat IP kaya mengkéné iki bisa dienggo déning panganggo sing séjé-séjé. Yèn panjenengan pancèn panganggo anonim lan olèh komentar-komentar miring, mangga [[Special:CreateAccount|nggawé akun]] utawa [[Special:UserLogin|log mlebu]] supaya ora rancu karo panganggo anonim liyané ing mangsa ngarep.''",
"noarticletext": "Kala saiki kaca iki durung ana tulisané.\nSampéyan bisa [[Special:Search/{{PAGENAME}}|nggolèki sesirahing kaca iki]] sajeroning kaca liya,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} nggolèki log sing magepokan],\nutawa [{{fullurl:{{FULLPAGENAME}}|action=edit}} nggawé kaca iki]</span>.",
"noarticletext-nopermission": "Saiki ora ana tèks ing kaca iki. \nSampéyan bisa [[Special:Search/{{PAGENAME}}|nggolèki judhul kaca iki]] nèng kaca liya, \nutawa <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|kaca={{urlencode:{{FULLPAGENAME}}}}}} nggolèki log sing kaitan]</span>, nanging Sampéyan ora nduwèni idin nggawé kaca iki.",
"missing-revision": "Benahan #$1 saka kaca ajeneng \"{{FULLPAGENAME}}\" ora ana.\n\nIki biasané kasebabaké pranala riwayat sing kedaluwarsa saka kaca kuwi wis dibusak.\nRinciané bisa ditemokaké nèng [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log pambusakan].",
"templatesusedsection": "{{PLURAL:$1|Cithakan}} sing dienggo ding bagian iki:",
"template-protected": "(kareksa)",
"template-semiprotected": "(semu kareksa)",
- "hiddencategories": "Kaca iki sawijining anggota saka {{PLURAL:$1|1 kategori ndelik|$1 kategori-kategori ndelik}}:",
+ "hiddencategories": "Kaca iki anggotaning {{PLURAL:$1|1 kategori wadi|$1 kategori wadi}}:",
"edittools": "<!-- Tèks ing ngisor iki bakal ditudhuhaké ing ngisoring isènan suntingan lan pangemotan.-->",
"nocreatetext": "Situs iki ngwatesi kemampuan kanggo nggawé kaca anyar. Panjenengan bisa bali lan nyunting kaca sing wis ana, utawa mangga [[Special:UserLogin|mlebua log utawa ndaftar]]",
"nocreate-loggedin": "Panjenengan ora kagungan idin kanggo nggawé kaca anyar.",
"undo-success": "Suntingan iki bisa dibatalaké. Tulung priksa prabandhingan ing ngisor iki kanggo mesthèkaké yèn prakara iki pancèn sing bener panjenengan pèngin lakoni, banjur simpenen pangowahan iku kanggo ngrampungaké pambatalan suntingan.",
"undo-failure": "Suntingan iki ora bisa dibatalakén amerga ana konflik panyuntingan antara.",
"undo-norev": "Suntingan iki ora bisa dibatalaké amerga ora ana utawa wis dibusak.",
- "undo-summary": "←Mbatalaké revisi $1 déning [[Special:Contributions/$2|$2]] ([[User talk:$2|Dhiskusi]])",
+ "undo-summary": "Balèkaké owahan $1 déning [[Special:Contributions/$2|$2]] ([[User talk:$2|rembugan]])",
"undo-summary-username-hidden": "Batalna revisi $1 saking panganggo kang didhelikake",
"cantcreateaccounttitle": "Akun ora bisa digawé",
"cantcreateaccount-text": "Saka alamat IP iki ('''$1''') ora diparengaké nggawé akun utawa rékening. Sing mblokir utawa ora marengaké iku [[User:$3|$3]].\n\nAlesané miturut $3 yaiku ''$2''",
"logdelete-failure": "'''Aturan pandhelikan ora bisa disèt:'''\n$1",
"revdel-restore": "Ngowahi visiblitas (pangatonan)",
"pagehist": "Babading kaca",
- "deletedhist": "Babad kabusakan",
+ "deletedhist": "Babad kabusak",
"revdelete-hide-current": "Gagal ndhelikaké révisi tanggal $2, $1: iki arupa révisi paling anyar.\nRévisi iki ora bisa didhelikaké.",
"revdelete-show-no-access": "Gagal nampilaké révisi tanggal $1, jam $2: révisi iki wis ditandhani \"kawates\".\nPanjenengan ora nduwèni aksès menyang révisi iki.",
"revdelete-modify-no-access": "Gagal ngowahi révisi tanggal $1, jam $2: révisi iki wis ditandhani \"kawates\".\nPanjenengan ora nduwèni aksès menyang révisi iki.",
"mergelog": "Gabung log",
"revertmerge": "Batalna panggabungan",
"mergelogpagetext": "Ing ngisor iki kapacak daftar panggabungan sajarah kaca ing kaca liyané.",
- "history-title": "Riwayat rèvisi saka \"$1\"",
+ "history-title": "Babad owahaning \"$1\"",
"difference-title": "Prabéda antara owahan \"$1\"",
"difference-title-multipage": "Prabédhan antara kaca \"$1\" lan \"$2\"",
"difference-multipage": "(Prabédhan antar kaca)",
"searchmenu-exists": "'''Ana kaca kanthi jeneng \"[[$1]]\" ing wiki iki'''",
"searchmenu-new": "<strong>Gawéa kaca \"[[:$1]]\" nyang wiki iki!</strong> {{PLURAL:$2|0=|Uga delenga kaca sing katemu sarana panggolèking sampéyan.|Uga delenga kasiling panggolèk.}}",
"searchprofile-articles": "Kaca isi",
- "searchprofile-images": "Sarwasarana",
+ "searchprofile-images": "Sarwamadya",
"searchprofile-everything": "Samubarang",
"searchprofile-advanced": "Lungidan",
"searchprofile-articles-tooltip": "Golèkan ing $1",
"search-external": "Panggolèkan èkstèrnal",
"searchdisabled": "Sawetara wektu iki panjenengan ora bisa nggolèk mawa fungsi golèk {{SITENAME}}. Kanggo saiki mangga panjenengan bisa golèk nganggo Google. Nanging isi indèks Google kanggo {{SITENAME}} bisa waé lawas lan durung dianyari.",
"search-error": "Ana kasalahan wektu nggoleki: $1",
- "preferences": "Preferensi (pilihan)",
- "mypreferences": "Préferènsi",
+ "preferences": "Pilihan",
+ "mypreferences": "Pilihan",
"prefs-edits": "Gunggung besutan:",
"prefsnologintext2": "Tulung $1 kanggo ngganti preferensi sampeyan.",
"prefs-skin": "Kulit",
- "skin-preview": "Pratilik",
- "datedefault": "Ora ana préferènsi",
+ "skin-preview": "Pratuduh",
+ "datedefault": "Ora ana pilihan",
"prefs-labs": "Piranti lab",
- "prefs-user-pages": "Kaca panganggo",
- "prefs-personal": "Profil panganggo",
+ "prefs-user-pages": "Kacaning sing nganggo",
+ "prefs-personal": "Panjèrènging sing nganggo",
"prefs-rc": "Owah-owahan pungkasan",
- "prefs-watchlist": "Dhaftar pangawasan",
+ "prefs-watchlist": "Pawawangan",
+ "prefs-editwatchlist": "Besut pawawangan",
+ "prefs-editwatchlist-label": "Besut isining pawawanganing sampéyan",
+ "prefs-editwatchlist-edit": "Deleng lan busak sesirah ing pawawanganing sampéyan",
+ "prefs-editwatchlist-raw": "Besut pawawangan lakaran",
+ "prefs-editwatchlist-clear": "Resiki pawawanganing sampéyan",
"prefs-watchlist-days": "Cacahé dina sing dituduhaké ing dhaftar pangawasan:",
"prefs-watchlist-days-max": "Maksimum $1 {{PLURAL:$1|dina|dina}}",
"prefs-watchlist-edits": "Cacahé suntingan maksimum sing dituduhaké ing dhaftar pangawasan sing luwih jangkep:",
"prefs-watchlist-edits-max": "Gunggung maksimum: 1000",
- "prefs-watchlist-token": "Token pantauan:",
+ "prefs-watchlist-token": "Tokening pawawangan:",
"prefs-misc": "Liya-liya",
"prefs-resetpass": "Ganti tembung sandi",
- "prefs-changeemail": "Ganti alamat layang èlèktronik",
+ "prefs-changeemail": "Owah utawa busak alamat layangtronik",
"prefs-setemail": "Setèl alamat layang èlèktronik",
"prefs-email": "Opsi layang-e",
"prefs-rendering": "Tampilan",
"columns": "Kolom:",
"searchresultshead": "Panggolèkan",
"stub-threshold": "Ambang wates kanggo format <a href=\"#\" class=\"stub\">pranala rintisan</a>:",
+ "stub-threshold-sample-link": "pralampita",
"stub-threshold-disabled": "Dipatèni",
"recentchangesdays": "Cacahé dina sing dituduhaké ing owah-owahan pungkasan:",
"recentchangesdays-max": "(maksimum $1 {{PLURAL:$1|dina|dina}})",
"recentchangescount": "Cacahing besutan sing dituduhaké kanthi baku:",
"prefs-help-recentchangescount": "Iki klebu owah-owahan pungkasan, kaca sajarah, lan log.",
"prefs-help-watchlist-token2": "Ini adalah kunci rahasia (token) ke web feed dari daftar pantauan Anda.\nSiapa saja yang tahu akan dapat melihat daftar pantauan Anda, jadi jangan dibagikan.\n[[Special:ResetTokens|Klik di sini jika Anda perlu menyetel ulang]].",
- "savedprefs": "Préferènsi Panjenengan wis disimpen",
+ "savedprefs": "Prèferènsi Panjenengan wis disimpen",
+ "savedrights": "Haking panganggo {{GENDER:$1|$1}} wis kasimpen.",
"timezonelegend": "Zona wektu:",
"localtime": "Wektu saenggon:",
"timezoneuseserverdefault": "Anggo gawan wiki ($1)",
"prefs-namespaces": "Ruang jeneng / Bilik jeneng",
"default": "baku",
"prefs-files": "Berkas",
- "prefs-custom-css": "CSS pribadi",
- "prefs-custom-js": "JS pribadi",
+ "prefs-custom-css": "CSS priangga",
+ "prefs-custom-js": "JavaScript priangga",
"prefs-common-css-js": "CSS/JS didumaké kanggo kabèh kulit:",
"prefs-reset-intro": "Panjenengan bisa migunakaké kaca iki kanggo mbalèkaké préferensi panjenengan marang setèlan baku situs.\nPembalikan ora bisa dibatalaké.",
"prefs-emailconfirm-label": "Konfirmasi layang-e:",
"prefs-help-signature": "Komentar ing kaca wicara kudu ditapak astani nganggo \"<nowiki>~~~~</nowiki>\" sing bakal dikonvèrsi dadi tapak asta panjenengan lan tanggal wektu.",
"badsig": "Tapak astanipun klèntu; cèk rambu HTML.",
"badsiglength": "Tapak asta panjenengan kedawan.\nAja luwih saka {{PLURAL:$1|karakter|karakter}}.",
- "yourgender": "Jinis kelamin:",
- "gender-unknown": "Ora dinyatakaké",
- "gender-male": "Lanang",
- "gender-female": "Wadon",
+ "yourgender": "Kepiyé sampéyan medhar priangganing sampéyan?",
+ "gender-unknown": "Nalika nyebut sampéyan, piranti alus iku bakal nganggo tembung sing nétral jèndher sabisané",
+ "gender-male": "Dhèwèké mbesut kaca wiki",
+ "gender-female": "Dhèwèké mbesut kaca wiki",
"prefs-help-gender": "Opsional: Dipigunakaké kanggo panyebutan jinis kelamin sing bener déning piranti alus.\nInformasi iki bakal kabuka kanggo publik.",
- "email": "Layang élèktronik (E-mail)",
- "prefs-help-realname": "* <strong>Asma asli</strong> (ora wajib): menawa panjenengan maringi, asma asli panjenengan bakal digunakaké kanggo mènèhi akrédhitasi kanggo kasil karya tulis panjenengan.",
+ "email": "Layangtronik",
+ "prefs-help-realname": "Jeneng asli manasuka.\nMenawa diisi, iku bakal kanggo ngatribusi sampéyan awit karyaning sampéyan.",
"prefs-help-email": "Alamat layang èlèktronik sipaté mung pilihan, nanging dibutuhaké kanggo nyetèl ulang tembung sandhi yèn Sampéyan lali.",
"prefs-help-email-others": "Sampéyan uga bisa milih kanggo ngidinaké wong liya ngubungi Sampéyan liwat layang èlèktronik sing ana ing kaca panganggo utawa kaca guneman.\nAlamat layang èlèktronik Sampéyan ora dituduhaké nalika wong liya ngubungi Sampéyan.",
"prefs-help-email-required": "Alamat layang-e dibutuhaké.",
- "prefs-info": "Informasi dhasar",
+ "prefs-info": "Katerangan pokok",
"prefs-i18n": "Internasionalisasi",
"prefs-signature": "Tapak asma",
"prefs-dateformat": "Format tanggal",
"grouppage-suppress": "{{ns:project}}:Oversight",
"right-read": "Maca kaca-kaca",
"right-edit": "Besut kaca",
- "right-createpage": "Nggawé kaca (sing dudu kaca dhiskusi)",
- "right-createtalk": "Nggawé kaca dhiskusi",
+ "right-createpage": "Gawé kaca (sing dudu kaca parembugan)",
+ "right-createtalk": "Gawé kaca parembugan",
"right-createaccount": "Nggawé rékening (akun) panganggo anyar",
"right-minoredit": "Tandhani minangka besutan cilik",
- "right-move": "Pindhahna kaca",
+ "right-move": "Ngalih kaca",
"right-move-subpages": "Pindhahaké kaca lan kabèh anak-kacané",
"right-move-rootuserpages": "Ngalih kaca panganggo oyod",
"right-movefile": "Mindhah berkas",
"right-bot": "Anggepen minangka prosès otomatis",
"right-nominornewtalk": "Suntingan sithik (''minor'') ora ngwetokaké prompt pesen anyar",
"right-apihighlimits": "Nganggo wates sing luwih dhuwur ing kwéri API",
- "right-writeapi": "Migunakaké API panulisan",
+ "right-writeapi": "Nganggo API tulis",
"right-delete": "Busak kaca-kaca",
"right-bigdelete": "Busak kaca-kaca mawa sajarah panyuntingan sing gedhé",
"right-deletelogentry": "Busak lan batalaké mbusak isi log spésipik",
"right-edituserjs": "Besut barkas-barkas JavaScript panganggo liya",
"right-editmyusercss": "Owahi berkas CSS panganggo sampeyan",
"right-editmyuserjs": "Owahi berkas JavaScript panganggo sampeyan",
- "right-viewmywatchlist": "Dheleng daftar pangawasan sampeyan",
+ "right-viewmywatchlist": "Deleng pawawanganing sampéyan",
"right-editmywatchlist": "Owahi daftar pangawasan sampeyan. Cathetan: ana cara liyane kanggo nambahi kaca menyang daftar, sanadyan ora duwe hak iki.",
"right-viewmyprivateinfo": "Dheleng data pribadi sampeyan (kayata alamat layang elektronik, jeneng asli)",
"right-editmyprivateinfo": "Owahi data pribadi sampeyan (kayata alamat layang elektronik, jeneng asli)",
"right-editmyoptions": "Owahi preferensi sampeyan",
- "right-rollback": "Sacara gelis mbalèkaké panganggo pungkasan sing nyunting kaca tartamtu",
+ "right-rollback": "Balèkaké kanthi gelis besutaning panganggo pungkasan sing mbesut kaca tinamtu",
"right-markbotedits": "Tandhani besutan kawurungan minangka besutan bot",
"right-noratelimit": "Ora dipengaruhi déning wates cacahing suntingan.",
"right-import": "Impor kaca-kaca saka wiki liya",
"action-move": "alihna kaca iki",
"action-move-subpages": "mindahaké kaca iki, lan kabèh anak-kacané",
"action-move-rootuserpages": "ngalih kaca panganggo oyod",
- "action-movefile": "pindhahna berkas iki",
+ "action-movefile": "lih barkas iki",
"action-upload": "ngunggahaké berkas iki",
"action-reupload": "nindhih berkas sing wis ana",
"action-reupload-shared": "nindhih berkas sing wis ana ing papan panyimpanan berkas sing dianggo bebarengan",
"recentchanges-label-minor": "Iki besutan cilik",
"recentchanges-label-bot": "Besutan iki diayahi bot",
"recentchanges-label-unpatrolled": "Besutan iki durung kapatroli",
- "recentchanges-label-plusminus": "Ukuraning kaca diowah kanthi cacahing bèt samangkéné",
+ "recentchanges-label-plusminus": "Ukuran owahing kaca ing bèt",
"recentchanges-legend-heading": "<strong>Legendha:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (uga deleng [[Special:NewPages|pratélaning kaca-kaca anyar]])",
"recentchanges-legend-plusminus": "(''±123'')",
"filehist-deleteone": "busaken iki",
"filehist-revert": "balèkna",
"filehist-current": "saiki",
- "filehist-datetime": "Surya/Tabuh",
+ "filehist-datetime": "Tanggal/Tabuh",
"filehist-thumb": "Gambar cilik",
"filehist-thumbtext": "Gambar cilik kanggo owahan $1",
"filehist-nothumb": "Ora ana miniatur",
"filehist-dimensions": "Alang ujur",
"filehist-filesize": "Gedhené berkas",
"filehist-comment": "Tanggapan",
- "imagelinks": "Panganggoan berkas",
+ "imagelinks": "Panganggoning barkas",
"linkstoimage": "{{PLURAL:$1|Kaca|$1 kaca}} ngisor iki nggayut barkas iki:",
"linkstoimage-more": "Luwih saka $1 {{PLURAL:$1|kaca|kaca-kaca}} nduwèni pranala menyang berkas iki.\nDhaftar ing ngisor nuduhaké {{PLURAL:$1|kaca pisanan kanthi pranala langsung|$1 kaca kanthi pranala langsung}} menyang berkas iki.\n[[Special:WhatLinksHere/$2|dhaftar pepak]] uga ana.",
- "nolinkstoimage": "Ora ana kaca sing nyambung menyang berkas iki.",
+ "nolinkstoimage": "Ora ana kaca sing nggayut menyang barkas iki.",
"morelinkstoimage": "Ndeleng [[Special:WhatLinksHere/$1|luwih akèh pranala]] menyang berkas iki.",
"linkstoimage-redirect": "$1 (alihan berkas) $2",
"duplicatesoffile": "{{PLURAL:$1|berkas ing ngisor arupa duplikat|$1 berkas ing ngisor arupa duplikat}} saka berkas iki ([[Special:FileDuplicateSearch/$2|luwih rinci]]):",
"doubleredirects": "Pangalihan dobel",
"doubleredirectstext": "Kaca iki ngandhut daftar kaca sing ngalih ing kaca pangalihan liyané.\nSaben baris ngandhut pranala menyang pangalihan kapisan lan kapindho, sarta tujuan saka pangalihan kapindho, sing biasané kaca tujuan sing \"sajatiné\", yakuwi pangalihan kapisan kuduné dialihaké menyang kaca tujuan iku.\nJeneng sing wis <del>dicorèk</del> tegesé wis rampung didandani.",
"double-redirect-fixed-move": "[[$1]] wis kapindhahaké, saiki dadi kaca peralihan menyang [[$2]]",
- "double-redirect-fixed-maintenance": "Mbenakaké rong pangalihan saka [[$1]] nèng [[$2]].",
+ "double-redirect-fixed-maintenance": "Otomatis ndandani lih-lihan dhobel saka [[$1]] nyang [[$2]] nalika ana opèn-opènan.",
"double-redirect-fixer": "Révisi pangalihan",
"brokenredirects": "Pangalihan rusak",
"brokenredirectstext": "Pengalihan ing ngisor iki tumuju menyang kaca sing ora ana:",
"wantedtemplates": "Cithakan sing diperlokaké",
"mostlinked": "Kaca sing kerep dhéwé dituju",
"mostlinkedcategories": "Kategori sing kerep dhéwé dienggo",
- "mostlinkedtemplates": "Cithakan sing kerep dhéwé dienggo",
+ "mostlinkedtemplates": "Kaca paling akèh transklusi",
"mostcategories": "Kaca sing kategoriné akèh dhéwé",
"mostimages": "Berkas sing kerep dhéwé dienggo",
"mostinterwikis": "Halaman dengan interwiki terbanyak",
"newpages-username": "Asma panganggo:",
"ancientpages": "Kaca-kaca langkung sepuh",
"move": "Pindhahen",
- "movethispage": "Pindhahna kaca iki",
+ "movethispage": "Lih kaca iki",
"unusedimagestext": "Berkas-berkas sing kapacak iki ana nanging ora dienggo ing kaca apa waé.\nTulung digatèkaké yèn situs wèb liyané mbok-menawa bisa nyambung ing sawijining berkas sacara langsung mawa URL langsung, lan berkas-berkas kaya mengkéné iku mbok-menawa ana ing daftar iki senadyan ora dienggo aktif manèh.",
"unusedcategoriestext": "Kategori iki ana senadyan ora ana artikel utawa kategori liyané sing nganggo.",
"notargettitle": "Ora ana sasaran",
"nopagetext": "Kaca sing panjenengan tuju ora ditemokaké.",
"pager-newer-n": "{{PLURAL:$1|1 luwih anyar|$1 luwih anyar}}",
"pager-older-n": "{{PLURAL:$1|1 sing luwih lawas|$1 sing luwih lawas}}",
- "suppress": "Pangawas (''oversight'')",
+ "suppress": "Dhelikaké",
"querypage-disabled": "Kaca kusus iki dipatèni kanggo alesan kinerja.",
"apisandbox": "Kothak wedhi API",
"apisandbox-api-disabled": "API dipatèni nèng situs iki.",
"usermessage-summary": "Tinggalaké layang sistem.",
"usermessage-editor": "Pawartaning layang sistem",
"watchlist": "Daptar pangawasan",
- "mywatchlist": "Daftar pangawasan",
+ "mywatchlist": "Pawawangan",
"watchlistfor2": "Kanggo $1 $2",
- "nowatchlist": "Daftar pangawasan panjenengan kosong.",
+ "nowatchlist": "Ora ana apa-apa ing pawawanganing sampéyan.",
"watchlistanontext": "Mangga $1 kanggo mirsani utawa nyunting daftar pangawasan panjenengan.",
"watchnologin": "Durung mlebu log",
"addwatch": "Tambah nèng daptar pangawasan",
"addedwatchtext": "Kaca \"[[:$1]]\" wis ditambahaké menyang [[Special:Watchlist|daftar pangawasan]].\nOwah-owahan sing dumadi ing tembé ing kaca iku lan kaca dhiskusi sing kagandhèng, bakal dipacak ing kéné.",
"removewatch": "Singkiraké saka daptar pangawasan",
"removedwatchtext": "Kaca \"[[:$1]]\" wis dibusak saka [[Special:Watchlist|daftar pangawasan]].",
- "watch": "Awati",
+ "watch": "Awasi",
"watchthispage": "Periksa kaca iki",
"unwatch": "Ora usah ngawasaké manèh",
"unwatchthispage": "Batalna olèhé ngawasi kaca iki",
"wlheader-showupdated": "Kaca-kaca sing wis owah wiwit ditiliki panjenengan kaping pungkasan, dituduhaké mawa '''aksara kandel'''",
"wlnote": "Ngisor iki {{PLURAL:$1|owahan pungkasan|'''$1''' owahan pungkasan}} {{PLURAL:$2|jam|'''$2''' jam}} kapungkur, per $3, $4.",
"wlshowlast": "Tuduhna $1 jam $2 dina pungkasan",
- "watchlist-options": "Opsi daftar pangawasan",
+ "watchlist-options": "Pilihaning pawawangan",
"watching": "Ngawasi...",
"unwatching": "Ngilangi pangawasan...",
"watcherrortext": "Ana kasalahan nalika ngganti pangaturan daptar pangawasan Sampéyan kanggo \"$1\".",
"cantrollback": "Ora bisa mbalèkaké suntingan; panganggo pungkasan iku siji-sijiné penulis artikel iki.",
"alreadyrolled": "Ora bisa mbalèkaké suntingan pungkasan [[:$1]] déning [[User:$2|$2]] ([[User talk:$2|Wicara]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]); wong liya wis nyunting utawa mbalèkaké kaca artikel iku.\n\nSuntingan pungkasan dilakoni déning [[User:$3|$3]] ([[User talk:$3|Wicara]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "Ringkesan suntingan yaiku: <em>$1</em>.",
- "revertpage": "Suntingan [[Special:Contributions/$2|$2]] ([[User talk:$2|dhiskusi]]) dipunwangsulaken dhateng ing vèrsi pungkasan déning [[User:$1|$1]]",
+ "revertpage": "Besutan sing dibalèkaké [[Special:Contributions/$2|$2]] ([[User talk:$2|rembugan]]) bab owahan pungkasan déning [[User:$1|$1]]",
"revertpage-nouser": "Suntingan déning panganggo sing didhelikake, dibalèkaké nèng benahan pungkasan déning [[User:$1|$1]]",
"rollback-success": "Suntingan dibalèkaké déning $1;\ndiowahi bali menyang vèrsi pungkasan déning $2.",
"sessionfailure-title": "Sèsi gagal",
"namespace": "Lowah aran:",
"invert": "Balèkaké pilihan",
"tooltip-invert": "Centhang kothak iki kanggo ndhelikaké owahan saka kaca-kaca nèng njero bilik jeneng kapilih (lan bilik jeneng kakait yèn dicenthang)",
- "namespace_association": "Bilik jeneng kakait",
+ "namespace_association": "Lowah aran magepokan",
"tooltip-namespace_association": "Centhang kothak iki kanggo nglebokaké uga bilik jeneng gumenan utawa subyèk sing kakait karo bilik jeneng kapilih",
"blanknamespace": "(Pokok)",
"contributions": "Sumbangan {{GENDER:$1|panganggo}}",
"nolinkshere-ns": " Ora ana kaca sing nduwé pranala menyang '''[[:$1]]''' ing bilik jeneng sing kapilih.",
"isredirect": "kaca lih-lihan",
"istemplate": "karo cithakan",
- "isimage": "pranala berkas",
+ "isimage": "pranala barkas",
"whatlinkshere-prev": "{{PLURAL:$1|sadurungé|$1 sadurungé}}",
"whatlinkshere-next": "{{PLURAL:$1|sabanjuré|$1 sabanjuré}}",
"whatlinkshere-links": "← pranala",
- "whatlinkshere-hideredirs": "$1 pangalihan-pangalihan",
+ "whatlinkshere-hideredirs": "$1 lih-lihan",
"whatlinkshere-hidetrans": "$1 transklusi",
"whatlinkshere-hidelinks": "pranala-pranala $1",
"whatlinkshere-hideimages": "$1 pranala berkas",
"autoblockid": "Blokir otomatis #$1",
"block": "Blokir panganggo",
"unblock": "Uculaké blokirané panganggo",
- "blockip": "Blokir panganggo",
+ "blockip": "Palang {{GENDER:$1|panganggo}}",
"blockip-legend": "Blokir panganggo",
"blockiptext": "Enggonen formulir ing ngisor iki kanggo mblokir sawijining alamat IP utawa panganggo supaya ora bisa nyunting kaca.\nPrekara iki perlu dilakoni kanggo menggak vandalisme, lan miturut [[{{MediaWiki:Policy-url}}|kawicaksanan {{SITENAME}}]].\nLebokna alesan panjenengan ing ngisor iki (contoné njupuk conto kaca sing wis tau dirusak).",
"ipaddressorusername": "Alamat IP utawa jeneng panganggo",
"ipbother": "Wektu liya",
"ipboptions": "2 jam:2 hours,1 dina:1 day,3 dina:3 days,1 minggu:1 week,2 minggu:2 weeks,1 sasi:1 month,3 sasi:3 months,6 sasi:6 months,1 taun:1 year,tanpa wates:infinite",
"ipbhidename": "Delikna jeneng panganggo saka suntingan lan pratélan",
- "ipbwatchuser": "Ngawasi kaca panganggo lan kaca-kaca dhiskusi panganggo iki",
+ "ipbwatchuser": "Wasi kaca panganggoning lan kaca gegunemaning panganggo iki",
"ipb-disableusertalk": "Alangi panganggo iki nyunting kaca gunemané nalika diblokir",
"ipb-change-block": "Blokir manèh panganggo kanthi sèting iki",
"ipb-confirm": "Pesthèkaké blokir",
"noautoblockblock": "pamblokiran otomatis dipatèni",
"createaccountblock": "ndamelipun akun dipunblokir",
"emailblock": "layang e-mail diblokir",
- "blocklist-nousertalk": "ora éntuk nyunting kaca gunemané dhéwé",
+ "blocklist-nousertalk": "ora kena mbesut kaca guneman dhéwé",
"ipblocklist-empty": "Daftar pamblokiran kosong.",
"ipblocklist-no-results": "alamat IP utawa panganggo sing disuwun ora diblokir.",
"blocklink": "palang",
"block-log-flags-nocreate": "opsi nggawé akun utawa rékening dipatèni",
"block-log-flags-noautoblock": "blokir otomatis dipatèni",
"block-log-flags-noemail": "e-mail diblokir",
- "block-log-flags-nousertalk": "ora éntuk nyunting kaca gunemané dhéwé",
+ "block-log-flags-nousertalk": "ora kena mbesut kaca guneman dhéwé",
"block-log-flags-angry-autoblock": "paningkatan sistem pamblokiran otomatis wis diaktifaké",
"block-log-flags-hiddenname": "jeneng panganggo didhelikaké",
"range_block_disabled": "Fungsi pamblokir blok IP kanggo para opsis dipatèni.",
"ipbnounblockself": "Sampéyan ora dililakaké mbukak blokirané Sampéyan",
"lockdb": "Kunci basis data",
"unlockdb": "Buka kunci basis data",
- "lockdbtext": "Ngunci basis data bakal menggak kabèh panganggo kanggo nyunting kaca, ngowahi préferènsi panganggo, nyunting daftar pangawasan, lan prekara-prekara liyané sing merlokaké owah-owahan basis data. Pastèkna yèn iki pancèn panjenengan gayuh, lan yèn panjenengan ora lali mbuka kunci basis data sawisé pangopènan rampung.",
- "unlockdbtext": "Mbuka kunci basis data bakal mbalèkaké kabèh panganggo bisa nyunting kaca manèh, ngowahi préferènsi panganggo, nyunting daftar pangawasan, lan prekara-prekara liyané sing merlokaké pangowahan marang basis data.\nTulung pastèkna yèn iki pancèn sing panjenengan gayuh.",
+ "lockdbtext": "Ngunci basis data bakal menggak kabèh panganggo kanggo nyunting kaca, ngowahi prèferènsi panganggo, nyunting daftar pangawasan, lan prekara-prekara liyané sing merlokaké owah-owahan basis data. Pastèkna yèn iki pancèn panjenengan gayuh, lan yèn panjenengan ora lali mbuka kunci basis data sawisé pangopènan rampung.",
+ "unlockdbtext": "Mbuka kunci basis data bakal mbalèkaké kabèh panganggo bisa nyunting kaca manèh, ngowahi prèferènsi panganggo, nyunting daftar pangawasan, lan prekara-prekara liyané sing merlokaké pangowahan marang basis data.\nTulung pastèkna yèn iki pancèn sing panjenengan gayuh.",
"lockconfirm": "Iya, aku pancèn péngin ngunci basis data.",
"unlockconfirm": "Iya, aku pancèn péngin tmbuka kunci basis data.",
"lockbtn": "Kunci basis data",
"lockfilenotwritable": "Berkas kunci basis data ora bisa ditulis. Kanggo ngunci utawa mbuka basis data, berkas iki kudu ditulis déning server wèb.",
"databasenotlocked": "Basis data ora dikunci.",
"lockedbyandtime": "(déning {{GENDER:$1|$1}} tanggal $2 wanci $3)",
- "move-page": "Pindhahna $1",
+ "move-page": "Ngalih $1",
"move-page-legend": "Mindhah kaca",
"movepagetext": "Formulir ing ngisor iki bakal ngowahi jeneng sawijining kaca, mindhah kabèh sajarahé menyang kaca sing anyar. Irah-irahan utawa judhul sing lawas bakal dadi kaca pangalihan menyang irah-irahan sing anyar. Pranala menyang kaca sing lawas ora bakal diowahi; dadi pastèkna dhisik mriksa pangalihan [[Special:DoubleRedirects|dobel]] utawa [[Special:BrokenRedirects|pangalihan sing rusak]] sawisé pamindhahan. Panjenengan sing tanggung jawab mastèkaké menawa kabèh pranala-pranala tetep nyambung ing kaca panujon kaya samesthiné.\n\nGatèkna yèn kaca iki '''ora''' bakal dipindhah yèn wis ana kaca liyané sing nganggo irah-irahan sing anyar, kejaba kaca iku kosong utawa ora nduwé sajarah panyuntingan. Dadi tegesé panjenengan bisa ngowahi jeneng kaca iku manèh kaya sedyakala menawa panjenengan luput, lan panjenengan ora bisa nimpani kaca sing wis ana.\n\n'''PÈNGET!'''\nPerkara iki bisa ngakibataké owah-owahan sing drastis lan ora kaduga kanggo kaca-kaca sing populèr;\npastekaké dhisik panjenengan ngerti konsekwènsi saka panggayuh panjenengan sadurungé dibanjuraké.",
"movepagetext-noredirectfixer": "Formulir di bawah ini digunakan untuk mengubah nama suatu halaman dan memindahkan semua data sejarah ke nama baru.\nJudul yang lama akan menjadi halaman peralihan menuju judul yang baru.\nPastikan untuk memeriksa pengalihan [[Special:DoubleRedirects|ganda]] atau [[Special:BrokenRedirects|rusak]].\nAnda bertanggung jawab untuk memastikan bahwa pranala terus menyambung ke halaman yang seharusnya.\n\nPerhatikan bahwa halaman '''tidak''' akan dipindah apabila telah ada halaman yang menggunakan judul yang baru, kecuali bila halaman tersebut kosong atau merupakan halaman peralihan dan tidak mempunyai sejarah penyuntingan.\nIni berarti Anda dapat mengubah nama halaman kembali seperti semula apabila Anda membuat kesalahan, dan Anda tidak dapat menimpa halaman yang telah ada.\n\n'''Peringatan:'''\nHal ini dapat mengakibatkan perubahan yang tak terduga dan drastis bagi halaman yang populer;\nPastikan Anda mengerti konsekuensi dari perbuatan ini sebelum melanjutkan.",
- "movepagetalktext": "Kaca dhiskusi sing kagandhèng uga bakal dipindhahaké sacara otomatis '''kejaba yèn:'''\n\n*Sawijining kaca dhiskusi sing ora kosong wis ana sangisoring irah-irahan (judhul) anyar, utawa\n*Panjenengan ora maringi tandha cèk ing kothak ing ngisor iki.\n\nIng kasus-kasus iku, yèn panjenengan gayuh, panjenengan bisa mindhahaké utawa nggabung kaca iku sacara manual.",
+ "movepagetalktext": "Menawa sampéyan nyénthang kothak iki, kaca parembugan sing magepokan bakal otomatis dilih nyang sesirah anyar, kajaba kaca parembugané sing dituju wis ana isiné.\n\nYèn mangkéné, sampéyan kudu ngalih utawa nggabung kaca-kaca iku kanthi manual.",
"moveuserpage-warning": "'''Pèngetan:''' Sampéyan arep mindhahaké kaca panganggo. Mangga cathet yèn namung kaca sing bakal dipindhahaké lan panganggo '''ora''' bakal diganti jenengé.",
"movenologintext": "Panjenengan kudu dadi panganggo sing wis ndaftar lan wis [[Special:UserLogin|mlebu log]] kanggo mindhah kaca.",
"movenotallowed": "Panjenengan ora pareng ngalihaké kaca.",
"movenotallowedfile": "Panjenengan ora duwé hak kanggo mindhahaké berkas.",
"cant-move-user-page": "Panjenengan ora nduwèni hak aksès kanggo mindhahaké kaca panganggo (kapisah saka anak-kaca).",
"cant-move-to-user-page": "Panjenengan ora nduwèni hak aksès kanggo mindhahaké kaca menyang sawijining kaca panganggoa (kajaba menyang anak-kaca panganggo).",
- "newtitle": "Menyang irah-irahan utawa judhul anyar:",
+ "newtitle": "Sesirah anyar:",
"move-watch": "Awasna kaca iki",
- "movepagebtn": "Pindhahna kaca",
+ "movepagebtn": "Ngalih kaca",
"pagemovedsub": "Bisa kasil dipindhahaké",
"movepage-moved": "'''\"$1\" dipindhahaké menyang \"$2\".'''",
"movepage-moved-redirect": "Kaca pengalihan wis kacipta.",
"movepage-moved-noredirect": "Kanggo gawé pengalihan wis ditahan.",
"articleexists": "Satunggalipun kaca kanthi asma punika sampun wonten, utawi asma ingkang panjenengan pendhet mboten leres. Sumangga nyobi asma sanèsipun.",
"cantmove-titleprotected": "Panjenengan ora bisa mindhahaké kaca iki menyang lokasi iki, amerga irah-irahan tujuan lagi direksa; ora olèh digawé",
- "movetalk": "Pindahna kaca dhiskusi sing ana gandhèngané.",
- "move-subpages": "Pindhahna anak-kaca (nganti $1)",
- "move-talk-subpages": "Pindhahna anak-kaca saka kaca wicara (nganti $1)",
+ "movetalk": "Lih kaca parembugan sing magepokan",
+ "move-subpages": "Lih anak kaca (tekan $1)",
+ "move-talk-subpages": "Lih anak kaca saka kaca parembugan (tekan $1)",
"movepage-page-exists": "Kaca $1 wis ana lan ora bisa ditindhes sacara otomatis.",
"movepage-page-moved": "Kaca $1 wis dipindhah menyang $2.",
"movepage-page-unmoved": "Kaca $1 ora bisa dialihaké menyang $2.",
"movenosubpage": "Kaca iki ora duwé anak-kaca.",
"movereason": "Alesan:",
"revertmove": "balèkaké",
- "delete_and_move_text": "== Perlu mbusak ==\n\nArtikel sing dituju, \"[[:$1]]\", wis ana isiné.\nApa panjenengan kersa mbusak iku supaya kacané bisa dialihaké?",
+ "delete_and_move_text": "Kaca jujugan \"[[:$1]]\" wis ana.\nApa sampéyan kersa mbusak iku supaya kacané bisa dilih?",
"delete_and_move_confirm": "Ya, busak kaca iku.",
"delete_and_move_reason": "Dibusak kanggo jaga-jaga ananing pamindhahan saka \"[[$1]]\"",
"selfmove": "Pangalihan kaca ora bisa dilakoni amerga irah-irahan utawa judhul sumber lan tujuané padha.",
"move-leave-redirect": "Gawé pangalihan menyang irah-irahan anyar",
"protectedpagemovewarning": "'''Pènget:''' Kaca iki wis dikunci dadi mung panganggo sing nduwé hak aksès pangurus baé sing bisa mindhahaké.\nCathetan entri pungkasan disadiakaké ing ngisor kanggo referensi:",
"semiprotectedpagemovewarning": "'''Cathetan:''' Kaca iki wis direksa saéngga mung panganggo kadhaptar sing bisa mindhahaké.\nEntri cathetan pungkasan disadiakake ing ngisor kanggo referensi:",
- "move-over-sharedrepo": "== Berkas wis ana ==\n[[:$1]] ana ing panyimpenan bebarengan. Mindhahaké berkas mawa judul iki bakal nibani berkas bebarengan.",
+ "move-over-sharedrepo": "[[:$1]] ana ing panyimpenan barengan. Ngalih barkas mawa sesirah iki bakal ngamblegi barkas barengan iku.",
"file-exists-sharedrepo": "Jeneng berkas kapilih wis ana kanggo nèng panyimpenan bebarengan.\nMangga pilih jeneng liya.",
"export": "Ekspor kaca",
"exporttext": "Panjenengan bisa ngèkspor tèks lan sajarah panyuntingan sawijining kaca tartamtu utawa sawijining sèt kaca awujud XML tartamtu. Banjur iki bisa diimpor ing wiki liyané nganggo MediaWiki nganggo fasilitas [[Special:Import|impor kaca]].\n\nKanggo ngèkspor kaca-kaca artikel, lebokna irah-irahan utawa judhul sajroning kothak tèks ing ngisor iki, irah-irahan utawa judhul siji per baris, lan pilihen apa panjenengan péngin ngèkspor jangkep karo vèrsi sadurungé, utawa namung vèrsi saiki mawa cathetan panyuntingan pungkasan.\n\nYèn panjenengan namun péngin ngimpor vèrsi pungkasan, panjenengan uga bisa nganggo pranala kusus, contoné [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] kanggo ngèkspor artikel \"[[{{MediaWiki:Mainpage}}]]\".",
"thumbnail_gd-library": "Konfigurasi pustaka GD ora pepak: fungsi $1 ilang",
"thumbnail_image-missing": "Berkas katonané ilang: $1",
"import": "Impor kaca",
- "importinterwiki": "Impor transwiki",
+ "importinterwiki": "Impor saka wiki liya",
"import-interwiki-text": "Pilih sawijining wiki lan irah-irahan kaca sing arep diimpor.\nTanggal révisi lan jeneng panyunting bakal dilestarèkaké.\nKabèh aktivitas impor transwiki bakal dilog ing [[Special:Log/import|log impor]].",
"import-interwiki-history": "Tuladen kabèh vèrsi lawas saka kaca iki",
"import-interwiki-templates": "Katutna kabèh cithakan",
"import-logentry-interwiki-detail": "$1 {{PLURAL:$1|révisi}} saka $2",
"javascripttest": "Panjajalan JavaScript",
"javascripttest-qunit-intro": "Delok [dhokumèntasi panjajalan $1] nèng mediawiki.org.",
- "tooltip-pt-userpage": "Kaca {{GENDER:|panganggo sampéyan}}",
+ "tooltip-pt-userpage": "Kaca {{GENDER:|panganggoning sampéyan}}",
"tooltip-pt-anonuserpage": "Kaca panganggo IP panjenengan",
- "tooltip-pt-mytalk": "Kaca paguneman {{GENDER:|sampéyan}}",
- "tooltip-pt-anontalk": "Dhiskusi perkara suntingan saka alamat IP iki",
- "tooltip-pt-preferences": "Pamiji {{GENDER:|sampéyan}}",
- "tooltip-pt-watchlist": "Daftar kaca sing tak-awasi.",
+ "tooltip-pt-mytalk": "Kaca gegunemaning {{GENDER:|sampéyan}}",
+ "tooltip-pt-anontalk": "Parembug ing besutan-besutan saka alamat IP iki",
+ "tooltip-pt-preferences": "Pilih-pilihaning {{GENDER:|sampéyan}}",
+ "tooltip-pt-watchlist": "Pratélaning kaca sing sampéyan awasi owah-owahané",
"tooltip-pt-mycontris": "Pratélaning sumbanganing {{GENDER:|sampéyan}}",
"tooltip-pt-login": "Sampéyan prayogané mlebu masiya ora kudu",
"tooltip-pt-logout": "Metu",
"tooltip-pt-createaccount": "Sampéyan prayogané gawé akun lan mlebu masiya ora kudu",
- "tooltip-ca-talk": "Parembuganing kaca isi",
+ "tooltip-ca-talk": "Rerembuganing kaca isi",
"tooltip-ca-edit": "Besut kaca iki",
"tooltip-ca-addsection": "Miwiti pérangan anyar",
"tooltip-ca-viewsource": "Kaca iki direksa. \nSampéyan bisa ndeleng sumberé",
"tooltip-ca-unprotect": "Ganti panjagan kaca iki",
"tooltip-ca-delete": "Busak kaca iki",
"tooltip-ca-undelete": "Balèkna suntingan ing kaca iki sadurungé kaca iki dibusak",
- "tooltip-ca-move": "Aliha kaca iki",
+ "tooltip-ca-move": "Lih kaca iki",
"tooltip-ca-watch": "Tambahaké kaca iki nyang pawawangan sapéyan",
- "tooltip-ca-unwatch": "Busak kaca iki saka daftar pangawasan panjenengan",
+ "tooltip-ca-unwatch": "Busak kaca iki saka pawawanganing sampéyan",
"tooltip-search": "Golèk nyang {{SITENAME}}",
"tooltip-search-go": "Jujug kaca asesirah persis mangkéné yèn ana",
"tooltip-search-fulltext": "Golèk kaca isi tulisan kaya mangkéné",
- "tooltip-p-logo": "Menyang kaca pokok",
- "tooltip-n-mainpage": "Menyang kaca pokok",
- "tooltip-n-mainpage-description": "Menyang kaca pokok",
+ "tooltip-p-logo": "Menyang tepas",
+ "tooltip-n-mainpage": "Menyang tepas",
+ "tooltip-n-mainpage-description": "Menyang tepas",
"tooltip-n-portal": "Bab proyèk, apa sing bisa sampéyan garap, ana ing endi saprelu golèk apa-apa",
"tooltip-n-currentevents": "Temokaké katerangan latar wuri saka kadadéan saiki",
"tooltip-n-recentchanges": "Pratélaning owah-owahan pungkasan sajeroning wiki.",
"tooltip-ca-nstab-category": "Deleng kaca kategori",
"tooltip-minoredit": "Tandhani iki minangka besutan cilik",
"tooltip-save": "Simpen owah-owahaning sampéyan",
- "tooltip-preview": "Prawuryan owah-owahaning sampéyan. Anggoa cara iki sadurungé nyimpen.",
+ "tooltip-preview": "Pratuduhing owah-owahaning sampéyan. Anggoa cara iki sadurungé nyimpen.",
"tooltip-diff": "Tuduhaké owah-owahan endi sing sampéyan gawé tumrap tulisan iki",
"tooltip-compareselectedversions": "Delengen prabédan antara rong vèrsi kaca iki sing dipilih.",
- "tooltip-watch": "Tambahna kaca iki ing daftar pangawasan panjenengan",
+ "tooltip-watch": "Wuwuh kaca iki nyang pawawanganing sampéyan",
"tooltip-watchlistedit-normal-submit": "Singkiraké judhul",
"tooltip-watchlistedit-raw-submit": "Anyari daptar pangawasan",
"tooltip-recreate": "Gawéa kaca iki manèh senadyan tau dibusak",
"file-info-size": "$1 × $2 piksel, ukuran barkas: $3, jinis MIME: $4",
"file-info-size-pages": "$1 × $2 piksel, gedhéné berkas: $3, jinisé MIME: $4, $5 {{PLURAL:$5|kaca|kaca}}",
"file-nohires": "Ora ana résolusi sing luwih dhuwur.",
- "svg-long-desc": "Berkas SVG, nominal $1 × $2 piksel, gedhené berkas: $3",
+ "svg-long-desc": "Barkas SVG, nominal $1 × $2 piksel, gedhéning barkas: $3",
"svg-long-desc-animated": "Berkas SVG, nominal $1 × $2 piksel, gedhené berkas: $3",
"svg-long-error": "Berkas SVG ora sah: $1",
"show-big-image": "Barkas asli",
- "show-big-image-preview": "Gedhéné pratayang iki: $1",
+ "show-big-image-preview": "Gedhéning pratuduh iki: $1",
"show-big-image-other": "{{PLURAL:$2|Résolusi|Résolusi}} liya: $1.",
"show-big-image-size": "$1 × $2 piksel",
"file-info-gif-looped": "mubeng",
"exif-primarychromaticities": "Kromatisitas werna primer",
"exif-ycbcrcoefficients": "Koèfisièn matriks transformasi papan werna",
"exif-referenceblackwhite": "Wiji réferènsi pasangan ireng putih",
- "exif-datetime": "Tanggal lan wektu pangowahan berkas",
+ "exif-datetime": "Tanggal lan tabuh owahing barkas",
"exif-imagedescription": "Judhul gambar",
"exif-make": "Produsèn kamera",
"exif-model": "Modhèl kaméra",
"exif-sublocationdest": "Dhaèrahé kutha katampilaké",
"exif-objectname": "Judhul cendhèk",
"exif-specialinstructions": "Prèntah kusus",
- "exif-headline": "Warta utama",
+ "exif-headline": "Tajuk",
"exif-credit": "Krédit/Panyadhiya",
"exif-source": "Sumber",
"exif-editstatus": "Status kapanyuntingan gambar",
"namespacesall": "kabèh",
"monthsall": "kabèh",
"confirmemail": "Konfirmasi alamat e-mail",
- "confirmemail_noemail": "Panjenengan ora maringi alamat e-mail sing absah ing [[Special:Preferences|préferènsi]] panjenengan.",
+ "confirmemail_noemail": "Panjenengan ora maringi alamat é-mail sing absah ing [[Special:Preferences|prèferènsi]] panjenengan.",
"confirmemail_text": "{{SITENAME}} ngwajibaké panjenengan ndhedhes utawa konfirmasi alamat e-mail panjenengan sadurungé bisa nganggo fitur-fitur e-mail.\nPencèten tombol ing ngisor iki kanggo ngirim sawijining kode konfirmasi arupa sawijining pranala;\nTuladen pranala iki ing panjlajah wèb panjenengan kanggo ndhedhes yèn alamat e-mail panjenengan pancèn bener.",
"confirmemail_pending": "Sawijining kode konfirmasi wis dikirim menyang alamat e-mail panjenengan;\nyèn panjenengan lagi waé nggawé akun utawa rékening panjenengan, mangga nunggu sawetara menit nganti layang iku tekan sadurungé nyuwun kode anyar manèh.",
"confirmemail_send": "Kirim kode konfirmasi",
"lag-warn-normal": "Owah-owahan pungkasan sing luwih anyar tinimbang $1 {{PLURAL:$1|detik|detik}} mbokmanawa ora metu ing pratélan iki.",
"lag-warn-high": "Amarga gedhéné ''lag'' basis data server, owah-owahan pungkasan sing luwih anyar saka $1 {{PLURAL:$1|detik|detik}} mbokmanawa ora metu ing daftar iki.",
"watchlistedit-normal-title": "Besut pawawangan",
- "watchlistedit-normal-legend": "Busak irah-irahan saka daftar pangawasan",
+ "watchlistedit-normal-legend": "Busak sesirah saka pawawangan",
"watchlistedit-normal-explain": "Irah-irahan utawa judhul ing daftar pangawasan panjenengan kapacak ing ngisor iki.\nKanggo mbusak sawijining irah-irahan, kliken kothak ing pinggiré, lan banjur kliken \"Busak judhul\".\nPanjenengan uga bisa [[Special:EditWatchlist/raw|nyunting daftar mentah]].",
"watchlistedit-normal-submit": "Busak irah-irahan",
"watchlistedit-normal-done": "Irah-irahan {{PLURAL:$1|siji|$1}} wis dibusak saka daftar pangawasan panjenengan:",
"watchlistedit-raw-legend": "Besut pawawangan wantahan",
"watchlistedit-raw-explain": "Irah-irahan ing daftar pangawasan panjenengan kapacak ing ngisor iki, lan bisa diowahi mawa nambahaké utawa mbusak daftar; sairah-irahan saban barisé.\nYèn wis rampung, anyarana kaca daftar pangawasan iki.\nPanjenengan uga bisa [[Special:EditWatchlist|nganggo éditor standar panjenengan]].",
"watchlistedit-raw-titles": "Irah-irahan:",
- "watchlistedit-raw-submit": "Anyarana daftar pangawasan",
- "watchlistedit-raw-done": "Daftar pangawasan panjenengan wis dianyari.",
+ "watchlistedit-raw-submit": "Anyari pawawangan",
+ "watchlistedit-raw-done": "Pawawanganing sampéyan wis dianyari.",
"watchlistedit-raw-added": "{{PLURAL:$1|1 irah-irahan wis|$1 irah-irahan wis}} ditambahaké:",
"watchlistedit-raw-removed": "{{PLURAL:$1|1 irah-irahan wis|$1 irah-irahan wis}} diwetokaké:",
"watchlisttools-view": "Tuduhna owah-owahan sing ana gandhèngané",
"watchlisttools-edit": "Deleng lan besut pawawangan",
"watchlisttools-raw": "Besut pawawangan wantahan",
- "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|wicara]])",
+ "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|rembugan]])",
"duplicate-defaultsort": "Pènget: Kunci pilih asal (''Default sort key'') \"$2\" nggantèkaké kunci pilih asal sadurungé \"$1\".",
"version": "Versi",
"version-extensions": "Èkstènsi sing wis diinstalasi",
- "version-skins": "Kulit",
+ "version-skins": "Kulit sing disetèl",
"version-specialpages": "Kaca astaméwa (kaca kusus)",
"version-parserhooks": "Canthèlan parser",
"version-variables": "Variabel",
"version-entrypoints": "URL tithik lebon",
"version-entrypoints-header-entrypoint": "Tithik lebon",
"version-entrypoints-header-url": "URL",
- "redirect": "Dialihake dening gambar, panganggo, kaca, utawa ID revisi",
+ "redirect": "Lih-lihan miturut barkas, panganggo, kaca, owahan, utawa cathetan",
"redirect-summary": "Kaca astamiwa iki dialihake menyang gambar (jeneng gambar diwenehi), kaca (ID revisi utama ID kaca diwenehi), utawa kaca panganggo (ID panganggo diwenehi). Cara nganggo: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], or [[{{#Special:Redirect}}/user/101]].",
"redirect-submit": "Nuju",
"redirect-lookup": "Golek:",
"intentionallyblankpage": "Kaca iki disengajakaké kosong",
"external_image_whitelist": " #Umbarna larikan iki apa anané<pre>\n#Pigunakaké fragmèn èksprèsi regular (mung bagéyan ing antara //) ing ngisor\n#Fragmèn ini bakal dicocogaké karo URL saka gambar-gambar èksternal\n#Fragmèn sing cocog bakal ditampilaké minangka gambar, yèn ora mung pranala menyang gambar waé sing ditampilaké\n#Larikan sing diwiwiti nganggo # dianggep minangka komentar\n#Iki ora mbédakaké aksara gedhé/cilik\n#Dèlèhna kabèh fragmèn èksprèsi regular sadhuwuré larikan iki. Umbarna larikan iki apa anané</pre>",
"tags": "Tag pangowahan sing absah",
- "tag-filter": "Panyaringan [[Special:Tags|tandha]]:",
+ "tag-filter": "Panyaringan [[Special:Tags|tenger]]:",
"tag-filter-submit": "Penyaring",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tenger|Tenger}}]]: $2)",
"tags-title": "Tag",
"revdelete-uname-unhid": "jeneng panganggo dituduhaké",
"revdelete-restricted": "rèstriksi ditrapaké marang para opsis",
"revdelete-unrestricted": "rèstriksi marang para opsis dijabel",
- "logentry-move-move": "$1 {{GENDER:$2|mindhahaké}} kaca $3 nèng $4",
+ "logentry-move-move": "$1 {{GENDER:$2|ngalih}} kaca $3 nyang $4",
"logentry-move-move-noredirect": "$1 {{GENDER:$2|mindhahaké}} kaca $3 nèng $4 tanpa ninggalaké pangalihan",
"logentry-move-move_redir": "$1 {{GENDER:$2|mindhahaké}} kaca $3 nèng $4 nindesi pangalihan liyane",
"logentry-move-move_redir-noredirect": "$1 {{GENDER:$2|mindhahaké}} kaca $3 nèng $4 nindesi pangalihan liyane tanpa nginggalaké pangalihan",
"api-error-badaccess-groups": "Sampéyan ora dililakaké ngunggah berkas nèng wiki iki.",
"api-error-badtoken": "Kasalahan njero: Token èlèk.",
"api-error-copyuploaddisabled": "Ngunggah saka URL dipatèni nèng sasana iki.",
- "api-error-duplicate": "Ana {{PLURAL:$1|berkas liya|pirang-pirang berkas liya}} sing wis ana nèng situsé saha isiné padha.",
+ "api-error-duplicate": "Wis ana {{PLURAL:$1|barkas liya|barkas-barkas liya}} mawa isi sing padha sajeroning sana jaringan iki.",
"api-error-duplicate-archive": "Ana {{PLURAL:$1|berkas liya|pirang-pirang berkas liya}} sing wis ana nèng situsé saha isiné padha, nanging {{PLURAL:$1|kuwi|kuwi kabèh}} wis dibusak.",
"api-error-empty-file": "Berkas sing Sampéyan kirim kosong.",
"api-error-emptypage": "Nggawé kaca kosong anyar ora dilikaké.",
"special-characters-group-lao": "Lao",
"special-characters-group-khmer": "Khmer",
"api-error-blacklisted": "Mangga pilih judhul liya sing njelasaké",
- "randomrootpage": "Kaca root waton"
+ "randomrootpage": "Kaca dhasaran waton"
}
"SHOTHA",
"Gi777ga",
"Matma Rex",
- "Sopopruidze"
+ "Sopopruidze",
+ "Dixtosa"
]
},
"tog-underline": "ბმულების ხაზგასმა:",
"tog-watchdefault": "დაამატე ჩემი კონტროლის სიას ჩემს მიერ რედაქტირებული გვერდები და ფაილები",
"tog-watchmoves": "ჩასვი გვერდები და ფაილები, რომლებიც მე გადამაქვს, ჩემს კონტროლის სიაში",
"tog-watchdeletion": "ჩასვი გვერდები და ფაილები, რომლებსაც მე ვშლი, ჩემს კონტროლის სიაში",
+ "tog-watchuploads": "დაამატე ჩემი ატვირთული ფაილები ჩემი კონტროლის სიას ხოლმე",
"tog-watchrollback": "დაამატე ჩემი კონტროლის სიას გვერდები, სადაც მე სწრაფი გაუქმება განვახორციელე",
"tog-minordefault": "ყველა რედაქტირების მონიშვნა, როგორც უმნიშვნელო, უპირობოდ",
"tog-previewontop": "წინასწარი გადახედვის ჩვენება რედაქტირების დაფამდე",
"tog-ccmeonemails": "გამომიგზავნე ელფოსტების ასლები, რომლებსაც მე სხვა მომხმარებლებს ვუგზავნი",
"tog-diffonly": "დამალე გვერდის შიგთავსი ცვლილების ქვევით",
"tog-showhiddencats": "დამალული კატეგორიების ჩვენება",
- "tog-norollbackdiff": "á\83\92á\83\90á\83£á\83¥á\83\9bá\83\94á\83\91á\83\98á\83¡á\83\90á\83¡ á\83\92á\83\90á\83\9bá\83\9dá\83¢á\83\9dá\83\95á\83\94á\83\97 ცვლილებათა განსხვავება",
+ "tog-norollbackdiff": "á\83ªá\83\95á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98á\83¡ á\83\92á\83\90á\83£á\83¥á\83\9bá\83\94á\83\91á\83\98á\83¡á\83\90á\83¡ á\83\90á\83 á\83\9bá\83\90á\83\9cá\83\90á\83®á\83\9d ცვლილებათა განსხვავება",
"tog-useeditwarning": "გამაფრთხილე, როდესაც დავტოვებ რედაქტირებად გვერდს, დაუმახსოვრებელი ცვლილებებით",
"tog-prefershttps": "უსაფრთხო კავშირის მუდამ გამოყენება ავტორიზაციის შემდეგ",
"underline-always": "მუდამ",
"password-change-forbidden": "თქვენ არ შეგიძლიათ ამ ვიკიში პაროლის შეცვლა.",
"externaldberror": "საგარეო მონაცემთა ბაზაში აუტენტიფიკაციის შეცდომაა, ან თქვენ არ გაქვთ საკმარისი უფლებები საგარეო ანგარიშში ცვლილებების შესატანად.",
"login": "შესვლა",
+ "login-security": "დაადასტურეთ თქვენი ავთენტურობა",
"nav-login-createaccount": "შესვლა / რეგისტრაცია",
"userlogin": "შესვლა/ანგარიშის შექმნა",
"userloginnocreate": "შესვლა",
"userlogin-resetpassword-link": "დაგავიწყდათ პაროლი?",
"userlogin-helplink2": "დახმარება:შესვლა",
"userlogin-loggedin": "თქვენ უკვე შეხვედით როგორც {{GENDER:$1|$1}}.\nგამოიყენეთ ფორმა ქვემოთ, რათა შეხვიდეთ სხვა ანგარიშიდან.",
+ "userlogin-reauth": "თქვენ კვლავ უნდა შეხვიდეთ სისტემაში რათა შემოწმდეს რომ ხართ $1",
"userlogin-createanother": "სხვა ანგარიშის შექმნა",
"createacct-emailrequired": "ელ. ფოსტის მისამართი",
"createacct-emailoptional": "ელ. ფოსტის მისამართი (არასავალდებულო)",
"createacct-email-ph": "შეიყვანეთ თქვენი ელ. ფოსტის მისამართი",
"createacct-another-email-ph": "შეიყვანეთ ელ.ფოსტის მისამართი",
"createaccountmail": "გამოიყენეთ შემთხვევითობის მეთოდით შერჩეული დროებითი პაროლი და გააგზავნეთ მითითებულ ელ.ფოსტის მისამართზე",
+ "createaccountmail-help": "შეიძლება იქნას გამოყენებული სხვისი პირონების ანგარიშის შექმნისთვის მისი პაროლის ცოდნის გარეშე",
"createacct-realname": "ნამდვილი სახელი (არააუცილებელი)",
"createaccountreason": "მიზეზი:",
"createacct-reason": "მიზეზი",
"createacct-reason-ph": "რატომ ქმნით ახალ ანგარიშს?",
+ "createacct-reason-help": "მესიჯი რომელიც გამოჩნდება ანგარიშის შექმის აღრიცხვის ჟურნალში",
"createacct-submit": "შექმენით თქვენი ანგარიში",
"createacct-another-submit": "ანგარიშის შექმნა",
+ "createacct-continue-submit": "განაგრძე ანგარიშის შექმნა",
+ "createacct-another-continue-submit": "განაგრძე ანგარიშის შექმნა",
"createacct-benefit-heading": "{{SITENAME}} შექმნილია თქვენნაირი ადამიანების მიერ.",
"createacct-benefit-body1": "{{PLURAL:$1|რედაქტირება|რედაქტირება}}",
"createacct-benefit-body2": "{{PLURAL:$1|გვერდი|გვერდი}}",
"nocookieslogin": "{{SITENAME}} მომხმარებლების შესვლისთვის იყენებს \"ქუქის ჩანაწერს\". თქვენ იგი გათიშეთ. გთხოვთ, ჩართოთ ისინი და ხელმეორედ მოსინჯოთ.",
"nocookiesfornew": "მომხმარებლის ანგარიში არ შექმნილა, რადგან მისი წყარო ვერ დადასტურდა.\nუზრუნველყოფილი უნდა იყოს ჭდეების აქტიურობა. შემდეგ განაახლეთ გვერდი და სცადეთ ხელახლა",
"nocookiesforlogin": "{{int:nocookieslogin}}",
+ "createacct-loginerror": "ანგარიში წარმატებით შეიქმნა, თუმცა თქვენ ვერ შეხვალთ სისტემაში ავტომატურად. გთხოვთ გამოიყენოთ [[Special:UserLogin|ეს გვერდი]].",
"noname": "თქვენს მიერ მითითებული მომხმარებლის სახელი ქმედითი არ არის.",
"loginsuccesstitle": "სისტემაში შესვლა განხორციელდა",
"loginsuccess": "'''ამჟამად შესული ხართ {{SITENAME}}-ში როგორც „$1“.'''",
- "nosuchuser": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\98 á\83¡á\83\90á\83®á\83\94á\83\9aá\83\90á\83\93 $1 á\83\90á\83 á\83\90á\83 á\83¡á\83\94á\83\91á\83\9dá\83\91á\83¡.\ná\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\97á\83\90 á\83¡á\83\90á\83®á\83\94á\83\9aá\83\94á\83\91á\83\98 á\83\92á\83 á\83«á\83\9cá\83\9dá\83\91á\83\90á\83\93á\83\98á\83\90 á\83\90á\83¡á\83\9dá\83\94á\83\91á\83\98á\83¡ á\83 á\83\94á\83\92á\83\98á\83¡á\83¢á\83 á\83\90á\83\9bá\83\93á\83\94..\ná\83¨á\83\94á\83\90á\83\9bá\83\9dá\83¬á\83\9bá\83\94á\83\97 á\83¡á\83\90á\83®á\83\94á\83\9aá\83\98á\83¡ á\83\93á\83\90á\83¬á\83\94á\83 á\83\90 á\83\90á\83\9c[[Special:UserLogin/signup|შექმენით ახალი ანგარიში]].",
+ "nosuchuser": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\98 á\83¡á\83\90á\83®á\83\94á\83\9aá\83\90á\83\93 $1 á\83\90á\83 á\83\90á\83 á\83¡á\83\94á\83\91á\83\9dá\83\91á\83¡.\ná\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\97á\83\90 á\83¡á\83\90á\83®á\83\94á\83\9aá\83\94á\83\91á\83¨á\83\98 á\83\90á\83¡á\83\9dá\83\94á\83\91á\83\98á\83¡ á\83 á\83\94á\83\92á\83\98á\83¡á\83¢á\83 á\83¡ á\83\90á\83¥á\83\95á\83¡ á\83\9bá\83\9cá\83\98á\83¨á\83\95á\83\9cá\83\94á\83\9aá\83\9dá\83\91á\83\90.\ná\83¨á\83\94á\83\90á\83\9bá\83\9dá\83¬á\83\9bá\83\94á\83\97 á\83¡á\83\90á\83®á\83\94á\83\9aá\83\98 á\83\90á\83\9c [[Special:CreateAccount|შექმენით ახალი ანგარიში]].",
"nosuchusershort": "მომხმარებელი სახელით „$1“ არ არსებობს. შეამოწმეთ მართლწერა.",
"nouserspecified": "საჭიროა მომხმარებლის სახელის მითითება.",
"login-userblocked": "ეს მომხმარებელი დაბლოკილია. სისტემაში შესვლა არაა ნებადართული.",
"noemail": "აქ „$1“ მომხმარებლის ელ. ფოსტის მისამართი მითითებული არ არის.",
"noemailcreate": "თქვენ უნდა მიუთითოთ ელ-ფოსტის კორექტული მისამართი.",
"passwordsent": "ახალი პაროლი გაიგზავნა ელ-ფოსტით მომხმარებელს \"$1\".\nგთხოვთ შეხვიდეთ სისტემაში მისი მიღების შემდეგ.",
- "blocked-mailpassword": "á\83\97á\83¥á\83\95á\83\94á\83\9cá\83\98 IP á\83\9bá\83\98á\83¡á\83\90á\83\9bá\83\90á\83 á\83\97á\83\98 á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\94á\83\91á\83\98á\83¡á\83\97á\83\95á\83\98á\83¡ á\83\93á\83\90á\83\91á\83\9aá\83\9dá\83\99á\83\98á\83\9aá\83\98á\83\90, á\83\90á\83\9bá\83\98á\83¢á\83\9dá\83\9b á\83\90á\83 á\83¨á\83\94á\83\92á\83\98á\83«á\83\9aá\83\98á\83\90á\83\97 á\83\9eá\83\90á\83 á\83\9dá\83\9aá\83\98á\83¡ á\83\90á\83¦á\83\93á\83\92á\83\94á\83\9cá\83\98á\83¡ á\83\92á\83\90á\83\9bá\83\9dá\83§á\83\94á\83\9cá\83\94á\83\91á\83\90 á\83\99á\83\9dá\83\9cá\83¤á\83\9aá\83\98á\83¥á\83¢á\83\98á\83¡ á\83\92á\83\90á\83\9bá\83\9d.",
+ "blocked-mailpassword": "á\83\97á\83¥á\83\95á\83\94á\83\9cá\83\98 IP á\83\9bá\83\98á\83¡á\83\90á\83\9bá\83\90á\83 á\83\97á\83\98 á\83\93á\83\90á\83\91á\83\9aá\83\9dá\83\99á\83\98á\83\9aá\83\98á\83\90 á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\94á\83\91á\83\98á\83¡á\83\92á\83\90á\83\9c á\83\93á\83\90 á\83¡á\83\98á\83¡á\83¢á\83\94á\83\9bá\83\98á\83¡ á\83¨á\83\94á\83¡á\83\90á\83«á\83\9aá\83\9d á\83\90á\83 á\83\90á\83\99á\83\94á\83\97á\83\98á\83\9aá\83¡á\83\98á\83\9cá\83\93á\83\98á\83¡á\83\98á\83\94á\83 á\83\98 á\83\92á\83\90á\83\9bá\83\9dá\83§á\83\94á\83\9cá\83\94á\83\91á\83\98á\83¡á\83\92á\83\90á\83\9c á\83\97á\83\90á\83\95á\83\98á\83¡ á\83\90á\83 á\83\98á\83\93á\83\94á\83\91á\83\98á\83¡ á\83\9bá\83\98á\83\96á\83\9cá\83\98á\83\97 á\83\9eá\83\90á\83 á\83\9dá\83\9aá\83\98á\83¡ á\83\90á\83¦á\83\93á\83\92á\83\94á\83\9cá\83\90á\83ª á\83¨á\83\94á\83\96á\83¦á\83£á\83\93á\83£á\83\9aá\83\98á\83\90.",
"eauthentsent": "A confirmation email has been sent to the specified email address.\nBefore any other email is sent to the account, you will have to follow the instructions in the email, to confirm that the account is actually yours.",
"throttled-mailpassword": "პაროლის შეხსენება უკვე გაგზავნილია ბოლო {{PLURAL:$1|საათის|$1 საათის}} განმავლობაში.\nბოროტად გამოყენების თავიდან აცილებისთვის, მხოლოდ ერთი შეხსენება იგზავნება ყოველ {{PLURAL:$1|საათში|$1 საათში}}.",
"mailerror": "შეცდომა ფოსტის გაგზავნაში: $1",
"createacct-another-realname-tip": "რეალური სახელი არასავალდებულოა.\nთუ თქვენ მას მიუთითებთ, იგი გამოყენებული იქნება იმისათვის, რომ ნაჩვენები იყოს ვის მიერ იყო შეტანილი გვერდის ცვლილება.",
"pt-login": "შესვლა",
"pt-login-button": "შესვლა",
+ "pt-login-continue-button": "სისტემაში შესვლის გაგრძელება",
"pt-createaccount": "ანგარიშის შექმნა",
"pt-userlogout": "გასვლა",
"php-mail-error-unknown": "ამოუცნობი შეცდომა PHP-ის mail() ფუნქციაში",
"botpasswords-invalid-name": "მითითებული მომხმარებელი ბოტის პაროლის გამყოფს (\"$1\").",
"botpasswords-not-exist": "მომხმარებელ \"$1\"-ს არ აქვს ბოტის პაროლი, სახელად \"$2\".",
"resetpass_forbidden": "პაროლის შეცვლა შეუძლებელია",
+ "resetpass_forbidden-reason": "პაროლების შეცვლა შეუძლებელია: $1",
"resetpass-no-info": "კონკრეტულად ამ გვერდთან სამუშაოდ თქვენ უნდა წარადგინოთ თავი სისტემისადმი.",
"resetpass-submit-loggedin": "პაროლის შეცვლა",
"resetpass-submit-cancel": "გაუქმება",
"passwordreset-emailsentusername": "თუ არსებობს მეილი, რომელიც ამ ანგარიშთანაა დაკავშირებული, გაიგზავნება პაროლის თავიდან დასაყენებელი ელექტრონული ფოსტა.",
"passwordreset-emailsent-capture": "ქვემოთ ნაჩვენები პაროლის თავიდან დასაყენებელი წერილი გაიგზავნა.",
"passwordreset-emailerror-capture": "ქვემოთ მოცემულია შექმნილი პაროლის დასაყენებელი წერილი, რომლის გაგზავნაც {{GENDER:$2|მომხმარებელთან}} ვერ მოხერხდა: $1 გამო",
+ "passwordreset-emailsent-capture2": "პაროლის გაუქმების შესახებ {{PLURAL:$1|მეილი|მეილები}} გაიგზავნა. {{PLURAL:$1|სახელი და პაროლი|სახელებისა და პაროლების სია}} არის ნაჩვენები ქვემოთ.",
+ "passwordreset-emailerror-capture2": "{{GENDER:$2|მომხმარებელთან}} მეილის გაგზავნა ვერ მოხერხდა: $1 {{PLURAL:$3|სახელი და პაროლი|სახელებისა და პაროლების სია}} არის ნაჩვენები ქვემოთ.",
+ "passwordreset-nocaller": "გამომძახებელი უნდა იყოს მიწოდებული",
+ "passwordreset-nosuchcaller": "გამომძახებელი არ არსებობს: $1",
+ "passwordreset-ignored": "პაროლის გაუქმება არ იქნა შესრულებული. შეიძლება კონფიგურაციაში პროვაიდერი არ იყო გათვალისწინებული?",
+ "passwordreset-invalideamil": "ელ-ფოსტის არასწორი მისამართი",
+ "passwordreset-nodata": "არც მომხმარებლის სახელი და არც ელ-ფოსტის მისამართი არ იყო მოწოდებული",
"changeemail": "ელ-ფოსტის მისამართის შეცვლა ან წაშლა",
"changeemail-header": "შეავსეთ ეს ფორმა მეილის შესაცვლელად. თუ გსურთ თქვენი ანგარიში არ იყოს დაკავშირებული არცერთ მეილთან, ახალი მეილის მისამართის ველი დატოვეთ ცარიელი.",
"changeemail-passwordrequired": "ამ ცვლილების დასადასტურებლად დაგჭირდებათ პაროლის შეყვანა.",
"minoredit": "მცირე რედაქტირება",
"watchthis": "უთვალთვალე ამ გვერდს",
"savearticle": "გვერდის შენახვა",
+ "publishpage": "გვერდის გამოქვეყნება",
"preview": "წინასწარი გადახედვა",
"showpreview": "წინასწარი გადახედვის ჩვენება",
"showdiff": "ცვლილებების ჩვენება",
"accmailtext": "შემთხვევითი მეთოდით შექმნილი პაროლი მომხმარებლისათვის [[User talk:$1|$1]] გაგზავნილია მისამართზე $2.\n\nავტორიზაციის გავლის შემდეგ შესაძლებელი იქნება ამ ანგარიშის ''[[Special:ChangePassword|პაროლის შეცვლა]]'' ანგარიშში შესვლის გვერდზე.",
"newarticle": "(ახალი)",
"newarticletext": "ბმულის მეშვეობით თქვენ მოხვდით გვერდზე, რომელიც ჯერ არ არსებობს.\nგვერდის შესაქმნელად შეიყვანეთ ინფორმაცია ქვემო ფანჯარაში\n(იხ. [$1 დახმარების გვერდი] დამატებითი ინფორმაციისთვის).\nთუ ამ გვერდზე შეცდომით მოხვდით, დაბრუნდით უკან თქვენი ბრაუზერის მეშვეობით.",
- "anontalkpagetext": "----''ეს არის ანონიმური მომხმარებლის განხილვის გვერდი, რომელსაც ანგარიში ჯერ არ შეუქმნია ან არ იყენებს მას.\n\nშესაბამისად, ჩვენ მისი ციფრული IP მისამართი უნდა გამოვიყენოთ მისი იდენტიფიცირებისთვის.\n\nამგვარი მისამართი შეიძლება რამდენიმე მომხმარებელმა გამოიყენოს.\n\nთუ თქვენ ანონიმური მომხმარებელი ხართ და თვლით, რომ სხვისთვის გამიზნული მითითება მიიღეთ, გთხოვთ [[Special:UserLogin/signup|შექმენით ანგარიში ან დარეგისტრირდით]] მომავალში გაუგებრობის თავიდან ასაცილებლად.''",
+ "anontalkpagetext": "----\n<em>ეს არის ანონიმური მომხმარებლის განხილვის გვერდი, რომელსაც ანგარიში ჯერ არ შეუქმნია ან არ იყენებს მას.</em>\n\nშესაბამისად, ჩვენ მისი ციფრული IP მისამართი უნდა გამოვიყენოთ მისი იდენტიფიცირებისთვის.\nამგვარი მისამართი შეიძლება რამდენიმე მომხმარებელმა გამოიყენოს.\n\nთუ თქვენ ხართ ანონიმური მომხმარებელი და თვლით, რომ გაუგებარი მითითებები მიიღეთ, გთხოვთ ან [[Special:UserLogin|შედით სისტემაში]] ან [[Special:CreateAccount|დაარეგისტირიეთ]] თქვენი ანგარიში მომავალში გაუგებრობის თავიდან ასაცილებლად.",
"noarticletext": "ამჟამად ამ გვერდზე ტექსტი არ არსებობს.\nთქვენ შეგიძლიათ [[Special:Search/{{PAGENAME}}|მოძებნოთ ამ გვერდის სათაური]] სხვა გვერდებზე,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} მოძებნოთ შესაბამისი ჟურნალები],\nან [{{fullurl:{{FULLPAGENAME}}|action=edit}} დაიწყოთ ამ გვერდის რედაქტირება]</span>.",
"noarticletext-nopermission": "ამ დროისთვის ეს გვერდი ცარიელია.\nთქვენ შეგიძლიათ [[Special:Search/{{PAGENAME}}|მოძებნოთ ეს სათაური]] სხვა გვერდებზე,\nან <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} მოძებნოთ ჟურნალების შესაბამისი ჩანაწერები].</span> თქვენ არ გაქვთ ამ გვერდის შექმნის ნებართვა.",
"missing-revision": "ვერსია $1 გვერდისათვის „{{FULLPAGENAME}}“ არ არსებობს.\n\nეს ჩვეულებრივ ხდება მაშინ, თუ მოძველებული ბმულით გადადიხართ გვერდზე, რომელიც წაიშალა.\nდეტალური ინფორმაცია შესაძლებელია იყოს [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} წაშლების ჟურნალში].",
"userpage-userdoesnotexist": "მომხმარებლის ანგარიში „$1“ არ არსებობს. დარწმუნდით, რომ ნამდვილად გსურთ ამ ანგარიშის შექმნა ან შესწორება.",
"userpage-userdoesnotexist-view": "მომხმარებელი „$1“ არ არის დარეგისტრირებული.",
"blocked-notice-logextract": "ეს მომხმარებელი უკვე დაიბლოკა.\nდაბლოკვის მიზეზი შემდეგშია:",
- "clearyourcache": "'''შენიშვნა:''' შენახვის შემდეგ შესაძლოა დაგჭირდეთ ბრაუზერის ქეშის გაწმენდა ცვლილებების სანახავად. \n* '''Firefox / Safari:''' დააჭირეთ ''Shift'' ''Reload''-ზე დაწკაპებისას, ან დააჭირეთ ''Ctrl-F5'', ან ''Ctrl-R'' (''⌘-R'' Mac-ზე); \n* '''Google Chrome:''' დააჭირეთ ''Ctrl-Shift-R'' (''⌘-Shift-R'' Mac-ზე);\n* '''IE:''' დააჭირეთ ''Ctrl'' ''Refresh''-ზე დაწკაპებისას, ან დააჭირეთ ''Ctrl-F5'';\n* '''Opera''' გაწმინდეთ კეში ''Tools→Preferences''-დან.",
+ "clearyourcache": "<strong>შენიშვნა:</strong> შენახვის შემდეგ შესაძლოა დაგჭირდეთ ბრაუზერის ქეშის გაწმენდა ცვლილებების სანახავად. \n* <strong>Firefox / Safari:</strong> დააჭირეთ <em>Shift</em> და <em>Reload</em>, ან დააჭირეთ <em>Ctrl-F5</em>, ან <em>Ctrl-R</em> (<em>⌘-R</em> Mac-ზე); \n* <strong>Google Chrome:</strong> დააჭირეთ <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> Mac-ზე);\n* <strong>IE:</strong> დააჭირეთ <em>Ctrl</em> და <em>Refresh</em>, ან დააჭირეთ <em>Ctrl-F5</em>;\n* <strong>Opera</strong> გაწმინდეთ კეში <em>Tools→Preferences</em>-დან.",
"usercssyoucanpreview": "'''რჩევა:''' შენახვამდე გამოიყენეთ ღილაკი \"{{int:showpreview}}\" თქვენი ახალი CSS ტესტირებისთვის.",
"userjsyoucanpreview": "'''რჩევა:''' შენახვამდე გამოიყენეთ ღილაკი \"{{int:showpreview}}\" თქვენი ახალი JS ტესტირებისთვის.",
"usercsspreview": "'''გახსოვდეთ, რომ თქვენ მხოლოდ წინასწარ გადახედვას უყურებთ თქვენს მომხმარებლის CSS-ს, ის ჯერ შენახული არ არის!'''",
"right-override-export-depth": "გვერდების ექსპორტირება, დაკავშირებული გვერდების ჩათვლით 5-მდე სიიღრმით",
"right-sendemail": "გაგუგზავნე ელექტრონული ფოსტა სხვა მომხმარებლებს",
"right-passwordreset": "ელ.ფოსტის ნახვა პაროლის შეცვლით",
- "right-managechangetags": "[[Special:Tags|tags]] შექმნა და წაშლა მონაცემთა ბაზიდან",
+ "right-managechangetags": "[[Special:Tags|ტეგების]] შექმნა და (დე)აქტივაცია",
"right-applychangetags": "[[Special:Tags|tags]] მიღება თქვენ ცვლილებებთან ერთად",
"right-changetags": "თვითნებური [[Special:Tags|tags]] დამატება ან წაშლა ცალკეულ ცვლილებებსა და ჟურნალის ჩანაწერებში",
"grant-generic": "\"$1\" უფლებები",
"action-viewmyprivateinfo": "თქვენი პირადი ინფორმაციის ხილვა",
"action-editmyprivateinfo": "თქვენი პირადი ინფორმაციის რედაქტირება",
"action-editcontentmodel": "გვერდის კონტენტური მოდელის რედაქტირება",
- "action-managechangetags": "á\83\93á\83\90á\83¡á\83\90á\83\97á\83\90á\83£á\83 á\83\94á\83\91á\83\98á\83¡ á\83¨á\83\94á\83¥á\83\9bá\83\9cá\83\90 á\83\93á\83\90 á\83¬á\83\90á\83¨á\83\9aá\83\90 á\83\9bá\83\9dá\83\9cá\83\90á\83ªá\83\94á\83\9bá\83\97á\83\90 á\83\91á\83\90á\83\96á\83\98á\83\93á\83\90á\83\9c",
+ "action-managechangetags": "á\83¢á\83\94á\83\92á\83\94á\83\91á\83\98á\83¡ á\83¨á\83\94á\83¥á\83\9bá\83\9cá\83\90 á\83\93á\83\90 (á\83\93á\83\94)á\83\90á\83¥á\83¢á\83\98á\83\95á\83\90á\83ªá\83\98á\83\90",
"action-applychangetags": "ტეგების მიღება თქვენ ცვლილებებთან ერთად",
"action-changetags": "თავისუფალი ტეგების დამატება და წაშლა ცალკეულ ცვლილებებსა და ჟურნალების ჩანაწერებში",
"nchanges": "$1 ცვლილება",
"recentchangeslinked-page": "გვერდის დასახელება:",
"recentchangeslinked-to": "საპირისპიროდ აჩვენეთ ამ გვერდზე ბმულის მქონე გვერდების ცვლილებები",
"recentchanges-page-added-to-category": "[[:$1]] დამატებულია კატეგორიაში",
- "recentchanges-page-added-to-category-bundled": "[[:$1]] და [[Special:WhatLinksHere/$1|{{PLURAL:$2|ერთი გვერდი|$2 გვერდი}}]] დამატებულია კატეგორიაში",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] დაემატა კატეგორიას, [[Special:WhatLinksHere/$1|ეს გვერდი არის გამოყნებული სხვა გვერდებში]]",
"recentchanges-page-removed-from-category": "[[:$1]] წაიშალა კატეგორიიდან",
- "recentchanges-page-removed-from-category-bundled": "[[:$1]] á\83\93á\83\90 [[Special:WhatLinksHere/$1|{{PLURAL:$2|á\83\94á\83 á\83\97á\83\98 á\83\92á\83\95á\83\94á\83 á\83\93á\83\98|$2 á\83\92á\83\95á\83\94á\83 á\83\93á\83\98}}]] á\83¬á\83\90á\83\98á\83¨á\83\90á\83\9aá\83\90 á\83\99á\83\90á\83¢á\83\94á\83\92á\83\9dá\83 á\83\98á\83\98á\83\93á\83\90á\83\9c",
+ "recentchanges-page-removed-from-category-bundled": "[[:$1]] á\83\90á\83\9bá\83\9dá\83\95á\83\90á\83 á\83\93á\83\90 á\83\99á\83\90á\83¢á\83\94á\83\92á\83\9dá\83 á\83\98á\83\98á\83\93á\83\90á\83\9c. [[Special:WhatLinksHere/$1|á\83\94á\83¡ á\83\92á\83\95á\83\94á\83 á\83\93á\83\98 á\83\92á\83\90á\83\9bá\83\9dá\83\98á\83§á\83\94á\83\9cá\83\94á\83\91á\83\90 á\83¡á\83®á\83\95á\83\90 á\83\92á\83\95á\83\94á\83 á\83\93á\83\94á\83\91á\83¨á\83\98]]",
"autochange-username": "მედიავიკის ავტომატური ცვლილება",
"upload": "ფაილის დამატება",
"uploadbtn": "ფაილის დამატება",
"upload-form-label-own-work": "ეს ჩემი პირადი ნამუშევარია",
"upload-form-label-infoform-categories": "კატეგორიები",
"upload-form-label-infoform-date": "თარიღი",
- "upload-form-label-own-work-message-local": "ვადასტურებ, რომ ვტვირთავვ ამ ფაილს მომსახურების პირობებისა და ლიცენსიის პოლიტიკის შესაბამისად {{SITENAME}}-ზე.",
- "upload-form-label-not-own-work-message-local": "თუ ვერ ტვირთავთ ამ ფაილს {{SITENAME}}-ის წესების დაცვით, გთხოვთ დახურეთ ეს ფანჯარა და სცადეთ სხვა მეთოდი.",
- "upload-form-label-not-own-work-local-local": "შეგიძლიათ სცადოთ [[Special:Upload|მთავარი ატვირთვის გვერდი]].",
- "upload-form-label-own-work-message-default": "ვიცი, რომ ამ ფაილს ვტვირთავ საზიარო ბაზაში. ვადასტურებ, რომ ამას ვაკეთებ მომსახურების პირობებისა და ლიცენზიის პოლიტიკის შესაბამისად.",
- "upload-form-label-not-own-work-message-default": "თუ ვერ ტვირთავთ ამ ფაილს {{SITENAME}}-ის წესების დაცვით, გთხოვთ დახურეთ ეს ფანჯარა და სცადეთ სხვა მეთოდი.",
- "upload-form-label-not-own-work-local-default": "შეგიძლიათ ასევე სცადოთ [[Special:Upload|ატვირთვის გვერდი {{SITENAME}}-ზე]], თუ ამ ფაილის ატვირთვა დაშვებულია მათი პოლიტიკის მიხედვით.",
- "upload-form-label-own-work-message-shared": "მე ვადასტურებ, რომ ამ ფაილზე საავტორო უფლებების მფლობელი ვარ და ვთანხმდები ამ ფაილის შეუქცევადად განთავსებაზე ვიკისაწყობში [https://creativecommons.org/licenses/by-sa/4.0/deed.ka Creative Commons Attribution-ShareAlike 4.0] ლიცენზიით, აგრეთვე ვეთანხმები [https://wikimediafoundation.org/wiki/Terms_of_Use გამოყენების წესებს].",
- "upload-form-label-not-own-work-message-shared": "თუ თქვენ არ ხართ საავტორო უფლებებს ამ ფაილზე, ან გსურთ გაუშვათ განსხვავებული ლიცენზიით, გთხოვთ გამოიყენეთ [https://commons.wikimedia.org/wiki/Special:UploadWizard ვიკისაწყობის ატვირთვის ფუნქცია].",
- "upload-form-label-not-own-work-local-shared": "შეგიძლიათ ასევე სცადოთ [[Special:Upload|ატვირთვის გვერდი {{SITENAME}}-ზე]], თუ ამ ფაილის ატვირთვა დაშვებულია მათი პოლიტიკის შესაბამისად.",
+ "upload-form-label-own-work-message-generic-local": "ვადასტურებ, რომ ვტვირთავვ ამ ფაილს მომსახურების პირობებისა და ლიცენსიის პოლიტიკის შესაბამისად {{SITENAME}}-ზე.",
+ "upload-form-label-not-own-work-message-generic-local": "თუ ვერ ტვირთავთ ამ ფაილს {{SITENAME}}-ის წესების დაცვით, გთხოვთ დახურეთ ეს ფანჯარა და სცადეთ სხვა მეთოდი.",
+ "upload-form-label-not-own-work-local-generic-local": "შეგიძლიათ სცადოთ [[Special:Upload|მთავარი ატვირთვის გვერდი]].",
+ "upload-form-label-own-work-message-generic-foreign": "ვიცი, რომ ამ ფაილს ვტვირთავ საზიარო ბაზაში. ვადასტურებ, რომ ამას ვაკეთებ მომსახურების პირობებისა და ლიცენზიის პოლიტიკის შესაბამისად.",
+ "upload-form-label-not-own-work-message-generic-foreign": "თუ ვერ ტვირთავთ ამ ფაილს {{SITENAME}}-ის წესების დაცვით, გთხოვთ დახურეთ ეს ფანჯარა და სცადეთ სხვა მეთოდი.",
+ "upload-form-label-not-own-work-local-generic-foreign": "შეგიძლიათ ასევე სცადოთ [[Special:Upload|ატვირთვის გვერდი {{SITENAME}}-ზე]], თუ ამ ფაილის ატვირთვა დაშვებულია მათი პოლიტიკის მიხედვით.",
"backend-fail-stream": "ფაილი $1 ტრანსლირება ვერ მოხერხდა.",
"backend-fail-backup": "ფაილი $1 სარეზერვო ასლის გაკეთება ვერ მოხერხდა.",
"backend-fail-notexists": "ფაილი $1 არ არსებობს.",
"whatlinkshere-prev": "{{PLURAL:$1|წინა|წინა $1}}",
"whatlinkshere-next": "{{PLURAL:$1|შემდეგი|შემდეგი $1}}",
"whatlinkshere-links": "← ბმულები",
- "whatlinkshere-hideredirs": "გადამისამართების $1",
- "whatlinkshere-hidetrans": "$1 á\83©á\83\90á\83 á\83\97á\83\95á\83\94á\83\91ი",
- "whatlinkshere-hidelinks": "ბმულების $1",
+ "whatlinkshere-hideredirs": "$1 გადამისამართება",
+ "whatlinkshere-hidetrans": "$1 á\83©á\83\90á\83\9cá\83\90á\83 á\83\97ი",
+ "whatlinkshere-hidelinks": "$1 ბმული",
"whatlinkshere-hideimages": "$1 სურათის ბმულები",
"whatlinkshere-filters": "ფილტრები",
"whatlinkshere-submit": "წინ",
"logentry-protect-protect-cascade": "$1-მ {{GENDER:$2|დაიცვა}} $3 $4 [კასკადური]",
"logentry-protect-modify": "$1-მ {{GENDER:$2|შეცვალა}} დაცვის დონე $3 $4-სთვის",
"logentry-protect-modify-cascade": "$1 {{GENDER:$2|შეცვალა}} დაცვის დონე $3 $4 [კასკადური]",
- "logentry-rights-rights": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\9bá\83\90 $1 {{GENDER:$2|á\83¨á\83\94á\83ªá\83\95á\83\90á\83\9aá\83\90}} á\83¯á\83\92á\83£á\83¤á\83\98á\83¡ á\83¬á\83\94á\83\95á\83 á\83\9dá\83\91á\83\90 $3-á\83\97á\83\95á\83\98ს $4-დან $5-ზე",
+ "logentry-rights-rights": "á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\9bá\83\90 $1 {{GENDER:$2|á\83¨á\83\94á\83£á\83ªá\83\95á\83\90á\83\9aá\83\90}} á\83¯á\83\92á\83£á\83¤á\83\98 $3-ს $4-დან $5-ზე",
"logentry-rights-rights-legacy": "მომხმარებელმა $1 {{GENDER:$2|შეცვალა}} ჯგუფის წევრობა $3-თვის",
"logentry-rights-autopromote": "მომხმარებელი $1 ავტომატურად იქნა {{GENDER:$2|გადაყვანილი}} $4–დან $5–ში",
"logentry-upload-upload": "მომხმარებელმა $1 {{GENDER:$2|ატვირთა}} $3",
"noname": "Siz kiritken paydalanıwshı atı qate.",
"loginsuccesstitle": "Kiriw tabıslı a'melge asırıldı",
"loginsuccess": "'''{{SITENAME}} saytına \"$1\" paydalanıwshı atı menen kirdin'iz.'''",
- "nosuchuser": "\"$1\" atlı paydalanıwshı joq.\nTuwrı jazılg'anlıg'ın tekserin' yamasa [[Special:UserLogin/signup|taza akkaunt jaratın']].",
+ "nosuchuser": "\"$1\" atlı paydalanıwshı joq.\nTuwrı jazılg'anlıg'ın tekserin' yamasa [[Special:CreateAccount|taza akkaunt jaratın']].",
"nosuchusershort": "\"$1\" atlı paydalanıwshı joq. Tuwrı jazılg'anlıg'ın tekserin'.",
"nouserspecified": "Siz paydalanıwshı atın ko'rsetpedin'iz.",
"wrongpassword": "Qate parol kiritlgen. Qaytadan kiritin'.",
"categories": "Kategoriyalar",
"categoriespagetext": "To'mendegi {{PLURAL:$1|kategoriya|kategoriyalar}} o'z ishine betler yamasa medialardı alg'an.\nBul jerde [[Special:UnusedCategories|paydalanılmag'an kategoriyalar]] ko'rsetilmegen.\nJa'nede [[Special:WantedCategories|kerekli kategoriyalardı]] qarap ko'rin'.",
"categoriesfrom": "Kategoriyalardı to'mendegilerden baslap ko'rset:",
- "special-categories-sort-count": "sanı boyınsha ta'rtiplew",
- "special-categories-sort-abc": "a'lipbe boyınsha ta'rtiplew",
"deletedcontributions": "Paydalanıwshının' o'shiriw u'lesi",
"linksearch": "Sırtqı siltewler",
"linksearch-pat": "İzlew shablonı:",
"noname": "Ur tefkiḍ ara isem n wemseqdac ṣaḥiḥ.",
"loginsuccesstitle": "Tkecmeḍ !",
"loginsuccess": "'''Tkecmeḍ ar {{SITENAME}} s yisem n wemseqdac \"$1\".'''",
- "nosuchuser": "Aseqdac « $1 » ulac-it d-agi.\nSsenqed tira n yisem-nni, naɣ [[Special:UserLogin/signup|snulfu-d amiḍan amaynut]].",
+ "nosuchuser": "Aseqdac « $1 » ulac-it d-agi.\nSsenqed tira n yisem-nni, naɣ [[Special:CreateAccount|snulfu-d amiḍan amaynut]].",
"nosuchusershort": "Ulac isem n wemseqdac s yisem \"$1\". Ssenqed tira n yisem-nni.",
"nouserspecified": "Yessefk ad tefkeḍ isem n wemseqdac.",
"login-userblocked": "Aseqdac agi i sewḥel. Tuqqna t-ugwi.",
"accmailtext": "Awal n uɛaddi id yuran s ugacur i [[User talk:$1|$1]] yetweceggaɛ i $2.\nYezmer ad yetbeddel ɣef usebtar [[Special:ChangePassword|Abeddel n awal uɛddi]] sakin tuqqna.",
"newarticle": "(Amaynut)",
"newarticletext": "Tḍefreḍ azday ɣer usebter mazal ur yettwaxleq ara.\nAkken ad txelqeḍ asebter-nni, aru deg tenkult i tella deg ukessar\n(ẓer [$1 asebter n tallalt] akken ad tessneḍ kter).\nMa tɣelṭeḍ, wekki kan ɣef tqeffalt \"Back/Précédent\" n browser/explorateur inek.",
- "anontalkpagetext": "---- ''Wagi d asebter n umyennan n useqdac adrig, mazal ur d-yesnufa ara amiḍan. I taɣẓint agi, ilaq an seqdec tansa IP ines iwakken at-id n sulu. Yiwet tansa IP tezmer at tettuseqdac sɣur aṭṭas n iseqdacen. Lukan ula d kečč aqla-k amseqdac adrig dɣa ur tebɣiḍ ara ad tettwabcreḍ izen am wigini, ihi [[Special:UserLogin/signup|snulfud amiḍan]] naɣ [[Special:UserLogin|qqened]] iwakken sya d asawen ur t-illint ara uguren n usulu.''",
+ "anontalkpagetext": "---- ''Wagi d asebter n umyennan n useqdac adrig, mazal ur d-yesnufa ara amiḍan. I taɣẓint agi, ilaq an seqdec tansa IP ines iwakken at-id n sulu. Yiwet tansa IP tezmer at tettuseqdac sɣur aṭṭas n iseqdacen. Lukan ula d kečč aqla-k amseqdac adrig dɣa ur tebɣiḍ ara ad tettwabcreḍ izen am wigini, ihi [[Special:CreateAccount|snulfud amiḍan]] naɣ [[Special:UserLogin|qqened]] iwakken sya d asawen ur t-illint ara uguren n usulu.''",
"noarticletext": "Ulac aḍris deg usebter-agi, tzemreḍ ad [[Special:Search/{{PAGENAME}}|tnadiḍ ɣef wezwel n usebter-agi]] deg isebtar wiyaḍ neɣ [{{fullurl:{{FULLPAGENAME}}|action=edit}} tettbeddileḍ asebter-agi].",
"noarticletext-nopermission": "Imira ulac aḍris deg usebter agi.\nTzemreḍ [[Special:Search/{{PAGENAME}}|ad nadiḍ ɣef azwel agi]] deg isebtaren nniḍen,\nnaɣ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|asebter={{FULLPAGENAMEE}}}} ad nadiḍ deg iɣmisen iqqenen]</span>.",
"missing-revision": "Tacaggart #$1 n usebter s isem « {{FULLPAGENAME}} » ulac-itt.\n\nAcku azday n umezruy, ɣef wayen tsennedeḍ, d-aqbur. Asebter yemḥa.\nTzemreḍ ad affeḍ tilɣa deg [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} uɣmis n isebtar yemḥan].",
"noname": "ЦӀыхухэтыцӀэ хъунур иптхакъым.",
"loginsuccesstitle": "ЗыкъегъэцӀыхуныр фӀыуэ зэфӀэкӀа.",
"loginsuccess": "'''Иджы цӀэ \"$1\" зепхьу улэжьэфыну.'''",
- "nosuchuser": "\"$1\" цӀэ зезыхьэ цӀыхухэт щыӀэкъым.\nЦӀыхухэтыцӀэхэр гурышхъу щытхэ хьэрыф регистырымкӀэ.\nЦӀэр тэрэзу птхамэ еплъ иэ [[Special:UserLogin/signup|аккаунт щӀэуэ щӀы]].",
+ "nosuchuser": "\"$1\" цӀэ зезыхьэ цӀыхухэт щыӀэкъым.\nЦӀыхухэтыцӀэхэр гурышхъу щытхэ хьэрыф регистырымкӀэ.\nЦӀэр тэрэзу птхамэ еплъ иэ [[Special:CreateAccount|аккаунт щӀэуэ щӀы]].",
"nosuchusershort": "ЦӀыхухэт \"$1\" щыӀэкъым.\nЦӀэр тэрэзу итхамэ еплъ.",
"nouserspecified": "ЦӀыхухэтыцӀэр иптхэн хуэй.",
"login-userblocked": "Мы цӀыхухэтыр теубыдауэ щытщ. Ихьэныр хуадэкъым.",
"accmailtext": "ЦӀыхухэт [[User talk:$1|$1-м]] щхьэкӀэ дэмыгъэ зэхэдзыгъэншу парол зэхэгъувар $2 адресым егъэхьа.\nСистемэм регистрациэ быщӀа яуж ''[[Special:ChangePassword|паролыр зэпхъуэкӀыфыну]].''",
"newarticle": "(ЩIэуэ)",
"newarticletext": "НапэкӀуэцӀ иджыри щымыӀэм утехуащ техьэпӀэмкэ.\nАр быщӀын щхьэкӀэ, и щӀагъым щӀэт игъувапӀэм тхылъ итхэ (еплъ [$1 щӀэупщӀэгъуэхэм я напэкӀуэцӀ]).\nГъуэщэгъуэкӀэ мыбым утехуамэ, уи браузерым гъэзэжыгъуэ иӀэм текъузи зэфэкащ.",
- "anontalkpagetext": "----''Мы напэкӀуэцӀ тепсэлъыхьыгъуэр аноним цӀыхухэтым ей, аккаунт зымыщӀам иэ къэзмыгъэсэбэпым.\nАбым щхьэкӀэ IP-адресымкӀэ идентификациэ иратыр.\nАноним цӀыхухэту ущытмэ, тхыгъэ къыпхуэкӀуауэ уигугъэмэ, [[Special:UserLogin/signup|аккаунт щӀы]] иэ [[Special:UserLogin|системэм зыкъегъэцӀыху]], япэкӀэ хэукъуэгъуэ пэмыкӀ цӀыхухэт анэнимхэм ям ухэмыхуэн щхьэкӀэ.''",
+ "anontalkpagetext": "----''Мы напэкӀуэцӀ тепсэлъыхьыгъуэр аноним цӀыхухэтым ей, аккаунт зымыщӀам иэ къэзмыгъэсэбэпым.\nАбым щхьэкӀэ IP-адресымкӀэ идентификациэ иратыр.\nАноним цӀыхухэту ущытмэ, тхыгъэ къыпхуэкӀуауэ уигугъэмэ, [[Special:CreateAccount|аккаунт щӀы]] иэ [[Special:UserLogin|системэм зыкъегъэцӀыху]], япэкӀэ хэукъуэгъуэ пэмыкӀ цӀыхухэт анэнимхэм ям ухэмыхуэн щхьэкӀэ.''",
"noarticletext": "Иджыпсту мы напэкӀуэцӀыр нэщӀ.\nУзхуэныкъуэм [[Special:Search/{{PAGENAME}}|игугъ бгъуэтыфыну]] нэгъуэщӀ напэкӀуэцӀхэм, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} тхылъхэм абым теухуа тхыгъэхэм], иэ '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} апхуэдэцӀэ зиӀэ напэкӀуцӀ быщӀыфынущ]'''</span>.",
"noarticletext-nopermission": "Джыпсту мы напэкӀуэцӀыр нэщӀу щытщ.\nУзхуэныкъуэм [[Special:Search/{{PAGENAME}}|и гугъ бгъуэтыфыну]] нэгъуэщӀ напэкӀуэцӀхэм, \nиэ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} абым теухуа тхъыгъэхэр].</span>",
"userpage-userdoesnotexist": "Аккаунт «<nowiki>$1</nowiki>» щыӀэкъым. У арэзыуэ ущыт мы напэкӀуэцӀыр быщӀыным иэ зэпхъуэкӀыным.",
"noname": "تو تان صحیح اسم صارفو داخل نو آرو",
"loginsuccesstitle": "داخلہ کامیاب",
"loginsuccess": "'''ھانیسے تو {{SITENAME}} بنام \"$1\" داخل بیتی آسوس'''",
- "nosuchuser": "\"$1\" نامو سورا کیہ صارف موجود نیکی.\nبرائے مہربانی! ہجان درست اندراجان تصدیقو کورے.\nاگر تو کہ مناسب جوشیتاو تھے [[Special:UserLogin/signup|نوغ کھاتہ دی ساوزیکو بوس]].",
+ "nosuchuser": "\"$1\" نامو سورا کیہ صارف موجود نیکی.\nبرائے مہربانی! ہجان درست اندراجان تصدیقو کورے.\nاگر تو کہ مناسب جوشیتاو تھے [[Special:CreateAccount|نوغ کھاتہ دی ساوزیکو بوس]].",
"nouserspecified": "تہ ای اسمِ صارفو مخصوص کوریلک",
"login-userblocked": "ھیہ صارفو سورا پاوبندی شیر. داخلِ نوشتہ بیکو اجازت نیکی",
"wrongpassword": "تو غلط کلمۂ شناخت درج کوری آسوس دوبارہ کو شش کورے",
"noname": "Ebe namê do vêrdoği ra cınêkota.",
"loginsuccesstitle": "Cıkotene biye ra",
"loginsuccess": "'''Sıta {{SITENAME}} de ebe namê karberi \"$1\" kota cı.'''",
- "nosuchuser": "Ebe namê \"$1\"i jü karber çino.\nNustena namunê karberu de herfa pil u qıze rê diqet kerê.\nNustena ho qonrol kerê, ya ki [[Special:UserLogin/signup|jü hesabo newe rakerê]].",
+ "nosuchuser": "Ebe namê \"$1\"i jü karber çino.\nNustena namunê karberu de herfa pil u qıze rê diqet kerê.\nNustena ho qonrol kerê, ya ki [[Special:CreateAccount|jü hesabo newe rakerê]].",
"nosuchusershort": "Karberê do ebe namê \"$1\" çino.\nNustena cı qontrol ke.",
"nouserspecified": "Gunê namê jü karberi bıdekernê.",
"login-userblocked": "No karber engel biyo. Cıkotene rê mısade cı nêdino.",
"Macofe",
"Batyrbek.kz",
"Matma Rex",
- "Nemo bis"
+ "Nemo bis",
+ "Mormegil"
]
},
"tog-underline": "Сілтеменің астын сызу:",
"tog-watchdefault": "Мен өңдеген беттерді және файлдарды бақылау тізіміне қосу",
"tog-watchmoves": "Мен жылжытқан беттерді және файлдарды бақылау тізіміне қосу",
"tog-watchdeletion": "Мен жойған беттерді және файлдарды бақылау тізіміне қосу",
+ "tog-watchuploads": "Бақылау тізіміме мен жүктеген файлдарды қосу",
"tog-watchrollback": "Мен шегіндіруін орындаған беттерді бақылау тізіміме қосу",
"tog-minordefault": "Әдепкі бойынша барлық өңдемелерді шағын деп белгілеу",
"tog-previewontop": "Қарап шығу аумағын өңдеу терезесінің жоғарғы жағында көрсету",
"noname": "Сізде жарамды қатысушы аты анықталмаған.",
"loginsuccesstitle": "Кірдіңіз.",
"loginsuccess": "<strong>Сіз енді {{SITENAME}} жобасына «$1» ретінде кірдіңіз.</strong>",
- "nosuchuser": "Мұнда «$1» деп аталған қатысушы тіркелмеген.\nҚатысушы аттары кіші әріптерден тұру керек.\nЕмлеңізді тексеріңіз немесе [[Special:UserLogin/signup|жаңа тіркелгі жасаңыз]].",
+ "nosuchuser": "Мұнда «$1» деп аталған қатысушы тіркелмеген.\nҚатысушы аттары кіші әріптерден тұру керек.\nЕмлеңізді тексеріңіз немесе [[Special:CreateAccount|жаңа тіркелгі жасаңыз]].",
"nosuchusershort": "Мұнда «$1» деп аталған қатысушы тіркелмеген.\nЕмлеңізді тексеріңіз.",
"nouserspecified": "Қатысушы атын көрсетуіңіз керек.",
"login-userblocked": "Бұл қатысушы бұғатталған. Жүйеге кiру рұқсат етiлмеген.",
"accmailtext": "$2 дегенге [[User talk:$1|$1]] үшін құпия сөзі жөнелтілді. Оны <em>[[Special:ChangePassword|құпия сөзді өзгерту]]</em> бетінде жүйеге кірген кезде өзгеруге болады.",
"newarticle": "(Жаңа)",
"newarticletext": "Сілтеме бойынша әлі басталмаған бетке келіпсіз.\nБетті бастау үшін төменгі терезеде мәтінді теріңіз (көбірек ақпарат үшін [$1 анықтама бетін] қараңыз).\nЕгер жаңылғаннан осында келген болсаңыз браузеріңіздің <strong>артқа</strong> деген батырмасын басыңыз.",
- "anontalkpagetext": "----\n<em>Бұл тіркелгісіз анонимді (немесе тіркелгісін қолданбаған) қатысушының талқылау беті.</em> \nСондықтан біз оны сандық IP мекенжайымен қолдануға тиістіміз.\nОсындай IP мекенжайды бірнеше пайдаланушы ортақтаса алады.\nЕгер сіз анонимді қатысушы болсаңыз және сізге қатыссыз хабарлама жіберілгенін сезсеңіз басқа анонимді қатысушылармен алдағы уақыттарда шатастырмау үшін [[Special:UserLogin/signup|тіркеліңіз]] не [[Special:UserLogin|кіріңіз]].",
+ "anontalkpagetext": "----\n<em>Бұл тіркелгісіз анонимді (немесе тіркелгісін қолданбаған) қатысушының талқылау беті.</em> \nСондықтан біз оны сандық IP мекенжайымен қолдануға тиістіміз.\nОсындай IP мекенжайды бірнеше пайдаланушы ортақтаса алады.\nЕгер сіз анонимді қатысушы болсаңыз және сізге қатыссыз хабарлама жіберілгенін сезсеңіз басқа анонимді қатысушылармен алдағы уақыттарда шатастырмау үшін [[Special:CreateAccount|тіркеліңіз]] не [[Special:UserLogin|кіріңіз]].",
"noarticletext": "Қазіргі уақытта бұл бетте еш мәтін жоқ.\n* Басқа беттерден [[Special:Search/{{PAGENAME}}|бұл бет атауын іздеу]],\n* <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Журналдардан бұл бетке қатысты сәйкес жазбаларды табу]</span>,\n* <span class=\"plainlinks\">'''[{{fullurl:{{FULLPAGENAME}}|action=edit}} Бұл бетті жаңадан бастау]'''</span>.",
"noarticletext-nopermission": "Қазіргі уақытта бұл бетте мәтін жоқ.\nСіз бұл бет атауын басқа беттерден [[Special:Search/{{PAGENAME}}|іздей аласыз]], немесе <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} қатысты журналдардан іздей аласыз]</span>. Ал бұл бетті жаңадан бастауға сізде рұқсат жоқ.",
"missing-revision": "#$1 нұсқалы «{{FULLPAGENAME}}» деп аталатын бет жоқ",
"recentchangeslinked-page": "Бет атауы:",
"recentchangeslinked-to": "Керісінше, келтірілген бетке сілтейтін беттердегі өзгерістерді көрсет",
"recentchanges-page-added-to-category": "[[:$1]] бетіне санат қосты",
- "recentchanges-page-added-to-category-bundled": "[[:$1]] және [[Special:WhatLinksHere/$1|{{PLURAL:$2|бір бет|$2 бет}}]] санатқа қосылды",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] санатқа қосылды, [[Special:WhatLinksHere/$1|{{PLURAL:$1|бұл бет басқа беттердің ішіне кірістірілген}}]]",
"recentchanges-page-removed-from-category": "[[:$1]] санаттан алынды",
"recentchanges-page-removed-from-category-bundled": "[[:$1]] және [[Special:WhatLinksHere/$1|{{PLURAL:$2|бір бет|$2 бет}}]] санаттан алынды",
"autochange-username": "МедиаУики өздікті өзгерісі",
"upload-form-label-own-work": "Бұл менің өз туындым",
"upload-form-label-infoform-categories": "Санаттар",
"upload-form-label-infoform-date": "Ай-күні",
- "upload-form-label-own-work-message-shared": "Мен осы файлдың авторы екенінімді растаймын және бұл файлды Wikimedia Commons ортаққорына [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] лицензиясы аясында қайтымсыз жариялауға келісемін, сонымен бірге [https://wikimediafoundation.org/wiki/Terms_of_Use Қолдану шарттарына] да келісемін.",
- "upload-form-label-not-own-work-message-shared": "Егер сіз осы файлдың авторы өзіңіз болмасаңыз немесе оны сіз басқа лицензия аясында жариялағыңыз келсе [https://commons.wikimedia.org/wiki/Special:UploadWizard Ортаққор Жүктеу шеберін] қолданыңыз.",
- "upload-form-label-not-own-work-local-shared": "Егер сайт бұл файлды жүктеуге өзінің ережелері аясында рұқсат беретін болса, сіз сондай-ақ [[Special:Upload|{{SITENAME}} жобасындағы жүктеу бетін]] қолданып көргіңіз келетін шығар.",
"backend-fail-stream": "«$1» файлы ақпады.",
"backend-fail-backup": "«$1» файлының сақтық есесі жасалмады.",
"backend-fail-notexists": "$1 файлы бар емес.",
"fewestrevisions": "Ең аз түзетілген беттер",
"nbytes": "$1 {{PLURAL:$1|байт|байт}}",
"ncategories": "$1 {{PLURAL:$1|Санат|Санаттар}}",
- "ninterwikis": "$1 {{PLURAL:$1|интеруики|интеруикилер}}",
+ "ninterwikis": "$1 {{PLURAL:$1|интеруики|интеруики}}",
"nlinks": "$1 сілтеме",
"nmembers": "$1 {{PLURAL:$1|мүше|мүше}}",
"nmemberschanged": "$1 → $2 {{PLURAL:$2|мүше|мүше}}",
"delete-toobig": "Бұл бетте үлкен түзету тарихы бар, $1 {{PLURAL:$1|түзетуден|түзетуден}} астам.\nБұндай беттердің жоюы {{SITENAME}} торабын әлдеқалай үзіп тастауына бөгет салу үшін тиымдалған.",
"delete-warning-toobig": "Бұл бетте үлкен өңдеу тарихы бар, $1 {{PLURAL:$1|түзетуден|түзетуден}} астам.\nБұның жоюы {{SITENAME}} торабындағы дерекқор әрекеттерді үзіп тастауын мүмкін;\nбұны абайлап өткізіңіз.",
"deleteprotected": "Сіз бұл бетті жоя алмайсыз, себебі ол қорғалған.",
- "deleting-backlinks-warning": "</strong>Ескерту:</strong> Сіз жоймақшы болған бетке [[Special:WhatLinksHere/{{FULLPAGENAME}}|басқа беттерден]] сілтенген немесе [[Special:WhatLinksHere/{{FULLPAGENAME}}|басқа беттерге]] кірістірілген.",
+ "deleting-backlinks-warning": "<strong>Ескерту:</strong> Сіз жоймақшы болған бетке [[Special:WhatLinksHere/{{FULLPAGENAME}}|басқа беттерден]] сілтенген немесе [[Special:WhatLinksHere/{{FULLPAGENAME}}|басқа беттерге]] кірістірілген.",
"rollback": "Өңдемелерді шегіндіру",
"rollbacklink": "шегіндіру",
"rollbacklinkcount": "$1 {{PLURAL:$1|өңдемені|өңдемені}} шегіндіру",
"noname": "អ្នកមិនបានផ្ដល់អត្តនាមត្រឹមត្រូវទេ។",
"loginsuccesstitle": "កត់ឈ្មោះចូលបានសម្រេច",
"loginsuccess": "'''ពេលនេះអ្នកបានកត់ឈ្មោះចូល{{SITENAME}}ដោយប្រើឈ្មោះ \"$1\"ហើយ។'''",
- "nosuchuser": "មិនមានអ្នកប្រើដែលមានឈ្មោះ \"$1\" ទេ។\n\nសូមពិនិត្យក្រែងលោមានកំហុសអក្ខរាវិរុទ្ធឬ [[Special:UserLogin/signup|បង្កើតគណនីថ្មី]]។",
+ "nosuchuser": "មិនមានអ្នកប្រើដែលមានឈ្មោះ \"$1\" ទេ។\n\nសូមពិនិត្យក្រែងលោមានកំហុសអក្ខរាវិរុទ្ធឬ [[Special:CreateAccount|បង្កើតគណនីថ្មី]]។",
"nosuchusershort": "គ្មានអ្នកប្រើដែលមានឈ្មោះ $1\" ទេ។\n\nសូមពិនិត្យអក្ខរាវិរុទ្ធរបស់អ្នក ។",
"nouserspecified": "អ្នកត្រូវតែផ្ដល់អត្តនាម។",
"login-userblocked": "អ្នកប្រើប្រាស់នេះស្ថិតក្រោមការហាមឃាត់។ មិនអនុញ្ញាតអោយកត់ឈ្មោះចូលទេ។",
"accmailtext": "ពាក្យសម្ងាត់ដែលបានបង្កើតដោយចៃដន្យសម្រាប់ [[User talk:$1|$1]] ត្រូវបានផ្ញើទៅ $2 ហើយ។ អ្នកអាចប្ដូរវាបាននៅទំព័រ ''[[Special:ChangePassword|ប្ដូរពាក្យសម្ងាត់]]'' បន្ទាប់ពីកត់ឈ្មោះចូលហើយ។",
"newarticle": "(ថ្មី)",
"newarticletext": "អ្នកបានតាមតំណភ្ជាប់ទៅទំព័រដែលមិនទាន់មាននៅឡើយ។\nដើម្បីបង្កើតទំព័រនេះ សូមចាប់ផ្ដើមវាយក្នុងប្រអប់ខាងក្រោម (សូមមើល [$1 ទំព័រជំនួយ] សម្រាប់ព័ត៌មានបន្ថែម)។\nបើអ្នកមកទីនេះដោយអចេតនា សូមចុចប៊ូតុង '''ត្រឡប់ក្រោយ''' របស់ឧបករណ៍រាវរករបស់អ្នក។",
- "anontalkpagetext": "----''ទំព័រពិភាក្សានេះគឺសម្រាប់តែអ្នកប្រើប្រាស់អនាមិកដែលមិនទាន់បានបង្កើតគណនីតែប៉ុណ្ណោះ។ ដូច្នេះអាសយដ្ឋានលេខIPរបស់កុំព្យូទ័ររបស់លោកអ្នកនឹងត្រូវបានបង្ហាញ ដើមី្បសម្គាល់លោកអ្នក។\n\nអាសយដ្ឋានIPទាំងនោះអាចនឹងត្រូវប្រើដោយមនុស្សច្រើននាក់។\n\nប្រសិនបើអ្នកជាអ្នកប្រើប្រាស់អនាមិកហើយប្រសិនបើអ្នកឃើញមានការបញ្ចេញយោបល់មកអ្នកពីអ្វីដែលមិនទាក់ទងទៅនឹងអ្វីដែលអ្នកបានធ្វើ សូម[[Special:UserLogin/signup|បង្កើតគណនី]] ឬ [[Special:UserLogin|កត់ឈ្មោះចូល]] ដើម្បីចៀសវាងការភ័ន្តច្រឡំណាមួយជាយថាហេតុជាមួយនិងអ្នកប្រើប្រាស់អនាមិកដទៃទៀត។''",
+ "anontalkpagetext": "----''ទំព័រពិភាក្សានេះគឺសម្រាប់តែអ្នកប្រើប្រាស់អនាមិកដែលមិនទាន់បានបង្កើតគណនីតែប៉ុណ្ណោះ។ ដូច្នេះអាសយដ្ឋានលេខIPរបស់កុំព្យូទ័ររបស់លោកអ្នកនឹងត្រូវបានបង្ហាញ ដើមី្បសម្គាល់លោកអ្នក។\n\nអាសយដ្ឋានIPទាំងនោះអាចនឹងត្រូវប្រើដោយមនុស្សច្រើននាក់។\n\nប្រសិនបើអ្នកជាអ្នកប្រើប្រាស់អនាមិកហើយប្រសិនបើអ្នកឃើញមានការបញ្ចេញយោបល់មកអ្នកពីអ្វីដែលមិនទាក់ទងទៅនឹងអ្វីដែលអ្នកបានធ្វើ សូម[[Special:CreateAccount|បង្កើតគណនី]] ឬ [[Special:UserLogin|កត់ឈ្មោះចូល]] ដើម្បីចៀសវាងការភ័ន្តច្រឡំណាមួយជាយថាហេតុជាមួយនិងអ្នកប្រើប្រាស់អនាមិកដទៃទៀត។''",
"noarticletext": "បច្ចុប្បន្នគ្មានអត្ថបទក្នុងទំព័រនេះទេ។\n\nអ្នកអាច [[Special:Search/{{PAGENAME}}|ស្វែងរកចំណងជើងនៃទំព័រនេះ]]ក្នុងទំព័រដទៃទៀត ឬ [{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ស្វែងរកកំណត់ហេតុដែលពាក់ព័ន្ធ] ឬ [{{fullurl:{{FULLPAGENAME}}|action=edit}} កែប្រែទំព័រនេះ]។",
"noarticletext-nopermission": "បច្ចុប្បន្ន គ្មានអត្ថបទណាមួយក្នុងទំព័រនេះទេ។\n\nអ្នកអាច [[Special:Search/{{PAGENAME}}|ស្វែងរកចំណងជើងនៃទំព័រនេះ]] ក្នុងទំព័រផ្សេងៗ ឬ<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ស្វែងរកកំណត់ហេតុដែលពាក់ព័ន្ធ]</span>។ ប៉ុន្តែអ្នកគ្មានសិទ្ធិក្នុងការបង្កើតទំព័រនេះទេ។",
"userpage-userdoesnotexist": "គណនីអ្នកប្រើឈ្មោះ\"<nowiki>$1</nowiki>\" មិនទាន់បានចុះបញ្ជី។\n\nចូរគិតម្ដងទៀតថាអ្នកចង់ បង្កើត / កែប្រែ ទំព័រនេះឬទេ។",
"noname": "ನೀವು ಸರಿಯಾದ ಬಳಕೆದಾರ ಹೆಸರನ್ನು ಸೂಚಿಸಿಲ್ಲ.",
"loginsuccesstitle": "ಲಾಗಿನ್ ಯಶಸ್ವಿ",
"loginsuccess": "ನೀವು ಈಗ \"$1\" ಆಗಿ ವಿಕಿಪೀಡಿಯಕ್ಕೆ ಲಾಗಿನ್ ಆಗಿದ್ದೀರಿ.",
- "nosuchuser": "\"$1\" ಹೆಸರಿನ ಯಾವ ಸದಸ್ಯರೂ ಇಲ್ಲ.\nಸದಸ್ಯನಾಮದಲ್ಲಿ ಲಘು ಮತ್ತು ದೀರ್ಘ ಅಕ್ಷರಗಳಲ್ಲಿ ವ್ಯತ್ಯಾಸವಿದೆ.\nಕಾಗುಣಿತವನ್ನು ಪರೀಕ್ಷಿಸಿ, ಅಥವಾ [[Special:UserLogin/signup|ಹೊಸ ಸದಸ್ಯತ್ವ ಖಾತೆಯನ್ನು ಸೃಷ್ಟಿಸಿ]].",
+ "nosuchuser": "\"$1\" ಹೆಸರಿನ ಯಾವ ಸದಸ್ಯರೂ ಇಲ್ಲ.\nಸದಸ್ಯನಾಮದಲ್ಲಿ ಲಘು ಮತ್ತು ದೀರ್ಘ ಅಕ್ಷರಗಳಲ್ಲಿ ವ್ಯತ್ಯಾಸವಿದೆ.\nಕಾಗುಣಿತವನ್ನು ಪರೀಕ್ಷಿಸಿ, ಅಥವಾ [[Special:CreateAccount|ಹೊಸ ಸದಸ್ಯತ್ವ ಖಾತೆಯನ್ನು ಸೃಷ್ಟಿಸಿ]].",
"nosuchusershort": "\"$1\" ಹೆಸರಿನ ಸದಸ್ಯರು ಯಾರೂ ಇಲ್ಲ.\nಹೆಸರಲ್ಲಿ ಕಾಗುಣಿತ ತಪ್ಪಿದೆಯೆ ಎಂದು ಪರೀಕ್ಷಿಸಿ.",
"nouserspecified": "ನೀವು ಒಂದು ಸದಸ್ಯತ್ವದ ಹೆಸರನ್ನು ಸೂಚಿಸಬೇಕು.",
"login-userblocked": "ಈ ಬಳಕೆದಾರರನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ. ಲಾಗಿನ್ ಆಗಲು ಸಾದ್ಯವಿಲ್ಲ.",
"accmailtext": "[[User talk:$1|$1]] ಅವರ ಹೊಸ ಪ್ರವೇಶಪದ $2 ಗೆ ಕಳುಹಿಸಲಾಗಿದೆ.\n\nಈ ಖಾತೆಯ ಪ್ರವೇಶಪದವನ್ನು ಲಾಗಿನ್ ಆದ ನಂತರ ''[[Special:ChangePassword|ಪ್ರವೇಶಪದ ಬದಲಾವಣೆ]]'' ಪುಟದಲ್ಲಿ ಬದಲಾಯಿಸಬಹುದು.",
"newarticle": "(ಹೊಸತು)",
"newarticletext": "ಇನ್ನೂ ಅಸ್ಥಿತ್ವದಲ್ಲಿ ಇರದ ಪುಟದ ಲಿಂಕ್ ಅನ್ನು ನೀವು ಒತ್ತಿರುವಿರಿ.\nಈ ಪುಟವನ್ನು ಸೃಷ್ಟಿಸಲು ಕೆಳಗಿನ ಚೌಕದಲ್ಲಿ ಬರೆಯಲು ಆರಂಭಿಸಿರಿ.\n(ಹೆಚ್ಚು ಮಾಹಿತಿಗೆ [$1 ಸಹಾಯ ಪುಟ] ನೋಡಿ).\nಈ ಪುಟಕ್ಕೆ ನೀವು ತಪ್ಪಾಗಿ ಬಂದಿದ್ದಲ್ಲಿ ನಿಮ್ಮ ಬ್ರೌಸರ್ನ '''back''' ಬಟನ್ ಅನ್ನು ಒತ್ತಿ.",
- "anontalkpagetext": "----''ಇದು ಖಾತೆಯೊಂದನ್ನು ಹೊಂದಿರದ ಅನಾಮಧೇಯ ಬಳಕೆದಾರರೊಬ್ಬರ ಚರ್ಚೆ ಪುಟ.\nಖಾತೆಯಿಲ್ಲದಿರುವುದರಿಂದ ಅವರನ್ನು ಗುರುತಿಸಲು ಅವರ IP ವಿಳಾಸವನ್ನು ಉಪಯೋಗಿಸುತ್ತಿದ್ದೇವೆ.\nಈ ರೀತಿಯ IP ವಿಳಾಸವು ಅನೇಕ ಬಳಕೆದಾರರಿಂದ ಉಪಯೋಗದಲ್ಲಿರಬಹುದು.\nನೀವು ಅನಾಮಧೇಯ ಬಳಕೆದಾರರಾಗಿದ್ದಲ್ಲಿ, ಹಾಗು ನಿಮಗೆ ಸಂಬಂಧವಿಲ್ಲದಂತ ಸಂದೇಶಗಳು ಬರುತ್ತಿವೆ ಎಂದು ಅನಿಸಿದರೆ, ಮುಂದೆ ಬೇರೆ ಅನಾಮಧೇಯ ಬಳಕೆದಾರರೊಂದಿಗೆ ತಪ್ಪಾಗಿ ಗುರುತಿಸಬಾರದೆಂದಿದ್ದರೆ ದಯವಿಟ್ಟು [[Special:UserLogin/signup|ಸದಸ್ಯರಾಗಿ]] ಅಥವ [[Special:UserLogin|ಲಾಗ್ ಇನ್ ಆಗಿ]].''",
+ "anontalkpagetext": "----''ಇದು ಖಾತೆಯೊಂದನ್ನು ಹೊಂದಿರದ ಅನಾಮಧೇಯ ಬಳಕೆದಾರರೊಬ್ಬರ ಚರ್ಚೆ ಪುಟ.\nಖಾತೆಯಿಲ್ಲದಿರುವುದರಿಂದ ಅವರನ್ನು ಗುರುತಿಸಲು ಅವರ IP ವಿಳಾಸವನ್ನು ಉಪಯೋಗಿಸುತ್ತಿದ್ದೇವೆ.\nಈ ರೀತಿಯ IP ವಿಳಾಸವು ಅನೇಕ ಬಳಕೆದಾರರಿಂದ ಉಪಯೋಗದಲ್ಲಿರಬಹುದು.\nನೀವು ಅನಾಮಧೇಯ ಬಳಕೆದಾರರಾಗಿದ್ದಲ್ಲಿ, ಹಾಗು ನಿಮಗೆ ಸಂಬಂಧವಿಲ್ಲದಂತ ಸಂದೇಶಗಳು ಬರುತ್ತಿವೆ ಎಂದು ಅನಿಸಿದರೆ, ಮುಂದೆ ಬೇರೆ ಅನಾಮಧೇಯ ಬಳಕೆದಾರರೊಂದಿಗೆ ತಪ್ಪಾಗಿ ಗುರುತಿಸಬಾರದೆಂದಿದ್ದರೆ ದಯವಿಟ್ಟು [[Special:CreateAccount|ಸದಸ್ಯರಾಗಿ]] ಅಥವ [[Special:UserLogin|ಲಾಗ್ ಇನ್ ಆಗಿ]].''",
"noarticletext": "ಈ ಪುಟದಲ್ಲಿ ಸದ್ಯಕ್ಕೆ ಏನೂ ಇಲ್ಲ.\nನೀವು ಇತರ ಪುಟಗಳಲ್ಲಿ [[Special:Search/{{PAGENAME}}|ಈ ಹೆಸರನ್ನು ಹುಡುಕಬಹುದು]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ಸಂಬಂಧಿತ ದಾಖಲೆಗಳನ್ನು ಹುಡುಕಬಹುದು],\nಅಥವ [{{fullurl:{{FULLPAGENAME}}|action=edit}} ಈ ಪುಟವನ್ನು ಸಂಪಾದಿಸಬಹುದು]</span>.",
"noarticletext-nopermission": "ಈ ಪುಟದಲ್ಲಿ ಸದ್ಯಕ್ಕೆ ಯಾವ ಪಠ್ಯವೂ ಇಲ್ಲ.\nನೀವು ಇತರ ಪುಟಗಳಲ್ಲಿ [[ವಿಶೇಷ:Search/{{PAGENAME}}|ಈ ಶೀರ್ಷಿಕೆಗಾಗಿ ಹುಡುಕಬಹುದು]],\nಅಥವಾ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ಸಂಬಂಧಿಸಿದ ದಾಖಲಾತಿ ಹುಡುಕಬಹುದು]</span>, ಆದರೆ ನಿಮಗೆ ಈ ಪುಟವನ್ನು ಸಂಪಾದಿಸಲು ಅನುಮತಿಯಿಲ್ಲ.",
"userpage-userdoesnotexist": "ಬಳಕೆದಾರ ಖಾತೆ \"<nowiki>$1</nowiki>\" ದಾಖಲಾಗಿಲ್ಲ. ನೀವು ಇದೇ ಪುಟವನ್ನು ಸೃಷ್ಟಿ/ಸಂಪಾದನೆ ಮಾಡಬೇಕೆಂದಿರುವಿರಿ ಎಂದು ಖಾತ್ರಿ ಮಾಡಿಕೊಳ್ಳಿ.",
"Mooozi",
"Ellif",
"HDNua",
- "Ykhwong"
+ "Ykhwong",
+ "Matma Rex"
]
},
"tog-underline": "링크에 밑줄:",
"tog-watchlistreloadautomatically": "필터가 수정될 때마다 주시문서 목록 자동으로 새로 고치기 (자바스크립트 필요)",
"tog-watchlisthideanons": "주시문서 목록에서 익명 사용자의 편집을 숨기기",
"tog-watchlisthidepatrolled": "주시문서 목록에서 점검한 편집을 숨기기",
- "tog-watchlisthidecategorization": "페이지 종류 숨기기",
+ "tog-watchlisthidecategorization": "페이지 분류 숨기기",
"tog-ccmeonemails": "이메일을 보낼 때 내 이메일로 복사본을 보내기",
"tog-diffonly": "편집 차이를 비교할 때 문서 내용을 보지 않기",
"tog-showhiddencats": "숨은 분류 보이기",
"youhavenewmessages": "다른 사용자로부터의 $1가 {{PLURAL:$3|있습니다}}. ($2)",
"youhavenewmessagesfromusers": "{{PLURAL:$3|다른 사용자로|사용자 $3명으로}}부터의 $1가 {{PLURAL:$4|있습니다}}. ($2)",
"youhavenewmessagesmanyusers": "여러 사용자로부터의 $1가 있습니다. ($2)",
- "newmessageslinkplural": "{{PLURAL:$1|새 메시지}}",
- "newmessagesdifflinkplural": "마지막으로 {{PLURAL:$1|바뀐 내용}}",
+ "newmessageslinkplural": "{{PLURAL:$1|새 메시지|999=새 메시지}}",
+ "newmessagesdifflinkplural": "마지막으로 {{PLURAL:$1|바뀐 내용|999=바뀐 내용}}",
"youhavenewmessagesmulti": "다른 사용자가 $1에 남긴 새 메시지가 있습니다",
"editsection": "편집",
"editold": "편집",
"nstab-category": "분류",
"mainpage-nstab": "대문",
"nosuchaction": "이러한 명령이 없습니다",
- "nosuchactiontext": "URL에 지정한 명령이 올바르지 않습니다.\nURL을 잘못 입력했거나, 올바르지 않은 링크를 따라갔을 수 있습니다.\n{{SITENAME}}에 사용하는 소프트웨어의 버그가 있을 수 있습니다.",
+ "nosuchactiontext": "URL에 지정한 명령이 올바르지 않습니다.\nURL을 잘못 입력했거나, 올바르지 않은 링크를 따라갔을 수 있습니다.\n{{SITENAME}}에 사용하는 소프트웨어의 버그일 수도 있습니다.",
"nosuchspecialpage": "해당하는 특수 문서가 없습니다",
- "nospecialpagetext": "<strong>요청한 특수 문서가 존재하지 않습니다.</strong>\n\n특수 문서의 목록은 [[Special:SpecialPages|여기]]에서 볼 수 있습니다.",
+ "nospecialpagetext": "<strong>요청한 특수 문서가 존재하지 않습니다.</strong>\n\n유효한 특수 문서의 목록은 [[Special:SpecialPages|{{int:specialpages}}]]에서 볼 수 있습니다.",
"error": "오류",
"databaseerror": "데이터베이스 오류",
- "databaseerror-text": "데이터베이스 쿼리에 오류가 발생했습니다.\n소프트웨어에 버그가 있을 수 있습니다.",
- "databaseerror-textcl": "데이터베이스 쿼리에 오류가 발생했습니다.",
+ "databaseerror-text": "데이터베이스 쿼리 오류가 발생했습니다.\n소프트웨어의 버그일 수 있습니다.",
+ "databaseerror-textcl": "데이터베이스 쿼리 오류가 발생했습니다.",
"databaseerror-query": "쿼리: $1",
"databaseerror-function": "함수: $1",
"databaseerror-error": "오류: $1",
"enterlockreason": "데이터베이스를 잠그는 이유와 예상되는 기간을 적어 주세요.",
"readonlytext": "데이터베이스가 잠겨 있어서 문서를 편집할 수 없습니다. 데이터베이스 관리가 끝난 후에는 정상으로 돌아올 것입니다.\n\n시스템 관리자가 데이터베이스를 잠글 때 남긴 메시지는 다음과 같습니다: $1",
"missing-article": "데이터베이스에서 \"$1\" 문서의 $2 텍스트를 찾지 못했습니다.\n\n삭제된 문서의 오래된 차이나 역사 링크를 보려고 시도할 때 이러한 문제가 발생할 수 있습니다.\n\n그렇지 않다면, 소프트웨어에 버그가 발생했을 수도 있습니다.\n[[Special:ListUsers/sysop|관리자]]에게 URL을 참조하여 알려주세요.",
- "missingarticle-rev": "(판번호: $1)",
+ "missingarticle-rev": "(판 번호: $1)",
"missingarticle-diff": "(차이: $1, $2)",
"readonly_lag": "슬레이브 데이터베이스 서버들이 마스터 서버와 동기화되고 있습니다. 그 동안 데이터베이스가 자동으로 잠겨져 있습니다.",
"nonwrite-api-promise-error": "'Promise-Non-Write-API-Action' HTTP 헤더가 붙어있지만 API 쓰기 모듈에 대한 요청을 했습니다.",
"cannotdelete": "\"$1\" 문서나 파일을 삭제할 수 없습니다.\n이미 삭제되었을 수도 있습니다.",
"cannotdelete-title": "\"$1\" 문서를 삭제할 수 없습니다.",
"delete-hook-aborted": "훅이 삭제를 중단했습니다.\n아무런 설명도 주어지지 않았습니다.",
- "no-null-revision": "\"$1\" 문서에 대한 새 빈 판을 만들 수 없습니다",
+ "no-null-revision": "\"$1\" 문서에 대한 빈 판을 새로 만들 수 없습니다.",
"badtitle": "잘못된 제목",
"badtitletext": "요청한 문서 제목이 잘못되었거나, 비어있거나, 잘못된 인터위키 제목으로 링크했습니다.\n문서 제목에 사용할 수 없는 문자를 사용했을 수 있습니다.",
- "title-invalid-empty": "요청한 페이지의 제목이 비거나 이름공간밖에 안 들어있습니다.",
+ "title-invalid-empty": "요청한 페이지의 제목이 비어있거나 이름공간의 이름만 포함하고 있습니다.",
"title-invalid-utf8": "요청한 페이지 제목에 잘못된 UTF-8 글자가 있습니다.",
"title-invalid-interwiki": "요청한 페이지 제목에 제목에는 사용될 수 없는 위키간 링크가 있습니다.",
"title-invalid-talk-namespace": "요청한 페이지 제목이 존재하지 않는 토론 문서를 가리킵니다.",
"title-invalid-characters": "요청된 문서 제목이 잘못된 문자를 포함하고 있습니다: \"$1\".",
"title-invalid-relative": "제목에 상대 경로가 있습니다. 제목에 상대 경로를 쓰는 것은 적절하지 않습니다. 제목에 붙은 상대 경로는 사용자 브라우저에서 제대로 인식하지 못할 수도 있습니다.",
"title-invalid-magic-tilde": "요청한 문서의 제목에 적절하지 못한 특수 물결 문자열(magic tilde sequence; <nowiki>~~~</nowiki>)이 들어있습니다.",
- "title-invalid-too-long": "페이지 제목이 너무 깁니다. 페이지 제목 길이는 최대 $1 까지 설정할 수 있습니다.",
- "title-invalid-leading-colon": "페이지 제목에 잘못된 문자가 포함되어 있습니다.",
+ "title-invalid-too-long": "요청된 페이지 제목이 너무 깁니다. 길이는 UTF-8 인코딩 기준 최대 $1 바이트까지 설정할 수 있습니다.",
+ "title-invalid-leading-colon": "요청된 페이지 제목 처음에 잘못된 콜론 문자가 포함되어 있습니다.",
"perfcached": "다음 자료는 캐시된 것이며 최신이 아닐 수 있습니다. 캐시에 최대 {{PLURAL:$1|결과 한 개|결과 $1개}}가 있습니다.",
"perfcachedts": "다음 자료는 캐시된 것으로, $1에 마지막으로 업데이트되었습니다. 캐시에 최대 {{PLURAL:$4|결과 한 개|결과 $4개}}가 있습니다.",
- "querypage-no-updates": "ì\9d´ 문ì\84\9cì\9d\98 ê°±ì\8b ì\9d´ í\98\84ì\9e¬ ì¤\91ì§\80ë\90\98ì\96´ ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì\9e\90ë£\8cê°\80 ì\9e ì\8b\9c 갱신되지 않을 것입니다.",
+ "querypage-no-updates": "ì\9d´ 문ì\84\9cì\9d\98 ê°±ì\8b ì\9d´ í\98\84ì\9e¬ ì¤\91ì§\80ë\90\98ì\96´ ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì§\80ê¸\88ì\9d\80 ì\9e\90ë£\8cê°\80 갱신되지 않을 것입니다.",
"viewsource": "원본 보기",
"viewsource-title": "$1 문서 원본 보기",
"actionthrottled": "동작 중지",
- "actionthrottledtext": "악용을 막기 위해 짧은 시간 동안 이 작업을 너무 많이 수행하는 것을 ë§\89ê³ ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì \9cí\95\9cì\9d\84 ë\84\98ì\97\88ì\9c¼ë\8b\88 ëª\87 ë¶\84 ë\92¤ì\97\90 ì\83\88ë¡\9c ì\8b\9cë\8f\84í\95\98ì\84¸ì\9a\94.",
+ "actionthrottledtext": "악용을 막기 위해 짧은 시간 동안 이 작업을 너무 많이 수행하는 것을 ì \9cí\95\9cí\95\98ê³ ì\9e\88ì\8aµë\8b\88ë\8b¤.\nì \9cí\95\9cì\9d\84 ë\84\98ì\97\88ì\9c¼ë\8b\88 ëª\87 ë¶\84 ë\92¤ì\97\90 ë\8b¤ì\8b\9c ì\8b\9cë\8f\84í\95\98ì\84¸ì\9a\94.",
"protectedpagetext": "이 문서는 편집하거나 다른 명령을 할 수 없도록 보호되어 있습니다.",
"viewsourcetext": "문서의 원본을 보거나 복사할 수 있습니다.",
- "viewyourtext": "이 문서로의 <strong>당신의 편집</strong>의 원본을 보고 복사할 수 있습니다.",
+ "viewyourtext": "이 문서에 속한 <strong>당신의 편집</strong>의 원본을 보고 복사할 수 있습니다.",
"protectedinterface": "이 문서는 이 위키의 소프트웨어 인터페이스에 쓰이는 문서로, 부정 행위를 막기 위해 보호되어 있습니다.\n모든 위키에 대한 번역을 추가하거나 바꾸려면 미디어위키 지역화 프로젝트인 [//translatewiki.net/wiki/Main_Page?setlang=ko translatewiki.net]에 참여하시기 바랍니다.",
"editinginterface": "<strong>경고:</strong> 소프트웨어 인터페이스에 쓰이는 문서를 고치고 있습니다.\n이 문서에 있는 내용을 바꾸면 이 위키에 있는 모든 사용자에게 영향을 끼칩니다.",
"translateinterface": "모든 위키를 위해 번역을 추가하거나 바꾸려면, 미디어위키 지역화 프로젝트인 [//translatewiki.net/ translatewiki.net]을 사용해 주시기 바랍니다.",
"cascadeprotected": "이 문서는 다음 \"연쇄적\" 보호가 걸린 {{PLURAL:$1|문서|문서들}}에 포함되어 있어 함께 보호됩니다:\n$2",
- "namespaceprotected": "<strong>$1</strong> 이름공간의 문서를 편집할 수 있는 권한이 없습니다.",
+ "namespaceprotected": "<strong>$1</strong> 이름공간의 문서를 편집할 권한이 없습니다.",
"customcssprotected": "여기에는 다른 사용자의 개인 설정이 포함되어 있기 때문에 이 CSS 문서를 편집할 수 없습니다.",
"customjsprotected": "여기에는 다른 사용자의 개인 설정이 포함되어 있기 때문에 이 자바스크립트 문서를 편집할 수 없습니다.",
"mycustomcssprotected": "이 CSS 문서를 편집할 권한이 없습니다.",
"mypreferencesprotected": "내 환경 설정을 편집할 권한이 없습니다.",
"ns-specialprotected": "특수 문서는 편집할 수 없습니다.",
"titleprotected": "[[User:$1|$1]] 사용자가 문서 만들기를 금지했습니다.\n이유는 다음과 같습니다. <em>$2</em>",
- "filereadonlyerror": "\"$2\" 파일 저장소가 읽기 전용이기 때문에 \"$1\" 파일을 바꿀 수 없습니다.\n\n저장소 관리자가 파일 저장소를 잠근 이유에 대한 설명을 남겼습니다: \"$3\".",
+ "filereadonlyerror": "\"$2\" 파일 저장소가 읽기 전용이기 때문에 \"$1\" 파일을 바꿀 수 없습니다.\n\n파일 저장소를 잠근 시스템 관리자가 다음과 같은 설명을 남겼습니다: \"$3\".",
"invalidtitle-knownnamespace": "제목 오류: \"$2\" 이름공간과 \"$3\" 텍스트",
- "invalidtitle-unknownnamespace": "제목 오류: 알 수 없는 $1 이름공간 번호와, \"$2\" 텍스트",
+ "invalidtitle-unknownnamespace": "제목 오류: 알 수 없는 $1 이름공간 번호와 \"$2\" 텍스트",
"exception-nologin": "로그인하지 않음",
"exception-nologin-text": "이 문서에 접근하거나 이 동작을 수행하려면 로그인하세요.",
"exception-nologin-text-manual": "이 문서에 접근하거나 이 명령을 수행하려면 $1하세요.",
"cannotlogoutnow-title": "지금 로그아웃할 수 없습니다",
"cannotlogoutnow-text": "$1 사용 중에는 로그아웃이 불가능합니다.",
"welcomeuser": "$1님, 환영합니다!",
- "welcomecreation-msg": "계정이 만들어졌습니다.\n[[Special:Preferences|{{SITENAME}} 사용자 환경 설정]]을 바꿀 수 있습니다.",
+ "welcomecreation-msg": "계정이 만들어졌습니다.\n{{SITENAME}}의 사용자 [[Special:Preferences|환경 설정]]을 바꿀 수 있습니다.",
"yourname": "사용자 이름:",
- "userlogin-yourname": "사용자 계정 이름",
- "userlogin-yourname-ph": "사용자 계정 이름을 입력하세요",
- "createacct-another-username-ph": "사용자 계정 이름을 입력하세요",
+ "userlogin-yourname": "사용자 이름",
+ "userlogin-yourname-ph": "사용자 이름을 입력하세요",
+ "createacct-another-username-ph": "사용자 이름을 입력하세요",
"yourpassword": "비밀번호:",
"userlogin-yourpassword": "비밀번호",
"userlogin-yourpassword-ph": "비밀번호를 입력하세요",
"yourpasswordagain": "비밀번호 다시 입력:",
"createacct-yourpasswordagain": "비밀번호 확인",
"createacct-yourpasswordagain-ph": "비밀번호를 다시 입력하세요",
- "remembermypassword": "이 브라우저에서 로그인 상태를 저장하기 (최대 $1{{PLURAL:$1|일}})",
+ "remembermypassword": "이 브라우저에 로그인 상태 저장하기 (최대 $1일)",
"userlogin-remembermypassword": "로그인 상태를 유지하기",
"userlogin-signwithsecure": "보안 연결 사용",
"cannotloginnow-title": "지금 로그인할 수 없습니다.",
"cannotloginnow-text": "$1 사용 중에는 로그인이 불가능합니다.",
"yourdomainname": "도메인 이름:",
"password-change-forbidden": "이 위키에서 비밀번호를 바꿀 수 없습니다.",
- "externaldberror": "바깥 인증 데이터베이스에 오류가 있거나 바깥 계정을 새로 고칠 권한이 없습니다.",
+ "externaldberror": "인증 데이터베이스에 오류가 있거나 바깥 계정을 새로 고칠 권한이 없습니다.",
"login": "로그인",
+ "login-security": "사용자 정보 확인",
"nav-login-createaccount": "로그인 / 계정 만들기",
"userlogin": "로그인 / 계정 만들기",
"userloginnocreate": "로그인",
"userlogin-resetpassword-link": "비밀번호를 잊으셨나요?",
"userlogin-helplink2": "로그인에 대한 도움말",
"userlogin-loggedin": "이미 {{GENDER:$1|$1}} 사용자로 로그인되어 있습니다.\n다른 사용자로 로그인하려면 아래의 양식을 사용하세요.",
+ "userlogin-reauth": "사용자가 $1임을 확인하려면 다시 로그인해야 합니다.",
"userlogin-createanother": "다른 계정 만들기",
"createacct-emailrequired": "이메일 주소",
"createacct-emailoptional": "이메일 주소 (선택 사항)",
"createacct-email-ph": "이메일 주소를 입력하세요",
"createacct-another-email-ph": "이메일 주소를 입력하세요",
- "createaccountmail": "임시 임의 비밀번호를 이메일로 보내기",
+ "createaccountmail": "임의의 임시 비밀번호를 이메일로 보내기",
+ "createaccountmail-help": "비밀번호를 기억하지 않고도 다른 사용자를 위한 계정을 만들 수 있습니다.",
"createacct-realname": "실명 (선택 사항)",
"createaccountreason": "이유:",
"createacct-reason": "이유",
"createacct-reason-ph": "왜 다른 계정을 만들어야 합니까",
+ "createacct-reason-help": "계정 생성 로그에 표시되는 메시지",
"createacct-submit": "계정 만들기",
"createacct-another-submit": "계정 만들기",
+ "createacct-continue-submit": "계정 만들기 계속",
+ "createacct-another-continue-submit": "계정 만들기 계속",
"createacct-benefit-heading": "{{SITENAME}} 프로젝트는 여러분과 같은 사람들이 만듭니다.",
"createacct-benefit-body1": "{{PLURAL:$1|편집}}",
"createacct-benefit-body2": "{{PLURAL:$1|문서}}",
"userexists": "입력한 사용자 계정 이름이 이미 사용되고 있습니다.\n다른 이름을 선택하세요.",
"loginerror": "로그인 오류",
"createacct-error": "계정 만들기 오류",
- "createaccounterror": "계정을 만들수 없습니다: $1",
- "nocookiesnew": "사용자 계정을 만들었지만, 아직 로그인하고 있지 않습니다.\n{{SITENAME}}에서는 로그인 정보를 저장하기 위해 쿠키를 사용합니다.\n지금 사용하는 웹 브라우저는 쿠키를 사용하지 않도록 설정되어 있습니다.\n로그인하기 전에 웹 브라우저에서 쿠키를 사용하도록 설정해주세요.",
+ "createaccounterror": "계정을 만들 수 없습니다: $1",
+ "nocookiesnew": "사용자 계정을 만들었지만, 로그인되어 있지 않습니다.\n{{SITENAME}}에서는 로그인을 위해 쿠키를 사용합니다.\n사용자는 쿠키를 사용하지 않도록 설정되어 있습니다.\n쿠키를 사용하도록 설정한 다음 새로운 사용자 이름과 비밀번호로 로그인하세요.",
"nocookieslogin": "{{SITENAME}}에서는 로그인을 위해 쿠키를 사용합니다.\n쿠키가 비활성되어 있습니다.\n쿠키 사용을 활성화한 다음 다시 시도하세요.",
"nocookiesfornew": "요청의 출처를 확인할 수 없기 때문에 사용자 계정이 만들어지지 않았습니다.\n쿠키를 활성화한 것을 확인하고, 이 문서를 새로 고치고 나서 다시 시도하세요.",
+ "createacct-loginerror": "계정 만들기는 성공했으나 자동으로 로그인하지 못했습니다. [[Special:UserLogin|수동으로 로그인]]해 주십시오.",
"noname": "사용자 계정 이름이 올바르지 않습니다.",
"loginsuccesstitle": "로그인함",
"loginsuccess": "<strong>{{SITENAME}}에 \"$1\" 계정으로 로그인했습니다.</strong>",
- "nosuchuser": "이름이 \"$1\"인 사용자는 없습니다.\n사용자 계정 이름은 대소문자를 구별합니다.\n철자가 맞는지 확인해주세요. [[Special:UserLogin/signup|새 계정을 만들 수도 있습니다]].",
+ "nosuchuser": "이름이 \"$1\"인 사용자는 없습니다.\n사용자 이름은 대소문자를 구별합니다.\n철자가 맞는지 확인해주세요. [[Special:CreateAccount|새 계정을 만들 수도 있습니다]].",
"nosuchusershort": "이름이 \"$1\"인 사용자는 없습니다.\n철자가 맞는지 확인하세요.",
"nouserspecified": "사용자 계정 이름을 입력하지 않았습니다.",
"login-userblocked": "이 사용자는 차단되었습니다. 로그인할 수 없습니다.",
"accountcreatedtext": "[[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|토론]]) 사용자 계정이 만들어졌습니다.",
"createaccount-title": "{{SITENAME}} 계정 만들기",
"createaccount-text": "누군가가 {{SITENAME}} ($4)에서 사용자 이름 \"$2\", 비밀번호 \"$3\"로 당신의 이메일 주소가 등록된 계정을 만들었습니다. \n지금 로그인하여 비밀번호를 바꾸십시오.\n\n실수로 계정을 잘못 만들었다면 이 메시지는 무시해도 됩니다.",
- "login-throttled": "로그인에 연속으로 실패하였습니다.\n$1 기다렸다가 다시 시도하세요.",
+ "login-throttled": "최근 너무 많이 로그인을 시도했습니다.\n$1 뒤에 다시 시도하세요.",
"login-abort-generic": "로그인에 실패했습니다 - 중지됨",
"login-migrated-generic": "당신의 계정이 마이그레이션되었으며, 당신의 사용자 이름이 더 이상 이 위키에 존재하지 않습니다.",
"loginlanguagelabel": "언어: $1",
"createacct-another-realname-tip": "실명은 선택 사항입니다.\n실명을 입력하면 문서 기여에 사용자의 이름이 들어가게 됩니다.",
"pt-login": "로그인",
"pt-login-button": "로그인",
+ "pt-login-continue-button": "로그인 계속",
"pt-createaccount": "계정 만들기",
"pt-userlogout": "로그아웃",
"php-mail-error-unknown": "PHP의 mail() 함수에서 알 수 없는 오류가 발생했습니다.",
"changepassword-success": "비밀번호가 바뀌었습니다!",
"changepassword-throttled": "최근 너무 많이 로그인을 시도했습니다.\n$1 뒤에 다시 시도하세요.",
"botpasswords": "봇 비밀번호",
- "botpasswords-summary": "<em>봇 비밀번호</em>는 사용자의 기본 로그인 정보를 이용하지 않고 API를 통한 사용자 계정으로의 접근을 허용합니다. 봇 비밀번호를 이용하여 로그인할 때 이용 가능한 사용자 권한은 제한될 수 있습니다.\n\n이 기능을 이용할 이유가 없다면 굳이 이용하지 않으셔도 됩니다. 누구도 이 비밀번호의 생성을 사용자에게 요청할 수 없으며, 이를 수락하여 전달하지 말아 주십시오.",
+ "botpasswords-summary": "'''봇 비밀번호'''는 사용자의 기본 로그인 정보를 이용하지 않고 API를 통한 사용자 계정으로의 접근을 허용합니다. 봇 비밀번호를 이용하여 로그인할 때 이용 가능한 사용자 권한은 제한될 수 있습니다.\n\n이 기능을 이용할 이유가 없다면 굳이 이용하지 않으셔도 됩니다. 누구도 이 비밀번호의 생성을 사용자에게 요청할 수 없으며, 이를 수락하여 전달하지 말아 주십시오.",
"botpasswords-disabled": "봇 비밀번호가 비활성화되었습니다.",
"botpasswords-no-central-id": "봇 비밀번호를 사용하려면 통합 계정으로 로그인해야 합니다.",
"botpasswords-existing": "기존의 봇 비밀번호",
"botpasswords-invalid-name": "지정된 사용자 이름은 봇 비밀번호 구분자(\"$1\")를 포함하고 있지 않습니다.",
"botpasswords-not-exist": "\"$1\" 사용자가 이름이 \"$2\"인 봇의 비밀번호를 가지고 있지 않습니다.",
"resetpass_forbidden": "비밀번호를 바꿀 수 없습니다",
- "resetpass-no-info": "이 특수 문서에 직접 접근하려면 반드시 로그인해야 합니다.",
+ "resetpass_forbidden-reason": "암호를 변경할 수 없습니다: $1",
+ "resetpass-no-info": "이 페이지에 직접 접근하려면 로그인해야 합니다.",
"resetpass-submit-loggedin": "비밀번호 바꾸기",
"resetpass-submit-cancel": "취소",
"resetpass-wrong-oldpass": "비밀번호가 잘못되었거나 현재의 비밀번호와 같습니다.\n이미 비밀번호를 바꾸었거나 새 임시 비밀번호를 요청했을 수 있습니다.",
"passwordreset-text-many": "{{PLURAL:$1|이메일을 통해 임시 비밀번호를 받으려면 필드 중 하나를 채우세요.}}",
"passwordreset-disabled": "이 위키에서는 비밀번호를 재설정할 수 없습니다.",
"passwordreset-emaildisabled": "이 위키에서 이메일 기능이 비활성화되어 있습니다.",
- "passwordreset-username": "사용자 계정 이름:",
+ "passwordreset-username": "사용자 이름:",
"passwordreset-domain": "도메인:",
"passwordreset-capture": "발송 결과 이메일을 보시겠습니까?",
"passwordreset-capture-help": "이 상자에 체크하면 이메일이 발송된 즉시 임시 비밀번호가 담긴 이메일을 볼 수 있습니다.",
"passwordreset-emailsentemail": "당신의 계정과 연결된 이메일 주소가 있다면, 비밀번호 재설정 메일이 전해질 것입니다.",
"passwordreset-emailsentusername": "이 사용자 이름과 연결된 이메일 주소가 있다면 비밀번호 초기화 이메일이 전송됩니다.",
"passwordreset-emailsent-capture": "비밀번호 재설정 이메일이 발송되었으며, 아래에 나타나 있습니다.",
- "passwordreset-emailerror-capture": "비밀번호 재설정 이메일이 생성되어 아래에 보여져 있지만, {{GENDER:$2|사용자}}에게 발송하는 데에는 실패했습니다: $1",
+ "passwordreset-emailerror-capture": "비밀번호 재설정 이메일이 생성되어 아래에 나타나 있지만, {{GENDER:$2|사용자}}에게 발송하는 데에는 실패했습니다: $1",
+ "passwordreset-emailsent-capture2": "비밀번호 재설정 이메일을 보냈습니다. {{PLURAL:$1|사용자 이름과 비밀번호는|사용자 이름과 비밀번호의 목록은}} 아래에 나타납니다.",
+ "passwordreset-emailerror-capture2": "{{GENDER:$2|사용자}} 이메일 보내기 실패: $1 {{PLURAL:$3|사용자 이름과 비밀번호가|사용자 이름과 비밀번호의 목록이}} 아래에 나타납니다.",
+ "passwordreset-nocaller": "호출자를 지정해야 합니다",
+ "passwordreset-nosuchcaller": "호출자가 존재하지 않습니다: $1",
+ "passwordreset-ignored": "비밀번호 재설정을 처리하지 못했습니다. 제공자가 구성되지 않았기 때문일 수 있습니다.",
+ "passwordreset-invalideamil": "잘못된 이메일 주소",
+ "passwordreset-nodata": "사용자 이름이나 이메일 주소가 지정되지 않았습니다",
"changeemail": "이메일 주소를 바꾸거나 제거하기",
"changeemail-header": "이메일 주소를 바꾸려면 이 양식을 채우세요. 계정에서 이메일 연동을 취소하고 싶다면 양식을 제출할 때 새 이메일 주소를 공란으로 두세요.",
"changeemail-passwordrequired": "변경을 적용하려면 비밀번호를 입력해야 합니다.",
- "changeemail-no-info": "ì\9d´ í\8a¹ì\88\98 문ì\84\9cì\97\90 ì§\81ì \91 ì \91ê·¼í\95\98ë ¤ë©´ ë°\98ë\93\9cì\8b\9c 로그인해야 합니다.",
+ "changeemail-no-info": "ì\9d´ í\8e\98ì\9d´ì§\80ì\97\90 ì§\81ì \91 ì \91ê·¼í\95\98ë ¤ë©´ 로그인해야 합니다.",
"changeemail-oldemail": "현재 이메일 주소:",
"changeemail-newemail": "새 이메일 주소:",
"changeemail-newemail-help": "이메일 주소를 삭제하고자 한다면 이 칸을 빈칸으로 두세요. 비밀번호 재설정이 불가능해지며, 이메일 주소가 없다면 이메일을 받을 수 없습니다.",
"changeemail-none": "(없음)",
"changeemail-password": "{{SITENAME}} 비밀번호:",
"changeemail-submit": "이메일 주소 바꾸기",
- "changeemail-throttled": "로그인에 연속으로 너무 많이 실패하였습니다.\n$1 기다렸다가 다시 시도하세요.",
+ "changeemail-throttled": "최근 너무 많이 로그인을 시도했습니다.\n$1 뒤에 다시 시도하세요.",
"changeemail-nochange": "다른 이메일 주소를 입력해 주세요.",
"resettokens": "토큰 재설정",
"resettokens-text": "여기에 당신의 계정과 관련된 특정 개인 데이터에 접근을 허용하는 토큰을 재설정합니다.\n\n토큰이 다른 사람에게 알려졌거나 계정이 침해되었을 때는 재설정해야 합니다.",
"preview": "미리 보기",
"showpreview": "미리 보기",
"showdiff": "차이 보기",
- "blankarticle": "<strong>경고:</strong> 만들려는 문서가 비어 있습니다.\n\"{{int:savearticle}}\"을 다시 클릭하면, 문서에 내용이 없이 만들어집니다.",
- "anoneditwarning": "<strong>경고:</strong> 로그인을 하고 있지 않습니다. 편집을 하게 되면 IP 주소가 공개적으로 보여집니다. <strong>[$1 로그인]</strong>하거나 <strong>[$2 계정을 생성하면]</strong>, 편집 시에 다른 이점과 함께 사용자 이름이 표시됩니다.",
+ "blankarticle": "<strong>경고:</strong> 만들려는 문서가 비어 있습니다.\n\"{{int:savearticle}}\"을 다시 클릭하면, 아무 내용 없이 문서가 만들어집니다.",
+ "anoneditwarning": "<strong>경고:</strong> 로그인을 하고 있지 않습니다. 편집을 하면 IP 주소가 공개적으로 보이게 됩니다. <strong>[$1 로그인]</strong>하거나 <strong>[$2 계정을 생성하면]</strong>, 편집 시에 사용자 이름이 표시되며 더불어 다른 혜택들도 누릴 수 있습니다.",
"anonpreviewwarning": "<em>로그인하고 있지 않습니다. 문서를 저장하면 당신의 IP 주소가 문서의 편집 역사에 남게 됩니다.</em>",
"missingsummary": "'''알림:''' 편집 요약을 적지 않았습니다.\n이대로 \"{{int:savearticle}}\"을 클릭하면 편집 요약 없이 저장됩니다.",
"selfredirect": "<strong>경고:</strong> 자기 자신으로 문서를 넘겨주고 있습니다.\n넘겨줄 대상을 잘못 입력했거나, 잘못된 문서를 편집하고 있을 수 있습니다.\n\"{{int:savearticle}}\"을 입력하면, 넘겨주기 문서가 생성될 것입니다.",
"accmailtext": "[[User talk:$1|$1]] 사용자의 비밀번호를 임의로 만들어 $2(으)로 보냈습니다. 로그인하고 나서 <em>[[Special:ChangePassword|비밀번호를 바꿀]]</em> 수 있습니다.",
"newarticle": "(새 문서)",
"newarticletext": "아직 없는 문서의 링크를 따라왔습니다.\n새 문서를 만들려면 아래 상자에 내용을 입력하면 됩니다. (자세한 내용은 [$1 도움말 문서]를 참조하세요)\n만약 잘못 찾아왔다면, 브라우저의 '''뒤로''' 버튼을 눌러 주세요.",
- "anontalkpagetext": "----\n여기는 계정을 만들지 않았거나 사용하고 있지 않은 익명 사용자를 위한 토론 문서입니다.\n익명 사용자를 구별하기 위해서는 숫자로 된 IP 주소를 사용해야만 합니다.\nIP 주소는 여러 사용자가 공유할 수 있습니다.\n자신과 관계없는 의견이 자신에게 남겨져 있어 불쾌하다고 생각하는 익명 사용자는 [[Special:UserLogin/signup|계정을 만들고]] [[Special:UserLogin|로그인해서]] 나중에 다른 익명 사용자에게 줄 혼란을 줄일 수 있습니다.",
+ "anontalkpagetext": "----\n여기는 계정을 만들지 않았거나 사용하고 있지 않은 익명 사용자를 위한 토론 문서입니다.\n익명 사용자를 구별하기 위해서는 숫자로 된 IP 주소를 사용해야만 합니다.\nIP 주소는 여러 사용자가 공유할 수 있습니다.\n자신과 관계없는 의견이 자신에게 남겨져 있어 불쾌하다고 생각하는 익명 사용자는 [[Special:CreateAccount|계정을 만들고]] [[Special:UserLogin|로그인해서]] 나중에 다른 익명 사용자에게 줄 혼란을 줄일 수 있습니다.",
"noarticletext": "이 문서가 현재 존재하지 않습니다.\n이 문서와 제목이 비슷한 문서가 있는지 [[Special:Search/{{PAGENAME}}|검색하거나]],\n이 문서에 관련된 <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 기록]을 확인하거나,\n문서를 직접 [{{fullurl:{{FULLPAGENAME}}|action=edit}} 생성]</span>할 수 있습니다.",
"noarticletext-nopermission": "이 문서가 현재 존재하지 않습니다.\n이 문서와 제목이 비슷한 문서가 있는지 [[Special:Search/{{PAGENAME}}|검색하거나]], 이 문서에 관련된 <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 기록]을 확인할 수 있습니다.</span> 그러나 이 문서를 만들 수 있는 권한은 없습니다.",
"missing-revision": "\"{{FULLPAGENAME}}\"이라는 문서의 #$1판이 존재하지 않습니다.\n\n이 문제는 주로 삭제된 문서를 가리키는 오래된 문서 역사 링크로 인해 발생합니다.\n자세한 내용은 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 삭제 기록]에서 확인할 수 있습니다.",
"userpage-userdoesnotexist": "\"$1\" 사용자 계정은 등록되어 있지 않습니다.\n이 문서를 만들거나 편집하기 전에 계정이 존재하는지 확인해주세요.",
"userpage-userdoesnotexist-view": "\"$1\" 사용자 계정은 등록되어 있지 않습니다.",
"blocked-notice-logextract": "이 사용자는 현재 차단되어 있습니다.\n해당 사용자의 최근 차단 기록을 참조하십시오:",
- "clearyourcache": "<strong>참고:</strong> 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.\n* <strong>파이어폭스 / 사파리</strong>: <em>Shift</em> 키를 누르면서 새로 고침을 클릭하거나, <em>Ctrl-F5</em> 또는 <em>Ctrl-R</em> 을 입력 (Mac에서는 <em>⌘-R</em>)\n* <strong>구글 크롬</strong>: <em>Ctrl-Shift-R</em>키를 입력 (Mac에서는 <em>⌘-Shift-R</em>)\n* <strong>인터넷 익스플로러</strong>: <em>Ctrl</em> 키를 누르면서 새로 고침을 클릭하거나, <em>Ctrl-F5</em>를 입력.\n* <strong>오페라:</strong> <em>메뉴 → 설정</em>(맥의 경우 <em>오페라 → 환경 설정</em>)으로 이동한 다음 <em>개인 정보 보호 및 보안 → 검색 데이터 지우기 → 캐시한 이미지 및 파일</em>를 누름.",
+ "clearyourcache": "<strong>참고:</strong> 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.\n* <strong>파이어폭스 / 사파리</strong>: <em>Shift</em> 키를 누르면서 새로 고침을 클릭하거나, <em>Ctrl-F5</em> 또는 <em>Ctrl-R</em> 을 입력 (Mac에서는 <em>⌘-R</em>)\n* <strong>구글 크롬</strong>: <em>Ctrl-Shift-R</em>키를 입력 (Mac에서는 <em>⌘-Shift-R</em>)\n* <strong>인터넷 익스플로러</strong>: <em>Ctrl</em> 키를 누르면서 새로 고침을 클릭하거나, <em>Ctrl-F5</em>를 입력.\n* <strong>오페라:</strong> <em>메뉴 → 설정</em>(맥의 경우 <em>오페라 → 환경 설정</em>)으로 이동한 다음 <em>개인 정보 보호 및 보안 → 검색 데이터 지우기 → 캐시한 이미지 및 파일</em>을 누름.",
"usercssyoucanpreview": "'''안내''': CSS 문서를 저장하기 전에 \"{{int:showpreview}}\" 기능을 통해 작동을 확인해주세요.",
"userjsyoucanpreview": "'''안내''': 자바스크립트 문서를 저장하기 전에 \"{{int:showpreview}}\" 기능을 통해 작동을 확인해주세요.",
"usercsspreview": "'''사용자 CSS의 미리 보기입니다.'''\n'''아직 저장하지 않았습니다!'''",
"note": "<strong>참고:</strong>",
"previewnote": "'''이 화면은 미리 보기입니다.'''\n편집한 내용은 아직 저장하지 않았습니다!",
"continue-editing": "편집 영역으로 가기",
- "previewconflict": "이 미리 보기는 저장할 때의 모습으로 위쪽 편집창의 문서를 반영합니다.",
+ "previewconflict": "이 미리 보기는 저장할 때의 모습으로, 위쪽 편집 영역의 텍스트를 반영합니다.",
"session_fail_preview": "세션 데이터가 없어져 편집을 저장하지 못했습니다.\n\n로그아웃되었는지도 모릅니다. <strong>아직 로그인 상태인지 확인하고 다시 시도해주세요</strong>.\n다시 시도해도 되지 않으면 [[Special:UserLogout|로그아웃]]한 다음 다시 로그인하세요. 그리고 브라우저 설정에서 쿠키 사용을 허용하는지 확인하세요.",
"session_fail_preview_html": "세션 데이터가 없어져 편집을 저장하지 못했습니다.\n\n<em>{{SITENAME}}에서 HTML 입력을 허용하기 때문에, 자바스크립트 공격을 막기 위해 미리 보기는 숨겨져 있습니다.</em>\n\n<strong>적합하게 편집을 시도했다면 다시 시도해주세요.</strong>\n다시 시도해도 되지 않으면 [[Special:UserLogout|로그아웃]]한 다음 다시 로그인하고, 브라우저가 이 사이트에서 쿠키를 허용하는지 확인하세요.",
"token_suffix_mismatch": "'''저장하려는 내용의 문장 부호가 망가져 있습니다.'''\n문서 보호를 위해 해당 내용을 저장하지 않습니다.\n버그가 있는 익명 프록시 서비스 등을 사용할 때 이런 문제가 발생할 수 있습니다.",
"explainconflict": "문서를 편집하는 도중에 누군가 이 문서를 고쳤습니다.\n위쪽의 문서가 지금 바뀐 문서이고, 아래쪽의 문서가 당신이 편집한 문서입니다.\n아래쪽의 내용을 위쪽에 적절히 합쳐 주시기 바랍니다.\n\"{{int:savearticle}}\"을 누르면 '''위쪽의 편집 내역만''' 저장됩니다.",
"yourtext": "당신의 편집",
"storedversion": "현재 문서",
- "nonunicodebrowser": "<strong>경고: 웹 브라우저가 유니코드를 완벽하게 지원하지 않습니다.</strong>\n아스키가 아닌 문자가 16진수 코드로 나타날 수 있습니다.",
+ "nonunicodebrowser": "<strong>경고: 브라우저가 유니코드를 지원하지 않습니다.</strong>\n문서를 안전하게 편집할 수 있도록 다음의 우회 방안이 제공됩니다: 편집 상자에서 아스키가 아닌 문자가 16진수 코드로 나타납니다.",
"editingold": "<strong>경고: 이 문서의 오래된 판을 편집하고 있습니다.</strong>\n이것을 저장하면, 이 판 이후로 바뀐 모든 편집이 사라집니다.",
"yourdiff": "차이",
"copyrightwarning": "{{SITENAME}}에서의 모든 기여는 $2 라이선스로 배포된다는 점을 유의해 주세요 (자세한 내용에 대해서는 $1 문서를 읽어주세요).\n만약 여기에 동의하지 않는다면 문서를 저장하지 말아 주세요.<br />\n또한, 직접 작성했거나 퍼블릭 도메인과 같은 자유 문서에서 가져왔다는 것을 보증해야 합니다.\n<strong>저작권이 있는 내용을 허가 없이 저장하지 마세요!</strong>",
"readonlywarning": "<strong>경고: 데이터베이스가 관리를 위해 잠겨 있습니다. 따라서 문서를 편집한 내용을 지금 저장할 수 없습니다.</strong>\n편집 내용을 복사하여 붙여넣기 등을 사용하여 일단 다른 곳에 저장한 후, 나중에 다시 시도해 주세요.\n\n데이터베이스를 잠근 시스템 관리자가 남긴 설명은 다음과 같습니다: $1",
"protectedpagewarning": "<strong>경고: 이 문서는 관리자 권한이 있는 사용자만 편집할 수 있도록 보호되어 있습니다.</strong>\n이 문서의 최근 기록을 참조하십시오:",
"semiprotectedpagewarning": "<strong>참고:</strong> 이 문서는 계정을 등록한 사용자만이 편집할 수 있도록 보호되어 있습니다.\n이 문서의 최근 기록을 참조하십시오:",
- "cascadeprotectedwarning": "<strong>경고:</strong> 이 문서는 보호되어 있어 관리자만 편집할 수 있습니다. 연쇄적 보호가 걸린 다음 {{PLURAL:$1|문서}}에서 이 문서를 사용하고 있습니다:",
+ "cascadeprotectedwarning": "<strong>경고:</strong> 이 문서는 보호되어 있어 관리자 권한이 있는 사용자만 편집할 수 있습니다. 연쇄적 보호가 걸린 다음 {{PLURAL:$1|문서}}에서 이 문서를 사용하고 있습니다:",
"titleprotectedwarning": "<strong>경고: 이 문서는 보호되어 있어, 문서를 만드려면 [[Special:ListGroupRights|특정한 권한]]이 필요합니다.</strong>\n아래 문서의 최근 기록을 참조하십시오:",
"templatesused": "이 문서에서 사용한 {{PLURAL:$1|틀}}:",
"templatesusedpreview": "이 미리 보기에서 사용하고 있는 {{PLURAL:$1|틀}}:",
"duplicate-args-category": "중복된 인수를 사용한 틀의 호출을 포함한 문서",
"duplicate-args-category-desc": "문서에 <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code>나 <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>와 같은, 인수를 중복하여 사용한 틀 호출을 포함합니다.",
"expensive-parserfunction-warning": "<strong>경고:</strong> 이 문서는 너무 많은 파서 함수를 포함하고 있습니다.\n\n$2개 보다 적게 {{PLURAL:$2|써야}} 하지만 {{PLURAL:$1|지금은 $1개를 쓰고 있습니다}}.",
- "expensive-parserfunction-category": "느린 파서 함수 호출을 너무 많이 하는 문서",
+ "expensive-parserfunction-category": "파서 함수 호출을 너무 많이 사용하는 문서",
"post-expand-template-inclusion-warning": "<strong>경고:</strong> 틀 포함 크기가 너무 큽니다.\n일부 틀은 포함되지 않을 수 있습니다.",
"post-expand-template-inclusion-category": "사용한 틀의 크기가 지나치게 큰 문서의 목록",
"post-expand-template-argument-warning": "<strong>경고:</strong> 이 문서는 전개하면 크기가 너무 큰 틀 인수가 하나 이상 포함되어 있습니다.\n이 인수는 생략했습니다.",
"parser-unstrip-loop-warning": "Unstrip의 반복을 감지했습니다",
"parser-unstrip-recursion-limit": "Unstrip의 재귀 한도를 초과했습니다 ($1)",
"converter-manual-rule-error": "언어 변환 규칙을 수동으로 지정하는 도중 오류",
- "undo-success": "편집을 되돌릴 수 있습니다.\n편집 되돌리기를 완료하려면 이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 저장해주세요.",
+ "undo-success": "편집을 되돌릴 수 있습니다.\n이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 저장해주세요.",
"undo-failure": "중간의 다른 편집과 충돌하여 이 편집을 되돌릴 수 없습니다.",
"undo-norev": "문서가 없거나 삭제되었기 때문에 편집을 되돌릴 수 없습니다.",
"undo-nochange": "편집이 이미 되돌려진 것으로 나타납니다.",
"undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|토론]])의 $1판 편집을 되돌림",
"undo-summary-username-hidden": "숨겨진 사용자가 $1 판을 되돌림",
"cantcreateaccounttitle": "계정을 만들 수 없습니다",
- "cantcreateaccount-text": "현재 아이피 주소('''$1''')는 [[User:$3|$3]] 사용자에 의해 계정 만들기가 차단되었습니다.\n\n차단 이유는 다음과 같습니다: $2",
+ "cantcreateaccount-text": "현재 IP 주소('''$1''')는 [[User:$3|$3]] 사용자에 의해 계정 만들기가 차단되었습니다.\n\n차단 이유는 다음과 같습니다: $2",
"cantcreateaccount-range-text": "당신의 IP 주소(<strong>$4</strong>)가 속해 있는 <strong>$1</strong> 대역에서의 계정 생성을 [[User:$3|$3]] 사용자가 차단하였습니다.\n\n$3 사용자가 제시한 이유는 \"$2\"입니다.",
"viewpagelogs": "이 문서의 기록 보기",
"nohistory": "이 문서는 편집 역사가 없습니다.",
"logdelete-selected": "{{PLURAL:$1|선택한 기록}}:",
"revdelete-text-text": "삭제된 판은 여전히 문서 역사에 남게 되지만, 그 내용의 일부는 다른 사람들이 접근할 수 없게 됩니다.",
"revdelete-text-file": "삭제된 파일 버전은 계속 파일 역사에 남게 되지만, 내용의 일부는 다른 사람들이 접근할 수 없게 됩니다.",
- "logdelete-text": "ì\82ì \9cë\90\9c ë¡\9cê·¸ ë\82´ì\9a©ì\9d\80 ë¡\9cê·¸ì\97\90 ë³´ì\97¬ì§\80ê² ì§\80ë§\8c, ë\82´ì\9a©ì\9d\98 ì\9d¼ë¶\80ë\8a\94 ë\8b¤ë¥¸ ì\82¬ë\9e\8cë\93¤이 접근할 수 없게 됩니다.",
+ "logdelete-text": "ì\82ì \9cë\90\9c ë¡\9cê·¸ ë\82´ì\9a©ì\9d\80 ë¡\9cê·¸ì\97\90 ë\82\98í\83\80ë\82\98ì§\80ë§\8c, ë\82´ì\9a© ì¤\91 ì\9d¼ë¶\80ë\8a\94 ì\9d¼ë°\98ì\9d¸이 접근할 수 없게 됩니다.",
"revdelete-text-others": "다른 관리자는 여전히 숨겨진 내용에 접근할 수 있고 추가 제한이 설정되어 있지 않으면, 다시 되살릴 수 있습니다.",
- "revdelete-confirm": "ì\9d´ ì\9e\91ì\97\85ì\9d\84 ì\88\98í\96\89í\95\98ë\8a\94 ê²\83ì\9d\98 결과를 ì\95\8cê³ ì\9e\88ì\9c¼ë©°, [[{{MediaWiki:Policy-url}}|ì \95ì±\85]]ì\97\90 ë§\9eë\8a\94 í\96\89ë\8f\99ì\9d¸지 확인해주세요.",
+ "revdelete-confirm": "ì\9d´ ì\9e\91ì\97\85ì\9d\98 ì\88\98í\96\89 결과를 ì\95\8cê³ ì\9e\88ì\9c¼ë©°, ì\9d´ ì\9e\91ì\97\85ì\9d´ [[{{MediaWiki:Policy-url}}|ì \95ì±\85]]ì\97\90 ì\9d\98ê±°í\95\98ë\8a\94지 확인해주세요.",
"revdelete-suppress-text": "숨기기는 <strong>다음 경우에만</strong> 사용되어야 합니다:\n* 잠재적인 비방 정보\n* 부적절한 개인 정보\n*: 집 주소, 전화번호, 주민등록번호 등",
"revdelete-legend": "보이기 제한을 설정",
"revdelete-hide-text": "판 문자열",
"mergehistory-submit": "판 합치기",
"mergehistory-empty": "합칠 수 있는 판이 없습니다.",
"mergehistory-done": "$1 문서의 {{PLURAL:$3|판}} $3개{{PLURAL:$3|가}} [[:$2]]에 성공적으로 합쳐졌습니다.",
- "mergehistory-fail": "역사 합치기를 수행할 수 없습니다, 문서와 시간 변수를 다시 확인하세요.",
- "mergehistory-fail-bad-timestamp": "타임스탬프(timestamp)가 적절하지 않습니다.",
+ "mergehistory-fail": "역사 합치기를 수행할 수 없습니다. 문서와 시간 변수를 다시 확인하세요.",
+ "mergehistory-fail-bad-timestamp": "타임스탬프가 적절하지 않습니다.",
"mergehistory-fail-invalid-source": "원본 문서가 적절하지 않습니다.",
"mergehistory-fail-invalid-dest": "대상 문서가 적절하지 않습니다.",
"mergehistory-fail-no-change": "역사 병합은 모든 판을 병합하지 못했습니다. 문서와 시간 변수를 다시 확인하여 주십시오.",
"notextmatches": "해당하는 문서 없음",
"prevn": "이전 {{PLURAL:$1|$1개}}",
"nextn": "다음 {{PLURAL:$1|$1개}}",
- "prev-page": "전 페이지",
+ "prev-page": "ì\9d´ì \84 í\8e\98ì\9d´ì§\80",
"next-page": "다음 페이지",
"prevn-title": "이전 {{PLURAL:$1|결과}} $1개",
"nextn-title": "다음 {{PLURAL:$1|결과}} $1개",
"right-move-rootuserpages": "최상위 사용자 문서 이동",
"right-move-categorypages": "분류 문서 이동",
"right-movefile": "파일 이동",
- "right-suppressredirect": "문서을 옮길 때 원래 문서 이름으로 된 넘겨주기를 만들지 않기",
+ "right-suppressredirect": "문서를 옮길 때 원래 문서 이름으로 된 넘겨주기를 만들지 않기",
"right-upload": "파일 올리기",
"right-reupload": "이미 존재하는 파일을 다시 올리기",
"right-reupload-own": "자신이 이미 올린 파일 덮어쓰기",
"right-managechangetags": "데이터베이스에서 [[Special:Tags|태그]]를 만들거나 지우기",
"right-applychangetags": "자신이 편집할 때 [[Special:Tags|태그]]를 적용하기",
"right-changetags": "문서의 특정 판과 특정 기록 항목에 임의의 [[Special:Tags|태그]]를 추가하거나 제거하기",
+ "right-deletechangetags": "데이터베이스에서 [[Special:Tags|태그]]를 지우기",
"grant-generic": "\"$1\" 권한 번들",
"grant-group-page-interaction": "문서로 상호 작용",
"grant-group-file-interaction": "미디어로 상호 작용",
"action-viewmyprivateinfo": "자신의 개인정보 보기",
"action-editmyprivateinfo": "자신의 개인정보 편집",
"action-editcontentmodel": "문서의 콘텐츠 모델을 편집",
- "action-managechangetags": "ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ì\97\90ì\84\9c í\83\9c그를 ë§\8cë\93¤ê±°ë\82\98 ì§\80ì\9a¸",
+ "action-managechangetags": "ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ì\97\90ì\84\9c í\83\9c그를 ë§\8cë\93¤ê±°ë\82\98 ì§\80ì\9a°ê¸°",
"action-applychangetags": "당신이 편집할 때 태그를 적용하기",
"action-changetags": "문서의 특정 판과 특정 기록 항목에 임의의 태그를 추가하거나 제거하기",
+ "action-deletechangetags": "데이터베이스에서 태그를 지우기",
"nchanges": "$1개 {{PLURAL:$1|바뀜}}",
"enhancedrc-since-last-visit": "{{PLURAL:$1|마지막 방문 이후}} $1개",
"enhancedrc-history": "역사",
"upload-form-label-own-work": "자작입니다",
"upload-form-label-infoform-categories": "분류",
"upload-form-label-infoform-date": "날짜",
- "upload-form-label-own-work-message-local": "사용자는 이 파일을 업로드할 때 {{SITENAME}}의 서비스 조항과 라이선스 정책에 동의하는 것으로 간주합니다.",
- "upload-form-label-not-own-work-message-local": "이 파일을 {{SITENAME}}의 정책에 따라 업로드할 수 없으면 이 대화 상자를 닫고 다른 방식을 사용하십시오.",
- "upload-form-label-not-own-work-local-local": "[[Special:Upload|기본 파일 올리기 문서]]를 이용할 수도 있습니다.",
- "upload-form-label-own-work-message-default": "이 파일을 공유 저장소에 업로드하면 사용자는 서비스 조항과 라이선스 정책에 동의하는 것으로 간주합니다.",
- "upload-form-label-not-own-work-message-default": "이 파일을 공유 저장소의 정책에 따라 업로드할 수 없으면 이 대화 상자를 닫고 다른 방식을 사용하십시오.",
- "upload-form-label-not-own-work-local-default": "이 파일이 정책에 따라 업로드가 가능할 경우 [[Special:Upload|{{SITENAME}}의 기본 파일 올리기 문서]]를 이용할 수도 있습니다.",
- "upload-form-label-own-work-message-shared": "나는 이 파일에 대한 저작권을 소유하고 있음을 입증하고, 영구히 위키미디어 공용에 이 파일을 [https://creativecommons.org/licenses/by-sa/4.0/ 크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0]에 따라 배포하는 데 동의하며, [https://wikimediafoundation.org/wiki/Terms_of_Use 이용 약관]에 동의합니다.",
- "upload-form-label-not-own-work-message-shared": "이 파일의 저작권을 소유하지 않거나 다른 라이선스로 배포하고 싶다면 [https://commons.wikimedia.org/wiki/Special:UploadWizard 공용 파일 올리기 마법사]를 사용하는 것을 고려해보세요.",
- "upload-form-label-not-own-work-local-shared": "사이트가 정책에 따라 이 파일의 업로드를 허용할 경우 [[Special:Upload|{{SITENAME}}의 기본 파일 올리기 문서]]를 이용할 수도 있습니다.",
+ "upload-form-label-own-work-message-generic-local": "사용자는 이 파일을 업로드할 때 {{SITENAME}}의 서비스 조항과 라이선스 정책에 동의하는 것으로 간주합니다.",
+ "upload-form-label-not-own-work-message-generic-local": "이 파일을 {{SITENAME}}의 정책에 따라 업로드할 수 없으면 이 대화 상자를 닫고 다른 방식을 사용하십시오.",
+ "upload-form-label-not-own-work-local-generic-local": "[[Special:Upload|기본 파일 올리기 문서]]를 이용할 수도 있습니다.",
+ "upload-form-label-own-work-message-generic-foreign": "이 파일을 공유 저장소에 업로드하면 사용자는 서비스 조항과 라이선스 정책에 동의하는 것으로 간주합니다.",
+ "upload-form-label-not-own-work-message-generic-foreign": "이 파일을 공유 저장소의 정책에 따라 업로드할 수 없으면 이 대화 상자를 닫고 다른 방식을 사용하십시오.",
+ "upload-form-label-not-own-work-local-generic-foreign": "이 파일이 정책에 따라 업로드가 가능할 경우 [[Special:Upload|{{SITENAME}}의 기본 파일 올리기 문서]]를 이용할 수도 있습니다.",
"backend-fail-stream": "\"$1\" 파일을 스트림할 수 없습니다.",
"backend-fail-backup": "\"$1\" 파일을 백업할 수 없습니다.",
"backend-fail-notexists": "$1 파일이 존재하지 않습니다.",
"apisandbox": "API 실험실",
"apisandbox-jsonly": "API 연습장을 이용하려면 자바스크립트가 필요합니다.",
"apisandbox-api-disabled": "이 사이트에서는 API가 꺼져 있습니다.",
- "apisandbox-intro": "<strong>미디어위키 웹 서비스 API</strong>를 시험해보려면 이 페이지를 이용해보세요. API 용법에 대해서는 [[mw:API:Main page|API 문서]]을 참고하십시오. 예: [//www.mediawiki.org/wiki/API#A_simple_example 대문의 내용 요청하기]. 더 많은 예를 보려면 액션을 선택하세요.\n\n여기가 연습장이라도 이 페이지에서 실행하는 동작때문에 위키를 변경할 수도 있다는 점에 유의하십시오.",
+ "apisandbox-intro": "<strong>미디어위키 웹 서비스 API</strong>를 시험해보려면 이 페이지를 이용해보세요. API 용법에 대해서는 [[mw:API:Main page|API 문서]]를 참고하십시오. 예: [//www.mediawiki.org/wiki/API#A_simple_example 대문의 내용 요청하기]. 더 많은 예를 보려면 액션을 선택하세요.\n\n여기가 연습장이라도 이 페이지에서 실행하는 동작 때문에 위키를 변경할 수도 있다는 점에 유의하십시오.",
"apisandbox-fullscreen": "패널 늘리기",
"apisandbox-fullscreen-tooltip": "브라우저 창에 맞도록 샌드박스 패널 늘리기",
"apisandbox-unfullscreen": "페이지 보기",
"apisandbox-results": "결과",
"apisandbox-sending-request": "API 요청을 보내는 중...",
"apisandbox-loading-results": "API 결과를 받는 중...",
- "apisandbox-results-error": "API ì§\88ì\9d\98 ì\9a\94ì²ì\9d\84 ë¡\9cë\94©í\95\98ë\8a\94 ë\8f\84ì¤\91 ì\97\90ë\9f¬ 발생: $1.",
+ "apisandbox-results-error": "API ì§\88ì\9d\98 ì\9d\91ë\8bµì\9d\84 ë¶\88ë\9f¬ì\98¤ë\8a\94 ë\8f\84ì¤\91 ì\98¤ë¥\98 발생: $1.",
"apisandbox-request-url-label": "요청 URL:",
"apisandbox-request-time": "요청 처리 시간: {{PLURAL:$1|$1 ms}}",
"apisandbox-results-fixtoken": "토큰 수정 후 다시 제출",
"trackingcategories-msg": "추적용 분류",
"trackingcategories-name": "메시지 이름",
"trackingcategories-desc": "분류 포함 기준",
+ "restricted-displaytitle-ignored": "제목 표시가 무시된 문서",
+ "restricted-displaytitle-ignored-desc": "문서의 실제 제목과 일치하지 않기 때문에 무시된 <code><nowiki>{{DISPLAYTITLE}}</nowiki></code>이 있는 문서입니다.",
"noindex-category-desc": "문서는 그것과 그 플래그가 허용된 곳에 있는 이름공간에서 <code><nowiki>__NOINDEX__</nowiki></code> 특수 명령이 있기 때문에 로봇이 색인하지 않습니다.",
"index-category-desc": "문서는 그것(과 플래그가 허용된 곳에 있는 이름공간에 있는 것)에 <code><nowiki>__INDEX__</nowiki></code>가 있어서, 정상적이지 않을 곳에 로봇에 의해 색인됩니다.",
"post-expand-template-inclusion-category-desc": "모든 틀을 전개하였을 때, 문서 크기가 <code>$wgMaxArticleSize</code>보다 커지므로, 어떤 틀은 전개하지 않았습니다.",
"unwatchthispage": "주시 해제하기",
"notanarticle": "문서가 아님",
"notvisiblerev": "이 판은 삭제되었습니다.",
- "watchlist-details": "별도의 토론 문서를 세지 않고, 주시문서 목록에 {{PLURAL:$1|문서 $1개}}가 있습니다.",
+ "watchlist-details": "토론 문서의 수는 제외하고, 주시문서 목록에 {{PLURAL:$1|문서 $1개}}가 있습니다.",
"wlheader-enotif": "이메일 알림 기능이 활성화되었습니다.",
"wlheader-showupdated": "마지막으로 방문한 이후에 바뀐 문서는 '''굵은 글씨'''로 보입니다.",
"wlnote": "$3 $4 기준으로, 아래에 최근 {{PLURAL:$2|한 시간|<strong>$2</strong>시간}} 동안 {{PLURAL:$1|마지막 바뀜이|마지막 바뀜 <strong>$1</strong>개가}} 있습니다.",
"rollbacklinkcount": "{{PLURAL:$1|편집}} $1회 되돌리기",
"rollbacklinkcount-morethan": "{{PLURAL:$1|편집}} $1회 이상 되돌리기",
"rollbackfailed": "되돌리기 실패",
+ "rollback-missingparam": "요청에 필요한 변수가 존재하지 않습니다.",
"cantrollback": "편집을 되돌릴 수 없습니다.\n문서를 편집한 사용자가 한 명뿐입니다.",
"alreadyrolled": "[[:$1]]에서 [[User:$2|$2]] ([[User talk:$2|토론]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]])의 편집을 되돌릴 수 없습니다.\n누군가가 이미 문서를 고치거나 되돌렸습니다.\n\n마지막으로 이 문서를 편집한 사용자는 [[User:$3|$3]] ([[User talk:$3|토론]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]])입니다.",
"editcomment": "편집 요약: <em>$1</em>",
"revertpage": "[[Special:Contributions/$2|$2]]([[User talk:$2|토론]])의 편집을 [[User:$1|$1]]의 마지막 판으로 되돌림",
"revertpage-nouser": "숨긴 사용자의 편집을 {{GENDER:$1|[[User:$1|$1]]}}의 마지막 판으로 되돌림",
"rollback-success": "$1의 편집을 되돌렸습니다.\n$2의 마지막 판으로 바뀌었습니다.",
+ "rollback-success-notify": "$1의 편집을 되돌렸습니다.\n$2의 마지막 판으로 바뀌었습니다. [$3 차이 보기]",
"sessionfailure-title": "세션 실패",
"sessionfailure": "로그인 세션에 문제가 발생한 것 같습니다.\n세션 하이재킹을 막기 위해 동작이 취소되었습니다.\n브라우저의 뒤로 버튼을 누르고 문서를 새로 고침한 후에 다시 시도해 주세요.",
"changecontentmodel": "문서의 콘텐츠 모델을 변경",
"changecontentmodel-success-text": "[[:$1]]의 콘텐츠 종류가 변경되었습니다.",
"changecontentmodel-cannot-convert": "[[:$1]]의 콘텐츠 모델이 $2의 모델로 전환될 수 없습니다.",
"changecontentmodel-nodirectediting": "$1 콘텐츠 모델은 직접 편집을 지원하지 않습니다",
+ "changecontentmodel-emptymodels-title": "이용 가능한 콘텐츠 모델이 없음",
+ "changecontentmodel-emptymodels-text": "[[:$1]]의 콘텐츠가 임의의 종류로 전환될 수 없습니다.",
"log-name-contentmodel": "콘텐츠 모델 변경 기록",
"log-description-contentmodel": "페이지의 콘텐츠 모델과 관련된 행위",
"logentry-contentmodel-new": "$1님이 비 기본값 \"$5\" 콘텐츠 모델을 사용해 $3 문서를 {{GENDER:$2|만들었습니다}}",
"lockdbsuccesstext": "데이터베이스가 잠겼습니다.<br />\n관리가 끝나면 잊지 말고 [[Special:UnlockDB|잠금을 풀어]] 주세요.",
"unlockdbsuccesstext": "데이터베이스 잠금 상태가 해제되었습니다.",
"lockfilenotwritable": "데이터베이스 잠금 파일에 쓰기 권한이 없습니다.\n데이터베이스를 잠그거나 잠금 해제하려면, 웹 서버에서 이 파일의 쓰기 권한을 설정해야 합니다.",
+ "databaselocked": "데이터베이스가 이미 잠겨 있습니다.",
"databasenotlocked": "데이터베이스가 잠겨 있지 않습니다.",
"lockedbyandtime": "({{GENDER:$1|$1}} 사용자가 $2 $3에 잠금)",
"move-page": "$1 이동",
"saturday-at": "토요일 $1",
"sunday-at": "일요일 $1",
"yesterday-at": "어제 $1",
- "bad_image_list": "형식은 아래와 같습니다.\n\n\"*\"로 시작하는 목록의 내용만 적용됩니다.\n매 줄의 첫번째 링크는 부적절한 파일을 가리켜야 합니다.\n같은 줄에 따라오는 모든 링크는 예외로 봅니다. (예: 파일이 사용되어야 하는 문서)",
+ "bad_image_list": "형식은 아래와 같습니다.\n\n\"*\"로 시작하는 목록의 내용만 적용됩니다.\n매 줄의 첫 번째 링크는 부적절한 파일을 가리켜야 합니다.\n같은 줄에 따라오는 모든 링크는 예외로 봅니다. (예: 파일이 사용되어야 하는 문서)",
"variantname-zh-hans": "간체",
"variantname-zh-hant": "번체",
"metadata": "메타데이터",
"confirm-watch-top": "이 문서를 주시문서 목록에 추가할까요?",
"confirm-unwatch-button": "확인",
"confirm-unwatch-top": "이 문서를 주시문서 목록에서 뺄까요?",
+ "confirm-rollback-button": "확인",
+ "confirm-rollback-top": "이 문서의 편집을 되돌리시겠습니까?",
"quotation-marks": "“$1”",
"imgmultipageprev": "← 이전 페이지",
"imgmultipagenext": "다음 페이지 →",
"timezone-local": "로컬",
"duplicate-defaultsort": "<strong>경고:</strong> 기본 정렬 키 \"$2\"가 이전의 기본 정렬 키 \"$1\"를 덮어쓰고 있습니다.",
"duplicate-displaytitle": "<strong>경고:</strong> \"$2\" 제목 표시는 기존의 표시되는 제목 \"$1\"을 덮어씁니다.",
+ "restricted-displaytitle": "<strong>경고:</strong> 표시하려는 제목 \"$1\"은(는) 문서의 실제 제목과 동일하지 않으므로 무시되었습니다.",
"invalid-indicator-name": "<strong>오류:</strong> 문서 상태 표시기의 <code>name</code> 특성은 비어 있지 않아야 합니다.",
"version": "버전",
"version-extensions": "설치된 확장 기능",
"tags-delete-not-found": "\"$1\" 태그가 존재하지 않습니다.",
"tags-delete-too-many-uses": "\"$1\" 태그가 $2개 이상의 판에 적용되어 있으므로 삭제할 수 없습니다.",
"tags-delete-warnings-after-delete": "\"$1\" 태그가 삭제되었으나 다음과 같은 $2개의 경고 태그가 발생하였습니다:",
+ "tags-delete-no-permission": "변경 태그를 삭제할 권한이 없습니다.",
"tags-activate-title": "태그 활성화",
"tags-activate-question": "\"$1\" 태그를 활성화하려고 합니다.",
"tags-activate-reason": "이유:",
"revdelete-unrestricted": "관리자에 대한 제한을 해제함",
"logentry-block-block": "$1님이 {{GENDER:$4|$3}}님을 $5 {{GENDER:$2|차단했습니다}} $6",
"logentry-block-unblock": "$1님이 {{GENDER:$4|$3}} 사용자의 {{GENDER:$2|차단을 해제했습니다}}",
- "logentry-block-reblock": "$1님이 {{GENDER:$4|$3}} 사용자의 차단 기간을 $5 설정으로 {{GENDER:$2|바꾸었습니다}} $6",
+ "logentry-block-reblock": "$1 님이 {{GENDER:$4|$3}} 사용자의 차단 기간을 $5 설정으로 {{GENDER:$2|바꾸었습니다}} $6",
"logentry-suppress-block": "$1님이 {{GENDER:$4|$3}} 사용자를 $5 {{GENDER:$2|차단했습니다}} $6",
- "logentry-suppress-reblock": "$1님이 {{GENDER:$4|$3}} 사용자의 차단 기간을 $5 설정으로 {{GENDER:$2|바꾸었습니다}} $6",
+ "logentry-suppress-reblock": "$1 님이 {{GENDER:$4|$3}} 사용자의 차단 기간을 $5 설정으로 {{GENDER:$2|바꾸었습니다}} $6",
"logentry-import-upload": "$1님이 $3 문서를 파일 올리기로 {{GENDER:$2|가져왔습니다}}",
"logentry-import-upload-details": "$1님이 $3 문서 ({{PLURAL:$4|판}} $4개)를 파일 올리기로 {{GENDER:$2|가져왔습니다}}",
"logentry-import-interwiki": "$1님이 $3 문서를 다른 위키에서 {{GENDER:$2|가져왔습니다}}",
"logentry-protect-protect-cascade": "$1님이 $3 문서를 {{GENDER:$2|보호했습니다}} $4 [연쇄적]",
"logentry-protect-modify": "$1님이 $3 문서의 보호 수준을 {{GENDER:$2|바꾸었습니다}} $4",
"logentry-protect-modify-cascade": "$1님이 $3 문서의 보호 수준을 {{GENDER:$2|바꾸었습니다}} $4 [연쇄적]",
- "logentry-rights-rights": "$1님이 {{GENDER:$6|$3}}을(를) 위해 $3 사용자의 권한을 $4에서 $5(으)로 {{GENDER:$2|바꾸었습니다}}",
+ "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|바꾸었습니다}}",
"logentry-upload-upload": "$1님이 $3 파일을 {{GENDER:$2|올렸습니다}}",
"log-action-filter-suppress-block": "차단을 통한 사용자 숨기기",
"log-action-filter-suppress-reblock": "재차단을 통한 사용자 숨기기",
"log-action-filter-upload-upload": "새로 업로드",
- "log-action-filter-upload-overwrite": "다시 업로드"
+ "log-action-filter-upload-overwrite": "다시 업로드",
+ "authmanager-authn-not-in-progress": "인증이 진행 중이 아니거나 세션 데이터를 분실했습니다. 처음부터 다시 시작해 주십시오.",
+ "authmanager-authn-no-primary": "제공된 자격 증명으로 인증할 수 없습니다.",
+ "authmanager-authn-no-local-user": "자격 증명으로 이 위키의 어느 사용자로도 로그인 할 수 없습니다.",
+ "authmanager-authn-no-local-user-link": "제공된 자격 증명은 유효하지만 이 위키의 어느 사용자와도 연결되어 있지 않습니다. 다른 방식으로 로그인하거나, 새로운 사용자를 생성하면 자격 증명을 계정에 추가할 수 있게 됩니다.",
+ "authmanager-authn-autocreate-failed": "로컬 계정 자동 생성 실패: $1",
+ "authmanager-create-disabled": "계정 만들기가 금지되어 있습니다.",
+ "authmanager-create-from-login": "계정을 만드려면, 아래의 칸들을 채워 주십시오.",
+ "authmanager-create-not-in-progress": "계정 만들기가 진행 중이 아니거나 세션 데이터를 분실했습니다. 처음부터 다시 시작해 주십시오.",
+ "authmanager-create-no-primary": "제공된 자격 증명은 계정 생성에 쓰일 수 없습니다.",
+ "authmanager-link-no-primary": "제공된 자격 증명은 계정을 연결하는 데 쓰일 수 없습니다.",
+ "authmanager-link-not-in-progress": "계정 연결이 진행 중이 아니거나 세션 데이터를 분실했습니다. 처음부터 다시 시작해 주십시오.",
+ "authmanager-authplugin-setpass-failed-title": "비밀번호 변경 실패",
+ "authmanager-authplugin-setpass-failed-message": "인증 플러그인이 비밀번호 변경을 거부했습니다.",
+ "authmanager-authplugin-create-fail": "인증 플러그인이 계정 만들기를 거부했습니다.",
+ "authmanager-authplugin-setpass-denied": "인증 플러그인이 비밀번호 변경을 허용하지 않습니다.",
+ "authmanager-authplugin-setpass-bad-domain": "잘못된 도메인.",
+ "authmanager-autocreate-noperm": "자동 계정 만들기는 허용되지 않습니다.",
+ "authmanager-autocreate-exception": "이전의 오류들로 인해 자동 계정 만들기를 일시적으로 사용할 수 없습니다.",
+ "authmanager-userdoesnotexist": "\"$1\" 사용자 계정은 등록되어 있지 않습니다.",
+ "authmanager-userlogin-remembermypassword-help": "세션 길이보다 더 오랜 시간 비밀번호를 기억할지에 대한 여부",
+ "authmanager-username-help": "인증을 위한 사용자 이름.",
+ "authmanager-password-help": "인증을 위한 비밀번호",
+ "authmanager-domain-help": "외부 인증의 도메인",
+ "authmanager-retype-help": "확인을 위해 암호 다시 입력.",
+ "authmanager-email-label": "이메일",
+ "authmanager-email-help": "이메일 주소",
+ "authmanager-realname-label": "실명",
+ "authmanager-realname-help": "사용자의 실명",
+ "authmanager-provider-password": "비밀번호 기반 인증",
+ "authmanager-provider-password-domain": "비밀번호 및 도메인 기반 인증",
+ "authmanager-provider-temporarypassword": "임시 비밀번호",
+ "authprovider-confirmlink-message": "최근의 로그인 시도를 참고하여 다음의 계정들을 사용자의 위키 계정에 연결할 수 있습니다. 이들을 연결하면 이 계정들을 통해 로그인이 가능해집니다. 연결하고자 하는 대상을 선택해 주십시오.",
+ "authprovider-confirmlink-request-label": "연결할 계정",
+ "authprovider-confirmlink-success-line": "$1: 연결을 성공했습니다.",
+ "authprovider-confirmlink-failed": "계정 연결을 완전히 성공하지 못했습니다: $1",
+ "authprovider-confirmlink-ok-help": "연결 실패 메시지를 보여준 뒤에도 계속합니다.",
+ "authprovider-resetpass-skip-label": "건너뛰기",
+ "authprovider-resetpass-skip-help": "비밀번호 재설정을 건너뜁니다.",
+ "authform-nosession-login": "인증은 성공했으나 사용자의 브라우저가 로그인 상태를 저장하지 못했습니다.\n\n$1",
+ "authform-nosession-signup": "계정은 생성되었으나 사용자의 브라우저가 로그인 상태를 저장하지 못했습니다.\n\n$1",
+ "authform-newtoken": "토큰이 없습니다. $1",
+ "authform-notoken": "토큰이 없습니다",
+ "authform-wrongtoken": "잘못된 토큰",
+ "specialpage-securitylevel-not-allowed-title": "허용하지 않음",
+ "specialpage-securitylevel-not-allowed": "자격을 확인할 수 없으므로 이 페이지를 사용할 수 없습니다.",
+ "authpage-cannot-login": "로그인을 시작할 수 없습니다.",
+ "authpage-cannot-login-continue": "로그인을 계속할 수 없습니다. 사용자 세션의 시간이 초과되었을 가능성이 높습니다.",
+ "authpage-cannot-create": "계정 만들기를 시작할 수 없습니다.",
+ "authpage-cannot-create-continue": "계정 만들기를 계속할 수 없습니다. 사용자 세션의 시간이 초과되었을 가능성이 높습니다.",
+ "authpage-cannot-link": "계정 연결을 시작할 수 없습니다.",
+ "authpage-cannot-link-continue": "계정 연결을 계속할 수 없습니다. 사용자 세션의 시간이 초과되었을 가능성이 높습니다.",
+ "cannotauth-not-allowed-title": "권한이 없음",
+ "cannotauth-not-allowed": "이 문서의 이용을 허용하지 않습니다.",
+ "changecredentials": "자격 증명 수정",
+ "changecredentials-submit": "자격 증명 수정",
+ "changecredentials-invalidsubpage": "$1은 유효한 자격 증명이 아닙니다.",
+ "changecredentials-success": "자격 증명이 변경되었습니다.",
+ "removecredentials": "자격 증명 제거",
+ "removecredentials-submit": "자격 증명 제거",
+ "removecredentials-invalidsubpage": "$1 은(는) 유효한 자격 증명이 아닙니다.",
+ "removecredentials-success": "자격 증명이 제거되었습니다.",
+ "credentialsform-provider": "자격 증명:",
+ "credentialsform-account": "계정 이름:",
+ "cannotlink-no-provider-title": "연결할 수 있는 계정이 없음",
+ "cannotlink-no-provider": "연결할 수 있는 계정이 없습니다.",
+ "linkaccounts": "계정 연결",
+ "linkaccounts-success-text": "계정이 연결되었습니다.",
+ "linkaccounts-submit": "계정 연결",
+ "unlinkaccounts": "계정 연결 해제",
+ "unlinkaccounts-success": "계정의 연결이 해제되었습니다."
}
"noname": "Терс атны джазгъансыз.",
"loginsuccesstitle": "Авторизация тыйыншлы ётдю",
"loginsuccess": "'''Энди {{SITENAME}} сайтха «$1» ат бла кирдигиз.'''",
- "nosuchuser": "$1 аты бла къошулуучу джокъду.\nКъошулуучу атла харифни регистрин (уллу-гитчеликлерин) айырады.\nАтны тюз джазылгъанына къарагъыз неда [[Special:UserLogin/signup|джангы тергеу джазыу (аккаунт) къурагъаз]].",
+ "nosuchuser": "$1 аты бла къошулуучу джокъду.\nКъошулуучу атла харифни регистрин (уллу-гитчеликлерин) айырады.\nАтны тюз джазылгъанына къарагъыз неда [[Special:CreateAccount|джангы тергеу джазыу (аккаунт) къурагъаз]].",
"nosuchusershort": "$1 аты бла къшулуучу джокъду. Атны тюз джазылгъанына къарагъыз.",
"nouserspecified": "Сиз къошулуучу атыгъызны джазаргъа керексиз.",
"login-userblocked": "Бу къошулуучу блокга салыннганды. Кирирге мадары джокъду.",
"accmailtext": "[[User talk:$1|$1]] къошулуучугъа къуралгъан пароль $2 адресине джиберилгенди.\n\nРегистрацияны тындыргъындан сора, ''[[Special:ChangePassword|паролну тюрлендирирге]]'' боллукъсуз.",
"newarticle": "(Джангы)",
"newarticletext": "Сиз джибериу бла алкъын къуралмагъан бетге кёчгенсиз.\nАны къурар ючюн тюбюндеги терезеде статьяны текстин басмалагъыз (толуракъ [$1 ангылатыу бетде] къарагъыз).\nДжангылыб кирген эсегиз а уа бери, браузеригизни '''артха''' тиегин басыгъызда къоюгъуз.",
- "anontalkpagetext": "----''Бу сюзюу бет, тергеу джазыу (аккаунт) къурамагъан неда аны бла хайырланмагъан аноним къошулуучунукъуду.\nАны ючюн идентификация этерге IP-адрес хайырланады.\nТалай башха къошулуучуланы да болургъа боллукъ быллай адреслери.\nСиз аноним къошулуучу эсегиз эмда сизге джиберилмеген билдириуле алама деб суна эсегиз, ангылашылмаула болмаз ючюн [[Special:UserLogin|тергеу джазыу (аккаунт) къурагъыз]] неда [[Special:UserLogin/signup|системагъа киригиз]].''",
+ "anontalkpagetext": "----''Бу сюзюу бет, тергеу джазыу (аккаунт) къурамагъан неда аны бла хайырланмагъан аноним къошулуучунукъуду.\nАны ючюн идентификация этерге IP-адрес хайырланады.\nТалай башха къошулуучуланы да болургъа боллукъ быллай адреслери.\nСиз аноним къошулуучу эсегиз эмда сизге джиберилмеген билдириуле алама деб суна эсегиз, ангылашылмаула болмаз ючюн [[Special:UserLogin|тергеу джазыу (аккаунт) къурагъыз]] неда [[Special:CreateAccount|системагъа киригиз]].''",
"noarticletext": "Бусагъатда бу бетде текст джокъду.\nСиз [[Special:Search/{{PAGENAME}}|бу атны башха статьялада]] излерге , <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} журналлагъа къараргъа], неда '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} быллай атлы джангы бет къураргъа боллукъсуз]'''</span>.",
"noarticletext-nopermission": "Бусагъатда бу бетде текст джокъду.\nСиз [[Special:Search/{{PAGENAME}}|бу атны таныгъан]] башха статьяланы, неда <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} журналлада джазылгъанланы]</span> табаргъа боллукъсуз, алай а бу бетни къураргъа эркинлигигиз джокъду.",
"userpage-userdoesnotexist": "«<nowiki>$1</nowiki>» тергеу джазыу (аккаунт) джокъду. Къураргъа/тюрлендирирге излеймисиз бу бетни?",
"tog-ccmeonemails": "Scheck mer en Kopie, wann ich en <i lang=\"en\">e-mail</i> an ene andere Metmaacher scheck",
"tog-diffonly": "Zeich beim Versione Verjliche nur de Ungerscheide aan (ävver pack nit noch de janze Sigg dodronger)",
"tog-showhiddencats": "Donn de verschtoche Saachjroppe aanzeije",
- "tog-norollbackdiff": "Donn noh „{{int:Rollback}}“ de Ungerscheide nit aanzeije",
+ "tog-norollbackdiff": "Donn noh „{{int:Rollback}}“ de Ongerscheide nit aanzeije",
"tog-useeditwarning": "Donn mesch warne, wann esch vun en Sigg fott jonn, ih dat esch all ming Änderunge avjeschpeischert hann.",
"tog-prefershttps": "Jangk emmer övver en verschlößelte Verbendong bei Enlogge",
"underline-always": "jo, ongershtriishe",
"createacct-reason-ph": "Woröm deihs De noch ene Zohjang aanlääje?",
"createacct-submit": "Lohß Jonn!",
"createacct-another-submit": "Donn jäz enne zohsäzlejje Zohjang aanlääje",
+ "createacct-continue-submit": "Wigger maache mem Aanmällde",
+ "createacct-another-continue-submit": "Wigger maache mem Aanmällde",
"createacct-benefit-heading": "{{ucfirst:{{GRAMMAR:Nominative|{{ucfirst:{{SITENAME}}}}}}}} weed vun Minsche wi Dir jemaat.",
"createacct-benefit-body1": "{{PLURAL:$1|Änderong|Änderonge|Änderonge }}",
"createacct-benefit-body2": "{{PLURAL:$1|Sigg|Sigge|Sigge }}",
"noname": "Dat jeiht nit als ene Metmaacher Name. Jetz muss De et noch ens versöke.",
"loginsuccesstitle": "Enjelogg",
"loginsuccess": "'''Do bes jetz enjelogg {{GRAMMAR:en|{{SITENAME}}}}, un Dinge Name als ene Metmaacher es „$1“.'''",
- "nosuchuser": "Dä Metmaacher Name „$1“ wor verkihrt.\nJroß- un Kleinboochshtabe maache ene Ungerscheid!\n<br />\nJetz muss De et noch ens versöke.\nUdder donn_[[Special:UserLogin/signup|ene neue Metmaacher aanmelde]].",
+ "nosuchuser": "Dä Metmaacher Name „$1“ wor verkihrt.\nJroß- un Kleinboochshtabe maache ene Ungerscheid!\n<br />\nJetz muss De et noch ens versöke.\nUdder donn_[[Special:CreateAccount|ene neue Metmaacher aanmelde]].",
"nosuchusershort": "Dä Metmaacher Name „$1“ wor verkihrt. Jetz muss De et noch ens versöke.",
"nouserspecified": "Dat jeiht nit als ene Metmaacher Name",
"login-userblocked": "Heh dä Kääl es jesperrt. Enlogge verbodde.",
"createacct-another-realname-tip": "Dä reschteje Nahme kam_mer fott lohße.\n\nWann dä aanjejovve es, weet_e jebruch, öm öffentlesch de Schriiver för Beidrääsch ze nänne.",
"pt-login": "Enlogge",
"pt-login-button": "Enlogge",
+ "pt-login-continue-button": "Wigger maache mem Ennlogge",
"pt-createaccount": "Ene neue Zohjang aanmälde",
"pt-userlogout": "Ußlogge",
"php-mail-error-unknown": "Nit bekannte Fähler met dä Funxjohn <code lang=\"en\">mail()</code> vum PHP",
"botpasswords-label-delete": "Fottschmiiße",
"botpasswords-label-resetpassword": "Paßwoot neu säze",
"botpasswords-label-restrictions": "Beschränkonge:",
+ "botpasswords-label-grants-column": "Zohjelohße",
"botpasswords-bad-appid": "„$1“ es keine jölltejje Nahme för ene Bot.",
"botpasswords-insert-failed": "Kunnt keine Bot mem Nahme „$1“ derbei donn. Wohr velleijsch ald doh.",
"botpasswords-update-failed": "Kunnt keine Bot mem Nahme „$1“ veränndere. Es velleijsch fottjeschmeße?",
"botpasswords-deleted-title": "Dat Bot-Paßwood es fott",
"botpasswords-deleted-body": "Dat Bot-Paßwoot för dä Bot „$1“ {{GENDER:$2|vum|vum|vumm Metmaacher|vun dä|vum}} „$2“ wood fott jeschmeße.",
"resetpass_forbidden": "E Passwoot kann nit jeändert wääde.",
+ "resetpass_forbidden-reason": "Paßwööter kam_mer nit änndere: $1",
"resetpass-no-info": "Do mööts ad enjelogg sin, öm tiräk op di Sigg jonn ze dörve",
"resetpass-submit-loggedin": "Passwood tuusche",
"resetpass-submit-cancel": "Nix donn!",
"passwordreset-emailsentemail": "Wann dat en ennjedrahre <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i>-Adräß vun Der es, dann weed en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i> för der Zohjang heh verschek, öm e neu Paßwoot ze krijje.",
"passwordreset-emailsent-capture": "En <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i> met Aanjahbe zom neue Paßwoot för der Zohjang heh es verschek woode. Heh dronger kanns De se lässe.",
"passwordreset-emailerror-capture": "En <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i> met Aanjahbe zom neue Paßwoot för der Zohjang heh sullt verschek wääde, ävver dat Verscheke aan {{GENDER:$2|dä|dat|dä Metmaacher|de|dat}} $2 hät nit jeflup: $1",
+ "passwordreset-invalideamil": "Dat es en onjöltejje Addräß fö de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i>",
"changeemail": "Donn en Adräß för de <i lang=\"en\">e-mail</i> ändere udder fott schmiiße",
"changeemail-header": "Donn heh dat Fommulaa ußfölle, öm Ding Adräß för de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i> ze ändere. Wann De en Adräß loß wähde wells, maach dat Fäld läddesch, ih dat De dat Fommolaa loß scheks.",
"changeemail-passwordrequired": "Do moß Ding Paßwood enjävve, öm di Änderong ze beschtähteje.",
"accmailtext": "En automattesch un zofällesch neu ußjewörfelt Passwood för dä\nMetmaacher „[[User talk:$1|$1]]“ es noh „$2“ jescheck woode.\n\nDat Passwoot för dä neue Zojang kanns De op dä {{int:Specialpage}} zom\n„[[Special:ChangePassword|{{int:resetpass}}]]“ ändere,\nwann De wider enjelogg bes.",
"newarticle": "(Neu)",
"newarticletext": "Ene Link op en Sigg, wo noch nix drop steiht, weil et se noch jar nit jitt, hät Dich noh heh jebraht.\nÖm di Sigg aanzelähje, schriev heh unge en dat Feld eren, un dun dat dann avspeichere.\nLuur op de [$1 Sigge met Hölp] noh, wann De mih doh drövver weßße wells.\nWann De jar nit heh hen kumme wollts, dann jangk zeröck op di Sigg, wo De herjekumme bes, Dinge Brauser hät ene Knopp doför.",
- "anontalkpagetext": "----\n<i>Dat heh es de Klaaf Sigg för ene namenlose Metmaacher. Dä hät sich noch keine Metmaacher Name jejovve un\nenjerich, ov deit keine bruche. Dröm bruche mer sing IP Adress öm It oder In en uns Lisste fasszehalde.\nSu en IP Adress kann vun janz vill Metmaacher jebruch wääde, un eine Metmaacher kann janz flöck\nzwesche de ungerscheidlichste IP Adresse wähßele, womöchlich ohne dat hä et merk. Wann Do jetz ene namenlose\nMetmaacher bes, un fings, dat heh Saache an Dich jeschrevve wääde, wo Do jar nix met am Hot häs, dann bes Do\nwahrscheinlich och nit jemeint. Denk villeich ens drüvver noh, datte Dich [[Special:UserLogin/signup|anmelde]] deis,\ndomet De dann donoh nit mieh met esu en Ömständ ze dun häs, wie de andere namenlose Metmaacher heh. Wann de aanjemelldt bes un deis [[Special:UserLogin|enlogge]], dann kam_mer Desch och fun alle andere Metmaacher ongerschejde.</i>",
+ "anontalkpagetext": "----\n<i>Dat heh es de Klaaf Sigg för ene namenlose Metmaacher. Dä hät sich noch keine Metmaacher Name jejovve un\nenjerich, ov deit keine bruche. Dröm bruche mer sing IP Adress öm It oder In en uns Lisste fasszehalde.\nSu en IP Adress kann vun janz vill Metmaacher jebruch wääde, un eine Metmaacher kann janz flöck\nzwesche de ungerscheidlichste IP Adresse wähßele, womöchlich ohne dat hä et merk. Wann Do jetz ene namenlose\nMetmaacher bes, un fings, dat heh Saache an Dich jeschrevve wääde, wo Do jar nix met am Hot häs, dann bes Do\nwahrscheinlich och nit jemeint. Denk villeich ens drüvver noh, datte Dich [[Special:CreateAccount|anmelde]] deis,\ndomet De dann donoh nit mieh met esu en Ömständ ze dun häs, wie de andere namenlose Metmaacher heh. Wann de aanjemelldt bes un deis [[Special:UserLogin|enlogge]], dann kam_mer Desch och fun alle andere Metmaacher ongerschejde.</i>",
"noarticletext": "<span class=\"plainlinks\">Em Momang es keine Täx op heh dä Sigg. Jangk en de Täxte vun ander Sigge [[Special:Search/{{PAGENAME}}|noh däm Titel söhke]], udder [{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} donn en de Logböscher donoh loore], udder [{{FULLURL:{{FULLPAGENAME}}|action=edit}} fang di Sigg aan] ze schrieve, udder jangk zeröck woh De heer kohms. Do hät Dinge Brauser ene Knopp för.</span>",
"noarticletext-nopermission": "Op dä Sigg es em Momang nix drop.\nDo kanns noh däm Tittel vun heh dä Sigg [[Special:Search/{{PAGENAME}}|em Tex op ander Sigge söhke]],\nudder en dä zopaß <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Logbööscher nohloore]</span>.",
"missing-revision": "En Version $1 vun dä Sigg „{{FULLPAGENAME}}“ jidd_et nit.\n\nEsu jät kütt för jewöhnlesch, wam_mer enem övverhollte Lengk ob en Sigg follesch, di zweschedren fottjeschmeße woode es.\nMih doh drövver fengk mer em [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Logbooch vum Sigge Fottschmiiße].",
"parser-template-recursion-depth-warning": "Schablohne rohfe sesch zo öff sellver op ($1)",
"language-converter-depth-warning": "Zoh vill Verschachtelonge (övver $1) beim Täx-Ömwandelle vun eine Schprohch udder Schrevv en en anndere.",
"node-count-exceeded-category": "Sigge, woh dä <i lang=\"en\" xml:lang=\"en\">node-count</i> övverschredde es",
- "node-count-exceeded-category-desc": "Di Sigg hät dä \"node-count\" övverschredde.",
- "node-count-exceeded-warning": "Heh di Sigg hät dä \"node-count\" övverschredde",
- "expansion-depth-exceeded-category": "Sigge, woh de \"expansion depth\" övverschredde es",
- "expansion-depth-exceeded-category-desc": "Dat heh es de Saachjropp för Sigge, woh de \"expansion depth\" övverschreddde es.",
- "expansion-depth-exceeded-warning": "Heh di Sigg hät de \"expansion depth\" övverschredde",
+ "node-count-exceeded-category-desc": "Di Sigg hät dä <i lang=\"en\" xml:lang=\"en\">node-count</i> övverschredde.",
+ "node-count-exceeded-warning": "Heh di Sigg hät dä <i lang=\"en\" xml:lang=\"en\">node-count</i> övverschredde",
+ "expansion-depth-exceeded-category": "Sigge, woh zoh vill automattesch ennjeföhsch weed",
+ "expansion-depth-exceeded-category-desc": "Dat heh es de Saachjropp för Sigge, woh zoh vill automattesch ennjeföhsch weed.",
+ "expansion-depth-exceeded-warning": "En heh di Sigg weed zoh vill automattesch ennjeföhsch.",
"parser-unstrip-loop-warning": "Ene Befähl em Täx betrek sesch op sesch sällefs.",
"parser-unstrip-recursion-limit": "Ene Befähl em Täx es mieh wi {{PLURAL:$1|eijmohl|$1 Mohl|jaa nit}} met sesch sellef verschachtelt.",
"converter-manual-rule-error": "Doh es ene Fähler en ene händesche Önwandelongsrääjel zwesche de Schprohche.",
"mergehistory-empty": "Mer han kei Versione för zesammezeläje",
"mergehistory-done": "{{PLURAL:$3|Ein Väsjohn es|$3 Väsjohn sen|Kei Väsjohn wood}} fun „$1“ noh „[[:$2]]“ övverdraare un domet zosamme jelaat.",
"mergehistory-fail": "Dat Versione zesamme läje is nit müjjelisch. Don ens di Sigge un de Zigge pröfe!",
+ "mergehistory-fail-bad-timestamp": "Dattom odder Zigg udder beeds sin nit jöltesch",
+ "mergehistory-fail-invalid-source": "De Quällesigg es nit jöltesch",
+ "mergehistory-fail-invalid-dest": "De Zihlsigg es nit jöltesch",
+ "mergehistory-fail-permission": "Kein Berääschtejong, de vörreje Väsjohne zesamme ze lähle.",
"mergehistory-fail-self-merge": "De Quell-Sigg un de Ziel-Sigg sin deselve Sigg.",
+ "mergehistory-fail-timestamps-overlap": "De Väjsohne vun de Quällesigg kumme övverkrüz udder noh de Väsjohne vun de Zihlsigg.",
"mergehistory-fail-toobig": "Mih wi {{PLURAL:$1|ein Väsjohn|$1 Väsjohne|kein Väsjohne}} wöödte zesamme jelaat. Esu vill künne mer nit, un maache mer nit.",
"mergehistory-no-source": "En Ursprungssigg „$1“ jidd_et nit.",
"mergehistory-no-destination": "En Zielsigg „$1“ jidd_et nit.",
"right-createpage": "Neu Sigge, ävver kein Klaafsigge, aanlääje",
"right-createtalk": "Neu Klaafsigge, ävver kein nomaale Sigge, aanlääje",
"right-createaccount": "Ene neue Metmaacher endraage lohße",
+ "right-autocreateaccount": "Automeattesch med enem Zohjang vun ußerhallev enlogge",
"right-minoredit": "Eije Änderong als klein Mini-Änderong makkehre",
"right-move": "Sigge ömnenne",
"right-move-subpages": "Sigge, un ier Ungersigge, zosamme ömnenne",
"right-override-export-depth": "Beim Sigge Expoteere de Sigge metnämme, woh Lingks drop jon — beß fönef Schredde wigk",
"right-sendemail": "<i lang=\"en\">e-mail</i> aan ander Metmaacher schecke",
"right-passwordreset": "De <i lang=\"en\">e-mails</i> vum Paßwoot neu Säze aanloore",
- "right-managechangetags": "[[Special:Tags|Kännzeijsche]] en de Dahtebangk aanlähje udder fottschmiiße",
+ "right-managechangetags": "[[Special:Tags|Kännzeijsche]] aanlähje udder ußschallde",
"right-applychangetags": "[[Special:Tags|Makehronge]] met de eije Änderonge zersamme verjävve",
"right-changetags": "[[Special:Tags|Makehronge]] vun Väsjohne un Enndrähsche em Logbohch fott nämme un zohföhje",
+ "right-deletechangetags": "[[Special:Tags|Kännzeijsche]] uß de Dahtebangk fott schmihße",
+ "grant-generic": "Rääschte \"$1\"",
"grant-group-page-interaction": "Met Sigge ömjonn",
"grant-group-file-interaction": "Met Mehdeje_Datteije ömjonn",
"grant-group-watchlist-interaction": "Met de eije Oppaßless ömjonn",
"grant-sendemail": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mails</i> aan ander Metmaacher schecke",
"grant-uploadeditmovefile": "Datteije uhlahde, ußtuusche un ömbenänne",
"grant-uploadfile": "Neu datteije huhlahde",
+ "grant-basic": "Jrondlähje Rääsch",
"grant-viewdeleted": "Fottjeschmeße Dahte un Sigge belohre",
"grant-viewmywatchlist": "De eije Oppaßleß ze belooere",
"newuserlogpage": "Logbohch för neu Metmaachere",
"action-createpage": "di Sigg aanzeläje",
"action-createtalk": "Klaafsigge aanzeläje",
"action-createaccount": "hee dä neue Metmaacher aanzemelde",
+ "action-autocreateaccount": "automattesch heh dä Metmaacher vun Ußerhallf aanzelähje",
"action-history": "de Leß met de fröhjere Väsohne vun heh dä Sigg ze belohre",
"action-minoredit": "heh di Änderong als klein „mini“ ze makkehre",
"action-move": "di Sigg ömzebenänne",
"action-viewmyprivateinfo": "de eije päsöhnlesche Aanjahbe ze belooere",
"action-editmyprivateinfo": "Ding päsöhnlesche Aanjahbe ze ändere",
"action-editcontentmodel": "et Modäll vum Ennhald vun Sigge ze verändere",
- "action-managechangetags": "Kännzeijsche en de Dahtebangk aanlähje udder fottschmiiße",
+ "action-managechangetags": "Kännzeijsche en de Dahtebangk aanlähje udder ußschallde",
"action-applychangetags": "Makehronge met de eije Änderonge zersamme ze verjävve",
"action-changetags": "Makehronge vun Väsjohne un Enndrähsche em Logbohch fott nämme un zohföhje",
+ "action-deletechangetags": "Kännzeijsche uß de Dahtebangk fottschmiiße",
"nchanges": "{{PLURAL:$1|Ein Änderong|$1 Änderonge|Kein Änderong}}",
"enhancedrc-since-last-visit": "{{PLURAL:$1|Ein|$1|Kein}} zigg_em läzde Aanloore",
"enhancedrc-history": "Väsjohne",
"upload-form-label-infoform-description": "Äkliehrong",
"upload-form-label-usage-title": "Der Jebruch",
"upload-form-label-usage-filename": "Dä Dattei iehre Nahme",
- "upload-form-label-own-work": "dat es ming eije Wärk",
+ "upload-form-label-own-work": "Dat es ming eije Wärk",
"upload-form-label-infoform-categories": "Saachjroppe",
"upload-form-label-infoform-date": "Dattum",
- "upload-form-label-not-own-work-message-local": "Wann De di Dattei nit en de jemeinsamme Sammlong vun Datteule huh lahde kanns un derbei de Rähjelle {{ucfirst:{{GRAMMAR:vun|{{ucfirst:{{SITENAME}}}}}}}} ennhalde, dann maach heh nit wigger, un probehr ene anndere Wähsch.",
- "upload-form-label-not-own-work-local-local": "Do künnts edd och ens met dä [[Special:Upload|Schtandatt-Sigg zom Huhlahde]] versöhke welle.",
- "upload-form-label-own-work-message-default": "Esch verschtonn, dadd esch en en jemeinsamme Sammlong huh aam lahde ben un dadd sesch dat met dä Bedengonge un de Lezänzbedengonge heh verdräht.",
- "upload-form-label-not-own-work-message-default": "Wann De di Dattei nit en de jemeinsamme Sammlong vun Datteule huh lahde kanns un derbei de Rähjelle ennhalde, dann maach heh nit wigger, un probehr ene anndere Wähsch.",
- "upload-form-label-not-own-work-local-default": "Wann dat noh dä Rähjelle doh jeiht, kanns De och probehre, [[Special:Upload|di Dattei {{GRAMMAR:em|{{ucfirst:{{SITENAME}}}}}} huhzelahde]]",
+ "upload-form-label-not-own-work-message-generic-local": "Wann De di Dattei nit en de jemeinsamme Sammlong vun Datteule huh lahde kanns un derbei och de Rähjelle {{GRAMMAR:vun|{{ucfirst:{{SITENAME}}}}}} ennhalde, dann maach heh nit wigger, un probehr ene anndere Wähsch.",
+ "upload-form-label-not-own-work-local-generic-local": "Do künnts edd och ens met dä [[Special:Upload|Schtandatt-Sigg zom Huhlahde]] versöhke welle.",
+ "upload-form-label-own-work-message-generic-foreign": "Esch verschtonn, dadd esch en en jemeinsamme Sammlong huh aam lahde ben un dadd sesch dat met dä Bedengonge un de Lezänzbedengonge heh verdräht.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Wann De di Dattei nit en de jemeinsamme Sammlong vun Datteije huh lahde kanns un derbei de Rähjelle ennhalde, dann maach heh nit wigger, un probehr ene anndere Wähsch.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Wann dat noh dä Rähjelle doh jeiht, kanns De och probehre, [[Special:Upload|di Dattei {{GRAMMAR:em|{{ucfirst:{{SITENAME}}}}}} huhzelahde]]",
"backend-fail-stream": "Mer kunnte di Dattei $1 nit övverdraare.",
"backend-fail-backup": "Mer kunnte kein Sescherongskopih vun dä Dattei $1 maache.",
"backend-fail-notexists": "En Dattei $1 jidd et nit.",
"apisandbox-jsonly": "Der ohne JavaSkrepp kam_mer de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> för zom erömprobehre nit bruche.",
"apisandbox-api-disabled": "Dat <i lang=\"en\">API</i> es en heh dämm Wiki afjeschalldt.",
"apisandbox-intro": "Op heh dä Sigg kanns De met dä <strong>MediaWiki web service <i lang=\"en\">API</i></strong> eröm schpelle.\nBeloor Der de Einzelheite, wi di jebruch weed, op dä iere [[mw:API:Main_page Sigg met de Verklieronge]].\nE Beiscpell: [//www.mediawiki.org/wiki/API#A_simple_example De Houpsigg holle].\nSöhk ene {{int:Apisb-label-action}} uß, öm mieh Beishpell aanjezeisch ze krijje.\nOch wann dat heh nor zom Ußprobeere es, kann dat, wat De heh mähß, et Wiki verändere.",
+ "apisandbox-unfullscreen": "Sigg aanzeije",
"apisandbox-submit": "Lohß jonn!",
"apisandbox-reset": "Läddesch maache",
"apisandbox-retry": "Norr_ens versöhke",
+ "apisandbox-helpurls": "Lengks för Hölp",
"apisandbox-examples": "Bäijshpelle",
"apisandbox-dynamic-parameters": "Zohsäzlejje Parrameetere",
- "apisandbox-results": "Erus jekumme es",
+ "apisandbox-dynamic-parameters-add-label": "Alle Parrammeetere:",
+ "apisandbox-dynamic-parameters-add-placeholder": "Däm Parramehter singe Nahme",
+ "apisandbox-dynamic-error-exists": "Ne Parramehter mem Nahme „$1“ ham_mer ald.",
+ "apisandbox-deprecated-parameters": "Övverhollte Parramehtere",
+ "apisandbox-submit-invalid-fields-title": "Paa Flder sin nit jöltesch",
+ "apisandbox-results": "Erus jekumme:",
"apisandbox-request-url-label": "Dä <i lang=\"en\">URL</i> vun dä Aanfrooch:",
"apisandbox-request-time": "De Zigg vum Afroof: $1",
"booksources": "Böcher",
"whatlinkshere-hideredirs": "de Ömleijdonge $1",
"whatlinkshere-hidetrans": "de Oproofe $1",
"whatlinkshere-hidelinks": "de nommahle Lengks $1",
- "whatlinkshere-hideimages": "$1 de Lengks op Datteihje",
+ "whatlinkshere-hideimages": "de Lengks op Datteihje $1",
"whatlinkshere-filters": "Ußsööke",
"whatlinkshere-submit": "Lohß jonn!",
"autoblockid": "Automattesche Sperr Nommer $1",
"confirm-watch-top": "Sulle mer di Sigg en Ding Oppaßleß opnämme?",
"confirm-unwatch-button": "Lohß Jonn!",
"confirm-unwatch-top": "Sulle mer di Sigg uß Dinger Oppaßleß erußnämme?",
+ "confirm-rollback-button": "Lohß Jonn!",
"semicolon-separator": ";",
"word-separator": " ",
"ellipsis": " …",
"searchsuggest-containing": "dren änthallde…",
"api-error-badaccess-groups": "Do häs nit et Rääsch, Datteije en heh dat Wiki huhzelaade.",
"api-error-badtoken": "Fähler: et Kännzeijsche (<i lang=\"en\">token</i>) es kappott.",
+ "api-error-blocked": "Do bes föh et Änndere jeschpächt.",
"api-error-copyuploaddisabled": "Et Huhlaade vun enem <i lang=\"en\">URL</i> es op däm ẞööver heh nit zohjelohße.",
"api-error-duplicate": "Mer han em Wiki ald {{PLURAL:$1|[en Dattei]|[$1 andere Datteije]|[kein Dattei]}} mem akeraat sellve Enhalldt.",
"api-error-duplicate-archive": "Mer hatte {{PLURAL:$1|[en ander Dattei]|[ander Datteije]|[kein ander Dattei]}} heh em Wiki mem sellve Enhalt, ävver se {{PLURAL:$1|es|sen|es}} ald fottjeschmeße woode.",
"api-error-overwrite": "En Dattei ze övverschrieve es nit zohjelohße.",
"api-error-stashfailed": "Fähler: Dä ẞööver hät kein Datteije zweschejeschpeischert.",
"api-error-publishfailed": "Ene Fähler es em ẞööver opjetrodde. En zweschejescheischerte Dattei kunnt nit öffentlesch jemaat wääde.",
- "api-error-stasherror": "Ene Fähler es opjetrodde, wi mer di Dattei en der \"stash\" huh aam lahde wohre.",
- "api-error-stashedfilenotfound": "Di Dattei wohd em \"stash\" nit jefonge, wi mer se vun doh huh lahde wullte.",
- "api-error-stashpathinvalid": "Di Dattei wohd em \"stash\" nit jefonge, weil dä Pad do hen nit jeschtemmp hät.",
- "api-error-stashfilestorage": "Ene Fähler es opjetrodd, wi mer di Dattei en der \"stash\" donn wullte.",
- "api-error-stashzerolength": "Dä ẞööver kunnt di Dattei nit en der \"stash\" donn, weil en dä Dattei nix dren schtund.",
- "api-error-stashnotloggedin": "Do moß enjelogg sin, öm en Dattei en der \"stash\" huh ze lahde.",
- "api-error-stashwrongowner": "Di Dattei em \"stash\" woh De draan wells, jehürt Der nit.",
- "api-error-stashnosuchfilekey": "Di Dattei em \"stash\" woh De draan wells, jidd_et nit.",
+ "api-error-stasherror": "Ene Fähler es opjetrodde, wi mer di Dattei en der Bunker huh aam lahde wohre.",
+ "api-error-stashedfilenotfound": "Di Dattei wohd em Bunker nit jefonge, wi mer se vun doh huh lahde wullte.",
+ "api-error-stashpathinvalid": "Di Dattei wohd em Bunker nit jefonge, weil dä Pad do hen nit jeschtemmp hät.",
+ "api-error-stashfilestorage": "Ene Fähler es opjetrodd, wi mer di Dattei en der Bunker donn wullte.",
+ "api-error-stashzerolength": "Dä ẞööver kunnt di Dattei nit en der Bunker donn, weil en dä Dattei nix dren schtund.",
+ "api-error-stashnotloggedin": "Do moß enjelogg sin, öm huhjelahde Datteije en der Bunker ze donn.",
+ "api-error-stashwrongowner": "Di Dattei em Bunker woh De draan wells, di jehürt Der nit.",
+ "api-error-stashnosuchfilekey": "Dä Schlößel fö_di Dattei, woh De draan wells, em Bunker, di jidd_et nit.",
"api-error-timeout": "Dä ẞööver hät en dä jewennde Zick nit jeantwoot.",
"api-error-unclassified": "Ene Fähler es opjetrodde, der mer nit kenne.",
"api-error-unknown-code": "Nit bekannte Fähler: „$1“",
"mw-widgets-titleinput-description-redirect": "ömleijde op „$1“",
"api-error-blacklisted": "Söhk Der ene anndere Nahme uß, dä mih drövver säht.",
"randomrootpage": "Zofällige Aanfangs-Sigg",
- "log-action-filter-delete-delete": "En Sigg wohd fott jeschmeße"
+ "log-action-filter-delete-delete": "En Sigg wohd fott jeschmeße",
+ "authmanager-authplugin-setpass-failed-title": "Dat Paßwoot ze änndere hät nit jeflupp",
+ "authmanager-userdoesnotexist": "Ene Metmaacher mem Nahme „$1“ es nit ennjedrahre.",
+ "authmanager-domain-help": "De Domäijn för de Zohjangsdaht vun ußerhallef beschtähtech ze krijje.",
+ "authmanager-email-label": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i>",
+ "authmanager-email-help": "De Addräß för de <i lang=\"en\">e-mail</i>",
+ "authmanager-realname-label": "Der „reeschteje“ Nahme",
+ "authmanager-provider-temporarypassword": "Zweschepasswood:",
+ "authprovider-resetpass-skip-label": "Övverjonn",
+ "specialpage-securitylevel-not-allowed-title": "Nit zohjelohße",
+ "cannotauth-not-allowed-title": "Zohjang verbodde.",
+ "changecredentials-submit": "Ändere",
+ "changecredentials-submit-cancel": "Ophüre",
+ "removecredentials-submit": "Fott nämme",
+ "removecredentials-submit-cancel": "Ophüre"
}
"Bikarhêner",
"Uygar",
"MikaelF",
- "Macofe"
+ "Macofe",
+ "Matma Rex"
]
},
"tog-underline": "Xetekê di bin girêdanê de çêke:",
"tog-editsectiononrightclick": "Beşekê bi rast-klîkekê biguherîne",
"tog-watchcreations": "Rûpelên min çêkirin û dosyeyên min barkirin, têxe nav lîsteya min a şopandinê",
"tog-watchdefault": "Rûpelên min guhertin û dosyeyên min barkirin, têxe nav lîsteya min a şopandinê",
- "tog-watchmoves": "Rûpelên min navê wan guhertin, têxe nav lîsteya min a şopandinê",
+ "tog-watchmoves": "Rûpel û dosyeyên ku ez navên wan diguherînim, têxe nav lîsteya min a şopandinê",
"tog-watchdeletion": "Rûpel û dosyeyên min jêbirin, têxe nav lîsteya min a şopandinê",
"tog-minordefault": "Her guhertinekê weke guhertineke biçûk nîşan bide",
"tog-previewontop": "Pêşdîtina gotarê li jorî cihê guherandinê nîşan bide",
"actionthrottled": "Hejmara guherandinên hatine hesibandin",
"actionthrottledtext": "Te ev tişt di demeke gelekî kin de kir. Ji kerema xwe çend xulekan bisekine û carekî din biceribîne.",
"protectedpagetext": "Ev rûpel ji bo guhertin û karên din ne kirin hatiye parastin.",
- "viewsourcetext": "Tu dikarî li çavkaniya vê rûpelê binêrî û wê kopî bikî:",
+ "viewsourcetext": "Tu dikarî li çavkaniya vê rûpelê binêrî û wê kopî bikî.",
"viewyourtext": "Hûn çavkaniyê <strong>guhertinê xwe</strong> yê di vê rûpelê de dikarin bibînin û kopî bikin:",
"protectedinterface": "Di vê rûpelê de nivîsandin ji bo navrû(interface)yî zimanan yê vê nivîsbariyê ye û ew tê parastin ku vandalîzm li vê derê çênebe.\nBo lêzêdekirin an jî guherandina wergerên bo hemû wîkiyan ji kerema xwe re mehelîkirina Mediawîkiyê [//translatewiki.net/ translatewiki.net]'ê bi kar bîne.",
"editinginterface": "'''Hişyarî:''' Tu rûpelekê a ku di Wîkîpediya de ji bo sîstemê girîng e, diguherînî. Guherandinên di vê rûpelê de wê ji aliyê hemû bikarhêneran ve werin dîtin. Ji bo wergerê ji kerema xwe di [//translatewiki.net/wiki/Main_Page?setlang=ku-latn translatewiki.net] de bixebite, projeya MediaWiki.",
"newpassword": "Şîfreya nû",
"retypenew": "Şîfreya nû careke din binîvîse",
"resetpass_submit": "Şîfreyê pêkbîne û têkeve",
- "changepassword-success": "Guhertine şîfreya te serkeftî bû!",
+ "changepassword-success": "Şîfreya te hate guhertandin!",
"botpasswords-label-appid": "Navê bot:",
"botpasswords-label-create": "Çêke",
"botpasswords-label-update": "Rojane bike",
"passwordreset-emailtitle": "Hûragahiyên hesab li ser {{SITENAME}}",
"passwordreset-emailelement": "Navê bikarhêner:\n$1\n\nŞîfreya niha:\n$2",
"passwordreset-emailsentemail": "E-nameyeke bibîrxistinê hate şandin.",
+ "passwordreset-invalideamil": "Navnîşana enameyê ya nederbasdar",
"changeemail": "Navnîşana enameya xwe biguherîne an rabike",
"changeemail-oldemail": "Navnîşana e-nameya niha:",
"changeemail-newemail": "Navnîşana e-nameya nû:",
"accmailtext": "Şîfreyekê ketober ê ji bo [[User talk:$1|$1]] hatiye çêkirin ji navnîşana $2 re hat şandin. Şîfreya ji bo vê hesabê nû, piştî ko te têket ji beşa <em>[[Special:ChangePassword|şîfreyê biguherîne]]</em> dikare were guhertin.",
"newarticle": "(Nû)",
"newarticletext": "Ev rûpel hîn tune. Eger tu bixwazî vê rûpelê çêkî, dest bi nivîsandinê bike û piştre qeyd bike. '''Wêrek be''', biceribîne!<br />\nJi bo alîkariyê binêre: [$1 Alîkarî].<br />\nHeke tu bi şaşîtî hatî, bizîvire rûpela berê.",
- "anontalkpagetext": "----''Ev rûpela gotûbêjê ye ji bo bikarhênerên nediyarkirî ku hîn hesabekî xwe çênekirine an jî bikarnaînin. Ji ber vê yekê divê em wan bi navnîşana IP ya hejmarî nîşan bikin. Navnîşaneke IP dikare ji aliyê gelek kesan ve were bikaranîn. Heger tu bikarhênerekî nediyarkirî bî û bawerdikî ku nirxandinên bê peywend di der barê te de hatine kirin ji kerema xwe re [[Special:UserLogin/signup|hesabekî xwe veke an jî têkeve]] da ku tu xwe ji tevlîheviyên bi bikarhênerên din re biparêzî.''",
+ "anontalkpagetext": "----''Ev rûpela gotûbêjê ye ji bo bikarhênerên nediyarkirî ku hîn hesabekî xwe çênekirine an jî bikarnaînin. Ji ber vê yekê divê em wan bi navnîşana IP ya hejmarî nîşan bikin. Navnîşaneke IP dikare ji aliyê gelek kesan ve were bikaranîn. Heger tu bikarhênerekî nediyarkirî bî û bawerdikî ku nirxandinên bê peywend di der barê te de hatine kirin ji kerema xwe re [[Special:CreateAccount|hesabekî xwe veke an jî têkeve]] da ku tu xwe ji tevlîheviyên bi bikarhênerên din re biparêzî.''",
"noarticletext": "Ev rûpel niha vala ye, tu dikarî [[Special:Search/{{PAGENAME}}|Di nav gotarên din de li \"{{PAGENAME}}\" bigerî]] an jî [{{fullurl:{{FULLPAGENAME}}|action=edit}} vê rûpelê biguherînî].",
"noarticletext-nopermission": "Ev rûpel niha vala ye. \nTu dikarî [[Special:Search/{{PAGENAME}}|Di nav gotarên din de li \"{{PAGENAME}}\" bigere]] \nan <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} vê rûpelê biguherînî]</span>, lê ji bo çêkirina vê rûpelê desthilatdariya te tine ye.",
"userpage-userdoesnotexist": "Hesabê bikarhêneran \"<nowiki>$1</nowiki>\" nehatiye qeydkirin. Heke tu bixwazî vê rûpelê çêkî/biguherînî ji kerema xwe lê binêre.",
"postedit-confirmation-restored": "Ev rûpel hate restorekirin.",
"postedit-confirmation-saved": "Guhertina te hate tomarkirin.",
"edit-already-exists": "Nikarî rûpeleka nuh çêke.\nEw berê heye.",
+ "defaultmessagetext": "Nivîsa peyamê ya standart",
"invalid-content-data": "Daneyên naverokê yên nederbasdar",
"content-model-wikitext": "wîkînivîs",
"content-model-text": "nivîsê sade",
"right-sendemail": "Ji bikarhênerên di re ename bişîne",
"grant-editpage": "Rûpelên ku hene biguherîne",
"grant-editprotected": "Rûpelên parastî bigûherîne",
+ "grant-basic": "Mafên bingehîn",
"newuserlogpage": "Çêkirina hesabê nû",
"newuserlogpagetext": "Ev têketina hesabên bikarhêneriyê ye ên ku nû hatine afirandin.",
"rightslog": "Guhertina mafê bikarhêneriyê",
"listusers-noresult": "Bikarhêner nehate dîtin.",
"listusers-blocked": "(hate astengkirin)",
"activeusers": "Lîsteya bikarhênerên çalak",
+ "activeusers-from": "Li bikarhênerên bi vê dest pê dikin bigere:",
"activeusers-hidebots": "Bot'an veşêre",
"activeusers-hidesysops": "Rêveberan veşêre",
"activeusers-noresult": "Tu bikarhêner nehate dîtin.",
"unblocklink": "astengkirinê rake",
"change-blocklink": "Astengkirinê biguherîne",
"contribslink": "beşdarî",
- "emaillink": "e-name bişîne",
+ "emaillink": "e-nameyê bişîne",
"autoblocker": "Otomatîk hate astengkirin ji ber ku IP'ya wê û ya \"[[User:$1|$1]]\" yek in. Sedem: \"''$2''\"",
"blocklogpage": "Astengkirina têketinê",
"blocklogentry": "\"[[$1]]\" ji bo dema $2, $3 asteng kir",
"tooltip-feed-rss": "RSS feed'ên ji bo rûpelê",
"tooltip-feed-atom": "Atom feed'ên ji bo vê rûpelê",
"tooltip-t-contributions": "Lîsteyekî beşdariyên {{GENDER:$1|vê bikarhênerê}} bibîne",
- "tooltip-t-emailuser": "Jê re name bişîne",
+ "tooltip-t-emailuser": "Jê {{GENDER:$1|vî bikarhênerî}}re peyamê bişîne",
"tooltip-t-info": "Bêhtir agahî di derbarê vê rûpelê de",
"tooltip-t-upload": "Dosyeyan bar bike",
"tooltip-t-specialpages": "Lîsteya hemû rûpelên taybetî",
"confirm-purge-top": "Bîra vê rûpelê jêbîbe ?",
"confirm-watch-button": "Temam",
"confirm-unwatch-button": "Baş e",
+ "confirm-rollback-button": "Baş e",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← rûpela berî vê",
"imgmultipagenext": "rûpela din →",
"mw-widgets-titleinput-description-new-page": "rûpel hê tune ye",
"mw-widgets-titleinput-description-redirect": "beralî bike ber bi $1 ve",
"log-action-filter-all": "Hemû",
- "log-action-filter-block-block": "Asteng bike"
+ "log-action-filter-block-block": "Asteng bike",
+ "authmanager-email-label": "E-name",
+ "authmanager-email-help": "Navnîşana e-nameyê"
}
"noname": "Сиз колдонуучунун анык атын көрсөткөн жоксуз.",
"loginsuccesstitle": "Сиз ийгиликтүү кирдиңиз",
"loginsuccess": "'''Сиз азыр {{SITENAME}} сайтына \"$1\" болуп кирдиңиз.'''",
- "nosuchuser": "\"$1\" аттуу колдонуучу катталган эмес.\nКолдонуучун аты регистирди айырмалайт.\nКатасын текшериңиз же [[Special:UserLogin/signup|жаңы эсеп түзүү]]",
+ "nosuchuser": "\"$1\" аттуу колдонуучу катталган эмес.\nКолдонуучун аты регистирди айырмалайт.\nКатасын текшериңиз же [[Special:CreateAccount|жаңы эсеп түзүү]]",
"nosuchusershort": "\"$1\" аттуу колдонуучу жок.\nЖазылышын текшериңиз.",
"nouserspecified": "Сиз колдонуучу атын көрсөтүшүңүз керек.",
"login-userblocked": "Бул колдонуучу бөгөттөлгөн. Системага кирүүгө уруксат жок.",
"noname": "Nomen usoris ratum non designavisti.",
"loginsuccesstitle": "Nomen feliciter datum est",
"loginsuccess": "'''Apud {{grammar:accusative|{{SITENAME}}}} agnosceris nomine \"$1\".'''",
- "nosuchuser": "Nomen \"$1\" ignoratur.\nIn nominibus interest litterarum aut maiuscularum aut minuscularum!\nQuarum cura rationem habeas aut [[Special:UserLogin/signup|novum nomen tibi da]].",
+ "nosuchuser": "Nomen \"$1\" ignoratur.\nIn nominibus interest litterarum aut maiuscularum aut minuscularum!\nQuarum cura rationem habeas aut [[Special:CreateAccount|novum nomen tibi da]].",
"nosuchusershort": "Usor \"$1\" non est.\nConfirma orthographiam.",
"nouserspecified": "Nomen usoris indicare debes.",
"wrongpassword": "Tessera quam scripsisti non constat. Conare denuo.",
"accmailtext": "Tessera nova usori [[User talk:$1|$1]] per inscriptionem $2 missa est. Nomine dato suademus ipsam tesseram ''[[Special:ChangePassword|mutare]]''.",
"newarticle": "(Nova)",
"newarticletext": "Per nexum progressus es ad paginam quae nondum exsistit.\nNovam paginam si vis creare, in capsam infra praebitam scribe.\n(Vide [$1 paginam auxilii] si plura cognoscere vis.)\nSi hic es propter errorem, solum '''Retrorsum''' in navigatro tuo preme.",
- "anontalkpagetext": "----\n<em>Haec est pagina disputationis usoris anonymi vel potius loci IP cuiusdam.</em>\nMemento locos IP interdum mutari et ab usoribus vel pluribus adhiberi.\nSi ipse sis usor ignotus et ex improviso invenias querulas aliquas, nomen tibi [[Special:UserLogin/signup|impone]] vel [[Special:UserLogin|nomen tuum da]], ut decetero confusionem effugias!",
+ "anontalkpagetext": "----\n<em>Haec est pagina disputationis usoris anonymi vel potius loci IP cuiusdam.</em>\nMemento locos IP interdum mutari et ab usoribus vel pluribus adhiberi.\nSi ipse sis usor ignotus et ex improviso invenias querulas aliquas, nomen tibi [[Special:CreateAccount|impone]] vel [[Special:UserLogin|nomen tuum da]], ut decetero confusionem effugias!",
"noarticletext": "Hac in pagina non sunt litterae.\nLicet [[Special:Search/{{PAGENAME}}|hanc rem in aliis paginis quaerere]] vel\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} acta huius paginae inspicere]\nvel [{{fullurl:{{FULLPAGENAME}}|action=edit}} hanc paginam creare]</span>.",
"noarticletext-nopermission": "Hac in pagina non sunt litterae.\nPotes [[Special:Search/{{PAGENAME}}|hanc rem in aliis paginis quaerere]] aut <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} acta huius paginae videre], sed tibi non licet hanc paginam creare.",
"userpage-userdoesnotexist": "Usor \"<nowiki>$1</nowiki>\" non est. Visne re vera hanc paginam creare vel recensere?",
"Zinneke",
"לערי ריינהארט",
"아라",
- "Nemo bis"
+ "Nemo bis",
+ "Matma Rex"
]
},
"tog-underline": "Linken ënnersträichen:",
"tog-watchdefault": "Säiten a Fichieren déi ech änneren op meng Iwwerwaachungslëscht derbäisetzen",
"tog-watchmoves": "Säiten a Fichieren déi ech réckelen automatesch op meng Iwwerwaachungslëscht derbäisetzen",
"tog-watchdeletion": "Säiten a Fichieren déi ech läschen op meng Iwwerwaachungslëscht derbäisetzen",
+ "tog-watchuploads": "Nei Fichieren déi ech eroplueden op meng Iwwerwaachungslëscht setzen",
"tog-watchrollback": "Säiten déi ech zréckgesat hunn op meng Iwwerwaachungslëscht derbäisetzen",
"tog-minordefault": "All Ännerungen automatesch als 'Kleng Ännerungen' markéieren.",
"tog-previewontop": "Déi ''nach-net gespäichert Versioun'' iwwer der Ännerungsfënster weisen",
"tog-ccmeonemails": "Schéck mir eng Kopie vun de Mailen, déi ech anere Benotzer schécken.",
"tog-diffonly": "Weis bei Versiounsvergläicher just d'Ënnerscheeder an net déi ganz Säit",
"tog-showhiddencats": "Verstoppt Kategorië weisen",
- "tog-norollbackdiff": "Ënnerscheed nom Zrécksetzen ënnerdrécken",
+ "tog-norollbackdiff": "Ënnerscheed nom Zrécksetzen net weisen",
"tog-useeditwarning": "Mech warne wann ech d'Ännerung vun enger Säit verloossen, ouni Ännerunge gespäichert ze hunn",
"tog-prefershttps": "Ëmmer eng sécher Verbindung benotze wann ageloggt",
"underline-always": "Ëmmer",
"noname": "Dir hutt kee gëltege Benotzernumm uginn.",
"loginsuccesstitle": "Ageloggt",
"loginsuccess": "'''Dir sidd elo als \"$1\" op {{SITENAME}} ugemellt.'''",
- "nosuchuser": "Et gëtt kee Benotzernumm mam Numm \"$1\".\nBeim Benotzernumm gëtt tëscht groussen a klenge Buschtawen ënnerscheet (casesensitive).\nKuckt w.e.g. op d'Schreifweis richteg ass, oder [[Special:UserLogin/signup|maacht en neie Benotzerkont op]].",
+ "nosuchuser": "Et gëtt kee Benotzer mam Numm \"$1\".\nBeim Benotzernumm gëtt tëscht groussen a klenge Buschtawen ënnerscheet (casesensitive).\nKuckt w.e.g. op d'Schreifweis richteg ass, oder [[Special:CreateAccount|maacht en neie Benotzerkont op]].",
"nosuchusershort": "De Benotzernumm \"$1\" gëtt et net.\nKuckt w.e.g. op d'Schreifweis richteg ass.",
"nouserspecified": "Gitt w.e.g. e Benotzernumm un.",
"login-userblocked": "Dëse Benotzer ass gespaart. Aloggen ass net erlaabt.",
"botpasswords-deleted-body": "D'Botpasswuert fir de Bot-Numm \"$1\" vum Benotzer ''$2'' gouf geläscht.",
"botpasswords-not-exist": "De Benotzer \"$1\" huet kee Botpasswuert mam Numm \"$2\".",
"resetpass_forbidden": "Passwierder kënnen net geännert ginn.",
+ "resetpass_forbidden-reason": "Passwierder kënnen net geännert ginn: $1",
"resetpass-no-info": "Dir musst ageloggt sinn, fir direkt op dës Säit ze kommen.",
"resetpass-submit-loggedin": "Passwuert änneren",
"resetpass-submit-cancel": "Annulléieren",
"passwordreset-emailsentusername": "Wann eng E-Mailadress mat dësem Benotzernumm associéiert ass, da gëtt Eng E-Mail fir d'Passwuert zeréckzesetze geschéckt.",
"passwordreset-emailsent-capture": "Eng Mail fir d'Passwuert zréckzesetze gouf geschéckt, Dir gesitt se hei drënner.",
"passwordreset-emailerror-capture": "Eng Mail fir d'Passwuert zréckzesetze gouf geschéckt, Dir gesitt se hei drënner, awer de {{GENDER:$2|Benotzer}} konnt se net kréien: $1",
+ "passwordreset-invalideamil": "Net-valabel E-Mail-Adress",
"changeemail": "E-Mail-Adress änneren oder ewechhuelen",
"changeemail-header": "Fëllt dëse Formulaire aus fir Är E-Mailadress z'änneren. Wann Dir d'Verbindung tëscht Ärer E-Mailadress an Ärem Benotzerkont ewechhuele wëllt, da loosst d'Feld e-Mailadress eidel wann Dir de Formulaire späichert.",
"changeemail-passwordrequired": "Dir musst Äert Passwuert agi fir dës Ännerung ze konfirméieren.",
"accmailtext": "En zoufälleg generéiert Passwuert fir [[User talk:$1|$1]] gouf op $2 geschéckt.\n\nEt kann op der ''[[Special:ChangePassword|Passwuert ännere]]'' Säit beim Alogge geännert ginn.",
"newarticle": "(Nei)",
"newarticletext": "Dir hutt op e Link vun enger Säit geklickt, déi et nach net gëtt. Fir déi Säit unzeleeën, gitt w.e.g. Ären Text an déi Këscht hei drënner an (kuckt d'[$1 Hëllef Säit] fir méi Informatiounen). Wann Dir duerch een Iertum heihi komm sidd, da klickt einfach op de Knäppchen '''Zréck''' vun Ärem Browser.",
- "anontalkpagetext": "---- ''Dëst ass d'Diskussiounssäit fir en anonyme Benotzer deen nach kee Kont opgemaach huet oder en net benotzt. Dowéinst musse mir d'IP Adress benotzen, fir de Benotzer z'identifizéieren.\nSou eng IP Adress ka vun e puer Benotzer gedeelt ginn.\nWann Dir en anonyme Benotzer sidd an Dir irrelevant Bemierkunge krut, [[Special:UserLogin/signup|maacht w.e.g. e Kont op]] oder [[Special:UserLogin|loggt Iech an]], fir weider Verwiesselunge mat aneren anonyme Benotzer ze verhënneren.''",
+ "anontalkpagetext": "---- ''Dëst ass d'Diskussiounssäit fir en anonyme Benotzer deen nach kee Kont opgemaach huet oder en net benotzt. Dowéinst musse mir d'IP Adress benotzen, fir de Benotzer z'identifizéieren.\nSou eng IP Adress ka vun e puer Benotzer gedeelt ginn.\nWann Dir en anonyme Benotzer sidd an Dir irrelevant Bemierkunge krut, [[Special:CreateAccount|maacht w.e.g. e Kont op]] oder [[Special:UserLogin|loggt Iech an]], fir weider Verwiesselunge mat aneren anonyme Benotzer ze verhënneren.''",
"noarticletext": "Dës Säit huet elo keen Text.\nDir kënnt op anere Säiten no [[Special:Search/{{PAGENAME}}|dësem Säitentitel sichen]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} an den entspriechende Logbicher nokucken] oder [{{fullurl:{{FULLPAGENAME}}|action=edit}} dës Säit uleeën]</span>.",
"noarticletext-nopermission": "Elo ass keen Text op dëser Säit.\nDir kënnt op anere Säiten [[Special:Search/{{PAGENAME}}|no dësem Säitentitel sichen]], oder <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} an de Logbicher sichen]</span>, mä Dir hutt net déi néideg Rechter fir dës Säit unzeleeën.",
"missing-revision": "D'Versioun #$1 vun der Säit mam Numm \"{{FULLPAGENAME}}\" gëtt et net.\n\nDat geschitt normalerweis wann Dir op e vereelste Link vun enger Versioun vun enger Säit klickt déi geläscht ginn ass.\nDetailer fannt Dir am [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Logbuch vum Läschen].",
"continue-editing": "Gitt weider an de Beräich fir z'änneren",
"previewconflict": "Dir gesitt an dem ieweschten Textfeld wéi den Text ausgesi wäert, wann Dir späichert.",
"session_fail_preview": "<strong>Är Ännerung konnt net gespäichert gi well d'Date vun Ärer Sessioun verluergaange sinn.</strong>\nVersicht et w.e.g. nach eng Kéier.\nWann de Problem dann ëmmer nach bestoe sollt, da versicht Iech [[Special:UserLogout|auszeloggen]] an dann erëm anzeloggen.",
- "session_fail_preview_html": "<strong>Är Ännerung konnt net gespäichert gi well d'Date vun Ärer Sessioun verluergaange sinn.</strong>\n\n<em>Well op {{SITENAME}} 'raw HTML' aktivéiert ass, gouf d'Uweise vun der nach net gespäicherter Versioun ausgeblennt fir JavaScript-Attacken ze vermeiden.</em>\n\n<strong>Wann Dir eng berechtegt Ännerung maache wëllt, da versicht et w.e.g. nach eng Kéier.\nWann de Problem dann ëmmer nach bestoe sollt, versicht Iech [[Special:UserLogout|auszeloggen]] an dann erëm anzeloggen.</strong>",
+ "session_fail_preview_html": "Är Ännerung konnt net gespäichert gi well d'Date vun Ärer Sessioun verluergaange sinn.\n\n<em>Well op {{SITENAME}} 'raw HTML' aktivéiert ass, gouf d'Uweise vun der nach net gespäicherter Versioun ausgeblennt fir JavaScript-Attacken ze vermeiden.</em>\n\n<strong>Wann Dir eng berechtegt Ännerung maache wëllt, da versicht et w.e.g. nach eng Kéier.</strong>\n\nWann de Problem dann ëmmer nach bestoe sollt, versicht Iech [[Special:UserLogout|auszeloggen]] an dann erëm anzeloggen a vergewëssert Iech datt Äre Browser d^Späichere vu Cookieë vun dësem Site zouléisst.",
"token_suffix_mismatch": "'''Är Ännerung gouf refuséiert, well Äre Browser Zeechen am Ännerungs-Identifiant verännert huet.'''\nD'Ännerung gouf refuséiert, fir ze verhënneren datt den Text op der Säit onliesbar gëtt.\nDëst geschitt heiansdo wann Dir en anonyme Proxy-Service um Internet benotzt.",
"edit_form_incomplete": "'''En Deel vum Ännerungsformulaire koum net um Server un; iwwerpréift w.e.g ob Är Ännerunge komplett sinn a probéiert nach emol.'''",
"editing": "Ännere vu(n) $1",
"whatlinkshere-prev": "{{PLURAL:$1|vireg|vireg $1}}",
"whatlinkshere-next": "{{PLURAL:$1|nächsten|nächst $1}}",
"whatlinkshere-links": "← Linken",
- "whatlinkshere-hideredirs": "Viruleedunge $1",
+ "whatlinkshere-hideredirs": "$1 Viruleedungen",
"whatlinkshere-hidetrans": "Agebonne Schabloune $1",
- "whatlinkshere-hidelinks": "Linken $1",
- "whatlinkshere-hideimages": "Linken op Fichiere $1",
+ "whatlinkshere-hidelinks": "$1 Linken",
+ "whatlinkshere-hideimages": "$1 Linken op Fichieren",
"whatlinkshere-filters": "Filteren",
"whatlinkshere-submit": "Lass",
"autoblockid": "Automatesch Spär #$1",
"confirm-watch-top": "Dës Säit op Är Iwwerwaachungslëscht bäisetzen?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Dës Säit vun Ärer Iwwerwaachungslëscht erofhuelen?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Ännerunge vun dëser Säit zrécksetzen?",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← Vireg Säit",
"imgmultipagenext": "nächst Säit →",
"log-action-filter-rights-rights": "Manuell Ännerung",
"log-action-filter-rights-autopromote": "Automatesch Ännerung",
"log-action-filter-upload-upload": "Neien Upload",
- "log-action-filter-upload-overwrite": "Nees eroplueden"
+ "log-action-filter-upload-overwrite": "Nees eroplueden",
+ "authmanager-authplugin-setpass-failed-title": "Änner vum Passwuert huet net funktionéiert",
+ "authmanager-userdoesnotexist": "De Benotzerkont \"$1\" ass net registréiert.",
+ "authmanager-retype-help": "Passwuert nach eng Kéier fir ze konfirméieren",
+ "authmanager-email-label": "E-Mail",
+ "authmanager-email-help": "E-Mail-Adress",
+ "authmanager-realname-label": "Richtegen Numm",
+ "authmanager-realname-help": "Richtegen Numm vum Benotzer",
+ "authmanager-provider-temporarypassword": "Temporäert Passwuert:",
+ "authprovider-resetpass-skip-label": "Iwwersprangen",
+ "authprovider-resetpass-skip-help": "D'Zrécksetze vum Passwuert iwwersprangen",
+ "specialpage-securitylevel-not-allowed-title": "Net erlaabt",
+ "specialpage-securitylevel-not-allowed": "Leider däerft Dir dës Säit net benotze well Är Identitéit net konnt iwwerpréift ginn.",
+ "cannotauth-not-allowed-title": "Erlaabnes refuséiert",
+ "cannotauth-not-allowed": "Dir däerft dës Säit net benotzen",
+ "changecredentials-submit": "Änneren",
+ "changecredentials-success": "Är Idendifikatiounsinformatioune goufe geännert.",
+ "removecredentials-submit": "Ewechhuelen",
+ "credentialsform-account": "Numm vum Kont:",
+ "cannotlink-no-provider-title": "Et gëtt keng Benotzerkonte fir ze verlinken",
+ "linkaccounts": "Benotzerkonte verbannen",
+ "linkaccounts-submit": "Benotzerkonte verbannen"
}
"noname": "Towandise linnya ly'obwa memba eriyinz'okukkirizibwa.",
"loginsuccesstitle": "Oyingidde",
"loginsuccess": "'''Kati oyingidde mu {{SITENAME}} nga okozesa erinnya \"$1\".'''",
- "nosuchuser": "Tewali memba akozesa lya \"$1\".<br />\nEry'obwa memba bw'okyusa obunene bw'ennukuta z'oliwandisa obeera owandise eddala.<br />\nKebera bw'oliwandise, oba [[Special:UserLogin/signup|kolawo akawunti empya]].",
+ "nosuchuser": "Tewali memba akozesa lya \"$1\".<br />\nEry'obwa memba bw'okyusa obunene bw'ennukuta z'oliwandisa obeera owandise eddala.<br />\nKebera bw'oliwandise, oba [[Special:CreateAccount|kolawo akawunti empya]].",
"nosuchusershort": "Tewali memba akozesa lya \"$1\".<br />\nKebera bw'oliwandise.",
"nouserspecified": "Kyetaagisa owandikewo erinnya ly'obwa memba.",
"login-userblocked": "Memba ono agaanidwa. Takkirizibwa kuyingira.",
"accmailtext": "Ekigambo ekikuumi ekya akawunti empya [[User talk:$1|$1]] kisindikiddwa ku $2.\n\nOkukyusa ekigambo kino memba, ng'ayingidde mu wiki, alage ku lupapula ''[[Special:ChangePassword|change password]]''.",
"newarticle": "(Lupapula lupya)",
"newarticletext": "Enyunzi gy'ogenzeko egguka ku lupapula olutannakolebwawo.<br />\nOba gwe oyagala okulukolawo, wandika mu kabokisi akaddako wano.\n(okuyiga ebisingawo, genda ku [$1 lupapula olw'obuyambi]).<br />\nBw'obanga tewagenderedde kutuuka wano, nyigabunyizi eppeesa ery'omu kalambula-neti yo\nerya '''ddayo'''.",
- "anontalkpagetext": "----''Olupapula olw'emboozi luno lukoledwawo at'eyanjula atakolera mu akawunti ya ku wiki eno.<br />\nKino kitwetaagisizza okumwawulira ku ndagiriro ya IP kwe yayimidde.<br />\nAbantu bangi basobola okukozesa endagiriro eya IP y'emu.<br />\nBw'obanga naawe okola ng'at'eyanjudde nga owulira nti ebimu ku birowozo ebikwolekezedwa wano<br />\ntebiggirawo oba tebikwatagana naawe, [[Special:UserLogin/signup|funa akawunti]] oba [[Special:UserLogin|yingira]] baleme okukutabula n'abalala abakola ng'abat'eyanjudde.",
+ "anontalkpagetext": "----''Olupapula olw'emboozi luno lukoledwawo at'eyanjula atakolera mu akawunti ya ku wiki eno.<br />\nKino kitwetaagisizza okumwawulira ku ndagiriro ya IP kwe yayimidde.<br />\nAbantu bangi basobola okukozesa endagiriro eya IP y'emu.<br />\nBw'obanga naawe okola ng'at'eyanjudde nga owulira nti ebimu ku birowozo ebikwolekezedwa wano<br />\ntebiggirawo oba tebikwatagana naawe, [[Special:CreateAccount|funa akawunti]] oba [[Special:UserLogin|yingira]] baleme okukutabula n'abalala abakola ng'abat'eyanjudde.",
"noarticletext": "Wano tewali kyawandikidwawo.<br />\nKy'obadde onoonya osobola [[Special:Search/{{PAGENAME}}| okukinoonyeza]] ku mpapula ndala oba oyinza [{{fullurl:{{FULLPAGENAME}}|action=edit}} gwe okukiwandikako] wano.",
"noarticletext-nopermission": "Wano tewali kyawandikidwawo.<br />\nKy'obadde onoonya osobola [[Special:Search/{{PAGENAME}}| okukinoonyeza]] ku mpapula ndala oba\noyinza <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} okukinoonyeza mu nkalala z'ebifuddeyo ebyekuusana nakyo]</span>.",
"userpage-userdoesnotexist": "Akawunti y'obwamemba \"<nowiki>$1</nowiki>\" teri mu nkalala za wiki eno.<br />\nSooka okakase oba ddala oyagala okukolawo olupapula olupya luno.",
"noname": "De mos 'n gebroekersnaam opgaeve.",
"loginsuccesstitle": "Aanmèlde geluk.",
"loginsuccess": "Doe bis noe es \"$1\" aangemeld bie {{SITENAME}}.",
- "nosuchuser": "D'r besjteit geine gebroeker mit de naam \"$1\".\nDie seen huidlettegevullig\nControleer dien spelling, of gebroek ongersjtaond formuleer om 'n [[Special:UserLogin/signup|nuuj]] gebroekersprofiel aan te make.",
+ "nosuchuser": "D'r besjteit geine gebroeker mit de naam \"$1\".\nDie seen huidlettegevullig\nControleer dien spelling, of gebroek ongersjtaond formuleer om 'n [[Special:CreateAccount|nuuj]] gebroekersprofiel aan te make.",
"nosuchusershort": "De gebroeker \"$1\" besjteit neet. Konterleer de sjriefwieze.",
"nouserspecified": "Doe deens 'ne gebroekersnaam op te gaeve.",
"login-userblocked": "Deze gebroeker steit geblokkeerd. Aanmèlje is neet toegestange.",
"accmailtext": "'n Willekäörig wachwaord veur [[User talk:$1|$1]] is nao $2 gesjtuurd.\n\n't Wachwaord veur deze nuje gebroeker kan gewiezig waere via de pagina ''[[Special:ChangePassword|Wachwaord wiezige]]'' nao 't aanmelje.",
"newarticle": "(Nuuj)",
"newarticletext": "De höbs 'ne link gevolg nao 'n pagina die nog neet besjteit.\nType in de box hiejónger óm de pagina te beginne (zuug de [$1 helppagina] veur mie infermasie).\nEs te hie per óngelök terech bis gekómme, klik dan op de '''trök'''-knóp van diene browser.",
- "anontalkpagetext": "----''Dit is de euverlèkpagina veur 'ne anonieme gebroeker dae nog gein account haet aangemaak of dae 't neet gebroek.\nDaoveur gebroeke v'r 't IP-adres óm de gebroeker te identificere.\nDet adres kan waere gedeild door mierdere gebroekers.\nEs te 'ne anonieme gebroeker bis en de höbs 't geveul dat 'r ónrelevante commentare aan dich gerich zeen, kèns te 't bèste [[Special:UserLogin/signup|'n account crëere]] of [[Special:UserLogin|inlogge]] óm toekomstige verwarring mit anger anoniem gebroekers te veurkomme.''",
+ "anontalkpagetext": "----''Dit is de euverlèkpagina veur 'ne anonieme gebroeker dae nog gein account haet aangemaak of dae 't neet gebroek.\nDaoveur gebroeke v'r 't IP-adres óm de gebroeker te identificere.\nDet adres kan waere gedeild door mierdere gebroekers.\nEs te 'ne anonieme gebroeker bis en de höbs 't geveul dat 'r ónrelevante commentare aan dich gerich zeen, kèns te 't bèste [[Special:CreateAccount|'n account crëere]] of [[Special:UserLogin|inlogge]] óm toekomstige verwarring mit anger anoniem gebroekers te veurkomme.''",
"noarticletext": "Dees pagina bevat gein teks.\nDe kèns [[Special:Search/{{PAGENAME}}|nao deze term zeuke]] in anger pagina's, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} de logbeuk doorzeuke] of [{{fullurl:{{FULLPAGENAME}}|action=edit}} dees pagina bewirke]</span>.",
"noarticletext-nopermission": "Dees pagina bevat gein teks.\nDe kans [[Special:Search/{{PAGENAME}}|nao dees term zeuke]] in anger pagina's of\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} de logbeuk doorzeuke]</span>.",
"userpage-userdoesnotexist": "Doe bewirks 'n gebroekerspagina van 'ne gebroeker dae neet besjteit (gebroeker \"<nowiki>$1</nowiki>\"). Controlere ofs doe dees pagina waal wils aanmake/bewirke.",
"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 ò [[Special:UserLogin/signup|crea una neuva utensa]].",
+ "nosuchuser": "No gh'è nisciun utente de nomme \"$1\".\nI nommi utente son senscibbili a-e maiuscole.\nVerifica o nomme inserîo ò [[Special:CreateAccount|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.",
"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 .''",
+ "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:CreateAccount|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 .''",
"noarticletext": "Po-u momento a pagina çercâ a l'è vêua. L'è poscibbile [[Special:Search/{{PAGENAME}}|çercâ 'sto tittolo]] inte âtre pagine do scîto opû [{{fullurl:{{FULLPAGENAME}}|action=edit}} cangiâ a pagina òua].",
"noarticletext-nopermission": "Òua a pàgina çercâ a l'è vêua. L'è poscìbile [[Special:Search/{{PAGENAME}}|çercâ sto tìtolo]] inte di âtre pàgine do scîto o <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} çercâ inti registri corelæ]</span>, ma no ti gh'hæ i outorizzaçioin pe creâ sta paggina.",
"missing-revision": "La verscion #$1 da paggina \"{{FULLPAGENAME}}\" a no l'esiste.\n\nQuesto succede solitamente se inta stoia ti sciacchi un vegio ingancio a una paggina scassâ.\n\nI dettaggi peuan ese attrovæ into [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de scançellaçioin].",
"allpagesbadtitle": "O tittolo dæto a-a paggina o non va ben, òpû o conten di prefissi inter-lengua o inter-wiki. O porriæ ascì contegnî un o ciù caratteri che inti tittoli no se peuan deuviâ.",
"allpages-bad-ns": "\"$1\" o no ghe in {{SITENAME}}.",
"categories": "Categorîe",
- "special-categories-sort-count": "ordenâ pe nûmmero",
- "special-categories-sort-abc": "ordenâ arfabeticamente",
"linksearch-line": "$1 colegòu a-a pagina $2",
"listusers-submit": "Fanni vedde",
"listusers-noresult": "Utente non trovöo.",
"noname": ".هؤمة نام کاربةری معتبری دیاری نکردئة",
"loginsuccesstitle": "إنۆم سیستم هەتن انجۆم گرت",
"loginsuccess": "هؤمة ایسة هةتیإ نؤم سیستم {{SITENAME}} وۀ نام\"$1\".'",
- "nosuchuser": "کاربةری وۀ نام «$1» ئة ائرة نیة.\nنام کاربةری وة کةڵنگی و گؤجةری حروف حساسة .\nاملای نام را بررسی کنید، یا [[Special:UserLogin/signup|یک حساب کاربری تازه بسازید]].",
+ "nosuchuser": "کاربةری وۀ نام «$1» ئة ائرة نیة.\nنام کاربةری وة کةڵنگی و گؤجةری حروف حساسة .\nاملای نام را بررسی کنید، یا [[Special:CreateAccount|یک حساب کاربری تازه بسازید]].",
"nosuchusershort": "هؤیچ کاربةری وة نام ''$1'' ئة ائرة نیة.\nاملایتان را وارسی کنید.",
"nouserspecified": ".باید یإ گِلة نام کاربةری دیاری کئین",
"login-userblocked": ".ئی کاربرە بەسیائە. إنؤم هەتِن سیستم ڕاووآ(مجاز)نیە",
"accmailtext": "یک گذرواژهٔ تصادفی برای [[User talk:$1|$1]] به $2 فرستاده شد. میتوان آن را از صفحهٔ ''[[Special:ChangePassword|تغییر گذرواژه]]'' که هنگام ثبت ورود نمایش مییابد تغییر داد.",
"newarticle": "(تازه)",
"newarticletext": "شما پیوندی را دنبال کردهاید و به صفحهای رسیدهاید که هنوز وجود ندارد.\nبرای ایجاد صفحه، در مستطیل زیر شروع به نوشتن کنید (برای اطلاعات بیشتر به [$1 صفحهٔ راهنما] مراجعه کنید).\nاگر به اشتباه اینجا آمدهاید، دکمهٔ «بازگشت» مرورگرتان را بزنید.",
- "anontalkpagetext": "----''این صفحهٔ بحث برای کاربر گمنامی است که هنوز حسابی درست نکرده است یا از آن استفاده نمیکند.\nبنا بر این برای شناساییاش مجبوریم از نشانی آیپی عددی استفاده کنیم.\nچنین نشانیهای آیپی ممکن است توسط چندین کاربر به شکل مشترک استفاده شود.\nاگر شما کاربر گمنامی هستید و تصور میکنید اظهار نظرات نامربوط به شما صورت گرفته است، لطفاً برای پیشگیری از اشتباه گرفته شدن با کاربران گمنام دیگر در آینده [[Special:UserLogin/signup|حسابی ایجاد کنید]] یا [[Special:UserLogin|به سامانه وارد شوید]].''",
+ "anontalkpagetext": "----''این صفحهٔ بحث برای کاربر گمنامی است که هنوز حسابی درست نکرده است یا از آن استفاده نمیکند.\nبنا بر این برای شناساییاش مجبوریم از نشانی آیپی عددی استفاده کنیم.\nچنین نشانیهای آیپی ممکن است توسط چندین کاربر به شکل مشترک استفاده شود.\nاگر شما کاربر گمنامی هستید و تصور میکنید اظهار نظرات نامربوط به شما صورت گرفته است، لطفاً برای پیشگیری از اشتباه گرفته شدن با کاربران گمنام دیگر در آینده [[Special:CreateAccount|حسابی ایجاد کنید]] یا [[Special:UserLogin|به سامانه وارد شوید]].''",
"noarticletext": "این صفحه هماکنون دارای هیچ متنی نیست.\nشما میتوانید در صفحههای دیگر [[Special:Search/{{PAGENAME}}|عنوان این صفحه را جستجو کنید]]،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} سیاهههای مرتبط را جستجو کنید]،\nیا [{{fullurl:{{FULLPAGENAME}}|action=edit}} این صفحه را ویرایش کنید]</span>.",
"noarticletext-nopermission": "این صفحه هماکنون متنی ندارد.\nشما میتوانید در دیگر صفحات [[Special:Search/{{PAGENAME}}|این عنوان را جستجو کنید]]،\nیا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} سیاهههای مرتبط را بگردید]</span> ولی شما اجازه ایجاد این صفحه را ندارید.",
"missing-revision": "ویرایش #$1 از صفحهٔ «{{FULLPAGENAME}}» موجود نیست.\n\nمعمولاً در اثر پیوند به تاریخچهٔ بهروز نشدهٔ صفحهٔ حذف شده است.\nمیتوانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.",
"upload-form-label-own-work": "یة کار ووژمة",
"upload-form-label-infoform-categories": "ڕزگەل",
"upload-form-label-infoform-date": "تاریخ",
- "upload-form-label-own-work-message-local": "تائید می کنم که این پرونده را تحت مجوزها و سیاستهای {{SITENAME}} بارگذاری میکنم.",
- "upload-form-label-not-own-work-message-local": "اگر امکان بارگذاری پرونده تحت سیاستهای {{SITENAME}} را ندارید، لطفاً این پنجره را ببندید و از روشهای دیگر استفاده کنید.",
- "upload-form-label-not-own-work-local-local": "ممکن بخواهید از [[Special:Upload|پنجرهٔ بارگذاری پیشفرض]] استفاده کنید.",
- "upload-form-label-own-work-message-default": "متوجهم که این پرونده را بر روی مخزن مشترک بارگذاری میکنم و تائید میکنم که تحت سیاستها و مجوزهای آنجا عمل میکنم.",
- "upload-form-label-not-own-work-message-default": "اگر امکان بارگذاری پرونده تحت سیاستها و مجوزهای مخزن اشتراکگذاری را ندارید، لطفاً این پنجره را ببندید و از روشهای دیگر استفاده کنید.",
- "upload-form-label-not-own-work-local-default": "در صورتی که نمیشود پرونده را تحت سیاستها بارگذاری کنید ممکن است بخواهید از [[Special:Upload|پنجرهٔ بارگذاری در {{SITENAME}}]] استفاده کنید.",
- "upload-form-label-own-work-message-shared": "تصدیق میکنم که مالک حق تکثیر این پرونده هستم و موافق اشتراکگذاری آن تحت مجوز [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] هستم و موافق [https://wikimediafoundation.org/wiki/Terms_of_Use سیاست نحوهٔ استفاده] هستم.",
- "upload-form-label-not-own-work-message-shared": "اگر مالک حق تکثیر این پرونده نیستید یا قصد بارگذاری تحت مجوز دیگری دارید، از [https://commons.wikimedia.org/wiki/Special:UploadWizard جادوگر بارگذاری ویکیانبار] استفاده کنید.",
- "upload-form-label-not-own-work-local-shared": "در صورتی که سایت امکان بارگذاری پرونده را تحت سیاستها بارگذاری میدهد ممکن است بخواهید از [[Special:Upload|پنجرهٔ بارگذاری در {{SITENAME}}]] استفاده کنید.",
+ "upload-form-label-own-work-message-generic-local": "تائید می کنم که این پرونده را تحت مجوزها و سیاستهای {{SITENAME}} بارگذاری میکنم.",
+ "upload-form-label-not-own-work-message-generic-local": "اگر امکان بارگذاری پرونده تحت سیاستهای {{SITENAME}} را ندارید، لطفاً این پنجره را ببندید و از روشهای دیگر استفاده کنید.",
+ "upload-form-label-not-own-work-local-generic-local": "ممکن بخواهید از [[Special:Upload|پنجرهٔ بارگذاری پیشفرض]] استفاده کنید.",
+ "upload-form-label-own-work-message-generic-foreign": "متوجهم که این پرونده را بر روی مخزن مشترک بارگذاری میکنم و تائید میکنم که تحت سیاستها و مجوزهای آنجا عمل میکنم.",
+ "upload-form-label-not-own-work-message-generic-foreign": "اگر امکان بارگذاری پرونده تحت سیاستها و مجوزهای مخزن اشتراکگذاری را ندارید، لطفاً این پنجره را ببندید و از روشهای دیگر استفاده کنید.",
+ "upload-form-label-not-own-work-local-generic-foreign": "در صورتی که نمیشود پرونده را تحت سیاستها بارگذاری کنید ممکن است بخواهید از [[Special:Upload|پنجرهٔ بارگذاری در {{SITENAME}}]] استفاده کنید.",
"backend-fail-stream": "نمیتوان پروندهٔ $1 را ارسال کرد.",
"backend-fail-backup": "نمیتوان نسخهٔ پشتیبان برای پروندهٔ $1 ایجاد کرد",
"backend-fail-notexists": "پروندهٔ $1 وجود ندارد.",
"noname": "Te g'hét mìa specificàt en nòm de ütènt bù.",
"loginsuccesstitle": "Login efetuàt.",
"loginsuccess": "<strong>Adès te sét cunitìt al server de {{SITENAME}} col nòm ütènt de \"$1\".</strong>",
- "nosuchuser": "A gh'è nissün druvat cun 'l nom ''$1''. <br />\nI suranomm i henn sensibil a i leter majùscul.<br />\nCuntrola 'l nom che t'hee metüü denter o [[Special:UserLogin/signup|crea un cünt növ]].",
+ "nosuchuser": "A gh'è nissün druvat cun 'l nom ''$1''. <br />\nI suranomm i henn sensibil a i leter majùscul.<br />\nCuntrola 'l nom che t'hee metüü denter o [[Special:CreateAccount|crea un cünt növ]].",
"nosuchusershort": "Ghe n'è mia d'ütent cun el nom de \"$1\". Ch'el cuntrola se l'ha scrivüü giüst.",
"nouserspecified": "Te gh'heet da specificà un nom del druvatt.",
"login-userblocked": "Chèsta ütènsa l'è blocàda. La conesiù l'è mìa cunsentìda.",
"accmailtext": "La password per [[User talk:$1|$1]] l'è stada mandada a $2. Chèsta password la pöl véser cambiàda per [[Special:ChangePassword|cambià la password]] apéna dòpo che te g'harét fat el log-in.",
"newarticle": "(Nöf)",
"newarticletext": "Te seet andaa adree a un ligam a una pagina che la esista gnamò.\nPer creà la pagina, a l'è assee che te tachet a scriv in del box desota (varda la [$1 pagina de vüt] per savèn püssee).\nSe te seet chì per erur, schiscia \"indree\" in sül tò browser.",
- "anontalkpagetext": "''Questa chí a l'é la pagina da ciciarada d'un druvadur che l'ha nonanmò registraa un cünt, o che 'l le dröva mia.\nPer 'sta reson chí, el pò vess identificaa dumà cunt el sò indirizz nümereg de IP.\n'Stu indirizz IP el pö vess druvaa da püssee d'un druvadur. Se te seet un druvadur anònim e te someja che un quaj messagg al ga nagòt à vidé con de ti, prœuva a [[Special:UserLogin/signup|creà 'n ütènsa nöa]] o [[Special:UserLogin|regìstret con chèla che te g'hét zà]] inscì de minga vess scunfundüü anmò con quaj alter ütent anomim.''",
+ "anontalkpagetext": "''Questa chí a l'é la pagina da ciciarada d'un druvadur che l'ha nonanmò registraa un cünt, o che 'l le dröva mia.\nPer 'sta reson chí, el pò vess identificaa dumà cunt el sò indirizz nümereg de IP.\n'Stu indirizz IP el pö vess druvaa da püssee d'un druvadur. Se te seet un druvadur anònim e te someja che un quaj messagg al ga nagòt à vidé con de ti, prœuva a [[Special:CreateAccount|creà 'n ütènsa nöa]] o [[Special:UserLogin|regìstret con chèla che te g'hét zà]] inscì de minga vess scunfundüü anmò con quaj alter ütent anomim.''",
"noarticletext": "Per 'l mument quela pagina chì l'è vöja. Te pòdet [[Special:Search/{{PAGENAME}}|cercà quel articul chì]] int i alter paginn, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cercà int i register imparentaa], o sedenò [{{fullurl:{{FULLPAGENAME}}|action=edit}} mudifichè 'sta pagina chì adess-adess]</span>.",
"noarticletext-nopermission": "Per 'l mument quela pagina chì l'è vöja. Te pòdet [[Special:Search/{{PAGENAME}}|cercà quel articul chì]] int i alter paginn, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cercà int i register imparentaa], ma te gh'ét nò i permiss per creà-la</span>.",
"userpage-userdoesnotexist": "L'ütènsa \"$1\" l'è mìa registràda. Arda bé semài che te ölet creàla o mudificàa adilbù.",
"allpagesprefix": "Varda i pagin ch'i scumenza per:",
"allpages-hide-redirects": "Scond i bot",
"categories": "Categurij",
- "special-categories-sort-count": "mèt en ùrden per nömer",
- "special-categories-sort-abc": "mèt en ùrden alfabétich",
"deletedcontributions": "Mudìfiche del ütènt scancelàde",
"deletedcontributions-title": "Cuntribüziun scancelaa",
"sp-deletedcontributions-contribs": "mudìfiche",
"remembermypassword": "Prisiminti prisijungimo duomenis šiame kompiuteryje (daugiausiai $1 {{PLURAL:$1|dieną|dienas|dienų}})",
"userlogin-remembermypassword": "Įsiminti mane",
"userlogin-signwithsecure": "Naudoti saugią jungtį",
- "cannotloginnow-title": "Negalima prisijungti dabar",
+ "cannotloginnow-title": "Dabar negalima prisijungti",
"cannotloginnow-text": "Prisijungimas negalimas, kai naudojama $1.",
"yourdomainname": "Jūsų domenas:",
"password-change-forbidden": "Jus negalite keisti slaptažodžių šioje wiki.",
"noname": "Jūs nesate nurodęs teisingo naudotojo vardo.",
"loginsuccesstitle": "Sėkmingai prisijungėte",
"loginsuccess": "'''Dabar jūs prisijungęs prie {{SITENAME}} kaip „$1“.'''",
- "nosuchuser": "Nėra jokio naudotojo, turinčio vardą „$1“.\nNaudotojų varduose skiriamos didžiosios ir mažosios raidės.\nPatikrinkite rašybą, arba [[Special:UserLogin/signup|sukurkite naują paskyrą]].",
+ "nosuchuser": "Nėra jokio naudotojo, turinčio vardą „$1“.\nNaudotojų varduose skiriamos didžiosios ir mažosios raidės.\nPatikrinkite rašybą, arba [[Special:CreateAccount|sukurkite naują paskyrą]].",
"nosuchusershort": "Nėra jokio naudotojo, pavadinto „$1“. Patikrinkite rašybą.",
"nouserspecified": "Jums reikia nurodyti naudotojo vardą.",
"login-userblocked": "Šis naudotojas yra užblokuotas. Prisijungti neleidžiama.",
"accmailtext": "Atsitiktinai sukurtas naudotojo [[User talk:$1|$1]] slaptažodis nusiųstas į $2.\n\nŠios naujos paskyros slaptažodis gali būti pakeistas <em>[[Special:ChangePassword|keisti slaptažodį]]</em> puslapyje beprisijungiant.",
"newarticle": "(Naujas)",
"newarticletext": "Jūs patekote į dar neegzistuojantį puslapį.\nNorėdami sukurti puslapį, pradėkite rašyti žemiau esančiame įvedimo lauke\n(plačiau [$1 pagalbos puslapyje]).\nJei patekote čia per klaidą, paprasčiausiai spustelkite naršyklės mygtuką '''atgal'''.",
- "anontalkpagetext": "----''Tai yra anoniminio naudotojo, nesusikūrusio arba nenaudojančio paskyros, aptarimų puslapis.\nDėl to naudojamas IP adresas jo identifikavimui.\nŠis IP adresas gali būti dalinamas keliems naudotojams.\nJeigu Jūs esate anoniminis naudotojas ir atrodo, kad komentarai nėra skirti Jums, [[Special:UserLogin/signup|sukurkite paskyrą]] arba [[Special:UserLogin|prisijunkite]], ir nebūsite tapatinamas su kitais anoniminiais naudotojais.''",
+ "anontalkpagetext": "----''Tai yra anoniminio naudotojo, nesusikūrusio arba nenaudojančio paskyros, aptarimų puslapis.\nDėl to naudojamas IP adresas jo identifikavimui.\nŠis IP adresas gali būti dalinamas keliems naudotojams.\nJeigu Jūs esate anoniminis naudotojas ir atrodo, kad komentarai nėra skirti Jums, [[Special:CreateAccount|sukurkite paskyrą]] arba [[Special:UserLogin|prisijunkite]], ir nebūsite tapatinamas su kitais anoniminiais naudotojais.''",
"noarticletext": "Šiuo metu šiame puslapyje nėra jokio teksto.\nJūs galite [[Special:Search/{{PAGENAME}}|ieškoti šio puslapio pavadinimo]] kituose puslapiuose,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ieškoti susijusių įrašų] arba [{{fullurl:{{FULLPAGENAME}}|action=edit}} sukurti šį puslapį]</span>.",
"noarticletext-nopermission": "Šiuo metu šiame puslapyje nėra jokio teksto.\nJūs galite [[Special:Search/{{PAGENAME}}|ieškoti šio puslapio pavadinimo]] kituose puslapiuose,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ieškoti susijusių įrašų]</span>, bet jūs neturite teisės sukurti šį puslapį.",
"missing-revision": "Puslapio peržiūra #$1 pavadinto „{{FULLPAGENAME}}“ neegzistuoja.\n\nTai paprastai atsitinka kai pasenusi nuoroda veda į puslapį, kuris buvo ištrintas.\nInformaciją galima rasti [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log].",
"upload-form-label-own-work": "Tai yra mano darbas",
"upload-form-label-infoform-categories": "Kategorijos",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-own-work-message-local": "Patvirtinu, kad įkeliu šį failą su šiomis naudojimosi sąlygomis ir licencijavimo politika į {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Jeigu Jūs negalite įkelti šio failo su {{SITENAME}} politika, prašome uždaryti dialogą ir pabandyti kitą metodą.",
- "upload-form-label-not-own-work-local-local": "Jūs taip pat galite norėti išbandyti [[Special:Upload|numatytąjį įkėlimo puslapį]].",
- "upload-form-label-own-work-message-default": "Aš suprantu, kad įkeliu šį failą į dalinimosi repozitoriją. Aš patvirtinu, kad tai darau laikydamasis jų paslaugų teikimo sąlygų ir licencijavimo politikos.",
- "upload-form-label-not-own-work-message-default": "Jeigu negalite įkelti šio failo su dalinimosi repozitorijos politika, prašome uždaryti šį dialogą ir bandyti kitą metodą.",
- "upload-form-label-not-own-work-local-default": "Jūs taip pat galite norėti išbandyti [[Special:Upload|{{SITENAME}} įkėlimo puslapį]], jeigu šis failas gali būti įkeltas su jų politika.",
- "upload-form-label-own-work-message-shared": "Aš patvirtinu, kad man priklauso šio failo autorinės teisės ir sutinku neatšaukiamai išleisti šį failą į Wikimedia Commons su [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] licencija, ir aš sutinku su [https://wikimediafoundation.org/wiki/Terms_of_Use paslaugų teikimo sąlygomis].",
- "upload-form-label-not-own-work-message-shared": "Jeigu Jums nepriklauso šio failo autorinės teisės arba Jūs norite išleisti jį su kitokia licencija, apsvarstykite naudojimą [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons įkėlimo vedlį].",
- "upload-form-label-not-own-work-local-shared": "Jūs taip pat galite norėti išbandyti [[Special:Upload|{{SITENAME}} įkėlimo puslapį]], jeigu šis puslapis leidžia failų įkėlimą pagal jų politiką.",
+ "upload-form-label-own-work-message-generic-local": "Patvirtinu, kad įkeliu šį failą su šiomis naudojimosi sąlygomis ir licencijavimo politika į {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Jeigu Jūs negalite įkelti šio failo su {{SITENAME}} politika, prašome uždaryti dialogą ir pabandyti kitą metodą.",
+ "upload-form-label-not-own-work-local-generic-local": "Jūs taip pat galite norėti išbandyti [[Special:Upload|numatytąjį įkėlimo puslapį]].",
+ "upload-form-label-own-work-message-generic-foreign": "Aš suprantu, kad įkeliu šį failą į dalinimosi repozitoriją. Aš patvirtinu, kad tai darau laikydamasis jų paslaugų teikimo sąlygų ir licencijavimo politikos.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Jeigu negalite įkelti šio failo su dalinimosi repozitorijos politika, prašome uždaryti šį dialogą ir bandyti kitą metodą.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Jūs taip pat galite norėti išbandyti [[Special:Upload|{{SITENAME}} įkėlimo puslapį]], jeigu šis failas gali būti įkeltas su jų politika.",
"backend-fail-stream": "Negali būti apdorotas failas $1.",
"backend-fail-backup": "Negali būti išsaugotas failas $1.",
"backend-fail-notexists": "Failas $1 neegzistuoja.",
"noname": "Hmangtu hming dik a ziak lo.",
"loginsuccesstitle": "Hlawhtling takin i lût tâ e.",
"loginsuccess": "'''{{SITENAME}}-ah \"$1\" hming puin a i lût ta.'''",
- "nosuchuser": "Hmingtuhming \"$1\" a awm lo.\nHmangtuhming hi hawrawppui leh të thliar hran a ngai a ni (entirna: Thara leh thara an inang lo).\nI thilziah enfiah rawh, a nih loh pawhin [[Special:UserLogin/signup|siangchan thar siam rawh]].",
+ "nosuchuser": "Hmingtuhming \"$1\" a awm lo.\nHmangtuhming hi hawrawppui leh të thliar hran a ngai a ni (entirna: Thara leh thara an inang lo).\nI thilziah enfiah rawh, a nih loh pawhin [[Special:CreateAccount|siangchan thar siam rawh]].",
"nosuchusershort": "Hmangtu hming \"$1\" a awm lo.\nI thilziah enfiah rawh.",
"nouserspecified": "Hmangtuhming i ziah a ngai.",
"login-userblocked": "Hë hmangtu hi danbeh a ni. Luh phalsak a ni lo.",
"site-atom-feed": "$1 Atom padeve",
"page-rss-feed": "\"$1\" RSS barotne",
"page-atom-feed": "\"$1\" Atom barotne",
- "red-link-title": "$1 (lapa neeksistē)",
+ "red-link-title": "$1 (lapa nepastāv)",
"sort-descending": "Kārtot dilstošā secībā",
"sort-ascending": "Kārtot augošā secībā",
"nstab-main": "Raksts",
"password-change-forbidden": "Šajā wiki paroles nevar mainīt.",
"externaldberror": "Notikusi vai nu ārējās autentifikācijas datubāzes kļūda, vai arī tev nav atļauts izmainīt savu ārējo kontu.",
"login": "Pieslēgties",
+ "login-security": "Apstiprini savu identitāti",
"nav-login-createaccount": "Izveidot jaunu lietotāju vai doties iekšā",
"userlogin": "Izveidot jaunu lietotāju vai doties iekšā",
"userloginnocreate": "Pieslēgties",
"noname": "Tu neesi norādījis derīgu lietotāja vārdu.",
"loginsuccesstitle": "Ieiešana veiksmīga",
"loginsuccess": "Tu esi ienācis {{grammar:lokatīvs|{{SITENAME}}}} kā \"$1\".",
- "nosuchuser": "Šeit nav lietotāja ar vārdu \"$1\". Lietotājvārdi ir reģistrjutīgi (lielie un mazie burti nav viens un tas pats) Pārbaudi, vai pareizi uzrakstīts, vai arī [[Special:UserLogin/signup|izveido jaunu kontu]].",
+ "nosuchuser": "Šeit nav lietotāja ar vārdu \"$1\". Lietotājvārdi ir reģistrjutīgi (lielie un mazie burti nav viens un tas pats) Pārbaudi, vai pareizi uzrakstīts, vai arī [[Special:CreateAccount|izveido jaunu kontu]].",
"nosuchusershort": "Šeit nav lietotāja ar vārdu \"$1\". Pārbaudi, vai nav drukas kļūda.",
"nouserspecified": "Tev jānorāda lietotājvārds.",
"login-userblocked": "Šis dalībnieks ir bloķēts. Pieslēgšanās nav atļauta.",
"retypenew": "Atkārto jauno paroli",
"resetpass_submit": "Uzstādīt paroli un ieiet",
"changepassword-success": "Jūsu parole tika nomainīta veiksmīgi!",
+ "botpasswords": "Botu paroles",
+ "botpasswords-createnew": "Izveidot jaunu bota paroli",
+ "botpasswords-editexisting": "Rediģētu esošu bota paroli",
"botpasswords-label-appid": "Bota nosaukums:",
"botpasswords-label-create": "Izveidot",
"botpasswords-label-update": "Atjaunināt",
"botpasswords-label-resetpassword": "Atiestatīt paroli",
"botpasswords-label-restrictions": "Lietošanas ierobežojumi:",
"botpasswords-label-grants-column": "Piešķirts",
+ "botpasswords-deleted-title": "Bota parole dzēsta",
"resetpass_forbidden": "Paroles nav iespējams nomainīt",
"resetpass-no-info": "Jums ir nepieciešams ieiet, lai tūlīt piekļūtu šai lapai.",
"resetpass-submit-loggedin": "Mainīt paroli",
"minoredit": "Maznozīmīgs labojums",
"watchthis": "Uzraudzīt šo lapu",
"savearticle": "Saglabāt lapu",
+ "publishpage": "Saglabāt lapu",
"preview": "Pirmskats",
"showpreview": "Rādīt pirmskatu",
"showdiff": "Rādīt izmaiņas",
"accmailtext": "Nejauši ģenerēta parole lietotājam [[User talk:$1|$1]] tika nosūtīta uz $2.\n\nŠī konta paroli pēc ielogošanās varēs nomainīt ''[[Special:ChangePassword|šeit]]''.",
"newarticle": "(Jauns raksts)",
"newarticletext": "Šajā projektā vēl nav lapas ar šādu nosaukumu.\nLai izveidotu lapu, sāc rakstīt teksta logā apakšā (par teksta formatēšanu un sīkākai informācija skatīt [$1 palīdzības lapu]).\nJa tu šeit nonāci kļūdas pēc, vienkārši uzspied <strong>back</strong> pogu pārlūkprogrammā.",
- "anontalkpagetext": "----''Šī ir diskusiju lapa anonīmam dalībniekam, kurš vēl nav kļuvis par reģistrētu dalībnieku vai arī neizmanto savu dalībnieka vārdu. Tādēļ mums ir jāizmanto skaitliskā IP adrese, lai viņu identificētu.\nŠāda IP adrese var būt vairākiem dalībniekiem.\nJa tu esi anonīms dalībnieks un uzskati, ka tev ir adresēti neatbilstoši komentāri, lūdzu, [[Special:UserLogin/signup|kļūsti par dalībnieku]] vai arī [[Special:UserLogin|izmanto jau izveidotu dalībnieka vārdu]], lai izvairītos no turpmākām neskaidrībām un tu netiktu sajaukts ar citiem anonīmiem dalībniekiem.''",
+ "anontalkpagetext": "----''Šī ir diskusiju lapa anonīmam dalībniekam, kurš vēl nav kļuvis par reģistrētu dalībnieku vai arī neizmanto savu dalībnieka vārdu. Tādēļ mums ir jāizmanto skaitliskā IP adrese, lai viņu identificētu.\nŠāda IP adrese var būt vairākiem dalībniekiem.\nJa tu esi anonīms dalībnieks un uzskati, ka tev ir adresēti neatbilstoši komentāri, lūdzu, [[Special:CreateAccount|kļūsti par dalībnieku]] vai arī [[Special:UserLogin|izmanto jau izveidotu dalībnieka vārdu]], lai izvairītos no turpmākām neskaidrībām un tu netiktu sajaukts ar citiem anonīmiem dalībniekiem.''",
"noarticletext": "Šajā lapā šobrīd nav nekāda teksta, tu vari [[Special:Search/{{PAGENAME}}|meklēt citās lapās pēc šīs lapas nosaukuma]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} meklēt saistītos reģistru ierakstos] vai arī [{{fullurl:{{FULLPAGENAME}}|action=edit}} sākt rediģēt šo lapu]</span>.",
"noarticletext-nopermission": "Šajā lapā pašlaik nav nekāda teksta.\nTu vari [[Special:Search/{{PAGENAME}}|meklēt šīs lapas nosaukumu]] citās lapās,\nvai <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} meklēt saistītus reģistru ierakstus]</span>, bet jums nav atļauja izveidot si lapu.",
"userpage-userdoesnotexist": "Lietotājs \"<nowiki>$1</nowiki>\" nav reģistrēts.\nLūdzu, pārliecinies vai vēlies izveidot/izmainīt šo lapu.",
"userpage-userdoesnotexist-view": "Dalībnieks \"$1\" nav reģistrēts.",
"blocked-notice-logextract": "Šis dalībnieks pašlaik ir nobloķēts.\n\nPēdējais bloķēšanas reģistra ieraksts ir apskatāms zemāk:",
- "clearyourcache": "'''Piezīme:''' Lai redzētu izmaiņas, pēc saglabāšanas jums var nākties iztīrīt sava pārlūka kešatmiņu.\n* '''Firefox / Safari:''' Pieturiet ''Shift'' un klikšķiniet uz ''Pārlādēt'' vai nospiediet ''Ctrl-F5'' vai ''Ctrl-R'' (''Command-R'' uz Mac)\n* '''Google Chrome:''' Nospiediet ''Ctrl-Shift-R'' (''Command-Shift-R'' uz Mac)\n* '''Internet Explorer:''' Pieturiet ''Ctrl'' un klikšķiniet uz ''Pārlādēt'' vai nospiediet ''Ctrl-F5''\n* '''Konqueror:''' Klikšķiniet uz ''Pārlādēt'' vai nospiediet ''F5''\n* '''Opera:''' Iztīriet kešatmiņu ''Tools → Preferences''",
+ "clearyourcache": "<strong>Piezīme:</strong> Lai redzētu izmaiņas, pēc saglabāšanas var nākties iztīrīt sava pārlūka kešatmiņu.\n* <strong>Firefox / Safari:</strong> Pieturi <em>Shift</em> un klikšķini uz <em>Pārlādēt</em> vai nospied <em>Ctrl-F5</em> vai <em>Ctrl-R</em> (<em>⌘-R</em> uz Mac)\n* <strong>Google Chrome:</strong> Nospied <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> uz Mac)\n* <strong>Internet Explorer:</strong> Pieturi <em>Ctrl</em> un klikšķini uz <em>Pārlādēt</em> vai nospied <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Dodies uz <em>Menu → Settings</em> (<em>Opera → Preferences</em> uz Mac) un pēc tam uz <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
"usercssyoucanpreview": "'''Ieteikums:''' Lieto pogu \"{{int:showpreview}}\", lai pārbaudītu savu jauno CSS pirms saglabāšanas.",
"userjsyoucanpreview": "'''Ieteikums:''' Lieto pogu \"{{int:showpreview}}\", lai pārbaudītu savu jauno JavaScript pirms saglabāšanas.",
"usercsspreview": "'''Atceries, ka šis ir tikai tava dalībnieka CSS pirmskats, lapa vēl nav saglabāta!'''",
"right-editusercssjs": "Izmainīt citu dalībnieku CSS un JS failus",
"right-editusercss": "Izmainīt citu dalībnieku CSS failus",
"right-edituserjs": "Izmainīt citu dalībnieku JS failus",
+ "right-editmyusercss": "Rediģējiet savus dalībnieka CSS failus",
+ "right-editmyuserjs": "Rediģējiet savus dalībnieka JavaScript failus",
"right-viewmywatchlist": "Apskatīt savu uzraugāmo rakstu sarakstu",
"right-rollback": "Ātri veikt atriti pēdējā dalībnieka labojumiem, kas veica izmaiņas kādā konkrētā lapā",
"right-markbotedits": "Atzīmēt labojumus, kam veikta atrite, kā bota labojumus",
"right-siteadmin": "Bloķēt un atbloķēt datubāzi",
"right-sendemail": "Sūtīt e-pastu citiem dalībniekiem",
"right-passwordreset": "Apskatīt paroles atiestatīšanas e-pasta ziņojumus",
+ "grant-group-email": "Sūtīt e-pastu",
+ "grant-createaccount": "Izveidot kontu",
"newuserlogpage": "Jauno dalībnieku reģistrs",
"newuserlogpagetext": "Jauno lietotājvārdu reģistrs.",
"rightslog": "Dalībnieku tiesību reģistrs",
"upload-form-label-infoform-description": "Apraksts",
"upload-form-label-usage-title": "Pielietojums",
"upload-form-label-usage-filename": "Faila nosaukums",
+ "upload-form-label-infoform-categories": "Kategorijas",
+ "upload-form-label-infoform-date": "Datums",
"backend-fail-stream": "Nevar straumēt failu $1.",
"backend-fail-backup": "Nevar dublēt failu $1.",
"backend-fail-notexists": "Fails $1 nepastāv.",
"apisandbox": "API smilškaste",
"apisandbox-api-disabled": "API ir atspējots šajā tīmekļa vietnē.",
"apisandbox-reset": "Notīrīt",
+ "apisandbox-retry": "Mēģināt vēlreiz",
"apisandbox-examples": "Piemēri",
"apisandbox-results": "Rezultāti",
"apisandbox-request-url-label": "Pieprasījuma URL:",
"whatlinkshere-hidelinks": "$1 saites",
"whatlinkshere-hideimages": "$1 failu saites",
"whatlinkshere-filters": "Filtri",
+ "whatlinkshere-submit": "Aiziet",
"autoblockid": "Autobloķēšana #$1",
"block": "Bloķēt dalībnieku",
"unblock": "Atbloķēt lietotāju",
"confirm-watch-button": "Labi",
"confirm-watch-top": "Pievienot šo lapu uzraugāmo lapu sarakstam?",
"confirm-unwatch-button": "Labi",
+ "confirm-rollback-button": "Labi",
"imgmultipageprev": "← iepriekšējā lapa",
"imgmultipagenext": "nākamā lapa →",
"imgmultigo": "Aiziet!",
"imgmultigoto": "Iet uz lapu $1",
"img-lang-default": "(noklusējuma valoda)",
+ "img-lang-go": "Aiziet",
"ascending_abbrev": "pieaug.",
"descending_abbrev": "dilst.",
"table_pager_next": "Nākamā lapa",
"version-libraries-license": "Licence",
"version-libraries-description": "Apraksts",
"version-libraries-authors": "Autori",
+ "redirect-submit": "Aiziet",
"redirect-value": "Vērtība:",
"redirect-user": "Lietotāja ID",
"redirect-page": "Lapas ID",
"expand_templates_preview": "Pirmskats",
"pagelang-name": "Lapa",
"pagelang-language": "Valoda",
+ "pagelang-select-lang": "Izvēlieties valodu",
+ "pagelang-submit": "Iesniegt",
+ "mediastatistics-table-mimetype": "MIME tips",
+ "mediastatistics-table-count": "Failu skaits",
+ "mediastatistics-table-totalbytes": "Kopējais izmērs",
+ "mediastatistics-header-unknown": "Nav zināms",
+ "mediastatistics-header-bitmap": "Bitmap attēli",
+ "mediastatistics-header-drawing": "Zīmējumi (vector attēli)",
"mediastatistics-header-audio": "Audio",
+ "mediastatistics-header-video": "Video",
+ "mediastatistics-header-total": "Visi faili",
"special-characters-group-latin": "Latīņu",
"special-characters-group-latinextended": "Latīņu (papildus)",
"special-characters-group-ipa": "IPA",
"special-characters-group-symbols": "Simboli",
"special-characters-group-greek": "Grieķu",
+ "special-characters-group-greekextended": "Grieķu paplašināta",
"special-characters-group-cyrillic": "Kirilica",
"special-characters-group-arabic": "Arābu",
"special-characters-group-persian": "Persiešu",
"special-characters-group-sinhala": "Singāļu",
"special-characters-group-gujarati": "Gudžarati",
"mw-widgets-dateinput-no-date": "Nav izvēlēts datums",
- "api-error-blacklisted": "Lūdzu, izvēlieties citu, aprakstošu nosaukumu!"
+ "mw-widgets-titleinput-description-new-page": "lapa vēl nepastāv",
+ "api-error-blacklisted": "Lūdzu, izvēlieties citu, aprakstošu nosaukumu!",
+ "authmanager-email-label": "E-pasts",
+ "authmanager-email-help": "E-pasta adrese",
+ "authmanager-realname-label": "Tavs īstais vārds",
+ "authmanager-realname-help": "Dalībnieka īstais vārds",
+ "authprovider-resetpass-skip-label": "Izlaist",
+ "specialpage-securitylevel-not-allowed-title": "Nav atļauts"
}
"noname": "缺簿名,或不格也。",
"loginsuccesstitle": "登簿成矣",
"loginsuccess": "'''$1'''登{{SITENAME}}矣",
- "nosuchuser": "查無此人。惠請更名,查大小寫或[[Special:UserLogin/signup|立此簿]]。",
+ "nosuchuser": "查無此人。惠請更名,查大小寫或[[Special:CreateAccount|立此簿]]。",
"nosuchusershort": "查無\"$1\",惠核之。",
"nouserspecified": "簿名必須",
"login-userblocked": "此簿見錮矣。是之登未見許可。",
"accmailtext": "\"$1\"之新符節至$2矣\n\n此符節可於登簿後改",
"newarticle": "撰",
"newarticletext": "此頁尚缺。欲補,撰於下,有惑見[$1 助]。\n誤入者,返前即可。",
- "anontalkpagetext": "----''此匿論也,為未簿或不簿者設,IP俱錄以辨人焉。然IP不獨,恐生亂象,不喜惠[[Special:UserLogin/signup|增]][[Special:UserLogin|登簿]]遠之。",
+ "anontalkpagetext": "----''此匿論也,為未簿或不簿者設,IP俱錄以辨人焉。然IP不獨,恐生亂象,不喜惠[[Special:CreateAccount|增]][[Special:UserLogin|登簿]]遠之。",
"noarticletext": "查無此文。[[Special:Search/{{PAGENAME}}|尋題]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 尋誌],\n或[{{fullurl:{{FULLPAGENAME}}|action=edit}} 纂頁]</span>。",
"noarticletext-nopermission": "查無此文。[[Special:Search/{{PAGENAME}}|尋題]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 尋誌],\n或[{{fullurl:{{FULLPAGENAME}}|action=edit}} 纂頁]</span>。",
"userpage-userdoesnotexist": "「<nowiki>$1</nowiki>」之簿未增也。請建纂本頁前查之。",
"noname": "अहाँ वैध प्रयोक्तानाम नै देने छी।",
"loginsuccesstitle": "सम्प्रवेश भएल",
"loginsuccess": "'''अहाँ सम्प्रवेश केलहुँ {{SITENAME}} \"$1\".'''क रूपमे।",
- "nosuchuser": "\"$1\" नामसँ कोनो प्रयोक्ता नै अछि।\nप्रयोक्तानाम ब्रह्मक्षर-लघ्वक्षर भेद युक्त अछि।\nअपन ह्रिजै जाँची, वा [[Special:UserLogin/signup|नव खाता बनाबी]] ।",
- "nosuchusershort": "\"$1\" नामà¥\8dना कोनो प्रयोक्ता नै अछि।\nअपन हिजए सुधारी।",
+ "nosuchuser": "\"$1\" नामसँ कोनो प्रयोक्ता नै अछि।\nप्रयोक्तानाम ब्रह्मक्षर-लघ्वक्षर भेद युक्त अछि।\nअपन ह्रिजै जाँची, वा [[Special:CreateAccount|नव खाता बनाबी]] ।",
+ "nosuchusershort": "\"$1\" नामà¤\95 कोनो प्रयोक्ता नै अछि।\nअपन हिजए सुधारी।",
"nouserspecified": "अहाँक एकटा प्रयोक्तानाम देबऽ पडत।",
"login-userblocked": "ई प्रयोक्ता प्रतिबन्धित अछि। सम्प्रवेशक अधिकार नै अछि।",
- "wrongpassword": "à¤\97लत à¤\95à¥\82à¤\9fशबà¥\8dद दà¥\87ल à¤\97à¥\87ल।\nफà¥\87रसà¤\81 पà¥\8dरयास à¤\95रà¥\82।",
- "wrongpasswordempty": "रिà¤\95à¥\8dत à¤\95à¥\82à¤\9fशबà¥\8dद दà¥\87ल à¤\97à¥\87ल।\nफà¥\87रसà¤\81 पà¥\8dरयास à¤\95रà¥\82।",
+ "wrongpassword": "à¤\97लत à¤\95à¥\82à¤\9fशबà¥\8dद दà¥\87ल à¤\97à¥\87ल।\nफà¥\87रसà¤\81 पà¥\8dरयास à¤\95रà¥\80।",
+ "wrongpasswordempty": "रिà¤\95à¥\8dत à¤\95à¥\82à¤\9fशबà¥\8dद दà¥\87ल à¤\97à¥\87ल।\nफà¥\87रसà¤\81 पà¥\8dरयास à¤\95रà¥\80।",
"passwordtooshort": "कूटशब्द कमसँ कम {{PLURAL:$1|1 वर्ण|$1 वर्णक}} हुअए।",
"passwordtoolong": "कुटशब्द kuttsabda {{PLURAL:$1|1 वर्ण|$1 वर्णों}} से बेसी नम्हर भ्या सकएत अछि।",
"passwordtoopopular": "आम पासवर्ड अहाँ नै चुनि सकएत अछि। कृपया अनोखा पासवर्ड चुनी।",
"password-name-match": "अहाँक कूटशब्द अहाँक प्रयोक्तानामसँ भिन्न हेबाक चाही।",
"password-login-forbidden": "ऐ प्रयोक्तानाम आ कूटशब्दक प्रयोग प्रतिबन्धित अछि।",
- "mailmypassword": "नà¥\82तन à¤\95à¥\82à¤\9fशबà¥\8dद à¤\88-पतà¥\8dरसà¤\81 पठाà¤\89",
- "passwordremindertitle": "नव अस्थायी कूटशब्द {{अन्तर्जाल-पता}} लेल।",
- "passwordremindertext": "कियो (सम्भवतः अहाँ, अनिकेत $1 सँ) एकटा नव कूटशब्दक आग्रह {{अन्तर्जाल}} ($4) लेल केलौं। एकटा अस्थायी कूटशब्द प्रयोक्ता \"$2\" लेल बनाओल गेल अछि आ \"$3\" रूपमे स्थापित कएल गेल अछि। जँ ई अहाँक इच्छा अछि तँ अहाँकेँ सम्प्रवेश करए पड़त आ एकटा नव कूटशब्दक चुनाव करए पड़त। \nअहाँक अस्थायी कूटशब्द खतम भऽ जाएत {{PLURAL:$5|एक दिन|$5 दिन}} मे।",
- "noemail": "पà¥\8dरयà¥\8bà¤\95à¥\8dता \"$1\" लà¥\87ल à¤\95à¥\8bनà¥\8b à¤\88-पतà¥\8dर सà¤\82केत दर्ज नै अछि।",
- "noemailcreate": "अहाँकेँ एकटा मान्य ई-पत्र संकेत देबऽ पड़त।",
- "passwordsent": "à¤\8fà¤\95à¤\9fा नव à¤\95à¥\82à¤\9fशबà¥\8dद \"$1\" लà¥\87ल पà¤\82à¤\9cà¥\80à¤\95à¥\83त à¤\88-पतà¥\8dर सà¤\82à¤\95à¥\87तपर पठाà¤\8fल à¤\97à¥\87ल à¤\85à¤\9bि।\nà¤\9cà¤\96न à¤\85हाà¤\81à¤\95à¥\87à¤\81 à¤\88 à¤à¥\87à¤\9fà¥\88à¤\8f तà¤\81 फà¥\87रसà¤\81 समà¥\8dपà¥\8dरवà¥\87श à¤\95रà¥\82।",
+ "mailmypassword": "नà¥\82तन à¤\95à¥\82à¤\9fशबà¥\8dद à¤\88-पतà¥\8dरसà¤\81 पठाबà¥\80",
+ "passwordremindertitle": "{{SITENAME}}क लेल नव अस्थायी कूटशब्द",
+ "passwordremindertext": "कियो (सम्भवतः अहाँ, अनिकेत $1 सँ) एकटा नव कूटशब्दक आग्रह {{SITENAME}} ($4) केनए अछि। एकटा अस्थायी कूटशब्द प्रयोक्ता \"$2\" लेल बनाओल गेल अछि आ \"$3\" रूपमे स्थापित कएल गेल अछि। जँ ई अहाँक इच्छा अछि तँ अहाँक सम्प्रवेश करए पडत आ एकटा नव कूटशब्दक चुनाव करए पडत। \nअहाँक अस्थायी कूटशब्द खतम भऽ जाएत {{PLURAL:$5|एक दिन|$5 दिन}} मे।",
+ "noemail": "पà¥\8dरयà¥\8bà¤\95à¥\8dता \"$1\" लà¥\87ल à¤\95à¥\8bनà¥\8b à¤\88-पतà¥\8dर सà¤\99à¥\8dकेत दर्ज नै अछि।",
+ "noemailcreate": "अहाँक एकटा मान्य ई-पत्र सङ्केत देबऽ पडत।",
+ "passwordsent": "à¤\8fà¤\95à¤\9fा नव à¤\95à¥\82à¤\9fशबà¥\8dद \"$1\" लà¥\87ल पà¤\9eà¥\8dà¤\9cà¤\9cà¥\80à¤\95à¥\83त à¤\88-पतà¥\8dर सà¤\99à¥\8dà¤\95à¥\87तपर पठाà¤\8fल à¤\97à¥\87ल à¤\85à¤\9bि।\nà¤\9cà¤\96न à¤\85हाà¤\81à¤\95 à¤\88 à¤à¥\87à¤\9fà¥\88à¤\8f तà¤\81 फà¥\87रसà¤\81 समà¥\8dपà¥\8dरवà¥\87श à¤\95रà¥\80।",
"blocked-mailpassword": "अहाँक अनिकेत सम्पादन लेल प्रतिबन्धित अछि, आ दुरुपयोग रोकबा लेल कुटशब्द प्रत्याहरण सेवा ई लेल उपलब्ध नै अछि।",
"eauthentsent": "एकटा पावती ई-पत्र निर्धारित ई-पत्र संकेतपर पठा देल गेल अछि।\nऐ खातापर कोनो दोसर ई-पत्र पठाएल जएबासँ पहिने, अहाँकेँ ऐ ई-पत्रक निर्देशक पालन करए पड़त, जइसँ ई पुष्ट भऽ सकए जे ई खाता वास्तवमे अहींक अछि।",
"throttled-mailpassword": "एकटा कूटशब्द स्मारक पहिनहिये पठाएल गेल अछि, {{PLURAL:$1|घण्टा|$1 घण्टा}}क भीतर।\nदुरुपयोग रोकबा लेल, मात्र एकटा कूटशब्द {{PLURAL:$1|घण्टा|$1 घण्टा}}मे पठाएल जाएत।",
"mailerror": "ई-पत्र पठेबामे त्रुटी: $1",
"acct_creation_throttle_hit": "अहाँके आइ॰पि. पतासँ आएल आगंतुक चौबीस घण्टा सँ बैसी ई विकिमे {{PLURAL:$1|एक खाता|$1 खाता}} बनौलक अछि, इ समयावधिमे ई अधिकतम सिमा छी। अतः अखन ई आइ॰पि. पताके प्रयोग करए वाला आगंतुक आर कोनो खाता नै खोइल सकएत अछि ।",
- "emailauthenticated": "à¤\85हाà¤\81à¤\95 à¤\88-पतà¥\8dर सà¤\82à¤\95à¥\87त $2 à¤\95à¥\87à¤\81 $3 बजे सत्यापित भेल।",
- "emailnotauthenticated": "à¤\85हाà¤\81à¤\95 à¤\88-पतà¥\8dर सà¤\82à¤\95à¥\87त à¤\85à¤\96न धरि सतà¥\8dयापित नà¥\88 à¤à¥\87ल à¤\85à¤\9bि।\nनिà¤\9aा दà¥\87ल à¤\97à¥\87ल à¤\95à¥\8bनà¥\8b सà¥\81विधा à¤\95à¥\87 लà¥\87ल à¤\85हाà¤\81à¤\95à¥\87 ई-पत्र नै भेजल जाएत।",
- "noemailprefs": "à¤\87 सà¥\81विधा सठà¤\95ऽ पà¥\8dरयà¥\8bà¤\97 à¤\95रà¤\8f à¤\95à¥\87 लà¥\87ल à¤\85पन विà¤\95लà¥\8dपमà¥\87 à¤\88-पतà¥\8dर पता राà¤\96à¥\81।",
- "emailconfirmlink": "à¤\85पन à¤\88-पतà¥\8dर सà¤\82à¤\95à¥\87त सतà¥\8dयापित à¤\95रà¥\81",
- "invalidemailaddress": "à¤\85मानà¥\8dय पà¥\8dरारà¥\82पà¤\95 à¤\95ारण à¤\90 à¤\88-पतà¥\8dर सà¤\82à¤\95à¥\87तà¤\95à¥\87à¤\81 सà¥\8dवà¥\80à¤\95ार नà¥\88 à¤\95à¤\8fल à¤\9cा सà¤\95à¥\88à¤\8f।\nà¤\8fà¤\95à¤\9fा मानà¥\8dय à¤\88-पतà¥\8dर सà¤\82à¤\95à¥\87त लिà¤\96à¥\82 वा à¤\93à¤\87 सà¥\8dथानà¤\95à¥\87à¤\81 à¤\96ालà¥\80 à¤\95रà¥\81।",
- "cannotchangeemail": "à¤\96ाता à¤\88-पतà¥\8dर सà¤\82केत ऐ विकिपर बदलल नै जा सकैए।",
+ "emailauthenticated": "à¤\85हाà¤\81à¤\95 à¤\88-पतà¥\8dर सà¤\99à¥\8dà¤\95à¥\87त $2 à¤\95 $3 बजे सत्यापित भेल।",
+ "emailnotauthenticated": "à¤\85हाà¤\81à¤\95 à¤\88-पतà¥\8dर सà¤\99à¥\8dà¤\95à¥\87त à¤\85à¤\96न धरि सतà¥\8dयापित नà¥\88 à¤à¥\87ल à¤\85à¤\9bि।\nनिà¤\9aा दà¥\87ल à¤\97à¥\87ल à¤\95à¥\8bनà¥\8b सà¥\81विधाà¤\95 लà¥\87ल à¤\85हाà¤\81à¤\95 ई-पत्र नै भेजल जाएत।",
+ "noemailprefs": "à¤\88 सà¥\81विधा सठà¤\95ऽ पà¥\8dरयà¥\8bà¤\97 à¤\95रà¤\8fà¤\95 लà¥\87ल à¤\85पन विà¤\95लà¥\8dपमà¥\87 à¤\88-पतà¥\8dर पता राà¤\96à¥\80।",
+ "emailconfirmlink": "à¤\85पन à¤\88-पतà¥\8dर सà¤\99à¥\8dà¤\95à¥\87त सतà¥\8dयापित à¤\95रà¥\80",
+ "invalidemailaddress": "à¤\85मानà¥\8dय पà¥\8dरारà¥\82पà¤\95 à¤\95ारण à¤\90 à¤\88-पतà¥\8dर सà¤\99à¥\8dà¤\95à¥\87तà¤\95 सà¥\8dवà¥\80à¤\95ार नà¥\88 à¤\95à¤\8fल à¤\9cा सà¤\95à¥\88à¤\8f।\nà¤\8fà¤\95à¤\9fा मानà¥\8dय à¤\88-पतà¥\8dर सà¤\99à¥\8dà¤\95à¥\87त लिà¤\96à¥\80 वा à¤\93à¤\87 सà¥\8dथानà¤\95à¥\87 à¤\96ालà¥\80 à¤\95रà¥\80।",
+ "cannotchangeemail": "à¤\96ाता à¤\88-पतà¥\8dर सà¤\99à¥\8dकेत ऐ विकिपर बदलल नै जा सकैए।",
"emaildisabled": "ई अन्तर्जाल ई-पत्र नै पठाएत।",
"accountcreated": "खाता खुजि गेल",
"accountcreatedtext": "[[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|वार्ता]]) के लेल खाता खोलल गेल अछि।",
"php-mail-error-unknown": "पी.एच.पी.कऽ समाद कार्य() मे अज्ञात दोष भेल।",
"user-mail-no-addy": "बिन ई-पत्र संकेतक ई-पत्र पठेबाक प्रयास कएल गेल।",
"user-mail-no-body": "एकटा खाली वा बहुत कनिका ई-पत्र भेजवाक प्रयास कल गेल।",
- "changepassword": "à¤\95à¥\82à¤\9fशबà¥\8dद बदलà¥\82",
- "resetpass_announce": "समà¥\8dपà¥\8dरवà¥\87श समà¥\8dपà¥\82रà¥\8dण à¤\95रबा लà¥\87ल, à¤\85हाà¤\81 à¤\8fà¤\95à¤\9fा नव à¤\95à¥\82à¤\9fशबà¥\8dद à¤\8fतà¤\8f निरà¥\8dधारित à¤\95रà¥\81।",
+ "changepassword": "à¤\95à¥\82à¤\9fशबà¥\8dद बदलà¥\80",
+ "resetpass_announce": "समà¥\8dपà¥\8dरवà¥\87श समà¥\8dपà¥\82रà¥\8dण à¤\95रबा लà¥\87ल, à¤\85हाà¤\81 à¤\8fà¤\95à¤\9fा नव à¤\95à¥\82à¤\9fशबà¥\8dद à¤\8fतà¤\8f निरà¥\8dधारित à¤\95रà¥\80।",
"resetpass_text": "<!-- पाठ एतऽ लिखू -->",
- "resetpass_header": "à¤\96ाता à¤\95à¥\82à¤\9fशबà¥\8dद बदलà¥\82",
+ "resetpass_header": "à¤\96ाता à¤\95à¥\82à¤\9fशबà¥\8dद बदलà¥\80",
"oldpassword": "पुरान कूटशब्द",
"newpassword": "नव कूटशब्द",
- "retypenew": "नव à¤\95à¥\82à¤\9fशबà¥\8dद फà¥\87रसà¤\81 à¤\9fà¤\82à¤\95ित à¤\95रà¥\82",
- "resetpass_submit": "à¤\95à¥\82à¤\9fशबà¥\8dद बनाà¤\89 à¤\86 समà¥\8dपà¥\8dरवà¥\87श à¤\95रà¥\82",
- "changepassword-success": "à¤\85हाà¤\81à¤\95 पासवरà¥\8dड सफलतासँ बदलि देल गेल!",
- "changepassword-throttled": "à¤\85हाà¤\81 ढ़à¥\87र रास समà¥\8dपà¥\8dरवà¥\87श पà¥\8dरयास à¤\95à¥\87लहà¥\81à¤\81।\nफà¥\87र पà¥\8dरयास $1 à¤\95रबासà¤\81 पहिनà¥\87 à¤\95नà¥\87 à¤\95ाल थमà¥\8dहà¥\82।",
+ "retypenew": "नव à¤\95à¥\82à¤\9fशबà¥\8dद फà¥\87रसà¤\81 à¤\9fà¤\82à¤\95ित à¤\95रà¥\80",
+ "resetpass_submit": "à¤\95à¥\82à¤\9fशबà¥\8dद बनाà¤\89 à¤\86 समà¥\8dपà¥\8dरवà¥\87श à¤\95रà¥\80",
+ "changepassword-success": "à¤\85हाà¤\81à¤\95 à¤\95à¥\82à¤\9fशबà¥\8dद सफलतासँ बदलि देल गेल!",
+ "changepassword-throttled": "अहाँ ढेर रास सम्प्रवेश प्रयास केलहुँ।\nफेर प्रयास $1 करबासँ पहिने कने काल थम्हू।",
"botpasswords": "बोट पासवर्ड",
"botpasswords-disabled": "बोट पासवर्ड अखन निष्क्रिय अछि।",
"botpasswords-no-central-id": "बोट पासवर्डक उपयोग करएक लेल अहाँक मुख्य खातासँ प्रवेश करै पडत।",
"resetpass-expired": "अहाँके कूटशब्दक वैधता अवधि खत्तम भऽ गेल अछि । कृपया सम्प्रवेशित करवाक लेल नयाँ कूटशब्द राखु।",
"resetpass-expired-soft": "अहाँके कूटशब्दकऽ वैधता अवधि समाप्त भऽ गेल आर कूटशब्द परिवार्तान करवाक आवश्यकता अछि। कृपया एगो नव कूटशब्द राखु, वा पाछु रिसेट करवाक लेल \"{{int:resetpass-submit-cancel}}\" क्लिक करु।",
"resetpass-validity-soft": "अहाँके कूटशब्द मान्य नै अछि: $1 \n\nकृपया आब एगो नव कूटशब्द चुनु, वा पाछु पुनर्स्थापित करए के लेल \"{{int:resetpass-submit-cancel}}\" में क्लिक करू।",
- "passwordreset": "à¤\95à¥\82à¤\9fशबà¥\8dद फà¥\87रसà¤\81 बनाà¤\89",
- "passwordreset-text-one": "à¤\85पन à¤\95à¥\82à¤\9fशबà¥\8dद रà¥\80सà¥\87à¤\9f à¤\95रवाà¤\95 लà¥\87ल à¤\87 फारम à¤à¤°à¥\81 ।",
- "passwordreset-text-many": "{{PLURAL:$1|à¤\88-पतà¥\8dरà¤\95à¥\87 माधà¥\8dयमसऽ à¤\8fà¤\95à¤\9fा à¤\85सà¥\8dथायà¥\80 à¤\95à¥\82à¤\9fशबà¥\8dद पावà¥\88लà¥\87ल à¤\95à¥\8bनà¥\8b à¤\8fà¤\95à¤\9fा डिबà¥\8dबा à¤à¤°à¥\81 ।}}",
+ "passwordreset": "à¤\95à¥\82à¤\9fशबà¥\8dद फà¥\87रसà¤\81 बनाबà¥\80",
+ "passwordreset-text-one": "à¤\85पन à¤\95à¥\82à¤\9fशबà¥\8dद रà¥\80सà¥\87à¤\9f à¤\95रवाà¤\95 लà¥\87ल à¤\87 फारम à¤à¤°à¥\80।",
+ "passwordreset-text-many": "{{PLURAL:$1|à¤\88-पतà¥\8dरà¤\95à¥\87 माधà¥\8dयमसऽ à¤\8fà¤\95à¤\9fा à¤\85सà¥\8dथायà¥\80 à¤\95à¥\82à¤\9fशबà¥\8dद पावà¥\88लà¥\87ल à¤\95à¥\8bनà¥\8b à¤\8fà¤\95à¤\9fा डिबà¥\8dबा à¤à¤°à¥\80।}}",
"passwordreset-disabled": "कूटशब्द फेरसँ बनाएब ऐ विकीपर अक्षम कएल अछि।",
"passwordreset-emaildisabled": "कूटशब्द फेरसँ बनाएब ऐ विकीपर अक्षम कएल अछि।",
"passwordreset-username": "प्रयोक्तानाम",
"passwordreset-capture": "परिणाम ई-पत्र देखू?",
"passwordreset-capture-help": "जँ अहाँ ऐ बक्शाकेँ देखै छी, ई-पत्र (तात्कालिक कूटशब्दक संग) अहाँकेँ देखाएल जाएत आ संगे प्रयोक्ताकेँ पठाएल जाएत।",
"passwordreset-email": "ई-पत्र संकेत",
- "passwordreset-emailtitle": "लेखा विवरण {{अन्तर्जालक नाम}}",
- "passwordreset-emailtext-ip": "कियो (सम्भवतः अहाँ, अन्तर्जाल सेवा कल्पक $1 सँ) अपन लेखा विवरणक पुनःस्मरणक लेल अनुरोध केलहुँ ऐ लेल {{ अन्तर्जालक नाम}} ($4). ई प्रयोक्ता {{PLURAL:$3|लेखा अछि| लेखा सभ अछि}}\nऐ ई-पत्र संकेतसँ सम्बन्धित:\n\n$2\n\n{{PLURAL:$3|ई अल्पकालक कूटशब्द| ई सभ अल्पकालक कूटशब्द}} खतम भऽ जाएत {{PLURAL:$5|एक दिन|$5 पाँच दिन}}.\nअहाँ सम्प्रवेश करू आ एकटा नव कूटशब्द चुनू।. जौं कियो आन ई आग्रह केने अछि, वा अहाँकेँ अपन पुरान कूटशब्द मोन पड़ि गेल अछि , आ आब एकरा बदलबाक इच्छा नै राखै छी तँ अहाँ ऐ संदेशकेँ बिसरि जाउ आ अपन पुरान कूटशब्दक प्रयोग करैत रहू।",
+ "passwordreset-emailtitle": "{{SITENAME}} पर लेखा विवरण",
+ "passwordreset-emailtext-ip": "कियो (सम्भवतः अहाँ, अन्तर्जाल सेवा कल्पक $1 सँ) अपन लेखा विवरणक पुनःस्मरणक लेल अनुरोध केलहुँ ऐ लेल {{SITENAME}} ($4). ई प्रयोक्ता {{PLURAL:$3|लेखा अछि|लेखा सभ अछि}}\nऐ ई-पत्र संकेतसँ सम्बन्धित:\n\n$2\n\n{{PLURAL:$3|ई अल्पकालक कूटशब्द| ई सभ अल्पकालक कूटशब्द}} खतम भऽ जाएत {{PLURAL:$5|एक दिन|$5 पाँच दिन}}.\nअहाँ सम्प्रवेश करू आ एकटा नव कूटशब्द चुनू।. जौं कियो आन ई आग्रह केने अछि, वा अहाँकेँ अपन पुरान कूटशब्द मोन पड़ि गेल अछि , आ आब एकरा बदलबाक इच्छा नै राखै छी तँ अहाँ ऐ संदेशकेँ बिसरि जाउ आ अपन पुरान कूटशब्दक प्रयोग करैत रहू।",
"passwordreset-emailtext-user": "प्रयोक्ता $1 {{अन्तर्जाल}} पर अहाँक खाता विवरणक {{SITENAME}} लेल फेरसँ ($4) आग्रह केने छथि। ई प्रयोक्ता {{PLURAL:$3|खाता अछि|खाता सभ अछि}} ऐ ई-पत्र संकेतसँ जुड़ल: $2\n{{PLURAL:$3| ई अस्थायी कूटशब्द|ई सभ अस्थायी कूटशब्द}} खतम भऽ जाएत {{PLURAL:$5|एक दिन|$5 दिन}} मे।\nअहाँ सम्प्रवेश करू आ एकटा नव कूटशब्द आब चुनू। जँ कियो दोसर ई आग्रह केने छथि, वा जँ अहाँकेँ अपन मूल कूटशब्द मोन पड़ि गेल अछि, आ अहाँ आब ओइ कूटशब्दकेँ नै बदलऽ चाहै छी, अहाँ ऐ संदेशकेँ बिसरि सकै छी आ अपन पुरान कूटशब्दक प्रयोग जारी राखि सकै छी।",
"passwordreset-emailelement": "प्रयोक्ता: \n$1\n\nअस्थायी कूटशब्द: \n$2",
"passwordreset-emailsentemail": "एकटा ई-पत्र मोन पाड़बा लेल पठाओल गेल अछि।",
"resettokens-token-label": "$1 (वर्तमान मूल्य: $2)",
"resettokens-watchlist-token": "[[Special:Watchlist|अहाँके साकांक्षसूची के पृष्ठसभ में परिवर्तन सभ]] के वेब फिट (Atom/RSS) लेल स्तोक",
"resettokens-done": "टोकन रीसेट भेल अछि।",
- "resettokens-resetbutton": "à¤\9bानल à¤\9fà¥\8bà¤\95न रà¥\80सà¥\87à¤\9f à¤\95रà¥\81",
- "bold_sample": "à¤\97à¤\81हà¥\80र लà¥\87à¤\96न",
- "bold_tip": "à¤\97à¤\81हà¥\80र लà¥\87à¤\96न",
+ "resettokens-resetbutton": "à¤\9aà¥\81नल à¤\9fà¥\8bà¤\95न रà¥\80सà¥\87à¤\9f à¤\95रà¥\80",
+ "bold_sample": "मà¥\8bà¤\9f पाठ",
+ "bold_tip": "मà¥\8bà¤\9f पाठ",
"italic_sample": "कटि लेखन",
"italic_tip": "क़टि लेखन",
- "link_sample": "लिà¤\82à¤\95 à¤\89पाधि",
- "link_tip": "à¤\85à¤\82तरà¤\82à¤\97 à¤\87शारा",
- "extlink_sample": "http://www.example.com लिà¤\82à¤\95 à¤\89पाधि",
- "extlink_tip": "बहरà¥\80 लिà¤\82à¤\95 (यादि राà¤\96à¥\82 http:// उपसर्ग)",
- "headline_sample": "मà¥\81à¤\96à¥\8dयपà¤\82à¤\95à¥\8dति लà¥\87à¤\96न",
- "headline_tip": "सà¥\8dतर 2 मà¥\81à¤\96à¥\8dयपà¤\82à¤\95à¥\8dति",
- "nowiki_sample": "फà¥\89रà¥\8dमà¥\87à¤\9f विहà¥\80न लà¥\87à¤\96 à¤\8fतय",
- "nowiki_tip": "विà¤\95à¥\80 फà¥\89रमà¥\87à¤\9fिà¤\82à¤\97à¤\95à¥\87à¤\81 à¤\9bà¥\8bड़à¥\82",
+ "link_sample": "लिà¤\99à¥\8dà¤\95 शà¥\80रà¥\8dषà¤\95",
+ "link_tip": "à¤\86नà¥\8dतरिà¤\95 लिà¤\99à¥\8dà¤\95",
+ "extlink_sample": "http://www.example.com लिà¤\99à¥\8dà¤\95 शà¥\80रà¥\8dषà¤\95",
+ "extlink_tip": "बाहà¥\8dय लिà¤\99à¥\8dà¤\95 (यादि राà¤\96à¥\80 http:// उपसर्ग)",
+ "headline_sample": "शà¥\80रà¥\8dषà¤\95 पाठ",
+ "headline_tip": "दà¥\8dवितà¥\80य-सà¥\8dतर शà¥\80रà¥\8dषà¤\95",
+ "nowiki_sample": "à¤\85पà¥\8dरारà¥\82पित पाठà¤\8fतय राà¤\96à¥\80",
+ "nowiki_tip": "विà¤\95à¥\80 पà¥\8dरारà¥\82पण नà¤\9cरà¤\85नà¥\8dदाà¤\9c à¤\95रà¥\80",
"image_sample": "उदाहरण.jpg",
"image_tip": "समाहित चित्र",
"media_sample": "उदाहरण.ogg",
"hr_tip": "अक्षांशीय पंक्ति (अल्प उपयोग)",
"summary": "सारांश:",
"subject": "विषय:",
- "minoredit": "à¤\85लà¥\8dप सà¤\82पादन",
- "watchthis": "à¤\8fहि पà¥\83षà¥\8dठà¤\95à¥\87à¤\81 दà¥\87à¤\96à¥\82",
- "savearticle": "पनà¥\8dनाà¤\95 रà¤\95à¥\8dषण à¤\95रà¥\82",
+ "minoredit": "à¤\85लà¥\8dप समà¥\8dपादन",
+ "watchthis": "à¤\88 पà¥\83षà¥\8dठà¤\95à¥\87 धà¥\8dयानसà¥\82à¤\9aà¥\80मà¥\87 राà¤\96à¥\80",
+ "savearticle": "पनà¥\8dनाà¤\95 रà¤\95à¥\8dषण à¤\95रà¥\80",
"preview": "पूर्वावलोकन",
"showpreview": "पूर्वप्रदर्शन",
- "showdiff": "परिवरà¥\8dतà¥\8dतन दà¥\87à¤\96ाà¤\8a",
- "blankarticle": "<strong>à¤\9aà¥\87तावनà¥\80:</strong> à¤\86हाà¤\81 à¤\8fà¤\95 रिà¤\95à¥\8dत पनà¥\8dना à¤\95à¥\87 निरà¥\8dमाण à¤\95à¤\87र रहल à¤\9bà¥\80।\nयदि à¤\86हाà¤\81 \"{{int:savearticle}}\" à¤\95à¥\8b पà¥\81नà¤\83 दाबà¤\88 à¤\9aिà¤\8f त पनà¥\8dना à¤\95à¥\87 बिना à¤\95à¥\8bनà¥\8b सामà¤\97à¥\8dरà¥\80 à¤\95à¥\87 निरà¥\8dमित à¤\95à¥\8dया सà¤\95à¥\88à¤\9aिà¤\8f ।",
- "anoneditwarning": "'''à¤\9aà¥\87तà¥\8cनà¥\80:''' à¤\85हाà¤\81 समà¥\8dपà¥\8dरवà¥\87शित नà¥\88 à¤\9bà¥\80।\nà¤\85हाà¤\81à¤\95 à¤\85निà¤\95à¥\87त à¤\90 पन्नाक सम्पादन इतिहासमे दर्ज कएल जाएत।",
- "anonpreviewwarning": "'' अहाँ सम्प्रवेशित नै छी। अखन रक्षण केलासँ अहाँक अनिकेत पता ऐ पन्नाक सम्पादन इतिहासमे दर्ज भऽ जाएत।''",
- "missingsummary": "'''स्मारक:''' अहाँ सम्पादन सार नै देने छी।\nजँ अहाँ फेरसँ क्लिक करब \"{{int:savearticle}}\", अहाँक सम्पादन बिना एकर संरक्षित भऽ जाएत।",
+ "showdiff": "परिवरà¥\8dतन दà¥\87à¤\96ाबà¥\80",
+ "blankarticle": "<strong>à¤\9aà¥\87तावनà¥\80:</strong> à¤\85हाà¤\81 à¤\8fà¤\95 रिà¤\95à¥\8dत पनà¥\8dना à¤\95à¥\87 निरà¥\8dमाण à¤\95रि रहल à¤\9bà¥\80।\nयदि à¤\85हाà¤\81 \"{{int:savearticle}}\" à¤\95 पà¥\81नà¤\83 दाबबà¥\88 त पनà¥\8dनाà¤\95 बिना à¤\95à¥\8bनà¥\8b सामà¤\97à¥\8dरà¥\80à¤\95 निरà¥\8dमित ठà¤\9cाà¤\8fत।",
+ "anoneditwarning": "'''à¤\9aà¥\87तà¥\8cनà¥\80:''' à¤\85हाà¤\81 समà¥\8dपà¥\8dरवà¥\87शित नà¥\88 à¤\9bà¥\80।\nà¤\85हाà¤\81à¤\95 à¤\85निà¤\95à¥\87त à¤\88 पन्नाक सम्पादन इतिहासमे दर्ज कएल जाएत।",
+ "anonpreviewwarning": "<em>अहाँ सम्प्रवेशित नै छी। अखन रक्षण केलासँ अहाँक अनिकेत पता ई पन्नाक सम्पादन इतिहासमे दर्ज भऽ जाएत।</em>",
+ "missingsummary": "<strong>स्मारक:</strong> अहाँ सम्पादन सार नै देने छी।\nजँ अहाँ फेरसँ क्लिक करब \"{{int:savearticle}}\", अहाँक सम्पादन बिना एकर संरक्षित भऽ जाएत।",
"selfredirect": "<strong>चेतावनी:</strong> आहाँ स्वेम के ई पन्ना पुनः निर्देशीत कएर रहल छी।\nआहाँ अनुप्रेषित के लेल गलत लक्ष्य निर्दिष्ट भ्या सकएत अछि, या आहाँ गलत पन्ना कें संपादन कैर सकएत छी।\nआहाँ फेरो से \"{{int:savearticle}}\" क्लिक करएत छी, रीडायरेक्ट ओनाहो भी बनाबल जेल अछि।",
"missingcommenttext": "कृपा कऽ अपन विचार नीचाँ प्रविष्ट करू।",
"missingcommentheader": "'''स्मरण:''' अहाँ कोनो विषय/ शीर्षक ऐ टिप्पणीक लेल नै देने छी।\nजँ अहाँ फेरसँ क्लिक करब \"{{int:savearticle}}\" , अहाँक सम्पादन बिना एकर संरक्षित भऽ जाएत।",
"blockednoreason": "कोनो कारण देल नै अछि।",
"whitelistedittext": "अहाँकेँ $1पन्ना सम्पादन करबा लेल",
"confirmedittext": "पन्ना सभक सम्पादन केलासँ पूर्व अहाँ अपन ई-पत्र संकेतकेँ सत्यापित करू।\nकृपा कऽ अपन ई-पत्र पता दर्ज करू आ सत्यापित करू ऐ सँ [[Special:Preferences|प्रयोक्ताक पसिन्न सभ]]",
- "nosuchsectiontitle": "सà¤\82वरà¥\8dà¤\97 नà¥\88 ताà¤\95ि सà¤\95ल",
- "nosuchsectiontext": "à¤\85हाà¤\81 à¤\8fहन सà¤\82वरà¥\8dà¤\97à¤\95à¥\87à¤\81 सम्पादित करबाक प्रयास केलहुँ जे अछि नै।\nअहाँ जखन ई पन्ना देख रहल छलहुँ तखन ई मेटा देल गेल हएत वा दोसर ठाम हटा देल गेल हएत।",
+ "nosuchsectiontitle": "à¤\8fहन à¤\95à¥\8bनà¥\8b à¤\85नà¥\81à¤à¤¾à¤\97 शà¥\80रà¥\8dषà¤\95 नà¥\88 à¤\85à¤\9bि",
+ "nosuchsectiontext": "à¤\85हाà¤\81 à¤\8fहन à¤\85नà¥\81à¤à¤¾à¤\97à¤\95 सम्पादित करबाक प्रयास केलहुँ जे अछि नै।\nअहाँ जखन ई पन्ना देख रहल छलहुँ तखन ई मेटा देल गेल हएत वा दोसर ठाम हटा देल गेल हएत।",
"loginreqtitle": "सम्प्रवेश आवश्यक",
"loginreqlink": "सम्प्रवेश",
"loginreqpagetext": "अहाँ निश्चयरूपेँ $1 दोसर पन्ना देखबाक लेल।",
"accmailtext": "एकटा बिना क्रमबला निर्माण पद्धतिसँ कूटशब्दक निर्माण [[User talk:$1|$1]] लेल $2 केँ पठाएल गेल अछि।\n\nऐ खाताक कूटशब्द बदलल जा सकैए ''[[Special:ChangePassword|कूटशब्द बदलू]]'' पन्नापर सम्प्रवेश केलाक बाद।",
"newarticle": "(नव)",
"newarticletext": "अहाँ एहेन पन्नाक लिंकक अनुसरण कऽ आएल छी जे पन्ना अखन बनले नै अछि।\nपन्ना बनेबाक लेल नीचाँक बक्शामे टाइप केनाइ शुरू करू (देखू [$1 सहायता पन्ना] विषेष जानकारी लेल)।",
- "anontalkpagetext": "----'' à¤\88 à¤\8fà¤\95à¤\9fा à¤\85नाम पà¥\8dरयà¥\8bà¤\95à¥\8dताà¤\95 लà¥\87ल वारà¥\8dता पनà¥\8dना à¤\9bà¥\80 à¤\9cà¥\87 à¤\85à¤\96न धरि à¤\85पन à¤\96ाता नà¥\88 à¤\96à¥\8bलनà¥\87 à¤\9bथि, वा à¤\9cà¥\87 à¤\8fà¤\95र पà¥\8dरयà¥\8bà¤\97 नà¥\88 à¤\95रà¥\88 à¤\9bथि।\nहमरा सà¤à¤\95à¥\87à¤\81 तà¤\87 लà¥\87ल à¤\85à¤\82à¤\95à¥\80य à¤\85निà¤\95à¥\87तà¤\95 पà¥\8dरयà¥\8bà¤\97 हà¥\81नà¤\95ा दà¥\87à¤\96ार à¤\95रबा लà¥\87ल à¤\95रऽ पड़ि रहल à¤\85à¤\9bि।\nà¤\90 तरहà¤\95 à¤\85निà¤\95à¥\87त à¤\85नà¥\87à¤\95 पà¥\8dरयà¥\8bà¤\95à¥\8dता दà¥\8dवारा साà¤\9dà¥\80 à¤\95à¤\8fल à¤\9cा सà¤\95à¥\88त à¤\85à¤\9bि।\nà¤\9cà¤\81 à¤\85हाà¤\81 à¤\85नाम पà¥\8dरयà¥\8bà¤\95à¥\8dता à¤\9bà¥\80 à¤\86 बà¥\81à¤\9dà¥\88 à¤\9bà¥\80 à¤\9cà¥\87 बिना मतलबà¤\95 à¤\9fिपà¥\8dपणà¥\80 à¤\85हाà¤\81 दिस दà¥\87ल à¤\9cा रहल à¤\85à¤\9bि, तà¤\81 à¤\95à¥\83पा à¤\95ऽ [[Special:UserLogin/signup|à¤\8fà¤\95à¤\9fा à¤\96ाता à¤\96à¥\8bलà¥\82]] वा [[Special:UserLogin|समà¥\8dपà¥\8dरवà¥\87श]] à¤\9cà¤\87सà¤\81 à¤à¤µà¤¿à¤·à¥\8dयमà¥\87 à¤\86न à¤\85नाम पà¥\8dरयà¥\8bà¤\95à¥\8dतासà¤\81 à¤\85हाà¤\81à¤\95à¥\87à¤\81 दिक्कत नै हो।''",
+ "anontalkpagetext": "----'' à¤\88 à¤\8fà¤\95à¤\9fा à¤\85नाम पà¥\8dरयà¥\8bà¤\95à¥\8dताà¤\95 लà¥\87ल वारà¥\8dता पनà¥\8dना à¤\9bà¥\80 à¤\9cà¥\87 à¤\85à¤\96न धरि à¤\85पन à¤\96ाता नà¥\88 à¤\96à¥\8bलनà¥\87 à¤\9bथि, वा à¤\9cà¥\87 à¤\8fà¤\95र पà¥\8dरयà¥\8bà¤\97 नà¥\88 à¤\95रà¥\88 à¤\9bथि।\nहमरा सà¤à¤\95à¥\87à¤\81 तà¤\87 लà¥\87ल à¤\85à¤\82à¤\95à¥\80य à¤\85निà¤\95à¥\87तà¤\95 पà¥\8dरयà¥\8bà¤\97 हà¥\81नà¤\95ा दà¥\87à¤\96ार à¤\95रबा लà¥\87ल à¤\95रऽ पडि रहल à¤\85à¤\9bि।\nà¤\90 तरहà¤\95 à¤\85निà¤\95à¥\87त à¤\85नà¥\87à¤\95 पà¥\8dरयà¥\8bà¤\95à¥\8dता दà¥\8dवारा साà¤\9dà¥\80 à¤\95à¤\8fल à¤\9cा सà¤\95à¥\88त à¤\85à¤\9bि।\nà¤\9cà¤\81 à¤\85हाà¤\81 à¤\85नाम पà¥\8dरयà¥\8bà¤\95à¥\8dता à¤\9bà¥\80 à¤\86 बà¥\81à¤\9dà¥\88 à¤\9bà¥\80 à¤\9cà¥\87 बिना मतलबà¤\95 à¤\9fिपà¥\8dपणà¥\80 à¤\85हाà¤\81 दिस दà¥\87ल à¤\9cा रहल à¤\85à¤\9bि, तà¤\81 à¤\95à¥\83पा à¤\95ऽ [[Special:CreateAccount|à¤\8fà¤\95à¤\9fा à¤\96ाता à¤\96à¥\8bलà¥\80]] वा [[Special:UserLogin|समà¥\8dपà¥\8dरवà¥\87श]] à¤\9cà¤\87सà¤\81 à¤à¤µà¤¿à¤·à¥\8dयमà¥\87 à¤\86न à¤\85नाम पà¥\8dरयà¥\8bà¤\95à¥\8dतासà¤\81 à¤\85हाà¤\81à¤\95 दिक्कत नै हो।''",
"noarticletext": "अखन ई पन्नापर कोनो पाठ नै अछि।\nअहाँ [[Special:Search/{{PAGENAME}}|ई पन्नाक शीर्षक ताकी]] आन पन्नापर,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} सम्बन्धी वृत्तलेख ताकी],\nआकि [{{fullurl:{{FULLPAGENAME}}|action=edit}} ई पन्नाक निर्माण करी]</span>।",
"noarticletext-nopermission": "अखन ऐ पन्नापर कोनो पाठ नै अछि।\nअहाँ [[Special:Search/{{PAGENAME}}|ऐ पन्ना शीर्षक लेल ताकू]]",
"missing-revision": "\"{{FULLPAGENAME}}\" पन्ना के अवतरण #$1 मौजूद नई अछि ।\n\nओन त ई एक हट्याल गेल पन्ना के पुराना कडी पे क्लिक करबाक कारण से होएत अछि।\nअधिक जानकारी के लेल आहाँ [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} हटाबै के लॉग] देख सकै अछि।",
"updated": "(अद्यतन कएल)",
"note": "'''टिप्पणी:'''",
"previewnote": "'''मोन राखू ई मातर पूर्वावलोकन छी।'''\nअहाँक परिवर्तन अखन धरि सँचिआएल नै गेल अछि!",
- "continue-editing": "सà¤\82पादन à¤\95à¥\8dषà¥\87तà¥\8dर à¤\9cाà¤\89",
- "previewconflict": "ई पूर्वदृश्य देखबैए उपरका सम्पादन क्षेत्रक पाठ , ई आएत जखन अहाँ संरक्षित करब।",
+ "continue-editing": "समà¥\8dपादन à¤\95à¥\8dषà¥\87तà¥\8dर à¤\9cाà¤\8f",
+ "previewconflict": "ई पूर्वदृश्य देखबैए उपरका सम्पादन क्षेत्रक पाठ, ई आएत जखन अहाँ संरक्षित करब।",
"session_fail_preview": "''' दुखी छी! अहाँक सत्रक दत्तांश खतम भऽ गेल तै कारणसँ अहाँक सम्पादनक निपटारा नै भऽ सकल।'''\nफेरसँ प्रयास करू।\nजँ ई फेरसँ काज नै करैए, प्रयोग करू [[Special:UserLogout|निष्क्रमण]] आ फेर सम्प्रवेश करू।",
"session_fail_preview_html": "''' दुखी छी! हम अहाँक सम्पादनक निष्पादन नै कऽ सकलहुँ कारण सत्रक दत्तांश खतम भऽ गेल।'''\n''कारण {{अन्तर्जाल}} लग काँच एच.टी.एम.एल. दत्तांश सक्रिय छै, पूर्वदृश्य जावास्क्रिप्ट आक्रमणक डरसँ नुकाएल राखल गेल अछि।''\n'''जँ ई वैध सम्पादन प्रयास अछि, कृपा कऽ पुनः प्रयास करू।'''\nजँ ई अखनो काज नै कऽ रहल अछि, प्रयास करू [[Special:UserLogout|निष्क्रमण कऽ रहल छी]] आ फेरसँ सम्प्रवेश।",
"token_suffix_mismatch": "'''अहाँक सम्पादन अस्वीकार कऽ देल गेल अछि कारण अहाँक ग्राहक प्रेष्यमान अंक विधानक विराम चेन्ह सभकेँ नष्ट कऽ देलन्हि।'''\nई सम्पादन पन्नाक पाठकेँ दूषित होएबासँ बचेबा लेल अमान्य कऽ देल गेल।\nई कखनो काल होइए जखन अहाँ जाल आधारित अनाम दोसरा लेल चल सेवा प्रयुक्त करै छी।",
"permissionserrorstext-withaction": "अहाँके अनुमति नै अछि $2 लेल, ऐ लेल {{PLURAL:$1|कारण|कारण सभ}}:",
"recreate-moveddeleted-warn": "'''चेतौनी''': अहाँ फेरसँ ओ पन्ना बना रहल छी जे पहिने मेटा देल गेल छै।'''\n\nअहाँ विचारू जे की ई सम्पादन केनाइ उचित अछि।\nऐ पन्नाक मेटाएल बला आ हटाएल वृत्तलेख एतए सुविधा लेल देल जा रहल अछि:",
"moveddeleted-notice": "ई पन्ना मेटा देल गेल अछि।\nऐ पन्ना लेल मेटाएल आ हटाएल बला वृत्तलेख सन्दर्भ लेल नीचाँ देल गेल अछि।",
- "log-fulllog": "सà¤à¤\9fा वà¥\83तà¥\8dतलà¥\87à¤\96 दà¥\87à¤\96à¥\82",
+ "log-fulllog": "सà¤à¤\9fा वà¥\83तà¥\8dतलà¥\87à¤\96 दà¥\87à¤\96à¥\80",
"edit-hook-aborted": "सम्पादन नोकसीसँ खतम भेल।\nई कोनो कारण नै देलक।",
"edit-gone-missing": "पन्ना अद्यतन नै भऽ सकल।\nलगैए जे ई मेटा देल गेल अछि।",
"edit-conflict": "सम्पादन अन्तर",
"edit-no-change": "अहाँक सम्पादनपर ध्यान नै देल गेल, कारण ऐ सँ पाठमे कोनो परिवर्तन नै आएल।",
"postedit-confirmation-created": "पन्ना निर्माण करल गेल अछि ।",
"postedit-confirmation-restored": "पन्नाके पुराण स्थितिमे लौने गेल अछि ।",
- "postedit-confirmation-saved": "अहाके संपादनके सुरक्षित भेल ।",
+ "postedit-confirmation-saved": "अहाक सम्पादन सुरक्षित भेल ।",
"edit-already-exists": "नव पन्नाक निर्माण नै भऽ सकल।\nई पहिनहियेसँ वर्तमान अछि।",
- "defaultmessagetext": "पà¥\82रà¥\8dवनिरà¥\8dधारित सà¤\82देश पाठ",
+ "defaultmessagetext": "पà¥\82रà¥\8dवनिरà¥\8dधारित सनà¥\8dदेश पाठ",
"content-failed-to-parse": "$1 के लेल $2 सामग्री के बिच्छेदन करए में विफल, त्रुटि: $3",
"invalid-content-data": "अवैध डाटा सामग्री",
"content-not-allowed-here": "[[$2]] पृष्ठ पर \"$1\" सामग्री वर्जित अछि।",
"currentrevisionlink": "नूतन संशोधन",
"cur": "हीन",
"next": "आगाँ",
- "last": "à¤\85à¤\82तिम",
+ "last": "पिà¤\9bला",
"page_first": "पहिल",
"page_last": "अन्तिम",
"histlegend": "फाइल तुलना तंत्रांशक चयन: संशोधन तुलनाक रेडियो बक्शाकेँ चिन्हित करू आ एन्टर बटन क्लिक करू वा सभसँ नीचाँक बटन क्लिक करू। <br />\nकहबी: '''({{int:cur}})''' = अद्यतन संशोधनसँ अन्तर, '''({{int:last}})''' = अद्यतनसँ पहिलुका संशोधनसँ अन्तर, '''{{int:minoreditletter}}''' = मामूली सम्पादन।",
"rev-suppressed-unhide-diff": "ऐ तुलना निर्धारकक कोनो एकटा संशोधन '''दबाएल''' गेल अछि।\nवर्णन ताकि सकै छी [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} suppression log] मे।\nअहाँ अखनो [$1 ई तुलना निर्धारक देखू] जँ अहाँ आगाँ बढ़ऽ चाहै छी।",
"rev-deleted-diff-view": "ई पन्ना संशोधनऐ तुलना निर्धारकक कोनो एकटा संशोधन '''मेटाएल''' गेल अछि।\nअहाँ एकरा देख सकै छी; वर्ण भेट सकैए [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] मे।",
"rev-suppressed-diff-view": "ऐ तुलना निर्धारकक कोनो एकटा संशोधन '''दबाएल''' गेल अछि।\nअहाँ एकरा देख सकै छी; वर्णन भेट सकैए [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} suppression log]मे।",
- "rev-delundel": "दà¥\87à¤\96ाà¤\89/ नà¥\81à¤\95ाà¤\89",
- "rev-showdeleted": "दà¥\87à¤\96ाà¤\89",
- "revisiondelete": "मà¥\87à¤\9fाà¤\89 / सà¤\82शà¥\8bधन फà¥\87रसà¤\81 à¤\86नà¥\82",
+ "rev-delundel": "दà¥\83षà¥\8dà¤\9fिà¤\95à¥\81शलता बदलà¥\80",
+ "rev-showdeleted": "दà¥\87à¤\96ाबà¥\80",
+ "revisiondelete": "à¤\85वतरण हà¤\9fाबà¥\80/पà¥\81नरà¥\8dसà¥\8dथापित à¤\95रà¥\80",
"revdelete-nooldid-title": "अमान्य लक्ष्य संशोधन",
"revdelete-nooldid-text": "अहाँ चाहे तँ ऐ प्रकार्यक निष्पादन लेल कोनो विशेष लक्ष्य संशोधन नै तँए-तफसिला केने छी, विशेष संशोधन नै उपस्थित अछि, वा अहाँ वर्तमान संशोधनकेँ नुकेबाक प्रयास कऽ रहल छी।",
"revdelete-no-file": "विषिष्ट संचिका अछिये नै।",
"revdelete-failure": "$1'''संशोधन दृश्यता अद्यतन नै कएल जा सकल:'''",
"logdelete-success": "'''वृत्तलेख दृश्यता सफलतासँ निर्धारित भेल।'''",
"logdelete-failure": "'''वृत्तलेख दृश्यता निर्धारित नै भऽ सकल।'''$1",
- "revdel-restore": "दà¥\83षà¥\8dà¤\9fिà¤\95à¥\81शलता बदलà¥\82",
+ "revdel-restore": "दà¥\83षà¥\8dà¤\9fिà¤\95à¥\81शलता बदलà¥\80",
"pagehist": "पन्नाक इतिहास",
"deletedhist": "मेटाएल इतिहास",
"revdelete-hide-current": "तिथि $2, $1 क अनुक्रमकेँ नुकेबा काल भ्रम: ई वर्तमान संशोधन छी।\nई नुकाएल नै जा सकैए।",
"suppressionlogtext": "नीचाँ मेटाएल आ प्रतिबन्धक उल्लेख अछि जे संचालकसँ नुकाएल सामिग्री अछि।\nअखन स्थित प्रभावी प्रतिबन्ध आ अवरोध लेल देखू [[Special:BlockList|IP block list]] ।",
"mergehistory": "मिज्झर भेल पन्ना सभक इतिहास",
"mergehistory-header": "ई पन्ना अहाँकेँ एकटा स्रोत पन्नाक एकटा नव पन्नामे संशोधन इतिहासकेँ मिज्झर करबाक अनुमति दैत अछि।\nसुनिश्चित होउ जे ई परिवर्तन ऐतिहासिक पन्ना सांतत्य स्थापित करत।",
- "mergehistory-box": "दू पन्नाक संशोधनकेँ मिज्झर करू।",
+ "mergehistory-box": "दू पन्नाक संशोधन मिज्झर करी।",
"mergehistory-from": "मूल पन्ना:",
"mergehistory-into": "लक्ष्य पन्ना:",
"mergehistory-list": "मिज्झर योग्य सम्पादन इतिहास",
"mergehistory-merge": "[[:$1]] एकर संशोधन सभकेँ [[:$2]] मे मिलाएल जा सकैए।\nरेडियो बटन स्तम्भक प्रयोग मात्र संशोधनकेँ निर्धारित समए वा ओइसँ पहिने मिज्झर करबामे प्रयोग करू।\nमोन राखू जे उपर नीचाँक लागिक प्रयोग ऐ स्तम्भकेँ पुनर्स्थापित कऽ देत।",
"mergehistory-go": "मिज्झर होइ योग्य सम्पादन सभकेँ देखाउ",
- "mergehistory-submit": "संशोधन सभकेँ मिज्झर करू",
+ "mergehistory-submit": "संशोधन सभके मिज्झर करी",
"mergehistory-empty": "कोनो संशोधन मिज्झर नै कएल जा सकैए।",
"mergehistory-done": "$3 {{PLURAL:$3|संशोधन|संशोधन सभ}} एकर $1 सफलता पूर्वक मिज्झर कएल गेल [[:$2]] मे।",
"mergehistory-fail": "इतिहासक मिश्रणकेँ नै कऽ सकल, कृपा कऽ पन्ना आ समए परिमितिकेँ फेरसँ जाँचू।",
"difference-title-multipage": "\"$1\" आर \"$2\" पृष्ठसभ मे अंतर",
"difference-multipage": "(पन्ना सभक बीचमे अन्तर)",
"lineno": "पंक्त्ति $1:",
- "compareselectedversions": "à¤\9aयन à¤\95à¤\8fल सà¤\82शà¥\8bधन सà¤à¤\95 तà¥\81लना à¤\95रà¥\82",
- "showhideselectedversions": "दà¥\87à¤\96ाà¤\89/ नà¥\81à¤\95ाà¤\89 à¤\9aयनित सà¤\82शà¥\8bधन सà¤",
+ "compareselectedversions": "à¤\9aयन à¤\95à¤\8fल सà¤\82शà¥\8bधन सà¤à¤\95 तà¥\81लना à¤\95रà¥\80",
+ "showhideselectedversions": "à¤\9aयनित à¤\85वतरण दà¥\87à¤\96ाबà¥\80/नà¥\81à¤\95ाबà¥\80",
"editundo": "असम्पादन",
"diff-empty": "(कोनो अंतर नै)",
"diff-multi-sameuser": "(इ प्रयोक्ताद्वारा {{PLURAL:$1|कएल गेल बीचके एक अवतरण नै देखाओल गेल |कएल गेल बीचके $1 अवतरण नै देखाओल गेल}})",
"searchprofile-images": "दृश्य-श्रव्य",
"searchprofile-everything": "सभटा",
"searchprofile-advanced": "विशिष्ट",
- "searchprofile-articles-tooltip": "$1 मà¥\87 ताà¤\95à¥\82",
+ "searchprofile-articles-tooltip": "$1 मà¥\87 ताà¤\95à¥\80",
"searchprofile-images-tooltip": "सञ्चिकासभ लेल ताकी",
"searchprofile-everything-tooltip": "सभटा सामिग्रीमे ताकू (चर्चा पन्ना सहित)",
- "searchprofile-advanced-tooltip": "बनाà¤\8fल नामसà¥\8dथान सà¤à¤®à¥\87 ताà¤\95à¥\82",
+ "searchprofile-advanced-tooltip": "बनाà¤\8fल नामसà¥\8dथान सà¤à¤®à¥\87 ताà¤\95à¥\80",
"search-result-size": "$1 ({{PLURAL:$2|1 शब्द|$2 शब्दसभ}})",
"search-result-category-size": "{{PLURAL:$1|1 सदस्य|$1 सदस्य}} ({{PLURAL:$2|1 उपसंवर्ग|$2 उपसंवर्ग}}, {{PLURAL:$3|1 संचिका|$3 संचिका}})",
"search-redirect": "(रस्ता बदलेन $1)",
"search-category": "(श्रेणी $1)",
"search-file-match": "(फाइल सामग्रीसे मेल खेलक अछि)",
"search-suggest": "अहाँ मोने अछि जे:$1",
- "search-interwiki-caption": "समà¥\8dबनà¥\8dधित परियà¥\8bà¤\9cना सà¤",
- "search-interwiki-default": "$1 सà¤à¤\9fा परिणाम:",
+ "search-interwiki-caption": "à¤\85नà¥\8dय पà¥\8dरà¤\95लà¥\8dप",
+ "search-interwiki-default": "$1 सà¤\81 परिणाम:",
"search-interwiki-more": "(आर)",
"search-relatedarticle": "सम्बन्धी",
"searchrelated": "सम्बन्धी",
"search-error": "खोजवाके समय निम्न त्रुटि उत्पन्न भेल: $1",
"preferences": "विकल्प",
"mypreferences": "खासमखास",
- "prefs-edits": "समà¥\8dपादनà¤\95 सà¤\82à¤\96à¥\8dया",
- "prefsnologintext2": "अपन वरीयतासभके बदलैक लेल $1 करू।",
+ "prefs-edits": "समà¥\8dपादनà¤\95 सà¤\99à¥\8dà¤\96à¥\8dया:",
+ "prefsnologintext2": "अपन वरीयतासभके बदलैक लेल कृपया सम्प्रवेश करी।",
"prefs-skin": "रूप",
"skin-preview": "पूर्वावलोकन",
"datedefault": "कोनो मोनपसंद नै",
"prefs-personal": "प्रयोक्ता परिचय",
"prefs-rc": "हालक परिवर्तन",
"prefs-watchlist": "साकांक्ष-सूची",
- "prefs-editwatchlist": "साà¤\95ाà¤\82à¤\95à¥\8dषसà¥\82à¤\9aà¥\80 बदलà¥\82",
+ "prefs-editwatchlist": "साà¤\95ाà¤\82à¤\95à¥\8dषसà¥\82à¤\9aà¥\80 बदलà¥\80",
"prefs-editwatchlist-label": "अपन साकांक्षसूचीक प्रविष्टिसभ सम्पादित करी:",
"prefs-editwatchlist-edit": "देखी आर अपन साकांक्षसूची पर शीर्षकके हटाबी।",
"prefs-editwatchlist-raw": "काँच साकांक्षसूची संपादित करी",
"prefs-editwatchlist-clear": "अपन साकांक्षसूची खालि करी",
"prefs-watchlist-days": "साकांक्ष-सूचीमे एतेक दिन देखाएल:",
"prefs-watchlist-days-max": "बेसीसँ बेसी $1 {{PLURAL:$1|दिन|दिन}}",
- "prefs-watchlist-edits": "बढ़ाà¤\8fल साà¤\95ाà¤\82à¤\95à¥\8dष सà¥\82à¤\9aà¥\80मà¥\87 à¤\85धिà¤\95तम परिवरà¥\8dतन दà¥\87à¤\96ाà¤\8fब:",
+ "prefs-watchlist-edits": "बढाएल साकांक्ष सूचीमे अधिकतम परिवर्तन देखाएब:",
"prefs-watchlist-edits-max": "बेसीसँ बेसी:१०००",
"prefs-watchlist-token": "साकांक्ष-सूची खेप:",
"prefs-misc": "आर",
- "prefs-resetpass": "à¤\95à¥\82à¤\9fशबà¥\8dद बदलà¥\82",
+ "prefs-resetpass": "à¤\95à¥\82à¤\9fशबà¥\8dद बदलà¥\80",
"prefs-changeemail": "ई-पत्र संकेत बदलू",
- "prefs-setemail": "à¤\88-पतà¥\8dर सà¤\82à¤\95à¥\87त निरà¥\8dधारित à¤\95रà¥\82",
- "prefs-email": "à¤\88-पतà¥\8dर à¤\9aà¥\81नाव",
+ "prefs-setemail": "à¤\88-पतà¥\8dर सà¤\82à¤\95à¥\87त निरà¥\8dधारित à¤\95रà¥\80",
+ "prefs-email": "à¤\88-पतà¥\8dर विà¤\95लà¥\8dपसà¤",
"prefs-rendering": "मुँहकान",
"saveprefs": "सुरक्षित करू",
"restoreprefs": "सभटा पूर्वनिर्धारित चयनकेँ फेरसँ आनू",
"prefs-editing": "सम्पादन कऽ रहल छी",
"rows": "पाँती सभ",
"columns": "स्तम्भ सभ",
- "searchresultshead": "ताà¤\95à¥\82",
+ "searchresultshead": "ताà¤\95à¥\80",
"stub-threshold": "सीमा <a href=\"#\" class=\"stub\">काटल लागि</a> सँचियाएल (अष्टक):",
"stub-threshold-sample-link": "उदाहरण",
"stub-threshold-disabled": "अशक्त कएल",
"recentchangesdays": "आइ-काल्हिक परिवर्तनमे कतेक दिन देखाएल गेल:",
"recentchangesdays-max": "बेसीसँ बेसी $1 {{PLURAL:$1|दिन|दिन}}",
"recentchangescount": "पूर्वनिर्धारित रूपेँ एतेक सम्पादन देखाएल गेल:",
- "prefs-help-recentchangescount": "à¤\90 मे सम्मिलित अछि आइ-काल्हिक परिवर्तन, पन्नाक इतिहास आ वृत्तलेख",
+ "prefs-help-recentchangescount": "à¤\8fहिमे सम्मिलित अछि आइ-काल्हिक परिवर्तन, पन्नाक इतिहास आ वृत्तलेख",
"prefs-help-watchlist-token2": "इ अहाँके कंक्षाकसूचीके वेब फिडके गोपनीय चाभी छी ।\nइ जे कोइ लंग अछि उ अपन कंक्षाकसूची पैढ सकैत अछि, ऐ लेल इ क्यों गोटा स नै बाटब ।\n[[Special:ResetTokens|एकरा रीसेट करवाक लेल यै ठाम क्लिक करु]]।",
"savedprefs": "अहाँक पसिन्न सुरक्षित कएल गेल",
"savedrights": "प्रयोक्ता {{GENDER:$1|$1}}क सदस्य अधिकार सङ्ग्रह कएल गेल।",
"timezonelegend": "समय क्षेत्र",
"localtime": "स्थानीय समए:",
- "timezoneuseserverdefault": "पà¥\82रà¥\8dवनिरà¥\8dधारित वितरà¤\95 पà¥\8dरयà¥\81à¤\95à¥\8dत à¤\95रà¥\82 ($1)",
- "timezoneuseoffset": "à¤\86न (सà¤\82तà¥\81लन à¤\95à¥\87निहारà¤\95 निरà¥\8dदà¥\87श à¤\95रà¥\82)",
+ "timezoneuseserverdefault": "पà¥\82रà¥\8dवनिरà¥\8dधारित वितरà¤\95 पà¥\8dरयà¥\81à¤\95à¥\8dत à¤\95रà¥\80 ($1)",
+ "timezoneuseoffset": "à¤\86न (सनà¥\8dतà¥\81लन à¤\95à¥\87निहारà¤\95 निरà¥\8dदà¥\87श à¤\95रà¥\80)",
"servertime": "वितरक समए:",
- "guesstimezone": "à¤\97वà¥\87षà¤\95à¤\95 पà¥\8dरयà¥\8bà¤\97 à¤\95ऽ à¤à¤°à¥\82",
- "timezoneregion-africa": "à¤\85फà¥\8dरà¥\80का",
+ "guesstimezone": "à¤\97वà¥\87षà¤\95à¤\95 पà¥\8dरयà¥\8bà¤\97 à¤\95ऽ à¤à¤°à¥\80",
+ "timezoneregion-africa": "à¤\85फà¥\8dरिका",
"timezoneregion-america": "अमेरिका",
- "timezoneregion-antarctica": "à¤\85à¤\82टार्कटिका",
+ "timezoneregion-antarctica": "à¤\85नà¥\8dटार्कटिका",
"timezoneregion-arctic": "आर्कटिक",
- "timezoneregion-asia": "à¤\8fशिया",
- "timezoneregion-atlantic": "à¤\85à¤\9fलाà¤\82टिक महासागर",
+ "timezoneregion-asia": "à¤\8fसिया",
+ "timezoneregion-atlantic": "à¤\85à¤\9fलानà¥\8dटिक महासागर",
"timezoneregion-australia": "अस्ट्रेलिया",
"timezoneregion-europe": "यूरोप",
- "timezoneregion-indian": "हिà¤\82द महासागर",
- "timezoneregion-pacific": "पà¥\8dरशाà¤\82त महासागर",
- "allowemail": "à¤\86न पà¥\8dरयà¥\8bà¤\95à¥\8dताà¤\95 à¤\88-पतà¥\8dर समरà¥\8dथ à¤\95रà¥\82",
- "prefs-searchoptions": "à¤\96à¥\8bà¤\9c विà¤\95लà¥\8dप",
- "prefs-namespaces": "नामस्थान सभ",
+ "timezoneregion-indian": "हिनà¥\8dद महासागर",
+ "timezoneregion-pacific": "पà¥\8dरशानà¥\8dत महासागर",
+ "allowemail": "à¤\86न पà¥\8dरयà¥\8bà¤\95à¥\8dताà¤\95 à¤\88-पतà¥\8dर समरà¥\8dथ à¤\95रà¥\80",
+ "prefs-searchoptions": "ताà¤\95à¥\80",
+ "prefs-namespaces": "नामस्थानसभ",
"default": "पूर्वनिर्धारित",
"prefs-files": "संचिका सभ",
"prefs-custom-css": "खास सी.एस.एस.",
"username": "{{GENDER:$1|प्रयोगकर्तानाम}}:",
"prefs-memberingroups": "निम्नलिखित {{PLURAL:$1|समूह|समूहसभ}}क {{GENDER:$2|सदस्य}}:",
"prefs-memberingroups-type": "$1",
- "prefs-registration": "पà¤\82जीकरणक समए:",
+ "prefs-registration": "पà¤\9eà¥\8dजीकरणक समए:",
"prefs-registration-date-time": "$1",
"yourrealname": "असली नाम:",
"yourlanguage": "भाषा:",
"prefs-help-email-others": "अहाँ ई विकल्प चुनि सकै छी जे अहाँकेँ दोसरा द्वारा ई-पत्रसँ, अहाँक प्रयोक्ता वा वार्ता पन्नापर देल लिंकक माध्यमसँ, सम्पर्क कएल जा सकए।\nअहाँक ई-पत्र संकेतक खुलासा नै हएत जखन कियो आन अहाँसँ सम्पर्क करत।",
"prefs-help-email-required": "ई-पत्र संकेत जरूरी अछि।",
"prefs-info": "न्यूनतम जानकारी",
- "prefs-i18n": "à¤\85à¤\82तर्राष्ट्रियकरण",
- "prefs-signature": "à¤\9aà¥\87नà¥\8dहासà¥\80",
- "prefs-dateformat": "तिथिक बगेबानी",
+ "prefs-i18n": "à¤\85नà¥\8dतर्राष्ट्रियकरण",
+ "prefs-signature": "हसà¥\8dताà¤\95à¥\8dषर",
+ "prefs-dateformat": "तिथि प्रारूप",
"prefs-timeoffset": "समए संशोधक",
"prefs-advancedediting": "विशिष्ट विकल्प सभ",
- "prefs-editor": "सà¤\82पादक",
+ "prefs-editor": "समà¥\8dपादक",
"prefs-preview": "पूर्वावलोकन",
- "prefs-advancedrc": "विशिष्ट विकल्प सभ",
- "prefs-advancedrendering": "विशिष्ट विकल्प सभ",
- "prefs-advancedsearchoptions": "विशिष्ट विकल्प सभ",
- "prefs-advancedwatchlist": "विशिष्ट विकल्प सभ",
- "prefs-displayrc": "दृश्य विकल्प सभ",
- "prefs-displaywatchlist": "दृश्य विकल्प सभ",
+ "prefs-advancedrc": "विशिष्ट विकल्पसभ",
+ "prefs-advancedrendering": "विशिष्ट विकल्पसभ",
+ "prefs-advancedsearchoptions": "विशिष्ट विकल्पसभ",
+ "prefs-advancedwatchlist": "विशिष्ट विकल्पसभ",
+ "prefs-displayrc": "दृश्य विकल्पसभ",
+ "prefs-displaywatchlist": "दृश्य विकल्पसभ",
"prefs-tokenwatchlist": "टोकन",
"prefs-diffs": "अन्तर निर्धारक सभ",
"prefs-help-prefershttps": "इ प्राथमिकता अहाँके फेर स सम्प्रवेश करलाक बाद प्रभाव पडत।",
"prefs-tabs-navigation-hint": "सुझाव: अहाँ टैब्स सूचीमे टैब्सके बीच आवागमन करवाक लेल बाम आर दाहिना बागलके कुंजिसभके उपयोग कइर सकैत छी।",
"userrights": "प्रयोक्ता अधिकारक प्रबन्धन",
- "userrights-lookup-user": "पà¥\8dरयà¥\8bà¤\95à¥\8dता सà¤\82वरà¥\8dà¤\97 सà¤à¤\95 पà¥\8dरबनà¥\8dध à¤\95रà¥\82",
- "userrights-user-editname": "à¤\8fà¤\95à¤\9fा पà¥\8dरयà¥\8bà¤\95à¥\8dतानाम लिà¤\96à¥\82:",
+ "userrights-lookup-user": "पà¥\8dरयà¥\8bà¤\95à¥\8dता समà¥\82हसà¤à¤\95 पà¥\8dरबनà¥\8dध à¤\95रà¥\80",
+ "userrights-user-editname": "à¤\8fà¤\95à¤\9fा पà¥\8dरयà¥\8bà¤\95à¥\8dतानाम लिà¤\96à¥\80:",
"editusergroup": "{{GENDER:$1|सदस्य}} समूहसभक सम्पादन करी",
"editinguser": "सदस्य '''[[User:$1|$1]]''' $2 क अधिकार बदलि\n{{GENDER:$1|सदस्य}}क सदस्य अधिकार बदलल जा रहल अछि <strong>[[User:$1|$1]]</strong> $2",
"userrights-editusergroup": "प्रयोक्ता संवर्ग सभक सम्पादन करू",
"group-bureaucrat": "अधिकारी",
"group-suppress": "नुकाबए वाला",
"group-all": "(सभ)",
- "group-user-member": "{{लिंग:$1|प्रयोक्ता}}",
- "group-autoconfirmed-member": "{{लिंग:$1|स्वतःअनुमोदित प्रयोक्ता}}",
- "group-bot-member": "{{लिंग:$1|स्वचालक}}",
- "group-sysop-member": "{{लिंग:$1|माइनजन}}",
- "group-bureaucrat-member": "{{लिंग:$1|अधिकारी}}",
+ "group-user-member": "{{GENDER:$1|प्रयोगकर्ता}}",
+ "group-autoconfirmed-member": "{{GENDER:$1|स्वतः स्थापित प्रयोगकर्ता}}",
+ "group-bot-member": "{{GENDER:$1|बोट}}",
+ "group-sysop-member": "{{GENDER:$1|प्रबन्धक}}",
+ "group-bureaucrat-member": "{{GENDER:$1|प्रशासक}}",
"group-suppress-member": "{{GENDER:$1|नुकाए वाला}}",
- "grouppage-user": "{{ns:project}}:पà¥\8dरयà¥\8bà¤\95à¥\8dता सभ",
- "grouppage-autoconfirmed": "{{ns:project}}:स्वतःअनुमोदित प्रयोक्ता सभ",
- "grouppage-bot": "{{ns:project}}:स्वचालक सभ",
- "grouppage-sysop": "{{ns:project}}:माà¤\87नà¤\9cन सà¤",
- "grouppage-bureaucrat": "{{ns:project}}:अधिकारी सभ",
+ "grouppage-user": "{{ns:project}}:पà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dतासभ",
+ "grouppage-autoconfirmed": "{{ns:project}}:स्वतःअनुमोदित प्रयोक्तासभ",
+ "grouppage-bot": "{{ns:project}}:स्वचालकसभ",
+ "grouppage-sysop": "{{ns:project}}:पà¥\8dरबनà¥\8dधà¤\95",
+ "grouppage-bureaucrat": "{{ns:project}}:अधिकारीसभ",
"grouppage-suppress": "{{ns:project}}:नुकाबी",
"right-read": "पन्ना सभ पढ़ू",
- "right-edit": "पन्ना सभ सम्पादन करू",
- "right-createpage": "पन्ना सभ बनाउ (जे वार्ता पन्ना नै हुअए)",
- "right-createtalk": "वार्ता पन्ना सभ बनाउ",
- "right-createaccount": "नव प्रयोक्ता खाता सभ बनाउ",
+ "right-edit": "पन्नासभ सम्पादन करी",
+ "right-createpage": "पन्नासभ बनाबी (जे वार्ता पन्ना नै हुअए)",
+ "right-createtalk": "वार्ता पन्नासभ बनाबी",
+ "right-createaccount": "नव प्रयोक्ता खातासभ बनाबी",
"right-autocreateaccount": "बाहरी खातासँ स्वतः प्रवेश",
"right-minoredit": "सम्पादन सभकेँ मामूली चिन्हित करू",
- "right-move": "पनà¥\8dना सठà¤\98सà¤\95ाà¤\89",
- "right-move-subpages": "पनà¥\8dना सà¤à¤\95à¥\87à¤\81 à¤\89पपनà¥\8dना सà¤à¤\95 सà¤\82à¤\97 à¤\98सà¤\95ाà¤\89",
- "right-move-rootuserpages": "मà¥\82ल पà¥\8dरयà¥\8bà¤\95à¥\8dता पनà¥\8dना सठà¤\98सà¤\95ाà¤\89",
- "right-move-categorypages": "शà¥\8dरà¥\87णà¥\80 पà¥\83षà¥\8dठसà¥\8dथानाà¤\82तरित à¤\95रà¥\82",
- "right-movefile": "सà¤\82à¤\9aिà¤\95ा सà¤à¤\95à¥\87à¤\81 à¤\98सà¤\95ाà¤\89",
- "right-suppressredirect": "पनà¥\8dना à¤\98सà¤\95à¥\87बा à¤\95ाल मà¥\82ल पनà¥\8dना सà¤à¤¸à¤\81 लाà¤\97ि सठनà¥\88 बनाà¤\89",
- "right-upload": "सà¤\82à¤\9aिà¤\95ा सठà¤\89पारà¥\8bपित à¤\95रà¥\82",
- "right-reupload": "वरà¥\8dतमान सà¤\82à¤\9aिà¤\95ा सà¤à¤\95 पà¥\81नरà¥\8dलà¥\87à¤\96न à¤\95रà¥\82",
- "right-reupload-own": "अपन उपारोपित पन्ना सभक पुनर्लेखन करू",
+ "right-move": "पनà¥\8dना à¤\98सà¤\95ाबà¥\80",
+ "right-move-subpages": "पà¥\83षà¥\8dठà¤\89पपà¥\83षà¥\8dठसठसहित à¤\98सà¤\95ाबà¥\80",
+ "right-move-rootuserpages": "मà¥\82ल पà¥\8dरयà¥\8bà¤\95à¥\8dता पनà¥\8dना à¤\98सà¤\95ाबà¥\80",
+ "right-move-categorypages": "शà¥\8dरà¥\87णà¥\80 पà¥\83षà¥\8dठà¤\98सà¤\95ाबà¥\80",
+ "right-movefile": "सà¤\9eà¥\8dà¤\9aिà¤\95ा सठà¤\98सà¤\95ाबà¥\80",
+ "right-suppressredirect": "पà¥\83षà¥\8dठà¤\98सà¤\95à¥\87बाà¤\95ाल पà¥\81नरà¥\8dनिरà¥\8dदà¥\87श नà¥\88 à¤\9bà¥\8bडà¥\80",
+ "right-upload": "सà¤\9eà¥\8dà¤\9aिà¤\95ासठà¤\89पारà¥\8bपित à¤\95रà¥\80",
+ "right-reupload": "वरà¥\8dतमान सà¤\9eà¥\8dà¤\9aिà¤\95ासà¤à¤\95 पà¥\81नरà¥\8dलà¥\87à¤\96न à¤\95रà¥\80",
+ "right-reupload-own": "अपन उपारोपित पन्नासभक पुनर्लेखन करी",
"right-reupload-shared": "श्रव्य-दृश्य साझी बखारीक फाइलक पुनर्लेखन स्थानीय रूपेँ करू।",
"right-upload_by_url": "सार्वत्रिक विभव संकेतसँ संचिका उपारोपित करू",
"right-purge": "जालक उपस्मृतिकेँ बिना स्वीकृतिक पन्नाक लेल खतम करू",
"right-deleterevision": "निर्धारित संशोधित पन्ना मेटाउ आ फेरसँ आनू",
"right-deletedhistory": "मेटाएल इतिहास प्रविष्टि देखू, बिना लागिक पाठक",
"right-deletedtext": "मेटाएल पाठ आ दूटा मेटाएल संशोधनक बीचक परिवर्तन देखू",
- "right-browsearchive": "मà¥\87à¤\9fाà¤\8fल पनà¥\8dना सà¤à¤\95à¥\87à¤\81 ताà¤\95à¥\82",
- "right-undelete": "पनà¥\8dना फà¥\87रसà¤\81 à¤\86नà¥\82",
+ "right-browsearchive": "मà¥\87à¤\9fाà¤\8fल पनà¥\8dना ताà¤\95à¥\80",
+ "right-undelete": "पनà¥\8dना फà¥\87रसà¤\81 à¤\86नà¥\80",
"right-suppressrevision": "संचालकसँ नुकाएल संशोधनकेँ पुनरीक्षित करू आ फेरसँ आनू",
"right-viewsuppressed": "कोनो प्रयोक्ताके नुकाएल संसोधन देखु",
"right-suppressionlog": "व्यक्तिगत वृत्तलेख देखू",
"rightslog": "प्रयोक्ता अधिकार वृत्तलेख",
"rightslogtext": "ई प्रयोक्ता अधिकार परिवर्तन सभक वृतलेख छी।",
"action-read": "ई पन्ना पढ़ू",
- "action-edit": "ई पन्नाकेँ सम्पादित करू",
+ "action-edit": "ई पन्नाक सम्पादित करी",
"action-createpage": "पन्ना सभ बनाउ",
- "action-createtalk": "वारà¥\8dता पनà¥\8dना सठबनाà¤\89",
- "action-createaccount": "à¤\88 पà¥\8dरयà¥\8bà¤\95à¥\8dता à¤\96ाता बनाà¤\89",
- "action-history": "पन्नाक इतिहासकेँ मिज्झर करू",
- "action-minoredit": "ऐ सम्पादनकेँ मामूली कहू",
- "action-move": "ऐ पृष्ठकेँ घसकाउ",
- "action-move-subpages": "ऐ पन्ना आ एकर उपपन्नाकेँ घसकाउ",
- "action-move-rootuserpages": "मà¥\82ल पà¥\8dरयà¥\8bà¤\95à¥\8dता पनà¥\8dना सठà¤\98सà¤\95ाà¤\89",
- "action-move-categorypages": "शà¥\8dरà¥\87णà¥\80 पà¥\83षà¥\8dठसà¥\8dथानाà¤\82तरित à¤\95रà¥\82",
+ "action-createtalk": "वारà¥\8dता पनà¥\8dना बनाबà¥\80",
+ "action-createaccount": "à¤\88 पà¥\8dरयà¥\8bà¤\95à¥\8dता à¤\96ाता बनाबà¥\80",
+ "action-history": "पन्नाक इतिहास मिज्झर करी",
+ "action-minoredit": "ऐ सम्पादनके मामूली कही",
+ "action-move": "ऐ पृष्ठके घसकाबी",
+ "action-move-subpages": "ऐ पन्ना आ एकर उपपन्नाके घसकाबी",
+ "action-move-rootuserpages": "मà¥\82ल पà¥\8dरयà¥\8bà¤\95à¥\8dता पनà¥\8dना à¤\98सà¤\95ाबà¥\80",
+ "action-move-categorypages": "शà¥\8dरà¥\87णà¥\80 पà¥\83षà¥\8dठà¤\98सà¤\95ाबà¥\80",
"action-movefile": "ई संचिकाकेँ घसकाउ",
"action-upload": "ई संचिकाकेँ उपारोपित करू",
"action-reupload": "ई संचिकाक पुनर्लेखन करू",
"recentchanges-label-unpatrolled": "ऐ सम्पादनक पुनरीक्षण अखन धरि नै कएल गेल अछि।",
"recentchanges-label-plusminus": "पन्नाके आकार इ बाइट संख्यासे बदलल गेल",
"recentchanges-legend-heading": "<strong>कुञ्जी:</strong>",
- "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|नयाà¤\81 पनà¥\8dनसà¤à¤\95à¥\87 सà¥\82à¤\9aà¥\80]] सहà¥\8b दà¥\87à¤\96à¥\81)",
+ "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|नव पनà¥\8dनसà¤à¤\95 सà¥\82à¤\9aà¥\80]] सà¥\87हà¥\8b दà¥\87à¤\96à¥\80)",
"rcnotefrom": "नीचाँमे '''$2''' सँ भेल परिवर्तन अछि ('''$1''' धरि देखाएल)।",
"rclistfrom": "$3 $2 सँ शुरू भेल नव परिवर्तन देखू",
- "rcshowhideminor": "$1 à¤\85लà¥\8dप सà¤\82पादन",
- "rcshowhideminor-show": "दà¥\87à¤\96ाà¤\89",
- "rcshowhideminor-hide": "नà¥\81à¤\95ाà¤\8a",
- "rcshowhidebots": "$1 स्वचालक सभ",
- "rcshowhidebots-show": "दà¥\87à¤\96ाà¤\89",
- "rcshowhidebots-hide": "नà¥\81à¤\95ाà¤\8a",
- "rcshowhideliu": "$1 सम्प्रवेशित प्रयोक्ता सभ",
- "rcshowhideliu-show": "दà¥\87à¤\96ाà¤\89",
- "rcshowhideliu-hide": "नà¥\81à¤\95ाà¤\8a",
- "rcshowhideanons": "$1 अज्ञात प्रयोक्ता सभ",
- "rcshowhideanons-show": "दà¥\87à¤\96ाà¤\8a",
- "rcshowhideanons-hide": "नà¥\81à¤\95ाà¤\8a",
- "rcshowhidepatr": "$1 सà¤\82चालित सम्पादन",
- "rcshowhidepatr-show": "दà¥\87à¤\96ाà¤\89",
- "rcshowhidepatr-hide": "नà¥\81à¤\95ाà¤\8a",
- "rcshowhidemine": "$1 हमर सम्पादन सभ",
- "rcshowhidemine-show": "दà¥\87à¤\96ाà¤\89",
- "rcshowhidemine-hide": "नà¥\81à¤\95ाà¤\8a",
+ "rcshowhideminor": "$1 à¤\85लà¥\8dप समà¥\8dपादन",
+ "rcshowhideminor-show": "दà¥\87à¤\96ाबà¥\80",
+ "rcshowhideminor-hide": "नà¥\81à¤\95ाबà¥\80",
+ "rcshowhidebots": "$1 स्वचालक",
+ "rcshowhidebots-show": "दà¥\87à¤\96ाबà¥\80",
+ "rcshowhidebots-hide": "नà¥\81à¤\95ाबà¥\80",
+ "rcshowhideliu": "पञ्जीकृत प्रयोगकर्तासभ $1",
+ "rcshowhideliu-show": "दà¥\87à¤\96ाबà¥\80",
+ "rcshowhideliu-hide": "नà¥\81à¤\95ाबà¥\80",
+ "rcshowhideanons": "$1 अज्ञात प्रयोक्तासभ",
+ "rcshowhideanons-show": "दà¥\87à¤\96ाबà¥\80",
+ "rcshowhideanons-hide": "नà¥\81à¤\95ाबà¥\80",
+ "rcshowhidepatr": "$1 सà¤\9eà¥\8dचालित सम्पादन",
+ "rcshowhidepatr-show": "दà¥\87à¤\96ाबà¥\80",
+ "rcshowhidepatr-hide": "नà¥\81à¤\95ाबà¥\80",
+ "rcshowhidemine": "$1 हमर सम्पादनसभ",
+ "rcshowhidemine-show": "दà¥\87à¤\96ाबà¥\80",
+ "rcshowhidemine-hide": "नà¥\81à¤\95ाबà¥\80",
"rcshowhidecategorization-show": "देखाबी",
"rcshowhidecategorization-hide": "नुकाबी",
"rclinks": "देखाऊ अंतिम $1 परिवर्त्तन अंतिम $2 दिनमे<br />$3",
"diff": "अन्तर",
"hist": "इति.",
- "hide": "नà¥\81à¤\95ाà¤\8a",
- "show": "दà¥\87à¤\96ाà¤\89",
+ "hide": "नà¥\81à¤\95ाबà¥\80",
+ "show": "दà¥\87à¤\96ाबà¥\80",
"minoreditletter": "अ",
"newpageletter": "न",
"boteditletter": "ब",
"rc-enhanced-expand": "वर्णन देखाउ (जावास्क्रिप्ट चाही)",
"rc-enhanced-hide": "वर्णन नुकाउ",
"rc-old-title": "मूल रूप स \"$1\" नाम स बनाएल गेल रह",
- "recentchangeslinked": "सà¤\82बà¤\82धित परिवरà¥\8dत्तन",
- "recentchangeslinked-feed": "सà¤\82बà¤\82धित परिवरà¥\8dत्तन",
+ "recentchangeslinked": "समà¥\8dबनà¥\8dधित परिवर्तन",
+ "recentchangeslinked-feed": "समà¥\8dबनà¥\8dधित परिवर्तन",
"recentchangeslinked-toolbox": "सम्बन्धित परिवर्तन",
"recentchangeslinked-title": "\"$1\" मे भेल परिवर्तन",
"recentchangeslinked-summary": "ई विशेष पन्नासँ सम्बद्ध पन्ना सभमे (आकि कोनो विशेष वर्गक समूहमे) भेल परिवर्तनक सूची छी ।\n[[Special:Watchlist|your watchlist]] पर पन्नासभ '''गाढ़''' अछि।",
"randomredirect-nopages": "नामस्थान \"$1\" मे कोनो बदलेनबला लागि नै अछि।",
"statistics": "सांख्यिकी",
"statistics-header-pages": "पन्नाक सांख्यिकी",
- "statistics-header-edits": "साà¤\82à¤\96à¥\8dयिà¤\95à¥\80à¤\95 समà¥\8dपादन à¤\95रà¥\82",
- "statistics-header-users": "पà¥\8dरयà¥\8bà¤\95à¥\8dता साà¤\82à¤\96à¥\8dयिà¤\95à¥\80",
- "statistics-header-hooks": "दà¥\8bसर साà¤\82à¤\96à¥\8dयिà¤\95à¥\80",
+ "statistics-header-edits": "समà¥\8dपादन तथà¥\8dयाà¤\99à¥\8dà¤\95",
+ "statistics-header-users": "पà¥\8dरयà¥\8bà¤\95à¥\8dता तथà¥\8dयाà¤\99à¥\8dà¤\95",
+ "statistics-header-hooks": "दà¥\8bसर तथà¥\8dयाà¤\99à¥\8dà¤\95",
"statistics-articles": "अनुक्रम पन्ना सभ",
"statistics-pages": "पन्ना सभ",
"statistics-pages-desc": "वार्ता पन्ना, बदलेन इत्यादि सहित सभटा विकि पन्ना सभ।",
"statistics-files": "उपारोपित संचिका सभ",
- "statistics-edits": "{{अन्तर्जाल}} अएबासँ लऽ कऽ भेल पन्ना सम्पादन सभ।",
+ "statistics-edits": "{{SITENAME}} अएबासँ लऽ कऽ भेल पन्ना सम्पादन",
"statistics-edits-average": "प्रति पन्ना औसत सम्पादन",
- "statistics-users": "पà¤\82जीकृत [[Special:ListUsers|प्रयोक्ता]]",
+ "statistics-users": "पà¤\9eà¥\8dजीकृत [[Special:ListUsers|प्रयोक्ता]]",
"statistics-users-active": "सक्रिय प्रयोक्ता",
"statistics-users-active-desc": "प्रयोक्ता जे अन्तिम {{PLURAL:$1|दिन|$1 दिन}} मे कोनो काज केने छथि",
"pageswithprop-submit": "जाऊ",
"double-redirect-fixer": "बदलेन स्थायित्व",
"brokenredirects": "टूटल बदलेन सभ",
"brokenredirectstext": "ई बदलेन सभ नै अवस्थित पन्ना सभक दिस जाइत अछि।",
- "brokenredirects-edit": "सà¤\82पादन à¤\95रà¥\82",
- "brokenredirects-delete": "मà¥\87à¤\9fाà¤\89",
- "withoutinterwiki": "बिना à¤à¤¾à¤·à¤¾ लाà¤\97िà¤\95 पनà¥\8dना सà¤",
+ "brokenredirects-edit": "समà¥\8dपादन à¤\95रà¥\80",
+ "brokenredirects-delete": "मà¥\87à¤\9fाबà¥\80",
+ "withoutinterwiki": "बिना à¤à¤¾à¤·à¤¾ लिà¤\99à¥\8dà¤\95à¤\95 पनà¥\8dना",
"withoutinterwiki-summary": "ई पन्ना सभ दोसर भाषाक संस्करण सभ दिस संकेत नै करैए।",
"withoutinterwiki-legend": "उपसर्ग",
"withoutinterwiki-submit": "देखाउ",
- "fewestrevisions": "एकाध संशोधनबला पन्ना सभ",
+ "fewestrevisions": "एकाध संशोधनबला पन्ना",
"nbytes": "$1 {{PLURAL:$1|बाइट|बाइट्स}}",
- "ncategories": "{{PLURAL:$1|सà¤\82वरà¥\8dà¤\97|à¤\95à¤\8fà¤\9fा सà¤\82वरà¥\8dà¤\97}}",
- "ninterwikis": "$1 à¤\85नà¥\8dतरविà¤\95ि {{PLURAL:$1|à¤\9cड़à¥\80|à¤\9cड़ि सभ}}",
- "nlinks": "$1 {{PLURAL:$1|लाà¤\97ि|लाà¤\97ि सभ}}",
- "nmembers": "$1 {{PLURAL:$1|सदस्य|सदस्य सभ}}",
- "nmemberschanged": "$1 → $2 {{PLURAL:$2|प्रयोक्ता|प्रयोक्ता सभ}}",
- "nrevisions": "$1{{PLURAL:$1|संशोधन|संशोधन सभ}}",
- "nimagelinks": "$1पर प्रयुक्त {{PLURAL:$1|पन्ना|पन्ना सभ}}",
- "ntransclusions": "$1पर प्रयुक्त {{PLURAL:$1|पन्ना|पन्ना सभ}}",
+ "ncategories": "{{PLURAL:$1|शà¥\8dरà¥\87णà¥\80|शà¥\8dरà¥\87णà¥\80सà¤}}",
+ "ninterwikis": "$1 à¤\85नà¥\8dतरविà¤\95ि {{PLURAL:$1|लिà¤\99à¥\8dà¤\95|लिà¤\99à¥\8dà¤\95सभ}}",
+ "nlinks": "$1 {{PLURAL:$1|लिà¤\99à¥\8dà¤\95|लिà¤\99à¥\8dà¤\95सभ}}",
+ "nmembers": "$1 {{PLURAL:$1|सदस्य|सदस्यसभ}}",
+ "nmemberschanged": "$1 → $2 {{PLURAL:$2|प्रयोक्ता|प्रयोक्तासभ}}",
+ "nrevisions": "$1{{PLURAL:$1|संशोधन|संशोधनसभ}}",
+ "nimagelinks": "$1पर प्रयुक्त {{PLURAL:$1|पन्ना|पन्नासभ}}",
+ "ntransclusions": "$1पर प्रयुक्त {{PLURAL:$1|पन्ना|पन्नासभ}}",
"specialpage-empty": "ऐ पन्ना लेल कोनो परिणाम नै अछि।",
- "lonelypages": "अनाथ पन्ना सभ",
- "lonelypagestext": "à¤\88 पनà¥\8dना सठनà¥\87 à¤\95à¥\8bनà¥\8b {{à¤\85नà¥\8dतरà¥\8dà¤\9cाल}} सà¤\81 à¤\9cà¥\81ड़ल à¤\85à¤\9bि à¤\86 नहियà¥\87 à¤\85नà¥\8dतरà¥\8dबाहà¥\8dय रà¥\82पसà¤\81 दà¥\8bसर पनà¥\8dनमà¥\87 à¤\85à¤\9bि।",
- "uncategorizedpages": "अवर्गीकृत पन्ना सभ",
- "uncategorizedcategories": "à¤\85वरà¥\8dà¤\97à¥\80à¤\95à¥\83त सà¤\82वरà¥\8dà¤\97 सभ",
- "uncategorizedimages": "à¤\85वरà¥\8dà¤\97à¥\80à¤\95à¥\83त सà¤\82à¤\9aिà¤\95ा सभ",
- "uncategorizedtemplates": "अवर्गीकृत नमूना सभ",
- "unusedcategories": "नà¥\88 पà¥\8dरयà¥\8bà¤\97 à¤\95à¤\8fल सà¤\82वरà¥\8dà¤\97 सभ",
- "unusedimages": "बिना पà¥\8dरयà¥\8bà¤\97à¤\95 सà¤\82à¤\9aिà¤\95ा सभ",
- "wantedcategories": "à¤\86वशà¥\8dयà¤\95 सà¤\82वरà¥\8dà¤\97 सभ",
- "wantedpages": "आवश्यक पन्ना सभ",
+ "lonelypages": "अनाथ पन्नासभ",
+ "lonelypagestext": "ई पन्ना सभ ने कोनो {{अन्तर्जाल}} सँ जुडल अछि आ नहिये अन्तर्बाह्य रूपसँ दोसर पन्नमे अछि।",
+ "uncategorizedpages": "अवर्गीकृत पन्नासभ",
+ "uncategorizedcategories": "à¤\85वरà¥\8dà¤\97à¥\80à¤\95à¥\83त शà¥\8dरà¥\87णà¥\80सभ",
+ "uncategorizedimages": "à¤\85वरà¥\8dà¤\97à¥\80à¤\95à¥\83त सà¤\9eà¥\8dà¤\9aिà¤\95ासभ",
+ "uncategorizedtemplates": "अवर्गीकृत नमूनासभ",
+ "unusedcategories": "नà¥\88 पà¥\8dरयà¥\8bà¤\97 à¤\95à¤\8fल शà¥\8dरà¥\87णà¥\80सभ",
+ "unusedimages": "बिना पà¥\8dरयà¥\8bà¤\97à¤\95 सà¤\9eà¥\8dà¤\9aिà¤\95ासभ",
+ "wantedcategories": "à¤\86वशà¥\8dयà¤\95 शà¥\8dरà¥\87णà¥\80सभ",
+ "wantedpages": "आवश्यक पन्नासभ",
"wantedpages-badtitle": "परिणाम सूचीमे अमान्य शीर्षक:$1",
- "wantedfiles": "à¤\86वशà¥\8dयà¤\95 सà¤\82à¤\9aिà¤\95ा सभ",
- "wantedtemplates": "आवश्यक नमूना सभ",
- "mostlinked": "सभसँ बेसी लागिबला पन्ना सभ",
- "mostlinkedcategories": "सà¤à¤¸à¤\81 बà¥\87सà¥\80 लाà¤\97िबला सà¤\82वरà¥\8dà¤\97 सभ",
- "mostlinkedtemplates": "सभसँ बेसी लागिबला नमूना सभ",
- "mostcategories": "सà¤à¤¸à¤\81 बà¥\87सà¥\80 सà¤\82वरà¥\8dà¤\97बला पनà¥\8dना सभ",
- "mostimages": "सà¤à¤¸à¤\81 बà¥\87सà¥\80 लाà¤\97िबला सà¤\82à¤\9aिà¤\95ा सभ",
+ "wantedfiles": "à¤\86वशà¥\8dयà¤\95 सà¤\9eà¥\8dà¤\9aिà¤\95ासभ",
+ "wantedtemplates": "आवश्यक नमूनासभ",
+ "mostlinked": "सभसँ बेसी लागिबला पन्नासभ",
+ "mostlinkedcategories": "सà¤à¤¸à¤\81 बà¥\87सà¥\80 लाà¤\97िबला शà¥\8dरà¥\87णà¥\80सभ",
+ "mostlinkedtemplates": "सभसँ बेसी लागिबला नमूनासभ",
+ "mostcategories": "सà¤à¤¸à¤\81 बà¥\87सà¥\80 शà¥\8dरà¥\87णà¥\80बला पनà¥\8dनासभ",
+ "mostimages": "सà¤à¤¸à¤\81 बà¥\87सà¥\80 लाà¤\97िबला सà¤\9eà¥\8dà¤\9aिà¤\95ासभ",
"mostinterwikis": "सर्वाधिक अन्तरविकी जडीभेल पृष्ठसभ",
"mostrevisions": "सभसँ बेसी संशोधनबला पन्ना सभ",
"prefixindex": "उपसर्गक संग सभटा पृष्ठ",
"protectedtitles": "संरक्षित शीर्षक सभ",
"protectedtitlesempty": "कोनो पन्ना ऐ सभ परिमिति लेल सुरक्षित नै राखल गेल अछि।",
"listusers": "प्रयोक्ता सूची",
- "listusers-editsonly": "सम्पादन करैबला प्रयोक्ताकेँ मात्र देखाउ",
- "listusers-creationsort": "निरà¥\8dमाण तिथिà¤\95 हिसाबसà¤\81 à¤\9bाà¤\81à¤\9fà¥\82",
- "listusers-desc": "अवरोही क्रम में क्रमबद्ध करी",
- "usereditcount": "$1 {{PLURAL:$1|सम्पादन|सम्पादन सभ}}",
- "usercreated": "{{GENDER:$3| बनैलक|बनैलकिन्ह}} $1 तिथि पर $2 काले",
+ "listusers-editsonly": "सम्पादन करैबला प्रयोक्ताक मात्र देखाबी",
+ "listusers-creationsort": "निरà¥\8dमाण तिथिà¤\95 हिसाबसà¤\81 à¤\9bाà¤\81à¤\9fà¥\80",
+ "listusers-desc": "अवरोही क्रममे क्रमबद्ध करी",
+ "usereditcount": "$1 {{PLURAL:$1|सम्पादन|सम्पादनसभ}}",
+ "usercreated": "{{GENDER:$3|बनैलक|बनैलकिन्ह}} $1 तिथि पर $2 काले",
"newpages": "नव पन्नासभ",
"newpages-username": "प्रयोक्तानाम:",
- "ancientpages": "सभसँ पुरान पन्ना सभ",
- "move": "हà¤\9fाà¤\89",
- "movethispage": "à¤\90 पà¥\83षà¥\8dठà¤\95à¥\87à¤\81 à¤\98सà¤\95ाà¤\89",
+ "ancientpages": "सभसँ पुरान पन्नासभ",
+ "move": "सà¥\8dथानानà¥\8dतरण",
+ "movethispage": "à¤\88 पà¥\83षà¥\8dठà¤\95à¥\87 à¤\98सà¤\95ाबà¥\80",
"unusedimagestext": "ई सभ संचिका अछि मुदा कोनो पन्नामे निवशित नै अछि।\nकृपा कऽ ई बुझू जे दोसर जालस्थल सभ सोझ सार्वत्रिक विभव संकेतबला कोनो संचिकासँ लागि बना सकैए, आ तँए सरिय प्रयोगक बादो अखनो एतए सूचित कएल जा सकैए।",
"unusedcategoriestext": "ई संवर्ग पन्ना सभ अछि, ओना कोनो दोसर पन्ना वा संवर्ग ओकर प्रयोग करैत अछि।",
"notargettitle": "बिन लक्ष्यक",
"apihelp": "API मद्दत",
"apihelp-no-such-module": "मोड्युल \"$1\" नै भेटल।",
"apisandbox": "ए॰पी॰आइ प्रयोगपृष्ठ",
- "apisandbox-submit": "à¤\85नà¥\81रà¥\8bध à¤\95रà¥\81",
+ "apisandbox-submit": "à¤\85नà¥\81रà¥\8bध à¤\95रà¥\80",
"apisandbox-reset": "स्पष्ट",
"apisandbox-examples": "उदाहरण",
"apisandbox-results": "परिणाम",
"apisandbox-request-url-label": "अनुरोध URL:",
"apisandbox-request-time": "अनुरोध समय: $1",
- "booksources": "à¤\95िताबà¤\95 सनà¥\8dदरà¥\8dठसà¤",
- "booksources-search-legend": "à¤\95िताबà¤\95 सनà¥\8dदरà¥\8dà¤à¤\95 लà¥\87ल ताà¤\95à¥\82",
+ "booksources": "à¤\95िताबà¤\95 सà¥\8dरà¥\8bत",
+ "booksources-search-legend": "à¤\95िताबà¤\95 सà¥\8dरà¥\8bत ताà¤\95à¥\80",
"booksources-isbn": "आइ.एस.बी.एन.:",
- "booksources-search": "ताà¤\95à¥\82",
+ "booksources-search": "ताà¤\95à¥\80",
"booksources-text": "नीचाँ दोसर जालस्थलसँ लागि सभक सूची अछि जे नव आ प्रयोग कएल किताब बेचैए, आ ई पोथी सभक विषयमे ओहो सूचना दऽ सकैए जे अहाँ ताकि रहल छी:",
"booksources-invalid-isbn": "देल आइ.एस.बी.एन. संख्या मान्य नै बुझाइत अछि; कृपा कऽ मूल स्रोतसँ द्वितीयक बनेबा काल भेल भ्रमकेँ जाँचू।",
"specialloguserlabel": "कर्ता:",
"allpagessubmit": "जाए",
"allpagesprefix": "उपसर्गक संग दृश्य पन्ना सभ:",
"allpagesbadtitle": "देल पन्नाक शीर्षक गलत, गलत सम्बन्धित अन्तर-भाषा अन्तर विकी शीर्षक छी। ई एक वा बेशी कलाकार युक्त भऽ सकैए जे शीर्षकमे प्रयुक्त नै कएल जा सकैए।",
- "allpages-bad-ns": "{{जालस्थल}} मे \"$1\" नामगाम नै अछि।",
- "allpages-hide-redirects": "बदलà¥\87न नà¥\81à¤\95ाà¤\8aà¤\81",
+ "allpages-bad-ns": "{{SITENAME}} मे \"$1\" नामगाम नै अछि।",
+ "allpages-hide-redirects": "पà¥\81नरà¥\8dनिरà¥\8dदà¥\87श नà¥\81à¤\95ाबà¥\80",
"cachedspecial-viewing-cached-ttl": "अहाँ ई पृष्ठ के क्यास कएल अवतरण देख रहल छी, जे $1 पूरान भऽ सकएत अछि।",
"cachedspecial-viewing-cached-ts": "अहाँ इ पृष्ठ के क्यास कएल गएल अवतरण देख रहल छी, जे कि संभवतः वर्तमान अवस्था सँ भिन्न भऽ सकएत अछि।",
"cachedspecial-refresh-now": "लब्का देखु",
- "categories": "सà¤\82वरà¥\8dà¤\97 सभ",
+ "categories": "शà¥\8dरà¥\87णà¥\80सभ",
"categoriespagetext": "ई {{PLURAL:$1|संवर्गमे अछि|संवर्ग सभमे अछि}} पन्ना वा मीडिया।\n[[Special:UnusedCategories|Unused categories]] एतए देखाएल नै अछि।\nईहो देखू [[Special:WantedCategories|wanted categories]]।",
"categoriesfrom": "पन्ना प्रदर्शन प्रारम्भ भेल:",
- "deletedcontributions": "मेटाएल प्रयोक्ता योगदान सभ",
- "deletedcontributions-title": "मेटाएल प्रयोक्ता योगदान सभ",
- "sp-deletedcontributions-contribs": "योगदान सभ",
- "linksearch": "बाहरà¤\95 समà¥\8dबनà¥\8dधक खोज",
+ "deletedcontributions": "मेटाएल प्रयोक्ता योगदान",
+ "deletedcontributions-title": "मेटाएल प्रयोक्ता योगदान",
+ "sp-deletedcontributions-contribs": "योगदान",
+ "linksearch": "बाहà¥\8dय लिà¤\99à¥\8dक खोज",
"linksearch-pat": "खोज तरीका:",
"linksearch-ns": "नामस्थान :",
- "linksearch-ok": "ताà¤\95à¥\82",
+ "linksearch-ok": "ताà¤\95à¥\80",
"linksearch-text": "ब्रह्मास्त्र जेना \"*.wikipedia.org\" प्रयोग कएल जा सकैए।\nसहायक संविद:$1 (खोजमे ऐमेसँ कोनो नै जोड़ू)।",
"linksearch-line": "$2 सँ $1 क लागि अछि।",
"linksearch-error": "निमंत्रकनामक प्रारम्भमे ब्रह्मास्त्र आबि सकैए।",
"listusersfrom": "प्रयोक्ता प्रदर्शन प्रारम्भ भेल:",
- "listusers-submit": "दà¥\87à¤\96ाà¤\89",
+ "listusers-submit": "दà¥\87à¤\96ाबà¥\80",
"listusers-noresult": "कोनो प्रयोक्ता नै",
"listusers-blocked": "(प्रतिबन्धित)",
"activeusers": "सक्रिय प्रयोक्ता सभक सूची",
"emailfrom": "एतऽसँ:",
"emailto": "ऐलेल:",
"emailsubject": "विषय:",
- "emailmessage": "सà¤\82देश:",
- "emailsend": "पठाà¤\89",
+ "emailmessage": "सनà¥\8dदेश:",
+ "emailsend": "पठाबà¥\80",
"emailccme": "हमर संदेशक द्वितीयक हमर ई-पत्रपर पठाउ",
"emailccsubject": "अहाँक संदेशक द्वितीयक $1: $2",
"emailsent": "ई-पत्र पठेलौं",
"unwatching": "छोड़ल ...",
"watcherrortext": "अहाँक साकांक्ष-सूची विकल्प \"$1\" लेल बदलबा काल एकटा भ्रम आएल।",
"enotif_reset": "सभ पन्नाकेँ देखल चिन्हित करू",
- "enotif_impersonal_salutation": "{{अन्तर्जाल}} प्रयोक्ता",
+ "enotif_impersonal_salutation": "{{SITENAME}} प्रयोगकर्ता",
"enotif_subject_deleted": "{{SITENAME}} पन्ना $1 के {{gender:$2|$2}} हटेलक",
"enotif_subject_created": "{{SITENAME}} पन्ना $1 को {{gender:$2|$2}} बनेलक",
"enotif_subject_moved": "{{SITENAME}} पृष्ठ $1 के {{gender:$2|$2}} घसकेलक",
"namespace_association": "सम्बद्ध चेन्हासी",
"tooltip-namespace_association": "ऐ बक्साकेँ सही करू जइसँ वार्ता आ विषय नामस्थान समाहित कएल जा सकए चुनल नामस्थानमे",
"blanknamespace": "(मुख्य)",
- "contributions": "प्रयोक्ताक योगदान सभ",
+ "contributions": "{{GENDER:$1|प्रयोगकर्ता}} योगदान",
"contributions-title": "$1 लेल प्रयोक्ताक अवदान",
"mycontris": "योगदान",
"anoncontribs": "योगदानसभ",
- "contribsub2": "$1 ($2) लेल",
+ "contribsub2": "{{GENDER:$3|$1}} ($2)क लेल",
"contributions-userdoesnotexist": "प्रयोक्ता खाता \"$1\" पंजीकृत नै अछि।",
"nocontribs": "कोनो परिवर्तन ऐ सँ मेल नै खाइए।",
"uctop": "(शिखर)",
"month": "माससँ (आ पहिने)",
"year": "ऐ साल (आ पहिने)",
- "sp-contributions-newbies": "नव à¤\96ाताà¤\95 à¤\85वदानà¤\95à¥\87à¤\81 दà¥\87à¤\96ाà¤\89",
+ "sp-contributions-newbies": "मातà¥\8dर नव à¤\96ाताà¤\95 यà¥\8bà¤\97दान दà¥\87à¤\96ाबà¥\80",
"sp-contributions-newbies-sub": "नब प्रयोक्ताकऽ लेल",
"sp-contributions-newbies-title": "नब प्रयोक्ताकऽ योगदान",
"sp-contributions-blocklog": "प्रतिबन्धित वृत्तलेख",
"whatlinkshere-prev": "{{PLURAL:$1|पहिलुका|पहिलुका $1}}",
"whatlinkshere-next": "{{PLURAL:$1|अगुलका|अगुलका $1}}",
"whatlinkshere-links": "← जडीसभ",
- "whatlinkshere-hideredirs": "$1 à¤\98à¥\81रबà¥\88à¤\8f",
+ "whatlinkshere-hideredirs": "$1 बदलà¥\87न नà¥\81à¤\95ाबà¥\80",
"whatlinkshere-hidetrans": "$1 परागत",
"whatlinkshere-hidelinks": "$1 सम्बन्ध सभ",
"whatlinkshere-hideimages": "$1 फाइल जडी सभ",
"autoblockid": "स्वतःप्रतिबन्धित #$1",
"block": "प्रयोक्ताकेँ प्रतिबन्धित करू",
"unblock": "प्रयोक्ताकेँ प्रतिबन्धसँ हटाउ",
- "blockip": "प्रयोक्ताकेँ प्रतिबन्धित करू",
+ "blockip": "{{GENDER:$1|प्रयोक्ता}}क प्रतिबन्धित करी",
"blockip-legend": "प्रयोक्ताकेँ प्रतिबन्धित करू",
"blockiptext": "नीचाँक आवेदनक प्रयोग कोनो खास अनिकेत वा प्रयोक्तानामक लिखैक प्रवेशकेँ प्रतिबन्धित करबा लेल करू।\nई अतत्तः करैबलाक विरुद्ध प्रयुक्त हुअए, आ एकर अनुसार [[{{MediaWiki:Policy-url}}|policy]]।\nनीचाँ स्पष्ट कारण लिखू (जेना, खास पन्नाकेँ देखबैत जतए अतत्तः कएल गेल अछि)।",
"ipaddressorusername": "अनिकेत संकेत वा प्रयोक्तानाम:",
"לערי ריינהארט",
"Bennylin",
"아라",
- "Macofe"
+ "Macofe",
+ "Mbrt"
]
},
"tog-underline": "Garisen ngisoré pranala:",
"tog-hideminor": "Umpetna suntingan cilik nang owahan anyar",
"tog-hidepatrolled": "Umpetna suntingan sing wis dipatroli nang owahan anyar",
"tog-newpageshidepatrolled": "Umpetna kaca sing wis dipatroli sekang daftar kaca anyar",
+ "tog-hidecategorization": "Umpetna kategori nang kaca",
"tog-extendwatchlist": "Kembangna daftar pengawasan kanggo nidokna kabeh pangowahan, ora mung sing paling anyar thok",
"tog-usenewrc": "Klompok owahan miturut kaca nang owahan anyar lan daptar pangawasan (mbutuhna JavaScript)",
"tog-numberheadings": "Aweh nomer judul secara otomatis",
"tog-watchdefault": "Tambahna kaca lan berkas sing tek-sunting maring daptar pangawasanne inyong",
"tog-watchmoves": "Tambahna kaca lan berkas sing tek-pindah maring daptar pangawasanne inyong",
"tog-watchdeletion": "Tambahna kaca lan berkas sing tek-busek maring daptar pangawasanne inyong",
+ "tog-watchuploads": "Sogna file anyar sing nyong unggah nang daptar sawangane nyong",
"tog-watchrollback": "Tambahna kaca sing wis tek rollback maring daftar pangawasane inyong",
"tog-minordefault": "Otomatis nandani kabeh suntingan dadi suntingan cilik",
"tog-previewontop": "Tidokna pratayang sedurunge kotak sunting",
"tog-watchlisthidebots": "Umpetna suntingane bot sekang daftar pangawasan",
"tog-watchlisthideminor": "Umpetna suntingan cilik sekang daftar pangawasan",
"tog-watchlisthideliu": "Umpetna suntingane pangganggo sing mlebu log sekang daftar pangawasan",
+ "tog-watchlistreloadautomatically": "Muat balik daptar sawangane otomatis yen saringan kebesut (Perintaeh JavaScript)",
"tog-watchlisthideanons": "Umpetna suntingane panganggo anonim sekang daftar pangawasan",
"tog-watchlisthidepatrolled": "Umpetna suntingan sing wis dipatroli sekang daftar pangawasan",
+ "tog-watchlisthidecategorization": "Umpetna kategori nang kaca",
"tog-ccmeonemails": "Kirimi inyong salinan imel sing tak-kirimna maring panganggo sejen",
"tog-diffonly": "Aja tidokna isi kaca nang ngisor bedane suntingan",
"tog-showhiddencats": "Tidokna kategori sing diumpetna",
- "tog-norollbackdiff": "Lirwakna perbedaan seuwise nglakokna pambalikan",
+ "tog-norollbackdiff": "Aja ndeleng perbedaane seuwise nglakokna pambalikan",
"tog-useeditwarning": "Elingna inyong angger ninggalna kaca panyuntingan sing durung disimpen owahane",
"tog-prefershttps": "Gunakna koneksi aman terus angger mlebu log",
"underline-always": "Saben",
"editfont-monospace": "Aksara (font) Monospace",
"editfont-sansserif": "Aksara (font) Sans-serif",
"editfont-serif": "Aksara (font) Serif",
- "sunday": "Minggu",
+ "sunday": "Ahad",
"monday": "Senen",
"tuesday": "Selasa",
"wednesday": "Rebo",
"october-date": " $1 Oktober",
"november-date": "$1 November",
"december-date": "$1 Desember",
+ "period-am": "AM",
+ "period-pm": "PM",
"pagecategories": "{{PLURAL:$1|Kategori|Kategori}}",
"category_header": "Kaca nang kategori \"$1\"",
"subcategories": "Subkategori",
"poolcounter-usage-error": "Usage error: $1",
"aboutsite": "Prakara {{SITENAME}}",
"aboutpage": "Project:Prakara",
- "copyright": "Kabeh teks ana miturut $1.",
+ "copyright": "Kabeh teks ana miturut $1 namung sing cathetan liya beda.",
"copyrightpage": "{{ns:project}}:Hak cipta",
"currentevents": "Kedaden Anyar",
"currentevents-url": "Project:Prastawa sekiye",
"nstab-template": "Cithakan",
"nstab-help": "Pitulung",
"nstab-category": "Kategori:",
+ "mainpage-nstab": "Kaca Utama",
"nosuchaction": "Ora ana tindakan kaya kuwe",
"nosuchactiontext": "Tindakan sing dijaluk URL kuwe ora sah.\nRika ndeyan salah ngetikna URL, utawa ngetutna pranala sing ora bener.\nKiye bisa uga ngindikasikna nek ana ''bug'' nang piranti alus sing digunakna nang {{SITENAME}}.",
"nosuchspecialpage": "Ora ana kaca astamiwa kaya kuwe",
"nospecialpagetext": "<strong>Rika njaluk kaca astamiwa sing ora sah.</strong>\n\nDaftar kaca astamiwa sing sah teyeng dideleng nang [[Special:SpecialPages|{{int:specialpages}}]].",
"error": "Kasalahan",
"databaseerror": "Kasalahan basis data",
+ "databaseerror-text": "Ana kesalahan nang panyuwunan database wonten. Kasalahan iki mbokmenawa nuduhna anane kesalahan nang piranti alus.",
+ "databaseerror-textcl": "Ana kesalahan nang database query",
+ "databaseerror-query": "Queri:$1",
+ "databaseerror-function": "Fungsine:$1",
+ "databaseerror-error": "Eror:$1",
+ "transaction-duration-limit-exceeded": "Nggo ngindari nciptakna replikasi lag duwur, transaksi iki dibatalna sebab durasi write ($1) nglewihi $2 {{PLURAL: $ 2 | detik | detik}} batas. Angger Rikangowah akeh item sekaligus,jajal ngelakokna beberapa operasi sing lewih cilik nggo gantine.",
"laggedslavemode": "'''Pènget:''' Kaca kiye mbokmenawa isiné dudu pangowahan pungkasan.",
"readonly": "Basis data dikunci",
"enterlockreason": "Lebokna alesan panguncèn, kalebu uga prakiran kapan kunci bakal dibuka",
- "readonlytext": "Basis data lagi dikunci sekang inputan anyar lan modifikasi liyane, ndeyane lagi ana perawatan basis data, seuwise kuwe tuli bakal balik normal maning.\n\nAdministrator sing ngunci kiye aweh katerangan kaya kiye: $1",
+ "readonlytext": "Basis data agi dikonci sekang inputan anyar lan modifikasi liyane, ndeyane agi ana perawatan basis data, seuwise kuwe toli bakal mbalik normal maning.\n\nAdministrator sing ngunci kiye aweh katerangan kaya kiye: $1",
"missing-article": "Basis data ora teyeng nemokna teks paca sing kudune ana, yaiku \"$1\" $2.\n\nKiye biasanye jalaran pranala daluwarsa maring revisi sedurunge sekang kaca sing wis dibusak.\n\nAngger dudu kuwe sebabe, Rika ndeyan nemokna \"bug\" nang software. \nMonggo dilaporna maring [[Special:ListUsers/sysop|administrator]], karo nyebutna URL sing dituju.\n\nA",
"missingarticle-rev": "(révisi#: $1)",
"missingarticle-diff": "(Béda: $1, $2)",
"readonly_lag": "Basis data uwis dikunci otomatis sawetara basis data sekunder lagi nglakokna sinkronisasi karo basis data utama",
"internalerror": "Kasalahan internal",
"internalerror_info": "Kasalahan internal: $1",
+ "internalerror-fatal-exception": "pengecualiane fatal tipe \"$1\"",
"filecopyerror": "Ora teyeng nyalin berkas \"$1\" maring \"$2\".",
"filerenameerror": "Ora teyeng ngowahi jeneng berkas sekang \"$1\" dadi \"$2\".",
"filedeleteerror": "Ora teyeng mbusak berkas \"$1\".",
"directorycreateerror": "Ora teyeng nggawé dirèktori \"$1\".",
+ "directoryreadonlyerror": "Direktori \"$1\" mung diwaca thok.",
+ "directorynotreadableerror": "Direktori \"$1\" ora teyeng diwaca.",
"filenotfound": "Ora teyeng nemokna berkas \"$1\".",
"unexpected": "Nilai-ne nang jaba jangkauan: \"$1\"=\"$2\".",
"formerror": "Kasalahan: Ora teyeng ngirimna formulir.",
"actionthrottled": "Tindakan diwatesi",
"actionthrottledtext": "Kanggo ngukur anti-spam, Rika diwatesi gole nglakoni tikdakan kiye keseringen nang wektu sing cendhak, lan Rika uwis nglewati watese kuwe.\nMonggo dijajal maning nang sawetara menit.",
"protectedpagetext": "Kaca kiye uwis dikunci ben ora teyeng disunting utawa aksi liyane (pokoke ora teyeng diapa-apakna maning).",
- "viewsourcetext": "Rika teyeng ndeleng lan nyalin sumbere kaca kiye:",
- "viewyourtext": "Rika teyeng ndeleng lan nyalin sumbere '''suntingane Rika''' nang kaca kiye:",
+ "viewsourcetext": "Rika teyeng ndeleng lan nyalin sumbere kaca kiye.",
+ "viewyourtext": "Rika teyeng ndeleng lan nyalin sumbere <strong>suntingane Rika</strong> meng kaca kiye:",
"protectedinterface": "Kaca kiye isine teks antarmuka ding dienggo piranti alus nang wiki kiye, lan uwis dikunci nggo menghindari kasalahan.\nKanggo nambaih utawa ngowaih terjemahan nang kabeh wiki, monggo gunakna [//translatewiki.net/ translatewiki.net], proyek lokalisasi MediaWiki.",
- "editinginterface": "'''Pènget:''' Rika nyunting kaca sing dienggo nyedyakna tèks antarmuka kanggo piranti alus.\nPangowahan kaca kiye bakal awèh pangaruh maring tampilan antarmuka panganggo duweke panganggo sejen nang wiki kiye.\nAngger arep nambaih utawa ngowaih terjemahan, monggo gunakna [//translatewiki.net/translatewiki.net], proyèk lokalisasi MediaWiki.",
+ "editinginterface": "'''Penget:''' Rika nyunting kaca sing dienggo nyedyakna teks antarmuka kanggo piranti alus.\nPangowahan kaca kiye engko aweh pangaruh maring tampilan antarmuka panganggo duweke panganggo liyane nang wiki kiye.",
"cascadeprotected": "Kaca kiye wis direksa sekang penyuntingan jalaran melu mlebu nang {{PLURAL:$1|kaca|kaca-kaca}} nang ngisor kiye sing wis direksa nganggo opsi \"runtun\":\n$2",
"namespaceprotected": "Rika ora duwe hak akses kanggo nyunting kaca nang bilik jeneng '''$1'''.",
"customcssprotected": "Rika ora duwe izin nggo nyunting kaca CSS kiye, jalaran isine pengaturan pribadine panganggo sejen.",
"filereadonlyerror": "Ora teyeng ngowaih berkas \"$1\" jalaran panyimpenan berkas \"$2\" ana nang mode-mung-teyeng-diwaca.\n\nAdministrator sing ngunci aweh keterangan: \"$3\".",
"invalidtitle-knownnamespace": "Irah-irahan ora sah nang bilikjeneng \"$2\" lan teks \"$3\"",
"invalidtitle-unknownnamespace": "Judhul ora sah nang bilik jeneng sing ora dingerteni nomer $1 lan teks \"$2\"",
- "exception-nologin-text": "Kaca utawa kelakon kiye mbutuhna mlebu log nèng wiki kiye dhisit.",
+ "exception-nologin": "Urung mlebu",
+ "exception-nologin-text": "Tulung mlebu disit ben Rika duwe akses maring kaca kiye.",
+ "exception-nologin-text-manual": "Tulung $1 ben tenyeng duwe akses maring kaca kiye.",
"virus-badscanner": "Kasalahan konfigurasi: pamindai virus ora dikenal: ''$1''",
"virus-scanfailed": "Pemindaian gagal (kode $1)",
"virus-unknownscanner": "Antivirus ora ditepungi:",
"logouttext": "'''Rika uwis metu log sekang sistem.'''\n\nDigatekna ya, cokan ana kaca sing esih terus nidokna nek rika esih mlebu log nganti Rika mbusak singgahan nang panjelajah web-e Rika.",
+ "cannotlogoutnow-title": "Ora teyeng metu siki",
+ "cannotlogoutnow-text": "Metu ora dadi angger nganggo:$1",
+ "welcomeuser": "Sugeng teka,$1",
"welcomecreation-msg": "Akune Rika uwis digawe. \nAja kelalen ngowaih [[Special:Preferences|preferensi {{SITENAME}}]] Rika.",
"yourname": "Jeneng panganggo:",
"userlogin-yourname": "Jenengpanganggo",
"remembermypassword": "Emutna data login-ne inyong nang peramban kiye (kanggo paling suwe $1 {{PLURAL:$1|dina|dina}})",
"userlogin-remembermypassword": "Jorna ben Inyong tetep mlebu log",
"userlogin-signwithsecure": "Gunakna koneksi aman",
+ "cannotloginnow-title": "Ora teyeng mlebu siki",
"yourdomainname": "Domain Rika:",
"password-change-forbidden": "Rika ora teyeng ngowaih tembung sandhi nang wiki kiye.",
"externaldberror": "Ana kesalahan otentikasi basis data utawa Rika ora olih nglakokna pemutakhiran maring akun eksternale Rika.",
"createacct-reason-ph": "Kenangapa Rika nggawe akun sejen",
"createacct-submit": "Gawe akune Rika",
"createacct-another-submit": "Gawe akun liyane",
+ "createacct-continue-submit": "Lanjutna penggawean akun",
"createacct-benefit-heading": "{{SITENAME}} kuwe digawe nang wong kaya Rika.",
"createacct-benefit-body1": "{{PLURAL:$1|owahan|owahan}}",
"createacct-benefit-body2": "{{PLURAL:$1|kaca}}",
"noname": "Jeneng panganggo sing Rika lebokna ora sah.",
"loginsuccesstitle": "Sukses mlebu log",
"loginsuccess": "'''Rika sekiye mlebu log nang {{SITENAME}} nganggo jeneng \"$1\".'''",
- "nosuchuser": "Ora ana panganggo sing jenenge \"$1\".\nJeneng panganggo kuwe mbedakna kapitalisasi.\nPriksa maning ejaane Rika, utawa [[Special:UserLogin/signup|gawe akun anyar]]",
+ "nosuchuser": "Ora ana panganggo sing jenenge \"$1\".\nJeneng panganggo kuwe dibedakna nang kapitalisasi.\nPriksa maning ejaane Rika, utawa [[Special:CreateAccount|gawe akun anyar]]",
"nosuchusershort": "Ora ana panganggo sing jenenge \"$1\".\nJajal dipriksa maning ejaane Rika.",
"nouserspecified": "Rika kudu nglebokna jeneng panganggo.",
"login-userblocked": "Panganggo kiye diblok. Ora olih mlebu log.",
"preview": "Pra tayang",
"showpreview": "Pra tayang",
"showdiff": "Ndeleng bedané",
- "anoneditwarning": "Rika ora kadaftar mlebu.\nAlamat IP-ne Rika bakal dicatet nang sajarah panyuntingane kaca kiye.",
+ "anoneditwarning": "Rika ora kadaftar utawa urung mlebu.\nAlamat IP-ne Rika bakal dicatet nang sajarah panyuntingane kaca kiye.",
"anonpreviewwarning": "''Rika durung mlebu log. Nyimpen kaca bakal nyatetna alamat IP-ne Rika nang riwayat suntingan kaca kiye.''",
"missingsummary": "'''Pènget:''' Rika ora nglebokna ringkesan panyuntingan. \nAngger Rika mencèt tombol Simpen maning, suntingane Rika bakal kasimpen tanpa ringkesan panyuntingan.",
"missingcommenttext": "Tulung lebokna komentar nang ngisor kiye.",
"shown-title": "Tidokna $1 {{PLURAL:$1|asil|asil}} saben kaca",
"viewprevnext": "Deleng ($1 {{int:pipe-separator}} $2) ($3)",
"searchmenu-exists": "''' Ana kaca nganggo jeneng \"[[:$1]]\" nang wiki kiye.'''",
- "searchmenu-new": "'''Gawe kaca \"[[:$1]]\" nang wiki kiye!'''",
+ "searchmenu-new": "'''Gawe kaca \"[[:$1]]\" nang wiki kiye!''' {{PLURAL:$2|0=|Deleng uga kaca sing Rika golet.|Deleng uga penggoletan sing digolet.}}",
"searchprofile-articles": "Isine kaca",
"searchprofile-images": "Multimedia",
"searchprofile-everything": "Kabèh",
"prefs-signature": "Tapak asta",
"prefs-dateformat": "Format tanggal",
"prefs-timeoffset": "Format wektu",
- "prefs-advancedediting": "Opsi lanjutan",
+ "prefs-advancedediting": "Opsi lanjutane",
"prefs-advancedrc": "Opsi lanjutan",
"prefs-advancedrendering": "Opsi lanjutan",
"prefs-advancedsearchoptions": "Opsi lanjutan",
"userrights": "Manajemen hak panganggo",
"userrights-lookup-user": "Ngatur kelompok panganggo",
"userrights-user-editname": "Lebokna jeneng panganggo:",
- "editusergroup": "Sunting kelompok panganggo",
+ "editusergroup": "Besut {{GENDER:$1|kelompok}} panganggo",
"editinguser": "Ngganti hak akses nggo pangganggo '''[[User:$1|$1]]''' $2",
"userrights-editusergroup": "Sunting kelompok panganggo",
"saveusergroups": "Simpen kelompok panganggo",
"revertpage": "Suntingane [[Special:Contributions/$2|$2]] ([[User talk:$2|dhiskusi]]) dibalekna maring vèrsi pungkasan sekang [[User:$1|$1]]",
"revertpage-nouser": "Mbalekna suntingan sekang (jeneng panganggo dibusek) ming revisi pungkasan sekang [[User:$1|$1]]",
"rollback-success": "Mbalekna suntingane $1;\ndibalekna ming revisi pungkasan sekang $2.",
+ "rollback-success-notify": "Mbalekna besutan sekang $1; owah mbalik nggo revisi mburi sekang $2. [$3 Deleng owahane]",
"sessionfailure-title": "Sèsi gagal",
"sessionfailure": "Ketone lagi ana masalah karo sesi log-e Rika;\nloge Rika wis dibatalna nggo nyegah pambajakan.\nMonggo mbalik ming kaca sedurunge, dibaleni gole muatna kaca (reload) lan jajal diunggahna maning.",
"protectlogpage": "Log pangreksan",
"whatlinkshere-prev": "{{PLURAL:$1|sedurungé|$1 sedurungé}}",
"whatlinkshere-next": "{{PLURAL:$1|terusane|$1 terusane}}",
"whatlinkshere-links": "← pranala",
- "whatlinkshere-hideredirs": "$1 pengalihan",
+ "whatlinkshere-hideredirs": "$1 Dialihna",
"whatlinkshere-hidetrans": "$1 transklusi",
"whatlinkshere-hidelinks": "$1 pranala",
"whatlinkshere-hideimages": "$1 pranala berkas",
"allmessagesdefault": "Tèks baku",
"thumbnail-more": "Gedhèkna",
"thumbnail_error": "Luput gole gawe gambar cilik (''thumbnail''): $1",
- "tooltip-pt-userpage": "Kaca panganggone Rika",
+ "tooltip-pt-userpage": "{{GENDER:|Kaca panganggone}} Rika",
"tooltip-pt-mytalk": "Kaca dhiskusine Rika",
- "tooltip-pt-preferences": "Preferensine Rika",
+ "tooltip-pt-preferences": "Preferensine {{GENDER:|Rika}}",
"tooltip-pt-watchlist": "Daftar kaca sing Rika awasi owah-owahane",
"tooltip-pt-mycontris": "Daftar kontribusine Rika",
"tooltip-pt-login": "Rika diajak kon mlebu log; senajan kuwe ora kudu.",
"tooltip-t-whatlinkshere": "Daftar kabeh kaca wiki sing duwe pranala maring kaca kiye",
"tooltip-t-recentchangeslinked": "Owahan anyar nang kaca sing gandeng karo kaca kiye",
"tooltip-feed-atom": "''Atom feed'' kanggo kaca kiye",
- "tooltip-t-contributions": "Deleng daftar kontribusine pangganggo kiye",
+ "tooltip-t-contributions": "Deleng daftar kontribusine pangganggo {{GENDER:$1|kiye}}",
"tooltip-t-emailuser": "Kirimna e-mail maring panganggo kiye",
"tooltip-t-upload": "Unggahna gambar utawa berkas media",
"tooltip-t-specialpages": "Daftar kabeh kaca astamiwa",
"file-info-size": "$1 × $2 piksel, ukuran berkas: $3, tipe MIME: $4",
"file-nohires": "Ora ana résolusi sing luwih dhuwur.",
"svg-long-desc": "Berkas SVG, nominal $1 × $2 piksel, gedhené berkas: $3",
- "show-big-image": "Résolusi kebak",
+ "show-big-image": "Resolusi biasa",
"bad_image_list": "Formate kaya kiye:\n\nMung butir daftar (baris sing diawali karo tanda*) sing melu diitung.\nPranala disit dhewek nang baris kuwe kudu pranala maring berkas sing ala.\nPranala seteruse nang baris sing padha dianggep dadi \"pengecualian\", yakuwe artikel sing bisa nampilna berkas kuwe mau.",
"metadata": "Metadata",
"metadata-help": "Berkas kiye ngandhut informasi tambahan, sing ndeyane ditambahna sekang kamera digital utawa ''scanner'' sing digunakna nggo nggawe utawa ''digitalisasi'' berkas kiye.\nAngger berkas kiye uwis diowahi sekang versi asline, rincian sing ana ndeyane wis ora sacara kebak nidokna informasi sekang gambar sing wis dimodifikasi kiye.",
"specialpages": "Kaca-kaca khusus",
"external_image_whitelist": " #Jorna baen larikan kiye apa anané<pre>\n#Gunakna fragmèn èksprèsi regular (mung bagéyan nang antarane //) nang ngisor\n#Fragmèn kiye bakal dicocogna karo URL sekang gambar-gambar èksternal\n#Fragmèn sing cocog bakal ditampilna minangka gambar, nék ora ya mung pranala maring gambare baen sing ditampilna\n#Larikan sing diwiwiti nganggo # dianggep minangka komentar\n#Kiye ora mbédakna aksara gedhé/cilik\n\n#Sogna kabèh fragmèn èksprèsi regular nang dhuwuré larikan kiye. Jorna baen larikan kiye apa anané</pre>",
"tag-filter": "Filter [[Special:Tags|Tag]]:",
- "rightsnone": "(ora ana)"
+ "rightsnone": "(ora ana)",
+ "searchsuggest-search": "Golet"
}
"noname": "Тон изеть пута кемокстаф тиить лемоц.",
"loginsuccesstitle": "Сувамась ётась лац",
"loginsuccess": "'''Тон сувать {{SITENAME}}-с кода \"$1\".'''",
- "nosuchuser": "Тиись \"$1\" лемса аш.\nВанк, улема, тон сёрмадыть лемть аф лац.\nИлякс тондейть эряви [[Special:UserLogin/signup|сёрматфтомс одукс]].",
+ "nosuchuser": "Тиись \"$1\" лемса аш.\nВанк, улема, тон сёрмадыть лемть аф лац.\nИлякс тондейть эряви [[Special:CreateAccount|сёрматфтомс одукс]].",
"nosuchusershort": "Тиись \"$1\" лемса аш. Ванк, улема, тон сёрмадыть лемть аф лац.",
"nouserspecified": "Тиить лемсь эряви.",
"login-userblocked": "Тиись перяф. Сувама кардаф.",
"accmailtext": "Апак арьсек тиф [[User talk:$1|$1]]нь сувама валоц кучфоль $2с.\n\nТя од сёрматфтомать сувама валть ули кода полафтомс ''[[Special:ChangePassword|сувама валонь полафтома]]'' лопаса сувамда меле.",
"newarticle": "(Од)",
"newarticletext": "Тон сать лопас кона нинге изь тие.\nСёрматк паксяв алу тя лопать тиеманкса\n(ванк [$1 лезкс лопа] лездама информациенкса).\nСаньдярять тяза эльбядезь, люпштак пунять '''меки''' тонь интернет полатксонь вальмасонза.",
- "anontalkpagetext": "----''Тя корхтама лопать тизе лемфтома тиись кона нинге аф сёрматфтф эли кона эсь сёрматфтомас аф кунци. Тяса минь нолдамс сонь лувомтяшкснень IP адресонц тиить содафтоманкса.\nТя IP адресть вельде ули кода сашендомс иля тиихненди.\nУляндяряйхть иля тиинь мяльполатксонза конатнень аф видекста лувозь тоннекс, тондейть пароль сай пингста [[Special:UserLogin/signup|сёрматфтомс/сувамс]] иля лемфтома тиихнень марс аф шовореманкса.''",
+ "anontalkpagetext": "----''Тя корхтама лопать тизе лемфтома тиись кона нинге аф сёрматфтф эли кона эсь сёрматфтомас аф кунци. Тяса минь нолдамс сонь лувомтяшкснень IP адресонц тиить содафтоманкса.\nТя IP адресть вельде ули кода сашендомс иля тиихненди.\nУляндяряйхть иля тиинь мяльполатксонза конатнень аф видекста лувозь тоннекс, тондейть пароль сай пингста [[Special:CreateAccount|сёрматфтомс/сувамс]] иля лемфтома тиихнень марс аф шовореманкса.''",
"noarticletext": "Тяни аш текст тя лопаса.\nТондейть ули кода [[Special:Search/{{PAGENAME}}|вешендемс тя лопать коняксонц]] иля лопава,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} вешендемс малады лувомава],\nэли [{{fullurl:{{FULLPAGENAME}}|action=edit}} петнемс тя лопать]</span>.",
"noarticletext-nopermission": "Тяни аш текст тя лопаса.\nТондейть ули кода [[Special:Search/{{PAGENAME}}|вешендемс тя лопать коняксонц]] иля лопава,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} вешендемс малады лувомава]</span>, аньцек тонь аш мярьговомаце тя лопать ушедомс.",
"userpage-userdoesnotexist": "Сёрматфтомась «<nowiki>$1</nowiki>» лемса аш. Арьсек лацкаста, афкукс тонь улендяряй мяльце тиемс эли полафтомс тя лопать.",
"accmailtext": "Nalefa tany amin'i $2 ny tenimiafina kisendra ho an'ny kaonty [[User talk:$1|$1]]! Azo ovaina eo amin'i ''[[Special:ChangePassword|Manova tenimiafina]]'' izany amin'ny alalan'ny fidirana.",
"newarticle": "(Vaovao)",
"newarticletext": "Mbola tsy misy ity takelaka ity koa azonao atao ny mamorona azy eto ambany. Jereo ny [$1 Fanoroana] raha misy fanazavana ilainao.\n\nRaha toa moa ka tsy nieritreritra ny hamorona ity takelaka ity ianao dia miverena etsy amin'ny fandraisana.",
- "anontalkpagetext": "----<i>Ity pejy ity dia pejin-dresak'olona tsy nanokatra na tsy nampiasa ny kaontiny.\nNoho izany dia ilainay ny mampiasa ny adiresy IP-ny hanondroana azy. Mety zarazarain'olona maro ny adiresy IP iray. Raha mpikambana tsy nisoratra anarana ianao, ka raha mahita resaka ts ho anao, azonao atao ny [[Special:UserLogin/signup|manokatra kaonty]], na [[Special:UserLogin|miditra]] mba tsy ho voafangarao amin'ny mpikambana hafa tsy nisoratra anarana.</i>",
+ "anontalkpagetext": "----<i>Ity pejy ity dia pejin-dresak'olona tsy nanokatra na tsy nampiasa ny kaontiny.\nNoho izany dia ilainay ny mampiasa ny adiresy IP-ny hanondroana azy. Mety zarazarain'olona maro ny adiresy IP iray. Raha mpikambana tsy nisoratra anarana ianao, ka raha mahita resaka ts ho anao, azonao atao ny [[Special:CreateAccount|manokatra kaonty]], na [[Special:UserLogin|miditra]] mba tsy ho voafangarao amin'ny mpikambana hafa tsy nisoratra anarana.</i>",
"noarticletext": "'''Tsy mbola nisy namorona io lahatsoratra io.\nAzonao atao ny [[Special:Search/{{PAGENAME}}|Tadiavo ny momba ny {{PAGENAME}}]].'''\n* '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} Na forony eto ny lahatsoratra momba ny {{PAGENAME}}]'''.",
"noarticletext-nopermission": "Mbola tsy misy lahatsoratra ao amin'io pejy io.\n\nAzonao atao ny [[Special:Search/{{PAGENAME}}|mikaroka ity lohateny ity]] eny amin'ny pejy hafa na <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mitady ao amin'ny laogy misy fifandraisana]</span>, fa tsy azonao atao ny mamorona ity pejy ity.",
"missing-revision": "Tsy misy ny santiôna #$1 ny pejy \"{{FULLPAGENAME}}\".\n\nMitranga izany rehefa manaraka rohin-tantara tola mankany amina pejy voafafa. Ahitana fampahalalana fanampiny ny [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} laogim-pamafana].",
"userlogin-resetpassword-link": "Шолыпмутым монденат?",
"createaccountmail": "Кӱчык жаплан чокым ыштыме шолыпмутым мылам e-mail дене колташ",
"createacct-benefit-heading": "{{SITENAME}} тендан гаяк еҥ-влак дене ыштен шындалтын.",
- "nosuchuser": "\"$1\" лӱман пайдаланыше уке.\nПайдаланышын лӱмыштӧ йӱкпале-влакын кугытшо тӱрыс лийшаш.\nЛӱмым чын возымым терге але [[Special:UserLogin/signup|регистрацийым эрте]].",
+ "nosuchuser": "\"$1\" лӱман пайдаланыше уке.\nПайдаланышын лӱмыштӧ йӱкпале-влакын кугытшо тӱрыс лийшаш.\nЛӱмым чын возымым терге але [[Special:CreateAccount|регистрацийым эрте]].",
"nosuchusershort": "\"$1\" лӱман пайдаланыше уке.\nЛӱмым чын возымым терге.",
"nouserspecified": "Тылат пайдаланышын лӱмжым пуртыман.",
"wrongpassword": "Тый йоҥылыш шолыпмутым пуртенат.\nЭше ик гана ыштен ончо.",
"noname": "Namo pangguno nan Sanak masuakan indak sah.",
"loginsuccesstitle": "Bahasil masuak log",
"loginsuccess": "'''Sanak kini lah masuak log di {{SITENAME}} sabagai \"$1\".'''",
- "nosuchuser": "Indak ado pangguno jo namo \"$1\".\nNamo pangguno mambedoan kapitalisasi.\nPariso baliak ejaan Sanak, atau [[Special:UserLogin/signup|buek akun baru]].",
+ "nosuchuser": "Indak ado pangguno jo namo \"$1\".\nNamo pangguno mambedoan kapitalisasi.\nPariso baliak ejaan Sanak, atau [[Special:CreateAccount|buek akun baru]].",
"nosuchusershort": "Indak ado pangguno jo namo \"$1\".\nCubo pariso baliak ejaan Sanak.",
"nouserspecified": "Sanak harus mamasuakan namo pangguno.",
"login-userblocked": "Pangguno ko kanai sakek. Indak diizinan untuak masuak log.",
"accmailtext": "Sabuah kato sandi acak untuak [[User talk:$1|$1]] alah dibuek dan dikiriman ka $2.\n\nKato sandi untuak akun baharu iko dapek diubah di laman ''[[Special:ChangePassword|pangubahan kato sandi]]'' satalah masuak log.",
"newarticle": "(Baru)",
"newarticletext": "Laman nan Sanak cari alun ado.\nUntuak mambuek laman tu, mulailah jo manulih dalam kotak di bawah (caliak [$1 laman bantuan] untuak informasi labiah lanjuik).\nJikok Sanak indak sangajo sampai ka laman ko, klik tombol '''back''' pado paramban web Sanak.",
- "anontalkpagetext": "----''Iko adolah laman rundiang saurang pangguno anonim nan alun mambuek akun atau indak manggunoannyo.\nJadi, kami tapaso mamakai alamat IP nan takaik untuak mangenalinyo.\nJikok Sanak adolah pangguno anonim dan maraso mandapek komentar nan indak lamak nan ditujuan langsung kapado Sanak, cubolah [[Special:UserLogin/signup|mambuek akun]] atau [[Special:UserLogin|masuak log]] guno manghindari karancuan jo pangguno anonim lainnyo.''",
+ "anontalkpagetext": "----''Iko adolah laman rundiang saurang pangguno anonim nan alun mambuek akun atau indak manggunoannyo.\nJadi, kami tapaso mamakai alamat IP nan takaik untuak mangenalinyo.\nJikok Sanak adolah pangguno anonim dan maraso mandapek komentar nan indak lamak nan ditujuan langsung kapado Sanak, cubolah [[Special:CreateAccount|mambuek akun]] atau [[Special:UserLogin|masuak log]] guno manghindari karancuan jo pangguno anonim lainnyo.''",
"noarticletext": "Kini ko indak ado teks di laman ko.\nSanak dapek [[Special:Search/{{PAGENAME}}|malakuan pancarian untuak judul laman ko]] di laman-laman lain, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mancari log takaik], atau [{{fullurl:{{FULLPAGENAME}}|action=edit}} manyuntiang laman iko]</span>.",
"noarticletext-nopermission": "Kini ko indak ado teks dalam laman ko.\nSanak dapek [[Special:Search/{{PAGENAME}}|malakukan pancarian untuak judul laman ko]] di laman lain, atau <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mancahari log takaik] </span>, tapi Sanak indak punyo izin untuak mambuek laman ko.",
"missing-revision": "Revisi $1 di laman nan banamo \"{{FULLPAGENAME}}\" ko indak ado.\n\nHal iko biasonyo disababkan dek pautan sijarah nan alah kadaluarsa ka laman nan alah diapuih.\nRinciannyo dapek dicaliak di [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log pangapuihan].",
"아라",
"Milicevic01",
"Macofe",
- "Nemo bis"
+ "Nemo bis",
+ "Matma Rex"
]
},
"tog-underline": "Потцртување на врски:",
"tog-watchdefault": "Додавај ги страниците и податотеките што ги уредувам во набљудуваните",
"tog-watchmoves": "Додавај ги страниците и податотеките што ги преместувам во набљудуваните",
"tog-watchdeletion": "Додавај ги страниците и податотеките што ги бришам во набљудуваните",
+ "tog-watchuploads": "Ставај ги податотеките што ги подигам во набљудуваните",
"tog-watchrollback": "Додај ги страниците сум ги отповикал во набљудувани",
"tog-minordefault": "Обележувај ги сите уредувања како ситни по основно",
"tog-previewontop": "Прикажи го прегледот пред кутијата за уредување",
"tog-ccmeonemails": "Испраќај ми мои примероци од писмата што ги праќам на другите корисници",
"tog-diffonly": "Не ја покажувај содржината на страницата под разликите",
"tog-showhiddencats": "Прикажи скриени категории",
- "tog-norollbackdiff": "Ð\98зоÑ\81Ñ\82ави Ñ\98а разликата по извршено отповикување",
+ "tog-norollbackdiff": "Ð\9dе Ñ\98а покажÑ\83ваÑ\98 разликата по извршено отповикување",
"tog-useeditwarning": "Предупреди ме кога сакам да напуштам страница за уредување без да ги имам зачувано промените",
"tog-prefershttps": "Секогаш најавувај ме преку безбедна врска",
"underline-always": "Секогаш",
"password-change-forbidden": "Не можете да ја менувате лозинката на ова вики.",
"externaldberror": "Настана грешка при надворешното најавување на базата или пак немате дозвола да ја подновите вашата надворешна сметка.",
"login": "Најава",
+ "login-security": "Потврдете го вашиот идентитет",
"nav-login-createaccount": "Најава / направи сметка",
"userlogin": "Најава / направи сметка",
"userloginnocreate": "Најава",
"userlogin-resetpassword-link": "Ја заборавивте лозинката?",
"userlogin-helplink2": "Помош за најава",
"userlogin-loggedin": "Веќе сте најавени како {{GENDER:$1|$1}}.\nСо образецот подолу можете да се најавите како друг корисник.",
+ "userlogin-reauth": "Ќе мора да се најавите повторно за да потврдите дека сте {{GENDER:$1|$1}}.",
"userlogin-createanother": "Направи нова сметка",
"createacct-emailrequired": "Е-пошта",
"createacct-emailoptional": "Е-пошта (незадолжително)",
"createacct-email-ph": "Внесете е-пошта",
"createacct-another-email-ph": "Внесете е-пошта",
"createaccountmail": "Дај привремена произволна лозинка и испрати ја на укажаната адреса",
+ "createaccountmail-help": "Може да се користи за создавање на сметка во туѓо име без да ја знаете лозинката.",
"createacct-realname": "Вистинско име (незадолжително)",
"createaccountreason": "Причина:",
"createacct-reason": "Причина",
"createacct-reason-ph": "Зошто правите друга сметка",
+ "createacct-reason-help": "Порака што се прикажува во дневникот на создадени сметки",
"createacct-submit": "Направи ја",
"createacct-another-submit": "Создај сметка",
+ "createacct-continue-submit": "Продолжи со создавањето на сметката",
+ "createacct-another-continue-submit": "Продолжи со создавањето на сметката",
"createacct-benefit-heading": "{{SITENAME}} е дело на луѓе како вас.",
"createacct-benefit-body1": "{{PLURAL:$1|уредување|уредувања}}",
"createacct-benefit-body2": "{{PLURAL:$1|страница|страници}}",
"nocookieslogin": "{{SITENAME}} користи колачиња за најавување на корисници.\nВие го имате оневозможено користењето на колачиња на вашиот прелистувач.\nВе молиме активирајте ги и обидете се повторно.",
"nocookiesfornew": "Корисничката сметка не е создадена бидејќи не можеше да се потврди нејзиниот извор.\nЗа оваа цел ќе ви требаат колачиња. Проверете дали се овозможени, превчитајте ја страницава и обидете се повторно.",
"nocookiesforlogin": "{{int:nocookieslogin}}",
+ "createacct-loginerror": "Сметката е успешно создадена но не можев да ве најавам автоматски. Појдеете да се [[Special:UserLogin|најавите рачно]].",
"noname": "Внесовте погрешно корисничко име.",
"loginsuccesstitle": "Најавени сте",
"loginsuccess": "Сега сте најавени на {{SITENAME}} како „$1“.",
- "nosuchuser": "Нема корисник со името „$1“.\nКорисничките имиња разликуваат мали и големи букви.\nПроверете да не сте направиле грешка во пишувањето, или [[Special:UserLogin/signup|создајте нова корисничка сметка]].",
+ "nosuchuser": "Нема корисник со името „$1“.\nКорисничките имиња разликуваат мали и големи букви.\nПроверете да не сте направиле грешка во пишувањето, или [[Special:CreateAccount|создајте нова корисничка сметка]].",
"nosuchusershort": "Нема корисник со името „$1“.\nПроверете дали правилно сте напишале.",
"nouserspecified": "Мора да наведете корисничко име.",
"login-userblocked": "Овој корисник е блокиран. Најавувањето не е дозволено.",
"noemail": "Нема заведено е-поштенска адреса за корисник „$1“.",
"noemailcreate": "Потребно е да наведете важечка е-поштенска адреса",
"passwordsent": "Нова лозинка е испратена на е-поштенската адреса заведена за „$1“.\nВе молиме најавете се повторно откако ќе ја примите пораката.",
- "blocked-mailpassword": "Ð\92аÑ\88аÑ\82а IP-адÑ\80еÑ\81а е блокиÑ\80ана за Ñ\83Ñ\80едÑ\83ваÑ\9aе, иÑ\81Ñ\82овÑ\80емено е Ñ\81Ñ\82авена забÑ\80ана за коÑ\80иÑ\81Ñ\82еÑ\9aе на Ñ\84Ñ\83нкÑ\86иÑ\98аÑ\82а за обнова на лозинка за да Ñ\81е Ñ\81пÑ\80еÑ\87и можноÑ\81Ñ\82а за злоÑ\83поÑ\82Ñ\80еба.",
+ "blocked-mailpassword": "Ð\92аÑ\88аÑ\82а IP-адÑ\80еÑ\81а има забÑ\80ана за Ñ\83Ñ\80едÑ\83ваÑ\9aе. Ð\97а да Ñ\81е Ñ\81пÑ\80еÑ\87и злоÑ\83поÑ\82Ñ\80еба, не е дозволено повÑ\80аÑ\82ок на лозинка од неа.",
"eauthentsent": "На назначената адреса е испратена потврдна порака.\nПред да се испрати друга порака на корисничката сметка, ќе морате да ги проследите напатствијата во пораката, за да потврдите дека таа корисничка сметка е навистина ваша.",
"throttled-mailpassword": "Веќе е испратена порака за измена на лозинката во {{PLURAL:$1|изминатиов час|изминативе $1 часа}}.\nЗа да се спречи злоупотреба, само едно потсетување може да се праќа на {{PLURAL:$1|секој час|секои $1 часа}}.",
"mailerror": "Грешка при испраќање на е-поштата: $1",
"createacct-another-realname-tip": "Вистинското име е незадолжително.\nДоколку изберете да го внесете, тоа може да се искористи за оддавање на заслуги за Вашата работа.",
"pt-login": "Најава",
"pt-login-button": "Најава",
+ "pt-login-continue-button": "Продолжи со најавата",
"pt-createaccount": "Направи сметка",
"pt-userlogout": "Одјава",
"php-mail-error-unknown": "Непозната грешка во функцијата mail() на PHP",
"changepassword-success": "Вашата лозинка е сменета!",
"changepassword-throttled": "Имате премногу обиди за најава за кратко време.\nПочекајте $1 пред да се обидете повторно.",
"botpasswords": "Ботовски лозинки",
+ "botpasswords-existing": "Постоечки ботовски лозинки",
+ "botpasswords-createnew": "Направи нова ботовска лозинка",
+ "botpasswords-editexisting": "Измени постоечка ботовска лозинка",
"botpasswords-label-appid": "Име на ботот:",
"botpasswords-label-create": "Создај",
"botpasswords-label-update": "Поднови",
"botpasswords-label-delete": "Избриши",
"botpasswords-label-resetpassword": "Ставете нова лозинка",
"botpasswords-label-grants": "Применливи доделувања:",
+ "botpasswords-label-grants-column": "Доделено",
+ "botpasswords-bad-appid": "Името на ботот „$1“ е неважечко.",
"resetpass_forbidden": "Лозинките не може да се менуваат",
"resetpass-no-info": "Мора да сте најавени ако сакате да имате директен пристап до оваа страница.",
"resetpass-submit-loggedin": "Смени лозинка",
"accmailtext": "На $2 е спратена е случајно создадена лозинка за [[User talk:$1|$1]] е испратена. Истата може да се смени на страницата ''[[Special:ChangePassword|Менување на лозинка]]'' откако ќе се најавите.",
"newarticle": "(нова)",
"newarticletext": "Проследивте врска до страница која не постои.\nЗа да ја создадете страницата, напишете текст во полето подолу ([$1 помош]). Ако сте овде по грешка, само систнете на копчето '''назад''' во вашиот прелистувач.",
- "anontalkpagetext": "----''Ова е страница за разговор со анонимен корисник кој сè уште не регистрирал корисничка сметка или не ја користи.\nЗатоа мораме да ја користиме неговата бројчена IP-адреса за да го препознаеме.\nЕдна ваква IP-адреса може да ја делат повеќе корисници.\nАко сте анонимен корисник и сметате дека кон вас се упатени нерелевантни коментари, тогаш [[Special:UserLogin/signup|создајте корисничка сметка]] или [[Special:UserLogin|најавете се]] за да избегнете поистоветување со други анонимни корисници во иднина.''",
+ "anontalkpagetext": "----''Ова е страница за разговор со анонимен корисник кој сè уште не регистрирал корисничка сметка или не ја користи.\nЗатоа мораме да ја користиме неговата бројчена IP-адреса за да го препознаеме.\nЕдна ваква IP-адреса може да ја делат повеќе корисници.\nАко сте анонимен корисник и сметате дека кон вас се упатени нерелевантни коментари, тогаш [[Special:CreateAccount|создајте корисничка сметка]] или [[Special:UserLogin|најавете се]] за да избегнете поистоветување со други анонимни корисници во иднина.''",
"noarticletext": "Таква страница сè уште не постои.\nМожете да проверите [[Special:Search/{{PAGENAME}}|дали насловот се споменува]] во други статии,\nда ги <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} пребарате дневниците],\nили да [{{fullurl:{{FULLPAGENAME}}|action=edit}} ја создадете]</span>.",
"noarticletext-nopermission": "Таква страница сè уште не постои.\nМожете да проверите [[Special:Search/{{PAGENAME}}|дали насловот се споменува]] во други статии или пак да <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} пребарате поврзаните дневници]</span>, но немате дозвола да ја создадете страницата.",
"missing-revision": "Не ја пронајдов преработката бр. $1 на страницата со наслов „{{FULLPAGENAME}}“.\n\nОва обично се должи на застарена врска за разлики што води кон избришана страница.\nПовеќе подробности ќе најдете во [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневникот на бришења].",
"mergehistory-empty": "Нема преработки кои можат да се спојат.",
"mergehistory-done": "$3 {{PLURAL:$3|преработка |преработки}} на $1 успешно {{PLURAL:$3|е споена|се споени}} во [[:$2]].",
"mergehistory-fail": "Не е возможно да се направи спојување на историјата, проверете ја страницата и временските параметри.",
+ "mergehistory-fail-bad-timestamp": "Временската ознака е неважечка.",
+ "mergehistory-fail-invalid-source": "Изворната страница е неважечка.",
+ "mergehistory-fail-invalid-dest": "Целната страница е неважечка.",
+ "mergehistory-fail-permission": "Немате дозвола за да ја споите историјата.",
+ "mergehistory-fail-self-merge": "Изворната и целната страница се исти.",
"mergehistory-fail-toobig": "Не можам да извршам спојување на историјата бидејќи така ќе се надмине границата од {{PLURAL:$1|една преработка|$1 преработки}}.",
"mergehistory-no-source": "Изворната страница $1 не постои.",
"mergehistory-no-destination": "Целната страница $1 не постои.",
"editusergroup": "Уреди кориснички групи",
"editinguser": "Менување на правата на {{GENDER:$1|корисникот}} <strong>[[User:$1|$1]]</strong> $2",
"userrights-editusergroup": "Уреди ги корисничките групи",
- "saveusergroups": "Зачувај ги корисничките групи",
+ "saveusergroups": "Зачувај ги {{GENDER:$1|корисничките}} групи",
"userrights-groupsmember": "Член на:",
"userrights-groupsmember-auto": "Подразбран член на:",
"userrights-groups-help": "Можете да измените на кои групи припаѓа корисник:\n* Штиклирано - корисникот е во таа група.\n* Нештиклирано - корисникот не припаѓа на групата.\n* Ѕвездичка (*) - не можете да ја отстраните групата откако сте ја додале (и обратно).",
"grant-group-administration": "Вршење на административни дејства",
"grant-group-other": "Разни активности",
"grant-blockusers": "Блокирање и одблокирање корисници",
- "grant-createaccount": "Ð\9dапÑ\80ави сметки",
+ "grant-createaccount": "Ð\9fÑ\80авеÑ\9aе сметки",
"grant-createeditmovepage": "Создавање, уредување и преместување страници",
- "grant-delete": "Бришење на страници, преработки и дневнички записи",
- "grant-editinterface": "Измена на именскиот простор „МедијаВики“ и кориснички CSS/JS",
- "grant-editmycssjs": "Уредување на ваш кориснички CSS/JavaScript",
- "grant-editmyoptions": "Уредете ги вашите кориснички нагодувања",
- "grant-editmywatchlist": "Уреди мои набљудувани",
- "grant-editpage": "Ð\98змени постоечки страници",
+ "grant-delete": "Бришење страници, преработки и дневнички записи",
+ "grant-editinterface": "Измена на именскиот простор „МедијаВики“ и кориснички CSS/JavaScript",
+ "grant-editmycssjs": "Уредување на вашиот кориснички CSS/JavaScript",
+ "grant-editmyoptions": "Уредување на вашите кориснички нагодувања",
+ "grant-editmywatchlist": "Уредување на вашите набљудувани",
+ "grant-editpage": "Ð\9cенÑ\83ваÑ\9aе постоечки страници",
"grant-editprotected": "Уредување на заштитени страници",
"grant-highvolume": "Високообемно уредување",
"grant-oversight": "Скривање на корисници и преработки",
"grant-rollback": "Отповикување на измени во страници",
"grant-sendemail": "Испраќање на е-пошта до други корисници",
"grant-uploadeditmovefile": "Подигање, замена и преместување на податотеки",
- "grant-uploadfile": "Подигни нови податотеки",
+ "grant-uploadfile": "Подигање нови податотеки",
+ "grant-basic": "Основни права",
"grant-viewdeleted": "Преглед на избришани податотеки и страници",
"grant-viewmywatchlist": "Преглед на вашите набљудувања",
"newuserlogpage": "Дневник на регистрирања на корисници",
"upload-form-label-own-work": "Ова е мое дело",
"upload-form-label-infoform-categories": "Категории",
"upload-form-label-infoform-date": "Датум",
- "upload-form-label-own-work-message-local": "Потврдувам дека податотекава ја подигам во согласност со уловите на користење и правилата за лиценцирање на {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Ако не сте во можност да ја подигнете податотекава согласно правилата на {{SITENAME}}. Затворете го дијалогов и обидете се на друг начин.",
- "upload-form-label-not-own-work-local-local": "Можете да ја пробате и [[Special:Upload|стандардната страница за подигање]].",
- "upload-form-label-own-work-message-default": "Разбирам дека ја подигам податотекава на заедничко складиште. Потврдувам дека со тоа ги почитувам тамошните услови на користење и лиценцните правила.",
- "upload-form-label-not-own-work-message-default": "Ако не сте во можност да ја подигнете податотекава во склад со правилата на заедничкото складиште, би ве замолиле да го затворите дијалогов и да пробате на друг начин.",
- "upload-form-label-not-own-work-local-default": "Можете да се обидете и на [[Special:Upload|страницата за подигање на {{SITENAME}}]], доколку податотеката може да се подигне под тамошните правила.",
- "upload-form-label-own-work-message-shared": "Сведочам дека јас сум имател на авторските права на оваа податотека, дека се согласувам дека неотповикливо ја објавувам на Ризницата под лиценцата [https://creativecommons.org/licenses/by-sa/4.0/deed.mk Криејтив комонс Наведи извор-Сподели под исти услови 4.0] и дека се согласувам да се придржувам до [https://wikimediafoundation.org/wiki/Terms_of_Use/mk Условите на употреба].",
- "upload-form-label-not-own-work-message-shared": "Доколку вие не сте имател на авторските права на податотекава, или пак сакате да ја објавите под поинаква лиценца, веројатно ќе треба да се послужите со [https://commons.wikimedia.org/wiki/Special:UploadWizard?uselang=mk Помошникот за подигање].",
- "upload-form-label-not-own-work-local-shared": "Можете да се обидете и на [[Special:Upload|страницата за подигање на {{SITENAME}}]], доколку податотеката може да се подигне под тамошните правила.",
+ "upload-form-label-own-work-message-generic-local": "Потврдувам дека податотекава ја подигам во согласност со уловите на користење и правилата за лиценцирање на {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Ако не сте во можност да ја подигнете податотекава согласно правилата на {{SITENAME}}. Затворете го дијалогов и обидете се на друг начин.",
+ "upload-form-label-not-own-work-local-generic-local": "Можете да ја пробате и [[Special:Upload|стандардната страница за подигање]].",
+ "upload-form-label-own-work-message-generic-foreign": "Разбирам дека ја подигам податотекава на заедничко складиште. Потврдувам дека со тоа ги почитувам тамошните услови на користење и лиценцните правила.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Ако не сте во можност да ја подигнете податотекава во склад со правилата на заедничкото складиште, би ве замолиле да го затворите дијалогов и да пробате на друг начин.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Можете да се обидете и на [[Special:Upload|страницата за подигање на {{SITENAME}}]], доколку податотеката може да се подигне под тамошните правила.",
"backend-fail-stream": "Не можев да ја емитувам податотеката $1.",
"backend-fail-backup": "Не можев да направам резерва на податотеката $1.",
"backend-fail-notexists": "Податотеката $1 не постои.",
"uploadstash-badtoken": "Не успеав да го извршам бараното дејство, можеби поради тоа што вашата сигурносна шифра е истечена. Обидете се повторно.",
"uploadstash-errclear": "Чистењето на податотеките не успеа.",
"uploadstash-refresh": "Превчитај го списокот на податотеки",
+ "uploadstash-thumbnail": "погл. минијатура",
"invalid-chunk-offset": "Неважечка појдовна точка",
"img-auth-accessdenied": "Оневозможен пристап",
"img-auth-nopathinfo": "Недостасува PATH_INFO.\nВашиот опслужувач не е нагоден за да ја предаде оваа информација.\nМожеби се заснова на CGI, и така не подржува img_auth.\nПогл. https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
"apisandbox": "Извршнички песочник",
"apisandbox-api-disabled": "Извршникот е оневозможен на ова мрежно место.",
"apisandbox-intro": "Страницава служи за вршење проби со '''Извршник на МедијаВики'''.\n\nПовеќе за употребата на овој извршник ќе најдете во [//www.mediawiki.org/wiki/API:Main_page неговата документација]. Пример: [//www.mediawiki.org/wiki/API#A_simple_example преземање на содржината на главната страница]. Одберете дејство за да видите повеќе примери.\n\nИмајте предвид дека она шо го правите на страницава може да се одрази врз викито, иако ова е песочник.",
+ "apisandbox-unfullscreen": "Прикажи страница",
"apisandbox-submit": "Постави барање",
"apisandbox-reset": "Исчисти",
+ "apisandbox-retry": "Пробај пак",
"apisandbox-examples": "Примери",
"apisandbox-dynamic-parameters": "Дополнителни параметри",
"apisandbox-dynamic-parameters-add-label": "Додај параметар:",
"listgrouprights-namespaceprotection-header": "Ограничувања за именски простори",
"listgrouprights-namespaceprotection-namespace": "Именски простор",
"listgrouprights-namespaceprotection-restrictedto": "Права што им овозможуваат на корисниците да уредуваат",
- "listgrants-summary": "Ова е список на доделувања на OAuth, секое со своите права. Корисниците можат да овластуваат извршници што ќе ги користат сметки, но со ограничувања во дозволите што им се доделени. Покрај ова, извршникот што делува во име на корисникот е ограничен на нештата на кои има права самиот корисник.\nМоже да најдете [[{{MediaWiki:Listgrouprights-helppage}}|уште информации]] за поединечните права.",
+ "listgrants": "Доделувања",
+ "listgrants-summary": "Ова е список на доделувања, секое со своите права. Корисниците можат да овластуваат извршници што ќе ги користат сметки, но со ограничувања во дозволите што им се доделени. Покрај ова, извршникот што делува во име на корисникот е ограничен на нештата на кои има права самиот корисник.\nМоже да најдете [[{{MediaWiki:Listgrouprights-helppage}}|уште информации]] за поединечните права.",
"listgrants-grant": "Доделување",
"listgrants-rights": "Права",
"trackingcategories": "Следечки категории",
"delete-toobig": "Оваа страница има долга историја на уредување, преку $1 {{PLURAL:$1|преработка|преработки}}.\nБришењето на ваквии страници е забрането со цел {{SITENAME}} да се заштити од оштетувања.",
"delete-warning-toobig": "Оваа страница има долга историја на уредување, преку $1 {{PLURAL:$1|преработка|преработки}}.\nБришењето може да предизвика проблеми при работењето на базата на податоци на {{SITENAME}};\nпродолжете доколку сте сигруни дека треба тоа да го сторите.",
"deleteprotected": "Не можете да ја избришете страницава бидејќи е заштитена.",
- "deleting-backlinks-warning": "'''Предупредување:''' До страницата што сакате да ја избришете водат [[Special:WhatLinksHere/{{FULLPAGENAME}}|други страници]] или пак се превметнуваат во неа.",
+ "deleting-backlinks-warning": "<strong>Предупредување:</strong> До страницата што сакате да ја избришете водат [[Special:WhatLinksHere/{{FULLPAGENAME}}|други страници]] или пак се превметнуваат во неа.",
"rollback": "Отповикај промени",
"rollbacklink": "отповикај",
"rollbacklinkcount": "отповикај $1 {{PLURAL:$1|уредување|уредувања}}",
"changecontentmodel-title-label": "Наслов на страницата",
"changecontentmodel-model-label": "Нов содржински модел",
"changecontentmodel-reason-label": "Причина:",
+ "changecontentmodel-submit": "Смени",
"changecontentmodel-success-title": "Содржинскиот модел е изменет",
"changecontentmodel-success-text": "Содржинскиот тип [[:$1]] е изменет.",
"changecontentmodel-cannot-convert": "Содржината на [[:$1]] не може да се претвори во типот $2.",
"changecontentmodel-nodirectediting": "Содржинскиот модел $1 не поддржува непосредно уредување",
+ "changecontentmodel-emptymodels-title": "Нема содржински модели на располагање",
+ "changecontentmodel-emptymodels-text": "Содржината на [[:$1]] не може да се претвори во ниеден тип.",
"log-name-contentmodel": "Дневник на измени во содржинските модели",
"log-description-contentmodel": "Настани поврзани со содржинските модели на една страница",
+ "logentry-contentmodel-new": "$1 {{GENDER:$2|ја создаде}} страницата $3 користејќи го нестандардниот содржински модел „$5“",
"logentry-contentmodel-change": "$1 {{GENDER:$2|го смени}} содржиснкиот модел на страницата $3 од „$4“ на „$5“",
"logentry-contentmodel-change-revertlink": "отповикај",
"logentry-contentmodel-change-revert": "отповикај",
"whatlinkshere-hideredirs": "$1 пренасочувања",
"whatlinkshere-hidetrans": "$1 превметнувања",
"whatlinkshere-hidelinks": "$1 врски",
- "whatlinkshere-hideimages": "$1 врски кон податотека",
+ "whatlinkshere-hideimages": "$1 врски кон податотеката",
"whatlinkshere-filters": "Филтри",
"whatlinkshere-submit": "Дај",
"autoblockid": "Автоблок бр. $1",
"ipb-unblock": "Одблокирај корисник или IP-адреса",
"ipb-blocklist": "Преглед на активни блокирања",
"ipb-blocklist-contribs": "Придонеси на {{GENDER:$1|$1}}",
+ "ipb-blocklist-duration-left": "{{PLURAL:$1|преостанува уште $1|преостануваат уште $1}}",
"unblockip": "Деблокирај корисник",
"unblockiptext": "Користете го долниот образец да го вратите правото на пишување на претходно блокирана IP-адреса или корисничко име.",
"ipusubmit": "Избриши го ова блокирање",
"block-log-flags-hiddenname": "сокриено корисничко име",
"range_block_disabled": "Администраторската можност да блокираат IP групи е исклучена.",
"ipb_expiry_invalid": "Погрешен рок на истекување.",
+ "ipb_expiry_old": "Времето на истекување е постаро од тековното време.",
"ipb_expiry_temp": "Скриените блокирања на корисникот мора да бидат перманентни.",
"ipb_hide_invalid": "Оваа сметка не може да се потисне; има {{PLURAL:$1|повеќе од едно уредување|преку $1 уредувања}}..",
"ipb_already_blocked": "„$1“ е веќе блокиран",
"lockdbsuccesstext": "Базата е заклучена. <br />\nСетете се да ја [[Special:UnlockDB|отклучите]] кога ќе завршите со нејзиното одржување.",
"unlockdbsuccesstext": "Базата е отклучена.",
"lockfilenotwritable": "Податотеката за заклучување на базата не е отворена за пишување.\nЗа да ја заклучите или отклучите базата, податотеката мора да биде достапна за пишување од страна на семрежниот опслужувач.",
+ "databaselocked": "Базата е веќе заклучена.",
"databasenotlocked": "Базата не е заклучена.",
"lockedbyandtime": "(од $1 на $2 цо $3 ч.)",
"move-page": "Премести $1",
"confirm-watch-top": "Да ја додадам страницава во набљудуваните?",
"confirm-unwatch-button": "ОК",
"confirm-unwatch-top": "Да ја отстранам страницава од набљудуваните?",
+ "confirm-rollback-button": "ОК",
+ "confirm-rollback-top": "Да ги отповикам уредувањата на страницава?",
"percent": "$1 %",
"quotation-marks": "„$1“",
"imgmultipageprev": "← претходна страница",
"tags-edit-revision-legend": "Додајте или отстранете ознаки од {{PLURAL:$1|преработкава|сите $1 преработки}}",
"tags-edit-logentry-legend": "Додајте или отстранете ознаки од {{PLURAL:$1|овој дневнички запис|сите $1 дневнички записи}}",
"tags-edit-existing-tags": "Постоечки ознаки",
- "tags-edit-existing-tags-none": "''нема''",
+ "tags-edit-existing-tags-none": "<em>Нема</em>",
"tags-edit-new-tags": "Нови ознаки:",
"tags-edit-add": "Додај ги следниве ознаки:",
"tags-edit-remove": "Отстрани ги следниве ознаки:",
"tags-edit-reason": "Причина:",
"tags-edit-revision-submit": "Примени измени врз {{PLURAL:$1|преработкава|$1 преработки}}",
"tags-edit-logentry-submit": "Примени измени врз {{PLURAL:$1|овој дневнички запис|$1 дневнички записи}}",
- "tags-edit-success": "Измените се успешно применети.",
+ "tags-edit-success": "Измените се применети.",
"tags-edit-failure": "Не можев да ги применам измените:\n$1",
"tags-edit-nooldid-title": "Неважечка целна преработка",
"tags-edit-nooldid-text": "Немате укажано целна преработка врз која би се примениле измените, или пак укажаната преработка не постои.",
"logentry-protect-protect-cascade": "$1 {{GENDER:$2|стави заштита}} на $3 $4 [каскадно]",
"logentry-protect-modify": "$1 {{GENDER:$2|го измени}} степенот на заштита на $3 $4",
"logentry-protect-modify-cascade": "$1 {{GENDER:$2|го измени}} степенот на заштита на $3 $4 [каскадно]",
- "logentry-rights-rights": "$1 {{GENDER:$2|го измени}} групното членство на $3 од $4 во $5",
+ "logentry-rights-rights": "$1 {{GENDER:$2|го измени}} групното членство на {{GENDER:$6|$3}} од $4 во $5",
"logentry-rights-rights-legacy": "$1 {{GENDER:$2|го измени}} групното членство во $3",
"logentry-rights-autopromote": "$1 автоматски {{GENDER:$2|унапреден|унапредена}} од $4 во $5",
"logentry-upload-upload": "$1 {{GENDER:$2|ја подигна}} $3",
"special-characters-group-ipa": "МФА",
"special-characters-group-symbols": "Симболи",
"special-characters-group-greek": "Грчки",
+ "special-characters-group-greekextended": "Грчки (допол.)",
"special-characters-group-cyrillic": "Кирилица",
"special-characters-group-arabic": "Арапски",
"special-characters-group-arabicextended": "Арапски-проширено",
"api-error-blacklisted": "Одберете поинаков, описен наслов.",
"sessionprovider-generic": "$1 седници",
"sessionprovider-mediawiki-session-cookiesessionprovider": "седници со колачиња",
- "randomrootpage": "Случајна основна страница"
+ "randomrootpage": "Случајна основна страница",
+ "log-action-filter-block": "Тип на блок:",
+ "log-action-filter-contentmodel": "Тип на змена на содржинскиот модел:",
+ "log-action-filter-delete": "Тип на бришење:",
+ "log-action-filter-import": "Тип на увоз:",
+ "log-action-filter-managetags": "Тип на дејство за управување со ознаки:",
+ "log-action-filter-move": "Тип на преместување:",
+ "log-action-filter-newusers": "Тип на создавање сметка:",
+ "log-action-filter-patrol": "Тип на патролирање:",
+ "log-action-filter-protect": "Тип на заштита:",
+ "log-action-filter-rights": "Тип на промена во правата",
+ "log-action-filter-suppress": "Тип на скривање",
+ "log-action-filter-upload": "Тип на подигање:",
+ "log-action-filter-all": "Сите",
+ "log-action-filter-block-block": "блокирање",
+ "log-action-filter-block-reblock": "Измена на блок",
+ "log-action-filter-block-unblock": "Одблокирање",
+ "log-action-filter-contentmodel-change": "Промена на содржински модел",
+ "log-action-filter-contentmodel-new": "Создавање страница со нестандарден содржински модел",
+ "log-action-filter-delete-delete": "Бришење на страница",
+ "log-action-filter-delete-restore": "Повраток на страница",
+ "log-action-filter-delete-event": "Бришење на дневник",
+ "log-action-filter-delete-revision": "Бришење на преработка",
+ "log-action-filter-import-interwiki": "Прекувики-увоз",
+ "log-action-filter-import-upload": "Увоз со подигање XML",
+ "log-action-filter-managetags-create": "Создавање на ознаки",
+ "log-action-filter-managetags-delete": "Бришење на ознаки",
+ "log-action-filter-managetags-activate": "Активирање на ознаки",
+ "log-action-filter-managetags-deactivate": "Деактивирање на ознаки",
+ "log-action-filter-move-move": "Преместување без запис врз пренасочувања",
+ "authmanager-authplugin-setpass-bad-domain": "Неважечки домен.",
+ "authmanager-autocreate-noperm": "Автоматското создавање на сметки не е дозволено.",
+ "authmanager-autocreate-exception": "Автоматското создавање на сметки е привремено оневозможено поради претходни грешки.",
+ "authmanager-userdoesnotexist": "Корисничката сметка „$1“ не е регистрирана.",
+ "authmanager-userlogin-remembermypassword-help": "Дали лозинката да биде запаметена подолго од траењето на седницата.",
+ "authmanager-username-help": "Корисничко име за заверка.",
+ "authmanager-password-help": "Лозинка за заверка.",
+ "authmanager-domain-help": "Домен за надворешна заверка.",
+ "authmanager-retype-help": "Повторно лозинката (за потврда).",
+ "authmanager-email-label": "Е-пошта",
+ "authmanager-email-help": "Е-пошта:",
+ "authmanager-realname-label": "Вистинско име",
+ "authmanager-realname-help": "Вистинско име на корисникот",
+ "authmanager-provider-password": "Заверка со лозинка",
+ "authmanager-provider-password-domain": "Заверка со лозинка и домен",
+ "authmanager-provider-temporarypassword": "Привремена лозинка",
+ "authprovider-resetpass-skip-label": "Прескокни",
+ "authprovider-resetpass-skip-help": "Прескокни го задавањето на нова лозинка."
}
"noname": "താങ്കൾ സാധുവായ ഉപയോക്തൃനാമം സൂചിപ്പിച്ചിട്ടില്ല.",
"loginsuccesstitle": "സ്വാഗതം! \nതാങ്കൾ വിജയകരമായി പ്രവേശിച്ചിരിക്കുന്നു.",
"loginsuccess": "'''{{SITENAME}} സംരംഭത്തിൽ \"$1\" എന്ന പേരിൽ താങ്കൾ ലോഗിൻ ചെയ്തിരിക്കുന്നു.'''",
- "nosuchuser": "ഇതുവരെ \"$1\" എന്ന പേരിൽ ആരും അംഗത്വമെടുത്തിട്ടില്ല.\nദയവായി അക്ഷരപ്പിശകുകൾ പരിശോധിക്കുക, അല്ലെങ്കിൽ\nപുതിയ [[Special:UserLogin/signup|അംഗത്വമെടുക്കുക]].",
+ "nosuchuser": "ഇതുവരെ \"$1\" എന്ന പേരിൽ ആരും അംഗത്വമെടുത്തിട്ടില്ല.\nദയവായി അക്ഷരപ്പിശകുകൾ പരിശോധിക്കുക, അല്ലെങ്കിൽ\nപുതിയ [[Special:CreateAccount|അംഗത്വമെടുക്കുക]].",
"nosuchusershort": "\"$1\" എന്ന പേരിൽ ഒരു ഉപയോക്താവ് ഇല്ല. അക്ഷരങ്ങൾ ഒന്നു കൂടി പരിശോധിക്കുക.",
"nouserspecified": "ഉപയോക്തൃനാമം നിർബന്ധമായും ചേർക്കണം.",
"login-userblocked": "ഈ ഉപയോക്താവ് തടയപ്പെട്ടിരിക്കുന്നു. പ്രവേശനം അനുവദിക്കുന്നില്ല.",
"accmailtext": "[[User talk:$1|$1]] എന്ന ഉപയോക്താവിനുള്ള ക്രമരഹിതമായി നിർമ്മിച്ച രഹസ്യവാക്ക് $2 എന്ന വിലാസത്തിലേക്ക് അയച്ചിട്ടുണ്ട്. പ്രവേശിച്ചതിനു ശേഷം ഇത് ''[[Special:ChangePassword|രഹസ്യവാക്ക് മാറ്റുക]]'' എന്ന താളിൽ മാറ്റാവുന്നതാണ്.",
"newarticle": "(പുതിയത്)",
"newarticletext": "ഇതുവരെ നിലവിലില്ലാത്ത ഒരു താൾ സൃഷ്ടിക്കാനുള്ള ശ്രമത്തിലാണ് താങ്കൾ. അതിനായി താഴെ ആവശ്യമുള്ള വിവരങ്ങൾ എഴുതിച്ചേർത്ത് സേവ് ചെയ്യുക (കൂടുതൽ വിവരങ്ങൾക്ക് [$1 സഹായം താൾ] കാണുക). താങ്കളിവിടെ അബദ്ധത്തിൽ വന്നതാണെങ്കിൽ ബ്രൗസറിന്റെ ബാക്ക് ബട്ടൺ ഞെക്കിയാൽ തിരിച്ചുപോകാം.",
- "anontalkpagetext": "----\n{| class=\"messagebox standard-talk\" style=\"border: 1px solid #B3B300; background-color:#FFFFBF; text-align: left;\"\n|\n''ഇതുവരെ അംഗത്വം എടുക്കാതിരിക്കുകയോ, നിലവിലുള്ള അംഗത്വം ഉപയോഗിക്കാതിരിക്കുകയോ ചെയ്യുന്ന '''ഒരു അജ്ഞാത ഉപയോക്താവിന്റെ സംവാദം താളാണിത്'''.\nഅതിനാൽ അദ്ദേഹത്തെ തിരിച്ചറിയുവാൻ അക്കരൂപത്തിലുള്ള ഐ.പി. വിലാസം ഉപയോഗിക്കേണ്ടതുണ്ട്. ഇത്തരം ഒരു ഐ.പി. വിലാസം പല ഉപയോക്താക്കൾ പങ്കുവെക്കുന്നുണ്ടാവാം.\nതാങ്കൾ ഈ സന്ദേശം ലഭിച്ച ഒരു അജ്ഞാത ഉപയോക്താവാണെങ്കിൽ, ഭാവിയിൽ ഇതര ഉപയോക്താക്കളുമായി ഉണ്ടായേക്കാവുന്ന ആശയക്കുഴപ്പം ഒഴിവാക്കാൻ ദയവായി [[Special:UserLogin/signup|ഒരു അംഗത്വമെടുക്കുക]] അല്ലെങ്കിൽ [[Special:UserLogin|പ്രവേശിക്കുക]].\n|}",
+ "anontalkpagetext": "----\n{| class=\"messagebox standard-talk\" style=\"border: 1px solid #B3B300; background-color:#FFFFBF; text-align: left;\"\n|\n''ഇതുവരെ അംഗത്വം എടുക്കാതിരിക്കുകയോ, നിലവിലുള്ള അംഗത്വം ഉപയോഗിക്കാതിരിക്കുകയോ ചെയ്യുന്ന '''ഒരു അജ്ഞാത ഉപയോക്താവിന്റെ സംവാദം താളാണിത്'''.\nഅതിനാൽ അദ്ദേഹത്തെ തിരിച്ചറിയുവാൻ അക്കരൂപത്തിലുള്ള ഐ.പി. വിലാസം ഉപയോഗിക്കേണ്ടതുണ്ട്. ഇത്തരം ഒരു ഐ.പി. വിലാസം പല ഉപയോക്താക്കൾ പങ്കുവെക്കുന്നുണ്ടാവാം.\nതാങ്കൾ ഈ സന്ദേശം ലഭിച്ച ഒരു അജ്ഞാത ഉപയോക്താവാണെങ്കിൽ, ഭാവിയിൽ ഇതര ഉപയോക്താക്കളുമായി ഉണ്ടായേക്കാവുന്ന ആശയക്കുഴപ്പം ഒഴിവാക്കാൻ ദയവായി [[Special:CreateAccount|ഒരു അംഗത്വമെടുക്കുക]] അല്ലെങ്കിൽ [[Special:UserLogin|പ്രവേശിക്കുക]].\n|}",
"noarticletext": "ഈ താളിൽ ഇതുവരെ ഉള്ളടക്കം ആയിട്ടില്ല.\nതാങ്കൾക്ക് മറ്റുതാളുകളിൽ [[Special:Search/{{PAGENAME}}|ഇതേക്കുറിച്ച് അന്വേഷിക്കുകയോ]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ബന്ധപ്പെട്ട രേഖകൾ പരിശോധിക്കുകയോ], [{{fullurl:{{FULLPAGENAME}}|action=edit}} ഈ താൾ തിരുത്തുകയോ ചെയ്യാവുന്നതാണ്]</span>.",
"noarticletext-nopermission": "ഇപ്പോൾ ഈ താളിൽ എഴുത്തുകളൊന്നും ഇല്ല.\nതാങ്കൾക്ക് മറ്റു താളുകളിൽ [[Special:Search/{{PAGENAME}}|ഈ താളിന്റെ തലക്കെട്ടിനായി തിരയാവുന്നതാണ്]], അല്ലെങ്കിൽ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ബന്ധപ്പെട്ട രേഖകൾ പരിശോധിക്കാവുന്നതാണ്]</span>. പക്ഷേ ഈ താൾ സൃഷ്ടിക്കാൻ താങ്കൾക്ക് അനുവാദമില്ല.",
"missing-revision": "\"{{FULLPAGENAME}}\" എന്ന താളിന്റെ #$1 എന്ന നാൾപ്പതിപ്പ് നിലവിലില്ല.\n\nമായ്ക്കപ്പെട്ട താളിന്റെ കാലഹരണപ്പെട്ട നാൾവഴി കണ്ണി ഉപയോഗിച്ചാലാണ് സാധാരണ ഇങ്ങനെ സംഭവിക്കുക.\nകൂടുതൽ വിവരങ്ങൾ [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} മായ്ക്കൽ രേഖയിൽ] കാണാവുന്നതാണ്.",
"upload-form-label-own-work": "ഇതെന്റെ സ്വന്തം സൃഷ്ടി ആണ്",
"upload-form-label-infoform-categories": "വർഗ്ഗങ്ങൾ",
"upload-form-label-infoform-date": "തീയതി",
- "upload-form-label-own-work-message-local": "{{SITENAME}} സംരംഭത്തിലെ സേവന നിബന്ധനകൾക്കും ഉപയോഗാനുമതി നയങ്ങൾക്കും അനുസരിച്ചാണ് ഈ പ്രമാണം അപ്ലോഡ് ചെയ്യുന്നതെന്ന് ഞാൻ സ്ഥിരീകരിക്കുന്നു.",
- "upload-form-label-not-own-work-message-local": "{{SITENAME}} സംരംഭത്തിലെ നയങ്ങളനുസരിച്ച് താങ്കൾക്ക് ഈ പ്രമാണം അപ്ലോഡ് ചെയ്യാൻ കഴിയില്ലെങ്കിൽ, ദയവായി ഇത് അടച്ച് മറ്റൊരു മാർഗ്ഗം ശ്രമിക്കുക.",
- "upload-form-label-not-own-work-local-local": "താങ്കൾക്ക് [[Special:Upload|സ്വതേ ഉള്ള അപ്ലോഡ് താളും]] പരിശോധിക്കാവുന്നതാണ്.",
- "upload-form-label-own-work-message-default": "ഈ പ്രമാണം പങ്ക് വെയ്ക്കപ്പെട്ടിരിക്കുന്ന ഒരു ശേഖരത്തിലോട്ടാണ് അപ്ലോഡ് ചെയ്യുന്നതെന്ന് ഞാൻ മനസ്സിലാക്കുന്നു. അവിടുത്തെ ഉപയോഗ നിബന്ധനകൾക്കും അനുമതി നയങ്ങൾക്കും അനുസൃതമായാണ് ഇത് ചെയ്യുന്നതെന്ന് ഞാൻ സ്ഥിരീകരിക്കുന്നു.",
- "upload-form-label-not-own-work-message-default": "പങ്ക് വെയ്ക്കപ്പെട്ടിരിക്കുന്ന ശേഖരത്തിന്റെ നയങ്ങളനുസരിച്ച് താങ്കൾക്ക് ഈ പ്രമാണം അപ്ലോഡ് ചെയ്യാൻ കഴിയില്ലെങ്കിൽ, ദയവായി ഇത് അടക്കുകയും മറ്റൊരു മാർഗ്ഗം ശ്രമിക്കുകയും ചെയ്യുക.",
- "upload-form-label-not-own-work-local-default": "ഈ പ്രമാണം അവരുടെ നയങ്ങളുമായി ചേർന്നുപോകുമെങ്കിൽ താങ്കൾക്ക് [[Special:Upload|{{SITENAME}} സംരംഭത്തിലെ അപ്ലോഡ് താൾ]] പരീക്ഷിച്ചു നോക്കാവുന്നതാണ്.",
- "upload-form-label-own-work-message-shared": "ഈ പ്രമാണത്തിന്റെ പകർപ്പവകാശം എനിക്ക് സ്വന്തമാണെന്നും, ഈ പ്രമാണം വിക്കിമീഡിയ കോമൺസിൽ പിന്നീട് മാറ്റാനാവത്തവിധം [https://creativecommons.org/licenses/by-sa/4.0/ ക്രിയേറ്റീവ് കോമൺസ് ആട്രിബ്യൂഷൻ-ഷെയർഎലൈക് 4.0] ഉപയോഗാനുമതിയിൽ പ്രസിദ്ധീകരിക്കാമെന്നും [https://wikimediafoundation.org/wiki/Terms_of_Use/ml ഉപയോഗനിബന്ധനകൾ] അംഗീകരിക്കുന്നുവെന്നും സാക്ഷ്യപ്പെടുത്തുന്നു.",
- "upload-form-label-not-own-work-message-shared": "ഈ പ്രമാണത്തിന്റെ പകർപ്പവകാശം താങ്കളുടെ സ്വന്തമല്ലെങ്കിൽ അഥവാ മറ്റൊരു ഉപയോഗാനുമതിയിലാണ് പ്രമാണം പ്രസിദ്ധീകരിക്കാൻ ഉദ്ദേശിക്കുന്നതെങ്കിൽ [https://commons.wikimedia.org/wiki/Special:UploadWizard?uselang=ml കോമൺസിലെ അപ്ലോഡ് സഹായി] ഉപയോഗിക്കുന്നത് പരിഗണിക്കുക.",
- "upload-form-label-not-own-work-local-shared": "ഈ പ്രമാണം അവരുടെ നയങ്ങൾക്കനുസൃതമായി അപ്ലോഡ് ചെയ്യാൻ സൈറ്റ് അനുവദിക്കുമെങ്കിൽ [[Special:Upload|{{SITENAME}} സംരംഭത്തിലെ അപ്ലോഡ് താൾ]] പരീക്ഷിച്ചു നോക്കാവുന്നതാണ്.",
+ "upload-form-label-own-work-message-generic-local": "{{SITENAME}} സംരംഭത്തിലെ സേവന നിബന്ധനകൾക്കും ഉപയോഗാനുമതി നയങ്ങൾക്കും അനുസരിച്ചാണ് ഈ പ്രമാണം അപ്ലോഡ് ചെയ്യുന്നതെന്ന് ഞാൻ സ്ഥിരീകരിക്കുന്നു.",
+ "upload-form-label-not-own-work-message-generic-local": "{{SITENAME}} സംരംഭത്തിലെ നയങ്ങളനുസരിച്ച് താങ്കൾക്ക് ഈ പ്രമാണം അപ്ലോഡ് ചെയ്യാൻ കഴിയില്ലെങ്കിൽ, ദയവായി ഇത് അടച്ച് മറ്റൊരു മാർഗ്ഗം ശ്രമിക്കുക.",
+ "upload-form-label-not-own-work-local-generic-local": "താങ്കൾക്ക് [[Special:Upload|സ്വതേ ഉള്ള അപ്ലോഡ് താളും]] പരിശോധിക്കാവുന്നതാണ്.",
+ "upload-form-label-own-work-message-generic-foreign": "ഈ പ്രമാണം പങ്ക് വെയ്ക്കപ്പെട്ടിരിക്കുന്ന ഒരു ശേഖരത്തിലോട്ടാണ് അപ്ലോഡ് ചെയ്യുന്നതെന്ന് ഞാൻ മനസ്സിലാക്കുന്നു. അവിടുത്തെ ഉപയോഗ നിബന്ധനകൾക്കും അനുമതി നയങ്ങൾക്കും അനുസൃതമായാണ് ഇത് ചെയ്യുന്നതെന്ന് ഞാൻ സ്ഥിരീകരിക്കുന്നു.",
+ "upload-form-label-not-own-work-message-generic-foreign": "പങ്ക് വെയ്ക്കപ്പെട്ടിരിക്കുന്ന ശേഖരത്തിന്റെ നയങ്ങളനുസരിച്ച് താങ്കൾക്ക് ഈ പ്രമാണം അപ്ലോഡ് ചെയ്യാൻ കഴിയില്ലെങ്കിൽ, ദയവായി ഇത് അടക്കുകയും മറ്റൊരു മാർഗ്ഗം ശ്രമിക്കുകയും ചെയ്യുക.",
+ "upload-form-label-not-own-work-local-generic-foreign": "ഈ പ്രമാണം അവരുടെ നയങ്ങളുമായി ചേർന്നുപോകുമെങ്കിൽ താങ്കൾക്ക് [[Special:Upload|{{SITENAME}} സംരംഭത്തിലെ അപ്ലോഡ് താൾ]] പരീക്ഷിച്ചു നോക്കാവുന്നതാണ്.",
"backend-fail-stream": "$1 എന്ന പ്രമാണം സ്ട്രീം ചെയ്യാൻ കഴിഞ്ഞില്ല.",
"backend-fail-backup": "$1 എന്ന പ്രമാണത്തിന്റെ ബാക്ക്അപ് എടുക്കാൻ കഴിഞ്ഞില്ല.",
"backend-fail-notexists": "$1 എന്ന പ്രമാണം നിലവിലില്ല.",
"noname": "Та хүчинтэй хэрэглэгчийн нэрийг өгөөгүй байна.",
"loginsuccesstitle": "Амжилттай нэвтэрлээ",
"loginsuccess": "'''Та {{SITENAME}} руу \"$1\" нэрээр нэвтэрлээ.'''",
- "nosuchuser": "\"$1\" нэртэй хэрэглэгч олдсонгүй.\nХэрэглэгчийн нэрийн үсгүүд том жижгээр бичсэн байдлаар өөр байна.\nТа зөв бичсэн эсэхээ шалгах, эсвэл [[Special:UserLogin/signup| шинээр бүртгүүлнэ үү]].",
+ "nosuchuser": "\"$1\" нэртэй хэрэглэгч олдсонгүй.\nХэрэглэгчийн нэрийн үсгүүд том жижгээр бичсэн байдлаар өөр байна.\nТа зөв бичсэн эсэхээ шалгах, эсвэл [[Special:CreateAccount| шинээр бүртгүүлнэ үү]].",
"nosuchusershort": "\"$1\" гэсэн нэртэй хэрэглэгч байхгүй байна.\nҮсгийн алдаагаа шалгана уу.",
"nouserspecified": "Та хэрэглэгчийн нэрээ зааж өгөх хэрэгтэй.",
"login-userblocked": "Энэхүү хэрэглэгчийг түгжсэн байна. Нэвтрэх боломжгүй.",
"accmailtext": "[[User talk:$1|$1]]-н санамсаргүй байдлаар үүсгэгдсэн нууц үг $2 руу илгээгдлээ.\n\nНэвтэрч орсны дараа энэ шинэ бүртгэлийн нууц үгийг ''[[Special:ChangePassword|энэ хуудсаар]]'' солих боломжтой.",
"newarticle": "(Шинэ)",
"newarticletext": "Таны орохыг хүссэн хуудас байхгүй байна. Энэ хуудсыг шинээр үүсгэхийн тулд доорх талбарт мэдээллээ оруулна уу (дэлгэрэ\nнгүй мэдээллийг [$1 тусламжийн хуудсаас] авч болно).\nХэрэв та энд санамсаргүйгээр орж ирсэн бол броузерийнхаа '''back''' товчийг дар.",
- "anontalkpagetext": "----''Энэ нь хараахан бүртгүүлээгүй байгаа буюу хэрэглэгчийн нэр хэрэглэхгүй байгаа хэрэглэгчийн хэлэлцүүлгийн хуудас болно.\nБид ийм хэрэглэгчдийг тогтоохын тулд IP хаягийг нь ашигладаг.\nНэг IP хаягийг хэд хэдэн хэрэглэгч хамтран ашиглаж байж болно.\nХэрвээ таны IP хаягт ирсэн санал хүсэлтүүд танд хандаагүй бөгөөд та цаашид ийм байдал үүсэхээс сэргийлье гэвэл [[Special:UserLogin/signup|бүртгүүлэх]] буюу [[Special:UserLogin|нэвтрэхийг]] хүсье.''",
+ "anontalkpagetext": "----''Энэ нь хараахан бүртгүүлээгүй байгаа буюу хэрэглэгчийн нэр хэрэглэхгүй байгаа хэрэглэгчийн хэлэлцүүлгийн хуудас болно.\nБид ийм хэрэглэгчдийг тогтоохын тулд IP хаягийг нь ашигладаг.\nНэг IP хаягийг хэд хэдэн хэрэглэгч хамтран ашиглаж байж болно.\nХэрвээ таны IP хаягт ирсэн санал хүсэлтүүд танд хандаагүй бөгөөд та цаашид ийм байдал үүсэхээс сэргийлье гэвэл [[Special:CreateAccount|бүртгүүлэх]] буюу [[Special:UserLogin|нэвтрэхийг]] хүсье.''",
"noarticletext": "Одоогийн байдлаар энэ хуудсанд текст алга.\nТа нэг бол энэ хуудасны нэрээр бусад хуудсуудад [[Special:Search/{{PAGENAME}}|хайлт хийх]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} холбоотой логуудад хайлт хийх],\nэсвэл [{{fullurl:{{FULLPAGENAME}}|action=edit}} энэ хуудсыг засварлаж болно]</span>.",
"noarticletext-nopermission": "Яг одоогоор уг хуудсанд текст алга.\nТа бусад хуудсан уг хуудасны [[Special:Search/{{PAGENAME}}| гарчигаар хайлт хийх]], эсвэл <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} холбоотой логоор хайлт]</span> хийж болно, гэхдээ танд уг хуудсыг үүсгэх зөвшөөрөл алга.",
"userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" хэрэглэгчийн бүртгэл бүртгэгдээгүй байна. Та энэ хуудсыг үүсгэх/засварлах тухайгаа дахин тунгааж бодно уу.",
"noname": "आपण वैध सदस्यनाम नमूद केले नाही.",
"loginsuccesstitle": "आपल्या सनोंद-प्रवेशाची नोंदणी यशस्वीरीत्या पूर्ण झाली",
"loginsuccess": "'''तुम्ही {{SITENAME}} वर \"$1\" नावाने सनोंद प्रवेशित आहात.'''",
- "nosuchuser": "\"$1\" या नावाचा कोणताही सदस्य नाही.तुमचे शुद्धलेखन तपासा, किंवा [[Special:UserLogin/signup|नवीन खाते]] तयार करा.",
+ "nosuchuser": "\"$1\" या नावाचा कोणताही सदस्य नाही.तुमचे शुद्धलेखन तपासा, किंवा [[Special:CreateAccount|नवीन खाते]] तयार करा.",
"nosuchusershort": "\"$1\" या नावाचा सदस्य नाही. लिहीताना आपली चूक तर नाही ना झाली?",
"nouserspecified": "तुम्हाला सदस्यनाव नमूद करावे लागेल.",
"login-userblocked": "हा सदस्य ’प्रतिबंधित’ आहे. त्यास सनोंद-प्रवेशाची परवानगी नाही.",
"accmailtext": "[[User talk:$1|$1]] यांसाठी अनियतक्रमाने निर्मित केलेला परवलीचा शब्द $2 यांना पाठवण्यात आला आहे.\n\nया नवीन खात्यासाठीचा परवलीचा शब्द,सनोंद-प्रवेश घेतल्यावर [[Special:ChangePassword|परवलीचा शब्द बदला]] येथे बदलता येईल.",
"newarticle": "(नवीन लेख)",
"newarticletext": "आपण सध्या अस्तित्त्वात नसलेल्या पानाच्या दुव्याचा मागोवा घेत आला आहात.\nहे पान नव्याने तयार करण्यासाठी खालील पेटीत टंकन करणे सुरु करा(अधिक माहितीसाठी [$1 साहाय्य पान] बघा).\n\nजर आपण येथे चुकून आला असाल तर ब्राउझरच्या <strong>परत</strong>(बॅक) कळीवर टिचकी द्या.",
- "anontalkpagetext": "---- ''हे चर्चापान अशा अज्ञात सदस्यासाठी आहे, ज्यांनी खाते तयार केलेले नाही किंवा त्याचा वापर करत नाहीत. त्यांच्या ओळखीसाठी आम्ही आंतरजाल अंकपत्ता वापरतो आहोत. असा अंकपत्ता बऱ्याच लोकांचा एकच असू शकतो. जर आपण अज्ञात सदस्य असाल आणि आपल्याला काही अप्रासंगिक संदेश मिळाला असेल तर कृपया [[Special:UserLogin| खाते तयार करा]] किंवा [[Special:UserLogin/signup|सनोंद-प्रवेश करा]] ज्यामुळे, पुढे असे गैरसमज होणार नाहीत.''",
+ "anontalkpagetext": "---- ''हे चर्चापान अशा अज्ञात सदस्यासाठी आहे, ज्यांनी खाते तयार केलेले नाही किंवा त्याचा वापर करत नाहीत. त्यांच्या ओळखीसाठी आम्ही आंतरजाल अंकपत्ता वापरतो आहोत. असा अंकपत्ता बऱ्याच लोकांचा एकच असू शकतो. जर आपण अज्ञात सदस्य असाल आणि आपल्याला काही अप्रासंगिक संदेश मिळाला असेल तर कृपया [[Special:UserLogin| खाते तयार करा]] किंवा [[Special:CreateAccount|सनोंद-प्रवेश करा]] ज्यामुळे, पुढे असे गैरसमज होणार नाहीत.''",
"noarticletext": "या लेखात सध्या काहीही मजकूर नाही.\nतुम्ही विकिपीडियावरील इतर लेखांमध्ये या [[Special:Search/{{PAGENAME}}| मथळ्याचा शोध घेऊ शकता]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} इतर नोंदी शोधा],\nकिंवा हा लेख [{{fullurl:{{FULLPAGENAME}}|action=edit}}संपादू शकता]</span>.",
"noarticletext-nopermission": "सध्या या लेखात काहीही मजकूर नाही.\nतुम्ही विकिपीडियावरील इतर लेखांमध्ये [[Special:Search/{{PAGENAME}}| या मथळ्याचा शोध घेऊ शकता]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAME}}}}आपण या लेखाच्या इतर नोंदी शोधा]</span>,परंतु, आपणास हा लेख लिहीण्याची परवानगी देण्यात येउ शकत नाही.",
"missing-revision": "\"{{FULLPAGENAME}}\" या लेखाचे #$1 हे संस्करण अस्तित्वात नाही.वगळल्या गेलेल्या लेखपानाच्या जुन्या इतिहास-दुव्याचे अनुसरण केल्यामुळे असे होते.याबाबत विस्तृत माहिती [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} वगळलेल्या नोंदी]येथे बघता येईल.",
"noname": "Nama pengguna tidak sah.",
"loginsuccesstitle": "Berjaya log masuk",
"loginsuccess": "'''Anda telah log masuk ke dalam {{SITENAME}} sebagai \"$1\".'''",
- "nosuchuser": "Pengguna \"$1\" tidak wujud. Nama pengguna adalah peka huruf besar. Sila semak ejaan anda, atau anda boleh [[Special:UserLogin/signup|membuka akaun baru]].",
+ "nosuchuser": "Pengguna \"$1\" tidak wujud. Nama pengguna adalah peka huruf besar. Sila semak ejaan anda, atau anda boleh [[Special:CreateAccount|membuka akaun baru]].",
"nosuchusershort": "Pengguna \"$1\" tidak wujud. Sila semak ejaan anda.",
"nouserspecified": "Sila nyatakan nama pengguna.",
"login-userblocked": "Pengguna ini disekat. Log masuk tidak dibenarkan.",
"accmailtext": "Kata laluan janaan rawak untuk [[User talk:$1|$1]] telah dikirim kepada $2. Anda boleh menukarnya di halaman ''[[Special:ChangePassword|tukar kata laluan]]'' sebaik sahaja log masuk.",
"newarticle": "(Baru)",
"newarticletext": "Anda telah mengikuti pautan ke laman yang belum wujud.\nUntuk mencipta laman ini, sila taip dalam kotak di bawah\n(lihat [$1 laman bantuan] untuk maklumat lanjut).\nJika anda tiba di sini secara tak sengaja, hanya klik butang '''back''' pada pelayar anda.",
- "anontalkpagetext": "----''Ini ialah laman perbincangan bagi pengguna tanpa nama yang belum membuka akaun atau tidak log masuk.\nOleh itu kami terpaksa menggunakan alamat IP untuk mengenal pasti pengguna tersebut. Alamat IP ini boleh dikongsi oleh ramai pengguna.\nSekiranya anda adalah seorang pengguna tanpa nama dan berasa bahawa komen yang tidak kena mengena telah ditujukan kepada anda, sila [[Special:UserLogin/signup|buka akaun baru]] atau [[Special:UserLogin|log masuk]] untuk mengelakkan sebarang kekeliruan dengan pengguna tanpa nama yang lain.''",
+ "anontalkpagetext": "----''Ini ialah laman perbincangan bagi pengguna tanpa nama yang belum membuka akaun atau tidak log masuk.\nOleh itu kami terpaksa menggunakan alamat IP untuk mengenal pasti pengguna tersebut. Alamat IP ini boleh dikongsi oleh ramai pengguna.\nSekiranya anda adalah seorang pengguna tanpa nama dan berasa bahawa komen yang tidak kena mengena telah ditujukan kepada anda, sila [[Special:CreateAccount|buka akaun baru]] atau [[Special:UserLogin|log masuk]] untuk mengelakkan sebarang kekeliruan dengan pengguna tanpa nama yang lain.''",
"noarticletext": "Laman ini buat masa sekarang tidak berteks. Anda boleh [[Special:Search/{{PAGENAME}}|cari tajuk bagi laman ini]] dalam laman-laman lain, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cari log-log yang berkaitan], atau [{{fullurl:{{FULLPAGENAME}}|action=edit}} sunting laman ini]</span>.",
"noarticletext-nopermission": "Tiada teks dalam laman ini ketika ini.\nAnda boleh [[Special:Search/{{PAGENAME}}|mencari tajuk laman ini]] dalam laman lain,\natau <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mencari log yang berkaitan]</span>.",
"missing-revision": "Semakan #$1 pada halaman \"{{FULLPAGENAME}}\" tidak wujud.\n\nHal ini biasanya disebabkan oleh pautan sejarah yang lapuk ke halaman yang sudah dihapuskan.\nButirannya boleh didapati di [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log penghapusan].",
"upload-form-label-own-work": "Ini ialah karya saya sendiri",
"upload-form-label-infoform-categories": "Kategori",
"upload-form-label-infoform-date": "Tarikh",
- "upload-form-label-own-work-message-local": "Saya mengesahkan bahawa saya memuat naik fail ini dengan mengikut terma perkhidmatan dan dasar perlesenan di {{SITENAME}}.",
- "upload-form-label-not-own-work-local-local": "Anda mungkin juga mahu mencuba [[Special:Upload|laman muat naik yang asal]].",
+ "upload-form-label-own-work-message-generic-local": "Saya mengesahkan bahawa saya memuat naik fail ini dengan mengikut terma perkhidmatan dan dasar perlesenan di {{SITENAME}}.",
+ "upload-form-label-not-own-work-local-generic-local": "Anda mungkin juga mahu mencuba [[Special:Upload|laman muat naik yang asal]].",
"backend-fail-stream": "Fail $1 tidak dapat distrimkan.",
"backend-fail-backup": "Fail $1 tidak dapat disandarkan.",
"backend-fail-notexists": "Fail $1 tidak wujud.",
"noname": "L-isem tal-utent li tajt mhuwiex validu.",
"loginsuccesstitle": "Dħalt b'suċċess",
"loginsuccess": "'''Irnexxielek taqbad mas-server ta' {{SITENAME}} bl-isem tal-utent \"$1\".'''",
- "nosuchuser": "M'hemm l-ebda utent bl-isem ta' \"$1\".<br />\nL-ismijiet tal-utenti huma sensittivi fuq kif jinkitbu.<br />\nJekk jogħġbok kun żġur li ktibtu sew, jew minflok [[Special:UserLogin/signup|oħloq kont ġdid]].",
+ "nosuchuser": "M'hemm l-ebda utent bl-isem ta' \"$1\".<br />\nL-ismijiet tal-utenti huma sensittivi fuq kif jinkitbu.<br />\nJekk jogħġbok kun żġur li ktibtu sew, jew minflok [[Special:CreateAccount|oħloq kont ġdid]].",
"nosuchusershort": "M'hemm l-ebda utent bl-isem \"$1\".\nAgħmel żġur li ktibta sew.",
"nouserspecified": "Trid tispeċifika isem tal-utent.",
"login-userblocked": "Dan l-utent huwa imblukkat. Mhuwiex possibbli li jsir il-login.",
"accmailtext": "Intbagħtet lil $2 password iġġenerata każwalment għal [[User talk:$1|$1]] .\nTista' tinbidel fuq il-paġna għat-<em>[[Special:ChangePassword|tibdil tal-password]]</em> wara d-dħul fil-kont.",
"newarticle": "(Ġdid)",
"newarticletext": "Inti segwejt link għal paġna li għadha ma ġietx maħluqa.\nSabiex toħloq il-paġna, ikteb fil-kaxxa li tinsab hawn taħt (ara [$1 paġna tal-għajnuna] għal aktar informazzjoni).\nJekk wasalt hawn biż-żball, agħfas il-buttuna '''lura''' (''back'') fuq il-browser tiegħek.",
- "anontalkpagetext": "----''Din hija l-paġna ta' diskussjoni ta' utent anonimu li għadu ma ħoloqx kont, jew inkella li ma jużahx.\nGħaldaqstant biex nidentifikawh ikollna nużaw l-indirizz tal-IP tiegħu/tagħha.\nL-istess indirizz tal-IP jista' jkun użat minn bosta utenti differenti.\nJekk int utent anonimu u tħoss li qiegħed tirċievi kummenti irrelevanti jew li ma jagħmlux sens, jekk jogħġbok [[Special:UserLogin|idħol fil-kont tiegħek]] jew [[Special:UserLogin/signup|oħloq wieħed]] sabiex tevita li fil-futur tiġi konfuż ma' utenti anonimi oħra.''",
+ "anontalkpagetext": "----''Din hija l-paġna ta' diskussjoni ta' utent anonimu li għadu ma ħoloqx kont, jew inkella li ma jużahx.\nGħaldaqstant biex nidentifikawh ikollna nużaw l-indirizz tal-IP tiegħu/tagħha.\nL-istess indirizz tal-IP jista' jkun użat minn bosta utenti differenti.\nJekk int utent anonimu u tħoss li qiegħed tirċievi kummenti irrelevanti jew li ma jagħmlux sens, jekk jogħġbok [[Special:UserLogin|idħol fil-kont tiegħek]] jew [[Special:CreateAccount|oħloq wieħed]] sabiex tevita li fil-futur tiġi konfuż ma' utenti anonimi oħra.''",
"noarticletext": "Bħalissa m'hemm l-ebda test f'din il-paġna.\nTista' [[Special:Search/{{PAGENAME}}|tfittex it-titlu ta' din il-paġna]] f'paġni oħra, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tfittex ir-reġistri relatati], jew [{{fullurl:{{FULLPAGENAME}}|action=edit}} toħloq dil-paġna]</span>.",
"noarticletext-nopermission": "Bħalissa m'hemm l-ebda test f'din il-paġna. Inti tista' [[Special:Search/{{PAGENAME}}|tfittex dan it-titlu tal-paġna]] f'paġni oħra, jew <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tfittex ir-reġistri relatati]</span>, imma m'għandikx permess toħloq dil-paġna.",
"missing-revision": "Ir-reviżjoni #$1 tal-paġna bl-isem \"{{FULLPAGENAME}}\" ma teżistix.\n\nDan ħafna drabi jiġri minħabba li tkun segwejt ħolqa lejn paġna mħassra, f'kronoloġija li mhix aġġornata.\nId-detallji tista' ssibhom fir-[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} reġistru tat-tħassir].",
"loginerror": "Erro de outenticaçon",
"loginsuccesstitle": "Antreste cumo debe de ser",
"loginsuccess": "'''Stás agora lhigado a {{SITENAME}} cumo \"$1\"'''.",
- "nosuchuser": "Num eisiste nanhun outelizador cul nome \"$1\".\nLs nomes de outelizador son defrentes an lhetra grande ó pequeinha.\nBei cumo screbiste, ó [[Special:UserLogin/signup|cria ua nuoba cuonta]].",
+ "nosuchuser": "Num eisiste nanhun outelizador cul nome \"$1\".\nLs nomes de outelizador son defrentes an lhetra grande ó pequeinha.\nBei cumo screbiste, ó [[Special:CreateAccount|cria ua nuoba cuonta]].",
"nosuchusershort": "Nun eisiste nanhun outelizador cul nome \"$1\".\nBei se l screbiste bien.",
"nouserspecified": "Tenes que dezir un nome de outelizador.",
"wrongpassword": "La palabra chabe ye ambálida.\nPor fabor, spurmenta outra beç.",
"move-page-legend": "Mover página",
"movepagetext": "Outelizando este formulário tu puodes renomear ua páigina, arrastrando to l stórico para l nuobo títalo. L títalo anterior será transformado nun ancaminamiento para l nuobo.\nYe possible amanhar de forma outomática ancaminamientos que lhigen un títalo oureginal.\nCauso scuolhas para que esso nun seia feito, bei se nun hai ancaminamientos [[Special:DoubleRedirects|dues bezes]] ó [[Special:BrokenRedirects|scachados]].\nYe de la tue respunsablidade tener la certeza de que las lhigaçones cuntinan a apuntar pa adonde dében.\n\nArrepara que la páigina '''nun''' será arrastrada se yá eisistir ua páigina cul nuobo títalo, a nun ser que steia bazio ó seia un ancaminamiento i nun tenga stórico de eidiçones. Esto quier dezir que puodes renomear outra beç ua páigina pa l nome que tenie antes de l anganho i que nun puodes subrescrebir ua páigina.\n\n<b>CUIDADO!</b>\nEsto puode ser ua altaraçon drástica i einesperada pa ua páigina popular; por fabor, ten la certeza de que antendes las cunsequéncias desto antes de cuntinar.",
"movepagetalktext": "La páigina de \"çcusson\" associada, se eistir, será outomaticamente arrastrada, '''a nun ser que:'''\n*Ua páigina de çcusson cun contenido yá eisista subre l nuobo títalo, ou\n*Tu marques la caixa ambaixo.\n\nNestes causos, tu terás que arrastrar ou ajuntar la páigina a la mano, se assi quejires.",
- "movearticle": "Arrastrar páigina",
"newtitle": "Pa nuobo títalo:",
"move-watch": "Begiar esta páigina",
"movepagebtn": "Arrastrar páigina",
"noname": "Зярс эзить максо кемекстазь теицянь лем.",
"loginsuccesstitle": "Совавить",
"loginsuccess": "'''Тон совить {{SITENAME}}-с кода \"$1\".'''",
- "nosuchuser": "$1 лем марто теиця арась.\nТеиця лемтне явозь тень корясь вишка эли покш тештинесэ сёрмадозь. Ваннык видестэ - а видестэ сёрмадык, эли [[Special:UserLogin/signup|тейть-шкак од совамо тарка]].",
+ "nosuchuser": "$1 лем марто теиця арась.\nТеиця лемтне явозь тень корясь вишка эли покш тештинесэ сёрмадозь. Ваннык видестэ - а видестэ сёрмадык, эли [[Special:CreateAccount|тейть-шкак од совамо тарка]].",
"nosuchusershort": "\"$1\" лемсэ теиця арась. Варштака, кизды, аволь истя сёрмадозь.",
"nouserspecified": "Теицянь лем эряви.",
"login-userblocked": "Те теицясь аравтозь саймас. Совамонзо а мерить.",
"noname": "Ahmo ōtiquihto cualli tlatequitiltilīlli tōcāitl.",
"loginsuccesstitle": "Cualli calaquiliztli",
"loginsuccess": "'''Ōticalac {{SITENAME}} quemeh \"$1\".'''",
- "nosuchuser": "Ayāc tlatequitiltilīlli motōcāitia \"$1\".\nIn tlatequitiltilīltōcāitl quimati in huēyimachiyōtlahtōliztli.\nXiquitta in yēquihcuilōlli, ahnozo [[Special:UserLogin/signup|xicchīhua yancuīc cuenta]].",
+ "nosuchuser": "Ayāc tlatequitiltilīlli motōcāitia \"$1\".\nIn tlatequitiltilīltōcāitl quimati in huēyimachiyōtlahtōliztli.\nXiquitta in yēquihcuilōlli, ahnozo [[Special:CreateAccount|xicchīhua yancuīc cuenta]].",
"nosuchusershort": "Ayāc tlatequitiltilīlli motōcāitia \"$1\". Xiquitta in tlein ōtitlahcuiloh melāhuacā cah.\nXiquitta moyēquihcuilōl.",
"nouserspecified": "Mohuīquilia tiquihtoa cualli tlatequitiltilīltōcāitl.",
"wrongpassword": "Ahcualli motlahtōlichtacāyo.\nTimitztlātlauhtia xicchīhua occeppa.",
"categories": "Tlaìxmatkàtlàlilòmë",
"categoriespagetext": "{{PLURAL:$1|Inìn tlaìxmatkàtlàlilòtl kimpia|Inîkë tlaìxmatkàtlàlilòmë kimpiâkë}} tlaìxtlapaltìn noso medios.\nÂmò monèxtiâkë nikàn in [[Special:UnusedCategories|tlaìxmatkàtlàlilòmë tlèn âmò mokìntekitìltia]].\nNò mà mỏta in tlèn [[Special:WantedCategories|ìpan kineki tlaìxmatkàtlàlilòtl]].",
"categoriesfrom": "Mà monèxtìkàn tlaìxmatkàtlàlilòmë tlèn pèwâkë ìka:",
- "special-categories-sort-count": "tlapōhualcopa",
- "special-categories-sort-abc": "tlahtōlcopa",
"linksearch": "Calān tzonhuiliztli tlatemoliztli",
"linksearch-ns": "Tōcātzin:",
"linksearch-ok": "Tictēmōz",
"noname": "Lí phah--ê iōng-chiá-miâ boē-sái.",
"loginsuccesstitle": "Teng-ji̍p sêng-kong",
"loginsuccess": "Lí hiān-chhú-sî í-keng teng-ji̍p {{SITENAME}} chò \"$1\".",
- "nosuchuser": "Chia bô iōng-chiá hō-chò \"$1\".\nIiōng-chiá hō-chò ū hun toā-jī sè-jī.\nChhiáⁿ kiám-cha lí ê phèng-im, a̍h-sī [[Special:UserLogin/signup|khui sin iōng-chiá ê kháu-chō.]]",
+ "nosuchuser": "Chia bô iōng-chiá hō-chò \"$1\".\nIiōng-chiá hō-chò ū hun toā-jī sè-jī.\nChhiáⁿ kiám-cha lí ê phèng-im, a̍h-sī [[Special:CreateAccount|khui sin iōng-chiá ê kháu-chō.]]",
"nosuchusershort": "Bô \"$1\" chit ê iōng-chiá miâ.\nTùi khoàⁿ-māi, lí phah--ê.",
"nouserspecified": "Lí ài chí-tēng chi̍t ê iōng-chiá miâ.",
"login-userblocked": "這個用者已經予人封鎖,袂使登入。",
"sp-contributions-submit": "Chhoē",
"whatlinkshere": "Tó-ūi liân kàu chia",
"whatlinkshere-title": "Liân khì \"$1\" ê ia̍h-bīn",
- "whatlinkshere-page": "頁:",
+ "whatlinkshere-page": "Ia̍h:",
"linkshere": "Í-hā '''[[:$1]]''' liân kàu chia:",
"nolinkshere": "Bô poàⁿ ia̍h liân kàu '''[[:$1]]'''.",
"isredirect": "choán-ia̍h",
"tooltip-ca-viewsource": "Chit ia̍h pó-hō͘ tiâu leh.\nLí ē-sái khoàⁿ i ê goân-sú-bé.",
"tooltip-ca-history": "Chit ia̍h ê chá-chêng pán-pún",
"tooltip-ca-delete": "Thâi chit ia̍h",
- "tooltip-ca-move": "徙這頁",
+ "tooltip-ca-move": "Sóa chit ia̍h",
"tooltip-ca-watch": "共這頁加入去你的監視單",
"tooltip-ca-unwatch": "Lí ê kàm-sī-toaⁿ soá tiàu chit ia̍h.",
"tooltip-search": "Chhoé {{SITENAME}}",
"tooltip-diff": "Hián-sī lí tùi bûn-pún só͘ chò ê kái-tōng",
"tooltip-watch": "共這頁加入去你的監視單",
"tooltip-rollback": "Ji̍h \"Hoê-choán\" ē-sái thè tńg-khì téng-chi̍t-ê kái ê lâng ê ia̍h.",
- "tooltip-preferences-save": "保存設定",
+ "tooltip-preferences-save": "Pó-chûn siat-tēng",
"tooltip-summary": "Siá chi̍t-ê kán-tan soat-bêng",
"anonymous": "{{SITENAME}} bô kì-miâ ê iōng-chiá",
"siteuser": "{{SITENAME}} iōng-chiá $1",
"password-change-forbidden": "Nun se ponno cagnà 'e password ncopp'a sta wiki.",
"externaldberror": "Ce sta n'errore ch' 'e server d'autenticazione esterno, o pure nun v'è permesso accedere all'aghiurnamento d' 'o cunto sterno vuosto.",
"login": "Tràse",
+ "login-security": "Cunferma l'identità",
"nav-login-createaccount": "Trasite o criate n'acciesso nuovo",
"userlogin": "Trasite o criate n'acciesso nuovo",
"userloginnocreate": "Tràse",
"userlogin-resetpassword-link": "Te sì scurdat' 'a password?",
"userlogin-helplink2": "Aiuto cu l'accieso",
"userlogin-loggedin": "Sì già {{GENDER:$1|connesso comme $1|connessa comme $1|connesso/a comme $1}}.\nUsa 'o modulo ccà abbascio pe trasì com'a n'atu utente.",
+ "userlogin-reauth": "Avit'a trasì n'ata vota pe' puté cuntrullà ca site overo {{GENDER:$1|$1}}.",
"userlogin-createanother": "Crèa n'at'account",
"createacct-emailrequired": "Indirizzo email",
"createacct-emailoptional": "Indirizzo 'e posta elettronica (ozzionale)",
"createacct-email-ph": "Scrivite 'o nderizzo mail vuosto",
"createacct-another-email-ph": "Scrivite nderizzo mail",
"createaccountmail": "Usa na password qualunque temporanea e manna sta password a l'indirizzo 'e posta e-mail specificato",
+ "createaccountmail-help": "Se putess'ausà pe' puté crià nu cunto pe' n'ata perzona senza mparà 'a password.",
"createacct-realname": "Nomme riale (ozzionale)",
"createaccountreason": "Mutivo:",
"createacct-reason": "Mutivo",
"createacct-reason-ph": "Pecché staje crianno n'at'utenza",
+ "createacct-reason-help": "Mmasciata mmustata dint'o riggistro 'e criazion' 'e cunte",
"createacct-submit": "Crèa 'o cunto utente vuosto",
"createacct-another-submit": "Crèa nu cunto",
+ "createacct-continue-submit": "Và avanti c' 'a criazion' 'e cunte",
+ "createacct-another-continue-submit": "Và avanti c' 'a criazion' 'e cunte",
"createacct-benefit-heading": "{{SITENAME}} è fatta 'e perzone comme te.",
"createacct-benefit-body1": "{{PLURAL:$1|càgnamiento|càgnamiente}}",
"createacct-benefit-body2": "{{PLURAL:$1|paggena|paggene}}",
"nocookiesnew": "'A riggistrazione è stata completata, ma nun se può accedere a {{SITENAME}} pecché 'e cookie songo disattivate. Prova n'ata vota c' 'o nomme e 'a password quanno 'e cookie sarrann'attivate dint'o navigatore stesso.",
"nocookieslogin": "{{SITENAME}} usa cookies pe' putè dà accies'a ll'utente.\n'E cookies vuoste songo stutate.\nPe' piacere appicciate 'e cookies dint'o navigatóre e pruvate n'ata vota.",
"nocookiesfornew": "'O cunto utente nu s'è criato, pecché nun s'è potuto confirmà d' 'a fonte suja.\nVide si 'e cookies song'appicciate, ricarreca 'a paggena e prova n'ata vota.",
+ "createacct-loginerror": "'O cunto fuje criato apposto, ma nun fosse stato possibile 'e ve fà trasì in modo automatico. Trasite cu l'[[Special:UserLogin|accesso manuale]].",
"noname": "Nun avite specificato nu nomme valido d'utente.",
"loginsuccesstitle": "Acciesso affettuato",
"loginsuccess": "'''Si stato cunnesso ô server 'e {{SITENAME}} cu 'o nomme utente 'e \"$1\".'''",
- "nosuchuser": "Nun è riggistrato nisciuno utente c' 'o nomme \"$1\".\n'E nomme utente songo sensibbele a 'e maiuscole.\nCuntrolla 'o nomme nzertàto, o [[Special:UserLogin/signup|crìa n'utenza nova]].",
+ "nosuchuser": "Nun è riggistrato nisciuno utente c' 'o nomme \"$1\".\n'E nomme utente songo sensibbele a 'e maiuscole.\nCuntrolla 'o nomme nzertàto, o [[Special:CreateAccount|crìa n'utenza nova]].",
"nosuchusershort": "Nun ce stanno utente cu o nòmme \"$1\". Cuntrolla si scrivìste buòno.",
"nouserspecified": "Tiene 'a dìcere nu nomme pricìso.",
"login-userblocked": "Chist'utente è bloccato. Nun se può effettuà 'o login.",
"createacct-another-realname-tip": "'O nomme overo vuosto è ozzionale.\nSi sciglite 'e nzertà 'o nomme overo, chesto s'ausarrà pe' dà l'utente l'attribuzione d' 'a fatica fatta.",
"pt-login": "Tràse",
"pt-login-button": "Tràse",
+ "pt-login-continue-button": "Và annanze e tràse",
"pt-createaccount": "Crèa nu cunto nuovo",
"pt-userlogout": "Jèsce",
"php-mail-error-unknown": "Errore scanusciuto dint'a funzione PHP mail()",
"botpasswords-invalid-name": "'O nomme utente nnecato nun cuntenesse nu spartetóre 'e bot password (\"$1\").",
"botpasswords-not-exist": "L'utente \"$1\" nun téne na password bot chiammata \"$2\".",
"resetpass_forbidden": "'E password nun se ponno cagnà",
+ "resetpass_forbidden-reason": "'E password nun se ponno cagnà: $1",
"resetpass-no-info": "Avite 'a trasì ('o login) pe ffà l'acciesso a sta paggena direttamente.",
"resetpass-submit-loggedin": "Cagna password",
"resetpass-submit-cancel": "Canciella",
"passwordreset-emailsentusername": "Si esistesse nu cunto e-mail suòccio a stu nomme utente, allora se mannarrà na mmasciata pe' riabbià 'a password.",
"passwordreset-emailsent-capture": "Na mmasciata e-mail pe' riabbià 'a password è stata mannata, chista mmasciata 'a putite vedé ccà abbascio.",
"passwordreset-emailerror-capture": "Na mmasciata e-mail pe' riabbià 'a password è stata mannata, 'a putite vedé ccà abbascio, ma aita sapé ca nun s'è mannata a {{GENDER:$2|l'utente}} pecché c'è stato cocch'errore: $1",
+ "passwordreset-emailsent-capture2": "L'email 'e reimpostazione d' 'a password {{PLURAL:$1|è stata mannata|so' state mannate}}. {{PLURAL:$1|'O nomme|L'elenco 'e nomme}} utente e password è mmustato ccà.",
+ "passwordreset-emailerror-capture2": "'O mannà 'email {{GENDER:$2|a ll'utente}} guastaje: $1. {{PLURAL:$3|'O nomme|L'elenco 'e nomme}} utente e password se ffà vedé ccà.",
+ "passwordreset-nocaller": "Nu chiammate s'avess'a dà",
+ "passwordreset-nosuchcaller": "'O chiammante nun esiste: $1",
+ "passwordreset-ignored": "'A reimpustazione d' 'a password nun s'è gistita. Fosse ca nisciunu fornitore è stato mpustato?",
+ "passwordreset-invalideamil": "Indirizzo 'e posta email nun valido",
+ "passwordreset-nodata": "Nun è stato fornito né nomme utente né indirizzo 'e posta email",
"changeemail": "Cagna o lèva l'indirizzo e-mail",
"changeemail-header": "Ghienchete stu modulo pe' puté cagnà 'o indirizzo e-mail d' 'o vuosto. Si vuje vulite luvà e 'o scucchià l'associazione 'e cocche cunto mail d' 'o cunto vuosto, lassate 'o cunto e-mail nuovo abbacante quanno mannarrate stu modulo.",
"changeemail-passwordrequired": "Avit'a miette 'a password vuosto pe' dà a cunferma 'e stu cagnamiento.",
"accmailtext": "'Na password gennerata casualmente ppe [[User talk:$1|$1]] è stata mannata a $2. Chista password può essere càgnata dint'â paggena ppe ''[[Special:ChangePassword|càgna 'a password]]'' subbeto doppo l'acciesso.",
"newarticle": "(Nuovo)",
"newarticletext": "Site ghiuto/a addò nu link 'e na paggena ca nun esiste ancora.\nP' 'a crià sta paggena, accummenciate a scrivere dint'a cascia cà abbascio (vedite 'a [$1 paggena d'aiuto] pe liegge cchiù nfurmazziune).\nSi site venuto/a ccà pe' sbaglio, vedite 'e sprémmere 'o buttòne '''Arreto''' d' 'o navigatóre.",
- "anontalkpagetext": "----\n''Chest'è 'a paggena 'e discussione 'e n'utente anonimo, ca nun ave criàt' 'ancora n'utenza o ca nun sta ausanno. Pe' l'identificà avite 'e truvà 'o nummero d' 'o ndirizzo IP d' 'o sujo. L'indirizze IP se ponno spartì però sempe ausanno cunte differente. Si site n'utente anonimo e penzate ca 'e cummente ccà dint'a sta paggena nun parlano 'e vuje, allora [[Special:UserLogin/signup|criate n'utenza nnova]] o [[Special:UserLogin|trasite cu chella ca tenite già]] pe' nun sta' mmescato mmiez'a l'ati utente anonime n futuro.''",
+ "anontalkpagetext": "----\n''Chest'è 'a paggena 'e discussione 'e n'utente anonimo, ca nun ave criàt' 'ancora n'utenza o ca nun sta ausanno. Pe' l'identificà avite 'e truvà 'o nummero d' 'o ndirizzo IP d' 'o sujo. L'indirizze IP se ponno spartì però sempe ausanno cunte differente. Si site n'utente anonimo e penzate ca 'e cummente ccà dint'a sta paggena nun parlano 'e vuje, allora [[Special:CreateAccount|criate n'utenza nnova]] o [[Special:UserLogin|trasite cu chella ca tenite già]] pe' nun sta' mmescato mmiez'a l'ati utente anonime n futuro.''",
"noarticletext": "Mo' mo' 'a paggena richiesta è abbacante. Se pò [[Special:Search/{{PAGENAME}}|ascià stu titolo]] dint'a l'ati paggene d' 'o sito, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ascià dint'e riggistre azzeccate] o pure [{{fullurl:{{FULLPAGENAME}}|action=edit}} crià 'a paggena mo']</span>.",
"noarticletext-nopermission": "Mo' mo' 'a paggena richiesta è abbacante. Se pò [[Special:Search/{{PAGENAME}}|ascià stu titolo]] dint'a l'ati paggene d' 'o sito, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ascià dint'e riggistre azzeccate]</span>, però nun tenite 'o permesso 'a crià sta paggena.",
"missing-revision": "'A verziona #$1 d' 'a paggena \"{{FULLPAGENAME}}\" nun esiste.\n\nChest'è causato quanno se và dint'a nu link a na paggena ch'è stata scancellata.\n'E dettaglie se ponno truvà dint'a [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 'o riggistro 'e scancellamiente].",
"right-override-export-depth": "Esporta 'e paggene azzeccanno 'e paggene cullegate nfin'a na profondità 'e 5",
"right-sendemail": "Manna na mail a ll'at'utente",
"right-passwordreset": "Vide 'e mmasciate 'e rimpustazione d' 'a password",
- "right-managechangetags": "Crìa e scancella 'e [[Special:Tags|tag]] d' 'o database",
+ "right-managechangetags": "Crìa e appiccia/stuta 'e [[Special:Tags|tag]]",
"right-applychangetags": "Appreca [[Special:Tags|tag]] pe' tramente ca se fanno 'e cagnamiente 'e coccheruno",
"right-changetags": "Azzecca o lèva a caso 'e [[Special:Tags|tag]] dint'a verziune nnividuale e riggistre 'e log",
+ "right-deletechangetags": "Scancella l'[[Special:Tags|etichette]] d' 'o database",
"grant-generic": "Pacco 'e deritte \"$1\"",
"grant-group-page-interaction": "Interagisce ch' 'e paggene",
"grant-group-file-interaction": "Intergische ch' 'e file 'e media",
"action-viewmyprivateinfo": "vide 'e date perzunale",
"action-editmyprivateinfo": "cagnà 'e proprie date perzunale",
"action-editcontentmodel": "càgna 'o mudelo 'e cuntenute 'e na paggena",
- "action-managechangetags": "crìa e scancella 'e tag d' 'o database",
+ "action-managechangetags": "crìa e appiccia/stuta tag",
"action-applychangetags": "appreca tag pe' tramente ca se fanno 'e cagnamiente vuoste",
"action-changetags": "azzecca o lèva tag a caso dint'a verziune nnividuale e riggistre 'e log",
+ "action-deletechangetags": "scancellare 'e tag d' 'o database",
"nchanges": "$1 {{PLURAL:$1|cagnamiento|cagnamiente}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|'a ll'urdema visita}}",
"enhancedrc-history": "cronologgia",
"upload-form-label-own-work": "Chest'è fatica mia",
"upload-form-label-infoform-categories": "Categurìe",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-own-work-message-local": "Io cunfermo ca songh'io ca carrecanno stu file sto secutanno 'e tiermene 'e servizio e pulitiche 'e licienza dint'a {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Si nun site capace 'e carrecà stu file pe' bbìa d' 'e pulitiche 'e {{SITENAME}}, pe' piacere nchiurete sta casciulella e tentate n'ata maniera.",
- "upload-form-label-not-own-work-local-local": "Forse vulite pure tentà [[Special:Upload|'a paggena 'e carreche predefinita]].",
- "upload-form-label-own-work-message-default": "Capisco ca sto a carrecà stu file a nu repositorio spartuto. Cunfermo ca facenno chesto sto secutanno 'e tèrmene 'e servizio e licienze llanno.",
- "upload-form-label-not-own-work-message-default": "Si nun site capace 'e carrecà stu file pe' bbìa d' 'e pulitiche d' 'o repusitorio spartuto, pe' piacere nchiurete sta casciulella e tentate n'ata maniera.",
- "upload-form-label-not-own-work-local-default": "Putite pure tentà 'ausà [[Special:Upload|'a paggena 'e carreche 'e {{SITENAME}}]], si stu file nun se putesse carrecà llanno pe' bbìa d' 'e pulitiche.",
- "upload-form-label-own-work-message-shared": "Faccio attestato ca songo 'o detentore d' 'o copyright 'e stu file, e so' d'accordo 'e lassà irrevocabbelmente stu file a Wikimedia Commons sott'a licienza [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribuziona-SparteEguale 4.0], e so' d'accordo cu sti [https://wikimediafoundation.org/wiki/Terms_of_Use Termene d'Uso].",
- "upload-form-label-not-own-work-message-shared": "Si nun tenite 'o copyright 'e stu file, o pure 'o vulite lassà libbero cu n'ata licienza, cunziderate 'ausà 'o [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons Upload Wizard].",
- "upload-form-label-not-own-work-local-shared": "Putite pure tentà 'e ausà [[Special:Upload|'a paggena 'e carreche 'e {{SITENAME}}]], si stu sito ve premmettesse 'e carrecà llanno pe' bbìa d' 'e pulitiche.",
+ "upload-form-label-own-work-message-generic-local": "Io cunfermo ca songh'io ca carrecanno stu file sto secutanno 'e tiermene 'e servizio e pulitiche 'e licienza dint'a {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Si nun site capace 'e carrecà stu file pe' bbìa d' 'e pulitiche 'e {{SITENAME}}, pe' piacere nchiurete sta casciulella e tentate n'ata maniera.",
+ "upload-form-label-not-own-work-local-generic-local": "Forse vulite pure tentà [[Special:Upload|'a paggena 'e carreche predefinita]].",
+ "upload-form-label-own-work-message-generic-foreign": "Capisco ca sto a carrecà stu file a nu repositorio spartuto. Cunfermo ca facenno chesto sto secutanno 'e tèrmene 'e servizio e licienze llanno.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Si nun site capace 'e carrecà stu file pe' bbìa d' 'e pulitiche d' 'o repusitorio spartuto, pe' piacere nchiurete sta casciulella e tentate n'ata maniera.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Putite pure tentà 'ausà [[Special:Upload|'a paggena 'e carreche 'e {{SITENAME}}]], si stu file nun se putesse carrecà llanno pe' bbìa d' 'e pulitiche.",
"backend-fail-stream": "Nun se può mannà 'o file \"$1\".",
"backend-fail-backup": "Nun se può ffà 'o backup d' 'o file \"$1\".",
"backend-fail-notexists": "'O file $1 nun esiste.",
"trackingcategories-msg": "Categurìe 'e cuntrollo",
"trackingcategories-name": "Nomme d' 'a mmasciata",
"trackingcategories-desc": "Criterie p' 'o miettere dint' 'a categurìa",
+ "restricted-displaytitle-ignored": "Paggene cu titule 'a ffà vedé ignurate",
+ "restricted-displaytitle-ignored-desc": "'A paggena tene nu <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> gnurato peccéh nu fosse eguale a 'o titolo d' 'a paggena 'e mo'.",
"noindex-category-desc": "'A paggena nun è indicizzata 'a 'e robot pecché cuntene 'a parola maggica <code><nowiki>__NOINDEX__</nowiki></code> e se trova dint'a nu namespace addò chistu flag è permesso.",
"index-category-desc": "'A paggena téne 'o codece <code><nowiki>__INDEX__</nowiki></code> dinto (e se trova dint'a nu namespace addò chistu flag è permesso), e picciò è indicizzata 'a 'e robot, pure si normalmente nun fosse accussì.",
"post-expand-template-inclusion-category-desc": "'A dimensione d' 'a paggena è cchiù granne 'e <code>$wgMaxArticleSize</code> aropp'a spannere tutt' 'e template, e picciò cocche template nun se so' spannute.",
"rollbacklinkcount": "annulla {{PLURAL:$1|nu cagnamiento|$1 cagnamiente}}",
"rollbacklinkcount-morethan": "annulla cchiù 'e {{PLURAL:$1|nu cagnamiento|$1 cagnamiente}}",
"rollbackfailed": "Annullamento fallito",
+ "rollback-missingparam": "Parammetre obbligate mancante int' 'a richiesta.",
"cantrollback": "Nun se può annullà stu cagnamiento;\nsapite ca l'urdemo autore è stato pure sul'isso a faticà dint'a sta paggena (nun ce sta n'at'autore).",
"alreadyrolled": "Nun se può turna arreto a l'urdemo cagnamiento [[:$1]] 'a [[User:$2|$2]] ([[User talk:$2|Chiacchiera]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\ncocch'ato ha cagnato o annullato 'a paggena già.\n\nL'urdemo cangamiento d' 'a paggena fuje 'a [[User:$3|$3]] ([[User talk:$3|Chiacchiera]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "'O riepilego d' 'o cagnamiento era: <em>$1</em>.",
"revertpage": "Cangiaje 'e cagnamiénte 'e [[Special:Contributions/$2|$2]] ([[User talk:$2|discussione]]), cu â verzione 'e pprimma 'e [[User:$1|$1]]",
"revertpage-nouser": "Annullate 'e cagnamiente 'e n'utente annascunnuto, è stata ripigliata ll'urdema verzione 'e {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Cagnamiente annullate 'a $1;\ns'è turnat arreto a l'urdema verzione 'e $2.",
+ "rollback-success-notify": "Cagnamiente annullate 'a $1;\ns'è turnat arreto a l'urdema verzione 'e $2. [$3 Fà vedé 'e cagnamiente]",
"sessionfailure-title": "Sessione fallita",
"sessionfailure": "Pare ca stanno probbleme cu 'a sessiona toja;\nst'azione è stata fermata pe' precauzione annanz' 'e cavall' 'e troia;\nPe' piacere turnate arreto, carrecate n'ata vota 'a paggena pe pruvate n'ata vota.",
"changecontentmodel": "Cagna 'o mudello 'e cuntenute 'e na paggena",
"changecontentmodel-success-text": "'O tipo 'e cuntenut 'e [[:$1]] è stato cagnato.",
"changecontentmodel-cannot-convert": "'E cuntenute dint'a [[:$1]] nun se ponno scagnà a nu tipo 'e $2.",
"changecontentmodel-nodirectediting": "'O mudello 'e cuntenute $1 nun suppurtasse 'o cagnamiento diretto",
+ "changecontentmodel-emptymodels-title": "Nisciuno modello 'e cuntenute a disposizione",
+ "changecontentmodel-emptymodels-text": "'E cuntenute dint'a [[:$1]] nun se ponno scagnà a nisciuno tipo.",
"log-name-contentmodel": "Riggistro 'e cagnamiente d' 'o mudello 'e cuntenute",
"log-description-contentmodel": "Evvente azzeccate c' 'o mudello 'e cuntenute 'e na paggena",
"logentry-contentmodel-new": "$1 {{GENDER:$2|criaje}} 'a paggena $3 ausanno nu mudell' 'e cuntenute nun-predefinito \"$5\"",
"whatlinkshere-prev": "{{PLURAL:$1|apprima|apprime $1}}",
"whatlinkshere-next": "{{PLURAL:$1|appriesso|$1 appriesso}}",
"whatlinkshere-links": "← jonte",
- "whatlinkshere-hideredirs": "$1 redirects",
+ "whatlinkshere-hideredirs": "$1 redirect",
"whatlinkshere-hidetrans": "$1 'nclusione",
"whatlinkshere-hidelinks": "$1 jonte",
"whatlinkshere-hideimages": "$1 links d' 'o file",
"lockdbsuccesstext": "'O database è stato bloccato.<br />\nArricuordateve 'e [[Special:UnlockDB|luvà 'o blocco]] appriesso c' 'a manutenziona sarrà fernuta.",
"unlockdbsuccesstext": "'O database è stato sbluccato.",
"lockfilenotwritable": "Nun se può scrivere ncopp' 'o file 'e blocco d' 'o database.\nPe' bluccà o sbluccà 'o database abbesuogne 'e scrivere dint' 'o server web.",
+ "databaselocked": "'O database è bluccato già.",
"databasenotlocked": "'O database nun è bluccato.",
"lockedbyandtime": "(pe' {{GENDER:$1|$1}} 'o $2 a 'e $3)",
"move-page": "Mòve $1",
"confirm-watch-top": "Vulite azzeccà sta paggena int' 'a lista 'e paggene cuntrullate vuosta?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Vulite luvà sta paggena d' 'a lista 'e paggene cuntrullate vuosta?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Turnà arreto 'e cagnamiente 'e sta paggena?",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← paggena 'e primma",
"imgmultipagenext": "paggena successiva →",
"timezone-local": "Lucale",
"duplicate-defaultsort": "<strong>Attenziò:</strong> A chiave d'arricetto \"$2\" se miette ncuollo a nu valore 'e primma \"$1\".",
"duplicate-displaytitle": "<strong>Attenziò:</strong> A chiave d'arricetto \"$2\" se scagna p' 'o valore 'e primma \"$1\".",
+ "restricted-displaytitle": "<strong>Attenziò:</strong> 'O titolo ccà \"$1\" è stato lassato perdere pecché nun fosse eguale a 'o titolo 'e mò d' 'a paggena.",
"invalid-indicator-name": "<strong>Errore:</strong> attribbuto <code>name</code> 'e ll'innecature d' 'o stato d' 'a paggena nu può rummanè abbacante.",
"version": "Verziona",
"version-extensions": "Estenziune installate",
"tags-delete-not-found": "'O tag $1 nun esiste.",
"tags-delete-too-many-uses": "'O tag \"$1\" è apprecato a cchiù 'e $2 {{PLURAL:$2|verziona|verziune}}, cosa ca vulesse dicere ca nun se ò scancellà.",
"tags-delete-warnings-after-delete": "'O tag \"$1\" s'è scancellato, ma {{PLURAL:$2|s'è ncuntrato ll'avviso|se songhe ncuntrate ll'avise}} ccà:",
+ "tags-delete-no-permission": "Nun tenite 'o permesso pe' scancellà 'e tag 'e cagnamiente.",
"tags-activate-title": "Appiccia 'o tag",
"tags-activate-question": "Vuje state p'appiccià 'o tag \"$1\".",
"tags-activate-reason": "Mutivo:",
"feedback-useragent": "Aggente utente:",
"searchsuggest-search": "Truova",
"searchsuggest-containing": "tène...",
+ "api-error-autoblocked": "Ll'indirizzo IP d' 'o vuosto è stato bloccato automaticamente, pecché a nu mumento l'ausaje n'utenza bloccata.",
"api-error-badaccess-groups": "Tun putite carrecà file ncopp' 'a sta wiki.",
"api-error-badtoken": "Errore interno: 'O token nun è buono.",
+ "api-error-blocked": "Site stato/a bloccato/a, nun putite ffà cagnamiente.",
"api-error-copyuploaddisabled": "'A funzione carrcà 'e n'URL nun è appicciata dint'a stu server.",
"api-error-duplicate": "Nce {{PLURAL:$1|sta è n'atu file|stanno ati file}} ncopp' 'o sito ch' 'e cuntenute eguale eguale.",
"api-error-duplicate-archive": "Nce {{PLURAL:$1|steva n'atu file|stevano ati file}} già ncopp' 'o sito ch' 'e stisse cuntenute, però {{PLURAL:$1|è stato|so' state}} scancellate.",
"api-error-nomodule": "Errore interno: Nisciuno modulo 'e carreca mpustato.",
"api-error-ok-but-empty": "Errore interno: Nisciuna resposta 'a 'o server.",
"api-error-overwrite": "Sovrascrivere nu file ch'esiste già nun è permesso.",
+ "api-error-ratelimited": "Vuje avite tntato 'e carrecà cchiù file dint'a nu mumento curt' 'e tiempo ca sta wiki premmettesse.\nPe' piacere, tentate n'ata vota int'a nu poch' 'e minute.",
"api-error-stashfailed": "Errore interno: 'O server nun ngarraje a s'astipà 'o file temporaneo.",
"api-error-publishfailed": "Errore interno: 'O server nun ngarraje a pubbrecà 'o file temporaneo.",
"api-error-stasherror": "'A carreca d' 'o file 'n stash è asciuta male, ce sta n'errore.",
"log-action-filter-suppress-block": "Scancellazione 'utente 'a blocco",
"log-action-filter-suppress-reblock": "Scancellazione utente 'a re-blocco",
"log-action-filter-upload-upload": "Carreca nova",
- "log-action-filter-upload-overwrite": "Recarreca"
+ "log-action-filter-upload-overwrite": "Recarreca",
+ "authmanager-authn-not-in-progress": "L'autenticazione nun è 'ncurzo o 'e date d' 'a sessione so' ghiute pierze. Verite 'accummincià n'ata vota a 'o prencipio.",
+ "authmanager-authn-no-primary": "'E credenziale ca s'hanno rato nun se ponno autenticà.",
+ "authmanager-authn-no-local-user": "'E credenziale ca s'hanno rato nun se ponno ffà suoccie a nisciun' 'utente int'a stu wiki."
}
"noname": "Du har ikke oppgitt et gyldig brukernavn.",
"loginsuccesstitle": "Du er nå logget inn",
"loginsuccess": "Du er nå logget inn på {{SITENAME}} som «$1».",
- "nosuchuser": "Det eksisterer ingen bruker ved navn «$1».\nMerk at det skilles mellom store og små bokstaver.\nSjekk stavemåten eller [[Special:UserLogin/signup|opprett en ny konto]].",
+ "nosuchuser": "Det eksisterer ingen bruker ved navn «$1».\nMerk at det skilles mellom store og små bokstaver.\nSjekk stavemåten eller [[Special:CreateAccount|opprett en ny konto]].",
"nosuchusershort": "Det finnes ingen bruker ved navn «$1». Kontroller stavemåten.",
"nouserspecified": "Du må oppgi et brukernavn.",
"login-userblocked": "Brukeren er blokkert. Innlogging er ikke tillatt.",
"accmailtext": "Et tilfeldig passord for [[User talk:$1|$1]] har blitt sendt til $2. Det kan endres på [[Special:ChangePassword|passordendringssiden]] under innlogging.",
"newarticle": "(Ny)",
"newarticletext": "Du har fulgt en lenke til en side som ikke finnes ennå.\nFor å opprette siden, begynn å skrive i boksen under (se [$1 hjelpesiden] for mer informasjon).\nOm du havnet her ved en feil, trykk '''tilbake''' i nettleseren.",
- "anontalkpagetext": "----\n''Dette er en diskusjonsside for en uregistrert bruker som ikke har opprettet konto eller ikke er logget inn.\nVi er derfor nødt til å bruke den numeriske IP-adressen til å identifisere ham eller henne.\nEn IP-adresse kan være delt mellom flere brukere.\nHvis du er en uregistrert bruker og synes at du har fått irrelevante kommentarer på en slik side, [[Special:UserLogin/signup|opprett en konto]] eller [[Special:UserLogin|logg inn]] så vi unngår fremtidige forvekslinger med andre uregistrerte brukere.''",
+ "anontalkpagetext": "----\n''Dette er en diskusjonsside for en uregistrert bruker som ikke har opprettet konto eller ikke er logget inn.\nVi er derfor nødt til å bruke den numeriske IP-adressen til å identifisere ham eller henne.\nEn IP-adresse kan være delt mellom flere brukere.\nHvis du er en uregistrert bruker og synes at du har fått irrelevante kommentarer på en slik side, [[Special:CreateAccount|opprett en konto]] eller [[Special:UserLogin|logg inn]] så vi unngår fremtidige forvekslinger med andre uregistrerte brukere.''",
"noarticletext": "Det er for tiden ingen tekst på denne siden.\nDu kan [[Special:Search/{{PAGENAME}}|søke etter denne sidetittelen]] på andre sider,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søke i relaterte logger],\neller [{{fullurl:{{FULLPAGENAME}}|action=edit}} opprette siden]</span>.",
"noarticletext-nopermission": "Det er for tiden ingen tekst på denne siden.\nDu kan [[Special:Search/{{PAGENAME}}|søke etter sidens tittel]] blant andre sider, eller <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søke i relevante logger]</span>, men du har ikke tillatelse til å opprette denne siden.",
"missing-revision": "Revisjonen #$1 av siden med navnet \"{{FULLPAGENAME}}\" eksisterer ikke.\n\nDette skyldes som regel at en gammel historikklenke er fulgt til en side som er slettet.\nDetaljer kan finnes i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} sletteloggen].",
"upload-form-label-own-work": "Dette er mitt eget verk",
"upload-form-label-infoform-categories": "Kategorier",
"upload-form-label-infoform-date": "Dato",
- "upload-form-label-own-work-message-local": "Jeg bekrefter at jeg ved å laste opp denne filen følger bruksvilkårene og lisensieringspolitikken på {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Hvis filen ikke lar seg laste opp under {{SITENAME}}s politikk må du lukke denne dialogboksen og prøve en annen metode.",
- "upload-form-label-not-own-work-local-local": "Du kan eventuelt forsøke [[Special:Upload|den ordinære opplastingssiden]].",
- "upload-form-label-own-work-message-default": "Jeg forstår at jeg laster opp denne filen til et delt arkiv. Jeg bekrefter at dette gjøres i tråd med bruksvilkårene og lisensieringspolitikken der.",
- "upload-form-label-not-own-work-message-default": "Hvis filen ikke lar seg laste opp under arkivets politikk må du lukke denne dialogboksen og prøve en annen metode.",
- "upload-form-label-not-own-work-local-default": "Du kan eventuelt forsøke [[Special:Upload|den ordinære opplastingssiden]] på {{SITENAME}} hvis filen kan lastes opp under politikken som gjelder der.",
- "upload-form-label-own-work-message-shared": "Jeg bekrefter at jeg har opphavsretten til denne filen, samtykker til å ugjenkallelig slippe filen til Wikimedia Commons under lisensen [https://creativecommons.org/licenses/by-sa/4.0/deed.no Creative Commons Navngivelse-DelPåSammeVilkår 4.0], og samtykker til [https://wikimediafoundation.org/wiki/Terms_of_Use bruksvilkårene].",
- "upload-form-label-not-own-work-message-shared": "Hvis du ikke sitter på opphavsretten til filen, eller ønsker å slippe den under en annen lisens, prøv [https://commons.wikimedia.org/wiki/Special:UploadWizard Opplastingsveiviseren på Commons].",
- "upload-form-label-not-own-work-local-shared": "Du kan eventuelt forsøke [[Special:Upload|den ordinære opplastingssiden på {{SITENAME}}]] hvis filen kan lastes opp under politikken som gjelder der.",
+ "upload-form-label-own-work-message-generic-local": "Jeg bekrefter at jeg ved å laste opp denne filen følger bruksvilkårene og lisensieringspolitikken på {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Hvis filen ikke lar seg laste opp under {{SITENAME}}s politikk må du lukke denne dialogboksen og prøve en annen metode.",
+ "upload-form-label-not-own-work-local-generic-local": "Du kan eventuelt forsøke [[Special:Upload|den ordinære opplastingssiden]].",
+ "upload-form-label-own-work-message-generic-foreign": "Jeg forstår at jeg laster opp denne filen til et delt arkiv. Jeg bekrefter at dette gjøres i tråd med bruksvilkårene og lisensieringspolitikken der.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Hvis filen ikke lar seg laste opp under arkivets politikk må du lukke denne dialogboksen og prøve en annen metode.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Du kan eventuelt forsøke [[Special:Upload|den ordinære opplastingssiden]] på {{SITENAME}} hvis filen kan lastes opp under politikken som gjelder der.",
"backend-fail-stream": "Kunne ikke strømme filen $1.",
"backend-fail-backup": "Kunne ikke sikkerhetskopiere filen $1.",
"backend-fail-notexists": "Filen $1 finnes ikke.",
"errorpagetitle": "Foutmelding",
"returnto": "Weerumme naor $1.",
"tagline": "Van {{SITENAME}}",
- "help": "Hulpe en kontakt",
+ "help": "Hulpe",
"search": "Zeuken",
"searchbutton": "Zeuken",
"go": "Artikel",
"disclaimers": "Veurbehold",
"disclaimerpage": "Project:Veurbehoud",
"edithelp": "Hulpe mit bewarken",
+ "helppage-top-gethelp": "Hulpe",
"mainpage": "Veurblad",
"mainpage-description": "Veurblad",
"policy-url": "Project:Beleid",
"badtitletext": "De naam van de op-evreugen zied is niet geldig, leeg, of n interwiki-verwiezing naor n onbekende of ongeldige wiki.",
"perfcached": "Disse gegevens koemen uut t tussengeheugen en bin misschien niet aktueel. Der {{PLURAL:$1|is hooguut een resultaot|bin hooguut $1 resultaoten}} beschikbaor in t tussengeheugen.",
"perfcachedts": "Disse gegevens koemen uut t tussengeheugen die veur t lest bie-ewörken is op $2 um $3. Der {{PLURAL:$4|is hooguut een resultaot|bin hooguut $4 resultaoten}} beschikbaor in t tussengeheugen.",
- "querypage-no-updates": "'''Disse zied wörden niet meer bie-ewörken.'''",
+ "querypage-no-updates": "'''Disse zied wördt niet meer bie-ewörken.'''",
"viewsource": "Brontekste bekieken",
"viewsource-title": "Bron bekieken van $1",
"actionthrottled": "Haandeling tegenehöllen",
"viewsourcetext": "Je kunnen de brontekste van disse zied bewarken en bekieken.",
"viewyourtext": "Je kunnen <strong>joew bewarkingen</strong> an de brontekste van disse zied bekieken en kopiëren.",
"protectedinterface": "Op disse zied steet tekste die gebruukt wördt veur systeemteksten van disse wiki. Allinnig beheerders kunnen disse zied bewarken.\nUm vertalingen veur alle wiki's derbie te zetten of te wiezigen, gebruuk [//translatewiki.net/ translatewiki.net], t vertaalprojekt veur MediaWiki.",
- "editinginterface": "<strong>Waorschuwing:</strong> je bewarken n zied die gebruukt wörden deur de programmatuur. Wa'j hier wiezigen, is van invleud op de hele wiki. Um vertalingen derbie te zetten of te wiezigen veur alle wiki's, gebruuk [//translatewiki.net/wiki/Main_Page?setlang=nds-nl translatewiki.net], t vertalingsprojekt veur MediaWiki.",
+ "editinginterface": "<strong>Waorschuwing:</strong> je bewarken n zied die gebruukt wördt deur de programmatuur. \nWa'j disse zied wiezigen is van invleud op t gebrukersuterlik veur aander gebrukers van disse wiki.",
+ "translateinterface": "Um vertalingen veur alle wiki's te doon of te wiezigen ku'j gebruukmaken van [//translatewiki.net/ translatewiki.net], t vertaalprojekt veur MediaWiki.",
"cascadeprotected": "Disse zied is beveiligd umdat t veurkömp in de volgende {{PLURAL:$1|zied|ziejen}}, die beveiligd {{PLURAL:$1|is|bin}} mit de \"kaskade\"-opsie:\n$2",
"namespaceprotected": "Je maggen gien ziejen in de '''$1'''-naamruumte bewarken.",
"customcssprotected": "Je kunnen disse CSS-zied niet bewarken, umdat der persoonlike instellingen van n aandere gebruker in staon.",
"noname": "Je mutten n gebrukersnaam opgeven.",
"loginsuccesstitle": "An-emeld",
"loginsuccess": "Je bin noen an-emeld bie {{SITENAME}} as \"$1\".",
- "nosuchuser": "Der is gien gebruker mit de naam \"$1\".\nGebrukersnamen bin heufdlettergeveulig.\nKiek de schriefwieze effen nao of [[Special:UserLogin/signup|maak n nieje gebruker an]].",
+ "nosuchuser": "Der is gien gebruker mit de naam \"$1\".\nGebrukersnamen bin heufdlettergeveulig.\nKiek de schriefwieze effen nao of [[Special:CreateAccount|maak n nieje gebruker an]].",
"nosuchusershort": "Der is gien gebruker mit de naam \"$1\". Kiek de spelling nao.",
"nouserspecified": "Vul n naam in",
"login-userblocked": "Disse gebruker is eblokkeerd.\nJe kunnen niet anmelden.",
"preview": "Naokieken",
"showpreview": "Bewarking naokieken",
"showdiff": "Verschil bekieken",
+ "blankarticle": "<strong>Waorschuwing:</strong> de zied die'j anmaken willen is leeg.\nA'j noen weer op \"{{int:savearticle}}\" klikken, dan wördt de zied an-emaakt zonder enige inhoud.",
"anoneditwarning": "<strong>Waorschuwing:</strong> je bin niet an-emeld.\nJoew IP-adres zal op-esleugen wörden a'j wiezigingen op disse zied anbrengen. A'j je eigen <strong>[$1 anmelden]</strong> of <strong>[$2 inschrieven]</strong> dan koemen joew bewarkingen onder joew gebrukersnaam te staon, samen mit aandere veurdelen.",
"anonpreviewwarning": "''Je bin niet an-emeld.''\n''Deur de bewarking op te slaon wörden joew IP-adres op-esleugen in de ziedgeschiedenisse.''",
"missingsummary": "'''Herinnering:''' je hebben gien samenvatting op-egeven veur de bewarking. A'j noen weer op ''Opslaon'' klikken wörden de bewarking zonder samenvatting op-esleugen.",
"accmailtext": "Der is n willekeurig wachtwoord veur [[User talk:$1|$1]] verstuurd naor $2. t Kan ewiezigd wörden op de zied ''[[Special:ChangePassword|wachtwoord wiezigen]]'' naoda'j an-emeld bin.",
"newarticle": "(Niej)",
"newarticletext": "Disse zied besteet nog niet.\nIn t veld hieronder ku'j wat schrieven um disse zied an te maken (meer informasie vie'j op de [$1 hulpzied]).\nA'j hier per ongelok terechtekeumen bin gebruuk dan de knoppe '''veurige''' um weerumme te gaon.",
- "anontalkpagetext": "---- ''Disse overlegzied heurt bie n anonieme gebruker die nog gien gebrukersnaam hef, of t niet gebruukt. We gebruken daorumme t IP-adres um hum of heur te herkennen, mer t kan oek ween dat meerdere personen t zelfde IP-adres gebruken, en da'j hiermee berichten ontvangen die niet veur joe bedoeld bin. A'j dit veurkoemen willen, dan ku'j t best [[Special:UserLogin/signup|n gebrukersnaam anmaken]] of [[Special:UserLogin|anmelden]].''",
+ "anontalkpagetext": "---- ''Disse overlegzied heurt bie n anonieme gebruker die nog gien gebrukersnaam hef, of t niet gebruukt. We gebruken daorumme t IP-adres um hum of heur te herkennen, mer t kan oek ween dat meerdere personen t zelfde IP-adres gebruken, en da'j hiermee berichten ontvangen die niet veur joe bedoeld bin. A'j dit veurkoemen willen, dan ku'j t best [[Special:CreateAccount|n gebrukersnaam anmaken]] of [[Special:UserLogin|anmelden]].''",
"noarticletext": "Der steet noen gien tekste op disse zied.\nJe kunnen [[Special:Search/{{PAGENAME}}|de titel opzeuken]] in aandere ziejen,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} zeuken in de logboeken],\nof [{{fullurl:{{FULLPAGENAME}}|action=edit}} disse zied anmaken]</span>.",
"noarticletext-nopermission": "Op disse zied steet gien tekste.\nJe kunnen [[Special:Search/{{PAGENAME}}|zeuken naor disse term]] in aandere ziejen of\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} de logboeken deurzeuken]</span>, mer je hebben gien rechten um disse zied an te maken.",
"missing-revision": "De versie #$1 van de zied \"{{FULLPAGENAME}} besteet niet.\n\nDit kömp meestentieds deur t volgen van n verouwerde verwiezing naor n zied die vortedaon is.\nWaorschienlik ku'j der meer gegevens over vienen in t [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} vortdologboek].",
"sectioneditnotsupported-text": "Je kunnen op disse zied gien seksies bewarken.",
"permissionserrors": "Gien toestemming",
"permissionserrorstext": "Je maggen of kunnen dit niet doon. De {{PLURAL:$1|reden|redens}} daorveur {{PLURAL:$1|is|bin}}:",
- "permissionserrorstext-withaction": "Je hebben gien rech um $2, mit de volgende {{PLURAL:$1|reden|redens}}:",
+ "permissionserrorstext-withaction": "Je hebben gien recht um $2, mit de volgende {{PLURAL:$1|reden|redens}}:",
"recreate-moveddeleted-warn": "'''Waorschuwing: je maken n zied an die eerder al vortedaon is.'''\n\nBedenk eerst of t neudig is um disse zied veerder te bewarken.\nVeur de dudelikheid steet hieronder t vortdologboek en t herneumlogboek veur disse zied:",
"moveddeleted-notice": "Disse zied is vortedaon.\nHieronder steet de informasie uut t vortdologboek en t herneumlogboek.",
"log-fulllog": "t Hele logboek bekieken",
"powersearch-togglelabel": "Selekteren:",
"powersearch-toggleall": "Alle",
"powersearch-togglenone": "Gien",
+ "powersearch-remember": "Keuze onthouwen veur toekomstige zeukopdrachten",
"search-external": "Extern zeuken",
"searchdisabled": "Zeuken in {{SITENAME}} is niet meugelik. Je kunnen gebruukmaken van Google. De gegevens over {{SITENAME}} bin misschien niet bie-ewörken.",
"search-error": "Der is wat mis-egaon bie t zeuken: $1",
"right-userrights": "Alle gebrukersrechten bewarken",
"right-userrights-interwiki": "Gebrukersrechten van gebrukers in aandere wiki's wiezigen",
"right-siteadmin": "De databanke blokkeren en weer vriegeven",
- "right-override-export-depth": "Ziejen uutvoeren, oek de ziejen waor naor verwezen wörden, tot n diepte van 5",
+ "right-override-export-depth": "Ziejen exporteren, oek de ziejen waor naor verwezen wördt, tot n diepte van 5",
"right-sendemail": "Bericht versturen naor aandere gebrukers",
"right-passwordreset": "Bekiek netpostberichten veur t opniej instellen van joew wachtwoord",
"newuserlogpage": "Logboek mit anwas",
"unusedimages": "Ongebruukten bestaanden",
"wantedcategories": "Gewunste kategorieën",
"wantedpages": "Gewunste ziejen",
+ "wantedpages-summary": "Lieste van niet-bestaonde ziejen mit de meeste verwiezingen derhinne, ziejen waor allinnig mer naor deurverwezen wördt staon der niet bie. Veur n lieste van niet-bestaonde ziejen waor naor deurverwezen wördt, ku'j terechte op [[{{#special:BrokenRedirects}}|de lieste van ebreuken deurverwiezingen]].",
"wantedpages-badtitle": "Ongeldige ziednaam in resultaot: $1",
"wantedfiles": "Gewunste bestaanden",
"wantedfiletext-cat": "De volgende bestaanden wörden gebruukt mer bestaon niet. Bestaanden van externe databanken kunnen op-eneumen ween in de lieste, ondanks dat ze bestaon. Soortgelieke vals positieven wörden <del>deurehaold weeregeven</del>. Ziejen die niet-bestaonde bestaanden insluten staon op de zied [[:$1]].",
"exbeforeblank": "veurdat disse zied leegemaakt wörden stung hier: '$1'",
"delete-confirm": "\"$1\" vortdoon",
"delete-legend": "Vortdoon",
- "historywarning": "'''Waorschuwing''': de zied die'j vortdoon, hef $1 {{PLURAL:$1|versie|versies}}:",
+ "historywarning": "'''Waorschuwing''': de zied die'j vortdoon willen, hef $1 {{PLURAL:$1|versie|versies}}:",
"historyaction-submit": "Bekiek",
"confirmdeletetext": "Je staon op t punt n zied en de geschiedenisse dervan vort te doon.\nBevestig hieronder dat dit inderdaod de bedoeling is, da'j de gevolgen begriepen en dat t akkedeert mit t [[{{MediaWiki:Policy-url}}|beleid]].",
"actioncomplete": "Uutevoerd",
"delete-edit-reasonlist": "Redens veur t vortdoon bewarken",
"delete-toobig": "Disse zied hef n lange bewarkingsgeschiedenisse, meer as $1 {{PLURAL:$1|versie|versies}}.\nt Vortdoon van dit soort ziejen is mit rechten bepark um t per ongelok versteuren van de warking van {{SITENAME}} te veurkoemen.",
"delete-warning-toobig": "Disse zied hef n lange bewarkingsgeschiedenisse, meer as $1 {{PLURAL:$1|versie|versies}}.\nWoart je: t vortdoon van disse zied kan de warking van de databanke van {{SITENAME}} versteuren.\nWees veurzichtig",
+ "deleting-backlinks-warning": "<strong>Waorschuwing:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|aandere ziejen]] gebruken of verwiezen naor de zied die'j vortdoon willen.",
"rollback": "Wiezigingen herstellen",
"rollbacklink": "weerummedreien",
"rollbacklinkcount": "{{PLURAL:$1|één bewarking|$1 bewarkingen}} weerummedreien",
"whatlinkshere-next": "{{PLURAL:$1|volgende|volgende $1}}",
"whatlinkshere-links": "← verwiezingen",
"whatlinkshere-hideredirs": "$1 deurverwiezingen",
- "whatlinkshere-hidetrans": "$1 in-evoegden mallen",
- "whatlinkshere-hidelinks": "$1 verwiezingen",
+ "whatlinkshere-hidetrans": "Vörlageninbinnungen $1",
+ "whatlinkshere-hidelinks": "Lenken $1",
"whatlinkshere-hideimages": "$1 bestaandsverwiezingen",
"whatlinkshere-filters": "Filters",
"autoblockid": "Automatiese blokkering #$1",
"sorbsreason": "Joew IP-adres is op-eneumen as open proxyserver in de zwarte lieste van DNS die'w veur {{SITENAME}} gebruken.",
"sorbs_create_account_reason": "Joew IP-adres is op-eneumen as open proxyserver in de zwarte lieste van DNS, die'w veur {{SITENAME}} gebruken.\nJe kunnen gien gebrukerszied anmaken.",
"xffblockreason": "n IP-adres dat jie gebruken is eblokkeerd. Dit steet in de kop 'X-Forwarded-For'. De oorspronkelike reden veur de blokkerings is: $1",
- "cant-see-hidden-user": "De gebruker die'j proberen te blokkeren is al eblokkeerd en verbörgen.\nUmda'j gien rech hebben um gebrukers te verbargen, ku'j de blokkering van de gebruker niet bekieken of bewarken.",
+ "cant-see-hidden-user": "De gebruker die'j proberen te blokkeren is al eblokkeerd en verbörgen.\nUmda'j gien recht hebben um gebrukers te verbargen, ku'j de blokkering van de gebruker niet bekieken of bewarken.",
"ipbblocked": "Je kunnen gien aandere gebrukers (de)blokkeren, umda'j zelf eblokkeerd bin",
"ipbnounblockself": "Je maggen je eigen niet deblokkeren",
"lockdb": "Databanke blokkeren",
"semiprotectedpagemovewarning": "'''Waorschuwing:''' disse zied kan allinnig deur eregistreerden gebrukers herneumd wörden.\nDe leste logboekregel steet hieronder:",
"move-over-sharedrepo": "== t Bestaand besteet al ==\n[[:$1]] besteet al in de edeelden mediadatabanke. A'j n bestaand naor disse titel herneumen, dan ku'j t edeelden bestaand niet gebruken.",
"file-exists-sharedrepo": "Disse bestaandsnaam besteet al in de edeelden mediadatabanke.\nKies n aandere bestaandsnaam.",
- "export": "Ziejen uutvoeren",
- "exporttext": "De tekste en geschiedenisse van n zied of n koppel ziejen kunnen in XML-formaot uutevoerd wörden. Dit bestaand ku'j daornao uutvoeren naor n aandere MediaWiki deur de [[Special:Import|invoerzied]] te gebruken.\n\nZet in t onderstaonde veld de namen van de ziejen die'j uutvoeren willen, één zied per regel, en gif an o'j alle versies mit de bewarkingssamenvatting uutvoeren willen of allinnig de leste versies mit de bewarkingssamenvatting.\n\nA'j dat leste doon willen dan ku'j oek n verwiezing gebruken, bieveurbeeld [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] veur de zied \"[[{{MediaWiki:Mainpage}}]]\".",
- "exportall": "Alle ziejen uutvoeren",
+ "export": "Ziejen exporteren",
+ "exporttext": "De tekste en geschiedenisse van n zied of n koppel ziejen kunnen in XML-formaot uutevoerd wörden. Dit bestaand ku'j daornao exporteren naor n aandere MediaWiki deur de [[Special:Import|invoerzied]] te gebruken.\n\nZet in t onderstaonde veld de namen van de ziejen die'j exporteren willen, één zied per regel, en geef an o'j alle versies mit de bewarkingssamenvatting exporteren willen of allinnig de leste versies mit de bewarkingssamenvatting.\n\nA'j dat leste doon willen dan ku'j oek n verwiezing gebruken, bieveurbeeld [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] veur de zied \"[[{{MediaWiki:Mainpage}}]]\".",
+ "exportall": "Alle ziejen exporteren",
"exportcuronly": "Allinnig de actuele versie, niet de veurgeschiedenisse",
- "exportnohistory": "----\n'''NB:''' t uutvoeren van de hele geschiedenisse is uutezet vanwegen prestasieredens.",
+ "exportnohistory": "----\n'''NB:''' t exporteren van de hele geschiedenisse is uutezet vanwegen prestasieredens.",
"exportlistauthors": "De hele auteurslieste opnemen veur elke zied",
- "export-submit": "Uutvoeren",
+ "export-submit": "Exporteren",
"export-addcattext": "Ziejen derbie doon uut de kategorie:",
"export-addcat": "Derbie doon",
"export-addnstext": "Ziejen uut de volgende naamruumte derbie doon:",
"oct": "Okt",
"nov": "Nov.",
"dec": "Dez",
+ "january-date": "$1. Januar",
+ "february-date": "$1. Februar",
+ "march-date": "$1. März",
+ "april-date": "$1. April",
+ "may-date": "$1. Mai",
+ "june-date": "$1. Juni",
+ "july-date": "$1. Juli",
+ "august-date": "$1. August",
+ "september-date": "$1. September",
+ "october-date": "$1. Oktober",
+ "november-date": "$1. November",
+ "december-date": "$1. Dezember",
"pagecategories": "{{PLURAL:$1|Kategorie|Kategorien}}",
"category_header": "Sieden in de Kategorie „$1“",
"subcategories": "Ünnerkategorien",
"actions": "Akschonen",
"namespaces": "Naamrüüm",
"variants": "Varianten",
+ "navigation-heading": "Navigatschoonsmenü",
"errorpagetitle": "Fehler",
"returnto": "Trüch to $1.",
"tagline": "Vun {{SITENAME}}",
"hidetoc": "Nich wiesen",
"collapsible-collapse": "Versteken",
"collapsible-expand": "Wiesen",
+ "confirmable-yes": "Jo",
+ "confirmable-no": "Nee",
"thisisdeleted": "Ankieken oder weerholen vun $1?",
"viewdeleted": "$1 ankieken?",
"restorelink": "{{PLURAL:$1|ene löschte Version|$1 löschte Versionen}}",
"virus-scanfailed": "Scan hett nich klappt (Code $1)",
"virus-unknownscanner": "Unbekannten Virenscanner:",
"logouttext": "'''Du büst nu afmellt.'''\n\nDu kannst {{SITENAME}} nu anonym wiederbruken oder di ünner dissen oder en annern Brukernaam wedder <span class='plainlinks'>[$1 anmellen]</span>.\nDenk dor an, dat welk Sieden ünner Ümstänn noch jümmer so wiest warrn köönt, as wenn du anmellt weerst. Dat ännert sik, wenn du den Cache vun dien Browser leddig maakst.",
+ "welcomeuser": "Willkamen, $1!",
"yourname": "Dien Brukernaam",
"userlogin-yourname": "Brukernaam",
"yourpassword": "Dien Passwoort",
"noname": "Du muttst en Brukernaam angeven.",
"loginsuccesstitle": "Anmellen hett Spood",
"loginsuccess": "Du büst nu as „$1“ bi {{SITENAME}} anmellt.",
- "nosuchuser": "Den Brukernaam „$1“ gifft dat nich.\nBrukernaams maakt en Ünnerscheed twischen groot un lütt schrevene Bookstaven.\nKiek de Schrievwies na oder [[Special:UserLogin/signup|mell di as ne’en Bruker an]].",
+ "nosuchuser": "Den Brukernaam „$1“ gifft dat nich.\nBrukernaams maakt en Ünnerscheed twischen groot un lütt schrevene Bookstaven.\nKiek de Schrievwies na oder [[Special:CreateAccount|mell di as ne’en Bruker an]].",
"nosuchusershort": "De Brukernaam „$1“ existeert nich. Prööv de Schrievwies.",
"nouserspecified": "Du musst en Brukernaam angeven",
"login-userblocked": "Disse Bruker is sperrt. Anmellen geiht nich.",
"accmailtext": "En tofällig Passwoord för [[User talk:$1|$1]] is $2 tostüürt worrn.\n\nDat Passwoord för dit Brukerkonto kann na dat Anmellen ünner ''[[Special:ChangePassword|Passwoord ännern]]'' ännert warrn.",
"newarticle": "(Nee)",
"newarticletext": "Du büst op en Sied kamen, de dat noch nich gifft.\nWenn du disse Sied opstellen wullt, schriev dien Text in dat Finster ünnen (kiek op de [$1 Hülpsied] för mehr Infos).\nWenn du de Sied gornich ännern wullst, denn klick op den '''Trügg'''-Knoop in dien Webkieker.",
- "anontalkpagetext": "---- ''Dit is de Diskuschoonssiet vun en nich anmellt Bruker, de noch keen Brukerkonto anleggt hett oder dat jüst nich bruukt.\nWi mööt hier de numerische IP-Adress verwennen, üm den Bruker to identifizeern.\nSo en Adress kann vun verscheden Brukern bruukt warrn.\nWenn du en anonymen Bruker büst un meenst, dat disse Kommentaren nich an di richt sünd, denn [[Special:UserLogin/signup|legg di en Brukerkonto an]] oder [[Special:UserLogin|mell di an]], dat dat Problem nich mehr dor is.''",
- "noarticletext": "Dor is opstunns keen Text op disse Sied. Du kannst [[Special:Search/{{PAGENAME}}|na dissen Utdruck in annere Sieden söken]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} in de Logböker söken],\noder [{{fullurl:{{FULLPAGENAME}}|action=edit}} disse Sied ännern]</span>.",
+ "anontalkpagetext": "---- ''Dit is de Diskuschoonssiet vun en nich anmellt Bruker, de noch keen Brukerkonto anleggt hett oder dat jüst nich bruukt.\nWi mööt hier de numerische IP-Adress verwennen, üm den Bruker to identifizeern.\nSo en Adress kann vun verscheden Brukern bruukt warrn.\nWenn du en anonymen Bruker büst un meenst, dat disse Kommentaren nich an di richt sünd, denn [[Special:CreateAccount|legg di en Brukerkonto an]] oder [[Special:UserLogin|mell di an]], dat dat Problem nich mehr dor is.''",
+ "noarticletext": "Dor is opstunns keen Text op disse Siet. \nDu kannst [[Special:Search/{{PAGENAME}}|na dissen Utdruck in annere Sieden söken]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} in de Logböker söken], oder [{{fullurl:{{FULLPAGENAME}}|action=edit}} disse Siet ännern]</span>.",
"noarticletext-nopermission": "Disse Sied hett opstunns keen Text.\nDu kannst in annere Sieden [[Special:Search/{{PAGENAME}}|na dissen Titel söken]]\noder <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} in de Logböker söken]</span>, man du hest nich dat Recht, de Sied optostellen.",
"userpage-userdoesnotexist": "Dat Brukerkonto „<nowiki>$1</nowiki>“ gifft dat noch nich. Överlegg, wat du disse Siet würklich nee opstellen/ännern wullt.",
"userpage-userdoesnotexist-view": "Dat Brukerkonto „$1“ gifft dat nich.",
"session_fail_preview_html": "'''Deit uns leed! Wi kunnen dien Ännern nich spiekern, de Sitzungsdaten sünd verloren gahn.'''\n\n''In {{SITENAME}} is dat Spiekern vun rein HTML verlöövt, dorvun is de Vörschau utblennt, dat JavaScript-Angrepen nich mööglich sünd.''\n\n'''Versöök dat noch wedder un klick noch wedder op „Siet spiekern“. Wenn dat Problem noch jümmer dor is, [[Special:UserLogout|mell di af]] un denn wedder an.'''",
"token_suffix_mismatch": "'''Dien Ännern sünd afwiest worrn. Dien Browser hett welk Teken in de Kuntrull-Tekenreeg kaputt maakt.\nWenn dat so spiekert warrt, kann dat angahn, dat noch mehr Teken in de Sied kaputt gaht.\nDat kann to’n Bispeel dor vun kamen, dat du en anonymen Proxy-Deenst bruukst, de wat verkehrt maakt.'''",
"editing": "Ännern vun $1",
+ "creating": "Opstellen vun $1",
"editingsection": "Ännern vun $1 (Afsatz)",
"editingcomment": "Ännern vun $1 (nee Afsnidd)",
"editconflict": "Konflikt bi’t Sied ännern: $1",
"currentrev": "Aktuelle Version",
"currentrev-asof": "Aktuelle Version vun’n $1",
"revisionasof": "Version vun $1",
- "revision-info": "Verschoon vun'n $4, Klock $5 vun $2",
+ "revision-info": "Verschoon vun'n $4, Klock $5 vun {{GENDER:$6|$2}}$7",
"previousrevision": "Nächstöllere Version→",
"nextrevision": "Ne’ere Version →",
"currentrevisionlink": "aktuelle Version",
"shown-title": "Wies $1 {{PLURAL:$1|Resultat|Resultaten}} per Sied",
"viewprevnext": "Wies ($1 {{int:pipe-separator}} $2) ($3).",
"searchmenu-exists": "* Sied '''[[$1]]'''",
- "searchmenu-new": "'''Stell de Sied „[[:$1]]“ in dit Wiki nee op!'''",
+ "searchmenu-new": "<strong>Stell de Siet „[[:$1]]“ in dit Wiki nee op!</strong> {{PLURAL:$2|0=|Süh ok de Siet mit dien Sökresultat.|Süh ok de funnen Sökresultaten.}}",
"searchprofile-articles": "Inholdsieden",
"searchprofile-images": "Datein",
"searchprofile-everything": "Allens",
"powersearch-togglelabel": "Utwählen:",
"powersearch-toggleall": "All",
"powersearch-togglenone": "Keen",
+ "powersearch-remember": "Utwahl för latere sökanfragen marken",
"search-external": "Externe Söök",
"searchdisabled": "<p>De Vulltextsöök is wegen Överlast en Stoot deaktiveert. In disse Tied kannst du disse Google-Söök verwennen,\nde aver nich jümmer den aktuellsten Stand weerspegelt.<p>",
"preferences": "Instellen",
"action-userrights-interwiki": "de Rechten vun Brukers op annere Wikis to ännern",
"action-siteadmin": "de Datenbank to sperren oder freetogeven",
"nchanges": "{{PLURAL:$1|Een Ännern|$1 Ännern}}",
+ "enhancedrc-history": "Historie",
"recentchanges": "Toletzt ännert",
"recentchanges-legend": "Optionen för toletzt ännert",
"recentchanges-summary": "Op disse Sied warrt de Sieden wiest, de toletzt ännert worrn sünd.",
"recentchanges-label-minor": "Dat is en lütte Ännern",
"recentchanges-label-bot": "Düsse Ännern worr maakt vun en Bot",
"recentchanges-label-unpatrolled": "Düsse Ännern is noch nich kontrolleert worrn",
+ "recentchanges-label-plusminus": "Disse Siedengrött is mit dit Antall Bytes ännert",
+ "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (süh ok de [[Special:NewPages|List mit ne'e Sieden]])",
"rcnotefrom": "Dit sünd de Ännern siet <b>$2</b> (bet to <b>$1</b> wiest).",
"rclistfrom": "Wies ne’e Ännern siet $3 $2",
- "rcshowhideminor": "$1 lütte Ännern",
- "rcshowhidebots": "$1 Bots",
- "rcshowhideliu": "$1 inloggte Brukers",
- "rcshowhideanons": "$1 anonyme Brukers",
+ "rcshowhideminor": "lütte Ännern $1",
+ "rcshowhideminor-show": "wiesen",
+ "rcshowhideminor-hide": "versteken",
+ "rcshowhidebots": "Bots $1",
+ "rcshowhidebots-show": "wiesen",
+ "rcshowhidebots-hide": "versteken",
+ "rcshowhideliu": "registreerte Brukers $1",
+ "rcshowhideliu-show": "wiesen",
+ "rcshowhideliu-hide": "versteken",
+ "rcshowhideanons": "anonyme Brukers $1",
+ "rcshowhideanons-show": "wiesen",
+ "rcshowhideanons-hide": "versteken",
"rcshowhidepatr": "$1 nakekene Ännern",
- "rcshowhidemine": "$1 miene Ännern",
+ "rcshowhidepatr-show": "wiesen",
+ "rcshowhidepatr-hide": "versteken",
+ "rcshowhidemine": "miene Ännern $1",
+ "rcshowhidemine-show": "wiesen",
+ "rcshowhidemine-hide": "versteken",
+ "rcshowhidecategorization": "kategoriserung vun Sieden $1",
"rclinks": "Wies de letzten '''$1''' Ännern vun de letzten '''$2''' Daag. ('''N''' - Ne’e Sieden; '''L''' - Lütte Ännern)<br />$3",
"diff": "Ünnerscheed",
"hist": "Versionen",
"hide": "Nich wiesen",
- "show": "Wiesen",
+ "show": "wiesen",
"minoreditletter": "L",
"newpageletter": "N",
"boteditletter": "B",
"pager-older-n": "{{PLURAL:$1|vörige|vörige $1}}",
"suppress": "Oversight",
"apisandbox-examples": "Bispeel",
- "apisandbox-results": "Resultat",
+ "apisandbox-results": "Resultaten",
"booksources": "Bookhannel",
"booksources-search-legend": "Na Böker bi Bookhökers söken",
"booksources-search": "Söken",
"wlheader-showupdated": "Sieden, de siet dien letzten Besöök ännert worrn sünd, warrt '''fett''' wiest.",
"wlnote": "Ünnen {{PLURAL:$1|steiht de letzte Ännern|staht de letzten $1 Ännern}} vun de {{PLURAL:$2|letzte Stünn|letzten '''$2''' Stünnen}}.",
"wlshowlast": "Wies de letzten $1 Stünnen $2 Daag",
+ "watchlist-hide": "Versteken",
"watchlist-options": "Optionen för de Oppasslist",
"watching": "warrt op de Oppasslist ropsett...",
"unwatching": "warrt vun de Oppasslist rünnernahmen...",
"undelete-show-file-submit": "Jo",
"namespace": "Naamruum:",
"invert": "Utwahl ümkehren",
+ "namespace_association": "Tohörige Naamruum",
"blanknamespace": "(Hööft-)",
- "contributions": "Bidrääg vun den Bruker",
+ "contributions": "Bidrääg vun den {{GENDER:$1|Bruker}}",
"contributions-title": "Brukerbidrääg vun „$1“",
"mycontris": "Mien Arbeid",
"contribsub2": "För $1 ($2)",
"whatlinkshere-prev": "{{PLURAL:$1|vörige|vörige $1}}",
"whatlinkshere-next": "{{PLURAL:$1|nächste|nächste $1}}",
"whatlinkshere-links": "← Lenken",
- "whatlinkshere-hideredirs": "Redirects $1",
- "whatlinkshere-hidetrans": "Vörlageninbinnungen $1",
- "whatlinkshere-hidelinks": "Lenken $1",
- "whatlinkshere-hideimages": "Dateilenken $1",
+ "whatlinkshere-hideredirs": "$1 Redirects",
+ "whatlinkshere-hidetrans": "$1 in-evoegden mallen",
+ "whatlinkshere-hidelinks": "$1 verwiezingen",
+ "whatlinkshere-hideimages": "$1 bestaandsverwiezingen",
"whatlinkshere-filters": "Filters",
"autoblockid": "Autoblock #$1",
"block": "Bruker blocken",
"importlogpagetext": "Administrativen Import vun Sieden mit Versionsgeschicht vun annere Wikis.",
"import-logentry-upload-detail": "{{PLURAL:$1|ene Version|$1 Versionen}}",
"import-logentry-interwiki-detail": "{{PLURAL:$1|ene Version|$1 Versionen}} vun $2",
- "tooltip-pt-userpage": "Dien Brukersied",
+ "tooltip-pt-userpage": "{{GENDER:|Dien}} Brukersiet",
"tooltip-pt-anonuserpage": "De Brukersiet för de IP-Adress ünner de du schriffst",
- "tooltip-pt-mytalk": "Dien Diskuschoonssied",
+ "tooltip-pt-mytalk": "{{GENDER:|Dien}} Diskuschoonssiet",
"tooltip-pt-anontalk": "Diskuschoon över Ännern vun disse IP-Adress",
- "tooltip-pt-preferences": "Mien Instellen",
+ "tooltip-pt-preferences": "{{GENDER:|Dien}} Instellen",
"tooltip-pt-watchlist": "Mien Oppasslist",
- "tooltip-pt-mycontris": "List vun dien Bidrääg",
+ "tooltip-pt-mycontris": "List vun {{GENDER:|dien}} Bidrääg",
"tooltip-pt-login": "Du kannst di geern anmellen, dat is aver nich nödig, dat du Sieden ännern kannst.",
"tooltip-pt-logout": "Afmellen",
"tooltip-ca-talk": "Diskuschoon över disse Siet",
- "tooltip-ca-edit": "Du kannst disse Siet ännern. Bruuk dat vör dat Spiekern.",
+ "tooltip-ca-edit": "Disse Siet ännern",
"tooltip-ca-addsection": "En Afsnidd tofögen",
"tooltip-ca-viewsource": "Disse Siet is schuult. Du kannst den Borntext ankieken.",
"tooltip-ca-history": "Historie vun disse Siet.",
"tooltip-t-recentchangeslinked": "Verlinkte Sieden",
"tooltip-feed-rss": "RSS-Feed för disse Siet",
"tooltip-feed-atom": "Atom-Feed för disse Siet",
- "tooltip-t-contributions": "List vun de Bidreeg vun dissen Bruker",
+ "tooltip-t-contributions": "List vun de Bidrääg vun {{GENDER:$1|dissen Bruker}}",
"tooltip-t-emailuser": "Dissen Bruker en E-Mail tostüren",
"tooltip-t-upload": "Biller oder Mediendatein hoochladen",
"tooltip-t-specialpages": "List vun alle Spezialsieden",
"tooltip-ca-nstab-main": "Siet ankieken",
"tooltip-ca-nstab-user": "Brukersiet ankieken",
"tooltip-ca-nstab-media": "Mediensiet ankieken",
- "tooltip-ca-nstab-special": "Dit is en Spezialsiet, du kannst disse Siet nich ännern.",
+ "tooltip-ca-nstab-special": "Dit is en Spezialsiet un kann nich ännert worrn.",
"tooltip-ca-nstab-project": "Portalsiet ankieken",
"tooltip-ca-nstab-image": "Bildsiet ankieken",
"tooltip-ca-nstab-mediawiki": "Systemnarichten ankieken",
"spambot_username": "MediaWiki Spam-Oprümen",
"spam_reverting": "Trüchdreiht na de letzte Version ahn Lenken na $1.",
"spam_blanking": "All Versionen harrn Lenken na $1, rein maakt.",
- "simpleantispam-label": "Antispam-Kuntrull. Hier '''nix''' indragen!",
+ "simpleantispam-label": "Antispam-Kuntrull. \nHier '''nix''' indragen!",
"pageinfo-title": "Informatschoon för \"$1\"",
"pageinfo-article-id": "Sied-ID",
+ "pageinfo-toolboxlink": "Sieteninformatschonen",
"pageinfo-redirectsto-info": "Info",
"pageinfo-contentpage-yes": "Jo",
"pageinfo-protect-cascading-yes": "Jo",
"file-info-size": "$1 × $2 Pixel, Grött: $3, MIME-Typ: $4",
"file-nohires": "Gifft dat Bild nich grötter.",
"svg-long-desc": "SVG-Datei, Utgangsgrött: $1 × $2 Pixel, Dateigrött: $3",
- "show-big-image": "Dat Bild wat grötter",
+ "show-big-image": "Originaldatei",
"show-big-image-size": "$1 × $2 Pixels",
"file-info-gif-looped": "löppt as Slööp",
"file-info-gif-frames": "$1 {{PLURAL:$1|Bild|Biller}}",
"htmlform-selectorother-other": "Annere",
"sqlite-has-fts": "$1 mit Stöhn för Vulltext-Söök",
"sqlite-no-fts": "$1 ahn Stöhn för Vulltext-Söök",
+ "logentry-delete-delete": "$1 {{GENDER:$2|wegsmeten}} Siet $3",
"revdelete-restricted": "Inschränkungen för Administraters instellt",
"revdelete-unrestricted": "Inschränkungen för Administraters rutnahmen",
"logentry-block-block": "$1 {{GENDER:$2|block}} {{GENDER:$4|$3}} för en Tiedruum vun $5 $6",
"expand_templates_ok": "Los",
"expand_templates_remove_comments": "Kommentaren rutnehmen",
"expand_templates_generate_xml": "XML-Parser-Boom wiesen",
- "expand_templates_preview": "Vörschau"
+ "expand_templates_preview": "Vörschau",
+ "pagelang-language": "Spraak"
}
"noname": "तपाईंले सही प्रयोगकर्ता नाम दिनु भएन।",
"loginsuccesstitle": "प्रवेश सफल",
"loginsuccess": "'''तपाईंले {{SITENAME}}मा \"$1\" को रुपमा प्रवेश गर्नुभएकोछ।'''",
- "nosuchuser": "\"$1\" को नामबाट कुनै पनि प्रयोगकर्ता भेटिएनन् ।\nप्रयोगकर्ता नाम वर्णसंवेदनशील हुन्छन् ।\nहिज्जे जाँच्नुहोस् , या [[Special:UserLogin/signup|नयाँ खाता बनाउनुहोस्]].",
+ "nosuchuser": "\"$1\" को नामबाट कुनै पनि प्रयोगकर्ता भेटिएनन् ।\nप्रयोगकर्ता नाम वर्णसंवेदनशील हुन्छन् ।\nहिज्जे जाँच्नुहोस् , या [[Special:CreateAccount|नयाँ खाता बनाउनुहोस्]].",
"nosuchusershort": " \"$1\" नामको कुनै पनि प्रयोगकर्ता भेटिएन।\n तपाईँको हिज्जे जाँच्नुहोस् ।",
"nouserspecified": "तपाँईले प्रयोगकर्ताको नाम जनाउनुपर्छ।",
"login-userblocked": "यस प्रयोगकर्तालाई रोक लगाइएको छ। प्रवेश गर्ने अनुमति छैन।",
"accmailtext": "जथाभावीरूपमा सृजना गरिएको प्रवेशशब्द प्रयोगकर्ता [[User talk:$1|$1]] को $2 मा पठाइएको छ।\n\nयो नयाँ खाताको प्रवेशशब्द ''[[Special:ChangePassword|change password]]'' मा प्रवेश गरेर परिवर्तन गर्न सकिन्छ ।",
"newarticle": "(नयाँ)",
"newarticletext": "तपाईँले अहिले सम्म नभएको पृष्ठको लिंङ्क पहिल्याउनु भएको छ।\nयो पृष्ठ निर्माण गर्न तलको कोष्ठमा टाइप गर्नुहोस् ।(थप जानकारीको लागि [$1 help page] हेर्नुहोस् )।\nयहाँ त्यत्तिकै आइपुग्नु भएको हो भने , ब्राउजरको '''back''' बटन थिच्नुहोस ।",
- "anontalkpagetext": "----''यो वार्तालाप पृष्ठ अज्ञात प्रयोगकर्ताको हो जसले अहिलेसम्म खाता बनाएकै छैन, अथवा जसले यस पृष्ठको उपयोग गर्दैन।\nयस कारण हामीले उसलाई उसको आइ पी (IP) ठेगानाले चिन्न सक्छौं। \nयस्तो आइ पी (IP) ठेगाना धेरै प्रयोगकर्ताहरूको साझा हुनसक्छ।\nयदि तपाईं अज्ञात प्रयोगकर्ता हुनुहुन्छ र तपाईंमाथि अचाहिँदो टिप्पणी भएको अनुभव गर्नुहुन्छ भने भविष्यमा अन्य अज्ञात प्रयोगकर्तासितको भ्रमबाट बाँच्न कृपया [[Special:UserLogin/signup|खाता खोल्नुहोस्]] अथवा [[Special:UserLogin|प्रवेश गर्नुहोस्]] ''",
+ "anontalkpagetext": "----''यो वार्तालाप पृष्ठ अज्ञात प्रयोगकर्ताको हो जसले अहिलेसम्म खाता बनाएकै छैन, अथवा जसले यस पृष्ठको उपयोग गर्दैन।\nयस कारण हामीले उसलाई उसको आइ पी (IP) ठेगानाले चिन्न सक्छौं। \nयस्तो आइ पी (IP) ठेगाना धेरै प्रयोगकर्ताहरूको साझा हुनसक्छ।\nयदि तपाईं अज्ञात प्रयोगकर्ता हुनुहुन्छ र तपाईंमाथि अचाहिँदो टिप्पणी भएको अनुभव गर्नुहुन्छ भने भविष्यमा अन्य अज्ञात प्रयोगकर्तासितको भ्रमबाट बाँच्न कृपया [[Special:CreateAccount|खाता खोल्नुहोस्]] अथवा [[Special:UserLogin|प्रवेश गर्नुहोस्]] ''",
"noarticletext": "यस लेखमा अहिले केहि पनि पाठ छैन ।\nतपाईंले अन्य पृष्ठमा [[Special:Search/{{PAGENAME}}|यस पृष्ठको शीर्षकको लागि खोज]] गर्न सक्नुहुन्छ ।\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} पृष्ठ सम्बन्धित ढड्डामा खोज],\nवा [{{fullurl:{{FULLPAGENAME}}|action=edit}} यसै पृष्ठलाई सम्पादन गर्ने]</span>.",
"noarticletext-nopermission": "यस लेखमा अहिले कुनै पनि पाठ छैन ।\nतपाईंले अन्य पृष्ठमा [[Special:Search/{{PAGENAME}}|यस पृष्ठको शीर्षकको लागि खोज]] गर्न सक्नुहुन्छ,\nअथवा <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|पृष्ठ={{FULLPAGENAMEE}}}} सम्बन्धित लगहरू खोज्न सक्नुहुनेछ ]</span> तर तपाईंलाई नयाँ पृष्ठ बनाउने अधिकार छैन।",
"missing-revision": "\"{{FULLPAGENAME}}\" पृष्ठको अवतरण #$1 रहेको छैन।\n\nसामान्य रूपमा यसो एउटा हटाइएको पृष्ठको पुरानो लिङ्कमा क्लिक गर्दा हुन्छ।\nअधिक जानकारीको लागि तपाईं [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} हटाएको लग] हेर्न सक्नुहुन्छ।",
"userlogin-resetpassword-link": "Wachtwoord vergeten?",
"userlogin-helplink2": "Hulp bij aanmelden",
"userlogin-loggedin": "U bent al aangemeld als {{GENDER:$1|$1}}.\nGebruik het onderstaande formulier om aan te melden als een andere gebruiker.",
+ "userlogin-reauth": "U moet opnieuw inloggen om te bevestigen dat u {{GENDER:$1|$1}} bent.",
"userlogin-createanother": "Een andere account registreren",
"createacct-emailrequired": "E-mailadres",
"createacct-emailoptional": "E-mailadres (optioneel)",
"noname": "U hebt geen geldige gebruikersnaam opgegeven.",
"loginsuccesstitle": "Aangemeld",
"loginsuccess": "<strong>U bent nu aangemeld bij {{SITENAME}} als \"$1\".</strong>",
- "nosuchuser": "De gebruiker \"$1\" bestaat niet.\nGebruikersnamen zijn hoofdlettergevoelig.\nControleer de schrijfwijze of [[Special:UserLogin/signup|maak een nieuw gebruiker aan]].",
+ "nosuchuser": "De gebruiker \"$1\" bestaat niet.\nGebruikersnamen zijn hoofdlettergevoelig.\nControleer de schrijfwijze of [[Special:CreateAccount|maak een nieuw gebruiker aan]].",
"nosuchusershort": "De gebruiker \"$1\" bestaat niet.\nControleer de schrijfwijze.",
"nouserspecified": "Geef een gebruikersnaam op.",
"login-userblocked": "Deze gebruiker is geblokkeerd.\nAanmelden is niet mogelijk.",
"anoneditwarning": "<strong>Waarschuwing:</strong> u bent niet aangemeld.\nUw IP-adres wordt opgeslagen als u wijzigingen op deze pagina maakt. Wanneer u <strong>[$1 aanmeldt]</strong> of <strong>[$2 een gebruiker aanmaakt]</strong> verschijnen uw bewerkingen onder uw gebruikersnaam, naast andere voordelen.",
"anonpreviewwarning": "''U bent niet aangemeld.''\n''Door uw bewerking op te slaan wordt uw IP-adres opgeslagen in de paginageschiedenis.''",
"missingsummary": "'''Let op:''' u hebt geen bewerkingssamenvatting opgegeven.\nAls u nogmaals op \"{{int:savearticle}}\" klikt wordt de bewerking zonder samenvatting opgeslagen.",
- "selfredirect": "<strong>Waarschuwing:</strong> U heeft een doorverwijzing gemaakt naar dezelfde pagina. Mogelijk heeft u de verkeerde bestemming voor de doorverwijzing gebruikt, of bewerkt u de verkeerde pagina. Door nogmaals op \"{{int:savearticle}}\" te klikken word de doorverwijzing alsnog aangemaakt.",
+ "selfredirect": "<strong>Waarschuwing:</strong> U heeft een doorverwijzing gemaakt naar deze pagina. Mogelijk heeft u de verkeerde bestemming voor de doorverwijzing gebruikt, of bewerkt u de verkeerde pagina. Door nogmaals op \"{{int:savearticle}}\" te klikken word de doorverwijzing alsnog aangemaakt.",
"missingcommenttext": "Plaats uw reactie hieronder.",
"missingcommentheader": "<strong>Let op:</strong> u hebt geen onderwerp/kop voor deze opmerking opgegeven.\nAls u opnieuw op \"{{int:savearticle}}\" klikt, wordt uw wijziging zonder een onderwerp/kop opgeslagen.",
"summary-preview": "Bewerkingssamenvatting nakijken:",
"accmailtext": "Een willekeurig gegenereerd wachtwoord voor [[User talk:$1|$1]] is verzonden naar $2. Het kan worden gewijzigd op de pagina \"[[Special:ChangePassword|wachtwoord wijzigen]]\" na het aanmelden.",
"newarticle": "(Nieuw)",
"newarticletext": "Deze pagina bestaat niet.\nTyp in het onderstaande veld om de pagina aan te maken (meer informatie staat op de [$1 hulppagina]).\nGebruik de knop <strong>Terug</strong> in uw browser als u hier per ongeluk terecht bent gekomen.",
- "anontalkpagetext": "----\n<em>Deze overlegpagina hoort bij een anonieme gebruiker die geen gebruikersnaam heeft of deze niet gebruikt.</em>\nDaarom wordt het IP-adres ter identificatie gebruikt.\nHet is mogelijk dat meerdere personen hetzelfde IP-adres gebruiken.\nMogelijk ontvangt u hier berichten die niet voor u bedoeld zijn.\nAls u dat wilt voorkomen, [[Special:UserLogin/signup|registreer u]] of [[Special:UserLogin|meld u aan]] om verwarring met andere anonieme gebruikers te voorkomen.",
+ "anontalkpagetext": "----\n<em>Deze overlegpagina hoort bij een anonieme gebruiker die geen gebruikersnaam heeft of deze niet gebruikt.</em>\nDaarom wordt het IP-adres ter identificatie gebruikt.\nHet is mogelijk dat meerdere personen hetzelfde IP-adres gebruiken.\nMogelijk ontvangt u hier berichten die niet voor u bedoeld zijn.\nAls u dat wilt voorkomen, [[Special:CreateAccount|registreer u]] of [[Special:UserLogin|meld u aan]] om verwarring met andere anonieme gebruikers te voorkomen.",
"noarticletext": "Deze pagina bevat geen tekst.\nU kunt [[Special:Search/{{PAGENAME}}|naar deze term zoeken]] in andere pagina's, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} de logboeken doorzoeken] of [{{fullurl:{{FULLPAGENAME}}|action=edit}} deze pagina aanmaken]</span>.",
"noarticletext-nopermission": "Deze pagina bevat geen tekst.\nU kunt [[Special:Search/{{PAGENAME}}|naar deze term zoeken]] in andere pagina's of\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} de logboeken doorzoeken]</span>, maar u mag de pagina niet aanmaken.",
"missing-revision": "De versie #$1 van de pagina \"{{FULLPAGENAME}}\" bestaat niet.\n\nDit wordt meestal veroorzaakt door het volgen van een verouderde koppeling naar een pagina die is verwijderd.\nMeer gegevens zijn mogelijk te vinden in het [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} verwijderingslogboek].",
"upload-form-label-own-work": "Dit is mijn eigen werk",
"upload-form-label-infoform-categories": "Categorieën",
"upload-form-label-infoform-date": "Datum",
- "upload-form-label-own-work-message-local": "Ik bevestig dat ik dit bestand upload onder de voorwaarden en het licentiebeleid van {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Als u niet in staat bent dit bestand te uploaden onder het beleid van {{SITENAME}}, sluit dit venster dan alstublieft en kies een andere methode.",
- "upload-form-label-not-own-work-local-local": "U kunt ook de [[Special:Upload|standaard uploadpagina]] gebruiken.",
- "upload-form-label-own-work-message-default": "Ik begrijp dat ik dit bestand upload naar een gedeelde repository. Ik bevestig dat ik voldoe aan de voorwaarden en het licentiebeleid daar.",
- "upload-form-label-not-own-work-message-default": "Als u niet in staat bent dit bestand te uploaden onder het beleid van de gedeelde repository, sluit dit venster dan alstublieft en kies een andere methode.",
- "upload-form-label-not-own-work-local-default": "U kunt ook proberen de [[Special:Upload|uploadpagina van {{SITENAME}}]] te gebruiken als dit bestand geüpload kan worden onder hun beleid.",
- "upload-form-label-own-work-message-shared": "Ik verklaar dat ik de auteursrechten bezit op dit bestand en ik ga onherroepbaar akkoord met het vrijgeven van dit bestand aan Wikimedia Commons onder de licentie [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Naamsvermelding-GelijkDelen 4.0] en ik ga akkoord met de [https://wikimediafoundation.org/wiki/Terms_of_Use Gebruiksvoorwaarden].",
- "upload-form-label-not-own-work-message-shared": "Als u geen eigenaar bent van de auteursrechten van dit bestand, of als u het onder een andere licentie wilt vrijgeven, overweeg dan gebruik te maken van de [https://commons.wikimedia.org/wiki/Special:UploadWizard Commons Upload Wizard].",
- "upload-form-label-not-own-work-local-shared": "U kunt ook de [[Special:Upload|uploadpagina op {{SITENAME}}]] gebruiken, als de site het uploaden van dit bestand onder hun beleid toestaat.",
+ "upload-form-label-own-work-message-generic-local": "Ik bevestig dat ik dit bestand upload onder de voorwaarden en het licentiebeleid van {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Als u niet in staat bent dit bestand te uploaden onder het beleid van {{SITENAME}}, sluit dit venster dan alstublieft en kies een andere methode.",
+ "upload-form-label-not-own-work-local-generic-local": "U kunt ook de [[Special:Upload|standaard uploadpagina]] gebruiken.",
+ "upload-form-label-own-work-message-generic-foreign": "Ik begrijp dat ik dit bestand upload naar een gedeelde repository. Ik bevestig dat ik voldoe aan de voorwaarden en het licentiebeleid daar.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Als u niet in staat bent dit bestand te uploaden onder het beleid van de gedeelde repository, sluit dit venster dan alstublieft en kies een andere methode.",
+ "upload-form-label-not-own-work-local-generic-foreign": "U kunt ook proberen de [[Special:Upload|uploadpagina van {{SITENAME}}]] te gebruiken als dit bestand geüpload kan worden onder hun beleid.",
"backend-fail-stream": "Het was niet mogelijk het bestand \"$1\" te streamen.",
"backend-fail-backup": "Het was niet mogelijk een reservekopie van het bestand $1 te maken.",
"backend-fail-notexists": "Het bestand $1 bestaat niet.",
"undelete-error-long": "Er zijn fouten opgetreden bij het herstellen van het bestand:\n\n$1",
"undelete-show-file-confirm": "Weet u zeker dat u een verwijderde versie van het bestand \"<nowiki>$1</nowiki>\" van $2 om $3 wilt bekijken?",
"undelete-show-file-submit": "Ja",
- "namespace": "Naamruimte:",
+ "namespace": "Naamruimte: ",
"invert": "Selectie omkeren",
"tooltip-invert": "Selecteer dit om wijzigingen te verbergen in de geselecteerde naamruimte (en de gekoppelde naamruimte indien aangevinkt)",
"tooltip-whatlinkshere-invert": "Selecteer dit vakje om koppelingen van pagina's in de geselecteerde naamruimte te verbergen.",
"confirm-watch-top": "Deze pagina toevoegen aan uw volglijst?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Deze pagina verwijderen uit uw volglijst?",
+ "confirm-rollback-button": "OK",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← vorige pagina",
"imgmultipagenext": "volgende pagina →",
"timezone-local": "Lokale tijd",
"duplicate-defaultsort": "'''Waarschuwing:''' de standaardsortering \"$2\" krijgt voorrang voor de sortering \"$1\".",
"duplicate-displaytitle": "<strong>Waarschuwing:</strong>Titelweergave \"$2\" overschrijft eerdere titelweergave \"$1\".",
+ "restricted-displaytitle": "<strong>Waarschuwing:</strong> Titelweergave \"$1\" werd genegeerd omdat deze niet overeenkomt met de werkelijke paginatitel.",
"invalid-indicator-name": "<strong>Fout:</strong> de eigenschap <code>name</code> van de paginastatusindicators mag niet leeg zijn.",
"version": "Versie",
"version-extensions": "Geïnstalleerde uitbreidingen",
"mw-widgets-titleinput-description-redirect": "doorverwijzing naar $1",
"api-error-blacklisted": "Kies een andere, beschrijvende naam.",
"sessionmanager-tie": "Het is niet mogelijk om meerdere authenticatietypen voor verzoeken te combineren: $1.",
- "sessionprovider-generic": "$1 sessies",
- "sessionprovider-mediawiki-session-cookiesessionprovider": "sessies gebaseerd op cookies",
+ "sessionprovider-generic": "$1-sessies",
+ "sessionprovider-mediawiki-session-cookiesessionprovider": "op cookies gebaseerde sessies",
"sessionprovider-nocookies": "Cookies kunnen uitgeschakeld zijn. Zorg ervoor dat u cookies hebt ingeschakeld en probeer het opnieuw.",
"randomrootpage": "Willekeurige hoofdpagina",
"log-action-filter-block": "Soort blokkade:",
"log-action-filter-rights-rights": "Handmatige aanpassing",
"log-action-filter-rights-autopromote": "Automatische aanpassing",
"log-action-filter-upload-upload": "Nieuwe upload",
- "log-action-filter-upload-overwrite": "Herupload"
+ "log-action-filter-upload-overwrite": "Herupload",
+ "authmanager-email-label": "E-mail"
}
"Gaute",
"Macofe",
"Chameleon222",
- "Matma Rex"
+ "Matma Rex",
+ "Mortensson"
]
},
"tog-underline": "Strek under lenkjer:",
"tog-hideminor": "Gøym småplukk i lista over siste endringar",
"tog-hidepatrolled": "Gøym patruljerte endringar i lista over siste endringar",
"tog-newpageshidepatrolled": "Gøym patruljerte sider frå lista over nye sider",
+ "tog-hidecategorization": "Løyn sidekategoriseringa",
"tog-extendwatchlist": "Utvid overvakingslista til å vise alle endringane, ikkje berre dei siste",
"tog-usenewrc": "Grupper endringar etter side i siste endringane og på overvakingslista",
"tog-numberheadings": "Vis nummererte overskrifter",
"tog-watchdefault": "Legg til sidene og filene eg endrar på overvakingslista mi",
"tog-watchmoves": "Legg til sidene og filene eg flytter på overvakingslista mi",
"tog-watchdeletion": "Legg til sidene og filene eg slettar på overvakingslista mi",
+ "tog-watchuploads": "Overvak nye filer som eg lastar opp",
+ "tog-watchrollback": "Overvak sider som eg har attra",
"tog-minordefault": "Merk endringar som «småplukk» som standard",
"tog-previewontop": "Vis førehandsvisinga før endringsboksen",
"tog-previewonfirst": "Førehandsvis første endring",
"tog-watchlisthidebots": "Gøym endringar gjorde av robotar i overvakingslista",
"tog-watchlisthideminor": "Gøym småplukk i overvakingslista",
"tog-watchlisthideliu": "Gøym endringar av innlogga brukarar i overvakingslista.",
+ "tog-watchlistreloadautomatically": "Oppdater overvakingslista automatisk når eit filter vert endra (krev JavaScript)",
"tog-watchlisthideanons": "Gøym endringar av anonyme brukarar i overvakingslista.",
"tog-watchlisthidepatrolled": "Gøym patruljerte endringar i overvakingslista",
+ "tog-watchlisthidecategorization": "Løyn sidekategoriseringa",
"tog-ccmeonemails": "Send meg kopi av e-postane eg sender til andre brukarar",
"tog-diffonly": "Ikkje vis sideinnhaldet under skilnadene mellom versjonane",
"tog-showhiddencats": "Vis gøymde kategoriar",
"october-date": "$1. oktober",
"november-date": "$1. november",
"december-date": "$1. desember",
+ "period-am": "f.m.",
+ "period-pm": "e.m.",
"pagecategories": "{{PLURAL:$1|Kategori|Kategoriar}}",
"category_header": "Artiklar i kategorien «$1»",
"subcategories": "Underkategoriar",
"morenotlisted": "Lista er ikkje heil.",
"mypage": "Sida mi",
"mytalk": "Diskusjon",
- "anontalk": "Diskusjonside for denne IP-adressa",
+ "anontalk": "Diskusjon",
"navigation": "Navigering",
"and": " og",
"qbfind": "Finn",
"noname": "Du har ikkje oppgjeve gyldig brukarnamn.",
"loginsuccesstitle": "Du er no innlogga",
"loginsuccess": "Du er no innlogga som «$1».",
- "nosuchuser": "Det finst ikkje nokon brukar med brukarnamnet «$1».\nBrukarnamn skil mellom stor og liten bokstav. Sjekk at du har skrive brukarnamet rett eller [[Special:UserLogin/signup|opprett ein ny konto]].",
+ "nosuchuser": "Det finst ikkje nokon brukar med brukarnamnet «$1».\nBrukarnamn skil mellom stor og liten bokstav. Sjekk at du har skrive brukarnamet rett eller [[Special:CreateAccount|opprett ein ny konto]].",
"nosuchusershort": "Det finst ikkje nokon brukar med brukarnamnet «$1». Sjekk at du har skrive rett.",
"nouserspecified": "Du må oppgje eit brukarnamn.",
"login-userblocked": "Denne brukaren er blokkert. Innlogging er ikkje tillate.",
"accmailtext": "Eit tilfeldig laga passord for [[User talk:$1|$1]] er sendt til $2.\n\nPassordet for den nye kontoen kan verta endra på ''[[Special:ChangePassword|endra passord]]''-sida etter innlogging.",
"newarticle": "(Ny)",
"newarticletext": "Du har følgt ei lenkje til ei side som ikkje finst enno.\nFor å opprette sida, kan du skrive i boksen under (sjå [$1 hjelpesida] for meir informasjon).\nHamna du her ved ein feil, klikk på '''attende'''-knappen i nettlesaren din.",
- "anontalkpagetext": "----''Dette er ei diskusjonsside for ein anonym brukar som ikkje har oppretta konto eller ikkje har logga inn.\nVi er difor nøydde til å bruke den numeriske IP-adressa til å identifisere brukaren. Same IP-adresse kan vere knytt til fleire brukarar. Om du er ein anonym brukar og meiner at du har fått irrelevante kommentarar på ei slik side, [[Special:UserLogin/signup|opprett ein brukarkonto]] eller [[Special:UserLogin|logg inn]] slik at vi unngår framtidige forvekslingar med andre anonyme brukarar.''",
+ "anontalkpagetext": "----''Dette er ei diskusjonsside for ein anonym brukar som ikkje har oppretta konto eller ikkje har logga inn.\nVi er difor nøydde til å bruke den numeriske IP-adressa til å identifisere brukaren. Same IP-adresse kan vere knytt til fleire brukarar. Om du er ein anonym brukar og meiner at du har fått irrelevante kommentarar på ei slik side, [[Special:CreateAccount|opprett ein brukarkonto]] eller [[Special:UserLogin|logg inn]] slik at vi unngår framtidige forvekslingar med andre anonyme brukarar.''",
"noarticletext": "Det er nett no ikkje noko tekst på denne sida.\nDu kan [[Special:Search/{{PAGENAME}}|søkja etter sidetittelen]] i andre sider, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søkja i dei relaterte loggane]\neller [{{fullurl:{{FULLPAGENAME}}|action=edit}} endra denne sida]</span>.",
"noarticletext-nopermission": "Der er nett no ikkje noko tekst på denne sida.\nDu kan [[Special:Search/{{PAGENAME}}|søkja etter sidetittelen]] i andre sider\neller <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søkja i dei relaterte loggane]</span>, men du har ikkje løyve til å oppretta denne sida.",
"missing-revision": "Versjonen #$1 av sida med namnet «{{FULLPAGENAME}}» finst ikkje.\n\nDette skriv seg som oftast frå at ei forelda historikklenkje vart fylgd til ei side som er sletta.\nDetaljar kan ein finna i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} sletteloggen].",
"noname": "Gawa fana ka leina la mošomiši la go loka.",
"loginsuccesstitle": "O tsene ka katlego",
"loginsuccess": "'''Bjale o tsene go {{SITENAME}} bjalo ka \"$1\".'''",
- "nosuchuser": "Ga gona mošomiši wa leina la \"$1\".\nMaina a huduetša ke ditlhaka.\nLebele mopeleto wa gago goba [[Special:UserLogin/signup|o tlhome mošomiši yo mophsa]].",
+ "nosuchuser": "Ga gona mošomiši wa leina la \"$1\".\nMaina a huduetša ke ditlhaka.\nLebele mopeleto wa gago goba [[Special:CreateAccount|o tlhome mošomiši yo mophsa]].",
"nosuchusershort": "Ga gona mošomiši wa leina la \"$1\". Hlokomela mopeleto wa gago.",
"nouserspecified": "O swanela ke go fana ka leina la mošomiši.",
"wrongpassword": "O loketše ditlhaka-tša-siphiri tšeo e sego tšona. Ka kgopelo, leka gape.",
"tog-numberheadings": "Numerotar automaticament los títols",
"tog-showtoolbar": "Far veire la barra d'aisinas de modificacion (necessita JavaScript)",
"tog-editondblclick": "Modificar de paginas amb un clic doble (necessita JavaScript)",
- "tog-editsectiononrightclick": "Activar la modificacion de seccions en fasent un clic drech suls títols (necessita JavaScript)",
+ "tog-editsectiononrightclick": "Activar la modificacion de seccions en fasent un clic dreit suls títols (necessita JavaScript)",
"tog-watchcreations": "Apondre las paginas que creï e los fichièrs qu'impòrti a ma lista de seguiment",
"tog-watchdefault": "Apondre las paginas que modifiqui e los fichièrs qu'impòrti a ma lista de seguiment",
"tog-watchmoves": "Apondre las paginas e los fichièrs que tòrni nomenar a ma lista de seguiment",
"tog-uselivepreview": "Utilizar l’apercebut rapid",
"tog-forceeditsummary": "M'avertir quand ai pas completat lo contengut de la bóstia de comentaris",
"tog-watchlisthideown": "Amagar mas pròprias modificacions dins la lista de seguiment",
- "tog-watchlisthidebots": "Amagar los cambiaments faches pels bòts dins la lista de seguiment",
+ "tog-watchlisthidebots": "Amagar los cambiaments faits pels bòts dins la lista de seguiment",
"tog-watchlisthideminor": "Amagar las modificacions menoras dins la lista de seguiment",
"tog-watchlisthideliu": "Amaga, de la lista, las modificacions pels utilizaires connectats",
"tog-watchlisthideanons": "Amaga, de la lista, las modificacions anonimas",
"jumptosearch": "Recercar",
"view-pool-error": "O planhèm, los servidors son subrecargats pel moment.\nTròp d’utilizaires cercan a accedir a aquesta pagina.\nEsperatz un moment abans d'ensajar d’accedir a aquesta pagina.\n\n$1",
"generic-pool-error": "O planhèm, los servidors son subrecargats pel moment.\nTròp d’utilizaires ensajan de consultar aquesta ressorsa.\nEsperatz un moment abans d'ensajar d’accedir a aquesta pagina.",
- "pool-timeout": "Relambi depassat pendent l'espèra del varrolh",
+ "pool-timeout": "Relambi depassat pendent l'espèra del verrolh",
"pool-queuefull": "La fila de trabalh es plena",
"pool-errorunknown": "Error desconeguda",
"pool-servererror": "Lo servici de comptatge de la reserva es pas disponible ($1).",
"privacy": "Politica de confidencialitat",
"privacypage": "Project:Confidencialitat",
"badaccess": "Error de permission",
- "badaccess-group0": "Avètz pas los dreches sufisents per realizar l’accion que demandatz.",
+ "badaccess-group0": "Avètz pas los dreits sufisents per realizar l’accion que demandatz.",
"badaccess-groups": "L’accion qu'ensajatz de realizar es pas accessibla qu’als utilizaires {{PLURAL:$2|del grop|d´un d´aquestes gropes}}: $1.",
"versionrequired": "Version $1 de MediaWiki necessària",
"versionrequiredtext": "La version $1 de MediaWiki es necessària per utilizar aquesta pagina. Consultatz [[Special:Version|la pagina de las versions]]",
"nosuchspecialpage": "Pagina especiala inexistanta",
"nospecialpagetext": "<strong>Avètz demandat una pagina especiala qu'es pas reconeguda pel logicial {{SITENAME}}.</strong>\n\nUna lista de las paginas especialas pòt èsser trobada sus [[Special:SpecialPages|{{int:specialpages}}]].",
"error": "Error",
- "databaseerror": "Error de la banca de donadas",
- "databaseerror-text": "Una error de requèsta de banca de donadas s'es producha. Aquò pòt provenir d'un bug dins lo logicial.",
- "databaseerror-textcl": "Una error de requèsta de banca de donadas s'es produsida.",
+ "databaseerror": "Error de la basa de donadas",
+ "databaseerror-text": "Una error de requèsta de basa de donadas s'es produita. Aquò pòt provenir d'un bug dins lo logicial.",
+ "databaseerror-textcl": "Una error de requèsta de basa de donadas s'es produita.",
"databaseerror-query": "Requèsta : $1",
"databaseerror-function": "Foncion : $1",
"databaseerror-error": "Error : $1",
"laggedslavemode": "<strong>Atencion :</strong> Aquesta pagina pòt conténer pas totes los darrièrs cambiaments efectuats.",
- "readonly": "Mesas a jorn blocadas sus la banca de donadas",
- "enterlockreason": "Indicatz la rason del varrolhatge, e mai una estimacion de sa durada",
- "readonlytext": "Los ajustons e mesas a jorn de la banca de donadas son actualament blocats, probablament per permetre la mantenença de la banca, aprèp aquò, tot dintrarà dins l'òrdre.\n\nL’administrator qu'a varrolhat la banca de donadas a balhat l’explicacion seguenta : $1",
+ "readonly": "Mesas a jorn blocadas sus la basa de donadas",
+ "enterlockreason": "Indicatz la rason del verrolhatge, e mai una estimacion de sa durada",
+ "readonlytext": "Los empeutons e mesas a jorn de la basa de donadas son actualament blocats, probablament per permetre la mantenença de la basa, aprèp aquò, tot dintrarà dins l'òrdre.\n\nL’administrator qu'a verrolhat la basa de donadas a balhat l’explicacion seguenta :<br /> $1",
"missing-article": "La banca de donada a pas trobat lo tèxte d’una pagina qu’auriá degut trobar, intitolada « $1 » $2.\n\nAquò es, en principi, causat en seguissent lo ligam perimit d'un diff o de l’istoric cap a una pagina qu'es estada suprimida.\n\nS'es pas lo cas, belèu avètz trobat un bòg dins lo programa.\nInformatz-ne un [[Special:ListUsers/sysop|administrator]] aprèp aver notada l’adreça cibla del ligam.",
"missingarticle-rev": "(revision#: $1)",
"missingarticle-diff": "(Diff: $1, $2)",
- "readonly_lag": "La banca de donadas es estada automaticament clavada pendent que los servidors segondaris ratrapan lor retard sul servidor principal.",
+ "readonly_lag": "La basa de donadas es estada automaticament clavada pendent que los servidors segondaris ratrapan lor retard sul servidor principal.",
"internalerror": "Error intèrna",
"internalerror_info": "Error intèrna: $1",
"internalerror-fatal-exception": "Error fatala de tipe \"$1\"",
"no-null-revision": "Impossible de crear una novèla revision voida per la pagina « $1 »",
"badtitle": "Títol marrit",
"badtitletext": "Lo títol de la pagina demandada es invalid, void o s’agís d’un títol interlenga o interprojècte mal ligat. Benlèu conten un o maites caractèrs que pòdon pas èsser utilizats dins los títols.",
- "perfcached": "Las donadas seguendas son en escondedor e benlèu, son pas a jorn. Un maximum de {{PLURAL:$1|un resultat|$1 resultats}} es disponible dins l'escondedor.",
- "perfcachedts": "Las donadas seguendas son en escondedor e benlèu, son pas a jorn. Un maximum de {{PLURAL:$1|un resultat|$1 resultats}} es disponible dins l'escondedor.",
+ "perfcached": "Las donadas seguendas son en cache e benlèu, son pas a jorn. Un maximum de {{PLURAL:$1|un resultat|$1 resultats}} es disponible dins lo cache.",
+ "perfcachedts": "Las donadas seguendas son en cache e benlèu, son pas a jorn. Un maximum de {{PLURAL:$1|un resultat|$1 resultats}} es disponible dins lo cache.",
"querypage-no-updates": "Las mesas a jorn per aquesta pagina son actualamnt desactivadas. Las donadas çaijós son pas mesas a jorn.",
"viewsource": "Vejatz lo tèxte font",
"viewsource-title": "Veire la font de $1",
"namespaceprotected": "Avètz pas la permission de modificar las paginas de l’espaci de noms « '''$1''' ».",
"customcssprotected": "Avètz pas la permission d'editar aquesta pagina CSS perque conten de preferéncias d’autres utilizaires.",
"customjsprotected": "Avètz pas la permission d'editar aquesta pagina JavaScript perque conten de preferéncias d’autres utilizaires.",
- "mycustomcssprotected": "Avètz pas lo drech de modificar aquesta pagina CSS.",
- "mycustomjsprotected": "Avètz pas lo drech de modificar aquesta pagina JavaScript.",
- "myprivateinfoprotected": "Avètz pas los dreches per modificar vòstras informacions personalas.",
- "mypreferencesprotected": "Avètz pas los dreches per modificar vòstras preferéncias.",
+ "mycustomcssprotected": "Avètz pas lo dreit de modificar aquesta pagina CSS.",
+ "mycustomjsprotected": "Avètz pas lo dreit de modificar aquesta pagina JavaScript.",
+ "myprivateinfoprotected": "Avètz pas los dreits per modificar vòstras informacions personalas.",
+ "mypreferencesprotected": "Avètz pas los dreits per modificar vòstras preferéncias.",
"ns-specialprotected": "Las paginas dins l’espaci de noms « {{ns:special}} » pòdon pas èsser modificadas",
"titleprotected": "Aqueste títol es estat protegit a la creacion per [[User:$1|$1]].\nLo motiu avançat es <em>$2</em>.",
- "filereadonlyerror": "Impossible de modificar lo fichièr « $1 » perque lo repertòri de fichièrs « $2 » es en lectura sola.\n\nL'administrator que l'a varrolhat a provesit aqueste motiu : « $3 ».",
+ "filereadonlyerror": "Impossible de modificar lo fichièr « $1 » perque lo repertòri de fichièrs « $2 » es en lectura sola.\n\nL'administrator del sistèma que l'a verrolhat a provesit aqueste motiu : « $3 ».",
"invalidtitle-knownnamespace": "Títol invalid amb l'espaci de noms « $2 » e l'intitulat « $3 »",
"invalidtitle-unknownnamespace": "Títol invalid amb lo numèro d'espaci de noms $1 e l'intitulat « $2 » desconeguts",
"exception-nologin": "Pas connectat",
"exception-nologin-text": "[[Special:Userlogin|Connectatz-vos]] per poder accedir a aquesta pagina o aquesta accion.",
"exception-nologin-text-manual": "$1 per poder accedir a aquesta pagina o aquesta accion.",
"virus-badscanner": "Marrida configuracion : escaner de virús desconegut : ''$1''",
- "virus-scanfailed": "Fracàs de la recèrca (còde $1)",
+ "virus-scanfailed": "Fracàs de la recèrca (còdi $1)",
"virus-unknownscanner": "antivirús desconegut :",
"logouttext": "'''Ara, sètz desconnectat.'''\n\nNotatz que d'unas paginas pòdon èsser encara afichadas coma s'eratz encara connectat, fins al moment qu'escafaretz l'escondedor de vòstre navigador.",
"cannotlogoutnow-title": "Impossible de se desconnectar ara",
"cannotloginnow-title": "Impossible de se connectar ara",
"yourdomainname": "Vòstre domeni",
"password-change-forbidden": "Podètz pas modificar los senhals sus aqueste wiki.",
- "externaldberror": "Siá una error s’es producha amb la banca de donadas d’autentificacion extèrna, siá sètz pas autorizat a metre a jorn vòstre compte extèrne.",
+ "externaldberror": "Siá una error s’es produita amb la basa de donadas d’autentificacion extèrna, siá sètz pas autorizat a metre a jorn vòstre compte extèrne.",
"login": "Identificacion",
"nav-login-createaccount": "Crear un compte o se connectar",
"userlogin": "Crear un compte o se connectar",
"createacct-reason-ph": "Perqué creatz un autre compte",
"createacct-submit": "Creatz vòstre compte",
"createacct-another-submit": "Crear un compte",
- "createacct-benefit-heading": "{{SITENAME}} es escrich per de monde coma vos.",
+ "createacct-benefit-heading": "{{SITENAME}} es escrit per de monde coma vos.",
"createacct-benefit-body1": "{{PLURAL:$1|cambiament|cambiaments}}",
"createacct-benefit-body2": "{{PLURAL:$1|pagina|paginas}}",
"createacct-benefit-body3": "{{PLURAL:$1|contributor recent|contributors recents}}",
"noname": "Avètz pas picat de nom d'utilizaire valid.",
"loginsuccesstitle": "Identificacion capitada.",
"loginsuccess": "Sètz actualament connectat(ada) sus {{SITENAME}} en tant que « $1 ».",
- "nosuchuser": "L'utilizaire « $1 » existís pas.\nLo nom d'utilizaire es sensible a la cassa.\nVerificatz qu'avètz plan ortografiat lo nom, o [[Special:UserLogin/signup|creatz-vos un compte novèl]].",
+ "nosuchuser": "L'utilizaire « $1 » existís pas.\nLo nom d'utilizaire es sensible a la cassa.\nVerificatz qu'avètz plan ortografiat lo nom, o [[Special:CreateAccount|creatz-vos un compte novèl]].",
"nosuchusershort": "I a pas de contributor amb lo nom « $1 ». Verificatz l’ortografia.",
"nouserspecified": "Vos cal especificar vòstre nom d'utilizaire.",
"login-userblocked": "Aqueste utilizaire es blocat. Connexion pas autorizada.",
"login-throttled": "Avètz ensajat un tròp grand nombre de connexions darrièrament.\nEsperatz $1 abans d’ensajar tornarmai.",
"login-abort-generic": "Vòstra temptativa de connexion a fracassat",
"loginlanguagelabel": "Lenga: $1",
- "suspicious-userlogout": "Vòstra demanda de desconnexion es estada refusada perque sembla qu’es estada mandada per un navigador copat o la mesa en escondedor d’un proxy.",
+ "suspicious-userlogout": "Vòstra demanda de desconnexion es estada refusada perque sembla qu’es estada mandada per un navigador copat o la mesa en cache d’un proxy.",
"createacct-another-realname-tip": "Lo nom vertadièr es opcional.\nSe decidissètz de lo provesir, serà utilizat per atribuir a l’utilizaire sos trabalhs.",
"pt-login": "Se connectar",
"pt-login-button": "Se connectar",
"resetpass-submit-cancel": "Anullar",
"resetpass-wrong-oldpass": "Senhal actual o temporari invalid.\nBenlèu ja avètz modificat vòstre senhal o demandat un senhal temporari novèl.",
"resetpass-recycled": "Reïnicializatz vòstre senhal a quicòm mai que l’actual.",
- "resetpass-temp-emailed": "Sètz connect{{GENDER:|at|ada}} amb un còde temporari provesit per corrièr electronic.\nPer acabar la connexion, vos cal provesir un senhal novèl aicí :",
+ "resetpass-temp-emailed": "Sètz connect{{GENDER:|at|ada}} amb un còdi temporari provesit per corrièr electronic.\nPer acabar la connexion, vos cal provesir un senhal novèl aicí :",
"resetpass-temp-password": "Senhal temporari :",
"resetpass-abort-generic": "La modificacion del senhal es estada anulada per una extension.",
"resetpass-expired": "Vòstre senhal a expirat. Provesissètz-ne un novèl per vos connectar.",
"changeemail-none": "(pas cap)",
"changeemail-password": "Vòstre senhal sus {{SITENAME}} :",
"changeemail-submit": "Cambiar l'adreça electronica:",
- "changeemail-throttled": "Avètz fach tròp de temptativas de connexion.\nEsperatz $1 abans d’ensajar tornarmai.",
+ "changeemail-throttled": "Avètz fait tròp de temptativas de connexion.\nEsperatz $1 abans d’ensajar tornarmai.",
"resettokens": "Reïnicializar los getons",
"resettokens-text": "Aici, podètz reïnicializar los getons que permeton d’accedir a d'unas donadas privadas associadas a vòstre compte.\n\nLo vos caldriá far se las avètz partejats accidentalament amb qualqu'un o se vòstre compte es estat compromés.",
"resettokens-no-tokens": "I a pas cap de geton de reïnicializar.",
"blankarticle": "<strong>Atencion :</strong> La pagina que creatz es voida.\nSe clicatz tornarmai sus « {{int:savearticle}} », la pagina serà creada sens cap de contengut.",
"anoneditwarning": "<strong>Atencion :<strong> sètz pas connectat.\nVòstra adreça IP serà visibla per tot lo monde se fasètz de modificacions. Se <strong>[$1 vos connectatz]</strong> o <strong>[$2 creatz un compte]</strong>, vòstras modificacions seràn atribuidas a vòstre nom d’utilizaire, entre autres avantatges.",
"anonpreviewwarning": "''Sètz pas identificat. Salvar enregistrarà vòstra adreça IP dins l’istoric de las modificacions de la pagina.''",
- "missingsummary": "'''Atencion :''' avètz pas modificat lo resumit de vòstra modificacion. Se clicatz tornarmai sul boton « Salvar », lo salvament serà fach sens avertiment mai.",
+ "missingsummary": "'''Atencion :''' avètz pas modificat lo resumit de vòstra modificacion. Se clicatz tornarmai sul boton « Salvar », lo salvament serà fait sens avertiment mai.",
"missingcommenttext": "Mercé de metre un comentari çaijós.",
- "missingcommentheader": "'''*Rampèl:''' Avètz pas escrich de títol per aqueste comentari. Se tornatz clicar sus \"{{*int:*savearticle}}\" serà enregistrat sens títol.",
+ "missingcommentheader": "<strong>Rapèl :</strong> Avètz pas provesit cap de subjècte per aqueste comentari.\nSe clicatz tornamai sus « {{int:Savearticle}} », vòstra modificacion serà enregistrada sens subjècte.",
"summary-preview": "Previsualizacion del resumit :",
"subject-preview": "Previsualizacion del subjècte",
"blockedtitle": "L'utilizaire es blocat",
"accmailtext": "Un senhal generat aleatòriament per [[User talk:$1|$1]] es estat mandat a $2.\nLo senhal per aqueste compte novèl pòt èsser cambiat sus la pagina ''[[Special:ChangePassword|Cambiament de senhal]]'' aprèp s'èsser connectat.",
"newarticle": "(Novèl)",
"newarticletext": "Avètz seguit un ligam cap a una pagina qu’existís pas encara o qu'es estada [{{fullurl:Special:Log|type=delete&page={{FULLPAGENAMEE}}}} escafada].\nPer crear aquesta pagina, picatz vòstre tèxte dins la bóstia çaijós (podètz consultar [$1 la pagina d’ajuda] per mai d’entresenhas).\nSe sètz arribat(ada) aicí per error, clicatz sul boton '''retorn''' de vòstre navigador.",
- "anontalkpagetext": "---- ''Sètz sus la pagina de discussion d'un utilizaire anonim qu'a pas encara creat un compte o que n'utiliza pas.\nPer aquesta rason, devèm utilizar son adreça IP per l'identificar. Una adreça d'aqueste tipe pòt èsser partejada entre mantun utilizaire. Se sètz un utilizaire anonim e se constatatz que de comentaris que vos concernisson pas vos son estats adreçats, podètz [[Special:UserLogin/signup|crear un compte]] o [[Special:UserLogin|vos connectar]] per evitar tota confusion venenta amb d’autres contributors anonims.''",
+ "anontalkpagetext": "---- ''Sètz sus la pagina de discussion d'un utilizaire anonim qu'a pas encara creat un compte o que n'utiliza pas.\nPer aquesta rason, devèm utilizar son adreça IP per l'identificar. Una adreça d'aqueste tipe pòt èsser partejada entre mantun utilizaire. Se sètz un utilizaire anonim e se constatatz que de comentaris que vos concernisson pas vos son estats adreçats, podètz [[Special:CreateAccount|crear un compte]] o [[Special:UserLogin|vos connectar]] per evitar tota confusion venenta amb d’autres contributors anonims.''",
"noarticletext": "Pel moment, i a pas cap de tèxte sus aquesta pagina ;\npodètz [[Special:Search/{{PAGENAME}}|aviar una recèrca sul títol d'aqueste títol de pagina]] dins las autras pagina,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} recercar dins las operacions ligadas]\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} crear aquesta pagina]</span>.",
"noarticletext-nopermission": "Actualament i a pas cap de tèxte dins aquesta pagina.\nPodètz [[Special:Search/{{PAGENAME}}|far una recèrca sul títol de la pagina]] dins las autras paginas,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} recercar dins los jornals associats]</span>.",
- "missing-revision": "La revision n° $1 de la pagina intitulada « {{FULLPAGENAME}} » existís pas.\n\nAquò se produsís en general en seguent un ligam istoric obsolèt cap a una pagina qu'es estada suprimida.\nPodètz trobar mai de detalhs dins lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornal de las supressions].",
+ "missing-revision": "La revision n° $1 de la pagina intitulada « {{FULLPAGENAME}} » existís pas.\n\nAquò se produtz en general en seguent un ligam istoric obsolèt cap a una pagina qu'es estada suprimida.\nPodètz trobar mai de detalhs dins lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornal de las supressions].",
"userpage-userdoesnotexist": "Lo compte d'utilizaire « <nowiki>$1</nowiki> » es pas enregistrat. Indicatz se volètz crear o editar aquesta pagina.",
"userpage-userdoesnotexist-view": "Lo compte d'utilizaire « $1 » es pas enregistrat.",
"blocked-notice-logextract": "Aqueste utilizaire es actualament blocat.\nLa darrièra entrada del jornal dels blocatges es indicada çaijós a títol d’informacion :",
"usercssyoucanpreview": "'''Astúcia :''' Utilizatz lo boton 'Previsualizacion' per testar vòstre fuèlh css/js novèl abans de l'enregistrar.",
"userjsyoucanpreview": "'''Astúcia :''' Utilizatz lo boton 'Previsualizacion' per testar vòstre fuèlh css/js novèl abans de l'enregistrar.",
"usercsspreview": "'''Remembratz-vos que sètz a previsualizar vòstre pròpri fuèlh CSS !'''\n'''Es pas estada encara enregistrada !'''",
- "userjspreview": "'''Remembratz-vos que sètz a visualizar o testar vòstre còde JavaScript e qu’es pas encara estat enregistrat !'''",
+ "userjspreview": "'''Remembratz-vos que sètz a visualizar o testar vòstre còdi JavaScript e qu’es pas encara estat enregistrat !'''",
"sitecsspreview": "'''Remembratz-vos que sètz a previsualizar vòstre pròpri fuèlh CSS !'''\n'''Es pas estada encara enregistrada !'''",
- "sitejspreview": "'''Remembratz-vos que sètz a visualizar o testar vòstre còde JavaScript e qu’es pas encara estat enregistrat !'''",
+ "sitejspreview": "'''Remembratz-vos que sètz a visualizar o testar vòstre còdi JavaScript e qu’es pas encara estat enregistrat !'''",
"userinvalidcssjstitle": "'''Atencion :''' existís pas d'estil « $1 ». Remembratz-vos que las paginas personalas amb extensions .css e .js utilizan de títols en minusculas, per exemple, {{ns:user}}:Foo/vector.css e non pas {{ns:user}}:Foo/Vector.css.",
"updated": "(Mes a jorn)",
"note": "'''Nòta :'''",
"explainconflict": "Aqueste pagina es estada salvada aprèp qu'avètz començat de la modificar.\nLa zòna d'edicion superiora conten lo tèxte tal coma es enregistrat actualament dins la banca de donadas.\nVòstras modificacions apareisson dins la zòna d'edicion inferiora.\nVos va caler aportar vòstras modificacions al tèxte existent.\n'''Sol''' lo tèxte de la zòna superiora serà salvat.",
"yourtext": "Vòstre tèxte",
"storedversion": "Version enregistrada",
- "nonunicodebrowser": "'''Atencion : Vòstre navigador supòrta pas l’unicode. Una solucion temporària es estada trobada per vos permetre de modificar un article en tota seguretat : los caractèrs non-ASCII apareisseràn dins vòstra bóstia de modificacion en tant que còdes exadecimals. Deuriatz utilizar un navigador mai recent.'''",
+ "nonunicodebrowser": "'''Atencion : Vòstre navigador supòrta pas l’unicode. Una solucion temporària es estada trobada per vos permetre de modificar un article en tota seguretat : los caractèrs non-ASCII apareisseràn dins vòstra bóstia de modificacion en tant que còdis exadecimals. Deuriatz utilizar un navigador mai recent.'''",
"editingold": "'''Atencion : sètz a modificar una version obsolèta d'aquesta pagina. Se salvatz, totas las modificacions efectuadas dempuèi aquesta version seràn perdudas.'''",
"yourdiff": "Diferéncias",
- "copyrightwarning": "Totas las contribucions a {{SITENAME}} son consideradas coma publicadas jols tèrmes de la $2 (vejatz $1 per mai de detalhs). Se desiratz pas que vòstres escriches sián modificats e distribuits a volontat, mercés de los sometre pas aicí.<br /> Nos prometètz tanben qu'avètz escrich aquò vos-meteis, o que l’avètz copiat d’una font provenent del domeni public, o d’una ressorsa liura.'''UTILIZETZ PAS DE TRABALHS JOS COPYRIGHT SENS AUTORIZACION EXPRÈSSA !'''",
- "copyrightwarning2": "Totas las contribucions a {{SITENAME}} pòdon èsser modificadas o suprimidas per d’autres utilizaires. Se desiratz pas que vòstres escriches sián modificats e distribuits a volontat, mercés de los sometre pas aicí.<br /> Tanben nos prometètz qu'avètz escrich aquò vos-meteis, o que l’avètz copiat d’una font provenent del domeni public, o d’una ressorsa liura. (vejatz $1 per mai de detalhs). '''UTILIZETZ PAS DE TRABALHS JOS COPYRIGHT SENS AUTORIZACION EXPRÈSSA !'''",
+ "copyrightwarning": "Totas las contribucions a {{SITENAME}} son consideradas coma publicadas jols tèrmes de la $2 (vejatz $1 per mai de detalhs). Se desiratz pas que vòstres escrits sián modificats e distribuits a volontat, mercés de los sometre pas aicí.<br /> Nos prometètz tanben qu'avètz escrit aquò vos-meteis, o que l’avètz copiat d’una font provenent del domeni public, o d’una ressorsa liura.'''UTILIZETZ PAS DE TRABALHS JOS COPYRIGHT SENS AUTORIZACION EXPRÈSSA !'''",
+ "copyrightwarning2": "Totas las contribucions a {{SITENAME}} pòdon èsser modificadas o suprimidas per d’autres utilizaires. Se desiratz pas que vòstres escrits sián modificats e distribuits a volontat, mercés de los sometre pas aicí.<br /> Tanben nos prometètz qu'avètz escrit aquò vos-meteis, o que l’avètz copiat d’una font provenent del domeni public, o d’una ressorsa liura. (vejatz $1 per mai de detalhs). '''UTILIZETZ PAS DE TRABALHS JOS COPYRIGHT SENS AUTORIZACION EXPRÈSSA !'''",
"longpageerror": "'''ERROR : Lo tèxte qu'avètz somés fa {{PLURAL:$1|un Kio|$1 Kio}}, çò que depassa lo limit fixat a {{PLURAL:$2|un Kio|$2 Kio}}.'''. Pòt pas èsser salvat.",
- "readonlywarning": "'''AVERTIMENT : La banca de donadas es estada varrolhada per d'operacions de mantenença. Doncas, poiretz pas publicar vòstras modificacions pel moment.'''\nPodètz copiar e pegar vòstre tèxte dins un fichièr de tèxte e lo salvar per mai tard.\n\nL’administrator qu'a varrolhat la banca de donadas a balhat l’explicacion seguenta : $1",
+ "readonlywarning": "<strong>AVERTIMENT : La basa de donadas es estada verrolhada per d'operacions de mantenença. Doncas, poiretz pas publicar vòstras modificacions pel moment.</strong>\nL’administrator sistèma qu'an verrolhada la basa de donadas a donat l’explicacion seguenta : $1",
"protectedpagewarning": "'''AVERTIMENT : Aquesta pagina es protegida. Sols los utilizaires qu'an l'estatut d'administrator la p�don modificar. ''' La darri�ra entrada del jornal es afichada �aij�s per refer�ncia :",
"semiprotectedpagewarning": "'''N�ta:''' Aquesta pagina es estada protegida d'un tal biais que sols los contributors enregistrats la p�scan modificar. La darri�ra entrada del jornal es afichada �aij�s per refer�ncia :",
"cascadeprotectedwarning": "'''ATENCION :''' Aquesta pagina es estada protegida de biais que sols los administrators pòscan l’editar.\nAquesta proteccion es estada facha perque aquesta pagina es inclusa dins {{PLURAL:$1|una pagina protegida|de paginas protegidas}} amb la « proteccion en cascada » activada.",
- "titleprotectedwarning": "'''ATENCION : Aquesta pagina es estada protegida de tal biais que de [[Special:ListGroupRights|dreches especifics]] son requesits per la poder crear.''' La darri�ra entrada del jornal es afichada �aij�s per refer�ncia :",
+ "titleprotectedwarning": "'''ATENCION : Aquesta pagina es estada protegida de tal biais que de [[Special:ListGroupRights|dreits especifics]] son requesits per la poder crear.''' La darrièra entrada del jornal es afichada çaijós per referéncia :",
"templatesused": "{{PLURAL:$1|Modèl utilizat|Modèls utilizats}} sus aquesta pagina :",
"templatesusedpreview": "{{PLURAL:$1|Modèl utilizat|Modèls utilizats}} dins aquesta previsualizacion :",
"templatesusedsection": "{{PLURAL:$1|Modèl utilizat|Modèls utilizats}} dins aquesta seccion :",
"template-semiprotected": "(semiprotegit)",
"hiddencategories": "{{PLURAL:$1|Categoria amagada|Categorias amagadas}} qu'aquesta pagina ne fa partida :",
"edittools": "<!-- Tot tèxte picat aicí serà afichat jos las bóstias de modificacion o d’impòrt de fichièr. -->",
- "nocreatetext": "{{SITENAME}} a restrencha la possibilitat de crear de paginas novèlas.\nPodètz tonar en rèire e modificar una pagina existenta, [[Special:UserLogin|vos connectar o crear un compte]].",
+ "nocreatetext": "{{SITENAME}} a restrenta la possibilitat de crear de paginas novèlas.\nPodètz tonar en rèire e modificar una pagina existenta, [[Special:UserLogin|vos connectar o crear un compte]].",
"nocreate-loggedin": "Avètz pas la permission de crear de paginas novèlas.",
"sectioneditnotsupported-title": "Modificacion de seccion pas presa en carga",
"sectioneditnotsupported-text": "La modificacion d'una seccion es pas suportada dins aquesta pagina de modificacion.",
"edit-hook-aborted": "Modificacion fracassada per croquet.\nCap d'explicacion pas balhada.",
"edit-gone-missing": "A pas pogut metre a jorn la pagina.\nSembla que siá estada suprimida.",
"edit-conflict": "Modificar lo conflicte.",
- "edit-no-change": "Vòstra modificacion es estada ignorada perque cap de cambiament es pas estat fach dins lo tèxte.",
+ "edit-no-change": "Vòstra modificacion es estada ignorada perque cap de cambiament es pas estat fait dins lo tèxte.",
"postedit-confirmation-created": "La pagina es estada creada.",
"postedit-confirmation-restored": "La pagina es estada restablida.",
"postedit-confirmation-saved": "Vòstra modificacion es estada salvada.",
"content-failed-to-parse": "Fracàs de l'analisi del contengut de $2 pel modèl $1: $3",
"invalid-content-data": "Donadas del contengut invalidas",
"content-not-allowed-here": "Lo contengut \"$1\" es pas autorizat sus la pagina [[$2]]",
- "editwarning-warning": "Quitar aquesta pagina vos farà pèrdre totas las modificacions qu'avètz fachas.\nSe sètz connectat, podètz desactivar aqueste avertiment dins la seccion « {{int:prefs-editing}} » de vòstras preferéncias.",
+ "editwarning-warning": "Quitar aquesta pagina vos farà pèrdre totas las modificacions qu'avètz faitas.\nSe sètz connectat, podètz desactivar aqueste avertiment dins la seccion « {{int:prefs-editing}} » de vòstras preferéncias.",
"editpage-notsupportedcontentformat-title": "Format de contengut pas pres en carga",
"editpage-notsupportedcontentformat-text": "Lo format de contengut $1 es pas pres en carga pel modèl de contengut $2 .",
"content-model-wikitext": "wikitèxte",
"expensive-parserfunction-category": "Paginas amb tròp d’apèls dispendioses de foncions parsaires",
"post-expand-template-inclusion-warning": "Atencion : Aquesta pagina conten tròp d'inclusions de modèls.\nD'unas inclusions seràn pas efectuadas.",
"post-expand-template-inclusion-category": "Paginas que contenon tròp d'inclusions de modèls",
- "post-expand-template-argument-warning": "Atencion : Aquesta pagina conten al mens un paramètre de modèl que l'inclusion es renduda impossibla. Aprèp extension, aqueste auriá produch un resultat tròp long, doncas, es pas estat inclut.",
+ "post-expand-template-argument-warning": "Atencion : Aquesta pagina conten al mens un paramètre de modèl que l'inclusion es renduda impossibla. Aprèp extension, aqueste auriá produit un resultat tròp long, doncas, es pas estat inclús.",
"post-expand-template-argument-category": "Paginas que contenon al mens un paramètre de modèl pas evaluat",
"parser-template-loop-warning": "Modèl en bocla detectat : [[$1]]",
"parser-template-recursion-depth-warning": "Limit de longor de la recursion del modèl depassat ($1)",
"parser-unstrip-loop-warning": "Bocla pas desmontabla detectada",
"parser-unstrip-recursion-limit": "Limit de recursion pas desmontable depassat ($1)",
"converter-manual-rule-error": "Error detectada dins la règla manuala de conversion de lenga",
- "undo-success": "Aquesta modificacion va èsser desfacha. Confirmatz los cambiaments (visibles en bas d'aquesta pagina), puèi salvatz se sètz d’acòrdi. Mercés de motivar l’anullacion dins la bóstia de resumit.",
- "undo-failure": "Aquesta modificacion a pas pogut èsser desfacha a causa de conflictes amb de modificacions intermediàrias.",
- "undo-norev": "La modificacion a pas pogut èsser desfacha perque siá es inexistenta siá es estada suprimida.",
+ "undo-success": "Aquesta modificacion va èsser desfaita. Confirmatz los cambiaments (visibles en bas d'aquesta pagina), puèi salvatz se sètz d’acòrdi. Mercés de motivar l’anullacion dins la bóstia de resumit.",
+ "undo-failure": "Aquesta modificacion a pas pogut èsser desfaita a causa de conflictes amb de modificacions intermediàrias.",
+ "undo-norev": "La modificacion a pas pogut èsser desfaita perque siá es inexistenta siá es estada suprimida.",
"undo-nochange": "Sembla que la modificacion es ja estada anullada.",
"undo-summary": "Anullacion de las modificacions $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|discutir]] | [[Special:Contributions/$2|{{MediaWiki:Contribslink}}]])",
"undo-summary-username-hidden": "Anullar la revision $1 per un utilizaire amagat",
"pagehist": "Istoric de la pagina",
"deletedhist": "Istoric de las supressions",
"revdelete-hide-current": "Error al moment de la supression de l'element datat del $1 e $2 : es la revision correnta.\nPòt pas èsser suprimit.",
- "revdelete-show-no-access": "Error al moment de l'afichatge de l'element datat del $1 e $2 : es marcat coma « restrench ».\nI avètz pas accès.",
- "revdelete-modify-no-access": "Error al moment de la modificacion de l'element datat del $1 a $2 : es marcat coma « restrench ».\nI avètz pas accès.",
- "revdelete-modify-missing": "Error al moment de la modificacion de l'element amb l'ID $1 : es mancant dins la banca de donadas !",
+ "revdelete-show-no-access": "Error al moment de l'afichatge de l'element datat del $1 e $2 : es marcat coma « restrent ».\nI avètz pas accès.",
+ "revdelete-modify-no-access": "Error al moment de la modificacion de l'element datat del $1 a $2 : es marcat coma « restrent ».\nI avètz pas accès.",
+ "revdelete-modify-missing": "Error al moment de la modificacion de l'element amb l'ID $1 : es mancant dins la basa de donadas !",
"revdelete-no-change": "'''Atencion :''' l'element datat del $1 a $2 ja a los paramètres de visibilitat demandats.",
"revdelete-concurrent-change": "Error al moment de la modificacion de l'element datat del $1 a $2 : son estatut es estat cambiat per qualqu'un mai pendent qu'o modificatz.\nVerificatz los jornals.",
"revdelete-only-restricted": "Error al moment de la supression de l'entrada datada del $1 a $2 : podètz pas suprimir aqueles elements als administrators sens seleccionar tanben d'opcions de supression mai.",
- "revdelete-reason-dropdown": "* Rasons correntas de supression\n** Violacion dels dreches d'autors\n** Entresenhas personalas inapropriadas\n** Nom d'utilizaire inapropriat\n** Informacions potencialament difamatòrias.",
+ "revdelete-reason-dropdown": "* Rasons correntas de supression\n** Violacion dels dreits d'autors\n** Entresenhas personalas inapropriadas\n** Nom d'utilizaire inapropriat\n** Informacions potencialament difamatòrias.",
"revdelete-otherreason": "Autra rason / rason suplementària :",
"revdelete-reasonotherlist": "Autra rason",
"revdelete-edit-reasonlist": "Modifica los motius de la supression",
"powersearch-remember": "Se remembrar de la seleccion per las recèrcas venentas",
"search-external": "Recèrca extèrna",
"searchdisabled": "La recèrca sus {{SITENAME}} es desactivada.\nEn esperant la reactivacion, podètz efectuar una recèrca via Google.\nAtencion, lor indexacion de contengut {{SITENAME}} benlèu es pas a jorn.",
- "search-error": "Una error s'es producha en recercant : $1",
+ "search-error": "Una error s'es produita en recercant : $1",
"preferences": "Preferéncias",
"mypreferences": "Preferéncias",
"prefs-edits": "Nombre d’edicions :",
"prefs-custom-css": "CSS personalizat",
"prefs-custom-js": "JS personalizat",
"prefs-common-css-js": "JavaScript e CSS partejat per totes los abilhatges :",
- "prefs-reset-intro": "Podètz utilizar aquesta pagina per restablir vòstras preferéncias a las valors per defaut del site. Aquò pòt pas èsser desfach.",
+ "prefs-reset-intro": "Podètz utilizar aquesta pagina per restablir vòstras preferéncias a las valors per defaut del site. Aquò pòt pas èsser desfait.",
"prefs-emailconfirm-label": "Confirmacion del corrièr electronic :",
"youremail": "Adreça de corrièr electronic :",
"username": "{{GENDER:$1|Nom d'utilizaire|Nom d'utilizaira}}:",
"prefs-help-signature": "Los comentaris sus las paginas de discussion devon èsser signats amb « <nowiki>~~~~</nowiki> », que serà convertit en vòstra signatura e un orodatament.",
"badsig": "Signatura bruta incorrècta, verificatz vòstras balisas HTML.",
"badsiglength": "Vòstra signatura es tròp longa.\nDeu aver, al maximum $1 caractèr{{PLURAL:$1||s}}.",
- "yourgender": "Cossí vos agrada mai èsser descrich ?",
+ "yourgender": "Cossí vos agrada mai d'èsser descrit ?",
"gender-unknown": "M'agrada mai sens detalh",
"gender-male": "Modifica de pagina del wiki",
"gender-female": "Modifica de paginas del wiki",
"prefs-tokenwatchlist": "Geton",
"prefs-diffs": "Diferéncias",
"prefs-help-prefershttps": "Aquesta preferéncia serà efectiva al moment de vòstra connexion que ven.",
- "prefs-tabs-navigation-hint": "Astúcia : Podètz utilizar las flèchas d'esquèrra e de drecha per navigar entre los onglets.",
- "userrights": "Gestion dels dreches d'utilizaire",
- "userrights-lookup-user": "Gestion dels dreches d'utilizaire",
+ "prefs-tabs-navigation-hint": "Astúcia : Podètz utilizar las sagetas d'esquèrra e de dreita per navigar entre los onglets.",
+ "userrights": "Gestion dels dreits d'utilizaire",
+ "userrights-lookup-user": "Gestion dels dreits d'utilizaire",
"userrights-user-editname": "Entrar un nom d’utilizaire :",
"editusergroup": "Modificacion dels gropes d’{{GENDER:$1|utilizaires}}",
- "editinguser": "Modificacion dels dreches de l’{{GENDER:$1|utilizaire|utilizaira}} <strong>[[User:$1|$1]]</strong> $2",
+ "editinguser": "Modificacion dels dreits de l’{{GENDER:$1|utilizaire|utilizaira}} <strong>[[User:$1|$1]]</strong> $2",
"userrights-editusergroup": "Modificar los gropes de l’utilizaire",
"saveusergroups": "Enregistrar los gropes de l’{{GENDER:$1|utilizaire|utilizaira}}",
"userrights-groupsmember": "Membre de :",
"userrights-groupsmember-auto": "Membre implicit de :",
"userrights-groups-help": "Podètz modificar los gropes alsquals aparten aqueste utilizaire.\n* Una casa marcada significa que l'utilizaire se tròba dins aqueste grop.\n* Una casa pas marcada significa, al contrari, que s’i tròba pas.\n* Una * indica que podretz pas levar aqueste grop un còp que l'auretz apondut e vice-versa.",
"userrights-reason": "Motiu :",
- "userrights-no-interwiki": "Sètz pas abilitat per modificar los dreches dels utilizaires sus d'autres wikis.",
- "userrights-nodatabase": "La banca de donadas « $1 » existís pas o es pas en local.",
- "userrights-nologin": "Vos cal [[Special:UserLogin|vos connectar]] amb un compte d'administrator per balhar los dreches d'utilizaire.",
- "userrights-notallowed": "Avètz pas la permission d'apondre o suprimir de dreches d'utilizaire.",
+ "userrights-no-interwiki": "Sètz pas abilitat per modificar los dreits dels utilizaires sus d'autres wikis.",
+ "userrights-nodatabase": "La basa de donadas « $1 » existís pas o es pas en local.",
+ "userrights-nologin": "Vos cal [[Special:UserLogin|vos connectar]] amb un compte d'administrator per balhar los dreits d'utilizaire.",
+ "userrights-notallowed": "Avètz pas la permission d'apondre o suprimir de dreits d'utilizaire.",
"userrights-changeable-col": "Los gropes que podètz cambiar",
"userrights-unchangeable-col": "Los gropes que podètz pas cambiar",
- "userrights-conflict": "Conflicte de modificacion de dreches d'utilizaire ! Relegissètz e confirmatz vòstras modificacions.",
- "userrights-removed-self": "Avètz suprimit vòstres pròpris dreches corrèctament. Del còp, podètz pas mai accedir a aquela pagina.",
+ "userrights-conflict": "Conflicte de modificacion de dreits d'utilizaire ! Relegissètz e confirmatz vòstras modificacions.",
+ "userrights-removed-self": "Avètz suprimit vòstres pròpris dreits. Del còp, podètz pas mai accedir a aquesta pagina.",
"group": "Grop :",
"group-user": "Utilizaires",
"group-autoconfirmed": "Utilizaires enregistrats",
"right-editmyusercss": "Modificar vòstres pròpris fichièrs CSS utilizaire",
"right-editmyuserjs": "Modificar vòstres pròpris fichièrs JavaScript utilizaire",
"right-viewmywatchlist": "Afichar vòstra pròpria lista de seguiment",
- "right-editmywatchlist": "Modificar vòstra pròpria lista de seguiment. Remarcatz que certanas accions apondràn encara de paginas sens aqueste drech.",
+ "right-editmywatchlist": "Modificar vòstra pròpria lista de seguiment. Remarcatz que certanas accions apondràn encara de paginas sens aqueste dreit.",
"right-viewmyprivateinfo": "Veire vòstras donadas personalas (exemple adreça, nom vertadièr)",
"right-editmyprivateinfo": "Modificar vòstras donadas personalas (exemple adreça, nom vertadièr)",
"right-editmyoptions": "Modificar vòstras preferéncias",
"right-patrolmarks": "Veire los marcatges de susvelhança dins los darrièrs cambiaments",
"right-unwatchedpages": "Veire la lista de las paginas pas seguidas",
"right-mergehistory": "Fusionar los istorics de las paginas",
- "right-userrights": "Modificar totes los dreches d'un utilizaire",
- "right-userrights-interwiki": "Modificar los dreches d'utilizaires que son sus un autre wiki",
- "right-siteadmin": "Varrolhar e desvarrolhar la banca de donadas",
+ "right-userrights": "Modificar totes los dreits d'un utilizaire",
+ "right-userrights-interwiki": "Modificar los dreits d'utilizaires que son sus un autre wiki",
+ "right-siteadmin": "Verrolhar e desverrolhar la basa de donadas",
"right-override-export-depth": "Exportar las paginas en incluent las paginas ligadas fins a una prigondor de 5 nivèls",
"right-sendemail": "Mandar un corrièl als autres utilizaires",
"right-passwordreset": "Veire los corrièrs electronics de reïnicializacion dels senhals",
"right-applychangetags": "Aplicar [[Special:Tags|las balisas]] amb sas pròprias modificacions",
- "grant-generic": "ensemble de dreches « $1 »",
+ "grant-generic": "ensemble de dreits « $1 »",
"grant-blockusers": "Blocar e desblocar d'utilizaires",
"grant-patrol": "Marcar de paginas coma patrolhadas",
"newuserlogpage": "Istoric de las creacions de comptes",
"action-autopatrol": "aver vòstra modificacion marcada coma patrolhada",
"action-unwatchedpages": "veire la lista de las paginas pas susvelhadas",
"action-mergehistory": "fusionar l’istoric d'aquesta pagina",
- "action-userrights": "modificar totes los dreches d’utilizaire",
- "action-userrights-interwiki": "modificar los dreches d’utilizaire e los sus d’autres wikis",
- "action-siteadmin": "varrolhar o desvarrolhar la banca de donadas",
+ "action-userrights": "modificar totes los dreits d’utilizaire",
+ "action-userrights-interwiki": "modificar los dreits d’utilizaire e los sus d’autres wikis",
+ "action-siteadmin": "verrolhar o desverrolhar la basa de donadas",
"action-sendemail": "mandar corrièrs electronics",
"action-editmywatchlist": "modificar vòstra lista de seguiment",
"action-viewmywatchlist": "afichar vòstra pròpria lista de seguiment",
"filedesc": "Descripcion",
"fileuploadsummary": "Resumit :",
"filereuploadsummary": "Modificacions del fichièr :",
- "filestatus": "Estatut dels dreches d'autor :",
+ "filestatus": "Estatut dels dreits d'autor :",
"filesource": "Font :",
"ignorewarning": "Ignorar l’avertiment e salvar lo fichièr",
"ignorewarnings": "Ignorar los avertiments al moment de l’impòrt",
"hookaborted": "La modificacion qu'avètz ensajat de realizar es estada anullada per un croquet d'extension.",
"illegal-filename": "Lo nom del fichièr es pas autorizat.",
"overwrite": "Espotir un fichièr existent es pas autorizat.",
- "unknown-error": "Una error desconeguda s'es producha.",
+ "unknown-error": "Una error desconeguda s'es produita.",
"tmp-create-error": "Impossible de crear lo fichièr temporari.",
"tmp-write-error": "Error d'escritura del fichièr temporari.",
"large-file": "Los fichièrs importats deurián pas èsser mai gros que $1 ; aqueste fichièr fa $2.",
"copyuploaddisabled": "Mandadís de fichièr per URL desactivat.",
"uploaddisabledtext": "L'impòrt de fichièrs cap al servidor es desactivat.",
"php-uploaddisabledtext": "Lo telecargament de fichièrs es estat desactivat dins PHP. Verificatz l'opcion de configuracion file_uploads.",
- "uploadscripted": "Aqueste fichièr conten de còde HTML o un escript que poiriá èsser interpretat d'un biais incorrècte per un navigador Internet.",
+ "uploadscripted": "Aqueste fichièr conten de còdi HTML o un escript que poiriá èsser interpretat d'un biais incorrècte per un navigador Internet.",
"uploadscriptednamespace": "Aqueste fichièr SVG conten un espaci de noms '$1' pas autorizat.",
"uploadinvalidxml": "Lo XML dins lo fichièr importat a pas pogut èsser analisat.",
"uploadvirus": "Aqueste fichièr conten un virús ! Per mai de detalhs, consultatz : $1",
"upload-proto-error": "Protocòl incorrècte",
"upload-proto-error-text": "L’impòrt requerís d'URLs començant per <code>http://</code> o <code>ftp://</code>.",
"upload-file-error": "Error intèrna",
- "upload-file-error-text": "Una error intèrna s'es producha en volent crear un fichièr temporari sul servidor. Contactatz un [[Special:ListUsers/sysop|administrator del sistèma]].",
+ "upload-file-error-text": "Una error intèrna s'es produita en volent crear un fichièr temporari sul servidor. Contactatz un [[Special:ListUsers/sysop|administrator del sistèma]].",
"upload-misc-error": "Error d’impòrt desconeguda",
- "upload-misc-error-text": "Una error desconeguda s'es producha pendent l’impòrt.\nVerificatz que l’URL es valida e accessibla, puèi ensajatz tornamai.\nSe lo problèma persistís, contactatz un [[Special:ListUsers/sysop|administrator del sistèma]].",
+ "upload-misc-error-text": "Una error desconeguda s'es produita pendent l’impòrt.\nVerificatz que l’URL es valida e accessibla, puèi ensajatz tornamai.\nSe lo problèma persistís, contactatz un [[Special:ListUsers/sysop|administrator del sistèma]].",
"upload-too-many-redirects": "L'URL conten tròp de redireccions",
"upload-http-error": "Una error HTTP es intervenguda : $1",
"upload-copy-upload-invalid-domain": "La còpia dels telecargaments es pas disponibla dempuèi aqueste domeni.",
"backend-fail-readonly": "Lo supòrt d'emmagazinatge \"$1\" es actualament en lectura sola. La rason indicada es : \"$2\"",
"backend-fail-synced": "Lo fichièr \"$1\" es dins un estat incoerent dins los supòrts d'emmagazinatge intèrnes",
"backend-fail-connect": "Impossible de se connectar al supòrt d'emmagazinatge \"$1\".",
- "backend-fail-internal": "Una error desconeguda s'es producha dins lo supòrt d'emmagazinatge \"$1\".",
+ "backend-fail-internal": "Una error desconeguda s'es produita dins lo supòrt d'emmagazinatge \"$1\".",
"backend-fail-contenttype": "Impossible de determinar lo tipe de contengut del fichièr d'emmagazinar en \"$1\".",
"backend-fail-batchsize": "Lo supòrt d'emmagazinatge a provesit un lòt de $1 {{PLURAL:$1|operacion|operacions}} de fichièr ; lo limit es de $2 {{PLURAL:$2|operacion|operacions}}.",
- "backend-fail-usable": "Impossible de legir o d'escriure lo fichièr « $1 » en rason de dreches insufisents o repertòris/contenidors mancants.",
- "filejournal-fail-dbconnect": "Impossible de se connectar a la banca de donadas del jornal pel terminal d'emmagazinatge \"$1\".",
- "filejournal-fail-dbquery": "Impossible de metre a jorn la banca de donadas del jornal pel terminal d'emmagazinatge \"$1\".",
- "lockmanager-notlocked": "Impossible de desvarrolhar « $1 » ; es pas varrolhada.",
- "lockmanager-fail-closelock": "Impossible de tampar lo fichièr de varrolh per « $1 ».",
- "lockmanager-fail-deletelock": "Impossible de suprimir lo fichièr de varrolh per « $1 ».",
- "lockmanager-fail-acquirelock": "Impossible d'obténer lo fichièr de varrolh per « $1 ».",
- "lockmanager-fail-openlock": "Impossible de dobrir lo fichièr de varrolh per « $1 ».",
- "lockmanager-fail-releaselock": "Impossible de daissar anar lo fichièr de varrolh per « $1 ».",
- "lockmanager-fail-db-bucket": "Impossible de contactar pro de bancas de donadas de varrolhatge dins lo godet $1.",
- "lockmanager-fail-db-release": "Impossible de daissar anar los varrolhs sus la banca de donadas $1.",
- "lockmanager-fail-svr-acquire": "Impossible d'aquerir de varrolhs sul servidor $1.",
- "lockmanager-fail-svr-release": "Impossible de daissar anar los varrolhs sul servidor $1.",
- "zip-file-open-error": "Una error s'es producha al moment de la dobertura del fichièr ZIP per contraròtle.",
+ "backend-fail-usable": "Impossible de legir o d'escriure lo fichièr « $1 » en rason de dreits insufisents o repertòris/contenidors mancants.",
+ "filejournal-fail-dbconnect": "Impossible de se connectar a la basa de donadas del jornal pel terminal d'emmagazinatge \"$1\".",
+ "filejournal-fail-dbquery": "Impossible de metre a jorn la basa de donadas del jornal pel terminal d'emmagazinatge \"$1\".",
+ "lockmanager-notlocked": "Impossible de desverrolhar « $1 » ; es pas verrolhada.",
+ "lockmanager-fail-closelock": "Impossible de tampar lo fichièr de verrolh per « $1 ».",
+ "lockmanager-fail-deletelock": "Impossible de suprimir lo fichièr de verrolh per « $1 ».",
+ "lockmanager-fail-acquirelock": "Impossible d'obténer lo fichièr de verrolh per « $1 ».",
+ "lockmanager-fail-openlock": "Impossible de dobrir lo fichièr de verrolh per « $1 ».",
+ "lockmanager-fail-releaselock": "Impossible de daissar anar lo fichièr de verrolh per « $1 ».",
+ "lockmanager-fail-db-bucket": "Impossible de contactar pro de basas de donadas de verrolhatge dins lo godet $1.",
+ "lockmanager-fail-db-release": "Impossible de daissar anar los verrolhs sus la basa de donadas $1.",
+ "lockmanager-fail-svr-acquire": "Impossible d'aquerir de verrolhs sul servidor $1.",
+ "lockmanager-fail-svr-release": "Impossible de daissar anar los verrolhs sul servidor $1.",
+ "zip-file-open-error": "Una error s'es produita al moment de la dobertura del fichièr ZIP per contraròtle.",
"zip-wrong-format": "Lo fichièr especificat es pas un archiu ZIP.",
"zip-bad": "Lo fichièr es un archiu ZIP corromput o illegible.\nPòt pas èsser verificat corrèctament per la seguretat.",
"zip-unsupported": "Lo fichièr es un archiu ZIP qu'utiliza de caracteristicas pas suportadas per MediaWiki. \nSa seguretat pòt pas èsser verificada corrèctament.",
- "uploadstash": "Escondedor d'impòrt",
- "uploadstash-clear": "Escafar los fichièrs en escondedor",
- "uploadstash-nofiles": "Avètz pas de fichièrs en escondedor d'impòrt.",
+ "uploadstash": "Cache d'impòrt",
+ "uploadstash-clear": "Escafar los fichièrs en cache",
+ "uploadstash-nofiles": "Avètz pas de fichièrs en cache d'impòrt.",
"uploadstash-errclear": "L'escafament dels fichièrs a fracassat.",
"uploadstash-refresh": "Actualizar la lista dels fichièrs",
"invalid-chunk-offset": "Offset de segment invalid",
"img-auth-isdir": "Ensajatz d'accedir al repertòri « $1 ».\nSol l'accès als fichièrs es permesa.",
"img-auth-streaming": "Lectura en continú de « $1 ».",
"img-auth-public": "La foncion d'img_auth.php es d'afichar de fichièrs d'un wiki privat.\nAqueste wiki es configurat coma un wiki public.\nPer una seguretat optimala, img_auth.php es desactivat.",
- "img-auth-noread": "L'utilizaire a pas lo drech en lectura sus « $1 ».",
+ "img-auth-noread": "L'utilizaire a pas lo dreit en lectura sus « $1 ».",
"http-invalid-url": "URL incorrècta : $1",
"http-invalid-scheme": "Las URLs amb l\"esquèma « $1 » son pas suportadas",
"http-request-error": "Error desconeguda al moment del mandadís de la requèsta.",
"filedelete-nofile-old": "Existís pas cap de version archivada de '''$1''' amb los atributs indicats.",
"filedelete-otherreason": "Rason diferenta/suplementària :",
"filedelete-reason-otherlist": "Autra rason",
- "filedelete-reason-dropdown": "*Motius de supression costumièrs\n** Violacion de drech d’autor\n** Fichièr duplicat",
+ "filedelete-reason-dropdown": "*Motius de supression costumièrs\n** Violacion de dreit d’autor\n** Fichièr duplicat",
"filedelete-edit-reasonlist": "Modifica los motius de la supression",
"filedelete-maintenance": "La supression e lo restabliment de fichièrs es temporàriament desactivada pendent la mantenença.",
"filedelete-maintenance-title": "Impossible de suprimir lo fichièr",
"statistics-edits-average": "Modificacions mejanas per pagina",
"statistics-users": "[[Special:ListUsers|Utilizaires]] enregistrats",
"statistics-users-active": "Utilizaires actius",
- "statistics-users-active-desc": "Utilizaires qu'an fach al mens una accion durant {{PLURAL:$1|lo darrièr jorn|los $1 darrièrs jorns}}",
+ "statistics-users-active-desc": "Utilizaires qu'an fait al mens una accion pendent {{PLURAL:$1|lo darrièr jorn|los $1 darrièrs jorns}}",
"pageswithprop": "Paginas amb una proprietat de pagina",
"pageswithprop-legend": "Paginas amb una proprietat de pagina",
"pageswithprop-text": "Aquesta pagina fa la lista de las paginas qu'utilizan una proprietat de pagina particulara.",
"doubleredirects": "Redireccions doblas",
"doubleredirectstext": "Vaquí una lista de las paginas que redirigisson cap a de paginas que son elas-meteissas de paginas de redireccion.\nCada entrada conten de ligams cap a la primièra e la segonda redireccions, e mai la primièra linha de tèxte de la segonda pagina, çò que provesís, de costuma, la « vertadièra » pagina cibla, cap a la quala la primièra redireccion deuriá redirigir.\nLas entradas <del>barradas</del> son estadas resolgudas.",
"double-redirect-fixed-move": "[[$1]] es estat desplaçat.\nEs estat mes a jorn automaticament e redirigís ara cap a [[$2]].",
- "double-redirect-fixed-maintenance": "Correccion automatica de la dobla redireccion de [[$1]] cap a [[$2]] dins un prètzfach de mantenença.",
+ "double-redirect-fixed-maintenance": "Correccion automatica de la dobla redireccion de [[$1]] cap a [[$2]] dins un prètzfait de mantenença.",
"double-redirect-fixer": "Corrector de redireccion",
"brokenredirects": "Redireccions copadas",
"brokenredirectstext": "Aquestas redireccions mènan cap a de paginas qu'existisson pas :",
"wantedpages-summary": "Aquesta pagina compta totes los ligams, encluses los inserits via de modèls de navigacion. Per una lista dels articles mai demandats, vejatz articles mai demandats, que comptabiliza pas que las referéncias que provenon de l'espaci de nom dels articles. Vejatz tanben lo '''articles mai demandats'''.",
"wantedpages-badtitle": "Títol invalid dins los resultats : $1",
"wantedfiles": "Fichièrs desirats",
- "wantedfiletext-cat": "Los fichièrs seguents son utilizats, mas existisson pas localament. Se se tròban sus un depaus partejat, pòdon èsser listats aicí, mentre que sián, de fach, ja disponibles. Totes aqueles falses positius seràn <del>raiats</del>. Amai, las paginas qu'intègran de fichièrs qu'existisson pas son repertoriadas dins [[:$1]].",
+ "wantedfiletext-cat": "Los fichièrs seguents son utilizats, mas existisson pas localament. Se se tròban sus un depaus partejat, pòdon èsser listats aicí, mentre que sián, de fait, ja disponibles. Totes aqueles falses positius seràn <del>raiats</del>. Amai, las paginas qu'intègran de fichièrs qu'existisson pas son repertoriadas dins [[:$1]].",
"wantedfiletext-cat-noforeign": "Los fichièrs seguents son utilizats mas existisson pas. Amai, las paginas qu'intègran los fichièrs qu'existisson pas son listats dins [[:$1]].",
- "wantedfiletext-nocat": "Los fichièrs seguents son utilizats, mas existisson pas localament. Se se tròban sus un depaus partejat, pòdon èsser listats aicí, mentre que sián, de fach, ja disponibles. Totes aqueles falses positius seràn <del>raiats</del>.",
+ "wantedfiletext-nocat": "Los fichièrs seguents son utilizats, mas existisson pas localament. Se se tròban sus un depaus partejat, pòdon èsser listats aicí, mentre que sián, de fait, ja disponibles. Totes aqueles falses positius seràn <del>raiats</del>.",
"wantedfiletext-nocat-noforeign": "Los fichièrs seguents son utilizats mas existisson pas.",
"wantedtemplates": "Modèls demandats",
"mostlinked": "Paginas mai ligadas",
"booksources-isbn": "ISBN :",
"booksources-search": "Recercar",
"booksources-text": "Vaquí una lista de ligams cap a d’autres sites que vendon de libres nòus e d’ocasion e suls quals trobaretz benlèu d'entresenhas suls obratges que cercatz. {{SITENAME}} es pas ligada a cap d'aquestas societats, a pas l’intencion de ne far la promocion.",
- "booksources-invalid-isbn": "Lo numèro ISBN balhat sembla pas èsser valid ; verificatz s'avètz fach una error al moment de la còpia dempuèi la font.",
+ "booksources-invalid-isbn": "Lo numèro ISBN balhat sembla pas èsser valid ; verificatz s'avètz fait una error al moment de la còpia dempuèi la font.",
"specialloguserlabel": "Autor :",
"speciallogtitlelabel": "Cibla (títol o utilizaire):",
"log": "Jornals",
"allpagesbadtitle": "Lo títol rensenhat per la pagina es incorrècte o possedís un prefix reservat. Conten segurament un o mantun caractèr especial que pòt pas èsser utilizats dins los títols.",
"allpages-bad-ns": "{{SITENAME}} a pas d’espaci de noms « $1 ».",
"allpages-hide-redirects": "Amagar las redireccions",
- "cachedspecial-viewing-cached-ttl": "Visualizatz una version d'aquesta pagina mesa en escondedor, que pòt èsser datada d’al mai $1.",
+ "cachedspecial-viewing-cached-ttl": "Visualizatz una version d'aquesta pagina mesa en cache, que pòt èsser datada d’al mai $1.",
"cachedspecial-refresh-now": "Veire lo mai recent.",
"categories": "Categorias",
"categoriespagetext": "{{PLURAL:$1|La categoria seguenta es utilizada|Las categorias seguentas son utilizadas}} per de paginas o de fichièrs.\n[[Special:UnusedCategories|Las categorias inutilizadas]] son pas afichadas aicí.\nVejatz tanben [[Special:WantedCategories|las categorias demandadas]].",
"activeusers-hidebots": "Amagar los robòts",
"activeusers-hidesysops": "Amagar los administrators",
"activeusers-noresult": "Cap d'utilizaire pas trobat.",
- "listgrouprights": "Dreches dels gropes d'utilizaires",
- "listgrouprights-summary": "Aquesta pagina conten una lista de gropes definits sus aqueste wiki e mai los dreches d'accès qu'i son associats.\nI pòt aver [[{{MediaWiki:Listgrouprights-helppage}}|d'entresenhas complementàrias]] a prepaus dels dreches.",
- "listgrouprights-key": "Legenda :\n*<span class=\"listgrouprights-granted\">Drech autrejat</span>\n*<span class=\"listgrouprights-revoked\">Drech revocat</span>",
+ "listgrouprights": "Dreits dels gropes d'utilizaires",
+ "listgrouprights-summary": "Aquesta pagina conten una lista de gropes definits sus aqueste wiki e mai los dreits d'accès qu'i son associats.\nI pòt aver [[{{MediaWiki:Listgrouprights-helppage}}|d'entresenhas complementàrias]] a prepaus dels dreits.",
+ "listgrouprights-key": "Legenda :\n*<span class=\"listgrouprights-granted\">Dreit autrejat</span>\n*<span class=\"listgrouprights-revoked\">Dreit revocat</span>",
"listgrouprights-group": "Grop",
- "listgrouprights-rights": "Dreches associats",
+ "listgrouprights-rights": "Dreits associats",
"listgrouprights-helppage": "Help:Dreches dels gropes",
"listgrouprights-members": "(lista dels membres)",
"listgrouprights-addgroup": "Pòt apondre $2 {{PLURAL:$2|grop|gropes}} : $1",
"listgrouprights-removegroup-self-all": "Se pòt levar totes los gropes de son compte pròpri",
"listgrouprights-namespaceprotection-header": "Restriccions d'espaci de noms",
"listgrouprights-namespaceprotection-namespace": "Espaci de noms",
- "listgrouprights-namespaceprotection-restrictedto": "Drech(s) que permet(on) a l'utilizaire de modificar",
+ "listgrouprights-namespaceprotection-restrictedto": "Dreit(s) que permet(on) a l'utilizaire de modificar",
"trackingcategories": "Categorias de seguiment",
"trackingcategories-msg": "Categoria de seguiment",
"trackingcategories-name": "Nom del messatge",
"watchlist-options": "Opcions de la lista de seguiment",
"watching": "Seguit...",
"unwatching": "Fin del seguit...",
- "watcherrortext": "Una error s'es producha al moment de la modificacion dels paramètres de vòstra lista de seguiment per « $1 ».",
+ "watcherrortext": "Una error s'es produita al moment de la modificacion dels paramètres de vòstra lista de seguiment per « $1 ».",
"enotif_reset": "Marcar totas las paginas coma visitadas",
"enotif_impersonal_salutation": "Utilizaire de {{SITENAME}}",
"enotif_subject_deleted": "La pagina $1 sus {{SITENAME}} es estada suprimida per {{GENDER:$2|$2}}",
"deletecomment": "Motiu :",
"deleteotherreason": "Motius suplementaris o autres :",
"deletereasonotherlist": "Autre motiu",
- "deletereason-dropdown": "* Motius de supression los mai corrents\n** Corrièrs indesirables\n** Vandalisme\n** Violacion dels dreches d’autor\n** Demanda de l’autor\n** Redireccion copada",
+ "deletereason-dropdown": "* Motius de supression los mai corrents\n** Corrièrs indesirables\n** Vandalisme\n** Violacion dels dreits d’autor\n** Demanda de l’autor\n** Redireccion copada",
"delete-edit-reasonlist": "Modifica los motius de la supression",
"delete-toobig": "Aquesta pagina dispausa d'un istoric important, depassant {{PLURAL:$1|revision|revisions}}.\nLa supression de talas paginas es estada limitada per evitar de perturbacions accidentalas de {{SITENAME}}.",
"delete-warning-toobig": "Aquesta pagina dispausa d'un istoric important, depassant {{PLURAL:$1|revision|revisions}}.\nLa suprimir pòt perturbar lo foncionament de la banca de donada de {{SITENAME}}.\nD'efectuar amb prudéncia.",
"protectexpiry": "Expiracion (expira pas per defaut)",
"protect_expiry_invalid": "Lo temps d’expiracion es invalid",
"protect_expiry_old": "Lo temps d’expiracion ja es passat.",
- "protect-unchain-permissions": "Desvarrolhar ancara mai d'opcions de proteccion",
+ "protect-unchain-permissions": "Desverrolhar ancara mai d'opcions de proteccion",
"protect-text": "Podètz consultar e modificar lo nivèl de proteccion de la pagina «$1».",
"protect-locked-blocked": "Podètz pas modificar los nivèls de proteccion tant que sètz bloca{{GENDER:||t|ada}}.. Vaquí los reglatges actuals de la pagina <strong>$1</strong> :",
- "protect-locked-dblock": "Lo nivèl de proteccion pòt pas èsser modificat perque la banca de donadas es varrolhada.\nVaquí los reglatges actuals de la pagina <strong>$1</strong> :",
- "protect-locked-access": "Avètz pas los dreches necessaris per modificar los nivèls de proteccion de las paginas.\nVaquí los reglatges actuals de la pagina <strong>$1</strong> :",
+ "protect-locked-dblock": "Lo nivèl de proteccion pòt pas èsser modificat perque la basa de donadas es verrolhada.\nVaquí los reglatges actuals de la pagina <strong>$1</strong> :",
+ "protect-locked-access": "Avètz pas los dreits necessaris per modificar los nivèls de proteccion de las paginas.\nVaquí los reglatges actuals de la pagina <strong>$1</strong> :",
"protect-cascadeon": "Aquesta pagina es protegida perque es inclusa dins {{PLURAL:$1|la pagina seguenta qu'es estada protegida|las paginas seguentas que son estadas protegidas}}, amb l’opcion « proteccion en cascada » activada. Podètz cambiar lo nivèl de proteccion d'aquesta pagina sens qu'aquò afècte la proteccion en cascada.",
"protect-default": "Autorizar totes los utilizaires",
- "protect-fallback": "Autorizar unicament los utilizaires amb lo drech « $1 »",
+ "protect-fallback": "Autorizar unicament los utilizaires amb lo dreit « $1 »",
"protect-level-autoconfirmed": "Autorizar unicament los utilizaires autoconfirmats",
"protect-level-sysop": "Autorizar unicament los administrators",
"protect-summary-cascade": "proteccion en cascada",
"undelete-filename-mismatch": "Impossible de restablir lo fichièr datat del $1 : fichièr introbable",
"undelete-bad-store-key": "Impossible de restablir lo fichièr datat del $1 : lo fichièr èra absent abans la supression.",
"undelete-cleanup-error": "Error al moment de la supression de l’archiu inutilizada « $1 ».",
- "undelete-missing-filearchive": "Impossible de restablir lo fichièr amb l’ID $1 perque es pas dins la banca de donadas. Benlèu ja i es estat restablit.",
+ "undelete-missing-filearchive": "Impossible de restablir lo fichièr amb l’ID $1 perque es pas dins la basa de donadas. Benlèu ja i es estat restablit.",
"undelete-error": "Pagina d'error d'anullacion",
"undelete-error-short": "Error al moment del restabliment del fichièr : $1",
"undelete-error-long": "D'errors son estadas rencontradas al moment del restabliment del fichièr :\n\n$1",
"sp-contributions-uploads": "impòrts",
"sp-contributions-logs": "jornals",
"sp-contributions-talk": "Discutir",
- "sp-contributions-userrights": "gerir los dreches",
+ "sp-contributions-userrights": "gerir los dreits",
"sp-contributions-blocked-notice": "Aqueste utilizaire es actualament blocat. La darrièra entrada del jornal dels blocatges es indicada çaijós a títol d’informacion :",
"sp-contributions-blocked-notice-anon": "Aquesta adreça IP es actualament blocada.\nLa darrièra intrada del jornal dels blocatges es indicada çaijós a títol d’informacion :",
"sp-contributions-search": "Cercar las contribucions",
"proxyblockreason": "Vòstra ip es estada blocada perque s’agís d’un proxy dobèrt. Mercé de contactar vòstre fornidor d’accès internet o vòstre supòrt tecnic e de l’informar d'aqueste problèma de seguretat.",
"sorbsreason": "Vòstra adreça IP es listada en tant que mandatari (proxy) dobèrt DNSBL per {{SITENAME}}.",
"sorbs_create_account_reason": "Vòstra adreça IP es listada en tant que mandatari (proxy) dobèrt DNSBL per {{SITENAME}}.\nPodètz pas crear un compte",
- "cant-see-hidden-user": "L'utilizaire qu'ensajatz de blocar es ja estat blocat e amagat. Sens lo drech hideuser, podètz pas veire o modificar lo blocatge de l'utilizaire.",
+ "cant-see-hidden-user": "L'utilizaire qu'ensajatz de blocar es ja estat blocat e amagat. Sens lo dreit hideuser, podètz pas veire o modificar lo blocatge de l'utilizaire.",
"ipbblocked": "Podètz pas blocar o desblocar d'autres utilizaire, perque vos {{GENDER:|meteis|meteissa|meteis}} sètz {{GENDER:|blocat|blocada|blocat}}.",
"ipbnounblockself": "Sètz pas autorizat a vos desblocar vos meteis",
- "lockdb": "Varrolhar la banca",
- "unlockdb": "Desvarrolhar la banca",
- "lockdbtext": "Lo clavatge de la banca de donadas empacharà totes los utilizaires de modificar las paginas, de salvar lors preferéncias, de modificar lor lista de seguiment e d'efectuar totas las autras operacions necessitant de modificacions dins la banca de donadas.\nConfirmatz qu'es plan çò que volètz far e que desblocaretz la banca tre que vòstra operacion de mantenença serà acabada.",
- "unlockdbtext": "Lo desclavatge de la banca de donadas permetrà a totes los utilizaires de modificar tornarmai de paginas, de metre a jorn lors preferéncias e lor lista de seguiment, e mai d'efectuar las autras operacions que necessitan de modificacions dins la banca de donadas.\nConfirmatz qu'es plan çò que volètz far.",
- "lockconfirm": "Òc, confirmi que desiri varrolhar la banca de donadas.",
- "unlockconfirm": "Òc, confirmi que desiri desvarrolhar la banca de donadas.",
- "lockbtn": "Varrolhar la banca",
- "unlockbtn": "Desvarrolhar la banca",
+ "lockdb": "Verrolhar la banca",
+ "unlockdb": "Desverrolhar la banca",
+ "lockdbtext": "Lo clavatge de la basa de donadas empacharà totes los utilizaires de modificar las paginas, de salvar lors preferéncias, de modificar lor lista de seguiment e d'efectuar totas las autras operacions necessitant de modificacions dins la basa de donadas.\nConfirmatz qu'es plan çò que volètz far e que desblocaretz la banca tre que vòstra operacion de mantenença serà acabada.",
+ "unlockdbtext": "Lo desclavatge de la basa de donadas permetrà a totes los utilizaires de modificar tornamai de paginas, de metre a jorn lors preferéncias e lor lista de seguiment, e mai d'efectuar las autras operacions que necessitan de modificacions dins la basa de donadas.\nConfirmatz qu'es plan çò que volètz far.",
+ "lockconfirm": "Òc, confirmi que desiri verrolhar la basa de donadas.",
+ "unlockconfirm": "Òc, confirmi que desiri desverrolhar la basa de donadas.",
+ "lockbtn": "Verrolhar la banca",
+ "unlockbtn": "Desverrolhar la basa",
"locknoconfirm": "Avètz pas marcat la casa de confirmacion.",
- "lockdbsuccesssub": "Varrolhatge de la banca capitat.",
- "unlockdbsuccesssub": "Banca desvarrolhada.",
- "lockdbsuccesstext": "La banca de donadas de {{SITENAME}} es varrolhada.\n\nDoblidetz pas de la desvarrolhar quand auretz acabat vòstra operacion de mantenença.",
- "unlockdbsuccesstext": "La banca de donadas de {{SITENAME}} es desvarrolhada.",
- "lockfilenotwritable": "Lo fichièr de blocatge de la banca de donadas es pas inscriptible. Per blocar o desblocar la banca de donadas, vos cal poder escriure sul servidor web.",
- "databasenotlocked": "La banca de donadas es pas varrolhada.",
+ "lockdbsuccesssub": "Verrolhatge de la basa capitat.",
+ "unlockdbsuccesssub": "Basa desverrolhada.",
+ "lockdbsuccesstext": "La basa de donadas de {{SITENAME}} es varrolhada.\n\nDoblidetz pas de la desverrolhar quand auretz acabat vòstra operacion de mantenença.",
+ "unlockdbsuccesstext": "La basa de donadas de {{SITENAME}} es desverrolhada.",
+ "lockfilenotwritable": "Lo fichièr de blocatge de la basa de donadas es pas inscriptible. Per blocar o desblocar la basa de donadas, vos cal poder escriure sul servidor web.",
+ "databasenotlocked": "La basa de donadas es pas verrolhada.",
"lockedbyandtime": "(per $1 lo $2 a $3)",
"move-page": "Renomenar $1",
"move-page-legend": "Tornar nomenar una pagina",
"imageinvalidfilename": "Lo nom del fichièr cibla es incorrècte",
"fix-double-redirects": "Metre a jorn las redireccions que puntant cap al títol ancian",
"move-leave-redirect": "Daissar una redireccion darrièr",
- "protectedpagemovewarning": "'''ATENCION:''' Aquesta pagina es estada protegida per que sonque los utilizaires qu'an los dreches d'administrators la pòscan tornar nomenar. La darrièra entrada del jornal es afichada çaijós per referéncia :",
+ "protectedpagemovewarning": "'''ATENCION:''' Aquesta pagina es estada protegida per que sonque los utilizaires qu'an los dreits d'administrators la pòscan renomenar. La darrièra entrada del jornal es afichada çaijós per referéncia :",
"semiprotectedpagemovewarning": "'''Nòta :''' Aquesta pagina es estada blocada per que sonque los utilizaires enregistrats la pòscan tornar nomenar. La darrièra entrada del jornal es afichada çaijós per referéncia :",
"move-over-sharedrepo": "== Lo fichièr existís ==\n[[:$1]] existís ja sus un depaus partejat. Tornar nomenar aqueste fichièr farà lo fichièr sul depaus partatge inaccessible.",
"file-exists-sharedrepo": "Lo nom causit es ja utilizat per un fichièr sus un depaus partejat.\nCausissètz un autre nom.",
"importuploaderrortemp": "Lo telecargament del fichièr d'importar a pas capitat. Un dorsièr temporari es mancant.",
"import-parse-failure": "Ruptura dins l'analisi de l'impòrt XML",
"import-noarticle": "Pas de pagina d'importar !",
- "import-nonewrevisions": "Cap de revision pas importada (totas èran ja presentas, o ignoradas del fach d’errors).",
+ "import-nonewrevisions": "Cap de revision pas importada (totas èran ja presentas, o ignoradas del fait d’errors).",
"xml-error-string": "$1 a la linha $2, col $3 (octet $4) : $5",
"import-upload": "Impòrt d'un fichier XML",
"import-token-mismatch": "Pèrda de las donadas de sesilha. Tornatz ensajar.",
"pageinfo-magic-words": "{{PLURAL:$1|Mot magic|Mots magics}} ($1)",
"pageinfo-hidden-categories": "{{PLURAL:$1|Categoria amagada|Categorias amagadas}} ($1)",
"pageinfo-templates": "{{PLURAL:$1|Modèl inclús|Modèls incluses}} ($1)",
- "pageinfo-transclusions": "{{PLURAL:$1|Pagina traducha|Paginas traduchas}} sus ($1)",
+ "pageinfo-transclusions": "{{PLURAL:$1|Pagina traduita|Paginas traduitas}} sus ($1)",
"pageinfo-toolboxlink": "Informacion sus la pagina",
"pageinfo-redirectsto": "Redirigir cap a",
"pageinfo-redirectsto-info": "info",
"rcpatroldisabledtext": "La foncionalitat de relectura dels darrièrs cambiaments es actualament desactivada.",
"markedaspatrollederror": "Pòt pas èsser marcat coma pas vandalizat",
"markedaspatrollederrortext": "Vos cal seleccionar una version per poder la marcar coma pas vandalizada.",
- "markedaspatrollederror-noautopatrol": "Avètz pas lo drech de marcar vòstras pròprias modificacions coma susvelhadas.",
+ "markedaspatrollederror-noautopatrol": "Avètz pas lo dreit de marcar vòstras pròprias modificacions coma susvelhadas.",
"markedaspatrollednotify": "Aquesta modificacion de $1 es estada marcada coma relegida.",
"markedaspatrollederrornotify": "Fracàs del marcatge coma contrarotlat.",
"patrol-log-page": "Istoric de las versions patrolhadas",
"filedeleteerror-short": "Error al moment de la supression del fichièr : $1",
"filedeleteerror-long": "D'errors son estadas rencontradas al moment de la supression del fichièr :\n\n$1",
"filedelete-missing": "Lo fichièr « $1 » pòt pas èsser suprimit perque existís pas.",
- "filedelete-old-unregistered": "La revision del fichièr especificat « $1 » es pas dins la banca de donadas.",
- "filedelete-current-unregistered": "Lo fichièr especificat « $1 » es pas dins la banca de donadas.",
+ "filedelete-old-unregistered": "La revision del fichièr especificat « $1 » es pas dins la basa de donadas.",
+ "filedelete-current-unregistered": "Lo fichièr especificat « $1 » es pas dins la basa de donadas.",
"filedelete-archive-read-only": "Lo dorsièr d’archivatge « $1 » es pas modificable pel servidor.",
"previousdiff": "← Cambiament precedent",
"nextdiff": "Cambiament seguent →",
- "mediawarning": "<strong>Atencion :</strong> Aqueste tipe de fichièr pòt conténer de còde malvolent.\nSe l'executatz, vòstre sistèma pòt èsser compromés.",
+ "mediawarning": "<strong>Atencion :</strong> Aqueste tipe de fichièr pòt conténer de còdi malvolent.\nSe l'executatz, vòstre sistèma pòt èsser compromés.",
"imagemaxsize": "Format maximal dels imatges :<br />''(per las paginas de descripcion d’imatges)''",
"thumbsize": "Talha de la miniatura :",
"widthheightpage": "$1 × $2, $3 {{PLURAL:$3|pagina|paginas}}",
"exif-keywords": "Mots claus",
"exif-worldregioncreated": "Region del mond dins la quala la fòto es estada presa",
"exif-countrycreated": "País dins lo qual la fòto es estada presa",
- "exif-countrycodecreated": "Còde del país dins lo qual la fòto es estada presa",
+ "exif-countrycodecreated": "Còdi del país dins lo qual la fòto es estada presa",
"exif-provinceorstatecreated": "Província o Estat dins lo qual la fòto es estada presa",
"exif-citycreated": "Vila dins la quala la fòto es estada presa",
"exif-sublocationcreated": "Partida de la vila dins la quala la fòto es estada presa",
"exif-worldregiondest": "Region del mond representada",
"exif-countrydest": "País representat",
- "exif-countrycodedest": "Còde del país representat",
+ "exif-countrycodedest": "Còdi del país representat",
"exif-provinceorstatedest": "Província o Estat representat",
"exif-citydest": "Vila representada",
"exif-sublocationdest": "Partida de la vila representada",
"exif-urgency": "Urgéncia",
"exif-fixtureidentifier": "Nom element recurrent",
"exif-locationdest": "Luòc representat",
- "exif-locationdestcode": "Còde del luòc representat",
+ "exif-locationdestcode": "Còdi del luòc representat",
"exif-objectcycle": "Moment de la jornada al qual aqueste mèdia es destinat",
"exif-contact": "Informacions de contacte",
"exif-writer": "Autor",
"exif-iimsupplementalcategory": "Categorias suplementàrias",
"exif-datetimeexpires": "Utilizar pas aprèp",
"exif-datetimereleased": "Paregut lo",
- "exif-originaltransmissionref": "Còde de localizacion de la transmission originala",
+ "exif-originaltransmissionref": "Còdi de localizacion de la transmission originala",
"exif-identifier": "Identificant",
"exif-lens": "Lentilha utilizada",
"exif-serialnumber": "Numèro de seria de l'aparelh de fòto",
"exif-datetimemetadata": "Data de la darrièra modificacion de las metadonadas",
"exif-nickname": "Nom informal de l'imatge",
"exif-rating": "Nòta (sus 5)",
- "exif-rightscertificate": "Certificat de gestion dels dreches",
- "exif-copyrighted": "Estatut del drech d'autor",
- "exif-copyrightowner": "Detentor del drech d'autor",
+ "exif-rightscertificate": "Certificat de gestion dels dreits",
+ "exif-copyrighted": "Estatut del dreit d'autor",
+ "exif-copyrightowner": "Detentor del dreit d'autor",
"exif-usageterms": "Condicions d'utilizacion",
- "exif-webstatement": "Declaracion de dreches d'autor en linha",
+ "exif-webstatement": "Declaracion de dreits d'autor en linha",
"exif-originaldocumentid": "Identificant unic del document original",
"exif-licenseurl": "URL de la licéncia",
"exif-morepermissionsurl": "Informacions sus las licéncias alternativas",
"exif-contentwarning": "Avertiment sul contengut",
"exif-giffilecomment": "Comentari de fichièr GIF",
"exif-intellectualgenre": "Tipe d'element",
- "exif-subjectnewscode": "Còde del subjècte",
- "exif-scenecode": "Còde de scèna IPTC",
+ "exif-subjectnewscode": "Còdi del subjècte",
+ "exif-scenecode": "Còdi de scèna IPTC",
"exif-event": "Eveniment representat",
"exif-organisationinimage": "Organizacion representada",
"exif-personinimage": "Persona representada",
"exif-compression-2": "CCITT Grop 3 Longor de l'encodatge Huffman modificat de dimension 1",
"exif-compression-3": "CCITT Grop 3 encodatge del fax",
"exif-compression-4": "CCITT Grop 4 encodatge del fax",
- "exif-copyrighted-true": "Somés al drech d'autor",
- "exif-copyrighted-false": "Estat dels dreches d’autor pas definit",
+ "exif-copyrighted-true": "Somés al dreit d'autor",
+ "exif-copyrighted-false": "Estat dels dreits d’autor pas definit",
"exif-unknowndate": "Data desconeguda",
"exif-orientation-1": "Normala",
"exif-orientation-2": "Inversada orizontalament",
"exif-exposureprogram-4": "Prioritat a l’obturacion",
"exif-exposureprogram-5": "Programa de creacion (preferéncia a la prigondor de camp)",
"exif-exposureprogram-6": "Programa d'accion (preferéncia a la velocitat d’obturacion)",
- "exif-exposureprogram-7": "Mòde retrach (per clichats de prèp amb rèireplan fosc)",
+ "exif-exposureprogram-7": "Mòde retrait (per clichats de prèp amb rèireplan fosc)",
"exif-exposureprogram-8": "Mòde païsatge (per de clichats de païsatges nets)",
"exif-subjectdistance-value": "{{PLURAL:$1|$1 mètre|$1 mètres}}",
"exif-meteringmode-0": "Desconegut",
"exif-whitebalance-1": "Balança dels blancs manuala",
"exif-scenecapturetype-0": "Estandard",
"exif-scenecapturetype-1": "Païsatge",
- "exif-scenecapturetype-2": "Retrach",
+ "exif-scenecapturetype-2": "Retrait",
"exif-scenecapturetype-3": "Scèna nuechenca",
"exif-gaincontrol-0": "Cap",
"exif-gaincontrol-1": "Augmentacion febla de l’aquisicion",
"exif-dc-date": "Data(s)",
"exif-dc-publisher": "Editor",
"exif-dc-relation": "Mèdias connèxes",
- "exif-dc-rights": "dreches",
+ "exif-dc-rights": "Dreits",
"exif-dc-source": "Mèdia font",
"exif-dc-type": "Tipe de mèdia",
"exif-rating-rejected": "Regetat",
"exif-isospeedratings-overflow": "Mai grand que 65535",
"exif-iimcategory-ace": "Arts, cultura e lésers",
- "exif-iimcategory-clj": "Crime e drech",
+ "exif-iimcategory-clj": "Crime e dreit",
"exif-iimcategory-dis": "Catastròfas e accidents",
"exif-iimcategory-fin": "Economia e afars",
"exif-iimcategory-edu": "Educacion",
"monthsall": "totes",
"confirmemail": "Confirmar l'adreça de corrièr electronic",
"confirmemail_noemail": "L’adreça de corrièr electronic configurada dins vòstras [[Special:Preferences|preferéncias]] es pas valida.",
- "confirmemail_text": "{{SITENAME}} necessita la verificacion de vòstra adreça de corrièr electronic abans de poder utilizar tota foncion de messatjariá. Utilizatz lo boton çaijós per mandar un corrièr electronic de confirmacion a vòstra adreça. Lo corrièr contendrà un ligam contenent un còde, cargatz aqueste ligam dins vòstre navigador per validar vòstra adreça.",
- "confirmemail_pending": "Un còde de confirmacion ja vos es estat mandat per corrièr electronic ;\nse venètz de crear vòstre compte, esperatz qualques minutas que l’e-mail arribe abans de demandar un còde novèl.",
- "confirmemail_send": "Mandar un còde de confirmacion",
+ "confirmemail_text": "{{SITENAME}} necessita la verificacion de vòstra adreça de corrièr electronic abans de poder utilizar tota foncion de messatjariá. Utilizatz lo boton çaijós per mandar un corrièr electronic de confirmacion a vòstra adreça. Lo corrièr contendrà un ligam contenent un còdi, cargatz aqueste ligam dins vòstre navigador per validar vòstra adreça.",
+ "confirmemail_pending": "Un còdi de confirmacion ja vos es estat mandat per corrièr electronic ;\nse venètz de crear vòstre compte, esperatz qualques minutas que l’e-mail arribe abans de demandar un còdi novèl.",
+ "confirmemail_send": "Mandar un còdi de confirmacion",
"confirmemail_sent": "Corrièr electronic de confirmacion mandat.",
- "confirmemail_oncreate": "Un còde de confirmacion es estat mandat a vòstra adreça de corrièr electronic.\nAqueste còde es pas requerit per se connectar, mas n'aurètz besonh per activar las foncionalitats ligadas als corrièrs electronics sus aqueste wiki.",
+ "confirmemail_oncreate": "Un còdi de confirmacion es estat mandat a vòstra adreça de corrièr electronic.\nAqueste còdi es pas requesit per se connectar, mas n'auretz besonh per activar las foncionalitats ligadas als corrièrs electronics sus aqueste wiki.",
"confirmemail_sendfailed": "{{SITENAME}} pòt pas mandar lo corrièr de confirmacion.\nVerificatz se vòstra adreça conten pas de caractèrs interdiches.\n\nRetorn del programa de corrièr : $1",
- "confirmemail_invalid": "Còde de confirmacion incorrècte. Benlèu lo còde a expirat.",
+ "confirmemail_invalid": "Còdi de confirmacion incorrècte. Benlèu que lo còdi a expirat.",
"confirmemail_needlogin": "Vos cal vos $1 per confirmar vòstra adreça de corrièr electronic.",
"confirmemail_success": "Vòstra adreça de corrièr electronic es confirmada. Ara, vos podètz connectar e aprofechar del wiki.",
"confirmemail_loggedin": "Ara, vòstra adreça es confirmada",
"confirmemail_subject": "Confirmacion d’adreça de corrièr electronic per {{SITENAME}}",
- "confirmemail_body": "Qualqu’un, probablament vos,e amb l’adreça IP $1, a enregistrat un compte « $2 » amb aquesta adreça de corrièr electronic sul site {{SITENAME}}.\n\nPer confirmar qu'aqueste compte vos aparten vertadièrament e activar las foncions de messatjariá sus {{SITENAME}}, seguissètz lo ligam çaijós dins vòstre navigador :\n\n$3\n\nSe s’agís pas de vos, dobriscatz pas lo ligam.\nAqueste còde de confirmacion expirarà lo $4, seguissètz l’autre ligam çaijós dins vòstre navigador :\n\n$5\n\nAqueste còde de confirmacion expirarà lo $4.",
- "confirmemail_body_changed": "Qualqu’un, probablament vos, a partir de l’adreça IP $1,\na modificat l’adreça de corrièr associada al compte « $2 » de {{SITENAME}}\nen aquesta adreça.\n\nPer confirmar qu'aqueste compte vos aparten vertadièrament e per tal\nde reactivar las foncions de messatjariá sus {{SITENAME}},\nseguissètz aqueste ligam dins vòstre navigador :\n\n$3\n\nS'aqueste compte vos aparten *pas*, dobriscatz pas aqueste ligam ;\npodètz seguir l’autre ligam çaijós per anullar la\nconfirmacion de vòstra adreça de corrièl :\n\n$5\n\nAqueste còde de confirmacion expirarà lo $4.",
- "confirmemail_body_set": "Qualqu’un, probablament vos, dempuèi l’adreça IP $1, a modificat l'adreça de corrièr electronic del compte « $2 » amb aquesta sul site {{SITENAME}}.\n\nPer confirmar qu'aqueste compte vos aparten vertadièrament e reactivar las foncions de messatjariá sus {{SITENAME}}, seguissètz lo ligam çaijós dins vòstre navigador :\n\n$3\n\nAqueste còde de confirmacion expirarà lo $4.\n\nSe s’agís *pas* de vòstre compte, seguissètz aqueste ligam per anullar la confirmacion de l'adreça de corrièr electronic :\n\n$5",
+ "confirmemail_body": "Qualqu’un, probablament vos,e amb l’adreça IP $1, a enregistrat un compte « $2 » amb aquesta adreça de corrièr electronic sul site {{SITENAME}}.\n\nPer confirmar qu'aqueste compte vos aparten vertadièrament e activar las foncions de messatjariá sus {{SITENAME}}, seguissètz lo ligam çaijós dins vòstre navigador :\n\n$3\n\nSe s’agís pas de vos, dobriscatz pas lo ligam.\nAqueste còdi de confirmacion expirarà lo $4, seguissètz l’autre ligam çaijós dins vòstre navigador :\n\n$5\n\nAqueste còdi de confirmacion expirarà lo $4.",
+ "confirmemail_body_changed": "Qualqu’un, probablament vos, a partir de l’adreça IP $1,\na modificat l’adreça de corrièr associada al compte « $2 » de {{SITENAME}}\nen aquesta adreça.\n\nPer confirmar qu'aqueste compte vos aparten vertadièrament e per tal\nde reactivar las foncions de messatjariá sus {{SITENAME}},\nseguissètz aqueste ligam dins vòstre navigador :\n\n$3\n\nS'aqueste compte vos aparten *pas*, dobriscatz pas aqueste ligam ;\npodètz seguir l’autre ligam çaijós per anullar la\nconfirmacion de vòstra adreça de corrièl :\n\n$5\n\nAqueste còdi de confirmacion expirarà lo $4.",
+ "confirmemail_body_set": "Qualqu’un, probablament vos, dempuèi l’adreça IP $1, a modificat l'adreça de corrièr electronic del compte « $2 » amb aquesta sul site {{SITENAME}}.\n\nPer confirmar qu'aqueste compte vos aparten vertadièrament e reactivar las foncions de messatjariá sus {{SITENAME}}, seguissètz lo ligam çaijós dins vòstre navigador :\n\n$3\n\nAqueste còdi de confirmacion expirarà lo $4.\n\nSe s’agís *pas* de vòstre compte, seguissètz aqueste ligam per anullar la confirmacion de l'adreça de corrièr electronic :\n\n$5",
"confirmemail_invalidated": "Confirmacion de l’adreça de corrièr electronic anullada",
"invalidateemail": "Anullar la confirmacion del corrièr electronic",
"scarytranscludedisabled": "[La transclusion interwiki es desactivada]",
"version-poweredby-others": "autres",
"version-poweredby-translators": "traductors de translatewiki.net",
"version-software": "Logicial installat",
- "version-software-product": "Produch",
+ "version-software-product": "Produit",
"version-software-version": "Version",
"version-entrypoints": "URL dels punts d'entrada",
"version-entrypoints-header-entrypoint": "Punt d'entrada",
"fileduplicatesearch-noresults": "Cap de fichièr nomenat « $1 » es pas estat trobat.",
"specialpages": "Paginas especialas",
"specialpages-note-top": "Legenda",
- "specialpages-note": "* Paginas especialas normalas.\n* <span class=\"mw-specialpagerestricted\">Paginas especialas restrenchas.</span>",
+ "specialpages-note": "* Paginas especialas normalas.\n* <span class=\"mw-specialpagerestricted\">Paginas especialas restrentas.</span>",
"specialpages-group-maintenance": "Rapòrts de mantenença",
"specialpages-group-other": "Autras paginas especialas",
"specialpages-group-login": "S'identificar / s'inscriure",
"specialpages-group-changes": "Darrièrs cambiaments e jornals",
"specialpages-group-media": "Rapòrts dels fichièrs de mèdias e dels impòrts",
- "specialpages-group-users": "Utilizaires e dreches estacats",
+ "specialpages-group-users": "Utilizaires e dreits estacats",
"specialpages-group-highuse": "Utilizacion intensa de las paginas",
"specialpages-group-pages": "Listas de paginas",
"specialpages-group-pagetools": "Aisinas per las paginas",
"compare-revision-not-exists": "La revision qu'avètz especificada existís pas.",
"dberr-problems": "O planhèm ! Aqueste site rencontra de dificultats tecnicas.",
"dberr-again": "Ensajatz d'esperar qualques minutas e tornatz cargar.",
- "dberr-info": "(Accès a la banca de donadas impossible : $1)",
- "dberr-info-hidden": "(Accès a la banca de donadas impossible)",
+ "dberr-info": "(Accès a la basa de donadas impossible : $1)",
+ "dberr-info-hidden": "(Accès a la basa de donadas impossible)",
"dberr-usegoogle": "Podètz ensajar de cercar amb Google pendent aqueste temps.",
"dberr-outofdate": "Notatz que lors indèxes de nòstre contengut pòdon èsser depassats.",
"dberr-cachederror": "Aquò es una còpia amagada de la pagina demandada e pòt èsser depassada.",
"feedback-bugcheck": "Remirable ! Verificatz simplament qu'es pas un dels [$1 bugs ja coneguts].",
"feedback-bugnew": "Ai verificat. Senhalar un bug novèl",
"feedback-cancel": "Anullar",
- "feedback-close": "Fach",
+ "feedback-close": "Fait",
"feedback-external-bug-report-button": "Senhalar un bug tecnic",
"feedback-dialog-title": "Sometre un comentari",
"feedback-error-title": "Error",
"api-error-publishfailed": "Error intèrna: Lo servidor a pas pogut publicar lo fichièr temporari.",
"api-error-stasherror": "Una error s'es produsida al moment del telecargament del fichièr per lo dissimular.",
"api-error-timeout": "Lo servidor a pas respondut dins lo relambi pervist.",
- "api-error-unclassified": "Una error desconeguda s'es producha.",
+ "api-error-unclassified": "Una error desconeguda s'es produita.",
"api-error-unknown-code": "Error desconeguda : « $1 »",
"api-error-unknown-error": "Error intèrna : Quicòm a mal virat al moment del mandadís de vòstre fichièr.",
"api-error-unknown-warning": "Avertiment desconegut : $1",
"limitreport-expansiondepth": "Mai granda prigondor d’espandiment",
"limitreport-expensivefunctioncount": "Nombre de foncions d’analisi costosas",
"expandtemplates": "Espandiment dels modèls",
- "expand_templates_intro": "Aquesta pagina especiala accèpta un tèxte wiki source e permet de realizar recursivament l’espandiment dels modèls que conten.\nRealiza tanben l’espandiment de las foncions del parser talas coma\n<code><nowiki>{{</nowiki>#language:...}}</code> e de variablas coma\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nEn fach, realiza l'espandiment de gaireben tot çò qu'es enquadrat per d'acoladas doblas.",
- "expand_templates_title": "Títol de la pagina, se lo còde utiliza {{FULLPAGENAME}}, etc. :",
+ "expand_templates_intro": "Aquesta pagina especiala accèpta un tèxte wiki source e permet de realizar recursivament l’espandiment dels modèls que conten.\nRealiza tanben l’espandiment de las foncions del parser talas coma\n<code><nowiki>{{</nowiki>#language:...}}</code> e de variablas coma\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nEn fait, realiza l'espandiment de gaireben tot çò qu'es enquadrat per d'acoladas doblas.",
+ "expand_templates_title": "Títol de la pagina, se lo còdi utiliza {{FULLPAGENAME}}, etc. :",
"expand_templates_input": "Picatz vòstre tèxte aicí :",
"expand_templates_output": "Visualizatz lo resultat :",
"expand_templates_xml_output": "Sortida XML",
"Denö",
"Hiloin Natoi",
"Ilja.mos",
- "Mashoi7"
+ "Mashoi7",
+ "Misosoof",
+ "Ghiutun",
+ "Matma Rex"
]
},
"tog-underline": "Linkien alleviivuamine:",
"resetpass_submit": "Azeta peittosana da kirjuttai sistiemah:",
"changepassword-success": "Sinun peittosana on vaihtettu!",
"changepassword-throttled": "Olet oppinuh kirjuttuakseh liijan moni kerdua. Ole hyvä, vuota $1 enne ku opit uvvessah.",
+ "botpasswords-label-create": "Luaji",
+ "botpasswords-label-update": "Päivitä",
+ "botpasswords-label-cancel": "Hylgiä",
+ "botpasswords-label-delete": "Poista",
"resetpass_forbidden": "Ei voi vaihtua peittosanua",
"resetpass-no-info": "Et voi nähtä tädä sivuu kuni et ole kirjutannuhes.",
"resetpass-submit-loggedin": "Vaihta peittosana",
"whatlinkshere-links": "← linkat",
"whatlinkshere-hideredirs": "$1 uvvellehohjavukset",
"whatlinkshere-hidetrans": "$1 sižällyttämizet",
- "whatlinkshere-hidelinks": "$1 linkat",
+ "whatlinkshere-hidelinks": "$1 linkit",
"whatlinkshere-filters": "Filtrat",
"blocklink": "Lukiče",
"contribslink": "kohendukset",
"noname": "ଆପଣ ଗୋଟିଏ ବୈଧ ଇଉଜର ନାମ ଦେଇନାହାନ୍ତି ।",
"loginsuccesstitle": "ଠିକଭାବେ ଲଗ-ଇନ ହେଲା",
"loginsuccess": "'''ଆପଣ {{SITENAME}}ରେ \"$1\" ନାମରେ ଲଗ-ଇନ କରିଛନ୍ତି ।'''",
- "nosuchuser": "\"$1\" ନାମରେ କେହି ଜଣେ ବି ସଭ୍ୟ ନାହାନ୍ତି ।\nଇଉଜର ନାମ ଇଂରାଜୀ ଛୋଟ ଓ ବଡ଼ ଅକ୍ଷର ପ୍ରତି ସମ୍ବେଦନଶୀଳ ।\nଆପଣ ନିଜର ବନାନ ପରଖି ନିଅନ୍ତୁ, ଅଥବା [[Special:UserLogin/signup|ନୂଆ ଖାତାଟିଏ ତିଆରି କରନ୍ତୁ]] ।",
+ "nosuchuser": "\"$1\" ନାମରେ କେହି ଜଣେ ବି ସଭ୍ୟ ନାହାନ୍ତି ।\nଇଉଜର ନାମ ଇଂରାଜୀ ଛୋଟ ଓ ବଡ଼ ଅକ୍ଷର ପ୍ରତି ସମ୍ବେଦନଶୀଳ ।\nଆପଣ ନିଜର ବନାନ ପରଖି ନିଅନ୍ତୁ, ଅଥବା [[Special:CreateAccount|ନୂଆ ଖାତାଟିଏ ତିଆରି କରନ୍ତୁ]] ।",
"nosuchusershort": "\"$1\" ନାମରେ କେହି ଜଣେ ବି ସଭ୍ୟ ନାହାନ୍ତି ।\nଆପଣ ବନାନ ପରଖି ନିଅନ୍ତୁ ।",
"nouserspecified": "ଆପଣଙ୍କୁ ଇଉଜର ନାମଟିଏ ଦେବାକୁ ପଡ଼ିବ ।",
"login-userblocked": "ଏହି ସଭ୍ୟଙ୍କୁ ଅଟକାଯାଇଛି । ଲଗ ଇନ କରିବାକୁ ଅନୁମତି ନାହିଁ ।",
"accmailtext": "[[User talk:$1|$1]] ପାଇଁ $2କୁ ଏକ ଆପେ ଆପେ ତିଆରି ପାସୱାର୍ଡ଼ ପଠାଗଲା । ଏହା ଲଗ ଇନ କଲା ପରେ<em>[[Special:ChangePassword|ପାସୱାର୍ଡ଼ ବଦଳ]]</em> ପୃଷ୍ଠାରେ ବଦଳାଯାଇପାରିବ ।",
"newarticle": "(ନୁଆ)",
"newarticletext": "ଆପଣ ଖୋଲିଥିବା ଲିଙ୍କଟିରେ ଏଯାଏଁ କିଛିବି ପୃଷ୍ଠା ନାହିଁ ।\nଏହି ପୃଷ୍ଠାଟିକୁ ତିଆରି କରିବା ପାଇଁ ତଳ ବାକ୍ସରେ ଟାଇପ କରନ୍ତୁ (ଅଧିକ ଜାଣିବା ପାଇଁ [$1 ସାହାଯ୍ୟ ପୃଷ୍ଠା] ଦେଖନ୍ତୁ) ।\nଯଦି ଆପଣ ଏଠାକୁ ଭୁଲରେ ଆସିଯାଇଥାନ୍ତି ତେବେ ଆପଣଙ୍କ ବ୍ରାଉଜରର '''Back''' ପତିଟି ଦବାନ୍ତୁ ।",
- "anontalkpagetext": "----''ଏହା ଏକ ଖାତା ଖୋଲିନଥିବା ବା ଖାତା ବ୍ୟବହାର କରିନଥିବା ଜଣେ ବେନାମି ସଭ୍ୟଙ୍କର ଆଲୋଚନା ପୃଷ୍ଠା ।''\nତେଣୁ ଆମ୍ଭେ ସଂଖ୍ୟା ଦେଇ ସୂଚୀତ IP ଠିକଣା ଦେଇ ତାଙ୍କୁ ଜାଣିବା ।\nଏହି ପ୍ରକାରର ଗୋଟିଏ IP ଠିକଣା ବହୁ ସଭ୍ୟଙ୍କ ଦେଇ ବ୍ୟବହାର କରାଯାଇପାରେ । \nଯଦି ଆପଣ ଜଣେ ଅଜଣା ସଭ୍ୟ ଓ ଭାବୁଛନ୍ତି ଇଆଡୁ ସିଆଡୁ ମତାମତ ସବୁ ଆପଣଙ୍କ ପାଇଁ ଦିଆଯାଇଛି ତେବେ ଦୟାକରି [[Special:UserLogin/signup|ନୂଆ ଖାତାଟିଏ ଖୋଲନ୍ତୁ]] କିମ୍ବା [[Special:UserLogin|ଆଗରୁ ଥିବା ଖାତାରେ ଲଗ ଇନ କରନ୍ତୁ]] ଯାହା ବେନାମି ସଭ୍ୟଙ୍କୁ ନେଇ ଉପୁଜିଥିବା ଦ୍ଵନ୍ଦର ସମାଧାନ କରିବ ।",
+ "anontalkpagetext": "----''ଏହା ଏକ ଖାତା ଖୋଲିନଥିବା ବା ଖାତା ବ୍ୟବହାର କରିନଥିବା ଜଣେ ବେନାମି ସଭ୍ୟଙ୍କର ଆଲୋଚନା ପୃଷ୍ଠା ।''\nତେଣୁ ଆମ୍ଭେ ସଂଖ୍ୟା ଦେଇ ସୂଚୀତ IP ଠିକଣା ଦେଇ ତାଙ୍କୁ ଜାଣିବା ।\nଏହି ପ୍ରକାରର ଗୋଟିଏ IP ଠିକଣା ବହୁ ସଭ୍ୟଙ୍କ ଦେଇ ବ୍ୟବହାର କରାଯାଇପାରେ । \nଯଦି ଆପଣ ଜଣେ ଅଜଣା ସଭ୍ୟ ଓ ଭାବୁଛନ୍ତି ଇଆଡୁ ସିଆଡୁ ମତାମତ ସବୁ ଆପଣଙ୍କ ପାଇଁ ଦିଆଯାଇଛି ତେବେ ଦୟାକରି [[Special:CreateAccount|ନୂଆ ଖାତାଟିଏ ଖୋଲନ୍ତୁ]] କିମ୍ବା [[Special:UserLogin|ଆଗରୁ ଥିବା ଖାତାରେ ଲଗ ଇନ କରନ୍ତୁ]] ଯାହା ବେନାମି ସଭ୍ୟଙ୍କୁ ନେଇ ଉପୁଜିଥିବା ଦ୍ଵନ୍ଦର ସମାଧାନ କରିବ ।",
"noarticletext": "ଏହି ପୃଷ୍ଠାଟିରେ କିଛି ବି ଲେଖା ନାହିଁ ।\nଆପଣ [[Special:Search/{{PAGENAME}}|ଏହି ଲେଖାଟିର ନାଆଁ]] ବାକି ପୃଷ୍ଠାମାନଙ୍କରେ ଖୋଜି ପାରନ୍ତି,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}}ରେ ଯୋଡ଼ାଯାଇଥିବା ବାକି ପୃଷ୍ଠାସବୁକୁ ଖୋଜି ପାରନ୍ତି],\nକିମ୍ବା [{{fullurl:{{FULLPAGENAME}}|action=edit}} ଏହି ପୃଷ୍ଠାଟିକୁ ବଦଳାଇ ପାରନ୍ତି]</span> ।",
"noarticletext-nopermission": "ଏବେ ଏହି ପୃଷ୍ଠାଟିରେ କିଛି ବି ଲେଖା ନାହିଁ ।\nଆପଣ [[Special:Search/{{PAGENAME}}|ଏହି ଲେଖାଟିର ନାଆଁ]] ବାକି ପୃଷ୍ଠାମାନଙ୍କରେ ଖୋଜି ପାରନ୍ତି, କିମ୍ବା\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}}ରେ ଯୋଡ଼ାଯାଇଥିବା ବାକି ପୃଷ୍ଠାସବୁକୁ ଖୋଜି ପାରନ୍ତି]\n</span>, କିନ୍ତୁ ଏହି ପୃଷ୍ଠାଟିକୁ ଆପଣ ତିଆରି କରିପାରିବେ ନାହିଁ ।",
"missing-revision": "\"{{FULLPAGENAME}}\" ନାମରେ ଥିବା ପୃଷ୍ଠାଟିର #$1 ପୁନରାବୃତ୍ତି ନାହିଁ ।\n\nପୁରୁଣା ହୋଇଯାଇଥିବା ଇତିହାସ ଲିଙ୍କ ଯାହା ଏକ ଲିଭାଯାଇଥିବା ପୃଷ୍ଠାକୁ ଦିଆଯାଇଥିବାରୁ ଏହା ସାଧାରଣତଃ ହୋଇଥାଏ ।\nଅଧିକ ବିବରଣୀ [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log]ରେ ମିଳିପାରିବ ।",
"preferences": "ପସନ୍ଦ",
"mypreferences": "ପସନ୍ଦ",
"prefs-edits": "ସମ୍ପାଦନା ସଂଖ୍ୟା:",
- "prefsnologintext2": "ନିà¬\9cର ପସନà\8dଦ ବଦଲାଇବା ପାଇଁ ଲଗ ଇନ କରନ୍ତୁ ।",
+ "prefsnologintext2": "ନିà¬\9cର ପସନà\8dଦ ବଦଳାଇବା ପାଇଁ ଲଗ ଇନ କରନ୍ତୁ ।",
"prefs-skin": "ବହିରାବରଣ",
"skin-preview": "ସାଇତା ଆଗରୁ ଦେଖଣା",
"datedefault": "କୌଣସି ପସନ୍ଦ ନାହିଁ",
"noname": "Раст фæсномыг нæ ныффыстай.",
"loginsuccesstitle": "Бахызтæ",
"loginsuccess": "'''Ныр ды дæ хыст {{grammar:genitive|{{SITENAME}}}} куыд \"$1\".'''",
- "nosuchuser": "Нæй ахæм архайæг \"$1\" номимæ.\nАрхайджыты нæмттæ хатынц дамгъæты регистр.\nСбæрæг æй кæн, раст ныффыстай ном, æви [[Special:UserLogin/signup|бакæн ног аккаунт]].",
+ "nosuchuser": "Нæй ахæм архайæг \"$1\" номимæ.\nАрхайджыты нæмттæ хатынц дамгъæты регистр.\nСбæрæг æй кæн, раст ныффыстай ном, æви [[Special:CreateAccount|бакæн ног аккаунт]].",
"nosuchusershort": "Нæй архайæг \"$1\" фæсномыгимæ.\nФен, фæсномыг раст ныффыстай, æви нæ.",
"nouserspecified": "Ды хъуамæ зæгъай дæ фæсномыг.",
"login-userblocked": "Ацы архайæг хъодыгонд у. Нæй гæнæн бахизын.",
"accmailtext": "[[User talk:$1|{{grammar:dative|$1}}]] халæй ист пароль æрвыст æрцыд ацы адрисмæ: $2. Ацы ног аккаунты пароль гæнæн ис фæивын <em>[[Special:ChangePassword|пароль ивæн фарсыл]]</em> бахизыны фæстæ.",
"newarticle": "(Ног)",
"newarticletext": "Ды ныххæцыдтæ ахæм æрвитæныл, кæй фарс нырмæ нæй.\nФарс бакæнынæн байдай фыссын дæлдæр цы къæртт ис, уым (кæс [$1 æххуысы фарс] фылдæр базонынæн).",
- "anontalkpagetext": "----''Ай у æнæном архайæджы ныхасы фарс. Ацы архайæг нырмæ нæ срегистраци кодта, кæнæ та йæ аккаунтæй нæ архайы.\nУый тыххæй мах пайда кæнæм йæ IP адрисæй, цæмæй-иу æй бæрæг кæнæм.\nАхæм IP адристæй гæнæн ис архайой цалдæр архайæджы.\nКæд ды æнæном архайæг дæ æмæ дæм цыдæр зæгъæлы фыстæджытæ цæуы, уæд, дæ хорзæхæй, [[Special:UserLogin/signup|бакæн аккаунт]] кæнæ [[Special:UserLogin|бахиз системæмæ]], цæмæй дæ мауал хæццæ кæной æндæр æнæном архайджытимæ.''",
+ "anontalkpagetext": "----''Ай у æнæном архайæджы ныхасы фарс. Ацы архайæг нырмæ нæ срегистраци кодта, кæнæ та йæ аккаунтæй нæ архайы.\nУый тыххæй мах пайда кæнæм йæ IP адрисæй, цæмæй-иу æй бæрæг кæнæм.\nАхæм IP адристæй гæнæн ис архайой цалдæр архайæджы.\nКæд ды æнæном архайæг дæ æмæ дæм цыдæр зæгъæлы фыстæджытæ цæуы, уæд, дæ хорзæхæй, [[Special:CreateAccount|бакæн аккаунт]] кæнæ [[Special:UserLogin|бахиз системæмæ]], цæмæй дæ мауал хæццæ кæной æндæр æнæном архайджытимæ.''",
"noarticletext": "Ацы фарсы нырмæ текст нæй.\nДæ бон у [[Special:Search/{{PAGENAME}}|бацагурын ацы фарсы ном]] æндæр фæрсты,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} агурын йæ кой логты],\nкæнæ [{{fullurl:{{FULLPAGENAME}}|action=edit}} скæнын ацы фарс]</span>.",
"noarticletext-nopermission": "Ацы фарсы нырмæ текст нæй.\nДæ бон у [[Special:Search/{{PAGENAME}}|бацагурын ацы фарсы ном]] æндæр фæрсты, кæнæ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} агурын йæ кой логты]</span>, фæлæ дын йæ саразыны бар нæй.",
"missing-revision": "\"{{grammar:genitive|{{FULLPAGENAME}}}}\" фарсæн $1-æм фæлтæр нæй.\n\nАй арæх æрцæуы, исчи хафт фарсы зæронд историйы æрвитæны фæдыл куы ацæуы.\nФылдæр гæнæн ис базонын [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} хафыны логы].",
"cachedspecial-refresh-now": "Фæстаг фенын.",
"categories": "Категоритæ",
"categoriespagetext": "Ацы {{PLURAL:$1|категорийы|категориты}} ис фæрстæ кæнæ файлтæ.\n[[Special:UnusedCategories|Нæ пайдагонд категоритæ]] æвдыст не сты.\nНоджы кæс [[Special:WantedCategories|хъæугæ категоритæ]].",
- "special-categories-sort-count": "нымæцмæ гæсгæ равæр",
- "special-categories-sort-abc": "алфавитмæ гæсгæ равæр",
"sp-deletedcontributions-contribs": "бавæрд",
"linksearch": "Æддаг æрвитæнтæ агурын",
"linksearch-ns": "Номдон:",
"tog-hideminor": "ਤਾਜ਼ਾ ਤਬਦੀਲੀਆਂ ਵਿੱਚੋਂ ਛੋਟੀਆਂ ਸੋਧਾਂ ਲੁਕਾਓ",
"tog-hidepatrolled": "ਤਾਜ਼ਾ ਤਬਦੀਲੀਆਂ ਵਿੱਚੋਂ ਜਾਂਚੀਆਂ ਸੋਧਾਂ ਲੁਕਾਓ",
"tog-newpageshidepatrolled": "ਨਵੀਂ ਸਫ਼ਾ ਸੂਚੀ ਵਿੱਚੋਂ ਜਾਂਚੇ ਸਫ਼ੇ ਲੁਕਾਓ",
+ "tog-hidecategorization": "ਸਫ਼ਿਆਂ ਦਾ ਸ਼੍ਰੇਣੀਕਰਨ ਲੁਕਾਓ",
"tog-extendwatchlist": "ਸਿਰਫ਼ ਤਾਜ਼ਾ ਹੀ ਨਹੀਂ, ਸਗੋਂ ਸਾਰੀਆਂ ਤਬਦੀਲੀਆਂ ਨੂੰ ਵਖਾਉਣ ਲਈ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਨੂੰ ਵਧਾਓ",
"tog-usenewrc": "ਹਾਲੀਆ ਤਬਦੀਲੀਆਂ ਅਤੇ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿੱਚ ਸਫ਼ੇ ਮੁਤਾਬਕ ਤਬਦੀਲੀਆਂ ਦੇ ਗਰੁੱਪ ਬਣਾਓ (ਜਾਵਾਸਕਰਿਪਟ ਲੋੜੀਂਦੀ ਹੈ)",
"tog-numberheadings": "ਆਟੋ-ਨੰਬਰ ਸਿਰਨਾਵੇਂ",
"password-change-forbidden": "ਇਸ ਵਿਕੀ ਤੇ ਤੁਸੀਂ ਪਾਸਵਰਡ ਨਹੀਂ ਬਦਲ ਸਕਦੇ।",
"externaldberror": "ਜਾਂ ਤਾਂ ਪ੍ਰਮਾਣਕੀ ਡਾਟਾਬੇਸ ਦੋਸ਼ ਆਇਆ ਹੈ ਜਾਂ ਤੁਹਾਨੂੰ ਆਪਣੇ ਬਾਹਰੀ ਖਾਤੇ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ।",
"login": "ਲਾਗਇਨ",
+ "login-security": "ਆਪਣੀ ਪਛਾਣ ਦੀ ਪੜਤਾਲ ਕਰਵਾਉ",
"nav-login-createaccount": "ਲਾਗਇਨ/ਖਾਤਾ ਬਣਾਓ",
"userlogin": "ਲਾਗਇਨ/ਖਾਤਾ ਬਣਾਓ",
"userloginnocreate": "ਲਾਗਇਨ",
"noname": "ਤੁਸੀਂ ਇੱਕ ਸਹੀ ਯੂਜ਼ਰ-ਨਾਂ ਨਹੀਂ ਦਿੱਤਾ।",
"loginsuccesstitle": "ਲਾਗਇਨ ਸਫ਼ਲ",
"loginsuccess": "'''ਤੁਸੀਂ {{SITENAME}} ਉੱਤੇ \"$1\" ਵਜੋਂ ਲਾਗਇਨ ਹੋ ਚੁੱਕੇ ਹੋ।'''",
- "nosuchuser": "!\"$1\" ਨਾਂ ਨਾਲ਼ ਕੋਈ ਵਰਤੋਂਕਾਰ ਨਹੀਂ ਹੈ। ਵੱਡੇ ਅਤੇ ਛੋਟੇ ਅੱਖਰ ਵਰਤਣ ਨਾਲ ਫ਼ਰਕ ਪੈਂਦਾ ਹੈ।\nਆਪਣੇ ਸਪੈਲਿੰਗ ਨੂੰ ਧਿਆਨ ਨਾਲ ਚੈੱਕ ਕਰੋ ਜਾਂ [[Special:UserLogin/signup|ਨਵਾਂ ਖਾਤਾ ਬਣਾਓ]]",
+ "nosuchuser": "!\"$1\" ਨਾਂ ਨਾਲ ਕੋਈ ਵਰਤੋਂਕਾਰ ਨਹੀਂ ਹੈ।\nਵੱਡੇ ਅਤੇ ਛੋਟੇ ਅੱਖਰ ਵਰਤਣ ਨਾਲ ਫ਼ਰਕ ਪੈਂਦਾ ਹੈ।\nਆਪਣੇ ਸ਼ਬਦਜੋੜ ਧਿਆਨ ਨਾਲ ਜਾਂਚੋ ਜਾਂ [[Special:CreateAccount|ਨਵਾਂ ਖਾਤਾ ਬਣਾਉ]]",
"nosuchusershort": "\"$1\" ਨਾਂ ਨਾਲ ਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਨਹੀਂ ਹੈ। ਆਪਣੇ ਸਪੈਲਿੰਗ ਧਿਆਨ ਨਾਲ ਚੈੱਕ ਕਰੋ।",
"nouserspecified": "ਤੁਹਾਨੂੰ ਇੱਕ ਯੂਜ਼ਰ-ਨਾਂ ਦੇਣਾ ਪਵੇਗਾ।",
"login-userblocked": "ਇਹ ਯੂਜ਼ਰ-ਨਾਂ ਪਾਬੰਦੀਸ਼ੁਦਾ ਹੈ। ਲਾਗਇਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ।",
"accmailtext": "[[User talk:$1|$1]] ਲਈ ਰਲ਼ਵੇਂ ਤੌਰ ’ਤੇ ਬਣਿਆ ਪਾਸਵਰਡ $2 ਨੂੰ ਭੇਜਿਆ ਜਾ ਚੁੱਕਾ ਹੈ।\nਇਸ ਨਵੇਂ ਖਾਤੇ ਲਈ ਲਾਗਇਨ ਕਰਨ ਤੋਂ ਬਾਅਦ ''[[Special:ChangePassword|ਪਾਸਵਰਡ ਬਦਲੋ]]'' ’ਤੇ ਜਾ ਕੇ ਪਾਸਵਰਡ ਬਦਲਿਆ ਜਾ ਸਕਦਾ ਹੈ।",
"newarticle": "(ਨਵਾਂ)",
"newarticletext": "ਤੁਸੀਂ ਕਿਸੇ ਅਜਿਹੇ ਸਫ਼ੇ ਦੇ ਕੜੀ ’ਤੇ ਹੋ ਜੋ ਹਾਲੇ ਬਣਾਇਆ ਨਹੀਂ ਗਿਆ।\nਸਫ਼ਾ ਬਣਾਉਣ ਲਈ ਹੇਠ ਦਿੱਤੇ ਖਾਨੇ ਵਿਚ ਲਿਖਣਾ ਸ਼ੁਰੂ ਕਰੋ। (ਹੋਰ ਮਦਦ ਲਈ [$1 ਮਦਦ ਸਫ਼ਾ] ਵੇਖੋ।)\nਜੇ ਤੁਸੀਂ ਗ਼ਲਤੀ ਨਾਲ ਇੱਥੇ ਆਏ ਹੋ ਤਾਂ ਆਪਣੇ ਬ੍ਰਾਊਜ਼ਰ ਦੇ '''ਪਿੱਛੇ''' ਬਟਨ ’ਤੇ ਕਲਿੱਕ ਕਰੋ।",
- "anontalkpagetext": "----''à¨\87ਹ à¨\87à¨\95 à¨\97à©\81ਮਨਾਮ ਮà©\88à¨\82ਬਰ ਲà¨\88 à¨\87à¨\95 à¨\9aਰà¨\9aਾ ਸਫ਼ਾ ਹà©\88 à¨\9cਿਸਨà©\87 ਹਾਲà©\87 à¨\96ਾਤਾ ਨਹà©\80 ਬਣਾà¨\87à¨\86 à¨\9cਾà¨\82 à¨\89ਸਨà©\82à©° ਵਰਤ ਨਹà©\80à¨\82 ਰਿਹਾ।\nà¨\87ਸ ਵਾਸਤà©\87 ਸਾਡà©\87 à¨\95à©\8bਲ à¨\89ਸਨà©\82à©° ਪà¨\9bਾਨਣ ਲà¨\88 IP ਪਤਾ ਹà©\88।\nà¨\87à¨\95 IP ਪਤਾ à¨\95à¨\88 ਵਰਤਣ ਵਾਲ਼ਿà¨\86à¨\82 ਦà©\81à¨\86ਰਾ ਸਾà¨\82à¨\9dਾ à¨\95à©\80ਤਾ à¨\9cਾ ਸà¨\95ਦਾ ਹà©\88।\nà¨\9cà©\87 ਤà©\81ਸà©\80à¨\82 à¨\87ੱà¨\95 à¨\97à©\81ਮਨਾਮ ਮà©\88à¨\82ਬਰ ਹà©\8b à¨\85ਤà©\87 ਸਮà¨\9dਦà©\87 ਹà©\8b à¨\95ਿ à¨\87ਹ à¨\9fਿੱਪਣà©\80à¨\86à¨\82 ਤà©\81ਹਾਡà©\87 ਲà¨\88 ਹਨ ਤਾà¨\82 ਮਿਹਰਬਾਨà©\80 à¨\95ਰà¨\95à©\87 ਹà©\8bਰਾà¨\82 à¨\97à©\81ਮਨਾਮ ਮà©\88à¨\82ਬਰਾà¨\82 ਨਾਲ਼ ਪà©\88ਦਾ ਹà©\8bਣ ਵਾਲ਼à©\80 à¨\89ਲà¨\9dਣ ਤà©\8bà¨\82 ਬà¨\9aਣ ਲà¨\88 [[Special:UserLogin/signup|à¨\96ਾਤਾ ਬਣਾà¨\93]] ਜਾਂ [[Special:UserLogin|ਲਾਗਇਨ ਕਰੋ]]।''",
+ "anontalkpagetext": "----''à¨\87ਹ à¨\95ਿਸà©\87 à¨\97à©\81ਮਨਾਮ ਮà©\88à¨\82ਬਰ ਲà¨\88 à¨\87à¨\95 à¨\9aਰà¨\9aਾ ਸਫ਼ਾ ਹà©\88 à¨\9cਿਸਨà©\87 ਹਾਲà©\87 à¨\96ਾਤਾ ਨਹà©\80à¨\82 ਬਣਾà¨\87à¨\86 à¨\9cਾà¨\82 à¨\9cਿਹà©\9cਾ à¨\87ਸਨà©\82à©° ਵਰਤਦਾ ਨਹà©\80à¨\82 ਹà©\88।\nà¨\87ਸ ਵਾਸਤà©\87 ਸਾਡà©\87 à¨\95à©\8bਲ à¨\89ਸਨà©\82à©° ਪà¨\9bਾਨਣ ਲà¨\88 IP ਪਤਾ ਹà©\88।\nà¨\85à¨\9cਿਹਾ à¨\95à©\8bà¨\88 IP ਪਤਾ à¨\95à¨\88 ਵਰਤਣ ਵਾਲਿà¨\86à¨\82 ਵੱਲà©\8bà¨\82 ਸਾà¨\82à¨\9dਾ à¨\95à©\80ਤਾ à¨\9cਾ ਸà¨\95ਦਾ ਹà©\88।\nà¨\9cà©\87 ਤà©\81ਸà©\80à¨\82 à¨\87ੱà¨\95 à¨\97à©\81ਮਨਾਮ ਮà©\88à¨\82ਬਰ ਹà©\8b à¨\85ਤà©\87 ਸਮà¨\9dਦà©\87 ਹà©\8b à¨\95ਿ ਤà©\81ਹਾਡà©\87 ਲà¨\88 ਬà©\87ਮਤਲਬ à¨\9fਿੱਪਣà©\80à¨\86à¨\82 ਹà©\8b ਰਹà©\80à¨\86à¨\82 ਹਨ ਤਾà¨\82 ਮਿਹਰਬਾਨà©\80 à¨\95ਰà¨\95à©\87 ਹà©\8bਰਾà¨\82 à¨\97à©\81ਮਨਾਮ ਮà©\88à¨\82ਬਰਾà¨\82 ਨਾਲ ਪà©\88ਦਾ ਹà©\8bਣ ਵਾਲ਼à©\80 à¨\89ਲà¨\9dਣ ਤà©\8bà¨\82 ਬà¨\9aਣ ਲà¨\88 [[Special:CreateAccount|à¨\96ਾਤਾ ਬਣਾà¨\89]] ਜਾਂ [[Special:UserLogin|ਲਾਗਇਨ ਕਰੋ]]।''",
"noarticletext": "ਫ਼ਿਲਹਾਲ ਇਸ ਸਫ਼ੇ ’ਤੇ ਕੋਈ ਲਿਖਤ ਨਹੀਂ ਹੈ। ਤੁਸੀਂ ਦੂਜੇ ਸਫ਼ਿਆਂ ’ਤੇ [[Special:Search/{{PAGENAME}}|ਇਸ ਸਿਰਲੇਖ ਦੀ ਖੋਜ]] ਕਰ ਸਕਦੇ ਹੋ, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ਸਬੰਧਤ ਚਿੱਠੇ ਲੱਭ] ਸਕਦੇ ਹੋ ਜਾਂ ਇਸ [{{fullurl:{{FULLPAGENAME}}|action=edit}} ਸਫ਼ੇ ਵਿਚ ਲਿਖ] ਸਕਦੇ ਹੋ</span>।",
"noarticletext-nopermission": "ਫ਼ਿਲਹਾਲ ਇਸ ਪੰਨੇ ’ਤੇ ਕੋਈ ਲਿਖਤ ਨਹੀਂ ਹੈ। ਤੁਸੀਂ ਦੂਸਰੇ ਪੰਨਿਆਂ ’ਤੇ [[Special:Search/{{PAGENAME}}|ਇਸ ਸਿਰਲੇਖ ਦੀ ਖੋਜ]] ਕਰ ਸਕਦੇ ਹੋ, ਸਬੰਧਤ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ਚਿੱਠੇ] ਖੋਜ ਸਕਦੇ ਹੋ ਜਾਂ [{{fullurl:{{FULLPAGENAME}}|action=edit}} ਇਸ ਪੰਨੇ ਵਿੱਚ ਲਿਖ] ਸਕਦੇ ਹੋ।</span>",
"userpage-userdoesnotexist": "ਵਰਤੋਂਕਾਰ ਖਾਤਾ \"$1\" ਰਜਿਸਟਰ ਨਹੀਂ ਹੈ।\nਜੇ ਤੁਸੀਂ ਇਸਨੂੰ ਬਣਾਉਣਾ/ਸੋਧਣਾ ਚਾਹੁੰਦੇ ਹੋ ਤਾਂ ਮਿਰਬਾਨੀ ਕਰਕੇ ਜਾਂਚ ਕਰ ਲਓ।",
"undelete-show-file-submit": "ਹਾਂ",
"namespace": "ਨਾਂ-ਥਾਂ:",
"invert": "ਉਲਟ ਚੋਣ",
+ "tooltip-invert": "ਚੁਣੇ ਗਏ ਨਾਮਸਥਾਨ ਵਿੱਚ ਮੌਜੂਦ ਸਫ਼ਿਆਂ ਵਿੱਚ ਹੋਈਆਂ ਤਬਦੀਲੀਆਂ ਨੂੰ ਲੁਕਾਉਣ ਲਈ ਇਸ ਡੱਬੇ ਉੱਤੇ ਨਿਸ਼ਾਨ ਲਗਾਓ।",
"namespace_association": "ਸਬੰਧਤ ਨਾਂ-ਥਾਂ",
+ "tooltip-namespace_association": "ਚੁਣੇ ਗਏ ਨਾਮਸਥਾਨ ਨਾਲ ਸੰਬੰਧਿਤ ਗੱਲਬਾਤ ਜਾਂ ਵਿਸ਼ਾ ਨਾਮਸਥਾਨ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਇਸ ਡੱਬੇ ਨੂੰ ਚੁਣੋ",
"blanknamespace": "(ਮੁੱਖ)",
"contributions": "{{GENDER:$1|ਮੈਂਬਰ}} ਯੋਗਦਾਨ",
"contributions-title": "$1 ਲਈ ਵਰਤੋਂਕਾਰ ਯੋਗਦਾਨ",
"mycontris": "ਯੋਗਦਾਨ",
+ "anoncontribs": "ਯੋਗਦਾਨ",
"contribsub2": "{{GENDER:$3|$1}} ($2) ਲਈ",
"uctop": "(ਮੌਜੂਦਾ)",
"month": "ਇਸ (ਅਤੇ ਪਿਛਲੇ) ਮਹੀਨੇ ਤੋਂ :",
"whatlinkshere-prev": "{{PLURAL:$1|ਪਿਛਲਾ|ਪਿਛਲੇ $1}}",
"whatlinkshere-next": "{{PLURAL:$1|ਅਗਲਾ|ਅਗਲੇ $1}}",
"whatlinkshere-links": "← ਕੜੀਆਂ",
- "whatlinkshere-hideredirs": "ਅਸਿੱਧੇ ਰਾਹ $1",
+ "whatlinkshere-hideredirs": "$1 ਰੀਡਾਇਰੈਕਟ",
"whatlinkshere-hidetrans": "$1 ਇੱਥੇ ਕੀ ਕੀ ਜੁੜਦਾ ਹੈ।",
"whatlinkshere-hidelinks": "$1 ਲਿੰਕ",
"whatlinkshere-hideimages": "ਫ਼ਾਈਲ ਲਿੰਕ $1",
"tooltip-pt-logout": "ਸਾਈਟ ਤੋਂ ਬਾਹਰ ਆਉ",
"tooltip-pt-createaccount": "ਤੁਹਾਨੂੰ ਖਾਤਾ ਬਣਾਉਣ ਤੋਂ ਬਾਅਦ ਲਾਗ ਇਨ ਕਰਨ ਦੀ ਸਲਾਹ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ; ਹਾਲਾਂਕਿ ਇਹ ਲਾਜ਼ਮੀ ਨਹੀਂ",
"tooltip-ca-talk": "ਸਮਗੱਰੀ ਸਫ਼ੇ ਬਾਰੇ ਚਰਚਾ",
- "tooltip-ca-edit": "ਤà©\81ਸà©\80à¨\82 à¨\87ਹ ਸਫ਼ਾ ਸà©\8bਧ ਸà¨\95ਦà©\87 ਹà©\8b। à¨\95ਿਰਪਾ à¨\95ਰà¨\95à©\87 ਤਬਦà©\80ਲà©\80 ਸਾà¨\82à¨à¨£ ਤà©\8bà¨\82 ਪਹਿਲਾà¨\82 à¨\9dਲà¨\95 ਵà©\87à¨\96à©\8b।",
+ "tooltip-ca-edit": "à¨\87ਹ ਸਫ਼ਾ ਸà©\8bਧà©\8b",
"tooltip-ca-addsection": "ਨਵਾਂ ਭਾਗ ਸ਼ੁਰੂ ਕਰੋ",
"tooltip-ca-viewsource": "ਇਹ ਸਫ਼ਾ ਸੁਰੱਖਿਅਤ ਹੈ।\nਤੁਸੀਂ ਇਹਦਾ ਸਰੋਤ ਵੇਖ ਸਕਦੇ ਹੋ।",
"tooltip-ca-history": "ਇਸ ਸਫ਼ੇ ਦੇ ਪਿਛਲੇ ਰੀਵਿਜਨ",
"tooltip-t-recentchangeslinked": "ਇਸ ਸਫ਼ੇ ਤੋਂ ਲਿੰਕ ਕੀਤੇ ਸਫ਼ਿਆਂ ਵਿਚ ਤਾਜ਼ਾ ਤਬਦੀਲੀਆਂ",
"tooltip-feed-rss": "ਇਸ ਸਫ਼ੇ ਲਈ RSS ਫ਼ੀਡ",
"tooltip-feed-atom": "ਇਸ ਸਫ਼ੇ ਦੀ ਐਟਮ ਫ਼ੀਡ",
- "tooltip-t-contributions": "à¨\87ਸ ਵਰਤà©\8bà¨\82à¨\95ਾਰ ਦà©\87 ਯà©\8bà¨\97ਦਾਨ ਦà©\80 ਸੂਚੀ",
+ "tooltip-t-contributions": "à¨\87ਸ ਵਰਤà©\8bà¨\82à¨\95ਾਰ ਦà©\80 ਯà©\8bà¨\97ਦਾਨ ਸੂਚੀ",
"tooltip-t-emailuser": "ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਈ-ਮੇਲ ਭੇਜੋ",
"tooltip-t-upload": "ਫ਼ਾਈਲਾਂ ਅਪਲੋਡ ਕਰੋ",
"tooltip-t-specialpages": "ਸਾਰੇ ਖ਼ਾਸ ਸਫ਼ਿਆਂ ਦੀ ਲਿਸਟ",
"anonusers": "{{SITENAME}} ਬੇਨਾਮ {{PLURAL:$2|ਵਰਤੋਂਕਾਰ|ਵਰਤੋਂਕਾਰ}} $1",
"creditspage": "ਸਫ਼ੇ ਬਾਬਤ ਕਰਜ਼",
"spamprotectiontitle": "Spam ਸੁਰੱਖਿਆ ਫਿਲਟਰ",
+ "simpleantispam-label": "ਸਪੈਮ ਵਿਰੋਧੀ ਚੈੱਕ।\nਇਸ ਨੂੰ <strong>ਨਾ</strong> ਭਰੋ!",
"pageinfo-title": "\"$1\" ਵਾਸਤੇ ਜਾਣਕਾਰੀ",
"pageinfo-not-current": "ਅਫ਼ਸੋਸ, ਪੁਰਾਣੀਆਂ ਸੁਧਾਈਆਂ ਵਾਸਤੇ ਇਹ ਜਾਣਕਾਰੀ ਦੇਣੀ ਅਸੰਭਵ ਹੈ।",
"pageinfo-header-basic": "ਮੁੱਢਲੀ ਜਾਣਕਾਰੀ",
"confirm-watch-top": "ਇਸ ਸਫ਼ੇ ਨੂੰ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਵਿਚ ਜੋੜਨਾ ਹੈ?",
"confirm-unwatch-button": "ਠੀਕ ਹੈ",
"confirm-unwatch-top": "ਇਸ ਸਫ਼ੇ ਨੂੰ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਤੋਂ ਹਟਾਉਣਾ ਹੈ?",
+ "confirm-rollback-button": "ਠੀਕ ਹੈ",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← ਪਿਛਲਾ ਸਫ਼ਾ",
"imgmultipagenext": "ਅਗਲਾ ਸਫ਼ਾ →",
"special-characters-group-khmer": "ਖ਼ਮੇਰ",
"special-characters-title-endash": "ਅੰਗਰੇਜ਼ੀ ਡੈਸ਼",
"special-characters-title-emdash": "em ਡੈਸ਼",
- "special-characters-title-minus": "ਘਟਾਓ ਦਾ ਨਿਸ਼ਾਨ"
+ "special-characters-title-minus": "ਘਟਾਓ ਦਾ ਨਿਸ਼ਾਨ",
+ "authmanager-password-help": "ਪ੍ਰਮਾਣਿਕਤਾ ਲਈ ਪਛਾਣ-ਸ਼ਬਦ।",
+ "authmanager-email-label": "ਈਮੇਲ",
+ "authmanager-email-help": "ਈਮੇਲ ਪਤਾ",
+ "authmanager-realname-label": "ਅਸਲੀ ਨਾਂ",
+ "authprovider-resetpass-skip-label": "ਛੱਡ ਦਿਉ",
+ "specialpage-securitylevel-not-allowed-title": "ਇਜਾਜ਼ਤ ਨਹੀਂ",
+ "cannotauth-not-allowed-title": "ਪ੍ਰਵਾਨਗੀ ਨਹੀਂ ਮਿਲੀ",
+ "credentialsform-account": "ਖਾਤੇ ਦਾ ਨਾਂ:"
}
"tog-ccmeonemails": "Przesyłaj mi kopie wiadomości, które wysyłam do innych użytkowników",
"tog-diffonly": "Nie pokazuj treści stron pod porównaniami zmian",
"tog-showhiddencats": "Pokazuj ukryte kategorie",
- "tog-norollbackdiff": "Pomiń pokazywanie zmian po użyciu funkcji „cofnij”",
+ "tog-norollbackdiff": "Nie pokazuj zmian po użyciu funkcji „cofnij”",
"tog-useeditwarning": "Ostrzegaj mnie, gdy opuszczam stronę edycji bez zapisania zmian",
"tog-prefershttps": "Zawsze używaj bezpiecznego połączenia po zalogowaniu",
"underline-always": "Zawsze",
"password-change-forbidden": "Nie można zmieniać haseł na tej wiki.",
"externaldberror": "Wystąpił błąd autentyfikacyjnej bazy danych lub nie posiadasz uprawnień koniecznych do aktualizacji zewnętrznego konta.",
"login": "Zaloguj się",
+ "login-security": "Potwierdź swoją tożsamość",
"nav-login-createaccount": "Logowanie i rejestracja",
"userlogin": "Logowanie i rejestracja",
"userloginnocreate": "Zaloguj się",
"userlogin-resetpassword-link": "Nie pamiętasz hasła?",
"userlogin-helplink2": "Pomoc przy logowaniu",
"userlogin-loggedin": "Zalogowano jako {{GENDER:$1|$1}}.\nUżyj poniższego formularza, aby zalogować się jako inny użytkownik.",
+ "userlogin-reauth": "Musisz się ponownie zalogować, aby potwierdzić, że jesteś {{GENDER:$1|$1}}.",
"userlogin-createanother": "Załóż nowe konto",
"createacct-emailrequired": "Adres e‐mail",
"createacct-emailoptional": "Adres e-mail (opcjonalnie)",
"createacct-reason-ph": "Dlaczego zakładasz kolejne konto",
"createacct-submit": "Utwórz konto",
"createacct-another-submit": "Utwórz konto",
+ "createacct-another-continue-submit": "Kontynuuj tworzenie konta",
"createacct-benefit-heading": "{{grammar:B.lp|{{SITENAME}}}} tworzą ludzie tacy jak Ty.",
"createacct-benefit-body1": "{{PLURAL:$1|edycja|edycje|edycji}}",
"createacct-benefit-body2": "{{PLURAL:$1|strona|strony|stron}}",
"noname": "To nie jest poprawna nazwa użytkownika.",
"loginsuccesstitle": "Zalogowano",
"loginsuccess": "'''{{GENDER:|Zalogowałeś się|Zalogowałaś się|Zalogowano}} do {{GRAMMAR:D.lp|{{SITENAME}}}} jako „$1”.'''",
- "nosuchuser": "Brak użytkownika o nazwie „$1”.\nW nazwie użytkownika ma znaczenie wielkość znaków.\nSprawdź pisownię lub [[Special:UserLogin/signup|utwórz nowe konto]].",
+ "nosuchuser": "Brak użytkownika o nazwie „$1”.\nW nazwie użytkownika ma znaczenie wielkość znaków.\nSprawdź pisownię lub [[Special:CreateAccount|utwórz nowe konto]].",
"nosuchusershort": "Brak użytkownika o nazwie „$1”.\nSprawdź poprawność pisowni.",
"nouserspecified": "Musisz podać nazwę użytkownika.",
"login-userblocked": "Ten użytkownik jest zablokowany. Zalogowanie się jest niemożliwe.",
"createacct-another-realname-tip": "Wpisanie imienia i nazwiska nie jest obowiązkowe.\nJeśli zdecydujesz się je podać, zostaną użyte, by udokumentować Twoje autorstwo.",
"pt-login": "Zaloguj się",
"pt-login-button": "Zaloguj się",
+ "pt-login-continue-button": "Kontynuuj logowanie",
"pt-createaccount": "Utwórz konto",
"pt-userlogout": "Wyloguj",
"php-mail-error-unknown": "Wystąpił nieznany błąd w funkcji PHP mail()",
"botpasswords-restriction-failed": "Logowanie nie powiodło się z powodu ograniczeń na hasło bota.",
"botpasswords-not-exist": "Użytkownik \"$1\" nie ma hasła dla bota o nazwie \"$2\".",
"resetpass_forbidden": "Hasła nie mogą zostać zmienione",
+ "resetpass_forbidden-reason": "Hasła nie mogą zostać zmienione: $1",
"resetpass-no-info": "Musisz być zalogowany, by uzyskać bezpośredni dostęp do tej strony.",
"resetpass-submit-loggedin": "Zmień hasło",
"resetpass-submit-cancel": "Anuluj",
"passwordreset-emailsentusername": "Jeśli z tym kontem powiązany jest adres e‐mail, zostanie na niego wysłany e-mail do odzyskiwania hasła.",
"passwordreset-emailsent-capture": "Wyświetlony poniżej e‐mail pozwalający na zresetowanie hasła został wysłany.",
"passwordreset-emailerror-capture": "Poniżej wyświetlony e‐mail pozwalający na zresetowanie hasła został wygenerowany, ale nie udało się wysłać go do {{GENDER:$2|użytkownika|użytkowniczki}}: $1",
+ "passwordreset-invalideamil": "Nieprawidłowy adres e-mail",
+ "passwordreset-nodata": "Nie podano ani nazwy użytkownika, ani adresu e-mail",
"changeemail": "Zmiana lub usunięcie adresu e‐mail",
"changeemail-header": "Wypełnij ten formularz, aby zmienić swój adres e-mail. Jeśli chcesz usunąć swój adres e-mail, to przy wypełnianiu formularza pozostaw puste pole nowego adresu e-mail.",
"changeemail-passwordrequired": "Musisz podać swoje hasło, aby potwierdzić tę zmianę.",
"minoredit": "To jest drobna zmiana",
"watchthis": "Obserwuj",
"savearticle": "Zapisz",
+ "publishpage": "Opublikuj stronę",
"preview": "Podgląd",
"showpreview": "Pokaż podgląd",
"showdiff": "Podgląd zmian",
"accmailtext": "Losowo wygenerowane hasło dla [[User talk:$1|$1]] zostało wysłane do $2.\n\nHasło dla tego nowego konta po zalogowaniu można zmienić na stronie ''[[Special:ChangePassword|zmiana hasła]]''.",
"newarticle": "(Nowy)",
"newarticletext": "Brak strony o tym tytule.\nJeśli chcesz ją utworzyć, wpisz treść strony w poniższym polu (więcej informacji odnajdziesz [$1 na stronie pomocy]).\nJeśli utworzenie nowej strony nie było Twoim zamiarem, wciśnij ''Wstecz'' w swojej przeglądarce.",
- "anontalkpagetext": "---- ''To jest strona dyskusji anonimowego użytkownika – takiego, który nie ma jeszcze swojego konta lub nie chce go w tej chwili używać.\nBy go identyfikować, używamy adresów IP.\nJednak adres IP może być współdzielony przez wielu użytkowników.\nJeśli jesteś anonimowym użytkownikiem i uważasz, że zamieszczone tu komentarze nie są skierowane do Ciebie, [[Special:UserLogin/signup|utwórz konto]] lub [[Special:UserLogin|zaloguj się]] – dzięki temu unikniesz w przyszłości podobnych nieporozumień.''",
+ "anontalkpagetext": "---- ''To jest strona dyskusji anonimowego użytkownika – takiego, który nie ma jeszcze swojego konta lub nie chce go w tej chwili używać.\nBy go identyfikować, używamy adresów IP.\nJednak adres IP może być współdzielony przez wielu użytkowników.\nJeśli jesteś anonimowym użytkownikiem i uważasz, że zamieszczone tu komentarze nie są skierowane do Ciebie, [[Special:CreateAccount|utwórz konto]] lub [[Special:UserLogin|zaloguj się]] – dzięki temu unikniesz w przyszłości podobnych nieporozumień.''",
"noarticletext": "Obecnie ta strona nie ma zawartości.\nMożesz [[Special:Search/{{PAGENAME}}|wyszukać ten tytuł na innych stronach]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} przeszukać rejestr] \nlub [{{fullurl:{{FULLPAGENAME}}|action=edit}} utworzyć tę stronę]</span>.",
"noarticletext-nopermission": "Ta strona nie posiada jeszcze zawartości.\nMożesz [[Special:Search/{{PAGENAME}}|wyszukać ten tytuł]] w treści innych stron\nlub <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} przeszukać powiązane rejestry]</span>, ale nie masz uprawnień do utworzenia tej strony",
"missing-revision": "Wersja #$1 strony \"{{FULLPAGENAME}}\" nie istnieje.\n\nZazwyczaj jest to spowodowane przestarzałym linkiem do usuniętej strony. Powód usunięcia znajduje się w [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} rejestrze].",
"gender-female": "kobieta",
"prefs-help-gender": "Podanie płci nie jest obowiązkowe. Jeśli zdecydujesz się ją określić, oprogramowanie dostosuje do niej interfejs. Informacja o Twojej płci będzie widoczna dla wszystkich.",
"email": "E‐mail",
- "prefs-help-realname": "Imię i nazwisko jest opcjonalne.\nJeśli zdecydujesz się je podać, zostaną użyte, by udokumentować Twoje autorstwo.",
+ "prefs-help-realname": "Imię i nazwisko jest opcjonalne.\nJeśli zdecydujesz się je podać, zostaną użyte, by udokumentować twoje autorstwo.",
"prefs-help-email": "Podanie adresu e‐mail nie jest obowiązkowe, lecz jest konieczne do zresetowania zapomnianego hasła.",
"prefs-help-email-others": "Możesz również umożliwić innym użytkownikom wysłanie do Ciebie e‐maila poprzez Twoją stronę użytkownika lub stronę dyskusji (bez ujawniania Twojego adresu).",
"prefs-help-email-required": "Wymagany jest adres e‐mail.",
"right-override-export-depth": "Eksport stron wraz z linkowanymi do głębokości 5 linków",
"right-sendemail": "Wysyłanie e‐maili do innych użytkowników",
"right-passwordreset": "Sprawdzanie treści e‐maila o resetowaniu hasła",
- "right-managechangetags": "Tworzenie i usuwanie [[Special:Tags|znaczników]] z bazy danych",
+ "right-managechangetags": "Tworzenie i (dez)aktywowanie [[Special:Tags|znaczników]]",
"right-applychangetags": "Wprowadzanie [[Special:Tags|znaczników]] wraz z własnymi zmianami",
"right-changetags": "Dodawanie i usuwanie dowolnych [[Special:Tags|znaczników]] z poszczególnych wersji i wpisów w rejestrze",
+ "right-deletechangetags": "Usuwanie [[Special:Tags|znaczników]] z bazy danych",
"grant-group-page-interaction": "Interakcja ze stronami",
"grant-group-file-interaction": "Interakcja z plikami multimedialnymi",
"grant-group-watchlist-interaction": "Interakcja z listą obserwowanych",
"action-viewmyprivateinfo": "zobaczenia swoich prywatnych danych",
"action-editmyprivateinfo": "edycji swoich prywatnych danych",
"action-editcontentmodel": "edycji modelu zawartości strony",
- "action-managechangetags": "utwórz lub usuń znaczniki z bazy danych",
+ "action-managechangetags": "tworzenia i de(aktywowania) znaczników",
"action-applychangetags": "wprowadzania znaczników wraz z własnymi zmianami",
"action-changetags": "dodawania i usuwania dowolnych znaczników z poszczególnych wersji i wpisów w rejestrze",
+ "action-deletechangetags": "usuwania znaczników z bazy danych",
"nchanges": "$1 {{PLURAL:$1|zmiana|zmiany|zmian}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od ostatniej wizyty}}",
"enhancedrc-history": "historia",
"upload-form-label-own-work": "To moja własna praca",
"upload-form-label-infoform-categories": "Kategorie",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-own-work-message-local": "Potwierdzam, że wysyłam ten plik zgodnie z warunkami i zasadami licencjonowania obowiązującymi na {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Jeśli nie możesz wysłać tego pliku zgodnie z zasadami obowiązującymi na {{SITENAME}}, zamknij ten komunikat i spróbuj innej metody.",
- "upload-form-label-not-own-work-local-local": "Możesz skorzystać też z [[Special:Upload|domyślnej strony przesyłania plików]].",
- "upload-form-label-own-work-message-default": "Rozumiem, że przesyłam ten plik do współdzielonego repozytorium. Potwierdzam, że robię to zgodnie z warunkami i zasadami licencjonowania tam obowiązującymi.",
- "upload-form-label-not-own-work-message-default": "Jeśli nie jesteś w stanie przesłać tego pliku zgodnie z zasadami współdzielonego repozytorium, zamknij to okno i spróbuj innej metody.",
- "upload-form-label-not-own-work-local-default": "Możesz spróbować użyć [[Special:Upload|strony przesyłania plików {{GRAMMAR:D.lp|{{SITENAME}}}}]], jeżeli zasady tej strony dopuszczają publikację tego pliku.",
- "upload-form-label-own-work-message-shared": "Oświadczam, że mam prawa autorskie do tego pliku, nieodwołalnie publikuję go na Wikimedia Commons na licencji [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0] i zgadzam się na [https://wikimediafoundation.org/wiki/Terms_of_Use/pl warunki użytkowania].",
- "upload-form-label-not-own-work-message-shared": "Jeżeli nie masz praw autorskich do tego pliku albo chcesz go opublikować na innej licencji, rozważ użycie [https://commons.wikimedia.org/wiki/Special:UploadWizard kreatora przesyłania plików].",
- "upload-form-label-not-own-work-local-shared": "Możesz spróbować użyć [[Special:Upload|strony przesyłania plików {{GRAMMAR:D.lp|{{SITENAME}}}}]], jeżeli zasady tej strony dopuszczają publikację tego pliku.",
+ "upload-form-label-own-work-message-generic-local": "Potwierdzam, że wysyłam ten plik zgodnie z warunkami i zasadami licencjonowania obowiązującymi na {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Jeśli nie możesz wysłać tego pliku zgodnie z zasadami obowiązującymi na {{SITENAME}}, zamknij ten komunikat i spróbuj innej metody.",
+ "upload-form-label-not-own-work-local-generic-local": "Możesz skorzystać też z [[Special:Upload|domyślnej strony przesyłania plików]].",
+ "upload-form-label-own-work-message-generic-foreign": "Rozumiem, że przesyłam ten plik do współdzielonego repozytorium. Potwierdzam, że robię to zgodnie z warunkami i zasadami licencjonowania tam obowiązującymi.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Jeśli nie jesteś w stanie przesłać tego pliku zgodnie z zasadami współdzielonego repozytorium, zamknij to okno i spróbuj innej metody.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Możesz spróbować użyć [[Special:Upload|strony przesyłania plików {{GRAMMAR:D.lp|{{SITENAME}}}}]], jeżeli zasady tej strony dopuszczają publikację tego pliku.",
"backend-fail-stream": "Nie można odczytać pliku $1.",
"backend-fail-backup": "Nie można utworzyć kopii zapasowej pliku $1 .",
"backend-fail-notexists": "Plik $1 nie istnieje.",
"trackingcategories-msg": "Śledzenie kategorii",
"trackingcategories-name": "Nazwa komunikatu",
"trackingcategories-desc": "Kryteria włączenia kategorii",
+ "restricted-displaytitle-ignored": "Strony z ignorowanym formatowaniem tytułu",
+ "restricted-displaytitle-ignored-desc": "Strona ma ignorowany <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> ponieważ nie pasuje on do tytułu aktualnej strony.",
"noindex-category-desc": "Ta strona nie jest indeksowana przez roboty, ponieważ ma wpisane magiczne słowo <code><nowiki>__NOINDEX__</nowiki></code> i znajduje się w przestrzeni nazw, w której ta flaga jest dozwolona.",
"index-category-desc": "Na stronie znajduje się magiczne słowo <code><nowiki>__INDEX__</nowiki></code> (i strona znajduje się w przestrzeni nazw, w której jest ono dozwolone), więc jest indeksowana przez wyszukiwarki nawet wtedy, gdy normalnie by się to nie działo.",
"post-expand-template-inclusion-category-desc": "Rozmiar tej strony jest większy niż <code>$wgMaxArticleSize</code> po rozszerzeniu wszystkich szablonów, więc część szablonów nie jest rozszerzonych.",
"lockdbsuccesstext": "Baza danych została zablokowana.<br />\nPamiętaj by [[Special:UnlockDB|zdjąć blokadę]] po zakończeniu działań administracyjnych.",
"unlockdbsuccesstext": "Baza danych została odblokowana.",
"lockfilenotwritable": "Nie można zapisać pliku blokady bazy danych.\nBlokowanie i odblokowywanie bazy danych, wymaga by plik mógł być zapisywany przez web serwer.",
+ "databaselocked": "Baza danych jest już zablokowana.",
"databasenotlocked": "Baza danych nie jest zablokowana.",
"lockedbyandtime": "(przez $1 dnia $2 o $3)",
"move-page": "Przenieś $1",
"tooltip-ca-nstab-category": "Zobacz stronę kategorii",
"tooltip-minoredit": "Oznacz zmianę jako drobną",
"tooltip-save": "Zapisz zmiany",
+ "tooltip-publish": "Opublikuj swoje zmiany",
"tooltip-preview": "Obejrzyj efekt swojej edycji przed zapisaniem zmian!",
"tooltip-diff": "Pokaż zmiany wykonane w tekście.",
"tooltip-compareselectedversions": "Pokazuje różnice między dwiema wybranymi wersjami tej strony.",
"confirm-watch-top": "Dodać tę stronę do listy obserwowanych?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Usunąć tę stronę z listy obserwowanych?",
+ "confirm-rollback-button": "OK",
"percent": "$1%",
"quotation-marks": "„$1”",
"imgmultipageprev": "← poprzednia strona",
"api-error-stashfilestorage": "Wystąpił błąd podczas przesyłania pliku do archiwum.",
"api-error-stashzerolength": "Serwer nie może zapisać pliku zapasowego do archiwum, gdyż ma on zerową długość.",
"api-error-stashnotloggedin": "Musisz się zalogować, aby móc zapisać plik zapasowy do archiwum.",
- "api-error-stashwrongowner": "Plik w archiwum, do którego próbujesz uzyskać dostęp, nie należy do ciebie.",
- "api-error-stashnosuchfilekey": "Klucz zbioru w archiwum, do którego próbujesz uzyskać dostęp, nie należy do ciebie.",
+ "api-error-stashwrongowner": "Plik w archiwum, do którego próbujesz uzyskać dostęp, nie należy do Ciebie.",
+ "api-error-stashnosuchfilekey": "Klucz zbioru w archiwum, do którego próbujesz uzyskać dostęp, nie należy do Ciebie.",
"api-error-timeout": "Serwer nie odpowiedział w oczekiwanym czasie.",
"api-error-unclassified": "Wystąpił nieznany błąd",
"api-error-unknown-code": "Błąd nieznany – „$1”",
"log-action-filter-rights-rights": "Ręczna zmiana",
"log-action-filter-rights-autopromote": "Automatyczna zmiana",
"log-action-filter-upload-upload": "Nowe przesłane",
- "log-action-filter-upload-overwrite": "Przesłane ponownie"
+ "log-action-filter-upload-overwrite": "Przesłane ponownie",
+ "authmanager-create-disabled": "Utworzenie konta jest wyłączone.",
+ "authmanager-create-from-login": "Aby utworzyć konto, wypełnij poniższe pola.",
+ "authmanager-authplugin-setpass-failed-title": "Zmiana hasła nie powiodła się",
+ "authmanager-authplugin-setpass-denied": "Wtyczka uwierzytelniania nie zezwala na zmianę haseł.",
+ "authmanager-authplugin-setpass-bad-domain": "Niepoprawna domena.",
+ "authmanager-autocreate-noperm": "Automatyczne tworzenie konta jest niedozwolone.",
+ "authmanager-autocreate-exception": "Automatyczne tworzenie konta tymczasowo wyłączone z powodu wcześniejszych błędów.",
+ "authmanager-userdoesnotexist": "Konto użytkownika „$1” nie jest zarejestrowane.",
+ "authmanager-username-help": "Nazwa użytkownika dla uwierzytelniania.",
+ "authmanager-password-help": "Hasło do uwierzytelniania.",
+ "authmanager-retype-help": "Ponownie hasło w celu potwierdzenia.",
+ "authmanager-email-label": "E-mail",
+ "authmanager-email-help": "Adres e‐mail",
+ "authmanager-realname-help": "Prawdziwe imię i nazwisko użytkownika",
+ "authmanager-provider-password": "Uwierzytelnianie oparte na haśle",
+ "authmanager-provider-password-domain": "Uwierzytelnianie na podstawie hasła i domeny",
+ "authmanager-provider-temporarypassword": "Hasło tymczasowe",
+ "authprovider-resetpass-skip-label": "Pomiń",
+ "authprovider-resetpass-skip-help": "Pomiń resetowanie hasła.",
+ "authform-newtoken": "Brakujący token. $1",
+ "authform-notoken": "Brakujący token",
+ "authform-wrongtoken": "Nieprawidłowy token",
+ "specialpage-securitylevel-not-allowed": "Niestety, nie możesz korzystać z tej strony, ponieważ twoja tożsamość nie może zostać zweryfikowana.",
+ "authpage-cannot-login-continue": "Nie można kontynuować logowania. Sesja najprawdopodobniej wygasła.",
+ "authpage-cannot-create": "Nie można rozpocząć tworzenie konta.",
+ "cannotauth-not-allowed-title": "Brak dostępu",
+ "cannotauth-not-allowed": "Nie masz uprawnień, aby skorzystać z tej strony",
+ "changecredentials-submit": "Zmień poświadczenia",
+ "removecredentials-submit": "Usuń poświadczenia",
+ "credentialsform-account": "Nazwa konta:"
}
"noname": "A l'ha nen ëspessificà në stranòm vàlid.",
"loginsuccesstitle": "Compliment! A l'é pen-a rintrà ant ël sistema.",
"loginsuccess": "'''Adess a l'é colegà a {{SITENAME}} con lë stranòm «$1».'''",
- "nosuchuser": "A-i é pa gnun utent con lë stranòm «$1».\nJë stranòm ëd j'utent a son sensìbij a le majùscole.\nCh'a contròla ël nòm che a l'ha batù, o [[Special:UserLogin/signup|ch'a crea un neuv cont]].",
+ "nosuchuser": "A-i é pa gnun utent con lë stranòm «$1».\nJë stranòm ëd j'utent a son sensìbij a le majùscole.\nCh'a contròla ël nòm che a l'ha batù, o [[Special:CreateAccount|ch'a crea un neuv cont]].",
"nosuchusershort": "A-i é pa gnun utent che as ciama «$1». Për piasì, che a contròla se a l'ha scrit tut giust.",
"nouserspecified": "A venta che a specìfica në stranòm d'utent",
"login-userblocked": "St'utent-sì a l'é blocà. A peul pa intré ant ël sistema.",
"accmailtext": "Na ciav generà a l'ancàpit për [[User talk:$1|$1]] a l'é stàita mandà a $2.\nA peul esse modificà an sla pàgina ''[[Special:ChangePassword|modìfica dla ciav]]'' apress esse rintrà ant ël sistema.",
"newarticle": "(Neuv)",
"newarticletext": "A l'é andaje dapress a na liura a na pàgina che a esist ancor nen.\nPër creé la pàgina, ch'a ancamin-a a scrive ant lë spassi sì-sota (vëdde la [$1 pàgina d'agiut] për savèjne ëd pì).\nS'a l'é rivà sì për eror, ch'a sgnaca ël boton '''andaré''' ëd sò navigador.",
- "anontalkpagetext": "----''Costa a l'é la pàgina ëd ciaciarade për n'utent anònim che a l'é ancó pa dorbusse un cont, ò pura che a lo deuvra nen. Alora i l'oma da dovré ël nùmer d'adrëssa IP për deje n'identificassion a chiel o chila.\nN'adrëssa IP përparèj a peul esse partagià da vàire utent.\nSe chiel a l'é n'utent anònim e a l'ha l'impression d'arsèive dij coment sensa sust, për piasì [[Special:UserLogin/signup|ch'a crea un cont]] o [[Special:UserLogin|ch'a rintra ant ël sistema]] për evité dë fé confusion con d'àutri utent anònim.''",
- "noarticletext": "Al moment costa pàgina a l'é veuida.\nA peul [[Special:Search/{{PAGENAME}}|sërché cost tìtol]] andrinta a d'àutre pàgine, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sërché ant ij registr colegà],\no purament [{{fullurl:{{FULLPAGENAME}}|action=edit}} modìfiché sta pàgina]</span>.",
+ "anontalkpagetext": "----\n<em>Costa a l'é la pàgina ëd ciaciarade për n'utent anònim che a l'é ancó pa duvertasse un cont, ò pura che a lo deuvra nen.</em>\nAlora i l'oma da dovré ël nùmer d'adrëssa IP për deje n'identificassion a chiel o chila.\nN'adrëssa IP përparèj a peul esse partagià da vàire utent.\nSe chiel a l'é n'utent anònim e a l'ha l'impression d'arsèive dij coment sensa sust, për piasì [[Special:CreateAccount|ch'a crea un cont]] o [[Special:UserLogin|ch'a rintra ant ël sistema]] për evité dë fé confusion con d'àutri utent anònim.''",
+ "noarticletext": "Al moment costa pàgina a l'é veuida.\nA peul [[Special:Search/{{PAGENAME}}|sërché cost tìtol]] andrinta a d'àutre pàgine, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sërché ant ij registr colegà],\no bin [{{fullurl:{{FULLPAGENAME}}|action=edit}} creé sta pàgina]</span>.",
"noarticletext-nopermission": "Al moment a-i é gnun test ansima a costa pàgina.\nA peul [[Special:Search/{{PAGENAME}}|sërché ës tìtol ëd pàgina]] an d'àutre pàgine,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sërché ant j'argistr colegà]</span>, ma a l'ha pa ël përmess ëd creé costa pàgina.",
"missing-revision": "La revision nùmer $1 dla pàgina antitolà «{{FULLPAGENAME}}» a esist pa.\n\nSòn a l'é normalment causà da l'andèje dapress a na vej liura stòrica a na pàgina ch'a l'é stàita scancelà. Ij detaj a peulo esse trovà ant ël [registr ëd jë scancelament ëd {{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}}].",
"userpage-userdoesnotexist": "Lë stranòm «<nowiki>$1</nowiki>» a l'é pa registrà. Për piasì ch'a varda se da bon a veul creé o modifiché costa pàgina.",
"whatlinkshere-prev": "{{PLURAL:$1|d'un andré|andré ëd $1}}",
"whatlinkshere-next": "{{PLURAL:$1|d'un anans|anans ëd $1}}",
"whatlinkshere-links": "← anliure",
- "whatlinkshere-hideredirs": "$1 le ridiression",
+ "whatlinkshere-hideredirs": "$1 ridiression",
"whatlinkshere-hidetrans": "$1 anclusion",
- "whatlinkshere-hidelinks": "$1 anliura",
+ "whatlinkshere-hidelinks": "$1 anliure",
"whatlinkshere-hideimages": "$1 j'archivi lijà",
"whatlinkshere-filters": "Filtr",
"autoblockid": "Blocagi automàtich #$1",
"javascripttest": "Preuva ëd JavaScript",
"javascripttest-pagetext-unknownaction": "Assion nen conossùa «$1».",
"javascripttest-qunit-intro": "Vëdde [$1 la documentassion dle preuve] dzora a mediawiki.org.",
- "tooltip-pt-userpage": "Soa pàgina utent",
+ "tooltip-pt-userpage": "{{GENDER:|Soa}} pàgina utent",
"tooltip-pt-anonuserpage": "La pàgina utent për l'IP con ël qual chiel a contribuiss",
- "tooltip-pt-mytalk": "Soa pàgina ëd discussion e ciaciarade",
+ "tooltip-pt-mytalk": "{{GENDER:|Soa}} pàgina ëd discussion",
"tooltip-pt-anontalk": "La pàgina ëd ciaciarade an sle contribussion da costa adrëssa IP",
- "tooltip-pt-preferences": "Coma che i veuj mia {{SITENAME}}.",
+ "tooltip-pt-preferences": "{{GENDER:|Ij tò}} gust",
"tooltip-pt-watchlist": "Lista dle pàgine che chiel as ten sot euj.",
- "tooltip-pt-mycontris": "Lista ëd soe contribussion",
+ "tooltip-pt-mycontris": "Lista ëd {{GENDER:|soe}} contribussion",
"tooltip-pt-login": "Un a l'é nen obligà a rintré ant al sistema, ma se a lo fa a l'é mej",
"tooltip-pt-logout": "Seurte da",
"tooltip-pt-createaccount": "I-j consejoma ëd creé un cont e ëd rintré ant ël sistema; però a l'é nen obligatòri",
"tooltip-t-recentchangeslinked": "Ùltime modìfiche dle pàgine andoa as peul andesse da costa.",
"tooltip-feed-rss": "Fluss RSS për costa pàgina",
"tooltip-feed-atom": "Fluss Atom për costa pàgina.",
- "tooltip-t-contributions": "Vardé la lista dle contribussion ëd cost utent",
+ "tooltip-t-contributions": "Vardé la lista dle contribussion ëd {{GENDER:$1|cost utent}}",
"tooltip-t-emailuser": "Mandeje un mëssagi ëd pòsta a st'utent",
"tooltip-t-info": "Pi d'anformassio su costa pàgina",
"tooltip-t-upload": "Carié n'archivi ëd figure ò son.",
"Amire80",
"Obaid Raza",
"Macofe",
- "Matma Rex"
+ "Matma Rex",
+ "Saanvel"
]
},
"tog-underline": "حوڑ تھلے لین:",
"tog-hideminor": "چھوٹیاں تبدیلیاں چھپاؤ",
"tog-hidepatrolled": "ویکھیاں تبدیلیاں لکاؤ",
"tog-newpageshidepatrolled": "نویاں صفیاں توں ویکھیاں تبدیلیاں لکاؤ",
+ "tog-hidecategorization": "صفحیاں دی گٹھ لکائو۔",
"tog-extendwatchlist": "نظر تھلے رکھے صفحے نوں ودھاو, تاں جے اوہ تبدیلیاں جیڑیاں کم دے قابل نیں ویکھیاں جا سکن",
"tog-usenewrc": "تھوڑا خر پہلے کیتیاں گیاں تبدیلیاں ورتو",
"tog-numberheadings": "آپ نمبر دین والیاں سرخیاں",
"tog-showtoolbar": "ایڈٹ ٹولبار وکھاؤ",
"tog-editondblclick": "صفیاں تے ڈبل کلک کرن تے تبدیلیاں لیاؤ",
- "tog-editsectiononrightclick": "سÛ\8cÚ©Ø´Ù\86 سرخÛ\8c تÛ\92 تبدÛ\8cÙ\84Û\8c Ù\84Û\8cاؤ سجÛ\8c کلک نال",
+ "tog-editsectiononrightclick": "سÛ\8cÚ©Ø´Ù\86 سرخÛ\8c تÛ\92 تبدÛ\8cÙ\84Û\8c Ù\84Û\8cاؤ سجÛ\92 کلک نال",
"tog-watchcreations": "جیہڑے صفے میں بناندا واں اوہ میری اکھ تھلے لسٹ چ کر دیو",
"tog-watchdefault": "جیہڑے صفے میں لکھداں اوہ میری اکھ تھلے لسٹ چ کر دیو",
"tog-watchmoves": "جیڈے صفحے میں لے چلداں اوہ میری اکھ تھلے کر دیو",
"noname": "تسی کوئی پکا ورتن آلا ناں نئیں رکھ رۓ۔",
"loginsuccesstitle": "تسی لاگن ہوگۓ او",
"loginsuccess": "'''ہن تسی {{SITENAME}} تے \"$1\" دے ناں توں لاگ ان او'''",
- "nosuchuser": "اس $1 ناں نال کوئی ورتن آلا نہیں۔\nاپنی لکھائی درست کرو یا نیا [[Special:UserLogin/signup|کھاتہ بناؤ]]۔",
+ "nosuchuser": "اس $1 ناں نال کوئی ورتن آلا نہیں۔\nاپنی لکھائی درست کرو یا نیا [[Special:CreateAccount|کھاتہ بناؤ]]۔",
"nosuchusershort": "اس \"$1\" ناں دا کوئی ورتن آلا نہيں اے۔\n\nاپنی الف، بے چیک کرو۔",
"nouserspecified": "توانوں اپنا ورتن آلا ناں دسنا ہوۓ گا۔",
"login-userblocked": "اے ورتن آلے روکیا ہویا اے۔ اے لاگ ان نئیں کرسکدا۔",
"accmailtext": "اک کنجی [[User talk:$1|$1]] $2 نوں پیج دتی گئی اے۔\nایس نویں کھاتے دی کنجی بدلی جاسکدی اے ''[[Special:ChangePassword|change password]]'' صفے تے لاگ ان ہون تے۔",
"newarticle": "(نواں)",
"newarticletext": "تسی ایسے صفحے دے جوڑ توں ایتھے پہنچے او جیڑا ھلے تک نہیں بنیا۔<br />\nاس صفحہ بنانے آسطے تھلے دتے گۓ ڈبے وچ لکھنا شروع کر دیو(زیادہ رہنمائی آستے اے ویکھو [$1 <br />مدد دا صفحہ])۔\nاگر تسی ایتھے غلطی نال پہنچے او تے اپنے کھوجی توں \"بیک\" دا بٹن دبا دیو۔",
- "anontalkpagetext": "----'' ایہ اک گمنام ورتن والے دا گل بات دا صفہ اے جینے ہلے کھاتہ نئیں کھولیا یا او اینون ورتدا نئیں۔\nسانوں فیر نمبراں والا آئی پی پتہ ورتنا پوے گا اونوں لئی. ایہو جیا آئی پی پتہ گئی ورتن والے ورت سکدے نیں۔ \nاگر تسیں اک گمنام ورتن والے او تے اے مسوس کردے او جے پیڑی گل بات تواڈی بارے ہوئی اے، مہربانی کرکے [[Special:UserLogin/signup|create an account]] یا [[Special:UserLogin|log in]] اگے کسے مسلے توں بچن گمنام ورتن والیاں کولوں",
+ "anontalkpagetext": "----'' ایہ اک گمنام ورتن والے دا گل بات دا صفہ اے جینے ہلے کھاتہ نئیں کھولیا یا او اینون ورتدا نئیں۔\nسانوں فیر نمبراں والا آئی پی پتہ ورتنا پوے گا اونوں لئی. ایہو جیا آئی پی پتہ گئی ورتن والے ورت سکدے نیں۔ \nاگر تسیں اک گمنام ورتن والے او تے اے مسوس کردے او جے پیڑی گل بات تواڈی بارے ہوئی اے، مہربانی کرکے [[Special:CreateAccount|create an account]] یا [[Special:UserLogin|log in]] اگے کسے مسلے توں بچن گمنام ورتن والیاں کولوں",
"noarticletext": "اس ویلے اس صفے تے کج نہیں لکھیا ہویا تسیں [[Special:Search/{{PAGENAME}}|اس صفے دے ناں نوں دوجے صفیاں تے کھوج سکدے او]] یا فیر [{{fullurl:{{FULLPAGENAME}}|action=edit}} اس صفے نوں لکھ سکدے او۔]",
"noarticletext-nopermission": "ایس ویلے ایس صفے تے کوئی لکھت نئیں۔ \nتسیں [[Special:Search/{{PAGENAME}}|search for this page title]] دوسریاں صفیاں تے،\nیا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} search the related logs]</span>۔",
"userpage-userdoesnotexist": "ورتن کھاتہ \"$1\" رجسٹر نئیں ہویا۔\nمہربانی کرکے دسو جے تسیں ای ھفا بنانا/بدلنا چاندے او۔",
"noname": "'Κ έβαλατε καλόν όνεμαν χρήστε.",
"loginsuccesstitle": "Έντον τ' εσέβεμαν",
"loginsuccess": "'''Εσήβετεν σο {{SITENAME}} με τ'όνεμαν \"$1\".'''",
- "nosuchuser": "Αδαπές 'κ εχ' χρήστεν με τ' όνομαν \"$1\".\nΤερέστεν τα γράμματα τη ονοματί, τερέστεν τα τρανογράμματα και τα μικρογράμματα να είναι τογρία.\nΤερέστεν την ορθογραφίαν ή [[Special:UserLogin/signup|ποισέστεν καινούρεον λογαρίαν]].",
+ "nosuchuser": "Αδαπές 'κ εχ' χρήστεν με τ' όνομαν \"$1\".\nΤερέστεν τα γράμματα τη ονοματί, τερέστεν τα τρανογράμματα και τα μικρογράμματα να είναι τογρία.\nΤερέστεν την ορθογραφίαν ή [[Special:CreateAccount|ποισέστεν καινούρεον λογαρίαν]].",
"nosuchusershort": "Αδαπές 'κ εχ' χρήστεν με τ' όνομαν \"$1\".\nΤ'όνομαν γραφέστεν ατο τογρία.",
"nouserspecified": "Πρέπ' να ψιλίζετε έναν όνεμαν.",
"login-userblocked": "Το χρήστεν έδεξαν ατον. Να εμπαίν 'κ ίνεται.",
"deleteotherreason": "Άλλον/αλλομίαν λόγον:",
"deletereasonotherlist": "Άλλον λόγον",
"rollback": "Φέρον ξαν σην υστερναίαν",
- "rollback_short": "Επαναφοράν",
"rollbacklink": "φέρον ξαν σην υστερναίαν",
"protectlogpage": "Αρχείον ασπαλιγματίων",
"protectedarticle": "ασπαλιζμένον \"[[$1]]\"",
"move-page-legend": "Ετεροχλάεμαν σελίδας",
"movepagetext": "Εάν εφτάτε το ψαλαφίον αφκά θα δείτε άλλον όνομαν σ' έναν σελίδαν και θα παίρτεν τ' ιστορικόνατς εκαικά. Το παλαιόν η σελίδαν θα μεταβάλκεται σε σύνδεσμον σην καινούραιαν.\n\nΕπορείτε να μεταβάλκετε τα συνδέσμαι που δεκνίζνε σο παλαιόν τη σελίδαν αυτόματα. Εάν 'κ φτάτε αέτς,\nευρέστεν [[Special:DoubleRedirects|διπλά]] για [[Special:BrokenRedirects|τσακωμένα συνδέσμ]].\nΈχετ' ευθύνην τα παλαιά τα συνδέσμαι να δεκνίζνε σο σωστόν τη σελίδαν.\n\nΗ σελίδαν ''''κ θ' αλλάζ'''' τη θέσηνατς όντες έχ' άλλον σελίδαν με το νέον τ' όνεμαν. Εξαίρεσην εν τ' εύκαιρα τα σελίδας και τα συνδέσμαι, ντο 'κ έχνε ιστορικόν.\nΕπορείτε δηλαδή να παίρετε τη σελίδαν σ' όνομαν ντ' είχεν προτεσνά. Άμα 'κ επορείτε με το ετεροχλάεμαν να σβήετε άλλον σελίδαν.\n\n'''ΩΡΙΑ!'''\nΑβούτεν η ενέργειαν επορεί να φέρει τρανά διαφοράς σ' έναν σελίδαν που δεβάζνε πολλοί.\nΝουνίστενατο καλά πριχού να εφτάτε τ' άλλαγμαν τ' ονοματί.",
"movepagetalktext": "Η σελίδαν καλατσεματί αυτόματα θα πηγαίν' εντάμαν, '''εξόν:'''\n*Έχ' άλλον σελίδαν καλατσεματί ντο 'κ εν εύκαιρον άμα έχ' το ίδιον τ' όνεμαν\n*θα ευκαιρώνετε το χουτίν αφκά.\n\nΕάν θέλετε να εφτάτε τα ένωμαν, να εφτάτε ατό με copy και paste.",
- "movearticle": "Ετεροχλάεμαν σελίδας:",
"newtitle": "Νέον τίτλον:",
"move-watch": "Ωρίαγμαν τη σελίδας",
"movepagebtn": "Ετεροχλάεμαν σελίδας",
"movelogpage": "Αρχείον ετεροχλαεματί",
"movereason": "Λόγον:",
"revertmove": "κλώσιμον",
- "delete_and_move": "Σβήσον και ετεροχλάεψον",
"export": "Εξαγωγήν σελίδιων",
"export-addcattext": "Βαλέστεν σελίδας ασήν κατηγορίαν:",
"export-addcat": "Βαλέστεν",
"importstart": "Έμπαζμαν σελιδίων...",
"import-noarticle": "'Κ εχ' σελίδαν για έμπαζμαν!",
"importlogpage": "Αρχείον εμπαζματίων",
- "import-logentry-interwiki": "εγέντον εισαγωγήν transwiki σην σελίδαν $1",
"tooltip-pt-userpage": "Τ' εσόν η σελίδαν",
"tooltip-pt-mytalk": "Τ' εσόν το καλάτσεμαν",
"tooltip-pt-preferences": "Τ' εμά τα προτιμήσεις",
"htmlform-selectorother-other": "Άλλον",
"rightsnone": "(τιδέν)",
"revdelete-summary": "σύνοψην",
- "searchsuggest-search": "Αράεμαν"
+ "searchsuggest-search": "Αράεμαν",
+ "special-characters-group-ipa": "ΔΦΑ",
+ "special-characters-group-telugu": "Τελούγκου"
}
"noname": "Sta ni ast tikrōmiska tērpautajas pabilisnā.",
"loginsuccesstitle": "Enēisenis izpalla",
"loginsuccess": "'''Assei teinū engūbun {{SITENAME}} kāigi \"$1\".'''",
- "nosuchuser": "Ni ast tērpautajs sen pabilīsnan \"$1\".\nZentlin debban en tērpautajas pabilīsnai ast zentlawingi.\nIzbandais peisāsnan anga [[Special:UserLogin/signup|teīkeis nāunan rekkenan]].",
+ "nosuchuser": "Ni ast tērpautajs sen pabilīsnan \"$1\".\nZentlin debban en tērpautajas pabilīsnai ast zentlawingi.\nIzbandais peisāsnan anga [[Special:CreateAccount|teīkeis nāunan rekkenan]].",
"nosuchusershort": "Ni ast tērpautajs sen pabilīsnan \"$1\".\nIzbandais peisāsnan.",
"nouserspecified": "Tu turri enpeisātun tērpautajas pabilīsnan.",
"wrongpassword": "Nitikrōmiskas kliptaswīrds. Bandais dabber rēizan.",
"accmailtitle": "Kliptaswīrds tengīntan.",
"newarticle": "(Nāuns)",
"newarticletext": "Tu assei autengīntan pra autengīnsenin en dabber niekzistīntin pāusan.\nKāi teīklai šin pāusan, pagaūneis enpeisātun en zemmaišasmu lāukan (wīdais [$1 help page] per tūls infōrmaciōnis).\nIk tū ni kwaitīwuns(si) teīktun nāunan pāusan, gnetteis \"Etwārtai\" knuppan en twajjai lasātlin.",
- "anontalkpagetext": "----''Sta ast anōnimas tērpautajas diskusiōnis pāusan - stawīdan, kawīds ni turri dabber swajjan rekkenan anga ni tērpaui din.\nKāi identificīlai tennan, tērpawimai IP adressins.\nAdder IP adressi mazzi būtwei dallautan pra tūlin tērpautajans.\nIk tu assei anōnims tērpautajs be tu mīri, kāi kumentārai stwi ni ast wartīntan prei tin, [[Special:UserLogin/signup|teīkeis rekkenan]] anga [[Special:UserLogin|enēis]] kāi aulānktun perejīngins kurtīsenins sen kittans anōnimans tērpautajs.''",
+ "anontalkpagetext": "----''Sta ast anōnimas tērpautajas diskusiōnis pāusan - stawīdan, kawīds ni turri dabber swajjan rekkenan anga ni tērpaui din.\nKāi identificīlai tennan, tērpawimai IP adressins.\nAdder IP adressi mazzi būtwei dallautan pra tūlin tērpautajans.\nIk tu assei anōnims tērpautajs be tu mīri, kāi kumentārai stwi ni ast wartīntan prei tin, [[Special:CreateAccount|teīkeis rekkenan]] anga [[Special:UserLogin|enēis]] kāi aulānktun perejīngins kurtīsenins sen kittans anōnimans tērpautajs.''",
"noarticletext": "Tēnti šin pāusan ni turri ēn sen tekstan.\nTu mazzi [[Special:Search/{{PAGENAME}}|laukītun šisse pāusas tītelin]] en kitēimans pāusans,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pralaukītun registerin],\nanga [{{fullurl:{{FULLPAGENAME}}|action=edit}} redigītun šin pāusan]</span>.",
"userpage-userdoesnotexist": "Tērpautajs \"<nowiki>$1</nowiki>\" ni ast registrītan.\nIzbāndais, anga tū perarwi kwaitīwuns teīktun/redigītun šin pāusan.",
"userpage-userdoesnotexist-view": "Tērpautajas rekkens \"$1\" ni ast registrītan.",
"아라",
"عثمان خان شاہ",
"Macofe",
- "Amire80"
+ "Amire80",
+ "Matma Rex"
]
},
"tog-underline": "کرښنې تړنې:",
"noname": "تاسې تر اوسه پورې کوم کره کارن نوم نه دی ځانگړی کړی.",
"loginsuccesstitle": "غونډال کې ورننوتلۍ",
"loginsuccess": "'''تاسې اوس {{SITENAME}} کې د \"$1\" په نوم ننوتي ياست.'''",
- "nosuchuser": "د \"$1\" په نوم هېڅ کارن نشته.\nد کارنانو نومونه د غټو او واړو تورو سره حساس دي.\nخپل حجا وڅارۍ، او يا هم [[Special:UserLogin/signup|يو نوی گڼون جوړ کړی]].",
+ "nosuchuser": "د \"$1\" په نوم هېڅ کارن نشته.\nد کارنانو نومونه د غټو او واړو تورو سره حساس دي.\nخپل حجا وڅارۍ، او يا هم [[Special:CreateAccount|يو نوی گڼون جوړ کړی]].",
"nosuchusershort": "د \"$1\" په نوم هېڅ کوم گڼون نشته. لطفاً خپل د نوم ليکلې بڼې ته ځير شی چې پکې تېروتنه نه وي.",
"nouserspecified": "تاسې ځان ته کوم کارن نوم نه دی ځانگړی کړی.",
"login-userblocked": "په دې کارن بنديز لگېدلی. غونډال کې ننوتلو ته پرې نه ښودلی شو.",
"passwordreset-emailelement": "کارن-نوم: \n$1\n\nلنډمهاله پټنوم: \n$2",
"passwordreset-emailsentemail": "د پټنوم بيا پرځای کېدنې لپاره برېښليک درولېږل شو.",
"passwordreset-emailsent-capture": "د پټنوم بياپرځای کېدنې لپار مو يو برېښليک درولېږه، برېښليک په لاندې توگه ښودل شوی.",
+ "passwordreset-invalideamil": "ناسمه برېښليک پته",
"changeemail": "برېښليک پته بدلول يا ليرې کول",
"changeemail-header": "د گڼون برېښليک پته بدلول",
"changeemail-no-info": "دې مخ ته د لاسرسي لپاره بايد غونډال کې ورننوځۍ.",
"accmailtitle": "پټنوم ولېږل شو.",
"newarticle": "(نوی)",
"newarticletext": "تاسې د يوې داسې تړنې څارنه کړې چې لا تر اوسه پورې نه شته.\nکه همدا مخ ليکل غواړۍ، نو په لانديني چوکاټ کې خپل متن وټاپئ (د لا نورو مالوماتو لپاره د [$1 لارښود مخ] وگورئ).\nکه چېرته تاسې دلته په تېروتنه راغلي ياست، نو يواځې د خپل د کتنمل '''مخ پر شا''' تڼۍ مو وټوکئ.",
- "anontalkpagetext": "----''دا د يوه ورکنومي کارن چې کارن-نوم نه لري او يا خپل کارن-نوم نه کاروي، د سکالو يوه پاڼه ده. نو د يوه کس د پېژندلو پخاطر موږ د هماغه کارن د انټرنېټ شمېره يا IP پته دلته ثبتوؤ. داسې يوه IP پته د ډېرو کارنانو لخوا هم کارېدلی شي. که تاسې يو ورکنومی کارن ياست او تاسې ته دا څرگندېږي چې تاسې ته نااړونده پېغامونه او تبصرې اشاره شوي، نو د نورو بې نومو کارنانو او ستاسې ترمېنځ د ټکنتوب د مخ نيونې لپاره لطفاً [[Special:UserLogin/signup|يو گڼون جوړ کړۍ]] او يا هم [[Special:UserLogin|غونډال ته ورننوځۍ]].''",
+ "anontalkpagetext": "----''دا د يوه ورکنومي کارن چې کارن-نوم نه لري او يا خپل کارن-نوم نه کاروي، د سکالو يوه پاڼه ده. نو د يوه کس د پېژندلو پخاطر موږ د هماغه کارن د انټرنېټ شمېره يا IP پته دلته ثبتوؤ. داسې يوه IP پته د ډېرو کارنانو لخوا هم کارېدلی شي. که تاسې يو ورکنومی کارن ياست او تاسې ته دا څرگندېږي چې تاسې ته نااړونده پېغامونه او تبصرې اشاره شوي، نو د نورو بې نومو کارنانو او ستاسې ترمېنځ د ټکنتوب د مخ نيونې لپاره لطفاً [[Special:CreateAccount|يو گڼون جوړ کړۍ]] او يا هم [[Special:UserLogin|غونډال ته ورننوځۍ]].''",
"noarticletext": "دم مهال په دې مخ کې څه نشته.\nتاسې کولای شی چې په نورو مخونو کې [[Special:Search/{{PAGENAME}}|د دې مخ د سرليک پلټنه]]،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} د اړوندو يادښتونو پلټنه] ،\nاو يا [{{fullurl:{{FULLPAGENAME}}|action=edit}} همدا مخ جوړ کړئ]</span>.",
"noarticletext-nopermission": "دم مهال په دې مخ کې متن نشته.\nتاسې کولای شی چې [[Special:Search/{{PAGENAME}}|همدا سرليک په نورو مخونو کې وپلټۍ]], يا هم <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} اړونده يادښتونه وپلټۍ]</span>، خو تاسې د دې مخ د جوړولو اجازه نه لرۍ.",
"userpage-userdoesnotexist": "د \"<nowiki>$1</nowiki>\" گڼون نه دی ثبت شوی.\nلطفاً ځان ډاډه کړئ چې آيا تاسې په رښتيا همدا مخ جوړول/سمول غواړئ.",
"whatlinkshere-next": "{{PLURAL:$1|راتلونکی|راتلونکي $1}}",
"whatlinkshere-links": "← تړنې",
"whatlinkshere-hideredirs": "مخ گرځونې $1",
- "whatlinkshere-hidetrans": "پاÙ\8aÙ\84ې $1",
+ "whatlinkshere-hidetrans": "Ù\88رگÚ\89Û\90دÙ\86ې $1",
"whatlinkshere-hidelinks": "تړنې $1",
"whatlinkshere-hideimages": "د دوتنې تړنې $1",
"whatlinkshere-filters": "چاڼگرونه",
"exif-primarychromaticities": "د لومړيتوبونو رنگينتوبونه",
"exif-datetime": "د دوتنې د بدلون وخت او نېټه",
"exif-imagedescription": "انځور سرليک",
- "exif-make": "د کامرې جوړونکی",
+ "exif-make": "کامره جوړونکی",
"exif-model": "د کامرې ماډل",
"exif-software": "کارېدلې ساوترۍ",
"exif-artist": "ليکوال",
"exif-pixelydimension": "د انځور جگوالی",
"exif-usercomment": "د کارن تبصرې",
"exif-relatedsoundfile": "اړونده غږيزه دوتنه",
- "exif-datetimeoriginal": "د اÙ\88Ù\85تÙ\88Ú© د جÙ\88Ú\93Û\90دÙ\86Û\90 Ù\88خت اÙ\88 Ù\86Û\90Ù¼Ù\87",
- "exif-datetimedigitized": "د گڼياليز کېدنې وخت او نېټه",
+ "exif-datetimeoriginal": "د اومتوک جوړېدنې وخت او نېټه",
+ "exif-datetimedigitized": "د گڼياليزېدنې وخت او نېټه",
"exif-exposuretime": "رڼاغورځونې وخت",
"exif-exposuretime-format": "$1 ثانيه ($2)",
"exif-fnumber": "F شمېره",
"confirm-watch-top": "همدا مخ خپل کتنلړ کې ورگډوې؟",
"confirm-unwatch-button": "ښه",
"confirm-unwatch-top": "همدا مخ خپل کتنلړ څخه لرې کوې؟",
+ "confirm-rollback-button": "هوکې",
"percent": "$1%",
"parentheses": "($1)",
"brackets": "[$1]",
"watchlistedit-raw-done": "ستاسې کتنلړ اوسمهاله شو.",
"watchlistedit-raw-added": "{{PLURAL:$1|1 سرليک ورگډ شو|$1 سرليکونه ورگډ شوه}}:",
"watchlistedit-raw-removed": "{{PLURAL:$1|1 سرليک ليرې شو|$1 سرليکونه ليري شوه}}:",
- "watchlistedit-clear-title": "کتنلړ سپين شو",
+ "watchlistedit-clear-title": "کتنلړ سپينول",
"watchlistedit-clear-legend": "کتنلړ سپينول",
"watchlistedit-clear-titles": "سرليکونه:",
"watchlistedit-clear-submit": "کتنلړ سپينول (دا دايمي ده!)",
"mw-widgets-titleinput-description-redirect": "$1 ته ورگرځېدنه",
"randomrootpage": "د ناټاکلې ريښې مخ",
"log-action-filter-all": "ټول",
- "log-action-filter-block-block": "بنديز لگول"
+ "log-action-filter-block-block": "بنديز لگول",
+ "authmanager-email-label": "برېښليک",
+ "authmanager-email-help": "برېښليک پته",
+ "authmanager-realname-label": "اصلي نوم",
+ "authmanager-realname-help": "د کارن اصلي نوم",
+ "authprovider-resetpass-skip-label": "تېرېدل",
+ "changecredentials-submit": "بدلول",
+ "removecredentials-submit": "غورځول",
+ "credentialsform-account": "گڼون نوم:"
}
"Caçador de Palavras",
"Luk3",
"Ryuu",
- "Luan"
+ "Luan",
+ "Anderson Costa"
]
},
"tog-underline": "Sublinhar links:",
"noname": "Você não colocou um nome de usuário válido.",
"loginsuccesstitle": "Autenticado",
"loginsuccess": "'''Agora você está {{GENDER:autenticado|autenticada}} ao wiki {{SITENAME}} como \"$1\"'''.",
- "nosuchuser": "Não existe nenhum usuário com o nome \"$1\".\nOs nomes de usuário são sensíveis a letras maiúsculas.\nVerifique o que foi digitado ou [[Special:UserLogin/signup|crie uma nova conta]].",
+ "nosuchuser": "Não existe nenhum usuário com o nome \"$1\".\nOs nomes de usuário são sensíveis a letras maiúsculas.\nVerifique o que foi digitado ou [[Special:CreateAccount|crie uma nova conta]].",
"nosuchusershort": "Não existe um usuário com o nome \"$1\". Verifique o nome que introduziu.",
"nouserspecified": "Você precisa especificar um nome de usuário.",
"login-userblocked": "Este usuário está bloqueado. Entrada proibida.",
"accmailtext": "Uma senha gerada aleatoriamente para [[User talk:$1|$1]] foi enviada para $2.\n\nEla pode ser alterada na página ''[[Special:ChangePassword|de troca de senha]]'', após o início de sessão.",
"newarticle": "(Nova)",
"newarticletext": "Você seguiu um link para uma página que ainda não existe.\nPara criá-la, comece escrevendo na caixa abaixo (veja [$1 a página de ajuda] para mais informações).\nSe você chegou aqui por engano, clique no botão '''voltar''' do seu navegador.",
- "anontalkpagetext": "---- ''Esta é a página de discussão para um usuário anônimo que ainda não criou uma conta ou que não a usa, de forma que temos de utilizar o endereço de IP para identificá-lo(a). Tal endereço de IP pode ser compartilhado por vários usuários. Se você é um usuário anônimo e acha que comentários irrelevantes foram direcionados a você, por gentileza, [[Special:UserLogin/signup|crie uma conta]] ou [[Special:UserLogin|autentique-se]], a fim de evitar futuras confusões com outros usuários anônimos.''",
+ "anontalkpagetext": "---- ''Esta é a página de discussão para um usuário anônimo que ainda não criou uma conta ou que não a usa, de forma que temos de utilizar o endereço de IP para identificá-lo(a). Tal endereço de IP pode ser compartilhado por vários usuários. Se você é um usuário anônimo e acha que comentários irrelevantes foram direcionados a você, por gentileza, [[Special:CreateAccount|crie uma conta]] ou [[Special:UserLogin|autentique-se]], a fim de evitar futuras confusões com outros usuários anônimos.''",
"noarticletext": "Não há conteúdo nesta página no momento.\nVocê pode [[Special:Search/{{PAGENAME}}|pesquisar pelo título desta página]] em outras páginas, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar por registros relacionados],\nou [{{fullurl:{{FULLPAGENAME}}|action=edit}} criar esta página]</span>.",
"noarticletext-nopermission": "No momento, não há conteúdo nesta página\nVocê pode [[Special:Search/{{PAGENAME}}|pesquisar pelo título desta página]] em outras páginas,\nou <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar por registros relacionados] </span>. Note que, no entanto, você não tem permissão para criar esta página.",
"missing-revision": "A revisão #$1 da página denominada \"{{FULLPAGENAME}}\" não existe.\n\nIsto é geralmente causado por seguir um link de histórico desatualizado para uma página que foi eliminada.\nOs detalhes podem ser encontrados no [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de eliminação].",
"upload-form-label-own-work": "Isto é o meu próprio trabalho",
"upload-form-label-infoform-categories": "Categorias",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-not-own-work-local-local": "Você pode também querer tentar [[Special:Upload|the default upload page]]",
+ "upload-form-label-not-own-work-local-generic-local": "Você pode também querer tentar [[Special:Upload|the default upload page]]",
"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.",
"apisandbox": "Caixa de areia da API",
"apisandbox-api-disabled": "A API está desabilitada neste site.",
"apisandbox-intro": "Use esta página para realizar testes com o '''serviço web de API do MediaWiki'''.\nConsulte a [//www.mediawiki.org/wiki/API:Main_page a documentação API] para obter mais detalhes de uso da API. Exemplo: [//www.mediawiki.org/wiki/API#A_simple_example obter o conteúdo de uma Página principal]. Selecione uma ação para mais exemplos.\n\nNote que, embora esta seja uma área de testes, as ações que executar nesta página podem modificar a wiki.",
+ "apisandbox-unfullscreen": "Mostrar página",
"apisandbox-submit": "Fazer requisição",
"apisandbox-reset": "Limpar",
"apisandbox-retry": "Tentar novamente",
"whatlinkshere-links": "← afluentes",
"whatlinkshere-hideredirs": "$1 redirecionamentos",
"whatlinkshere-hidetrans": "$1 transclusões",
- "whatlinkshere-hidelinks": "$1 links",
- "whatlinkshere-hideimages": "$1 links para arquivos",
+ "whatlinkshere-hidelinks": "$1 ligações",
+ "whatlinkshere-hideimages": "$1 ligações para arquivos",
"whatlinkshere-filters": "Filtros",
"whatlinkshere-submit": "Avançar",
"autoblockid": "Autobloqueio #$1",
"timezone-local": "Local",
"duplicate-defaultsort": "Aviso: A chave de ordenação padrão \"$2\" sobrepõe-se à anterior chave de ordenação padrão \"$1\".",
"duplicate-displaytitle": "<strong>Aviso:</strong> O título exibido \"$2\" substituí o título anterior \"$1\".",
+ "restricted-displaytitle": "<strong>Aviso:</strong> O título de exibição “$1” foi ignorado devido a não ser equivalente ao título verdadeiro da página.",
"invalid-indicator-name": "<strong>Erro:</strong> O atributo indicador do status da página <code>name</code> não deve estar vazio.",
"version": "Versão",
"version-extensions": "Extensões instaladas",
"noname": "Não especificou um nome de utilizador válido.",
"loginsuccesstitle": "Autenticação bem sucedida",
"loginsuccess": "'''Encontra-se agora ligado à {{SITENAME}} como \"$1\"'''.",
- "nosuchuser": "Não existe nenhum utilizador com o nome \"$1\".\nOs nomes de utilizador são sensíveis à capitalização.\nVerifique a ortografia, ou [[Special:UserLogin/signup|crie uma nova conta]].",
+ "nosuchuser": "Não existe nenhum utilizador com o nome \"$1\".\nOs nomes de utilizador são sensíveis à capitalização.\nVerifique a ortografia, ou [[Special:CreateAccount|crie uma nova conta]].",
"nosuchusershort": "Não existe um utilizador com o nome \"$1\". Verifique o nome que introduziu.",
"nouserspecified": "Precisa de especificar um nome de utilizador.",
"login-userblocked": "Este utilizador está bloqueado. Não é permitido o acesso.",
"accmailtext": "Uma palavra-passe gerada aleatoriamente para [[User talk:$1|$1]] foi enviada para $2.\n\nEla pode ser alterada na página [[Special:ChangePassword|de alteração da palavra-passe]] após iniciar sessão.",
"newarticle": "(Nova)",
"newarticletext": "Seguiu uma ligação para uma página que ainda não existe.\nPara criá-la, escreva o seu conteúdo na caixa abaixo (consulte a [$1 página de ajuda] para mais detalhes).\nSe chegou aqui por engano, clique o botão '''voltar''' (ou ''back'') do seu navegador.",
- "anontalkpagetext": "----''Esta é a página de discussão de um utilizador anónimo que ainda não criou uma conta ou não a utiliza, pelo que temos de utilizar o endereço IP para identificá-lo(a).\nUm endereço IP pode ser partilhado por vários utilizadores.\nSe é um utilizador anónimo e sente que lhe foram direcionados comentários irrelevantes, por favor [[Special:UserLogin/signup|crie uma conta]] ou [[Special:UserLogin|inicie sessão]] para evitar futuras confusões com outros utilizadores anónimos.''",
+ "anontalkpagetext": "----''Esta é a página de discussão de um utilizador anónimo que ainda não criou uma conta ou não a utiliza, pelo que temos de utilizar o endereço IP para identificá-lo(a).\nUm endereço IP pode ser partilhado por vários utilizadores.\nSe é um utilizador anónimo e sente que lhe foram direcionados comentários irrelevantes, por favor [[Special:CreateAccount|crie uma conta]] ou [[Special:UserLogin|inicie sessão]] para evitar futuras confusões com outros utilizadores anónimos.''",
"noarticletext": "Ainda não existe texto nesta página.\nPode [[Special:Search/{{PAGENAME}}|pesquisar o título desta página]] noutras páginas,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} procurar registos relacionados]\nou [{{fullurl:{{FULLPAGENAME}}|action=edit}} editar esta página]</span>.",
"noarticletext-nopermission": "Ainda não existe texto nesta página.\nPode [[Special:Search/{{PAGENAME}}|pesquisar o título desta página]] noutras páginas, ou <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} procurar nos registos relacionados]</span>, mas não tem permissão para criar esta página.",
"missing-revision": "A revisão #$1 da página denominada \"{{FULLPAGENAME}}\" não existe.\n\nIsto é geralmente causado por seguir uma ligação de histórico desatualizada para uma página que foi eliminada.\nOs detalhes podem ser encontrados no [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registo de eliminação].",
"upload-form-label-own-work": "Este é minha obra própria",
"upload-form-label-infoform-categories": "Categorias",
"upload-form-label-infoform-date": "Data",
- "upload-form-label-own-work-message-local": "Confirmo que estou a carregar este ficheiro segundo as condições de serviço e política de licenças de {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Se não é capaz de carregar este ficheiro sob as políticas de {{SITENAME}}, por favor feche esta janela e tente outro método.",
- "upload-form-label-not-own-work-local-local": "Poderá querer experimentar [[Special:Upload|a página padrão de carregamento]].",
- "upload-form-label-own-work-message-default": "Entendo que estou a carregar este ficheiro em um repositório partilhado. Confirmo que estou a fazê-lo cumprindo com os termos de serviço e com as políticas de licenciamento.",
- "upload-form-label-not-own-work-message-default": "Se não é capaz de carregar este ficheiro sob as políticas do repositório partilhado, por favor feche esta janela e tente outro método.",
- "upload-form-label-not-own-work-local-default": "Pode querer tentar utilizar [[Special:Upload|a página de carregamento em {{SITENAME}}]], se este ficheiro puder ser carregado de acordo com suas as políticas.",
- "upload-form-label-own-work-message-shared": "Confirmo que sou o proprietário dos direitos de autor deste ficheiro, e aceito partilhar irrevogavelmente este ficheiro para o Wikimedia Commons nos termos da licença [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Atribuição-CompartilhaIgual 4.0], e concordo com os [https://wikimediafoundation.org/wiki/Terms_of_Use Termos de Utilização].",
- "upload-form-label-not-own-work-message-shared": "Se não é o proprietário dos direitos de autor deste ficheiro, ou caso deseje partilhá-lo sob uma licença diferente, considere utilizar o [https://commons.wikimedia.org/wiki/Special:UploadWizard Assistente de Envio de Ficheiros do Commons].",
- "upload-form-label-not-own-work-local-shared": "Pode querer tentar utilizar [[Special:Upload|a página de carregamento em {{SITENAME}}]], se o sítio aceitar o carregamento deste ficheiro de acordo com as suas políticas.",
+ "upload-form-label-own-work-message-generic-local": "Confirmo que estou a carregar este ficheiro segundo as condições de serviço e política de licenças de {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Se não é capaz de carregar este ficheiro sob as políticas de {{SITENAME}}, por favor feche esta janela e tente outro método.",
+ "upload-form-label-not-own-work-local-generic-local": "Poderá querer experimentar [[Special:Upload|a página padrão de carregamento]].",
+ "upload-form-label-own-work-message-generic-foreign": "Entendo que estou a carregar este ficheiro em um repositório partilhado. Confirmo que estou a fazê-lo cumprindo com os termos de serviço e com as políticas de licenciamento.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Se não é capaz de carregar este ficheiro sob as políticas do repositório partilhado, por favor feche esta janela e tente outro método.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Pode querer tentar utilizar [[Special:Upload|a página de carregamento em {{SITENAME}}]], se este ficheiro puder ser carregado de acordo com suas as políticas.",
"backend-fail-stream": "Não foi possível transmitir o ficheiro \"$1\".",
"backend-fail-backup": "Não foi possível fazer cópia de segurança do ficheiro \"$1\".",
"backend-fail-notexists": "O ficheiro $1 não existe.",
"rollbacklinkcount": "reverter $1 {{PLURAL:$1|edição|edições}}",
"rollbacklinkcount-morethan": "reverter mais do que $1 {{PLURAL:$1|edição|edições}}",
"rollbackfailed": "A reversão falhou",
+ "rollback-missingparam": "Faltam parâmetros obrigatórios no pedido.",
"cantrollback": "Não foi possível reverter a edição; o último contribuidor é o único autor desta página",
"alreadyrolled": "Não foi possível reverter as edições de [[:$1]] por [[User:$2|$2]] ([[User talk:$2|discussão]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nalguém editou ou já reverteu a página.\n\nA última edição foi de [[User:$3|$3]] ([[User talk:$3|discussão]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "O resumo da edição era: <em$1</em>.",
"revertpage": "Foram revertidas as edições de [[Special:Contributions/$2|$2]] ([[User talk:$2|disc]]) para a última revisão de [[User:$1|$1]]",
"revertpage-nouser": "Foram revertidas as edições de um utilizador oculto para a última revisão de {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Foram revertidas as edições de $1, com o conteúdo passando a estar como na última edição de $2.",
+ "rollback-success-notify": "Foram revertidas as edições de $1 para a última revisão de $2. [$3 Mostrar alterações]",
"sessionfailure-title": "Erro de sessão",
"sessionfailure": "Foram detectados problemas com a sua sessão;\na operação foi cancelada como medida de proteção contra a interceptação de sessões.\nVolte à página anterior, recarregue-a e tente novamente.",
"changecontentmodel": "Editar o modelo de conteúdo de uma página",
"whatlinkshere-links": "← afluentes",
"whatlinkshere-hideredirs": "$1 redirecionamentos",
"whatlinkshere-hidetrans": "$1 transclusões",
- "whatlinkshere-hidelinks": "$1 ligações",
- "whatlinkshere-hideimages": "$1 ligações para ficheiros",
+ "whatlinkshere-hidelinks": "$1 links",
+ "whatlinkshere-hideimages": "$1 links para arquivos",
"whatlinkshere-filters": "Filtros",
"whatlinkshere-submit": "Ir",
"autoblockid": "Bloqueio automático nº$1",
"confirm-watch-top": "Adicionar esta página à lista de páginas vigiadas?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Remover esta página da lista de páginas vigiadas?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Reverter as edições desta página?",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← página anterior",
"imgmultipagenext": "página seguinte →",
"Robin van der Vliet",
"Conquistador",
"Frigory",
- "Psychoslave"
+ "Psychoslave",
+ "Guycn2",
+ "2axterix2",
+ "Ата"
]
},
"sidebar": "{{notranslate}}",
"password-change-forbidden": "Error message shown when an external authentication source does not allow the password to be changed.",
"externaldberror": "This message is thrown when a valid attempt to change the wiki password for a user fails because of a database error or an error from an external system.",
"login": "{{Doc-special|UserLogin|unlisted=1}}\n{{Identical|Log in}}",
+ "login-security": "Used as the title of the login page when the user is already logged in but sent to reauthenticate before getting access to a feature with elevated security.",
"nav-login-createaccount": "Shown to anonymous users in the upper right corner of the page. When you can't create an account, the message {{msg-mw|login}} is shown.\n{{Identical|Log in / create account}}",
"loginprompt": "{{ignored}}",
"userlogin": "Since 1.22 no longer used in core, but may still be used by extensions. DEPRECATED\n\n{{Identical|Log in / create account}}",
"helplogin-url": "{{doc-important|Do not translate the namespace name <code>Help</code>.}}\nUsed as name of the page that provides information about logging into the wiki.\n\nUsed as a link target in the message {{msg-mw|Userlogin-helplink}}.",
"userlogin-helplink2": "Label for a link to login help.\n\nSee example: [[Special:UserLogin]]\n\nSee also:\n* {{msg-mw|Helplogin-url}}",
"userlogin-loggedin": "Used as warning on [[Special:UserLogin]] when the current user is already logged in.\n\nFollowed by the Login form.\n\nSee example: [[Special:UserLogin]].\n\nParameters:\n* $1 - user name (used for display and for gender support)\nSee also:\n* {{msg-mw|Mobile-frontend-userlogin-loggedin-register}}",
+ "userlogin-reauth": "Used as an explanatory message on [[Special:UserLogin]] when the user is redirected there to log in again when trying to use a security-sensitive page.\n\nParameters:\n* $1 - user name (used for display and for gender support)",
"userlogin-createanother": "Used as label for the button on [[Special:UserLogin]] shown when the current user is already logged in.\n{{Identical|Create another account}}",
"createacct-emailrequired": "Label in create account form for email field when it is required.\n\nSee also:\n* {{msg-mw|Createacct-emailoptional}}\n{{Identical|E-mail address}}",
"createacct-emailoptional": "Label in vertical-layout create account form for email field when it is optional.\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]\n\nSee also:\n* {{msg-mw|Createacct-emailrequired}}",
"createacct-email-ph": "Placeholder in vertical-layout create account form for email field.\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]",
"createacct-another-email-ph": "Placeholder in create account form for email field when one user creates an account for another.",
- "createaccountmail": "The label for the checkbox for creating a new account and sending the new password to the specified email address directly, as used on [[Special:UserLogin/signup]] when one user creates an account for another (if creating accounts by email is allowed).\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]",
+ "createaccountmail": "The label for the checkbox for creating a new account and sending the new password to the specified email address directly, as used on [[Special:CreateAccount]] when one user creates an account for another (if creating accounts by email is allowed).\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]",
+ "createaccountmail-help": "Account creation API help message for the <code>mailpassword</code> parameter.",
"createacct-realname": "In vertical-layout create account form, label for field to enter optional real name.",
"createaccountreason": "Since 1.22 no longer used in core, but may be used by some extensions. DEPRECATED\n\n{{Identical|Reason}}",
"createacct-reason": "In create account form, label for field to enter reason to create an account when already logged-in.\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]\n{{Identical|Reason}}",
"createacct-reason-ph": "Placeholder in vertical-layout create account form for reason field.\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]",
+ "createacct-reason-help": "Account creation API help message for the <code>reason</code> parameter.",
"createacct-imgcaptcha-help": "{{Optional}} Optional help text in vertical-layout create account form for image CAPTCHA input field when repositioned by JavaScript.\n\nBlank by default.",
"createacct-submit": "Submit button on vertical-layout create account form.\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]",
- "createacct-another-submit": "Submit button of [[Special:UserLogin/signup]] ([[Special:CreateAccount]]) when accessed by a registered user.\n\nThe original means \"create an account in addition to the one you already have\"; sometimes, but not always, it means you are going to \"Create the account on behalf of somebody else\" or \"Create account for another\".\n{{Identical|Create another account}}",
+ "createacct-another-submit": "Submit button of [[Special:CreateAccount]] when accessed by a registered user.\n\nThe original means \"create an account in addition to the one you already have\"; sometimes, but not always, it means you are going to \"Create the account on behalf of somebody else\" or \"Create account for another\".\n{{Identical|Create another account}}",
+ "createacct-continue-submit": "Submit button on create account form in second and later steps of a multistep account creation.",
+ "createacct-another-continue-submit": "Submit button on create account form in second and later steps of a multistep account creation, when done by a registered user.",
"createacct-benefit-heading": "In vertical-layout create account form, the heading for the section describing the benefits of creating an account. See example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]\n\nIf in your language you need to know the gender of the name for the wiki (which is the subject of the English sentence), please adapt the sentence as much as you need for your translation to fit.",
"createacct-benefit-icon1": "In vertical-layout create account form, the CSS style for the div next to the first benefit. If you replace this you will need probably need to adjust CSS.\n\nUsed as a CSS class name.\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup&useNew=1}} Special:UserLogin?type=signup&useNew=1]",
"createacct-benefit-head1": "In vertical-layout create account form, the text in the heading for the first benefit. Do not edit the magic word; if you replace it you will probably need to adjust CSS.\n\nFollowed by the message {{msg-mw|Createacct-benefit-body1}}.\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup&useNew=1}} Special:UserLogin?type=signup&useNew=1]",
"nocookieslogin": "This message is displayed when someone tried to login, but the browser doesn't accept cookies.",
"nocookiesfornew": "This message is displayed when the user tried to create a new account, but it failed the cross-site request forgery (CSRF) check. It could be blocking an attack, but most likely, the browser isn't accepting cookies.",
"nocookiesforlogin": "{{optional}}\nThis message is displayed when someone tried to login and the CSRF failed (most likely, the browser doesn't accept cookies).\n\nDefault:\n* {{msg-mw|Nocookieslogin}}",
+ "createacct-loginerror": "This message is displayed after a successful registration when there is a server-side error with logging the user in. This is not expected to happen.",
"noname": "Error message.",
"loginsuccesstitle": "The title of the page saying that you are logged in. The content of the page is the message {{msg-mw|Loginsuccess}}.\n{{Identical|Log in}}",
"loginsuccess": "The content of the page saying that you are logged in. The title of the page is {{msg-mw|Loginsuccesstitle}}.\n\nParameters:\n* $1 - the name of the logged in user\n{{Gender}}",
"createacct-another-realname-tip": "{{doc-singularthey}}\nUsed on the account creation form when creating another user's account. Similar to {{msg-mw|prefs-help-realname}}.\n{{Identical|Real name attribution}}",
"pt-login": "Shown to anonymous users in the upper right corner of the page when they can't create an account (otherwise the message {{msg-mw|nav-login-createaccount}} is shown there).\n{{Identical|Log in}}",
"pt-login-button": "Shown as the caption of the button at [[Special:UserLogin]].\n{{Identical|Log in}}",
+ "pt-login-continue-button": "Shown as the caption of the button at [[Special:UserLogin]] in second and later steps of a multipage login.",
"pt-createaccount": "Used on the top of the page for logged out users, where it appears next to {{msg-mw|login}}, so consider making them similar.\n{{Identical|Create account}}",
"pt-userlogout": "{{Doc-actionlink}}\n{{Identical|Log out}}",
"pear-mail-error": "{{notranslate}}\nParameters:\n* $1 - error message which is returned by PEAR mailer.",
"botpasswords-invalid-name": "Error message when a username lacking the separator character is passed to BotPassword. Parameters:\n* $1 - The separator character.",
"botpasswords-not-exist": "Error message when a username exists but does not a bot password for the given \"bot name\". Parameters:\n* $1 - username\n* $2 - bot name",
"resetpass_forbidden": "Used as error message in changing password. Maybe the external auth plugin won't allow local password changes.",
+ "resetpass_forbidden-reason": "Like {{msg-mw|resetpass_forbidden}} but the auth provider gave a reason.\n\nParameters:\n* $1 - reason given by auth provider",
"resetpass-no-info": "Error message for [[Special:ChangePassword]].\n\nParameters:\n* $1 (unused) - a link to [[Special:UserLogin]] with {{msg-mw|loginreqlink}} as link description",
"resetpass-submit-loggedin": "Button on [[Special:ResetPass]] to submit new password.\n\n{{Identical|Change password}}",
"resetpass-submit-cancel": "Used on [[Special:ResetPass]].\n{{Identical|Cancel}}",
"passwordreset-emailsentusername": "Used in [[Special:PasswordReset]].\n\nSee also:\n* {{msg-mw|Passwordreset-emailsent-capture}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
"passwordreset-emailsent-capture": "Used in [[Special:PasswordReset]].\n\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
"passwordreset-emailerror-capture": "Error message displayed in [[Special:PasswordReset]] when sending an email fails. Parameters:\n* $1 - error message\n* $2 - username, used for GENDER\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailsent-capture}}",
+ "passwordreset-emailsent-capture2": "Used in [[Special:PasswordReset]].\n\nParameters:\n* $1 - number of accounts notified\n\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
+ "passwordreset-emailerror-capture2": "Error message displayed in [[Special:PasswordReset]] when sending an email fails. Parameters:\n* $1 - error message\n* $2 - username, used for GENDER\n* $3 - number of accounts notified\n\nSee also:\n* {{msg-mw|Passwordreset-emailsentemail}}\n* {{msg-mw|Passwordreset-emailsentusername}}\n* {{msg-mw|Passwordreset-emailsent-capture}}\n* {{msg-mw|Passwordreset-emailerror-capture}}",
+ "passwordreset-nocaller": "Shown when a password reset was requested but the caller was not provided. This is an internal error.",
+ "passwordreset-nosuchcaller": "Shown when a password reset was requested but the username of the caller could not be resolved to a user. This is an internal error.\n\nParameters:\n* $1 - username of the caller",
+ "passwordreset-ignored": "Shown when password reset was unsuccessful due to configuration problems.",
+ "passwordreset-invalideamil": "Returned when the email address is syntatically invalid.",
+ "passwordreset-nodata": "Returned when no data was provided.",
"changeemail": "Title of [[Special:ChangeEmail|special page]]. This page also allows removing the user's email address.",
"changeemail-summary": "{{ignored}}",
"changeemail-header": "Text of [[Special:ChangeEmail]].",
"image_tip": "This is the text that appears when you hover the mouse over the sixth (middle) button on the edit toolbar.\n\n{{Identical|Embedded file}}",
"media_sample": "{{optional}}\n{{Identical|Example}}",
"media_tip": "This is the text that appears when you hover the mouse over the fifth button from the right in the edit toolbar.\n{{Identical|File link}}",
+ "sig-text": "{{notranslate}} This is the text that appears when you click on the signature button (second button from the right) on the edit toolbar. $1 will be replaced with four tildes (which cannot be included directly in the message for technical reasons).",
"sig_tip": "This is the text that appears when you hover the mouse over the second key from the right on the edit toolbar.\n{{Identical|Signature with timestamp}}",
"hr_tip": "This is the text that appears when you hover the mouse over the first button on the right on the edit toolbar.",
"summary": "The Summary text beside the edit summary field\n\nSee also:\n* {{msg-mw|Subject}}\nSee also:\n* {{msg-mw|Accesskey-summary}}\n* {{msg-mw|Tooltip-summary}}\n{{Identical|Summary}}",
"showpreview": "The text of the button to preview the page you are editing. See also {{msg-mw|showdiff}} and {{msg-mw|savearticle}} for the other buttons.\n\nSee also:\n* {{msg-mw|Showpreview}}\n* {{msg-mw|Accesskey-preview}}\n* {{msg-mw|Tooltip-preview}}\n{{Identical|Show preview}}",
"showdiff": "Button below the edit page. See also {{msg-mw|Showpreview}} and {{msg-mw|Savearticle}} for the other buttons.\n\nSee also:\n* {{msg-mw|Showdiff}}\n* {{msg-mw|Accesskey-diff}}\n* {{msg-mw|Tooltip-diff}}\n{{Identical|Show change}}",
"blankarticle": "Notice displayed once after the user tries to save an empty page.",
- "anoneditwarning": "Shown when editing a page anonymously.\n\nParameters:\n* $1 – A link to log in, <nowiki>{{fullurl:Special:UserLogin|returnto={{FULLPAGENAMEE}}}}</nowiki>\n* $2 – A link to sign up, <nowiki>{{fullurl:Special:UserLogin/signup|returnto={{FULLPAGENAMEE}}}}</nowiki>\n\nSee also:\n* {{msg-mw|Mobile-frontend-editor-anonwarning}}",
+ "anoneditwarning": "Shown when editing a page anonymously.\n\nParameters:\n* $1 – A link to log in, <nowiki>{{fullurl:Special:UserLogin|returnto={{FULLPAGENAMEE}}}}</nowiki>\n* $2 – A link to sign up, <nowiki>{{fullurl:Special:CreateAccount|returnto={{FULLPAGENAMEE}}}}</nowiki>\n\nSee also:\n* {{msg-mw|Mobile-frontend-editor-anonwarning}}",
"anonpreviewwarning": "See also:\n* {{msg-mw|Anoneditwarning}}",
"missingsummary": "The text \"edit summary\" is in {{msg-mw|Summary}}.\n\nSee also:\n* {{msg-mw|Missingcommentheader}}\n* {{msg-mw|Savearticle}}",
"selfredirect": "Notice displayed once after the user tries to create a redirect to the same article.",
"yourtext": "Used in Diff Preview page. The diff is between {{msg-mw|currentrev}} and {{msg-mw|yourtext}}.\n\nAlso used in Edit Conflict page; the diff between {{msg-mw|yourtext}} and {{msg-mw|storedversion}}.",
"storedversion": "This is used in an edit conflict as the label for the top revision that has been stored, as opposed to your version {{msg-mw|yourtext}} that has not been stored which is shown at the bottom of the page.",
"nonunicodebrowser": "Used as warning when editing page.",
- "editingold": "Used as warning when editing page.",
+ "editingold": "Used as warning when editing an old revision of a page.",
"yourdiff": "Used as h2 header for the diff of the current version of a page with the user's version in case there is an edit conflict or a spam filter hit.",
"copyrightwarning": "Copyright warning displayed under the edit box in editor. Parameters:\n* $1 - link\n* $2 - license name",
"copyrightwarning2": "Copyright warning displayed under the edit box in editor\n*$1 - license name",
"undo-summary-username-hidden": "Edit summary for an undo action where the username of the old revision is hidden.\n\nParameters:\n* $1 - the revision ID being undone\nSee also:\n* {{msg-mw|Undo-summary}}",
"cantcreateaccounttitle": "Used as title of the error message {{msg-mw|Cantcreateaccount-text}}.",
"cantcreateaccount-text": "Used as error message, with the title {{msg-mw|Cantcreateaccounttitle}}.\n* $1 - target IP address\n* $2 - reason or {{msg-mw|Blockednoreason}}\n* $3 - username\nSee also:\n* {{msg-mw|Cantcreateaccount-range-text}}",
- "cantcreateaccount-range-text": "Used as more detailed version of the {{msg-mw|Cantcreateaccount-text}} error message, with the title {{msg-mw|Cantcreateaccounttitle}}.\n* $1 - target IP address range\n* $2 - reason or {{msg-mw|Blockednoreason}}\n* $3 - username\n* $4 - current user's IP address",
+ "cantcreateaccount-range-text": "Used instead of the {{msg-mw|Cantcreateaccount-text}} when the block is a range block.\n* $1 - target IP address range\n* $2 - reason or {{msg-mw|Blockednoreason}}\n* $3 - username\n* $4 - current user's IP address",
"createaccount-hook-aborted": "Placeholder message to return with API errors on account create; passes through the message from a hook {{notranslate}}",
"viewpagelogs": "Link displayed in history of pages",
"nohistory": "Message shown when there are no history to list. See [{{canonicalurl:x|action=history}} example history].\n----\nAlso used as title of error message when the feed is empty. See [{{canonicalurl:x|action=history&feed=atom}} example feed].\n\nSee the error message:\n* {{msg-mw|history-feed-empty}}",
"columns": "Used on [[Special:Preferences]], \"Editing\" section in the \"Size of editing window\" fieldset.\n{{Identical|Column}}",
"searchresultshead": "Replaced by {{msg-mw|prefs-searchoptions}}, though may still be used in some extensions. DEPRECATED.\n\n{{Identical|Search}}",
"stub-threshold": "Used in [[Special:Preferences]], \"Advanced options\" section. The setting allows the user to select a threshold value, in bytes, from a predefined list of options. Any links that lead to pages smaller than the threshold (\"stub links\") will be styled differently.\n\nParameters:\n* $1: the text of {{msg-mw|stub-threshold-sample-link}}, styled as a stub link",
- "stub-threshold-sample-link": "Passed as a parameter to the {{msg-mw|stub-threshold}} message.",
+ "stub-threshold-sample-link": "Passed as a parameter to the {{msg-mw|stub-threshold}} message.\n{{Identical|Sample}}",
"stub-threshold-disabled": "Used in [[Special:Preferences]].\n{{Identical|Disabled}}",
"recentchangesdays": "Used in [[Special:Preferences]], tab \"Recent changes\".",
"recentchangesdays-max": "Shown as hint in [[Special:Preferences]], tab \"Recent changes\". Parameters:\n* $1 - number of days\nSee also:\n* {{msg-mw|Prefs-watchlist-days-max}}",
"right-managechangetags": "{{doc-right|managechangetags}}",
"right-applychangetags": "{{doc-right|applychangetags}}",
"right-changetags": "{{doc-right|changetags}}",
+ "right-deletechangetags": "{{doc-right|deletechangetags}}",
"grant-generic": "Used if the grant name is not defined. Parameters:\n* $1 - grant name\n\nDefined grants (grant name refers: blockusers, createeditmovepage, ...):\n* {{msg-mw|grant-checkuser}}\n* {{msg-mw|grant-blockusers}}\n* {{msg-mw|grant-createaccount}}\n* {{msg-mw|grant-createeditmovepage}}\n* {{msg-mw|grant-delete}}\n* {{msg-mw|grant-editinterface}}\n* {{msg-mw|grant-editmycssjs}}\n* {{msg-mw|grant-editmyoptions}}\n* {{msg-mw|grant-editmywatchlist}}\n* {{msg-mw|grant-editpage}}\n* {{msg-mw|grant-editprotected}}\n* {{msg-mw|grant-highvolume}}\n* {{msg-mw|grant-oversight}}\n* {{msg-mw|grant-patrol}}\n* {{msg-mw|grant-protect}}\n* {{msg-mw|grant-rollback}}\n* {{msg-mw|grant-sendemail}}\n* {{msg-mw|grant-uploadeditmovefile}}\n* {{msg-mw|grant-uploadfile}}\n* {{msg-mw|grant-basic}}\n* {{msg-mw|grant-viewdeleted}}\n* {{msg-mw|grant-viewmywatchlist}}",
"grant-group-page-interaction": "{{Related|grant-group}}",
"grant-group-file-interaction": "{{Related|grant-group}}",
"grant-group-customization": "{{Related|Grant-group}}",
"grant-group-administration": "{{Related|Grant-group}}",
"grant-group-other": "{{Related|Grant-group}}",
- "grant-blockusers": "Name for grant \"blockusers\".\n{{Related|grant}}",
+ "grant-blockusers": "Name for grant \"blockusers\".\n{{Related|Grant}}",
"grant-createaccount": "Name for grant \"createaccount\".\n{{Related|grant}}",
"grant-createeditmovepage": "Name for grant \"createeditmovepage\".\n{{Related|grant}}",
"grant-delete": "Name for grant \"delete\".\n{{Related|grant}}",
"action-managechangetags": "{{doc-action|managechangetags}}",
"action-applychangetags": "{{doc-action|applychangetags}}",
"action-changetags": "{{doc-action|changetags}}",
+ "action-deletechangetags": "{{doc-action|deletechangetags}}",
"nchanges": "Appears on enhanced watchlist and recent changes when page has more than one change on given date, linking to a diff of the changes.\n\nParameters:\n* $1 - the number of changes on that day (2 or more)\nThree messages are shown side-by-side: ({{msg-mw|Nchanges}} | {{msg-mw|Enhancedrc-since-last-visit}} | {{msg-mw|Enhancedrc-history}}).",
"enhancedrc-since-last-visit": "Appears on enhanced watchlist and recent changes when page has more than one change on given date and at least one that the user hasn't seen yet, linking to a diff of the unviewed changes.\n\nParameters:\n* $1 - the number of unviewed changes (1 or more)\nThree messages are shown side-by-side: ({{msg-mw|nchanges}} | {{msg-mw|enhancedrc-since-last-visit}} | {{msg-mw|enhancedrc-history}}).",
"enhancedrc-history": "Appears on enhanced watchlist and recent changes when page has more than one change on given date, linking to its history.\n\nThis is the same as {{msg-mw|hist}}, but not abbreviated.\n\nThree messages are shown side-by-side: ({{msg-mw|nchanges}} | {{msg-mw|enhancedrc-since-last-visit}} | {{msg-mw|enhancedrc-history}}).\n{{Identical|History}}",
"upload-form-label-own-work": "[[File:Cross-wiki media upload dialog, December 2015 AB test option 1.png|thumb]] Label for own work confirmation checkbox",
"upload-form-label-infoform-categories": "Label for category selector input\n{{Identical|Category}}",
"upload-form-label-infoform-date": "Label for date input\n{{Identical|Date}}",
- "upload-form-label-own-work-message-local": "Message shown by local when a user affirms that their file upload to the local wiki follows the terms of service and licensing policies of the local wiki.",
- "upload-form-label-not-own-work-message-local": "Message shown by local when a user cannot upload a file to the local wiki.",
- "upload-form-label-not-own-work-local-local": "Suggests uploading a file via Special:Upload instead of using whatever method they're currently using.",
- "upload-form-label-own-work-message-default": "Message shown by default when a user affirms that they are allowed to upload a file to a remote wiki.",
- "upload-form-label-not-own-work-message-default": "Message shown by default when a user cannot upload a file to a remote wiki.",
- "upload-form-label-not-own-work-local-default": "Suggests uploading a file locally instead of to a remote wiki.",
- "upload-form-label-own-work-message-shared": "[[File:Cross-wiki media upload dialog, December 2015 AB test option 1.png|thumb]] Legal message, confirming that the user is allowed to upload the file.",
- "upload-form-label-not-own-work-message-shared": "[[File:Cross-wiki media upload dialog, December 2015 AB test option 1.png|thumb]] Explains alternatives when the copyright isn't owned by the uploader.",
- "upload-form-label-not-own-work-local-shared": "[[File:Cross-wiki media upload dialog, December 2015 AB test option 1.png|thumb]] Message suggesting the user might want to upload a file locally instead of to Wikimedia Commons.",
+ "upload-form-label-own-work-message-generic-local": "Message shown by local when a user affirms that their file upload to the local wiki follows the terms of service and licensing policies of the local wiki.",
+ "upload-form-label-not-own-work-message-generic-local": "Message shown by local when a user cannot upload a file to the local wiki.",
+ "upload-form-label-not-own-work-local-generic-local": "Suggests uploading a file via Special:Upload instead of using whatever method they're currently using.",
+ "upload-form-label-own-work-message-generic-foreign": "Message shown by default when a user affirms that they are allowed to upload a file to a remote wiki.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Message shown by default when a user cannot upload a file to a remote wiki.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Suggests uploading a file locally instead of to a remote wiki.",
"backend-fail-stream": "Parameters:\n* $1 - a filename",
"backend-fail-backup": "Parameters:\n* $1 - a filename",
"backend-fail-notexists": "Parameters:\n* $1 - a filename",
"trackingcategories-msg": "Header for the message column of the table on [[Special:TrackingCategories]]. This column lists the mediawiki message that controls the tracking category in question.\n{{Identical|Tracking category}}",
"trackingcategories-name": "Header for the message column of the table on [[Special:TrackingCategories]]. This column lists the name of the tracking category in the content language.",
"trackingcategories-desc": "Header for the message column of the table on [[Special:TrackingCategories]]. This column lists the inclusion criteria for the category.",
+ "restricted-displaytitle-ignored": "This message is used as a category name for a [[mw:Special:MyLanguage/Help:Tracking categories|tracking category]] where pages are placed automatically if a page has an ignored display title.\n\nSee also:\n* {{msg-mw|restricted-displaytitle-ignored-desc}}\n*{{msg-mw|restricted-displaytitle}}",
+ "restricted-displaytitle-ignored-desc": "Pages with ignored display titles category description. Shown on [[Special:TrackingCategories]].\n\nSee also:\n* {{msg-mw|restricted-displaytitle-ignored}}\n* {{msg-mw|restricted-displaytitle}}",
"noindex-category-desc": "No-index category-description. Shown on [[Special:TrackingCategories]].\n\nSee also:\n* {{msg-mw|Noindex-category}}",
"index-category-desc": "Index category-description. Shown on [[Special:TrackingCategories]].\n\nSee also:\n* {{msg-mw|Index-category}}",
"post-expand-template-inclusion-category-desc": "Post expand template inclusion category description. Shown on [[Special:TrackingCategories]].\n\nSee also:\n* {{msg-mw|Post-expand-template-inclusion-category}}",
"emailsubject": "Field in [[Special:EmailUser]].\n\n{{Identical|Subject}}",
"emailmessage": "Field in [[Special:EmailUser]].\n\n{{Identical|Message}}",
"emailsend": "Button name in [[Special:EmailUser]].\n\n{{Identical|Send}}",
- "emailccme": "Used at [[Special:Preferences]] > E-mail",
+ "emailccme": "Used at [[Special:EmailUser]]",
"emailccsubject": "Used in [[Special:EmailUser]].\n\nSubject of the carbon-copied email for the sender sent through MediaWiki.\n\nParameters:\n* $1 - target username\n* $2 - email subject",
"emailsent": "Title of [[Special:EmailUser]] when it says you it sent an email",
"emailsenttext": "Confirmation page: when you send an email, [[Special:EmailUser]] says you this (Your email has been sent).\n\nParameters:\n* $1 - (Optional) the recipient's username, for local customizations",
"rollbacklinkcount": "{{doc-actionlink}}\nText of the rollback link showing the number of edits to be rolled back. See also {{msg-mw|rollbacklink}}.\n\nParameters:\n* $1 - the number of edits that will be rolled back. If $1 is over the value of <code>$wgShowRollbackEditCount</code> (default: 10) {{msg-mw|rollbacklinkcount-morethan}} is used.\n\nThe rollback link is displayed with a tooltip {{msg-mw|Tooltip-rollback}}",
"rollbacklinkcount-morethan": "{{doc-actionlink}}\nText of the rollback link when a greater number of edits is to be rolled back. See also {{msg-mw|rollbacklink}}.\n\nWhen the number of edits rolled back is smaller than [[mw:Special:MyLanguage/Manual:$wgShowRollbackEditCount|$wgShowRollbackEditCount]], {{msg-mw|rollbacklinkcount}} is used instead.\n\nParameters:\n* $1 - number of edits",
"rollbackfailed": "{{Identical|Rollback}}",
- "cantrollback": "Used as error message when rolling back.\n\nSee also:\n* {{msg-mw|Notvisiblerev}}\n{{Identical|Revert}}\n{{Identical|Rollback}}",
+ "rollback-missingparam": "Used as error message rollback is accessed without the required parameters\n\nSee also:\n* {{msg-mw|Rollbackfailed}}",
+ "cantrollback": "Used as error message when rollback fails due to there not being a valid revision to revert back to.\n\nSee also:\n* {{msg-mw|Notvisiblerev}}\n{{Identical|Revert}}\n{{Identical|Rollback}}",
"alreadyrolled": "Appear when there's rollback and/or edit collision.\n\nRefers to:\n* {{msg-mw|Pipe-separator}}\n* {{msg-mw|Contribslink}}\nParameters:\n* $1 - the page to be rolled back\n* $2 - the editor to be rolled-back of that page\n* $3 - the editor that cause collision\n{{Identical|Rollback}}",
"editcomment": "Only shown if there is an edit {{msg-mw|Summary}}. Parameters:\n* $1 - the edit summary",
"revertpage": "Parameters:\n* $1 - username 1\n* $2 - username 2\n* $3 - (Optional) revision ID of the revision reverted to\n* $4 - (Optional) timestamp of the revision reverted to\n* $5 - (Optional) revision ID of the revision reverted from\n* $6 - (Optional) timestamp of the revision reverted from\nSee also:\n* {{msg-mw|Revertpage-nouser}}\n{{Identical|Revert}}",
"revertpage-nouser": "This is a confirmation message a user sees after reverting, when the username of the version is hidden with RevisionDelete.\n\nIn other cases the message {{msg-mw|Revertpage}} is used.\n\nParameters:\n* $1 - username 1, can be used for GENDER\n* $2 - (Optional) username 2\n* $3 - (Optional) revision ID of the revision reverted to\n* $4 - (Optional) timestamp of the revision reverted to\n* $5 - (Optional) revision ID of the revision reverted from\n* $6 - (Optional) timestamp of the revision reverted from",
"rollback-success": "This message shows up on screen after successful revert (generally visible only to admins). $1 describes user whose changes have been reverted, $2 describes user which produced version, which replaces reverted version.\n{{Identical|Revert}}\n{{Identical|Rollback}}",
+ "rollback-success-notify": "Notification shown after a successful revert.\n* $1 - User whose changes have been reverted\n* $2 - User that made the edit that was restored\n* $3 - Url to the diff of the rollback\nSee also:\n* {{msg-mw|showdiff}}\n{{Identical|rollback-success}}\n{{Format|jquerymsg}}",
"sessionfailure-title": "Used as title of the error message {{msg-mw|Sessionfailure}}.",
"sessionfailure": "Used as error message.\n\nThe title for this error message is {{msg-mw|Sessionfailure-title}}.",
"changecontentmodel": "Title of the change content model special page",
"whatlinkshere-prev": "This is part of the navigation message on the top and bottom of Whatlinkshere pages, where it is used as the first argument of {{msg-mw|Viewprevnext}}.\n\nParameters:\n* $1 - the number of items shown per page. It is not used when $1 is zero; not sure what happens when $1 is one.\nSpecial pages use {{msg-mw|Prevn}} instead (still as an argument to {{msg-mw|Viewprevnext}}).\n\nSee also:\n* {{msg-mw|Whatlinkshere-next}}\n{{Identical|Previous}}",
"whatlinkshere-next": "This is part of the navigation message on the top and bottom of Whatlinkshere pages, where it is used as the second argument of {{msg-mw|Viewprevnext}}.\n\nParameters:\n* $1 - the number of items shown per page. It is not used when $1 is zero; not sure what happens when $1 is one.\nSpecial pages use {{msg-mw|Nextn}} instead (still as an argument to {{msg-mw|Viewprevnext}}).\n\nSee also:\n* {{msg-mw|Whatlinkshere-prev}}\n{{Identical|Next}}",
"whatlinkshere-links": "Used on [[Special:WhatLinksHere]]. It is a link to the WhatLinksHere page of that page.\n\nExample line:\n* [[Main Page]] ([[Special:WhatLinksHere/Main Page|{{int:whatlinkshere-links}}]])\n{{Identical|Link}}",
- "whatlinkshere-hideredirs": "Filter option in [[Special:WhatLinksHere]]. Parameters:\n* $1 is the {{msg-mw|hide}} or {{msg-mw|show}}\n{{Identical|Redirect}}",
- "whatlinkshere-hidetrans": "First filter option in [[Special:WhatLinksHere]]. Parameters:\n* $1 is the {{msg-mw|hide}} or {{msg-mw|show}}\n{{Identical|Transclusion}}",
- "whatlinkshere-hidelinks": "Filter option in [[Special:WhatLinksHere]]. Parameters:\n* $1 is the {{msg-mw|hide}} or {{msg-mw|show}}\n{{Identical|Link}}",
- "whatlinkshere-hideimages": "Filter option in [[Special:WhatLinksHere]]. Parameters:\n* $1 - the {{msg-mw|Hide}} or {{msg-mw|Show}}\n\nSee also:\n*{{msg-mw|Isimage}}\n*{{msg-mw|Media tip}}",
+ "whatlinkshere-hideredirs": "Filter option in [[Special:WhatLinksHere]].\n\nParameters:\n* $1 - {{msg-mw|hide}}/{{msg-mw|show}}",
+ "whatlinkshere-hidetrans": "First filter option in [[Special:WhatLinksHere]]. Parameters:\n* $1 is the {{msg-mw|hide}} or {{msg-mw|show}}",
+ "whatlinkshere-hidelinks": "Filter option in [[Special:WhatLinksHere]].",
+ "whatlinkshere-hideimages": "Filter option in [[Special:WhatLinksHere]].\n\nSee also:\n*{{msg-mw|Isimage}}\n*{{msg-mw|Media tip}}",
"whatlinkshere-filters": "{{Identical|Filter}}",
"whatlinkshere-submit": "Label for submit button in [[Special:WhatLinksHere]]\n{{Identical|Go}}",
"autoblockid": "Used as name of autoblock, instead of autoblocked IPs. Parameters:\n* $1 - autoblock ID",
"ipb-blocklist": "Used as link text in [[Special:Block]].\n\nThe link points to Specil:BlockList.",
"ipb-blocklist-contribs": "Used in [[Special:Block]].\n* $1 - target username",
"ipb-blocklist-duration-left": "Used on [[Special:BlockList]] to show the remaining time (years, months, days, hours, minutes) until the block expires.\n$1 - The duration left",
- "unblockip": "Used as legend for the form in [[Special:Unblock]].",
+ "unblockip": "Used as title and legend for the form in [[Special:Unblock]].",
"unblockiptext": "Used in the {{msg-mw|Unblockip}} form on [[Special:Unblock]].",
"ipusubmit": "Used as button text on [{{canonicalurl:Special:BlockList|action=unblock}} Special:BlockList?action=unblock]. To see the message:\n* Go to [[Special:BlockList]]\n* Click \"unblock\" for any block (but you can only see \"unblock\" if you have administrator rights)\n* It is now the button below the form",
"unblocked": "{{doc-important|Do not translate the namespace \"User:\".}}\nParameters:\n* $1 - the username that was unblocked\nSee also:\n* {{msg-mw|Unblocked-range}}\n* {{msg-mw|Unblocked-id}}\n*{{msg-mw|Unblocked-ip}}",
"unlockdbsuccesssub": "Used as subtitle in [[Special:UnlockDB]].\n\nSee also:\n* {{msg-mw|Lockdbsuccesssub|subtitle}}\n* {{msg-mw|Lockdbsuccesstext|text}}\n* {{msg-mw|Unlockdbsuccesssub|subtitle}}\n* {{msg-mw|Unlockdbsuccesstext|text}}",
"lockdbsuccesstext": "Used as message text in [[Special:LockDB]].\n\nSee also:\n* {{msg-mw|Lockdbsuccesssub|subtitle}}\n* {{msg-mw|Lockdbsuccesstext|text}}\n* {{msg-mw|Unlockdbsuccesssub|subtitle}}\n* {{msg-mw|Unlockdbsuccesstext|text}}",
"unlockdbsuccesstext": "Used as message text in [[Special:UnlockDB]].\n\nSee also:\n* {{msg-mw|Lockdbsuccesssub|subtitle}}\n* {{msg-mw|Lockdbsuccesstext|text}}\n* {{msg-mw|Unlockdbsuccesssub|subtitle}}\n* {{msg-mw|Unlockdbsuccesstext|text}}",
- "lockfilenotwritable": "'No longer needed' on wikipedia.",
+ "lockfilenotwritable": "Used as error message in [[Special:LockDB]].",
+ "databaselocked": "Used as error message in [[Special:LockDB]].\nThe title of this error message is {{msg-mw|Lockdb}}.\n\nSee also:\n* {{msg-mw|Lockdb|title}}\n* {{msg-mw|Databaselocked|message}}",
"databasenotlocked": "Used as error message in [[Special:UnlockDB]].\nThe title of this error message is {{msg-mw|Lockdb}}.\n\nSee also:\n* {{msg-mw|Lockdb|title}}\n* {{msg-mw|Databasenotlocked|message}}",
"lockedbyandtime": "Used as part of the message when a database is locked through [[Special:LockDB]]. Parameters:\n* $1 is the user that locked the database.\n* $2 is the date on which the lock was made\n* $3 is the time at which the lock was made",
"move-page": "Used as page title of [[Special:MovePage]] to move pages.\n\nSee example: [[Special:MovePage/Portal:En]].\n\nParameters:\n* $1 - the name of the page to be moved (without link)\n{{Identical|Move}}",
"tooltip-ca-nstab-category": "Tooltip shown when hovering over the {{msg-mw|Nstab-category}} tab.\n\nSee also:\n* {{msg-mw|Nstab-category}}\n* {{msg-mw|Accesskey-ca-nstab-category}}\n* {{msg-mw|Tooltip-ca-nstab-category}}",
"tooltip-minoredit": "Tooltip shown when hovering over the \"{{msg-mw|Minoredit}}\" link below the edit form.\n\nSee also:\n* {{msg-mw|Minoredit}}\n* {{msg-mw|Accesskey-minoredit}}\n* {{msg-mw|Tooltip-minoredit}}",
"tooltip-save": "This is the text that appears when you hover the mouse over {{msg-mw|Savearticle}} button on the edit page.\n\nSee also:\n* {{msg-mw|Savearticle}}\n* {{msg-mw|Accesskey-save}}\n* {{msg-mw|Tooltip-save}}",
- "tooltip-publish": "This is the text that appears when you hover the mouse over {{msg-mw|publishpage}} button on the edit page.\n\nNote: This i18n is being introduced in advance of usage to provide extra time for translators.\n\nSee also:\n* {{msg-mw|publishpage}}\n* {{msg-mw|Accesskey-publish}}\n{{Identical|Publish page}}",
+ "tooltip-publish": "This is the text that appears when you hover the mouse over {{msg-mw|publishpage}} button on the edit page.\n\nNote: This i18n is being introduced in advance of usage to provide extra time for translators.\n\nSee also:\n* {{msg-mw|publishpage}}\n* {{msg-mw|Accesskey-publish}}",
"tooltip-preview": "Tooltip shown when hovering over {{msg-mw|Showpreview}} button.\n\nIf the length of the translated message is over 60 characters (including spaces) then the end of the message will be cut off when using Firefox 2.0.0.7 browser, Linux operating system and the Monobook skin.\n\nSee also:\n* {{msg-mw|Showpreview}}\n* {{msg-mw|Accesskey-preview}}\n* {{msg-mw|Tooltip-preview}}",
"tooltip-diff": "This is the text (tooltip) that appears when you hover the mouse over {{msg-mw|Showdiff}} button on the edit page.\n\nSee also:\n* {{msg-mw|Showdiff}}\n* {{msg-mw|Accesskey-diff}}\n* {{msg-mw|Tooltip-diff}}",
"tooltip-compareselectedversions": "Tooltip of {{msg-mw|Compareselectedversions}} (which is used as button in history pages).\n\nSee also:\n* {{msg-mw|Compareselectedversions}}\n* {{msg-mw|Accesskey-compareselectedversions}}\n* {{msg-mw|Tooltip-compareselectedversions}}",
"confirm-watch-top": "Used as confirmation message.",
"confirm-unwatch-button": "Used as Submit button text.\n{{Identical|OK}}",
"confirm-unwatch-top": "Used as confirmation message.",
+ "confirm-rollback-button": "Used as Submit button text.\n{{Identical|OK}}",
+ "confirm-rollback-top": "Used as confirmation message.",
"semicolon-separator": "{{optional}}",
"comma-separator": "{{optional}}\n\nWarning: languages have different usages of punctuation, and sometimes they are swapped (e.g. openining and closing quotation marks, or full stop and colon in Armenian), or change their form (the full stop in Chinese and Japanese, the prefered \"colon\" in Armenian used in fact as the regular full stop, the comma in Arabic, Armenian, and Chinese...)\n\nTheir spacing (before or after) may also vary across languages (for example French requires a non-breaking space, preferably narrow if the browser supports NNBSP, on the inner side of some punctuations like quotation/question/exclamation marks, colon, and semicolons).",
"colon-separator": "{{optional}}\nChange it only if your language uses another character for ':' or it needs an extra space before the colon.",
"timezone-local": "Label to indicate that a time is in the user's local timezone.\n{{Identical|Local}}",
"duplicate-defaultsort": "See definition of [[w:Sorting|sort key]] on Wikipedia. Parameters:\n* $1 - old default sort key\n* $2 - new default sort key",
"duplicate-displaytitle": "Warning shown when a page has its display title set multiple times. Parameters:\n* $1 - old display title\n* $2 - new display title",
+ "restricted-displaytitle": "Warning shown when a display title is ignored because it is not equivalent to its actual title. Parameters:\n* $1 - the ignored display title",
"invalid-indicator-name": "Warning shown when the [https://www.mediawiki.org/wiki/Help:Page_status_indicators <indicator name=\"''unique-identifier''\">''content''</indicator>] parser tag is used incorrectly.",
"version": "{{doc-special|Version}}\n{{Identical|Version}}",
"version-summary": "{{doc-specialpagesummary|version}}",
"tags-delete-not-found": "Error message on [[Special:Tags]]",
"tags-delete-too-many-uses": "Error message on [[Special:Tags]]",
"tags-delete-warnings-after-delete": "Warning shown after deleting a tag.\n\nParameters:\n* $1 - the code name of the tag that was deleted\n* $2 - the number of warnings",
+ "tags-delete-no-permission": "Error message on [[Special:Tags]]",
"tags-activate-title": "The title of a page used to activate a tag. For more information on tags see [[mw:Manual:Tags|MediaWiki]].",
"tags-activate-question": "An explanation to tell users what they are about to do.\n\nParameters:\n* $1 - the code name of the tag that is about to be activated",
"tags-activate-reason": "{{Identical|Reason}}",
"log-action-filter-suppress-block": "{{doc-log-action-filter-action|suppress|block}}",
"log-action-filter-suppress-reblock": "{{doc-log-action-filter-action|suppress|reblock}}",
"log-action-filter-upload-upload": "{{doc-log-action-filter-action|upload|upload}}",
- "log-action-filter-upload-overwrite": "{{doc-log-action-filter-action|upload|overwrite}}"
+ "log-action-filter-upload-overwrite": "{{doc-log-action-filter-action|upload|overwrite}}",
+ "authmanager-authn-not-in-progress": "Error message when AuthManager session data is lost during authentication, or the user hits the \"continue\" endpoint without an active authentication attempt.",
+ "authmanager-authn-no-primary": "Error message when no AuthenticationProvider handles the AuthenticationRequests for login. This might mean the user needs to fill out all the form fields.",
+ "authmanager-authn-no-local-user": "Error message when authentication somehow succeeds without a username being known. This probably should never happen.",
+ "authmanager-authn-no-local-user-link": "Error message when federated authentication (e.g. \"login with Google\") succeeds, but no account is associated.",
+ "authmanager-authn-autocreate-failed": "Error message when auto-creation fails during login. Parameters:\n* $1 - Error message from the account creation attempt, as wikitext.",
+ "authmanager-change-not-supported": "Error message when all PrimaryAuthenticationProviders ignore the change request.",
+ "authmanager-create-disabled": "Message displayed when account creation is disabled.",
+ "authmanager-create-from-login": "Message displayed when moving from login to account creation and additional data must be collected from the user.",
+ "authmanager-create-not-in-progress": "Error message when AuthManager session data is lost during account creation, or the user hits the \"continue\" endpoint without an active account creation attempt.",
+ "authmanager-create-no-primary": "Error message when no AuthenticationProvider handles the AuthenticationRequests for account creation. This might mean the user needs to fill out all the form fields.",
+ "authmanager-link-no-primary": "Error message when no AuthenticationProvider handles the AuthenticationRequests for account linking. This might mean the user needs to fill out all the form fields.",
+ "authmanager-link-not-in-progress": "Error message when AuthManager session data is lost during account linking, or the user hits the \"continue\" endpoint without an active account link attempt.",
+ "authmanager-authplugin-setpass-failed-title": "Title of error page from AuthManager if AuthPlugin returns false from its setPassword() method.",
+ "authmanager-authplugin-setpass-failed-message": "Text of error page from AuthManager if AuthPlugin returns false from its setPassword() method.",
+ "authmanager-authplugin-create-fail": "Error message from AuthManager if the AuthPlugin returns false from its addUser() method.",
+ "authmanager-authplugin-setpass-denied": "Error message from AuthManager if the AuthPlugin returns false from its allowPasswordChange() method.",
+ "authmanager-authplugin-setpass-bad-domain": "Error message from AuthManager if the AuthPlugin rejects the passed domain.",
+ "authmanager-autocreate-noperm": "Error message when auto-creation fails due to lack of permission.",
+ "authmanager-autocreate-exception": "Error message when auto-creation fails because we tried recently and an exception was thrown, so we're not going to try again yet.",
+ "authmanager-userdoesnotexist": "Error message when a user account does not exist. Parameters:\n* $1 - User name.",
+ "authmanager-userlogin-remembermypassword-help": "Description of the field with label {{msg-mw|userlogin-remembermypassword}}.",
+ "authmanager-username-help": "Description of the field with label {{msg-mw|userlogin-yourname}}.",
+ "authmanager-password-help": "Description of the field with label {{msg-mw|userlogin-yourpassword}}.",
+ "authmanager-domain-help": "Description of the field with label {{msg-mw|yourdomainname}}.",
+ "authmanager-retype-help": "Description of the field with label {{msg-mw|createacct-yourpasswordagain}}.",
+ "authmanager-email-label": "Label for the email field.\n{{Identical|E-mail}}",
+ "authmanager-email-help": "Description of the field with label {{msg-mw|authmanager-email-label}}.\n{{Identical|E-mail address}}",
+ "authmanager-realname-label": "Label for the realname field.\n{{Identical|Real name}}",
+ "authmanager-realname-help": "Description of the field with label {{msg-mw|authmanager-realname-label}}.",
+ "authmanager-provider-password": "Description for PasswordAuthenticationRequest. Will be used as $1 in messages such as {{msg-mw|authprovider-confirmlink-option}}.",
+ "authmanager-provider-password-domain": "Description for PasswordDomainAuthenticationRequest. Will be used as $1 in messages such as {{msg-mw|authprovider-confirmlink-option}}.",
+ "authmanager-account-password-domain": "Format to display username and domain for PasswordDomainAuthenticationRequest. Will be used as $2 in messages such as {{msg-mw|authprovider-confirmlink-option}}. Parameters:\n* $1 - Username\n* $2 - Domain",
+ "authmanager-provider-temporarypassword": "Description for TemporaryPasswordAuthenticationRequest. Will be used as $1 in messages such as {{msg-mw|authprovider-confirmlink-option}}.",
+ "authprovider-confirmlink-message": "Message from ConfirmLinkSecondaryAuthenticationProvider to indicate that credentials may be linked.",
+ "authprovider-confirmlink-option": "Used to format linkable credentials in ConfirmLinkSecondaryAuthenticationProvider. Parameters:\n* $1 - Credential provider (e.g. the name of the third-party authentication service).\n* $2 - Credential account (e.g. the email address).",
+ "authprovider-confirmlink-request-label": "Form field label for the list of linkable credentials",
+ "authprovider-confirmlink-request-help": "Form field help text",
+ "authprovider-confirmlink-success-line": "Line to display that credentials were linked successfully. Parameters:\n* $1 - Linked credentials, formatted with {{msg-mw|authprovider-confirmlink-option}}\n\nSee also:\n* {{msg-mw|authprovider-confirmlink-failed}}\n* {{msg-mw|authprovider-confirmlink-failed-line}}",
+ "authprovider-confirmlink-failed-line": "Line to display that credentials were not linked successfully. Parameters:\n* $1 - Credentials that failed, formatted with {{msg-mw|authprovider-confirmlink-option}}\n* $2 - Failure message text.\n\nSee also:\n* {{msg-mw|authprovider-confirmlink-failed}}\n* {{msg-mw|authprovider-confirmlink-success-line}}",
+ "authprovider-confirmlink-failed": "Used to prefix the list of individual link statuses when some did not succeed. Parameters:\n* $1 - Failure message, or a wikitext bulleted list of failure messages.\n\nSee also:\n* {{msg-mw|authprovider-confirmlink-success-line}}\n* {{msg-mw|authprovider-confirmlink-failed-line}}",
+ "authprovider-confirmlink-ok-help": "Description of the \"ok\" field when ConfirmLinkSecondaryAuthenticationProvider needs to display link failure messages to the user.",
+ "authprovider-resetpass-skip-label": "Label for the \"Skip\" button when it's possible to skip resetting a password in ResetPasswordSecondaryAuthenticationProvider.\n{{Identical|Skip}}",
+ "authprovider-resetpass-skip-help": "Description of the option to skip resetting a password in ResetPasswordSecondaryAuthenticationProvider.",
+ "authform-nosession-login": "Error message shown when the login was successful, but the session could not be reestablished on the next request. $1 is an explanation which depends on what session handler is being used, such as {{msg-mw|sessionprovider-nocookies}}.",
+ "authform-nosession-signup": "Error message shown when the account creation was successful, but the session could not be reestablished on the next request. $1 is an explanation which depends on what session handler is being used, such as {{msg-mw|sessionprovider-nocookies}}.",
+ "authform-newtoken": "Error message shown on the auth form when the session has no CSRF token. This can be caused by session expiry but it is more likely that the client does not support sessions for some reason (e.g. a browser with all cookies diabled). $1 is an explanation (in the form of full sentences) given by the session provider of why sessions might not work (usually this will be {{msg-mw|sessionprovider-nocookies}}).",
+ "authform-notoken": "Error message shown on the auth form when the submitted data has no CSRF token.",
+ "authform-wrongtoken": "Error message shown on the auth form when the submitted CSRF token value is invalid.",
+ "specialpage-securitylevel-not-allowed-title": "Error page title shown when the user visits a special page but the authentication security check fails.",
+ "specialpage-securitylevel-not-allowed": "Error message shown when the user visits a special page but the authentication security check fails.",
+ "authpage-cannot-login": "Error message shown on authentication-related special pages when login cannot start. This is not supposed to happen unless the site is misconfigured.",
+ "authpage-cannot-login-continue": "Error message shown on authentication-related special pages when login cannot continue. This most likely means a session timeout.",
+ "authpage-cannot-create": "Error message shown on authentication-related special pages when account creation cannot start. This is not supposed to happen unless the site is misconfigured.",
+ "authpage-cannot-create-continue": "Error message shown on authentication-related special pages when account creation cannot continue. This most likely means a session timeout.",
+ "authpage-cannot-link": "Error message shown on authentication-related special pages when account linking cannot start. This is not supposed to happen unless the site is misconfigured.",
+ "authpage-cannot-link-continue": "Error message shown on authentication-related special pages when account linking cannot continue. This most likely means a session timeout.",
+ "cannotauth-not-allowed-title": "Title of the error page shown when the user tries to use an authentication-related page they should not have access to.",
+ "cannotauth-not-allowed": "Text of the error page shown when the user tries t use an authentication-related page they should not have access to.",
+ "changecredentials": "Title of the special page [[Special:ChangeCredentials]] which allows changing authentication credentials (such as the password).",
+ "changecredentials-submit": "Used on [[Special:ChangeCredentials]].",
+ "changecredentials-invalidsubpage": "Error message shown when using [[Special:ChangeCredentials]] with an invalid type.\n\nParameters:\n* $1 - subpage name.",
+ "changecredentials-success": "Success message after using [[Special:ChangeCredentials]].",
+ "removecredentials": "Title of the special page [[Special:RemoveCredentials]] which allows removing authentication credentials (such as a two-factor token).",
+ "removecredentials-submit": "Used on [[Special:RemoveCredentials]].",
+ "removecredentials-invalidsubpage": "Error message shown when using [[Special:RemoveCredentials]] with an invalid type.\n\nParameters:\n* $1 - subpage name.",
+ "removecredentials-success": "Success message after using [[Special:RemoveCredentials]].",
+ "credentialsform-provider": "Shown on [[Special:ChangeCredentials]]/[[Special:RemoveCredentials]] as the label for the authentication type (e.g. \"password\", \"English Wikipedia via OAuth\")",
+ "credentialsform-account": "Shown on [[Special:ChangeCredentials]]/[[Special:RemoveCredentials]] as the label for the account name",
+ "cannotlink-no-provider-title": "Error page title shown when the user visits [[Special:LinkAccounts]] but there is no external account provider that could be linked.",
+ "cannotlink-no-provider": "Error message shown when the user visits [[Special:LinkAccounts]] but there is no external account provider that could be linked.",
+ "linkaccounts": "Title of the special page [[Special:LinkAccounts]] which allows the user to connect the local user accounts with external ones such as Google or Facebook.",
+ "linkaccounts-success-text": "Text shown on top of the form after a successful action.",
+ "linkaccounts-submit": "Text of the main submit button on [[Special:LinkAccounts]] (when there is one)",
+ "unlinkaccounts": "Title of the special page [[Special:UnlinkAccounts]] which allows the user to remove linked remote accounts.",
+ "unlinkaccounts-success": "Account unlinking form success message"
}
"noname": "Manam niwarqankichu ruraqpa allin sutinta.",
"loginsuccesstitle": "Llamk'apuy tiyayqa qallarisqañam",
"loginsuccess": "Llamk'apuy tiyayniykiqa qallarisqam {{SITENAME}}-pi \"$1\" sutiyuq kaspa.",
- "nosuchuser": "Nisqayki \"$1\" sutiyuq ruraqqa manam kanchu.\nRuraqpa sutinqa uchuypas hatunpas sanampakunayuqmi kayta atin.\nAllin qillqasqaykita llanchiriy, ichataq urapi kaq hunt'ana p'anqata llamk'achiy [[Special:UserLogin/signup|musuq rakiqunata kicharinaykipaq]].",
+ "nosuchuser": "Nisqayki \"$1\" sutiyuq ruraqqa manam kanchu.\nRuraqpa sutinqa uchuypas hatunpas sanampakunayuqmi kayta atin.\nAllin qillqasqaykita llanchiriy, ichataq urapi kaq hunt'ana p'anqata llamk'achiy [[Special:CreateAccount|musuq rakiqunata kicharinaykipaq]].",
"nosuchusershort": "Nisqayki \"$1\" sutiyuq ruraqqa manam kanchu.\nAllin qillqasqaykita llanchiriy.",
"nouserspecified": "Ruraqpa sutiykitam qunayki.",
"login-userblocked": "Kay ruraqqa hark'asqam. Manam yaykuyta atinchu.",
"accmailtext": "Kikinmanta kamarisqa [[User talk:$1|$1]]-paq yaykuna rimaqa $2-manmi kachasqaña.\n\nYaykurqaspaqa ''[[Special:ChangePassword|yaykuna rima hukchana]]'' p'anqapi kay yaykuna rimata hukchaytam atinki.",
"newarticle": "(Musuq)",
"newarticletext": "Manaraq kachkaq p'anqatam llamk'apuchkanki. Musuq p'anqata kamariyta munaspaykiqa, qillqarillay. Astawan ñawiriyta munaspaykiqa, [$1 yanapana p'anqata] qhaway. Mana munaspaykitaq, ñawpaq p'anqaman ripuy.",
- "anontalkpagetext": "---- ''Kayqa huk sutinnaq icha mana sutinta llamk'achiq ruraqpa rimanakuyninmi. IP huchhantam hallch'asunchik payta sutinchanapaq. Achka ruraqkunam huklla IP huchhanta llamk'achiyta atin. Sutinnaq ruraq kaspaykiqa, mana qampa rurasqaykimanta willamusqakunata rikuspaykiqa, ama hina kaspa [[Special:UserLogin/signup|rakiqunaykita kamariy]] icha [[Special:UserLogin|yaykuy]] huk sutinnaq ruraqkunawan ama pantasqa kanaykipaq.''",
+ "anontalkpagetext": "---- ''Kayqa huk sutinnaq icha mana sutinta llamk'achiq ruraqpa rimanakuyninmi. IP huchhantam hallch'asunchik payta sutinchanapaq. Achka ruraqkunam huklla IP huchhanta llamk'achiyta atin. Sutinnaq ruraq kaspaykiqa, mana qampa rurasqaykimanta willamusqakunata rikuspaykiqa, ama hina kaspa [[Special:CreateAccount|rakiqunaykita kamariy]] icha [[Special:UserLogin|yaykuy]] huk sutinnaq ruraqkunawan ama pantasqa kanaykipaq.''",
"noarticletext": "Kunanqa kay p'anqa ch'usaqmi kachkan.\nKaytam rurayta atinkiman: kay p'anqap sutinta [[Special:Search/{{PAGENAME}}|huk p'anqakunapi maskay]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} hallch'ankunapi maskay]\nicha [{{fullurl:{{FULLPAGENAME}}|action=edit}} kay p'anqata llamk'apuy]</span>.",
"noarticletext-nopermission": "Kunanqa kay p'anqa ch'usaqmi kachkan.\nKaytam rurayta atinkiman: kay p'anqap sutinta [[Special:Search/{{PAGENAME}}|huk p'anqakunapi maskay]]\nicha payman kapuq <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} hallch'akunapi maskay]</span>,\nichataq kay p'anqata kamariyta manam saqillasunkichu.",
"missing-revision": "\"{{FULLPAGENAME}}\" nisqa p'anqapaq #$1 musuqchasqaqa manam kanchu.\n\nKayqa tukurqanman qullusqa p'anchaman t'inkimuq mawk'ayasqa wiñay kawsay t'inkiraykuchá.\nImaymanata [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} qulluy hallch'apim] tariykiman.",
"noname": "Ti n'has betg inditgà in num d'utilisader valid.",
"loginsuccesstitle": "T'annunzià cun success",
"loginsuccess": "'''Ti es t'annunzia tar {{SITENAME}} sco \"$1\".'''",
- "nosuchuser": "I n'exista nagin utilisader cun il num \"$1\".\nFa stim dad utilisar correctamain maiusclas e minusclas.\nCurregia il num u [[Special:UserLogin/signup|creescha in nov conto]].",
+ "nosuchuser": "I n'exista nagin utilisader cun il num \"$1\".\nFa stim dad utilisar correctamain maiusclas e minusclas.\nCurregia il num u [[Special:CreateAccount|creescha in nov conto]].",
"nosuchusershort": "I na dat nagin utilisader cun il num \"$1\".\nCurregia ti'endataziun.",
"nouserspecified": "Inditgescha per plaschair in num d'utilisader.",
"login-userblocked": "Quest utilisader è bloccà. Betg pussaivel da t'annunziar.",
"accmailtext": "In pled-clav casual per [[User talk:$1|$1]] è vegnì tramess a $2. El po vegnir midà sin la pagina ''[[Special:ChangePassword|midar pled-clav]]'' suenter che ti t'es annunzià.",
"newarticle": "(Nov)",
"newarticletext": "Ti has cliccà ina colliaziun ad ina pagina che n'exista anc betg. Per crear ina pagina, entschaiva a tippar en la stgaffa sutvart (guarda [$1 la pagina d'agid] per t'infurmar).",
- "anontalkpagetext": "----''Quai è la pagina da discussiun per in utilisader anomim che n'ha anc betg creà in conto d'utilisader u che n'al utilisescha betg.\nPerquai avain nus d'utilisar l'adressa dad IP per l'identifitgar.\nIna tala adressa dad IP po vegnir utilisada da differents utilisaders.\nSche ti es in utilisaders anonim e pensas che commentaris che na pertutgan betg tai vegnan adressads a tai, lura [[Special:UserLogin/signup|creescha in conto]] u [[Special:UserLogin|t'annunzia]] per evitar en futur che ti vegns sbaglià cun auters utilisaders.''",
+ "anontalkpagetext": "----''Quai è la pagina da discussiun per in utilisader anomim che n'ha anc betg creà in conto d'utilisader u che n'al utilisescha betg.\nPerquai avain nus d'utilisar l'adressa dad IP per l'identifitgar.\nIna tala adressa dad IP po vegnir utilisada da differents utilisaders.\nSche ti es in utilisaders anonim e pensas che commentaris che na pertutgan betg tai vegnan adressads a tai, lura [[Special:CreateAccount|creescha in conto]] u [[Special:UserLogin|t'annunzia]] per evitar en futur che ti vegns sbaglià cun auters utilisaders.''",
"noarticletext": "Quest artitgel na cuntegna actualmain nagin text.\nTi pos [[Special:Search/{{PAGENAME}}|tschertgar il term]] sin in'autra pagina,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tschertgar en ils protocols],\nu [{{fullurl:{{FULLPAGENAME}}|action=edit}} crear questa pagina]</span>.",
"noarticletext-nopermission": "Questa pagina na cuntegna actualmain nagin text.\nTi pos [[Special:Search/{{PAGENAME}}|tschertgar quest titel]] en autras paginas u <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tschertgar en ils protocols correspundents]</span>, ma ti n'has betg ils dretgs da crear questa pagina.",
"missing-revision": "La versiun #$1 da la pagina cun il num \"{{FULLPAGENAME}}\" n'exista betg.\n\nQuai capita savnes sche ti cliccas sin ina colliaziun antiquada en la cronologia per ina pagina ch'è vegnida stizzada.\nDetagls pon vegnri chattads en il [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} protocol da stizzar].",
"tog-watchdefault": "Adaugă paginile și fișierele pe care le modific la lista mea de urmărire",
"tog-watchmoves": "Adaugă paginile și fișierele pe care le redenumesc la lista mea de urmărire",
"tog-watchdeletion": "Adaugă paginile și fișierele pe care le șterg la lista mea de urmărire",
+ "tog-watchuploads": "Adaugă în lista de pagini urmărite fișierele noi pe care le încarc",
"tog-watchrollback": "Adaugă în lista mea de pagini urmărite acele pagini asupra cărora am efectuat o revenire",
"tog-minordefault": "Marchează din oficiu toate modificările ca fiind minore",
"tog-previewontop": "Arată previzualizarea deasupra căsuței de modificare",
"password-change-forbidden": "Nu puteți schimba parole pe acest wiki.",
"externaldberror": "A fost fie o eroare de bază de date pentru o autentificare extenă sau nu aveți permisiunea să actualizați contul extern.",
"login": "Autentificare",
+ "login-security": "Verificați-vă identitatea",
"nav-login-createaccount": "Creare cont / Autentificare",
"userlogin": "Creare cont / Autentificare",
"userloginnocreate": "Autentificare",
"userlogin-resetpassword-link": "V-ați uitat parola?",
"userlogin-helplink2": "Ajutor la autentificare",
"userlogin-loggedin": "Sunteți deja {{GENDER:$1|autentificat|autentificată}} ca {{GENDER:$1|$1}}.\nUtilizați formularul de mai jos pentru a vă autentifica cu alt nume de utilizator.",
+ "userlogin-reauth": "Trebuie să vă autentificați din nou pentru a confirma că sunteți {{GENDER:$1|$1}}.",
"userlogin-createanother": "Creează un alt cont",
"createacct-emailrequired": "Adresă de e-mail",
"createacct-emailoptional": "Adresă de e-mail (opțională)",
"createacct-email-ph": "Introduceți adresa dumnevoastră de e-mail",
"createacct-another-email-ph": "Introduceți adresa de e-mail",
"createaccountmail": "Utilizează o parolă temporară aleasă la întâmplare și o trimite la adresa de e-mail indicată",
+ "createaccountmail-help": "Poate fi folosit pentru a crea un cont pentru o altă persoană fără a cunoaște parola.",
"createacct-realname": "Nume real (opțional)",
"createaccountreason": "Motiv:",
"createacct-reason": "Motiv",
"createacct-reason-ph": "De ce creați un alt cont",
+ "createacct-reason-help": "Mesaj care apare în jurnalul de creare a conturilor",
"createacct-submit": "Creați-vă contul",
"createacct-another-submit": "Creează contul",
+ "createacct-continue-submit": "Continuă crearea contului",
+ "createacct-another-continue-submit": "Continuă crearea contului",
"createacct-benefit-heading": "{{SITENAME}} este un proiect clădit de oameni ca dumneavoastră.",
"createacct-benefit-body1": "{{PLURAL:$1|modificare|modificări|de modificări}}",
"createacct-benefit-body2": "{{PLURAL:$1|pagină|pagini|de pagini}}",
"nocookiesnew": "Contul a fost creat, dar nu sunteți autentificat{{GENDER:||ă|}}. {{SITENAME}} folosește module cookie pentru a reține utilizatorii autentificați. Navigatorul dumneavoastră are aceste module cookie dezactivate. Vă rugăm să le activați și să vă reautentificați folosind noul nume de utilizator și noua parolă.",
"nocookieslogin": "{{SITENAME}} folosește module cookie pentru a autentifica utilizatorii. Browser-ul dvs. are cookie-urile dezactivate. Vă rugăm să le activați și să incercați din nou.",
"nocookiesfornew": "Contul de utilizator nu a fost creat, deoarece nu am putut confirma sursa.\nAsigurați-vă că aveți cookie-urile activate, reîncărcați pagina și încercați din nou.",
+ "createacct-loginerror": "Contul a fost creat cu succes, dar nu s-a putut efectua autentificarea automată. Vă rugăm să vă [[Special:UserLogin|autentificați manual]].",
"noname": "Numele de utilizator pe care l-ați introdus nu este valid.",
"loginsuccesstitle": "Autentificat(ă)",
"loginsuccess": "'''Ați fost autentificat la {{SITENAME}} ca „$1”.'''",
- "nosuchuser": "Nu există nici un utilizator cu numele „$1”.\nNumele de utilizatori sunt sensibile la majuscule.\nVerifică dacă ai scris corect sau [[Special:UserLogin/signup|creează un nou cont de utilizator]].",
+ "nosuchuser": "Nu există nici un utilizator cu numele „$1”.\nNumele de utilizatori sunt sensibile la majuscule.\nVerificați dacă ați scris corect sau [[Special:CreateAccount|creați un nou cont de utilizator]].",
"nosuchusershort": "Nu există niciun utilizator cu numele „$1”.\nVerificați ortografierea.",
"nouserspecified": "Trebuie să specificați un nume de utilizator.",
"login-userblocked": "Acest utilizator este blocat. Autentificarea nu este permisă.",
"createacct-another-realname-tip": "Numele real este opțional.\nDacă decideți furnizarea sa, acesta va fi folosit pentru a atribui utilizatorului munca sa.",
"pt-login": "Autentificare",
"pt-login-button": "Autentificare",
+ "pt-login-continue-button": "Continuă autentificarea",
"pt-createaccount": "Creare cont",
"pt-userlogout": "Închide sesiunea",
"php-mail-error-unknown": "Eroare necunoscută în funcția PHP mail()",
"passwordreset-emailsentusername": "Dacă există o adresă de e-mail asociată acestui nume de utilizator, atunci se va trimite un e-mail de resetare a parolei.",
"passwordreset-emailsent-capture": "Un mesaj de resetare a parolei a fost trimis, fiind afișat mai jos.",
"passwordreset-emailerror-capture": "Un mesaj de resetare a parolei a fost generat (fiind afișat mai jos), dar trimiterea sa către {{GENDER:$2|utilizator}} a eșuat: $1",
+ "passwordreset-invalideamil": "Adresă de e-mail nevalidă",
+ "passwordreset-nodata": "Nu au fost furnizate un nume de utilizator sau o adresă de e-mail",
"changeemail": "Modificare sau înlăturare adresă de e-mail",
"changeemail-header": "Completați acest formular pentru a vă schimba adresa de e-mail. Dacă doriți să înlăturați orice asociere a unei adrese de e-mail cu contul dumneavoastră, lăsați necompletat câmpul pentru introducerea unei noi adrese de e-mail atunci când trimiteți formularul.",
"changeemail-passwordrequired": "Va trebui să introduceți parola pentru a confirma această schimbare.",
"minoredit": "Aceasta este o modificare minoră",
"watchthis": "Urmărește această pagină",
"savearticle": "Salvare pagină",
+ "publishpage": "Publică pagina",
"preview": "Previzualizare",
"showpreview": "Previzualizare",
"showdiff": "Afișare diferențe",
"accmailtext": "O parolă generată aleator pentru [[User talk:$1|$1]] a fost trimisă la $2. Parola poate fi schimbată după autentificare din pagina ''[[Special:ChangePassword|schimbare parolă]]''.",
"newarticle": "(Nou)",
"newarticletext": "Ați încercat să ajungeți la o pagină care nu există. Pentru a o crea, începeți să scrieți în caseta de mai jos (vedeți [$1 pagina de ajutor] pentru mai multe informații). Dacă ați ajuns aici din greșeală, întoarceți-vă folosind controalele navigatorului dumneavoastră.",
- "anontalkpagetext": "---- ''Aceasta este pagina de discuții pentru un utilizator care nu și-a creat un cont încă, sau care nu s-a autentificat.\nDe aceea trebuie să folosim adresă IP pentru a identifica această persoană.\nO adresă IP poate fi folosită în comun de mai mulți utilizatori.\nDacă sunteți un astfel de utilizator și credeți că vă sunt adresate mesaje irelevante, vă rugăm să [[Special:UserLogin/signup|vă creați un cont]] sau să [[Special:UserLogin|vă autentificați]] pentru a evita confuzii cu alți utilizatori anonimi în viitor.''",
+ "anontalkpagetext": "---- ''Aceasta este pagina de discuții pentru un utilizator care nu și-a creat un cont încă, sau care nu s-a autentificat.\nDe aceea trebuie să folosim adresă IP pentru a identifica această persoană.\nO adresă IP poate fi folosită în comun de mai mulți utilizatori.\nDacă sunteți un astfel de utilizator și credeți că vă sunt adresate mesaje irelevante, vă rugăm să [[Special:CreateAccount|vă creați un cont]] sau să [[Special:UserLogin|vă autentificați]] pentru a evita confuzii cu alți utilizatori anonimi în viitor.''",
"noarticletext": "Actualmente, această pagină este lipsită de conținut.\nPuteți [[Special:Search/{{PAGENAME}}|căuta titlul acestei pagini]] în alte pagini, puteți <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} căuta înregistrări în jurnalele relevante]\nsau puteți [{{fullurl:{{FULLPAGENAME}}|action=edit}} crea această pagină]</span>.",
"noarticletext-nopermission": "Actualmente, această pagină este lipsită de conținut.\nPuteți [[Special:Search/{{PAGENAME}}|căuta acest titlu]] în alte pagini sau puteți <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} căuta înregistrări în jurnale]</span>; nu aveți însă permisiunea de a crea această pagină.",
"missing-revision": "Versiunea nr. $1 a paginii „{{FULLPAGENAME}}” nu există.\n\nAcest lucru se întâmplă de obicei atunci când se accesează o legătură expirată către istoricul unei pagini șterse.\nDetalii se pot găsi în [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jurnalul ștergerilor].",
"revdelete-unsuppress": "Anulează restricțiile la versiunile restaurate",
"revdelete-log": "Motivul ștergerii:",
"revdelete-submit": "Aplică {{PLURAL:$1|versiunii selectate|versiunilor selectate}}",
- "revdelete-success": "'''Vizibilitatea versiunilor a fost schimbată cu succes.'''",
+ "revdelete-success": "Vizibilitatea versiunilor a fost schimbată.",
"revdelete-failure": "'''Nu s-a putut modifica vizibilitatea versiunii:'''\n$1",
- "logdelete-success": "'''Jurnalul vizibilității a fost configurat cu succes.'''",
+ "logdelete-success": "Vizibilitatea jurnalului modificată.",
"logdelete-failure": "'''Vizibilitatea jurnalului nu poate fi definită:'''\n$1",
"revdel-restore": "Schimbă vizibilitatea",
"pagehist": "Istoricul paginii",
"mergehistory-fail-bad-timestamp": "Ora și data nu sunt valide.",
"mergehistory-fail-invalid-source": "Pagina sursă nu este validă.",
"mergehistory-fail-invalid-dest": "Pagina de destinație nu este validă.",
+ "mergehistory-fail-no-change": "Unificarea istoricului nu a unit nicio versiune. Verificați din nou pagina și parametrii temporali.",
+ "mergehistory-fail-permission": "Permisiuni insuficiente pentru a uni istoricul.",
+ "mergehistory-fail-self-merge": "Paginile sursă și destinație sunt identice.",
"mergehistory-fail-toobig": "Nu s-a putut efectua unirea istoricelor întrucât s-ar fi depășit limita de $1 {{PLURAL:$1|versiune|versiuni|de versiuni}} mutat{{PLURAL:$1|ă|e}}.",
"mergehistory-no-source": "Pagina sursă $1 nu există.",
"mergehistory-no-destination": "Pagina de destinație $1 nu există.",
"prefs-personal": "Informații personale",
"prefs-rc": "Schimbări recente",
"prefs-watchlist": "Listă de urmărire",
- "prefs-editwatchlist": "Modifică lista de pagini urmărite",
+ "prefs-editwatchlist": "Modificare listă de pagini urmărite",
"prefs-editwatchlist-label": "Modificați titluri din lista dumneavoastră de pagini urmărite:",
- "prefs-editwatchlist-edit": "Vizualizați și eliminați titluri din lista dumneavoastră de pagini urmărite",
+ "prefs-editwatchlist-edit": "Vizualizare și eliminare titluri din lista dumneavoastră de pagini urmărite",
"prefs-editwatchlist-raw": "Modifică lista brută de pagini urmărite",
- "prefs-editwatchlist-clear": "Goliți-vă lista de pagini urmărite",
+ "prefs-editwatchlist-clear": "Golește-mi lista de pagini urmărite",
"prefs-watchlist-days": "Numărul de zile care apar în lista paginilor urmărite:",
"prefs-watchlist-days-max": "Maxim $1 {{PLURAL:$1|zi|zile}}",
"prefs-watchlist-edits": "Numărul de modificări care apar în lista extinsă a paginilor urmărite:",
"right-override-export-depth": "Exportă inclusiv paginile legate până la o adâncime de 5",
"right-sendemail": "Trimite e-mail altor utilizatori",
"right-passwordreset": "Vizualizează e-mailurile de reinițializare a parolelor",
- "right-managechangetags": "Creează și șterge [[Special:Tags|etichete]] din baza de date",
+ "right-managechangetags": "Creează și (dez)activează [[Special:Tags|etichete]]",
"right-applychangetags": "Aplică [[Special:Tags|etichete]] asociate modificărilor unui utilizator",
"right-changetags": "Adaugă și înlătură [[Special:Tags|etichete]] arbitrare din versiuni și intrări de jurnal individuale",
+ "right-deletechangetags": "Șterge [[Special:Tags|etichete]] din baza de date",
+ "grant-generic": "set de permisiuni „$1”",
+ "grant-group-page-interaction": "Interacționează cu paginile",
+ "grant-group-file-interaction": "Interacționează cu conținut media",
"grant-basic": "Drepturi de bază",
"newuserlogpage": "Jurnal utilizatori noi",
"newuserlogpagetext": "Acesta este jurnalul creărilor conturilor de utilizator.",
"action-viewmyprivateinfo": "vă vizualizați informațiile personale",
"action-editmyprivateinfo": "să vă modificați informațiile personale",
"action-editcontentmodel": "modificați modelul de conținut al unei pagini",
- "action-managechangetags": "creați și să ștergeți etichete din baza de date",
+ "action-managechangetags": "creați și să (dez)activați etichete",
"action-applychangetags": "aplicați etichete asociate modificărilor dumneavoastră",
"action-changetags": "adăugați și să înlăturați etichete arbitrare din versiuni și intrări de jurnal individuale",
+ "action-deletechangetags": "ștergeți etichete din baza de date",
"nchanges": "$1 {{PLURAL:$1|modificare|modificări|de modificări}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|de la ultima vizită}}",
"enhancedrc-history": "istoric",
"upload-form-label-own-work": "Aceasta este propria mea operă",
"upload-form-label-infoform-categories": "Categorii",
"upload-form-label-infoform-date": "Dată",
- "upload-form-label-own-work-message-local": "Confirm că încarc acest fișier în concordanță cu termenii serviciului și politicile de licențiere de la {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Dacă nu puteți încărca acest fișier în conformitate cu politicile de la {{SITENAME}}, închideți această casetă de dialog și încercați altă metodă.",
- "upload-form-label-not-own-work-local-local": "Poate doriți să încercați [[Special:Upload|pagina de încărcare implicită]].",
- "upload-form-label-own-work-message-default": "Înțeleg că încarc acest fișier într-un depozit partajat. Confirm că fac acest lucru conform termenilor serviciului și politicilor de licențiere de acolo.",
- "upload-form-label-not-own-work-message-default": "Dacă nu puteți încărca acest fișier în conformitate cu politicile depozitului partajat, închideți această casetă de dialog și încercați altă metodă.",
- "upload-form-label-not-own-work-local-default": "Poate doriți să încercați [[Special:Upload|pagina de încărcare de la {{SITENAME}}]], în cazul în care acest fișier poate fi încărcat acolo în conformitate cu politicele lor.",
- "upload-form-label-own-work-message-shared": "Declar că dețin drepturile de autor asupra acestui fișier, accept să public irevocabil acest fișier la Wikimedia Commons sub licența [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Atribuire și distribuire în condiții identice 4.0] și sunt de acord cu [https://wikimediafoundation.org/wiki/Terms_of_Use Termenii de utilizare].",
- "upload-form-label-not-own-work-message-shared": "Dacă nu dețineți drepturile de autor asupra acestui fișier sau doriți să-l publicați sub o altă licență, puteți utiliza [https://commons.wikimedia.org/wiki/Special:UploadWizard Expertul de încărcare de la Commons].",
- "upload-form-label-not-own-work-local-shared": "Poate doriți să încercați [[Special:Upload|pagina de încărcare de la {{SITENAME}}]], în cazul în care acest site permite încărcarea acestui fișier în conformitate cu politicele lor.",
+ "upload-form-label-own-work-message-generic-local": "Confirm că încarc acest fișier în concordanță cu termenii serviciului și politicile de licențiere de la {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Dacă nu puteți încărca acest fișier în conformitate cu politicile de la {{SITENAME}}, închideți această casetă de dialog și încercați altă metodă.",
+ "upload-form-label-not-own-work-local-generic-local": "Poate doriți să încercați [[Special:Upload|pagina de încărcare implicită]].",
+ "upload-form-label-own-work-message-generic-foreign": "Înțeleg că încarc acest fișier într-un depozit partajat. Confirm că fac acest lucru conform termenilor serviciului și politicilor de licențiere de acolo.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Dacă nu puteți încărca acest fișier în conformitate cu politicile depozitului partajat, închideți această casetă de dialog și încercați altă metodă.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Poate doriți să încercați [[Special:Upload|pagina de încărcare de la {{SITENAME}}]], în cazul în care acest fișier poate fi încărcat acolo în conformitate cu politicele lor.",
"backend-fail-stream": "Imposibil de citit fișierul $1.",
"backend-fail-backup": "Imposibil de efectuat o copie de rezervă a fișierului $1.",
"backend-fail-notexists": "Fișierul $1 nu există.",
"changecontentmodel-success-text": "Tipul de conținut al paginii [[:$1]] a fost modificat.",
"changecontentmodel-cannot-convert": "Conținutul paginii [[:$1]] nu poate fi convertit în tipul $2.",
"changecontentmodel-nodirectediting": "Modelul de conținut $1 nu acceptă editarea directă",
+ "changecontentmodel-emptymodels-title": "Nu sunt disponibile modele de conținut",
+ "changecontentmodel-emptymodels-text": "Conținutul paginii [[:$1]] nu poate fi convertit în alt tip.",
"log-name-contentmodel": "Jurnal modificări model de conținut",
"log-description-contentmodel": "Evenimente referitoare la modelele de conținut ale paginilor",
"logentry-contentmodel-change": "$1 {{GENDER:$2|a modificat}} modelul de conținut al paginii $3 din „$4” în „$5”",
"ipb-unblock": "Deblocați un nume de utilizator sau o adresă IP",
"ipb-blocklist": "Vezi blocările existente",
"ipb-blocklist-contribs": "Contribuțiile {{GENDER:$1|utilizatorului $1|utilizatoarei $1}}",
+ "ipb-blocklist-duration-left": "$1 a mai rămas",
"unblockip": "Deblochează adresă IP",
"unblockiptext": "Folosiți formularul de mai jos pentru a restaura permisiunea de scriere pentru adrese IP sau nume de utilizator blocate anterior.",
"ipusubmit": "Elimină blocarea",
"lockdbsuccesstext": "Baza de date a fost blocată.<br />\nNu uitați să o [[Special:UnlockDB|deblocați]] la terminarea operațiilor administrative.",
"unlockdbsuccesstext": "Baza de date a fost deblocată.",
"lockfilenotwritable": "Fișierul bazei de date închise nu poate fi scris.\nPentru a închide sau deschide baza de date, acesta trebuie să poată fi scris de serverul web.",
+ "databaselocked": "Baza de date este deja blocată.",
"databasenotlocked": "Baza de date nu este blocată.",
"lockedbyandtime": "(de $1, pe $2, la $3 )",
"move-page": "Redenumire $1",
"confirm-watch-top": "Adăugați această pagină la lista de pagini urmărite?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Eliminați această pagină din lista de pagini urmărite?",
+ "confirm-rollback-button": "OK",
"quotation-marks": "„$1”",
"imgmultipageprev": "← pagina anterioară",
"imgmultipagenext": "pagina următoare →",
"tags-edit-revision-legend": "Adaugă sau înlătură etichete din {{PLURAL:$1|această versiune|toate cele $1 versiuni|toate cele $1 de versiuni}}",
"tags-edit-logentry-legend": "Adaugă sau înlătură etichete din {{PLURAL:$1|această intrare din jurnal|toate cele $1 intrări din jurnal|toate cele $1 de intrări din jurnal}}",
"tags-edit-existing-tags": "Etichete existente:",
- "tags-edit-existing-tags-none": "''Niciuna''",
+ "tags-edit-existing-tags-none": "<em>Niciuna</em>",
"tags-edit-new-tags": "Etichete noi:",
"tags-edit-add": "Se adaugă aceste etichete:",
"tags-edit-remove": "Se șterg aceste etichete:",
"tags-edit-reason": "Motiv:",
"tags-edit-revision-submit": "Aplică modificările {{PLURAL:$1|acestei versiuni|celor $1 versiuni|celor $1 de versiuni}}",
"tags-edit-logentry-submit": "Aplică modificările {{PLURAL:$1|acestei intrări din jurnal|celor $1 intrări din jurnal|celor $1 de intrări din jurnal}}",
- "tags-edit-success": "Modificările au fost aplicate cu succes.",
+ "tags-edit-success": "Modificările au fost aplicate.",
"tags-edit-failure": "Modificările nu au putut fi aplicate:\n$1",
"tags-edit-nooldid-title": "Versiune-țintă nevalidă",
"tags-edit-nooldid-text": "Fie nu ați indicat nicio versiune-țintă pe care să aplicați această funcție, fie versiunea indicată nu există.",
"logentry-protect-protect-cascade": "$1 {{GENDER:$2|a protejat}} $3 $4 [protecție în cascadă]",
"logentry-protect-modify": "$1 {{GENDER:$2|a modificat}} nivelul protecției pentru $3 $4",
"logentry-protect-modify-cascade": "$1 {{GENDER:$2|a modificat}} nivelul protecției pentru $3 $4 [protecție în cascadă]",
- "logentry-rights-rights": "$1 {{GENDER:$2|a schimbat}} apartenența la grup pentru $3 de la $4 la $5",
+ "logentry-rights-rights": "$1 {{GENDER:$2|a schimbat}} apartenența la grup pentru {{GENDER:$6|$3}} de la $4 la $5",
"logentry-rights-rights-legacy": "$1 {{GENDER:$2|a schimbat}} apartenența la grup pentru $3",
"logentry-rights-autopromote": "$1 {{GENDER:$2|a fost promovat|a fost promovată}} în mod automat de la $4 la $5",
"logentry-upload-upload": "$1 {{GENDER:$2|a încărcat}} $3",
"feedback-useragent": "Agent utilizator:",
"searchsuggest-search": "Căutare",
"searchsuggest-containing": "conținând...",
+ "api-error-autoblocked": "Adresa dumnevoastră IP a fost blocată automat, pentru că a fost folosită de un utilizator blocat.",
"api-error-badaccess-groups": "Nu aveți dreptul să încărcați fișiere pe acest wiki.",
"api-error-badtoken": "Eroare internă: jeton greșit.",
+ "api-error-blocked": "Vi s-a blocat accesul la modificări.",
"api-error-copyuploaddisabled": "Încărcarea prin URL este dezactivată pe acest server.",
"api-error-duplicate": "Există {{PLURAL:$1|un alt fișier deja încărcat|alte fișiere deja încărcate}} cu același conținut.",
"api-error-duplicate-archive": "{{PLURAL:$1|A existat un alt fișier|Au existat alte fișiere}} cu același conținut pe site, dar {{PLURAL:$1|a fost|au fost}} șterse.",
"api-error-nomodule": "Eroare internă: niciun modul de încărcare setat.",
"api-error-ok-but-empty": "Eroare internă: niciun răspuns de la server.",
"api-error-overwrite": "Nu este permisă suprascrierea unui fișier existent.",
+ "api-error-ratelimited": "Ați încercat să încărcați într-un interval de timp scurt mai multe fișiere decât permite acest wiki.\nÎncercați din nou peste câteva minute.",
"api-error-stashfailed": "Eroare internă: serverul nu a putut stoca fișierul temporar.",
"api-error-publishfailed": "Eroare internă: serverul nu a putut publica fișierul temporar.",
"api-error-stasherror": "A apărut o eroare la încărcarea fișierului în depozitul temporar.",
"api-error-unknownerror": "Eroare necunoscută: „$1”.",
"api-error-uploaddisabled": "Încărcarea este dezactivată pe acest wiki.",
"api-error-verification-error": "Acest fișier ar putea fi corupt sau poate avea extensia greșită.",
+ "api-error-was-deleted": "Un fișier cu același nume a fost deja încărcat în trecut și ulterior șters.",
"duration-seconds": "$1 {{PLURAL:$1|secundă|secunde|de secunde}}",
"duration-minutes": "$1 {{PLURAL:$1|minut|minute|de minute}}",
"duration-hours": "$1 {{PLURAL:$1|oră|ore|de ore}}",
"expand_templates_generate_xml": "Arată arborele de analiză XML",
"expand_templates_generate_rawhtml": "Arată HTML brut",
"expand_templates_preview": "Previzualizare",
- "expand_templates_preview_fail_html": "<em>Întrucât la {{SITENAME}} este activat HTML brut și a avut loc o pierdere a sesiunii de date, previzualizarea a fost ascunsă ca măsură de precauție împotriva atacurilor prin JavaScript.</em>\n\n<strong>Dacă aceasta este o încercare legitimă de a previzualiza, încercați din nou.</strong>\nDacă nici astfel nu funcționează, încercați să [[Special:UserLogout|închideţi sesiunea]] şi să vă autentificaţi din nou.",
+ "expand_templates_preview_fail_html": "<em>Întrucât la {{SITENAME}} este activat HTML brut și a avut loc o pierdere a sesiunii de date, previzualizarea a fost ascunsă ca măsură de precauție împotriva atacurilor prin JavaScript.</em>\n\n<strong>Dacă aceasta este o încercare legitimă de a previzualiza, încercați din nou.</strong>\nDacă nici astfel nu funcționează, încercați să [[Special:UserLogout|închideţi sesiunea]] şi să vă autentificaţi din nou și să verificați dacă navigatorul dumneavoastră permite module cookie pentru acest site.",
"expand_templates_preview_fail_html_anon": "<em>Întrucât la {{SITENAME}} este activat HTML brut și nu v-ați autentificat, previzualizarea a fost ascunsă ca măsură de precauție împotriva atacurilor prin JavaScript.</em>\n\n<strong>Dacă aceasta este o încercare legitimă de a previzualiza, [[Special:UserLogin|autentificați-vă]] și încercați din nou.</strong>",
"expand_templates_input_missing": "Trebuie să furnizați cel puțin un text ca date de intrare.",
"pagelanguage": "Modificare limbă pagină",
"noname": "Non gìè specifichete 'nu nome utende valide.",
"loginsuccesstitle": "Tutte a poste, è trasute!",
"loginsuccess": "'''Mò tu si colleghete jndr'à {{SITENAME}} cumme \"$1\".'''",
- "nosuchuser": "Non g'esiste n'utende cu 'u nome \"$1\".\nFà attenzione ca le nome de l'utinde so senzibbele a le lettere granne e piccenne.\nVide bbuene a cumme l'è scritte, o [[Special:UserLogin/signup|ccreje n'utende nuève]].",
+ "nosuchuser": "Non g'esiste n'utende cu 'u nome \"$1\".\nFà attenzione ca le nome de l'utinde so senzibbele a le lettere granne e piccenne.\nVide bbuene a cumme l'è scritte, o [[Special:CreateAccount|ccreje n'utende nuève]].",
"nosuchusershort": "Non ge ste nisciune utende cu 'u nome \"$1\".\nCondrolle accume l'è scritte.",
"nouserspecified": "A scrivere pe forze 'u nome de l'utende.",
"login-userblocked": "Stu utende jè bloccate. Non ge puè trasè.",
"accmailtext": "'A passuord ccrejate a uecchije pe [[User talk:$1|$1]] ha state mannate sus a $2.\n\n'A passuord pe stu cunde utende pò essere cangiate sus a pàgene ''[[Special:ChangePassword|cange passuord]]'' 'na vote ca è trasute.",
"newarticle": "(Nuève)",
"newarticletext": "Tu ste segue 'nu collegamende a pàgene ca angore non g'esiste.\nPe ccrejà 'a pàgene, accuminze a scrivere jndr'à 'u scatole de sotte (vide 'a [$1 pàggene d'ajute] pe avè cchiù 'mbormaziune).\nCe tu te iacche aqquà e manghe tu 'u se purcè, allore cazze 'u buttone '''back''' d'u brauser.",
- "anontalkpagetext": "----''Queste jè 'na pàgene de 'ngazzaminde pe 'n'utende anonime, ca non ge vò ccu ccreje angore 'nu cunde utende, o de ce non g'u use.\nNuje auseme 'n'indirizze IP (ca jè numereche) pe identificarle.\nE' normale ca essende 'n'indirizze IP pò essere ausete pure da otre utinde ca 'u pigghiene.\nCe tu non ge si 'n'utende anonime e pinze ca le commende ca so revolte a te sonde studecarije, pe piacere [[Special:UserLogin/signup|ccreje 'nu cunde utende]] o [[Special:UserLogin|tràse]] pe no fà confusione jndr'à 'u future cu otre utinde anoneme.''",
+ "anontalkpagetext": "----''Queste jè 'na pàgene de 'ngazzaminde pe 'n'utende anonime, ca non ge vò ccu ccreje angore 'nu cunde utende, o de ce non g'u use.\nNuje auseme 'n'indirizze IP (ca jè numereche) pe identificarle.\nE' normale ca essende 'n'indirizze IP pò essere ausete pure da otre utinde ca 'u pigghiene.\nCe tu non ge si 'n'utende anonime e pinze ca le commende ca so revolte a te sonde studecarije, pe piacere [[Special:CreateAccount|ccreje 'nu cunde utende]] o [[Special:UserLogin|tràse]] pe no fà confusione jndr'à 'u future cu otre utinde anoneme.''",
"noarticletext": "Non ge stè scritte ninde jndr'à sta pàgene.\nTu puè [[Special:Search/{{PAGENAME}}|cercà pe quiste titele]] jndr'à otre pàggene, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}}] oppure [{{fullurl:{{FULLPAGENAME}}|action=edit}} cange sta pàgene]</span>.",
"noarticletext-nopermission": "Pe mò non ge stè teste jndr'à sta pàgene.\nTu puè [[Special:Search/{{PAGENAME}}|cercà pe stu titole]] jndr'à otre pàggene,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cirche jndr'à l'archivije cullegate]</span>, ma non ge tìne le permesse pe ccrejà sta pàgene.",
"missing-revision": "'A revisione #$1 d'a pàgene chiamate \"{{FULLPAGENAME}}\" non g'esiste.\n\nQuiste succede normalmende purcé 'u cunde jè collegate a 'na pàgene ca ha state scangellate.\nLe dettaglie le puè acchià jndr'à l'[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} archivije de le scangellaziune].",
"password-change-forbidden": "Вы не можете изменить пароль в этой вики.",
"externaldberror": "Произошла ошибка при аутентификации с помощью внешней базы данных или у вас недостаточно прав для внесения изменений в свою внешнюю учётную запись.",
"login": "Представиться системе",
+ "login-security": "Подтвердите свою личность",
"nav-login-createaccount": "Представиться / зарегистрироваться",
"userlogin": "Представиться или зарегистрироваться",
"userloginnocreate": "Представиться",
"userlogin-resetpassword-link": "Сбросить ваш пароль?",
"userlogin-helplink2": "Помощь по входу",
"userlogin-loggedin": "Вы уже вошли как {{GENDER:$1|$1}}.\nИспользуйте форму ниже, чтобы войти под другой учётной записью.",
+ "userlogin-reauth": "Вы должны войти в систему снова, чтобы подтвердить, что вы и есть {{GENDER:$1|$1}}.",
"userlogin-createanother": "Создать другую учётную запись",
"createacct-emailrequired": "Адрес электронной почты",
"createacct-emailoptional": "Адрес электронной почты (необязательно)",
"createacct-email-ph": "Введите свой адрес электронной почты",
"createacct-another-email-ph": "Введите адрес электронной почты",
"createaccountmail": "Использовать сгенерированный случайным образом временный пароль и выслать его на указанный адрес электронной почты",
+ "createaccountmail-help": "\nМожет использоваться, чтобы создать учетную запись для другого лица, не узнавая пароль.",
"createacct-realname": "Настоящее имя (необязательно)",
"createaccountreason": "Причина:",
"createacct-reason": "Причина",
"createacct-reason-ph": "Зачем вы создаёте другую учетную запись",
+ "createacct-reason-help": "Сообщение, отображаемое в журнале создания учётных записей",
"createacct-submit": "Создать учётную запись",
"createacct-another-submit": "Создать учётную запись",
+ "createacct-continue-submit": "Продолжить создание учётной записи",
+ "createacct-another-continue-submit": "Продолжить создание учётной записи",
"createacct-benefit-heading": "{{SITENAME}} — совместный труд таких же людей, как вы.",
"createacct-benefit-body1": "{{PLURAL:$1|правка|правки|правок}}",
"createacct-benefit-body2": "{{PLURAL:$1|статья|статьи|статей}}",
"nocookiesnew": "Участник зарегистрирован, но не представлен. {{SITENAME}} использует «cookies» для представления участников. У вас «cookies» запрещены. Пожалуйста, разрешите их, а затем представьтесь со своиим новым именем участника и паролем.",
"nocookieslogin": "{{SITENAME}} использует «cookies» для представления участников. Вы их отключили. Пожалуйста, включите их и попробуйте снова.",
"nocookiesfornew": "Учётная запись участника не была создана из-за невозможности проверить её источник. \nУбедитесь, что включены «cookies», обновите страницу и попробуйте ещё раз.",
+ "createacct-loginerror": "Учётная запись была успешно создана, но вы не смогли войти в систему автоматически. Пожалуйста, [[Special:UserLogin|авторизуйтесь вручную]].",
"noname": "Вы не указали допустимого имени участника.",
"loginsuccesstitle": "Вход произведён",
"loginsuccess": "Теперь вы работаете под именем $1.",
- "nosuchuser": "Участника с именем «$1» не существует.\nИмена участников чувствительны к регистру букв.\nПроверьте правильность написания имени или [[Special:UserLogin/signup|создайте новую учётную запись]].",
+ "nosuchuser": "Участника с именем «$1» не существует.\nИмена участников чувствительны к регистру букв.\nПроверьте правильность написания имени или [[Special:CreateAccount|создайте новую учётную запись]].",
"nosuchusershort": "Не существует участника с именем «$1». Проверьте написание имени.",
"nouserspecified": "Вы должны указать имя участника.",
"login-userblocked": "Этот участник заблокирован. Вход в систему не разрешён.",
"createacct-another-realname-tip": "Настоящее имя (необязательное поле).\nЕсли вы укажете его, то оно будет использовано для того, чтобы показать, кем была внесена правка страницы.",
"pt-login": "Войти",
"pt-login-button": "Войти",
+ "pt-login-continue-button": "Продолжить процедуру входа",
"pt-createaccount": "Создать учётную запись",
"pt-userlogout": "Выйти",
"php-mail-error-unknown": "Неизвестная ошибка в PHP-функции mail()",
"botpasswords-invalid-name": "Указанное имя участника не содержит разделителя для пароля бота («$1»).",
"botpasswords-not-exist": "У участника «$1» нет пароля для бота с названием «$2».",
"resetpass_forbidden": "Пароль не может быть изменён",
+ "resetpass_forbidden-reason": "Пароли не могут быть изменены: $1",
"resetpass-no-info": "Чтобы обращаться непосредственно к этой странице, вам следует представиться системе.",
"resetpass-submit-loggedin": "Изменить пароль",
"resetpass-submit-cancel": "Отмена",
"passwordreset-emailsentusername": "Если есть адрес электронной почты, связанный с этим именем участника, то будет отправлено письмо для восстановления пароля.",
"passwordreset-emailsent-capture": "Отправлено электронное письмо с информацией о сбросе пароля, текст которого можно увидеть ниже.",
"passwordreset-emailerror-capture": "Было создано электронное письмо с информацией о сбросе пароля, текст которого можно увидеть ниже, однако его не удалось отправить {{GENDER:$2|участнику|участнице}} по следующей причине: $1",
+ "passwordreset-emailsent-capture2": "{{PLURAL:$1|Письмо|Письма}} для сброса пароля {{PLURAL:$1|было отправлено|были отправлены}}. {{PLURAL:$1|Логин и пароль показаны|Список логинов и паролей показан}} ниже.",
+ "passwordreset-invalideamil": "Недопустимый адрес электронной почты",
"changeemail": "Изменить или удалить адрес электронной почты",
"changeemail-header": "Заполните эту форму, чтобы изменить свой адрес электронной почты. Если вы хотите отвязать свой адрес электронной почты от учётной записи, то при заполнении формы оставьте пустым поле нового адреса электронной почты.",
"changeemail-passwordrequired": "Чтобы подтвердить это изменение, вам нужно будет ввести свой пароль.",
"accmailtext": "Сгенерированный случайным образом пароль для [[User talk:$1|$1]] выслан на адрес $2.\n\nПосле авторизации можно будет сменить пароль для этой учётной записи на ''[[Special:ChangePassword|специальной странице смены пароля]]''.",
"newarticle": "(Новая)",
"newarticletext": "Вы перешли по ссылке на страницу, которой пока не существует.\nЧтобы её создать, наберите текст в окне, расположенном ниже (подробнее см. [$1 справочную страницу]).\nЕсли вы оказались здесь по ошибке, просто нажмите кнопку '''назад''' своего браузера.",
- "anontalkpagetext": "----''Эта страница обсуждения принадлежит анонимному участнику, который ещё не создал учётной записи, или не использует её.\nПоэтому для идентификации используется цифровой IP-адрес.\nЭтот же адрес может соответствовать нескольким другим участникам.\nЕсли вы анонимный участник и полагаете, что получили сообщения, адресованные не вам, пожалуйста, [[Special:UserLogin/signup|создайте учётную запись]] или [[Special:UserLogin|представьтесь системе]], чтобы впредь избежать возможной путаницы с другими анонимными участниками.''",
+ "anontalkpagetext": "----\n<em>Эта страница обсуждения анонимного участника, который ещё не создал учётной записи или не использует её.</em>\nПоэтому мы вынуждены для его/её идентификации использовать цифровой IP-адрес.\nЭтот же адрес может использоваться нескольким другим участникам.\nЕсли вы анонимный участник и полагаете, что получили сообщения, адресованные не вам, пожалуйста, [[Special:CreateAccount|создайте учётную запись]] или [[Special:UserLogin|представьтесь системе]], чтобы впредь избежать возможной путаницы с другими анонимными участниками.",
"noarticletext": "В настоящий момент текст на данной странице отсутствует.\nВы можете [[Special:Search/{{PAGENAME}}|найти упоминание данного названия]] на других страницах,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} найти соответствующие записи журналов]\nили '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} создать страницу с таким названием]'''</span>.",
"noarticletext-nopermission": "В настоящее время на этой странице нет текста.\nВы можете [[Special:Search/{{PAGENAME}}|найти упоминание данного названия]] на других страницах,\nили <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} найти соответствующие записи журналов].</span> У вас нет разрешения создать данную страницу.",
"missing-revision": "Версия $1 страницы «{{FULLPAGENAME}}» не существует.\n\nЭто обычно бывает, если последовать по устаревшей ссылке на страницу, которая была удалена.\nПодробности могут быть в [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале удалений].",
"userpage-userdoesnotexist": "Учётной записи «<nowiki>$1</nowiki>» не существует. Убедитесь, что вы действительно желаете создать или изменить эту страницу.",
"userpage-userdoesnotexist-view": "Не зарегистрировано учётной записи «$1».",
"blocked-notice-logextract": "Этот участник в данный момент заблокирован.\nНиже приведена последняя запись из журнала блокировок:",
- "clearyourcache": "'''Замечание.''' Возможно, после сохранения вам придётся очистить кэш своего браузера, чтобы увидеть изменения.\n* '''Firefox / Safari:''' Удерживая клавишу ''Shift'', нажмите на панели инструментов ''Обновить'' либо нажмите ''Ctrl-F5'' или ''Ctrl-R'' (''⌘-R'' на Mac)\n* '''Google Chrome:''' Нажмите ''Ctrl-Shift-R'' (''⌘-Shift-R'' на Mac)\n* '''Internet Explorer:''' Удерживая ''Ctrl'', нажмите ''Обновить'' либо нажмите ''Ctrl-F5''\n* '''Opera:''' Выберите очистку кэша в меню ''Инструменты → Настройки''",
+ "clearyourcache": "<strong>Замечание.</strong> Возможно, после сохранения вам придётся очистить кэш своего браузера, чтобы увидеть изменения.\n* <strong>Firefox / Safari:</strong> Удерживая клавишу <em>Shift</em>, нажмите на панели инструментов <em>Обновить</em> либо нажмите <em>Ctrl-F5</em> или <em>Ctrl-R</em> (<em>⌘-R</em> на Mac)\n* <strong>Google Chrome:</strong> Нажмите <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> на Mac)\n* <strong>Internet Explorer:</strong> Удерживая <em>Ctrl</em>, нажмите <em>Обновить</em> либо нажмите <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Перейдите в <em>Menu → Настройки</em> (<em>Opera → Настройки</em> на Mac), а затем <em>Безопасность → Очистить историю посещений → Кэшированные изображения и файлы</em>",
"usercssyoucanpreview": "'''Подсказка.''' Нажмите кнопку «{{int:showpreview}}», чтобы проверить свой новый CSS-файл перед сохранением.",
"userjsyoucanpreview": "'''Подсказка.''' Нажмите кнопку «{{int:showpreview}}», чтобы проверить свой новый JS-файл перед сохранением.",
"usercsspreview": "'''Помните, что это только предварительный просмотр вашего CSS-файла, он ещё не сохранён!'''",
"right-override-export-depth": "экспортирование страниц, включая связанные страницы с глубиной до 5",
"right-sendemail": "отправка электронной почты другим участникам",
"right-passwordreset": "просмотр электронных писем с изменением пароля",
- "right-managechangetags": "создание и удаление [[Special:Tags|меток]] из базы данных",
+ "right-managechangetags": "Создание и (де)активация [[Special:Tags|меток]]",
"right-applychangetags": "применение [[Special:Tags|меток]] вместе со своими правками",
"right-changetags": "добавление и удаление произвольных [[Special:Tags|меток]] на отдельных правках и записях в журнале",
+ "right-deletechangetags": "Удаление [[Special:Tags|меток]] из базы данных",
"grant-generic": "Набор прав «$1»",
"grant-group-page-interaction": "Взаимодействие со страницами",
"grant-group-file-interaction": "Взаимодействие с медиафайлами",
"action-viewmyprivateinfo": "просмотр вашей частной информации",
"action-editmyprivateinfo": "редактирование вашей частной информации",
"action-editcontentmodel": "редактирование контентной модели страницы",
- "action-managechangetags": "создание и удаление меток из базы данных",
+ "action-managechangetags": "создание и (де)активацию меток",
"action-applychangetags": " применять теги наряду с Вашими изменениями",
"action-changetags": "Добавлять и удалять произвольные теги на отдельных изменениях и записях в журнале",
+ "action-deletechangetags": "удаление меток из базы данных",
"nchanges": "$1 {{PLURAL:$1|изменение|изменения|изменений}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|с последнего посещения}}",
"enhancedrc-history": "история",
"upload-form-label-own-work": "Это моя собственная работа",
"upload-form-label-infoform-categories": "Категории",
"upload-form-label-infoform-date": "Дата",
- "upload-form-label-own-work-message-local": "Я подтверждаю, что загружаю этот файл в соответствиями с правилами и лицензионной политикой сайта {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Если Вы не можете загрузить этот файл в соответствиями с правилами сайта {{SITENAME}}, пожалуйста, закройте это диалоговое окно и попробуйте другой метод.",
- "upload-form-label-not-own-work-local-local": "Возможно, вы также захотите попробовать [[Special:Upload|страницу загрузки по умолчанию]].",
- "upload-form-label-own-work-message-default": "Я понимаю, что загружаю этот файл в общий репозиторий. Я подтверждаю, что я делаю это в соответствии с пользовательским соглашением и лицензионной политикой.",
- "upload-form-label-not-own-work-message-default": "Если Вы не можете загрузить этот файл в соответствиями с правилами общего хранилища, пожалуйста, закройте это диалоговое окно и попробуйте другой метод.",
- "upload-form-label-not-own-work-local-default": "В том случае, если этот файл может быть загружен в соответствии с правилами сайта {{SITENAME}}, вы также можете попробовать использовать его [[Special:Upload|страницу загрузки]].",
- "upload-form-label-own-work-message-shared": "Я подтверждаю, что являюсь владельцем авторских прав на этот файл, и соглашаюсь на безотзывной основе разместить этот файл на Викискладе под лицензией [https://creativecommons.org/licenses/by-sa/4.0/deed.ru Creative Commons Attribution-ShareAlike 4.0], а также соглашаюсь с [https://wikimediafoundation.org/wiki/Условия_использования Условиями использования].",
- "upload-form-label-not-own-work-message-shared": "Если вы не являетесь владельцем авторских прав на этот файл, или вы хотите выпустить его под другой лицензией, рассмотрите возможность использования [https://commons.wikimedia.org/wiki/Special:UploadWizard Мастера загрузки на Викисладе].",
- "upload-form-label-not-own-work-local-shared": "В том случае, если этот файл может быть загружен в соответствии с правилами сайта {{SITENAME}}, вы также можете попробовать использовать его [[Special:Upload|страницу загрузки]].",
+ "upload-form-label-own-work-message-generic-local": "Я подтверждаю, что загружаю этот файл в соответствиями с правилами и лицензионной политикой сайта {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Если Вы не можете загрузить этот файл в соответствиями с правилами сайта {{SITENAME}}, пожалуйста, закройте это диалоговое окно и попробуйте другой метод.",
+ "upload-form-label-not-own-work-local-generic-local": "Возможно, вы также захотите попробовать [[Special:Upload|страницу загрузки по умолчанию]].",
+ "upload-form-label-own-work-message-generic-foreign": "Я понимаю, что загружаю этот файл в общий репозиторий. Я подтверждаю, что я делаю это в соответствии с пользовательским соглашением и лицензионной политикой.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Если Вы не можете загрузить этот файл в соответствиями с правилами общего хранилища, пожалуйста, закройте это диалоговое окно и попробуйте другой метод.",
+ "upload-form-label-not-own-work-local-generic-foreign": "В том случае, если этот файл может быть загружен в соответствии с правилами сайта {{SITENAME}}, вы также можете попробовать использовать его [[Special:Upload|страницу загрузки]].",
"backend-fail-stream": "Не удалось транслировать файл $1.",
"backend-fail-backup": "Невозможно сделать резервную копию файла $1.",
"backend-fail-notexists": "Файл $1 не существует.",
"changecontentmodel-success-text": "Модель содержимого [[:$1]] была изменена.",
"changecontentmodel-cannot-convert": "Содержимое [[:$1]] не может быть преобразовано к типу $2.",
"changecontentmodel-nodirectediting": "Модель содержимого $1 не поддерживает прямое редактирование",
+ "changecontentmodel-emptymodels-title": "Нет доступных моделей содержимого",
+ "changecontentmodel-emptymodels-text": "Содержимое на [[:$1]] не может быть преобразовано ни к одному типу.",
"log-name-contentmodel": "Журнал изменения моделей содержимого",
"log-description-contentmodel": "События, связанные с моделями содержимого страниц",
"logentry-contentmodel-new": "$1 создал{{GENDER:$2||а}} страницу $3 с использованием нестандартной модели содержимого «$5»",
"lockdbsuccesstext": "База данных проекта была заблокирована.<br />\nНе забудьте [[Special:UnlockDB|убрать блокировку]] после завершения процедуры обслуживания.",
"unlockdbsuccesstext": "База данных проекта была разблокирована.",
"lockfilenotwritable": "Нет права на запись в файл блокировки базы данных. Чтобы заблокировать или разблокировать базу данных, веб-сервер должен иметь разрешение на запись в этот файл.",
+ "databaselocked": "База данных уже заблокирована.",
"databasenotlocked": "База данных не была заблокирована.",
"lockedbyandtime": "($1 $2 $3)",
"move-page": "$1 — переименование",
"tooltip-ca-nstab-category": "Страница категории",
"tooltip-minoredit": "Отметить это изменение как незначительное",
"tooltip-save": "Сохранить ваши изменения",
+ "tooltip-publish": "Опубликовать ваши изменения",
"tooltip-preview": "Предварительный просмотр страницы; пожалуйста, используйте его перед сохранением!",
"tooltip-diff": "Показать изменения, сделанные по отношению к исходному тексту.",
"tooltip-compareselectedversions": "Посмотреть разницу между двумя выбранными версиями этой страницы.",
"confirm-watch-top": "Добавить эту страницу в ваш список наблюдения?",
"confirm-unwatch-button": "ОК",
"confirm-unwatch-top": "Удалить эту страницу из вашего списка наблюдения?",
+ "confirm-rollback-button": "ОК",
+ "confirm-rollback-top": "Откатить правки на этой странице?",
"pipe-separator": " | ",
"word-separator": " ",
"ellipsis": "…",
"timezone-local": "Местное",
"duplicate-defaultsort": "Внимание. Ключ сортировки по умолчанию «$2» переопределяет прежний ключ сортировки по умолчанию «$1».",
"duplicate-displaytitle": "<strong>Внимание:</strong> Отображаемое название «$2» переопределяет ранее заданное отображаемое название «$1».",
+ "restricted-displaytitle": "<strong>Внимание:</strong> Отображаемое название «$1» было проигнорировано, поскольку она не соответствует актуальному названию страницы.",
"invalid-indicator-name": "<strong>Ошибка:</strong> Атрибут <code>name</code> индикаторов состояния страницы не должен быть пустым.",
"version": "Версия",
"version-extensions": "Установленные расширения",
"tags-delete-not-found": "Метка «$1» не существует.",
"tags-delete-too-many-uses": "Метка «$1» применяется в более чем $2 {{PLURAL:$2|версии|версиям}}, что означает, что она не может быть удалена.",
"tags-delete-warnings-after-delete": "Метка «$1» была удалена, но {{PLURAL:$2|было обнаружено следующее предупреждение|были обнаружены следующие предупреждения}}:",
+ "tags-delete-no-permission": "У вас нет прав на удаление изменений меток.",
"tags-activate-title": "Активировать метку",
"tags-activate-question": "Вы собираетесь активировать метку «$1».",
"tags-activate-reason": "Причина:",
"feedback-useragent": "Браузер:",
"searchsuggest-search": "Поиск",
"searchsuggest-containing": "содержащие…",
+ "api-error-autoblocked": "Ваш IP-адрес был автоматически заблокирован, потому что он был использован заблокированным участником.",
"api-error-badaccess-groups": "Вам не разрешено загружать файлы в эту вики.",
"api-error-badtoken": "Внутренняя ошибка: некорректный токен.",
+ "api-error-blocked": "Редактирование было для вас заблокировано.",
"api-error-copyuploaddisabled": "Загрузка по URL-адресу отключена на этом сервере.",
"api-error-duplicate": "Уже {{PLURAL:$1|существует другой файл|существуют другие файлы}} с таким же содержимым.",
"api-error-duplicate-archive": "Раньше на сайте {{PLURAL:$1|1=уже был файл|были файлы}} с точно таким же содержанием, но {{PLURAL:$1|1=он был удалён|они были удалены}}.",
"api-error-nomodule": "Внутренняя ошибка: не настроен модуль загрузки.",
"api-error-ok-but-empty": "Внутренняя ошибка: нет ответа от сервера.",
"api-error-overwrite": "Не допускается замена существующего файла.",
+ "api-error-ratelimited": "Вы пытаетесь загрузить несколько файлов за более короткий промежуток времени, чем это позволено.\nПожалуйста, попробуйте ещё раз через несколько минут.",
"api-error-stashfailed": "Внутренняя ошибка: сервер не смог сохранить временный файл.",
"api-error-publishfailed": "Внутренняя ошибка: сервер не смог сохранить временный файл.",
"api-error-stasherror": "При загрузке файла в хранилище произошла ошибка.",
"log-action-filter-suppress-block": "Сокрытие пользователя через блокировки",
"log-action-filter-suppress-reblock": "Сокрытие пользователя через повторное блокирование",
"log-action-filter-upload-upload": "Новая загрузка",
- "log-action-filter-upload-overwrite": "Повторно загрузить"
+ "log-action-filter-upload-overwrite": "Повторно загрузить",
+ "authmanager-authn-autocreate-failed": "Автоматическое создание локальной учётной записи не удалось: $1",
+ "authmanager-create-disabled": "Создание учётных записей отключено.",
+ "authmanager-authplugin-setpass-failed-title": "Ошибка изменения пароля",
+ "authmanager-authplugin-setpass-bad-domain": "Неверный домен.",
+ "authmanager-autocreate-exception": "Автоматическое создание учётной записи временно отключено из-за предыдущих ошибок.",
+ "authmanager-userdoesnotexist": "Не зарегистрировано учётной записи «$1».",
+ "authmanager-domain-help": "Домен для внешней аутентификации.",
+ "authmanager-email-label": "Электронная почта",
+ "authmanager-email-help": "Адрес электронной почты",
+ "authmanager-realname-label": "Настоящее имя",
+ "authmanager-realname-help": "Настоящее имя участника",
+ "authmanager-provider-password": "Аутентификация на основе пароля",
+ "authmanager-provider-temporarypassword": "Временный пароль",
+ "authprovider-resetpass-skip-label": "Пропустить",
+ "authprovider-resetpass-skip-help": "Пропустить сброс пароля.",
+ "cannotauth-not-allowed-title": "Доступ запрещён",
+ "cannotauth-not-allowed": "Вы не можете использовать эту страницу",
+ "changecredentials": "Изменение учётных данных",
+ "changecredentials-submit": "Изменить учётные данные",
+ "changecredentials-invalidsubpage": "$1 является недопустимым типом учётных данных.",
+ "changecredentials-success": "Ваши учётные данные были изменены.",
+ "removecredentials": "Удалить учётные данные",
+ "removecredentials-submit": "Удалить учётные данные",
+ "removecredentials-success": "Ваши учётные данные были удалены.",
+ "credentialsform-provider": "Тип учётных данных:",
+ "credentialsform-account": "Имя учётной записи:",
+ "linkaccounts": "Связать учётные записи",
+ "linkaccounts-success-text": "Учетная запись была связана.",
+ "linkaccounts-submit": "Связать учётные записи",
+ "unlinkaccounts": "Отвязать учётные записи",
+ "unlinkaccounts-success": "Учетная запись была отвязан."
}
"noname": "Мусите увести мено свого конта.",
"loginsuccesstitle": "Успішне приголошіня",
"loginsuccess": "'''Теперь працуєте {{grammar:locative|{{SITENAME}}}} під меном $1.'''",
- "nosuchuser": "Не екзістує хоснователь з меном «$1». У хосновательскых мен ся розлишують малы/великы писмена. Сконтролюйте запис, або собі [[Special:UserLogin/signup|зареґіструйте нове конто]].",
+ "nosuchuser": "Не екзістує хоснователь з меном «$1». У хосновательскых мен ся розлишують малы/великы писмена. Сконтролюйте запис, або собі [[Special:CreateAccount|зареґіструйте нове конто]].",
"nosuchusershort": "Хоснователь з меном $1 не екзістує.\nПеревірте правилность написаня мена.",
"nouserspecified": "Мусите задати мено хоснователя.",
"login-userblocked": "Тот хоснователь є заблокованый. Приголошіня не є дозволене.",
"accmailtext": "Трафунково выґенероване гесло про хоснователя [[User talk:$1|$1]] было послане на $2.\nОно може быти змінене на [[Special:ChangePassword|сторінцї про зміну гесла]].",
"newarticle": "(Нова)",
"newarticletext": "Перешли сте на сторінку, котра іщі не екзістує.\nНову сторінку створите так, же зачнете писати в окнї ниже (вид. [$1 сторінка помочі], про вецей інформації).\nКідь сте ту помылково, просто кликните в переглядачу на '''назад'''",
- "anontalkpagetext": "----''Тото є діскузна сторінка анонімного хоснователя, котрый іщі не має конто або го не хоснує. Про ёго ідентіфікацію прото мусиме хосновати IP адресу. Таку IP адресу може хосновати декілько хоснователїв. Покы сьте анонімный хоснователь і і уважуєте, же вам суть адресованы ірелевантны коментарї, просиме, [[Special:UserLogin/signup|створьте собі конто]] або [[Special:UserLogin|ся приголосте]], уникнете тым будучій замінї з іншыма анонімныма хоснователями.''",
+ "anontalkpagetext": "----''Тото є діскузна сторінка анонімного хоснователя, котрый іщі не має конто або го не хоснує. Про ёго ідентіфікацію прото мусиме хосновати IP адресу. Таку IP адресу може хосновати декілько хоснователїв. Покы сьте анонімный хоснователь і і уважуєте, же вам суть адресованы ірелевантны коментарї, просиме, [[Special:CreateAccount|створьте собі конто]] або [[Special:UserLogin|ся приголосте]], уникнете тым будучій замінї з іншыма анонімныма хоснователями.''",
"noarticletext": "Теперь на тїй сторінцї не є текст.\nМожете [[Special:Search/{{PAGENAME}}|глядати тоту назву]] в іншых сторінках,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} глядати в лоґах]\nабо [{{fullurl:{{FULLPAGENAME}}|action=edit}} вытворити сторінку з таков назвов]</span>.",
"noarticletext-nopermission": "Теперь на тій сторінцї тексту не є.\nМожете [[Special:Search/{{PAGENAME}}|глядати тоту назву]] в іншых сторінках, або <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} глядати в лоґах]</span>, но вы не мате права створити тоту сторінку.",
"missing-revision": "Ревізія #$1 сторінкы з назвов „{{FULLPAGENAME}}“ не є.\n\nГевсе звычайно запрічінене так, же наслїдовали сьте застарїлый історічный одказ на сторінку, котра была уж змазана.\nДетайлы можуть быти найджены в [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} книзї змазаных сторінок].",
"noname": "भवता/भवत्या योग्यं सदस्यनाम न प्रदत्तम् ।",
"loginsuccesstitle": "स्वागतं ! प्रवेशः सिद्धः ।",
"loginsuccess": "भवता/भवत्या {{SITENAME}} इत्यत्र \"$1\"-योजकत्वेन प्रवेशः प्राप्तः ।",
- "nosuchuser": "'''$1''' नाम्नः न कोऽपि योजकः विद्यते ।\n\nप्रयोक्तृनामानि पक्षानुगुणं (case sensitive) भवन्ति ।\n\nयत् टङ्कितं, तत् पश्यतु अथवा [[Special:UserLogin/signup|नूतनसदस्यता प्राप्यताम्]] ।",
+ "nosuchuser": "'''$1''' नाम्नः न कोऽपि योजकः विद्यते ।\n\nप्रयोक्तृनामानि पक्षानुगुणं (case sensitive) भवन्ति ।\n\nयत् टङ्कितं, तत् पश्यतु अथवा [[Special:CreateAccount|नूतनसदस्यता प्राप्यताम्]] ।",
"nosuchusershort": "'''$1''' नाम्नः न कोऽपि सदस्यः विद्यते ।\n\nयत् टङ्कितं, तत् पश्यतु ।",
"nouserspecified": "भवता/भवत्या एकं योग्यं सदस्यनाम अवश्यमेव दातव्यम् ।",
"login-userblocked": "एषः सदस्यः प्रतिबन्धितः । प्रवेष्टुम् अनुमतिः नास्ति ।",
"accmailtext": "[[User talk:$1|$1]] कृते अशृङ्खलितरीत्या (randomly) उत्पादितः कूटशब्दः $2 वि-पत्रसङ्केतं प्रति प्रेषितः अस्ति । <em>[[Special:ChangePassword|कूटशब्दः परिवर्त्यताम्]]</em> अत्र तत् परिर्तयितुं शक्यते ।",
"newarticle": "(नूतनम्)",
"newarticletext": "भवान्/भवती अनिर्मिते पृष्ठे अस्ति । \nपृष्ठं स्रष्टुम् अधः प्रदत्तायां पेटिकायां टङ्कनं प्रारभताम् (साहाय्यार्थं [$1 अत्र]) नुदतु ।\nभवान्/भवती यदि क्षतिकारणात् एतत् पृष्ठं प्रति आगच्छत्, तर्हि अस्य गवेषकस्य (browser) Back नुदतु ।",
- "anontalkpagetext": "----\n<em>एतत् सम्भाषणपृष्ठम् अनामकसदस्येभ्यः अस्ति । एतत् तेभ्यः अनामकसदस्येभ्यः रचितमस्ति, यैः सदस्यता न प्राप्ता अस्ति तथा च अस्य पृष्ठस्य उपयोगं न कुर्वन्तः सन्ति ।</em>\nतेषां व्यक्तिगतसूचनां प्राप्तुमेव वयं तस्य/तस्याः अन्तर्जालसंविदः उपयोगं कुर्मः । केचन सदस्याः स्वस्य अन्तर्जालसंविदम् अन्यान् सदस्यान् कथयन्ति । \nयद्यपि अनामकसदस्यः अहं नास्मि, तथापि अयोग्यसूचनाः मम पार्श्वे आगच्छन्त्यः सन्ति इति यदि भवान्/भवती शङ्कते, तर्हि एतत् [[Special:UserLogin/signup|create an account]] एतत् [[Special:UserLogin|log in]] वा कृत्वा भविष्यस्य अनामकसदस्यानां सन्देशेभ्यः स्वस्य रक्षणं करोतु ।",
+ "anontalkpagetext": "----\n<em>एतत् सम्भाषणपृष्ठम् अनामकसदस्येभ्यः अस्ति । एतत् तेभ्यः अनामकसदस्येभ्यः रचितमस्ति, यैः सदस्यता न प्राप्ता अस्ति तथा च अस्य पृष्ठस्य उपयोगं न कुर्वन्तः सन्ति ।</em>\nतेषां व्यक्तिगतसूचनां प्राप्तुमेव वयं तस्य/तस्याः अन्तर्जालसंविदः उपयोगं कुर्मः । केचन सदस्याः स्वस्य अन्तर्जालसंविदम् अन्यान् सदस्यान् कथयन्ति । \nयद्यपि अनामकसदस्यः अहं नास्मि, तथापि अयोग्यसूचनाः मम पार्श्वे आगच्छन्त्यः सन्ति इति यदि भवान्/भवती शङ्कते, तर्हि एतत् [[Special:CreateAccount|create an account]] एतत् [[Special:UserLogin|log in]] वा कृत्वा भविष्यस्य अनामकसदस्यानां सन्देशेभ्यः स्वस्य रक्षणं करोतु ।",
"noarticletext": "अस्मिन् पृष्ठे अधुना किमपि न विद्यते । [[Special:Search/{{PAGENAME}}|एषः शब्दः]] येषु पृष्ठेषु अन्तर्भवति, तानि पृष्ठानि अन्वेष्टुं शक्यन्ते । \n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} सम्बद्धेषु पृष्ठेषु अन्वेषणं]\n[{{fullurl:{{FULLPAGENAME}}|action=edit}} अस्य पृष्ठस्य निर्माणं] वा शक्यम्</span>.",
"noarticletext-nopermission": "अस्मिन् पृष्ठे अधुना किमपि न विद्यते । [[Special:Search/{{PAGENAME}}|एषः शब्दः]] येषु पृष्ठेषु अन्तर्भवति, तानि पृष्ठानि अन्वेष्टुं शक्यन्ते । \n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} सम्बद्धेषु पृष्ठेषु अन्वेषणं]\n[{{fullurl:{{FULLPAGENAME}}|action=edit}} अस्य पृष्ठस्य सम्पादनं] वा शक्यम्</span>.",
"missing-revision": "\"{{FULLPAGENAME}}\" पृष्ठस्य संस्करणं #$1 नोपलभ्यम् ।\nयस्य पृष्ठस्य इतिहासे परिसन्धयः कालातीताः सन्ति, तेषु पृष्ठेषु एवं भवति ।\nअधिकसूचनाः अत्र प्राप्तुं शक्यते [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} अपाकृतानाम् आवलिः].",
"noname": "Эн тиһилик билэр аатын киллэрбэтэххин.",
"loginsuccesstitle": "Киирдиҥ",
"loginsuccess": "'''Билигин бу аатынан үлэлиигин: \"$1\".'''",
- "nosuchuser": "Маннык - \"$1\" - ааттаах кыттааччы суох.\nУлахан кыра буукубалар атыннаахтар.\nАатыҥ сөпкө суруллубутун көр эбэтэр [[Special:UserLogin/signup|саҥаттан бэлиэтэн]].",
+ "nosuchuser": "Маннык - \"$1\" - ааттаах кыттааччы суох.\nУлахан кыра буукубалар атыннаахтар.\nАатыҥ сөпкө суруллубутун көр эбэтэр [[Special:CreateAccount|саҥаттан бэлиэтэн]].",
"nosuchusershort": "Маннык - \"$1\" - ааттаах кыттааччы суох. Аатыҥ сөпкө суруллубутун көр.",
"nouserspecified": "Кыттааччы аатын киллэриэхтээххин.",
"login-userblocked": "Бу кыттааччы бобуллубут. Тиһиккэ киирии көҥүллэммэт.",
"accmailtext": "[[User talk:$1|$1]] кыттааччыга түбэспиччэ бэлиэлэртэн оҥоһуллубут киирии тыл бу аадырыска $2 ыытылынна.\nТиһиккэ бэлиэтэнэн баран киирии тылгын ''[[Special:ChangePassword|уларытыаххын]]'' сөп.",
"newarticle": "(Саҥа ыстатыйа)",
"newarticletext": "Эн суох сирэйгэ киирэ сатаатыҥ.\nМаннык ааттаах саҥа ыстатыйаны оҥорор буоллаххына, аллара баар түннүккэ суруй\n(сиһ. [$1 көмөнү] көрүөххүн сөп).\nӨскө манна сыыһа киирбит буоллаххына интэриниэтиҥ бырагыраамматын \"төнүн\" диэххин сөп.",
- "anontalkpagetext": "----''Бу аатын эппэтэх кыттааччы ырытар сирэйэ.\nIP-аадырыһа эрэ көстөр.\nБиир IP-аадырыс хас да киһиэхэ бэриллиэн сөп. Өскө атын киһиэхэ суруллубут суругу алҕас туппут буоллаххына, бэйэҥ [[Special:UserLogin/signup|ааккын билиһиннэр]] эбэтэр [[Special:UserLogin|киир]], оччоҕо кэлин да булкуур тахсыа суоҕа.''",
- "noarticletext": "Ð\91илигин бÑ\83 Ñ\81иÑ\80Ñ\8dй кÑ\83Ñ\80аанаÑ\85.\nÐ\91Ñ\83 ааÑ\82 аÑ\82Ñ\8bн Ñ\8bÑ\81Ñ\82аÑ\82Ñ\8bйалга Ñ\82Ñ\83Ñ\82Ñ\82Ñ\83ллаÑ\80Ñ\8bн [[Special:Search/{{PAGENAME}}|бÑ\83лÑ\83оÑ\85Ñ\85Ñ\83н Ñ\81өп]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Ñ\81Ñ\83Ñ\80Ñ\83нааллаÑ\80га көÑ\80дүөÑ\85Ñ\85үн Ñ\81өп],\nÑ\8dбÑ\8dÑ\82Ñ\8dÑ\80 [{{fullurl:{{FULLPAGENAME}}|action=edit}} маннÑ\8bк ааÑ\82Ñ\82ааÑ\85 Ñ\81аҥа Ñ\8bÑ\81Ñ\82аÑ\82Ñ\8bйанÑ\8b Ñ\81Ñ\83Ñ\80Ñ\83йÑ\83оÑ\85Ñ\85Ñ\83н] Ñ\81өп</span>.",
+ "anontalkpagetext": "----''Бу аатын эппэтэх кыттааччы ырытар сирэйэ.\nIP-аадырыһа эрэ көстөр.\nБиир IP-аадырыс хас да киһиэхэ бэриллиэн сөп. Өскө атын киһиэхэ суруллубут суругу алҕас туппут буоллаххына, бэйэҥ [[Special:CreateAccount|ааккын билиһиннэр]] эбэтэр [[Special:UserLogin|киир]], оччоҕо кэлин да булкуур тахсыа суоҕа.''",
+ "noarticletext": "Ð\91илигин бÑ\83 Ñ\81иÑ\80Ñ\8dй кÑ\83Ñ\80аанаÑ\85.\nÐ\91Ñ\83 ааÑ\82 аÑ\82Ñ\8bн Ñ\8bÑ\81Ñ\82аÑ\82Ñ\8bйалаÑ\80га Ñ\82Ñ\83Ñ\82Ñ\82Ñ\83ллаÑ\80Ñ\8bн [[Special:Search/{{PAGENAME}}|бÑ\83лÑ\83оÑ\85Ñ\85Ñ\83н Ñ\81өп]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Ñ\81Ñ\83Ñ\80Ñ\83нааллаÑ\80га көÑ\80дүөÑ\85Ñ\85үн Ñ\81өп],\nÑ\8dбÑ\8dÑ\82Ñ\8dÑ\80 [{{fullurl:{{FULLPAGENAME}}|action=edit}} маннÑ\8bк ааÑ\82Ñ\82ааÑ\85 Ñ\81аҥа Ñ\8bÑ\81Ñ\82аÑ\82Ñ\8bйанÑ\8b Ñ\81Ñ\83Ñ\80Ñ\83йÑ\83оÑ\85Ñ\85Ñ\83н Ñ\81өп]</span>.",
"noarticletext-nopermission": "Билигин бу сирэй кураанах.\nБу [[Special:Search/{{PAGENAME}}|ааты атын сирэйдэргэ көрдөөн көрүөххүн]] сөп,\nэбэтэр <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} сурунаалларга манна сыһыаннаах суруктары булуоххун сөп].</span> Бу сирэйи айар кыаҕыҥ суох.",
"missing-revision": "«{{FULLPAGENAME}}» сирэй $1 барыла суох.\n\nМаннык үксүн хайыы-үйэ сотуллубут билэҕэ эргэрбит сигэнэн бардахха буолааччы.\nСиһилии баҕар [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} сотуу сурунаалыгар] баара буолуо.",
"userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" аат бэлиэтэммэтэх. Бу сирэйи оҥорор/уларытар баҕалааххын дуо?",
"upload-form-label-own-work": "Бу бэйэм оҥоруум",
"upload-form-label-infoform-categories": "Категорията",
"upload-form-label-infoform-date": "Күнэ-дьыла",
- "upload-form-label-own-work-message-local": "{{SITENAME}} быраабылатын уонна лиссиэнсийэлиир бэлиитикэтин тутуһан бу билэни киллэрэрбин бигэргэтэбин.",
- "upload-form-label-not-own-work-message-local": "Бу билэҕин {{SITENAME}} быраабылатынан угар кыаҕыҥ суох буоллаҕына, маны сап уонна атын ньыманан туһанан көр.",
- "upload-form-label-not-own-work-local-local": "Баҕар [[Special:Upload|киллэрии сүрүн ньыматын]] туһаныаххын баҕарыаҥ.",
- "upload-form-label-own-work-message-default": "Уопсай репозиторийга угарбын өйдөөн туран угабын. Туһаныы сиэрин уонна лиссиэнсийэлиир бэлиитикэни кытта сөп түбэһэрин мэктиэлиибин.",
- "upload-form-label-not-own-work-message-default": "Бу билэҕин уопсай репозиторий быраабылатынан угар кыаҕыҥ суох буоллаҕына, маны сап уонна атын ньыманы туһанан көр.",
- "upload-form-label-not-own-work-local-default": "Өскө, {{SITENAME}} быраабылатынан угар сатанар буоллаҕына, кини [[Special:Upload|киллэрии тэрилин]] туһаныаххын сөп.",
- "upload-form-label-own-work-message-shared": "Бу билэни бас билэрбин уонна Биики Ыскылаакка төнүннэрбэттии [https://creativecommons.org/licenses/by-sa/4.0/deed.ru Creative Commons Attribution-ShareAlike 4.0] лиссиэнсийэннэн угары бигэргэтэбин. Ону тэҥэ [https://wikimediafoundation.org/wiki/Условия_использования Туһаныы усулуобуйатын кытта] сөбүлэһэбин.",
- "upload-form-label-not-own-work-message-shared": "Өскөтө билэни бас билбэт буоллаххына, биитэр атын лиссиэнсийэннэн угуоххун баҕарар буоллаххына, манна баар ньыманы туһаныаххын сөп: [https://commons.wikimedia.org/wiki/Special:UploadWizard Биики Ыскылаакка угуу маастара].",
- "upload-form-label-not-own-work-local-shared": "Өскө, {{SITENAME}} быраабылатынан угар сатанар буоллаҕына, кини [[Special:Upload|киллэрии тэрилин]] туһаныаххын эмиэ сөп.",
+ "upload-form-label-own-work-message-generic-local": "{{SITENAME}} быраабылатын уонна лиссиэнсийэлиир бэлиитикэтин тутуһан бу билэни киллэрэрбин бигэргэтэбин.",
+ "upload-form-label-not-own-work-message-generic-local": "Бу билэҕин {{SITENAME}} быраабылатынан угар кыаҕыҥ суох буоллаҕына, маны сап уонна атын ньыманан туһанан көр.",
+ "upload-form-label-not-own-work-local-generic-local": "Баҕар [[Special:Upload|киллэрии сүрүн ньыматын]] туһаныаххын баҕарыаҥ.",
+ "upload-form-label-own-work-message-generic-foreign": "Уопсай репозиторийга угарбын өйдөөн туран угабын. Туһаныы сиэрин уонна лиссиэнсийэлиир бэлиитикэни кытта сөп түбэһэрин мэктиэлиибин.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Бу билэҕин уопсай репозиторий быраабылатынан угар кыаҕыҥ суох буоллаҕына, маны сап уонна атын ньыманы туһанан көр.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Өскө, {{SITENAME}} быраабылатынан угар сатанар буоллаҕына, кини [[Special:Upload|киллэрии тэрилин]] туһаныаххын сөп.",
"backend-fail-stream": "$1 билэни ыытар табыллыбата.",
"backend-fail-backup": "Бу билэ $1 резервнэй куопуйатын оҥорор табыллыбата.",
"backend-fail-notexists": "Маннык $1 билэ суох эбит.",
"whatlinkshere-links": "← ыйынньыктар",
"whatlinkshere-hideredirs": "$1 утаарыы",
"whatlinkshere-hidetrans": "$1 киллэриилэр",
- "whatlinkshere-hidelinks": "$1 сигэ (ыйынньык)",
+ "whatlinkshere-hidelinks": "$1 сигэ",
"whatlinkshere-hideimages": "$1 билэ сигэтэ",
"whatlinkshere-filters": "Фильтрдар",
"whatlinkshere-submit": "Толор",
"noname": "Su nùmene impitadore insertadu no est vàlidu.",
"loginsuccesstitle": "Ti ses identificadu",
"loginsuccess": "'''Immoe ses intradu in {{SITENAME}} cun su nùmene impitadore \"$1\".'''",
- "nosuchuser": "Non b'at impitadore cun su nùmene \"$1\".\nIs nùmenes impitadore sunt sensìbiles a is lìteras mannas.\nVerìfica su nùmene insertadu o [[Special:UserLogin/signup|crea unu contu nou]].",
+ "nosuchuser": "Non b'at impitadore cun su nùmene \"$1\".\nIs nùmenes impitadore sunt sensìbiles a is lìteras mannas.\nVerìfica su nùmene insertadu o [[Special:CreateAccount|crea unu contu nou]].",
"nosuchusershort": "Non b'est perunu impitadore chi tenet \"$1\" comente nùmene.\nCòmpida su nùmene insertadu.",
"nouserspecified": "Depes ispetzificare unu nùmene impitadore.",
"login-userblocked": "{{GENDER:$1|Custu impitadore est arreadu|Custa impidadora est arreada}}. Atzessu no adduidu.",
"accmailtext": "Una password ingendrada a manera casuale pro [[User talk:$1|$1]] est istada imbiada a $2. Podet èssere cambiada in sa pàgina de <em>[[Special:ChangePassword|càmbiu password]]</em> a pustis de èssere intradu in su contu tuo.",
"newarticle": "(Nou)",
"newarticletext": "Custa pàgina no esistit galu.\nPro creare sa pàgina, iscrie in sa casella a suta (càstia sa [$1 pàgina de agiudu] pro àteras informatziones).\nSi ses intradu inoghe pro isbàlliu, carca su butone <strong>back/indietro</strong> in su navigadore tuo.",
- "anontalkpagetext": "----\n<em>Custa est sa pàgina de cuntierra de unu impitadore anònimu ki no at creadu unu contu galu, o ki non dd'usat.</em>\nPro custu impreamus su nùmeru de indiritzos IP pro ddu identificare. Is indiritzos IP podent perou èsser cundivìdidos dae unos cantos impitadores. Si ses unu impitadore anònimu e ritenes ki custos cummentos non sunt diretos a tue, pro praxere [[Special:UserLogin/signup|crea unu contu]] o [[Special:UserLogin|identifica·ti (log in)]] pro evitare cunfusione cun àteros impitadore anònimos.''",
+ "anontalkpagetext": "----\n<em>Custa est sa pàgina de cuntierra de unu impitadore anònimu ki no at creadu unu contu galu, o ki non dd'usat.</em>\nPro custu impreamus su nùmeru de indiritzos IP pro ddu identificare. Is indiritzos IP podent perou èsser cundivìdidos dae unos cantos impitadores. Si ses unu impitadore anònimu e ritenes ki custos cummentos non sunt diretos a tue, pro praxere [[Special:CreateAccount|crea unu contu]] o [[Special:UserLogin|identifica·ti (log in)]] pro evitare cunfusione cun àteros impitadore anònimos.''",
"noarticletext": "In custu momentu sa pàgina est bùida.\nPodes [[Special:Search/{{PAGENAME}}|chircare custu tìtulu]] in àteras pàginas, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} chircare in is registros ligados] o puru [{{fullurl:{{FULLPAGENAME}}|action=edit}} modificare sa pàgina]</span>.",
"noarticletext-nopermission": "In custu tempu sa pàgina rechesta est bùida.\nPodes [[Special:Search/{{PAGENAME}}|chircare custu tìtulu]] in is àteras pàginas, o <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} chircare in is regìstros ligados]</span>, ma non tenes su permissu de creare custa pàgina.",
"userpage-userdoesnotexist": "Su contu de s'impitadore \"<nowiki>$1</nowiki>\" no est stadu registradu.\nPro praxere abbàida si boles a sèriu creare/cambiare custa pàgina.",
"noname": "Nun spicificasti nu nomu utenti vàlidu.",
"loginsuccesstitle": "Trasuta rinisciuta",
"loginsuccess": "<strong>Ora trasisti nta {{SITENAME}} comu \"$1\".</strong>",
- "nosuchuser": "Nun è riggistratu nuddu utenti di nomu \"$1\".\nLi nomi di l'utenti fannu diffirenza tra maiùsculi e minùsculi.\nCuntrolla chi scrivisti lu nomu bonu, o puru [[Special:UserLogin/signup|crea un cuntu novu]].",
+ "nosuchuser": "Nun è riggistratu nuddu utenti di nomu \"$1\".\nLi nomi di l'utenti fannu diffirenza tra maiùsculi e minùsculi.\nCuntrolla chi scrivisti lu nomu bonu, o puru [[Special:CreateAccount|crea un cuntu novu]].",
"nosuchusershort": "Nun è riggistratu nuddu utenti di nomu \"$1\".\nCuntrolla chi scrivisti lu nomu bonu.",
"nouserspecified": "Hai a spicificari un nomu utenti.",
"login-userblocked": "St'utenti è bluccatu. Nun è pussìbbili di tràsiri.",
"accmailtext": "Na password ginirata casualmenti pi [[User talk:$1|$1]] fu spiduta a $2. Si pò canciari dâ pàggina di <em>[[Special:ChangePassword|canciamentu dâ password]]</em> comu unu trasi.",
"newarticle": "(Novu)",
"newarticletext": "Siguisti na lijami a na pàggina c'ancora nun esisti.\nPi criari sta pàggina, accumenza a scrìviri ccassutta (talìa la [$1 pàggina d'aiutu] p'aviri maiuri nfurmazzioni).\nSi agghicasti ccà pi sbagghiu, carca lu buttuni <strong>n arreri</strong> dû tò browser.",
- "anontalkpagetext": "----''Chista è la pàggina di discussioni di n’utenti anònimu, ca nun criau ancora n’accessu o ca nun l’usa.\nP’idintificàrilu è pirciò nicissariu usari lu nùmmiru di lu sò nnirizzu IP.\nLi nnirizzi IP ponnu pirò èssiri spartuti di cchiù utenti.\nSiddu sî n’utenti anònimu e riteni ca li cummenti prisenti nta sta pàggina nun si rifirìscinu a tia, [[Special:UserLogin/signup|crea n’accessu novu]] o [[Special:UserLogin|trasi]] cu chiddu ca già hai p’evitari d’èssiri cunfusu cu àutri utenti anònimi ‘n futuru.''",
+ "anontalkpagetext": "----''Chista è la pàggina di discussioni di n’utenti anònimu, ca nun criau ancora n’accessu o ca nun l’usa.\nP’idintificàrilu è pirciò nicissariu usari lu nùmmiru di lu sò nnirizzu IP.\nLi nnirizzi IP ponnu pirò èssiri spartuti di cchiù utenti.\nSiddu sî n’utenti anònimu e riteni ca li cummenti prisenti nta sta pàggina nun si rifirìscinu a tia, [[Special:CreateAccount|crea n’accessu novu]] o [[Special:UserLogin|trasi]] cu chiddu ca già hai p’evitari d’èssiri cunfusu cu àutri utenti anònimi ‘n futuru.''",
"noarticletext": "Nta stu mumentu la pàggina addumannata è vacanti. È pussìbbili [[Special:Search/{{PAGENAME}}|circari stu tìtulu]] nta l'àutri pàggini dû situ oppuru <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|action=edit}} circari ntê riggistri culligati] oppuru [{{fullurl:{{FULLPAGENAME}}|action=edit}} canciari la pàggina ora]</span>.",
"noarticletext-nopermission": "Nta stu mumentu la pàggina addumannata è vacanti. È pussìbbili [[Special:Search/{{PAGENAME}}|circari stu tìtulu]] nti àutri pàggini dû situ o <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} circari ntê riggistri culligati]</span>, ma nun hai li pirmissi pi criari sta pàggina.",
"missing-revision": "La virsioni #$1 dâ paggina ntitulata \"{{FULLPAGENAME}}\" nun esisti.\n\nStu fattu di sòlitu succedi quannu si segui nu lijami di crunuluggìa versu na pàggina chi fu cancillata.\nSi ponnu vìdiri li dittagghî ntô [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} riggistru dî cancillazzioni].",
"noname": "Ye'v na speceefie'd ae valid uisername.",
"loginsuccesstitle": "Login fine",
"loginsuccess": "<strong>Ye're nou loggit in tae {{SITENAME}} aes \"$1\".</strong>",
- "nosuchuser": "Thaur's nae sic uiser aes \"$1\".\nUiser names ar case-sensiteeve.\nCheck yer speelin, or [[Special:UserLogin/signup|mak ae new accoont]].",
+ "nosuchuser": "Thaur's nae sic uiser aes \"$1\".\nUiser names ar case-sensiteeve.\nCheck yer speelin, or [[Special:CreateAccount|mak ae new accoont]].",
"nosuchusershort": "Thaur's nae sic uiser aes \"$1\". Check yer spellin.",
"nouserspecified": "Ye hae tae merk up ae uisername.",
"login-userblocked": "Uiser \"$1\" is blockit. Log-in naw permitit.",
"accmailtext": "Ae randomly generated passwaird fer [[User talk:$1|$1]] haes been sent til $2. It can be chynged oan the <em>[[Special:ChangePassword|chynge passwaird]]</em> page upo loggin in.",
"newarticle": "(New)",
"newarticletext": "Ye'v follaed aen airtin til ae page that disna exeest yet. Tae cræft the page, stairt typin in the kist ablo (see the [$1 heelp page] fer mair info). Gif ye'r here bi mistak, jist clap yer brouser's <strong>back</strong> button.",
- "anontalkpagetext": "----\n<em>This is the discussion page fer aen anonymoos uiser that's naw cræftit aen accoont yet, or that disna uise it.</em>\nWe maun therefore uise the numerical IP address tae identifie him/her.\nSic aen IP address can be shaired bi several uisers.\nGif ye'r aen anonymos uiser n feel that onreelavant comments hae been directed at ye, please [[Special:UserLogin/signup|cræft aen accoont]] or [[Special:UserLogin|log in]] tae avoid futur confusion wi ither anonymoos uisers.",
+ "anontalkpagetext": "----\n<em>This is the discussion page fer aen anonymoos uiser that's naw cræftit aen accoont yet, or that disna uise it.</em>\nWe maun therefore uise the numerical IP address tae identifie him/her.\nSic aen IP address can be shaired bi several uisers.\nGif ye'r aen anonymos uiser n feel that onreelavant comments hae been directed at ye, please [[Special:CreateAccount|cræft aen accoont]] or [[Special:UserLogin|log in]] tae avoid futur confusion wi ither anonymoos uisers.",
"noarticletext": "Thaur's naw tex oan this page the nou. \nYe can [[Special:Search/{{PAGENAME}}|rake fer this page teitle]] in ither pages,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rake the related logs],\nor [{{fullurl:{{FULLPAGENAME}}|action=edit}} eedit this page].</span>",
"noarticletext-nopermission": "Thaur's nae tex in this page the nou.\nYe can [[Special:Search/{{PAGENAME}}|rake fer this page title]] in ither pages, or <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rake the relatit logs]</span>, but ye dinna hae permeession tae cræft this page.",
"missing-revision": "The reveesion #$1 o the page named \"{{FULLPAGENAME}}\" disna exeest.\n\nThis is uissuallie caused bi follaein aen ootdated histerie airtin til ae page that haes been delytit.\nDetails can be foond in the [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} delytion log].",
"noname": "توهان جو ڄاڻايل يُوزرنانءُ ناقابل ڪار آهي.",
"loginsuccesstitle": "لاگ اِن ڪامياب",
"loginsuccess": "'''هاڻي توهان {{SITENAME}} تي بطور \"$1\" لاگ اِن ٿيل آهيو.'''",
- "nosuchuser": "\"$1\" نالي سان ڪو بہ يوزر نہ آهي. \"$1\".\n ننڍن وڏن اکرن ۾ امتياز ڪرڻ لازمي آهي. \nهِجي چڪاسيو،يا [[Special:UserLogin/signup|نئون کاتو تخليق ڪريو]]",
+ "nosuchuser": "\"$1\" نالي سان ڪو بہ يوزر نہ آهي. \"$1\".\n ننڍن وڏن اکرن ۾ امتياز ڪرڻ لازمي آهي. \nهِجي چڪاسيو،يا [[Special:CreateAccount|نئون کاتو تخليق ڪريو]]",
"nosuchusershort": "\"$1\" نالي ڪو بہ يُوزر ناهي.\nهِجي جي پڪ ڪندا.",
"nouserspecified": "توهان کي ڪو يوزرنانءُ ڄاڻائڻو پوندو.",
"login-userblocked": "هيءُ يُوزر بندشيل آهي. لاگ اِن جي اجازت نہ ٿي ڏجي.",
"tog-hideminor": "Fasal kayney kaŋ hun barmayyaŋ korawey ra tugu",
"tog-hidepatrolled": "Fasalyan kurantey tugu barmay korawey ra",
"tog-newpageshidepatrolled": "Moo kurantey tugu moo taaga maašeedaa ra",
+ "tog-hidecategorization": "Moɲey kanandiyanoo tugu",
"tog-extendwatchlist": "Hawgay maašeedaa hayandi ka barmawey kul cebe, manti ikokorantaa hinne",
"tog-usenewrc": "Barmawey marga moo bande barmay korawey nda hawgayhayey ra",
"tog-numberheadings": "Boŋdekerey boŋkabuyan",
"tog-watchdefault": "Moɲey nda tukey kaŋ ay g'i fasal tonton ay hawgayhayey ga",
"tog-watchmoves": "Moɲey nda tukey kaŋ ay g'i ganandi tonton ay hawgayhayey ga",
"tog-watchdeletion": "Moɲey nda tukey kaŋ ay g'i tuusu tonton ay hawgayhayey ga",
+ "tog-watchuploads": "Tuku taagey kaŋ g'i zijandi tonton hawgayhayey ga",
"tog-watchrollback": "Moɲey kaŋ ay n'i taagandi tonton ay hawgayhayey ga",
"tog-minordefault": "Fasalyaney kul šilbay sanda ikaynayaŋ nda tilasu",
"tog-previewontop": "Moofuryan cebe jina fasal bataa ra",
"tog-shownumberswatching": "Goykey kaŋ ga moɲoo hawgay hinnaa cebe",
"tog-oldsig": "Kanbežeeri barantaa:",
"tog-fancysig": "Kanbežeero tee sanda wikihantum (bila nda nga boŋdobu)",
- "tog-uselivepreview": "Moofuryan goywaati ra (šiiyan)",
- "tog-forceeditsummary": "Ay šaawar nda ya na fasal durandiyan dam",
+ "tog-uselivepreview": "Cebe kaŋ a ga dira",
+ "tog-forceeditsummary": "Ay šaawar nda fasal durandiyan koonu ga huru",
"tog-watchlisthideown": "Ay boŋ fasalyaney tugu hawgayhayey ra",
"tog-watchlisthidebots": "Maršin fasalyaney tugu hawgayhayey ra",
"tog-watchlisthideminor": "Fasalyan kayney tugu hawgayhayey ra",
"noname": "War mana goykaw maa henna kayandi.",
"loginsuccesstitle": "Huryanoo boori",
"loginsuccess": "<strong>War huru {{SITENAME}} ra sohõ sanda \"$1\".</strong>",
- "nosuchuser": "Goykaw kul šii kaŋ ti \"$1\". \nGoykawmaaɲey ga kula nda harfu azzaati.\nWar hantumoo koroši, wala [[Special:UserLogin/signup|kontu taaga tee]].",
+ "nosuchuser": "Goykaw kul šii kaŋ ti \"$1\". \nGoykawmaaɲey ga kula nda harfu azzaati.\nWar hantumoo koroši, wala [[Special:CreateAccount|kontu taaga tee]].",
"nosuchusershort": "Goykaw kul šii kaŋ ti \"$1\".\nHantum-tenjiyan koroši.",
"nouserspecified": "War ga hima ka goykawmaa kayandi.",
"login-userblocked": "Goykaw gagayandi. Huruyan šii nda fondo.",
"accmailtext": "Ɲaami-ra šennikufal kaŋ tee [[User talk:$1|$1]] sanbandi $2 do. A ga hin ka barmay <em>[[Special:ChangePassword|šennikufal barmay]] moɲoo ga </em> nda war ga huru.",
"newarticle": "(Itaaga)",
"newarticletext": "War hanga dobu kaŋ ka fatta moo foo kaŋ ši bara jina ga.\nKa moɲoo tee, soobay ka hantum ganda bataa ra ([$1 faaba moɲoo] guna ka bay ka tonton.\nNda war n' ka dere ka kaa ne, war ceecikaa <strong>banda</strong>butoŋoo naagu.",
- "anontalkpagetext": "----\n<em>Kakaw moɲoo woo goo goykaw kaŋ maaɲoo ši bangay se, boro kaɲ mana kontu tee jina, wal'a ši a ka goy.</em>\nAdiši kal'ir ma goy nda hinna IP aderesu ka boraa alhaaloo tabatandi.\nIP aderesu dumoo woo ga hin ka žemnandi goykaw booboyaŋ game.\nNda war ti goykaw kaŋ maaɲoo ši bangay nda war ga tammahã kaŋ war ši kula nda šenney wey, [[Special:UserLogin/signup|kontu tee]] wala [[Special:UserLogin|huru]] ka ganji hiino war nda goykaw taney kaŋ šii nda maa ma birji cere ra. \\",
+ "anontalkpagetext": "----\n<em>Kakaw moɲoo woo goo goykaw kaŋ maaɲoo ši bangay se, boro kaɲ mana kontu tee jina, wal'a ši a ka goy.</em>\nAdiši kal'ir ma goy nda hinna IP aderesu ka boraa alhaaloo tabatandi.\nIP aderesu dumoo woo ga hin ka žemnandi goykaw booboyaŋ game.\nNda war ti goykaw kaŋ maaɲoo ši bangay nda war ga tammahã kaŋ war ši kula nda šenney wey, [[Special:CreateAccount|kontu tee]] wala [[Special:UserLogin|huru]] ka ganji hiino war nda goykaw taney kaŋ šii nda maa ma birji cere ra. \\",
"noarticletext": "Hantum kul šii moɲoo woo ga sohõda.\nWar ga hin ka [Special:Search/{{PAGENAME}}|moɲoo woo maaɲoo ceeci]] moɲe jerey ra,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|moo={{FULLPAGENAMEE}}}} hantum himantey guna],\nwala [{{fullurl:{{FULLPAGENAME}}|teera=fasal}} moɲoo woo fasal]</span>.",
"noarticletext-nopermission": "Hantum kul šii moɲoo woo ra sohõda.\nWar ga hin ka [[Special:Search/{{PAGENAME}}|moɲoo woo maaɲoo ceeci]] moɲey jerey ra wala <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|moo={{FULLPAGENAMEE}}}} cceci hantum himantey ra]</span>, amma war ši nda fondo ka moɲoo woo tee.",
"missing-revision": "Filla #$1 moɲoo kaŋ maaɲoo ti \"{{FULLPAGENAME}}\" se ši bara.\n\nWoo ga doona ka tee nda boro hanga taariki dobu žeena banda kaŋ ga fatta moo tuusante ga.\nŠilbaywey ga hin ka duwandi [{{fullurl:{{#Special:Log}}/tuusu|moo={{FULLPAGENAMEE}}}} tuusuyan taariki] ra.",
"exception-nologin": "Nesat prėsėjongis",
"exception-nologin-text": "Ka galietomiet ton padėrbtė, Tamstā būtėnā rēk prėsėjongtė.",
"exception-nologin-text-manual": "Ka galietomiet ton padėrbtė, Tamstā būtėnā rēk $1.",
- "logouttext": "'''Daba Tamsta esat atsėjongė̄s.'''\n\nGalat ė tuoliau nauduotė {{SITENAME}} anuonėmėškā aba <span class='plainlinks'>[$1 prėsėjonkat]</span> ėš naujė tuo patio aba kėto nauduotuojė vardo.\nAtėduos: katrūs nakatrūs poslapiūs ė tuoliau gal ruodītė būktā būtomiet prėsėjongis lėgė tuol, kumet ėšvalīsat sava naršīklės dietovė (''cache'').",
+ "logouttext": "<strong>Daba Tamsta esat atsėjongė̄s.</strong>\n\nAtėduos: katrūs nakatrūs poslapiūs ė tuoliau gal ruodītė būktā būtomėt prėsėjongė̄s lėg tuol, kūmet ėšvalīsėt sava naršīklės dietovė (''cache'').",
"cannotlogoutnow-title": "Nēn atsijongtė",
"welcomeuser": "Svēks, $1!",
"welcomecreation-msg": "Tamstas paskīra jau padėrbta.\nNūnā galat pakeistė sava {{SITENAME}} [[Special:Preferences|nustatīmus]], jēgo tėktās nuorat.",
"createaccounterror": "Nė̄šiejė padėrbtė paskīruos: $1",
"nocookiesnew": "Nauduotuojė paskīra bova sokurta, bat Tamsta nēsot prėsėjongis. {{SITENAME}} nauduo pakavukus (''cookies''), ka prėkergtom nauduotuojus. Tamsta esot ėšjongis anūs. Prašuom ijongtė pakavukus, tumet prisėjonkat so sava naujo nauduotuojė vardo ė slaptažuodio.",
"nocookieslogin": "{{SITENAME}} nauduo pakavukus (''cookies''), ka prėkergtom nauduotuojus. Tamsta esat ėšjongis anūs. Prašuom ijongtė pakavukus ė pamiegītė apent.",
- "loginsuccesstitle": "Gerā prėsėjongiet",
+ "loginsuccesstitle": "Prisijongiet gerā",
"loginsuccess": "'''Dabā Tamsta esat prėsėjongis prī {{SITENAME}} kāp „$1“.'''",
- "nosuchuser": "Nier anėjuokė nauduotuojė pavadėnta „$1“.\nPatikrinkat rašība, aba [[Special:UserLogin/signup|padėrbkat naujė paskīra]].",
+ "nosuchuser": "Nier anėjuokė nauduotuojė, katrou vards būtom „$1“ (dėdliuosės rādės svarbo ī).\nPatikrinkėt rašība aba [[Special:CreateAccount|padėrbkėt naujė paskīra]].",
"nosuchusershort": "Nier juokė nauduotuojė, pavadėnta „$1“. Patėkrinkat rašība.",
"nouserspecified": "Tamstā rēk nuruodītė nauduotuojė varda.",
"login-userblocked": "Nauduotuos ožgints īr. Pakliūtė nie galama.",
"wrongpasswordempty": "Slaptažuodis dīks īr. Pamiegīkat apent.",
"passwordtooshort": "Tamstas slaptažuodis nier tinkoms aba par tromps īr. Ons tor būtė nuors {{PLURAL:$1|1 sėmbuolė|$1 sėmbuoliu}} ėlgoma.",
"passwordtoolong": "Slaptažuodis negal būtė ėlgesnis kāp {{PLURAL:$1|1 znuoks|$1 znuokā|$1 znuoku}}.",
+ "passwordtoopopular": "Tonkē nauduojami slaptažuodē natink. Somīslėkėt kuoki tās godresni slaptažuodi.",
"password-name-match": "Tamstas slaptažuodis tor skirtėis nu Tamstas nauduotuojė varda.",
"password-login-forbidden": "Tuo nauduotuojė varda ė slaptažuodė nauduojėms nie galėms.",
"mailmypassword": "Atgamintė slaptažuodi",
"noemail": "Nier anėjuokė el. pašta adresa ivesta nauduotuojō „$1“.",
"noemailcreate": "Tamsta nuruodīkat elektruonėni pašta, katros vēk",
"passwordsent": "Naus slaptažuodis bova nusiōsts i el. pašta adresa,\nožregėstrouta nauduotuojė „$1“.\nPrašuom prisėjongtė vielē, kumet Tamsta gausėt anū.",
- "blocked-mailpassword": "Tamstas IP adresos īr ožblokouts nū redagavėma, tudie neleidama nauduotė slaptažuodė priminėma funkcėjės, kū apsėsauguotomė nū pėktnaudžēvėma.",
+ "blocked-mailpassword": "Tamstas IP adresos ožgints ī, ka negalietomiet nieka čė dirbtė. Ka būtom apsisauguota nūg pėktnaudiavėma, slaptažuodė atgamėnėms ėšjongts ī.",
"eauthentsent": "Patvėrtėnėma gruomata bova nusiōsta i paskėrta el. pašta adresa.\nPrīš ėšsiontiant kėta gruomata i Tamstas diežote, Tamsta torėt vīkdītė nuruodīmus gruomatuo, kū patvėrtėntomiet, kū diežotė tėkrā īr Tamstas.",
"throttled-mailpassword": "Slaptažuodžė priminims jau bova ėšsiōsts, par paskotėnės {{PLURAL:$1|adīna|$1 adīnas}}. Nuorint apsėsauguotė nū pėktnaudēvėma, slaptažuodė priminėms gal būt ėšsiōsts tėk kas {{PLURAL:$1|adīna|$1 adīnas}}.",
"mailerror": "Bieda siontiont gromata: $1",
"emailnotauthenticated": "Tamstas el. pašta adresos da nier patvėrtėnts. Anėjuokės gruomatas\nnebus siontamas ni vėinam žemiau ėšvardėntam puoslaugiō.",
"noemailprefs": "Nuruodėkīt el. pašta adresa, kū vėiktu šėtos funkcėjės.",
"emailconfirmlink": "Patvėrtinkėt sava el. pašta adresa",
+ "invalidemailaddress": "Alektruonėnė pašta adresos nagal būtė prijėmts, ba ėšruod kap natinkamas skvarmas. Da sīk pamieginkėt ivestė tou adresa aba palikėt laukali dīka.",
"accountcreated": "Nauduotuos padėrbts īr",
"accountcreatedtext": "Paskīra nauduotojō [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|aptarėms]]) bova padėrbta.",
"createaccount-title": "{{SITENAME}} paskīruos kūrėms",
"createaccount-text": "Kažkastā svetainie {{SITENAME}} ($4) padėrba nauduotojė poslapi, katros vadėnas \"$2\" ė katruo slaptažuodis ī \"$3\", so Tamstas el. pašta adreso.\nDaba galat prėsėjongtė ė pasėkeistė slaptažuodi.\n\nJēgo tat ī kuokistā soklīdėms, tumet Jumis nieka darītė nerēk.",
"login-throttled": "Tamsta nuognē daug sīkiu miegėnat prėsėjongtė.\nPalaukat $1 prīš miegėnont apent.",
+ "login-abort-generic": "Tamstas prisijongėms napavīka. Ons bova atšaukts.",
"loginlanguagelabel": "Kalba: $1",
+ "createacct-another-realname-tip": "Viernos vards nie būtėns. \nJēb anou ožrašīsėt, tap ons būs ruodoms prī Tamstas darbū pamėnavuojėma.",
"pt-login": "Prėsėjongtė",
"pt-login-button": "Prėsėjongtė",
+ "pt-login-continue-button": "Tuoliau prisijongėnietė",
"pt-createaccount": "Pasėdėrbtė paskīra",
"pt-userlogout": "Atsėjongtė",
"changepassword": "Pakeistė slaptažuodė",
"newpassword": "Naus slaptažuodis:",
"retypenew": "Apent ožrašīkat naujė slaptažuodi:",
"resetpass_submit": "Nostatītė slaptažuodi ė prėsėjongtė",
- "changepassword-success": "Tamstas slaptažuodis pakeists siekmėngā!",
+ "changepassword-success": "Tamstas slaptažuodis pamainīts gerā!",
"changepassword-throttled": "Baisē daug čiesu mieginot prisėjongtė.\nDaba palaukėt $1 prīš mieginant vie.",
"resetpass-submit-loggedin": "Keistė slaptažuodi",
"resetpass-submit-cancel": "Pabengtė",
"resetpass-temp-password": "Laikėns slaptažuodis:",
+ "resetpass-expired": "Tamstas slaptažuodis bengė vēktė. Padirbkėt nauja slaptažuodi, ka prisijongtomiet.",
"passwordreset": "Apent padėrbtė slaptažuodi",
"passwordreset-username": "Nauduotuojė vards:",
"passwordreset-domain": "Domens:",
"passwordreset-email": "El. pašta adresos:",
+ "passwordreset-emailtext-ip": "Kažėkas (mosietās Tamsta, ėš IP adresa $1) ožprašė pamainītė slaptažuodi tinklapie {{SITENAME}} ($4). Tou nauduotuojė {{PLURAL:$3|poslapis|poslapio|poslapē|poslapiu}}\nsorištė so tou al. pašta adreso ī:\n\n$2\n\n{{PLURAL:$3|Tas čiesėškos slaptažuodis|čiesėški slaptažuodē}} bengs vēktė pu {{PLURAL:$5|dėinuos|$5 dėinū}}.\nTamsta prisijonkėt ė pamainīkėt sava slaptažuodi. Jēb kas tā kėts padirba tou prašīma, aba jēb atminiet sava sena slaptažuodi, ta galėt nakrēptė atėdies i tou gromata ė jongtėis so sava seno slaptažuodio.",
"passwordreset-emailelement": "Nauduotuos:\n$1\n\nČiesėšks slaptažuodis:\n$2",
"changeemail": "Keistė aba trintė el. pašta adresa",
"changeemail-oldemail": "Vielībs el. pašta adresosː",
"accmailtext": "Bikāp padėrbts slaptažuodis, katros prėgol prī [[User talk:$1|$1]] bova siōsts pošto $2. Kāp prėsėjongsat, galat <em>[[Special:ChangePassword|anon parkeistė]]</em>.",
"newarticle": "(Naus)",
"newarticletext": "Tamsta pakliovat poslapin, katros dā nie padėrbts.\nJēgo nuorat anon padėrbtė, rašīkat laukė, katros ī apatiuo\n(veiziekat [$1 pagelbas poslapi]).\nJēgo pakliovat čė netīčiuom, paprastiausē paspauskat naršīklės mīgtoka '''atgal'''.",
- "anontalkpagetext": "----''Tas īr anonimėnė nauduotuojė, katros nier sosėkūrės aba nenauduo paskīruos, aptarėmu poslapis.\nDielē tuo nauduojams IP adresos anuo atpažėnėmō.\nTas IP adresos gal būtė dalinams keletō nauduotuoju.\nJēgo Tamsta esat anonimėnis nauduotuos ėr veizėt, kū kuomentarā nier skėrtė Tamstā, [[Special:UserLogin/signup|sokorkėt paskīra]] aba [[Special:UserLogin|prisėjonkėt]], ė nebūsėt maišuoms so kėtās anonimėnēs nauduotuojās.''",
- "noarticletext": "Nūnā tamė poslapie nie nė juokė teksta.\nTamsta galat [[Special:Search/{{PAGENAME}}|ėiškuotė ton poslapė pavadėnėma]] terp kėtū poslapiū,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ėiškuotė prėgolontiu īrašu],\naba [{{fullurl:{{FULLPAGENAME}}|action=edit}} keistė ton poslapi]</span>.",
+ "anontalkpagetext": "----''Tas īr anonimėnė nauduotuojė, katros nier sosėkūrės aba nenauduo paskīruos, aptarėmu poslapis.\nDielē tuo nauduojams IP adresos anuo atpažėnėmō.\nTas IP adresos gal būtė dalinams keletō nauduotuoju.\nJēgo Tamsta esat anonimėnis nauduotuos ėr veizėt, kū kuomentarā nier skėrtė Tamstā, [[Special:CreateAccount|sokorkėt paskīra]] aba [[Special:UserLogin|prisėjonkėt]], ė nebūsėt maišuoms so kėtās anonimėnēs nauduotuojās.''",
+ "noarticletext": "Nūnā tamė poslapie nie nijuokė teksta.\nTamsta galat [[Special:Search/{{PAGENAME}}|ėiškuotė tou poslapė pavadėnėma]] terp kėtū poslapiu,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ėiškuotė prėgolontiu īrašu],\naba [{{fullurl:{{FULLPAGENAME}}|action=edit}} keistė tou poslapi]</span>.",
"noarticletext-nopermission": "Nūnā tamė poslapie nier anėjuokė teksta.\nTamsta galat [[Special:Search/{{PAGENAME}}|ėiškuotė šėtuo poslapė pavadėnėma]] kėtūs poslapiūs,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ėiškuotė prėgolontiūm ragėstru]</span>.",
"userpage-userdoesnotexist": "Nauduotuojė paskīra „<nowiki>$1</nowiki>“ nier ožregėstrouta. Prašuom patikrėntė, a Tamsta nuorėt kortė/keistė ta poslapi.",
"userpage-userdoesnotexist-view": "Nie nauduotuojė vardo „$1“",
"right-upload": "Ikeltė failus",
"right-writeapi": "Nauduotė API rašīmō",
"right-delete": "Trintė poslapius",
+ "right-browsearchive": "Ėiškuotė ėštrintū poslapiu",
+ "right-undelete": "Tou poslapi padėrbtė apent",
"newuserlogpage": "Nauduotuojė kūrėma sārošos",
"rightslog": "Nauduotuoju teisiu istuorėjė",
"rightslogtext": "Pateikiams nauduotuoju teisiu pakeitėmu sārašos.",
"pager-older-n": "{{PLURAL:$1|paskesnis|paskesnė|paskesniū}}",
"booksources": "Kningu šaltėnē",
"booksources-search-legend": "Kningu šaltėniu paėiška",
+ "booksources-search": "Ėiškuotė",
"specialloguserlabel": "Nauduotuos:",
"speciallogtitlelabel": "Pavadėnims:",
"log": "Specēliūju vīksmū istuorėjė",
"whatlinkshere-prev": "$1 {{PLURAL:$1|pėrmesnis|pėrmesnė|pėrmesniū}}",
"whatlinkshere-next": "$1 {{PLURAL:$1|kėts|kėtė|kėtū}}",
"whatlinkshere-links": "← nūruodas",
- "whatlinkshere-hideredirs": "$1 nusokėmus",
+ "whatlinkshere-hideredirs": "$1 nūsokėmus",
"whatlinkshere-hidetrans": "$1 itraukėmus",
"whatlinkshere-hidelinks": "$1 nūruodas",
"whatlinkshere-hideimages": "$1 abruozdieliu nūruodas",
"tooltip-t-recentchangeslinked": "Paskotėnē pakeitėmā straipsniūs, pasėikiamūs nug šėta straipsnė",
"tooltip-feed-rss": "Šėta poslapė RSS šaltėnis",
"tooltip-feed-atom": "Ton poslapė Atom šaltėnis",
- "tooltip-t-contributions": "Ruodītė tou nauduotuojė duovi",
+ "tooltip-t-contributions": "Ruodītė tou {{GENDER:$1|nauduotuojė}} duovi",
"tooltip-t-emailuser": "Siōstė gromata šėtom prietėliō",
"tooltip-t-upload": "Ožkrautė abruozdielius",
"tooltip-t-specialpages": "Specēliūju poslapiu sārašos",
"noname": "Niste izabrali ispravno korisničko ime.",
"loginsuccesstitle": "Prijavljivanje uspješno",
"loginsuccess": "Trenutno ste prijavljeni na {{SITENAME}} kao \"$1\".",
- "nosuchuser": "Ne postoji korisnik sa imenom \"$1\".\nKorisnička imena razlikuju velika i mala slova.\nProvjerite vaše kucanje ili [[Special:UserLogin/signup|napravite novi korisnički račun]].",
+ "nosuchuser": "Ne postoji korisnik sa imenom \"$1\".\nKorisnička imena razlikuju velika i mala slova.\nProvjerite vaše kucanje ili [[Special:CreateAccount|napravite novi korisnički račun]].",
"nosuchusershort": "Ne postoji korisnik sa imenom \"$1\".\nProvjerite da li ste dobro ukucali.",
"nouserspecified": "Morate izabrati korisničko ime.",
"login-userblocked": "Ovaj korisnik je blokiran. Prijava nije dozvoljena.",
"accmailtext": "Nasumično odabrana šifra za [[User talk:$1|$1]] je poslata na adresu $2.\n\nŠifra/lozinka za ovaj novi račun može biti promijenjena na stranici ''[[Special:ChangePassword|izmjene šifre]]'' nakon prijave.",
"newarticle": "(Novi)",
"newarticletext": "Preko linka ste došli na stranicu koja još uvijek ne postoji.\n* Ako želite stvoriti stranicu, počnite tipkati u okviru dolje (v. [$1 stranicu za pomoć] za više informacija).\n* Ukoliko ste došli greškom, pritisnike dugme '''Nazad''' ('''back''') na vašem pregledniku.",
- "anontalkpagetext": "----''Ovo je stranica za razgovor za anonimnog korisnika koji još nije napravio račun ili ga ne koristi.\nZbog toga moramo da koristimo brojčanu IP adresu kako bismo identifikovali njega ili nju.\nTakvu adresu može dijeliti više korisnika.\nAko ste anonimni korisnik i mislite da su vam upućene nebitne primjedbe, molimo Vas da [[Special:UserLogin/signup|napravite račun]] ili se [[Special:UserLogin|prijavite]] da biste izbjegli buduću zabunu sa ostalim anonimnim korisnicima.''",
+ "anontalkpagetext": "----''Ovo je stranica za razgovor za anonimnog korisnika koji još nije napravio račun ili ga ne koristi.\nZbog toga moramo da koristimo brojčanu IP adresu kako bismo identifikovali njega ili nju.\nTakvu adresu može dijeliti više korisnika.\nAko ste anonimni korisnik i mislite da su vam upućene nebitne primjedbe, molimo Vas da [[Special:CreateAccount|napravite račun]] ili se [[Special:UserLogin|prijavite]] da biste izbjegli buduću zabunu sa ostalim anonimnim korisnicima.''",
"noarticletext": "Na ovoj stranici trenutno nema teksta.\nMožete [[Special:Search/{{PAGENAME}}|tražiti naslov ove stranice]] u drugim stranicama,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretraživati srodne registre],\nili [{{fullurl:{{FULLPAGENAME}}|action=edit}} urediti ovu stranicu]</span>.",
"noarticletext-nopermission": "Trenutno nema teksta na ovoj stranici.\nMožete [[Special:Search/{{PAGENAME}}|tražiti ovaj naslov stranice]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane registre]</span>. alio nemate dozvolu za stvaranje ove stranice.",
"missing-revision": "Ne mogu da pronađem izmenu br. $1 na stranici pod nazivom „{{FULLPAGENAME}}“.\n\nOvo se obično dešava kada pratite zastarjelu vezu do stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
"upload-form-label-own-work": "Ovo je moje djelo",
"upload-form-label-infoform-categories": "Kategorije",
"upload-form-label-infoform-date": "Datum",
- "upload-form-label-own-work-message-local": "Potvrđujem kako postavljam ovu datoteku u skladu sa uvjetima korištenja i politikom licenciranja na {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Ukoliko niste u stanju postaviti ovu datoteku pod politikom {{SITENAME}}, molimo zatvorite ovaj dijalog i pokušajte drugom metodom.",
- "upload-form-label-not-own-work-local-local": "Također možete pokušati [[Special:Upload|na standarnoj stranici za postavljanje]].",
- "upload-form-label-own-work-message-default": "Razumijem kako postavljam ovu datoteku na dijeljeno skladište. Potvrđujem kako to činim u skladu sa uvjetima korištenja i ovdašnjom politikom licenciranja.",
- "upload-form-label-not-own-work-message-default": "Ukoliko niste u stanju postaviti ovu datoteku pod politikom dijeljene ostave, molimo zatvorite ovaj dijalog i pokušajte drugu metodu.",
- "upload-form-label-not-own-work-local-default": "Možete također pokušati koristeći [[Special:Upload|stranicu za postavljanje na {{SITENAME}}]], ukoliko se ova datoteka može postaviti pod tamošnjom politikom.",
- "upload-form-label-own-work-message-shared": "Potvrđujem da posjedujem autorska prava za ovu datoteku i slažem se da ću je neopozivo postaviti na Wikimedia Commons pod licencom [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0], te se slažem s [https://wikimediafoundation.org/wiki/Terms_of_Use Uvjetima korištenja].",
- "upload-form-label-not-own-work-message-shared": "Ako ne posjedujete autorska prava za ovu datoteku ili je želite postaviti pod drugom licencom, imajte na umu da možete koristiti [https://commons.wikimedia.org/wiki/Special:UploadWizard čarobnjak za postavljanje datoteka na Commonsu].",
- "upload-form-label-not-own-work-local-shared": "Također možete koristiti [[Special:Upload|stranicu za postavljanje datoteka na projektu {{SITENAME}}]] ako politika stranice dozvoljava postavljanje ove datoteke.",
+ "upload-form-label-own-work-message-generic-local": "Potvrđujem kako postavljam ovu datoteku u skladu sa uvjetima korištenja i politikom licenciranja na {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Ukoliko niste u stanju postaviti ovu datoteku pod politikom {{SITENAME}}, molimo zatvorite ovaj dijalog i pokušajte drugom metodom.",
+ "upload-form-label-not-own-work-local-generic-local": "Također možete pokušati [[Special:Upload|na standarnoj stranici za postavljanje]].",
+ "upload-form-label-own-work-message-generic-foreign": "Razumijem kako postavljam ovu datoteku na dijeljeno skladište. Potvrđujem kako to činim u skladu sa uvjetima korištenja i ovdašnjom politikom licenciranja.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Ukoliko niste u stanju postaviti ovu datoteku pod politikom dijeljene ostave, molimo zatvorite ovaj dijalog i pokušajte drugu metodu.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Možete također pokušati koristeći [[Special:Upload|stranicu za postavljanje na {{SITENAME}}]], ukoliko se ova datoteka može postaviti pod tamošnjom politikom.",
"backend-fail-stream": "Ne mogu da emitujem datoteku $1.",
"backend-fail-backup": "Ne mogu da napravim rezervu datoteke $1.",
"backend-fail-notexists": "Datoteka $1 ne postoji.",
"createaccounterror": "$1 ur as tufit at kcmt",
"loginsuccesstitle": "Tkcmt mzyan (tllit ɣil ɣ ifalan)",
"loginsuccess": "Tllit ɣilad ɣ ifalan (tzdit d tuqqna) {{GENDER:$1|||}} ar {{SITENAME}} zund « $1 ».",
- "nosuchuser": "Asqdac « $1 » ur illi.\nUssaɣ n isqdacn ḥiln hlli.\nẒṛ daɣ ist turit mzyan mayad, niɣd [[Special:UserLogin/signup|tmmurẓmt amiḍan amaynu]].",
+ "nosuchuser": "Asqdac « $1 » ur illi.\nUssaɣ n isqdacn ḥiln hlli.\nẒṛ daɣ ist turit mzyan mayad, niɣd [[Special:CreateAccount|tmmurẓmt amiḍan amaynu]].",
"nosuchusershort": "Ur illa umsaws lli ilan assaɣ « $1 ». Ẓṛ ist turit mzyan mayad.",
"nouserspecified": "Illa fllak ad tarat assaɣ nk.",
"login-userblocked": "Asqdac ad ur as yufi ad ikcm. Tazdayt ɣ ifalan uras ttuyskar",
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Khun Sar",
+ "Nemo bis",
+ "Piangpha",
+ "Saiddzone",
+ "Saimawnkham",
+ "Saosukham",
+ "Sengwan"
+ ]
+ },
+ "tog-underline": "ႁဵင်းၵွင်ႉ ဢၼ်ထတ်းထႅဝ်တႂ်ႈဝႆႉ:",
+ "tog-hideminor": "လပ်ႉဝႆႉ ၶေႃႈထတ်းမႄးဢိတ်းဢွတ်း တီႈလွင်ႈလႅၵ်ႈလၢႆႊ ဢၼ်ၸင်ႇပူၼ်ႉမႃး",
+ "tog-hidepatrolled": "လပ်ႉဝႆႉ ၵၢၼ်ပႂ်ႉတူၺ်း ၶေႃႈထတ်းမႄး တီႈလွင်ႈလႅၵ်ႈလၢႆႊဢၼ်ၸင်ႇပူၼ်ႉမႃး",
+ "tog-newpageshidepatrolled": "လပ်ႉဝႆႉၼႃႈလိၵ်ႈဢၼ်ပႂ်ႉတူၺ်း ၵႃႊတီႈသဵၼ်ႈၸိုဝ်ႈၼႃႈလိၵ်ႈမႂ်ႇ",
+ "tog-hidecategorization": "သိူင်ႇၼႃႈလိၵ်ႈ လွင်ႈပၢႆး-",
+ "tog-extendwatchlist": "မႄႇၼႄ သဵၼ်ႈၸိုဝ်ႈ တႃႇၼႄလွင်ႈလႅၵ်ႈလၢႆႊတင်းသဵင်ႈ၊ ဢၼ်ဢမ်ႇၵႃး ၸိူဝ်းလႅၵ်ႈလၢႆႈပႆႇပေႃးႁိုင်",
+ "tog-usenewrc": "လွင်ႈလႅၵ်ႈလၢႆႊၼႃႈလိၵ်ႈၸုမ်း ၼႂ်းလွင်ႈလႅၵ်ႈလၢႆႊလႄႈသဵၼ်ႈၸိုဝ်ႈ ဢၼ်ပူၼ်ႉမႃးပႆႇႁိုင်",
+ "tog-numberheadings": "ႁူဝ်ၶေႃႈၶပ်ႉတူဝ်ၼပ်ႉဝႅၼ်ႊဝႅၼ်ႊ",
+ "tog-showtoolbar": "ၼႄပၼ် ႁၢဝ်းၶိူင်ႈထတ်းမႄး",
+ "tog-editondblclick": "ၼဵၵ်းၵူပ်ႉသေ ထတ်းမႄးၼႃႈလိၵ်ႈ",
+ "tog-editsectiononrightclick": "ၼဵၵ်းၼိူဝ်ႁူဝ်ၶေႃႈၵၼ်ႊသေ ၽုၺ်ႇၵၢၼ်ထတ်းမႄးၵၼ်ႊ",
+ "tog-watchcreations": "ထႅမ်ၼႃႈလိၵ်ႈ လႄႈ ၾၢႆႇ ဢၼ်ၵဝ်ၶႃႈသၢင်ႈၼၼ်ႉ သႂ်ႇတီႈသဵၼ်ႈမၢႆၵဝ်ၶႃႈ",
+ "tog-watchdefault": "ထႅမ်ၼႃႈလိၵ်ႈလႄႈၾၢႆႇ ဢၼ်ၵဝ်ၶႃႈသၢင်ႈၼၼ်ႉ သႂ်ႇတီႈသဵၼ်ႈမၢႆၵဝ်ၶႃႈ",
+ "tog-watchmoves": "ထႅမ်ၼႃႈလိၵ်ႈလႄႈၾၢႆႇလ် ဢၼ်ၵဝ်ၶႃႈၶၢႆႉမႃးၼၼ်ႉ သႂ်ႇတီႈသဵၼ်ႈမၢႆၵဝ်ၶႃႈ",
+ "tog-watchdeletion": "ထႅမ်ၼႃႈလိၵ်ႈလႄႈၾၢႆႇလ် ဢၼ်ၵဝ်ႇၶႃႈမွတ်ႇၼၼ်ႉ သႂ်ႇတီႈသဵၼ်ႈမၢႆၵဝ်ၶႃႈ",
+ "tog-watchuploads": "ထႅမ်သႂ်ႇ ၾႆႇဢၼ်မႂ်ႇ ဢၼ်ၵဝ်ၶႃႈ လူတ်ႇၶိုၼ်ႈၸူး သဵၼ်ႈမၢႆတူၺ်း ၵဝ်ၶႃႈ",
+ "tog-watchrollback": "ထႅမ်သႂ်ႇ ၼႃးလိၵ်ႈသႂ်ႇၸူး သဵၼ်ႈမၢႆတူၺ်းၵဝ်ႇၵႃႈ တီႈဢၼ်ၶႃႈႁဵတ်မႃး လွင်ႈႁူၼ်ၶိုၼ်း",
+ "tog-minordefault": "မၵ်းမၢႆ ၶေႃႈထတ်းမႄးဢိတ်းဢွၼ်ႇ ၼင်ႇပိူင်ၵႅဝ်ႈ",
+ "tog-previewontop": "ၼႄပၼ် ၵၢၼ်တူၺ်းလူင်ႈၼႃႈ ဢွၼ်တၢင်းၶွင်ႉထတ်းမႄး",
+ "tog-previewonfirst": "ၼႄပၼ် ၵၢၼ်တူၺ်းလူင်ႈၼႃႈ တီႈၵၢၼ်ထတ်းမႄးဢွၼ်တၢင်းသုတ်း",
+ "tog-enotifwatchlistpages": "ပေႃးၼႃႈလိၵ်ႈ ဢမ်ႇၼၼ် ၾၢႆႇလ်ႇ ၼႂ်းသဵၼ်ႈမၢႆၵဝ်ၶႃႈ မီးလွင်ႈလႅၵ်ႈလၢႆႊၸိုင် သူင်ႇဢီးမဵလ်းၸူးၵဝ်ၶႃႈတႃႉ",
+ "tog-enotifusertalkpages": "ပေႃးၼႃႈလိၵ်ႈ ၵၢၼ်ဢုပ်ႇလၢတ်ႈၽူႈၸႂ်ႉတိုဝ်းႁင်းၵဝ်ၶႃႈ မီးလွင်ႈလႅၵ်ႈလၢႆႊၸိုင် သူင်ႇဢီးမဵလ်းၸူးၵဝ်ၶႃႈတႃႉ",
+ "tog-enotifminoredits": "လွင်ႈထတ်းမႄး ၼႃႈလိၵ်ႈလႄႈၾၢႆႇလ်ဢိတ်းဢီႈၵေႃႈ သူင်ႇဢီးမေးလ်ၸူးၵဝ်ၶႃႈတႃႉ",
+ "tog-enotifrevealaddr": "ပိုတ်ႇၼႄပၼ် ႁဵင်းဢီးမဵလ်းၵဝ်ၶႃႈ တီႈလွင်ႈၾၢင်ႉတိူၼ်ဢီးမဵလ်း",
+ "tog-shownumberswatching": "ၼႄတၢင်းၼမ် ၵူၼ်းတူၺ်းလႄႈ",
+ "tog-oldsig": "လၢႆးမိုဝ်း ဢၼ်တိုၵ်ႉမီးဝႆႉ",
+ "tog-fancysig": "ႁဵတ်းႁႂ်ႈလၢႆးမိုဝ်း ပဵၼ်ၼင်ႇပိူင်ၾၢင်ဝီႇၶီႇ (လူၺ်ႈဢမ်ႇမီးၵွင်ႉဢၼ်ဝႅၼ်ႊ)",
+ "tog-uselivepreview": "ၸႂ်ႉတိုဝ်း ၵၢၼ်တူၺ်းလူင်ႈၼႃႈ ဢၼ်တူင်ႉဝႆ",
+ "tog-forceeditsummary": "ပေႃးဝႃႈ တီႈႁုဝ်ႁူပ်ႈမႄးထတ်းၼၼ်ႉ ဢမ်ႇသႂ်ႇသင်သေ ပဵၼ်လွၵ်းပဝ်ႇဝႆ့ၼႆ ပၼ်ၽၢင်ႉၶႃႈသေၵမ်း",
+ "tog-watchlisthideown": "လပ်ႉၵၢၼ်ထတ်းမႄးၵဝ်ၶႃႈ ၵႃႊတီႈသဵၼ်ႈမၢႆဝႆႉ",
+ "tog-watchlisthidebots": "သိူင်ႇ ၶေႃႈထတ်းၵဝ် တမ်ႈတီႈ သဵၼ်ႈပႂ်ႉတူၺ်း",
+ "tog-watchlisthideminor": "လပ်ႉၵၢၼ်ထတ်းမႄးဢိတ်းဢီႈ ၵႃႊတီႈသဵၼ်ႈမၢႆဝႆႉ",
+ "tog-watchlisthideliu": "လပ်ႉဝႆႉ ၵၢၼ်ထတ်းမႄး လူၺ်ႈၽူႈၸႂ်ႉတိုဝ်းဢၼ်ၶဝ်ႈဝႆႉ ၵႃႊတီႈသဵၼ်ႈမၢႆ",
+ "tog-watchlistreloadautomatically": "ပေႃးဝႃႈ တူဝ်ထွင်မီး လွင်ႈလႅၵ်ႈလၢႆႈၼႆ ၶိုၼ်းၽိုၼ်ႉပၼ် သဵၼ်ႈပႂ်ႉတူၺ်း ႁင်းမၼ်းလႄႈ။ (တေလူဝ်ႇ JavaScript)",
+ "tog-watchlisthideanons": "လပ်ႉဝႆႉ ၵၢၼ်ထတ်းမႄး လူၺ်ႈၽူႈၸႂ်ႉတိုဝ်းႁၢမ်းၸိုဝ်ႈ ၵႃႊတီႈသဵၼ်ႈမၢႆ",
+ "tog-watchlisthidepatrolled": "လပ်ႉဝႆႉ ၵၢၼ်ထတ်းမႄးဢၼ်ပႂ်ႉတူၺ်းဝႆႉၼၼ်ႉ ၵႃႊတီႈသဵၼ်ႈမၢႆ",
+ "tog-watchlisthidecategorization": "သိူင်ႇၼႃႈလိၵ်ႈ လွင်ႈပၢႆး-",
+ "tog-ccmeonemails": "သူင်ႇၽိုၼ်မိူၼ်ဢီးမဵလ်း ဢၼ်ၵဝ်ၶႃႈသူင်ႇၸူး ၽူႈၸႂ်ႉတိုဝ်းတၢင်ႇၵေႃႉၶဝ်",
+ "tog-diffonly": "ယႃႇပေၼႄ လွင်ႈၶဝ်ႈပႃးၼႂ်း ၼႃႈလိၵ်ႈ ၸွမ်းၼင်ႇ လွၵ်းၽၢႆႇတႂ်ႈၼႆႉ",
+ "tog-showhiddencats": "ပိုတ်ႇၼႄ လိူင်ႈ ဢၼ်လပ်ႉဝႆႉ",
+ "tog-norollbackdiff": "ဝၢႆးသေႁဵတ်း ႁူၼ်လင်ၶိုၼ်းယဝ်ႉၼႆ ယႃႇပေၼႄ လွၵ်း diff လႃႈ",
+ "tog-useeditwarning": "ပေႃးပႆႇလႆႈ ၵဵပ်းသိမ်းၼႃႈလိၵ်ႈ ဢၼ်ၶႃႈမူၼ်ႉမႄးဝႆႉသေ သင်ၸိူဝ်ႉဝႃႈ ၶႃႈဢွၵ်ႇၵႂႃႇၼႆ ၽၢင်ႉတိူၼ်ႇပၼ်ၶႃႈ သေၵမ်း",
+ "tog-prefershttps": "ၽွင်းၶဝ်ႈၸႂ်ႉတိုဝ်းၼၼ်ႉ ၸႂ်ႉတိုဝ်းၶွၼ်ႇၼႅၵ်ႉသျိၼ်ႇ ဢၼ်ႁူမ်ႇလူမ်ႈ",
+ "underline-always": "ၵူႊယၢမ်း",
+ "underline-never": "ဢမ်ႇႁဵတ်းသေပွၵ်ႈ",
+ "underline-default": "ပိူင်ၵႅဝ်ႈၾၢင်ႁၢင်ႊတၢင်းၼွၵ်ႈ ဢမ်ႇၼၼ် ပြၢဝ်းသိူဝ်ႇ",
+ "editfont-style": "ဢွင်ႈတီႈဢၼ်ထတ်းမႄး ဝႅပ်ႇယၢင်ႇၾွၼ်ႉ",
+ "editfont-default": "ပၵ်းၵဝ်ႇပိူင်ၵဝ်ႇပြၢဝ်းသိူဝ်ႇ",
+ "editfont-monospace": "ၾွၼ်ႉ မူဝ်ႇၼူဝ်သပဵတ်ႉ",
+ "editfont-sansserif": "ၾွၼ်ႉ San-serif",
+ "editfont-serif": "ၾွၼ်ႉဢၼ်သဵၼ်ႈတိူဝ်းၸႅင်ႈ",
+ "sunday": "ဝၼ်းဢႃးတိတ်ႉ",
+ "monday": "ဝၼ်းၸၼ်",
+ "tuesday": "ဝၼ်းဢင်းၵၢၼ်း",
+ "wednesday": "ဝၼ်းပုတ်ႉ",
+ "thursday": "ဝၼ်းၽတ်း",
+ "friday": "ဝၼ်းသုၵ်း",
+ "saturday": "ဝၼ်းသဝ်",
+ "sun": "တိတ်ႉ",
+ "mon": "ၸၼ်",
+ "tue": "ၵၢၼ်း",
+ "wed": "ပုတ်ႉ",
+ "thu": "ၽတ်း",
+ "fri": "သုၵ်း",
+ "sat": "သဝ်",
+ "january": "ၸၼ်ႇဝႃႇရီႇ",
+ "february": "ၾႅပ်ႇဝႃႇရီႇ",
+ "march": "မၢၶျ်ႉ",
+ "april": "ဢေႇပရႄႇ",
+ "may_long": "မေႇ",
+ "june": "ၵျုၼ်ႇ",
+ "july": "ၵျူႇလၢႆႇ",
+ "august": "ဢေႃးၵၢသ်ႉ",
+ "september": "သႅပ်ႇထႅမ်ႇပႃႇ",
+ "october": "ဢွၵ်ႇထူဝ်ႇပႃႇ",
+ "november": "ၼူဝ်ႇဝႅမ်ႇပႃႇ",
+ "december": "တီႇသႅမ်ႇပႃႇ",
+ "january-gen": "ၸၼ်ႇဝႃႇရီႇ",
+ "february-gen": "ၾႅပ်ႇဝႃႇရီႇ",
+ "march-gen": "မၢၶျ်ႉ",
+ "april-gen": "ဢေႇပရႄႇ",
+ "may-gen": "မေႇ",
+ "june-gen": "ၵျုၼ်ႇ",
+ "july-gen": "ၵျူႇလၢႆႇ",
+ "august-gen": "ဢေႃးၵၢသ်ႉ",
+ "september-gen": "သႅပ်ႇထႅမ်ႇပႃႇ",
+ "october-gen": "ဢွၵ်ႇထူဝ်ႇပႃႇ",
+ "november-gen": "ၼူဝ်ႇဝႅမ်ႇပႃႇ",
+ "december-gen": "တီႇသႅမ်ႇပႃႇ",
+ "jan": "ၸၼ်ႇ",
+ "feb": "ၾႅပ်ႇ",
+ "mar": "မၢၶျ်ႉ",
+ "apr": "ဢေႇ",
+ "may": "မေႇ",
+ "jun": "ၵျုၼ်ႇ",
+ "jul": "ၵျူႇ",
+ "aug": "ဢေႃး",
+ "sep": "သႅပ်ႇ",
+ "oct": "ဢွၵ်ႇ",
+ "nov": "ၼူဝ်ႇ",
+ "dec": "တီႇ",
+ "january-date": "ၸၼ်ႇဝႃႇရီႇ $1",
+ "february-date": "ၾႅပ်ႇဝႃႇရီႇ $1",
+ "march-date": "မၢၶျ်ႉ $1",
+ "april-date": "ဢေႇပရႄႇ $1",
+ "may-date": "လိူၼ်မေႇ $1",
+ "june-date": "လိူၼ်ၵျုၼ်ႇ $1",
+ "july-date": "လိူၼ်ၵျူႇလၢႆႇ $1",
+ "august-date": "လိူၼ်ဢေႃးၵၢသ်ႉ $1",
+ "september-date": "လိူၼ်သႅပ်ႇထႅမ်ႇပႃႇ $1",
+ "october-date": "လိူၼ်ဢွၵ်ႇထူဝ်ႇပႃႇ $1",
+ "november-date": "လိူၼ်ၼူဝ်ႇဝႅမ်ႇပႃႇ $1",
+ "december-date": "လိူၼ်တီႇသႅမ်ႇပႃႇ $1",
+ "period-am": "AM ပွတ်းၸဝ်ႉ",
+ "period-pm": "PM ပွတ်းလႃႈ",
+ "pagecategories": "{{PLURAL:$1|လိူင်ႈ|လိူင်ႈတင်းလၢႆ}}",
+ "category_header": "ၼႃႈလိၵ်ႈၼႂ်းလိူင်ႈ \"$1\"",
+ "subcategories": "ၵိင်ႇၽႄလိူင်ႈ",
+ "category-media-header": "သိုဝ်ႇၼႂ်းလိူင်ႈ \"$1\"",
+ "category-empty": "<em> လိူင်ႈဢၼ်ၼႆႉ ၸင်ႇၼႆႉ ဢမ်ႇမီးၼႃႈလိၵ်ႈ ဢမ်ႇၼၼ် သိုဝ်ႈဢီႈသင်ဝႆႉ</em>",
+ "hidden-categories": "{{PLURAL:$1|လိူင်ႈဢၼ်လပ်ႉဝႆႉ |လိူင်ႈၸိူဝ်း ဢၼ်လပ်ႉဝႆႉ}}",
+ "hidden-category-category": "လိူင်ႈ ဢၼ်လပ်ႉသိူင်ႇဝႆႉ",
+ "category-subcat-count": "{{PLURAL:$2|ၼႂ်းလိူင်ႈဢၼ်ၼႆႉ မီးၵိင်ႇၽႄလိူင်ႈၼႆႉ ၸိူင်ႉၼႆၵွၺ်း|ၼႂ်းလိူင်ႈၼႆႉ မီး This category has the following {{PLURAL:$1|ၵိင်ႇၽႄလိူင်ႈ|$1 ၵိင်ႇၽႄလိူင်ႈတင်းလၢႆး}}, ၼႂ်းၵႃႊ $2 တင်းသဵင်ႈတင်းမူတ်း}}",
+ "category-subcat-count-limited": "ၼႂ်းလိူင်ႈၼႆႉ မီးဝႆႉလိူင်ႈၼင်ႇၼႆ {{PLURAL:$1| ၵိင်ႇၽႄလိူင်ႈ |$1 ၵိင်ႇၽႄလိူင်ႈတင်းလၢႆ}}",
+ "category-article-count": "{{PLURAL:$2| လိူင်ႈဢၼ်ၼႆႉ ပႃးဝႆႉၼႃႈလိၵ်ႈၼင်ႇပႃႈတႂ်ႈၼႆႉၵွၺ်း |တၢင်းပႃႈတႂ်ႈၼႆႉ{{PLURAL:$1| ၼႃႈလိၵ်ႈ }} မီးၼႂ်းလိူင်ႈၼႆႉ ၵႃႊၼႂ်း $2 တင်းသဵင်ႈတင်းမူတ်း}}",
+ "category-article-count-limited": "တၢင်းပႃႈတႂ်ႈၼႆႉ {{PLURAL:$1| ၼႃႈလိၵ်ႈ }} မီးၼႂ်းလိူင်ႈ တေႃႈလဵဝ်ၼႆႉ",
+ "category-file-count": "{{PLURAL:$2| လိူင်ႈဢၼ်ၼႆႉ ပႃးဝႆႉၼႃႈလိၵ်ႈၼင်ႇပႃႈတႂ်ႈၼႆႉၵွၺ်း |တၢင်းပႃႈတႂ်ႈၼႆႉ{{PLURAL:$1| ၾႆႇၼႆႉပဵၼ်|$1 ၾၢႆႇၸိူဝ်းၼႆႉပဵၼ် }} မီးၼႂ်းလိူင်ႈၼႆႉ ၵႃႊၼႂ်း $2 တင်းသဵင်ႈတင်းမူတ်း}}",
+ "category-file-count-limited": "ဢၼ်ပဵၼ် {{PLURAL:$1|ၾၢႆႇၼႆႉ|$1 ၾၢႆႇၸိူဝ်းၼႆႉ}} မီးဝႆႉတီႈၼႂ်း တွၼ်ႈၵၼ်ၼႆ့။",
+ "listingcontinuesabbrev": "သိုပ်ႇ",
+ "index-category": "ၼႃႈလိၵ်ႈ ၸိူဝ်းၸီ့ဝႆ့",
+ "noindex-category": "ၼႃႈလိၵ်ႈ ၸိူဝ်းၸီ့ဝႆ့",
+ "broken-file-category": "ၼႃႈလိၵ်ႈၸိူဝ်းမီးဝႆႉ ႁဵင်းၵွင်ႉၾၢႆႇဢၼ်လူ့လႅဝ်",
+ "about": "လွင်ႈတၢင်း",
+ "article": "ၼမ်းၼႂ်း",
+ "newwindow": "(ပိုတ်ႇၼင်ႇဝိၼ်းတူဝ်း ဢၼ်မႂ်ႇ)",
+ "cancel": "ဢမ်ႇႁဵတ်း",
+ "moredotdotdot": "ထႅင်ႈ...",
+ "morenotlisted": "သဵၼ်ႈမၢႆဢၼ်ၼႆႉ ဢမ်ႇတဵမ်ထူၼ်ႈ။",
+ "mypage": "ၼႃႈလိၵ်ႈ",
+ "mytalk": "တွၼ်ႈဢုပ်ႇ",
+ "anontalk": "တွၼ်ႈဢုပ်ႇ",
+ "navigation": "ၼႄတၢင်း",
+ "and": " လႄႈ",
+ "qbfind": "ႁႃ",
+ "qbbrowse": "ပိုတ်ႇႁႃ",
+ "qbedit": "မူၼ်ႉမႄး",
+ "qbpageoptions": "ၼႃႈလိၵ်ႈၼႆ့",
+ "qbmyoptions": "ၼႃႈလိၵ်ႈၵဝ်ၶႃႈ",
+ "faq": "ၶေႃႈထၢမ်ၵႆႉႁူပ်ႉ",
+ "faqpage": "Project:တွၼ်ႈတွင်ႈထၢမ်",
+ "actions": "ၵၢၼ်ႁဵတ်းသၢင်ႈ",
+ "namespaces": "ဢွင်ႈတီႈၸိုဝ်ႈ",
+ "variants": "လွင်ႈပႅၵ်ႇပိူင်ႈ",
+ "navigation-heading": "သဵၼ်ႈၵၢၼ်ၼႄတၢင်း",
+ "errorpagetitle": "ၽိတ်း",
+ "returnto": "ၶိုၼ်းဝၢႆႇၸူး $1.",
+ "tagline": "လုၵ်ႉတီႈ {{SITENAME}} မႃး",
+ "help": "ၸွႆႈထႅမ်",
+ "search": "ၶူၼ်ႉႁႃ",
+ "searchbutton": "ၶူၼ်ႉႁႃ",
+ "go": "သိုပ်ႇၵႂႃႇ",
+ "searcharticle": "သိုပ်ႇၵႂႃႇ",
+ "history": "ပိုၼ်းၼႃႈလိၵ်ႈ",
+ "history_short": "ပိုၼ်း",
+ "updatedmarker": "ပဵၼ်ဢၢပ်ႉတိတ်ႉဝႆႉ ၸဵမ်မိူဝ်ႈၶႃႈၵႂႃႇဢႅဝ်ႇၵမ်းလိုၼ်းသုတ်း",
+ "printableversion": "တွၼ်ႈတႃႇဢိတ်ႇဢွၵ်ႇ",
+ "permalink": "ႁဵင်းၵွင်ႉ မၼ်ႈၵိုမ်း",
+ "print": "ထုတ်ႇဢွၵ်ႇ",
+ "view": "လူတူၺ်း",
+ "view-foreign": "တူၺ်းတီႈ $1",
+ "edit": "မူၼ်ႉမႄး",
+ "edit-local": "မႄးထတ်း ၶေႃႈသပ်းလႅင်းလူဝ်ႇၵႄႇ",
+ "create": "သၢင်ႈ",
+ "create-local": "ထႅမ်သႂ်ႇ ၶေႃႈသပ်းလႅင်းလူဝ်ႇၵႄႇ",
+ "editthispage": "မူၼ်ႉမႄး ၼႃႈလိၵ်ႈၼႆႉ",
+ "create-this-page": "သၢင်ႈ ၼႃႈလိၵ်ႈၼႆႉ",
+ "delete": "ယႃႉ",
+ "deletethispage": "ယႃႉ ၼႃႈလိၵ်ႈၼႆႉ",
+ "undeletethispage": "ဢဝ်ၶိုၼ်း ၼႃႈလိၵ်ႈၼႆ့",
+ "undelete_short": "ဢဝ်ၶိုၼ်း {{PLURAL:$1|ဢၼ် ထတ်းသၢင်ႈ |$1 ၸိူဝ်းထတ်းသၢင်ႈ}}",
+ "viewdeleted_short": "တူၺ်း {{PLURAL:$1|လွင်ႈထတ်းသၢင်ႈ ဢၼ်မွတ်ႇပႅတ်ႈ|$1 ၸိူဝ်းထတ်းသၢင်ႈ ဢၼ်မွတ်ႇပႅတ်ႈ}}",
+ "protect": "ႁေႉၵင်ႈ",
+ "protect_change": "လႅၵ်ႈလၢႆႈ",
+ "protectthispage": "ႁေႉၵင်ႈ ၼႃႈလိၵ်ႈၼႆႉ",
+ "unprotect": "လႅၵ်ႈလၢႆႊ ၵၢၼ်ႁေႉၵင်ႈ",
+ "unprotectthispage": "လႅၵ်ႈလၢႆႊ ၵၢၼ်ႁေႉၵင်ႈ ၼႃႈလိၵ်ႈၼႆႉ",
+ "newpage": "ၼႃႈလိၵ်ႈမႂ်ႇ",
+ "talkpage": "ဢုပ်ႇလိူၺ်ႈ ၼႃႈလိၵ်ႈၼႆႉ",
+ "talkpagelinktext": "တွၼ်ႊဢုပ်ႇ",
+ "specialpage": "ၼႃႈလိၵ်ႈ ၶိုၵ်ႉတွၼ်း",
+ "personaltools": "ၶိူင်ႈသုၼ်ႇလဵဝ်",
+ "articlepage": "တူၺ်း ၼႃႈလိၵ်ႈ ၼမ်းၼႂ်း",
+ "talk": "တႃႇဢုပ်ႇ",
+ "views": "လူတူၺ်း",
+ "toolbox": "ၶိူင်ႈၵမ်ႉၵႅမ်",
+ "userpage": "တူၺ်းၼႃႈလိၵ်ႈၽူႈၸႂ်ႉတိုဝ်း",
+ "projectpage": "တူၺ်းၼႃႈလိၵ်ႈ ပရေႃးၵျႅၵ်ႉ",
+ "imagepage": "တူၺ်းၼႃႈလိၵ်ႈၾၢႆႇ",
+ "mediawikipage": "တူၺ်းၼႃႈလိၵ်ႈ ၶေႃႈၶၢဝ်ႇ",
+ "templatepage": "တူၺ်းၼႃႈလိၵ်ႈ လွၵ်းပိူင်",
+ "viewhelppage": "တူၺ်းၼႃႈလိၵ်ႈ ၸွႆႈထႅမ်",
+ "categorypage": "တူၺ်းၼႃႈလိၵ်ႈထၢၼ်ႈ",
+ "viewtalkpage": "တူၺ်း တွၼ်ႈဢုပ်ႇဢူဝ်း",
+ "otherlanguages": "ၼႂ်းလိၵ်ႈတၢင်ႇဢၼ်",
+ "redirectedfrom": "(လုၵ်ႉတီး $1 ၼႆႈသေ ၶိုၼ်းပိၼ်ႇဝၢႆႇမႃး)",
+ "redirectpagesub": "ပိၼ်ႇႁူဝ်ၼႃႈလိၵ်ႈ",
+ "redirectto": "ဝိၼ်ႇၵႂႃႇၸူး:",
+ "lastmodifiedat": "ၼႃႈလိၵ်ႈၼႆ့ မႄးဝႆႉ ၼင်ႇၵမ်းလိုၼ်းသုတ်း မိူဝ်ႈ ဝၼ်းတီႈ $1 ၶၢဝ်းယၢမ်း $2",
+ "viewcount": "ၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇၸႂ်ႉဝႆႉ {{PLURAL:$1|ပွၵ်ႈၼိုင်ႈ|$1 ၵမ်း}}.",
+ "protectedpage": "ၼႃးလိၵ်ႈ ဢၼ်ႁႄႉၵင်ႈဝႆႉ",
+ "jumpto": "ၶၢမ်ႈၸူး :",
+ "jumptonavigation": "ၼႄတၢင်း",
+ "jumptosearch": "ၶူၼ်ႉႁႃ",
+ "view-pool-error": "ၵဵင်ၸႂ်ယူႇၶႃႈ၊ သႃႇပိူဝ်ႁဝ်း ထုၵ်ႇလႆႈၸႂ်ႉႁၢဝ်ႈႁႅင်းဝႆႉ ယၢမ်းလဵဝ်။\nယွၼ်ႉပိူဝ်ႈဝႃႈ ၽူႈၸႂ်ႉတိုဝ်းတၢင်းၼမ်တၢင်းလၢႆ တိုၵ်ႉၽွမ်ႉၵၼ် ၶဝ်ႈတူၺ်း ၼႃႈလိၵ်ႈၼႆ့။\nၶႅၼ်းတေႃႈ ပႂ်ႉပၼ်ၵမ်းၼိုင်ႈသေ ၸွင်ႇၵွႆႈၶိုၼ်း ပိုတ်ႇတူၺ်း ၼႃႈလိၵ်ႈၼႆႉၶႃႈ။\n\n$1",
+ "generic-pool-error": "ၵဵင်ၸႂ်ယူႇၶႃႈ၊ သႃႇပိူဝ်ႁဝ်း ထုၵ်ႇလႆႈၸႂ်ႉႁၢဝ်ႈႁႅင်းဝႆႉ ယၢမ်းလဵဝ်။\nယွၼ်ႉပိူဝ်ႈဝႃႈ ၽူႈၸႂ်ႉတိုဝ်းတၢင်းၼမ်တၢင်းလၢႆ တိုၵ်ႉၽွမ်ႉၵၼ် ၶဝ်ႈတူၺ်း ငဝ်ႈငႃႇၼႆ့။\nၶႅၼ်းတေႃႈ ပႂ်ႉပၼ်ၵမ်းၼိုင်ႈသေ ၸွင်ႇၵွႆႈၶိုၼ်း ပိုတ်ႇတူၺ်း ငဝ်ႈငႃႇၼႆႉၶႃႈ။",
+ "pool-timeout": "ၶၢဝ်းယၢမ်းသုတ်းသဵင်ႈ ဢၼ်ပႂ်ႉတႃႇပိုတ်ႇသေႃး",
+ "pool-queuefull": "ၼွင်ၸႅၼ်ႇထႅဝ် တဵမ်ဝႆႉဢေႃႈ။",
+ "pool-errorunknown": "ဢမ်ႇႁူ့ ၵၢၼ်ၽိတ်ႈပိူင်ႈ",
+ "pool-servererror": "ဢၼ်ပဵၼ်ၼႃႈၵၢၼ် တူဝ်ဢၢၼ်ႇၼွင်ၼၼ်ႉ မၼ်းဢမ်ႇႁဵတ်းၵၢၼ် ($1).",
+ "poolcounter-usage-error": "ၵၢၼ်ၸႂ်ႉၸိုဝ်း ၽိတ်းပိူင်ႈ: $1",
+ "aboutsite": "လွင်ႈတၢင်း {{SITENAME}}",
+ "aboutpage": "Project: လွင်ႈဝႅပ်ႉသႆႉ",
+ "copyright": "ၸိူဝ်းၶဝ်ႈပႃးဝႆႉၼႆႉ မၼ်းတေၸၢင်ႈၸႂ်ႉလႆႈ ၵႃႈတီႈ ဝႂ် $1",
+ "copyrightpage": "{{ns:project}}:သုၼ်ႇထုတ်ႇ",
+ "currentevents": "ၵၢၼ်ႁဵတ်းသၢင်ႈယၢမ်းလဵဝ်",
+ "currentevents-url": "Project:ၵၢၼ်ႁဵတ်းသၢင်ႈ ယၢမ်းလဵဝ်",
+ "disclaimers": "ၶေႃႈထဵင်",
+ "disclaimerpage": "Project:ၵၢၼ်ထဵင်ၶိုၼ်းၵူႈလွင်ႈလွင်ႈ",
+ "edithelp": "မႄးထတ်းၵၼ်ၸွႆႈထႅမ်",
+ "helppage-top-gethelp": "ၸွႆႈထႅမ်",
+ "mainpage": "ၼႃႈႁူဝ်ႁႅၵ်ႈ",
+ "mainpage-description": "ၼႃႈႁူဝ်ႁႅၵ်ႈ",
+ "policy-url": "Project:လၢႆးငၢၼ်း",
+ "portal": "ၽွတ်ႇတိူဝ်ႇ တူင်ႇဝိူင်း",
+ "portal-url": "Project:ၽွတ်ႇတိူဝ်ႇ တူင်ႇဝိူင်း",
+ "privacy": "လၵ်းၼမ်း လွင်ႈႁူမ်ႇလူမ်ႈ သုၼ်ႇလဵဝ်",
+ "privacypage": "Project:လၵ်းၼမ်း လွင်ႈႁူမ်ႈလူမ်ႈ သုၼ်ႇလဵဝ်",
+ "badaccess": "ၵၢၼ်လူတ်းပွႆႇ ၽိတ်းပိူင်ႈ",
+ "badaccess-group0": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇထုၵ်ႇၶႂၢင်းပၼ်တႃႇတေၸႂ်ႉ လွင်ႈႁဵတ်းသၢင်ႈ ဢၼ်ၸဝ်ႈၵဝ်ႇ တုၵ်းယွၼ်းဝႆႉၼၼ်ႉ။",
+ "badaccess-groups": "လွင်ႈႁဵတ်သၢင်ႈ ဢၼ်ၸဝ်ႈၵဝ်ႇ တုၵ်းယွၼ်းဝႆႉၼၼ်ႉ မၼ်းထုၵ်ႇ မၵ်းၶႅၼ်ႈဝႆႉတႃႇ ၽူႈၸႂ်ႉတိုဝ်းၶဝ် တီႈၼႂ်း {{PLURAL:$2|ၸုမ်း |ၸုမ်းၸိူဝ်းၼႆႉ}}: $1.",
+ "versionrequired": "တေလူဝ်ႇ ပိူဝ်းသျိၼ်း မၢႆဢွၵ်ႇ ဝီႇၶီႇမီႇတီႇယႃႇ $1",
+ "versionrequiredtext": "တႃႇတေၸႂ်ႉ ၼႃႈလိၵ်ႈၼႆ့ၼႆ တေလူဝ်ႇ ပိူဝ်းသျိၼ်း မႆဢွၵ်ႇ ဝီႇၶီႇမီႇတီႇယႃႇ $1 ဢေႃႈ။ တူၺ်းပႃး [[Special:Version|ၼႃးလိၵ်ႈ မၢႆဢွၵ်ႇ]].",
+ "ok": "ဢူဝ်ႇၶေႇ",
+ "retrievedfrom": "ဢဝ်ၶိုၼ်းမႃးတီႈ \"$1\"",
+ "youhavenewmessages": "{{PLURAL:$3|ၸဝ်ႈၵဝ်ႇ လႆႈႁပ်ႉဝႆႉ}} $1 ($2).",
+ "youhavenewmessagesfromusers": "{{PLURAL:$4|ၸဝ်ႈၵဝ်ႇလႆႈႁပ်ႉဝႆႉ}} $1 ၵႃႈတီႈ {{PLURAL:$3|ၽူႈၸႂ်ႉတိုဝ်း တၢင်ႇၵေႃႉ |$3 ၽူႈၸႂ်ႉတိုဝ်း တၢင်ႇၸိူဝ်း}} ($2).",
+ "youhavenewmessagesmanyusers": "ၸဝ်ႈၵဝ်ႇလႆႈႁၢပ်ႉဝႆႉ $1 ၵႃႈတီႈၽူႈၸႂ်ႉတိုဝ်းတၢင်းၼမ် ($2).",
+ "newmessageslinkplural": "{{PLURAL:$1|ၶေႃႈၶၢဝ်ႇမႂ်ႇ|999=ၶေႃႈၶၢဝ်ႇမႂ်ႇ}}",
+ "newmessagesdifflinkplural": "ဢၼ် {{PLURAL:$1|လႅၵ်ႈလၢႆႈ|999=လႅၵ်ႈလၢႆႈ}} ၵမ်းလိုၼ်းသုတ်း",
+ "youhavenewmessagesmulti": "ၸဝ်ႈၵဝ်ႇႁပ်ႉလႆႈၶေႃႈၶၢဝ်ႇမႂ်ႇ ၵႃႈတီႈ $1",
+ "editsection": "မူၼ်ႉမႄး",
+ "editold": "မူၼ်ႉမႄး",
+ "viewsourceold": "တူၺ်း ငဝ်ႈငႃႇ",
+ "editlink": "မႄးထတ်း",
+ "viewsourcelink": "တူၺ်း ငဝ်ႈငႃႇ",
+ "editsectionhint": "မူၼ်ႉမႄး တွၼ်ႊ :$1",
+ "toc": "ၼမ်းၼႂ်း",
+ "showtoc": "ၼႄ",
+ "hidetoc": "သိူင်ႇ",
+ "collapsible-collapse": "တူပ်ႉဝႆႉ",
+ "collapsible-expand": "ၽႄႇၼေ",
+ "confirmable-confirm": "ၸွင်ႇ {{GENDER:$1|ၸဝ်ႈၵဝ်ႇ}} လပ်ႉလွင်းႁိုဝ်?",
+ "confirmable-yes": "ၸႂ်ႈယဝ်ႉ",
+ "confirmable-no": "ဢမ်ႇ",
+ "thisisdeleted": "တူၺ်း ဢမ်ႇၼၼ် ၶိုၼ်းဢဝ် $1?",
+ "viewdeleted": "တေတူၺ်း $1 ၼေ?",
+ "restorelink": "တူၺ်း {{PLURAL:$1|လွင်ႈထတ်းသၢင်ႈ ဢၼ်မွတ်ႇပႅတ်ႈ|$1 ၸိူဝ်းထတ်းသၢင်ႈ ဢၼ်မွတ်ႇပႅတ်ႈ}}",
+ "feedlinks": "ၶၢဝ်ႇၶီး:",
+ "feed-invalid": "လိူင်ႈၶၢဝ်ႇၶီး ဢၼ်ဢၢၼ်းဢဝ်ၼႆႉ ၽိတ်းပိူင်ႈဝႆႉ",
+ "feed-unavailable": "ၶၢဝ်ႇၶီးတႃႇ ၸုမ်းႁူမ်ႈသၢင်ႈၼၼ်ႉ ဢမ်ႇပႆႇၸႂ်ႉလႆႈ။",
+ "site-rss-feed": "$1 ၶၢဝ်ႇၶီး RSS",
+ "site-atom-feed": "ၾိတ်ႉဢတွမ်ႊ $1 ဢၼ်",
+ "page-rss-feed": "\"$1\" ၶၢဝ်ႇၶီး RSS",
+ "page-atom-feed": "ၾိတ်ႉဢတွမ်ႊ $1 ဢၼ်",
+ "red-link-title": "ၼႃႈလိၵ်ႈ $1 ၼႆႉ ဢမ်ႇမီးယဝ်ႉ",
+ "sort-descending": "ၶပ်ႉတၢမ်းလူင်း",
+ "sort-ascending": "ၶပ်ႉတၢမ်းၶိုၼ်ႈ",
+ "nstab-main": "ၼႃႈလိၵ်ႈ",
+ "nstab-user": "ၼႃႈလိၵ်ႈ ၽူႈၸႂ်ႉတိုဝ်း",
+ "nstab-media": "ၼႃႈလိၵ်ႈ သိုဝ်ႇၶၢဝ်ႇ",
+ "nstab-special": "ၼႃႈလိၵ်ႈ ၶိုၵ်ႉတွၼ်း",
+ "nstab-project": "ၼႃႈလိၵ်ႈ ၶူင်းၵၢၼ်",
+ "nstab-image": "ၾၢႆႇ",
+ "nstab-mediawiki": "ၶေႃႈၽၢၵ်ႇ",
+ "nstab-template": "ပိူင်",
+ "nstab-help": "ၼႃႈလိၵ်ႈ ၸွႆႈထႅမ်",
+ "nstab-category": "လိူင်ႈ",
+ "mainpage-nstab": "ၼႃႈႁူဝ်ႁႅၵ်ႈ",
+ "nosuchaction": "ဢမ်ႇမီး လွင်ႈတူင်ႉၼိုင်",
+ "nosuchactiontext": "လွင်ႈတူင်ႉၼိုင်ဢၼ် URL မၵ်းမၼ်ႈဝႆႉၼၼ်ႉ မၼ်းဢမ်ႇမီးဝႆႉ။\n ၸဝ်ႈၵဝ်ႇတေပေႃႉ URL မၼ်းၽိတ်းဝႆႉ ဢမ်ႇၼၼ် လႆႈၸွမ်းဝႆႉ ႁဵင်းၵွင်ႉ ဢၼ်ၽိတ်းဝႆ့။ ပေႃးၸႂ်ႉ {{SITENAME}} ၼႆ မၼ်းတေၸီ့ၼႄပၼ် ၶေႃႈယုင်ႈယၢင်ႈ တီႈၼႂ်း သွပ်ႉၾ်ဝႄးယူႇ။",
+ "nosuchspecialpage": "ဢမ်ႇမီး ၼႃႈလိၵ်ႈၶိုၵ်ႉတွၼ်း",
+ "nospecialpagetext": "<strong>ၸဝ်ႈၵဝ်ႇ တုၵ်းယွၼ်းဝႆႉ ၼႃႈလိၵ်ႈၶိုၵ်ႉတွၼ်း ဢၼ်ဢမ်ႇပႆႇမီး</strong>\n\nသဵၼ်ႈမၢႆ ၼႃႈလိၵ်ႈၶိုၵ်ႉတွၼ်း ၸိူဝ်းဢၼ်ၸၢင်ႈဢဝ်လႆႈၼႆႉ တေလႆႈႁၼ်ၵႃႈတီႈ [[Special:SpecialPages|{{int:specialpages}}]].",
+ "error": "ၽိတ်းပိူင်ႈ",
+ "databaseerror": "ယွင်ၶေႃႈမုၼ်း ၽိတ်းပိူင်ႈ",
+ "databaseerror-text": "လႆႈပဵၼ်ဝႆႉ လွင်ႈၽိတ်းပိူင်ႈ ၵၢၼ်ၶူၼ်ႉႁႃ ယွင်ၶေႃႈမုၼ်း ။ ၼႆႉမၼ်းတေ ၼႄပၼ် လွင်ႈယုင်ႈယၢင်ႈ ၵႃႈတီႈၼႂ်း သွပ်ႉၾ်ဝႄး",
+ "databaseerror-textcl": "ၵၢၼ်ၶူၼ်ႉႁႃ ယွင်ၶေႃႈမုၼ်း လႆႈပဵၼ် လွင်ႈၽိတ်းပိူင်ႈဝႆႉ။",
+ "databaseerror-query": "ၶူၼ်ႉႁႃ : $1",
+ "databaseerror-function": "ၼႃႈၵၢၼ် : $1",
+ "databaseerror-error": "လွင်ႈၽိတ်းပိူင် : $1",
+ "transaction-duration-limit-exceeded": "တႃတေဝႄႈလႆႈ လွင်ႈသၢင်ႈၼႃႈလိၵ်ႈ မႃးမိူၼ်ၵၼ်ၼၼ်ႉ ၵၢၼ်လၢႆႈတီႈဢၼ်ၼႆႉ ထုၵ်ႇၵိုတ်းယင်ႉပႅတ်ႈ၊ ယွၼ်ႉပိူဝ်ႈဝႃႈ ၶၢဝ်းယၢမ်းတႅမ်ႈ ($1) ၼႆႉ မၼ်းပူၼ်ႉလိူဝ်သေ $2 {{PLURAL:$2|ၸႅတ်ႉၵၢၼ်ႉ|ၸႅတ်ႉၵၢၼ်ႉလိူဝ်}} ဢၼ်မၵ်းၶႅၼ်ႈဝႆႉ။\nသင်ၸိူဝ်ႉဝႃႈ ၸဝ်ႈၵဝ်ႇ လႅၵ်ႈလၢႆႈလၢႆဢၼ်ႁူမ်ႈမိူဝ်ႈလဵဝ်ၵၼ်ၼႆ၊ ၶႂ်ႈႁႂ်ႈၶတ်းၸႂ်ႁဵတ်းတူၺ်း တင်း multiple smaller operation ဢေႃႈ။",
+ "laggedslavemode": "<strong>ၶေႃႈၽၢင်ႉ:</strong>ၼႃႈလိၵ်ႈ တေဢမ်ႇဢၢပ်ႈၶဝ်ႈပႃး ဢၢပ်ႉတိတ်ႉ",
+ "readonly": "ယွင်ၶေႃႈမုၼ်း ထုၵ်ႇၶတ်းဝႆႉ",
+ "enterlockreason": "ပေႃႉသႂ်ႇပၼ် လွင်ႈတၢင်းတႃႇ တေၶတ်းဝႆႉ၊ ႁႂ်ႈပႃးပၼ် ၸဵမ်ၶၢဝ်းယၢမ်း လၢမ်းဢၼ်ဝႃႈ လွင်ႈၶတ်းဝႆႉၼႆႉ တေဢၢပ်ႈၶိုၼ်းပိုတ်ႇပၼ် မိူဝ်ႈလႂ် ဢၼ်ဝႃႈၼၼ်ႉ။",
+ "readonlytext": "ယွင်ၶေႃႈမုၼ်းၼႆႉ ယၢမ်းလဵဝ် ထုၵ်ႇၶတ်းဝႆႉတႃႇ တေထႅမ်သႂ်ႇဢၼ်မႂ်ႇ လႄႈ တႃႇမူၼ်ႉမႄး တၢင်ႇလွင်ႈတၢင်ႇၸိူဝ်း၊ မၼ်းတေဢၢပ်ႈပဵၼ်လူၺ်ႈ လွင်ႈဝႃႈ တိုၵ်ႉမူၼ်ႉမႄး ယွင်ၶေႃႈမုၼ်း ၼင်ႇၵႆႉႁဵတ်း။ ဝၢႆးသေၼၼ်ႉတႄႉ တေၶိုၼ်းႁဵတ်းၵၢၼ် မိူၼ်ၵဝ်ႇယူႇ။\n\nဢၼ်ပဵၼ် ၽူႈၵုမ်းၵမ်ပိူင်ႈသၢင်ႈ ၵေႃႉဢၼ်လႆႈ ၶတ်းၼႆႉဝႆႉၼၼ်ႉ မၼ်းပၼ်လွင်ႈသပ်းလႅင်းဝႆႉဝႃႈ : $1",
+ "missing-article": "ယွင်ၶေႃႈမုၼ်း ဢမ်ႇသွၵ်ႈႁႃႁၼ်လႆႈ ၽိုၼ်ၼႃႈလိၵ်ႈ ဢၼ်ထုၵ်ႇလီသွၵ်ႈထူပ်းႁၼ် ဢၼ်မီးၸိုဝ်ႈဝႃႈ \"$1\" $2 ။\n\nၼႆႉမၼ်းဢၢပ်ႈပဵၼ်ဝႆႉ ဢၼ်ၸိူဝ်းၼၼ်ႉ မၼ်းၵဝ်ႇၵႄႇၼႃႇလႄႈသင် ဢၼ်ပဵၼ် ပိုၼ်းႁဵင်းၵွင်ႉ ၸူးၼႃႈလိၵ်ႈၼၼ်ႉ ထုၵ်ႇမွတ်ႇပႅတ်ႈယဝ်ႉလႄႈသင် ၼႆဢေႃႈ။\n\nပေႃးဢမ်ႇၸႂ်ၸိူင်ႉၼၼ်တႄႉ ၸဝ်ႈၵဝ်ႇ တေလႆႈႁၼ် လွင်ႈယုင်ႈယၢင်ႈၼႆႉ တေၼႄဝႆႉ တီႈၼႂ်း သွပ်ႉၾ်ဝႄး ယူႇ။\nၶႅၼ်းတေႃႈ လဝ်ႈထိုင်ၼႆႉၸူး ၵႃႈတီႈ [[Special:ListUsers/sysop|administrator]] သေ မၢႆတွင်းဝႆႉပႃး ႁဵင်းလိၵ်ႈ URL မၼ်းသေၶႃႈလႄႈ။",
+ "missingarticle-rev": "(ၵၢၼ်ၶူၼ်ႉၶိုၼ်း#: $1)",
+ "missingarticle-diff": "(ၼိူင်း: $1, $2)",
+ "readonly_lag": "ယွင်ၶေႃႈမုၼ်းၼႆႉ မၼ်းထုၵ်ႇၶတ်းၵႂႃႇ ႁင်းမၼ်း ၽွင်းမိူဝ်ႈ သႃႇပိူဝ်ႇယွင်ၶေႃႈမုၼ်း ဢၼ်ၵႅမ်မၼ်း ထုၵ်ႇတီႉၸပ်းၸူး သႃႇပိူဝ်ႇယွင်ၶေႃႈမုၼ်း ငဝ်ႈမၼ်း။",
+ "nonwrite-api-promise-error": "ဢၼ်ပဵၼ်ႁူဝ်ၶေႃႈ HTTP ၼင်ႇ 'Promise-Non-Write-API-Action' ၼၼ်ႉထုၵ်ႇ သူင်ႇၸူးယဝ်ႉသေတႃႉ လွင်ႈတုၵ်းယွၼ်း မၼ်းတႄႉ တိုၵ်ႉမီးယူႇတီႈ API write module ။",
+ "internalerror": "ၽိတ်းၽၢႆႇၼႂ်း",
+ "internalerror_info": "ၽိတ်းပိူင်ႈၽၢႆႇၼႂ်း : $1",
+ "internalerror-fatal-exception": "လွင်ႈတၢင်း လွင်ႈလူႉလႅဝ် ၶွင်လိူင်ႈ \"$1\"",
+ "filecopyerror": "ဢမ်ႇၸၢင်ႈထုတ်ႇဢဝ် ၾၢႆႇ \"$1\" ၸူး \"$2\".",
+ "filerenameerror": "ဢမ်ႇၸၢင်ႈမႄးလၢႆႈၸိုဝ်ႈ \"$1\" ၸူး \"$2\".",
+ "filedeleteerror": "ဢမ်ႇၸၢင်ႈမွတ်ႇပႅတ်ႈ ၾၢႆႇ \"$1\".",
+ "directorycreateerror": "ဢမ်ႇၸၢင်ႈသၢင်ႈ ၾူဝ်ႇတႃႇဢွင်ႈသိမ်း \"$1\".",
+ "directoryreadonlyerror": "ၾူဝ်ႇတႃႇဢွင်ႈသိမ်း \"$1\" ၼႆႉပဵၼ် တႃႇလူႇၵူၺ်း။",
+ "directorynotreadableerror": "ၾူဝ်ႇတႃႇဢွင်ႈသိမ်း \"$1\" ၼႆႉ လူဢမ်ႇလႆႈ။",
+ "filenotfound": "ဢမ်ႇၸၢင်ႈသွၵ်ႈႁႃၾၢႆႇ \"$1\"",
+ "unexpected": "မၢႆၶၼ် ဢၼ်ဢမ်ႇမုင်ႈမွင်းဝႆႉ \"$1\"=\"$2\".",
+ "formerror": "လွင်ႈၽိတ်းပိူင်ႈ : ဢမ်ႇၸၢင်ႈယိုၼ်ႈသူင်ႇ ၽိုၼ်တမ်း",
+ "badarticleerror": "လွင်ႈႁဵတ်းသၢင်ႈ ဢၼ်ၼႆႉ တေဢမ်ႇၸၢင်ႈ ႁဵတ်းလႆႈ တီႈ ၼႃႈလိၵ်ႈၼႆႉ။",
+ "cannotdelete": "ၼႃႈလိၵ်ႈ ဢမ်ႇၼၼ် ၾၢႆႇ \"$1\" ၼႆႉ ဢမ်ႇၸၢင်ႈ မွတ်ႇပႅတ်ႈလႆႈ။\nမၼ်းဢၢပ်ႈပဵၼ် ၵူၼ်းသေၵေႃႉၵေႃႉ မွတ်ႇပႅတ်ႈၵႂႃႇယဝ်ႉ။",
+ "cannotdelete-title": "ဢမ်ႇၸၢင်ႈ မွတ်ႇပႅတ်ႈ ၼႃႈ လိၵ်ႈ \"$1\"",
+ "delete-hook-aborted": "လွင်ႈမွတ်ႇပႅတ်ႈ ထုၵ်ႇ ၵိုတ်းပႅတ်ႈ။\nမၼ်းဢမ်ႇမီး လွင်ႈ သပ်းလႅင်းၼႄသင်ဝႆႉ။",
+ "no-null-revision": "ဢမ်ႇၸၢင်ႈၵေႃႇသၢင်ႈ တူဝ်ၶူၼ်ႉၶိုၼ်းပဝ်ႇမႂ်ႇ တွၼ်ႈတႃႇ ၼႃႈလိၵ်ႈ \"$1\"",
+ "badtitle": "ႁူဝ်ၶေႃႈႁၢႆႉၸႃႉ",
+ "badtitletext": "ႁူဝ်ၶေႃႈ ၼႃႈလိၵ်ႈဢၼ် တုၵ်းယွၼ်းဝႆႉၼႆႉ မၼ်းဢမ်ႇၸႂ်ႉလႆႈ၊ ပဝ်ႇဝႆ့ ဢမ်ႇၼၼ် မၼ်းၵွင်ႉၽိတ်းပိူင်ႈဝႆႉတင်း ၽႃႇသႃႇၵႂၢမ်းတၢင်ႇဢၼ် ဢမ်ႇၼၼ် ႁူဝ်ၶေႃႈၼႂ်းၼႃႈလိၵ်ႈ ဝီႇၶီႇၼႆ့။",
+ "title-invalid-empty": "ၼႃႈလိၵ်ႈဢၼ်တုၵ်းယွၼ်းမႃးၼၼ်ႉ မၼ်းဢမ်ႇပႃးဝႆႉႁူဝ်ၶေႃႈမၼ်း ဢမ်ႇၼၼ် မၼ်းတေပႃးဝႃႈ ၸိုဝ်ႈဢၼ်ပဵၼ် လွၵ်းပဝ်ႇဝႆႉၼၼ်ႉၵူၺ်း။",
+ "title-invalid-utf8": "ႁူဝ်ၶေႃႈ ၼႃႈလိၵ်ႈ ဢၼ်တုၵ်းယွၼ်းဝႆႉၼႆႉ မၼ်းပႃးဝႆႉ သၢႆသဵၼ်ႈ UTF-8 ဢၼ်ဢမ်ႇပဵၼ်လႆႈ။",
+ "title-invalid-interwiki": "ႁူဝ်ၶေႃႈ ၼႃႈလိၵ်ႈ ဢၼ်တုၵ်းယွၼ်းမႃးၼၼ်ႉ မၼ်းပႃးဝႆႉ ႁဵင်းၵွင်ႉ တူဝ်ၼႂ်းဝီႇၶီႇ ဢၼ်ဢမ်ႇၸၢင်ႈဢဝ်ၸႂ်ႉလႆႈ တႃႇႁူဝ်ၶေႃႈ။",
+ "title-invalid-talk-namespace": "ႁူဝ်ၶေႃႈၼႃႈလိၵ်ႈ ဢၼ်တုၵ်းယွၼ်းမႃးၼၼ်ႉ မၼ်းမၢႆထိုင်ၸူး ၼႃႈလိၵ်ႈဢုပ်ႇဢူဝ်း ဢၼ်ဢမ်ႇၸၢင်ႈ မီးလႆႈၼၼ်ႉ။",
+ "title-invalid-characters": "ႁူဝ်ၶေႃႈ ၼႃႈလိၵ်ႈ ဢၼ်တုၵ်းယွၼ်းမႃးၼၼ်ႉ မၼ်းၶဝ်ႈပႃးဝႆႉ တူဝ်လိၵ်ႈ ဢၼ်ဢမ်ႇ ၸႂ်ႉလႆႈ : \"$1\"",
+ "viewsource": "တူၺ်း ငဝ်ႈငႃႇ",
+ "viewsource-title": "တူၺ်းငဝ်ႈငႃႇ တွၼ်ႈတႃႇ $1",
+ "protectedpagetext": "ၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇႁႄႉၵင်ႈဝႆႉ တႃႇၵႅတ်ႇၶႄ လွင်ႈမူၼ်ႉမႄး ဢမ်ႇၼၼ် လွင်ႈႁဵတ်းသၢင်ႈ တၢင်ႇၸိူဝ်း",
+ "viewsourcetext": "ၸဝ်ႈၵဝ်ႇ ၸၢင်ႈတူၺ်း သေ ထုတ်ႇဢဝ်လႆႈ ငဝ်ႈငႃႇ တႃႇၼႃႈလိၵ်ႈၼႆႉ",
+ "viewyourtext": "ၸဝ်ႈၵဝ်ႇ ၸၢင်ႈတူၺ်းသေ ထုတ်ႇဢဝ်လႆႈ ငဝ်ႈငႃႇ တွၼ်ႈတႃႇ <strong>လွင်ႈမႄးထတ်းၸဝ်ႈၵဝ်ႇ</strong> ၸူး ၼႃႈလိၵ်ႈၼႆႉ",
+ "translateinterface": "တႃႇတေထႅမ်သႂ်ႇ ဢမ်ႇၼၼ် မႄးလႅၵ်ႈလၢႆႈ လွင်ႈပိၼ်ႇၽႃႇသႃႇ တႃႇ ဝီႇၶီႇၼႆ ၶႅၼ်းတေႃႈ ၸႂ်ႉပၼ် [//translatewiki.net/ translatewiki.net] ဢၼ်ပဵၼ် ၼႃႈၵၢၼ် ပိၼ်ႇၽႃႇသႃႇ မီႇတီႇယႃႇဝီႇၶီႇ ၼႆႉၶႃႈ။",
+ "namespaceprotected": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇမီးသုၼ်ႇၶႂၢင်းပၼ် တႃႇတေမႄးထတ်း ၼႃႈလိၵ်ႈၸိူဝ်းၼႆႉ ၵႃႈတီႈၼႂ်း <strong>$1</strong> ၸိုဝ်ႈၼႆႉ။",
+ "customcssprotected": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇမီးသုၼ်ႇၶႂၢင်းပၼ် တွၼ်ႈတႃႇမႄးထတ်း ၼႃႈလိၵ်ႈ CSS ဢၼ်ၼႆႉ။ ယွၼ်ႉပိူဝ်ႈဝႃႈ မၼ်းပႃးဝႆႉ ၵၢၼ်တင်ႈ လွင်ႈသုၼ်ႇတူဝ် ၽူႈၸႂ်ႉတိုဝ်းတၢင်ႇၵေႃႉဢေႃႈ။",
+ "customjsprotected": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇမီးသုၼ်ႇၶႂၢင်းပၼ် တွၼ်ႈတႃႇမႄးထတ်း ၼႃႈလိၵ်ႈ JavaScript ဢၼ်ၼႆႉ။ ယွၼ်ႉပိူဝ်ႈဝႃႈ မၼ်းပႃးဝႆႉ ၵၢၼ်တင်ႈ လွင်ႈသုၼ်ႇတူဝ် ၽူႈၸႂ်ႉတိုဝ်းတၢင်ႇၵေႃႉဢေႃႈ။",
+ "mycustomcssprotected": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇမီးသုၼ်ႇၶႂၢင်းပၼ် တွၼ်ႈတႃႇမႄးထတ်း ၼႃႈလိၵ်ႈ CSS ဢၼ်ၼႆႉ။",
+ "mycustomjsprotected": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇမီးသုၼ်ႇၶႂၢင်းပၼ် တွၼ်ႈတႃႇမႄးထတ်း ၼႃႈလိၵ်ႈ JavaScript ဢၼ်ၼႆႉ။",
+ "ns-specialprotected": "ၼႃႈလိၵ်ႈၶိုၵ်ႉတွၼ်းၸိူဝ်းၼႆႉ တေဢမ်ႇၸၢင်ႈ မႄးထတ်းလႆႈ",
+ "titleprotected": "ႁူဝ်ၶေႃႈဢၼ်ၼႆႉၼႆႉ ထုၵ်ႇ ၽူႈၸႂ်ႉတိုဝ်း [[User:$1|$1]] ၵေႃႉၼႆႉ ႁႄႉၵင်ႈဝႆႉ။ လွင်ႈတၢင်း ဢၼ်မၼ်းပၼ်ဝႆႉတႄႉ <em>$2</em>.",
+ "exception-nologin": "ဢမ်ႇလႆႈၶဝ်ႈဝႆ့",
+ "cannotlogoutnow-title": "ဢမ်ႇၸၢင်ႈ လွၵ်ႉဢွၵ်ႇ ယၢမ်းလဵဝ်",
+ "cannotlogoutnow-text": "တေဢမ်ႇၸၢင်ႈ လွၵ်ႉၶဝ်ႈ ၽွင်းမိူဝ်ႈၸႂ်ႉ $1",
+ "welcomeuser": "ႁပ်ႉတွၼ်ႈယူႇ, $1!",
+ "welcomecreation-msg": "ဢၶွင်ႉၸဝ်ႈၵဝ်ႇၼႆႉ ထုၵ်ႇၵေႃႇသၢင်ႈၵႂႃႇယဝ်ႉ။\nပေႃးၸဝ်ႈၵဝ်ႇ မီးၵၢင်ၸႂ်ၼႆ ၸဝ်ႈၵဝ်ႇၸၢင်ႈလႅၵ်ႈလၢႆး {{SITENAME}} [[Special:Preferences|preferences]] လႆႈယူႇ။",
+ "yourname": "ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း",
+ "userlogin-yourname": "ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း",
+ "userlogin-yourname-ph": "ပေႃႇသႂ်ႇပၼ် ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း ၸဝ်ႈၵဝ်ႇ",
+ "createacct-another-username-ph": "ပေႃႇသႂ်ႇပၼ် ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း",
+ "yourpassword": "ၶေႃႈလပ်ႉ",
+ "userlogin-yourpassword": "ၶေႃႈလပ်ႉ",
+ "userlogin-yourpassword-ph": "ပေႃႉသႂ်ႇၶေႃႈလပ်ႉ",
+ "createacct-yourpassword-ph": "ပေႃႉသႂ်ႇၶေႃႈလပ်ႉ",
+ "yourpasswordagain": "ၶိုၼ်းပေႃႉပၼ် ၶေႃႈလပ်ႉ :",
+ "createacct-yourpasswordagain": "ၼႄႉၼွၼ်းပၼ် ၶေႃႈလပ်ႉ",
+ "createacct-yourpasswordagain-ph": "ပေႃႉသႂ်ႇၶေႃႈလပ်ႉထႅင်ႈၵမ်းၼိုင်ႈ",
+ "remembermypassword": "တွင်းဝႆႉပၼ် လွၵ်ႉဢိၼ်ႇၵဝ်ၶႃႈ တီႈၼႂ်း ၶိူင်ႈပိုတ်ႇဝႆႉၼႆႉ (တီႈႁိုင်ႁိုင်မၼ်း $1 {{PLURAL:$1|ၼိုင်ႈဝၼ်း|ဝၼ်း}})",
+ "userlogin-remembermypassword": "သိုပ်ႇဢဝ်ၵဝ်ၶႃႈ လွၵ်ႉဢိၼ်ႇဝႆႉလႄႈ",
+ "userlogin-signwithsecure": "ၸႂ်ႉၵွင်ႉသၢၼ် ႁူမ်ႇလူမ်ႈ",
+ "cannotloginnow-title": "ဢမ်ႇၸၢင်ႈၶဝ်ႈ လွၵ်ႉဢိၼ်ႇ ယၢမ်းလဵဝ်",
+ "cannotloginnow-text": "တေဢမ်ႇၸၢင်ႈ လွၵ်ႉၶဝ်ႈ ၽွင်းမိူဝ်ႈၸႂ်ႉ $1",
+ "yourdomainname": "တူဝ်ႇမဵင်း ၸဝ်ႈၵဝ်ႇ :",
+ "password-change-forbidden": "ၸဝ်ႈၵဝ်ႇတေဢမ်ႇၸၢင်ႈ လႅၵ်ႈလၢႆႈ ၶေႃႈလပ်ႉ ၵႃႈတီႈၼိူဝ် ဝီႇၶီႇၼႆႉ",
+ "login": "လွၵ်ႉဢိၼ်ႇ",
+ "login-security": "ၼႄႉၼွၼ်း မၢႆၽၢင်ၸဝ်ႈၵဝ်ႇ",
+ "nav-login-createaccount": "လွၵ်ႉဢိၼ်ႇ / သၢင်ႈဢၶွင်ႉ",
+ "userlogin": "လွၵ်ႉဢိၼ်ႇ / သၢင်ႈဢၶွင်ႉ",
+ "userloginnocreate": "လွၵ်ႉဢိၼ်ႇ",
+ "logout": "လွၵ်ႉဢဝ်ႉ",
+ "userlogout": "လွၵ်ႉဢဝ်ႉ",
+ "notloggedin": "ဢမ်ႇလႆႈၶဝ်ႈဝႆ့",
+ "userlogin-noaccount": "ပႆႇပႃႈမီးဢၶွင်ႉႁႃႉ?",
+ "userlogin-joinproject": "ႁူမ်ႈ {{SITENAME}}",
+ "nologin": "ပႆႇပႃႈမီးဢၶွင်ႉႁႃႉ? $1",
+ "nologinlink": "ၵေႃႇသၢင်ႈဢၶွင်ႉ",
+ "createaccount": "ႁဵတ်းဢၶွင်ႉ",
+ "gotaccount": "မီးဢၶွင်ႉဝႆႉယဝ်ႉႁႃႉ? $1",
+ "gotaccountlink": "လွၵ်ႉဢိၼ်ႇ",
+ "userlogin-resetlink": "လိုမ်းပႅတ်ႈၵႂႃႇ ႁူဝ်ယွႆႈ လွၵ်ႉဢိၼ်ႉၸဝ်ႈၵဝ်ႇယဝ်ႉႁႃႉ?",
+ "userlogin-resetpassword-link": "လိုမ်းၵႂႃႇ ၶေႃႈလပ်ႉၸဝ်ႈၵဝ်ႇႁႃႉ?",
+ "userlogin-helplink2": "ၸွႆႈထႅမ်တင်း ၶဝ်ႈလွၵ်ႉဢိၼ်ႇ",
+ "userlogin-loggedin": "ၸဝ်ႈၵဝ်ႇပေႃး ၶဝ်ႈၸႂ်ႉဝႆႉ ၼင်ႇ{{GENDER:$1|$1}} ယဝ်ႈ။\nၸႂ်ႉပၼ် လၢႆးၼင်ႇပႃႈတႂ်ႈၼႆႉသေ လွၵ်ႉဢိၼ်ႇၼင်ႇ ၽူႈၸႂ်ႉတိုဝ်းတၢင်ႇၵေႃႉ",
+ "userlogin-reauth": "ၸဝ်ႈၵဝ်ႇတေလႆႈ လွၵ်ႉဢိၼ်ႇထႅင်ႈၵမ်းၼိုင်ႈသေ တႃႇၼႄႉၼွၼ်းဝႃႈ ၸဝ်ႈၵဝ်ႇၼႆႉ ပဵၼ် {{GENDER:$1|$1}}.",
+ "userlogin-createanother": "ၵေႃႇသၢင်ႈဢၶွင်ႉ တၢင်ႇဢၼ်",
+ "createacct-emailrequired": "ႁဵင်းလိၵ်ႈ ဢီးမေးလ်",
+ "createacct-emailoptional": "ႁဵင်းလိၵ်ႈဢီးမေး (သႂ်ႇၵေႃႈလႆႈ၊ ဢမ်ႇသႂ်ႇၵေႃႈလႆႈ)",
+ "createacct-email-ph": "ပေႃႉသႂ်ႇပၼ် ႁဵင်းလိၵ်ႈ ဢီးမေးၸဝ်ႈၵဝ်ႇ",
+ "createacct-another-email-ph": "ပေႃႉသႂ်ႇပၼ် ႁဵင်းလိၵ်ႈ ဢီးမေးလ်",
+ "createaccountmail": "ၸႂ်ႉပၼ် ၶေႃႈလပ်ႉၸူဝ်ႈၵႅပ်ႉ သူင်ႇၼၼ်ႉၵႂႃႇၸူး ႁဵင်းလိၵ်ႈဢီးမေးလ် ဢၼ်မၵ်းမၼ်ႈဝႆႉ ပၼ်ၼၼ်ႉ။",
+ "createacct-realname": "ၸိုဝ်ႈတႄႉတႄႉ (ဢဝ်ၸႂ်ဝႃႈ)",
+ "createaccountreason": "လွင်ႈတၢင်း :",
+ "createacct-reason": "လွင်ႈတၢင်း :",
+ "createacct-reason-ph": "ယွၼ်ႉပိူဝ်ႈသင်လႄႈ ၸဝ်ႈၵဝ်ႇ ၵေႃႇသၢင်ႈဢၶွင်ႉတၢင်ႇဢၼ်",
+ "createacct-reason-help": "ၶေႃႈၶၢဝ်ႇၼႄဝႆႉ ၵႃႈတီႈၼႂ်း သဵၼ်ႈမၢႆၵေႃႇသၢင်ႈ ဢၶွင်ႉ",
+ "createacct-submit": "ၵေႃႇသၢင်ႈ ဢၶွင်ႉၸဝ်ႈၵဝ်ႇ",
+ "createacct-another-submit": "ၵေႃႇသၢင်ႈဢၶွင်ႉ",
+ "createacct-continue-submit": "သိုပ်ႇၼႃႈ ၵၢၼ်ၵေႃႇသၢင်ႈ ဢၶွင်ႉ",
+ "createacct-another-continue-submit": "သိုပ်ႇၼႃႈ ၵၢၼ်ၵေႃႇသၢင်ႈ ဢၶွင်ႉ",
+ "createacct-benefit-heading": "{{SITENAME}} ၵူၼ်းၼင်ႇၸဝ်ႈၵဝ်ႇ ၵေႃႉႁဵတ်းဝႆႉ",
+ "createacct-benefit-body1": "{{PLURAL:$1|edit|မႄးထတ်း}}",
+ "createacct-benefit-body2": "{{PLURAL:$1|page|ၼႃႈလိၵ်ႈ}}",
+ "createacct-benefit-body3": "မိူဝ်ႈဢၼ်ပႆႇပေႃးႁိုင် {{PLURAL:$1|contributor|ၽူႈၶဝ်ႈႁူမ်ႈ}}",
+ "badretype": "ၶေႃႈလပ်ႉ ဢၼ်ၸဝ်ႈၵဝ်ႇပေႃႉသႂ်ႇၼၼ်ႉ မၼ်းဢမ်ႇၶူပ်းၵၼ်",
+ "usernameinprogress": "ၵၢၼ်ၵေႃႇသၢင်ႈ ဢၶွင်ႉတွၼ်ႈတႃႇ ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်းၵေႃႉၼႆႉ တိုၵ်ႉႁဵတ်းၵၢၼ်ဝႆႉယူႇ။ ၶႅၼ်းတေႃႈပႂ်ႉပၼ်ၵမ်းၼိုင်ႈ။",
+ "userexists": "ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း ဢၼ်ပေႃႉသႂ်ႇဝႆႉၼၼ်ႉ မၼ်းထုၵ်ႇၸႂ်ႉဝႆႉယဝ်ႉ။\nၶႅၼ်းတေႃႈ လိူၵ်ႈပၼ် ၸိုဝ်ႈတၢင်ႇဢၼ်ၶႃႈလႄႈ။",
+ "loginerror": "လွၵ်ႉဢိၼ်ႇ ၽိတ်းပိူင်ႈ",
+ "createacct-error": "ၵၢၼ်ၵေႃႇသၢင်ႈ ဢၶွင်ႉ ၽိတ်းပိူင်ႈ",
+ "createaccounterror": "ဢမ်ႇၸၢင်ႈၵေႃႇသၢင်ႈ ဢၶွင်ႉ : $1",
+ "noname": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇလႆႈ မၵ်းမၼ်ႈဝႆႉပၼ် ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း ဢၼ်ၸႂ်ႉလႆႈ။",
+ "loginsuccesstitle": "လွၵ်ႉဢိၼ်ႇဝႆႉယဝ်ႉ",
+ "loginsuccess": "<strong>ၸဝ်ႈၵဝ်ႇ လွၵ်ႉဢိၼ်ႇၶဝ်ႈၸူး {{SITENAME}} ၼင်ႇ \"$1\".</strong> ယဝ်ႉဢေႃႈ ယၢမ်းလဵဝ်",
+ "nosuchusershort": "ဢၼ်ပဵၼ်ၸိုဝ်ႈ ၽူႈၸႂ်ႉတိုဝ်း \"$1\" ဢၼ်ၼႆႉ မၼ်းဢမ်ႇမီး။\nမႄးၵူတ်ႇတူၺ်း တူဝ်လိၵ်ႈမၼ်းလီလီလႄႈ။",
+ "nouserspecified": "ၸဝ်ႈၵဝ်ႇ ထုၵ်ႇလီမၵ်းမၼ်ႈ ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း",
+ "login-userblocked": "ၽူႈၸႂ်ႉတိုဝ်းၵေႃႉၼႆႉ ထုၵ်ႇႁႄႉတတ်းဝႆႉ။ ဢမ်ႇမီးသုၼ်ႇတႃႇ လွၵ်ႉဢိၼ်ႇ",
+ "wrongpassword": "ၶေႃႈလပ်ႉဢၼ်ပေႃႉသႂ်ႇ ၽိတ်းပိူင်ႈဝႆႉ။\nၶတ်းၸႂ်တူၺ်းထႅင်ႈၵမ်းၼိုင်ႈ။",
+ "wrongpasswordempty": "ၶေႃႈလပ်ႉဢၼ်ပေႃႉသႂ်ႇၵႂႃႇၼၼ်ႉ မၼ်းပဵၼ်လွၵ်းပဝ်ႇဝႆႉ။\nၶတ်းၸႂ်တူၺ်း ထႅင်ႈၵမ်းၼိုင်ႈလႄႈ။",
+ "passwordtooshort": "ၶေႃႈလပ်ႉၼႆႉ တီႈဢေႇသုတ်းမၼ်း တေလႆႈမီး {{PLURAL:$1|1 တူဝ်|$1 တူဝ်}}.",
+ "passwordtoolong": "ၶေႃႈလပ်ႉၼႆႉ တေဢမ်ႇလႆႈ ယၢဝ်းပူၼ်ႉလိူဝ် {{PLURAL:$1|1 တူဝ်|$1 တူဝ်}}.",
+ "passwordtoopopular": "ၶေႃႈလပ်ႉၸိူဝ်းၵူၼ်းၸႂ်ႉၼမ်ၼၼ်ႉ တေဢမ်ႇၸၢင်ႈဢဝ်ၸႂ်ႉ။ ၶႅၼ်းတေႃႈ လိူၵ်ႈပၼ် ၶေႃႈလပ်ႉ ဢၼ်ပႅၵ်ႇပိူၼ်ႈၼၼ်ႉလႄႈ။",
+ "password-name-match": "ၶေႃႈလပ်ႉၸဝ်ႈၵဝ်ႇၼႆႉ တေလႆႈပႅၵ်ႇပိူင်ႈၵၼ်တင်း ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်းၸဝ်ႈၵဝ်ႇ။",
+ "password-login-forbidden": "လွင်ႈဢဝ်ၸႂ်ႉ ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း ဢၼ်ၼႆႉလႄႈ ၶေႃႈလပ်ႉဢၼ်ၼႆႉၼႆႉ ထုၵ်ႇႁၢမ်ႈသီး ဝႆႉဢေႃႈ။",
+ "mailmypassword": "ၶိုၼ်းမႄးတင်ႈ ၶေႃႈလပ်ႉ",
+ "passwordremindertitle": "ၶေႃႈလပ်ႉၸူဝ်ႈၵႅပ်ႉ ဢၼ်မႂ်ႇ တွၼ်ႈတႃႇ {{SITENAME}}",
+ "noemail": "ဢမ်ႇမီးႁဵင်းလိၵ်ႈဢီးမေးလ် ဢၼ်မၢႆတွင်းဝႆႉတႃႇ ၽူႈၸႂ်ႉတိုဝ်း \"$1\" ၼႆႉ",
+ "noemailcreate": "ၸဝ်ႈၵဝ်ႇ တေလႆႈသႂ်ႇပၼ်ႇ ႁဵင်းလိၵ်ႈဢီးမေးလ် ဢၼ်ၸၢင်ႈၸႂ်ႉလႆႈၼၼ်ႉ။",
+ "passwordsent": "ၶေႃႈလပ်ႉဢၼ်မႂ်ႇ ထုၵ်ႇလႆႈသူင်ႇၵႂႃႇၸူး ႁဵင်းလိၵ်ႈဢီးမေးလ် ဢၼ်တၢင်ႇမၢႆၽၢင်ႇဝႆႉ တႃႇ \"$1\" ။\nပေႃးဝႃႈ ႁပ်ႉလႆႈယဝ်ႉၼႆ ၶႅၼ်းတေႃႈ လွၵ်ႉဢိၼ်ႇၶဝ်ႈၸူး ထႅင်ႈၵမ်းၼိုင်ႈၶႃႈ။",
+ "blocked-mailpassword": "ႁဵင်းလိၵ်ႈ ဢၢႆႇပီႇ IP ၸဝ်ႈၵဝ်ႇၼၼ်ႉ ထုၵ်ႇႁႄႉတတ်းဝႃႈ တႃႇတေ မႄးထတ်း။ လႆႈႁႄႉၵင်ႈဝႆႉ တွၼ်ႈတႃႇ ယႃႇႁႂ်းမီး လွင်ႈလူလၢႆၵၼ်လႄႈ လုၵ်ႉတီႈ မၢႆဢၢႆႇပီႇ IP ၼႆႉသေ တေဢမ်ႇၸၢင်ႈ ဢဝ်ၶိုၼ်းလႆႈ မၢႆလပ်ႉ။",
+ "eauthentsent": "ဢီးမေးလ်ၶေႃႈၼႄႉၼွၼ်း ၼၼ်ႉ ထုၵ်ႇသူင်ႇၵႂႃႇၸူးတီႈ ႁဵင်းလိၵ်ႈဢီးမေးလ် ဢၼ်လႆႈ မၵ်းမၼ်ႈပၼ်ဝႆႉၼၼ်ႉယဝ်ႉ။ မိူဝ်ႈဢီးမေးလ်တၢင်ႇဢၼ် ပႆႇတၼ်းသူင်ႇၶဝ်ႈမႃး ၸူးတီႈဢၶွင်ႉဢၼ်ၼႆႉၼႆႉ ၸဝ်ႈၵဝ်ႇ ထုၵ်ႇလီႁဵတ်းၸွမ်းၼင်ႇ ၶေႃႈၸီႉသင်ႇ ဢၼ်ပႃး ၵႃႈတီႈၼႂ်း ဢီးမေးလ်ၼၼ်ႉယူႇ။ ၼၼ်ႉမၼ်းပဵၼ်တႃႇၼႄႉၼွၼ်းဝႃႈ ဢၶွင်ႉဢၼ်ၼႆႉ မၼ်းပဵၼ်ႁင်းၸဝ်ႈၵဝ်ႇယူႇတႄႉ ၼႆဢေႃႈ။",
+ "throttled-mailpassword": "ဢီးမေးလ်တႃႇ ၶိုၼ်းတင်ႈၶေႃႈလပ်ႉၼႆႉ ထုၵ်ႇသူင်ႇၵႂႃႇ မိူဝ်ႈပူၼ်ႉမႃး\n{{PLURAL:$1|မူင်း|$1 မူင်း}}.\nတွၼ်ႈတႃႇႁႄႉၵင်ႈ လွင်ႈလူလၢႆၵၼ်ၼႆ ၼႂ်းၵႃႈ \n{{PLURAL:$1| ၸူဝ်ႈမူင်း|$1 ၸူဝ်ႈမူင်း}} တေသူင်ႇပၼ် ဢီးမေးလ် ၶိုၼ်းတင်ႈၶေႃႈလပ်ႉ ၼိုင်ႈပွၵ်ႈၵူၺ်း။",
+ "mailerror": "လွင်ႈသူင်ႇ ဢီးမေးလ် ၽိတ်းပိူင်ႈ : $1",
+ "emailauthenticated": "ႁဵင်းလိၵ်ႈ ဢီးမေးလ်ၸဝ်ႈၵဝ်ႇၼႆႉ ထုၵ်ႇၼႄႉၼွၼ်း မိူဝ်ႈ ဝၼ်းထီႉ $2 ၶၢဝ်းယၢဝ်း $3",
+ "emailnotauthenticated": "ႁဵင်းလိၵ်ႈ ဢီးမေးလ်ၸဝ်ႈၵဝ်ႇ ၼႆႉ ဢမ်ႇပႆႇလႆႈ ၼႄႉၼွၼ်း။\nဢီးမေးလ် တွၼ်ႈတႃႇ ၽၢင်ႈႁၢင်ႈၵၢၼ် ၸွမ်းၼင်ႇၼႄဝႆႉၼၼ်ႉတႄႉ တေဢမ်ႇသူင်ႇ ပၼ်သေဢၼ်။",
+ "noemailprefs": "တႃႇႁႂ်ႈ ၽၢင်ႁၢင်ႈၵၢၼ်ၸိူဝ်းၼႆႉ ႁဵတ်းၵၢၼ်ပၼ်ၼႆ ၵႂႃႇမၵ်းမၼ်ႈပၼ် ႁဵင်းလိၵ်ႈ ဢီးမေးလ် ၵႃႈတီႈ ငဝ်ႈၵုမ်းပိူင် ၸဝ်ႈၵဝ်ႇၼၼ်ႉလႄႈ။",
+ "emailconfirmlink": "ၼႄႉၼွၼ်း ႁဵင်းလိၵ်ႈ ဢီးမေးလ်ၸဝ်ႈၵဝ်ႇ။",
+ "cannotchangeemail": "ႁဵင်းလိၵ်ႈဢီးမေး ဢၶွင်ႉၼႆႉ တေဢမ်ႇၸၢင်ႈ လႅၵ်ႈလၢႆႈလႆႈ ၵႃႈတီႈဝီႇၶီႇၼႆႉ။",
+ "emaildisabled": "သၢႆႉဢၼ်ၼႆႉ တေဢမ်ႇၸၢင်ႈသူင်ႇလႆႈ ဢီးမေးလ်",
+ "accountcreated": "ၵေႃႇသၢင်ႈ ဢၶွင်ႉ ယဝ်ႉယဝ်ႈ",
+ "accountcreatedtext": "ဢၶွင်ႉ ၽူႈၸႂ်ႉတိုဝ်း တွၼ်ႈတႃႇ [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|talk]]) ၼႆႉ ထုၵ်ႇၵေႃႇသၢင်ႈယဝ်ႉယဝ်ႈ။",
+ "createaccount-title": "ၵေႃႇသၢင်ႈဢၶွင်ႉ တွၼ်ႈတႃႇ {{SITENAME}}",
+ "login-abort-generic": "ၸဝ်ႈၵဝ်ႇ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇ ဢမ်ႇၶႅမ်ႉလႅၵ်ႈ - မၼ်းလႆႈ ယင်ႉၵိုတ်ႈၵႂႃႇယဝ်ႉ။",
+ "login-migrated-generic": "ဢၶွင်ႉၸဝ်ႈၵဝ်ႇၼႆႉ ထုၵ်ႇလႆႈ ၶၢႆႉၵႂႃႇတၢင်ႇတီႈယဝ်ႉ။ ယဝ်ႉၵေႃႈ ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း ၸဝ်ႈၵဝ်ႇၼႆႉ မၼ်းဢမ်ႇသိုပ်ႇမီးဝႆႉ ၵႃႈတီႈ ဝီႇၶီႇၼႆႉယဝ်ႈ။",
+ "loginlanguagelabel": "ၽႃႇသႃႇၵႂၢမ်း: $1",
+ "pt-login": "လွၵ်ႉဢိၼ်ႇ",
+ "pt-login-button": "လွၵ်ႉဢိၼ်ႇ",
+ "pt-login-continue-button": "သိုပ်ၶဝ်ႈလွၵ်ႉဢိၼ်ႇ",
+ "pt-createaccount": "ၵေႃႇသၢင်ႈဢၶွင်ႉ",
+ "pt-userlogout": "လွၵ်ႉဢဝ်ႉ",
+ "php-mail-error-unknown": "ဢမ်ႇႁူႉ လွင်ႈၽိတ်းပိူင်ႈ ၵႃႈတီႈ PHP's mail() function ၼၼ်ႉ။",
+ "user-mail-no-addy": "ဢမ်ႇပႃး ႁဵင်းလိၵ်ႈဢီးမေးလ်သေ ၶတ်းၸႂ်သူင်ႇ ဢီးမေးလ်",
+ "user-mail-no-body": "ၶတ်းၸႂ်သူင်ႇဢီးမေးလ် လူၺ်ႈ လွင်ႈတၢင်းပဝ်ႇ ဢမ်ႇၼၼ် ပွင်ႈလိၵ်ႈ ဢၼ်ဢမ်ႇမီး တီႈပွင်ႇ",
+ "changepassword": "လႅၵ်ႈလၢႆႈ ၶေႃႈလပ်ႉ",
+ "resetpass_announce": "တႃႇႁႂ်ႈ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇယဝ်ႉတူဝ်ႈၼႆ ၸဝ်ႈၵဝ်ႇ တေလႆႈမၵ်းသႂ်ႇပၼ် ၶေႃႈလပ်ႉဢၼ်မႂ်ႇ",
+ "resetpass_header": "လႅၵ်ႈလၢႆႈ ၶေႃႈလပ်ႉဢၶွင်ႉ",
+ "oldpassword": "ၶေႃႈလပ်ႉဢၼ်ၵဝ်ႇ",
+ "newpassword": "ၶေႃႈလပ်ႉဢၼ်မႂ်ႇ",
+ "retypenew": "ၶိုၼ်းပေႃႉပၼ် ၶေႃႈလပ်ႉ ဢၼ်မႂ်ႇ :",
+ "resetpass_submit": "မၵ်းသႂ်ႇ ၶေႃႈလပ်ႉ လႄႈ လွၵ်ႉဢိၼ်ႇ",
+ "changepassword-success": "ၶေႃႈလပ်ႉၸဝ်ႈၵဝ်ႇ လႅၵ်ႈလၢႆႈၵႂႃႇယဝ်ႉ!",
+ "changepassword-throttled": "ၸဝ်ႈၵဝ်ႇ ႁႃၶဝ်ႈ လွၵ်ႉဢိၼ် လၢႆပွၵ်ႈၼႅၼ်ႇယဝ်ႉ။\nမိူဝ်ႈပႆႇၶတ်းၸႂ်ၶဝ်ႈတူၺ်းထႅင်ႈၼၼ်ႉ ၶႅၼ်းတေႃႈ ပႂ်ႉပၼ် $1 ။",
+ "botpasswords": "ၶေႃႈလပ်ႉ ပွတ်ႉ",
+ "botpasswords-disabled": "ၶေႃႈလပ်ႉပွတ်ႉၼၼ်ႉ ဢမ်ႇၸႂ်ႉလႆႈယဝ်ႉဝႃႈ",
+ "botpasswords-no-central-id": "တႃႇတေၸႂ်ႉ ၶေႃႈလပ်ႉပွတ်ႉၼၼ်ႉ ၸဝ်ႈၵဝ်ႇ တေလႆႈ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇ ဢၼ်ပဵၼ် ဢၶွင်ႉ ၽုင်ႇၼၼ်ႉဢေႃႈ။",
+ "botpasswords-existing": "ၶေႃႈလပ်ႉပွတ်ႉ ဢၼ်မီးယူႇယၢမ်းလဵဝ်",
+ "botpasswords-createnew": "ၵေႃႇသၢင်ႈ ၶေႃႈလပ်ႉပွတ်ႉ ဢၼ်မႂ်ႇ",
+ "botpasswords-editexisting": "မႄးထတ်း ၶေႃႈလပ်ႉပွတ်ႉ ဢၼ်တိုၵ်ႉမီးယူႇ ယၢမ်းလဵဝ်",
+ "botpasswords-label-appid": "ၸိုဝ်ႈ ပွတ်ႉ :",
+ "botpasswords-label-create": "ၵေႃႇသၢင်ႈ",
+ "botpasswords-label-update": "ဢၢပ်ႉတိတ်ႉ",
+ "botpasswords-label-cancel": "ဢမ်ႇႁဵတ်း",
+ "botpasswords-label-delete": "ယႃႉ",
+ "botpasswords-label-resetpassword": "ၶိုၼ်းမႄးတင်ႈ ၶေႃႈလပ်ႉ",
+ "botpasswords-bad-appid": "ၸိုဝ်ႈပွတ်ႉ \"$1\" ၼႆႉ ဢမ်ႇၸႂ်ႉလႆႈ။",
+ "botpasswords-insert-failed": "တႃႇထႅမ်သႂ်ႇၸႂ်ႉ ပွတ်ႉ \"$1\" ၼႆ့ ဢမ်ႇၶႅမ်ႉလႅပ်ႈ။ သႂ်ႇဝႆႉယဝ်ႉႁႃႈ ဝႃႈလႃး?",
+ "botpasswords-update-failed": "တႃႇႁဵတ်း ဢၢပ်ႉတိတ်ႉ ၸိုဝ်ႈပွတ်ႉ \"$1\" ၼႆႉ ဢမ်ႇၶႅမ်ႉလႅပ်ႈ။ မွတ်ႇပႅတ်ႈမၼ်းယဝ်ႉႁႃႈ ဝႃႈလႃး?",
+ "botpasswords-created-title": "ၶေႃႈလပ်ႉပွတ်ႉ ၵေႃႇသၢင်ႈယဝ်ႉယဝ်ႈ။",
+ "botpasswords-created-body": "ၶေႃႈလပ်ႉပွတ်ႉ တွၼ်ႈတႃႇ ၸိုဝ်ႈပွတ်ႉ \"$1\" ဢၼ်ပဵၼ်ၶွင် ၽူႈၸႂ်ႉတိုဝ်း \"$2\" ၼၼ်ႉ ထုၵ်ႇၵေႃႇသၢင်ႈ ယဝ်ႉယဝ်ႈ။",
+ "botpasswords-updated-title": "ၶေႃႈလပ်ႉ ပွတ်ႉ ပဵၼ်ဢၢပ်ႉတိတ်ႉယဝ်ႈ။",
+ "botpasswords-updated-body": "ၶေႃႈလပ်ႉပွတ်ႉ တွၼ်ႈတႃႇ ၸိုဝ်ႈပွတ်ႉ \"$1\" ဢၼ်ပဵၼ်ၶွင် ၽူႈၸႂ်ႉတိုဝ်း \"$2\" ၼၼ်ႉ ပဵၼ် ဢၢပ်ႉတိတ်ႉယဝ်ႈ။",
+ "botpasswords-deleted-title": "ၶေႃႈလပ်ႉပွတ်ႉၼၼ်ႉ မွတ်ႇပႅတ်ႈယဝ်ႉယဝ်ႈ။",
+ "botpasswords-deleted-body": "ၶေႃႈလပ်ႉပွတ်ႉ တွၼ်ႈတႃႇ ၸိုဝ်ႈပွတ်ႉ \"$1\" ဢၼ်ပဵၼ်ၶွင် ၽူႈၸႂ်ႉတိုဝ်း \"$2\" ၼၼ်ႉ မွတ်ႇပႅတ်ႈယဝ်ႉယဝ်ႈ။",
+ "botpasswords-newpassword": "ၶေႃႈလပ်ႉဢၼ်မႂ်ႇ တႃႇတေၶဝ်ႈ လွၵ်ႉဢိၼ်ႇၸွမ်း <strong>$1</strong> ပဵၼ် <strong>$2</strong>. <em>ၶႅၼ်းတေႃႈ မၢႆတွင်းၼႆႉဝႆႉ တွၼ်ႈတႃႇ ပဵၼ် ၽိုၼ်ဢိင်မိူဝ်းၼႃႈ</em>",
+ "botpasswords-no-provider": "ၵၼ်တူဝ်ၵမ်ႉထႅမ်ၶေႃႈလပ်ႉပွတ်ႉၼႆ မၼ်းဢမ်ႇၸႂ်ႉလႆႈ။",
+ "botpasswords-restriction-failed": "ၵၼ်ၵႅတ်ႇၶေႃႈလပ်ႉပွတ်ႉ ၼႆႉ ႁႄႉၵင်ႈလွင်ႈ လွၵ်ႉဢိၼ်ႇဢၼ်ၼႆႉ။",
+ "botpasswords-invalid-name": "ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်ႈ ဢၼ်မၵ်းမၼ်ႈဝႆႉၼႆႉ မၼ်းဢမ်ႇၶဝ်ႈပႃးဝႆႉ တူဝ်ၸႅၵ်ႇၶေႃႈလပ်ႉ ပွတ်ႉ (\"$1\") ။",
+ "botpasswords-not-exist": "ၽူႈၸႂ်ႉတိုဝ်း \"$1\" ၼႆႉမၼ်းဢမ်ႇမီး ၶေႃႈလပ်ႉပွတ်ႉ ဢၼ်လႆႈၸိုဝ်ႈဝႃႈ \"$2\" ။",
+ "resetpass_forbidden": "ၶေႃႈလပ်ႉ တေဢမ်ႇၸၢင်ႈ လႅၵ်ႈလၢႆႈ",
+ "resetpass_forbidden-reason": "ၶေႃႈလပ်ႉ တေဢမ်ႇၸၢင်ႈ လႅင်ႈလၢႆႈ : $1�",
+ "resetpass-no-info": "တႃႇၸဝ်ႈၵဝ်ႇ တေၸၢင်ႈၸႂ်ႉလႆႈ ၼႃႈလိၵ်ႈၼႆႉ ၵမ်းသိုဝ်ၼၼ်ႉၼႆ ၸဝ်ႈၵဝ်ႇ တေလႆႈ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇဝႆႉဢေႃႈ။",
+ "resetpass-submit-loggedin": "လႅၵ်ႈလၢႆႈ ၶေႃႈလပ်ႉ",
+ "resetpass-submit-cancel": "ဢမ်ႇႁဵတ်း",
+ "resetpass-wrong-oldpass": "ဢမ်ႇၸၢင်ႈၸႂ်ႉလႆႈ ၸူဝ်ႈၵႅပ်ႉ ဢမ်ႇၼၼ် ၶေႃႈလပ်ႉယၢမ်းလဵဝ်။\nၸဝ်ႈၵဝ်ႇ ဢၢပ်ႈလႅၷ်ႈလၢႆႈ ၶေႃႈလပ်ႉၸဝ်ႈၵဝ်ႇ ဢမ်ႇၼၼ်ႉ တုၵ်းယွၼ်းဝႆႉ ၶေႃႈလပ်ႉ ၸူဝ်ႈၵႅပ်ႉ။",
+ "resetpass-recycled": "ၶႅၼ်းတေႃႈ ၶိုၼ်းတင်ႈ ၶေႃႈလပ်ႉၸဝ်ႈၵဝ်ႇ တႃႇသေဢၼ်ဢၼ် ဢၼ်ဢမ်ႇၸႂ်ႇ ၶေႃႈလပ်ႉ ယၢမ်းလဵဝ်။",
+ "resetpass-temp-emailed": "ၸဝ်ႈၵဝ်ႇ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇတင်း ၶူတ်ႉၸူဝ်ႉၵႅပ်ႉ ဢၼ်သူင်ႇတင်း ဢီးမေးလ်ဝႆႉ။\nတႃႇတေယဝ်ႉတူဝ်ႈ လွင်ႈၶဝ်ႈလွၵ်ႉဢိၼ်ႇၼႆ ၸဝ်ႈၵဝ်ႇတေလႆႈမၵ်းသႂ်ႇပၼ် ၶေႃႈလပ်ႉဢၼ်မီႈ ၵႃႈတီႈၼႆႈ :",
+ "resetpass-temp-password": "ၶေႃႈလပ်ႉ ၸူဝ်ႈၵႅပ်ႉ :",
+ "resetpass-expired": "ၶေႃႈလပ်ႉၸဝ်ႈၵဝ်ႇၼႆႉ မၼ်းၵဝ်ႇသႃးၵႂႃႇယဝ်ႉ။ တႃႇတေၶဝ်ႈ လွၵ်ႉဢိၼ်ၼႆ ၶႅၼ်းတေႃႈ မၵ်းသႂ်ႇပၼ် ၶေႃႈလပ်ႉ ဢၼ်မႂ်ႇလႄႈ။",
+ "passwordreset": "ၶိုၼ်းမႄးတင်ႈ ၶေႃႈလပ်ႉ",
+ "passwordreset-disabled": "ၵၢၼ်တိုင်ႈၶိုၼ်း ၶေႃႈလပ်ႉၼႆႉ ထုၵ်ႇဢိုတ်းဝႆႉၵႃႈ တီႈ ဝီႇၶီႇၼႆႉ။",
+ "passwordreset-emaildisabled": "ၽၢင်ႁဵတ်းၵၢၼ် ဢီးမေးလ် ထုၵ်ႇဢိုတ်းဝႆႉ ၵႃႈတီႈ ဝီႇၶီႇၼႆႉ။",
+ "passwordreset-username": "ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း",
+ "passwordreset-domain": "တူဝ်ႇမဵင်း :",
+ "passwordreset-capture": "တေတူၺ်း ဢီးမေးလ်ၽွၼ်းလႆႈ?",
+ "passwordreset-capture-help": "ပေႃးၸဝ်ႈၵဝ်ႇ ၶိုၼ်ႇလွၵ်ႈၼႆႉၼႆ ဢီးမေးလ် (ဢၼ်ၸႂ်ႉၶေႃႈလပ်ႉၸူဝ်ႈၵႅပ်ႉ) တေၼႄဝႆႉဝႃႈ မၼ်းသူင်ႇၸူး ၽူႈၸႂ်ႉတိုဝ်း ဝႆႉယဝ်ႉ ၼႆဢေႃႈ.",
+ "passwordreset-email": "ႁဵင်းလိၵ်ႈ ဢီးမေးလ် :",
+ "passwordreset-emailtitle": "လွင်ႈႁူဝ်ယွႆႈ ဢၶွင်ႉ ၵႃႈတီႈ {{SITENAME}}",
+ "passwordreset-emailelement": "ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း:\n$1\n\nၶေႃႈလပ်ႉ ၸူဝ်ႈၵႅပ်ႉ:\n$2",
+ "passwordreset-emailsentemail": "ႁဵင်းလိၵ်ႈ ဢီးမေးလ်ဢၼ်ၼႆႉၼႆႉ မၼ်းၵပ်းၵၢႆႇၵၼ်တင်း ဢၶွင်ႉၸဝ်ႈၵဝ်ႇ၊ ဢၼ်ပဵၼ် ဢီးမေးလ် တႃႇတင်ႈၶိုၼ်းမၢႆလပ်ႉၼၼ်ႉ တေထုၵ်ႇသူင်ႇၸူးယူႇ.",
+ "passwordreset-emailsentusername": "ႁဵင်းလိၵ်ႈ ဢီးမေးလ်ဢၼ်ၼႆႉၼႆႉ မၼ်းၵပ်းၵၢႆႇၵၼ်တင်း ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း ဢၼ်ၼႆႉ၊ ဢၼ်ပဵၼ် ဢီးမေးလ် တႃႇတင်ႈၶိုၼ်းမၢႆလပ်ႉၼၼ်ႉ တေထုၵ်ႇသူင်ႇၸူးယူႇ.",
+ "passwordreset-emailsent-capture": "ဢီးမေးလ် ၵၢၼ်တင်ႈၶိုၼ်း မၢႆလပ်ႉၼၼ်ႉ ထုၵ်ႇသူင်ႇၵႂႃႇၸူး ဢၼ်ၼႄဝႆႉၼင်ႇ ၽၢႆႇတႂ်ႈၼႆႉ။",
+ "passwordreset-invalideamil": "ႁဵင်းလိၵ်ႈ ဢီႈမေးလ် ၽိတ်းဝႆႉ။",
+ "passwordreset-nodata": "ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်းလႄႈ ႁဵင်းလိၵ်ႈဢီးမေးလ် ဢမ်ႇလႆႈၵမ်ႉထႅမ်ဝႆႉ သေဢၼ်။",
+ "changeemail": "လႅၵ်ႈလၢႆႈ ဢမ်ႇၼၼ် ထွၼ်ပႅတ်ႈ ႁဵင်းလိၵ်ႈ ဢီးမေးလ်",
+ "changeemail-no-info": "တႃႇၸဝ်ႈၵဝ်ႇ တေၸၢင်ႈၸႂ်ႉလႆႈ ၼႃႈလိၵ်ႈၼႆႉ ၵမ်းသိုဝ်ၼၼ်ႉၼႆ ၸဝ်ႈၵဝ်ႇ တေလႆႈ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇဝႆႉဢေႃႈ။",
+ "changeemail-oldemail": "ႁဵင်းလိၵ်ႈ ဢီးမေးလ် ဢၼ်ၸႂ်ႉဝႆႉ ယၢမ်းလဵဝ် :",
+ "changeemail-newemail": "ႁဵင်းလိၵ်ႈ ဢီးမေးလ် ဢၼ်မႂ်ႇ :",
+ "changeemail-none": "(ဢမ်ႇမီးသင်)",
+ "changeemail-password": "ၶေႃႈလပ်ႉ {{SITENAME}} ၸဝ်ႈၵဝ်ႇ :",
+ "changeemail-submit": "လႅၵ်ႈလၢႆႈ ဢီးမေးလ်",
+ "changeemail-throttled": "ၸဝ်ႈၵဝ်ႇ ႁႃၶဝ်ႈ လွၵ်ႉဢိၼ် လၢႆပွၵ်ႈၼႅၼ်ႇယဝ်ႉ။\nမိူဝ်ႈပႆႇၶတ်းၸႂ်ၶဝ်ႈတူၺ်းထႅင်ႈၼၼ်ႉ ၶႅၼ်းတေႃႈ ပႂ်ႉပၼ် $1 ။",
+ "changeemail-nochange": "ၶႅၼ်းတေႃႇ ပေႃႉထႅမ်သႂ်ႇပၼ် ႁဵင်းလိၵ်ႈဢီးမေးလ် ဢၼ်မႂ်ႇ ဢၼ်ပႅၵ်ႇပိူင်ႈဢၼ်ၼႆ့။",
+ "resettokens": "ၶိုၼ်းတင်ႈ မၢႆၶပ်ႉ",
+ "resettokens-no-tokens": "မၼ်းဢမ်ႇမီး တူဝ်ၶပ်ႉတၢမ်း တႃႇတေ တင်ႈၶိုၼ်း",
+ "resettokens-tokens": "မၢႆၶပ်ႉ :",
+ "resettokens-token-label": "$1 (ၵႃႈၶၼ် ယၢမ်းလဵဝ်: $2)",
+ "resettokens-done": "ၶိုၼ်းတင်ႈ မၢႆၶပ်ႉ",
+ "resettokens-resetbutton": "ၶိုၼ်းတင်ႈ မၢႆၶပ်ႉ ဢၼ်လိူၵ်ႈဝႆႉၼႆႉ",
+ "bold_sample": "တူဝ်လိၵ်ႈၼႃ",
+ "bold_tip": "တူဝ်လိၵ်ႈၼႃ",
+ "italic_sample": "တူဝ်လိၵ်ႈၵိူင်း",
+ "italic_tip": "တူဝ်လိၵ်ႈၵိူင်း",
+ "link_sample": "ႁူဝ်ၶေႃႈႁဵင်းၵွင်ႉ",
+ "link_tip": "ႁဵင်းၵွင်ႉတၢင်းၼႂ်း",
+ "extlink_sample": "http://www.example.com ႁူဝ်ၶေႃႈႁဵင်းၵွင်ႉ",
+ "extlink_tip": "ႁဵင်းၵွင်ႉၵႂႃႇတၢင်ႇတီႈ (ယႃႇလိုမ်းသႂ်ႇ http:// ပႃႈၼႃႈသုတ်း)",
+ "headline_sample": "လိၵ်ႈႁူဝ်ၶေႃႈ",
+ "headline_tip": "ႁူဝ်ၶေႃႈ ထၢၼ်ႈ ႒",
+ "nowiki_sample": "ဢဝ်လိၵ်ႈဢၼ်ဢမ်ႇမီးပိူင် သႂ်ႇပၼ်တီႈၼႆႈ",
+ "nowiki_tip": "ၶၢမ်ႈပႅတ်ႈပိူင် wiki",
+ "image_tip": "ၾၢႆႇၽင်ဝႆႉ",
+ "media_tip": "ႁဵင်းၵွင်ႉၾၢႆႇ",
+ "sig_tip": "လၢႆးမိုဝ်းၸဝ်ႈၵဝ်ႇ ၸွမ်း ၸုမ်ႈၶၢဝ်းယၢမ်း",
+ "hr_tip": "သၢႆၼႃႈသုင် - ၸႂ်ႉဢၼ်ၵႅမ်",
+ "summary": "ႁူဝ်ႁုပ်ႈ :",
+ "subject": "ႁူဝ်ၶေႃႈ :",
+ "minoredit": "ပဵၼ်လွင်ႈမူၼ်ႉမႄးဢိတ်းဢီႈ",
+ "watchthis": "တူၺ်းၼႃႈလိၵ်ႈၼႆႉ",
+ "savearticle": "ၵဵပ်းသိမ်း ၼႃႈလိၵ်ႈ",
+ "publishpage": "ပိုၼ်ဢွၵ်ႇ ၼႃႈလိၵ်ႈ",
+ "preview": "တူၺ်းလူင်ႈၼႃႈ",
+ "showpreview": "ၼႄတူဝ်ယၢင်ႇ",
+ "showdiff": "ၼႄလွင်ႈလႅၵ်ႈလၢႆႈ",
+ "blankarticle": "<strong>ၽၢင်ႉ:</strong> ၼႃႈလိၵ်ႈ ဢၼ်ၸဝ်ႈၵဝ်ႇ ၵေႃႇသၢင်ႈဝႆႉၼႆႉ မၼ်းတိုၵ်ႉပဵၼ် ဢၼ်ပဝ်ႇဝႆႉၵူၺ်း။ ပေႃးၸဝ်ႈၵဝ်ႇ ၼဵၵ်း \"{{int:savearticle}}\" ထႅင်ႈၵမ်းၼိုင်ႈၼႆ, ၼႃႈလိၵ်ႈၼႆႉ မၼ်းတေၵေႃႇသၢင်ႈၵႂႃႇ ၼင်ႇ ဢၼ်ပဝ်ႇ ဢၼ်ဢမ်ႇမီးသင်ၼၼ်ႉယဝ်ႈ။",
+ "anoneditwarning": "<strong>ၽၢင်ႉပၼ်:</strong> ၸဝ်ႈၵဝ်ႇဢမ်ႇလႆႈ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇဝႆႉ။ သင်ၸိူဝ်ႉဝႃႈ ၸဝ်ႈၵဝ်ႇ ႁဵတ်းလွင်ႈလႅၵ်ႈလၢႆႈသေဢၼ်ၼႆႉ ဢၼ်ပဵၼ် မၢႆသၢႆၼႅတ်ႇ - IP address ၸဝ်ႈၵဝ်ႇၼၼ်ႉ တေဢွၵ်ႇၼႄဝႆႉ ႁႂ်ႈၵူၼ်းတၢင်းၼမ်ႁၼ်ၸွမ်း။ သင်ၸိူဝ်ႉၸဝ်ႈၵဝ်ႇ <strong>[$1 log in]</strong> ဢမ်ႇၼၼ် <strong>[$2 create an account]</strong>, ၵၢၼ်ၸဝ်ႈၵဝ်ႇ ႁဵတ်းၼၼ်ႉၵေႃႈ မၼ်းတေၵႂႃႇၶဝ်ႈပဵၼ် လွင်ႈႁူမ်ႈသၢင်ႈ ၵႃႈတီႈ ၸိုဝ်ႈၸဝ်ႈၵဝ်ႇသေ ၸဝ်ႈၵဝ်ႇ ႁူမ်ႈသၢင်ႈသင်ၼႆၵေႃႈ ၵူႈၵေႃႉ တေလႆႈႁၼ်ၵိုၵ်းၸိုဝ်ႈ ၸဝ်ႈၵဝ်ႇယူႇ။",
+ "anonpreviewwarning": "<em>ၸဝ်ႈၵဝ်ႇၼႆႉ ဢမ်ႇပႆႇလႆႈ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇဝႆႉ။ တေဢဝ် မၢႆဢၢႆႇပီၸဝ်ႈၵဝ်ႇသေ သိမ်းပၼ်ၵႂႃႇ တီႈၼႂ်း ပိုၼ်းမႄးထတ်း ၼႃႈလိၵ်ႈၼႆႉၶႃႈ။",
+ "missingsummary": "<strong>ၶေႃႈၵိုတ်းလိူဝ်:</strong> ၸဝ်ႈၵဝ်ႇဢမ်ႇလႆႈၵမ်ႉထႅမ်ပၼ်ဝႆႉ ႁူဝ်ႁုပ်ၵၢၼ်မႄးထတ်း။ သင်ၸိူဝ်ႉဝႃႈ ၸဝ်ႈၵဝ်ႇ ၼဵၵ်း \"{{int:savearticle}}\" ထႅင်ႈၵမ်းၼိုင်ႈၼႆ ၵၢၼ်မႄးထတ်းၸဝ်ႈၵဝ်ႇ ႁဵတ်းဝႆႉၼၼ်ႉ မၼ်းတေသိမ်းၵႂႃႇ ၼင်ႇဢမ်ႇမီးပႃး လွင်ႈႁူဝ်ႁုပ်မၼ်းၼၼ်ႉယဝ်ႈ။",
+ "missingcommenttext": "ၶႅၼ်းတေႃႈ ပေႃႉသႂ်ႇပၼ် တၢင်းၶႆႈၸႂ် ၵႃႈတီႈတႂ်ႈၼႆႉ",
+ "previewerrortext": "မိူဝ်ႈၽွင်းၶတ်းၸႂ်ၼႄ တႃႇတူၺ်းလူင်ႈၼႃႈ လွင်ႈလႅၵ်ႈလၢႆႈ ဢၼ်ၸဝ်ႈၵဝ်ႇ ႁဵတ်းမႃးၼၼ်ႉ လႆႈမီးလွင်ႈၽိတ်းပိူင်ႈ ဢွၵ်ႇပဵၼ်ဝႆႉ။",
+ "blockedtitle": "ၽူႈၸႂ်ႉတိုဝ်းၼႆႉ ထုၵ်ႇတတ်းၶၢတ်ႇဝႆ့",
+ "blockednoreason": "ဢမ်ႇလႆႈပၼ်ဝႆႉ လွင်ႈတၢင်းသင်။",
+ "whitelistedittext": "တႃႇတေမႄးထတ်း ၼႃႈလိၵ်ႈၼႆႉ ၶႅၼ်းတေႃႈ $1 ။",
+ "loginreqtitle": "လူဝ်ႇလႆႈ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇ",
+ "loginreqlink": "လွၵ်ႉဢိၼ်ႇ",
+ "loginreqpagetext": "တႃႇတေတူၺ်းၼႃႈလိၵ်ႈၼႆ ၶႅၼ်းတေႃႈ $1",
+ "accmailtitle": "ၶေႃႈလပ်ႉ သူင်ႇၵႂႃႇယဝ်ႉယဝ်ႈ။",
+ "newarticle": "(ဢၼ်မႂ်ႇ)",
+ "newarticletext": "ၸဝ်ႈၵဝ်ႇလႆႈၸွမ်းလင်ဝႆႉ ႁႅင်းၵွင်ႉ ၼႃႈလိၵ်ႈ ဢၼ်ဢမ်ႇမီးဝႆႉၼၼ်ႉ။\nတႃႇတေၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈ၊ တႄႇပေႃႉသႂ်ႇၵႃႈတီႈ လွၵ်ႈပႃႈတႂ်ႈ \n (တွၼ်ႈတႃႇ လွၼ်ႉၶၢဝ်ႇ တၢင်ႇၸိူဝ်း တူၺ်းၵႃႈတီႈ [$1 help page] ).\nသင်ၸိူဝ်ႉဝႃႈ ၸဝ်ႈၵဝ်ႇ ၽိတ်းတၢင်းသေ ၽႅဝ်မႃးတီႈၼႆႈၼႆ၊ ၼဵၵ်း ပၼ်တူဝ် <strong>ၼဵၼ်ႁူၼ်လင်</strong> ၶွင် တူဝ်ပိုတ်ႇဝႅပ်ႉ ၸဝ်ႈၵဝ်ႇလႄႈ။",
+ "noarticletext": "ၼႂ်းၼႃႈၼႆႉယင်းဢမ်ႇမီးလိၵ်ႈသင်တေႃႈလဵဝ်။\nသူၸၢင်ႈ [[Special:Search/{{PAGENAME}}|ႁႃ ႁူဝ်ၶေႃႈၼႃႈလိၵ်ႈၼႆႉ]] ၼႂ်းတၢင်ႇၼႃႈ၊\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ၶူၼ်ႉႁႃ logs ဢၼ်ၵွင်ႉၵၢႆၵၼ်],\nဢမ်ႇၼၼ် [{{fullurl:{{FULLPAGENAME}}|action=edit}} သၢင်ႈၼႃႈၼႆႉ]</span>။",
+ "noarticletext-nopermission": "ၼႂ်းၼႃႈၼႆႉယင်းဢမ်ႇမီးလိၵ်ႈသင်တေႃႈလဵဝ်။\nသူၸၢင်ႈ [[Special:Search/{{PAGENAME}}|ႁႃ ႁူဝ်ၶေႃႈၼႆႉ]] ၼႂ်းတၢင်ႇၼႃႈ၊\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ၶူၼ်ႉႁႃ logs ဢၼ်ၵဵဝ်ႇၵွင်ႉၵၼ်],\nဢမ်ႇၼၼ် [{{fullurl:{{FULLPAGENAME}}|action=edit}} မူၼ်ႉမႄးၼႃႈၼႆႉ]</span>။",
+ "userpage-userdoesnotexist-view": "ဢၶွင်ႉ ၽူႈၸႂ်ႉတိုဝ်း \"$1\" ၼႆႉ ဢမ်ႇပႆႇလႆႈ တၢင်ႇမၢႆၽၢင်ဝႆႉ။",
+ "blocked-notice-logextract": "ၽူႈၸႂ်ႉတိုဝ်းၵေႃႉၼႆႉ ထုၵ်ႇတတ်းၶၢတ်ႇဝႆႉဢေႃႈ ယၢမ်းလဵဝ်။\nသဵၼ်ႈမၢႆတတ်းၶၢတ်ႇ ၵမ်းလိုၼ်းသုတ်းၼႆႉ ၼႄဝႆႉယူႇၵႃႈတီႈ သဵၼ်ႈမၢႆၽိုၼ်ဢိင် ပႃႈတႂ်ႈၼႆႉ။",
+ "updated": "(ဢၢပ်ႉတိတ်ႉ)",
+ "note": "<strong>မၢႆတွင်း:</strong>",
+ "previewnote": "<strong>တွင်းဝႆႉပၼ်ဝႃႈ ၼႆႉပဵၼ် ဢၼ်တူၺ်းလူင်ႈၼႃႈၵူၺ်း</strong>\nဢၼ်ၸဝ်ႈၵဝ်ႇ ႁဵတ်းလွင်ႈလႅၵ်ႈလၢႆႈမႃးၸိူဝ်းၼၼ်ႉ ပႆႇလႆႈသိမ်းၵွၼ်ႇ။",
+ "continue-editing": "ၵႂႃႇၸူးတီႈ ဢွင်ႈမႄးထတ်း",
+ "editing": "တိုၵ်ႉမူၼ်ႉမႄး $1",
+ "creating": "တိုၵ်ႉၵေႃႇသၢင်ႈ $1",
+ "editingsection": "မႄးထတ်း $1 (ၵၼ်)",
+ "editconflict": "မႄးထတ်း လွင်ႈယုင်ႈယၢင်ႈ : $1",
+ "yourtext": "လိၵ်ႈၸဝ်ႈၵဝ်ႇ",
+ "storedversion": "ၵၢၼ်ၶူၼ်ႉလူ ဢၼ်ဢဝ်ၶိုၼ်း",
+ "yourdiff": "ၸိူဝ်းပႅၵ်ႇပိူင်ႈ",
+ "longpageerror": "<strong>လွင်ႈၽိတ်းပိူင်ႈ : လိၵ်ႈၸိူဝ်းဢၼ်ၸဝ်ႈၵဝ်ႇ မၵ်းမၼ်ႈသႂ်ႇပၼ်မႃးၼၼ်ႉ တၢင်းယၢဝ်းမၼ်း မီး {{PLURAL:$1|ၼိုင်ႈ kilobyte|$1 kilobytes}}, မၼ်းတိူဝ်းယၢဝ်ၢးလိူဝ်သေ {{PLURAL:$2|ၼိုင်ႈ kilobyte|$2 kilobytes}}.</strong>\nမၼ်းတေဢမ်ႇၸၢင်ႈ သိမ်းဝႆႉပၼ်လႆႈ။",
+ "readonlywarning": "<strong>ၽၢင်ႉ : ယွင်ၶေႃႈမုၼ်းၼႆႉ ထုၵ်ႇၶတ်းဝႆႉ တွၼ်ႈတႃႇ ၵၢၼ်မူၼ်ႉမေး၊ ယွၼ်ႉၼၼ်လႄႈ ၸဝ်ႈၵဝ်ႇ တေဢမ်ႇၸၢင်ႈ သိမ်းဝႆႉ ၵၢၼ်လႅၵ်ႈလၢႆႈ ၸဝ်ႈၵဝ်ႇ ယၢမ်းလဵဝ်</strong>\nၸဝ်ႈဝ်ႇ တေလူဝ်ႇ ထုတ်ႇ ၵေႃႇပီႇ သေ ပႃႉသႂ်ႇ ၽဵတ်ႉသႂ်ႇဝႆႉ တီႈၼႂ်း ၾၢႆႇလိၵ်ႈ သေ သိမ်းဝႆႉ တွၼ်ႈတႃႇၶိုၼ်းၸႂ်ႉဝၢႆးလင်။\nၵေႃႉၵုမ်းထိင်ပိူင်သၢင်ႈ ၵေႃႉဢၼ်ၶတ်းဝႆႉၼႆႉ မၼ်းပၼ်လွင်ႈတၢင်းမၼ်းဝႆႉဝႃႈ : $1",
+ "protectedpagewarning": "<strong>ၽၢင်ႉ : ၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇႁႄႉၵင်ႈဝႆႉ၊ ယွၼ်ႉၼၼ်လႄႈ ၸိူဝ်းပဵၼ် ၽူႈၸႂ်ႉတိုဝ်း ၽူႈၵုမ်းၵၢၼ် ၶဝ်ၵူၺ်းတေၸၢင်ႈမီး သုၼ်ႇမႄးထတ်းလႆႈ။</strong>\nသဵၼ်ႈမၢႆၵမ်းလိုၼ်းၸိူဝ်းၼႆႉ ပၼ်ဝႆႉၽၢႆႇတႂ်ႈၼႆႉ တွၼ်ႈတႃႇႁႂ်ႈပဵၼ် ၵၢၼ်ဢိင် :",
+ "semiprotectedpagewarning": "<strong>မၢႆတွင်း:</strong> ၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇႁႄႉၵင်ႈဝႆႉ၊ ယွၼ်ႉၼၼ်လႄႈ ၸိူဝ်းပဵၼ် ၽူႈၸႂ်ႉတိုဝ်း ဢၼ်တၢင်ႇမၢႆၽၢင်ဝႆႉၼၼ်ႉၵူၺ်း တေၸၢင်ႈ မႄးထတ်းလႆႈ။ \nသဵၼ်ႈမၢႆၵမ်းလိုၼ်းၸိူဝ်းၼႆႉ ပၼ်ဝႆႉၽၢႆႇတႂ်ႈၼႆႉ တွၼ်ႈတႃႇႁႂ်ႈပဵၼ် ၵၢၼ်ဢိင် :",
+ "cascadeprotectedwarning": "<strong>ၽၢင်ႉ :</strong> ၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇႁႄႉၵင်ႈဝႆႉလႄႈ ၸိူဝ်းပဵၼ် ၽူႈၸႂ်ႉတိုဝ်း ၽူႈၵုမ်းၵၢၼ်ၶဝ်ၵူၺ်း တေမီးသုၼ်ႇ မႄးထတ်းလႆႈ၊ ယွၼ်ႉပိူဝ်ႈဝႃႈ မၼ်းၶဝ်ႈပႃးဝႆႉ ၼႂ်းၵိင်ႇၽႄ ၸိူဝ်းပဵၼ် ဢၼ်ထုၵ်ႇႁႄႉၵင်ႈဝႆႉ {{PLURAL:$1|page|pages}}:",
+ "titleprotectedwarning": "<strong>ၽၢင်ႉ : ၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇႁႄႉၵင်ႈဝႆႉ ယွၼ်ႉၼၼ် [[Special:ListGroupRights|specific rights]] ၸိူဝ်းၼႆႉ ထုၵ်ႇၵေႃႇသၢင်ႈဝႆႉ။</strong>\nသဵၼ်ႈမၢႆၵမ်းလိုၼ်းၸိူဝ်းၼႆႉ ပၼ်ဝႆႉၽၢႆႇတႂ်ႈၼႆႉ တွၼ်ႈတႃႇႁႂ်ႈပဵၼ် ၵၢၼ်ဢိင် :",
+ "templatesused": "{{PLURAL:$1|Template|ပိူင်တမ်း}} ၸႂ်ႉဝႆႉတီႈၼႃႈလိၵ်ႈၼႆႉ:",
+ "templatesusedpreview": "{{PLURAL:$1|ပိူင်တမ်း|ပိူင်တမ်း၊}} ၸႂ်ႉဝႆႉတီႈၼႂ်း ၵၢၼ်တူၺ်းလူင်ႈၼႃႈ :",
+ "templatesusedsection": "{{PLURAL:$1|ပိူင်တမ်း|ပိူင်တမ်း၊}} ၸႂ်ႉဝႆႉ တီႈၼႂ်း ၵၼ်ၼႆႉ :",
+ "template-protected": "ႁႄႉၵင်ႈဝႆႉ",
+ "template-semiprotected": "(ႁႄႉၵၼ်ႈဝႆႉ ၵမ်ႈၽွင်ႈ)",
+ "hiddencategories": "ၼႃႈလိၵ်ႈဢၼ်ၼႆႉ မၼ်းပဵၼ် ၼႃႈလိၵ်ႈၶဝ်ႈၸုမ်း {{PLURAL:$1|1 hidden category|$1 ၵၼ်သိူင်ႇဝႆႉ}}:",
+ "nocreate-loggedin": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇလႆႈမီးသုၼ်ႇ တွၼ်ႈတႃႇတေၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈဢၼ်မႂ်ႇ။",
+ "sectioneditnotsupported-title": "ၵၢၼ်မႄးထတ်း တွၼ်ႈၵၼ် ဢမ်ႇလႆႈ ၵမ်ႉထႅမ်ဝႆႉပၼ်။",
+ "sectioneditnotsupported-text": "ၵၢၼ်မႄးထတ်း တွၼ်ႈၵၼ် ဢမ်ႇလႆႈ ၵမ်ႉထႅမ်ဝႆႉပၼ် တီႈၼႃႈလိၵ်ႈၼႆ့။",
+ "permissionserrors": "ၵၢၼ်လူတ်းပွႆႇ ၽိတ်းပိူင်ႈ",
+ "permissionserrorstext": "ၸဝ်ႈၵဝ်ႇဢမ်ႇမီးသုၼ်ႇ တႃႇႁဵတ်းဢၼ်ၼၼ်ႉ၊ ယွၼ်ႉပိူဝ်ႈဝႃႈ {{PLURAL:$1|လွင်ႈတၢင်း|လွင်ႈတၢင်းၸိူဝ်း}} ၼႆႉ:",
+ "permissionserrorstext-withaction": "ၸဝ်ႈၵဝ်ႇဢမ်ႇမီးသုၼ်ႇ တႃႇ $2, တွၼ်ႈတႃႇ ၸိူဝ်း ဢၼ်ပဵၼ် {{PLURAL:$1|reason|လွင်ႈတၢင်း}}:",
+ "contentmodelediterror": "ၸဝ်ႈၵဝ်ႇတေဢမ်ႇၸၢင်ႈ မႄးထတ်း ၵၢၼ်ၶူၼ်ႉလူဢၼ်ၼႆႉ၊ ယွၼ်ႉပိူဝ်ႈဝႃႈ ၽၢင်တူဝ် ၶေႃႈၶဝ်ႈပႃး မၼ်းၼႆႉပဵၼ် <code>$1</code>, ဢၼ် ပႅၵ်ႇပိူင်ႈၵၼ်တၢင်း ၽၢင်တူဝ် ၶေႃႈၶဝ်ႈပႃး ၶွင်ႈၼႃႈလိၵ်ႈ <code>$2</code> ၼႆႉ။",
+ "recreate-moveddeleted-warn": "<strong>ၶေႃႈၽၢင်ႉပၼ် : ၸဝ်ႈၵဝ်ႇ ၶိုၼ်းၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈ ဢၼ်လႆႈ မွတ်ႇပႅတ်ႈၵႂႃႇဝႆႉၼၼ်ႉ။</strong>\n\nၸဝ်ႈၵဝ်ႇ ထုၵ်ႇလီဝူၼ်ႉတူၺ်းဝႃႈ ၸွင်ႇမၼ်းသၢင်ႇထုၵ်ႇ တွၼ်ႈတႃႇတေသိုပ်ႇ မႄးထတ်း ၼႃႈလိၵ်ႈၼႆႉဢၼ်ဝႃႈၼၼ်ႉ။\nသဵၼ်ႈလၢႆ မွတ်ႇပႅတ်ႈလႄႈ ၶၢႆႉဢွင်ႈ တွၼ်ႈတႃႇၼႃႈလိၵ်ႈၼႆႉ ၵမ်ႉထႅမ်ဝႆႉပၼ် ၵႃႈတီႈၼႆႈ တွၼ်ႈတႃႇ ႁႂ်းငၢႆႈလူမ်ၸႂ် :",
+ "moveddeleted-notice": "ၼႃႈလိၵ်ႈၼႆႉ မွတ်ႇပႅတ်ႈၵႂႃႇယဝ်ႉ။ လွင်ႈမွတ်ႇပႅတ်ႈလႄႈ လွင်ႈၶၢႆႉသၢႆမၢႆ တွၼ်ႈတႃႇ ၼႃႈလိၵ်ႈၼႆႉ ၵမ်ႉထႅမ်ဝႆႉပၼ် ၼင်ႇပႃႈတႂ်ႈၼႆႉယူႇ။ မၼ်းပဵၼ် တွၼ်ႈတႃႇ ႁဵတ်းၽိုၼ်ဢိင်ယဝ်ႉ။",
+ "moveddeleted-notice-recent": "ယိၼ်းၶီၸွမ်ႈယူႇ၊ ၼႃႈလိၵ်ႈၼႆႉ တိုၵ်ႉႁႃထုၵ်ႇမွတ်ႇပႅတ်ႈ (ၼႂ်းၶၢဝ်းတၢင်း မိူဝ်ႈပူၼ်ႉမႃး 24 ၸူဝ်ႈမူင်း) ၼႆႉၵူၺ်း။ သဵၼ်ႈမၢႆ မွတ်ႇပႅတ်ႈ လႄႈ ၶၢႆႉဢွင်ႈတီႈ ၸိူဝ်းၼၼ်ႉ လႆႈၵမ်ႉထႅမ်ဝႆႉပၼ်ၼင်ႇၽၢႆႇတႂ်ႈ ႁႂ်ႈၸၢင်ႈပဵၼ် ၵၢၼ်ၽိုၼ်ဢိင်။",
+ "log-fulllog": "တူၺ်း သဵၼ်ႈမၢႆဢၼ်တဵမ်ထူၼ်ႈ",
+ "edit-hook-aborted": "ၵၢၼ်မႄးထတ်း ထုၵ်ႇလူတ်းပႅတ်တင်းၶေႃၵွင်ႉ။\nမၼ်းဢမ်ႇပၼ်ဝႆႉ ၶေႃႈသပ်းလႅင်းသင်။",
+ "edit-gone-missing": "ဢမ်ႇၸၢင်ႈႁဵတ်း ဢၢပ်ႉတိတ်ႉၼႃႈလိၵ်ႈ။\nမၼ်းဢၢပ်ႇ မွတ်ႇပႅတ်ႇဝႆႉယဝ်ႉ။",
+ "edit-conflict": "မႄးထတ်း လွင်ႈယုင်ႈယၢင်ႈ",
+ "edit-no-change": "ၵၢၼ်မႄးထတ်းၸဝ်ႈၵဝ်ႇၼၼ်ႉ ထုၵ်ႇၶၢမ်ႈပႅတ်ႈၵႂႃႇ။ ယွၼ်ႉပိူဝ်ႈဝႃႈ တီႈလိၵ်ႈၸိူဝ်းၼႆႉ ဢမ်ႇလႆႈႁၼ် မီးလွင်ႈလႅၵ်ႈလၢႆႈသင်။",
+ "postedit-confirmation-created": "ၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇၵေႃႇသၢင်ႈယဝ်ႉယဝ်ႈ။",
+ "postedit-confirmation-restored": "ၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇဢဝ်ၶိုၼ်းယဝ်ႉယဝ်ႈ။",
+ "postedit-confirmation-saved": "လွင်ႈမႄးထတ်းၸဝ်ႈၵဝ်ႇ သိမ်းပၼ်ယဝ်ႉယဝ်ႈ။",
+ "edit-already-exists": "ဢမ်ႇၸၢင်ႈ ၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈဢၼ်မႂ်ႇ။\nမၼ်းမီးဝႆႉထႃႈယဝ်ႈ။",
+ "defaultmessagetext": "လိၵ်ႈၶေႃႈၶၢဝ်ႇ ပိူင်ႇၵႅဝ်ႈ",
+ "invalid-content-data": "ၶေႃႈမုၼ်းၶဝ်ႈပႃး ၽိတ်းပိူင်ႈဝႆႉ",
+ "content-not-allowed-here": "\"$1\" ၶေႃႈၶဝ်ႈပႃးၼႆႉ ဢမ်ႇၶႂၢင်းပၼ်ဝႆႉ တီႈၼႃႈ လိၵ်ႈ [[$2]]",
+ "editpage-notsupportedcontentformat-title": "ပိူင်ၶေႃႈၶဝ်ႈပႃး ၼႆႉ ဢမ်ႇၵမ်ႉထႅမ်ဝႆႉပၼ်။",
+ "editpage-notsupportedcontentformat-text": "ပိူင်ၶေႃႈၶဝ်ႈပႃး $1 ၼႆႉ မၼ်းဢမ်ႇလႆႈ ၵမ်ႉထႅမ်ဝႆႉပၼ် တင်း ၽၢင်တူဝ် ၶေႃႈၶဝ်ႈပႃး $2",
+ "content-model-wikitext": "လိၵ်ႈဝီႇၶီႇ",
+ "content-model-text": "လိၵ်ႈလွၼ်ႉလွၼ်ႉ",
+ "content-model-javascript": "ၵျႃႇပႃးသၶလႂိပ်ႉ",
+ "content-json-empty-object": "ၵၢၼ်ပဝ်ႇ",
+ "content-json-empty-array": "ထႅဝ်ပဝ်ႇ",
+ "post-expand-template-inclusion-warning": "<strong>ၶေႃႈၽၢင်ႉ</strong> - ပိူင်ဢဝ်မႃးႁူမ်ႈၼၼ်ႉယႂ်ႇပူၼ်ႉၼႃႇ။\nပိူင်မၢင်ၼႃႈတေဢမ်ႇႁူမ်ႈပႃးၸွမ်း။",
+ "cantcreateaccounttitle": "ဢမ်ႇၸၢင်ႈၵေႃႇသၢင်ႈ ဢၶွင်ႉ",
+ "viewpagelogs": "တူၺ်းသၢႆမၢႆ တွၼ်ႈတႃႇၼႃႈလိၵ်ႈၼႆႉ",
+ "nohistory": "တီႈၼႆႈ ဢမ်ႇမီး ပိုၼ်းထတ်းသၢင်ႈ တွၼ်ႈတႃႇၼႃႈလိၵ်ႈၼႆႉ",
+ "currentrev": "ၵၢၼ်ၶူၼ်ႉလူ ၵမ်းလိုၼ်းသုတ်း",
+ "currentrev-asof": "ၵၢၼ်ၶူၼ်ႉလူ ၵမ်းလိုၼ်းသုတ်းၼင်ႇ $1",
+ "revisionasof": "ၶိုၼ်းၶူၼ်ႉလူၼင်ႇ $1",
+ "revision-info": "ၶူၼ်ႉလူၼင်ႇ $1 ၼင်ႇ {{GENDER:$6|$2}}$7",
+ "previousrevision": "← ၸိူဝ်းဢၼ်ၵဝ်ႇ",
+ "nextrevision": "ၵၢၼ်ၶူၼ်ႉလူဢၼ်မႂ်ႇ",
+ "currentrevisionlink": "ၵၢၼ်ၶူၼ်ႉလူ ၵမ်းလိုၼ်းသုတ်း",
+ "cur": "ယၢမ်းလဵဝ်",
+ "next": "ၵႂႃႇၼႃႈ",
+ "last": "ဢွၼ်တၢင်း",
+ "page_first": "ဢွၼ်တၢင်း",
+ "page_last": "လိုတ်းသုတ်း",
+ "history-fieldset-title": "ပိုၼ်းပိုတ်ႇႁႃ",
+ "history-show-deleted": "ဢၼ်ယႃႉဝႆႉၼၼ်ႉၵွၺ်း",
+ "histfirst": "ၵဝ်ႇသုတ်း",
+ "histlast": "မႂ်ႇသုတ်း",
+ "historysize": "({{PLURAL:$1|1 ပၢႆႉ|$1 ပၢႆႉ}})",
+ "historyempty": "(ပဝ်ႇ)",
+ "history-feed-title": "ပိုၼ်းၶူၼ်ႉလူ",
+ "history-feed-description": "ပိုၼ်းၶူၼ်ႉလူ တႃႇၼႃႈလိၵ်ႈၼႆႉ ၵႃႈတီႈၼိူဝ် ဝီႇၶီႇ",
+ "history-feed-item-nocomment": "$1 တီႈ $2",
+ "history-edit-tags": "မႄးထတ်း ၶႅပ်းတိင် ၶွင် ၶူၼ်ႉလူၸိူဝ်းလိူၵ်ႈဝႆႉၼၼ်ႉ။",
+ "rev-deleted-comment": "(ႁူဝ်ႁုပ်ႈၵၢၼ်ထတ်းသၢင် ထွၼ်ဢွၵ်ႇပႅတ်ႈယဝ်ႉ)",
+ "rev-deleted-user": "(ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း ထွၼ်ဢွၵ်ႇပႅတ်ႈယဝ်ႉ)",
+ "rev-deleted-event": "(သဵၼ်ႈမၢႆ ႁူဝ်ယွႆႈ ထွၼ်ဢွၵ်ႇပႅတ်ႈယဝ်ႉ)",
+ "rev-deleted-user-contribs": "[ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း ဢမ်ႇၼၼ် မၢႆဢၢႆႇပီႇ ထွၼ်ဢွၵ်ႇပႅတ်ႈယဝ်ႉ - ၵၢၼ်မႄးထတ်း ၸိူဝ်းၼၼ်ႉ ထုၵ်ႇလပ်ႉဝႆႉ ၵႃႈတီႈ ၵၢၼ်ႁူမ်ႈသၢင်ႈ]",
+ "rev-deleted-text-permission": "ၼႃႈလိၵ်ႈၶူၼ်ႉလူၼႆႉ ထုၵ်ႇ <strong>မွတ်ႇပႅတ်ႈ</strong>ယဝ်ႉ။\nလွင်ႈႁူဝ်ယွႆႈမၼ်း တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] ၼႆႈၶႃႈ။",
+ "rev-suppressed-text-permission": "ၼႃႈလိၵ်ႈ ၶူၼ်ႉလူဢၼ်ၼႆႉ ထုၵ်ႇ <strong>တဵၵ်းၵိုတ်း</strong> ပႅတ်ႈယဝ်ႉ။\nလွင်ႈႁူဝ်ယွႆႈမၼ်း တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} suppression log] ၼႆႈယူႇ။",
+ "rev-deleted-text-unhide": "ၼႃႈလိၵ်ႈၶူၼ်ႉလူၼႆႉ ထုၵ်ႇ <strong>မွတ်ႇပႅတ်ႈ</strong>ယဝ်ႉ။\nလွင်ႈႁူဝ်ယွႆႈမၼ်း တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] ၼႆႈၶႃႈ။\nပေႃးဝႃႈ ၸဝ်ႈၵဝ်ႇ တိုၵ်ႉမီးၵၢင်ၸႂ် ၶႂ်ႈသိုပ်ႇ ႁဵတ်းၵႂႃႇၼႆ ၸဝ်ႈၵဝ်ႇ တိုၵ်ႉ [$1 တူၺ်း လွင်ႈၶူၼ်ႉလူၼႆႉ] ။",
+ "rev-suppressed-text-unhide": "ၼႃႈလိၵ်ႈ ၶူၼ်ႉလူဢၼ်ၼႆႉ ထုၵ်ႇ <strong>တဵၵ်းၵိုတ်း</strong> ပႅတ်ႈယဝ်ႉ။\nလွင်ႈႁူဝ်ယွႆႈမၼ်း တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} suppression log] ၼႆႈယူႇ။\nပေႃးဝႃႈ ၸဝ်ႈၵဝ်ႇ တိုၵ်ႉမီးၵၢင်ၸႂ် ၶႂ်ႈသိုပ်ႇ ႁဵတ်းၵႂႃႇၼႆ ၸဝ်ႈၵဝ်ႇ တိုၵ်ႉ [$1 တူၺ်း လွင်ႈၶူၼ်ႉလူၼႆႉ] ။",
+ "rev-deleted-text-view": "ၼႃႈလိၵ်ႈ ၶူၼ်ႉလူဢၼ်ၼႆႉ ထုၵ်ႇ <strong>မွတ်ႇပႅတ်ႈ</strong> ၵႂႃႇယဝ်ႉ။\nၸဝ်ႈၵဝ်ႇတိုၵ်ႉၸၢင်ႈတူၺ်ႈမၼ်းသေ လွင်ႈႁူဝ်ယွႆႈမၼ်းတႄႉ တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] ၼႆႈယူႇ။",
+ "rev-suppressed-text-view": "ၼႃႈလိၵ်ႈ ၶူၼ်ႉလူဢၼ်ၼႆႉ ထုၵ်ႇ <strong>တဵၵ်းၵိုတ်း</strong> ပႅတ်ႈယဝ်ႉ။\nၸဝ်ႈၵဝ်ႇတိုၵ်ႉၸၢင်ႈတူၺ်းသေ လွင်ႈႁူဝ်ယွႆႈမၼ်း တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} suppression log] ၼႆႈယူႇ။",
+ "rev-deleted-no-diff": "ၸဝ်ႈၵဝ်ႇ တေဢမ်ႇၸၢင်ႈတူၺ်း လွင်ႈပႅၵ်ႇပိူင်ႈဢၼ်ၼႆႉ၊ ယွၼ်ႉပိူဝ်ႈဝႃႈ ၼႂ်ႈၵႃႈ ၵၢၼ်ၶူၼ်ႉလူဢၼ်ၼိုင်ႈၼႆႉ ထုၵ်ႇ<strong>မွတ်ႇပႅတ်ႈ</strong> ၵႂႃႇယဝ်ႉ။\nလွင်ႈႁူဝ်ယွႆႈမၼ်း တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] ၼႆႈယူႇ။",
+ "rev-suppressed-no-diff": "ၸဝ်ႈၵဝ်ႇ တေဢမ်ႇၸၢင်ႈတူၺ်း လွင်ႈပႅၵ်ႇပိူင်ႈဢၼ်ၼႆႉ၊ ယွၼ်ႉပိူဝ်ႈဝႃႈ ၼႂ်ႈၵႃႈ ၵၢၼ်ၶူၼ်ႉလူဢၼ်ၼိုင်ႈၼႆႉ ထုၵ်ႇ<strong>မွတ်ႇပႅတ်ႈ</strong> ၵႂႃႇယဝ်ႉ။",
+ "rev-deleted-unhide-diff": "ၸဝ်ႈၵဝ်ႇ တေဢမ်ႇၸၢင်ႈတူၺ်း လွင်ႈပႅၵ်ႇပိူင်ႈဢၼ်ၼႆႉ၊ ယွၼ်ႉပိူဝ်ႈဝႃႈ ၼႂ်ႈၵႃႈ ၵၢၼ်ၶူၼ်ႉလူဢၼ်ၼိုင်ႈၼႆႉ ထုၵ်ႇ<strong>မွတ်ႇပႅတ်ႈ</strong> ၵႂႃႇယဝ်ႉ။\nလွင်ႈႁူဝ်ယွႆႈမၼ်း တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] ၼႆႈယူႇ။\nပေႃးၸဝ်ႈၵဝ်ႇတိုၵ်ႉၶႂ်ႈ သိုပ်ႇႁဵတ်းၵႂႃႇယူႇၼႆ ၸဝ်ႈၵဝ်ႇတေၸၢင်ႈ [$1တူၺ်း လွင်ႈပႅၵ်ႈပိူင်ႈ] ၼႆႉလႆႈ။",
+ "rev-suppressed-unhide-diff": "ၼႂ်းၵႃႈ ၵၢၼ်ၶူၼ်ႉလူ လွင်ႈပႅၵ်ႇပိူင်ႈ ဢၼ်ၼိုင်ႈၼႆႉ ထုၵ်ႇ <strong>တဵၵ်းၵိုတ်း</strong> ၵႂႃႇယဝ်ႉ။\nႁူဝ်ယွႆႈမၼ်း တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} suppression log] ၼႆႈယူႇ။\nပေႃးၸဝ်ႈၵဝ်ႇတိုၵ်ႉၶႂ်ႈ သိုပ်ႇႁဵတ်းၵႂႃႇယူႇၼႆ ၸဝ်ႈၵဝ်ႇတေၸၢင်ႈ [$1တူၺ်း လွင်ႈပႅၵ်ႈပိူင်ႈ] ၼႆႉလႆႈ။",
+ "rev-deleted-diff-view": "ၼႂ်းၵႃႈ ၵၢၼ်ၶူၼ်ႉလူ လွင်ႈပႅၵ်ႇပိူင်ႈ ဢၼ်ၼႆႉၼႆႉ ထုၵ်ႇ <strong>မွတ်ႇပႅတ်ႈ</strong>ၵႂႃႇယဝ်ႉ။\nၸဝ်ႈၵဝ်ႇၸၢင်ႈတူၺ်းလႆႈ လွင်ႈပႅၵ်ႇပိူင်ႈသေ လွင်ႈႁူဝ်ယွႆႈမၼ်းတႄႉ တေၸၢင်ႈႁၼ်လႆႈၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log] ၼႆႈယူႇ။",
+ "rev-suppressed-diff-view": "ၼႂ်းၵႃႈ ၵၢၼ်ၶူၼ်ႉလူ လွင်ႈပႅၵ်ႇပိူင်ႈ ဢၼ်ၼႆႉၼႆႉ ထုၵ်ႇ <strong>တဵၵ်းၵိုတ်း</strong> ၵႂႃႇယဝ်ႉ။\nၸဝ်ႈၵဝ်ႇ ၸၢင်ႈတူၺ်း လွင်ႈပႅၵ်ႇပိူင်ႈသေ လွင်ႈႁူဝ်ယွႆႈမၼ်းတႄႉ တေၸၢင်ႈႁၼ်လႆႈ ၵႃႈတီႈ [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} suppression log] ၼႆႈယူႇ။",
+ "rev-delundel": "ၼႄ/သိူင်ႇ",
+ "rev-showdeleted": "ၼႄ",
+ "revisiondelete": "မွတ်ႇပႅတ်ႈ/ ဢမ်ႇမွတ်ႇ ၵၢၼ်ၶူၼ်ႉလူ",
+ "revdelete-nooldid-title": "ၵၢၼ်ၶူၼ်ႉလူ ဢၼ်ယိူင်းၸူးၼၼ်ႉ ၽိတ်းဝႆႉ",
+ "revdelete-no-file": "ၾၢႆႇဢၼ်မၵ်းမၼ်ႈဝႆႉၼၼ်ႉ မၼ်းဢမ်ႇလႆႈမီးဝႆႉ",
+ "revdelete-show-file-confirm": "ၸဝ်ႈၵဝ်ႇ လပ်ႉလွင်းယဝ်ႉႁႃႈဝႃႈ တေၶႂ်ႈတူၺ်း ၵၢၼ်ၶူၼ်ႉလူ ၶွင်ၾၢႆႇ ဢၼ်လႆႈမွတ်ႇပႅတ်ႈၵႂႃႇၼၼ်ႉ။ \"<nowiki>$1</nowiki>\" ၵႃႇတီႈ $2 တေႃႇ $3?",
+ "revdelete-show-file-submit": "ၸႂ်ႈယဝ်ႉ",
+ "revdelete-selected-text": "{{PLURAL:$1|ၵၢၼ်ၶူၼ်ႉလူ ဢၼ်လိူၵ်ႈဝႆႉ|ၵၢၼ်ၶူၼ်ႉလူ ၸိူဝ်းလိူၵ်ႈဝႆႉ}} ၶွင် [[:$2]]:",
+ "revdelete-selected-file": "{{PLURAL:$1|ၾၢႆပိူဝ်းသျိၼ်း ဢၼ်လိူၵ်ႈဝႆႉ|ၾၢႆႇပိူဝ်းသျိၼ်း ၸိူဝ်းလိူၵ်ႈဝႆႉ}} ၶွင် [[:$2]]:",
+ "logdelete-selected": "{{PLURAL:$1|သဵၼ်ႈမၢႆ လွင်ႈႁဵတ်းသၢင်ႈ ဢၼ်လိူၵ်ႈဝႆႉ|သဵၼ်ႈမၢႆ လွင်ႈႁဵတ်းသၢင်ႈ ၸိူဝ်းလိူၵ်ႈဝႆႉ}}:",
+ "revdelete-text-text": "ၵၢၼ်ၶူၼ်ႉလူ ဢၼ်မွတ်ႇပႅတ်ႈၵႂႃႇၼၼ်ႉ မၼ်းတိုၵ်ႉတေ ဢွၵ်ႇၼႄဝႆႉၵႃႈတီႈ ပိုၼ်း ၼႃႈလိၵ်ႈ၊ ၵူၺ်းၵႃႈဝႃႈ ၶေႃႈၶဝ်ႈပႃး ဢၼ်ၵိုၵ်းဝႆႉမၼ်းၼၼ်ႉတႄႉ တေဢမ်ႇၸၢင်ႈဢဝ်ၸႂ်ႉလႆႈၵႃႈတီႈ ၵူၼ်းတင်းၼမ်ယဝ်ႉ။",
+ "revdelete-text-file": "ၾၢႆႇပိူဝ်းသျိၼ်း ဢၼ်မွတ်ႇပႅတ်ႈၵႂႃႇၼၼ်ႉ မၼ်းတိုၵ်ႉတေ ဢွၵ်ႇၼႄဝႆႉၵႃႈတီႈ ပိုၼ်း ၾၢႆႇ၊ ၵူၺ်းၵႃႈဝႃႈ ၶေႃႈၶဝ်ႈပႃး ဢၼ်ၵိုၵ်းဝႆႉမၼ်းၼၼ်ႉတႄႉ တေဢမ်ႇၸၢင်ႈဢဝ်ၸႂ်ႉလႆႈၵႃႈတီႈ ၵူၼ်းတင်းၼမ်ယဝ်ႉ။",
+ "logdelete-text": "သဵၼ်ႈမၢႆ လွင်ႈႁဵတ်းသၢင်ႈ ဢၼ်လႆႈမွတ်ႇပႅတ်ႈၵႂႃႇၼၼ်ႉ မၼ်းတိုၵ်ႉတေ ဢွၵ်ႇၼႄဝႆႉၵႃႈတီႈ သဵၼ်ႈမၢႆ၊ ၵူၺ်းၵႃႈဝႃႈ ၶေႃႈၶဝ်ႈပႃး ဢၼ်ၵိုၵ်းဝႆႉမၼ်းၼၼ်ႉတႄႉ တေဢမ်ႇၸၢင်ႈဢဝ်ၸႂ်ႉလႆႈၵႃႈတီႈ ၵူၼ်းတင်းၼမ်ယဝ်ႉ။",
+ "revdelete-text-others": "သင်ၸိူဝ်ႉဝႃႈ ဢမ်ႇလႆႈ မၵ်ႈသႂ်ႇဝႆႉ လွင်ႈႁႄႉတၢပ်ႈသင်ၼႆတႄႉ ၽူႈၵုမ်းထိင်း မၢင်ၸိူဝ်းၼႆႉ တိုၵ်ႉတေဢဝ်ၸႂ်ႉလႆႈ ၶေႃႈၶဝ်ႈပႃး ဢၼ်လပ်ႉဝႆႉသေ တႃႇတေၶိုၼ်းဢမ်ႇမွတ်ႇ ဢၼ်ၼၼ်ႉ။",
+ "revdelete-confirm": "ၶႅၼ်းတေႃႈ ၼႄႉၼွၼ်းပၼ်ဝႃႈ ၸဝ်ႈၵဝ်ႇ ယိူင်းဢၢၼ်း ၶႂ်ႈႁဵတ်းဢၼ်ၼႆႉယူႇတႄႉ ဢၼ်ဝႃႈၼၼ်ႉ၊ ယဝ်ႉၵေႃႈ ၸဝ်ႈၵဝ်ႇႁူႉပွင်ႇပႃးဝႃႈ လွင်ႈတေသိုပ်ႇပဵၼ်ၸွမ်းၽၢႆႇလင်လႄႈ လွင်ႈဝႃႈၸဝ်ႈၵဝ်ႇ ႁဵတ်းဢၼ်ၼႆႉၸွမ်းၼင်ႇ လွင်ႈလႆႈၸႂ်ၵၼ်တင်း \n [[{{MediaWiki:Policy-url}}|the policy]].",
+ "revdelete-suppress-text": "လွင်ႈတဵၵ်းၵိုတ်း ၼႆႉ <strong>ထုၵ်ႇလီ ၸႂ်ႉ</strong> တွၼ်ႈတႃႇ လွင်ႈတၢင်း ၸိူင်ႉၼင်ႇ ပႃႈတႂ်ႈၼႆႉၵူၺ်း။\n* ၶေႃႈပူင်လွၼ်ႉၶၢဝ်ႇ ဢၼ်ဢၢပ်ႈပဵၼ်လႆႈ\n* လွၼ်ႉၶၢဝ်ႇသုၼ်ႇတူဝ် ဢၼ်ဢမ်ႇဢၢပ်ႈ သၢင်ႇတေႃႇ\n*: <em>ႁဵင်းလိၵ်ႈႁိူၼ်း လႄႈ မၢႆၾူင်း၊ မၢႆၶႅပ်းၽၢင်တူဝ် ၸၵႂႃႇၸိူဝ်းၼႆႉ</em>",
+ "revdelete-legend": "မၵ်းသႂ်ႇပၼ် လွင်ႈႁႄႉၵင်ႈ တႃႇႁၼ်လႆႈ",
+ "revdelete-hide-text": "လိၵ်ႈၶူၼ်ႉလူ",
+ "revdelete-hide-image": "လပ်ႉ ၶေႃႈပႃးၼႂ်း ၾၢႆႇ",
+ "revdelete-hide-name": "လပ်ႉ ၶေႃႈယိူင်း လႄႈ ၽၢင်ၵိုၵ်း",
+ "revdelete-hide-comment": "မႄးထတ်း ႁုဝ်ႁုပ်ႈ",
+ "revdelete-hide-user": "ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း/ ႁဵင်းလိၵ်ႈဢၢႆႇပီႇ ၶွင် ၽူႈမႄးထတ်း",
+ "revdelete-hide-restricted": "တဵၵ်းၵိုတ်းၶေႃႈမုၼ်း ၸိူဝ်းလုၵ်ႈတီႈ ၽူႈၵုမ်းၵၢၼ်ၶဝ် လႄႈ တၢင်ႇၸိူဝ်း",
+ "revdelete-radio-same": "(ဢမ်ႇလႅၵ်ႈလၢႆႈ)",
+ "revdelete-radio-set": "လပ်ႉဝႆႉ",
+ "revdelete-radio-unset": "ႁၼ်လႆႈ",
+ "revdelete-suppress": "တဵၵ်းၵိုတ်းၶေႃႈမုၼ်း ၸိူဝ်းလုၵ်ႈတီႈ ၽူႈၵုမ်းၵၢၼ်ၶဝ် လႄႈ တၢင်ႇၸိူဝ်း",
+ "revdelete-unsuppress": "ထွၼ်ပႅတ်ႈ လွင်ႈၵႅတ်ႇႁႄႉ ဢၼ်မီးတီႈ ၵၢၼ်ၶူၼ်ႉလူ ဢၼ်ဢဝ်ဝႆႉၶိုၼ်းၼၼ်ႉ။",
+ "revdelete-log": "လွင်ႈတၢင်း :",
+ "revdelete-submit": "သိုပ်ႇႁဵတ်း တွၼ်ႈတႃႇ {{PLURAL:$1|ၵၢၼ်ၶူၼ်ႉလူ|ၵၢၼ်ၶူၼ်ႉလူၸိူဝ်း}}ဢၼ်လိူၵ်ႈဝႆႉ",
+ "revdelete-success": "လွင်ႈႁၼ်လႆႈ ၵၢၼ်ၶူၼ်ႉလူၼႆႉ ပဵၼ် ဢၢပ်ႉတိတ်ႉၵႂႃႇယဝ်ႉ။",
+ "revdelete-failure": "လွင်ႈႁၼ်လႆႈ ၵၢၼ်ၶူၼ်ႉလူၼႆႉ ဢမ်ႇပႆႇပဵၼ် ဢၢပ်ႉတိတ်ႉလႆႈ။\n$1",
+ "logdelete-success": "မၵ်းသႂ်ႇ လွင်ႈႁၼ်လႆႈ သဵၼ်ႈမၢႆ",
+ "logdelete-failure": "လွင်ႈႁၼ်လႆႈ သဵၼ်ႈၵၢၼ်ၼႆႉ ဢမ်ႇၸၢင်ႈမၵ်းသႂ်ႇလႆႈ။\n$1",
+ "revdel-restore": "လႅၵ်ႈလၢႆႈ ၵၢၼ်ႁၼ်လႆႈ",
+ "pagehist": "ပိုၼ်းၼႃႈလိၵ်ႈ",
+ "deletedhist": "ပိုၼ်း ၸိူဝ်းမွတ်ႇပႅတ်ႈဝႆႉ။",
+ "revdelete-otherreason": "တၢင်ႇၸိူဝ်း / လွင်ႈတၢင်း ထႅမ်သႂ်ႇထႅင်ႈ",
+ "revdelete-reasonotherlist": "လွင်ႈတၢင်းတၢင်ႇၸိူဝ်း",
+ "revdelete-edit-reasonlist": "မႄးထတ်း လွင်ႈတၢင်း တႃႇမွတ်ႇ",
+ "revdelete-offender": "ၽူႈတႅမ်ႈ ၶေႃႈၶူၼ်ႉဢၢၼ်ႇ :",
+ "suppressionlog": "သဵၼ်ႈမၢႆ တဵၵ်းၵိုတ်း",
+ "mergehistory": "ပိုၼ်းၸိူဝ်း ႁူမ်ႈၼႃႈလိၵ်ႈ",
+ "mergehistory-box": "ဢဝ်ၶေႃႈၶူၼ်ႉဢၢၼ်ႇၶွင် သွင်ၼႃႈလိၵ်ႈၼႆႉ ႁူမ်ႈၵၼ်",
+ "mergehistory-from": "ၼႃႈလိၵ်ႈ ငဝ်ႈငႃႇ :",
+ "mergehistory-into": "ၼႃႈလိၵ်ႈ ယိူင်းၸူး :",
+ "mergehistory-list": "ပိုၼ်းမႄးထတ်း ဢၼ်ၸၢင်ႈႁူမ်ႈလႆႈ",
+ "mergehistory-go": "ၼႄပၼ် ၵၢၼ်မႄးထတ်း ဢၼ်ၸၢင်ႈႁူမ်ႈၵၼ်လႆႈ",
+ "mergehistory-submit": "ၶေႃႈၶူၼ်ႉဢၢၼ်ႇ ႁူမ်ႈၵၼ်",
+ "mergehistory-empty": "ၶေႃႈၶူၼ်ႉဢၢၼ်ႇ ဢၼ်တေၸၢင်ႈႁူမ်ႈၵၼ်လႆႈၼၼ်ႉ ဢမ်ႇမီး",
+ "mergehistory-fail-bad-timestamp": "မိၵ်ႈၶၢဝ်းယၢမ်း ၼႆႉဢမ်ႇၸႂ်ႉလႆႈ",
+ "mergehistory-fail-invalid-source": "ၼႃးလိၵ်ႈငဝ်ႈငႃႇ ၼႆႉ ဢမ်ႇၸႂ်ႉလႆႈ။",
+ "mergehistory-fail-invalid-dest": "ၼႃႈလိၵ်ႈယိူင်းၸူးၼၼ်ႉ ဢမ်ႇၸႂ်ႉလႆႈ",
+ "mergehistory-fail-self-merge": "ၼႃႈလိၵ်ႈငဝ်ႈငႃႇလႄႈ ၼႃႈလိၵ်ႈယိူင်းၸူးၼႆႉ မိူၼ်ၵၼ်။",
+ "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": "ၶိုၼ်းၸႅၵ်ႇဢွၵ်ႇ",
+ "mergelogpagetext": "သဵၼ်ႈမၢႆ ၸိူဝ်းမီးတႂ်ႈၼႆႉ မၼ်းပဵၼ် သဵၼ်ႈမၢႆ ဢၼ်တိုၵ်ႉဢဝ်ပိုၼ်း ၼႃႈလိၵ်ႈဢၼ်ၼိုင်ႈ ၵႂႃႇလေႃႈၵၼ် ထႅင်ႈတၢင်ႇဢၼ်။",
+ "history-title": "ပိုၼ်းၶူၼ်ႉလူတွၼ်ႈတႃႇ \"$1\"",
+ "difference-title": "လွင်ႈပႅၵ်ႇပိူင်ႈ ၼႂ်းၵႄႈ လွင်ႈၶူၼ်ႉလူ တင်း \"$1\"",
+ "difference-title-multipage": "လွင်ႈပႅၵ်ႇပိူင်ႈ ၼႂ်းၵႄႈ ၼႃႈလိၵ်ႈ \"$1\" လႄႈ \"$2\"",
+ "difference-multipage": "(လွင်ႈပႅၵ်ႇပိူင်ႈ ၼႂ်းၵႄႈ ၼႃႈလိၵ်ႈ)",
+ "lineno": "ထႅဝ် $1:",
+ "compareselectedversions": "ၼိူင်းၵၼ်တူၺ်း ၶေႃႈၶူၼ်ႉဢၢၼ်ႇ ၸိူဝ်းလိူၵ်ႈဝႆႉ",
+ "showhideselectedversions": "လႅၵ်ႈလၢႆႈ ၵၢၼ်ႁၼ်လႆႈ ၶွင် ၶေႃႈၶူၼ်ႉဢၢၼ်ႇ ၸိူဝ်းလိူၵ်ႈဝႆႉ",
+ "editundo": "ၶိုၼ်ၶိုၼ်း",
+ "diff-empty": "(ဢမ်ႇမီးလွင်ႈပႅၵ်ႇပိူင်ႈ)",
+ "diff-multi-sameuser": "({{PLURAL:$1|လွင်ႈမႄး ပၢၼ်ၵၢင် |$1 လွင်ႈၸိူဝ်းမႄး ပၢၼ်ၵၢင်}} ပေႃးတႃႇ ၽူႈၸႂ်တိုဝ်းမိူၼ်ၵၼ် တေဢမ်ႇၼႄပၼ်)",
+ "searchresults": "ၶူၼ်ႉႁႃၺႃး",
+ "searchresults-title": "ၶူၼ်ႉႁႃၺႃးတွၼ်ႈတႃႇ \"$1\"",
+ "titlematches": "ႁူဝ်ၶေႃႈ ၼႃႈလိၵ်ႈ ၶူပ်းၵၼ်ယူႇ",
+ "textmatches": "လိၵ်ႈၼႂ်းၼႃႈလိၵ်ႈ ၶူပ်းၵၼ်ယူႇ",
+ "notextmatches": "လိၵ်ႈၼႂ်းၼႃႈလိၵ်ႈ ဢမ်ႇၶူပ်းၵၼ်",
+ "prevn": "ပႃႈၼႃႈ {{PLURAL:$1|$1}}",
+ "nextn": "တေႃႇထႅင်ႈ {{PLURAL:$1|$1}}",
+ "prev-page": "ၼႃႈလိၵ်ႈဢၼ်ပူၼ်ႉမႃး",
+ "next-page": "ၼႃႈလိၵ်ႈတေမႃး",
+ "prevn-title": "သိုပ်ႇၵႂႃႇၸူး $1 {{PLURAL:$1|ၽွၼ်းလႆႈ|ၸိူဝ်းၽွၼ်းလႆႈ}}",
+ "nextn-title": "သိုပ်ႇၵႂႃႇၸူး $1 {{PLURAL:$1|result|ၽွၼ်းလႆႈ}}",
+ "shown-title": "ၼႄ $1 {{PLURAL:$1|result|results}} ၼိူဝ်ၼႃႈလိၵ်ႈၼိူင်ႈၼႃႈ",
+ "viewprevnext": "တူၺ်း ($1 {{int:pipe-separator}} $2) ($3)",
+ "searchmenu-new": "<strong> ၶူင်သၢင်ႈၼႃႈလိၵ်ႈ \"[[:$1]]\" တီႈဝီႇၶီႇၼႆႉ </strong> {{PLURAL:$2|0=|ၼႃႈလိၵ်ႈၼႆႉ ၼႄဝႆႉ ဢၼ်ၸဝ်ႈၵဝ်ႇသွၵ်ႈႁႃ| တူၺ်းၼႃႈလိၵ်ႈဢၼ် ၼႄပၼ် ၸိူဝ်း ဢၼ်ၸဝ်ႈၵဝ်ႇသွၵ်ႈႁႃဝႆ့}}",
+ "searchprofile-articles": "ၼႃႈလိၵ်ႈ ၼမ်းၼႂ်း",
+ "searchprofile-images": "သႅၼ်သိုဝ်ႇၶၢဝ်ႇ",
+ "searchprofile-everything": "ၵူႊဢၼ်",
+ "searchprofile-advanced": "ၸၼ်ႉသုင်",
+ "searchprofile-articles-tooltip": "ႁႃၼႂ်း $1",
+ "searchprofile-images-tooltip": "ႁႃတႃႇၾၢႆႇ",
+ "searchprofile-everything-tooltip": "သွၵ်ႈႁႃလမ်းၼႂ်းတင်းမူတ်း (ဢိၵ်ႇပႃးၼႃႈလိၵ်ႈ ဢုပ်ႇဢူဝ်း)",
+ "searchprofile-advanced-tooltip": "သွၵ်ႈႁႃတီႈၼႂ်း ဢွင်ႈတီႈၸိုဝ်ႈႁင်းတူဝ်",
+ "search-result-size": "$1 ({{PLURAL:$2|1 ၶေႃႈ|$2 ၶေႃႈ}})",
+ "search-redirect": "(ပိၼ်ႇသဵၼ်ႈတၢင်းၸူး $1)",
+ "search-section": "(တွၼ်ႈၵၼ် $1)",
+ "search-category": "(တွၼ်ႈၵၼ် $1)",
+ "search-suggest": "ၶႂ်ႈဝႃႈ $1 - ၼႆႁႃႉ",
+ "search-interwiki-caption": "ၼႃႈၵၢၼ် ပီႈၼွင်ႉၵၼ်",
+ "search-interwiki-default": "ၽွၼ်းလႆႈ ၵႃႈတီႈ $1 :",
+ "search-interwiki-more": "(လိူဝ်)",
+ "search-relatedarticle": "ၸိူဝ်းၵပ်းၵၢႆႇ",
+ "searchrelated": "ၸိူဝ်းၵပ်းၵၢႆႇ",
+ "searchall": "တင်းမူတ်း",
+ "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": "ၵူတ်ႇတူၺ်း :",
+ "powersearch-toggleall": "တင်းမူတ်း",
+ "powersearch-togglenone": "ဢမ်ႇမီးသင်",
+ "powersearch-remember": "တွင်းဝႆႉၵၼ်လိူၵ်ႈၸိူဝ်းၼႆႉ တွၼ်ႈတႃႇ ၸႂ်ႉၵၢၼ်သွၵ်ႈႁႃ မိူဝ်းၼႃႈ",
+ "search-external": "သွၵ်ႈႁႃႈ ၽၢႆၼွၵ်ႈ",
+ "search-error": "မိူဝ်ႈၽွင်းသွၵ်ႈႁႃၼၼ်ႉ မီးလွင်ႈၽိတ်းပိူင်ႈ : $1",
+ "preferences": "ငဝ်ႈၵုမ်းပိူင်",
+ "mypreferences": "လွင်ႈလႆႈၸႂ်လိူဝ်",
+ "prefs-edits": "ၵမ်းၸိူဝ်း မႄးထတ်းမႃး :",
+ "prefsnologintext2": "တႃႇတေလႅၵ်ႈလၢႆႈ ငဝ်ႈၵုမ်းပိူင်ၸဝ်ႈၵဝ်ႇၼၼ်ႉ ၶႅၼ်းတေႃႈ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇလႄႈ။",
+ "prefs-skin": "ၽိဝ်",
+ "skin-preview": "တူၺ်းလူင်ႈၼႃႈ",
+ "datedefault": "ဢမ်ႇမီး ငဝ်ႈၵုမ်းပိူင်",
+ "prefs-user-pages": "ၼႃႈလိၵ်ႈ ၽူႈၸႂ်ႉတိုဝ်း",
+ "prefs-personal": "ပိုၼ်းၵႅပ်ႈ ၽူႈၸႂ်ႉတိုဝ်း",
+ "prefs-rc": "လွင်ႈလႅၵ်ႈလၢႆႈမႂ်ႇမႂ်ႇ",
+ "prefs-watchlist": "သဵၼ်ႈမၢႆပႂ်ႉတူၺ်း",
+ "prefs-editwatchlist": "မႄးထတ်း သဵၼ်ႈမၢႆပႂ်ႉတူၺ်း",
+ "prefs-editwatchlist-label": "မႄးထတ်း ၸိူဝ်းမီးဝႆႉ ၵႃႈတီႈ သဵၼ်ႈမၢႆပႂ်ႉတူၺ်းၸဝ်ႈၵဝ်ႇ",
+ "prefs-editwatchlist-edit": "တူၺ်းသေ ထွၼ်ပႅတ်ႈႁူဝ်ၶေႃႈ ၸိူဝ်းမီးၵႃႈတီး သဵၼ်ႈမၢႆပႂ်ႉတူၺ်း ၸဝ်ႈၵဝ်ႇ",
+ "prefs-editwatchlist-raw": "မႄးထတ်း သဵၼ်ႈမၢႆပႂ်ႉတူၺ်းပိူင်လိူင်း",
+ "prefs-editwatchlist-clear": "ၽဵဝ်ႈလၢင်ႉ သဵၼ်ႈမၢႆပႂ်ႉတူၺ်းၸဝ်ႈၵဝ်ႇ",
+ "prefs-watchlist-days": "ဝၼ်းၸိူဝ်း တႃႇတေၼႄ ၵႃႈတီႈ သဵၼ်ႈမၢႆပႂ်ႉတူၺ်း :",
+ "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": "ၵဵပ်းသိမ်း",
+ "restoreprefs": "ၶိုၼ်းတမ်း ၵၢၼ်တင်ႈတင်းမူတ်း ႁႂ်ႈမိူၼ်ၵဝ်ႇၶိုၼ်း (ၵႃႈတီႈ တွၼ်ႈၵၼ်ၵူႈဢၼ်)",
+ "prefs-editing": "တိုၵ်ႉမႄးထတ်းယူႇ",
+ "rows": "သၢႆတမ်း :",
+ "columns": "သၢႆၸုၵ်း :",
+ "searchresultshead": "ၶူၼ်ႉႁႃ",
+ "stub-threshold-sample-link": "တူဝ်ယၢင်ႇ",
+ "stub-threshold-disabled": "ဢိုတ်းဝႆႉ",
+ "recentchangesdays": "ဝၼ်းၸိူဝ်းဢၼ်တေၼႄ ၵႃႈတီႈၼႂ်း လွင်ႈလႅၵ်ႈလၢႆႈ မႂ်ႇမႂ်ႇ",
+ "recentchangesdays-max": "တီႈၼမ်သုတ်း $1 {{PLURAL:$1|ဝၼ်း|ဝၼ်း။}}",
+ "recentchangescount": "တၢင်းၼမ်ၵၢၼ်မႄးထတ်း ဢၼ်တေၼႄဝႆႉၼင်ႇ ပိူင်ၵႅဝ်ႈ :",
+ "prefs-help-recentchangescount": "ၼႆ့မၼ်းၶဝ်ႈပႃးဝႆႉ လွင်ႈလႅၵ်ႈလၢႆႈ မႂ်ႇမႂ်ႇ၊ ပိုၼ်းၼႃႈလိၵ်ႈ လႄႈ သဵၼ်ႈမၢႆ။",
+ "savedprefs": "လွင်ႈလႆႈၸႂ်ၸဝ်ႈၵဝ်ႇၸိူဝ်းၼၼ်ႉ ထုၵ်ႇသိမ်းဝႆႉပၼ်ယဝ်ႉ။",
+ "savedrights": "သုၼ်ႇလႆႈၽူႈၸႂ်ႉတိုဝ်း {{GENDER:$1|$1}} ၼႆႉ ထုၵ်ႇသိမ်းဝႆႉပၼ်ယဝ်ႉ။",
+ "timezonelegend": "ၼႃႈလိၼ် ၶၢဝ်းယၢမ်း :",
+ "localtime": "ၶၢဝ်းယၢဝ်း ၼႂ်းမိူင်း :",
+ "timezoneuseserverdefault": "ၸႂ်ႉပိူင်ၵႅဝ်ႈ ဝီႇၶီႇ ($1)",
+ "timezoneuseoffset": "တၢင်ႇၸိူဝ်း (မၵ်းမၼ်ႈ ႁႂ်ႈမီးၼမ်ႉတွၼ်း)",
+ "servertime": "ၶၢဝ်းယၢမ်း သႃႇပိူဝ်ႇ :",
+ "guesstimezone": "လုၵ်ႉတီႈ ၶိူင်ႈပိုတ်ႇဝႅပ်ႉသေ ထႅမ်သႂ်ႇ",
+ "timezoneregion-africa": "ဢႃႇၽရိၵ",
+ "timezoneregion-america": "ဢမေႇရိၵ",
+ "timezoneregion-antarctica": "ဢၼ်ႇထႃႇထိၵ",
+ "timezoneregion-arctic": "ဢႃႇတိတ်ႉ",
+ "timezoneregion-asia": "ဢေးသျႃး",
+ "timezoneregion-atlantic": "သမုတ်ႉတရႃႇ ဢတ်ႉလၢၼ်ႇတိတ်ႉ",
+ "timezoneregion-australia": "ဢေႃႇၸထရေးရီးယႃႇ",
+ "timezoneregion-europe": "ရူးရူပ်ႉ",
+ "timezoneregion-indian": "သမုတ်ႉတရႃႇ ဢိၼ်းတီးယၼ်း",
+ "timezoneregion-pacific": "သမုတ်ႉတရႃႇ ၽၸိၽိၵ်ႉ",
+ "allowemail": "ပိုတ်ႇၸႂ်ႉဢီးမေးလ် ဢၼ်ၵႃႈတီႈ ၽူႈၸႂ်ႉတိုဝ်းတၢင်ႇၸိူဝ်း",
+ "prefs-searchoptions": "ၶူၼ်ႉႁႃ",
+ "prefs-namespaces": "ဢွင်ႈတီႈၸိုဝ်ႈ",
+ "default": "ပိူင်ၵႅဝ်ႈ",
+ "prefs-files": "ၾၢႆႇ",
+ "prefs-custom-css": "CSS ႁင်းတူဝ်",
+ "prefs-custom-js": "JavaScript ႁင်းတူဝ်",
+ "prefs-common-css-js": "CSS/Javascript ၸိူဝ်းၽႄႈၸႂ်ႉဝႆႉ တႃႇ ၽိဝ်ၼင်တင်းသဵင်ႈ :",
+ "prefs-reset-intro": "ၸဝ်ႈၵဝ်ႇ တေၸၢင်ႈၸႂ်ႉၼႃႈလိၵ်ႈၼႆႉ တွၼ်ႈတႃႇ တင်ႈၶိုၼ်း လွင်ႈလႆႈၸႂ်ၸဝ်ႈၵဝ်ႇ ၸူးၵႃႈတီႈ သၢႆႉ ပိူင်ၵႅဝ်ႈ။ ၼႆႉမၼ်းတေဢမ်ႇၸၢင်ႈ ၶိုၼ်းမႄးၶိုင်ၶိုၼ်း။",
+ "prefs-emailconfirm-label": "ၶေႃႈၼႄႉၼွၼ်း ဢီးမေးလ် :",
+ "youremail": "ဢီးမေးလ် :",
+ "username": "{{GENDER:$1|ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း}}:",
+ "prefs-memberingroups": "{{GENDER:$2|ၽူႈၶဝ်ႈၸုမ်း}} of {{PLURAL:$1|ၸုမ်း|ၸုမ်း။}}:",
+ "prefs-registration": "ၶၢဝ်းယၢမ်းတၢင်ႇမၢႆၽၢင် :",
+ "yourrealname": "ၶၢဝ်းယၢမ်း တႄႉတႄႉ :",
+ "yourlanguage": "ၽႃႇသႃႇၵႂၢမ်း :",
+ "yournick": "လၢႆးမိုဝ်းမႂ်ႇ :",
+ "gender-male": "မၼ်းမႄးထတ်း ၼႃႈလိၵ်ႈ ဝီႇၶီႇ",
+ "gender-female": "မၼ်းၼၢင်း မႄးထတ်း ၼႃႈလိၵ်ႈဝီႇၶီႇ",
+ "email": "ဢီးမေးလ်",
+ "prefs-help-realname": "ၸိုဝ်ႈတႄႉတႄႉၼၼ်ႉ ပဵၼ်ဢဝ်ၸႂ်ဝႃႈၵူၺ်ႈ။\nသင်ၸိူဝ်ႉဝႃႈ သႂ်ႇပၼ်ၼႆ မၼ်းတေၸၢင်ႈဢဝ်ၵႂႃႇၸႂ်ႉၵႃႈတီႈ ၼႃႈၵၢၼ်ဢၼ်ၸဝ်ႈၵဝ်ႇ ၶဝ်ႈႁူမ်ႈသၢင်ႈဝႆႉၼၼ်ႉဢေႃႈ။",
+ "prefs-help-email": "ႁဵင်းလိၵ်ႈ ဢီးမေးလ်ၵေႃႈ ၵေႃႈ ပဵၼ်ဢဝ်ၸႂ်ဝႃႈၵူၺ်း။ ၵူၺ်းၵႃႈဝႃႈ ပေႃးဝႃႈ ၸဝ်ႈၵဝ်ႇ လိုမ်းၶေႃႈလပ်ႉလႄႈ တေၶႂ်ႈတင်ႈၶိုၼ်း ၶေႃႈလပ်ႉမႂ်ႇၼႆတႄႉ တေလူဝ်ႇ ႁဵင်းလိၵ်ႈဢီးမေးလ်ယဝ်ႉ။",
+ "prefs-help-email-required": "တေလူဝ်ႇႁဵင်းလိၵ်ႈဢီးမေးလ်",
+ "prefs-info": "လွၼ်ႉၶၢဝ်ႈ ပိုၼ်ႉထၢၼ်",
+ "prefs-i18n": "ၵၢၼ်ၵူႈမိူင်းမိူင်း",
+ "prefs-signature": "လၢႆးမိုဝ်း",
+ "prefs-dateformat": "ပိူင်ဝၼ်း",
+ "prefs-timeoffset": "ၶူပ်းၶၢဝ်းယၢမ်း",
+ "prefs-advancedediting": "ၵၢၼ်လၵ်ႈသၢင်ႈ ၵူႈလွင်ႈ",
+ "prefs-editor": "ၽူႈမႄးထတ်း",
+ "prefs-preview": "တူၺ်းလူင်ႈၼႃႈ",
+ "prefs-advancedrc": "ၵၼ်လိူၵ်ႈသၢင်ႈ ၶိုၵ်ႉတွၼ်း",
+ "prefs-advancedrendering": "ၵၢၼ်လိူၵ်ႈသၢင်ႈ ၶိုၵ်ႉတွၼ်း",
+ "prefs-advancedsearchoptions": "ၵၢၼ်လိူၵ်ႈသၢင်ႈ ၶိုၵ်ႉတွၼ်း",
+ "prefs-advancedwatchlist": "ၵၼ်လိူၵ်ႈသၢင်ႈ ၶိုၵ်ႉတွၼ်း",
+ "prefs-displayrc": "ၼႄပၼ် ၵၢၼ်လိူၵ်ႈသၢင်ႈ",
+ "prefs-displaywatchlist": "ၼႄပၼ် ၵၢၼ်လိူၵ်ႈသၢင်ႈ",
+ "prefs-tokenwatchlist": "မၢႆၶပ်ႉ",
+ "prefs-diffs": "လွင်ႈပႅၵ်ႇပိူင်ႈ",
+ "prefs-help-prefershttps": "ငဝ်ႈၵုမ်းၵၢၼ်ၼႆႉ ပေႃးဝႃႈ ၶိုၼ်းၶဝ်ႈလွၵ်ႉဢိၼ်ႇထႅင်ႈၵမ်းၼင်ႇ ၸင်ႇတေလႅၵ်ႈလၢႆႈ။",
+ "userrights": "လွင်ႈၸတ်းၵၢၼ်သုၼ်ႈလႆႈ ၽူႈၸႂ်ႉတိုတ်း",
+ "userrights-lookup-user": "ၸတ်းၵၢၼ် ၸုမ်းၽူႈၸႂ်ႉတိုဝ်း",
+ "userrights-user-editname": "ပေႃႇသႂ်ႇပၼ် ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း :",
+ "editusergroup": "မႄးထတ်း {{GENDER:$1|ၽူႈၸႂ်ႉတိုဝ်း}} ၸုမ်း",
+ "editinguser": "လႅၵ်ႈလၢႆႈသုၼ်ႇလႆႈ ၽူႈၸႂ်ႉတိုဝ်း ၶွင် {{GENDER:$1|ၽူႈၸႂ်ႉတိုဝ်း}} <strong>[[User:$1|$1]]</strong> $2",
+ "userrights-editusergroup": "မႄးထတ်းၸိူဝ်းၸုမ်း ၽူႈၸႂ်ႉတိုဝ်း",
+ "saveusergroups": "သိမ်း ၸိူဝ်းၸုမ်း {{GENDER:$1|ၽူႈၸႂ်ႉတိုဝ်း}}",
+ "userrights-groupsmember": "ၽူႈၶဝ်ႈၸုမ်း ၶွင် :",
+ "userrights-groupsmember-auto": "ၽူႈၶဝ်ႈၸုမ်းပႃးဝႆႉ ၶွင် :",
+ "userrights-reason": "လွင်ႈတၢင်း :",
+ "userrights-no-interwiki": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇမီးသုၼ်ႇၶႂၢင်းပၼ် တွၼ်ႈတႃႇ မႄးထတ်း သုၼ်ႇၽူႈၸႂ်ႉတိုဝ်းၵႃႈတီႈဝီႇၶီႇ တၢင်ႇဢၼ်။",
+ "userrights-nodatabase": "ယွင်ၶေႃႈမုၼ်း $1 ၼႆႉဢမ်ႇမီး ဢမ်ႇၼၼ် မၼ်းဢမ်ႇၸႂ်ႈ လူဝ်ႇၵႄႇ။",
+ "userrights-notallowed": "ၸဝ်ႈၵဝ်ႇဢမ်ႇလႆႈမီးသုၼ်ႇၶႂၢင်းပၼ် တွၼ်ႈတႃႇ တေထႅမ်သႂ်ႇ ဢမ်ႇၼၼ် ထွၼ်ပႅတ်ႈ သုၼ်ႇလႆႈ ၽူႈၸႂ်ႉတိုဝ်း",
+ "userrights-changeable-col": "ၸုမ်း ၸိူဝ်းၸဝ်ႈၵဝ်ႇ ၸၢင်ႈလႅၵ်ႈလၢႆႈ",
+ "userrights-unchangeable-col": "ၸုမ်း ၸိူဝ်းၸဝ်ႈၵဝ်ႇ ဢမ်ႇၸၢင်ႈလႅၵ်ႈလၢႆႈ",
+ "userrights-conflict": "လွင်ႈလႅၵ်ႈလၢႆႈ သုၼ်ႇၽူႈၸႂ်ႉတိုဝ်းၼၼ်ႉ မီးလွင်ႈယုင်ႈယၢင်ႈဝႆႉ။ ၶႅၼ်းတေႃႈ ၶိုၼ်းထတ်းတူၺ်းပၼ် သေ ၶိုၼ်းၼႄႉၼွၼ်းပၼ် လွင်ႈလႅၵ်ႈလၢႆႈၸဝ်ႈၵဝ်ႇလႄႈ။",
+ "userrights-removed-self": "ၸဝ်ႈၵဝ်ႇထွၼ်ပႅတ်ႇ သုၼ်ႇလႆႈတူဝ်ၸဝ်ႈၵဝ်ႇ။ ယွၼ်ႉၼၼ်လႄႈ ၸဝ်ႈၵဝ်ႇ တေဢမ်ႇၸၢင်ႈၶဝ်ႈၸႂ်ႉ ၼႃႈလိၵ်ႈၼႆႉလႆႈယဝ်ႉ။",
+ "group": "ၸုမ်း :",
+ "group-user": "ၽူႈၸႂ်ႉတိုဝ်း",
+ "group-autoconfirmed": "ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းၼႄႉၼွၼ်းတူဝ်ႁင်းၵူၺ်း",
+ "group-bot": "ပွတ်ႉ",
+ "group-sysop": "ၽူႈၵုမ်းၵၢၼ်ၶဝ်",
+ "group-bureaucrat": "ၸဝ်ႈၼႃႈတီႈၶဝ်",
+ "group-suppress": "ၽူႈတဵၵ်းတဵင်ၶဝ်",
+ "group-all": "(တင်းမူတ်း)",
+ "group-user-member": "{{GENDER:$1|ၽူႈၸႂ်ႉတိုဝ်း}}",
+ "group-autoconfirmed-member": "{{GENDER:$1|ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းၼႄႉၼွၼ်းတူဝ်ႁင်းၵူၺ်း}}",
+ "group-bot-member": "{{GENDER:$1|ပွတ်ႉ}}",
+ "group-sysop-member": "{{GENDER:$1|ၽူႈၵုမ်းၵၢၼ်}}",
+ "group-bureaucrat-member": "{{GENDER:$1|ၸဝ်ႈၼႃႈတီႈ}}",
+ "group-suppress-member": "{{GENDER:$1|ၽူႈတဵၵ်းတဵင်}}",
+ "grouppage-user": "{{ns:project}}:ၽူႈၸႂ်ႉတိုဝ်းၶဝ်",
+ "grouppage-autoconfirmed": "{{ns:project}}:ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းၼႄႉၼွၼ်းတူဝ်ႁင်းၵူၺ်း",
+ "grouppage-bot": "{{ns:project}}:ပွတ်ႉၶဝ်",
+ "grouppage-sysop": "{{ns:project}}:ၽူႈၵုမ်းၵၢၼ်ၶဝ်",
+ "grouppage-bureaucrat": "{{ns:project}}:ၸဝ်ႈၼႃႈတီႈၶဝ်",
+ "grouppage-suppress": "{{ns:project}}:တဵၵ်းတဵင်",
+ "right-read": "လူ ၼႃႈလိၵ်ႈ",
+ "right-edit": "မႄးထတ်း ၼႃႈလိၵ်ႈ",
+ "right-createpage": "ၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈ (ၸိူဝ်းဢၼ်ဢမ်ႇၸႂ်ႈ ၼႃးလိၵ်ႈဢုပ်ႇဢူဝ်းၵၼ်)",
+ "right-createtalk": "ၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈ ဢုပ်ႇဢူဝ်းၵၼ်",
+ "right-createaccount": "ၵေႃႇသၢင်ႈ ဢၶွင်ႉ ၽူႈၸႂ်ႉတိုဝ်း ဢၼ်မႂ်ႇ",
+ "right-autocreateaccount": "ဢဝ် ဢၶွင်ႉၽူႈၸႂ်ႉတိုဝ်း ၽၢႆႇၼွၵ်ႈသေ ၶဝ်ႈလွၵ်ႉဢိၼ်ႇႁင်းတူဝ်",
+ "right-minoredit": "မၢႆၵၢၼ်မႄးထတ်း ၼင်ႇ ၵၢၼ်ၼွႆႉ",
+ "right-move": "ၶၢႆႉ ၼႃႈလိၵ်ႈ",
+ "right-move-subpages": "ၶၢႆ့ၼႃႈလိၵ်ႈ ဢိၵ်ႇ ၼႃႈလိၵ်ႈၽႄၶဝ်",
+ "right-move-rootuserpages": "ၶၢႆ့ၼႃႈလိၵ်ႉ ၽူႈၸႂ်ႉတိုဝ်း ငဝ်ႈႁၢၵ်ႈ",
+ "right-move-categorypages": "ၶၢႆ့ၼႃႈလိၵ်ႈ တွၼ်ႈၵၼ်",
+ "right-movefile": "ၶၢႆ့ၾၢႆႇ",
+ "right-suppressredirect": "ၽွင်းတိုၵ်ႉၶၢႆ့ၼႃႈလိၵ်ႈယူႇၼၼ်ႉ တေဢမ်ႇသၢင်ႈ တူဝ်ပိၼ်ႇၸီႉ ၵႃႈတီႈ ၼႃႈလိၵ်ႈ ငဝ်ႈငႃႇ",
+ "right-upload": "လူတ်ႇၶိုၼ်ႈ ၾၢႆႇ",
+ "right-reupload": "သႂ်ႇတဵင်ၵႂႃႇ ၼိူဝ် ၾၢႆႇဢၼ်မီးဝႆႉၼၼ်ႉ",
+ "right-reupload-own": "ဢဝ် ဢၼ်သေၵေႃႉၵေႃႉ လူတ်ႇၶိုၼ်ႈမႃးၼၼ်ႉ သႂ်ႇတဵင်ၵႂႃႇၼိူဝ်ၾၢႆႇ ဢၼ်မီးဝႆ့",
+ "right-upload_by_url": "လုၵ်ႉတီႈ URL သေ လူတ်ႇၶိုၼ်ႈ ၾၢႆႇ",
+ "right-purge": "ၽဵဝ်ႈလၢင်ႈ ၶေႃႈမုၼ်းသၢႆႉ တွၼ်ႈတႃႇ ၼႃႈလိၵ်ႈၼႆႉ ဢမ်ႇတၢပ်ႇလူဝ်ႇ ၶေႃႈၼႄႉၼွၼ်း။",
+ "right-writeapi": "ၸႂ်ႉတိုဝ်း လွင်ႈတႅမ်ႈ API",
+ "right-delete": "မွတ်ႇပႅတ်ႈ ၼႃႈလိၵ်ႈ",
+ "right-bigdelete": "မွတ်ႇပႅတ်ႈၼႃႈ ဢၼ်ၸိူၵ်းမီးဝႆႉ ပိုၼ်းယႂ်ႇၵႂၢင်ႈ",
+ "right-deletelogentry": "မွတ်ႇပႅတ်ႈ လႄႈ ဢမ်ႇမွတ်ႇပႅတ်ႈ သဵၼ်ႈမၢႆသႂ်ႇသေ မၵ်းမၼ်ႈဝႆႉ",
+ "right-deleterevision": "မွတ်ႇပႅတ်ႈ လႄႈ ဢမ်ႇမွတ်ႇပႅတ်ႈ ပိူဝ်းသျိၼ်းၼႃႈလိၵ်ႈ ၸိူဝ်းမၵ်းမၼ်ႈဝႆႉ",
+ "right-deletedhistory": "တူၺ်း ပိုၼ်းၸိူဝ်းသႂ်ႇဝႆႉ ဢၼ်လႆႈမွတ်ႇပႅတ်ႈၵႂႃႇ၊ ဢမ်ႇတၢပ်ႈလူဝ်ႇ လိၵ်ႈဢၼ်ၵွင်ႉၵၢႆႇ ၶဝ်ဝႆႉ။",
+ "right-deletedtext": "တူၺ်း လိၵ်ႈၸိူဝ်းမွတ်ႇပႅတ်ႈဝႆႉလႄႈ လႅၵ်ႈလၢႆႈပၼ် ၼႂ်းၵႄႈ ပိူဝ်းသျိၼ်း ၸိူဝ်းမွတ်ႇပႅတ်ႈဝႆႉ။",
+ "right-browsearchive": "ၶူၼ်ႉႁႃ ၼႃႈလိၵ်ႈ ၸိူဝ်းမွတ်ႇပႅတ်ႈၵႂႃႇ",
+ "right-undelete": "ဢဝ်ၶိုၼ်း ၼႃႈလိၵ်ႈ",
+ "right-suppressrevision": "တူၺ်း၊ သိူင်ႇလပ်ႉ လႄႈ ၼႄၶိုၼ်း ၶေႃႈၶူၼ်ႉလူ ၼႃႈလိၵ်ႈၸိူဝ်းမၵ်းမၼ်ႈဝႆႉ ၵႃႈတီႈ ၽူႈၸႂ်ႉတိုဝ်း သေၵေႃႉၵေႃႉ",
+ "right-viewsuppressed": "တူၺ်း ၶေႃႈၶူၼ်ႉလူ ဢၼ်သိူင်ႇဝႆႉ ၵႃႈတီႈ ၽူႈၸႂ်ႉတိုဝ်း သေၵေႃႉၵေႃႉ",
+ "right-suppressionlog": "တူၺ်း သဵၼ်ႈမၢႆႇ သုၼ်ႇတူဝ်",
+ "right-block": "ႁႄႉတတ်း ၽူႈၸႂ်ႉတိုဝ်းတၢင်ႇၸိူဝ်း ၵႃႈတီႈ ၵၢၼ်မႄးထတ်း",
+ "right-blockemail": "ႁႄႉတတ်း ၽူႈၸႂ်ႉတိုဝ်း ၵႃႈတီႈ သူင်ႇဢီးမေးလ်",
+ "right-hideuser": "ႁႄႉတတ်း ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း၊ လပ်ႉမၼ်းဝႆႉ ၵႃႈတီႈ ၵူၼ်ႈတၢင်းၼမ်",
+ "right-unblockself": "ၶိုၼ်းပိုတ်ႇႁႄႉတတ်း ပၼ် ႁင်းၸဝ်ႈၵဝ်ႇ",
+ "right-editprotected": "မႄးထတ်း ၼႃႈလိၵ်ႈၸိူဝ်း ႁႄႉၵင်ႈဝႆႉ ၼင်ႇ \"{{int:protect-level-sysop}}\"",
+ "right-editsemiprotected": "မႄးထတ်းၼႃႈလိၵ်ႈၸိူဝ်း ႁႄႉၵင်ႈဝႆႉၼင်ႇ \"{{int:protect-level-autoconfirmed}}\"",
+ "right-editcontentmodel": "မႄးထတ်း ၽၢင်ႁၢင်ႈတူဝ်ၶဝ်ႈပႃး ၶွင်ၼႃႈလိၵ်ႈ",
+ "right-editinterface": "မႄးထတ်း ယူင်ႉႁၢင်ႈ ၽူႈၸႂ်ႉတိုဝ်း",
+ "right-editusercssjs": "မႄးထတ်းၾၢႆႇ CSS လႄႈ JavaScript ၶွင် ၽူႈၸႂ်ႉတိုဝ်းတၢင်ႇၸိူဝ်း",
+ "right-editusercss": "မႄးထတ်း ၾၢႆႇ CSS ၶွင် ၽူႈၸႂ်ႉတိုဝ်းတၢင်ႇၸိူဝ်း",
+ "right-edituserjs": "မႄးထတ်း ၾၢႆႇ JavaScript ၶွင် ၽူႈၸႂ်ႉတိုဝ်း တၢင်ႇၸိူဝ်း",
+ "right-editmyusercss": "မႄးထတ်း ၾၢႆႇ CSS ၶွင်ႁင်းၸဝ်ႈၵဝ်ႇ",
+ "right-editmyuserjs": "မႄးထတ်း ၾၢႆႇ JavaScript ၶွင်ႁင်းၸဝ်ႈၵဝ်ႇ",
+ "right-viewmywatchlist": "တူၺ်း သဵၼ်ႈမၢႆပႂ်ႉတူၺ်း ႁင်းၶွင်ၵဝ်ႇ",
+ "right-editmywatchlist": "မႄးထတ်း သဵၼ်ႈမၢႆပႂ်ႉတူၺ်း ႁင်းတူဝ်ၵဝ်ႇ။ မၢႆတွင်းဝႆႉဝႃႈ လွင်ႈႁဵတ်းသၢင်ႈ ၵမ်ႈၽွင်ႈၼႆႉ ႁူမ်ႈဝႃႈဢမ်ႇမီးသုၼ်ႇၵေႃႈ တိုၵ်ႉတေထႅမ်သႂ်ႇ ၼႃႈလိၵ်ႈၵႂႃႇယူႇ။",
+ "right-viewmyprivateinfo": "တူၺ်း ၶေႃႈမုၼ်း သုၼ်ႇတူဝ် ၸဝ်ႈၵဝ်ႇ (တူဝ်ယၢင်ႇ ႁဵင်းလိၵ်ႈ ဢီးမေးလ်၊ ၸိုဝ်ႈတေႉတေႉ)",
+ "right-editmyprivateinfo": "မႄးထတ်း ၶေႃႈမုၼ်းသုၼ်ႇတူဝ် ၸဝ်ႈၵဝ်ႇ (တူဝ်ယၢင်ႇ ႁဵင်းလိၵ်ႈ ဢီးမေးလ်၊ ၸိုဝ်ႈတေႉတေႉ)",
+ "right-editmyoptions": "မႄးထတ်း ငဝ်ႈၵုမ်းပိူင် ၶွင်တူဝ်ၵဝ်ႇ",
+ "right-import": "ဢဝ်ၼႃႈလိၵ်ႈ ၸိူဝ်းလုၵ်ႉၵႃႈတီႈ ဝီႇၶီႇတၢင်ႇၸိူဝ်း သႂ်ႇၶဝ်ႈ",
+ "right-importupload": "ဢဝ်ၼႃႈလိၵ်ႈၸိူဝ်း ၵႃႈတီႈၾၢႆႇလူတ်ႇၶိုၼ်ႈၼၼ်ႉ သႂ်ႇၶဝ်ႈ",
+ "right-unwatchedpages": "တူၺ်းသဵၼ်ႈမၢႆ ၼႃႈလိၵ်ႈတူၺ်း ဢမ်ႇပႆႇလႆႈတူၺ်းဝႆႉၼၼ်ႉ",
+ "right-mergehistory": "ဢဝ်ပိုၼ်းၶွင်ၼႃႈလိၵ်ႈ ႁူမ်ႈၵၼ်",
+ "right-userrights": "မႄးထတ်းသုၼ်ႇလႆႈ တႃႇၽူႈၸႂ်ႉတိုဝ်း တင်းသဵင်ႈ",
+ "right-userrights-interwiki": "မႄးထတ်း သုၼ်ႇလႆႈ ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းပဵၼ် ၽူႈၸႂ်ႉတိုဝ်း ဢၼ်မီးဝႆႉယူႇ ၵႃႈတီႈၼိူဝ် ဝီႇၶီႇတၢင်ႇၸိူဝ်း",
+ "right-siteadmin": "ၶတ်းသေႃး လႄႈ ဢမ်ႇၶတ်းသေႃး ယွင်ၶေႃႈမုၼ်း",
+ "right-sendemail": "သူင်ႇဢီးမေးလ်ၸူး ၽူႈၸႂ်ႉတိုဝ်း တၢင်ႇၸိူဝ်း",
+ "right-passwordreset": "တူၺ်း ဢီးမေး တင်ႈၶိုၼ်း ၶေႃႈလပ်ႉ",
+ "right-managechangetags": "ၵေႃႇသၢင်ႈ လႄႈ (ဢမ်ႇ) တူင်ႉတိုၼ်ႇ [[Special:Tags|tags]]",
+ "right-deletechangetags": "မွတ်ႇပႅတ်ႈ [[Special:Tags|tags]] ၵႃႈတီႈ ယွင်ၶေႃႈမုၼ်း",
+ "grant-generic": "\"$1\" ထုပ်ႉႁေႃႇ သုၼ်ႇလႆႈ",
+ "grant-group-page-interaction": "ႁႂ်ႈမီးၽွၼ်းလီတင်း ၼႃႈလိၵ်ႈ",
+ "grant-group-file-interaction": "ႁႂ်ႈမီးၽွင်းလီတင်း သိုဝ်ႇၶၢဝ်ႇ",
+ "grant-group-watchlist-interaction": "ႁႂ်းမီးၽွၼ်းလီတင်း သဵၼ်ႈမၢႆပႂ်ႉတူၺ်းၸဝ်ႈၵဝ်ႇ",
+ "grant-group-email": "သူင်ႇ ဢီးမေးလ်",
+ "grant-group-high-volume": "ႁဵၼ်းၵၢၼ်တူင်ႉၼိုင် ဢၼ်ႁႅင်းယႂ်ႇ",
+ "grant-blockusers": "ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းႁႄႉတတ်း လႄႈ ဢမ်ႇႁႄႉတတ်း",
+ "grant-createaccount": "ၵေႃႇသၢင်ႈဢၶွင်ႉ",
+ "grant-createeditmovepage": "ၵေႃႇသၢင်ႈ၊ မႄးထတ်း လႄႈ ၶၢႆႉဢွင်ႈ ၼႃႈလိၵ်ႈ",
+ "grant-delete": "မွတ်ႇ ၼႃႈလိၵ်ႈ၊ ၶူၼ်ႉလူ လႄ သဵၼ်ႈမၢႆ သႂ်ႇၶဝ်ႈ",
+ "grant-editinterface": "မႄးထတ်း လွၵ်းၸိုဝ်ႈ သိုဝ်ႇၶၢဝ်ႇဝီႇၶီႇ လႄႈ ၽူႈၸႂ်ႉတိုဝ်း CSS/JavaScript",
+ "grant-editmycssjs": "မႄးထတ်း ၽူႈၸႂ်ႉတိုဝ်း CSS/JavaScript ၸဝ်ႈၵဝ်ႇ",
+ "grant-editmyoptions": "မႄးထတ်း ငဝ်ႈၵုမ်းပိူင် ၽူႈၸႂ်ႉတိုဝ်း ၶွင်ၸဝ်ႈၵဝ်ႇ",
+ "grant-editmywatchlist": "မႄးထတ်း သဵၼ်ႈမၢႆပႂ်ႉတူၺ်းၸဝ်ႈၵဝ်ႇ",
+ "grant-editpage": "မႄးထတ်း ၼႃႈလိၵ်ႈ မီးယူႇ ယၢမ်းလဵဝ်ၼႆႉ",
+ "grant-editprotected": "မႄးထတ်း ၼႃႈလိၵ်ႈၸိူဝ်း ႁႄႉၵင်ႈဝႆႉ",
+ "grant-highvolume": "ၵၢၼ်မႄးထတ်း ဢၼ်ယႂ်ႇၵႂၢင်ႈ",
+ "grant-oversight": "လပ်ႉဝႆႉ ၽူႈၸႂ်ႉတိုဝ်း လႄႈ တဵၵ်းတဵင် ၶေႃႈၶူၼ်ႉလူ",
+ "grant-sendemail": "သူင်ႇဢီးမေးလ်ၸူး ၽူႈၸႂ်ႉတိုဝ်း တၢင်ႇၸိူဝ်း",
+ "grant-uploadeditmovefile": "လူတ်ႇၶိုၼ်ႈ၊ တၢင်တီႈ လႄႈ ၶၢႆႉၾၢႆႇ",
+ "grant-uploadfile": "လူတ်ႇၶိုၼ်ႈ ၾၢႆႇဢၼ်မႂ်ႇ",
+ "grant-basic": "သုၼ်ႇပိုၼ်ႉထၢၼ်",
+ "grant-viewdeleted": "တူၺ်း ၾၢႆႇလႄႈ ၼႃႈလိၵ်ႈ ၸိူဝ်းမွတ်ႇပႅတ်ႈယဝ်ႉ။",
+ "grant-viewmywatchlist": "တူၺ်း သဵၼ်ႈမၢႆပႂ်ႉတူၺ်း ႁင်းၶွင်ၵဝ်ႇ",
+ "newuserlogpage": "သၢႆမၢႆလွင်ႈၵေႃႇသၢင်ႈ ၽူႈၸႂ်ႉတိုဝ်း",
+ "newuserlogpagetext": "ဢၼ်ၼႆႉပဵၼ် သဵၼ်ႈမၢႆ လွင်ႈၵေႃႇသၢင်ႈ ၽူႈၸႂ်ႉတိုဝ်း။",
+ "rightslog": "သဵၼ်ႈမၢႆ သုၼ်ႇလႆႈ ၽူႈၸႂ်ႉတိုဝ်း",
+ "rightslogtext": "ဢၼ်ၼႆႉပဵၼ် သဵၼ်ႈမၢႆ လွင်ႈလႅၵ်ႈလၢႆႈ သုၼ်ႈလႆႈ ၽူႈၸႂ်ႉတိုဝ်း",
+ "action-read": "လူၼႃႈလိၵ်ႈၼႆႉ",
+ "action-edit": "မူၼ်ႉမႄး ၼႃႈလိၵ်ႈၼႆႉ",
+ "action-createpage": "ၵေႃႈသၢင်ႈ ၼႃႈလိၵ်ႈ",
+ "action-createtalk": "ၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈ ဢုပ်ႇဢူဝ်းၵၼ်",
+ "action-createaccount": "ၵေႃႇသၢင်ႈ ဢၶွင်ႉၽူႈၸႂ်ႉတိုဝ်း ဢၼ်ၼႆႉ",
+ "action-autocreateaccount": "ၵေႃႇသၢင်ႈ ဢၶွင်ႉၽူႈၸႂ်ႉတိုဝ်း ၽၢႆႇၼွၵ်ႈ ႁင်းတူဝ်",
+ "action-history": "တူၺ်း ပိုၼ်းၼႃႈလိၵ်ႈဢၼ်ၼႆႉ",
+ "action-minoredit": "မၢႆလွင်ႈမႄးထတ်း ဢၼ်ၼႆႉ ႁႂ်ႈပဵၼ် ၵၢၼ်ၼွႆႉ",
+ "action-move": "ၶၢႆႉဢွင်ႈ ၼႃႈလိၵ်ႈၼႆႉ",
+ "action-move-subpages": "ၶၢႆႉဢွင်ႈ ၼႃႈလိၵ်ႈၼႆႉ လႄႈ ဢိၵ်ႇတင်း ၼႃႈလိၵ်ႈၽႄမၼ်း",
+ "action-move-rootuserpages": "ၶၢႆ့ၼႃႈလိၵ်ႉ ၽူႈၸႂ်ႉတိုဝ်း ငဝ်ႈႁၢၵ်ႈ",
+ "action-move-categorypages": "ၶၢႆ့ၼႃႈလိၵ်ႈ တွၼ်ႈၵၼ်",
+ "action-movefile": "ၶၢႆႉဢွင်ႈ ၾၢႆႇဢၼ်ၼႆႉ",
+ "action-upload": "လူတ်ႇၶိုၼ်ႈ ၾၢႆႇဢၼ်ၼႆႉ",
+ "action-reupload": "သႂ်ႇတဵင်ၵႂႃႇ ၼိူဝ် ၾၢႆႇဢၼ်မီးဝႆႉၼၼ်ႉ",
+ "action-reupload-shared": "ဢဝ်ၾၢႆႇၼႆႉ သႂ်ႇတဵင်ၵႂႃႇ ၵႃႈတီႈၼိူဝ် ယွင်ဢၼ်ၽႄႈၸႂ်ႉဝႆႉၼၼ်ႉ",
+ "action-upload_by_url": "လုၵ်ႉၵႃႈတီႈ URL သေ လူတ်ႇၶိုၼ်ႈ ၾၢႆႇဢၼ်ၼႆႉ",
+ "action-writeapi": "ၸႂ်ႉတိုဝ်း လွင်ႈတႅမ်ႈ API",
+ "action-delete": "မွတ်ႇပႅတ်ႈၼႃႈလိၵ်ႈၼႆႉ",
+ "action-deleterevision": "မွတ်ႇပႅတ်ႈ ၶေႃႈၶူၼ်ႉလူဢၼ်ၼႆႉ",
+ "action-deletedhistory": "တူၺ်း ပိုၼ်းၸိူဝ်းမွတ်ႇပႅတ်ႈ ၶွင်ၼႃႈလိၵ်ႈၼႆႉ",
+ "action-browsearchive": "ၶူၼ်ႉႁႃ ၼႃႈလိၵ်ႈ ၸိူဝ်းမွတ်ႇပႅတ်ႈၵႂႃႇ",
+ "action-undelete": "ဢဝ်ၶိုၼ်း ၼႃႈလိၵ်ႈၼႆ့",
+ "action-suppressrevision": "တူၺ်းထတ်းၶိုၼ်း လႄႈ ၶိုၼ်းဢဝ် ၶေႃႈၶူၼ်ႉႁႃဢၼ်လပ်ႉသိူင်ႇဝႆႉ",
+ "action-suppressionlog": "တူၺ်း သဵၼ်ႈမၢႆ သုၼ်ႇတူဝ်",
+ "action-block": "ႁႄႉတတ်း ၽူႈၸႂ်ႉတိုဝ်းတၢင်ႇၸိူဝ်း ၵႃႈတီႈ ၵၢၼ်မႄးထတ်း",
+ "action-protect": "လႅၵ်ႈလၢႆႈၸၼ်ႉထၢၼ်ႈ ၵၢၼ်ႁႄႉၵင်ႈ တွၼ်ႈတႃႇ ၼႃႈလိၵ်ႈၼႆႉ",
+ "action-import": "ဢဝ်ၼႃႈလိၵ်ႈ ၸိူဝ်းလုၵ်ႉၵႃႈတီႈ ဝီႇၶီႇတၢင်ႇၸိူဝ်း သႂ်ႇၶဝ်ႈ",
+ "action-importupload": "ဢဝ်ၼႃႈလိၵ်ႈၸိူဝ်း ၵႃႈတီႈၾၢႆႇလူတ်ႇၶိုၼ်ႈၼၼ်ႉ သႂ်ႇၶဝ်ႈ",
+ "action-unwatchedpages": "တူၺ်းသဵၼ်ႈမၢႆ ၼႃႈလိၵ်ႈတူၺ်း ဢမ်ႇပႆႇလႆႈတူၺ်းဝႆႉၼၼ်ႉ",
+ "action-mergehistory": "ဢဝ်ပိုၼ်းၶွင်ၼႃႈလိၵ်ႈ ႁူမ်ႈၵၼ်",
+ "action-userrights": "မႄးထတ်းသုၼ်ႇလႆႈ တႃႇၽူႈၸႂ်ႉတိုဝ်း တင်းသဵင်ႈ",
+ "action-userrights-interwiki": "မႄးထတ်း သုၼ်ႇလႆႈ ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းပဵၼ် ၽူႈၸႂ်ႉတိုဝ်း ဢၼ်မီးဝႆႉယူႇ ၵႃႈတီႈၼိူဝ် ဝီႇၶီႇတၢင်ႇၸိူဝ်း",
+ "action-siteadmin": "ၶတ်းသေႃး လႄႈ ဢမ်ႇၶတ်းသေႃး ယွင်ၶေႃႈမုၼ်း",
+ "action-sendemail": "သူင်ႇ ဢီးမေးလ်",
+ "action-editmywatchlist": "မႄးထတ်း သဵၼ်ႈမၢႆပႂ်ႉတူၺ်းၸဝ်ႈၵဝ်ႇ",
+ "action-viewmywatchlist": "တူၺ်း သဵၼ်ႈမၢႆပႂ်ႉတူၺ်း ႁင်းၶွင်ၵဝ်ႇ",
+ "action-viewmyprivateinfo": "တူၺ်း လွၼ်ႉၶၢဝ်ႇသုၼ်ႇတူဝ် ၸဝ်ႈၵဝ်ႇ",
+ "action-editmyprivateinfo": "မႄးထတ်း လွၼ်ႉၶၢဝ်ႇသုၼ်ႇတူဝ် ၸဝ်ႈၵဝ်ႇ",
+ "action-editcontentmodel": "မႄးထတ်း ၽၢင်ႁၢင်ႈတူဝ်ၶဝ်ႈပႃး ၶွင်ၼႃႈလိၵ်ႈ",
+ "action-managechangetags": "ၵေႃႇသၢင်ႈ လႄႈ (ဢမ်ႇ)တူင်ႉတိုၼ်ႇ တူဝ်တိင်",
+ "action-applychangetags": "တိင်ၸပ်းၸွမ်းၼင်ႇ လွင်ႈလႅၵ်ႈလၢႆႈၸဝ်ႈၵဝ်ႇ",
+ "action-deletechangetags": "မွတ်ႇပႅတ်ႈ တိင်ႇၸိူဝ်းမီးယူႇ ၵႃႈတီႈ ယွင်ၶေႃႈမုၼ်း",
+ "nchanges": "$1 {{PLURAL:$1|လႅၵ်ႈလၢႆႈ|ၸိူဝ်းလႅၵ်ႈလၢႆႈ}}",
+ "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ၸဵမ်မိူဝ်ႈ ၵႂႃႇဢႅတ်ႇပွၵ်ႈၵမ်းလိုၼ်း}}",
+ "enhancedrc-history": "ပိုၼ်း",
+ "recentchanges": "မီးလွင်ႈလႅၵ်ႈလၢႆႈပႆႇႁိုင်",
+ "recentchanges-legend": "ၵၼ်လိူၵ်ႈသၢင်ႈ လွင်ႈလႅၵ်ႈလၢႆႈဢၼ်ပူၼ်ႉမႃး",
+ "recentchanges-summary": "ၸွမ်းတူၺ်းႁွႆး ဢၼ်ပဵၼ်ၵၢၼ် တိုၵ်ႉႁႃလႅၵ်ႈလၢႆႈၵႂႃႇ တွၼ်ႈတႃႇၼႃႈလိၵ်ႈ ဝီႇၶီႇၼႆႉ။",
+ "recentchanges-feed-description": "ၸွမ်းတူၺ်းႁွႆး ဢၼ်ပဵၼ်ၵၢၼ် တိုၵ်ႉႁႃလႅၵ်ႈလၢႆႈၵႂႃႇ တွၼ်ႈတႃႇၼႃႈလိၵ်ႈ ဝီႇၶီႇၼႆႉ။",
+ "recentchanges-label-newpage": "လွင်ႈမႄးထတ်းဢၼ်ၼႆႉ ၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈဢၼ်မႂ်ႇယဝ်ႉ",
+ "recentchanges-label-minor": "ပဵၼ်လွင်ႈမူၼ်ႉမႄးဢိတ်းဢီႈ",
+ "recentchanges-label-bot": "လွင်ႈမႄးထတ်းဢၼ်ၼႆႉ ပမၼ်းပဵၼ် bot ၵေႃႉႁဵတ်းၵႂႃႇ",
+ "recentchanges-label-unpatrolled": "ၶေႃႈထတ်းၼႆႉ ပႆႉၼႅၼ်ႈၼႃ",
+ "recentchanges-label-plusminus": "သႅၼ်းၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇလႅၵ်ႈလၢႆႈ ၸွမ်းၼင်ႇ မၢႆ bytes ဢၼ်ၼႆႉ",
+ "recentchanges-legend-heading": "<strong>ဢပုမ်ႇ:</strong>",
+ "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (တူၺ်းပႃးထႅင်ႈ [[Special:NewPages|သဵၼ်ႈမၢႆ ၼႃႈလိၵ်ႈဢၼ်မႂ်ႇ]])",
+ "recentchanges-submit": "ၼႄ",
+ "rclistfrom": "ၼႄ လွင်ႈလႅၵ်ႈလၢႆႈဢၼ်မႂ်ႇ တႄႇတီႈ $2, $3",
+ "rcshowhideminor": "$1 လွင်ႈမူၼ်ႉမႄး ဢိတ်းဢီႈ",
+ "rcshowhideminor-show": "ၼႄ",
+ "rcshowhideminor-hide": "သိူင်ႇ",
+ "rcshowhidebots": "$1 ၿွတ်ႉ",
+ "rcshowhidebots-show": "ၼႄ",
+ "rcshowhidebots-hide": "သိူင်ႇ",
+ "rcshowhideliu": "$1 ၽူႈၸႂ်ႉ ဢၼ်တၢင်ႇမၢႆၽၢင်ဝႆႉ",
+ "rcshowhideliu-show": "ၼႄ",
+ "rcshowhideliu-hide": "သိူင်ႇ",
+ "rcshowhideanons": "$1 ၽူႈၸႂ်ႉတိုဝ်းဢမ်ႇသႂ်ႇၸိုဝ်ႈ",
+ "rcshowhideanons-show": "ၼႄ",
+ "rcshowhideanons-hide": "သိူင်ႇ",
+ "rcshowhidepatr-show": "ၼႄ",
+ "rcshowhidepatr-hide": "သိူင်ႇ",
+ "rcshowhidemine": "$1 ဢၼ်ၵဝ်ၶႃႈ မူၼ်ႉမႄး",
+ "rcshowhidemine-show": "ၼႄ",
+ "rcshowhidemine-hide": "သိူင်ႇ",
+ "rcshowhidecategorization": "$1 ၼႃႈလိၵ်ႈ ပၢႆး-",
+ "rcshowhidecategorization-show": "ၼႄ",
+ "rcshowhidecategorization-hide": "သိူင်ႇ",
+ "rclinks": "ၼႄလွင်ႈလႅၵ်ႈလၢႆႈ ၵမ်းလိုၼ်းသုတ်း $1 ဢၼ်လႅၵ်ႈလၢႆႈမႃး မိူဝ်ႈ $2 ဝၼ်းၼၼ်ႉ<br />$3",
+ "diff": "ပႅၵ်ႇပိူင်ႈ",
+ "hist": "ပိုၼ်း",
+ "hide": "သိူင်ႇ",
+ "show": "ၼႄ",
+ "minoreditletter": "m",
+ "newpageletter": "N",
+ "boteditletter": "b",
+ "number_of_watching_users_pageview": "[$1 ပႂ်ႉတူၺ်း {{PLURAL:$1|ၽူႈၸႂ်ႉတိုဝ်း|ၽူႈၸႂ်ႉတိုဝ်းၶဝ်}}]",
+ "rc_categories_any": "လိူၵ်ႈသေဢၼ်ဢၼ်",
+ "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} ဝၢႆးသေလႅၵ်ႈလၢႆႈ",
+ "newsectionsummary": "/* $1 */ ၵၼ်ဢၼ်မႂ်ႇ",
+ "rc-enhanced-expand": "ၼႄပၼ် ႁူဝ်ယွႆႈမၼ်း",
+ "rc-enhanced-hide": "သိူင်ႇဝႆႉ ႁူဝ်ယွႆႈမၼ်း",
+ "rc-old-title": "ၵေႃႇသၢင်ႈဝႆႉၼင်ႇ ငဝ်ႈတိုၼ်းမၼ်း \"$1\"",
+ "recentchangeslinked": "တၢင်းလႅၵ်ႈလၢႆႈ ဢၼ်ၵဵဝ်ႇၵွင်ႉ",
+ "recentchangeslinked-feed": "တၢင်းလႅၵ်ႈလၢႆႈ ဢၼ်ၵဵဝ်ႇၵွင်ႉ",
+ "recentchangeslinked-toolbox": "တၢင်းလႅၵ်ႈလၢႆႈ ဢၼ်ၵဵဝ်ႇၵွင်ႉ",
+ "recentchangeslinked-title": "ၵၢၼ်လႅၵ်ႈလၢႆႈ ဢၼ်ၵပ်းၵၢႆႇလူၺ်ႈ \"$1\"",
+ "recentchangeslinked-summary": "ဢၼ်ၼႆႉၼႆႉပဵၼ် သဵၼ်ႈမၢႆ လွင်ႈလႅၵ်ႈလၢႆႈ ၸိူဝ်းဢၼ်တိုၵ်ႉႁႃ လႅၵ်ႈလၢႆႈမႃးၸူး ၼႃႈလိၵ်ႈ ဢၼ်မၵ်းမၼ်ႈဝႆႉၼႆႉ (ဢမ်ႇၼၼ် ၸူး ၽူႈၶဝ်ႈၸုမ်း ဢၼ်မီးၼႂ်း ၵၼ် ဢၼ်လႆႈမၵ်းမၼ်ႈဝႆႉ).\nၼႃးလိၵ်ႈ ၸိူဝ်းမီးၼိူဝ် [[Special:Watchlist|your watchlist]] ၼႆႉ <strong>တေလမ်ၼႃႈ</strong>ဝႆ့။",
+ "recentchangeslinked-page": "ၸိုဝ်ႈၼႃႈလိၵ်ႈ",
+ "recentchangeslinked-to": "ၼႄပၼ် လွၵ်ႈလႅၵ်ႈလၢႆႈ ၸူး ၼႃႈလိၵ်ႈ ဢၼ်ၵွင်ႉသိုပ်ႇ",
+ "recentchanges-page-added-to-category": "[[:$1]] သႂ်ႇၼႂ်း ပၢႆးယဝ်ႉ",
+ "recentchanges-page-added-to-category-bundled": "[[:$1]] ထႅမ်သႂ်ႇဝႆႉယဝ်ႉ တီႈၼႂ်းတွၼ်ႈၵၼ်, [[Special:WhatLinksHere/$1|ၼႃႈလိၵ်ႈၼႆႉ မၼ်းၶဝ်ႈပႃးဝႆႉ ၵႃႈတီႈၼႂ်း ၼႃႈလိၵ်ႈ တၢင်ႇၸိူဝ်း]]",
+ "recentchanges-page-removed-from-category": "[[:$1]] ဢဝ်ဢွၵ်ႇတမ်ႈတီႈ ပၢႆး",
+ "recentchanges-page-removed-from-category-bundled": "[[:$1]]ထွၼ်ပႅတ်ႈယဝ်ႉ ၵႃႈတီႈ တွၼ်ႈၵၼ်, [[Special:WhatLinksHere/$1|ၼႃႈလိၵ်ႈၼႆႉ မၼ်းၶဝ်ႈပႃးဝႆႉ ၵႃႈတီႈၼႂ်း ၼႃႈလိၵ်ႈ တၢင်ႇၸိူဝ်း]]",
+ "autochange-username": "သိုဝ်ႇၶၢဝ်ႇဝီႇၶီႇ လႅၵ်ႈလၢႆႈ ႁင်းတူဝ်",
+ "upload": "လူတ်ႇၶိုၼ်ႈၾၢႆႇ",
+ "uploadbtn": "လူတ်ႇၶိုၼ်ႈၾၢႆႇ",
+ "reuploaddesc": "ယႃႉပႅတ်ႈ ၵၢၼ်လူတ်ႇၶိုၼ်ႈသေ ၶိုၼ်းဝၢႆပွၵ်ႈၸူး ၼႃးလိၵ်ႈ လူတ်ႇၶိုၼ်ႈ",
+ "uploadnologin": "ဢမ်ႇလႆႈၶဝ်ႈလွၵ်ႉဢိၼ်ႇဝႆ့",
+ "uploadnologintext": "ၶႅၼ်းတေႃႈ $1 တႃႇလူတ်ႇၶိုၼ်ႈ ၾၢႆႇ။",
+ "upload_directory_missing": "ၾူဝ်ႇတိူဝ်ႇ လူတ်ႇၶိုၼ်ႈဢၼ် ($1) ၼႆႉၼႆႉ မၼ်းႁၢႆဝႆႉလႄႈ မၼ်းတေဢမ်ႇၸၢင်ႈၵႂႃႇ ၵေႃႇသၢင်ႈလႆႈတီႈ သႃႇပိူဝ်ႇဝႅပ်ႉ။",
+ "upload_directory_read_only": "ၾူဝ်ႇတိူဝ်ႇလူတ်ႇၶိုၼ်ႈ ($1) ဢၼ်ၼႆႉၼႆႉ မၼ်းတေဢမ်ႇၸၢင်ႈတႅမ်ႈ တင်း သႃႇပိူဝ်ႇဝႅပ်ႉ",
+ "uploaderror": "ၵၢၼ်လူတ်ႇၶိုၼ်ႈ ၽိတ်းပိူင်ႈ",
+ "upload-recreate-warning": "<strong>ၽၢင်ႉ : ၾၢႆႇဢၼ်ၼင်ႇၸိုဝ်ႈၼၼ်ႉ ထုၵ်ႇမွတ်ႇပႅတ်ႈ ဢမ်ႇ ထုၵ်ႇၶၢႆႉဢွင်ႈတီႈယဝ်ႉ။</strong>\n\nသဵၼ်ႈမၢႆ မွတ်ႇပႅတ်ႈ လႄ သဵၼ်ႈမၢႆ ၶၢႆႉတီႈတွၼ်ႈတႃႇ ၼႃႈလိၵ်ႈၼႆႉ လႆႈၵမ်ႉထႅမ်ဝႆႉပၼ် တီးၼႆႉသေ ယိူင်းဢၢၼ်းႁႂ်ႈ ငၢႆႈလူမ်ၸႂ် :",
+ "uploadlogpage": "သဵၼ်ႈမၢႆ လူတ်ႇၶိုၼ်ႈ",
+ "filename": "ၸိုဝ်ႈၾၢႆႇ",
+ "filedesc": "ႁူဝ်ႁုပ်ႈ",
+ "fileuploadsummary": "ႁူဝ်ႁုပ်ႈ",
+ "filereuploadsummary": "လွင်ႈလႅၵ်ႈလၢႆႈ ၾၢႆႇ :",
+ "filestatus": "သၢႆငၢႆ သုၼ်ႇထုတ်ႇၸႂ်ႉ :",
+ "filesource": "ငဝ်ႈငႃႇ :",
+ "ignorewarning": "ၶၢမ်ႈပႅတ်ႈ ၶေႃႈၽၢင်ႉသေ ပဵၼ်ႁိုဝ်ၵေႃႈ သိမ်းၾၢႆႇဝႆႉ",
+ "ignorewarnings": "ၶၢမ်ႈပႅတ်ႈ ၶေႃႈၽၢင်ႉ ၵူႈဢၼ်ဢၼ်",
+ "minlength1": "ၸိုဝ်ႈၾၢႆႇ ၼႆႉ တီႈဢေႇသုတ်းတေလႆႈပႃး လိၵ်ႈၼိုင်ႈတူဝ်",
+ "filename-toolong": "ၸိုဝ်ႈၾၢႆႇၼႆႉ တေဢမ်ႇလႆႈယၢဝ်းပူၼ်ႉလိူဝ် 240 bytes",
+ "badfilename": "ၸိုဝ်ႈၾၢႆႇၼႆႉ ထုၵ်ႇလႅၵ်ႈလၢႆႈပဵၼ်ၸူး \"$1\" ယဝ်ႈ။",
+ "filetype-missing": "ၾၢႆႇၼႆႉဢမ်ႇမီးယွႆးလင် (မိူၼ်ၼင်ႇ \".jpg\")",
+ "empty-file": "ၾၢႆႇဢၼ်ၸဝ်ႈၵဝ်ႇ မၵ်းမၼ်ႈယိုၼ်ႈမႃးၼၼ်ႉ မၼ်းပဝ်ႇဝႆႉ။",
+ "file-too-large": "ၾၢႆႇဢၼ်ၸဝ်ႈၵဝ်ႇ မၵ်းမၼ်ႈယိုၼ်ႈမႃးၼၼ်ႉ မႂ်းယႂ်ႇႁႅင်းၼႃႇ။",
+ "filename-tooshort": "ၸိုဝ်ႈၾၢႆႇၼႆႉ ပွတ်းႁႅင်းၼႃႇၽႅဝ်။",
+ "filetype-banned": "လိူင်ႈၾၢႆႇမဵဝ်းၼႆႉ ၼႆႉ ထုၵ်ႇဢိုတ်းတတ်းဝႆႉ။",
+ "verification-error": "ၾၢႆႇဢၼ်ၼႆႉၼႆႉ မၼ်းဢမ်ႇၶၢမ်ႈပူၼ်ႉလႆႈ ၵၢၼ်ၼႄႉၼွၼ်း။",
+ "illegal-filename": "ၸိုဝ်ႈၾၢႆႇဢၼ်ၼႆႉ မၼ်းဢမ်ႇၶႂၢင်းပၼ်ႁႂ်ႈၸႂ်ႉ။",
+ "overwrite": "လွင်ဢဝ်တဵင်သႂ်ႇ ၾၢႆႇဢၼ်မီးဝႆႉၼႆႉၵေႃႈ ဢမ်ႇလႆႈၶႂၢင်ႈပၼ်ဝႆႉ။",
+ "unknown-error": "လွင်ႈၽိတ်းပိူင်ႈ ဢၼ်ဢမ်ႇလၢမ်းလႆႈၼၼ်ႉ ဢွၵ်ႇပဵၼ်ဝႆႉ။",
+ "tmp-create-error": "ဢမ်ႇၸၢင်ႈၵေႃႇသၢင်ႈ ၾၢႆႇတိုဝ်းၸူဝ်ႈၵႅပ်ႉ။",
+ "tmp-write-error": "ၵၢၼ်တႅမ်ႈ ၾၢႆႇၸႂ်ႉတိုဝ်း ၸူဝ်ႈၵႅပ်ႉၼႆႉ ၽိတ်းပိူင်ႈဝႆႉ။",
+ "windows-nonascii-filename": "ဝီႇၶီႇၼႆႉ မၼ်းဢမ်ႇၵမ်ႉထႅမ်ဝႆႉပၼ် ၸိုဝ်ႈၾၢႆႇ ဢၼ်ၸႂ်ႉပႃးတင်း တူဝ်လိၵ်ႈၶိုၵ်ႉတွၼ်း။",
+ "uploadwarning": "ၶေႃႈၽၢင်ႉတႃႇ ၵၢၼ်လူတ်ႇၶိုၼ်ႈ",
+ "uploadwarning-text": "ၶႅၼ်းတေႃႈ မႄးပၼ်ၶိုၼ်း ၶေႃႈသပ်းလႅင်း ၾၢႆႇ ဢၼ်ၽၢႆႇတႂ်ႈၼႆႉသေ ၶိုၼ်းၶတ်းၸႂ်တူၺ်းထႅင်ႈလႄႈ။",
+ "savefile": "သိမ်း ၾၢႆႇ",
+ "uploaddisabled": "ၵၢၼ်လူတ်ႇၶိုၼ်ႈ ထုၵ်ႇဢိုတ်းဝႆႉ။",
+ "copyuploaddisabled": "ၵၢၼ်လူတ်ႇၶိုၼ်ႈၵႃႈတီႈ URL ၼႆႉ ထုၵ်ႇဢိုတ်းဝႆႉ။",
+ "uploaddisabledtext": "ၵၢၼ်လူတ်ႇၾၢႆႇၶိုၼ်ႈၼႆႉ ထုၵ်ႇဢိုတ်းဝႆႉ။",
+ "php-uploaddisabledtext": "ၵၢၼ်လူတ်ႇၾၢႆႇၶိုၼ်ႈၼႆႉ ထုၵ်ႇဢိုတ်းဝႆႉ ၵႃႈတီႈၼႂ်း PHP ။\nၶႅၼ်းတေႃႇ ၵႂႃႇၵူတ်ႇတူၺ်း ၵၢၼ်တင်ႈတႃႈ ၵၢၼ်လူတ်ႇၶိုၼ်ႈၾၢႆႇ။",
+ "upload-source": "ၾၢႆႇငဝ်ႈငႃႇ",
+ "sourcefilename": "ၸိုဝ်ႈၾၢႆႇငဝ်ႈငႃႇ :",
+ "sourceurl": "URL ငဝ်ႈငႃႈ :",
+ "destfilename": "ၸိုဝ်ႈၾၢႆႇ ယိူင်းၸူး :",
+ "upload-maxfilesize": "သႅၼ်းၾၢႆ ဢၼ်ယႂ်ႇသုတ်း : $1",
+ "upload-description": "ၶေႃႈသပ်းလႅင်း ၾၢႆႇ",
+ "upload-options": "ၵၼ်လိူၵ်ႈသၢင်ႈ ၵၢၼ်လူတ်ႇၶိုၼ်ႈ",
+ "watchthisupload": "ပႂ်ႉတူၺ်းၾၢႆႇဢၼ်ၼႆႉ",
+ "upload-dialog-title": "လူတ်ႇၶိုၼ်ႈၾၢႆႇ",
+ "upload-dialog-button-cancel": "ဢမ်ႇႁဵတ်း",
+ "upload-dialog-button-done": "ယဝ်ႉ",
+ "upload-dialog-button-save": "ၵဵပ်းသိမ်း",
+ "upload-dialog-button-upload": "လူတ်ႇၶိုၼ်ႈ",
+ "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": "ၸိုဝ်ႈၾၢႆႇ",
+ "upload-form-label-own-work": "ဢၼ်ၼႆႉပဵၼ် ၼႃႈၵၢၼ်တူဝ်ၶႃႈ။",
+ "upload-form-label-infoform-categories": "လိူင်ႈ",
+ "upload-form-label-infoform-date": "ဝၼ်းထီႉ",
+ "lockmanager-notlocked": "ဢမ်ႇၸၢင်ႈ ပိုတ်ႇသေႃး \"$1\"; ၼၼ်ႉမၼ်းဢမ်ႇလႆႈ ၶတ်းဝႆႉ။",
+ "lockmanager-fail-closelock": "ဢမ်ႇၸၢင်ႈဢိုတ်း ၾၢႆႇဢၼ်ၶတ်းဝႆႉ တွၼ်ႈတႃႇ \"$1\" ။",
+ "lockmanager-fail-deletelock": "ဢမ်ႇၸၢင်ႈမွတ်ႇပႅတ်ႈ ၾၢႆႇဢၼ်ၶတ်းဝႆႉ တွၼ်ႈတႃႈ \"$1\".",
+ "lockmanager-fail-acquirelock": "ဢမ်ႇၸၢင်ႈဢဝ် ၶတ်းတွၼ်ႈတႃႇ \"$1\" ။",
+ "lockmanager-fail-openlock": "ဢမ်ႇၸၢင်ႈဢိုတ်း ၾၢႆႇဢၼ်ၶတ်းဝႆႉ တွၼ်ႈတႃႇ \"$1\" ။",
+ "lockmanager-fail-releaselock": "ဢမ်ႇၸၢင်ႈပွႆႇပၼ် ဢၼ်ၶတ်း တွၼ်ႈတႃႈ \"$1\" ။",
+ "lockmanager-fail-db-release": "ဢမ်ႇၸၢင်ႈပွႆႇပၼ်ၵၢၼ်ၶတ်း ၵႃႈတီႈ ယွင်ၶေႃႈမုၼ်း $1 ။",
+ "lockmanager-fail-svr-acquire": "ဢမ်ႇၸၢင်ႈဢဝ်လႆႈ ၵၢၼ်ၶတ်း ၵႃႈတီႈၼိူဝ် သႃႇပိူဝ်ႇ $1 ။",
+ "lockmanager-fail-svr-release": "ဢမ်ႇၸၢင်ႈပွႆႇပၼ် ၵၢၼ်ၶတ်း ၵႃႈတီႈၼိူဝ် သႃႇပိူဝ်ႇ $1 ။",
+ "zip-wrong-format": "ၾၢႆႇဢၼ်မၵ်းမၼ်ႈဝႆႉပၼ်ၼၼ်ႉ မၼ်းဢမ်ႇၸႂ်ႈ ၾၢႆႇ ZIP ။",
+ "zip-bad": "ၾၢႆႇၼႆႉ မၼ်းၵွႆဝႆႉ ဢမ်ႇၼၼ် မၼ်းပဵၼ် ၾၢႆႇ ZIP ဢၼ်ဢမ်ႇလူႇလႆႈ။\nမၼ်းဢမ်ႇၸၢင်ႈ ၵူတ်ႇတူၺ်း တွၼ်ႈတႃႇ ပၢႆးႁူမ်ႇလူမ်ႈ လႆႈလီလီ။",
+ "zip-unsupported": "ၾၢႆႇၼႆႉပဵၼ် ZIP ၾၢႆႇ ဢၼ်ၸႂ်ႉဝႆႉ ၽၢင်ႁၢင်ႈၵၢၼ် ZIP ဢၼ် သိူဝ်ႇၶၢဝ်ႇဝီႇၶီႇ ဢမ်ႇၵမ်ႉထႅမ်ဝႆႉ။ မၼ်းဢမ်ႇၸၢင်ႈ ၵူတ်ႇတူၺ်း တွၼ်ႈတႃႇ ပၢႆးႁူမ်ႇလူမ်ႈ လႆႈလီလီ။",
+ "uploadstash": "လူတ်ႇၶိုၼ်ႈ ၵၢၼ်သိူင်ႇ",
+ "uploadstash-clear": "ၽဵဝ်ႈလၢင်ႈ ၾၢႆႇၸိူဝ်းသိူင်ႇသိမ်းဝႆႉ",
+ "uploadstash-nofiles": "တီႈၸဝ်ႈၵဝ်ႇ ဢမ်ႇမီးၾၢႆႇသိူင်ႇသိမ်းသင်။",
+ "uploadstash-errclear": "လွင်ႈၽဵဝ်ႈလၢင်ႉၾၢႆႇဢမ်ႇၶႅမ်ႉလႅပ်ႈ။",
+ "uploadstash-refresh": "သၢႆႇၶိုၼ်း သဵၼ်ႈမၢႆၾၢႆႇ",
+ "uploadstash-thumbnail": "တူၺ်းၼင်ႇ ႁၢင်ႈလဵၵ်ႉ",
+ "img-auth-accessdenied": "ၵၢၼ်ၸႂ်ႉတိုဝ်း ထုၵ်ႇထဵင်ၶိုၼ်း။",
+ "img-auth-nologinnWL": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇလႆႈၶဝ်ႈ လွၵ်ႉဢိၼ်ဝႆႉသေ \"$1\" ၼႆႉ မၼ်းဢမ်ႇမီးဝႆႉ တီႈၼႂ်း သဵၼ်ႈမၢႆၶၢဝ်။",
+ "img-auth-nofile": "ၾၢႆႇ \"$1\" ၼႆႉ မၼ်းဢမ်ႇမီးဝႆႉ။",
+ "img-auth-isdir": "ၸဝ်ႈၵဝ်ႇ တိုၵ်ႉၶတ်းၸႂ်ႉ ၶဝ်ႈၸႂ်ႉ ၾူဝ်ႇတိူဝ်ႇ \"$1\" ယူႇ။\nၶႂၢင်းဝႆႉပၼ် ၵၢၼ်ၸႂ်ႉတိုဝ်းၾၢႆႇၵူၺ်း။",
+ "img-auth-streaming": "သၢႆလႆ \"$1\" ။",
+ "img-auth-noread": "ၽူႈၸႂ်ႉတိုဝ်းၼႆႉဢမ်ႇမီးသုၼ်ႇၸႂ်ႉ တႃႇတေလူ \"$1\" ။",
+ "http-invalid-url": "URL ပိူင်ႈဝႆႉ : $1",
+ "http-invalid-scheme": "ပိူင် URLs တင်း \"$1\" ၼႆႉ မၼ်းဢမ်ႇလႆႈ ၵမ်ႉထႅမ်ပၼ်ဝႆႉ။",
+ "http-request-error": "ၶေႃႈတုၵ်းယွၼ်း HTTP ၼၼ်ႉ ဢမ်ႇၶႅမ်ႉလႅပ်ႈ လွင်ႈလူၺ်ႈ ပဵၼ်လွင်ႈၽိတ်းပိူင်ႈ ဢၼ်ဢမ်ႇႁူႉၸွမ်းလႆႈ။",
+ "http-read-error": "ၵၢၼ်လူ HTTP ၽိတ်းပိူင်ႈ ။",
+ "http-timed-out": "ၵၢၼ်တုၵ်းယွၼ်း HTTP ယၢမ်းသုတ်းၵႂႃႇ။",
+ "http-curl-error": "URL ဢၼ်တိုၵ်ႉႁွင်ႉ ၵၢၼ်ၽိတ်းပိူင်ႈ : $1",
+ "http-bad-status": "ၽွင်းမိူဝ်ႈတိုၵ်ႉ တုၵ်းယွၼ်း HTTP ၼၼ်ႉ လႆႈပဵၼ်လွင်ႈၽိတ်းပိူင်ႈဝႆႉ : $1 $2",
+ "upload-curl-error6": "ဢမ်ႇၸၢင်ႈ ၽဵဝ်ၸူးၵႃႈတီႈ URL",
+ "upload-curl-error6-text": "URL ဢၼ်ၵမ်ႉထႅမ်ဝႆႉပၼ်ၼႆႉ ဢမ်ႇၸၢင်ႈၽႅဝ်ထိုင်ၸူး။\nၶႅၼ်းတေႃႈ ၶိုၼ်းၵူတ်ႇတူၺ်းပွၵ်ႈသွင်ဝႃႈ URL ၼၼ်ႉ မႅၼ်ႈယူႇၼႆသေ သၢႆႉၵေႃႈ ၶိုၼ်ႈမီးဝႆႉ။",
+ "upload-curl-error28": "ၶၢဝ်းယၢမ်း ၵၢၼ်လူတ်ႇၶိုၼ်ႈ သုတ်းၵႂႃႇ",
+ "upload-curl-error28-text": "သၢႆႉဢၼ်ၼႆႉ တႃႇတေတူင်ႉတွပ်ႇၶိုၼ်းၼႆႉ မၼ်းႁိုင်ႁႅင်းၼႃႇ။\nၶႅၼ်းတေႃႇ ၵူတ်ႇတူၺ်းဝႃႈ သၢႆႉၼႆႉ ၶိုၼ်ႈယူႇႁႃႉ၊ ၽွင်းမိူဝ်ႈ တိုၵ်ႉၶိုၼ်းၶတ်းၸႂ်တူၺ်း ၼၼ်ႉ ပႂ်ႉပၼ် ၸူဝ်ၶၢဝ်း။ ၸဝ်ႈၵဝ်ႇတေလႅပ်ႈၶႂ်ႈ ၶိုၼ်းႁဵတ်းတူၺ်း ၽွင်းမိူဝ်ႈ ဢမ်ႇပေႃး ၵၢၼ်သုၵ်ႉၼၼ်ႉ။",
+ "license": "ဝႂ်ၶႂၢင်း :",
+ "license-header": "ဝႆၶႂၢင်း",
+ "nolicense": "ဢမ်ႇလႆႈလိူၵ်ႈသင်ဝႆႉ",
+ "licenses-edit": "မႄးထတ်း ၵၢၼ်လိူၵ်ႈသၢင်ႈ ဝႂ်ၶႂၢင်း",
+ "upload_source_url": "(ၾၢႆႇဢၼ်ၸဝ်ႈၵဝ်ႇလိူၵ်ႈဝႆႉၵႃႈတီႈ ဢၼ်မၢၼ်ႇမႅၼ်ႈ၊ URL ဢၼ်ၵူၼ်းတၢင်းၼမ် ၸၢင်ႈၸႂ်ႉလႆႈ )",
+ "upload_source_file": "(ၸဝ်ႈၵဝ်ႇလႆႈလိူၵ်ႈဝႆႉၾၢႆႇ ၵႃႈတီႈ ၶွမ်ႇပိဝ်ႇတႃႇ ၸဝ်ႈၵဝ်ႇ)",
+ "listfiles-delete": "မွတ်ႇပႅတ်ႈ",
+ "listfiles-summary": "ၼႃႈလိၵ်ႈၶိုၵ်ႉတွၼ်းဢၼ်ၼႆႉ မၼ်းၼႄပၼ် ၾၢႆႇ ၸိူဝ်းလူတ်ႇၶိုၼ်ႈဝႆႉ တင်းသဵင်ႈ။",
+ "listfiles_search_for": "ၶူၼ်ႉႁႃတႃႇ ၸိုဝ်ႈသိုဝ်ႇၶၢဝ်ႇ :",
+ "listfiles-userdoesnotexist": "ဢၶွင်ႉ ၽူႈၸႂ်ႉတိုဝ်း \"$1\" ၼႆႉ ဢမ်ႇပႆႇလႆႈ တၢင်ႇမၢႆၽၢင်ဝႆႉ။",
+ "imgfile": "ၾၢႆႇ",
+ "listfiles": "သဵၼ်ႈမၢႆၾၢႆႇ",
+ "listfiles_thumb": "ႁၢင်ႈလဵၵ်ႉ",
+ "listfiles_date": "ဝၼ်းထီႉ",
+ "listfiles_name": "ၸိုဝ်ႈ",
+ "listfiles_user": "ၽူႈၸႂ်ႉတိုဝ်း",
+ "listfiles_size": "သႅၼ်း",
+ "listfiles_description": "ၶေႃႈသပ်းလႅင်း",
+ "listfiles_count": "မၢႆဢွၵ်ႇ",
+ "listfiles-show-all": "ၶဝ်ႈပႃးဝႆႉ ၶႅပ်းႁႃင်ႈၸိူဝ်း ပဵၼ်မၢႆဢွၵ်ႇၵဝ်ႇ။",
+ "listfiles-latestversion": "မၢႆဢွၵ်ႇ ယၢမ်းလဵဝ်",
+ "listfiles-latestversion-yes": "ၸႂ်ႈယဝ်ႉ",
+ "listfiles-latestversion-no": "ဢမ်ႇ",
+ "file-anchor-link": "ၾၢႆႇ",
+ "filehist": "ပိုၼ်းၾၢႆႇ",
+ "filehist-help": "တဵၵ်းၼိူဝ် ဝၼ်းထိ/ၶၢဝ်းယၢမ်း တႃႇႁၼ်ၾၢႆႇ ၼႂ်းဝၼ်းၼၼ်ႉ",
+ "filehist-deleteall": "မွတ်ႇပႅတ်ႈမူတ်း",
+ "filehist-deleteone": "မွတ်ႇပႅတ်ႈ",
+ "filehist-revert": "ပိၼ်ႇပွၵ်ႈၶိုၼ်း",
+ "filehist-current": "ယၢမ်းလဵဝ်",
+ "filehist-datetime": "ဝၼ်းထီႉ/ၶၢဝ်းယၢမ်း",
+ "filehist-thumb": "ႁၢင်ႈလဵၵ်ႉ",
+ "filehist-thumbtext": "ၽၢင်ယဵမ်ႈ တွၼ်ႈတႃႇ ပိူဝ်းသျိၼ်းၼင်ႇ $1",
+ "filehist-nothumb": "ဢမ်ႇမီး ႁၢင်ႈလဵၵ်ႉ",
+ "filehist-user": "ၽူႈၸႂ်ႉတိုဝ်း",
+ "filehist-dimensions": "သႅၼ်းမၼ်း",
+ "filehist-filesize": "သႅၼ်းၾၢႆႇ",
+ "filehist-comment": "တၢင်းႁၼ်ထိုင်",
+ "imagelinks": "လွင်ႈၸႂ်ႉတိုဝ်း ၾၢႆႇ",
+ "linkstoimage": "{{PLURAL:$1|ၼႃႈလိၵ်ႈ|$1 ၼႃႈလိၵ်ႈ}} ၵွင်ႉမႃးၸူးၾၢႆႇၼႆႉ:",
+ "nolinkstoimage": "ဢမ်ႇမီးၼႃႈလိၵ်ႈဢၼ်ၵွင်ႉၸူး ၾၢႆႇဢၼ်ၼႆႉ",
+ "morelinkstoimage": "တူၺ်း [[Special:WhatLinksHere/$1|ႁဵင်းၵွင်ႉတၢင်ႇၸိူဝ်း]] ၸူး ၾၢႆႇဢၼ်ၼႆႉ။",
+ "linkstoimage-redirect": "$1 (ပိၼ်ႇၸီႉ ၾၢႆႇၸူး) $2",
+ "sharedupload": "ၾၢႆႇဢၼ်ၼႆႉ လုၵ်ႉၵႃႈတီႈ $1 မႃးသေ ၼႃႈၵၢၼ်တၢင်ႇၸိူဝ်းၵေႃႈ ဢၢပ်ႈတေဢဝ်ၸႂ်ႉဝႆႉ။",
+ "sharedupload-desc-there": "ၾၢႆႇဢၼ်ၼႆႉ လုၵ်ႉၵႃႈတီႈ $1 မႃးသေ ၼႃႈၵၢၼ်တၢင်ႇၸိူဝ်းၵေႃႈ ဢၢပ်ႈတေဢဝ်ၸႂ်ႉဝႆႉ။\nၶႅၼ်းတေႃႈ တူၺ်းပၼ် [$2 ၼႃႈလိၵ်ႈၶေႃႈသပ်းလႅင်းၾၢႆႇ] တွၼ်ႈတႃႇ လွၼ်ႉၶၢဝ်ႇ တၢင်ႇၸိူဝ်း။",
+ "sharedupload-desc-here": "ၾၢႆႇဢၼ်ၼႆႉ လုၵ်ႉတီႈ $1 သေ တေၸၢင်ႈၵႂႃႇၸႂ်ႉ တီႈပရေႃးၵျႅၵ်ႉတၢင်ႇဢၼ်။\nဢၼ်တႅမ်ႈၼႄ တီႈၼႂ်း [$2 file description page] ၼၼ်ႉ တေၼႄပၼ် တီႈတႂ်ႈၼႆႉ။",
+ "sharedupload-desc-edit": "ၾၢႆႇဢၼ်ၼႆႉ လုၵ်ႉၵႃႈတီႈ $1 မႃးသေ ၼႃႈၵၢၼ်တၢင်ႇၸိူဝ်းၵေႃႈ ဢၢပ်ႈတေဢဝ်ၸႂ်ႉဝႆႉ။\nၸဝ်ႈၵဝ်ႇ ဢၢပ်ႈတေၶႂ်ႈ မႄးထတ်း ၶေႃႈသပ်းလႅင်း ၵႃႈတီႈ [$2 ၼႃႈလိၵ်ႈ ၶေႃႈသပ်းလႅင်း ၾၢႆႇ] ၼႆႉ။",
+ "sharedupload-desc-create": "ၾၢႆႇဢၼ်ၼႆႉ လုၵ်ႉၵႃႈတီႈ $1 မႃးသေ ၼႃႈၵၢၼ်တၢင်ႇၸိူဝ်းၵေႃႈ ဢၢပ်ႈတေဢဝ်ၸႂ်ႉဝႆႉ။\nၸဝ်ႈၵဝ်ႇ ဢၢပ်ႈတေၶႂ်ႈ မႄးထတ်း ၶေႃႈသပ်းလႅင်း ၵႃႈတီႈ [$2 ၼႃႈလိၵ်ႈ ၶေႃႈသပ်းလႅင်း ၾၢႆႇ] ၼႆႉ။",
+ "filepage-nofile": "ၾၢႆႇဢၼ်ပဵၼ်ၸိုဝ်ႈၼႆႉ မၼ်းဢမ်ႇမီးဝႆႉ။",
+ "filepage-nofile-link": "ၾၢႆႇဢၼ်ပဵၼ်ၸိုဝ်ႈၼႆႉ မၼ်းဢမ်ႇမီးဝႆႉ၊ ၵူၺ်းၵႃႈ ၸဝ်ႈၵဝ်ႇ ၸၢင်ႈ [$1 လူတ်ႇၶိုၼ်ႈ မၼ်း] လႆႈ။",
+ "uploadnewversion-linktext": "လူတ်ႇၶိုၼ်ႈပၼ် မၢႆဢွၵ်ႇဢၼ်မႂ်ႇ တွၼ်ႈတႃႇ ၾၢႆႇဢၼ်ၼႆႉ",
+ "shared-repo-from": "လုၵ်ႉတီႈ $1",
+ "shared-repo": "ယွင်ဢၼ်ၽႄႈၸႂ်ႉဝႆႉ",
+ "upload-disallowed-here": "ၸဝ်ႈၵဝ်ႇတေဢမ်ႇၸၢင်ႈ တႅမ်တၢင်သႂ်ႇၼိူဝ် ၾၢႆႇဢၼ်ၼႆႉ",
+ "filerevert": "ၶူၼ်ႉပိၼ်ၸူး $1",
+ "filerevert-legend": "ၶူၼ်ႉပိၼ်ႇၾၢႆႇ",
+ "filerevert-intro": "ၸဝ်ႈၵဝ်ႇ ၶူၼ်ႉပိၼ်ႇတေၶူၼ်ႉပိၼ်ႇ ၾၢႆႇ <strong>[[Media:$1|$1]]</strong> ၸူး [$4 မၢႆဢွၵ်ႇ ၼင်ႇ $3, $2].",
+ "filerevert-comment": "လွင်ႈတၢင်း :",
+ "filerevert-defaultcomment": "ၶူၼ်ႉပိၼ်ႇ ၸူး မၢႆဢွၵ်ႇ ၼင်ႇ $2, $1 ($3)",
+ "filerevert-submit": "ၶူၼ်ႉပိၼ်ႇ",
+ "filerevert-success": "<strong>[[Media:$1|$1]]</strong>ၼႆႉထုၵ်ႇၶူၼ်ႉပိၼ်ႇၸူး [$4 မၢႆဢွၵ်ႇၼင်ႇ ၶွင် $3, $2].",
+ "filedelete": "မွတ်ႇပႅတ်ႈ $1",
+ "filedelete-legend": "မွတ်ႇပႅတ်ႈ ၾၢႆႇ",
+ "filedelete-intro": "ၸဝ်ႈၵဝ်ႇ တေမွတ်ႇပႅတ်ႈၾၢႆႇ <strong>[[Media:$1|$1]]</strong> ဢၼ်ၵိုၵ်းဝႆႉ ပိုၼ်းမၼ်းတင်းသဵင်ႈတင်းမူတ်း။",
+ "filedelete-intro-old": "ၸဝ်ႈၵဝ်ႇတိုၵ်ႉမွတ်ႇ မၢႆဢွၵ်ႇ ၶွင် <strong>[[Media:$1|$1]]</strong> ၼင်ႇၶွင် [$4 $3, $2].",
+ "filedelete-comment": "လွင်ႈတၢင်း :",
+ "filedelete-submit": "မွတ်ႇပႅတ်ႈ",
+ "filedelete-success": "<strong>$1</strong> ၼႆႉ ထုၵ်ႇမွတ်ႇပႅတ်ႈၵႂႃႇယဝ်ႉ။",
+ "filedelete-success-old": "မၢႆဢွၵ်ႇၶွင် <strong>[[Media:$1|$1]]</strong> ၼင်ႇၶွင် $3, $2 ၼႆႉ ထုၵ်ႇမွတ်ႇပႅတ်ႈယဝ်ႉ။",
+ "filedelete-nofile": "<strong>$1</strong> ၼႆႉ ဢမ်ႇမီးဝႆႉ။",
+ "filedelete-otherreason": "တၢင်ႇၸိူဝ်း / လွင်ႈတၢင်း ထႅမ်သႂ်ႇထႅင်ႈ",
+ "filedelete-reason-otherlist": "လွင်ႈတၢင်းတၢင်ႇၸိူဝ်း",
+ "filedelete-reason-dropdown": "*လွင်ႈတၢင်း ၽုင်ႇ ၵၢၼ်ႇမွတ်ႇပႅတ်ႈ\n** လွင်ႈပူၼ်ႉပႅၼ် သုၼ်ႇထုတ်ႇ Copyright\n** မီးၾၢႆႇ မိူၼ်ၵၼ်ဝႆႉ",
+ "filedelete-edit-reasonlist": "မႄးထတ်း လွင်ႈတၢင်း တႃႇမွတ်ႇ",
+ "filedelete-maintenance": "ၽွင်းမိူဝ်ႈ တိုၵ်ႉမႄးၵုမ်းယူႇၼႆႉ ၵၢၼ်မွတ်ႇပႅတ်ႈလႄႈ ၵၢၼ်ဢဝ်ၶိုၼ်း ၾၢႆႇၸိူဝ်းၼႆႉ တေဢမ်ႇၸႂ်ႉလႆႈ ၸူဝ်ႈၶၢဝ်း။",
+ "filedelete-maintenance-title": "ဢမ်ႇၸၢင်ႈမွတ်ႇပႅတ်ႈ ၾၢႆႇ",
+ "mimesearch": "ၶူၼ်ႉႁႃ MIME",
+ "mimetype": "လိူင်ႈ MIME :",
+ "download": "လူတ်ႇလူင်း",
+ "unwatchedpages": "ၼႃႈလိၵ်ႈ ၸိူဝ်းဢမ်ႇပႆႇလႆႈတူၺ်း။",
+ "listredirects": "သဵၼ်ႈမၢႆ ၸိူဝ်းပိၼ်ႇၸီႉ",
+ "listduplicatedfiles": "သဵၼ်ႈမၢႆၾၢႆႇ ၸိူဝ်းမိူၼ်ၵၼ်ဝႆႉ",
+ "listduplicatedfiles-entry": "[[:File:$1|$1]] ၼႆႉမၼ်း [[$3|{{PLURAL:$2|a မိူၼ်ၵၼ်|$2 မိူၼ်ၵၼ်}}]].",
+ "unusedtemplates": "လွၵ်းပိူင် ဢၼ်ဢမ်ႇၸႂ်ႉဝႆႉ",
+ "unusedtemplateswlh": "ႁဵင်းၵွင်ႉ တၢင်ႇၸိူဝ်း",
+ "randompage": "ဢဝ်ၼႃႈလိၵ်ႈသၢင်ႇထုၵ်ႇဝႃႈ",
+ "randompage-nopages": "ၸွမ်းၼင်ႇပႃႈတႂ်ႈၼႆႉ မၼ်းဢမ်ႇမီး ဝႆႉ ၼႃႈလိၵ်ႈသင်\n{{PLURAL:$2|လွၵ်းၸိုဝ်ႈ|လွၵ်းၸိုဝ်ႈ}}: $1.",
+ "randomincategory": "ၼႃႈလိၵ်ႈၵမ်ႉသၢင်ႇတေႃႇ ၵႃႈတီႈၼႂ်း လိူင်ႈ",
+ "randomincategory-invalidcategory": "\"$1\" ၼႆႉ ပဵၼ်ၸိုဝ်ႈလိူင်ႈ ဢၼ်ဢမ်ႇပဵၼ်လႆႈ။",
+ "randomincategory-nopages": "မၼ်းဢမ်ႇမီးဝႆ ၼႃႈလိၵ်ႈသင် ၵႃႈတီႈၼႂ်း [[:Category:$1|$1]] လိူင်ႈ။",
+ "randomincategory-category": "လိူင်ႈ",
+ "randomincategory-legend": "ၼႃႈလိၵ်ႈၵမ်ႉသၢင်ႇတေႃႇ ၵႃႈတီႈၼႂ်း လိူင်ႈ",
+ "randomincategory-submit": "သိုပ်ႇၵႂႃႇ",
+ "randomredirect": "တူဝ်ပိၼ်ႇၸီႉ ၵမ်ႉသၢင်ႇတေႃႇ",
+ "randomredirect-nopages": "မၼ်းဢမ်ႇမီးဝႆႉ တူဝ်ပိၼ်ႇၸီႈ ၼင်ႇလွၵ်းၸိုဝ်ႈ ဝႃႈ \"$1\" ။",
+ "statistics": "သဵၼ်ႈမၢႆ",
+ "statistics-header-pages": "ၼႃႈလိၵ်ႈ သဵၼ်ႈမၢႆ",
+ "statistics-header-edits": "မႄးထတ်း သဵၼ်ႈမၢႆ",
+ "statistics-header-users": "သဵၼ်ႈမၢႆ ၽူႈၸႂ်ႉတိုဝ်း",
+ "statistics-header-hooks": "သဵၼ်ႈမၢႆ တၢင်ႇၸိူဝ်း",
+ "statistics-articles": "ၼႃႈလိၵ်ႈ ၼမ်းၼႂ်း",
+ "statistics-pages": "ၼႃႈလိၵ်ႈ",
+ "statistics-pages-desc": "ၼႃႈလိၵ်ႈတင်းသဵင်ႈ ၵႃႈတီႈၼႂ်း ဝီႇၶီႇ၊ ဢိၵ်ႇၶဝ်ႈပႃး ၼႃႈလိၵ်ႈ ဢုပ်ႇဢူဝ်း၊ တူဝ်ပိၼ်ႇၸီႉ ၸၵႂႃႇၸိူဝ်းၼႆႉ။",
+ "statistics-files": "လူတ်ႇၶိုၼ်ႈ ၾၢႆႇ",
+ "statistics-edits": "မႄးထတ်းၼႃႈလိၵ်ႈ ၸဵမ်မိူဝ်ႈ {{SITENAME}} လႆႈတင်ႈတေႃႇမႃး",
+ "statistics-edits-average": "ၽတ်ႉၽဵင်ႇၵၢၼ်မႄးထတ်း ႁူဝ်ၼႃႈလိၵ်ႈ",
+ "statistics-users": "တၢင်ႇမၢႆၽၢင်ဝႆႉယဝ်ႉ [[Special:ListUsers|users]]",
+ "statistics-users-active": "ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းတူင်ႉတိုၼ်ႇဝႆႉ",
+ "statistics-users-active-desc": "ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းႁဵတ်း လွင်ႈတူင်ႉၼိုင်ဝႆႉ ၼႂ်းၵႃႈဝၼ်းလိုၼ်းသုတ်း {{PLURAL:$1|ဝၼ်း|$1 ဝၼ်း}}။",
+ "pageswithprop": "ၼႃႈလိၵ်ႈၸိူဝ်းမီး ၶွင်တူဝ်ၼႃႈလိၵ်ႈ",
+ "pageswithprop-legend": "ၼႃႈလိၵ်ႈၸိူဝ်းမီး ၶွင်တူဝ်ၼႃႈလိၵ်ႈ",
+ "pageswithprop-text": "ၼႃႈလိၵ်ႈၼႆႉ ႁဵတ်းသဵၼ်ႈမၢႆၼႃႈလိၵ်ႈၸိူဝ်း ၸႂ်ႉဝႆႉ ၶွင်တူဝ်ၼႃႈလိၵ်ႈ ဢၼ်လႂ်ဢၼ်ၼၼ်ႉ။",
+ "pageswithprop-prop": "ၸိုဝ်ႈ ၶွင်တူဝ် :",
+ "pageswithprop-submit": "သိုပ်ႇၵႂႃႇ",
+ "pageswithprop-prophidden-long": "လပ်ႉဝႆႉ ၵႃႈၶၼ်လိၵ်ႈၶူဝ်တူဝ်ဢၼ်ယၢဝ်း ($1)",
+ "pageswithprop-prophidden-binary": "လပ်ႉဝႆႉ ၵႃႈၶၼ် ၶွင်တူဝ်ပဵၼ်ၸုမ်ႇ ($1)",
+ "doubleredirects": "တူဝ်ပိၼ်ႇၸီႉ သွင်ၸၼ်ႉ",
+ "double-redirect-fixed-move": "[[$1]] ထုၵ်ႇၶၢႆႉတီႈဝႆႉယဝ်ႉ။\nမၼ်ႈႁဵတ်းဢၢပ်ႉတိတ်ႉၵႂႃႇ ႁင်းတူဝ်မၼ်းသေ ယၢမ်းလဵဝ် ပိၼ်ႇၸီႉၸူး [[$2]]။",
+ "double-redirect-fixed-maintenance": "မႄးပၼ် တူဝ်ပိၼ်ႇၸီႉသွင်ၸၼ်ႉ ႁင်းတူဝ် ၵႃႈတီႈ [[$1]] ၸူး [[$2]] ၼႂ်း ၼႃႈၵၢၼ် မူၼ်ႉမေး။",
+ "double-redirect-fixer": "တူဝ်မေးပၼ် ၵၢၼ်ပိၼ်ႇၸီႉ",
+ "brokenredirects": "တူဝ်ပိၼ်ႇၸီႉ ၸိူဝ်းလူႉလႅဝ်ဝႆႉ",
+ "brokenredirectstext": "တူဝ်ပိၼ်ႇၸီႉ ၸိူဝ်းပႃႈတႂ်ႈၼႆႉ ၵွင်ႉၸူး ၼႃႈလိၵ်ႈၸိူဝ်းဢမ်ႇမီးဝႆႉ :",
+ "brokenredirects-edit": "မႄးထတ်း",
+ "brokenredirects-delete": "မွတ်ႇပႅတ်ႈ",
+ "withoutinterwiki": "ၼႃႈလိၵ်ႈၸိူဝ်းဢမ်ႇမီးဝႆႉ ႁဵင်းၵွင်ႉ ၽႃႇသႃႇၵႂၢမ်း",
+ "withoutinterwiki-summary": "ၼႃႈလိၵ်ႈၸိူဝ်းပႃႈတႂ်ႈၼႆႉ မၼ်းဢမ်ႇၵွင်ႉဝႆႉၸူး မၢႆဢွၵ်ႇၽႃႇသႃႇၵႂၢမ်း တၢင်ႇၸိူဝ်း",
+ "withoutinterwiki-legend": "တူဝ်ၼမ်းၼႃႈ",
+ "withoutinterwiki-submit": "ၼႄ",
+ "fewestrevisions": "ၼႃႈလိၵ်ႈၸိူဝ်းမီး ၶေႃႈၶူၼ်ႉႁႃ ဢၼ်ဢေႇသေပိူၼ်ႈ",
+ "nbytes": "$1 {{PLURAL:$1|ၿႆႉ|ၿႆႉ}}",
+ "ncategories": "{{PLURAL:$1|လိူင်ႈ|လိူင်ႈတင်းလၢႆ}}",
+ "ninterwikis": "$1 {{PLURAL:$1|ဝီႇၶီႇၽၢႆႇၼႂ်း|ဝီႇၶီႇၸိူဝ်းၽၢႆႇၼႂ်း}}",
+ "nlinks": "$1 {{PLURAL:$1|ႁဵင်းၵွင်ႉ|ႁဵင်းၵွင်ႉ}}",
+ "nmembers": "$1 {{PLURAL:$1|member|ၽူႈၶဝ်ႈၸုမ်း}}",
+ "nmemberschanged": "$1 → $2 {{PLURAL:$2|ၽူႈၶဝ်ႈၸုမ်း|ၽူႈၶဝ်ႈၸုမ်း}}",
+ "nrevisions": "$1 {{PLURAL:$1|ၶေႃႈၶူၼ်ႉလူ|ၶေႃႈၶူၼ်ႉလူ}}",
+ "nimagelinks": "ၸႂ်ႉဝႆႉၵႃႈတီႈၼိူဝ် $1 {{PLURAL:$1|ၼႃႈလိၵ်ႈ|ၼႃႈလိၵ်ႈ}}",
+ "ntransclusions": "ၸႂ်ႉဝႆႉၵႃႈတီႈၼိူဝ် $1 {{PLURAL:$1|ၼႃႈလိၵ်ႈ|ၼႃႈလိၵ်ႈ}}",
+ "specialpage-empty": "တွၼ်ႈတႃႇ ၶေႃႈပွင်ႇၼႄ ဢၼ်ၼႆႉၼႆႉ မၼ်းဢမ်ႇမီး ၽွၼ်းလႆႈ။",
+ "lonelypages": "ၼႃႈလိၵ်ႈ ႁၢမ်းႁိူၼ်း",
+ "lonelypagestext": "ၼႃႈလိၵ်ႈၸိူဝ်းပႃႈတႂ်ႈၼႆႉ မၼ်းဢမ်ႇလႆႈ ၵွင်ႉဝႆႉ ဢမ်ႇၼၼ် ဢမ်ႇလႆႈၶဝ်ႈပႃႈဝႆႉ တႂ်ႈၼႂ်း ၼႃႈလိၵ်ႈတႃႇၸိူဝ်း ၼင်ႇ {{SITENAME}} ၼႆႉ။",
+ "uncategorizedpages": "ၼႃႈလိၵ်ႈၸိူဝ်းဢမ်ႇမီးလိူင်ႈ",
+ "uncategorizedcategories": "လိူင်ႈ ၸိူဝ်းဢမ်ႇၶပ်ႉလိူင်ႈဝႆႉ",
+ "uncategorizedimages": "ၽၢႆႇၸိူဝ်း ဢမ်ႇမီးလိူင်ႈ",
+ "uncategorizedtemplates": "လွၵ်းပိူင် ၸိူဝ်းဢမ်ႇမီးလိူင်ႈ",
+ "unusedcategories": "လိူင်ႈၸိူဝ်း ဢမ်ႇၸႂ်ႉဝႆႉ",
+ "unusedimages": "ၾၢႆႇ ၸိူဝ်းဢမ်ႇၸႂ်ႉဝႆႉ",
+ "wantedcategories": "လိူင်ႈၸိူဝ်း ၶႂ်ႈလႆႈမႃး",
+ "wantedpages": "ၼႃႈလိူၵ်ႈ ၸိူဝ်းၶႂ်ႈလႆႈမႃး",
+ "wantedpages-badtitle": "ႁူဝ်ၶေႃႈၽိတ်းပိူင်ႈ ၵႃႈတႂ်ႈၼႂ်း ၽွၼ်းလႆႈ မၵ်းသႂ်ႇဝႆႉ : $1",
+ "wantedfiles": "ၾၢႆႇ ၸိူဝ်းၶႂ်ႈလႆႈမႃး",
+ "wantedfiletext-cat-noforeign": "ၾၢႆႇၸိူဝ်းပႃႈတႂ်ႈၼႆႉ ထုၵ်ႇၸႂ်ႉဝႆႉယူႇ သေတႃႉ မၼ်းဢမ်ႇမီးဝႆႉယဝ်ႉ။ လိူဝ်သေၼၼ်ႉ၊ ၼႃႈလိၵ်ႈၸိူဝ်း ဢဝ်ၾၢႆႇၽင်ဝႆႉသေ ၸိူဝ်းဢမ်ႇမီးဝႆႉၼၼ်ႉ ႁဵတ်းသဵၼ်ႈမၢႆဝႆႉ ၵႃႈတီႈၼႂ်း [[:$1]] ။",
+ "wantedfiletext-nocat-noforeign": "ၾၢႆႇၸိူဝ်းပႃႈတႂ်ႈၼႆႉ ၸႂ်ႉဝႆႉသေတႃႉ မၼ်းဢမ်ႇမီးဝႆႉယဝ်ႉ။",
+ "wantedtemplates": "လွၵ်းပိူင် ဢၼ်ၶႂ်ႈလႆႈမႃး",
+ "mostlinked": "ၼႃႈလိၵ်ႈၸိူဝ်း မီးႁဵင်းၵွင်ႉၸူး ၼမ်သေပိူၼ်ႈ",
+ "mostlinkedcategories": "လိူင်ႈ ၸိူဝ်းမီး ႁဵင်းၵွင်ႉၼမ်သေပိူၼ်ႈ",
+ "mostlinkedtemplates": "ၼႃႈလိၵ်ႈ ၸိူဝ်းမီးၵဵင်ႇၽႄ ၼမ်သေပိူၼ်ႈ",
+ "mostcategories": "ၼႃႈလိၵ်ႈၸိူဝ်း မီးလိူင်ႈၼမ်သေပိူၼ်ႈ",
+ "mostimages": "ၾၢႆႇ ၸိူဝ်းမီး ႁဵင်းၵွင်ႉၸူး ၼမ်သေပိူၼ်ႈ",
+ "mostinterwikis": "ၼႃႈလိၵ်ႈ ၸိူဝ်းမီး ဝီႇၶီႇၼႂ်ႈ ၼမ်သေပိူၼ်ႈ",
+ "mostrevisions": "ၼႃႈလိၵ်ႈၸိူဝ်းမီး ၶေႃႈၶူၼ်ႉလူ ဢၼ်ၼမ်သေပိူၼ်ႈ",
+ "prefixindex": "ၼႃႈလိၵ်ႈတင်းသဵင်ႈ ၸိူဝ်းဢၼ်ပႃး တူဝ်ၼမ်းၼႃႈ",
+ "prefixindex-namespace": "ၼႃႈလိၵ်ႈတင်းသဵင်ႈ ဢၼ်ပႃး တူဝ်ၼမ်းၼႃႈ ($1 လွၵ်းၸိုဝ်ႈ)",
+ "prefixindex-submit": "ၼႄ",
+ "shortpages": "ၼႃႈလိၵ်ႈ ၸိူဝ်းဢၼ်ပွတ်း",
+ "longpages": "ၼႃႈလိၵ်ႈၸိူဝ်း ဢၼ်ယၢဝ်း",
+ "deadendpages": "ၼႃႈလိၵ်ႈ ၸိူဝ်းသုတ်း",
+ "deadendpagestext": "ၼႃႈလိၵ်ႈၸိူဝ်းပႃႈတႂ်ႈၼႆႉ ဢမ်ႇလႆႈၵွင်ႉၸူး ၼႃႈလိၵ်ႈတၢင်ႇၸိူဝ်း တီႈၼႂ်း {{SITENAME}}။",
+ "protectedpages": "ၼႃႈလိၵ်ႈၸိူဝ်းႁႄႉၵင်ႈဝႆႉ",
+ "protectedpages-noredirect": "သိူင်ႇ တူဝ်ပိၼ်ႇၸီႉ",
+ "protectedpagesempty": "ဢမ်ႇမီးၼႃႈလိၵ်ႈ ၸႂ်ႉၽၢင်ၵိုၵ်းသေ ႁႄႉၵင်ႈဝႆႉ ယၢမ်းလဵဝ်",
+ "protectedpages-timestamp": "ၸုမ်ႈၶၢဝ်းယၢမ်း",
+ "protectedpages-page": "ၼႃႈလိၵ်ႈ",
+ "protectedpages-expiry": "ဢႃႇယုသဵင်ႈ",
+ "protectedpages-performer": "ၽူႈၸႂ်ႉတိုဝ်း ဢၼ်ႁႄႉၵင်ႈ",
+ "protectedpages-params": "ၽၢင်ၵိုၵ်း ႁႄႉၵၼ်ႈ",
+ "protectedpages-reason": "လွင်ႈတၢင်း",
+ "protectedpages-submit": "ၼႃႈလိၵ်ႈ ၸိူဝ်းဢွၵ်ႇၼႄ",
+ "protectedpages-unknown-timestamp": "ဢမ်ႇႁူႉၸွမ်း",
+ "protectedpages-unknown-performer": "ၽူႈၸႂ်ႉတိုဝ်း ဢၼ်ဢမ်ႇႁူႉ",
+ "protectedtitles": "ၼႃႈလိၵ်ႈၸိူဝ်းႁႄႉၵင်ႈဝႆႉ",
+ "protectedtitlesempty": "ဢမ်ႇမီးႁူဝ်ၶေႃႈ ၸိူဝ်းၸႂ်ႉၽၢင်ၵိုၵ်းၼႆႉသေ ႁႄႉၵင်ႈဝႆႉ ယၢမ်းလဵဝ်",
+ "protectedtitles-submit": "ဢွၵ်ႇၼႄ ႁူဝ်ၶေႃႈ",
+ "listusers": "သဵၼ်ႈမၢႆ ၽူႈၸႂ်ႉတိုဝ်း",
+ "listusers-editsonly": "ၼႄပၼ် ၽူႈၸႂ်ႉတိုဝ်း ၸိူဝ်းမႄးထတ်းၼၼ်ႉၵူၺ်း",
+ "listusers-creationsort": "ၶပ်ႉၸႅၼ်ၸွမ်း ဝၼ်းထီႉ ၵေႃႇသၢင်ႈ",
+ "listusers-desc": "ၶပ်ႉၸႅၼ်ႇၸွမ်း မၢႆၶပ်ႉတူဝ်လဵၵ်ႉ",
+ "usereditcount": "$1 {{PLURAL:$1|မႄးထတ်း|မႄးထတ်း}}",
+ "usercreated": "{{GENDER:$3|ၵေႃႇသၢင်ႈယဝ်ႉ}} မိူဝ်ႈ $1 မိူဝ်ႈ$2",
+ "newpages": "ၼႃႈလိၵ်ႈမႂ်ႇ",
+ "newpages-submit": "ၼႄ",
+ "newpages-username": "ၸိုဝ်ႈၽူႈၸႂ်ႉတိုဝ်း :",
+ "ancientpages": "ၼႃႈလိၵ်ႈ ၵဝ်ႇမွၼ်ႇ",
+ "move": "ၶၢႆႉ",
+ "movethispage": "ၶၢႆႉဢွင်ႈ ၼႃႈလိၵ်ႈၼႆႉ",
+ "unusedcategoriestext": "ၼႃႈလိၵ်ႈလိူင်ႈ ၸိူဝ်းပႃႈတႂ်ႈၼႆႉ မီးဝႆႉယူႇ၊ ႁူမ်ႈဝႃႈ ဢမ်ႇမီး ၼႃႈလိၵ်ႈတၢင်ႇၸိူဝ်း ဢမ်ႇၼၼ်ႉ လိူင်ႈ ဢၼ်ၸႂ်ႉၶဝ်ဝႆႉ။",
+ "notargettitle": "ဢမ်ႇမီး တီႈယိူင်း",
+ "notargettext": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇလႆႈမၵ်းမၼ်ႈဝႆႉ ၼႃႈလိၵ်ႈတီႈယိူင်း ဢမ်ႇၼၼ် ၽူႈၸႂ်ႉတိုဝ်း တွၼ်ႈတႃႇႁဵတ်း ၼႃႈၵၢၼ်ၼႆႉ။",
+ "nopagetitle": "ဢမ်ႇမီး ၼႃႈလိၵ်ႈ တီႈယိူင်းၸူး",
+ "pager-older-n": "{{PLURAL:$1|older 1|ဢၼ်ၵဝ်ႇၵဝ်ႇ $1}}",
+ "booksources": "ငဝ်ႈငႃႇ ပပ်ႉလိၵ်ႈ",
+ "booksources-search-legend": "ၶူၼ်ႉႁႃတႃႇ ငဝ်ႇငႃႇပပ်ႉ",
+ "booksources-search": "ၶူၼ်ႉႁႃ",
+ "log": "သၢႆမၢႆ",
+ "allpages": "ၼႃႈလိၵ်ႈတင်းသဵင်ႈ",
+ "allarticles": "ၼႃႈလိၵ်ႈတင်းသဵင်ႈ",
+ "allpagessubmit": "ၶူၼ်ႉႁႃ",
+ "categories": "လိူင်ႈ",
+ "mywatchlist": "သဵၼ်ႈမၢႆပႂ်ႉတူၺ်း",
+ "watch": "ပႂ်ႉတူၺ်း",
+ "dellogpage": "မွတ်ႇပႅတ်ႈ သၢႆမၢႆ",
+ "rollbacklink": "ထွႆပွၵ်ႈၶိုၼ်း",
+ "rollbacklinkcount": "ၵိင်ႈၶိုၼ်းလင် $1 {{PLURAL:$1|edit|မႄးထတ်း}}",
+ "protectlogpage": "မၢႆတမ်း ၵၢၼ်ႁေႉၵင်ႈ",
+ "undeleterevisions": "$1 {{PLURAL:$1|revision|revisions}} မွတ်ႇပႅတ်ႈယဝ်ႉ",
+ "undeletelink": "တူၺ်း/ၶိုၼ်းမိူၼ်ၵဝ်ႇ",
+ "undeleteviewlink": "တူၺ်း",
+ "namespace": "ဢွင်ႈတီႈၸိုဝ်ႈ",
+ "invert": "ပဵၼ်ႇၽၢႆႇ လွင်ႈလိူၵ်ႈသၢင်ႈ",
+ "tooltip-invert": "လိူၵ်ႈပၼ် လွၵ်းၼႆႉဝႃႈ တႃႇတေလပ်ႉဝႆႉ လွင်ႈလႅၵ်ႈလၢႆႈ ဢၼ်ႁဵတ်းၸူး ၼႃႈလိၵ်ႈၸိူဝ်းၼႆႉ ၸွမ်းၼင်ႇ ၸိုဝ်ႈ ၸိူဝ်းလိူၵ်ႈဝႆႉ (လႄႈ ၸွမ်းၼင်ႇၸိုဝ်ႈ ၸိူဝ်းဢၼ်လိူၵ်ႈဝႆႉယဝ်ႉၼၼ်ႉ)",
+ "namespace_association": "ဢွင်ႈတီႈၸိုဝ်ႈ ဢၼ်ၵွင်ႉၵၢႆႇဝႆႉ",
+ "tooltip-namespace_association": "လိူၵ်ႈပၼ် လွၵ်းၼႆႉ တႃႇတေႁႂ်ႈပႃး ၶေႃႈဢုပ်ႇဢူဝ်း ဢမ်ႇၼၼ် ၸိုဝ်ႈႁူဝ်ၶေႃႈ ဢၼ်ၵပ်းၵၢႆႇလူၺ်ႈ ႁူဝ်ၶေႃႈ ဢၼ်လိူၵ်ႈဝႆႉၼၼ်ႉ။",
+ "blanknamespace": "ႁူဝ်ႁႅၵ်ႇ",
+ "contributions": "{{GENDER:$1|User}} ၶဝ်ႈႁူမ်ႈပႃး",
+ "mycontris": "လွင်ႈၶဝ်ႈႁူမ်ႈ",
+ "anoncontribs": "လွင်ႈၶဝ်ႈႁူမ်ႈ",
+ "month": "တႄႇဢဝ်လိူၼ် (လႄႈ ဢၼ်ပူၼ်ႉမႃး):",
+ "year": "တႄႇဢဝ်ပီ (လႄႈ ဢၼ်ပူၼ်ႉမႃး):",
+ "whatlinkshere": "ႁဵင်းၵွင်ႉ ဢၼ်မီးတီႈၼႆႉ ပဵၼ်သင်",
+ "whatlinkshere-title": "ၼႃႈလိၵ်ႈၸိူဝ်းလိင်ႉၸူး \"$1\"",
+ "whatlinkshere-page": "ၼႃႈလိၵ်ႈ",
+ "linkshere": "ၼႃႈလိၵ်ႈၽၢႆႇတႂ်ႈၼႆႉ မၼ်းၵွင်ႉသၢၼ် ဝႆႉၸူး <strong>[[:$1]]</strong>:",
+ "isredirect": "ပိၼ်ႇႁူဝ်ၼႃႈလိၵ်ႈ",
+ "istemplate": "တူဝ်ၶဝ်ႈပႃး",
+ "isimage": "ၾၢႆႇၵွင်ႉ",
+ "whatlinkshere-prev": "{{PLURAL:$1|ဢၼ်ပူၼ်ႉမႃး|ဢၼ်ပူၼ်ႉမႃး $1}}",
+ "whatlinkshere-next": "{{PLURAL:$1|သိုပ်ႇၼႃႈ|သိုပ်ႇၼႃႈ $1}}",
+ "whatlinkshere-links": "ႁဵင်းၵွင်ႉ",
+ "whatlinkshere-hideredirs": "$1 လၢႆႈၽၢႆႇ",
+ "whatlinkshere-hidetrans": "သိူင်ႇတူဝ်ၶဝ်ႈပႃး",
+ "whatlinkshere-hidelinks": "$1 လိင်ႉၵွင်ႉ",
+ "whatlinkshere-filters": "တူဝ်ထွင်",
+ "blocklink": "ႁႄႉတတ်း",
+ "unblocklink": "ဢမ်ႇႁႄႉႁၢမ်ႈ",
+ "contribslink": "ၶဝ်ႈႁူမ်ႈ",
+ "movelogpage": "ၶၢႆႉသၢႆမၢႆ",
+ "revertmove": "ပိၼ်ႇပွၵ်ႈၶိုၼ်း",
+ "export": "သူင်ႇၼႃႈလိၵ်ႈဢွၵ်ႇ",
+ "thumbnail-more": "ႁၢင်ႈယႂ်ႇ",
+ "tooltip-pt-userpage": "ၼႃႈလိၵ်ႈသုၼ်ႇတူဝ်ၸဝ်ႈၵဝ်ႇ",
+ "tooltip-pt-mytalk": "ၼႃႈလိၵ်ႈသပ်းလႅင်းၸဝ်ႈၵဝ်ႇ",
+ "tooltip-pt-preferences": "{{GENDER:|ၸဝ်ႈၵဝ်ႇ}} ငဝ်ႈၵုမ်းပိူင်",
+ "tooltip-pt-watchlist": "သဵၼ်ႈမၢႆၼႃႈလိၵ်ႈ ဢၼ်ပႂ်ႉတူၺ်း တႃႇလႅၵ်ႈလၢႆႈ",
+ "tooltip-pt-mycontris": "သဵၼ်ႈမၢႆ ၶေႃႈလိၵ်ႈၸဝ်ႈၵဝ်ႇ",
+ "tooltip-pt-login": "ဢမ်ႇလွၵ်ႉဢိၼ်ႇၵေႃႈမူၼ်ႉမႄးလႆႈ ၵူၺ်း တိုၵ်းသူၼ်းႁႂ်ႈလွၵ်ႉဢိၼ်ႇ",
+ "tooltip-pt-logout": "လွၵ်ႉဢဝ်ႉ",
+ "tooltip-pt-createaccount": "ၸဝ်ႈၵဝ်ႇထုၵ်ႇပၼ်ႁႅင်း တွၼ်ႈတႃႇၵေႃႇသၢင်ႈ ဢၶွင်ႉလႄႈ လွၵ်ႉဢိၼ်ႇ။ ႁူမ်ႈဝႃႈၼၼ်သေတႃႉ ဢမ်ႇၸႂ်ႈဝႃႈ ဢမ်ႇႁဵတ်းဢမ်ႇလႆႈၼင်ႇၵဝ်ႇ။",
+ "tooltip-ca-talk": "ဢုပ်ႇဢူဝ်းလွင်ႈပႃးဝႆႉၼႂ်းၼႃႈလိၵ်ႈ",
+ "tooltip-ca-edit": "မႄးထတ်း ၼႃးလိၵ်ႈၼႆႉ",
+ "tooltip-ca-addsection": "တႄႇပွတ်းတွၼ်ႈမႂ်ႇ",
+ "tooltip-ca-viewsource": "ၼႃႈလိၵ်ႈၼႆႉ ထုၵ်ႇႁေႉၵင်ႈဝႆႉ။ သူၸၢင်ႊတူၺ်း ငဝ်ႈငႃႇမၼ်းလႆႈ",
+ "tooltip-ca-history": "လွင်ႈၶူၼ်ႉလူဢၼ်ပူၼ်ႉမႃး တႃႇၼႃႈလိၵ်ႈၼႆႉ",
+ "tooltip-ca-protect": "ႁေႉၵင်ႈ ၼႃႈလိၵ်ႈၼႆႉ",
+ "tooltip-ca-delete": "ယႃႉ ၼႃႈလိၵ်ႈၼႆႉ",
+ "tooltip-ca-move": "ၶၢႆႉ ၼႃႈလိၵ်ႈၼႆႉ",
+ "tooltip-ca-watch": "ဢဝ်ၼႃႈလိၵ်ႈၼႆႉ သႂ်ႇၼႂ်းသဵၼ်ႈမၢႆပႂ်ႉတူၺ်း",
+ "tooltip-search": "ၶူၼ်ႉႁႃ {{SITENAME}}",
+ "tooltip-search-go": "သင်ဝႃႈ မီးဝႆႉၸိုဝ်ႈ ၵႂႃႇၸူးၼႃႈလိၵ်ႈၸွမ်းၼင်ႇၸိုဝ်ႈၼႆႉ",
+ "tooltip-search-fulltext": "ႁႃပၼ် ၼႃႈလိၵ်ႈ ဢၼ်ပႃးတူဝ်လိၵ်ႈ ၸိူဝ်းၼႆႉလႄႈ",
+ "tooltip-p-logo": "ၶဝ်ႈလႄႇ ၼႃႈႁူဝ်ႁႅၵ်ႈ",
+ "tooltip-n-mainpage": "ၶဝ်ႈလႄႇ ၼႃႈႁူဝ်ႁႅၵ်ႈ",
+ "tooltip-n-mainpage-description": "ၶဝ်ႈလႄႇ ၼႃႈႁူဝ်ႁႅၵ်ႈ",
+ "tooltip-n-portal": "လိူင်ႈၶူင်းၵၢၼ်၊ သူႁဵတ်းသင်လႆႈ လႄႈ တေႁႃလႆႈၵႃႈလႂ်",
+ "tooltip-n-currentevents": "သွၵ်ႈႁႃ လွၼ်ႉၶၢဝ်ႇ ပိုၼ်ႉလင်တွၼ်ႈတႃႇ လွင်ႈႁဵတ်းသၢင်ႈယၢမ်းလဵဝ်ၼႆႉ",
+ "tooltip-n-recentchanges": "သဵၼ်ႈမၢႆမူၼ်ႉမႄးၼႂ်းဝီႇၶီႇ ဢၼ်ပႆႇႁိုင်",
+ "tooltip-n-randompage": "ပိုတ်ႇၼႃႈလိၵ်ႈသၢင်ႇထုၵ်ႇဝႃႈ",
+ "tooltip-n-help": "ဢွင်ႈတီႈ တႃႇသွၵ်ႈႁႃ",
+ "tooltip-t-whatlinkshere": "သဵၼ်ႈမၢႆ ၼႃႈလိၵ်ႈဝီႇၶီႇလိင်ႉတီႈၼႆႈ",
+ "tooltip-t-recentchangeslinked": "ၵၢၼ်လႅၵ်ႈလၢႆႈၼႂ်းၼႃႈလိၵ်ႈ ဢၼ်လုၵ်ႉတီႈၼႃႈလိၵ်ႈၼႆႉသေ လိင်ႉဝႆႉ",
+ "tooltip-feed-atom": "ၾိတ်ႉဢတွမ်ႊ(Atom) ၶွင်ႈၼႃႈလိၵ်ႈၼႆႉ",
+ "tooltip-t-contributions": "သဵၼ်ႈမၢႆလွင်ႈၶဝ်ႈႁူမ်ႈ တွၼ်ႈတႃႇ {{GENDER:$1|ၽူႈၸႂ်ႉတိုဝ်းၼႆ့}}",
+ "tooltip-t-upload": "လူတ်ႇၶိုၼ်ႈ ၾၢႆႇ",
+ "tooltip-t-specialpages": "ပိုတ်ႇၼႄသဵၼ်ႈ ၼႃႈလိၵ်ႈ ၶိုၵ်ႉတွၼ်း",
+ "tooltip-t-print": "ၼႃႈလိၵ်ႈၼႆႉ မၼ်းပဵၼ်ပိူဝ်းသျိၼ်း ဢၼ်ဢိတ်ႇဢွၵ်ႇလႆႈ",
+ "tooltip-t-permalink": "ႁဵင်းၵွင်ႉမၼ်ႈၵိုမ်းတႃႇၸူး ၼႃႈလိၵ်ႈၶူၼ်ႉလူဢၼ်ၼႆႉ",
+ "tooltip-ca-nstab-main": "တူၺ်းၼႃႈလိၵ်ႈလမ်းၼႂ်း",
+ "tooltip-ca-nstab-user": "တူၺ်းၼႃႈလိၵ်ႈၽူႈၸႂ်ႉတိုဝ်း",
+ "tooltip-ca-nstab-special": "ၼႃႈလိၵ်ႈၼႆႉပဵၼ် ၼႃႈလိၵ်ႈၶိုၵ်ႉတွၼ်း၊ ၸဝ်ႈၵဝ်ႇ တေဢမ်ႇၸၢင်ႈ မႄးထတ်းႁင်း ၸဝ်ႈၵဝ်ႇ ၶေႃၶေႃ။",
+ "tooltip-ca-nstab-project": "တူၺ်းၼႃႈလိၵ်ႈ ပရေႃးၵျႅၵ်ႉ",
+ "tooltip-ca-nstab-image": "တူၺ်းၼႃႈလိၵ်ႈၾၢႆႇ",
+ "tooltip-ca-nstab-template": "တူၺ်း ပိူင်တမ်း",
+ "tooltip-ca-nstab-category": "တူၺ်းလိူင်ႈမၼ်း",
+ "tooltip-save": "ၵဵပ်းသိမ်း လွင်ႈလႅၵ်ႈလၢႆႈ",
+ "tooltip-preview": "လူင်ႈၼႃႈတူၺ်း လွင်ႈလႅၵ်ႈလၢႆႈၸဝ်ႈၵဝ်ႇ၊ ၶႅၼ်းတေႃႈၸႂ်ႉပၼ် မိူဝ်ႈပႆႇသိမ်း",
+ "tooltip-diff": "ၼႄပၼ် လွင်ႈလႅၵ်ႈလၢႆႈ ၸိူဝ်းၸဝ်ႈၵဝ်ႇ ႁဵတ်းၵႂႃႇတီႈ တူဝ်လိၵ်ႈ",
+ "tooltip-rollback": "\"ႁူၼ်လင်ၶိုၼ်း\" ၼႆႉ မၼ်းတေဢဝ် ၼႃႈလိၵ်ႈၼႆႉ ၶိုၼ်းပိၼ်ႇဝၢႆႇၸူး ၸွမ်းၼင်ႇ ၽူႈႁူမ်ႈသၢင်ႈ ၵေႃႉလိုၼ်းသုတ်းၼၼ်ႉ ထတ်းသၢင်မႃး။",
+ "tooltip-undo": "\"Undo\" ၼႆ့ မၼ်းတေဢဝ် ၵၢၼ်ထတ်းသၢင်ဢၼ်ၼႆႉ ၶိုၼ်းပိၼ်ႇၸူးသေ ၶိုၼ်းပၼ် ပၼ် လၢႆးတူၺ်းလူင်ႈၼႃႈ တႃႇၵၢၼ်ထတ်းသၢင်ႈဢၼ်ၼႆႉ။ မၼ်းတေႁဵတ်းႁႂ်ႈၸဝ်ႈၵဝ်ႇ ထႅမ်သႂ်ႇ လွင်ႈတၢင်းမၼ်း ၵႃႈတီႈ လွၵ်းႁူဝ်ႁုပ်ႇမၼ်းၼၼ်ႉယူႇ။",
+ "tooltip-summary": "ထႅမ်သႂ်ႇ ၶေႃႈသပ်းလႅင်း ဢၼ်ၵႅပ်ႈ",
+ "simpleantispam-label": "ၵူတ်ႇထတ်း Anti-spam.\n<strong>ယႃႇပေ</strong>ထႅမ်ဢၼ်ၼႆႉသႂ်ႇ!",
+ "pageinfo-toolboxlink": "လွၼ်ႉၶၢဝ်ႇၼႃႈလိၵ်ႈ",
+ "previousdiff": "ၵၢၼ်မႄးထတ်း ဢၼ်ၵဝ်ႇ",
+ "nextdiff": "ထတ်းသၢင်ႈဢၼ်မႂ်ႇမႂ်ႇ",
+ "file-info-size": "$1 × $2 pixels, တၢင်းလဵၵ်ႉတၢင်းယႂ်ႇ ၾၢႆႇ: $3, ယိူင်ႈ MIME: $4",
+ "file-nohires": "ဢမ်ႇမီး ဢၼ်ႁႅင်းၸိုၼ်ႈသႂ်ႇမၼ်း သုင်သုင်",
+ "svg-long-desc": "ၾၢႆႇ SVG, ၸိုဝ်ႈ $1 × $2 pixels, သႅၼ်းၾၢႆႇ : $3",
+ "show-big-image": "ၾၢႆႇငဝ်ႈတိုၼ်း",
+ "show-big-image-preview": "သႅၼ်းတႃႇတူၺ်းလူင်ႈၼႃႈ: $1.",
+ "show-big-image-other": " {{PLURAL:$2|resolution|resolutions}}: $1 တၢင်ႇဢၼ်",
+ "show-big-image-size": "$1 × $2 ၽိၵ်ႉသိူဝ်ႇ",
+ "metadata": "ၶေႃႈမုၼ်းၼႅပ်ႇ",
+ "metadata-help": "ၾၢႆႇဢၼ်ၼႆႉ မၼ်းၶဝ်ႈပႃးဝႆႉလွၼ်ႉၶၢဝ်ႇ ထႅမ်သႂ်ႇမႂ်ႇ၊ ဢၼ်ဢၢပ်ႈထုၵ်ႉတီႈ ၵွင်ႈထႆႇ digital ဢမ်ႇၼၼ် တူဝ်ၵူတ်ႇ scanner ထႅမ်သႂ်ႇသေ သၢင်ႈဝႆႉ ဢမ်ႇၼၼ် လႅၵ်ႈလၢႆႈဝႆႉ။\nသင်ၸိူဝ်ႉၾၢႆႇဢၼ်ၼႆႉ ထုၵ်ႇမႄးၶိုၼ်းဝႆႉၵႃႈတီႈ ၾၢႆႇငဝ်ႈတိုၼ်းမၼ်းၼႆ ၼႂ်းၵႃႈ ၸဝ်ႈၵဝ်ႇမႄးဝႆႉၼၼ်ႉ မၼ်းတေဢမ်ႇထၢင်ႇႁၢင်ႈလႆႈ ၵူႈလွင်ႈ။",
+ "metadata-fields": "ၸိူဝ်းပဵၼ် လွၵ်းၶေႃႈမုၼ်းႁူဝ်ယွႆႈ တႃႇၶႅပ်းႁၢင်ႈ ဢၼ်မီးဝႆႉတီႈၼႂ်း ၶေႃႈၶၢဝ်ႇပွတ်း message ၼႆႉၼႆ မၼ်းတေၶဝ်ႈပႃးဝႆႉ ၵႃႈတီႈ ၼႃႈလိၵ်ႈၶႅပ်းႁၢင်ႈ ဢၼ်တေၼႄပၼ် ၽွင်းမိူဝ်ႈ လွၵ်းၶေႃႈမုၼ်းႁူဝ်ယွႆႈ လၼ်ႇၼႄပၼ်။\nဢၼ်ၵိုတ်းလိူဝ်ၸိူဝ်းၼၼ်ႉတႄႉ တေထုၵ်ႇလပ်ႉဝႆႉ ၸွမ်းၼင်ႇ ပိူင်ၵႅဝ်ႈမၼ်း။\n\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+ "exif-orientation": "ၼႃႈဝၢႆႇ",
+ "exif-xresolution": "ႁႅင်းၸိုၼ်ႈသႂ် ၼႃႈသုင်",
+ "exif-yresolution": "ႁႅင်းၸိုၼ်ႈသႂ် ၼႃႈယၢဝ်း",
+ "exif-datetime": "ဝၼ်းထီႉ လႄႈ ၶၢဝ်းယၢမ်း လႅၵ်ႈလၢႆႈၾၢႆႇ",
+ "exif-make": "ႁူင်းၵၢၼ်ႁဵတ်းဢွၵ်ႇ ၵွင်ႈထႆႇ",
+ "exif-model": "မေႃႇတႄႇ ၵွင်ႈထႆႇ",
+ "exif-software": "သွပ်ႉဝႄးၸိူဝ်းၸႂ်ႉမႃး",
+ "exif-exifversion": "ဢွၵ်ႇဝိူဝ်းသျိၼ်း",
+ "exif-colorspace": "ဢွင်ႈတီႈသီ",
+ "exif-datetimeoriginal": "ဝၼ်းလႄႈၶၢဝ်းယၢမ်း တမ်ႈတီႈ ၶေႃႈမုၼ်းမႂ်ႇ",
+ "exif-datetimedigitized": "ဝၼ်းထီႉလႄႈ ၶၢဝ်းယၢမ်းတႃႇ digitizing",
+ "exif-orientation-1": "သႃမၺ်း",
+ "namespacesall": "တင်းမူတ်း",
+ "monthsall": "တင်းမူတ်း",
+ "watchlistedit-normal-done": "{{PLURAL:$1|A single title was|$1 titles were}} ဢဝ်ဢွၵ်ႇ တမ်ႈတီႈ သဵၼ်ႈဢၼ်ၸဝ်ႈၵဝ်ႇ ပႂ်ႉတူၺ်း",
+ "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|talk]])",
+ "specialpages": "ၼႃႈလိၵ်ႈ ၶိုၵ်ႉတွၼ်း",
+ "tag-filter": "ၶတ်းလိူၵ်ႈဢဝ်[[Special:Tags|Tag]]:",
+ "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag|Tags}}]]: $2)",
+ "logentry-delete-delete": "$1 {{GENDER:$2|မွတ်ႇယဝ်ႉ}} ၼႃႈလိၵ်ႈ $3",
+ "logentry-move-move": "$1 {{GENDER:$2|ၶၢႆႉယဝ်ႉ}} ၼႃႈလိၵ်ႈ $3 တေႃႇ $4",
+ "logentry-newusers-create": "ဢၶွင်ႉၽူႈၸႂ်ႉတိုဝ်း $1 ၼႆႉ လႆႈ {{GENDER:$2|ၵေႃႇသၢင်ႈယဝ်ႉ}}",
+ "logentry-upload-upload": "$1 {{GENDER:$2|လူတ်ႇၶိုၼ်ႈၵႂႃႇယဝ်ႉ}} $3",
+ "searchsuggest-search": "ၶူၼ်ႉႁႃ",
+ "mw-widgets-dateinput-no-date": "ပႆႇလိူၵ်ႈဝၼ်းယၢမ်း"
+}
"Macofe",
"Roonyh",
"Matma Rex",
- "SusithCM"
+ "SusithCM",
+ "Sandaru"
]
},
"tog-underline": "සබැඳි යටීර කිරීම:",
"tog-newpageshidepatrolled": "විමසුමට ලක්කෙරුණු පිටු, අළුත් පිටු ලැයිස්තුව තුල නොපෙන්වන්න",
"tog-hidecategorization": "පිටුවේ ප්රවර්ගීකරණය සගවන්න",
"tog-extendwatchlist": "මෑත වෙනස්වීම් පමණක් නොව, අදාළ සියළු වෙනස්වීම් දක්වා පෙන්වන අයුරින් මුර-ලැයිස්තුව පුළුල් කරන්න",
- "tog-usenewrc": "මෑත වෙනස්වීම් සහ මුර ලැයිස්තුව හී පිටුව අනුව සමූහ වෙනස්වීම් (ජාවාස්ක්රිප්ට් ඇවැසිය)",
+ "tog-usenewrc": "මෑත වෙනස්වීම් සහ මුර ලැයිස්තුව හී පිටුව අනුව සමූහ වෙනස්වීම්",
"tog-numberheadings": "ශීර්ෂ-නාම ස්වයංක්රීයව අංකනය කරන්න",
"tog-showtoolbar": "සංස්කරණ මෙවලම්තීරුව පෙන්වන්න",
"tog-editondblclick": "ද්විත්ව-ක්ලික් කිරීම මගින් පිටු සංස්කරණය අරඹන්න",
- "tog-editsectiononrightclick": "ඡේද ශීර්ෂ මත දකුණු-ක්ලික් කිරීමෙන් ඡේද සංස්කරණය සක්රීය කරන්න (ජාවාස්ක්රිප්ට්)",
+ "tog-editsectiononrightclick": "ඡේද ශීර්ෂ මත දකුණු-ක්ලික් කිරීමෙන් ඡේද සංස්කරණය සක්රීය කරන්න",
"tog-watchcreations": "මම තනන පිටු හා මම උඩුගත කරන ගොනු මාගේ මුරලැයිස්තුවට එක් කරන්න",
"tog-watchdefault": "මම සංස්කරණය කරන පිටු හා ගොනු මාගේ මුර ලැයිස්තුවට එක් කරන්න",
"tog-watchmoves": "මම ගෙනයන පිටු හා ගොනු මාගේ මුර ලැයිස්තුවට එක් කරන්න",
"noname": "වලංගු පරිශීලක-නාමයක් සඳහන් කිරීමට ඔබ අසමත් වී ඇත.",
"loginsuccesstitle": "පිවිසුම සාර්ථකයි!",
"loginsuccess": "'''දැන් ඔබ , \"$1\" ලෙස, {{SITENAME}} වෙත පිවිස සිටී.'''",
- "nosuchuser": "\"$1\" යන නමැති පරිශීලකයෙකු නොමැත.\nපරිශීලක නාමයන්හි මහාප්රාණ ආදිය සැලකේ (case sensitive).\nඔබගේ අක්ෂර-වින්යාසය පිරික්සා බැලීම හෝ, [[Special:UserLogin/signup|නව ගිණුමක් තැනීම]] හෝ සිදුකරන්න.",
+ "nosuchuser": "\"$1\" යන නමැති පරිශීලකයෙකු නොමැත.\nපරිශීලක නාමයන්හි මහාප්රාණ ආදිය සැලකේ (case sensitive).\nඔබගේ අක්ෂර-වින්යාසය පිරික්සා බැලීම හෝ, [[Special:CreateAccount|නව ගිණුමක් තැනීම]] හෝ සිදුකරන්න.",
"nosuchusershort": "\"$1\" නමින් පරිශීලකයෙකු නොමැත.\nඅක්ෂර-වින්යාසය පිරික්සා බලන්න.",
"nouserspecified": "ඔබ විසින් පරිශීලක-නාමයක් සඳහන් කල යුතු වේ.",
"login-userblocked": "මෙම පරිශීලකයා වාරණය කොට ඇත. පිවිසීමට ඉඩ දෙනු නොලැබේ.",
"accmailtext": "[[User talk:$1|$1]] සඳහා අහඹු ලෙස ජනනය කරන ලද මුරපදයක් $2 වෙත යවා ඇත.\n\nමෙම නව ගිණුම සඳහා මුරපදය, ප්රවිෂ්ට වීමෙන් අනතුරුව, ''[[Special:ChangePassword|මුර පදය වෙනස් කරන්න]]'' පිටුව තුලදී වෙනස් කල හැක.",
"newarticle": "(නව)",
"newarticletext": "බැඳියක් ඔස්සේ පැමිණ ඔබ පිවිස ඇත්තේ දැනට නොපවතින පිටුවකටයි.\nමෙම ලිපිය තැනීමට අවශ්ය නම්, පහත ඇති කොටුව තුල අකුරු ලිවීම අරඹන්න (වැඩිදුර තොරතුරු සඳහා [$1 උදවු පිටුව] බලන්න).\nඔබ මෙහි පිවිස ඇත්තේ අත්වැරැද්දකින් නම්, ඔබගේ ගවේෂකයෙහි '''ආපසු''' බොත්තම ඔබන්න.",
- "anontalkpagetext": "----''මෙම සංවාද පිටුව අයත් වන්නේ තවමත් ගිණුමක් තනා නැති හෝ එසේ කොට එනමුදු එය භාවිතා නොකරන හෝ නිර්නාමික පරිශීලකයෙකුටය.\nඑබැවින්, ඔහු/ඇය හැඳින්වීමට සංඛ්යාත්මක IP ලිපිනය භාවිතා කිරීමට අප හට සිදුවේ.\nපරිශීලකයන් කිහිප දෙනෙකු විසින් මෙවැනි IP ලිපිනයක් හවුලේ පරිහරණය කරනවා විය හැක.\nඔබ නිර්නාමික පරිශීලකයෙකු නම් හා ඔබ පිළිබඳ අනනුකූල පරිකථනයන් සිදුවෙන බවක් ඔබට හැඟේ නම්, අනෙකුත් නිර්නාමික පරිශීලකයන් හා සමග මෙවැනි සංකූලතා ඇතිවීම වලක්වනු වස්, කරුණාකර [[Special:UserLogin/signup|ගිණුමක් තැනීමට]] හෝ [[Special:UserLogin|ප්රවිෂ්ට වීමට]] කාරුණික වන්න.''",
+ "anontalkpagetext": "----''මෙම සංවාද පිටුව අයත් වන්නේ තවමත් ගිණුමක් තනා නැති හෝ එසේ කොට එනමුදු එය භාවිතා නොකරන හෝ නිර්නාමික පරිශීලකයෙකුටය.\nඑබැවින්, ඔහු/ඇය හැඳින්වීමට සංඛ්යාත්මක IP ලිපිනය භාවිතා කිරීමට අප හට සිදුවේ.\nපරිශීලකයන් කිහිප දෙනෙකු විසින් මෙවැනි IP ලිපිනයක් හවුලේ පරිහරණය කරනවා විය හැක.\nඔබ නිර්නාමික පරිශීලකයෙකු නම් හා ඔබ පිළිබඳ අනනුකූල පරිකථනයන් සිදුවෙන බවක් ඔබට හැඟේ නම්, අනෙකුත් නිර්නාමික පරිශීලකයන් හා සමග මෙවැනි සංකූලතා ඇතිවීම වලක්වනු වස්, කරුණාකර [[Special:CreateAccount|ගිණුමක් තැනීමට]] හෝ [[Special:UserLogin|ප්රවිෂ්ට වීමට]] කාරුණික වන්න.''",
"noarticletext": "දැනට මෙම පිටුවෙහි කිසිදු පෙළක් නොමැත.\nඅනෙකුත් පිටුවල [[Special:Search/{{PAGENAME}}|මෙම පිටු ශීර්ෂය සඳහා ගවේශනය කිරීම]] හෝ,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} අදාළ ලඝු-සටහන් සඳහා ගවේෂණය කිරීම],\nහෝ [{{fullurl:{{FULLPAGENAME}}|action=edit}} මෙම පිටුව සංස්කරණය කිරීම] හෝ ඔබට සිදු කල හැක</span>.",
"noarticletext-nopermission": "දැනට මෙම පිටුවෙහි කිසිදු පෙළක් නොමැත.\nඅනෙකුත් පිටුවල [[Special:Search/{{PAGENAME}}|මෙම පිටු ශීර්ෂය සඳහා ගවේශනය කිරීම]] හෝ, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}}අදාළ ලඝු-සටහන් සඳහා ගවේෂණය කිරීම]</span>, හෝ මෙම පිටුව සංස්කරණය කිරීම හෝ ඔබට කල හැක.",
"missing-revision": "සංශෝධනය නම් පිටුවේ #$1 \"{{FULLPAGENAME}}\" නොපවතියි.\n\nමෙය සාමාන්යයෙන් මකා දැමූ පිටුවක ඉතිහාසය සබැඳියන් යල් පැනගිය පහත සඳහන් හේතු වේ [{{fullurl:{{#Special:Log}}/මකන්න|page={{FULLPAGENAMEE}}}} මැකීමේ ලොගය].",
"noname": "Nezadali ste platné používateľské meno.",
"loginsuccesstitle": "Prihlásenie úspešné",
"loginsuccess": "'''Teraz ste prihlásený do {{GRAMMAR:genitív|{{SITENAME}}}} ako „$1“.'''",
- "nosuchuser": "Používateľské meno „$1“ neexistuje.\nV používateľských menách sa rozlišuje veľkosť písmen.\nSkontrolujte preklepy alebo sa [[Special:UserLogin/signup|zaregistrujte ako nový používateľ]].",
+ "nosuchuser": "Používateľské meno „$1“ neexistuje.\nV používateľských menách sa rozlišuje veľkosť písmen.\nSkontrolujte preklepy alebo sa [[Special:CreateAccount|zaregistrujte ako nový používateľ]].",
"nosuchusershort": "V súčasnosti neexistuje používateľ s menom „$1“. Skontrolujte preklepy.",
"nouserspecified": "Musíte uviesť meno používateľa.",
"login-userblocked": "Tento používateľ je zablokovaný. Nie je mu dovolené prihlásiť sa.",
"accmailtext": "Náhodne vytvorené heslo pre používateľa [[User talk:$1|$1]] bolo poslané na $2. Je možné ho zmeniť na stránke ''[[Special:ChangePassword|zmena hesla]]'' po prihlásení.",
"newarticle": "(Nový)",
"newarticletext": "Sledovali ste odkaz na stránku, ktorá zatiaľ neexistuje.\nStránku vytvoríte tak, že začnete písať do poľa nižšie (viac informácií nájdete na stránkach [$1 nápovedy]).\nAk ste sa sem dostali nechtiac, kliknite na tlačidlo <strong>späť</strong> vo svojom prehliadači.",
- "anontalkpagetext": "----''Toto je diskusná stránka anonymného používateľa, ktorý nemá vytvorené svoje konto alebo ho nepoužíva.\nPreto musíme na jeho identifikáciu použiť numerickú IP adresu. Je možné, že takúto IP adresu používajú viacerí používatelia.\nAk ste anonymný používateľ a máte pocit, že vám boli adresované irelevantné diskusné príspevky, [[Special:UserLogin/signup|vytvorte si konto]] alebo sa [[Special:UserLogin|prihláste]], aby sa zamedzilo budúcim zámenám s inými anonymnými používateľmi.''",
+ "anontalkpagetext": "----''Toto je diskusná stránka anonymného používateľa, ktorý nemá vytvorené svoje konto alebo ho nepoužíva.\nPreto musíme na jeho identifikáciu použiť numerickú IP adresu. Je možné, že takúto IP adresu používajú viacerí používatelia.\nAk ste anonymný používateľ a máte pocit, že vám boli adresované irelevantné diskusné príspevky, [[Special:CreateAccount|vytvorte si konto]] alebo sa [[Special:UserLogin|prihláste]], aby sa zamedzilo budúcim zámenám s inými anonymnými používateľmi.''",
"noarticletext": "Na tejto stránke sa momentálne nenachádza žiadny text.\nMôžete [[Special:Search/{{PAGENAME}}|vyhľadávať názov tejto stránky]] v obsahu iných stránok,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} vyhľadávať v súvisiacich záznamoch] alebo [{{fullurl:{{FULLPAGENAME}}|action=edit}} vytvoriť túto stránku]</span>.",
"noarticletext-nopermission": "Táto stránka momentálne neobsahuje žiadny text.\nMôžete [[Special:Search/{{PAGENAME}}|hľadať názov tejto stránky]] v texte iných stránok\nalebo <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} hľadať v súvisiacich záznamoch]</span>, ale nemáte oprávnenie túto stránku vytvoriť.",
"missing-revision": "Revízia #$1 stránky s názvom „{{FULLPAGENAME}}“ neexistuje.\n\nPravdepodobne ste nasledovali zastaraný odkaz na historickú verziu stránky, ktorá bola medzičasom odstránená.\nPodrobnosti nájdete v [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} zázname zmazaní].",
"아라",
"MaGa",
"Skalcaa",
- "Janezdrilc"
+ "Janezdrilc",
+ "Matma Rex"
]
},
"tog-underline": "Podčrtavanje povezav:",
"tog-ccmeonemails": "Pošlji mi kopijo e-pošt, ki jih pošljem drugim uporabnikom",
"tog-diffonly": "Pod primerjavo ne prikaži vsebine strani",
"tog-showhiddencats": "Prikaži skrite kategorije",
- "tog-norollbackdiff": "Ne prikaži primerjave po izvedeni vrnitvi",
+ "tog-norollbackdiff": "Po izvedeni vrnitvi ne prikaži primerjave",
"tog-useeditwarning": "Opozori me, ko skušam zapreti urejevalno polje z neshranjenimi spremembami",
"tog-prefershttps": "Med prijavo vedno uporabljaj varno povezavo",
"underline-always": "Vedno",
"noname": "Niste vnesli veljavnega uporabniškega imena.",
"loginsuccesstitle": "Sedaj ste prijavljeni",
"loginsuccess": "'''Zdaj ste prijavljeni v {{GRAMMAR:tožilnik|{{SITENAME}}}} kot »$1«.'''",
- "nosuchuser": "Uporabnik z imenom »$1« ne obstaja.\nUporabniška imena so občutljiva na velikost črk.\nPreverite črkovanje ali pa si [[Special:UserLogin/signup|ustvarite nov uporabniški račun]].",
+ "nosuchuser": "Uporabnik z imenom »$1« ne obstaja.\nUporabniška imena so občutljiva na velikost črk.\nPreverite črkovanje ali pa si [[Special:CreateAccount|ustvarite nov uporabniški račun]].",
"nosuchusershort": "Uporabnik z imenom »$1« ne obstaja.\nPreverite črkovanje.",
"nouserspecified": "Prosimo, vpišite uporabniško ime.",
"login-userblocked": "Ta uporabnik je blokiran. Prijava ni dovoljena.",
"accmailtext": "Naključno generirano geslo za [[User talk:$1|$1]] smo poslali na $2. Po prijavi ga lahko spremenite na strani za ''[[Special:ChangePassword|spremembo gesla]]''.",
"newarticle": "(Nov)",
"newarticletext": "Sledili ste povezavi na stran, ki še ne obstaja.\nDa bi stran ustvarili, vnesite v spodnji obrazec besedilo\n(za več informacij glej [$1 pomoč]).\nČe ste sem prišli po pomoti, v svojem brskalniku kliknite gumb ''Nazaj''.",
- "anontalkpagetext": "---- ''To je pogovorna stran brezimnega uporabnika, ki si še ni ustvaril računa ali pa ga ne uporablja. Zaradi tega moramo uporabiti IP-naslov za njegovo/njeno ugotavljanje istovetnosti. Takšen IP-naslov si lahko deli več uporabnikov. Če ste brezimni uporabnik in menite, da so nepomembne pripombe namenjene vam, prosimo [[Special:UserLogin|ustvarite račun]] ali pa se [[Special:UserLogin/signup|vpišite]], da preprečite zmedo z drugimi nepodpisanimi uporabniki.''",
+ "anontalkpagetext": "----\n<em>To je pogovorna stran brezimnega uporabnika, ki si še ni ustvaril računa ali pa ga ne uporablja.</em>\nZaradi tega moramo uporabiti IP-naslov za njegovo/njeno ugotavljanje istovetnosti.\nTakšen IP-naslov si lahko deli več uporabnikov.\nČe ste brezimni uporabnik in menite, da so nepomembne pripombe namenjene vam, prosimo [[Special:CreateAccount|ustvarite račun]] ali pa se [[Special:UserLogin|vpišite]], da preprečite zmedo z drugimi nepodpisanimi uporabniki.",
"noarticletext": "Na tej strani ni trenutno nobenega besedila. Naslov strani lahko poskusite [[Special:Search/{{PAGENAME}}|poiskati]] na drugih straneh, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} v dnevniških zapisih] ali pa [{{fullurl:{{FULLPAGENAME}}|action=edit}} stran ustvarite]</span>.",
"noarticletext-nopermission": "Na strani trenutno ni nobenega besedila.\nLahko poskusite [[Special:Search/{{PAGENAME}}|poiskati naslov strani]] na drugih straneh ali <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} v povezanih dnevniških zapisih]</span>, vendar za ustvarjanje strani nimate zadostnih dovoljenj.",
"missing-revision": "Redakcija št. $1 strani »{{FULLPAGENAME}}« ne obstaja.\n\nPo navadi se to zgodi, ko sledite zastareli povezavi na zgodovino strani, ki jo je nekdo izbrisal.\nPodrobnosti lahko najdete v [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} dnevniku brisanja].",
"right-override-export-depth": "Izvoz strani, vključno s povezaimi straneh do globine 5",
"right-sendemail": "Pošiljanje e-pošte drugim uporabnikom",
"right-passwordreset": "Ogled e-pošt ponastavitve gesel",
- "right-managechangetags": "Ustvarjanje in brisanje [[Special:Tags|oznak]] iz zbirke podatkov",
+ "right-managechangetags": "Ustvarjanje in (dez)aktivacijo [[Special:Tags|oznak]]",
"right-applychangetags": "Uveljavitev [[Special:Tags|oznak]] skupaj s spremembami",
"right-changetags": "Dodajanje in odstranjevanje poljubnih [[Special:Tags|oznak]] na posameznih redakcijah in dnevniških vnosih",
+ "right-deletechangetags": "Izbris [[Special:Tags|oznak]] iz zbirke podatkov",
"grant-generic": "Snov pravic »$1«",
"grant-group-page-interaction": "Interakcija s stranmi",
"grant-group-file-interaction": "Interakcija s predstavnostjo",
"action-viewmyprivateinfo": "ogled svojih zasebnih informacij",
"action-editmyprivateinfo": "urejanje svojih zasebnih informacij",
"action-editcontentmodel": "urejanje vsebinskega modela strani",
- "action-managechangetags": "ustvarjanje in brisanje oznak iz zbirke podatkov",
+ "action-managechangetags": "ustvarjanje in (dez)aktivacijo oznak",
"action-applychangetags": "uveljavitev oznak skupaj z vašimi spremembami",
"action-changetags": "dodajanje in odstranjevanje poljubnih oznak na posameznih redakcijah in dnevniških vnosih",
+ "action-deletechangetags": "izbris oznak iz zbirke podatkov",
"nchanges": "$1 {{PLURAL:$1|sprememba|spremembi|spremembe|sprememb|sprememb}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|od zadnjega obiska}}",
"enhancedrc-history": "zgodovina",
"upload-form-label-own-work": "To je moje lastno delo",
"upload-form-label-infoform-categories": "Kategorije",
"upload-form-label-infoform-date": "Datum",
- "upload-form-label-own-work-message-local": "Potrjujem, da datoteko nalagam v skladu s pogoji uporabe in pravili o licenciranju na {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Če datoteke ne morete naložiti pod pogoji {{SITENAME}}, zaprite to okno in poskusite drugo metodo.",
- "upload-form-label-not-own-work-local-local": "Morda želite poskusiti [[Special:Upload|privzeto stran za nalaganje]].",
- "upload-form-label-own-work-message-default": "Razumem, da datoteko nalagam v deljeno hrambo. Potrjujem, da to počnem v skladu s tukajšnjimi pogoji uporabe in pravili za licenciranje.",
- "upload-form-label-not-own-work-message-default": "Če datoteke ne morete naložiti pod pogoji deljene hrambe, zaprite to okno in poskusite drugo metodo.",
- "upload-form-label-not-own-work-local-default": "Morda želite datoteko poskusiti naložiti na [[Special:Upload|strani za nalaganje na {{SITENAME}}]], če jo lahko naložite pod njihovimi pravili.",
- "upload-form-label-own-work-message-shared": "Izjavljam, da sem lastnik avtorskih pravic te datoteke, strinjam se z nepreklicno objavo datoteke v Wikimedijini Zbirki pod dovoljenjem [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Priznanje avtorstva-Deljenje pod enakimi pogoji 4.0] in strinjam se s [https://wikimediafoundation.org/wiki/Terms_of_Use Pogoji uporabe].",
- "upload-form-label-not-own-work-message-shared": "Če niste lastnik avtorskih pravic datoteke ali jo želite objaviti pod drugačnim dovoljenje, uporabite [https://commons.wikimedia.org/wiki/Special:UploadWizard Čarovnik za nalaganje v Zbirko].",
- "upload-form-label-not-own-work-local-shared": "Morda želite datoteko poskusiti naložiti na [[Special:Upload|strani za nalaganje na {{SITENAME}}]], če stran dovoljuje nalaganje datoteke pod njihovimi pravili.",
+ "upload-form-label-own-work-message-generic-local": "Potrjujem, da datoteko nalagam v skladu s pogoji uporabe in pravili o licenciranju na {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Če datoteke ne morete naložiti pod pogoji {{SITENAME}}, zaprite to okno in poskusite drugo metodo.",
+ "upload-form-label-not-own-work-local-generic-local": "Morda želite poskusiti [[Special:Upload|privzeto stran za nalaganje]].",
+ "upload-form-label-own-work-message-generic-foreign": "Razumem, da datoteko nalagam v deljeno hrambo. Potrjujem, da to počnem v skladu s tukajšnjimi pogoji uporabe in pravili za licenciranje.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Če datoteke ne morete naložiti pod pogoji deljene hrambe, zaprite to okno in poskusite drugo metodo.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Morda želite datoteko poskusiti naložiti na [[Special:Upload|strani za nalaganje na {{SITENAME}}]], če jo lahko naložite pod njihovimi pravili.",
"backend-fail-stream": "Ne morem pretakati datoteke $1.",
"backend-fail-backup": "Ne morem varnostno kopirati datoteke $1.",
"backend-fail-notexists": "Datoteka $1 ne obstaja.",
"changecontentmodel-success-text": "Spremenili smo vrsto vsebine [[:$1]].",
"changecontentmodel-cannot-convert": "Vsebine na [[:$1]] ni mogoče pretvoriti v vrsto $2.",
"changecontentmodel-nodirectediting": "Model vsebine $1 ne podpira neposrednega urejanja",
+ "changecontentmodel-emptymodels-title": "Na voljo ni noben model vsebine",
+ "changecontentmodel-emptymodels-text": "Vsebine na [[:$1]] ni mogoče pretvoriti v katero koli vrsto.",
"log-name-contentmodel": "Dnevnik sprememb modela vsebine",
"log-description-contentmodel": "Dogodki, povezani z modeli vsebin strani",
"logentry-contentmodel-new": "$1 je {{GENDER:$2|ustvaril|ustvarila|ustvaril(-a)}} stran $3 z neprivzetim modelom vsebine »$5«",
"lockdbsuccesstext": "Podatkovna baza je bila zaklenjena.<br />\nNe pozabite je [[Special:UnlockDB|odkleniti]], ko boste končali z vzdrževanjem.",
"unlockdbsuccesstext": "Zbirka podatkov {{GRAMMAR:rodilnik|{{SITENAME}}}} je spet odklenjena.",
"lockfilenotwritable": "Datoteka zaklepanja zbirke podatkov ni zapisljiva.\nZa zaklepanje in odklepanje zbirke podatkov mora biti ta datoteka zapisljiva s strani spletnega strežnika.",
+ "databaselocked": "Zbirka podatkov je že zaklenjena.",
"databasenotlocked": "Zbirka podatkov ni zaklenjena.",
"lockedbyandtime": "($1 dne $2 ob $3)",
"move-page": "Preimenuj $1",
"timezone-local": "Krajevno",
"duplicate-defaultsort": "'''Opozorilo:''' Privzeti ključ razvrščanja »$2« prepiše prejšnji privzeti ključ razvrščanja »$1«.",
"duplicate-displaytitle": "<strong>Opozorilo:</strong> Prikazni naslov »$2« prepiše prejšnji prikazni naslov »$1«.",
+ "restricted-displaytitle": "<strong>Opozorilo:</strong> Prikazni naslov »$1« smo prezrli, saj ni enak dejanskemu naslovu strani.",
"invalid-indicator-name": "<strong>Napaka:</strong> Atribut <code>name</code> indikatorjev stanja strani ne sme biti prazen.",
"version": "Različica",
"version-extensions": "Nameščene razširitve",
"tags-delete-not-found": "Oznaka »$1« ne obstaja.",
"tags-delete-too-many-uses": "Oznaka »$1« je uporabljena pri več kot $2 {{PLURAL:$2|redakciji|redakcijah}}, kar pomeni, da je ni mogoče izbrisati.",
"tags-delete-warnings-after-delete": "Oznako »$1« smo izbrisali, vendar smo naleteli na {{PLURAL:$2|naslednjo težavo|naslednji težavi|naslednje težave}}:",
+ "tags-delete-no-permission": "Nimate dovoljenja za izbris oznak sprememb.",
"tags-activate-title": "Aktiviraj oznako",
"tags-activate-question": "Aktivirali boste oznako »$1«.",
"tags-activate-reason": "Razlog:",
"noname": "Du muußt enn giltiga Nutzernoama oangahn.",
"loginsuccesstitle": "Oameldung erfolgreich",
"loginsuccess": "Du biest jitz ols „$1“ bei {{SITENAME}} oagemeldet.",
- "nosuchuser": "Dar Nutzernoame „$1“ existiert ne.\nIeberpriefe de Schreibweise (Gruß-/Kleenschreibung beachta) oder [[Special:UserLogin/signup|melde diech ols neuer Benutzer oa]].",
+ "nosuchuser": "Dar Nutzernoame „$1“ existiert ne.\nIeberpriefe de Schreibweise (Gruß-/Kleenschreibung beachta) oder [[Special:CreateAccount|melde diech ols neuer Benutzer oa]].",
"nosuchusershort": "Dar Nutzernoame „$1“ existiert ne. Bitte ieberpriefe de Schreibweise.",
"nouserspecified": "Bitte gieb enn Benutzernoamen oa.",
"wrongpassword": "Doas Passwurt ies foalsch (oder fehlt). Bitte versuche is erneut.",
"accmailtitle": "Passwurt wourde verschickt",
"newarticle": "(Neu)",
"newarticletext": "Du best an'm Link zu anner Seite gefulgt, de nee vorhanden ies.\nIm de Seite oazulega, trage denn Text ei de undastehende Box a (siehe de [$1 Hilfeseite] fier meh Informationen).\nBest du fälschlicherweise hier, klicke de '''Zerricke'''-Schaltfläche dennes Browsers.",
- "anontalkpagetext": "----''Diese Seite dient dazu, a'm nee oagemeldeta Benutzer Noachrichta zu hinterlassa. 'S werd senne IP-Atresse zur Identifizierung verwendet. IP-Atressen kinna vu mehrera Nutzern gemeensam verwendet waan. Wenn du miet dann Kommentarn uff dieser Seite nischt oafanga koast, richta se siech vermutlich oa an'n friehera Inhaber denner IP-Atresse und du koast se ignorieren. Du koast dir au a [[Special:UserLogin/signup|Nutzerkonto erstalla]] oder dich [[Special:UserLogin|oamelda]], im kinftig Verwechslunga miet andern anonyma Nutzern zu vermeida.''",
+ "anontalkpagetext": "----''Diese Seite dient dazu, a'm nee oagemeldeta Benutzer Noachrichta zu hinterlassa. 'S werd senne IP-Atresse zur Identifizierung verwendet. IP-Atressen kinna vu mehrera Nutzern gemeensam verwendet waan. Wenn du miet dann Kommentarn uff dieser Seite nischt oafanga koast, richta se siech vermutlich oa an'n friehera Inhaber denner IP-Atresse und du koast se ignorieren. Du koast dir au a [[Special:CreateAccount|Nutzerkonto erstalla]] oder dich [[Special:UserLogin|oamelda]], im kinftig Verwechslunga miet andern anonyma Nutzern zu vermeida.''",
"noarticletext": "Diese Seite enthält momentan noo kenn Text.\nDu koast diesen Tittel uffa andern Seita [[Special:Search/{{PAGENAME}}|sucha]],\n<span class=\"plainlinks\"> ei dan zugeheeriga [{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Logbichern sucha] oder diese Seite [{{fullurl:{{FULLPAGENAME}}|action=edit}} bearbta]</span>.",
"noarticletext-nopermission": "Diese Seite enthält momentan noo kenn Text.\nDu koast diesen Tittel uff dann andern Seita [[Special:Search/{{PAGENAME}}|sucha]]\noder de zugehieriga <span class=\"plainlinks\">[{{fullurl:{{#special:Log}}|page={{FULLPAGENAMEE}}}} Logbichern betrachta].</span>",
"userpage-userdoesnotexist": "Doas Nutzerkonto „<nowiki>$1</nowiki>“ ies nee vurhanda. Bitte priefe, ob du diese Seite wirklich erstella/beoarbta wielst.",
"noname": "Ma jiro magaca isticmaalaha aad qortay",
"loginsuccesstitle": "Gudagalida waa la dhamaystiray",
"loginsuccess": "'''Waxaa hadda gudaha ugu soo gashay {{SITENAME}} sida \"$1\".'''",
- "nosuchuser": "Ma jiro isticmaalo leh magacaan \"$1\".\nMagacyada way kala waaweyn yihiin.\nSax hingaada, ama [[Special:UserLogin/signup|samayso magac gudagale ah]].",
+ "nosuchuser": "Ma jiro isticmaalo leh magacaan \"$1\".\nMagacyada way kala waaweyn yihiin.\nSax hingaada, ama [[Special:CreateAccount|samayso magac gudagale ah]].",
"nosuchusershort": "Majiro isticmaale leh magacaan \"$1\". Sax qoraalkaaga.",
"nouserspecified": "Waa in aad magac gudagale heshaa.",
"login-userblocked": "Isticmaalahaan waa la mamnuucay. Lama ogolo in oo gudaha u galo",
"accmailtext": "Ereysir loogu tala galay [[User talk:$1|$1]] waxaa loogu diray $2.\n\nAkoonkaan cusub eraysirkiisa waxaa ku badali kartaa bogga ''[[Special:ChangePassword|bedel eraysirka]]'' si aad u soo gashid.",
"newarticle": "(Cusub)",
"newarticletext": "Waxaa soo raacday link kula soo xiriiriyay bog oo hadda wali jirin.\nHadii aad rabto in aad sameyso bogga, hoos ka bilaaw qoraalkaada (fiiri [$1 bogga caawinaada] wax war ah oo kale).\nhadii aad meeshaan ku soo qaldantay, riix batoonka barowsahaaga '''gadaal uuga noqo''' .",
- "anontalkpagetext": "----''Meeshaan waa bogga wadahadalka isticmaalayaasha la aqoon oo aanan weli sameysanin akoon, ama wali isticmaalin. \nSidaas darteed, waa in aan isticmaalnaa lambar cinwaaneedka IP:ga si aan u ogaano asiga/ayada. Cinwaanka IP:ga waxaa suurto gal ah in ay qeybsadaan isticmaaleyaal badan.\nHadii aad tahay isticmaale aanan la'aqoonsanin oo aad dareemaysid in laguu gafay, fadlan [[Special:UserLogin/signup|sameyso akoon]] ama [[Special:UserLogin|gudaha gal]] si aad u dhowrsatid in hadhowdi laguugu qaldo isticmaalada kale oo aann la'aqoonsanin.''",
+ "anontalkpagetext": "----''Meeshaan waa bogga wadahadalka isticmaalayaasha la aqoon oo aanan weli sameysanin akoon, ama wali isticmaalin. \nSidaas darteed, waa in aan isticmaalnaa lambar cinwaaneedka IP:ga si aan u ogaano asiga/ayada. Cinwaanka IP:ga waxaa suurto gal ah in ay qeybsadaan isticmaaleyaal badan.\nHadii aad tahay isticmaale aanan la'aqoonsanin oo aad dareemaysid in laguu gafay, fadlan [[Special:CreateAccount|sameyso akoon]] ama [[Special:UserLogin|gudaha gal]] si aad u dhowrsatid in hadhowdi laguugu qaldo isticmaalada kale oo aann la'aqoonsanin.''",
"noarticletext": "Boggaan hadda wax qoraal ah kuma qorno.\nWaxaa [[Special:Search/{{PAGENAME}}|magaca boggaan]] ka raadin kartaa bogyaasha kale,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} raadi kuwo la mid ah],\nama [{{fullurl:{{FULLPAGENAME}}|action=edit}} wax ka bedel boggaan]</span>.",
"noarticletext-nopermission": "Hadda boggaan wax qoraal ah kuma qorno.\nWaxaa [[Special:Search/{{PAGENAME}}|magaca boggaan ka raadin kartaa]] boggaga kale ama <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ka raadi gudagalayaasha kale]</span>.",
"userpage-userdoesnotexist": "Isticmaalahan \"<nowiki>$1</nowiki>\" ma diiwaangashno.\nFadlan fiiri hadii aad rabto in aad sameeyso/wax ka bedesho boggaan.",
"allpagesprefix": "Soo saar boggaga leh horgalaha:",
"allpagesbadtitle": "Cinwaanka bogga xaq ma'aha ama waa ereyo u gaar ah isdhaafka-luqadaha ama isdhaafka-wiki. Waxaa ku jirikara xuruufo aanan loo isticmaalikarin cinwaan ahaan.",
"categories": "Qeybaha",
- "special-categories-sort-count": "xisaabi marka aad tirisid",
"linksearch-ns": "Xarun magaceedka:",
"linksearch-ok": "Raadi",
"linksearch-line": "$1 wuxuu ka socdaa $2",
"watchlisttools-raw": "Badal liiska waardiyeenta ceeriinka ah",
"version-poweredby-others": "kuwa kale",
"redirect-file": "Magaca faylka",
- "fileduplicatesearch-legend": "Raadi mid tusaale ah",
"fileduplicatesearch-submit": "Raadi",
"specialpages": "bogagga khaaska ah",
"specialpages-note-top": "Furaha",
"october-date": "$1 tetor",
"november-date": "$1 nëntor",
"december-date": "$1 dhjetor",
+ "period-am": "PD",
+ "period-pm": "PD",
"pagecategories": "{{PLURAL:$1|Kategoria|Kategoritë}}",
"category_header": "Faqet në kategorinë \"$1\"",
"subcategories": "Nënkategoritë",
"morenotlisted": "Kjo listë nuk është e plotë.",
"mypage": "Faqja",
"mytalk": "Diskuto",
- "anontalk": "Diskutimet për këtë IP",
+ "anontalk": "Diskutimi",
"navigation": "Navigimi",
"and": " dhe",
"qbfind": "Gjeni",
"pool-timeout": "Mbaroi koha duke pritur për kyçin",
"pool-queuefull": "Radha e proceseve është mbushur",
"pool-errorunknown": "Gabim i panjohur",
- "pool-servererror": "Pishinë e numerimit te shërbimit nuk është në dispozicion (<span class=\"notranslate\" translate=\"asnjë\">$1</span>).",
+ "pool-servererror": "Shërbimi i pellgut të numërimit nuk është në dispozicion ($1).",
"poolcounter-usage-error": "Gabim përdorimi: $1",
"aboutsite": "Rreth {{SITENAME}}",
"aboutpage": "Project:Rreth",
"databaseerror-text": "\nKjo mund të tregojë një gabim në software.",
"databaseerror-textcl": " ka ndodhur një gabim ne query te bazën të dhënash",
"databaseerror-query": "\nPyetje: $ 1",
- "databaseerror-function": "Funksioni: <span class=\"notranslate\" translate=\"asnjë\">$1</span>",
- "databaseerror-error": "Gabim: <span class=\"notranslate\" translate=\"asnjë\">$1</span>",
+ "databaseerror-function": "Funksioni: $1",
+ "databaseerror-error": "Gabim: $1",
"laggedslavemode": "'''Kujdes:''' Kjo faqe nuk mund të ketë përditësime të kohëve të fundit.",
"readonly": "Databaza e kyçur",
"enterlockreason": "Shëno arsyen e kyçjes, gjithashtu shëno se kur mund të hapet.",
"filerenameerror": "I pamundur riemërtimi i skedës \"$1\" në \"$2\".",
"filedeleteerror": "E pamundur fshirja e skedës \"$1\".",
"directorycreateerror": "I pamundur krijimi i direktorisë \"$1\".",
- "directoryreadonlyerror": "Direktoria \"<span class=\"notranslate\" translate=\"asnjë\">$1</span>\" është vetëm e lexueshme",
- "directorynotreadableerror": "Direktoria \"<span class=\"notranslate\" translate=\"asnjë\">$1</span>\" nuk është e lexueshme.",
+ "directoryreadonlyerror": "Direktoria \"$1\" është vetëm e lexueshme",
+ "directorynotreadableerror": "Direktoria \"$1\" nuk është e lexueshme.",
"filenotfound": "E pamundur gjetja e skedës \"$1\".",
"unexpected": "Vlerë e papritur: \"$1\"=\"$2\".",
"formerror": "Gabim: Formulari nuk mund të dërgohet.",
"invalidtitle-unknownnamespace": "Titull jo i vlefshëm me numrin e panjohur të hapësirës së emrit $1 dhe tekstit \"$2\"",
"exception-nologin": "I paqasur",
"exception-nologin-text": "Ju lutem [[Special:Userlogin|hyni brënda]] për të qenë në gjendje të hyni në këtë faqe ose veprim.",
- "exception-nologin-text-manual": "Ju lutem <span class=\"notranslate\" translate=\"asnjë\">$1</span> që të jeni në gjendje për të hyrë në këtë faqe ose të veproni.",
+ "exception-nologin-text-manual": "Ju lutem $1 që të jeni në gjendje për të hyrë në këtë faqe ose të veproni.",
"virus-badscanner": "Konfiguracion i parregullt: Skaner i panjohur virusesh: ''$1''",
"virus-scanfailed": "skanimi dështoi (code $1)",
"virus-unknownscanner": "antivirus i pa njohur:",
"password-change-forbidden": "Ju nuk mund të ndryshoni fjalëkalimet në këtë wiki.",
"externaldberror": "Ose kishte një gabim tek regjistri i identifikimit të jashtëm, ose nuk ju lejohet të përtërini llogarinë tuaje të jashtme.",
"login": "Hyni",
+ "login-security": "Verifiko identitetin tuaj",
"nav-login-createaccount": "Hyni ose hapni një llogari",
"userlogin": "Hyni / hapni llogari",
"userloginnocreate": "Hyni",
"userlogin-resetlink": "Ke harruar të dhënat e tua të identifikimit?",
"userlogin-resetpassword-link": "Keni harruar fjalëkalimin?",
"userlogin-helplink2": "Ndihmë rreth identifikimit",
- "userlogin-loggedin": "Ju tashmë janë të regjistruar si <span class=\"notranslate\" translate=\"asnjë\">{{GJINIA:$1|</span><span class=\"notranslate\" translate=\"asnjë\">$1</span>}}.\nPërdorim formularin më poshtë që të hyni në si një përdorues tjetër.",
+ "userlogin-loggedin": "Ju tashmë jeni i regjistruar si {{GENDER:$1|$1}}.\nPërdore formularin më poshtë për të hyrë si një përdorues tjetër.",
"userlogin-createanother": "Krijo një llogari tjeter",
"createacct-emailrequired": "Posta elektronike",
"createacct-emailoptional": "Adresa Elektronike (me dëshirë)",
"noname": "Nuk keni dhënë një emër përdoruesi të pranueshëm.",
"loginsuccesstitle": "Identifikim i suksesshëm",
"loginsuccess": "'''Ju tani jeni identifikuar tek {{SITENAME}} si \"$1\".'''",
- "nosuchuser": "Nuk ka ndonjë përdorues me emrin \"$1\".\nKontrolloni shkrimin ose [[Special:UserLogin/signup|hapni një llogari të re]].",
+ "nosuchuser": "Nuk ka ndonjë përdorues me emrin \"$1\".\nKontrolloni shkrimin ose [[Special:CreateAccount|hapni një llogari të re]].",
"nosuchusershort": "Nuk ka asnjë përdorues me emrin \"$1\".",
"nouserspecified": "Ju duhet të jepni një nofkë",
"login-userblocked": "Ky përdorues është bllokuar. Identifikimi nuk lejohet.",
"resetpass-validity-soft": "Fjalëkalimi juaj ka skaduar dhe duhet të rivendoset. Ju lutem zgjidhni një fjalëkalim të ri tani, ose klikoni \"{{int:resetpass-submit-cancel}}\" për ta rivendosur më vonë.",
"passwordreset": "Ndrysho fjalkalimin",
"passwordreset-text-one": "Plotësoni këtë formular për të marrë një fjalëkalim të përkohshëm nëpërmjet postës elektronike.",
- "passwordreset-text-many": "<span class=\"notranslate\" translate=\"asnjë\">{{PLURAL:$1|</span>Mbush një nga fushat për të marrë një fjalëkalim të përkohshëm nëpërmjet postës elektronike.}}",
+ "passwordreset-text-many": "{{PLURAL:$1|Mbush një nga fushat për të marrë një fjalëkalim të përkohshëm nëpërmjet postës elektronike.}}",
"passwordreset-disabled": "Rivendosja e fjalëkalimit është deaktivizuar në këtë wiki.",
"passwordreset-emaildisabled": "Karakteristikat e Email janë të paaftë në këtë wiki.",
"passwordreset-username": "Nofka:",
"accmailtext": "Një fjalëkalim i krijuar në mënyrë të rastësishme për [[User talk:$1|$1]] u dërgua në $2.\n\nFjalëkalimi për këtë llogari mund të ndryshohet në faqen ''[[Special:ChangePassword|ndrysho fjalëkalimin]]'' pasi të jeni identifikuar.",
"newarticle": "(I ri)",
"newarticletext": "Ti ke ndjekur nje lidhje drejt një faqeje që nuk ekziston.\nPër ta krijuar këtë faqe, fillo të shkruash në kutinë e mëposhtme (shih [$1 faqen e ndihmës] për më shumë informacion).\nNëse ti ke mbërritur këtu gabimisht, atëherë kliko butonin '''pas''' të shfletuesit tënd.",
- "anontalkpagetext": "----'' Kjo është një faqe diskutimi për një përdorues anonim i cili nuk ka krijuar akoma një llogari, ose qe nuk e përdor atë. \n Prandaj, ne duhet të përdorim adresën IP numerike për identifikimin e tij. \nKjo adresë IP mund të përdoret nga disa përdorues.\n Në qoftë se jeni një përdorues anonim dhe mendoni se ndaj jush janë bërë komente të parëndësishme, ju lutem [[Special:UserLogin/signup|krijoni një llogari]] ose [[Special:UserLogin|identifikohuni]] për të shmangur konfuzionin në të ardhmen me përdorues të tjerë anonim .''",
- "noarticletext": "Momentalisht nuk ka tekst në këtë faqe.\nJu mund [[Special:Search/{{PAGENAME}}|ta kërkoni këtë titull]] në faqe tjera,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} të kërkoni ngjarjet e ngjashme në regjistër],\nose [{{fullurl:{{FULLPAGENAME}}|action=edit}} të redaktoni këtë faqe]</span>.",
+ "anontalkpagetext": "----'' Kjo është një faqe diskutimi për një përdorues anonim i cili nuk ka krijuar akoma një llogari, ose qe nuk e përdor atë. \n Prandaj, ne duhet të përdorim adresën IP numerike për identifikimin e tij. \nKjo adresë IP mund të përdoret nga disa përdorues.\n Në qoftë se jeni një përdorues anonim dhe mendoni se ndaj jush janë bërë komente të parëndësishme, ju lutem [[Special:CreateAccount|krijoni një llogari]] ose [[Special:UserLogin|identifikohuni]] për të shmangur konfuzionin në të ardhmen me përdorues të tjerë anonim .''",
+ "noarticletext": "Momentalisht nuk ka tekst në këtë faqe.\nJu mund [[Special:Search/{{PAGENAME}}|ta kërkoni këtë titull]] në faqe tjera,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} të kërkoni ngjarjet e ngjashme në regjistër],\nose [{{fullurl:{{FULLPAGENAME}}|action=edit}} të krijoni këtë faqe]</span>.",
"noarticletext-nopermission": "Për momentin faqja e kërkuar është bosh.\nJu mund të [[Special:Search/{{PAGENAME}}|kërkoni këtë titiull]] në faqet e tjera, ose të <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} këtkoni regjistrat e ngjashëm]</span>, por ju nuk mundeni ta krijoni këtë faqe.",
"missing-revision": "Inspektimi #$1 i faqes me emrin \"{{FULLPAGENAME}}\" nuk ekziston.\n\nKjo zakonisht shkaktuar duke ndjekur një lidhje të vjetër tek një faqe që është fshirë. Hollësitë mund të gjenden në [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} regjistrin e fshirjeve].",
"userpage-userdoesnotexist": "Llogaria e përdoruesit \"<nowiki>$1</nowiki>\" nuk është e regjistruar. \nJu lutem kontrolloni nëse dëshironi të krijoni/redaktoni këtë faqe.",
"contributions": "Kontributet e {{GENDER:$1|përdoruesit|përdorueses}}",
"contributions-title": "Kontributet e përdoruesit për $1",
"mycontris": "Kontributet",
+ "anoncontribs": "Kontribute",
"contribsub2": "Për $1 ($2)",
"nocontribs": "Nuk ka asnjë ndryshim që përputhet me këto kritere.",
"uctop": "(aktual)",
"whatlinkshere-prev": "{{PLURAL:$1|e kaluara|të kaluarat $1}}",
"whatlinkshere-next": "{{PLURAL:$1|tjetra|tjerat $1}}",
"whatlinkshere-links": "← lidhje",
- "whatlinkshere-hideredirs": "$1 përcjellimet",
+ "whatlinkshere-hideredirs": "$1 përcjellime",
"whatlinkshere-hidetrans": "$1 përfshirjet",
"whatlinkshere-hidelinks": "$1 lidhjet",
"whatlinkshere-hideimages": "$1 lidhjet me skedat",
"api-error-badtoken": "Gabim i brendshëm: Shenjë e keqe.",
"api-error-copyuploaddisabled": "Ngarkimi nga URL-ja është çaktivizuar në këtë server.",
"api-error-duplicate": "{{PLURAL:$1|Ekziston një skedë tjetër|Ekzistojnë disa skeda të tjera}} me të njëjtën përmbajtje.",
- "api-error-duplicate-archive": "{{Ekzistonte një skedë tjetër|Ekzistonin disa skeda të tjera}} me të njëjtën përmbajtje, por {{PLURAL:$1|ajo është|ato janë}} fshirë.",
+ "api-error-duplicate-archive": "{{PLURAL:$1|Ekzistonte një skedë tjetër|Ekzistonin disa skeda të tjera}} me të njëjtën përmbajtje, por {{PLURAL:$1|ajo është|ato janë}} fshirë.",
"api-error-empty-file": "Skeda që paraqitët ishte bosh.",
"api-error-emptypage": "Nuk lejohet krijimi i faqeve të reja bosh.",
"api-error-fetchfileerror": "Gabim i brendshëm: Diçka shkoi keq gjatë marrjes së skedës.",
"Srdjan m",
"Macofe",
"Сербијана",
- "Xð"
+ "Xð",
+ "Matma Rex"
]
},
"tog-underline": "Подвлачење веза:",
"tog-ccmeonemails": "Пошаљи ми копије имејлова које пошаљем другим корисницима",
"tog-diffonly": "Не приказуј садржај странице испод разлика",
"tog-showhiddencats": "Прикажи скривене категорије",
- "tog-norollbackdiff": "Ð\98зоÑ\81Ñ\82ави разлику након извршеног враћања",
+ "tog-norollbackdiff": "Ð\9dе пÑ\80иказÑ\83Ñ\98 разлику након извршеног враћања",
"tog-useeditwarning": "Упозори ме када напуштам страницу са несачуваним променама",
"tog-prefershttps": "Увек користи сигурну конекцију када сам пријављен.",
"underline-always": "увек подвлачи",
"category_header": "Странице у категорији „$1“",
"subcategories": "Поткатегорије",
"category-media-header": "Датотеке у категорији „$1“",
- "category-empty": "<div style=\"margin:2em 1em 0 1em; padding:0.5em; border:1px solid #AAA; text-align:center;\">''Ова категорија тренутно не садржи странице или датотеке.''</div>",
+ "category-empty": "<em>Ова категорија тренутно не садржи странице или датотеке.</em>",
"hidden-categories": "{{PLURAL:$1|Сакривена категорија|Сакривене категорије}}",
"hidden-category-category": "Скривене категорије",
"category-subcat-count": "{{PLURAL:$2|1=Ова категорија садржи само следећу поткатегорију.|Ова категорија има {{PLURAL:$1|1=следећу поткатегорију|следеће $1 поткатегорије|следећих $1 поткатегорија}}, од укупно $2.}}",
"newwindow": "(отвара се у новом прозору)",
"cancel": "Откажи",
"moredotdotdot": "Више…",
- "morenotlisted": "Ова листа није комплетна.",
+ "morenotlisted": "Овај списак није комплетан.",
"mypage": "Страница",
"mytalk": "Разговор",
"anontalk": "Разговор",
"perfcachedts": "Следећи подаци су кеширани и последњи пут су ажурирани $2 у $3. У кешу {{PLURAL:$4|1=је доступан највише један резултат|су доступна највише $4 резултата|је доступно највише $4 резултата}}.",
"querypage-no-updates": "Ажурирање ове странице је тренутно онемогућено.\nПодаци који се овде налазе могу бити застарели.",
"viewsource": "Изворни код",
- "viewsource-title": "Ð\9fÑ\80иказ извоÑ\80а странице $1",
+ "viewsource-title": "Ð\98звоÑ\80ни Ñ\82екÑ\81Ñ\82 странице $1",
"actionthrottled": "Радња је успорена",
"actionthrottledtext": "У циљу борбе против непожељних порука, ограничене су вам измене у одређеном времену, а управо сте прешли то ограничење. Покушајте поново за неколико минута.",
"protectedpagetext": "Ова страница је закључана за измене и друге радње.",
"viewsourcetext": "Можете читати и копирати садржај ове странице.",
- "viewyourtext": "Можете да погледате и копирате извор <strong>ваших измена</strong> на овој страници.",
+ "viewyourtext": "Можете да погледате и копирате изворни текст <strong>ваших измена</strong> на овој страници.",
"protectedinterface": "Ова страница садржи текст корисничког окружења за софтвер на овом викију и заштићена је ради спречавања злоупотребе.\nДа бисте додали или изменили преводе свих викија, посетите [//translatewiki.net/ Транслејтвики], пројекат за локализацију Медијавикија.",
"editinginterface": "<strong>Упозорење:</strong> уређујете страницу која се користи за приказивање текста корисничког окружења.\nИзмене на овој страници ће утицати на све кориснике овог викија.",
"translateinterface": "Да додате или промените преводе за све викије, посетите [//translatewiki.net/ Транслејтвики], пројекат за локализацију Медијавикија.",
"noname": "Унели сте неисправно корисничко име.",
"loginsuccesstitle": "Успешно пријављивање",
"loginsuccess": "'''Пријављени сте као „$1“.'''",
- "nosuchuser": "Не постоји корисник с именом „$1“.\nКорисничка имена су осетљива на мала и велика слова.\nПроверите да ли сте га добро унели или [[Special:UserLogin/signup|отворите нови налог]].",
+ "nosuchuser": "Не постоји корисник с именом „$1“.\nКорисничка имена су осетљива на мала и велика слова.\nПроверите да ли сте га добро унели или [[Special:CreateAccount|отворите нови налог]].",
"nosuchusershort": "Корисник с именом „$1“ не постоји.\nПроверите да ли сте правилно написали.",
"nouserspecified": "Морате навести корисничко име.",
"login-userblocked": "{{GENDER:$1|Овај корисник је блокиран|Ова корисница је блокирана|Овај корисник је блокиран}}. Пријава није дозвољена.",
"accmailtext": "Лозинка за {{GENDER:$1|корисника|корисницу}} [[User talk:$1|$1]] је послата на $2. Након пријаве, лозинка се може променити [[Special:ChangePassword|овде]].",
"newarticle": "(нови)",
"newarticletext": "Дошли сте на страницу која још не постоји.\nДа бисте је направили, почните да куцате у прозор испод овог текста (погледајте [$1 страницу за помоћ]).\nАко сте овде дошли грешком, вратите се на претходну страницу.",
- "anontalkpagetext": "---- Ово је страница за разговор с анонимним корисником који још нема налог или га не користи.\nЗбог тога морамо да користимо бројчану ИП адресу како бисмо га препознали.\nТакву адресу може делити више корисника.\nАко сте анонимни корисник и мислите да су вам упућене примедбе, [[Special:UserLogin/signup|отворите налог]] или се [[Special:UserLogin|пријавите]] да бисте избегли будућу забуну с осталим анонимним корисницима.",
+ "anontalkpagetext": "----\n<em>Ово је страница за разговор с анонимним корисником који још нема налог или га не користи.</em>\nЗбог тога морамо да користимо бројчану ИП адресу како бисмо га препознали.\nТакву адресу може делити више корисника.\nАко сте анонимни корисник и мислите да су вам упућене примедбе, [[Special:CreateAccount|отворите налог]] или се [[Special:UserLogin|пријавите]] да бисте избегли будућу забуну с осталим анонимним корисницима.",
"noarticletext": "На овој страници тренутно нема садржаја.\nМожете [[Special:Search/{{PAGENAME}}|потражити овај наслов]] на другим страницама,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} претражити сродне извештаје] или [{{fullurl:{{FULLPAGENAME}}|action=edit}} направити ову страницу]</span>.",
"noarticletext-nopermission": "На овој страници тренутно нема садржаја.\nМожете [[Special:Search/{{PAGENAME}}|потражити овај наслов]] на другим страницама или <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} претражити сродне дневнике]</span>, али немате дозволу да направите ову страницу.",
"missing-revision": "Не могу да пронађем измену бр. $1 на страници под називом „{{FULLPAGENAME}}“.\n\nОво се обично дешава када пратите застарелу везу до странице која је обрисана.\nВише информација можете пронаћи у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневнику брисања].",
"right-override-export-depth": "извоз страница укључујући и повазене странице до дубине од пет веза",
"right-sendemail": "слање имејла другим корисницима",
"right-passwordreset": "прегледање порука за обнављање лозинке",
- "right-managechangetags": "прављење и/или брисање [[Special:Tags|ознака]] из базе података",
+ "right-managechangetags": "прављење и (де)активирање [[Special:Tags|ознака]]",
"right-applychangetags": "примењивање [[Special:Tags|ознака]] на нечије измене",
"right-changetags": "додавање и уклањање разних [[Special:Tags|ознака]] на појединачним изменама и уносима у дневницима",
"grant-group-page-interaction": "Уређивање страница",
"action-viewmyprivateinfo": "прегледање ваших личних података",
"action-editmyprivateinfo": "уређивање ваших личних података",
"action-editcontentmodel": "мењање модела садржаја странице",
- "action-managechangetags": "прављење и/или брисање ознака из базе података",
+ "action-managechangetags": "прављење и (де)активирање ознака",
"action-applychangetags": "додавање ознака на ваше измене",
"action-changetags": "додавање и уклањање разних ознака на појединачним изменама и уносима у дневницима",
"nchanges": "$1 {{PLURAL:$1|измена|измене|измена}}",
"import-nonewrevisions": "Измене нису увезене (све су већ биле или присутне или прескочене због грешки).",
"xml-error-string": "$1 у реду $2, колона $3 (бајт $4): $5",
"import-upload": "Отпремање XML података",
- "import-token-mismatch": "Губитак података о сесији.\nПокушајте поново.",
+ "import-token-mismatch": "Губитак података о сесији.\n\nМожда сте одјављени.\n<strong>Молимо Вас проверите да ли сте још увек пријављени и покушајте поново<strong>.\n\nАко и даље не ради, покушајте се [[Special:UserLogout|одјавити]] и поново пријавити и проверите да ли Ваш веб-пртраживач дозвољава колачиће са овог сајта.",
"import-invalid-interwiki": "Не могу да увозим с наведеног викија.",
"import-error-edit": "Страница „$1“ није увезена јер вам није дозвољено да је уређујете.",
"import-error-create": "Страница „$1“ није увезена јер вам није дозвољено да је направите.",
"tooltip-ca-talk": "Разговор о страници са садржајем",
"tooltip-ca-edit": "Уреди ову страницу",
"tooltip-ca-addsection": "Започните нови одељак",
- "tooltip-ca-viewsource": "Ова страница је закључана. Можете да видите изворни код.",
+ "tooltip-ca-viewsource": "Ова страница је закључана. \nМожете погледати изворни текст.",
"tooltip-ca-history": "Претходне верзије ове странице",
"tooltip-ca-protect": "Заштитите ову страницу",
"tooltip-ca-unprotect": "Промени заштиту ове странице",
"variantname-gan": "gan",
"variantname-sr-ec": "Ћирилица",
"variantname-sr-el": "Latinica",
- "variantname-sr": "ћир/lat",
+ "variantname-sr": "Ћир./lat.",
"variantname-kk-kz": "kk-kz",
"variantname-kk-tr": "kk-tr",
"variantname-kk-cn": "kk-cn",
"size-megabytes": "$1 MB",
"size-gigabytes": "$1 GB",
"lag-warn-normal": "Измене новије од $1 {{PLURAL:$1|секунде|секунде|секунди}} неће бити приказане.",
- "lag-warn-high": "Због преоптерећења базе података, измене новије од $1 {{PLURAL:$1|секунда|секунде}} неће бити приказане.",
+ "lag-warn-high": "Због преоптерећења базе података, измене новије од $1 {{PLURAL:$1|1=секунде|секунде|секунди}} неће бити приказане.",
"watchlistedit-normal-title": "Уређивање списка надгледања",
"watchlistedit-normal-legend": "Уклањање наслова са списка надгледања",
"watchlistedit-normal-explain": "Наслови на вашем списку надгледања су приказани испод.\nДа бисте уклонили наслов, означите квадратић до њега и кликните на „{{int:Watchlistedit-normal-submit}}“.\nМожете и да [[Special:EditWatchlist/raw|уредите сиров списак]].",
"Srdjan m",
"Macofe",
"Сербијана",
- "Xð"
+ "Xð",
+ "Matma Rex"
]
},
"tog-underline": "Podvlačenje veza:",
"perfcachedts": "Sledeći podaci su keširani i poslednji put su ažurirani $2 u $3. U kešu {{PLURAL:$4|1=je dostupan najviše jedan rezultat|su dostupna najviše $4 rezultata|je dostupno najviše $4 rezultata}}.",
"querypage-no-updates": "Ažuriranje ove stranice je trenutno onemogućeno.\nPodaci koji se ovde nalaze mogu biti zastareli.",
"viewsource": "Izvorni kod",
- "viewsource-title": "Prikaz izvora stranice $1",
+ "viewsource-title": "Izvorni tekst stranice $1",
"actionthrottled": "Radnja je usporena",
"actionthrottledtext": "U cilju borbe protiv nepoželjnih poruka, ograničene su vam izmene u određenom vremenu, a upravo ste prešli to ograničenje. Pokušajte ponovo za nekoliko minuta.",
"protectedpagetext": "Ova stranica je zaključana za izmene i druge radnje.",
- "viewsourcetext": "Možete čitati i kopirati sadržaj ove stranice:",
- "viewyourtext": "Možete da pogledate i umnožite izvor '''vaših izmena''' na ovoj stranici:",
+ "viewsourcetext": "Možete čitati i kopirati sadržaj ove stranice.",
+ "viewyourtext": "Možete da pogledate i kopirate izvorni tekst <strong>vaših izmena</strong> na ovoj stranici.",
"protectedinterface": "Ova stranica sadrži tekst korisničkog okruženja za softver na ovom vikiju i zaštićena je radi sprečavanja zloupotrebe.\nDa biste dodali ili izmenili prevode svih vikija, posetite [//translatewiki.net/ Translejtviki], projekat za lokalizaciju Medijavikija.",
"editinginterface": "<strong>Upozorenje:</strong> uređujete stranicu koja se koristi za prikazivanje teksta korisničkog okruženja.\nIzmene na ovoj stranici će uticati na sve korisnike ovog vikija.",
"translateinterface": "Da dodate ili promenite prevode za sve vikije, posetite [//translatewiki.net/ Translejtviki], projekat za lokalizaciju Medijavikija.",
"noname": "Uneli ste neispravno korisničko ime.",
"loginsuccesstitle": "Uspešno prijavljivanje",
"loginsuccess": "'''Prijavljeni ste kao „$1“.'''",
- "nosuchuser": "Ne postoji korisnik s imenom „$1“.\nKorisnička imena su osetljiva na mala i velika slova.\nProverite da li ste ga dobro uneli ili [[Special:UserLogin/signup|otvorite novi nalog]].",
+ "nosuchuser": "Ne postoji korisnik s imenom „$1“.\nKorisnička imena su osetljiva na mala i velika slova.\nProverite da li ste ga dobro uneli ili [[Special:CreateAccount|otvorite novi nalog]].",
"nosuchusershort": "Korisnik s imenom „$1“ ne postoji.\nProverite da li ste pravilno napisali.",
"nouserspecified": "Morate navesti korisničko ime.",
"login-userblocked": "{{GENDER:$1|Ovaj korisnik je blokiran|Ova korisnica je blokirana|Ovaj korisnik je blokiran}}. Prijava nije dozvoljena.",
"accmailtext": "Lozika za {{GENDER:$1|korisnika|korisnicu}} [[User talk:$1|$1]] je poslata na $2. Nakon prijave, lozinka se može promeniti [[Special:ChangePassword|ovde]].",
"newarticle": "(novi)",
"newarticletext": "Došli ste na stranicu koja još ne postoji.\nDa biste je napravili, počnite da kucate u prozor ispod ovog teksta (pogledajte [$1 stranicu za pomoć]).\nAko ste ovde došli greškom, vratite se na prethodnu stranicu.",
- "anontalkpagetext": "---- Ovo je stranica za razgovor s anonimnim korisnikom koji još nema nalog ili ga ne koristi.\nZbog toga moramo da koristimo brojčanu IP adresu kako bismo ga prepoznali.\nTakvu adresu može deliti više korisnika.\nAko ste anonimni korisnik i mislite da su vam upućene primedbe, [[Special:UserLogin/signup|otvorite nalog]] ili se [[Special:UserLogin|prijavite]] da biste izbegli buduću zabunu s ostalim anonimnim korisnicima.",
+ "anontalkpagetext": "---- Ovo je stranica za razgovor s anonimnim korisnikom koji još nema nalog ili ga ne koristi.\nZbog toga moramo da koristimo brojčanu IP adresu kako bismo ga prepoznali.\nTakvu adresu može deliti više korisnika.\nAko ste anonimni korisnik i mislite da su vam upućene primedbe, [[Special:CreateAccount|otvorite nalog]] ili se [[Special:UserLogin|prijavite]] da biste izbegli buduću zabunu s ostalim anonimnim korisnicima.",
"noarticletext": "Na ovoj stranici trenutno nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|potražiti ovaj naslov]] na drugim stranicama,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti srodne izveštaje] ili [{{fullurl:{{FULLPAGENAME}}|action=edit}} napraviti ovu stranicu]</span>.",
"noarticletext-nopermission": "Na ovoj stranici trenutno nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|potražiti ovaj naslov]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti srodne dnevnike]</span>, ali nemate dozvolu da napravite ovu stranicu.",
"missing-revision": "Ne mogu da pronađem izmenu br. $1 na stranici pod nazivom „{{FULLPAGENAME}}“.\n\nOvo se obično dešava kada pratite zastarelu vezu do stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} dnevniku brisanja].",
"right-override-export-depth": "izvoz stranica uključujući i povazene stranice do dubine od pet veza",
"right-sendemail": "slanje e-poruka drugim korisnicima",
"right-passwordreset": "pregledanje poruka za obnavljanje lozinke",
- "right-managechangetags": "pravljenje i/ili brisanje [[Special:Tags|oznaka]] iz baze podataka",
+ "right-managechangetags": "pravljenje i (de)aktiviranje [[Special:Tags|oznaka]]",
"grant-group-page-interaction": "Uređivanje stranica",
"grant-group-file-interaction": "Uređivanje datoteka",
"grant-group-watchlist-interaction": "Uređivanje vašeg spiska nadgledanja",
"tooltip-ca-talk": "Razgovor o stranici sa sadržajem",
"tooltip-ca-edit": "Uredi ovu stranicu",
"tooltip-ca-addsection": "Započnite novi odeljak",
- "tooltip-ca-viewsource": "Ova stranica je zaključana. Možete da vidite izvorni kod.",
+ "tooltip-ca-viewsource": "Ова страница је закључана. \nМожете погледати изворни текст.",
"tooltip-ca-history": "Prethodne verzije ove stranice",
"tooltip-ca-protect": "Zaštitite ovu stranicu",
"tooltip-ca-unprotect": "Promeni zaštitu ove stranice",
"variantname-gan": "gan",
"variantname-sr-ec": "Ćirilica",
"variantname-sr-el": "Latinica",
- "variantname-sr": "ћир/lat",
+ "variantname-sr": "Ћир./lat.",
"variantname-kk-kz": "kk-kz",
"variantname-kk-tr": "kk-tr",
"variantname-kk-cn": "kk-cn",
"size-megabytes": "$1 MB",
"size-gigabytes": "$1 GB",
"lag-warn-normal": "Izmene novije od $1 {{PLURAL:$1|sekunde|sekunde|sekundi}} neće biti prikazane.",
- "lag-warn-high": "Zbog preopterećenja baze podataka, izmene novije od $1 {{PLURAL:$1|sekunde|sekundi}} neće biti prikazane.",
+ "lag-warn-high": "Zbog preopterećenja baze podataka, izmene novije od $1 {{PLURAL:$1|1=sekunde|sekunde|sekundi}} neće biti prikazane.",
"watchlistedit-normal-title": "Uređivanje spiska nadgledanja",
"watchlistedit-normal-legend": "Uklanjanje naslova sa spiska nadgledanja",
"watchlistedit-normal-explain": "Naslovi na vašem spisku nadgledanja su prikazani ispod.\nDa biste uklonili naslov, označite kvadratić do njega i kliknite na „{{int:Watchlistedit-normal-submit}}“.\nMožete i da [[Special:EditWatchlist/raw|uredite sirov spisak]].",
"noname": "Du moast n Benutsernoome anreeke.",
"loginsuccesstitle": "Anmäldenge mäd Ärfoulch",
"loginsuccess": "'''Du bäst nu as \"$1\" bie {{SITENAME}} anmälded.'''",
- "nosuchuser": "Die Benutsernoome \"$1\" bestoant nit.\nUurpröif ju Skrieuwwiese (Groot-/Littekskrieuwenge beoachtje) of [[Special:UserLogin/signup|mäld die as näien Benutser an]].",
+ "nosuchuser": "Die Benutsernoome \"$1\" bestoant nit.\nUurpröif ju Skrieuwwiese (Groot-/Littekskrieuwenge beoachtje) of [[Special:CreateAccount|mäld die as näien Benutser an]].",
"nosuchusershort": "Die Benutsernooome \"$1\" bestoant nit. Uurpröif ju Skrieuwwiese.",
"nouserspecified": "Reek jädden n Benutsernoome an.",
"login-userblocked": "Dissen Benutser is speerd. Anmäldenge nit ferlööwed.",
"accmailtext": "N toufällich generierd Paaswoud foar [[User talk:$1|$1]] wuud an $2 fersoand.\n\nDät Paaswoud foar dit näie Benutserkonto kon ap ju Spezioalsiede\n„[[Special:ChangePassword|Paaswoud annerje]]“ annerd wäide.",
"newarticle": "(Näi)",
"newarticletext": "Du hääst n Link foulged ätter ne Siede, ju dät noch nit rakt.\nUum ju Siede tou moakjen, dien Text fon dän näie Artikkel iendreege in ju unnerstoundene Box (sjuch ju [$1 Hälpesiede] foar moor Informatione).\nBäst du hier bie Fersjoon, klik ju '''Tourääch'''-Skaltfläche fon din Browser.",
- "anontalkpagetext": "----''Dit is ju Diskussionssiede fon n uunbekoanden Benutser, die sik nit anmälded häd.\nWail naan Noome deer is, wäd ju nuumeriske IP-Adrässe tou Identifizierenge ferwoand.\nMan oafte wäd sunne Adrässe fon moorere Benutsere ferwoand.\nWan du n uunbekoanden Benutser bääst un du toankst dät du Kommentare krichst do nit foar die meend sunt, dan koast du ap bääste n [[Special:UserLogin/signup|Benutserkonto iengjuchte]] of die [[Special:UserLogin|anmäldje]], uum sukke Fertuusengen mäd uur anomyme Benutsere tou fermieden.''",
+ "anontalkpagetext": "----''Dit is ju Diskussionssiede fon n uunbekoanden Benutser, die sik nit anmälded häd.\nWail naan Noome deer is, wäd ju nuumeriske IP-Adrässe tou Identifizierenge ferwoand.\nMan oafte wäd sunne Adrässe fon moorere Benutsere ferwoand.\nWan du n uunbekoanden Benutser bääst un du toankst dät du Kommentare krichst do nit foar die meend sunt, dan koast du ap bääste n [[Special:CreateAccount|Benutserkonto iengjuchte]] of die [[Special:UserLogin|anmäldje]], uum sukke Fertuusengen mäd uur anomyme Benutsere tou fermieden.''",
"noarticletext": "Deer is apstuuns naan Text ap disse Siede.\nDu koast dissen Tittel ap do uur Sieden [[Special:Search/{{PAGENAME}}|säike]],\n<span class=\"plainlinks\"> in do touheerige [{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Logbouke säike] of disse Siede [{{fullurl:{{FULLPAGENAME}}|action=edit}} beoarbaidje]</span>.",
"noarticletext-nopermission": "Der is apstuuns noch naan Text ap disse Siede.\nDu koast dissen Tittel ap do uur Sieden [[Special:Search/{{PAGENAME}}|säike]]\nof <span class=\"plainlinks\">in do touheerige [{{fullurl:{{#special:Log}}|page={{FULLPAGENAMEE}}}} Logbouke säike].</span>",
"userpage-userdoesnotexist": "Dät Benutserkonto „<nowiki>$1</nowiki>“ is nit deer. Pröif, of du disse Siede wuddelk moakje/beoarbaidje wolt.",
"noname": "Anjeun teu nuliskeun ngaran pamaké nu sah.",
"loginsuccesstitle": "Asup log geus hasil",
"loginsuccess": "Anjeun ayeuna geus asup log ka {{SITENAME}} salaku \"$1\".",
- "nosuchuser": "Euweuh pamaké nu ngaranna \"$1\".\nNgaran pamaké ngabedakeun hurup kapital.\nPariksa éjahanana, atawa paké formulir di handap pikeun [[Special:UserLogin/signup|nyieun rekening anyar]].",
+ "nosuchuser": "Euweuh pamaké nu ngaranna \"$1\".\nNgaran pamaké ngabedakeun hurup kapital.\nPariksa éjahanana, atawa paké formulir di handap pikeun [[Special:CreateAccount|nyieun rekening anyar]].",
"nosuchusershort": "Taya pamaké nu ngaranna \"$1\", pariksa éjahanana!",
"nouserspecified": "Anjeun kudu ngeusian ngaran landihan.",
"login-userblocked": "Ieu pamaké keur dipeungpeuk, teu diwenangkeun asup log.",
"accmailtext": "Sandi acak pikeun [[User talk:$1|$1]] geus dikirim ka $2. Éta sandi bisa diganti dina kaca ''[[Special:ChangePassword|ganti sandi]]'' sanggeus asup log.",
"newarticle": "(anyar)",
"newarticletext": "Anjeun geus nuturkeun tutumbu ka kaca nu can aya.\nPikeun nyieun kaca, mimitian ku ngetik jeroeun kotak di handap\n(tempo [$1 kaca pitulung] pikeun leuwih écés).\nMun anjeun ka dieu teu ngahaja, klik baé tombol '''back''' na panyungsi anjeun.",
- "anontalkpagetext": "----\n<em>Ieu mangrupa kaca sawala pikeun pamaké anonim anu can nyieun akun, atawa anu henteu maké.</em>\nKu kituna kapaksa make alamat IP pikeun nyirikeun anjeunna. Alamat IP ieu bisa dipaké ku sababaraha jalma. Lamun anjeun salasahiji pamaké anonim sarta ngarasa aya koméntar nu teu pakait geus ditujukeun ka anjeun, mangga [[Special:UserLogin/signup|nyieun akun]] atawa [[Special:UserLogin|asup log]] sangkan teu pacorok jeung pamaké anonim lianna.",
+ "anontalkpagetext": "----\n<em>Ieu mangrupa kaca sawala pikeun pamaké anonim anu can nyieun akun, atawa anu henteu maké.</em>\nKu kituna kapaksa make alamat IP pikeun nyirikeun anjeunna. Alamat IP ieu bisa dipaké ku sababaraha jalma. Lamun anjeun salasahiji pamaké anonim sarta ngarasa aya koméntar nu teu pakait geus ditujukeun ka anjeun, mangga [[Special:CreateAccount|nyieun akun]] atawa [[Special:UserLogin|asup log]] sangkan teu pacorok jeung pamaké anonim lianna.",
"noarticletext": "Kiwari can aya téks dina ieu kaca.\nAnjeun bisa [[Special:Search/{{PAGENAME}}|nyusud judul ieu kaca]] dina kaca séjén,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} nyusud log nu tumali],\natawa [{{fullurl:{{FULLPAGENAME}}|action=edit}} nyieun ieu kaca]</span>.",
"noarticletext-nopermission": "Kiwari can aya téks dina ieu kaca.\nAnjeun bisa [[Special:Search/{{PAGENAME}}|nyusud judul ieu kaca]] dina kaca séjén,atawa <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} nyusud log nu tumali]</span>, tapi teu wenang pikeun nyieun ieu kaca.",
"missing-revision": "Révisi #$1 kaca \"{{FULLPAGENAME}}\" teu aya.\n\nKajadian ieu biasana kusabab nuturkeun tutumbu jujutan kaca anu geus dihapus.\nWincikanana bisa ditempo di [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log hapusan].",
"Josve05a",
"Pipetricker",
"Dammråtta",
- "Mgr"
+ "Mgr",
+ "Matma Rex",
+ "McDutchie"
]
},
"tog-underline": "Stryk under länkar:",
"password-change-forbidden": "Du kan inte ändra lösenord på denna wiki.",
"externaldberror": "Antingen inträffade autentiseringsproblem med en extern databas, eller så får du inte uppdatera ditt externa konto.",
"login": "Logga in",
+ "login-security": "Verifiera din identitet",
"nav-login-createaccount": "Logga in / skapa konto",
"userlogin": "Logga in / skapa konto",
"userloginnocreate": "Logga in",
"userlogin-resetpassword-link": "Glömt ditt lösenord?",
"userlogin-helplink2": "Hjälp med inloggning",
"userlogin-loggedin": "Du är redan inloggad som {{GENDER:$1|$1}}.\nAnvänd formuläret nedan för att logga in som en annan användare.",
+ "userlogin-reauth": "Du måste logga in igen för att verifiera att du är {{GENDER:$1|$1}}.",
"userlogin-createanother": "Skapa ett annat konto",
"createacct-emailrequired": "E-postadress",
"createacct-emailoptional": "E-postadress (valfritt)",
"createacct-email-ph": "Bekräfta din e-postadress",
"createacct-another-email-ph": "Skriv in e-postadress",
"createaccountmail": "Använd ett tillfälligt slumpvis valt lösenord och skicka det till den angivna e-postadressen",
+ "createaccountmail-help": "Kan användas för att skapa ett konto åt en annan person utan att kunna lösenordet.",
"createacct-realname": "Riktigt namn (valfritt)",
"createaccountreason": "Orsak:",
"createacct-reason": "Orsak",
"createacct-reason-ph": "Varför du skapar ett annat konto",
+ "createacct-reason-help": "Meddelande som visas i loggen för skapade konton",
"createacct-submit": "Skapa ditt konto",
"createacct-another-submit": "Skapa konto",
+ "createacct-continue-submit": "Fortsätt att skapa konto",
+ "createacct-another-continue-submit": "Fortsätt att skapa konto",
"createacct-benefit-heading": "{{SITENAME}} är skapad av människor som dig.",
"createacct-benefit-body1": "{{PLURAL:$1|redigering|redigeringar}}",
"createacct-benefit-body2": "{{PLURAL:$1|sida|sidor}}",
"nocookiesnew": "Användarkontot skapades, men du är inte inloggad.\n{{SITENAME}} använder kakor för att logga in användare.\nDu har kakor inaktiverade.\nAktivera dem, och logga sedan in med ditt nya användarnamn och lösenord.",
"nocookieslogin": "{{SITENAME}} använder kakor för att logga in användare. Du har stängt av kakor i din webbläsare. Försök igen med stöd för kakor aktiverat.",
"nocookiesfornew": "Användarkontot skapades inte, eftersom vi inte kunde bekräfta dess källa.\nSe till att du har aktiverat kakor, ladda om denna sida och försök igen.",
+ "createacct-loginerror": "Kontot skapades men du kunde inte loggas in automatiskt. Var god [[Special:UserLogin|logga in manuellt]].",
"noname": "Du har angett ett ogiltigt användarnamn.",
"loginsuccesstitle": "Inloggad",
"loginsuccess": "'''Du är nu inloggad på {{SITENAME}} som \"$1\".'''",
- "nosuchuser": "Det finns ingen användare med namnet \"$1\".\nAnvändarnamn är skiftlägeskänsliga.\nKontrollera din stavning, eller [[Special:UserLogin/signup|skapa ett nytt konto]].",
+ "nosuchuser": "Det finns ingen användare med namnet \"$1\".\nAnvändarnamn är skiftlägeskänsliga.\nKontrollera din stavning, eller [[Special:CreateAccount|skapa ett nytt konto]].",
"nosuchusershort": "Det finns ingen användare som heter \"$1\". Kontrollera att du stavat rätt.",
"nouserspecified": "Du måste ange ett användarnamn.",
"login-userblocked": "Denna användare är blockerad. Inloggning är inte tillåtet.",
"createacct-another-realname-tip": "Riktigt namn behöver inte anges.\nOm du väljer att ange det, kommer det att användas för att tillskriva dig ditt arbete.",
"pt-login": "Logga in",
"pt-login-button": "Logga in",
+ "pt-login-continue-button": "Fortsätt att logga in",
"pt-createaccount": "Skapa konto",
"pt-userlogout": "Logga ut",
"php-mail-error-unknown": "Okänt fel i PHP:s mail()-funktion",
"botpasswords-invalid-name": "Det angivna användarnamnet innehåller inte separatorn för botlösenord (\"$1\").",
"botpasswords-not-exist": "Användaren \"$1\" har inte ett botlösenord som är \"$2\".",
"resetpass_forbidden": "Lösenord kan inte ändras",
+ "resetpass_forbidden-reason": "Lösenorden kan inte ändras: $1",
"resetpass-no-info": "Du måste vara inloggad för att komma åt den här sidan direkt.",
"resetpass-submit-loggedin": "Ändra lösenord",
"resetpass-submit-cancel": "Avbryt",
"passwordreset-emailsentusername": "Om det finns en e-postadress som associeras med detta användarnamn kommer en lösenordsåterställning skickas via e-post.",
"passwordreset-emailsent-capture": "En lösenordsåterställning via e-post har skickats, som visas nedan.",
"passwordreset-emailerror-capture": "En lösenordsåterställning via e-post har skapats, som visas nedan, men det gick inte att skicka den till {{GENDER:$2|användaren}}: $1",
+ "passwordreset-emailsent-capture2": "{{PLURAL:$1|E-postmeddelande|E-postmeddelanden}} för återställning av lösenord har skickats. {{PLURAL:$1|Användarnamnet och lösenordet|Listan över användarnamn och lösenord}} visas nedan.",
+ "passwordreset-emailerror-capture2": "Kunde inte skicka e-post till {{GENDER:$2|användaren}}: $1 {{PLURAL:$3|Användarnamnet och lösenordet|Listan över användarnamn och lösenord}} listas nedan.",
+ "passwordreset-nocaller": "En användare måste anges",
+ "passwordreset-nosuchcaller": "Användare finns inte: $1",
+ "passwordreset-ignored": "Lösenordsåterställningen hanterades inte. Kanske ingen leverantör har konfigurerats?",
+ "passwordreset-invalideamil": "Ogiltig e-postadress",
+ "passwordreset-nodata": "Varken ett användarnamn eller en e-postadress angavs",
"changeemail": "Ändra eller ta bort e-postadress",
"changeemail-header": "Fyll i detta formulär för att ändra din e-postadress. Lämna fältet för ny e-postadress tomt när du skickar in formuläret om du vill ta bort en associerad e-postadress från ditt konto.",
"changeemail-passwordrequired": "Du måste ange ditt lösenord för att bekräfta denna ändring.",
"accmailtext": "Ett slumpgenererat lösenord för [[User talk:$1|$1]] har skickats till $2. Det kan ändras på sidan ''[[Special:ChangePassword|ändra lösenord]]'' när du loggar in.",
"newarticle": "(Ny)",
"newarticletext": "Du har klickat på en länk till en sida som inte finns ännu. För att skapa sidan, börja att skriva i fältet nedan (du kan läsa mer på [$1 hjälpsidan]). Om du kom hit av misstag kan du bara trycka på <strong>tillbaka</strong>-knappen i din webbläsare.",
- "anontalkpagetext": "----''Detta är diskussionssidan för en anonym användare som inte ännu skapat ett konto, eller som inte använder det.\nDärför måste vi använda den numeriska IP-adressen för att identifiera honom/henne.\nEn sådan IP-adress kan delas av flera användare.\nOm du är en anonym användare och känner att irrelevanta kommentarer har riktats mot dig, vänligen [[Special:UserLogin/signup|skapa ett konto]] eller [[Special:UserLogin|logga in]] för att undvika framtida förväxlingar med andra anonyma användare.''",
+ "anontalkpagetext": "----<em>Detta är diskussionssidan för en anonym användare som inte ännu skapat ett konto, eller som inte använder det.</em>\nDärför måste vi använda den numeriska IP-adressen för att identifiera honom/henne.\nEn sådan IP-adress kan delas av flera användare.\nOm du är en anonym användare och känner att irrelevanta kommentarer har riktats mot dig, vänligen [[Special:CreateAccount|skapa ett konto]] eller [[Special:UserLogin|logga in]] för att undvika framtida förväxlingar med andra anonyma användare.",
"noarticletext": "Det finns just nu ingen text på denna sida.\nDu kan [[Special:Search/{{PAGENAME}}|söka efter denna sidtitel]] på andra sidor, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} söka i relaterade loggar], eller [{{fullurl:{{FULLPAGENAME}}|action=edit}} skapa denna sida]</span>.",
"noarticletext-nopermission": "Det finns för tillfället ingen text på denna sida.\nDu kan [[Special:Search/{{PAGENAME}}|söka efter denna sidas titel]] på andra sidor,\neller <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} söka i relaterade loggar]</span> men du har inte behörighet att skapa sidan.",
"missing-revision": "Revisionen #$1 av sidan med namnet \"{{FULLPAGENAME}}\" finns inte.\n\nDetta orsakas vanligen av efter en gammal historiklänk till en sida som har raderats.\nDetaljer kan hittas i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} raderingsloggen].",
"history-feed-description": "Versionshistorik för denna sida på wikin",
"history-feed-item-nocomment": "$1 den $2",
"history-feed-empty": "Den begärda sidan finns inte.\nDen kan ha tagits bort från wikin eller bytt namn.\nProva att [[Special:Search|söka på wikin]] för relevanta nya sidor.",
- "history-edit-tags": "Redigera taggar för valda sidversioner",
+ "history-edit-tags": "Redigera märken för valda sidversioner",
"rev-deleted-comment": "(redigeringssammanfattning togs bort)",
"rev-deleted-user": "(användarnamn borttaget)",
"rev-deleted-event": "(loggdetaljer borttagna)",
"right-override-export-depth": "Exportera sidor inklusive länkade sidor till ett djup på 5",
"right-sendemail": "Skicka e-post till andra användare",
"right-passwordreset": "Visa e-postmeddelanden med lösenordsåterställning",
- "right-managechangetags": "Skapa och radera [[Special:Tags|taggar]] från databasen",
- "right-applychangetags": "Tillämpa [[Special:Tags|taggar]] tillsammans med ens ändringar",
+ "right-managechangetags": "Skapa och (in)aktivera [[Special:Tags|märken]]",
+ "right-applychangetags": "Tillämpa [[Special:Tags|märken]] tillsammans med ens ändringar",
"right-changetags": "Lägg till och ta bort godtyckliga [[Special:Tags|märken]] på individuella sidversioner och loggposter.",
+ "right-deletechangetags": "Radera [[Special:Tags|märken]] från databasen",
"grant-generic": "Rättighetsgrupp \"$1\"",
"grant-group-page-interaction": "Interagera med sidor",
"grant-group-file-interaction": "Interagera med media",
"action-viewmyprivateinfo": "visa din privata information",
"action-editmyprivateinfo": "redigera din privata information",
"action-editcontentmodel": "ändra innehållsmodellen för en sida",
- "action-managechangetags": "skapa och radera taggar från databasen",
- "action-applychangetags": "tillämpa taggar tillsammans med dina ändringar",
+ "action-managechangetags": "skapa och (in)aktivera märken",
+ "action-applychangetags": "tillämpa märken tillsammans med dina ändringar",
"action-changetags": "lägg till och ta bort godtyckliga märken på individuella sidversioner och loggposter",
+ "action-deletechangetags": "radera märken från databasen",
"nchanges": "$1 {{PLURAL:$1|ändring|ändringar}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sedan senaste besöket}}",
"enhancedrc-history": "historik",
"upload-form-label-own-work": "Detta är mitt eget verk",
"upload-form-label-infoform-categories": "Kategorier",
"upload-form-label-infoform-date": "Datum",
- "upload-form-label-own-work-message-local": "Jag bekräftar att jag laddar upp denna fil enligt {{SITENAME}}s användarvillkor och licenspolicys.",
- "upload-form-label-not-own-work-message-local": "Stäng denna dialogruta och prova ett annat sätt om du inte kan ladda upp denna fil under {{SITENAME}}s policys.",
- "upload-form-label-not-own-work-local-local": "Du kanske också skulle vilja prova [[Special:Upload|standarduppladdningssidan]].",
- "upload-form-label-own-work-message-default": "Jag förstår att jag laddar upp denna fil till ett delat centralförvar. Jag bekräftar att jag gör det enligt de användarvillkor och licenspolicys som finns där.",
- "upload-form-label-not-own-work-message-default": "Stäng denna dialogruta och prova en annan metod om du inte kan ladda upp denna fil under de policys som gäller för det delade centralförvaret.",
- "upload-form-label-not-own-work-local-default": "Du kanske också skulle vilja prova att använda [[Special:Upload|uppladdningssidan på {{SITENAME}}]] om denna fil kan laddas upp där under deras policys.",
- "upload-form-label-own-work-message-shared": "Jag intygar att jag äger upphovsrätten för denna fil och samtycker till att oåterkalleligen släppa filen på Wikimedia Commons under licensen \n[https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] och jag accepterar [https://wikimediafoundation.org/wiki/Terms_of_Use villkoren för användning].",
- "upload-form-label-not-own-work-message-shared": "Om du inte äger upphovsrätten för denna fil eller om du önskar att släppa den under en annan licens bör du överväga att använda [https://commons.wikimedia.org/wiki/Special:UploadWizard uppladdningsguiden på Commons].",
- "upload-form-label-not-own-work-local-shared": "Du kanske skulle vilja prova att använda [[Special:Upload|uppladdningssidan på {{SITENAME}}]] om webbplatsens policys tillåter att denna fil laddas upp.",
+ "upload-form-label-own-work-message-generic-local": "Jag bekräftar att jag laddar upp denna fil enligt {{SITENAME}}s användarvillkor och licenspolicys.",
+ "upload-form-label-not-own-work-message-generic-local": "Stäng denna dialogruta och prova ett annat sätt om du inte kan ladda upp denna fil under {{SITENAME}}s policys.",
+ "upload-form-label-not-own-work-local-generic-local": "Du kanske också skulle vilja prova [[Special:Upload|standarduppladdningssidan]].",
+ "upload-form-label-own-work-message-generic-foreign": "Jag förstår att jag laddar upp denna fil till ett delat centralförvar. Jag bekräftar att jag gör det enligt de användarvillkor och licenspolicys som finns där.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Stäng denna dialogruta och prova en annan metod om du inte kan ladda upp denna fil under de policys som gäller för det delade centralförvaret.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Du kanske också skulle vilja prova att använda [[Special:Upload|uppladdningssidan på {{SITENAME}}]] om denna fil kan laddas upp där under deras policys.",
"backend-fail-stream": "Kunde inte strömma filen $1.",
"backend-fail-backup": "Kunde inte säkerhetskopiera filen ''$1''.",
"backend-fail-notexists": "Filen $1 finns inte.",
"logempty": "Inga matchande träffar i loggen.",
"log-title-wildcard": "Sök efter sidtitlar som börjar med texten",
"showhideselectedlogentries": "Visa/Dölj markerade loggposter",
- "log-edit-tags": "Redigera taggar i valda loggposter",
+ "log-edit-tags": "Redigera märken i valda loggposter",
"checkbox-select": "Välj: $1",
"checkbox-all": "Alla",
"checkbox-none": "Ingen",
"trackingcategories-msg": "Spårningskategori",
"trackingcategories-name": "Meddelandenamn",
"trackingcategories-desc": "Inklusionskriterier för kategori",
+ "restricted-displaytitle-ignored": "Sidor med ignorerade visningstitlar",
+ "restricted-displaytitle-ignored-desc": "Sidan har ignorerat <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> eftersom den inte överensstämmer med sidans riktiga titel.",
"noindex-category-desc": "Sidan innehåller det magiska ordet <code><nowiki>__NOINDEX__</nowiki></code> (och är i en namnrymd där denna flagga tillåts), och indexeras därför inte av robotar.",
"index-category-desc": "Denna sidan innehåller ett <code><nowiki>__INDEX__</nowiki></code> (och är i en namnrymd där denna flagga tillåts), och indexeras därför av robotar även där detta normalt inte skulle ske.",
"post-expand-template-inclusion-category-desc": "Sidan är större än <code>$wgMaxArticleSize</code> efter att alla mallar har expanderats, därför har vissa mallar inte expanderats.",
"rollbacklinkcount": "rulla tillbaka $1 {{PLURAL:$1|redigering|redigeringar}}",
"rollbacklinkcount-morethan": "rulla tillbaka mer än $1 {{PLURAL:$1|redigering|redigeringar}}",
"rollbackfailed": "Tillbakarullning misslyckades",
+ "rollback-missingparam": "Nödvändiga parametrar i begäran saknas.",
"cantrollback": "Det gick inte att rulla tillbaka, då sidan endast redigerats av en användare.",
"alreadyrolled": "Det gick inte att rulla tillbaka den senaste redigeringen av [[User:$2|$2]] ([[User talk:$2|diskussion]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) på sidan [[:$1|$1]]. Någon annan har redan rullat tillbaka eller redigerat sidan.\n\nSidan ändrades senast av [[User:$3|$3]] ([[User talk:$3|diskussion]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]).",
"editcomment": "Redigeringskommentaren var: <em>$1</em>.",
"revertpage": "Återställde redigeringar av [[Special:Contributions/$2|$2]] ([[User talk:$2|användardiskussion]]) till senaste versionen av [[User:$1|$1]]",
"revertpage-nouser": "Återställde redigeringar av en dold användare till den senaste versionen av {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Återställde ändringar av $1;\nändrade tillbaka till senaste version av $2.",
+ "rollback-success-notify": "Återställde ändringar av $1;\nändrade tillbaka till senaste version av $2. [$3 Visa ändringar]",
"sessionfailure-title": "Sessionsfel",
"sessionfailure": "Något med din session som inloggad är på tok. Din begärda åtgärd har avbrutits, för att förhindra att någon kapar din session. Klicka på \"Tillbaka\" i din webbläsare och ladda om den sida du kom ifrån. Försök sedan igen.",
"changecontentmodel": "Ändra innehållsmodell för en sida",
"changecontentmodel-success-text": "Innehållstypen för [[:$1]] har ändrats.",
"changecontentmodel-cannot-convert": "Innehållet på [[:$1]] kan inte konverteras till typen $2.",
"changecontentmodel-nodirectediting": "Innehållsmodellen $1 stöder inte direkt redigering",
+ "changecontentmodel-emptymodels-title": "Inget innehållsmodeller finns tillgängliga",
+ "changecontentmodel-emptymodels-text": "Innehållet på [[:$1]] kan inte konverteras till någon typ.",
"log-name-contentmodel": "Ändringslogg för innehållsmodellen",
"log-description-contentmodel": "Händelser som är relaterade till en sidas innehållsmodeller",
"logentry-contentmodel-new": "$1 {{GENDER:$2|skapade}} sidan $3 med den icke-standardiserade innehållsmodellen \"$5\"",
"lockdbsuccesstext": "Databasen är nu låst.\n<br />Kom ihåg att [[Special:UnlockDB|ta bort låsningen]] när du är färdig med ditt underhåll.",
"unlockdbsuccesstext": "Databasen är upplåst.",
"lockfilenotwritable": "Det går inte att skriva till databasens låsfil. För att låsa eller låsa upp databasen, så måste webbservern kunna skriva till den filen.",
+ "databaselocked": "Databasen är redan låst.",
"databasenotlocked": "Databasen är inte låst.",
"lockedbyandtime": "(av $1 den $2 kl. $3)",
"move-page": "Flytta $1",
"confirm-watch-top": "Lägg till denna sida till din bevakningslista?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Ta bort denna sida från din bevakningslista?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Återställ redigeringar på denna sida?",
"quotation-marks": "\"$1\"",
"imgmultipageprev": "← föregående sida",
"imgmultipagenext": "nästa sida →",
"autoredircomment": "Omdirigerar till [[$1]]",
"autosumm-new": "Skapade sidan med '$1'",
"autosumm-newblank": "Skapade tom sida",
- "size-bytes": "$1 byte",
+ "size-bytes": "$1 {{PLURAL:$1|byte}}",
"size-kilobytes": "$1 kbyte",
"size-megabytes": "$1 Mbyte",
"size-gigabytes": "$1 Gbyte",
+ "size-pixel": "$1 {{PLURAL:$1|bildpunkt|bildpunkter}}",
"lag-warn-normal": "Ändringar under {{PLURAL:$1|den senaste sekunden|de $1 senaste sekunderna}} kanske inte visas i den här listan.",
"lag-warn-high": "På grund av omfattande fördröjning i databasen visas kanske inte ändringar nyare än $1 {{PLURAL:$1|sekund|sekunder}} i den här listan.",
"watchlistedit-normal-title": "Redigera bevakningslista",
"timezone-local": "Lokal",
"duplicate-defaultsort": "'''Varning:''' Standardsorteringsnyckeln \"$2\" tar över från den tidigare standardsorteringsnyckeln \"$1\".",
"duplicate-displaytitle": "<strong>Varning:</strong> Visningstiteln \"$2\" skriver över den tidigare visningstiteln \"$1\".",
+ "restricted-displaytitle": "<strong>Varning:</strong> Visningstiteln \"$1\" ignorerades eftersom den inte motsvarar sidans riktiga titel.",
"invalid-indicator-name": "<p>Fel:</strong> Sidstatus-indikatorernas <code>namn</code>-attributet får inte vara tomt.",
"version": "Version",
"version-extensions": "Installerade programtillägg",
"tags-hitcount": "$1 {{PLURAL:$1|ändring|ändringar}}",
"tags-manage-no-permission": "Du har inte behörighet att hantera förändringstaggar.",
"tags-manage-blocked": "Du kan inte hantera ändringsmärken när du är blockerad.",
- "tags-create-heading": "Skapa en ny tag",
+ "tags-create-heading": "Skapa ett nytt märke",
"tags-create-explanation": "Som standard, kommer nyskapade taggar att bli tillgängliga för användning av användare och botar.",
- "tags-create-tag-name": "Taggnamn:",
+ "tags-create-tag-name": "Märkesnamn:",
"tags-create-reason": "Anledning:",
"tags-create-submit": "Skapa",
- "tags-create-no-name": "Du måste ange ett taggnamn.",
- "tags-create-invalid-chars": "Taggnamn får inte innehålla kommatecken (<code>,</code>) eller snedstreck (<code>/</code>).",
- "tags-create-invalid-title-chars": "Taggnamn får inte innehålla tecken som inte kan användas i sidtitlar.",
- "tags-create-already-exists": "Taggen \"$1\" finns redan.",
- "tags-create-warnings-above": "Följande {{PLURAL:$2|varning |varningar}} stöttes på när du försöker skapa etiketten \" $1 \":",
- "tags-create-warnings-below": "Vill du fortsätta att skapa taggen?",
- "tags-delete-title": "Radera tagg",
- "tags-delete-explanation-initial": "Du är på väg att ta bort taggen \"$1\" från databasen.",
+ "tags-create-no-name": "Du måste ange ett märkesnamn.",
+ "tags-create-invalid-chars": "Märkesnamn får inte innehålla kommatecken (<code>,</code>) eller snedstreck (<code>/</code>).",
+ "tags-create-invalid-title-chars": "Märkesnamn får inte innehålla tecken som inte kan användas i sidtitlar.",
+ "tags-create-already-exists": "Märket \"$1\" finns redan.",
+ "tags-create-warnings-above": "Följande {{PLURAL:$2|varning|varningar}} uppstod när du försökte skapa märket \"$1\":",
+ "tags-create-warnings-below": "Vill du fortsätta att skapa märket?",
+ "tags-delete-title": "Radera märke",
+ "tags-delete-explanation-initial": "Du är på väg att ta bort märket \"$1\" från databasen.",
"tags-delete-explanation-in-use": "Den kommer att tas bort från {{PLURAL:$2|$2 sidversioner eller loggposter|alla $2 sidversioner och/eller loggposter}} som den för närvarande används på.",
- "tags-delete-explanation-warning": "Denna åtgärd är <strong>oåterkallelig</strong> och <strong>kan inte ångras</strong>, inte ens av databasadministratörer. Var säker på att detta är den tagg du vill radera.",
- "tags-delete-explanation-active": "<strong>Taggen\" $1 \" är fortfarande aktiv, och kommer att fortsätta att appliceras i framtiden.</strong> För att hindra detta, gå till den eller de platser där taggen är inställd att användas, och inaktivera den där.",
+ "tags-delete-explanation-warning": "Denna åtgärd är <strong>oåterkallelig</strong> och <strong>kan inte ångras</strong>, inte ens av databasadministratörer. Var säker på att detta är det märke du vill radera.",
+ "tags-delete-explanation-active": "<strong>Märket \"$1\" är fortfarande aktivt, och kommer att fortsätta att appliceras i framtiden.</strong> För att hindra detta, gå till den eller de platser där märket är inställd att användas, och inaktivera den där.",
"tags-delete-reason": "Anledning:",
- "tags-delete-submit": "Radera denna tagg oåterkalleligen",
- "tags-delete-not-allowed": "Tagg definierade med ett tillägg kan inte raderas utan att tillägget specifikt tillåter det.",
- "tags-delete-not-found": "Taggen \"$1\" finns inte.",
- "tags-delete-too-many-uses": "Taggen \"$1\" appliceras på mer än $2 {{PLURAL:$2|version|versioner}}, vilket innebär att den inte kan raderas.",
- "tags-delete-warnings-after-delete": "Taggen \"$1\" raderades, men följande {{PLURAL:$2|varning|varningar}} inträffade:",
- "tags-activate-title": "Aktivera tagg",
- "tags-activate-question": "Du är på väg att aktivera taggen \"$1\".",
+ "tags-delete-submit": "Radera denna märke oåterkalleligen",
+ "tags-delete-not-allowed": "Märken definierade med ett tillägg kan inte raderas utan att tillägget specifikt tillåter det.",
+ "tags-delete-not-found": "Märket \"$1\" finns inte.",
+ "tags-delete-too-many-uses": "Märket \"$1\" appliceras på fler än $2 {{PLURAL:$2|version|versioner}}, vilket innebär att det inte kan raderas.",
+ "tags-delete-warnings-after-delete": "Märket \"$1\" raderades, men följande {{PLURAL:$2|varning|varningar}} uppstod:",
+ "tags-delete-no-permission": "Du har inte behörighet att radera ändringsmärken.",
+ "tags-activate-title": "Aktivera märke",
+ "tags-activate-question": "Du är på väg att aktivera märket \"$1\".",
"tags-activate-reason": "Anledning:",
- "tags-activate-not-allowed": "Det är inte möjligt att aktivera taggen \"$1\".",
- "tags-activate-not-found": "Taggen \"$1\" finns inte.",
+ "tags-activate-not-allowed": "Det är inte möjligt att aktivera märket \"$1\".",
+ "tags-activate-not-found": "Märket \"$1\" finns inte.",
"tags-activate-submit": "Aktivera",
- "tags-deactivate-title": "Inaktivera tagg",
- "tags-deactivate-question": "Du är på väg att inaktivera taggen \"$1\".",
+ "tags-deactivate-title": "Inaktivera märke",
+ "tags-deactivate-question": "Du är på väg att inaktivera märket \"$1\".",
"tags-deactivate-reason": "Anledning:",
- "tags-deactivate-not-allowed": "Det är inte möjligt att inaktivera taggen \"$1\".",
+ "tags-deactivate-not-allowed": "Det är inte möjligt att inaktivera märket \"$1\".",
"tags-deactivate-submit": "Inaktivera",
- "tags-apply-no-permission": "Du har inte behörighet att tillämpa taggar på dina ändringar",
+ "tags-apply-no-permission": "Du har inte behörighet att tillämpa märken på dina ändringar",
"tags-apply-blocked": "Du kan inte ange ändringsmärken med dina ändringar medans du är blockerad.",
"tags-apply-not-allowed-one": "Märket \"$1\" kan inte läggas till manuellt.",
"tags-apply-not-allowed-multi": "Följande {{PLURAL:$2|märke|märken}} kan inte läggas till manuellt: $1",
- "tags-update-no-permission": "Du har inte behörighet att lägga till eller ta bort taggar från individuella sidversioner eller loggposter.",
+ "tags-update-no-permission": "Du har inte behörighet att lägga till eller ta bort märken från individuella sidversioner eller loggposter.",
"tags-update-blocked": "Du kan inte lägga till eller ta bort ändringsmärken när du är blockerad.",
"tags-update-add-not-allowed-one": "Märket \"$1\" kan inte läggas till manuellt.",
"tags-update-add-not-allowed-multi": "Följande {{PLURAL:$2|märke|märken}} kan inte läggas till manuellt: $1",
"logentry-upload-revert": "$1 {{GENDER:$2|laddade upp}} $3",
"log-name-managetags": "Märkeshanteringslogg",
"log-description-managetags": "Denna sida innehåller administrativa [[Special:Tags|märke]]srelaterade uppgifter. Loggen innehåller bara åtgärder som utförts manuellt av en administratör; märken kan skapas eller raderas av wikins mjukvara utan att en post registreras i loggen.",
- "logentry-managetags-create": "$1 {{GENDER:$2|skapade}} taggen \"$4\"",
- "logentry-managetags-delete": "$1 {{GENDER:$2|raderade}} taggen \"$4\" (borttagen från $5 {{PLURAL:$5|version eller loggpost|versioner och/eller loggposter}})",
- "logentry-managetags-activate": "$1 {{GENDER:$2|aktiverade}} taggen \"$4\" för användning av användare och botar.",
- "logentry-managetags-deactivate": "$1 {{GENDER:$2|inaktiverade}} taggen \"$4\" för användning av användare och botar.",
+ "logentry-managetags-create": "$1 {{GENDER:$2|skapade}} märket \"$4\"",
+ "logentry-managetags-delete": "$1 {{GENDER:$2|raderade}} märket \"$4\" (borttagen från $5 {{PLURAL:$5|version eller loggpost|versioner och/eller loggposter}})",
+ "logentry-managetags-activate": "$1 {{GENDER:$2|aktiverade}} märket \"$4\" för användning av användare och botar.",
+ "logentry-managetags-deactivate": "$1 {{GENDER:$2|inaktiverade}} märket \"$4\" för användning av användare och botar.",
"log-name-tag": "Märkeslogg",
- "log-description-tag": "Denna sida visar när användare har lagt till eller tagit bort [[Special:Tags|taggar]] från individuella sidversioner eller loggposter. Loggen registrerar inte handlingar där märken hanteras i redigeringar, raderingar eller liknande handlingar.",
+ "log-description-tag": "Denna sida visar när användare har lagt till eller tagit bort [[Special:Tags|märken]] från individuella sidversioner eller loggposter. Loggen registrerar inte handlingar där märken hanteras i redigeringar, raderingar eller liknande handlingar.",
"logentry-tag-update-add-revision": "$1 {{GENDER:$2|lade till}} {{PLURAL:$7|märket|märkena}} $6 för sidversionen $4 av sidan $3",
"logentry-tag-update-add-logentry": "$1 {{GENDER:$2|lade till}} {{PLURAL:$7|märket|märkena}} $6 till loggposten $5 för siden $3",
"logentry-tag-update-remove-revision": "$1 {{GENDER:$2|tog bort}} {{PLURAL:$9|märket|märkena}} $8 från sidversionen $4 av sidan $3",
"feedback-useragent": "Användaragent:",
"searchsuggest-search": "Sök",
"searchsuggest-containing": "innehåller...",
+ "api-error-autoblocked": "Din IP-adress har blockerats automatiskt eftersom den har använts av en blockerad användare.",
"api-error-badaccess-groups": "Du får inte ladda upp filer till denna wiki.",
"api-error-badtoken": "Internt fel: felaktig nyckel.",
+ "api-error-blocked": "Du har blockerats från att redigera.",
"api-error-copyuploaddisabled": "Uppladdning via URL är inaktiverad på den här servern.",
"api-error-duplicate": "Det finns redan {{PLURAL:$1|en annan fil|andra filer}} på webbplatsen med samma innehåll.",
"api-error-duplicate-archive": "Det fanns redan {{PLURAL:$1|en annan fil|några andra filer}} på webbplatsen med samma innehåll, men {{PLURAL:$1|den har|de har}} raderats.",
"api-error-nomodule": "Internt fel: ingen uppladdningsmodul uppsatt.",
"api-error-ok-but-empty": "Internt fel: Inget svar från servern.",
"api-error-overwrite": "Det är inte tillåtet att skriva över en befintlig fil.",
+ "api-error-ratelimited": "Du försöker ladda upp fler filer inom en kort tidsrymd än denna wiki tillåter.\nFörsök igen om några minuter.",
"api-error-stashfailed": "Internt fel: servern kunde inte lagra temporär fil.",
"api-error-publishfailed": "Internt fel: Servern kunde inte publicera temporär fil.",
"api-error-stasherror": "Ett fel uppstod under uppladdningen av filen till mellanlagringsfilen.",
"sessionprovider-nocookies": "Cookies kan vara inaktiverade. Se till att du har cookies aktiverat och försök igen.",
"randomrootpage": "Slumprotsida",
"log-action-filter-block": "Typ av blockering:",
+ "log-action-filter-contentmodel": "Typ av innehållsmodellsändring:",
"log-action-filter-delete": "Typ av radering:",
"log-action-filter-import": "Importeringstyp:",
+ "log-action-filter-managetags": "Typ av märkeshanteringsåtgärd:",
"log-action-filter-move": "Flyttningstyp:",
"log-action-filter-newusers": "Typ av kontoskapande:",
"log-action-filter-patrol": "Typ av patrullering:",
"log-action-filter-protect": "Typ av skydd:",
+ "log-action-filter-rights": "Typ av rättighetsändring",
"log-action-filter-suppress": "Censurtyp",
"log-action-filter-upload": "Typ av uppladdning:",
"log-action-filter-all": "Alla",
"log-action-filter-block-reblock": "Blockeringsändring",
"log-action-filter-block-unblock": "Tog bort blockering",
"log-action-filter-contentmodel-change": "Ändring av innehållsmodell",
+ "log-action-filter-contentmodel-new": "Skapande av sida med icke-standardiserad innehållsmodell",
"log-action-filter-delete-delete": "Radering av sida",
"log-action-filter-delete-restore": "Återställde sida",
"log-action-filter-delete-event": "Radering av logg",
"log-action-filter-protect-move_prot": "Flyttade skydd",
"log-action-filter-rights-rights": "Manuell ändring",
"log-action-filter-rights-autopromote": "Automatisk ändring",
+ "log-action-filter-suppress-event": "Loggcensur",
+ "log-action-filter-suppress-revision": "Sidversionscensur",
+ "log-action-filter-suppress-delete": "Sidcensur",
+ "log-action-filter-suppress-block": "Användarcensur efter blockering",
+ "log-action-filter-suppress-reblock": "Användarcensur efter återblockering",
"log-action-filter-upload-upload": "Ny uppladdning",
- "log-action-filter-upload-overwrite": "Återuppladdning"
+ "log-action-filter-upload-overwrite": "Återuppladdning",
+ "authmanager-authn-not-in-progress": "Autentiseringen pågår inte eller så har sessionsdata förlorats. Var god börja om från början igen.",
+ "authmanager-authn-no-primary": "De angivna inloggningsuppgifterna kunde inte autentiseras.",
+ "authmanager-authn-no-local-user": "De angivna inloggningsuppgifterna är inte associerade med någon användare på denna wiki.",
+ "authmanager-authn-no-local-user-link": "De angivna inloggningsuppgifterna är giltiga, men inte associerade med någon användare på denna wiki. Logga in på ett annat sätt eller skapa en ny användare och du kommer att få välja att länka dina föregående inloggningsuppgifter till det kontot.",
+ "authmanager-authn-autocreate-failed": "Kunde inte skapa ett lokalt konto automatiskt: $1",
+ "authmanager-change-not-supported": "De angivna inloggningsuppgifterna kan inte ändras, då ingenting kan använda dem.",
+ "authmanager-create-disabled": "Kontoregistrering är inaktiverat.",
+ "authmanager-create-from-login": "Fyll i fälten nedan för att skapa ditt konto.",
+ "authmanager-create-not-in-progress": "Skapande av konto pågår inte eller så har sessionsdata förlorats. Var god börja om från början igen.",
+ "authmanager-create-no-primary": "De angivna inloggningsuppgifterna kunde inte användas för att skapa ett konto.",
+ "authmanager-link-no-primary": "De angivna inloggningsuppgifterna kunde inte användas för att länka ett konto.",
+ "authmanager-link-not-in-progress": "Kontolänkning pågår inte eller så har sessionsdata förlorats. Var god börja om från början igen.",
+ "authmanager-authplugin-setpass-failed-title": "Kunde inte ändra lösenordet",
+ "authmanager-authplugin-setpass-failed-message": "Insticksmodulen för autentisering nekade lösenordsändringen.",
+ "authmanager-authplugin-create-fail": "Insticksmodulen för autentisering nekade skapande av konto.",
+ "authmanager-authplugin-setpass-denied": "Insticksmodulen för autentisering tillåter inte ändring av lösenord.",
+ "authmanager-authplugin-setpass-bad-domain": "Ogiltig domän.",
+ "authmanager-autocreate-noperm": "Det är inte tillåtet att skapa konton automatiskt.",
+ "authmanager-autocreate-exception": "P.g.a. tidigare fel har automatiskt skapande av konton inaktiverats.",
+ "authmanager-userdoesnotexist": "Användarkontot \"$1\" är inte registrerat.",
+ "authmanager-userlogin-remembermypassword-help": "Om lösenordet borde kommas ihåg längre än sessionens längd.",
+ "authmanager-username-help": "Användarnamn för autentisering.",
+ "authmanager-password-help": "Lösenord för autentisering.",
+ "authmanager-domain-help": "Domän för extern autentisering.",
+ "authmanager-retype-help": "Lösenord igen för att bekräfta.",
+ "authmanager-email-label": "E-post",
+ "authmanager-email-help": "E-postadress",
+ "authmanager-realname-label": "Riktigt namn",
+ "authmanager-realname-help": "Användarens riktiga namnet",
+ "authmanager-provider-password": "Lösenordsbaserad autentisering",
+ "authmanager-provider-password-domain": "Lösenord- och domänbaserad autentisering",
+ "authmanager-provider-temporarypassword": "Tillfälligt lösenord",
+ "authprovider-confirmlink-message": "Baserat på dina nyliga inloggningsförsök kan följande konton länkas till ditt wikikonto. Om dessa konton länkas kan du logga in via dem. Välj vilka som bör länkas.",
+ "authprovider-confirmlink-request-label": "Konton som bör vara länkade",
+ "authprovider-confirmlink-success-line": "$1: Länkning genomförd.",
+ "authprovider-confirmlink-failed": "Konto kunde inte länkas helt och hållet: $1",
+ "authprovider-confirmlink-ok-help": "Fortsätt efter att felmeddelanden om länkning har visats.",
+ "authprovider-resetpass-skip-label": "Hoppa över",
+ "authprovider-resetpass-skip-help": "Hoppa över återställningen av lösenord.",
+ "authform-nosession-login": "Autentiseringen lyckades, men din webbläsare kan inte \"komma ihåg\" att du är inloggad.\n\n$1",
+ "authform-nosession-signup": "Kontot skapades, men din webbläsare kan inte \"komma ihåg\" att du är inloggad.\n\n$1",
+ "authform-newtoken": "Nyckel saknas. $1",
+ "authform-notoken": "Nyckel saknas",
+ "authform-wrongtoken": "Fel nyckel",
+ "specialpage-securitylevel-not-allowed-title": "Inte tillåtet",
+ "specialpage-securitylevel-not-allowed": "Tyvärr, du har inte tillåtelse att använda denna sida eftersom din identitet inte kunde verifieras.",
+ "authpage-cannot-login": "Det gick inte att starta inloggning.",
+ "authpage-cannot-login-continue": "Det gick inte att fortsätta inloggning. Din session har mest sannolikt gått ut.",
+ "authpage-cannot-create": "Det gick inte att starta kontoskapande.",
+ "authpage-cannot-create-continue": "Det gick inte att fortsätta kontoskapande. Din session har mest sannolikt gått ut.",
+ "authpage-cannot-link": "Det gick inte att starta kontolänkning.",
+ "authpage-cannot-link-continue": "Det gick inte att starta kontolänkning. Din session har mest sannolikt gått ut.",
+ "cannotauth-not-allowed-title": "Tillgång nekad",
+ "cannotauth-not-allowed": "Du har inte behörighet att använda denna sida",
+ "changecredentials": "Ändra inloggningsuppgifter",
+ "changecredentials-submit": "Ändra inloggningsuppgifter",
+ "changecredentials-invalidsubpage": "$1 är inte en giltig typ av inloggningsuppgift.",
+ "changecredentials-success": "Dina inloggningsuppgifter har ändrats.",
+ "removecredentials": "Ta bort inloggningsuppgifter",
+ "removecredentials-submit": "Ta bort inloggningsuppgifter",
+ "removecredentials-invalidsubpage": "$1 är inte en giltig typ av inloggningsuppgift.",
+ "removecredentials-success": "Dina inloggningsuppgifter har tagits bort.",
+ "credentialsform-provider": "Typ av inloggningsuppgifter:",
+ "credentialsform-account": "Kontonamn:",
+ "cannotlink-no-provider-title": "Det finns inga konton som kan länkas",
+ "cannotlink-no-provider": "Det finns inga konton som kan länkas.",
+ "linkaccounts": "Länka konton",
+ "linkaccounts-success-text": "Kontot länkades.",
+ "linkaccounts-submit": "Länka konton",
+ "unlinkaccounts": "Avlänka konton",
+ "unlinkaccounts-success": "Kontot avlänkades."
}
"noname": "Hauja dhihilisha jina la mtumiaji.",
"loginsuccesstitle": "Umefaulu kuingia",
"loginsuccess": "'''Umeingia {{SITENAME}} kama \"$1\".'''",
- "nosuchuser": "Hakuna mtumiaji mwenye jina \"$1\".\nKumbuka kwamba programu inatofautishana kati ya herufi kubwa na ndogo.\nLabda umeandika vibaya, au [[Special:UserLogin/signup|sajili akaunti mpya]].",
+ "nosuchuser": "Hakuna mtumiaji mwenye jina \"$1\".\nKumbuka kwamba programu inatofautishana kati ya herufi kubwa na ndogo.\nLabda umeandika vibaya, au [[Special:CreateAccount|sajili akaunti mpya]].",
"nosuchusershort": "Hakuna mtumiaji mwenye jina \"$1\". Labda umeandika vibaya.",
"nouserspecified": "Lazima uandike jina la mtumiaji.",
"login-userblocked": "Mtumiaji huyu amezuiwa. Hawezi kuingia.",
"accmailtext": "Neno la siri limetolewa na programu kwa ajili ya [[User talk:$1|$1]] na limetumwa kwa $2.\n\nUnaweza kubadilisha neno la siri hilo kwenye ukurasa wa ''[[Special:ChangePassword|kubadilisha neno la siri]]'' baada ya kuingia.",
"newarticle": "(Mpya)",
"newarticletext": "Ukurasa unaotaka haujaandikwa bado. Ukipenda unaweza kuuandika wewe mwenyewe kwa kutumia sanduku la hapa chini (tazama [$1 Mwongozo] kwa maelezo zaidi). Ukifika hapa kwa makosa, bofya kibonyezi '''back''' (nyuma) cha programu yako.",
- "anontalkpagetext": "----''Huu ni ukurasa wa majadiliano wa mtumiaji ambaye hana jina na bado hajaumba akaunti bado, au hajawahi kutumia kabisa.\nKwa hiyo tunatumia namba za anwani ya IP yake kumtambulisha.\nAnwani ya IP kama hiyo inaweza kutumika na watumiaji kadhaa.\nLabda itakusumbua kwamba kuna maoni mengine yanawekwa hapa na unaamini kwamba haya maoni hayakulengi. Ikiwa hivyo, tafadhali [[Special:UserLogin/signup|fungua akaunti]] au [[Special:UserLogin|ingia]] ili kuepuka kuchanganywa na watumiaji wengine ambao hawana jina.''",
+ "anontalkpagetext": "----''Huu ni ukurasa wa majadiliano wa mtumiaji ambaye hana jina na bado hajaumba akaunti bado, au hajawahi kutumia kabisa.\nKwa hiyo tunatumia namba za anwani ya IP yake kumtambulisha.\nAnwani ya IP kama hiyo inaweza kutumika na watumiaji kadhaa.\nLabda itakusumbua kwamba kuna maoni mengine yanawekwa hapa na unaamini kwamba haya maoni hayakulengi. Ikiwa hivyo, tafadhali [[Special:CreateAccount|fungua akaunti]] au [[Special:UserLogin|ingia]] ili kuepuka kuchanganywa na watumiaji wengine ambao hawana jina.''",
"noarticletext": "Ukurasa huu haujaandikwa bado. [[Special:Search/{{PAGENAME}}|tafutia jina hili]] katika kurasa nyingine, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tafuta kumbukumbu zinazohusika], au [{{fullurl:{{FULLPAGENAME}}|action=edit}} hariri ukurasa huu]</span>.",
"noarticletext-nopermission": "Kwa sasa hakuna maandishi katika ukurasa huu.\nUnaweza [[Special:Search/{{PAGENAME}}|kutafuta jina la ukurasa huu]] katika kurasa nyingine,\nau <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tafuta kumbukumbu zinazohusika]</span>, lakini huruhusiwi kuanzisha ukurasa huu.",
"userpage-userdoesnotexist": "Akaunti ya mtumiaji \"<nowiki>$1</nowiki>\" haijasajilishwa.\nUkitaka kuanzisha au kuhariri ukurasa huu tafadhali ucheki jina la akaunti.",
"noname": "To ńy je poprowne mjano użytkowńika.",
"loginsuccesstitle": "Logowańy udane",
"loginsuccess": "'''Terozki jeżeś zalogowany do {{SITENAME}} kej \"$1\".'''",
- "nosuchuser": "Ńy ma sam użytkowńika uo mjańe \"$1\".\nSprowdź szrajbůng, abo [[Special:UserLogin/signup|utwůrz nowe kůnto]].",
+ "nosuchuser": "Ńy ma sam użytkowńika uo mjańe \"$1\".\nSprowdź szrajbůng, abo [[Special:CreateAccount|utwůrz nowe kůnto]].",
"nosuchusershort": "Ńy mo sam użytkowńika uo mjańe \"$1\".",
"nouserspecified": "Podej mjano użytkowńika.",
"login-userblocked": "Tyn sprowjorz ma zawrzite sprowjyńa. Ńy możno sie zalogować.",
"accmailtext": "Cufalńe hasło lo [[User talk:$1|$1]] uostoło posłane do $2. Hasło lo tygo nowygo kůnta po zalogowańu je mogebność pomjyńić na zajće ''[[Special:ChangePassword|pomjyńańe hasła]]''.",
"newarticle": "(Nowy)",
"newarticletext": "Ńy mo sam jeszcze artikla uo takijj titli. Eli chcesz go sprowjać, naszkryflej niżyj jego tekst (wjyncy informacyj nojdźesz [$1 na zajće půmocy]). Eli żeś chćoł zrobić cośik inksze, naćiś ino knefel \"Nazod\".",
- "anontalkpagetext": "---- ''To je zajta godki lo anůnimowych używoczy - takich, kerzi ńy majům jeszcze swojigo kůnta abo ńy chcům go terozki używać.\nBy jejich idyntyfikować, używomy numerůw IP.\nEli jeżeś anůnimowym używoczym a wydowo Ći śe, aże zamjyszczůne sam kůmyntorze ńy sům skjyrowane do Ćebje, [[Special:UserLogin/signup|utwůrz kůnto]] abo [[Special:UserLogin|zaloguj śe]] - beztůż uńikńesz potym podobnych ńyporozumjyń.''",
+ "anontalkpagetext": "---- ''To je zajta godki lo anůnimowych używoczy - takich, kerzi ńy majům jeszcze swojigo kůnta abo ńy chcům go terozki używać.\nBy jejich idyntyfikować, używomy numerůw IP.\nEli jeżeś anůnimowym używoczym a wydowo Ći śe, aże zamjyszczůne sam kůmyntorze ńy sům skjyrowane do Ćebje, [[Special:CreateAccount|utwůrz kůnto]] abo [[Special:UserLogin|zaloguj śe]] - beztůż uńikńesz potym podobnych ńyporozumjyń.''",
"noarticletext": "Ńy můmy zajta uo takij titli. Mogesz [{{fullurl:{{FULLPAGENAME}}|action=edit}} wćepać artikel {{FULLPAGENAME}}] abo [[Special:Search/{{PAGENAME}}|sznupać {{PAGENAME}} we inkszych]].",
"noarticletext-nopermission": "Ta zajta terozki je pusto.\nMogesz [[Special:Search/{{PAGENAME}}|wysznupać ta titla]] we treśćach inkszych zajtůw, abo <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} przesznupać powjůnzane rejery]</span>, nale ńy mosz uprowńyń coby ta zajta wćepać",
"userpage-userdoesnotexist": "Użytkowńik \"<nowiki>$1</nowiki>\" ńy je zarejesztrowany. Sprowdź eli na pewno chćołżeś stworzyć/pomjynić gynał ta zajta.",
"Maathavan",
"தமிழ்க்குரிசில்",
"Nemo bis",
- "JAaron95"
+ "JAaron95",
+ "Info-farmer"
]
},
- "tog-underline": "à®\87ணà¯\88பà¯\8dபà¯\81à®\95ளà¯\81à®\95à¯\8dà®\95à¯\81 à®\85à®\9fிà®\95à¯\8dà®\95à¯\8bà®\9fிà®\9fà¯\81",
+ "tog-underline": "à®\85à®\9fிà®\95à¯\8dà®\95à¯\8bà®\9fிà®\9fà¯\8dà®\9fதà¯\8dதà¯\88 à®\87ணà¯\88:",
"tog-hideminor": "அண்மைய மாற்றங்களில் சிறிய தொகுப்புகளை மறை",
"tog-hidepatrolled": "அண்மைய மாற்றங்களில் ரோந்திட்ட தொகுப்புகளை மறைக்கவும்",
"tog-newpageshidepatrolled": "பலமுறை பார்வையிட்ட பக்கங்களைப் புதியபக்கங்களின் பட்டியலில் காட்டவேண்டாம்.",
"noname": "நீங்கள் கொடுத்த பயனர் பெயர் செல்லுபடியற்றது.",
"loginsuccesstitle": "புகுபதிகையில் உள்ளீர்கள்.",
"loginsuccess": "நீங்கள் தற்பொழுது {{SITENAME}} தளத்தில் \"$1\" கணக்கினூடாக புகுபதிகை செய்துள்ளீர்கள்.",
- "nosuchuser": "\"$1\" என்ற பெயரில் பயனர் எவருமில்லை.\n\nபயனர் பெயர், பெரிய எழுத்து, சிறிய எழுத்து என்ற வித்தியாசத்திற்குட்பட்டது.\n\nஎழுத்துப் பிழைகளைச் சரி பார்க்கவும், அல்லது [[Special:UserLogin/signup|புதிய பயனர் கணக்கொன்றை உருவாக்கவும்]].",
+ "nosuchuser": "\"$1\" என்ற பெயரில் பயனர் எவருமில்லை.\n\nபயனர் பெயர், பெரிய எழுத்து, சிறிய எழுத்து என்ற வித்தியாசத்திற்குட்பட்டது.\n\nஎழுத்துப் பிழைகளைச் சரி பார்க்கவும், அல்லது [[Special:CreateAccount|புதிய பயனர் கணக்கொன்றை உருவாக்கவும்]].",
"nosuchusershort": "\"$1\" என்ற பெயரில் பயனர் யாரும் இல்லை. நீங்கள் உள்ளிட்ட பெயரைச் சரி பார்க்கவும்.",
"nouserspecified": "நீங்கள் பயனர் பெயரொன்றைக் குறிப்பிட வேண்டும்.",
"login-userblocked": "இப்பயனர் கணக்கு தடைசெய்யப்பட்டுள்ளது. புகுபதிகை அனுமதிக்கப்படவில்லை.",
"accmailtext": "தானியக்கமாக [[User talk:$1|$1]]-க்கு ஒரு கடவுச்சொலை உறுவாக்கி $2-க்கு அனுப்பி வைக்கப்பட்டுள்ளது. இதனை புகுபதிகை செய்தவுடன் ''[[Special:ChangePassword|கடவுச்சொல்லை மாற்று]]'' பக்கத்தில் மாற்றிக்கொள்ளளாம்.",
"newarticle": "(புதிது)",
"newarticletext": "ஒரு இணைப்பினூடாக நீங்கள் வந்துள்ள இப்பக்கம் இன்னும் உருவாக்கப்படவில்லை. பக்கத்தை உருவாக்குவதற்குக் கீழேயுள்ள கட்டத்துள் தட்டச்சிடத் தொடங்குங்கள். (மேலதிக விபரங்களுக்கு [$1 உதவிப் பக்கத்தைப்] பார்க்கவும்). நீங்கள் தவறுதலாக இங்கே வந்திருந்தால், உங்கள் உலாவியின் பின் செல்வதற்கான பொத்தானைச் சொடுக்கவும்.",
- "anontalkpagetext": "----''இது இன்னும் கணக்கொன்று ஏற்படுத்தாத அல்லது வழமையாக பயனர் கணக்கை பயன்படுத்தாத பயனர்களுக்குரிய கலந்துரையாடல் பக்கமாகும். அதனால் நாங்கள் இவரை அடையாளம் காண்பதற்கு எண்சார்ந்த ஐபி முகவரியைப் பயன்படுத்த வேண்டியதாய் இருக்கின்றது. இவ்வாறான ஐபி முகவரிகள் பல பயனர்களினால் பகிர்ந்துகொள்ளப்படலாம்.\nநீங்கள் ஒரு முகவரியற்ற பயனராயிருந்து, தொடர்பற்ற கருத்துக்கள் உங்களைக் குறித்துச் சொல்லப்பட்டிருப்பதாக நீங்கள் உணர்ந்தால், முகவரியற்ற ஏனைய பயனர்களுடனான குழப்பங்களை எதிர்காலத்தில் தவிர்ப்பதற்கு, தயவுசெய்து [[Special:UserLogin/signup|புதிய கணக்கொன்றை ஏற்படுத்துங்கள்]] அல்லது [[Special:UserLogin|புகுபதிகை]] செய்யுங்கள்.''",
+ "anontalkpagetext": "----''இது இன்னும் கணக்கொன்று ஏற்படுத்தாத அல்லது வழமையாக பயனர் கணக்கை பயன்படுத்தாத பயனர்களுக்குரிய கலந்துரையாடல் பக்கமாகும். அதனால் நாங்கள் இவரை அடையாளம் காண்பதற்கு எண்சார்ந்த ஐபி முகவரியைப் பயன்படுத்த வேண்டியதாய் இருக்கின்றது. இவ்வாறான ஐபி முகவரிகள் பல பயனர்களினால் பகிர்ந்துகொள்ளப்படலாம்.\nநீங்கள் ஒரு முகவரியற்ற பயனராயிருந்து, தொடர்பற்ற கருத்துக்கள் உங்களைக் குறித்துச் சொல்லப்பட்டிருப்பதாக நீங்கள் உணர்ந்தால், முகவரியற்ற ஏனைய பயனர்களுடனான குழப்பங்களை எதிர்காலத்தில் தவிர்ப்பதற்கு, தயவுசெய்து [[Special:CreateAccount|புதிய கணக்கொன்றை ஏற்படுத்துங்கள்]] அல்லது [[Special:UserLogin|புகுபதிகை]] செய்யுங்கள்.''",
"noarticletext": "இப் பக்கத்தில் தற்பொழுது உள்ளடக்கம் எதுவுமில்லை. நீங்கள் இப்பக்க [[Special:Search/{{PAGENAME}}|தலைப்பை வேறு பக்கங்களில் தேடவோ]] அல்லது [{{fullurl:{{FULLPAGENAME}}|action=edit}} இப்பக்கத்தை தொகுக்கவோ] முடியும்.",
"noarticletext-nopermission": "தற்பொழுது இப்பக்கத்தில் உரை எதுவும் இல்லை.\nநீங்கள் [[Special:Search/{{PAGENAME}}|பக்கத் தலைப்பை வைத்து]] அல்லது மற்ற பக்கங்களில்,\nஅல்லது <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} அல்லது தேடுதல் தொடர்பான பதிவுகளில் தேடலாம்.]</span>, ஆனால் இந்தப் பக்கத்தை உருவாக்க அனுமதியில்லை.",
"missing-revision": "இந்த பரிசீலனை # $1 '' {{FULLPAGENAME}}' பெயருள்ள பக்கத்தின் இல்லை.!N வேடிக்கையானN!இது தான் வழக்கமாக ஏற்பட்டிருக்கலாம் நீக்கப்பட்டுள்ளது பக்கத்திற்கு outdated வரலாறு இணைப்பை தொடர்ந்து.\nவிவரங்கள் முடியும் கண்டறிய, [{{fullurl: {{# சிறப்பு: குறிப்பேடு}} / delete|page = {{FULLPAGENAMEE}}}} நீக்குதல் குறிப்பேடு].",
"unprotectthispage": "ಈ ಪುಟೊತ ರಕ್ಷಣೆನ್ ಬದಲ್ಪುಲೆ",
"newpage": "ಪೊಸ ಪುಟೊ",
"talkpage": "ಪುಟದ ಬಗ್ಗೆ ಚರ್ಚೆ ಮನ್ಪುಲೆ",
- "talkpagelinktext": "ಪಾತೆರ್ಲೆ",
+ "talkpagelinktext": "ಪಾತೆರ",
"specialpage": "ವಿಶೇಷ ಪುಟ",
"personaltools": "ಸ್ವಂತೊ ಉಪಕರಣೊಲು",
"articlepage": "ಲೇಖನ ಪುಟೊನು ತೂಲೆ",
"mainpage-description": "ಮುಖ್ಯ ಪುಟ",
"policy-url": "Project:ನಿಯಮಾವಳಿ",
"portal": "ಸಮುದಾಯೊ ಪುಟೊ",
- "portal-url": "Project:ಸಮುದಾಯೊ ಪುಟೊ",
+ "portal-url": "Project:ಸಮುದಾಯ ಪುಟ",
"privacy": "ಕಾಸಗಿ ಕಾರ್ಯೊನೀತಿ",
"privacypage": "Project:ಕಾಸಗಿ ಕಾರ್ಯೊನೀತಿ",
"badaccess": "ಅನುಮತಿ ದೋಷ",
"page-atom-feed": "\"$1\" ಪುಟೊತ Atom ಫೀಡ್",
"feed-atom": "Atom",
"feed-rss": "RSS",
- "red-link-title": "$1 (à²\88 ಪà³\81à²\9fà³\8a ನನಲ à²\85ಸà³\8dತಿತà³\8dವà³\8aಡà³\8d à²\87ದà³\8dದಿ)",
+ "red-link-title": "$1 (à²\88 ಪà³\81à²\9fà³\8a ನನಲ à²\85ಸà³\8dತಿತà³\8dವà³\8aಡà³\8d à²\87à²\9cà³\8dà²\9cಿ)",
"sort-descending": "ಇಳಿಕೆ ಕ್ರಮೊಟ್ಟು ಜೋಡಿಸಾಲ",
"sort-ascending": "ಏರಿಕೆ ಕ್ರಮೊಟ್ಟು ಜೋಡಿಸಾಲ",
"nstab-main": "ಪುಟೊ",
"enterlockreason": "ಡೇಟಬೇಸ್ ಮುಚ್ಚುನ ಕಾರಣೊನು ಬೊಕ್ಕೊ ನಾನೊರೊ ಅಯಿನ್ ದೆಪ್ಪುನ ಅಂದಾಜಿದ ಪೊರ್ತುನು ತೆರಿಪಾಲೆ",
"missing-article": "\"$1\" $2 ಪುದರ್’ದ ಪುಟ ದೇಟಬೇಸ್’ಡ್ ಇಜ್ಜಿ.\n\nಡಿಲೀಟ್ ಮಲ್ತಿನ ಪುಟೊಕು ಸಂಪರ್ಕ ಕೊರ್ಪುನ ಇತಿಹಾಸ ಲಿಂಕ್ ಅತ್ತ್’ನ್ಡ ವ್ಯತ್ಯಾಸ ಲಿಂಕ್’ನ್ ಒತ್ತುನೆರ್ದಾದ್ ಈ ದೋಷ ಸಾಧಾರಣವಾದ್ ಬರ್ಪುಂಡು.\n\nಒಂಜಿ ವೇಳೆ ಅಂಚ ಆದಿಜ್ಜಿಂಡ, ಉಂದು ಒಂಜಿ ಸಾಫ್ಟ್-ವೇರ್ ದೋಷ ಆದುಪ್ಪು.\nಇಂದೆನ್ [[Special:ListUsers/sysop|ವಿಕಿ-ಅಧಿಕಾರಿಗ್]] ತೆರಿಪಾಲೆ.",
"missingarticle-rev": "(ಮರು-ಆವೃತ್ತಿ#: $1)",
+ "missingarticle-diff": "(ವ್ಯತ್ಯಾಸೊ: $1, $2)",
+ "readonly_lag": "ಅಡಿಟುಪ್ಪುನ ಡೇಟಾಬೇಸ್ ಸರ್ವರ್ಕುಲು ಮೂಲೊ ಸರ್ವರ್ದೊಟ್ಟುಗೆ ಸಮಾನತೆಗ್ ಬರ್ಪುನ ಮುಟ್ಟೊ ಡೇಟಾಬೇಸ್ನ್ ಯಾಂತ್ರಿಕವಾದ್ ಮುಚ್ಚಿದ್ ಆತ್ಂಡ್",
"internalerror": "ಆ೦ತರಿಕ ದೋಷ",
"internalerror_info": "ಆಂತರಿಕ ದೋಷ: $1",
+ "internalerror-fatal-exception": "\"$1\" ಬಗೆತ ಒಂಜಿ ಗಂಭೀರವಾಯಿನ ಆಕ್ಷೇಪಣೆ",
"filecopyerror": "ಫೈಲ್ \"$1\" ನ್ \"$2\" ಗ್ ನಕಲ್ ಮಲ್ಪೆರೆ ಆಯಿಜಿ",
"filerenameerror": "\"$1\" ಫೈಲ್ ನ್ \"$2\"ಗ್ ಪುನರ್ನಾಮಕರಣ ಮಲ್ಪೆರೆ ಆಯಿಜಿ.",
"filedeleteerror": "\"$1\" ಫೈಲ್ ನ್ ದೆತ್ತ್ ಪಾಡೆರೆ ಆವೊ೦ದಿಜ್ಜಿ.",
"directorycreateerror": "\"$1\" ಡೈರೆಕ್ಟರಿನ್ ಉ೦ಡು ಮಲ್ಪೆರೆ ಆವೊ೦ದಿಜ್ಜಿ.",
+ "directoryreadonlyerror": "\"$1\" ಡೈರೆಕ್ಟರಿ ಓದೆರೆ ಮಾಂತ್ರೊ.",
+ "directorynotreadableerror": "\"$1\" ಡೈರೆಕ್ಟರಿನ್ ಓದೆರೆ ಸಾದ್ಯೊ ಇದ್ದಿ",
"filenotfound": "\"$1\" ಫೈಲ್ ನ್ ನಾಡಿಯೆರೆ ಆಯಿಜಿ.",
"unexpected": "ಅನಿರೀಕ್ಷಿತ ಮೌಲ್ಯ: \"$1\"=\"$2\".",
"formerror": "ದೋಷ: ಅರ್ಜಿನ್ ಕಡಪುಡಿಯೆರ್ ಆಯಿಜಿ",
"badarticleerror": "ಈ ಪುಟಡ್ ಈರ್ ಪ್ರಯತ್ನಿಸಾನ ಕಾರ್ಯ ಸಾದ್ಯ ಇಜ್ಜಿ",
"cannotdelete": "ಪುಟ ಅಥವಾ ಹೊತ್ತಗೆ \"$1\" ನ್ ಮಾಜಾವರ ಆಪುಜ್ಜಿ.(ಬೇತೆ ಎರೋ ಮಾಜಾದಿಪ್ಪೆರ್)",
"cannotdelete-title": "\"$1\" ಮಾಜಾವರೆ ಆಪುಜ್ಜಿ",
+ "delete-hook-aborted": "ಮಾಜಪುನೆನ್ ರದ್ದ್ ಮಲ್ತಿನ ಕೊಂಡಿ. ಅವು ಒವ್ವೇ ಇವರಣೆ ಕೊರ್ತ್ಜಿ.",
+ "no-null-revision": "\"$1\" ಪುಟೊದ ಸೊನ್ನೆ ಪುನರಾವರ್ತನೆನ್ ರಚಿಸಯರ್ ಸಾದ್ಯೊ ಇದ್ದಿ",
"badtitle": "ಸರಿ ಇದ್ಯಾಂದಿನ ಪುದರ್",
"badtitletext": "ಈರ್ ಕೋರಿನ ಪುಟದ ಶೀರ್ಷಿಕೆ ಸಿಂಧು ಅತ್ತ್ ಅಥವಾ ಕಾಲಿ ಅಥವಾ ಸರಿಯಾಯಿನ ಕೊಂಡಿ ಅತ್ತಾಂದಿನ ಅಂತರ ಬಾಸೆ/ಅಂತರ ವಿಕಿ ಸಂಪರ್ಕೊ.\nಅಯಿಟ್ ಒಂಜಿ ಅತ್ತಂಡ ಸೀರ್ಸಿಕೆಲೆ ಬಳಕೆ ಮಲ್ಪರೆ ನಿಸೇದೊ ಆಯಿನ ಅಕ್ಷರೊಲು ಇಪ್ಪು.",
+ "title-invalid-empty": "ಮನವಿ ಮಾಲ್ತ್ನ ಪುಟೊದ ತರೆಬರವು ಕಾಲಿಯಾತ್ಂಡ್ ಅತ್ತಂಡ ಕೇವಲೊ ಪುದರ್ದ ಜಾಗೆದ ಪುದರ್ನ್ ಮಾಂತ್ರೊ ಹೊಂದ್ದ್ಂಡ್.",
"perfcached": "ಈ ತಿರ್ತ್ದ ಮಾಹಿತಿಲು cacheದ್ ಬತ್ತ್ಂಡ್ ಬುಕ್ಕೊ ಇತ್ತೆದ ಸ್ತಿತಿನ್ ಬಿಂಬಿಸವೊಂದುಂಡು. ದಿಂಜ ಪಂಡ {{PLURAL:$1|one result is|$1 ಪಲಿತಾಂಸೊಲು}}cacheಡ್ ತಿಕುಂಡು.",
"perfcachedts": "ಈ ತಿರ್ತ್ದ ಮಾಹಿತಿಲು cacheದ್ ಬತ್ತ್ಂಡ್ ಬುಕ್ಕೊ ಇತ್ತೆದ ಸ್ತಿತಿನ್ ಬಿಂಬಿಸವೊಂದುಂಡು. ದಿಂಜ ಪಂಡ {{PLURAL:$4|one result is|$4 ಪಲಿತಾಂಸೊಲು}}cacheಡ್ ತಿಕುಂಡು.",
"querypage-no-updates": "ಈ ಪುಟೊತ್ತ ಆಧುನಿಕ ಮಲ್ಪುನ ಕ್ರಿಯೆನ್ ಸದ್ಯಗ್ ಉಂತಾದ್ಂಡ್. ಮುಲ್ಪ ಉಪ್ಪುನ ಮಾಹಿತಿನ್ ನವೀಕರಣ ಮಲ್ಪರಾಪುಜಿ",
"noname": "ಈರ್ ಸರಿಯಾಯಿನ ಬಳಕೆದಾರ ಪುದರ್ ಕೊರ್ತಿಜ್ಜರ್.",
"loginsuccesstitle": "ಲಾಗ್ ಇನ್ ಯಶಸ್ವಿಯಾತ್ಂಡ್",
"loginsuccess": "ಲಾಗ್ ಇನ್ ಯಶಸ್ವಿಯಾತ್‘ಂಡ್\". {{SITENAME}} \"$1\".'''",
- "nosuchuser": "!!\"$1\"ಪುದರ್‘ದ ವಾ ಸದಸ್ಯೆರ್‘ಲಾ ಇಜ್ಜೆರ್, ಅಕ್ಷರ ಸರಿಯಾದ ತೂಲೆ ಅಥವಾ [[Special:UserLogin/signup|ಪೊಸ ಸದಸ್ಯತ್ವ ಖಾತೆನ್ ಸೃಷ್ಟಿ ಮಲ್ಪುಲೆ]].",
+ "nosuchuser": "!!\"$1\"ಪುದರ್‘ದ ವಾ ಸದಸ್ಯೆರ್‘ಲಾ ಇಜ್ಜೆರ್, ಅಕ್ಷರ ಸರಿಯಾದ ತೂಲೆ ಅಥವಾ [[Special:CreateAccount|ಪೊಸ ಸದಸ್ಯತ್ವ ಖಾತೆನ್ ಸೃಷ್ಟಿ ಮಲ್ಪುಲೆ]].",
"nosuchusershort": "!!\"$1\"ಪುದರ್‘ದ ವಾ ಸದಸ್ಯೆರ್‘ಲಾ ಇಜ್ಜೆರ್, ಅಕ್ಷರ ಸರಿಯಾದ ತೂಲೆ.",
"nouserspecified": "ಈರ್ ಒಂಜಿ ಸದಸ್ಯತ್ವದ ಪುದರ್ ಸೂಚನೆ ಮಲ್ಪೊಡು.",
"login-userblocked": "ಈ ಸದಸ್ಯರೆನ ಖಾತೆನ್ ತಡೆ ಪತ್ತ್‘ದುಂಡು. ಲಾಗ್ ಇನ್ ಮಲ್ಪರೆ ಆಪುಜ್ಜಿ.",
"loginlanguagelabel": "ಬಾಸೆ: $1",
"pt-login": "ಲಾಗ್ ಇನ್",
"pt-login-button": "ಲಾಗಿನ್ ಆಲೆ",
- "pt-createaccount": "ಪà³\8aಸ à²\95ಾತೆ ಸುರು ಮಲ್ಪುಲೆ",
+ "pt-createaccount": "ಪà³\8aಸ à²\96ಾತೆ ಸುರು ಮಲ್ಪುಲೆ",
"pt-userlogout": "ಲಾಗ್ ಔಟ್",
"changepassword": "ಪ್ರವೇಶಪದೊನ್ ಬದಲಾವಣೆ ಮಲ್ಪುಲೆ",
"resetpass_header": "ಈ ಖಾತೆದ ಪ್ರವೇಶಪದ ಬದಲಾವಣೆ ಮಲ್ಪುಲೆ",
"noarticletext-nopermission": "ಈ ಪುಟೊಡ್ ಸದ್ಯಗ್ ಒವ್ವೇ ಬರವುಲಾ ಇಜ್ಜಿ, ಈರ್ ಬೇತೆ ಪುಟೊಡ್ [[Special:Search/{{PAGENAME}}|ಈ ಲೇಕನೊನು ನಾಡೊಲಿ]] <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ಸಂಬಂದೊ ಇತ್ತ್ನ ಲಾಗ್ನ್ ನಾಡ್ಲೆ], ಅತ್ತ್ಂಡ [{{fullurl:{{FULLPAGENAME}}|action=edit}} ಈ ಪುಟೊನು ಸಂಪೊಲಿಪೊಲಿ]</span>.",
"userpage-userdoesnotexist": "ಬಳಕೆದಾರ ಖಾತೆ \"<nowiki>$1</nowiki>\" ದಾಖಲಾತ್‘ಜ್ಜಿ. ಈರ್ ಉಂದುವೇ ಪುಟನ್ ಸಂಪಾದನೆ ಮಲ್ಪರ ಉಂಡಾಂದ್ ಖಾತ್ರಿ ಮಲ್ತೊನಿ.",
"previewnote": "'''ಉಂದು ಕೇವಲ ಮುನ್ನೋಟ; ಪುಟೊನು ನನಲ ಒರಿಪಾದಿಜಿ ಪನ್ಪುನೇನ್ ಮರಪೊರ್ಚಿ!'''",
- "editing": "$1 ಲೇಕನೊನು ಈರ್ ಸಂಪದನೆ ಮಲ್ತೊಂದುಲ್ಲರ್",
+ "editing": "$1 ಲà³\87à²\95ನà³\8aನà³\81 à²\88ರà³\8d ಸà²\82ಪಾದನà³\86 ಮಲà³\8dತà³\8aà²\82ದà³\81ಲà³\8dಲರà³\8d",
"creating": "$1 ನ್ನು ಸ್ರಿಸ್ಟಿಸವೊಂದುಂಡು",
"editingsection": "$1(ವಿಬಾಗೊನು) ಸಂಪದನೆ ಮಲ್ತೊಂದುಲ್ಲರ್",
"yourtext": "ಇರೆನ ಸಂಪಾದನೆ",
"yourdiff": "ವ್ಯತ್ಯಾಸೊಲು",
"copyrightwarning": "ದಯಮಲ್ತ್’ದ್ ಗಮನಿಸ್’ಲೆ: {{SITENAME}} ಸೈಟ್’ಡ್ ಇರೆನ ಪೂರಾ ಕಾಣಿಕೆಲುಲಾ $2 ಅಡಿಟ್ ಬಿಡುಗಡೆ ಆಪುಂಡು (ಮಾಹಿತಿಗ್ $1 ನ್ ತೂಲೆ). ಇರೆನ ಸಂಪಾದನೆಲೆನ್ ಬೇತೆಕುಲು ನಿರ್ಧಾಕ್ಷಿಣ್ಯವಾದ್ ಬದಲ್ ಮಲ್ತ್’ದ್ ಬೇತೆ ಕಡೆಲೆಡ್ ಪಟ್ಟೆರ್. ಇಂದೆಕ್ ಇರೆನ ಒಪ್ಪಿಗೆ ಇತ್ತ್’ನ್ಡ ಮಾತ್ರ ಮುಲ್ಪ ಸಂಪಾದನೆ ಮಲ್ಪುಲೆ.<br />\nಅತ್ತಂದೆ ಇರೆನ ಸಂಪಾದನೆಲೆನ್ ಈರ್ ಸ್ವತಃ ಬರೆತರ್, ಅತ್ತ್’ನ್ಡ ಕೃತಿಸ್ವಾಮ್ಯತೆ ಇಜ್ಜಂದಿನ ಕಡೆರ್ದ್ ದೆತೊನ್ದರ್ ಪಂಡ್’ದ್ ಪ್ರಮಾಣಿಸೊಂದುಲ್ಲರ್.\n'''ಕೃತಿಸ್ವಾಮ್ಯತೆದ ಅಡಿಟುಪ್ಪುನಂಚಿನ ಕೃತಿಲೆನ್ ಒಪ್ಪಿಗೆ ಇಜ್ಜಂದೆ ಮುಲ್ಪ ಪಾಡೊಚಿ!'''",
"templatesused": "ಈ ಪುಟೊಟ್ ಉಪಯೋಗ ಮಲ್ತಿನ {{PLURAL:$1|ಟೆಂಪ್ಲೇಟು|ಟೆಂಪ್ಲೇಟುಗಳು}}:",
- "templatesusedpreview": "ಈ ಮುನ್ನೋಟೊಡು ಉಪಯೋಗ ಮಲ್ತಿನ ಟೆಂಪ್ಲೇಟ್’ಲು:",
+ "templatesusedpreview": "ಈ ಮುನ್ನೋಟೊಡು ಉಪಯೋಗ ಮಲ್ತಿನ{{PLURAL:$1|Template|Templates}}:",
+ "templatesusedsection": "ಈ ಇಬಾಗೊಡು ಉಪಯೋಗ ಮಲ್ತಿನ {{PLURAL:$1|Template|Templates}}:",
"template-protected": "(ಸಂರಕ್ಷಿತೊ)",
"template-semiprotected": "(ಅರೆ-ಸಂರಕ್ಷಿತೊ)",
"hiddencategories": "ಈ ಪುಟೊ {{PLURAL:$1|೧ ಗುಪ್ತ ವರ್ಗೊಗ್|$1 ಗುಪ್ತ ವರ್ಗೊಲೆಗ್}} ಸೇರ್ದ್ನ್ಡ್:",
"history-fieldset-title": "ಇತಿಹಾಸಡ್ ನಾಡ್ಲೆ",
"history-show-deleted": "ದೆತ್ತ್ ಪಾಡಿನ",
"histfirst": "ಬಾರಿ ದುಂಬುದ",
- "histlast": "ಇಂಚಿಪ್ಪದ",
+ "histlast": "ಪೊಸ",
+ "historysize": "({{PLURAL:$1|೧ ಬೈಟ್|$1 ಬೈಟ್ಲು}})",
"historyempty": "(ಖಾಲಿ)",
"history-feed-title": "ಬದಲಾವಣೆಲೆನ ಇತಿಹಾಸೊ",
+ "history-feed-description": "ವಿಕಿದ ಈ ಪುಟೊತ ಬದಲಾವಣೆಲೆ ಇತಿಹಾಸೊ",
+ "history-feed-item-nocomment": "$1 $2 ಅಲ್ಪ",
"rev-delundel": "ತೋಜುನೆನ್ ದೆಂಗಲ",
"rev-showdeleted": "ತೊಜಾವು",
"revisiondelete": "ಮಾಜಾಯಿನ/ಮಾಜಾವಂದಿನ ಬದಲಾವಣೆಲು",
"powersearch-legend": "ಅಡ್ವಾನ್ಸ್’ಡ್ ಸರ್ಚ್",
"powersearch-ns": "ನೇಮ್-ಸ್ಪೇಸ್’ಲೆಡ್ ನಾಡ್ಲೆ",
"powersearch-toggleall": "ಮಾತಾ",
+ "powersearch-togglenone": "ಇದ್ದಿ",
+ "search-external": "ಬಾಹ್ಯೊ ಹುಡುಕಾಟೊ",
"preferences": "ಪ್ರಾಶಸ್ತ್ಯೊಲು",
"mypreferences": "ಪ್ರಾಸಸ್ತ್ಯೊಲು",
+ "prefs-skin": "ಸ್ಕಿನ್",
+ "skin-preview": "ಮುನ್ನೋಟೊ",
+ "datedefault": "ಒವ್ವೇ ಪ್ರಾಸಸ್ತ್ಯೊ ಇದ್ದಿ",
"prefs-rc": "ಇಂಚಿಪದ ಬದಲಾವಣೆಲು",
"prefs-resetpass": "ಪ್ರವೇಶಪದೊನ್ ಬದಲಾವಣೆ ಮಲ್ಪುಲೆ",
- "prefs-changeemail": "ಇ-ಅಂಚೆ ವಿಳಾಸೊನು ಬದಲಾವಣೆ ಮಲ್ಪುಲೆ",
+ "prefs-changeemail": "ಇ-ಅಂಚೆ ವಿಳಾಸೊನು ಬದಲಾವಣೆ ಮಲ್ಪುಲೆ ಅತ್ತಂಡ ದೆಪ್ಪುಲೆ",
+ "prefs-setemail": "ಇ-ಅಂಚೆ ವಿಳಾಸೊನು ಸ್ತಾಪನೆ ಮಲ್ಪು",
+ "prefs-email": "ಇ-ಅಂಚೆ ಇಚ್ಛೆಲು",
+ "prefs-rendering": "ಗೋಚರೊ",
"saveprefs": "ಒರಿಪಾಲೆ",
+ "prefs-editing": "ಸಂಪೊಲಿಪು",
"rows": "ಸಾಲ್‘ಲು",
+ "columns": "ಸಾಲ್ಕುಲು:",
"searchresultshead": " \nನಾಡ್’ಲೆ",
+ "stub-threshold-sample-link": "ಸಾಂಪಲ್",
+ "stub-threshold-disabled": "ಕ್ರಿಯೆ ಉಂತ್ದ್ಂಡ್",
+ "recentchangesdays": "ಇಂಚಿಪೊದ ಬದಲಾವಣೆಡ್ ತೋಜ್ಪಾವೊಡಾಯಿನ ದಿನೊಕುಲು:",
+ "timezonelegend": "ಸಮಯೊದ ವಲಯೊ:",
"localtime": "ಸ್ಥಳೀಯ ಸಮಯ:",
+ "servertime": "ಸರ್ವರ್ದ ಕಾಲೊ:",
+ "guesstimezone": "ಬ್ರೌಸರ್ಡ್ದ ದಿಂಜವು",
"timezoneregion-africa": "ಆಫ್ರಿಕ",
"timezoneregion-america": "ಅಮೇರಿಕ",
"timezoneregion-antarctica": "ಅಂಟಾರ್ಟಿಕ",
"timezoneregion-arctic": "ಆರ್ಕ್ಟಿಕ್",
"timezoneregion-asia": "ಏಷ್ಯಾ",
+ "timezoneregion-atlantic": "ಅಟ್ಲಾಂಟಿಕ್ ಮಹಾಸಾಗರೊ",
"timezoneregion-australia": "ಆಸ್ಟ್ರೇಲಿಯಾ",
+ "timezoneregion-europe": "ಯುರೋಪ್",
+ "timezoneregion-indian": "ಹಿಂದೂ ಮಹಾಸಾಗರೊ",
+ "timezoneregion-pacific": "ಪೆಸಿಫಿಕ್ ಮಹಾಸಾಗರೊ",
+ "allowemail": "ಬೇತೆ ಸದಸ್ಯೆರೆಡ್ದ್ ಇ-ಮೈಲ್ಲೆನ್ ದೆತೊನ್ಲ",
+ "prefs-searchoptions": "ನಾಡ್ಲ",
+ "prefs-namespaces": "ಪುದರ್ದ ವರ್ಗೊಲು",
+ "default": "ಮೂಲೊಸ್ಥಿತಿ",
"prefs-files": "ಕಡತೊಲು",
+ "prefs-custom-css": "ಕಸ್ಟಮ್ ಸಿಎಸ್ಎಸ್",
+ "prefs-custom-js": "ಕಸ್ಟಮ್ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್",
+ "prefs-emailconfirm-label": "ಇ-ಮೈಲ್ದ ಒಪ್ಪಿಗೆ:",
"youremail": "ಇ-ಅಂಚೆ",
- "username": "ಸದಸ್ಯೆರ್ನ ಪುದರ್:",
+ "username": "{{GENDER:$1|ಸದಸ್ಯತ್ವೊದ ಪುದರ್}}:",
+ "prefs-registration": "ನೋಂದಣಿದ ಸಮಯ:",
"yourrealname": "ನಿಜವಾಯಿನ ಪುದರ್",
"yourlanguage": "ಭಾಷೆ:",
"yournick": "ಪೊಸ ಸಹಿ",
- "badsiglength": "ಇರೆನ ಸಹಿ ಭಾರೀ ಉದ್ದ ಆಂಡ್",
+ "badsiglength": "ಇರೆನ ಸಹಿ ಭಾರೀ ಉದ್ದ ಆಂಡ್. ಉಂದು ಮಸ್ತ್ ಉದ್ದೊ ಆಯೆರೆ ಬಲ್ಲಿ{{PLURAL:$1|character|characters}}.",
"yourgender": "ಲಿಂಗೊ",
- "gender-male": "à²\86ಣà³\8d",
- "gender-female": "ಪà³\8aಣà³\8dಣà³\81",
+ "gender-male": "à²\86ಯà³\86 ವಿà²\95ಿ ಪà³\81à²\9fà³\8aನà³\81 ಸà²\82ಪà³\8aಲಿಪà³\81ವà³\86",
+ "gender-female": "à²\86ಲà³\8d ವಿà²\95ಿ ಪà³\81à²\9fà³\8aನà³\81 ಸà²\82ಪà³\8aಲಿಪà³\81ವಲà³\8d",
"email": "ಇ-ಅಂಚೆ",
+ "prefs-help-email": "ಇ-ಮೈಲ್ ಎಡ್ರಾಸ್ ಕಡ್ಡಾಯೊ ಅತ್ತ್, ಆಂಡ ನಿಕುಲು ಅಯಿನ್ ಕೊರ್ಂಡ ಈರ್ ನಿಕ್ಲೆನ ಪ್ರವೇಸೊ ಪದೊನು ಮರತ್ಂಡ ಅಯಿನ್ ಈರೆಗ್ ಇ-ಮೈಲ್ಡ್ದ್ ಕಡಪುಡೊಲಿ.",
+ "prefs-help-email-required": "ಇ-ಮೈಲ್ ಎಡ್ರಾಸ್ ಬೋಡಾತ್ಂಡ್.",
+ "prefs-info": "ಬುಡೊತ ಮಾಹಿತಿ",
+ "prefs-i18n": "ಅಂತರರಾಷ್ಟ್ರೀಕರಣ",
"prefs-signature": "ಸಹಿ",
+ "prefs-dateformat": "ತಾರೋಕ್ದ ಸೈಲಿ",
+ "prefs-advancedediting": "ಸಾಮಾನ್ಯೊ ಆಯ್ಕೆಲು",
+ "prefs-editor": "ಸಂಪಾದಕೆ",
+ "prefs-preview": "ಮುನ್ನೋಟೊ",
+ "prefs-advancedrc": "ಪರಿಣತ ಇಚ್ಛೆಲು",
+ "prefs-advancedrendering": "ಪರಿಣತ ಇಚ್ಛೆಲು",
+ "prefs-advancedsearchoptions": "ಪರಿಣತ ಇಚ್ಛೆಲು",
+ "prefs-advancedwatchlist": "ಪರಿಣತ ಇಚ್ಛೆಲು",
+ "prefs-displayrc": "ಪ್ರದರ್ಸನೊ ಆಯ್ಕೆಲು",
+ "prefs-displaywatchlist": "ಪ್ರದರ್ಸನೊ ಆಯ್ಕೆಲು",
+ "prefs-tokenwatchlist": "ಟೊಕನ್",
+ "userrights-lookup-user": "ಬಳಕೆದಾರೆರೆ ಗುಂಪುಲೆನ್ ನಿರ್ವಹಿಸಲ",
+ "userrights-user-editname": "ಒಂಜಿ ಸದಸ್ಯ ಪುದರ್ ಬರೆಲೆ",
"group": "ಗುಂಪುಲು:",
"group-user": "ಬಳಕೆದಾರೆರ್",
"group-sysop": "ನಿರ್ವಾಹಕೆರ್",
"upload-disallowed-here": "ಈರ್ ಈ ಫೈಲ್ನ್ ಕುಡೊರೊ ಬರೆವರೆ ಸಾದ್ಯೊ ಇದ್ದಿ.",
"filedelete-comment": "ಕಾರಣ",
"filedelete-submit": "ಮಾಜಾಲೆ",
- "randompage": "à²\87à²\9aà³\8dà²\9aà³\86ದ ಪುಟೊ",
+ "randompage": "ಯಾದà³\83à²\9aà³\8dà²\9bಿà²\95 ಪುಟೊ",
"statistics": "ಅಂಕಿ ಅಂಶೊಲು",
"statistics-header-pages": "ಪುಟೊತ ಅಂಕಿ ಅಂಶಲು",
"nbytes": "$1 {{PLURAL:$1|ಬೈಟ್|ಬೈಟ್ಲು}}",
"whatlinkshere-prev": "{{PLURAL:$1|ದುಂಬುದ|ದುಂಬುದ $1}}",
"whatlinkshere-next": "{{PLURAL:$1|ಬೊಕ್ಕದ|ಬೊಕ್ಕದ $1}}",
"whatlinkshere-links": "← ಕೊಂಡಿಲು",
- "whatlinkshere-hideredirs": "$1 ಪಿರ ನಿರ್ದೇಶನೊಲು",
- "whatlinkshere-hidetrans": "$1 ಸà³\87ರಾವà³\81ನà³\86",
- "whatlinkshere-hidelinks": "$1 ಕೊಂಡಿಲು",
+ "whatlinkshere-hideredirs": "$1 ಪಿರನಿರ್ದೇಶನೊಲು",
+ "whatlinkshere-hidetrans": "$1 ಸà³\87ರಾವà³\81ನವà³\81",
+ "whatlinkshere-hidelinks": "$1 à²\95à³\8aà²\82ಡಿà²\95à³\81ಲà³\81",
"whatlinkshere-filters": "ಅರಿಪೆಲು",
"blockip": "ಈ ಸದಸ್ಯೆರೆನ್ ಬ್ಲಾಕ್ ಮಲ್ಪುಲೆ",
"ipboptions": "2 ಗಂಟೆಲು:2 hours,1 ದಿನ:1 day,3 ದಿನೊಲು:3 days,1 ವಾರ:1 week,2 ವಾರೊಲು:2 weeks,1 ತಿಂಗೊಲು:1 month,3 ತಿಂಗೊಲು:3 months,6 ತಿಂಗೊಲು:6 months,1 ವರ್ಷ:1 year,ಅನಿರ್ಧಿಷ್ಟ:infinite",
"tooltip-t-contributions": "{{GENDER:$1|ಈ ಬಳಕೆದಾರೆರ್}}ಈ ಸದಸ್ಯೆರ್ನ ಕಾಣಿಕೆದ ಪಟ್ಟಿನ್ ತೋಜಾವು",
"tooltip-t-emailuser": "ಈ ಸದಸ್ಯೆರೆಗ್ ಇ-ಮೇಲ್ ಕಡಪುಡ್ಲೆ",
"tooltip-t-upload": "ಫೈಲನ್ ಅಪ್ಲೋಡ್ ಮಲ್ಪುಲೆ",
- "tooltip-t-specialpages": "ಪೂರ ಪುಟೊಲೆನ ವಿಸೇಸೊ ಪಟ್ಟಿ",
+ "tooltip-t-specialpages": "ಪೂರ ವಿಸೇಸೊ ಪುಟೊಲೆನ ಪಟ್ಟಿ",
"tooltip-t-print": "ಈ ಪುಟೊದ ಮುದ್ರಣೊ ಮಲ್ಪುನ ಆವೃತ್ತಿ",
"tooltip-t-permalink": "ಪುಟೊದ ಈ ಆವೃತ್ತಿಗ್ ಸಾಸಿತೊ ಕೊಂಡಿ",
"tooltip-ca-nstab-main": "ಮಾಹಿತಿ ಪುಟೊನ್ ತೂಲೆ",
"noname": "మీరు సరైన వాడుకరి పేరు ఇవ్వలేదు.",
"loginsuccesstitle": "ప్రవేశం విజయవంతమైంది",
"loginsuccess": "<strong>మీరు ఇప్పుడు {{SITENAME}}లోనికి \"$1\"గా ప్రవేశించారు.</strong>",
- "nosuchuser": "\"$1\" అనే పేరుతో వాడుకరులు లేరు.\nవాడుకరి పేర్లు కేస్ సెన్సిటివ్.\nఅక్షరక్రమం సరిచూసుకోండి, లేదా [[Special:UserLogin/signup|కొత్త ఖాతా సృష్టించుకోండి]].",
+ "nosuchuser": "\"$1\" అనే పేరుతో వాడుకరులు లేరు.\nవాడుకరి పేర్లు కేస్ సెన్సిటివ్.\nఅక్షరక్రమం సరిచూసుకోండి, లేదా [[Special:CreateAccount|కొత్త ఖాతా సృష్టించుకోండి]].",
"nosuchusershort": "\"$1\" పేరుతో వాడుకరి ఎవరూ లేరు. పేరు సరి చూసుకోండి.",
"nouserspecified": "వాడుకరి పేరును తప్పనిసరిగా ఇవ్వాలి.",
"login-userblocked": "ఈ వాడుకరిని నిరోధించారు. ప్రవేశానికి అనుమతి లేదు.",
"accmailtext": "[[User talk:$1|$1]] కొరకు ఒక యాదృచ్ఛిక సంకేతపదాన్ని $2కి పంపించాం. లాగినయ్యాక, ''[[Special:ChangePassword|సంకేతపదాన్ని మార్చుకోండి]]'' అనే పేజీలో ఈ సంకేతపదాన్ని మార్చుకోవచ్చు.",
"newarticle": "(కొత్తది)",
"newarticletext": "ఈ లింకుకు సంబంధించిన పేజీ లేనే లేదు.\nకింది పెట్టెలో మీ రచనను టైపు చేసి ఆ పేజీని సృష్టించండి (దీనిపై సమాచారం కొరకు [$1 సహాయం పేజీ] చూడండి). మీరిక్కడికి పొరపాటున వచ్చి ఉంటే, మీ బ్రౌజరు <strong>back</strong> మీట నొక్కండి.",
- "anontalkpagetext": "----\n<em>ఇది ఒక అజ్ఞాత వాడుకరి చర్చా పేజీ. ఆ వాడుకరి ఇంకా తనకై ఖాతాను సృష్టించుకోలేదు, లేదా ఖాతా ఉన్నా దానిని ఉపయోగించడం లేదు.</em>\nఅంచేత, అతణ్ణి/ఆమెను గుర్తించడానికి ఐ.పీ. చిరునామాను వాడాల్సి వచ్చింది. \nఒకే ఐ.పీ. చిరునామాని చాలా మంది వాడుకరులు ఉపయోగించే అవకాశం ఉంది. \nమీరూ అజ్ఞాత వాడుకరి అయితే, మీకు సంబంధంలేని వ్యాఖ్యలు మిమ్మల్ని ఉద్దేశించినట్టుగా అనిపిస్తే, భవిష్యత్తులో ఇతర అజ్ఞాత వాడుకరులతో అయోమయం లేకుండా ఉండటానికి, [[Special:UserLogin/signup|ఖాతాను సృష్టించుకోండి]] లేదా [[Special:UserLogin|లాగినవండి]].''",
+ "anontalkpagetext": "----\n<em>ఇది ఒక అజ్ఞాత వాడుకరి చర్చా పేజీ. ఆ వాడుకరి ఇంకా తనకై ఖాతాను సృష్టించుకోలేదు, లేదా ఖాతా ఉన్నా దానిని ఉపయోగించడం లేదు.</em>\nఅంచేత, అతణ్ణి/ఆమెను గుర్తించడానికి ఐ.పీ. చిరునామాను వాడాల్సి వచ్చింది. \nఒకే ఐ.పీ. చిరునామాని చాలా మంది వాడుకరులు ఉపయోగించే అవకాశం ఉంది. \nమీరూ అజ్ఞాత వాడుకరి అయితే, మీకు సంబంధంలేని వ్యాఖ్యలు మిమ్మల్ని ఉద్దేశించినట్టుగా అనిపిస్తే, భవిష్యత్తులో ఇతర అజ్ఞాత వాడుకరులతో అయోమయం లేకుండా ఉండటానికి, [[Special:CreateAccount|ఖాతాను సృష్టించుకోండి]] లేదా [[Special:UserLogin|లాగినవండి]].''",
"noarticletext": "ప్రస్తుతం ఈ పేజీలో పాఠ్యమేమీ లేదు.\nవేరే పేజీలలో [[Special:Search/{{PAGENAME}}|ఈ పేజీ శీర్షిక కోసం వెతకవచ్చు]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} సంబంధిత చిట్టాలు చూడవచ్చు],\nలేదా [{{fullurl:{{FULLPAGENAME}}|action=edit}} ఈ పేజీని మార్చవచ్చు]</span>.",
"noarticletext-nopermission": "ప్రస్తుతం ఈ పేజీలో పాఠ్యమేమీ లేదు.\nమీరు ఇతర పేజీలలో [[Special:Search/{{PAGENAME}}|ఈ పేజీ శీర్షిక కోసం వెతకవచ్చు]], లేదా <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} సంబంధిత చిట్టాలలో వెతకవచ్చు]</span>, కానీ ఈ పేజీని సృష్టించడానికి మీకు అనుమతి లేదు.",
"missing-revision": "\"{{FULLPAGENAME}}\" అనే పేజీ యొక్క కూర్పు #$1 ఉనికిలో లేదు. సాధారణంగా ఏదైనా తొలగించబడిన పేజీ యొక్క కాలం చెల్లిన చరితం లింకును నొక్కినపుడు ఇది జరుగుతుంది. వివరాలు [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} తొలగింపు లాగ్] లో దొరుకుతాయి.",
"noname": "Номи корбари дурустеро шумо пешниҳод накардед.",
"loginsuccesstitle": "Вуруд бо муваффақият",
"loginsuccess": "'''Шумо акнун ба Википедиа ҳамчун \"$1\". вуруд кардед'''",
- "nosuchuser": "Корбаре бо номи \"$1\" вуҷуд надорад.\nАмали номро барраси кунед, ё [[Special:UserLogin/signup|ҳисоби ҷадидеро эҷод кунед]].",
+ "nosuchuser": "Корбаре бо номи \"$1\" вуҷуд надорад.\nАмали номро барраси кунед, ё [[Special:CreateAccount|ҳисоби ҷадидеро эҷод кунед]].",
"nosuchusershort": "Ягон корбаре бо номи \"$1\" вуҷуд надорад. Тарзи навишти номро санҷед.",
"nouserspecified": "Шумо бояд як номи корбарӣ мушаххас кунед.",
"login-userblocked": "Ин корбар баста шудааст. Вуруд манъ аст.",
"accmailtext": "Як гузарвожаи тасодуфан эҷодшуда барои [[User talk:$1|$1]] ба $2 фиристода шуд. Онро метавон дар саҳифаи <em>[[Special:ChangePassword|тағийри гузарвожа]]</em> пас аз вуруд тағйир дод.",
"newarticle": "(Нав)",
"newarticletext": "Шумо пайвандеро интихоб кардед, ки саҳифа дар он арзи вуҷуд надорад.\nБарои сохтани саҳифа, ба қуттии зерин нависед ([$1 саҳифаи роҳнаморо] барои маълумоти бештар нигаред).\nАгар аз сабаби хатогӣ ва ё иштибоҳ омадед, тугмаи '''Ба оқиб'''-ро дар браузери худ пахш кунед.",
- "anontalkpagetext": "----\n<em>Ин саҳифаи баҳс барои як корбари гумном (аноним) аст, ки ҳанӯз ҳисоби ҷадид эҷод накардааст ва ё аз он истифода намекунад.</em> \nБинобар ин барои шиносоиаш маҷбурем аз нишонаи IP рақамии вай истифода баред.\nЧунин нишонаи IP шояд аз сӯи чандин корбарон ба шакли муштарак истифода шавад. \nАгар шумо корбари гумном ҳастед ва ҳис мекунед, ки изҳори назари номарбуте ба шумо сурат гирифтааст, лутфан [[Special:UserLogin/signup|ҳисоберо эҷод кунед]] ё [[Special:UserLogin|вуруд шавед]] барои пешгирӣ аз нофаҳмиҳои оянда бо корбарони гумном.",
+ "anontalkpagetext": "----\n<em>Ин саҳифаи баҳс барои як корбари гумном (аноним) аст, ки ҳанӯз ҳисоби ҷадид эҷод накардааст ва ё аз он истифода намекунад.</em> \nБинобар ин барои шиносоиаш маҷбурем аз нишонаи IP рақамии вай истифода баред.\nЧунин нишонаи IP шояд аз сӯи чандин корбарон ба шакли муштарак истифода шавад. \nАгар шумо корбари гумном ҳастед ва ҳис мекунед, ки изҳори назари номарбуте ба шумо сурат гирифтааст, лутфан [[Special:CreateAccount|ҳисоберо эҷод кунед]] ё [[Special:UserLogin|вуруд шавед]] барои пешгирӣ аз нофаҳмиҳои оянда бо корбарони гумном.",
"noarticletext": "Дар ин саҳифа то кунун матне вуҷуд надорад.\nШумо метавонед дар дигар саҳифаҳо [[Special:Search/{{PAGENAME}}|унвони ин саҳифаро ҷустуҷӯ кунед]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} гузоришҳои алоқамандро ҷустуҷӯ намоед],\nё [{{fullurl:{{FULLPAGENAME}}|action=edit}} ин саҳифаро вироиш кунед]</span>.",
"noarticletext-nopermission": "Дар ин саҳифа то кунун матне вуҷуд надорад. Шумо метавонед дар дигар саҳифаҳо [[Special:Search/{{PAGENAME}}|унвони ин саҳифаро ҷустуҷӯ кунед]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} гузоришҳои алоқамандро ҷустуҷӯ намоед], ё [{{fullurl:{{FULLPAGENAME}}|action=edit}} ин саҳифаро вироиш кунед]</span>.",
"missing-revision": "Нусхаи #$1 саҳифа бо номи \"{{FULLPAGENAME}}\" вуҷуд надорад.\n\nОдатан ин амал дар ҳоли пайгирии пайванди барӯзнашудаи таърих ба саҳифаи ҳазвшуда рух медиҳад.\nИттилооти муфассалро [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дар гузориши ҳазв] дарёфт кардан мумкин аст.",
"expand_templates_remove_comments": "Ҳазфи тавзеҳот",
"expand_templates_generate_xml": "Намоиши дарахти таҷзеҳи XML",
"expand_templates_preview": "Пешнамоиш",
- "randomrootpage": "Саҳифаи решавии тасодуфӣ"
+ "randomrootpage": "Саҳифаи решавии тасодуфӣ",
+ "changecredentials-submit": "Тағйири ҳисоби корбарӣ",
+ "removecredentials-submit": "Хориҷи эътиборнома"
}
"noname": "Nomi korbari durustero şumo peşnihod nakarded.",
"loginsuccesstitle": "Vurud bo muvaffaqijat",
"loginsuccess": "'''Şumo aknun ba Vikipedia hamcun \"$1\". vurud karded'''",
- "nosuchuser": "Korbare bo nomi \"$1\" vuçud nadorad.\nAmali nomro barrasi kuned, jo [[Special:UserLogin/signup|hisobi çadidero eçod kuned]].",
+ "nosuchuser": "Korbare bo nomi \"$1\" vuçud nadorad.\nAmali nomro barrasi kuned, jo [[Special:CreateAccount|hisobi çadidero eçod kuned]].",
"nosuchusershort": "Jagon korbare bo nomi \"$1\" vuçud nadorad. Tarzi navişti nomro sançed.",
"nouserspecified": "Şumo bojad jak nomi korbarī muşaxxas kuned.",
"login-userblocked": "In korbar basta şudaast. Vurud man' ast.",
"วรากร อึ้งวิเชียร (Varakorn Ungvichian)",
"아라",
"Pphongpan355",
- "Macofe"
+ "Macofe",
+ "Pilarbini",
+ "Matma Rex"
]
},
"tog-underline": "การขีดเส้นใต้ลิงก์:",
"tog-watchdefault": "เพิ่มหน้าและไฟล์ที่ฉันแก้ไขเข้ารายการเฝ้าดู",
"tog-watchmoves": "เพิ่มและไฟล์ที่ฉันย้ายเข้ารายการเฝ้าดู",
"tog-watchdeletion": "เพิ่มหน้าและไฟล์ที่ฉันลบเข้ารายการเฝ้าดู",
+ "tog-watchuploads": "เพิ่มไฟล์ใหม่ที่ฉันอัพโหลดไปยังรายการเฝ้าดูของฉัน",
"tog-watchrollback": "เพิ่มหน้าที่ฉันย้อนกลับฉุกเฉินเข้ารายการเฝ้าดู",
"tog-minordefault": "กำหนดการแก้ไขทุกครั้งเป็นการแก้ไขเล็กน้อยโดยปริยาย",
"tog-previewontop": "แสดงตัวอย่างก่อนกล่องแก้ไข",
"noname": "คุณไม่ได้ใส่ชื่อผู้ใช้ที่ถูกต้อง",
"loginsuccesstitle": "ล็อกอินสำเร็จ",
"loginsuccess": "<strong>ขณะนี้คุณล็อกอินสู่ {{SITENAME}} ในชื่อ \"$1\"</strong>",
- "nosuchuser": "ไม่มีผู้ใช้ชื่อ \"$1\"\nชื่อผู้ใช้นั้นไวต่ออักษรใหญ่เล็ก\nกรุณาตรวจการสะกดอีกครั้ง หรือ[[Special:UserLogin/signup|สร้างบัญชีใหม่]]",
+ "nosuchuser": "ไม่มีผู้ใช้ชื่อ \"$1\"\nชื่อผู้ใช้นั้นไวต่ออักษรใหญ่เล็ก\nกรุณาตรวจการสะกดอีกครั้ง หรือ[[Special:CreateAccount|สร้างบัญชีใหม่]]",
"nosuchusershort": "ไม่มีผู้ใช้ชื่อ \"$1\" \nกรุณาตรวจสอบการสะกด",
"nouserspecified": "คุณต้องระบุชื่อผู้ใช้",
"login-userblocked": "ผู้ใช้นี้ถูกบล็อก ไม่อนุญาตให้ล็อกอิน",
"changepassword-success": "เปลี่ยนรหัสผ่านของคุณสำเร็จ!",
"changepassword-throttled": "ล่าสุดคุณพยายามล็อกอินมากครั้งเกินไป\nกรุณารอ $1 ก่อนลองอีกครั้ง",
"botpasswords": "รหัสผ่านบอต",
+ "botpasswords-label-appid": "ชื่อบอต:",
+ "botpasswords-label-create": "สร้าง",
+ "botpasswords-label-update": "อัปเดต",
+ "botpasswords-label-cancel": "ยกเลิก",
+ "botpasswords-label-delete": "ลบ",
+ "botpasswords-label-resetpassword": "ตั้งรหัสผ่านใหม่",
"resetpass_forbidden": "ไม่สามารถเปลี่ยนรหัสผ่านได้",
"resetpass-no-info": "คุณต้องล็อกอินเพื่อเข้าถึงหน้านี้โดยตรง",
"resetpass-submit-loggedin": "เปลี่ยนรหัสผ่าน",
"minoredit": "เป็นการแก้ไขเล็กน้อย",
"watchthis": "เฝ้าดูหน้านี้",
"savearticle": "บันทึกหน้า",
+ "publishpage": "เผยแพร่หน้า",
"preview": "ตัวอย่าง",
"showpreview": "แสดงตัวอย่าง",
"showdiff": "แสดงการเปลี่ยนแปลง",
"accmailtext": "ส่งรหัสผ่านแบบสุ่มของ [[User talk:$1|$1]] ไป $2 แล้ว สามารถเปลี่ยนรหัสผ่านในหน้า<em>[[Special:ChangePassword|เปลี่ยนรหัสผ่าน]]</em> หลังล็อกอิน",
"newarticle": "(ใหม่)",
"newarticletext": "คุณตามลิงก์ไปยังหน้าที่ยังไม่มีในขณะนี้\nในการสร้างหน้า เริ่มพิมพ์ในกล่องด้านล่าง (ดูข้อมูลเพิ่มเติมใน[$1 หน้าคำอธิบาย])\nถ้าคุณเข้ามาหน้านี้โดยผิดพลาด ให้กดปุ่ม<strong>ถอยหลัง</strong> (back) ของเบราว์เซอร์",
- "anontalkpagetext": "----\n<em>หน้านี้เป็นหน้าคุยกับผู้ใช้สำหรับผู้ใช้นิรนามซึ่งยังไม่ได้สร้างหรือใช้บัญชี</em>\nดังนั้นเราจึงระบุตัวตนโดยใช้เลขที่อยู่ไอพีแทน\nเลขที่อยู่ไอพีนี้อาจมีผู้ใช้ร่วมกันหลายคน\nถ้าคุณเป็นผู้ใช้นิรนาม และรู้สึกว่าคุณได้รับความเห็นที่ไม่เกี่ยวข้องส่งหาคุณ กรุณา[[Special:UserLogin/signup|สร้างบัญชี]]หรือ[[Special:UserLogin|ล็อกอิน]] เพื่อป้องกันการสับสนกับผู้ใช้นิรนามรายอื่นในอนาคต",
+ "anontalkpagetext": "----\n<em>หน้านี้เป็นหน้าคุยกับผู้ใช้สำหรับผู้ใช้นิรนามซึ่งยังไม่ได้สร้างหรือใช้บัญชี</em>\nดังนั้นเราจึงระบุตัวตนโดยใช้เลขที่อยู่ไอพีแทน\nเลขที่อยู่ไอพีนี้อาจมีผู้ใช้ร่วมกันหลายคน\nถ้าคุณเป็นผู้ใช้นิรนาม และรู้สึกว่าคุณได้รับความเห็นที่ไม่เกี่ยวข้องส่งหาคุณ กรุณา[[Special:CreateAccount|สร้างบัญชี]]หรือ[[Special:UserLogin|ล็อกอิน]] เพื่อป้องกันการสับสนกับผู้ใช้นิรนามรายอื่นในอนาคต",
"noarticletext": "ปัจจุบันไม่มีข้อความในหน้านี้\nคุณสามารถ[[Special:Search/{{PAGENAME}}|ค้นหาชื่อเรื่องหน้านี้]]ในหน้าอื่น <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ค้นหาปูมที่เกี่ยวข้อง] หรือ[{{fullurl:{{FULLPAGENAME}}|action=edit}} แก้ไขหน้านี้]</span>",
"noarticletext-nopermission": "ปัจจุบันไม่มีข้อความในหน้านี้\nคุณสามารถ[[Special:Search/{{PAGENAME}}|ค้นหาชื่อหน้านี้]]ในหน้าอื่น หรือ<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ค้นหาปูมที่เกี่ยวข้อง]</span> แต่คุณไม่มีสิทธิสร้างหน้านี้",
"missing-revision": "ไม่มีรุ่นปรับปรุง #$1 ของหน้าชื่อ \"{{FULLPAGENAME}}\" \n\nปกติเกิดจากการตามการโยงประวัติเก่าไปยังหน้าที่ถูกลบแล้ว\nดูรายละเอียดได้ที่[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ปูมการลบ]",
"yourdiff": "ความแตกต่าง",
"copyrightwarning": "โปรดระลึกว่างานเขียนทั้งหมดใน {{SITENAME}} ถือว่าเผยแพร่ภายใต้ $2 (ดูรายละเอียดทาง $1)\nหากคุณไม่ต้องการให้งานของคุณถูกแก้ไขและกระจายได้ตามใจ ก็อย่าส่งเข้ามา<br />\nนอกจากนี้ คุณยังสัญญาเราว่าคุณเขียนงานด้วยตนเอง หรือคัดลอกจากสาธารณสมบัติหรือทรัพยากรเสรีที่คล้ายกัน\n<strong>อย่าส่งงานมีลิขสิทธิ์โดยไม่ได้รับอนุญาต!</strong>",
"copyrightwarning2": "โปรดระลึกว่างานเขียนทั้งหมดใน {{SITENAME}} อาจถูกผู้เขียนอื่นแก้ไข เปลี่ยนแปลงหรือนำออก\nหากคุณไม่ต้องการให้งานของคุณถูกแก้ไข ก็อย่าส่งเข้ามา<br />\nนอกจากนี้ คุณยังสัญญาเราว่าคุณเขียนงานด้วยตนเอง หรือคัดลอกจากสาธารณสมบัติหรือทรัพยากรเสรีที่คล้ายกัน (ดูรายละเอียดที่ $1)\n<strong>อย่าส่งงานมีลิขสิทธิ์โดยไม่ได้รับอนุญาต!</strong>",
+ "editpage-cannot-use-custom-model": "รูปแบบเนื้อหาหน้านี้ไม่สามารถเปลี่ยนได้",
"longpageerror": "<strong>ข้อผิดพลาด: ข้อความที่คุณส่งมีขนาด $1 กิโลไบต์\nซึ่งเกินสูงสุด $2 กิโลไบต์</strong>\nไม่สามารถบันทึกได้",
"readonlywarning": "<strong>คำเตือน: ฐานข้อมูลถูกล็อกเพื่อบำรุงรักษา คุณจึงไม่สามารถบันทึกการแก้ไขของคุณได้ในขณะนี้</strong>\nคุณอาจต้องการคัดลอกและวางข้อความของคุณในไฟล์ข้อความ และบันทึกไว้ภายหลัง\n\nผู้ดูแลระบบที่ล็อกฐานข้อมูลให้คำอธิบายดังนี้: $1",
"protectedpagewarning": "<strong>คำเตือน: หน้านี้ถูกล็อก เพื่อให้เฉพาะผู้ใช้ที่มีสิทธิผู้ดูแลระบบแก้ไขได้เท่านั้น</strong>\nรายการปูมล่าสุดจัดไว้ด้านล่างเพื่อการอ้างอิง:",
"userrights": "การบริหารสิทธิผู้ใช้",
"userrights-lookup-user": "บริหารกลุ่มผู้ใช้",
"userrights-user-editname": "ใส่ชื่อผู้ใช้:",
- "editusergroup": "แก้ไขกลุ่มผู้ใช้",
+ "editusergroup": "แก้ไขกลุ่ม{{GENDER:$1|ผู้ใช้}}",
"editinguser": "กำลังเปลี่ยนสิทธิผู้ใช้ของผู้ใช้ <strong>[[User:$1|$1]]</strong> $2",
"userrights-editusergroup": "แก้ไขกลุ่มผู้ใช้",
- "saveusergroups": "บันทึกกลุ่มผู้ใช้",
+ "saveusergroups": "บันทึกกลุ่ม{{GENDER:$1|ผู้ใช้}}",
"userrights-groupsmember": "สมาชิกของ:",
"userrights-groupsmember-auto": "สมาชิกโดยปริยายของ:",
"userrights-groups-help": "คุณสามารถเปลี่ยนแปลงกลุ่มที่ผู้ใช้รายนี้อยู่:\n* กล่องที่มีเครื่องหมายถูก หมายความว่า ผู้ใช้อยู่ในกลุ่มนั้น\n* กล่องที่ไม่มีเครื่องหมายถูก หมายความว่า ผู้ใช้ไม่ได้อยู่ในกลุ่มนั้น\n* เครื่องหมาย * ชี้ว่าคุณไม่สามารถนำกลุ่มนั้นออกได้เมื่อคุณเพิ่มกลุ่มนั้นไปแล้ว หรือกลับกัน",
"right-override-export-depth": "ส่งออกหน้า รวมหน้าที่เชื่อมโยงกับหน้านี้สูงสุด 5 ลำดับชั้น",
"right-sendemail": "ส่งอีเมลหาผู้ใช้อื่น",
"right-passwordreset": "ดูอีเมลตั้งรหัสผ่านใหม่",
+ "grant-group-email": "ส่งอีเมล",
+ "grant-createaccount": "สร้างบัญชี",
+ "grant-createeditmovepage": "สร้าง แก้ไข และย้ายหน้า",
+ "grant-editmywatchlist": "แก้ไขรายการเฝ้าดูของคุณ",
+ "grant-editpage": "แก้ไขหน้านี้",
+ "grant-uploadeditmovefile": "อัปโหลด แทนที่ และย้ายไฟล์",
+ "grant-uploadfile": "อัปโหลดไฟล์ใหม่",
+ "grant-viewmywatchlist": "ดูรายการเฝ้าดูของคุณ",
"newuserlogpage": "ปูมการสร้างผู้ใช้",
"newuserlogpagetext": "นี่คือปูมการสร้างผู้ใช้",
"rightslog": "ปูมสิทธิผู้ใช้",
"uploaderror": "การอัปโหลดผิดพลาด",
"upload-recreate-warning": "<strong>คำเตือน: ไฟล์ชื่อนั้นถูกลบหรือเปลี่ยนชื่อแล้ว</strong>\n\nปูมการลบและปูมการย้ายของหน้านี้จัดไว้ด้านล่างเพื่อความสะดวก:",
"uploadtext": "กรุณาใช้แบบด้านล่างในการอัปโหลดไฟล์\nสำหรับการดูหรือการค้นหาไฟล์ที่เคยอัปโหลดก่อนหน้านี้ ให้ไปที่[[Special:FileList|รายการไฟล์ที่ถูกอัปโหลด]] การอัปโหลดและการอัปโหลดซ้ำดูได้ที่[[Special:Log/upload|ปูมการอัปโหลด]] และการลบไฟล์ดูได้ที่[[Special:Log/delete|ปูมการลบ]]\n\nถ้าต้องการแทรกไฟล์ลงในหน้าหนึ่ง ๆ ให้ใช้คำสั่งหนึ่งในรูปแบบต่อไปนี้\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code>''' เพื่อใช้รูปขนาดเต็ม\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|ข้อความอธิบาย]]</nowiki></code>''' เพื่อใช้รูปย่อขนาดกว้าง 200 พิกเซลในกล่องที่จัดชิดซ้าย โดยมี \"ข้อความอธิบาย\" เป็นคำบรรยายใต้ภาพ\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>''' สำหรับการเชื่อมโยงไฟล์โดยตรง โดยไม่ปรากฏไฟล์นั้นออกมา",
- "upload-permitted": "ชนิดไฟล์ที่อนุญาต: $1",
- "upload-preferred": "ชนิดไฟล์ที่ควรใช้: $1",
- "upload-prohibited": "ชนิดไฟล์ที่ไม่อนุญาต: $1",
+ "upload-permitted": "{{PLURAL:$2|type|ชนิด}}ไฟล์ที่อนุญาต: $1",
+ "upload-preferred": "{{PLURAL:$2|type|ชนิด}}ไฟล์ที่ควรใช้: $1",
+ "upload-prohibited": "{{PLURAL:$2|type|ชนิด}}:ไฟล์ที่ไม่อนุญาต: $1",
"uploadlogpage": "ปูมการอัปโหลด",
"uploadlogpagetext": "ด้านล่างเป็นรายการการอัปโหลดไฟล์ล่าสุด\nดูภาพรวมที่ [[Special:NewFiles|แกลอรีไฟล์ใหม่]]",
"filename": "ชื่อไฟล์",
"upload-form-label-infoform-description": "คำอธิบาย",
"upload-form-label-usage-title": "การใช้",
"upload-form-label-usage-filename": "ชื่อไฟล์",
+ "upload-form-label-infoform-categories": "หมวดหมู่",
+ "upload-form-label-infoform-date": "วันที่",
"backend-fail-backup": "ไม่สามารถสำรองไฟล์ \"$1\"",
"backend-fail-notexists": "ไม่มีไฟล์ $1",
"backend-fail-delete": "ไม่สามารถลบไฟล์ \"$1\"",
"suppress": "ผู้ดูแลประวัติ",
"querypage-disabled": "หน้าพิเศษนี้ถูกปิดใช้งานด้วยเหตุผลด้านสมรรถภาพ",
"apihelp-no-such-module": "ไม่พบมอดูล \"$1\"",
+ "apisandbox-unfullscreen": "แสดงหน้า",
+ "apisandbox-reset": "ล้าง",
+ "apisandbox-retry": "ลองใหม่",
+ "apisandbox-examples": "ตัวอย่าง",
+ "apisandbox-results": "ผลลัพธ์",
+ "apisandbox-request-url-label": "ขอ URL:",
"booksources": "แหล่งหนังสือ",
"booksources-search-legend": "ค้นหาแหล่งหนังสือ",
"booksources-search": "ค้นหา",
"listgrouprights-namespaceprotection-header": "การจำกัดเนมสเปซ",
"listgrouprights-namespaceprotection-namespace": "เนมสเปซ",
"listgrouprights-namespaceprotection-restrictedto": "สิทธิอนุญาตให้ผู้ใช้แก้ไข",
+ "listgrants-rights": "สิทธิ",
"trackingcategories": "หมวดหมู่ค้นหาและติดตาม",
"trackingcategories-summary": "หน้านี้แสดงรายการหมวดหมู่ค้นหาและติดตามซึ่งซอฟต์แวร์มีเดียวิกิจัดการอัตโนมัติ สามารถเปลี่ยนชื่อเหล่านี้ได้โดยการเปลี่ยนสารระบบที่เกี่ยวข้องในเนมสเปซ {{ns:8}}",
"trackingcategories-msg": "หมวดหมู่ค้นหาและติดตาม",
"rollback-success": "ย้อนการแก้ไขโดย $1; \nเปลี่ยนกลับไปรุ่นล่าสุดโดย $2",
"sessionfailure-title": "ช่วงเวลาสื่อสารล้มเหลว",
"sessionfailure": "ดูเหมือนมีปัญหากับช่วงเวลาสื่อสารล็อกอินของคุณ\nการกระทำนี้ถูกยกเลิกเป็นการป้องกันการลักลอบช่วงเวลาสื่อสารไว้ก่อน \nกลับไปหน้าที่แล้ว โหลดหน้าใหม่ แล้วลองอีกครั้ง",
+ "changecontentmodel-title-label": "ชื่อหน้า:",
+ "changecontentmodel-reason-label": "เหตุผล:",
+ "changecontentmodel-submit": "ความเปลี่ยนแปลง",
+ "logentry-contentmodel-change-revertlink": "ย้อน",
+ "logentry-contentmodel-change-revert": "ย้อน",
"protectlogpage": "ปูมการล็อก",
"protectlogtext": "ด้านล่างเป็นรายการการเปลี่ยนแปลงการล็อกหน้า\nดู[[Special:ProtectedPages|รายการหน้าที่ถูกล็อก]]สำหรับการล็อกหน้าที่มีผลอยู่ในปัจจุบัน",
"protectedarticle": "ล็อก \"[[$1]]\"",
"lockdbsuccesstext": "ล็อกฐานข้อมูลเรียบร้อย\n<br />อย่าลืม[[Special:UnlockDB|ปลดล็อก]]หลังการบำรุงรักษาเสร็จสิ้น",
"unlockdbsuccesstext": "ปลดล็อกฐานข้อมูลเรียบร้อย",
"lockfilenotwritable": "ไม่สามารถล็อกฐานข้อมูลได้ เนื่องจากการเขียนลงฐานข้อมูล การล็อกและการปลดล็อกจำเป็นต้องทำที่เว็บเซิร์ฟเวอร์",
+ "databaselocked": "ฐานข้อมูลถูกล็อก",
"databasenotlocked": "ฐานข้อมูลไม่ได้ล็อก",
"lockedbyandtime": "(โดย {{GENDER:$1|$1}} เมื่อวันที่ $2 เวลา $3)",
"move-page": "ย้าย $1",
"thumbnail_gd-library": "การตั้งค่าไลบรารี GD ไม่สมบูรณ์: ไม่พบฟังก์ชัน $1",
"thumbnail_image-missing": "ไฟล์ที่เหมือนหายไป: $1",
"import": "หน้านำเข้า",
- "importinterwiki": "à¸\99ำà¹\80à¸\82à¹\89าà¸\82à¹\89ามวิà¸\81ิ",
+ "importinterwiki": "à¸\99ำà¹\80à¸\82à¹\89าหà¸\99à¹\89าà¸\88าà¸\81วิà¸\81ิà¸à¸·à¹\88à¸\99",
"import-interwiki-text": "เลือกวิกิและชื่อหัวข้อที่ต้องการนำเข้า วันที่และชื่อผู้เขียนทั้งหมดจะถูกเก็บไว้ โดยการนำเข้าทุกส่วนจะถูกเก็บไว้ใน [[Special:Log/import|ปูมการนำเข้า]]",
"import-interwiki-sourcewiki": "วิกิต้นทาง:",
"import-interwiki-sourcepage": "หน้าต้นทาง:",
"import-logentry-interwiki-detail": "นำเข้า $1 {{PLURAL:$1|รุ่นการแก้ไข|รุ่นการแก้ไข}}จาก $2",
"javascripttest": "การทดสอบจาวาสคริปต์",
"javascripttest-qunit-intro": "ดู[$1 เอกสารกำกับการทดสอบ]บน mediawiki.org",
- "tooltip-pt-userpage": "หน้าผู้ใช้ของคุณ",
+ "tooltip-pt-userpage": "{{GENDER:|หน้าผู้ใช้}}ของคุณ",
"tooltip-pt-anonuserpage": "หน้าผู้ใช้ของเลขที่อยู่ไอพีที่คุณกำลังใช้แก้ไข",
- "tooltip-pt-mytalk": "หน้าพูดคุยของคุณ",
+ "tooltip-pt-mytalk": "หน้าพูดคุย{{GENDER:|ของคุณ}}",
"tooltip-pt-anontalk": "อภิปรายเกี่ยวกับการแก้ไขจากเลขที่อยู่ไอพีนี้",
- "tooltip-pt-preferences": "การตั้งค่าของคุณ",
+ "tooltip-pt-preferences": "การตั้งค่า{{GENDER:|ของคุณ}}",
"tooltip-pt-watchlist": "รายการหน้าที่คุณกำลังเฝ้าดูการเปลี่ยนแปลง",
- "tooltip-pt-mycontris": "รายการหน้าที่คุณเขียน",
+ "tooltip-pt-mycontris": "รายการหน้าที่{{GENDER:|คุณ}}เขียน",
"tooltip-pt-anoncontribs": "รายการการแก้ไขจากเลขที่อยู่ไอพีนี้",
"tooltip-pt-login": "สนับสนุนให้คุณล็อกอิน แต่ไม่บังคับ",
"tooltip-pt-logout": "ล็อกเอาต์",
"tooltip-t-recentchangeslinked": "รายการปรับปรุงล่าสุดในหน้าที่ลิงก์จากหน้านี้",
"tooltip-feed-rss": "ฟีดชนิดอาร์เอสเอส (RSS) ของหน้านี้",
"tooltip-feed-atom": "ฟีดอะตอม (Atom) ของหน้านี้",
- "tooltip-t-contributions": "รายการเรื่องที่ผู้ใช้นี้เขียน",
+ "tooltip-t-contributions": "รายการเรื่องที่{{GENDER:$1|ผู้ใช้นี้}}เขียน",
"tooltip-t-emailuser": "ส่งอีเมลถึงผู้ใช้นี้",
"tooltip-t-info": "สารสนเทศเพิ่มเติมเกี่ยวกับหน้านี้",
"tooltip-t-upload": "อัปโหลดไฟล์",
"noname": "Dogry bir ulanyjy adyny görkezmediňiz.",
"loginsuccesstitle": "Hasaba girdiňiz",
"loginsuccess": "'''{{SITENAME}} saýtynda \"$1\" ulanyjy ady bilen hasaba girdiňiz.'''",
- "nosuchuser": "\"$1\" diýen at bilen ulanyjy ýok.\nUlanyjy atlary baş hem-de setir harplara duýgurdyr.\nÝazylyşyny barlaň ýa-da [[Special:UserLogin/signup|täze hasap açyň]].",
+ "nosuchuser": "\"$1\" diýen at bilen ulanyjy ýok.\nUlanyjy atlary baş hem-de setir harplara duýgurdyr.\nÝazylyşyny barlaň ýa-da [[Special:CreateAccount|täze hasap açyň]].",
"nosuchusershort": "\"$1\" dýen at bilen ulanyjy ýok. Ýazylyşyny barlaň.",
"nouserspecified": "Ulanyjy adyny görkezmegiňiz hökmanydyr.",
"login-userblocked": "Bu ulanyjy blokirlenipdir. Sessiýa açmaga rugsat berilmeýär.",
"accmailtext": "[[User talk:$1|$1]] üçin ugralla döredilen parol $2 adresine iberildi.\n\nBu paroly sessiýa açanyňyzdan soňra ''[[Special:ChangePassword|paroly üýtget]]'' sahypasynda üýtgedip bilersiňiz.",
"newarticle": "(Täze)",
"newarticletext": "Häzirlikçe ýazylmadyk bir sahypa goýlan çykgyda tykladyňyz. Bu sahypany döretmek üçin aşakdaky tekst gutusyndan peýdalanyň. Maglumat üçin [$1 ýardam sahypasyna] serediň. Bu ýere ýalňyşlyk bilen gelen bolsaňyz, programmanyň '''Yza''' düwmesine tyklaň.",
- "anontalkpagetext": "----''Bu sahypa heniz ulanyjy hasaby edinmedik ýa-da hasabyny ulanmaýan bir anonim ulanyjynyň pikir alyşma sahypasydyr.\nŞonuň üçinem biz ony görkezmek üçin sanlaýyn IP adresini ulanmaly bolýarys.\nŞunuň ýaly IP adresinden ençeme ulanyjy peýdalanýan bolmagy ahmal.\nEger-de sizem anonim ulanyjy bolsaňyz we size siziň bilen dahyly ýok habarlaşyklar gelýän bolsa, onda mundan beýläk başga anonim ulanyjylar bilen garjaşmazlygyňyz üçin [[Special:UserLogin/signup|özüňize hasap ediniň]] ýa-da [[Special:UserLogin|sessiýa açyň]].''",
+ "anontalkpagetext": "----''Bu sahypa heniz ulanyjy hasaby edinmedik ýa-da hasabyny ulanmaýan bir anonim ulanyjynyň pikir alyşma sahypasydyr.\nŞonuň üçinem biz ony görkezmek üçin sanlaýyn IP adresini ulanmaly bolýarys.\nŞunuň ýaly IP adresinden ençeme ulanyjy peýdalanýan bolmagy ahmal.\nEger-de sizem anonim ulanyjy bolsaňyz we size siziň bilen dahyly ýok habarlaşyklar gelýän bolsa, onda mundan beýläk başga anonim ulanyjylar bilen garjaşmazlygyňyz üçin [[Special:CreateAccount|özüňize hasap ediniň]] ýa-da [[Special:UserLogin|sessiýa açyň]].''",
"noarticletext": "Bu sahypa şu wagt boş dur.\nBu ady başga sahypalarda [[Special:Search/{{PAGENAME}}|gözläp bilersiňiz]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} degişli gündeliklerde gözleg geçirip bilersiňiz],\nýa-da bu sahypany [{{fullurl:{{FULLPAGENAME}}|action=edit}} üýtgedip bilersiňiz]</span>.",
"noarticletext-nopermission": "Häzirki wagtda bu sahypada tekst ýok.\nBu sahypa adyny [[Special:Search/{{PAGENAME}}|başga sahypalarda gözläp]]\nýa-da <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} degişli gündeliklerde gözleg geçirip bilersiňiz]</span>, ýöne bu sahypany döretmäge rugsadyňyz ýok.",
"userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" ulanyjy hasaby hasaba alynmandyr.\nBu sahypany döretmek/redaktirlemek isleýän bolsaňyz, onda esewan boluň.",
"noname": "Hindi mo tinukoy ang isang tanggap na pangalan ng tagagamit.",
"loginsuccesstitle": "Matagumpay ang paglagda",
"loginsuccess": "'''Nakalagda ka na sa {{SITENAME}} bilang si \"$1\".'''",
- "nosuchuser": "Walang tagagamit na may pangalang \"$1\".\nMaselan sa pagtitipa ang mga pangalan ng tagagamit.\nSuriin ang iyong pagbabaybay, o [[Special:UserLogin/signup|lumikha ng bagong account]].",
+ "nosuchuser": "Walang tagagamit na may pangalang \"$1\".\nMaselan sa pagtitipa ang mga pangalan ng tagagamit.\nSuriin ang iyong pagbabaybay, o [[Special:CreateAccount|lumikha ng bagong account]].",
"nosuchusershort": "Walang tagagamit na may pangalang \"$1\".\nPakitingnan ang iyong pagbabaybay.",
"nouserspecified": "Kailangang tukuyin mo ang isang pangalang pantagagamit.",
"login-userblocked": "Hinarang ang tagagamit na ito. Hindi pinahihintulutan ang paglalagda.",
"accmailtext": "Ipinadala na sa $2 ang isang password na nilikha ng pagkakataon para kay [[User talk:$1|$1]]. Maaari itong baguhin sa pahinang ''[[Special:ChangePassword|palitan ang password]]'' kapag nag-login.",
"newarticle": "(Bago)",
"newarticletext": "Sinundan mo ang isang kawing para sa isang pahinang hindi pa umiiral.\nPara likhain ang pahina, magsimulang magmakinilya sa loob ng kahong nasa ibaba (tingnan ang [$1 pahina ng tulong] para sa mas maraming kabatiran).\nKung napunta ka rito dahil sa pagkakamali, pakipindot ang pinduntang '''balik''' ('''''back''''') ng iyong pantingin-tingin (''browser'').",
- "anontalkpagetext": "Ito ang pahinang usapan para sa isang hindi nakikilalang tagagamit na hindi pa lumilikha ng account, o kaya hindi ito ginagamit.\nKaya't kinailangan naming gamitin ang may bilang na IP address para makilala siya.\nMaaaring pagsaluhan ng ilang mga tagagamit ang ganiyang IP address.\nKung isa kang hindi nagpapakilalang tagagamit at nakadaramang may mga walang saysay na komentong patungkol sa iyo, [[Special:UserLogin/signup|pakilikha ng isang account]] o [[Special:UserLogin|lumagda]] para maiwasan ang kalituhan o mapagkamalan ka bilang ibang hindi nakikilalang mga tagagamit sa hinaharap.",
+ "anontalkpagetext": "Ito ang pahinang usapan para sa isang hindi nakikilalang tagagamit na hindi pa lumilikha ng account, o kaya hindi ito ginagamit.\nKaya't kinailangan naming gamitin ang may bilang na IP address para makilala siya.\nMaaaring pagsaluhan ng ilang mga tagagamit ang ganiyang IP address.\nKung isa kang hindi nagpapakilalang tagagamit at nakadaramang may mga walang saysay na komentong patungkol sa iyo, [[Special:CreateAccount|pakilikha ng isang account]] o [[Special:UserLogin|lumagda]] para maiwasan ang kalituhan o mapagkamalan ka bilang ibang hindi nakikilalang mga tagagamit sa hinaharap.",
"noarticletext": "Kasalukuyang walang teksto sa loob ng pahinang ito.\nMaaari mong [[Special:Search/{{PAGENAME}}|hanapin ang pamagat ng pahinang ito]] sa loob iba pang mga pahina,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} maghanap sa kaugnay na mga talaan],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} baguhin ang pahinang ito]</span>.",
"noarticletext-nopermission": "Kasalukuyang walang teksto sa pahinang ito.\nMaaari mong [[Special:Search/{{PAGENAME}}|hanapin ang pamagat ng pahinang ito]] sa ibang mga pahina,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} maghanap sa kaugnay na mga talaan]</span>.",
"missing-revision": "Hindi umiiral ang rebisyong #$1 ng pahinang napangalanang \"{{FULLPAGENAME}}\".\n\nKaraniwang itong dulot ng pagsunod sa isang wala na sa panahong kawing ng kasaysayan na papunta sa isang pahinang nabura na.\nMatatagpuan ang mga detalye sa loob ng [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} talaan ng pagbura].",
"actions": "Һәрәкәтон",
"namespaces": "Номон мәконон",
"variants": "Вариантон",
+ "navigation-heading": "Naviqasiyə menü",
"errorpagetitle": "Сәһв",
"returnto": "Бә сәһифә огәрдеј $1.",
"tagline": "Материал че {{SITENAME}}",
"unprotectthispage": "Ын сәһифә мыдофијә дәгиш кардеј",
"newpage": "Тожә сәһифә",
"talkpage": "Ым сәһифә мызокирә кардеј",
- "talkpagelinktext": "Mızokirə",
+ "talkpagelinktext": "Müzakirə",
"specialpage": "Хысусијә сәһифә",
"personaltools": "Шәхси диләгон",
"articlepage": "Мәғолә дијә кардеј",
"talk": "Mızokirə",
"views": "Тәмшо кардеј",
- "toolbox": "Диләгон",
+ "toolbox": "Diləqon",
"userpage": "Иштирокәкә сәһифә дијә кардеј",
"projectpage": "Нәхши сәһифә дијә кардеј",
"imagepage": "Фајли сәһифә дијә кардеј",
"copyrightpage": "{{ns:project}}:Мыәллифә һуғуғ",
"currentevents": "Есәтнә һодисон",
"currentevents-url": "Project: Есәтнә һодисон",
- "disclaimers": "Çe məsuliyyətiku imtino.",
+ "disclaimers": "Çı məsuliyyətiku imtina",
"disclaimerpage": "Project:Дејни бә гиј ныгәтеј",
"edithelp": "Арајиш бо редактә кардеј",
- "mainpage": "Əsosə səhifə",
+ "mainpage": "Sərlohə",
"mainpage-description": "Әсосә сәһифә",
"policy-url": "Project:Ғајдон",
"portal": "Ҹәмјәт",
"nstab-image": "Фајл",
"nstab-template": "Ғәлиб",
"nstab-category": "Тиспир",
+ "mainpage-nstab": "Sərlohə",
"error": "Сәһв",
"readonly": "Бә база нывыште блок быә.",
"missing-article": "База мәлумотон дыләдә бә ахтар кардә быә саһифон «$1» $2 барәдә мәлумот пәјдо карде ныбе.\nЖыго вәзијјәт бе бәзне бә вахтики, ым сәһифә че рәдд кардә быә сәһифә канә рәвојәте.\nГирәм ым жыго ни, жәгәдә шымә програм тәминатијәдә сәһв пәјдо кардәјоне.\nХаһиш кардәмон че сәһифә URL-и бә [[Special:ListUsers/sysop|администратори]] бывғандәнән.",
"createaccountreason": "Сәбәб:",
"mailmypassword": "Нујә парол вығандеј бә Е-номә.",
"loginlanguagelabel": "Зывон: $1",
+ "pt-login": "Dəşi",
+ "pt-createaccount": "Qeydiyyat",
"changepassword": "Пароли дәгиш кардеј",
"resetpass_header": "Иштирокәкә пароли дәгиш карде",
"oldpassword": "Канә парол:",
"preview": "Сыфтәнә нишо дој",
"showpreview": "Сыфтәнә нишо дој",
"showdiff": "Дәғандә быә дәгишон",
- "anoneditwarning": "'''Дығғәт.''' Шымә ыштәни едәштәнијоне системәдә.\nШымә IP-унвон бә ым сәһифә дәгишон тарых ғејд бәбе.",
+ "anoneditwarning": "<strong>Diqqət:</strong> Şımə bə sistem dəşənin. Berdəm şımə qıli sərost bıkon çı şımə lP-ünvani harkəs bəvinde. Berdəm <strong>[$1 daxil bıbu]</strong> jaanki <strong>[$2 hesob okə]</strong>, \nşımə sərostəti bə şımə nom nıvışte bəbe, imən bə şımə co üstünlükon bədoe",
"loginreqlink": "ыштәни едаштеј",
"newarticle": "(Нујә)",
"newarticletext": "Шымә давардијон де сәбони бә сәһифә, әмма жыго сәһифә ни.\nБо сәһифә офәјеј мәтн бынывыштән жиннә пенҹәдә (мыффәссәл дијә быкән [$1 араијшә сәһифә]).\nГирәм шымә ијо де сәһви бешијон, һиччекәни ыштә браузери \"думо\" егәтән.",
- "noarticletext": "Есәт бы сәһифәдә мәтн ни.\nШымә бәзынешон [[Special:Search/{{PAGENAME}}|пәјдо кардеј конҹо ым ном һесте]] бә ҹо мәғолонәдә,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} журналон ујғунә нывыштәјон пәјдо кардеј],\nјаанки '''[{{fullurl:{{FULLPAGENAME}}|action=edit}}де жыго номи сәһифә офәјеј ]'''</span>.",
+ "noarticletext": "Isə bı səhəfədə mətn ni.\nŞımə bəzneyon [[Special:Search/{{PAGENAME}}|peydo kardey konco im nom hıste] bə co səhəfədə,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} bə jurnalon uyğunə nıvıştəyon pedo kardey],\nor [{{fullurl:{{FULLPAGENAME}}|action=edit}} create this page]</span>.",
"noarticletext-nopermission": "Есәт бы сәһифәдә мәтн ни. \nШымә бәзынејон [[Special:Search/{{PAGENAME}}|пәјдо кардеј конҹо ым ном һесте]] бә ҹо мәғолонәдә,\nјаанки <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} журналон ујғунә нывыштәјон пәјдо кардеј].</span>, интаси шымәку изн ни ым сәһифә офәје.",
"previewnote": "'''Јодәдә огәтән ки ым һәлә сыфтәнә нишо доје.'''\nШымә дәгишон һәлә огәтә быәнин!",
"editing": "Редәктә кардеј $1",
"viewpagelogs": "Бо ым сәһифә журналон нишо дој",
"currentrev-asof": "Есәтнә рәвојәт бә $1",
"revisionasof": "Рәвојәт $1",
- "revision-info": "Рәвојәти мәлумот: $1; $2",
+ "revision-info": "Çı $7 $1 tarixədə kardə sərostəti",
"previousrevision": "← Навынәни",
"nextrevision": "Думотоно шә →",
"currentrevisionlink": "Есәтнә рәвојәт",
"shown-title": "Нишо дој $1 {{PLURAL:$1|нывыштәј|нывыштәјон}} сәһифәдә",
"viewprevnext": "Дијә кардеј ($1 {{int:pipe-separator}} $2) ($3)",
"searchmenu-exists": "'''Бы вики-нәхшәдә һесте сәһифә «[[:$1]]»'''",
- "searchmenu-new": "'''Сәһифә офәјеј «[[:$1]]» бә ым вики-нахшәдә!'''",
+ "searchmenu-new": "<strong> im vikiədə \"[[:$1]]\" səhifə okəy!</strong> {{PLURAL:$2|0=|Həmçinin bə nəve nəticədə peydo bıə səhifon dekə.| Bə nəve nəticədə peydo bıə nəticon dekə.}}",
"searchprofile-articles": "Әсосә сәһифон",
"searchprofile-images": "Мултимедијә",
"searchprofile-everything": "Һар вырәдә",
"rclistfrom": "$3 $2 вахтику дәгишон нишо быдә",
"rcshowhideminor": "$1 гәдәлијә дәгишон",
"rcshowhidebots": "$1 ботон",
- "rcshowhideliu": "$1 ыштәни едаштә иштирокәкон",
+ "rcshowhideliu": "$1 qeyd bıə iştirakəkon",
"rcshowhideanons": "$1 әнәномә иштирокәкон",
"rcshowhidepatr": "$1 осә кардә быә дәгишон",
"rcshowhidemine": "$1 ыштә дәгишон",
"filedelete-comment": "Сәбәб:",
"filedelete-submit": "Рәдд кардеј",
"randompage": "Рајрастә мәғолә",
+ "randomincategory-submit": "Давард",
"statistics": "Статистика",
"nbytes": "$1 {{PLURAL:$1|бајт|бајтон}}",
"nmembers": "$1 {{PLURAL:$1|узв|узвон}}",
"whatlinkshere-prev": "{{PLURAL:$1|навынәни|навынәни $1}}",
"whatlinkshere-next": "{{PLURAL:$1|думотоно шә|думотоно шә $1}}",
"whatlinkshere-links": "← сәбонон",
- "whatlinkshere-hideredirs": "$1 бә тожә унвон вығандеј",
- "whatlinkshere-hidetrans": "$1 әловон",
- "whatlinkshere-hidelinks": "$1 сәбонон",
+ "whatlinkshere-hideredirs": "$1 bə tojə ünvan vığande",
+ "whatlinkshere-hidetrans": "$1 əlavon",
+ "whatlinkshere-hidelinks": "$1 səbonon",
"whatlinkshere-hideimages": "$1 фајлинә сәбонон",
"whatlinkshere-filters": "Филтрон",
"ipbreason": "Сәбәб:",
"allmessages-filter-submit": "Давард",
"thumbnail-more": "Һејве кардеј",
"thumbnail_error": "Гәдә шикили туму кардејәдә сәһв: $1",
- "tooltip-pt-userpage": "ШÑ\8bмÓ\99 иÑ\88Ñ\82иÑ\80окÓ\99кÓ\99 Ñ\81Ó\99һиÑ\84Ó\99",
- "tooltip-pt-mytalk": "ШÑ\8bмÓ\99 мÑ\8bзокиÑ\80он Ñ\81Ó\99һиÑ\84Ó\99",
- "tooltip-pt-preferences": "Шымә кукон",
+ "tooltip-pt-userpage": "Å\9eımÉ\99 sÉ\99hifÉ\99",
+ "tooltip-pt-mytalk": "Å\9eımÉ\99 müzakirÉ\99 sÉ\99hifÉ\99",
+ "tooltip-pt-preferences": "Şımə nizamon",
"tooltip-pt-watchlist": "Сәһифон сијоһи, конҹо шымә де дығғәти дијә кардејдәјон бә дәгишон",
- "tooltip-pt-mycontris": "Шымә гәнҹон сијоһи",
+ "tooltip-pt-mycontris": "Şımə səroston siyahi",
"tooltip-pt-login": "Ијо бәбе ыштәни ғејд кардовнијеј системәдә, интаси ым һукман ни",
"tooltip-pt-logout": "Системәдә кој орохнијеј",
+ "tooltip-pt-createaccount": "Təklif kardəmon, boştə tojə səhifə okənən və bə sistem dıştə nomi dəşənən, hərçənd ım mütləq ni",
"tooltip-ca-talk": "Сәһифә мығдори бәрәдә мызокирә",
- "tooltip-ca-edit": "Ым сәһифә бәбе дагиш кардеј. Быһамијән, огәтеј бә нав, \"сыфтәнә нишо дој\" истифодә быкән",
+ "tooltip-ca-edit": "İm səhifə sərost karde",
"tooltip-ca-addsection": "Нујә ғысм офәјеј",
"tooltip-ca-viewsource": "Ым сәһифә мыдофијә быә дагиш кардеку, әммә шымә бәзынешон дијә кардеј ијән сурәт бекардеј әчәј бешемонә мәтни",
"tooltip-ca-history": "Сәһифә дәгишон журнал",
"tooltip-t-whatlinkshere": "Бә ым сәһифә сәбон вардә һәммәј вики сәһифон сијоһи",
"tooltip-t-recentchangeslinked": "Охонә дәгишон сәһифонәдә, бә ком сәһифон сәбон вардә ым сәһифә",
"tooltip-feed-atom": "Транслјасијә кардеј бә Atom бо ым сәһифә",
- "tooltip-t-contributions": "Че иштирок кардәкәси дагиш кардә быә сәһифон сијоһи",
+ "tooltip-t-contributions": "Çı iştirak kardəkəsi dəgiş kardə səhifon siyohi",
"tooltip-t-emailuser": "Бы иштироәкә номә вығәнде",
"tooltip-t-upload": "Шикилон јаанки мултимедијә фајлон бо жај",
"tooltip-t-specialpages": "Xıdmətə səhifon siyohi",
"tooltip-ca-nstab-main": "Мәғолә мығдор",
"tooltip-ca-nstab-user": "Иштирок кардәкәси сәһифә",
"tooltip-ca-nstab-media": "Медиа-фајл",
- "tooltip-ca-nstab-special": "Ым хыдмәтә сәһифәје бычыми горә дәгиш кардеј әбыни",
+ "tooltip-ca-nstab-special": "İm xidmətə səhifəye bəçi qorşo sərost karde əbıni",
"tooltip-ca-nstab-project": "Нәхши сәһифә",
"tooltip-ca-nstab-image": "Фајли сәһифә",
"tooltip-ca-nstab-template": "Ғәлиби сәһифә",
"tooltip-summary": "Кыртә тәсвир бынывыштән",
"pageinfo-header-edits": "Дәгиш кардә быә чијон тарых",
"pageinfo-redirects-value": "$1",
+ "pageinfo-toolboxlink": "Səhifə həxədə məlumaton",
"previousdiff": "← Навынәни дәгиши",
"nextdiff": "Думотоно шә дәгиши →",
"file-info-size": "$1 × $2 пиксел, фајли памјә: $3, MIME тип: $4",
"file-nohires": "Ән барзә рәвојәт ни.",
"svg-long-desc": "SVG фајл, номинәләдә $1 × $2 пиксел, фајли памјә: $3",
- "show-big-image": "Тикәјән јолә кејфијјәтинә шикил",
+ "show-big-image": "Çı fayli əsl",
+ "show-big-image-size": "$1 × $2 piksel",
"ilsubmit": "Нәве",
"bad_image_list": "Формат бәпе быбу жыго:\n\nБә һисоб сә быәбен әнҹәх сијоһи әсосон (де * рәмзи бино быә сәтырон).\nСәтыри иминә сәбон бәпе быбу сәбон бә ғәдәғән кардә быә бо дәғанде шикили.\nПешонә сәбонон бә һамонә сәтырәдә бәнә истино дијә кардә бәбен, јәни мәғолон, бә коврә шикил дахыл карде бәзне бе.",
"metadata": "Метамәлумотон",
"specialpages": "Хысусијә сәһифон",
"external_image_whitelist": " #Ым сәтри огәтәнән чокнәј әв һесте<pre>\n#Рә рә истифадә быә фрагментон ијо быдәнән (ә һиссә, че // мијонәдә бедә )\n#Әвон ды харичи шикили URL и дуз бәбен.\n#Дуз омә гылә бәнә шикили нишо бәбе, амандәни бәнә шикили линк нишо бәбе.\n#Сәтрон де # комментариј һисоб бедән.\n#Сәтрон бә регистри һәссос нин.\n\n#Рә рә око доә быә фрагментон че сәтри пентоно ијо быдәнән. Ым сәтри огәтәнән чокнәј һесте.</pre>",
"tag-filter": "[[Special:Tags|нышонон]] филтр:",
- "tags-title": "Нышонон"
+ "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Nişon|Nişonon}}]]: $2)",
+ "tags-title": "Нышонон",
+ "logentry-newusers-create": "$1 istifadəmon hesob okarde be",
+ "searchsuggest-search": "Nəve"
}
"noname": "Naʻe ʻikai te ke ʻoatu hao hingoa ʻetita ʻoku totonu.",
"loginsuccesstitle": "Kuo ola ʻa e kau-ki-ai",
"loginsuccess": "'''ʻOku ke kau-ki-ai he taimí ni ki he {{SITENAME}} hangē \"$1\".'''",
- "nosuchuser": "ʻOku ʻikai ʻi ai ha ʻetita mo hono hingoa \"$1\". Sivi hoʻo sipela pe [[Special:UserLogin/signup|fakatupu haʻo kau-ki-ai foʻou]].",
+ "nosuchuser": "ʻOku ʻikai ʻi ai ha ʻetita mo hono hingoa \"$1\". Sivi hoʻo sipela pe [[Special:CreateAccount|fakatupu haʻo kau-ki-ai foʻou]].",
"nosuchusershort": "ʻOku ʻikai ʻi ai ha ʻetita mo hono hingoa \"$1\". Sivi hoʻo sipela.",
"nouserspecified": "ʻOku pau te ke ʻoatu ha hingoa ʻo e ʻetita.",
"wrongpassword": "ʻOku ʻikai totonu ʻa e leatapu, kātaki ʻe toki feinga.",
"HakanIST",
"Imabadplayer",
"İnternion",
- "Hbseren"
+ "Hbseren",
+ "Kumkumuk"
]
},
"tog-underline": "Bağlantıların altını çiz:",
"noname": "Geçerli bir kullanıcı adı girmediniz.",
"loginsuccesstitle": "Oturum açıldı",
"loginsuccess": "'''{{SITENAME}} üzerinde \"$1\" kullanıcı adıyla oturum açtınız.'''",
- "nosuchuser": "\"$1\" adında bir kullanıcı bulunmamaktadır.\nKullanıcı adları büyük-küçük harf duyarlıdır.\nYazılışı kontrol edin veya [[Special:UserLogin/signup|yeni bir hesap açın]].",
+ "nosuchuser": "\"$1\" adında bir kullanıcı bulunmamaktadır.\nKullanıcı adları büyük-küçük harf duyarlıdır.\nYazılışı kontrol edin veya [[Special:CreateAccount|yeni bir hesap açın]].",
"nosuchusershort": "\"$1\" adında bir kullanıcı bulunmamaktadır. Yazılışı kontrol edin.",
"nouserspecified": "Bir kullanıcı adı belirtmek zorundasınız.",
"login-userblocked": "Bu kullanıcı engellenmiş. Giriş yapmaya izin verilmiyor.",
"accmailtext": "[[User talk:$1|$1]] için rastgele oluşturulan parola $2 adresine gönderildi.\n\nBu yeni hesap için parola, giriş yapıldıktan sonra ''[[Special:ChangePassword|parolayı değiştir]]'' bölümünde değiştirilebilir.",
"newarticle": "(Yeni)",
"newarticletext": "Henüz varolmayan bir sayfaya konulmuş bir bağlantıya tıkladınız.\nSayfayı oluşturmak için aşağıdaki metin kutusunu kullanın. ([$1 yardım sayfasına] bakınız).\nBuraya yanlışlıkla geldiyseniz tarayıcınızın <strong>geri </strong> tuşuna tıklayın.",
- "anontalkpagetext": "----''Bu sayfa henüz bir kullanıcı hesabı oluşturmamış veya hesabını kullanmayan bir anonim kullanıcının mesaj sayfasıdır. Bu nedenle bu kişiyi belirtmek için rakamsal IP adresini kullanmak zorundayız. Bu gibi IP adresleri birçok kullanıcı tarafından paylaşılabilir. Eğer siz de bir anonim kullanıcıysanız ve size sizin ilginiz olmayan iletiler geliyorsa, lütfen diğer anonim kullanıcılarla olabilecek olan karmaşayı önlemek için [[Special:UserLogin/signup|bir hesap edinin]] veya [[Special:UserLogin|oturum açın]].''",
+ "anontalkpagetext": "----''Bu sayfa henüz bir kullanıcı hesabı oluşturmamış veya hesabını kullanmayan bir anonim kullanıcının mesaj sayfasıdır. Bu nedenle bu kişiyi belirtmek için rakamsal IP adresini kullanmak zorundayız. Bu gibi IP adresleri birçok kullanıcı tarafından paylaşılabilir. Eğer siz de bir anonim kullanıcıysanız ve size sizin ilginiz olmayan iletiler geliyorsa, lütfen diğer anonim kullanıcılarla olabilecek olan karmaşayı önlemek için [[Special:CreateAccount|bir hesap edinin]] veya [[Special:UserLogin|oturum açın]].''",
"noarticletext": "Bu sayfa şu anda boştur.\nBu başlığı [[Special:Search/{{PAGENAME}}|diğer sayfalarda arayabilir]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ilgili kayıtları arayabilir],\nya da bu sayfayı [{{fullurl:{{FULLPAGENAME}}|action=edit}} oluşturabilirsiniz]</span>.",
"noarticletext-nopermission": "Bu sayfa şu anda boştur. \nBu başlığı [[Special:Search/{{PAGENAME}}|diğer sayfalarda arayabilir]] ya da <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ilgili kayıtları tarayabilirsiniz]</span>, fakat sayfayı oluşturma yetkiniz bulunmamaktadır.",
"missing-revision": "\"{{FULLPAGENAME}}\" sayfasının #$1 sürümü yok.\n\nBu duruma genellikle silinmiş bir sayfaya eski tarihli bir bağlantının takip edilmesi neden olur.\n\nDaha fazla detaylı bilgi [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} sayfasında bulunabilir].",
"rcshowhidemine-show": "göster",
"rcshowhidemine-hide": "gizle",
"rcshowhidecategorization": "sayfa kategorizasyonunu $1",
- "rcshowhidecategorization-show": "Göster",
- "rcshowhidecategorization-hide": "Gizle",
+ "rcshowhidecategorization-show": "göster",
+ "rcshowhidecategorization-hide": "gizle",
"rclinks": "Son $2 günde yapılan son $1 değişikliği göster;<br /> $3",
"diff": "fark",
"hist": "geçmiş",
"tog-watchdefault": "Мин үзгәрткән битләр һәм файллар күзәтү исемлегемә өстәлсен",
"tog-watchmoves": "Мин күчергән битләр һәм файллар күзәтү исемлегемә өстәлсен",
"tog-watchdeletion": "Мин бетергән битләр һәм файлларны күзәтү исемлегемгә өстәлсен",
+ "tog-watchuploads": "Минем тарафтан йөкләнелгән файлларны күзәтү исемлегемә кертергә",
"tog-minordefault": "Барлык үзгәртүләрне килешү буенча кече дип билгеләнсен",
"tog-previewontop": "Үзгәртү тәрәзәсеннән өстәрәк битне алдан карау өлкәсен күрсәтелсен",
"tog-previewonfirst": "Үзгәртү битенә күчкәндә башта алдан карау бите күрсәтелсен",
"tog-watchlisthidebots": "Бот үзгәртүләре күзәтү исемлегеннән яшерелсен",
"tog-watchlisthideminor": "Кече үзгәртүләр күзәтү исемлегеннән яшерелсен",
"tog-watchlisthideliu": "Авторизацияне узган кулланучыларның үзгәртүләре күзәтү исемлегеннән яшерелсен",
+ "tog-watchlistreloadautomatically": "Фильтр алмашкан очракта күзәтү исемлеген автоматик рәвештә яңартырга (JavaScript кирәк)",
"tog-watchlisthideanons": "Аноним кулланучыларның үзгәртүләре күзәтү исемлегеннән яшерелсен",
"tog-watchlisthidepatrolled": "Тикшерелгән үзгәртүләр күзәтү исемлегеннән яшерелсен",
"tog-watchlisthidecategorization": "Битләрне төркемләшүне ябу",
"noname": "Сез кулланучы исемегезне күрсәтергә тиешсез.",
"loginsuccesstitle": "Керү уңышлы үтте",
"loginsuccess": "'''Сез {{SITENAME}} проектына $1 исеме белән кердегез.'''",
- "nosuchuser": "$1 иÑ\81емле кÑ\83лланÑ\83Ñ\87Ñ\8b Ñ\8eк.\nÐ\9aÑ\83лланÑ\83Ñ\87Ñ\8b иÑ\81еменең дөÑ\80еÑ\81леге Ñ\80егиÑ\81Ñ\82Ñ\80га бÓ\99йле.\nЯзÑ\8bлÑ\8bÑ\88Ñ\8bгÑ\8bзнÑ\8b Ñ\82икÑ\88еÑ\80егез Ñ\8fки [[Special:UserLogin/signup|яңа хисап язмасы төзегез]].",
+ "nosuchuser": "$1 иÑ\81емле кÑ\83лланÑ\83Ñ\87Ñ\8b Ñ\8eк.\nÐ\9aÑ\83лланÑ\83Ñ\87Ñ\8b иÑ\81еменең дөÑ\80еÑ\81леге Ñ\85Ó\99Ñ\80еÑ\84лÓ\99Ñ\80нең Ñ\80егиÑ\81Ñ\82Ñ\80Ñ\8bна бÓ\99йле.\nЯзÑ\8bлÑ\8bÑ\88Ñ\8bгÑ\8bзнÑ\8b Ñ\82икÑ\88еÑ\80егез Ñ\8fки [[Special:CreateAccount|яңа хисап язмасы төзегез]].",
"nosuchusershort": "$1 исемле кулланучы юк. Язылышыгызны тикшерегез.",
"nouserspecified": "Сез теркәү исмегезне күрсәтергә тиешсез.",
"login-userblocked": "Бу кулланучы тыелды. Керү тыелган.",
"accmailtext": "[[User talk:$1|$1]] кулланучысы өчен төзелгән серсүз $2 адресына җибәрелде.\n\nАвторизация узгач, үз хисап язмагызда сез ''[[Special:ChangePassword|серсүзегезне үзгәртә аласыз]]''.",
"newarticle": "(Яңа)",
"newarticletext": "Сез әлегә язылмаган биткә кердегез.\nЯңа бит ясау өчен астагы тәрәзәдә мәкалә текстын җыегыз ([$1 ярдәм битен] карый аласыз).\nӘгәр сез бу биткә ялгышлык белән эләккән булсагыз, браузерыгызның '''артка''' төймәсенә басыгыз.",
- "anontalkpagetext": "----''Бу бәхәс бите системада теркәлмәгән яисә үз исеме белән кермәгән кулланучыныкы.\nАны тану өчен IP адресы файдаланыла.\nӘгәр сез аноним кулланучы һәм сезгә юлланмаган хәбәрләр алдым дип саныйсыз икән (бер IP адресы күп кулланучы өчен булырга мөмкин), башка мондый аңлашылмаучанлыклар килеп чыкмасын өчен [[Special:UserLogin|системага керегез]] яисә [[Special:UserLogin/signup|теркәлегез]].''",
+ "anontalkpagetext": "----\n<em>Бу бәхәс бите системада теркәлмәгән яисә үз исеме белән кермәгән кулланучыныкы.</em>\nАны тану өчен без санлы IP адресын файдаланырга мәҗбүрбез.\nӘлеге адрес башка аноним кулланучылар тарафыннан да кулланылырга мөмкин.\nӘгәр сез аноним кулланучы һәм сезгә юлланмаган хәбәрләр алдым дип саныйсыз икән (бер IP адресы күп кулланучы өчен булырга мөмкин), башка мондый аңлашылмаучанлыклар килеп чыкмасын өчен [[Special:UserLogin|системага керегез]] яисә [[Special:CreateAccount|теркәлегез]].",
"noarticletext": "Хәзерге вакытта бу биттә текст юк.\nСез [[Special:Search/{{PAGENAME}}|бу исем кергән башка мәкаләләрне]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} көндәлекләрдәге язмаларны] таба\nяки '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} шушындый исемле яңа бит төзи]'''</span> аласыз.",
"noarticletext-nopermission": "Хәзерге вакытта бу биттә текст юк.\nСез [[Special:Search/{{PAGENAME}}|бу исем кергән башка мәкаләләрне]] башка битләрдә,\nяисә <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} көндәлекләрдәге язмаларны] таба аласыз.</span> Сезнең бу битне ясарга хакыгыз юк.",
"userpage-userdoesnotexist": "«<nowiki>$1</nowiki>» исемле хисап язмасы юк. Сез чынлап та бу битне ясарга яисә үзгәртергә телисезме?",
"userpage-userdoesnotexist-view": "\"$1\" исемле хисап язмасы юк.",
"blocked-notice-logextract": "Бу кулланучы хәзергә тыелды.\nТүбәндә тыю көндәлегенең соңгы язу бирелгән:",
- "clearyourcache": "<strong>Искәрмә:</strong> Сез саклаган үзгәртүләр кулланышка керсен өчен браузерыгызның кешын чистартырга туры киләчәк. \n* <strong>Firefox/Safari:</strong> Shift төймшсенә баскан килеш җиһазлар тасмасында <em>Яңарту (Обновить)</em> язуына басыгыз, яисә <em>Ctrl-F5</em> яки ''Ctrl-R</em> (Mac өчен <em>⌘-R</em>) төймәләренә басыгыз\n* <strong>Google Chrome:</strong> <em>Ctrl-Shift-R</em> (Mac өчен <em>⌘-Shift-R</em> ) төймәләренә басыгыз\n* <strong>Internet Explorer:</strong> <em>Ctrl</em> төймәсенә баскан килеш <em>Яңарту (Обновить)</em> язуына, яисә <em>Ctrl-F5</em> басыгыз\n* <strong>Opera:</strong> Менюдан кеш чистартуны сайлагыз: <em>Кораллар (Инструменты) → Көйләнмәләр (Настройки)</em>",
+ "clearyourcache": "<strong>Искәрмә:</strong> Сез саклаган үзгәртүләр кулланышка керсен өчен браузерыгызның кешын чистартырга туры киләчәк. \n* <strong>Firefox/Safari:</strong> Shift төймшсенә баскан килеш җиһазлар тасмасында <em>Яңарту (Обновить)</em> язуына басыгыз, яисә <em>Ctrl-F5</em> яки ''Ctrl-R</em> (Mac өчен <em>⌘-R</em>) төймәләренә басыгыз\n* <strong>Google Chrome:</strong> <em>Ctrl-Shift-R</em> (Mac өчен <em>⌘-Shift-R</em> ) төймәләренә басыгыз\n* <strong>Internet Explorer:</strong> <em>Ctrl</em> төймәсенә баскан килеш <em>Яңарту (Обновить)</em> язуына, яисә <em>Ctrl-F5</em> басыгыз\n* <strong>Opera:</strong> <em>Menu → Көйләнмәләр</em> (<em>Opera → Көйләнмәләр</em> на Mac) бүлегенә күчегез, аннан <em>Куркынычсызлык → Керүләр тарыхын чистарту → Рәсемнәр кэшлау</em>",
"usercssyoucanpreview": "'''Ярдәм:''' \"{{int:showpreview}} төймәсенә басып, яңа CSS-файлны тикшереп була.",
"userjsyoucanpreview": "'''Ярдәм:''' \"{{int:showpreview}}\" төймәсенә басып, яңа JS-файлны тикшереп була.",
"usercsspreview": "'''Бу бары тик CSS-файлны алдан карау гына, ул әле сакланмаган!'''",
"recentchangesdays-max": "(иң күбе $1 {{PLURAL:$1|көн}})",
"recentchangescount": "Төп буларак кулланучы үзгәртүләр саны:",
"prefs-help-recentchangescount": "Үз өченә үзгәртүләрне, битләрнең тарихын һәм язлу көндәлеген дә кертә.",
+ "prefs-help-watchlist-token2": "Бу сезнең кузәтү исемлеге өчен ясалган веб-агымының серле ачкычы.\nАны белгән һәркем сезнең күзәтү исемлегегезне карый ала, шуңа да башкаларга аны күрсәтмәгез. [[Special:ResetTokens|Ачкычны ташларга теләсәгез, әлеге юрамага басыгыз]].",
"savedprefs": "Көйләнмәләрегез сакланды.",
"timezonelegend": "Сәгать поясы:",
"localtime": "Җирле вакыт",
"noname": "Sez qullanuçı isemegezne kürsätergä tieşsez.",
"loginsuccesstitle": "Kerü uñışlı ütte",
"loginsuccess": "'''Sez {{SITENAME}} proyektına $1 iseme belän kerdegez.'''",
- "nosuchuser": "$1 isemle qullanuçı yuq.\nQullanuçı isemeneñ döreslege registrğa bäyle.\nYazılışığıznı tikşeregez yäki [[Special:UserLogin/signup|yaña xisap yazması tözegez]].",
+ "nosuchuser": "$1 isemle qullanuçı yuq.\nQullanuçı isemeneñ döreslege registrğa bäyle.\nYazılışığıznı tikşeregez yäki [[Special:CreateAccount|yaña xisap yazması tözegez]].",
"nosuchusershort": "$1 isemle qullanuçı yuq. Yazılışığıznı tikşeregez.",
"nouserspecified": "Sez terkäw ismegezne kürsätergä tieşsez.",
"login-userblocked": "Bu qullanuçı tıyıldı. Kerü tıyılğan.",
"accmailtext": "[[User talk:$1|$1]] qullanuçısı öçen tözelgän sersüz $2 adresına cibärelde.\n\nSaytqa kergäç sez ''[[Special:ChangePassword|sersüzegezne üzgärtä alasız]]''.",
"newarticle": "(Yaña)",
"newarticletext": "Sez älegä yazılmağan bitkä kerdegez.\nYaña bit yasaw öçen astağı täräzädä mäqälä tekstın cıyığız ([$1 yärdäm biten] qarıy alasız).\nÄgär sez bu bitkä yalğışlıq belän eläkkän bulsağız, brauzerığıznıñ '''artqa''' töymäsenä basığız.",
- "anontalkpagetext": "----''Bu bäxäs bite sistemada terkälmägän yäisä üz iseme belän kermägän qullanuçınıqı.\nAnı tanu öçen IP adresı faydalanıla.\nÄgär sez anonim qullanuçı häm sezgä yullanmağan xäbärlär aldım dip sanıysız ikän (ber IP adresı küp qullanuçı öçen bulırğa mömkin), başqa mondıy añlaşılmawçanlıqlar kilep çıqmasın öçen [[Special:UserLogin|sistemağa keregez]] yäisä [[Special:UserLogin/signup|terkälegez]].''",
+ "anontalkpagetext": "----''Bu bäxäs bite sistemada terkälmägän yäisä üz iseme belän kermägän qullanuçınıqı.\nAnı tanu öçen IP adresı faydalanıla.\nÄgär sez anonim qullanuçı häm sezgä yullanmağan xäbärlär aldım dip sanıysız ikän (ber IP adresı küp qullanuçı öçen bulırğa mömkin), başqa mondıy añlaşılmawçanlıqlar kilep çıqmasın öçen [[Special:UserLogin|sistemağa keregez]] yäisä [[Special:CreateAccount|terkälegez]].''",
"noarticletext": "Xäzerge waqıtta bu bittä tekst yuq.\nSez [[Special:Search/{{PAGENAME}}|bu isem kergän başqa mäqälälärne]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} köndäleklärdäge yazmalarnı] taba\nyäki '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} şuşındıy isemle yaña bit tözi]'''</span> alasız.",
"noarticletext-nopermission": "Xäzerge waqıtta bu bittä tekst yuq.\n[[Special:Search/{{PAGENAME}}|Bu başlam qullanılğan başqa bitlärne]] yäki\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} köndäleklärdäge yazmalarnı] ezläp ala alasız</span>, läkin bu bitne tözü röxsätegez yuq.",
"userpage-userdoesnotexist": "«<nowiki>$1</nowiki>» isemle xisap yazması yuq. Sez çınlap ta bu bitne yasarğa yäisä üzgärtergä telisezme?",
"noname": "سىز تېخى ئىناۋەتلىك ئىشلەتكۈچى نامىنى بەلگىلىمىدىڭىز.",
"loginsuccesstitle": "تىزىمغا كىرىش مۇۋەپپەقىيەتلىك",
"loginsuccess": "'''سىز {{SITENAME}} غا \"$1\" سالاھىيىتىدە كىردىڭىز.'''",
- "nosuchuser": "\"$1\" ناملىق ئىشلەتكۈچىنى تاپالمىدى.\nئىشلەتكۈچى نامىنى تەكشۈرۈڭ.\nياكى [[Special:UserLogin/signup|يېڭى ھېسابات قۇرۇڭ]].",
+ "nosuchuser": "\"$1\" ناملىق ئىشلەتكۈچىنى تاپالمىدى.\nئىشلەتكۈچى نامىنى تەكشۈرۈڭ.\nياكى [[Special:CreateAccount|يېڭى ھېسابات قۇرۇڭ]].",
"nosuchusershort": "\"$1\" ناملىق ئىشلەتكۈچى يوق.\nكىرگۈزگىنىڭىزنى تەكشۈرۈڭ.",
"nouserspecified": "ئىشلەتكۈچى نامىدىن بىرنى بەلگىلەڭ.",
"login-userblocked": "بۇ ئىشلەتكۈچى چەكلەنگەن. تىزىمغا كىرىشكە يول قويۇلمايدۇ.",
"accmailtext": "[[User talk:$1|$1]] ئىختىيارىي قۇرۇلغان ئىم $2 غا يوللاندى.\n\nيېڭى ھېساباتقا قۇرغان ئىمنى تىزىمغا كىرىپ''[[Special:ChangePassword|ئىم ئۆزگەرت]]'' بېتىدىن ئۆزگەرتەلەيسىز.",
"newarticle": "(يېڭى)",
"newarticletext": "سىز تېخى قۇرۇلمىغان بەتكە كىردىڭىز.\n بۇ بەتنى قۇرسىڭىز، تۆۋەندىكى تەھرىرلەش رامكىسىغا مەزمۇن كىرگۈزۈڭ(تەپسىلاتىنى [$1 ياردەم بېتى]دىن كۆرۈڭ)",
- "anontalkpagetext": "----''بۇ تېخى ھېسابات قۇرمىغان ئاتسىز ئىشلەتكۈچىنىڭ مۇنازىرە بېتى ياكى ئۇنى ئىشلەتمەڭ..\nبىز ئۇنىڭ بىلەن پەقەت IP ئادرېسى بىلەنلا ئالاقە قىلالايمىز..\nبۇ خىل IP ئادرېسنى بىر قانچە ئىشلەتكۈچى ئىشلىتىشى ئورتاق ئىشلىتىشى مۇمكىن.\nئەگەر سىز ئاتسىز ئىشلەتكۈچى بولسىڭىز ھەمدە بۇ بەتتىكى مۇنازىرە سىز بىلەن مۇناسىۋەتلىك بولسا، [[Special:UserLogin/signup|ھېسابات قۇر]] ياكى [[Special:UserLogin|تىزىمغا كىر]] ئارقىلىق كەلگۈسىدىكى باشقا ئاتسىز ئىشلەتكۈچى بىلەن ئارىلىشىپ كېتىشنىڭ ئالدىنى ئېلىڭ.''",
+ "anontalkpagetext": "----''بۇ تېخى ھېسابات قۇرمىغان ئاتسىز ئىشلەتكۈچىنىڭ مۇنازىرە بېتى ياكى ئۇنى ئىشلەتمەڭ..\nبىز ئۇنىڭ بىلەن پەقەت IP ئادرېسى بىلەنلا ئالاقە قىلالايمىز..\nبۇ خىل IP ئادرېسنى بىر قانچە ئىشلەتكۈچى ئىشلىتىشى ئورتاق ئىشلىتىشى مۇمكىن.\nئەگەر سىز ئاتسىز ئىشلەتكۈچى بولسىڭىز ھەمدە بۇ بەتتىكى مۇنازىرە سىز بىلەن مۇناسىۋەتلىك بولسا، [[Special:CreateAccount|ھېسابات قۇر]] ياكى [[Special:UserLogin|تىزىمغا كىر]] ئارقىلىق كەلگۈسىدىكى باشقا ئاتسىز ئىشلەتكۈچى بىلەن ئارىلىشىپ كېتىشنىڭ ئالدىنى ئېلىڭ.''",
"noarticletext": "بۇ بەتتە ھازىرچە مەزمۇن يوق.\n سىز باشقا بەتتە [[Special:Search/{{PAGENAME}}|بۇ بەتنىڭ ماۋزۇسىنى ئىزدىيەلەيسىز]] ياكى\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} مۇناسىۋەتلىك خاتىرىسىنى ئىزدىيەلەيسىز،],\n[{{fullurl:{{FULLPAGENAME}}|action=edit}} بۇ بەتنى تەھرىرلىيەلەيسىز]</span>",
"noarticletext-nopermission": "بۇ بەتتە ھازىرچە مەزمۇن يوق.\n سىز باشقا بەتتە [[Special:Search/{{PAGENAME}}|بۇ بەتنىڭ ماۋزۇسىنى ئىزدىيەلەيسىز]] ياكى <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}}] مۇناسىۋەتلىك خاتىرىسىنى ئىزدىيەلەيسىز،</span>لىكىن سزنىڭ بەت قۇرۇش ھوقوقىڭز يوق.",
"missing-revision": "\"{{FULLPAGENAME}}\" ئاتلىق بەتنىڭ تۈزىتىلگەن نەشرى #$1 مەۋجۇت ئەمەس.\n\nئادەتتە بۇ ئۆچۈرۈلگەن بىر بەتنىڭ ئۇلانمىسىغا كىرگەنلىك سەۋەبىدىن بولىدۇ.\nتەپسىلىي ئۇچۇرنى [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ئۆچۈرۈش خاتىرىسى] دىن تاپقىلى بولىدۇ.",
"password-change-forbidden": "Ви не можна змінити пароль на цій вікі.",
"externaldberror": "Сталася помилка при автентифікації за допомогою зовнішньої бази даних, або у вас недостатньо прав для внесення змін до свого зовнішнього облікового запису.",
"login": "Вхід до системи",
+ "login-security": "Підтвердіть свою особу",
"nav-login-createaccount": "Вхід / реєстрація",
"userlogin": "Вхід / реєстрація",
"userloginnocreate": "Увійти",
"userlogin-resetpassword-link": "Забули пароль?",
"userlogin-helplink2": "Допомога з входом у систему",
"userlogin-loggedin": "Ви вже увійшли як {{GENDER:$1|$1}}.\nВикористайте нижче форму для входу як інший користувач.",
+ "userlogin-reauth": "Ви маєте увійти в систему знову, щоб підтвердити, що Ви і є {{GENDER:$1|$1}}.",
"userlogin-createanother": "Створити інший обліковий запис",
"createacct-emailrequired": "Адреса електронної пошти",
"createacct-emailoptional": "Адреса електронної пошти (не обов'язково)",
"createacct-email-ph": "Введіть Вашу адресу електронної пошти",
"createacct-another-email-ph": "Введіть адресу електронної пошти",
"createaccountmail": "Використати тимчасовий випадковий пароль і надіслати його на вказану адресу електронної пошти",
+ "createaccountmail-help": "Може використовуватися, щоб створити обліковий запис для іншої особи, не дізнаючись пароль.",
"createacct-realname": "Справжнє ім'я (не обов'язково)",
"createaccountreason": "Причина:",
"createacct-reason": "Причина",
"createacct-reason-ph": "Чому ви створюєте інший обліковий запис",
+ "createacct-reason-help": "Повідомлення, що показується в журналі створення облікових записів",
"createacct-submit": "Створіть ваш обліковий запис",
"createacct-another-submit": "Створити обліковий запис",
+ "createacct-continue-submit": "Продовжити створення облікового запису",
+ "createacct-another-continue-submit": "Продовжити створення облікового запису",
"createacct-benefit-heading": "{{SITENAME}} створюється такими самими людьми, як і Ви.",
"createacct-benefit-body1": "{{PLURAL:$1|редагування|редагування|редагувань}}",
"createacct-benefit-body2": "{{PLURAL:$1|сторінка|сторінки|сторінок}}",
"nocookieslogin": "{{SITENAME}} використовує куки (''cookies'') для входу до системи.\nВи їх вимкнули.\nБудь ласка, ввімкніть куки і спробуйте знову.",
"nocookiesfornew": "Обліковий запис користувача не був створений через неможливість перевірити походження даних.\nПереконайтеся, що куки ввімкнено, оновіть сторінку і спробуйте ще раз.",
"nocookiesforlogin": "{{int:nocookieslogin}}",
+ "createacct-loginerror": "Обліковий запис було успішно створено, але Ви не змогли увійти в систему автоматично. Будь ласка, [[Special:UserLogin|увійдіть вручну]].",
"noname": "Ви зазначили неправильне ім'я користувача.",
"loginsuccesstitle": "Вхід виконано",
"loginsuccess": "'''Тепер ви працюєте в {{grammar:locative|{{SITENAME}}}} під іменем $1.'''",
- "nosuchuser": "Користувача з іменем «$1» не існує.\nВ іменах користувачів розрізняються великі й малі символи.\nПеревірте правильність написання або скористайтеся формою нижче, щоб [[Special:UserLogin/signup|створити новий обліковий запис]].",
+ "nosuchuser": "Користувача з іменем «$1» не існує.\nВ іменах користувачів розрізняються великі й малі символи.\nПеревірте правильність написання або скористайтеся формою нижче, щоб [[Special:CreateAccount|створити новий обліковий запис]].",
"nosuchusershort": "Користувача з іменем «$1» не існує.\nПеревірте правильність написання імені.",
"nouserspecified": "Ви повинні зазначити ім'я користувача.",
"login-userblocked": "Цей користувач заблокований. Вхід в систему не дозволений.",
"createacct-another-realname-tip": "Справжнє ім'я є необов'язковим.\nЯкщо ви вирішите надати його, воно буде використовуватись для позначення редагувань та інших дій користувача.",
"pt-login": "Увійти",
"pt-login-button": "Вхід",
+ "pt-login-continue-button": "Продовжити вхід",
"pt-createaccount": "Створити обліковий запис",
"pt-userlogout": "Вийти",
"php-mail-error-unknown": "Невідома помилка в PHP-функції mail()",
"botpasswords-invalid-name": "Вказане ім'я користувача не містить роздільник для пароля бота («$1»).",
"botpasswords-not-exist": "У користувача «$1» нема пароля для бота «$2».",
"resetpass_forbidden": "Пароль не можна змінити",
+ "resetpass_forbidden-reason": "Пароль не можна змінити: $1",
"resetpass-no-info": "Щоб звертатися безпосередньо до цієї сторінки, вам слід увійти до системи.",
"resetpass-submit-loggedin": "Змінити пароль",
"resetpass-submit-cancel": "Скасувати",
"passwordreset-emailsentusername": "Якщо існує електронна адреса, яка асоційована з цим обліковим записом, на неї буде надіслано лист для відновлення пароля.",
"passwordreset-emailsent-capture": "Електронний лист скидання пароля було надіслано, як показано нижче.",
"passwordreset-emailerror-capture": "Електронний лист для відновлення пароля мав бути надісланий, як показано нижче, але його надсилання {{GENDER:$2|користувачеві|користувачці}} $1 не вдалося.",
+ "passwordreset-emailsent-capture2": "{{PLURAL:$1|Електронний лист|Електронні листи}} скидання паролю було надіслано. {{PLURAL:$1|Ім'я користувача і пароль|Список імен користувачів і паролів}} показано нижче.",
+ "passwordreset-emailerror-capture2": "Не вдалося надіслати листа {{GENDER:$2|користувачу|користувачці}}: $1 {{PLURAL:$3|Ім'я користувача і пароль|список імен користувачів і паролів}} показано нижче.",
+ "passwordreset-nocaller": "Має бути надане джерело виклику",
+ "passwordreset-nosuchcaller": "Джерело виклику не існує: $1",
+ "passwordreset-ignored": "Скидання пароля не відбулося. Можливо, не було налашатовано надавача?",
+ "passwordreset-invalideamil": "Недійсна адреса електронної пошти",
+ "passwordreset-nodata": "Не надано ні імені користувача, ні електронної адреси",
"changeemail": "Змінити або вилучити адресу електронної пошти",
"changeemail-header": "Заповніть цю форму, щоб змінити адресу електронної пошти. Якщо Ви хочете взагалі прибрати зв'язок свого облікового запису з адресою електронної пошти, при надсиланні форми залиште поле нової електронної адреси порожнім.",
"changeemail-passwordrequired": "Вам потрібно буде ввести пароль, щоб підтвердити цю зміну.",
"minoredit": "Незначна зміна",
"watchthis": "Спостерігати за цією сторінкою",
"savearticle": "Зберегти сторінку",
+ "publishpage": "Опублікувати сторінку",
"preview": "Попередній перегляд",
"showpreview": "Попередній перегляд",
"showdiff": "Показати зміни",
"subject-preview": "Тема буде:",
"previewerrortext": "Сталася помилка при спробі попереднього перегляду Ваших змін.",
"blockedtitle": "Користувача заблоковано",
- "blockedtext": "'''Ваш обліковий запис або IP-адреса заблоковані.'''\n\nБлокування виконане адміністратором $1.\nЗазначена наступна причина: ''$2''.\n\n* Початок блокування: $8\n* Закінчення блокування: $6\n* Блокування виконав: $7\n\nВи можете надіслати листа користувачеві $1 або будь-якому іншому [[{{MediaWiki:Grouppage-sysop}}|адміністратору]], щоб обговорити блокування.\n\nЗверніть увагу, що ви не зможете надіслати листа адміністратору, якщо ви не зареєстровані або не підтвердили свою електронну адресу в [[Special:Preferences|особистих налаштуваннях]], а також якщо вам було заборонено надсилати листи при блокуванні.\n\nВаша поточна IP-адреса — $3, ідентифікатор блокування — #$5. Будь ласка, зазначайте ці дані у своїх запитах.",
+ "blockedtext": "<strong>Ваш обліковий запис або IP-адреса заблоковані.</strong>\n\nБлокування виконане адміністратором $1.\nПричина блокування: <em>$2</em>.\n\n* Початок блокування: $8\n* Закінчення блокування: $6\n* Діапазон блокування: $7\n\nВи можете надіслати листа користувачеві $1 або будь-якому іншому [[{{MediaWiki:Grouppage-sysop}}|адміністратору]], щоб обговорити блокування.\n\nЗверніть увагу, що ви не зможете надіслати листа адміністратору, якщо ви не зареєстровані або не підтвердили свою електронну адресу в [[Special:Preferences|особистих налаштуваннях]], а також якщо вам було заборонено надсилати листи при блокуванні.\n\nВаша поточна IP-адреса — $3, ідентифікатор блокування — #$5. Будь ласка, зазначайте ці дані у своїх запитах.",
"autoblockedtext": "Ваша IP-адреса автоматично заблокована у зв'язку з тим, що вона раніше використовувалася кимось із заблокованих користувачів. Адміністратор ($1), що її заблокував, зазначив наступну причину блокування:\n\n:''$2''\n\n* Початок блокування: $8\n* Закінчення блокування: $6\n* Блокування виконав: $7\n\nВи можете надіслати листа користувачеві $1 або будь-якому іншому [[{{MediaWiki:Grouppage-sysop}}|адміністратору]], щоб обговорити блокування.\n\nЗверніть увагу, що ви не зможете надіслати листа адміністраторові, якщо ви не зареєстровані у проекті або не підтвердили свою електронну адресу в [[Special:Preferences|особистих налаштуваннях]], а також якщо вам було заборонено надсилати листи при блокуванні.\n\nВаша поточна IP-адреса — $3, ідентифікатор блокування — #$5. Будь ласка, зазначайте його у своїх запитах.",
"blockednoreason": "не вказано причини",
"whitelistedittext": "Ви повинні $1, щоб редагувати сторінки.",
"accmailtext": "Пароль для користувача [[User talk:$1|$1]], згенерований випадковим чином, надісланий на адресу $2.\nПісля реєстрації в системі ви зможете ''[[Special:ChangePassword|змінити пароль]]''.",
"newarticle": "(Нова)",
"newarticletext": "Ви перейшли на сторінку, яка поки що не існує.\n\nЩоб створити нову сторінку, наберіть текст у вікні нижче (див. [$1 довідкову статтю], щоб отримати більше інформації).\nЯкщо Ви опинились тут помилково, просто натисніть кнопку браузера '''назад'''.",
- "anontalkpagetext": "----\n<em>Це сторінка обговорення анонімного користувача, який ще не зареєструвався або не скористався зареєстрованим обліковим записом.</em>\nТому ми вимушені використовувати IP-адресу для його ідентифікації.\nОдна IP-адреса може використовуватись кількома користувачами.\nЯкщо Ви — анонімний користувач і вважаєте, що отримали коментарі, адресовані не Вам, будь ласка [[Special:UserLogin/signup|зареєструйтесь]] або [[Special:UserLogin|увійдіть до системи]], щоб у майбутньому уникнути можливої плутанини з іншими анонімними користувачами.",
+ "anontalkpagetext": "----\n<em>Це сторінка обговорення анонімного користувача, який ще не зареєструвався або не скористався зареєстрованим обліковим записом.</em>\nТому ми вимушені використовувати IP-адресу для його ідентифікації.\nОдна IP-адреса може використовуватись кількома користувачами.\nЯкщо Ви — анонімний користувач і вважаєте, що отримали коментарі, адресовані не Вам, будь ласка [[Special:CreateAccount|зареєструйтесь]] або [[Special:UserLogin|увійдіть до системи]], щоб у майбутньому уникнути можливої плутанини з іншими анонімними користувачами.",
"noarticletext": "Зараз на цій сторінці нема тексту.\nВи можете [[Special:Search/{{PAGENAME}}|пошукати цю назву]] на інших сторінках,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} пошукати в журналах]\nабо [{{fullurl:{{FULLPAGENAME}}|action=edit}} створити сторінку з такою назвою]</span>.",
"noarticletext-nopermission": "Зараз на цій сторінці немає тексту.\nВи можете [[Special:Search/{{PAGENAME}}|пошукати цю назву]] на інших сторінках,\nабо <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} пошукати пов'язані записи в журналах]</span>, але ви не маєте дозволу на створення такої сторінки.",
"missing-revision": "Версія #$1 сторінки «{{FULLPAGENAME}}» не існує.\n\nІмовірно, Ви перейшли за застарілим посиланням на вилучену сторінку.\nПодробиці можна дізнатися з [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журналу вилучень].",
"userpage-userdoesnotexist": "Користувач під назвою \"<nowiki>$1</nowiki>\" не зареєстрований. Переконайтеся, що ви хочете створити/редагувати цю сторінку.",
- "userpage-userdoesnotexist-view": "Обліковий запис користувача „$1“ не зареєстровано.",
+ "userpage-userdoesnotexist-view": "Обліковий запис користувача «$1» не зареєстровано.",
"blocked-notice-logextract": "Цей користувач наразі заблокований.\nОстанній запис у журналі блокувань такий:",
"clearyourcache": "<strong>Увага:</strong> Після збереження слід очистити кеш оглядача, щоб побачити зміни.\n* <strong>Firefox / Safari:</strong> тримайте <em>Shift</em>, коли натискаєте <em>Оновити</em>, або натисніть <em>Ctrl-F5</em> чи <em>Ctrl-Shift-R</em> (<em>⌘-R</em> на Apple Mac)\n* <strong>Google Chrome:</strong> натисніть <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> на Apple Mac)\n* <strong>Internet Explorer:</strong> тримайте <em>Ctrl</em>, коли натискаєте <em>Оновити</em>, або натисніть <em>Ctrl-F5</em>\n* <strong>Opera:</strong> очистіть кеш за допомогою <em>Інструменти → Налаштування</em> (<em>Opera → Побажання</em> на Apple Mac) та перейдіть на <em>Привітність & безпека → очистити дані браузера → кеш</em>",
"usercssyoucanpreview": "'''Підказка:''' використовуйте кнопку «{{int:showpreview}}», щоб протестувати ваш новий css-файл перед збереженням.",
"right-override-export-depth": "експорт сторінок, включаючи пов'язані сторінки з глибиною до 5",
"right-sendemail": "надсилання електронної пошти іншим користувачам",
"right-passwordreset": "Перегляд повідомлень електронної пошти для зміни паролю",
- "right-managechangetags": "створення та вилучення [[Special:Tags|міток]] з бази даних",
+ "right-managechangetags": "створення та (де)активування [[Special:Tags|міток]]",
"right-applychangetags": "додавання [[Special:Tags|міток]] разом зі змінами",
"right-changetags": "додавання або вилучення будь-яких [[Special:Tags|міток]] для певних версій сторінок або записів журналів",
+ "right-deletechangetags": "вилучення [[Special:Tags|міток]] з бази даних",
"grant-generic": "Набір прав «$1»",
"grant-group-page-interaction": "Взаємодіяти зі сторінками",
"grant-group-file-interaction": "Взаємодіяти з медіа",
"action-viewmyprivateinfo": "перегляд своєї приватної інформації",
"action-editmyprivateinfo": "редагування своєї приватної інформації",
"action-editcontentmodel": "редагувати модель вмісту сторінки",
- "action-managechangetags": "створення та вилучення міток з бази даних",
+ "action-managechangetags": "створення та (де)активування міток",
"action-applychangetags": "додавання міток разом зі змінами",
"action-changetags": "додавання або вилучення будь-яких міток для певних версій сторінок або записів журналів",
+ "action-deletechangetags": "вилучення міток з бази даних",
"nchanges": "$1 {{PLURAL:$1|зміна|зміни|змін}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|зміна з останнього візиту|зміни з останнього візиту|змін з останнього візиту}}",
"enhancedrc-history": "історія",
"upload-form-label-own-work": "Це моя власна робота",
"upload-form-label-infoform-categories": "Категорії",
"upload-form-label-infoform-date": "Дата",
- "upload-form-label-own-work-message-local": "Я підтверджую, що вивантажую цей файл згідно з умовами користування та політики ліцензування {{GRAMMAR:locative|{{SITENAME}}}}.",
- "upload-form-label-not-own-work-message-local": "Якщо Ви не можете завантажити цей файл згідно з правилами {{GRAMMAR:genitive|{{SITENAME}}}}, будь ласка, закрийте цей вікно та оберіть інший спосіб.",
- "upload-form-label-not-own-work-local-local": "Ви також можете спробувати [[Special:Upload|сторінку завантаження за замовчуванням]].",
- "upload-form-label-own-work-message-default": "Я розумію, що я завантажую цей файл до спільного сховища. Я підтверджую, що я роблю це у відповідності до Умов надання послуг та правил ліцензування.",
- "upload-form-label-not-own-work-message-default": "Якщо ви не можете завантажити цей файл згідно з правилами спільного сховища, будь ласка, закрийте цей вікно та оберіть інший спосіб.",
- "upload-form-label-not-own-work-local-default": "Ви також можете спробувати використати [[Special:Upload|сторінку завантаження на {{GRAMMAR:locative|{{SITENAME}}}}]], якщо цей файл може бути завантажений згідно з їх правилами.",
- "upload-form-label-own-work-message-shared": "Я підтверджую, що я є власником авторських прав на цей файл та погоджуюся беззастережно поширити його у Вікісховищі на умовах ліцензії [https://creativecommons.org/licenses/by-sa/4.0/deed.uk Creative CommonsAttribution-ShareAlike 4.0], і я згоден з [https://wikimediafoundation.org/wiki/Terms_of_Use умовами використання].",
- "upload-form-label-not-own-work-message-shared": "Якщо ви не є власником авторських прав на цей файл або ви хочете розповсюджувати його на умовах іншої ліцензії, рекомендуємо використати [https://commons.wikimedia.org/wiki/Special:UploadWizard Майстер завантажень на Вікісховищі].",
- "upload-form-label-not-own-work-local-shared": "Ви також можете спробувати використати [[Special:Upload|сторінку завантаження на {{GRAMMAR:locative|{{SITENAME}}}}]], якщо цей файл може бути завантажений на цей сайт згідно з його правилами.",
+ "upload-form-label-own-work-message-generic-local": "Я підтверджую, що вивантажую цей файл згідно з умовами користування та політики ліцензування {{GRAMMAR:locative|{{SITENAME}}}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Якщо Ви не можете завантажити цей файл згідно з правилами {{GRAMMAR:genitive|{{SITENAME}}}}, будь ласка, закрийте цей вікно та оберіть інший спосіб.",
+ "upload-form-label-not-own-work-local-generic-local": "Ви також можете спробувати [[Special:Upload|сторінку завантаження за замовчуванням]].",
+ "upload-form-label-own-work-message-generic-foreign": "Я розумію, що я завантажую цей файл до спільного сховища. Я підтверджую, що я роблю це у відповідності до Умов надання послуг та правил ліцензування.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Якщо ви не можете завантажити цей файл згідно з правилами спільного сховища, будь ласка, закрийте цей вікно та оберіть інший спосіб.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Ви також можете спробувати використати [[Special:Upload|сторінку завантаження на {{GRAMMAR:locative|{{SITENAME}}}}]], якщо цей файл може бути завантажений згідно з їх правилами.",
"backend-fail-stream": "Не вдалося транслювати файл $1.",
"backend-fail-backup": "Не вдалося створити резервну копію файлу $1.",
"backend-fail-notexists": "Файл $1 не існує.",
"trackingcategories-msg": "Відстежувана категорія",
"trackingcategories-name": "Ім'я повідомлення",
"trackingcategories-desc": "Критерій включення в категорію",
+ "restricted-displaytitle-ignored": "Сторінки, де ігноруються відображувані назви",
+ "restricted-displaytitle-ignored-desc": "На цій сторінці ігнорується <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> бо він не відповідає власне назві сторінки.",
"noindex-category-desc": "Сторінка не індексується пошуковими роботами, тому що на ній є «чарівне слово» <code><nowiki>__NOINDEX__</nowiki></code>, і вона знаходиться в просторі імен, де дозволений цей прапор).",
"index-category-desc": "На сторінці є «чарівне слово» <code><nowiki>__INDEX__</nowiki></code> (і сторінка знаходиться в просторі назв, де дозволений цей прапор), тому вона індексується пошуковими роботами в тих випадках, коли цього зазвичай не відбувається.",
"post-expand-template-inclusion-category-desc": "Розмір сторінки стане більший за <code>$wgMaxArticleSize</code> після показу всіх шаблонів, тому деякі з них не були показані повністю.",
"rollbacklinkcount": "відкинути $1 {{PLURAL:$1|редагування|редагування|редагувань}}",
"rollbacklinkcount-morethan": "відкинути понад $1 {{PLURAL:$1|редагування|редагування|редагувань}}",
"rollbackfailed": "Відкинути зміни не вдалося",
+ "rollback-missingparam": "Відсутні обов'язкові параметри за запитом.",
"cantrollback": "Неможливо відкинути редагування, оскільки останній дописувач сторінки є її автором.",
"alreadyrolled": "Неможливо відкинути останні редагування [[:$1]], зроблені [[User:$2|$2]] ([[User talk:$2|обговорення]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]), оскільки хтось інший уже змінив чи відкинув редагування цієї статті.\n\nОстанні редагування зроблено [[User:$3|$3]] ([[User talk:$3|обговорення]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "Пояснення редагування було: «<em>$1</em>.».",
"revertpage": "Відкинуто редагування [[Special:Contributions/$2|$2]] ([[User talk:$2|обговорення]]) до зробленого [[User:$1|$1]]",
"revertpage-nouser": "Відкинуто редагування прихованого користувача до останньої версії, зробленої {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "Відкинуті редагування користувача $1; повернення до версії користувача $2.",
+ "rollback-success-notify": "Відкинуті редагування користувача $1; \nповернено до останньої версії користувача $2. [$3 Показати зміни]",
"sessionfailure-title": "Помилка сеансу",
"sessionfailure": "Здається, виникли проблеми з поточним сеансом роботи;\nця дія була скасована з метою попередити «захоплення сеансу».\nБудь ласка, натисніть кнопку «Назад» і перезавантажте сторінку, з якої ви прийшли.",
"changecontentmodel": "Змінити модель вмісту сторінки",
"changecontentmodel-success-text": "Тип вмісту сторінки [[:$1]] було змінено.",
"changecontentmodel-cannot-convert": "Вміст сторінки [[:$1]] не можна перетворити на вміст типу $2.",
"changecontentmodel-nodirectediting": "Модель вмісту $1 не підтримує пряме редагування",
+ "changecontentmodel-emptymodels-title": "Немає доступних моделей коментарів",
+ "changecontentmodel-emptymodels-text": "Вміст сторінки [[:$1]] не може бути перетворений до будь якого типу.",
"log-name-contentmodel": "Журнал змін моделі вмісту",
"log-description-contentmodel": "Події, пов'язані з моделями вмісту сторінки",
"logentry-contentmodel-new": "$1 {{GENDER:$2|створив|створила}} сторінку $3, використовуючи нестандартну модель вмісту «$5»",
"whatlinkshere-hideredirs": "$1 перенаправлення",
"whatlinkshere-hidetrans": "$1 включення",
"whatlinkshere-hidelinks": "$1 посилання",
- "whatlinkshere-hideimages": "$1 посилання на зображення",
+ "whatlinkshere-hideimages": "$1 посилання на файли",
"whatlinkshere-filters": "Фільтри",
"whatlinkshere-submit": "Виконати",
"autoblockid": "Автоблокування #$1",
"unblockip": "Розблокувати IP-адресу",
"unblockiptext": "Використовуйте подану нижче форму, щоб відновити можливість збереження з раніше заблокованої IP-адреси.",
"ipusubmit": "Зняти це блокування",
- "unblocked": "[[User:$1|$1]] {{GENDER:$1|Ñ\80азблокований|Ñ\80азблокована}}",
+ "unblocked": "[[User:$1|$1]] {{GENDER:$1|Ñ\80озблокований|Ñ\80озблокована}}",
"unblocked-range": "$1 розблоковано",
"unblocked-id": "Блокування $1 було зняте",
"unblocked-ip": "[[Special:Contributions/$1|$1]] вже розлоковано.",
"blocklist-timestamp": "Часова позначка",
"blocklist-target": "Мета",
"blocklist-expiry": "Закінчується",
- "blocklist-by": "Ð\92иконав блокÑ\83ваннÑ\8f",
+ "blocklist-by": "Ð\90дмÑ\96нÑ\96Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80, Ñ\89о заблокÑ\83вав",
"blocklist-params": "Параметри блокування",
"blocklist-reason": "Причина",
"ipblocklist-submit": "Пошук",
"lockdbsuccesstext": "Базу даних проекту заблоковано.<br />\nНе забудьте її [[Special:UnlockDB|розблокувати]] після завершення обслуговування.",
"unlockdbsuccesstext": "Базу даних проекту розблоковано.",
"lockfilenotwritable": "Немає права на запис в файл блокування бази даних. Щоб заблокувати чи розблокувати БД, веб-сервер повинен мати дозвіл на запис в цей файл.",
+ "databaselocked": "База даних вже заблокована.",
"databasenotlocked": "База даних не заблокована.",
"lockedbyandtime": "($1 $2 $3)",
"move-page": "Перейменування сторінки «$1»",
"movesubpagetext": "Ця сторінка має $1 {{PLURAL:$1|підсторінку|підсторінки|підсторінок}}.",
"movenosubpage": "Ця сторінка не має підсторінок.",
"movereason": "Причина:",
- "revertmove": "відкинути",
+ "revertmove": "скасувати перейменування",
"delete_and_move_text": "Сторінка з назвою [[:$1|«$1»]] вже існує.\nБажаєте вилучити її для можливості перейменування?",
"delete_and_move_confirm": "Так, вилучити для перейменування",
"delete_and_move_reason": "Вилучена для можливості перейменування сторінки «[[$1]]»",
"confirm-watch-top": "Додати цю сторінку до списку спостереження?",
"confirm-unwatch-button": "Гаразд",
"confirm-unwatch-top": "Вилучити цю сторінку з вашого списку спостереження?",
+ "confirm-rollback-button": "Гаразд",
+ "confirm-rollback-top": "Відкотити редагування цієї сторінки?",
"semicolon-separator": "; ",
"comma-separator": ", ",
"colon-separator": ": ",
"timezone-local": "Місцеві",
"duplicate-defaultsort": "Увага. Ключ сортування «$2» перекриває попередній ключ сортування «$1».",
"duplicate-displaytitle": "<strong>Увага:</strong> Відображений заголовок \"$2\" заміщує раніше відображений заголовок \"$1\".",
+ "restricted-displaytitle": "<strong>Увага:</strong> Відображувану назву «$1» було проігноровано, оскільки воно не відповідає власне назві сторінки.",
"invalid-indicator-name": "<strong>Помилка:</strong> Сторінка індикатора стану <code>name</code> атрибута не може бути пуста.",
"version": "Версія MediaWiki",
"version-extensions": "Установлені розширення",
"tags-activate": "активувати",
"tags-deactivate": "вимкнути",
"tags-hitcount": "$1 {{PLURAL:$1|зміна|зміни|змін}}",
- "tags-manage-no-permission": "У Ð\92аÑ\81 нема дозволÑ\83 кеÑ\80Ñ\83ваÑ\82и змÑ\96нами мÑ\96Ñ\82ок.",
+ "tags-manage-no-permission": "У Ð\92аÑ\81 нема дозволÑ\83 кеÑ\80Ñ\83ваÑ\82и мÑ\96Ñ\82ками змÑ\96н.",
"tags-manage-blocked": "Не можна змінювати мітки під час блокування.",
"tags-create-heading": "Створити нову мітку",
"tags-create-explanation": "За замовчуванням, новостворені мітки будуть доступні для використання користувачами і ботами.",
"tags-delete-not-found": "Мітка «$1» не існує.",
"tags-delete-too-many-uses": "Міткою «$1» понад $2 {{PLURAL:$2|редагування|редагування|редагувань}}, і це означає, що її не можна вилучити.",
"tags-delete-warnings-after-delete": "Мітку «$1» було вилучено, але {{PLURAL:$2|з'явилось таке|з'явились такі}} попередження:",
+ "tags-delete-no-permission": "У Вас нема дозволу вилучати мітки змін.",
"tags-activate-title": "Активувати мітку",
"tags-activate-question": "Ви збираєтеся активувати мітку «$1».",
"tags-activate-reason": "Причина:",
"feedback-useragent": "User Agent:",
"searchsuggest-search": "Пошук",
"searchsuggest-containing": "що містять...",
+ "api-error-autoblocked": "Вашу IP-адресу було заблоковано автоматично, тому що її використовував заблокований користувач.",
"api-error-badaccess-groups": "Вам не дозволено завантажувати файли до цього вікіпроекту.",
"api-error-badtoken": "Внутрішня помилка: некоректний токен.",
+ "api-error-blocked": "Можливість редагування для вас заблоковано.",
"api-error-copyuploaddisabled": "На цьому сервері вимкнене завантаження за URL-адресою.",
"api-error-duplicate": "Уже {{PLURAL:$1|1=існує інший файл|існують інші файли}} з таким самим вмістом.",
"api-error-duplicate-archive": "Раніше на сайті вже {{PLURAL:$1|1=був файл|були файли}} з ідентичним вмістом, але {{PLURAL:$1|1=його|їх}} вилучили.",
"log-action-filter-suppress-block": "Приховування користувача через блокування",
"log-action-filter-suppress-reblock": "Приховування користувача через повторне блокування",
"log-action-filter-upload-upload": "Нове завантаження",
- "log-action-filter-upload-overwrite": "Повторне завантаження"
+ "log-action-filter-upload-overwrite": "Повторне завантаження",
+ "authmanager-authn-not-in-progress": "Автентифікація не виконується або втрачено дані сесії. Будь ласка, почніть знову з самого початку.",
+ "authmanager-authn-no-primary": "Надані облікові дані не можуть бути завірені.",
+ "authmanager-authn-no-local-user": "Надані облікові дані не пов'язані з жодним користувачем у цій вікі.",
+ "authmanager-authn-no-local-user-link": "Надані облікові дані дійсні, але не пов'язані з жодним користувачем у цій вікі. Увійдіть іншим способом або створіть нового користувача, й у Вас з'явиться можливість зв'язати свої старі облікові дані з цим обліковим записом.",
+ "authmanager-authn-autocreate-failed": "Автоматичне створення локального облікового запису не вдалося: $1",
+ "authmanager-change-not-supported": "Надані облікові дані не можуть бути змінені, оскільки їх нічого не буде використовувати.",
+ "authmanager-create-disabled": "Створення облікових записів вимкнене.",
+ "authmanager-create-from-login": "Щоб створити обліковий запис, будь ласка, заповніть поля нижче.",
+ "authmanager-create-not-in-progress": "Створення облікового запису не виконується або втрачено дані сесії. Будь ласка, почніть знову з самого початку.",
+ "authmanager-create-no-primary": "Надані облікові дані не можуть бути використані для створення облікового запису.",
+ "authmanager-link-no-primary": "Надані облікові дані не можуть бути використані для прив'язки облікового запису.",
+ "authmanager-link-not-in-progress": "Пов'язання облікового запису не виконується або втрачено дані сесії. Будь ласка, почніть знову з самого початку.",
+ "authmanager-authplugin-setpass-failed-title": "Не вдалося змінити пароль",
+ "authmanager-authplugin-setpass-failed-message": "Плагін автентифікації відмовив у зміні пароля.",
+ "authmanager-authplugin-create-fail": "Плагін автентифікації відмовив у створенні облікового запису.",
+ "authmanager-authplugin-setpass-denied": "Плагін автентифікації не дозволяє змінювати паролі.",
+ "authmanager-authplugin-setpass-bad-domain": "Неприпустимий домен.",
+ "authmanager-autocreate-noperm": "Автоматичне створення облікових записів не допускається.",
+ "authmanager-autocreate-exception": "Автоматичне створення облікових записів тимчасово відключене через попередні помилки.",
+ "authmanager-userdoesnotexist": "Обліковий запис користувача «$1» не зареєстровано.",
+ "authmanager-userlogin-remembermypassword-help": "Чи слід пам'ятати пароль довше, ніж тривалість сесії.",
+ "authmanager-username-help": "Ім'я користувача для автентифікації.",
+ "authmanager-password-help": "Пароль для автентифікації.",
+ "authmanager-domain-help": "Домен для зовнішньої аутентифікації.",
+ "authmanager-retype-help": "Знову пароль для підтвердження.",
+ "authmanager-email-label": "Електронна пошта",
+ "authmanager-email-help": "Адреса електронної пошти",
+ "authmanager-realname-label": "Справжнє ім'я",
+ "authmanager-realname-help": "Справжнє ім'я користувача",
+ "authmanager-provider-password": "Автентифікація на основі пароля",
+ "authmanager-provider-password-domain": "Автентифікація на основі пароля і домена",
+ "authmanager-provider-temporarypassword": "Тимчасовий пароль",
+ "authprovider-confirmlink-message": "На основі Ваших останніх спроб входу в систему, з Вашим обліковим записом вікі можна пов'язати такі облікові записи. Їх поєднання дає можливість входу в систему через ці облікові записи. Будь ласка, виберіть, які з них повинні бути пов'язані.",
+ "authprovider-confirmlink-request-label": "Облікові записи, які мають бути пов'язані",
+ "authprovider-confirmlink-success-line": "$1: Успішно пов'язано.",
+ "authprovider-confirmlink-failed": "Пов'язування облікових записів не вдалося до кінця: $1",
+ "authprovider-confirmlink-ok-help": "Продовжити після показу повідомлень помилки зв'язування.",
+ "authprovider-resetpass-skip-label": "Пропустити",
+ "authprovider-resetpass-skip-help": "Пропустити скидання пароля.",
+ "authform-nosession-login": "Автентифікація пройшла успішно, але Ваш браузер не може «запам'ятати» вхід у систему.\n\n$1",
+ "authform-nosession-signup": "Обліковий запис було створено, але Ваш браузер не може «запам'ятати» вхід у систему.\n\n$1",
+ "authform-newtoken": "Відсутній токен. $1",
+ "authform-notoken": "Відсутній токен",
+ "authform-wrongtoken": "Неправильний токен",
+ "specialpage-securitylevel-not-allowed-title": "Не дозволено",
+ "specialpage-securitylevel-not-allowed": "Вибачте, Вам не дозволено використати цю сторінку, тому що Вашу ідентичність не вдалося перевірити.",
+ "authpage-cannot-login": "Не вдалося запустити входження в систему.",
+ "authpage-cannot-login-continue": "Не вдалося продовжити вхід в систему. Вірогідно, вийшов час Вашої сесії.",
+ "authpage-cannot-create": "Не вдалося почати створення облікового запису.",
+ "authpage-cannot-create-continue": "Не вдалося продовжити створення облікового запису. Вірогідно, вийшов час Вашої сесії.",
+ "authpage-cannot-link": "Не вдалося почати поєднання облікових записів.",
+ "authpage-cannot-link-continue": "Не вдалося продовжити поєднання облікових записів. Вірогідно, вийшов час Вашої сесії.",
+ "cannotauth-not-allowed-title": "Доступ заборонено",
+ "cannotauth-not-allowed": "Вам не дозволено використовувати цю сторінку",
+ "changecredentials": "Зміна облікових даних",
+ "changecredentials-submit": "Змінити",
+ "changecredentials-submit-cancel": "Скасувати",
+ "changecredentials-invalidsubpage": "«$1» не є коректним типом облікових даних.",
+ "changecredentials-success": "Ваші облікові дані змінено.",
+ "removecredentials": "Вилучити облікові дані",
+ "removecredentials-submit": "Вилучити",
+ "removecredentials-submit-cancel": "Скасувати",
+ "removecredentials-invalidsubpage": "$1 не є коректним типом облікових даних.",
+ "removecredentials-success": "Ваші облікові дані вилучено.",
+ "credentialsform-provider": "Тип облікових даних:",
+ "credentialsform-account": "Ім'я облікового запису:",
+ "cannotlink-no-provider-title": "Немає облікових записів, які можна поєднати",
+ "cannotlink-no-provider": "Немає облікових записів, які можна поєднати.",
+ "linkaccounts": "Пов'язати облікові записи",
+ "linkaccounts-success-text": "Обліковий запис було пов'язано.",
+ "linkaccounts-submit": "Пов'язати облікові записи",
+ "unlinkaccounts": "Відв'язати облікові записи",
+ "unlinkaccounts-success": "Обліковий запис було відв'язано."
}
"عثمان خان شاہ",
"Syedalinaqinaqvi",
"محمد افضل",
- "Macofe"
+ "Macofe",
+ "Hindustanilanguage"
]
},
"tog-underline": "ربط کی خط کشیدگی:",
"noname": "آپ نے صحیح اسم صارف نہیں چنا.",
"loginsuccesstitle": "داخلہ کامیاب",
"loginsuccess": "'''اب آپ {{SITENAME}} میں بنام \"$1\" داخل ہوچکے ہیں۔'''",
- "nosuchuser": "\"$1\" کے نام سے کوئی صارف موجود نہیں ہے.\nبرائے مہربانی! ہجوں کے درست اندراج کی تصدیق کرلیجئے.\nاگر آپ چاہیں تو [[Special:UserLogin/signup|نیا کھاتہ بھی بناسکتے ہیں]].",
+ "nosuchuser": "\"$1\" کے نام سے کوئی صارف موجود نہیں ہے.\nبرائے مہربانی! ہجوں کے درست اندراج کی تصدیق کرلیجئے.\nاگر آپ چاہیں تو [[Special:CreateAccount|نیا کھاتہ بھی بناسکتے ہیں]].",
"nosuchusershort": "\"$1\" کے نام سے کوئی صارف موجود نہیں.\nاپنا ہجہ جانچئے.",
"nouserspecified": "آپ کو ایک اسمِ صارف مخصوص کرنا ہے.",
"login-userblocked": "اِس صارف پر پابندی ہے. داخلِ نوشتہ ہونے کی اجازت نہیں.",
"accmailtext": "[[User talk:$1|$1]] کے لیے خودکار طریقے سے تخلیق کیا گیا پاسورڈ $2 کو بھیج دیا گیا ہے.\n\nلاگ ان ہونے کے بعد <em>[[Special:ChangePassword|اسے تبدیل]]</em> کیا جا سکتا ہے۔",
"newarticle": "(نیا)",
"newarticletext": "آپ نے ایک ایسے صفحے کے ربط کی پیروی کی ہے جو کہ ابھی موجود نہیں ہے.\nیہ صفحہ تخلیق کرنے کیلئے درج ذیل خانہ میں متن درج کیجئے (مزید معلومات کیلئے [$1 صفحۂ معاونت] ملاحظہ فرمائیے).\nاگر آپ یہاں غلطی سے پہنچے ہیں تو پچھلے صفحے پر واپس جانے کیلئے اپنے متصفح پر '''back''' کا بٹن ٹک کیجئے.",
- "anontalkpagetext": "----''یہ صفحہ ایک ایسے صارف کا ہے جنہوں نے یا تو اب تک اپنا کھاتا نہیں بنایا یا پھر وہ اسے استعمال نہیں کر رہے/ رہی ہیں۔ لہٰذا ہمیں انکی شناخت کے لئے ایک عددی آئی پی پتہ استعمال کرنا پڑرہا ہے۔ اس قسم کا آئی پی پتہ ایک سے زائد صارفین کے لئے مشترک بھی ہوسکتا ہے۔ اگر آپکی موجودہ حیثیت ایک گمنام صارف کی ہے اور آپ محسوس کریں کہ اس صفحہ پر آپکی جانب منسوب یہ بیان غیرضروری ہے تو براہ کرم [[Special:UserLogin/signup|کھاتہ بنائیں]] یا [[Special:UserLogin|داخلِ نوشتہ]] ہوجائیے تاکہ مستقبل میں آپکو گمنام صارفین میں شمار کرنے سے پرہیز کیا جاسکے۔\"",
+ "anontalkpagetext": "----''یہ صفحہ ایک ایسے صارف کا ہے جنہوں نے یا تو اب تک اپنا کھاتا نہیں بنایا یا پھر وہ اسے استعمال نہیں کر رہے/ رہی ہیں۔ لہٰذا ہمیں انکی شناخت کے لئے ایک عددی آئی پی پتہ استعمال کرنا پڑرہا ہے۔ اس قسم کا آئی پی پتہ ایک سے زائد صارفین کے لئے مشترک بھی ہوسکتا ہے۔ اگر آپکی موجودہ حیثیت ایک گمنام صارف کی ہے اور آپ محسوس کریں کہ اس صفحہ پر آپکی جانب منسوب یہ بیان غیرضروری ہے تو براہ کرم [[Special:CreateAccount|کھاتہ بنائیں]] یا [[Special:UserLogin|داخلِ نوشتہ]] ہوجائیے تاکہ مستقبل میں آپکو گمنام صارفین میں شمار کرنے سے پرہیز کیا جاسکے۔\"",
"noarticletext": "اِس صفحہ میں فی الحال کوئی متن موجود نہیں ہے.\nآپ دیگں صفحات میں [[Special:Search/{{PAGENAME}}|اِس صفحہ کے عنوان کیلئے تلاش کرسکتے ہیں]]، <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} متعلقہ نوشتہ جات تلاش کرسکتے ہیں],\nیا [{{fullurl:{{FULLPAGENAME}}|action=edit}} اِس صفحہ میں ترمیم کرسکتے ہیں]</span>",
"noarticletext-nopermission": "اس صفحہ میں فی الحال کوئی متن موجود نہیں ہے.\nآپ دیگں صفحات میں [[Special:Search/{{PAGENAME}}|اِس صفحہ کے عنوان کیلئے]] یا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} متعلقہ نوشتہ جات تلاش کرسکتے ہیں]</span>",
"userpage-userdoesnotexist-view": "صارف کھاتہ \"$1\" مندرج نہیں ہے۔",
"allmessagesdefault": "طے شدہ متن",
"allmessagescurrent": "موجودہ متن",
"allmessagestext": "یہ میڈیاویکی: جاۓ نام میں دستیاب نظامی پیغامات کی فہرست ہے۔",
+ "allmessages-filter": "تلاش بلحاظ:",
"allmessages-filter-all": "تمام",
"allmessages-filter-modified": "تبدیل شدہ",
+ "allmessages-prefix": "تلاش بلحاظ سابقہ:",
"allmessages-language": "زبان:",
"allmessages-filter-submit": "ٹھیک",
"allmessages-filter-translate": "ترجمہ",
"monthsall": "تمام",
"deletedwhileediting": "انتباہ: آپ کے ترمیم شروع کرنے کے بعد یہ صفحہ حذف کیا جا چکا ہے!",
"confirm_purge_button": "جی!",
+ "confirm-rollback-button": "ٹھیک ہے",
"semicolon-separator": "؛ ",
"imgmultipageprev": "← پچھلا",
"imgmultipagenext": "اگلا →",
"logentry-delete-delete": "$1 {{GENDER:$2|حذف کیا گیا}} صفحہ $3",
"logentry-move-move": "$1 نے صفحہ $3 کو بجانب $4 منتقل کیا",
"logentry-newusers-create": "صارف کھاتہ $1 {{GENDER:$2|بنایا گیا}}",
+ "logentry-protect-modify": "$1 نے $3 کا درجۂ حفاظت {{GENDER:$2|تبدیل کیا}} $4",
"logentry-upload-upload": "$1 {{GENDER:$2|اپلوڈ}} $3",
"rightsnone": "(کچھ نہیں)",
"revdelete-summary": "خلاصۂ تدوین",
"accmailtitle": "Maxfiy soʻz joʻnatildi",
"newarticle": "(Yangi)",
"newarticletext": "Bu sahifa hali mavjud emas.\nSahifani yaratish uchun quyida matn kiritishingiz mumkin (qoʻshimcha axborot uchun [$1 yordam sahifasini] koʻring).\nAgar bu sahifaga xatolik sabab kelib qolgan boʻlsangiz brauzeringizning '''orqaga''' tugmasini bosing.",
- "anontalkpagetext": "----\n<em>Ushbu munozara sahifasi hisob yozuvi yaratmagan (yoki yaratishni xohlamaydigan) anonim foydalanuvchiga tegishli.</em>\n\nShu sababli, uni aniqlash uchun raqamli IP-manzildan foydalaniladi.\nUshbu IP-manzil bir nechta foydalanuvchilarga tegishli boʻlishi mumkin.\nAgar siz anonim foydalanuvchi boʻlsangiz va qoldirilgan xabarlar sizga yoʻnaltirilmagan deb hisoblasangiz, iltimos, boshqa anonim foydalanuvchilar bilan adashtirib yubormasliklari uchun [[Special:UserLogin/signup|hisob yozuvi yarating]] yoki [[Special:UserLogin|tizimga kiring]].",
+ "anontalkpagetext": "----\n<em>Ushbu munozara sahifasi hisob yozuvi yaratmagan (yoki yaratishni xohlamaydigan) anonim foydalanuvchiga tegishli.</em>\n\nShu sababli, uni aniqlash uchun raqamli IP-manzildan foydalaniladi.\nUshbu IP-manzil bir nechta foydalanuvchilarga tegishli boʻlishi mumkin.\nAgar siz anonim foydalanuvchi boʻlsangiz va qoldirilgan xabarlar sizga yoʻnaltirilmagan deb hisoblasangiz, iltimos, boshqa anonim foydalanuvchilar bilan adashtirib yubormasliklari uchun [[Special:CreateAccount|hisob yozuvi yarating]] yoki [[Special:UserLogin|tizimga kiring]].",
"noarticletext": "Bu sahifada hozircha hech qanday matn yoʻq. Siz bu sarlavhani boshqa sahifalardan [[Special:Search/{{PAGENAME}}|qidirishingiz]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tegishli qaydlarga qarashingiz] yoki bu sahifani [{{fullurl:{{FULLPAGENAME}}|action=edit}} tahrirlashingiz]</span> mumkin.",
"userpage-userdoesnotexist-view": "\"$1\" foydalanuvchi hisobi roʻyxatga olinmagan.",
"clearyourcache": "'''Eslatma.''' Saqlaganingizdan so'ng o'zgarishlarni ko'rish uchun siz o'z brauzeringiz keshini tozalashingizga to'gri kelishi mumkin.\n* '''Firefox / Safari:''' ''Shift'' tugmasini bosgan holda, ''Yangilash'' unsurlar darchasini bosing, yoki ''Ctrl-F5'' yoki ''Ctrl-R'' (Macda ''⌘-R'') ni bosing\n* '''Google Chrome:''' ''Ctrl-Shift-R'' (Macda ''⌘-Shift-R'') ni bosing\n* '''Internet Explorer:''' ''Ctrl''ni bosgan holda, ''Yangilash''ni bosing, yoki ''Ctrl-F5''ni bosing\n* '''Opera:''' ''Asboblar → Moslamalar'' menyusidan keshni tozalashni tanlang",
"categories": "Turkumlar",
"categoriespagetext": "Quyidagi {{PLURAL:$1|turkumda|turkumlarda}} sahifa yoki media-fayllar mavjud.\n[[Special:UnusedCategories|Ishlatilmayotgan turkumlar]] bu yerda koʻrsatilmaydi.\nShuningdek qarang: [[Special:WantedCategories|talab qilinayotgan turkumlar]].",
"categoriesfrom": "Quyidagidan boshlanuvchi turkumlarni koʻrsatish:",
- "special-categories-sort-count": "miqdori bo‘yicha saralash",
- "special-categories-sort-abc": "alifbo bo‘yicha saralash",
"deletedcontributions": "Foydalanuvchining o‘chirilgan hissasi",
"deletedcontributions-title": "O‘chirilgan foydalanuvchilar hissalari",
"sp-deletedcontributions-contribs": "hissa",
"noname": "El nome utente indicà no xè vałido.",
"loginsuccesstitle": "Aceso efetuà",
"loginsuccess": "'''Te si sta conesso al server de {{SITENAME}} con el nome utente de \"$1\".'''",
- "nosuchuser": "Nol xè rejistrà alcun utente de nome \"$1\". I nomi utente i xè sensibiłi a łe majuscołe. Verifegare el nome inserio o [[Special:UserLogin/signup|creare on novo aceso]].",
+ "nosuchuser": "Nol xè rejistrà alcun utente de nome \"$1\". I nomi utente i xè sensibiłi a łe majuscołe. Verifegare el nome inserio o [[Special:CreateAccount|creare on novo aceso]].",
"nosuchusershort": "No ghe xe nissun utente de nome \"$1\". Sito sicuro che te lo ghè scrito ben?",
"nouserspecified": "Te ghè da métar un nome utente.",
"login-userblocked": "Sta utensa xè blocà. No xè posibiłe efetuare el login.",
"accmailtext": "Na password xenerà casualmente par [[User talk:$1|$1]] la xe stà mandà a $2.\n\nLa password par sta nova utensa la pode vegner canbià, dopo ver fato l'acesso, su la pàxena ''[[Special:ChangePassword|canbiar la password]]''.",
"newarticle": "(Novo)",
"newarticletext": "Te ghe sì 'ndà drio a un colegamento a na pagina che no esiste gnancora.\nSe te voli crear sta pagina, taca scrìvar el testo in te la casèla qua soto\n(varda le [$1 pagine de ajuto] par saverghene de pì).\nSe te sì rivà qua par sbajo, basta che te struchi '''Indrìo''' sul to browser.",
- "anontalkpagetext": "----''Sta qua la xe la pagina de discussion de un utente anonimo che no'l se gà gnancora registrà o che no'l xe entrà col so nome utente.\nDe conseguenza xè necessario identificarlo tramite l'indirizo IP numerico.\nSto indirizo el pode èssar doparà da tanti utenti.\nSe te sì un utente anonimo e te ghè ricevù dei messagi che te secondo ti i gera par qualchedun altro, te podi [[Special:UserLogin/signup|registrarte]] o [[Special:UserLogin|entrar col to nome utente]] par evitar confusion con altri utenti anonimi in futuro.''",
+ "anontalkpagetext": "----''Sta qua la xe la pagina de discussion de un utente anonimo che no'l se gà gnancora registrà o che no'l xe entrà col so nome utente.\nDe conseguenza xè necessario identificarlo tramite l'indirizo IP numerico.\nSto indirizo el pode èssar doparà da tanti utenti.\nSe te sì un utente anonimo e te ghè ricevù dei messagi che te secondo ti i gera par qualchedun altro, te podi [[Special:CreateAccount|registrarte]] o [[Special:UserLogin|entrar col to nome utente]] par evitar confusion con altri utenti anonimi in futuro.''",
"noarticletext": "In sto momento no ghe xe nissun testo su sta pagina.\nTe pol [[Special:Search/{{PAGENAME}}|sercar el titolo de sta pagina]] in altre pagine,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sercar in tei registri ligà a sta pagina] o se nò [{{fullurl:{{FULLPAGENAME}}|action=edit}} canbiar la pagina]</span>.",
"noarticletext-nopermission": "In sto momento no ghe xe nissun testo su sta pagina.\nTe pol [[Special:Search/{{PAGENAME}}|sercar sto titolo de pagina]] in altre pagine,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sercar in tei registri ligà a sta pagina]</span>, ma no te ghè el parmesso de crear sta pagina.",
"missing-revision": "Ła revixion #$1 de ła pàjina \"{{FULLPAGENAME}}\" nó ła existe.",
"noname": "Tö ei olgoi kirjutanuded lasktud kävutajan nimed.",
"loginsuccesstitle": "Tulend sistemha om lopnus satusekahas.",
"loginsuccess": "'''Tö radat nügüd' {{SITENAME}}-saital kut \"$1\".'''",
- "nosuchuser": "Ei ole kävutajad \"$1\"-nimenke.\nKävutajan nimiden oigedkirjutamine rippub kirjamiden registraspäi.\nKodvgat teiden oigedkirjutamine, vai [[Special:UserLogin/signup|säkat uz' registracii]].",
+ "nosuchuser": "Ei ole kävutajad \"$1\"-nimenke.\nKävutajan nimiden oigedkirjutamine rippub kirjamiden registraspäi.\nKodvgat teiden oigedkirjutamine, vai [[Special:CreateAccount|säkat uz' registracii]].",
"nosuchusershort": "Ei ole kävutajad \"$1\"-nimenke.\nKodvgat teiden oigedkirjutamine.",
"nouserspecified": "Pidab kirjutada kävutajan nimi.",
"login-userblocked": "Nece kävutai om blokiruidud. Tulend sistemha om kel'tud.",
"rcnotefrom": "Alemba oma anttud toižetused '''$2'''-späi ( '''$1'''-hesai).",
"rclistfrom": "Ozutada uded toižetused dataspäi $3 $2 augotaden",
"rcshowhideminor": "$1 pened redakcijad",
+ "rcshowhideminor-show": "Ozutada",
"rcshowhideminor-hide": "Peitta",
"rcshowhidebots": "$1 botad",
"rcshowhidebots-show": "Ozutada",
+ "rcshowhidebots-hide": "Peitta",
"rcshowhideliu": "$1 sistemha kirjutadud kävutajad",
"rcshowhideliu-hide": "Peitta",
"rcshowhideanons": "$1 anonimišt kävutajad",
"rcshowhideanons-hide": "Peitta",
"rcshowhidepatr": "$1 kodvdud toižetust",
"rcshowhidemine": "$1 ičein redakcijad",
+ "rcshowhidemine-show": "Ozutada",
"rcshowhidemine-hide": "Peitta",
"rclinks": "Ozutada jäl'gmäižed $1 toižetust $2 päiväs<br />$3",
"diff": "erod",
"booksources": "Kirjpurtked",
"booksources-search-legend": "Ectä kirjpurtkid",
"booksources-isbn": "ISBN:",
+ "booksources-search": "Ectä",
"booksources-text": "Naku om kosketusid saitoile, kudambil mödas uzid da kuluid kirjoid. Niilpäi voib löuta ližainformacijad ectud kirjoiš:",
"booksources-invalid-isbn": "Nece ISBN, näguse, om vär; Kodvgat, oikti-k oled kopiruinuded sidä originaližes purtkespäi.",
"specialloguserlabel": "Kävutai:",
"tog-ccmeonemails": "Gửi bản sao cho tôi khi gửi thư điện tử cho người khác",
"tog-diffonly": "Không hiển thị nội dung trang dưới phần so sánh phiên bản",
"tog-showhiddencats": "Hiển thị thể loại ẩn",
- "tog-norollbackdiff": "Không so sánh sau khi lùi sửa",
+ "tog-norollbackdiff": "Bỏ qua bản so sánh sau khi lùi sửa",
"tog-useeditwarning": "Cảnh báo khi tôi thoát trang sửa đổi mà chưa lưu trang",
"tog-prefershttps": "Luôn kết nối an toàn khi đăng nhập",
"underline-always": "Luôn luôn",
"password-change-forbidden": "Bạn không thể đổi mật khẩu trên wiki này.",
"externaldberror": "Có lỗi khi xác nhận cơ sở dữ liệu bên ngoài hoặc bạn không được phép cập nhật tài khoản bên ngoài.",
"login": "Đăng nhập",
+ "login-security": "Xác minh danh tính của bạn",
"nav-login-createaccount": "Đăng nhập / Mở tài khoản",
"userlogin": "Đăng nhập / Mở tài khoản",
"userloginnocreate": "Đăng nhập",
"userlogin-resetpassword-link": "Quên mật khẩu?",
"userlogin-helplink2": "Trợ giúp đăng nhập",
"userlogin-loggedin": "Bạn đã đăng nhập với tên {{GENDER:$1}}$1.\nHãy sử dụng biểu mẫu ở dưới để đăng nhập với tài khoản người dùng khác.",
+ "userlogin-reauth": "Bạn phải đăng nhập lại để xác minh rằng bạn là $1.",
"userlogin-createanother": "Mở thêm tài khoản",
"createacct-emailrequired": "Địa chỉ thư điện tử",
"createacct-emailoptional": "Địa chỉ thư điện tử (tùy chọn)",
"createacct-email-ph": "Nhập địa chỉ thư điện tử của bạn",
"createacct-another-email-ph": "Nhập địa chỉ thư điện tử",
"createaccountmail": "Sử dụng mật khẩu ngẫu nhiên tạm và gửi nó cho địa chỉ thư điện tử được chỉ định",
+ "createaccountmail-help": "Có thể sử dụng để tạo tài khoản cho người khác mà không được biết mật khẩu.",
"createacct-realname": "Tên thật (tùy chọn)",
"createaccountreason": "Lý do:",
"createacct-reason": "Lý do",
"createacct-reason-ph": "Nhập lý do tạo một tài khoản khác",
+ "createacct-reason-help": "Thông điệp xuất hiện trong nhật trình tạo tài khoản",
"createacct-submit": "Tạo tài khoản",
"createacct-another-submit": "Mở tài khoản",
+ "createacct-continue-submit": "Tiếp tục tạo tài khoản",
+ "createacct-another-continue-submit": "Tiếp tục tạo tài khoản",
"createacct-benefit-heading": "{{SITENAME}} được xây dựng bởi những người như bạn.",
"createacct-benefit-body1": "{{PLURAL:$1}}lần sửa đổi",
"createacct-benefit-body2": "{{PLURAL:$1}}trang nội dung",
"nocookiesnew": "Bạn đã tạo tài khoản thành công, nhưng bạn chưa đăng nhập. {{SITENAME}} sử dụng cookie để đăng nhập vào tài khoản. Bạn đã tắt cookie. Xin hãy bật cookie lên, rồi đăng nhập lại với tên người dùng và mật khẩu mới.",
"nocookieslogin": "{{SITENAME}} sử dụng cookie để đăng nhập thành viên. Bạn đã tắt cookie. Xin hãy kích hoạt rồi thử lại.",
"nocookiesfornew": "Không thể mở tài khoản vì không thể xác nhận nguồn yêu cầu nó.\nHãy chắc chắn bạn đã bật lên cookie, làm mới trang này, và thử lại.",
+ "createacct-loginerror": "Bạn đã tạo tài khoản thành công nhưng không thể tự động đăng nhập. Xin hãy [[Special:UserLogin|đăng nhập thủ công]].",
"noname": "Chưa nhập tên.",
"loginsuccesstitle": "Đã đăng nhập",
"loginsuccess": "'''Bạn đã đăng nhập vào {{SITENAME}} với tên “$1”.'''",
- "nosuchuser": "Không có thành viên nào có tên “$1”.\nTên người dùng có phân biệt chữ hoa chữ thường.\nHãy kiểm tra lại chính tả, hoặc [[Special:UserLogin/signup|mở tài khoản mới]].",
+ "nosuchuser": "Không có thành viên nào có tên “$1”.\nTên người dùng có phân biệt chữ hoa chữ thường.\nHãy kiểm tra lại chính tả, hoặc [[Special:CreateAccount|mở tài khoản mới]].",
"nosuchusershort": "Không có thành viên nào có tên “$1”. Xin hãy kiểm tra lại chính tả.",
"nouserspecified": "Bạn phải chỉ định một tên người dùng.",
"login-userblocked": "Thành viên này đã bị cấm. Không cho phép đăng nhập.",
"createacct-another-realname-tip": "Tên thật là không bắt buộc. \n\nNếu bạn đồng ý cung cấp, nó sẽ dùng để ghi nhận công lao của bạn.",
"pt-login": "Đăng nhập",
"pt-login-button": "Đăng nhập",
+ "pt-login-continue-button": "Tiếp tục đăng nhập",
"pt-createaccount": "Mở tài khoản",
"pt-userlogout": "Đăng xuất",
"php-mail-error-unknown": "Lỗi không rõ trong hàm PHP mail()",
"botpasswords-invalid-name": "Tên người dùng đã chỉ định không chứa dấu tách mật khẩu bot (\"$1\").",
"botpasswords-not-exist": "Người dùng \"$1\" không có mật khẩu bot có tên \"$2\".",
"resetpass_forbidden": "Không được đổi mật khẩu",
+ "resetpass_forbidden-reason": "Không thể đổi mật khẩu: $1",
"resetpass-no-info": "Bạn phải đăng nhập mới có thể truy cập trực tiếp trang này.",
"resetpass-submit-loggedin": "Thay đổi mật khẩu",
"resetpass-submit-cancel": "Hủy bỏ",
"passwordreset-emailsentusername": "Nếu một địa chỉ thư điện tử đã gắn với tên người dùng này thì một thư điện tử để đặt lại mật khẩu sẽ được gửi đến.",
"passwordreset-emailsent-capture": "Thư điện tử để tái tạo mật khẩu đã được gửi, nội dung như sau.",
"passwordreset-emailerror-capture": "Chúng tôi đã tạo thư tái tạo mật khẩu dưới đây, nhưng không thể gửi đến {{GENDER:$2}}người dùng: $1",
+ "passwordreset-emailsent-capture2": "Đã gửi {{PLURAL:$1|thư điện tử|các thư điện tử}} để đặt lại mật khẩu. {{PLURAL:$1|Tên người dùng và mật khẩu|Các tên người dùng và mật khẩu}} được liệt kê dưới đây.",
+ "passwordreset-emailerror-capture2": "Không gửi được thư điện tử đến {{GENDER:$2}}người dùng: $1 {{PLURAL:$3|Tên người dùng và mật khẩu|Các tên người dùng và mật khẩu}} được liệt kê dưới đây.",
+ "passwordreset-nocaller": "Yêu cầu hàm gọi",
+ "passwordreset-nosuchcaller": "Hàm gọi không tồn tại: $1",
+ "passwordreset-ignored": "Tác vụ đặt lại mật khẩu không được xử lý. Có lẽ trình cung cấp chưa được cấu hình?",
+ "passwordreset-invalideamil": "Địa chỉ thư điện tử không hợp lệ",
+ "passwordreset-nodata": "Cả tên người dùng và địa chỉ thư điện tử bị thiếu",
"changeemail": "Đổi hoặc gỡ địa chỉ thư điện tử",
"changeemail-header": "Điền biểu mẫu này để đổi địa chỉ thư điện tử của bạn. Nếu bạn muốn gỡ địa chỉ thư điện tử nào khỏi tài khoản của bạn, để trống hộp địa chỉ thư điện tử mới và lưu biểu mẫu.",
"changeemail-passwordrequired": "Bạn sẽ cần phải nhập mật khẩu của bạn để xác nhận thay đổi này.",
"accmailtext": "Một mật khẩu được tạo ngẫu nhiên cho [[User talk:$1|$1]] đã được gửi đến $2. Có thể đổi mật khẩu tại trang ''[[Special:ChangePassword|đổi mật khẩu]]'' sau khi đã đăng nhập.",
"newarticle": "(Mới)",
"newarticletext": "Bạn đi đến đây từ một liên kết đến một trang chưa tồn tại. Để tạo trang, hãy bắt đầu gõ vào ô bên dưới (xem [$1 trang trợ giúp] để có thêm thông tin). Nếu bạn đến đây do nhầm lẫn, chỉ cần nhấn vào nút '''Lùi''' (hoặc Trở lại, Quay lại, Back) trong trình duyệt của bạn.",
- "anontalkpagetext": "----''Đây là trang thảo luận của một người dùng vô danh chưa tạo tài khoản hoặc có tài khoản nhưng không đăng nhập.\nDo đó chúng ta phải dùng một dãy số gọi là địa chỉ IP để xác định anh/chị ta.\nMột địa chỉ IP như vậy có thể có nhiều người cùng dùng chung.\nNếu bạn là một thành viên vô danh và cảm thấy rằng có những lời bàn luận không thích hợp đang nhắm vào bạn, xin hãy [[Special:UserLogin/signup|tạo tài khoản]] hoặc [[Special:UserLogin|đăng nhập]] để tránh sự nhầm lẫn về sau với những thành viên vô danh khác.''",
+ "anontalkpagetext": "----\n<em>Đây là trang thảo luận của một người dùng vô danh chưa tạo tài khoản hoặc có tài khoản nhưng không đăng nhập.</em>\nDo đó chúng ta phải dùng một dãy số gọi là địa chỉ IP để xác định anh/chị ta.\nMột địa chỉ IP như vậy có thể có nhiều người cùng dùng chung.\nNếu bạn là một thành viên vô danh và cảm thấy rằng có những lời bàn luận không thích hợp đang nhắm vào bạn, xin hãy [[Special:CreateAccount|tạo tài khoản]] hoặc [[Special:UserLogin|đăng nhập]] để tránh sự nhầm lẫn về sau với những thành viên vô danh khác.",
"noarticletext": "Trang này hiện chưa có nội dung.\nBạn có thể [[Special:Search/{{PAGENAME}}|tìm kiếm tựa trang này]] trong các trang khác, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tìm trong các nhật trình liên quan],\nhoặc [{{fullurl:{{FULLPAGENAME}}|action=edit}} tạo mới trang này]</span>.",
"noarticletext-nopermission": "Trang này hiện đang trống.\nBạn có thể [[Special:Search/{{PAGENAME}}|tìm kiếm tựa trang này]] tại các trang khác, hoặc <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tìm kiếm các nhật trình liên quan]</span>, nhưng bạn không được phép tạo trang này.",
"missing-revision": "Phiên bản #$1 của trang có tên “{{FULLPAGENAME}}” không tồn tại.\n\nLỗi này thường xuất hiện đối khi theo dõi liên kết lỗi thời đến phiên bản cũ của một trang đã bị xóa.\nXem chi tiết trong [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} nhật trình xóa].",
"undo-failure": "Sửa đổi không thể phục hồi vì đã có những sửa đổi mới ở sau.",
"undo-norev": "Sửa đổi không thể hồi phục vì nó không tồn tại hoặc đã bị xóa.",
"undo-nochange": "Hình như sửa đổi này đã được lùi lại rồi.",
- "undo-summary": "Đã lùi lại sửa đổi $1 của [[Special:Contributions/$2|$2]] ([[User talk:$2|Thảo luận]])",
+ "undo-summary": "Đã lùi lại sửa đổi $1 của [[Special:Contributions/$2|$2]] ([[User talk:$2|thảo luận]])",
"undo-summary-username-hidden": "Đã lùi lại sửa đổi $1 của một người dùng ẩn",
"cantcreateaccounttitle": "Không thể mở tài khoản",
"cantcreateaccount-text": "Chức năng tài tạo khoản từ địa chỉ IP này ('''$1''') đã bị [[User:$3|$3]] cấm.\n\nLý do được $3 đưa ra là ''$2''",
"prefs-watchlist-days-max": "Tối đa $1 ngày",
"prefs-watchlist-edits": "Số lần sửa đổi tối đa trong danh sách theo dõi mở rộng:",
"prefs-watchlist-edits-max": "Con số tối đa: 1.000",
- "prefs-watchlist-token": "Số thẻ Danh sách theo dõi:",
+ "prefs-watchlist-token": "Dấu hiệu cho danh sách theo dõi:",
"prefs-misc": "Linh tinh",
"prefs-resetpass": "Thay đổi mật khẩu",
"prefs-changeemail": "Đổi hoặc gỡ địa chỉ thư điện tử",
"right-override-export-depth": "Xuất trang kèm theo các trang được liên kết đến với độ sâu tối đa là 5",
"right-sendemail": "Gửi thư điện tử cho thành viên khác",
"right-passwordreset": "Xem các thư điện tử đặt lại mật khẩu",
- "right-managechangetags": "Tạo và xóa [[Special:Tags|thẻ]] từ cơ sở dữ liệu",
+ "right-managechangetags": "Tạo và bật/tắt [[Special:Tags|thẻ]]",
"right-applychangetags": "Áp dụng [[Special:Tags|thẻ]], cùng với những thay đổi của một người",
"right-changetags": "Thêm và loại bỏ tùy ý các [[Special:Tags|thẻ]] vào các phiên bản riêng và các mục nhật trình",
+ "right-deletechangetags": "Xóa [[Special:Tags|thẻ]] khỏi cơ sở dữ liệu",
"grant-generic": "Gói quyền “$1”",
"grant-group-page-interaction": "Tương tác với trang",
"grant-group-file-interaction": "Tương tác với tập tin",
"action-viewmyprivateinfo": "xem thông tin cá nhân của bạn",
"action-editmyprivateinfo": "sửa đổi thông tin cá nhân của bạn",
"action-editcontentmodel": "sửa kiểu nội dung của trang",
- "action-managechangetags": "tạo và xóa các thẻ từ cơ sở dữ liệu",
+ "action-managechangetags": "tạo và bật/tắt thẻ",
"action-applychangetags": "áp dụng các thẻ cùng với những thay đổi của bạn",
"action-changetags": "thêm và loại bỏ các thẻ tùy ý trên các phiên bản riêng và các mục nhật trình",
+ "action-deletechangetags": "xóa thẻ khỏi cơ sở dữ liệu",
"nchanges": "$1 thay đổi",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sau lần truy cập vừa rồi}}",
"enhancedrc-history": "lịch sử",
"upload-form-label-own-work": "Đây là tác phẩm của chính tôi",
"upload-form-label-infoform-categories": "Thể loại",
"upload-form-label-infoform-date": "Ngày tháng",
- "upload-form-label-own-work-message-local": "Tôi xác nhận rằng tôi tải lên tập tin này tuân theo các điều khoản sử dụng và quy định giấy phép của {{SITENAME}}.",
- "upload-form-label-not-own-work-message-local": "Nếu bạn không được phép tải lên tập tin này tuân theo quy định của {{SITENAME}}, xin vui lòng đóng hộp thoại này và thử tải lên bằng một phương pháp khác.",
- "upload-form-label-not-own-work-local-local": "Bạn cũng có thể muốn sử dụng [[Special:Upload|trang tải lên mặc định]].",
- "upload-form-label-own-work-message-default": "Tôi hiểu rằng tôi đang tải tập tin này lên một kho dùng chung. Tôi xác nhận rằng tôi làm việc này tuân theo các điều khoản sử dụng và quy định về giấy phép tại đấy.",
- "upload-form-label-not-own-work-message-default": "Nếu bạn không có thể tải tập tin này lên mà tuân theo quy định của kho dùng chung, xin vui lòng đóng hộp thoại này và thử một cách khác.",
- "upload-form-label-not-own-work-local-default": "Bạn có thể muốn thử [[Special:Upload|trang tải lên tại {{SITENAME}}]] nếu tập tin này có thể được tải lên đấy theo các quy định của họ.",
- "upload-form-label-own-work-message-shared": "Tôi khẳng định rằng tôi giữ quyền tác giả của tập tin này và đồng ý phát hành, một cách không thể hủy bỏ, tập tin này cho Wikimedia Commons theo giấy phép [https://creativecommons.org/licenses/by-sa/4.0/deed.vi Creative Commons Ghi công–Chia sẻ tương tự 4.0], và tôi chấp nhận các [https://wikimediafoundation.org/wiki/Terms_of_Use/vi?uselang=vi Điều khoản Sử dụng].",
- "upload-form-label-not-own-work-message-shared": "Nếu bạn không giữ quyền tác giả của tập tin hoặc muốn phát hành nó theo một giấy phép khác, xin nghĩ đến việc sử dụng [https://commons.wikimedia.org/wiki/Special:UploadWizard?uselang=vi Trình thuật sĩ tải lên Commons].",
- "upload-form-label-not-own-work-local-shared": "Bạn cũng có thể muốn thử [[Special:Upload|trang tải lên tại {{SITENAME}}]] nếu trang đó cho phép tải lên tập tin này theo các quy định của họ.",
+ "upload-form-label-own-work-message-generic-local": "Tôi xác nhận rằng tôi tải lên tập tin này tuân theo các điều khoản sử dụng và quy định giấy phép của {{SITENAME}}.",
+ "upload-form-label-not-own-work-message-generic-local": "Nếu bạn không được phép tải lên tập tin này tuân theo quy định của {{SITENAME}}, xin vui lòng đóng hộp thoại này và thử tải lên bằng một phương pháp khác.",
+ "upload-form-label-not-own-work-local-generic-local": "Bạn cũng có thể muốn sử dụng [[Special:Upload|trang tải lên mặc định]].",
+ "upload-form-label-own-work-message-generic-foreign": "Tôi hiểu rằng tôi đang tải tập tin này lên một kho dùng chung. Tôi xác nhận rằng tôi làm việc này tuân theo các điều khoản sử dụng và quy định về giấy phép tại đấy.",
+ "upload-form-label-not-own-work-message-generic-foreign": "Nếu bạn không có thể tải tập tin này lên mà tuân theo quy định của kho dùng chung, xin vui lòng đóng hộp thoại này và thử một cách khác.",
+ "upload-form-label-not-own-work-local-generic-foreign": "Bạn có thể muốn thử [[Special:Upload|trang tải lên tại {{SITENAME}}]] nếu tập tin này có thể được tải lên đấy theo các quy định của họ.",
"backend-fail-stream": "Không thể gửi luồng tập tin $1.",
"backend-fail-backup": "Không thể sao lưu tập tin $1.",
"backend-fail-notexists": "Tập tin $1 không tồn tại.",
"trackingcategories-msg": "Thể loại phần mềm",
"trackingcategories-name": "Tên thông điệp",
"trackingcategories-desc": "Tiêu chuẩn xếp thể loại",
+ "restricted-displaytitle-ignored": "Trang có tên hiển thị được bỏ qua",
+ "restricted-displaytitle-ignored-desc": "Trang có <code><nowiki>{{TÊN_HIỂN_THỊ}}</nowiki></code>, <code><nowiki>{{TÊNHIỂNTHỊ}}</nowiki></code>, hoặc <code><nowiki>{{DISPLAYTITLE}}</nowiki></code> được bỏ qua vì nó không tương đương với tên thật của trang.",
"noindex-category-desc": "Trang này không được các robot đánh chỉ mục vì trang có từ thần chú <code><nowiki>__NOINDEX__</nowiki></code> và nằm trong không gian tên cho phép từ thần chú này.",
"index-category-desc": "Trang này có từ thần chú <code><nowiki>__INDEX__</nowiki></code> và nằm trong một không gian tên cho phép từ thần chú này, nên được các robot đánh chỉ mục, trong khi bình thường nó không được đánh chỉ mục.",
"post-expand-template-inclusion-category-desc": "Kích thước trang sẽ vượt quá <code>$wgMaxArticleSize</code> nếu bung hết toàn bộ bản mẫu, nên một số bản mẫu không được bung.",
"rollbacklinkcount": "lùi tất cả $1 sửa đổi",
"rollbacklinkcount-morethan": "lùi tất cả hơn $1 sửa đổi",
"rollbackfailed": "Lùi sửa đổi không thành công",
+ "rollback-missingparam": "Yêu cầu thiếu những tham số bắt buộc.",
"cantrollback": "Không lùi sửa đổi được;\nngười viết trang cuối cùng cũng là tác giả duy nhất của trang này.",
"alreadyrolled": "Không thể lùi tất cả sửa đổi cuối của [[User:$2|$2]] ([[User talk:$2|thảo luận]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) tại [[:$1]]; ai đó đã thực hiện sửa đổi hoặc thực hiện lùi tất cả rồi.\n\nSửa đổi cuối cùng tại trang do [[User:$3|$3]] ([[User talk:$3|thảo luận]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]) thực hiện.",
"editcomment": "Tóm lược sửa đổi: <em>$1</em>.",
"revertpage": "Đã lùi lại sửa đổi của [[Special:Contributions/$2|$2]] ([[User talk:$2|Thảo luận]]) quay về phiên bản cuối của [[User:$1|$1]]",
"revertpage-nouser": "Đã lùi lại sửa đổi của người dùng ẩn quay về phiên bản cuối của {{GENDER:$1}}[[User:$1|$1]]",
"rollback-success": "Đã hủy sửa đổi của $1;\nquay về phiên bản cuối của $2.",
+ "rollback-success-notify": "Đã hủy sửa đổi của $1;\nquay về phiên bản cuối của $2. [$3 Xem thay đổi]",
"sessionfailure-title": "Phiên thất bại",
"sessionfailure": "Dường như có trục trặc với phiên đăng nhập của bạn; thao tác này đã bị hủy để tránh việc cướp quyền đăng nhập. Xin hãy nhấn nút “Back”, tải lại trang đó, rồi thử lại.",
"changecontentmodel": "Thay đổi kiểu nội dung của một trang",
"changecontentmodel-success-text": "Kiểu nội dung của [[:$1]] đã được thay đổi.",
"changecontentmodel-cannot-convert": "Không thể chuyển đổi nội dung [[:$1]] thành nội dung dưới dạng $2.",
"changecontentmodel-nodirectediting": "Kiểu nội dung $1 không hỗ trợ sửa đổi trực tiếp",
+ "changecontentmodel-emptymodels-title": "Không có sẵn kiểu nội dung nào",
+ "changecontentmodel-emptymodels-text": "Không thể chuyển đổi nội dung tại [[:$1]] thành nội dung dưới định dạng nào.",
"log-name-contentmodel": "Nhật trình thay đổi kiểu nội dung",
"log-description-contentmodel": "Sự kiện có liên quan đến kiểu nội dung của trang.",
"logentry-contentmodel-new": "$1 {{GENDER:$2}}đã tạo trang $3 với kiểu nội dung không mặc định “$5”",
"lockdbsuccesstext": "Cơ sở dữ liệu đã bị khóa.\n<br />Nhớ [[Special:UnlockDB|mở khóa]] sau khi bảo trì xong.",
"unlockdbsuccesstext": "Cơ sở dữ liệu đã được mở khóa.",
"lockfilenotwritable": "Tập tin khóa của cơ sở dữ liệu không cho phép ghi. Để khóa hay mở khóa cơ sở dữ liệu, máy chủ web phải có khả năng ghi tập tin.",
+ "databaselocked": "Cơ sở dữ liệu đã được khóa rồi.",
"databasenotlocked": "Cơ sở dữ liệu không bị khóa.",
"lockedbyandtime": "($1 khóa vào $2 lúc $3)",
"move-page": "Di chuyển $1",
"confirm-watch-top": "Bạn có muốn thêm trang này vào danh sách theo dõi của bạn?",
"confirm-unwatch-button": "Ngừng theo dõi",
"confirm-unwatch-top": "Bạn có muốn gỡ trang này khỏi danh sách theo dõi của bạn?",
+ "confirm-rollback-button": "OK",
+ "confirm-rollback-top": "Có muốn lùi lại các sửa đổi trong trang này?",
"ellipsis": "…",
"quotation-marks": "“$1”",
"imgmultipageprev": "← trang trước",
"timezone-local": "Địa phương",
"duplicate-defaultsort": "Cảnh báo: Từ khóa xếp mặc định “$2” ghi đè từ khóa trước, “$1”.",
"duplicate-displaytitle": "<strong>Cảnh báo:</strong> Tên hiển thị “$2” ghi đè tên hiển thị “$1” bên trên.",
+ "restricted-displaytitle": "<strong>Chú ý:</strong> Tên hiển thị “$1” được bỏ qua vì nó không tương đương với tên thật của trang.",
"invalid-indicator-name": "<strong>Lỗi:</strong> Không thể để trống thuộc tính <code>name</code> của cái chỉ trạng thái trang.",
"version": "Phiên bản",
"version-extensions": "Các phần mở rộng được cài đặt",
"tags-delete-not-found": "Thẻ “$1” không tồn tại.",
"tags-delete-too-many-uses": "Thẻ “$1” được áp dụng cho hơn $2 phiên bản, có nghĩa là nó không thể bị xóa.",
"tags-delete-warnings-after-delete": "Thẻ “$1” đã được xóa thành công, nhưng gặp phải {{PLURAL:$2|cảnh báo|các cảnh báo}} sau:",
+ "tags-delete-no-permission": "Bạn không có quyền hạn để xóa các thẻ thay đổi.",
"tags-activate-title": "Kích hoạt thẻ",
"tags-activate-question": "Bạn sắp sửa kích hoạt thẻ “$1”.",
"tags-activate-reason": "Lý do:",
"log-action-filter-suppress-block": "Ẩn giấu người dùng bằng cách cấm",
"log-action-filter-suppress-reblock": "Ẩn giấu người dùng bằng cách cấm lại",
"log-action-filter-upload-upload": "Tải lên mới",
- "log-action-filter-upload-overwrite": "Tải lên lại"
+ "log-action-filter-upload-overwrite": "Tải lên lại",
+ "authmanager-authn-not-in-progress": "Không phải đang xác thực, hoặc dữ liệu phiên làm việc bị mất. Xin hãy thử lại từ đầu.",
+ "authmanager-authn-no-primary": "Không thể xác thực định danh được cung cấp.",
+ "authmanager-authn-no-local-user": "Định danh được cung cấp không ứng với người dùng nào trên wiki này.",
+ "authmanager-authn-no-local-user-link": "Định danh được cung cấp có hợp lệ nhưng không ứng với người dùng nào trên wiki này. Hãy đăng nhập một cách khác hoặc tạo tài khoản mới; bạn sẽ có cơ hội để liên kết định danh cũ với tài khoản mới.",
+ "authmanager-authn-autocreate-failed": "Thất bại khi tự động tạo tài khoản địa phương: $1",
+ "authmanager-change-not-supported": "Không thể thay đổi định danh được cung cấp, vì sẽ không có gì sử dụng nó.",
+ "authmanager-create-disabled": "Chứng năng tạo tài khoản được tắt.",
+ "authmanager-create-from-login": "Để tạo tài khoản của mình, xin hãy điền vào các thông tin bên dưới.",
+ "authmanager-create-not-in-progress": "Không phải đang tạo tài khoản, hoặc dữ liệu phiên làm việc bị mất. Xin hãy thử lại từ đầu.",
+ "authmanager-create-no-primary": "Không thể sử dụng định danh được cung cấp để tạo tài khoản.",
+ "authmanager-link-no-primary": "Không thể sử dụng định danh được cung cấp để liên kết tài khoản.",
+ "authmanager-link-not-in-progress": "Không phải đang liên kết tài khoản, hoặc dữ liệu phiên làm việc bị mất. Xin hãy thử lại từ đầu.",
+ "authmanager-authplugin-setpass-failed-title": "Thay đổi mật khẩu bị thất bại",
+ "authmanager-authplugin-setpass-failed-message": "Phần bổ trợ xác thực đã từ chối việc đổi mật khẩu.",
+ "authmanager-authplugin-create-fail": "Phần bổ trợ xác thực đã từ chối việc tạo tài khoản.",
+ "authmanager-authplugin-setpass-denied": "Phần bổ trợ xác thực không cho phép đổi mật khẩu.",
+ "authmanager-authplugin-setpass-bad-domain": "Tên miền không hợp lệ.",
+ "authmanager-autocreate-noperm": "Không cho phép tự động tạo tài khoản.",
+ "authmanager-autocreate-exception": "Tạm thời không cho phép tự động tạo tài khoản vì các lỗi trước đây.",
+ "authmanager-userdoesnotexist": "Chưa có tài khoản với tên “$1”.",
+ "authmanager-userlogin-remembermypassword-help": "Mật khẩu có nên được duy trì sau phiên làm việc hay không.",
+ "authmanager-username-help": "Tên người dùng để xác thực.",
+ "authmanager-password-help": "Mật khẩu để xác thực.",
+ "authmanager-domain-help": "Tên miền để xác thực bên ngoài.",
+ "authmanager-retype-help": "Mật khẩu lần nữa để xác nhận.",
+ "authmanager-email-label": "Thư điện tử",
+ "authmanager-email-help": "Địa chỉ thư điện tử",
+ "authmanager-realname-label": "Tên thật",
+ "authmanager-realname-help": "Tên thật của người dùng",
+ "authmanager-provider-password": "Xác thực qua mật khẩu",
+ "authmanager-provider-password-domain": "Xác thực qua mật khẩu và tên miền",
+ "authmanager-provider-temporarypassword": "Mật khẩu tạm",
+ "authprovider-confirmlink-message": "Dựa trên các lần bạn thử đăng nhập gần đây, có thể liên kết các tài khoản bên dưới với tài khoản wiki của bạn. Sau khi liên kết các tài khoản này, bạn có thể đăng nhập qua chúng. Xin hãy chọn các tài khoản để liên kết.",
+ "authprovider-confirmlink-request-label": "Các tài khoản để liên kết",
+ "authprovider-confirmlink-success-line": "$1: Đã liên kết thành công.",
+ "authprovider-confirmlink-failed": "Việc liên kết tài khoản không hoàn toàn thành công: $1",
+ "authprovider-confirmlink-ok-help": "Tiếp tục sau khi hiển thị các thông báo liên kết thất bại.",
+ "authprovider-resetpass-skip-label": "Bỏ qua",
+ "authprovider-resetpass-skip-help": "Bỏ qua việc đặt lại mật khẩu.",
+ "authform-nosession-login": "Đã xác thực thành công, nhưng trình duyệt của bạn không thể duy trì đăng nhập.\n\n$1",
+ "authform-nosession-signup": "Đã tạo tài khoản thành công, nhưng trình duyệt của bạn không thể duy trì đăng nhập.\n\n$1",
+ "authform-newtoken": "Dấu hiệu bị mất. $1",
+ "authform-notoken": "Dấu hiệu bị mất",
+ "authform-wrongtoken": "Dấu hiệu sai",
+ "specialpage-securitylevel-not-allowed-title": "Không được phép",
+ "specialpage-securitylevel-not-allowed": "Rất tiếc, bạn không được phép sử dụng trang này vì không thể xác nhận danh tính của bạn.",
+ "authpage-cannot-login": "Không thể tiến hành đăng nhập.",
+ "authpage-cannot-login-continue": "Không thể tiếp tục đăng nhập. Có lẽ phiên làm việc của bạn đã hết hạn.",
+ "authpage-cannot-create": "Không thể tiến hành tạo tài khoản.",
+ "authpage-cannot-create-continue": "Không thể tiếp tục tạo tài khoản. Có lẽ phiên làm việc của bạn đã hết hạn.",
+ "authpage-cannot-link": "Không thể tiến hành liên kết tài khoản.",
+ "authpage-cannot-link-continue": "Không thể tiếp tục liên kết tài khoản. Có lẽ phiên làm việc của bạn đã hết hạn.",
+ "cannotauth-not-allowed-title": "Không cho phép",
+ "cannotauth-not-allowed": "Bạn không có quyền sử dụng trang này.",
+ "changecredentials": "Thay đổi định danh",
+ "changecredentials-submit": "Thay đổi định danh",
+ "changecredentials-invalidsubpage": "$1 không phải là kiểu định danh hợp lệ.",
+ "changecredentials-success": "Đã thay đổi định danh của bạn.",
+ "removecredentials": "Xóa định danh",
+ "removecredentials-submit": "Xóa định danh",
+ "removecredentials-invalidsubpage": "$1 không phải là kiểu định danh hợp lệ.",
+ "removecredentials-success": "Đã xóa định danh của bạn.",
+ "credentialsform-provider": "Kiểu định danh:",
+ "credentialsform-account": "Tên tài khoản:",
+ "cannotlink-no-provider-title": "Không có tài khoản liên kết được",
+ "cannotlink-no-provider": "Không có tài khoản liên kết được.",
+ "linkaccounts": "Liên kết tài khoản",
+ "linkaccounts-success-text": "Đã liên kết tài khoản.",
+ "linkaccounts-submit": "Liên kết tài khoản",
+ "unlinkaccounts": "Gỡ liên kết tài khoản",
+ "unlinkaccounts-success": "Đã gỡ liên kết tài khoản."
}
"noname": "No egivol gebananemi lonöföl.",
"loginsuccesstitle": "Enunädol oli benosekiko",
"loginsuccess": "'''Binol anu in {{SITENAME}} as \"$1\".'''",
- "nosuchuser": "No dabinon geban labü nem: \"$1\".\nGebananems distidons mayudis i minudis.\nKoräkolös tonatami nema at, u [[Special:UserLogin/signup|jafolös kali nulik]].",
+ "nosuchuser": "No dabinon geban labü nem: \"$1\".\nGebananems distidons mayudis i minudis.\nKoräkolös tonatami nema at, u [[Special:CreateAccount|jafolös kali nulik]].",
"nosuchusershort": "No dabinon geban labü nem: \"$1\". Koräkolös tonatami nema at.",
"nouserspecified": "Mutol välön gebananemi.",
"wrongpassword": "Letavöd neveräton. Steifülolös dönu.",
"noname": "Võlssi kirotõt pruukjanimi.",
"loginsuccesstitle": "Sisseminek läts' kõrda",
"loginsuccess": "Olõt nimega sisse lännüq. Suq pruukjanimi om \"$1\".",
- "nosuchuser": "\"$1\" nimelist pruukjat olõ-i olõman.\nKaeq kiräpilt üle vai [[Special:UserLogin/signup|luuq vahtsõnõ pruukjanimi]].",
+ "nosuchuser": "\"$1\" nimelist pruukjat olõ-i olõman.\nKaeq kiräpilt üle vai [[Special:CreateAccount|luuq vahtsõnõ pruukjanimi]].",
"nosuchusershort": "\"$1\" nimelist pruukjat olõ-i olõman. Kas kirotit iks nime õigõhe?",
"nouserspecified": "Olõ-i kirotõt pruukjanimme.",
"login-userblocked": "Seo pruukja om kinniq peet. Nimega sisseminemine olõ-õi lubat.",
"accmailtext": "Pruukjalõ '$1' luud johuslinõ salasõna saadõti aadresi pääle $2.\n\nTuud salasõnna saa muutaq ''[[Special:ChangePassword|salasõba muutmisõ lehe pääl]]'' päält vahtsõ nimega sisseminemist.",
"newarticle": "(Vahtsõnõ)",
"newarticletext": "Taad lehekülge olõ-i viil luud.\nLeheküle luumisõs nakkaq kirotama alanolõvahe kasti (kaeq [$1 oppust]).\nKu sa johtuq siiäq kogõmaldaq, sis klõpsaq võrgokaeja '''Tagasi'''-nuppi.",
- "anontalkpagetext": "---- ''Taa om arotusleht nimeldä pruukja kotsilõ, kiä olõ-i loonuq pruukjanimme vai pruugi-i tuud. Tuuperäst tulõ meil pruukja kimmästegemises pruukiq timä puutri võrgoaadrõssit. Taa aadrõs või ollaq mitmõ pruukja pääle ütine. Ku olõt nimeldä pruukja ja lövvät, et taa leheküle pääle kirotõt jutt käü suq kotsilõ, sis olõq hää, [[Special:UserLogin/signup|luuq konto]] vai [[Special:UserLogin|mineq nimega sisse]], et edespiten segähüisi ärq hoitaq.''",
+ "anontalkpagetext": "---- ''Taa om arotusleht nimeldä pruukja kotsilõ, kiä olõ-i loonuq pruukjanimme vai pruugi-i tuud. Tuuperäst tulõ meil pruukja kimmästegemises pruukiq timä puutri võrgoaadrõssit. Taa aadrõs või ollaq mitmõ pruukja pääle ütine. Ku olõt nimeldä pruukja ja lövvät, et taa leheküle pääle kirotõt jutt käü suq kotsilõ, sis olõq hää, [[Special:CreateAccount|luuq konto]] vai [[Special:UserLogin|mineq nimega sisse]], et edespiten segähüisi ärq hoitaq.''",
"noarticletext": "Seo leht om parlaq tühi.\nVõit [[Special:Search/{{PAGENAME}}|otsiq soe lehe nimme]] tõisi lehti päält vai\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} uuriq muutmisnimekirjo] vai [{{fullurl:{{FULLPAGENAME}}|action=edit}} puuduolõva leheküle esiq luvvaq]</span>.",
"noarticletext-nopermission": "Seo lehe pääl olõ-õi parlaq teksti.\nVõit [[Special:Search/{{PAGENAME}}|otsiq soe lehe nimme]] tõisi lehti päält vai\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} uuriq muutmisnimekirjo]</span>, a sul olõ-õi õigust seod lehte alostaq.",
"userpage-userdoesnotexist": "Pruukjanimme \"<nowiki>$1</nowiki>\" olõ-i kirjä pant. Kaeq perrä, kas olõt iks kimmäs, et tahat taad lehte toimõndaq.",
"noname": "Vos n' avoz nén dné di no d' uzeu valide.",
"loginsuccesstitle": "Vos estoz elodjî",
"loginsuccess": "'''L' elodjaedje a stî comifåt, asteure vos estoz elodjî dins {{SITENAME}} dizo l' no d' uzeu «$1».'''",
- "nosuchuser": "I g na nou uzeu dizo l' no «$1».\nNotez k' les nos d' uzeu fjhèt l' diferince etur pitites et grandès letes.\nVerifyîz çou k' vos avoz tapé, oudonbén [[Special:UserLogin/signup|ahivez on novea conte]].",
+ "nosuchuser": "I g na nou uzeu dizo l' no «$1».\nNotez k' les nos d' uzeu fjhèt l' diferince etur pitites et grandès letes.\nVerifyîz çou k' vos avoz tapé, oudonbén [[Special:CreateAccount|ahivez on novea conte]].",
"nosuchusershort": "I g na nou uzeu dizo l' no «$1». Verifyîz çou k' vos avoz tapé.",
"nouserspecified": "Vos dvoz dner on no d' elodjaedje.",
"login-userblocked": "{{GENDER:$1|Cist uzeu est bloké|Ciste uzeuse est blokêye}}. L' elodjaedje n' est nén possibe.",
"accmailtext": "On scret costrût a l' astcheyance po [[User talk:$1|$1]] a stî evoyî a $2.\n\nLi scret po ci novea conte ci pout esse candjî sol pådje di ''[[Special:ChangePassword|candjmint di scret]]'' après l' elodjaedje.",
"newarticle": "(Novea)",
"newarticletext": "Vos avoz clitchî so on loyén viè ene pådje ki n' egzistêye nén co.\nMins '''vos''' l' poloz askepyî! Po çoula, vos n' avoz k' a cmincî a taper vosse tecse dins l' boesse di tecse cial pa dzo (alez vey li [$1 pådje d' aidance] po pus d' infôrmåcion).\nSi vos estoz droci par accidint, clitchîz simplumint sol boton <strong>En erî</strong> di vosse betchteu waibe po rivni al pådje di dvant.",
- "anontalkpagetext": "---- ''Çouchal, c' est li pådje di copene po èn uzeu anonime ki n' a nén (co) fwait on conte por lu s' elodjî, ou ki n' l' eploye nén.\nÇa fwait k' on doet eployî si adresse IP limerike po l' idintifyî.\nCome ene sifwaite adresse IP pout esse eployeye pa pus d' èn uzeu, i s' pout ki vos veyoz chal des rmarkes et des messaedjes ki n' sont nén por vos.\nLoukîz s' i vs plait po [[Special:UserLogin/signup|fé on novea conte]] ou [[Special:UserLogin|s' elodjî]] po n' pus aveur d' ecramiaedje avou des ôtes uzeus anonimes.''",
+ "anontalkpagetext": "---- ''Çouchal, c' est li pådje di copene po èn uzeu anonime ki n' a nén (co) fwait on conte por lu s' elodjî, ou ki n' l' eploye nén.\nÇa fwait k' on doet eployî si adresse IP limerike po l' idintifyî.\nCome ene sifwaite adresse IP pout esse eployeye pa pus d' èn uzeu, i s' pout ki vos veyoz chal des rmarkes et des messaedjes ki n' sont nén por vos.\nLoukîz s' i vs plait po [[Special:CreateAccount|fé on novea conte]] ou [[Special:UserLogin|s' elodjî]] po n' pus aveur d' ecramiaedje avou des ôtes uzeus anonimes.''",
"noarticletext": "I gn a pol moumint nou tecse e cisse pådje chal.\nVos ploz [[Special:Search/{{PAGENAME}}|cweri après l' tite di cisse pådje ci]] dins des ôtès pådjes,\noudonbén <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cweri dins les djournås],\nou co [{{fullurl:{{FULLPAGENAME}}|action=edit}} ahiver l' pådje]</span>.",
"noarticletext-nopermission": "I gn a pol moumint nou tecse e cisse pådje chal.\nVos ploz [[Special:Search/{{PAGENAME}}|cweri après l' tite di cisse pådje ci]] dins des ôtès pådjes,\noudonbén <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cweri dins les djournås]</span>, mins vos n' avoz nén l' livea d' permission pol poleur ahiver.",
"blocked-notice-logextract": "{{GENDER:$1|Cist uzeu est bloké|Ciste uzeuse est blokêye}} pol moumint.\nLi dierinne intrêye e djournå des blocaedjes est dnêye chal pa dzo po infôrmåcion:",
"categories-submit": "Mostrer",
"categoriespagetext": "{{PLURAL:$1|Li categoreye shuvante est eployeye|Les categoreyes shuvantes sont-st eployeyes}} pa des pådjes ou des fitchîs.\n[[Special:UnusedCategories|Les categoreyes nén eployeyes]] èn sont nén håynêyes chal.\nLoukîz eto [[Special:WantedCategories|les categoreyes dimandêyes]].",
"categoriesfrom": "Håyner les categoreyes a pårti di:",
- "special-categories-sort-count": "relére pa nombe di cayets",
- "special-categories-sort-abc": "relére alfabeticmint",
"deletedcontributions": "Contribouwaedjes disfacés",
"deletedcontributions-title": "Contribouwaedjes disfacés",
"sp-deletedcontributions-contribs": "contribouwaedjes",
"Kolega2357",
"아라",
"MarcoAurelio",
- "Macofe"
+ "Macofe",
+ "Matma Rex"
]
},
"tog-underline": "Bagisa ha ilarom an mga sumpay:",
"tog-ccmeonemails": "Padad-i ak hin mga kopya hin mga email nga akon ginpapadara ha iba nga mga gumaramit",
"tog-diffonly": "Ayaw igpakita an sulod han pakli ha ilarom han pagkakaiba",
"tog-showhiddencats": "Igpakita an mga tinago nga mga kaarangay",
- "tog-norollbackdiff": "Iglat-ang an kaiban kahuman himoa an libot-pabalik",
+ "tog-norollbackdiff": "Ayaw igpakita an kaiban kahuman himoa an rollback",
"tog-useeditwarning": "Pasabti ako kun nabaya ako hin ginliwat ng pakli nga waray katipig an mga pagbag-o",
"tog-prefershttps": "Pirmihi paggamit hin segurado nga koneksyon kun nakalog-in",
"underline-always": "Pirme",
"laggedslavemode": "Pahimatngon: It pakli bangin waray mga kabag-ohan nga bag-o.",
"readonly": "Gintrankahan an database",
"enterlockreason": "Pagbutang hin rason para han pagtrangka, upod hin banabana kon san-o kukuha-on an pagtrangka",
- "readonlytext": "An database in nakatrangka yana ha bag-o nga mga entrada ngan iba nga mga modipikasyon, tungod siguro ha routine database maintenance, kahuman ini in mabalik ha normal.\n\nAn magdudumara nga nagtrangka hini in naghatag hini nga kasayoran: $1",
+ "readonlytext": "An database in nakatrangka yana ha bag-o nga mga entrada ngan iba nga mga modipikasyon, tungod siguro ha routine database maintenance, kahuman ini in mabalik ha normal.\n\nAn system administrator nga nagtrangka hini in naghatag hini nga kasayoran: $1",
"missing-article": "Ini nga database in waray nakaagi han teksto han pakli nga dapat mabilngan, nga ginngaranan nga \"$1\" $2.\n\nIni in agsob hinungdan han pagsunod han kadaan nga kaibhan o sumpay han kaagi ngadto ha pakli nga ginpara.\n\nKun diri ini an kaso, bangin ka nakabiling hin bug ha software.\nAlayon la igsumat ini ha [[Special:ListUsers/sysop|administrator]], igsurat la an URL.",
"missingarticle-rev": "(pagbag-o#: $1)",
"missingarticle-diff": "(Kaibhan: $1, $2)",
"protectedinterface": "Ini nga pakli in nahatag hin teksto hit interface para han software han hin nga wiki, ngan in pinasasaliporan para makalikay hit pag-abuso.\nPara makadugang o makaliwat hin mga paghubad para han tanan nga mga wiki, alayon paggamit han [//translatewiki.net/ translatewiki.net], an kanan MediaWiki proyekto hin lokalisasyon.",
"editinginterface": "'''Pahimatngon:''' Imo ginliliwat an pakli nga gingagamit paghatag hin interface text para han software.\nAn mga pagbag-o hinin nga pakli in makakaapekto han itsura han user interface han iba nga mga gumaramit hini nga wiki.",
"translateinterface": "Para han pagdugang o pagbag-o han mga paghubad han ngatanan nga mga wiki, alayon paggamit han [//translatewiki.net/ translatewiki.net], an MediaWiki lokalisasyon nga proyekto.",
- "cascadeprotected": "Ini nga pakli in pinapasaliporan hin pagliwat tungod ini in nalalakip ha masunod nga {{PLURAL:$1|pakli, kun diin |mga pakli, kun diin}} pinapasaliporan hit \"cascading\" nga pagpili nga pinaandar:\n$2",
+ "cascadeprotected": "Ini nga pakli in pinapasaliporan tikang ha pagliwat tungod ini in naka-transclude ha masunod nga {{PLURAL:$1|pakli, kun diin |mga pakli, kun diin}} pinapasaliporan hit \"cascading\" nga pagpili nga pinaandar:\n$2",
"namespaceprotected": "Diri ka gintutugutan pagliwat han mga pakli ha ngaran-lat'ang nga '''$1'''.",
"customcssprotected": "Diri ka gintutugotan pagliwat hini nga CSS nga pakli, tungod nga nagsusulod ini hin kanan iba nga tawo personal nga karuyagon.",
"customjsprotected": "Diri ka gintutugotan pagliwat hini nga JavaScript nga pakli, tungod nga nagsusulod ini hin kanan iba nga tawo personal nga karuyagon.",
"mypreferencesprotected": "Waray nim pagtugot hit pagliwat hit imo mga karuyag.",
"ns-specialprotected": "Diri maliliwat an mga ispisyal nga pakli.",
"titleprotected": "Ini nga titulo pinasalipod ha paghimo ni [[User:$1|$1]].\nAn katadungan nga ginhatag amo in <em>$2</em>.",
- "filereadonlyerror": "Diri maliliwat ini nga paypay \"$1\" tungod an ginsusudlan han paypay nga \"$2\" in aada la ha pagbasa-la nga kahimtang.\n\nAn magdudurmara nga nagtrangka hini in naghatag hini nga eksplenasyon: \"$3\".",
+ "filereadonlyerror": "Diri maliliwat ini nga paypay \"$1\" tungod an ginsusudlan han paypay nga \"$2\" in aada la ha pagbasa-la nga kahimtang.\n\nAn system administrator nga nagtrangka hini in naghatag hini nga eksplenasyon: \"$3\".",
"invalidtitle-knownnamespace": "Titulo nga inbalido nga may pan-ngaran \"$2 ngan teksto nga \"$3\"",
"invalidtitle-unknownnamespace": "Diri ginkakarawat nga titulo tungod mayda ini hin mga diri nakikilala nga ngaran-lat'ang ihap $1 ngan teksto \"$2\"",
"exception-nologin": "Diri nakalog-in",
- "exception-nologin-text": "Alayon [[Special:Userlogin|pagsakob]] basi makakadto hiní nga pakli o buruhatón.",
+ "exception-nologin-text": "Alayon paglog-in basi makakadto hiní nga pakli o buruhatón.",
"exception-nologin-text-manual": "Alayon $1 basi makakadto hini nga pakli o buruhatón.",
"virus-badscanner": "Maraot nga configuration: Waray kasabti nga virus scanner: ''$1''",
"virus-scanfailed": "Pakyas an pag-scan (kodigo $1)",
"noname": "Waray ka nakahatag hin maupay nga agnay-hit-gumaramit.",
"loginsuccesstitle": "Nakalog-in",
"loginsuccess": "'''Ikaw in nakalog-in ha {{SITENAME}} komo \"$1\".'''",
- "nosuchuser": "Waray gumaramit an may-ada ngaran nga \"$1\".\nIt mga agnay-hi-gumaramit in case sensitive.\nPanginano-a it imo pagbaybay, o [[Special:UserLogin/signup|paghimo hin bag-o nga akawnt]].",
+ "nosuchuser": "Waray gumaramit an may-ada ngaran nga \"$1\".\nIt mga agnay-hi-gumaramit in case sensitive.\nPanginano-a it imo pagbaybay, o [[Special:CreateAccount|paghimo hin bag-o nga akawnt]].",
"nosuchusershort": "Waray nagamit it may ngaran nga \"$1\".\nKitaa kun amo it im pagbaybay.",
"nouserspecified": "Dapat nim magbutang hin agnay hit gumaramit.",
"login-userblocked": "Ini nga gumaramit in ginpugngan. Diri gintutugutan an pagsakob.",
"noemail": "Waray e-mail nga adres nga ginrekord para han nágámit \"$1\".",
"noemailcreate": "Kinahanglan nim maghatag hin may hinungdan nga e-mail address",
"passwordsent": "Uska bag-o nga password in ginpadangat ha e-mail address nga nakarehistro kan \"$1\".\nAlayon paglog-in utro kahuman mo makarawat ini.",
- "blocked-mailpassword": "An imo IP address in ginpugong ha pag-edit, ngan tungod hini in diri gintutugotan paggamit han password recovery function para malikyan an abuso.",
+ "blocked-mailpassword": "An imo IP address in ginpugngan pag-edit. Para pugngan an pag-abuso, ini in diri tinutogotan paggamit hin password recovery function tikang hinin nga IP address.",
"eauthentsent": "Mayda e-mail hin pagkumpirma nga ginpadará hini nga ginhatag nga e-mail adres.\n\nSan-o magatagán pa hin ibá nga e-mail it akwant, kinahanglan nimo sundon an mga tugon nga nahabutáng han email basi makumpirma nga imo gud itón akawnt.",
"throttled-mailpassword": "Usa nga tigaman-pagnakob reset email in ginpadangat na, ha sakob han urhi nga {{PLURAL:$1|oras|$1 ka mga oras}}.\nBasi diri ini maabuso, uusa la nga tigaman-panakob in igpapadangat kada {{PLURAL:$1|oras|$1 ka mga oras}}.",
"mailerror": "Sayop han pagpadangat hin surat: $1",
"createaccount-title": "Paghimo hin akawnt para han {{SITENAME}}",
"createaccount-text": "Mayda tawo nga naghimo hin akawnt nga gingamit an imo email address ha {{SITENAME}} ($4) nga ginngaranan nga \"$2\", nga may-ada tigaman-panakob nga \"$3\".\n\nKinahanglan ka maglog-in ngan igbal-iw an imo tigaman-panakob yana dayon.\n\nPuydi nimo pabay-on ini nga mensahe, kun ini nga paghimo hin akwant in nagsayop la.",
"login-throttled": "Damo na an imo login attempts ha pagkayana.\nAlayon paghulat hin $1 san-o ka umutro.",
- "login-abort-generic": "An imo paglog-in in diri malinamposon - Naundang",
+ "login-abort-generic": "An imo paglog-in in pakyas - Gin-undang",
"login-migrated-generic": "An imo account in nabalhin, ngan an imo agnay-gumaramit in waray na hinin nga wiki.",
"loginlanguagelabel": "Pinulongan: $1",
"suspicious-userlogout": "Waray ka tugoti pag-logout tungod nga baga ini ginpadangat hin usa nga broken browser o caching proxy.",
"newpassword": "Bag-o nga tigaman-pagsulod:",
"retypenew": "Utroha pagbutang an bag-o nga tigaman-pagsulod:",
"resetpass_submit": "Igbutang an password ngan log in",
- "changepassword-success": "Malinamposon an pagbal-iw hit imo tigaman-panakob!",
+ "changepassword-success": "Malinamposon an pagliwat hit imo password!",
"changepassword-throttled": "Damo na nga mga paningkamot hin pagsakob an imo ginhimò.\nAlayon paghulat hin $1 san-o ka umutro.",
"botpasswords": "Mga bot password",
"botpasswords-disabled": "Ginparong an mga bot password.",
"botpasswords-insert-failed": "Pakyas han pagdugang han ngaran han bot nga \"$1\". Naidugang na ini?",
"botpasswords-update-failed": "Pakyas han pag-update han bot nga ngaran nga \"$1\". Ginpara na ini?",
"botpasswords-created-title": "Nahimo an bot password",
- "botpasswords-created-body": "An bot password nga \"$1\" in malinamposon nga nahimo.",
+ "botpasswords-created-body": "An bot password para han bot nga ngaran nga \"$1\" ni gumaramit \"$2\" in nahimo.",
"botpasswords-updated-title": "Gin-update an bot password",
- "botpasswords-updated-body": "An bot password nga \"$1\" in malinamposon nga na-update.",
+ "botpasswords-updated-body": "An bot password para han ngaran han bot nga \"$1\" ni gumaramit \"$2\" in na-update.",
"botpasswords-deleted-title": "Ginpara an bot password",
- "botpasswords-deleted-body": "An bot password nga \"$1\" in ginpara.",
+ "botpasswords-deleted-body": "An bot password para han bot nga ngaran nga \"$1\" ni gumaramit \"$2\" in ginpara.",
"botpasswords-newpassword": "An bag-o nga password para han pag log-in han <strong>$1</strong> in <strong>$2</strong>. <em>Alayon igrecord ini para han future reference.</em>",
"botpasswords-no-provider": "BotPasswordsSessionProvider in waray dinhi.",
"botpasswords-restriction-failed": "An mga restriction han bot password in nagpupugong han pag-login hinin.",
"resetpass-no-info": "Kinahanglan mo paglog-in para direkta ka makasakob dinhi nga pakli.",
"resetpass-submit-loggedin": "Igbal-iw an tigaman-pagsulod",
"resetpass-submit-cancel": "Pasagdi",
- "resetpass-wrong-oldpass": "Diri balido an temporaryo o yana nga tigaman-panakob.\nImo malinamposon nga ginsalyuan an imo tigaman-panakob o umaro ka na hin bag-o nga temporaryo nga tigman-panakob.",
+ "resetpass-wrong-oldpass": "Diri balido an temporaryo o yana nga password.\nImo na ginsalyuan an imo password o umaro ka na hin bag-o nga temporaryo nga password.",
"resetpass-recycled": "Alayon pagreset han imo tigaman-pansakob hin lain tikang han imo yanâ nga tigaman-pansakob",
"resetpass-temp-emailed": "Nagsakob ka pinaagi hin temporary nga gin-email nga kodigo.\nBasi matapos an imo pagsakob, kinahanglan ka maghimo hin bag-o nga tigaman-pansakob dinhi:",
"resetpass-temp-password": "Temporaryo nga tigaman-pagsakob:",
"passwordreset-emailtitle": "Mga detalye han akawnt ha {{SITENAME}}",
"passwordreset-emailtext-ip": "Mayda gumaramit (bangin hi ikaw, tikang han IP adres nga $1) nga naghangyo hin reset han imo tigaman-pansulod han {{SITENAME}} ($4). An nasunod nga gumaramit {{PLURAL:$3|nga akawnt|nga mga akawnt}} nahanungod hini nga email nga adres: \n\n$2\n\n{{PLURAL:$3|Iní nga temporaryo nga tigaman-pansulod|Iní nga mga temporaryo nga tigaman-pansulod}} ma-waray bali hin {{PLURAL:$5|usa ka adlaw|$5 nga mga adlaw}}.\nAngay ka sumakob ngan pumílì hin bag-o nga tigaman-pansulod ha yanâ. Kun mayda lain nga naghatag hini nga hangyo, o kun nahinumdoman mo an imo orihinal nga tigaman-pansulod, ngan nadírì ka na pagbalyo hiní, puyde mo pasagdan ini nga sumat ngan magpadayon hin paggamit han imo daan nga tigaman-pansulod.",
"passwordreset-emailelement": "Agnay han gumaramit: \n$1\n\nTemporaryo nga tigaman han pagsakob: \n$2",
- "passwordreset-emailsentemail": "Ginpadangat an password reset email.",
+ "passwordreset-emailsentemail": "Kun inin nga email address in may pagkahisumpay ha imo account, papadangaton ka hin usa nga password reset email.",
"passwordreset-emailsent-capture": "Ginpadangat an password reset email, nga ginpakita ha ubos.",
"passwordreset-emailerror-capture": "Ginhimo an password reset email, kun diin nakikita ha ubos, pero pakyas an pagpadara ha {{GENDER:$2|gumaramit}}: $1",
"changeemail": "Igliwat o igtanggal an e-mail address",
- "changeemail-header": "Igliwan an e-mail address akawnt",
+ "changeemail-header": "Kompletoha ini nga form para masalyuan an imo email address. Kun karuyag nimo tanggalun an may pagkahisumpay han bisan ano nga email address tikang ha imo account, blankoha la an bag-o nga email address kun magsusumiti ka han form.",
"changeemail-passwordrequired": "Kinahanglan nim igbutang an imo password para igkompirma inin nga pagbag-o.",
"changeemail-no-info": "Kinahanglanon mo mag-log-in para ka direkta makasakob hini nga pakli.",
"changeemail-oldemail": "Yana nga e-mail address:",
"minoredit": "Gutiay ini nga pagliwat",
"watchthis": "Bantayi ini nga pakli",
"savearticle": "Igtipig an pakli",
+ "publishpage": "Igmantala an pakli",
"preview": "Pahiuna nga pagawas",
"showpreview": "Pakit-a an pahiuna nga pagawas",
"showdiff": "Igpakita an mga ginliwat",
"anonpreviewwarning": "''Diri ka naka-log in. Mahisusurat an imo IP address ngada ha kanan pakli kaagi hit pagliwat kun igtipig nimo.''",
"missingsummary": "<strong>Pahinumdom:</strong> Waray ka humatag hin halipotay nga masisiring hiton pagliwat. Kun pidliton mo an \"{{int:savearticle}}\" utro, an imo ginliwat in matitipig bisan waray hini.",
"missingcommenttext": "Alayon pagbutang hin komento ha ilarom.",
- "missingcommentheader": "'''Pahinumdom:''' Waray ka humatag hin subject/headline para hini nga komento. Kun pinduton mo an \"{{int:savearticle}}\" utro, an imo pagliwat in matitipig bisan waray hini.",
+ "missingcommentheader": "<strong>Pahinumdom:</strong> Waray ka humatag hin subject para hinin nga komento. Kun pinduton mo an \"{{int:savearticle}}\" utro, an imo pagliwat in matitipig bisan waray hini.",
"summary-preview": "Pahiuna nga pagawas han dalikyat nga pulong:",
"subject-preview": "Pahiuna nga pagawas hit himangrawan:",
"blockedtitle": "Ginpugngan ini nga gumaramit",
"accmailtext": "Uska hinimo nga random nga tigaman-panakob para kan [[User talk:$1|$1]] in ginpadangat ha $2. Puydi ini mabal-iwan ha ''[[Special:ChangePassword|liwani an tigaman-panakob]]'' nga pakli han paglog-in.",
"newarticle": "(Bag-o)",
"newarticletext": "Ginsunod mo an pakli nga waray pa kahihimo. Para ighimo an pakli, tikanga pagmakinilya ha kahon nga aada ha ubos (kitaa an [$1 nabulig nga pakli] para han kadugangan nga pananabutan). Kun sayop an imo pagkanhi, igpidlit an imo kanan panngaykay (''browser'') '''balik''' (''back'') nga piridlitan.",
- "anontalkpagetext": "----\n''Ini in hiruhimangraw-nga-pakli para han waray magpakilala nga gumaramit, nga waray pa hinmimo hin akawnt.''\nMagamit la kami hin IP address para makilal-an hiya.\nSugad hini nga IP address, in puydi sinmaro hiton pipira nga mga gumaramit.\nKun ikaw in waray magpakilala nga gumaramit, ngan pag-abat mo in may mga diri naangay nga komento an ginpapadangat ha imo, alayon nala [[Special:UserLogin/signup|paghimo hin akawnt]] o [[Special:UserLogin|pag-log in]] para malikyan an sumurunod nga mga pagkalipat nga dapat para ha iba nga waray magpakilala nga mga gumaramit.",
+ "anontalkpagetext": "----\n''Ini in hiruhimangraw-nga-pakli para han waray magpakilala nga gumaramit, nga waray pa hinmimo hin akawnt.''\nMagamit la kami hin IP address para makilal-an hiya.\nSugad hini nga IP address, in puydi sinmaro hiton pipira nga mga gumaramit.\nKun ikaw in waray magpakilala nga gumaramit, ngan pag-abat mo in may mga diri naangay nga komento an ginpapadangat ha imo, alayon nala [[Special:CreateAccount|paghimo hin akawnt]] o [[Special:UserLogin|pag-log in]] para malikyan an sumurunod nga mga pagkalipat nga dapat para ha iba nga waray magpakilala nga mga gumaramit.",
"noarticletext": "Waray yana teksto ha sulod hinin nga pakli.\nPuyde ka [[Special:Search/{{PAGENAME}}|mamiling hin titulo hinin nga pakli]] ha iba pa nga mga pakli,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pamilnga an may mga pagkahisumpay nga mga talaan],\no [{{fullurl:{{FULLPAGENAME}}|action=edit}} igliwat ini nga pakli]</span>.",
"noarticletext-nopermission": "Waray yana nahasurat hini nga pakli\nPuyde hi ikaw [[Special:Search/{{PAGENAME}}|magbiling han ngaran hini nga pakli]] ha iba nga mga pakli,\no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mamiling han mga nanginginlabot nga mga talaan]</span>, kundi diri ka gintutugotan hin paghímò hini nga pakli.",
"missing-revision": "Waray na an rebisyon #$1 han pakli nga ginngaranan nga \"{{FULLPAGENAME}}\".\n\nIni in agsob tungod han pagsunod hin daan nga sumpay hin kaagi ha pakli nga ginpara.\nAn mga detalye in mabibilngan ha [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log].",
"rev-delundel": "igpakita/igtago",
"rev-showdeleted": "igpakita",
"revisiondelete": "Pagpara/pagtanggal han pagpara nga mga rebisyon",
+ "revdelete-nooldid-title": "Diri ginkakarawat an target revision",
"revdelete-show-file-confirm": "Sigurado ka nga gusto mo makita an ginpara nga pagliwat han file \"<nowiki>$1</nowiki>\" tikang $2 ha $3?",
"revdelete-show-file-submit": "Oo",
"revdelete-hide-text": "Rebisyon nga sinurat",
"mergehistory-into": "Kakadtoan nga pakli:",
"mergehistory-submit": "Igtampo an mga rebisyon",
"mergehistory-empty": "Waray mga rebisyon in puydi matampo.",
+ "mergehistory-fail-bad-timestamp": "Diri puydi an timestamp.",
+ "mergehistory-fail-invalid-source": "Diri puydi an ginkuhaan nga pakli.",
+ "mergehistory-fail-invalid-dest": "Diri puydi an kakadtoan nga pakli.",
+ "mergehistory-fail-self-merge": "Pareho an tinikangan ngan kakadtoan nga mga pakli.",
"mergehistory-no-source": "Waray pa an tinikangan nga pakli nga $1.",
"mergehistory-no-destination": "Waray pa an kakadtuan nga pakli nga $1.",
+ "mergehistory-invalid-source": "An tinikangan nga pakli in dapat may-ada valid title.",
+ "mergehistory-invalid-destination": "An kakadtoan nga pakli in kinahanglan may-ada valid title.",
"mergehistory-autocomment": "Gintampo an [[:$1]] tipakadto ha [[:$2]]",
"mergehistory-comment": "Gintampo an [[:$1]] ngada ha [[:$2]]: $3",
"mergehistory-same-destination": "An gintikangan ngan kakadtoan nga mga pakli in diri puydi magkaparo",
"revertmerge": "Igbulag an gintampo",
"history-title": "Kaagi han pagbag-o han ''$1''",
"difference-title": "An pagkakaiba han mga rebisyon han \"$1\"",
+ "difference-title-multipage": "An pagkakaiba ha butnga han mga pakli \"$1\" ngan \"$2\"",
"difference-multipage": "(Kaibhan ha butnga han mga pakli)",
"lineno": "Bagis $1:",
"compareselectedversions": "Igkumpara an mga pinili nga pagbabag-o",
"prefs-watchlist-token": "Token hin talaan hin barantayon:",
"prefs-misc": "Dirudilain",
"prefs-resetpass": "Igliwan an tigaman-pagsulod",
- "prefs-changeemail": "Igliwan an e-mail address",
+ "prefs-changeemail": "Igliwan o tatanggalon an e-mail address",
"prefs-setemail": "Igbutang an email address",
"prefs-email": "Mga pagpipilian han e-mail",
"prefs-rendering": "Hitsura",
"yournick": "Bag-o nga pirma:",
"badsiglength": "Hilaba hin duro it im pirma.\nDapat diri malabaw ha $1 {{PLURAL:$1|agi|mga agi}} nga kahilaba.",
"yourgender": "Ano an karuyag mo nga pangilal-an?",
- "gender-unknown": "Karuyag ko diri la magyakan",
+ "gender-unknown": "Kun ikaw in mangangaranan, an software in magamit hin gender neutral words kun mahihimo",
"gender-male": "Hiya in nag-aayad hin mga wiki nga pakli",
"gender-female": "Hiya in nag-aayad hin mga wiki nga pakli",
"email": "E-mail",
- "prefs-help-realname": "Opsyonal an tinuod nga ngaran.\nKun pilion mo nga ihatag, ini in gagamiton ha paghatag hin atribusyon ha imo mga buhat.",
+ "prefs-help-realname": "Opsyonal an paggamit hin tinuod nga ngaran.\nKun ihatag, ini in puydi magamit paghatag hin pagkilala ha imo mga buhat.",
"prefs-help-email": "Diri pinipirit it pagbutang hin E-mail address, pero kinahanglan ini para hin pag-utro hin tigaman-hit-pagsulod (''password''), ngan kun mangalimot ka hit imo tigaman-hit-pagsulod.",
"prefs-help-email-others": "Puydi mo pilion nga it iba in makakontak ha imo gamit an e-mail pinaagi han sumpay ha imo gumaramit o hiruhimangraw nga pakli.\nAn imo e-mail address in diri makikit-an kun an iba nga mga gumaramit in makontak ha imo.",
"prefs-help-email-required": "Kinahanglanon it e-mail address.",
"userrights": "Pagdudumara hin mga katungod han gumaramit",
"userrights-lookup-user": "Pagdumaraa han mga hugpo han gumaramit",
"userrights-user-editname": "Igbutang an agnay han gumaramit:",
- "editusergroup": "Igliwat han mga hugpo han gumaramit",
- "editinguser": "Igliliwat an mga katungod han gumaramit han gumaramit '''[[User:$1|$1]]''' $2",
+ "editusergroup": "Igliwat an mga hugpo han {{GENDER:$1|gumaramit}}",
+ "editinguser": "Ginsasaliwanan an katungod-han-gumaramit ni {{GENDER:$1|gumaramit}} <strong>[[User:$1|$1]]</strong> $2",
"userrights-editusergroup": "Igliwat an mga hugpo hin gumaramit",
- "saveusergroups": "Igtipig an mga hugpo han gumaramit",
+ "saveusergroups": "Igtipig an mga hugpo han {{GENDER:$1|gumaramit}}",
"userrights-groupsmember": "Api han:",
"userrights-groupsmember-auto": "Api nga daan han:",
"userrights-reason": "Katadungan:",
"userrights-notallowed": "Waray nim pagtugot hin pagdugang o pagtanggal hin mga katungod han gumaramit.",
"userrights-changeable-col": "Mga hugpo nga puydi mo labtan",
"userrights-unchangeable-col": "Mga hugpo nga diri mo puydi labtan",
- "userrights-removed-self": "Malinamposon nim gintanggal an imo kalugaringon mga katungod. Tungod hito, diri ka na makaka-access hini nga pakli.",
+ "userrights-removed-self": "Imo gintanggal an imo kalugaringon mga katungod. Tungod hito, diri kana makaka-access hinin nga pakli.",
"group": "Hugpo:",
"group-user": "Mga gumaramit",
"group-autoconfirmed": "Mga gumaramit nga lugaring nakokonpirma",
"group-suppress": "Mga suppressor",
"group-all": "(ngatanan)",
"group-user-member": "{{HENERO:$1|gumaramit}}",
+ "group-autoconfirmed-member": "{{GENDER:$1|autoconfirmed user}}",
"group-bot-member": "bot",
"group-sysop-member": "magdudumara",
"group-bureaucrat-member": "{{GENDER:$1|burokrata}}",
- "group-suppress-member": "{{GENDER:$1|magmarangno}}",
+ "group-suppress-member": "{{GENDER:$1|suppressor}}",
"grouppage-user": "{{ns:project}}:Mga gumaramit",
"grouppage-autoconfirmed": "{{ns:project}}:Mga gumaramit nga naka-awtokompirmado",
"grouppage-bot": "{{ns:project}}:Mga bot",
"grouppage-sysop": "{{ns:project}}:Mga magdudumara",
"grouppage-bureaucrat": "{{ns:project}}:Mga burokrata",
- "grouppage-suppress": "{{ns:project}}:Nanginginano",
+ "grouppage-suppress": "{{ns:project}}:Suppress",
"right-read": "Igbasa an mga pakli",
"right-edit": "Igliwat an mga pakli",
"right-createpage": "Paghimo hin mga pakli (nga diri an mga hiruhimangraw nga mga pakli)",
"right-reupload": "Sapawa an mga aada nga mga paypay",
"right-reupload-own": "Igsapaw an aada yana nga mga paypay nga ginkarga-pasaka nimo mismo",
"right-upload_by_url": "Igkarga paigbaw an mga paypay tikang ha uska URL",
+ "right-purge": "Igpurge an site cache han pakli bisan waray kompirmasyon",
"right-autoconfirmed": "Diri malalalbtan hin IP-nga-nahibasi nga mga rate hin paglimit",
"right-bot": "Igtrato komo uska naglulugaring nga proseso",
"right-writeapi": "Paggamit han write API",
"right-import": "Man-aangbit hin mga pakli tikang ha iba nga mga wiki",
"right-importupload": "Man-aangbit hin mga pakli tikang ha uska paypay nga iginkarga-pasaka",
"right-patrol": "Igmarka an kanan iba mga pagliwat komo ginpatrolya na",
+ "right-unwatchedpages": "Pakit-a an lista han mga gintanggal an pagbantay nga mga pakli",
"right-mergehistory": "Igtampo an kaagi han mga pakli",
"right-userrights": "Igliwat an ngatanan nga mga katungod han gumaramit",
"right-userrights-interwiki": "Igliwat an mga katungod han gumaramit han mga gumaramit ha iba nga mga wiki",
"right-siteadmin": "Igtrangka ngan igrangka an database",
"right-sendemail": "Padad-i hin e-mail ngada ha iba nga mga gumaramit",
+ "right-passwordreset": "Pakit-a an mga password reset email",
+ "right-deletechangetags": "Igpara an [[Special:Tags|tags]] tikang han database",
+ "grant-generic": "mga katungod nga katitirok han \"$1\"",
+ "grant-group-page-interaction": "Pakig-interact han mga pakli",
+ "grant-group-file-interaction": "Pakig-interact hiton media",
+ "grant-group-watchlist-interaction": "Pakig-interact ha imo mga barantayan",
"grant-group-email": "Padangat hin email",
"grant-createaccount": "Pahimo hin mga account",
"grant-createeditmovepage": "Paghimo, pagliwat, ngan pagbalhin hin mga pakli",
"grant-delete": "Pagpara hin mga pakli, mga rebisyon, ngan mga iginsulod ha log",
+ "grant-editinterface": "Igliwat an MediaWiki namespace ngan kanan gumaramit CSS/JavaScript",
+ "grant-editmycssjs": "Igliwat an imo gumaramit nga CSS/JavaScript",
+ "grant-editmyoptions": "Igliwat an imo gumaramit nga mga karuyagon",
+ "grant-editmywatchlist": "Igliwat an imo barantayon",
+ "grant-editpage": "Igliwat an aada nga mga pakli",
+ "grant-editprotected": "Igliwat an mga pinansaliporan nga mga pakli",
+ "grant-highvolume": "High-volume nga pagliwat",
+ "grant-oversight": "Igtago an mga gumaramit ngan pag-suppress nga mga rebisyon",
+ "grant-patrol": "Igliwat an pagpatrolya ha mga pakli",
+ "grant-protect": "Igpanalipod ngan igtanggal an mga panalipod han mga pakli",
+ "grant-rollback": "Ig-rollback an mga pagliwat ngadto ha mga pakli",
"grant-sendemail": "Igpadara hin email ngadto ha iba nga mga gumaramit",
"grant-uploadeditmovefile": "Pagkarga, pagsaliwan, ngan pagbalhin hin mga file",
"grant-uploadfile": "Pagkarga hin bag-o nga mga file",
"action-createpage": "pahimo hin mga pakli",
"action-createtalk": "Paghimo hin hiruhimangraw nga mga pakli",
"action-createaccount": "Himoa ini nga akawnt hin gumaramit",
+ "action-autocreateaccount": "automatic nga hihimoon ini nga external user account",
+ "action-history": "kitaa an kaagi hinin nga pakli",
"action-minoredit": "butanga hin tigaman hinin nga pagliwat komo gutiay",
"action-move": "balhina ini nga pakli",
"action-move-subpages": "igbalhin ini nga pakli, ngan iya mga bahin-pakli",
"action-move-rootuserpages": "Igbalhin an gamot nga mga pakli han gumaramit",
+ "action-move-categorypages": "igbalhin an mga kaarangay nga pakli",
"action-movefile": "igbalhin ini nga paypay",
"action-upload": "igkarga-pasaka ini nga paypay",
"action-reupload": "igsapaw ini nga aanhi nga paypay",
+ "action-reupload-shared": "ig-override ini nga file ha pinagsasaroan nga repositoryo",
"action-upload_by_url": "igkaraga-pasaka ini nga paypay tikang ha uska URL",
+ "action-writeapi": "gamiti an write API",
"action-delete": "paraa ini nga pakli",
"action-deleterevision": "igpara ini nga pagbag-o",
"action-deletedhistory": "kitaa an kanan hini nga pakli kaagi han mga ginpara",
"action-browsearchive": "Pamiling hin mga ginpara nga mga pakli",
"action-undelete": "Balika an ginpara hini nga pakli",
+ "action-suppressrevision": "ig-review ngan ig-restore inin nga nakatago nga rebisyon",
"action-suppressionlog": "kitaa an kanan hini pribado nga talaan",
"action-block": "Pugnga ini nga gumaramit ha pagliwat",
"action-protect": "igsaliwan an katupngan han pananalipod para hini nga pakli",
+ "action-rollback": "dagmiti pag-rollback an mga pagliwat an kataposan nga gumaramit nga nagliwat hit usa ka partikular nga pakli",
"action-import": "ig-angbit hin mga pakli tikang ha iba nga wiki",
"action-importupload": "ig-angbit hin mga pakli pakli tikang ha uska ginkarga-pasaka nga paypay",
"action-patrol": "markahi an kanan iba pagliwat komo nakapatrolya",
+ "action-autopatrol": "ig-marka nga ginpatrolyahan na an imo pagliwat",
+ "action-unwatchedpages": "kitaa an mga lista han gintanggal an pagbantay nga mga pakli",
"action-mergehistory": "Igtampo an kaagi hini nga pakli",
"action-userrights": "Igliwat an ngatanan nga mga katungod han gumaramit",
+ "action-userrights-interwiki": "igliwat an mga katungod han mga gumaramit ha iba nga mga wiki",
+ "action-siteadmin": "ig-lock o ig-unlock an database",
"action-sendemail": "Padara hin mga e-mail",
"action-editmywatchlist": "igliwat an imo watchlist",
"action-viewmywatchlist": "kitaa an imo watchlist",
"action-viewmyprivateinfo": "kitaa an imo pribado nga impormasyon",
"action-editmyprivateinfo": "igliwat an imo pribado nga impormasyon",
"action-editcontentmodel": "igliwat an content model han uska pakli",
- "action-managechangetags": "himua ngan igpara na mga tag tikang ha database",
+ "action-managechangetags": "himoa ngan igpaandar/diri-paganahon an mga tag",
+ "action-applychangetags": "ig-apply an mga tag kaupod an imo mga pagliwat",
"nchanges": "$1 {{PLURAL:$1|pagbag-o|mga pagbabag-o}}",
"enhancedrc-history": "kasaysayan",
"recentchanges": "Mga kabag-ohan",
"recentchanges-legend-heading": "<strong>Leyenda:</strong>",
"recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (kitaa gihapon [[Special:NewPages|talaan han mga bag-o nga pakli]])",
"recentchanges-submit": "Pakit-a",
- "rcnotefrom": "An ha ubos in mga pagbabag-o tikang han <strong>$2</strong> (kutob ngadto ha <strong>$1</strong> nga ginpakita).",
+ "rcnotefrom": "Didi ha ubos amo {{PLURAL:$5|an pagbag-o|an mga pagbabag-o}} tikang<strong>$3, $4</strong> (tubtob <strong>$1</strong> nga ginpakita).",
"rclistfrom": "Pakit-a an mga ginbag-ohan tikang han $3 $2",
"rcshowhideminor": "$1 gudti nga mga pagliwat",
"rcshowhideminor-show": "Pakit-a",
"newpageletter": "B",
"boteditletter": "b",
"number_of_watching_users_pageview": "[$1 nagbabatay hin {{PLURAL:$1|gumaramit|mga gumaramit}}]",
- "rc_categories_any": "Bisan ano nga",
+ "rc_categories_any": "Bisan ano nga pinili",
"rc-change-size-new": "$1 {{PLURAL:$1|nga byte|nga mga byte}} kahuman han pagbag-o",
"newsectionsummary": "/* $1 */ bag-o nga bahin",
"rc-enhanced-expand": "Igpakita an detalye",
"uploadnologintext": "Alayon $1 para han pag-upload han mga file.",
"uploaderror": "Sayop hit pagkarga-pasaka",
"upload-recreate-warning": "'''Pahimatngon: An fayl nga may-ada hiton nga ngaran in ginpara o ginbalhin.'''\n\nAn taramdan han pagpara ngan pagbalhin para hini nga pakli in ginhahatag para han imo kamurayaw:",
- "upload-permitted": "Gintutugotan nga mga klase han paypay: $1.",
- "upload-preferred": "Karuyag nga mga tipo hin paypay: $1.",
- "upload-prohibited": "Gindidire nga mga klase han paypay: $1.",
+ "upload-permitted": "Gintutugotan nga {{PLURAL:$2|klase|mga klase}} nga file: $1.",
+ "upload-preferred": "Mas karuyag nga {{PLURAL:$2|klase|mga klase}} hin file: $1.",
+ "upload-prohibited": "Gindidire nga {{PLURAL:$2|klase|mga klase}} hin file: $1.",
"uploadlogpage": "Talaan han mga ginkarga-paigbaw",
"filename": "Ngaran han fayl",
"filedesc": "Dalikyat nga pulong",
"filename-toolong": "Iton ngaran hin paypay in diri puyde na mas lapos pa ha 240 ka mga byte.",
"badfilename": "An ngaran-han-paypay in ginliwat ngada ha \"$1\".",
"empty-file": "An paypay nga imo ginsumite in waray sulod.",
+ "file-too-large": "An file nga imo ginhatag in sobra kadako.",
"filename-tooshort": "An ngaran han fayl in halipot hin duro.",
"filetype-banned": "Ini nga klase nga paypay in gindidire.",
+ "verification-error": "Ini nga pakli in waray nakapasar han file verification.",
+ "hookaborted": "An modipikasyon nga imo gintatalinguha nga himoon in gin-undang hin usa ka extension.",
"illegal-filename": "An ngaran han fayl in diri gintutugutan.",
"overwrite": "It pagsapaw han aada nga paypay in diri gintutugotan.",
"unknown-error": "Nahitabo an waray kasasabti nga sayop.",
"tmp-write-error": "Sayop ha pagsurat hin temporaryo nga paypay.",
"large-file": "Ginrerekomenda nga it mga paypay in diri malapos hin $1;\nini nga paypay in $2.",
"largefileserver": "Ini nga paypay in durudako kaysa ha ginpapakarawat han serbidor.",
+ "emptyfile": "An file nga imo gin-upload in baga waray sulod.\nIni in bangin tungod nagsayop pag-type han filename.\nAlayon kitaa kun imo karuyag gud nimo ig-upload inin nga file.",
"windows-nonascii-filename": "Ini nga wiki in diri nakasuportado han mga ngaran-han-paypay nga may-ada pinaurog nga mga karakter.",
"uploadwarning": "Pahimatngon han pagkarga paigbaw",
"savefile": "Igtipig an paypay",
"upload-proto-error": "Sayop nga protocol",
"upload-file-error": "Sayop ha sulod",
"upload-misc-error": "Waray kasasabti nga sayop hin pagkarga-paigbaw",
+ "upload-too-many-redirects": "An URL in nagsusulod hin damo hin duro nga mga redirect",
"upload-http-error": "Mayda nahitabo nga sayop hin HTTP: $1",
"upload-dialog-title": "Ig-upload an file",
"upload-dialog-button-cancel": "Pasagda",
"upload-dialog-button-upload": "Upload",
"upload-form-label-infoform-title": "Mga detalye",
"upload-form-label-infoform-name": "Ngaran",
+ "upload-form-label-infoform-description": "Deskripsyon",
"upload-form-label-usage-title": "Paggamit",
"upload-form-label-usage-filename": "Ngaran han file",
"upload-form-label-own-work": "Buhat ko ini",
"backend-fail-read": "Diri nababasahan han paypay nga \"$1\".",
"backend-fail-create": "Diri nasusuratan an paypay nga \"$1\".",
"backend-fail-maxsize": "Diri nasusuratan an paypay nga \"$1\" tungod nga mas dako ini kaysa hin {{PLURAL:\"$2|usa nga byte|$2 nga mga byte}}.",
- "backend-fail-readonly": "An panluyo nga tiripigan nga \"$1\" in ha pagkayana in panbasa-la. An rason nga ginhatag in: \"''$2''\"",
+ "backend-fail-readonly": "An storage backend nga \"$1\" in ha pagkayana read-only. An rason nga ginhatag in: <em>$2</em>",
"backend-fail-connect": "Diri nakakasumpay ha storage backend \"$1\".",
"lockmanager-notlocked": "Waray ka rangka an \"$1\"; diri ini nakatrangka.",
"lockmanager-fail-closelock": "Diri nakakasera han nakatrangka nga paypay para han \"$1\".",
"lockmanager-fail-svr-acquire": "Diri nakakakarawat in mga trangka ha serbidor $1.",
"lockmanager-fail-svr-release": "Diri nakakabul-iw in mga trangka ha serbidor $1.",
"zip-wrong-format": "An espisipikado nga paypay in diri naka ZIP nga paypay.",
- "uploadstash-errclear": "An paghawan han mga paypay in diri malinamposon.",
+ "uploadstash-errclear": "Pakyas an paghawan han mga file.",
"uploadstash-refresh": "Igpalab-as utro an talaan hin mga paypay",
"img-auth-accessdenied": "Diri gintutugutan makasulod",
"img-auth-nofile": "Waray ngada an paypay nga \"$1\".",
+ "img-auth-streaming": "Nag ii-stream \"$1\".",
"http-read-error": "HTTP maysayop ha pagbasa.",
"http-timed-out": "Naubosan hin oras ha pagpaalayon ha HTTP.",
"http-curl-error": "May sayop ha pagkuha hin URL: $1",
"statistics-users": "Mga [[Special:ListUsers|gumaramit]] nga nakarehistro",
"statistics-users-active": "Mga gumaramit nga nanggigios",
"statistics-users-active-desc": "Mga gumaramit nga may-ada iginbuhat ha urhi nga {{PLURAL:$1|ka adlaw|$1 ka mga adlaw}}",
+ "pageswithprop-prop": "Ngaran han propyudad:",
"pageswithprop-submit": "Kadto-a",
"doubleredirects": "Mga doble nga redirekta",
"double-redirect-fixer": "Mangangayad hin redirekta",
"wantedtemplates": "Mga ginkikinahanglan nga batakan",
"mostlinked": "Pinakadamo nga mga ginsumpayan nga pakli",
"mostlinkedcategories": "Pinakadamo nga mga ginsumpayan nga kaarangay",
- "mostlinkedtemplates": "Pinakadamo nga mga ginsumpayan nga batakan",
+ "mostlinkedtemplates": "Pinakana-transclude nga mga pakli",
"mostcategories": "Mga paypay nga may-ada pinakadamo nga mga kaarangay",
"mostimages": "Pinakadamo nga nahisumpayan nga mga paypay",
"mostinterwikis": "Mga pakli nga may-ada pinakadamo nga mga interwiki",
"longpages": "Haglaba nga mga pakli",
"deadendpages": "Waray na kakadtoan nga mga pakli",
"protectedpages": "Pinapasaliporan nga mga pakli",
+ "protectedpages-timestamp": "Timestamp",
+ "protectedpages-page": "Pakli",
+ "protectedpages-expiry": "Mahuhuman",
+ "protectedpages-performer": "Pinapasaliporan an gumaramit",
+ "protectedpages-params": "Mga parametro han pananalipod",
+ "protectedpages-reason": "Rason",
+ "protectedpages-submit": "Pagdisplay hin mga pakli",
+ "protectedpages-unknown-timestamp": "Waray kasabti",
+ "protectedpages-unknown-performer": "Waray magpasabot nga gumaramit",
"protectedtitles": "Pinapasaliporan nga mga titulo",
+ "protectedtitles-submit": "Igpakita an mga titulo",
"listusers": "Lista han mga gumaramit",
"listusers-editsonly": "Igpakita la an mga gumaramit nga may-ada ginliwat",
"listusers-creationsort": "Ginsusunodsunod pinaagi han paghimo nga petsa",
+ "listusers-desc": "Ig-ayos ha paubos nga orden",
"usereditcount": "$1 {{PLURAL:$1|ka pagliwat|ka mga pagliwat}}",
"usercreated": "{{GENDER:$3|Ginhimo}} han $1 ha $2",
"newpages": "Bag-o nga mga pakli",
"nopagetitle": "Waray sugad hito nga kakadtoan nga pakli",
"pager-newer-n": "{{PLURAL:$1|burubag-o 1|burubag-o $1}}",
"pager-older-n": "{{PLURAL:$1|durudaan 1|durudaan $1}}",
+ "suppress": "Ig-suppress",
+ "apihelp": "Pabulig hit API",
+ "apihelp-no-such-module": "Waray kahiagii an Module \"$1\"",
+ "apisandbox": "sandbox hit API",
+ "apisandbox-jsonly": "Kinahanglan hin JavaSript para ha paggamit han API sandbox.",
+ "apisandbox-fullscreen": "Igpahilawig an panel",
+ "apisandbox-fullscreen-tooltip": "Igpahilawig an sandbox panel para masudlan an browser window.",
"apisandbox-unfullscreen": "Igpakita an pakli",
+ "apisandbox-unfullscreen-tooltip": "Igpaguti an sandbox panel, para an MediaWiki navigation link in mahikit-an.",
"apisandbox-submit": "Paghimo hin request",
"apisandbox-reset": "Hawana",
"apisandbox-retry": "Utroha",
+ "apisandbox-loading": "Nagloload hin impormasyon para han API module nga \"$1\"...",
+ "apisandbox-load-error": "May sayop nga nahitabo samtang nagloload hin impormasyon para han API module nga \"$1\": $2",
+ "apisandbox-no-parameters": "Waray mga parametro ini nga API module.",
"apisandbox-helpurls": "Mga sumpay hit pabulig",
"apisandbox-examples": "Mga pananglitan",
"apisandbox-dynamic-parameters": "Dugang nga mga parameter",
"apisandbox-dynamic-parameters-add-label": "Dugngi hin parameter:",
"apisandbox-dynamic-parameters-add-placeholder": "Ngaran hit parameter",
"apisandbox-dynamic-error-exists": "May-ada na nakangaran nga \"$1\" nga parameter.",
+ "apisandbox-deprecated-parameters": "Naka-deprecate nga mga parametro",
"apisandbox-results": "Mga resulta",
+ "apisandbox-request-url-label": "Ginpapaalayon nga URL:",
+ "apisandbox-request-time": "Oras nga naglabay han pagpaalayon : {{PLURAL:$1|$1 ms}}",
"booksources": "Mga libro nga tinikangan",
"booksources-search-legend": "Pamilnga an mga libro nga gintikangan",
"booksources-search": "Bilnga",
"specialloguserlabel": "Magburuhat:",
- "speciallogtitlelabel": "iiguon (titulo o gumarami):",
+ "speciallogtitlelabel": "Hinihingyap nga (titulo o {{ns:user}}:ngaran-han-gumaramit para han gumaramit):",
"log": "Mga talaan",
+ "logeventslist-submit": "Igpakita",
"all-logs-page": "Ngatanan nga mga talaan panpubliko",
+ "checkbox-all": "Ngatanan",
+ "checkbox-none": "Waray",
+ "checkbox-invert": "Baliskara",
"allpages": "Ngatanan nga mga pakli",
"nextpage": "Sunod nga pakli ($1)",
"prevpage": "Nahiuna nga pakli ($1)",
"allpages-hide-redirects": "Igtago an mga redirekta",
"cachedspecial-refresh-now": "Igkita an pinakaurhi.",
"categories": "Mga kaarangay",
+ "categories-submit": "Igpakita",
"categoriesfrom": "Igpakita in mga kaarangay nga natikang ha:",
"deletedcontributions": "Mga ginpara nga mga ámot hin nágámit",
"deletedcontributions-title": "Ginpara nga mga amot han nagamit",
"listusers-noresult": "Waray gumaramit nga nahiagian.",
"listusers-blocked": "(ginpugngan)",
"activeusers": "Taramdan hin mga gumaramit nga nanggigios",
+ "activeusers-from": "Igpakita an mga gumaramit tikang ha:",
"activeusers-hidebots": "Igtago an mga bot",
"activeusers-hidesysops": "Igtago an mga magdudumara",
"activeusers-noresult": "Waray gumaramit nga nahiagian.",
+ "activeusers-submit": "Igpakita an mga gumaramit nga nangigios",
"listgrouprights": "Mga katungod han grupo hin gumaramit",
"listgrouprights-summary": "An masunod nga uska talaan hin mga grupo hin gumaramit sumala hinin nga wiki, ngan an ira nahisusumpay nga paggamit nga katungod. Bangin may-ada [[{{MediaWiki:Listgrouprights-helppage}}|dugang nga impormasyon]] mahiunong han indibiduwal nga mga katungod.",
"listgrouprights-key": "Leyenda:\n* <span class=\"listgrouprights-granted\">Gintagan hin katungod</span>\n* <span class=\"listgrouprights-revoked\">Waray ginhatag an katungod</span>",
"listgrouprights-removegroup-self": "Igtanggal an {{PLURAL:$2|grupo|mga grupo}} tikang ha kalugaringon nga akawnt: $1",
"listgrouprights-addgroup-self-all": "Igdugang an ngatanan nga mga grupo ha kalugaringon nga akawnt",
"listgrouprights-removegroup-self-all": "Igtanggal an ngatanan nga mga grupo tikang ha kalugaringon nga akawnt",
+ "listgrouprights-namespaceprotection-namespace": "Ngaran-lat'ang",
+ "listgrouprights-namespaceprotection-restrictedto": "(Mga) katungod han pagtugot ha gumaramit nga pagliwat",
+ "listgrants": "Mga iginhatag",
+ "listgrants-grant": "Iginhatag",
+ "listgrants-rights": "Mga katungod",
+ "trackingcategories": "Ginsusubay an mga kategorya",
+ "trackingcategories-msg": "Ginsusubay an kaarangay",
+ "trackingcategories-name": "Ngaran han mensahe",
"mailnologin": "Waray kakadtoan nga address",
"mailnologintext": "Kinahanglan nimo nga [[Special:UserLogin|nakalog-in]] ngan may-ada balido nga email address ha imo[[Special:Preferences|mga preperensya]] para makapadangat hin email ngadto ha iba nga mga gumaramit.",
"emailuser": "Ig-e-mail ini nga gumaramit",
"notanarticle": "Diri uska unod nga pakli",
"notvisiblerev": "An urhi nga pagliwat han iba nga gumaramit in ginpara",
"watchlist-details": "{{PLURAL:$1|$1 nga pakli|$1 nga mga pakli}} nga aada ha imo talaan nga binabantayan, diri bulag nga paglakip han mga hiruhimangraw-nga-pakli.",
- "wlshowlast": "Igpakita an katapusan nga $1 nga mga oras $2 nga mga adlaw",
+ "wlshowlast": "Igpakita an katapusan nga $1 ka mga oras $2 ka mga adlaw",
"watchlist-hide": "Tago-a",
"watchlist-submit": "Pakit-a",
+ "wlshowtime": "Kaiha han oras ha pagdisplay:",
"wlshowhideminor": "gudti nga mga pagliwat",
"wlshowhidebots": "Mga bot",
"wlshowhideliu": "Mga nakarehistro nga gumaramit",
"wlshowhideanons": "Mga waray magpakilala nga gumaramit",
"wlshowhidepatr": "Nakapatrolya na nga mga pagliwat",
"wlshowhidemine": "ako mga pagliwat",
+ "wlshowhidecategorization": "Kategorisasyon han pakli",
"watchlist-options": "Mga pirilian han talaan han binabantayan",
"watching": "Ginbabantay...",
"unwatching": "Diri na ginbabantay...",
"deletepage": "Igpara an pakli",
"confirm": "Kompirma",
"excontent": "An sulod in: ''$1''",
- "excontentauthor": "an sulod in: ''$1'' (ngan hi \"[[Special:Contributions/$2|$2]]\" la an nag-amot)",
+ "excontentauthor": "An nasusulod in: ''$1'', ngan hi \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|pakighimangraw]]) la an nag-amot",
"exbeforeblank": "sulod san-o paghawan in: \"$1\"",
"delete-confirm": "Igpara \"$1\"",
"delete-legend": "Igpara",
+ "historyaction-submit": "Igpakita",
"actioncomplete": "Malinampuson an ginbuhat",
"actionfailed": "Napakyas an ginbuhat",
"deletedtext": "Ginpara an \"$1\".\nKitaa an $2 para hin talaan han mga gibag-ohi nga mga ginpamara.",
"deletereasonotherlist": "Lain nga katadungan",
"deletereason-dropdown": "*Agsob nga rason hin pagpara\n** Spam\n** Bandalismo\n** Pagtalapas ha katungod hin pagtatag-iya (''copyright'')\n** Tugon han manunurat\n** Utod nga redirek",
"delete-edit-reasonlist": "Igliwat an mga rason han pagpara",
+ "deleteprotected": "Diri nimo mapapara ini nga pakli tunod ini in ginpasaliporan.",
"rollback": "Mga libot-pabalik nga pagliwat",
"rollbacklink": "libot-pabalik",
"rollbacklinkcount": "rollback $1 {{PLURAL:$1|ka pagliwat|ka mga pagliwat}}",
+ "rollbacklinkcount-morethan": "Igrollback hin labaw han $1 nga {{PLURAL:$1|pagliwat|mga pagliwat}}",
"rollbackfailed": "Diri malinamposon an paglibot-pabalik",
+ "cantrollback": "Diri makakapabalik han pagliwat;\nan urhi nga nag-amot in amo la an awtor hinin nga pakli.",
+ "editcomment": "An halipotay nga masisiring hiunong han pagliwat in: <em>$1</em>.",
"revertpage": "Ginpabalik an ginliwat ni [[Special:Contributions/$2|$2]] ([[User talk:$2|hiruhimangraw]]) ngadto ha urhi nga pagliwat ni [[User:$1|$1]]",
"sessionfailure-title": "Pakyas an sesyon",
+ "changecontentmodel-title-label": "Titulo han pakli",
"changecontentmodel-reason-label": "Rason:",
+ "changecontentmodel-submit": "Balyo-a",
"protectlogpage": "Talaan han pinasaliporan",
"protectedarticle": "pinasaliporan \"[[$1]]\"",
"prot_1movedto2": "[[$1]] in ginbalhin ngadto ha [[$2]]",
"protectcomment": "Katadongan:",
"protect-default": "Togota an ngatanan nga mga gumaramit",
"protect-level-sysop": "Tuguti la an mga magdudumara",
+ "protect-expiring": "mawawaray gamit pag-$1 (UTC)",
+ "protect-expiring-local": "mawawaray gamit $1",
+ "protect-expiry-indefinite": "waray kataposan",
"protect-othertime": "Lain nga oras:",
"protect-othertime-op": "lain nga oras",
"protect-otherreason": "Lain/dugang nga katadongan:",
"restriction-move": "Balhina",
"restriction-create": "Himo-a",
"restriction-upload": "Igkarga-pasaka",
+ "restriction-level-sysop": "bug-os nga pinasaliporan",
+ "restriction-level-autoconfirmed": "tunga-tunga nga pinasaliporan",
"restriction-level-all": "bisan ano nga katupngan",
"undelete": "Igpakita an mga ginpara nga mga pakli",
+ "undeletepage": "Igpakita ngan igbalik-ha-pagkawara an mga pinara nga pakli",
+ "undeletepagetitle": "<strong>An masunod in nag-uupod hin mga pinara nga mga rebisyon han [[:$1|$1]]</strong>.",
+ "viewdeletedpage": "Igpakita an mga pinara nga pakli",
"undeletelink": "igpakita/igbalik",
"undeleteviewlink": "kitaa",
"undeletecomment": "Katadungan:",
"whatlinkshere-filters": "Mga panara",
"whatlinkshere-submit": "Kadto-a",
"block": "Pugngi an gumaramit",
- "blockip": "Pugngi an gumaramit",
+ "blockip": "Pugngi an{{GENDER:$1|gumaramit}}",
"blockip-legend": "Pugngi an gumaramit",
"ipaddressorusername": "IP address o agnay-hit-gumaramit:",
"ipbexpiry": "Matitima an dulot:",
"movenotallowedfile": "Waray ka pagtugot para makabalhin hin mga paypay.",
"cant-move-user-page": "Diri ka gintutugotan pagbalhin hin mga pakli nga gumaramit (labot la tikang ha mga bahin-pakli).",
"cant-move-to-user-page": "Diri ka gintutugotan pagbalhin hin uska pakli pakada ha uska pakli hin gumaramit (labot la pakadto ha usa nga bahin-pakli han gumaramit).",
- "newtitle": "Para ha bag-o nga titulo:",
+ "cant-move-category-page": "Waray ka pagtugot hin pagbalhin han mga kaarangay nga pakli.",
+ "cant-move-to-category-page": "Waray ka pagtugot pagbalhin hin pakli ngada ha kaarangay nga pakli.",
+ "newtitle": "Bag-o nga titulo:",
"move-watch": "Kitaa an tinikangan nga pakli ngan kakadtoan nga pakli",
"movepagebtn": "Igbalhin an pakli",
"pagemovedsub": "Malinamposon an pagbalhin",
"movepage-moved": "'''\"$1\" in ginbalhin ngadto ha \"$2\"'''",
"movepage-moved-redirect": "Nahimo an uska redirect.",
+ "movepage-moved-noredirect": "An paghimo hin redirect in nai-suppress.",
+ "articleexists": "May-ada na hiton nga ngaran nga pakli, o an ngaran nga imo pinili in diri balido.\nAlayon pagpili hin iba nga ngaran.",
+ "cantmove-titleprotected": "Didi ka makakabalhin hin pakli ngadi nga lokasyon tungod an bag-o nga titulo in pinasaliporan tikang ha paghimo.",
+ "movetalk": "Igbalhin an may pagkahisumpay nga pakighimangraw-nga-pakli",
"move-subpages": "Balhina an mga bahin-pakli (tubtob ngadto ha $1)",
"move-talk-subpages": "Balhina an mga bahin-pakli han pakli han hiruhimangraw (tubtob ngadto ha $1)",
"movepage-page-exists": "An pakli nga $1 in aada na ngan diri ini lugaring nga masasapawan pagsurat.",
"movepage-page-unmoved": "An pakli nga $1 in diri mababalhin ngadto ha $2.",
"movelogpage": "Talaan han pagbalhin",
"movelogpagetext": "Ubos hini in uska talaan han ngatanan nga nabalhin nga pakli",
+ "movesubpage": "{{PLURAL:$1|Ubos-pakli|Mga ubos-pakli}}",
+ "movesubpagetext": "Ini nga pakli in may-ada $1 nga {{PLURAL:$1|ubos-pakli|mga ubos-pakli}} nga ginpapakita ha ubos.",
"movenosubpage": "Ini nga pakli in waray mga bahin-pakli.",
"movereason": "Rason:",
"revertmove": "igbalik",
+ "delete_and_move_text": "An destinasyon nga pakli nga \"[[:$1]]\" in may-ada na.\nKaruyag mo nga igpara ini para maghatag hin paagi para hini nga pagbalhin?",
"delete_and_move_confirm": "Oo, paraa an pakli",
"delete_and_move_reason": "Ginpara para makahatag hin aragian para makabalhin tikang ha \"[[$1]]\"",
"selfmove": "An tinikangan ngan kakadtoan nga mga titulo in parehas;\ndiri makakabalhin ha iya kalugaringon ngahaw.",
"immobile-target-namespace-iw": "An sumpay interwiki in diri balido nga irig-on para han pagbalhin hin pakli.",
"immobile-source-page": "Diri mababalhin ini nga pakli.",
"immobile-target-page": "Diri makakabalhin ha ngada nga kakadtoon nga titulo.",
+ "imagenocrossnamespace": "Diri nakakabalhin hin file ngadto ha non-file namespace.",
+ "nonfile-cannot-move-to-file": "Diri nakakabalhin hin non-file ngadto ha file namespace.",
"imageinvalidfilename": "An kakadtoon nga ngaran-han-paypay in diri balido",
"move-leave-redirect": "Pagbilin hin redirect",
"export": "Mga pakli hit pagexport",
"importbadinterwiki": "Maraot nga sumpay hit interwiki",
"importsuccess": "Natapos an pag-aangbit!",
"import-noarticle": "Waray pakli nga maaangbit!",
- "import-token-mismatch": "Nawara an datos sesyon.\nAlayon utroha.",
- "import-error-edit": "An pakli nga \"$1\" in waray naangbit tungod nga diri ka gintutugotan pagliwat hini.",
- "import-error-create": "An pakli nga \"$1\" in waray naangbit tungod nga diri ka gintutugotan paghimo hini.",
- "import-error-interwiki": "An pakli nga \"$1\" in waray naangbit tungod nga an ngaran in nakareserba para han pagsusumpay ha gawas (interwiki).",
- "import-error-special": "An pakli nga \"$1\" in waray naangbit tungod nga nahihilakip ini ha uska pinaurog nga ngaran-lat'ang nga diri natugot hin mga pakli.",
- "import-error-invalid": "An pakli nga \"$1\" in waray naangbit tungod nga it iya ngaran in diri balido.",
+ "import-token-mismatch": "Nawara an datos sesyon.\n\n\nBangin ka naglog-out na. <strong>Alayon igberipika kun ikaw in nakalog-in pa ngan utro buhata</strong>. Kun diri pa iton nagana, alayon [[Special:UserLogout|pag-log out]] ngan paglog-in balik, ngan kitaa an imo browser kun natugot hin cookies tikang hinin nga site.",
+ "import-error-edit": "An pakli nga \"$1\" in waray napaangbit tungod nga diri ka gintutugotan pagliwat hini.",
+ "import-error-create": "An pakli nga \"$1\" in waray napaangbit tungod nga diri ka gintutugotan paghimo hini.",
+ "import-error-interwiki": "An pakli nga \"$1\" in waray napaangbit tungod nga an ngaran in nakareserba para han external linking (interwiki).",
+ "import-error-special": "An pakli nga \"$1\" in waray napaangbit tungod nga nahihilakip ini ha usa ka special namespace nga diri natugot hin mga pakli.",
+ "import-error-invalid": "An pakli nga \"$1\" in waray napaangbit tungod nga an ngaran kun diin inin ig-aangbit in diri balido para hinin nga wiki.",
"import-options-wrong": "Sayop {{PLURAL:$2|nga pirilion|nga mga pirilion}}: <nowiki>$1</nowiki>",
"import-rootpage-invalid": "An ginhatag nga gamot-pakli in uska diri balido nga titulo.",
"import-rootpage-nosubpage": "Ngaran-lat'ang nga \"$1\" han gamot-pakli in diri natugot hin mga bahin-pakli.",
"tooltip-feed-rss": "RSS nga pangarga para hini nga pakli",
"tooltip-feed-atom": "Atom nga pangarga para hini nga pakli",
"tooltip-t-contributions": "Kitaa an listahan hin mga amot {{GENDER:$1|hinin nga gumaramit}}",
- "tooltip-t-emailuser": "Padad-i hin e-mail ini nga nágámit",
+ "tooltip-t-emailuser": "Padad-i hin e-mail ngadto {{GENDER:$1|hinin nga gumaramit}}",
"tooltip-t-upload": "Pagkarga hin mga paypay",
"tooltip-t-specialpages": "Talaan hin mga pinaurog nga pakli",
"tooltip-t-print": "Maipapatik nga bersyon hini nga pakli",
"tooltip-compareselectedversions": "Kitaa an mga kaibhan ha butnga han duha nga pinili nga mga pagliwat hini nga pakli",
"tooltip-watch": "Dugnga ini nga pakli ngadto han imo talaan hin ginbibinantayan",
"tooltip-watchlistedit-normal-submit": "Igtanggal an mga titulo",
+ "tooltip-watchlistedit-raw-submit": "Ig-update an barantayon",
"tooltip-recreate": "Utroha paghimo an pakli bisan ini in ginpara na",
"tooltip-upload": "Tikanga an pagkarga-pasaka",
"tooltip-rollback": "An \"libot-pabalik\" in nabalik han (mga) pagliwat hini nga pakli ngadto han kataposan nga nag-amot hin usa ka pidlit",
"tooltip-preferences-save": "Tipiga an mga karuyag",
"tooltip-summary": "Pagbutang hin halipotay nga masisiring hiton pagliwat",
"interlanguage-link-title": "$1 – $2",
+ "anonymous": "Waray magpakilala nga {{PLURAL:$1|gumaramit|mga gumaramit}} han {{SITENAME}}",
"siteuser": "{{SITENAME}} gumaramit $1",
"anonuser": "{{SITENAME}} waray nagpakilala nga gumaramit $1",
+ "lastmodifiedatby": "Ini nga pakli in urhi ginliwat $2, $1 ni $3.",
"othercontribs": "Ginbasihan ha binuhat ni $1.",
"others": "mga iba",
- "siteusers": "{{SITENAME}} {{PLURAL:$2|gumaramit|mga gumaramit}} $1",
+ "siteusers": "{{SITENAME}} {{PLURAL:$2|{{GENDER:$1|gumaramit}}|mga gumaramit}} $1",
+ "anonusers": "{{SITENAME}} waray magpakilala nga {{PLURAL:$2|gumaramit|mga gumaramit}} $1",
+ "creditspage": "Pagkilala ha pakli",
+ "nocredits": "Waray pagkilala nga impormasyon para hinin nga pakli",
+ "spamprotectiontitle": "Filter para pag-iwas hit spam",
+ "spamprotectiontext": "An teksto nga karuyag nimo igtipig in ginpugong han spam filter.\nIni posible nahitabo tungod han sumpay ngadto ha usa nga blacklisted nga external site.",
+ "spamprotectionmatch": "An masunod nga teksto amo an nagpagana han amon spam filter: $1",
+ "spambot_username": "Paglimpyo han MediaWiki spam",
+ "spam_reverting": "Ginbabalik ha urhi nga rebisyon nga waray lakip nga sumpay ngadto ha $1",
+ "spam_blanking": "Ngatan nga mga rebisyon nga may-ada sumpay ngadto ha $1, ginhahawan",
+ "spam_deleting": "Ngatanan nga mga rebisyon nga naglalakip hin sumpay ngadto ha $1, ginpapara",
"simpleantispam-label": "Anti-spam check.\n<strong>Ayaw</strong> pagbinutangi dinhi!",
"pageinfo-title": "Impormasyon para \"$1\"",
"pageinfo-not-current": "Pasaylo-a, imposible makahatag hin impormasyon hiunong han mga daan nga rebisyon.",
"pageinfo-header-basic": "Panguna nga pananabotan",
"pageinfo-header-edits": "Kaagi han pagliwat",
"pageinfo-header-restrictions": "Panalipod han pakli",
+ "pageinfo-header-properties": "Mga propyudad han pakli",
"pageinfo-display-title": "Iglatag an titulo",
+ "pageinfo-default-sort": "Default sort key",
"pageinfo-length": "Kahilaba han pakli (ha mga byte)",
"pageinfo-article-id": "ID han pakli",
+ "pageinfo-language": "An ginagamit nga pinulongan han pakli",
+ "pageinfo-content-model": "An gingagamit nga modelo han pakli",
"pageinfo-robot-policy": "Pag-index hin mga robot",
"pageinfo-robot-index": "Gintutugot",
"pageinfo-robot-noindex": "Dírì gintutugot",
"pageinfo-watchers": "Ihap han nangingita hin pakli",
+ "pageinfo-visiting-watchers": "An kadamo han mga nagbabantay han pakli nga nagduaw ha mga bag-o nga pagliwat",
+ "pageinfo-few-watchers": "Guruguti han $1 nga {{PLURAL:$1|nagbabantay|mga nagbabantay}}",
+ "pageinfo-few-visiting-watchers": "Bangin may-ada o waray nagbabantay nga gumaramit nga nagduduaw han mga bag-o nga pagliwat",
"pageinfo-redirects-name": "Ihap hin mga redirek ngani nga pakli",
"pageinfo-subpages-name": "Mga bahinpakli hin nga pakli",
"pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|redirekta|mga redirekta}}; $3 {{PLURAL:$3|diri redirekta|mga diri redirekta}})",
"pageinfo-lastuser": "Giurhii nga nagliwat",
"pageinfo-lasttime": "Petsa han kataposan nga pagliwat",
"pageinfo-edits": "Ngatanan nga ihap han mga pakli",
+ "pageinfo-authors": "An kadamo han mga awtor",
+ "pageinfo-recent-edits": "An kadamo han mga bag-o nga mga pakli (ha sulod han naglabay nga $1)",
+ "pageinfo-recent-authors": "An kadamo han awtor nga nagliwat pala",
+ "pageinfo-magic-words": "Magic {{PLURAL:$1|word|words}} ($1)",
+ "pageinfo-hidden-categories": "Nakatago nga {{PLURAL:$1|kaarangay|mga kaarangay}} ($1)",
+ "pageinfo-templates": "Naka-transclude nga {{PLURAL:$1|batakan|mga batakan}} ($1)",
+ "pageinfo-transclusions": "{{PLURAL:$1|Pakli|Mga pakli}} nga naka-transclude ha ($1)",
"pageinfo-toolboxlink": "Impormasyon han pakli",
"pageinfo-redirectsto": "Igredirect ngadto ha",
"pageinfo-redirectsto-info": "info",
"show-big-image-preview": "Kadako hin nga pahiuna nga pagawas: $1.",
"show-big-image-other": "Iba {{PLURAL:$2|nga resolusyon|nga mga resolusyon}}: $1.",
"show-big-image-size": "$1 × $2 nga mga pixel",
+ "file-info-gif-looped": "naka-loop",
+ "file-info-png-looped": "naka-loop",
+ "file-info-png-frames": "$1 {{PLURAL:$1|frame|mga frame}}",
+ "file-no-thumb-animation": "<strong>Pasabot: Tungod hin limitasyon pan-teknikal\n, an mga thumbnail hinin nga file in diri naka-animate.</strong>",
+ "file-no-thumb-animation-gif": "<strong>Pasabot: Tungod hin limitasyon pan-teknikal\n, an mga thumbnail nga may-ada hitaas nga resolusyon nga GIF images sugad hini in diri naka-animate.</strong>",
"newimages": "Galeryia hin mga paypay nga bag-o",
+ "imagelisttext": "Ngadi ubos in lista hin <strong>$1</strong> ka {{PLURAL:$1|file|mga file}} nga naka-sort $2.",
+ "newimages-summary": "Ini nga ispisyal nga pakli in nagpapakita hin kataposan nga gin-upload nga mga file.",
"newimages-legend": "Panara",
"newimages-label": "Ngaran han paypay (o uska bahin hini):",
+ "newimages-showbots": "Igpakita an upload han mga bot",
+ "newimages-hidepatrolled": "Igtago an nakapatrolya nga mga upload",
"noimages": "Waray makikit-an.",
"ilsubmit": "Bilnga",
"bydate": "pinaagi han petsa",
+ "sp-newimages-showfrom": "Igpakita an mga bag-o nga file tikang $2, $1",
+ "seconds": "{{PLURAL:$1|$1 ka segundo|$1 ka mga segundo}}",
+ "minutes": "{{PLURAL:$1|$1 ka minuto|$1 ka mga minuto}}",
+ "hours": "{{PLURAL:$1|$1 ka oras|$1 ka mga oras}}",
+ "days": "{{PLURAL:$1|$1 ka adlaw|$1 ka mga adlaw}}",
+ "weeks": "{{PLURAL:$1|$1 ka semana|$1 ka mga semana}}",
+ "months": "{{PLURAL:$1|$1 ka bulan|$1 ka mga bulan}}",
+ "years": "{{PLURAL:$1|$1 ka tuig|$1 ka mga tuig}}",
"ago": "$1 an nakalabay",
"just-now": "yana pala",
+ "hours-ago": "{{PLURAL:$1|$1 ka oras|$1 ka mga oras}} nga naglabay",
+ "minutes-ago": "{{PLURAL:$1|$1 ka minuto|$1 ka mga minuto}} nga naglabay",
+ "seconds-ago": "{{PLURAL:$1|$1 ka segundo|$1 ka mga segundo}} nga naglabay",
"monday-at": "Lunes ha $1",
"tuesday-at": "Martes ha $1",
"wednesday-at": "Miyerkules ha $1",
"bad_image_list": "An kabutangan in masunod:\n\nAn nakatalala la nga mga butang (mga bagis nga nagtitikang hin *) in mahiuupod paglabot.\nAn syahan nga sumpay ha uska bagis in dapat may-ada sumpay ngadto ha maraot nga fayl.\nAn bisan ano nga masunod nga mga sumpay ha kapareho nga bagis in igtratrato nga eksepsyon, sugad hin, mga pakli kun diin an mga fayl in puydi mabubutang ha sulod han bagis.",
"metadata": "Metadata",
"metadata-help": "Iní nga paypay mayda dugang nga pagpasabot, nga bangin gindugáng tikang han digital nga camera o iskaner nga gin-gamit paghimo o pag-digitar hini.\nKon an paypay ginliwat tikang han orihinal nga kamutangan, mayda mga detalye nga bangin diri magpakita han ginliwat nga paypay",
+ "metadata-expand": "Igpakita an mga pinahilawig nga detalye",
+ "metadata-collapse": "Igtago an mga pinahilawig nga detalye",
"metadata-fields": "An mga rumbay han hulagway han metadato nga nakatala dinhi nga mensahe in iglalakip ha padayag hin hulagway nga pakli kun an taramdan metadato in nakalukot.\nAn iba in daan nakatago.\n* make\n* modelo\n* pitsaorasorihinal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpsngalatitud\n* gpsngalongitud\n* gpsngaaltitud",
"exif-imagewidth": "Kahaluag",
"exif-imagelength": "Kahitaas",
+ "exif-bitspersample": "Mga bit kada komponente",
"exif-orientation": "Orientation",
"exif-ycbcrpositioning": "Pagpoposisyon han Y ngan C",
"exif-xresolution": "Resolusyon horizontal",
"exif-copyrighted": "Kahimtang han copyright",
"exif-copyrightowner": "Tag-iya han copyright",
"exif-usageterms": "Mga termino hit paggamit",
+ "exif-copyrighted-true": "Naka-copyright",
"exif-copyrighted-false": "Status hin katungod-hin-panag-iya waray mahabutang",
"exif-unknowndate": "Waray kasabti an petsa",
"exif-orientation-1": "Normal",
+ "exif-orientation-3": "Igpalibot hin 180°",
+ "exif-orientation-4": "Igpalibot patukdaw",
+ "exif-orientation-5": "Igpalibot hin 90° CCW ngan igpalibot patukdaw",
+ "exif-orientation-6": "Igpalibot hin 90° CCW",
+ "exif-orientation-7": "Igpalibot hin 90° CW ngan igpalibot patukdaw",
+ "exif-orientation-8": "Igpalibot hin 90° CW",
"exif-exposureprogram-1": "Mano-mano",
+ "exif-exposureprogram-2": "Normal nga progama",
"exif-subjectdistance-value": "$1 ka mga metro",
"exif-meteringmode-0": "Waray kasabti",
"exif-meteringmode-255": "iba",
"confirm-watch-top": "Dudugngon ini nga pakli ngadto han imo talaan hin ginbibinantayan?",
"confirm-unwatch-button": "OK",
"confirm-unwatch-top": "Tatanggalon ini nga pakli tikang han imo tala hin binabantayan?",
+ "quotation-marks": "\"$1\"",
"imgmultipageprev": "← naha-una nga pakli",
"imgmultipagenext": "sunod nga pakli →",
"imgmultigo": "Pakadto!",
"imgmultigoto": "Pakadto ha pakli $1",
+ "img-lang-go": "Kadto",
"ascending_abbrev": "pasaka",
"descending_abbrev": "paubos",
"table_pager_next": "Sunod nga pakli",
"autosumm-replace": "Ginsaliwanan an sulod hin \"$1\"",
"autoredircomment": "Ginredirecta an pakli ngada ha [[$1]]",
"autosumm-new": "Nahimo an pakli nga may \"$1\"",
+ "autosumm-newblank": "Paghimo hin blangko nga pakli",
"size-bytes": "$1 nga B",
"size-kilobytes": "$1 nga KB",
"size-megabytes": "$1 nga MB",
"size-gigabytes": "$1 nga GB",
+ "lag-warn-normal": "An mga pagbabag-o nga burubag-o han $1 ka {{PLURAL:$1|segundo|mga segundo}} in diri maipapakita dinhi nga lista.",
"watchlistedit-normal-title": "Igliwat an talaan han binabantayan",
"watchlistedit-normal-legend": "Igtanggal an mga titulo tikang ha talaan hit binabantayan",
"watchlistedit-normal-submit": "Igtanggal an mga titulo",
"watchlistedit-raw-done": "Ginpayana an imo talaan han barantayon.",
"watchlistedit-raw-added": "{{PLURAL:$1|1 nga titulo|$1 nga mga titulo}} in gindugang:",
"watchlistedit-raw-removed": "{{PLURAL:$1|1 nga titulo|$1 nga mga titulo}} in gintanggal:",
+ "watchlistedit-clear-titles": "Mga titulo:",
+ "watchlistedit-clear-submit": "Hawana an barantayon nga listahan (Permamente ini!)",
"watchlisttools-view": "Kitaa an mga nanginginlabot nga mga pagbabag-o",
"watchlisttools-edit": "Kitaa ngan igliwat an talaan han binabantayan",
"watchlisttools-raw": "Igliwat an hilaw nga talaan han binabantayan",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|hiruhimangraw]])",
+ "timezone-local": "Lokal",
"duplicate-defaultsort": "'''Pahimatngon:''' An daan-aada nga paglainlain nga piridlitan nga \"$2\" in igsasapaw an durudaan nga daan-aada nga paglainlain nga piridlitan nga \"$1\".",
"version": "Bersyon",
- "version-skins": "Mga panit",
+ "version-skins": "Mga panit nga naka-install",
"version-specialpages": "Mga pinaurog nga pakli",
"version-parserhooks": "Mga kawil parser",
"version-variables": "Mga variable",
"version-hook-name": "Ngaran han kawil",
"version-version": "($1)",
"version-license": "MediaWiki nga Lisensya",
+ "version-ext-license": "Lisensya",
+ "version-skin-colheader-name": "Panit",
+ "version-ext-colheader-version": "Bersyon",
+ "version-ext-colheader-license": "Lisensya",
+ "version-ext-colheader-description": "Deskripsyon",
+ "version-ext-colheader-credits": "Mga awtor",
+ "version-license-title": "Lisensya para han $1",
+ "version-license-not-found": "Waray detalye han impormasyon han lisensya nga mahihiagian para hinin nga ekstensyon.",
+ "version-credits-title": "Pagkilala para kan $1",
+ "version-credits-not-found": "Waray detalye nga mga pagkilala nga impormasyon an mahihiagian para hinin nga ekstensyon.",
"version-poweredby-credits": "Ini nga wiki in pinapaandar han '''[https://www.mediawiki.org/ MediaWiki]''', copyright © 2001-$1 $2.",
"version-poweredby-others": "mga iba",
+ "version-poweredby-translators": "mga maghuhubad han translatewiki.net",
+ "version-credits-summary": "Gusto namon ngaranon an masunod nga mga tawo tungod han ira mga amot ha [[Special:Version|MediaWiki]].",
"version-software-product": "Produkto",
"version-software-version": "Bersyon",
"version-entrypoints": "Surudlan nga mga URL",
"version-entrypoints-header-entrypoint": "Surudlan",
"version-entrypoints-header-url": "URL",
+ "version-libraries-version": "Bersyon",
+ "version-libraries-license": "Lisensya",
+ "version-libraries-description": "Deskripsyon",
+ "version-libraries-authors": "Mga awtor",
+ "redirect-submit": "Kadtoa",
+ "redirect-file": "Ngaran han file",
"fileduplicatesearch": "Pamiling hin nadoble nga mga paypay",
"fileduplicatesearch-filename": "Ngaran han paypay:",
"fileduplicatesearch-submit": "Pamilnga",
"fileduplicatesearch-noresults": "Waray nabilngan nga paypay nga an ngaran in \"$1\".",
"specialpages": "Mga pinaurog nga pakli",
+ "specialpages-note-top": "Leyenda",
"specialpages-group-maintenance": "Mga sumat han pagmintinar",
"specialpages-group-other": "Mga iba nga pinaurog nga pakli",
"specialpages-group-login": "Magpalista nga masakob / paghimo hin bag-o nga akawnt",
"tag-filter": "[[Special:Tags|Tag]] panara:",
"tag-filter-submit": "Panara",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ka tag|ka mga tag}}]]: $2)",
+ "tags-title": "Mga tag",
+ "tags-tag": "Ngaran han tag",
+ "tags-source-header": "Tinikangan",
+ "tags-active-header": "Nagios?",
+ "tags-actions-header": "Mga buhat",
+ "tags-active-yes": "Oo",
+ "tags-active-no": "Diri",
"tags-edit": "igliwat",
+ "tags-delete": "paraa",
"tags-hitcount": "$1 {{PLURAL:$1|nga pagbag-o|nga mga pagbag-o}}",
+ "tags-create-reason": "Rason:",
+ "tags-create-submit": "Himoa",
+ "tags-delete-title": "Igpara an tag",
+ "tags-delete-reason": "Rason:",
+ "tags-activate-reason": "Rason:",
+ "tags-deactivate-reason": "Rason:",
+ "tags-edit-new-tags": "Mga bag-o nga tag:",
+ "tags-edit-add": "Dugngi ini nga mga tag:",
+ "tags-edit-remove": "Tanggala ini nga mga tag:",
+ "tags-edit-remove-all-tags": "(tanggala an ngatanan nga mga tag)",
+ "tags-edit-chosen-placeholder": "Pilia an pipira nga mga tag",
+ "tags-edit-chosen-no-results": "Waray tag nga kaparehas",
+ "tags-edit-reason": "Rason:",
"comparepages": "Igkumpara an mga pakli",
"compare-page1": "Pakli 1",
"compare-page2": "Pakli 2",
"logentry-newusers-autocreate": "An gumaramit nga akawnt nga $1 in lugaring nga {{GENDER:$2|ginhimo}}",
"logentry-upload-upload": "Hi $1 {{GENDER:$2|gin-upload}} an $3",
"rightsnone": "(waray)",
+ "feedback-back": "Balik",
"feedback-cancel": "Pasagdi",
"feedback-close": "Human na.",
+ "feedback-error-title": "Sayop",
"feedback-error2": "Sayop: Pakyas an pagliwat",
"feedback-message": "Mensahe:",
"feedback-subject": "Himangrawon:",
+ "feedback-thanks-title": "Salamat!",
"searchsuggest-search": "Pamilnga",
"searchsuggest-containing": "nagsusulod. . .",
"api-error-badaccess-groups": "Diri ka gintutugotan pagkarga paigbaw ha dinhi nga wiki.",
"duration-years": "$1 {{PLURAL:$1|tuig|mga tuig}}",
"duration-decades": "$1 {{PLURAL:$1|dekada|mga dekada}}",
"duration-centuries": "$1 {{PLURAL:$1|gatostuig|mga gatostuig}}",
- "duration-millennia": "$1 {{PLURAL:$1|yukottuig|mga yukottuig}}"
+ "duration-millennia": "$1 {{PLURAL:$1|yukottuig|mga yukottuig}}",
+ "mediastatistics-header-unknown": "Waray kasabti",
+ "mediastatistics-header-audio": "Audio",
+ "mediastatistics-header-video": "Mga video",
+ "mediastatistics-header-office": "Buhatan",
+ "mediastatistics-header-total": "Ngatanan nga pakli"
}
"noname": "用户名无效。",
"loginsuccesstitle": "登录哉",
"loginsuccess": "<strong>侬现在以“$1”个身份登录到{{SITENAME}}。</strong>",
- "nosuchuser": "寻弗着用户“$1”。用户名是大小写敏感外加区分繁简体个。请检查拼写,或者[[Special:UserLogin/signup|开只新账户]]。",
+ "nosuchuser": "寻弗着用户“$1”。用户名是大小写敏感外加区分繁简体个。请检查拼写,或者[[Special:CreateAccount|开只新账户]]。",
"nosuchusershort": "无没叫“$1”个用户。请检查侬个输入。",
"nouserspecified": "侬必须选个用户名。",
"login-userblocked": "箇个用户拨封锁拉许。弗允许登录。",
"accmailtext": "已经为[[User talk:$1|$1]]产生只随机密码,并且已经发送到$2。登录之后,侬可以垃拉<em>[[Special:ChangePassword|箇只页面]]</em>更改密码。",
"newarticle": "(新)",
"newarticletext": "倷跟著链接来着一个还弗勒里个页面。要创建该页面呢,就勒下底个框里向开始写([$1 帮助页面]浪有更加多个信息)。要是倷是弗用心到该𡍲个说话,请点击浏览器个<strong>返回</strong>揿钮。",
- "anontalkpagetext": "---- ''箇是一个还弗曾建立账户个匿名用户个讨论页, 箇咾我伲只好用IP地址来搭渠联络。该IP地址可能由几名用户共享。如果侬是一名匿名用户并认为箇只页面高头个评语搭侬弗搭界,请 [[Special:UserLogin/signup|创建新账户]]或[[Special:UserLogin|登录]]来避免垃拉将来搭其他匿名用户混淆。''",
+ "anontalkpagetext": "----\n<em>箇是一位还弗曾建立账号或者呒不使用账号个匿名用户个讨论页。</em>箇咾我伲只好用数字IP地址来识别渠。该IP地址可能由几名用户共享。如果侬是一名匿名用户并认为箇只页面高头个评语搭侬弗搭界,请[[Special:CreateAccount|创建只账号]]或[[Special:UserLogin|登录]]来避免垃拉将来搭其他匿名用户混淆。",
"noarticletext": "箇只页面目前呒没文本。侬可以垃拉其他页面高头[[Special:Search/{{PAGENAME}}|寻该只标题]]、<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 寻相关日志]或[{{fullurl:{{FULLPAGENAME}}|action=edit}} 建立此页]</span>。",
"noarticletext-nopermission": "箇只页面目前呒不文本。侬可以垃拉其他页面高头[[Special:Search/{{PAGENAME}}|寻箇页标题]],或者<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 寻相关日志]</span>,但必过侬呒不权限建立箇只页面。",
"userpage-userdoesnotexist": "用户账户“<nowiki>$1</nowiki>”弗曾创建。请垃拉创建/编辑迭个页面前头先检查一记。",
"blockipsuccesstext": "[[Special:Contributions/$1|$1]]已经畀查封。<br />\n参看[[Special:BlockList|查封列表]]来复审查封。",
"ipblocklist": "封脱个用户",
"infiniteblock": "永远",
+ "blocklist-nousertalk": "弗准编辑自家个讨论页",
"blocklink": "封禁",
"unblocklink": "解封",
"change-blocklink": "改变封禁",
"blocklogtext": "该个是用户查封搭著解封操作个记录。自动查封个IP地址弗会列勒该𡍲。到[[Special:BlockList|封禁列表]]去看当前生效个查封。",
"unblocklogentry": "$1已经拨解封",
"block-log-flags-nocreate": "建账号禁用哉",
+ "block-log-flags-nousertalk": "弗准编辑自家个讨论页",
"lockdb": "鎖數據庫",
"unlockdb": "開鎖數據庫",
"lockbtn": "鎖數據庫",
"noname": "Та зөвшәсн демнәчнә нер заасн уга.",
"loginsuccesstitle": "Йовудта орлһн",
"loginsuccess": "<strong>Та ода «$1» нертә {{SITENAME}} төсвд бәәнәт.</strong>",
- "nosuchuser": "«$1» нертә демнәч уга.\nДемнәчнә нернд баһ болн том үзгүд әдл биш.\nЧик бичсн шүүтн аль [[Special:UserLogin/signup|бигчдлһн бүтәтн]].",
+ "nosuchuser": "«$1» нертә демнәч уга.\nДемнәчнә нернд баһ болн том үзгүд әдл биш.\nЧик бичсн шүүтн аль [[Special:CreateAccount|бигчдлһн бүтәтн]].",
"nosuchusershort": "«$1» нертә демнәч уга.\nЧик бичсн шүүтн.",
"nouserspecified": "Та демнәчнә нер заах йоста.",
"login-userblocked": "Эн демнәч бүслсн, орҗ болшго.",
"nstab-template": "თანგი",
"nstab-help": "დახმარება",
"nstab-category": "კატეგორია",
+ "mainpage-nstab": "დუდხასჷლა",
"nosuchaction": "მოქმედება არ არსებობს",
"nosuchactiontext": "URL-ის მიერ მითითებული მოქმედება მცდარია.\nშესაძლოა შეცდომით აკრიფეთ URL, ან არასწორ ბმულზე გადახვედით.\nაგრეთვე შესაძლოა, {{SITENAME}}-ს მიერ გამოყენებულ პროგრამულ უზრუნველყოფაში იყოს შეცდომა.",
"nosuchspecialpage": "თეჯგუა გჷშაკერძაფილი ხასჷლეფი ვარსებენს",
"noname": "თქვენს მიერ მითითებული მომხმარებლის სახელი ქმედითი არ არის.",
"loginsuccesstitle": "სისტემაში შესვლა განხორციელდა.",
"loginsuccess": "'''ასე მიშულირ რეთ {{SITENAME}}-ს მუჭოთ \"$1\".'''",
- "nosuchuser": "მომხმარებელი სახელად $1 არ არსებობს.\nმომხმარებელთა სახელები გრძნობადია ასოების რეგისტრამდე..\nშეამოწმეთ სახელის დაწერა ან[[Special:UserLogin/signup|შექმენით ახალი ანგარიში]].",
+ "nosuchuser": "მომხმარებელი სახელად $1 არ არსებობს.\nმომხმარებელთა სახელები გრძნობადია ასოების რეგისტრამდე..\nშეამოწმეთ სახელის დაწერა ან[[Special:CreateAccount|შექმენით ახალი ანგარიში]].",
"nosuchusershort": "მომხმარებელი სახელით „$1“ არ არსებობს. შეამოწმეთ მართლწერა.",
"nouserspecified": "საჭირო რე მახვარებუშ ჯოხოშ მიშაჭარუა.",
"login-userblocked": "ეს მომხმარებელი დაბლოკილია. სისტემაში შესვლა არაა ნებადართული.",
"accmailtext": "შემთხვევითი მეთოდით შექმნილი პაროლი მომხმარებლისათვის [[User talk:$1|$1]] გაგზავნილია მისამართზე $2.\n\nავტორიზაციის გავლის შემდეგ შესაძლებელი იქნება ამ ანგარიშის <em>[[Special:ChangePassword|პაროლის შეცვლა]]</em> ანგარიშში შესვლის გვერდზე.",
"newarticle": "(ახალ)",
"newarticletext": "თქვა გეჸუნელჷ რეთ ხასჷლაშ რცხის, ნამუთ დიო ვა რე დორცხუაფილი.\nხასჷლაშ დარცხუაფალო გემშეჸონით ტექსტი თუდონ ოჭკორიეშა. (ქოძირით[$1 მოხვარაშ ხასჷლა] უმოს ინფორმაციაშო).\nთე ხასჷლას ჩილათირო მოხვადით–და, ქიგუნჭირით თქვან ბრაუზერიშ კონჭის '''უკახალე'''.\"",
- "anontalkpagetext": "----\n<em>ეს არის ანონიმური მომხმარებლის განხილვის გვერდი, რომელსაც ანგარიში ჯერ არ შეუქმნია ან არ იყენებს მას.</em>\n\nშესაბამისად, ჩვენ მისი ციფრული IP მისამართი უნდა გამოვიყენოთ მისი იდენტიფიცირებისთვის.\n\nამგვარი მისამართი შეიძლება რამდენიმე მომხმარებელმა გამოიყენოს.\n\nთუ თქვენ ანონიმური მომხმარებელი ხართ და თვლით, რომ სხვისთვის გამიზნული მითითება მიიღეთ, გთხოვთ [[Special:UserLogin/signup|შექმენით ანგარიში ან დარეგისტრირდით]] მომავალში გაუგებრობის თავიდან ასაცილებლად.",
- "noarticletext": "á\83\90á\83¡á\83\94 á\83\97á\83\94 á\83®á\83\90á\83¡á\83·á\83\9aá\83\90á\83¡ á\83¢á\83\94á\83¥á\83¡á\83¢á\83\98 á\83\95á\83\90 á\83 á\83\94. \ná\83\97á\83¥á\83\95á\83\90 á\83¨á\83\94á\83\98á\83\9aá\83\94á\83\91á\83£á\83\9cá\83\90 [[Special:Search/{{PAGENAME}}|á\83\92á\83\9dá\83 á\83\90á\83\97 á\83\90á\83\97á\83\94 á\83®á\83\90á\83¡á\83·á\83\9aá\83\90á\83¨ á\83¯á\83\9dá\83®á\83\9d]] á\83¨á\83®á\83\95á\83\90 á\83®á\83\90á\83¡á\83·á\83\9aá\83\94á\83¤á\83¡,\n<span class=\\\"plainlinks\\\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} á\83\93á\83\9dá\83\92á\83\9dá\83 á\83\90á\83\97 á\83\9bá\83\94á\83®á\83£á\83¯á\83\90á\83¤á\83\98á\83\9a á\83\9fá\83£á\83 á\83\9cá\83\90á\83\9aá\83\94á\83¤á\83\98],\ná\83\95á\83\90á\83 á\83\90 [{{fullurl:{{FULLPAGENAME}}|action=edit}} á\83\93á\83\98á\83á\83§á\83\90á\83\97 á\83\90á\83\97á\83\94 á\83®á\83\90á\83¡á\83·á\83\9aá\83\90á\83¨ á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\90á\83¤ა]</span>.",
+ "anontalkpagetext": "----\n<em>ეს არის ანონიმური მომხმარებლის განხილვის გვერდი, რომელსაც ანგარიში ჯერ არ შეუქმნია ან არ იყენებს მას.</em>\n\nშესაბამისად, ჩვენ მისი ციფრული IP მისამართი უნდა გამოვიყენოთ მისი იდენტიფიცირებისთვის.\n\nამგვარი მისამართი შეიძლება რამდენიმე მომხმარებელმა გამოიყენოს.\n\nთუ თქვენ ანონიმური მომხმარებელი ხართ და თვლით, რომ სხვისთვის გამიზნული მითითება მიიღეთ, გთხოვთ [[Special:CreateAccount|შექმენით ანგარიში ან დარეგისტრირდით]] მომავალში გაუგებრობის თავიდან ასაცილებლად.",
+ "noarticletext": "á\83\90á\83¡á\83\94 á\83\97á\83\94 á\83®á\83\90á\83¡á\83·á\83\9aá\83\90á\83¡ á\83¢á\83\94á\83¥á\83¡á\83¢á\83\98 á\83\95á\83\90 á\83 á\83\94. \ná\83\97á\83¥á\83\95á\83\90 á\83¨á\83\94á\83\98á\83\9aá\83\94á\83\91á\83£á\83\9cá\83\90 [[Special:Search/{{PAGENAME}}|á\83\92á\83\9dá\83 á\83\90á\83\97 á\83\90á\83\97á\83\94 á\83®á\83\90á\83¡á\83·á\83\9aá\83\90á\83¨ á\83¯á\83\9dá\83®á\83\9d]] á\83¨á\83®á\83\95á\83\90 á\83®á\83\90á\83¡á\83·á\83\9aá\83\94á\83¤á\83¡,\n<span class=\\\"plainlinks\\\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} á\83\93á\83\9dá\83\92á\83\9dá\83 á\83\90á\83\97 á\83\9bá\83\94á\83®á\83£á\83¯á\83\90á\83¤á\83\98á\83\9a á\83\9fá\83£á\83 á\83\9cá\83\90á\83\9aá\83\94á\83¤á\83\98],\ná\83\95á\83\90á\83 á\83\90 [{{fullurl:{{FULLPAGENAME}}|action=edit}} á\83\93á\83\98á\83á\83§á\83\90á\83\97 á\83\90á\83\97á\83\94 á\83®á\83\90á\83¡á\83·á\83\9aá\83\90á\83¨ á\83\90á\83\99á\83\9dá\83¥á\83\98á\83\9bá\83\98á\83\9cá\83£ა]</span>.",
"noarticletext-nopermission": "ათე ხასჷლას ასე ტექსტი ვა რე. თქვა შეილებუნა [[Special:Search/{{PAGENAME}}|დოგორათ თე ხასჷლაშ დუდჯოხო]] შხვა ხასჷლეფს,\nვარდა <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} დოგორათ გინორცხილ ჟურნალეფი]</span>.",
"missing-revision": "ვერსია $1 გვერდისათვის „{{FULLPAGENAME}}“ არ არსებობს.\n\nეს ჩვეულებრივ ხდება მაშინ, თუ მოძველებული ბმულით გადადიხართ გვერდზე, რომელიც წაიშალა.\nდეტალური ინფორმაცია შესაძლებელია იყოს [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} წაშლების ჟურნალში].",
"userpage-userdoesnotexist": "მახვარებუშ ანგარიში „$1“ ვაარსებენს. დერწმუნით, ნამჷ-და დასურო გოკონა თე ანგარიშიშ დორსხუაფა ვარდა მიშათინუა.",
"allpagessubmit": "გინულა",
"categories": "კატეგორიეფი",
"categoriesfrom": "გეგმარჩქინ ხასილეფ დოჭყაფილ:",
- "special-categories-sort-count": "დაალაგეთ რაოდენობის მიხედვით",
- "special-categories-sort-abc": "ანბანზე დალაგება",
"deletedcontributions": "მომხმარებლის წაშლილი წვლილი",
"deletedcontributions-title": "წაშლილი წვლილი",
"sp-deletedcontributions-contribs": "წვლილი",
"contributions": "{{GENDER:$1|მახვარებუშ}} მიშნაღელ თია",
"contributions-title": "$1-შა მახვარებუშ მიშაღალირ თია",
"mycontris": "ჩქიმ მიშნაღელ თია",
+ "anoncontribs": "მიშნაღელი თიეფი",
"contribsub2": "$1 ($2) შენი",
"uctop": "(დუდ)",
"month": "ათე თუთაშე (დო უადრაშე):",
"whatlinkshere-next": "{{PLURAL:$1|უკულიან|უკულიან $1}}",
"whatlinkshere-links": "← რცხიეფ",
"whatlinkshere-hideredirs": "გინოწურაფა $1",
- "whatlinkshere-hidetrans": "$1 ტრანსკლუზიეფ",
- "whatlinkshere-hidelinks": "$1 რცხუეფ",
+ "whatlinkshere-hidetrans": "$1 ტრანსკლუზიეფი",
+ "whatlinkshere-hidelinks": "$1 რცხუეფი",
"whatlinkshere-hideimages": "$1 ფაილიშ რცხუეფი",
"whatlinkshere-filters": "ტკიბირეფი",
"autoblockid": "ავტომატური ბლოკირება #$1",
"import-upload-filename": "ფაილის სახელი:",
"import-comment": "კომენტარეფი:",
"importlogpage": "იმპორტიშ ჟურნალ",
- "tooltip-pt-userpage": "თქვანი მახვარებუშ ხასჷლა",
- "tooltip-pt-mytalk": "თქვან სხუნუაშ ხასჷლა",
- "tooltip-pt-preferences": "ჩქიმ კონფიგურაციეფი",
+ "tooltip-pt-userpage": "{{GENDER:|თქვანი მახვარებუშ}} ხასჷლა",
+ "tooltip-pt-mytalk": "{{GENDER:|თქვანი}} სხუნუაშ ხასჷლა",
+ "tooltip-pt-preferences": "{{GENDER:|თქვანი}} კონფიგურაცია",
"tooltip-pt-watchlist": "ხასჷლეფიშ ერკებულ, ნამუშ მონიტორინგის ორთუთ თირაფაშ ღანკით",
- "tooltip-pt-mycontris": "თქვან მიშნაღელ თიეფიშ ერკებულ",
+ "tooltip-pt-mycontris": "{{GENDER:|თქვანი}} მიშნაღელი თიაშ ერკებული",
"tooltip-pt-login": "ჯგირ იჸი გემშურთუ–და, მარა თენა ვა რე უციო",
"tooltip-pt-logout": "გიშულა",
"tooltip-pt-createaccount": "ჩქი გიზალუთ, გონწყათ ანგარიში დო გენშართათ სისტემაშა; მარა თენა ვა რე უციო",
"tooltip-t-permalink": "პერმანენტულ რცხი ხასილაშ თე ვერსიაშა",
"tooltip-ca-nstab-main": "დინორეშ ხასჷლაშ ძირაფა",
"tooltip-ca-nstab-user": "მახვარებუშ ხასჷლაშ ძირაფა",
- "tooltip-ca-nstab-special": "თქვა ასე რეთ სპეციალურ ხასჷლას, თქვა ვა შეილებუნა ათე ხასჷლაშ რედაქტირაფა",
+ "tooltip-ca-nstab-special": "თქვა ასე რეთ სპეციალურ ხასჷლას დო თქვა შეილებუნა თიშ რედაქტირაფა",
"tooltip-ca-nstab-project": "პროექტიშ ხასჷლაშ ძირაფა",
"tooltip-ca-nstab-image": "ფაილიშ ხასჷლაშ ძირაფა",
"tooltip-ca-nstab-template": "თანგიშ ძირაფა",
"version-libraries-library": "ბიბლიოთეკა",
"version-libraries-version": "ვერსია",
"redirect": "გადამისამართება ფაილიდან, მომხმარებლიდან, გვერდიდან ან ვერსიის იდენტიფიკატორიდან",
- "redirect-legend": "გადამისამართება ფაილზე ან გვერდზე",
"redirect-summary": "ეს დამხმარე გვერდი ამისამართებს ფაილის (ფაილის სახელიდან) გვერდზე, (გვერდის ან ვერსიის იდენტიფიკატორიდან) ან მომხმარებლის გვერდზე (მომხმარებლის რაოდენობრივი იდენტიფიკატორიდან). გამოყენება: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]] ან [[{{#Special:Redirect}}/user/101]].",
"redirect-submit": "გინულა",
"redirect-lookup": "ძიება:",
"redirect-not-exists": "მნიშვნელობა ვერ მოიძებნა",
"fileduplicatesearch": "ერთნაირი ფაილების ძიება",
"fileduplicatesearch-summary": "ერთნაირი ფაილების ძიება ჰეშ-კოდის მიხედვით.",
- "fileduplicatesearch-legend": "დუბლიკატების ძიება",
"fileduplicatesearch-filename": "ფაილის სახელი:",
"fileduplicatesearch-submit": "გორუა",
"specialpages": "გჷშაკერძაფილი ხასჷლეფი",
"පසිඳු කාවින්ද",
"Matma Rex",
"Macofe",
- "Nemo bis"
+ "Nemo bis",
+ "Alefbeis"
]
},
"tog-underline": "שטרייכט אונטער לינקען",
"tog-watchdefault": "צולייגן בלעטער וואס איך רעדאקטיר צו מיין אכטונג ליסטע",
"tog-watchmoves": "צולייגן בלעטער וואס איך באוועג און טעקעס וואס איך לאד ארויף צו מיין אכטונג ליסטע",
"tog-watchdeletion": "צולייגן בלעטער וואס איך מעק אויס צו מיין אויפפאסונג ליסטע",
+ "tog-watchuploads": "לייגט צו נייע פיילס וואס איך טוה ארויפלאדירן צו מיין וואטש ליסטע",
"tog-watchrollback": "צולייגן צו מיין אויפפאסן ליסטע בלעטער אויף וואס איך האב אדורכגעפירט א צוריקשטעלן.",
"tog-minordefault": "באגרענעצן אלע רעדאַקטירונגען גרונטלעך אלס מינערדיק",
"tog-previewontop": "צײַג די \"פֿאָרויסיגע װײַזונג\" גלײַך בײַ דער ערשטער באַאַרבעטונג",
"tog-ccmeonemails": "שיק מיר קאפיעס פון בליצבריוו וואס איך שיק צו אנדערע באַניצער",
"tog-diffonly": "ווייז נישט אינהאלט אונטער די דיפערענץ",
"tog-showhiddencats": "ווײַזן באהאלטענע קאטעגאריעס",
- "tog-norollbackdiff": "×\94×\99פ×\98 ×\90×\99×\91ער ווײַזן אונטערשייד נאכן אויספֿירן א צוריקדריי",
+ "tog-norollbackdiff": "× ×\99ש×\98 ווײַזן אונטערשייד נאכן אויספֿירן א צוריקדריי",
"tog-useeditwarning": "שטעלן א ווארענונג ווען איך לאז איבער א רעדאקטירונג בלאט מיט נישט אויפגעהיטענע ענדערונגען",
"tog-prefershttps": "ניצט שטענדיק א זיכערע פארבינדונג ווען ארײַנגלאגירט",
"underline-always": "אייביג",
"february-gen": "פעברואר",
"march-gen": "מערץ",
"april-gen": "אַפּריל",
- "may-gen": "×\9e×\99י",
+ "may-gen": "×\9e×\90Ö·י",
"june-gen": "יוני",
"july-gen": "יולי",
"august-gen": "אויגוסט",
"returnto": "צוריקקערן צו $1.",
"tagline": "פֿון {{SITENAME}}",
"help": "הילף",
- "search": "×\96×\95×\9b×\9f",
- "searchbutton": "×\96×\95×\9b×\9f",
+ "search": "×\96×\95×\9a",
+ "searchbutton": "×\96×\95×\9a",
"go": "גיין",
"searcharticle": "גיין",
"history": "בלאט היסטאריע",
"protectedpage": "באשיצטער בלאט",
"jumpto": "שפּרינג צו:",
"jumptonavigation": "נאַוויגאַציע",
- "jumptosearch": "×\96×\95×\9b×\9f",
+ "jumptosearch": "×\96×\95×\9a",
"view-pool-error": "אנטשולדיגט, די סערווערס זענען איבערגעפילט איצט.\nצופיל באניצער פרובירן צו ליינען דעם בלאט.\nביטע ווארטן א ביסל צייט בעפאר איר פרובירט ווידער אריינגיין אינעם בלאט.\n\n$1",
"generic-pool-error": "אנטשולדיגט, די סערווערס זענען איבערגעפילט איצט.\nצופיל באניצער פרובירן צו באקוקן דעם רעסורס.\nביטע ווארטן א ביסל צייט בעפאר איר פרובירט ווידער אריינטרעטן אין דעם רעסורס.",
"pool-timeout": "אַריבער דער צײַט וואַרטן פֿאר דער שליסונג",
"newmessageslinkplural": "{{PLURAL:$1|א נייע מעלדונג|999=נייע מעלדונגען}}",
"newmessagesdifflinkplural": "לעצטע {{PLURAL:$1|ענדערונג|999=ענדערונגען}}",
"youhavenewmessagesmulti": "איר האט נייע מעלדונגען אין $1",
- "editsection": "×\91×\90Ö·×\90ַר×\91×¢×\98ן",
+ "editsection": "רע×\93×\90ַק×\98×\99רן",
"editold": "רעדאַקטירן",
"viewsourceold": "ווײַזן מקור",
"editlink": "רעדאַקטירן",
"red-link-title": "$1 (בלאט טוט נאָך נישט עקזיסטירן)",
"sort-descending": "סארטירן אַראָפ",
"sort-ascending": "סארטירן אַרויף",
- "nstab-main": "×\90ַר×\98×\99ק×\9c",
+ "nstab-main": "×\91×\9c×\90Ö·×\98",
"nstab-user": "באַניצער בלאט",
"nstab-media": "מעדיע בלאט",
"nstab-special": "ספעציעלער בלאט",
"virus-unknownscanner": "אומבאוואוסטער אנטי־ווירוס:",
"logouttext": "'''איר האָט זיך ארויסלאָגירט.'''\n\nבאמערקט אז געוויסע בלעטער קענען זיך ווייטער ארויסשטעלן אזוי ווי ווען איר זענט אריינלאגירט, ביז איר וועט אויסליידיגן דעם בלעטערער זאפאס.",
"cannotlogoutnow-title": "קען נישט ארויסלאגירן אצינד",
+ "cannotlogoutnow-text": "ארויסלאגירן נישט מעגלעך ווען מען ניצט $1.",
"welcomeuser": "ברוך הבא, $1!",
"welcomecreation-msg": "מ'האט געשאפן אייער קאנטע.\nפארגעסט נישט צו ענדערן אייערע [[Special:Preferences|{{SITENAME}} פרעפערענצן]].",
"yourname": "באַניצער נאָמען:",
"userlogin-remembermypassword": "לאז מיך בלײַבן ארײַנלאגירט",
"userlogin-signwithsecure": "ניצן זיכערן סארווער",
"cannotloginnow-title": "קען נישט אריינלאגירן אצינד",
+ "cannotloginnow-text": "אריינלאגירן נישט מעגלעך ווען מען ניצט $1.",
"yourdomainname": "אײַער געביט:",
"password-change-forbidden": "איר קען נישט ענדערן פאסווערטער אויף דער וויקי.",
"externaldberror": "עס איז אדער פארגעקומען אן אויטענטיקאציע דאטנבאזע פֿעלער אדער איר זענט נישט ערמעגליכט צו דערהיינטיגן אייער דרויסנדיגע קאנטע.",
"nocookieslogin": "{{SITENAME}} נוצט קיכלעך כדי אַרײַנלאגירן באַניצער.\nבײַ אײַך זענען קיכלעך אומדערמעגלעכט.\nביטע אַקטיווירט זיי און פרובירט נאכאַמאָל.",
"nocookiesfornew": "מען האט נישט געשאַפֿן די באַניצער קאנטע, ווײַל מען האט נישט געקענט באַשטעטיקן איר מקור.\nטוט פֿעסטשטעלן אָז קיכלעך זענען אַקטיווירט, לאָדט אָן נאכאַמאל דעם בלאַט און פרואווט ווידער.",
"noname": "איר האט נישט אַרײַנגעשטעלט קײַן גילטיקן באַניצער נאָמען.",
- "loginsuccesstitle": "אריינלאגירט מיט הצלחה",
+ "loginsuccesstitle": "אריינלאגירט",
"loginsuccess": "'''איר זענט אַצינד אַרײַנלאָגירט אין {{SITENAME}} ווי \"$1\".'''",
- "nosuchuser": "נישטא קיין באניצער מיטן נאמען \"$1\".\n\nקוקט איבער אײַער אויסלייג, אדער [[Special:UserLogin/signup|שאַפֿט א נײַע קאנטע]].",
+ "nosuchuser": "נישטא קיין באניצער מיטן נאמען \"$1\".\n\nקוקט איבער אײַער אויסלייג, אדער [[Special:CreateAccount|שאַפֿט א נײַע קאנטע]].",
"nosuchusershort": "נישטאָ קיין באַניצער מיטן נאָמען \"$1\".\nביטע באַשטעטיקט דעם אויסלייג.",
"nouserspecified": "איר ברויכט ספעציפֿיצירן א באַניצער-נאָמען.",
"login-userblocked": "דער באַניצער איז בלאקירט. ארײַנלאגירן נישט ערלויבט.",
"createaccount-title": "קאנטע באשאפֿן אין {{SITENAME}}",
"createaccount-text": "עמעצער האט באשאפֿן א קאנטע פֿאר אייער ע-פאסט אדרעס אין {{SITENAME}} ($4) מיטן נאמען \"$2\" און פאסווארט \"$3\". איר דארפט אצינד איינלאגירן און ענדערן דאס פאסווארט.\n\nאיר קענט איגנארירן די מעלדונג, ווען די קאנטע איז באשאפֿן בטעות.",
"login-throttled": "איר האט געפרוווט צופֿיל מאל אריינלאגירן.\nזייט אזוי גוט און וואַרט $1 איידער איר פרוווט נאכאמאל.",
- "login-abort-generic": "×\90ײַער ×\90×¨×²Ö·× ×\9c×\90×\92×\99ר×\95× ×\92 ×\90×\99×\96 × ×\99ש×\98 ×\92×¢×\95×\95×¢×\9f ×\93ערפֿ×\90×\9c×\92ר×\99×\99×\9a—אָפגעשטעלט",
+ "login-abort-generic": "×\90ײַער ×\90×¨×²Ö·× ×\9c×\90×\92×\99ר×\95× ×\92 ×\90×\99×\96 ×\93×\95ר×\9b×\92עפ×\90×\9c×\9f—אָפגעשטעלט",
"login-migrated-generic": "אײַער קאנטע איז געווארן מיגרירט, און אײַער באניצער־נאמען איז מער נישט פאראן אויף דער וויקי.",
"loginlanguagelabel": "שפראך: $1",
"suspicious-userlogout": " אײַער בקשה אַרויסלאָגירן זיך איז אפגעלייגט געווארן ווייַל אייגנטלעך איז זי געשיקט דורך אַ צעבראכענעם בלעטערער אָדער א פראקסי מיט א זאפאס.",
"createacct-another-realname-tip": "עכטער נאמען איז אפציאנאל.\nאויב איר וויילט אויס צוצושטעלן אים, וועט דאס גענוצט ווערן צו געבן אטריבוציע פאר זייער ארבעט.",
- "pt-login": "אַרײַנלאגירן",
+ "pt-login": "אריינלאגירן",
"pt-login-button": "אַרײַנלאָגירן",
"pt-createaccount": "שאַפֿן אַ קאנטע",
"pt-userlogout": "אַרויסלאָגירן",
"newpassword": "ניי פּאסוואָרט:",
"retypenew": "ווידער שרײַבן פאַסווארט:",
"resetpass_submit": "שטעלן פאסווארט און אריינלאגירן",
- "changepassword-success": "אייער פאַסווארט איז געטוישט געווארן מיט דערפֿאלג!",
+ "changepassword-success": "אייער פאַסווארט איז געטוישט געווארן!",
"changepassword-throttled": "איר האט געפרוווט צופֿיל מאל אריינלאגירן.\nזייט אזוי גוט און וואַרט $1 איידער איר פרוווט נאכאמאל.",
+ "botpasswords": "באט פאסווערטער",
+ "botpasswords-label-appid": "באט נאמען:",
"botpasswords-label-create": "שאַפֿן",
"botpasswords-label-update": "דערהײַנטיקן",
"botpasswords-label-cancel": "אַנולירן",
"botpasswords-label-delete": "אויסמעקן",
"botpasswords-label-resetpassword": "ווידערשטעלן פאַסווארט",
+ "botpasswords-label-grants-column": "נאכגעגעבן",
+ "botpasswords-created-title": "באט פאסווארט געשאפן",
+ "botpasswords-created-body": "דאס באט פאסווארט פאר באט־נאמען \"$1\" פון באניצער \"$2\" איז געשאפן געווארן.",
+ "botpasswords-updated-title": "באט פאסווארט דערהיינטיקט",
+ "botpasswords-updated-body": "דאס באט פאסווארט פאר באט־נאמען \"$1\" פון באניצער \"$2\" איז דערהיינטיקט געווארן.",
+ "botpasswords-deleted-title": "באט פאסווארט אויסגעמעקט",
"resetpass_forbidden": "פאסווערטער קענען נישט ווערן געטוישט",
"resetpass-no-info": "איר דארפֿט זיין אריינלאגירט צוצוקומען גלייך צו דעם דאזיגן בלאט.",
"resetpass-submit-loggedin": "טוישן פאסווארט",
"resetpass-submit-cancel": "אַנולירן",
- "resetpass-wrong-oldpass": "×\90×\95×\9e×\92×\99×\9c×\98×\99×\92 צײַ×\98×\95×\95ײַ×\9c×\99ק ×\90×\93ער ×\9c×\95×\99פֿ×\99ק פ×\90ַס×\95×\95×\90ר×\98.\n×\90×\99ר ×\94×\90×\98 ×\9e×¢×\92×\9c×¢×\9a ש×\95×\99×\9f ×\92×¢×\98×\95×\99ש×\98 ×\90×\99×\99ער פ×\90ַס×\95×\95×\90ר×\98 ×\9e×\99×\98 ×\94צ×\9c×\97×\94 ×\90×\93ער ×\92×¢×\91×¢×\98×\9f ×\90 × ×²Ö· צײַ×\98×\95×\95ײַ×\9c×\99ק פ×\90ַס×\95×\95×\90ר×\98.",
+ "resetpass-wrong-oldpass": "אומגילטיג צײַטווײַליק אדער לויפֿיק פאַסווארט.\nאיר האט מעגלעך שוין געטוישט אייער פאַסווארט אדער געבעטן א נײַ צײַטווײַליק פאַסווארט.",
"resetpass-recycled": "זײַט אזוי גוט שטעטל אירע פאסווארט צו עפעס אנדערש פונעם לויפיקן פאסווארט.",
"resetpass-temp-emailed": "איר האט זיך ארי לאגירת מיט א פראוויזארישן קאד געשיקט דורכן ע־פאסט. כדי שליסן דאס ארײַנלאגירן, דארט איר שטעלן א נײַ פאסווארט דא.",
"resetpass-temp-password": "צײַטווייליק פאַסווארט:",
"passwordreset-emailtext-user": "באניצער $1 אויף {{SITENAME}} האט געבעטן צוריקצושטעלן אייער פאסווארט פאר {{SITENAME}} ($4).\nדי פאלגנדע באניצער {{PLURAL:$3|קאנטע איז|קאנטעס זענען}} פארבונדן מיט דעם ע־פאסט אדרעס:\n\n$2\n\n{{PLURAL:$3|דאס פראוויזארישע פאסווארט|די פראוויזארישע פאסווערטער}} וועלן אויסגיין נאך {{PLURAL:$5|איין טאג|$5 טעג}}.\nאיר זאלט אריינלאגירן און קלויבן א נייע פאסווארט אצינד. טאמער א צווייטער האט געשיקט די בקשה,\nאדער ווען איר געדענקט יא אייער פריעריקע פאסווארט, און וויל עס נישט ענדערן,\n קענט איר איגנארירן דעם אנזאג און ניצן ווייטער דאס אלטע פאסווארט.",
"passwordreset-emailelement": "באַניצער נאָמען: \n$1\n\nפראוויזארישער פּאַראָל: \n$2",
"passwordreset-emailsentemail": "טאמער איז דער ע־פאסט אדרעס פארקניפט מיט אייער קאנטע, וועט מען שיקן א פאסווארט צוריקשטעלן ע-פּאָסט.",
+ "passwordreset-emailsentusername": "טאמער איז פאראן אן ע־פאסט אדרעס פארקניפט מיט דעם באניצער־נאמען, וועט מען שיקן א פאסווארט צוריקשטעלן ע-פּאָסט.",
"passwordreset-emailsent-capture": "מען האט געשיקט א פאסווארט צוריקשטעלן בליצבריוו, וואס ווערט געוויזן אונטן.",
"passwordreset-emailerror-capture": "מען האט געשאפן א פאסווארט צוריקשטעלן בליצבריוו, וואס ווערט געוויזן אונטן, אבער שיקן צום {{GENDER:$2|באניצער}}איז דורכגעפאלן: $1",
"changeemail": "ענדערן אדער אראפנעמען ע-פּאָסט אַדרעס",
"minoredit": "דאס איז א מינערדיגע ענדערונג",
"watchthis": "טוט אױפֿפּאַסן דעם בלאט",
"savearticle": "אויפהיטן בלאַט",
+ "publishpage": "פובליצירן בלאט",
"preview": "פֿאראויסקוק",
"showpreview": "ווייזן פאָרױסקוק",
"showdiff": "ווײַז די ענדערונגען",
"accmailtext": "א צופֿעליק פאַסווארט פֿאַר [[User talk:$1|$1]] איז געשיקט געוואָרן צו $2.\n\nמען קען עס טוישן אויפֿן [[Special:ChangePassword|טוישן פאַסווארט]] בלאַט נאָכן ארײַנלאגירן.",
"newarticle": "(ניי)",
"newarticletext": "איר זענט געקומען צו אַ בלאַט וואָס עקזיסטירט נאָך נישט!\nכדי שאַפֿן דעם בלאַט, קלאַפט אַרײַן טעקסט אין דעם קעסטל אונטן (זעט דעם [$1 הילף בלאַט] פֿאַר מער אינפֿארמאַציע).\nאויב איר זענט אַהערגעקומען בטעות, דרוקט דאָס '''Back''' קנעפל אין אײַער בלעטערער.",
- "anontalkpagetext": "----'''דאָס איז א רעדן בלאַט פון א אַן אַנאנימען באַניצער וואָס האט נאך נישט געשאַפֿן קיין קאנטע, אדער באניצט זיך נישט דערמיט. דערוועגן, מוזן מיר זיך באניצן מיט זיין IP אדרעס כדי אים צו אידענטיפיצירן. עס קען זיין אז עטלעכע אנדערע ניצן אויך דעם IP אדרעס. אויב זענט איר אן אנאנימער באַניצער וואס שפירט אז איר האט באקומען מעלדונגען וואס זענען נישט שייך צו אייך, ביטע [[Special:UserLogin/signup|שאַפֿט א קאנטע]] אדער [[Special:UserLogin|טוט זיך אריינלאגירן]] כדי צו פארמיידן דאס אין די עתיד זיך פארמישן מיט אנדערע אַנאנימע באַניצערס.'''",
+ "anontalkpagetext": "<em>דאָס איז א רעדן בלאַט פון א אַן אַנאנימען באַניצער וואָס האט נאך נישט געשאַפֿן קיין קאנטע, אדער באניצט זיך נישט דערמיט. </em>\nדערוועגן, מוזן מיר זיך באניצן מיט זיין IP אדרעס כדי אים צו אידענטיפיצירן. עס קען זיין אז עטלעכע אנדערע ניצן אויך דעם IP אדרעס. אויב זענט איר אן אנאנימער באַניצער וואס שפירט אז איר האט באקומען מעלדונגען וואס זענען נישט שייך צו אייך, ביטע [[Special:CreateAccount|שאַפֿט א קאנטע]] אדער [[Special:UserLogin|טוט זיך אריינלאגירן]] כדי צו פארמיידן דאס אין די עתיד זיך פארמישן מיט אנדערע אַנאנימע באַניצערס.'''",
"noarticletext": "דערווייל איז נישט פאַרהאן קיין שום טעקסט אין דעם בלאט.\nאיר קענט [[Special:Search/{{PAGENAME}}|זוכן דעם בלאט טיטל]] אין אנדערע בלעטער,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} זוכן די רעלעוואנטע לאגביכער],\nאדער [{{fullurl:{{FULLPAGENAME}}|action=edit}} שאפֿן דעם בלאט]</span>.",
"noarticletext-nopermission": "דערווײַל איז נישט פאַראַן קיין שום טעקסט אין דעם בלאַט.\nאיר קענט [[Special:Search/{{PAGENAME}}| זוכן דעם בלאט טיטל]] אין אנדערע בלעטער,\nאדער <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} נאָכזוכן די רעלעוואנטע לאגביכער]</span>., אבער איר זענט נישט ערלויבט צו שאפֿן דעם בלאט.",
"missing-revision": "די רעוויזיע #$1 פונעם בלאט \"{{FULLPAGENAME}}\" עקזיסטירט נישט.\n\nדאס געשעט געוויינלעך פון פאלגן א פארעלטערטן היסטאריע לינק צו א בלאט וואס איז געווארן אויסגעמעקט.\nפרטים קען מען געפינען אינעם [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} אויסמעקונג לאגבוך].",
"userpage-userdoesnotexist": "באניצער קאנטע \"$1\" איז נישט אײַנגעשריבן.\nקוקט איבער צי איר ווילט שאפֿן/רעדאקטירן דעם בלאט.",
"userpage-userdoesnotexist-view": "באניצער קאנטע \"$1\" איז נישט איינגעשריבן.",
"blocked-notice-logextract": "דער באַניצער איז דערווייַל פֿאַרשפאַרט.\nדי לעצטע בלאָקירן לאג אַקציע איז צוגעשטעלט אונטן:",
- "clearyourcache": "'''אַכטונג:''' נאכן אויפֿהיטן, ברויכט איר אפשר נאך אַריבערגיין דעם בלעטערערס זאַפאַס צו זען די ענדערונגען.\n\n* '''פֿייערפוקס/סאפֿארי:''' האלט אראפ ''שיפֿט'' בשעתן דרוקן ''Reload'', אדער דרוקט ''Ctrl-F5'' אדער ''Ctrl-R'' (אויף א מאקינטאש ''⌘-R'')\n\n* '''גוגל כראם:''' דרוקט ''Ctrl-Shift-R'' (אויף א מאקינטאש ''⌘-Shift-R'')\n\n* '''אינטערנעט עקספלארער:''' האלט אראפ ''Ctrl'' בשעתן קליקן ''Refresh'', אדער דרוקט ''Ctrl-F5''\n\n* '''אפערע:''' ליידיגט אויס דעם זאַפאַס אין ''Tools → Preferences'' (''העדפות'' > ''כלים'')",
+ "clearyourcache": "'''אַכטונג:''' נאכן אויפֿהיטן, ברויכט איר אפשר נאך אַריבערגיין דעם בלעטערערס זאַפאַס צו זען די ענדערונגען.\n\n* '''פֿייערפוקס/סאפֿארי:''' האלט אראפ ''שיפֿט'' בשעתן דרוקן ''Reload'', אדער דרוקט ''Ctrl-F5'' אדער ''Ctrl-R'' (אויף א מאקינטאש ''⌘-R'')\n\n* '''גוגל כראם:''' דרוקט ''Ctrl-Shift-R'' (אויף א מאקינטאש ''⌘-Shift-R'')\n\n* '''אינטערנעט עקספלארער:''' האלט אראפ ''Ctrl'' בשעתן קליקן ''Refresh'', אדער דרוקט ''Ctrl-F5''\n\n* <strong>אפערע:</strong> גייט צו <em>מעניו → שטעלונגען</em> (<em> אפערע → פרעפערנצן</em> אויף א מעק) און דערנאך צו <em>פריוואטקייט & און זיכערהייט → אראפראמען בלעטערן דאטן → בילדער און טעקעס אין זאפאס</em>",
"usercssyoucanpreview": "'''טיפ:''' נוצט דאס {{int:showpreview}} קנעפל אויספרובירן אייער CSS בעפארן אויפהיטן.",
"userjsyoucanpreview": "'''טיפ:''' נוצט דאס {{int:showpreview}} קנעפל אויספרובירן אייער JavaScript בעפארן אויפהיטן.",
"usercsspreview": "'''געדענקט אז איר טוט בלויז פאראויס זען אייער באניצער CSS.'''\n'''ער איז דערווייל נאכנישט אויפֿגעהיטן!'''",
"revdelete-unsuppress": "טוה אפ באגרענעצונגן אין גענדערטע רעוויזיעס",
"revdelete-log": "אורזאַך:",
"revdelete-submit": "צושטעלן צו {{PLURAL:$1|סעלעקטירטער רעוויזיע| סעלעקטירטע רעוויזיעס}}",
- "revdelete-success": "'''רע×\95×\95×\99×\96×\99×¢ ×\96×¢×\91×\90ַרק×\99×\99×\98 ×\93ערפֿ×\90×\9c×\92ר×\99×\99×\9a ×\93ער×\94×²Ö·× ×\98×\99ק×\98.'''",
+ "revdelete-success": "'''רעוויזיע זעבאַרקייט דערהײַנטיקט.'''",
"revdelete-failure": "'''נישט מעגלעך צו דערהײַנטיקן רעוויזיע זעבאַרקייט:'''\n$1",
- "logdelete-success": "'''לאג באהאלטן איז סוקסעספול איינגעשטעלט.'''",
+ "logdelete-success": "'''לאגבוך זעבארקייט איינגעשטעלט.'''",
"logdelete-failure": "'''נישט מעגלעך צו שטעלן לאג זעבאַרקייט:'''\n$1",
"revdel-restore": "טויש די זעבארקייט",
"pagehist": "בלאט היסטאריע",
"userrights-changeable-col": "גרופעס איר קענט ענדערן",
"userrights-unchangeable-col": "גרופעס איר קענט נישט ענדערן",
"userrights-conflict": "קאנפֿליקט פון באניצער־רעכטן ענדערונגען! זייט אזוי גוט רעצענזירן און באשטעטיקן אײַערע ענדערונגען.",
- "userrights-removed-self": "×\90×\99ר ×\94×\90×\98 ×\93ערפ×\90×\9c×\92ר×\99×\99×\9a ×\90ר×\90פ×\92×¢× ×\95×\9e×¢×\9f ×\90×\99×\99ערע ×\90×\99×\99×\92×¢× ×¢ רע×\9b×\98×¢. אזוי קענט איר מער נישט דערגרייכן דעם בלאט.",
+ "userrights-removed-self": "×\90×\99ר ×\94×\90×\98 ×\90ר×\90פ×\92×¢× ×\95×\9e×¢×\9f ×\90×\99×\99ערע ×\90×\99×\99×\92×¢× ×¢ רע×\9b×\98×\9f. אזוי קענט איר מער נישט דערגרייכן דעם בלאט.",
"group": "גרופע:",
"group-user": "באניצערס",
"group-autoconfirmed": "באַשטעטיקטע באַניצער",
"grant-group-file-interaction": "אינטעראגירן מיט מעדיע",
"grant-group-email": "שיקן ע־פאסט",
"grant-createaccount": "שאַפֿן קאנטעס",
+ "grant-uploadfile": "אַרויפֿלאָדן נייע טעקעס",
+ "grant-basic": "בעיסיק רעכטן",
+ "grant-viewmywatchlist": "קוקט אייער אויפפאסונג ליסטע",
"newuserlogpage": "נייע באַניצערס לאָג-בוך",
"newuserlogpagetext": "דאס איז א לאג פון באַניצערס אײַנשרײַבונגען.",
"rightslog": "באַניצער רעכטן לאג",
"upload-form-label-own-work": "דאס איז מיין אייגענע ארבעט.",
"upload-form-label-infoform-categories": "קאַטעגאריעס",
"upload-form-label-infoform-date": "דאַטע",
- "upload-form-label-not-own-work-local-local": "אפשר ווילט איר פרובירן [[Special:Upload|דעם גרונטלעכן ארויפלאד־בלאט]].",
+ "upload-form-label-not-own-work-local-generic-local": "אפשר ווילט איר פרובירן [[Special:Upload|דעם גרונטלעכן ארויפלאד־בלאט]].",
"backend-fail-stream": "קען נישט מאכן שטראמען טעקע $1.",
"backend-fail-notexists": "נישט פֿאראן די טעקע $1.",
"backend-fail-notsame": "א נישט־אידענטישע טעקע עקזיסטירט שוין ביי \"$1\".",
"imagelinks": "טעקע באַניץ",
"linkstoimage": "{{PLURAL:$1|דער פאלגנדער בלאט ניצט|די פאלגנדע בלעטער ניצן}} דאס דאזיגע בילד:",
"linkstoimage-more": "מער ווי $1 {{PLURAL:$1|בלאַט פֿאַרבינדט|בלעטער פֿאַרבינדן}} צו דער דאזיגער טעקע.\nדי פֿאלגנדע ליסטע ווײַזט {{PLURAL:$1|דעם ערשטן בלאַט לינק|די ערשטע $1 בלאַט לינקען}} צו דער טעקע.\nס'איז פֿאַראַן[[Special:WhatLinksHere/$2|פֿולע רשימה]].",
- "nolinkstoimage": "× ×\99ש×\98×\90 ק×\99×\99×\9f ×\91×\9c×¢×\98ער ×\95×\95×\90ס × ×\99צ×\9f ×\93×\90ס ×\93×\90×\96×\99×\92×¢ ×\91×\99×\9c×\93.",
+ "nolinkstoimage": "× ×\99ש×\98×\90 ק×\99×\99×\9f ×\91×\9c×¢×\98ער ×\95×\95×\90ס פ×\90ר×\91×\99× ×\93×\9f צ×\95 ×\93×\99 ×\98עקע.",
"morelinkstoimage": "באַקוקן [[Special:WhatLinksHere/$1|מער לינקען]] צו דער טעקע.",
"linkstoimage-redirect": "$1 (טעקע ווײַטערפֿירונג) $2",
"duplicatesoffile": "די פֿאלגנדע {{PLURAL:$1|טעקע דופליקירט|$1 טעקעס דופליקירן}} די דאזיגע טעקע ([[Special:FileDuplicateSearch/$2|נאך פרטים]]):",
"unusedtemplates": "נישט באניצטע מוסטערן",
"unusedtemplatestext": "דער בלאט ווײַזט אלע בלעטער אינעם {{ns:template}} נאמענטייל וואס זענען נישט אײַנגעשלאסן אין אן אנדער בלאט. געדענקט צו באקוקן אנדערע בלעטער פאר לינקען צו די מוסטערן איידער איר מעקט זיי אויס.",
"unusedtemplateswlh": "אנדערע פֿאַרבינדונגען",
- "randompage": "צ×\95פֿע×\9c×\99×\92ער ×\90ַר×\98×\99ק×\9c",
+ "randompage": "צ×\95פֿע×\9c×\99×\92ער ×\91×\9c×\90×\98",
"randompage-nopages": "נישטא קיין בלעטער אין {{PLURAL:$2|דעם פאלגנדן נאמענטייל |די פאלגנדע נאמענטיילן}} \"$1\".",
"randomincategory": "צופעליקער בלאט אין קאטעגאריע",
"randomincategory-invalidcategory": "\"$1\" איז נישט קיין גילטיקער קאטעגאריע נאמען.",
"querypage-disabled": "דער באַזונדער־בלאַט איז אומאַקטיווירט צוליב אויספֿירונג סיבות.",
"apihelp": "API־הילף",
"apihelp-no-such-module": "מאָדול \"$1\" נישט געפונען.",
+ "apisandbox-unfullscreen": "ווייזן בלאט",
"apisandbox-reset": "רייניקן",
+ "apisandbox-retry": "פרובירן נאכאמאל",
+ "apisandbox-helpurls": "הילף לינקען",
+ "apisandbox-examples": "ביישפילן",
"apisandbox-results": "רעזולטאטן",
"booksources": "דרויסנדיגע ליטעראַטור ISBN",
"booksources-search-legend": "זוכן פאר דרויסנדע ביכער מקורות",
"logempty": "נישטא קיין פאַסנדיקע זאכן אין לאג.",
"log-title-wildcard": "זוכן טיטלען וואס הייבן אָן מיט דעם טעקסט",
"showhideselectedlogentries": "ווײַזן/באַהאַלטן געקליבענע לאגבוך אקציעס",
+ "checkbox-all": "אַלע",
+ "checkbox-none": "קיינע",
+ "checkbox-invert": "אומקערן",
"allpages": "אַלע בלעטער",
"nextpage": "קומענדיקער בלאַט ($1)",
"prevpage": "פֿריִערדיקער בלאַט ($1)",
"listgrouprights-namespaceprotection-header": "נאמענטייל באשרענקונגען",
"listgrouprights-namespaceprotection-namespace": "נאָמענטייל",
"listgrouprights-namespaceprotection-restrictedto": "רעכט(ן) וואס דערלויבט באניצער צו רעדאקטירן",
+ "listgrants-grant": "צולאזן",
+ "listgrants-rights": "רעכטן",
"trackingcategories": "אויפפאסן־קאטעגאריעס",
"trackingcategories-msg": "אויפפאסן־קאטעגאריע",
"trackingcategories-name": "מעלדונג נאמען",
"wlnote": "אונטן {{PLURAL:$1|איז די לעצטע ענדערונג|זענען די לעצטע <strong>$1</strong> ענדערונגען}} אין {{PLURAL:$2|דער לעצטער שעה|די לעצטע <strong>$2</strong> שעה'ן}} ביז $3, $4.",
"wlshowlast": "ווײַזן די לעצטע $1 שעה'ן $2 טעג",
"watchlist-hide": "באַהאַלטן",
+ "watchlist-submit": "ווײַזן",
"wlshowtime": "צייט־פעריאד צו ווייזן:",
"wlshowhideminor": "מינערדיקער רעדאקטירונגען",
"wlshowhidebots": "באטן",
"wlshowhideanons": "אַנאָנימע באַניצער",
"wlshowhidepatr": "פאטראלירטע רעדאקטירונגען",
"wlshowhidemine": "מיינע רעקאקטירונגען",
+ "wlshowhidecategorization": "בלאט קאטעגאריזירונג",
"watchlist-options": "אויפֿפאַסן ליסטע ברירות",
"watching": "אויפפאסענדונג…",
"unwatching": "נעמט אראפ פון אויפפאסונג ליסטע…",
"delete-toobig": "דער בלאַט האט א גרויסע רעדאקטירונג היסטאריע, מער ווי $1 {{PLURAL:$1|רעוויזיע|רעוויזיעס}}. אויסמעקן אזעלכע בלעטער איז באַגרענעצט געווארן בכדי צו פֿאַרמײַדן א צופֿעליגע פֿאַרשטערונג פֿון {{SITENAME}}.",
"delete-warning-toobig": "דער בלאַט האט א גרויסע רעדאקטירונג היסטאריע, מער ווי $1 {{PLURAL:$1|רעוויזיע|רעוויזיעס}}. אויסמעקן אים קען פֿאַרשטערן דאַטנבאַזע אפעראַציעס פֿון {{SITENAME}}; זײַט פֿארזיכטיג איידער איר מעקט אויס.",
"deleteprotected": "איר קענט נישט אויסמעקן דעם בלאט ווײַל ער איז געשיצט.",
- "deleting-backlinks-warning": "'''ווארענוג:'''\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|אנדערע בלעטער]] פארבינדן צום בלאט אדער אריבערשליסן דעם בלאט איר האלט ביי אויסמעקן.",
+ "deleting-backlinks-warning": "</strong>ווארענוג:<strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|אנדערע בלעטער]] פארבינדן צום בלאט אדער אריבערשליסן דעם בלאט איר האלט ביי אויסמעקן.",
"rollback": "צוריקדרייען רעדאַקטירונגען",
"rollbacklink": "צוריקדרייען",
"rollbacklinkcount": "צוריקדרייען $1 {{PLURAL:$1|רעדאקטירונג|רעדאקטירונגען}}",
"rollbackfailed": "צוריקדרייען דורכגעפֿאַלן",
"cantrollback": "מען קען נישט צוריקדרייען די ענדערונג – דער לעצטער בײַשטייערער איז דער איינציגסטער שרײַבער אין דעם בלאַט.",
"alreadyrolled": "מען קען נישט צוריקדרייען די לעצטע ענדערונג פון בלאט [[:$1]] פֿון\n[[User:$2|$2]] ([[User talk:$2|רעדן]]{{int:pipe-separator}} [[Special:Contributions/$2|{{int:contribslink}}]]);\nאן אנדערער האט שוין געענדערט אדער צוריקגעדרייט דעם בלאט.\n\nדי לעצטע ענדערונג צום בלאַט איז געווען פון [[User:$3|$3]] ([[User talk:$3|רעדן]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
- "editcomment": "קורץ ווארט איז געווען: \"'''$1'''\".",
+ "editcomment": "קורץ ווארט איז געווען: <em>$1</em>.",
"revertpage": "רעדאַקטירונגען פֿון [[Special:Contributions/$2|$2]] צוריקגענומען ([[User talk:$2|רעדן]]) צו דער לעצטער ווערסיע פֿון [[User:$1|$1]]",
"revertpage-nouser": "צוריקגעשטעלט רעדאַקטירונגען פֿון א באהאלטענעם באַניצער צו לעצטער רעוויזיע פֿון {{GENDER:$1|[[User:$1|$1]]}}",
"rollback-success": "צוריקגעדרייט רעדאַקטירונגען פֿון $1 צו דער לעצטע ווערסיע פֿון $2",
"changecontentmodel-title-label": "בלאט־טיטל",
"changecontentmodel-model-label": "נייער אינהאלט מאדעל",
"changecontentmodel-reason-label": "אורזאַך:",
+ "changecontentmodel-submit": "טוישן",
"logentry-contentmodel-change-revertlink": "צוריקשטעלן",
"logentry-contentmodel-change-revert": "צוריקשטעלן",
"protectlogpage": "באשיצונג לאָג-בוך",
"ipb-unblock": "אויפֿבלאקירן א באַניצער נאמען אדער IP אדרעס",
"ipb-blocklist": "זעט עקזיסטירנדע בלאקירונגען",
"ipb-blocklist-contribs": "בײַשטײַערונגען פֿון {{GENDER:$1|$1}}",
+ "ipb-blocklist-duration-left": "נאך $1",
"unblockip": "אויפֿבלאקירן באניצער",
"unblockiptext": "מיט דעם פארמולאר קענט איר צוריקשטעלן שרייבן ערלויבניש צו אן IP אדרעס אדער באניצער נאמען וואס איז געווען בלאקירט.",
"ipusubmit": "אוועקנעמען דעם בלאק",
"blocklink": "ארויסטרייבן",
"unblocklink": "באַפֿרײַען",
"change-blocklink": "ענדערן בלאק",
- "contribslink": "×\91×\90Ö·× ×\99צערס ×\91ײַש×\98ײַער×\95× ×\92×¢×\9f",
+ "contribslink": "בײַשטײַערונגען",
"emaillink": "שיקן ע־פאסט",
"autoblocker": "אויטאמאטיש בלאקירט ווייל אײַער IP אדרעס איז לעצטנס געניצט געווארן דורך [[User:$1|$1]]. \nדער סיבה וואס איז אנגעבען געווארן איז: \"$2\".",
"blocklogpage": "בלאקירן לאג",
"import-nonewrevisions": "קיין רעוויזיעס נישט אימפארטירט (אדער אלע שוין דא, אדער איבערגעהיפט צוליב גרײַזן).",
"xml-error-string": "$1 בײַ שורה $2, זייל $3 (בייט $4): $5",
"import-upload": "אַרויפֿלאָדן XML דאַטן",
- "import-token-mismatch": "×\90Ö¸× ×\95×\95ער פ×\95×\9f סעס×\99×¢ ×\93×\90Ö·×\98×\9f.\n ×\91×\99×\98×¢ פר×\95×\91×\99ר×\98 × ×\90×\9b×\90×\9e×\90×\9c.",
+ "import-token-mismatch": "פ×\90ר×\9c×\95ס×\98 פ×\95×\9f סעס×\99×¢ ×\93×\90×\98×\9f. \n\nקע×\9f ×\96×\99×\99×\9f ×\90×\96 ×\90×\99ר ×\96×¢× ×¢×\9f ×\92×¢×\95×\95×\90ר×\9f ×\90ר×\95×\99ס×\9c×\90×\92×\99ר×\98\n<strong>×\91×\99×\98×¢ פר×\95×\91×\99ר×\98 × ×\90×\9b×\90×\9e×\90×\9c</strong>. \n\n×\90×\95×\99×\91 ס'×\90ר×\91×¢×\98 × ×\90×\9a ×\90×\9cס × ×\99×\98, פר×\95×\91×\99ר×\98 [[Special:UserLogout|×\90ר×\95×\99ס×\9c×\90×\92×\99ר×\9f]] ×\90×\95×\9f ×\96×\99×\9a צ×\95ר×\99ק ×\90ר×\99×\99× ×\9c×\90×\92×\99ר×\9f.",
"import-invalid-interwiki": "נישט מעגלעך צו אימפארטירן פון ספעציפֿירטער וויקי.",
"import-error-edit": "דעם בלאט \"$1\" קען מען נישט אימפארטירן ווייל איר האט נישט די רעכט אים צו רעדאקטירן.",
"import-error-create": "דעם בלאט \"$1\" האט מען נישט אימפארטירט ווייל איר האט נישט די רעכט צו שאפן אים.",
"tooltip-pt-mycontris": "ליסטע פון {{GENDER:|אייערע}} ביישטייערונגען",
"tooltip-pt-login": "עס איז רעקאָמענדירט זיך אײַנשרײַבן; ס'איז אבער נישט קיין פֿליכט",
"tooltip-pt-logout": "ארויסלאגירן",
- "tooltip-pt-createaccount": "איר ווערט דערמוטיגט צו שאפן א קאנטע און אריינלאגירן; ס'איז אביר נישט אבליגאטאריש",
+ "tooltip-pt-createaccount": "איר ווערט דערמוטיגט צו שאַפֿן א קאנטע און אריינלאגירן; ס׳איז אבער נישט פארפליכטעט",
"tooltip-ca-talk": "שמועס וועגן דעם אינהאַלט בלאַט",
- "tooltip-ca-edit": "רעדאקטירן דעם בלאַט",
+ "tooltip-ca-edit": "רעדאַקטירן דעם בלאַט",
"tooltip-ca-addsection": "אָנהייבן א נײַע אָפטיילונג",
"tooltip-ca-viewsource": "דאס איז א פֿארשלאסענער בלאט, איר קענט נאר באַקוקן זיין מקור",
"tooltip-ca-history": "פריערדיגע ווערסיעס פון דעם בלאט.",
"tooltip-ca-move": "באַוועגן דעם בלאַט",
"tooltip-ca-watch": "לייגט צו דעם בלאט אויפצופאסן",
"tooltip-ca-unwatch": "נעמט אַראָפּ דעם בלאַט פון נאָכפאָלג־ליסטע",
- "tooltip-search": "×\96×\95×\9b×\98 ×\90×\99× ×¢×\9d ס×\99×\99×\98",
+ "tooltip-search": "×\96×\95×\9a {{SITENAME}}",
"tooltip-search-go": "גייט צו א בלאט מיט אט דעם נאמען, אויב ער עקסיסטירט",
"tooltip-search-fulltext": "זוכט דעם טעקסט אין די בלעטער",
- "tooltip-p-logo": "×\94×\95×\99פ×\98 ×\96×\99×\99ט",
+ "tooltip-p-logo": "×\91×\90Ö·×\96×\95×\9b×\9f ×\93×¢×\9d ×\94×\95×\99פ×\98 ×\91×\9c×\90Ö·ט",
"tooltip-n-mainpage": "באַזוכט דעם הויפּט־זײַט",
"tooltip-n-mainpage-description": "באַזוכן דעם הויפט בלאַט",
"tooltip-n-portal": "גייט אריין אין די געמיינדע צו שמועסן",
"tooltip-n-currentevents": "מער אינפארמאציע איבער אקטועלע געשענישען",
- "tooltip-n-recentchanges": "ליסטע פון לעצטע ענדערונגען",
+ "tooltip-n-recentchanges": "ליסטע פון לעצטע ענדערונגען אין דעם וויקי",
"tooltip-n-randompage": "וועלט אויס א צופעליגער בלאט",
- "tooltip-n-help": "×\94×\99×\9c×£",
- "tooltip-t-whatlinkshere": "×\90×\9c×¢ ×\91×\9c×¢×\98ער ×\95×\95×\90ס פ×\90ר×\91×\99× ×\93×¢×\9f צ×\95 ×\93×¢×\9d ×\91×\9c×\90×\98",
+ "tooltip-n-help": "×\93ער פ×\9c×\90×¥ ×\90×\95×\99סצ×\95×\92עפ×\99× ×¢×\9f",
+ "tooltip-t-whatlinkshere": "×\90×\9c×¢ ×\9c×\99ס×\98×¢ פ×\95×\9f ×\90×\9c×¢ ×\91×\9c×¢×\98ער ×\95×\95×\90ס פ×\90ר×\91×\99× ×\93×\98 ×\90×\94ער",
"tooltip-t-recentchangeslinked": "אלע ענדערונגען פון בלעטער וואס זענען אהער פארבינדען",
"tooltip-feed-rss": "דערהײַנטיגט אויטאמאטיש פון אר.עס.עס. RSS",
"tooltip-feed-atom": "לייג צו אן אטאמאטישער אפדעיט דורך אטאם Atom",
"lastmodifiedatby": "די לעצטע ענדערונג פֿון דעם בלאַט איז געווען $2, $1 דורך $3.",
"othercontribs": "באזירט אויף ארבעט פון $1.",
"others": "אנדערע",
- "siteusers": "{{PLURAL:$2|באַניצער| באַניצערס}} {{SITENAME}} $1",
+ "siteusers": "{{SITENAME}} {{PLURAL:$2|{{GENDER:$1| באַניצער}}| באַניצערס}} $1",
"anonusers": "{{SITENAME}} {{PLURAL:$2| אַנאנימער באַניצער|אַנאנימע באַניצער}} $1",
"creditspage": "בלאט קרעדיטס",
"nocredits": "נישט פאראן קיין אינפארמאציע פאר דעם בלאט.",
"scarytranscludedisabled": "[אינטערוויקי אריבערשליסן איז אַנולירט]",
"scarytranscludetoolong": "[URL צו לאנג]",
"deletedwhileediting": "ווארענונג: דער בלאט איז געווארן אויסגעמעקט נאכדעם וואס איר האט אנגעהויבן רעדאקטירן!",
- "confirmrecreate": "באַניצער [[User:$1|$1]] ([[User talk:$1|רעדן]]) האט אויסגעמעקט דעם בלאט נאכדעם וואס איר האט אנגעהויבן דאס צו ענדערן, אלס אָנגעבליכער סיבה:\n:'''$2'''\nביטע באשטעטיגט אז איר ווילט טאקע צוריקשטעלן דעם בלאט.",
+ "confirmrecreate": "באַניצער [[User:$1|$1]] ([[User talk:$1|רעדן]]) {{GENDER:$1|האט אויסגעמעקט}} דעם בלאט נאכדעם וואס איר האט אנגעהויבן דאס צו ענדערן, אלס אָנגעבליכער סיבה:\n: <em>$2</em>\nביטע באשטעטיגט אז איר ווילט טאקע צוריקשטעלן דעם בלאט.",
"recreate": "שאַפֿן פֿונדאסניי",
"confirm_purge_button": "אויספֿירן",
"confirm-purge-top": "אויסקלארן די קאשעי פון דעם בלאט?",
"confirm-watch-top": "צולייגן דעם בלאט צו אייער אויפֿפאסונג ליסטע?",
"confirm-unwatch-button": "יאָ",
"confirm-unwatch-top": "אראפנעמען דעם בלאט פון אייער אויפפאסונג ליסטע?",
+ "confirm-rollback-button": "יאָ",
"quotation-marks": "„$1“",
"imgmultipageprev": "→ פֿריערדיגער בלאַט",
"imgmultipagenext": "צום קומענדיגן בלאט ←",
"hebrew-calendar-m12-gen": "אלול",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|רעדן]])",
"duplicate-defaultsort": "'''ווארענונג:''' גרונט סארטשליסל \"$2\" פֿאָרט איבערן פֿריערדיגן גרונט סארטשליסל \"$1\".",
+ "duplicate-displaytitle": "<strong>ווארענונג:</strong> דער אויסשטעלונג־טיטל \"$2\" שרייבט איבער דעם פריערדיקן אויסשטעלונג־טיטל \"$1\".",
+ "restricted-displaytitle": "<strong>ווארענונג:</strong> דער אויסשטעלונג־טיטל \"$1\" איז געווארן איגנארירט ווייל ער שטימט נישט מיטן עכטן טיטל פונעם בלאַט.",
"version": "ווערסיע",
"version-extensions": "אינסטאלירטע פארברייטערונגען",
"version-skins": "אינסטאלירטע באניצער־אייבערפלאכן",
"fileduplicatesearch-submit": "זוכן",
"fileduplicatesearch-info": "$1 × $2 פיקסעל<br />טעקע גרייס: $3<br /> טיפ MIME: $4",
"fileduplicatesearch-noresults": "קיין טעקע מיטן נאמען \"$1\" נישט געטראפֿן.",
- "specialpages": "ספּעציעלע זײַטן",
+ "specialpages": "ספעציעלע בלעטער",
"specialpages-note-top": "לעגענדע",
"specialpages-note": "* נארמאַלע באַזונדערע בלעטער.\n* <span class=\"mw-specialpagerestricted\">באַגרענעצטע באַזונדערע בלעטער.</span>",
"specialpages-group-maintenance": "אויפֿהאַלטונג באַריכטן",
"logentry-newusers-create2": "באניצער קאנטע $1 איז {{GENDER:$2|געשאפן געווארן}} דורך $3",
"logentry-newusers-byemail": "באניצער קאנטע $3 איז {{GENDER:$2|געשאפן געווארן}} דורך $1 און דאס פאסווארט איז געשיקט געווארט דורך ע־פאסט",
"logentry-newusers-autocreate": "באַניצער קאנטע $1 {{GENDER:$2|געשאפן}} אויטאמאטיש",
- "logentry-rights-rights": "$1 האָט {{GENDER:$2|געביטן}} גרופּע מיטגלידערשאַפט פאַר $3 פון $4 אויף $5",
+ "logentry-rights-rights": "$1 האָט {{GENDER:$2|געביטן}} גרופּע מיטגלידערשאַפט פאַר {{GENDER:$6|$3}} פון $4 אויף $5",
"logentry-rights-rights-legacy": "$1 {{GENDER:$2|האט געביטן}} גרופע מיטגלידערשאפט פאר $3",
"logentry-rights-autopromote": "$1 אויטאמאטיש {{GENDER:$2|פראמאווירט}} פון $4 צו $5",
"logentry-upload-upload": "$1 {{GENDER:$2|האט ארויפגעלאדן}} $3",
"feedback-subject": "טעמע:",
"feedback-submit": "אײַנגעבן",
"feedback-thanks": "ייש\"כ! אײַער פֿידבעק איז געווארן ארויפגעלעגט צום בלאט \"[$2 $1]\".",
- "searchsuggest-search": "×\96×\95×\9b×\9f",
+ "searchsuggest-search": "×\96×\95×\9a",
"searchsuggest-containing": "כולל…",
"api-error-badaccess-groups": "איר האט נישט קיין רעכטן אַרויפֿלאָדן טעקעס אויף דער וויקי.",
"api-error-badtoken": "אינערלעכער גרײַז: סימן טויג נישט.",
"noname": "Ẹ kò tọ́kasí orúkọ oníṣe tó ní ìbámu.",
"loginsuccesstitle": "Ìwọlé ti yọrí sí rere",
"loginsuccess": "'''Ẹ ti wọlé sínú {{SITENAME}} gẹ́gẹ́ bi \"$1\".'''",
- "nosuchuser": "Kò sí oníṣe kankan pẹ̀lú orúkọ \"$1\".\nÀwọn lẹ́tà àwọn orúkọ oníṣe gbọ́dọ̀ jẹ́ irúkanna.\nẸ yẹ lẹ́tà yín wò, tàbí [[Special:UserLogin/signup|kí ẹ dá àkópamọ́ tuntun]].",
+ "nosuchuser": "Kò sí oníṣe kankan pẹ̀lú orúkọ \"$1\".\nÀwọn lẹ́tà àwọn orúkọ oníṣe gbọ́dọ̀ jẹ́ irúkanna.\nẸ yẹ lẹ́tà yín wò, tàbí [[Special:CreateAccount|kí ẹ dá àkópamọ́ tuntun]].",
"nosuchusershort": "Kò sí oníṣe t'ón jẹ́ $1.\nẸ yẹ lẹ́tà ọ̀rọ̀ yín wò.",
"nouserspecified": "Ẹ gbọ́dọ̀ tọ́kasí orúkọ oníṣe kan.",
"login-userblocked": "Oníṣe yìí jẹ́ dídínà. Ìwọlé kò jẹ́ gbígbà láyè.",
"accmailtext": "A ti fi ọ̀rọ̀ìpamọ́ àrìnàkò tí a pèsè fún [[User talk:$1|$1]] ránṣẹ́ sí $2. Ẹ le ṣe àyípadà ọ̀rọ̀ìpamọ́ fún àpamọ́ tuntun yìí ní ibi ''[[Special:ChangePassword|àyípadà ọ̀rọ̀ìpamọ́]]'' lẹ́yìn tí ẹ bá ti jáwọlé.",
"newarticle": "(Tuntun)",
"newarticletext": "Ẹ ti tẹ̀lé ìjápọ̀ mọ́ ojúewé tí kò sí.\nLáti dá ojúewé yí ẹ bẹ̀rẹ̀ síní tẹ́kọ sí inú àpótí ìsàlẹ̀ yí (ẹ wo [$1 ojúewé ìrànlọ́wọ́ ] fun ẹ̀kúnrẹ́rẹ́ ).\nT'óbá sepé àsìse ló gbé yin dé bi, ẹ kọn bọ́tìnì ìpadàsẹ́yìn.",
- "anontalkpagetext": "''Ojúewé ìfọ̀rọ̀wérọ̀ yìí wà fún oníṣe aláílórúkọ tí kò tíì dá àkópamọ́, tàbí tí kò lò ó rárá.\nBí bẹ́ẹ̀ laṣe únlo àdírẹ́ẹ̀sì IP oníyenọ́mbà láti dáamọ̀.\nIrú àdírẹ́ẹ̀sì IP báun ṣeéṣe kó jẹ́ pínpínlọ̀ pẹ̀lú àwọn oníṣe míràn.\nTó bá jẹ́ pé oníṣe aláìlórúkọ ni yín, tí ẹ sì ri pé wọ́n ùnsọ̀rọ̀ tí kò kàn yín sí i yín, ẹ jọ̀wọ́ [[Special:UserLogin/signup|ẹ dá àkópamọ́ kan]] tàbí [[Special:UserLogin|kí ẹ wọlẹ́]] kó mọ́ baà sí ìdàrúpọ̀ lọ́jọ́ọwájú mọ́ àwọn oníṣe aláìlórúkọ mírán.''",
+ "anontalkpagetext": "''Ojúewé ìfọ̀rọ̀wérọ̀ yìí wà fún oníṣe aláílórúkọ tí kò tíì dá àkópamọ́, tàbí tí kò lò ó rárá.\nBí bẹ́ẹ̀ laṣe únlo àdírẹ́ẹ̀sì IP oníyenọ́mbà láti dáamọ̀.\nIrú àdírẹ́ẹ̀sì IP báun ṣeéṣe kó jẹ́ pínpínlọ̀ pẹ̀lú àwọn oníṣe míràn.\nTó bá jẹ́ pé oníṣe aláìlórúkọ ni yín, tí ẹ sì ri pé wọ́n ùnsọ̀rọ̀ tí kò kàn yín sí i yín, ẹ jọ̀wọ́ [[Special:CreateAccount|ẹ dá àkópamọ́ kan]] tàbí [[Special:UserLogin|kí ẹ wọlẹ́]] kó mọ́ baà sí ìdàrúpọ̀ lọ́jọ́ọwájú mọ́ àwọn oníṣe aláìlórúkọ mírán.''",
"noarticletext": "Lọ́wọ́lọ́wọ́ kò sí ìkọ̀ nínú ojúewé yìí.\nẸ le [[Special:Search/{{PAGENAME}}|wá àkọlé ojúewé yìí]] nínú àwọn ojúewé mìíràn,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} wá àkọọ́lẹ̀ rẹ̀], tàbí [{{fullurl:{{FULLPAGENAME}}|action=edit}} kí ẹ ṣ'àtúnṣe ojúewé òún]</span>.",
"noarticletext-nopermission": "Lọ́wọ́lọ́wọ́ kò sí ìkọ̀ nínú ojúewé yìí.\nẸ le [[Special:Search/{{PAGENAME}}|wá àkọlé ojúewé yìí]] nínú àwọn ojúewé mìíràn, tàbí\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} wá àwọn àkọọ́lẹ̀ tó bámu]</span>, sùgbọ́n ẹ kò ní àṣẹ láti ṣ'ẹ̀dá ojúewé yìí.",
"missing-revision": "Àtúnyẹ̀wò #$1 ojúewé tó únjẹ́ \"{{FULLPAGENAME}}\" kò sí.\n\nÈyí únsábà ṣẹlẹ̀ nítorípé ẹ tẹ̀lé ìtàn àjápọ̀ tí kò ṣiṣẹ́ mọ́ wá sí orí ojúewé tó ti jẹ́ píparẹ́.\nẸ̀kúnrẹ́rẹ́ wà nínú [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} àkọọ́lẹ̀ ìparẹ́].",
"noname": "你未指定一個有效嘅用戶名。",
"loginsuccesstitle": "登入成功",
"loginsuccess": "'''「$1」登入咗{{SITENAME}}。'''",
- "nosuchuser": "呢度冇叫做 \"$1\"嘅用戶。\n用戶名係有分大細楷嘅。\n請檢查你個名嘅輸入方法,或者[[Special:UserLogin/signup|建立一個新嘅戶口]]。",
+ "nosuchuser": "呢度冇叫做 \"$1\"嘅用戶。\n用戶名係有分大細楷嘅。\n請檢查你個名嘅輸入方法,或者[[Special:CreateAccount|建立一個新嘅戶口]]。",
"nosuchusershort": "呢度冇叫做 \"$1\"嘅用戶。 請檢查你個名嘅輸入方法。",
"nouserspecified": "你需要指定一個用戶名。",
"login-userblocked": "呢位用戶封鎖咗。唔容許登入。",
"accmailtext": "「[[User talk:$1|$1]]」嘅隨機產生密碼已經寄咗去 $2。\n\n呢個密碼可以響簽到咗之後嘅<em>[[Special:ChangePassword|改密碼]]</em> 版度改佢。",
"newarticle": "(新)",
"newarticletext": "你連連過嚟嘅頁面重未存在。\n要起版新嘅,請你喺下面嗰格度輸入。(睇睇[$1 自助版]拎多啲資料。)\n如果你係唔覺意嚟到呢度,撳一次你個瀏覽器'''返轉頭'''個掣。",
- "anontalkpagetext": "----''呢度係匿名用戶嘅討論頁,佢可能係重未開戶口,或者佢重唔識開戶口。我哋會用數字表示嘅IP地址嚟代表佢。一個IP地址係可以由幾個用戶夾來用。如果你係匿名用戶,同覺得呢啲留言係同你冇關係嘅話,唔該去[[Special:UserLogin/signup|開一個新戶口]]或[[Special:UserLogin|登入]],避免喺以後嘅留言會同埋其它用戶混淆。''",
+ "anontalkpagetext": "----''呢度係匿名用戶嘅討論頁,佢可能係重未開戶口,或者佢重唔識開戶口。我哋會用數字表示嘅IP地址嚟代表佢。一個IP地址係可以由幾個用戶夾來用。如果你係匿名用戶,同覺得呢啲留言係同你冇關係嘅話,唔該去[[Special:CreateAccount|開一個新戶口]]或[[Special:UserLogin|登入]],避免喺以後嘅留言會同埋其它用戶混淆。''",
"noarticletext": "喺呢一頁而家並冇任何嘅文字,你可以喺其它嘅頁面中[[Special:Search/{{PAGENAME}}|搵呢一頁嘅標題]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 搵有關嘅日誌],\n或者[{{fullurl:{{FULLPAGENAME}}|action=edit}} 編輯呢一版]</span>。",
"noarticletext-nopermission": "呢一頁而家冇任何文字,你可以喺其它嘅頁面中[[Special:Search/{{PAGENAME}}|搵呢一頁嘅標題]],或者<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 搵有關嘅日誌]</span>。",
"missing-revision": "The revision #$1 of the page named \"{{FULLPAGENAME}}\" does not exist.\n\nThis is usually caused by following an outdated history link to a page that has been deleted.\nDetails can be found in the [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log].\n\n《{{FULLPAGENAME}}》嘅編輯#$1唔存在。\n\n恁通常係因為一條過徂時嘅鏈接帶徂閣下去一個已經刪除徂嘅版。\n詳情請查閱[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪文紀錄]。",
"noname": "Je ei hin heldihe gebrukersnaem opeheven.",
"loginsuccesstitle": "Anmelden geslaegd",
"loginsuccess": "'''Je bin noe anemeld bie {{SITENAME}} as \"$1\".'''",
- "nosuchuser": "De gebruker \"$1\" besti nie.\nControleer de schriefwieze of [[Special:UserLogin/signup|mik een nieuwe gebruker an]].",
+ "nosuchuser": "De gebruker \"$1\" besti nie.\nControleer de schriefwieze of [[Special:CreateAccount|mik een nieuwe gebruker an]].",
"nosuchusershort": "De gebruker \"$1\" besti nie. Controleer de schriefwieze.",
"nouserspecified": "Je dien een gebrukersnaem op te heven.",
"wrongpassword": "Wachtwoôrd onjuust. Probeer 't opnieuw.",
"allpagesbadtitle": "D'n ingegeven bladzie-titel was ongeldeg of ao 'n interwiki-vòvoegsel. Meschien stae d'r eên of meer teêkens in die-an nie in titels gebruukt ore kunne.",
"categories": "Categorieën",
"categoriespagetext": "De wiki eit de volgende categorieën.\n[[Special:UnusedCategories|Unused categories]] are not shown here.\nAlso see [[Special:WantedCategories|wanted categories]].",
- "special-categories-sort-count": "op antal sorteern",
- "special-categories-sort-abc": "alfabetisch sorteern",
"linksearch-line": "$1 ei 'n verwiezienge in $2",
"listgrouprights-members": "(ledenlieste)",
"emailuser": "E-mail deêze gebruker",
"Nbdd0121",
"Apflu",
"飞舞回堂前",
- "Cosine02"
+ "Cosine02",
+ "Arthur2e5"
]
},
"tog-underline": "链接下划线:",
"password-change-forbidden": "您不能在本wiki上更改密码。",
"externaldberror": "验证数据库出错或您被禁止更新您的外部账号。",
"login": "登录",
+ "login-security": "证明您的身份",
"nav-login-createaccount": "登录/创建账户",
"userlogin": "登录/创建账户",
"userloginnocreate": "登录",
"userlogin-resetpassword-link": "忘记密码?",
"userlogin-helplink2": "登录帮助",
"userlogin-loggedin": "您已经以{{GENDER:$1|$1}}的身份登录。使用下面的表格以其他用户的身份登录。",
+ "userlogin-reauth": "您必须再次登录以证明您是{{GENDER:$1|$1}}。",
"userlogin-createanother": "创建另一个账户",
"createacct-emailrequired": "电子邮件地址",
"createacct-emailoptional": "电子邮件地址(可选)",
"createacct-email-ph": "请输入你的电子邮件地址",
"createacct-another-email-ph": "输入电子邮件地址",
"createaccountmail": "使用一个临时的随机密码并将其发送到指定的电子邮件地址中",
+ "createaccountmail-help": "可被用于为另一个人创建账户而不需要得知密码。",
"createacct-realname": "真实姓名(可选)",
"createaccountreason": "原因:",
"createacct-reason": "原因",
"createacct-reason-ph": "您为什么要创建另一个账户",
+ "createacct-reason-help": "在账户创建日志中显示的消息",
"createacct-submit": "创建您的账户",
"createacct-another-submit": "创建账户",
- "createacct-benefit-heading": "{{SITENAME}}是由同你一样的人们构筑的。",
+ "createacct-continue-submit": "继续账户创建",
+ "createacct-another-continue-submit": "继续账户创建",
+ "createacct-benefit-heading": "{{SITENAME}}是由像您一样的人们构筑的。",
"createacct-benefit-body1": "{{PLURAL:$1|编辑}}",
"createacct-benefit-body2": "{{PLURAL:$1|页面}}",
"createacct-benefit-body3": "最近{{PLURAL:$1|贡献者}}",
"nocookiesnew": "该用户帐户已被创建,但登录失败。{{SITENAME}}使用Cookie实现用户登录。您已禁用Cookie,请启用Cookie,然后使用您的新用户名与密码登录。",
"nocookieslogin": "{{SITENAME}}使用Cookie实现用户登录。您已停用Cookie。请启用Cookie后再试。",
"nocookiesfornew": "该用户账户未被创建,我们不能确认它的来源。请确保你已启用Cookie,刷新本页后再试。",
+ "createacct-loginerror": "账户已成功创建,但您不能自动登录。请继续[[Special:UserLogin|手动登录]]。",
"noname": "未指定有效的用户名。",
"loginsuccesstitle": "已登录",
"loginsuccess": "<strong>您现在已经以\"$1\"的身份登录了{{SITENAME}}。</strong>",
- "nosuchuser": "没有名为“$1”的用户。用户名区分大小写。请检查你的拼写或[[Special:UserLogin/signup|创建新账户]]。",
+ "nosuchuser": "没有名为“$1”的用户。用户名区分大小写。请检查您的拼写或[[Special:CreateAccount|创建新账户]]。",
"nosuchusershort": "没有名为“$1”的用户。请检查您的拼写。",
"nouserspecified": "您必须指定一个用户名。",
"login-userblocked": "该用户已被封禁,禁止登录。",
"createacct-another-realname-tip": "真实姓名是选填项目。\n如果你选择提供它,它将会用于贡献署名。",
"pt-login": "登录",
"pt-login-button": "登录",
+ "pt-login-continue-button": "继续登录",
"pt-createaccount": "创建账户",
"pt-userlogout": "退出",
"php-mail-error-unknown": "在 PHP 的 mail() 函数中的未知错误",
"botpasswords-invalid-name": "指定的用户名不包含机器人密码分隔符(“$1”)。",
"botpasswords-not-exist": "用户“$1”没有名叫“$2”的机器人密码。",
"resetpass_forbidden": "无法更改密码",
+ "resetpass_forbidden-reason": "密码不能更改:$1",
"resetpass-no-info": "您必须登录后直接进入这个页面。",
"resetpass-submit-loggedin": "更改密码",
"resetpass-submit-cancel": "取消",
"passwordreset-emailsentusername": "如果有邮件地址与此用户名相关联的话,将发送一封密码重置邮件。",
"passwordreset-emailsent-capture": "密码重设电子邮件已发送,并在下面显示。",
"passwordreset-emailerror-capture": "重置密码邮件已生成,但是无法向{{GENDER:$2|下列用户}} 发送:$1",
+ "passwordreset-emailsent-capture2": "密码重置{{PLURAL:$1|邮件}}已发送。{{PLURAL:$1|用户名和密码|用户名和密码列表}}在下方显示。",
+ "passwordreset-emailerror-capture2": "向{{GENDER:$2|用户}}发送电子邮件失败:$1 {{PLURAL:$3|用户名和密码|用户名和密码列表}}在下方显示。",
+ "passwordreset-nocaller": "必须提供一个调用方",
+ "passwordreset-nosuchcaller": "调用方不存在:$1",
+ "passwordreset-ignored": "密码重置没有处理。也许没有配置提供者?",
+ "passwordreset-invalideamil": "无效的电子邮件地址",
+ "passwordreset-nodata": "用户名和电子邮件地址均未提供",
"changeemail": "更改或移除电子邮件地址",
"changeemail-header": "完成此表格以更改您的电子邮件地址。如果您希望从您的账户中移除任何关联的电子邮件地址,请在提交表格时将新电子邮件地址留空。",
"changeemail-passwordrequired": "您需要输入您的密码以确认此次更改。",
"accmailtext": "为[[User talk:$1|$1]]随机生成的密码已送至$2。登录后可以在<em>[[Special:ChangePassword|更改密码]]</em>页面中修改。",
"newarticle": "(新页面)",
"newarticletext": "您点击了一个尚不存在的页面的链接。要创建该页面,请在下面的编辑框中输入内容(更多信息请见[$1 帮助页面])。如果您是错误地进入了此页面,请点击您的浏览器的<strong>返回</strong>按钮。",
- "anontalkpagetext": "----\n<em>这是一个还未建立账户的匿名用户的讨论页, 因此我们只能用IP地址来与他或她联络。</em>该IP地址可能由几名用户共享。如果您是一名匿名用户并认为此页上的评语与您无关,请[[Special:UserLogin/signup|创建新账户]]或[[Special:UserLogin|登录]]以避免在未来与其他匿名用户混淆。",
+ "anontalkpagetext": "----\n<em>这是一个还未建立账户的匿名用户的讨论页, 因此我们只能用IP地址来与他或她联络。</em>该IP地址可能由几名用户共享。如果您是一名匿名用户并认为此页上的评语与您无关,请[[Special:CreateAccount|创建新账户]]或[[Special:UserLogin|登录]]以避免在未来与其他匿名用户混淆。",
"noarticletext": "本页面目前没有内容。您可以在其他页面中[[Special:Search/{{PAGENAME}}|搜索本页标题]]、<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 搜索相关日志]或[{{fullurl:{{FULLPAGENAME}}|action=edit}} 创建本页面]</span>。",
"noarticletext-nopermission": "本页面目前没有内容。您可以在其他页面中[[Special:Search/{{PAGENAME}}|搜索本页标题]]或<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 搜索相关日志]</span>,但您没有权限创建本页面。",
"missing-revision": "“{{FULLPAGENAME}}”的版本#$1不存在。\n\n这通常是因为进入了一个已被删除的页面的历史链接。\n详细信息可以在[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 删除日志]中找到。",
"userpage-userdoesnotexist": "用户账户“$1”没有注册。请在创建/编辑本页前检查。",
"userpage-userdoesnotexist-view": "用户账户“$1”没有被注册。",
"blocked-notice-logextract": "这位用户目前已被封禁。以下提供最近的封禁日志以供参考:",
- "clearyourcache": "<strong>注意:</strong>在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。\n* <strong>Firefox或Safari:</strong>按住<em>Shift</em>的同时单击<em>刷新</em>,或按<em>Ctrl-F5</em>或<em>Ctrl-R</em>(Mac为<em>⌘-R</em>)\n* <strong>Google Chrome:</strong>按<em>Ctrl-Shift-R</em>(Mac为<em>⌘-Shift-R</em>)\n* <strong>Internet Explorer:</strong>按住<em>Ctrl</em>的同时单击<em>刷新</em>,或按<em>Ctrl-F5</em>\n* <strong>Opera:</strong>前往<em>菜单 → 设置</em>(Mac为<em>Opera → Preferences</em>),然后em>隐私和安全 → 清除浏览数据 → 缓存的图片和文件</em>。",
+ "clearyourcache": "<strong>注意:</strong>在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。\n* <strong>Firefox或Safari:</strong>按住<em>Shift</em>的同时单击<em>刷新</em>,或按<em>Ctrl-F5</em>或<em>Ctrl-R</em>(Mac为<em>⌘-R</em>)\n* <strong>Google Chrome:</strong>按<em>Ctrl-Shift-R</em>(Mac为<em>⌘-Shift-R</em>)\n* <strong>Internet Explorer:</strong>按住<em>Ctrl</em>的同时单击<em>刷新</em>,或按<em>Ctrl-F5</em>\n* <strong>Opera:</strong>前往<em>菜单 → 设置</em>(Mac为<em>Opera → Preferences</em>),然后<em>隐私和安全 → 清除浏览数据 → 缓存的图片和文件</em>。",
"usercssyoucanpreview": "<strong>提示:</strong>在保存前请用“{{int:showpreview}}”按钮来测试您新的 CSS 。",
"userjsyoucanpreview": "<strong>提示:</strong>在保存前请用“{{int:showpreview}}”按钮来测试您新的 JavaScript 。",
"usercsspreview": "<strong>请记住您现在只是在预览你的用户CSS。它尚未保存!</strong>",
"rows": "行数:",
"columns": "列数:",
"searchresultshead": "搜索",
- "stub-threshold": "短链接格式阈值($1):",
+ "stub-threshold": "小作品链接格式阈值($1):",
"stub-threshold-sample-link": "样例",
"stub-threshold-disabled": "停用",
"recentchangesdays": "最近更改中显示的天数:",
"right-override-export-depth": "导出页面,包括最多5层链接",
"right-sendemail": "发送电子邮件给其他用户",
"right-passwordreset": "查看密码重置电子邮件",
- "right-managechangetags": "从数据库创建和删除[[Special:Tags|标签]]",
+ "right-managechangetags": "创建和(取消)激活[[Special:Tags|标签]]",
"right-applychangetags": "连同某人的更改一起应用[[Special:Tags|标签]]",
"right-changetags": "在个别修订和日志记录中添加和移除任意[[Special:Tags|标签]]",
+ "right-deletechangetags": "从数据库删除[[Special:Tags|标签]]",
"grant-generic": "“$1”权限束",
"grant-group-page-interaction": "与页面交互",
"grant-group-file-interaction": "与媒体交互",
"action-viewmyprivateinfo": "查看您的私人信息",
"action-editmyprivateinfo": "编辑你的私人信息",
"action-editcontentmodel": "编辑页面的内容模型",
- "action-managechangetags": "创建和从数据库中删除标签",
+ "action-managechangetags": "创建和(取消)激活标签",
"action-applychangetags": "连同您的更改应用标签",
"action-changetags": "在个别修订和日志记录中添加和移除任意标签",
+ "action-deletechangetags": "从数据库删除标签",
"nchanges": "$1次更改",
"enhancedrc-since-last-visit": "{{PLURAL:$1|上次访问后}}$1个",
"enhancedrc-history": "历史",
"upload-form-label-own-work": "这是我的作品",
"upload-form-label-infoform-categories": "分类",
"upload-form-label-infoform-date": "日期",
- "upload-form-label-own-work-message-local": "我确认我正在依据{{SITENAME}}上的服务条款和许可协议方针上传文件。",
- "upload-form-label-not-own-work-message-local": "如果您无法依据{{SITENAME}}的方针上传此文件,请关闭此对话框并尝试其他方法。",
- "upload-form-label-not-own-work-local-local": "您也可以尝试[[Special:Upload|默认上传页面]]。",
- "upload-form-label-own-work-message-default": "我知道我正在上传此文件至一个共享的存储库。我确认我依据这里的服务条款和许可方针做此事。",
- "upload-form-label-not-own-work-message-default": "如果您无法依据分享存储库的方针上传此文件,请关闭此对话框并尝试其他方法。",
- "upload-form-label-not-own-work-local-default": "如果此文件可以依据他们的方针上传的话,您也可以尝试使用[[Special:Upload|{{SITENAME}}上的上传页面]]。",
- "upload-form-label-own-work-message-shared": "我证明我拥有此文件的版权,并不可撤销地同意采用[https://creativecommons.org/licenses/by-sa/4.0/ 知识共享 署名-相同方式共享 4.0]许可协议将此文件发布至维基共享资源,并且我同意[https://wikimediafoundation.org/wiki/Terms_of_Use 使用条款]。",
- "upload-form-label-not-own-work-message-shared": "如果您并不拥有此文件的版权,或者您希望将其以其他许可协议发布,请考虑使用[https://commons.wikimedia.org/wiki/Special:UploadWizard 共享资源的上传向导]。",
- "upload-form-label-not-own-work-local-shared": "如果网站允许依据他们的方针上传此文件的话,您也可以尝试使用[[Special:Upload|{{SITENAME}}上的上传页面]]。",
+ "upload-form-label-own-work-message-generic-local": "我确认我正在依据{{SITENAME}}上的服务条款和许可协议方针上传文件。",
+ "upload-form-label-not-own-work-message-generic-local": "如果您无法依据{{SITENAME}}的方针上传此文件,请关闭此对话框并尝试其他方法。",
+ "upload-form-label-not-own-work-local-generic-local": "您也可以尝试[[Special:Upload|默认上传页面]]。",
+ "upload-form-label-own-work-message-generic-foreign": "我知道我正在上传此文件至一个共享的存储库。我确认我依据这里的服务条款和许可方针做此事。",
+ "upload-form-label-not-own-work-message-generic-foreign": "如果您无法依据分享存储库的方针上传此文件,请关闭此对话框并尝试其他方法。",
+ "upload-form-label-not-own-work-local-generic-foreign": "如果此文件可以依据他们的方针上传的话,您也可以尝试使用[[Special:Upload|{{SITENAME}}上的上传页面]]。",
"backend-fail-stream": "无法流传送文件$1。",
"backend-fail-backup": "无法备份文件$1。",
"backend-fail-notexists": "条目$1不存在。",
"trackingcategories-msg": "追踪分类",
"trackingcategories-name": "信息名",
"trackingcategories-desc": "分类收录标准",
+ "restricted-displaytitle-ignored": "有忽略显示标题的页面",
+ "restricted-displaytitle-ignored-desc": "页面有被忽略的<code><nowiki>{{DISPLAYTITLE}}</nowiki></code>,因为它不等同于页面的实际标题。",
"noindex-category-desc": "因为页面上有魔术字<code><nowiki>__NOINDEX__</nowiki></code>并位于允许该标记的名字空间,而不被机器人索引的页面。",
"index-category-desc": "页面上有魔术字<code><nowiki>__INDEX__</nowiki></code>(并位于允许该标记的名字空间),并因此被机器人索引,但通常不应被索引。",
"post-expand-template-inclusion-category-desc": "在展开所有模板后,页面大小大于<code>$wgMaxArticleSize</code>,所以某些模板未展开。",
"deletereasonotherlist": "其他原因",
"deletereason-dropdown": "*常见删除原因\n**广告\n**破坏行为\n**侵犯著作权\n**作者申请\n**受损重定向",
"delete-edit-reasonlist": "编辑删除原因",
- "delete-toobig": "这个页面有一个十分大量的编辑历史,超过$1个版本。删除此类页面的动作已经被限制,以防止在{{SITENAME}}上的意外扰乱。",
- "delete-warning-toobig": "这个页面有一个十分大量的编辑历史,超过$1个版本。删除它可能会扰乱{{SITENAME}}的数据库操作;在继续此动作前请小心。",
+ "delete-toobig": "此页面有大量的编辑历史,超过$1个版本。删除此类页面的操作已被限制,以防止对{{SITENAME}}的意外破坏。",
+ "delete-warning-toobig": "此页面有大量的编辑历史,超过$1个版本。删除它可能会破坏{{SITENAME}}的数据库操作;请谨慎考虑是否执行。",
"deleteprotected": "您不能删除此页面因为它被保护。",
"deleting-backlinks-warning": "<strong>警告:</strong>有[[Special:WhatLinksHere/{{FULLPAGENAME}}|其他页面]]链接至或包含您要删除的页面。",
"rollback": "回退编辑",
"rollbacklinkcount": "回退$1次编辑",
"rollbacklinkcount-morethan": "回退超过$1次的编辑",
"rollbackfailed": "回退失败",
+ "rollback-missingparam": "请求中缺少必需参数。",
"cantrollback": "无法恢复编辑,最后贡献者是该页面的唯一作者。",
"alreadyrolled": "无法回退[[User:$2|$2]]([[User talk:$2|讨论]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]])对[[:$1]]的编辑,其他人已经编辑或者回退了该页。\n\n本页最后的编辑者是[[User:$3|$3]]([[User talk:$3|讨论]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]])。",
"editcomment": "编辑摘要:<em>$1</em>。",
"revertpage": "恢复[[Special:Contributions/$2|$2]]([[User talk:$2|讨论]])的编辑至[[User:$1|$1]]的最后版本",
"revertpage-nouser": "恢复隐藏用户的编辑至{{GENDER:$1|[[User:$1|$1]]}}的最后版本",
"rollback-success": "已恢复$1的编辑,更改回$2的最后版本。",
+ "rollback-success-notify": "已回退$1的编辑,更改回$2的最后版本。[$3 显示更改]",
"sessionfailure-title": "会话无效",
"sessionfailure": "似乎您的登录会话有问题;\n为了防止会话劫持,这个操作已经被取消。\n请返回先前的页面,重新载入该页面,然后重试。",
"changecontentmodel": "更改一个页面的内容模型",
"changecontentmodel-success-text": "[[:$1]]的内容类型被更改。",
"changecontentmodel-cannot-convert": "[[:$1]]上的内容不能转换为$2的一个类型。",
"changecontentmodel-nodirectediting": "$1内容模型不支持直接编辑",
+ "changecontentmodel-emptymodels-title": "没有内容模型可用",
+ "changecontentmodel-emptymodels-text": "[[:$1]]上的内容不能转换为任何类型。",
"log-name-contentmodel": "内容模型更改日志",
"log-description-contentmodel": "与一个页面的内容模型相关的活动",
"logentry-contentmodel-new": "$1已使用非默认的内容模型“$5”{{GENDER:$2|创建}}页面$3",
"lockdbsuccesstext": "数据库已锁定。<br />请记住在维护工作完成后[[Special:UnlockDB|解锁数据库]]。",
"unlockdbsuccesstext": "数据库已解锁。",
"lockfilenotwritable": "数据库锁定文件不可写。要锁定和解锁数据库,该文件必须对网络服务器可写。",
+ "databaselocked": "数据库已被锁定。",
"databasenotlocked": "数据库未被锁定。",
"lockedbyandtime": "(由 {{GENDER:$1|$1}} 于$2 $3执行)",
"move-page": "移动$1",
"confirm-watch-top": "将此页添加到您的监视列表吗?",
"confirm-unwatch-button": "确定",
"confirm-unwatch-top": "从监视列表中删除此页吗?",
+ "confirm-rollback-button": "确定",
+ "confirm-rollback-top": "回退此页面的编辑么?",
"semicolon-separator": ";",
"comma-separator": "、",
"colon-separator": ":",
"timezone-local": "本地",
"duplicate-defaultsort": "<strong>警告:</strong>默认排序关键词“$2”覆盖了之前的默认排序关键词“$1”。",
"duplicate-displaytitle": "<strong>警告:</strong>显示的标题“$2”重写了此前显示的标题“$1”。",
+ "restricted-displaytitle": "<strong>警告:</strong>显示标题“$1”被忽略,因为它不等同于页面的实际标题。",
"invalid-indicator-name": "<strong>错误:</strong>页面状态指示器的<code>name</code>属性必须不为空。",
"version": "版本",
"version-extensions": "安装的扩展程序",
"tags-delete-not-found": "标签“$1”不存在。",
"tags-delete-too-many-uses": "“$1”标签已应用到超过$2个修订版本,这意味着它不能被删除。",
"tags-delete-warnings-after-delete": "标签“$1”已删除,但遇到了以下{{PLURAL:$2|警告}}:",
+ "tags-delete-no-permission": "您没有权限删除更改标签。",
"tags-activate-title": "激活标签",
"tags-activate-question": "您将要激活标签“$1”。",
"tags-activate-reason": "原因:",
"log-action-filter-suppress-block": "通过封禁的用户屏蔽",
"log-action-filter-suppress-reblock": "通过再封禁的用户屏蔽",
"log-action-filter-upload-upload": "新上传",
- "log-action-filter-upload-overwrite": "重新上传"
+ "log-action-filter-upload-overwrite": "重新上传",
+ "authmanager-authn-not-in-progress": "身份验证尚未进行,或会话数据丢失。请从头重新开始。",
+ "authmanager-authn-no-primary": "提供的证书不能被验证。",
+ "authmanager-authn-no-local-user": "提供的证书没有与该wiki上的任何用户相关联。",
+ "authmanager-authn-no-local-user-link": "提供的证书有效,但没有与该wiki上的任何用户相关联。请通过不同方式登录,或创建一个新用户,然后您将拥有一个把您之前的证书链接到对应账户的选项。",
+ "authmanager-authn-autocreate-failed": "所有账户的自动创建失败:$1",
+ "authmanager-change-not-supported": "提供的证书不能被更改,因为没有东西会使用它们。",
+ "authmanager-create-disabled": "账户创建已停用。",
+ "authmanager-create-from-login": "要创建您的账户,请填写下方的字段。",
+ "authmanager-create-not-in-progress": "账户创建尚未进行,或会话数据丢失。请从头重新开始。",
+ "authmanager-create-no-primary": "提供的证书不能用于账户创建。",
+ "authmanager-link-no-primary": "提供的证书不能用于账户链接。",
+ "authmanager-link-not-in-progress": "账户链接尚未进行,或会话数据丢失。请从头重新开始。",
+ "authmanager-authplugin-setpass-failed-title": "密码更改失败",
+ "authmanager-authplugin-setpass-failed-message": "身份验证插件拒绝了密码更改。",
+ "authmanager-authplugin-create-fail": "身份验证插件拒绝了账户创建。",
+ "authmanager-authplugin-setpass-denied": "身份验证插件不允许更改密码。",
+ "authmanager-authplugin-setpass-bad-domain": "无效域。",
+ "authmanager-autocreate-noperm": "不允许自动账户创建。",
+ "authmanager-autocreate-exception": "由于之前的错误,自动账户创建已临时停用。",
+ "authmanager-userdoesnotexist": "用户帐户“$1”尚未注册。",
+ "authmanager-userlogin-remembermypassword-help": "密码是否应为长于会话长度而被记住。",
+ "authmanager-username-help": "用于身份验证的用户名。",
+ "authmanager-password-help": "用于身份验证的密码。",
+ "authmanager-domain-help": "外部身份验证域。",
+ "authmanager-retype-help": "再次输入密码以确认。",
+ "authmanager-email-label": "电子邮件",
+ "authmanager-email-help": "电子邮件地址",
+ "authmanager-realname-label": "真实姓名",
+ "authmanager-realname-help": "用户的真实姓名",
+ "authmanager-provider-password": "基于密码的身份验证",
+ "authmanager-provider-password-domain": "基于密码和域的身份验证",
+ "authmanager-provider-temporarypassword": "临时密码",
+ "authprovider-confirmlink-message": "基于您最近的登录尝试,以下账户可被链接至您的wiki账户。链接它们会启用通过这些账户的登录。请选择应链接的账户。",
+ "authprovider-confirmlink-request-label": "应被链接的账户",
+ "authprovider-confirmlink-success-line": "$1:已成功连接。",
+ "authprovider-confirmlink-failed": "账户链接未完全成功:$1",
+ "authprovider-confirmlink-ok-help": "在显示链接失败消息后继续。",
+ "authprovider-resetpass-skip-label": "跳过",
+ "authprovider-resetpass-skip-help": "跳过重置密码。",
+ "authform-nosession-login": "身份验证已成功,但您的浏览器不能“记住”其登录。\n\n$1",
+ "authform-nosession-signup": "账户已创建,但您的浏览器不能“记住”其登录。\n\n$1",
+ "authform-newtoken": "丢失令牌。$1",
+ "authform-notoken": "丢失令牌",
+ "authform-wrongtoken": "错误令牌",
+ "specialpage-securitylevel-not-allowed-title": "不允许",
+ "specialpage-securitylevel-not-allowed": "对不起,您未被允许使用此页面,因为您的身份不能被验证。",
+ "authpage-cannot-login": "无法开始登录。",
+ "authpage-cannot-login-continue": "无法继续登录。您的会话大概已超时。",
+ "authpage-cannot-create": "无法开始账户创建。",
+ "authpage-cannot-create-continue": "无法继续账户创建。您的会话大概已超时。",
+ "authpage-cannot-link": "无法开始账户链接。",
+ "authpage-cannot-link-continue": "无法继续账户链接。您的会话大概已超时。",
+ "cannotauth-not-allowed-title": "权限被拒绝",
+ "cannotauth-not-allowed": "您不被允许使用此页面",
+ "changecredentials": "更改证书",
+ "changecredentials-submit": "更改证书",
+ "changecredentials-invalidsubpage": "$1不是有效的证书类型。",
+ "changecredentials-success": "您的证书已被更改。",
+ "removecredentials": "移除证书",
+ "removecredentials-submit": "移除证书",
+ "removecredentials-invalidsubpage": "$1不是有效的证书类型。",
+ "removecredentials-success": "您的证书已被移除。",
+ "credentialsform-provider": "证书类型:",
+ "credentialsform-account": "帐户名称:",
+ "cannotlink-no-provider-title": "没有可链接账户",
+ "cannotlink-no-provider": "没有可链接账户。",
+ "linkaccounts": "链接账户",
+ "linkaccounts-success-text": "账户已链接。",
+ "linkaccounts-submit": "链接帐户",
+ "unlinkaccounts": "取消链接账户",
+ "unlinkaccounts-success": "账户已取消链接。"
}
"Bowleerin",
"飞舞回堂前",
"Bbslam",
- "Zerng07"
+ "Zerng07",
+ "Reke",
+ "Kly"
]
},
"tog-underline": "底線標示連結:",
"password-change-forbidden": "您不可變更此 Wiki 上的密碼。",
"externaldberror": "這可能是由於資料庫驗證錯誤,或是不允許您更新外部帳號。",
"login": "登入",
+ "login-security": "驗証您的 ID",
"nav-login-createaccount": "登入/建立帳號",
"userlogin": "登入/建立帳號",
"userloginnocreate": "登入",
"userlogin-resetpassword-link": "忘記密碼?",
"userlogin-helplink2": "登入協助",
"userlogin-loggedin": "您目前已登入 {{GENDER:$1|$1}} 使用者,\n請使用下列表單改登入另一位使用者。",
+ "userlogin-reauth": "您必須再登入一次來驗証您為 {{GENDER:$1|$1}}。",
"userlogin-createanother": "建立另一個帳號",
"createacct-emailrequired": "電子郵件地址",
"createacct-emailoptional": "電子郵件地址 (選填)",
"createacct-email-ph": "輸入您的電子郵件地址",
"createacct-another-email-ph": "輸入電子郵件地址",
"createaccountmail": "使用臨時的隨機密碼,並將它寄至指定的電子郵件地址",
+ "createaccountmail-help": "可用來建立其他人的帳號 (不需要知道密碼)。",
"createacct-realname": "真實姓名 (選填)",
"createaccountreason": "原因:",
"createacct-reason": "原因",
"createacct-reason-ph": "您為什麼要建立另一個帳號",
+ "createacct-reason-help": "顯示於帳號建立日誌的訊息",
"createacct-submit": "建立您的帳號",
"createacct-another-submit": "建立帳號",
+ "createacct-continue-submit": "繼續帳號建立",
+ "createacct-another-continue-submit": "繼續帳號建立",
"createacct-benefit-heading": "{{SITENAME}} 是由像您一樣貢獻的人所建立的。",
"createacct-benefit-body1": "{{PLURAL:$1|次編輯}}",
"createacct-benefit-body2": "$1 頁",
"nocookiesnew": "使用者帳號已建立成功,但您尚未登入。\n要登入 {{SITENAME}} 使用者需使用 Cookies,\n您的 Cookies 未尚開啟。\n請在開啟後使用您新的使用者名稱及密碼登入。",
"nocookieslogin": "要登入 {{SITENAME}} 使用者需使用 Cookies,\n您的 Cookies 未尚開啟。\n請在開啟後重試。",
"nocookiesfornew": "這個使用者的帳號未建立,我們不能確認它的來源。\n請確認您已開啟 Cookie,重新載入後再試。",
+ "createacct-loginerror": "已成功建立帳號,但無法自動登入。\n請繼續 [[Special:UserLogin|手動登入]]。",
"noname": "您輸入的使用者名稱無效。",
"loginsuccesstitle": "已登入",
"loginsuccess": "<strong>{{GENDER:|您|妳|你}}現在已經以 \"$1\" 的身分登入了 {{SITENAME}}。</strong>",
- "nosuchuser": "查無使用者 \"$1\"。\n使用者名稱有大小寫區分,\n請檢查您拼寫是否正確,或者 [[Special:UserLogin/signup|建立新帳號]]。",
+ "nosuchuser": "查無名稱為 \"$1\" 的使用者。\n使用者名稱有大小寫區分,\n請檢查您拼寫是否正確,或者 [[Special:CreateAccount|建立新帳號]]。",
"nosuchusershort": "查無使用者 \"$1\",\n請檢查您拼寫是否正確。",
"nouserspecified": "您必須指定一個使用者名稱。",
"login-userblocked": "這位使用者已被封鎖,不允許登入。",
"createacct-another-realname-tip": "真實姓名為選填欄位。\n若您提供真實姓名,它會用於使用者貢獻署名。",
"pt-login": "登入",
"pt-login-button": "登入",
+ "pt-login-continue-button": "繼續登入",
"pt-createaccount": "建立帳號",
"pt-userlogout": "登出",
"php-mail-error-unknown": "PHP 的 mail() 函數發生不明錯誤。",
"botpasswords-invalid-name": "指定的使用者名稱未包含機器人密碼分隔字元 (\"$1\")。",
"botpasswords-not-exist": "使用者 \"$1\" 並沒有名稱為 \"$2\" 的機器人密碼。",
"resetpass_forbidden": "無法變更密碼",
+ "resetpass_forbidden-reason": "無法變更密碼:$1",
"resetpass-no-info": "您必須直接登入存取這個頁面。",
"resetpass-submit-loggedin": "變更密碼",
"resetpass-submit-cancel": "取消",
"passwordreset-emailsentusername": "若此確實為您使用者名稱所登記的電子郵件地址,將會寄出重設密碼的信件給您。",
"passwordreset-emailsent-capture": "已寄出重設密碼的電子郵件,並於下方顯示。",
"passwordreset-emailerror-capture": "下列為重設密碼的電子郵件內容,傳送給{{GENDER:$2|使用者}}失敗:$1",
+ "passwordreset-emailsent-capture2": "密碼重設{{PLURAL:$1|郵件|郵件}}已寄出,{{PLURAL:$1|使用者名稱與密碼|使用者名稱與密碼}}如下顯示。",
+ "passwordreset-emailerror-capture2": "寄發電子郵件給{{GENDER:$2|使用者}}失敗:$1,{{PLURAL:$3|使用者名稱與密碼|使用者名稱與密碼}}如下顯示。",
+ "passwordreset-nocaller": "必須提供 caller",
+ "passwordreset-nosuchcaller": "Caller 不存在:$1",
+ "passwordreset-ignored": "未處理密碼重設動作,可能尚未設定提供者?",
+ "passwordreset-invalideamil": "無效的電子郵件地址",
+ "passwordreset-nodata": "未提供使用者名稱或是電子郵件地址",
"changeemail": "變更或移除電子郵件地址",
"changeemail-header": "請填寫此表單來變更您的電子郵件地址,若您想要移除您帳號所連結的所有電子郵件地址,請於新電子郵件地址欄位留空。",
"changeemail-passwordrequired": "您須要輸入您的密碼來確認此次變更。",
"minoredit": "這是一個小修訂",
"watchthis": "監視此頁面",
"savearticle": "儲存頁面",
+ "publishpage": "發佈頁面",
"preview": "預覽",
"showpreview": "顯示預覽",
"showdiff": "顯示變更",
"accmailtext": "[[User talk:$1|$1]] 的隨機密碼已經寄送至 $2,可登入後至 <em>[[Special:ChangePassword|變更密碼]] 頁面更改</em>。",
"newarticle": "(新)",
"newarticletext": "您正連結至一頁不存在頁面。\n要建立該頁面,請在下方的編輯方塊中輸入內容 (詳情請參考 [$1 説明頁面]) 。\n如果您是不小心來到此頁面,請點選瀏覽器的 <strong>返回</strong> 按鈕。",
- "anontalkpagetext": "----\n<em>此討論頁面是給尚未建立帳號的匿名使用者使用</em>\n因此我們必須使用 IP 位址來辨識身份,但相同的 IP 位址可能由許多不同的使用者所共用。\n如果您是匿名使用者並且覺得評論的內容與您無關,請 [[Special:UserLogin/signup|建立新帳號]] 或 [[Special:UserLogin|登入]] 避免與其他匿名使用者混淆。",
+ "anontalkpagetext": "----\n<em>此討論頁面是給尚未建立帳號的匿名使用者使用</em>\n因此我們必須使用 IP 位址來辨識身份,但相同的 IP 位址可能由許多不同的使用者所共用。\n如果您是匿名使用者並且覺得評論的內容與您無關,請 [[Special:CreateAccount|建立新帳號]] 或 [[Special:UserLogin|登入]] 避免與其他匿名使用者混淆。",
"noarticletext": "此頁面目前沒有內容,您可以在其它頁面中[[Special:Search/{{PAGENAME}}|搜尋此頁面標題]]、<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 搜尋相關日誌]或[{{fullurl:{{FULLPAGENAME}}|action=edit}} 建立此頁]</span>。",
"noarticletext-nopermission": "此頁面目前沒有內容,\n您可以在其它頁面中 [[Special:Search/{{PAGENAME}}|搜尋此頁面標題]],或 <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 搜尋相關日誌]</span>,但您沒有權限建立此頁面。",
"missing-revision": "頁面名稱 \"{{FULLPAGENAME}}\" 的 #$1 修訂版本不存在。\n\n通常是因連結到過期的歷史頁面,該頁面已被刪除。\n詳情請參考 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪除日誌]。",
"userpage-userdoesnotexist": "使用者帳號 \"$1\" 尚未註冊。\n若您要建立/編輯此頁面,請先檢查是否正確。",
"userpage-userdoesnotexist-view": "使用者帳號 \"$1\" 尚未註冊。",
"blocked-notice-logextract": "此使用者目前已被封鎖。\n以下為最近的封鎖紀錄以供參考:",
- "clearyourcache": "<strong>注意:</strong>在您儲存之後您必須清除瀏覽器快取才可看到最新的變更。\n* <strong>Firefox / Safari:</strong>按住 <em>Shift</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em> 或 <em>Ctrl-R</em> (Mac 則為 <em>⌘-R</em>) \n* <strong>Google Chrome:</strong>按 <em>Ctrl-Shift-R</em> (Mac 則為 <em>⌘-Shift-R</em>) \n* <strong>Internet Explorer:</strong>按住 <em>Ctrl</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em>\n* <strong>Opera:</strong>進入 <em>工具 → 偏好設定</em> 中清除快取。",
+ "clearyourcache": "<strong>注意:</strong>在您儲存之後您必須清除瀏覽器快取才可看到最新的變更。\n* <strong>Firefox / Safari:</strong>按住 <em>Shift</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em> 或 <em>Ctrl-R</em> (Mac 則為 <em>⌘-R</em>) \n* <strong>Google Chrome:</strong>按 <em>Ctrl-Shift-R</em> (Mac 則為 <em>⌘-Shift-R</em>) \n* <strong>Internet Explorer:</strong>按住 <em>Ctrl</em> 時點選 <em>重新整理</em>,或按 <em>Ctrl-F5</em>\n* <strong>Opera:</strong>前往 <em>選單 → 設定</em> (在 Mac 為 <em>Opera → 偏好設定</em>) 然後再到 <em>隱私 & 安全性 → 清除瀏覽資料 → 已快取的圖片與檔案</em>。",
"usercssyoucanpreview": "<strong>提示:</strong>在儲存之前使用 \"{{int:showpreview}}\" 按鈕來測試您的新 CSS 。",
"userjsyoucanpreview": "<strong>提示:</strong>在儲存之前使用 \"{{int:showpreview}}\" 按鈕來測試您的新 JavaScript 。",
"usercsspreview": "<strong>您目前正預覽您的使用者 CSS,CSS 還尚未儲存!</strong>",
"previewnote": "<strong>您目前正在預覽,您的變更還尚未儲存!</strong>",
"continue-editing": "前往編輯框",
"previewconflict": "此預覽顯示了您於上方文字編輯框中的內容儲存之後將會顯示的結果。",
- "session_fail_preview": "很抱歉!由於連線階段的資料遺失,以至於我們無法處理您的編輯動作。\n您可能已經登出了。<strong>請您確認您仍然在登入狀態,並請再試一次<strong/>。\n請再試一次。\n如果仍然失敗,請 [[Special:UserLogout|登出]] 後重新登入,並請您確認您的瀏覽器允許此網站的Cookie。",
+ "session_fail_preview": "很抱歉!由於連線階段的資料遺失,以至於我們無法處理您的編輯動作。\n您可能已經登出了。<strong>請您確認您仍然在登入狀態,並請再試一次</strong>。\n請再試一次。\n如果仍然失敗,請 [[Special:UserLogout|登出]] 後重新登入,並請您確認您的瀏覽器允許此網站的 Cookie。",
"session_fail_preview_html": "<strong>抱歉!由於是次登入時段出現資料遺失,我們無法處理您所作出的編輯。</strong>\n\n<em> {{SITENAME}} 已開啟了原始 HTML 模式,故此預覽畫面將不會顯示以避免 JavaScript 攻擊。</em>\n\n<strong>如您希望真正能夠作出這次編輯,請再試一次。</strong>\n如果仍不成功,請 [[Special:UserLogout|登出]] 後再重新登入,並確保瀏覽器設定為「允許這個網域的cookie」。",
"token_suffix_mismatch": "<strong>因您使用的瀏覽器破壞了編輯密鑰中的特殊符號,您的編輯已被拒絕。</strong>\n為了避免破壞頁面內容,已拒絕此次編輯動作,\n會發生這個問題通常是因為您使用了有問題的匿名網頁代理伺服器。",
"edit_form_incomplete": "<strong>部份編輯的內容未送至伺服器,請檢查您的編輯內容是否完整並再試一次。</strong>",
"right-override-export-depth": "匯出頁面包含連結內容,深度上限為 5 層",
"right-sendemail": "傳送電子郵件聯絡其他使用者",
"right-passwordreset": "檢視重設密碼電子郵件",
- "right-managechangetags": "建立並自資料庫移除[[Special:Tags|標籤]]",
+ "right-managechangetags": "建立並自資料庫 (取消) 啟用 [[Special:Tags|標籤]]",
"right-applychangetags": "連同某個人的變更一起套用[[Special:Tags|標籤]]",
"right-changetags": "加入與移除任何於各別修訂與日誌項目的[[Special:Tags|標籤]]",
+ "right-deletechangetags": "從資料庫刪除 [[Special:Tags|標籤]]",
"grant-generic": "\"$1\" 權限組合",
"grant-group-page-interaction": "與頁面互動",
"grant-group-file-interaction": "與媒體互動",
"action-viewmyprivateinfo": "檢視您的個人資訊",
"action-editmyprivateinfo": "編輯您的個人資訊",
"action-editcontentmodel": "編輯頁面的內容模型",
- "action-managechangetags": "建立並自資料庫移除標籤",
+ "action-managechangetags": "建立與 (取消) 啟用標籤",
"action-applychangetags": "連同您的變更一起套用標籤",
"action-changetags": "加入與移除任何於各別修訂與日誌項目的標籤",
+ "action-deletechangetags": "從資料庫刪除標籤",
"nchanges": "$1 次變更",
"enhancedrc-since-last-visit": "{{PLURAL:$1|自上次拜訪}}已有 $1",
"enhancedrc-history": "歷史",
"upload-form-label-own-work": "這是我的作品",
"upload-form-label-infoform-categories": "分類",
"upload-form-label-infoform-date": "日期",
- "upload-form-label-own-work-message-local": "我確定我上傳的檔案已遵守下列 {{SITENAME}} 的服務條款與授權條款。",
- "upload-form-label-not-own-work-message-local": "若您無法同意遵守 {{SITENAME}} 的政策上傳檔案,請關閉此對話框並嘗試其他方法。",
- "upload-form-label-not-own-work-local-local": "您也可嘗試[[Special:Upload|預設的上傳頁面]]。",
- "upload-form-label-own-work-message-default": "我明白我將上傳此檔案到一個共享的儲存庫,我確認已遵守本站的服務條款與授權政策。",
- "upload-form-label-not-own-work-message-default": "若您無法同意遵守共享儲存庫的政策上傳檔案,請關閉此對話框並嘗試其他方法。",
- "upload-form-label-not-own-work-local-default": "若此檔案可遵守該站的授權政策上傳檔案,您可能會希望直接嘗試使用 [[Special:Upload|{{SITENAME}} 的上傳頁面]]。",
- "upload-form-label-own-work-message-shared": "我保証我擁有此檔案的版權,並且不反悔同意使用 [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0] 授權條款發佈此檔案到維基媒體共享資源,並且我同意 [https://wikimediafoundation.org/wiki/Terms_of_Use 使用條款]。",
- "upload-form-label-not-own-work-message-shared": "若您並未擁有此檔案的版權,或者您希望使用其他的授權條款發佈此檔案,請考慮使用[https://commons.wikimedia.org/wiki/Special:UploadWizard 通用上傳精靈]。",
- "upload-form-label-not-own-work-local-shared": "若該站的授權政策允許上傳此檔案,您可能會希望直接嘗試使用 [[Special:Upload|{{SITENAME}} 的上傳頁面]]。",
+ "upload-form-label-own-work-message-generic-local": "我確定我上傳的檔案已遵守下列 {{SITENAME}} 的服務條款與授權條款。",
+ "upload-form-label-not-own-work-message-generic-local": "若您無法同意遵守 {{SITENAME}} 的政策上傳檔案,請關閉此對話框並嘗試其他方法。",
+ "upload-form-label-not-own-work-local-generic-local": "您也可嘗試[[Special:Upload|預設的上傳頁面]]。",
+ "upload-form-label-own-work-message-generic-foreign": "我明白我將上傳此檔案到一個共享的儲存庫,我確認已遵守本站的服務條款與授權政策。",
+ "upload-form-label-not-own-work-message-generic-foreign": "若您無法同意遵守共享儲存庫的政策上傳檔案,請關閉此對話框並嘗試其他方法。",
+ "upload-form-label-not-own-work-local-generic-foreign": "若此檔案可遵守該站的授權政策上傳檔案,您可能會希望直接嘗試使用 [[Special:Upload|{{SITENAME}} 的上傳頁面]]。",
"backend-fail-stream": "無法傳輸檔案 \"$1\"。",
"backend-fail-backup": "無法備份檔案 \"$1\"。",
"backend-fail-notexists": "檔案 $1 不存在。",
"trackingcategories-msg": "追蹤分類",
"trackingcategories-name": "訊息名稱",
"trackingcategories-desc": "分類收錄標準",
+ "restricted-displaytitle-ignored": "已忽略顯示標題的頁面",
+ "restricted-displaytitle-ignored-desc": "頁面已忽略 <code><nowiki>{{DISPLAYTITLE}}</nowiki></code>,因該標題於頁面實際標題不相同。",
"noindex-category-desc": "命名空間允許,且含有魔術字 <code><nowiki>__NOINDEX__</nowiki></code> 未被機器人列入索引的頁面。",
"index-category-desc": "命名空間允許,且含有魔術字 <code><nowiki>__INDEX__</nowiki></code> 被機器人列入索引的頁面。",
"post-expand-template-inclusion-category-desc": "展開模板後大小超過 <code>$wgMaxArticleSize</code> 導致部份模板未正常展開的頁面。",
"rollbacklinkcount": "還原 $1 次編輯",
"rollbacklinkcount-morethan": "還原超過 $1 次{{PLURAL:$1|編輯}}",
"rollbackfailed": "還原失敗",
+ "rollback-missingparam": "請求缺少必要參數。",
"cantrollback": "無法還原編輯;\n此頁面的最後貢獻者是唯一的作者。",
"alreadyrolled": "無法還原由 [[User:$2|$2]] ([[User talk:$2|對話]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]] 所作的最後一次編輯 [[:$1]],已有其他人編輯或還原了該頁面。\n\n最後一次編輯該頁面的使用者是 [[User:$3|$3]] ([[User talk:$3|對話]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]])。",
"editcomment": "編輯摘要為:<em>$1</em>。",
"revertpage": "已還原 [[Special:Contributions/$2|$2]] ([[User talk:$2|對話]]) 的編輯為最後由 [[User:$1|$1]] 所修訂的版本",
"revertpage-nouser": "已還隱藏使用者的編輯為最後 {{GENDER:$1|[[User:$1|$1]]}} 修訂的版本",
"rollback-success": "已還原 $1 所做的編輯;\n變更回由 $2 修訂的最後一個版本。",
+ "rollback-success-notify": "已還原 $1 所做的編輯;\n變更回由 $2 修訂的最後一個版本。[$3 顯示變更]",
"sessionfailure-title": "連線階段失敗",
"sessionfailure": "您的登入連線階段似乎有問題,\n為了預防連線階段受到劫持攻擊,此動作已經被取消。\n請返回上一頁,重新讀取該頁面再試一次。",
"changecontentmodel": "變更頁面的內容模型",
"changecontentmodel-success-text": "已變更 [[:$1]] 的內容類型。",
"changecontentmodel-cannot-convert": "[[:$1]] 的內容無法轉換為 $2 類型。",
"changecontentmodel-nodirectediting": "$1 的內容模型不支援直接編輯",
+ "changecontentmodel-emptymodels-title": "沒有內容模型可用",
+ "changecontentmodel-emptymodels-text": "[[:$1]]上的內容不能轉換為任何類型。",
"log-name-contentmodel": "內容模型變更日誌",
"log-description-contentmodel": "與頁面內容模型相關的事件",
"logentry-contentmodel-new": "$1 {{GENDER:$2|已使用}}非預設的內容模型 \"$5\" 建立頁面 $3",
"lockdbsuccesstext": "已鎖定資料庫。<br />\n請記得在維護完成後 [[Special:UnlockDB|解除鎖定]] 資料庫。",
"unlockdbsuccesstext": "已解除鎖定資料庫。",
"lockfilenotwritable": "沒有權限寫入資料庫鎖定檔案。\n網頁伺服器需要該檔案的寫入權限以鎖定和解除鎖定資料庫。",
+ "databaselocked": "資料庫已被鎖定。",
"databasenotlocked": "資料庫尚未鎖定。",
"lockedbyandtime": "(由 {{GENDER:$1|$1}} 於 $2 的 $3)",
"move-page": "移動 $1",
"tooltip-ca-nstab-category": "檢視分類頁面",
"tooltip-minoredit": "標記為小修訂",
"tooltip-save": "儲存您的變更",
+ "tooltip-publish": "發佈您的更改",
"tooltip-preview": "請在儲存前預覽您的變更!",
"tooltip-diff": "顯示您對內容所做的變更",
"tooltip-compareselectedversions": "查閱此頁面兩個已選擇的修訂間的差異",
"invalidateemail": "取消電子郵件確認",
"notificationemail_subject_changed": "{{SITENAME}} 註冊的電子郵件位址已變更",
"notificationemail_subject_removed": "{{SITENAME}} 註冊的電子郵件位址已移除",
+ "notificationemail_body_changed": "來自IP位址$1的某個人(可能是您),在{{SITENAME}}上將帳號\"$2\"的電子郵件位址改成\"$3\"。\n\n如果非您本人所為,請立即跟網站管理員聯繫。",
+ "notificationemail_body_removed": "來自IP位址$1的某人(可能是您),在{{SITENAME}}上移除了帳號$2的電子郵件位址。\n\n如果非您本人所為,請立即跟網站管理員聯繫。",
"scarytranscludedisabled": "[Interwiki 轉換代碼不可用]",
"scarytranscludefailed": "[模板 $1 讀取失敗]",
"scarytranscludefailed-httpstatus": "[模板 $1 讀取失敗:HTTP $2]",
"confirm-watch-top": "新增此頁面至您的監視清單?",
"confirm-unwatch-button": "確定",
"confirm-unwatch-top": "從您的監視清單中移除此頁面?",
+ "confirm-rollback-button": "確定",
+ "confirm-rollback-top": "還原編輯到此頁面?",
"semicolon-separator": ";",
"comma-separator": "、",
"colon-separator": ":",
"timezone-local": "當地",
"duplicate-defaultsort": "<strong>警告:</strong>預設的排序鍵 \"$2\" 會覆蓋先前預設的排序鍵 \"$1\"。",
"duplicate-displaytitle": "<strong>警告:</strong> 顯示標題 \"$2\" 覆蓋之前的顯示標題 \"$1\"。",
+ "restricted-displaytitle": "<strong>警告:</strong> 由於顯示標題與頁面實際標題不哃,已忽略顯示標題 \"$1\"。",
"invalid-indicator-name": "<strong>錯誤:</strong>頁面狀態指示的 <code>name</code> 屬性不能為空。",
"version": "版本",
"version-extensions": "已安裝的擴充套件",
"tags-delete-not-found": "標籤 \"$1\" 不存在。",
"tags-delete-too-many-uses": "標籤 \"$1\" 會套用至 $2 筆以上的{{PLURAL:$2|修訂|修訂}},這代表該標籤將無法刪除。",
"tags-delete-warnings-after-delete": "標籤 \"$1\" 已刪除,但發生下列{{PLURAL:$2|警告|警告}}:",
+ "tags-delete-no-permission": "您沒有權限刪除標籤。",
"tags-activate-title": "啟動標籤",
"tags-activate-question": "您正要啟動標籤 \"$1\"。",
"tags-activate-reason": "原因:",
"logentry-protect-protect-cascade": "$1 {{GENDER:$2|已保護}} $3 $4 [連鎖]",
"logentry-protect-modify": "$1 {{GENDER:$2|已更改}} $3 的保護層級 $4",
"logentry-protect-modify-cascade": "$1 {{GENDER:$2|已更改}} $3 的保護層級 $4 [連鎖]",
- "logentry-rights-rights": "$1 {{GENDER:$2|已更改}} $3 的群組成員資格由 $4 成為 $5",
+ "logentry-rights-rights": "$1 {{GENDER:$2|已更改}} {{GENDER:$6|$3}} 的群組成員資格由 $4 成為 $5",
"logentry-rights-rights-legacy": "$1 {{GENDER:$2|已更改}} $3 的群組成員資格",
"logentry-rights-autopromote": "$1 已自動{{GENDER:$2|提升}}從 $4 成為 $5",
"logentry-upload-upload": "$1 {{GENDER:$2|已上傳}} $3",
"feedback-useragent": "使用者代理:",
"searchsuggest-search": "搜尋",
"searchsuggest-containing": "包含...",
+ "api-error-autoblocked": "您的IP位址已經被自動封禁,因為它曾經被一名已封禁的使用者使用過。",
"api-error-badaccess-groups": "您沒有權限在此 Wiki 上傳檔案。",
"api-error-badtoken": "內部錯誤:密鑰錯誤。",
+ "api-error-blocked": "您已被封鎖,無法編輯。",
"api-error-copyuploaddisabled": "此伺服器已停用使用 URL 上傳檔案的功能。",
"api-error-duplicate": "在網站上已有相同內容的{{PLURAL:$1|其他檔案|其他檔案}}。",
"api-error-duplicate-archive": "在網站上曾有相同內容的{{PLURAL:$1|其他檔案|其他檔案}},但已被刪除。",
"api-error-nomodule": "內部錯誤:缺少上傳模組集。",
"api-error-ok-but-empty": "內部錯誤:伺服器沒有回應。",
"api-error-overwrite": "不允許覆蓋已存在的檔案。",
+ "api-error-ratelimited": "您正在嘗試在比本wiki所允許時間更短的時間內,上傳更多的檔案。請稍待幾分鐘之後再試一次。",
"api-error-stashfailed": "內部錯誤:伺服器儲存暫存檔案失敗。",
"api-error-publishfailed": "內部錯誤:伺服器發佈暫存檔案失敗。",
"api-error-stasherror": "上傳檔案至儲藏庫時發生錯誤。",
"api-error-unknownerror": "不明錯誤:\"$1\"。",
"api-error-uploaddisabled": "此 Wiki 的上傳功能已停用。",
"api-error-verification-error": "此檔案可能已損壞,或副檔名錯誤。",
+ "api-error-was-deleted": "與此名稱相同的檔案曾被上傳過,隨後遭到刪除。",
"duration-seconds": "$1 秒",
"duration-minutes": "$1 分鐘",
"duration-hours": "$1 小時",
"special-characters-group-ipa": "國際音標",
"special-characters-group-symbols": "符號",
"special-characters-group-greek": "希臘文",
+ "special-characters-group-greekextended": "希臘字母擴展",
"special-characters-group-cyrillic": "斯拉夫文",
"special-characters-group-arabic": "阿拉伯文",
"special-characters-group-arabicextended": "阿拉伯文擴充",
"log-action-filter-suppress-block": "由封鎖禁止顯示使用者",
"log-action-filter-suppress-reblock": "由重新封鎖禁止顯示使用者",
"log-action-filter-upload-upload": "新上傳",
- "log-action-filter-upload-overwrite": "重新上傳"
+ "log-action-filter-upload-overwrite": "重新上傳",
+ "authmanager-authn-not-in-progress": "認証尚未進行或連線階段資料已遺失,請重頭再開始。",
+ "authmanager-authn-no-primary": "提供的憑證無法用來認証。",
+ "authmanager-authn-no-local-user": "提供的憑證沒有與任何在此 wiki 上的使用者相關聯。",
+ "authmanager-authn-no-local-user-link": "提供的憑證有效但沒有與任何在此 wiki 上的使用者相關聯。請採用其他方式登入,或建立新使用者,您將會有選項可以連結您先前的憑證到新帳號。",
+ "authmanager-authn-autocreate-failed": "自動建立本地帳號失敗:$1",
+ "authmanager-change-not-supported": "提供的憑證無法變更,因為尚無法使用。",
+ "authmanager-create-disabled": "已關閉帳號自動建立。",
+ "authmanager-create-from-login": "要建立您的帳號,請先填寫以下欄位。",
+ "authmanager-create-not-in-progress": "帳號建立尚未進行或連線階段資料已遺失,請重頭再開始。",
+ "authmanager-create-no-primary": "提供的憑證無使用在帳號建立。",
+ "authmanager-link-no-primary": "提供的憑證無使用在帳號連結。",
+ "authmanager-link-not-in-progress": "帳號連結尚未進行或連線階段資料已遺失,請重頭再開始。",
+ "authmanager-authplugin-setpass-failed-title": "密碼變更失敗",
+ "authmanager-authplugin-setpass-failed-message": "認証外掛已拒絕密碼變更。",
+ "authmanager-authplugin-create-fail": "認証外掛已拒絕帳號建立。",
+ "authmanager-authplugin-setpass-denied": "認証外掛不允許更改密碼。",
+ "authmanager-authplugin-setpass-bad-domain": "無效網域。",
+ "authmanager-autocreate-noperm": "不允許自動帳號建立。",
+ "authmanager-autocreate-exception": "自動帳號建立因發生錯誤臨時關閉。",
+ "authmanager-userdoesnotexist": "使用者帳號 \"$1\" 尚未註冊。",
+ "authmanager-userlogin-remembermypassword-help": "是否要記住密碼來取得更長的連線階段時間。",
+ "authmanager-username-help": "認証用的使用者名稱。",
+ "authmanager-password-help": "認証用的密碼。",
+ "authmanager-domain-help": "外部認証用的網域。",
+ "authmanager-retype-help": "再輸入一次密碼確認。",
+ "authmanager-email-label": "電子郵件",
+ "authmanager-email-help": "電子郵件地址",
+ "authmanager-realname-label": "真實姓名",
+ "authmanager-realname-help": "使用者的真實姓名",
+ "authmanager-provider-password": "Password-based 認証",
+ "authmanager-provider-password-domain": "Password- 及 domain-based 認証",
+ "authmanager-provider-temporarypassword": "臨時密碼",
+ "authprovider-confirmlink-message": "根據您最近的登入嘗試次數,以下帳號可以被連結至您的 wiki 帳號。連結帳號可以讓您使用這些帳號登入。請選擇一個您想連結的帳號。",
+ "authprovider-confirmlink-request-label": "應連結的帳號",
+ "authprovider-confirmlink-success-line": "$1:已成功連結。",
+ "authprovider-confirmlink-failed": "帳號連結未完全成功:$1",
+ "authprovider-confirmlink-ok-help": "顯示連結失敗訊息後繼續。",
+ "authprovider-resetpass-skip-label": "略過",
+ "authprovider-resetpass-skip-help": "略過重設密碼。",
+ "authform-nosession-login": "已成功認証,但您的瀏覽器無法 \"記住\" 登入資訊。\n\n$1",
+ "authform-nosession-signup": "已建立帳號,但您的瀏覽器無法 \"記住\" 登入資訊。\n\n$1",
+ "authform-newtoken": "缺少密鑰。$1",
+ "authform-notoken": "缺少密鑰",
+ "authform-wrongtoken": "密鑰錯誤",
+ "specialpage-securitylevel-not-allowed-title": "不允許",
+ "specialpage-securitylevel-not-allowed": "抱歉,您不被允許使用此頁面,由於您的身份尚無法被驗証。",
+ "authpage-cannot-login": "無法開始登入。",
+ "authpage-cannot-login-continue": "無法繼續登入,您的連線階段似乎已逾時。",
+ "authpage-cannot-create": "無法開始帳號建立。",
+ "authpage-cannot-create-continue": "無法繼續帳號建立,您的連線階段似乎已逾時。",
+ "authpage-cannot-link": "無法開始帳號連結。",
+ "authpage-cannot-link-continue": "無法繼續帳號連結,您的連線階段似乎已逾時。",
+ "cannotauth-not-allowed-title": "權限不足",
+ "cannotauth-not-allowed": "您不被允許使用此頁面",
+ "changecredentials": "更改憑證",
+ "changecredentials-submit": "更改憑證",
+ "changecredentials-invalidsubpage": "$1 不是有效的憑証類型。",
+ "changecredentials-success": "已更改您的憑證。",
+ "removecredentials": "移除憑證",
+ "removecredentials-submit": "移除憑證",
+ "removecredentials-invalidsubpage": "$1 不是有效的憑証類型。",
+ "removecredentials-success": "已移除您的憑證。",
+ "credentialsform-provider": "憑證類型:",
+ "credentialsform-account": "帳號名稱:",
+ "cannotlink-no-provider-title": "沒有可連結的帳號",
+ "cannotlink-no-provider": "沒有可連結的帳號。",
+ "linkaccounts": "連結帳號",
+ "linkaccounts-success-text": "已連結帳號。",
+ "linkaccounts-submit": "連結帳號",
+ "unlinkaccounts": "取消連結帳號",
+ "unlinkaccounts-success": "已取消連結帳號。"
}
$specialPageAliases = [
'Activeusers' => [ 'Aktivní_uživatelé', 'Aktivni_uzivatele' ],
'Allmessages' => [ 'Všechna_hlášení', 'Všechny_zprávy', 'Vsechna_hlaseni', 'Vsechny_zpravy' ],
+ 'AllMyUploads' => [ 'Všechny_moje_soubory', 'Všechny_mé_soubory' ],
'Allpages' => [ 'Všechny_stránky', 'Vsechny_stranky' ],
'Ancientpages' => [ 'Nejstarší_stránky', 'Staré_stránky', 'Stare_stranky' ],
+ 'ApiHelp' => [ 'Nápověda_k_API' ],
+ 'ApiSandbox' => [ 'API_pískoviště' ],
+ 'Badtitle' => [ 'Neplatný_název' ],
'Blankpage' => [ 'Prázdná_stránka' ],
'Block' => [ 'Blokování', 'Blokovani', 'Blokovat_uživatele', 'Blokovat_IP', 'Blokovat_uzivatele' ],
'Booksources' => [ 'Zdroje_knih' ],
+ 'BotPasswords' => [ 'Hesla_pro_boty' ],
'BrokenRedirects' => [ 'Přerušená_přesměrování', 'Prerusena_presmerovani' ],
'Categories' => [ 'Kategorie' ],
+ 'ChangeContentModel' => [ 'Změnit_model_obsahu_stránky' ],
'ChangeEmail' => [ 'Změna_emailu', 'Zmena_emailu' ],
'ChangePassword' => [ 'Změna_hesla', 'Zmena_hesla' ],
'ComparePages' => [ 'Porovnání_stránek', 'PorovnáníStránek', 'Porovnani_stranek', 'PorovnaniStranek' ],
'CreateAccount' => [ 'Vytvořit_účet', 'Vytvorit_ucet' ],
'Deadendpages' => [ 'Slepé_stránky', 'Slepe_stranky' ],
'DeletedContributions' => [ 'Smazané_příspěvky', 'Smazane_prispevky' ],
+ 'Diff' => [ 'Rozdíl' ],
'DoubleRedirects' => [ 'Dvojitá_přesměrování', 'Dvojita_presmerovani' ],
+ 'EditTags' => [ 'Upravit_značky' ],
+ 'EditWatchlist' => [ 'Upravit_seznam_sledovaných_stránek' ],
'Emailuser' => [ 'E-mail' ],
'ExpandTemplates' => [ 'Testy_šablon' ],
'Export' => [ 'Exportovat_stránky' ],
'LinkSearch' => [ 'Hledání_odkazů', 'Hledani_odkazu' ],
'Listadmins' => [ 'Seznam_správců', 'Seznam_spravcu' ],
'Listbots' => [ 'Seznam_botů', 'Seznam_botu' ],
+ 'ListDuplicatedFiles' => [ 'Seznam_duplicitních_souborů' ],
'Listfiles' => [ 'Seznam_souborů', 'Seznam_souboru' ],
+ 'Listgrants' => [ 'Seznam_grantů' ],
'Listgrouprights' => [ 'Práva_uživatelských_skupin', 'Seznam_uživatelských_práv', 'Seznam_uzivatelskych_prav' ],
'Listredirects' => [ 'Seznam_přesměrování', 'Seznam_presmerovani' ],
'Listusers' => [ 'Uživatelé', 'Uzivatele', 'Seznam_uživatelů', 'Seznam_uzivatelu' ],
'Log' => [ 'Protokolovací_záznamy', 'Protokoly', 'Protokol', 'Protokolovaci_zaznamy' ],
'Lonelypages' => [ 'Sirotčí_stránky', 'Sirotci_stranky' ],
'Longpages' => [ 'Nejdelší_stránky', 'Nejdelsi_stranky' ],
+ 'MediaStatistics' => [ 'Statistika_souborů', 'Statistiky_souborů' ],
'MergeHistory' => [ 'Sloučení_historie', 'Slouceni_historie', 'Sloučit_historii' ],
'MIMEsearch' => [ 'Hledání_podle_MIME', 'Hledani_podle_MIME', 'Hledat_podle_MIME_typu' ],
'Mostcategories' => [ 'Stránky_s_nejvíce_kategoriemi', 'Stranky_s_nejvice_kategoriemi', 'Stránky_s_nejvyšším_počtem_kategorií' ],
'Mostrevisions' => [ 'Stránky_s_nejvíce_editacemi', 'Stranky_s_nejvice_editacemi', 'Stránky_s_nejvyšším_počtem_editací' ],
'Movepage' => [ 'Přesunout_stránku', 'Přejmenovat_stránku' ],
'Mycontributions' => [ 'Mé_příspěvky', 'Me_prispevky' ],
+ 'MyLanguage' => [ 'V_mém_jazyce', 'Můj_jazyk' ],
'Mypage' => [ 'Moje_stránka', 'Moje_stranka' ],
'Mytalk' => [ 'Moje_diskuse' ],
+ 'Myuploads' => [ 'Moje_soubory', 'Mé_soubory' ],
'Newimages' => [ 'Nové_obrázky', 'Galerie_nových_obrázků', 'Nove_obrazky' ],
'Newpages' => [ 'Nové_stránky', 'Nove_stranky', 'Nejnovější_stránky', 'Nejnovejsi_stranky' ],
'PasswordReset' => [ 'Reset_hesla', 'Resetovat_heslo' ],
+ 'PagesWithProp' => [ 'Stránky_s_vlastností', 'Stránky_s_vlastnostmi' ],
+ 'PasswordReset' => [ 'Reset_hesla', 'Resetovat_heslo', 'Obnova_hesla', 'Obnovit_heslo' ],
+ 'PermanentLink' => [ 'Trvalý_odkaz' ],
'Preferences' => [ 'Nastavení', 'Nastaveni' ],
+ 'Prefixindex' => [ 'Stránky_podle_začátku' ],
'Protectedpages' => [ 'Zamčené_stránky', 'Zamcene_stranky' ],
'Protectedtitles' => [ 'Zamčené_názvy', 'Zamcene_nazvy', 'Stránky_které_nelze_vytvořit' ],
'Randompage' => [ 'Náhodná_stránka', 'Nahodna_stranka' ],
'Randomredirect' => [ 'Náhodné_přesměrování', 'Nahodne_presmerovani' ],
+ 'RandomInCategory' => [ 'Náhodná_stránka_v_kategorii' ],
+ 'Randomrootpage' => [ 'Náhodná_kořenová_stránka' ],
'Recentchanges' => [ 'Poslední_změny', 'Posledni_zmeny' ],
'Recentchangeslinked' => [ 'Související_změny', 'Souvisejici_zmeny' ],
+ 'Redirect' => [ 'Přesměrování', 'Přesměrovat' ],
'Revisiondelete' => [ 'Smazat_revizi' ],
'Search' => [ 'Hledání', 'Hledani' ],
'Shortpages' => [ 'Nejkratší_stránky', 'Nejkratsi_stranky' ],
'BrokenRedirects' => [ 'BrokenRedirects' ],
'Categories' => [ 'Categories' ],
'ChangeContentModel' => [ 'ChangeContentModel' ],
+ 'ChangeCredentials' => [ 'ChangeCredentials' ],
'ChangeEmail' => [ 'ChangeEmail' ],
'ChangePassword' => [ 'ChangePassword', 'ResetPass', 'ResetPassword' ],
'ComparePages' => [ 'ComparePages' ],
'JavaScriptTest' => [ 'JavaScriptTest' ],
'BlockList' => [ 'BlockList', 'ListBlocks', 'IPBlockList' ],
'LinkSearch' => [ 'LinkSearch' ],
+ 'LinkAccounts' => [ 'LinkAccounts' ],
'Listadmins' => [ 'ListAdmins' ],
'Listbots' => [ 'ListBots' ],
'Listfiles' => [ 'ListFiles', 'FileList', 'ImageList' ],
'Recentchanges' => [ 'RecentChanges' ],
'Recentchangeslinked' => [ 'RecentChangesLinked', 'RelatedChanges' ],
'Redirect' => [ 'Redirect' ],
+ 'RemoveCredentials' => [ 'RemoveCredentials' ],
'ResetTokens' => [ 'ResetTokens' ],
'Revisiondelete' => [ 'RevisionDelete' ],
'RunJobs' => [ 'RunJobs' ],
'Uncategorizedpages' => [ 'UncategorizedPages' ],
'Uncategorizedtemplates' => [ 'UncategorizedTemplates' ],
'Undelete' => [ 'Undelete' ],
+ 'UnlinkAccounts' => [ 'UnlinkAccounts' ],
'Unlockdb' => [ 'UnlockDB' ],
'Unusedcategories' => [ 'UnusedCategories' ],
'Unusedimages' => [ 'UnusedFiles', 'UnusedImages' ],
$this->addArg( 'path', 'Location to the PHP entry point you wish to convert',
/* $required = */ true );
$this->addOption( 'skin', 'Whether to write to skin.json', false, false );
+ $this->addOption( 'config-prefix', 'Custom prefix for configuration settings', false, true );
}
protected function getAllGlobals() {
$this->dir = dirname( realpath( $this->getArg( 0 ) ) );
$this->json = [];
$globalSettings = $this->getAllGlobals();
+ $configPrefix = $this->getOption( 'config-prefix', 'wg' );
+ if ( $configPrefix !== 'wg' ) {
+ $this->json['config']['_prefix'] = $configPrefix;
+ }
foreach ( $vars as $name => $value ) {
$realName = substr( $name, 2 ); // Strip 'wg'
+ if ( $realName === false ) {
+ continue;
+ }
// If it's an empty array that we likely set, skip it
if ( is_array( $value ) && count( $value ) === 0 && in_array( $realName, $__settings ) ) {
$this->noLongerSupportedGlobals[$realName] . '). ' .
"Please update the entry point before convert to registration.\n" );
$this->hasWarning = true;
- } elseif ( strpos( $name, 'wg' ) === 0 ) {
+ } elseif ( strpos( $name, $configPrefix ) === 0 ) {
// Most likely a config setting
- $this->json['config'][$realName] = $value;
+ $this->json['config'][substr( $name, strlen( $configPrefix ) )] = $value;
+ } elseif ( $configPrefix !== 'wg' && strpos( $name, 'wg' ) === 0 ) {
+ // Warn about this
+ $this->output( 'Warning: Skipped global "' . $name . '" (' .
+ 'config prefix is "' . $configPrefix . '"). ' .
+ "Please check that this setting isn't needed.\n" );
}
}
<?php
/**
- * Populates the rev_len and ar_len fields for old revisions created
- * before MW 1.10.
+ * Populates the rev_len and ar_len fields when they are NULL.
*
* 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
require_once __DIR__ . '/Maintenance.php';
/**
- * Maintenance script that populates the rev_len and ar_len fields
- * for old revisions created before MW 1.10.
+ * Maintenance script that populates the rev_len and ar_len fields when they are NULL.
+ * This is the case for all revisions created before MW 1.10, as well as those affected
+ * by T18748 (MW 1.10-1.13) and those affected by T135414 (MW 1.21-1.24).
*
* @ingroup Maintenance
*/
}
public function doDBUpdates() {
- $db = $this->getDB( DB_MASTER );
- if ( !$db->tableExists( 'revision' ) ) {
+ $dbw = $this->getDB( DB_MASTER );
+ if ( !$dbw->tableExists( 'revision' ) ) {
$this->error( "revision table does not exist", true );
- } elseif ( !$db->tableExists( 'archive' ) ) {
+ } elseif ( !$dbw->tableExists( 'archive' ) ) {
$this->error( "archive table does not exist", true );
- } elseif ( !$db->fieldExists( 'revision', 'rev_len', __METHOD__ ) ) {
+ } elseif ( !$dbw->fieldExists( 'revision', 'rev_len', __METHOD__ ) ) {
$this->output( "rev_len column does not exist\n\n", true );
return false;
* @return int
*/
protected function doLenUpdates( $table, $idCol, $prefix, $fields ) {
- $db = $this->getDB( DB_MASTER );
- $start = $db->selectField( $table, "MIN($idCol)", false, __METHOD__ );
- $end = $db->selectField( $table, "MAX($idCol)", false, __METHOD__ );
+ $dbr = $this->getDB( DB_SLAVE );
+ $dbw = $this->getDB( DB_MASTER );
+ $start = $dbw->selectField( $table, "MIN($idCol)", false, __METHOD__ );
+ $end = $dbw->selectField( $table, "MAX($idCol)", false, __METHOD__ );
if ( !$start || !$end ) {
$this->output( "...$table table seems to be empty.\n" );
while ( $blockStart <= $end ) {
$this->output( "...doing $idCol from $blockStart to $blockEnd\n" );
- $res = $db->select(
+ $res = $dbr->select(
$table,
$fields,
[
__METHOD__
);
- $this->beginTransaction( $db, __METHOD__ );
- # Go through and update rev_len from these rows.
- foreach ( $res as $row ) {
- if ( $this->upgradeRow( $row, $table, $idCol, $prefix ) ) {
- $count++;
+ if ( $res->numRows() > 0 ) {
+ $this->beginTransaction( $dbw, __METHOD__ );
+ # Go through and update rev_len from these rows.
+ foreach ( $res as $row ) {
+ if ( $this->upgradeRow( $row, $table, $idCol, $prefix ) ) {
+ $count++;
+ }
}
+ $this->commitTransaction( $dbw, __METHOD__ );
}
- $this->commitTransaction( $db, __METHOD__ );
$blockStart += $this->mBatchSize;
$blockEnd += $this->mBatchSize;
* @return bool
*/
protected function upgradeRow( $row, $table, $idCol, $prefix ) {
- $db = $this->getDB( DB_MASTER );
+ $dbw = $this->getDB( DB_MASTER );
$rev = ( $table === 'archive' )
? Revision::newFromArchiveRow( $row )
}
# Update the row...
- $db->update( $table,
+ $dbw->update( $table,
[ "{$prefix}_len" => $content->getSize() ],
[ $idCol => $row->$idCol ],
__METHOD__
public $reportingInterval = 10;
public $numProcs = 1;
public $numBatches = 0;
- public $useDiff, $pageBlobClass, $orphanBlobClass;
+ public $pageBlobClass, $orphanBlobClass;
public $slavePipes, $slaveProcs, $prevSlaveId;
public $copyOnly = false;
public $isChild = false;
} elseif ( $this->slaveId !== false ) {
$GLOBALS['wgDebugLogPrefix'] = "RCT {$this->slaveId}: ";
}
- $this->useDiff = function_exists( 'xdiff_string_bdiff' );
- $this->pageBlobClass = $this->useDiff ? 'DiffHistoryBlob' : 'ConcatenatedGzipHistoryBlob';
+ $this->pageBlobClass = function_exists( 'xdiff_string_bdiff' ) ?
+ 'DiffHistoryBlob' : 'ConcatenatedGzipHistoryBlob';
$this->orphanBlobClass = 'ConcatenatedGzipHistoryBlob';
}
*/
class UpdateCollation extends Maintenance {
const BATCH_SIZE = 100; // Number of rows to process in one batch
- const SYNC_INTERVAL = 20; // Wait for slaves after this many batches
+ const SYNC_INTERVAL = 5; // Wait for slaves after this many batches
public $sizeHistogram = [];
global $wgCategoryCollation;
$dbw = $this->getDB( DB_MASTER );
+ $dbr = $this->getDB( DB_SLAVE );
$force = $this->getOption( 'force' );
$dryRun = $this->getOption( 'dry-run' );
$verboseStats = $this->getOption( 'verbose-stats' );
$options = [
'LIMIT' => self::BATCH_SIZE,
'ORDER BY' => $orderBy,
+ 'STRAIGHT_JOIN' // per T58041
];
if ( $force || $dryRun ) {
];
}
- $count = $dbw->estimateRowCount(
+ $count = $dbr->estimateRowCount(
'categorylinks',
'*',
$collationConds,
);
// Improve estimate if feasible
if ( $count < 1000000 ) {
- $count = $dbw->selectField(
+ $count = $dbr->selectField(
'categorylinks',
'COUNT(*)',
$collationConds,
return;
}
$this->output( "Fixing collation for $count rows.\n" );
+ wfWaitForSlaves();
}
$count = 0;
$batchCount = 0;
body {
margin: 0;
background: #eee;
- font-family: Verdana;
+ font-family: 'Verdana';
color: #333;
}
#main {
- border: 1px solid #D0D0D0;
+ border: 1px solid #d0d0d0;
background: #fff;
margin: 0.5em;
}
border-left: 1px dotted #ccc;
float: right;
width: 230px;
- background: white;
+ background: #fff;
margin: 0 0 10px 10px;
}
display: list-item;
line-height: 1.5em;
/* @embed */
- list-style-image: url(images/bullet.gif);
+ list-style-image: url( images/bullet.gif );
list-style-type: square;
}
}
.error {
- color: red;
+ color: #f00;
background-color: #fff;
font-weight: bold;
left: 1em;
.success-message {
font-weight: bold;
font-size: 110%;
- color: green;
+ color: #008000;
}
.success-box {
}
.config-download-link a {
- background: url(images/download-32.png) no-repeat center left;
+ background: url( images/download-32.png ) no-repeat center left;
padding-left: 40px; /* 32 px for the image (above), plus some breathing room */
height: 32px; /* provide enough vertical room for the image */
display: inline-block; /* allow the height property (above) to work */
margin-bottom: -8px;
padding: 0 0 0 15px;
/* @embed */
- background-image: url(images/help-question.gif);
+ background-image: url( images/help-question.gif );
background-position: left center;
background-repeat: no-repeat;
cursor: pointer;
.config-help-field-hint:hover {
/* @embed */
- background-image: url(images/help-question-hover.gif);
+ background-image: url( images/help-question-hover.gif );
}
.config-help-field-data {
"grunt-jscs": "2.8.0",
"grunt-jsonlint": "1.0.7",
"grunt-karma": "0.12.2",
+ "grunt-stylelint": "0.3.0",
"karma": "0.13.22",
"karma-chrome-launcher": "0.2.2",
"karma-firefox-launcher": "0.1.7",
"karma-qunit": "0.1.9",
- "qunitjs": "1.22.0"
+ "qunitjs": "1.22.0",
+ "stylelint-config-wikimedia": "0.1.0"
}
}
'class' => 'ResourceLoaderWikiModule',
'styles' => [ 'MediaWiki:Filepage.css' ],
],
- 'user.groups' => [ 'class' => 'ResourceLoaderUserGroupsModule' ],
+ 'user.groups' => [
+ // Merged into 'user' since MediaWiki 1.28 - kept for back-compat
+ 'dependencies' => 'user',
+ 'targets' => [ 'desktop', 'mobile' ],
+ ],
// Scripts managed by the current user (stored in their user space)
'user' => [ 'class' => 'ResourceLoaderUserModule' ],
'de' => 'resources/lib/moment/locale/de.js',
'de-at' => 'resources/lib/moment/locale/de-at.js',
'el' => 'resources/lib/moment/locale/el.js',
+ 'en' => 'resources/src/moment-dmy.js',
'en-au' => 'resources/lib/moment/locale/en-au.js',
'en-ca' => 'resources/lib/moment/locale/en-ca.js',
'en-gb' => 'resources/lib/moment/locale/en-gb.js',
'resources/src/moment-locale-overrides.js',
],
],
+ 'dependencies' => [
+ 'mediawiki.language',
+ ],
'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.api',
],
],
+ 'mediawiki.api.rollback' => [
+ 'scripts' => 'resources/src/mediawiki/api/rollback.js',
+ 'dependencies' => [
+ 'mediawiki.api',
+ ],
+ ],
'mediawiki.content.json' => [
'position' => 'top',
'styles' => 'resources/src/mediawiki/mediawiki.content.json.css',
// @todo Load this message in content language
'colon-separator',
],
+ 'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.htmlform.styles' => [
'styles' => 'resources/src/mediawiki/mediawiki.htmlform.css',
'position' => 'top',
+ 'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.htmlform.ooui.styles' => [
'styles' => 'resources/src/mediawiki/mediawiki.htmlform.ooui.css',
'position' => 'top',
+ 'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.icon' => [
'styles' => 'resources/src/mediawiki/mediawiki.icon.less',
'upload-foreign-cant-upload',
]
],
+ 'mediawiki.ForeignStructuredUpload.config' => [
+ 'class' => 'ResourceLoaderUploadDialogModule',
+ ],
'mediawiki.ForeignStructuredUpload' => [
'scripts' => 'resources/src/mediawiki/mediawiki.ForeignStructuredUpload.js',
'dependencies' => [
'mediawiki.ForeignUpload',
+ 'mediawiki.ForeignStructuredUpload.config',
],
],
'mediawiki.Upload.Dialog' => [
'mediawiki.widgets.CategorySelector',
'mediawiki.widgets.DateInputWidget',
'mediawiki.jqueryMsg',
+ 'mediawiki.api.messages',
'moment',
'mediawiki.libs.jpegmeta',
],
'upload-form-label-own-work',
'upload-form-label-infoform-categories',
'upload-form-label-infoform-date',
- 'upload-form-label-own-work-message-default',
- 'upload-form-label-not-own-work-message-default',
- 'upload-form-label-not-own-work-local-default',
- 'upload-form-label-own-work-message-shared',
- 'upload-form-label-not-own-work-message-shared',
- 'upload-form-label-not-own-work-local-shared',
- 'upload-form-label-own-work-message-local',
- 'upload-form-label-not-own-work-message-local',
- 'upload-form-label-not-own-work-local-local',
+ 'upload-form-label-own-work-message-generic-local',
+ 'upload-form-label-not-own-work-message-generic-local',
+ 'upload-form-label-not-own-work-local-generic-local',
+ 'upload-form-label-own-work-message-generic-foreign',
+ 'upload-form-label-not-own-work-message-generic-foreign',
+ 'upload-form-label-not-own-work-local-generic-foreign',
],
],
'mediawiki.toc' => [
'watcherrortext',
],
],
+ 'mediawiki.page.rollback' => [
+ 'scripts' => 'resources/src/mediawiki/page/rollback.js',
+ 'dependencies' => [
+ 'mediawiki.api.rollback',
+ 'mediawiki.notify',
+ 'jquery.spinner',
+ ],
+ 'messages' => [
+ 'rollbackfailed',
+ 'actioncomplete',
+ ],
+ ],
'mediawiki.page.image.pagination' => [
'scripts' => 'resources/src/mediawiki/page/image-pagination.js',
'dependencies' => [
'mediawiki.special' => [
'position' => 'top',
- 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.js',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.css',
'targets' => [ 'desktop', 'mobile' ],
],
'styles' => 'resources/src/mediawiki.special/mediawiki.special.apisandbox.css',
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.apisandbox.js',
'dependencies' => [
- 'mediawiki.special',
'mediawiki.api',
'mediawiki.jqueryMsg',
'oojs-ui',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.block.css',
'dependencies' => 'mediawiki.util',
],
- 'mediawiki.special.blocklist' => [
- 'styles' => 'resources/src/mediawiki.special/mediawiki.special.blocklist.css',
- 'position' => 'top',
- ],
'mediawiki.special.changeslist' => [
'position' => 'top',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.changeslist.css',
],
'mediawiki.special.recentchanges' => [
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.recentchanges.js',
- 'dependencies' => 'mediawiki.special',
'position' => 'top',
],
'mediawiki.special.search' => [
'powersearch-togglenone',
],
],
+ 'mediawiki.special.search.styles' => [
+ 'styles' => 'resources/src/mediawiki.special/mediawiki.special.search.styles.css',
+ 'targets' => [ 'desktop', 'mobile' ],
+ ],
'mediawiki.special.undelete' => [
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.undelete.js',
],
'thumbnail.html' => 'resources/src/mediawiki.special/templates/thumbnail.html',
],
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.upload.js',
- 'styles' => 'resources/src/mediawiki.special/mediawiki.special.upload.css',
'messages' => [
'widthheight',
'size-bytes',
'prefs-editing',
],
'dependencies' => [
+ 'mediawiki.special.upload.styles',
'jquery.spinner',
'mediawiki.jqueryMsg',
'mediawiki.api',
'user.options',
],
],
+ 'mediawiki.special.upload.styles' => [
+ 'styles' => 'resources/src/mediawiki.special/mediawiki.special.upload.styles.css',
+ ],
'mediawiki.special.userlogin.common.styles' => [
'styles' => [
'resources/src/mediawiki.special/mediawiki.special.userlogin.common.css',
'skipFunction' => 'resources/src/oojs-ui-styles-skip.js',
];
- // Deprecated old name for the module 'oojs-ui-core.styles'.
- $modules['oojs-ui.styles'] = $modules['oojs-ui-core.styles'];
-
// Additional widgets and layouts module.
$modules['oojs-ui-widgets'] = [
'scripts' => 'resources/lib/oojs-ui/oojs-ui-widgets.js',
;
// UMD (Universal Module Definition)
-// see https://github.com/umdjs/umd/blob/master/returnExports.js
+// see https://github.com/umdjs/umd/blob/master/templates/returnExports.js
(function (root, factory) {
'use strict';
- /*global define, exports, module */
+ /* global define, exports, module */
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(factory);
*/
// Shortcut to an often accessed properties, in order to avoid multiple
-// dereference that costs universally.
-var ArrayPrototype = Array.prototype;
-var ObjectPrototype = Object.prototype;
-var FunctionPrototype = Function.prototype;
-var StringPrototype = String.prototype;
-var NumberPrototype = Number.prototype;
+// dereference that costs universally. This also holds a reference to known-good
+// functions.
+var $Array = Array;
+var ArrayPrototype = $Array.prototype;
+var $Object = Object;
+var ObjectPrototype = $Object.prototype;
+var $Function = Function;
+var FunctionPrototype = $Function.prototype;
+var $String = String;
+var StringPrototype = $String.prototype;
+var $Number = Number;
+var NumberPrototype = $Number.prototype;
var array_slice = ArrayPrototype.slice;
var array_splice = ArrayPrototype.splice;
var array_push = ArrayPrototype.push;
var array_unshift = ArrayPrototype.unshift;
var array_concat = ArrayPrototype.concat;
+var array_join = ArrayPrototype.join;
var call = FunctionPrototype.call;
+var apply = FunctionPrototype.apply;
+var max = Math.max;
+var min = Math.min;
// Having a toString local variable name breaks in Opera so use to_string.
var to_string = ObjectPrototype.toString;
-var isArray = Array.isArray || function isArray(obj) {
- return to_string.call(obj) === '[object Array]';
-};
-
+/* global Symbol */
+/* eslint-disable one-var-declaration-per-line, no-redeclare, max-statements-per-line */
var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
-var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, tryFunctionObject = function tryFunctionObject(value) { try { fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]'; isCallable = function isCallable(value) { if (typeof value !== 'function') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; };
+var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, constructorRegex = /^\s*class /, isES6ClassFn = function isES6ClassFn(value) { try { var fnStr = fnToStr.call(value); var singleStripped = fnStr.replace(/\/\/.*\n/g, ''); var multiStripped = singleStripped.replace(/\/\*[.\s\S]*\*\//g, ''); var spaceStripped = multiStripped.replace(/\n/mg, ' ').replace(/ {2}/g, ' '); return constructorRegex.test(spaceStripped); } catch (e) { return false; /* not a function */ } }, tryFunctionObject = function tryFunctionObject(value) { try { if (isES6ClassFn(value)) { return false; } fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]', isCallable = function isCallable(value) { if (!value) { return false; } if (typeof value !== 'function' && typeof value !== 'object') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } if (isES6ClassFn(value)) { return false; } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; };
+
var isRegex; /* inlined from https://npmjs.com/is-regex */ var regexExec = RegExp.prototype.exec, tryRegexExec = function tryRegexExec(value) { try { regexExec.call(value); return true; } catch (e) { return false; } }, regexClass = '[object RegExp]'; isRegex = function isRegex(value) { if (typeof value !== 'object') { return false; } return hasToStringTag ? tryRegexExec(value) : to_string.call(value) === regexClass; };
var isString; /* inlined from https://npmjs.com/is-string */ var strValue = String.prototype.valueOf, tryStringObject = function tryStringObject(value) { try { strValue.call(value); return true; } catch (e) { return false; } }, stringClass = '[object String]'; isString = function isString(value) { if (typeof value === 'string') { return true; } if (typeof value !== 'object') { return false; } return hasToStringTag ? tryStringObject(value) : to_string.call(value) === stringClass; };
-
-var isArguments = function isArguments(value) {
- var str = to_string.call(value);
- var isArgs = str === '[object Arguments]';
- if (!isArgs) {
- isArgs = !isArray(value) &&
- value !== null &&
- typeof value === 'object' &&
- typeof value.length === 'number' &&
- value.length >= 0 &&
- isCallable(value.callee);
- }
- return isArgs;
-};
+/* eslint-enable one-var-declaration-per-line, no-redeclare, max-statements-per-line */
/* inlined from http://npmjs.com/define-properties */
+var supportsDescriptors = $Object.defineProperty && (function () {
+ try {
+ var obj = {};
+ $Object.defineProperty(obj, 'x', { enumerable: false, value: obj });
+ for (var _ in obj) { return false; }
+ return obj.x === obj;
+ } catch (e) { /* this is ES3 */
+ return false;
+ }
+}());
var defineProperties = (function (has) {
- var supportsDescriptors = Object.defineProperty && (function () {
- try {
- var obj = {};
- Object.defineProperty(obj, 'x', { enumerable: false, value: obj });
- for (var _ in obj) { return false; }
- return obj.x === obj;
- } catch (e) { /* this is ES3 */
- return false;
- }
- }());
-
- // Define configurable, writable and non-enumerable props
+ // Define configurable, writable, and non-enumerable props
// if they don't exist.
var defineProperty;
if (supportsDescriptors) {
defineProperty = function (object, name, method, forceAssign) {
if (!forceAssign && (name in object)) { return; }
- Object.defineProperty(object, name, {
+ $Object.defineProperty(object, name, {
configurable: true,
enumerable: false,
writable: true,
return input === null || (type !== 'object' && type !== 'function');
};
+var isActualNaN = $Number.isNaN || function (x) { return x !== x; };
+
var ES = {
// ES5 9.4
// http://es5.github.com/#x9.4
/* replaceable with https://npmjs.com/package/es-abstract ES5.ToInteger */
ToInteger: function ToInteger(num) {
var n = +num;
- if (n !== n) { // isNaN
+ if (isActualNaN(n)) {
n = 0;
} else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
// http://es5.github.com/#x9.9
/* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */
ToObject: function (o) {
- /*jshint eqnull: true */
if (o == null) { // this matches both null and undefined
throw new TypeError("can't convert " + o + ' to object');
}
- return Object(o);
+ return $Object(o);
},
/* replaceable with https://npmjs.com/package/es-abstract ES5.ToUint32 */
// 5. Return the result of calling the [[Construct]] internal
// method of target providing args as the arguments.
- var result = target.apply(
+ var result = apply.call(
+ target,
this,
array_concat.call(args, array_slice.call(arguments))
);
- if (Object(result) === result) {
+ if ($Object(result) === result) {
return result;
}
return this;
// providing args as the arguments.
// equiv: target.call(this, ...boundArgs, ...args)
- return target.apply(
+ return apply.call(
+ target,
that,
array_concat.call(args, array_slice.call(arguments))
);
// larger.
// 16. Else set the length own property of F to 0.
- var boundLength = Math.max(0, target.length - args.length);
+ var boundLength = max(0, target.length - args.length);
// 17. Set the attributes of the length own property of F to the values
// specified in 15.3.5.1.
var boundArgs = [];
for (var i = 0; i < boundLength; i++) {
- boundArgs.push('$' + i);
+ array_push.call(boundArgs, '$' + i);
}
// XXX Build a dynamic function with desired amount of arguments is the only
// for ex.) all use of eval or Function costructor throws an exception.
// However in all of these environments Function.prototype.bind exists
// and so this code will never be executed.
- bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);
+ bound = $Function('binder', 'return function (' + array_join.call(boundArgs, ',') + '){ return binder.apply(this, arguments); }')(binder);
if (target.prototype) {
Empty.prototype = target.prototype;
});
// _Please note: Shortcuts are defined after `Function.prototype.bind` as we
-// us it in defining shortcuts.
+// use it in defining shortcuts.
var owns = call.bind(ObjectPrototype.hasOwnProperty);
+var toStr = call.bind(ObjectPrototype.toString);
+var arraySlice = call.bind(array_slice);
+var arraySliceApply = apply.bind(array_slice);
+var strSlice = call.bind(StringPrototype.slice);
+var strSplit = call.bind(StringPrototype.split);
+var strIndexOf = call.bind(StringPrototype.indexOf);
+var pushCall = call.bind(array_push);
+var isEnum = call.bind(ObjectPrototype.propertyIsEnumerable);
+var arraySort = call.bind(ArrayPrototype.sort);
//
// Array
// =====
//
-// ES5 15.4.4.12
-// http://es5.github.com/#x15.4.4.12
-var spliceNoopReturnsEmptyArray = (function () {
- var a = [1, 2];
- var result = a.splice();
- return a.length === 2 && isArray(result) && result.length === 0;
-}());
-defineProperties(ArrayPrototype, {
- // Safari 5.0 bug where .splice() returns undefined
- splice: function splice(start, deleteCount) {
- if (arguments.length === 0) {
- return [];
- } else {
- return array_splice.apply(this, arguments);
- }
- }
-}, !spliceNoopReturnsEmptyArray);
-
-var spliceWorksWithEmptyObject = (function () {
- var obj = {};
- ArrayPrototype.splice.call(obj, 0, 0, 1);
- return obj.length === 1;
-}());
-defineProperties(ArrayPrototype, {
- splice: function splice(start, deleteCount) {
- if (arguments.length === 0) { return []; }
- var args = arguments;
- this.length = Math.max(ES.ToInteger(this.length), 0);
- if (arguments.length > 0 && typeof deleteCount !== 'number') {
- args = array_slice.call(arguments);
- if (args.length < 2) {
- args.push(this.length - start);
- } else {
- args[1] = ES.ToInteger(deleteCount);
- }
- }
- return array_splice.apply(this, args);
- }
-}, !spliceWorksWithEmptyObject);
+var isArray = $Array.isArray || function isArray(obj) {
+ return toStr(obj) === '[object Array]';
+};
// ES5 15.4.4.12
// http://es5.github.com/#x15.4.4.13
// ES5 15.4.3.2
// http://es5.github.com/#x15.4.3.2
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
-defineProperties(Array, { isArray: isArray });
+defineProperties($Array, { isArray: isArray });
// The IsCallable() check in the Array functions
// has been replaced with a strict check on the
// Check failure of by-index access of string characters (IE < 9)
// and failure of `0 in boxedString` (Rhino)
-var boxedString = Object('a');
+var boxedString = $Object('a');
var splitString = boxedString[0] !== 'a' || !(0 in boxedString);
var properlyBoxesContext = function properlyBoxed(method) {
// Check node 0.6.21 bug where third parameter is not boxed
var properlyBoxesNonStrict = true;
var properlyBoxesStrict = true;
+ var threwException = false;
if (method) {
- method.call('foo', function (_, __, context) {
- if (typeof context !== 'object') { properlyBoxesNonStrict = false; }
- });
+ try {
+ method.call('foo', function (_, __, context) {
+ if (typeof context !== 'object') {
+ properlyBoxesNonStrict = false;
+ }
+ });
- method.call([1], function () {
- 'use strict';
+ method.call([1], function () {
+ 'use strict';
- properlyBoxesStrict = typeof this === 'string';
- }, 'x');
+ properlyBoxesStrict = typeof this === 'string';
+ }, 'x');
+ } catch (e) {
+ threwException = true;
+ }
}
- return !!method && properlyBoxesNonStrict && properlyBoxesStrict;
+ return !!method && !threwException && properlyBoxesNonStrict && properlyBoxesStrict;
};
defineProperties(ArrayPrototype, {
- forEach: function forEach(callbackfn /*, thisArg*/) {
+ forEach: function forEach(callbackfn/*, thisArg*/) {
var object = ES.ToObject(this);
- var self = splitString && isString(this) ? this.split('') : object;
+ var self = splitString && isString(this) ? strSplit(this, '') : object;
var i = -1;
- var length = self.length >>> 0;
+ var length = ES.ToUint32(self.length);
var T;
if (arguments.length > 1) {
T = arguments[1];
if (i in self) {
// Invoke the callback function with call, passing arguments:
// context, property value, property key, thisArg object
- if (typeof T !== 'undefined') {
- callbackfn.call(T, self[i], i, object);
- } else {
+ if (typeof T === 'undefined') {
callbackfn(self[i], i, object);
+ } else {
+ callbackfn.call(T, self[i], i, object);
}
}
}
defineProperties(ArrayPrototype, {
map: function map(callbackfn/*, thisArg*/) {
var object = ES.ToObject(this);
- var self = splitString && isString(this) ? this.split('') : object;
- var length = self.length >>> 0;
- var result = Array(length);
+ var self = splitString && isString(this) ? strSplit(this, '') : object;
+ var length = ES.ToUint32(self.length);
+ var result = $Array(length);
var T;
if (arguments.length > 1) {
T = arguments[1];
for (var i = 0; i < length; i++) {
if (i in self) {
- if (typeof T !== 'undefined') {
- result[i] = callbackfn.call(T, self[i], i, object);
- } else {
+ if (typeof T === 'undefined') {
result[i] = callbackfn(self[i], i, object);
+ } else {
+ result[i] = callbackfn.call(T, self[i], i, object);
}
}
}
// http://es5.github.com/#x15.4.4.20
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
defineProperties(ArrayPrototype, {
- filter: function filter(callbackfn /*, thisArg*/) {
+ filter: function filter(callbackfn/*, thisArg*/) {
var object = ES.ToObject(this);
- var self = splitString && isString(this) ? this.split('') : object;
- var length = self.length >>> 0;
+ var self = splitString && isString(this) ? strSplit(this, '') : object;
+ var length = ES.ToUint32(self.length);
var result = [];
var value;
var T;
if (i in self) {
value = self[i];
if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) {
- result.push(value);
+ pushCall(result, value);
}
}
}
// http://es5.github.com/#x15.4.4.16
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
defineProperties(ArrayPrototype, {
- every: function every(callbackfn /*, thisArg*/) {
+ every: function every(callbackfn/*, thisArg*/) {
var object = ES.ToObject(this);
- var self = splitString && isString(this) ? this.split('') : object;
- var length = self.length >>> 0;
+ var self = splitString && isString(this) ? strSplit(this, '') : object;
+ var length = ES.ToUint32(self.length);
var T;
if (arguments.length > 1) {
T = arguments[1];
defineProperties(ArrayPrototype, {
some: function some(callbackfn/*, thisArg */) {
var object = ES.ToObject(this);
- var self = splitString && isString(this) ? this.split('') : object;
- var length = self.length >>> 0;
+ var self = splitString && isString(this) ? strSplit(this, '') : object;
+ var length = ES.ToUint32(self.length);
var T;
if (arguments.length > 1) {
T = arguments[1];
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
var reduceCoercesToObject = false;
if (ArrayPrototype.reduce) {
- reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object';
+ reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) {
+ return list;
+ }) === 'object';
}
defineProperties(ArrayPrototype, {
- reduce: function reduce(callbackfn /*, initialValue*/) {
+ reduce: function reduce(callbackfn/*, initialValue*/) {
var object = ES.ToObject(this);
- var self = splitString && isString(this) ? this.split('') : object;
- var length = self.length >>> 0;
+ var self = splitString && isString(this) ? strSplit(this, '') : object;
+ var length = ES.ToUint32(self.length);
// If no callback function or if callback is not a callable function
if (!isCallable(callbackfn)) {
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
var reduceRightCoercesToObject = false;
if (ArrayPrototype.reduceRight) {
- reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object';
+ reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) {
+ return list;
+ }) === 'object';
}
defineProperties(ArrayPrototype, {
reduceRight: function reduceRight(callbackfn/*, initial*/) {
var object = ES.ToObject(this);
- var self = splitString && isString(this) ? this.split('') : object;
- var length = self.length >>> 0;
+ var self = splitString && isString(this) ? strSplit(this, '') : object;
+ var length = ES.ToUint32(self.length);
// If no callback function or if callback is not a callable function
if (!isCallable(callbackfn)) {
// ES5 15.4.4.14
// http://es5.github.com/#x15.4.4.14
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
-var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
+var hasFirefox2IndexOfBug = ArrayPrototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
defineProperties(ArrayPrototype, {
- indexOf: function indexOf(searchElement /*, fromIndex */) {
- var self = splitString && isString(this) ? this.split('') : ES.ToObject(this);
- var length = self.length >>> 0;
+ indexOf: function indexOf(searchElement/*, fromIndex */) {
+ var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this);
+ var length = ES.ToUint32(self.length);
if (length === 0) {
return -1;
}
// handle negative indices
- i = i >= 0 ? i : Math.max(0, length + i);
+ i = i >= 0 ? i : max(0, length + i);
for (; i < length; i++) {
if (i in self && self[i] === searchElement) {
return i;
// ES5 15.4.4.15
// http://es5.github.com/#x15.4.4.15
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
-var hasFirefox2LastIndexOfBug = Array.prototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1;
+var hasFirefox2LastIndexOfBug = ArrayPrototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1;
defineProperties(ArrayPrototype, {
- lastIndexOf: function lastIndexOf(searchElement /*, fromIndex */) {
- var self = splitString && isString(this) ? this.split('') : ES.ToObject(this);
- var length = self.length >>> 0;
+ lastIndexOf: function lastIndexOf(searchElement/*, fromIndex */) {
+ var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this);
+ var length = ES.ToUint32(self.length);
if (length === 0) {
return -1;
}
var i = length - 1;
if (arguments.length > 1) {
- i = Math.min(i, ES.ToInteger(arguments[1]));
+ i = min(i, ES.ToInteger(arguments[1]));
}
// handle negative indices
i = i >= 0 ? i : length - Math.abs(i);
}
}, hasFirefox2LastIndexOfBug);
+// ES5 15.4.4.12
+// http://es5.github.com/#x15.4.4.12
+var spliceNoopReturnsEmptyArray = (function () {
+ var a = [1, 2];
+ var result = a.splice();
+ return a.length === 2 && isArray(result) && result.length === 0;
+}());
+defineProperties(ArrayPrototype, {
+ // Safari 5.0 bug where .splice() returns undefined
+ splice: function splice(start, deleteCount) {
+ if (arguments.length === 0) {
+ return [];
+ } else {
+ return array_splice.apply(this, arguments);
+ }
+ }
+}, !spliceNoopReturnsEmptyArray);
+
+var spliceWorksWithEmptyObject = (function () {
+ var obj = {};
+ ArrayPrototype.splice.call(obj, 0, 0, 1);
+ return obj.length === 1;
+}());
+defineProperties(ArrayPrototype, {
+ splice: function splice(start, deleteCount) {
+ if (arguments.length === 0) { return []; }
+ var args = arguments;
+ this.length = max(ES.ToInteger(this.length), 0);
+ if (arguments.length > 0 && typeof deleteCount !== 'number') {
+ args = arraySlice(arguments);
+ if (args.length < 2) {
+ pushCall(args, this.length - start);
+ } else {
+ args[1] = ES.ToInteger(deleteCount);
+ }
+ }
+ return array_splice.apply(this, args);
+ }
+}, !spliceWorksWithEmptyObject);
+var spliceWorksWithLargeSparseArrays = (function () {
+ // Per https://github.com/es-shims/es5-shim/issues/295
+ // Safari 7/8 breaks with sparse arrays of size 1e5 or greater
+ var arr = new $Array(1e5);
+ // note: the index MUST be 8 or larger or the test will false pass
+ arr[8] = 'x';
+ arr.splice(1, 1);
+ // note: this test must be defined *after* the indexOf shim
+ // per https://github.com/es-shims/es5-shim/issues/313
+ return arr.indexOf('x') === 7;
+}());
+var spliceWorksWithSmallSparseArrays = (function () {
+ // Per https://github.com/es-shims/es5-shim/issues/295
+ // Opera 12.15 breaks on this, no idea why.
+ var n = 256;
+ var arr = [];
+ arr[n] = 'a';
+ arr.splice(n + 1, 0, 'b');
+ return arr[n] === 'a';
+}());
+defineProperties(ArrayPrototype, {
+ splice: function splice(start, deleteCount) {
+ var O = ES.ToObject(this);
+ var A = [];
+ var len = ES.ToUint32(O.length);
+ var relativeStart = ES.ToInteger(start);
+ var actualStart = relativeStart < 0 ? max((len + relativeStart), 0) : min(relativeStart, len);
+ var actualDeleteCount = min(max(ES.ToInteger(deleteCount), 0), len - actualStart);
+
+ var k = 0;
+ var from;
+ while (k < actualDeleteCount) {
+ from = $String(actualStart + k);
+ if (owns(O, from)) {
+ A[k] = O[from];
+ }
+ k += 1;
+ }
+
+ var items = arraySlice(arguments, 2);
+ var itemCount = items.length;
+ var to;
+ if (itemCount < actualDeleteCount) {
+ k = actualStart;
+ var maxK = len - actualDeleteCount;
+ while (k < maxK) {
+ from = $String(k + actualDeleteCount);
+ to = $String(k + itemCount);
+ if (owns(O, from)) {
+ O[to] = O[from];
+ } else {
+ delete O[to];
+ }
+ k += 1;
+ }
+ k = len;
+ var minK = len - actualDeleteCount + itemCount;
+ while (k > minK) {
+ delete O[k - 1];
+ k -= 1;
+ }
+ } else if (itemCount > actualDeleteCount) {
+ k = len - actualDeleteCount;
+ while (k > actualStart) {
+ from = $String(k + actualDeleteCount - 1);
+ to = $String(k + itemCount - 1);
+ if (owns(O, from)) {
+ O[to] = O[from];
+ } else {
+ delete O[to];
+ }
+ k -= 1;
+ }
+ }
+ k = actualStart;
+ for (var i = 0; i < items.length; ++i) {
+ O[k] = items[i];
+ k += 1;
+ }
+ O.length = len - actualDeleteCount + itemCount;
+
+ return A;
+ }
+}, !spliceWorksWithLargeSparseArrays || !spliceWorksWithSmallSparseArrays);
+
+var originalJoin = ArrayPrototype.join;
+var hasStringJoinBug;
+try {
+ hasStringJoinBug = Array.prototype.join.call('123', ',') !== '1,2,3';
+} catch (e) {
+ hasStringJoinBug = true;
+}
+if (hasStringJoinBug) {
+ defineProperties(ArrayPrototype, {
+ join: function join(separator) {
+ var sep = typeof separator === 'undefined' ? ',' : separator;
+ return originalJoin.call(isString(this) ? strSplit(this, '') : this, sep);
+ }
+ }, hasStringJoinBug);
+}
+
+var hasJoinUndefinedBug = [1, 2].join(undefined) !== '1,2';
+if (hasJoinUndefinedBug) {
+ defineProperties(ArrayPrototype, {
+ join: function join(separator) {
+ var sep = typeof separator === 'undefined' ? ',' : separator;
+ return originalJoin.call(this, sep);
+ }
+ }, hasJoinUndefinedBug);
+}
+
+var pushShim = function push(item) {
+ var O = ES.ToObject(this);
+ var n = ES.ToUint32(O.length);
+ var i = 0;
+ while (i < arguments.length) {
+ O[n + i] = arguments[i];
+ i += 1;
+ }
+ O.length = n + i;
+ return n + i;
+};
+
+var pushIsNotGeneric = (function () {
+ var obj = {};
+ var result = Array.prototype.push.call(obj, undefined);
+ return result !== 1 || obj.length !== 1 || typeof obj[0] !== 'undefined' || !owns(obj, 0);
+}());
+defineProperties(ArrayPrototype, {
+ push: function push(item) {
+ if (isArray(this)) {
+ return array_push.apply(this, arguments);
+ }
+ return pushShim.apply(this, arguments);
+ }
+}, pushIsNotGeneric);
+
+// This fixes a very weird bug in Opera 10.6 when pushing `undefined
+var pushUndefinedIsWeird = (function () {
+ var arr = [];
+ var result = arr.push(undefined);
+ return result !== 1 || arr.length !== 1 || typeof arr[0] !== 'undefined' || !owns(arr, 0);
+}());
+defineProperties(ArrayPrototype, { push: pushShim }, pushUndefinedIsWeird);
+
+// ES5 15.2.3.14
+// http://es5.github.io/#x15.4.4.10
+// Fix boxed string bug
+defineProperties(ArrayPrototype, {
+ slice: function (start, end) {
+ var arr = isString(this) ? strSplit(this, '') : this;
+ return arraySliceApply(arr, arguments);
+ }
+}, splitString);
+
+var sortIgnoresNonFunctions = (function () {
+ try {
+ [1, 2].sort(null);
+ [1, 2].sort({});
+ return true;
+ } catch (e) { /**/ }
+ return false;
+}());
+var sortThrowsOnRegex = (function () {
+ // this is a problem in Firefox 4, in which `typeof /a/ === 'function'`
+ try {
+ [1, 2].sort(/a/);
+ return false;
+ } catch (e) { /**/ }
+ return true;
+}());
+var sortIgnoresUndefined = (function () {
+ // applies in IE 8, for one.
+ try {
+ [1, 2].sort(undefined);
+ return true;
+ } catch (e) { /**/ }
+ return false;
+}());
+defineProperties(ArrayPrototype, {
+ sort: function sort(compareFn) {
+ if (typeof compareFn === 'undefined') {
+ return arraySort(this);
+ }
+ if (!isCallable(compareFn)) {
+ throw new TypeError('Array.prototype.sort callback must be a function');
+ }
+ return arraySort(this, compareFn);
+ }
+}, sortIgnoresNonFunctions || !sortIgnoresUndefined || !sortThrowsOnRegex);
+
//
// Object
// ======
// http://es5.github.com/#x15.2.3.14
// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
-var hasDontEnumBug = !({ 'toString': null }).propertyIsEnumerable('toString'),
- hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'),
- hasStringEnumBug = !owns('x', '0'),
- dontEnums = [
- 'toString',
- 'toLocaleString',
- 'valueOf',
- 'hasOwnProperty',
- 'isPrototypeOf',
- 'propertyIsEnumerable',
- 'constructor'
- ],
- dontEnumsLength = dontEnums.length;
-
-defineProperties(Object, {
+var hasDontEnumBug = !({ 'toString': null }).propertyIsEnumerable('toString');
+var hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype');
+var hasStringEnumBug = !owns('x', '0');
+var equalsConstructorPrototype = function (o) {
+ var ctor = o.constructor;
+ return ctor && ctor.prototype === o;
+};
+var blacklistedKeys = {
+ $window: true,
+ $console: true,
+ $parent: true,
+ $self: true,
+ $frame: true,
+ $frames: true,
+ $frameElement: true,
+ $webkitIndexedDB: true,
+ $webkitStorageInfo: true,
+ $external: true
+};
+var hasAutomationEqualityBug = (function () {
+ /* globals window */
+ if (typeof window === 'undefined') { return false; }
+ for (var k in window) {
+ try {
+ if (!blacklistedKeys['$' + k] && owns(window, k) && window[k] !== null && typeof window[k] === 'object') {
+ equalsConstructorPrototype(window[k]);
+ }
+ } catch (e) {
+ return true;
+ }
+ }
+ return false;
+}());
+var equalsConstructorPrototypeIfNotBuggy = function (object) {
+ if (typeof window === 'undefined' || !hasAutomationEqualityBug) { return equalsConstructorPrototype(object); }
+ try {
+ return equalsConstructorPrototype(object);
+ } catch (e) {
+ return false;
+ }
+};
+var dontEnums = [
+ 'toString',
+ 'toLocaleString',
+ 'valueOf',
+ 'hasOwnProperty',
+ 'isPrototypeOf',
+ 'propertyIsEnumerable',
+ 'constructor'
+];
+var dontEnumsLength = dontEnums.length;
+
+// taken directly from https://github.com/ljharb/is-arguments/blob/master/index.js
+// can be replaced with require('is-arguments') if we ever use a build process instead
+var isStandardArguments = function isArguments(value) {
+ return toStr(value) === '[object Arguments]';
+};
+var isLegacyArguments = function isArguments(value) {
+ return value !== null &&
+ typeof value === 'object' &&
+ typeof value.length === 'number' &&
+ value.length >= 0 &&
+ !isArray(value) &&
+ isCallable(value.callee);
+};
+var isArguments = isStandardArguments(arguments) ? isStandardArguments : isLegacyArguments;
+
+defineProperties($Object, {
keys: function keys(object) {
- var isFn = isCallable(object),
- isArgs = isArguments(object),
- isObject = object !== null && typeof object === 'object',
- isStr = isObject && isString(object);
+ var isFn = isCallable(object);
+ var isArgs = isArguments(object);
+ var isObject = object !== null && typeof object === 'object';
+ var isStr = isObject && isString(object);
if (!isObject && !isFn && !isArgs) {
throw new TypeError('Object.keys called on a non-object');
var skipProto = hasProtoEnumBug && isFn;
if ((isStr && hasStringEnumBug) || isArgs) {
for (var i = 0; i < object.length; ++i) {
- theKeys.push(String(i));
+ pushCall(theKeys, $String(i));
}
}
if (!isArgs) {
for (var name in object) {
if (!(skipProto && name === 'prototype') && owns(object, name)) {
- theKeys.push(String(name));
+ pushCall(theKeys, $String(name));
}
}
}
if (hasDontEnumBug) {
- var ctor = object.constructor,
- skipConstructor = ctor && ctor.prototype === object;
+ var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
for (var j = 0; j < dontEnumsLength; j++) {
var dontEnum = dontEnums[j];
if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) {
- theKeys.push(dontEnum);
+ pushCall(theKeys, dontEnum);
}
}
}
}
});
-var keysWorksWithArguments = Object.keys && (function () {
+var keysWorksWithArguments = $Object.keys && (function () {
// Safari 5.0 bug
- return Object.keys(arguments).length === 2;
+ return $Object.keys(arguments).length === 2;
}(1, 2));
-var originalKeys = Object.keys;
-defineProperties(Object, {
+var keysHasArgumentsLengthBug = $Object.keys && (function () {
+ var argKeys = $Object.keys(arguments);
+ return arguments.length !== 1 || argKeys.length !== 1 || argKeys[0] !== 1;
+}(1));
+var originalKeys = $Object.keys;
+defineProperties($Object, {
keys: function keys(object) {
if (isArguments(object)) {
- return originalKeys(ArrayPrototype.slice.call(object));
+ return originalKeys(arraySlice(object));
} else {
return originalKeys(object);
}
}
-}, !keysWorksWithArguments);
+}, !keysWorksWithArguments || keysHasArgumentsLengthBug);
//
// Date
// ====
//
+var hasNegativeMonthYearBug = new Date(-3509827329600292).getUTCMonth() !== 0;
+var aNegativeTestDate = new Date(-1509842289600292);
+var aPositiveTestDate = new Date(1449662400000);
+var hasToUTCStringFormatBug = aNegativeTestDate.toUTCString() !== 'Mon, 01 Jan -45875 11:59:59 GMT';
+var hasToDateStringFormatBug;
+var hasToStringFormatBug;
+var timeZoneOffset = aNegativeTestDate.getTimezoneOffset();
+if (timeZoneOffset < -720) {
+ hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Tue Jan 02 -45875';
+ hasToStringFormatBug = !(/^Thu Dec 10 2015 \d\d:\d\d:\d\d GMT[-\+]\d\d\d\d(?: |$)/).test(aPositiveTestDate.toString());
+} else {
+ hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Mon Jan 01 -45875';
+ hasToStringFormatBug = !(/^Wed Dec 09 2015 \d\d:\d\d:\d\d GMT[-\+]\d\d\d\d(?: |$)/).test(aPositiveTestDate.toString());
+}
+
+var originalGetFullYear = call.bind(Date.prototype.getFullYear);
+var originalGetMonth = call.bind(Date.prototype.getMonth);
+var originalGetDate = call.bind(Date.prototype.getDate);
+var originalGetUTCFullYear = call.bind(Date.prototype.getUTCFullYear);
+var originalGetUTCMonth = call.bind(Date.prototype.getUTCMonth);
+var originalGetUTCDate = call.bind(Date.prototype.getUTCDate);
+var originalGetUTCDay = call.bind(Date.prototype.getUTCDay);
+var originalGetUTCHours = call.bind(Date.prototype.getUTCHours);
+var originalGetUTCMinutes = call.bind(Date.prototype.getUTCMinutes);
+var originalGetUTCSeconds = call.bind(Date.prototype.getUTCSeconds);
+var originalGetUTCMilliseconds = call.bind(Date.prototype.getUTCMilliseconds);
+var dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
+var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+var daysInMonth = function daysInMonth(month, year) {
+ return originalGetDate(new Date(year, month, 0));
+};
+
+defineProperties(Date.prototype, {
+ getFullYear: function getFullYear() {
+ if (!this || !(this instanceof Date)) {
+ throw new TypeError('this is not a Date object.');
+ }
+ var year = originalGetFullYear(this);
+ if (year < 0 && originalGetMonth(this) > 11) {
+ return year + 1;
+ }
+ return year;
+ },
+ getMonth: function getMonth() {
+ if (!this || !(this instanceof Date)) {
+ throw new TypeError('this is not a Date object.');
+ }
+ var year = originalGetFullYear(this);
+ var month = originalGetMonth(this);
+ if (year < 0 && month > 11) {
+ return 0;
+ }
+ return month;
+ },
+ getDate: function getDate() {
+ if (!this || !(this instanceof Date)) {
+ throw new TypeError('this is not a Date object.');
+ }
+ var year = originalGetFullYear(this);
+ var month = originalGetMonth(this);
+ var date = originalGetDate(this);
+ if (year < 0 && month > 11) {
+ if (month === 12) {
+ return date;
+ }
+ var days = daysInMonth(0, year + 1);
+ return (days - date) + 1;
+ }
+ return date;
+ },
+ getUTCFullYear: function getUTCFullYear() {
+ if (!this || !(this instanceof Date)) {
+ throw new TypeError('this is not a Date object.');
+ }
+ var year = originalGetUTCFullYear(this);
+ if (year < 0 && originalGetUTCMonth(this) > 11) {
+ return year + 1;
+ }
+ return year;
+ },
+ getUTCMonth: function getUTCMonth() {
+ if (!this || !(this instanceof Date)) {
+ throw new TypeError('this is not a Date object.');
+ }
+ var year = originalGetUTCFullYear(this);
+ var month = originalGetUTCMonth(this);
+ if (year < 0 && month > 11) {
+ return 0;
+ }
+ return month;
+ },
+ getUTCDate: function getUTCDate() {
+ if (!this || !(this instanceof Date)) {
+ throw new TypeError('this is not a Date object.');
+ }
+ var year = originalGetUTCFullYear(this);
+ var month = originalGetUTCMonth(this);
+ var date = originalGetUTCDate(this);
+ if (year < 0 && month > 11) {
+ if (month === 12) {
+ return date;
+ }
+ var days = daysInMonth(0, year + 1);
+ return (days - date) + 1;
+ }
+ return date;
+ }
+}, hasNegativeMonthYearBug);
+
+defineProperties(Date.prototype, {
+ toUTCString: function toUTCString() {
+ if (!this || !(this instanceof Date)) {
+ throw new TypeError('this is not a Date object.');
+ }
+ var day = originalGetUTCDay(this);
+ var date = originalGetUTCDate(this);
+ var month = originalGetUTCMonth(this);
+ var year = originalGetUTCFullYear(this);
+ var hour = originalGetUTCHours(this);
+ var minute = originalGetUTCMinutes(this);
+ var second = originalGetUTCSeconds(this);
+ return dayName[day] + ', ' +
+ (date < 10 ? '0' + date : date) + ' ' +
+ monthName[month] + ' ' +
+ year + ' ' +
+ (hour < 10 ? '0' + hour : hour) + ':' +
+ (minute < 10 ? '0' + minute : minute) + ':' +
+ (second < 10 ? '0' + second : second) + ' GMT';
+ }
+}, hasNegativeMonthYearBug || hasToUTCStringFormatBug);
+
+// Opera 12 has `,`
+defineProperties(Date.prototype, {
+ toDateString: function toDateString() {
+ if (!this || !(this instanceof Date)) {
+ throw new TypeError('this is not a Date object.');
+ }
+ var day = this.getDay();
+ var date = this.getDate();
+ var month = this.getMonth();
+ var year = this.getFullYear();
+ return dayName[day] + ' ' +
+ monthName[month] + ' ' +
+ (date < 10 ? '0' + date : date) + ' ' +
+ year;
+ }
+}, hasNegativeMonthYearBug || hasToDateStringFormatBug);
+
+// can't use defineProperties here because of toString enumeration issue in IE <= 8
+if (hasNegativeMonthYearBug || hasToStringFormatBug) {
+ Date.prototype.toString = function toString() {
+ if (!this || !(this instanceof Date)) {
+ throw new TypeError('this is not a Date object.');
+ }
+ var day = this.getDay();
+ var date = this.getDate();
+ var month = this.getMonth();
+ var year = this.getFullYear();
+ var hour = this.getHours();
+ var minute = this.getMinutes();
+ var second = this.getSeconds();
+ var timezoneOffset = this.getTimezoneOffset();
+ var hoursOffset = Math.floor(Math.abs(timezoneOffset) / 60);
+ var minutesOffset = Math.floor(Math.abs(timezoneOffset) % 60);
+ return dayName[day] + ' ' +
+ monthName[month] + ' ' +
+ (date < 10 ? '0' + date : date) + ' ' +
+ year + ' ' +
+ (hour < 10 ? '0' + hour : hour) + ':' +
+ (minute < 10 ? '0' + minute : minute) + ':' +
+ (second < 10 ? '0' + second : second) + ' GMT' +
+ (timezoneOffset > 0 ? '-' : '+') +
+ (hoursOffset < 10 ? '0' + hoursOffset : hoursOffset) +
+ (minutesOffset < 10 ? '0' + minutesOffset : minutesOffset);
+ };
+ if (supportsDescriptors) {
+ $Object.defineProperty(Date.prototype, 'toString', {
+ configurable: true,
+ enumerable: false,
+ writable: true
+ });
+ }
+}
+
// ES5 15.9.5.43
// http://es5.github.com/#x15.9.5.43
// This function returns a String value represent the instance in time
var negativeDate = -62198755200000;
var negativeYearString = '-000001';
var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1;
+var hasSafari51DateBug = Date.prototype.toISOString && new Date(-1).toISOString() !== '1969-12-31T23:59:59.999Z';
+
+var getTime = call.bind(Date.prototype.getTime);
defineProperties(Date.prototype, {
toISOString: function toISOString() {
- var result, length, value, year, month;
- if (!isFinite(this)) {
+ if (!isFinite(this) || !isFinite(getTime(this))) {
+ // Adope Photoshop requires the second check.
throw new RangeError('Date.prototype.toISOString called on non-finite value.');
}
- year = this.getUTCFullYear();
+ var year = originalGetUTCFullYear(this);
- month = this.getUTCMonth();
+ var month = originalGetUTCMonth(this);
// see https://github.com/es-shims/es5-shim/issues/111
year += Math.floor(month / 12);
month = (month % 12 + 12) % 12;
// the date time string format is specified in 15.9.1.15.
- result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
+ var result = [month + 1, originalGetUTCDate(this), originalGetUTCHours(this), originalGetUTCMinutes(this), originalGetUTCSeconds(this)];
year = (
(year < 0 ? '-' : (year > 9999 ? '+' : '')) +
- ('00000' + Math.abs(year)).slice((0 <= year && year <= 9999) ? -4 : -6)
+ strSlice('00000' + Math.abs(year), (0 <= year && year <= 9999) ? -4 : -6)
);
- length = result.length;
- while (length--) {
- value = result[length];
- // pad months, days, hours, minutes, and seconds to have two
- // digits.
- if (value < 10) {
- result[length] = '0' + value;
- }
+ for (var i = 0; i < result.length; ++i) {
+ // pad months, days, hours, minutes, and seconds to have two digits.
+ result[i] = strSlice('00' + result[i], -2);
}
// pad milliseconds to have three digits.
return (
- year + '-' + result.slice(0, 2).join('-') +
- 'T' + result.slice(2).join(':') + '.' +
- ('000' + this.getUTCMilliseconds()).slice(-3) + 'Z'
+ year + '-' + arraySlice(result, 0, 2).join('-') +
+ 'T' + arraySlice(result, 2).join(':') + '.' +
+ strSlice('000' + originalGetUTCMilliseconds(this), -3) + 'Z'
);
}
-}, hasNegativeDateBug);
+}, hasNegativeDateBug || hasSafari51DateBug);
// ES5 15.9.5.44
// http://es5.github.com/#x15.9.5.44
// 1. Let O be the result of calling ToObject, giving it the this
// value as its argument.
// 2. Let tv be ES.ToPrimitive(O, hint Number).
- var O = Object(this);
+ var O = $Object(this);
var tv = ES.ToPrimitive(O);
// 3. If tv is a Number and is not finite, return null.
if (typeof tv === 'number' && !isFinite(tv)) {
var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15;
var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')) || !isNaN(Date.parse('2012-12-31T23:59:60.000Z'));
var doesNotParseY2KNewYear = isNaN(Date.parse('2000-01-01T00:00:00.000Z'));
-if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) {
+if (doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) {
// XXX global assignment won't work in embeddings that use
// an alternate object for the context.
- /*global Date: true */
- /*eslint-disable no-undef*/
+ /* global Date: true */
+ /* eslint-disable no-undef */
+ var maxSafeUnsigned32Bit = Math.pow(2, 31) - 1;
+ var hasSafariSignedIntBug = isActualNaN(new Date(1970, 0, 1, 0, 0, 0, maxSafeUnsigned32Bit + 1).getTime());
+ /* eslint-disable no-implicit-globals */
Date = (function (NativeDate) {
- /*eslint-enable no-undef*/
+ /* eslint-enable no-implicit-globals */
+ /* eslint-enable no-undef */
// Date.length === 7
var DateShim = function Date(Y, M, D, h, m, s, ms) {
var length = arguments.length;
var date;
if (this instanceof NativeDate) {
- date = length === 1 && String(Y) === Y ? // isString(Y)
+ var seconds = s;
+ var millis = ms;
+ if (hasSafariSignedIntBug && length >= 7 && ms > maxSafeUnsigned32Bit) {
+ // work around a Safari 8/9 bug where it treats the seconds as signed
+ var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit;
+ var sToShift = Math.floor(msToShift / 1e3);
+ seconds += sToShift;
+ millis -= sToShift * 1e3;
+ }
+ date = length === 1 && $String(Y) === Y ? // isString(Y)
// We explicitly pass it through parse:
new NativeDate(DateShim.parse(Y)) :
// We have to manually make calls depending on argument
// length here
- length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
- length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
+ length >= 7 ? new NativeDate(Y, M, D, h, m, seconds, millis) :
+ length >= 6 ? new NativeDate(Y, M, D, h, m, seconds) :
length >= 5 ? new NativeDate(Y, M, D, h, m) :
length >= 4 ? new NativeDate(Y, M, D, h) :
length >= 3 ? new NativeDate(Y, M, D) :
length >= 2 ? new NativeDate(Y, M) :
- length >= 1 ? new NativeDate(Y) :
+ length >= 1 ? new NativeDate(Y instanceof NativeDate ? +Y : Y) :
new NativeDate();
} else {
date = NativeDate.apply(this, arguments);
}
- // Prevent mixups with unfixed Date object
- defineProperties(date, { constructor: DateShim }, true);
+ if (!isPrimitive(date)) {
+ // Prevent mixups with unfixed Date object
+ defineProperties(date, { constructor: DateShim }, true);
+ }
return date;
};
};
var toUTC = function toUTC(t) {
- return Number(new NativeDate(1970, 0, 1, 0, 0, 0, t));
+ var s = 0;
+ var ms = t;
+ if (hasSafariSignedIntBug && ms > maxSafeUnsigned32Bit) {
+ // work around a Safari 8/9 bug where it treats the seconds as signed
+ var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit;
+ var sToShift = Math.floor(msToShift / 1e3);
+ s += sToShift;
+ ms -= sToShift * 1e3;
+ }
+ return $Number(new NativeDate(1970, 0, 1, 0, 0, s, ms));
};
// Copy any custom methods a 3rd party library may have added
}, true);
// Upgrade Date.parse to handle simplified ISO 8601 strings
- DateShim.parse = function parse(string) {
+ var parseShim = function parse(string) {
var match = isoDateExpression.exec(string);
if (match) {
// parse months, days, hours, minutes, seconds, and milliseconds
// provide default values if necessary
// parse the UTC offset component
- var year = Number(match[1]),
- month = Number(match[2] || 1) - 1,
- day = Number(match[3] || 1) - 1,
- hour = Number(match[4] || 0),
- minute = Number(match[5] || 0),
- second = Number(match[6] || 0),
- millisecond = Math.floor(Number(match[7] || 0) * 1000),
+ var year = $Number(match[1]),
+ month = $Number(match[2] || 1) - 1,
+ day = $Number(match[3] || 1) - 1,
+ hour = $Number(match[4] || 0),
+ minute = $Number(match[5] || 0),
+ second = $Number(match[6] || 0),
+ millisecond = Math.floor($Number(match[7] || 0) * 1000),
// When time zone is missed, local offset should be used
// (ES 5.1 bug)
// see https://bugs.ecmascript.org/show_bug.cgi?id=112
isLocalTime = Boolean(match[4] && !match[8]),
signOffset = match[9] === '-' ? 1 : -1,
- hourOffset = Number(match[10] || 0),
- minuteOffset = Number(match[11] || 0),
+ hourOffset = $Number(match[10] || 0),
+ minuteOffset = $Number(match[11] || 0),
result;
+ var hasMinutesOrSecondsOrMilliseconds = minute > 0 || second > 0 || millisecond > 0;
if (
- hour < (
- minute > 0 || second > 0 || millisecond > 0 ?
- 24 : 25
- ) &&
+ hour < (hasMinutesOrSecondsOrMilliseconds ? 24 : 25) &&
minute < 60 && second < 60 && millisecond < 1000 &&
month > -1 && month < 12 && hourOffset < 24 &&
minuteOffset < 60 && // detect invalid offsets
day > -1 &&
- day < (
- dayFromMonth(year, month + 1) -
- dayFromMonth(year, month)
- )
+ day < (dayFromMonth(year, month + 1) - dayFromMonth(year, month))
) {
result = (
(dayFromMonth(year, month) + day) * 24 +
}
return NativeDate.parse.apply(this, arguments);
};
+ defineProperties(DateShim, { parse: parseShim });
return DateShim;
}(Date));
- /*global Date: false */
+ /* global Date: false */
}
// ES5 15.9.4.4
}
},
divide: function divide(n) {
- var i = toFixedHelpers.size, c = 0;
+ var i = toFixedHelpers.size;
+ var c = 0;
while (--i >= 0) {
c += toFixedHelpers.data[i];
toFixedHelpers.data[i] = Math.floor(c / n);
var s = '';
while (--i >= 0) {
if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) {
- var t = String(toFixedHelpers.data[i]);
+ var t = $String(toFixedHelpers.data[i]);
if (s === '') {
s = t;
} else {
- s += '0000000'.slice(0, 7 - t.length) + t;
+ s += strSlice('0000000', 0, 7 - t.length) + t;
}
}
}
}
};
-defineProperties(NumberPrototype, {
- toFixed: function toFixed(fractionDigits) {
- var f, x, s, m, e, z, j, k;
-
- // Test for NaN and round fractionDigits down
- f = Number(fractionDigits);
- f = f !== f ? 0 : Math.floor(f);
-
- if (f < 0 || f > 20) {
- throw new RangeError('Number.toFixed called with invalid number of decimals');
- }
+var toFixedShim = function toFixed(fractionDigits) {
+ var f, x, s, m, e, z, j, k;
- x = Number(this);
-
- // Test for NaN
- if (x !== x) {
- return 'NaN';
- }
-
- // If it is too big or small, return the string value of the number
- if (x <= -1e21 || x >= 1e21) {
- return String(x);
- }
+ // Test for NaN and round fractionDigits down
+ f = $Number(fractionDigits);
+ f = isActualNaN(f) ? 0 : Math.floor(f);
- s = '';
+ if (f < 0 || f > 20) {
+ throw new RangeError('Number.toFixed called with invalid number of decimals');
+ }
- if (x < 0) {
- s = '-';
- x = -x;
- }
+ x = $Number(this);
- m = '0';
+ if (isActualNaN(x)) {
+ return 'NaN';
+ }
- if (x > 1e-21) {
- // 1e-21 < x < 1e21
- // -70 < log2(x) < 70
- e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69;
- z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1));
- z *= 0x10000000000000; // Math.pow(2, 52);
- e = 52 - e;
+ // If it is too big or small, return the string value of the number
+ if (x <= -1e21 || x >= 1e21) {
+ return $String(x);
+ }
- // -18 < e < 122
- // x = z / 2 ^ e
- if (e > 0) {
- toFixedHelpers.multiply(0, z);
- j = f;
+ s = '';
- while (j >= 7) {
- toFixedHelpers.multiply(1e7, 0);
- j -= 7;
- }
+ if (x < 0) {
+ s = '-';
+ x = -x;
+ }
- toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0);
- j = e - 1;
+ m = '0';
+
+ if (x > 1e-21) {
+ // 1e-21 < x < 1e21
+ // -70 < log2(x) < 70
+ e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69;
+ z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1));
+ z *= 0x10000000000000; // Math.pow(2, 52);
+ e = 52 - e;
+
+ // -18 < e < 122
+ // x = z / 2 ^ e
+ if (e > 0) {
+ toFixedHelpers.multiply(0, z);
+ j = f;
+
+ while (j >= 7) {
+ toFixedHelpers.multiply(1e7, 0);
+ j -= 7;
+ }
- while (j >= 23) {
- toFixedHelpers.divide(1 << 23);
- j -= 23;
- }
+ toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0);
+ j = e - 1;
- toFixedHelpers.divide(1 << j);
- toFixedHelpers.multiply(1, 1);
- toFixedHelpers.divide(2);
- m = toFixedHelpers.numToString();
- } else {
- toFixedHelpers.multiply(0, z);
- toFixedHelpers.multiply(1 << (-e), 0);
- m = toFixedHelpers.numToString() + '0.00000000000000000000'.slice(2, 2 + f);
+ while (j >= 23) {
+ toFixedHelpers.divide(1 << 23);
+ j -= 23;
}
+
+ toFixedHelpers.divide(1 << j);
+ toFixedHelpers.multiply(1, 1);
+ toFixedHelpers.divide(2);
+ m = toFixedHelpers.numToString();
+ } else {
+ toFixedHelpers.multiply(0, z);
+ toFixedHelpers.multiply(1 << (-e), 0);
+ m = toFixedHelpers.numToString() + strSlice('0.00000000000000000000', 2, 2 + f);
}
+ }
- if (f > 0) {
- k = m.length;
+ if (f > 0) {
+ k = m.length;
- if (k <= f) {
- m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m;
- } else {
- m = s + m.slice(0, k - f) + '.' + m.slice(k - f);
- }
+ if (k <= f) {
+ m = s + strSlice('0.0000000000000000000', 0, f - k + 2) + m;
} else {
- m = s + m;
+ m = s + strSlice(m, 0, k - f) + '.' + strSlice(m, k - f);
}
+ } else {
+ m = s + m;
+ }
+
+ return m;
+};
+defineProperties(NumberPrototype, { toFixed: toFixedShim }, hasToFixedBugs);
- return m;
+var hasToPrecisionUndefinedBug = (function () {
+ try {
+ return 1.0.toPrecision(undefined) === '1';
+ } catch (e) {
+ return true;
+ }
+}());
+var originalToPrecision = NumberPrototype.toPrecision;
+defineProperties(NumberPrototype, {
+ toPrecision: function toPrecision(precision) {
+ return typeof precision === 'undefined' ? originalToPrecision.call(this) : originalToPrecision.call(this, precision);
}
-}, hasToFixedBugs);
+}, hasToPrecisionUndefinedBug);
//
// String
// ''.split(/.?/) should be [], not [""]
// '.'.split(/()()/) should be ["."], not ["", "", "."]
-var string_split = StringPrototype.split;
if (
'ab'.split(/(?:ab)*/).length !== 2 ||
'.'.split(/(.?)(.?)/).length !== 4 ||
) {
(function () {
var compliantExecNpcg = typeof (/()??/).exec('')[1] === 'undefined'; // NPCG: nonparticipating capturing group
+ var maxSafe32BitInt = Math.pow(2, 32) - 1;
StringPrototype.split = function (separator, limit) {
- var string = this;
+ var string = String(this);
if (typeof separator === 'undefined' && limit === 0) {
return [];
}
// If `separator` is not a regex, use native split
if (!isRegex(separator)) {
- return string_split.call(this, separator, limit);
+ return strSplit(this, separator, limit);
}
var output = [];
var flags = (separator.ignoreCase ? 'i' : '') +
(separator.multiline ? 'm' : '') +
- (separator.extended ? 'x' : '') + // Proposed for ES6
- (separator.sticky ? 'y' : ''), // Firefox 3+
+ (separator.unicode ? 'u' : '') + // in ES6
+ (separator.sticky ? 'y' : ''), // Firefox 3+ and ES6
lastLastIndex = 0,
// Make `global` and avoid `lastIndex` issues by working with a copy
separator2, match, lastIndex, lastLength;
var separatorCopy = new RegExp(separator.source, flags + 'g');
- string += ''; // Type-convert
if (!compliantExecNpcg) {
// Doesn't need flags gy, but they don't hurt
separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags);
}
/* Values for `limit`, per the spec:
- * If undefined: 4294967295 // Math.pow(2, 32) - 1
+ * If undefined: 4294967295 // maxSafe32BitInt
* If 0, Infinity, or NaN: 0
* If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
* If negative number: 4294967296 - Math.floor(Math.abs(limit))
* If other: Type-convert, then use the above rules
*/
- var splitLimit = typeof limit === 'undefined' ?
- -1 >>> 0 : // Math.pow(2, 32) - 1
- ES.ToUint32(limit);
+ var splitLimit = typeof limit === 'undefined' ? maxSafe32BitInt : ES.ToUint32(limit);
match = separatorCopy.exec(string);
while (match) {
// `separatorCopy.lastIndex` is not reliable cross-browser
lastIndex = match.index + match[0].length;
if (lastIndex > lastLastIndex) {
- output.push(string.slice(lastLastIndex, match.index));
+ pushCall(output, strSlice(string, lastLastIndex, match.index));
// Fix browsers whose `exec` methods don't consistently return `undefined` for
// nonparticipating capturing groups
if (!compliantExecNpcg && match.length > 1) {
- /*eslint-disable no-loop-func */
+ /* eslint-disable no-loop-func */
match[0].replace(separator2, function () {
for (var i = 1; i < arguments.length - 2; i++) {
if (typeof arguments[i] === 'undefined') {
}
}
});
- /*eslint-enable no-loop-func */
+ /* eslint-enable no-loop-func */
}
if (match.length > 1 && match.index < string.length) {
- array_push.apply(output, match.slice(1));
+ array_push.apply(output, arraySlice(match, 1));
}
lastLength = match[0].length;
lastLastIndex = lastIndex;
}
if (lastLastIndex === string.length) {
if (lastLength || !separatorCopy.test('')) {
- output.push('');
+ pushCall(output, '');
}
} else {
- output.push(string.slice(lastLastIndex));
+ pushCall(output, strSlice(string, lastLastIndex));
}
- return output.length > splitLimit ? output.slice(0, splitLimit) : output;
+ return output.length > splitLimit ? arraySlice(output, 0, splitLimit) : output;
};
}());
} else if ('0'.split(void 0, 0).length) {
StringPrototype.split = function split(separator, limit) {
if (typeof separator === 'undefined' && limit === 0) { return []; }
- return string_split.call(this, separator, limit);
+ return strSplit(this, separator, limit);
};
}
var replaceReportsGroupsCorrectly = (function () {
var groups = [];
'x'.replace(/x(.)?/g, function (match, group) {
- groups.push(group);
+ pushCall(groups, group);
});
return groups.length === 1 && typeof groups[0] === 'undefined';
}());
searchValue.lastIndex = 0;
var args = searchValue.exec(match) || [];
searchValue.lastIndex = originalLastIndex;
- args.push(arguments[length - 2], arguments[length - 1]);
+ pushCall(args, arguments[length - 2], arguments[length - 1]);
return replaceValue.apply(this, args);
};
return str_replace.call(this, searchValue, wrappedReplaceValue);
substr: function substr(start, length) {
var normalizedStart = start;
if (start < 0) {
- normalizedStart = Math.max(this.length + start, 0);
+ normalizedStart = max(this.length + start, 0);
}
return string_substr.call(this, normalizedStart, length);
}
if (typeof this === 'undefined' || this === null) {
throw new TypeError("can't convert " + this + ' to object');
}
- return String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
+ return $String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
}
}, hasTrimWhitespaceBug);
+var trim = call.bind(String.prototype.trim);
+
+var hasLastIndexBug = StringPrototype.lastIndexOf && 'abcあい'.lastIndexOf('あい', 2) !== -1;
+defineProperties(StringPrototype, {
+ lastIndexOf: function lastIndexOf(searchString) {
+ if (typeof this === 'undefined' || this === null) {
+ throw new TypeError("can't convert " + this + ' to object');
+ }
+ var S = $String(this);
+ var searchStr = $String(searchString);
+ var numPos = arguments.length > 1 ? $Number(arguments[1]) : NaN;
+ var pos = isActualNaN(numPos) ? Infinity : ES.ToInteger(numPos);
+ var start = min(max(pos, 0), S.length);
+ var searchLen = searchStr.length;
+ var k = start + searchLen;
+ while (k > 0) {
+ k = max(0, k - searchLen);
+ var index = strIndexOf(strSlice(S, k, start + searchLen), searchStr);
+ if (index !== -1) {
+ return k + index;
+ }
+ }
+ return -1;
+ }
+}, hasLastIndexBug);
+
+var originalLastIndexOf = StringPrototype.lastIndexOf;
+defineProperties(StringPrototype, {
+ lastIndexOf: function lastIndexOf(searchString) {
+ return originalLastIndexOf.apply(this, arguments);
+ }
+}, StringPrototype.lastIndexOf.length !== 1);
// ES-5 15.1.2.2
+/* eslint-disable radix */
if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) {
- /*global parseInt: true */
+/* eslint-enable radix */
+ /* global parseInt: true */
parseInt = (function (origParseInt) {
- var hexRegex = /^0[xX]/;
+ var hexRegex = /^[\-+]?0[xX]/;
return function parseInt(str, radix) {
- var string = String(str).trim();
- var defaultedRadix = Number(radix) || (hexRegex.test(string) ? 16 : 10);
+ var string = trim(str);
+ var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10);
return origParseInt(string, defaultedRadix);
};
}(parseInt));
}
+// https://es5.github.io/#x15.1.2.3
+if (1 / parseFloat('-0') !== -Infinity) {
+ /* global parseFloat: true */
+ parseFloat = (function (origParseFloat) {
+ return function parseFloat(string) {
+ var inputString = trim(string);
+ var result = origParseFloat(inputString);
+ return result === 0 && strSlice(inputString, 0, 1) === '-' ? -0 : result;
+ };
+ }(parseFloat));
+}
+
+if (String(new RangeError('test')) !== 'RangeError: test') {
+ var errorToStringShim = function toString() {
+ if (typeof this === 'undefined' || this === null) {
+ throw new TypeError("can't convert " + this + ' to object');
+ }
+ var name = this.name;
+ if (typeof name === 'undefined') {
+ name = 'Error';
+ } else if (typeof name !== 'string') {
+ name = $String(name);
+ }
+ var msg = this.message;
+ if (typeof msg === 'undefined') {
+ msg = '';
+ } else if (typeof msg !== 'string') {
+ msg = $String(msg);
+ }
+ if (!name) {
+ return msg;
+ }
+ if (!msg) {
+ return name;
+ }
+ return name + ': ' + msg;
+ };
+ // can't use defineProperties here because of toString enumeration issue in IE <= 8
+ Error.prototype.toString = errorToStringShim;
+}
+
+if (supportsDescriptors) {
+ var ensureNonEnumerable = function (obj, prop) {
+ if (isEnum(obj, prop)) {
+ var desc = Object.getOwnPropertyDescriptor(obj, prop);
+ if (desc.configurable) {
+ desc.enumerable = false;
+ Object.defineProperty(obj, prop, desc);
+ }
+ }
+ };
+ ensureNonEnumerable(Error.prototype, 'message');
+ if (Error.prototype.message !== '') {
+ Error.prototype.message = '';
+ }
+ ensureNonEnumerable(Error.prototype, 'name');
+}
+
+if (String(/a/mig) !== '/a/gim') {
+ var regexToString = function toString() {
+ var str = '/' + this.source + '/';
+ if (this.global) {
+ str += 'g';
+ }
+ if (this.ignoreCase) {
+ str += 'i';
+ }
+ if (this.multiline) {
+ str += 'm';
+ }
+ return str;
+ };
+ // can't use defineProperties here because of toString enumeration issue in IE <= 8
+ RegExp.prototype.toString = regexToString;
+}
+
}));
"ooui-dialog-process-continue": "Jarraitu",
"ooui-selectfile-button-select": "Fitxategi bat aukeratu",
"ooui-selectfile-not-supported": "Fitxategi aukeraketa ez da onartzen",
- "ooui-selectfile-placeholder": "Ez da fitxategirik hautatu"
+ "ooui-selectfile-placeholder": "Ez da fitxategirik hautatu",
+ "ooui-selectfile-dragdrop-placeholder": "Fitxategia hemen utzi"
}
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "The Discoverer"
+ ]
+ },
+ "ooui-toolbar-more": "Anik",
+ "ooui-toolgroup-expand": "Anik",
+ "ooui-dialog-message-reject": "Rodd'dd kor",
+ "ooui-dialog-process-retry": "Porot proyotn kor",
+ "ooui-selectfile-button-select": "Ek fayl nivodd",
+ "ooui-selectfile-placeholder": "Khuimchech fayl nivddunk nam",
+ "ooui-selectfile-dragdrop-placeholder": "Fayl hanga udoi"
+}
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Marwan Mohamad"
+ ]
+ },
+ "ooui-outline-control-move-down": "Heyiya botu ode tibawa",
+ "ooui-outline-control-move-up": "Heyiya botu ode yitaato",
+ "ooui-outline-control-remove": "Yinggila botu",
+ "ooui-toolbar-more": "Pe'eentapo",
+ "ooui-toolgroup-expand": "Pe'eentapo",
+ "ooui-toolgroup-collapse": "ngoolo botu",
+ "ooui-dialog-message-accept": "Jo",
+ "ooui-dialog-message-reject": "Bataliya",
+ "ooui-dialog-process-error": "Woluwo u yilotalawa",
+ "ooui-dialog-process-dismiss": "He'uti",
+ "ooui-dialog-process-retry": "Yimontali pooli",
+ "ooui-dialog-process-continue": "Turusi",
+ "ooui-selectfile-button-select": "Tulawota berkas tuwawu",
+ "ooui-selectfile-not-supported": "Berkas tilulawoto ja motuhatawa",
+ "ooui-selectfile-placeholder": "Diya'a berkas u letulawoto",
+ "ooui-selectfile-dragdrop-placeholder": "Dutuwa berkas teeya"
+}
"ooui-dialog-process-dismiss": "Zatvori",
"ooui-dialog-process-retry": "Pokušajte ponovo",
"ooui-selectfile-button-select": "Odaberi datoteku",
- "ooui-selectfile-placeholder": "Datoteka nije označena"
+ "ooui-selectfile-placeholder": "Datoteka nije označena",
+ "ooui-selectfile-dragdrop-placeholder": "Povucite datoteku ovdje"
}
},
"ooui-outline-control-move-down": "Pārvietot vienumu uz leju",
"ooui-outline-control-move-up": "Pārvietot vienumu uz augšu",
+ "ooui-outline-control-remove": "Noņemt vienumu",
"ooui-toolbar-more": "Vairāk",
"ooui-toolgroup-expand": "Vairāk",
"ooui-toolgroup-collapse": "Mazāk",
"ooui-dialog-message-accept": "Labi",
"ooui-dialog-message-reject": "Atcelt",
"ooui-dialog-process-error": "Kaut kas nogāja greizi",
+ "ooui-dialog-process-dismiss": "Paslēpt",
"ooui-dialog-process-retry": "Mēģināt vēlreiz",
- "ooui-dialog-process-continue": "Turpināt"
+ "ooui-dialog-process-continue": "Turpināt",
+ "ooui-selectfile-button-select": "Izvēlies failu",
+ "ooui-selectfile-not-supported": "Failu izvēle nav atbalstīta",
+ "ooui-selectfile-placeholder": "Nav izvēlēts neviens fails",
+ "ooui-selectfile-dragdrop-placeholder": "Nomet failu šeit"
}
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:02Z
+ * Date: 2016-05-31T21:50:52Z
*/
( function ( OO ) {
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:06Z
+ * Date: 2016-05-31T21:50:56Z
*/
.oo-ui-element-hidden {
display: none !important;
display: inline-block;
vertical-align: middle;
font: inherit;
+ line-height: normal;
white-space: nowrap;
-webkit-touch-callout: none;
-webkit-user-select: none;
vertical-align: middle;
}
.oo-ui-buttonElement-frameless {
- display: inline-block;
position: relative;
}
.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
vertical-align: top;
text-align: center;
}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- cursor: default;
-}
.oo-ui-buttonElement > .oo-ui-buttonElement-button {
color: #333333;
}
.oo-ui-buttonElement-framed.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
.oo-ui-buttonElement-framed.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
- color: black;
+ color: #000000;
border-color: #c9c9c9;
background-color: #eeeeee;
background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0, #dddddd), color-stop(100%, #ffffff));
position: relative;
margin: 0;
padding: 0;
- border: none;
+ border: 0;
}
.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
display: block;
position: relative;
display: block;
padding: 0.25em 0.5em;
- border: none;
+ border: 0;
}
.oo-ui-optionWidget.oo-ui-widget-enabled {
cursor: pointer;
padding: 0;
background-color: transparent;
}
+.oo-ui-checkboxMultiselectInputWidget .oo-ui-fieldLayout {
+ margin-bottom: 0;
+}
.oo-ui-dropdownInputWidget {
position: relative;
vertical-align: middle;
display: none;
}
.oo-ui-textInputWidget [type="search"]::-webkit-search-decoration,
-.oo-ui-textInputWidget [type="search"]::-webkit-search-cancel-button,
-.oo-ui-textInputWidget [type="search"]::-webkit-search-results-button,
-.oo-ui-textInputWidget [type="search"]::-webkit-search-results-decoration {
+.oo-ui-textInputWidget [type="search"]::-webkit-search-cancel-button {
display: none;
}
.oo-ui-textInputWidget > .oo-ui-iconElement-icon,
font-size: inherit;
font-family: inherit;
background-color: #ffffff;
- color: black;
+ color: #000000;
border: 1px solid #cccccc;
- box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #dddddd;
+ box-shadow: 0 0 0 #ffffff, inset 0 0.1em 0.2em #dddddd;
border-radius: 0.25em;
-webkit-transition: border-color 250ms ease, box-shadow 250ms ease;
-moz-transition: border-color 250ms ease, box-shadow 250ms ease;
.oo-ui-textInputWidget.oo-ui-widget-enabled textarea:focus {
outline: none;
border-color: #a7dcff;
- box-shadow: 0 0 0.3em #a7dcff, 0 0 0 white;
+ box-shadow: 0 0 0.3em #a7dcff, 0 0 0 #ffffff;
}
.oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly],
.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly] {
border-color: rgba(0, 0, 0, 0.2);
}
.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator {
+ top: 0;
right: 0;
+ margin: 0.775em;
}
.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
+ top: 0;
left: 0.25em;
+ margin: 0.3em;
}
.oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
line-height: 2.5em;
margin: 0 0.5em;
}
-.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator {
- top: 0;
- margin: 0.775em;
-}
-.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
- top: 0;
- margin: 0.3em;
-}
.oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-dropdownWidget-handle {
color: #cccccc;
text-shadow: 0 1px 1px #ffffff;
cursor: default;
opacity: 0.2;
}
+.oo-ui-multioptionWidget {
+ position: relative;
+ display: block;
+}
+.oo-ui-multioptionWidget.oo-ui-widget-enabled {
+ cursor: pointer;
+}
+.oo-ui-multioptionWidget.oo-ui-widget-disabled {
+ cursor: default;
+}
+.oo-ui-multioptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: block;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+.oo-ui-multioptionWidget .oo-ui-labelElement-label {
+ line-height: 1.5em;
+}
+.oo-ui-multioptionWidget.oo-ui-widget-disabled {
+ color: #cccccc;
+}
+.oo-ui-checkboxMultioptionWidget {
+ cursor: default;
+ padding: 0;
+}
+.oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget,
+.oo-ui-checkboxMultioptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-checkboxMultioptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ padding-left: 0.5em;
+}
+.oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget {
+ margin-right: 0;
+}
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:06Z
+ * Date: 2016-05-31T21:50:56Z
*/
.oo-ui-element-hidden {
display: none !important;
display: inline-block;
vertical-align: middle;
font: inherit;
+ line-height: normal;
white-space: nowrap;
-webkit-touch-callout: none;
-webkit-user-select: none;
vertical-align: middle;
}
.oo-ui-buttonElement-frameless {
- display: inline-block;
position: relative;
}
.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
vertical-align: top;
text-align: center;
}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- cursor: default;
-}
.oo-ui-buttonElement > .oo-ui-buttonElement-button {
font-weight: bold;
text-decoration: none;
.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
margin-left: 0.46875em;
}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:focus {
- box-shadow: inset 0 0 0 1px #347bff, 0 0 0 1px #347bff;
-}
.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button .oo-ui-indicatorElement-indicator {
margin-right: 0;
}
padding-right: 0.25em;
color: #333333;
}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #347bff, 0 0 0 1px #347bff;
+}
.oo-ui-buttonElement-frameless.oo-ui-widget-enabled > input.oo-ui-buttonElement-button,
.oo-ui-buttonElement-frameless.oo-ui-widget-enabled > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
color: #555555;
.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
color: #cccccc;
}
-.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button:focus {
- box-shadow: none;
-}
.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon,
.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
opacity: 0.2;
color: #ffffff;
border: 1px solid #dddddd;
}
+.oo-ui-buttonElement-framed.oo-ui-widget-disabled + .oo-ui-widget-disabled > .oo-ui-buttonElement-button {
+ border-left-color: #ffffff;
+}
.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
color: #555555;
background-color: #ffffff;
background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-invert.svg");
background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check-invert.png");
}
+.oo-ui-checkboxMultiselectInputWidget .oo-ui-fieldLayout {
+ margin-bottom: 0;
+}
+.oo-ui-checkboxMultiselectInputWidget .oo-ui-fieldLayout .oo-ui-fieldLayout-body {
+ padding: 0.25em 0;
+}
+.oo-ui-checkboxMultiselectInputWidget .oo-ui-fieldLayout .oo-ui-fieldLayout-body .oo-ui-labelElement-label {
+ line-height: 1.5em;
+}
.oo-ui-dropdownInputWidget {
position: relative;
vertical-align: middle;
display: none;
}
.oo-ui-textInputWidget [type="search"]::-webkit-search-decoration,
-.oo-ui-textInputWidget [type="search"]::-webkit-search-cancel-button,
-.oo-ui-textInputWidget [type="search"]::-webkit-search-results-button,
-.oo-ui-textInputWidget [type="search"]::-webkit-search-results-decoration {
+.oo-ui-textInputWidget [type="search"]::-webkit-search-cancel-button {
display: none;
}
.oo-ui-textInputWidget > .oo-ui-iconElement-icon,
.oo-ui-textInputWidget.oo-ui-widget-enabled textarea:focus {
outline: 0;
border-color: #347bff;
- box-shadow: inset 0 0 0 0.1em #347bff;
+ box-shadow: inset 0 0 0 1px #347bff;
}
.oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly],
.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly] {
border-radius: 2px;
}
.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator {
+ top: 0;
right: 0;
+ margin: 0.775em;
}
.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
+ top: 0;
left: 0.25em;
+ margin: 0.3em;
}
.oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
margin: 0 1em;
}
-.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator {
- top: 0;
- margin: 0.775em;
-}
-.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
- top: 0;
- margin: 0.3em;
-}
.oo-ui-dropdownWidget:hover .oo-ui-dropdownWidget-handle {
border-color: #aaaaaa;
}
.oo-ui-comboBoxInputWidget textarea {
height: 2.35em;
}
+.oo-ui-multioptionWidget {
+ position: relative;
+ display: block;
+}
+.oo-ui-multioptionWidget.oo-ui-widget-enabled {
+ cursor: pointer;
+}
+.oo-ui-multioptionWidget.oo-ui-widget-disabled {
+ cursor: default;
+}
+.oo-ui-multioptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: block;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+.oo-ui-multioptionWidget .oo-ui-labelElement-label {
+ line-height: 1.5em;
+}
+.oo-ui-multioptionWidget.oo-ui-widget-disabled {
+ color: #cccccc;
+}
+.oo-ui-checkboxMultioptionWidget {
+ cursor: default;
+ padding: 0.25em 0;
+}
+.oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget,
+.oo-ui-checkboxMultioptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-checkboxMultioptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ padding: 0.25em 0.25em 0.25em 1em;
+}
+.oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget {
+ margin-right: 0;
+}
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:02Z
+ * Date: 2016-05-31T21:50:52Z
*/
( function ( OO ) {
/**
* Set the button's active state.
*
- * The active state occurs when a {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} or
- * a {@link OO.ui.ToggleButtonWidget ToggleButtonWidget} is pressed. This method does nothing
- * for other button types.
+ * The active state can be set on:
*
+ * - {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} when it is selected
+ * - {@link OO.ui.ToggleButtonWidget ToggleButtonWidget} when it is toggle on
+ * - {@link OO.ui.ButtonWidget ButtonWidget} when clicking the button would only refresh the page
+ *
+ * @protected
* @param {boolean} value Make button active
* @chainable
*/
/**
* Check if the button is active
*
+ * @protected
* @return {boolean} The button is active
*/
OO.ui.mixin.ButtonElement.prototype.isActive = function () {
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {boolean} [active=false] Whether button should be shown as active
* @cfg {string} [href] Hyperlink to visit when the button is clicked.
* @cfg {string} [target] The frame or window in which to open the hyperlink.
* @cfg {boolean} [noFollow] Search engine traversal hint (default: true)
this.$element
.addClass( 'oo-ui-buttonWidget' )
.append( this.$button );
+ this.setActive( config.active );
this.setHref( config.href );
this.setTarget( config.target );
this.setNoFollow( config.noFollow );
return this;
};
+// Override method visibility hints from ButtonElement
+/**
+ * @method setActive
+ */
+/**
+ * @method isActive
+ */
+
/**
* A ButtonGroupWidget groups related buttons and is used together with OO.ui.ButtonWidget and
* its subclasses. Each button in a group is addressed by a unique reference. Buttons can be added,
* @private
* @abstract
* @class
- * @extends OO.ui.mixin.GroupElement
+ * @mixins OO.ui.mixin.GroupElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
OO.ui.mixin.GroupWidget = function OoUiMixinGroupWidget( config ) {
- // Parent constructor
- OO.ui.mixin.GroupWidget.parent.call( this, config );
+ // Mixin constructors
+ OO.ui.mixin.GroupElement.call( this, config );
};
/* Setup */
-OO.inheritClass( OO.ui.mixin.GroupWidget, OO.ui.mixin.GroupElement );
+OO.mixinClass( OO.ui.mixin.GroupWidget, OO.ui.mixin.GroupElement );
/* Methods */
*
* @class
* @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.ItemWidget
* @mixins OO.ui.mixin.LabelElement
* @mixins OO.ui.mixin.FlaggedElement
+ * @mixins OO.ui.mixin.AccessKeyedElement
*
* @constructor
* @param {Object} [config] Configuration options
OO.ui.mixin.ItemWidget.call( this );
OO.ui.mixin.LabelElement.call( this, config );
OO.ui.mixin.FlaggedElement.call( this, config );
+ OO.ui.mixin.AccessKeyedElement.call( this, config );
// Properties
this.selected = false;
// Initialization
this.$element
.data( 'oo-ui-optionWidget', this )
+ // Allow programmatic focussing (and by accesskey), but not tabbing
+ .attr( 'tabindex', '-1' )
.attr( 'role', 'option' )
.attr( 'aria-selected', 'false' )
.addClass( 'oo-ui-optionWidget' )
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.ItemWidget );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.LabelElement );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.FlaggedElement );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.AccessKeyedElement );
/* Static Properties */
toggle: 'onToggle'
} );
this.$element.on( {
- focus: this.onFocus.bind( this ),
+ focusin: this.onFocus.bind( this ),
mousedown: this.onMouseDown.bind( this ),
mouseover: this.onMouseOver.bind( this ),
mouseleave: this.onMouseLeave.bind( this )
/* Setup */
OO.inheritClass( OO.ui.SelectWidget, OO.ui.Widget );
-
-// Need to mixin base class as well
-OO.mixinClass( OO.ui.SelectWidget, OO.ui.mixin.GroupElement );
OO.mixinClass( OO.ui.SelectWidget, OO.ui.mixin.GroupWidget );
-/* Static */
-OO.ui.SelectWidget.static.passAllFilter = function () {
- return true;
-};
-
/* Events */
/**
* @private
* @param {jQuery.Event} event
*/
-OO.ui.SelectWidget.prototype.onFocus = function () {
- // The styles for focus state depend on one of the items being selected.
- if ( !this.getSelectedItem() ) {
- this.selectItem( this.getFirstSelectableItem() );
+OO.ui.SelectWidget.prototype.onFocus = function ( event ) {
+ var item;
+ if ( event.target === this.$element[ 0 ] ) {
+ // This widget was focussed, e.g. by the user tabbing to it.
+ // The styles for focus state depend on one of the items being selected.
+ if ( !this.getSelectedItem() ) {
+ item = this.getFirstSelectableItem();
+ }
+ } else {
+ // One of the options got focussed (and the event bubbled up here).
+ // They can't be tabbed to, but they can be activated using accesskeys.
+ item = this.getTargetItem( event );
+ }
+
+ if ( item ) {
+ if ( item.constructor.static.highlightable ) {
+ this.highlightItem( item );
+ } else {
+ this.selectItem( item );
+ }
+ }
+
+ if ( event.target !== this.$element[ 0 ] ) {
+ this.$element.focus();
}
};
item = this.getRelativeSelectableItem( item, 1, filter );
}
if ( item ) {
- if ( item.constructor.static.highlightable ) {
+ if ( this.isVisible() && item.constructor.static.highlightable ) {
this.highlightItem( item );
} else {
this.chooseItem( item );
*
* @param {OO.ui.OptionWidget|null} item Item to describe the start position, or `null` to start at the beginning of the array.
* @param {number} direction Direction to move in: -1 to move backward, 1 to move forward
- * @param {Function} filter Only consider items for which this function returns
+ * @param {Function} [filter] Only consider items for which this function returns
* true. Function takes an OO.ui.OptionWidget and returns a boolean.
* @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the select
*/
increase = direction > 0 ? 1 : -1,
len = this.items.length;
- if ( !$.isFunction( filter ) ) {
- filter = OO.ui.SelectWidget.static.passAllFilter;
- }
-
if ( item instanceof OO.ui.OptionWidget ) {
currentIndex = this.items.indexOf( item );
nextIndex = ( currentIndex + increase + len ) % len;
for ( i = 0; i < len; i++ ) {
item = this.items[ nextIndex ];
- if ( item instanceof OO.ui.OptionWidget && item.isSelectable() && filter( item ) ) {
+ if (
+ item instanceof OO.ui.OptionWidget && item.isSelectable() &&
+ ( !filter || filter( item ) )
+ ) {
return item;
}
nextIndex = ( nextIndex + increase + len ) % len;
* @return {OO.ui.OptionWidget|null} Item, `null` if there aren't any selectable items
*/
OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
- var i, len, item;
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[ i ];
- if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
- return item;
- }
- }
-
- return null;
+ return this.getRelativeSelectableItem( null, 1 );
};
/**
* the text the user types. This config is used by {@link OO.ui.ComboBoxInputWidget ComboBoxInputWidget}
* and {@link OO.ui.mixin.LookupElement LookupElement}
* @cfg {jQuery} [$input] Text input used to implement option highlighting for menu items that match
- * the text the user types. This config is used by {@link OO.ui.CapsuleMultiSelectWidget CapsuleMultiSelectWidget}
+ * the text the user types. This config is used by {@link OO.ui.CapsuleMultiselectWidget CapsuleMultiselectWidget}
* @cfg {OO.ui.Widget} [widget] Widget associated with the menu's active state. If the user clicks the mouse
* anywhere on the page outside of this widget, the menu is hidden. For example, if there is a button
* that toggles the menu's visibility on click, the menu will be hidden then re-shown when the user clicks
// Events
this.$handle.on( {
click: this.onClick.bind( this ),
- keydown: this.onKeyDown.bind( this )
+ keydown: this.onKeyDown.bind( this ),
+ // Hack? Handle type-to-search when menu is not expanded and not handling its own events
+ keypress: this.menu.onKeyPressHandler,
+ blur: this.menu.clearKeyPressBuffer.bind( this.menu )
} );
this.menu.connect( this, { select: 'onMenuSelect' } );
// Parent constructor
OO.ui.RadioOptionWidget.parent.call( this, config );
- // Events
- this.radio.$input.on( 'focus', this.onInputFocus.bind( this ) );
-
// Initialization
// Remove implicit role, we're handling it ourselves
this.radio.$input.attr( 'role', 'presentation' );
/* Methods */
-/**
- * @param {jQuery.Event} e Focus event
- * @private
- */
-OO.ui.RadioOptionWidget.prototype.onInputFocus = function () {
- this.radio.$input.blur();
- this.$element.parent().focus();
-};
-
/**
* @inheritdoc
*/
OO.inheritClass( OO.ui.RadioSelectWidget, OO.ui.SelectWidget );
OO.mixinClass( OO.ui.RadioSelectWidget, OO.ui.mixin.TabIndexedElement );
+/**
+ * MultioptionWidgets are special elements that can be selected and configured with data. The
+ * data is often unique for each option, but it does not have to be. MultioptionWidgets are used
+ * with OO.ui.SelectWidget to create a selection of mutually exclusive options. For more information
+ * and examples, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Multioptions
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.ItemWidget
+ * @mixins OO.ui.mixin.LabelElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [selected=false] Whether the option is initially selected
+ */
+OO.ui.MultioptionWidget = function OoUiMultioptionWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.MultioptionWidget.parent.call( this, config );
+
+ // Mixin constructors
+ OO.ui.mixin.ItemWidget.call( this );
+ OO.ui.mixin.LabelElement.call( this, config );
+
+ // Properties
+ this.selected = null;
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-multioptionWidget' )
+ .append( this.$label );
+ this.setSelected( config.selected );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.MultioptionWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.MultioptionWidget, OO.ui.mixin.ItemWidget );
+OO.mixinClass( OO.ui.MultioptionWidget, OO.ui.mixin.LabelElement );
+
+/* Events */
+
+/**
+ * @event change
+ *
+ * A change event is emitted when the selected state of the option changes.
+ *
+ * @param {boolean} selected Whether the option is now selected
+ */
+
+/* Methods */
+
+/**
+ * Check if the option is selected.
+ *
+ * @return {boolean} Item is selected
+ */
+OO.ui.MultioptionWidget.prototype.isSelected = function () {
+ return this.selected;
+};
+
+/**
+ * Set the option’s selected state. In general, all modifications to the selection
+ * should be handled by the SelectWidget’s {@link OO.ui.SelectWidget#selectItem selectItem( [item] )}
+ * method instead of this method.
+ *
+ * @param {boolean} [state=false] Select option
+ * @chainable
+ */
+OO.ui.MultioptionWidget.prototype.setSelected = function ( state ) {
+ state = !!state;
+ if ( this.selected !== state ) {
+ this.selected = state;
+ this.emit( 'change', state );
+ this.$element.toggleClass( 'oo-ui-multioptionWidget-selected', state );
+ }
+ return this;
+};
+
+/**
+ * MultiselectWidget allows selecting multiple options from a list.
+ *
+ * For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.GroupWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {OO.ui.MultioptionWidget[]} [items] An array of options to add to the multiselect.
+ */
+OO.ui.MultiselectWidget = function OoUiMultiselectWidget( config ) {
+ // Parent constructor
+ OO.ui.MultiselectWidget.parent.call( this, config );
+
+ // Configuration initialization
+ config = config || {};
+
+ // Mixin constructors
+ OO.ui.mixin.GroupWidget.call( this, config );
+
+ // Events
+ this.aggregate( { change: 'select' } );
+ // This is mostly for compatibility with CapsuleMultiselectWidget... normally, 'change' is emitted
+ // by GroupElement only when items are added/removed
+ this.connect( this, { select: [ 'emit', 'change' ] } );
+
+ // Initialization
+ if ( config.items ) {
+ this.addItems( config.items );
+ }
+ this.$group.addClass( 'oo-ui-multiselectWidget-group' );
+ this.$element.addClass( 'oo-ui-multiselectWidget' )
+ .append( this.$group );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.MultiselectWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.MultiselectWidget, OO.ui.mixin.GroupWidget );
+
+/* Events */
+
+/**
+ * @event change
+ *
+ * A change event is emitted when the set of items changes, or an item is selected or deselected.
+ */
+
+/**
+ * @event select
+ *
+ * A select event is emitted when an item is selected or deselected.
+ */
+
+/* Methods */
+
+/**
+ * Get options that are selected.
+ *
+ * @return {OO.ui.MultioptionWidget[]} Selected options
+ */
+OO.ui.MultiselectWidget.prototype.getSelectedItems = function () {
+ return this.items.filter( function ( item ) {
+ return item.isSelected();
+ } );
+};
+
+/**
+ * Get the data of options that are selected.
+ *
+ * @return {Object[]|string[]} Values of selected options
+ */
+OO.ui.MultiselectWidget.prototype.getSelectedItemsData = function () {
+ return this.getSelectedItems().map( function ( item ) {
+ return item.data;
+ } );
+};
+
+/**
+ * Select options by reference. Options not mentioned in the `items` array will be deselected.
+ *
+ * @param {OO.ui.MultioptionWidget[]} items Items to select
+ * @chainable
+ */
+OO.ui.MultiselectWidget.prototype.selectItems = function ( items ) {
+ this.items.forEach( function ( item ) {
+ var selected = items.indexOf( item ) !== -1;
+ item.setSelected( selected );
+ } );
+ return this;
+};
+
+/**
+ * Select items by their data. Options not mentioned in the `datas` array will be deselected.
+ *
+ * @param {Object[]|string[]} datas Values of items to select
+ * @chainable
+ */
+OO.ui.MultiselectWidget.prototype.selectItemsByData = function ( datas ) {
+ var items,
+ widget = this;
+ items = datas.map( function ( data ) {
+ return widget.getItemFromData( data );
+ } );
+ this.selectItems( items );
+ return this;
+};
+
+/**
+ * CheckboxMultioptionWidget is an option widget that looks like a checkbox.
+ * The class is used with OO.ui.CheckboxMultiselectWidget to create a selection of checkbox options.
+ * Please see the [OOjs UI documentation on MediaWiki] [1] for more information.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Button_selects_and_option
+ *
+ * @class
+ * @extends OO.ui.MultioptionWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.CheckboxMultioptionWidget = function OoUiCheckboxMultioptionWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Properties (must be done before parent constructor which calls #setDisabled)
+ this.checkbox = new OO.ui.CheckboxInputWidget();
+
+ // Parent constructor
+ OO.ui.CheckboxMultioptionWidget.parent.call( this, config );
+
+ // Events
+ this.checkbox.on( 'change', this.onCheckboxChange.bind( this ) );
+ this.$element.on( 'keydown', this.onKeyDown.bind( this ) );
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-checkboxMultioptionWidget' )
+ .prepend( this.checkbox.$element );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.CheckboxMultioptionWidget, OO.ui.MultioptionWidget );
+
+/* Static Properties */
+
+OO.ui.CheckboxMultioptionWidget.static.tagName = 'label';
+
+/* Methods */
+
+/**
+ * Handle checkbox selected state change.
+ *
+ * @private
+ */
+OO.ui.CheckboxMultioptionWidget.prototype.onCheckboxChange = function () {
+ this.setSelected( this.checkbox.isSelected() );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxMultioptionWidget.prototype.setSelected = function ( state ) {
+ OO.ui.CheckboxMultioptionWidget.parent.prototype.setSelected.call( this, state );
+ this.checkbox.setSelected( state );
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxMultioptionWidget.prototype.setDisabled = function ( disabled ) {
+ OO.ui.CheckboxMultioptionWidget.parent.prototype.setDisabled.call( this, disabled );
+ this.checkbox.setDisabled( this.isDisabled() );
+ return this;
+};
+
+/**
+ * Focus the widget.
+ */
+OO.ui.CheckboxMultioptionWidget.prototype.focus = function () {
+ this.checkbox.focus();
+};
+
+/**
+ * Handle key down events.
+ *
+ * @protected
+ * @param {jQuery.Event} e
+ */
+OO.ui.CheckboxMultioptionWidget.prototype.onKeyDown = function ( e ) {
+ var
+ element = this.getElementGroup(),
+ nextItem;
+
+ if ( e.keyCode === OO.ui.Keys.LEFT || e.keyCode === OO.ui.Keys.UP ) {
+ nextItem = element.getRelativeFocusableItem( this, -1 );
+ } else if ( e.keyCode === OO.ui.Keys.RIGHT || e.keyCode === OO.ui.Keys.DOWN ) {
+ nextItem = element.getRelativeFocusableItem( this, 1 );
+ }
+
+ if ( nextItem ) {
+ e.preventDefault();
+ nextItem.focus();
+ }
+};
+
+/**
+ * CheckboxMultiselectWidget is a {@link OO.ui.MultiselectWidget multiselect widget} that contains
+ * checkboxes and is used together with OO.ui.CheckboxMultioptionWidget. The
+ * CheckboxMultiselectWidget provides an interface for adding, removing and selecting options.
+ * Please see the [OOjs UI documentation on MediaWiki][1] for more information.
+ *
+ * If you want to use this within a HTML form, such as a OO.ui.FormLayout, use
+ * OO.ui.CheckboxMultiselectInputWidget instead.
+ *
+ * @example
+ * // A CheckboxMultiselectWidget with CheckboxMultioptions.
+ * var option1 = new OO.ui.CheckboxMultioptionWidget( {
+ * data: 'a',
+ * selected: true,
+ * label: 'Selected checkbox'
+ * } );
+ *
+ * var option2 = new OO.ui.CheckboxMultioptionWidget( {
+ * data: 'b',
+ * label: 'Unselected checkbox'
+ * } );
+ *
+ * var multiselect=new OO.ui.CheckboxMultiselectWidget( {
+ * items: [ option1, option2 ]
+ * } );
+ *
+ * $( 'body' ).append( multiselect.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
+ *
+ * @class
+ * @extends OO.ui.MultiselectWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.CheckboxMultiselectWidget = function OoUiCheckboxMultiselectWidget( config ) {
+ // Parent constructor
+ OO.ui.CheckboxMultiselectWidget.parent.call( this, config );
+
+ // Properties
+ this.$lastClicked = null;
+
+ // Events
+ this.$group.on( 'click', this.onClick.bind( this ) );
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-checkboxMultiselectWidget' );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.CheckboxMultiselectWidget, OO.ui.MultiselectWidget );
+
+/* Methods */
+
+/**
+ * Get an option by its position relative to the specified item (or to the start of the option array,
+ * if item is `null`). The direction in which to search through the option array is specified with a
+ * number: -1 for reverse (the default) or 1 for forward. The method will return an option, or
+ * `null` if there are no options in the array.
+ *
+ * @param {OO.ui.CheckboxMultioptionWidget|null} item Item to describe the start position, or `null` to start at the beginning of the array.
+ * @param {number} direction Direction to move in: -1 to move backward, 1 to move forward
+ * @return {OO.ui.CheckboxMultioptionWidget|null} Item at position, `null` if there are no items in the select
+ */
+OO.ui.CheckboxMultiselectWidget.prototype.getRelativeFocusableItem = function ( item, direction ) {
+ var currentIndex, nextIndex, i,
+ increase = direction > 0 ? 1 : -1,
+ len = this.items.length;
+
+ if ( item ) {
+ currentIndex = this.items.indexOf( item );
+ nextIndex = ( currentIndex + increase + len ) % len;
+ } else {
+ // If no item is selected and moving forward, start at the beginning.
+ // If moving backward, start at the end.
+ nextIndex = direction > 0 ? 0 : len - 1;
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ item = this.items[ nextIndex ];
+ if ( item && !item.isDisabled() ) {
+ return item;
+ }
+ nextIndex = ( nextIndex + increase + len ) % len;
+ }
+ return null;
+};
+
+/**
+ * Handle click events on checkboxes.
+ *
+ * @param {jQuery.Event} e
+ */
+OO.ui.CheckboxMultiselectWidget.prototype.onClick = function ( e ) {
+ var $options, checked,
+ $lastClicked = this.$lastClicked,
+ $nowClicked = $( e.target ).closest( '.oo-ui-checkboxMultioptionWidget' )
+ .not( '.oo-ui-widget-disabled' );
+
+ // Allow selecting multiple options at once by Shift-clicking them
+ if ( $lastClicked && $nowClicked.length && e.shiftKey ) {
+ $options = this.$group.find( '.oo-ui-checkboxMultioptionWidget' );
+ checked = $nowClicked.find( 'input' ).prop( 'checked' );
+
+ $options
+ .slice(
+ Math.min( $options.index( $lastClicked ), $options.index( $nowClicked ) ),
+ Math.max( $options.index( $lastClicked ), $options.index( $nowClicked ) ) + 1
+ )
+ .find( 'input' )
+ .filter( function () {
+ return !this.disabled;
+ } )
+ .prop( 'checked', checked )
+ .trigger( 'change' );
+ }
+
+ if ( $nowClicked.length ) {
+ this.$lastClicked = $nowClicked;
+ }
+};
+
/**
* Element that will stick under a specified container, even when it is inserted elsewhere in the
* document (for example, in a OO.ui.Window's $overlay).
return this;
};
+/**
+ * CheckboxMultiselectInputWidget is a
+ * {@link OO.ui.CheckboxMultiselectWidget CheckboxMultiselectWidget} intended to be used within a
+ * HTML form, such as a OO.ui.FormLayout. The selected values are synchronized with the value of
+ * HTML `<input type=checkbox>` tags. Please see the [OOjs UI documentation on MediaWiki][1] for
+ * more information about input widgets.
+ *
+ * @example
+ * // Example: A CheckboxMultiselectInputWidget with three options
+ * var multiselectInput = new OO.ui.CheckboxMultiselectInputWidget( {
+ * options: [
+ * { data: 'a', label: 'First' },
+ * { data: 'b', label: 'Second'},
+ * { data: 'c', label: 'Third' }
+ * ]
+ * } );
+ * $( 'body' ).append( multiselectInput.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
+ *
+ * @class
+ * @extends OO.ui.InputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`
+ */
+OO.ui.CheckboxMultiselectInputWidget = function OoUiCheckboxMultiselectInputWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Properties (must be done before parent constructor which calls #setDisabled)
+ this.checkboxMultiselectWidget = new OO.ui.CheckboxMultiselectWidget();
+
+ // Parent constructor
+ OO.ui.CheckboxMultiselectInputWidget.parent.call( this, config );
+
+ // Properties
+ this.inputName = config.name;
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-checkboxMultiselectInputWidget' )
+ .append( this.checkboxMultiselectWidget.$element );
+ // We don't use this.$input, but rather the CheckboxInputWidgets inside each option
+ this.$input.detach();
+ this.setOptions( config.options || [] );
+ // Have to repeat this from parent, as we need options to be set up for this to make sense
+ this.setValue( config.value );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.CheckboxMultiselectInputWidget, OO.ui.InputWidget );
+
+/* Static Properties */
+
+OO.ui.CheckboxMultiselectInputWidget.static.supportsSimpleLabel = false;
+
+/* Static Methods */
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxMultiselectInputWidget.static.gatherPreInfuseState = function ( node, config ) {
+ var state = OO.ui.CheckboxMultiselectInputWidget.parent.static.gatherPreInfuseState( node, config );
+ state.value = $( node ).find( '.oo-ui-checkboxInputWidget .oo-ui-inputWidget-input:checked' )
+ .toArray().map( function ( el ) { return el.value; } );
+ return state;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxMultiselectInputWidget.static.reusePreInfuseDOM = function ( node, config ) {
+ config = OO.ui.CheckboxMultiselectInputWidget.parent.static.reusePreInfuseDOM( node, config );
+ // Cannot reuse the `<input type=checkbox>` set
+ delete config.$input;
+ return config;
+};
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ * @protected
+ */
+OO.ui.CheckboxMultiselectInputWidget.prototype.getInputElement = function () {
+ // Actually unused
+ return $( '<div>' );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxMultiselectInputWidget.prototype.getValue = function () {
+ var value = this.$element.find( '.oo-ui-checkboxInputWidget .oo-ui-inputWidget-input:checked' )
+ .toArray().map( function ( el ) { return el.value; } );
+ if ( this.value !== value ) {
+ this.setValue( value );
+ }
+ return this.value;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxMultiselectInputWidget.prototype.setValue = function ( value ) {
+ value = this.cleanUpValue( value );
+ this.checkboxMultiselectWidget.selectItemsByData( value );
+ OO.ui.CheckboxMultiselectInputWidget.parent.prototype.setValue.call( this, value );
+ return this;
+};
+
+/**
+ * Clean up incoming value.
+ *
+ * @param {string[]} value Original value
+ * @return {string[]} Cleaned up value
+ */
+OO.ui.CheckboxMultiselectInputWidget.prototype.cleanUpValue = function ( value ) {
+ var i, singleValue,
+ cleanValue = [];
+ if ( !Array.isArray( value ) ) {
+ return cleanValue;
+ }
+ for ( i = 0; i < value.length; i++ ) {
+ singleValue =
+ OO.ui.CheckboxMultiselectInputWidget.parent.prototype.cleanUpValue.call( this, value[ i ] );
+ // Remove options that we don't have here
+ if ( !this.checkboxMultiselectWidget.getItemFromData( singleValue ) ) {
+ continue;
+ }
+ cleanValue.push( singleValue );
+ }
+ return cleanValue;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxMultiselectInputWidget.prototype.setDisabled = function ( state ) {
+ this.checkboxMultiselectWidget.setDisabled( state );
+ OO.ui.CheckboxMultiselectInputWidget.parent.prototype.setDisabled.call( this, state );
+ return this;
+};
+
+/**
+ * Set the options available for this input.
+ *
+ * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`
+ * @chainable
+ */
+OO.ui.CheckboxMultiselectInputWidget.prototype.setOptions = function ( options ) {
+ var widget = this;
+
+ // Rebuild the checkboxMultiselectWidget menu
+ this.checkboxMultiselectWidget
+ .clearItems()
+ .addItems( options.map( function ( opt ) {
+ var optValue, item;
+ optValue =
+ OO.ui.CheckboxMultiselectInputWidget.parent.prototype.cleanUpValue.call( widget, opt.data );
+ item = new OO.ui.CheckboxMultioptionWidget( {
+ data: optValue,
+ label: opt.label !== undefined ? opt.label : optValue
+ } );
+ // Set the 'name' and 'value' for form submission
+ item.checkbox.$input.attr( 'name', widget.inputName );
+ item.checkbox.setValue( optValue );
+ return item;
+ } ) );
+
+ // Re-set the value, checking the checkboxes as needed.
+ // This will also get rid of any stale options that we just removed.
+ this.setValue( this.getValue() );
+
+ return this;
+};
+
/**
* TextInputWidgets, like HTML text inputs, can be configured with options that customize the
* size of the field as well as its presentation. In addition, these widgets can be configured
*/
OO.ui.TextInputWidget.prototype.getSaneType = function ( config ) {
var allowedTypes = [
- 'text',
- 'password',
- 'search',
- 'email',
- 'url',
- 'date',
- 'number'
- ],
- type = allowedTypes.indexOf( config.type ) !== -1 ? config.type : 'text';
- return config.multiline ? 'multiline' : type;
+ 'text',
+ 'password',
+ 'search',
+ 'email',
+ 'url',
+ 'date',
+ 'number'
+ ];
+ return allowedTypes.indexOf( config.type ) !== -1 ? config.type : 'text';
};
/**
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:02Z
+ * Date: 2016-05-31T21:50:52Z
*/
( function ( OO ) {
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:06Z
+ * Date: 2016-05-31T21:50:56Z
*/
.oo-ui-popupTool .oo-ui-popupWidget-popup,
.oo-ui-popupTool .oo-ui-popupWidget-anchor {
}
.oo-ui-toolGroup .oo-ui-tool-link {
text-decoration: none;
+ cursor: pointer;
+}
+.oo-ui-toolGroup.oo-ui-widget-disabled .oo-ui-tool-link,
+.oo-ui-toolGroup .oo-ui-widget-disabled > .oo-ui-tool-link {
+ outline: 0;
+ cursor: default;
}
.oo-ui-toolbar-narrow .oo-ui-toolGroup + .oo-ui-toolGroup {
margin-left: 0;
.oo-ui-barToolGroup > .oo-ui-labelElement-label {
display: none;
}
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
- cursor: pointer;
-}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool {
display: inline-block;
position: relative;
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-iconElement.oo-ui-tool-with-label > .oo-ui-tool-link .oo-ui-tool-title {
display: inline;
}
-.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link {
- outline: 0;
- cursor: default;
-}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool {
margin: -1px 0 -1px -1px;
border: 1px solid transparent;
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel {
text-align: right;
}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel:not(:empty) {
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel:not( :empty ) {
padding-left: 3em;
}
.oo-ui-toolbar-narrow .oo-ui-popupToolGroup {
top: 2.5em;
margin: 0 -1px;
border: 1px solid #cccccc;
- background-color: white;
+ background-color: #ffffff;
box-shadow: 0 0.3125em 1.25em rgba(0, 0, 0, 0.25);
}
.oo-ui-popupToolGroup .oo-ui-tool-link {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- cursor: pointer;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
padding: 0.3125em;
}
.oo-ui-menuToolGroup .oo-ui-tool {
display: block;
}
-.oo-ui-menuToolGroup .oo-ui-tool-link {
- cursor: pointer;
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
min-width: 10em;
}
-ms-filter: "progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffffff', endColorstr='#fff1f7fb' )";
}
.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
- border: none;
+ border: 0;
background: none;
}
.oo-ui-toolbar-actions > .oo-ui-buttonElement-framed,
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:06Z
+ * Date: 2016-05-31T21:50:56Z
*/
.oo-ui-popupTool .oo-ui-popupWidget-popup,
.oo-ui-popupTool .oo-ui-popupWidget-anchor {
margin: 0;
}
.oo-ui-toolGroupTool > .oo-ui-toolGroup {
- border-right: none;
+ border-right: 0;
}
.oo-ui-toolGroupTool > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle {
height: 2.5em;
}
.oo-ui-toolGroup .oo-ui-tool-link {
text-decoration: none;
+ cursor: pointer;
+}
+.oo-ui-toolGroup.oo-ui-widget-disabled .oo-ui-tool-link,
+.oo-ui-toolGroup .oo-ui-widget-disabled > .oo-ui-tool-link {
+ outline: 0;
+ cursor: default;
}
.oo-ui-toolbar-narrow .oo-ui-toolGroup + .oo-ui-toolGroup {
margin-left: 0;
}
.oo-ui-toolGroup .oo-ui-toolGroup .oo-ui-widget-enabled {
- border-right: none !important;
+ border-right: 0 !important;
}
.oo-ui-barToolGroup > .oo-ui-iconElement-icon,
.oo-ui-barToolGroup > .oo-ui-labelElement-label {
display: none;
}
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
- cursor: pointer;
-}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool {
display: inline-block;
position: relative;
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-iconElement.oo-ui-tool-with-label > .oo-ui-tool-link .oo-ui-tool-title {
display: inline;
}
-.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link {
- outline: 0;
- cursor: default;
-}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
height: 1.875em;
padding: 0.625em;
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel {
text-align: right;
}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel:not(:empty) {
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel:not( :empty ) {
padding-left: 3em;
}
.oo-ui-toolbar-narrow .oo-ui-popupToolGroup {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- cursor: pointer;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
border-color: rgba(0, 0, 0, 0.2);
}
.oo-ui-menuToolGroup .oo-ui-tool {
display: block;
}
-.oo-ui-menuToolGroup .oo-ui-tool-link {
- cursor: pointer;
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
min-width: 10em;
}
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:02Z
+ * Date: 2016-05-31T21:50:52Z
*/
( function ( OO ) {
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:06Z
+ * Date: 2016-05-31T21:50:56Z
*/
.oo-ui-draggableElement-handle,
.oo-ui-draggableElement-handle.oo-ui-widget {
height: 2em;
width: 4em;
border-radius: 1em;
- box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #dddddd;
+ box-shadow: 0 0 0 #ffffff, inset 0 0.1em 0.2em #dddddd;
border: 1px solid #cccccc;
margin-right: 0.5em;
background-color: #eeeeee;
}
.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button > [type="file"] {
position: absolute;
- margin: 0;
top: 0;
bottom: 0;
left: 0;
position: absolute;
right: 0.5em;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel {
- display: block;
-}
.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
display: none;
.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-clearButton {
display: none;
}
+.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
+ display: block;
+}
.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget,
.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
margin-right: 0;
}
.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
- margin-left: 0.5em;
+ border-radius: 0 0.25em 0.25em 0;
}
.oo-ui-selectFileWidget-info {
height: 2.4em;
background-color: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 0.25em;
+ border-radius: 0.25em 0 0 0.25em;
+ border-width: 1px 0 1px 1px;
}
.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+ top: 0;
right: 0;
+ height: 2.3em;
+ margin-right: 0.775em;
}
.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
+ top: 0;
left: 0;
+ height: 2.3em;
+ margin-left: 0.3em;
}
.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
line-height: 2.3em;
.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
height: 2.3em;
}
-.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
- top: 0;
- height: 2.3em;
- margin-right: 0.775em;
-}
-.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
- top: 0;
- height: 2.3em;
- margin-left: 0.3em;
-}
.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
color: #cccccc;
text-shadow: 0 1px 1px #ffffff;
vertical-align: middle;
border-radius: 0.25em;
}
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+ border-radius: 0.25em;
+}
.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget {
border-style: dashed;
}
padding: 0.5em 1em;
margin: 0.5em 0 0 0.75em;
border: 1px solid transparent;
- border-bottom: none;
+ border-bottom: 0;
border-top-left-radius: 0.5em;
border-top-right-radius: 0.5em;
}
background-color: #ffffff;
border-color: #dddddd;
}
-.oo-ui-capsuleMultiSelectWidget {
+.oo-ui-capsuleMultiselectWidget {
display: inline-block;
position: relative;
width: 100%;
max-width: 50em;
}
-.oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget-handle {
width: 100%;
display: block;
position: relative;
}
-.oo-ui-capsuleMultiSelectWidget-content {
+.oo-ui-capsuleMultiselectWidget-content {
position: relative;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-content > input {
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-content > input {
display: none;
}
-.oo-ui-capsuleMultiSelectWidget-group {
+.oo-ui-capsuleMultiselectWidget-group {
display: inline;
}
-.oo-ui-capsuleMultiSelectWidget > .oo-ui-menuSelectWidget {
+.oo-ui-capsuleMultiselectWidget > .oo-ui-menuSelectWidget {
z-index: 1;
width: 100%;
}
-.oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget-handle {
background-color: #ffffff;
cursor: text;
min-height: 2.4em;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
-.oo-ui-capsuleMultiSelectWidget-handle:last-child {
+.oo-ui-capsuleMultiselectWidget-handle:last-child {
margin-right: 0;
}
-.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator,
-.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon {
+.oo-ui-capsuleMultiselectWidget-handle > .oo-ui-indicatorElement-indicator,
+.oo-ui-capsuleMultiselectWidget-handle > .oo-ui-iconElement-icon {
position: absolute;
}
-.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-capsuleMultiSelectWidget-content > input {
- border: none;
+.oo-ui-capsuleMultiselectWidget-handle > .oo-ui-capsuleMultiselectWidget-content > input {
+ border: 0;
line-height: 1.675em;
margin: 0;
margin-left: 0.2em;
font-size: inherit;
font-family: inherit;
background-color: transparent;
- color: black;
+ color: #000000;
vertical-align: middle;
}
-.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-capsuleMultiSelectWidget-content > input:focus {
+.oo-ui-capsuleMultiselectWidget-handle > .oo-ui-capsuleMultiselectWidget-content > input:focus {
outline: none;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiselectWidget-handle {
padding-right: 2.4875em;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
+.oo-ui-capsuleMultiselectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-indicatorElement-indicator {
right: 0;
top: 0;
margin: 0.775em;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-iconElement .oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget.oo-ui-iconElement .oo-ui-capsuleMultiselectWidget-handle {
padding-left: 2.475em;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-iconElement .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon {
+.oo-ui-capsuleMultiselectWidget.oo-ui-iconElement .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-iconElement-icon {
left: 0;
top: 0;
margin: 0.3em;
}
-.oo-ui-capsuleMultiSelectWidget:hover .oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget:hover .oo-ui-capsuleMultiselectWidget-handle {
border-color: rgba(0, 0, 0, 0.2);
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-handle {
color: #cccccc;
text-shadow: 0 1px 1px #ffffff;
border-color: #dddddd;
background-color: #f3f3f3;
cursor: default;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon,
-.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-iconElement-icon,
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-indicatorElement-indicator {
opacity: 0.2;
}
.oo-ui-capsuleItemWidget {
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:06Z
+ * Date: 2016-05-31T21:50:56Z
*/
.oo-ui-draggableElement-handle,
.oo-ui-draggableElement-handle.oo-ui-widget {
.oo-ui-buttonOptionWidget {
display: inline-block;
padding: 0;
- background-color: transparent;
}
.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
position: relative;
}
.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus {
border-color: #347bff;
+ box-shadow: inset 0 0 0 1px #347bff;
outline: 0;
}
.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus.oo-ui-toggleWidget-on {
}
.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button > [type="file"] {
position: absolute;
- margin: 0;
top: 0;
bottom: 0;
left: 0;
position: absolute;
right: 0.5em;
}
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel {
- display: block;
-}
.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
display: none;
.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-clearButton {
display: none;
}
+.oo-ui-selectFileWidget-empty.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropLabel {
+ display: block;
+}
.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget,
.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button,
margin-right: 0;
}
.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
- margin-left: 0.5em;
+ border-radius: 0 2px 2px 0;
}
.oo-ui-selectFileWidget-info {
height: 2.4em;
background-color: #ffffff;
border: 1px solid #cccccc;
- border-radius: 2px;
+ border-radius: 2px 0 0 2px;
+ border-width: 1px 0 1px 1px;
}
.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
left: 0;
.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
height: 2.3em;
}
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info,
.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
background-color: #f3f3f3;
color: #cccccc;
border-color: #dddddd;
cursor: default;
}
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
opacity: 0.2;
}
overflow: hidden;
border-radius: 2px;
}
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+ border-radius: 2px;
+}
.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-dropTarget {
background-color: #eeeeee;
border-style: dashed;
}
+.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropLabel {
+ display: none;
+}
.oo-ui-outlineOptionWidget {
position: relative;
cursor: pointer;
padding: 0.35em 1em;
margin: 0.5em 0 0 0.75em;
border: 1px solid transparent;
- border-bottom: none;
+ border-bottom: 0;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
color: #555555;
background-color: #ffffff;
color: #333333;
}
-.oo-ui-capsuleMultiSelectWidget {
+.oo-ui-capsuleMultiselectWidget {
display: inline-block;
position: relative;
width: 100%;
max-width: 50em;
}
-.oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget-handle {
width: 100%;
display: block;
position: relative;
}
-.oo-ui-capsuleMultiSelectWidget-content {
+.oo-ui-capsuleMultiselectWidget-content {
position: relative;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-content > input {
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-content > input {
display: none;
}
-.oo-ui-capsuleMultiSelectWidget-group {
+.oo-ui-capsuleMultiselectWidget-group {
display: inline;
}
-.oo-ui-capsuleMultiSelectWidget > .oo-ui-menuSelectWidget {
+.oo-ui-capsuleMultiselectWidget > .oo-ui-menuSelectWidget {
z-index: 1;
width: 100%;
}
-.oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget-handle {
background-color: #ffffff;
cursor: text;
min-height: 2.4em;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
-.oo-ui-capsuleMultiSelectWidget-handle:last-child {
+.oo-ui-capsuleMultiselectWidget-handle:last-child {
margin-right: 0;
}
-.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator,
-.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon {
+.oo-ui-capsuleMultiselectWidget-handle > .oo-ui-indicatorElement-indicator,
+.oo-ui-capsuleMultiselectWidget-handle > .oo-ui-iconElement-icon {
position: absolute;
}
-.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-capsuleMultiSelectWidget-content > input {
+.oo-ui-capsuleMultiselectWidget-handle > .oo-ui-capsuleMultiselectWidget-content > input {
border: 0;
line-height: 1.675em;
margin: 0 0 0 0.2em;
color: #000000;
vertical-align: middle;
}
-.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-capsuleMultiSelectWidget-content > input:focus {
+.oo-ui-capsuleMultiselectWidget-handle > .oo-ui-capsuleMultiselectWidget-content > input:focus {
outline: 0;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiselectWidget-handle {
padding-right: 2.4875em;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
+.oo-ui-capsuleMultiselectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-indicatorElement-indicator {
right: 0;
top: 0;
margin: 0.775em;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-iconElement .oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget.oo-ui-iconElement .oo-ui-capsuleMultiselectWidget-handle {
padding-left: 2.475em;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-iconElement .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon {
+.oo-ui-capsuleMultiselectWidget.oo-ui-iconElement .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-iconElement-icon {
left: 0;
top: 0;
margin: 0.3em;
}
-.oo-ui-capsuleMultiSelectWidget:hover .oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget:hover .oo-ui-capsuleMultiselectWidget-handle {
border-color: #aaaaaa;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle {
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-handle {
color: #cccccc;
text-shadow: 0 1px 1px #ffffff;
border-color: #dddddd;
background-color: #f3f3f3;
cursor: default;
}
-.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon,
-.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-iconElement-icon,
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-indicatorElement-indicator {
opacity: 0.2;
}
.oo-ui-capsuleItemWidget {
.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget {
width: 2.5em;
}
-.oo-ui-numberInputWidget-minusButton.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+.oo-ui-numberInputWidget-minusButton.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right-width: 0;
}
-.oo-ui-numberInputWidget-plusButton.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+.oo-ui-numberInputWidget-plusButton.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left-width: 0;
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:02Z
+ * Date: 2016-05-31T21:50:52Z
*/
( function ( OO ) {
*
* @class
* @abstract
+ * @mixins OO.ui.mixin.RequestManager
*
* @constructor
* @param {Object} [config] Configuration options
* @mixins OO.ui.mixin.ButtonElement
* @mixins OO.ui.mixin.IconElement
* @mixins OO.ui.mixin.IndicatorElement
- * @mixins OO.ui.mixin.TabIndexedElement
* @mixins OO.ui.mixin.TitledElement
*
* @constructor
OO.ui.mixin.IconElement.call( this, config );
OO.ui.mixin.IndicatorElement.call( this, config );
OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$button } ) );
- OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, {
- $tabIndexed: this.$button,
- tabIndex: -1
- } ) );
// Initialization
this.$element.addClass( 'oo-ui-buttonOptionWidget' );
OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.IconElement );
OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.IndicatorElement );
OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.TitledElement );
-OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.TabIndexedElement );
/* Static Properties */
OO.mixinClass( OO.ui.TabSelectWidget, OO.ui.mixin.TabIndexedElement );
/**
- * CapsuleItemWidgets are used within a {@link OO.ui.CapsuleMultiSelectWidget
- * CapsuleMultiSelectWidget} to display the selected items.
+ * CapsuleItemWidgets are used within a {@link OO.ui.CapsuleMultiselectWidget
+ * CapsuleMultiselectWidget} to display the selected items.
*
* @class
* @extends OO.ui.Widget
};
/**
- * CapsuleMultiSelectWidgets are something like a {@link OO.ui.ComboBoxInputWidget combo box widget}
+ * CapsuleMultiselectWidgets are something like a {@link OO.ui.ComboBoxInputWidget combo box widget}
* that allows for selecting multiple values.
*
* For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
*
* @example
- * // Example: A CapsuleMultiSelectWidget.
- * var capsule = new OO.ui.CapsuleMultiSelectWidget( {
- * label: 'CapsuleMultiSelectWidget',
+ * // Example: A CapsuleMultiselectWidget.
+ * var capsule = new OO.ui.CapsuleMultiselectWidget( {
+ * label: 'CapsuleMultiselectWidget',
* selected: [ 'Option 1', 'Option 3' ],
* menu: {
* items: [
*
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.mixin.TabIndexedElement
* @mixins OO.ui.mixin.GroupElement
+ * @mixins OO.ui.mixin.PopupElement
+ * @mixins OO.ui.mixin.TabIndexedElement
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.IconElement
* @uses OO.ui.CapsuleItemWidget
* @uses OO.ui.FloatingMenuSelectWidget
*
* the containing `<div>` and has a larger area. By default, the menu uses
* relative positioning.
*/
-OO.ui.CapsuleMultiSelectWidget = function OoUiCapsuleMultiSelectWidget( config ) {
+OO.ui.CapsuleMultiselectWidget = function OoUiCapsuleMultiselectWidget( config ) {
var $tabFocus;
// Parent constructor
- OO.ui.CapsuleMultiSelectWidget.parent.call( this, config );
+ OO.ui.CapsuleMultiselectWidget.parent.call( this, config );
// Configuration initialization
config = $.extend( {
if ( config.data ) {
this.setItemsFromData( config.data );
}
- this.$content.addClass( 'oo-ui-capsuleMultiSelectWidget-content' )
+ this.$content.addClass( 'oo-ui-capsuleMultiselectWidget-content' )
.append( this.$group );
- this.$group.addClass( 'oo-ui-capsuleMultiSelectWidget-group' );
- this.$handle.addClass( 'oo-ui-capsuleMultiSelectWidget-handle' )
+ this.$group.addClass( 'oo-ui-capsuleMultiselectWidget-group' );
+ this.$handle.addClass( 'oo-ui-capsuleMultiselectWidget-handle' )
.append( this.$indicator, this.$icon, this.$content );
- this.$element.addClass( 'oo-ui-capsuleMultiSelectWidget' )
+ this.$element.addClass( 'oo-ui-capsuleMultiselectWidget' )
.append( this.$handle );
if ( this.popup ) {
this.$content.append( $tabFocus );
/* Setup */
-OO.inheritClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.GroupElement );
-OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.PopupElement );
-OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.TabIndexedElement );
-OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.IndicatorElement );
-OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.IconElement );
+OO.inheritClass( OO.ui.CapsuleMultiselectWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.CapsuleMultiselectWidget, OO.ui.mixin.GroupElement );
+OO.mixinClass( OO.ui.CapsuleMultiselectWidget, OO.ui.mixin.PopupElement );
+OO.mixinClass( OO.ui.CapsuleMultiselectWidget, OO.ui.mixin.TabIndexedElement );
+OO.mixinClass( OO.ui.CapsuleMultiselectWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.CapsuleMultiselectWidget, OO.ui.mixin.IconElement );
/* Events */
* @param {string} label The label text.
* @return {OO.ui.CapsuleItemWidget}
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.createItemWidget = function ( data, label ) {
+OO.ui.CapsuleMultiselectWidget.prototype.createItemWidget = function ( data, label ) {
return new OO.ui.CapsuleItemWidget( { data: data, label: label } );
};
*
* @return {Mixed[]}
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.getItemsData = function () {
- return $.map( this.getItems(), function ( e ) { return e.data; } );
+OO.ui.CapsuleMultiselectWidget.prototype.getItemsData = function () {
+ return this.getItems().map( function ( item ) {
+ return item.data;
+ } );
};
/**
*
* @chainable
* @param {Mixed[]} datas
- * @return {OO.ui.CapsuleMultiSelectWidget}
+ * @return {OO.ui.CapsuleMultiselectWidget}
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.setItemsFromData = function ( datas ) {
+OO.ui.CapsuleMultiselectWidget.prototype.setItemsFromData = function ( datas ) {
var widget = this,
menu = this.menu,
items = this.getItems();
*
* @chainable
* @param {Mixed[]} datas
- * @return {OO.ui.CapsuleMultiSelectWidget}
+ * @return {OO.ui.CapsuleMultiselectWidget}
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.addItemsFromData = function ( datas ) {
+OO.ui.CapsuleMultiselectWidget.prototype.addItemsFromData = function ( datas ) {
var widget = this,
menu = this.menu,
items = [];
* @param {string} label
* @return {boolean} Whether the item was added or not
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.addItemFromLabel = function ( label ) {
+OO.ui.CapsuleMultiselectWidget.prototype.addItemFromLabel = function ( label ) {
var item = this.menu.getItemFromLabel( label, true );
if ( item ) {
this.addItemsFromData( [ item.data ] );
*
* @chainable
* @param {Mixed[]} datas
- * @return {OO.ui.CapsuleMultiSelectWidget}
+ * @return {OO.ui.CapsuleMultiselectWidget}
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.removeItemsFromData = function ( datas ) {
+OO.ui.CapsuleMultiselectWidget.prototype.removeItemsFromData = function ( datas ) {
var widget = this,
items = [];
/**
* @inheritdoc
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.addItems = function ( items ) {
+OO.ui.CapsuleMultiselectWidget.prototype.addItems = function ( items ) {
var same, i, l,
oldItems = this.items.slice();
*
* @param {Object} item
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.editItem = function ( item ) {
+OO.ui.CapsuleMultiselectWidget.prototype.editItem = function ( item ) {
this.$input.val( item.label );
this.updateInputSize();
this.focus();
/**
* @inheritdoc
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.removeItems = function ( items ) {
+OO.ui.CapsuleMultiselectWidget.prototype.removeItems = function ( items ) {
var same, i, l,
oldItems = this.items.slice();
/**
* @inheritdoc
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.clearItems = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.clearItems = function () {
if ( this.items.length ) {
OO.ui.mixin.GroupElement.prototype.clearItems.call( this );
this.emit( 'change', this.getItemsData() );
* @param {OO.ui.CapsuleItemWidget} [item]
* @return {OO.ui.CapsuleItemWidget|jQuery|boolean}
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.getNextItem = function ( item ) {
+OO.ui.CapsuleMultiselectWidget.prototype.getNextItem = function ( item ) {
var itemIndex;
if ( item === undefined ) {
* @param {OO.ui.CapsuleItemWidget} [item]
* @return {OO.ui.CapsuleItemWidget|jQuery|boolean}
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.getPreviousItem = function ( item ) {
+OO.ui.CapsuleMultiselectWidget.prototype.getPreviousItem = function ( item ) {
var itemIndex;
if ( item === undefined ) {
*
* @return {OO.ui.MenuSelectWidget} Menu widget
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.getMenu = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.getMenu = function () {
return this.menu;
};
* @private
* @param {jQuery.Event} event
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.onInputFocus = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.onInputFocus = function () {
if ( !this.isDisabled() ) {
this.menu.toggle( true );
}
* @private
* @param {jQuery.Event} event
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.onInputBlur = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.onInputBlur = function () {
this.addItemFromLabel( this.$input.val() );
this.clearInput();
};
* @private
* @param {jQuery.Event} event
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.onFocusForPopup = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.onFocusForPopup = function () {
if ( !this.isDisabled() ) {
this.popup.setSize( this.$handle.width() );
this.popup.toggle( true );
- this.popup.$element.find( '*' )
- .filter( function () { return OO.ui.isFocusableElement( $( this ), true ); } )
- .first()
- .focus();
+ OO.ui.findFocusable( this.popup.$element ).focus();
}
};
* @private
* @param {jQuery.Event} e Focus out event
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.onPopupFocusOut = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.onPopupFocusOut = function () {
var widget = this.popup;
setTimeout( function () {
* @private
* @param {jQuery.Event} e Mouse down event
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.onMouseDown = function ( e ) {
+OO.ui.CapsuleMultiselectWidget.prototype.onMouseDown = function ( e ) {
if ( e.which === OO.ui.MouseButtons.LEFT ) {
this.focus();
return false;
* @private
* @param {jQuery.Event} e Key press event
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.onKeyPress = function ( e ) {
+OO.ui.CapsuleMultiselectWidget.prototype.onKeyPress = function ( e ) {
if ( !this.isDisabled() ) {
if ( e.which === OO.ui.Keys.ESCAPE ) {
this.clearInput();
* @private
* @param {jQuery.Event} e Key down event
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.onKeyDown = function ( e ) {
+OO.ui.CapsuleMultiselectWidget.prototype.onKeyDown = function ( e ) {
if (
!this.isDisabled() &&
this.$input.val() === '' &&
* @private
* @param {jQuery.Event} e Event of some sort
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.updateInputSize = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.updateInputSize = function () {
var $lastItem, direction, contentWidth, currentWidth, bestWidth;
if ( !this.isDisabled() ) {
this.$input.css( 'width', '1em' );
*
* @private
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.updateIfHeightChanged = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.updateIfHeightChanged = function () {
var height = this.$element.height();
if ( height !== this.height ) {
this.height = height;
* @private
* @param {OO.ui.OptionWidget} item Chosen item
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.onMenuChoose = function ( item ) {
+OO.ui.CapsuleMultiselectWidget.prototype.onMenuChoose = function ( item ) {
if ( item && item.isVisible() ) {
this.addItemsFromData( [ item.getData() ] );
this.clearInput();
*
* @private
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.onMenuItemsChange = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.onMenuItemsChange = function () {
this.setItemsFromData( this.getItemsData() );
- this.$element.toggleClass( 'oo-ui-capsuleMultiSelectWidget-empty', this.menu.isEmpty() );
+ this.$element.toggleClass( 'oo-ui-capsuleMultiselectWidget-empty', this.menu.isEmpty() );
};
/**
*
* @private
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.clearInput = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.clearInput = function () {
if ( this.$input ) {
this.$input.val( '' );
this.updateInputSize();
/**
* @inheritdoc
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.setDisabled = function ( disabled ) {
+OO.ui.CapsuleMultiselectWidget.prototype.setDisabled = function ( disabled ) {
var i, len;
// Parent method
- OO.ui.CapsuleMultiSelectWidget.parent.prototype.setDisabled.call( this, disabled );
+ OO.ui.CapsuleMultiselectWidget.parent.prototype.setDisabled.call( this, disabled );
if ( this.$input ) {
this.$input.prop( 'disabled', this.isDisabled() );
* Focus the widget
*
* @chainable
- * @return {OO.ui.CapsuleMultiSelectWidget}
+ * @return {OO.ui.CapsuleMultiselectWidget}
*/
-OO.ui.CapsuleMultiSelectWidget.prototype.focus = function () {
+OO.ui.CapsuleMultiselectWidget.prototype.focus = function () {
if ( !this.isDisabled() ) {
if ( this.popup ) {
this.popup.setSize( this.$handle.width() );
this.popup.toggle( true );
- this.popup.$element.find( '*' )
- .filter( function () { return OO.ui.isFocusableElement( $( this ), true ); } )
- .first()
- .focus();
+ OO.ui.findFocusable( this.popup.$element ).focus();
} else {
this.updateInputSize();
this.menu.toggle( true );
return this;
};
+/**
+ * @class
+ * @deprecated since 0.17.3; use OO.ui.CapsuleMultiselectWidget instead
+ */
+OO.ui.CapsuleMultiSelectWidget = OO.ui.CapsuleMultiselectWidget;
+
/**
* SelectFileWidgets allow for selecting files, using the HTML5 File API. These
* widgets can be configured with {@link OO.ui.mixin.IconElement icons} and {@link
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:06Z
+ * Date: 2016-05-31T21:50:56Z
*/
.oo-ui-actionWidget.oo-ui-pendingElement-pending {
background-image: /* @embed */ url(themes/apex/images/textures/pending.gif);
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:06Z
+ * Date: 2016-05-31T21:50:56Z
*/
.oo-ui-window {
background: transparent;
/*!
- * OOjs UI v0.17.1
+ * OOjs UI v0.17.4
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-05-03T22:58:02Z
+ * Date: 2016-05-31T21:50:52Z
*/
( function ( OO ) {
"lang": {
"ar": "images/icons/bold-arab-ain.svg",
"be": "images/icons/bold-cyrl-te.svg",
- "cs,en,he,ml,pl,sco": "images/icons/bold-b.svg",
+ "cs,en,en-ca,en-gb,he,ml,pl,sco": "images/icons/bold-b.svg",
"da,de,hu,ksh,nn,no,sv": "images/icons/bold-f.svg",
"es,gl,pt": "images/icons/bold-n.svg",
"eu,fi": "images/icons/bold-l.svg",
"default": "images/icons/italic-a.svg",
"lang": {
"ar": "images/icons/italic-arab-meem.svg",
- "cs,en,fr,he,ml,pl,pt,sco": "images/icons/italic-i.svg",
+ "cs,en,en-ca,en-gb,fr,he,ml,pl,pt,sco": "images/icons/italic-i.svg",
"be,da,de,fi,ky,nn,no,os,sv,ru,uk": "images/icons/italic-k.svg",
"es,gl,it,nl": "images/icons/italic-c.svg",
"eu": "images/icons/italic-e.svg",
"strikethrough": { "file": {
"default": "images/icons/strikethrough-a.svg",
"lang": {
- "en": "images/icons/strikethrough-s.svg",
+ "en,en-ca,en-gb": "images/icons/strikethrough-s.svg",
"fi": "images/icons/strikethrough-y.svg"
}
} },
"underline": { "file": {
"default": "images/icons/underline-a.svg",
"lang": {
- "en": "images/icons/underline-u.svg"
+ "en,en-ca,en-gb": "images/icons/underline-u.svg"
}
} },
"textLanguage": { "file": {
"lang": {
"ar": "images/icons/bold-arab-ain.svg",
"be": "images/icons/bold-cyrl-te.svg",
- "cs,en,he,ml,pl,sco": "images/icons/bold-b.svg",
+ "cs,en,en-ca,en-gb,he,ml,pl,sco": "images/icons/bold-b.svg",
"da,de,hu,ksh,nn,no,sv": "images/icons/bold-f.svg",
"es,gl,pt": "images/icons/bold-n.svg",
"eu,fi": "images/icons/bold-l.svg",
"default": "images/icons/italic-a.svg",
"lang": {
"ar": "images/icons/italic-arab-meem.svg",
- "cs,en,fr,he,ml,pl,pt,sco": "images/icons/italic-i.svg",
+ "cs,en,en-ca,en-gb,fr,he,ml,pl,pt,sco": "images/icons/italic-i.svg",
"be,da,de,fi,ky,nn,no,os,sv,ru,uk": "images/icons/italic-k.svg",
"es,gl,it,nl": "images/icons/italic-c.svg",
"eu": "images/icons/italic-e.svg",
"strikethrough": { "file": {
"default": "images/icons/strikethrough-a.svg",
"lang": {
- "en": "images/icons/strikethrough-s.svg",
+ "en,en-ca,en-gb": "images/icons/strikethrough-s.svg",
"fi": "images/icons/strikethrough-y.svg"
}
} },
"underline": { "file": {
"default": "images/icons/underline-a.svg",
"lang": {
- "en": "images/icons/underline-u.svg"
+ "en,en-ca,en-gb": "images/icons/underline-u.svg"
}
} },
"textLanguage": { "file": {
.tipsy-inner {
padding: 5px 8px 4px 8px;
/*background-color: #e8f2f8;*/
- background-color: #ffffff;
+ background-color: #fff;
border: solid 1px #a7d7f9;
- color: black;
+ color: #000;
max-width: 15em;
border-radius: 4px;
/*
.tipsy-arrow {
position: absolute;
/* @embed */
- background: url('images/tipsy.png') no-repeat top left;
+ background: url( images/tipsy.png ) no-repeat top left;
width: 11px;
height: 6px;
}
.arrowSteps {
list-style-type: none;
list-style-image: none;
- border: 1px solid #666666;
+ border: 1px solid #666;
position: relative;
}
.arrowSteps li.arrow div {
/* @embed */
- background: url(images/jquery.arrowSteps.divider-ltr.png) no-repeat right center;
+ background: url( images/jquery.arrowSteps.divider-ltr.png ) no-repeat right center;
}
/* applied to the element preceding the highlighted step */
.arrowSteps li.arrow.tail div {
/* @embed */
- background: url(images/jquery.arrowSteps.tail-ltr.png) no-repeat right center;
+ background: url( images/jquery.arrowSteps.tail-ltr.png ) no-repeat right center;
}
/* this applies to all highlighted, including the last */
.arrowSteps li.head div {
/* @embed */
- background: url(images/jquery.arrowSteps.head-ltr.png) no-repeat left center;
+ background: url( images/jquery.arrowSteps.head-ltr.png ) no-repeat left center;
font-weight: bold;
}
.arrowSteps li.arrow.head div {
/* TODO: eliminate duplication of jquery.arrowSteps.head.png embedding */
/* @embed */
- background: url(images/jquery.arrowSteps.head-ltr.png) no-repeat right center;
+ background: url( images/jquery.arrowSteps.head-ltr.png ) no-repeat right center;
}
.mw-badge-content {
font-weight: bold;
- color: white;
+ color: #fff;
vertical-align: baseline;
- text-shadow: 0 1px rgba(0, 0, 0, 0.4);
+ text-shadow: 0 1px rgba( 0, 0, 0, 0.4 );
}
.mw-badge-inline {
}
.mw-badge-important {
- background-color: #cc0000;
+ background-color: #c00;
}
}
.jquery-confirmable-element {
- transition: margin 250ms cubic-bezier(0.2, 0.8, 0.2, 0.8);
+ transition: margin 250ms cubic-bezier( 0.2, 0.8, 0.2, 0.8 );
}
.jquery-confirmable-interface {
- transition: width 250ms cubic-bezier(0.2, 0.8, 0.2, 0.8);
+ transition: width 250ms cubic-bezier( 0.2, 0.8, 0.2, 0.8 );
}
}
.farbtastic .wheel {
/* @embed */
- background: url(images/wheel.png) no-repeat;
+ background: url( images/wheel.png ) no-repeat;
width: 195px;
height: 195px;
}
.farbtastic .overlay {
/* @embed */
- background: url(images/mask.png) no-repeat;
+ background: url( images/mask.png ) no-repeat;
}
.farbtastic .marker {
width: 17px;
margin: -8px 0 0 -8px;
overflow: hidden;
/* @embed */
- background: url(images/marker.png) no-repeat;
+ background: url( images/marker.png ) no-repeat;
}
.mw-spinner-small {
/* @embed */
- background-image: url(images/spinner.gif);
+ background-image: url( images/spinner.gif );
height: 20px;
width: 20px;
/* Avoid issues with .mw-spinner-block when floated without width. */
.mw-spinner-large {
/* @embed */
- background-image: url(images/spinner-large.gif);
+ background-image: url( images/spinner-large.gif );
height: 32px;
width: 32px;
/* Avoid issues with .mw-spinner-block when floated without width. */
.suggestions-special {
position: relative;
- background-color: white;
+ background-color: #fff;
cursor: pointer;
- border: solid 1px #aaaaaa;
+ border: solid 1px #aaa;
padding: 0;
margin: 0;
margin-top: -2px;
}
.suggestions-results {
- background-color: white;
+ background-color: #fff;
cursor: pointer;
- border: solid 1px #aaaaaa;
+ border: solid 1px #aaa;
padding: 0;
margin: 0;
}
.suggestions-result {
- color: black;
+ color: #000;
margin: 0;
line-height: 1.5em;
padding: 0.01em 0.25em;
}
.suggestions-result-current {
- background-color: #4C59A6;
- color: white;
+ background-color: #4c59a6;
+ color: #fff;
}
.suggestions-special .special-label {
- color: gray;
+ color: #808080;
text-align: left;
}
.suggestions-special .special-query {
- color: black;
+ color: #000;
font-style: italic;
text-align: left;
}
.suggestions-special .special-hover {
- background-color: silver;
+ background-color: #c0c0c0;
}
.suggestions-result-current .special-label,
.suggestions-result-current .special-query {
- color: white;
+ color: #fff;
}
.highlight {
#pagehistory li.after input[name="diff"] {
visibility: hidden;
}
+
+.updatedmarker {
+ background-color: #b7f430;
+}
td.diff-context {
background: #f9f9f9;
border-color: #e6e6e6;
- color: #333333;
+ color: #333;
}
.diffchange {
.filehistory a img,
#file img:hover {
/* @embed */
- background: white url(images/checker.png) repeat;
+ background: #fff url( images/checker.png ) repeat;
}
/*
*/
ul#filetoc {
text-align: center;
- border: 1px solid #aaaaaa;
+ border: 1px solid #aaa;
background-color: #f9f9f9;
padding: 5px;
font-size: 95%;
$table = $( '#mw_metadata' ),
$tbody = $table.find( 'tbody' );
- if ( !$tbody.length || !$tbody.find( '.collapsable' ).length ) {
+ if ( !$tbody.find( '.collapsable' ).length ) {
return;
}
color: #626465;
background-color: #f4f4f4;
border: 1px solid #dcd9d9;
- text-shadow: 0 0.0625em 0 rgba(255, 255, 255, 0.5);
+ text-shadow: 0 0.0625em 0 rgba( 255, 255, 255, 0.5 );
border-radius: 5px;
box-shadow: 0 2px 5px 0 #ccc;
-webkit-transition: all 0.25s ease-in-out;
.postedit-icon-checkmark {
/* @embed */
- background-image: url(images/green-checkmark.png);
+ background-image: url( images/green-checkmark.png );
background-position: left;
}
font-size: 1.25em;
font-weight: bold;
line-height: 2.3em;
- color: black;
- text-shadow: 0 0.0625em 0 white;
+ color: #000;
+ text-shadow: 0 0.0625em 0 #fff;
text-decoration: none;
opacity: 0.2;
- filter: alpha(opacity=20);
+ filter: alpha( opacity=20 );
}
.postedit-close:hover {
- color: black;
+ color: #000;
text-decoration: none;
opacity: 0.4;
- filter: alpha(opacity=40);
+ filter: alpha( opacity=40 );
}
margin: 0;
padding: 0;
padding-left: 42px;
- background: transparent url(images/nextredirect-ltr.png) bottom left no-repeat;
+ background: transparent url( images/nextredirect-ltr.png ) bottom left no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/nextredirect-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/nextredirect-ltr.svg );
}
/* @noflip */
.mw-content-ltr .redirectText li:first-child {
padding-left: 47px;
- background: transparent url(images/redirect-ltr.png) bottom left no-repeat;
+ background: transparent url( images/redirect-ltr.png ) bottom left no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/redirect-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/redirect-ltr.svg );
}
/* @noflip */
margin: 0;
padding: 0;
padding-right: 42px;
- background: transparent url(images/nextredirect-rtl.png) bottom right no-repeat;
+ background: transparent url( images/nextredirect-rtl.png ) bottom right no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/nextredirect-rtl.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/nextredirect-rtl.svg );
}
/* @noflip */
.mw-content-rtl .redirectText li:first-child {
padding-right: 47px;
- background: transparent url(images/redirect-rtl.png) bottom right no-repeat;
+ background: transparent url( images/redirect-rtl.png ) bottom right no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/redirect-rtl.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/redirect-rtl.svg );
}
}
img,
+figure,
.wikitable,
.thumb {
/* Pagination */
.mw-body a.external.text:after,
.mw-body a.external.autonumber:after {
content: " (" attr( href ) ")";
+ word-break: break-all;
word-wrap: break-word;
}
padding: 3px !important;
font-size: 94%;
text-align: center;
+ /* new block formatting context,
+ * to clear background from floating content */
+ overflow: hidden;
}
html .thumbimage {
line-height: 1.4em;
padding: 3px !important;
font-size: 94%;
- overflow: hidden;
- word-wrap: break-word;
}
/* @noflip */
div.thumb {
margin-bottom: .5em;
border-style: solid;
- border-color: white;
+ border-color: #fff;
width: auto;
}
background-color: #f9f9f9;
font-size: 94%;
text-align: center;
+ /* new block formatting context,
+ * to clear background from floating content */
+ overflow: hidden;
}
html .thumbimage {
padding: 3px;
font-size: 94%;
text-align: left;
- overflow: hidden;
- word-wrap: break-word;
}
div.magnify {
width: 15px;
height: 11px;
/* Use same SVG support hack as mediawiki.legacy's shared.css */
- background: url(images/magnify-clip-ltr.png) center center no-repeat;
+ background: url( images/magnify-clip-ltr.png ) center center no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/magnify-clip-ltr.svg );
/* Don't annoy people who copy-paste everything too much */
-moz-user-select: none;
-webkit-user-select: none;
}
img.thumbborder {
- border: 1px solid #dddddd;
+ border: 1px solid #ddd;
}
/* Page history styling */
}
.error {
- color: red;
+ color: #f00;
font-size: larger;
}
}
#preftoc li {
- border: 1px solid White;
+ border: 1px solid #fff;
}
#preftoc li.selected {
background-color: #f9f9f9;
- border: 1px dashed #aaaaaa;
+ border: 1px dashed #aaa;
}
#preftoc a,
/* use this instead of #toc for page content */
.toccolours {
- border: 1px solid #aaaaaa;
+ border: 1px solid #aaa;
background-color: #f9f9f9;
padding: 5px;
font-size: 95%;
}
#siteNotice {
- border: 1px solid #aaaaaa;
+ border: 1px solid #aaa;
padding-left: 0.5em;
padding-right: 0.5em;
}
span.unpatrolled {
font-weight: bold;
- color: red;
-}
-
-span.updatedmarker {
- color: black;
- background-color: #00FF00;
+ color: #f00;
}
div.gallerybox {
.previewnote {
text-align: center;
- color: #cc0000;
+ color: #c00;
}
.editExternally {
border-style: solid;
border-width: 1px;
- border-color: gray;
- background: #ffffff;
+ border-color: #808080;
+ background: #fff;
padding: 3px;
margin-top: 0.5em;
float: left;
.editExternallyHelp {
font-style: italic;
- color: gray;
+ color: #808080;
}
li span.deleted {
table.mw_metadata td,
table.mw_metadata th {
- border: 1px solid #aaaaaa;
+ border: 1px solid #aaa;
padding-left: 4px;
padding-right: 4px;
}
}
div.multipageimagenavbox {
- border: solid 1px silver;
+ border: solid 1px #c0c0c0;
padding: 4px;
margin: 1em;
background: #f0f0f0;
}
body.ns-0 {
- background-color: white;
+ background-color: #fff;
}
/** RTL specific CSS starts here **/
/* User-Agent styles for new HTML5 elements */
mark {
- background-color: yellow;
- color: black;
+ background-color: #ff0;
+ color: #000;
}
/* Helper for wbr element on IE 8+; in HTML5, but not supported by default as of IE 11. */
.unpatrolled {
font-weight: bold;
- color: red;
+ color: #f00;
}
div.patrollink {
.catlinks li {
display: inline-block;
line-height: 1.25em;
- border-left: 1px solid #AAA;
+ border-left: 1px solid #aaa;
margin: 0.125em 0;
padding: 0 0.5em;
zoom: 1;
/* The auto-generated edit comments */
.autocomment {
- color: gray;
+ color: #808080;
}
#pagehistory .history-user {
}
#pagehistory li {
- border: 1px solid white;
+ border: 1px solid #fff;
}
#pagehistory li.selected {
div.mw-warning-with-logexcerpt {
padding: 3px;
margin-bottom: 3px;
- border: 2px solid #2F6FAB;
+ border: 2px solid #2f6fab;
clear: both;
}
/* red links; see bug 36276 */
a.new {
- color: #BA0000;
+ color: #ba0000;
}
/* Plainlinks - this can be used to switch
background-color: #f9f9f9;
border: 1px solid #aaa;
border-collapse: collapse;
- color: black;
+ color: #000;
}
table.wikitable > tr > th,
}
.error {
- color: #cc0000;
+ color: #c00;
}
.warning {
}
.errorbox {
- color: #cc0000;
+ color: #c00;
border-color: #fac5c5;
background-color: #fae3e3;
}
.mw-datatable,
.mw-datatable td,
.mw-datatable th {
- border: 1px solid #aaaaaa;
+ border: 1px solid #aaa;
padding: 0 0.15em 0 0.15em;
}
.mw-datatable th {
- background-color: #ddddff;
+ background-color: #ddf;
}
.mw-datatable td {
- background-color: #ffffff;
+ background-color: #fff;
}
.mw-datatable tr:hover td {
- background-color: #eeeeff;
+ background-color: #eef;
}
/* Classes for Exif data display */
table.mw_metadata th {
font-weight: normal;
+ text-align: center;
}
table.mw_metadata td {
table.mw_metadata td,
table.mw_metadata th {
- text-align: center;
- border: 1px solid #aaaaaa;
+ border: 1px solid #aaa;
padding-left: 5px;
padding-right: 5px;
}
}
.mw-ajax-loader {
- background-image: url(images/ajax-loader.gif);
+ background-image: url( images/ajax-loader.gif );
background-position: center center;
background-repeat: no-repeat;
padding: 16px;
.mw-small-spinner {
padding: 10px !important;
margin-right: 0.6em;
- background-image: url(images/spinner.gif);
+ background-image: url( images/spinner.gif );
background-position: center center;
background-repeat: no-repeat;
}
margin-left: 2px;
margin-bottom: -8px;
padding: 0 0 0 15px;
- background-image: url(images/help-question.gif);
+ background-image: url( images/help-question.gif );
background-position: left center;
background-repeat: no-repeat;
cursor: pointer;
}
.mw-help-field-hint:hover {
- background-image: url(images/help-question-hover.gif);
+ background-image: url( images/help-question-hover.gif );
}
.mw-help-field-data {
background-color: #f9f9f9;
font-size: 94%;
text-align: center;
+ /* new block formatting context,
+ * to clear background from floating content */
+ overflow: hidden;
}
html .thumbimage {
line-height: 1.4em;
padding: 3px;
font-size: 94%;
- overflow: hidden;
- word-wrap: break-word;
/* Default styles when there's no .mw-content-ltr or .mw-content-rtl, overridden below */
text-align: left;
}
/* Default styles when there's no .mw-content-ltr or .mw-content-rtl, overridden below */
/* Use same SVG support hack as mediawiki.legacy's shared.css */
- background-image: url(images/magnify-clip-ltr.png);
+ background-image: url( images/magnify-clip-ltr.png );
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/magnify-clip-ltr.svg );
/* Don't annoy people who copy-paste everything too much */
-moz-user-select: none;
-webkit-user-select: none;
}
img.thumbborder {
- border: 1px solid #dddddd;
+ border: 1px solid #ddd;
}
/* Directionality-specific styles for thumbnails - their positioning depends on content language */
/* @noflip */
.mw-content-ltr div.magnify a {
/* Use same SVG support hack as mediawiki.legacy's shared.css */
- background-image: url(images/magnify-clip-ltr.png);
+ background-image: url( images/magnify-clip-ltr.png );
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/magnify-clip-ltr.svg );
}
/* @noflip */
/* @noflip */
.mw-content-rtl div.magnify a {
/* Use same SVG support hack as mediawiki.legacy's shared.css */
- background-image: url(images/magnify-clip-rtl.png);
+ background-image: url( images/magnify-clip-rtl.png );
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/magnify-clip-rtl.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/magnify-clip-rtl.svg );
}
/* @noflip */
* and using the .background-image-svg mixin. */
/* SVG support using a transparent gradient to guarantee cross-browser
- * compatibility (browsers able to understand gradient syntax support also SVG).
+ * compatibility ( browsers able to understand gradient syntax support also SVG ).
* http://pauginer.tumblr.com/post/36614680636/invisible-gradient-technique */
.mw-body a.external,
.link-https {
- background: url(images/external-ltr.png) center right no-repeat;
+ background: url( images/external-ltr.png ) center right no-repeat;
/* @embed */
- background-image: -webkit-linear-gradient(transparent, transparent), url(images/external-ltr.svg);
+ background-image: -webkit-linear-gradient( transparent, transparent ), url( images/external-ltr.svg );
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/external-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/external-ltr.svg );
padding-right: 15px;
}
.mw-body a.external[href^="mailto:"],
.link-mailto {
- background: url(images/mail.png) center right no-repeat;
+ background: url( images/mail.png ) center right no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/mail.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/mail.svg );
padding-right: 15px;
}
.mw-body a.external[href^="ftp://"],
.link-ftp {
- background: url(images/ftp-ltr.png) center right no-repeat;
+ background: url( images/ftp-ltr.png ) center right no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/ftp-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/ftp-ltr.svg );
padding-right: 15px;
}
.mw-body a.external[href^="irc://"],
.mw-body a.external[href^="ircs://"],
.link-irc {
- background: url(images/chat-ltr.png) center right no-repeat;
+ background: url( images/chat-ltr.png ) center right no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/chat-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/chat-ltr.svg );
padding-right: 15px;
}
.mw-body a.external[href$=".wav"], .mw-body a.external[href$=".WAV"],
.mw-body a.external[href$=".wma"], .mw-body a.external[href$=".WMA"],
.link-audio {
- background: url(images/audio-ltr.png) center right no-repeat;
+ background: url( images/audio-ltr.png ) center right no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/audio-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/audio-ltr.svg );
padding-right: 15px;
}
.mw-body a.external[href$=".mpeg"], .mw-body a.external[href$=".MPEG"],
.mw-body a.external[href$=".mpg"], .mw-body a.external[href$=".MPG"],
.link-video {
- background: url(images/video.png) center right no-repeat;
+ background: url( images/video.png ) center right no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/video.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/video.svg );
padding-right: 15px;
}
.mw-body a.external[href*=".pdf#"], .mw-body a.external[href*=".PDF#"],
.mw-body a.external[href*=".pdf?"], .mw-body a.external[href*=".PDF?"],
.link-document {
- background: url(images/document-ltr.png) center right no-repeat;
+ background: url( images/document-ltr.png ) center right no-repeat;
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/document-ltr.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/document-ltr.svg );
padding-right: 15px;
}
}
.mw-body-content a[rel~="mw:ExtLink"]:empty:after {
- content: "[" counter(mw-NumberedExtLink) "]";
+ content: "[" counter( mw-NumberedExtLink ) "]";
counter-increment: mw-NumberedExtLink;
}
figure[typeof~='mw:Image/Thumb'] > *:first-child > img,
figure[typeof~='mw:Image/Frame'] > *:first-child > img,
.mw-image-border > *:first-child > img {
- border: 1px solid #cccccc;
+ border: 1px solid #ccc;
margin: 3px;
}
}
a.stub {
- color: #772233;
+ color: #723;
}
a.new, #p-personal a.new {
h4,
h5,
h6 {
- color: black;
+ color: #000;
background: none;
font-weight: normal;
margin: 0;
* Some browsers will render the monospace text too small, namely Firefox, Chrome and Safari.
* Specifying any valid, second value will trigger correct behavior without forcing a different font.
*/
- font-family: monospace, Courier;
+ font-family: monospace, 'Courier';
}
code {
- color: black;
+ color: #000;
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 2px;
pre,
.mw-code {
- color: black;
+ color: #000;
background-color: #f9f9f9;
border: 1px solid #ddd;
padding: 1em;
clear: both;
}
+textarea {
+ /* Support Firefox: Border rule required to override system appearance on Linux */
+ border: 1px solid #c0c0c0;
+}
+
.editOptions {
- background-color: #F0F0F0;
- border: 1px solid silver;
+ background-color: #f0f0f0;
+ border: 1px solid #c0c0c0;
border-top: none;
padding: 1em 1em 1.5em 1em;
margin-bottom: 2em;
.usermessage {
background-color: #ffce7b;
border: 1px solid #ffa500;
- color: black;
+ color: #000;
font-weight: bold;
margin: 2em 0 1em;
padding: .5em 1em;
}
} );
} else if ( Util.apiBool( pi.multi ) ) {
- widget = new OO.ui.CapsuleMultiSelectWidget( {
+ widget = new OO.ui.CapsuleMultiselectWidget( {
allowArbitrary: true
} );
widget.paramInfo = pi;
return a.data - b.data;
} );
if ( Util.apiBool( pi.multi ) ) {
- widget = new OO.ui.CapsuleMultiSelectWidget( {
+ widget = new OO.ui.CapsuleMultiselectWidget( {
menu: { items: items }
} );
widget.paramInfo = pi;
return new OO.ui.MenuOptionWidget( { data: String( v ), label: String( v ) } );
} );
if ( Util.apiBool( pi.multi ) ) {
- widget = new OO.ui.CapsuleMultiSelectWidget( {
+ widget = new OO.ui.CapsuleMultiselectWidget( {
menu: { items: items }
} );
widget.paramInfo = pi;
throw new Error( 'Unknown multiMode "' + multiMode + '"' );
}
- widget = new OO.ui.CapsuleMultiSelectWidget( {
+ widget = new OO.ui.CapsuleMultiselectWidget( {
allowArbitrary: true,
popup: {
classes: [ 'mw-apisandbox-popup' ],
*
* @class mw.special.ApiSandbox
*/
- mw.special.ApiSandbox = ApiSandbox = {
+ ApiSandbox = {
/**
* Initialize the UI
*
}
if ( Util.apiBool( pi.parameters[ i ].multi ) ) {
tmp = [];
- if ( flag && !( widget instanceof OO.ui.CapsuleMultiSelectWidget ) &&
+ if ( flag && !( widget instanceof OO.ui.CapsuleMultiselectWidget ) &&
!(
widget instanceof OptionalWidget &&
- widget.widget instanceof OO.ui.CapsuleMultiSelectWidget
+ widget.widget instanceof OO.ui.CapsuleMultiselectWidget
)
) {
tmp.push( mw.message( 'api-help-param-multi-separate' ).parse() );
$( ApiSandbox.init );
+ module.exports = ApiSandbox;
+
}( jQuery, mediaWiki, OO ) );
+++ /dev/null
-.mw-htmlform-flatlist-item {\r
- /* FIXME: There should be an option in OOUI to do that */\r
- display: inline-block !important;\r
-}
\ No newline at end of file
font-size: 90%;
}
span.mw-protectedpages-unknown {
- color: grey;
+ color: #808080;
font-size: 90%;
}
+++ /dev/null
-/*!
- * Namespace for mediawiki.special.* modules
- */
-
-/**
- * @class mw.special
- * @singleton
- */
-mediaWiki.special = {};
.mw-email-none .mw-input{
border: 1px solid #fde29b;
background-color: #fdf1d1;
- color: #000000;
+ color: #000;
}
/* Authenticated email field has its own class too. Unstyled by default */
/*
$( rc.init );
- mw.special.recentchanges = rc;
+ module.exports = rc;
}( mediaWiki, jQuery ) );
-/* Special:Search */
-
-/*
- * Fixes sister projects box moving down the extract
- * of the first result (bug #16886).
- * It only happens when the window is small and
- * This changes slightly the layout for big screens
- * where there was space for the extracts and the
- * sister projects and thus it showed like in any
- * other browser.
- *
- * This will only affect IE 7 and lower
- */
-.searchresult {
- display: inline !ie;
-}
-.searchresults {
- margin: 1em 0 1em .4em;
-}
-/* needs extra specificity to override `.mw-body p` selector */
-.mw-body p.mw-search-nonefound {
- margin: 0;
-}
-.mw-search-interwiki-header {
- font-weight: bold;
-}
-.mw-search-nonefound + .mw-search-interwiki-header {
- margin-top: 0;
-}
-div.searchresult {
- font-size: 95%;
- width: 38em;
-}
-.mw-search-results {
- margin-left: 0;
- float: left;
-}
-.mw-search-results li {
- padding-bottom: 1.2em;
- list-style: none;
- list-style-image: none;
-}
-.mw-search-results li a {
- font-size: 108%;
-}
-.mw-search-result-data {
- color: green;
- font-size: 97%;
-}
-.mw-search-profile-tabs {
- background-color: #f3f3f3;
- margin-top: 1em;
- border: 1px solid silver;
-}
-.mw-search-profile-tabs div.search-types {
- float: left;
- padding-left: 0.25em;
-}
-.mw-search-profile-tabs div.search-types ul {
- margin: 0;
- padding: 0;
- list-style: none;
-}
-.mw-search-profile-tabs div.search-types ul li {
- float: left;
- margin: 0;
- padding: 0;
-}
-.mw-search-profile-tabs div.search-types ul li a {
- display: block;
- padding: 0.5em;
-}
-.mw-search-profile-tabs div.search-types ul li.current a {
- color: #333333;
- cursor: default;
-}
-.mw-search-profile-tabs div.search-types ul li.current a:hover {
- text-decoration: none;
-}
-#mw-search-top-table div.results-info {
- float: right;
- padding: 0.5em;
- padding-right: 0.75em;
- color: #666;
- font-size: 95%;
-}
-
-fieldset#mw-searchoptions {
- margin: 0;
- padding: 0.5em 0.75em 0.75em 0.75em;
- border: none;
- background-color: #f9f9f9;
- border: 1px solid silver;
- border-top-width: 0;
-}
-fieldset#mw-searchoptions legend {
- display: none;
-}
-fieldset#mw-searchoptions h4 {
- padding: 0;
- margin: 0;
- float: left;
-}
-fieldset#mw-searchoptions div#mw-search-togglebox {
+#mw-search-togglebox {
float: right;
}
-fieldset#mw-searchoptions div#mw-search-togglebox label {
+#mw-search-togglebox label {
margin-right: 0.25em;
}
-fieldset#mw-searchoptions div#mw-search-togglebox input {
+#mw-search-togglebox input {
margin-left: 0.25em;
}
-fieldset#mw-searchoptions table {
- float: left;
- margin-right: 3em;
- border-collapse: collapse;
-}
-fieldset#mw-searchoptions table td {
- padding: 0 1em 0 0;
- white-space: nowrap;
-}
-fieldset#mw-searchoptions div.divider {
- clear: both;
- border-bottom: 1px solid #DDDDDD;
- padding-top: 0.5em;
- margin-bottom: 0.5em;
-}
-td#mw-search-menu {
- padding-left:6em;
- font-size:85%;
-}
-div#mw-search-interwiki {
- float: right;
- width: 18em;
- border: 1px solid #AAAAAA;
- margin-top: 2ex;
-}
-div#mw-search-interwiki li {
- font-size: 95%;
-}
-.mw-search-interwiki-more {
- float: right;
- font-size: 90%;
-}
-div#mw-search-interwiki-caption {
- text-align: center;
- font-weight: bold;
- font-size: 95%;
-}
-.mw-search-interwiki-project {
- font-size: 97%;
- text-align: left;
- padding: 0.15em 0.15em 0.2em 0.2em;
- background-color: #ececec;
- border-top: 1px solid #BBBBBB;
-}
-span.searchalttitle {
- font-size: 95%;
-}
-div.searchdidyoumean {
- font-size: 127%;
- margin-top: 0.8em;
- /* Note that this color won't affect the link, as desired. */
- color: #c00;
-}
-div.searchdidyoumean em {
- font-weight: bold;
-}
-.searchmatch {
- font-weight: bold;
-}
-/* Advanced PowerSearch box */
-td#mw-search-togglebox {
- text-align: right;
-}
-table#mw-search-powertable {
- width: 100%;
-}
-form#powersearch {
- clear: both;
-}
--- /dev/null
+/* Special:Search */
+
+/*
+ * Fixes sister projects box moving down the extract
+ * of the first result (bug #16886).
+ * It only happens when the window is small and
+ * This changes slightly the layout for big screens
+ * where there was space for the extracts and the
+ * sister projects and thus it showed like in any
+ * other browser.
+ *
+ * This will only affect IE 7 and lower
+ */
+.searchresult {
+ display: inline !ie;
+}
+.searchresults {
+ margin: 1em 0 1em .4em;
+}
+/* needs extra specificity to override `.mw-body p` selector */
+.mw-body p.mw-search-nonefound {
+ margin: 0;
+}
+.mw-search-interwiki-header {
+ font-weight: bold;
+}
+.mw-search-nonefound + .mw-search-interwiki-header {
+ margin-top: 0;
+}
+div.searchresult {
+ font-size: 95%;
+ width: 38em;
+}
+.mw-search-results {
+ margin-left: 0;
+ float: left;
+}
+.mw-search-results li {
+ padding-bottom: 1.2em;
+ list-style: none;
+ list-style-image: none;
+}
+.mw-search-results li a {
+ font-size: 108%;
+}
+.mw-search-result-data {
+ color: #008000;
+ font-size: 97%;
+}
+.mw-search-profile-tabs {
+ background-color: #f3f3f3;
+ margin-top: 1em;
+ border: 1px solid #c0c0c0;
+}
+.mw-search-profile-tabs div.search-types {
+ float: left;
+ padding-left: 0.25em;
+}
+.mw-search-profile-tabs div.search-types ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+.mw-search-profile-tabs div.search-types ul li {
+ float: left;
+ margin: 0;
+ padding: 0;
+}
+.mw-search-profile-tabs div.search-types ul li a {
+ display: block;
+ padding: 0.5em;
+}
+.mw-search-profile-tabs div.search-types ul li.current a {
+ color: #333;
+ cursor: default;
+}
+.mw-search-profile-tabs div.search-types ul li.current a:hover {
+ text-decoration: none;
+}
+#mw-search-top-table div.results-info {
+ float: right;
+ padding: 0.5em;
+ padding-right: 0.75em;
+ color: #666;
+ font-size: 95%;
+}
+#mw-search-top-table div.oo-ui-actionFieldLayout {
+ float: left;
+}
+fieldset#mw-searchoptions {
+ margin: 0;
+ padding: 0.5em 0.75em 0.75em 0.75em;
+ border: none;
+ background-color: #f9f9f9;
+ border: 1px solid #c0c0c0;
+ border-top-width: 0;
+}
+fieldset#mw-searchoptions legend {
+ display: none;
+}
+fieldset#mw-searchoptions h4 {
+ padding: 0;
+ margin: 0;
+ float: left;
+}
+fieldset#mw-searchoptions table {
+ float: left;
+ margin-right: 3em;
+ border-collapse: collapse;
+}
+fieldset#mw-searchoptions table td {
+ padding: 0 1em 0 0;
+ white-space: nowrap;
+}
+fieldset#mw-searchoptions div.divider {
+ clear: both;
+ border-bottom: 1px solid #ddd;
+ padding-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+td#mw-search-menu {
+ padding-left: 6em;
+ font-size: 85%;
+}
+div#mw-search-interwiki {
+ float: right;
+ width: 18em;
+ border: 1px solid #aaa;
+ margin-top: 2ex;
+}
+div#mw-search-interwiki li {
+ font-size: 95%;
+}
+.mw-search-interwiki-more {
+ float: right;
+ font-size: 90%;
+}
+div#mw-search-interwiki-caption {
+ text-align: center;
+ font-weight: bold;
+ font-size: 95%;
+}
+.mw-search-interwiki-project {
+ font-size: 97%;
+ text-align: left;
+ padding: 0.15em 0.15em 0.2em 0.2em;
+ background-color: #ececec;
+ border-top: 1px solid #bbb;
+}
+span.searchalttitle {
+ font-size: 95%;
+}
+div.searchdidyoumean {
+ font-size: 127%;
+ margin-top: 0.8em;
+ /* Note that this color won't affect the link, as desired. */
+ color: #c00;
+}
+div.searchdidyoumean em {
+ font-weight: bold;
+}
+.searchmatch {
+ font-weight: bold;
+}
+++ /dev/null
-/*!
- * Styling for Special:Upload
- */
-.mw-destfile-warning {
- border: 1px solid #fde29b;
- padding: .5em 1em;
- margin-bottom: 1em;
- color: #705000;
- background-color: #fdf1d1;
-}
--- /dev/null
+/*!
+ * Styling for Special:Upload
+ */
+.mw-destfile-warning {
+ border: 1px solid #fde29b;
+ padding: .5em 1em;
+ margin-bottom: 1em;
+ color: #705000;
+ background-color: #fdf1d1;
+}
color: #347bff;
}
#mw-createaccount-join:hover {
- background-color: #ebf2ff; /* rgba(52, 123, 255, 0.1); */
+ background-color: #ebf2ff; /* rgba( 52, 123, 255, 0.1 ); */
border-color: #859ecc;
box-shadow: none;
}
.mw-number-text.icon-edits {
/* @embed */
- background: url(images/icon-edits.png) no-repeat left center;
+ background: url( images/icon-edits.png ) no-repeat left center;
}
.mw-number-text.icon-pages {
/* @embed */
- background: url(images/icon-pages.png) no-repeat left center;
+ background: url( images/icon-pages.png ) no-repeat left center;
}
.mw-number-text.icon-contributors {
/* @embed */
- background: url(images/icon-contributors.png) no-repeat left center;
+ background: url( images/icon-contributors.png ) no-repeat left center;
}
/*
margin: 0;
padding: 0;
color: #252525;
- font-family: "Linux Libertine", Georgia, Times, serif;
+ font-family: 'Linux Libertine', 'Georgia', 'Times', serif;
font-weight: normal;
font-size: 2.2em;
line-height: 1.2;
// Awful workaround for T113868, while it awaits a better fix.
#mw-t113868 {
- background-image: url(images/ar/button_bold.png), url(images/ar/button_headline.png), url(images/ar/button_italic.png), url(images/ar/button_link.png), url(images/ar/button_nowiki.png), url(images/be-tarask/button_bold.png), url(images/be-tarask/button_italic.png), url(images/be-tarask/button_link.png), url(images/de/button_bold.png), url(images/de/button_italic.png), url(images/en/button_bold.png), url(images/en/button_extlink.png), url(images/en/button_headline.png), url(images/en/button_hr.png), url(images/en/button_image.png), url(images/en/button_italic.png), url(images/en/button_link.png), url(images/en/button_media.png), url(images/en/button_nowiki.png), url(images/en/button_sig.png), url(images/fa/button_bold.png), url(images/fa/button_headline.png), url(images/fa/button_italic.png), url(images/fa/button_link.png), url(images/fa/button_nowiki.png), url(images/ksh/button_italic.png), url(images/ru/button_bold.png), url(images/ru/button_italic.png), url(images/ru/button_link.png);
+ background-image: url( images/ar/button_bold.png ), url( images/ar/button_headline.png ), url( images/ar/button_italic.png ), url( images/ar/button_link.png ), url( images/ar/button_nowiki.png ), url( images/be-tarask/button_bold.png ), url( images/be-tarask/button_italic.png ), url( images/be-tarask/button_link.png ), url( images/de/button_bold.png ), url( images/de/button_italic.png ), url( images/en/button_bold.png ), url( images/en/button_extlink.png ), url( images/en/button_headline.png ), url( images/en/button_hr.png ), url( images/en/button_image.png ), url( images/en/button_italic.png ), url( images/en/button_link.png ), url( images/en/button_media.png ), url( images/en/button_nowiki.png ), url( images/en/button_sig.png ), url( images/fa/button_bold.png ), url( images/fa/button_headline.png ), url( images/fa/button_italic.png ), url( images/fa/button_link.png ), url( images/fa/button_nowiki.png ), url( images/ksh/button_italic.png ), url( images/ru/button_bold.png ), url( images/ru/button_italic.png ), url( images/ru/button_link.png );
}
}
}
- background-color: white;
+ background-color: #fff;
border: 1px solid #ccc;
&.mw-widgets-datetime-calendarWidget-dependent {
margin-top: -1px;
- border-top: 1px solid white;
+ border-top: 1px solid #fff;
}
&-heading {
.oo-ui-buttonElement-button {
width: 100%;
- border: 1px dotted rgba(255,255,255,0.0);
+ border: 1px dotted rgba( 255, 255, 255, 0.0 );
.oo-ui-box-sizing( border-box );
}
}
&:focus &-grid &-cell&-focused .oo-ui-buttonElement-button {
- border-color: rgba(0,0,0,0.3);
+ border-color: rgba( 0, 0, 0, 0.3 );
}
}
padding: 0 1em;
margin: 0;
background-color: #fff;
- color: black;
+ color: #000;
border: solid 1px #ccc;
box-shadow: inset 0 0 0 0 @progressive;
border-radius: 0.1em;
&.oo-ui-flaggedElement-invalid {
.mw-widgets-datetime-dateTimeInputWidget-handle {
- border-color: red;
- box-shadow: inset 0 0 0 0 red;
+ border-color: #f00;
+ box-shadow: inset 0 0 0 0 #f00;
}
.mw-widgets-datetime-dateTimeInputWidget-handle:focus {
- border-color: red;
- box-shadow: inset 0 0 0 0.1em red;
+ border-color: #f00;
+ box-shadow: inset 0 0 0 0.1em #f00;
}
}
}
}
&-editField.mw-widgets-datetime-dateTimeInputWidget-invalid {
- border: 1px solid red;
- box-shadow: inset 0 0 0 0 red;
+ border: 1px solid #f00;
+ box-shadow: inset 0 0 0 0 #f00;
&:focus {
- border: 1px solid red;
- box-shadow: inset 0 0 0 0.1em red;
+ border: 1px solid #f00;
+ box-shadow: inset 0 0 0 0.1em #f00;
}
}
}
.oo-ui-transition( @value1, @value2: X, ... ) {
- @value: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`;
+ @value: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`; // stylelint-disable-line function-comma-space-after, function-parentheses-space-inside, function-whitespace-after
-webkit-transition: @value;
-moz-transition: @value;
transition: @value;
}
-@indicator-size: unit(12 / 16 / 0.8, em);
-@icon-size: unit(24 / 16 / 0.8, em);
+@indicator-size: unit( 12 / 16 / 0.8, em );
+@icon-size: unit( 24 / 16 / 0.8, em );
@quick-ease: 100ms ease;
@progressive: #347bff;
* @constructor
* @inheritdoc
*/
- function ForeignTitle() {
- ForeignTitle.parent.apply( this, arguments );
+ function ForeignTitle( title, namespace ) {
+ // We only need to handle categories here... but we don't know the target language.
+ // So assume that any namespace-like prefix is the 'Category' namespace...
+ title = title.replace( /^(.+?)_*:_*(.*)$/, 'Category:$2' ); // HACK
+ ForeignTitle.parent.call( this, title, namespace );
}
OO.inheritClass( ForeignTitle, mw.Title );
ForeignTitle.prototype.getNamespacePrefix = function () {
.text( this.label )
.attr( 'target', '_blank' )
.on( 'click', function ( e ) {
- // CapsuleMultiSelectWidget really wants to prevent you from clicking the link, don't let it
+ // CapsuleMultiselectWidget really wants to prevent you from clicking the link, don't let it
e.stopPropagation();
} );
NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;
/**
- * Category selector widget. Displays an OO.ui.CapsuleMultiSelectWidget
+ * Category selector widget. Displays an OO.ui.CapsuleMultiselectWidget
* and autocompletes with available categories.
*
* var selector = new mw.widgets.CategorySelector( {
*
* @class mw.widgets.CategorySelector
* @uses mw.Api
- * @extends OO.ui.CapsuleMultiSelectWidget
+ * @extends OO.ui.CapsuleMultiselectWidget
* @mixins OO.ui.mixin.PendingElement
*
* @constructor
/* Setup */
- OO.inheritClass( CategorySelector, OO.ui.CapsuleMultiSelectWidget );
+ OO.inheritClass( CategorySelector, OO.ui.CapsuleMultiselectWidget );
OO.mixinClass( CategorySelector, OO.ui.mixin.PendingElement );
CSP = CategorySelector.prototype;
}
}
-@indicator-size: unit(12 / 16 / 0.8, em);
+@indicator-size: unit( 12 / 16 / 0.8, em );
.mw-widget-dateInputWidget {
display: inline-block;
border: 1px solid #ccc;
border-radius: 0.1em;
line-height: 1.275em;
- background-color: white;
+ background-color: #fff;
}
&.oo-ui-indicatorElement .mw-widget-dateInputWidget-handle > .oo-ui-indicatorElement-indicator {
}
&-calendar {
- background-color: white;
+ background-color: #fff;
margin-top: -2px;
&:focus {
&.oo-ui-flaggedElement-invalid {
.mw-widget-dateInputWidget-handle {
- border-color: red;
- box-shadow: inset 0 0 0 0 red;
+ border-color: #f00;
+ box-shadow: inset 0 0 0 0 #f00;
}
}
* @cfg {boolean} [performSearchOnClick=true] If true, the script will start a search when-
* ever a user hits a suggestion. If false, the text of the suggestion is inserted into the
* text field only.
+ * @cfg {string} [dataLocation='header'] Where the search input field will be
+ * used (header or content).
*/
mw.widgets.SearchInputWidget = function MwWidgetsSearchInputWidget( config ) {
config = $.extend( {
type: 'search',
icon: 'search',
maxLength: undefined,
- performSearchOnClick: true
+ performSearchOnClick: true,
+ dataLocation: 'header'
}, config );
// Parent constructor
.mw-widgets-stashedFileWidget-info {
height: 2.4em;
- background-color: #ffffff;
- border: 1px solid #cccccc;
+ background-color: #fff;
+ border: 1px solid #ccc;
border-radius: 2px;
width: 100%;
display: table-cell;
float: left;
}
> .mw-widgets-stashedFileWidget-fileType {
- color: #888888;
+ color: #888;
float: right;
}
}
&.oo-ui-widget-disabled {
.mw-widgets-stashedFileWidget-info {
- color: #cccccc;
- text-shadow: 0 1px 1px #ffffff;
- border-color: #dddddd;
+ color: #ccc;
+ text-shadow: 0 1px 1px #fff;
+ border-color: #ddd;
background-color: #f3f3f3;
> .oo-ui-iconElement-icon,
height: 5.5em;
text-align: left;
padding: 0;
- background-color: #ffffff;
- border: 1px solid #cccccc;
+ background-color: #fff;
+ border: 1px solid #ccc;
margin-bottom: 0.5em;
vertical-align: middle;
overflow: hidden;
> .mw-widgets-stashedFileWidget-noThumbnail-icon {
opacity: 0.4;
- background-color: #cccccc;
+ background-color: #ccc;
height: 5.5em;
width: 5.5em;
}
}
.mw-widgets-stashedFileWidget-label {
- color: #cccccc;
+ color: #ccc;
right: 0.5em;
}
* @since 1.22
*/
postWithToken: function ( tokenType, params, ajaxOptions ) {
- var api = this;
+ var api = this,
+ abortable;
- return api.getToken( tokenType, params.assert ).then( function ( token ) {
+ return ( abortable = api.getToken( tokenType, params.assert ) ).then( function ( token ) {
params.token = token;
- return api.post( params, ajaxOptions ).then(
+ return ( abortable = api.post( params, ajaxOptions ) ).then(
// If no error, return to caller as-is
null,
// Error handler
api.badToken( tokenType );
// Try again, once
params.token = undefined;
- return api.getToken( tokenType, params.assert ).then( function ( token ) {
+ return ( abortable = api.getToken( tokenType, params.assert ) ).then( function ( token ) {
params.token = token;
- return api.post( params, ajaxOptions );
+ return ( abortable = api.post( params, ajaxOptions ) ).promise();
} );
}
return this;
}
);
- } );
+ } ).promise( { abort: function () {
+ abortable.abort();
+ } } );
},
/**
--- /dev/null
+/**
+ * @class mw.Api.plugin.rollback
+ * @since 1.27
+ */
+( function ( mw, $ ) {
+
+ $.extend( mw.Api.prototype, {
+ /**
+ * Convenience method for `action=rollback`.
+ *
+ * @param {string|mw.Title} page
+ * @param {string} user
+ * @param {Object} [params] Additional parameters
+ * @return {jQuery.Promise}
+ */
+ rollback: function ( page, user, params ) {
+ return this.postWithToken( 'rollback', $.extend( {
+ action: 'rollback',
+ title: String( page ),
+ user: user,
+ uselang: mw.config.get( 'wgUserLanguage' )
+ }, params ) )
+ .then( function ( data ) {
+ return data.rollback;
+ } );
+ }
+ } );
+
+ /**
+ * @class mw.Api
+ * @mixins mw.Api.plugin.rollback
+ */
+
+}( mediaWiki, jQuery ) );
var booklet = this;
return mw.ForeignStructuredUpload.BookletLayout.parent.prototype.initialize.call( this ).then(
function () {
- // Point the CategorySelector to the right wiki
- return booklet.upload.getApi().then(
- function ( api ) {
+ return $.when(
+ // Point the CategorySelector to the right wiki
+ booklet.upload.getApi().then( function ( api ) {
// If this is a ForeignApi, it will have a apiUrl, otherwise we don't need to do anything
if ( api.apiUrl ) {
// Can't reuse the same object, CategorySelector calls #abort on its mw.Api instance
booklet.categoriesWidget.api = new mw.ForeignApi( api.apiUrl );
}
return $.Deferred().resolve();
- },
- function () {
- return $.Deferred().resolve();
- }
+ } ),
+ // Set up booklet fields and license messages to match configuration
+ booklet.upload.loadConfig().then( function ( config ) {
+ var
+ msgPromise,
+ isLocal = booklet.upload.target === 'local',
+ fields = config.fields,
+ msgs = config.licensemessages[ isLocal ? 'local' : 'foreign' ];
+
+ // Hide disabled fields
+ booklet.descriptionField.toggle( !!fields.description );
+ booklet.categoriesField.toggle( !!fields.categories );
+ booklet.dateField.toggle( !!fields.date );
+ // Update form validity
+ booklet.onInfoFormChange();
+
+ // Load license messages from the remote wiki if we don't have these messages locally
+ // (this means that we only load messages from the foreign wiki for custom config)
+ if ( mw.message( 'upload-form-label-own-work-message-' + msgs ).exists() ) {
+ msgPromise = $.Deferred().resolve();
+ } else {
+ msgPromise = booklet.upload.apiPromise.then( function ( api ) {
+ return api.loadMessages( [
+ 'upload-form-label-own-work-message-' + msgs,
+ 'upload-form-label-not-own-work-message-' + msgs,
+ 'upload-form-label-not-own-work-local-' + msgs
+ ] );
+ } );
+ }
+
+ // Update license messages
+ return msgPromise.then( function () {
+ var $labels;
+ booklet.$ownWorkMessage.msg( 'upload-form-label-own-work-message-' + msgs );
+ booklet.$notOwnWorkMessage.msg( 'upload-form-label-not-own-work-message-' + msgs );
+ booklet.$notOwnWorkLocal.msg( 'upload-form-label-not-own-work-local-' + msgs );
+
+ $labels = $( [
+ booklet.$ownWorkMessage[ 0 ],
+ booklet.$notOwnWorkMessage[ 0 ],
+ booklet.$notOwnWorkLocal[ 0 ]
+ ] );
+
+ // Improve the behavior of links inside these labels, which may point to important
+ // things like licensing requirements or terms of use
+ $labels.find( 'a' )
+ .attr( 'target', '_blank' )
+ .on( 'click', function ( e ) {
+ // OO.ui.FieldLayout#onLabelClick is trying to prevent default on all clicks,
+ // which causes the links to not be openable. Don't let it do that.
+ e.stopPropagation();
+ } );
+ } );
+ } )
);
- },
- function () {
- return $.Deferred().resolve();
}
+ ).then(
+ null,
+ // Always resolve, never reject
+ function () { return $.Deferred().resolve(); }
);
};
* @inheritdoc
*/
mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm = function () {
- var fieldset, $ownWorkMessage, $notOwnWorkMessage,
- ownWorkMessage, notOwnWorkMessage, notOwnWorkLocal,
- validTargets = mw.config.get( 'wgForeignUploadTargets' ),
- target = this.target || validTargets[ 0 ] || 'local',
+ var fieldset,
layout = this;
- // upload-form-label-own-work-message-local
- // upload-form-label-own-work-message-shared
- ownWorkMessage = mw.message( 'upload-form-label-own-work-message-' + target );
- // upload-form-label-not-own-work-message-local
- // upload-form-label-not-own-work-message-shared
- notOwnWorkMessage = mw.message( 'upload-form-label-not-own-work-message-' + target );
- // upload-form-label-not-own-work-local-local
- // upload-form-label-not-own-work-local-shared
- notOwnWorkLocal = mw.message( 'upload-form-label-not-own-work-local-' + target );
-
- if ( !ownWorkMessage.exists() ) {
- ownWorkMessage = mw.message( 'upload-form-label-own-work-message-default' );
- }
- if ( !notOwnWorkMessage.exists() ) {
- notOwnWorkMessage = mw.message( 'upload-form-label-not-own-work-message-default' );
- }
- if ( !notOwnWorkLocal.exists() ) {
- notOwnWorkLocal = mw.message( 'upload-form-label-not-own-work-local-default' );
- }
-
- $ownWorkMessage = $( '<p>' ).append( ownWorkMessage.parseDom() )
+ // These elements are filled with text in #initialize
+ // TODO Refactor this to be in one place
+ this.$ownWorkMessage = $( '<p>' )
.addClass( 'mw-foreignStructuredUpload-bookletLayout-license' );
- $notOwnWorkMessage = $( '<div>' ).append(
- $( '<p>' ).append( notOwnWorkMessage.parseDom() ),
- $( '<p>' ).append( notOwnWorkLocal.parseDom() )
- );
- $ownWorkMessage.add( $notOwnWorkMessage ).find( 'a' ).attr( 'target', '_blank' );
+ this.$notOwnWorkMessage = $( '<p>' );
+ this.$notOwnWorkLocal = $( '<p>' );
this.selectFileWidget = new OO.ui.SelectFileWidget( {
showDropTarget: true
} );
this.messageLabel = new OO.ui.LabelWidget( {
- label: $notOwnWorkMessage
+ label: $( '<div>' ).append(
+ this.$notOwnWorkMessage,
+ this.$notOwnWorkLocal
+ )
} );
this.ownWorkCheckbox = new OO.ui.CheckboxInputWidget().on( 'change', function ( on ) {
layout.messageLabel.toggle( !on );
align: 'inline',
label: $( '<div>' ).append(
$( '<p>' ).text( mw.msg( 'upload-form-label-own-work' ) ),
- $ownWorkMessage
+ this.$ownWorkMessage
)
} ),
new OO.ui.FieldLayout( this.messageLabel, {
mustBeBefore: moment().add( 1, 'day' ).locale( 'en' ).format( 'YYYY-MM-DD' ) // Tomorrow
} );
+ this.filenameField = new OO.ui.FieldLayout( this.filenameWidget, {
+ label: mw.msg( 'upload-form-label-infoform-name' ),
+ align: 'top',
+ classes: [ 'mw-foreignStructuredUploa-bookletLayout-small-notice' ],
+ notices: [ mw.msg( 'upload-form-label-infoform-name-tooltip' ) ]
+ } );
+ this.descriptionField = new OO.ui.FieldLayout( this.descriptionWidget, {
+ label: mw.msg( 'upload-form-label-infoform-description' ),
+ align: 'top',
+ classes: [ 'mw-foreignStructuredUploa-bookletLayout-small-notice' ],
+ notices: [ mw.msg( 'upload-form-label-infoform-description-tooltip' ) ]
+ } );
+ this.categoriesField = new OO.ui.FieldLayout( this.categoriesWidget, {
+ label: mw.msg( 'upload-form-label-infoform-categories' ),
+ align: 'top'
+ } );
+ this.dateField = new OO.ui.FieldLayout( this.dateWidget, {
+ label: mw.msg( 'upload-form-label-infoform-date' ),
+ align: 'top'
+ } );
+
fieldset = new OO.ui.FieldsetLayout( {
label: mw.msg( 'upload-form-label-infoform-title' )
} );
fieldset.addItems( [
- new OO.ui.FieldLayout( this.filenameWidget, {
- label: mw.msg( 'upload-form-label-infoform-name' ),
- align: 'top',
- classes: [ 'mw-foreignStructuredUploa-bookletLayout-small-notice' ],
- notices: [ mw.msg( 'upload-form-label-infoform-name-tooltip' ) ]
- } ),
- new OO.ui.FieldLayout( this.descriptionWidget, {
- label: mw.msg( 'upload-form-label-infoform-description' ),
- align: 'top',
- classes: [ 'mw-foreignStructuredUploa-bookletLayout-small-notice' ],
- notices: [ mw.msg( 'upload-form-label-infoform-description-tooltip' ) ]
- } ),
- new OO.ui.FieldLayout( this.categoriesWidget, {
- label: mw.msg( 'upload-form-label-infoform-categories' ),
- align: 'top'
- } ),
- new OO.ui.FieldLayout( this.dateWidget, {
- label: mw.msg( 'upload-form-label-infoform-date' ),
- align: 'top'
- } )
+ this.filenameField,
+ this.descriptionField,
+ this.categoriesField,
+ this.dateField
] );
this.infoForm = new OO.ui.FormLayout( {
classes: [ 'mw-upload-bookletLayout-infoForm' ],
* @inheritdoc
*/
mw.ForeignStructuredUpload.BookletLayout.prototype.onInfoFormChange = function () {
- var layout = this;
- $.when(
- this.filenameWidget.getValidity(),
- this.descriptionWidget.getValidity(),
- this.dateWidget.getValidity()
- ).done( function () {
+ var layout = this,
+ validityPromises = [];
+
+ validityPromises.push( this.filenameWidget.getValidity() );
+ if ( this.descriptionField.isVisible() ) {
+ validityPromises.push( this.descriptionWidget.getValidity() );
+ }
+ if ( this.dateField.isVisible() ) {
+ validityPromises.push( this.dateWidget.getValidity() );
+ }
+
+ $.when.apply( $, validityPromises ).done( function () {
layout.emit( 'infoValid', true );
} ).fail( function () {
layout.emit( 'infoValid', false );
-( function ( mw, OO ) {
+( function ( mw, $, OO ) {
/**
* @class mw.ForeignStructuredUpload
* @extends mw.ForeignUpload
this.descriptions = [];
this.categories = [];
+ // Config for uploads to local wiki.
+ // Can be overridden with foreign wiki config when #loadConfig is called.
+ this.config = mw.config.get( 'wgUploadDialog' );
+
mw.ForeignUpload.call( this, target, apiconfig );
}
OO.inheritClass( ForeignStructuredUpload, mw.ForeignUpload );
+ /**
+ * Get the configuration for the form and filepage from the foreign wiki, if any, and use it for
+ * this upload.
+ *
+ * @return {jQuery.Promise} Promise returning config object
+ */
+ ForeignStructuredUpload.prototype.loadConfig = function () {
+ var deferred,
+ upload = this;
+
+ if ( this.configPromise ) {
+ return this.configPromise;
+ }
+
+ if ( this.target === 'local' ) {
+ deferred = $.Deferred();
+ setTimeout( function () {
+ // Resolve asynchronously, so that it's harder to accidentally write synchronous code that
+ // will break for cross-wiki uploads
+ deferred.resolve( upload.config );
+ } );
+ this.configPromise = deferred.promise();
+ } else {
+ this.configPromise = this.apiPromise.then( function ( api ) {
+ // Get the config from the foreign wiki
+ return api.get( {
+ action: 'query',
+ meta: 'siteinfo',
+ siprop: 'uploaddialog',
+ // For convenient true/false booleans
+ formatversion: 2
+ } ).then( function ( resp ) {
+ // Foreign wiki might be running a pre-1.27 MediaWiki, without support for this
+ if ( resp.query && resp.query.uploaddialog ) {
+ upload.config = resp.query.uploaddialog;
+ }
+ return upload.config;
+ } );
+ } );
+ }
+
+ return this.configPromise;
+ };
+
/**
* Add categories to the upload.
*
* @return {string}
*/
ForeignStructuredUpload.prototype.getText = function () {
- return (
- '== {{int:filedesc}} ==\n' +
- '{{Information' +
- '\n|description=' +
- this.getDescriptions() +
- '\n|date=' +
- this.getDate() +
- '\n|source=' +
- this.getSource() +
- '\n|author=' +
- this.getUser() +
- '\n}}\n\n' +
- '== {{int:license-header}} ==\n' +
- this.getLicense() +
- '\n\n' +
- this.getCategories()
- );
+ return this.config.format.filepage
+ // Replace "numbered parameters" with the given information
+ .replace( '$DESCRIPTION', this.getDescriptions() )
+ .replace( '$DATE', this.getDate() )
+ .replace( '$SOURCE', this.getSource() )
+ .replace( '$AUTHOR', this.getUser() )
+ .replace( '$LICENSE', this.getLicense() )
+ .replace( '$CATEGORIES', this.getCategories() );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ ForeignStructuredUpload.prototype.getComment = function () {
+ return this.config.comment
+ .replace( '$PAGENAME', mw.config.get( 'wgPageName' ) )
+ .replace( '$HOST', location.host );
};
/**
for ( i = 0; i < this.descriptions.length; i++ ) {
desc = this.descriptions[ i ];
- templateCalls.push( '{{' + desc.language + '|1=' + desc.text + '}}' );
+ templateCalls.push(
+ this.config.format.description
+ .replace( '$LANGUAGE', desc.language )
+ .replace( '$TEXT', desc.text )
+ );
}
return templateCalls.join( '\n' );
var i, cat, categoryLinks = [];
if ( this.categories.length === 0 ) {
- return '{{subst:unc}}';
+ return this.config.format.uncategorized;
}
for ( i = 0; i < this.categories.length; i++ ) {
* @return {string}
*/
ForeignStructuredUpload.prototype.getLicense = function () {
- // Make sure this matches the messages for different targets in
- // mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm
- return this.target === 'shared' ? '{{self|cc-by-sa-4.0}}' : '';
+ return this.config.format.license;
};
/**
* @return {string}
*/
ForeignStructuredUpload.prototype.getSource = function () {
- return '{{own}}';
+ return this.config.format.ownwork;
};
/**
};
mw.ForeignStructuredUpload = ForeignStructuredUpload;
-}( mediaWiki, OO ) );
+}( mediaWiki, jQuery, OO ) );
// actual API call methods to wait for the apiPromise to resolve
// before continuing.
mw.Upload.call( this, null );
-
- if ( this.target !== 'local' ) {
- // Keep these untranslated. We don't know the content language of the foreign wiki, best to
- // stick to English in the text.
- this.setComment( 'Cross-wiki upload from ' + location.host );
- }
}
OO.inheritClass( ForeignUpload, mw.Upload );
// Thumbnails
/\/[a-f0-9]\/[a-f0-9]{2}\/([^\s\/]+)\/[^\s\/]+-[^\s\/]*$/,
- // Thumbnails in non-hashed upload directories
- /\/([^\s\/]+)\/[^\s\/]+-(?:\1|thumbnail)[^\s\/]*$/,
-
// Full size images
/\/[a-f0-9]\/[a-f0-9]{2}\/([^\s\/]+)$/,
+ // Thumbnails in non-hashed upload directories
+ /\/([^\s\/]+)\/[^\s\/]+-(?:\1|thumbnail)[^\s\/]*$/,
+
// Full-size images in non-hashed upload directories
/\/([^\s\/]+)$/
],
return this.upload.getApi().then(
function ( api ) {
- // If the user can't upload anything, don't give them the option to.
- return api.getUserInfo().then(
- function ( userInfo ) {
+ return $.when(
+ booklet.upload.loadConfig(),
+ // If the user can't upload anything, don't give them the option to.
+ api.getUserInfo().then( function ( userInfo ) {
if ( userInfo.rights.indexOf( 'upload' ) === -1 ) {
// TODO Use a better error message when not all logged-in users can upload
booklet.getPage( 'upload' ).$element.msg( 'api-error-mustbeloggedin' );
}
return $.Deferred().resolve();
- },
- function () {
- return $.Deferred().resolve();
- }
+ } )
+ ).then(
+ null,
+ // Always resolve, never reject
+ function () { return $.Deferred().resolve(); }
);
},
function ( errorMsg ) {
.apihelp-flags {
font-size: smaller;
float: right;
- border: 1px solid black;
+ border: 1px solid #000;
padding: 0.25em;
width: 20em;
}
.apihelp-deprecated, .apihelp-flag-deprecated,
.apihelp-flag-internal strong {
font-weight: bold;
- color: red;
+ color: #f00;
}
.apihelp-unknown {
.mw-json th,
.mw-json td {
- border: 1px solid gray;
+ border: 1px solid #808080;
font-size: 16px;
padding: 0.5em 1em;
}
}
.mw-json table caption {
- color: gray;
+ color: #808080;
display: inline-block;
font-size: 10px;
font-style: italic;
font-size: 13px;
/* IE-hack for display: inline-block */
zoom: 1;
- *display:inline;
+ *display: inline;
}
.mw-debug-panelink {
height: 300px;
overflow: scroll;
display: none;
+ font-family: monospace;
font-size: 11px;
background-color: #e1eff2;
box-sizing: border-box;
th,
td,
table {
- border: 1px solid #D0DBB3;
+ border: 1px solid #d0dbb3;
border-collapse: collapse;
margin: 0;
}
}
th {
- background-color: #F1F7E2;
+ background-color: #f1f7e2;
font-weight: bold;
}
td {
- background-color: white;
+ background-color: #fff;
}
}
zoom: 1;
*display: inline; /* IE7 and below */
/* @embed */
- background: url(mediawiki.feedback.spinner.gif);
+ background: url( mediawiki.feedback.spinner.gif );
width: 18px;
height: 18px;
}
/* SVG support using a transparent gradient to guarantee cross-browser
* compatibility (browsers able to understand gradient syntax support also SVG).
* http://pauginer.tumblr.com/post/36614680636/invisible-gradient-technique */
- background-image: url(images/feed-icon.png);
+ background-image: url( images/feed-icon.png );
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/feed-icon.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/feed-icon.svg );
background-position: center left;
background-repeat: no-repeat;
background-size: 12px 12px;
}
.mediawiki-filewarning-footer {
- color: #888888;
+ color: #888;
}
.empty {
counter-increment: list-item;
}
.hlist ol > li:before {
- content: counter(list-item) " ";
+ content: counter( list-item ) " ";
}
.hlist dd ol > li:first-child:before,
.hlist dt ol > li:first-child:before,
.hlist li ol > li:first-child:before {
- content: "(" counter(list-item) " ";
+ content: "(" counter( list-item ) " ";
}
}
.mw-htmlform-invalid-input td.mw-input input {
- border-color: red;
+ border-color: #f00;
}
.mw-htmlform-flatlist div.mw-htmlform-flatlist-item {
/* SVG support using a transparent gradient to guarantee cross-browser
* compatibility (browsers able to understand gradient syntax support also SVG).
* http://pauginer.tumblr.com/post/36614680636/invisible-gradient-technique */
- background-image: url(images/question.png);
+ background-image: url( images/question.png );
/* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/question.svg);
+ background-image: linear-gradient( transparent, transparent ), url( images/question.svg );
background-repeat: no-repeat;
background-size: 13px 13px;
display: inline-block;
.mw-icon-question:lang(ar),
.mw-icon-question:lang(fa),
.mw-icon-question:lang(ur) {
- -webkit-transform: scaleX(-1);
- -ms-transform: scaleX(-1);
- transform: scaleX(-1);
+ -webkit-transform: scaleX( -1 );
+ -ms-transform: scaleX( -1 );
+ transform: scaleX( -1 );
}
margin: 1em 0;
}
-.oo-ui-fieldLayout.mw-htmlform-ooui-header-empty,
-.oo-ui-fieldLayout.mw-htmlform-ooui-header-empty .oo-ui-fieldLayout-body {
- display: none;
-}
-
-.oo-ui-fieldLayout.mw-htmlform-ooui-header-errors {
- /* Override 'display: none' from above */
- display: block;
-}
-
.mw-htmlform-ooui .mw-htmlform-submit-buttons {
margin-top: 1em;
}
width: 39%;
}
-.oo-ui-fieldLayout .oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline {
- margin-bottom: 0;
+.mw-htmlform-flatlist .oo-ui-optionWidget,
+.mw-htmlform-flatlist .oo-ui-multioptionWidget {
+ display: inline-block;
+ margin-right: 1em;
}
} catch ( e ) {
fallback = parser.settings.messages.get( key );
mw.log.warn( 'mediawiki.jqueryMsg: ' + key + ': ' + e.message );
+ mw.track( 'mediawiki.jqueryMsg.error', {
+ messageKey: key,
+ errorMessage: e.message
+ } );
return $( '<span>' ).text( fallback );
}
};
return result === null ? null : result.join( '' );
}
- asciiAlphabetLiteral = makeRegexParser( /[A-Za-z]+/ );
+ asciiAlphabetLiteral = makeRegexParser( /^[A-Za-z]+/ );
htmlDoubleQuoteAttributeValue = makeRegexParser( /^[^"]*/ );
htmlSingleQuoteAttributeValue = makeRegexParser( /^[^']*/ );
return result;
}
+ // <nowiki>...</nowiki> tag. The tags are stripped and the contents are returned unparsed.
+ function nowiki() {
+ var parsedResult, plainText,
+ result = null;
+
+ parsedResult = sequence( [
+ makeStringParser( '<nowiki>' ),
+ // We use a greedy non-backtracking parser, so we must ensure here that we don't take too much
+ makeRegexParser( /^.*?(?=<\/nowiki>)/ ),
+ makeStringParser( '</nowiki>' )
+ ] );
+ if ( parsedResult !== null ) {
+ plainText = parsedResult[ 1 ];
+ result = [ 'CONCAT' ].concat( plainText );
+ }
+
+ return result;
+ }
+
templateName = transform(
// see $wgLegalTitleChars
// not allowing : due to the need to catch "PLURAL:$1"
wikilink,
extlink,
replacement,
+ nowiki,
html,
literal
] );
*
* This method is only available when jqueryMsg is loaded.
*
+ * @since 1.27
* @method parseDom
* @member mw.Message
* @return {jQuery}
*/
jobs = [],
- // Selector cache for the marker element. Use getMarker() to get/use the marker!
- $marker = null,
+ // For getMarker()
+ marker = null,
- // For #addEmbeddedCSS
+ // For addEmbeddedCSS()
cssBuffer = '',
cssBufferTimer = null,
- cssCallbacks = $.Callbacks();
+ cssCallbacks = $.Callbacks(),
+ isIEto9 = 'documentMode' in document && document.documentMode <= 9,
+ isIE9 = document.documentMode === 9;
function getMarker() {
- if ( !$marker ) {
+ if ( !marker ) {
// Cache
- $marker = $( 'meta[name="ResourceLoaderDynamicStyles"]' );
- if ( !$marker.length ) {
- mw.log( 'No <meta name="ResourceLoaderDynamicStyles"> found, inserting dynamically' );
- $marker = $( '<meta>' ).attr( 'name', 'ResourceLoaderDynamicStyles' ).appendTo( 'head' );
+ marker = document.querySelector( 'meta[name="ResourceLoaderDynamicStyles"]' );
+ if ( !marker ) {
+ mw.log( 'Create <meta name="ResourceLoaderDynamicStyles"> dynamically' );
+ marker = $( '<meta>' ).attr( 'name', 'ResourceLoaderDynamicStyles' ).appendTo( 'head' )[ 0 ];
}
}
- return $marker;
+ return marker;
}
/**
*
* @private
* @param {string} text CSS text
- * @param {HTMLElement|jQuery} [nextnode=document.head] The element where the style tag
+ * @param {Node} [nextNode] The element where the style tag
* should be inserted before
* @return {HTMLElement} Reference to the created style element
*/
- function newStyleTag( text, nextnode ) {
+ function newStyleTag( text, nextNode ) {
var s = document.createElement( 'style' );
// Support: IE
- // Must attach to document before setting cssText (bug 33305)
- if ( nextnode ) {
- $( nextnode ).before( s );
+ // Must attach style element to the document before setting cssText (T35305)
+ if ( nextNode && nextNode.parentNode ) {
+ nextNode.parentNode.insertBefore( s, nextNode );
} else {
document.getElementsByTagName( 'head' )[ 0 ].appendChild( s );
}
cssBuffer = '';
}
- // By default, always create a new <style>. Appending text to a <style>
- // tag is bad as it means the contents have to be re-parsed (bug 45810).
+ // By default, always create a new <style>. Appending text to a <style> tag is
+ // is a performance anti-pattern as it requires CSS to be reparsed (T47810).
//
- // Except, of course, in IE 9 and below. In there we default to re-using and
- // appending to a <style> tag due to the IE stylesheet limit (bug 31676).
- if ( 'documentMode' in document && document.documentMode <= 9 ) {
-
- $style = getMarker().prev();
- // Verify that the element before the marker actually is a
- // <style> tag and one that came from ResourceLoader
- // (not some other style tag or even a `<meta>` or `<script>`).
+ // Support: IE 6-9
+ // Try to re-use existing <style> tags due to the IE stylesheet limit (T33676).
+ if ( isIEto9 ) {
+ $style = $( getMarker() ).prev();
+ // Verify that the element before the marker actually is a <style> tag created
+ // by mw.loader (not some other style tag, or e.g. a <meta> tag).
if ( $style.data( 'ResourceLoaderDynamicStyleTag' ) ) {
- // There's already a dynamic <style> tag present and
- // we are able to append more to it.
- styleEl = $style.get( 0 );
- // Support: IE6-10
+ styleEl = $style[ 0 ];
+ // Support: IE 6-10
if ( styleEl.styleSheet ) {
try {
- // Support: IE9
- // We can't do styleSheet.cssText += cssText, since IE9 mangles this property on
- // write, dropping @media queries from the CSS text. If we read it and used its
- // value, we would accidentally apply @media-specific styles to all media. (T108727)
- if ( document.documentMode === 9 ) {
+ // Support: IE 9
+ // We can't do styleSheet.cssText += cssText in IE9 because it mangles cssText on
+ // write (removes @media queries). If we read it and used its value, we'd
+ // accidentally apply @media-specific styles to all media. (T108727)
+ if ( isIE9 ) {
newCssText = $style.data( 'ResourceLoaderDynamicStyleTag' ) + cssText;
styleEl.styleSheet.cssText = newCssText;
$style.data( 'ResourceLoaderDynamicStyleTag', newCssText );
fireCallbacks();
return;
}
+ // Else: No existing tag to reuse. Continue below and create the first one.
}
$style = $( newStyleTag( cssText, getMarker() ) );
- if ( document.documentMode === 9 ) {
- // Support: IE9
- // Preserve original CSS text because IE9 mangles it on write
- $style.data( 'ResourceLoaderDynamicStyleTag', cssText );
- } else {
- $style.data( 'ResourceLoaderDynamicStyleTag', true );
+ if ( isIEto9 ) {
+ if ( isIE9 ) {
+ $style.data( 'ResourceLoaderDynamicStyleTag', cssText );
+ } else {
+ $style.data( 'ResourceLoaderDynamicStyleTag', true );
+ }
}
fireCallbacks();
var el = document.createElement( 'link' );
// Support: IE
// Insert in document *before* setting href
- getMarker().before( el );
+ $( getMarker() ).before( el );
el.rel = 'stylesheet';
if ( media && media !== 'all' ) {
el.media = media;
cursor: pointer;
opacity: 0;
- -webkit-transform: translateX(35px);
- transform: translateX(35px);
+ -webkit-transform: translateX( 35px );
+ transform: translateX( 35px );
-webkit-transition: opacity 0.35s ease-in-out, -webkit-transform 0.35s ease-in-out;
transition: opacity 0.35s ease-in-out, transform 0.35s ease-in-out;
}
.mw-notification-visible {
opacity: 1;
- -webkit-transform: translateX(0);
- transform: translateX(0);
+ -webkit-transform: translateX( 0 );
+ transform: translateX( 0 );
}
.mw-notification-replaced {
opacity: 0;
- -webkit-transform: translateY(-35px);
- transform: translateY(-35px);
+ -webkit-transform: translateY( -35px );
+ transform: translateY( -35px );
pointer-events: none;
}
}
.mw-notification-type-warn {
- border-color: #F5BE00; /* yellow */
- background-color: #FFFFE8;
+ border-color: #f5be00; /* yellow */
+ background-color: #ffffe8;
}
.mw-notification-type-error {
- border-color: #EB3941; /* red */
- background-color: #FFF8F8;
+ border-color: #eb3941; /* red */
+ background-color: #fff8f8;
}
+.mw-empty-elt,
.mw-empty-li {
display: none;
}
.suggestions a.mw-searchSuggest-link:hover,
.suggestions a.mw-searchSuggest-link:active,
.suggestions a.mw-searchSuggest-link:focus {
- color: black;
+ color: #000;
text-decoration: none;
}
.suggestions-result-current a.mw-searchSuggest-link:hover,
.suggestions-result-current a.mw-searchSuggest-link:active,
.suggestions-result-current a.mw-searchSuggest-link:focus {
- color: white;
+ color: #fff;
}
.suggestions a.mw-searchSuggest-link .special-query {
RE_IP_BYTE = '(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])',
RE_IP_ADD = '(?:' + RE_IP_BYTE + '\\.){3}' + RE_IP_BYTE;
- return address.search( new RegExp( '^' + RE_IP_ADD + block + '$' ) ) !== -1;
+ return ( new RegExp( '^' + RE_IP_ADD + block + '$' ).test( address ) );
},
/**
'[0-9A-Fa-f]{1,4}' + '(?::' + '[0-9A-Fa-f]{1,4}' + '){7}' +
')';
- if ( address.search( new RegExp( '^' + RE_IPV6_ADD + block + '$' ) ) !== -1 ) {
+ if ( new RegExp( '^' + RE_IPV6_ADD + block + '$' ).test( address ) ) {
return true;
}
- RE_IPV6_ADD = // contains one "::" in the middle (single '::' check below)
- '[0-9A-Fa-f]{1,4}' + '(?:::?' + '[0-9A-Fa-f]{1,4}' + '){1,6}';
+ // contains one "::" in the middle (single '::' check below)
+ RE_IPV6_ADD = '[0-9A-Fa-f]{1,4}' + '(?:::?' + '[0-9A-Fa-f]{1,4}' + '){1,6}';
- return address.search( new RegExp( '^' + RE_IPV6_ADD + block + '$' ) ) !== -1
- && address.search( /::/ ) !== -1 && address.search( /::.*::/ ) === -1;
+ return (
+ new RegExp( '^' + RE_IPV6_ADD + block + '$' ).test( address )
+ && /::/.test( address )
+ && !/::.*::/.test( address )
+ );
},
/**
* Add the appropriate prefix to the accesskey shown in the tooltip.
*
* If the `$nodes` parameter is given, only those nodes are updated;
- * otherwise, depending on browser support, we update either all elements
- * with accesskeys on the page or a bunch of elements which are likely to
- * have them on core skins.
+ * otherwise we update all elements with accesskeys on the page.
*
* @method updateTooltipAccessKeys
* @param {Array|jQuery} [$nodes] A jQuery object, or array of nodes to update.
*/
mw.log.deprecate( util, 'updateTooltipAccessKeys', function ( $nodes ) {
if ( !$nodes ) {
- if ( document.querySelectorAll ) {
- // If we're running on a browser where we can do this efficiently,
- // just find all elements that have accesskeys. We can't use jQuery's
- // polyfill for the selector since looping over all elements on page
- // load might be too slow.
- $nodes = $( document.querySelectorAll( '[accesskey]' ) );
- } else {
- // Otherwise go through some elements likely to have accesskeys rather
- // than looping over all of them. Unfortunately this will not fully
- // work for custom skins with different HTML structures. Input, label
- // and button should be rare enough that no optimizations are needed.
- $nodes = $( '#column-one a, #mw-head a, #mw-panel a, #p-logo a, input, label, button' );
- }
+ $nodes = $( '[accesskey]' );
} else if ( !( $nodes instanceof $ ) ) {
$nodes = $( $nodes );
}
ul.mw-gallery-packed-overlay li.gallerybox div.gallerytextwrapper,
ul.mw-gallery-packed-hover li.gallerybox.mw-gallery-focused div.gallerytextwrapper {
position: absolute;
- background: white;
+ background: #fff;
background: rgba(255, 255, 255, 0.8);
padding: 5px 10px;
bottom: 0;
return;
}
$( function () {
- var $patrolLinks = $( '.patrollink a' );
+ var $patrolLinks = $( '.patrollink[data-mw="interface"] a' );
$patrolLinks.on( 'click', function ( e ) {
- var $spinner, href, rcid, apiRequest;
+ var $spinner, rcid, apiRequest;
- // Start preloading the notification module (normally loaded by mw.notify())
+ // Preload the notification module for mw.notify
mw.loader.load( 'mediawiki.notification' );
// Hide the link and create a spinner to show it inside the brackets.
} );
$( this ).hide().after( $spinner );
- href = $( this ).attr( 'href' );
- rcid = mw.util.getParamValue( 'rcid', href );
+ rcid = mw.util.getParamValue( 'rcid', this.href );
apiRequest = new mw.Api();
apiRequest.postWithToken( 'patrol', {
}
// Add accesskey hints to the tooltips
- if ( document.querySelectorAll ) {
- // If we're running on a browser where we can do this efficiently,
- // just find all elements that have accesskeys. We can't use jQuery's
- // polyfill for the selector since looping over all elements on page
- // load might be too slow.
- $nodes = $( document.querySelectorAll( '[accesskey]' ) );
- } else {
- // Otherwise go through some elements likely to have accesskeys rather
- // than looping over all of them. Unfortunately this will not fully
- // work for custom skins with different HTML structures. Input, label
- // and button should be rare enough that no optimizations are needed.
- $nodes = $( '#column-one a, #mw-head a, #mw-panel a, #p-logo a, input, label, button' );
- }
- $nodes.updateTooltipAccessKeys();
+ $( '[accesskey]' ).updateTooltipAccessKeys();
// Infuse OOUI widgets, if any are present
$oouiNodes = $( '[data-ooui]' );
--- /dev/null
+/*!
+ * Enhance rollback links by using asynchronous API requests,
+ * rather than navigating to an action page.
+ *
+ * @since 1.27
+ * @author Timo Tijhof
+ */
+( function ( mw, $ ) {
+
+ $( function () {
+ $( '.mw-rollback-link' ).on( 'click', 'a[data-mw="interface"]', function ( e ) {
+ var api, $spinner,
+ $link = $( this ),
+ url = this.href,
+ page = mw.util.getParamValue( 'title', url ),
+ user = mw.util.getParamValue( 'from', url );
+
+ if ( !page || !user ) {
+ // Let native browsing handle the link
+ return true;
+ }
+
+ // Preload the notification module for mw.notify
+ mw.loader.load( 'mediawiki.notification' );
+
+ // Remove event handler so that next click (re-try) uses server action
+ $( e.delegateTarget ).off( 'click' );
+
+ // Hide the link and create a spinner to show it inside the brackets.
+ $spinner = $.createSpinner( { size: 'small', type: 'inline' } );
+ $link.hide().after( $spinner );
+
+ api = new mw.Api();
+ api.rollback( page, user )
+ .then( function ( data ) {
+ mw.notify( $.parseHTML( data.messageHtml ), {
+ title: mw.msg( 'actioncomplete' )
+ } );
+
+ // Remove link container and the subsequent text node containing " | ".
+ if ( e.delegateTarget.nextSibling && e.delegateTarget.nextSibling.nodeType === Node.TEXT_NODE ) {
+ $( e.delegateTarget.nextSibling ).remove();
+ }
+ $( e.delegateTarget ).remove();
+ }, function ( errorCode, data ) {
+ var message = data && data.error && data.error.messageHtml
+ ? $.parseHTML( data.error.messageHtml )
+ : mw.msg( 'rollbackfailed' ),
+ type = errorCode === 'alreadyrolled' ? 'warn' : 'error';
+
+ mw.notify( message, {
+ type: type,
+ title: mw.msg( 'rollbackfailed' ),
+ autoHide: false
+ } );
+
+ // Restore the link (enables user to try again)
+ $spinner.remove();
+ $link.show();
+ } );
+
+ e.preventDefault();
+ } );
+ } );
+
+}( mediaWiki, jQuery ) );
$links.click( function ( e ) {
var action, api, $link;
- // Start preloading the notification module (normally loaded by mw.notify())
+ // Preload the notification module for mw.notify
mw.loader.load( 'mediawiki.notification' );
action = mwUriGetAction( this.href );
if ( action !== 'watch' && action !== 'unwatch' ) {
- // Could not extract target action from link url,
- // let native browsing handle it further
+ // Let native browsing handle the link
return true;
}
e.preventDefault();
--- /dev/null
+// Use DMY date format for Moment.js, in accordance with MediaWiki's date formatting routines.
+// This affects English only (and languages without localisations, that fall back to English).
+// http://momentjs.com/docs/#/customization/long-date-formats/
+/*global moment */
+moment.locale( 'en', {
+ longDateFormat: {
+ // Unchanged, but have to be repeated here:
+ LT: 'h:mm A',
+ LTS: 'h:mm:ss A',
+ // Customized:
+ L: 'DD/MM/YYYY',
+ LL: 'D MMMM YYYY',
+ LLL: 'D MMMM YYYY LT',
+ LLLL: 'dddd, D MMMM YYYY LT'
+ }
+} );
-// Use DMY date format for Moment.js, in accordance with MediaWiki's date formatting routines.
-// This affects English only (and languages without localisations, that fall back to English).
-// http://momentjs.com/docs/#/customization/long-date-formats/
/*global moment, mw */
-moment.locale( 'en', {
- longDateFormat: {
- // Unchanged, but have to be repeated here:
- LT: 'h:mm A',
- LTS: 'h:mm:ss A',
- // Customized:
- L: 'DD/MM/YYYY',
- LL: 'D MMMM YYYY',
- LLL: 'D MMMM YYYY LT',
- LLLL: 'dddd, D MMMM YYYY LT'
- }
-} );
// HACK: Overwrite moment's i18n with MediaWiki's for the current language so that
// wgTranslateNumerals is respected.
if ( mw.config.get( 'wgTranslateNumerals' ) ) {
for ( i = 0; i < 10; i++ ) {
if ( table[ i ] !== undefined ) {
- s = s.replace( new RegExp( mw.RegExp.escape( i ), 'g' ), table[ i ] );
+ s = s.replace( new RegExp( i, 'g' ), table[ i ] );
}
}
}
'ResourceLoaderTestModule' => "$testDir/phpunit/ResourceLoaderTestCase.php",
'ResourceLoaderFileModuleTestModule' => "$testDir/phpunit/ResourceLoaderTestCase.php",
'TestUser' => "$testDir/phpunit/includes/TestUser.php",
+ 'TestUserRegistry' => "$testDir/phpunit/includes/TestUserRegistry.php",
'LessFileCompilationTest' => "$testDir/phpunit/LessFileCompilationTest.php",
# tests/phpunit/includes
'UserWrapper' => "$testDir/phpunit/includes/api/UserWrapper.php",
'RandomImageGenerator' => "$testDir/phpunit/includes/api/RandomImageGenerator.php",
+ # tests/phpunit/includes/auth
+ 'MediaWiki\\Auth\\AuthenticationRequestTestCase' =>
+ "$testDir/phpunit/includes/auth/AuthenticationRequestTestCase.php",
+
# tests/phpunit/includes/changes
'TestRecentChangesHelper' => "$testDir/phpunit/includes/changes/TestRecentChangesHelper.php",
-@chrome @firefox @vagrant
+@chrome @firefox @skip @vagrant
Feature: Edit Page
Scenario: Create and edit page
-@chrome @firefox @vagrant
+@chrome @firefox @skip @vagrant
Feature: View History
Scenario: Edit page and view history
* @file
* @ingroup Testing
*/
+use MediaWiki\MediaWikiServices;
/**
* @ingroup Testing
# add a namespace shadowing a interwiki link, to test
# proper precedence when resolving links. (bug 51680)
$wgExtraNamespaces[100] = 'MemoryAlpha';
+ $wgExtraNamespaces[101] = 'MemoryAlpha talk';
// XXX: tests won't run without this (for CACHE_DB)
if ( $wgMainCacheType === CACHE_DB ) {
Hooks::clear( 'InterwikiLoadPrefix' );
}
+ /**
+ * Reset the Title-related services that need resetting
+ * for each test
+ */
+ public static function resetTitleServices() {
+ $services = MediaWikiServices::getInstance();
+ $services->resetServiceForTesting( 'TitleFormatter' );
+ $services->resetServiceForTesting( 'TitleParser' );
+ $services->resetServiceForTesting( '_MediaWikiTitleCodec' );
+ $services->resetServiceForTesting( 'LinkRenderer' );
+ $services->resetServiceForTesting( 'LinkRendererFactory' );
+ }
+
public function setupRecorder( $options ) {
if ( isset( $options['record'] ) ) {
$this->recorder = new DbTestRecorder( $this );
'wgMaxTocLevel' => $maxtoclevel,
'wgCapitalLinks' => true,
'wgNoFollowLinks' => true,
- 'wgNoFollowDomainExceptions' => [],
+ 'wgNoFollowDomainExceptions' => [ 'no-nofollow.org' ],
'wgThumbnailScriptPath' => false,
'wgUseImageResize' => true,
'wgSVGConverter' => 'null',
'wgExperimentalHtmlIds' => false,
'wgExternalLinkTarget' => false,
'wgHtml5' => true,
- 'wgWellFormedXml' => true,
'wgAdaptiveMessageCache' => true,
'wgDisableLangConversion' => false,
'wgDisableTitleConversion' => false,
MWTidy::destroySingleton();
RepoGroup::destroySingleton();
+ self::resetTitleServices();
+
return $context;
}
!! end
+!! test
+<nowiki> inside of #tag:pre
+!! wikitext
+{{#tag:pre|Foo <nowiki>→bar</nowiki>}}
+!! html/php
+<pre>Foo →bar</pre>
+
+!! html/parsoid
+<pre about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"#tag:pre","function":"#tag"},"params":{"1":{"wt":"Foo <nowiki>&rarr;bar</nowiki>"}},"i":0}}]}'>Foo <span typeof="mw:Entity">→</span>bar</pre>
+!! end
+
!! test
<nowiki> and <pre> preference (first one wins)
!! wikitext
!! wikitext
{{echo|[{{fullurl:{{FULLPAGENAME}}|action=edit}} bar]}}
!! html
-<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[{{fullurl:{{FULLPAGENAME}}|action=edit}} bar]"}},"i":0}}]}'>[Main Page bar]</p>
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[{{fullurl:{{FULLPAGENAME}}|action=edit}} bar]"}},"i":0}}]}'>[Main_Page bar]</p>
!! end
!! test
</p>
!! end
+!! test
+External links: nofollow domain exception
+!! wikitext
+A [https://no-nofollow.org/foobar link], and another [https://example.org link].
+!! html
+<p>A <a class="external text" href="https://no-nofollow.org/foobar">link</a>, and another <a rel="nofollow" class="external text" href="https://example.org">link</a>.
+</p>
+!!end
+
!! test
External image
!! wikitext
</p><p>(<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>)
</p>
!! html/parsoid
-<p>(<a typeof="mw:ExpandedAttrs" about="#mwt2" rel="mw:ExtLink" href="http://example.com/hi" data-parsoid='{"stx":"url","a":{"href":"http://example.com/hi"},"sa":{"href":"http://example.com/{{echo|hi}}"}}' data-mw='{"attribs":[[{"txt":"href"},{"html":"http://example.com/<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]],&quot;dsr&quot;:[20,31,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;hi&quot;}},&quot;i&quot;:0}}]}\">hi</span>"}]]}'>http://example.com/hi</a>)</p>
+<p>(<a typeof="mw:ExpandedAttrs" about="#mwt2" rel="mw:ExtLink" href="http://example.com/hi" data-parsoid='{"stx":"url","a":{"href":"http://example.com/hi"},"sa":{"href":"http://example.com/{{echo|hi}}"}}' data-mw='{"attribs":[[{"txt":"href"},{"html":"http://example.com/<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[20,31,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"hi\"}},\"i\":0}}]}'>hi</span>"}]]}'>http://example.com/hi</a>)</p>
<p>(<a rel="mw:ExtLink" href="http://example.com" data-parsoid='{"stx":"url","a":{"href":"http://example.com"},"sa":{"href":"http://example.com<!-- hi -->"}}'>http://example.com</a>)</p>
!! end
text
<nowiki>*</nowiki>text
<nowiki>[[foo]]</nowiki>
-<nowiki>*a [[foo]]</nowiki>
+<nowiki>*</nowiki>a <nowiki>[[foo]]</nowiki>
!! end
!! test
!! options
parsoid=html2wt
!! html/parsoid
-<a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid='{"stx":"piped","a":{"href":"./Foo"},"sa":{"href":"Foo"},"dsr":[0,11,6,2]}'>Bar</a>
+<a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid='{"stx":"piped","a":{"href":"./Foo"},"sa":{"href":"Foo"}}'>Bar</a>
<a rel="mw:WikiLink" href="./Foo" title="Foo">Bar</a>
<a rel="mw:WikiLink" href="http://en.wikipedia.org/wiki/Foo" title="Foo">Bar</a>
<a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" title="Foo">Bar</a>
|}
!! end
+!! test
+Testing serialization after deletion in references
+!! options
+parsoid={
+ "modes": ["wt2wt"],
+ "changes": [
+ ["#x", "remove"]
+ ]
+}
+!! wikitext
+hi <ref><div id="x">ho</div></ref>
+
+<references />
+!! wikitext/edited
+hi <ref></ref>
+
+<references />
+!! end
+
!!test
Testing serialization after deletion of table cells
!!options
|}
!!end
+!! test
+Testing selser after addition of new row before first row (T125419)
+!! options
+parsoid={
+ "modes": ["wt2wt", "selser"],
+ "changes": [
+ [ "tr", "before", "<tr><td>X</td></tr>" ]
+ ]
+}
+!! wikitext
+{|
+|a
+|}
+!! wikitext/edited
+{|
+|X
+|-
+|a
+|}
+!! end
+
+!! test
+Serialize new table rows in a HTML table using HTML tags
+!! options
+parsoid={
+ "modes": ["wt2wt", "selser"],
+ "changes": [
+ [ "tr", "before", "<tr><td>X</td></tr>" ]
+ ]
+}
+!! wikitext
+<table><tr><td>a</td></tr></table>
+!! wikitext/edited
+<table><tr><td>X</td></tr><tr><td>a</td></tr></table>
+!! end
+
+!! test
+Serialize new table cells in a HTML row using HTML tags
+!! options
+parsoid={
+ "modes": ["wt2wt", "selser"],
+ "changes": [
+ [ "td", "before", "<td>X</td>" ]
+ ]
+}
+!! wikitext
+<table><tr><td>a</td></tr></table>
+!! wikitext/edited
+<table><tr><td>X</td><td>a</td></tr></table>
+!! end
+
+!! test
+Wikitext tables can be nested inside HTML tables
+!! options
+parsoid=html2wt
+!! html
+<table data-parsoid='{"stx":"html"}'>
+<tr><td>
+<table>
+<tr><td>foo</td></tr>
+</table>
+</td></tr>
+</table>
+!! wikitext
+<table>
+<tr><td>
+{|
+|foo
+|}
+</td></tr>
+</table>
+!! end
+
###
### Internal links
###
<p><a href="#.3C">#<</a><a href="#.3E">#></a>
</p>
!! html/parsoid
-<p><a rel="mw:WikiLink" href="./Main%20Page#%3C" title="Main Page">#<</a><a rel="mw:WikiLink" href="./Main%20Page#%3E" title="Main Page">#></a></p>
+<p><a rel="mw:WikiLink" href="./Main_Page#%3C" title="Main Page">#<</a><a rel="mw:WikiLink" href="./Main_Page#%3E" title="Main Page">#></a></p>
!! end
!! test
<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent">abc</a>
</p>
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&lt;script&gt;&lt;/script&gt;"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span>
-<span typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&lt;script&gt;&lt;/script&gt;"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="100" width="100"/></a></span>
-<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"<span typeof=\"mw:Entity\" data-parsoid=\"{&quot;src&quot;:&quot;&amp;lt;&quot;,&quot;srcContent&quot;:&quot;<&quot;,&quot;dsr&quot;:[107,111,null,null]}\">&lt;</span>"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span>
-<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"a<i data-parsoid=\"{&quot;stx&quot;:&quot;html&quot;,&quot;dsr&quot;:[134,142,3,4]}\">b</i>c"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"<script></script>"}]}' data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&lt;script>&lt;/script>"}'><a href="./File:Nonexistent" data-parsoid='{"a":{"href":"./File:Nonexistent"},"sa":{}}'><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220" data-parsoid='{"a":{"resource":"./File:Nonexistent","height":"220","width":"220"},"sa":{"resource":"File:Nonexistent"}}'/></a></span>
+<span typeof="mw:Error mw:Image" data-parsoid='{"optList":[{"ck":"width","ak":"100x100px"},{"ck":"caption","ak":"<script></script>"}]}' data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&lt;script>&lt;/script>"}'><a href="./File:Nonexistent" data-parsoid='{"a":{"href":"./File:Nonexistent"},"sa":{}}'><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="100" width="100" data-parsoid='{"a":{"resource":"./File:Nonexistent","height":"100","width":"100"},"sa":{"resource":"File:Nonexistent"}}'/></a></span>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"&lt;"}]}' data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"<span typeof=\"mw:Entity\" data-parsoid='{\"src\":\"&amp;lt;\",\"srcContent\":\"&lt;\",\"dsr\":[107,111,null,null]}'>&lt;</span>"}'><a href="./File:Nonexistent" data-parsoid='{"a":{"href":"./File:Nonexistent"},"sa":{}}'><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220" data-parsoid='{"a":{"resource":"./File:Nonexistent","height":"220","width":"220"},"sa":{"resource":"File:Nonexistent"}}'/></a></span>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"a<i>b</i>c"}]}' data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"a<i data-parsoid='{\"stx\":\"html\",\"dsr\":[134,142,3,4]}'>b</i>c"}'><a href="./File:Nonexistent" data-parsoid='{"a":{"href":"./File:Nonexistent"},"sa":{}}'><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220" data-parsoid='{"a":{"resource":"./File:Nonexistent","height":"220","width":"220"},"sa":{"resource":"File:Nonexistent"}}'/></a></span></p>
!! end
!! test
!! wikitext
#REDIRECT [[{{echo|Foo}}bar]]
!! html/parsoid
-<link typeof="mw:ExpandedAttrs" rel="mw:PageProp/redirect" href="./Foobar" data-mw='{"attribs":[[{"txt":"href"},{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]],&quot;dsr&quot;:[12,24,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;Foo&quot;}},&quot;i&quot;:0}}]}\">Foo</span>bar"}]]}'/>
+<link about="#mwt2" typeof="mw:ExpandedAttrs" rel="mw:PageProp/redirect" href="./Foobar" data-parsoid='{"a":{"href":"./Foobar"},"sa":{"href":"{{echo|Foo}}bar"}}' data-mw='{"attribs":[[{"txt":"href"},{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[12,24,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"Foo\"}},\"i\":0}}]}'>Foo</span>bar"}]]}'/>
!! end
!! test
!! wikitext
{{DISPLAYTITLE:''{{PAGENAME}}''}}
!! html/parsoid
-<meta property="mw:PageProp/displaytitle" content="Main Page" about="#mwt2" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"content"},{"html":"<i data-parsoid=\"{&quot;dsr&quot;:[15,31,2,2]}\"><span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[]],&quot;dsr&quot;:[17,29,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;PAGENAME&quot;,&quot;function&quot;:&quot;pagename&quot;},&quot;params&quot;:{},&quot;i&quot;:0}}]}\">Main Page</span></i>"}]]}'/>
+<meta property="mw:PageProp/displaytitle" content="Main_Page" about="#mwt2" typeof="mw:ExpandedAttrs" data-parsoid='{"src":"{{DISPLAYTITLE:''{{PAGENAME}}''}}"}' data-mw='{"attribs":[[{"txt":"content"},{"html":"<i data-parsoid='{\"dsr\":[15,31,2,2]}'><span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[]],\"dsr\":[17,29,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"PAGENAME\",\"function\":\"pagename\"},\"params\":{},\"i\":0}}]}'>Main_Page</span></i>"}]]}'/>
!! end
!! test
!! wikitext
{{{{echo|DISPLAYTITLE}}:Foo}}
!! html/parsoid
-<meta property="mw:PageProp/displaytitle" content="Foo" about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"dsr":[0,29,null,null],"pi":[[]]}' data-mw='{"parts":[{"template":{"target":{"wt":"{{echo|DISPLAYTITLE}}:Foo"},"params":{},"i":0}}]}'/>
+<meta property="mw:PageProp/displaytitle" content="Foo" about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[]]}' data-mw='{"parts":[{"template":{"target":{"wt":"{{echo|DISPLAYTITLE}}:Foo"},"params":{},"i":0}}]}'/>
!! end
!! test
|c
|}
!!html/parsoid
-<meta typeof="mw:Includes/IncludeOnly"/><meta typeof="mw:Includes/IncludeOnly/End"/><table about="#mwt2" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"{{{b}}}","html":"<span about=\"#mwt1\" typeof=\"mw:Param\" data-parsoid=\"{&quot;dsr&quot;:[31,38,null,null],&quot;src&quot;:&quot;{{{b}}}&quot;}\">{{{b}}}</span>"},{"html":""}]]}' data-parsoid='{"a":{"{{{b}}}":null},"sa":{"{{{b}}}":""}}'>
+<meta typeof="mw:Includes/IncludeOnly" data-parsoid='{"src":"<includeonly>a</includeonly>"}'/><meta typeof="mw:Includes/IncludeOnly/End" data-parsoid='{"src":""}'/><table about="#mwt2" typeof="mw:ExpandedAttrs" data-parsoid='{"a":{"{{{b}}}":null},"sa":{"{{{b}}}":""}}' data-mw='{"attribs":[[{"txt":"{{{b}}}","html":"<span about=\"#mwt1\" typeof=\"mw:Param\" data-parsoid='{\"dsr\":[31,38,null,null],\"src\":\"{{{b}}}\"}'>{{{b}}}</span>"},{"html":""}]]}'>
<tbody><tr><td>c</td></tr>
</tbody></table>
-
!!end
###
<div style="background:#f9f9f9;">foo</div>
!! html/parsoid
-<div style="background:#f9f9f9;" about="#mwt3" typeof="mw:ExpandedAttrs" data-parsoid='{"stx":"html"}' data-mw='{"attribs":[[{"txt":"style","html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]],&quot;dsr&quot;:[5,49,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;style{{=}}\\&quot;background:&amp;#35;f9f9f9;\\&quot;&quot;}},&quot;i&quot;:0}}]}\">style</span><span typeof=\"mw:Nowiki\" about=\"#mwt1\" data-parsoid=\"{}\">=</span><span about=\"#mwt1\" data-parsoid=\"{}\">\"background:</span><span typeof=\"mw:Entity\" about=\"#mwt1\" data-parsoid=\"{&quot;src&quot;:&quot;&amp;#35;&quot;,&quot;srcContent&quot;:&quot;#&quot;}\">#</span><span about=\"#mwt1\" data-parsoid=\"{}\">f9f9f9;\"</span>"},{"html":""}]]}'>foo</div>
+<div style="background:#f9f9f9;" about="#mwt3" typeof="mw:ExpandedAttrs" data-parsoid='{"stx":"html"}' data-mw='{"attribs":[[{"txt":"style","html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[5,49,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"style{{=}}\\\"background:&amp;#35;f9f9f9;\\\"\"}},\"i\":0}}]}'>style</span><span typeof=\"mw:Nowiki\" about=\"#mwt1\" data-parsoid=\"{}\">=</span><span about=\"#mwt1\" data-parsoid=\"{}\">\"background:</span><span typeof=\"mw:Entity\" about=\"#mwt1\" data-parsoid='{\"src\":\"&amp;#35;\",\"srcContent\":\"#\"}'>#</span><span about=\"#mwt1\" data-parsoid=\"{}\">f9f9f9;\"</span>"},{"html":""}]]}'>foo</div>
!! end
!! test
<div class="thumb tright"><div class="thumbinner" style="width:139px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/137px-Foobar.jpg" width="137" height="16" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/206px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/274px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is a caption</div></div></div>
!! html/parsoid
-<figure typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt2" data-mw='{"attribs":[["thumbnail",{"html":"thumb"}],["width",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]],&quot;dsr&quot;:[24,38,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;137px&quot;}},&quot;i&quot;:0}}]}\">137px</span>"}]]}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/137px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="16" width="137"/></a><figcaption>This is a caption</figcaption></figure>
+<figure typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt2" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"width","ak":"{{echo|137px}}"},{"ck":"caption","ak":"This is a caption"}]}' data-mw='{"attribs":[["thumbnail",{"html":"thumb"}],["width",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[24,38,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"137px\"}},\"i\":0}}]}'>137px</span>"}]]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/137px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="16" width="137" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"16","width":"137"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>This is a caption</figcaption></figure>
!! end
!! test
<div class="thumb tright"><div class="thumbinner" style="width:139px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/137px-Foobar.jpg" width="137" height="16" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/206px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/274px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is a caption</div></div></div>
!! html/parsoid
-<figure typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt3" data-mw='{"attribs":[["thumbnail",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]],&quot;dsr&quot;:[18,32,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;thumb&quot;}},&quot;i&quot;:0}}]}\">thumb</span>"}],["width",{"html":"<span about=\"#mwt2\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]],&quot;dsr&quot;:[33,47,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;137px&quot;}},&quot;i&quot;:0}}]}\">137px</span>"}]]}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/137px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="16" width="137"/></a><figcaption>This is a caption</figcaption></figure>
+<figure typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt3" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"{{echo|thumb}}"},{"ck":"width","ak":"{{echo|137px}}"},{"ck":"caption","ak":"This is a caption"}]}' data-mw='{"attribs":[["thumbnail",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[18,32,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"thumb\"}},\"i\":0}}]}'>thumb</span>"}],["width",{"html":"<span about=\"#mwt2\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[33,47,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"137px\"}},\"i\":0}}]}'>137px</span>"}]]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/137px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="16" width="137" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"16","width":"137"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>This is a caption</figcaption></figure>
!! end
!! test
<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" width="50" height="6" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/75px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/100px-Foobar.jpg 2x" /></a>
</p>
!! html/parsoid
-<p><span typeof="mw:Image mw:ExpandedAttrs" about="#mwt2" data-parsoid='{"optList":[{"ck":"width","ak":"{{echo|50px}}"}]}' data-mw='{"attribs":[["width",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]],&quot;dsr&quot;:[18,31,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;50px&quot;}},&quot;i&quot;:0}}]}\">50px</span>"}]]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a></span></p>
+<p><span typeof="mw:Image mw:ExpandedAttrs" about="#mwt2" data-parsoid='{"optList":[{"ck":"width","ak":"{{echo|50px}}"}]}' data-mw='{"attribs":[["width",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[18,31,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"50px\"}},\"i\":0}}]}'>50px</span>"}]]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
## Parsoid does not provide editing support for images where templates produce multiple image attributes.
!! config
wgExternalLinkTarget='foobar'
!! html/php
-<p><a href="http://example.com/" target="foobar" rel="nofollow"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+<p><a href="http://example.com/" target="foobar" rel="nofollow noreferrer noopener"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! end
!! config
wgExternalLinkTarget='foobar'
!! html/php
-<p><a href="http://example.com/" title="Title" target="foobar" rel="nofollow"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+<p><a href="http://example.com/" title="Title" target="foobar" rel="nofollow noreferrer noopener"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! end
</p><p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="testing bold in alt" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"testing <b data-parsoid=\"{&quot;dsr&quot;:[27,37,3,3]}\">bold</b> in alt"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"Image:Foobar.jpg"}}'/></a></span></p>
-<p><span class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img alt="testing bold in alt" resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"alt":"testing bold in alt","resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"alt":"alt=testing '''bold''' in alt","resource":"Image:Foobar.jpg"}}'/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"testing '''bold''' in alt"}]}' data-mw='{"caption":"testing <b data-parsoid='{\"dsr\":[27,37,3,3]}'>bold</b> in alt"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"Image:Foobar.jpg"}}'/></a></span></p>
+
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"alt","ak":"alt=testing '''bold''' in alt"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img alt="testing bold in alt" resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"alt":"testing bold in alt","resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"alt":"alt=testing '''bold''' in alt","resource":"Image:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="This is a link and a bold template." src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is the image caption</div></div></div>
!! html/parsoid
-<figure class="mw-default-size" typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt2" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"This is the image caption"},{"ck":"alt","ak":"alt=This is a [[link]] and a {{echo|''bold template''}}."}]}' data-mw='{"attribs":[["thumbnail",{"html":"thumb"}],["alt",{"html":"alt=This is a <a rel=\"mw:WikiLink\" href=\"./Link\" title=\"Link\" data-parsoid=\"{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;./Link&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;link&quot;},&quot;dsr&quot;:[65,73,2,2]}\">link</a> and a <i about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;dsr&quot;:[80,106,null,null],&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;''bold template''&quot;}},&quot;i&quot;:0}}]}\">bold template</i>."}]]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img alt="This is a link and a bold template." resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"alt":"This is a link and a bold template.","resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"alt":"alt=This is a [[link]] and a {{echo|''bold template''}}.","resource":"Image:Foobar.jpg"}}'/></a><figcaption>This is the image caption</figcaption></figure>
+<figure class="mw-default-size" typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt2" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"This is the image caption"},{"ck":"alt","ak":"alt=This is a [[link]] and a {{echo|''bold template''}}."}]}' data-mw='{"attribs":[["thumbnail",{"html":"thumb"}],["alt",{"html":"alt=This is a <a rel=\"mw:WikiLink\" href=\"./Link\" title=\"Link\" data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Link\"},\"sa\":{\"href\":\"link\"},\"dsr\":[65,73,2,2]}'>link</a> and a <i about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"dsr\":[80,106,null,null],\"pi\":[[{\"k\":\"1\"}]]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"&#39;&#39;bold template&#39;&#39;\"}},\"i\":0}}]}'>bold template</i>."}]]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img alt="This is a link and a bold template." resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"alt":"This is a link and a bold template.","resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"alt":"alt=This is a [[link]] and a {{echo|''bold template''}}.","resource":"Image:Foobar.jpg"}}'/></a><figcaption>This is the image caption</figcaption></figure>
!! end
###################
<p><a href="/wiki/File:Foobar.jpg" class="image" title="http://example.com"><img alt="http://example.com" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"<a rel=\"mw:ExtLink\" href=\"http://example.com\" data-parsoid=\"{&quot;stx&quot;:&quot;url&quot;,&quot;dsr&quot;:[18,36,0,0]}\">http://example.com</a>"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"http://example.com"}]}' data-mw='{"caption":"<a rel=\"mw:ExtLink\" href=\"http://example.com\" data-parsoid='{\"stx\":\"url\",\"dsr\":[18,36,0,0]}'>http://example.com</a>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
<p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a link in it"><img alt="text with a link in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a <a rel=\"mw:WikiLink\" href=\"./Link\" title=\"Link\" data-parsoid=\"{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;./Link&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;link&quot;},&quot;dsr&quot;:[30,38,2,2]}\">link</a> in it"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"text with a [[link]] in it"}]}' data-mw='{"caption":"text with a <a rel=\"mw:WikiLink\" href=\"./Link\" title=\"Link\" data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Link\"},\"sa\":{\"href\":\"link\"},\"dsr\":[30,38,2,2]}'>link</a> in it"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
<p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a linkfoo in it"><img alt="text with a linkfoo in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a <a rel=\"mw:WikiLink\" href=\"./Link\" title=\"Link\" data-parsoid=\"{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;./Link&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;link&quot;},&quot;dsr&quot;:[30,41,2,5],&quot;tail&quot;:&quot;foo&quot;}\">linkfoo</a> in it"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"text with a [[link]]foo in it"}]}' data-mw='{"caption":"text with a <a rel=\"mw:WikiLink\" href=\"./Link\" title=\"Link\" data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Link\"},\"sa\":{\"href\":\"link\"},\"dsr\":[30,41,2,5],\"tail\":\"foo\"}'>linkfoo</a> in it"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
<p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a MeatBall:Link in it"><img alt="text with a MeatBall:Link in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a <a rel=\"mw:ExtLink\" href=\"http://www.usemod.com/cgi-bin/mb.pl?Link\" title=\"meatball:Link\" data-parsoid=\"{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;http://www.usemod.com/cgi-bin/mb.pl?Link&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;MeatBall:Link&quot;},&quot;isIW&quot;:true,&quot;dsr&quot;:[30,47,2,2]}\">MeatBall:Link</a> in it"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"text with a [[MeatBall:Link]] in it"}]}' data-mw='{"caption":"text with a <a rel=\"mw:ExtLink\" href=\"http://www.usemod.com/cgi-bin/mb.pl?Link\" title=\"meatball:Link\" data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"http://www.usemod.com/cgi-bin/mb.pl?Link\"},\"sa\":{\"href\":\"MeatBall:Link\"},\"isIW\":true,\"dsr\":[30,47,2,2]}'>MeatBall:Link</a> in it"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
<p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a link in it"><img alt="text with a link in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a <a rel=\"mw:ExtLink\" href=\"http://www.usemod.com/cgi-bin/mb.pl?Link\" title=\"meatball:Link\" data-parsoid=\"{&quot;stx&quot;:&quot;piped&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;http://www.usemod.com/cgi-bin/mb.pl?Link&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;MeatBall:Link&quot;},&quot;isIW&quot;:true,&quot;dsr&quot;:[30,52,16,2]}\">link</a> in it"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"text with a [[MeatBall:Link|link]] in it"}]}' data-mw='{"caption":"text with a <a rel=\"mw:ExtLink\" href=\"http://www.usemod.com/cgi-bin/mb.pl?Link\" title=\"meatball:Link\" data-parsoid='{\"stx\":\"piped\",\"a\":{\"href\":\"http://www.usemod.com/cgi-bin/mb.pl?Link\"},\"sa\":{\"href\":\"MeatBall:Link\"},\"isIW\":true,\"dsr\":[30,52,16,2]}'>link</a> in it"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
!! wikitext
[[File:Foobar.jpg|<nowiki>text with a [[MeatBall:Link|link]] in it</nowiki>]]
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"<span typeof=\"mw:Nowiki\" data-parsoid=\"{&quot;dsr&quot;:[18,75,8,9]}\">text with a [[MeatBall:Link|link]] in it</span>"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"<nowiki>text with a [[MeatBall:Link|link]] in it</nowiki>"}]}' data-mw='{"caption":"<span typeof=\"mw:Nowiki\" data-parsoid='{\"dsr\":[18,75,8,9]}'>text with a [[MeatBall:Link|link]] in it</span>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
<p><a href="/wiki/File:Foobar.jpg" class="image" title="& < > ""><img alt="& < > "" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"&amp; &lt; &gt; \""}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"& < > \""}]}' data-mw='{"caption":"&amp; &lt; > \""}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
<p><a href="/wiki/File:Foobar.jpg" class="image" title="♀"><img alt="♀" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"<span typeof=\"mw:Entity\" data-parsoid=\"{&quot;src&quot;:&quot;&amp;#9792;&quot;,&quot;srcContent&quot;:&quot;♀&quot;,&quot;dsr&quot;:[18,25,null,null]}\">♀</span>"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"&#9792;"}]}' data-mw='{"caption":"<span typeof=\"mw:Entity\" data-parsoid='{\"src\":\"&amp;#9792;\",\"srcContent\":\"♀\",\"dsr\":[18,25,null,null]}'>♀</span>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
!! wikitext
[[Image:Barfoo.jpg]]
!! html/php
-<p><a href="/wiki/File:Barfoo.jpg" title="File:Barfoo.jpg">File:Barfoo.jpg</a>
+<p><a href="/wiki/File:Barfoo.jpg" class="mw-redirect" title="File:Barfoo.jpg">File:Barfoo.jpg</a>
</p>
!! end
!! wikitext
[[File:Foobar.jpg|<table><tr><td>a</td><td>b</td></tr><tr><td>c</td></tr></table>]]
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"<table data-parsoid=\"{&quot;stx&quot;:&quot;html&quot;,&quot;dsr&quot;:[18,81,7,8]}\"><tbody data-parsoid=\"{&quot;dsr&quot;:[25,73,0,0]}\"><tr data-parsoid=\"{&quot;stx&quot;:&quot;html&quot;,&quot;dsr&quot;:[25,54,4,5]}\"><td data-parsoid=\"{&quot;stx&quot;:&quot;html&quot;,&quot;dsr&quot;:[29,39,4,5]}\">a</td><td data-parsoid=\"{&quot;stx&quot;:&quot;html&quot;,&quot;dsr&quot;:[39,49,4,5]}\">b</td></tr><tr data-parsoid=\"{&quot;stx&quot;:&quot;html&quot;,&quot;dsr&quot;:[54,73,4,5]}\"><td data-parsoid=\"{&quot;stx&quot;:&quot;html&quot;,&quot;dsr&quot;:[58,68,4,5]}\">c</td></tr></tbody></table>"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"<table><tr><td>a</td><td>b</td></tr><tr><td>c</td></tr></table>"}]}' data-mw='{"caption":"<table data-parsoid='{\"stx\":\"html\",\"dsr\":[18,81,7,8]}'><tbody data-parsoid='{\"dsr\":[25,73,0,0]}'><tr data-parsoid='{\"stx\":\"html\",\"dsr\":[25,54,4,5]}'><td data-parsoid='{\"stx\":\"html\",\"dsr\":[29,39,4,5]}'>a</td><td data-parsoid='{\"stx\":\"html\",\"dsr\":[39,49,4,5]}'>b</td></tr><tr data-parsoid='{\"stx\":\"html\",\"dsr\":[54,73,4,5]}'><td data-parsoid='{\"stx\":\"html\",\"dsr\":[58,68,4,5]}'>c</td></tr></tbody></table>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
!! end
!! test
<references />
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"Undisplayed caption in inline image with ref: <ref>foo</ref>"}]}' data-mw='{"caption":"Undisplayed caption in inline image with ref: <span about=\"#mwt2\" class=\"mw-ref\" id=\"cite_ref-1\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid=\"{&quot;dsr&quot;:[64,78,5,6]}\" data-mw=\"{&quot;name&quot;:&quot;ref&quot;,&quot;body&quot;:{&quot;id&quot;:&quot;mw-reference-text-cite_note-1&quot;},&quot;attrs&quot;:{}}\"><a href=\"#cite_note-1\" style=\"counter-reset: mw-Ref 1;\"><span class=\"mw-reflink-text\">[1]</span></a></span><meta typeof=\"mw:Extension/ref/Marker\" about=\"#mwt2\" data-parsoid=\"{&quot;group&quot;:&quot;&quot;,&quot;name&quot;:&quot;&quot;,&quot;content&quot;:&quot;foo&quot;,&quot;hasRefInRef&quot;:false,&quot;dsr&quot;:[64,78,5,6],&quot;tmp&quot;:{}}\" data-mw=\"{}\">"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"Undisplayed caption in inline image with ref: <ref>foo</ref>"}]}' data-mw='{"caption":"Undisplayed caption in inline image with ref: <span about=\"#mwt2\" class=\"mw-ref\" id=\"cite_ref-1\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid='{\"dsr\":[64,78,5,6]}' data-mw='{\"name\":\"ref\",\"body\":{\"id\":\"mw-reference-text-cite_note-1\"},\"attrs\":{}}'><a href=\"#cite_note-1\" style=\"counter-reset: mw-Ref 1;\" data-parsoid=\"{}\"><span class=\"mw-reflink-text\" data-parsoid=\"{}\">[1]</span></a></span><meta typeof=\"mw:Extension/ref/Marker\" about=\"#mwt2\" data-parsoid='{\"group\":\"\",\"name\":\"\",\"content\":\"foo\",\"hasRefInRef\":false,\"dsr\":[64,78,5,6]}'/>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
<ol class="mw-references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text" data-parsoid="{}">foo</span></li></ol>
!! end
<references />
!! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"Undisplayed caption in inline image with ref: {{echo|<ref>{{echo|foo}}</ref>}}"}]}' data-mw='{"caption":"Undisplayed caption in inline image with ref: <span about=\"#mwt2\" class=\"mw-ref\" id=\"cite_ref-1\" rel=\"dc:references\" typeof=\"mw:Transclusion mw:Extension/ref\" data-parsoid=\"{&quot;dsr&quot;:[64,96,null,null],&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;<ref>{{echo|foo}}</ref>&quot;}},&quot;i&quot;:0}}]}\"><a href=\"#cite_note-1\" style=\"counter-reset: mw-Ref 1;\"><span class=\"mw-reflink-text\">[1]</span></a></span><meta typeof=\"mw:Transclusion mw:Extension/ref/Marker\" about=\"#mwt2\" data-parsoid=\"{&quot;group&quot;:&quot;&quot;,&quot;name&quot;:&quot;&quot;,&quot;content&quot;:&quot;foo&quot;,&quot;hasRefInRef&quot;:false,&quot;dsr&quot;:[64,96,null,null],&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;}]],&quot;tmp&quot;:{}}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;<ref>{{echo|foo}}</ref>&quot;}},&quot;i&quot;:0}}]}\">"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"Undisplayed caption in inline image with ref: {{echo|<ref>{{echo|foo}}</ref>}}"}]}' data-mw='{"caption":"Undisplayed caption in inline image with ref: <span about=\"#mwt2\" class=\"mw-ref\" id=\"cite_ref-1\" rel=\"dc:references\" typeof=\"mw:Transclusion mw:Extension/ref\" data-parsoid='{\"dsr\":[64,96,null,null],\"pi\":[[{\"k\":\"1\"}]]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"&lt;ref>{{echo|foo}}&lt;/ref>\"}},\"i\":0}}]}'><a href=\"#cite_note-1\" style=\"counter-reset: mw-Ref 1;\" data-parsoid=\"{}\"><span class=\"mw-reflink-text\" data-parsoid=\"{}\">[1]</span></a></span><meta typeof=\"mw:Transclusion mw:Extension/ref/Marker\" about=\"#mwt2\" data-parsoid='{\"group\":\"\",\"name\":\"\",\"content\":\"foo\",\"hasRefInRef\":false,\"dsr\":[64,96,null,null],\"pi\":[[{\"k\":\"1\"}]]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"&lt;ref>{{echo|foo}}&lt;/ref>\"}},\"i\":0}}]}'/>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
<ol class="mw-references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text" data-parsoid="{}">foo</span></li></ol>
!! end
!! wikitext
{{{{echo|DEFAULTSORT}}:Foo}}
!! html/parsoid
-<meta property="mw:PageProp/categorydefaultsort" content="Foo" about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"dsr":[0,28,null,null],"pi":[[]]}' data-mw='{"parts":[{"template":{"target":{"wt":"{{echo|DEFAULTSORT}}:Foo"},"params":{},"i":0}}]}'/>
+<meta property="mw:PageProp/categorydefaultsort" content="Foo" about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[]]}' data-mw='{"parts":[{"template":{"target":{"wt":"{{echo|DEFAULTSORT}}:Foo"},"params":{},"i":0}}]}'/>
!! end
###
<div title=""></div>
!! html/parsoid
-<div title='" onmouseover="alert(document.cookie)' about="#mwt2" typeof="mw:ExpandedAttrs" data-parsoid='{"stx":"html","a":{"title":"\" onmouseover=\"alert(document.cookie)"},"sa":{"title":"{{dangerous attribute}}"}}' data-mw='{"attribs":[[{"txt":"title"},{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[]],&quot;dsr&quot;:[12,35,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;dangerous attribute&quot;,&quot;href&quot;:&quot;./Template:Dangerous_attribute&quot;},&quot;params&quot;:{},&quot;i&quot;:0}}]}\">\" onmouseover=\"alert(document.cookie)</span>"}]]}'></div>
+<div title='" onmouseover="alert(document.cookie)' about="#mwt2" typeof="mw:ExpandedAttrs" data-parsoid='{"stx":"html","a":{"title":"\" onmouseover=\"alert(document.cookie)"},"sa":{"title":"{{dangerous attribute}}"}}' data-mw='{"attribs":[[{"txt":"title"},{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[]],\"dsr\":[12,35,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"dangerous attribute\",\"href\":\"./Template:Dangerous_attribute\"},\"params\":{},\"i\":0}}]}'>\" onmouseover=\"alert(document.cookie)</span>"}]]}'></div>
!! end
!! test
<pre typeof="mw:Extension/tag" data-mw='{"name":"tag","attrs":{"foo":"bar"},"body":null}' data-parsoid='{}' about="#mwt2"></pre>text
!! end
-# </tag> should be output literally since there is no matching tag that begins it
+## </tag> should be output literally since there is no matching tag that begins it
+## Don't expect parsoid to rt this form.
!! test
Parser hook: basic arguments using terminated empty elements (bug 2374)
+!! options
+parsoid=wt2html
!! wikitext
<tag width=200 height = "100" depth = '50' square/>
other stuff
<p>other stuff
</tag>
</p>
+!! html/parsoid
+<pre typeof="mw:Extension/tag" data-mw='{"name":"tag","attrs":{"width":"200","height":"100","depth":"50","square":""},"body":null}' about="#mwt2"></pre><p>other stuff
+</tag></p>
+!! end
+
+## Don't expect parsoid to rt this form.
+!! test
+Parser hook: Don't allow unclosed extension tags
+!! options
+parsoid=wt2html
+!! wikitext
+test <tag>123
+
+this is a '''test'''
+!! html/php
+<p>test <tag>123
+</p><p>this is a <b>test</b>
+</p>
+!! html/parsoid
+<p>test <tag>123</p>
+
+<p>this is a <b>test</b></p>
!! end
###
</ul>
</li>
</ul>
-!! html
+!! html/php
<ul>
<li>One</li>
<li>Two:
</li>
</ul>
+!! html/parsoid
+<ul data-parsoid='{"stx":"html"}'>
+<li data-parsoid='{"stx":"html"}'>One</li>
+<li data-parsoid='{"stx":"html"}'>Two:
+<ul data-parsoid='{"stx":"html"}'>
+<li data-parsoid='{"stx":"html"}'>Sub-one</li>
+<li data-parsoid='{"stx":"html"}'>Sub-two</li>
+</ul>
+</li>
+</ul>
!! end
!! test
<div class="thumb tright"><div class="thumbinner" style="width:182px;">Error creating thumbnail: <div class="thumbcaption"></div></div></div>
!! html/parsoid
-<figure class="mw-default-size" typeof="mw:Error mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"manualthumb","ak":"thumbnail= "}],"dsr":[0,32,2,2]}' data-mw='{"errors":[{"key":"missing-thumbnail","message":"This thumbnail does not exist.","params":{"name":""}}],"thumb":""}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{},"dsr":[2,30,null,null]}'><img resource="./File:Foobar.jpg" src="./Special:FilePath/" height="220" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"220"},"sa":{"resource":"Image:foobar.jpg"}}'/></a></figure>
+<figure class="mw-default-size" typeof="mw:Error mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"manualthumb","ak":"thumbnail= "}]}' data-mw='{"errors":[{"key":"missing-thumbnail","message":"This thumbnail does not exist.","params":{"name":""}}],"thumb":""}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="./Special:FilePath/" height="220" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"220"},"sa":{"resource":"Image:foobar.jpg"}}'/></a></figure>
!!end
!! test
<a href="/index.php?title=3E&action=edit&redlink=1" class="new" title="3E (page does not exist)">3E</a> <a href="/index.php?title=3E%2B&action=edit&redlink=1" class="new" title="3E+ (page does not exist)">3E+</a>
</p>
!! html/parsoid
-<p><a rel="mw:WikiLink" href="./User:+%25" title="User:+%">User:+%</a> <a rel="mw:WikiLink" href="Page+title%25" title="Page+title%">Page+title%</a>
-<a rel="mw:WikiLink" href="%25+" title="%+">%+</a> <a rel="mw:WikiLink" href="%25+" title="%+">%20</a> <a rel="mw:WikiLink" href="%25+" title="%+">%+ </a> <a rel="mw:WikiLink" href="%25+r" title="%+r">%+r</a>
-<a rel="mw:WikiLink" href="%25" title="%">%</a> <a rel="mw:WikiLink" href="+" title="+">+</a> <span class="mw-default-size" typeof="mw:Error mw:Image" data-parsoid='{"optList":[{"ck":"bogus","ak":"foo"},{"ck":"caption","ak":"[[bar]]"}]}' data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"<a rel=\"mw:WikiLink\" href=\"./Bar\" title=\"Bar\" data-parsoid=\"{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;./Bar&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;bar&quot;},&quot;dsr&quot;:[94,101,2,2]}\">bar</a>"}'><a href="./File:%25+abc9"><img resource="./File:%25+abc9" src="./Special:FilePath/%25+abc9" height="220" width="220" data-parsoid='{"a":{"resource":"./File:%25+abc9","height":"220","width":"220"},"sa":{"resource":"File:%+abc%39"}}'/></a></span>
+<p><a rel="mw:WikiLink" href="./User:+%25" title="User:+%" data-parsoid='{"stx":"simple","a":{"href":"./User:+%25"},"sa":{"href":"User:+%"}}'>User:+%</a> <a rel="mw:WikiLink" href="./Page+title%25" title="Page+title%" data-parsoid='{"stx":"simple","a":{"href":"./Page+title%25"},"sa":{"href":"Page+title%"}}'>Page+title%</a>
+<a rel="mw:WikiLink" href="./%25+" title="%+" data-parsoid='{"stx":"simple","a":{"href":"./%25+"},"sa":{"href":"%+"}}'>%+</a> <a rel="mw:WikiLink" href="./%25+" title="%+" data-parsoid='{"stx":"piped","a":{"href":"./%25+"},"sa":{"href":"%+"}}'>%20</a> <a rel="mw:WikiLink" href="./%25+" title="%+" data-parsoid='{"stx":"simple","a":{"href":"./%25+"},"sa":{"href":"%+ "}}'>%+ </a> <a rel="mw:WikiLink" href="./%25+r" title="%+r" data-parsoid='{"stx":"simple","a":{"href":"./%25+r"},"sa":{"href":"%+r"}}'>%+r</a>
+<a rel="mw:WikiLink" href="./%25" title="%" data-parsoid='{"stx":"simple","a":{"href":"./%25"},"sa":{"href":"%"}}'>%</a> <a rel="mw:WikiLink" href="./+" title="+" data-parsoid='{"stx":"simple","a":{"href":"./+"},"sa":{"href":"+"}}'>+</a> <span class="mw-default-size" typeof="mw:Error mw:Image" data-parsoid='{"optList":[{"ck":"bogus","ak":"foo"},{"ck":"caption","ak":"[[bar]]"}]}' data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"<a rel=\"mw:WikiLink\" href=\"./Bar\" title=\"Bar\" data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Bar\"},\"sa\":{\"href\":\"bar\"},\"dsr\":[94,101,2,2]}'>bar</a>"}'><a href="./File:%25+abc9" data-parsoid='{"a":{"href":"./File:%25+abc9"},"sa":{}}'><img resource="./File:%25+abc9" src="./Special:FilePath/%25+abc9" height="220" width="220" data-parsoid='{"a":{"resource":"./File:%25+abc9","height":"220","width":"220"},"sa":{"resource":"File:%+abc%39"}}'/></a></span>
<a rel="mw:WikiLink" href="./3E" title="3E" data-parsoid='{"stx":"simple","a":{"href":"./3E"},"sa":{"href":"%33%45"}}'>3E</a> <a rel="mw:WikiLink" href="./3E+" title="3E+" data-parsoid='{"stx":"simple","a":{"href":"./3E+"},"sa":{"href":"%33%45+"}}'>3E+</a></p>
!! end
B <span about="#mwt4" class="mw-ref" id="cite_ref-b_2-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-b-2"},"attrs":{"name":"b"}}'><a href="#cite_note-b-2"><span class="mw-reflink-text">[2]</span></a></span></p>
-<ol class="mw-references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{},"body":{"html":"\n<span about=\"#mwt8\" class=\"mw-ref\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid='{\"dsr\":[59,82,14,6]}' data-mw='{\"name\":\"ref\",\"body\":{\"id\":\"mw-reference-text-cite_note-a-1\"},\"attrs\":{\"name\":\"a\"}}'><a href=\"#cite_note-a-1\" style=\"counter-reset: mw-Ref 1;\"><span class=\"mw-reflink-text\">[1]</span></a></span>\n"}}'><li about="#cite_note-a-1" id="cite_note-a-1"><a href="#cite_ref-a_1-0" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-a-1" class="mw-reference-text">foo</span></li><li about="#cite_note-b-2" id="cite_note-b-2"><a href="#cite_ref-b_2-0" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-b-2" class="mw-reference-text">bar</span></li>
+<ol class="mw-references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{},"body":{"html":"\n<span about=\"#mwt8\" class=\"mw-ref\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid='{\"dsr\":[59,82,14,6]}' data-mw='{\"name\":\"ref\",\"body\":{\"id\":\"mw-reference-text-cite_note-a-1\"},\"attrs\":{\"name\":\"a\"}}'><a href=\"#cite_note-a-1\" style=\"counter-reset: mw-Ref 1;\" data-parsoid=\"{}\"><span class=\"mw-reflink-text\" data-parsoid=\"{}\">[1]</span></a></span>\n"}}'><li about="#cite_note-a-1" id="cite_note-a-1"><a href="#cite_ref-a_1-0" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-a-1" class="mw-reference-text">foo</span></li><li about="#cite_note-b-2" id="cite_note-b-2"><a href="#cite_ref-b_2-0" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-b-2" class="mw-reference-text">bar</span></li>
</ol>
!! end
<li about="#cite_note-1" id="cite_note-1"><a href="#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo bar for a</span></li>
</ol>
-<ol class="mw-references" typeof="mw:Extension/references" about="#mwt8" data-mw-group="X" data-mw='{"name":"references","attrs":{"group":"X"},"body":{"html":"\n<span about=\"#mwt10\" class=\"mw-ref\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid='{\"dsr\":[96,119,14,6]}' data-mw='{\"name\":\"ref\",\"body\":{\"id\":\"mw-reference-text-cite_note-b-2\"},\"attrs\":{\"name\":\"b\"}}'><a href=\"#cite_note-b-2\" style=\"counter-reset: mw-Ref 1;\" data-mw-group=\"X\"><span class=\"mw-reflink-text\">[X 1]</span></a></span>\n"}}'>
+<ol class="mw-references" typeof="mw:Extension/references" about="#mwt8" data-mw-group="X" data-mw='{"name":"references","attrs":{"group":"X"},"body":{"html":"\n<span about=\"#mwt10\" class=\"mw-ref\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid='{\"dsr\":[96,119,14,6]}' data-mw='{\"name\":\"ref\",\"body\":{\"id\":\"mw-reference-text-cite_note-b-2\"},\"attrs\":{\"name\":\"b\"}}'><a href=\"#cite_note-b-2\" style=\"counter-reset: mw-Ref 1;\" data-mw-group=\"X\" data-parsoid=\"{}\"><span class=\"mw-reflink-text\" data-parsoid=\"{}\">[X 1]</span></a></span>\n"}}'>
<li about="#cite_note-b-2" id="cite_note-b-2"><a href="#cite_ref-b_2-0" data-mw-group="X" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-b-2" class="mw-reference-text">foo</span></li>
</ol>
!! end
</ol>
!! end
-# This test is wt2html only because we're permitting the serializer to produce
-# dirty diffs, normalizing the unclosed references to the self-closed version.
+## The output here may look funny, but it's what the php parser will do. The
+## unclosed references tag becomes escaped text, and then a new references
+## tag is auto-generated. The test is wt2html only because it roundtrips with
+## nowiki tags, and the auto-generated references tag is only dropped in
+## rtTestMode.
!! test
Generate references for unclosed references tag
!! options
<references>
!! html/parsoid
-<p>a<span about="#mwt2" class="mw-ref" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1"><span class="mw-reflink-text">[1]</span></a></span></p>
-<ol class="mw-references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'>
-<li about="#cite_note-1" id="cite_note-1"><a href="#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li></ol>
+<p>a<span about="#mwt2" class="mw-ref" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1" style="counter-reset: mw-Ref 1;"><span class="mw-reflink-text">[1]</span></a></span></p>
+
+<p><references></p>
+<ol class="mw-references" typeof="mw:Extension/references" about="#mwt3" data-mw='{"name":"references","attrs":{},"autoGenerated":true}'><li about="#cite_note-1" id="cite_note-1"><a href="#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li></ol>
!! end
!! test
!! test
2. Leading whitespace in non-indent-pre contexts should not be escaped
!! options
-parsoid=htm2wt
+parsoid=html2wt
!! html/parsoid
<p>foo <span about="#mwt2" class="mw-ref" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1"><span class="mw-reflink-text">[1]</span></a></span></p>
<ol class="mw-references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'>
-<li about="#cite_note-1" id="cite_note-1"><a href="#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text"><i data-parsoid='{"dsr":[9,14,2,2]}'>a</i>
+<li about="#cite_note-1" id="cite_note-1"><a href="#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text"><i>a</i>
b</span></li>
</ol>
!! wikitext
!! wikitext
<table><td></td>{{echo|<tr>[[Category:One]]}}<!--c-->[[Category:Two]]
!! html/parsoid
-<link rel="mw:PageProp/Category" href="./Category:One" about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"stx":"simple","a":{"href":"./Category:One"},"sa":{"href":"Category:One"},"fostered":true,"pi":[[{"k":"1"}]]}' data-mw='{"parts":["<table><td></td>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<tr>[[Category:One]]"}},"i":0}},"<!--c-->[[Category:Two]]"]}'/><link rel="mw:PageProp/Category" href="./Category:Two" about="#mwt2"/><table about="#mwt2" data-parsoid='{"stx":"html","autoInsertedEnd":true,"dsr":[0,53,7,0]}'><tbody><tr><td></td></tr><tr><!--c--></tr></tbody></table>
+<link rel="mw:PageProp/Category" href="./Category:One" about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"stx":"simple","a":{"href":"./Category:One"},"sa":{"href":"Category:One"},"fostered":true,"pi":[[{"k":"1"}]]}' data-mw='{"parts":["<table><td></td>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<tr>[[Category:One]]"}},"i":0}},"<!--c-->[[Category:Two]]"]}'/><link rel="mw:PageProp/Category" href="./Category:Two" about="#mwt2"/><table about="#mwt2" data-parsoid='{"stx":"html","autoInsertedEnd":true}'><tbody><tr><td></td></tr><tr><!--c--></tr></tbody></table>
!! end
!! test
!! html/parsoid
<p>x<meta typeof="mw:Placeholder" data-parsoid='{"src":"<nowiki/>"}'/><meta typeof="mw:Placeholder" data-parsoid='{"src":"<nowiki/>"}'/>
y</p>
-<p><span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"dsr":[0,23,null,null],"pi":[[{"k":"1","named":true,"spc":["\n"," "," ",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<nowiki/>"}},"i":0}}]}'></span></p>
-<p><span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"dsr":[0,24,null,null],"pi":[[{"k":"1","named":true,"spc":["\n"," "," ","\n"]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<nowiki/>"}},"i":0}}]}'></span></p>
+<p><span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1","named":true,"spc":["\n"," "," ",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<nowiki/>"}},"i":0}}]}'></span></p>
+<p><span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1","named":true,"spc":["\n"," "," ","\n"]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<nowiki/>"}},"i":0}}]}'></span></p>
!! wikitext
x
y
self::prepareServices( new GlobalVarConfig() );
}
+ /**
+ * Convenience method for getting an immutable test user
+ *
+ * @since 1.28
+ *
+ * @param string[] $groups Groups the test user should be in.
+ * @return TestUser
+ */
+ public static function getTestUser( $groups = [] ) {
+ return TestUserRegistry::getImmutableTestUser( $groups );
+ }
+
+ /**
+ * Convenience method for getting a mutable test user
+ *
+ * @since 1.28
+ *
+ * @param string[] $groups Groups the test user should be added in.
+ * @return TestUser
+ */
+ public static function getMutableTestUser( $groups = [] ) {
+ return TestUserRegistry::getMutableTestUser( __CLASS__, $groups );
+ }
+
+ /**
+ * Convenience method for getting an immutable admin test user
+ *
+ * @since 1.28
+ *
+ * @param string[] $groups Groups the test user should be added to.
+ * @return TestUser
+ */
+ public static function getTestSysop() {
+ return self::getTestUser( [ 'sysop', 'bureaucrat' ] );
+ }
+
/**
* Prepare service configuration for unit testing.
*
$defaultOverrides->set( 'ObjectCaches', $objectCaches );
$defaultOverrides->set( 'MainCacheType', CACHE_NONE );
+ // Use a fast hash algorithm to hash passwords.
+ $defaultOverrides->set( 'PasswordDefault', 'A' );
+
$testConfig = $customOverrides
? new MultiConfig( [ $customOverrides, $defaultOverrides, $baseConfig ] )
: new MultiConfig( [ $defaultOverrides, $baseConfig ] );
$needsResetDB = false;
- if ( $this->needsDB() ) {
+ if ( !self::$dbSetup || $this->needsDB() ) {
// set up a DB connection for this test to use
self::$useTemporaryTables = !$this->getCliArg( 'use-normal-tables' );
}
$wgRequest = new FauxRequest();
MediaWiki\Session\SessionManager::resetCache();
+ MediaWiki\Auth\AuthManager::resetCache();
$phpErrorLevel = intval( ini_get( 'error_reporting' ) );
}
}
+ /**
+ * Check if we can back up a value by performing a shallow copy.
+ * Values which fail this test are copied recursively.
+ *
+ * @param mixed $value
+ * @return bool True if a shallow copy will do; false if a deep copy
+ * is required.
+ */
+ private static function canShallowCopy( $value ) {
+ if ( is_scalar( $value ) || $value === null ) {
+ return true;
+ }
+ if ( is_array( $value ) ) {
+ foreach ( $value as $subValue ) {
+ if ( !is_scalar( $subValue ) && $subValue !== null ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
/**
* Stashes the global, will be restored in tearDown()
*
// NOTE: we serialize then unserialize the value in case it is an object
// this stops any objects being passed by reference. We could use clone
// and if is_object but this does account for objects within objects!
- try {
- $this->mwGlobals[$globalKey] = unserialize( serialize( $GLOBALS[$globalKey] ) );
- }
- // NOTE; some things such as Closures are not serializable
- // in this case just set the value!
- catch ( Exception $e ) {
+ if ( self::canShallowCopy( $GLOBALS[$globalKey] ) ) {
$this->mwGlobals[$globalKey] = $GLOBALS[$globalKey];
+ } elseif (
+ // Many MediaWiki types are safe to clone. These are the
+ // ones that are most commonly stashed.
+ $GLOBALS[$globalKey] instanceof Language ||
+ $GLOBALS[$globalKey] instanceof User ||
+ $GLOBALS[$globalKey] instanceof FauxRequest
+ ) {
+ $this->mwGlobals[$globalKey] = clone $GLOBALS[$globalKey];
+ } else {
+ try {
+ $this->mwGlobals[$globalKey] = unserialize( serialize( $GLOBALS[$globalKey] ) );
+ } catch ( Exception $e ) {
+ $this->mwGlobals[$globalKey] = $GLOBALS[$globalKey];
+ }
}
}
}
protected function insertPage( $pageName, $text = 'Sample page for unit test.' ) {
$title = Title::newFromText( $pageName, 0 );
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$comment = __METHOD__ . ': Sample page for unit test.';
// Avoid memory leak...?
# Insert 0 user to prevent FK violations
# Anonymous user
- $this->db->insert( 'user', [
- 'user_id' => 0,
- 'user_name' => 'Anonymous' ], __METHOD__, [ 'IGNORE' ] );
+ if ( !$this->db->selectField( 'user', '1', [ 'user_id' => 0 ] ) ) {
+ $this->db->insert( 'user', [
+ 'user_id' => 0,
+ 'user_name' => 'Anonymous' ], __METHOD__, [ 'IGNORE' ] );
+ }
# Insert 0 page to prevent FK violations
# Blank page
- $this->db->insert( 'page', [
- 'page_id' => 0,
- 'page_namespace' => 0,
- 'page_title' => ' ',
- 'page_restrictions' => null,
- 'page_is_redirect' => 0,
- 'page_is_new' => 0,
- 'page_random' => 0,
- 'page_touched' => $this->db->timestamp(),
- 'page_latest' => 0,
- 'page_len' => 0 ], __METHOD__, [ 'IGNORE' ] );
+ if ( !$this->db->selectField( 'page', '1', [ 'page_id' => 0 ] ) ) {
+ $this->db->insert( 'page', [
+ 'page_id' => 0,
+ 'page_namespace' => 0,
+ 'page_title' => ' ',
+ 'page_restrictions' => null,
+ 'page_is_redirect' => 0,
+ 'page_is_new' => 0,
+ 'page_random' => 0,
+ 'page_touched' => $this->db->timestamp(),
+ 'page_latest' => 0,
+ 'page_len' => 0 ], __METHOD__, [ 'IGNORE' ] );
+ }
}
User::resetIdByNameCache();
// Make sysop user
- $user = User::newFromName( 'UTSysop' );
-
- if ( $user->idForName() == 0 ) {
- $user->addToDatabase();
- TestUser::setPasswordForUser( $user, 'UTSysopPassword' );
- $user->addGroup( 'sysop' );
- $user->addGroup( 'bureaucrat' );
- }
+ $user = static::getTestSysop()->getUser();
// Make 1 page with 1 revision
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
// If any of the user tables were marked as used, we should clear all of them.
if ( array_intersect( $tablesUsed, $userTables ) ) {
$tablesUsed = array_unique( array_merge( $tablesUsed, $userTables ) );
-
- // Totally clear User class in-process cache to avoid CAS errors
- TestingAccessWrapper::newFromClass( 'User' )
- ->getInProcessCache()
- ->clear();
+ TestUserRegistry::clear();
}
$truncate = in_array( $db->getType(), [ 'oracle', 'mysql' ] );
}
}
- /**
- * Check whether we have the 'gzip' commandline utility, will skip
- * the test whenever "gzip -V" fails.
- *
- * Result is cached at the process level.
- *
- * @return bool
- *
- * @since 1.21
- */
- protected function checkHasGzip() {
- static $haveGzip;
-
- if ( $haveGzip === null ) {
- $retval = null;
- wfShellExec( 'gzip -V', $retval );
- $haveGzip = ( $retval === 0 );
- }
-
- if ( !$haveGzip ) {
- $this->markTestSkipped( "Skip test, requires the gzip utility in PATH" );
- }
-
- return $haveGzip;
- }
-
/**
* Check if $extName is a loaded PHP extension, will skip the
* test whenever it is not loaded.
--- /dev/null
+.efbbbf_bom_char_at_start_of_file {}
parent::setUp();
$this->setMwGlobals( [
- 'wgWellFormedXml' => false,
'wgUseMediaWikiUIEverywhere' => false,
] );
*/
public function testElementBasics() {
$this->assertEquals(
- '<img>',
+ '<img/>',
Html::element( 'img', null, '' ),
- 'No close tag for short-tag elements'
+ 'Self-closing tag for short-tag elements'
);
$this->assertEquals(
Html::element( 'element', [], '' ),
'Close tag for empty element (array, string)'
);
-
- $this->setMwGlobals( 'wgWellFormedXml', true );
-
- $this->assertEquals(
- '<img/>',
- Html::element( 'img', null, '' ),
- 'Self-closing tag for short-tag elements (wgWellFormedXml = true)'
- );
}
public function dataXmlMimeType() {
);
$this->assertEquals(
- ' selected',
+ ' selected=""',
Html::expandAttributes( [ 'selected' => true ] ),
'Boolean attributes have no value when value is true'
);
$this->assertEquals(
- ' selected',
+ ' selected=""',
Html::expandAttributes( [ 'selected' ] ),
'Boolean attributes have no value when value is true (passed as numerical array)'
);
-
- $this->setMwGlobals( 'wgWellFormedXml', true );
-
- $this->assertEquals(
- ' selected=""',
- Html::expandAttributes( [ 'selected' => true ] ),
- 'Boolean attributes have empty string value when value is true (wgWellFormedXml)'
- );
}
/**
*/
public function testExpandAttributesForNumbers() {
$this->assertEquals(
- ' value=1',
+ ' value="1"',
Html::expandAttributes( [ 'value' => 1 ] ),
'Integer value is cast to a string'
);
$this->assertEquals(
- ' value=1.1',
+ ' value="1.1"',
Html::expandAttributes( [ 'value' => 1.1 ] ),
'Float value is cast to a string'
);
*/
public function testExpandAttributesForObjects() {
$this->assertEquals(
- ' value=stringValue',
+ ' value="stringValue"',
Html::expandAttributes( [ 'value' => new HtmlTestValue() ] ),
'Object value is converted to a string'
);
'Empty string is always quoted'
);
$this->assertEquals(
- ' key=value',
+ ' key="value"',
Html::expandAttributes( [ 'key' => 'value' ] ),
'Simple string value needs no quotes'
);
$this->assertEquals(
- ' one=1',
+ ' one="1"',
Html::expandAttributes( [ 'one' => 1 ] ),
'Number 1 value needs no quotes'
);
$this->assertEquals(
- ' zero=0',
+ ' zero="0"',
Html::expandAttributes( [ 'zero' => 0 ] ),
'Number 0 value needs no quotes'
);
- $this->setMwGlobals( 'wgWellFormedXml', true );
-
- $this->assertEquals(
- ' empty_string=""',
- Html::expandAttributes( [ 'empty_string' => '' ] ),
- 'Attribute values are always quoted (wgWellFormedXml): Empty string'
- );
- $this->assertEquals(
- ' key="value"',
- Html::expandAttributes( [ 'key' => 'value' ] ),
- 'Attribute values are always quoted (wgWellFormedXml): Simple string'
- );
- $this->assertEquals(
- ' one="1"',
- Html::expandAttributes( [ 'one' => 1 ] ),
- 'Attribute values are always quoted (wgWellFormedXml): Number 1'
- );
- $this->assertEquals(
- ' zero="0"',
- Html::expandAttributes( [ 'zero' => 0 ] ),
- 'Attribute values are always quoted (wgWellFormedXml): Number 0'
- );
}
/**
*/
public function testNamespaceSelector() {
$this->assertEquals(
- '<select id=namespace name=namespace>' . "\n" .
- '<option value=0>(Main)</option>' . "\n" .
- '<option value=1>Talk</option>' . "\n" .
- '<option value=2>User</option>' . "\n" .
- '<option value=3>User talk</option>' . "\n" .
- '<option value=4>MyWiki</option>' . "\n" .
- '<option value=5>MyWiki Talk</option>' . "\n" .
- '<option value=6>File</option>' . "\n" .
- '<option value=7>File talk</option>' . "\n" .
- '<option value=8>MediaWiki</option>' . "\n" .
- '<option value=9>MediaWiki talk</option>' . "\n" .
- '<option value=10>Template</option>' . "\n" .
- '<option value=11>Template talk</option>' . "\n" .
- '<option value=14>Category</option>' . "\n" .
- '<option value=15>Category talk</option>' . "\n" .
- '<option value=100>Custom</option>' . "\n" .
- '<option value=101>Custom talk</option>' . "\n" .
+ '<select id="namespace" name="namespace">' . "\n" .
+ '<option value="0">(Main)</option>' . "\n" .
+ '<option value="1">Talk</option>' . "\n" .
+ '<option value="2">User</option>' . "\n" .
+ '<option value="3">User talk</option>' . "\n" .
+ '<option value="4">MyWiki</option>' . "\n" .
+ '<option value="5">MyWiki Talk</option>' . "\n" .
+ '<option value="6">File</option>' . "\n" .
+ '<option value="7">File talk</option>' . "\n" .
+ '<option value="8">MediaWiki</option>' . "\n" .
+ '<option value="9">MediaWiki talk</option>' . "\n" .
+ '<option value="10">Template</option>' . "\n" .
+ '<option value="11">Template talk</option>' . "\n" .
+ '<option value="14">Category</option>' . "\n" .
+ '<option value="15">Category talk</option>' . "\n" .
+ '<option value="100">Custom</option>' . "\n" .
+ '<option value="101">Custom talk</option>' . "\n" .
'</select>',
Html::namespaceSelector(),
'Basic namespace selector without custom options'
);
$this->assertEquals(
- '<label for=mw-test-namespace>Select a namespace:</label> ' .
- '<select id=mw-test-namespace name=wpNamespace>' . "\n" .
- '<option value=all>all</option>' . "\n" .
- '<option value=0>(Main)</option>' . "\n" .
- '<option value=1>Talk</option>' . "\n" .
- '<option value=2 selected>User</option>' . "\n" .
- '<option value=3>User talk</option>' . "\n" .
- '<option value=4>MyWiki</option>' . "\n" .
- '<option value=5>MyWiki Talk</option>' . "\n" .
- '<option value=6>File</option>' . "\n" .
- '<option value=7>File talk</option>' . "\n" .
- '<option value=8>MediaWiki</option>' . "\n" .
- '<option value=9>MediaWiki talk</option>' . "\n" .
- '<option value=10>Template</option>' . "\n" .
- '<option value=11>Template talk</option>' . "\n" .
- '<option value=14>Category</option>' . "\n" .
- '<option value=15>Category talk</option>' . "\n" .
- '<option value=100>Custom</option>' . "\n" .
- '<option value=101>Custom talk</option>' . "\n" .
+ '<label for="mw-test-namespace">Select a namespace:</label> ' .
+ '<select id="mw-test-namespace" name="wpNamespace">' . "\n" .
+ '<option value="all">all</option>' . "\n" .
+ '<option value="0">(Main)</option>' . "\n" .
+ '<option value="1">Talk</option>' . "\n" .
+ '<option value="2" selected="">User</option>' . "\n" .
+ '<option value="3">User talk</option>' . "\n" .
+ '<option value="4">MyWiki</option>' . "\n" .
+ '<option value="5">MyWiki Talk</option>' . "\n" .
+ '<option value="6">File</option>' . "\n" .
+ '<option value="7">File talk</option>' . "\n" .
+ '<option value="8">MediaWiki</option>' . "\n" .
+ '<option value="9">MediaWiki talk</option>' . "\n" .
+ '<option value="10">Template</option>' . "\n" .
+ '<option value="11">Template talk</option>' . "\n" .
+ '<option value="14">Category</option>' . "\n" .
+ '<option value="15">Category talk</option>' . "\n" .
+ '<option value="100">Custom</option>' . "\n" .
+ '<option value="101">Custom talk</option>' . "\n" .
'</select>',
Html::namespaceSelector(
[ 'selected' => '2', 'all' => 'all', 'label' => 'Select a namespace:' ],
);
$this->assertEquals(
- '<label for=namespace>Select a namespace:</label> ' .
- '<select id=namespace name=namespace>' . "\n" .
- '<option value=0>(Main)</option>' . "\n" .
- '<option value=1>Talk</option>' . "\n" .
- '<option value=2>User</option>' . "\n" .
- '<option value=3>User talk</option>' . "\n" .
- '<option value=4>MyWiki</option>' . "\n" .
- '<option value=5>MyWiki Talk</option>' . "\n" .
- '<option value=6>File</option>' . "\n" .
- '<option value=7>File talk</option>' . "\n" .
- '<option value=8>MediaWiki</option>' . "\n" .
- '<option value=9>MediaWiki talk</option>' . "\n" .
- '<option value=10>Template</option>' . "\n" .
- '<option value=11>Template talk</option>' . "\n" .
- '<option value=14>Category</option>' . "\n" .
- '<option value=15>Category talk</option>' . "\n" .
- '<option value=100>Custom</option>' . "\n" .
- '<option value=101>Custom talk</option>' . "\n" .
+ '<label for="namespace">Select a namespace:</label> ' .
+ '<select id="namespace" name="namespace">' . "\n" .
+ '<option value="0">(Main)</option>' . "\n" .
+ '<option value="1">Talk</option>' . "\n" .
+ '<option value="2">User</option>' . "\n" .
+ '<option value="3">User talk</option>' . "\n" .
+ '<option value="4">MyWiki</option>' . "\n" .
+ '<option value="5">MyWiki Talk</option>' . "\n" .
+ '<option value="6">File</option>' . "\n" .
+ '<option value="7">File talk</option>' . "\n" .
+ '<option value="8">MediaWiki</option>' . "\n" .
+ '<option value="9">MediaWiki talk</option>' . "\n" .
+ '<option value="10">Template</option>' . "\n" .
+ '<option value="11">Template talk</option>' . "\n" .
+ '<option value="14">Category</option>' . "\n" .
+ '<option value="15">Category talk</option>' . "\n" .
+ '<option value="100">Custom</option>' . "\n" .
+ '<option value="101">Custom talk</option>' . "\n" .
'</select>',
Html::namespaceSelector(
[ 'label' => 'Select a namespace:' ]
public function testCanFilterOutNamespaces() {
$this->assertEquals(
- '<select id=namespace name=namespace>' . "\n" .
- '<option value=2>User</option>' . "\n" .
- '<option value=4>MyWiki</option>' . "\n" .
- '<option value=5>MyWiki Talk</option>' . "\n" .
- '<option value=6>File</option>' . "\n" .
- '<option value=7>File talk</option>' . "\n" .
- '<option value=8>MediaWiki</option>' . "\n" .
- '<option value=9>MediaWiki talk</option>' . "\n" .
- '<option value=10>Template</option>' . "\n" .
- '<option value=11>Template talk</option>' . "\n" .
- '<option value=14>Category</option>' . "\n" .
- '<option value=15>Category talk</option>' . "\n" .
+ '<select id="namespace" name="namespace">' . "\n" .
+ '<option value="2">User</option>' . "\n" .
+ '<option value="4">MyWiki</option>' . "\n" .
+ '<option value="5">MyWiki Talk</option>' . "\n" .
+ '<option value="6">File</option>' . "\n" .
+ '<option value="7">File talk</option>' . "\n" .
+ '<option value="8">MediaWiki</option>' . "\n" .
+ '<option value="9">MediaWiki talk</option>' . "\n" .
+ '<option value="10">Template</option>' . "\n" .
+ '<option value="11">Template talk</option>' . "\n" .
+ '<option value="14">Category</option>' . "\n" .
+ '<option value="15">Category talk</option>' . "\n" .
'</select>',
Html::namespaceSelector(
[ 'exclude' => [ 0, 1, 3, 100, 101 ] ]
public function testCanDisableANamespaces() {
$this->assertEquals(
- '<select id=namespace name=namespace>' . "\n" .
- '<option disabled value=0>(Main)</option>' . "\n" .
- '<option disabled value=1>Talk</option>' . "\n" .
- '<option disabled value=2>User</option>' . "\n" .
- '<option disabled value=3>User talk</option>' . "\n" .
- '<option disabled value=4>MyWiki</option>' . "\n" .
- '<option value=5>MyWiki Talk</option>' . "\n" .
- '<option value=6>File</option>' . "\n" .
- '<option value=7>File talk</option>' . "\n" .
- '<option value=8>MediaWiki</option>' . "\n" .
- '<option value=9>MediaWiki talk</option>' . "\n" .
- '<option value=10>Template</option>' . "\n" .
- '<option value=11>Template talk</option>' . "\n" .
- '<option value=14>Category</option>' . "\n" .
- '<option value=15>Category talk</option>' . "\n" .
- '<option value=100>Custom</option>' . "\n" .
- '<option value=101>Custom talk</option>' . "\n" .
+ '<select id="namespace" name="namespace">' . "\n" .
+ '<option disabled="" value="0">(Main)</option>' . "\n" .
+ '<option disabled="" value="1">Talk</option>' . "\n" .
+ '<option disabled="" value="2">User</option>' . "\n" .
+ '<option disabled="" value="3">User talk</option>' . "\n" .
+ '<option disabled="" value="4">MyWiki</option>' . "\n" .
+ '<option value="5">MyWiki Talk</option>' . "\n" .
+ '<option value="6">File</option>' . "\n" .
+ '<option value="7">File talk</option>' . "\n" .
+ '<option value="8">MediaWiki</option>' . "\n" .
+ '<option value="9">MediaWiki talk</option>' . "\n" .
+ '<option value="10">Template</option>' . "\n" .
+ '<option value="11">Template talk</option>' . "\n" .
+ '<option value="14">Category</option>' . "\n" .
+ '<option value="15">Category talk</option>' . "\n" .
+ '<option value="100">Custom</option>' . "\n" .
+ '<option value="101">Custom talk</option>' . "\n" .
'</select>',
Html::namespaceSelector( [
'disable' => [ 0, 1, 2, 3, 4 ]
*/
public function testHtmlElementAcceptsNewHtml5TypesInHtml5Mode( $HTML5InputType ) {
$this->assertEquals(
- '<input type=' . $HTML5InputType . '>',
+ '<input type="' . $HTML5InputType . '"/>',
Html::element( 'input', [ 'type' => $HTML5InputType ] ),
'In HTML5, Html::element() should accept type="' . $HTML5InputType . '"'
);
$cases = [];
# ## Generic cases, match $attribDefault static array
- $cases[] = [ '<area>',
+ $cases[] = [ '<area/>',
'area', [ 'shape' => 'rect' ]
];
- $cases[] = [ '<button type=submit></button>',
+ $cases[] = [ '<button type="submit"></button>',
'button', [ 'formaction' => 'GET' ]
];
- $cases[] = [ '<button type=submit></button>',
+ $cases[] = [ '<button type="submit"></button>',
'button', [ 'formenctype' => 'application/x-www-form-urlencoded' ]
];
'canvas', [ 'width' => 300 ]
];
- $cases[] = [ '<command>',
+ $cases[] = [ '<command/>',
'command', [ 'type' => 'command' ]
];
'form', [ 'enctype' => 'application/x-www-form-urlencoded' ]
];
- $cases[] = [ '<input>',
+ $cases[] = [ '<input/>',
'input', [ 'formaction' => 'GET' ]
];
- $cases[] = [ '<input>',
+ $cases[] = [ '<input/>',
'input', [ 'type' => 'text' ]
];
- $cases[] = [ '<keygen>',
+ $cases[] = [ '<keygen/>',
'keygen', [ 'keytype' => 'rsa' ]
];
- $cases[] = [ '<link>',
+ $cases[] = [ '<link/>',
'link', [ 'media' => 'all' ]
];
# ## SPECIFIC CASES
# <link type="text/css">
- $cases[] = [ '<link>',
+ $cases[] = [ '<link/>',
'link', [ 'type' => 'text/css' ]
];
# <input> specific handling
- $cases[] = [ '<input type=checkbox>',
+ $cases[] = [ '<input type="checkbox"/>',
'input', [ 'type' => 'checkbox', 'value' => 'on' ],
'Default value "on" is stripped of checkboxes',
];
- $cases[] = [ '<input type=radio>',
+ $cases[] = [ '<input type="radio"/>',
'input', [ 'type' => 'radio', 'value' => 'on' ],
'Default value "on" is stripped of radio buttons',
];
- $cases[] = [ '<input type=submit value=Submit>',
+ $cases[] = [ '<input type="submit" value="Submit"/>',
'input', [ 'type' => 'submit', 'value' => 'Submit' ],
'Default value "Submit" is kept on submit buttons (for possible l10n issues)',
];
- $cases[] = [ '<input type=color>',
+ $cases[] = [ '<input type="color"/>',
'input', [ 'type' => 'color', 'value' => '' ],
];
- $cases[] = [ '<input type=range>',
+ $cases[] = [ '<input type="range"/>',
'input', [ 'type' => 'range', 'value' => '' ],
];
# <button> specific handling
# see remarks on http://msdn.microsoft.com/en-us/library/ie/ms535211%28v=vs.85%29.aspx
- $cases[] = [ '<button type=submit></button>',
+ $cases[] = [ '<button type="submit"></button>',
'button', [ 'type' => 'submit' ],
'According to standard the default type is "submit". '
. 'Depending on compatibility mode IE might use "button", instead.',
];
# <select> specific handling
- $cases[] = [ '<select multiple></select>',
+ $cases[] = [ '<select multiple=""></select>',
'select', [ 'size' => '4', 'multiple' => true ],
];
# .. with numeric value
- $cases[] = [ '<select multiple></select>',
+ $cases[] = [ '<select multiple=""></select>',
'select', [ 'size' => 4, 'multiple' => true ],
];
$cases[] = [ '<select></select>',
'Blacklist form validation attributes.'
);
$this->assertEquals(
- ' step=any',
+ ' step="any"',
Html::expandAttributes(
[
'min' => 1,
public function testWrapperInput() {
$this->assertEquals(
- '<input type=radio value=testval name=testname>',
+ '<input type="radio" value="testval" name="testname"/>',
Html::input( 'testname', 'testval', 'radio' ),
'Input wrapper with type and value.'
);
$this->assertEquals(
- '<input name=testname>',
+ '<input name="testname"/>',
Html::input( 'testname' ),
'Input wrapper with all default values.'
);
public function testWrapperCheck() {
$this->assertEquals(
- '<input type=checkbox value=1 name=testname>',
+ '<input type="checkbox" value="1" name="testname"/>',
Html::check( 'testname' ),
'Checkbox wrapper unchecked.'
);
$this->assertEquals(
- '<input checked type=checkbox value=1 name=testname>',
+ '<input checked="" type="checkbox" value="1" name="testname"/>',
Html::check( 'testname', true ),
'Checkbox wrapper checked.'
);
$this->assertEquals(
- '<input type=checkbox value=testval name=testname>',
+ '<input type="checkbox" value="testval" name="testname"/>',
Html::check( 'testname', false, [ 'value' => 'testval' ] ),
'Checkbox wrapper with a value override.'
);
public function testWrapperRadio() {
$this->assertEquals(
- '<input type=radio value=1 name=testname>',
+ '<input type="radio" value="1" name="testname"/>',
Html::radio( 'testname' ),
'Radio wrapper unchecked.'
);
$this->assertEquals(
- '<input checked type=radio value=1 name=testname>',
+ '<input checked="" type="radio" value="1" name="testname"/>',
Html::radio( 'testname', true ),
'Radio wrapper checked.'
);
$this->assertEquals(
- '<input type=radio value=testval name=testname>',
+ '<input type="radio" value="testval" name="testname"/>',
Html::radio( 'testname', false, [ 'value' => 'testval' ] ),
'Radio wrapper with a value override.'
);
public function testWrapperLabel() {
$this->assertEquals(
- '<label for=testid>testlabel</label>',
+ '<label for="testid">testlabel</label>',
Html::label( 'testlabel', 'testid' ),
'Label wrapper'
);
<?php
+use MediaWiki\MediaWikiServices;
+
/**
* @group Database
*/
public function testUserLink( $expected, $userId, $userName, $altUserName = false, $msg = '' ) {
$this->setMwGlobals( [
'wgArticlePath' => '/wiki/$1',
- 'wgWellFormedXml' => true,
] );
- $this->assertEquals( $expected,
- Linker::userLink( $userId, $userName, $altUserName, $msg )
+ $this->assertEquals(
+ $expected,
+ Linker::userLink( $userId, $userName, $altUserName ),
+ $msg
);
}
# ## ANONYMOUS USER ########################################
[
'<a href="/wiki/Special:Contributions/JohnDoe" '
- . 'title="Special:Contributions/JohnDoe" '
- . 'class="mw-userlink mw-anonuserlink">JohnDoe</a>',
+ . 'class="mw-userlink mw-anonuserlink" '
+ . 'title="Special:Contributions/JohnDoe">JohnDoe</a>',
0, 'JohnDoe', false,
],
[
'<a href="/wiki/Special:Contributions/::1" '
- . 'title="Special:Contributions/::1" '
- . 'class="mw-userlink mw-anonuserlink">::1</a>',
+ . 'class="mw-userlink mw-anonuserlink" '
+ . 'title="Special:Contributions/::1">::1</a>',
0, '::1', false,
'Anonymous with pretty IPv6'
],
[
'<a href="/wiki/Special:Contributions/0:0:0:0:0:0:0:1" '
- . 'title="Special:Contributions/0:0:0:0:0:0:0:1" '
- . 'class="mw-userlink mw-anonuserlink">::1</a>',
+ . 'class="mw-userlink mw-anonuserlink" '
+ . 'title="Special:Contributions/0:0:0:0:0:0:0:1">::1</a>',
0, '0:0:0:0:0:0:0:1', false,
'Anonymous with almost pretty IPv6'
],
[
'<a href="/wiki/Special:Contributions/0000:0000:0000:0000:0000:0000:0000:0001" '
- . 'title="Special:Contributions/0000:0000:0000:0000:0000:0000:0000:0001" '
- . 'class="mw-userlink mw-anonuserlink">::1</a>',
+ . 'class="mw-userlink mw-anonuserlink" '
+ . 'title="Special:Contributions/0000:0000:0000:0000:0000:0000:0000:0001">::1</a>',
0, '0000:0000:0000:0000:0000:0000:0000:0001', false,
'Anonymous with full IPv6'
],
[
'<a href="/wiki/Special:Contributions/::1" '
- . 'title="Special:Contributions/::1" '
- . 'class="mw-userlink mw-anonuserlink">AlternativeUsername</a>',
+ . 'class="mw-userlink mw-anonuserlink" '
+ . 'title="Special:Contributions/::1">AlternativeUsername</a>',
0, '::1', 'AlternativeUsername',
'Anonymous with pretty IPv6 and an alternative username'
],
# IPV4
[
'<a href="/wiki/Special:Contributions/127.0.0.1" '
- . 'title="Special:Contributions/127.0.0.1" '
- . 'class="mw-userlink mw-anonuserlink">127.0.0.1</a>',
+ . 'class="mw-userlink mw-anonuserlink" '
+ . 'title="Special:Contributions/127.0.0.1">127.0.0.1</a>',
0, '127.0.0.1', false,
'Anonymous with IPv4'
],
[
'<a href="/wiki/Special:Contributions/127.0.0.1" '
- . 'title="Special:Contributions/127.0.0.1" '
- . 'class="mw-userlink mw-anonuserlink">AlternativeUsername</a>',
+ . 'class="mw-userlink mw-anonuserlink" '
+ . 'title="Special:Contributions/127.0.0.1">AlternativeUsername</a>',
0, '127.0.0.1', 'AlternativeUsername',
'Anonymous with IPv4 and an alternative username'
],
$this->setMwGlobals( [
'wgScript' => '/wiki/index.php',
'wgArticlePath' => '/wiki/$1',
- 'wgWellFormedXml' => true,
'wgCapitalLinks' => true,
'wgConf' => $conf,
] );
$this->setMwGlobals( [
'wgScript' => '/wiki/index.php',
'wgArticlePath' => '/wiki/$1',
- 'wgWellFormedXml' => true,
'wgCapitalLinks' => true,
'wgConf' => $conf,
] );
];
// @codingStandardsIgnoreEnd
}
+
+ public static function provideLinkBeginHook() {
+ // @codingStandardsIgnoreStart Generic.Files.LineLength
+ return [
+ // Modify $html
+ [
+ function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+ $html = 'foobar';
+ },
+ '<a href="/wiki/Special:BlankPage" title="Special:BlankPage">foobar</a>'
+ ],
+ // Modify $attribs
+ [
+ function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+ $attribs['bar'] = 'baz';
+ },
+ '<a href="/wiki/Special:BlankPage" title="Special:BlankPage" bar="baz">Special:BlankPage</a>'
+ ],
+ // Modify $query
+ [
+ function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+ $query['bar'] = 'baz';
+ },
+ '<a href="/w/index.php?title=Special:BlankPage&bar=baz" title="Special:BlankPage">Special:BlankPage</a>'
+ ],
+ // Force HTTP $options
+ [
+ function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+ $options = [ 'http' ];
+ },
+ '<a href="http://example.org/wiki/Special:BlankPage" title="Special:BlankPage">Special:BlankPage</a>'
+ ],
+ // Force 'forcearticlepath' in $options
+ [
+ function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+ $options = [ 'forcearticlepath' ];
+ $query['foo'] = 'bar';
+ },
+ '<a href="/wiki/Special:BlankPage?foo=bar" title="Special:BlankPage">Special:BlankPage</a>'
+ ],
+ // Abort early
+ [
+ function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+ $ret = 'foobar';
+ return false;
+ },
+ 'foobar'
+ ],
+ ];
+ // @codingStandardsIgnoreEnd
+ }
+
+ /**
+ * @covers MediaWiki\Linker\LinkRenderer::runLegacyBeginHook
+ * @dataProvider provideLinkBeginHook
+ */
+ public function testLinkBeginHook( $callback, $expected ) {
+ $this->setMwGlobals( [
+ 'wgArticlePath' => '/wiki/$1',
+ 'wgServer' => '//example.org',
+ 'wgCanonicalServer' => 'http://example.org',
+ 'wgScriptPath' => '/w',
+ 'wgScript' => '/w/index.php',
+ ] );
+
+ $this->setMwGlobals( 'wgHooks', [ 'LinkBegin' => [ $callback ] ] );
+ $title = SpecialPage::getTitleFor( 'Blankpage' );
+ $out = Linker::link( $title );
+ $this->assertEquals( $expected, $out );
+ }
+
+ public static function provideLinkEndHook() {
+ return [
+ // Override $html
+ [
+ function( $dummy, $title, $options, &$html, &$attribs, &$ret ) {
+ $html = 'foobar';
+ },
+ '<a href="/wiki/Special:BlankPage" title="Special:BlankPage">foobar</a>'
+ ],
+ // Modify $attribs
+ [
+ function( $dummy, $title, $options, &$html, &$attribs, &$ret ) {
+ $attribs['bar'] = 'baz';
+ },
+ '<a href="/wiki/Special:BlankPage" title="Special:BlankPage" bar="baz">Special:BlankPage</a>'
+ ],
+ // Fully override return value and abort hook
+ [
+ function( $dummy, $title, $options, &$html, &$attribs, &$ret ) {
+ $ret = 'blahblahblah';
+ return false;
+ },
+ 'blahblahblah'
+ ],
+
+ ];
+ }
+
+ /**
+ * @covers MediaWiki\Linker\LinkRenderer::buildAElement
+ * @dataProvider provideLinkEndHook
+ */
+ public function testLinkEndHook( $callback, $expected ) {
+ $this->setMwGlobals( [
+ 'wgArticlePath' => '/wiki/$1',
+ ] );
+
+ $this->setMwGlobals( 'wgHooks', [ 'LinkEnd' => [ $callback ] ] );
+
+ $title = SpecialPage::getTitleFor( 'Blankpage' );
+ $out = Linker::link( $title );
+ $this->assertEquals( $expected, $out );
+ }
+
+ /**
+ * @covers Linker::getLinkColour
+ */
+ public function testGetLinkColour() {
+ $linkCache = MediaWikiServices::getInstance()->getLinkCache();
+ $foobarTitle = Title::makeTitle( NS_MAIN, 'FooBar' );
+ $redirectTitle = Title::makeTitle( NS_MAIN, 'Redirect' );
+ $userTitle = Title::makeTitle( NS_USER, 'Someuser' );
+ $linkCache->addGoodLinkObj(
+ 1, // id
+ $foobarTitle,
+ 10, // len
+ 0 // redir
+ );
+ $linkCache->addGoodLinkObj(
+ 2, // id
+ $redirectTitle,
+ 10, // len
+ 1 // redir
+ );
+
+ $linkCache->addGoodLinkObj(
+ 3, // id
+ $userTitle,
+ 10, // len
+ 0 // redir
+ );
+
+ $this->assertEquals(
+ '',
+ Linker::getLinkColour( $foobarTitle, 0 )
+ );
+
+ $this->assertEquals(
+ 'stub',
+ Linker::getLinkColour( $foobarTitle, 20 )
+ );
+
+ $this->assertEquals(
+ 'mw-redirect',
+ Linker::getLinkColour( $redirectTitle, 0 )
+ );
+
+ $this->assertEquals(
+ '',
+ Linker::getLinkColour( $userTitle, 20 )
+ );
+ }
}
<?php
use Liuggio\StatsdClient\Factory\StatsdDataFactory;
+use MediaWiki\Interwiki\InterwikiLookup;
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Linker\LinkRendererFactory;
use MediaWiki\MediaWikiServices;
+use MediaWiki\Services\DestructibleService;
+use MediaWiki\Services\SalvageableService;
use MediaWiki\Services\ServiceDisabledException;
/**
*
* @group MediaWiki
*/
-class MediaWikiServicesTest extends PHPUnit_Framework_TestCase {
+class MediaWikiServicesTest extends MediaWikiTestCase {
/**
* @return Config
$newServices = $this->newMediaWikiServices();
$oldServices = MediaWikiServices::forceGlobalInstance( $newServices );
+ $service1 = $this->getMock( SalvageableService::class );
+ $service1->expects( $this->never() )
+ ->method( 'salvage' );
+
+ $newServices->defineService(
+ 'Test',
+ function() use ( $service1 ) {
+ return $service1;
+ }
+ );
+
+ // force instantiation
+ $newServices->getService( 'Test' );
+
MediaWikiServices::resetGlobalInstance( $this->newTestConfig() );
$theServices = MediaWikiServices::getInstance();
+ $this->assertSame(
+ $service1,
+ $theServices->getService( 'Test' ),
+ 'service definition should survive reset'
+ );
+
+ $this->assertNotSame( $theServices, $newServices );
+ $this->assertNotSame( $theServices, $oldServices );
+
+ MediaWikiServices::forceGlobalInstance( $oldServices );
+ }
+
+ public function testResetGlobalInstance_quick() {
+ $newServices = $this->newMediaWikiServices();
+ $oldServices = MediaWikiServices::forceGlobalInstance( $newServices );
+
+ $service1 = $this->getMock( SalvageableService::class );
+ $service1->expects( $this->never() )
+ ->method( 'salvage' );
+
+ $service2 = $this->getMock( SalvageableService::class );
+ $service2->expects( $this->once() )
+ ->method( 'salvage' )
+ ->with( $service1 );
+
+ // sequence of values the instantiator will return
+ $instantiatorReturnValues = [
+ $service1,
+ $service2,
+ ];
+
+ $newServices->defineService(
+ 'Test',
+ function() use ( &$instantiatorReturnValues ) {
+ return array_shift( $instantiatorReturnValues );
+ }
+ );
+
+ // force instantiation
+ $newServices->getService( 'Test' );
+
+ MediaWikiServices::resetGlobalInstance( $this->newTestConfig(), 'quick' );
+ $theServices = MediaWikiServices::getInstance();
+
+ $this->assertSame( $service2, $theServices->getService( 'Test' ) );
+
$this->assertNotSame( $theServices, $newServices );
$this->assertNotSame( $theServices, $oldServices );
}
MediaWikiServices::forceGlobalInstance( $oldServices );
+ $newServices->destroy();
}
public function testResetChildProcessServices() {
$newServices = $this->newMediaWikiServices();
$oldServices = MediaWikiServices::forceGlobalInstance( $newServices );
- $lbFactory = $this->getMockBuilder( 'LBFactorySimple' )
- ->disableOriginalConstructor()
- ->getMock();
+ $service1 = $this->getMock( DestructibleService::class );
+ $service1->expects( $this->once() )
+ ->method( 'destroy' );
- $lbFactory->expects( $this->once() )
+ $service2 = $this->getMock( DestructibleService::class );
+ $service2->expects( $this->never() )
->method( 'destroy' );
- $newServices->redefineService(
- 'DBLoadBalancerFactory',
- function() use ( $lbFactory ) {
- return $lbFactory;
+ // sequence of values the instantiator will return
+ $instantiatorReturnValues = [
+ $service1,
+ $service2,
+ ];
+
+ $newServices->defineService(
+ 'Test',
+ function() use ( &$instantiatorReturnValues ) {
+ return array_shift( $instantiatorReturnValues );
}
);
// force the service to become active, so we can check that it does get destroyed
- $oldLBFactory = $newServices->getService( 'DBLoadBalancerFactory' );
+ $oldTestService = $newServices->getService( 'Test' );
MediaWikiServices::resetChildProcessServices();
$finalServices = MediaWikiServices::getInstance();
- $newLBFactory = $finalServices->getService( 'DBLoadBalancerFactory' );
-
- $this->assertNotSame( $oldLBFactory, $newLBFactory );
+ $newTestService = $finalServices->getService( 'Test' );
+ $this->assertNotSame( $oldTestService, $newTestService );
MediaWikiServices::forceGlobalInstance( $oldServices );
}
// All getters should be named just like the service, with "get" added.
foreach ( $getServiceCases as $name => $case ) {
+ if ( $name[0] === '_' ) {
+ // Internal service, no getter
+ continue;
+ }
list( $service, $class ) = $case;
$getterCases[$name] = [
'get' . $service,
'SiteStore' => [ 'SiteStore', SiteStore::class ],
'SiteLookup' => [ 'SiteLookup', SiteLookup::class ],
'StatsdDataFactory' => [ 'StatsdDataFactory', StatsdDataFactory::class ],
+ 'InterwikiLookup' => [ 'InterwikiLookup', InterwikiLookup::class ],
'EventRelayerGroup' => [ 'EventRelayerGroup', EventRelayerGroup::class ],
'SearchEngineFactory' => [ 'SearchEngineFactory', SearchEngineFactory::class ],
'SearchEngineConfig' => [ 'SearchEngineConfig', SearchEngineConfig::class ],
'DBLoadBalancerFactory' => [ 'DBLoadBalancerFactory', 'LBFactory' ],
'DBLoadBalancer' => [ 'DBLoadBalancer', 'LoadBalancer' ],
'WatchedItemStore' => [ 'WatchedItemStore', WatchedItemStore::class ],
+ 'GenderCache' => [ 'GenderCache', GenderCache::class ],
+ 'LinkCache' => [ 'LinkCache', LinkCache::class ],
+ 'LinkRenderer' => [ 'LinkRenderer', LinkRenderer::class ],
+ 'LinkRendererFactory' => [ 'LinkRendererFactory', LinkRendererFactory::class ],
+ '_MediaWikiTitleCodec' => [ '_MediaWikiTitleCodec', MediaWikiTitleCodec::class ],
+ 'TitleFormatter' => [ 'TitleFormatter', TitleFormatter::class ],
+ 'TitleParser' => [ 'TitleParser', TitleParser::class ],
];
}
);
// Sysop with mergehistory permission
- $sysop = User::newFromName( 'UTSysop' );
+ $sysop = static::getTestSysop()->getUser();
$status = $mh->checkPermissions( $sysop, '' );
$this->assertTrue( $status->isOK() );
// Normal user
- $notSysop = User::newFromName( 'UTNotSysop' );
- $notSysop->addToDatabase();
+ $notSysop = static::getTestUser()->getUser();
$status = $mh->checkPermissions( $notSysop, '' );
$this->assertTrue( $status->hasMessage( 'mergehistory-fail-permission' ) );
}
Title::newFromText( 'Merge2' )
);
- $mh->merge( User::newFromName( 'UTSysop' ) );
+ $sysop = static::getTestSysop()->getUser();
+ $mh->merge( $sysop );
$this->assertEquals( $mh->getMergedRevisionCount(), 1 );
}
}
[
// Don't condition wrap raw modules (like the startup module)
[ 'test.raw', ResourceLoaderModule::TYPE_SCRIPTS ],
- '<script async src="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.raw&only=scripts&skin=fallback"></script>'
+ '<script async="" src="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.raw&only=scripts&skin=fallback"></script>'
],
// Load module styles only
// This also tests the order the modules are put into the url
[
[ [ 'test.baz', 'test.foo', 'test.bar' ], ResourceLoaderModule::TYPE_STYLES ],
- '<link rel=stylesheet href="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.bar%2Cbaz%2Cfoo&only=styles&skin=fallback">'
+ '<link rel="stylesheet" href="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.bar%2Cbaz%2Cfoo&only=styles&skin=fallback"/>'
],
// Load private module (only=scripts)
[
// noscript group
[
[ 'test.noscript', ResourceLoaderModule::TYPE_STYLES ],
- '<noscript><link rel=stylesheet href="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.noscript&only=styles&skin=fallback"></noscript>'
+ '<noscript><link rel="stylesheet" href="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.noscript&only=styles&skin=fallback"/></noscript>'
],
// Load two modules in separate groups
[
$this->setMwGlobals( [
'wgResourceLoaderDebug' => false,
'wgLoadScript' => 'http://127.0.0.1:8080/w/load.php',
- // Affects whether CDATA is inserted
- 'wgWellFormedXml' => false,
] );
$class = new ReflectionClass( 'OutputPage' );
$method = $class->getMethod( 'makeResourceLoaderLink' );
$this->assertSame( 'Bar!', $services->getService( 'Bar' ) );
}
+ public function testImportWiring() {
+ $services = $this->newServiceContainer();
+
+ $wiring = [
+ 'Foo' => function() {
+ return 'Foo!';
+ },
+ 'Bar' => function() {
+ return 'Bar!';
+ },
+ 'Car' => function() {
+ return 'FUBAR!';
+ },
+ ];
+
+ $services->applyWiring( $wiring );
+
+ $newServices = $this->newServiceContainer();
+
+ // define a service before importing, so we can later check that
+ // existing service instances survive importWiring()
+ $newServices->defineService( 'Car', function() {
+ return 'Car!';
+ } );
+
+ // force instantiation
+ $newServices->getService( 'Car' );
+
+ // Define another service, so we can later check that extra wiring
+ // is not lost.
+ $newServices->defineService( 'Xar', function() {
+ return 'Xar!';
+ } );
+
+ // import wiring, but skip `Bar`
+ $newServices->importWiring( $services, [ 'Bar' ] );
+
+ $this->assertNotContains( 'Bar', $newServices->getServiceNames(), 'Skip `Bar` service' );
+ $this->assertSame( 'Foo!', $newServices->getService( 'Foo' ) );
+
+ // import all wiring, but preserve existing service instance
+ $newServices->importWiring( $services );
+
+ $this->assertContains( 'Bar', $newServices->getServiceNames(), 'Import all services' );
+ $this->assertSame( 'Bar!', $newServices->getService( 'Bar' ) );
+ $this->assertSame( 'Car!', $newServices->getService( 'Car' ), 'Use existing service instance' );
+ $this->assertSame( 'Xar!', $newServices->getService( 'Xar' ), 'Predefined services are kept' );
+ }
+
public function testLoadWiringFiles() {
$services = $this->newServiceContainer();
$this->assertSame( $theService1, $services->getService( $name ) );
}
+ public function testRedefineService_disabled() {
+ $services = $this->newServiceContainer( [ 'Foo' ] );
+
+ $theService1 = new stdClass();
+ $name = 'TestService92834576';
+
+ $services->defineService( $name, function() {
+ return 'Foo';
+ } );
+
+ // disable the service. we should be able to redefine it anyway.
+ $services->disableService( $name );
+
+ $services->redefineService( $name, function() use ( $theService1 ) {
+ return $theService1;
+ } );
+
+ // force instantiation, check result
+ $this->assertSame( $theService1, $services->getService( $name ) );
+ }
+
public function testRedefineService_fail_undefined() {
$services = $this->newServiceContainer();
$this->assertContains( 'Bar', $services->getServiceNames() );
$this->assertContains( 'Qux', $services->getServiceNames() );
- // re-enable Bar service
- $services->redefineService( 'Bar', function() {
- return new stdClass();
- } );
-
- $services->getService( 'Bar' );
-
$this->setExpectedException( 'MediaWiki\Services\ServiceDisabledException' );
$services->getService( 'Qux' );
}
$this->user->removeGroup( $group );
}
if ( $change ) {
+ // Disable CAS check before saving. The User object may have been initialized from cached
+ // information that may be out of whack with the database during testing. If tests were
+ // perfectly isolated, this would not happen. But if it does happen, let's just ignore the
+ // inconsistency, and just write the data we want - during testing, we are not worried
+ // about data loss.
+ $this->user->mTouched = '';
$this->user->saveSettings();
}
}
throw new MWException( "Passed User has not been added to the database yet!" );
}
- $passwordFactory = new PasswordFactory();
- $passwordFactory->init( RequestContext::getMain()->getConfig() );
- // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
- $passwordFactory->setDefaultType( 'A' );
- $pwhash = $passwordFactory->newFromPlaintext( $password );
- wfGetDB( DB_MASTER )->update(
+ $dbw = wfGetDB( DB_MASTER );
+ $row = $dbw->selectRow(
'user',
- [ 'user_password' => $pwhash->toString() ],
+ [ 'user_password' ],
[ 'user_id' => $user->getId() ],
__METHOD__
);
+ if ( !$row ) {
+ throw new MWException( "Passed User has an ID but is not in the database?" );
+ }
+
+ $passwordFactory = new PasswordFactory();
+ $passwordFactory->init( RequestContext::getMain()->getConfig() );
+ if ( !$passwordFactory->newFromCiphertext( $row->user_password )->equals( $password ) ) {
+ $passwordHash = $passwordFactory->newFromPlaintext( $password );
+ $dbw->update(
+ 'user',
+ [ 'user_password' => $passwordHash->toString() ],
+ [ 'user_id' => $user->getId() ],
+ __METHOD__
+ );
+ }
}
/**
--- /dev/null
+<?php
+
+/**
+ * @since 1.28
+ */
+class TestUserRegistry {
+
+ /** @var TestUser[] (group key => TestUser) */
+ private static $testUsers = [];
+
+ /** @var int Count of users that have been generated */
+ private static $counter = 0;
+
+ /** @var int Random int, included in IDs */
+ private static $randInt;
+
+ public static function getNextId() {
+ if ( !self::$randInt ) {
+ self::$randInt = mt_rand( 1, 0xFFFFFF );
+ }
+ return sprintf( '%06x.%03x', self::$randInt, ++self::$counter );
+ }
+
+ /**
+ * Get a TestUser object that the caller may modify.
+ *
+ * @since 1.28
+ *
+ * @param string $testName Caller's __CLASS__. Used to generate the
+ * user's username.
+ * @param string[] $groups Groups the test user should be added to.
+ * @return TestUser
+ */
+ public static function getMutableTestUser( $testName, $groups = [] ) {
+ $id = self::getNextId();
+ $password = wfRandomString( 20 );
+ $testUser = new TestUser(
+ "TestUser $testName $id", // username
+ "Name $id", // real name
+ "$id@mediawiki.test", // e-mail
+ $groups, // groups
+ $password // password
+ );
+ $testUser->getUser()->clearInstanceCache();
+ return $testUser;
+ }
+
+ /**
+ * Get a TestUser object that the caller may not modify.
+ *
+ * Whenever possible, unit tests should use immutable users, because
+ * immutable users can be reused in multiple tests, which helps keep
+ * the unit tests fast.
+ *
+ * @since 1.28
+ *
+ * @param string[] $groups Groups the test user should be added to.
+ * @return TestUser
+ */
+ public static function getImmutableTestUser( $groups = [] ) {
+ $groups = array_unique( $groups );
+ sort( $groups );
+ $key = implode( ',', $groups );
+
+ $testUser = isset( self::$testUsers[$key] )
+ ? self::$testUsers[$key]
+ : false;
+
+ if ( !$testUser || !$testUser->getUser()->isLoggedIn() ) {
+ $id = self::getNextId();
+ // Hack! If this is the primary sysop account, make the username
+ // be 'UTSysop', for back-compat, and for the sake of PHPUnit data
+ // provider methods, which are executed before the test database
+ // is set up. See T136348.
+ if ( $groups === [ 'bureaucrat', 'sysop' ] ) {
+ $username = 'UTSysop';
+ $password = 'UTSysopPassword';
+ } else {
+ $username = "TestUser $id";
+ $password = wfRandomString( 20 );
+ }
+ self::$testUsers[$key] = $testUser = new TestUser(
+ $username, // username
+ "Name $id", // real name
+ "$id@mediawiki.test", // e-mail
+ $groups, // groups
+ $password // password
+ );
+ }
+
+ $testUser->getUser()->clearInstanceCache();
+ return self::$testUsers[$key];
+ }
+
+ /**
+ * Clear the registry.
+ *
+ * TestUsers created by this class will not be deleted, but any handles
+ * to existing immutable TestUsers will be deleted, ensuring these users
+ * are not reused. We don't reset the counter or random string by design.
+ *
+ * @since 1.28
+ *
+ * @param string[] $groups Groups the test user should be added to.
+ * @return TestUser
+ */
+ public static function clear() {
+ self::$testUsers = [];
+ }
+}
]
]
] );
+
+ // Reset TitleParser since we modified $wgLocalInterwikis
+ $this->setService( 'TitleParser', new MediaWikiTitleCodec(
+ Language::factory( 'en' ),
+ new GenderCache(),
+ [ 'localtestiw' ]
+ ) );
}
/**
$this->assertEquals( $title->getInterwiki(), $fragmentTitle->getInterwiki() );
$this->assertEquals( $fragment, $fragmentTitle->getFragment() );
}
+
+ public function provideGetPrefixedText() {
+ return [
+ // ns = 0
+ [
+ Title::makeTitle( NS_MAIN, 'Foobar' ),
+ 'Foobar'
+ ],
+ // ns = 2
+ [
+ Title::makeTitle( NS_USER, 'Foobar' ),
+ 'User:Foobar'
+ ],
+ // fragment not included
+ [
+ Title::makeTitle( NS_MAIN, 'Foobar', 'fragment' ),
+ 'Foobar'
+ ],
+ // ns = -2
+ [
+ Title::makeTitle( NS_MEDIA, 'Foobar' ),
+ 'Media:Foobar'
+ ],
+ // non-existent namespace
+ [
+ Title::makeTitle( 100000, 'Foobar' ),
+ ':Foobar'
+ ],
+ ];
+ }
+
+ /**
+ * @covers Title::getPrefixedText
+ * @dataProvider provideGetPrefixedText
+ */
+ public function testGetPrefixedText( Title $title, $expected ) {
+ $this->assertEquals( $expected, $title->getPrefixedText() );
+ }
}
parent::setUp();
self::$users['WatchedItemIntegrationTestUser']
= new TestUser( 'WatchedItemIntegrationTestUser' );
+
+ $this->hideDeprecated( 'WatchedItem::fromUserTitle' );
+ $this->hideDeprecated( 'WatchedItem::addWatch' );
+ $this->hideDeprecated( 'WatchedItem::removeWatch' );
+ $this->hideDeprecated( 'WatchedItem::isWatched' );
+ $this->hideDeprecated( 'WatchedItem::resetNotificationTimestamp' );
+ $this->hideDeprecated( 'WatchedItem::duplicateEntries' );
+ $this->hideDeprecated( 'WatchedItem::batchAddWatch' );
}
private function getUser() {
}
public function testWatchAndUnWatchItem() {
+
$user = $this->getUser();
$title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
// Cleanup after previous tests
);
}
- public function testUpdateAndResetNotificationTimestamp() {
+ public function testUpdateResetAndSetNotificationTimestamp() {
$user = $this->getUser();
$otherUser = ( new TestUser( 'WatchedItemStoreIntegrationTestUser_otherUser' ) )->getUser();
$title = Title::newFromText( 'WatchedItemStoreIntegrationTestPage' );
[ [ $title, '20150202020202' ] ], $initialVisitingWatchers + 1
)
);
+
+ // setNotificationTimestampsForUser specifying a title
+ $this->assertTrue(
+ $store->setNotificationTimestampsForUser( $user, '20200202020202', [ $title ] )
+ );
+ $this->assertEquals(
+ '20200202020202',
+ $store->getWatchedItem( $user, $title )->getNotificationTimestamp()
+ );
+
+ // setNotificationTimestampsForUser not specifying a title
+ $this->assertTrue(
+ $store->setNotificationTimestampsForUser( $user, '20210202020202' )
+ );
+ $this->assertEquals(
+ '20210202020202',
+ $store->getWatchedItem( $user, $title )->getNotificationTimestamp()
+ );
}
public function testDuplicateAllAssociatedEntries() {
ScopedCallback::consume( $scopedOverrideRevision );
}
+ public function testSetNotificationTimestampsForUser_anonUser() {
+ $store = $this->newWatchedItemStore(
+ $this->getMockLoadBalancer( $this->getMockDb() ),
+ $this->getMockCache()
+ );
+ $this->assertFalse( $store->setNotificationTimestampsForUser( $this->getAnonUser(), '' ) );
+ }
+
+ public function testSetNotificationTimestampsForUser_allRows() {
+ $user = $this->getMockNonAnonUserWithId( 1 );
+ $timestamp = '20100101010101';
+
+ $mockDb = $this->getMockDb();
+ $mockDb->expects( $this->once() )
+ ->method( 'update' )
+ ->with(
+ 'watchlist',
+ [ 'wl_notificationtimestamp' => 'TS' . $timestamp . 'TS' ],
+ [ 'wl_user' => 1 ]
+ )
+ ->will( $this->returnValue( true ) );
+ $mockDb->expects( $this->exactly( 1 ) )
+ ->method( 'timestamp' )
+ ->will( $this->returnCallback( function( $value ) {
+ return 'TS' . $value . 'TS';
+ } ) );
+
+ $store = $this->newWatchedItemStore(
+ $this->getMockLoadBalancer( $mockDb ),
+ $this->getMockCache()
+ );
+
+ $this->assertTrue(
+ $store->setNotificationTimestampsForUser( $user, $timestamp )
+ );
+ }
+
+ public function testSetNotificationTimestampsForUser_specificTargets() {
+ $user = $this->getMockNonAnonUserWithId( 1 );
+ $timestamp = '20100101010101';
+ $targets = [ new TitleValue( 0, 'Foo' ), new TitleValue( 0, 'Bar' ) ];
+
+ $mockDb = $this->getMockDb();
+ $mockDb->expects( $this->once() )
+ ->method( 'update' )
+ ->with(
+ 'watchlist',
+ [ 'wl_notificationtimestamp' => 'TS' . $timestamp . 'TS' ],
+ [ 'wl_user' => 1, 0 => 'makeWhereFrom2d return value' ]
+ )
+ ->will( $this->returnValue( true ) );
+ $mockDb->expects( $this->exactly( 1 ) )
+ ->method( 'timestamp' )
+ ->will( $this->returnCallback( function( $value ) {
+ return 'TS' . $value . 'TS';
+ } ) );
+ $mockDb->expects( $this->once() )
+ ->method( 'makeWhereFrom2d' )
+ ->with(
+ [ [ 'Foo' => 1, 'Bar' => 1 ] ],
+ $this->isType( 'string' ),
+ $this->isType( 'string' )
+ )
+ ->will( $this->returnValue( 'makeWhereFrom2d return value' ) );
+
+ $store = $this->newWatchedItemStore(
+ $this->getMockLoadBalancer( $mockDb ),
+ $this->getMockCache()
+ );
+
+ $this->assertTrue(
+ $store->setNotificationTimestampsForUser( $user, $timestamp, $targets )
+ );
+ }
+
public function testUpdateNotificationTimestamp_watchersExist() {
$mockDb = $this->getMockDb();
$mockDb->expects( $this->once() )
protected function setUp() {
parent::setUp();
- $this->setMwGlobals( [
- 'wgWellFormedXml' => true,
- ] );
$this->select = new XmlSelect();
}
$this->setMwGlobals( [
'wgLang' => $langObj,
- 'wgWellFormedXml' => true,
'wgUseMediaWikiUIEverywhere' => false,
] );
}
+++ /dev/null
-<?php
-
-/**
- * @group Database
- * @group API
- * @group medium
- *
- * @covers ApiCreateAccount
- */
-class ApiCreateAccountTest extends ApiTestCase {
- protected function setUp() {
- parent::setUp();
- $this->setMwGlobals( [ 'wgEnableEmail' => true ] );
- }
-
- /**
- * Test the account creation API with a valid request. Also
- * make sure the new account can log in and is valid.
- *
- * This test does multiple API requests so it might end up being
- * a bit slow. Raise the default timeout.
- * @group medium
- */
- public function testValid() {
- global $wgServer;
-
- if ( !isset( $wgServer ) ) {
- $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
- }
-
- $password = PasswordFactory::generateRandomPasswordString();
-
- $ret = $this->doApiRequest( [
- 'action' => 'createaccount',
- 'name' => 'Apitestnew',
- 'password' => $password,
- 'email' => 'test@domain.test',
- 'realname' => 'Test Name'
- ] );
-
- $result = $ret[0];
- $this->assertNotInternalType( 'bool', $result );
- $this->assertNotInternalType( 'null', $result['createaccount'] );
-
- // Should first ask for token.
- $a = $result['createaccount'];
- $this->assertEquals( 'NeedToken', $a['result'] );
- $token = $a['token'];
-
- // Finally create the account
- $ret = $this->doApiRequest(
- [
- 'action' => 'createaccount',
- 'name' => 'Apitestnew',
- 'password' => $password,
- 'token' => $token,
- 'email' => 'test@domain.test',
- 'realname' => 'Test Name'
- ],
- $ret[2]
- );
-
- $result = $ret[0];
- $this->assertNotInternalType( 'bool', $result );
- $this->assertEquals( 'Success', $result['createaccount']['result'] );
-
- // Try logging in with the new user.
- $ret = $this->doApiRequest( [
- 'action' => 'login',
- 'lgname' => 'Apitestnew',
- 'lgpassword' => $password,
- ] );
-
- $result = $ret[0];
- $this->assertNotInternalType( 'bool', $result );
- $this->assertNotInternalType( 'null', $result['login'] );
-
- $a = $result['login']['result'];
- $this->assertEquals( 'NeedToken', $a );
- $token = $result['login']['token'];
-
- $ret = $this->doApiRequest(
- [
- 'action' => 'login',
- 'lgtoken' => $token,
- 'lgname' => 'Apitestnew',
- 'lgpassword' => $password,
- ],
- $ret[2]
- );
-
- $result = $ret[0];
-
- $this->assertNotInternalType( 'bool', $result );
- $a = $result['login']['result'];
-
- $this->assertEquals( 'Success', $a );
-
- // log out to destroy the session
- $ret = $this->doApiRequest(
- [
- 'action' => 'logout',
- ],
- $ret[2]
- );
- $this->assertEquals( [], $ret[0] );
- }
-
- /**
- * Make sure requests with no names are invalid.
- * @expectedException UsageException
- */
- public function testNoName() {
- $this->doApiRequest( [
- 'action' => 'createaccount',
- 'token' => LoginForm::getCreateaccountToken()->toString(),
- 'password' => 'password',
- ] );
- }
-
- /**
- * Make sure requests with no password are invalid.
- * @expectedException UsageException
- */
- public function testNoPassword() {
- $this->doApiRequest( [
- 'action' => 'createaccount',
- 'name' => 'testName',
- 'token' => LoginForm::getCreateaccountToken()->toString(),
- ] );
- }
-
- /**
- * Make sure requests with existing users are invalid.
- * @expectedException UsageException
- */
- public function testExistingUser() {
- $this->doApiRequest( [
- 'action' => 'createaccount',
- 'name' => 'Apitestsysop',
- 'token' => LoginForm::getCreateaccountToken()->toString(),
- 'password' => 'password',
- 'email' => 'test@domain.test',
- ] );
- }
-
- /**
- * Make sure requests with invalid emails are invalid.
- * @expectedException UsageException
- */
- public function testInvalidEmail() {
- $this->doApiRequest( [
- 'action' => 'createaccount',
- 'name' => 'Test User',
- 'token' => LoginForm::getCreateaccountToken()->toString(),
- 'password' => 'password',
- 'email' => 'invalid',
- ] );
- }
-}
* Test result of attempted login with an empty username
*/
public function testApiLoginNoName() {
+ global $wgDisableAuthManager;
+
$session = [
'wsTokenSecrets' => [ 'login' => 'foobar' ],
];
'lgname' => '', 'lgpassword' => self::$users['sysop']->password,
'lgtoken' => (string)( new MediaWiki\Session\Token( 'foobar', '' ) )
], $session );
- $this->assertEquals( 'NoName', $data[0]['login']['result'] );
+ $this->assertEquals( $wgDisableAuthManager ? 'NoName' : 'Failed', $data[0]['login']['result'] );
}
public function testApiLoginBadPass() {
- global $wgServer;
+ global $wgServer, $wgDisableAuthManager;
$user = self::$users['sysop'];
$user->getUser()->logout();
$this->assertNotInternalType( "bool", $result );
$a = $result["login"]["result"];
- $this->assertEquals( "WrongPass", $a );
+ $this->assertEquals( $wgDisableAuthManager ? 'WrongPass' : 'Failed', $a );
}
public function testApiLoginGoodPass() {
$passwordFactory = new PasswordFactory();
$passwordFactory->init( RequestContext::getMain()->getConfig() );
// A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
- $passwordFactory->setDefaultType( 'A' );
- $pwhash = $passwordFactory->newFromPlaintext( 'foobaz' );
+ $passwordHash = $passwordFactory->newFromPlaintext( 'foobaz' );
$dbw = wfGetDB( DB_MASTER );
$dbw->insert(
[
'bp_user' => $centralId,
'bp_app_id' => 'foo',
- 'bp_password' => $pwhash->toString(),
+ 'bp_password' => $passwordHash->toString(),
'bp_token' => '',
'bp_restrictions' => MWRestrictions::newDefault()->toJson(),
'bp_grants' => '["test"]',
];
}
+ /**
+ * @covers ApiMain::lacksSameOriginSecurity
+ */
+ public function testLacksSameOriginSecurity() {
+ // Basic test
+ $main = new ApiMain( new FauxRequest( [ 'action' => 'query', 'meta' => 'siteinfo' ] ) );
+ $this->assertFalse( $main->lacksSameOriginSecurity(), 'Basic test, should have security' );
+
+ // JSONp
+ $main = new ApiMain(
+ new FauxRequest( [ 'action' => 'query', 'format' => 'xml', 'callback' => 'foo' ] )
+ );
+ $this->assertTrue( $main->lacksSameOriginSecurity(), 'JSONp, should lack security' );
+
+ // Header
+ $request = new FauxRequest( [ 'action' => 'query', 'meta' => 'siteinfo' ] );
+ $request->setHeader( 'TrEaT-As-UnTrUsTeD', '' ); // With falsey value!
+ $main = new ApiMain( $request );
+ $this->assertTrue( $main->lacksSameOriginSecurity(), 'Header supplied, should lack security' );
+
+ // Hook
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [
+ 'RequestHasSameOriginSecurity' => [ function () {
+ return false;
+ } ]
+ ] );
+ $main = new ApiMain( new FauxRequest( [ 'action' => 'query', 'meta' => 'siteinfo' ] ) );
+ $this->assertTrue( $main->lacksSameOriginSecurity(), 'Hook, should lack security' );
+ }
}
--- /dev/null
+<?php
+
+use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @group API
+ * @group Database
+ * @group medium
+ *
+ * @covers ApiQueryWatchlist
+ */
+class ApiQueryWatchlistIntegrationTest extends ApiTestCase {
+
+ public function __construct( $name = null, array $data = [], $dataName = '' ) {
+ parent::__construct( $name, $data, $dataName );
+ $this->tablesUsed = array_unique(
+ array_merge( $this->tablesUsed, [ 'watchlist', 'recentchanges', 'page' ] )
+ );
+ }
+
+ protected function setUp() {
+ parent::setUp();
+ self::$users['ApiQueryWatchlistIntegrationTestUser'] = $this->getMutableTestUser();
+ self::$users['ApiQueryWatchlistIntegrationTestUser2'] = $this->getMutableTestUser();
+ $this->doLogin( 'ApiQueryWatchlistIntegrationTestUser' );
+ }
+
+ private function getLoggedInTestUser() {
+ return self::$users['ApiQueryWatchlistIntegrationTestUser']->getUser();
+ }
+
+ private function getNonLoggedInTestUser() {
+ return self::$users['ApiQueryWatchlistIntegrationTestUser2']->getUser();
+ }
+
+ private function doPageEdit( User $user, LinkTarget $target, $content, $summary ) {
+ $title = Title::newFromLinkTarget( $target );
+ $page = WikiPage::factory( $title );
+ $page->doEditContent(
+ ContentHandler::makeContent( $content, $title ),
+ $summary,
+ 0,
+ false,
+ $user
+ );
+ }
+
+ private function doMinorPageEdit( User $user, LinkTarget $target, $content, $summary ) {
+ $title = Title::newFromLinkTarget( $target );
+ $page = WikiPage::factory( $title );
+ $page->doEditContent(
+ ContentHandler::makeContent( $content, $title ),
+ $summary,
+ EDIT_MINOR,
+ false,
+ $user
+ );
+ }
+
+ private function doBotPageEdit( User $user, LinkTarget $target, $content, $summary ) {
+ $title = Title::newFromLinkTarget( $target );
+ $page = WikiPage::factory( $title );
+ $page->doEditContent(
+ ContentHandler::makeContent( $content, $title ),
+ $summary,
+ EDIT_FORCE_BOT,
+ false,
+ $user
+ );
+ }
+
+ private function doAnonPageEdit( LinkTarget $target, $content, $summary ) {
+ $title = Title::newFromLinkTarget( $target );
+ $page = WikiPage::factory( $title );
+ $page->doEditContent(
+ ContentHandler::makeContent( $content, $title ),
+ $summary,
+ 0,
+ false,
+ User::newFromId( 0 )
+ );
+ }
+
+ private function doPatrolledPageEdit(
+ User $user,
+ LinkTarget $target,
+ $content,
+ $summary,
+ User $patrollingUser
+ ) {
+ $title = Title::newFromLinkTarget( $target );
+ $page = WikiPage::factory( $title );
+ $status = $page->doEditContent(
+ ContentHandler::makeContent( $content, $title ),
+ $summary,
+ 0,
+ false,
+ $user
+ );
+ /** @var Revision $rev */
+ $rev = $status->value['revision'];
+ $rc = $rev->getRecentChange();
+ $rc->doMarkPatrolled( $patrollingUser, false, [] );
+ }
+
+ private function deletePage( LinkTarget $target, $reason ) {
+ $title = Title::newFromLinkTarget( $target );
+ $page = WikiPage::factory( $title );
+ $page->doDeleteArticleReal( $reason );
+ }
+
+ /**
+ * Performs a batch of page edits as a specified user
+ * @param User $user
+ * @param array $editData associative array, keys:
+ * - target => LinkTarget page to edit
+ * - content => string new content
+ * - summary => string edit summary
+ * - minorEdit => bool mark as minor edit if true (defaults to false)
+ * - botEdit => bool mark as bot edit if true (defaults to false)
+ */
+ private function doPageEdits( User $user, array $editData ) {
+ foreach ( $editData as $singleEditData ) {
+ if ( array_key_exists( 'minorEdit', $singleEditData ) && $singleEditData['minorEdit'] ) {
+ $this->doMinorPageEdit(
+ $user,
+ $singleEditData['target'],
+ $singleEditData['content'],
+ $singleEditData['summary']
+ );
+ continue;
+ }
+ if ( array_key_exists( 'botEdit', $singleEditData ) && $singleEditData['botEdit'] ) {
+ $this->doBotPageEdit(
+ $user,
+ $singleEditData['target'],
+ $singleEditData['content'],
+ $singleEditData['summary']
+ );
+ continue;
+ }
+ $this->doPageEdit(
+ $user,
+ $singleEditData['target'],
+ $singleEditData['content'],
+ $singleEditData['summary']
+ );
+ }
+ }
+
+ private function getWatchedItemStore() {
+ return MediaWikiServices::getInstance()->getWatchedItemStore();
+ }
+
+ /**
+ * @param User $user
+ * @param LinkTarget[] $targets
+ */
+ private function watchPages( User $user, array $targets ) {
+ $store = $this->getWatchedItemStore();
+ $store->addWatchBatchForUser( $user, $targets );
+ }
+
+ private function doListWatchlistRequest( array $params = [], $user = null ) {
+ return $this->doApiRequest(
+ array_merge(
+ [ 'action' => 'query', 'list' => 'watchlist' ],
+ $params
+ ), null, false, $user
+ );
+ }
+
+ private function doGeneratorWatchlistRequest( array $params = [] ) {
+ return $this->doApiRequest(
+ array_merge(
+ [ 'action' => 'query', 'generator' => 'watchlist' ],
+ $params
+ )
+ );
+ }
+
+ private function getItemsFromApiResponse( array $response ) {
+ return $response[0]['query']['watchlist'];
+ }
+
+ /**
+ * Convenience method to assert that actual items array fetched from API is equal to the expected
+ * array, Unlike assertEquals this only checks if values of specified keys are equal in both
+ * arrays. This could be used e.g. not to compare IDs that could change between test run
+ * but only stable keys.
+ * Optionally this also checks that specified keys are present in the actual item without
+ * performing any checks on the related values.
+ *
+ * @param array $actualItems array of actual items (associative arrays)
+ * @param array $expectedItems array of expected items (associative arrays),
+ * those items have less keys than actual items
+ * @param array $keysUsedInValueComparison list of keys of the actual item that will be used
+ * in the comparison of values
+ * @param array $requiredKeys optional, list of keys that must be present in the
+ * actual items. Values of those keys are not checked.
+ */
+ private function assertArraySubsetsEqual(
+ array $actualItems,
+ array $expectedItems,
+ array $keysUsedInValueComparison,
+ array $requiredKeys = []
+ ) {
+ $this->assertCount( count( $expectedItems ), $actualItems );
+
+ // not checking values of all keys of the actual item, so removing unwanted keys from comparison
+ $actualItemsOnlyComparedValues = array_map(
+ function( array $item ) use ( $keysUsedInValueComparison ) {
+ return array_intersect_key( $item, array_flip( $keysUsedInValueComparison ) );
+ },
+ $actualItems
+ );
+
+ $this->assertEquals(
+ $expectedItems,
+ $actualItemsOnlyComparedValues
+ );
+
+ // Check that each item in $actualItems contains all of keys specified in $requiredKeys
+ $actualItemsKeysOnly = array_map( 'array_keys', $actualItems );
+ foreach ( $actualItemsKeysOnly as $keysOfTheItem ) {
+ $this->assertEmpty( array_diff( $requiredKeys, $keysOfTheItem ) );
+ }
+ }
+
+ private function getTitleFormatter() {
+ return new MediaWikiTitleCodec( Language::factory( 'en' ), GenderCache::singleton() );
+ }
+
+ private function getPrefixedText( LinkTarget $target ) {
+ $formatter = $this->getTitleFormatter();
+ return $formatter->getPrefixedText( $target );
+ }
+
+ private function cleanTestUsersWatchlist() {
+ $user = $this->getLoggedInTestUser();
+ $store = $this->getWatchedItemStore();
+ $items = $store->getWatchedItemsForUser( $user );
+ foreach ( $items as $item ) {
+ $store->removeWatch( $user, $item->getLinkTarget() );
+ }
+ }
+
+ public function testListWatchlist_returnsWatchedItemsWithRCInfo() {
+ // Clean up after previous tests that might have added something to the watchlist of
+ // the user with the same user ID as user used here as the test user
+ $this->cleanTestUsersWatchlist();
+
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $result = $this->doListWatchlistRequest();
+
+ $this->assertArrayHasKey( 'query', $result[0] );
+ $this->assertArrayHasKey( 'watchlist', $result[0]['query'] );
+
+ $this->assertArraySubsetsEqual(
+ $this->getItemsFromApiResponse( $result ),
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $target->getNamespace(),
+ 'title' => $this->getPrefixedText( $target ),
+ 'bot' => false,
+ 'new' => true,
+ 'minor' => false,
+ ]
+ ],
+ [ 'type', 'ns', 'title', 'bot', 'new', 'minor' ],
+ [ 'pageid', 'revid', 'old_revid' ]
+ );
+ }
+
+ public function testIdsPropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'ids', ] );
+ $items = $this->getItemsFromApiResponse( $result );
+
+ $this->assertCount( 1, $items );
+ $this->assertArrayHasKey( 'pageid', $items[0] );
+ $this->assertArrayHasKey( 'revid', $items[0] );
+ $this->assertArrayHasKey( 'old_revid', $items[0] );
+ $this->assertEquals( 'new', $items[0]['type'] );
+ }
+
+ public function testTitlePropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $subjectTarget,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $talkTarget,
+ 'content' => 'Some Talk Page Content',
+ 'summary' => 'Create Talk page',
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $talkTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $talkTarget ),
+ ],
+ [
+ 'type' => 'new',
+ 'ns' => $subjectTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $subjectTarget ),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testFlagsPropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $normalEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $minorEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageM' );
+ $botEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageB' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $normalEditTarget,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $minorEditTarget,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $minorEditTarget,
+ 'content' => 'Slightly Better Content',
+ 'summary' => 'Change content',
+ 'minorEdit' => true,
+ ],
+ [
+ 'target' => $botEditTarget,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page with a bot',
+ 'botEdit' => true,
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $normalEditTarget, $minorEditTarget, $botEditTarget ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'flags', ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'new' => true,
+ 'minor' => false,
+ 'bot' => true,
+ ],
+ [
+ 'type' => 'edit',
+ 'new' => false,
+ 'minor' => true,
+ 'bot' => false,
+ ],
+ [
+ 'type' => 'new',
+ 'new' => true,
+ 'minor' => false,
+ 'bot' => false,
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testUserPropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $userEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $anonEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageA' );
+ $this->doPageEdit(
+ $user,
+ $userEditTarget,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->doAnonPageEdit(
+ $anonEditTarget,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $userEditTarget, $anonEditTarget ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'user', ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'anon' => true,
+ 'user' => User::newFromId( 0 )->getName(),
+ ],
+ [
+ 'type' => 'new',
+ 'user' => $user->getName(),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testUserIdPropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $userEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $anonEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageA' );
+ $this->doPageEdit(
+ $user,
+ $userEditTarget,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->doAnonPageEdit(
+ $anonEditTarget,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $userEditTarget, $anonEditTarget ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'userid', ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'anon' => true,
+ 'user' => 0,
+ 'userid' => 0,
+ ],
+ [
+ 'type' => 'new',
+ 'user' => $user->getId(),
+ 'userid' => $user->getId(),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testCommentPropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the <b>page</b>'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'comment', ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'comment' => 'Create the <b>page</b>',
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testParsedCommentPropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the <b>page</b>'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'parsedcomment', ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'parsedcomment' => 'Create the <b>page</b>',
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testTimestampPropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'timestamp', ] );
+ $items = $this->getItemsFromApiResponse( $result );
+
+ $this->assertCount( 1, $items );
+ $this->assertArrayHasKey( 'timestamp', $items[0] );
+ $this->assertInternalType( 'string', $items[0]['timestamp'] );
+ }
+
+ public function testSizesPropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'sizes', ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'oldlen' => 0,
+ 'newlen' => 12,
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testNotificationTimestampPropParameter() {
+ $otherUser = $this->getNonLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $otherUser,
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $store = $this->getWatchedItemStore();
+ $store->addWatch( $this->getLoggedInTestUser(), $target );
+ $store->updateNotificationTimestamp(
+ $otherUser,
+ $target,
+ '20151212010101'
+ );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'notificationtimestamp', ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'notificationtimestamp' => '2015-12-12T01:01:01Z',
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ private function setupPatrolledSpecificFixtures( User $user ) {
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+
+ $this->doPatrolledPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the page (this gets patrolled)',
+ $user
+ );
+
+ $this->watchPages( $user, [ $target ] );
+ }
+
+ public function testPatrolPropParameter() {
+ $testUser = static::getTestSysop();
+ $user = $testUser->getUser();
+ $this->setupPatrolledSpecificFixtures( $user );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'patrol', ], $user );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'patrolled' => true,
+ 'unpatrolled' => false,
+ ]
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ private function createPageAndDeleteIt( LinkTarget $target ) {
+ $this->doPageEdit(
+ $this->getLoggedInTestUser(),
+ $target,
+ 'Some Content',
+ 'Create the page that will be deleted'
+ );
+ $this->deletePage( $target, 'Important Reason' );
+ }
+
+ public function testLoginfoPropParameter() {
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->createPageAndDeleteIt( $target );
+
+ $this->watchPages( $this->getLoggedInTestUser(), [ $target ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'loginfo', ] );
+
+ $this->assertArraySubsetsEqual(
+ $this->getItemsFromApiResponse( $result ),
+ [
+ [
+ 'type' => 'log',
+ 'logtype' => 'delete',
+ 'logaction' => 'delete',
+ 'logparams' => [],
+ ],
+ ],
+ [ 'type', 'logtype', 'logaction', 'logparams' ],
+ [ 'logid' ]
+ );
+ }
+
+ public function testEmptyPropParameter() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => '', ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ ]
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testNamespaceParam() {
+ $user = $this->getLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $subjectTarget,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $talkTarget,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the talk page',
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlnamespace' => '0', ] );
+
+ $this->assertArraySubsetsEqual(
+ $this->getItemsFromApiResponse( $result ),
+ [
+ [
+ 'ns' => 0,
+ 'title' => $this->getPrefixedText( $subjectTarget ),
+ ],
+ ],
+ [ 'ns', 'title' ]
+ );
+ }
+
+ public function testUserParam() {
+ $user = $this->getLoggedInTestUser();
+ $otherUser = $this->getNonLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $subjectTarget,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->doPageEdit(
+ $otherUser,
+ $talkTarget,
+ 'What is this page about?',
+ 'Create the talk page'
+ );
+ $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
+
+ $result = $this->doListWatchlistRequest( [
+ 'wlprop' => 'user|title',
+ 'wluser' => $otherUser->getName(),
+ ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $talkTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $talkTarget ),
+ 'user' => $otherUser->getName(),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testExcludeUserParam() {
+ $user = $this->getLoggedInTestUser();
+ $otherUser = $this->getNonLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $subjectTarget,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->doPageEdit(
+ $otherUser,
+ $talkTarget,
+ 'What is this page about?',
+ 'Create the talk page'
+ );
+ $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
+
+ $result = $this->doListWatchlistRequest( [
+ 'wlprop' => 'user|title',
+ 'wlexcludeuser' => $otherUser->getName(),
+ ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $subjectTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $subjectTarget ),
+ 'user' => $user->getName(),
+ ]
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testShowMinorParams() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $target,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $target,
+ 'content' => 'Slightly Better Content',
+ 'summary' => 'Change content',
+ 'minorEdit' => true,
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $resultMinor = $this->doListWatchlistRequest( [ 'wlshow' => 'minor', 'wlprop' => 'flags' ] );
+ $resultNotMinor = $this->doListWatchlistRequest( [ 'wlshow' => '!minor', 'wlprop' => 'flags' ] );
+
+ $this->assertArraySubsetsEqual(
+ $this->getItemsFromApiResponse( $resultMinor ),
+ [
+ [ 'minor' => true, ]
+ ],
+ [ 'minor' ]
+ );
+ $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotMinor ) );
+ }
+
+ public function testShowBotParams() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doBotPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $resultBot = $this->doListWatchlistRequest( [ 'wlshow' => 'bot' ] );
+ $resultNotBot = $this->doListWatchlistRequest( [ 'wlshow' => '!bot' ] );
+
+ $this->assertArraySubsetsEqual(
+ $this->getItemsFromApiResponse( $resultBot ),
+ [
+ [ 'bot' => true ],
+ ],
+ [ 'bot' ]
+ );
+ $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotBot ) );
+ }
+
+ public function testShowAnonParams() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doAnonPageEdit(
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $resultAnon = $this->doListWatchlistRequest( [
+ 'wlprop' => 'user',
+ 'wlshow' => 'anon'
+ ] );
+ $resultNotAnon = $this->doListWatchlistRequest( [
+ 'wlprop' => 'user',
+ 'wlshow' => '!anon'
+ ] );
+
+ $this->assertArraySubsetsEqual(
+ $this->getItemsFromApiResponse( $resultAnon ),
+ [
+ [ 'anon' => true ],
+ ],
+ [ 'anon' ]
+ );
+ $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotAnon ) );
+ }
+
+ public function testShowUnreadParams() {
+ $user = $this->getLoggedInTestUser();
+ $otherUser = $this->getNonLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $subjectTarget,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->doPageEdit(
+ $otherUser,
+ $talkTarget,
+ 'Some Content',
+ 'Create the talk page'
+ );
+ $store = $this->getWatchedItemStore();
+ $store->addWatchBatchForUser( $user, [ $subjectTarget, $talkTarget ] );
+ $store->updateNotificationTimestamp(
+ $otherUser,
+ $talkTarget,
+ '20151212010101'
+ );
+
+ $resultUnread = $this->doListWatchlistRequest( [
+ 'wlprop' => 'notificationtimestamp|title',
+ 'wlshow' => 'unread'
+ ] );
+ $resultNotUnread = $this->doListWatchlistRequest( [
+ 'wlprop' => 'notificationtimestamp|title',
+ 'wlshow' => '!unread'
+ ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'notificationtimestamp' => '2015-12-12T01:01:01Z',
+ 'ns' => $talkTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $talkTarget )
+ ]
+ ],
+ $this->getItemsFromApiResponse( $resultUnread )
+ );
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'notificationtimestamp' => '',
+ 'ns' => $subjectTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $subjectTarget )
+ ]
+ ],
+ $this->getItemsFromApiResponse( $resultNotUnread )
+ );
+ }
+
+ public function testShowPatrolledParams() {
+ $user = static::getTestSysop()->getUser();
+ $this->setupPatrolledSpecificFixtures( $user );
+
+ $resultPatrolled = $this->doListWatchlistRequest( [
+ 'wlprop' => 'patrol',
+ 'wlshow' => 'patrolled'
+ ], $user );
+ $resultNotPatrolled = $this->doListWatchlistRequest( [
+ 'wlprop' => 'patrol',
+ 'wlshow' => '!patrolled'
+ ], $user );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'patrolled' => true,
+ 'unpatrolled' => false,
+ ]
+ ],
+ $this->getItemsFromApiResponse( $resultPatrolled )
+ );
+ $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotPatrolled ) );
+ }
+
+ public function testNewAndEditTypeParameters() {
+ $user = $this->getLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $subjectTarget,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $subjectTarget,
+ 'content' => 'Some Other Content',
+ 'summary' => 'Change the content',
+ ],
+ [
+ 'target' => $talkTarget,
+ 'content' => 'Some Talk Page Content',
+ 'summary' => 'Create Talk page',
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
+
+ $resultNew = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'new' ] );
+ $resultEdit = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'edit' ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $talkTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $talkTarget ),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $resultNew )
+ );
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'edit',
+ 'ns' => $subjectTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $subjectTarget ),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $resultEdit )
+ );
+ }
+
+ public function testLogTypeParameters() {
+ $user = $this->getLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->createPageAndDeleteIt( $subjectTarget );
+ $this->doPageEdit(
+ $user,
+ $talkTarget,
+ 'Some Talk Page Content',
+ 'Create Talk page'
+ );
+ $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'log' ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'log',
+ 'ns' => $subjectTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $subjectTarget ),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ private function getExternalRC( LinkTarget $target ) {
+ $title = Title::newFromLinkTarget( $target );
+
+ $rc = new RecentChange;
+ $rc->mTitle = $title;
+ $rc->mAttribs = [
+ 'rc_timestamp' => wfTimestamp( TS_MW ),
+ 'rc_namespace' => $title->getNamespace(),
+ 'rc_title' => $title->getDBkey(),
+ 'rc_type' => RC_EXTERNAL,
+ 'rc_source' => 'foo',
+ 'rc_minor' => 0,
+ 'rc_cur_id' => $title->getArticleID(),
+ 'rc_user' => 0,
+ 'rc_user_text' => 'External User',
+ 'rc_comment' => '',
+ 'rc_this_oldid' => $title->getLatestRevID(),
+ 'rc_last_oldid' => $title->getLatestRevID(),
+ 'rc_bot' => 0,
+ 'rc_ip' => '',
+ 'rc_patrolled' => 0,
+ 'rc_new' => 0,
+ 'rc_old_len' => $title->getLength(),
+ 'rc_new_len' => $title->getLength(),
+ 'rc_deleted' => 0,
+ 'rc_logid' => 0,
+ 'rc_log_type' => null,
+ 'rc_log_action' => '',
+ 'rc_params' => '',
+ ];
+ $rc->mExtra = [
+ 'prefixedDBkey' => $title->getPrefixedDBkey(),
+ 'lastTimestamp' => 0,
+ 'oldSize' => $title->getLength(),
+ 'newSize' => $title->getLength(),
+ 'pageStatus' => 'changed'
+ ];
+
+ return $rc;
+ }
+
+ public function testExternalTypeParameters() {
+ $user = $this->getLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $subjectTarget,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->doPageEdit(
+ $user,
+ $talkTarget,
+ 'Some Talk Page Content',
+ 'Create Talk page'
+ );
+
+ $rc = $this->getExternalRC( $subjectTarget );
+ $rc->save();
+
+ $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'external' ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'external',
+ 'ns' => $subjectTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $subjectTarget ),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testCategorizeTypeParameter() {
+ $user = $this->getLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $categoryTarget = new TitleValue( NS_CATEGORY, 'ApiQueryWatchlistIntegrationTestCategory' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $categoryTarget,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the category',
+ ],
+ [
+ 'target' => $subjectTarget,
+ 'content' => 'Some Content [[Category:ApiQueryWatchlistIntegrationTestCategory]]t',
+ 'summary' => 'Create the page and add it to the category',
+ ],
+ ]
+ );
+ $title = Title::newFromLinkTarget( $subjectTarget );
+ $revision = Revision::newFromTitle( $title );
+
+ $rc = RecentChange::newForCategorization(
+ $revision->getTimestamp(),
+ Title::newFromLinkTarget( $categoryTarget ),
+ $user,
+ $revision->getComment(),
+ $title,
+ 0,
+ $revision->getId(),
+ null,
+ false
+ );
+ $rc->save();
+
+ $this->watchPages( $user, [ $subjectTarget, $categoryTarget ] );
+
+ $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'categorize' ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'categorize',
+ 'ns' => $categoryTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $categoryTarget ),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testLimitParam() {
+ $user = $this->getLoggedInTestUser();
+ $target1 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $target2 = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $target3 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage2' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $target1,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $target2,
+ 'content' => 'Some Talk Page Content',
+ 'summary' => 'Create Talk page',
+ ],
+ [
+ 'target' => $target3,
+ 'content' => 'Some Other Content',
+ 'summary' => 'Create the page',
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $target1, $target2, $target3 ] );
+
+ $resultWithoutLimit = $this->doListWatchlistRequest( [ 'wlprop' => 'title' ] );
+ $resultWithLimit = $this->doListWatchlistRequest( [ 'wllimit' => 2, 'wlprop' => 'title' ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $target3->getNamespace(),
+ 'title' => $this->getPrefixedText( $target3 )
+ ],
+ [
+ 'type' => 'new',
+ 'ns' => $target2->getNamespace(),
+ 'title' => $this->getPrefixedText( $target2 )
+ ],
+ [
+ 'type' => 'new',
+ 'ns' => $target1->getNamespace(),
+ 'title' => $this->getPrefixedText( $target1 )
+ ],
+ ],
+ $this->getItemsFromApiResponse( $resultWithoutLimit )
+ );
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $target3->getNamespace(),
+ 'title' => $this->getPrefixedText( $target3 )
+ ],
+ [
+ 'type' => 'new',
+ 'ns' => $target2->getNamespace(),
+ 'title' => $this->getPrefixedText( $target2 )
+ ],
+ ],
+ $this->getItemsFromApiResponse( $resultWithLimit )
+ );
+ $this->assertArrayHasKey( 'continue', $resultWithLimit[0] );
+ $this->assertArrayHasKey( 'wlcontinue', $resultWithLimit[0]['continue'] );
+ }
+
+ public function testAllRevParam() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $target,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $target,
+ 'content' => 'Some Other Content',
+ 'summary' => 'Change the content',
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $resultAllRev = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wlallrev' => '', ] );
+ $resultNoAllRev = $this->doListWatchlistRequest( [ 'wlprop' => 'title' ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'edit',
+ 'ns' => $target->getNamespace(),
+ 'title' => $this->getPrefixedText( $target ),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $resultNoAllRev )
+ );
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'edit',
+ 'ns' => $target->getNamespace(),
+ 'title' => $this->getPrefixedText( $target ),
+ ],
+ [
+ 'type' => 'new',
+ 'ns' => $target->getNamespace(),
+ 'title' => $this->getPrefixedText( $target ),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $resultAllRev )
+ );
+ }
+
+ public function testDirParams() {
+ $user = $this->getLoggedInTestUser();
+ $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $subjectTarget,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $talkTarget,
+ 'content' => 'Some Talk Page Content',
+ 'summary' => 'Create Talk page',
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
+
+ $resultDirOlder = $this->doListWatchlistRequest( [ 'wldir' => 'older', 'wlprop' => 'title' ] );
+ $resultDirNewer = $this->doListWatchlistRequest( [ 'wldir' => 'newer', 'wlprop' => 'title' ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $talkTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $talkTarget )
+ ],
+ [
+ 'type' => 'new',
+ 'ns' => $subjectTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $subjectTarget )
+ ],
+ ],
+ $this->getItemsFromApiResponse( $resultDirOlder )
+ );
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $subjectTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $subjectTarget )
+ ],
+ [
+ 'type' => 'new',
+ 'ns' => $talkTarget->getNamespace(),
+ 'title' => $this->getPrefixedText( $talkTarget )
+ ],
+ ],
+ $this->getItemsFromApiResponse( $resultDirNewer )
+ );
+ }
+
+ public function testStartEndParams() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $resultStart = $this->doListWatchlistRequest( [
+ 'wlstart' => '20010115000000',
+ 'wldir' => 'newer',
+ 'wlprop' => 'title',
+ ] );
+ $resultEnd = $this->doListWatchlistRequest( [
+ 'wlend' => '20010115000000',
+ 'wldir' => 'newer',
+ 'wlprop' => 'title',
+ ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $target->getNamespace(),
+ 'title' => $this->getPrefixedText( $target ),
+ ]
+ ],
+ $this->getItemsFromApiResponse( $resultStart )
+ );
+ $this->assertEmpty( $this->getItemsFromApiResponse( $resultEnd ) );
+ }
+
+ public function testContinueParam() {
+ $user = $this->getLoggedInTestUser();
+ $target1 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $target2 = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
+ $target3 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage2' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $target1,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $target2,
+ 'content' => 'Some Talk Page Content',
+ 'summary' => 'Create Talk page',
+ ],
+ [
+ 'target' => $target3,
+ 'content' => 'Some Other Content',
+ 'summary' => 'Create the page',
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $target1, $target2, $target3 ] );
+
+ $firstResult = $this->doListWatchlistRequest( [ 'wllimit' => 2, 'wlprop' => 'title' ] );
+ $this->assertArrayHasKey( 'continue', $firstResult[0] );
+ $this->assertArrayHasKey( 'wlcontinue', $firstResult[0]['continue'] );
+
+ $continuationParam = $firstResult[0]['continue']['wlcontinue'];
+
+ $continuedResult = $this->doListWatchlistRequest(
+ [ 'wlcontinue' => $continuationParam, 'wlprop' => 'title' ]
+ );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $target3->getNamespace(),
+ 'title' => $this->getPrefixedText( $target3 ),
+ ],
+ [
+ 'type' => 'new',
+ 'ns' => $target2->getNamespace(),
+ 'title' => $this->getPrefixedText( $target2 ),
+ ],
+ ],
+ $this->getItemsFromApiResponse( $firstResult )
+ );
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $target1->getNamespace(),
+ 'title' => $this->getPrefixedText( $target1 )
+ ]
+ ],
+ $this->getItemsFromApiResponse( $continuedResult )
+ );
+ }
+
+ public function testOwnerAndTokenParams() {
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $this->getLoggedInTestUser(),
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+
+ $otherUser = $this->getNonLoggedInTestUser();
+ $otherUser->setOption( 'watchlisttoken', '1234567890' );
+ $otherUser->saveSettings();
+
+ $this->watchPages( $otherUser, [ $target ] );
+
+ $result = $this->doListWatchlistRequest( [
+ 'wlowner' => $otherUser->getName(),
+ 'wltoken' => '1234567890',
+ 'wlprop' => 'title',
+ ] );
+
+ $this->assertEquals(
+ [
+ [
+ 'type' => 'new',
+ 'ns' => $target->getNamespace(),
+ 'title' => $this->getPrefixedText( $target )
+ ]
+ ],
+ $this->getItemsFromApiResponse( $result )
+ );
+ }
+
+ public function testOwnerAndTokenParams_wrongToken() {
+ $otherUser = $this->getNonLoggedInTestUser();
+ $otherUser->setOption( 'watchlisttoken', '1234567890' );
+ $otherUser->saveSettings();
+
+ $this->setExpectedException( UsageException::class, 'Incorrect watchlist token provided' );
+
+ $this->doListWatchlistRequest( [
+ 'wlowner' => $otherUser->getName(),
+ 'wltoken' => 'wrong-token',
+ ] );
+ }
+
+ public function testOwnerAndTokenParams_noWatchlistTokenSet() {
+ $this->setExpectedException( UsageException::class, 'Incorrect watchlist token provided' );
+
+ $this->doListWatchlistRequest( [
+ 'wlowner' => $this->getNonLoggedInTestUser()->getName(),
+ 'wltoken' => 'some-token',
+ ] );
+ }
+
+ public function testGeneratorWatchlistPropInfo_returnsWatchedPages() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdit(
+ $user,
+ $target,
+ 'Some Content',
+ 'Create the page'
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $result = $this->doGeneratorWatchlistRequest( [ 'prop' => 'info' ] );
+
+ $this->assertArrayHasKey( 'query', $result[0] );
+ $this->assertArrayHasKey( 'pages', $result[0]['query'] );
+
+ // $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
+ $pages = array_values( $result[0]['query']['pages'] );
+
+ $this->assertArraySubsetsEqual(
+ $pages,
+ [
+ [
+ 'ns' => $target->getNamespace(),
+ 'title' => $this->getPrefixedText( $target ),
+ 'new' => true,
+ ]
+ ],
+ [ 'ns', 'title', 'new' ]
+ );
+ }
+
+ public function testGeneratorWatchlistPropRevisions_returnsWatchedItemsRevisions() {
+ $user = $this->getLoggedInTestUser();
+ $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
+ $this->doPageEdits(
+ $user,
+ [
+ [
+ 'target' => $target,
+ 'content' => 'Some Content',
+ 'summary' => 'Create the page',
+ ],
+ [
+ 'target' => $target,
+ 'content' => 'Some Other Content',
+ 'summary' => 'Change the content',
+ ],
+ ]
+ );
+ $this->watchPages( $user, [ $target ] );
+
+ $result = $this->doGeneratorWatchlistRequest( [ 'prop' => 'revisions', 'gwlallrev' => '' ] );
+
+ $this->assertArrayHasKey( 'query', $result[0] );
+ $this->assertArrayHasKey( 'pages', $result[0]['query'] );
+
+ // $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
+ $pages = array_values( $result[0]['query']['pages'] );
+
+ $this->assertCount( 1, $pages );
+ $this->assertEquals( 0, $pages[0]['ns'] );
+ $this->assertEquals( $this->getPrefixedText( $target ), $pages[0]['title'] );
+ $this->assertArraySubsetsEqual(
+ $pages[0]['revisions'],
+ [
+ [
+ 'comment' => 'Create the page',
+ 'user' => $user->getName(),
+ 'minor' => false,
+ ],
+ [
+ 'comment' => 'Change the content',
+ 'user' => $user->getName(),
+ 'minor' => false,
+ ],
+ ],
+ [ 'comment', 'user', 'minor' ]
+ );
+ }
+
+}
--- /dev/null
+<?php
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @author Addshore
+ * @covers ApiSetNotificationTimestamp
+ * @group API
+ * @group medium
+ * @group Database
+ */
+class ApiSetNotificationTimestampIntegrationTest extends ApiTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+ self::$users[__CLASS__] = new TestUser( __CLASS__ );
+ $this->doLogin( __CLASS__ );
+ }
+
+ public function testStuff() {
+ $user = self::$users[__CLASS__]->getUser();
+ $page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
+
+ $user->addWatch( $page->getTitle() );
+
+ $result = $this->doApiRequestWithToken(
+ [
+ 'action' => 'setnotificationtimestamp',
+ 'timestamp' => '20160101020202',
+ 'pageids' => $page->getId(),
+ ],
+ null,
+ $user
+ );
+
+ $this->assertEquals(
+ [
+ 'batchcomplete' => true,
+ 'setnotificationtimestamp' => [
+ [ 'ns' => 0, 'title' => 'UTPage', 'notificationtimestamp' => '2016-01-01T02:02:02Z' ]
+ ],
+ ],
+ $result[0]
+ );
+
+ $watchedItemStore = MediaWikiServices::getInstance()->getWatchedItemStore();
+ $this->assertEquals(
+ $watchedItemStore->getNotificationTimestampsBatch( $user, [ $page->getTitle() ] ),
+ [ [ 'UTPage' => '20160101020202' ] ]
+ );
+ }
+
+}
*/
protected $apiContext;
- /**
- * @var array
- */
- protected $tablesUsed = [ 'user', 'user_groups', 'user_properties' ];
-
protected function setUp() {
- global $wgServer;
+ global $wgServer, $wgDisableAuthManager;
parent::setUp();
self::$apiUrl = $wgServer . wfScript( 'api' );
ApiQueryInfo::resetTokenCache(); // tokens are invalid because we cleared the session
self::$users = [
- 'sysop' => new TestUser(
- 'Apitestsysop',
- 'Api Test Sysop',
- 'api_test_sysop@example.com',
- [ 'sysop' ]
- ),
- 'uploader' => new TestUser(
- 'Apitestuser',
- 'Api Test User',
- 'api_test_user@example.com',
- []
- )
+ 'sysop' => static::getTestSysop(),
+ 'uploader' => static::getTestUser(),
];
$this->setMwGlobals( [
- 'wgAuth' => new AuthPlugin,
+ 'wgAuth' => $wgDisableAuthManager ? new AuthPlugin : new MediaWiki\Auth\AuthManagerAuthPlugin,
'wgRequest' => new FauxRequest( [] ),
'wgUser' => self::$users['sysop']->user,
] );
$wgRequest = new FauxRequest( $params, true, $session );
RequestContext::getMain()->setRequest( $wgRequest );
RequestContext::getMain()->setUser( $wgUser );
+ MediaWiki\Auth\AuthManager::resetCache();
// set up local environment
$context = $this->apiContext->newTestContext( $wgRequest, $wgUser );
}
}
- protected function doLogin( $user = 'sysop' ) {
- if ( !array_key_exists( $user, self::$users ) ) {
- throw new MWException( "Can not log in to undefined user $user" );
+ protected function doLogin( $testUser = 'sysop' ) {
+ if ( $testUser === null ) {
+ $testUser = static::getTestSysop();
+ } elseif ( is_string( $testUser ) && array_key_exists( $testUser, self::$users ) ) {
+ $testUser = self::$users[ $testUser ];
+ } elseif ( !$testUser instanceof TestUser ) {
+ throw new MWException( "Can not log in to undefined user $testUser" );
}
$data = $this->doApiRequest( [
'action' => 'login',
- 'lgname' => self::$users[$user]->username,
- 'lgpassword' => self::$users[$user]->password ] );
+ 'lgname' => $testUser->username,
+ 'lgpassword' => $testUser->password ] );
$token = $data[0]['login']['token'];
[
'action' => 'login',
'lgtoken' => $token,
- 'lgname' => self::$users[$user]->username,
- 'lgpassword' => self::$users[$user]->password,
+ 'lgname' => $testUser->username,
+ 'lgpassword' => $testUser->password,
],
$data[2]
);
+ if ( $data[0]['login']['result'] === 'Success' ) {
+ // DWIM
+ global $wgUser;
+ $wgUser = $testUser->getUser();
+ RequestContext::getMain()->setUser( $wgUser );
+ }
+
return $data;
}
[ [ 1 ], '/**/myCallback([1])', [ 'callback' => 'myCallback' ] ],
// Cross-domain mangling
- [ [ '< Cross-Domain-Policy >' ], '["\u003C Cross-Domain-Policy \u003E"]' ],
+ [ [ '< Cross-Domain-Policy >' ], '["\u003C Cross-Domain-Policy >"]' ],
] ),
self::addFormatVersion( 2, [
// Basic types
[ [ 1 ], '/**/myCallback([1])', [ 'callback' => 'myCallback' ] ],
// Cross-domain mangling
- [ [ '< Cross-Domain-Policy >' ], '["\u003C Cross-Domain-Policy \u003E"]' ],
+ [ [ '< Cross-Domain-Policy >' ], '["\u003C Cross-Domain-Policy >"]' ],
] )
);
}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\AbstractAuthenticationProvider
+ */
+class AbstractAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testAbstractAuthenticationProvider() {
+ $provider = $this->getMockForAbstractClass( AbstractAuthenticationProvider::class );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $obj = $this->getMockForAbstractClass( 'Psr\Log\LoggerInterface' );
+ $provider->setLogger( $obj );
+ $this->assertSame( $obj, $providerPriv->logger, 'setLogger' );
+
+ $obj = AuthManager::singleton();
+ $provider->setManager( $obj );
+ $this->assertSame( $obj, $providerPriv->manager, 'setManager' );
+
+ $obj = $this->getMockForAbstractClass( 'Config' );
+ $provider->setConfig( $obj );
+ $this->assertSame( $obj, $providerPriv->config, 'setConfig' );
+
+ $this->assertType( 'string', $provider->getUniqueId(), 'getUniqueId' );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\AbstractPasswordPrimaryAuthenticationProvider
+ */
+class AbstractPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testConstructor() {
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class
+ );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+ $this->assertTrue( $providerPriv->authoritative );
+
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class,
+ [ [ 'authoritative' => false ] ]
+ );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+ $this->assertFalse( $providerPriv->authoritative );
+ }
+
+ public function testGetPasswordFactory() {
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class
+ );
+ $provider->setConfig( \ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $obj = $providerPriv->getPasswordFactory();
+ $this->assertInstanceOf( 'PasswordFactory', $obj );
+ $this->assertSame( $obj, $providerPriv->getPasswordFactory() );
+ }
+
+ public function testGetPassword() {
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class
+ );
+ $provider->setConfig( \ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $obj = $providerPriv->getPassword( null );
+ $this->assertInstanceOf( 'Password', $obj );
+
+ $obj = $providerPriv->getPassword( 'invalid' );
+ $this->assertInstanceOf( 'Password', $obj );
+ }
+
+ public function testGetNewPasswordExpiry() {
+ $config = new \HashConfig;
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class
+ );
+ $provider->setConfig( new \MultiConfig( [
+ $config,
+ \ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
+ ] ) );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'ResetPasswordExpiration' => [] ] );
+
+ $config->set( 'PasswordExpirationDays', 0 );
+ $this->assertNull( $providerPriv->getNewPasswordExpiry( 'UTSysop' ) );
+
+ $config->set( 'PasswordExpirationDays', 5 );
+ $this->assertEquals(
+ time() + 5 * 86400,
+ wfTimestamp( TS_UNIX, $providerPriv->getNewPasswordExpiry( 'UTSysop' ) ),
+ '',
+ 2 /* Fuzz */
+ );
+
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [
+ 'ResetPasswordExpiration' => [ function ( $user, &$expires ) {
+ $this->assertSame( 'UTSysop', $user->getName() );
+ $expires = '30001231235959';
+ } ]
+ ] );
+ $this->assertEquals( '30001231235959', $providerPriv->getNewPasswordExpiry( 'UTSysop' ) );
+ }
+
+ public function testCheckPasswordValidity() {
+ $uppCalled = 0;
+ $uppStatus = \Status::newGood();
+ $this->setMwGlobals( [
+ 'wgPasswordPolicy' => [
+ 'policies' => [
+ 'default' => [
+ 'Check' => true,
+ ],
+ ],
+ 'checks' => [
+ 'Check' => function () use ( &$uppCalled, &$uppStatus ) {
+ $uppCalled++;
+ return $uppStatus;
+ },
+ ],
+ ]
+ ] );
+
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class
+ );
+ $provider->setConfig( \ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $this->assertEquals( $uppStatus, $providerPriv->checkPasswordValidity( 'foo', 'bar' ) );
+
+ $uppStatus->fatal( 'arbitrary-warning' );
+ $this->assertEquals( $uppStatus, $providerPriv->checkPasswordValidity( 'foo', 'bar' ) );
+ }
+
+ public function testSetPasswordResetFlag() {
+ $config = new \HashConfig( [
+ 'InvalidPasswordReset' => true,
+ ] );
+
+ $manager = new AuthManager(
+ new \FauxRequest(), \ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
+ );
+
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class
+ );
+ $provider->setConfig( $config );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setManager( $manager );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $manager->removeAuthenticationSessionData( null );
+ $status = \Status::newGood();
+ $providerPriv->setPasswordResetFlag( 'Foo', $status );
+ $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+
+ $manager->removeAuthenticationSessionData( null );
+ $status = \Status::newGood();
+ $status->error( 'testing' );
+ $providerPriv->setPasswordResetFlag( 'Foo', $status );
+ $ret = $manager->getAuthenticationSessionData( 'reset-pass' );
+ $this->assertNotNull( $ret );
+ $this->assertSame( 'resetpass-validity-soft', $ret->msg->getKey() );
+ $this->assertFalse( $ret->hard );
+
+ $config->set( 'InvalidPasswordReset', false );
+ $manager->removeAuthenticationSessionData( null );
+ $providerPriv->setPasswordResetFlag( 'Foo', $status );
+ $ret = $manager->getAuthenticationSessionData( 'reset-pass' );
+ $this->assertNull( $ret );
+ }
+
+ public function testFailResponse() {
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class,
+ [ [ 'authoritative' => false ] ]
+ );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $req = new PasswordAuthenticationRequest;
+
+ $ret = $providerPriv->failResponse( $req );
+ $this->assertSame( AuthenticationResponse::ABSTAIN, $ret->status );
+
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class,
+ [ [ 'authoritative' => true ] ]
+ );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $req->password = '';
+ $ret = $providerPriv->failResponse( $req );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'wrongpasswordempty', $ret->message->getKey() );
+
+ $req->password = 'X';
+ $ret = $providerPriv->failResponse( $req );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'wrongpassword', $ret->message->getKey() );
+ }
+
+ /**
+ * @dataProvider provideGetAuthenticationRequests
+ * @param string $action
+ * @param array $response
+ */
+ public function testGetAuthenticationRequests( $action, $response ) {
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class
+ );
+
+ $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
+ }
+
+ public static function provideGetAuthenticationRequests() {
+ return [
+ [ AuthManager::ACTION_LOGIN, [ new PasswordAuthenticationRequest() ] ],
+ [ AuthManager::ACTION_CREATE, [ new PasswordAuthenticationRequest() ] ],
+ [ AuthManager::ACTION_LINK, [] ],
+ [ AuthManager::ACTION_CHANGE, [ new PasswordAuthenticationRequest() ] ],
+ [ AuthManager::ACTION_REMOVE, [ new PasswordAuthenticationRequest() ] ],
+ ];
+ }
+
+ public function testProviderRevokeAccessForUser() {
+ $req = new PasswordAuthenticationRequest;
+ $req->action = AuthManager::ACTION_REMOVE;
+ $req->username = 'foo';
+ $req->password = null;
+
+ $provider = $this->getMockForAbstractClass(
+ AbstractPasswordPrimaryAuthenticationProvider::class
+ );
+ $provider->expects( $this->once() )
+ ->method( 'providerChangeAuthenticationData' )
+ ->with( $this->equalTo( $req ) );
+
+ $provider->providerRevokeAccessForUser( 'foo' );
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\AbstractPreAuthenticationProvider
+ */
+class AbstractPreAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testAbstractPreAuthenticationProvider() {
+ $user = \User::newFromName( 'UTSysop' );
+
+ $provider = $this->getMockForAbstractClass( AbstractPreAuthenticationProvider::class );
+
+ $this->assertEquals(
+ [],
+ $provider->getAuthenticationRequests( AuthManager::ACTION_LOGIN, [] )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAuthentication( [] )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $user, [] )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testUserForCreation( $user, AuthManager::AUTOCREATE_SOURCE_SESSION )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testUserForCreation( $user, false )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountLink( $user )
+ );
+
+ $res = AuthenticationResponse::newPass();
+ $provider->postAuthentication( $user, $res );
+ $provider->postAccountCreation( $user, $user, $res );
+ $provider->postAccountLink( $user, $res );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\AbstractPrimaryAuthenticationProvider
+ */
+class AbstractPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testAbstractPrimaryAuthenticationProvider() {
+ $user = \User::newFromName( 'UTSysop' );
+
+ $provider = $this->getMockForAbstractClass( AbstractPrimaryAuthenticationProvider::class );
+
+ try {
+ $provider->continuePrimaryAuthentication( [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ }
+
+ try {
+ $provider->continuePrimaryAccountCreation( $user, $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ }
+
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+
+ $this->assertTrue( $provider->providerAllowsPropertyChange( 'foo' ) );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $user, [] )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testUserForCreation( $user, AuthManager::AUTOCREATE_SOURCE_SESSION )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testUserForCreation( $user, false )
+ );
+
+ $this->assertNull(
+ $provider->finishAccountCreation( $user, $user, AuthenticationResponse::newPass() )
+ );
+ $provider->autoCreatedAccount( $user, AuthManager::AUTOCREATE_SOURCE_SESSION );
+
+ $res = AuthenticationResponse::newPass();
+ $provider->postAuthentication( $user, $res );
+ $provider->postAccountCreation( $user, $user, $res );
+ $provider->postAccountLink( $user, $res );
+
+ $provider->expects( $this->once() )
+ ->method( 'testUserExists' )
+ ->with( $this->equalTo( 'foo' ) )
+ ->will( $this->returnValue( true ) );
+ $this->assertTrue( $provider->testUserCanAuthenticate( 'foo' ) );
+ }
+
+ public function testProviderRevokeAccessForUser() {
+ $reqs = [];
+ for ( $i = 0; $i < 3; $i++ ) {
+ $reqs[$i] = $this->getMock( AuthenticationRequest::class );
+ $reqs[$i]->done = false;
+ }
+
+ $provider = $this->getMockForAbstractClass( AbstractPrimaryAuthenticationProvider::class );
+ $provider->expects( $this->once() )->method( 'getAuthenticationRequests' )
+ ->with(
+ $this->identicalTo( AuthManager::ACTION_REMOVE ),
+ $this->identicalTo( [ 'username' => 'UTSysop' ] )
+ )
+ ->will( $this->returnValue( $reqs ) );
+ $provider->expects( $this->exactly( 3 ) )->method( 'providerChangeAuthenticationData' )
+ ->will( $this->returnCallback( function ( $req ) {
+ $this->assertSame( 'UTSysop', $req->username );
+ $this->assertFalse( $req->done );
+ $req->done = true;
+ } ) );
+
+ $provider->providerRevokeAccessForUser( 'UTSysop' );
+
+ foreach ( $reqs as $i => $req ) {
+ $this->assertTrue( $req->done, "#$i" );
+ }
+ }
+
+ /**
+ * @dataProvider providePrimaryAccountLink
+ * @param string $type PrimaryAuthenticationProvider::TYPE_* constant
+ * @param string $msg Error message from beginPrimaryAccountLink
+ */
+ public function testPrimaryAccountLink( $type, $msg ) {
+ $provider = $this->getMockForAbstractClass( AbstractPrimaryAuthenticationProvider::class );
+ $provider->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( $type ) );
+
+ $class = AbstractPrimaryAuthenticationProvider::class;
+ $msg1 = "{$class}::beginPrimaryAccountLink $msg";
+ $msg2 = "{$class}::continuePrimaryAccountLink is not implemented.";
+
+ $user = \User::newFromName( 'Whatever' );
+
+ try {
+ $provider->beginPrimaryAccountLink( $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ $this->assertSame( $msg1, $ex->getMessage() );
+ }
+ try {
+ $provider->continuePrimaryAccountLink( $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ $this->assertSame( $msg2, $ex->getMessage() );
+ }
+ }
+
+ public static function providePrimaryAccountLink() {
+ return [
+ [
+ PrimaryAuthenticationProvider::TYPE_NONE,
+ 'should not be called on a non-link provider.',
+ ],
+ [
+ PrimaryAuthenticationProvider::TYPE_CREATE,
+ 'should not be called on a non-link provider.',
+ ],
+ [
+ PrimaryAuthenticationProvider::TYPE_LINK,
+ 'is not implemented.',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideProviderNormalizeUsername
+ */
+ public function testProviderNormalizeUsername( $name, $expect ) {
+ // fake interwiki map for the 'Interwiki prefix' testcase
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [
+ 'InterwikiLoadPrefix' => [
+ function ( $prefix, &$iwdata ) {
+ if ( $prefix === 'interwiki' ) {
+ $iwdata = [
+ 'iw_url' => 'http://example.com/',
+ 'iw_local' => 0,
+ 'iw_trans' => 0,
+ ];
+ return false;
+ }
+ },
+ ],
+ ] );
+
+ $provider = $this->getMockForAbstractClass( AbstractPrimaryAuthenticationProvider::class );
+ $this->assertSame( $expect, $provider->providerNormalizeUsername( $name ) );
+ }
+
+ public static function provideProviderNormalizeUsername() {
+ return [
+ 'Leading space' => [ ' Leading space', 'Leading space' ],
+ 'Trailing space ' => [ 'Trailing space ', 'Trailing space' ],
+ 'Namespace prefix' => [ 'Talk:Username', null ],
+ 'Interwiki prefix' => [ 'interwiki:Username', null ],
+ 'With hash' => [ 'name with # hash', null ],
+ 'Multi spaces' => [ 'Multi spaces', 'Multi spaces' ],
+ 'Lowercase' => [ 'lowercase', 'Lowercase' ],
+ 'Invalid character' => [ 'in[]valid', null ],
+ 'With slash' => [ 'with / slash', null ],
+ 'Underscores' => [ '___under__scores___', 'Under scores' ],
+ ];
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\AbstractSecondaryAuthenticationProvider
+ */
+class AbstractSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testAbstractSecondaryAuthenticationProvider() {
+ $user = \User::newFromName( 'UTSysop' );
+
+ $provider = $this->getMockForAbstractClass( AbstractSecondaryAuthenticationProvider::class );
+
+ try {
+ $provider->continueSecondaryAuthentication( $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ }
+
+ try {
+ $provider->continueSecondaryAccountCreation( $user, $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ }
+
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+
+ $this->assertTrue( $provider->providerAllowsPropertyChange( 'foo' ) );
+ $this->assertEquals(
+ \StatusValue::newGood( 'ignored' ),
+ $provider->providerAllowsAuthenticationDataChange( $req )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $user, [] )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testUserForCreation( $user, AuthManager::AUTOCREATE_SOURCE_SESSION )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testUserForCreation( $user, false )
+ );
+
+ $provider->providerChangeAuthenticationData( $req );
+ $provider->autoCreatedAccount( $user, AuthManager::AUTOCREATE_SOURCE_SESSION );
+
+ $res = AuthenticationResponse::newPass();
+ $provider->postAuthentication( $user, $res );
+ $provider->postAccountCreation( $user, $user, $res );
+ }
+
+ public function testProviderRevokeAccessForUser() {
+ $reqs = [];
+ for ( $i = 0; $i < 3; $i++ ) {
+ $reqs[$i] = $this->getMock( AuthenticationRequest::class );
+ $reqs[$i]->done = false;
+ }
+
+ $provider = $this->getMockBuilder( AbstractSecondaryAuthenticationProvider::class )
+ ->setMethods( [ 'providerChangeAuthenticationData' ] )
+ ->getMockForAbstractClass();
+ $provider->expects( $this->once() )->method( 'getAuthenticationRequests' )
+ ->with(
+ $this->identicalTo( AuthManager::ACTION_REMOVE ),
+ $this->identicalTo( [ 'username' => 'UTSysop' ] )
+ )
+ ->will( $this->returnValue( $reqs ) );
+ $provider->expects( $this->exactly( 3 ) )->method( 'providerChangeAuthenticationData' )
+ ->will( $this->returnCallback( function ( $req ) {
+ $this->assertSame( 'UTSysop', $req->username );
+ $this->assertFalse( $req->done );
+ $req->done = true;
+ } ) );
+
+ $provider->providerRevokeAccessForUser( 'UTSysop' );
+
+ foreach ( $reqs as $i => $req ) {
+ $this->assertTrue( $req->done, "#$i" );
+ }
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+use MediaWiki\Session\SessionInfo;
+use MediaWiki\Session\UserInfo;
+use Psr\Log\LogLevel;
+use StatusValue;
+
+/**
+ * @group AuthManager
+ * @group Database
+ * @covers MediaWiki\Auth\AuthManager
+ */
+class AuthManagerTest extends \MediaWikiTestCase {
+ /** @var WebRequest */
+ protected $request;
+ /** @var Config */
+ protected $config;
+ /** @var \\Psr\\Log\\LoggerInterface */
+ protected $logger;
+
+ protected $preauthMocks = [];
+ protected $primaryauthMocks = [];
+ protected $secondaryauthMocks = [];
+
+ /** @var AuthManager */
+ protected $manager;
+ /** @var TestingAccessWrapper */
+ protected $managerPriv;
+
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+
+ $this->setMwGlobals( [ 'wgAuth' => null ] );
+ $this->stashMwGlobals( [ 'wgHooks' ] );
+ }
+
+ /**
+ * Sets a mock on a hook
+ * @param string $hook
+ * @param object $expect From $this->once(), $this->never(), etc.
+ * @return object $mock->expects( $expect )->method( ... ).
+ */
+ protected function hook( $hook, $expect ) {
+ global $wgHooks;
+ $mock = $this->getMock( __CLASS__, [ "on$hook" ] );
+ $wgHooks[$hook] = [ $mock ];
+ return $mock->expects( $expect )->method( "on$hook" );
+ }
+
+ /**
+ * Unsets a hook
+ * @param string $hook
+ */
+ protected function unhook( $hook ) {
+ global $wgHooks;
+ $wgHooks[$hook] = [];
+ }
+
+ /**
+ * Ensure a value is a clean Message object
+ * @param string|Message $key
+ * @param array $params
+ * @return Message
+ */
+ protected function message( $key, $params = [] ) {
+ if ( $key === null ) {
+ return null;
+ }
+ if ( $key instanceof \MessageSpecifier ) {
+ $params = $key->getParams();
+ $key = $key->getKey();
+ }
+ return new \Message( $key, $params, \Language::factory( 'en' ) );
+ }
+
+ /**
+ * Initialize the AuthManagerConfig variable in $this->config
+ *
+ * Uses data from the various 'mocks' fields.
+ */
+ protected function initializeConfig() {
+ $config = [
+ 'preauth' => [
+ ],
+ 'primaryauth' => [
+ ],
+ 'secondaryauth' => [
+ ],
+ ];
+
+ foreach ( [ 'preauth', 'primaryauth', 'secondaryauth' ] as $type ) {
+ $key = $type . 'Mocks';
+ foreach ( $this->$key as $mock ) {
+ $config[$type][$mock->getUniqueId()] = [ 'factory' => function () use ( $mock ) {
+ return $mock;
+ } ];
+ }
+ }
+
+ $this->config->set( 'AuthManagerConfig', $config );
+ $this->config->set( 'LanguageCode', 'en' );
+ $this->config->set( 'NewUserLog', false );
+ }
+
+ /**
+ * Initialize $this->manager
+ * @param bool $regen Force a call to $this->initializeConfig()
+ */
+ protected function initializeManager( $regen = false ) {
+ if ( $regen || !$this->config ) {
+ $this->config = new \HashConfig();
+ }
+ if ( $regen || !$this->request ) {
+ $this->request = new \FauxRequest();
+ }
+ if ( !$this->logger ) {
+ $this->logger = new \TestLogger();
+ }
+
+ if ( $regen || !$this->config->has( 'AuthManagerConfig' ) ) {
+ $this->initializeConfig();
+ }
+ $this->manager = new AuthManager( $this->request, $this->config );
+ $this->manager->setLogger( $this->logger );
+ $this->managerPriv = \TestingAccessWrapper::newFromObject( $this->manager );
+ }
+
+ /**
+ * Setup SessionManager with a mock session provider
+ * @param bool|null $canChangeUser If non-null, canChangeUser will be mocked to return this
+ * @param array $methods Additional methods to mock
+ * @return array (MediaWiki\Session\SessionProvider, ScopedCallback)
+ */
+ protected function getMockSessionProvider( $canChangeUser = null, array $methods = [] ) {
+ if ( !$this->config ) {
+ $this->config = new \HashConfig();
+ $this->initializeConfig();
+ }
+ $this->config->set( 'ObjectCacheSessionExpiry', 100 );
+
+ $methods[] = '__toString';
+ $methods[] = 'describe';
+ if ( $canChangeUser !== null ) {
+ $methods[] = 'canChangeUser';
+ }
+ $provider = $this->getMockBuilder( 'DummySessionProvider' )
+ ->setMethods( $methods )
+ ->getMock();
+ $provider->expects( $this->any() )->method( '__toString' )
+ ->will( $this->returnValue( 'MockSessionProvider' ) );
+ $provider->expects( $this->any() )->method( 'describe' )
+ ->will( $this->returnValue( 'MockSessionProvider sessions' ) );
+ if ( $canChangeUser !== null ) {
+ $provider->expects( $this->any() )->method( 'canChangeUser' )
+ ->will( $this->returnValue( $canChangeUser ) );
+ }
+ $this->config->set( 'SessionProviders', [
+ [ 'factory' => function () use ( $provider ) {
+ return $provider;
+ } ],
+ ] );
+
+ $manager = new \MediaWiki\Session\SessionManager( [
+ 'config' => $this->config,
+ 'logger' => new \Psr\Log\NullLogger(),
+ 'store' => new \HashBagOStuff(),
+ ] );
+ \TestingAccessWrapper::newFromObject( $manager )->getProvider( (string)$provider );
+
+ $reset = \MediaWiki\Session\TestUtils::setSessionManagerSingleton( $manager );
+
+ if ( $this->request ) {
+ $manager->getSessionForRequest( $this->request );
+ }
+
+ return [ $provider, $reset ];
+ }
+
+ public function testSingleton() {
+ // Temporarily clear out the global singleton, if any, to test creating
+ // one.
+ $rProp = new \ReflectionProperty( AuthManager::class, 'instance' );
+ $rProp->setAccessible( true );
+ $old = $rProp->getValue();
+ $cb = new \ScopedCallback( [ $rProp, 'setValue' ], [ $old ] );
+ $rProp->setValue( null );
+
+ $singleton = AuthManager::singleton();
+ $this->assertInstanceOf( AuthManager::class, AuthManager::singleton() );
+ $this->assertSame( $singleton, AuthManager::singleton() );
+ $this->assertSame( \RequestContext::getMain()->getRequest(), $singleton->getRequest() );
+ $this->assertSame(
+ \RequestContext::getMain()->getConfig(),
+ \TestingAccessWrapper::newFromObject( $singleton )->config
+ );
+
+ $this->setMwGlobals( [ 'wgDisableAuthManager' => true ] );
+ try {
+ AuthManager::singleton();
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ $this->assertSame( '$wgDisableAuthManager is set', $ex->getMessage() );
+ }
+ }
+
+ public function testCanAuthenticateNow() {
+ $this->initializeManager();
+
+ list( $provider, $reset ) = $this->getMockSessionProvider( false );
+ $this->assertFalse( $this->manager->canAuthenticateNow() );
+ \ScopedCallback::consume( $reset );
+
+ list( $provider, $reset ) = $this->getMockSessionProvider( true );
+ $this->assertTrue( $this->manager->canAuthenticateNow() );
+ \ScopedCallback::consume( $reset );
+ }
+
+ public function testNormalizeUsername() {
+ $mocks = [
+ $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class ),
+ $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class ),
+ $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class ),
+ $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class ),
+ ];
+ foreach ( $mocks as $key => $mock ) {
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( $key ) );
+ }
+ $mocks[0]->expects( $this->once() )->method( 'providerNormalizeUsername' )
+ ->with( $this->identicalTo( 'XYZ' ) )
+ ->willReturn( 'Foo' );
+ $mocks[1]->expects( $this->once() )->method( 'providerNormalizeUsername' )
+ ->with( $this->identicalTo( 'XYZ' ) )
+ ->willReturn( 'Foo' );
+ $mocks[2]->expects( $this->once() )->method( 'providerNormalizeUsername' )
+ ->with( $this->identicalTo( 'XYZ' ) )
+ ->willReturn( null );
+ $mocks[3]->expects( $this->once() )->method( 'providerNormalizeUsername' )
+ ->with( $this->identicalTo( 'XYZ' ) )
+ ->willReturn( 'Bar!' );
+
+ $this->primaryauthMocks = $mocks;
+
+ $this->initializeManager();
+
+ $this->assertSame( [ 'Foo', 'Bar!' ], $this->manager->normalizeUsername( 'XYZ' ) );
+ }
+
+ /**
+ * @dataProvider provideSecuritySensitiveOperationStatus
+ * @param bool $mutableSession
+ */
+ public function testSecuritySensitiveOperationStatus( $mutableSession ) {
+ $this->logger = new \Psr\Log\NullLogger();
+ $user = \User::newFromName( 'UTSysop' );
+ $provideUser = null;
+ $reauth = $mutableSession ? AuthManager::SEC_REAUTH : AuthManager::SEC_FAIL;
+
+ list( $provider, $reset ) = $this->getMockSessionProvider(
+ $mutableSession, [ 'provideSessionInfo' ]
+ );
+ $provider->expects( $this->any() )->method( 'provideSessionInfo' )
+ ->will( $this->returnCallback( function () use ( $provider, &$provideUser ) {
+ return new SessionInfo( SessionInfo::MIN_PRIORITY, [
+ 'provider' => $provider,
+ 'id' => \DummySessionProvider::ID,
+ 'persisted' => true,
+ 'userInfo' => UserInfo::newFromUser( $provideUser, true )
+ ] );
+ } ) );
+ $this->initializeManager();
+
+ $this->config->set( 'ReauthenticateTime', [] );
+ $this->config->set( 'AllowSecuritySensitiveOperationIfCannotReauthenticate', [] );
+ $provideUser = new \User;
+ $session = $provider->getManager()->getSessionForRequest( $this->request );
+ $this->assertSame( 0, $session->getUser()->getId(), 'sanity check' );
+
+ // Anonymous user => reauth
+ $session->set( 'AuthManager:lastAuthId', 0 );
+ $session->set( 'AuthManager:lastAuthTimestamp', time() - 5 );
+ $this->assertSame( $reauth, $this->manager->securitySensitiveOperationStatus( 'foo' ) );
+
+ $provideUser = $user;
+ $session = $provider->getManager()->getSessionForRequest( $this->request );
+ $this->assertSame( $user->getId(), $session->getUser()->getId(), 'sanity check' );
+
+ // Error for no default (only gets thrown for non-anonymous user)
+ $session->set( 'AuthManager:lastAuthId', $user->getId() + 1 );
+ $session->set( 'AuthManager:lastAuthTimestamp', time() - 5 );
+ try {
+ $this->manager->securitySensitiveOperationStatus( 'foo' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame(
+ $mutableSession
+ ? '$wgReauthenticateTime lacks a default'
+ : '$wgAllowSecuritySensitiveOperationIfCannotReauthenticate lacks a default',
+ $ex->getMessage()
+ );
+ }
+
+ if ( $mutableSession ) {
+ $this->config->set( 'ReauthenticateTime', [
+ 'test' => 100,
+ 'test2' => -1,
+ 'default' => 10,
+ ] );
+
+ // Mismatched user ID
+ $session->set( 'AuthManager:lastAuthId', $user->getId() + 1 );
+ $session->set( 'AuthManager:lastAuthTimestamp', time() - 5 );
+ $this->assertSame(
+ AuthManager::SEC_REAUTH, $this->manager->securitySensitiveOperationStatus( 'foo' )
+ );
+ $this->assertSame(
+ AuthManager::SEC_REAUTH, $this->manager->securitySensitiveOperationStatus( 'test' )
+ );
+ $this->assertSame(
+ AuthManager::SEC_OK, $this->manager->securitySensitiveOperationStatus( 'test2' )
+ );
+
+ // Missing time
+ $session->set( 'AuthManager:lastAuthId', $user->getId() );
+ $session->set( 'AuthManager:lastAuthTimestamp', null );
+ $this->assertSame(
+ AuthManager::SEC_REAUTH, $this->manager->securitySensitiveOperationStatus( 'foo' )
+ );
+ $this->assertSame(
+ AuthManager::SEC_REAUTH, $this->manager->securitySensitiveOperationStatus( 'test' )
+ );
+ $this->assertSame(
+ AuthManager::SEC_OK, $this->manager->securitySensitiveOperationStatus( 'test2' )
+ );
+
+ // Recent enough to pass
+ $session->set( 'AuthManager:lastAuthTimestamp', time() - 5 );
+ $this->assertSame(
+ AuthManager::SEC_OK, $this->manager->securitySensitiveOperationStatus( 'foo' )
+ );
+
+ // Not recent enough to pass
+ $session->set( 'AuthManager:lastAuthTimestamp', time() - 20 );
+ $this->assertSame(
+ AuthManager::SEC_REAUTH, $this->manager->securitySensitiveOperationStatus( 'foo' )
+ );
+ // But recent enough for the 'test' operation
+ $this->assertSame(
+ AuthManager::SEC_OK, $this->manager->securitySensitiveOperationStatus( 'test' )
+ );
+ } else {
+ $this->config->set( 'AllowSecuritySensitiveOperationIfCannotReauthenticate', [
+ 'test' => false,
+ 'default' => true,
+ ] );
+
+ $this->assertEquals(
+ AuthManager::SEC_OK, $this->manager->securitySensitiveOperationStatus( 'foo' )
+ );
+
+ $this->assertEquals(
+ AuthManager::SEC_FAIL, $this->manager->securitySensitiveOperationStatus( 'test' )
+ );
+ }
+
+ // Test hook, all three possible values
+ foreach ( [
+ AuthManager::SEC_OK => AuthManager::SEC_OK,
+ AuthManager::SEC_REAUTH => $reauth,
+ AuthManager::SEC_FAIL => AuthManager::SEC_FAIL,
+ ] as $hook => $expect ) {
+ $this->hook( 'SecuritySensitiveOperationStatus', $this->exactly( 2 ) )
+ ->with(
+ $this->anything(),
+ $this->anything(),
+ $this->callback( function ( $s ) use ( $session ) {
+ return $s->getId() === $session->getId();
+ } ),
+ $mutableSession ? $this->equalTo( 500, 1 ) : $this->equalTo( -1 )
+ )
+ ->will( $this->returnCallback( function ( &$v ) use ( $hook ) {
+ $v = $hook;
+ return true;
+ } ) );
+ $session->set( 'AuthManager:lastAuthTimestamp', time() - 500 );
+ $this->assertEquals(
+ $expect, $this->manager->securitySensitiveOperationStatus( 'test' ), "hook $hook"
+ );
+ $this->assertEquals(
+ $expect, $this->manager->securitySensitiveOperationStatus( 'test2' ), "hook $hook"
+ );
+ $this->unhook( 'SecuritySensitiveOperationStatus' );
+ }
+
+ \ScopedCallback::consume( $reset );
+ }
+
+ public function onSecuritySensitiveOperationStatus( &$status, $operation, $session, $time ) {
+ }
+
+ public static function provideSecuritySensitiveOperationStatus() {
+ return [
+ [ true ],
+ [ false ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideUserCanAuthenticate
+ * @param bool $primary1Can
+ * @param bool $primary2Can
+ * @param bool $expect
+ */
+ public function testUserCanAuthenticate( $primary1Can, $primary2Can, $expect ) {
+ $mock1 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock1->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'primary1' ) );
+ $mock1->expects( $this->any() )->method( 'testUserCanAuthenticate' )
+ ->with( $this->equalTo( 'UTSysop' ) )
+ ->will( $this->returnValue( $primary1Can ) );
+ $mock2 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock2->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'primary2' ) );
+ $mock2->expects( $this->any() )->method( 'testUserCanAuthenticate' )
+ ->with( $this->equalTo( 'UTSysop' ) )
+ ->will( $this->returnValue( $primary2Can ) );
+ $this->primaryauthMocks = [ $mock1, $mock2 ];
+
+ $this->initializeManager( true );
+ $this->assertSame( $expect, $this->manager->userCanAuthenticate( 'UTSysop' ) );
+ }
+
+ public static function provideUserCanAuthenticate() {
+ return [
+ [ false, false, false ],
+ [ true, false, true ],
+ [ false, true, true ],
+ [ true, true, true ],
+ ];
+ }
+
+ public function testRevokeAccessForUser() {
+ $this->initializeManager();
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'primary' ) );
+ $mock->expects( $this->once() )->method( 'providerRevokeAccessForUser' )
+ ->with( $this->equalTo( 'UTSysop' ) );
+ $this->primaryauthMocks = [ $mock ];
+
+ $this->initializeManager( true );
+ $this->logger->setCollect( true );
+
+ $this->manager->revokeAccessForUser( 'UTSysop' );
+
+ $this->assertSame( [
+ [ LogLevel::INFO, 'Revoking access for {user}' ],
+ ], $this->logger->getBuffer() );
+ }
+
+ public function testProviderCreation() {
+ $mocks = [
+ 'pre' => $this->getMockForAbstractClass( PreAuthenticationProvider::class ),
+ 'primary' => $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class ),
+ 'secondary' => $this->getMockForAbstractClass( SecondaryAuthenticationProvider::class ),
+ ];
+ foreach ( $mocks as $key => $mock ) {
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( $key ) );
+ $mock->expects( $this->once() )->method( 'setLogger' );
+ $mock->expects( $this->once() )->method( 'setManager' );
+ $mock->expects( $this->once() )->method( 'setConfig' );
+ }
+ $this->preauthMocks = [ $mocks['pre'] ];
+ $this->primaryauthMocks = [ $mocks['primary'] ];
+ $this->secondaryauthMocks = [ $mocks['secondary'] ];
+
+ // Normal operation
+ $this->initializeManager();
+ $this->assertSame(
+ $mocks['primary'],
+ $this->managerPriv->getAuthenticationProvider( 'primary' )
+ );
+ $this->assertSame(
+ $mocks['secondary'],
+ $this->managerPriv->getAuthenticationProvider( 'secondary' )
+ );
+ $this->assertSame(
+ $mocks['pre'],
+ $this->managerPriv->getAuthenticationProvider( 'pre' )
+ );
+ $this->assertSame(
+ [ 'pre' => $mocks['pre'] ],
+ $this->managerPriv->getPreAuthenticationProviders()
+ );
+ $this->assertSame(
+ [ 'primary' => $mocks['primary'] ],
+ $this->managerPriv->getPrimaryAuthenticationProviders()
+ );
+ $this->assertSame(
+ [ 'secondary' => $mocks['secondary'] ],
+ $this->managerPriv->getSecondaryAuthenticationProviders()
+ );
+
+ // Duplicate IDs
+ $mock1 = $this->getMockForAbstractClass( PreAuthenticationProvider::class );
+ $mock2 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock1->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock2->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $this->preauthMocks = [ $mock1 ];
+ $this->primaryauthMocks = [ $mock2 ];
+ $this->secondaryauthMocks = [];
+ $this->initializeManager( true );
+ try {
+ $this->managerPriv->getAuthenticationProvider( 'Y' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \RuntimeException $ex ) {
+ $class1 = get_class( $mock1 );
+ $class2 = get_class( $mock2 );
+ $this->assertSame(
+ "Duplicate specifications for id X (classes $class1 and $class2)", $ex->getMessage()
+ );
+ }
+
+ // Wrong classes
+ $mock = $this->getMockForAbstractClass( AuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $class = get_class( $mock );
+ $this->preauthMocks = [ $mock ];
+ $this->primaryauthMocks = [ $mock ];
+ $this->secondaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+ try {
+ $this->managerPriv->getPreAuthenticationProviders();
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \RuntimeException $ex ) {
+ $this->assertSame(
+ "Expected instance of MediaWiki\\Auth\\PreAuthenticationProvider, got $class",
+ $ex->getMessage()
+ );
+ }
+ try {
+ $this->managerPriv->getPrimaryAuthenticationProviders();
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \RuntimeException $ex ) {
+ $this->assertSame(
+ "Expected instance of MediaWiki\\Auth\\PrimaryAuthenticationProvider, got $class",
+ $ex->getMessage()
+ );
+ }
+ try {
+ $this->managerPriv->getSecondaryAuthenticationProviders();
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \RuntimeException $ex ) {
+ $this->assertSame(
+ "Expected instance of MediaWiki\\Auth\\SecondaryAuthenticationProvider, got $class",
+ $ex->getMessage()
+ );
+ }
+
+ // Sorting
+ $mock1 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock2 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock3 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock1->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'A' ) );
+ $mock2->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'B' ) );
+ $mock3->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'C' ) );
+ $this->preauthMocks = [];
+ $this->primaryauthMocks = [ $mock1, $mock2, $mock3 ];
+ $this->secondaryauthMocks = [];
+ $this->initializeConfig();
+ $config = $this->config->get( 'AuthManagerConfig' );
+
+ $this->initializeManager( false );
+ $this->assertSame(
+ [ 'A' => $mock1, 'B' => $mock2, 'C' => $mock3 ],
+ $this->managerPriv->getPrimaryAuthenticationProviders(),
+ 'sanity check'
+ );
+
+ $config['primaryauth']['A']['sort'] = 100;
+ $config['primaryauth']['C']['sort'] = -1;
+ $this->config->set( 'AuthManagerConfig', $config );
+ $this->initializeManager( false );
+ $this->assertSame(
+ [ 'C' => $mock3, 'B' => $mock2, 'A' => $mock1 ],
+ $this->managerPriv->getPrimaryAuthenticationProviders()
+ );
+ }
+
+ public function testSetDefaultUserOptions() {
+ $this->initializeManager();
+
+ $context = \RequestContext::getMain();
+ $reset = new \ScopedCallback( [ $context, 'setLanguage' ], [ $context->getLanguage() ] );
+ $context->setLanguage( 'de' );
+ $this->setMwGlobals( 'wgContLang', \Language::factory( 'zh' ) );
+
+ $user = \User::newFromName( self::usernameForCreation() );
+ $user->addToDatabase();
+ $oldToken = $user->getToken();
+ $this->managerPriv->setDefaultUserOptions( $user, false );
+ $user->saveSettings();
+ $this->assertNotEquals( $oldToken, $user->getToken() );
+ $this->assertSame( 'zh', $user->getOption( 'language' ) );
+ $this->assertSame( 'zh', $user->getOption( 'variant' ) );
+
+ $user = \User::newFromName( self::usernameForCreation() );
+ $user->addToDatabase();
+ $oldToken = $user->getToken();
+ $this->managerPriv->setDefaultUserOptions( $user, true );
+ $user->saveSettings();
+ $this->assertNotEquals( $oldToken, $user->getToken() );
+ $this->assertSame( 'de', $user->getOption( 'language' ) );
+ $this->assertSame( 'zh', $user->getOption( 'variant' ) );
+
+ $this->setMwGlobals( 'wgContLang', \Language::factory( 'en' ) );
+
+ $user = \User::newFromName( self::usernameForCreation() );
+ $user->addToDatabase();
+ $oldToken = $user->getToken();
+ $this->managerPriv->setDefaultUserOptions( $user, true );
+ $user->saveSettings();
+ $this->assertNotEquals( $oldToken, $user->getToken() );
+ $this->assertSame( 'de', $user->getOption( 'language' ) );
+ $this->assertSame( null, $user->getOption( 'variant' ) );
+ }
+
+ public function testForcePrimaryAuthenticationProviders() {
+ $mockA = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mockB = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mockB2 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mockA->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'A' ) );
+ $mockB->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'B' ) );
+ $mockB2->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'B' ) );
+ $this->primaryauthMocks = [ $mockA ];
+
+ $this->logger = new \TestLogger( true );
+
+ // Test without first initializing the configured providers
+ $this->initializeManager();
+ $this->manager->forcePrimaryAuthenticationProviders( [ $mockB ], 'testing' );
+ $this->assertSame(
+ [ 'B' => $mockB ], $this->managerPriv->getPrimaryAuthenticationProviders()
+ );
+ $this->assertSame( null, $this->managerPriv->getAuthenticationProvider( 'A' ) );
+ $this->assertSame( $mockB, $this->managerPriv->getAuthenticationProvider( 'B' ) );
+ $this->assertSame( [
+ [ LogLevel::WARNING, 'Overriding AuthManager primary authn because testing' ],
+ ], $this->logger->getBuffer() );
+ $this->logger->clearBuffer();
+
+ // Test with first initializing the configured providers
+ $this->initializeManager();
+ $this->assertSame( $mockA, $this->managerPriv->getAuthenticationProvider( 'A' ) );
+ $this->assertSame( null, $this->managerPriv->getAuthenticationProvider( 'B' ) );
+ $this->request->getSession()->setSecret( 'AuthManager::authnState', 'test' );
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState', 'test' );
+ $this->manager->forcePrimaryAuthenticationProviders( [ $mockB ], 'testing' );
+ $this->assertSame(
+ [ 'B' => $mockB ], $this->managerPriv->getPrimaryAuthenticationProviders()
+ );
+ $this->assertSame( null, $this->managerPriv->getAuthenticationProvider( 'A' ) );
+ $this->assertSame( $mockB, $this->managerPriv->getAuthenticationProvider( 'B' ) );
+ $this->assertNull( $this->request->getSession()->getSecret( 'AuthManager::authnState' ) );
+ $this->assertNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' )
+ );
+ $this->assertSame( [
+ [ LogLevel::WARNING, 'Overriding AuthManager primary authn because testing' ],
+ [
+ LogLevel::WARNING,
+ 'PrimaryAuthenticationProviders have already been accessed! I hope nothing breaks.'
+ ],
+ ], $this->logger->getBuffer() );
+ $this->logger->clearBuffer();
+
+ // Test duplicate IDs
+ $this->initializeManager();
+ try {
+ $this->manager->forcePrimaryAuthenticationProviders( [ $mockB, $mockB2 ], 'testing' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \RuntimeException $ex ) {
+ $class1 = get_class( $mockB );
+ $class2 = get_class( $mockB2 );
+ $this->assertSame(
+ "Duplicate specifications for id B (classes $class2 and $class1)", $ex->getMessage()
+ );
+ }
+
+ // Wrong classes
+ $mock = $this->getMockForAbstractClass( AuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $class = get_class( $mock );
+ try {
+ $this->manager->forcePrimaryAuthenticationProviders( [ $mock ], 'testing' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \RuntimeException $ex ) {
+ $this->assertSame(
+ "Expected instance of MediaWiki\\Auth\\PrimaryAuthenticationProvider, got $class",
+ $ex->getMessage()
+ );
+ }
+
+ }
+
+ public function testBeginAuthentication() {
+ $this->initializeManager();
+
+ // Immutable session
+ list( $provider, $reset ) = $this->getMockSessionProvider( false );
+ $this->hook( 'UserLoggedIn', $this->never() );
+ $this->request->getSession()->setSecret( 'AuthManager::authnState', 'test' );
+ try {
+ $this->manager->beginAuthentication( [], 'http://localhost/' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \LogicException $ex ) {
+ $this->assertSame( 'Authentication is not possible now', $ex->getMessage() );
+ }
+ $this->unhook( 'UserLoggedIn' );
+ $this->assertNull( $this->request->getSession()->getSecret( 'AuthManager::authnState' ) );
+ \ScopedCallback::consume( $reset );
+ $this->initializeManager( true );
+
+ // CreatedAccountAuthenticationRequest
+ $user = \User::newFromName( 'UTSysop' );
+ $reqs = [
+ new CreatedAccountAuthenticationRequest( $user->getId(), $user->getName() )
+ ];
+ $this->hook( 'UserLoggedIn', $this->never() );
+ try {
+ $this->manager->beginAuthentication( $reqs, 'http://localhost/' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \LogicException $ex ) {
+ $this->assertSame(
+ 'CreatedAccountAuthenticationRequests are only valid on the same AuthManager ' .
+ 'that created the account',
+ $ex->getMessage()
+ );
+ }
+ $this->unhook( 'UserLoggedIn' );
+
+ $this->request->getSession()->clear();
+ $this->request->getSession()->setSecret( 'AuthManager::authnState', 'test' );
+ $this->managerPriv->createdAccountAuthenticationRequests = [ $reqs[0] ];
+ $this->hook( 'UserLoggedIn', $this->once() )
+ ->with( $this->callback( function ( $u ) use ( $user ) {
+ return $user->getId() === $u->getId() && $user->getName() === $u->getName();
+ } ) );
+ $this->hook( 'AuthManagerLoginAuthenticateAudit', $this->once() );
+ $this->logger->setCollect( true );
+ $ret = $this->manager->beginAuthentication( $reqs, 'http://localhost/' );
+ $this->logger->setCollect( false );
+ $this->unhook( 'UserLoggedIn' );
+ $this->unhook( 'AuthManagerLoginAuthenticateAudit' );
+ $this->assertSame( AuthenticationResponse::PASS, $ret->status );
+ $this->assertSame( $user->getName(), $ret->username );
+ $this->assertSame( $user->getId(), $this->request->getSessionData( 'AuthManager:lastAuthId' ) );
+ $this->assertEquals(
+ time(), $this->request->getSessionData( 'AuthManager:lastAuthTimestamp' ),
+ 'timestamp ±1', 1
+ );
+ $this->assertNull( $this->request->getSession()->getSecret( 'AuthManager::authnState' ) );
+ $this->assertSame( $user->getId(), $this->request->getSession()->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::INFO, 'Logging in {user} after account creation' ],
+ ], $this->logger->getBuffer() );
+ }
+
+ public function testCreateFromLogin() {
+ $user = \User::newFromName( 'UTSysop' );
+ $req1 = $this->getMock( AuthenticationRequest::class );
+ $req2 = $this->getMock( AuthenticationRequest::class );
+ $req3 = $this->getMock( AuthenticationRequest::class );
+ $userReq = new UsernameAuthenticationRequest;
+ $userReq->username = 'UTDummy';
+
+ $req1->returnToUrl = 'http://localhost/';
+ $req2->returnToUrl = 'http://localhost/';
+ $req3->returnToUrl = 'http://localhost/';
+ $req3->username = 'UTDummy';
+ $userReq->returnToUrl = 'http://localhost/';
+
+ // Passing one into beginAuthentication(), and an immediate FAIL
+ $primary = $this->getMockForAbstractClass( AbstractPrimaryAuthenticationProvider::class );
+ $this->primaryauthMocks = [ $primary ];
+ $this->initializeManager( true );
+ $res = AuthenticationResponse::newFail( wfMessage( 'foo' ) );
+ $res->createRequest = $req1;
+ $primary->expects( $this->any() )->method( 'beginPrimaryAuthentication' )
+ ->will( $this->returnValue( $res ) );
+ $createReq = new CreateFromLoginAuthenticationRequest(
+ null, [ $req2->getUniqueId() => $req2 ]
+ );
+ $this->logger->setCollect( true );
+ $ret = $this->manager->beginAuthentication( [ $createReq ], 'http://localhost/' );
+ $this->logger->setCollect( false );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertInstanceOf( CreateFromLoginAuthenticationRequest::class, $ret->createRequest );
+ $this->assertSame( $req1, $ret->createRequest->createRequest );
+ $this->assertEquals( [ $req2->getUniqueId() => $req2 ], $ret->createRequest->maybeLink );
+
+ // UI, then FAIL in beginAuthentication()
+ $primary = $this->getMockBuilder( AbstractPrimaryAuthenticationProvider::class )
+ ->setMethods( [ 'continuePrimaryAuthentication' ] )
+ ->getMockForAbstractClass();
+ $this->primaryauthMocks = [ $primary ];
+ $this->initializeManager( true );
+ $primary->expects( $this->any() )->method( 'beginPrimaryAuthentication' )
+ ->will( $this->returnValue(
+ AuthenticationResponse::newUI( [ $req1 ], wfMessage( 'foo' ) )
+ ) );
+ $res = AuthenticationResponse::newFail( wfMessage( 'foo' ) );
+ $res->createRequest = $req2;
+ $primary->expects( $this->any() )->method( 'continuePrimaryAuthentication' )
+ ->will( $this->returnValue( $res ) );
+ $this->logger->setCollect( true );
+ $ret = $this->manager->beginAuthentication( [], 'http://localhost/' );
+ $this->assertSame( AuthenticationResponse::UI, $ret->status, 'sanity check' );
+ $ret = $this->manager->continueAuthentication( [] );
+ $this->logger->setCollect( false );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertInstanceOf( CreateFromLoginAuthenticationRequest::class, $ret->createRequest );
+ $this->assertSame( $req2, $ret->createRequest->createRequest );
+ $this->assertEquals( [], $ret->createRequest->maybeLink );
+
+ // Pass into beginAccountCreation(), see that maybeLink and createRequest get copied
+ $primary = $this->getMockForAbstractClass( AbstractPrimaryAuthenticationProvider::class );
+ $this->primaryauthMocks = [ $primary ];
+ $this->initializeManager( true );
+ $createReq = new CreateFromLoginAuthenticationRequest( $req3, [ $req2 ] );
+ $createReq->returnToUrl = 'http://localhost/';
+ $createReq->username = 'UTDummy';
+ $res = AuthenticationResponse::newUI( [ $req1 ], wfMessage( 'foo' ) );
+ $primary->expects( $this->any() )->method( 'beginPrimaryAccountCreation' )
+ ->with( $this->anything(), $this->anything(), [ $userReq, $createReq, $req3 ] )
+ ->will( $this->returnValue( $res ) );
+ $primary->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $this->logger->setCollect( true );
+ $ret = $this->manager->beginAccountCreation(
+ $user, [ $userReq, $createReq ], 'http://localhost/'
+ );
+ $this->logger->setCollect( false );
+ $this->assertSame( AuthenticationResponse::UI, $ret->status );
+ $state = $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' );
+ $this->assertNotNull( $state );
+ $this->assertEquals( [ $userReq, $createReq, $req3 ], $state['reqs'] );
+ $this->assertEquals( [ $req2 ], $state['maybeLink'] );
+ }
+
+ /**
+ * @dataProvider provideAuthentication
+ * @param StatusValue $preResponse
+ * @param array $primaryResponses
+ * @param array $secondaryResponses
+ * @param array $managerResponses
+ * @param bool $link Whether the primary authentication provider is a "link" provider
+ */
+ public function testAuthentication(
+ StatusValue $preResponse, array $primaryResponses, array $secondaryResponses,
+ array $managerResponses, $link = false
+ ) {
+ $this->initializeManager();
+ $user = \User::newFromName( 'UTSysop' );
+ $id = $user->getId();
+ $name = $user->getName();
+
+ // Set up lots of mocks...
+ $req = new RememberMeAuthenticationRequest;
+ $req->rememberMe = (bool)rand( 0, 1 );
+ $req->pre = $preResponse;
+ $req->primary = $primaryResponses;
+ $req->secondary = $secondaryResponses;
+ $mocks = [];
+ foreach ( [ 'pre', 'primary', 'secondary' ] as $key ) {
+ $class = ucfirst( $key ) . 'AuthenticationProvider';
+ $mocks[$key] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key]->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key ) );
+ $mocks[$key . '2'] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key . '2']->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key . '2' ) );
+ $mocks[$key . '3'] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key . '3']->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key . '3' ) );
+ }
+ foreach ( $mocks as $mock ) {
+ $mock->expects( $this->any() )->method( 'getAuthenticationRequests' )
+ ->will( $this->returnValue( [] ) );
+ }
+
+ $mocks['pre']->expects( $this->once() )->method( 'testForAuthentication' )
+ ->will( $this->returnCallback( function ( $reqs ) use ( $req ) {
+ $this->assertContains( $req, $reqs );
+ return $req->pre;
+ } ) );
+
+ $ct = count( $req->primary );
+ $callback = $this->returnCallback( function ( $reqs ) use ( $req ) {
+ $this->assertContains( $req, $reqs );
+ return array_shift( $req->primary );
+ } );
+ $mocks['primary']->expects( $this->exactly( min( 1, $ct ) ) )
+ ->method( 'beginPrimaryAuthentication' )
+ ->will( $callback );
+ $mocks['primary']->expects( $this->exactly( max( 0, $ct - 1 ) ) )
+ ->method( 'continuePrimaryAuthentication' )
+ ->will( $callback );
+ if ( $link ) {
+ $mocks['primary']->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_LINK ) );
+ }
+
+ $ct = count( $req->secondary );
+ $callback = $this->returnCallback( function ( $user, $reqs ) use ( $id, $name, $req ) {
+ $this->assertSame( $id, $user->getId() );
+ $this->assertSame( $name, $user->getName() );
+ $this->assertContains( $req, $reqs );
+ return array_shift( $req->secondary );
+ } );
+ $mocks['secondary']->expects( $this->exactly( min( 1, $ct ) ) )
+ ->method( 'beginSecondaryAuthentication' )
+ ->will( $callback );
+ $mocks['secondary']->expects( $this->exactly( max( 0, $ct - 1 ) ) )
+ ->method( 'continueSecondaryAuthentication' )
+ ->will( $callback );
+
+ $abstain = AuthenticationResponse::newAbstain();
+ $mocks['pre2']->expects( $this->atMost( 1 ) )->method( 'testForAuthentication' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $mocks['primary2']->expects( $this->atMost( 1 ) )->method( 'beginPrimaryAuthentication' )
+ ->will( $this->returnValue( $abstain ) );
+ $mocks['primary2']->expects( $this->never() )->method( 'continuePrimaryAuthentication' );
+ $mocks['secondary2']->expects( $this->atMost( 1 ) )->method( 'beginSecondaryAuthentication' )
+ ->will( $this->returnValue( $abstain ) );
+ $mocks['secondary2']->expects( $this->never() )->method( 'continueSecondaryAuthentication' );
+ $mocks['secondary3']->expects( $this->atMost( 1 ) )->method( 'beginSecondaryAuthentication' )
+ ->will( $this->returnValue( $abstain ) );
+ $mocks['secondary3']->expects( $this->never() )->method( 'continueSecondaryAuthentication' );
+
+ $this->preauthMocks = [ $mocks['pre'], $mocks['pre2'] ];
+ $this->primaryauthMocks = [ $mocks['primary'], $mocks['primary2'] ];
+ $this->secondaryauthMocks = [
+ $mocks['secondary3'], $mocks['secondary'], $mocks['secondary2'],
+ // So linking happens
+ new ConfirmLinkSecondaryAuthenticationProvider,
+ ];
+ $this->initializeManager( true );
+ $this->logger->setCollect( true );
+
+ $constraint = \PHPUnit_Framework_Assert::logicalOr(
+ $this->equalTo( AuthenticationResponse::PASS ),
+ $this->equalTo( AuthenticationResponse::FAIL )
+ );
+ $providers = array_filter(
+ array_merge(
+ $this->preauthMocks, $this->primaryauthMocks, $this->secondaryauthMocks
+ ),
+ function ( $p ) {
+ return is_callable( [ $p, 'expects' ] );
+ }
+ );
+ foreach ( $providers as $p ) {
+ $p->postCalled = false;
+ $p->expects( $this->atMost( 1 ) )->method( 'postAuthentication' )
+ ->willReturnCallback( function ( $user, $response ) use ( $constraint, $p ) {
+ if ( $user !== null ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( 'UTSysop', $user->getName() );
+ }
+ $this->assertInstanceOf( AuthenticationResponse::class, $response );
+ $this->assertThat( $response->status, $constraint );
+ $p->postCalled = $response->status;
+ } );
+ }
+
+ $session = $this->request->getSession();
+ $session->setRememberUser( !$req->rememberMe );
+
+ foreach ( $managerResponses as $i => $response ) {
+ $success = $response instanceof AuthenticationResponse &&
+ $response->status === AuthenticationResponse::PASS;
+ if ( $success ) {
+ $this->hook( 'UserLoggedIn', $this->once() )
+ ->with( $this->callback( function ( $user ) use ( $id, $name ) {
+ return $user->getId() === $id && $user->getName() === $name;
+ } ) );
+ } else {
+ $this->hook( 'UserLoggedIn', $this->never() );
+ }
+ if ( $success || (
+ $response instanceof AuthenticationResponse &&
+ $response->status === AuthenticationResponse::FAIL &&
+ $response->message->getKey() !== 'authmanager-authn-not-in-progress' &&
+ $response->message->getKey() !== 'authmanager-authn-no-primary'
+ )
+ ) {
+ $this->hook( 'AuthManagerLoginAuthenticateAudit', $this->once() );
+ } else {
+ $this->hook( 'AuthManagerLoginAuthenticateAudit', $this->never() );
+ }
+
+ $ex = null;
+ try {
+ if ( !$i ) {
+ $ret = $this->manager->beginAuthentication( [ $req ], 'http://localhost/' );
+ } else {
+ $ret = $this->manager->continueAuthentication( [ $req ] );
+ }
+ if ( $response instanceof \Exception ) {
+ $this->fail( 'Expected exception not thrown', "Response $i" );
+ }
+ } catch ( \Exception $ex ) {
+ if ( !$response instanceof \Exception ) {
+ throw $ex;
+ }
+ $this->assertEquals( $response->getMessage(), $ex->getMessage(), "Response $i, exception" );
+ $this->assertNull( $session->getSecret( 'AuthManager::authnState' ),
+ "Response $i, exception, session state" );
+ $this->unhook( 'UserLoggedIn' );
+ $this->unhook( 'AuthManagerLoginAuthenticateAudit' );
+ return;
+ }
+
+ $this->unhook( 'UserLoggedIn' );
+ $this->unhook( 'AuthManagerLoginAuthenticateAudit' );
+
+ $this->assertSame( 'http://localhost/', $req->returnToUrl );
+
+ $ret->message = $this->message( $ret->message );
+ $this->assertEquals( $response, $ret, "Response $i, response" );
+ if ( $success ) {
+ $this->assertSame( $id, $session->getUser()->getId(),
+ "Response $i, authn" );
+ } else {
+ $this->assertSame( 0, $session->getUser()->getId(),
+ "Response $i, authn" );
+ }
+ if ( $success || $response->status === AuthenticationResponse::FAIL ) {
+ $this->assertNull( $session->getSecret( 'AuthManager::authnState' ),
+ "Response $i, session state" );
+ foreach ( $providers as $p ) {
+ $this->assertSame( $response->status, $p->postCalled,
+ "Response $i, post-auth callback called" );
+ }
+ } else {
+ $this->assertNotNull( $session->getSecret( 'AuthManager::authnState' ),
+ "Response $i, session state" );
+ foreach ( $ret->neededRequests as $neededReq ) {
+ $this->assertEquals( AuthManager::ACTION_LOGIN, $neededReq->action,
+ "Response $i, neededRequest action" );
+ }
+ $this->assertEquals(
+ $ret->neededRequests,
+ $this->manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN_CONTINUE ),
+ "Response $i, continuation check"
+ );
+ foreach ( $providers as $p ) {
+ $this->assertFalse( $p->postCalled, "Response $i, post-auth callback not called" );
+ }
+ }
+
+ $state = $session->getSecret( 'AuthManager::authnState' );
+ $maybeLink = isset( $state['maybeLink'] ) ? $state['maybeLink'] : [];
+ if ( $link && $response->status === AuthenticationResponse::RESTART ) {
+ $this->assertEquals(
+ $response->createRequest->maybeLink,
+ $maybeLink,
+ "Response $i, maybeLink"
+ );
+ } else {
+ $this->assertEquals( [], $maybeLink, "Response $i, maybeLink" );
+ }
+ }
+
+ if ( $success ) {
+ $this->assertSame( $req->rememberMe, $session->shouldRememberUser(),
+ 'rememberMe checkbox had effect' );
+ } else {
+ $this->assertNotSame( $req->rememberMe, $session->shouldRememberUser(),
+ 'rememberMe checkbox wasn\'t applied' );
+ }
+ }
+
+ public function provideAuthentication() {
+ $user = \User::newFromName( 'UTSysop' );
+ $id = $user->getId();
+ $name = $user->getName();
+
+ $rememberReq = new RememberMeAuthenticationRequest;
+ $rememberReq->action = AuthManager::ACTION_LOGIN;
+
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ $req->foobar = 'baz';
+ $restartResponse = AuthenticationResponse::newRestart(
+ $this->message( 'authmanager-authn-no-local-user' )
+ );
+ $restartResponse->neededRequests = [ $rememberReq ];
+
+ $restartResponse2Pass = AuthenticationResponse::newPass( null );
+ $restartResponse2Pass->linkRequest = $req;
+ $restartResponse2 = AuthenticationResponse::newRestart(
+ $this->message( 'authmanager-authn-no-local-user-link' )
+ );
+ $restartResponse2->createRequest = new CreateFromLoginAuthenticationRequest(
+ null, [ $req->getUniqueId() => $req ]
+ );
+ $restartResponse2->createRequest->action = AuthManager::ACTION_LOGIN;
+ $restartResponse2->neededRequests = [ $rememberReq, $restartResponse2->createRequest ];
+
+ return [
+ 'Failure in pre-auth' => [
+ StatusValue::newFatal( 'fail-from-pre' ),
+ [],
+ [],
+ [
+ AuthenticationResponse::newFail( $this->message( 'fail-from-pre' ) ),
+ AuthenticationResponse::newFail(
+ $this->message( 'authmanager-authn-not-in-progress' )
+ ),
+ ]
+ ],
+ 'Failure in primary' => [
+ StatusValue::newGood(),
+ $tmp = [
+ AuthenticationResponse::newFail( $this->message( 'fail-from-primary' ) ),
+ ],
+ [],
+ $tmp
+ ],
+ 'All primary abstain' => [
+ StatusValue::newGood(),
+ [
+ AuthenticationResponse::newAbstain(),
+ ],
+ [],
+ [
+ AuthenticationResponse::newFail( $this->message( 'authmanager-authn-no-primary' ) )
+ ]
+ ],
+ 'Primary UI, then redirect, then fail' => [
+ StatusValue::newGood(),
+ $tmp = [
+ AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) ),
+ AuthenticationResponse::newRedirect( [ $req ], '/foo.html', [ 'foo' => 'bar' ] ),
+ AuthenticationResponse::newFail( $this->message( 'fail-in-primary-continue' ) ),
+ ],
+ [],
+ $tmp
+ ],
+ 'Primary redirect, then abstain' => [
+ StatusValue::newGood(),
+ [
+ $tmp = AuthenticationResponse::newRedirect(
+ [ $req ], '/foo.html', [ 'foo' => 'bar' ]
+ ),
+ AuthenticationResponse::newAbstain(),
+ ],
+ [],
+ [
+ $tmp,
+ new \DomainException(
+ 'MockPrimaryAuthenticationProvider::continuePrimaryAuthentication() returned ABSTAIN'
+ )
+ ]
+ ],
+ 'Primary UI, then pass with no local user' => [
+ StatusValue::newGood(),
+ [
+ $tmp = AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) ),
+ AuthenticationResponse::newPass( null ),
+ ],
+ [],
+ [
+ $tmp,
+ $restartResponse,
+ ]
+ ],
+ 'Primary UI, then pass with no local user (link type)' => [
+ StatusValue::newGood(),
+ [
+ $tmp = AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) ),
+ $restartResponse2Pass,
+ ],
+ [],
+ [
+ $tmp,
+ $restartResponse2,
+ ],
+ true
+ ],
+ 'Primary pass with invalid username' => [
+ StatusValue::newGood(),
+ [
+ AuthenticationResponse::newPass( '<>' ),
+ ],
+ [],
+ [
+ new \DomainException( 'MockPrimaryAuthenticationProvider returned an invalid username: <>' ),
+ ]
+ ],
+ 'Secondary fail' => [
+ StatusValue::newGood(),
+ [
+ AuthenticationResponse::newPass( $name ),
+ ],
+ $tmp = [
+ AuthenticationResponse::newFail( $this->message( 'fail-in-secondary' ) ),
+ ],
+ $tmp
+ ],
+ 'Secondary UI, then abstain' => [
+ StatusValue::newGood(),
+ [
+ AuthenticationResponse::newPass( $name ),
+ ],
+ [
+ $tmp = AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) ),
+ AuthenticationResponse::newAbstain()
+ ],
+ [
+ $tmp,
+ AuthenticationResponse::newPass( $name ),
+ ]
+ ],
+ 'Secondary pass' => [
+ StatusValue::newGood(),
+ [
+ AuthenticationResponse::newPass( $name ),
+ ],
+ [
+ AuthenticationResponse::newPass()
+ ],
+ [
+ AuthenticationResponse::newPass( $name ),
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideUserExists
+ * @param bool $primary1Exists
+ * @param bool $primary2Exists
+ * @param bool $expect
+ */
+ public function testUserExists( $primary1Exists, $primary2Exists, $expect ) {
+ $mock1 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock1->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'primary1' ) );
+ $mock1->expects( $this->any() )->method( 'testUserExists' )
+ ->with( $this->equalTo( 'UTSysop' ) )
+ ->will( $this->returnValue( $primary1Exists ) );
+ $mock2 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock2->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'primary2' ) );
+ $mock2->expects( $this->any() )->method( 'testUserExists' )
+ ->with( $this->equalTo( 'UTSysop' ) )
+ ->will( $this->returnValue( $primary2Exists ) );
+ $this->primaryauthMocks = [ $mock1, $mock2 ];
+
+ $this->initializeManager( true );
+ $this->assertSame( $expect, $this->manager->userExists( 'UTSysop' ) );
+ }
+
+ public static function provideUserExists() {
+ return [
+ [ false, false, false ],
+ [ true, false, true ],
+ [ false, true, true ],
+ [ true, true, true ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideAllowsAuthenticationDataChange
+ * @param StatusValue $primaryReturn
+ * @param StatusValue $secondaryReturn
+ * @param Status $expect
+ */
+ public function testAllowsAuthenticationDataChange( $primaryReturn, $secondaryReturn, $expect ) {
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+
+ $mock1 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock1->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( '1' ) );
+ $mock1->expects( $this->any() )->method( 'providerAllowsAuthenticationDataChange' )
+ ->with( $this->equalTo( $req ) )
+ ->will( $this->returnValue( $primaryReturn ) );
+ $mock2 = $this->getMockForAbstractClass( SecondaryAuthenticationProvider::class );
+ $mock2->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( '2' ) );
+ $mock2->expects( $this->any() )->method( 'providerAllowsAuthenticationDataChange' )
+ ->with( $this->equalTo( $req ) )
+ ->will( $this->returnValue( $secondaryReturn ) );
+
+ $this->primaryauthMocks = [ $mock1 ];
+ $this->secondaryauthMocks = [ $mock2 ];
+ $this->initializeManager( true );
+ $this->assertEquals( $expect, $this->manager->allowsAuthenticationDataChange( $req ) );
+ }
+
+ public static function provideAllowsAuthenticationDataChange() {
+ $ignored = \Status::newGood( 'ignored' );
+ $ignored->warning( 'authmanager-change-not-supported' );
+
+ $okFromPrimary = StatusValue::newGood();
+ $okFromPrimary->warning( 'warning-from-primary' );
+ $okFromSecondary = StatusValue::newGood();
+ $okFromSecondary->warning( 'warning-from-secondary' );
+
+ return [
+ [
+ StatusValue::newGood(),
+ StatusValue::newGood(),
+ \Status::newGood(),
+ ],
+ [
+ StatusValue::newGood(),
+ StatusValue::newGood( 'ignore' ),
+ \Status::newGood(),
+ ],
+ [
+ StatusValue::newGood( 'ignored' ),
+ StatusValue::newGood(),
+ \Status::newGood(),
+ ],
+ [
+ StatusValue::newGood( 'ignored' ),
+ StatusValue::newGood( 'ignored' ),
+ $ignored,
+ ],
+ [
+ StatusValue::newFatal( 'fail from primary' ),
+ StatusValue::newGood(),
+ \Status::newFatal( 'fail from primary' ),
+ ],
+ [
+ $okFromPrimary,
+ StatusValue::newGood(),
+ \Status::wrap( $okFromPrimary ),
+ ],
+ [
+ StatusValue::newGood(),
+ StatusValue::newFatal( 'fail from secondary' ),
+ \Status::newFatal( 'fail from secondary' ),
+ ],
+ [
+ StatusValue::newGood(),
+ $okFromSecondary,
+ \Status::wrap( $okFromSecondary ),
+ ],
+ ];
+ }
+
+ public function testChangeAuthenticationData() {
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ $req->username = 'UTSysop';
+
+ $mock1 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock1->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( '1' ) );
+ $mock1->expects( $this->once() )->method( 'providerChangeAuthenticationData' )
+ ->with( $this->equalTo( $req ) );
+ $mock2 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock2->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( '2' ) );
+ $mock2->expects( $this->once() )->method( 'providerChangeAuthenticationData' )
+ ->with( $this->equalTo( $req ) );
+
+ $this->primaryauthMocks = [ $mock1, $mock2 ];
+ $this->initializeManager( true );
+ $this->logger->setCollect( true );
+ $this->manager->changeAuthenticationData( $req );
+ $this->assertSame( [
+ [ LogLevel::INFO, 'Changing authentication data for {user} class {what}' ],
+ ], $this->logger->getBuffer() );
+ }
+
+ public function testCanCreateAccounts() {
+ $types = [
+ PrimaryAuthenticationProvider::TYPE_CREATE => true,
+ PrimaryAuthenticationProvider::TYPE_LINK => true,
+ PrimaryAuthenticationProvider::TYPE_NONE => false,
+ ];
+
+ foreach ( $types as $type => $can ) {
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( $type ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( $type ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+ $this->assertSame( $can, $this->manager->canCreateAccounts(), $type );
+ }
+ }
+
+ public function testCheckAccountCreatePermissions() {
+ global $wgGroupPermissions;
+
+ $this->stashMwGlobals( [ 'wgGroupPermissions' ] );
+
+ $this->initializeManager( true );
+
+ $wgGroupPermissions['*']['createaccount'] = true;
+ $this->assertEquals(
+ \Status::newGood(),
+ $this->manager->checkAccountCreatePermissions( new \User )
+ );
+
+ $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] );
+ $this->assertEquals(
+ \Status::newFatal( 'readonlytext', 'Because' ),
+ $this->manager->checkAccountCreatePermissions( new \User )
+ );
+ $this->setMwGlobals( [ 'wgReadOnly' => false ] );
+
+ $wgGroupPermissions['*']['createaccount'] = false;
+ $status = $this->manager->checkAccountCreatePermissions( new \User );
+ $this->assertFalse( $status->isOK() );
+ $this->assertTrue( $status->hasMessage( 'badaccess-groups' ) );
+ $wgGroupPermissions['*']['createaccount'] = true;
+
+ $user = \User::newFromName( 'UTBlockee' );
+ if ( $user->getID() == 0 ) {
+ $user->addToDatabase();
+ \TestUser::setPasswordForUser( $user, 'UTBlockeePassword' );
+ $user->saveSettings();
+ }
+ $oldBlock = \Block::newFromTarget( 'UTBlockee' );
+ if ( $oldBlock ) {
+ // An old block will prevent our new one from saving.
+ $oldBlock->delete();
+ }
+ $blockOptions = [
+ 'address' => 'UTBlockee',
+ 'user' => $user->getID(),
+ 'reason' => __METHOD__,
+ 'expiry' => time() + 100500,
+ 'createAccount' => true,
+ ];
+ $block = new \Block( $blockOptions );
+ $block->insert();
+ $status = $this->manager->checkAccountCreatePermissions( $user );
+ $this->assertFalse( $status->isOK() );
+ $this->assertTrue( $status->hasMessage( 'cantcreateaccount-text' ) );
+
+ $blockOptions = [
+ 'address' => '127.0.0.0/24',
+ 'reason' => __METHOD__,
+ 'expiry' => time() + 100500,
+ 'createAccount' => true,
+ ];
+ $block = new \Block( $blockOptions );
+ $block->insert();
+ $scopeVariable = new \ScopedCallback( [ $block, 'delete' ] );
+ $status = $this->manager->checkAccountCreatePermissions( new \User );
+ $this->assertFalse( $status->isOK() );
+ $this->assertTrue( $status->hasMessage( 'cantcreateaccount-range-text' ) );
+ \ScopedCallback::consume( $scopeVariable );
+
+ $this->setMwGlobals( [
+ 'wgEnableDnsBlacklist' => true,
+ 'wgDnsBlacklistUrls' => [
+ 'local.wmftest.net', // This will resolve for every subdomain, which works to test "listed?"
+ ],
+ 'wgProxyWhitelist' => [],
+ ] );
+ $status = $this->manager->checkAccountCreatePermissions( new \User );
+ $this->assertFalse( $status->isOK() );
+ $this->assertTrue( $status->hasMessage( 'sorbs_create_account_reason' ) );
+ $this->setMwGlobals( 'wgProxyWhitelist', [ '127.0.0.1' ] );
+ $status = $this->manager->checkAccountCreatePermissions( new \User );
+ $this->assertTrue( $status->isGood() );
+ }
+
+ /**
+ * @param string $uniq
+ * @return string
+ */
+ private static function usernameForCreation( $uniq = '' ) {
+ $i = 0;
+ do {
+ $username = "UTAuthManagerTestAccountCreation" . $uniq . ++$i;
+ } while ( \User::newFromName( $username )->getId() !== 0 );
+ return $username;
+ }
+
+ public function testCanCreateAccount() {
+ $username = self::usernameForCreation();
+ $this->initializeManager();
+
+ $this->assertEquals(
+ \Status::newFatal( 'authmanager-create-disabled' ),
+ $this->manager->canCreateAccount( $username )
+ );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( true ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $this->assertEquals(
+ \Status::newFatal( 'userexists' ),
+ $this->manager->canCreateAccount( $username )
+ );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( false ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $this->assertEquals(
+ \Status::newFatal( 'noname' ),
+ $this->manager->canCreateAccount( $username . '<>' )
+ );
+
+ $this->assertEquals(
+ \Status::newFatal( 'userexists' ),
+ $this->manager->canCreateAccount( 'UTSysop' )
+ );
+
+ $this->assertEquals(
+ \Status::newGood(),
+ $this->manager->canCreateAccount( $username )
+ );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( false ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newFatal( 'fail' ) ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $this->assertEquals(
+ \Status::newFatal( 'fail' ),
+ $this->manager->canCreateAccount( $username )
+ );
+ }
+
+ public function testBeginAccountCreation() {
+ $creator = \User::newFromName( 'UTSysop' );
+ $userReq = new UsernameAuthenticationRequest;
+ $this->logger = new \TestLogger( false, function ( $message, $level ) {
+ return $level === LogLevel::DEBUG ? null : $message;
+ } );
+ $this->initializeManager();
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState', 'test' );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ try {
+ $this->manager->beginAccountCreation(
+ $creator, [], 'http://localhost/'
+ );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \LogicException $ex ) {
+ $this->assertEquals( 'Account creation is not possible', $ex->getMessage() );
+ }
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' )
+ );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( true ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->beginAccountCreation( $creator, [], 'http://localhost/' );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'noname', $ret->message->getKey() );
+
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $userReq->username = self::usernameForCreation();
+ $userReq2 = new UsernameAuthenticationRequest;
+ $userReq2->username = $userReq->username . 'X';
+ $ret = $this->manager->beginAccountCreation(
+ $creator, [ $userReq, $userReq2 ], 'http://localhost/'
+ );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'noname', $ret->message->getKey() );
+
+ $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $userReq->username = self::usernameForCreation();
+ $ret = $this->manager->beginAccountCreation( $creator, [ $userReq ], 'http://localhost/' );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'readonlytext', $ret->message->getKey() );
+ $this->assertSame( [ 'Because' ], $ret->message->getParams() );
+ $this->setMwGlobals( [ 'wgReadOnly' => false ] );
+
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $userReq->username = self::usernameForCreation();
+ $ret = $this->manager->beginAccountCreation( $creator, [ $userReq ], 'http://localhost/' );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'userexists', $ret->message->getKey() );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( false ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newFatal( 'fail' ) ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $userReq->username = self::usernameForCreation();
+ $ret = $this->manager->beginAccountCreation( $creator, [ $userReq ], 'http://localhost/' );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'fail', $ret->message->getKey() );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( false ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $userReq->username = self::usernameForCreation() . '<>';
+ $ret = $this->manager->beginAccountCreation( $creator, [ $userReq ], 'http://localhost/' );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'noname', $ret->message->getKey() );
+
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $userReq->username = $creator->getName();
+ $ret = $this->manager->beginAccountCreation( $creator, [ $userReq ], 'http://localhost/' );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'userexists', $ret->message->getKey() );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( false ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $mock->expects( $this->any() )->method( 'testForAccountCreation' )
+ ->will( $this->returnValue( StatusValue::newFatal( 'fail' ) ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $req = $this->getMockBuilder( UserDataAuthenticationRequest::class )
+ ->setMethods( [ 'populateUser' ] )
+ ->getMock();
+ $req->expects( $this->any() )->method( 'populateUser' )
+ ->willReturn( \StatusValue::newFatal( 'populatefail' ) );
+ $userReq->username = self::usernameForCreation();
+ $ret = $this->manager->beginAccountCreation(
+ $creator, [ $userReq, $req ], 'http://localhost/'
+ );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'populatefail', $ret->message->getKey() );
+
+ $req = new UserDataAuthenticationRequest;
+ $userReq->username = self::usernameForCreation();
+
+ $ret = $this->manager->beginAccountCreation(
+ $creator, [ $userReq, $req ], 'http://localhost/'
+ );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'fail', $ret->message->getKey() );
+
+ $this->manager->beginAccountCreation(
+ \User::newFromName( $userReq->username ), [ $userReq, $req ], 'http://localhost/'
+ );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'fail', $ret->message->getKey() );
+ }
+
+ public function testContinueAccountCreation() {
+ $creator = \User::newFromName( 'UTSysop' );
+ $username = self::usernameForCreation();
+ $this->logger = new \TestLogger( false, function ( $message, $level ) {
+ return $level === LogLevel::DEBUG ? null : $message;
+ } );
+ $this->initializeManager();
+
+ $session = [
+ 'userid' => 0,
+ 'username' => $username,
+ 'creatorid' => 0,
+ 'creatorname' => $username,
+ 'reqs' => [],
+ 'primary' => null,
+ 'primaryResponse' => null,
+ 'secondary' => [],
+ 'ranPreTests' => true,
+ ];
+
+ $this->hook( 'LocalUserCreated', $this->never() );
+ try {
+ $this->manager->continueAccountCreation( [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \LogicException $ex ) {
+ $this->assertEquals( 'Account creation is not possible', $ex->getMessage() );
+ }
+ $this->unhook( 'LocalUserCreated' );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( false ) );
+ $mock->expects( $this->any() )->method( 'beginPrimaryAccountCreation' )->will(
+ $this->returnValue( AuthenticationResponse::newFail( $this->message( 'fail' ) ) )
+ );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState', null );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->continueAccountCreation( [] );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'authmanager-create-not-in-progress', $ret->message->getKey() );
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState',
+ [ 'username' => "$username<>" ] + $session );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->continueAccountCreation( [] );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'noname', $ret->message->getKey() );
+ $this->assertNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' )
+ );
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState', $session );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $cache = \ObjectCache::getLocalClusterInstance();
+ $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $username ) ) );
+ $ret = $this->manager->continueAccountCreation( [] );
+ unset( $lock );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'usernameinprogress', $ret->message->getKey() );
+ // This error shouldn't remove the existing session, because the
+ // raced-with process "owns" it.
+ $this->assertSame(
+ $session, $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' )
+ );
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState',
+ [ 'username' => $creator->getName() ] + $session );
+ $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->continueAccountCreation( [] );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'readonlytext', $ret->message->getKey() );
+ $this->assertSame( [ 'Because' ], $ret->message->getParams() );
+ $this->setMwGlobals( [ 'wgReadOnly' => false ] );
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState',
+ [ 'username' => $creator->getName() ] + $session );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->continueAccountCreation( [] );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'userexists', $ret->message->getKey() );
+ $this->assertNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' )
+ );
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState',
+ [ 'userid' => $creator->getId() ] + $session );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ try {
+ $ret = $this->manager->continueAccountCreation( [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertEquals( "User \"{$username}\" should exist now, but doesn't!", $ex->getMessage() );
+ }
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' )
+ );
+
+ $id = $creator->getId();
+ $name = $creator->getName();
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState',
+ [ 'username' => $name, 'userid' => $id + 1 ] + $session );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ try {
+ $ret = $this->manager->continueAccountCreation( [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertEquals(
+ "User \"{$name}\" exists, but ID $id != " . ( $id + 1 ) . '!', $ex->getMessage()
+ );
+ }
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' )
+ );
+
+ $req = $this->getMockBuilder( UserDataAuthenticationRequest::class )
+ ->setMethods( [ 'populateUser' ] )
+ ->getMock();
+ $req->expects( $this->any() )->method( 'populateUser' )
+ ->willReturn( \StatusValue::newFatal( 'populatefail' ) );
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState',
+ [ 'reqs' => [ $req ] ] + $session );
+ $ret = $this->manager->continueAccountCreation( [] );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'populatefail', $ret->message->getKey() );
+ $this->assertNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' )
+ );
+ }
+
+ /**
+ * @dataProvider provideAccountCreation
+ * @param StatusValue $preTest
+ * @param StatusValue $primaryTest
+ * @param StatusValue $secondaryTest
+ * @param array $primaryResponses
+ * @param array $secondaryResponses
+ * @param array $managerResponses
+ */
+ public function testAccountCreation(
+ StatusValue $preTest, $primaryTest, $secondaryTest,
+ array $primaryResponses, array $secondaryResponses, array $managerResponses
+ ) {
+ $creator = \User::newFromName( 'UTSysop' );
+ $username = self::usernameForCreation();
+
+ $this->initializeManager();
+
+ // Set up lots of mocks...
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ $req->preTest = $preTest;
+ $req->primaryTest = $primaryTest;
+ $req->secondaryTest = $secondaryTest;
+ $req->primary = $primaryResponses;
+ $req->secondary = $secondaryResponses;
+ $mocks = [];
+ foreach ( [ 'pre', 'primary', 'secondary' ] as $key ) {
+ $class = ucfirst( $key ) . 'AuthenticationProvider';
+ $mocks[$key] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key]->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key ) );
+ $mocks[$key]->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $mocks[$key]->expects( $this->any() )->method( 'testForAccountCreation' )
+ ->will( $this->returnCallback(
+ function ( $user, $creatorIn, $reqs )
+ use ( $username, $creator, $req, $key )
+ {
+ $this->assertSame( $username, $user->getName() );
+ $this->assertSame( $creator->getId(), $creatorIn->getId() );
+ $this->assertSame( $creator->getName(), $creatorIn->getName() );
+ $foundReq = false;
+ foreach ( $reqs as $r ) {
+ $this->assertSame( $username, $r->username );
+ $foundReq = $foundReq || get_class( $r ) === get_class( $req );
+ }
+ $this->assertTrue( $foundReq, '$reqs contains $req' );
+ $k = $key . 'Test';
+ return $req->$k;
+ }
+ ) );
+
+ for ( $i = 2; $i <= 3; $i++ ) {
+ $mocks[$key . $i] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key . $i]->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key . $i ) );
+ $mocks[$key . $i]->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $mocks[$key . $i]->expects( $this->atMost( 1 ) )->method( 'testForAccountCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ }
+ }
+
+ $mocks['primary']->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mocks['primary']->expects( $this->any() )->method( 'testUserExists' )
+ ->will( $this->returnValue( false ) );
+ $ct = count( $req->primary );
+ $callback = $this->returnCallback( function ( $user, $creator, $reqs ) use ( $username, $req ) {
+ $this->assertSame( $username, $user->getName() );
+ $this->assertSame( 'UTSysop', $creator->getName() );
+ $foundReq = false;
+ foreach ( $reqs as $r ) {
+ $this->assertSame( $username, $r->username );
+ $foundReq = $foundReq || get_class( $r ) === get_class( $req );
+ }
+ $this->assertTrue( $foundReq, '$reqs contains $req' );
+ return array_shift( $req->primary );
+ } );
+ $mocks['primary']->expects( $this->exactly( min( 1, $ct ) ) )
+ ->method( 'beginPrimaryAccountCreation' )
+ ->will( $callback );
+ $mocks['primary']->expects( $this->exactly( max( 0, $ct - 1 ) ) )
+ ->method( 'continuePrimaryAccountCreation' )
+ ->will( $callback );
+
+ $ct = count( $req->secondary );
+ $callback = $this->returnCallback( function ( $user, $creator, $reqs ) use ( $username, $req ) {
+ $this->assertSame( $username, $user->getName() );
+ $this->assertSame( 'UTSysop', $creator->getName() );
+ $foundReq = false;
+ foreach ( $reqs as $r ) {
+ $this->assertSame( $username, $r->username );
+ $foundReq = $foundReq || get_class( $r ) === get_class( $req );
+ }
+ $this->assertTrue( $foundReq, '$reqs contains $req' );
+ return array_shift( $req->secondary );
+ } );
+ $mocks['secondary']->expects( $this->exactly( min( 1, $ct ) ) )
+ ->method( 'beginSecondaryAccountCreation' )
+ ->will( $callback );
+ $mocks['secondary']->expects( $this->exactly( max( 0, $ct - 1 ) ) )
+ ->method( 'continueSecondaryAccountCreation' )
+ ->will( $callback );
+
+ $abstain = AuthenticationResponse::newAbstain();
+ $mocks['primary2']->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_LINK ) );
+ $mocks['primary2']->expects( $this->any() )->method( 'testUserExists' )
+ ->will( $this->returnValue( false ) );
+ $mocks['primary2']->expects( $this->atMost( 1 ) )->method( 'beginPrimaryAccountCreation' )
+ ->will( $this->returnValue( $abstain ) );
+ $mocks['primary2']->expects( $this->never() )->method( 'continuePrimaryAccountCreation' );
+ $mocks['primary3']->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_NONE ) );
+ $mocks['primary3']->expects( $this->any() )->method( 'testUserExists' )
+ ->will( $this->returnValue( false ) );
+ $mocks['primary3']->expects( $this->never() )->method( 'beginPrimaryAccountCreation' );
+ $mocks['primary3']->expects( $this->never() )->method( 'continuePrimaryAccountCreation' );
+ $mocks['secondary2']->expects( $this->atMost( 1 ) )
+ ->method( 'beginSecondaryAccountCreation' )
+ ->will( $this->returnValue( $abstain ) );
+ $mocks['secondary2']->expects( $this->never() )->method( 'continueSecondaryAccountCreation' );
+ $mocks['secondary3']->expects( $this->atMost( 1 ) )
+ ->method( 'beginSecondaryAccountCreation' )
+ ->will( $this->returnValue( $abstain ) );
+ $mocks['secondary3']->expects( $this->never() )->method( 'continueSecondaryAccountCreation' );
+
+ $this->preauthMocks = [ $mocks['pre'], $mocks['pre2'] ];
+ $this->primaryauthMocks = [ $mocks['primary3'], $mocks['primary'], $mocks['primary2'] ];
+ $this->secondaryauthMocks = [
+ $mocks['secondary3'], $mocks['secondary'], $mocks['secondary2']
+ ];
+
+ $this->logger = new \TestLogger( true, function ( $message, $level ) {
+ return $level === LogLevel::DEBUG ? null : $message;
+ } );
+ $expectLog = [];
+ $this->initializeManager( true );
+
+ $constraint = \PHPUnit_Framework_Assert::logicalOr(
+ $this->equalTo( AuthenticationResponse::PASS ),
+ $this->equalTo( AuthenticationResponse::FAIL )
+ );
+ $providers = array_merge(
+ $this->preauthMocks, $this->primaryauthMocks, $this->secondaryauthMocks
+ );
+ foreach ( $providers as $p ) {
+ $p->postCalled = false;
+ $p->expects( $this->atMost( 1 ) )->method( 'postAccountCreation' )
+ ->willReturnCallback( function ( $user, $creator, $response )
+ use ( $constraint, $p, $username )
+ {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( $username, $user->getName() );
+ $this->assertSame( 'UTSysop', $creator->getName() );
+ $this->assertInstanceOf( AuthenticationResponse::class, $response );
+ $this->assertThat( $response->status, $constraint );
+ $p->postCalled = $response->status;
+ } );
+ }
+
+ // We're testing with $wgNewUserLog = false, so assert that it worked
+ $dbw = wfGetDB( DB_MASTER );
+ $maxLogId = $dbw->selectField( 'logging', 'MAX(log_id)', [ 'log_type' => 'newusers' ] );
+
+ $first = true;
+ $created = false;
+ foreach ( $managerResponses as $i => $response ) {
+ $success = $response instanceof AuthenticationResponse &&
+ $response->status === AuthenticationResponse::PASS;
+ if ( $i === 'created' ) {
+ $created = true;
+ $this->hook( 'LocalUserCreated', $this->once() )
+ ->with(
+ $this->callback( function ( $user ) use ( $username ) {
+ return $user->getName() === $username;
+ } ),
+ $this->equalTo( false )
+ );
+ $expectLog[] = [ LogLevel::INFO, "Creating user {user} during account creation" ];
+ } else {
+ $this->hook( 'LocalUserCreated', $this->never() );
+ }
+
+ $ex = null;
+ try {
+ if ( $first ) {
+ $userReq = new UsernameAuthenticationRequest;
+ $userReq->username = $username;
+ $ret = $this->manager->beginAccountCreation(
+ $creator, [ $userReq, $req ], 'http://localhost/'
+ );
+ } else {
+ $ret = $this->manager->continueAccountCreation( [ $req ] );
+ }
+ if ( $response instanceof \Exception ) {
+ $this->fail( 'Expected exception not thrown', "Response $i" );
+ }
+ } catch ( \Exception $ex ) {
+ if ( !$response instanceof \Exception ) {
+ throw $ex;
+ }
+ $this->assertEquals( $response->getMessage(), $ex->getMessage(), "Response $i, exception" );
+ $this->assertNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' ),
+ "Response $i, exception, session state"
+ );
+ $this->unhook( 'LocalUserCreated' );
+ return;
+ }
+
+ $this->unhook( 'LocalUserCreated' );
+
+ $this->assertSame( 'http://localhost/', $req->returnToUrl );
+
+ if ( $success ) {
+ $this->assertNotNull( $ret->loginRequest, "Response $i, login marker" );
+ $this->assertContains(
+ $ret->loginRequest, $this->managerPriv->createdAccountAuthenticationRequests,
+ "Response $i, login marker"
+ );
+
+ $expectLog[] = [
+ LogLevel::INFO,
+ "MediaWiki\Auth\AuthManager::continueAccountCreation: Account creation succeeded for {user}"
+ ];
+
+ // Set some fields in the expected $response that we couldn't
+ // know in provideAccountCreation().
+ $response->username = $username;
+ $response->loginRequest = $ret->loginRequest;
+ } else {
+ $this->assertNull( $ret->loginRequest, "Response $i, login marker" );
+ $this->assertSame( [], $this->managerPriv->createdAccountAuthenticationRequests,
+ "Response $i, login marker" );
+ }
+ $ret->message = $this->message( $ret->message );
+ $this->assertEquals( $response, $ret, "Response $i, response" );
+ if ( $success || $response->status === AuthenticationResponse::FAIL ) {
+ $this->assertNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' ),
+ "Response $i, session state"
+ );
+ foreach ( $providers as $p ) {
+ $this->assertSame( $response->status, $p->postCalled,
+ "Response $i, post-auth callback called" );
+ }
+ } else {
+ $this->assertNotNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountCreationState' ),
+ "Response $i, session state"
+ );
+ foreach ( $ret->neededRequests as $neededReq ) {
+ $this->assertEquals( AuthManager::ACTION_CREATE, $neededReq->action,
+ "Response $i, neededRequest action" );
+ }
+ $this->assertEquals(
+ $ret->neededRequests,
+ $this->manager->getAuthenticationRequests( AuthManager::ACTION_CREATE_CONTINUE ),
+ "Response $i, continuation check"
+ );
+ foreach ( $providers as $p ) {
+ $this->assertFalse( $p->postCalled, "Response $i, post-auth callback not called" );
+ }
+ }
+
+ if ( $created ) {
+ $this->assertNotEquals( 0, \User::idFromName( $username ) );
+ } else {
+ $this->assertEquals( 0, \User::idFromName( $username ) );
+ }
+
+ $first = false;
+ }
+
+ $this->assertSame( $expectLog, $this->logger->getBuffer() );
+
+ $this->assertSame(
+ $maxLogId,
+ $dbw->selectField( 'logging', 'MAX(log_id)', [ 'log_type' => 'newusers' ] )
+ );
+ }
+
+ public function provideAccountCreation() {
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ $good = StatusValue::newGood();
+
+ return [
+ 'Pre-creation test fail in pre' => [
+ StatusValue::newFatal( 'fail-from-pre' ), $good, $good,
+ [],
+ [],
+ [
+ AuthenticationResponse::newFail( $this->message( 'fail-from-pre' ) ),
+ ]
+ ],
+ 'Pre-creation test fail in primary' => [
+ $good, StatusValue::newFatal( 'fail-from-primary' ), $good,
+ [],
+ [],
+ [
+ AuthenticationResponse::newFail( $this->message( 'fail-from-primary' ) ),
+ ]
+ ],
+ 'Pre-creation test fail in secondary' => [
+ $good, $good, StatusValue::newFatal( 'fail-from-secondary' ),
+ [],
+ [],
+ [
+ AuthenticationResponse::newFail( $this->message( 'fail-from-secondary' ) ),
+ ]
+ ],
+ 'Failure in primary' => [
+ $good, $good, $good,
+ $tmp = [
+ AuthenticationResponse::newFail( $this->message( 'fail-from-primary' ) ),
+ ],
+ [],
+ $tmp
+ ],
+ 'All primary abstain' => [
+ $good, $good, $good,
+ [
+ AuthenticationResponse::newAbstain(),
+ ],
+ [],
+ [
+ AuthenticationResponse::newFail( $this->message( 'authmanager-create-no-primary' ) )
+ ]
+ ],
+ 'Primary UI, then redirect, then fail' => [
+ $good, $good, $good,
+ $tmp = [
+ AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) ),
+ AuthenticationResponse::newRedirect( [ $req ], '/foo.html', [ 'foo' => 'bar' ] ),
+ AuthenticationResponse::newFail( $this->message( 'fail-in-primary-continue' ) ),
+ ],
+ [],
+ $tmp
+ ],
+ 'Primary redirect, then abstain' => [
+ $good, $good, $good,
+ [
+ $tmp = AuthenticationResponse::newRedirect(
+ [ $req ], '/foo.html', [ 'foo' => 'bar' ]
+ ),
+ AuthenticationResponse::newAbstain(),
+ ],
+ [],
+ [
+ $tmp,
+ new \DomainException(
+ 'MockPrimaryAuthenticationProvider::continuePrimaryAccountCreation() returned ABSTAIN'
+ )
+ ]
+ ],
+ 'Primary UI, then pass; secondary abstain' => [
+ $good, $good, $good,
+ [
+ $tmp1 = AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) ),
+ AuthenticationResponse::newPass(),
+ ],
+ [
+ AuthenticationResponse::newAbstain(),
+ ],
+ [
+ $tmp1,
+ 'created' => AuthenticationResponse::newPass( '' ),
+ ]
+ ],
+ 'Primary pass; secondary UI then pass' => [
+ $good, $good, $good,
+ [
+ AuthenticationResponse::newPass( '' ),
+ ],
+ [
+ $tmp1 = AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) ),
+ AuthenticationResponse::newPass( '' ),
+ ],
+ [
+ 'created' => $tmp1,
+ AuthenticationResponse::newPass( '' ),
+ ]
+ ],
+ 'Primary pass; secondary fail' => [
+ $good, $good, $good,
+ [
+ AuthenticationResponse::newPass(),
+ ],
+ [
+ AuthenticationResponse::newFail( $this->message( '...' ) ),
+ ],
+ [
+ 'created' => new \DomainException(
+ 'MockSecondaryAuthenticationProvider::beginSecondaryAccountCreation() returned FAIL. ' .
+ 'Secondary providers are not allowed to fail account creation, ' .
+ 'that should have been done via testForAccountCreation().'
+ )
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideAccountCreationLogging
+ * @param bool $isAnon
+ * @param string|null $logSubtype
+ */
+ public function testAccountCreationLogging( $isAnon, $logSubtype ) {
+ $creator = $isAnon ? new \User : \User::newFromName( 'UTSysop' );
+ $username = self::usernameForCreation();
+
+ $this->initializeManager();
+
+ // Set up lots of mocks...
+ $mock = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\PrimaryAuthenticationProvider", []
+ );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'primary' ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $mock->expects( $this->any() )->method( 'testForAccountCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )
+ ->will( $this->returnValue( false ) );
+ $mock->expects( $this->any() )->method( 'beginPrimaryAccountCreation' )
+ ->will( $this->returnValue( AuthenticationResponse::newPass( $username ) ) );
+ $mock->expects( $this->any() )->method( 'finishAccountCreation' )
+ ->will( $this->returnValue( $logSubtype ) );
+
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+ $this->logger->setCollect( true );
+
+ $this->config->set( 'NewUserLog', true );
+
+ $dbw = wfGetDB( DB_MASTER );
+ $maxLogId = $dbw->selectField( 'logging', 'MAX(log_id)', [ 'log_type' => 'newusers' ] );
+
+ $userReq = new UsernameAuthenticationRequest;
+ $userReq->username = $username;
+ $reasonReq = new CreationReasonAuthenticationRequest;
+ $reasonReq->reason = $this->toString();
+ $ret = $this->manager->beginAccountCreation(
+ $creator, [ $userReq, $reasonReq ], 'http://localhost/'
+ );
+
+ $this->assertSame( AuthenticationResponse::PASS, $ret->status );
+
+ $user = \User::newFromName( $username );
+ $this->assertNotEquals( 0, $user->getId(), 'sanity check' );
+ $this->assertNotEquals( $creator->getId(), $user->getId(), 'sanity check' );
+
+ $data = \DatabaseLogEntry::getSelectQueryData();
+ $rows = iterator_to_array( $dbw->select(
+ $data['tables'],
+ $data['fields'],
+ [
+ 'log_id > ' . (int)$maxLogId,
+ 'log_type' => 'newusers'
+ ] + $data['conds'],
+ __METHOD__,
+ $data['options'],
+ $data['join_conds']
+ ) );
+ $this->assertCount( 1, $rows );
+ $entry = \DatabaseLogEntry::newFromRow( reset( $rows ) );
+
+ $this->assertSame( $logSubtype ?: ( $isAnon ? 'create' : 'create2' ), $entry->getSubtype() );
+ $this->assertSame(
+ $isAnon ? $user->getId() : $creator->getId(),
+ $entry->getPerformer()->getId()
+ );
+ $this->assertSame(
+ $isAnon ? $user->getName() : $creator->getName(),
+ $entry->getPerformer()->getName()
+ );
+ $this->assertSame( $user->getUserPage()->getFullText(), $entry->getTarget()->getFullText() );
+ $this->assertSame( [ '4::userid' => $user->getId() ], $entry->getParameters() );
+ $this->assertSame( $this->toString(), $entry->getComment() );
+ }
+
+ public static function provideAccountCreationLogging() {
+ return [
+ [ true, null ],
+ [ true, 'foobar' ],
+ [ false, null ],
+ [ false, 'byemail' ],
+ ];
+ }
+
+ public function testAutoAccountCreation() {
+ global $wgGroupPermissions, $wgHooks;
+
+ // PHPUnit seems to have a bug where it will call the ->with()
+ // callbacks for our hooks again after the test is run (WTF?), which
+ // breaks here because $username no longer matches $user by the end of
+ // the testing.
+ $workaroundPHPUnitBug = false;
+
+ $username = self::usernameForCreation();
+ $this->initializeManager();
+
+ $this->stashMwGlobals( [ 'wgGroupPermissions' ] );
+ $wgGroupPermissions['*']['createaccount'] = true;
+ $wgGroupPermissions['*']['autocreateaccount'] = false;
+
+ \ObjectCache::$instances[__METHOD__] = new \HashBagOStuff();
+ $this->setMwGlobals( [ 'wgMainCacheType' => __METHOD__ ] );
+
+ // Set up lots of mocks...
+ $mocks = [];
+ foreach ( [ 'pre', 'primary', 'secondary' ] as $key ) {
+ $class = ucfirst( $key ) . 'AuthenticationProvider';
+ $mocks[$key] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key]->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key ) );
+ }
+
+ $good = StatusValue::newGood();
+ $callback = $this->callback( function ( $user ) use ( &$username, &$workaroundPHPUnitBug ) {
+ return $workaroundPHPUnitBug || $user->getName() === $username;
+ } );
+
+ $mocks['pre']->expects( $this->exactly( 12 ) )->method( 'testUserForCreation' )
+ ->with( $callback, $this->identicalTo( AuthManager::AUTOCREATE_SOURCE_SESSION ) )
+ ->will( $this->onConsecutiveCalls(
+ StatusValue::newFatal( 'ok' ), StatusValue::newFatal( 'ok' ), // For testing permissions
+ StatusValue::newFatal( 'fail-in-pre' ), $good, $good,
+ $good, // backoff test
+ $good, // addToDatabase fails test
+ $good, // addToDatabase throws test
+ $good, // addToDatabase exists test
+ $good, $good, $good // success
+ ) );
+
+ $mocks['primary']->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mocks['primary']->expects( $this->any() )->method( 'testUserExists' )
+ ->will( $this->returnValue( true ) );
+ $mocks['primary']->expects( $this->exactly( 9 ) )->method( 'testUserForCreation' )
+ ->with( $callback, $this->identicalTo( AuthManager::AUTOCREATE_SOURCE_SESSION ) )
+ ->will( $this->onConsecutiveCalls(
+ StatusValue::newFatal( 'fail-in-primary' ), $good,
+ $good, // backoff test
+ $good, // addToDatabase fails test
+ $good, // addToDatabase throws test
+ $good, // addToDatabase exists test
+ $good, $good, $good
+ ) );
+ $mocks['primary']->expects( $this->exactly( 3 ) )->method( 'autoCreatedAccount' )
+ ->with( $callback, $this->identicalTo( AuthManager::AUTOCREATE_SOURCE_SESSION ) );
+
+ $mocks['secondary']->expects( $this->exactly( 8 ) )->method( 'testUserForCreation' )
+ ->with( $callback, $this->identicalTo( AuthManager::AUTOCREATE_SOURCE_SESSION ) )
+ ->will( $this->onConsecutiveCalls(
+ StatusValue::newFatal( 'fail-in-secondary' ),
+ $good, // backoff test
+ $good, // addToDatabase fails test
+ $good, // addToDatabase throws test
+ $good, // addToDatabase exists test
+ $good, $good, $good
+ ) );
+ $mocks['secondary']->expects( $this->exactly( 3 ) )->method( 'autoCreatedAccount' )
+ ->with( $callback, $this->identicalTo( AuthManager::AUTOCREATE_SOURCE_SESSION ) );
+
+ $this->preauthMocks = [ $mocks['pre'] ];
+ $this->primaryauthMocks = [ $mocks['primary'] ];
+ $this->secondaryauthMocks = [ $mocks['secondary'] ];
+ $this->initializeManager( true );
+ $session = $this->request->getSession();
+
+ $logger = new \TestLogger( true, function ( $m ) {
+ $m = str_replace( 'MediaWiki\\Auth\\AuthManager::autoCreateUser: ', '', $m );
+ return $m;
+ } );
+ $this->manager->setLogger( $logger );
+
+ try {
+ $user = \User::newFromName( 'UTSysop' );
+ $this->manager->autoCreateUser( $user, 'InvalidSource', true );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \InvalidArgumentException $ex ) {
+ $this->assertSame( 'Unknown auto-creation source: InvalidSource', $ex->getMessage() );
+ }
+
+ // First, check an existing user
+ $session->clear();
+ $user = \User::newFromName( 'UTSysop' );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $expect = \Status::newGood();
+ $expect->warning( 'userexists' );
+ $this->assertEquals( $expect, $ret );
+ $this->assertNotEquals( 0, $user->getId() );
+ $this->assertSame( 'UTSysop', $user->getName() );
+ $this->assertEquals( $user->getId(), $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, '{username} already exists locally' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+
+ $session->clear();
+ $user = \User::newFromName( 'UTSysop' );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, false );
+ $this->unhook( 'LocalUserCreated' );
+ $expect = \Status::newGood();
+ $expect->warning( 'userexists' );
+ $this->assertEquals( $expect, $ret );
+ $this->assertNotEquals( 0, $user->getId() );
+ $this->assertSame( 'UTSysop', $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, '{username} already exists locally' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+
+ // Wiki is read-only
+ $session->clear();
+ $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] );
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'readonlytext', 'Because' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, 'denied by wfReadOnly(): {reason}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->setMwGlobals( [ 'wgReadOnly' => false ] );
+
+ // Session blacklisted
+ $session->clear();
+ $session->set( 'AuthManager::AutoCreateBlacklist', 'test' );
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'test' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, 'blacklisted in session {sessionid}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+
+ $session->clear();
+ $session->set( 'AuthManager::AutoCreateBlacklist', StatusValue::newFatal( 'test2' ) );
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'test2' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, 'blacklisted in session {sessionid}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+
+ // Uncreatable name
+ $session->clear();
+ $user = \User::newFromName( $username . '@' );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'noname' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username . '@', $user->getId() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, 'name "{username}" is not creatable' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertSame( 'noname', $session->get( 'AuthManager::AutoCreateBlacklist' ) );
+
+ // IP unable to create accounts
+ $wgGroupPermissions['*']['createaccount'] = false;
+ $wgGroupPermissions['*']['autocreateaccount'] = false;
+ $session->clear();
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'authmanager-autocreate-noperm' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, 'IP lacks the ability to create or autocreate accounts' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertSame(
+ 'authmanager-autocreate-noperm', $session->get( 'AuthManager::AutoCreateBlacklist' )
+ );
+
+ // Test that both permutations of permissions are allowed
+ // (this hits the two "ok" entries in $mocks['pre'])
+ $wgGroupPermissions['*']['createaccount'] = false;
+ $wgGroupPermissions['*']['autocreateaccount'] = true;
+ $session->clear();
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'ok' ), $ret );
+
+ $wgGroupPermissions['*']['createaccount'] = true;
+ $wgGroupPermissions['*']['autocreateaccount'] = false;
+ $session->clear();
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'ok' ), $ret );
+ $logger->clearBuffer();
+
+ // Test lock fail
+ $session->clear();
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $cache = \ObjectCache::getLocalClusterInstance();
+ $lock = $cache->getScopedLock( $cache->makeGlobalKey( 'account', md5( $username ) ) );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ unset( $lock );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'usernameinprogress' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, 'Could not acquire account creation lock' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+
+ // Test pre-authentication provider fail
+ $session->clear();
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'fail-in-pre' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, 'Provider denied creation of {username}: {reason}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertEquals(
+ StatusValue::newFatal( 'fail-in-pre' ), $session->get( 'AuthManager::AutoCreateBlacklist' )
+ );
+
+ $session->clear();
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'fail-in-primary' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, 'Provider denied creation of {username}: {reason}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertEquals(
+ StatusValue::newFatal( 'fail-in-primary' ), $session->get( 'AuthManager::AutoCreateBlacklist' )
+ );
+
+ $session->clear();
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'fail-in-secondary' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, 'Provider denied creation of {username}: {reason}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertEquals(
+ StatusValue::newFatal( 'fail-in-secondary' ), $session->get( 'AuthManager::AutoCreateBlacklist' )
+ );
+
+ // Test backoff
+ $cache = \ObjectCache::getLocalClusterInstance();
+ $backoffKey = wfMemcKey( 'AuthManager', 'autocreate-failed', md5( $username ) );
+ $cache->set( $backoffKey, true );
+ $session->clear();
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newFatal( 'authmanager-autocreate-exception' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::DEBUG, '{username} denied by prior creation attempt failures' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertSame( null, $session->get( 'AuthManager::AutoCreateBlacklist' ) );
+ $cache->delete( $backoffKey );
+
+ // Test addToDatabase fails
+ $session->clear();
+ $user = $this->getMock( 'User', [ 'addToDatabase' ] );
+ $user->expects( $this->once() )->method( 'addToDatabase' )
+ ->will( $this->returnValue( \Status::newFatal( 'because' ) ) );
+ $user->setName( $username );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->assertEquals( \Status::newFatal( 'because' ), $ret );
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertNotEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::INFO, 'creating new user ({username}) - from: {from}' ],
+ [ LogLevel::ERROR, '{username} failed with message {message}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertSame( null, $session->get( 'AuthManager::AutoCreateBlacklist' ) );
+
+ // Test addToDatabase throws an exception
+ $cache = \ObjectCache::getLocalClusterInstance();
+ $backoffKey = wfMemcKey( 'AuthManager', 'autocreate-failed', md5( $username ) );
+ $this->assertFalse( $cache->get( $backoffKey ), 'sanity check' );
+ $session->clear();
+ $user = $this->getMock( 'User', [ 'addToDatabase' ] );
+ $user->expects( $this->once() )->method( 'addToDatabase' )
+ ->will( $this->throwException( new \Exception( 'Excepted' ) ) );
+ $user->setName( $username );
+ try {
+ $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \Exception $ex ) {
+ $this->assertSame( 'Excepted', $ex->getMessage() );
+ }
+ $this->assertEquals( 0, $user->getId() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::INFO, 'creating new user ({username}) - from: {from}' ],
+ [ LogLevel::ERROR, '{username} failed with exception {exception}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertSame( null, $session->get( 'AuthManager::AutoCreateBlacklist' ) );
+ $this->assertNotEquals( false, $cache->get( $backoffKey ) );
+ $cache->delete( $backoffKey );
+
+ // Test addToDatabase fails because the user already exists.
+ $session->clear();
+ $user = $this->getMock( 'User', [ 'addToDatabase' ] );
+ $user->expects( $this->once() )->method( 'addToDatabase' )
+ ->will( $this->returnCallback( function () use ( $username ) {
+ $status = \User::newFromName( $username )->addToDatabase();
+ $this->assertTrue( $status->isOK(), 'sanity check' );
+ return \Status::newFatal( 'userexists' );
+ } ) );
+ $user->setName( $username );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $expect = \Status::newGood();
+ $expect->warning( 'userexists' );
+ $this->assertEquals( $expect, $ret );
+ $this->assertNotEquals( 0, $user->getId() );
+ $this->assertEquals( $username, $user->getName() );
+ $this->assertEquals( $user->getId(), $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::INFO, 'creating new user ({username}) - from: {from}' ],
+ [ LogLevel::INFO, '{username} already exists locally (race)' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertSame( null, $session->get( 'AuthManager::AutoCreateBlacklist' ) );
+
+ // Success!
+ $session->clear();
+ $username = self::usernameForCreation();
+ $user = \User::newFromName( $username );
+ $this->hook( 'AuthPluginAutoCreate', $this->once() )
+ ->with( $callback );
+ $this->hideDeprecated( 'AuthPluginAutoCreate hook (used in ' .
+ get_class( $wgHooks['AuthPluginAutoCreate'][0] ) . '::onAuthPluginAutoCreate)' );
+ $this->hook( 'LocalUserCreated', $this->once() )
+ ->with( $callback, $this->equalTo( true ) );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
+ $this->unhook( 'LocalUserCreated' );
+ $this->unhook( 'AuthPluginAutoCreate' );
+ $this->assertEquals( \Status::newGood(), $ret );
+ $this->assertNotEquals( 0, $user->getId() );
+ $this->assertEquals( $username, $user->getName() );
+ $this->assertEquals( $user->getId(), $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::INFO, 'creating new user ({username}) - from: {from}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+
+ $dbw = wfGetDB( DB_MASTER );
+ $maxLogId = $dbw->selectField( 'logging', 'MAX(log_id)', [ 'log_type' => 'newusers' ] );
+ $session->clear();
+ $username = self::usernameForCreation();
+ $user = \User::newFromName( $username );
+ $this->hook( 'LocalUserCreated', $this->once() )
+ ->with( $callback, $this->equalTo( true ) );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, false );
+ $this->unhook( 'LocalUserCreated' );
+ $this->assertEquals( \Status::newGood(), $ret );
+ $this->assertNotEquals( 0, $user->getId() );
+ $this->assertEquals( $username, $user->getName() );
+ $this->assertEquals( 0, $session->getUser()->getId() );
+ $this->assertSame( [
+ [ LogLevel::INFO, 'creating new user ({username}) - from: {from}' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
+ $this->assertSame(
+ $maxLogId,
+ $dbw->selectField( 'logging', 'MAX(log_id)', [ 'log_type' => 'newusers' ] )
+ );
+
+ $this->config->set( 'NewUserLog', true );
+ $session->clear();
+ $username = self::usernameForCreation();
+ $user = \User::newFromName( $username );
+ $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, false );
+ $this->assertEquals( \Status::newGood(), $ret );
+ $logger->clearBuffer();
+
+ $data = \DatabaseLogEntry::getSelectQueryData();
+ $rows = iterator_to_array( $dbw->select(
+ $data['tables'],
+ $data['fields'],
+ [
+ 'log_id > ' . (int)$maxLogId,
+ 'log_type' => 'newusers'
+ ] + $data['conds'],
+ __METHOD__,
+ $data['options'],
+ $data['join_conds']
+ ) );
+ $this->assertCount( 1, $rows );
+ $entry = \DatabaseLogEntry::newFromRow( reset( $rows ) );
+
+ $this->assertSame( 'autocreate', $entry->getSubtype() );
+ $this->assertSame( $user->getId(), $entry->getPerformer()->getId() );
+ $this->assertSame( $user->getName(), $entry->getPerformer()->getName() );
+ $this->assertSame( $user->getUserPage()->getFullText(), $entry->getTarget()->getFullText() );
+ $this->assertSame( [ '4::userid' => $user->getId() ], $entry->getParameters() );
+
+ $workaroundPHPUnitBug = true;
+ }
+
+ /**
+ * @dataProvider provideGetAuthenticationRequests
+ * @param string $action
+ * @param array $expect
+ * @param array $state
+ */
+ public function testGetAuthenticationRequests( $action, $expect, $state = [] ) {
+ $makeReq = function ( $key ) use ( $action ) {
+ $req = $this->getMock( AuthenticationRequest::class );
+ $req->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key ) );
+ $req->action = $action === AuthManager::ACTION_UNLINK ? AuthManager::ACTION_REMOVE : $action;
+ $req->key = $key;
+ return $req;
+ };
+ $cmpReqs = function ( $a, $b ) {
+ $ret = strcmp( get_class( $a ), get_class( $b ) );
+ if ( !$ret ) {
+ $ret = strcmp( $a->key, $b->key );
+ }
+ return $ret;
+ };
+
+ $good = StatusValue::newGood();
+
+ $mocks = [];
+ foreach ( [ 'pre', 'primary', 'secondary' ] as $key ) {
+ $class = ucfirst( $key ) . 'AuthenticationProvider';
+ $mocks[$key] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key]->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key ) );
+ $mocks[$key]->expects( $this->any() )->method( 'getAuthenticationRequests' )
+ ->will( $this->returnCallback( function ( $action ) use ( $key, $makeReq ) {
+ return [ $makeReq( "$key-$action" ), $makeReq( 'generic' ) ];
+ } ) );
+ $mocks[$key]->expects( $this->any() )->method( 'providerAllowsAuthenticationDataChange' )
+ ->will( $this->returnValue( $good ) );
+ }
+
+ $primaries = [];
+ foreach ( [
+ PrimaryAuthenticationProvider::TYPE_NONE,
+ PrimaryAuthenticationProvider::TYPE_CREATE,
+ PrimaryAuthenticationProvider::TYPE_LINK
+ ] as $type ) {
+ $class = 'PrimaryAuthenticationProvider';
+ $mocks["primary-$type"] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks["primary-$type"]->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( "primary-$type" ) );
+ $mocks["primary-$type"]->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( $type ) );
+ $mocks["primary-$type"]->expects( $this->any() )->method( 'getAuthenticationRequests' )
+ ->will( $this->returnCallback( function ( $action ) use ( $type, $makeReq ) {
+ return [ $makeReq( "primary-$type-$action" ), $makeReq( 'generic' ) ];
+ } ) );
+ $mocks["primary-$type"]->expects( $this->any() )
+ ->method( 'providerAllowsAuthenticationDataChange' )
+ ->will( $this->returnValue( $good ) );
+ $this->primaryauthMocks[] = $mocks["primary-$type"];
+ }
+
+ $mocks['primary2'] = $this->getMockForAbstractClass(
+ PrimaryAuthenticationProvider::class, [], "MockPrimaryAuthenticationProvider"
+ );
+ $mocks['primary2']->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'primary2' ) );
+ $mocks['primary2']->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_LINK ) );
+ $mocks['primary2']->expects( $this->any() )->method( 'getAuthenticationRequests' )
+ ->will( $this->returnValue( [] ) );
+ $mocks['primary2']->expects( $this->any() )
+ ->method( 'providerAllowsAuthenticationDataChange' )
+ ->will( $this->returnCallback( function ( $req ) use ( $good ) {
+ return $req->key === 'generic' ? StatusValue::newFatal( 'no' ) : $good;
+ } ) );
+ $this->primaryauthMocks[] = $mocks['primary2'];
+
+ $this->preauthMocks = [ $mocks['pre'] ];
+ $this->secondaryauthMocks = [ $mocks['secondary'] ];
+ $this->initializeManager( true );
+
+ if ( $state ) {
+ if ( isset( $state['continueRequests'] ) ) {
+ $state['continueRequests'] = array_map( $makeReq, $state['continueRequests'] );
+ }
+ if ( $action === AuthManager::ACTION_LOGIN_CONTINUE ) {
+ $this->request->getSession()->setSecret( 'AuthManager::authnState', $state );
+ } elseif ( $action === AuthManager::ACTION_CREATE_CONTINUE ) {
+ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState', $state );
+ } elseif ( $action === AuthManager::ACTION_LINK_CONTINUE ) {
+ $this->request->getSession()->setSecret( 'AuthManager::accountLinkState', $state );
+ }
+ }
+
+ $expectReqs = array_map( $makeReq, $expect );
+ if ( $action === AuthManager::ACTION_LOGIN ) {
+ $req = new RememberMeAuthenticationRequest;
+ $req->action = $action;
+ $req->required = AuthenticationRequest::REQUIRED;
+ $expectReqs[] = $req;
+ } elseif ( $action === AuthManager::ACTION_CREATE ) {
+ $req = new UsernameAuthenticationRequest;
+ $req->action = $action;
+ $expectReqs[] = $req;
+ $req = new UserDataAuthenticationRequest;
+ $req->action = $action;
+ $req->required = AuthenticationRequest::REQUIRED;
+ $expectReqs[] = $req;
+ }
+ usort( $expectReqs, $cmpReqs );
+
+ $actual = $this->manager->getAuthenticationRequests( $action );
+ foreach ( $actual as $req ) {
+ // Don't test this here.
+ $req->required = AuthenticationRequest::REQUIRED;
+ }
+ usort( $actual, $cmpReqs );
+
+ $this->assertEquals( $expectReqs, $actual );
+
+ // Test CreationReasonAuthenticationRequest gets returned
+ if ( $action === AuthManager::ACTION_CREATE ) {
+ $req = new CreationReasonAuthenticationRequest;
+ $req->action = $action;
+ $req->required = AuthenticationRequest::REQUIRED;
+ $expectReqs[] = $req;
+ usort( $expectReqs, $cmpReqs );
+
+ $actual = $this->manager->getAuthenticationRequests( $action, \User::newFromName( 'UTSysop' ) );
+ foreach ( $actual as $req ) {
+ // Don't test this here.
+ $req->required = AuthenticationRequest::REQUIRED;
+ }
+ usort( $actual, $cmpReqs );
+
+ $this->assertEquals( $expectReqs, $actual );
+ }
+ }
+
+ public static function provideGetAuthenticationRequests() {
+ return [
+ [
+ AuthManager::ACTION_LOGIN,
+ [ 'pre-login', 'primary-none-login', 'primary-create-login',
+ 'primary-link-login', 'secondary-login', 'generic' ],
+ ],
+ [
+ AuthManager::ACTION_CREATE,
+ [ 'pre-create', 'primary-none-create', 'primary-create-create',
+ 'primary-link-create', 'secondary-create', 'generic' ],
+ ],
+ [
+ AuthManager::ACTION_LINK,
+ [ 'primary-link-link', 'generic' ],
+ ],
+ [
+ AuthManager::ACTION_CHANGE,
+ [ 'primary-none-change', 'primary-create-change', 'primary-link-change',
+ 'secondary-change' ],
+ ],
+ [
+ AuthManager::ACTION_REMOVE,
+ [ 'primary-none-remove', 'primary-create-remove', 'primary-link-remove',
+ 'secondary-remove' ],
+ ],
+ [
+ AuthManager::ACTION_UNLINK,
+ [ 'primary-link-remove' ],
+ ],
+ [
+ AuthManager::ACTION_LOGIN_CONTINUE,
+ [],
+ ],
+ [
+ AuthManager::ACTION_LOGIN_CONTINUE,
+ $reqs = [ 'continue-login', 'foo', 'bar' ],
+ [
+ 'continueRequests' => $reqs,
+ ],
+ ],
+ [
+ AuthManager::ACTION_CREATE_CONTINUE,
+ [],
+ ],
+ [
+ AuthManager::ACTION_CREATE_CONTINUE,
+ $reqs = [ 'continue-create', 'foo', 'bar' ],
+ [
+ 'continueRequests' => $reqs,
+ ],
+ ],
+ [
+ AuthManager::ACTION_LINK_CONTINUE,
+ [],
+ ],
+ [
+ AuthManager::ACTION_LINK_CONTINUE,
+ $reqs = [ 'continue-link', 'foo', 'bar' ],
+ [
+ 'continueRequests' => $reqs,
+ ],
+ ],
+ ];
+ }
+
+ public function testGetAuthenticationRequestsRequired() {
+ $makeReq = function ( $key, $required ) {
+ $req = $this->getMock( AuthenticationRequest::class );
+ $req->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key ) );
+ $req->action = AuthManager::ACTION_LOGIN;
+ $req->key = $key;
+ $req->required = $required;
+ return $req;
+ };
+ $cmpReqs = function ( $a, $b ) {
+ $ret = strcmp( get_class( $a ), get_class( $b ) );
+ if ( !$ret ) {
+ $ret = strcmp( $a->key, $b->key );
+ }
+ return $ret;
+ };
+
+ $good = StatusValue::newGood();
+
+ $primary1 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $primary1->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'primary1' ) );
+ $primary1->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $primary1->expects( $this->any() )->method( 'getAuthenticationRequests' )
+ ->will( $this->returnCallback( function ( $action ) use ( $makeReq ) {
+ return [
+ $makeReq( "primary-shared", AuthenticationRequest::REQUIRED ),
+ $makeReq( "required", AuthenticationRequest::REQUIRED ),
+ $makeReq( "optional", AuthenticationRequest::OPTIONAL ),
+ $makeReq( "foo", AuthenticationRequest::REQUIRED ),
+ $makeReq( "bar", AuthenticationRequest::REQUIRED ),
+ $makeReq( "baz", AuthenticationRequest::OPTIONAL ),
+ ];
+ } ) );
+
+ $primary2 = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $primary2->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'primary2' ) );
+ $primary2->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $primary2->expects( $this->any() )->method( 'getAuthenticationRequests' )
+ ->will( $this->returnCallback( function ( $action ) use ( $makeReq ) {
+ return [
+ $makeReq( "primary-shared", AuthenticationRequest::REQUIRED ),
+ $makeReq( "required2", AuthenticationRequest::REQUIRED ),
+ $makeReq( "optional2", AuthenticationRequest::OPTIONAL ),
+ ];
+ } ) );
+
+ $secondary = $this->getMockForAbstractClass( SecondaryAuthenticationProvider::class );
+ $secondary->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'secondary' ) );
+ $secondary->expects( $this->any() )->method( 'getAuthenticationRequests' )
+ ->will( $this->returnCallback( function ( $action ) use ( $makeReq ) {
+ return [
+ $makeReq( "foo", AuthenticationRequest::OPTIONAL ),
+ $makeReq( "bar", AuthenticationRequest::REQUIRED ),
+ $makeReq( "baz", AuthenticationRequest::REQUIRED ),
+ ];
+ } ) );
+
+ $rememberReq = new RememberMeAuthenticationRequest;
+ $rememberReq->action = AuthManager::ACTION_LOGIN;
+
+ $this->primaryauthMocks = [ $primary1, $primary2 ];
+ $this->secondaryauthMocks = [ $secondary ];
+ $this->initializeManager( true );
+
+ $actual = $this->manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN );
+ $expected = [
+ $rememberReq,
+ $makeReq( "primary-shared", AuthenticationRequest::REQUIRED ),
+ $makeReq( "required", AuthenticationRequest::PRIMARY_REQUIRED ),
+ $makeReq( "required2", AuthenticationRequest::PRIMARY_REQUIRED ),
+ $makeReq( "optional", AuthenticationRequest::OPTIONAL ),
+ $makeReq( "optional2", AuthenticationRequest::OPTIONAL ),
+ $makeReq( "foo", AuthenticationRequest::PRIMARY_REQUIRED ),
+ $makeReq( "bar", AuthenticationRequest::REQUIRED ),
+ $makeReq( "baz", AuthenticationRequest::REQUIRED ),
+ ];
+ usort( $actual, $cmpReqs );
+ usort( $expected, $cmpReqs );
+ $this->assertEquals( $expected, $actual );
+
+ $this->primaryauthMocks = [ $primary1 ];
+ $this->secondaryauthMocks = [ $secondary ];
+ $this->initializeManager( true );
+
+ $actual = $this->manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN );
+ $expected = [
+ $rememberReq,
+ $makeReq( "primary-shared", AuthenticationRequest::REQUIRED ),
+ $makeReq( "required", AuthenticationRequest::REQUIRED ),
+ $makeReq( "optional", AuthenticationRequest::OPTIONAL ),
+ $makeReq( "foo", AuthenticationRequest::REQUIRED ),
+ $makeReq( "bar", AuthenticationRequest::REQUIRED ),
+ $makeReq( "baz", AuthenticationRequest::REQUIRED ),
+ ];
+ usort( $actual, $cmpReqs );
+ usort( $expected, $cmpReqs );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function testAllowsPropertyChange() {
+ $mocks = [];
+ foreach ( [ 'primary', 'secondary' ] as $key ) {
+ $class = ucfirst( $key ) . 'AuthenticationProvider';
+ $mocks[$key] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key]->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key ) );
+ $mocks[$key]->expects( $this->any() )->method( 'providerAllowsPropertyChange' )
+ ->will( $this->returnCallback( function ( $prop ) use ( $key ) {
+ return $prop !== $key;
+ } ) );
+ }
+
+ $this->primaryauthMocks = [ $mocks['primary'] ];
+ $this->secondaryauthMocks = [ $mocks['secondary'] ];
+ $this->initializeManager( true );
+
+ $this->assertTrue( $this->manager->allowsPropertyChange( 'foo' ) );
+ $this->assertFalse( $this->manager->allowsPropertyChange( 'primary' ) );
+ $this->assertFalse( $this->manager->allowsPropertyChange( 'secondary' ) );
+ }
+
+ public function testAutoCreateOnLogin() {
+ $username = self::usernameForCreation();
+
+ $req = $this->getMock( AuthenticationRequest::class );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'primary' ) );
+ $mock->expects( $this->any() )->method( 'beginPrimaryAuthentication' )
+ ->will( $this->returnValue( AuthenticationResponse::newPass( $username ) ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( true ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+
+ $mock2 = $this->getMockForAbstractClass( SecondaryAuthenticationProvider::class );
+ $mock2->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( 'secondary' ) );
+ $mock2->expects( $this->any() )->method( 'beginSecondaryAuthentication' )->will(
+ $this->returnValue(
+ AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) )
+ )
+ );
+ $mock2->expects( $this->any() )->method( 'continueSecondaryAuthentication' )
+ ->will( $this->returnValue( AuthenticationResponse::newAbstain() ) );
+ $mock2->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+
+ $this->primaryauthMocks = [ $mock ];
+ $this->secondaryauthMocks = [ $mock2 ];
+ $this->initializeManager( true );
+ $this->manager->setLogger( new \Psr\Log\NullLogger() );
+ $session = $this->request->getSession();
+ $session->clear();
+
+ $this->assertSame( 0, \User::newFromName( $username )->getId(),
+ 'sanity check' );
+
+ $callback = $this->callback( function ( $user ) use ( $username ) {
+ return $user->getName() === $username;
+ } );
+
+ $this->hook( 'UserLoggedIn', $this->never() );
+ $this->hook( 'LocalUserCreated', $this->once() )->with( $callback, $this->equalTo( true ) );
+ $ret = $this->manager->beginAuthentication( [], 'http://localhost/' );
+ $this->unhook( 'LocalUserCreated' );
+ $this->unhook( 'UserLoggedIn' );
+ $this->assertSame( AuthenticationResponse::UI, $ret->status );
+
+ $id = (int)\User::newFromName( $username )->getId();
+ $this->assertNotSame( 0, \User::newFromName( $username )->getId() );
+ $this->assertSame( 0, $session->getUser()->getId() );
+
+ $this->hook( 'UserLoggedIn', $this->once() )->with( $callback );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->continueAuthentication( [] );
+ $this->unhook( 'LocalUserCreated' );
+ $this->unhook( 'UserLoggedIn' );
+ $this->assertSame( AuthenticationResponse::PASS, $ret->status );
+ $this->assertSame( $username, $ret->username );
+ $this->assertSame( $id, $session->getUser()->getId() );
+ }
+
+ public function testAutoCreateFailOnLogin() {
+ $username = self::usernameForCreation();
+
+ $mock = $this->getMockForAbstractClass(
+ PrimaryAuthenticationProvider::class, [], "MockPrimaryAuthenticationProvider" );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'primary' ) );
+ $mock->expects( $this->any() )->method( 'beginPrimaryAuthentication' )
+ ->will( $this->returnValue( AuthenticationResponse::newPass( $username ) ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mock->expects( $this->any() )->method( 'testUserExists' )->will( $this->returnValue( true ) );
+ $mock->expects( $this->any() )->method( 'testUserForCreation' )
+ ->will( $this->returnValue( StatusValue::newFatal( 'fail-from-primary' ) ) );
+
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+ $this->manager->setLogger( new \Psr\Log\NullLogger() );
+ $session = $this->request->getSession();
+ $session->clear();
+
+ $this->assertSame( 0, $session->getUser()->getId(),
+ 'sanity check' );
+ $this->assertSame( 0, \User::newFromName( $username )->getId(),
+ 'sanity check' );
+
+ $this->hook( 'UserLoggedIn', $this->never() );
+ $this->hook( 'LocalUserCreated', $this->never() );
+ $ret = $this->manager->beginAuthentication( [], 'http://localhost/' );
+ $this->unhook( 'LocalUserCreated' );
+ $this->unhook( 'UserLoggedIn' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'authmanager-authn-autocreate-failed', $ret->message->getKey() );
+
+ $this->assertSame( 0, \User::newFromName( $username )->getId() );
+ $this->assertSame( 0, $session->getUser()->getId() );
+ }
+
+ public function testAuthenticationSessionData() {
+ $this->initializeManager( true );
+
+ $this->assertNull( $this->manager->getAuthenticationSessionData( 'foo' ) );
+ $this->manager->setAuthenticationSessionData( 'foo', 'foo!' );
+ $this->manager->setAuthenticationSessionData( 'bar', 'bar!' );
+ $this->assertSame( 'foo!', $this->manager->getAuthenticationSessionData( 'foo' ) );
+ $this->assertSame( 'bar!', $this->manager->getAuthenticationSessionData( 'bar' ) );
+ $this->manager->removeAuthenticationSessionData( 'foo' );
+ $this->assertNull( $this->manager->getAuthenticationSessionData( 'foo' ) );
+ $this->assertSame( 'bar!', $this->manager->getAuthenticationSessionData( 'bar' ) );
+ $this->manager->removeAuthenticationSessionData( 'bar' );
+ $this->assertNull( $this->manager->getAuthenticationSessionData( 'bar' ) );
+
+ $this->manager->setAuthenticationSessionData( 'foo', 'foo!' );
+ $this->manager->setAuthenticationSessionData( 'bar', 'bar!' );
+ $this->manager->removeAuthenticationSessionData( null );
+ $this->assertNull( $this->manager->getAuthenticationSessionData( 'foo' ) );
+ $this->assertNull( $this->manager->getAuthenticationSessionData( 'bar' ) );
+
+ }
+
+ public function testCanLinkAccounts() {
+ $types = [
+ PrimaryAuthenticationProvider::TYPE_CREATE => true,
+ PrimaryAuthenticationProvider::TYPE_LINK => true,
+ PrimaryAuthenticationProvider::TYPE_NONE => false,
+ ];
+
+ foreach ( $types as $type => $can ) {
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( $type ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( $type ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+ $this->assertSame( $can, $this->manager->canCreateAccounts(), $type );
+ }
+ }
+
+ public function testBeginAccountLink() {
+ $user = \User::newFromName( 'UTSysop' );
+ $this->initializeManager();
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountLinkState', 'test' );
+ try {
+ $this->manager->beginAccountLink( $user, [], 'http://localhost/' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \LogicException $ex ) {
+ $this->assertEquals( 'Account linking is not possible', $ex->getMessage() );
+ }
+ $this->assertNull( $this->request->getSession()->getSecret( 'AuthManager::accountLinkState' ) );
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_LINK ) );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $ret = $this->manager->beginAccountLink( new \User, [], 'http://localhost/' );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'noname', $ret->message->getKey() );
+
+ $ret = $this->manager->beginAccountLink(
+ \User::newFromName( 'UTDoesNotExist' ), [], 'http://localhost/'
+ );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'authmanager-userdoesnotexist', $ret->message->getKey() );
+ }
+
+ public function testContinueAccountLink() {
+ $user = \User::newFromName( 'UTSysop' );
+ $this->initializeManager();
+
+ $session = [
+ 'userid' => $user->getId(),
+ 'username' => $user->getName(),
+ 'primary' => 'X',
+ ];
+
+ try {
+ $this->manager->continueAccountLink( [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \LogicException $ex ) {
+ $this->assertEquals( 'Account linking is not possible', $ex->getMessage() );
+ }
+
+ $mock = $this->getMockForAbstractClass( PrimaryAuthenticationProvider::class );
+ $mock->expects( $this->any() )->method( 'getUniqueId' )->will( $this->returnValue( 'X' ) );
+ $mock->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_LINK ) );
+ $mock->expects( $this->any() )->method( 'beginPrimaryAccountLink' )->will(
+ $this->returnValue( AuthenticationResponse::newFail( $this->message( 'fail' ) ) )
+ );
+ $this->primaryauthMocks = [ $mock ];
+ $this->initializeManager( true );
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountLinkState', null );
+ $ret = $this->manager->continueAccountLink( [] );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'authmanager-link-not-in-progress', $ret->message->getKey() );
+
+ $this->request->getSession()->setSecret( 'AuthManager::accountLinkState',
+ [ 'username' => $user->getName() . '<>' ] + $session );
+ $ret = $this->manager->continueAccountLink( [] );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'noname', $ret->message->getKey() );
+ $this->assertNull( $this->request->getSession()->getSecret( 'AuthManager::accountLinkState' ) );
+
+ $id = $user->getId();
+ $this->request->getSession()->setSecret( 'AuthManager::accountLinkState',
+ [ 'userid' => $id + 1 ] + $session );
+ try {
+ $ret = $this->manager->continueAccountLink( [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertEquals(
+ "User \"{$user->getName()}\" is valid, but ID $id != " . ( $id + 1 ) . '!',
+ $ex->getMessage()
+ );
+ }
+ $this->assertNull( $this->request->getSession()->getSecret( 'AuthManager::accountLinkState' ) );
+ }
+
+ /**
+ * @dataProvider provideAccountLink
+ * @param StatusValue $preTest
+ * @param array $primaryResponses
+ * @param array $managerResponses
+ */
+ public function testAccountLink(
+ StatusValue $preTest, array $primaryResponses, array $managerResponses
+ ) {
+ $user = \User::newFromName( 'UTSysop' );
+
+ $this->initializeManager();
+
+ // Set up lots of mocks...
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ $req->primary = $primaryResponses;
+ $mocks = [];
+
+ foreach ( [ 'pre', 'primary' ] as $key ) {
+ $class = ucfirst( $key ) . 'AuthenticationProvider';
+ $mocks[$key] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key]->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key ) );
+
+ for ( $i = 2; $i <= 3; $i++ ) {
+ $mocks[$key . $i] = $this->getMockForAbstractClass(
+ "MediaWiki\\Auth\\$class", [], "Mock$class"
+ );
+ $mocks[$key . $i]->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( $key . $i ) );
+ }
+ }
+
+ $mocks['pre']->expects( $this->any() )->method( 'testForAccountLink' )
+ ->will( $this->returnCallback(
+ function ( $u )
+ use ( $user, $preTest )
+ {
+ $this->assertSame( $user->getId(), $u->getId() );
+ $this->assertSame( $user->getName(), $u->getName() );
+ return $preTest;
+ }
+ ) );
+
+ $mocks['pre2']->expects( $this->atMost( 1 ) )->method( 'testForAccountLink' )
+ ->will( $this->returnValue( StatusValue::newGood() ) );
+
+ $mocks['primary']->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_LINK ) );
+ $ct = count( $req->primary );
+ $callback = $this->returnCallback( function ( $u, $reqs ) use ( $user, $req ) {
+ $this->assertSame( $user->getId(), $u->getId() );
+ $this->assertSame( $user->getName(), $u->getName() );
+ $foundReq = false;
+ foreach ( $reqs as $r ) {
+ $this->assertSame( $user->getName(), $r->username );
+ $foundReq = $foundReq || get_class( $r ) === get_class( $req );
+ }
+ $this->assertTrue( $foundReq, '$reqs contains $req' );
+ return array_shift( $req->primary );
+ } );
+ $mocks['primary']->expects( $this->exactly( min( 1, $ct ) ) )
+ ->method( 'beginPrimaryAccountLink' )
+ ->will( $callback );
+ $mocks['primary']->expects( $this->exactly( max( 0, $ct - 1 ) ) )
+ ->method( 'continuePrimaryAccountLink' )
+ ->will( $callback );
+
+ $abstain = AuthenticationResponse::newAbstain();
+ $mocks['primary2']->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_LINK ) );
+ $mocks['primary2']->expects( $this->atMost( 1 ) )->method( 'beginPrimaryAccountLink' )
+ ->will( $this->returnValue( $abstain ) );
+ $mocks['primary2']->expects( $this->never() )->method( 'continuePrimaryAccountLink' );
+ $mocks['primary3']->expects( $this->any() )->method( 'accountCreationType' )
+ ->will( $this->returnValue( PrimaryAuthenticationProvider::TYPE_CREATE ) );
+ $mocks['primary3']->expects( $this->never() )->method( 'beginPrimaryAccountLink' );
+ $mocks['primary3']->expects( $this->never() )->method( 'continuePrimaryAccountLink' );
+
+ $this->preauthMocks = [ $mocks['pre'], $mocks['pre2'] ];
+ $this->primaryauthMocks = [ $mocks['primary3'], $mocks['primary2'], $mocks['primary'] ];
+ $this->logger = new \TestLogger( true, function ( $message, $level ) {
+ return $level === LogLevel::DEBUG ? null : $message;
+ } );
+ $this->initializeManager( true );
+
+ $constraint = \PHPUnit_Framework_Assert::logicalOr(
+ $this->equalTo( AuthenticationResponse::PASS ),
+ $this->equalTo( AuthenticationResponse::FAIL )
+ );
+ $providers = array_merge( $this->preauthMocks, $this->primaryauthMocks );
+ foreach ( $providers as $p ) {
+ $p->postCalled = false;
+ $p->expects( $this->atMost( 1 ) )->method( 'postAccountLink' )
+ ->willReturnCallback( function ( $user, $response ) use ( $constraint, $p ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( 'UTSysop', $user->getName() );
+ $this->assertInstanceOf( AuthenticationResponse::class, $response );
+ $this->assertThat( $response->status, $constraint );
+ $p->postCalled = $response->status;
+ } );
+ }
+
+ $first = true;
+ $created = false;
+ $expectLog = [];
+ foreach ( $managerResponses as $i => $response ) {
+ if ( $response instanceof AuthenticationResponse &&
+ $response->status === AuthenticationResponse::PASS
+ ) {
+ $expectLog[] = [ LogLevel::INFO, 'Account linked to {user} by primary' ];
+ }
+
+ $ex = null;
+ try {
+ if ( $first ) {
+ $ret = $this->manager->beginAccountLink( $user, [ $req ], 'http://localhost/' );
+ } else {
+ $ret = $this->manager->continueAccountLink( [ $req ] );
+ }
+ if ( $response instanceof \Exception ) {
+ $this->fail( 'Expected exception not thrown', "Response $i" );
+ }
+ } catch ( \Exception $ex ) {
+ if ( !$response instanceof \Exception ) {
+ throw $ex;
+ }
+ $this->assertEquals( $response->getMessage(), $ex->getMessage(), "Response $i, exception" );
+ $this->assertNull( $this->request->getSession()->getSecret( 'AuthManager::accountLinkState' ),
+ "Response $i, exception, session state" );
+ return;
+ }
+
+ $this->assertSame( 'http://localhost/', $req->returnToUrl );
+
+ $ret->message = $this->message( $ret->message );
+ $this->assertEquals( $response, $ret, "Response $i, response" );
+ if ( $response->status === AuthenticationResponse::PASS ||
+ $response->status === AuthenticationResponse::FAIL
+ ) {
+ $this->assertNull( $this->request->getSession()->getSecret( 'AuthManager::accountLinkState' ),
+ "Response $i, session state" );
+ foreach ( $providers as $p ) {
+ $this->assertSame( $response->status, $p->postCalled,
+ "Response $i, post-auth callback called" );
+ }
+ } else {
+ $this->assertNotNull(
+ $this->request->getSession()->getSecret( 'AuthManager::accountLinkState' ),
+ "Response $i, session state"
+ );
+ foreach ( $ret->neededRequests as $neededReq ) {
+ $this->assertEquals( AuthManager::ACTION_LINK, $neededReq->action,
+ "Response $i, neededRequest action" );
+ }
+ $this->assertEquals(
+ $ret->neededRequests,
+ $this->manager->getAuthenticationRequests( AuthManager::ACTION_LINK_CONTINUE ),
+ "Response $i, continuation check"
+ );
+ foreach ( $providers as $p ) {
+ $this->assertFalse( $p->postCalled, "Response $i, post-auth callback not called" );
+ }
+ }
+
+ $first = false;
+ }
+
+ $this->assertSame( $expectLog, $this->logger->getBuffer() );
+ }
+
+ public function provideAccountLink() {
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ $good = StatusValue::newGood();
+
+ return [
+ 'Pre-link test fail in pre' => [
+ StatusValue::newFatal( 'fail-from-pre' ),
+ [],
+ [
+ AuthenticationResponse::newFail( $this->message( 'fail-from-pre' ) ),
+ ]
+ ],
+ 'Failure in primary' => [
+ $good,
+ $tmp = [
+ AuthenticationResponse::newFail( $this->message( 'fail-from-primary' ) ),
+ ],
+ $tmp
+ ],
+ 'All primary abstain' => [
+ $good,
+ [
+ AuthenticationResponse::newAbstain(),
+ ],
+ [
+ AuthenticationResponse::newFail( $this->message( 'authmanager-link-no-primary' ) )
+ ]
+ ],
+ 'Primary UI, then redirect, then fail' => [
+ $good,
+ $tmp = [
+ AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) ),
+ AuthenticationResponse::newRedirect( [ $req ], '/foo.html', [ 'foo' => 'bar' ] ),
+ AuthenticationResponse::newFail( $this->message( 'fail-in-primary-continue' ) ),
+ ],
+ $tmp
+ ],
+ 'Primary redirect, then abstain' => [
+ $good,
+ [
+ $tmp = AuthenticationResponse::newRedirect(
+ [ $req ], '/foo.html', [ 'foo' => 'bar' ]
+ ),
+ AuthenticationResponse::newAbstain(),
+ ],
+ [
+ $tmp,
+ new \DomainException(
+ 'MockPrimaryAuthenticationProvider::continuePrimaryAccountLink() returned ABSTAIN'
+ )
+ ]
+ ],
+ 'Primary UI, then pass' => [
+ $good,
+ [
+ $tmp1 = AuthenticationResponse::newUI( [ $req ], $this->message( '...' ) ),
+ AuthenticationResponse::newPass(),
+ ],
+ [
+ $tmp1,
+ AuthenticationResponse::newPass( '' ),
+ ]
+ ],
+ 'Primary pass' => [
+ $good,
+ [
+ AuthenticationResponse::newPass( '' ),
+ ],
+ [
+ AuthenticationResponse::newPass( '' ),
+ ]
+ ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\AuthPluginPrimaryAuthenticationProvider
+ */
+class AuthPluginPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testConstruction() {
+ $plugin = new AuthManagerAuthPlugin();
+ try {
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Trying to wrap AuthManagerAuthPlugin in AuthPluginPrimaryAuthenticationProvider ' .
+ 'makes no sense.',
+ $ex->getMessage()
+ );
+ }
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertEquals(
+ [ new PasswordAuthenticationRequest ],
+ $provider->getAuthenticationRequests( AuthManager::ACTION_LOGIN, [] )
+ );
+
+ $req = $this->getMock( PasswordAuthenticationRequest::class );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin, get_class( $req ) );
+ $this->assertEquals(
+ [ $req ],
+ $provider->getAuthenticationRequests( AuthManager::ACTION_LOGIN, [] )
+ );
+
+ $reqType = get_class( $this->getMock( AuthenticationRequest::class ) );
+ try {
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin, $reqType );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \InvalidArgumentException $ex ) {
+ $this->assertSame(
+ "$reqType is not a MediaWiki\\Auth\\PasswordAuthenticationRequest",
+ $ex->getMessage()
+ );
+ }
+ }
+
+ public function testOnUserSaveSettings() {
+ $user = \User::newFromName( 'UTSysop' );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'updateExternalDB' )
+ ->with( $this->identicalTo( $user ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+ \Hooks::run( 'UserSaveSettings', [ $user ] );
+ }
+
+ public function testOnUserGroupsChanged() {
+ $user = \User::newFromName( 'UTSysop' );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'updateExternalDBGroups' )
+ ->with(
+ $this->identicalTo( $user ),
+ $this->identicalTo( [ 'added' ] ),
+ $this->identicalTo( [ 'removed' ] )
+ );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+ \Hooks::run( 'UserGroupsChanged', [ $user, [ 'added' ], [ 'removed' ] ] );
+ }
+
+ public function testOnUserLoggedIn() {
+ $user = \User::newFromName( 'UTSysop' );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->exactly( 2 ) )->method( 'updateUser' )
+ ->with( $this->identicalTo( $user ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ \Hooks::run( 'UserLoggedIn', [ $user ] );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'updateUser' )
+ ->will( $this->returnCallback( function ( &$user ) {
+ $user = \User::newFromName( 'UTSysop' );
+ } ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ try {
+ \Hooks::run( 'UserLoggedIn', [ $user ] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame(
+ get_class( $plugin ) . '::updateUser() tried to replace $user!',
+ $ex->getMessage()
+ );
+ }
+ }
+
+ public function testOnLocalUserCreated() {
+ $user = \User::newFromName( 'UTSysop' );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->exactly( 2 ) )->method( 'initUser' )
+ ->with( $this->identicalTo( $user ), $this->identicalTo( false ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ \Hooks::run( 'LocalUserCreated', [ $user, false ] );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'initUser' )
+ ->will( $this->returnCallback( function ( &$user ) {
+ $user = \User::newFromName( 'UTSysop' );
+ } ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ try {
+ \Hooks::run( 'LocalUserCreated', [ $user, false ] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame(
+ get_class( $plugin ) . '::initUser() tried to replace $user!',
+ $ex->getMessage()
+ );
+ }
+ }
+
+ public function testGetUniqueId() {
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertSame(
+ 'MediaWiki\\Auth\\AuthPluginPrimaryAuthenticationProvider:' . get_class( $plugin ),
+ $provider->getUniqueId()
+ );
+ }
+
+ /**
+ * @dataProvider provideGetAuthenticationRequests
+ * @param string $action
+ * @param array $response
+ * @param bool $allowPasswordChange
+ */
+ public function testGetAuthenticationRequests( $action, $response, $allowPasswordChange ) {
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->any() )->method( 'allowPasswordChange' )
+ ->will( $this->returnValue( $allowPasswordChange ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
+ }
+
+ public static function provideGetAuthenticationRequests() {
+ $arr = [ new PasswordAuthenticationRequest() ];
+ return [
+ [ AuthManager::ACTION_LOGIN, $arr, true ],
+ [ AuthManager::ACTION_LOGIN, $arr, false ],
+ [ AuthManager::ACTION_CREATE, $arr, true ],
+ [ AuthManager::ACTION_CREATE, $arr, false ],
+ [ AuthManager::ACTION_LINK, [], true ],
+ [ AuthManager::ACTION_LINK, [], false ],
+ [ AuthManager::ACTION_CHANGE, $arr, true ],
+ [ AuthManager::ACTION_CHANGE, [], false ],
+ [ AuthManager::ACTION_REMOVE, $arr, true ],
+ [ AuthManager::ACTION_REMOVE, [], false ],
+ ];
+ }
+
+ public function testAuthentication() {
+ $req = new PasswordAuthenticationRequest();
+ $req->action = AuthManager::ACTION_LOGIN;
+ $reqs = [ PasswordAuthenticationRequest::class => $req ];
+
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'authenticate' ] )
+ ->getMock();
+ $plugin->expects( $this->never() )->method( 'authenticate' );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( [] )
+ );
+
+ $req->username = 'foo';
+ $req->password = null;
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $req->username = null;
+ $req->password = 'bar';
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $req->username = 'foo';
+ $req->password = 'bar';
+
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'userExists', 'authenticate' ] )
+ ->getMock();
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'authenticate' )
+ ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+ ->will( $this->returnValue( true ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertEquals(
+ AuthenticationResponse::newPass( 'Foo', $req ),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'userExists', 'authenticate' ] )
+ ->getMock();
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->will( $this->returnValue( false ) );
+ $plugin->expects( $this->never() )->method( 'authenticate' );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $pluginUser = $this->getMockBuilder( 'AuthPluginUser' )
+ ->setMethods( [ 'isLocked' ] )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $pluginUser->expects( $this->once() )->method( 'isLocked' )
+ ->will( $this->returnValue( true ) );
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'userExists', 'getUserInstance', 'authenticate' ] )
+ ->getMock();
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'getUserInstance' )
+ ->will( $this->returnValue( $pluginUser ) );
+ $plugin->expects( $this->never() )->method( 'authenticate' );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'userExists', 'authenticate' ] )
+ ->getMock();
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'authenticate' )
+ ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+ ->will( $this->returnValue( false ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'userExists', 'authenticate', 'strict' ] )
+ ->getMock();
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'authenticate' )
+ ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+ ->will( $this->returnValue( false ) );
+ $plugin->expects( $this->any() )->method( 'strict' )->will( $this->returnValue( true ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'wrongpassword', $ret->message->getKey() );
+
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'userExists', 'authenticate', 'strictUserAuth' ] )
+ ->getMock();
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'authenticate' )
+ ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+ ->will( $this->returnValue( false ) );
+ $plugin->expects( $this->any() )->method( 'strictUserAuth' )
+ ->with( $this->equalTo( 'Foo' ) )
+ ->will( $this->returnValue( true ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'wrongpassword', $ret->message->getKey() );
+
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'domainList', 'validDomain', 'setDomain', 'userExists', 'authenticate' ] )
+ ->getMock();
+ $plugin->expects( $this->any() )->method( 'domainList' )
+ ->will( $this->returnValue( [ 'Domain1', 'Domain2' ] ) );
+ $plugin->expects( $this->any() )->method( 'validDomain' )
+ ->will( $this->returnCallback( function ( $domain ) {
+ return in_array( $domain, [ 'Domain1', 'Domain2' ] );
+ } ) );
+ $plugin->expects( $this->once() )->method( 'setDomain' )
+ ->with( $this->equalTo( 'Domain2' ) );
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'authenticate' )
+ ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+ ->will( $this->returnValue( true ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ list( $req ) = $provider->getAuthenticationRequests( AuthManager::ACTION_LOGIN, [] );
+ $req->username = 'foo';
+ $req->password = 'bar';
+ $req->domain = 'Domain2';
+ $provider->beginPrimaryAuthentication( [ $req ] );
+ }
+
+ public function testTestUserExists() {
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->with( $this->equalTo( 'Foo' ) )
+ ->will( $this->returnValue( true ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+ $this->assertTrue( $provider->testUserExists( 'foo' ) );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->with( $this->equalTo( 'Foo' ) )
+ ->will( $this->returnValue( false ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+ $this->assertFalse( $provider->testUserExists( 'foo' ) );
+ }
+
+ public function testTestUserCanAuthenticate() {
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->with( $this->equalTo( 'Foo' ) )
+ ->will( $this->returnValue( false ) );
+ $plugin->expects( $this->never() )->method( 'getUserInstance' );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertFalse( $provider->testUserCanAuthenticate( 'foo' ) );
+
+ $pluginUser = $this->getMockBuilder( 'AuthPluginUser' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $pluginUser->expects( $this->once() )->method( 'isLocked' )
+ ->will( $this->returnValue( true ) );
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->with( $this->equalTo( 'Foo' ) )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'getUserInstance' )
+ ->with( $this->callback( function ( $user ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertEquals( 'Foo', $user->getName() );
+ return true;
+ } ) )
+ ->will( $this->returnValue( $pluginUser ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertFalse( $provider->testUserCanAuthenticate( 'foo' ) );
+
+ $pluginUser = $this->getMockBuilder( 'AuthPluginUser' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $pluginUser->expects( $this->once() )->method( 'isLocked' )
+ ->will( $this->returnValue( false ) );
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'userExists' )
+ ->with( $this->equalTo( 'Foo' ) )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'getUserInstance' )
+ ->with( $this->callback( function ( $user ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertEquals( 'Foo', $user->getName() );
+ return true;
+ } ) )
+ ->will( $this->returnValue( $pluginUser ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertTrue( $provider->testUserCanAuthenticate( 'foo' ) );
+ }
+
+ public function testProviderRevokeAccessForUser() {
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'userExists', 'setPassword' ] )
+ ->getMock();
+ $plugin->expects( $this->once() )->method( 'userExists' )->willReturn( true );
+ $plugin->expects( $this->once() )->method( 'setPassword' )
+ ->with( $this->callback( function ( $u ) {
+ return $u instanceof \User && $u->getName() === 'Foo';
+ } ), $this->identicalTo( null ) )
+ ->willReturn( true );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $provider->providerRevokeAccessForUser( 'foo' );
+
+ $plugin = $this->getMockBuilder( 'AuthPlugin' )
+ ->setMethods( [ 'domainList', 'userExists', 'setPassword' ] )
+ ->getMock();
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [ 'D1', 'D2', 'D3' ] );
+ $plugin->expects( $this->exactly( 3 ) )->method( 'userExists' )
+ ->willReturnCallback( function () use ( $plugin ) {
+ return $plugin->getDomain() !== 'D2';
+ } );
+ $plugin->expects( $this->exactly( 2 ) )->method( 'setPassword' )
+ ->with( $this->callback( function ( $u ) {
+ return $u instanceof \User && $u->getName() === 'Foo';
+ } ), $this->identicalTo( null ) )
+ ->willReturnCallback( function () use ( $plugin ) {
+ $this->assertNotEquals( 'D2', $plugin->getDomain() );
+ return $plugin->getDomain() !== 'D1';
+ } );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ try {
+ $provider->providerRevokeAccessForUser( 'foo' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame(
+ 'AuthPlugin failed to reset password for Foo in the following domains: D1',
+ $ex->getMessage()
+ );
+ }
+ }
+
+ public function testProviderAllowsPropertyChange() {
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->any() )->method( 'allowPropChange' )
+ ->will( $this->returnCallback( function ( $prop ) {
+ return $prop === 'allow';
+ } ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+ $this->assertTrue( $provider->providerAllowsPropertyChange( 'allow' ) );
+ $this->assertFalse( $provider->providerAllowsPropertyChange( 'deny' ) );
+ }
+
+ /**
+ * @dataProvider provideProviderAllowsAuthenticationDataChange
+ * @param string $type
+ * @param bool|null $allow
+ * @param StatusValue $expect
+ */
+ public function testProviderAllowsAuthenticationDataChange( $type, $allow, $expect ) {
+ $domains = $type instanceof PasswordDomainAuthenticationRequest ? [ 'foo', 'bar' ] : [];
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( $domains );
+ $plugin->expects( $allow === null ? $this->never() : $this->once() )
+ ->method( 'allowPasswordChange' )->will( $this->returnValue( $allow ) );
+ $plugin->expects( $this->any() )->method( 'validDomain' )
+ ->willReturnCallback( function ( $d ) use ( $domains ) {
+ return in_array( $d, $domains, true );
+ } );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+ if ( is_object( $type ) ) {
+ $req = $type;
+ } else {
+ $req = $this->getMock( $type );
+ }
+ $req->action = AuthManager::ACTION_CHANGE;
+ $req->username = 'UTSysop';
+ $req->password = 'Pa$$w0Rd!!!';
+ $req->retype = 'Pa$$w0Rd!!!';
+ $this->assertEquals( $expect, $provider->providerAllowsAuthenticationDataChange( $req ) );
+ }
+
+ public static function provideProviderAllowsAuthenticationDataChange() {
+ $domains = [ 'foo', 'bar' ];
+ $reqNoDomain = new PasswordDomainAuthenticationRequest( $domains );
+ $reqValidDomain = new PasswordDomainAuthenticationRequest( $domains );
+ $reqValidDomain->domain = 'foo';
+ $reqInvalidDomain = new PasswordDomainAuthenticationRequest( $domains );
+ $reqInvalidDomain->domain = 'invalid';
+
+ return [
+ [ AuthenticationRequest::class, null, \StatusValue::newGood( 'ignored' ) ],
+ [ new PasswordAuthenticationRequest, true, \StatusValue::newGood() ],
+ [
+ new PasswordAuthenticationRequest,
+ false,
+ \StatusValue::newFatal( 'authmanager-authplugin-setpass-denied' )
+ ],
+ [ $reqNoDomain, true, \StatusValue::newGood( 'ignored' ) ],
+ [ $reqValidDomain, true, \StatusValue::newGood() ],
+ [
+ $reqInvalidDomain,
+ true,
+ \StatusValue::newFatal( 'authmanager-authplugin-setpass-bad-domain' )
+ ],
+ ];
+ }
+
+ public function testProviderChangeAuthenticationData() {
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->never() )->method( 'setPassword' );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $provider->providerChangeAuthenticationData(
+ $this->getMock( AuthenticationRequest::class )
+ );
+
+ $req = new PasswordAuthenticationRequest();
+ $req->action = AuthManager::ACTION_CHANGE;
+ $req->username = 'foo';
+ $req->password = 'bar';
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'setPassword' )
+ ->with( $this->callback( function ( $u ) {
+ return $u instanceof \User && $u->getName() === 'Foo';
+ } ), $this->equalTo( 'bar' ) )
+ ->will( $this->returnValue( true ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $provider->providerChangeAuthenticationData( $req );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )->method( 'setPassword' )
+ ->with( $this->callback( function ( $u ) {
+ return $u instanceof \User && $u->getName() === 'Foo';
+ } ), $this->equalTo( 'bar' ) )
+ ->will( $this->returnValue( false ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ try {
+ $provider->providerChangeAuthenticationData( $req );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \ErrorPageError $e ) {
+ $this->assertSame( 'authmanager-authplugin-setpass-failed-title', $e->title );
+ $this->assertSame( 'authmanager-authplugin-setpass-failed-message', $e->msg );
+ }
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )
+ ->will( $this->returnValue( [ 'Domain1', 'Domain2' ] ) );
+ $plugin->expects( $this->any() )->method( 'validDomain' )
+ ->will( $this->returnCallback( function ( $domain ) {
+ return in_array( $domain, [ 'Domain1', 'Domain2' ] );
+ } ) );
+ $plugin->expects( $this->once() )->method( 'setDomain' )
+ ->with( $this->equalTo( 'Domain2' ) );
+ $plugin->expects( $this->once() )->method( 'setPassword' )
+ ->with( $this->callback( function ( $u ) {
+ return $u instanceof \User && $u->getName() === 'Foo';
+ } ), $this->equalTo( 'bar' ) )
+ ->will( $this->returnValue( true ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ list( $req ) = $provider->getAuthenticationRequests( AuthManager::ACTION_CREATE, [] );
+ $req->username = 'foo';
+ $req->password = 'bar';
+ $req->domain = 'Domain2';
+ $provider->providerChangeAuthenticationData( $req );
+ }
+
+ /**
+ * @dataProvider provideAccountCreationType
+ * @param bool $can
+ * @param string $expect
+ */
+ public function testAccountCreationType( $can, $expect ) {
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->once() )
+ ->method( 'canCreateAccounts' )->will( $this->returnValue( $can ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+ $this->assertSame( $expect, $provider->accountCreationType() );
+ }
+
+ public static function provideAccountCreationType() {
+ return [
+ [ true, PrimaryAuthenticationProvider::TYPE_CREATE ],
+ [ false, PrimaryAuthenticationProvider::TYPE_NONE ],
+ ];
+ }
+
+ public function testTestForAccountCreation() {
+ $user = \User::newFromName( 'foo' );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $user, [] )
+ );
+ }
+
+ public function testAccountCreation() {
+ $user = \User::newFromName( 'foo' );
+ $user->setEmail( 'email' );
+ $user->setRealName( 'realname' );
+
+ $req = new PasswordAuthenticationRequest();
+ $req->action = AuthManager::ACTION_CREATE;
+ $reqs = [ PasswordAuthenticationRequest::class => $req ];
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+ ->will( $this->returnValue( false ) );
+ $plugin->expects( $this->never() )->method( 'addUser' );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ try {
+ $provider->beginPrimaryAccountCreation( $user, $user, [] );
+ $this->fail( 'Expected exception was not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ $this->assertSame(
+ 'Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage()
+ );
+ }
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->never() )->method( 'addUser' );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAccountCreation( $user, $user, [] )
+ );
+
+ $req->username = 'foo';
+ $req->password = null;
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+ );
+
+ $req->username = null;
+ $req->password = 'bar';
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+ );
+
+ $req->username = 'foo';
+ $req->password = 'bar';
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'addUser' )
+ ->with(
+ $this->callback( function ( $u ) {
+ return $u instanceof \User && $u->getName() === 'Foo';
+ } ),
+ $this->equalTo( 'bar' ),
+ $this->equalTo( 'email' ),
+ $this->equalTo( 'realname' )
+ )
+ ->will( $this->returnValue( true ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $this->assertEquals(
+ AuthenticationResponse::newPass(),
+ $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+ );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+ $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->once() )->method( 'addUser' )
+ ->with(
+ $this->callback( function ( $u ) {
+ return $u instanceof \User && $u->getName() === 'Foo';
+ } ),
+ $this->equalTo( 'bar' ),
+ $this->equalTo( 'email' ),
+ $this->equalTo( 'realname' )
+ )
+ ->will( $this->returnValue( false ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ $ret = $provider->beginPrimaryAccountCreation( $user, $user, $reqs );
+ $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+ $this->assertSame( 'authmanager-authplugin-create-fail', $ret->message->getKey() );
+
+ $plugin = $this->getMock( 'AuthPlugin' );
+ $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+ ->will( $this->returnValue( true ) );
+ $plugin->expects( $this->any() )->method( 'domainList' )
+ ->will( $this->returnValue( [ 'Domain1', 'Domain2' ] ) );
+ $plugin->expects( $this->any() )->method( 'validDomain' )
+ ->will( $this->returnCallback( function ( $domain ) {
+ return in_array( $domain, [ 'Domain1', 'Domain2' ] );
+ } ) );
+ $plugin->expects( $this->once() )->method( 'setDomain' )
+ ->with( $this->equalTo( 'Domain2' ) );
+ $plugin->expects( $this->once() )->method( 'addUser' )
+ ->with( $this->callback( function ( $u ) {
+ return $u instanceof \User && $u->getName() === 'Foo';
+ } ), $this->equalTo( 'bar' ) )
+ ->will( $this->returnValue( true ) );
+ $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+ list( $req ) = $provider->getAuthenticationRequests( AuthManager::ACTION_CREATE, [] );
+ $req->username = 'foo';
+ $req->password = 'bar';
+ $req->domain = 'Domain2';
+ $provider->beginPrimaryAccountCreation( $user, $user, [ $req ] );
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\AuthenticationRequest
+ */
+class AuthenticationRequestTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testBasics() {
+ $mock = $this->getMockForAbstractClass( AuthenticationRequest::class );
+
+ $this->assertSame( get_class( $mock ), $mock->getUniqueId() );
+
+ $this->assertType( 'array', $mock->getMetadata() );
+
+ $ret = $mock->describeCredentials();
+ $this->assertInternalType( 'array', $ret );
+ $this->assertArrayHasKey( 'provider', $ret );
+ $this->assertInstanceOf( 'Message', $ret['provider'] );
+ $this->assertArrayHasKey( 'account', $ret );
+ $this->assertInstanceOf( 'Message', $ret['account'] );
+ }
+
+ public function testLoadRequestsFromSubmission() {
+ $mb = $this->getMockBuilder( AuthenticationRequest::class )
+ ->setMethods( [ 'loadFromSubmission' ] );
+
+ $data = [ 'foo', 'bar' ];
+
+ $req1 = $mb->getMockForAbstractClass();
+ $req1->expects( $this->once() )->method( 'loadFromSubmission' )
+ ->with( $this->identicalTo( $data ) )
+ ->will( $this->returnValue( false ) );
+
+ $req2 = $mb->getMockForAbstractClass();
+ $req2->expects( $this->once() )->method( 'loadFromSubmission' )
+ ->with( $this->identicalTo( $data ) )
+ ->will( $this->returnValue( true ) );
+
+ $this->assertSame(
+ [ $req2 ],
+ AuthenticationRequest::loadRequestsFromSubmission( [ $req1, $req2 ], $data )
+ );
+ }
+
+ public function testGetRequestByClass() {
+ $mb = $this->getMockBuilder(
+ AuthenticationRequest::class, 'AuthenticationRequestTest_AuthenticationRequest2'
+ );
+
+ $reqs = [
+ $this->getMockForAbstractClass(
+ AuthenticationRequest::class, [], 'AuthenticationRequestTest_AuthenticationRequest1'
+ ),
+ $mb->getMockForAbstractClass(),
+ $mb->getMockForAbstractClass(),
+ $this->getMockForAbstractClass(
+ PasswordAuthenticationRequest::class, [],
+ 'AuthenticationRequestTest_PasswordAuthenticationRequest'
+ ),
+ ];
+
+ $this->assertNull( AuthenticationRequest::getRequestByClass(
+ $reqs, 'AuthenticationRequestTest_AuthenticationRequest0'
+ ) );
+ $this->assertSame( $reqs[0], AuthenticationRequest::getRequestByClass(
+ $reqs, 'AuthenticationRequestTest_AuthenticationRequest1'
+ ) );
+ $this->assertNull( AuthenticationRequest::getRequestByClass(
+ $reqs, 'AuthenticationRequestTest_AuthenticationRequest2'
+ ) );
+ $this->assertNull( AuthenticationRequest::getRequestByClass(
+ $reqs, PasswordAuthenticationRequest::class
+ ) );
+ $this->assertNull( AuthenticationRequest::getRequestByClass(
+ $reqs, 'ClassThatDoesNotExist'
+ ) );
+
+ $this->assertNull( AuthenticationRequest::getRequestByClass(
+ $reqs, 'AuthenticationRequestTest_AuthenticationRequest0', true
+ ) );
+ $this->assertSame( $reqs[0], AuthenticationRequest::getRequestByClass(
+ $reqs, 'AuthenticationRequestTest_AuthenticationRequest1', true
+ ) );
+ $this->assertNull( AuthenticationRequest::getRequestByClass(
+ $reqs, 'AuthenticationRequestTest_AuthenticationRequest2', true
+ ) );
+ $this->assertSame( $reqs[3], AuthenticationRequest::getRequestByClass(
+ $reqs, PasswordAuthenticationRequest::class, true
+ ) );
+ $this->assertNull( AuthenticationRequest::getRequestByClass(
+ $reqs, 'ClassThatDoesNotExist', true
+ ) );
+ }
+
+ public function testGetUsernameFromRequests() {
+ $mb = $this->getMockBuilder( AuthenticationRequest::class );
+
+ for ( $i = 0; $i < 3; $i++ ) {
+ $req = $mb->getMockForAbstractClass();
+ $req->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
+ 'username' => [
+ 'type' => 'string',
+ ],
+ ] ) );
+ $reqs[] = $req;
+ }
+
+ $req = $mb->getMockForAbstractClass();
+ $req->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [] ) );
+ $req->username = 'baz';
+ $reqs[] = $req;
+
+ $this->assertNull( AuthenticationRequest::getUsernameFromRequests( $reqs ) );
+
+ $reqs[1]->username = 'foo';
+ $this->assertSame( 'foo', AuthenticationRequest::getUsernameFromRequests( $reqs ) );
+
+ $reqs[0]->username = 'foo';
+ $reqs[2]->username = 'foo';
+ $this->assertSame( 'foo', AuthenticationRequest::getUsernameFromRequests( $reqs ) );
+
+ $reqs[1]->username = 'bar';
+ try {
+ AuthenticationRequest::getUsernameFromRequests( $reqs );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame(
+ 'Conflicting username fields: "bar" from ' .
+ get_class( $reqs[1] ) . '::$username vs. "foo" from ' .
+ get_class( $reqs[0] ) . '::$username',
+ $ex->getMessage()
+ );
+ }
+ }
+
+ public function testMergeFieldInfo() {
+ $msg = wfMessage( 'foo' );
+
+ $req1 = $this->getMock( AuthenticationRequest::class );
+ $req1->required = AuthenticationRequest::REQUIRED;
+ $req1->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
+ 'string1' => [
+ 'type' => 'string',
+ 'label' => $msg,
+ 'help' => $msg,
+ ],
+ 'string2' => [
+ 'type' => 'string',
+ 'label' => $msg,
+ 'help' => $msg,
+ ],
+ 'optional' => [
+ 'type' => 'string',
+ 'label' => $msg,
+ 'help' => $msg,
+ 'optional' => true,
+ ],
+ 'select' => [
+ 'type' => 'select',
+ 'options' => [ 'foo' => $msg, 'baz' => $msg ],
+ 'label' => $msg,
+ 'help' => $msg,
+ ],
+ ] ) );
+
+ $req2 = $this->getMock( AuthenticationRequest::class );
+ $req2->required = AuthenticationRequest::REQUIRED;
+ $req2->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
+ 'string1' => [
+ 'type' => 'string',
+ 'label' => $msg,
+ 'help' => $msg,
+ ],
+ 'string3' => [
+ 'type' => 'string',
+ 'label' => $msg,
+ 'help' => $msg,
+ ],
+ 'select' => [
+ 'type' => 'select',
+ 'options' => [ 'bar' => $msg, 'baz' => $msg ],
+ 'label' => $msg,
+ 'help' => $msg,
+ ],
+ ] ) );
+
+ $req3 = $this->getMock( AuthenticationRequest::class );
+ $req3->required = AuthenticationRequest::REQUIRED;
+ $req3->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
+ 'string1' => [
+ 'type' => 'checkbox',
+ 'label' => $msg,
+ 'help' => $msg,
+ ],
+ ] ) );
+
+ $req4 = $this->getMock( AuthenticationRequest::class );
+ $req4->required = AuthenticationRequest::REQUIRED;
+ $req4->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [] ) );
+
+ // Basic combining
+
+ $fields = AuthenticationRequest::mergeFieldInfo( [ $req1 ] );
+ $expect = $req1->getFieldInfo();
+ foreach ( $expect as $name => &$options ) {
+ $options['optional'] = !empty( $options['optional'] );
+ }
+ unset( $options );
+ $this->assertEquals( $expect, $fields );
+
+ $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req4 ] );
+ $this->assertEquals( $expect, $fields );
+
+ try {
+ AuthenticationRequest::mergeFieldInfo( [ $req1, $req3 ] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame(
+ 'Field type conflict for "string1", "string" vs "checkbox"',
+ $ex->getMessage()
+ );
+ }
+
+ $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
+ $expect += $req2->getFieldInfo();
+ $expect['string2']['optional'] = false;
+ $expect['string3']['optional'] = false;
+ $expect['select']['options']['bar'] = $msg;
+ $this->assertEquals( $expect, $fields );
+
+ // Combining with something not required
+
+ $req1->required = AuthenticationRequest::PRIMARY_REQUIRED;
+
+ $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
+ $expect += $req2->getFieldInfo();
+ $expect['string1']['optional'] = false;
+ $expect['string3']['optional'] = false;
+ $expect['select']['optional'] = false;
+ $expect['select']['options']['bar'] = $msg;
+ $this->assertEquals( $expect, $fields );
+
+ $req2->required = AuthenticationRequest::PRIMARY_REQUIRED;
+
+ $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
+ $expect = $req1->getFieldInfo() + $req2->getFieldInfo();
+ $expect['string1']['optional'] = false;
+ $expect['string2']['optional'] = true;
+ $expect['string3']['optional'] = true;
+ $expect['select']['optional'] = false;
+ $expect['select']['options']['bar'] = $msg;
+ $this->assertEquals( $expect, $fields );
+ }
+
+ /**
+ * @dataProvider provideLoadFromSubmission
+ * @param array $fieldInfo
+ * @param array $data
+ * @param array|bool $expectState
+ */
+ public function testLoadFromSubmission( $fieldInfo, $data, $expectState ) {
+ $mock = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ $mock->expects( $this->any() )->method( 'getFieldInfo' )
+ ->will( $this->returnValue( $fieldInfo ) );
+
+ $ret = $mock->loadFromSubmission( $data );
+ if ( is_array( $expectState ) ) {
+ $this->assertTrue( $ret );
+ $expect = call_user_func( [ get_class( $mock ), '__set_state' ], $expectState );
+ $this->assertEquals( $expect, $mock );
+ } else {
+ $this->assertFalse( $ret );
+ }
+ }
+
+ public static function provideLoadFromSubmission() {
+ return [
+ 'No fields' => [
+ [],
+ $data = [ 'foo' => 'bar' ],
+ false
+ ],
+
+ 'Simple field' => [
+ [
+ 'field' => [
+ 'type' => 'string',
+ ],
+ ],
+ $data = [ 'field' => 'string!' ],
+ $data
+ ],
+ 'Simple field, not supplied' => [
+ [
+ 'field' => [
+ 'type' => 'string',
+ ],
+ ],
+ [],
+ false
+ ],
+ 'Simple field, empty' => [
+ [
+ 'field' => [
+ 'type' => 'string',
+ ],
+ ],
+ [ 'field' => '' ],
+ false
+ ],
+ 'Simple field, optional, not supplied' => [
+ [
+ 'field' => [
+ 'type' => 'string',
+ 'optional' => true,
+ ],
+ ],
+ [],
+ false
+ ],
+ 'Simple field, optional, empty' => [
+ [
+ 'field' => [
+ 'type' => 'string',
+ 'optional' => true,
+ ],
+ ],
+ $data = [ 'field' => '' ],
+ $data
+ ],
+
+ 'Checkbox, checked' => [
+ [
+ 'check' => [
+ 'type' => 'checkbox',
+ ],
+ ],
+ [ 'check' => '' ],
+ [ 'check' => true ]
+ ],
+ 'Checkbox, unchecked' => [
+ [
+ 'check' => [
+ 'type' => 'checkbox',
+ ],
+ ],
+ [],
+ false
+ ],
+ 'Checkbox, optional, unchecked' => [
+ [
+ 'check' => [
+ 'type' => 'checkbox',
+ 'optional' => true,
+ ],
+ ],
+ [],
+ [ 'check' => false ]
+ ],
+
+ 'Button, used' => [
+ [
+ 'push' => [
+ 'type' => 'button',
+ ],
+ ],
+ [ 'push' => '' ],
+ [ 'push' => true ]
+ ],
+ 'Button, unused' => [
+ [
+ 'push' => [
+ 'type' => 'button',
+ ],
+ ],
+ [],
+ false
+ ],
+ 'Button, optional, unused' => [
+ [
+ 'push' => [
+ 'type' => 'button',
+ 'optional' => true,
+ ],
+ ],
+ [],
+ [ 'push' => false ]
+ ],
+ 'Button, image-style' => [
+ [
+ 'push' => [
+ 'type' => 'button',
+ ],
+ ],
+ [ 'push_x' => 0, 'push_y' => 0 ],
+ [ 'push' => true ]
+ ],
+
+ 'Select' => [
+ [
+ 'choose' => [
+ 'type' => 'select',
+ 'options' => [
+ 'foo' => wfMessage( 'mainpage' ),
+ 'bar' => wfMessage( 'mainpage' ),
+ ],
+ ],
+ ],
+ $data = [ 'choose' => 'foo' ],
+ $data
+ ],
+ 'Select, invalid choice' => [
+ [
+ 'choose' => [
+ 'type' => 'select',
+ 'options' => [
+ 'foo' => wfMessage( 'mainpage' ),
+ 'bar' => wfMessage( 'mainpage' ),
+ ],
+ ],
+ ],
+ $data = [ 'choose' => 'baz' ],
+ false
+ ],
+ 'Multiselect (2)' => [
+ [
+ 'choose' => [
+ 'type' => 'multiselect',
+ 'options' => [
+ 'foo' => wfMessage( 'mainpage' ),
+ 'bar' => wfMessage( 'mainpage' ),
+ ],
+ ],
+ ],
+ $data = [ 'choose' => [ 'foo', 'bar' ] ],
+ $data
+ ],
+ 'Multiselect (1)' => [
+ [
+ 'choose' => [
+ 'type' => 'multiselect',
+ 'options' => [
+ 'foo' => wfMessage( 'mainpage' ),
+ 'bar' => wfMessage( 'mainpage' ),
+ ],
+ ],
+ ],
+ $data = [ 'choose' => [ 'bar' ] ],
+ $data
+ ],
+ 'Multiselect, string for some reason' => [
+ [
+ 'choose' => [
+ 'type' => 'multiselect',
+ 'options' => [
+ 'foo' => wfMessage( 'mainpage' ),
+ 'bar' => wfMessage( 'mainpage' ),
+ ],
+ ],
+ ],
+ [ 'choose' => 'foo' ],
+ [ 'choose' => [ 'foo' ] ]
+ ],
+ 'Multiselect, invalid choice' => [
+ [
+ 'choose' => [
+ 'type' => 'multiselect',
+ 'options' => [
+ 'foo' => wfMessage( 'mainpage' ),
+ 'bar' => wfMessage( 'mainpage' ),
+ ],
+ ],
+ ],
+ [ 'choose' => [ 'foo', 'baz' ] ],
+ false
+ ],
+ 'Multiselect, empty' => [
+ [
+ 'choose' => [
+ 'type' => 'multiselect',
+ 'options' => [
+ 'foo' => wfMessage( 'mainpage' ),
+ 'bar' => wfMessage( 'mainpage' ),
+ ],
+ ],
+ ],
+ [ 'choose' => [] ],
+ false
+ ],
+ 'Multiselect, optional, nothing submitted' => [
+ [
+ 'choose' => [
+ 'type' => 'multiselect',
+ 'options' => [
+ 'foo' => wfMessage( 'mainpage' ),
+ 'bar' => wfMessage( 'mainpage' ),
+ ],
+ 'optional' => true,
+ ],
+ ],
+ [],
+ [ 'choose' => [] ]
+ ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ */
+abstract class AuthenticationRequestTestCase extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ abstract protected function getInstance( array $args = [] );
+
+ /**
+ * @dataProvider provideGetFieldInfo
+ */
+ public function testGetFieldInfo( array $args ) {
+ $info = $this->getInstance( $args )->getFieldInfo();
+ $this->assertType( 'array', $info );
+
+ foreach ( $info as $field => $data ) {
+ $this->assertType( 'array', $data, "Field $field" );
+ $this->assertArrayHasKey( 'type', $data, "Field $field" );
+ $this->assertArrayHasKey( 'label', $data, "Field $field" );
+ $this->assertInstanceOf( 'Message', $data['label'], "Field $field, label" );
+
+ if ( $data['type'] !== 'null' ) {
+ $this->assertArrayHasKey( 'help', $data, "Field $field" );
+ $this->assertInstanceOf( 'Message', $data['help'], "Field $field, help" );
+ }
+
+ if ( isset( $data['optional'] ) ) {
+ $this->assertType( 'bool', $data['optional'], "Field $field, optional" );
+ }
+ if ( isset( $data['image'] ) ) {
+ $this->assertType( 'string', $data['image'], "Field $field, image" );
+ }
+
+ switch ( $data['type'] ) {
+ case 'string':
+ case 'password':
+ case 'hidden':
+ break;
+ case 'select':
+ case 'multiselect':
+ $this->assertArrayHasKey( 'options', $data, "Field $field" );
+ $this->assertType( 'array', $data['options'], "Field $field, options" );
+ foreach ( $data['options'] as $val => $msg ) {
+ $this->assertInstanceOf( 'Message', $msg, "Field $field, option $val" );
+ }
+ break;
+ case 'checkbox':
+ break;
+ case 'button':
+ break;
+ case 'null':
+ break;
+ default:
+ $this->fail( "Field $field, unknown type " . $data['type'] );
+ break;
+ }
+ }
+ }
+
+ public static function provideGetFieldInfo() {
+ return [
+ [ [] ]
+ ];
+ }
+
+ /**
+ * @dataProvider provideLoadFromSubmission
+ * @param array $args
+ * @param array $data
+ * @param array|bool $expectState
+ */
+ public function testLoadFromSubmission( array $args, array $data, $expectState ) {
+ $instance = $this->getInstance( $args );
+ $ret = $instance->loadFromSubmission( $data );
+ if ( is_array( $expectState ) ) {
+ $this->assertTrue( $ret );
+ $expect = call_user_func( [ get_class( $instance ), '__set_state' ], $expectState );
+ $this->assertEquals( $expect, $instance );
+ } else {
+ $this->assertFalse( $ret );
+ }
+ }
+
+ abstract public function provideLoadFromSubmission();
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\AuthenticationResponse
+ */
+class AuthenticationResponseTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ /**
+ * @dataProvider provideConstructors
+ * @param string $constructor
+ * @param array $args
+ * @param array|Exception $expect
+ */
+ public function testConstructors( $constructor, $args, $expect ) {
+ if ( is_array( $expect ) ) {
+ $res = new AuthenticationResponse();
+ foreach ( $expect as $field => $value ) {
+ $res->$field = $value;
+ }
+ $ret = call_user_func_array( "MediaWiki\\Auth\\AuthenticationResponse::$constructor", $args );
+ $this->assertEquals( $res, $ret );
+ } else {
+ try {
+ call_user_func_array( "MediaWiki\\Auth\\AuthenticationResponse::$constructor", $args );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \Exception $ex ) {
+ $this->assertEquals( $expect, $ex );
+ }
+ }
+ }
+
+ public function provideConstructors() {
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ $msg = new \Message( 'mainpage' );
+
+ return [
+ [ 'newPass', [], [
+ 'status' => AuthenticationResponse::PASS,
+ ] ],
+ [ 'newPass', [ 'name' ], [
+ 'status' => AuthenticationResponse::PASS,
+ 'username' => 'name',
+ ] ],
+ [ 'newPass', [ 'name', null ], [
+ 'status' => AuthenticationResponse::PASS,
+ 'username' => 'name',
+ ] ],
+
+ [ 'newFail', [ $msg ], [
+ 'status' => AuthenticationResponse::FAIL,
+ 'message' => $msg,
+ ] ],
+
+ [ 'newRestart', [ $msg ], [
+ 'status' => AuthenticationResponse::RESTART,
+ 'message' => $msg,
+ ] ],
+
+ [ 'newAbstain', [], [
+ 'status' => AuthenticationResponse::ABSTAIN,
+ ] ],
+
+ [ 'newUI', [ [ $req ], $msg ], [
+ 'status' => AuthenticationResponse::UI,
+ 'neededRequests' => [ $req ],
+ 'message' => $msg,
+ ] ],
+ [ 'newUI', [ [], $msg ],
+ new \InvalidArgumentException( '$reqs may not be empty' )
+ ],
+
+ [ 'newRedirect', [ [ $req ], 'http://example.org/redir' ], [
+ 'status' => AuthenticationResponse::REDIRECT,
+ 'neededRequests' => [ $req ],
+ 'redirectTarget' => 'http://example.org/redir',
+ ] ],
+ [
+ 'newRedirect',
+ [ [ $req ], 'http://example.org/redir', [ 'foo' => 'bar' ] ],
+ [
+ 'status' => AuthenticationResponse::REDIRECT,
+ 'neededRequests' => [ $req ],
+ 'redirectTarget' => 'http://example.org/redir',
+ 'redirectApiData' => [ 'foo' => 'bar' ],
+ ]
+ ],
+ [ 'newRedirect', [ [], 'http://example.org/redir' ],
+ new \InvalidArgumentException( '$reqs may not be empty' )
+ ],
+ ];
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\ButtonAuthenticationRequest
+ */
+class ButtonAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ $data = array_intersect_key( $args, [ 'name' => 1, 'label' => 1, 'help' => 1 ] );
+ return ButtonAuthenticationRequest::__set_state( $data );
+ }
+
+ public static function provideGetFieldInfo() {
+ return [
+ [ [ 'name' => 'foo', 'label' => 'bar', 'help' => 'baz' ] ]
+ ];
+ }
+
+ public function provideLoadFromSubmission() {
+ return [
+ 'Empty request' => [
+ [ 'name' => 'foo', 'label' => 'bar', 'help' => 'baz' ],
+ [],
+ false
+ ],
+ 'Button present' => [
+ [ 'name' => 'foo', 'label' => 'bar', 'help' => 'baz' ],
+ [ 'foo' => 'Foobar' ],
+ [ 'name' => 'foo', 'label' => 'bar', 'help' => 'baz', 'foo' => true ]
+ ],
+ ];
+ }
+
+ public function testGetUniqueId() {
+ $req = new ButtonAuthenticationRequest( 'foo', wfMessage( 'bar' ), wfMessage( 'baz' ) );
+ $this->assertSame(
+ 'MediaWiki\\Auth\\ButtonAuthenticationRequest:foo', $req->getUniqueId()
+ );
+ }
+
+ public function testGetRequestByName() {
+ $reqs = [];
+ $reqs['testOne'] = new ButtonAuthenticationRequest(
+ 'foo', wfMessage( 'msg' ), wfMessage( 'help' )
+ );
+ $reqs[] = new ButtonAuthenticationRequest( 'bar', wfMessage( 'msg1' ), wfMessage( 'help1' ) );
+ $reqs[] = new ButtonAuthenticationRequest( 'bar', wfMessage( 'msg2' ), wfMessage( 'help2' ) );
+ $reqs['testSub'] = $this->getMockBuilder( ButtonAuthenticationRequest::class )
+ ->setConstructorArgs( [ 'subclass', wfMessage( 'msg3' ), wfMessage( 'help3' ) ] )
+ ->getMock();
+
+ $this->assertNull( ButtonAuthenticationRequest::getRequestByName( $reqs, 'missing' ) );
+ $this->assertSame(
+ $reqs['testOne'], ButtonAuthenticationRequest::getRequestByName( $reqs, 'foo' )
+ );
+ $this->assertNull( ButtonAuthenticationRequest::getRequestByName( $reqs, 'bar' ) );
+ $this->assertSame(
+ $reqs['testSub'], ButtonAuthenticationRequest::getRequestByName( $reqs, 'subclass' )
+ );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @group Database
+ * @covers MediaWiki\Auth\CheckBlocksSecondaryAuthenticationProvider
+ */
+class CheckBlocksSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testConstructor() {
+ $provider = new CheckBlocksSecondaryAuthenticationProvider();
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+ $config = new \HashConfig( [
+ 'BlockDisablesLogin' => false
+ ] );
+ $provider->setConfig( $config );
+ $this->assertSame( false, $providerPriv->blockDisablesLogin );
+
+ $provider = new CheckBlocksSecondaryAuthenticationProvider(
+ [ 'blockDisablesLogin' => true ]
+ );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+ $config = new \HashConfig( [
+ 'BlockDisablesLogin' => false
+ ] );
+ $provider->setConfig( $config );
+ $this->assertSame( true, $providerPriv->blockDisablesLogin );
+ }
+
+ public function testBasics() {
+ $provider = new CheckBlocksSecondaryAuthenticationProvider();
+ $user = \User::newFromName( 'UTSysop' );
+
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginSecondaryAccountCreation( $user, $user, [] )
+ );
+ }
+
+ /**
+ * @dataProvider provideGetAuthenticationRequests
+ * @param string $action
+ * @param array $response
+ */
+ public function testGetAuthenticationRequests( $action, $response ) {
+ $provider = new CheckBlocksSecondaryAuthenticationProvider();
+
+ $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
+ }
+
+ public static function provideGetAuthenticationRequests() {
+ return [
+ [ AuthManager::ACTION_LOGIN, [] ],
+ [ AuthManager::ACTION_CREATE, [] ],
+ [ AuthManager::ACTION_LINK, [] ],
+ [ AuthManager::ACTION_CHANGE, [] ],
+ [ AuthManager::ACTION_REMOVE, [] ],
+ ];
+ }
+
+ private function getBlockedUser() {
+ $user = \User::newFromName( 'UTBlockee' );
+ if ( $user->getID() == 0 ) {
+ $user->addToDatabase();
+ \TestUser::setPasswordForUser( $user, 'UTBlockeePassword' );
+ $user->saveSettings();
+ }
+ $oldBlock = \Block::newFromTarget( 'UTBlockee' );
+ if ( $oldBlock ) {
+ // An old block will prevent our new one from saving.
+ $oldBlock->delete();
+ }
+ $blockOptions = [
+ 'address' => 'UTBlockee',
+ 'user' => $user->getID(),
+ 'reason' => __METHOD__,
+ 'expiry' => time() + 100500,
+ 'createAccount' => true,
+ ];
+ $block = new \Block( $blockOptions );
+ $block->insert();
+ return $user;
+ }
+
+ public function testBeginSecondaryAuthentication() {
+ $unblockedUser = \User::newFromName( 'UTSysop' );
+ $blockedUser = $this->getBlockedUser();
+
+ $provider = new CheckBlocksSecondaryAuthenticationProvider(
+ [ 'blockDisablesLogin' => false ]
+ );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginSecondaryAuthentication( $unblockedUser, [] )
+ );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginSecondaryAuthentication( $blockedUser, [] )
+ );
+
+ $provider = new CheckBlocksSecondaryAuthenticationProvider(
+ [ 'blockDisablesLogin' => true ]
+ );
+ $this->assertEquals(
+ AuthenticationResponse::newPass(),
+ $provider->beginSecondaryAuthentication( $unblockedUser, [] )
+ );
+ $ret = $provider->beginSecondaryAuthentication( $blockedUser, [] );
+ $this->assertEquals( AuthenticationResponse::FAIL, $ret->status );
+ }
+
+ public function testTestUserForCreation() {
+ $provider = new CheckBlocksSecondaryAuthenticationProvider(
+ [ 'blockDisablesLogin' => false ]
+ );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setConfig( new \HashConfig() );
+ $provider->setManager( AuthManager::singleton() );
+
+ $unblockedUser = \User::newFromName( 'UTSysop' );
+ $blockedUser = $this->getBlockedUser();
+
+ $user = \User::newFromName( 'RandomUser' );
+
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testUserForCreation( $unblockedUser, AuthManager::AUTOCREATE_SOURCE_SESSION )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testUserForCreation( $unblockedUser, false )
+ );
+
+ $status = $provider->testUserForCreation( $blockedUser, AuthManager::AUTOCREATE_SOURCE_SESSION );
+ $this->assertInstanceOf( 'StatusValue', $status );
+ $this->assertFalse( $status->isOK() );
+ $this->assertTrue( $status->hasMessage( 'cantcreateaccount-text' ) );
+
+ $status = $provider->testUserForCreation( $blockedUser, false );
+ $this->assertInstanceOf( 'StatusValue', $status );
+ $this->assertFalse( $status->isOK() );
+ $this->assertTrue( $status->hasMessage( 'cantcreateaccount-text' ) );
+ }
+
+ public function testRangeBlock() {
+ $blockOptions = [
+ 'address' => '127.0.0.0/24',
+ 'reason' => __METHOD__,
+ 'expiry' => time() + 100500,
+ 'createAccount' => true,
+ ];
+ $block = new \Block( $blockOptions );
+ $block->insert();
+ $scopeVariable = new \ScopedCallback( [ $block, 'delete' ] );
+
+ $user = \User::newFromName( 'UTNormalUser' );
+ if ( $user->getID() == 0 ) {
+ $user->addToDatabase();
+ \TestUser::setPasswordForUser( $user, 'UTNormalUserPassword' );
+ $user->saveSettings();
+ }
+ $this->setMwGlobals( [ 'wgUser' => $user ] );
+ $newuser = \User::newFromName( 'RandomUser' );
+
+ $provider = new CheckBlocksSecondaryAuthenticationProvider(
+ [ 'blockDisablesLogin' => true ]
+ );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setConfig( new \HashConfig() );
+ $provider->setManager( AuthManager::singleton() );
+
+ $ret = $provider->beginSecondaryAuthentication( $user, [] );
+ $this->assertEquals( AuthenticationResponse::FAIL, $ret->status );
+
+ $status = $provider->testUserForCreation( $newuser, AuthManager::AUTOCREATE_SOURCE_SESSION );
+ $this->assertInstanceOf( 'StatusValue', $status );
+ $this->assertFalse( $status->isOK() );
+ $this->assertTrue( $status->hasMessage( 'cantcreateaccount-range-text' ) );
+
+ $status = $provider->testUserForCreation( $newuser, false );
+ $this->assertInstanceOf( 'StatusValue', $status );
+ $this->assertFalse( $status->isOK() );
+ $this->assertTrue( $status->hasMessage( 'cantcreateaccount-range-text' ) );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+use InvalidArgumentException;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\ConfirmLinkAuthenticationRequest
+ */
+class ConfirmLinkAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ return new ConfirmLinkAuthenticationRequest( $this->getLinkRequests() );
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage $linkRequests must not be empty
+ */
+ public function testConstructorException() {
+ new ConfirmLinkAuthenticationRequest( [] );
+ }
+
+ /**
+ * Get requests for testing
+ * @return AuthenticationRequest[]
+ */
+ private function getLinkRequests() {
+ $reqs = [];
+
+ $mb = $this->getMockBuilder( AuthenticationRequest::class )
+ ->setMethods( [ 'getUniqueId' ] );
+ for ( $i = 1; $i <= 3; $i++ ) {
+ $req = $mb->getMockForAbstractClass();
+ $req->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( "Request$i" ) );
+ $reqs[$req->getUniqueId()] = $req;
+ }
+
+ return $reqs;
+ }
+
+ public function provideLoadFromSubmission() {
+ $reqs = $this->getLinkRequests();
+
+ return [
+ 'Empty request' => [
+ [],
+ [],
+ [ 'linkRequests' => $reqs ],
+ ],
+ 'Some confirmed' => [
+ [],
+ [ 'confirmedLinkIDs' => [ 'Request1', 'Request3' ] ],
+ [ 'confirmedLinkIDs' => [ 'Request1', 'Request3' ], 'linkRequests' => $reqs ],
+ ],
+ ];
+ }
+
+ public function testGetUniqueId() {
+ $req = new ConfirmLinkAuthenticationRequest( $this->getLinkRequests() );
+ $this->assertSame(
+ get_class( $req ) . ':Request1|Request2|Request3',
+ $req->getUniqueId()
+ );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider
+ */
+class ConfirmLinkSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ /**
+ * @dataProvider provideGetAuthenticationRequests
+ * @param string $action
+ * @param array $response
+ */
+ public function testGetAuthenticationRequests( $action, $response ) {
+ $provider = new ConfirmLinkSecondaryAuthenticationProvider();
+
+ $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
+ }
+
+ public static function provideGetAuthenticationRequests() {
+ return [
+ [ AuthManager::ACTION_LOGIN, [] ],
+ [ AuthManager::ACTION_CREATE, [] ],
+ [ AuthManager::ACTION_LINK, [] ],
+ [ AuthManager::ACTION_CHANGE, [] ],
+ [ AuthManager::ACTION_REMOVE, [] ],
+ ];
+ }
+
+ public function testBeginSecondaryAuthentication() {
+ $user = \User::newFromName( 'UTSysop' );
+ $obj = new \stdClass;
+
+ $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
+ ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
+ ->getMock();
+ $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
+ ->with( $this->identicalTo( $user ), $this->identicalTo( 'AuthManager::authnState' ) )
+ ->will( $this->returnValue( $obj ) );
+ $mock->expects( $this->never() )->method( 'continueLinkAttempt' );
+
+ $this->assertSame( $obj, $mock->beginSecondaryAuthentication( $user, [] ) );
+ }
+
+ public function testContinueSecondaryAuthentication() {
+ $user = \User::newFromName( 'UTSysop' );
+ $obj = new \stdClass;
+ $reqs = [ new \stdClass ];
+
+ $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
+ ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
+ ->getMock();
+ $mock->expects( $this->never() )->method( 'beginLinkAttempt' );
+ $mock->expects( $this->once() )->method( 'continueLinkAttempt' )
+ ->with(
+ $this->identicalTo( $user ),
+ $this->identicalTo( 'AuthManager::authnState' ),
+ $this->identicalTo( $reqs )
+ )
+ ->will( $this->returnValue( $obj ) );
+
+ $this->assertSame( $obj, $mock->continueSecondaryAuthentication( $user, $reqs ) );
+ }
+
+ public function testBeginSecondaryAccountCreation() {
+ $user = \User::newFromName( 'UTSysop' );
+ $obj = new \stdClass;
+
+ $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
+ ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
+ ->getMock();
+ $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
+ ->with( $this->identicalTo( $user ), $this->identicalTo( 'AuthManager::accountCreationState' ) )
+ ->will( $this->returnValue( $obj ) );
+ $mock->expects( $this->never() )->method( 'continueLinkAttempt' );
+
+ $this->assertSame( $obj, $mock->beginSecondaryAccountCreation( $user, $user, [] ) );
+ }
+
+ public function testContinueSecondaryAccountCreation() {
+ $user = \User::newFromName( 'UTSysop' );
+ $obj = new \stdClass;
+ $reqs = [ new \stdClass ];
+
+ $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
+ ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
+ ->getMock();
+ $mock->expects( $this->never() )->method( 'beginLinkAttempt' );
+ $mock->expects( $this->once() )->method( 'continueLinkAttempt' )
+ ->with(
+ $this->identicalTo( $user ),
+ $this->identicalTo( 'AuthManager::accountCreationState' ),
+ $this->identicalTo( $reqs )
+ )
+ ->will( $this->returnValue( $obj ) );
+
+ $this->assertSame( $obj, $mock->continueSecondaryAccountCreation( $user, $user, $reqs ) );
+ }
+
+ /**
+ * Get requests for testing
+ * @return AuthenticationRequest[]
+ */
+ private function getLinkRequests() {
+ $reqs = [];
+
+ $mb = $this->getMockBuilder( AuthenticationRequest::class )
+ ->setMethods( [ 'getUniqueId' ] );
+ for ( $i = 1; $i <= 3; $i++ ) {
+ $req = $mb->getMockForAbstractClass();
+ $req->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( "Request$i" ) );
+ $req->id = $i - 1;
+ $reqs[$req->getUniqueId()] = $req;
+ }
+
+ return $reqs;
+ }
+
+ public function testBeginLinkAttempt() {
+ $badReq = $this->getMockBuilder( AuthenticationRequest::class )
+ ->setMethods( [ 'getUniqueId' ] )
+ ->getMockForAbstractClass();
+ $badReq->expects( $this->any() )->method( 'getUniqueId' )
+ ->will( $this->returnValue( "BadReq" ) );
+
+ $user = \User::newFromName( 'UTSysop' );
+ $provider = \TestingAccessWrapper::newFromObject(
+ new ConfirmLinkSecondaryAuthenticationProvider
+ );
+ $request = new \FauxRequest();
+ $manager = $this->getMockBuilder( AuthManager::class )
+ ->setMethods( [ 'allowsAuthenticationDataChange' ] )
+ ->setConstructorArgs( [ $request, \RequestContext::getMain()->getConfig() ] )
+ ->getMock();
+ $manager->expects( $this->any() )->method( 'allowsAuthenticationDataChange' )
+ ->will( $this->returnCallback( function ( $req ) {
+ return $req->getUniqueId() !== 'BadReq'
+ ? \StatusValue::newGood()
+ : \StatusValue::newFatal( 'no' );
+ } ) );
+ $provider->setManager( $manager );
+
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginLinkAttempt( $user, 'state' )
+ );
+
+ $request->getSession()->setSecret( 'state', [
+ 'maybeLink' => [],
+ ] );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginLinkAttempt( $user, 'state' )
+ );
+
+ $reqs = $this->getLinkRequests();
+ $request->getSession()->setSecret( 'state', [
+ 'maybeLink' => $reqs + [ 'BadReq' => $badReq ]
+ ] );
+ $res = $provider->beginLinkAttempt( $user, 'state' );
+ $this->assertInstanceOf( AuthenticationResponse::class, $res );
+ $this->assertSame( AuthenticationResponse::UI, $res->status );
+ $this->assertSame( 'authprovider-confirmlink-message', $res->message->getKey() );
+ $this->assertCount( 1, $res->neededRequests );
+ $req = $res->neededRequests[0];
+ $this->assertInstanceOf( ConfirmLinkAuthenticationRequest::class, $req );
+ $this->assertEquals( $reqs, \TestingAccessWrapper::newFromObject( $req )->linkRequests );
+ }
+
+ public function testContinueLinkAttempt() {
+ $user = \User::newFromName( 'UTSysop' );
+ $obj = new \stdClass;
+ $reqs = $this->getLinkRequests();
+
+ $done = [ false, false, false ];
+
+ // First, test the pass-through for not containing the ConfirmLinkAuthenticationRequest
+ $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
+ ->setMethods( [ 'beginLinkAttempt' ] )
+ ->getMock();
+ $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
+ ->with( $this->identicalTo( $user ), $this->identicalTo( 'state' ) )
+ ->will( $this->returnValue( $obj ) );
+ $this->assertSame(
+ $obj,
+ \TestingAccessWrapper::newFromObject( $mock )->continueLinkAttempt( $user, 'state', $reqs )
+ );
+
+ // Now test the actual functioning
+ $provider = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
+ ->setMethods( [
+ 'beginLinkAttempt', 'providerAllowsAuthenticationDataChange',
+ 'providerChangeAuthenticationData'
+ ] )
+ ->getMock();
+ $provider->expects( $this->never() )->method( 'beginLinkAttempt' );
+ $provider->expects( $this->any() )->method( 'providerAllowsAuthenticationDataChange' )
+ ->will( $this->returnCallback( function ( $req ) use ( $reqs ) {
+ return $req->getUniqueId() === 'Request3'
+ ? \StatusValue::newFatal( 'foo' ) : \StatusValue::newGood();
+ } ) );
+ $provider->expects( $this->any() )->method( 'providerChangeAuthenticationData' )
+ ->will( $this->returnCallback( function ( $req ) use ( &$done ) {
+ $done[$req->id] = true;
+ } ) );
+ $config = new \HashConfig( [
+ 'AuthManagerConfig' => [
+ 'preauth' => [],
+ 'primaryauth' => [],
+ 'secondaryauth' => [
+ [ 'factory' => function () use ( $provider ) {
+ return $provider;
+ } ],
+ ],
+ ],
+ ] );
+ $request = new \FauxRequest();
+ $manager = new AuthManager( $request, $config );
+ $provider->setManager( $manager );
+ $provider = \TestingAccessWrapper::newFromObject( $provider );
+
+ $req = new ConfirmLinkAuthenticationRequest( $reqs );
+
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->continueLinkAttempt( $user, 'state', [ $req ] )
+ );
+
+ $request->getSession()->setSecret( 'state', [
+ 'maybeLink' => [],
+ ] );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->continueLinkAttempt( $user, 'state', [ $req ] )
+ );
+
+ $request->getSession()->setSecret( 'state', [
+ 'maybeLink' => $reqs
+ ] );
+ $this->assertEquals(
+ AuthenticationResponse::newPass(),
+ $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] )
+ );
+ $this->assertSame( [ false, false, false ], $done );
+
+ $request->getSession()->setSecret( 'state', [
+ 'maybeLink' => [ $reqs['Request2'] ],
+ ] );
+ $req->confirmedLinkIDs = [ 'Request1', 'Request2' ];
+ $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
+ $this->assertEquals( AuthenticationResponse::newPass(), $res );
+ $this->assertSame( [ false, true, false ], $done );
+ $done = [ false, false, false ];
+
+ $request->getSession()->setSecret( 'state', [
+ 'maybeLink' => $reqs,
+ ] );
+ $req->confirmedLinkIDs = [ 'Request1', 'Request2' ];
+ $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
+ $this->assertEquals( AuthenticationResponse::newPass(), $res );
+ $this->assertSame( [ true, true, false ], $done );
+ $done = [ false, false, false ];
+
+ $request->getSession()->setSecret( 'state', [
+ 'maybeLink' => $reqs,
+ ] );
+ $req->confirmedLinkIDs = [ 'Request1', 'Request3' ];
+ $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
+ $this->assertEquals( AuthenticationResponse::UI, $res->status );
+ $this->assertCount( 1, $res->neededRequests );
+ $this->assertInstanceOf( ButtonAuthenticationRequest::class, $res->neededRequests[0] );
+ $this->assertSame( [ true, false, false ], $done );
+ $done = [ false, false, false ];
+
+ $res = $provider->continueLinkAttempt( $user, 'state', [ $res->neededRequests[0] ] );
+ $this->assertEquals( AuthenticationResponse::newPass(), $res );
+ $this->assertSame( [ false, false, false ], $done );
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\CreateFromLoginAuthenticationRequest
+ */
+class CreateFromLoginAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ return new CreateFromLoginAuthenticationRequest(
+ null, []
+ );
+ }
+
+ public function provideLoadFromSubmission() {
+ return [
+ 'Empty request' => [
+ [],
+ [],
+ [],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideState
+ */
+ public function testState(
+ $createReq, $maybeLink, $username, $loginState, $createState, $createPrimaryState
+ ) {
+ $req = new CreateFromLoginAuthenticationRequest( $createReq, $maybeLink );
+ $this->assertSame( $username, $req->username );
+ $this->assertSame( $loginState, $req->hasStateForAction( AuthManager::ACTION_LOGIN ) );
+ $this->assertSame( $createState, $req->hasStateForAction( AuthManager::ACTION_CREATE ) );
+ $this->assertFalse( $req->hasStateForAction( AuthManager::ACTION_LINK ) );
+ $this->assertFalse( $req->hasPrimaryStateForAction( AuthManager::ACTION_LOGIN ) );
+ $this->assertSame( $createPrimaryState,
+ $req->hasPrimaryStateForAction( AuthManager::ACTION_CREATE ) );
+ }
+
+ public static function provideState() {
+ $req1 = new UsernameAuthenticationRequest;
+ $req2 = new UsernameAuthenticationRequest;
+ $req2->username = 'Bob';
+
+ return [
+ 'Nothing' => [ null, [], null, false, false, false ],
+ 'Link, no create' => [ null, [ $req2 ], null, true, true, false ],
+ 'No link, create but no name' => [ $req1, [], null, false, true, true ],
+ 'Link and create but no name' => [ $req1, [ $req2 ], null, true, true, true ],
+ 'No link, create with name' => [ $req2, [], 'Bob', false, true, true ],
+ 'Link and create with name' => [ $req2, [ $req2 ], 'Bob', true, true, true ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\CreatedAccountAuthenticationRequest
+ */
+class CreatedAccountAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ return new CreatedAccountAuthenticationRequest( 42, 'Test' );
+ }
+
+ public function testConstructor() {
+ $ret = new CreatedAccountAuthenticationRequest( 42, 'Test' );
+ $this->assertSame( 42, $ret->id );
+ $this->assertSame( 'Test', $ret->username );
+ }
+
+ public function provideLoadFromSubmission() {
+ return [
+ 'Empty request' => [
+ [],
+ [],
+ false
+ ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\CreationReasonAuthenticationRequest
+ */
+class CreationReasonAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ return new CreationReasonAuthenticationRequest();
+ }
+
+ public function provideLoadFromSubmission() {
+ return [
+ 'Empty request' => [
+ [],
+ [],
+ false
+ ],
+ 'Reason given' => [
+ [],
+ $data = [ 'reason' => 'Because' ],
+ $data,
+ ],
+ 'Reason empty' => [
+ [],
+ [ 'reason' => '' ],
+ false
+ ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+use Psr\Log\LoggerInterface;
+
+class EmailNotificationSecondaryAuthenticationProviderTest extends \PHPUnit_Framework_TestCase {
+ public function testConstructor() {
+ $config = new \HashConfig( [
+ 'EnableEmail' => true,
+ 'EmailAuthentication' => true,
+ ] );
+
+ $provider = new EmailNotificationSecondaryAuthenticationProvider();
+ $provider->setConfig( $config );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+ $this->assertTrue( $providerPriv->sendConfirmationEmail );
+
+ $provider = new EmailNotificationSecondaryAuthenticationProvider( [
+ 'sendConfirmationEmail' => false,
+ ] );
+ $provider->setConfig( $config );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+ $this->assertFalse( $providerPriv->sendConfirmationEmail );
+ }
+
+ /**
+ * @dataProvider provideGetAuthenticationRequests
+ * @param string $action
+ * @param AuthenticationRequest[] $expected
+ */
+ public function testGetAuthenticationRequests( $action, $expected ) {
+ $provider = new EmailNotificationSecondaryAuthenticationProvider( [
+ 'sendConfirmationEmail' => true,
+ ] );
+ $this->assertSame( $expected, $provider->getAuthenticationRequests( $action, [] ) );
+ }
+
+ public function provideGetAuthenticationRequests() {
+ return [
+ [ AuthManager::ACTION_LOGIN, [] ],
+ [ AuthManager::ACTION_CREATE, [] ],
+ [ AuthManager::ACTION_LINK, [] ],
+ [ AuthManager::ACTION_CHANGE, [] ],
+ [ AuthManager::ACTION_REMOVE, [] ],
+ ];
+ }
+
+ public function testBeginSecondaryAuthentication() {
+ $provider = new EmailNotificationSecondaryAuthenticationProvider( [
+ 'sendConfirmationEmail' => true,
+ ] );
+ $this->assertEquals( AuthenticationResponse::newAbstain(),
+ $provider->beginSecondaryAuthentication( \User::newFromName( 'Foo' ), [] ) );
+ }
+
+ public function testBeginSecondaryAccountCreation() {
+ $authManager = new AuthManager( new \FauxRequest(), new \HashConfig() );
+
+ $creator = $this->getMock( 'User' );
+ $userWithoutEmail = $this->getMock( 'User' );
+ $userWithoutEmail->expects( $this->any() )->method( 'getEmail' )->willReturn( '' );
+ $userWithoutEmail->expects( $this->never() )->method( 'sendConfirmationMail' );
+ $userWithEmailError = $this->getMock( 'User' );
+ $userWithEmailError->expects( $this->any() )->method( 'getEmail' )->willReturn( 'foo@bar.baz' );
+ $userWithEmailError->expects( $this->any() )->method( 'sendConfirmationMail' )
+ ->willReturn( \Status::newFatal( 'fail' ) );
+ $userExpectsConfirmation = $this->getMock( 'User' );
+ $userExpectsConfirmation->expects( $this->any() )->method( 'getEmail' )
+ ->willReturn( 'foo@bar.baz' );
+ $userExpectsConfirmation->expects( $this->once() )->method( 'sendConfirmationMail' )
+ ->willReturn( \Status::newGood() );
+ $userNotExpectsConfirmation = $this->getMock( 'User' );
+ $userNotExpectsConfirmation->expects( $this->any() )->method( 'getEmail' )
+ ->willReturn( 'foo@bar.baz' );
+ $userNotExpectsConfirmation->expects( $this->never() )->method( 'sendConfirmationMail' );
+
+ $provider = new EmailNotificationSecondaryAuthenticationProvider( [
+ 'sendConfirmationEmail' => false,
+ ] );
+ $provider->setManager( $authManager );
+ $provider->beginSecondaryAccountCreation( $userNotExpectsConfirmation, $creator, [] );
+
+ $provider = new EmailNotificationSecondaryAuthenticationProvider( [
+ 'sendConfirmationEmail' => true,
+ ] );
+ $provider->setManager( $authManager );
+ $provider->beginSecondaryAccountCreation( $userWithoutEmail, $creator, [] );
+ $provider->beginSecondaryAccountCreation( $userExpectsConfirmation, $creator, [] );
+
+ // test logging of email errors
+ $logger = $this->getMockForAbstractClass( LoggerInterface::class );
+ $logger->expects( $this->once() )->method( 'warning' );
+ $provider->setLogger( $logger );
+ $provider->beginSecondaryAccountCreation( $userWithEmailError, $creator, [] );
+
+ // test disable flag used by other providers
+ $authManager->setAuthenticationSessionData( 'no-email', true );
+ $provider->setManager( $authManager );
+ $provider->beginSecondaryAccountCreation( $userNotExpectsConfirmation, $creator, [] );
+
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @group Database
+ * @covers MediaWiki\Auth\LegacyHookPreAuthenticationProvider
+ */
+class LegacyHookPreAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ /**
+ * Get an instance of the provider
+ * @return LegacyHookPreAuthenticationProvider
+ */
+ protected function getProvider() {
+ $request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
+ $request->expects( $this->any() )->method( 'getIP' )->will( $this->returnValue( '127.0.0.42' ) );
+
+ $manager = new AuthManager(
+ $request, \ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
+ );
+
+ $provider = new LegacyHookPreAuthenticationProvider();
+ $provider->setManager( $manager );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setConfig( new \HashConfig( [
+ 'PasswordAttemptThrottle' => [ 'count' => 23, 'seconds' => 42 ],
+ ] ) );
+ return $provider;
+ }
+
+ /**
+ * Sets a mock on a hook
+ * @param string $hook
+ * @param object $expect From $this->once(), $this->never(), etc.
+ * @return object $mock->expects( $expect )->method( ... ).
+ */
+ protected function hook( $hook, $expect ) {
+ $mock = $this->getMock( __CLASS__, [ "on$hook" ] );
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [
+ $hook => [ $mock ],
+ ] );
+ return $mock->expects( $expect )->method( "on$hook" );
+ }
+
+ /**
+ * Unsets a hook
+ * @param string $hook
+ */
+ protected function unhook( $hook ) {
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [
+ $hook => [],
+ ] );
+ }
+
+ // Stubs for hooks taking reference parameters
+ public function onLoginUserMigrated( $user, &$msg ) {
+ }
+ public function onAbortLogin( $user, $password, &$abort, &$msg ) {
+ }
+ public function onAbortNewAccount( $user, &$abortError, &$abortStatus ) {
+ }
+ public function onAbortAutoAccount( $user, &$abortError ) {
+ }
+
+ /**
+ * @dataProvider provideTestForAuthentication
+ * @param string|null $username
+ * @param string|null $password
+ * @param string|null $msgForLoginUserMigrated
+ * @param int|null $abortForAbortLogin
+ * @param string|null $msgForAbortLogin
+ * @param string|null $failMsg
+ * @param array $failParams
+ */
+ public function testTestForAuthentication(
+ $username, $password,
+ $msgForLoginUserMigrated, $abortForAbortLogin, $msgForAbortLogin,
+ $failMsg, $failParams = []
+ ) {
+ $reqs = [];
+ if ( $username === null ) {
+ $this->hook( 'LoginUserMigrated', $this->never() );
+ $this->hook( 'AbortLogin', $this->never() );
+ } else {
+ if ( $password === null ) {
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ } else {
+ $req = new PasswordAuthenticationRequest();
+ $req->action = AuthManager::ACTION_LOGIN;
+ $req->password = $password;
+ }
+ $req->username = $username;
+ $reqs[get_class( $req )] = $req;
+
+ $h = $this->hook( 'LoginUserMigrated', $this->once() );
+ if ( $msgForLoginUserMigrated !== null ) {
+ $h->will( $this->returnCallback(
+ function ( $user, &$msg ) use ( $username, $msgForLoginUserMigrated ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( $username, $user->getName() );
+ $msg = $msgForLoginUserMigrated;
+ return false;
+ }
+ ) );
+ $this->hook( 'AbortLogin', $this->never() );
+ } else {
+ $h->will( $this->returnCallback(
+ function ( $user, &$msg ) use ( $username ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( $username, $user->getName() );
+ return true;
+ }
+ ) );
+ $h2 = $this->hook( 'AbortLogin', $this->once() );
+ if ( $abortForAbortLogin !== null ) {
+ $h2->will( $this->returnCallback(
+ function ( $user, $pass, &$abort, &$msg )
+ use ( $username, $password, $abortForAbortLogin, $msgForAbortLogin )
+ {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( $username, $user->getName() );
+ if ( $password !== null ) {
+ $this->assertSame( $password, $pass );
+ } else {
+ $this->assertInternalType( 'string', $pass );
+ }
+ $abort = $abortForAbortLogin;
+ $msg = $msgForAbortLogin;
+ return false;
+ }
+ ) );
+ } else {
+ $h2->will( $this->returnCallback(
+ function ( $user, $pass, &$abort, &$msg ) use ( $username, $password ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( $username, $user->getName() );
+ if ( $password !== null ) {
+ $this->assertSame( $password, $pass );
+ } else {
+ $this->assertInternalType( 'string', $pass );
+ }
+ return true;
+ }
+ ) );
+ }
+ }
+ }
+ unset( $h, $h2 );
+
+ $status = $this->getProvider()->testForAuthentication( $reqs );
+
+ $this->unhook( 'LoginUserMigrated' );
+ $this->unhook( 'AbortLogin' );
+
+ if ( $failMsg === null ) {
+ $this->assertEquals( \StatusValue::newGood(), $status, 'should succeed' );
+ } else {
+ $this->assertInstanceOf( 'StatusValue', $status, 'should fail (type)' );
+ $this->assertFalse( $status->isOk(), 'should fail (ok)' );
+ $errors = $status->getErrors();
+ $this->assertEquals( $failMsg, $errors[0]['message'], 'should fail (message)' );
+ $this->assertEquals( $failParams, $errors[0]['params'], 'should fail (params)' );
+ }
+ }
+
+ public static function provideTestForAuthentication() {
+ return [
+ 'No valid requests' => [
+ null, null, null, null, null, null
+ ],
+ 'No hook errors' => [
+ 'User', 'PaSsWoRd', null, null, null, null
+ ],
+ 'No hook errors, no password' => [
+ 'User', null, null, null, null, null
+ ],
+ 'LoginUserMigrated no message' => [
+ 'User', 'PaSsWoRd', false, null, null, 'login-migrated-generic'
+ ],
+ 'LoginUserMigrated with message' => [
+ 'User', 'PaSsWoRd', 'LUM-abort', null, null, 'LUM-abort'
+ ],
+ 'LoginUserMigrated with message and params' => [
+ 'User', 'PaSsWoRd', [ 'LUM-abort', 'foo' ], null, null, 'LUM-abort', [ 'foo' ]
+ ],
+ 'AbortLogin, SUCCESS' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::SUCCESS, null, null
+ ],
+ 'AbortLogin, NEED_TOKEN, no message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::NEED_TOKEN, null, 'nocookiesforlogin'
+ ],
+ 'AbortLogin, NEED_TOKEN, with message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::NEED_TOKEN, 'needtoken', 'needtoken'
+ ],
+ 'AbortLogin, WRONG_TOKEN, no message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::WRONG_TOKEN, null, 'sessionfailure'
+ ],
+ 'AbortLogin, WRONG_TOKEN, with message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::WRONG_TOKEN, 'wrongtoken', 'wrongtoken'
+ ],
+ 'AbortLogin, ILLEGAL, no message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::ILLEGAL, null, 'noname'
+ ],
+ 'AbortLogin, ILLEGAL, with message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::ILLEGAL, 'badname', 'badname'
+ ],
+ 'AbortLogin, NO_NAME, no message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::NO_NAME, null, 'noname'
+ ],
+ 'AbortLogin, NO_NAME, with message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::NO_NAME, 'badname', 'badname'
+ ],
+ 'AbortLogin, WRONG_PASS, no message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::WRONG_PASS, null, 'wrongpassword'
+ ],
+ 'AbortLogin, WRONG_PASS, with message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::WRONG_PASS, 'badpass', 'badpass'
+ ],
+ 'AbortLogin, WRONG_PLUGIN_PASS, no message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::WRONG_PLUGIN_PASS, null, 'wrongpassword'
+ ],
+ 'AbortLogin, WRONG_PLUGIN_PASS, with message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::WRONG_PLUGIN_PASS, 'badpass', 'badpass'
+ ],
+ 'AbortLogin, NOT_EXISTS, no message' => [
+ "User'", 'A', null, \LoginForm::NOT_EXISTS, null, 'nosuchusershort', [ 'User'' ]
+ ],
+ 'AbortLogin, NOT_EXISTS, with message' => [
+ "User'", 'A', null, \LoginForm::NOT_EXISTS, 'badname', 'badname', [ 'User'' ]
+ ],
+ 'AbortLogin, EMPTY_PASS, no message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::EMPTY_PASS, null, 'wrongpasswordempty'
+ ],
+ 'AbortLogin, EMPTY_PASS, with message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::EMPTY_PASS, 'badpass', 'badpass'
+ ],
+ 'AbortLogin, RESET_PASS, no message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::RESET_PASS, null, 'resetpass_announce'
+ ],
+ 'AbortLogin, RESET_PASS, with message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::RESET_PASS, 'resetpass', 'resetpass'
+ ],
+ 'AbortLogin, THROTTLED, no message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::THROTTLED, null, 'login-throttled',
+ [ \Message::durationParam( 42 ) ]
+ ],
+ 'AbortLogin, THROTTLED, with message' => [
+ 'User', 'PaSsWoRd', null, \LoginForm::THROTTLED, 't', 't',
+ [ \Message::durationParam( 42 ) ]
+ ],
+ 'AbortLogin, USER_BLOCKED, no message' => [
+ "User'", 'P', null, \LoginForm::USER_BLOCKED, null, 'login-userblocked', [ 'User'' ]
+ ],
+ 'AbortLogin, USER_BLOCKED, with message' => [
+ "User'", 'P', null, \LoginForm::USER_BLOCKED, 'blocked', 'blocked', [ 'User'' ]
+ ],
+ 'AbortLogin, ABORTED, no message' => [
+ "User'", 'P', null, \LoginForm::ABORTED, null, 'login-abort-generic', [ 'User'' ]
+ ],
+ 'AbortLogin, ABORTED, with message' => [
+ "User'", 'P', null, \LoginForm::ABORTED, 'aborted', 'aborted', [ 'User'' ]
+ ],
+ 'AbortLogin, USER_MIGRATED, no message' => [
+ 'User', 'P', null, \LoginForm::USER_MIGRATED, null, 'login-migrated-generic'
+ ],
+ 'AbortLogin, USER_MIGRATED, with message' => [
+ 'User', 'P', null, \LoginForm::USER_MIGRATED, 'migrated', 'migrated'
+ ],
+ 'AbortLogin, USER_MIGRATED, with message and params' => [
+ 'User', 'P', null, \LoginForm::USER_MIGRATED, [ 'migrated', 'foo' ],
+ 'migrated', [ 'foo' ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideTestForAccountCreation
+ * @param string $msg
+ * @param Status|null $status
+ * @param StatusValue Result
+ */
+ public function testTestForAccountCreation( $msg, $status, $result ) {
+ $this->hook( 'AbortNewAccount', $this->once() )
+ ->will( $this->returnCallback( function ( $user, &$error, &$abortStatus )
+ use ( $msg, $status )
+ {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( 'User', $user->getName() );
+ $error = $msg;
+ $abortStatus = $status;
+ return $error === null && $status === null;
+ } ) );
+
+ $user = \User::newFromName( 'User' );
+ $creator = \User::newFromName( 'UTSysop' );
+ $ret = $this->getProvider()->testForAccountCreation( $user, $creator, [] );
+
+ $this->unhook( 'AbortNewAccount' );
+
+ $this->assertEquals( $result, $ret );
+ }
+
+ public static function provideTestForAccountCreation() {
+ return [
+ 'No hook errors' => [
+ null, null, \StatusValue::newGood()
+ ],
+ 'AbortNewAccount, old style' => [
+ 'foobar', null, \StatusValue::newFatal(
+ \Message::newFromKey( 'createaccount-hook-aborted' )->rawParams( 'foobar' )
+ )
+ ],
+ 'AbortNewAccount, new style' => [
+ 'foobar',
+ \Status::newFatal( 'aborted!', 'param' ),
+ \StatusValue::newFatal( 'aborted!', 'param' )
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideTestUserForCreation
+ * @param string|null $error
+ * @param string|null $failMsg
+ */
+ public function testTestUserForCreation( $error, $failMsg ) {
+ $this->hook( 'AbortNewAccount', $this->never() );
+ $this->hook( 'AbortAutoAccount', $this->once() )
+ ->will( $this->returnCallback( function ( $user, &$abortError ) use ( $error ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( 'UTSysop', $user->getName() );
+ $abortError = $error;
+ return $error === null;
+ } ) );
+
+ $status = $this->getProvider()->testUserForCreation(
+ \User::newFromName( 'UTSysop' ), AuthManager::AUTOCREATE_SOURCE_SESSION
+ );
+
+ $this->unhook( 'AbortNewAccount' );
+ $this->unhook( 'AbortAutoAccount' );
+
+ if ( $failMsg === null ) {
+ $this->assertEquals( \StatusValue::newGood(), $status, 'should succeed' );
+ } else {
+ $this->assertInstanceOf( 'StatusValue', $status, 'should fail (type)' );
+ $this->assertFalse( $status->isOk(), 'should fail (ok)' );
+ $errors = $status->getErrors();
+ $this->assertEquals( $failMsg, $errors[0]['message'], 'should fail (message)' );
+ }
+
+ $this->hook( 'AbortAutoAccount', $this->never() );
+ $this->hook( 'AbortNewAccount', $this->once() )
+ ->will( $this->returnCallback(
+ function ( $user, &$abortError, &$abortStatus ) use ( $error ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( 'UTSysop', $user->getName() );
+ $abortError = $error;
+ return $error === null;
+ }
+ ) );
+ $status = $this->getProvider()->testUserForCreation( \User::newFromName( 'UTSysop' ), false );
+ $this->unhook( 'AbortNewAccount' );
+ $this->unhook( 'AbortAutoAccount' );
+ if ( $failMsg === null ) {
+ $this->assertEquals( \StatusValue::newGood(), $status, 'should succeed' );
+ } else {
+ $this->assertInstanceOf( 'StatusValue', $status, 'should fail (type)' );
+ $this->assertFalse( $status->isOk(), 'should fail (ok)' );
+ $errors = $status->getErrors();
+ $msg = $errors[0]['message'];
+ $this->assertInstanceOf( \Message::class, $msg );
+ $this->assertEquals(
+ 'createaccount-hook-aborted', $msg->getKey(), 'should fail (message)'
+ );
+ }
+
+ if ( $error !== false ) {
+ $this->hook( 'AbortAutoAccount', $this->never() );
+ $this->hook( 'AbortNewAccount', $this->once() )
+ ->will( $this->returnCallback(
+ function ( $user, &$abortError, &$abortStatus ) use ( $error ) {
+ $this->assertInstanceOf( 'User', $user );
+ $this->assertSame( 'UTSysop', $user->getName() );
+ $abortStatus = $error ? \Status::newFatal( $error ) : \Status::newGood();
+ return $error === null;
+ }
+ ) );
+ $status = $this->getProvider()->testUserForCreation( \User::newFromName( 'UTSysop' ), false );
+ $this->unhook( 'AbortNewAccount' );
+ $this->unhook( 'AbortAutoAccount' );
+ if ( $failMsg === null ) {
+ $this->assertEquals( \StatusValue::newGood(), $status, 'should succeed' );
+ } else {
+ $this->assertInstanceOf( 'StatusValue', $status, 'should fail (type)' );
+ $this->assertFalse( $status->isOk(), 'should fail (ok)' );
+ $errors = $status->getErrors();
+ $this->assertEquals( $failMsg, $errors[0]['message'], 'should fail (message)' );
+ }
+ }
+ }
+
+ public static function provideTestUserForCreation() {
+ return [
+ 'Success' => [ null, null ],
+ 'Fail, no message' => [ false, 'login-abort-generic' ],
+ 'Fail, with message' => [ 'fail', 'fail' ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @group Database
+ * @covers MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider
+ */
+class LocalPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
+
+ private $manager = null;
+ private $config = null;
+ private $validity = null;
+
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ /**
+ * Get an instance of the provider
+ *
+ * $provider->checkPasswordValidity is mocked to return $this->validity,
+ * because we don't need to test that here.
+ *
+ * @param bool $loginOnly
+ * @return LocalPasswordPrimaryAuthenticationProvider
+ */
+ protected function getProvider( $loginOnly = false ) {
+ if ( !$this->config ) {
+ $this->config = new \HashConfig();
+ }
+ $config = new \MultiConfig( [
+ $this->config,
+ \ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
+ ] );
+
+ if ( !$this->manager ) {
+ $this->manager = new AuthManager( new \FauxRequest(), $config );
+ }
+ $this->validity = \Status::newGood();
+
+ $provider = $this->getMock(
+ LocalPasswordPrimaryAuthenticationProvider::class,
+ [ 'checkPasswordValidity' ],
+ [ [ 'loginOnly' => $loginOnly ] ]
+ );
+ $provider->expects( $this->any() )->method( 'checkPasswordValidity' )
+ ->will( $this->returnCallback( function () {
+ return $this->validity;
+ } ) );
+ $provider->setConfig( $config );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setManager( $this->manager );
+
+ return $provider;
+ }
+
+ public function testBasics() {
+ $user = $this->getMutableTestUser()->getUser();
+ $userName = $user->getName();
+ $lowerInitialUserName = mb_strtolower( $userName[0] ) . substr( $userName, 1 );
+
+ $provider = new LocalPasswordPrimaryAuthenticationProvider();
+
+ $this->assertSame(
+ PrimaryAuthenticationProvider::TYPE_CREATE,
+ $provider->accountCreationType()
+ );
+
+ $this->assertTrue( $provider->testUserExists( $userName ) );
+ $this->assertTrue( $provider->testUserExists( $lowerInitialUserName ) );
+ $this->assertFalse( $provider->testUserExists( 'DoesNotExist' ) );
+ $this->assertFalse( $provider->testUserExists( '<invalid>' ) );
+
+ $provider = new LocalPasswordPrimaryAuthenticationProvider( [ 'loginOnly' => true ] );
+
+ $this->assertSame(
+ PrimaryAuthenticationProvider::TYPE_NONE,
+ $provider->accountCreationType()
+ );
+
+ $this->assertTrue( $provider->testUserExists( $userName ) );
+ $this->assertFalse( $provider->testUserExists( 'DoesNotExist' ) );
+
+ $req = new PasswordAuthenticationRequest;
+ $req->action = AuthManager::ACTION_CHANGE;
+ $req->username = '<invalid>';
+ $provider->providerChangeAuthenticationData( $req );
+ }
+
+ public function testTestUserCanAuthenticate() {
+ $user = $this->getMutableTestUser()->getUser();
+ $userName = $user->getName();
+ $dbw = wfGetDB( DB_MASTER );
+
+ $provider = $this->getProvider();
+
+ $this->assertFalse( $provider->testUserCanAuthenticate( '<invalid>' ) );
+
+ $this->assertFalse( $provider->testUserCanAuthenticate( 'DoesNotExist' ) );
+
+ $this->assertTrue( $provider->testUserCanAuthenticate( $userName ) );
+ $lowerInitialUserName = mb_strtolower( $userName[0] ) . substr( $userName, 1 );
+ $this->assertTrue( $provider->testUserCanAuthenticate( $lowerInitialUserName ) );
+
+ $dbw->update(
+ 'user',
+ [ 'user_password' => \PasswordFactory::newInvalidPassword()->toString() ],
+ [ 'user_name' => $userName ]
+ );
+ $this->assertFalse( $provider->testUserCanAuthenticate( $userName ) );
+
+ // Really old format
+ $dbw->update(
+ 'user',
+ [ 'user_password' => '0123456789abcdef0123456789abcdef' ],
+ [ 'user_name' => $userName ]
+ );
+ $this->assertTrue( $provider->testUserCanAuthenticate( $userName ) );
+ }
+
+ public function testSetPasswordResetFlag() {
+ // Set instance vars
+ $this->getProvider();
+
+ /// @todo: Because we're currently using User, which uses the global config...
+ $this->setMwGlobals( [ 'wgPasswordExpireGrace' => 100 ] );
+
+ $this->config->set( 'PasswordExpireGrace', 100 );
+ $this->config->set( 'InvalidPasswordReset', true );
+
+ $provider = new LocalPasswordPrimaryAuthenticationProvider();
+ $provider->setConfig( $this->config );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setManager( $this->manager );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $user = $this->getMutableTestUser()->getUser();
+ $userName = $user->getName();
+ $dbw = wfGetDB( DB_MASTER );
+ $row = $dbw->selectRow(
+ 'user',
+ '*',
+ [ 'user_name' => $userName ],
+ __METHOD__
+ );
+
+ $this->manager->removeAuthenticationSessionData( null );
+ $row->user_password_expires = wfTimestamp( TS_MW, time() + 200 );
+ $providerPriv->setPasswordResetFlag( $userName, \Status::newGood(), $row );
+ $this->assertNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
+
+ $this->manager->removeAuthenticationSessionData( null );
+ $row->user_password_expires = wfTimestamp( TS_MW, time() - 200 );
+ $providerPriv->setPasswordResetFlag( $userName, \Status::newGood(), $row );
+ $ret = $this->manager->getAuthenticationSessionData( 'reset-pass' );
+ $this->assertNotNull( $ret );
+ $this->assertSame( 'resetpass-expired', $ret->msg->getKey() );
+ $this->assertTrue( $ret->hard );
+
+ $this->manager->removeAuthenticationSessionData( null );
+ $row->user_password_expires = wfTimestamp( TS_MW, time() - 1 );
+ $providerPriv->setPasswordResetFlag( $userName, \Status::newGood(), $row );
+ $ret = $this->manager->getAuthenticationSessionData( 'reset-pass' );
+ $this->assertNotNull( $ret );
+ $this->assertSame( 'resetpass-expired-soft', $ret->msg->getKey() );
+ $this->assertFalse( $ret->hard );
+
+ $this->manager->removeAuthenticationSessionData( null );
+ $row->user_password_expires = null;
+ $status = \Status::newGood();
+ $status->error( 'testing' );
+ $providerPriv->setPasswordResetFlag( $userName, $status, $row );
+ $ret = $this->manager->getAuthenticationSessionData( 'reset-pass' );
+ $this->assertNotNull( $ret );
+ $this->assertSame( 'resetpass-validity-soft', $ret->msg->getKey() );
+ $this->assertFalse( $ret->hard );
+ }
+
+ public function testAuthentication() {
+ $testUser = $this->getMutableTestUser();
+ $userName = $testUser->getUser()->getName();
+
+ $dbw = wfGetDB( DB_MASTER );
+ $id = \User::idFromName( $userName );
+
+ $req = new PasswordAuthenticationRequest();
+ $req->action = AuthManager::ACTION_LOGIN;
+ $reqs = [ PasswordAuthenticationRequest::class => $req ];
+
+ $provider = $this->getProvider();
+
+ // General failures
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( [] )
+ );
+
+ $req->username = 'foo';
+ $req->password = null;
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $req->username = null;
+ $req->password = 'bar';
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $req->username = '<invalid>';
+ $req->password = 'WhoCares';
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $req->username = 'DoesNotExist';
+ $req->password = 'DoesNotExist';
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ // Validation failure
+ $req->username = $userName;
+ $req->password = $testUser->getPassword();
+ $this->validity = \Status::newFatal( 'arbitrary-failure' );
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status
+ );
+ $this->assertEquals(
+ 'arbitrary-failure',
+ $ret->message->getKey()
+ );
+
+ // Successful auth
+ $this->manager->removeAuthenticationSessionData( null );
+ $this->validity = \Status::newGood();
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $userName ),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+ $this->assertNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
+
+ // Successful auth after normalizing name
+ $this->manager->removeAuthenticationSessionData( null );
+ $this->validity = \Status::newGood();
+ $req->username = mb_strtolower( $userName[0] ) . substr( $userName, 1 );
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $userName ),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+ $this->assertNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $req->username = $userName;
+
+ // Successful auth with reset
+ $this->manager->removeAuthenticationSessionData( null );
+ $this->validity->error( 'arbitrary-warning' );
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $userName ),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+ $this->assertNotNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
+
+ // Wrong password
+ $this->validity = \Status::newGood();
+ $req->password = 'Wrong';
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status
+ );
+ $this->assertEquals(
+ 'wrongpassword',
+ $ret->message->getKey()
+ );
+
+ // Correct handling of legacy encodings
+ $password = ':B:salt:' . md5( 'salt-' . md5( "\xe1\xe9\xed\xf3\xfa" ) );
+ $dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
+ $req->password = 'áéíóú';
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status
+ );
+ $this->assertEquals(
+ 'wrongpassword',
+ $ret->message->getKey()
+ );
+
+ $this->config->set( 'LegacyEncoding', true );
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $userName ),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $req->password = 'áéíóú Wrong';
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status
+ );
+ $this->assertEquals(
+ 'wrongpassword',
+ $ret->message->getKey()
+ );
+
+ // Correct handling of really old password hashes
+ $this->config->set( 'PasswordSalt', false );
+ $password = md5( 'FooBar' );
+ $dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
+ $req->password = 'FooBar';
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $userName ),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $this->config->set( 'PasswordSalt', true );
+ $password = md5( "$id-" . md5( 'FooBar' ) );
+ $dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
+ $req->password = 'FooBar';
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $userName ),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ }
+
+ /**
+ * @dataProvider provideProviderAllowsAuthenticationDataChange
+ * @param string $type
+ * @param string $user
+ * @param \Status $validity Result of the password validity check
+ * @param \StatusValue $expect1 Expected result with $checkData = false
+ * @param \StatusValue $expect2 Expected result with $checkData = true
+ */
+ public function testProviderAllowsAuthenticationDataChange( $type, $user, \Status $validity,
+ \StatusValue $expect1, \StatusValue $expect2
+ ) {
+ if ( $type === PasswordAuthenticationRequest::class ) {
+ $req = new $type();
+ } elseif ( $type === PasswordDomainAuthenticationRequest::class ) {
+ $req = new $type( [] );
+ } else {
+ $req = $this->getMock( $type );
+ }
+ $req->action = AuthManager::ACTION_CHANGE;
+ $req->username = $user;
+ $req->password = 'NewPassword';
+ $req->retype = 'NewPassword';
+
+ $provider = $this->getProvider();
+ $this->validity = $validity;
+ $this->assertEquals( $expect1, $provider->providerAllowsAuthenticationDataChange( $req, false ) );
+ $this->assertEquals( $expect2, $provider->providerAllowsAuthenticationDataChange( $req, true ) );
+
+ $req->retype = 'BadRetype';
+ $this->assertEquals(
+ $expect1,
+ $provider->providerAllowsAuthenticationDataChange( $req, false )
+ );
+ $this->assertEquals(
+ $expect2->getValue() === 'ignored' ? $expect2 : \StatusValue::newFatal( 'badretype' ),
+ $provider->providerAllowsAuthenticationDataChange( $req, true )
+ );
+
+ $provider = $this->getProvider( true );
+ $this->assertEquals(
+ \StatusValue::newGood( 'ignored' ),
+ $provider->providerAllowsAuthenticationDataChange( $req, true ),
+ 'loginOnly mode should claim to ignore all changes'
+ );
+ }
+
+ public static function provideProviderAllowsAuthenticationDataChange() {
+ $err = \StatusValue::newGood();
+ $err->error( 'arbitrary-warning' );
+
+ return [
+ [ AuthenticationRequest::class, 'UTSysop', \Status::newGood(),
+ \StatusValue::newGood( 'ignored' ), \StatusValue::newGood( 'ignored' ) ],
+ [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::newGood(),
+ \StatusValue::newGood(), \StatusValue::newGood() ],
+ [ PasswordAuthenticationRequest::class, 'uTSysop', \Status::newGood(),
+ \StatusValue::newGood(), \StatusValue::newGood() ],
+ [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::wrap( $err ),
+ \StatusValue::newGood(), $err ],
+ [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::newFatal( 'arbitrary-error' ),
+ \StatusValue::newGood(), \StatusValue::newFatal( 'arbitrary-error' ) ],
+ [ PasswordAuthenticationRequest::class, 'DoesNotExist', \Status::newGood(),
+ \StatusValue::newGood(), \StatusValue::newGood( 'ignored' ) ],
+ [ PasswordDomainAuthenticationRequest::class, 'UTSysop', \Status::newGood(),
+ \StatusValue::newGood( 'ignored' ), \StatusValue::newGood( 'ignored' ) ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideProviderChangeAuthenticationData
+ * @param callable|bool $usernameTransform
+ * @param string $type
+ * @param bool $loginOnly
+ * @param bool $changed
+ */
+ public function testProviderChangeAuthenticationData(
+ $usernameTransform, $type, $loginOnly, $changed ) {
+ $testUser = $this->getMutableTestUser();
+ $user = $testUser->getUser()->getName();
+ if ( is_callable( $usernameTransform ) ) {
+ $user = call_user_func( $usernameTransform, $user );
+ }
+ $cuser = ucfirst( $user );
+ $oldpass = $testUser->getPassword();
+ $newpass = 'NewPassword';
+
+ $dbw = wfGetDB( DB_MASTER );
+ $oldExpiry = $dbw->selectField( 'user', 'user_password_expires', [ 'user_name' => $cuser ] );
+
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [
+ 'ResetPasswordExpiration' => [ function ( $user, &$expires ) {
+ $expires = '30001231235959';
+ } ]
+ ] );
+
+ $provider = $this->getProvider( $loginOnly );
+
+ // Sanity check
+ $loginReq = new PasswordAuthenticationRequest();
+ $loginReq->action = AuthManager::ACTION_LOGIN;
+ $loginReq->username = $user;
+ $loginReq->password = $oldpass;
+ $loginReqs = [ PasswordAuthenticationRequest::class => $loginReq ];
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $cuser ),
+ $provider->beginPrimaryAuthentication( $loginReqs ),
+ 'Sanity check'
+ );
+
+ if ( $type === PasswordAuthenticationRequest::class ) {
+ $changeReq = new $type();
+ } else {
+ $changeReq = $this->getMock( $type );
+ }
+ $changeReq->action = AuthManager::ACTION_CHANGE;
+ $changeReq->username = $user;
+ $changeReq->password = $newpass;
+ $provider->providerChangeAuthenticationData( $changeReq );
+
+ if ( $loginOnly ) {
+ $old = 'fail';
+ $new = 'fail';
+ $expectExpiry = null;
+ } elseif ( $changed ) {
+ $old = 'fail';
+ $new = 'pass';
+ $expectExpiry = '30001231235959';
+ } else {
+ $old = 'pass';
+ $new = 'fail';
+ $expectExpiry = $oldExpiry;
+ }
+
+ $loginReq->password = $oldpass;
+ $ret = $provider->beginPrimaryAuthentication( $loginReqs );
+ if ( $old === 'pass' ) {
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $cuser ),
+ $ret,
+ 'old password should pass'
+ );
+ } else {
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status,
+ 'old password should fail'
+ );
+ $this->assertEquals(
+ 'wrongpassword',
+ $ret->message->getKey(),
+ 'old password should fail'
+ );
+ }
+
+ $loginReq->password = $newpass;
+ $ret = $provider->beginPrimaryAuthentication( $loginReqs );
+ if ( $new === 'pass' ) {
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $cuser ),
+ $ret,
+ 'new password should pass'
+ );
+ } else {
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status,
+ 'new password should fail'
+ );
+ $this->assertEquals(
+ 'wrongpassword',
+ $ret->message->getKey(),
+ 'new password should fail'
+ );
+ }
+
+ $this->assertSame(
+ $expectExpiry,
+ $dbw->selectField( 'user', 'user_password_expires', [ 'user_name' => $cuser ] )
+ );
+ }
+
+ public static function provideProviderChangeAuthenticationData() {
+ return [
+ [ false, AuthenticationRequest::class, false, false ],
+ [ false, PasswordAuthenticationRequest::class, false, true ],
+ [ false, AuthenticationRequest::class, true, false ],
+ [ false, PasswordAuthenticationRequest::class, true, true ],
+ [ 'ucfirst', PasswordAuthenticationRequest::class, false, true ],
+ [ 'ucfirst', PasswordAuthenticationRequest::class, true, true ],
+ ];
+ }
+
+ public function testTestForAccountCreation() {
+ $user = \User::newFromName( 'foo' );
+ $req = new PasswordAuthenticationRequest();
+ $req->action = AuthManager::ACTION_CREATE;
+ $req->username = 'Foo';
+ $req->password = 'Bar';
+ $req->retype = 'Bar';
+ $reqs = [ PasswordAuthenticationRequest::class => $req ];
+
+ $provider = $this->getProvider();
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $user, [] ),
+ 'No password request'
+ );
+
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $user, $reqs ),
+ 'Password request, validated'
+ );
+
+ $req->retype = 'Baz';
+ $this->assertEquals(
+ \StatusValue::newFatal( 'badretype' ),
+ $provider->testForAccountCreation( $user, $user, $reqs ),
+ 'Password request, bad retype'
+ );
+ $req->retype = 'Bar';
+
+ $this->validity->error( 'arbitrary warning' );
+ $expect = \StatusValue::newGood();
+ $expect->error( 'arbitrary warning' );
+ $this->assertEquals(
+ $expect,
+ $provider->testForAccountCreation( $user, $user, $reqs ),
+ 'Password request, not validated'
+ );
+
+ $provider = $this->getProvider( true );
+ $this->validity->error( 'arbitrary warning' );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $user, $reqs ),
+ 'Password request, not validated, loginOnly'
+ );
+ }
+
+ public function testAccountCreation() {
+ $user = \User::newFromName( 'Foo' );
+
+ $req = new PasswordAuthenticationRequest();
+ $req->action = AuthManager::ACTION_CREATE;
+ $reqs = [ PasswordAuthenticationRequest::class => $req ];
+
+ $provider = $this->getProvider( true );
+ try {
+ $provider->beginPrimaryAccountCreation( $user, $user, [] );
+ $this->fail( 'Expected exception was not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ $this->assertSame(
+ 'Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage()
+ );
+ }
+
+ try {
+ $provider->finishAccountCreation( $user, $user, AuthenticationResponse::newPass() );
+ $this->fail( 'Expected exception was not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ $this->assertSame(
+ 'Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage()
+ );
+ }
+
+ $provider = $this->getProvider( false );
+
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAccountCreation( $user, $user, [] )
+ );
+
+ $req->username = 'foo';
+ $req->password = null;
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+ );
+
+ $req->username = null;
+ $req->password = 'bar';
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+ );
+
+ $req->username = 'foo';
+ $req->password = 'bar';
+
+ $expect = AuthenticationResponse::newPass( 'Foo' );
+ $expect->createRequest = clone( $req );
+ $expect->createRequest->username = 'Foo';
+ $this->assertEquals( $expect, $provider->beginPrimaryAccountCreation( $user, $user, $reqs ) );
+
+ // We have to cheat a bit to avoid having to add a new user to
+ // the database to test the actual setting of the password works right
+ $dbw = wfGetDB( DB_MASTER );
+
+ $user = \User::newFromName( 'UTSysop' );
+ $req->username = $user->getName();
+ $req->password = 'NewPassword';
+ $expect = AuthenticationResponse::newPass( 'UTSysop' );
+ $expect->createRequest = $req;
+
+ $res2 = $provider->beginPrimaryAccountCreation( $user, $user, $reqs );
+ $this->assertEquals( $expect, $res2, 'Sanity check' );
+
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals( AuthenticationResponse::FAIL, $ret->status, 'sanity check' );
+
+ $this->assertNull( $provider->finishAccountCreation( $user, $user, $res2 ) );
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals( AuthenticationResponse::PASS, $ret->status, 'new password is set' );
+
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\PasswordAuthenticationRequest
+ */
+class PasswordAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ $ret = new PasswordAuthenticationRequest();
+ $ret->action = $args[0];
+ return $ret;
+ }
+
+ public static function provideGetFieldInfo() {
+ return [
+ [ [ AuthManager::ACTION_LOGIN ] ],
+ [ [ AuthManager::ACTION_CREATE ] ],
+ [ [ AuthManager::ACTION_CHANGE ] ],
+ [ [ AuthManager::ACTION_REMOVE ] ],
+ ];
+ }
+
+ public function testGetFieldInfo2() {
+ $info = [];
+ foreach ( [
+ AuthManager::ACTION_LOGIN,
+ AuthManager::ACTION_CREATE,
+ AuthManager::ACTION_CHANGE,
+ AuthManager::ACTION_REMOVE,
+ ] as $action ) {
+ $req = new PasswordAuthenticationRequest();
+ $req->action = $action;
+ $info[$action] = $req->getFieldInfo();
+ }
+
+ $this->assertSame( [], $info[AuthManager::ACTION_REMOVE], 'No data needed to remove' );
+
+ $this->assertArrayNotHasKey( 'retype', $info[AuthManager::ACTION_LOGIN],
+ 'No need to retype password on login' );
+ $this->assertArrayHasKey( 'retype', $info[AuthManager::ACTION_CREATE],
+ 'Need to retype when creating new password' );
+ $this->assertArrayHasKey( 'retype', $info[AuthManager::ACTION_CHANGE],
+ 'Need to retype when changing password' );
+
+ $this->assertNotEquals(
+ $info[AuthManager::ACTION_LOGIN]['password']['label'],
+ $info[AuthManager::ACTION_CHANGE]['password']['label'],
+ 'Password field for change is differentiated from login'
+ );
+ $this->assertNotEquals(
+ $info[AuthManager::ACTION_CREATE]['password']['label'],
+ $info[AuthManager::ACTION_CHANGE]['password']['label'],
+ 'Password field for change is differentiated from create'
+ );
+ $this->assertNotEquals(
+ $info[AuthManager::ACTION_CREATE]['retype']['label'],
+ $info[AuthManager::ACTION_CHANGE]['retype']['label'],
+ 'Retype field for change is differentiated from create'
+ );
+ }
+
+ public function provideLoadFromSubmission() {
+ return [
+ 'Empty request, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ [],
+ false,
+ ],
+ 'Empty request, change' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [],
+ false,
+ ],
+ 'Empty request, remove' => [
+ [ AuthManager::ACTION_REMOVE ],
+ [],
+ false,
+ ],
+ 'Username + password, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ $data = [ 'username' => 'User', 'password' => 'Bar' ],
+ $data + [ 'action' => AuthManager::ACTION_LOGIN ],
+ ],
+ 'Username + password, change' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [ 'username' => 'User', 'password' => 'Bar' ],
+ false,
+ ],
+ 'Username + password + retype' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [ 'username' => 'User', 'password' => 'Bar', 'retype' => 'baz' ],
+ [ 'password' => 'Bar', 'retype' => 'baz', 'action' => AuthManager::ACTION_CHANGE ],
+ ],
+ 'Username empty, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ [ 'username' => '', 'password' => 'Bar' ],
+ false,
+ ],
+ 'Username empty, change' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [ 'username' => '', 'password' => 'Bar', 'retype' => 'baz' ],
+ [ 'password' => 'Bar', 'retype' => 'baz', 'action' => AuthManager::ACTION_CHANGE ],
+ ],
+ 'Password empty, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ [ 'username' => 'User', 'password' => '' ],
+ false,
+ ],
+ 'Password empty, login, with retype' => [
+ [ AuthManager::ACTION_LOGIN ],
+ [ 'username' => 'User', 'password' => '', 'retype' => 'baz' ],
+ false,
+ ],
+ 'Retype empty' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [ 'username' => 'User', 'password' => 'Bar', 'retype' => '' ],
+ false,
+ ],
+ ];
+ }
+
+ public function testDescribeCredentials() {
+ $req = new PasswordAuthenticationRequest;
+ $req->action = AuthManager::ACTION_LOGIN;
+ $req->username = 'UTSysop';
+ $ret = $req->describeCredentials();
+ $this->assertInternalType( 'array', $ret );
+ $this->assertArrayHasKey( 'provider', $ret );
+ $this->assertInstanceOf( 'Message', $ret['provider'] );
+ $this->assertSame( 'authmanager-provider-password', $ret['provider']->getKey() );
+ $this->assertArrayHasKey( 'account', $ret );
+ $this->assertInstanceOf( 'Message', $ret['account'] );
+ $this->assertSame( [ 'UTSysop' ], $ret['account']->getParams() );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\PasswordDomainAuthenticationRequest
+ */
+class PasswordDomainAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ $ret = new PasswordDomainAuthenticationRequest( [ 'd1', 'd2' ] );
+ $ret->action = $args[0];
+ return $ret;
+ }
+
+ public static function provideGetFieldInfo() {
+ return [
+ [ [ AuthManager::ACTION_LOGIN ] ],
+ [ [ AuthManager::ACTION_CREATE ] ],
+ [ [ AuthManager::ACTION_CHANGE ] ],
+ [ [ AuthManager::ACTION_REMOVE ] ],
+ ];
+ }
+
+ public function testGetFieldInfo2() {
+ $info = [];
+ foreach ( [
+ AuthManager::ACTION_LOGIN,
+ AuthManager::ACTION_CREATE,
+ AuthManager::ACTION_CHANGE,
+ AuthManager::ACTION_REMOVE,
+ ] as $action ) {
+ $req = new PasswordDomainAuthenticationRequest( [ 'd1', 'd2' ] );
+ $req->action = $action;
+ $info[$action] = $req->getFieldInfo();
+ }
+
+ $this->assertSame( [], $info[AuthManager::ACTION_REMOVE], 'No data needed to remove' );
+
+ $this->assertArrayNotHasKey( 'retype', $info[AuthManager::ACTION_LOGIN],
+ 'No need to retype password on login' );
+ $this->assertArrayHasKey( 'domain', $info[AuthManager::ACTION_LOGIN],
+ 'Domain needed on login' );
+ $this->assertArrayHasKey( 'retype', $info[AuthManager::ACTION_CREATE],
+ 'Need to retype when creating new password' );
+ $this->assertArrayHasKey( 'domain', $info[AuthManager::ACTION_CREATE],
+ 'Domain needed on account creation' );
+ $this->assertArrayHasKey( 'retype', $info[AuthManager::ACTION_CHANGE],
+ 'Need to retype when changing password' );
+ $this->assertArrayNotHasKey( 'domain', $info[AuthManager::ACTION_CHANGE],
+ 'Domain not needed on account creation' );
+
+ $this->assertNotEquals(
+ $info[AuthManager::ACTION_LOGIN]['password']['label'],
+ $info[AuthManager::ACTION_CHANGE]['password']['label'],
+ 'Password field for change is differentiated from login'
+ );
+ $this->assertNotEquals(
+ $info[AuthManager::ACTION_CREATE]['password']['label'],
+ $info[AuthManager::ACTION_CHANGE]['password']['label'],
+ 'Password field for change is differentiated from create'
+ );
+ $this->assertNotEquals(
+ $info[AuthManager::ACTION_CREATE]['retype']['label'],
+ $info[AuthManager::ACTION_CHANGE]['retype']['label'],
+ 'Retype field for change is differentiated from create'
+ );
+ }
+
+ public function provideLoadFromSubmission() {
+ $domainList = [ 'domainList' => [ 'd1', 'd2' ] ];
+ return [
+ 'Empty request, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ [],
+ false,
+ ],
+ 'Empty request, change' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [],
+ false,
+ ],
+ 'Empty request, remove' => [
+ [ AuthManager::ACTION_REMOVE ],
+ [],
+ false,
+ ],
+ 'Username + password, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ $data = [ 'username' => 'User', 'password' => 'Bar' ],
+ false,
+ ],
+ 'Username + password + domain, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ $data = [ 'username' => 'User', 'password' => 'Bar', 'domain' => 'd1' ],
+ $data + [ 'action' => AuthManager::ACTION_LOGIN ] + $domainList,
+ ],
+ 'Username + password + bad domain, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ $data = [ 'username' => 'User', 'password' => 'Bar', 'domain' => 'd5' ],
+ false,
+ ],
+ 'Username + password + domain, change' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [ 'username' => 'User', 'password' => 'Bar', 'domain' => 'd1' ],
+ false,
+ ],
+ 'Username + password + domain + retype' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [ 'username' => 'User', 'password' => 'Bar', 'retype' => 'baz', 'domain' => 'd1' ],
+ [ 'password' => 'Bar', 'retype' => 'baz', 'action' => AuthManager::ACTION_CHANGE ] +
+ $domainList,
+ ],
+ 'Username empty, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ [ 'username' => '', 'password' => 'Bar', 'domain' => 'd1' ],
+ false,
+ ],
+ 'Username empty, change' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [ 'username' => '', 'password' => 'Bar', 'retype' => 'baz', 'domain' => 'd1' ],
+ [ 'password' => 'Bar', 'retype' => 'baz', 'action' => AuthManager::ACTION_CHANGE ] +
+ $domainList,
+ ],
+ 'Password empty, login' => [
+ [ AuthManager::ACTION_LOGIN ],
+ [ 'username' => 'User', 'password' => '', 'domain' => 'd1' ],
+ false,
+ ],
+ 'Password empty, login, with retype' => [
+ [ AuthManager::ACTION_LOGIN ],
+ [ 'username' => 'User', 'password' => '', 'retype' => 'baz', 'domain' => 'd1' ],
+ false,
+ ],
+ 'Retype empty' => [
+ [ AuthManager::ACTION_CHANGE ],
+ [ 'username' => 'User', 'password' => 'Bar', 'retype' => '', 'domain' => 'd1' ],
+ false,
+ ],
+ ];
+ }
+
+ public function testDescribeCredentials() {
+ $req = new PasswordDomainAuthenticationRequest( [ 'd1', 'd2' ] );
+ $req->action = AuthManager::ACTION_LOGIN;
+ $req->username = 'UTSysop';
+ $req->domain = 'd2';
+ $ret = $req->describeCredentials();
+ $this->assertInternalType( 'array', $ret );
+ $this->assertArrayHasKey( 'provider', $ret );
+ $this->assertInstanceOf( 'Message', $ret['provider'] );
+ $this->assertSame( 'authmanager-provider-password-domain', $ret['provider']->getKey() );
+ $this->assertArrayHasKey( 'account', $ret );
+ $this->assertInstanceOf( 'Message', $ret['account'] );
+ $this->assertSame( 'authmanager-account-password-domain', $ret['account']->getKey() );
+ $this->assertSame( [ 'UTSysop', 'd2' ], $ret['account']->getParams() );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\RememberMeAuthenticationRequest
+ */
+class RememberMeAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ public static function provideGetFieldInfo() {
+ return [
+ [ [ 1 ] ],
+ [ [ null ] ],
+ ];
+ }
+
+ public function testGetFieldInfo_2() {
+ $req = new RememberMeAuthenticationRequest();
+ $reqWrapper = \TestingAccessWrapper::newFromObject( $req );
+
+ $reqWrapper->expiration = 30 * 24 * 3600;
+ $this->assertNotEmpty( $req->getFieldInfo() );
+
+ $reqWrapper->expiration = null;
+ $this->assertEmpty( $req->getFieldInfo() );
+ }
+
+ protected function getInstance( array $args = [] ) {
+ $req = new RememberMeAuthenticationRequest();
+ $reqWrapper = \TestingAccessWrapper::newFromObject( $req );
+ $reqWrapper->expiration = $args[0];
+ return $req;
+ }
+
+ public function provideLoadFromSubmission() {
+ return [
+ 'Empty request' => [
+ [ 30 * 24 * 3600 ],
+ [],
+ [ 'expiration' => 30 * 24 * 3600, 'rememberMe' => false ]
+ ],
+ 'RememberMe present' => [
+ [ 30 * 24 * 3600 ],
+ [ 'rememberMe' => '' ],
+ [ 'expiration' => 30 * 24 * 3600, 'rememberMe' => true ]
+ ],
+ 'RememberMe present but session provider cannot remember' => [
+ [ null ],
+ [ 'rememberMe' => '' ],
+ false
+ ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider
+ */
+class ResetPasswordSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ /**
+ * @dataProvider provideGetAuthenticationRequests
+ * @param string $action
+ * @param array $response
+ */
+ public function testGetAuthenticationRequests( $action, $response ) {
+ $provider = new ResetPasswordSecondaryAuthenticationProvider();
+
+ $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
+ }
+
+ public static function provideGetAuthenticationRequests() {
+ return [
+ [ AuthManager::ACTION_LOGIN, [] ],
+ [ AuthManager::ACTION_CREATE, [] ],
+ [ AuthManager::ACTION_LINK, [] ],
+ [ AuthManager::ACTION_CHANGE, [] ],
+ [ AuthManager::ACTION_REMOVE, [] ],
+ ];
+ }
+
+ public function testBasics() {
+ $user = \User::newFromName( 'UTSysop' );
+ $user2 = new \User;
+ $obj = new \stdClass;
+ $reqs = [ new \stdClass ];
+
+ $mb = $this->getMockBuilder( ResetPasswordSecondaryAuthenticationProvider::class )
+ ->setMethods( [ 'tryReset' ] );
+
+ $methods = [
+ 'beginSecondaryAuthentication' => [ $user, $reqs ],
+ 'continueSecondaryAuthentication' => [ $user, $reqs ],
+ 'beginSecondaryAccountCreation' => [ $user, $user2, $reqs ],
+ 'continueSecondaryAccountCreation' => [ $user, $user2, $reqs ],
+ ];
+ foreach ( $methods as $method => $args ) {
+ $mock = $mb->getMock();
+ $mock->expects( $this->once() )->method( 'tryReset' )
+ ->with( $this->identicalTo( $user ), $this->identicalTo( $reqs ) )
+ ->will( $this->returnValue( $obj ) );
+ $this->assertSame( $obj, call_user_func_array( [ $mock, $method ], $args ) );
+ }
+ }
+
+ public function testTryReset() {
+ $user = \User::newFromName( 'UTSysop' );
+
+ $provider = $this->getMockBuilder(
+ ResetPasswordSecondaryAuthenticationProvider::class
+ )
+ ->setMethods( [
+ 'providerAllowsAuthenticationDataChange', 'providerChangeAuthenticationData'
+ ] )
+ ->getMock();
+ $provider->expects( $this->any() )->method( 'providerAllowsAuthenticationDataChange' )
+ ->will( $this->returnCallback( function ( $req ) {
+ $this->assertSame( 'UTSysop', $req->username );
+ return $req->allow;
+ } ) );
+ $provider->expects( $this->any() )->method( 'providerChangeAuthenticationData' )
+ ->will( $this->returnCallback( function ( $req ) {
+ $this->assertSame( 'UTSysop', $req->username );
+ $req->done = true;
+ } ) );
+ $config = new \HashConfig( [
+ 'AuthManagerConfig' => [
+ 'preauth' => [],
+ 'primaryauth' => [],
+ 'secondaryauth' => [
+ [ 'factory' => function () use ( $provider ) {
+ return $provider;
+ } ],
+ ],
+ ],
+ ] );
+ $manager = new AuthManager( new \FauxRequest, $config );
+ $provider->setManager( $manager );
+ $provider = \TestingAccessWrapper::newFromObject( $provider );
+
+ $msg = wfMessage( 'foo' );
+ $skipReq = new ButtonAuthenticationRequest(
+ 'skipReset',
+ wfMessage( 'authprovider-resetpass-skip-label' ),
+ wfMessage( 'authprovider-resetpass-skip-help' )
+ );
+ $passReq = new PasswordAuthenticationRequest();
+ $passReq->action = AuthManager::ACTION_CHANGE;
+ $passReq->password = 'Foo';
+ $passReq->retype = 'Bar';
+ $passReq->allow = \StatusValue::newGood();
+ $passReq->done = false;
+
+ $passReq2 = $this->getMockBuilder( PasswordAuthenticationRequest::class )
+ ->enableProxyingToOriginalMethods()
+ ->getMock();
+ $passReq2->action = AuthManager::ACTION_CHANGE;
+ $passReq2->password = 'Foo';
+ $passReq2->retype = 'Foo';
+ $passReq2->allow = \StatusValue::newGood();
+ $passReq2->done = false;
+
+ $passReq3 = new PasswordAuthenticationRequest();
+ $passReq3->action = AuthManager::ACTION_LOGIN;
+ $passReq3->password = 'Foo';
+ $passReq3->retype = 'Foo';
+ $passReq3->allow = \StatusValue::newGood();
+ $passReq3->done = false;
+
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->tryReset( $user, [] )
+ );
+
+ $manager->setAuthenticationSessionData( 'reset-pass', 'foo' );
+ try {
+ $provider->tryReset( $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame( 'reset-pass is not valid', $ex->getMessage() );
+ }
+
+ $manager->setAuthenticationSessionData( 'reset-pass', (object)[] );
+ try {
+ $provider->tryReset( $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame( 'reset-pass msg is missing', $ex->getMessage() );
+ }
+
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => 'foo',
+ ] );
+ try {
+ $provider->tryReset( $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame( 'reset-pass msg is not valid', $ex->getMessage() );
+ }
+
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ ] );
+ try {
+ $provider->tryReset( $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame( 'reset-pass hard is missing', $ex->getMessage() );
+ }
+
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ 'hard' => true,
+ 'req' => 'foo',
+ ] );
+ try {
+ $provider->tryReset( $user, [] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame( 'reset-pass req is not valid', $ex->getMessage() );
+ }
+
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ 'hard' => false,
+ 'req' => $passReq3,
+ ] );
+ try {
+ $provider->tryReset( $user, [ $passReq ] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \UnexpectedValueException $ex ) {
+ $this->assertSame( 'reset-pass req is not valid', $ex->getMessage() );
+ }
+
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ 'hard' => true,
+ ] );
+ $res = $provider->tryReset( $user, [] );
+ $this->assertInstanceOf( AuthenticationResponse::class, $res );
+ $this->assertSame( AuthenticationResponse::UI, $res->status );
+ $this->assertEquals( $msg, $res->message );
+ $this->assertCount( 1, $res->neededRequests );
+ $this->assertInstanceOf(
+ PasswordAuthenticationRequest::class,
+ $res->neededRequests[0]
+ );
+ $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $this->assertFalse( $passReq->done );
+
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ 'hard' => false,
+ 'req' => $passReq,
+ ] );
+ $res = $provider->tryReset( $user, [] );
+ $this->assertInstanceOf( AuthenticationResponse::class, $res );
+ $this->assertSame( AuthenticationResponse::UI, $res->status );
+ $this->assertEquals( $msg, $res->message );
+ $this->assertCount( 2, $res->neededRequests );
+ $expectedPassReq = clone $passReq;
+ $expectedPassReq->required = AuthenticationRequest::OPTIONAL;
+ $this->assertEquals( $expectedPassReq, $res->neededRequests[0] );
+ $this->assertEquals( $skipReq, $res->neededRequests[1] );
+ $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $this->assertFalse( $passReq->done );
+
+ $passReq->retype = 'Bad';
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ 'hard' => false,
+ 'req' => $passReq,
+ ] );
+ $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
+ $this->assertEquals( AuthenticationResponse::newPass(), $res );
+ $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $this->assertFalse( $passReq->done );
+
+ $passReq->retype = 'Bad';
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ 'hard' => true,
+ ] );
+ $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
+ $this->assertSame( AuthenticationResponse::UI, $res->status );
+ $this->assertSame( 'badretype', $res->message->getKey() );
+ $this->assertCount( 1, $res->neededRequests );
+ $this->assertInstanceOf(
+ PasswordAuthenticationRequest::class,
+ $res->neededRequests[0]
+ );
+ $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $this->assertFalse( $passReq->done );
+
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ 'hard' => true,
+ ] );
+ $res = $provider->tryReset( $user, [ $skipReq, $passReq3 ] );
+ $this->assertSame( AuthenticationResponse::UI, $res->status );
+ $this->assertEquals( $msg, $res->message );
+ $this->assertCount( 1, $res->neededRequests );
+ $this->assertInstanceOf(
+ PasswordAuthenticationRequest::class,
+ $res->neededRequests[0]
+ );
+ $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $this->assertFalse( $passReq->done );
+
+ $passReq->retype = $passReq->password;
+ $passReq->allow = \StatusValue::newFatal( 'arbitrary-fail' );
+ $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
+ $this->assertSame( AuthenticationResponse::UI, $res->status );
+ $this->assertSame( 'arbitrary-fail', $res->message->getKey() );
+ $this->assertCount( 1, $res->neededRequests );
+ $this->assertInstanceOf(
+ PasswordAuthenticationRequest::class,
+ $res->neededRequests[0]
+ );
+ $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $this->assertFalse( $passReq->done );
+
+ $passReq->allow = \StatusValue::newGood();
+ $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
+ $this->assertEquals( AuthenticationResponse::newPass(), $res );
+ $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $this->assertTrue( $passReq->done );
+
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ 'hard' => false,
+ 'req' => $passReq2,
+ ] );
+ $res = $provider->tryReset( $user, [ $passReq2 ] );
+ $this->assertEquals( AuthenticationResponse::newPass(), $res );
+ $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $this->assertTrue( $passReq2->done );
+
+ $passReq->done = false;
+ $passReq2->done = false;
+ $manager->setAuthenticationSessionData( 'reset-pass', [
+ 'msg' => $msg,
+ 'hard' => false,
+ 'req' => $passReq2,
+ ] );
+ $res = $provider->tryReset( $user, [ $passReq ] );
+ $this->assertInstanceOf( AuthenticationResponse::class, $res );
+ $this->assertSame( AuthenticationResponse::UI, $res->status );
+ $this->assertEquals( $msg, $res->message );
+ $this->assertCount( 2, $res->neededRequests );
+ $expectedPassReq = clone $passReq2;
+ $expectedPassReq->required = AuthenticationRequest::OPTIONAL;
+ $this->assertEquals( $expectedPassReq, $res->neededRequests[0] );
+ $this->assertEquals( $skipReq, $res->neededRequests[1] );
+ $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $this->assertFalse( $passReq->done );
+ $this->assertFalse( $passReq2->done );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\TemporaryPasswordAuthenticationRequest
+ */
+class TemporaryPasswordAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ $ret = new TemporaryPasswordAuthenticationRequest;
+ $ret->action = $args[0];
+ return $ret;
+ }
+
+ public static function provideGetFieldInfo() {
+ return [
+ [ [ AuthManager::ACTION_CREATE ] ],
+ [ [ AuthManager::ACTION_CHANGE ] ],
+ [ [ AuthManager::ACTION_REMOVE ] ],
+ ];
+ }
+
+ public function testNewRandom() {
+ global $wgPasswordPolicy;
+
+ $this->stashMwGlobals( 'wgPasswordPolicy' );
+ $wgPasswordPolicy['policies']['default'] += [
+ 'MinimalPasswordLength' => 1,
+ 'MinimalPasswordLengthToLogin' => 1,
+ ];
+
+ $ret1 = TemporaryPasswordAuthenticationRequest::newRandom();
+ $ret2 = TemporaryPasswordAuthenticationRequest::newRandom();
+ $this->assertNotSame( '', $ret1->password );
+ $this->assertNotSame( '', $ret2->password );
+ $this->assertNotSame( $ret1->password, $ret2->password );
+ }
+
+ public function testNewInvalid() {
+ $ret = TemporaryPasswordAuthenticationRequest::newInvalid();
+ $this->assertNull( $ret->password );
+ }
+
+ public function provideLoadFromSubmission() {
+ return [
+ 'Empty request' => [
+ [ AuthManager::ACTION_REMOVE ],
+ [],
+ false,
+ ],
+ 'Create, empty request' => [
+ [ AuthManager::ACTION_CREATE ],
+ [],
+ false,
+ ],
+ 'Create, mailpassword set' => [
+ [ AuthManager::ACTION_CREATE ],
+ [ 'mailpassword' => 1 ],
+ [ 'mailpassword' => true, 'action' => AuthManager::ACTION_CREATE ],
+ ],
+ ];
+ }
+
+ public function testDescribeCredentials() {
+ $req = new TemporaryPasswordAuthenticationRequest;
+ $req->action = AuthManager::ACTION_LOGIN;
+ $req->username = 'UTSysop';
+ $ret = $req->describeCredentials();
+ $this->assertInternalType( 'array', $ret );
+ $this->assertArrayHasKey( 'provider', $ret );
+ $this->assertInstanceOf( 'Message', $ret['provider'] );
+ $this->assertSame( 'authmanager-provider-temporarypassword', $ret['provider']->getKey() );
+ $this->assertArrayHasKey( 'account', $ret );
+ $this->assertInstanceOf( 'Message', $ret['account'] );
+ $this->assertSame( [ 'UTSysop' ], $ret['account']->getParams() );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @group Database
+ * @covers MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider
+ */
+class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
+
+ private $manager = null;
+ private $config = null;
+ private $validity = null;
+
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ /**
+ * Get an instance of the provider
+ *
+ * $provider->checkPasswordValidity is mocked to return $this->validity,
+ * because we don't need to test that here.
+ *
+ * @param array $params
+ * @return TemporaryPasswordPrimaryAuthenticationProvider
+ */
+ protected function getProvider( $params = [] ) {
+ if ( !$this->config ) {
+ $this->config = new \HashConfig( [
+ 'EmailEnabled' => true,
+ ] );
+ }
+ $config = new \MultiConfig( [
+ $this->config,
+ \ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
+ ] );
+
+ if ( !$this->manager ) {
+ $this->manager = new AuthManager( new \FauxRequest(), $config );
+ }
+ $this->validity = \Status::newGood();
+
+ $mockedMethods[] = 'checkPasswordValidity';
+ $provider = $this->getMock(
+ TemporaryPasswordPrimaryAuthenticationProvider::class,
+ $mockedMethods,
+ [ $params ]
+ );
+ $provider->expects( $this->any() )->method( 'checkPasswordValidity' )
+ ->will( $this->returnCallback( function () {
+ return $this->validity;
+ } ) );
+ $provider->setConfig( $config );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setManager( $this->manager );
+
+ return $provider;
+ }
+
+ protected function hookMailer( $func = null ) {
+ \Hooks::clear( 'AlternateUserMailer' );
+ if ( $func ) {
+ \Hooks::register( 'AlternateUserMailer', $func );
+ // Safety
+ \Hooks::register( 'AlternateUserMailer', function () {
+ return false;
+ } );
+ } else {
+ \Hooks::register( 'AlternateUserMailer', function () {
+ $this->fail( 'AlternateUserMailer hook called unexpectedly' );
+ return false;
+ } );
+ }
+
+ return new \ScopedCallback( function () {
+ \Hooks::clear( 'AlternateUserMailer' );
+ \Hooks::register( 'AlternateUserMailer', function () {
+ return false;
+ } );
+ } );
+ }
+
+ public function testBasics() {
+ $provider = new TemporaryPasswordPrimaryAuthenticationProvider();
+
+ $this->assertSame(
+ PrimaryAuthenticationProvider::TYPE_CREATE,
+ $provider->accountCreationType()
+ );
+
+ $this->assertTrue( $provider->testUserExists( 'UTSysop' ) );
+ $this->assertTrue( $provider->testUserExists( 'uTSysop' ) );
+ $this->assertFalse( $provider->testUserExists( 'DoesNotExist' ) );
+ $this->assertFalse( $provider->testUserExists( '<invalid>' ) );
+
+ $req = new PasswordAuthenticationRequest;
+ $req->action = AuthManager::ACTION_CHANGE;
+ $req->username = '<invalid>';
+ $provider->providerChangeAuthenticationData( $req );
+ }
+
+ public function testConfig() {
+ $config = new \HashConfig( [
+ 'EnableEmail' => false,
+ 'NewPasswordExpiry' => 100,
+ 'PasswordReminderResendTime' => 101,
+ ] );
+
+ $p = \TestingAccessWrapper::newFromObject( new TemporaryPasswordPrimaryAuthenticationProvider() );
+ $p->setConfig( $config );
+ $this->assertSame( false, $p->emailEnabled );
+ $this->assertSame( 100, $p->newPasswordExpiry );
+ $this->assertSame( 101, $p->passwordReminderResendTime );
+
+ $p = \TestingAccessWrapper::newFromObject( new TemporaryPasswordPrimaryAuthenticationProvider( [
+ 'emailEnabled' => true,
+ 'newPasswordExpiry' => 42,
+ 'passwordReminderResendTime' => 43,
+ ] ) );
+ $p->setConfig( $config );
+ $this->assertSame( true, $p->emailEnabled );
+ $this->assertSame( 42, $p->newPasswordExpiry );
+ $this->assertSame( 43, $p->passwordReminderResendTime );
+ }
+
+ public function testTestUserCanAuthenticate() {
+ $dbw = wfGetDB( DB_MASTER );
+
+ $passwordFactory = new \PasswordFactory();
+ $passwordFactory->init( \RequestContext::getMain()->getConfig() );
+ // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
+ $passwordFactory->setDefaultType( 'A' );
+ $pwhash = $passwordFactory->newFromPlaintext( 'password' )->toString();
+
+ $provider = $this->getProvider();
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $this->assertFalse( $provider->testUserCanAuthenticate( '<invalid>' ) );
+ $this->assertFalse( $provider->testUserCanAuthenticate( 'DoesNotExist' ) );
+
+ $dbw->update(
+ 'user',
+ [
+ 'user_newpassword' => \PasswordFactory::newInvalidPassword()->toString(),
+ 'user_newpass_time' => null,
+ ],
+ [ 'user_name' => 'UTSysop' ]
+ );
+ $this->assertFalse( $provider->testUserCanAuthenticate( 'UTSysop' ) );
+
+ $dbw->update(
+ 'user',
+ [
+ 'user_newpassword' => $pwhash,
+ 'user_newpass_time' => null,
+ ],
+ [ 'user_name' => 'UTSysop' ]
+ );
+ $this->assertTrue( $provider->testUserCanAuthenticate( 'UTSysop' ) );
+ $this->assertTrue( $provider->testUserCanAuthenticate( 'uTSysop' ) );
+
+ $dbw->update(
+ 'user',
+ [
+ 'user_newpassword' => $pwhash,
+ 'user_newpass_time' => $dbw->timestamp( time() - 10 ),
+ ],
+ [ 'user_name' => 'UTSysop' ]
+ );
+ $providerPriv->newPasswordExpiry = 100;
+ $this->assertTrue( $provider->testUserCanAuthenticate( 'UTSysop' ) );
+ $providerPriv->newPasswordExpiry = 1;
+ $this->assertFalse( $provider->testUserCanAuthenticate( 'UTSysop' ) );
+
+ $dbw->update(
+ 'user',
+ [
+ 'user_newpassword' => \PasswordFactory::newInvalidPassword()->toString(),
+ 'user_newpass_time' => null,
+ ],
+ [ 'user_name' => 'UTSysop' ]
+ );
+ }
+
+ /**
+ * @dataProvider provideGetAuthenticationRequests
+ * @param string $action
+ * @param array $options
+ * @param array $expected
+ */
+ public function testGetAuthenticationRequests( $action, $options, $expected ) {
+ $actual = $this->getProvider()->getAuthenticationRequests( $action, $options );
+ foreach ( $actual as $req ) {
+ if ( $req instanceof TemporaryPasswordAuthenticationRequest && $req->password !== null ) {
+ $req->password = 'random';
+ }
+ }
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideGetAuthenticationRequests() {
+ $anon = [ 'username' => null ];
+ $loggedIn = [ 'username' => 'UTSysop' ];
+
+ return [
+ [ AuthManager::ACTION_LOGIN, $anon, [
+ new PasswordAuthenticationRequest
+ ] ],
+ [ AuthManager::ACTION_LOGIN, $loggedIn, [
+ new PasswordAuthenticationRequest
+ ] ],
+ [ AuthManager::ACTION_CREATE, $anon, [] ],
+ [ AuthManager::ACTION_CREATE, $loggedIn, [
+ new TemporaryPasswordAuthenticationRequest( 'random' )
+ ] ],
+ [ AuthManager::ACTION_LINK, $anon, [] ],
+ [ AuthManager::ACTION_LINK, $loggedIn, [] ],
+ [ AuthManager::ACTION_CHANGE, $anon, [
+ new TemporaryPasswordAuthenticationRequest( 'random' )
+ ] ],
+ [ AuthManager::ACTION_CHANGE, $loggedIn, [
+ new TemporaryPasswordAuthenticationRequest( 'random' )
+ ] ],
+ [ AuthManager::ACTION_REMOVE, $anon, [
+ new TemporaryPasswordAuthenticationRequest
+ ] ],
+ [ AuthManager::ACTION_REMOVE, $loggedIn, [
+ new TemporaryPasswordAuthenticationRequest
+ ] ],
+ ];
+ }
+
+ public function testAuthentication() {
+ $password = 'TemporaryPassword';
+ $hash = ':A:' . md5( $password );
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update(
+ 'user',
+ [ 'user_newpassword' => $hash, 'user_newpass_time' => $dbw->timestamp( time() - 10 ) ],
+ [ 'user_name' => 'UTSysop' ]
+ );
+
+ $req = new PasswordAuthenticationRequest();
+ $req->action = AuthManager::ACTION_LOGIN;
+ $reqs = [ PasswordAuthenticationRequest::class => $req ];
+
+ $provider = $this->getProvider();
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+
+ $providerPriv->newPasswordExpiry = 100;
+
+ // General failures
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( [] )
+ );
+
+ $req->username = 'foo';
+ $req->password = null;
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $req->username = null;
+ $req->password = 'bar';
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $req->username = '<invalid>';
+ $req->password = 'WhoCares';
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ $req->username = 'DoesNotExist';
+ $req->password = 'DoesNotExist';
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+
+ // Validation failure
+ $req->username = 'UTSysop';
+ $req->password = $password;
+ $this->validity = \Status::newFatal( 'arbitrary-failure' );
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status
+ );
+ $this->assertEquals(
+ 'arbitrary-failure',
+ $ret->message->getKey()
+ );
+
+ // Successful auth
+ $this->manager->removeAuthenticationSessionData( null );
+ $this->validity = \Status::newGood();
+ $this->assertEquals(
+ AuthenticationResponse::newPass( 'UTSysop' ),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+ $this->assertNotNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
+
+ $this->manager->removeAuthenticationSessionData( null );
+ $this->validity = \Status::newGood();
+ $req->username = 'uTSysop';
+ $this->assertEquals(
+ AuthenticationResponse::newPass( 'UTSysop' ),
+ $provider->beginPrimaryAuthentication( $reqs )
+ );
+ $this->assertNotNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
+ $req->username = 'UTSysop';
+
+ // Expired password
+ $providerPriv->newPasswordExpiry = 1;
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status
+ );
+ $this->assertEquals(
+ 'wrongpassword',
+ $ret->message->getKey()
+ );
+
+ // Bad password
+ $providerPriv->newPasswordExpiry = 100;
+ $this->validity = \Status::newGood();
+ $req->password = 'Wrong';
+ $ret = $provider->beginPrimaryAuthentication( $reqs );
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status
+ );
+ $this->assertEquals(
+ 'wrongpassword',
+ $ret->message->getKey()
+ );
+
+ }
+
+ /**
+ * @dataProvider provideProviderAllowsAuthenticationDataChange
+ * @param string $type
+ * @param string $user
+ * @param \Status $validity Result of the password validity check
+ * @param \StatusValue $expect1 Expected result with $checkData = false
+ * @param \StatusValue $expect2 Expected result with $checkData = true
+ */
+ public function testProviderAllowsAuthenticationDataChange( $type, $user, \Status $validity,
+ \StatusValue $expect1, \StatusValue $expect2
+ ) {
+ if ( $type === PasswordAuthenticationRequest::class ||
+ $type === TemporaryPasswordAuthenticationRequest::class
+ ) {
+ $req = new $type();
+ } else {
+ $req = $this->getMock( $type );
+ }
+ $req->action = AuthManager::ACTION_CHANGE;
+ $req->username = $user;
+ $req->password = 'NewPassword';
+
+ $provider = $this->getProvider();
+ $this->validity = $validity;
+ $this->assertEquals( $expect1, $provider->providerAllowsAuthenticationDataChange( $req, false ) );
+ $this->assertEquals( $expect2, $provider->providerAllowsAuthenticationDataChange( $req, true ) );
+ }
+
+ public static function provideProviderAllowsAuthenticationDataChange() {
+ $err = \StatusValue::newGood();
+ $err->error( 'arbitrary-warning' );
+
+ return [
+ [ AuthenticationRequest::class, 'UTSysop', \Status::newGood(),
+ \StatusValue::newGood( 'ignored' ), \StatusValue::newGood( 'ignored' ) ],
+ [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::newGood(),
+ \StatusValue::newGood( 'ignored' ), \StatusValue::newGood( 'ignored' ) ],
+ [ TemporaryPasswordAuthenticationRequest::class, 'UTSysop', \Status::newGood(),
+ \StatusValue::newGood(), \StatusValue::newGood() ],
+ [ TemporaryPasswordAuthenticationRequest::class, 'uTSysop', \Status::newGood(),
+ \StatusValue::newGood(), \StatusValue::newGood() ],
+ [ TemporaryPasswordAuthenticationRequest::class, 'UTSysop', \Status::wrap( $err ),
+ \StatusValue::newGood(), $err ],
+ [ TemporaryPasswordAuthenticationRequest::class, 'UTSysop',
+ \Status::newFatal( 'arbitrary-error' ), \StatusValue::newGood(),
+ \StatusValue::newFatal( 'arbitrary-error' ) ],
+ [ TemporaryPasswordAuthenticationRequest::class, 'DoesNotExist', \Status::newGood(),
+ \StatusValue::newGood(), \StatusValue::newGood( 'ignored' ) ],
+ [ TemporaryPasswordAuthenticationRequest::class, '<invalid>', \Status::newGood(),
+ \StatusValue::newGood(), \StatusValue::newGood( 'ignored' ) ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideProviderChangeAuthenticationData
+ * @param string $user
+ * @param string $type
+ * @param bool $changed
+ */
+ public function testProviderChangeAuthenticationData( $user, $type, $changed ) {
+ $cuser = ucfirst( $user );
+ $oldpass = 'OldTempPassword';
+ $newpass = 'NewTempPassword';
+
+ $hash = ':A:' . md5( $oldpass );
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update(
+ 'user',
+ [ 'user_newpassword' => $hash, 'user_newpass_time' => $dbw->timestamp( time() + 10 ) ],
+ [ 'user_name' => 'UTSysop' ]
+ );
+
+ $dbw = wfGetDB( DB_MASTER );
+ $oldHash = $dbw->selectField( 'user', 'user_newpassword', [ 'user_name' => $cuser ] );
+ $cb = new \ScopedCallback( function () use ( $dbw, $cuser, $oldHash ) {
+ $dbw->update( 'user', [ 'user_newpassword' => $oldHash ], [ 'user_name' => $cuser ] );
+ } );
+
+ $provider = $this->getProvider();
+
+ // Sanity check
+ $loginReq = new PasswordAuthenticationRequest();
+ $loginReq->action = AuthManager::ACTION_CHANGE;
+ $loginReq->username = $user;
+ $loginReq->password = $oldpass;
+ $loginReqs = [ PasswordAuthenticationRequest::class => $loginReq ];
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $cuser ),
+ $provider->beginPrimaryAuthentication( $loginReqs ),
+ 'Sanity check'
+ );
+
+ if ( $type === PasswordAuthenticationRequest::class ||
+ $type === TemporaryPasswordAuthenticationRequest::class
+ ) {
+ $changeReq = new $type();
+ } else {
+ $changeReq = $this->getMock( $type );
+ }
+ $changeReq->action = AuthManager::ACTION_CHANGE;
+ $changeReq->username = $user;
+ $changeReq->password = $newpass;
+ $resetMailer = $this->hookMailer();
+ $provider->providerChangeAuthenticationData( $changeReq );
+ \ScopedCallback::consume( $resetMailer );
+
+ $loginReq->password = $oldpass;
+ $ret = $provider->beginPrimaryAuthentication( $loginReqs );
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status,
+ 'old password should fail'
+ );
+ $this->assertEquals(
+ 'wrongpassword',
+ $ret->message->getKey(),
+ 'old password should fail'
+ );
+
+ $loginReq->password = $newpass;
+ $ret = $provider->beginPrimaryAuthentication( $loginReqs );
+ if ( $changed ) {
+ $this->assertEquals(
+ AuthenticationResponse::newPass( $cuser ),
+ $ret,
+ 'new password should pass'
+ );
+ $this->assertNotNull(
+ $dbw->selectField( 'user', 'user_newpass_time', [ 'user_name' => $cuser ] )
+ );
+ } else {
+ $this->assertEquals(
+ AuthenticationResponse::FAIL,
+ $ret->status,
+ 'new password should fail'
+ );
+ $this->assertEquals(
+ 'wrongpassword',
+ $ret->message->getKey(),
+ 'new password should fail'
+ );
+ $this->assertNull(
+ $dbw->selectField( 'user', 'user_newpass_time', [ 'user_name' => $cuser ] )
+ );
+ }
+ }
+
+ public static function provideProviderChangeAuthenticationData() {
+ return [
+ [ 'UTSysop', AuthenticationRequest::class, false ],
+ [ 'UTSysop', PasswordAuthenticationRequest::class, false ],
+ [ 'UTSysop', TemporaryPasswordAuthenticationRequest::class, true ],
+ ];
+ }
+
+ public function testProviderChangeAuthenticationDataEmail() {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update(
+ 'user',
+ [ 'user_newpass_time' => $dbw->timestamp( time() - 5 * 3600 ) ],
+ [ 'user_name' => 'UTSysop' ]
+ );
+
+ $user = \User::newFromName( 'UTSysop' );
+ $reset = new \ScopedCallback( function ( $email ) use ( $user ) {
+ $user->setEmail( $email );
+ $user->saveSettings();
+ }, [ $user->getEmail() ] );
+
+ $user->setEmail( 'test@localhost.localdomain' );
+ $user->saveSettings();
+
+ $req = TemporaryPasswordAuthenticationRequest::newRandom();
+ $req->username = $user->getName();
+ $req->mailpassword = true;
+
+ $provider = $this->getProvider( [ 'emailEnabled' => false ] );
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertEquals( \StatusValue::newFatal( 'passwordreset-emaildisabled' ), $status );
+ $req->hasBackchannel = true;
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertFalse( $status->hasMessage( 'passwordreset-emaildisabled' ) );
+ $req->hasBackchannel = false;
+
+ $provider = $this->getProvider( [ 'passwordReminderResendTime' => 10 ] );
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertEquals( \StatusValue::newFatal( 'throttled-mailpassword', 10 ), $status );
+
+ $provider = $this->getProvider( [ 'passwordReminderResendTime' => 3 ] );
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
+
+ $dbw->update(
+ 'user',
+ [ 'user_newpass_time' => $dbw->timestamp( time() + 5 * 3600 ) ],
+ [ 'user_name' => 'UTSysop' ]
+ );
+ $provider = $this->getProvider( [ 'passwordReminderResendTime' => 0 ] );
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
+
+ $req->caller = null;
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertEquals( \StatusValue::newFatal( 'passwordreset-nocaller' ), $status );
+
+ $req->caller = '127.0.0.256';
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertEquals( \StatusValue::newFatal( 'passwordreset-nosuchcaller', '127.0.0.256' ),
+ $status );
+
+ $req->caller = '<Invalid>';
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertEquals( \StatusValue::newFatal( 'passwordreset-nosuchcaller', '<Invalid>' ),
+ $status );
+
+ $req->caller = '127.0.0.1';
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertEquals( \StatusValue::newGood(), $status );
+
+ $req->caller = 'UTSysop';
+ $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
+ $this->assertEquals( \StatusValue::newGood(), $status );
+
+ $mailed = false;
+ $resetMailer = $this->hookMailer( function ( $headers, $to, $from, $subject, $body )
+ use ( &$mailed, $req )
+ {
+ $mailed = true;
+ $this->assertSame( 'test@localhost.localdomain', $to[0]->address );
+ $this->assertContains( $req->password, $body );
+ return false;
+ } );
+ $provider->providerChangeAuthenticationData( $req );
+ \ScopedCallback::consume( $resetMailer );
+ $this->assertTrue( $mailed );
+
+ $priv = \TestingAccessWrapper::newFromObject( $provider );
+ $req->username = '<invalid>';
+ $status = $priv->sendPasswordResetEmail( $req );
+ $this->assertEquals( \Status::newFatal( 'noname' ), $status );
+ }
+
+ public function testTestForAccountCreation() {
+ $user = \User::newFromName( 'foo' );
+ $req = new TemporaryPasswordAuthenticationRequest();
+ $req->username = 'Foo';
+ $req->password = 'Bar';
+ $reqs = [ TemporaryPasswordAuthenticationRequest::class => $req ];
+
+ $provider = $this->getProvider();
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $user, [] ),
+ 'No password request'
+ );
+
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $user, $reqs ),
+ 'Password request, validated'
+ );
+
+ $this->validity->error( 'arbitrary warning' );
+ $expect = \StatusValue::newGood();
+ $expect->error( 'arbitrary warning' );
+ $this->assertEquals(
+ $expect,
+ $provider->testForAccountCreation( $user, $user, $reqs ),
+ 'Password request, not validated'
+ );
+ }
+
+ public function testAccountCreation() {
+ $resetMailer = $this->hookMailer();
+
+ $user = \User::newFromName( 'Foo' );
+
+ $req = new TemporaryPasswordAuthenticationRequest();
+ $reqs = [ TemporaryPasswordAuthenticationRequest::class => $req ];
+
+ $authreq = new PasswordAuthenticationRequest();
+ $authreq->action = AuthManager::ACTION_CREATE;
+ $authreqs = [ PasswordAuthenticationRequest::class => $authreq ];
+
+ $provider = $this->getProvider();
+
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAccountCreation( $user, $user, [] )
+ );
+
+ $req->username = 'foo';
+ $req->password = null;
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+ );
+
+ $req->username = null;
+ $req->password = 'bar';
+ $this->assertEquals(
+ AuthenticationResponse::newAbstain(),
+ $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+ );
+
+ $req->username = 'foo';
+ $req->password = 'bar';
+
+ $expect = AuthenticationResponse::newPass( 'Foo' );
+ $expect->createRequest = clone( $req );
+ $expect->createRequest->username = 'Foo';
+ $this->assertEquals( $expect, $provider->beginPrimaryAccountCreation( $user, $user, $reqs ) );
+ $this->assertNull( $this->manager->getAuthenticationSessionData( 'no-email' ) );
+
+ // We have to cheat a bit to avoid having to add a new user to
+ // the database to test the actual setting of the password works right
+ $user = \User::newFromName( 'UTSysop' );
+ $req->username = $authreq->username = $user->getName();
+ $req->password = $authreq->password = 'NewPassword';
+ $expect = AuthenticationResponse::newPass( 'UTSysop' );
+ $expect->createRequest = $req;
+
+ $res2 = $provider->beginPrimaryAccountCreation( $user, $user, $reqs );
+ $this->assertEquals( $expect, $res2, 'Sanity check' );
+
+ $ret = $provider->beginPrimaryAuthentication( $authreqs );
+ $this->assertEquals( AuthenticationResponse::FAIL, $ret->status, 'sanity check' );
+
+ $this->assertSame( null, $provider->finishAccountCreation( $user, $user, $res2 ) );
+
+ $ret = $provider->beginPrimaryAuthentication( $authreqs );
+ $this->assertEquals( AuthenticationResponse::PASS, $ret->status, 'new password is set' );
+ }
+
+ public function testAccountCreationEmail() {
+ $creator = \User::newFromName( 'Foo' );
+ $user = \User::newFromName( 'UTSysop' );
+ $reset = new \ScopedCallback( function ( $email ) use ( $user ) {
+ $user->setEmail( $email );
+ $user->saveSettings();
+ }, [ $user->getEmail() ] );
+
+ $user->setEmail( null );
+
+ $req = TemporaryPasswordAuthenticationRequest::newRandom();
+ $req->username = $user->getName();
+ $req->mailpassword = true;
+
+ $provider = $this->getProvider( [ 'emailEnabled' => false ] );
+ $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
+ $this->assertEquals( \StatusValue::newFatal( 'emaildisabled' ), $status );
+ $req->hasBackchannel = true;
+ $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
+ $this->assertFalse( $status->hasMessage( 'emaildisabled' ) );
+ $req->hasBackchannel = false;
+
+ $provider = $this->getProvider( [ 'emailEnabled' => true ] );
+ $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
+ $this->assertEquals( \StatusValue::newFatal( 'noemailcreate' ), $status );
+ $req->hasBackchannel = true;
+ $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
+ $this->assertFalse( $status->hasMessage( 'noemailcreate' ) );
+ $req->hasBackchannel = false;
+
+ $user->setEmail( 'test@localhost.localdomain' );
+ $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
+ $this->assertEquals( \StatusValue::newGood(), $status );
+
+ $mailed = false;
+ $resetMailer = $this->hookMailer( function ( $headers, $to, $from, $subject, $body )
+ use ( &$mailed, $req )
+ {
+ $mailed = true;
+ $this->assertSame( 'test@localhost.localdomain', $to[0]->address );
+ $this->assertContains( $req->password, $body );
+ return false;
+ } );
+
+ $expect = AuthenticationResponse::newPass( 'UTSysop' );
+ $expect->createRequest = clone( $req );
+ $expect->createRequest->username = 'UTSysop';
+ $res = $provider->beginPrimaryAccountCreation( $user, $creator, [ $req ] );
+ $this->assertEquals( $expect, $res );
+ $this->assertTrue( $this->manager->getAuthenticationSessionData( 'no-email' ) );
+ $this->assertFalse( $mailed );
+
+ $this->assertSame( 'byemail', $provider->finishAccountCreation( $user, $creator, $res ) );
+ $this->assertTrue( $mailed );
+
+ \ScopedCallback::consume( $resetMailer );
+ $this->assertTrue( $mailed );
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @group Database
+ * @covers MediaWiki\Auth\ThrottlePreAuthenticationProvider
+ */
+class ThrottlePreAuthenticationProviderTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testConstructor() {
+ $provider = new ThrottlePreAuthenticationProvider();
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+ $config = new \HashConfig( [
+ 'AccountCreationThrottle' => 123,
+ 'PasswordAttemptThrottle' => [ [
+ 'count' => 5,
+ 'seconds' => 300,
+ ] ],
+ ] );
+ $provider->setConfig( $config );
+ $this->assertSame( [
+ 'accountCreationThrottle' => [ [ 'count' => 123, 'seconds' => 86400 ] ],
+ 'passwordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300 ] ]
+ ], $providerPriv->throttleSettings );
+ $accountCreationThrottle = \TestingAccessWrapper::newFromObject(
+ $providerPriv->accountCreationThrottle );
+ $this->assertSame( [ [ 'count' => 123, 'seconds' => 86400 ] ],
+ $accountCreationThrottle->conditions );
+ $passwordAttemptThrottle = \TestingAccessWrapper::newFromObject(
+ $providerPriv->passwordAttemptThrottle );
+ $this->assertSame( [ [ 'count' => 5, 'seconds' => 300 ] ],
+ $passwordAttemptThrottle->conditions );
+
+ $provider = new ThrottlePreAuthenticationProvider( [
+ 'accountCreationThrottle' => [ [ 'count' => 43, 'seconds' => 10000 ] ],
+ 'passwordAttemptThrottle' => [ [ 'count' => 11, 'seconds' => 100 ] ],
+ ] );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+ $config = new \HashConfig( [
+ 'AccountCreationThrottle' => 123,
+ 'PasswordAttemptThrottle' => [ [
+ 'count' => 5,
+ 'seconds' => 300,
+ ] ],
+ ] );
+ $provider->setConfig( $config );
+ $this->assertSame( [
+ 'accountCreationThrottle' => [ [ 'count' => 43, 'seconds' => 10000 ] ],
+ 'passwordAttemptThrottle' => [ [ 'count' => 11, 'seconds' => 100 ] ],
+ ], $providerPriv->throttleSettings );
+
+ $cache = new \HashBagOStuff();
+ $provider = new ThrottlePreAuthenticationProvider( [ 'cache' => $cache ] );
+ $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
+ $provider->setConfig( new \HashConfig( [
+ 'AccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 1 ] ],
+ 'PasswordAttemptThrottle' => [ [ 'count' => 1, 'seconds' => 1 ] ],
+ ] ) );
+ $accountCreationThrottle = \TestingAccessWrapper::newFromObject(
+ $providerPriv->accountCreationThrottle );
+ $this->assertSame( $cache, $accountCreationThrottle->cache );
+ $passwordAttemptThrottle = \TestingAccessWrapper::newFromObject(
+ $providerPriv->passwordAttemptThrottle );
+ $this->assertSame( $cache, $passwordAttemptThrottle->cache );
+ }
+
+ public function testDisabled() {
+ $provider = new ThrottlePreAuthenticationProvider( [
+ 'accountCreationThrottle' => [],
+ 'passwordAttemptThrottle' => [],
+ 'cache' => new \HashBagOStuff(),
+ ] );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setConfig( new \HashConfig( [
+ 'AccountCreationThrottle' => null,
+ 'PasswordAttemptThrottle' => null,
+ ] ) );
+ $provider->setManager( AuthManager::singleton() );
+
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation(
+ \User::newFromName( 'Created' ),
+ \User::newFromName( 'Creator' ),
+ []
+ )
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAuthentication( [] )
+ );
+ }
+
+ /**
+ * @dataProvider provideTestForAccountCreation
+ * @param string $creatorname
+ * @param bool $succeed
+ * @param bool $hook
+ */
+ public function testTestForAccountCreation( $creatorname, $succeed, $hook ) {
+ $provider = new ThrottlePreAuthenticationProvider( [
+ 'accountCreationThrottle' => [ [ 'count' => 2, 'seconds' => 86400 ] ],
+ 'cache' => new \HashBagOStuff(),
+ ] );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setConfig( new \HashConfig( [
+ 'AccountCreationThrottle' => null,
+ 'PasswordAttemptThrottle' => null,
+ ] ) );
+ $provider->setManager( AuthManager::singleton() );
+
+ $user = \User::newFromName( 'RandomUser' );
+ $creator = \User::newFromName( $creatorname );
+ if ( $hook ) {
+ $mock = $this->getMock( 'stdClass', [ 'onExemptFromAccountCreationThrottle' ] );
+ $mock->expects( $this->any() )->method( 'onExemptFromAccountCreationThrottle' )
+ ->will( $this->returnValue( false ) );
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [
+ 'ExemptFromAccountCreationThrottle' => [ $mock ],
+ ] );
+ }
+
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $creator, [] ),
+ 'attempt #1'
+ );
+ $this->assertEquals(
+ \StatusValue::newGood(),
+ $provider->testForAccountCreation( $user, $creator, [] ),
+ 'attempt #2'
+ );
+ $this->assertEquals(
+ $succeed ? \StatusValue::newGood() : \StatusValue::newFatal( 'acct_creation_throttle_hit', 2 ),
+ $provider->testForAccountCreation( $user, $creator, [] ),
+ 'attempt #3'
+ );
+ }
+
+ public static function provideTestForAccountCreation() {
+ return [
+ 'Normal user' => [ 'NormalUser', false, false ],
+ 'Sysop' => [ 'UTSysop', true, false ],
+ 'Normal user with hook' => [ 'NormalUser', true, true ],
+ ];
+ }
+
+ public function testTestForAuthentication() {
+ $provider = new ThrottlePreAuthenticationProvider( [
+ 'passwordAttemptThrottle' => [ [ 'count' => 2, 'seconds' => 86400 ] ],
+ 'cache' => new \HashBagOStuff(),
+ ] );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setConfig( new \HashConfig( [
+ 'AccountCreationThrottle' => null,
+ 'PasswordAttemptThrottle' => null,
+ ] ) );
+ $provider->setManager( AuthManager::singleton() );
+
+ $req = new UsernameAuthenticationRequest;
+ $req->username = 'SomeUser';
+ for ( $i = 1; $i <= 3; $i++ ) {
+ $status = $provider->testForAuthentication( [ $req ] );
+ $this->assertEquals( $i < 3, $status->isGood(), "attempt #$i" );
+ }
+ $this->assertCount( 1, $status->getErrors() );
+ $msg = new \Message( $status->getErrors()[0]['message'], $status->getErrors()[0]['params'] );
+ $this->assertEquals( 'login-throttled', $msg->getKey() );
+
+ $provider->postAuthentication( \User::newFromName( 'SomeUser' ),
+ AuthenticationResponse::newFail( wfMessage( 'foo' ) ) );
+ $this->assertFalse( $provider->testForAuthentication( [ $req ] )->isGood(), 'after FAIL' );
+
+ $provider->postAuthentication( \User::newFromName( 'SomeUser' ),
+ AuthenticationResponse::newPass() );
+ $this->assertTrue( $provider->testForAuthentication( [ $req ] )->isGood(), 'after PASS' );
+
+ $req1 = new UsernameAuthenticationRequest;
+ $req1->username = 'foo';
+ $req2 = new UsernameAuthenticationRequest;
+ $req2->username = 'bar';
+ $this->assertTrue( $provider->testForAuthentication( [ $req1, $req2 ] )->isGood() );
+
+ $req = new UsernameAuthenticationRequest;
+ $req->username = 'Some user';
+ $provider->testForAuthentication( [ $req ] );
+ $req->username = 'Some_user';
+ $provider->testForAuthentication( [ $req ] );
+ $req->username = 'some user';
+ $status = $provider->testForAuthentication( [ $req ] );
+ $this->assertFalse( $status->isGood(), 'denormalized usernames are normalized' );
+ }
+
+ public function testPostAuthentication() {
+ $provider = new ThrottlePreAuthenticationProvider( [
+ 'passwordAttemptThrottle' => [],
+ 'cache' => new \HashBagOStuff(),
+ ] );
+ $provider->setLogger( new \TestLogger );
+ $provider->setConfig( new \HashConfig( [
+ 'AccountCreationThrottle' => null,
+ 'PasswordAttemptThrottle' => null,
+ ] ) );
+ $provider->setManager( AuthManager::singleton() );
+ $provider->postAuthentication( \User::newFromName( 'SomeUser' ),
+ AuthenticationResponse::newPass() );
+
+ $provider = new ThrottlePreAuthenticationProvider( [
+ 'passwordAttemptThrottle' => [ [ 'count' => 2, 'seconds' => 86400 ] ],
+ 'cache' => new \HashBagOStuff(),
+ ] );
+ $logger = new \TestLogger( true );
+ $provider->setLogger( $logger );
+ $provider->setConfig( new \HashConfig( [
+ 'AccountCreationThrottle' => null,
+ 'PasswordAttemptThrottle' => null,
+ ] ) );
+ $provider->setManager( AuthManager::singleton() );
+ $provider->postAuthentication( \User::newFromName( 'SomeUser' ),
+ AuthenticationResponse::newPass() );
+ $this->assertSame( [
+ [ \Psr\Log\LogLevel::ERROR, 'throttler data not found for {user}' ],
+ ], $logger->getBuffer() );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+use BagOStuff;
+use HashBagOStuff;
+use InvalidArgumentException;
+use Psr\Log\AbstractLogger;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\Throttler
+ */
+class ThrottlerTest extends \MediaWikiTestCase {
+ protected function setUp() {
+ global $wgDisableAuthManager;
+
+ parent::setUp();
+ if ( $wgDisableAuthManager ) {
+ $this->markTestSkipped( '$wgDisableAuthManager is set' );
+ }
+ }
+
+ public function testConstructor() {
+ $cache = new \HashBagOStuff();
+ $logger = $this->getMockBuilder( AbstractLogger::class )
+ ->setMethods( [ 'log' ] )
+ ->getMockForAbstractClass();
+
+ $throttler = new Throttler(
+ [ [ 'count' => 123, 'seconds' => 456 ] ],
+ [ 'type' => 'foo', 'cache' => $cache ]
+ );
+ $throttler->setLogger( $logger );
+ $throttlerPriv = \TestingAccessWrapper::newFromObject( $throttler );
+ $this->assertSame( [ [ 'count' => 123, 'seconds' => 456 ] ], $throttlerPriv->conditions );
+ $this->assertSame( 'foo', $throttlerPriv->type );
+ $this->assertSame( $cache, $throttlerPriv->cache );
+ $this->assertSame( $logger, $throttlerPriv->logger );
+
+ $throttler = new Throttler( [ [ 'count' => 123, 'seconds' => 456 ] ] );
+ $throttler->setLogger( new NullLogger() );
+ $throttlerPriv = \TestingAccessWrapper::newFromObject( $throttler );
+ $this->assertSame( [ [ 'count' => 123, 'seconds' => 456 ] ], $throttlerPriv->conditions );
+ $this->assertSame( 'custom', $throttlerPriv->type );
+ $this->assertInstanceOf( BagOStuff::class, $throttlerPriv->cache );
+ $this->assertInstanceOf( LoggerInterface::class, $throttlerPriv->logger );
+
+ $this->setMwGlobals( [ 'wgPasswordAttemptThrottle' => [ [ 'count' => 321,
+ 'seconds' => 654 ] ] ] );
+ $throttler = new Throttler();
+ $throttler->setLogger( new NullLogger() );
+ $throttlerPriv = \TestingAccessWrapper::newFromObject( $throttler );
+ $this->assertSame( [ [ 'count' => 321, 'seconds' => 654 ] ], $throttlerPriv->conditions );
+ $this->assertSame( 'password', $throttlerPriv->type );
+ $this->assertInstanceOf( BagOStuff::class, $throttlerPriv->cache );
+ $this->assertInstanceOf( LoggerInterface::class, $throttlerPriv->logger );
+
+ try {
+ new Throttler( [], [ 'foo' => 1, 'bar' => 2, 'baz' => 3 ] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \InvalidArgumentException $ex ) {
+ $this->assertSame( 'unrecognized parameters: foo, bar, baz', $ex->getMessage() );
+ }
+ }
+
+ /**
+ * @dataProvider provideNormalizeThrottleConditions
+ */
+ public function testNormalizeThrottleConditions( $condition, $normalized ) {
+ $throttler = new Throttler( $condition );
+ $throttler->setLogger( new NullLogger() );
+ $throttlerPriv = \TestingAccessWrapper::newFromObject( $throttler );
+ $this->assertSame( $normalized, $throttlerPriv->conditions );
+ }
+
+ public function provideNormalizeThrottleConditions() {
+ return [
+ [
+ [],
+ [],
+ ],
+ [
+ [ 'count' => 1, 'seconds' => 2 ],
+ [ [ 'count' => 1, 'seconds' => 2 ] ],
+ ],
+ [
+ [ [ 'count' => 1, 'seconds' => 2 ], [ 'count' => 2, 'seconds' => 3 ] ],
+ [ [ 'count' => 1, 'seconds' => 2 ], [ 'count' => 2, 'seconds' => 3 ] ],
+ ],
+ ];
+ }
+
+ public function testNormalizeThrottleConditions2() {
+ $priv = \TestingAccessWrapper::newFromClass( Throttler::class );
+ $this->assertSame( [], $priv->normalizeThrottleConditions( null ) );
+ $this->assertSame( [], $priv->normalizeThrottleConditions( 'bad' ) );
+ }
+
+ public function testIncrease() {
+ $cache = new \HashBagOStuff();
+ $throttler = new Throttler( [
+ [ 'count' => 2, 'seconds' => 10, ],
+ [ 'count' => 4, 'seconds' => 15, 'allIPs' => true ],
+ ], [ 'cache' => $cache ] );
+ $throttler->setLogger( new NullLogger() );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 2, 'wait' => 10 ], $result );
+
+ $result = $throttler->increase( 'OtherUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '2.3.4.5' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '3.4.5.6' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '3.4.5.6' );
+ $this->assertSame( [ 'throttleIndex' => 1, 'count' => 4, 'wait' => 15 ], $result );
+ }
+
+ public function testZeroCount() {
+ $cache = new \HashBagOStuff();
+ $throttler = new Throttler( [ [ 'count' => 0, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
+ $throttler->setLogger( new NullLogger() );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle, count=0 is ignored' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle, count=0 is ignored' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle, count=0 is ignored' );
+ }
+
+ public function testNamespacing() {
+ $cache = new \HashBagOStuff();
+ $throttler1 = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ],
+ [ 'cache' => $cache, 'type' => 'foo' ] );
+ $throttler2 = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ],
+ [ 'cache' => $cache, 'type' => 'foo' ] );
+ $throttler3 = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ],
+ [ 'cache' => $cache, 'type' => 'bar' ] );
+ $throttler1->setLogger( new NullLogger() );
+ $throttler2->setLogger( new NullLogger() );
+ $throttler3->setLogger( new NullLogger() );
+
+ $throttled = [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ];
+
+ $result = $throttler1->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler1->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertEquals( $throttled, $result, 'should throttle' );
+
+ $result = $throttler2->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertEquals( $throttled, $result, 'should throttle, same namespace' );
+
+ $result = $throttler3->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle, different namespace' );
+ }
+
+ public function testExpiration() {
+ $cache = $this->getMock( HashBagOStuff::class, [ 'add' ] );
+ $throttler = new Throttler( [ [ 'count' => 3, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
+ $throttler->setLogger( new NullLogger() );
+
+ $cache->expects( $this->once() )->method( 'add' )->with( $this->anything(), 1, 10 );
+ $throttler->increase( 'SomeUser' );
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testException() {
+ $throttler = new Throttler( [ [ 'count' => 3, 'seconds' => 10 ] ] );
+ $throttler->setLogger( new NullLogger() );
+ $throttler->increase();
+ }
+
+ public function testLog() {
+ $cache = new \HashBagOStuff();
+ $throttler = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
+
+ $logger = $this->getMockBuilder( AbstractLogger::class )
+ ->setMethods( [ 'log' ] )
+ ->getMockForAbstractClass();
+ $logger->expects( $this->never() )->method( 'log' );
+ $throttler->setLogger( $logger );
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $logger = $this->getMockBuilder( AbstractLogger::class )
+ ->setMethods( [ 'log' ] )
+ ->getMockForAbstractClass();
+ $logger->expects( $this->once() )->method( 'log' )->with( $this->anything(), $this->anything(), [
+ 'type' => 'custom',
+ 'index' => 0,
+ 'ip' => '1.2.3.4',
+ 'username' => 'SomeUser',
+ 'count' => 1,
+ 'expiry' => 10,
+ 'method' => 'foo',
+ ] );
+ $throttler->setLogger( $logger );
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4', 'foo' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
+ }
+
+ public function testClear() {
+ $cache = new \HashBagOStuff();
+ $throttler = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
+ $throttler->setLogger( new NullLogger() );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
+
+ $result = $throttler->increase( 'OtherUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'OtherUser', '1.2.3.4' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
+
+ $throttler->clear( 'SomeUser', '1.2.3.4' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'OtherUser', '1.2.3.4' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\UserDataAuthenticationRequest
+ */
+class UserDataAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ return new UserDataAuthenticationRequest;
+ }
+
+ protected function setUp() {
+ parent::setUp();
+ $this->setMwGlobals( 'wgHiddenPrefs', [] );
+ }
+
+ /**
+ * @dataProvider providePopulateUser
+ * @param string $email Email to set
+ * @param string $realname Realname to set
+ * @param StatusValue $expect Expected return
+ */
+ public function testPopulateUser( $email, $realname, $expect ) {
+ $user = new \User();
+ $user->setEmail( 'default@example.com' );
+ $user->setRealName( 'Fake Name' );
+
+ $req = new UserDataAuthenticationRequest;
+ $req->email = $email;
+ $req->realname = $realname;
+ $this->assertEquals( $expect, $req->populateUser( $user ) );
+ if ( $expect->isOk() ) {
+ $this->assertSame( $email ?: 'default@example.com', $user->getEmail() );
+ $this->assertSame( $realname ?: 'Fake Name', $user->getRealName() );
+ }
+
+ }
+
+ public static function providePopulateUser() {
+ $good = \StatusValue::newGood();
+ return [
+ [ 'email@example.com', 'Real Name', $good ],
+ [ 'email@example.com', '', $good ],
+ [ '', 'Real Name', $good ],
+ [ '', '', $good ],
+ [ 'invalid-email', 'Real Name', \StatusValue::newFatal( 'invalidemailaddress' ) ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideLoadFromSubmission
+ */
+ public function testLoadFromSubmission(
+ array $args, array $data, $expectState /* $hiddenPref, $enableEmail */
+ ) {
+ list( $args, $data, $expectState, $hiddenPref, $enableEmail ) = func_get_args();
+ $this->setMwGlobals( 'wgHiddenPrefs', $hiddenPref );
+ $this->setMwGlobals( 'wgEnableEmail', $enableEmail );
+ parent::testLoadFromSubmission( $args, $data, $expectState );
+ }
+
+ public function provideLoadFromSubmission() {
+ $unhidden = [];
+ $hidden = [ 'realname' ];
+
+ return [
+ 'Empty request, unhidden, email enabled' => [
+ [],
+ [],
+ false,
+ $unhidden,
+ true
+ ],
+ 'email + realname, unhidden, email enabled' => [
+ [],
+ $data = [ 'email' => 'Email', 'realname' => 'Name' ],
+ $data,
+ $unhidden,
+ true
+ ],
+ 'email empty, unhidden, email enabled' => [
+ [],
+ $data = [ 'email' => '', 'realname' => 'Name' ],
+ $data,
+ $unhidden,
+ true
+ ],
+ 'email omitted, unhidden, email enabled' => [
+ [],
+ [ 'realname' => 'Name' ],
+ false,
+ $unhidden,
+ true
+ ],
+ 'realname empty, unhidden, email enabled' => [
+ [],
+ $data = [ 'email' => 'Email', 'realname' => '' ],
+ $data,
+ $unhidden,
+ true
+ ],
+ 'realname omitted, unhidden, email enabled' => [
+ [],
+ [ 'email' => 'Email' ],
+ false,
+ $unhidden,
+ true
+ ],
+ 'Empty request, hidden, email enabled' => [
+ [],
+ [],
+ false,
+ $hidden,
+ true
+ ],
+ 'email + realname, hidden, email enabled' => [
+ [],
+ [ 'email' => 'Email', 'realname' => 'Name' ],
+ [ 'email' => 'Email' ],
+ $hidden,
+ true
+ ],
+ 'email empty, hidden, email enabled' => [
+ [],
+ $data = [ 'email' => '', 'realname' => 'Name' ],
+ [ 'email' => '' ],
+ $hidden,
+ true
+ ],
+ 'email omitted, hidden, email enabled' => [
+ [],
+ [ 'realname' => 'Name' ],
+ false,
+ $hidden,
+ true
+ ],
+ 'realname empty, hidden, email enabled' => [
+ [],
+ $data = [ 'email' => 'Email', 'realname' => '' ],
+ [ 'email' => 'Email' ],
+ $hidden,
+ true
+ ],
+ 'realname omitted, hidden, email enabled' => [
+ [],
+ [ 'email' => 'Email' ],
+ [ 'email' => 'Email' ],
+ $hidden,
+ true
+ ],
+ 'email + realname, unhidden, email disabled' => [
+ [],
+ [ 'email' => 'Email', 'realname' => 'Name' ],
+ [ 'realname' => 'Name' ],
+ $unhidden,
+ false
+ ],
+ 'email omitted, unhidden, email disabled' => [
+ [],
+ [ 'realname' => 'Name' ],
+ [ 'realname' => 'Name' ],
+ $unhidden,
+ false
+ ],
+ 'email empty, unhidden, email disabled' => [
+ [],
+ [ 'email' => '', 'realname' => 'Name' ],
+ [ 'realname' => 'Name' ],
+ $unhidden,
+ false
+ ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\UsernameAuthenticationRequest
+ */
+class UsernameAuthenticationRequestTest extends AuthenticationRequestTestCase {
+
+ protected function getInstance( array $args = [] ) {
+ return new UsernameAuthenticationRequest();
+ }
+
+ public function provideLoadFromSubmission() {
+ return [
+ 'Empty request' => [
+ [],
+ [],
+ false
+ ],
+ 'Username' => [
+ [],
+ $data = [ 'username' => 'User' ],
+ $data,
+ ],
+ 'Username empty' => [
+ [],
+ [ 'username' => '' ],
+ false
+ ],
+ ];
+ }
+}
*/
class GenderCacheTest extends MediaWikiLangTestCase {
+ /** @var string[] User key => username */
+ private static $nameMap;
+
function addDBDataOnce() {
// ensure the correct default gender
$this->mergeMwGlobalArrayValue( 'wgDefaultUserOptions', [ 'gender' => 'unknown' ] );
- $user = User::newFromName( 'UTMale' );
- if ( $user->getId() == 0 ) {
- $user->addToDatabase();
- TestUser::setPasswordForUser( $user, 'UTMalePassword' );
- }
- // ensure the right gender
- $user->setOption( 'gender', 'male' );
- $user->saveSettings();
+ $male = $this->getMutableTestUser()->getUser();
+ $male->setOption( 'gender', 'male' );
+ $male->saveSettings();
+
+ $female = $this->getMutableTestUser()->getUser();
+ $female->setOption( 'gender', 'female' );
+ $female->saveSettings();
- $user = User::newFromName( 'UTFemale' );
- if ( $user->getId() == 0 ) {
- $user->addToDatabase();
- TestUser::setPasswordForUser( $user, 'UTFemalePassword' );
- }
- // ensure the right gender
- $user->setOption( 'gender', 'female' );
- $user->saveSettings();
+ $default = $this->getMutableTestUser()->getUser();
+ $default->setOption( 'gender', null );
+ $default->saveSettings();
- $user = User::newFromName( 'UTDefaultGender' );
- if ( $user->getId() == 0 ) {
- $user->addToDatabase();
- TestUser::setPasswordForUser( $user, 'UTDefaultGenderPassword' );
- }
- // ensure the default gender
- $user->setOption( 'gender', null );
- $user->saveSettings();
+ self::$nameMap = [
+ 'UTMale' => $male->getName(),
+ 'UTFemale' => $female->getName(),
+ 'UTDefaultGender' => $default->getName()
+ ];
}
/**
* @dataProvider provideUserGenders
* @covers GenderCache::getGenderOf
*/
- public function testUserName( $username, $expectedGender ) {
+ public function testUserName( $userKey, $expectedGender ) {
$genderCache = GenderCache::singleton();
+ $username = isset( self::$nameMap[$userKey] ) ? self::$nameMap[$userKey] : $userKey;
$gender = $genderCache->getGenderOf( $username );
$this->assertEquals( $gender, $expectedGender, "GenderCache normal" );
}
* @dataProvider provideUserGenders
* @covers GenderCache::getGenderOf
*/
- public function testUserObjects( $username, $expectedGender ) {
+ public function testUserObjects( $userKey, $expectedGender ) {
+ $username = isset( self::$nameMap[$userKey] ) ? self::$nameMap[$userKey] : $userKey;
$genderCache = GenderCache::singleton();
- $user = User::newFromName( $username );
- $gender = $genderCache->getGenderOf( $user );
+ $gender = $genderCache->getGenderOf( $username );
$this->assertEquals( $gender, $expectedGender, "GenderCache normal" );
}
* test strip of subpages to avoid unnecessary queries
* against the never existing username
*
- * @dataProvider provideStripSubpages
+ * @dataProvider provideUserGenders
* @covers GenderCache::getGenderOf
*/
- public function testStripSubpages( $pageWithSubpage, $expectedGender ) {
+ public function testStripSubpages( $userKey, $expectedGender ) {
+ $username = isset( self::$nameMap[$userKey] ) ? self::$nameMap[$userKey] : $userKey;
$genderCache = GenderCache::singleton();
- $gender = $genderCache->getGenderOf( $pageWithSubpage );
+ $gender = $genderCache->getGenderOf( "$username/subpage" );
$this->assertEquals( $gender, $expectedGender, "GenderCache must strip of subpages" );
}
-
- public static function provideStripSubpages() {
- return [
- [ 'UTMale/subpage', 'male' ],
- [ 'UTFemale/subpage', 'female' ],
- [ 'UTDefaultGender/subpage', 'unknown' ],
- [ 'UTNotExist/subpage', 'unknown' ],
- [ '127.0.0.1/subpage', 'unknown' ],
- ];
- }
}
*/
private static $pageRev = null;
+ /**
+ * @var User
+ */
+ private static $revUser = null;
+
/**
* @var string
*/
$page = WikiPage::factory( $title );
self::$pageRev = $page->getRevision();
+ self::$revUser = User::newFromId( self::$pageRev->getUser( Revision::RAW ) );
}
private function newChange( Revision $revision = null ) {
$this->assertTrue( strlen( self::$lastNotifyArgs[0] ) === 14 );
$this->assertEquals( 'Category:CategoryName', self::$lastNotifyArgs[1]->getPrefixedText() );
- $this->assertEquals( 'UTSysop', self::$lastNotifyArgs[2]->getName() );
+ $this->assertEquals( self::$revUser->getName(), self::$lastNotifyArgs[2]->getName() );
$this->assertEquals( '(recentchanges-page-added-to-category: ' . self::$pageName . ')',
self::$lastNotifyArgs[3] );
$this->assertEquals( self::$pageName, self::$lastNotifyArgs[4]->getPrefixedText() );
$this->assertTrue( strlen( self::$lastNotifyArgs[0] ) === 14 );
$this->assertEquals( 'Category:CategoryName', self::$lastNotifyArgs[1]->getPrefixedText() );
- $this->assertEquals( 'UTSysop', self::$lastNotifyArgs[2]->getName() );
+ $this->assertEquals( self::$revUser->getName(), self::$lastNotifyArgs[2]->getName() );
$this->assertEquals( '(recentchanges-page-removed-from-category: ' . self::$pageName . ')',
self::$lastNotifyArgs[3] );
$this->assertEquals( self::$pageName, self::$lastNotifyArgs[4]->getPrefixedText() );
* @return RecentChange
*/
private function getEditChange( $timestamp ) {
- $user = $this->getTestUser();
+ $user = $this->getMutableTestUser()->getUser();
$recentChange = $this->testRecentChangesHelper->makeEditRecentChange(
$user, 'Cat', $timestamp, 5, 191, 190, 0, 0
);
$wikiPage = new WikiPage( Title::newFromText( 'Category:Foo' ) );
$wikiPage->doEditContent( new WikitextContent( 'Some random text' ), 'category page created' );
- $user = $this->getTestUser();
+ $user = $this->getMutableTestUser()->getUser();
$recentChange = $this->testRecentChangesHelper->makeCategorizationRecentChange(
$user, 'Category:Foo', $wikiPage->getId(), $thisId, $lastId, $timestamp
);
return $recentChange;
}
- /**
- * @return User
- */
- private function getTestUser() {
- $user = User::newFromName( 'TestRecentChangesUser' );
-
- if ( !$user->getId() ) {
- $user->addToDatabase();
- }
-
- return $user;
- }
-
private function createCategorizationLine( $recentChange ) {
$enhancedChangesList = $this->newEnhancedChangesList();
$cacheEntry = $this->testRecentChangesHelper->getCacheEntry( $recentChange );
'assert diff link'
);
- $this->assertRegExp( '/tabindex="0"/', $line, 'assert tab index' );
$this->assertRegExp(
'/title=Cat&curid=20131103212153&action=history"/',
$line,
}
private function getNewBotEditChange() {
- $user = $this->getTestUser();
+ $user = $this->getMutableTestUser()->getUser();
$recentChange = $this->testRecentChangesHelper->makeNewBotEditRecentChange(
$user, 'Abc', '20131103212153', 5, 191, 190, 0, 0
}
private function getLogChange( $logType, $logAction ) {
- $user = $this->getTestUser();
+ $user = $this->getMutableTestUser()->getUser();
$recentChange = $this->testRecentChangesHelper->makeLogRecentChange(
$logType, $logAction, $user, 'Abc', '20131103212153', 0, 0
}
private function getEditChange() {
- $user = $this->getTestUser();
+ $user = $this->getMutableTestUser()->getUser();
$recentChange = $this->testRecentChangesHelper->makeEditRecentChange(
$user, 'Cat', '20131103212153', 5, 191, 190, 0, 0
);
return new OldChangesList( $context );
}
- private function getTestUser() {
- $user = User::newFromName( 'TestRecentChangesUser' );
-
- if ( !$user->getId() ) {
- $user->addToDatabase();
- }
-
- return $user;
- }
-
private function getContext() {
- $user = $this->getTestUser();
+ $user = $this->getMutableTestUser()->getUser();
$context = $this->testRecentChangesHelper->getTestContext( $user );
$context->setLanguage( 'qqx' );
<?php
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\MediaWikiServices;
+
/**
* @covers RCCacheEntryFactory
*
*/
private $testRecentChangesHelper;
+ /**
+ * @var LinkRenderer;
+ */
+ private $linkRenderer;
+
public function __construct( $name = null, array $data = [], $dataName = '' ) {
parent::__construct( $name, $data, $dataName );
$this->setMwGlobals( [
'wgArticlePath' => '/wiki/$1'
] );
+
+ $this->linkRenderer = new LinkRenderer(
+ MediaWikiServices::getInstance()->getTitleFormatter()
+ );
}
- /**
- * @dataProvider editChangeProvider
- */
- public function testNewFromRecentChange( $expected, $context, $messages,
- $recentChange, $watched
- ) {
- $cacheEntryFactory = new RCCacheEntryFactory( $context, $messages );
- $cacheEntry = $cacheEntryFactory->newFromRecentChange( $recentChange, $watched );
+ public function testNewFromRecentChange() {
+ $user = $this->getMutableTestUser()->getUser();
+ $recentChange = $this->testRecentChangesHelper->makeEditRecentChange(
+ $user,
+ 'Xyz',
+ 5, // curid
+ 191, // thisid
+ 190, // lastid
+ '20131103212153',
+ 0, // counter
+ 0 // number of watching users
+ );
+ $cacheEntryFactory = new RCCacheEntryFactory(
+ $this->getContext(),
+ $this->getMessages(),
+ $this->linkRenderer
+ );
+ $cacheEntry = $cacheEntryFactory->newFromRecentChange( $recentChange, false );
$this->assertInstanceOf( 'RCCacheEntry', $cacheEntry );
- $this->assertEquals( $watched, $cacheEntry->watched, 'watched' );
- $this->assertEquals( $expected['timestamp'], $cacheEntry->timestamp, 'timestamp' );
- $this->assertEquals(
- $expected['numberofWatchingusers'], $cacheEntry->numberofWatchingusers,
- 'watching users'
- );
- $this->assertEquals( $expected['unpatrolled'], $cacheEntry->unpatrolled, 'unpatrolled' );
+ $this->assertEquals( false, $cacheEntry->watched, 'watched' );
+ $this->assertEquals( '21:21', $cacheEntry->timestamp, 'timestamp' );
+ $this->assertEquals( 0, $cacheEntry->numberofWatchingusers, 'watching users' );
+ $this->assertEquals( false, $cacheEntry->unpatrolled, 'unpatrolled' );
- $this->assertUserLinks( 'TestRecentChangesUser', $cacheEntry );
+ $this->assertUserLinks( $user->getName(), $cacheEntry );
$this->assertTitleLink( 'Xyz', $cacheEntry );
- $this->assertQueryLink( 'cur', $expected['cur'], $cacheEntry->curlink, 'cur link' );
- $this->assertQueryLink( 'prev', $expected['diff'], $cacheEntry->lastlink, 'prev link' );
- $this->assertQueryLink( 'diff', $expected['diff'], $cacheEntry->difflink, 'diff link' );
+ $diff = [ 'curid' => 5, 'diff' => 191, 'oldid' => 190 ];
+ $cur = [ 'curid' => 5, 'diff' => 0, 'oldid' => 191 ];
+ $this->assertQueryLink( 'cur', $cur, $cacheEntry->curlink, 'cur link' );
+ $this->assertQueryLink( 'prev', $diff, $cacheEntry->lastlink, 'prev link' );
+ $this->assertQueryLink( 'diff', $diff, $cacheEntry->difflink, 'diff link' );
}
- public function editChangeProvider() {
- return [
- [
- [
- 'title' => 'Xyz',
- 'user' => 'TestRecentChangesUser',
- 'diff' => [ 'curid' => 5, 'diff' => 191, 'oldid' => 190 ],
- 'cur' => [ 'curid' => 5, 'diff' => 0, 'oldid' => 191 ],
- 'timestamp' => '21:21',
- 'numberofWatchingusers' => 0,
- 'unpatrolled' => false
- ],
- $this->getContext(),
- $this->getMessages(),
- $this->testRecentChangesHelper->makeEditRecentChange(
- $this->getTestUser(),
- 'Xyz',
- 5, // curid
- 191, // thisid
- 190, // lastid
- '20131103212153',
- 0, // counter
- 0 // number of watching users
- ),
- false
- ]
+ public function testNewForDeleteChange() {
+ $expected = [
+ 'title' => 'Abc',
+ 'user' => 'TestRecentChangesUser',
+ 'timestamp' => '21:21',
+ 'numberofWatchingusers' => 0,
+ 'unpatrolled' => false
];
- }
-
- /**
- * @dataProvider deleteChangeProvider
- */
- public function testNewForDeleteChange( $expected, $context, $messages, $recentChange, $watched ) {
- $cacheEntryFactory = new RCCacheEntryFactory( $context, $messages );
- $cacheEntry = $cacheEntryFactory->newFromRecentChange( $recentChange, $watched );
+ $user = $this->getMutableTestUser()->getUser();
+ $recentChange = $this->testRecentChangesHelper->makeLogRecentChange(
+ 'delete',
+ 'delete',
+ $user,
+ 'Abc',
+ '20131103212153',
+ 0, // counter
+ 0 // number of watching users
+ );
+ $cacheEntryFactory = new RCCacheEntryFactory(
+ $this->getContext(),
+ $this->getMessages(),
+ $this->linkRenderer
+ );
+ $cacheEntry = $cacheEntryFactory->newFromRecentChange( $recentChange, false );
$this->assertInstanceOf( 'RCCacheEntry', $cacheEntry );
- $this->assertEquals( $watched, $cacheEntry->watched, 'watched' );
- $this->assertEquals( $expected['timestamp'], $cacheEntry->timestamp, 'timestamp' );
- $this->assertEquals(
- $expected['numberofWatchingusers'],
- $cacheEntry->numberofWatchingusers, 'watching users'
- );
- $this->assertEquals( $expected['unpatrolled'], $cacheEntry->unpatrolled, 'unpatrolled' );
+ $this->assertEquals( false, $cacheEntry->watched, 'watched' );
+ $this->assertEquals( '21:21', $cacheEntry->timestamp, 'timestamp' );
+ $this->assertEquals( 0, $cacheEntry->numberofWatchingusers, 'watching users' );
+ $this->assertEquals( false, $cacheEntry->unpatrolled, 'unpatrolled' );
$this->assertDeleteLogLink( $cacheEntry );
- $this->assertUserLinks( 'TestRecentChangesUser', $cacheEntry );
+ $this->assertUserLinks( $user->getName(), $cacheEntry );
$this->assertEquals( 'cur', $cacheEntry->curlink, 'cur link for delete log or rev' );
$this->assertEquals( 'diff', $cacheEntry->difflink, 'diff link for delete log or rev' );
$this->assertEquals( 'prev', $cacheEntry->lastlink, 'pref link for delete log or rev' );
}
- public function deleteChangeProvider() {
- return [
- [
- [
- 'title' => 'Abc',
- 'user' => 'TestRecentChangesUser',
- 'timestamp' => '21:21',
- 'numberofWatchingusers' => 0,
- 'unpatrolled' => false
- ],
- $this->getContext(),
- $this->getMessages(),
- $this->testRecentChangesHelper->makeLogRecentChange(
- 'delete',
- 'delete',
- $this->getTestUser(),
- 'Abc',
- '20131103212153',
- 0, // counter
- 0 // number of watching users
- ),
- false
- ]
- ];
- }
-
- /**
- * @dataProvider revUserDeleteProvider
- */
- public function testNewForRevUserDeleteChange( $expected, $context, $messages,
- $recentChange, $watched
- ) {
- $cacheEntryFactory = new RCCacheEntryFactory( $context, $messages );
- $cacheEntry = $cacheEntryFactory->newFromRecentChange( $recentChange, $watched );
+ public function testNewForRevUserDeleteChange() {
+ $user = $this->getMutableTestUser()->getUser();
+ $recentChange = $this->testRecentChangesHelper->makeDeletedEditRecentChange(
+ $user,
+ 'Zzz',
+ '20131103212153',
+ 191, // thisid
+ 190, // lastid
+ '20131103212153',
+ 0, // counter
+ 0 // number of watching users
+ );
+ $cacheEntryFactory = new RCCacheEntryFactory(
+ $this->getContext(),
+ $this->getMessages(),
+ $this->linkRenderer
+ );
+ $cacheEntry = $cacheEntryFactory->newFromRecentChange( $recentChange, false );
$this->assertInstanceOf( 'RCCacheEntry', $cacheEntry );
- $this->assertEquals( $watched, $cacheEntry->watched, 'watched' );
- $this->assertEquals( $expected['timestamp'], $cacheEntry->timestamp, 'timestamp' );
- $this->assertEquals(
- $expected['numberofWatchingusers'],
- $cacheEntry->numberofWatchingusers, 'watching users'
- );
- $this->assertEquals( $expected['unpatrolled'], $cacheEntry->unpatrolled, 'unpatrolled' );
+ $this->assertEquals( false, $cacheEntry->watched, 'watched' );
+ $this->assertEquals( '21:21', $cacheEntry->timestamp, 'timestamp' );
+ $this->assertEquals( 0, $cacheEntry->numberofWatchingusers, 'watching users' );
+ $this->assertEquals( false, $cacheEntry->unpatrolled, 'unpatrolled' );
$this->assertRevDel( $cacheEntry );
$this->assertTitleLink( 'Zzz', $cacheEntry );
$this->assertEquals( 'prev', $cacheEntry->lastlink, 'pref link for delete log or rev' );
}
- public function revUserDeleteProvider() {
- return [
- [
- [
- 'title' => 'Zzz',
- 'user' => 'TestRecentChangesUser',
- 'diff' => '',
- 'cur' => '',
- 'timestamp' => '21:21',
- 'numberofWatchingusers' => 0,
- 'unpatrolled' => false
- ],
- $this->getContext(),
- $this->getMessages(),
- $this->testRecentChangesHelper->makeDeletedEditRecentChange(
- $this->getTestUser(),
- 'Zzz',
- '20131103212153',
- 191, // thisid
- 190, // lastid
- '20131103212153',
- 0, // counter
- 0 // number of watching users
- ),
- false
- ]
- ];
- }
-
private function assertUserLinks( $user, $cacheEntry ) {
$this->assertTag(
[
];
}
- private function getTestUser() {
- $user = User::newFromName( 'TestRecentChangesUser' );
-
- if ( !$user->getId() ) {
- $user->addToDatabase();
- }
-
- return $user;
- }
-
private function getContext() {
- $user = $this->getTestUser();
+ $user = $this->getMutableTestUser()->getUser();
$context = $this->testRecentChangesHelper->getTestContext( $user );
$title = Title::newFromText( 'RecentChanges', NS_SPECIAL );
$pageProps->expects( $this->once() )
->method( 'getProperties' )
->with( $categoryTitle, 'hiddencat' )
- ->will( $this->returnValue( $isHidden ? [ $categoryTitle->getArticleID() => '' ] : [ ] ) );
+ ->will( $this->returnValue( $isHidden ? [ $categoryTitle->getArticleID() => '' ] : [] ) );
$scopedOverride = PageProps::overrideInstance( $pageProps );
<?php
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\MediaWikiServices;
/**
* Helper for generating test recent changes entries.
public function getCacheEntry( $recentChange ) {
$rcCacheFactory = new RCCacheEntryFactory(
new RequestContext(),
- [ 'diff' => 'diff', 'cur' => 'cur', 'last' => 'last' ]
+ [ 'diff' => 'diff', 'cur' => 'cur', 'last' => 'last' ],
+ new LinkRenderer(
+ MediaWikiServices::getInstance()->getTitleFormatter()
+ )
);
return $rcCacheFactory->newFromRecentChange( $recentChange, false );
}
$this->assertNotSame( $config1, $config2 );
}
+ /**
+ * @covers ConfigFactory::register
+ */
+ public function testSalvage() {
+ $oldFactory = new ConfigFactory();
+ $oldFactory->register( 'foo', 'GlobalVarConfig::newInstance' );
+ $oldFactory->register( 'bar', 'GlobalVarConfig::newInstance' );
+ $oldFactory->register( 'quux', 'GlobalVarConfig::newInstance' );
+
+ // instantiate two of the three defined configurations
+ $foo = $oldFactory->makeConfig( 'foo' );
+ $bar = $oldFactory->makeConfig( 'bar' );
+ $quux = $oldFactory->makeConfig( 'quux' );
+
+ // define new config instance
+ $newFactory = new ConfigFactory();
+ $newFactory->register( 'foo', 'GlobalVarConfig::newInstance' );
+ $newFactory->register( 'bar', function() {
+ return new HashConfig();
+ } );
+
+ // "foo" and "quux" are defined in the old and the new factory.
+ // The old factory has instances for "foo" and "bar", but not "quux".
+ $newFactory->salvage( $oldFactory );
+
+ $newFoo = $newFactory->makeConfig( 'foo' );
+ $this->assertSame( $foo, $newFoo, 'existing instance should be salvaged' );
+
+ $newBar = $newFactory->makeConfig( 'bar' );
+ $this->assertNotSame( $bar, $newBar, 'don\'t salvage if callbacks differ' );
+
+ // the new factory doesn't have quux defined, so the quux instance should not be salvaged
+ $this->setExpectedException( 'ConfigException' );
+ $newFactory->makeConfig( 'quux' );
+ }
+
/**
* @covers ConfigFactory::register
*/
<?php
+use MediaWiki\MediaWikiServices;
/**
* @group ContentHandler
MWNamespace::getCanonicalNamespaces( true );
$wgContLang->resetNamespaces();
// And LinkCache
- LinkCache::destroySingleton();
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'LinkCache' );
}
protected function tearDown() {
MWNamespace::getCanonicalNamespaces( true );
$wgContLang->resetNamespaces();
// And LinkCache
- LinkCache::destroySingleton();
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'LinkCache' );
parent::tearDown();
}
*/
class JsonContentTest extends MediaWikiLangTestCase {
- protected function setUp() {
- parent::setUp();
-
- $this->setMwGlobals( 'wgWellFormedXml', true );
- }
-
public static function provideValidConstruction() {
return [
[ 'foo', false, null ],
protected function setUp() {
parent::setUp();
- // Make sure MWDebug class is enabled
- static $MWDebugEnabled = false;
- if ( !$MWDebugEnabled ) {
- MWDebug::init();
- $MWDebugEnabled = true;
- }
/** Clear log before each test */
MWDebug::clearLog();
+ }
+
+ public static function setUpBeforeClass() {
+ parent::setUpBeforeClass();
+ MWDebug::init();
MediaWiki\suppressWarnings();
}
- protected function tearDown() {
+ public static function tearDownAfterClass() {
+ parent::tearDownAfterClass();
+ MWDebug::deinit();
MediaWiki\restoreWarnings();
- parent::tearDown();
}
/**
--- /dev/null
+<?php
+/**
+ * @covers MediaWiki\Interwiki\ClassicInterwikiLookup
+ *
+ * @group MediaWiki
+ * @group Database
+ */
+class ClassicInterwikiLookupTest extends MediaWikiTestCase {
+
+ private function populateDB( $iwrows ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->delete( 'interwiki', '*', __METHOD__ );
+ $dbw->insert( 'interwiki', array_values( $iwrows ), __METHOD__ );
+ $this->tablesUsed[] = 'interwiki';
+ }
+
+ public function testDatabaseStorage() {
+ // NOTE: database setup is expensive, so we only do
+ // it once and run all the tests in one go.
+ $dewiki = [
+ 'iw_prefix' => 'de',
+ 'iw_url' => 'http://de.wikipedia.org/wiki/',
+ 'iw_api' => 'http://de.wikipedia.org/w/api.php',
+ 'iw_wikiid' => 'dewiki',
+ 'iw_local' => 1,
+ 'iw_trans' => 0
+ ];
+
+ $zzwiki = [
+ 'iw_prefix' => 'zz',
+ 'iw_url' => 'http://zzwiki.org/wiki/',
+ 'iw_api' => 'http://zzwiki.org/w/api.php',
+ 'iw_wikiid' => 'zzwiki',
+ 'iw_local' => 0,
+ 'iw_trans' => 0
+ ];
+
+ $this->populateDB( [ $dewiki, $zzwiki ] );
+ $lookup = new \MediaWiki\Interwiki\ClassicInterwikiLookup(
+ Language::factory( 'en' ),
+ WANObjectCache::newEmpty(),
+ 60*60,
+ false,
+ 3,
+ 'en'
+ );
+
+ $this->assertEquals(
+ [ $dewiki, $zzwiki ],
+ $lookup->getAllPrefixes(),
+ 'getAllPrefixes()'
+ );
+ $this->assertEquals(
+ [ $dewiki ],
+ $lookup->getAllPrefixes( true ),
+ 'getAllPrefixes()'
+ );
+ $this->assertEquals(
+ [ $zzwiki ],
+ $lookup->getAllPrefixes( false ),
+ 'getAllPrefixes()'
+ );
+
+ $this->assertTrue( $lookup->isValidInterwiki( 'de' ), 'known prefix is valid' );
+ $this->assertFalse( $lookup->isValidInterwiki( 'xyz' ), 'unknown prefix is valid' );
+
+ $this->assertNull( $lookup->fetch( null ), 'no prefix' );
+ $this->assertFalse( $lookup->fetch( 'xyz' ), 'unknown prefix' );
+
+ $interwiki = $lookup->fetch( 'de' );
+ $this->assertInstanceOf( 'Interwiki', $interwiki );
+ $this->assertSame( $interwiki, $lookup->fetch( 'de' ), 'in-process caching' );
+
+ $this->assertSame( 'http://de.wikipedia.org/wiki/', $interwiki->getURL(), 'getURL' );
+ $this->assertSame( 'http://de.wikipedia.org/w/api.php', $interwiki->getAPI(), 'getAPI' );
+ $this->assertSame( 'dewiki', $interwiki->getWikiID(), 'getWikiID' );
+ $this->assertSame( true, $interwiki->isLocal(), 'isLocal' );
+ $this->assertSame( false, $interwiki->isTranscludable(), 'isTranscludable' );
+
+ $lookup->invalidateCache( 'de' );
+ $this->assertNotSame( $interwiki, $lookup->fetch( 'de' ), 'invalidate cache' );
+ }
+
+ /**
+ * @param string $thisSite
+ * @param string[] $local
+ * @param string[] $global
+ *
+ * @return string[]
+ */
+ private function populateHash( $thisSite, $local, $global ) {
+ $hash = [];
+ $hash[ '__sites:' . wfWikiID() ] = $thisSite;
+
+ $globals = [];
+ $locals = [];
+
+ foreach ( $local as $row ) {
+ $prefix = $row['iw_prefix'];
+ $data = $row['iw_local'] . ' ' . $row['iw_url'];
+ $locals[] = $prefix;
+ $hash[ "_{$thisSite}:{$prefix}" ] = $data;
+ }
+
+ foreach ( $global as $row ) {
+ $prefix = $row['iw_prefix'];
+ $data = $row['iw_local'] . ' ' . $row['iw_url'];
+ $globals[] = $prefix;
+ $hash[ "__global:{$prefix}" ] = $data;
+ }
+
+ $hash[ '__list:__global' ] = implode( ' ', $globals );
+ $hash[ '__list:_' . $thisSite ] = implode( ' ', $locals );
+
+ return $hash;
+ }
+
+ private function populateCDB( $thisSite, $local, $global ) {
+ $cdbFile = tempnam( wfTempDir(), 'MW-ClassicInterwikiLookupTest-' ) . '.cdb';
+ $cdb = \Cdb\Writer::open( $cdbFile );
+
+ $hash = $this->populateHash( $thisSite, $local, $global );
+
+ foreach ( $hash as $key => $value ) {
+ $cdb->set( $key, $value );
+ }
+
+ $cdb->close();
+ return $cdbFile;
+ }
+
+ public function testCDBStorage() {
+ // NOTE: CDB setup is expensive, so we only do
+ // it once and run all the tests in one go.
+
+ $dewiki = [
+ 'iw_prefix' => 'de',
+ 'iw_url' => 'http://de.wikipedia.org/wiki/',
+ 'iw_local' => 1
+ ];
+
+ $zzwiki = [
+ 'iw_prefix' => 'zz',
+ 'iw_url' => 'http://zzwiki.org/wiki/',
+ 'iw_local' => 0
+ ];
+
+ $cdbFile = $this->populateCDB(
+ 'en',
+ [ $dewiki ],
+ [ $zzwiki ]
+ );
+ $lookup = new \MediaWiki\Interwiki\ClassicInterwikiLookup(
+ Language::factory( 'en' ),
+ WANObjectCache::newEmpty(),
+ 60*60,
+ $cdbFile,
+ 3,
+ 'en'
+ );
+
+ $this->assertEquals(
+ [ $dewiki, $zzwiki ],
+ $lookup->getAllPrefixes(),
+ 'getAllPrefixes()'
+ );
+
+ $this->assertTrue( $lookup->isValidInterwiki( 'de' ), 'known prefix is valid' );
+ $this->assertTrue( $lookup->isValidInterwiki( 'zz' ), 'known prefix is valid' );
+
+ $interwiki = $lookup->fetch( 'de' );
+ $this->assertInstanceOf( 'Interwiki', $interwiki );
+
+ $this->assertSame( 'http://de.wikipedia.org/wiki/', $interwiki->getURL(), 'getURL' );
+ $this->assertSame( true, $interwiki->isLocal(), 'isLocal' );
+
+ $interwiki = $lookup->fetch( 'zz' );
+ $this->assertInstanceOf( 'Interwiki', $interwiki );
+
+ $this->assertSame( 'http://zzwiki.org/wiki/', $interwiki->getURL(), 'getURL' );
+ $this->assertSame( false, $interwiki->isLocal(), 'isLocal' );
+
+ // cleanup temp file
+ unlink( $cdbFile );
+ }
+
+ public function testArrayStorage() {
+ $dewiki = [
+ 'iw_prefix' => 'de',
+ 'iw_url' => 'http://de.wikipedia.org/wiki/',
+ 'iw_local' => 1
+ ];
+
+ $zzwiki = [
+ 'iw_prefix' => 'zz',
+ 'iw_url' => 'http://zzwiki.org/wiki/',
+ 'iw_local' => 0
+ ];
+
+ $hash = $this->populateHash(
+ 'en',
+ [ $dewiki ],
+ [ $zzwiki ]
+ );
+ $lookup = new \MediaWiki\Interwiki\ClassicInterwikiLookup(
+ Language::factory( 'en' ),
+ WANObjectCache::newEmpty(),
+ 60*60,
+ $hash,
+ 3,
+ 'en'
+ );
+
+ $this->assertEquals(
+ [ $dewiki, $zzwiki ],
+ $lookup->getAllPrefixes(),
+ 'getAllPrefixes()'
+ );
+
+ $this->assertTrue( $lookup->isValidInterwiki( 'de' ), 'known prefix is valid' );
+ $this->assertTrue( $lookup->isValidInterwiki( 'zz' ), 'known prefix is valid' );
+
+ $interwiki = $lookup->fetch( 'de' );
+ $this->assertInstanceOf( 'Interwiki', $interwiki );
+
+ $this->assertSame( 'http://de.wikipedia.org/wiki/', $interwiki->getURL(), 'getURL' );
+ $this->assertSame( true, $interwiki->isLocal(), 'isLocal' );
+
+ $interwiki = $lookup->fetch( 'zz' );
+ $this->assertInstanceOf( 'Interwiki', $interwiki );
+
+ $this->assertSame( 'http://zzwiki.org/wiki/', $interwiki->getURL(), 'getURL' );
+ $this->assertSame( false, $interwiki->isLocal(), 'isLocal' );
+ }
+
+}
<?php
+use MediaWiki\MediaWikiServices;
+
/**
* @covers Interwiki
*
$this->tablesUsed[] = 'interwiki';
}
+ private function setWgInterwikiCache( $interwikiCache ) {
+ $this->overrideMwServices();
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'InterwikiLookup' );
+ $this->setMwGlobals( 'wgInterwikiCache', $interwikiCache );
+ }
+
public function testDatabaseStorage() {
+ $this->markTestSkipped( 'Needs I37b8e8018b3 <https://gerrit.wikimedia.org/r/#/c/270555/>' );
+
// NOTE: database setup is expensive, so we only do
// it once and run all the tests in one go.
$dewiki = [
$this->populateDB( [ $dewiki, $zzwiki ] );
- Interwiki::resetLocalCache();
- $this->setMwGlobals( 'wgInterwikiCache', false );
+ $this->setWgInterwikiCache( false );
$this->assertEquals(
[ $dewiki, $zzwiki ],
[ $zzwiki ]
);
- Interwiki::resetLocalCache();
- $this->setMwGlobals( 'wgInterwikiCache', $cdbFile );
+ $this->setWgInterwikiCache( $cdbFile );
$this->assertEquals(
[ $dewiki, $zzwiki ],
[ $zzwiki ]
);
- Interwiki::resetLocalCache();
- $this->setMwGlobals( 'wgInterwikiCache', $cdbData );
+ $this->setWgInterwikiCache( $cdbData );
$this->assertEquals(
[ $dewiki, $zzwiki ],
--- /dev/null
+<?php
+
+/**
+ * @covers HtmlArmor
+ */
+class HtmlArmorTest extends PHPUnit_Framework_TestCase {
+
+ public static function provideHtmlArmor() {
+ return [
+ [
+ 'foobar',
+ 'foobar',
+ ],
+ [
+ '<script>alert("evil!");</script>',
+ '<script>alert("evil!");</script>',
+ ],
+ [
+ new HtmlArmor( '<script>alert("evil!");</script>' ),
+ '<script>alert("evil!");</script>',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideHtmlArmor
+ */
+ public function testHtmlArmor( $input, $expected ) {
+ $this->assertEquals(
+ $expected,
+ HtmlArmor::getHtml( $input )
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @uses XhprofData
+ * @uses AutoLoader
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
+ * @since 1.25
+ */
+class XhprofDataTest extends PHPUnit_Framework_TestCase {
+
+ /**
+ * @covers XhprofData::splitKey
+ * @dataProvider provideSplitKey
+ */
+ public function testSplitKey( $key, $expect ) {
+ $this->assertSame( $expect, XhprofData::splitKey( $key ) );
+ }
+
+ public function provideSplitKey() {
+ return [
+ [ 'main()', [ null, 'main()' ] ],
+ [ 'foo==>bar', [ 'foo', 'bar' ] ],
+ [ 'bar@1==>bar@2', [ 'bar@1', 'bar@2' ] ],
+ [ 'foo==>bar==>baz', [ 'foo', 'bar==>baz' ] ],
+ [ '==>bar', [ '', 'bar' ] ],
+ [ '', [ null, '' ] ],
+ ];
+ }
+
+ /**
+ * @covers XhprofData::pruneData
+ */
+ public function testInclude() {
+ $xhprofData = $this->getXhprofDataFixture( [
+ 'include' => [ 'main()' ],
+ ] );
+ $raw = $xhprofData->getRawData();
+ $this->assertArrayHasKey( 'main()', $raw );
+ $this->assertArrayHasKey( 'main()==>foo', $raw );
+ $this->assertArrayHasKey( 'main()==>xhprof_disable', $raw );
+ $this->assertSame( 3, count( $raw ) );
+ }
+
+ /**
+ * Validate the structure of data returned by
+ * Xhprof::getInclusiveMetrics(). This acts as a guard against unexpected
+ * structural changes to the returned data in lieu of using a more heavy
+ * weight typed response object.
+ *
+ * @covers XhprofData::getInclusiveMetrics
+ */
+ public function testInclusiveMetricsStructure() {
+ $metricStruct = [
+ 'ct' => 'int',
+ 'wt' => 'array',
+ 'cpu' => 'array',
+ 'mu' => 'array',
+ 'pmu' => 'array',
+ ];
+ $statStruct = [
+ 'total' => 'numeric',
+ 'min' => 'numeric',
+ 'mean' => 'numeric',
+ 'max' => 'numeric',
+ 'variance' => 'numeric',
+ 'percent' => 'numeric',
+ ];
+
+ $xhprofData = $this->getXhprofDataFixture();
+ $metrics = $xhprofData->getInclusiveMetrics();
+
+ foreach ( $metrics as $name => $metric ) {
+ $this->assertArrayStructure( $metricStruct, $metric );
+
+ foreach ( $metricStruct as $key => $type ) {
+ if ( $type === 'array' ) {
+ $this->assertArrayStructure( $statStruct, $metric[$key] );
+ if ( $name === 'main()' ) {
+ $this->assertEquals( 100, $metric[$key]['percent'] );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Validate the structure of data returned by
+ * Xhprof::getCompleteMetrics(). This acts as a guard against unexpected
+ * structural changes to the returned data in lieu of using a more heavy
+ * weight typed response object.
+ *
+ * @covers XhprofData::getCompleteMetrics
+ */
+ public function testCompleteMetricsStructure() {
+ $metricStruct = [
+ 'ct' => 'int',
+ 'wt' => 'array',
+ 'cpu' => 'array',
+ 'mu' => 'array',
+ 'pmu' => 'array',
+ 'calls' => 'array',
+ 'subcalls' => 'array',
+ ];
+ $statsMetrics = [ 'wt', 'cpu', 'mu', 'pmu' ];
+ $statStruct = [
+ 'total' => 'numeric',
+ 'min' => 'numeric',
+ 'mean' => 'numeric',
+ 'max' => 'numeric',
+ 'variance' => 'numeric',
+ 'percent' => 'numeric',
+ 'exclusive' => 'numeric',
+ ];
+
+ $xhprofData = $this->getXhprofDataFixture();
+ $metrics = $xhprofData->getCompleteMetrics();
+
+ foreach ( $metrics as $name => $metric ) {
+ $this->assertArrayStructure( $metricStruct, $metric, $name );
+
+ foreach ( $metricStruct as $key => $type ) {
+ if ( in_array( $key, $statsMetrics ) ) {
+ $this->assertArrayStructure(
+ $statStruct, $metric[$key], $key
+ );
+ $this->assertLessThanOrEqual(
+ $metric[$key]['total'], $metric[$key]['exclusive']
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * @covers XhprofData::getCallers
+ * @covers XhprofData::getCallees
+ * @uses XhprofData
+ */
+ public function testEdges() {
+ $xhprofData = $this->getXhprofDataFixture();
+ $this->assertSame( [], $xhprofData->getCallers( 'main()' ) );
+ $this->assertSame( [ 'foo', 'xhprof_disable' ],
+ $xhprofData->getCallees( 'main()' )
+ );
+ $this->assertSame( [ 'main()' ],
+ $xhprofData->getCallers( 'foo' )
+ );
+ $this->assertSame( [], $xhprofData->getCallees( 'strlen' ) );
+ }
+
+ /**
+ * @covers XhprofData::getCriticalPath
+ * @uses XhprofData
+ */
+ public function testCriticalPath() {
+ $xhprofData = $this->getXhprofDataFixture();
+ $path = $xhprofData->getCriticalPath();
+
+ $last = null;
+ foreach ( $path as $key => $value ) {
+ list( $func, $call ) = XhprofData::splitKey( $key );
+ $this->assertSame( $last, $func );
+ $last = $call;
+ }
+ $this->assertSame( $last, 'bar@1' );
+ }
+
+ /**
+ * Get an Xhprof instance that has been primed with a set of known testing
+ * data. Tests for the Xhprof class should laregly be concerned with
+ * evaluating the manipulations of the data collected by xhprof rather
+ * than the data collection process itself.
+ *
+ * The returned Xhprof instance primed will be with a data set created by
+ * running this trivial program using the PECL xhprof implementation:
+ * @code
+ * function bar( $x ) {
+ * if ( $x > 0 ) {
+ * bar($x - 1);
+ * }
+ * }
+ * function foo() {
+ * for ( $idx = 0; $idx < 2; $idx++ ) {
+ * bar( $idx );
+ * $x = strlen( 'abc' );
+ * }
+ * }
+ * xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY );
+ * foo();
+ * $x = xhprof_disable();
+ * var_export( $x );
+ * @endcode
+ *
+ * @return Xhprof
+ */
+ protected function getXhprofDataFixture( array $opts = [] ) {
+ return new XhprofData( [
+ 'foo==>bar' => [
+ 'ct' => 2,
+ 'wt' => 57,
+ 'cpu' => 92,
+ 'mu' => 1896,
+ 'pmu' => 0,
+ ],
+ 'foo==>strlen' => [
+ 'ct' => 2,
+ 'wt' => 21,
+ 'cpu' => 141,
+ 'mu' => 752,
+ 'pmu' => 0,
+ ],
+ 'bar==>bar@1' => [
+ 'ct' => 1,
+ 'wt' => 18,
+ 'cpu' => 19,
+ 'mu' => 752,
+ 'pmu' => 0,
+ ],
+ 'main()==>foo' => [
+ 'ct' => 1,
+ 'wt' => 304,
+ 'cpu' => 307,
+ 'mu' => 4008,
+ 'pmu' => 0,
+ ],
+ 'main()==>xhprof_disable' => [
+ 'ct' => 1,
+ 'wt' => 8,
+ 'cpu' => 10,
+ 'mu' => 768,
+ 'pmu' => 392,
+ ],
+ 'main()' => [
+ 'ct' => 1,
+ 'wt' => 353,
+ 'cpu' => 351,
+ 'mu' => 6112,
+ 'pmu' => 1424,
+ ],
+ ], $opts );
+ }
+
+ /**
+ * Assert that the given array has the described structure.
+ *
+ * @param array $struct Array of key => type mappings
+ * @param array $actual Array to check
+ * @param string $label
+ */
+ protected function assertArrayStructure( $struct, $actual, $label = null ) {
+ $this->assertInternalType( 'array', $actual, $label );
+ $this->assertCount( count( $struct ), $actual, $label );
+ foreach ( $struct as $key => $type ) {
+ $this->assertArrayHasKey( $key, $actual );
+ $this->assertInternalType( $type, $actual[$key] );
+ }
+ }
+}
* @file
*/
-/**
- * @uses Xhprof
- * @uses AutoLoader
- * @author Bryan Davis <bd808@wikimedia.org>
- * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
- * @since 1.25
- */
class XhprofTest extends PHPUnit_Framework_TestCase {
-
- public function setUp() {
- if ( !function_exists( 'xhprof_enable' ) ) {
- $this->markTestSkipped( 'No xhprof support detected.' );
- }
- }
-
- /**
- * @covers Xhprof::splitKey
- * @dataProvider provideSplitKey
- */
- public function testSplitKey( $key, $expect ) {
- $this->assertSame( $expect, Xhprof::splitKey( $key ) );
- }
-
- public function provideSplitKey() {
- return [
- [ 'main()', [ null, 'main()' ] ],
- [ 'foo==>bar', [ 'foo', 'bar' ] ],
- [ 'bar@1==>bar@2', [ 'bar@1', 'bar@2' ] ],
- [ 'foo==>bar==>baz', [ 'foo', 'bar==>baz' ] ],
- [ '==>bar', [ '', 'bar' ] ],
- [ '', [ null, '' ] ],
- ];
- }
-
- /**
- * @covers Xhprof::__construct
- * @covers Xhprof::stop
- * @covers Xhprof::getRawData
- * @dataProvider provideRawData
- */
- public function testRawData( $flags, $keys ) {
- $xhprof = new Xhprof( [ 'flags' => $flags ] );
- $raw = $xhprof->getRawData();
- $this->assertArrayHasKey( 'main()', $raw );
- foreach ( $keys as $key ) {
- $this->assertArrayHasKey( $key, $raw['main()'] );
- }
- }
-
- public function provideRawData() {
- $tests = [
- [ 0, [ 'ct', 'wt' ] ],
- ];
-
- if ( defined( 'XHPROF_FLAGS_CPU' ) && defined( 'XHPROF_FLAGS_CPU' ) ) {
- $tests[] = [ XHPROF_FLAGS_MEMORY, [
- 'ct', 'wt', 'mu', 'pmu',
- ] ];
- $tests[] = [ XHPROF_FLAGS_CPU, [
- 'ct', 'wt', 'cpu',
- ] ];
- $tests[] = [ XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU, [
- 'ct', 'wt', 'mu', 'pmu', 'cpu',
- ] ];
- }
-
- return $tests;
- }
-
- /**
- * @covers Xhprof::pruneData
- */
- public function testInclude() {
- $xhprof = $this->getXhprofFixture( [
- 'include' => [ 'main()' ],
- ] );
- $raw = $xhprof->getRawData();
- $this->assertArrayHasKey( 'main()', $raw );
- $this->assertArrayHasKey( 'main()==>foo', $raw );
- $this->assertArrayHasKey( 'main()==>xhprof_disable', $raw );
- $this->assertSame( 3, count( $raw ) );
- }
-
/**
- * Validate the structure of data returned by
- * Xhprof::getInclusiveMetrics(). This acts as a guard against unexpected
- * structural changes to the returned data in lieu of using a more heavy
- * weight typed response object.
+ * Trying to enable Xhprof when it is already enabled causes an exception
+ * to be thrown.
*
- * @covers Xhprof::getInclusiveMetrics
- */
- public function testInclusiveMetricsStructure() {
- $metricStruct = [
- 'ct' => 'int',
- 'wt' => 'array',
- 'cpu' => 'array',
- 'mu' => 'array',
- 'pmu' => 'array',
- ];
- $statStruct = [
- 'total' => 'numeric',
- 'min' => 'numeric',
- 'mean' => 'numeric',
- 'max' => 'numeric',
- 'variance' => 'numeric',
- 'percent' => 'numeric',
- ];
-
- $xhprof = $this->getXhprofFixture();
- $metrics = $xhprof->getInclusiveMetrics();
-
- foreach ( $metrics as $name => $metric ) {
- $this->assertArrayStructure( $metricStruct, $metric );
-
- foreach ( $metricStruct as $key => $type ) {
- if ( $type === 'array' ) {
- $this->assertArrayStructure( $statStruct, $metric[$key] );
- if ( $name === 'main()' ) {
- $this->assertEquals( 100, $metric[$key]['percent'] );
- }
- }
- }
- }
- }
-
- /**
- * Validate the structure of data returned by
- * Xhprof::getCompleteMetrics(). This acts as a guard against unexpected
- * structural changes to the returned data in lieu of using a more heavy
- * weight typed response object.
- *
- * @covers Xhprof::getCompleteMetrics
- */
- public function testCompleteMetricsStructure() {
- $metricStruct = [
- 'ct' => 'int',
- 'wt' => 'array',
- 'cpu' => 'array',
- 'mu' => 'array',
- 'pmu' => 'array',
- 'calls' => 'array',
- 'subcalls' => 'array',
- ];
- $statsMetrics = [ 'wt', 'cpu', 'mu', 'pmu' ];
- $statStruct = [
- 'total' => 'numeric',
- 'min' => 'numeric',
- 'mean' => 'numeric',
- 'max' => 'numeric',
- 'variance' => 'numeric',
- 'percent' => 'numeric',
- 'exclusive' => 'numeric',
- ];
-
- $xhprof = $this->getXhprofFixture();
- $metrics = $xhprof->getCompleteMetrics();
-
- foreach ( $metrics as $name => $metric ) {
- $this->assertArrayStructure( $metricStruct, $metric, $name );
-
- foreach ( $metricStruct as $key => $type ) {
- if ( in_array( $key, $statsMetrics ) ) {
- $this->assertArrayStructure(
- $statStruct, $metric[$key], $key
- );
- $this->assertLessThanOrEqual(
- $metric[$key]['total'], $metric[$key]['exclusive']
- );
- }
- }
- }
- }
-
- /**
- * @covers Xhprof::getCallers
- * @covers Xhprof::getCallees
- * @uses Xhprof
- */
- public function testEdges() {
- $xhprof = $this->getXhprofFixture();
- $this->assertSame( [], $xhprof->getCallers( 'main()' ) );
- $this->assertSame( [ 'foo', 'xhprof_disable' ],
- $xhprof->getCallees( 'main()' )
- );
- $this->assertSame( [ 'main()' ],
- $xhprof->getCallers( 'foo' )
- );
- $this->assertSame( [], $xhprof->getCallees( 'strlen' ) );
- }
-
- /**
- * @covers Xhprof::getCriticalPath
- * @uses Xhprof
- */
- public function testCriticalPath() {
- $xhprof = $this->getXhprofFixture();
- $path = $xhprof->getCriticalPath();
-
- $last = null;
- foreach ( $path as $key => $value ) {
- list( $func, $call ) = Xhprof::splitKey( $key );
- $this->assertSame( $last, $func );
- $last = $call;
- }
- $this->assertSame( $last, 'bar@1' );
- }
-
- /**
- * Get an Xhprof instance that has been primed with a set of known testing
- * data. Tests for the Xhprof class should laregly be concerned with
- * evaluating the manipulations of the data collected by xhprof rather
- * than the data collection process itself.
- *
- * The returned Xhprof instance primed will be with a data set created by
- * running this trivial program using the PECL xhprof implementation:
- * @code
- * function bar( $x ) {
- * if ( $x > 0 ) {
- * bar($x - 1);
- * }
- * }
- * function foo() {
- * for ( $idx = 0; $idx < 2; $idx++ ) {
- * bar( $idx );
- * $x = strlen( 'abc' );
- * }
- * }
- * xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY );
- * foo();
- * $x = xhprof_disable();
- * var_export( $x );
- * @endcode
- *
- * @return Xhprof
- */
- protected function getXhprofFixture( array $opts = [] ) {
- $xhprof = new Xhprof( $opts );
- $xhprof->loadRawData( [
- 'foo==>bar' => [
- 'ct' => 2,
- 'wt' => 57,
- 'cpu' => 92,
- 'mu' => 1896,
- 'pmu' => 0,
- ],
- 'foo==>strlen' => [
- 'ct' => 2,
- 'wt' => 21,
- 'cpu' => 141,
- 'mu' => 752,
- 'pmu' => 0,
- ],
- 'bar==>bar@1' => [
- 'ct' => 1,
- 'wt' => 18,
- 'cpu' => 19,
- 'mu' => 752,
- 'pmu' => 0,
- ],
- 'main()==>foo' => [
- 'ct' => 1,
- 'wt' => 304,
- 'cpu' => 307,
- 'mu' => 4008,
- 'pmu' => 0,
- ],
- 'main()==>xhprof_disable' => [
- 'ct' => 1,
- 'wt' => 8,
- 'cpu' => 10,
- 'mu' => 768,
- 'pmu' => 392,
- ],
- 'main()' => [
- 'ct' => 1,
- 'wt' => 353,
- 'cpu' => 351,
- 'mu' => 6112,
- 'pmu' => 1424,
- ],
- ] );
- return $xhprof;
- }
-
- /**
- * Assert that the given array has the described structure.
- *
- * @param array $struct Array of key => type mappings
- * @param array $actual Array to check
- * @param string $label
- */
- protected function assertArrayStructure( $struct, $actual, $label = null ) {
- $this->assertInternalType( 'array', $actual, $label );
- $this->assertCount( count( $struct ), $actual, $label );
- foreach ( $struct as $key => $type ) {
- $this->assertArrayHasKey( $key, $actual );
- $this->assertInternalType( $type, $actual[$key] );
- }
+ * @expectedException Exception
+ * @expectedExceptionMessage already enabled
+ * @covers Xhprof::enable
+ */
+ public function testEnable() {
+ $xhprof = new ReflectionClass( 'Xhprof' );
+ $enabled = $xhprof->getProperty( 'enabled' );
+ $enabled->setAccessible( true );
+ $enabled->setValue( true );
+ $xhprof->getMethod( 'enable' )->invoke( null );
}
}
* @param integer $ttl
*/
public function testSetAndGet( $value, $ttl ) {
+ $curTTL = null;
+ $asOf = null;
$key = wfRandomString();
+
+ $this->cache->get( $key, $curTTL, [], $asOf );
+ $this->assertNull( $curTTL, "Current TTL is null" );
+ $this->assertNull( $asOf, "Current as-of-time is infinite" );
+
+ $t = microtime( true );
$this->cache->set( $key, $value, $ttl );
- $curTTL = null;
- $this->assertEquals( $value, $this->cache->get( $key, $curTTL ) );
+ $this->assertEquals( $value, $this->cache->get( $key, $curTTL, [], $asOf ) );
if ( is_infinite( $ttl ) || $ttl == 0 ) {
$this->assertTrue( is_infinite( $curTTL ), "Current TTL is infinite" );
} else {
$this->assertGreaterThan( 0, $curTTL, "Current TTL > 0" );
$this->assertLessThanOrEqual( $ttl, $curTTL, "Current TTL < nominal TTL" );
}
+ $this->assertGreaterThanOrEqual( $t - 1, $asOf, "As-of-time in range of set() time" );
+ $this->assertLessThanOrEqual( $t + 1, $asOf, "As-of-time in range of set() time" );
}
public static function provideSetAndGet() {
}
/**
+ * @dataProvider getWithSetCallback_provider
* @covers WANObjectCache::getWithSetCallback()
* @covers WANObjectCache::doGetWithSetCallback()
+ * @param array $extOpts
+ * @param bool $versioned
*/
- public function testGetWithSetCallback() {
+ public function testGetWithSetCallback( array $extOpts, $versioned ) {
$cache = $this->cache;
$key = wfRandomString();
};
$wasSet = 0;
- $v = $cache->getWithSetCallback( $key, 30, $func, [ 'lockTSE' => 5 ] );
+ $v = $cache->getWithSetCallback( $key, 30, $func, [ 'lockTSE' => 5 ] + $extOpts );
$this->assertEquals( $value, $v, "Value returned" );
$this->assertEquals( 1, $wasSet, "Value regenerated" );
$v = $cache->getWithSetCallback( $key, 30, $func, [
'lowTTL' => 0,
'lockTSE' => 5,
- ] );
+ ] + $extOpts );
$this->assertEquals( $value, $v, "Value returned" );
$this->assertEquals( 0, $wasSet, "Value not regenerated" );
$priorTime = microtime( true );
usleep( 1 );
$wasSet = 0;
- $v = $cache->getWithSetCallback( $key, 30, $func,
- [ 'checkKeys' => [ $cKey1, $cKey2 ] ] );
+ $v = $cache->getWithSetCallback(
+ $key, 30, $func, [ 'checkKeys' => [ $cKey1, $cKey2 ] ] + $extOpts
+ );
$this->assertEquals( $value, $v, "Value returned" );
$this->assertEquals( 1, $wasSet, "Value regenerated due to check keys" );
$t1 = $cache->getCheckKeyTime( $cKey1 );
$priorTime = microtime( true );
$wasSet = 0;
- $v = $cache->getWithSetCallback( $key, 30, $func,
- [ 'checkKeys' => [ $cKey1, $cKey2 ] ] );
+ $v = $cache->getWithSetCallback(
+ $key, 30, $func, [ 'checkKeys' => [ $cKey1, $cKey2 ] ] + $extOpts
+ );
$this->assertEquals( $value, $v, "Value returned" );
$this->assertEquals( 1, $wasSet, "Value regenerated due to still-recent check keys" );
$t1 = $cache->getCheckKeyTime( $cKey1 );
$curTTL = null;
$v = $cache->get( $key, $curTTL, [ $cKey1, $cKey2 ] );
- $this->assertEquals( $value, $v, "Value returned" );
+ if ( $versioned ) {
+ $this->assertEquals( $value, $v[$cache::VFLD_DATA], "Value returned" );
+ } else {
+ $this->assertEquals( $value, $v, "Value returned" );
+ }
$this->assertLessThanOrEqual( 0, $curTTL, "Value has current TTL < 0 due to check keys" );
$wasSet = 0;
$key = wfRandomString();
- $v = $cache->getWithSetCallback( $key, 30, $func, [ 'pcTTL' => 5 ] );
+ $v = $cache->getWithSetCallback( $key, 30, $func, [ 'pcTTL' => 5 ] + $extOpts );
$this->assertEquals( $value, $v, "Value returned" );
$cache->delete( $key );
- $v = $cache->getWithSetCallback( $key, 30, $func, [ 'pcTTL' => 5 ] );
+ $v = $cache->getWithSetCallback( $key, 30, $func, [ 'pcTTL' => 5 ] + $extOpts );
$this->assertEquals( $value, $v, "Value still returned after deleted" );
$this->assertEquals( 1, $wasSet, "Value process cached while deleted" );
}
+ public static function getWithSetCallback_provider() {
+ return [
+ [ [], false ],
+ [ [ 'version' => 1 ], true ]
+ ];
+ }
+
/**
* @covers WANObjectCache::getWithSetCallback()
* @covers WANObjectCache::doGetWithSetCallback()
$this->assertGreaterThan( 0, $curTTL, "Existing key has current TTL > 0" );
}
+ /**
+ * @dataProvider getWithSetCallback_versions_provider
+ * @param array $extOpts
+ * @param $versioned
+ */
+ public function testGetWithSetCallback_versions( array $extOpts, $versioned ) {
+ $cache = $this->cache;
+
+ $key = wfRandomString();
+ $value = wfRandomString();
+
+ $wasSet = 0;
+ $func = function( $old, &$ttl ) use ( &$wasSet, $value ) {
+ ++$wasSet;
+ return $value;
+ };
+
+ // Set the main key (version N if versioned)
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, 30, $func, $extOpts );
+ $this->assertEquals( $value, $v, "Value returned" );
+ $this->assertEquals( 1, $wasSet, "Value regenerated" );
+ $cache->getWithSetCallback( $key, 30, $func, $extOpts );
+ $this->assertEquals( 1, $wasSet, "Value not regenerated" );
+ // Set the key for version N+1 (if versioned)
+ if ( $versioned ) {
+ $verOpts = [ 'version' => $extOpts['version'] + 1 ];
+
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, 30, $func, $verOpts + $extOpts );
+ $this->assertEquals( $value, $v, "Value returned" );
+ $this->assertEquals( 1, $wasSet, "Value regenerated" );
+
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, 30, $func, $verOpts + $extOpts );
+ $this->assertEquals( $value, $v, "Value returned" );
+ $this->assertEquals( 0, $wasSet, "Value not regenerated" );
+ }
+
+ $wasSet = 0;
+ $cache->getWithSetCallback( $key, 30, $func, $extOpts );
+ $this->assertEquals( 0, $wasSet, "Value not regenerated" );
+
+ $wasSet = 0;
+ $cache->delete( $key );
+ $v = $cache->getWithSetCallback( $key, 30, $func, $extOpts );
+ $this->assertEquals( $value, $v, "Value returned" );
+ $this->assertEquals( 1, $wasSet, "Value regenerated" );
+
+ if ( $versioned ) {
+ $wasSet = 0;
+ $verOpts = [ 'version' => $extOpts['version'] + 1 ];
+ $v = $cache->getWithSetCallback( $key, 30, $func, $verOpts + $extOpts );
+ $this->assertEquals( $value, $v, "Value returned" );
+ $this->assertEquals( 1, $wasSet, "Value regenerated" );
+ }
+ }
+
+ public static function getWithSetCallback_versions_provider() {
+ return [
+ [ [], false ],
+ [ [ 'version' => 1 ], true ]
+ ];
+ }
+
/**
* @covers WANObjectCache::touchCheckKey()
* @covers WANObjectCache::resetCheckKey()
--- /dev/null
+<?php
+
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Linker\LinkRendererFactory;
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @covers MediaWiki\Linker\LinkRendererFactory
+ */
+class LinkRendererFactoryTest extends MediaWikiLangTestCase {
+
+ /**
+ * @var TitleFormatter
+ */
+ private $titleFormatter;
+
+ public function setUp() {
+ parent::setUp();
+ $this->titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
+ }
+
+ public static function provideCreateFromLegacyOptions() {
+ return [
+ [
+ [ 'forcearticlepath' ],
+ 'getForceArticlePath',
+ true
+ ],
+ [
+ [ 'http' ],
+ 'getExpandURLs',
+ PROTO_HTTP
+ ],
+ [
+ [ 'https' ],
+ 'getExpandURLs',
+ PROTO_HTTPS
+ ],
+ [
+ [ 'stubThreshold' => 150 ],
+ 'getStubThreshold',
+ 150
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideCreateFromLegacyOptions
+ */
+ public function testCreateFromLegacyOptions( $options, $func, $val ) {
+ $factory = new LinkRendererFactory( $this->titleFormatter );
+ $linkRenderer = $factory->createFromLegacyOptions(
+ $options
+ );
+ $this->assertInstanceOf( LinkRenderer::class, $linkRenderer );
+ $this->assertEquals( $val, $linkRenderer->$func(), $func );
+ }
+
+ public function testCreate() {
+ $factory = new LinkRendererFactory( $this->titleFormatter );
+ $this->assertInstanceOf( LinkRenderer::class, $factory->create() );
+ }
+
+ public function testCreateForUser() {
+ $user = $this->getMock( User::class, [ 'getStubThreshold' ] );
+ $user->expects( $this->once() )
+ ->method( 'getStubThreshold' )
+ ->willReturn( 15 );
+ $factory = new LinkRendererFactory( $this->titleFormatter );
+ $linkRenderer = $factory->createForUser( $user );
+ $this->assertInstanceOf( LinkRenderer::class, $linkRenderer );
+ $this->assertEquals( 15, $linkRenderer->getStubThreshold() );
+ }
+}
--- /dev/null
+<?php
+
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @covers MediaWiki\Linker\LinkRenderer
+ */
+class LinkRendererTest extends MediaWikiLangTestCase {
+
+ /**
+ * @var TitleFormatter
+ */
+ private $titleFormatter;
+
+ public function setUp() {
+ parent::setUp();
+ $this->setMwGlobals( [
+ 'wgArticlePath' => '/wiki/$1',
+ 'wgServer' => '//example.org',
+ 'wgCanonicalServer' => 'http://example.org',
+ 'wgScriptPath' => '/w',
+ 'wgScript' => '/w/index.php',
+ ] );
+ $this->titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
+ }
+
+ public function testMergeAttribs() {
+ $target = new TitleValue( NS_SPECIAL, 'Blankpage' );
+ $linkRenderer = new LinkRenderer( $this->titleFormatter );
+ $link = $linkRenderer->makeBrokenLink( $target, null, [
+ // Appended to class
+ 'class' => 'foobar',
+ // Suppresses href attribute
+ 'href' => false,
+ // Extra attribute
+ 'bar' => 'baz'
+ ] );
+ $this->assertEquals(
+ '<a href="/wiki/Special:BlankPage" class="new foobar" '
+ . 'title="Special:BlankPage (page does not exist)" bar="baz">'
+ . 'Special:BlankPage</a>',
+ $link
+ );
+ }
+
+ public function testMakeKnownLink() {
+ $target = new TitleValue( NS_MAIN, 'Foobar' );
+ $linkRenderer = new LinkRenderer( $this->titleFormatter );
+
+ // Query added
+ $this->assertEquals(
+ '<a href="/w/index.php?title=Foobar&foo=bar" '. 'title="Foobar">Foobar</a>',
+ $linkRenderer->makeKnownLink( $target, null, [], [ 'foo' => 'bar' ] )
+ );
+
+ // forcearticlepath
+ $linkRenderer->setForceArticlePath( true );
+ $this->assertEquals(
+ '<a href="/wiki/Foobar?foo=bar" title="Foobar">Foobar</a>',
+ $linkRenderer->makeKnownLink( $target, null, [], [ 'foo' => 'bar' ] )
+ );
+
+ // expand = HTTPS
+ $linkRenderer->setForceArticlePath( false );
+ $linkRenderer->setExpandURLs( PROTO_HTTPS );
+ $this->assertEquals(
+ '<a href="https://example.org/wiki/Foobar" title="Foobar">Foobar</a>',
+ $linkRenderer->makeKnownLink( $target )
+ );
+ }
+
+ public function testMakeBrokenLink() {
+ $target = new TitleValue( NS_MAIN, 'Foobar' );
+ $special = new TitleValue( NS_SPECIAL, 'Foobar' );
+ $linkRenderer = new LinkRenderer( $this->titleFormatter );
+
+ // action=edit&redlink=1 added
+ $this->assertEquals(
+ '<a href="/w/index.php?title=Foobar&action=edit&redlink=1" '
+ . 'class="new" title="Foobar (page does not exist)">Foobar</a>',
+ $linkRenderer->makeBrokenLink( $target )
+ );
+
+ // action=edit&redlink=1 not added due to action query parameter
+ $this->assertEquals(
+ '<a href="/w/index.php?title=Foobar&action=foobar" class="new" '
+ . 'title="Foobar (page does not exist)">Foobar</a>',
+ $linkRenderer->makeBrokenLink( $target, null, [], [ 'action' => 'foobar' ] )
+ );
+
+ // action=edit&redlink=1 not added due to NS_SPECIAL
+ $this->assertEquals(
+ '<a href="/wiki/Special:Foobar" class="new" title="Special:Foobar '
+ . '(page does not exist)">Special:Foobar</a>',
+ $linkRenderer->makeBrokenLink( $special )
+ );
+
+ // fragment stripped
+ $this->assertEquals(
+ '<a href="/w/index.php?title=Foobar&action=edit&redlink=1" '
+ . 'class="new" title="Foobar (page does not exist)">Foobar</a>',
+ $linkRenderer->makeBrokenLink( $target->createFragmentTarget( 'foobar' ) )
+ );
+ }
+
+ public function testMakeLink() {
+ $linkRenderer = new LinkRenderer( $this->titleFormatter );
+ $foobar = new TitleValue( NS_SPECIAL, 'Foobar' );
+ $blankpage = new TitleValue( NS_SPECIAL, 'Blankpage' );
+ $this->assertEquals(
+ '<a href="/wiki/Special:Foobar" class="new" title="Special:Foobar '
+ . '(page does not exist)">foo</a>',
+ $linkRenderer->makeLink( $foobar, 'foo' )
+ );
+
+ $this->assertEquals(
+ '<a href="/wiki/Special:BlankPage" title="Special:BlankPage">blank</a>',
+ $linkRenderer->makeLink( $blankpage, 'blank' )
+ );
+
+ $this->assertEquals(
+ '<a href="/wiki/Special:Foobar" class="new" title="Special:Foobar '
+ . '(page does not exist)"><script>evil()</script></a>',
+ $linkRenderer->makeLink( $foobar, '<script>evil()</script>' )
+ );
+
+ $this->assertEquals(
+ '<a href="/wiki/Special:Foobar" class="new" title="Special:Foobar '
+ . '(page does not exist)"><script>evil()</script></a>',
+ $linkRenderer->makeLink( $foobar, new HtmlArmor( '<script>evil()</script>' ) )
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * @group BagOStuff
+ */
+class RedisBagOStuffTest extends MediaWikiTestCase {
+ /** @var RedisBagOStuff */
+ private $cache;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->cache = TestingAccessWrapper::newFromObject( new RedisBagOStuff( [ 'servers' => [] ] ) );
+ }
+
+ /**
+ * @covers RedisBagOStuff::unserialize
+ * @dataProvider unserializeProvider
+ */
+ public function testUnserialize( $expected, $input, $message ) {
+ $actual = $this->cache->unserialize( $input );
+ $this->assertSame( $expected, $actual, $message );
+ }
+
+ public function unserializeProvider() {
+ return [
+ [
+ -1,
+ '-1',
+ 'String representation of \'-1\'',
+ ],
+ [
+ 0,
+ '0',
+ 'String representation of \'0\'',
+ ],
+ [
+ 1,
+ '1',
+ 'String representation of \'1\'',
+ ],
+ [
+ -1.0,
+ 'd:-1;',
+ 'Serialized negative double',
+ ],
+ [
+ 'foo',
+ 's:3:"foo";',
+ 'Serialized string',
+ ]
+ ];
+ }
+
+ /**
+ * @covers RedisBagOStuff::serialize
+ * @dataProvider serializeProvider
+ */
+ public function testSerialize( $expected, $input, $message ) {
+ $actual = $this->cache->serialize( $input );
+ $this->assertSame( $expected, $actual, $message );
+ }
+
+ public function serializeProvider() {
+ return [
+ [
+ -1,
+ -1,
+ '-1 as integer',
+ ],
+ [
+ 0,
+ 0,
+ '0 as integer',
+ ],
+ [
+ 1,
+ 1,
+ '1 as integer',
+ ],
+ [
+ 'd:-1;',
+ -1.0,
+ 'Negative double',
+ ],
+ [
+ 's:3:"2.1";',
+ '2.1',
+ 'Decimal string',
+ ],
+ [
+ 's:1:"1";',
+ '1',
+ 'String representation of 1',
+ ],
+ [
+ 's:3:"foo";',
+ 'foo',
+ 'String',
+ ],
+ ];
+ }
+}
$pageProps->expects( $this->once() )
->method( 'getProperties' )
->with( $title, 'hiddencat' )
- ->will( $this->returnValue( [ ] ) );
+ ->will( $this->returnValue( [] ) );
$scopedOverride = PageProps::overrideInstance( $pageProps );
$pageProps->expects( $this->once() )
->method( 'getProperties' )
->with( $categoryTitle, 'hiddencat' )
- ->will( $this->returnValue( $isHidden ? [ $categoryTitle->getArticleID() => '' ] : [ ] ) );
+ ->will( $this->returnValue( $isHidden ? [ $categoryTitle->getArticleID() => '' ] : [] ) );
$scopedOverride = PageProps::overrideInstance( $pageProps );
<?php
-
/**
* Although marked as a stub, can work independently.
*
$tmpGlobals['wgParserCacheType'] = CACHE_NONE;
$tmpGlobals['wgCapitalLinks'] = true;
$tmpGlobals['wgNoFollowLinks'] = true;
- $tmpGlobals['wgNoFollowDomainExceptions'] = [];
+ $tmpGlobals['wgNoFollowDomainExceptions'] = [ 'no-nofollow.org' ];
$tmpGlobals['wgExternalLinkTarget'] = false;
$tmpGlobals['wgThumbnailScriptPath'] = false;
$tmpGlobals['wgUseImageResize'] = true;
$tmpGlobals['wgAllowExternalImages'] = true;
$tmpGlobals['wgRawHtml'] = false;
- $tmpGlobals['wgWellFormedXml'] = true;
$tmpGlobals['wgExperimentalHtmlIds'] = false;
$tmpGlobals['wgAdaptiveMessageCache'] = true;
$tmpGlobals['wgUseDatabaseMessages'] = true;
$tmpGlobals['wgHooks'] = $tmpHooks;
# add a namespace shadowing a interwiki link, to test
# proper precedence when resolving links. (bug 51680)
- $tmpGlobals['wgExtraNamespaces'] = [ 100 => 'MemoryAlpha' ];
+ $tmpGlobals['wgExtraNamespaces'] = [
+ 100 => 'MemoryAlpha',
+ 101 => 'MemoryAlpha_talk'
+ ];
$tmpGlobals['wgLocalInterwikis'] = [ 'local', 'mi' ];
# "extra language links"
MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
$wgContLang->resetNamespaces(); # reset namespace cache
+ ParserTest::resetTitleServices();
}
protected function tearDown() {
'wgThumbLimits' => [ self::getOptionValue( 'thumbsize', $opts, 180 ) ],
'wgMaxTocLevel' => $maxtoclevel,
'wgUseTeX' => isset( $opts['math'] ) || isset( $opts['texvc'] ),
- 'wgWellFormedXml' => true,
'wgMathDirectory' => $uploadDir . '/math',
'wgDefaultLanguageVariant' => $variant,
'wgLinkHolderBatchSize' => $linkHolderBatchSize,
$keysWithTwoSlots = $keysWithFiveSlots = [];
foreach ( range( 1, 100 ) as $i ) {
- $keysWithTwoSlots[] = $hashKeyIntoSlots->invoke( $poolCounter, 'key ' . $i, 2 );
- $keysWithFiveSlots[] = $hashKeyIntoSlots->invoke( $poolCounter, 'key ' . $i, 5 );
+ $keysWithTwoSlots[] = $hashKeyIntoSlots->invoke( $poolCounter, 'test', 'key ' . $i, 2 );
+ $keysWithFiveSlots[] = $hashKeyIntoSlots->invoke( $poolCounter, 'test', 'key ' . $i, 5 );
}
- $this->assertArrayEquals( range( 0, 1 ), array_unique( $keysWithTwoSlots ) );
- $this->assertArrayEquals( range( 0, 4 ), array_unique( $keysWithFiveSlots ) );
+ $twoSlotKeys = [];
+ for ( $i = 0; $i <= 1; $i++ ) {
+ $twoSlotKeys[] = "test:$i";
+ }
+ $fiveSlotKeys = [];
+ for ( $i = 0; $i <= 4; $i++ ) {
+ $fiveSlotKeys[] = "test:$i";
+ }
+
+ $this->assertArrayEquals( $twoSlotKeys, array_unique( $keysWithTwoSlots ) );
+ $this->assertArrayEquals( $fiveSlotKeys, array_unique( $keysWithFiveSlots ) );
// make sure it is deterministic
$this->assertEquals(
- $hashKeyIntoSlots->invoke( $poolCounter, 'asdfgh', 1000 ),
- $hashKeyIntoSlots->invoke( $poolCounter, 'asdfgh', 1000 )
+ $hashKeyIntoSlots->invoke( $poolCounter, 'test', 'asdfgh', 1000 ),
+ $hashKeyIntoSlots->invoke( $poolCounter, 'test', 'asdfgh', 1000 )
);
}
}
$this->assertEquals( $rl->getTemplates(), $expected );
}
+
+ public function testBomConcatenation() {
+ $basePath = __DIR__ . '/../../data/css';
+ $testModule = new ResourceLoaderFileModule( [
+ 'localBasePath' => $basePath,
+ 'styles' => [ 'bom.css' ],
+ ] );
+ $this->assertEquals(
+ substr( file_get_contents( "$basePath/bom.css" ), 0, 10 ),
+ "\xef\xbb\xbf.efbbbf",
+ 'File has leading BOM'
+ );
+
+ $contextLtr = $this->getResourceLoaderContext( 'en', 'ltr' );
+ $this->assertEquals(
+ $testModule->getStyles( $contextLtr ),
+ [ 'all' => ".efbbbf_bom_char_at_start_of_file {}\n" ],
+ 'Leading BOM removed when concatenating files'
+ );
+ }
}
public function addDBDataOnce() {
$passwordFactory = new \PasswordFactory();
$passwordFactory->init( \RequestContext::getMain()->getConfig() );
- // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
- $passwordFactory->setDefaultType( 'A' );
- $pwhash = $passwordFactory->newFromPlaintext( 'foobaz' );
+ $passwordHash = $passwordFactory->newFromPlaintext( 'foobaz' );
- $userId = \CentralIdLookup::factory( 'local' )->centralIdFromName( 'UTSysop' );
+ $sysop = static::getTestSysop()->getUser();
+ $userId = \CentralIdLookup::factory( 'local' )->centralIdFromName( $sysop->getName() );
$dbw = wfGetDB( DB_MASTER );
$dbw->delete(
[
'bp_user' => $userId,
'bp_app_id' => 'BotPasswordSessionProvider',
- 'bp_password' => $pwhash->toString(),
+ 'bp_password' => $passwordHash->toString(),
'bp_token' => 'token!',
'bp_restrictions' => '{"IPAddresses":["127.0.0.0/8"]}',
'bp_grants' => '["test"]',
public function testNewSessionInfoForRequest() {
$provider = $this->getProvider();
- $user = \User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
$request->expects( $this->any() )->method( 'getIP' )
->will( $this->returnValue( '127.0.0.1' ) );
$provider = $this->getProvider();
$provider->setLogger( $logger );
- $user = \User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
$request->expects( $this->any() )->method( 'getIP' )
->will( $this->returnValue( '127.0.0.1' ) );
class CookieSessionProviderTest extends MediaWikiTestCase {
private function getConfig() {
- global $wgCookieExpiration;
return new \HashConfig( [
'CookiePrefix' => 'CookiePrefix',
'CookiePath' => 'CookiePath',
'CookieSecure' => true,
'CookieHttpOnly' => true,
'SessionName' => false,
+ 'CookieExpiration' => 100,
'ExtendedLoginCookies' => [ 'UserID', 'Token' ],
- 'ExtendedLoginCookieExpiration' => $wgCookieExpiration * 2,
+ 'ExtendedLoginCookieExpiration' => 200,
] );
}
$provider->setConfig( $this->getConfig() );
$provider->setManager( new SessionManager() );
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$id = $user->getId();
$name = $user->getName();
$token = $user->getToken( true );
}
public function testPersistSession() {
- $this->setMwGlobals( [ 'wgCookieExpiration' => 100 ] );
-
$provider = new CookieSessionProvider( [
'priority' => 1,
'sessionName' => 'MySessionName',
$sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
$store = new TestBagOStuff();
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$anon = new User;
$backend = new SessionBackend(
*/
public function testCookieData( $secure, $remember ) {
$this->setMwGlobals( [
- 'wgCookieExpiration' => 100,
'wgSecureLogin' => false,
] );
$provider->setManager( SessionManager::singleton() );
$sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$this->assertFalse( $user->requiresHTTPS(), 'sanity check' );
$backend = new SessionBackend(
$sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
$store = new TestBagOStuff();
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$anon = new User;
$backend = new SessionBackend(
$this->assertNull( $provider->getCookie( $request, 'Baz', 'x' ) );
}
+ public function testGetRememberUserDuration() {
+ $config = $this->getConfig();
+ $provider = new CookieSessionProvider( [ 'priority' => 10 ] );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setConfig( $config );
+ $provider->setManager( SessionManager::singleton() );
+
+ $this->assertSame( 200, $provider->getRememberUserDuration() );
+
+ $config->set( 'ExtendedLoginCookieExpiration', null );
+
+ $this->assertSame( 100, $provider->getRememberUserDuration() );
+
+ $config->set( 'ExtendedLoginCookieExpiration', 0 );
+
+ $this->assertSame( null, $provider->getRememberUserDuration() );
+ }
+
+ public function testGetLoginCookieExpiration() {
+ $config = $this->getConfig();
+ $provider = \TestingAccessWrapper::newFromObject( new CookieSessionProvider( [
+ 'priority' => 10
+ ] ) );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $provider->setConfig( $config );
+ $provider->setManager( SessionManager::singleton() );
+
+ $this->assertSame( 200, $provider->getLoginCookieExpiration( 'Token' ) );
+ $this->assertSame( 100, $provider->getLoginCookieExpiration( 'User' ) );
+
+ $config->set( 'ExtendedLoginCookieExpiration', null );
+
+ $this->assertSame( 100, $provider->getLoginCookieExpiration( 'Token' ) );
+ $this->assertSame( 100, $provider->getLoginCookieExpiration( 'User' ) );
+ }
}
}
$this->assertEquals( [
'value' => 'true',
- 'expire' => $remember ? 100 : null,
+ 'expire' => null,
'path' => 'CookiePath',
'domain' => 'CookieDomain',
'secure' => false,
$this->assertSame( $expect, $_SESSION );
}
- // Test expiry
- session_write_close();
- ini_set( 'session.gc_divisor', 1 );
- ini_set( 'session.gc_probability', 1 );
- sleep( 3 );
- session_start();
- $this->assertSame( [], $_SESSION );
-
// Re-fill the session, then test that session_destroy() works.
$_SESSION['AuthenticationSessionTest'] = $rand;
session_write_close();
}
public function testSetUser() {
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$this->provider = $this->getMock( 'DummySessionProvider', [ 'canChangeUser' ] );
$this->provider->expects( $this->any() )->method( 'canChangeUser' )
}
public function testSave() {
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$this->store = new TestBagOStuff();
$testData = [ 'foo' => 'foo!', 'bar', [ 'baz', null ] ];
}
public function testRenew() {
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$this->store = new TestBagOStuff();
$testData = [ 'foo' => 'foo!', 'bar', [ 'baz', null ] ];
$handler->enable = true;
}
- $backend = $this->getBackend( User::newFromName( 'UTSysop' ) );
+ $backend = $this->getBackend( static::getTestSysop()->getUser() );
\TestingAccessWrapper::newFromObject( $backend )->usePhpSessionHandling = true;
$resetSingleton = TestUtils::setSessionManagerSingleton( $this->manager );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $anonInfo, $info->getUserInfo() );
$this->assertTrue( $info->isIdSafe() );
+ $this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $unverifiedUserInfo, $info->getUserInfo() );
$this->assertTrue( $info->isIdSafe() );
+ $this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $userInfo, $info->getUserInfo() );
$this->assertTrue( $info->isIdSafe() );
+ $this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertTrue( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $anonInfo, $info->getUserInfo() );
$this->assertFalse( $info->isIdSafe() );
+ $this->assertFalse( $info->forceUse() );
$this->assertTrue( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $userInfo, $info->getUserInfo() );
$this->assertFalse( $info->isIdSafe() );
+ $this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertTrue( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $userInfo, $info->getUserInfo() );
$this->assertFalse( $info->isIdSafe() );
+ $this->assertFalse( $info->forceUse() );
$this->assertTrue( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertTrue( $info->isIdSafe() );
+ $info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
+ 'id' => $id,
+ 'forceUse' => true,
+ ] );
+ $this->assertFalse( $info->forceUse(), 'no provider' );
+
+ $info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
+ 'provider' => $provider,
+ 'forceUse' => true,
+ ] );
+ $this->assertFalse( $info->forceUse(), 'no id' );
+
+ $info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
+ 'provider' => $provider,
+ 'id' => $id,
+ 'forceUse' => true,
+ ] );
+ $this->assertTrue( $info->forceUse(), 'correct use' );
+
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, [
'id' => $id,
'forceHTTPS' => 1,
'provider' => $provider,
'userInfo' => $userInfo,
'idIsSafe' => true,
+ 'forceUse' => true,
'persisted' => true,
'remembered' => true,
'forceHTTPS' => true,
$this->assertSame( $provider, $info->getProvider() );
$this->assertSame( $userInfo, $info->getUserInfo() );
$this->assertTrue( $info->isIdSafe() );
+ $this->assertTrue( $info->forceUse() );
$this->assertTrue( $info->wasPersisted() );
$this->assertTrue( $info->wasRemembered() );
$this->assertTrue( $info->forceHTTPS() );
'provider' => $provider2,
'userInfo' => $unverifiedUserInfo,
'idIsSafe' => false,
+ 'forceUse' => false,
'persisted' => false,
'remembered' => false,
'forceHTTPS' => false,
$this->assertSame( $provider2, $info->getProvider() );
$this->assertSame( $unverifiedUserInfo, $info->getUserInfo() );
$this->assertFalse( $info->isIdSafe() );
+ $this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
}
}
+ public function testInvalidateSessionsForUser() {
+ $user = User::newFromName( 'UTSysop' );
+ $manager = $this->getManager();
+
+ $providerBuilder = $this->getMockBuilder( 'DummySessionProvider' )
+ ->setMethods( [ 'invalidateSessionsForUser', '__toString' ] );
+
+ $provider1 = $providerBuilder->getMock();
+ $provider1->expects( $this->once() )->method( 'invalidateSessionsForUser' )
+ ->with( $this->identicalTo( $user ) );
+ $provider1->expects( $this->any() )->method( '__toString' )
+ ->will( $this->returnValue( 'MockProvider1' ) );
+
+ $provider2 = $providerBuilder->getMock();
+ $provider2->expects( $this->once() )->method( 'invalidateSessionsForUser' )
+ ->with( $this->identicalTo( $user ) );
+ $provider2->expects( $this->any() )->method( '__toString' )
+ ->will( $this->returnValue( 'MockProvider2' ) );
+
+ $this->config->set( 'SessionProviders', [
+ $this->objectCacheDef( $provider1 ),
+ $this->objectCacheDef( $provider2 ),
+ ] );
+
+ $oldToken = $user->getToken( true );
+ $manager->invalidateSessionsForUser( $user );
+ $this->assertNotEquals( $oldToken, $user->getToken() );
+ }
+
public function testGetVaryHeaders() {
$manager = $this->getManager();
}
public function testAutoCreateUser() {
- global $wgGroupPermissions;
+ global $wgGroupPermissions, $wgDisableAuthManager;
+
+ if ( !$wgDisableAuthManager ) {
+ $this->markTestSkipped( 'AuthManager is not disabled' );
+ }
\ObjectCache::$instances[__METHOD__] = new TestBagOStuff();
$this->setMwGlobals( [ 'wgMainCacheType' => __METHOD__ ] );
[ LogLevel::WARNING, 'Session "{session}": Hook aborted' ],
], $logger->getBuffer() );
$logger->clearBuffer();
+ $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'SessionCheckInfo' => [] ] );
+
+ // forceUse deletes bad backend data
+ $this->store->setSessionMeta( $id, [ 'userToken' => 'Bad' ] + $metadata );
+ $info = new SessionInfo( SessionInfo::MIN_PRIORITY, [
+ 'provider' => $provider,
+ 'id' => $id,
+ 'userInfo' => $userInfo,
+ 'forceUse' => true,
+ ] );
+ $this->assertTrue( $loadSessionInfoFromStore( $info ) );
+ $this->assertFalse( $this->store->getSession( $id ) );
+ $this->assertSame( [
+ [ LogLevel::WARNING, 'Session "{session}": User token mismatch' ],
+ ], $logger->getBuffer() );
+ $logger->clearBuffer();
}
}
$this->assertSame( $manager, $priv->manager );
$this->assertSame( $manager, $provider->getManager() );
+ $provider->invalidateSessionsForUser( new \User );
+
$this->assertSame( [], $provider->getVaryHeaders() );
$this->assertSame( [], $provider->getVaryCookies() );
$this->assertSame( null, $provider->suggestLoginUsername( new \FauxRequest ) );
$this->assertSame( get_class( $provider ), (string)$provider );
+ $this->assertNull( $provider->getRememberUserDuration() );
+
$this->assertNull( $provider->whyNoSession() );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, [
// getGenderCache() provides a mock that considers first
// names ending in "a" to be female.
[ NS_USER, 'Lisa_Müller', '', 'de', 'Benutzerin:Lisa Müller' ],
+ [ 1000000, 'Invalid_namespace', '', 'en', ':Invalid namespace' ],
];
}
$this->assertEquals( $expected, $actual );
}
+ public static function provideGetPrefixedDBkey() {
+ return [
+ [ NS_MAIN, 'Foo_Bar', '', '', 'en', 'Foo_Bar' ],
+ [ NS_USER, 'Hansi_Maier', 'stuff_and_so_on', '', 'en', 'User:Hansi_Maier' ],
+
+ // No capitalization or normalization is applied while formatting!
+ [ NS_USER_TALK, 'hansi__maier', '', '', 'en', 'User_talk:hansi__maier' ],
+
+ // getGenderCache() provides a mock that considers first
+ // names ending in "a" to be female.
+ [ NS_USER, 'Lisa_Müller', '', '', 'de', 'Benutzerin:Lisa_Müller' ],
+
+ [ NS_MAIN, 'Remote_page', '', 'remotetestiw', 'en', 'remotetestiw:Remote_page' ],
+
+ // non-existent namespace
+ [ 10000000, 'Foobar', '', '', 'en', ':Foobar' ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideGetPrefixedDBkey
+ */
+ public function testGetPrefixedDBkey( $namespace, $dbkey, $fragment,
+ $interwiki, $lang, $expected
+ ) {
+ $codec = $this->makeCodec( $lang );
+ $title = new TitleValue( $namespace, $dbkey, $fragment, $interwiki );
+
+ $actual = $codec->getPrefixedDBkey( $title );
+
+ $this->assertEquals( $expected, $actual );
+ }
+
public static function provideGetFullText() {
return [
[ NS_MAIN, 'Foo_Bar', '', 'en', 'Foo Bar' ],
$title = new TitleValue( $ns, $text, $fragment, $interwiki );
$this->assertEquals( $ns, $title->getNamespace() );
+ $this->assertTrue( $title->inNamespace( $ns ) );
$this->assertEquals( $text, $title->getText() );
$this->assertEquals( $fragment, $title->getFragment() );
$this->assertEquals( $hasFragment, $title->hasFragment() );
false,
'SVG with external entity'
],
-
+ [
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"> <g> <a xlink:href=\"javascript:alert('1 https://google.com')\"> <rect width=\"300\" height=\"100\" style=\"fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,2)\" /> </a> </g> </svg>",
+ true,
+ true,
+ 'SVG with javascript <a> link with newline (T122653)'
+ ],
// Test good, but strange files that we want to allow
[
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g> <a xlink:href="http://en.wikipedia.org/wiki/Main_Page"> <path transform="translate(0,496)" id="path6706" d="m 112.09375,107.6875 -5.0625,3.625 -4.3125,5.03125 -0.46875,0.5 -4.09375,3.34375 -9.125,5.28125 -8.625,-3.375 z" style="fill:#cccccc;fill-opacity:1;stroke:#6e6e6e;stroke-width:0.69999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;display:inline" /> </a> </g> </svg>',
* @group Database
*/
class BotPasswordTest extends MediaWikiTestCase {
+
+ /** @var TestUser */
+ private $testUser;
+
+ /** @var string */
+ private $testUserName;
+
protected function setUp() {
parent::setUp();
'wgUserrightsInterwikiDelimiter' => '@',
] );
+ $this->testUser = $this->getMutableTestUser();
+ $this->testUserName = $this->testUser->getUser()->getName();
+
$mock1 = $this->getMockForAbstractClass( 'CentralIdLookup' );
$mock1->expects( $this->any() )->method( 'isAttached' )
->will( $this->returnValue( true ) );
$mock1->expects( $this->any() )->method( 'lookupUserNames' )
- ->will( $this->returnValue( [ 'UTSysop' => 42, 'UTDummy' => 43, 'UTInvalid' => 0 ] ) );
+ ->will( $this->returnValue( [ $this->testUserName => 42, 'UTDummy' => 43, 'UTInvalid' => 0 ] ) );
$mock1->expects( $this->never() )->method( 'lookupCentralIds' );
$mock2 = $this->getMockForAbstractClass( 'CentralIdLookup' );
public function addDBData() {
$passwordFactory = new \PasswordFactory();
$passwordFactory->init( \RequestContext::getMain()->getConfig() );
- // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
- $passwordFactory->setDefaultType( 'A' );
- $pwhash = $passwordFactory->newFromPlaintext( 'foobaz' );
+ $passwordHash = $passwordFactory->newFromPlaintext( 'foobaz' );
$dbw = wfGetDB( DB_MASTER );
$dbw->delete(
[
'bp_user' => 42,
'bp_app_id' => 'BotPassword',
- 'bp_password' => $pwhash->toString(),
+ 'bp_password' => $passwordHash->toString(),
'bp_token' => 'token!',
'bp_restrictions' => '{"IPAddresses":["127.0.0.0/8"]}',
'bp_grants' => '["test"]',
[
'bp_user' => 43,
'bp_app_id' => 'BotPassword',
- 'bp_password' => $pwhash->toString(),
+ 'bp_password' => $passwordHash->toString(),
'bp_token' => 'token!',
'bp_restrictions' => '{"IPAddresses":["127.0.0.0/8"]}',
'bp_grants' => '["test"]',
}
public function testBasics() {
- $user = User::newFromName( 'UTSysop' );
+ $user = $this->testUser->getUser();
$bp = BotPassword::newFromUser( $user, 'BotPassword' );
$this->assertInstanceOf( 'BotPassword', $bp );
$this->assertTrue( $bp->isSaved() );
}
public function testUnsaved() {
- $user = User::newFromName( 'UTSysop' );
+ $user = $this->testUser->getUser();
$bp = BotPassword::newUnsaved( [
'user' => $user,
'appId' => 'DoesNotExist'
$this->assertEquals( '{"IPAddresses":["127.0.0.0/8"]}', $bp->getRestrictions()->toJson() );
$this->assertSame( [ 'test' ], $bp->getGrants() );
- $user = User::newFromName( 'UTSysop' );
+ $user = $this->testUser->getUser();
$bp = BotPassword::newUnsaved( [
'centralId' => 45,
'appId' => 'DoesNotExist'
$this->assertSame( 45, $bp->getUserCentralId() );
$this->assertSame( 'DoesNotExist', $bp->getAppId() );
- $user = User::newFromName( 'UTSysop' );
+ $user = $this->testUser->getUser();
$bp = BotPassword::newUnsaved( [
'user' => $user,
'appId' => 'BotPassword'
'appId' => str_repeat( 'X', BotPassword::APPID_MAXLENGTH + 1 ),
] ) );
$this->assertNull( BotPassword::newUnsaved( [
- 'user' => 'UTSysop',
+ 'user' => $this->testUserName,
'appId' => 'Ok',
] ) );
$this->assertNull( BotPassword::newUnsaved( [
$this->assertNotInstanceOf( 'InvalidPassword', $bp1->getPassword(), 'sanity check' );
$this->assertNotInstanceOf( 'InvalidPassword', $bp2->getPassword(), 'sanity check' );
- BotPassword::invalidateAllPasswordsForUser( 'UTSysop' );
+ BotPassword::invalidateAllPasswordsForUser( $this->testUserName );
$this->assertInstanceOf( 'InvalidPassword', $bp1->getPassword() );
$this->assertNotInstanceOf( 'InvalidPassword', $bp2->getPassword() );
$this->assertNotNull( BotPassword::newFromCentralId( 42, 'BotPassword' ), 'sanity check' );
$this->assertNotNull( BotPassword::newFromCentralId( 43, 'BotPassword' ), 'sanity check' );
- BotPassword::removeAllPasswordsForUser( 'UTSysop' );
+ BotPassword::removeAllPasswordsForUser( $this->testUserName );
$this->assertNull( BotPassword::newFromCentralId( 42, 'BotPassword' ) );
$this->assertNotNull( BotPassword::newFromCentralId( 43, 'BotPassword' ) );
public function testLogin() {
// Test failure when bot passwords aren't enabled
$this->setMwGlobals( 'wgEnableBotPasswords', false );
- $status = BotPassword::login( 'UTSysop@BotPassword', 'foobaz', new FauxRequest );
+ $status = BotPassword::login( "{$this->testUserName}@BotPassword", 'foobaz', new FauxRequest );
$this->assertEquals( Status::newFatal( 'botpasswords-disabled' ), $status );
$this->setMwGlobals( 'wgEnableBotPasswords', true );
$manager->getProvider( MediaWiki\Session\BotPasswordSessionProvider::class ),
'sanity check'
);
- $status = BotPassword::login( 'UTSysop@BotPassword', 'foobaz', new FauxRequest );
+ $status = BotPassword::login( "{$this->testUserName}@BotPassword", 'foobaz', new FauxRequest );
$this->assertEquals( Status::newFatal( 'botpasswords-no-provider' ), $status );
ScopedCallback::consume( $reset );
$reset = MediaWiki\Session\TestUtils::setSessionManagerSingleton( $manager );
// No "@"-thing in the username
- $status = BotPassword::login( 'UTSysop', 'foobaz', new FauxRequest );
+ $status = BotPassword::login( $this->testUserName, 'foobaz', new FauxRequest );
$this->assertEquals( Status::newFatal( 'botpasswords-invalid-name', '@' ), $status );
// No base user
$this->assertEquals( Status::newFatal( 'nosuchuser', 'UTDummy' ), $status );
// No bot password
- $status = BotPassword::login( 'UTSysop@DoesNotExist', 'foobaz', new FauxRequest );
+ $status = BotPassword::login( "{$this->testUserName}@DoesNotExist", 'foobaz', new FauxRequest );
$this->assertEquals(
- Status::newFatal( 'botpasswords-not-exist', 'UTSysop', 'DoesNotExist' ),
+ Status::newFatal( 'botpasswords-not-exist', $this->testUserName, 'DoesNotExist' ),
$status
);
$request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
$request->expects( $this->any() )->method( 'getIP' )
->will( $this->returnValue( '10.0.0.1' ) );
- $status = BotPassword::login( 'UTSysop@BotPassword', 'foobaz', $request );
+ $status = BotPassword::login( "{$this->testUserName}@BotPassword", 'foobaz', $request );
$this->assertEquals( Status::newFatal( 'botpasswords-restriction-failed' ), $status );
// Wrong password
- $status = BotPassword::login( 'UTSysop@BotPassword', 'UTSysopPassword', new FauxRequest );
+ $status = BotPassword::login(
+ "{$this->testUserName}@BotPassword", $this->testUser->password, new FauxRequest );
$this->assertEquals( Status::newFatal( 'wrongpassword' ), $status );
// Success!
$request->getSession()->getProvider(),
'sanity check'
);
- $status = BotPassword::login( 'UTSysop@BotPassword', 'foobaz', $request );
+ $status = BotPassword::login( "{$this->testUserName}@BotPassword", 'foobaz', $request );
$this->assertInstanceOf( 'Status', $status );
$this->assertTrue( $status->isGood() );
$session = $status->getValue();
public function testSave( $password ) {
$passwordFactory = new \PasswordFactory();
$passwordFactory->init( \RequestContext::getMain()->getConfig() );
- // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
- $passwordFactory->setDefaultType( 'A' );
$bp = BotPassword::newUnsaved( [
'centralId' => 42,
BotPassword::newFromCentralId( 42, 'TestSave', BotPassword::READ_LATEST ), 'sanity check'
);
- $pwhash = $password ? $passwordFactory->newFromPlaintext( $password ) : null;
- $this->assertFalse( $bp->save( 'update', $pwhash ) );
- $this->assertTrue( $bp->save( 'insert', $pwhash ) );
+ $passwordHash = $password ? $passwordFactory->newFromPlaintext( $password ) : null;
+ $this->assertFalse( $bp->save( 'update', $passwordHash ) );
+ $this->assertTrue( $bp->save( 'insert', $passwordHash ) );
$bp2 = BotPassword::newFromCentralId( 42, 'TestSave', BotPassword::READ_LATEST );
$this->assertInstanceOf( 'BotPassword', $bp2 );
$this->assertEquals( $bp->getUserCentralId(), $bp2->getUserCentralId() );
$this->assertTrue( $pw->equals( $password ) );
}
- $pwhash = $passwordFactory->newFromPlaintext( 'XXX' );
+ $passwordHash = $passwordFactory->newFromPlaintext( 'XXX' );
$token = $bp->getToken();
- $this->assertTrue( $bp->save( 'update', $pwhash ) );
+ $this->assertTrue( $bp->save( 'update', $passwordHash ) );
$this->assertNotEquals( $token, $bp->getToken() );
$pw = TestingAccessWrapper::newFromObject( $bp )->getPassword();
$this->assertTrue( $pw->equals( 'XXX' ) );
$this->getMockForAbstractClass( 'CentralIdLookup' )
);
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestSysop()->getUser();
$this->assertSame( $user, $mock->checkAudience( $user ) );
$user = $mock->checkAudience( CentralIdLookup::AUDIENCE_PUBLIC );
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();
+ $this->localUsers[] = $this->getMutableTestUser()->getUser();
}
- User::newFromName( 'UTLocalIdLookup1' )->addGroup( 'local-id-lookup-test' );
+ $sysop = static::getTestSysop()->getUser();
$block = new Block( [
- 'address' => 'UTLocalIdLookup3',
- 'by' => User::idFromName( 'UTSysop' ),
+ 'address' => $this->localUsers[2]->getName(),
+ 'by' => $sysop->getId(),
'reason' => __METHOD__,
'expiry' => '1 day',
'hideName' => false,
$block->insert();
$block = new Block( [
- 'address' => 'UTLocalIdLookup4',
- 'by' => User::idFromName( 'UTSysop' ),
+ 'address' => $this->localUsers[3]->getName(),
+ 'by' => $sysop->getId(),
'reason' => __METHOD__,
'expiry' => '1 day',
'hideName' => true,
$block->insert();
}
+ public function getLookupUser() {
+ return static::getTestUser( [ 'local-id-lookup-test' ] )->getUser();
+ }
+
public function testLookupCentralIds() {
$lookup = new LocalIdLookup();
- $user1 = User::newFromName( 'UTLocalIdLookup1' );
+
+ $user1 = $this->getLookupUser();
$user2 = User::newFromName( 'UTLocalIdLookup2' );
$this->assertTrue( $user1->isAllowed( 'hideuser' ), 'sanity check' );
$this->assertSame( [], $lookup->lookupCentralIds( [] ) );
- $expect = array_flip( $this->localUsers );
- $expect[123] = 'X';
+ $expect = [];
+ foreach ( $this->localUsers as $localUser ) {
+ $expect[$localUser->getId()] = $localUser->getName();
+ }
+ $expect[12345] = 'X';
ksort( $expect );
$expect2 = $expect;
- $expect2[$this->localUsers['UTLocalIdLookup4']] = '';
+ $expect2[$this->localUsers[3]->getId()] = '';
$arg = array_fill_keys( array_keys( $expect ), 'X' );
public function testLookupUserNames() {
$lookup = new LocalIdLookup();
- $user1 = User::newFromName( 'UTLocalIdLookup1' );
+ $user1 = $this->getLookupUser();
$user2 = User::newFromName( 'UTLocalIdLookup2' );
$this->assertTrue( $user1->isAllowed( 'hideuser' ), 'sanity check' );
$this->assertSame( [], $lookup->lookupUserNames( [] ) );
- $expect = $this->localUsers;
+ $expect = [];
+ foreach ( $this->localUsers as $localUser ) {
+ $expect[$localUser->getName()] = $localUser->getId();
+ }
$expect['UTDoesNotExist'] = 'X';
ksort( $expect );
$expect2 = $expect;
- $expect2['UTLocalIdLookup4'] = 'X';
+ $expect2[$this->localUsers[3]->getName()] = 'X';
$arg = array_fill_keys( array_keys( $expect ), 'X' );
public function testIsAttached() {
$lookup = new LocalIdLookup();
- $user1 = User::newFromName( 'UTLocalIdLookup1' );
+ $user1 = $this->getLookupUser();
$user2 = User::newFromName( 'DoesNotExist' );
$this->assertTrue( $lookup->isAttached( $user1 ) );
$lookup = new LocalIdLookup();
$this->assertSame(
$sharedDB && $sharedTable && $localDBSet,
- $lookup->isAttached( User::newFromName( 'UTLocalIdLookup1' ), 'shared' )
+ $lookup->isAttached( $this->getLookupUser(), 'shared' )
);
}
--- /dev/null
+<?php
+
+use MediaWiki\Auth\AuthManager;
+
+/**
+ * @group Database
+ */
+class PasswordResetTest extends PHPUnit_Framework_TestCase {
+ /**
+ * @dataProvider provideIsAllowed
+ */
+ public function testIsAllowed( $passwordResetRoutes, $enableEmail,
+ $allowsAuthenticationDataChange, $canEditPrivate, $canSeePassword,
+ $userIsBlocked, $isAllowed, $isAllowedToDisplayPassword
+ ) {
+ $config = new HashConfig( [
+ 'PasswordResetRoutes' => $passwordResetRoutes,
+ 'EnableEmail' => $enableEmail,
+ ] );
+
+ $authManager = $this->getMockBuilder( AuthManager::class )->disableOriginalConstructor()
+ ->getMock();
+ $authManager->expects( $this->any() )->method( 'allowsAuthenticationDataChange' )
+ ->willReturn( $allowsAuthenticationDataChange ? Status::newGood() : Status::newFatal( 'foo' ) );
+
+ $user = $this->getMock( User::class );
+ $user->expects( $this->any() )->method( 'getName' )->willReturn( 'Foo' );
+ $user->expects( $this->any() )->method( 'isBlocked' )->willReturn( $userIsBlocked );
+ $user->expects( $this->any() )->method( 'isAllowed' )
+ ->will( $this->returnCallback( function ( $perm ) use ( $canEditPrivate, $canSeePassword ) {
+ if ( $perm === 'editmyprivateinfo' ) {
+ return $canEditPrivate;
+ } elseif ( $perm === 'passwordreset' ) {
+ return $canSeePassword;
+ } else {
+ $this->fail( 'Unexpected permission check' );
+ }
+ } ) );
+
+ $passwordReset = new PasswordReset( $config, $authManager );
+
+ $this->assertSame( $isAllowed, $passwordReset->isAllowed( $user )->isGood() );
+ $this->assertSame( $isAllowedToDisplayPassword,
+ $passwordReset->isAllowed( $user, true )->isGood() );
+ }
+
+ public function provideIsAllowed() {
+ return [
+ [
+ 'passwordResetRoutes' => [],
+ 'enableEmail' => true,
+ 'allowsAuthenticationDataChange' => true,
+ 'canEditPrivate' => true,
+ 'canSeePassword' => true,
+ 'userIsBlocked' => false,
+ 'isAllowed' => false,
+ 'isAllowedToDisplayPassword' => false,
+ ],
+ [
+ 'passwordResetRoutes' => [ 'username' => true ],
+ 'enableEmail' => false,
+ 'allowsAuthenticationDataChange' => true,
+ 'canEditPrivate' => true,
+ 'canSeePassword' => true,
+ 'userIsBlocked' => false,
+ 'isAllowed' => false,
+ 'isAllowedToDisplayPassword' => false,
+ ],
+ [
+ 'passwordResetRoutes' => [ 'username' => true ],
+ 'enableEmail' => true,
+ 'allowsAuthenticationDataChange' => false,
+ 'canEditPrivate' => true,
+ 'canSeePassword' => true,
+ 'userIsBlocked' => false,
+ 'isAllowed' => false,
+ 'isAllowedToDisplayPassword' => false,
+ ],
+ [
+ 'passwordResetRoutes' => [ 'username' => true ],
+ 'enableEmail' => true,
+ 'allowsAuthenticationDataChange' => true,
+ 'canEditPrivate' => false,
+ 'canSeePassword' => true,
+ 'userIsBlocked' => false,
+ 'isAllowed' => false,
+ 'isAllowedToDisplayPassword' => false,
+ ],
+ [
+ 'passwordResetRoutes' => [ 'username' => true ],
+ 'enableEmail' => true,
+ 'allowsAuthenticationDataChange' => true,
+ 'canEditPrivate' => true,
+ 'canSeePassword' => true,
+ 'userIsBlocked' => true,
+ 'isAllowed' => false,
+ 'isAllowedToDisplayPassword' => false,
+ ],
+ [
+ 'passwordResetRoutes' => [ 'username' => true ],
+ 'enableEmail' => true,
+ 'allowsAuthenticationDataChange' => true,
+ 'canEditPrivate' => true,
+ 'canSeePassword' => false,
+ 'userIsBlocked' => false,
+ 'isAllowed' => true,
+ 'isAllowedToDisplayPassword' => false,
+ ],
+ [
+ 'passwordResetRoutes' => [ 'username' => true ],
+ 'enableEmail' => true,
+ 'allowsAuthenticationDataChange' => true,
+ 'canEditPrivate' => true,
+ 'canSeePassword' => true,
+ 'userIsBlocked' => false,
+ 'isAllowed' => true,
+ 'isAllowedToDisplayPassword' => true,
+ ],
+ ];
+ }
+
+ public function testExecute_email() {
+ $config = new HashConfig( [
+ 'PasswordResetRoutes' => [ 'username' => true, 'email' => true ],
+ 'EnableEmail' => true,
+ ] );
+
+ $authManager = $this->getMockBuilder( AuthManager::class )->disableOriginalConstructor()
+ ->getMock();
+ $authManager->expects( $this->any() )->method( 'allowsAuthenticationDataChange' )
+ ->willReturn( Status::newGood() );
+ $authManager->expects( $this->exactly( 2 ) )->method( 'changeAuthenticationData' );
+
+ $request = new FauxRequest();
+ $request->setIP( '1.2.3.4' );
+ $performingUser = $this->getMock( User::class );
+ $performingUser->expects( $this->any() )->method( 'getRequest' )->willReturn( $request );
+ $performingUser->expects( $this->any() )->method( 'isAllowed' )->willReturn( true );
+
+ $targetUser1 = $this->getMock( User::class );
+ $targetUser2 = $this->getMock( User::class );
+ $targetUser1->expects( $this->any() )->method( 'getName' )->willReturn( 'User1' );
+ $targetUser2->expects( $this->any() )->method( 'getName' )->willReturn( 'User2' );
+ $targetUser1->expects( $this->any() )->method( 'getId' )->willReturn( 1 );
+ $targetUser2->expects( $this->any() )->method( 'getId' )->willReturn( 2 );
+ $targetUser1->expects( $this->any() )->method( 'getEmail' )->willReturn( 'foo@bar.baz' );
+ $targetUser2->expects( $this->any() )->method( 'getEmail' )->willReturn( 'foo@bar.baz' );
+
+ $passwordReset = $this->getMockBuilder( PasswordReset::class )
+ ->setMethods( [ 'getUsersByEmail' ] )->setConstructorArgs( [ $config, $authManager ] )
+ ->getMock();
+ $passwordReset->expects( $this->any() )->method( 'getUsersByEmail' )->with( 'foo@bar.baz' )
+ ->willReturn( [ $targetUser1, $targetUser2 ] );
+
+ $status = $passwordReset->isAllowed( $performingUser );
+ $this->assertTrue( $status->isGood() );
+
+ $status = $passwordReset->execute( $performingUser, null, 'foo@bar.baz' );
+ $this->assertTrue( $status->isGood() );
+ }
+}
* @covers User::getEditCount
*/
public function testEditCount() {
- $user = User::newFromName( 'UnitTestUser' );
-
- if ( !$user->getId() ) {
- $user->addToDatabase();
- }
+ $user = $this->getMutableTestUser()->getUser();
// let the user have a few (3) edits
$page = WikiPage::factory( Title::newFromText( 'Help:UserTest_EditCount' ) );
* @covers User::getOption
*/
public function testOptions() {
- $user = User::newFromName( 'UnitTestUser' );
-
- if ( !$user->getId() ) {
- $user->addToDatabase();
- }
+ $user = $this->getMutableTestUser()->getUser();
$user->setOption( 'userjs-someoption', 'test' );
$user->setOption( 'cols', 200 );
$user->saveSettings();
- $user = User::newFromName( 'UnitTestUser' );
+ $user = User::newFromName( $user->getName() );
$this->assertEquals( 'test', $user->getOption( 'userjs-someoption' ) );
$this->assertEquals( 200, $user->getOption( 'cols' ) );
}
'MinimalPasswordLength' => 6,
'PasswordCannotMatchUsername' => true,
'PasswordCannotMatchBlacklist' => true,
- 'MaximalPasswordLength' => 30,
+ 'MaximalPasswordLength' => 40,
],
],
'checks' => [
],
] );
- $user = User::newFromName( 'Useruser' );
+ $user = static::getTestUser()->getUser();
+
// Sanity
$this->assertTrue( $user->isValidPassword( 'Password1234' ) );
$this->assertEquals( 'passwordtooshort', $user->getPasswordValidity( 'a' ) );
// Maximum length
- $longPass = str_repeat( 'a', 31 );
+ $longPass = str_repeat( 'a', 41 );
$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' ) );
+ $this->assertFalse( $user->checkPasswordValidity( $user->getName() )->isGood() );
+ $this->assertTrue( $user->checkPasswordValidity( $user->getName() )->isOK() );
+ $this->assertEquals( 'password-name-match', $user->getPasswordValidity( $user->getName() ) );
// On the forbidden list
+ $user = User::newFromName( 'Useruser' );
$this->assertFalse( $user->checkPasswordValidity( 'Passpass' )->isGood() );
$this->assertEquals( 'password-login-forbidden', $user->getPasswordValidity( 'Passpass' ) );
}
* @covers User::equals
*/
public function testEquals() {
- $first = User::newFromName( 'EqualUser' );
- $second = User::newFromName( 'EqualUser' );
+ $first = $this->getMutableTestUser()->getUser();
+ $second = User::newFromName( $first->getName() );
$this->assertTrue( $first->equals( $first ) );
$this->assertTrue( $first->equals( $second ) );
$this->assertTrue( $second->equals( $first ) );
- $third = User::newFromName( '0' );
- $fourth = User::newFromName( '000' );
+ $third = $this->getMutableTestUser()->getUser();
+ $fourth = $this->getMutableTestUser()->getUser();
$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' );
+ $user = $this->getMutableTestUser()->getUser();
+ $fifth = User::newFromId( $user->getId() );
+ $sixth = User::newFromName( $user->getName() );
$this->assertTrue( $fifth->equals( $sixth ) );
}
* @covers User::getId
*/
public function testGetId() {
- $user = User::newFromName( 'UTSysop' );
+ $user = static::getTestUser()->getUser();
$this->assertTrue( $user->getId() > 0 );
}
* @covers User::isAnon
*/
public function testLoggedIn() {
- $user = User::newFromName( 'UTSysop' );
+ $user = $this->getMutableTestUser()->getUser();
$this->assertTrue( $user->isLoggedIn() );
$this->assertFalse( $user->isAnon() );
* @covers User::checkAndSetTouched
*/
public function testCheckAndSetTouched() {
- $user = TestingAccessWrapper::newFromObject( User::newFromName( 'UTSysop' ) );
+ $user = $this->getMutableTestUser()->getUser();
+ $user = TestingAccessWrapper::newFromObject( $user );
$this->assertTrue( $user->isLoggedIn() );
$touched = $user->getDBTouched();
],
];
}
+
+ public function testEquals() {
+ $en1 = new Language();
+ $en1->setCode( 'en' );
+
+ $en2 = Language::factory( 'en' );
+ $en2->setCode( 'en' );
+
+ $this->assertTrue( $en1->equals( $en2 ), 'en equals en' );
+
+ $fr = Language::factory( 'fr' );
+ $this->assertFalse( $en1->equals( $fr ), 'en not equals fr' );
+ }
}
*/
protected $xml = null;
+ /** @var bool|null Whether the 'gzip' utility is available */
+ protected static $hasGzip = null;
+
+ /**
+ * Skip the test if 'gzip' is not in $PATH.
+ *
+ * @return bool
+ */
+ protected function checkHasGzip() {
+ if ( self::$hasGzip === null ) {
+ self::$hasGzip = ( Installer::locateExecutableInDefaultPaths( 'gzip' ) !== false );
+ }
+
+ if ( !self::$hasGzip ) {
+ $this->markTestSkipped( "Skip test, requires the gzip utility in PATH" );
+ }
+
+ return self::$hasGzip;
+ }
+
/**
* Adds a revision to a page, while returning the resuting revision's id
*
global $wgLanguageConverterCacheType, $wgUseDatabaseMessages;
global $wgLocaltimezone, $wgLocalisationCacheConf;
global $wgDevelopmentWarnings;
- global $wgSessionProviders;
+ global $wgSessionProviders, $wgSessionPbkdf2Iterations;
global $wgJobTypeConf;
+ global $wgAuthManagerConfig, $wgAuth, $wgDisableAuthManager;
// Inject test autoloader
require_once __DIR__ . '/../TestsAutoLoader.php';
],
];
+ // Single-iteration PBKDF2 session secret derivation, for speed.
+ $wgSessionPbkdf2Iterations = 1;
+
+ // Generic AuthManager configuration for testing
+ $wgAuthManagerConfig = [
+ 'preauth' => [],
+ 'primaryauth' => [
+ [
+ 'class' => MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider::class,
+ 'args' => [ [
+ 'authoritative' => false,
+ ] ],
+ ],
+ [
+ 'class' => MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider::class,
+ 'args' => [ [
+ 'authoritative' => true,
+ ] ],
+ ],
+ ],
+ 'secondaryauth' => [],
+ ];
+ $wgAuth = $wgDisableAuthManager ? new AuthPlugin : new MediaWiki\Auth\AuthManagerAuthPlugin();
+
// Bug 44192 Do not attempt to send a real e-mail
Hooks::clear( 'AlternateUserMailer' );
Hooks::register(
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTestSize="true"
- verbose="true">
+ verbose="false">
<testsuites>
<testsuite name="includes">
<directory>includes</directory>
// TODO: verify checkboxes == [ 'nsassociated', 'nsinvert' ]
QUnit.test( '"all" namespace disable checkboxes', 8, function ( assert ) {
- var selectHtml, $env, $options;
+ var selectHtml, $env, $options,
+ rc = require( 'mediawiki.special.recentchanges' );
// from Special:Recentchanges
selectHtml = '<select id="namespace" name="namespace" class="namespaceselector">'
assert.strictEqual( $( '#nsassociated' ).prop( 'disabled' ), false );
// Initiate the recentchanges module
- mw.special.recentchanges.init();
+ rc.init();
// By default
assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), true );
} );
// HTML in wikitext
- QUnit.test( 'HTML', 32, function ( assert ) {
+ QUnit.test( 'HTML', 33, function ( assert ) {
mw.messages.set( 'jquerymsg-italics-msg', '<i>Very</i> important' );
assertBothModes( assert, [ 'jquerymsg-italics-msg' ], mw.messages.get( 'jquerymsg-italics-msg' ), 'Simple italics unchanged' );
'Self-closing tags don\'t cause a parse error'
);
+ mw.messages.set( 'jquerymsg-asciialphabetliteral-regression', '<b >>>="dir">asd</b>' );
+ assert.htmlEqual(
+ formatParse( 'jquerymsg-asciialphabetliteral-regression' ),
+ '<b>>>="dir">asd</b>',
+ 'Regression test for bad "asciiAlphabetLiteral" definition'
+ );
+
mw.messages.set( 'jquerymsg-entities1', 'A&B' );
mw.messages.set( 'jquerymsg-entities2', 'A>B' );
mw.messages.set( 'jquerymsg-entities3', 'A→B' );
);
} );
+ QUnit.test( 'Nowiki', 3, function ( assert ) {
+ mw.messages.set( 'jquerymsg-nowiki-link', 'Foo <nowiki>[[bar]]</nowiki> baz.' );
+ assert.equal(
+ formatParse( 'jquerymsg-nowiki-link' ),
+ 'Foo [[bar]] baz.',
+ 'Link inside nowiki is not parsed'
+ );
+
+ mw.messages.set( 'jquerymsg-nowiki-htmltag', 'Foo <nowiki><b>bar</b></nowiki> baz.' );
+ assert.equal(
+ formatParse( 'jquerymsg-nowiki-htmltag' ),
+ 'Foo <b>bar</b> baz.',
+ 'HTML inside nowiki is not parsed and escaped'
+ );
+
+ mw.messages.set( 'jquerymsg-nowiki-template', 'Foo <nowiki>{{bar}}</nowiki> baz.' );
+ assert.equal(
+ formatParse( 'jquerymsg-nowiki-template' ),
+ 'Foo {{bar}} baz.',
+ 'Template inside nowiki is not parsed and does not cause a parse error'
+ );
+ } );
+
QUnit.test( 'Behavior in case of invalid wikitext', 3, function ( assert ) {
mw.messages.set( 'invalid-wikitext', '<b>{{FAIL}}</b>' );