Merge "Make sure that SQLite uses no prefix"
authorNikerabbit <niklas.laxstrom@gmail.com>
Sun, 11 Nov 2012 08:14:35 +0000 (08:14 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sun, 11 Nov 2012 08:14:35 +0000 (08:14 +0000)
220 files changed:
.gitignore
.jshintignore
.jshintrc
RELEASE-NOTES-1.20
RELEASE-NOTES-1.21
docs/hooks.txt
img_auth.php
includes/Article.php
includes/AutoLoader.php
includes/Category.php
includes/CategoryViewer.php
includes/Categoryfinder.php
includes/DefaultSettings.php
includes/EditPage.php
includes/GlobalFunctions.php
includes/RecentChange.php
includes/Revision.php
includes/SpecialPage.php
includes/Title.php
includes/User.php
includes/WikiPage.php
includes/api/ApiQueryRevisions.php
includes/api/ApiQueryUsers.php
includes/content/AbstractContent.php
includes/content/Content.php
includes/content/ContentHandler.php
includes/content/TextContent.php
includes/context/RequestContext.php
includes/db/ORMRow.php
includes/diff/DifferenceEngine.php
includes/filebackend/FSFileBackend.php
includes/filebackend/FileBackend.php
includes/filebackend/FileBackendMultiWrite.php
includes/filebackend/FileBackendStore.php
includes/filebackend/SwiftFileBackend.php
includes/filebackend/filejournal/DBFileJournal.php
includes/filerepo/FileRepo.php
includes/filerepo/file/ArchivedFile.php
includes/filerepo/file/File.php
includes/installer/Installer.i18n.php
includes/job/JobQueue.php
includes/job/JobQueueDB.php
includes/job/JobQueueGroup.php
includes/job/jobs/DoubleRedirectJob.php
includes/job/jobs/RefreshLinksJob.php
includes/objectcache/MemcachedPeclBagOStuff.php
includes/parser/Parser.php
includes/resourceloader/ResourceLoaderWikiModule.php
includes/search/SearchEngine.php
includes/site/SitesTable.php
includes/specials/SpecialChangePassword.php
includes/specials/SpecialListusers.php
includes/specials/SpecialMovepage.php
includes/specials/SpecialRecentchanges.php
includes/specials/SpecialRecentchangeslinked.php
includes/specials/SpecialSearch.php
includes/specials/SpecialSpecialpages.php
includes/specials/SpecialWatchlist.php
languages/classes/LanguageHe.php
languages/messages/MessagesAst.php
languages/messages/MessagesAz.php
languages/messages/MessagesBa.php
languages/messages/MessagesBar.php
languages/messages/MessagesBcl.php
languages/messages/MessagesBe_tarask.php
languages/messages/MessagesBn.php
languages/messages/MessagesBr.php
languages/messages/MessagesCa.php
languages/messages/MessagesCs.php
languages/messages/MessagesCy.php
languages/messages/MessagesDa.php
languages/messages/MessagesDe.php
languages/messages/MessagesDiq.php
languages/messages/MessagesDsb.php
languages/messages/MessagesEn.php
languages/messages/MessagesEs.php
languages/messages/MessagesFa.php
languages/messages/MessagesFi.php
languages/messages/MessagesFr.php
languages/messages/MessagesGl.php
languages/messages/MessagesGsw.php
languages/messages/MessagesHe.php
languages/messages/MessagesHsb.php
languages/messages/MessagesHu.php
languages/messages/MessagesHy.php
languages/messages/MessagesIa.php
languages/messages/MessagesIlo.php
languages/messages/MessagesIt.php
languages/messages/MessagesJa.php
languages/messages/MessagesKa.php
languages/messages/MessagesKiu.php
languages/messages/MessagesKo.php
languages/messages/MessagesKrc.php
languages/messages/MessagesKsh.php
languages/messages/MessagesKu_latn.php
languages/messages/MessagesKy.php
languages/messages/MessagesLa.php
languages/messages/MessagesLb.php
languages/messages/MessagesMg.php
languages/messages/MessagesMk.php
languages/messages/MessagesMl.php
languages/messages/MessagesMs.php
languages/messages/MessagesNb.php
languages/messages/MessagesNl.php
languages/messages/MessagesNn.php
languages/messages/MessagesPcd.php
languages/messages/MessagesPdc.php
languages/messages/MessagesPl.php
languages/messages/MessagesPms.php
languages/messages/MessagesPt.php
languages/messages/MessagesPt_br.php
languages/messages/MessagesQqq.php
languages/messages/MessagesRo.php
languages/messages/MessagesRu.php
languages/messages/MessagesSah.php
languages/messages/MessagesSk.php
languages/messages/MessagesSl.php
languages/messages/MessagesSv.php
languages/messages/MessagesSw.php
languages/messages/MessagesTa.php
languages/messages/MessagesTe.php
languages/messages/MessagesTet.php
languages/messages/MessagesTl.php
languages/messages/MessagesTr.php
languages/messages/MessagesTyv.php
languages/messages/MessagesUk.php
languages/messages/MessagesUz.php
languages/messages/MessagesVi.php
languages/messages/MessagesYi.php
languages/messages/MessagesZh_hans.php
languages/messages/MessagesZh_hant.php
maintenance/checkAutoLoader.php [deleted file]
maintenance/nextJobDB.php
resources/jquery/jquery.badge.css
resources/jquery/jquery.badge.js
resources/jquery/jquery.checkboxShiftClick.js
resources/jquery/jquery.client.js
resources/jquery/jquery.collapsibleTabs.js
resources/jquery/jquery.colorUtil.js
resources/jquery/jquery.expandableField.js
resources/jquery/jquery.hidpi.js
resources/jquery/jquery.highlightText.js
resources/jquery/jquery.mw-jump.js
resources/jquery/jquery.mwExtension.js
resources/jquery/jquery.qunit.completenessTest.js
resources/jquery/jquery.suggestions.js
resources/jquery/jquery.textSelection.js
resources/mediawiki.action/mediawiki.action.edit.js
resources/mediawiki.action/mediawiki.action.history.diff.css
resources/mediawiki.language/mediawiki.cldr.js
resources/mediawiki.language/mediawiki.language.init.js
resources/mediawiki.language/mediawiki.language.js
resources/mediawiki.page/mediawiki.page.ready.js
resources/mediawiki.page/mediawiki.page.watch.ajax.js
resources/mediawiki.special/mediawiki.special.block.js
resources/mediawiki.special/mediawiki.special.javaScriptTest.js
resources/mediawiki.special/mediawiki.special.js
resources/mediawiki.special/mediawiki.special.movePage.js
resources/mediawiki.special/mediawiki.special.preferences.js
resources/mediawiki.special/mediawiki.special.recentchanges.js
resources/mediawiki.special/mediawiki.special.search.js
resources/mediawiki.special/mediawiki.special.undelete.js
resources/mediawiki.special/mediawiki.special.upload.js
resources/mediawiki/mediawiki.Title.js
resources/mediawiki/mediawiki.feedback.js
resources/mediawiki/mediawiki.hidpi.js
resources/mediawiki/mediawiki.htmlform.js
resources/mediawiki/mediawiki.jqueryMsg.js
resources/mediawiki/mediawiki.js
resources/mediawiki/mediawiki.notification.js
resources/mediawiki/mediawiki.util.js
resources/startup.js
skins/Vector.php
tests/TestsAutoLoader.php
tests/parser/parserTests.txt
tests/phpunit/AutoLoaderTest.php [new file with mode: 0644]
tests/phpunit/includes/EditPageTest.php
tests/phpunit/includes/GlobalFunctions/GlobalTest.php
tests/phpunit/includes/RequestContextTest.php [new file with mode: 0644]
tests/phpunit/includes/RevisionStorageTest.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/UserTest.php
tests/phpunit/includes/content/TextContentTest.php
tests/phpunit/includes/db/ORMRowTest.php
tests/phpunit/includes/db/ORMTableTest.php [new file with mode: 0644]
tests/phpunit/includes/db/TestORMRowTest.php
tests/phpunit/includes/filebackend/FileBackendTest.php
tests/phpunit/includes/parser/TagHooksTest.php
tests/phpunit/includes/site/SiteObjectTest.php
tests/phpunit/languages/LanguageHeTest.php
tests/qunit/data/callMwLoaderTestCallback.js
tests/qunit/data/generateJqueryMsgData.php
tests/qunit/data/mediawiki.jqueryMsg.data.js
tests/qunit/data/testrunner.js
tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js
tests/qunit/suites/resources/jquery/jquery.byteLength.test.js
tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js
tests/qunit/suites/resources/jquery/jquery.client.test.js
tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js
tests/qunit/suites/resources/jquery/jquery.delayedBind.test.js
tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js
tests/qunit/suites/resources/jquery/jquery.hidpi.test.js
tests/qunit/suites/resources/jquery/jquery.highlightText.test.js
tests/qunit/suites/resources/jquery/jquery.localize.test.js
tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js
tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js
tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js
tests/qunit/suites/resources/jquery/jquery.textSelection.test.js
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.parse.test.js
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js
tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.cldr.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js
thumb.php

index 7f1ac5e..a47a454 100644 (file)
@@ -31,6 +31,9 @@ AdminSettings.php
 LocalSettings.php
 StartProfiler.php
 
+# Building & testing
+node_modules/
+
 # Operating systems
 ## Mac OS X
 .DS_Store
index 026eaaa..3869deb 100644 (file)
@@ -1,4 +1,6 @@
-# upstream libs
+# third-party libs
+extensions/
+node_modules/
 resources/jquery/jquery.appear.js
 resources/jquery/jquery.async.js
 resources/jquery/jquery.cycle.all.js
@@ -13,9 +15,13 @@ resources/jquery/jquery.mockjax.js
 resources/jquery/jquery.qunit.js
 resources/jquery/jquery.validate.js
 resources/jquery/jquery.xmldom.js
-resources/jquery.effects
-resources/jquery.tipsy
-resources/jquery.ui
-resources/mediawiki.libs
-tests/jasmine/lib/jasmine-1.0.1/jasmine-html.js
-tests/jasmine/lib/jasmine-1.0.1/jasmine.js
+resources/jquery.effects/
+resources/jquery.tipsy/
+resources/jquery.ui/
+resources/mediawiki.libs/
+
+# legacy scripts
+skins/common/
+
+# github.com/jshint/jshint/issues/729
+tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js
index b86ceb5..7fa138d 100644 (file)
--- a/.jshintrc
+++ b/.jshintrc
@@ -1,20 +1,25 @@
 {
        "predef": [
                "mediaWiki",
+               "jQuery",
                "QUnit"
        ],
 
        "bitwise": true,
+       "camelcase": true,
        "curly": true,
        "eqeqeq": true,
+       "forin": false,
        "immed": true,
        "latedef": true,
        "newcap": true,
        "noarg": true,
        "noempty": true,
        "nonew": true,
+       "quotmark": "single",
        "regexp": false,
        "undef": true,
+       "unused": true,
        "strict": false,
        "trailing": true,
 
@@ -23,7 +28,6 @@
        "multistr": true,
 
        "browser": true,
-       "jquery": true,
 
        "nomen": true,
        "onevar": true
index 52c4e86..1a92968 100644 (file)
@@ -5,10 +5,7 @@ setting since version 1.2.0. If you have it on, turn it '''off''' if you can.
 
 == MediaWiki 1.20 ==
 
-THIS IS NOT A RELEASE YET
-
-MediaWiki 1.20 is an alpha-quality branch and is not recommended for use in
-production.
+MediaWiki 1.20 is a stable release.
 
 === PHP 5.3 now required ===
 Since 1.20, the lowest supported version of PHP is now 5.3.2. Please
@@ -152,7 +149,32 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
 * (bug 40448) mediawiki.legacy.mwsuggest has been replaced with a new module,
   mediawiki.searchSuggest, based on SimpleSeach from Extension:Vector.
 
+=== Known issues in 1.20.0 ===
+These are issues that we're targeting to be fixed in a later release
+in the 1.20 series.  Issues may be added or removed from this list as
+we see fit.  For now, it is comprised of those bugs on the 1.20.0
+milestone in Bugzilla.
+
+* (bug 35894): Reports of secret key generation "hanging" on windows
+    This is probably a bug that has been fixed in PHP.  If you run
+    into this, try upgrading your PHP.
+* (bug 38334): PHP Notice:  Undefined index: href in /www/w/skins/Vector.php on line 416
+    We think this is a problem in some extension.  If you see this,
+    try disabling your extensions and check out the logging patch on
+    this bug.  Or try this patch:
+    <https://gerrit.wikimedia.org/r/#/c/27937/1/skins/Vector.php>
+* (bug 39268): [Regression] Toolbar inserts in main textarea only (instead of the focussed textarea)
+    This should only be an issue if you are using the ProofreadPage
+    extension.
+* (bug 40641): Clicking "others" in Special:Version asks to download a file
+    If you encounter this, you can tell your webserver to serve the
+    CREDITS file with text/plain MIME type to fix it.
+
 === Bug fixes in 1.20 ===
+* (bug 40939): [Regression] InfoAction: Call to a member function getUserText() on a non-object
+* (bug 40780): searchsuggest-containing line ("containing...") doesn't include the entered text
+* (bug 37714): [Regression] Incomplete log entries
+* (bug 27202): API: Add timestamp sort to list=allimages
 * (bug 30245) Use the correct way to construct a log page title.
 * (bug 34237) Regenerate an empty user_token and save to the database
   when we try to set the user's cookies for login.
index ce6966e..b9b026c 100644 (file)
@@ -58,6 +58,9 @@ production.
   caught during API execution.
 * (bug 37963) Fixed loading process for user options
 * (bug 26995) Update filename field on Upload page after having sanitized it.
+* (bug 41793) Contribution links to users with 0 edits on Special:ListUsers didn't
+  show up red.
+* (bug 41899) A PHP notice no longer occurs when using the "rvcontinue" API parameter.
 
 === API changes in 1.21 ===
 * prop=revisions can now report the contentmodel and contentformat, see docs/contenthandler.txt
index 998523f..67b4580 100644 (file)
@@ -752,6 +752,16 @@ cointent model name, but no entry for that model exists in $wgContentHandlers.
 $modeName: the requested content model name
 &$handler: set this to a ContentHandler object, if desired.
 
+'ConvertContent': Called by AbstractContent::convert when a conversion to another
+content model is requested.
+$content: The Content object to be converted.
+$toModel: The ID of the content model to convert to.
+$lossy:   boolean indicating whether lossy conversion is allowed.
+&$result: Output parameter, in case the handler function wants to provide a
+converted Content object. Note that $result->getContentModel() must return $toModel.
+Handler functions that modify $result should generally return false to further
+attempts at conversion.
+
 'ContribsPager::getQueryInfo': Before the contributions query is about to run
 &$pager: Pager object for contributions
 &$queryInfo: The query for the contribs Pager
@@ -1831,6 +1841,21 @@ $result: The search result
 $terms: The search terms entered
 $page: The SpecialSearch object.
 
+'ShowSearchHit': Customize display of search hit.
+$searchPage: The SpecialSearch instance.
+$result: The SearchResult to show
+$terms: Search terms, for highlighting
+&$link: HTML of link to the matching page. May be modified.
+&$redirect: HTML of redirect info. May be modified.
+&$section: HTML of matching section. May be modified.
+&$extract: HTML of content extract. May be modified.
+&$score: HTML of score. May be modified.
+&$size: HTML of page size. May be modified.
+&$date: HTML of of page modification date. May be modified.
+&$related: HTML of additional info for the matching page. May be modified.
+&$html: May be set to the full HTML that should be used to represent the search hit. Must include
+the <li> ... </li> tags. Will only be used if the hook function returned false.
+
 'SiteNoticeBefore': Before the sitenotice/anonnotice is composed
 &$siteNotice: HTML returned as the sitenotice
 $skin: Skin object
@@ -2110,7 +2135,7 @@ $result: Boolean; whether MediaWiki currently thinks this is a CSS/JS page. Hook
 Allows overriding default behaviour for determining if a page exists.
 If $isKnown is kept as null, regular checks happen. If it's a boolean, this value is returned by the isKnown method.
 $title: Title object that is being checked
-$result: Boolean|null; whether MediaWiki currently thinks this page is known
+&$isKnown: Boolean|null; whether MediaWiki currently thinks this page is known
 
 'TitleIsMovable': Called when determining if it is possible to move a page.
 Note that this hook is not called for interwiki pages or pages in immovable namespaces: for these, isMovable() always returns false.
index b3a3495..b04974b 100644 (file)
@@ -48,7 +48,7 @@ if ( isset( $_SERVER['MW_COMPILED'] ) ) {
 wfProfileIn( 'img_auth.php' );
 
 # Set action base paths so that WebRequest::getPathInfo()
-# recognizes the "X" as the 'title' in ../image_auth/X urls.
+# recognizes the "X" as the 'title' in ../img_auth.php/X urls.
 $wgArticlePath = false; # Don't let a "/*" article path clober our action path
 $wgActionPaths = array( "$wgUploadPath/" );
 
index 0eb0c68..169dd03 100644 (file)
@@ -688,7 +688,7 @@ class Article extends Page {
                                                $outputDone = true;
                                        } else {
                                                $content = $this->getContentObject();
-                                               $rt = $content->getRedirectChain();
+                                               $rt = $content ? $content->getRedirectChain() : null;
                                                if ( $rt ) {
                                                        wfDebug( __METHOD__ . ": showing redirect=no page\n" );
                                                        # Viewing a redirect page (e.g. with parameter redirect=no)
@@ -704,9 +704,8 @@ class Article extends Page {
                                        # Run the parse, protected by a pool counter
                                        wfDebug( __METHOD__ . ": doing uncached parse\n" );
 
-                                       // @todo: shouldn't we be passing $this->getPage() to PoolWorkArticleView instead of plain $this?
-                                       $poolArticleView = new PoolWorkArticleView( $this, $parserOptions,
-                                               $this->getRevIdFetched(), $useParserCache, $this->getContentObject(), $this->getContext() );
+                                       $poolArticleView = new PoolWorkArticleView( $this->getPage(), $parserOptions,
+                                               $this->getRevIdFetched(), $useParserCache, $this->getContentObject() );
 
                                        if ( !$poolArticleView->execute() ) {
                                                $error = $poolArticleView->getError();
@@ -842,10 +841,14 @@ class Article extends Page {
                                'clearyourcache' );
                }
 
-               // Give hooks a chance to customise the output
-               if ( ContentHandler::runLegacyHooks( 'ShowRawCssJs', array( $this->fetchContentObject(), $this->getTitle(), $outputPage ) ) ) {
-                       $po = $this->mContentObject->getParserOutput( $this->getTitle() );
-                       $outputPage->addHTML( $po->getText() );
+               $this->fetchContentObject();
+
+               if ( $this->mContentObject ) {
+                       // Give hooks a chance to customise the output
+                       if ( ContentHandler::runLegacyHooks( 'ShowRawCssJs', array( $this->mContentObject, $this->getTitle(), $outputPage ) ) ) {
+                               $po = $this->mContentObject->getParserOutput( $this->getTitle() );
+                               $outputPage->addHTML( $po->getText() );
+                       }
                }
        }
 
index dcaaf5a..a49d901 100644 (file)
@@ -152,6 +152,7 @@ $wgAutoloadLocalClasses = array(
        'IndexPager' => 'includes/Pager.php',
        'Interwiki' => 'includes/interwiki/Interwiki.php',
        'IP' => 'includes/IP.php',
+       'LCStore' => 'includes/LocalisationCache.php',
        'LCStore_Accel' => 'includes/LocalisationCache.php',
        'LCStore_CDB' => 'includes/LocalisationCache.php',
        'LCStore_DB' => 'includes/LocalisationCache.php',
@@ -204,6 +205,7 @@ $wgAutoloadLocalClasses = array(
        'RdfMetaData' => 'includes/Metadata.php',
        'ReadOnlyError' => 'includes/Exception.php',
        'RecentChange' => 'includes/RecentChange.php',
+       'RedirectSpecialArticle' => 'includes/SpecialPage.php',
        'RedirectSpecialPage' => 'includes/SpecialPage.php',
        'RegexlikeReplacer' => 'includes/StringUtils.php',
        'ReplacementArray' => 'includes/StringUtils.php',
@@ -577,7 +579,6 @@ $wgAutoloadLocalClasses = array(
        'CopyFileOp' => 'includes/filebackend/FileOp.php',
        'MoveFileOp' => 'includes/filebackend/FileOp.php',
        'DeleteFileOp' => 'includes/filebackend/FileOp.php',
-       'ConcatenateFileOp' => 'includes/filebackend/FileOp.php',
        'CreateFileOp' => 'includes/filebackend/FileOp.php',
        'NullFileOp' => 'includes/filebackend/FileOp.php',
 
@@ -613,7 +614,6 @@ $wgAutoloadLocalClasses = array(
        'Ibm_db2Updater' => 'includes/installer/Ibm_db2Updater.php',
        'InstallDocFormatter' => 'includes/installer/InstallDocFormatter.php',
        'Installer' => 'includes/installer/Installer.php',
-       'LBFactory_InstallerFake' => 'includes/installer/Installer.php',
        'LocalSettingsGenerator' => 'includes/installer/LocalSettingsGenerator.php',
        'MysqlInstaller' => 'includes/installer/MysqlInstaller.php',
        'MysqlUpdater' => 'includes/installer/MysqlUpdater.php',
@@ -850,7 +850,6 @@ $wgAutoloadLocalClasses = array(
        'RevDel_LogList' => 'includes/revisiondelete/RevisionDelete.php',
        'RevDel_RevisionItem' => 'includes/revisiondelete/RevisionDelete.php',
        'RevDel_RevisionList' => 'includes/revisiondelete/RevisionDelete.php',
-       'RevisionDelete' => 'includes/revisiondelete/RevisionDelete.php',
        'RevisionDeleter' => 'includes/revisiondelete/RevisionDeleter.php',
        'RevisionDeleteUser' => 'includes/revisiondelete/RevisionDeleteUser.php',
 
@@ -894,8 +893,6 @@ $wgAutoloadLocalClasses = array(
        'BrokenRedirectsPage' => 'includes/specials/SpecialBrokenRedirects.php',
        'CategoryPager' => 'includes/specials/SpecialCategories.php',
        'ContribsPager' => 'includes/specials/SpecialContributions.php',
-       'DBLockForm' => 'includes/specials/SpecialLockdb.php',
-       'DBUnlockForm' => 'includes/specials/SpecialUnlockdb.php',
        'DeadendPagesPage' => 'includes/specials/SpecialDeadendpages.php',
        'DeletedContribsPager' => 'includes/specials/SpecialDeletedContributions.php',
        'DeletedContributionsPage' => 'includes/specials/SpecialDeletedContributions.php',
@@ -960,7 +957,6 @@ $wgAutoloadLocalClasses = array(
        'SpecialLockdb' => 'includes/specials/SpecialLockdb.php',
        'SpecialLog' => 'includes/specials/SpecialLog.php',
        'SpecialMergeHistory' => 'includes/specials/SpecialMergeHistory.php',
-       'SpecialMostlinkedtemplates' => 'includes/specials/SpecialMostlinkedtemplates.php',
        'SpecialNewFiles' => 'includes/specials/SpecialNewimages.php',
        'SpecialNewpages' => 'includes/specials/SpecialNewpages.php',
        'SpecialPasswordReset' => 'includes/specials/SpecialPasswordReset.php',
@@ -1020,7 +1016,6 @@ $wgAutoloadLocalClasses = array(
        'UploadFromUrl' => 'includes/upload/UploadFromUrl.php',
        'UploadStash' => 'includes/upload/UploadStash.php',
        'UploadStashBadPathException' => 'includes/upload/UploadStash.php',
-       'UploadStashBadVersionException' => 'includes/upload/UploadStash.php',
        'UploadStashFile' => 'includes/upload/UploadStash.php',
        'UploadStashFileException' => 'includes/upload/UploadStash.php',
        'UploadStashFileNotFoundException' => 'includes/upload/UploadStash.php',
@@ -1044,14 +1039,17 @@ $wgAutoloadLocalClasses = array(
        'CLDRPluralRuleError' => 'languages/utils/CLDRPluralRuleEvaluator.php',
 
        # maintenance
+       'BackupDumper' => 'maintenance/backup.inc',
        'ConvertLinks' => 'maintenance/convertLinks.php',
        'DeleteArchivedFilesImplementation' => 'maintenance/deleteArchivedFiles.inc',
        'DeleteArchivedRevisionsImplementation' => 'maintenance/deleteArchivedRevisions.inc',
        'DeleteDefaultMessages' => 'maintenance/deleteDefaultMessages.php',
+       'DumpDBZip2Output' => 'maintenance/backup.inc',
+       'ExportProgressFilter' => 'maintenance/backup.inc',
        'FakeMaintenance' => 'maintenance/Maintenance.php',
+       'FixExtLinksProtocolRelative' => 'maintenance/fixExtLinksProtocolRelative.php',
        'LoggedUpdateMaintenance' => 'maintenance/Maintenance.php',
        'Maintenance' => 'maintenance/Maintenance.php',
-       'FixExtLinksProtocolRelative' => 'maintenance/fixExtLinksProtocolRelative.php',
        'PopulateCategory' => 'maintenance/populateCategory.php',
        'PopulateImageSha1' => 'maintenance/populateImageSha1.php',
        'PopulateFilearchiveSha1' => 'maintenance/populateFilearchiveSha1.php',
@@ -1084,47 +1082,6 @@ $wgAutoloadLocalClasses = array(
        'InstallerOverrides' => 'mw-config/overrides.php',
        'MyLocalSettingsGenerator' => 'mw-config/overrides.php',
 
-       # tests
-       'DbTestPreviewer' => 'tests/testHelpers.inc',
-       'DbTestRecorder' => 'tests/testHelpers.inc',
-       'DelayedParserTest' => 'tests/testHelpers.inc',
-       'TestFileIterator' => 'tests/testHelpers.inc',
-       'TestRecorder' => 'tests/testHelpers.inc',
-
-       # tests/phpunit
-       'RevisionStorageTest' => 'tests/phpunit/includes/RevisionStorageTest.php',
-       'WikiPageTest' => 'tests/phpunit/includes/WikiPageTest.php',
-
-       # tests/phpunit/content
-       'DummyContentHandlerForTesting' => 'tests/phpunit/includes/content/ContentHandlerTest.php',
-       'DummyContentForTesting' => 'tests/phpunit/includes/content/ContentHandlerTest.php',
-       'JavascriptContentTest' => 'tests/phpunit/includes/content/JavascriptContentTest.php',
-       'TextContentTest' => 'tests/phpunit/includes/content/TextContentTest.php',
-
-       # tests/phpunit/includes
-       'GenericArrayObjectTest' => 'tests/phpunit/includes/libs/GenericArrayObjectTest.php',
-
-       # tests/phpunit/includes/db
-       'ORMRowTest' => 'tests/phpunit/includes/db/ORMRowTest.php',
-
-       # tests/phpunit/includes/site
-       'SiteObjectTest' => 'tests/phpunit/includes/site/SiteObjectTest.php',
-       'TestSites' => 'tests/phpunit/includes/site/TestSites.php',
-
-       # tests/parser
-       'ParserTest' => 'tests/parser/parserTest.inc',
-       'ParserTestParserHook' => 'tests/parser/parserTestsParserHook.php',
-
-       # tests/selenium
-       'Selenium' => 'tests/selenium/Selenium.php',
-       'SeleniumLoader' => 'tests/selenium/SeleniumLoader.php',
-       'SeleniumTestCase' => 'tests/selenium/SeleniumTestCase.php',
-       'SeleniumTestConsoleLogger' => 'tests/selenium/SeleniumTestConsoleLogger.php',
-       'SeleniumTestHTMLLogger' => 'tests/selenium/SeleniumTestHTMLLogger.php',
-       'SeleniumTestListener' => 'tests/selenium/SeleniumTestListener.php',
-       'SeleniumTestSuite' => 'tests/selenium/SeleniumTestSuite.php',
-       'SeleniumConfig' => 'tests/selenium/SeleniumConfig.php',
-
        # skins
        'CologneBlueTemplate' => 'skins/CologneBlue.php',
        'ModernTemplate' => 'skins/Modern.php',
index ffd7bb8..6a5eac7 100644 (file)
@@ -58,6 +58,9 @@ class Category {
                        # Already initialized
                        return true;
                }
+
+               wfProfileIn( __METHOD__ );
+
                $dbr = wfGetDB( DB_SLAVE );
                $row = $dbr->selectRow(
                        'category',
@@ -66,6 +69,8 @@ class Category {
                        __METHOD__
                );
 
+               wfProfileOut( __METHOD__ );
+
                if ( !$row ) {
                        # Okay, there were no contents.  Nothing to initialize.
                        if ( $this->mTitle ) {
@@ -190,25 +195,37 @@ class Category {
        }
 
        /** @return mixed DB key name, or false on failure */
-       public function getName() { return $this->getX( 'mName' ); }
+       public function getName() {
+               return $this->getX( 'mName' );
+       }
 
        /** @return mixed Category ID, or false on failure */
-       public function getID() { return $this->getX( 'mID' ); }
+       public function getID() {
+               return $this->getX( 'mID' );
+       }
 
        /** @return mixed Total number of member pages, or false on failure */
-       public function getPageCount() { return $this->getX( 'mPages' ); }
+       public function getPageCount() {
+               return $this->getX( 'mPages' );
+       }
 
        /** @return mixed Number of subcategories, or false on failure */
-       public function getSubcatCount() { return $this->getX( 'mSubcats' ); }
+       public function getSubcatCount() {
+               return $this->getX( 'mSubcats' );
+       }
 
        /** @return mixed Number of member files, or false on failure */
-       public function getFileCount() { return $this->getX( 'mFiles' ); }
+       public function getFileCount() {
+               return $this->getX( 'mFiles' );
+       }
 
        /**
         * @return Title|bool Title for this category, or false on failure.
         */
        public function getTitle() {
-               if ( $this->mTitle ) return $this->mTitle;
+               if ( $this->mTitle ) {
+                       return $this->mTitle;
+               }
 
                if ( !$this->initialize() ) {
                        return false;
@@ -226,20 +243,22 @@ class Category {
         * @return TitleArray object for category members.
         */
        public function getMembers( $limit = false, $offset = '' ) {
+               wfProfileIn( __METHOD__ );
+
                $dbr = wfGetDB( DB_SLAVE );
 
                $conds = array( 'cl_to' => $this->getName(), 'cl_from = page_id' );
                $options = array( 'ORDER BY' => 'cl_sortkey' );
 
                if ( $limit ) {
-                       $options[ 'LIMIT' ] = $limit;
+                       $options['LIMIT'] = $limit;
                }
 
                if ( $offset !== '' ) {
                        $conds[] = 'cl_sortkey > ' . $dbr->addQuotes( $offset );
                }
 
-               return TitleArray::newFromResult(
+               $result = TitleArray::newFromResult(
                        $dbr->select(
                                array( 'page', 'categorylinks' ),
                                array( 'page_id', 'page_namespace', 'page_title', 'page_len',
@@ -249,6 +268,10 @@ class Category {
                                $options
                        )
                );
+
+               wfProfileOut( __METHOD__ );
+
+               return $result;
        }
 
        /**
@@ -259,7 +282,7 @@ class Category {
                if ( !$this->initialize() ) {
                        return false;
                }
-               return $this-> { $key } ;
+               return $this->{$key};
        }
 
        /**
@@ -279,8 +302,10 @@ class Category {
                        }
                }
 
+               wfProfileIn( __METHOD__ );
+
                $dbw = wfGetDB( DB_MASTER );
-               $dbw->begin( __METHOD__  );
+               $dbw->begin( __METHOD__ );
 
                # Insert the row if it doesn't exist yet (e.g., this is being run via
                # update.php from a pre-1.16 schema).  TODO: This will cause lots and
@@ -303,8 +328,8 @@ class Category {
                $result = $dbw->selectRow(
                        array( 'categorylinks', 'page' ),
                        array( 'pages' => 'COUNT(*)',
-                                  'subcats' => "COUNT($cond1)",
-                                  'files' => "COUNT($cond2)"
+                               'subcats' => "COUNT($cond1)",
+                               'files' => "COUNT($cond2)"
                        ),
                        array( 'cl_to' => $this->mName, 'page_id = cl_from' ),
                        __METHOD__,
@@ -322,6 +347,8 @@ class Category {
                );
                $dbw->commit( __METHOD__ );
 
+               wfProfileOut( __METHOD__ );
+
                # Now we should update our local counts.
                $this->mPages   = $result->pages;
                $this->mSubcats = $result->subcats;
index 3d66b74..b59b4e1 100644 (file)
@@ -173,7 +173,7 @@ class CategoryViewer extends ContextSource {
 
        /**
         * Add a subcategory to the internal lists, using a title object
-        * @deprecated since 1.17 kept for compatibility, please use addSubcategoryObject instead
+        * @deprecated since 1.17 kept for compatibility, use addSubcategoryObject instead
         */
        function addSubcategory( Title $title, $sortkey, $pageLength ) {
                wfDeprecated( __METHOD__, '1.17' );
@@ -181,14 +181,14 @@ class CategoryViewer extends ContextSource {
        }
 
        /**
-       * Get the character to be used for sorting subcategories.
-       * If there's a link from Category:A to Category:B, the sortkey of the resulting
-       * entry in the categorylinks table is Category:A, not A, which it SHOULD be.
-       * Workaround: If sortkey == "Category:".$title, than use $title for sorting,
-       * else use sortkey...
-       *
-       * @param Title $title
-       * @param string $sortkey The human-readable sortkey (before transforming to icu or whatever).
+        * Get the character to be used for sorting subcategories.
+        * If there's a link from Category:A to Category:B, the sortkey of the resulting
+        * entry in the categorylinks table is Category:A, not A, which it SHOULD be.
+        * Workaround: If sortkey == "Category:".$title, than use $title for sorting,
+        * else use sortkey...
+        *
+        * @param Title $title
+        * @param string $sortkey The human-readable sortkey (before transforming to icu or whatever).
         * @return string
         */
        function getSubcategorySortChar( $title, $sortkey ) {
@@ -259,15 +259,15 @@ class CategoryViewer extends ContextSource {
 
        function finaliseCategoryState() {
                if ( $this->flip['subcat'] ) {
-                       $this->children            = array_reverse( $this->children );
+                       $this->children = array_reverse( $this->children );
                        $this->children_start_char = array_reverse( $this->children_start_char );
                }
                if ( $this->flip['page'] ) {
-                       $this->articles            = array_reverse( $this->articles );
+                       $this->articles = array_reverse( $this->articles );
                        $this->articles_start_char = array_reverse( $this->articles_start_char );
                }
                if ( !$this->showGallery && $this->flip['file'] ) {
-                       $this->imgsNoGallery            = array_reverse( $this->imgsNoGallery );
+                       $this->imgsNoGallery = array_reverse( $this->imgsNoGallery );
                        $this->imgsNoGallery_start_char = array_reverse( $this->imgsNoGallery_start_char );
                }
        }
@@ -302,7 +302,7 @@ class CategoryViewer extends ContextSource {
                                        'page_is_redirect', 'cl_sortkey', 'cat_id', 'cat_title',
                                        'cat_subcats', 'cat_pages', 'cat_files',
                                        'cl_sortkey_prefix', 'cl_collation' ),
-                               array_merge( array( 'cl_to' => $this->title->getDBkey() ),  $extraConds ),
+                               array_merge( array( 'cl_to' => $this->title->getDBkey() ), $extraConds ),
                                __METHOD__,
                                array(
                                        'USE INDEX' => array( 'categorylinks' => 'cl_sortkey' ),
@@ -310,7 +310,7 @@ class CategoryViewer extends ContextSource {
                                        'ORDER BY' => $this->flip[$type] ? 'cl_sortkey DESC' : 'cl_sortkey',
                                ),
                                array(
-                                       'categorylinks'  => array( 'INNER JOIN', 'cl_from = page_id' ),
+                                       'categorylinks' => array( 'INNER JOIN', 'cl_from = page_id' ),
                                        'category' => array( 'LEFT JOIN', 'cat_title = page_title AND page_namespace = ' . NS_CATEGORY )
                                )
                        );
@@ -469,7 +469,7 @@ class CategoryViewer extends ContextSource {
         */
        function formatList( $articles, $articles_start_char, $cutoff = 6 ) {
                $list = '';
-               if ( count ( $articles ) > $cutoff ) {
+               if ( count( $articles ) > $cutoff ) {
                        $list = self::columnList( $articles, $articles_start_char );
                } elseif ( count( $articles ) > 0 ) {
                        // for short lists of articles in categories.
@@ -478,7 +478,7 @@ class CategoryViewer extends ContextSource {
 
                $pageLang = $this->title->getPageLanguage();
                $attribs = array( 'lang' => $pageLang->getCode(), 'dir' => $pageLang->getDir(),
-                       'class' => 'mw-content-'.$pageLang->getDir() );
+                       'class' => 'mw-content-' . $pageLang->getDir() );
                $list = Html::rawElement( 'div', $attribs, $list );
 
                return $list;
@@ -604,7 +604,7 @@ class CategoryViewer extends ContextSource {
                        );
                }
 
-               return $this->msg('categoryviewer-pagedlinks')->rawParams($prevLink, $nextLink)->escaped();
+               return $this->msg( 'categoryviewer-pagedlinks' )->rawParams( $prevLink, $nextLink )->escaped();
        }
 
        /**
@@ -635,6 +635,7 @@ class CategoryViewer extends ContextSource {
                return Title::makeTitle( $title->getNamespace(),
                        $title->getDBkey(), $fragment );
        }
+
        /**
         * What to do if the category table conflicts with the number of results
         * returned?  This function says what. Each type is considered independently
@@ -676,8 +677,9 @@ class CategoryViewer extends ContextSource {
                        $fromOrUntil = true;
                }
 
-               if ( $dbcnt == $rescnt || ( ( $rescnt == $this->limit || $fromOrUntil )
-                       && $dbcnt > $rescnt ) ) {
+               if ( $dbcnt == $rescnt ||
+                       ( ( $rescnt == $this->limit || $fromOrUntil ) && $dbcnt > $rescnt )
+               ) {
                        # Case 1: seems sane.
                        $totalcnt = $dbcnt;
                } elseif ( $rescnt < $this->limit && !$fromOrUntil ) {
index e2b6a0c..589950f 100644 (file)
  *
  * Example use :
  * <code>
- *     # Determines whether the article with the page_id 12345 is in both
- *     # "Category 1" and "Category 2" or their subcategories, respectively
+ *     # Determines whether the article with the page_id 12345 is in both
+ *     # "Category 1" and "Category 2" or their subcategories, respectively
  *
- *     $cf = new Categoryfinder;
- *     $cf->seed(
- *             array( 12345 ),
- *             array( 'Category 1', 'Category 2' ),
- *             'AND'
- *     );
- *     $a = $cf->run();
- *     print implode( ',' , $a );
+ *     $cf = new Categoryfinder;
+ *     $cf->seed(
+ *         array( 12345 ),
+ *         array( 'Category 1', 'Category 2' ),
+ *         'AND'
+ *     );
+ *     $a = $cf->run();
+ *     print implode( ',' , $a );
  * </code>
  *
  */
@@ -135,7 +135,7 @@ class Categoryfinder {
 
                # iterate through the parents
                foreach ( $this->parents[$id] as $p ) {
-                       $pname = $p->cl_to ;
+                       $pname = $p->cl_to;
 
                        # Is this a condition?
                        if ( isset( $conds[$pname] ) ) {
@@ -172,6 +172,8 @@ class Categoryfinder {
         * Scans a "parent layer" of the articles/categories in $this->next
         */
        function scan_next_layer() {
+               wfProfileIn( __METHOD__ );
+
                # Find all parents of the article currently in $this->next
                $layer = array();
                $res = $this->dbr->select(
@@ -225,6 +227,7 @@ class Categoryfinder {
                foreach ( $layer as $v ) {
                        $this->deadend[$v] = $v;
                }
-       }
 
+               wfProfileOut( __METHOD__ );
+       }
 }
index 16cae7d..494b2a3 100644 (file)
@@ -361,7 +361,9 @@ $wgImgAuthPublicTest = true;
  *                          container  : backend container name the zone is in
  *                          directory  : root path within container for the zone
  *                          url        : base URL to the root of the zone
- *                          handlerUrl : base script handled URL to the root of the zone
+ *                          urlsByExt  : map of file extension types to base URLs
+ *                                       (useful for using a different cache for videos)
+ *                          handlerUrl : base script-handled URL to the root of the zone
  *                                       (see FileRepo::getZoneHandlerUrl() function)
  *                      Zones default to using "<repo name>-<zone name>" as the container name
  *                      and default to using the container root as the zone's root directory.
@@ -2779,6 +2781,13 @@ $wgFooterIcons = array(
  */
 $wgUseCombinedLoginLink = false;
 
+/**
+ *  Appearance of user page and talk page labels in personal tools.
+ *  - true = combine links into a single label
+ *  - false = keep links in separate labels
+ */
+$wgVectorCombineUserTalk = false;
+
 /**
  * Search form look for Vector skin only.
  *  - true = use an icon search button
index 963b4af..21a100f 100644 (file)
@@ -1473,16 +1473,14 @@ class EditPage {
                                $this->isConflict = true;
                                $content = $textbox_content; // do not try to merge here!
                        } elseif ( $this->isConflict ) {
-                               $contentObj = $content;
                                # Attempt merge
-                               if ( $this->mergeChangesInto( $content ) ) {
+                               if ( $this->mergeChangesIntoContent( $content ) ) {
                                        // Successful merge! Maybe we should tell the user the good news?
                                        $this->isConflict = false;
-                                       $content = $this->toEditContent( $content );
                                        wfDebug( __METHOD__ . ": Suppressing edit conflict, successful merge.\n" );
                                } else {
                                        $this->section = '';
-                                       $this->textbox1 = ContentHandler::getContentText( $contentObj );
+                                       $this->textbox1 = ContentHandler::getContentText( $content );
                                        wfDebug( __METHOD__ . ": Keeping edit conflict, failed merge.\n" );
                                }
                        }
@@ -1666,37 +1664,15 @@ class EditPage {
        function mergeChangesInto( &$editText ){
                ContentHandler::deprecated( __METHOD__, "1.21" );
 
-               wfProfileIn( __METHOD__ );
-
-               $db = wfGetDB( DB_MASTER );
-
-               // This is the revision the editor started from
-               $baseRevision = $this->getBaseRevision();
-               if ( is_null( $baseRevision ) ) {
-                       wfProfileOut( __METHOD__ );
-                       return false;
-               }
-               $baseText = $baseRevision->getText();
-
-               // The current state, we want to merge updates into it
-               $currentRevision = Revision::loadFromTitle( $db, $this->mTitle );
-               if ( is_null( $currentRevision ) ) {
-                       wfProfileOut( __METHOD__ );
-                       return false;
-               }
-               $currentText = $currentRevision->getText();
+               $editContent = $this->toEditContent( $editText );
 
-               $result = '';
-               $editText = $this->toEditText( $editText );
+               $ok = $this->mergeChangesIntoContent( $editContent );
 
-               if ( wfMerge( $baseText, $editText, $currentText, $result ) ) {
-                       $editText = $result;
-                       wfProfileOut( __METHOD__ );
+               if ( $ok ) {
+                       $editText = $this->toEditText( $editContent );
                        return true;
-               } else {
-                       wfProfileOut( __METHOD__ );
-                       return false;
                }
+               return false;
        }
 
        /**
index 3de25e7..7dc9a70 100644 (file)
@@ -2895,11 +2895,15 @@ function wfMerge( $old, $mine, $yours, &$result ) {
        $mytextFile = fopen( $mytextName = tempnam( $td, 'merge-mine-' ), 'w' );
        $yourtextFile = fopen( $yourtextName = tempnam( $td, 'merge-your-' ), 'w' );
 
-       fwrite( $oldtextFile, $old );
+       # NOTE: diff3 issues a warning to stderr if any of the files does not end with
+       #       a newline character. To avoid this, we normalize the trailing whitespace before
+       #       creating the diff.
+
+       fwrite( $oldtextFile, rtrim( $old ) . "\n" );
        fclose( $oldtextFile );
-       fwrite( $mytextFile, $mine );
+       fwrite( $mytextFile, rtrim( $mine ) . "\n" );
        fclose( $mytextFile );
-       fwrite( $yourtextFile, $yours );
+       fwrite( $yourtextFile, rtrim( $yours ) . "\n" );
        fclose( $yourtextFile );
 
        # Check for a conflict
index 3cf6c72..2bdcab4 100644 (file)
@@ -125,7 +125,7 @@ class RecentChange {
         */
        public static function newFromConds( $conds, $fname = __METHOD__ ) {
                $dbr = wfGetDB( DB_SLAVE );
-               $row = $dbr->selectRow( 'recentchanges', '*', $conds, $fname );
+               $row = $dbr->selectRow( 'recentchanges', self::selectFields(), $conds, $fname );
                if ( $row !== false ) {
                        return self::newFromRow( $row );
                } else {
@@ -133,6 +133,40 @@ class RecentChange {
                }
        }
 
+       /**
+        * Return the list of recentchanges fields that should be selected to create
+        * a new recentchanges object.
+        * @return array
+        */
+       public static function selectFields() {
+               return array(
+                       'rc_id',
+                       'rc_timestamp',
+                       'rc_cur_time',
+                       'rc_user',
+                       'rc_user_text',
+                       'rc_namespace',
+                       'rc_title',
+                       'rc_comment',
+                       'rc_minor',
+                       'rc_bot',
+                       'rc_new',
+                       'rc_cur_id',
+                       'rc_this_oldid',
+                       'rc_last_oldid',
+                       'rc_type',
+                       'rc_patrolled',
+                       'rc_ip',
+                       'rc_old_len',
+                       'rc_new_len',
+                       'rc_deleted',
+                       'rc_logid',
+                       'rc_log_type',
+                       'rc_log_action',
+                       'rc_params',
+               );
+       }
+
        # Accessors
 
        /**
index d556edc..fd356e1 100644 (file)
@@ -52,7 +52,7 @@ class Revision implements IDBAccessObject {
        protected $mContentFormat;
 
        /**
-        * @var Content
+        * @var Content|null|bool
         */
        protected $mContent;
 
@@ -124,7 +124,7 @@ class Revision implements IDBAccessObject {
         * Returns null if no such revision can be found.
         *
         * $flags include:
-        *      Revision::READ_LATEST  : Select the data from the master
+        *      Revision::READ_LATEST  : Select the data from the master (since 1.20)
         *      Revision::READ_LOCKING : Select & lock the data from the master
         *
         * @param $revId Integer
@@ -982,27 +982,34 @@ class Revision implements IDBAccessObject {
        }
 
        /**
-        * Gets the content object for the revision
+        * Gets the content object for the revision (or null on failure).
+        *
+        * Note that for mutable Content objects, each call to this method will return a
+        * fresh clone.
         *
         * @since 1.21
-        * @return Content
+        * @return Content|null the Revision's content, or null on failure.
         */
        protected function getContentInternal() {
                if( is_null( $this->mContent ) ) {
                        // Revision is immutable. Load on demand:
-
-                       $handler = $this->getContentHandler();
-                       $format = $this->getContentFormat();
-
                        if( is_null( $this->mText ) ) {
-                               // Load text on demand:
                                $this->mText = $this->loadText();
                        }
 
-                       $this->mContent = is_null( $this->mText ) ? null : $handler->unserializeContent( $this->mText, $format );
+                       if ( $this->mText !== null && $this->mText !== false ) {
+                               // Unserialize content
+                               $handler = $this->getContentHandler();
+                               $format = $this->getContentFormat();
+
+                               $this->mContent = $handler->unserializeContent( $this->mText, $format );
+                       } else {
+                               $this->mContent = false; // negative caching!
+                       }
                }
 
-               return $this->mContent->copy(); // NOTE: copy() will return $this for immutable content objects
+               // NOTE: copy() will return $this for immutable content objects
+               return $this->mContent ? $this->mContent->copy() : null;
        }
 
        /**
@@ -1377,7 +1384,7 @@ class Revision implements IDBAccessObject {
 
                $content = $this->getContent( Revision::RAW );
 
-               if ( !$content->isValid() ) {
+               if ( !$content || !$content->isValid() ) {
                        $t = $title->getPrefixedDBkey();
 
                        throw new MWException( "Content of $t is not valid! Content model is $model" );
@@ -1397,7 +1404,11 @@ class Revision implements IDBAccessObject {
         * Lazy-load the revision's text.
         * Currently hardcoded to the 'text' table storage engine.
         *
-        * @return String
+<<<<<<< HEAD
+        * @return String|boolean the revision text, or false on failure
+=======
+        * @return String|bool the revision's text, or false on failure
+>>>>>>> (Bug 41244) Gracefully handle failure to load text blob.
         */
        protected function loadText() {
                wfProfileIn( __METHOD__ );
index 816831f..67aa2b3 100644 (file)
@@ -513,6 +513,19 @@ class SpecialPage {
                return false;
        }
 
+       /**
+        * Is this page cached?
+        * Expensive pages are cached or disabled in miser mode.
+        * Used by QueryPage and subclasses, moved here so that
+        * Special:SpecialPages can safely call it for all special pages.
+        *
+        * @return Boolean
+        * @since 1.21
+        */
+       public function isCached() {
+               return false;
+       }
+
        /**
         * Can be overridden by subclasses with more complicated permissions
         * schemes.
index c1e2ccf..0f02dc7 100644 (file)
@@ -3981,7 +3981,7 @@ class Title {
                $content = $rev->getContent();
                # Does the redirect point to the source?
                # Or is it a broken self-redirect, usually caused by namespace collisions?
-               $redirTitle = $content->getRedirectTarget();
+               $redirTitle = $content ? $content->getRedirectTarget() : null;
 
                if ( $redirTitle ) {
                        if ( $redirTitle->getPrefixedDBkey() != $this->getPrefixedDBkey() &&
index c0d71e4..0aa613a 100644 (file)
@@ -1102,10 +1102,10 @@ class User {
                }
 
                if ( is_array( $data ) ) {
-                       if ( is_array( $data['user_groups'] ) ) {
+                       if ( isset( $data['user_groups'] ) && is_array( $data['user_groups'] ) ) {
                                $this->mGroups = $data['user_groups'];
                        }
-                       if ( is_array( $data['user_properties'] ) ) {
+                       if ( isset( $data['user_properties'] ) && is_array( $data['user_properties'] ) ) {
                                $this->loadOptions( $data['user_properties'] );
                        }
                }
@@ -2357,7 +2357,7 @@ class User {
                        $this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() );
                        wfRunHooks( 'UserGetRights', array( $this, &$this->mRights ) );
                        // Force reindexation of rights when a hook has unset one of them
-                       $this->mRights = array_values( $this->mRights );
+                       $this->mRights = array_values( array_unique( $this->mRights ) );
                }
                return $this->mRights;
        }
@@ -2389,6 +2389,8 @@ class User {
                        ) );
                        # Hook for additional groups
                        wfRunHooks( 'UserEffectiveGroups', array( &$this, &$this->mEffectiveGroups ) );
+                       // Force reindexation of groups when a hook has unset one of them
+                       $this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) );
                        wfProfileOut( __METHOD__ );
                }
                return $this->mEffectiveGroups;
@@ -2469,7 +2471,7 @@ class User {
                                        $count = $this->initEditCount();
                                }
                                wfProfileOut( __METHOD__ );
-                               $this->mEditCount = $count;
+                               $this->mEditCount = intval( $count );
                        }
                        return $this->mEditCount;
                } else {
@@ -3979,7 +3981,7 @@ class User {
                // Pull from a slave to be less cruel to servers
                // Accuracy isn't the point anyway here
                $dbr = wfGetDB( DB_SLAVE );
-               $count = $dbr->selectField(
+               $count = (int) $dbr->selectField(
                        'revision',
                        'COUNT(rev_user)',
                        array( 'rev_user' => $this->getId() ),
index df3086a..a4bc6ee 100644 (file)
@@ -1237,8 +1237,8 @@ class WikiPage extends Page implements IDBAccessObject {
                wfProfileIn( __METHOD__ );
 
                $content = $revision->getContent();
-               $len = $content->getSize();
-               $rt = $content->getUltimateRedirectTarget();
+               $len = $content ? $content->getSize() : 0;
+               $rt = $content ? $content->getUltimateRedirectTarget() : null;
 
                $conditions = array( 'page_id' => $this->getId() );
 
@@ -1469,11 +1469,6 @@ class WikiPage extends Page implements IDBAccessObject {
                        // Bug 30711: always use current version when adding a new section
                        if ( is_null( $edittime ) || $section == 'new' ) {
                                $oldContent = $this->getContent();
-                               if ( ! $oldContent ) {
-                                       wfDebug( __METHOD__ . ": no page text\n" );
-                                       wfProfileOut( __METHOD__ );
-                                       return null;
-                               }
                        } else {
                                $dbw = wfGetDB( DB_MASTER );
                                $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime );
@@ -1488,6 +1483,13 @@ class WikiPage extends Page implements IDBAccessObject {
                                $oldContent = $rev->getContent();
                        }
 
+                       if ( ! $oldContent ) {
+                               wfDebug( __METHOD__ . ": no page text\n" );
+                               wfProfileOut( __METHOD__ );
+                               return null;
+                       }
+
+                       //FIXME: $oldContent might be null?
                        $newContent = $oldContent->replaceSection( $section, $sectionContent, $sectionTitle );
                }
 
@@ -1852,6 +1854,10 @@ class WikiPage extends Page implements IDBAccessObject {
                        # Bug 37225: use accessor to get the text as Revision may trim it
                        $content = $revision->getContent(); // sanity; get normalized version
 
+                       if ( $content ) {
+                               $newsize = $content->getSize();
+                       }
+
                        # Update the page record with revision data
                        $this->updateRevisionOn( $dbw, $revision, 0 );
 
@@ -1864,7 +1870,7 @@ class WikiPage extends Page implements IDBAccessObject {
                                        $this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) );
                                # Add RC row to the DB
                                $rc = RecentChange::notifyNew( $now, $this->mTitle, $isminor, $user, $summary, $bot,
-                                       '', $content->getSize(), $revisionId, $patrolled );
+                                       '', $newsize, $revisionId, $patrolled );
 
                                # Log auto-patrolled edits
                                if ( $patrolled ) {
@@ -1956,7 +1962,7 @@ class WikiPage extends Page implements IDBAccessObject {
         * @since 1.21
         */
        public function prepareContentForEdit( Content $content, $revid = null, User $user = null, $serialization_format = null ) {
-               global $wgParser, $wgContLang, $wgUser;
+               global $wgContLang, $wgUser;
                $user = is_null( $user ) ? $wgUser : $user;
                //XXX: check $user->getId() here???
 
@@ -1977,23 +1983,21 @@ class WikiPage extends Page implements IDBAccessObject {
                $edit = (object)array();
                $edit->revid = $revid;
 
-               $edit->pstContent = $content->preSaveTransform( $this->mTitle, $user, $popts );
-               $edit->pst = $edit->pstContent->serialize( $serialization_format ); #XXX: do we need this??
-               $edit->format = $serialization_format;
+               $edit->pstContent = $content ? $content->preSaveTransform( $this->mTitle, $user, $popts ) : null;
 
+               $edit->format = $serialization_format;
                $edit->popts = $this->makeParserOptions( 'canonical' );
-
-               $edit->output = $edit->pstContent->getParserOutput( $this->mTitle, $revid, $edit->popts );
+               $edit->output = $edit->pstContent ? $edit->pstContent->getParserOutput( $this->mTitle, $revid, $edit->popts ) : null;
 
                $edit->newContent = $content;
                $edit->oldContent = $this->getContent( Revision::RAW );
 
                #NOTE: B/C for hooks! don't use these fields!
-               $edit->newText = ContentHandler::getContentText( $edit->newContent );
+               $edit->newText = $edit->newContent ? ContentHandler::getContentText( $edit->newContent ) : '';
                $edit->oldText = $edit->oldContent ? ContentHandler::getContentText( $edit->oldContent ) : '';
+               $edit->pst = $edit->pstContent ? $edit->pstContent->serialize( $serialization_format ) : '';
 
                $this->mPreparedEdit = $edit;
-
                return $edit;
        }
 
@@ -2038,8 +2042,10 @@ class WikiPage extends Page implements IDBAccessObject {
                }
 
                # Update the links tables and other secondary data
-               $updates = $content->getSecondaryDataUpdates( $this->getTitle(), null, true, $editInfo->output );
-               DataUpdate::runUpdates( $updates );
+               if ( $content ) {
+                       $updates = $content->getSecondaryDataUpdates( $this->getTitle(), null, true, $editInfo->output );
+                       DataUpdate::runUpdates( $updates );
+               }
 
                wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
 
@@ -2111,7 +2117,7 @@ class WikiPage extends Page implements IDBAccessObject {
 
                if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
                        #XXX: could skip pseudo-messages like js/css here, based on content model.
-                       $msgtext = $content->getWikitextForTransclusion();
+                       $msgtext = $content ? $content->getWikitextForTransclusion() : null;
                        if ( $msgtext === false || $msgtext === null ) $msgtext = '';
 
                        MessageCache::singleton()->replace( $shortTitle, $msgtext );
index 5c3b33b..ad40a64 100644 (file)
@@ -261,7 +261,7 @@ class ApiQueryRevisions extends ApiQueryBase {
                        // rvstart and rvstartid when that is supplied.
                        if ( !is_null( $params['continue'] ) ) {
                                $params['startid'] = $params['continue'];
-                               unset( $params['start'] );
+                               $params['start'] = null;
                        }
 
                        // This code makes an assumption that sorting by rev_id and rev_timestamp produces
index 1cf8e31..591ace9 100644 (file)
@@ -138,7 +138,7 @@ class ApiQueryUsers extends ApiQueryBase {
                                if ( !isset( $userGroups ) ) {
                                        $user = User::newFromRow( $row );
                                } else {
-                                       if ( !is_array( $userGroups[$row->user_name] ) ) {
+                                       if ( !isset( $userGroups[$row->user_name] ) || !is_array( $userGroups[$row->user_name] ) ) {
                                                $userGroups[$row->user_name] = array();
                                        }
                                        $user = User::newFromRow( $row, array( 'user_groups' => $userGroups[$row->user_name] ) );
index 0a8bb9e..386f55a 100644 (file)
@@ -411,4 +411,30 @@ abstract class AbstractContent implements Content {
        public function matchMagicWord( MagicWord $word ) {
                return false;
        }
+
+       /**
+        * @see Content::convert()
+        *
+        * This base implementation calls the hook ConvertContent to enable custom conversions.
+        * Subclasses may override this to implement conversion for "their" content model.
+        *
+        * @param String  $toModel the desired content model, use the CONTENT_MODEL_XXX flags.
+        * @param String  $lossy flag, set to "lossy" to allow lossy conversion. If lossy conversion is
+        * not allowed, full round-trip conversion is expected to work without losing information.
+        *
+        * @return Content|bool A content object with the content model $toModel, or false if
+        * that conversion is not supported.
+        */
+       public function convert( $toModel, $lossy = '' ) {
+               if ( $this->getModel() === $toModel ) {
+                       //nothing to do, shorten out.
+                       return $this;
+               }
+
+               $lossy = ( $lossy === 'lossy' ); // string flag, convert to boolean for convenience
+               $result = false;
+
+               wfRunHooks( 'ConvertContent', array( $this, $toModel, $lossy, &$result ) );
+               return $result;
+       }
 }
index 3c77694..35b51c3 100644 (file)
@@ -42,7 +42,7 @@ interface Content {
        /**
         * @since 1.21
         *
-        * @return string The wikitext to include when another page includes this
+        * @return string|false The wikitext to include when another page includes this
         * content, or false if the content is not includable in a wikitext page.
         *
         * @todo allow native handling, bypassing wikitext representation, like
@@ -481,7 +481,20 @@ interface Content {
         */
        public function matchMagicWord( MagicWord $word );
 
-       // TODO: ImagePage and CategoryPage interfere with per-content action handlers
+       /**
+        * Converts this content object into another content object with the given content model,
+        * if that is possible.
+        *
+        * @param String  $toModel the desired content model, use the CONTENT_MODEL_XXX flags.
+        * @param String  $lossy flag, set to "lossy" to allow lossy conversion. If lossy conversion is
+        * not allowed, full round-trip conversion is expected to work without losing information.
+        *
+        * @return Content|bool A content object with the content model $toModel, or false if
+        * that conversion is not supported.
+        */
+       public function convert( $toModel, $lossy = '' );
+
+               // TODO: ImagePage and CategoryPage interfere with per-content action handlers
        // TODO: nice&sane integration of GeSHi syntax highlighting
        //   [11:59] <vvv> Hooks are ugly; make CodeHighlighter interface and a
        //   config to set the class which handles syntax highlighting
index ee2f2ed..b61dc34 100644 (file)
@@ -582,8 +582,6 @@ abstract class ContentHandler {
                $rcid = 0, # FIXME: use everywhere!
                $refreshCache = false, $unhide = false
        ) {
-               $this->checkModelID( $context->getTitle()->getContentModel() );
-
                $diffEngineClass = $this->getDiffEngineClass();
 
                return new $diffEngineClass( $context, $old, $new, $rcid, $refreshCache, $unhide );
index 0e22fce..872738b 100644 (file)
@@ -115,12 +115,21 @@ class TextContent extends AbstractContent {
        }
 
        /**
-        * Returns the text represented by this Content object, as a string.
+        * Returns attempts to convert this content object to wikitext,
+        * and then returns the text string. The conversion may be lossy.
         *
-        * @return string: the raw text
+        * @note: this allows any text-based content to be transcluded as if it was wikitext.
+        *
+        * @return string|false: the raw text, or null if the conversion failed
         */
        public function getWikitextForTransclusion( ) {
-               return $this->getNativeData();
+               $wikitext = $this->convert( CONTENT_MODEL_WIKITEXT, 'lossy' );
+
+               if ( $wikitext ) {
+                       return $wikitext->getNativeData();
+               } else {
+                       return false;
+               }
        }
 
        /**
@@ -237,4 +246,35 @@ class TextContent extends AbstractContent {
                # TODO: make Highlighter interface, use highlighter here, if available
                return htmlspecialchars( $this->getNativeData() );
        }
+
+       /**
+        * @see Content::convert()
+        *
+        * This implementation provides lossless conversion between content models based
+        * on TextContent.
+        *
+        * @param String  $toModel the desired content model, use the CONTENT_MODEL_XXX flags.
+        * @param String  $lossy flag, set to "lossy" to allow lossy conversion. If lossy conversion is
+        * not allowed, full round-trip conversion is expected to work without losing information.
+        *
+        * @return Content|bool A content object with the content model $toModel, or false if
+        * that conversion is not supported.
+        */
+       public function convert( $toModel, $lossy = '' ) {
+               $converted = parent::convert( $toModel, $lossy );
+
+               if ( $converted !== false ) {
+                       return $converted;
+               }
+
+               $toHandler = ContentHandler::getForModelID( $toModel );
+
+               if ( $toHandler instanceof TextContentHandler ) {
+                       //NOTE: ignore content serialization format - it's just text anyway.
+                       $text = $this->getNativeData();
+                       $converted = $toHandler->unserializeContent( $text );
+               }
+
+               return $converted;
+       }
 }
index cd2bf55..e4de030 100644 (file)
@@ -93,6 +93,8 @@ class RequestContext implements IContextSource {
         */
        public function setTitle( Title $t ) {
                $this->title = $t;
+               // Erase the WikiPage so a new one with the new title gets created.
+               $this->wikipage = null;
        }
 
        /**
@@ -138,6 +140,12 @@ class RequestContext implements IContextSource {
         * @param $p WikiPage object
         */
        public function setWikiPage( WikiPage $p ) {
+               $contextTitle = $this->getTitle();
+               $pageTitle = $p->getTitle();
+               if ( !$contextTitle || !$pageTitle->equals( $contextTitle ) ) {
+                       $this->setTitle( $pageTitle );
+               }
+               // Defer this to the end since setTitle sets it to null.
                $this->wikipage = $p;
        }
 
index 1753afe..affd65f 100644 (file)
@@ -263,8 +263,10 @@ abstract class ORMRow implements IORMRow {
                                switch ( $type ) {
                                        case 'array':
                                                $value = (array)$value;
+                                               // fall-through!
                                        case 'blob':
                                                $value = serialize( $value );
+                                               // fall-through!
                                }
 
                                $values[$this->table->getPrefixedField( $name )] = $value;
@@ -356,6 +358,8 @@ abstract class ORMRow implements IORMRow {
                        is_null( $functionName ) ? __METHOD__ : $functionName
                );
 
+               $this->table->releaseConnection( $dbw );
+
                // DatabaseBase::update does not always return true for success as documented...
                return $success !== false;
        }
@@ -389,7 +393,7 @@ abstract class ORMRow implements IORMRow {
                        $this->table->getName(),
                        $this->getWriteValues(),
                        is_null( $functionName ) ? __METHOD__ : $functionName,
-                       is_null( $options ) ? array( 'IGNORE' ) : $options
+                       $options
                );
 
                // DatabaseBase::insert does not always return true for success as documented...
@@ -399,6 +403,8 @@ abstract class ORMRow implements IORMRow {
                        $this->setField( 'id', $dbw->insertId() );
                }
 
+               $this->table->releaseConnection( $dbw );
+
                return $success;
        }
 
@@ -573,6 +579,8 @@ abstract class ORMRow implements IORMRow {
                        $this->setField( $field, $this->getField( $field ) + $amount );
                }
 
+               $this->table->releaseConnection( $dbw );
+
                return $success;
        }
 
index f3dc5a3..0295f77 100644 (file)
@@ -522,8 +522,10 @@ class DifferenceEngine extends ContextSource {
                                if ( ContentHandler::runLegacyHooks( 'ShowRawCssJs', array( $this->mNewContent, $this->mNewPage, $out ) ) ) {
                                        // NOTE: deprecated hook, B/C only
                                        // use the content object's own rendering
-                                       $po = $this->mNewRev->getContent()->getParserOutput( $this->mNewRev->getTitle(), $this->mNewRev->getId() );
-                                       $out->addHTML( $po->getText() );
+                                       $cnt = $this->mNewRev->getContent();
+                                       $po = $cnt ? $cnt->getParserOutput( $this->mNewRev->getTitle(), $this->mNewRev->getId() ) : null;
+                                       $txt = $po ? $po->getText() : '';
+                                       $out->addHTML( $txt );
                                }
                        } elseif( !wfRunHooks( 'ArticleContentViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) {
                                // Handled by extension
@@ -545,7 +547,7 @@ class DifferenceEngine extends ContextSource {
                                $parserOutput = $this->getParserOutput( $wikiPage, $this->mNewRev );
 
                                # Also try to load it as a redirect
-                               $rt = $this->mNewContent->getRedirectTarget();
+                               $rt = $this->mNewContent ? $this->mNewContent->getRedirectTarget() : null;
 
                                if ( $rt ) {
                                        $article = Article::newFromTitle( $this->mNewPage, $this->getContext() );
@@ -1169,13 +1171,13 @@ class DifferenceEngine extends ContextSource {
                }
                if ( $this->mOldRev ) {
                        $this->mOldContent = $this->mOldRev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
-                       if ( $this->mOldContent === false ) {
+                       if ( $this->mOldContent === null ) {
                                return false;
                        }
                }
                if ( $this->mNewRev ) {
                        $this->mNewContent = $this->mNewRev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
-                       if ( $this->mNewContent === false ) {
+                       if ( $this->mNewContent === null ) {
                                return false;
                        }
                }
index 04cf29e..3a03d4d 100644 (file)
@@ -190,16 +190,9 @@ class FSFileBackend extends FileBackendStore {
                        return $status;
                }
 
-               if ( file_exists( $dest ) ) {
-                       $ok = unlink( $dest );
-                       if ( !$ok ) {
-                               $status->fatal( 'backend-fail-delete', $params['dst'] );
-                               return $status;
-                       }
-               }
-
                if ( !empty( $params['async'] ) ) { // deferred
-                       $cmd = implode( ' ', array( wfIsWindows() ? 'COPY' : 'cp',
+                       $cmd = implode( ' ', array(
+                               wfIsWindows() ? 'COPY /B /Y' : 'cp', // (binary, overwrite)
                                wfEscapeShellArg( $this->cleanPathSlashes( $params['src'] ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
                        ) );
@@ -257,16 +250,9 @@ class FSFileBackend extends FileBackendStore {
                        return $status; // do nothing; either OK or bad status
                }
 
-               if ( file_exists( $dest ) ) {
-                       $ok = unlink( $dest );
-                       if ( !$ok ) {
-                               $status->fatal( 'backend-fail-delete', $params['dst'] );
-                               return $status;
-                       }
-               }
-
                if ( !empty( $params['async'] ) ) { // deferred
-                       $cmd = implode( ' ', array( wfIsWindows() ? 'COPY' : 'cp',
+                       $cmd = implode( ' ', array(
+                               wfIsWindows() ? 'COPY /B /Y' : 'cp', // (binary, overwrite)
                                wfEscapeShellArg( $this->cleanPathSlashes( $source ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
                        ) );
@@ -324,19 +310,9 @@ class FSFileBackend extends FileBackendStore {
                        return $status; // do nothing; either OK or bad status
                }
 
-               if ( file_exists( $dest ) ) {
-                       // Windows does not support moving over existing files
-                       if ( wfIsWindows() ) {
-                               $ok = unlink( $dest );
-                               if ( !$ok ) {
-                                       $status->fatal( 'backend-fail-delete', $params['dst'] );
-                                       return $status;
-                               }
-                       }
-               }
-
                if ( !empty( $params['async'] ) ) { // deferred
-                       $cmd = implode( ' ', array( wfIsWindows() ? 'MOVE' : 'mv',
+                       $cmd = implode( ' ', array(
+                               wfIsWindows() ? 'MOVE /Y' : 'mv', // (overwrite)
                                wfEscapeShellArg( $this->cleanPathSlashes( $source ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
                        ) );
@@ -384,7 +360,8 @@ class FSFileBackend extends FileBackendStore {
                }
 
                if ( !empty( $params['async'] ) ) { // deferred
-                       $cmd = implode( ' ', array( wfIsWindows() ? 'DEL' : 'unlink',
+                       $cmd = implode( ' ', array(
+                               wfIsWindows() ? 'DEL' : 'unlink',
                                wfEscapeShellArg( $this->cleanPathSlashes( $source ) )
                        ) );
                        $status->value = new FSFileOpHandle( $this, $params, 'Copy', $cmd );
@@ -422,14 +399,6 @@ class FSFileBackend extends FileBackendStore {
                        return $status;
                }
 
-               if ( file_exists( $dest ) ) {
-                       $ok = unlink( $dest );
-                       if ( !$ok ) {
-                               $status->fatal( 'backend-fail-delete', $params['dst'] );
-                               return $status;
-                       }
-               }
-
                if ( !empty( $params['async'] ) ) { // deferred
                        $tempFile = TempFSFile::factory( 'create_', 'tmp' );
                        if ( !$tempFile ) {
@@ -441,7 +410,8 @@ class FSFileBackend extends FileBackendStore {
                                $status->fatal( 'backend-fail-create', $params['dst'] );
                                return $status;
                        }
-                       $cmd = implode( ' ', array( wfIsWindows() ? 'COPY' : 'cp',
+                       $cmd = implode( ' ', array(
+                               wfIsWindows() ? 'COPY /B /Y' : 'cp', // (binary, overwrite)
                                wfEscapeShellArg( $this->cleanPathSlashes( $tempFile->getPath() ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
                        ) );
index e01bfc2..b5e2315 100644 (file)
@@ -904,6 +904,24 @@ abstract class FileBackend {
         */
        abstract public function getLocalCopyMulti( array $params );
 
+       /**
+        * Return an HTTP URL to a given file that requires no authentication to use.
+        * The URL may be pre-authenticated (via some token in the URL) and temporary.
+        * This will return null if the backend cannot make an HTTP URL for the file.
+        *
+        * This is useful for key/value stores when using scripts that seek around
+        * large files and those scripts (and the backend) support HTTP Range headers.
+        * Otherwise, one would need to use getLocalReference(), which involves loading
+        * the entire file on to local disk.
+        *
+        * @param $params Array
+        * $params include:
+        *   - src : source storage path
+        * @return string|null
+        * @since 1.21
+        */
+       abstract public function getFileHttpUrl( array $params );
+
        /**
         * Check if a directory exists at a given storage path.
         * Backends using key/value stores will check if the path is a
index 90292ee..a443a3a 100644 (file)
@@ -651,6 +651,15 @@ class FileBackendMultiWrite extends FileBackend {
                return $tempFiles;
        }
 
+       /**
+        * @see FileBackend::getFileHttpUrl()
+        * @return string|null
+        */
+       public function getFileHttpUrl( array $params ) {
+               $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+               return $this->backends[$this->masterIndex]->getFileHttpUrl( $realParams );
+       }
+
        /**
         * @see FileBackend::directoryExists()
         * @param $params array
index 7e91949..97e49a5 100644 (file)
@@ -804,6 +804,14 @@ abstract class FileBackendStore extends FileBackend {
         */
        abstract protected function doGetLocalCopyMulti( array $params );
 
+       /**
+        * @see FileBackend::getFileHttpUrl()
+        * @return string|null
+        */
+       public function getFileHttpUrl( array $params ) {
+               return null; // not supported
+       }
+
        /**
         * @see FileBackend::streamFile()
         * @return Status
index 8441f8f..48db9d3 100644 (file)
@@ -40,6 +40,7 @@ class SwiftFileBackend extends FileBackendStore {
        /** @var CF_Authentication */
        protected $auth; // Swift authentication handler
        protected $authTTL; // integer seconds
+       protected $swiftTempUrlKey; // string; shared secret value for making temp urls
        protected $swiftAnonUser; // string; username to handle unauthenticated requests
        protected $swiftUseCDN; // boolean; whether CloudFiles CDN is enabled
        protected $swiftCDNExpiry; // integer; how long to cache things in the CDN
@@ -66,6 +67,8 @@ class SwiftFileBackend extends FileBackendStore {
         *   - swiftUser          : Swift user used by MediaWiki (account:username)
         *   - swiftKey           : Swift authentication key for the above user
         *   - swiftAuthTTL       : Swift authentication TTL (seconds)
+        *   - swiftTempUrlKey    : Swift "X-Account-Meta-Temp-URL-Key" value on the account.
+        *                          Do not set this until it has been set in the backend.
         *   - swiftAnonUser      : Swift user used for end-user requests (account:username).
         *                          If set, then views of public containers are assumed to go
         *                          through this user. If not set, then public containers are
@@ -104,6 +107,9 @@ class SwiftFileBackend extends FileBackendStore {
                $this->swiftAnonUser = isset( $config['swiftAnonUser'] )
                        ? $config['swiftAnonUser']
                        : '';
+               $this->swiftTempUrlKey = isset( $config['swiftTempUrlKey'] )
+                       ? $config['swiftTempUrlKey']
+                       : '';
                $this->shardViaHashLevels = isset( $config['shardViaHashLevels'] )
                        ? $config['shardViaHashLevels']
                        : '';
@@ -1119,6 +1125,28 @@ class SwiftFileBackend extends FileBackendStore {
                return $tmpFiles;
        }
 
+       /**
+        * @see FileBackendStore::getFileHttpUrl()
+        * @return string|null
+        */
+       public function getFileHttpUrl( array $params ) {
+               if ( $this->swiftTempUrlKey != '' ) { // temp urls enabled
+                       list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
+                       if ( $srcRel === null ) {
+                               return null; // invalid path
+                       }
+                       try {
+                               $sContObj = $this->getContainer( $srcCont );
+                               $obj = new CF_Object( $sContObj, $srcRel, false, false ); // skip HEAD
+                               return $obj->get_temp_url( $this->swiftTempUrlKey, 86400, "GET" );
+                       } catch ( NoSuchContainerException $e ) {
+                       } catch ( CloudFilesException $e ) { // some other exception?
+                               $this->handleException( $e, null, __METHOD__, $params );
+                       }
+               }
+               return null;
+       }
+
        /**
         * @see FileBackendStore::directoriesAreVirtual()
         * @return bool
index 34f3e53..44c6567 100644 (file)
@@ -75,6 +75,9 @@ class DBFileJournal extends FileJournal {
 
                try {
                        $dbw->insert( 'filejournal', $data, __METHOD__ );
+                       if ( mt_rand( 0, 99 ) == 0 ) {
+                               $this->purgeOldLogs(); // occasionally delete old logs
+                       }
                } catch ( DBError $e ) {
                        $status->fatal( 'filejournal-fail-dbquery', $this->backend );
                        return $status;
index 6cd93cc..651ee27 100644 (file)
@@ -127,6 +127,9 @@ class FileRepo {
                        if ( !isset( $this->zones[$zone]['directory'] ) ) {
                                $this->zones[$zone]['directory'] = '';
                        }
+                       if ( !isset( $this->zones[$zone]['urlsByExt'] ) ) {
+                               $this->zones[$zone]['urlsByExt'] = array();
+                       }
                }
        }
 
@@ -196,14 +199,17 @@ class FileRepo {
        /**
         * Get the URL corresponding to one of the four basic zones
         *
-        * @param $zone String: one of: public, deleted, temp, thumb
+        * @param $zone String One of: public, deleted, temp, thumb
+        * @param $ext String|null Optional file extension
         * @return String or false
         */
-       public function getZoneUrl( $zone ) {
-               if ( isset( $this->zones[$zone]['url'] )
-                       && in_array( $zone, array( 'public', 'temp', 'thumb' ) ) )
-               {
-                       return $this->zones[$zone]['url']; // custom URL
+       public function getZoneUrl( $zone, $ext = null ) {
+               if ( in_array( $zone, array( 'public', 'temp', 'thumb' ) ) ) { // standard public zones
+                       if ( $ext !== null && isset( $this->zones[$zone]['urlsByExt'][$ext] ) ) {
+                               return $this->zones[$zone]['urlsByExt'][$ext]; // custom URL for extension/zone
+                       } elseif ( isset( $this->zones[$zone]['url'] ) ) {
+                               return $this->zones[$zone]['url']; // custom URL for zone
+                       }
                }
                switch ( $zone ) {
                        case 'public':
index 694623b..e1a8547 100644 (file)
@@ -135,8 +135,9 @@ class ArchivedFile {
                }
 
                if( !$this->title || $this->title->getNamespace() == NS_FILE ) {
+                       $this->dataLoaded = true; // set it here, to have also true on miss
                        $dbr = wfGetDB( DB_SLAVE );
-                       $res = $dbr->select( 'filearchive',
+                       $row = $dbr->selectRow( 'filearchive',
                                array(
                                        'fa_id',
                                        'fa_name',
@@ -159,20 +160,18 @@ class ArchivedFile {
                                        'fa_sha1' ),
                                $conds,
                                __METHOD__,
-                               array( 'ORDER BY' => 'fa_timestamp DESC' ) );
-                       if ( $res == false || $dbr->numRows( $res ) == 0 ) {
-                       // this revision does not exist?
+                               array( 'ORDER BY' => 'fa_timestamp DESC')
+                       );
+                       if ( !$row ) {
+                               // this revision does not exist?
                                return null;
                        }
-                       $ret = $dbr->resultObject( $res );
-                       $row = $ret->fetchObject();
 
                        // initialize fields for filestore image object
                        $this->loadFromRow( $row );
                } else {
                        throw new MWException( 'This title does not correspond to an image page.' );
                }
-               $this->dataLoaded = true;
                $this->exists = true;
 
                return true;
index 557609d..9a080ae 100644 (file)
@@ -316,7 +316,8 @@ abstract class File {
        public function getUrl() {
                if ( !isset( $this->url ) ) {
                        $this->assertRepoDefined();
-                       $this->url = $this->repo->getZoneUrl( 'public' ) . '/' . $this->getUrlRel();
+                       $ext = $this->getExtension();
+                       $this->url = $this->repo->getZoneUrl( 'public', $ext ) . '/' . $this->getUrlRel();
                }
                return $this->url;
        }
@@ -1253,7 +1254,8 @@ abstract class File {
         */
        function getArchiveUrl( $suffix = false ) {
                $this->assertRepoDefined();
-               $path = $this->repo->getZoneUrl( 'public' ) . '/archive/' . $this->getHashPath();
+               $ext = $this->getExtension();
+               $path = $this->repo->getZoneUrl( 'public', $ext ) . '/archive/' . $this->getHashPath();
                if ( $suffix === false ) {
                        $path = substr( $path, 0, -1 );
                } else {
@@ -1272,7 +1274,8 @@ abstract class File {
         */
        function getArchiveThumbUrl( $archiveName, $suffix = false ) {
                $this->assertRepoDefined();
-               $path = $this->repo->getZoneUrl( 'thumb' ) . '/archive/' .
+               $ext = $this->getExtension();
+               $path = $this->repo->getZoneUrl( 'thumb', $ext ) . '/archive/' .
                        $this->getHashPath() . rawurlencode( $archiveName ) . "/";
                if ( $suffix === false ) {
                        $path = substr( $path, 0, -1 );
@@ -1291,7 +1294,8 @@ abstract class File {
         */
        function getThumbUrl( $suffix = false ) {
                $this->assertRepoDefined();
-               $path = $this->repo->getZoneUrl( 'thumb' ) . '/' . $this->getUrlRel();
+               $ext = $this->getExtension();
+               $path = $this->repo->getZoneUrl( 'thumb', $ext ) . '/' . $this->getUrlRel();
                if ( $suffix !== false ) {
                        $path .= '/' . rawurlencode( $suffix );
                }
index 7d8bda0..32056e3 100644 (file)
@@ -9471,6 +9471,7 @@ $messages['is'] = array(
  * @author Beta16
  * @author Darth Kule
  * @author F. Cosoleto
+ * @author Gianfranco
  * @author Karika
  */
 $messages['it'] = array(
@@ -9564,10 +9565,14 @@ Installazione interrotta.",
        'config-using-server' => 'Nome server in uso "<nowiki>$1</nowiki>".',
        'config-using-uri' => 'URL del server in uso "<nowiki>$1$2</nowiki>".',
        'config-db-type' => 'Tipo di database:',
+       'config-db-wiki-settings' => 'Identifica questo wiki',
        'config-db-name' => 'Nome del database:',
+       'config-db-name-oracle' => 'Schema del database:',
+       'config-db-username' => 'Nome utente del database:',
        'config-db-password-empty' => 'Inserire una password per il nuovo utente del database: $1.
 Anche se può essere possibile creare utenti senza password, questo non è sicuro.',
        'config-db-install-help' => "Inserire il nome utente e la password che verranno usate per la connessione al database durante il processo d'installazione.",
+       'config-db-prefix' => 'Prefisso tabella del database:',
        'config-db-charset' => 'Set di caratteri del database',
        'config-charset-mysql5' => 'MySQL 4.1/5.0 UTF-8',
        'config-charset-mysql4' => 'MySQL 4.0 con compatibilità UTF-8',
@@ -9585,15 +9590,18 @@ Da cambiare solamente se si è sicuri di averne bisogno.',
        'config-header-oracle' => 'Impostazioni Oracle',
        'config-header-ibm_db2' => 'Impostazioni IBM DB2',
        'config-invalid-db-type' => 'Tipo di database non valido',
+       'config-db-web-account' => "Account del database per l'accesso web",
        'config-db-web-create' => "Crea l'account se non esiste già",
        'config-mysql-engine' => 'Storage engine:',
        'config-mysql-innodb' => 'InnoDB',
        'config-mysql-myisam' => 'MyISAM',
        'config-mysql-charset' => 'Set di caratteri del database:',
+       'config-mysql-binary' => 'Binario',
        'config-mysql-utf8' => 'UTF-8',
        'config-ibm_db2-low-db-pagesize' => "Il database DB2 in uso ha una tablespace predefinita con un insufficiente pagesize, che dovrebbe essere '''32K''' o maggiore.",
        'config-ns-generic' => 'Progetto',
        'config-ns-site-name' => 'Stesso nome wiki: $1',
+       'config-ns-other-default' => 'MyWiki',
        'config-admin-box' => 'Account amministratore',
        'config-admin-name' => 'Tuo nome:',
        'config-admin-password' => 'Password:',
@@ -9614,26 +9622,47 @@ Specificare un nome utente diverso.',
 Inserire un indirizzo email se si desidera effettuare l'iscrizione alla mailing list.",
        'config-almost-done' => 'Hai quasi finito!
 Adesso puoi saltare la rimanente parte della configurazione e semplicemente installare la wiki.',
+       'config-optional-continue' => 'Fammi altre domande.',
+       'config-profile-wiki' => 'Wiki tradizionale',
+       'config-profile-no-anon' => 'Creazione utenza obbligatoria',
+       'config-profile-fishbowl' => 'Solo editori autorizzati',
+       'config-profile-private' => 'Wiki privata',
        'config-license' => 'Copyright e licenza:',
+       'config-license-none' => 'Nessun piè di pagina per la licenza',
        'config-license-cc-by-sa' => 'Creative Commons Attribuzione-Condividi allo stesso modo',
        'config-license-cc-by' => 'Creative Commons Attribuzione',
        'config-license-cc-by-nc-sa' => 'Creative Commons Attribuzione-Non commerciale-Condividi allo stesso modo',
        'config-license-cc-0' => 'Creative Commons Zero (pubblico dominio)',
        'config-license-gfdl' => 'GNU Free Documentation License 1.3 o versioni successive',
        'config-license-pd' => 'Pubblico dominio',
+       'config-license-cc-choose' => 'Seleziona una delle licenze Creative Commons',
+       'config-license-help' => "Molti wiki pubblici rilasciano i loro contributi con una [http://freedomdefined.org/Definition licenza libera]. Questo aiuta a creare un senso di proprietà condivisa nella comunità e incoraggia a contribuire a lungo termine. Non è generalmente necessario per un wiki privato o aziendale.
+
+Se vuoi usare testi da Wikipedia, o desideri che Wikipedia possa essere in grado di accettare testi copiati dal tuo wiki, dovresti scegliere '''Creative Commons Attribution Share Alike'''.
+
+In precedenza Wikipedia ha utilizzato la GNU Free Documentation License. La GFDL è una licenza valida, ma è di difficile comprensione e complica il riutilizzo dei contenuti.",
        'config-email-settings' => 'Impostazioni email',
+       'config-email-user' => 'Abilita invio email fra utenti',
        'config-email-auth' => 'Abilita autenticazione via email',
+       'config-upload-enable' => 'Consentire il caricamento di file',
        'config-upload-deleted' => 'Directory per i file cancellati:',
        'config-logo' => 'URL del logo:',
+       'config-instantcommons' => 'Abilita Instant Commons',
        'config-cc-again' => 'Seleziona di nuovo...',
        'config-cc-not-chosen' => 'Scegliere quale licenza Creative Commons si desidera e cliccare su "procedi".',
        'config-advanced-settings' => 'Configurazione avanzata',
+       'config-memcache-needservers' => 'È stato selezionato il tipo di caching Memcached, ma non è stato impostato alcun server.',
        'config-memcache-badip' => 'È stato inserito un indirizzo IP non valido per Memcached: $1.',
        'config-extensions' => 'Estensioni',
+       'config-install-step-done' => 'fatto',
+       'config-install-step-failed' => 'non riuscito',
+       'config-install-schema' => 'Creazione dello schema',
+       'config-install-user' => 'Creazione di utente del database',
        'config-install-user-alreadyexists' => 'L\'utente "$1" è già presente',
        'config-install-user-create-failed' => 'Creazione dell\'utente "$1" non riuscita: $2',
        'config-install-user-missing' => 'L\'utente indicato "$1" non esiste.',
        'config-install-tables-failed' => "'''Errore''': La creazione della tabella non è riuscita: $1",
+       'config-install-interwiki' => 'Riempimento della tabella interwiki predefinita',
        'config-install-interwiki-list' => 'Impossibile leggere il file <code>interwiki.list</code>.',
        'config-install-stats' => 'Inizializzazione delle statistiche',
        'config-install-keys' => 'Generazione delle chiavi segrete',
index dc5bdbd..21ef6d3 100644 (file)
@@ -88,7 +88,10 @@ abstract class JobQueue {
        }
 
        /**
-        * @return bool Quickly check if the queue is empty
+        * Quickly check if the queue is empty.
+        * Queue classes should use caching if they are any slower without memcached.
+        *
+        * @return bool
         */
        final public function isEmpty() {
                wfProfileIn( __METHOD__ );
index a8a2e89..223ef41 100644 (file)
@@ -28,7 +28,7 @@
  * @since 1.21
  */
 class JobQueueDB extends JobQueue {
-       const CACHE_TTL      = 30; // integer; seconds
+       const CACHE_TTL      = 300; // integer; seconds
        const MAX_JOB_RANDOM = 2147483647; // 2^31 - 1; used for job_random
 
        /**
@@ -97,7 +97,7 @@ class JobQueueDB extends JobQueue {
                                        $dbw->setFlag( $autoTrx ? DBO_TRX : 0 ); // restore automatic begin()
                                }
 
-                               $wgMemc->set( $key, 'false', $ttl );
+                               $wgMemc->set( $key, 'false', $ttl ); // queue is not empty
                        } );
                }
 
index 44db516..48f2746 100644 (file)
@@ -153,4 +153,17 @@ class JobQueueGroup {
 
                return array_diff( $this->getQueueTypes(), $wgJobTypesExcludedFromDefaultQueue );
        }
+
+       /**
+        * @return Array List of job types that have non-empty queues
+        */
+       public function getQueuesWithJobs() {
+               $types = array();
+               foreach ( $this->getQueueTypes() as $type ) {
+                       if ( !$this->get( $type )->isEmpty() ) {
+                               $types[] = $type;
+                       }
+               }
+               return $types;
+       }
 }
index b1b96b6..ddd4fcc 100644 (file)
@@ -94,7 +94,7 @@ class DoubleRedirectJob extends Job {
                        return true;
                }
                $content = $targetRev->getContent();
-               $currentDest = $content->getRedirectTarget();
+               $currentDest = $content ? $content->getRedirectTarget() : null;
                if ( !$currentDest || !$currentDest->equals( $this->redirTitle ) ) {
                        wfDebug( __METHOD__.": Redirect has changed since the job was queued\n" );
                        return true;
index a29f29f..384244f 100644 (file)
@@ -70,18 +70,17 @@ class RefreshLinksJob extends Job {
        }
 
        public static function runForTitleInternal( Title $title, Revision $revision, $fname ) {
-               global $wgContLang;
+               wfProfileIn( $fname );
+               $content = $revision->getContent( Revision::RAW );
 
-               wfProfileIn( $fname . '-parse' );
-               $options = ParserOptions::newFromUserAndLang( new User, $wgContLang );
-               $content = $revision->getContent();
-               $parserOutput = $content->getParserOutput( $title, $revision->getId(), $options, false );
-               wfProfileOut( $fname . '-parse' );
+               if ( !$content ) {
+                       // if there is no content, pretend the content is empty
+                       $content = $revision->getContentHandler()->makeEmptyContent();
+               }
 
-               wfProfileIn( $fname . '-update' );
-               $updates = $content->getSecondaryDataUpdates( $title, null, false, $parserOutput  );
+               $updates = $content->getSecondaryDataUpdates( $title, null, false );
                DataUpdate::runUpdates( $updates );
-               wfProfileOut( $fname . '-update' );
+               wfProfileOut( $fname );
        }
 }
 
index 76886eb..7793710 100644 (file)
@@ -107,8 +107,11 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
         * @return Mixed
         */
        public function get( $key ) {
+               wfProfileIn( __METHOD__ );
                $this->debugLog( "get($key)" );
-               return $this->checkResult( $key, parent::get( $key ) );
+               $value = $this->checkResult( $key, parent::get( $key ) );
+               wfProfileOut( __METHOD__ );
+               return $value;
        }
 
        /**
@@ -224,9 +227,11 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
         * @return Array
         */
        public function getMulti( array $keys ) {
+               wfProfileIn( __METHOD__ );
                $this->debugLog( 'getMulti(' . implode( ', ', $keys ) . ')' );
                $callback = array( $this, 'encodeKey' );
                $result = $this->client->getMulti( array_map( $callback, $keys ) );
+               wfProfileOut( __METHOD__ );
                return $this->checkResult( false, $result );
        }
 
index b31288f..9dad1e5 100644 (file)
@@ -3617,7 +3617,7 @@ class Parser {
 
                        if ( $rev ) {
                                $content = $rev->getContent();
-                               $text = $content->getWikitextForTransclusion();
+                               $text = $content ? $content->getWikitextForTransclusion() : null;
 
                                if ( $text === false || $text === null ) {
                                        $text = false;
index 28c3426..1e61a3e 100644 (file)
@@ -77,10 +77,16 @@ abstract class ResourceLoaderWikiModule extends ResourceLoaderModule {
                }
 
                $content = $revision->getContent( Revision::RAW );
+
+               if ( !$content ) {
+                       wfDebug( __METHOD__ . "failed to load content of JS/CSS page!\n" );
+                       return null;
+               }
+
                $model = $content->getModel();
 
                if ( $model !== CONTENT_MODEL_CSS && $model !== CONTENT_MODEL_JAVASCRIPT ) {
-                       wfDebug( __METHOD__ . "bad content model #$model for JS/CSS page!\n" );
+                       wfDebug( __METHOD__ . "bad content model $model for JS/CSS page!\n" );
                        return null;
                }
 
index f8f5fa5..ec542a6 100644 (file)
@@ -795,7 +795,7 @@ class SearchResult {
                                //TODO: if we could plug in some code that knows about special content models *and* about
                                //      special features of the search engine, the search could benefit.
                                $content = $this->mRevision->getContent();
-                               $this->mText = $content->getTextForSearchIndex();
+                               $this->mText = $content ? $content->getTextForSearchIndex() : '';
                        } else { // TODO: can we fetch raw wikitext for commons images?
                                $this->mText = '';
                        }
index a03c598..bb12740 100644 (file)
@@ -95,6 +95,7 @@ class SitesTable extends ORMTable {
 
                        'forward' => false,
                        'config' => array(),
+                       'language' => 'en', // XXX: can we default to '' instead?
                );
        }
 
index 41b3b25..54a2771 100644 (file)
@@ -27,6 +27,9 @@
  * @ingroup SpecialPage
  */
 class SpecialChangePassword extends UnlistedSpecialPage {
+
+       protected $mUserName, $mOldpass, $mNewpass, $mRetype, $mDomain;
+
        public function __construct() {
                parent::__construct( 'ChangePassword' );
        }
@@ -105,6 +108,9 @@ class SpecialChangePassword extends UnlistedSpecialPage {
                $this->getOutput()->redirect( $titleObj->getFullURL() );
        }
 
+       /**
+        * @param $msg string
+        */
        function error( $msg ) {
                $this->getOutput()->addHTML( Xml::element('p', array( 'class' => 'error' ), $msg ) );
        }
@@ -170,6 +176,10 @@ class SpecialChangePassword extends UnlistedSpecialPage {
                );
        }
 
+       /**
+        * @param $fields array
+        * @return string
+        */
        function pretty( $fields ) {
                $out = '';
                foreach ( $fields as $list ) {
@@ -234,7 +244,7 @@ class SpecialChangePassword extends UnlistedSpecialPage {
                try {
                        $user->setPassword( $this->mNewpass );
                        wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
-                       $this->mNewpass = $this->mOldpass = $this->mRetypePass = '';
+                       $this->mNewpass = $this->mOldpass = $this->mRetype = '';
                } catch( PasswordError $e ) {
                        wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
                        throw new PasswordError( $e->getMessage() );
index 8b44828..ea598c3 100644 (file)
@@ -153,7 +153,7 @@ class UsersPager extends AlphabeticPager {
                $userName = $row->user_name;
 
                $ulinks = Linker::userLink( $row->user_id, $userName );
-               $ulinks .= Linker::userToolLinks( $row->user_id, $userName );
+               $ulinks .= Linker::userToolLinksRedContribs( $row->user_id, $userName, intval( $row->edits ) );
 
                $lang = $this->getLanguage();
 
index af3dbf3..ce2633f 100644 (file)
@@ -464,8 +464,6 @@ class MovePageForm extends UnlistedSpecialPage {
                        DoubleRedirectJob::fixRedirects( 'move', $ot, $nt );
                }
 
-               wfRunHooks( 'SpecialMovepageAfterMove', array( &$this, &$ot, &$nt ) );
-
                $out = $this->getOutput();
                $out->setPageTitle( $this->msg( 'pagemovedsub' ) );
 
@@ -484,6 +482,8 @@ class MovePageForm extends UnlistedSpecialPage {
                        $newLink )->params( $oldText, $newText )->parseAsBlock() );
                $out->addWikiMsg( $msgName );
 
+               wfRunHooks( 'SpecialMovepageAfterMove', array( &$this, &$ot, &$nt ) );
+
                # Now we move extra pages we've been asked to move: subpages and talk
                # pages.  First, if the old page or the new page is a talk page, we
                # can't move any talk pages: cancel that.
index 2bd8b0a..f542640 100644 (file)
@@ -382,7 +382,7 @@ class SpecialRecentChanges extends IncludableSpecialPage {
                $invert = $opts['invert'];
                $associated = $opts['associated'];
 
-               $fields = array( $dbr->tableName( 'recentchanges' ) . '.*' ); // all rc columns
+               $fields = RecentChange::selectFields();
                // JOIN on watchlist for users
                if ( $uid ) {
                        $tables[] = 'watchlist';
index 40ebc2f..4db8958 100644 (file)
@@ -93,7 +93,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
                $dbkey = $title->getDBkey();
 
                $tables = array( 'recentchanges' );
-               $select = array( $dbr->tableName( 'recentchanges' ) . '.*' );
+               $select = RecentChange::selectFields();
                $join_conds = array();
                $query_options = array();
 
index 6c33bb8..7c8ff84 100644 (file)
@@ -684,11 +684,21 @@ class SpecialSearch extends SpecialPage {
                        }
                }
 
-               wfProfileOut( __METHOD__ );
-               return "<li><div class='mw-search-result-heading'>{$link} {$redirect} {$section}</div> {$extract}\n" .
-                       "<div class='mw-search-result-data'>{$score}{$size} - {$date}{$related}</div>" .
-                       "</li>\n";
+               $html = null;
+
+               if ( wfRunHooks( 'ShowSearchHit', array (
+                       $this, $result, $terms,
+                       &$link, &$redirect, &$section, &$extract,
+                       &$score, &$size, &$date, &$related,
+                       &$html
+               ) ) ) {
+                       $html = "<li><div class='mw-search-result-heading'>{$link} {$redirect} {$section}</div> {$extract}\n" .
+                               "<div class='mw-search-result-data'>{$score}{$size} - {$date}{$related}</div>" .
+                               "</li>\n";
+               }
 
+               wfProfileOut( __METHOD__ );
+               return $html;
        }
 
        /**
index e973ddc..1e7c8bb 100644 (file)
@@ -66,7 +66,11 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
                                if( !isset( $groups[$group] ) ) {
                                        $groups[$group] = array();
                                }
-                               $groups[$group][$page->getDescription()] = array( $page->getTitle(), $page->isRestricted(), $page->isExpensive() );
+                               $groups[$group][$page->getDescription()] = array(
+                                       $page->getTitle(),
+                                       $page->isRestricted(),
+                                       $page->isCached()
+                               );
                        }
                }
 
@@ -88,15 +92,14 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
        }
 
        private function outputPageList( $groups ) {
-               global $wgMiserMode;
                $out = $this->getOutput();
 
                $includesRestrictedPages = false;
                $includesCachedPages = false;
 
                foreach ( $groups as $group => $sortedPages ) {
-                       $middle = ceil( count( $sortedPages )/2 );
                        $total = count( $sortedPages );
+                       $middle = ceil( $total / 2 );
                        $count = 0;
 
                        $out->wrapWikiMsg( "<h2 class=\"mw-specialpagesgroup\" id=\"mw-specialpagesgroup-$group\">$1</h2>\n", "specialpages-group-$group" );
@@ -107,10 +110,10 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
                                Html::openElement( 'ul' ) . "\n"
                        );
                        foreach( $sortedPages as $desc => $specialpage ) {
-                               list( $title, $restricted, $expensive) = $specialpage;
+                               list( $title, $restricted, $cached ) = $specialpage;
 
                                $pageClasses = array();
-                               if ( $expensive && $wgMiserMode ){
+                               if ( $cached ) {
                                        $includesCachedPages = true;
                                        $pageClasses[] = 'mw-specialpagecached';
                                }
index 5dfc113..688e0a5 100644 (file)
@@ -272,7 +272,7 @@ class SpecialWatchlist extends SpecialPage {
                $form .= '<hr />';
 
                $tables = array( 'recentchanges', 'watchlist' );
-               $fields = array( $dbr->tableName( 'recentchanges' ) . '.*' );
+               $fields = RecentChange::selectFields();
                $join_conds = array(
                        'watchlist' => array(
                                'INNER JOIN',
index 48c0c05..0391988 100644 (file)
@@ -49,17 +49,17 @@ class LanguageHe extends Language {
                switch ( $case ) {
                        case 'prefixed':
                        case 'תחילית':
-                               # Duplicate the "Waw" if prefixed
-                               if ( substr( $word, 0, 2 ) == "ו" && substr( $word, 0, 4 ) != "וו" ) {
+                               # Duplicate the "Waw" if prefixed, but not if it is already double.
+                               if ( substr( $word, 0, 2 ) === "ו" && substr( $word, 0, 4 ) !== "וו" ) {
                                        $word = "ו" . $word;
                                }
 
-                               # Remove the "He" if prefixed
-                               if ( substr( $word, 0, 2 ) == "ה" ) {
+                               # Remove the "He" article if prefixed.
+                               if ( substr( $word, 0, 2 ) === "ה" ) {
                                        $word = substr( $word, 2 );
                                }
 
-                               # Add a hyphen (maqaf) if non-Hebrew letters
+                               # Add a hyphen (maqaf) before non-Hebrew letters.
                                if ( substr( $word, 0, 2 ) < "א" || substr( $word, 0, 2 ) > "ת" ) {
                                        $word = "־" . $word;
                                }
@@ -67,5 +67,4 @@ class LanguageHe extends Language {
 
                return $word;
        }
-
 }
index 708fcd8..801344e 100644 (file)
@@ -192,8 +192,8 @@ $messages = array(
 'newwindow' => '(ábrese nuna ventana nueva)',
 'cancel' => 'Encaboxar',
 'moredotdotdot' => 'Más...',
-'mypage' => 'La mio páxina',
-'mytalk' => 'El mio alderique',
+'mypage' => 'Páxina',
+'mytalk' => 'Alderique',
 'anontalk' => 'Alderique pa esta IP',
 'navigation' => 'Navegación',
 'and' => '&#32;y',
@@ -1154,7 +1154,7 @@ Se puen alcontrar más detalles nel [{{fullurl:{{#Special:Log}}/delete|page={{FU
 
 # Preferences page
 'preferences' => 'Preferencies',
-'mypreferences' => 'Les mios preferencies',
+'mypreferences' => 'Preferencies',
 'prefs-edits' => "Númberu d'ediciones:",
 'prefsnologin' => 'Non identificáu',
 'prefsnologintext' => 'Necesites tar <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} identificáu]</span> pa camudar les preferencies d\'usuariu.',
@@ -2024,7 +2024,7 @@ Ver tamién les [[Special:WantedCategories|categoríes más buscaes]].",
 'linksearch-ok' => 'Guetar',
 'linksearch-text' => 'Se puen usar comodinos como "*.wikipedia.org".
 Necesita polo menos un dominiu de primer nivel, como "*.org".<br />
-Protocolos almitíos: <code>$1</code> (nun amiestes dengún d\'estos na to gueta).',
+Protocolos almitíos: <code>$1</code> (el predetermináu ye http:// si nun se conseña dengún protocolu).',
 'linksearch-line' => '$1 enllaciáu dende $2',
 'linksearch-error' => 'Los comodinos namái puen apaecer al entamu del nome del güéspede.',
 
@@ -2107,7 +2107,7 @@ La direición de corréu electrónicu qu\'especificasti nes [[Special:Preference
 
 # Watchlist
 'watchlist' => 'La mio páxina de vixilancia',
-'mywatchlist' => 'La mio llista de vixilancia',
+'mywatchlist' => 'Llista de vixilancia',
 'watchlistfor2' => 'Pa $1 $2',
 'nowatchlist' => 'La to llista de vixilancia ta vacia.',
 'watchlistanontext' => 'Por favor $1 pa ver o editar entraes na to llista de vixilancia.',
@@ -2369,7 +2369,7 @@ $1",
 # Contributions
 'contributions' => 'Collaboraciones del usuariu',
 'contributions-title' => "Contribuciones d'usuariu pa $1",
-'mycontris' => 'Les mios collaboraciones',
+'mycontris' => 'Collaboraciones',
 'contribsub2' => 'De $1 ($2)',
 'nocontribs' => "Nun s'atoparon cambeos que coincidan con esi criteriu.",
 'uctop' => '(actual)',
@@ -2410,7 +2410,7 @@ La cabera entrada del rexistru de bloqueos s'ufre darréu pa referencia:",
 'whatlinkshere-hideredirs' => '$1 redireiciones',
 'whatlinkshere-hidetrans' => '$1 tresclusiones',
 'whatlinkshere-hidelinks' => '$1 enllaces',
-'whatlinkshere-hideimages' => "$1 enllaces d'imaxe",
+'whatlinkshere-hideimages' => '$1 los enllaces al ficheru',
 'whatlinkshere-filters' => 'Peñeres',
 
 # Block/unblock
index 4c4dff3..5460386 100644 (file)
@@ -9,6 +9,7 @@
  *
  * @author Cekli829
  * @author Don Alessandro
+ * @author E THP
  * @author Emperyan
  * @author Erdemaslancan
  * @author Gulmammad
@@ -956,7 +957,7 @@ $1",
 
 # Preferences page
 'preferences' => 'Nizamlamalar',
-'mypreferences' => 'Nizamlamalarım',
+'mypreferences' => 'Nizamlamalar',
 'prefs-edits' => 'Redaktələrin sayı:',
 'prefsnologin' => 'Daxil olmamısınız',
 'prefsnologintext' => 'Nizamlamaları dəyişmək üçün <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} daxil olmaq]</span> zəruridir.',
index 7c527d6..c6fd49c 100644 (file)
@@ -3426,16 +3426,16 @@ $1',
 'confirmemail_loggedin' => 'Һеҙҙең электрон почта адресығыҙ раҫланды.',
 'confirmemail_error' => 'Электрон почта адресын раҫлаған ваҡытта хата килеп сыҡты.',
 'confirmemail_subject' => '{{SITENAME}} электрон почта адресын раҫлау',
-'confirmemail_body' => 'Кемдер, бәлки һеҙҙер, $1 IP адресынан 
-{{SITENAME}}  проектында ошо электрон почта адресы менән "$2" иҫәп яҙмаһын теркәгән.
+'confirmemail_body' => 'Кемдер, бәлки һеҙҙер, $1 IP адресынан {{SITENAME}} проектында 
+ошо электрон почта адресы менән "$2" иҫәп яҙмаһын теркәгән.
 
-Был иҫәп яҙмаһы ысынлап та һеҙҙеке икәнен раҫлау өсөн һәм
-{{SITENAME}} проектында элетрон почта мөмкинлектәрен тоҡандырыу өсөн, браузерығыҙҙа түбәндәге һылтанманы асығыҙ:
+Был иҫәп яҙмаһы ысынлап та һеҙҙеке икәнен раҫлау өсөн һәм {{SITENAME}} проектында электрон почта 
+мөмкинлектәрен тоҡандырыу өсөн, браузерығыҙҙа түбәндәге һылтанманы асығыҙ:
 
 $3
 
-Әгәр һеҙ иҫәп яҙмаһын *булдырмағанһығыҙ* икән,
-электрон почта адресын раҫлауҙы үтҡәрмәү өсөн т үбәндәге һылтанманы асығыҙ:
+Әгәр һеҙ иҫәп яҙмаһын *булдырмағанһығыҙ* икән, электрон почта 
+адресын раҫлауҙы үткәрмәү өсөн түбәндәге һылтанманы асығыҙ:
 
 $5
 
@@ -3444,12 +3444,12 @@ $5
 {{SITENAME}}  проектында "$2" иҫәп яҙмаһының электрон почта адресын ошо адресҡа үҙгәрткән.
 
 Был иҫәп яҙмаһы ысынлап та һеҙҙеке икәнен раҫлау өсөн һәм
-{{SITENAME}} проектында элетрон почта мөмкинлектәрен яңынан тоҡандырыу өсөн, браузерығыҙҙа түбәндәге һылтанманы асығыҙ:
+{{SITENAME}} проектында электрон почта мөмкинлектәрен яңынан тоҡандырыу өсөн, браузерығыҙҙа түбәндәге һылтанманы асығыҙ:
 
 $3
 
 Әгәр һеҙ иҫәп яҙмаһын *булдырмағанһығыҙ* икән,
-электрон почта адресын раҫлауҙы үтҡәрмәү өсөн т үбәндәге һылтанманы асығыҙ:
+электрон почта адресын раҫлауҙы үткәрмәү өсөн түбәндәге һылтанманы асығыҙ:
 
 $5
 
@@ -3458,12 +3458,12 @@ $5
 {{SITENAME}}  проектында "$2" иҫәп яҙмаһының электрон почта адресын ошо адрес итеп билдәләгән.
 
 Был иҫәп яҙмаһы ысынлап та һеҙҙеке икәнен раҫлау өсөн һәм
-{{SITENAME}} проектында элетрон почта мөмкинлектәрен яңынан тоҡандырыу өсөн, браузерығыҙҙа түбәндәге һылтанманы асығыҙ:
+{{SITENAME}} проектында электрон почта мөмкинлектәрен яңынан тоҡандырыу өсөн, браузерығыҙҙа түбәндәге һылтанманы асығыҙ:
 
 $3
 
 Әгәр иҫәп яҙмаһы һеҙҙеке *түгел* икән,
-электрон почта адресын раҫлауҙы үтҡәрмәү өсөн т үбәндәге һылтанманы асығыҙ:
+электрон почта адресын раҫлауҙы үткәрмәү өсөн түбәндәге һылтанманы асығыҙ:
 
 $5
 
index ac4f2d5..fbe88c5 100644 (file)
@@ -575,8 +575,8 @@ Zur Informazion foigt da aktuöie Logbuachaitrog:",
 'nocreate-loggedin' => "Du host koah Berechtigung, neiche Seiten z' erstön.",
 'permissionserrors' => 'Berechtigungsfeeler',
 'permissionserrorstext' => 'Du bist néd berechtigt, dé Akzión auszfyrn.  {{PLURAL:$1|Grund|Grynd}}:',
-'permissionserrorstext-withaction' => "Du host de Berechtigung ned, dass d' $2.
-{{PLURAL:$1|Grund|Grynd}}:",
+'permissionserrorstext-withaction' => 'Du host koa Berechtigung ned, dass de $2.
+{{PLURAL:$1|Grund|Grind}}:',
 'recreate-moveddeleted-warn' => "'''Ówocht: Du dastöst a Seiten dé schoh friarer gléschd worn is.'''
 
 Bittscheh priaff genau, ób dé erneite Seitendastöung dé Richtlinien entsprichd.
@@ -761,7 +761,7 @@ Details stehen im [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}}
 'rightslog' => 'Rechte-Logbiache',
 
 # Associated actions - in the sentence "You do not have permission to X"
-'action-edit' => 'an derer Seiten duast werkeln',
+'action-edit' => 'beorbadd de Seitn',
 'action-createpage' => "Seiten z' dastön",
 'action-autopatrol' => 'eigerne Beorweitungen ois kontroilird markirn',
 
@@ -1056,7 +1056,7 @@ Zuasätzlige Informaziónen ywer dé oahzelnen Rechtt kennan [[{{MediaWiki:Listg
 'listgrouprights-group' => 'Gruppm',
 'listgrouprights-rights' => 'Rechte',
 'listgrouprights-helppage' => 'Help:Gruppmrechte',
-'listgrouprights-members' => '(Mitgliaderlisten)',
+'listgrouprights-members' => '(Mitgliedalistn)',
 'listgrouprights-addgroup' => 'Benutzer zua {{PLURAL:$2|derer Gruppm|dé Gruppm}} dazuadoah: $1',
 'listgrouprights-removegroup' => 'Benutzer aus {{PLURAL:$2|derer Gruppm|dé Gruppm}} entferner: $1',
 'listgrouprights-addgroup-all' => 'Benutzer zua olle Gruppm dazuadoah',
index 48cb369..c328974 100644 (file)
@@ -232,7 +232,7 @@ $messages = array(
 'cancel' => 'Kanselaron',
 'moredotdotdot' => 'Kadagdagan...',
 'mypage' => 'An sakóng pahina',
-'mytalk' => 'An sakóng olay',
+'mytalk' => 'Orolayan',
 'anontalk' => 'Olay para kaining IP address',
 'navigation' => 'Nabigasyon',
 'and' => '&#32;asin',
@@ -1173,7 +1173,7 @@ Prubaran na panigmitan an saimong kahaputan nin ''all:'' sa paghanap kan gabos n
 
 # Preferences page
 'preferences' => 'Mga kabòtan',
-'mypreferences' => 'Mga kabòtan ko',
+'mypreferences' => 'Mga Kamuyahan ko',
 'prefs-edits' => 'Bilang kan mga hirá:',
 'prefsnologin' => 'Dai nakalaog',
 'prefsnologintext' => 'Ika dapat na magin <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} nakalaog na]</span> tanganing tuytuyon an mga kabotan nin paragamit.',
@@ -2105,7 +2105,7 @@ An e-surat na adres na saimong ilalaog sa [[Special:Preferences|saimong paragami
 
 # Watchlist
 'watchlist' => 'Pigbabantayan ko',
-'mywatchlist' => 'Babantáyan ko',
+'mywatchlist' => 'Bantay-listahan',
 'watchlistfor2' => 'Para ki $1 $2',
 'nowatchlist' => 'Mayo ka man na mga bagay saimong lista nin pigbabantayan.',
 'watchlistanontext' => 'Mag $1 tabi para mahiling o maghira nin mga bagay saimong lista nin mga pigbabantayan.',
@@ -2367,7 +2367,7 @@ $1",
 # Contributions
 'contributions' => 'Mga kontribusyon kan parágamit',
 'contributions-title' => 'Mga kontribusyon kan paragamit para sa $1',
-'mycontris' => 'Mga ambág ko',
+'mycontris' => 'Mga Kaarambagan',
 'contribsub2' => 'Para sa $1 ($2)',
 'nocontribs' => 'Mayong mga pagbabago na nahanap na kapadis sa ining mga criteria.',
 'uctop' => '(alituktok)',
@@ -2408,7 +2408,7 @@ An pinakahuring entrada sa talaan nin pagbara nakahaya sa ibaba bilang reperensi
 'whatlinkshere-hideredirs' => '$1 mga panukdong otro',
 'whatlinkshere-hidetrans' => '$1 kabaling-binalyuhan',
 'whatlinkshere-hidelinks' => '$1 mga kasugpon',
-'whatlinkshere-hideimages' => '$1 mga kasugpon kan imahe',
+'whatlinkshere-hideimages' => '$1 mga kasugpon nin mga sagunson',
 'whatlinkshere-filters' => 'Mga pansarà',
 
 # Block/unblock
index 15ec73d..ccdae69 100644 (file)
@@ -390,8 +390,8 @@ $messages = array(
 'newwindow' => '(адкрываецца ў новым акне)',
 'cancel' => 'Скасаваць',
 'moredotdotdot' => 'Далей…',
-'mypage' => 'Ð\9cаÑ\8f Ñ\81таронка',
-'mytalk' => 'Ð\9cае Ð³утаркі',
+'mypage' => 'Старонка',
+'mytalk' => 'Ð\93утаркі',
 'anontalk' => 'Гутаркі для гэтага IP-адрасу',
 'navigation' => 'Навігацыя',
 'and' => '&#32;і',
@@ -1554,6 +1554,8 @@ $1",
 'rightslogtext' => 'Гэта журнал зьменаў правоў удзельнікаў.',
 'rightslogentry' => 'зьменена прыналежнасьць $1 з групы $2 да $3',
 'rightslogentry-autopromote' => 'быў аўтаматычна падвышаны з $2 да $3',
+'logentry-rights-rights' => '$1 {{GENDER:$1|зьмяніў|зьмяніла}} прыналежнасьць $3 да групы з $4 на $5',
+'logentry-rights-rights-legacy' => '$1 {{GENDER:$1|зьмяніў|зьмяніла}} прыналежнасьць $3 да групаў',
 'logentry-rights-autopromote' => '$1 {{GENDER:$1|быў аўтаматычна пераведзены|была аўтаматычна пераведзеная}} з групы $4 ў $5',
 'rightsnone' => '(няма)',
 
@@ -2519,7 +2521,7 @@ $1',
 # Contributions
 'contributions' => 'Унёсак',
 'contributions-title' => 'Унёсак {{GENDER:$1|удзельніка|удзельніцы}} $1',
-'mycontris' => 'Ð\9cой Ñ\83нёсак',
+'mycontris' => 'Унёсак',
 'contribsub2' => 'Для $1 ($2)',
 'nocontribs' => 'Ня знойдзена зьменаў, якія адпавядаюць гэтым крытэрыям.',
 'uctop' => ' (апошняя)',
@@ -3983,4 +3985,6 @@ MediaWiki распаўсюджваецца з надзеяй, што будзе
 'duration-centuries' => '$1 {{PLURAL:$1|стагодзьдзе|стагодзьдзі|стагодзьдзяў}}',
 'duration-millennia' => '$1 {{PLURAL:$1|тысячагодзьдзе|тысячагодзьдзі|тысячагодзьдзяў}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'гутаркі',
 );
index fec007b..b08cce1 100644 (file)
@@ -1166,7 +1166,7 @@ $1",
 'prefs-help-recentchangescount' => 'এতে সাম্প্রতিক পরিবর্তনসমূহ, পাতার ইতিহাস এবং লগ অন্তর্ভুক্ত।',
 'prefs-help-watchlist-token' => 'এই ঘরটি একটি গোপন শব্দ চাবি দ্বারা পূরণ করলে আপনার নজর তালিকার জন্য একটি আরএসএস ফিড তৈরী হবে। যারা এই ঘরের চাবি জানবে তারা আপনার নজর তালিকা দেখতে পারবে, তাই একটি গোপন মান ব্যবহার করুন। এখানে এলোমেলোভাবে তৈরী একটি মান দেখানো হয়েছে যা আপনি ব্যবহার করতে পারেন: $1',
 'savedprefs' => 'আপনার পছন্দগুলো সংরক্ষণ করা হয়েছে।',
-'timezonelegend' => 'সময় বলয়:',
+'timezonelegend' => 'সময়স্থান:',
 'localtime' => 'স্থানীয় সময়:',
 'timezoneuseserverdefault' => 'উইকির পূর্বনির্ধারিত সময় ব্যবহার করো ($1)',
 'timezoneuseoffset' => 'অন্য (অফসেট নির্দিষ্ট করুন)',
@@ -1970,7 +1970,7 @@ Maybe you want to edit the description on its [$2 file description page] there.'
 
 # Special:ListUsers
 'listusersfrom' => 'সেই সব ব্যবহারকারী দেখাও যাদের নাম এই অক্ষর দিয়ে শুরু:',
-'listusers-submit' => 'দà§\87à¦\96ানà§\8b à¦¹à§\8bà¦\95',
+'listusers-submit' => 'দà§\87à¦\96াà¦\93',
 'listusers-noresult' => 'কোন ব্যবহারকারী খুঁজে পাওয়া যায়নি।',
 'listusers-blocked' => '(ব্লককৃত)',
 
index ba7f061..b9cb6da 100644 (file)
@@ -227,7 +227,7 @@ $messages = array(
 
 'underline-always' => 'Atav',
 'underline-never' => 'Morse',
-'underline-default' => 'Diouzh ar merdeer',
+'underline-default' => 'Merdeer dre ziouer',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Stil font an takad skridaozañ :',
@@ -864,7 +864,7 @@ Dindan emañ merket moned diwezhañ marilh ar stankadennoù, d'ho kelaouiñ :",
 'note' => "'''Notenn :'''",
 'previewnote' => "'''Diwallit mat, n'eus ken ur rakweled eus an destenn-mañ.'''
 N'eo ket bet enrollet ho kemmoù evit c'hoazh !",
-'continue-editing' => "Kenderc'hel da gemmañ",
+'continue-editing' => "Mont d'an takad kemmañ",
 'previewconflict' => 'Gant ar rakweled e teu testenn ar bajenn war wel evel ma vo pa vo bet enrollet.',
 'session_fail_preview' => "'''Ho tigarez! N'eus ket bet tu da enrollañ ho kemmoù rak kollet eo bet roadennoù an dalc'h.'''
 Klaskit en-dro mar plij.
@@ -939,6 +939,9 @@ Diverket eo bet evit doare.',
 'edit-already-exists' => "N'eus ket bet gallet krouiñ ur bajenn nevez.
 Krouet e oa bet c'hoazh.",
 'defaultmessagetext' => 'Testenn dre ziouer',
+'content-failed-to-parse' => "C'hwitet eo dielfennadur endalc'had $2 evit ar patrom $1: $3",
+'invalid-content-data' => "n'eo ket mat roadennoù an endalc'had",
+'content-not-allowed-here' => 'N\'eo ket aotreet an endalc\'had "$1" er bajenn [[$2]]',
 
 # Content models
 'content-model-wikitext' => 'wikitestenn',
@@ -2088,7 +2091,7 @@ Gwelet ivez ar [[Special:WantedCategories|rummadoù goulennet a vank]].',
 'linksearch-ok' => 'Klask',
 'linksearch-text' => 'Gallout a reer implijout arouezennoù "joker" evel, da skouer, "*.wikipedia.org".
 Rekis eo dezho un domani a-us da nebeutañ evel, da skouer, "*.org".<br />
-Protokoloù skoret : <code>$1</code> (na lakait hini ebet eus ar re-se en ho klask)',
+Protokoloù skoret : <code>$1</code> (defaults to http:// na lakait hini ebet eus ar re-se en ho klask)',
 'linksearch-line' => '$1 gant ul liamm adal $2',
 'linksearch-error' => "N'hall an arouezennoù joker bezañ implijet nemet e deroù anv domani an ostiz.",
 
@@ -2470,7 +2473,7 @@ Dindan emañ merket enmont diwezhañ marilh ar stankadennoù, d'ho kelaouiñ :",
 'whatlinkshere-hideredirs' => '$1 adkas',
 'whatlinkshere-hidetrans' => '$1 treuzkluzadur',
 'whatlinkshere-hidelinks' => '$1 liamm',
-'whatlinkshere-hideimages' => '$1 liamm skeudennoù',
+'whatlinkshere-hideimages' => '$1 ar restroù liammet',
 'whatlinkshere-filters' => 'Siloù',
 
 # Block/unblock
@@ -2950,7 +2953,7 @@ Sur a-walc'h abalamour d'ul liamm enni a gas d'ul lec'hienn ziavaez berzet.",
 
 # Info page
 'pageinfo-title' => 'Titouroù evit "$1"',
-'pageinfo-not-current' => "Evit an adwel bremañ e c'hall bezañ diskwelet an titouroù hepken.",
+'pageinfo-not-current' => "Hon digarezit, ne c'haller ket reiñ an titouroù-mañ evit an adweloù kozh.",
 'pageinfo-header-basic' => 'Titouroù diazez',
 'pageinfo-header-edits' => 'Kemmoù',
 'pageinfo-header-restrictions' => 'Gwarez ar bajenn',
@@ -2980,6 +2983,7 @@ Sur a-walc'h abalamour d'ul liamm enni a gas d'ul lec'hienn ziavaez berzet.",
 'pageinfo-templates' => "{{PLURAL:$1|Patrom endalc'het|Patromoù endalc'het}} ($1)",
 'pageinfo-toolboxlink' => 'Titouroù ar bajenn',
 'pageinfo-redirectsto' => 'Adkas a ra da',
+'pageinfo-redirectsto-info' => 'Titouroù',
 'pageinfo-contentpage-yes' => 'Ya',
 'pageinfo-protect-cascading-yes' => 'Ya',
 
index e2a8d68..f19cb10 100644 (file)
@@ -2509,8 +2509,8 @@ quines pàgines en concret estan sent vandalitzades).",
 'ipb-confirm' => 'Confirma el blocatge',
 'badipaddress' => "L'adreça IP no té el format correcte.",
 'blockipsuccesssub' => "S'ha blocat amb èxit",
-'blockipsuccesstext' => "[[Special:Contributions/$1|$1]] ha estat {{GENDER:$1|bloquejat|bloquejada|bloquejat/da}}.<br />
-Vegeu la [[Special:BlockList|llista d'IP blocades]] per revisar els bloqueigs.",
+'blockipsuccesstext' => '[[Special:Contributions/$1|$1]] ha estat {{GENDER:$1|blocat|blocada}}.<br />
+Vegeu la [[Special:BlockList|llista de bloqueigs]] per revisar-los.',
 'ipb-blockingself' => 'Esteu a punt de blocar-vos a vós mateix! Esteu segurs de voler-ho fer?',
 'ipb-confirmhideuser' => "Esteu a punt de bloquejar un usuari que està marcat amb l'opció «amaga l'usuari». Això suprimirà el seu nom a totes les llistes i registres. Esteu segurs de voler-ho fer?",
 'ipb-edit-dropdown' => 'Edita les raons per a blocar',
index 5e9a1a0..813fe6f 100644 (file)
@@ -492,8 +492,8 @@ $messages = array(
 'newwindow' => '(otevře se v novém okně)',
 'cancel' => 'Storno',
 'moredotdotdot' => 'Další…',
-'mypage' => 'Moje stránka',
-'mytalk' => 'Moje diskuse',
+'mypage' => 'Stránka',
+'mytalk' => 'Diskuse',
 'anontalk' => 'Diskuse k této IP adrese',
 'navigation' => 'Navigace',
 'and' => '&#32;a',
@@ -2599,7 +2599,7 @@ $1',
 # Contributions
 'contributions' => 'Příspěvky uživatele',
 'contributions-title' => 'Příspěvky uživatele $1',
-'mycontris' => 'Mé příspěvky',
+'mycontris' => 'Příspěvky',
 'contribsub2' => '$1 ($2)',
 'nocontribs' => 'Nenalezeny žádné změny vyhovující kritériím.',
 'uctop' => ' (aktuální)',
@@ -4050,8 +4050,8 @@ Obrázky se zobrazí v plném rozlišení, jiné typy souborů se otevřenou v p
 'logentry-move-move_redir-noredirect' => '$1 přesunul stránku $3 na $4 místo přesměrování bez založení přesměrování',
 'logentry-patrol-patrol' => '$1 označil revizi $4 stránky $3 jako prověřenou',
 'logentry-patrol-patrol-auto' => '$1 automaticky označil revizi $4 stránky $3 jako prověřenou',
-'logentry-newusers-newusers' => '$1 založil uživatelský účet',
-'logentry-newusers-create' => '$1 založil uživatelský účet',
+'logentry-newusers-newusers' => '$1 si založil uživatelský účet',
+'logentry-newusers-create' => '$1 si založil uživatelský účet',
 'logentry-newusers-create2' => '$1 založil uživatelský účet $3',
 'logentry-newusers-autocreate' => 'Automaticky byl založen účet $1',
 'newuserlog-byemail' => 'heslo zasláno e-mailem',
index 4c3bd4d..8a37f5e 100644 (file)
@@ -164,7 +164,7 @@ $messages = array(
 
 'underline-always' => 'Bob amser',
 'underline-never' => 'Byth',
-'underline-default' => 'Rhagosodyn y porwr',
+'underline-default' => "Rhagosodyn y porwr neu'r wedd",
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Arddull y ffont yn y blwch golygu:',
@@ -249,8 +249,8 @@ $messages = array(
 'newwindow' => '(yn agor mewn ffenest newydd)',
 'cancel' => 'Diddymu',
 'moredotdotdot' => 'Rhagor...',
-'mypage' => 'Fy nhudalen',
-'mytalk' => 'Fy sgwrs',
+'mypage' => 'Tudalen defnyddiwr',
+'mytalk' => 'Sgwrs',
 'anontalk' => 'Sgwrs ar gyfer y cyfeiriad IP hwn',
 'navigation' => 'Panel llywio',
 'and' => '&#32;a/ac',
@@ -868,6 +868,11 @@ Ymddengys iddi gael ei dileu.",
 Mae ar gael yn barod.',
 'defaultmessagetext' => 'Y testun rhagosodedig',
 
+# Content models
+'content-model-wikitext' => 'cystrawen wici',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
+
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''Rhybudd:''' Mae gormod o alwadau ar ffwythiannau dosrannu sy'n dreth ar adnoddau yn y dudalen hon.
 
@@ -1152,7 +1157,7 @@ Cofiwch y gall mynegeion Google o gynnwys {{SITENAME}} fod ar ei hôl hi.",
 
 # Preferences page
 'preferences' => 'Dewisiadau',
-'mypreferences' => 'Fy newisiadau',
+'mypreferences' => 'Dewisiadau',
 'prefs-edits' => 'Nifer y golygiadau:',
 'prefsnologin' => 'Nid ydych wedi mewngofnodi',
 'prefsnologintext' => 'Rhaid i chi <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} fewngofnodi]</span> er mwyn gosod eich dewisiadau defnyddiwr.',
@@ -2082,7 +2087,7 @@ Bydd y cyfeiriad e-bost a osodoch yn eich [[Special:Preferences|dewisiadau chith
 
 # Watchlist
 'watchlist' => 'Fy rhestr wylio',
-'mywatchlist' => 'Fy rhestr wylio',
+'mywatchlist' => 'Rhestr wylio',
 'watchlistfor2' => 'Yn ôl gofyn $1 $2',
 'nowatchlist' => "Mae eich rhestr wylio'n wag.",
 'watchlistanontext' => "Rhaid $1 er mwyn gweld neu ddiwygio'ch rhestr wylio.",
@@ -2341,7 +2346,7 @@ $1',
 # Contributions
 'contributions' => "Cyfraniadau'r defnyddiwr",
 'contributions-title' => "Cyfraniadau'r defnyddiwr am $1",
-'mycontris' => 'Fy nghyfraniadau',
+'mycontris' => 'Cyfraniadau',
 'contribsub2' => 'Dros $1 ($2)',
 'nocontribs' => "Heb ddod o hyd i newidiadau gyda'r meini prawf hyn.",
 'uctop' => '(cyfredol)',
@@ -2382,7 +2387,7 @@ Mae'r cofnod diweddaraf yn y lòg blocio i'w weld isod:",
 'whatlinkshere-hideredirs' => '$1 ailgyfeiriadau',
 'whatlinkshere-hidetrans' => '$1 cynhwysion',
 'whatlinkshere-hidelinks' => '$1 cysylltau',
-'whatlinkshere-hideimages' => '$1 cysylltau delweddau',
+'whatlinkshere-hideimages' => '$1 cysylltau ffeiliau',
 'whatlinkshere-filters' => 'Hidlau',
 
 # Block/unblock
@@ -2851,6 +2856,7 @@ Achos hyn yn fwy na thebyg yw presenoldeb cysylltiad i wefan ar y rhestr wahardd
 'pageinfo-default-sort' => 'Allwedd trefnu diofyn',
 'pageinfo-length' => 'Hyd y dudalen (beitiau)',
 'pageinfo-article-id' => 'ID y dudalen',
+'pageinfo-language' => 'Iaith cynnwys y dudalen',
 'pageinfo-robot-policy' => 'Statws i beiriannau chwilio',
 'pageinfo-views' => 'Nifer yr ymweliadau',
 'pageinfo-watchers' => 'Nifer gwylwyr y dudalen',
@@ -2864,6 +2870,7 @@ Achos hyn yn fwy na thebyg yw presenoldeb cysylltiad i wefan ar y rhestr wahardd
 'pageinfo-authors' => 'Cyfanswm yr awduron gwahanol',
 'pageinfo-magic-words' => '{{PLURAL:$1|Gair|Gair|Geiriau}} hud ($1)',
 'pageinfo-hidden-categories' => '{{PLURAL:$1|Categori|Categori|Categorïau}} cudd ($1)',
+'pageinfo-toolboxlink' => 'Gwybodaeth am y dudalen',
 
 # Skin names
 'skinname-standard' => 'Safonol',
index 727d017..625eecf 100644 (file)
@@ -236,7 +236,7 @@ $messages = array(
 
 'underline-always' => 'Altid',
 'underline-never' => 'Aldrig',
-'underline-default' => 'Brug browserens indstilling',
+'underline-default' => 'Brug browserens indstilling eller standarden for det valgte udseende',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Skriftstil ved redigering:',
@@ -322,7 +322,7 @@ $messages = array(
 'cancel' => 'Afbryd',
 'moredotdotdot' => 'Mere...',
 'mypage' => 'Min side',
-'mytalk' => 'Min diskussion',
+'mytalk' => 'Diskussion',
 'anontalk' => 'Diskussionsside for denne IP-adresse',
 'navigation' => 'Navigation',
 'and' => '&#32;og',
@@ -1475,6 +1475,9 @@ Hvis du vælger at oplyse dit navn, vil det blive brugt til at tilskrive dig dit
 'rightslogtext' => 'Dette er en log over ændringer i brugeres rettigheder.',
 'rightslogentry' => 'ændrede grupperettigheder for „$1“ fra „$2“ til „$3“.',
 'rightslogentry-autopromote' => 'blev automatisk forfremmet fra $2 til $3',
+'logentry-rights-rights' => '$1 ændrede gruppemedlemskabet for $3 fra $4 til $5',
+'logentry-rights-rights-legacy' => '$1 ændrede gruppemedlemskabet for $3',
+'logentry-rights-autopromote' => '$1 blev automatisk forfremmet fra $4 til $5',
 'rightsnone' => '(-)',
 
 # Associated actions - in the sentence "You do not have permission to X"
@@ -2084,7 +2087,7 @@ Se også [[Special:WantedCategories|ønskede kategorier]].',
 'linksearch-ok' => 'Søg',
 'linksearch-text' => 'Wildcards som "*.wikipedia.org" kan benyttes.
 Der skal som minimum angives et topniveau-domæne som f. eks. "*.org".<br />
-Understøttede protokoller: <code>$1</code> (tilføj ikke protokollerne til din søgning).',
+Understøttede protokoller: <code>$1</code> (bruger automatisk http:// hvis der ikke er angivet nogen protokol).',
 'linksearch-line' => '$2 linker til $1',
 'linksearch-error' => 'Wildcards må kun benyttes i starten af hostnavnet.',
 
@@ -2166,7 +2169,7 @@ Den e-mail-adresse, du har angivet i [[Special:Preferences|dine indstillinger]],
 
 # Watchlist
 'watchlist' => 'Overvågningsliste',
-'mywatchlist' => 'Min overvågningsliste',
+'mywatchlist' => 'Overvågningsliste',
 'watchlistfor2' => 'For $1 $2',
 'nowatchlist' => 'Du har ingenting i din overvågningsliste.',
 'watchlistanontext' => 'Du skal $1, for at se din overvågningsliste eller ændre indholdet af den.',
@@ -2420,7 +2423,7 @@ $1',
 # Contributions
 'contributions' => 'Brugerbidrag',
 'contributions-title' => 'Brugerbidrag for $1',
-'mycontris' => 'Mine bidrag',
+'mycontris' => 'Bidrag',
 'contribsub2' => 'For $1 ($2)',
 'nocontribs' => 'Ingen ændringer er fundet som opfylder disse kriterier.',
 'uctop' => ' (seneste)',
@@ -2460,7 +2463,7 @@ Den seneste post i blokeringsloggen vises nedenfor:',
 'whatlinkshere-hideredirs' => '$1 omdirigeringer',
 'whatlinkshere-hidetrans' => '$1 inkluderinger',
 'whatlinkshere-hidelinks' => '$1 henvisninger',
-'whatlinkshere-hideimages' => '$1 fillinks',
+'whatlinkshere-hideimages' => '$1 filhenvisninger',
 'whatlinkshere-filters' => 'Filtre',
 
 # Block/unblock
@@ -3851,4 +3854,6 @@ Ellers kan du bruge den enkle formular nedenfor. Din kommentar vil blive tilføj
 'duration-centuries' => '$1 {{PLURAL:$1|århundrede|århundreder}}',
 'duration-millennia' => '$1 {{PLURAL:$1|årtusind|årtusinder}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'diskussion',
 );
index 50e7b28..7bd2d85 100644 (file)
@@ -541,7 +541,7 @@ $messages = array(
 'cancel' => 'Abbrechen',
 'moredotdotdot' => 'Mehr …',
 'mypage' => 'Eigene Seite',
-'mytalk' => 'Eigene Diskussion',
+'mytalk' => 'Diskussion',
 'anontalk' => 'Diskussionsseite dieser IP',
 'navigation' => 'Navigation',
 'and' => '&#32;und',
@@ -2651,7 +2651,7 @@ $1',
 # Contributions
 'contributions' => 'Benutzerbeiträge',
 'contributions-title' => 'Benutzerbeiträge von „$1“',
-'mycontris' => 'Eigene Beiträge',
+'mycontris' => 'Beiträge',
 'contribsub2' => 'Von $1 ($2)',
 'nocontribs' => 'Es wurden keine Benutzerbeiträge mit diesen Kriterien gefunden.',
 'uctop' => '(aktuell)',
@@ -3207,8 +3207,8 @@ Das liegt wahrscheinlich an einem Link auf eine externe Seite.',
 'pageinfo-lasttime' => 'Datum der letzten Bearbeitung',
 'pageinfo-edits' => 'Gesamtzahl der Bearbeitungen',
 'pageinfo-authors' => 'Gesamtzahl unterschiedlicher Autoren',
-'pageinfo-recent-edits' => 'Anzahl der kürzlich erfolgten Bearbeitungen (innerhalb von $1)',
-'pageinfo-recent-authors' => 'Anzahl der unterschiedlichen Autoren',
+'pageinfo-recent-edits' => 'Anzahl der kürzlich erfolgten Bearbeitungen (innerhalb der letzten $1)',
+'pageinfo-recent-authors' => 'Anzahl unterschiedlicher Autoren',
 'pageinfo-magic-words' => '{{PLURAL:$1|Magisches Wort|Magische Wörter}} ($1)',
 'pageinfo-hidden-categories' => 'Versteckte {{PLURAL:$1|Kategorie|Kategorien}} ($1)',
 'pageinfo-templates' => 'Eingebundene {{PLURAL:$1|Vorlage|Vorlagen}} ($1)',
@@ -4150,4 +4150,6 @@ Anderenfalls kannst du auch das untenstehende einfache Formular nutzen. Dein Kom
 'duration-centuries' => '$1 {{PLURAL:$1|Jahrhundert|Jahrhunderte}}',
 'duration-millennia' => '$1 {{PLURAL:$1|Jahrtausend|Jahrtausende}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'Diskussion',
 );
index bbc7bf7..f90d61c 100644 (file)
@@ -357,7 +357,7 @@ $messages = array(
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Cayê vurnayışi de terzê nuştışi:',
-'editfont-default' => 'Cıgeyrayoğo hesıbyaye',
+'editfont-default' => 'Cıgeyrayoğo hesabiyaye',
 'editfont-monospace' => 'Terzê nusteyê sabıtcagırewtoği',
 'editfont-sansserif' => 'Babetê Sans-serifi',
 'editfont-serif' => 'Babetê serifi',
@@ -439,11 +439,11 @@ $messages = array(
 
 'about' => 'Heqa',
 'article' => 'Wesiqe',
-'newwindow' => '<br />(teqa da newi de abena/pençereyê newey de beno a)',
+'newwindow' => '(pençereyê newey de beno a)',
 'cancel' => 'Bıtexelne',
 'moredotdotdot' => 'Vêşi...',
-'mypage' => 'Pela mı',
-'mytalk' => 'Werênayışê mı',
+'mypage' => 'Per',
+'mytalk' => 'Werênayış',
 'anontalk' => 'Pela werênayışê nê IPy',
 'navigation' => 'Geyrayış',
 'and' => '&#32;u',
@@ -461,7 +461,7 @@ $messages = array(
 # Vector skin
 'vector-action-addsection' => 'Mesel Vırazê',
 'vector-action-delete' => 'Besterne',
-'vector-action-move' => 'Bere',
+'vector-action-move' => 'Berê',
 'vector-action-protect' => 'Bıpawe',
 'vector-action-undelete' => 'Esterıtışi peyser bıgê',
 'vector-action-unprotect' => 'Starkerdışi bıvurne',
@@ -894,7 +894,7 @@ Parola vêrdiye: $2',
 'image_sample' => 'Misal resim.jpg',
 'image_tip' => 'Dosyaya gumın',
 'media_sample' => 'misal.jpg',
-'media_tip' => 'Gırey dosya',
+'media_tip' => 'Gıreyê dosya',
 'sig_tip' => 'İmza u wext',
 'hr_tip' => 'Çıxiza dimdayi (hend akar mefiye)',
 
@@ -1369,7 +1369,7 @@ Pe verbendi ''all:'', vaceyê xo bıvurni ki contenti hemi cıgeyro (pelanê mı
 
 # Preferences page
 'preferences' => 'Tercihi',
-'mypreferences' => 'Tercihê mı',
+'mypreferences' => 'Tercihi',
 'prefs-edits' => 'Amarê vurnayışan:',
 'prefsnologin' => 'Şıma cıkewtış nêvıraşto',
 'prefsnologintext' => 'Şıma gani be <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} cikewte]</span> ke tercihanê karberi xo eyar bıkerê.',
@@ -2154,7 +2154,7 @@ gıreyê her satıri de gıreyi; raş motışê yewın u dıyıni esto.
 'newpages' => 'Pelê newey',
 'newpages-username' => 'Nameyê karberi:',
 'ancientpages' => 'Wesiqeyê ke vurnayışê ciyê peyeni tewr kehani',
-'move' => 'Berden',
+'move' => 'Berdış',
 'movethispage' => 'Ena pele bere',
 'unusedimagestext' => 'Enê dosyey estê, feqet zerrey yew pele de wedardey niyê.
 Xo 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ê.',
@@ -2229,9 +2229,9 @@ hem zi bıewnê [[Special:WantedCategories|kategori yê ke waziyeni]].',
 'linksearch-pat' => 'bıgêr motif:',
 'linksearch-ns' => 'Cayênameyî:',
 'linksearch-ok' => 'Cı geyre',
-'linksearch-text' => 'Joker ê zey "*.wikipedia.org"i karneno.<br />
-Tewr tayn en cêra "*.org" wazêno. <br />
-qaydeyê destek biyayeyi: <code>$1</code> (Cı geyrayış de xo miyan enina ra yeweri de mefiye).',
+'linksearch-text' => 'Jokeri ê zey "*.wikipedia.org"i benê ke bıgureniyê.
+Tewr senık yew sewiya serêna cayê tesiri lazıma, mesela "*.org".<br />
+Qeydeyê destegbiyayey: <code>$1</code> (qet yew qeydeyo hesabiyaye http:// ke name nêbiyo).',
 'linksearch-line' => '$1, $2 ra link biya',
 'linksearch-error' => 'jokeri têna nameyê makina ya serekini de aseni/eseni.',
 
@@ -2315,7 +2315,7 @@ qey heqê şexsi de [[{{MediaWiki:Listgrouprights-helppage}}|hema malumato ziyed
 
 # Watchlist
 'watchlist' => 'Lista mına seyrkerdışi',
-'mywatchlist' => 'Lista mına seyrkerdışi',
+'mywatchlist' => 'Lista seyr kerdışi',
 'watchlistfor2' => 'Qandê $1 ($2)',
 'nowatchlist' => 'listeya temaşa kerdıişê şıma de yew madde zi çina.',
 'watchlistanontext' => 'qey vurnayişê maddeya listeya temaşakerdişi $1.',
@@ -2573,7 +2573,7 @@ $1',
 # Contributions
 'contributions' => 'İştiraqê karberi',
 'contributions-title' => 'Dekerdenê karber de $1',
-'mycontris' => 'Cıkerdışê mı',
+'mycontris' => 'Cıkerdışi',
 'contribsub2' => 'Qandê $1 ($2)',
 'nocontribs' => 'Ena kriteriya de vurnayîş çini yo.',
 'uctop' => '(top)',
@@ -2614,7 +2614,7 @@ Cıkewtışo tewr peyêno ke bloke biyo, cêr seba referansi belikerdeyo:',
 'whatlinkshere-hideredirs' => 'Hetenayışê $1',
 'whatlinkshere-hidetrans' => 'Açarnayışê $1',
 'whatlinkshere-hidelinks' => 'Greyê $1',
-'whatlinkshere-hideimages' => 'Linkanê resımi $1',
+'whatlinkshere-hideimages' => 'Gıreyê dosya $1',
 'whatlinkshere-filters' => 'Avrêci',
 
 # Block/unblock
@@ -4742,4 +4742,6 @@ Ena sita dı newke xırabiya teknik esta.',
 'duration-centuries' => '$1 {{PLURAL:$1|seserre|seserri}}',
 'duration-millennia' => '$1 {{PLURAL:$1|milenyum|milenyumi}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'behse',
 );
index e3e50c2..35f92f7 100644 (file)
@@ -291,8 +291,8 @@ $messages = array(
 'newwindow' => '(se wótcynijo w nowem woknje)',
 'cancel' => 'Pśetergnuś',
 'moredotdotdot' => 'Wěcej…',
-'mypage' => 'Mój bok',
-'mytalk' => 'mója diskusija',
+'mypage' => 'Bok',
+'mytalk' => 'Diskusija',
 'anontalk' => 'Diskusija z toś teju IP',
 'navigation' => 'Nawigacija',
 'and' => '&#32;a',
@@ -1190,7 +1190,7 @@ Drobnostki móžoš w [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}
 
 # Preferences page
 'preferences' => 'Nastajenja',
-'mypreferences' => 'nastajenja',
+'mypreferences' => 'Nastajenja',
 'prefs-edits' => 'Licba wobźěłanjow:',
 'prefsnologin' => 'Njejsy pśizjawjony',
 'prefsnologintext' => 'Musyš se <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} pśizjawiś]</span>, aby mógał swóje nastajenja změniś.',
@@ -2039,7 +2039,7 @@ Glědaj teke [[Special:WantedCategories|póžedane kategorije]].',
 'linksearch-ok' => 'Pytaś',
 'linksearch-text' => 'Jo móžno zastupne znamuška kaž "*.wikipedia.org" wužywaś. 
 Jo nanejmjenjej głowna domena trěbna, na pśikład "*.org"<br />
-Pódpěrane protokole: <code>$1</code> (pšosym njepódaj je w swójom pytanju).',
+Pódpěrane protokole: <code>$1</code> (standard jo http://, jolic žeden protokol njejo pódany).',
 'linksearch-line' => '$1 wótkazany z $2',
 'linksearch-error' => 'Zasupne znamješko daju se jano na zachopjeńku URL wužywaś.',
 
@@ -2119,7 +2119,7 @@ E-mailowa adresa, kótaruž sy zapódał w [[Special:Preferences|swójich wužyw
 
 # Watchlist
 'watchlist' => 'Wobglědowańka',
-'mywatchlist' => 'wobglědowańka',
+'mywatchlist' => 'Wobglědowańka',
 'watchlistfor2' => 'Za wužywarja $1 $2',
 'nowatchlist' => 'Žedne zapise w twójej wobglědowańce.',
 'watchlistanontext' => 'Dejš $1, aby mógał swóju wobglědowańku wiźeś abo zapise w njej wobźěłaś.',
@@ -2368,7 +2368,7 @@ $1',
 # Contributions
 'contributions' => 'Wužywarske pśinoski',
 'contributions-title' => 'Wužywarske pśinoski wót $1',
-'mycontris' => 'móje pśinoski',
+'mycontris' => 'Pśinoski',
 'contribsub2' => 'Za $1 ($2)',
 'nocontribs' => 'Za toś te kriterije njejsu žedne změny se namakali.',
 'uctop' => '(aktualny)',
@@ -3807,4 +3807,6 @@ Hować móžoš slědujucy jadnory formular wužywaś. Twój komentar pśidajo s
 'duration-centuries' => '$1 {{PLURAL:$1|stolěśe|stolěśi|stolěśa|stolěśow}}',
 'duration-millennia' => '$1 {{PLURAL:$1|lěttysac|lěttysaca|lěttysace|lěttysacow}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'diskusija',
 );
index ab5e6a3..ec31872 100644 (file)
@@ -767,16 +767,17 @@ XHTML id names.
 
 'linkprefix' => '/^(.*?)([a-zA-Z\\x80-\\xff]+)$/sD', # only translate this message to other languages if you have to change it
 
-'about'         => 'About',
-'article'       => 'Content page',
-'newwindow'     => '(opens in new window)',
-'cancel'        => 'Cancel',
-'moredotdotdot' => 'More...',
-'mypage'        => 'Page',
-'mytalk'        => 'Talk',
-'anontalk'      => 'Talk for this IP address',
-'navigation'    => 'Navigation',
-'and'           => '&#32;and',
+'about'                => 'About',
+'article'              => 'Content page',
+'newwindow'            => '(opens in new window)',
+'cancel'               => 'Cancel',
+'moredotdotdot'        => 'More...',
+'mypage'               => 'Page',
+'mytalk'               => 'Talk',
+'mytalk-parenthetical' => 'talk',
+'anontalk'             => 'Talk for this IP address',
+'navigation'           => 'Navigation',
+'and'                  => '&#32;and',
 
 # Cologne Blue skin
 'qbfind'         => 'Find',
index a52f812..9b8ebd9 100644 (file)
@@ -1041,7 +1041,7 @@ La última entrada del registro de bloqueos se proporciona debajo para mayor ref
 * '''Opera:''' vacía la caché en ''Herramientas → Preferencias''",
 'usercssyoucanpreview' => "'''Consejo:''' Usa el botón «{{int:showpreview}}» para probar el nuevo CSS antes de guardarlo.",
 'userjsyoucanpreview' => "'''Consejo:''' Usa el botón «{{int:showpreview}}» para probar el nuevo JS antes de guardarlo.",
-'usercsspreview' => "'''Recuerda que solo estás previsualizando tu CSS de usuario.'''
+'usercsspreview' => "'''Recuerda que sólo estás previsualizando tu CSS de usuario.'''
 '''¡Aún no se ha guardado!'''",
 'userjspreview' => "'''¡Recuerda que solo estás previsualizando tu JavaScript de usuario.'''
 '''¡Aún no se ha guardado!'''",
@@ -1049,7 +1049,7 @@ La última entrada del registro de bloqueos se proporciona debajo para mayor ref
 '''¡Aún no se ha guardado!'''",
 'sitejspreview' => "'''Recuerda que sólo estás previsualizando este código JavaScript.'''
 '''¡Aún no se ha guardado!'''",
-'userinvalidcssjstitle' => "'''Aviso:''' No existe la skin «$1». Recuerda que las páginas personalizadas ''.css'' y ''.js'' tienen un título en minúsculas. Por ejemplo, {{ns:user}}:Ejemplo/vector.css en vez de {{ns:user}}:Ejemplo/Vector.css.",
+'userinvalidcssjstitle' => "'''Aviso:''' No existe la piel «$1». Recuerda que las páginas personalizadas ''.css'' y ''.js'' tienen un título en minúsculas. Por ejemplo, {{ns:user}}:Ejemplo/vector.css en vez de {{ns:user}}:Ejemplo/Vector.css.",
 'updated' => '(Actualizado)',
 'note' => "'''Nota:'''",
 'previewnote' => "'''Recuerda que esto es solo una previsualización.'''
@@ -1193,8 +1193,8 @@ El motivo dado por $3 es ''$2''",
 'page_first' => 'primeras',
 'page_last' => 'últimas',
 'histlegend' => "Selección de diferencias: marca los selectores de las versiones a comparar y pulsa ''enter'' o el botón de abajo.<br />
-Leyenda: (act) = diferencias con la versión actual,
-(prev) = diferencias con la versión previa, M = edición menor",
+Leyenda: '''(act)''' = diferencias con la versión actual,
+'''(ant)''' = diferencias con la versión anterior, '''m''' = edición menor",
 'history-fieldset-title' => 'Buscar en el historial',
 'history-show-deleted' => 'Solo ediciones ocultadas',
 'histfirst' => 'Primeras',
@@ -1257,7 +1257,7 @@ Aún tiene la posibilidad de verla; puede ampliar los detalles en el [{{fullurl:
 'revdelete-text' => "Las revisiones borradas aún aparecerán en el historial de la página y en los registros, pero sus contenidos no serán accesibles al público.'''
 Otros administradores de {{SITENAME}} aún podrán acceder al contenido oculto y podrán deshacer el borrado a través de la misma interfaz, a menos que se establezcan restricciones adicionales.",
 'revdelete-confirm' => 'Por favor confirma que deseas realizar la operación, que entiendes las consecuencias y que estás ejecutando dicha acción acorde con [[{{MediaWiki:Policy-url}}|las políticas]].',
-'revdelete-suppress-text' => "La herramienta de supresión '''sólo''' debería usarse en los siguientes casos:
+'revdelete-suppress-text' => "La herramienta de supresión '''solo''' debería usarse en los siguientes casos:
 * Información potencialmente injuriosa o calumniante.
 * Información personal inapropiada, tal como:
 *: ''nombres, domicilios, números de teléfono, números de la seguridad social e información análoga.",
@@ -2292,7 +2292,7 @@ Véase también las [[Special:WantedCategories|categorías requeridas]].',
 'linksearch-ok' => 'Buscar',
 'linksearch-text' => 'Se pueden usar caracteres comodín como "*.wikipedia.org".
 Es necesario, por lo menos, un dominio de alto nivel, por ejemplo "*.org".<br />
-Protocolos soportados: <code>$1</code> (si no se especidica ninguno, el protocolo por defecto es http://).',
+Protocolos soportados: <code>$1</code> (si no se especifica ninguno, el protocolo por defecto es http://).',
 'linksearch-line' => '$1 enlazado desde $2',
 'linksearch-error' => 'Los comodines sólo pueden aparecer al principio del nombre de sitio.',
 
@@ -2627,7 +2627,7 @@ $1',
 # Contributions
 'contributions' => 'Contribuciones {{GENDER:{{BASEPAGENAME}}|del usuario|de la usuaria}}',
 'contributions-title' => 'Contribuciones {{GENDER:$1|del usuario|de la usuaria}} $1',
-'mycontris' => 'Mis contribuciones',
+'mycontris' => 'Contribuciones',
 'contribsub2' => '$1 ($2)',
 'nocontribs' => 'No se encontraron cambios que cumplieran estos criterios.',
 'uctop' => '(última edición)',
index 3b321b4..5047cbb 100644 (file)
@@ -474,7 +474,7 @@ $messages = array(
 
 'underline-always' => 'همیشه',
 'underline-never' => 'هرگز',
-'underline-default' => 'پیش‌فرض مرورگر',
+'underline-default' => 'پوسته یا مرورگر پیش‌فرض',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'سبک قلم جعبهٔ ویرایش:',
@@ -559,8 +559,8 @@ $messages = array(
 'newwindow' => '(در پنجرهٔ جدید باز می‌شود)',
 'cancel' => 'لغو',
 'moredotdotdot' => 'بیشتر...',
-'mypage' => 'صفحهٔ من',
-'mytalk' => 'بحث من',
+'mypage' => 'صفحه',
+'mytalk' => 'بحث',
 'anontalk' => 'بحث برای این آی‌پی',
 'navigation' => 'گشتن',
 'and' => '&#32;و',
@@ -1114,7 +1114,7 @@ $2
 'userpage-userdoesnotexist-view' => 'حساب کاربری «$1» ثبت نشده‌است.',
 'blocked-notice-logextract' => 'دسترسی این کاربر در حال حاضر بسته است.
 آخرین مورد سیاهه قطع دسترسی در زیر آمده‌است:',
-'clearyourcache' => "''نکته:''' پس از ذخیره‌کردن ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.
+'clearyourcache' => "'''نکته:''' پس از ذخیره‌کردن ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.
 *'''فایرفاکس / سافاری:'''  کلید ''Shift'' را نگه دارید و روی دکمهٔ ''Reload'' کلیک کنید، یا کلید‌های ''Ctrl-F5'' یا ''Ctrl-R'' را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ''⌘-R'')
 *'''گوگل کروم:'''کلیدهای ''Ctrl+Shift+R'' را با هم فشار دهید. (در رایانه‌های اپل مکینتاش کلید‌های ''⌘-Shift-R'')
 *'''اینترنت اکسپلورر:''' کلید ''Ctrl'' را نگه‌دارید و روی دکمهٔ ''Refresh'' کلیک کنید، یا کلید‌های ''Ctrl-F5'' را با هم فشار دهید
@@ -1519,7 +1519,7 @@ $1",
 
 # Preferences page
 'preferences' => 'ترجیحات',
-'mypreferences' => 'ترجیحات من',
+'mypreferences' => 'ترجیحات',
 'prefs-edits' => 'تعداد ویرایش‌ها:',
 'prefsnologin' => 'به سامانه وارد نشده‌اید',
 'prefsnologintext' => 'برای تنظیم ترجیحات کاربر باید <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} به سامانه وارد شوید]</span>.',
@@ -1754,6 +1754,9 @@ $1",
 'rightslogtext' => 'این سیاههٔ تغییرات اختیارات کاربر است.',
 'rightslogentry' => 'عضویت $1 را از گروه $2 به $3 تغییر داد',
 'rightslogentry-autopromote' => 'به طور خودکار از $2 به $3 ارتقا یافت',
+'logentry-rights-rights' => '$1 عضویت $3 را از گروه $4 به $5 تغییر داد',
+'logentry-rights-rights-legacy' => '$1 گروه عضویت $3 را تغییر داد',
+'logentry-rights-autopromote' => '$1به طور خودکار از $4  به $5 ارتقا یافت',
 'rightsnone' => '(هیچ)',
 
 # Associated actions - in the sentence "You do not have permission to X"
@@ -2383,7 +2386,7 @@ https://www.mediawiki.org/wiki/Manual:Image_Authorization را ببینید.',
 'linksearch-ok' => 'جستجو',
 'linksearch-text' => 'نشانه‌هایی مانند «‎*.wikipedia.org» را می‌توان استفاده کرد.
 حداقل یک دامنه سطح بالا ، به عنوان مثال "*.org" نیاز دارد.<br />
-پرÙ\88تکÙ\84â\80\8cÙ\87اÛ\8c Ù¾Ø´ØªÛ\8cباÙ\86Û\8câ\80\8cشدÙ\87: <code>$1</code> (Ù\87Û\8cÚ\86 Û\8cÚ© Ø§Ø² Ø§Û\8cÙ\86 Ù\85Ù\88ارد Ø±Ø§ Ø¯Ø± Ø¬Ø³ØªØ¬Ù\88Û\8c Ø®Ù\88د Ù\86Û\8cاÙ\81زاÛ\8cÛ\8cد)',
+پرÙ\88تکÙ\84â\80\8cÙ\87اÛ\8c Ù¾Ø´ØªÛ\8cباÙ\86Û\8câ\80\8cشدÙ\87: <code>$1</code> (Ù¾Û\8cØ´â\80\8cÙ\81رض Ø¨Ø±Ø§Û\8c http:// Ø¯Ø± ØµÙ\88رت Ù\85شخص Ù\86شدÙ\86 Ù¾Ø±Ù\88تکÙ\84 ØªÙ\86ظÛ\8cÙ\85 Ø´Ø¯Ù\87â\80\8cاست)',
 'linksearch-line' => '$1 از $2 پیوند دارد',
 'linksearch-error' => 'نشانه‌ها فقط در ابتدای نام میزبان اینترنتی می‌توانند استفاده شوند.',
 
@@ -2464,7 +2467,7 @@ https://www.mediawiki.org/wiki/Manual:Image_Authorization را ببینید.',
 
 # Watchlist
 'watchlist' => 'فهرست پی‌گیری‌های من',
-'mywatchlist' => 'Ù¾Û\8câ\80\8cÚ¯Û\8cرÛ\8câ\80\8cÙ\87اÛ\8c Ù\85Ù\86',
+'mywatchlist' => 'Ù\81Ù\87رست Ù¾Û\8câ\80\8cÚ¯Û\8cرÛ\8câ\80\8cÙ\87ا',
 'watchlistfor2' => 'برای $1 $2',
 'nowatchlist' => 'در فهرست پی‌گیری‌های شما هیچ موردی نیست.',
 'watchlistanontext' => 'برای مشاهده و ویرایش فهرست پی‌گیری‌های خود از $1 استفاده کنید.',
@@ -2728,7 +2731,7 @@ $1',
 # Contributions
 'contributions' => 'مشارکت‌های کاربری',
 'contributions-title' => 'مشارکت‌های کاربری $1',
-'mycontris' => 'مشارکت‌های من',
+'mycontris' => 'مشارکت‌ها',
 'contribsub2' => 'برای $1 ($2)',
 'nocontribs' => 'هیچ تغییری با این مشخصات یافت نشد.',
 'uctop' => ' (بالا)',
@@ -2769,7 +2772,7 @@ $1',
 'whatlinkshere-hideredirs' => '$1 تغییرمسیر',
 'whatlinkshere-hidetrans' => '$1 تراگنجانش‌ها',
 'whatlinkshere-hidelinks' => '$1 پیوند',
-'whatlinkshere-hideimages' => '$1 پیوند به تصویر',
+'whatlinkshere-hideimages' => '$1 پیوندهای پرونده',
 'whatlinkshere-filters' => 'پالایه‌ها',
 
 # Block/unblock
@@ -3242,7 +3245,7 @@ $1',
 
 # Info page
 'pageinfo-title' => 'اطلاعات در مورد «$1»',
-'pageinfo-not-current' => 'اطلاعات ممکن است تنها برای نسخهٔ فعلی نمایش داده شود.',
+'pageinfo-not-current' => 'متاسفانه تهیه اطلاعات ویرایش‌های قدیمی غیرممکن است.',
 'pageinfo-header-basic' => 'اطلاعات اولیه',
 'pageinfo-header-edits' => 'ویرایش تاریخچه',
 'pageinfo-header-restrictions' => 'حفاظت از صفحه',
@@ -4036,6 +4039,7 @@ $5
 'version-license' => 'اجازه‌نامه',
 'version-poweredby-credits' => "این ویکی توسط '''[//www.mediawiki.org/ مدیاویکی]''' پشتیبانی می‌شود، کلیهٔ حقوق محفوظ است © 2001-$1 $2.",
 'version-poweredby-others' => 'دیگران',
+'version-credits-summary' => 'افراد زیر را به خاطر ویرایش‌هایش در [[Special:Version|مدیاویکی]] معرفی می‌نمائیم.',
 'version-license-info' => 'مدیاویکی نرم‌افزاری رایگان است؛ می‌توانید آن را تحت شرایط مجوز عمومی همگانی گنو که توسط بنیاد نرم‌افزار رایگان منتشر شده‌است، بازنشر کنید؛ یا نسخهٔ ۲ از این مجوز، یا (بنا به اختیار) نسخه‌های بعدی.
 
 مدیاویکی به این امید که مفید واقع شود منتشر شده‌است، ولی بدون هیچ‌گونه ضمانتی؛ بدون ضمانت ضمنی که تجاری یا برای کار خاصی مناسب باشد. برای اطلاعات بیشتر مجوز گنو جی‌پی‌ال را مشاهده کنید.
index 35f02ec..53a88c6 100644 (file)
@@ -879,7 +879,7 @@ Väliaikainen salasana: $2',
 'image_sample' => 'Esimerkki.jpg',
 'image_tip' => 'Tallennettu tiedosto',
 'media_sample' => 'Esimerkki.ogg',
-'media_tip' => 'Mediatiedostolinkki',
+'media_tip' => 'Tiedostolinkki',
 'sig_tip' => 'Allekirjoitus aikamerkinnällä',
 'hr_tip' => 'Vaakasuora viiva',
 
@@ -2181,7 +2181,7 @@ Katso myös [[Special:WantedCategories|halutut luokat]].',
 'linksearch-ok' => 'Etsi',
 'linksearch-text' => 'Tähteä (*) voi käyttää jokerimerkkinä, esimerkiksi ”*.wikipedia.org”.
 Vähintään ylätason verkkotunnus, esimerkiksi "*.org", tarvitaan.<br />
-Tuetut protokollat: <code>$1</code> (älä lisää näitä hakuusi).',
+Tuetut protokollat: <code>$1</code> (oletuksena on <code>http://</code>, jos protokollaa ei määritetä).',
 'linksearch-line' => '$1 on linkitetty sivulta $2',
 'linksearch-error' => 'Jokerimerkkiä voi käyttää ainoastaan osoitteen alussa.',
 
index be8f141..d25d3f3 100644 (file)
@@ -506,8 +506,8 @@ $messages = array(
 'newwindow' => '(ouvre une nouvelle fenêtre)',
 'cancel' => 'Annuler',
 'moredotdotdot' => 'Plus...',
-'mypage' => 'Ma page',
-'mytalk' => 'Page de discussion',
+'mypage' => 'Page',
+'mytalk' => 'Discussion',
 'anontalk' => 'Discussion avec cette adresse IP',
 'navigation' => 'Navigation',
 'and' => '&#32;et',
@@ -691,7 +691,7 @@ Une liste des pages spéciales valides se trouve sur [[Special:SpecialPages|{{in
 'error' => 'Erreur',
 'databaseerror' => 'Erreur de la base de données',
 'dberrortext' => "Une erreur de syntaxe de la requête dans la base de données est survenue.
-Ceci peut indiquer un bogue dans le logiciel.
+Ceci peut indiquer un bug dans le logiciel.
 La dernière requête traitée par la base de données était :
 <blockquote><code>$1</code></blockquote>
 depuis la fonction « <code>$2</code> ».
@@ -711,7 +711,7 @@ L'administrateur ayant verrouillé la base de données a fourni l'explication su
 
 Généralement, cela survient en suivant un lien vers un diff périmé ou vers l'historique d'une page supprimée.
 
-Si ce n'est pas le cas, il peut s'agir d'un bogue dans le programme.
+Si ce n'est pas le cas, il peut s'agir d'un bug dans le programme.
 Veuillez le signaler à un [[Special:ListUsers/sysop|administrateur]] sans oublier de lui indiquer l'URL du lien.",
 'missingarticle-rev' => '(numéro de version : $1)',
 'missingarticle-diff' => '(diff : $1, $2)',
@@ -781,27 +781,27 @@ L'administrateur qui l'a verrouillé a fourni ce motif: « $3 ».",
 
 Vous pouvez continuer à utiliser {{SITENAME}} de façon anonyme, <span class='plainlinks'>[$1 vous reconnecter]</span> sous le même nom ou un autre.
 Notez que certaines pages peuvent être encore affichées comme si vous étiez toujours connecté(e), jusqu'à ce que vous effaciez le cache de votre navigateur.",
-'welcomecreation' => '== Bienvenue, $1 ! ==
+'welcomecreation' => "== Bienvenue, $1 ! ==
 
 Votre compte a été créé.
-N’oubliez pas de personnaliser vos [[Special:Preferences|préférences sur {{SITENAME}}]].',
-'yourname' => 'Nom d’utilisateur :',
+N'oubliez pas de personnaliser vos [[Special:Preferences|préférences sur {{SITENAME}}]].",
+'yourname' => "Nom d'utilisateur :",
 'yourpassword' => 'Mot de passe&nbsp;:',
 'yourpasswordagain' => 'Confirmez le mot de passe :',
 'remembermypassword' => 'Me reconnecter automatiquement aux prochaines visites avec ce navigateur (au maximum $1&nbsp;{{PLURAL:$1|jour|jours}})',
 'securelogin-stick-https' => 'Rester connecté en HTTPS après la connexion',
 'yourdomainname' => 'Votre domaine :',
 'password-change-forbidden' => 'Vous ne pouvez pas modifier les mots de passe sur ce wiki.',
-'externaldberror' => 'Une erreur s’est produite avec la base de données d’authentification externe, ou bien vous n’êtes pas autorisé{{GENDER:||e|(e)}} à mettre à jour votre compte externe.',
+'externaldberror' => "Une erreur s'est produite avec la base de données d'authentification externe, ou bien vous n'êtes pas autorisé{{GENDER:||e|(e)}} à mettre à jour votre compte externe.",
 'login' => 'Connexion',
 'nav-login-createaccount' => 'Créer un compte ou se connecter',
-'loginprompt' => "Vous devez activer les témoins (''cookies'') pour vous connecter à {{SITENAME}}.",
+'loginprompt' => 'Vous devez activer les cookies pour vous connecter à {{SITENAME}}.',
 'userlogin' => 'Créer un compte ou se connecter',
 'userloginnocreate' => 'Connexion',
 'logout' => 'Se déconnecter',
 'userlogout' => 'Déconnexion',
 'notloggedin' => 'Non connecté',
-'nologin' => 'Vous n’êtes pas encore inscrit ? $1.',
+'nologin' => "Vous n'êtes pas encore inscrit ? $1.",
 'nologinlink' => 'Créer un compte',
 'createaccount' => 'Créer un compte',
 'gotaccount' => "Vous avez déjà un compte ? '''$1'''.",
@@ -810,51 +810,51 @@ N’oubliez pas de personnaliser vos [[Special:Preferences|préférences sur {{S
 'createaccountmail' => 'par courriel',
 'createaccountreason' => 'Motif :',
 'badretype' => 'Les mots de passe que vous avez saisis ne correspondent pas.',
-'userexists' => 'Nom d’utilisateur entré déjà utilisé.
-Veuillez choisir un nom différent.',
+'userexists' => "Nom d'utilisateur entré déjà utilisé.
+Veuillez choisir un nom différent.",
 'loginerror' => 'Erreur de connexion',
 'createaccounterror' => 'Impossible de créer le compte : $1',
-'nocookiesnew' => "Le compte utilisateur a été créé, mais vous n’êtes pas connecté{{GENDER:||e|(e)}}. {{SITENAME}} utilise des témoins (''cookies'') pour la connexion mais vous les avez désactivés. Veuillez les activer et vous reconnecter avec le même nom et le même mot de passe.",
-'nocookieslogin' => "{{SITENAME}} utilise des témoins (''cookies'') pour la connexion mais vous les avez désactivés. Veuillez les activer et vous reconnecter.",
-'nocookiesfornew' => 'Le compte utilisateur n’a pas été créé, car nous n’avons pas pu identifier son origine.
-Vérifiez que vous avez activé les cookies, rechargez la page et réessayez.',
-'noname' => 'Vous n’avez pas saisi un nom d’utilisateur valide.',
+'nocookiesnew' => "Le compte utilisateur a été créé, mais vous n'êtes pas connecté{{GENDER:||e|(e)}}. {{SITENAME}} utilise des cookies pour la connexion mais vous les avez désactivés. Veuillez les activer et vous reconnecter avec le même nom et le même mot de passe.",
+'nocookieslogin' => '{{SITENAME}} utilise des cookies pour la connexion mais vous les avez désactivés. Veuillez les activer et vous reconnecter.',
+'nocookiesfornew' => "Le compte utilisateur n'a pas été créé, car nous n'avons pas pu identifier son origine.
+Vérifiez que vous avez activé les cookies, rechargez la page et réessayez.",
+'noname' => "Vous n'avez pas saisi un nom d'utilisateur valide.",
 'loginsuccesstitle' => 'Connexion réussie',
 'loginsuccess' => 'Vous êtes maintenant connecté{{GENDER:$1||e|(e)}} à {{SITENAME}} en tant que « $1 ».',
-'nosuchuser' => 'L’utilisateur « $1 » n’existe pas.
-Les noms dutilisateurs sont sensibles à la casse.
-Vérifiez l’orthographe, ou [[Special:UserLogin/signup|créez un nouveau compte]].',
-'nosuchusershort' => 'Il n’y a pas de contributeur avec le nom « $1 ». Veuillez vérifier l’orthographe.',
-'nouserspecified' => 'Vous devez saisir un nom d’utilisateur.',
+'nosuchuser' => "L'utilisateur « $1 » n'existe pas.
+Les noms d'utilisateurs sont sensibles à la casse.
+Vérifiez l'orthographe, ou [[Special:UserLogin/signup|créez un nouveau compte]].",
+'nosuchusershort' => "Il n'y a pas de contributeur avec le nom « $1 ». Veuillez vérifier l'orthographe.",
+'nouserspecified' => "Vous devez saisir un nom d'utilisateur.",
 'login-userblocked' => 'Cet utilisateur est bloqué. Connexion non autorisée.',
 'wrongpassword' => 'Le mot de passe est incorrect. Veuillez essayer à nouveau.',
-'wrongpasswordempty' => 'Vous n’avez pas entré de mot de passe. Veuillez essayer à nouveau.',
+'wrongpasswordempty' => "Vous n'avez pas entré de mot de passe. Veuillez essayer à nouveau.",
 'passwordtooshort' => 'Votre mot de passe doit contenir au moins $1 caractère{{PLURAL:$1||s}}.',
-'password-name-match' => 'Votre mot de passe doit être différent de votre nom d’utilisateur.',
-'password-login-forbidden' => "Lutilisation de ce nom d'utilisateur et de ce mot de passe a été interdite.",
+'password-name-match' => "Votre mot de passe doit être différent de votre nom d'utilisateur.",
+'password-login-forbidden' => "L'utilisation de ce nom d'utilisateur et de ce mot de passe a été interdite.",
 'mailmypassword' => 'Recevoir un nouveau mot de passe par courriel',
 'passwordremindertitle' => 'Nouveau mot de passe temporaire pour {{SITENAME}}',
-'passwordremindertext' => 'Quelqu’un (probablement vous, ayant l’adresse IP $1) a demandé un nouveau mot de
+'passwordremindertext' => "Quelqu'un (probablement vous, ayant l'adresse IP $1) a demandé un nouveau mot de
 passe pour {{SITENAME}} ($4 ). Un mot de passe temporaire a été créé pour
-lutilisateur « $2 » et est « $3 ». Si cela était votre intention, vous devrez
+l'utilisateur « $2 » et est « $3 ». Si cela était votre intention, vous devrez
 vous connecter et choisir un nouveau mot de passe.
 Votre mot de passe temporaire expirera dans $5 jour{{PLURAL:$5||s}}.
 
-Si vous n’êtes pas l’auteur de cette demande, ou si vous vous souvenez à présent
+Si vous n'êtes pas l'auteur de cette demande, ou si vous vous souvenez à présent
 de votre ancien mot de passe et que vous ne souhaitez plus en changer, vous
-pouvez ignorer ce message et continuer à utiliser votre ancien mot de passe.',
-'noemail' => "Aucune adresse de courriel na été enregistrée pour l'utilisateur « $1 ».",
+pouvez ignorer ce message et continuer à utiliser votre ancien mot de passe.",
+'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 ». Veuillez vous reconnecter après l'avoir reçu.",
 'blocked-mailpassword' => 'Votre adresse IP est bloquée en écriture, la fonction de rappel du mot de passe est donc désactivée pour éviter les abus.',
-'eauthentsent' => 'Un courriel de confirmation a été envoyé à l’adresse indiquée.
-Avant 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 rappel de votre mot de passe a déjà été envoyé durant {{PLURAL:$1|la dernière heure|les $1 dernières heures}}. Afin d’éviter les abus, un seul courriel de rappel sera envoyé par {{PLURAL:$1|heure|intervalle de $1 heures}}.',
-'mailerror' => 'Erreur lors de l’envoi du courriel : $1',
-'acct_creation_throttle_hit' => 'Quelqu’un utilisant votre adresse IP a créé {{PLURAL:$1|un compte|$1 comptes}} au cours des dernières 24 heures, ce qui constitue la limite autorisée dans cet intervalle de temps.
-Par conséquent, la création de compte a été temporairement désactivée pour cette adresse IP.',
+'eauthentsent' => "Un courriel de confirmation a été envoyé à l'adresse indiquée.
+Avant 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 rappel de votre mot de passe a déjà été envoyé durant {{PLURAL:$1|la dernière heure|les $1 dernières heures}}. Afin d'éviter les abus, un seul courriel de rappel sera envoyé par {{PLURAL:$1|heure|intervalle de $1 heures}}.",
+'mailerror' => "Erreur lors de l'envoi du courriel : $1",
+'acct_creation_throttle_hit' => "Quelqu'un utilisant votre adresse IP a créé {{PLURAL:$1|un compte|$1 comptes}} au cours des dernières 24 heures, ce qui constitue la limite autorisée dans cet intervalle de temps.
+Par conséquent, la création de compte a été temporairement désactivée pour cette adresse IP.",
 'emailauthenticated' => 'Votre adresse de courriel a été authentifiée le $2 à $3.',
-'emailnotauthenticated' => 'Votre adresse de courriel n’est <strong>pas encore authentifiée</strong>. Aucun courriel ne sera envoyé pour chacune des fonctions suivantes.',
+'emailnotauthenticated' => "Votre adresse de courriel n'est <strong>pas encore authentifiée</strong>. Aucun courriel ne sera envoyé pour chacune des fonctions suivantes.",
 'noemailprefs' => 'Indiquez une adresse de courriel dans vos préférences pour utiliser ces fonctions.',
 'emailconfirmlink' => 'Confirmez votre adresse de courriel',
 'invalidemailaddress' => 'Cette adresse courriel ne peut pas être acceptée car elle semble avoir un format incorrect.
@@ -863,25 +863,25 @@ Entrez une adresse bien formatée ou laissez ce champ vide.',
 'emaildisabled' => 'Ce site ne peut pas envoyer de courriels.',
 'accountcreated' => 'Compte créé',
 'accountcreatedtext' => 'Le compte utilisateur pour $1 a été créé.',
-'createaccount-title' => 'Création d’un compte pour {{SITENAME}}',
-'createaccount-text' => 'Quelqu’un a créé un compte pour votre adresse de courriel sur {{SITENAME}} ($4) intitulé « $2 », avec le mot de passe « $3 ».
+'createaccount-title' => "Création d'un compte pour {{SITENAME}}",
+'createaccount-text' => "Quelqu'un a créé un compte pour votre adresse de courriel sur {{SITENAME}} ($4) intitulé « $2 », avec le mot de passe « $3 ».
 Vous devriez ouvrir une session et modifier dès à présent votre mot de passe.
 
-Ignorez ce message si ce compte a été créé par erreur.',
-'usernamehasherror' => 'Le nom d’utilisateur ne peut pas contenir des caractères de hachage',
-'login-throttled' => 'Vous avez tenté un trop grand nombre de connexions dernièrement.
-Veuillez attendre avant d’essayer à nouveau.',
+Ignorez ce message si ce compte a été créé par erreur.",
+'usernamehasherror' => "Le nom d'utilisateur ne peut pas contenir des caractères de hachage",
+'login-throttled' => "Vous avez tenté un trop grand nombre de connexions dernièrement.
+Veuillez attendre avant d'essayer à nouveau.",
 'login-abort-generic' => 'Votre tentative de connexion a échoué',
 'loginlanguagelabel' => 'Langue : $1',
-'suspicious-userlogout' => 'Votre demande de déconnexion a été refusée car il semble qu’elle a été envoyée par un navigateur cassé ou la mise en cache d’un proxy.',
+'suspicious-userlogout' => "Votre demande de déconnexion a été refusée car il semble qu'elle a été envoyée par un navigateur cassé ou la mise en cache d'un proxy.",
 
 # E-mail sending
 'php-mail-error-unknown' => 'Erreur inconnue dans la fonction mail() de PHP.',
-'user-mail-no-addy' => 'Tenté d’envoyer un courriel sans adresse de courriel',
+'user-mail-no-addy' => "Tenté d'envoyer un courriel sans adresse de courriel",
 
 # Change password dialog
 'resetpass' => 'Changer de mot de passe',
-'resetpass_announce' => 'Vous vous êtes enregistré{{GENDER:||e|(e)}} avec un mot de passe temporaire envoyé par courriel. Pour terminer l’enregistrement, vous devez entrer un nouveau mot de passe ici :',
+'resetpass_announce' => "Vous vous êtes enregistré{{GENDER:||e|(e)}} avec un mot de passe temporaire envoyé par courriel. Pour terminer l'enregistrement, vous devez entrer un nouveau mot de passe ici :",
 'resetpass_text' => '<!-- Ajoutez le texte ici -->',
 'resetpass_header' => 'Changer le mot de passe du compte',
 'oldpassword' => 'Ancien mot de passe :',
@@ -903,37 +903,37 @@ Vous avez peut-être déjà changé votre mot de passe ou demandé un nouveau mo
 'passwordreset-legend' => 'Remise à zéro du mot de passe',
 'passwordreset-disabled' => 'La réinitialisation des mots de passe a été désactivée sur ce wiki.',
 'passwordreset-pretext' => '{{PLURAL:$1||Entrez un élément de données ci-dessous}}',
-'passwordreset-username' => 'Nom d’utilisateur :',
+'passwordreset-username' => "Nom d'utilisateur :",
 'passwordreset-domain' => 'Domaine :',
 'passwordreset-capture' => 'Voir le courriel résultant?',
-'passwordreset-capture-help' => 'Si vous cochez cette case, le courriel (avec le mot de passe temporaire) vous sera affiché en même temps qu’il sera envoyé à l’utilisateur.',
+'passwordreset-capture-help' => "Si vous cochez cette case, le courriel (avec le mot de passe temporaire) vous sera affiché en même temps qu'il sera envoyé à l'utilisateur.",
 'passwordreset-email' => 'Adresse de courriel :',
 'passwordreset-emailtitle' => 'Détails du compte sur {{SITENAME}}',
-'passwordreset-emailtext-ip' => 'Quelqu’un (probablement vous, depuis l’adresse IP $1) a demandé un rappel des informations de votre compte pour {{SITENAME}} ($4). {{PLURAL:$3|Le compte utilisateur suivant est associé|Les comptes utilisateurs suivants sont associés}} à cette adresse de courriel :
+'passwordreset-emailtext-ip' => "Quelqu'un (probablement vous, depuis l'adresse IP $1) a demandé un rappel des informations de votre compte pour {{SITENAME}} ($4). {{PLURAL:$3|Le compte utilisateur suivant est associé|Les comptes utilisateurs suivants sont associés}} à cette adresse de courriel :
 
 $2
 
-{{PLURAL:$3|Ce mot de passe temporaire expirera|Ces mots de passe temporaires expireront}} dans {{PLURAL:$5|un jour|$5 jours}}. Vous devez maintenant vous connecter et choisir un nouveau mot de passe. Si cette demande ne provient pas de vous, ou que vous vous êtes souvenu de votre mot de passe initial, et ne souhaitez plus le modifier, vous pouvez ignorer ce message et continuer à utiliser votre ancien mot de passe.',
-'passwordreset-emailtext-user' => 'L’utilisateur $1 sur {{SITENAME}} a demandé un rappel des informations de votre compte pour {{SITENAME}} ($4). {{PLURAL:$3|Le compte utilisateur suivant est associé|Les comptes utilisateurs suivants sont associés}} à cette adresse de courriel :
+{{PLURAL:$3|Ce mot de passe temporaire expirera|Ces mots de passe temporaires expireront}} dans {{PLURAL:$5|un jour|$5 jours}}. Vous devez maintenant vous connecter et choisir un nouveau mot de passe. Si cette demande ne provient pas de vous, ou que vous vous êtes souvenu de votre mot de passe initial, et ne souhaitez plus le modifier, vous pouvez ignorer ce message et continuer à utiliser votre ancien mot de passe.",
+'passwordreset-emailtext-user' => "L'utilisateur $1 sur {{SITENAME}} a demandé un rappel des informations de votre compte pour {{SITENAME}} ($4). {{PLURAL:$3|Le compte utilisateur suivant est associé|Les comptes utilisateurs suivants sont associés}} à cette adresse de courriel :
 
 $2
 
-{{PLURAL:$3|Ce mot de passe temporaire expirera|Ces mots de passe temporaires expireront}} dans {{PLURAL:$5|un jour|$5 jours}}. Vous devez maintenant vous connecter et choisir un nouveau mot de passe. Si cette demande ne provient pas de vous, ou que vous vous êtes souvenu de votre mot de passe initial, et ne souhaitez plus le modifier, vous pouvez ignorer ce message et continuer à utiliser votre ancien mot de passe.',
-'passwordreset-emailelement' => 'Nom d’utilisateur : $1
-Mot de passe temporaire : $2',
+{{PLURAL:$3|Ce mot de passe temporaire expirera|Ces mots de passe temporaires expireront}} dans {{PLURAL:$5|un jour|$5 jours}}. Vous devez maintenant vous connecter et choisir un nouveau mot de passe. Si cette demande ne provient pas de vous, ou que vous vous êtes souvenu de votre mot de passe initial, et ne souhaitez plus le modifier, vous pouvez ignorer ce message et continuer à utiliser votre ancien mot de passe.",
+'passwordreset-emailelement' => "Nom d'utilisateur : $1
+Mot de passe temporaire : $2",
 'passwordreset-emailsent' => 'Un courriel de rappel a été envoyé.',
 'passwordreset-emailsent-capture' => 'Un courriel de rappel a été envoyé, qui est affiché ci-dessous.',
-'passwordreset-emailerror-capture' => 'Un courriel de rappel a été généré, qui est affiché ci-dessous, mais l’envoi à l’utilisateur a échoué : $1',
+'passwordreset-emailerror-capture' => "Un courriel de rappel a été généré, qui est affiché ci-dessous, mais l'envoi à l'utilisateur a échoué : $1",
 
 # Special:ChangeEmail
-'changeemail' => 'Changer l’adresse de courriel',
-'changeemail-header' => 'Changer l’adresse de courriel du compte',
+'changeemail' => "Changer l'adresse de courriel",
+'changeemail-header' => "Changer l'adresse de courriel du compte",
 'changeemail-text' => 'Remplissez ce formulaire pour changer votre adresse de courriel. Vous devrez entrer votre mot de passe pour confirmer ce changement.',
 'changeemail-no-info' => 'Vous devez être connecté pour pouvoir accéder directement à cette page.',
 'changeemail-oldemail' => 'Adresse de courriel actuelle :',
 'changeemail-newemail' => 'Nouvelle adresse de courriel :',
 'changeemail-none' => '(aucune)',
-'changeemail-submit' => 'Changer l’adresse de courriel',
+'changeemail-submit' => "Changer l'adresse de courriel",
 'changeemail-cancel' => 'Annuler',
 
 # Edit page toolbar
@@ -944,7 +944,7 @@ Mot de passe temporaire : $2',
 'link_sample' => 'Titre du lien',
 'link_tip' => 'Lien interne',
 'extlink_sample' => 'http://www.example.com titre du lien',
-'extlink_tip' => 'Lien externe (n’oubliez pas le préfixe http://)',
+'extlink_tip' => "Lien externe (n'oubliez pas le préfixe http://)",
 'headline_sample' => 'Texte du titre',
 'headline_tip' => 'Sous-titre niveau 2',
 'nowiki_sample' => 'Entrez le texte non formaté ici',
@@ -966,16 +966,16 @@ Mot de passe temporaire : $2',
 'showpreview' => 'Prévisualiser',
 'showlivepreview' => 'Aperçu rapide',
 'showdiff' => 'Modifications en cours',
-'anoneditwarning' => "'''Attention :''' vous n’êtes pas identifié(e). Votre adresse IP sera enregistrée dans l’historique de cette page.",
-'anonpreviewwarning' => "''Vous n’êtes pas identifié. Sauvegarder enregistrera votre adresse IP dans l’historique des modifications de la page.''",
-'missingsummary' => "'''Rappel :''' vous navez pas encore fourni le résumé de votre modification.
+'anoneditwarning' => "'''Attention :''' vous n'êtes pas identifié(e). Votre adresse IP sera enregistrée dans l'historique de cette page.",
+'anonpreviewwarning' => "''Vous n'êtes pas identifié. Sauvegarder enregistrera votre adresse IP dans l'historique des modifications de la page.''",
+'missingsummary' => "'''Rappel :''' vous n'avez pas encore fourni le résumé de votre modification.
 Si vous cliquez de nouveau sur le bouton « {{int:savearticle}} », la publication sera faite sans nouvel avertissement.",
 'missingcommenttext' => 'Veuillez entrer un commentaire ci-dessous.',
-'missingcommentheader' => "'''Rappel :''' vous navez pas fourni de sujet ou de titre à ce commentaire.
+'missingcommentheader' => "'''Rappel :''' vous n'avez pas fourni de sujet ou de titre à ce commentaire.
 Si vous cliquez de nouveau sur « {{int:Savearticle}} », votre modification sera enregistrée sans titre.",
 'summary-preview' => 'Aperçu du résumé :',
 'subject-preview' => 'Prévisualisation du sujet/titre :',
-'blockedtitle' => 'L’utilisateur est bloqué.',
+'blockedtitle' => "L'utilisateur est bloqué.",
 'blockedtext' => "'''Votre compte utilisateur ou votre adresse IP a été bloqué.'''
 
 Le blocage a été effectué par $1.
@@ -986,7 +986,7 @@ La raison invoquée est la suivante : ''$2''.
 * Compte bloqué : $7.
 
 Vous pouvez contacter $1 ou un autre [[{{MediaWiki:Grouppage-sysop}}|administrateur]] pour en discuter.
-Vous ne pouvez utiliser la fonction « {{MediaWiki:emailpage}} » que si une adresse de courriel valide est spécifiée dans vos [[Special:Preferences|préférences]] et que cette fonctionnalité na pas été bloquée.
+Vous ne pouvez utiliser la fonction « {{MediaWiki:emailpage}} » que si une adresse de courriel valide est spécifiée dans vos [[Special:Preferences|préférences]] et que cette fonctionnalité n'a pas été bloquée.
 Votre adresse IP actuelle est $3 et votre identifiant de blocage est $5.
 Veuillez préciser ces indications dans toutes les requêtes que vous ferez.",
 'autoblockedtext' => "Votre adresse IP a été bloquée automatiquement car elle a été utilisée par un autre utilisateur, lui-même bloqué par $1.
@@ -998,9 +998,9 @@ La raison invoquée est :
 * Expiration du blocage : $6
 * Compte bloqué : $7
 
-Vous pouvez contacter $1 ou lun des autres [[{{MediaWiki:Grouppage-sysop}}|administrateurs]] pour discuter de ce blocage.
+Vous pouvez contacter $1 ou l'un des autres [[{{MediaWiki:Grouppage-sysop}}|administrateurs]] pour discuter de ce blocage.
 
-Notez que vous ne pourrez utiliser la fonctionnalité d’envoi de courriel que si vous avez une adresse de courriel validée dans vos [[Special:Preferences|préférences]] et que la fonctionnalité n’a pas été désactivée.
+Notez que vous ne pourrez utiliser la fonctionnalité d'envoi de courriel que si vous avez une adresse de courriel validée dans vos [[Special:Preferences|préférences]] et que la fonctionnalité n'a pas été désactivée.
 
 Votre adresse IP actuelle est $3, et le numéro de blocage est $5.
 Veuillez préciser ces indications dans toutes les requêtes que vous ferez.",
@@ -1009,100 +1009,100 @@ Veuillez préciser ces indications dans toutes les requêtes que vous ferez.",
 'confirmedittext' => 'Vous devez confirmer votre adresse de courriel avant de modifier les pages.
 Veuillez entrer et valider votre adresse de courriel dans vos [[Special:Preferences|préférences]].',
 'nosuchsectiontitle' => 'Impossible de trouver la section',
-'nosuchsectiontext' => 'Vous avez essayé de modifier une section qui n’existe pas.
-Elle a peut-être été déplacée ou supprimée depuis que vous avez lu cette page.',
+'nosuchsectiontext' => "Vous avez essayé de modifier une section qui n'existe pas.
+Elle a peut-être été déplacée ou supprimée depuis que vous avez lu cette page.",
 'loginreqtitle' => 'Connexion nécessaire',
 'loginreqlink' => 'connecter',
 'loginreqpagetext' => 'Vous devez vous $1 pour voir les autres pages.',
 'accmailtitle' => 'Mot de passe envoyé.',
 'accmailtext' => "Un mot de passe généré aléatoirement pour [[User talk:$1|$1]] a été envoyé à $2.
-Le mot de passe pour ce nouveau compte peut être changé sur la page ''[[Special:ChangePassword|de changement de mot de passe]]'' après sêtre connecté.",
+Le mot de passe pour ce nouveau compte peut être changé sur la page ''[[Special:ChangePassword|de changement de mot de passe]]'' après s'être connecté.",
 'newarticle' => '(Nouveau)',
-'newarticletext' => "Vous avez suivi un lien vers une page qui nexiste pas encore ou qui a été [{{fullurl:Special:Log|type=delete&page={{FULLPAGENAMEE}}}} effacée].
-Pour créer cette page, entrez votre texte dans la boîte ci-dessous (vous pouvez consulter [[{{MediaWiki:Helppage}}|la page d’aide]] pour plus d’informations).
+'newarticletext' => "Vous avez suivi un lien vers une page qui n'existe pas encore ou qui a été [{{fullurl:Special:Log|type=delete&page={{FULLPAGENAMEE}}}} effacée].
+Pour créer cette page, entrez votre texte dans la boîte ci-dessous (vous pouvez consulter [[{{MediaWiki:Helppage}}|la page d'aide]] pour plus d'informations).
 Si vous êtes arrivé{{GENDER:||e|(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.''",
-'noarticletext' => 'Il n’y a pour l’instant aucun texte sur cette page.
+'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.''",
+'noarticletext' => 'Il n\'y a pour l\'instant aucun texte sur cette page.
 Vous pouvez [[Special:Search/{{PAGENAME}}|lancer une recherche sur ce titre]] dans les autres pages,
 <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rechercher dans les opérations liées]
 ou [{{fullurl:{{FULLPAGENAME}}|action=edit}} créer cette page]</span>.',
-'noarticletext-nopermission' => 'Il n’y a pour l’instant aucun texte sur cette page.
+'noarticletext-nopermission' => 'Il n\'y a pour l\'instant aucun texte sur cette page.
 Vous pouvez [[Special:Search/{{PAGENAME}}|faire une recherche sur ce titre]] dans les autres pages,
 ou <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 « {{PAGENAME}} » n'existe pas.
 
 Cela survient en général en suivant un lien historique obsolète vers une page qui a été supprimée.
 Vous pouvez trouver plus de détails dans le [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} journal des suppressions].",
-'userpage-userdoesnotexist' => 'Le compte utilisateur « <nowiki>$1</nowiki> » n’est pas enregistré. Veuillez vérifier que vous voulez créer cette page.',
-'userpage-userdoesnotexist-view' => 'Le compte utilisateur « $1 » n’est pas enregistré.',
-'blocked-notice-logextract' => 'Cet utilisateur est actuellement bloqué.
-La dernière entrée du registre des blocages est indiquée ci-dessous à titre d’information :',
+'userpage-userdoesnotexist' => "Le compte utilisateur « <nowiki>$1</nowiki> » n'est pas enregistré. Veuillez vérifier que vous voulez créer cette page.",
+'userpage-userdoesnotexist-view' => "Le compte utilisateur « $1 » n'est pas enregistré.",
+'blocked-notice-logextract' => "Cet utilisateur est actuellement bloqué.
+La dernière entrée du registre des blocages est indiquée ci-dessous à titre d'information :",
 'clearyourcache' => "'''Note :''' après avoir enregistré vos préférences, vous devrez forcer le rechargement complet du cache de votre navigateur pour voir les changements.
 * '''Firefox / Safari :''' Maintenez la touche ''Maj'' (''Shift'') en cliquant sur le bouton ''Actualiser'' ou pressez ''Ctrl-F5'' ou ''Ctrl-R'' (''⌘-R'' sur un Mac) ;
 * '''Google Chrome :''' Appuyez sur ''Ctrl-Maj-R'' (''⌘-Shift-R'' sur un Mac) ;
 * '''Internet Explorer :''' Maintenez la touche ''Ctrl'' en cliquant sur le bouton ''Actualiser'' ou pressez ''Ctrl-F5'' ;
 * '''Opera :''' Videz le cache dans ''Outils → Préférences''.",
-'usercssyoucanpreview' => "'''Astuce :''' utilisez le bouton « {{int:showpreview}} » pour tester votre nouvelle feuille CSS avant de lenregistrer.",
-'userjsyoucanpreview' => "'''Astuce :''' utilisez le bouton « {{int:showpreview}} » pour tester votre nouvelle feuille JavaScript avant de lenregistrer.",
-'usercsspreview' => "'''Rappelez-vous que vous n’êtes qu’en train de prévisualiser votre propre feuille CSS.'''
-'''Elle na pas encore été enregistrée !'''",
-'userjspreview' => "'''Rappelez-vous que vous êtes en train de visualiser ou de tester votre code JavaScript et qu’il n’a pas encore été enregistré !'''",
+'usercssyoucanpreview' => "'''Astuce :''' utilisez le bouton « {{int:showpreview}} » pour tester votre nouvelle feuille CSS avant de l'enregistrer.",
+'userjsyoucanpreview' => "'''Astuce :''' utilisez le bouton « {{int:showpreview}} » pour tester votre nouvelle feuille JavaScript avant de l'enregistrer.",
+'usercsspreview' => "'''Rappelez-vous que vous n'êtes qu'en train de prévisualiser votre propre feuille CSS.'''
+'''Elle n'a pas encore été enregistrée !'''",
+'userjspreview' => "'''Rappelez-vous que vous êtes en train de visualiser ou de tester votre code JavaScript et qu'il n'a pas encore été enregistré !'''",
 'sitecsspreview' => "'''Souvenez-vous que vous êtes seulement en train de prévisualiser cette feuille de style.'''
-'''Elle na pas encore été enregistrée !'''",
+'''Elle n'a pas encore été enregistrée !'''",
 'sitejspreview' => "'''Souvenez-vous que vous êtes seulement en train de prévisualiser ce code JavaScript.'''
-'''Il na pas encore été enregistré !'''",
-'userinvalidcssjstitle' => "'''Attention :''' il n’existe pas d’habillage « $1 ». Rappelez-vous que les pages personnelles avec extensions .css et .js utilisent des titres en minuscules, par exemple {{ns:user}}:Foo/vector.css et non {{ns:user}}:Foo/Vector.css.",
+'''Il n'a pas encore été enregistré !'''",
+'userinvalidcssjstitle' => "'''Attention :''' il n'existe pas d'habillage « $1 ». Rappelez-vous que les pages personnelles avec extensions .css et .js utilisent des titres en minuscules, par exemple {{ns:user}}:Foo/vector.css et non {{ns:user}}:Foo/Vector.css.",
 'updated' => '(Mis à jour)',
 'note' => "'''Note :'''",
-'previewnote' => "'''Rappelez-vous que ce n’est qu’une prévisualisation.'''
-Vos modifications nont pas encore été enregistrées !",
+'previewnote' => "'''Rappelez-vous que ce n'est qu'une prévisualisation.'''
+Vos modifications n'ont pas encore été enregistrées !",
 'continue-editing' => 'Aller à la zone de modification',
-'previewconflict' => 'Cette prévisualisation montre le texte de la boîte supérieure de modification tel qu’il apparaîtra si vous choisissez de le publier.',
-'session_fail_preview' => "'''Nous ne pouvons enregistrer votre modification à cause d’une perte d’informations concernant votre session.'''
+'previewconflict' => "Cette prévisualisation montre le texte de la boîte supérieure de modification tel qu'il apparaîtra si vous choisissez de le publier.",
+'session_fail_preview' => "'''Nous ne pouvons enregistrer votre modification à cause d'une perte d'informations concernant votre session.'''
 Veuillez réessayer.
 Si cela échoue de nouveau, essayez en vous [[Special:UserLogout|déconnectant]], puis en vous reconnectant.",
-'session_fail_preview_html' => "'''Nous ne pouvons enregistrer votre modification à cause d’une perte d’informations concernant votre session.'''
+'session_fail_preview_html' => "'''Nous ne pouvons enregistrer votre modification à cause d'une perte d'informations concernant votre session.'''
 
 ''Parce que {{SITENAME}} a activé le HTML brut, la prévisualisation a été masquée afin de prévenir les attaques par JavaScript.''
 
 '''Si la tentative de modification était légitime, veuillez réessayer.'''
 Si cela échoue de nouveau, [[Special:UserLogout|déconnectez-vous]], puis reconnectez-vous.",
-'token_suffix_mismatch' => "'''Votre modification n’a pas été acceptée car votre navigateur a mal codé les caractères de ponctuation dans l’identifiant de modification.'''
+'token_suffix_mismatch' => "'''Votre modification n'a pas été acceptée car votre navigateur a mal codé les caractères de ponctuation dans l'identifiant de modification.'''
 Ce rejet est nécessaire pour empêcher la corruption du texte de la page.
 Ce problème se produit parfois lorsque vous utilisez un serveur mandataire anonyme problématique basé sur le web.",
-'edit_form_incomplete' => "'''Certaines parties du formulaire de modification nont pas atteint le serveur, vérifiez que vos modifications sont intactes et essayez à nouveau.'''",
+'edit_form_incomplete' => "'''Certaines parties du formulaire de modification n'ont pas atteint le serveur, vérifiez que vos modifications sont intactes et essayez à nouveau.'''",
 'editing' => 'Modification de $1',
 'creating' => 'Création de $1',
 'editingsection' => 'Modification de $1 (section)',
 'editingcomment' => 'Modification de $1 (nouvelle section)',
 'editconflict' => 'Conflit de modification : $1',
 'explainconflict' => "Cette page a été changée après que vous ayez commencé à la modifier.
-La zone de modification supérieure contient le texte tel quil est actuellement enregistré dans la base de données.
+La zone de modification supérieure contient le texte tel qu'il est actuellement enregistré dans la base de données.
 Vos modifications apparaissent dans la zone de modification inférieure.
 Vous allez devoir fusionner vos modifications dans le texte existant.
 '''Seul''' le texte de la zone supérieure sera sauvegardé si vous cliquez sur « {{int:savearticle}} ».",
 'yourtext' => 'Votre texte',
 'storedversion' => 'La version enregistrée',
-'nonunicodebrowser' => "'''Attention : Votre navigateur ne supporte pas lUnicode.'''
+'nonunicodebrowser' => "'''Attention : Votre navigateur ne supporte pas l'Unicode.'''
 Une solution de rechange a été trouvée pour vous permettre de modifier en toute sûreté une page : les caractères non-ASCII apparaîtront dans votre boîte de modification en tant que codes hexadécimaux. Vous devriez utiliser un navigateur plus récent.",
 'editingold' => "'''Attention : vous êtes en train de modifier une ancienne version de cette page.
 Si vous la publiez, toutes les modifications effectuées depuis cette version seront perdues.'''",
 'yourdiff' => 'Différences',
 'copyrightwarning' => "Toutes les contributions à {{SITENAME}} sont considérées comme publiées sous les termes de la $2 (voir $1 pour plus de détails). Si vous ne désirez pas que vos écrits soient modifiés et distribués à volonté, merci de ne pas les soumettre ici.<br />
-Vous nous promettez aussi que vous avez écrit ceci vous-même, ou que vous l’avez copié d’une source provenant du domaine public, ou d’une ressource libre. '''N’UTILISEZ PAS DE TRAVAUX SOUS DROIT D’AUTEUR SANS AUTORISATION EXPRESSE !'''",
-'copyrightwarning2' => "Toutes les contributions à {{SITENAME}} peuvent être modifiées ou supprimées par dautres utilisateurs. Si vous ne désirez pas que vos écrits soient modifiés et distribués à volonté, merci de ne pas les soumettre ici.<br />
-Vous nous promettez aussi que vous avez écrit ceci vous-même, ou que vous l’avez copié d’une source provenant du domaine public, ou d’une ressource libre. (voir $1 pour plus de détails).
-'''N’UTILISEZ PAS DE TRAVAUX SOUS DROIT D’AUTEUR SANS AUTORISATION EXPRESSE !'''",
+Vous nous promettez aussi que vous avez écrit ceci vous-même, ou que vous l'avez copié d'une source provenant du domaine public, ou d'une ressource libre. '''N'UTILISEZ PAS DE TRAVAUX SOUS DROIT D'AUTEUR SANS AUTORISATION EXPRESSE !'''",
+'copyrightwarning2' => "Toutes les contributions à {{SITENAME}} peuvent être modifiées ou supprimées par d'autres utilisateurs. Si vous ne désirez pas que vos écrits soient modifiés et distribués à volonté, merci de ne pas les soumettre ici.<br />
+Vous nous promettez aussi que vous avez écrit ceci vous-même, ou que vous l'avez copié d'une source provenant du domaine public, ou d'une ressource libre. (voir $1 pour plus de détails).
+'''N'UTILISEZ PAS DE TRAVAUX SOUS DROIT D'AUTEUR SANS AUTORISATION EXPRESSE !'''",
 'longpageerror' => "'''Erreur: Le texte que vous avez soumis fait {{PLURAL:$1|un Kio|$1 Kio}}, ce qui dépasse la limite fixée à {{PLURAL:$2|un Kio|$2 Kio}}.'''
 Il ne peut pas être sauvegardé.",
-'readonlywarning' => "'''AVERTISSEMENT : la base de données a été verrouillée pour des opérations de maintenance. Vous ne pouvez donc pas publier vos modifications pour linstant.'''
+'readonlywarning' => "'''AVERTISSEMENT : la base de données a été verrouillée pour des opérations de maintenance. Vous ne pouvez donc pas publier vos modifications pour l'instant.'''
 Vous pouvez copier le texte dans un fichier texte et le conserver pour plus tard.
 
-L’administrateur ayant verrouillé la base de données a donné l’explication suivante : $1",
-'protectedpagewarning' => "'''AVERTISSEMENT : cette page est protégée. Seuls les utilisateurs ayant le statut dadministrateur peuvent la modifier.'''<br />
+L'administrateur ayant verrouillé la base de données a donné l'explication suivante : $1",
+'protectedpagewarning' => "'''AVERTISSEMENT : cette page est protégée. Seuls les utilisateurs ayant le statut d'administrateur peuvent la modifier.'''<br />
 La dernière entrée du journal est affichée ci-dessous pour référence :",
 'semiprotectedpagewarning' => "'''Note :''' Cette page a été protégée de telle façon que seuls les contributeurs enregistrés puissent la modifier. La dernière entrée du journal est affichée ci-dessous pour référence :",
-'cascadeprotectedwarning' => "'''ATTENTION :''' Cette page a été protégée de manière à ce que seuls les administrateurs puissent léditer. Cette protection est héritée par son inclusion par {{PLURAL:$1|la page protégée suivante, qui a|les pages protégées suivantes, qui ont}} la « protection en cascade » activée :",
+'cascadeprotectedwarning' => "'''ATTENTION :''' Cette page a été protégée de manière à ce que seuls les administrateurs puissent l'éditer. Cette protection est héritée par son inclusion par {{PLURAL:$1|la page protégée suivante, qui a|les pages protégées suivantes, qui ont}} la « protection en cascade » activée :",
 'titleprotectedwarning' => "'''ATTENTION : Cette page a été protégée de telle manière que des [[Special:ListGroupRights|droits spécifiques]] sont requis pour pouvoir la créer.''' La dernière entrée du journal est affichée ci-dessous pour référence :",
 'templatesused' => '{{PLURAL:$1|Modèle utilisé|Modèles utilisés}} par cette page :',
 'templatesusedpreview' => '{{PLURAL:$1|Modèle utilisé|Modèles utilisés}} dans cette prévisualisation :',
@@ -1114,25 +1114,25 @@ La dernière entrée du journal est affichée ci-dessous pour référence :",
 'nocreatetitle' => 'Création de page limitée',
 'nocreatetext' => '{{SITENAME}} a restreint la possibilité de créer de nouvelles pages.
 Vous pouvez revenir en arrière et modifier une page existante, ou bien [[Special:UserLogin|vous connecter ou créer un compte]].',
-'nocreate-loggedin' => 'Vous n’avez pas la permission de créer de nouvelles pages.',
+'nocreate-loggedin' => "Vous n'avez pas la permission de créer de nouvelles pages.",
 'sectioneditnotsupported-title' => 'Modification de section non prise en charge',
-'sectioneditnotsupported-text' => 'La modification d’une section n’est pas prise en charge pour cette page.',
+'sectioneditnotsupported-text' => "La modification d'une section n'est pas prise en charge pour cette page.",
 'permissionserrors' => 'Erreur de permissions',
-'permissionserrorstext' => 'Vous n’avez pas la permission d’effectuer l’opération demandée pour {{PLURAL:$1|la raison suivante|les raisons suivantes}} :',
-'permissionserrorstext-withaction' => 'Vous n’êtes pas autorisé{{GENDER:||e|(e)}} à $2, pour {{PLURAL:$1|la raison suivante|les raisons suivantes}} :',
+'permissionserrorstext' => "Vous n'avez pas la permission d'effectuer l'opération demandée pour {{PLURAL:$1|la raison suivante|les raisons suivantes}} :",
+'permissionserrorstext-withaction' => "Vous n'êtes pas autorisé{{GENDER:||e|(e)}} à $2, pour {{PLURAL:$1|la raison suivante|les raisons suivantes}} :",
 'recreate-moveddeleted-warn' => "'''Attention : vous êtes en train de recréer une page qui a été précédemment supprimée.'''
 
-Assurez-vous quil est pertinent de poursuivre les modifications sur cette page. Le journal des suppressions et des déplacements est affiché ci-dessous :",
+Assurez-vous qu'il est pertinent de poursuivre les modifications sur cette page. Le journal des suppressions et des déplacements est affiché ci-dessous :",
 'moveddeleted-notice' => 'Cette page a été supprimée. Le journal des suppressions et des déplacements est affiché ci-dessous pour référence.',
 'log-fulllog' => 'Voir le journal complet',
 'edit-hook-aborted' => 'Échec de la modification par une extension.
 Cause inconnue',
-'edit-gone-missing' => 'N’a pas pu mettre à jour la page.
-Il semble qu’elle ait été supprimée.',
+'edit-gone-missing' => "N'a pas pu mettre à jour la page.
+Il semble qu'elle ait été supprimée.",
 'edit-conflict' => 'Conflit de modification.',
-'edit-no-change' => 'Votre modification a été ignorée car aucun changement n’a été fait au texte.',
-'edit-already-exists' => 'La nouvelle page n’a pas pu être créée.
-Elle existe déjà.',
+'edit-no-change' => "Votre modification a été ignorée car aucun changement n'a été fait au texte.",
+'edit-already-exists' => "La nouvelle page n'a pas pu être créée.
+Elle existe déjà.",
 'defaultmessagetext' => 'Message par défaut',
 'content-failed-to-parse' => "Échec de l'analyse du contenu de $2 pour le modèle $1: $3",
 'invalid-content-data' => 'Données du contenu non valides',
@@ -1145,13 +1145,13 @@ Elle existe déjà.',
 'content-model-css' => 'CSS',
 
 # Parser/template warnings
-'expensive-parserfunction-warning' => 'Attention : cette page contient de trop nombreux appels à des fonctions coûteuses de l’analyseur syntaxique.
+'expensive-parserfunction-warning' => "Attention : cette page contient de trop nombreux appels à des fonctions coûteuses de l'analyseur syntaxique.
 
-Il devrait y avoir moins de $2 appel{{PLURAL:$2||s}}, alors qu’il y en a maintenant $1.',
-'expensive-parserfunction-category' => 'Pages avec trop d’appels dispendieux de fonctions de l’analyseur syntaxique',
-'post-expand-template-inclusion-warning' => 'Attention : Cette page contient trop d’inclusions de modèles. Certaines inclusions ne seront pas effectuées.',
-'post-expand-template-inclusion-category' => 'Pages contenant trop d’inclusions de modèles',
-'post-expand-template-argument-warning' => 'Attention : Cette page contient au moins un paramètre de modèle dont l’inclusion est rendue impossible. Après extension, celui-ci aurait produit un résultat trop long, il n’a donc pas été inclus.',
+Il devrait y avoir moins de $2 appel{{PLURAL:$2||s}}, alors qu'il y en a maintenant $1.",
+'expensive-parserfunction-category' => "Pages avec trop d'appels dispendieux de fonctions de l'analyseur syntaxique",
+'post-expand-template-inclusion-warning' => "Attention : Cette page contient trop d'inclusions de modèles. Certaines inclusions ne seront pas effectuées.",
+'post-expand-template-inclusion-category' => "Pages contenant trop d'inclusions de modèles",
+'post-expand-template-argument-warning' => "Attention : Cette page contient au moins un paramètre de modèle dont l'inclusion est rendue impossible. Après extension, celui-ci aurait produit un résultat trop long, il n'a donc pas été inclus.",
 'post-expand-template-argument-category' => 'Pages contenant des paramètres de modèle non évalués',
 'parser-template-loop-warning' => 'Modèle en boucle détecté : [[$1]]',
 'parser-template-recursion-depth-warning' => 'Limite de profondeur des appels de modèles dépassée ($1)',
@@ -1165,9 +1165,9 @@ Il devrait y avoir moins de $2 appel{{PLURAL:$2||s}}, alors qu’il y en a maint
 'converter-manual-rule-error' => 'Erreur détectée dans la règle manuelle de conversion de langue',
 
 # "Undo" feature
-'undo-success' => 'Cette modification va être défaite. Veuillez vérifier les modifications ci-dessous, puis publier si c’est bien ce que vous voulez faire.',
+'undo-success' => "Cette modification va être défaite. Veuillez vérifier les modifications ci-dessous, puis publier si c'est bien ce que vous voulez faire.",
 'undo-failure' => 'Cette modification ne peut pas être défaite : cela entrerait en conflit avec les modifications intermédiaires.',
-'undo-norev' => 'La modification n’a pas pu être défaite parce qu’elle est inexistante ou qu’elle a été supprimée.',
+'undo-norev' => "La modification n'a pas pu être défaite parce qu'elle est inexistante ou qu'elle a été supprimée.",
 'undo-summary' => 'Annulation des modifications $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|discussion]])',
 
 # Account creation failure
@@ -1178,7 +1178,7 @@ La raison donnée était ''$2''.",
 
 # History pages
 'viewpagelogs' => 'Voir les opérations sur cette page',
-'nohistory' => 'Il n’existe pas d’historique pour cette page.',
+'nohistory' => "Il n'existe pas d'historique pour cette page.",
 'currentrev' => 'Version actuelle',
 'currentrev-asof' => 'Version actuelle en date du $1',
 'revisionasof' => 'Version du $1',
@@ -1192,7 +1192,7 @@ La raison donnée était ''$2''.",
 'page_first' => 'première',
 'page_last' => 'dernière',
 'histlegend' => 'Légende : ({{int:cur}}) = différence avec la version actuelle, ({{int:last}}) = différence avec la version précédente, <b>{{int:minoreditletter}}</b> = modification mineure',
-'history-fieldset-title' => 'Naviguer dans l’historique',
+'history-fieldset-title' => "Naviguer dans l'historique",
 'history-show-deleted' => 'Masqués seulement',
 'histfirst' => 'première page',
 'histlast' => 'dernière page',
@@ -1203,15 +1203,15 @@ La raison donnée était ''$2''.",
 'history-feed-title' => 'Historique des versions',
 'history-feed-description' => 'Historique pour cette page sur le wiki',
 'history-feed-item-nocomment' => '$1 le $2',
-'history-feed-empty' => 'La page demandée n’existe pas.
+'history-feed-empty' => "La page demandée n'existe pas.
 Elle a peut-être été effacée ou renommée.
-Essayez de [[Special:Search|rechercher sur le wiki]] pour trouver des pages en rapport.',
+Essayez de [[Special:Search|rechercher sur le wiki]] pour trouver des pages en rapport.",
 
 # Revision deletion
-'rev-deleted-comment' => '(résumé d’édition enlevé)',
-'rev-deleted-user' => '(nom d’utilisateur supprimé)',
+'rev-deleted-comment' => "(résumé d'édition enlevé)",
+'rev-deleted-user' => "(nom d'utilisateur supprimé)",
 'rev-deleted-event' => '(entrée supprimée)',
-'rev-deleted-user-contribs' => '[nom d’utilisateur ou adresse IP supprimée - modification cachée sur les contributions]',
+'rev-deleted-user-contribs' => "[nom d'utilisateur ou adresse IP supprimée - modification cachée sur les contributions]",
 'rev-deleted-text-permission' => "Cette version de la page a été '''effacée'''.
 Des détails sont disponibles dans le [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} journal des effacements].",
 'rev-deleted-text-unhide' => "Cette version de la page a été '''effacée'''.
@@ -1224,7 +1224,7 @@ Vous pouvez toujours [$1 voir cette version] si vous le voulez.",
 Vous pouvez la visualiser ; des détails sont disponibles dans le [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} journal des effacements].",
 'rev-suppressed-text-view' => "Cette version de la page a été '''supprimée'''.
 Vous pouvez la visualiser ; des détails sont disponibles dans le [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} journal des suppressions].",
-'rev-deleted-no-diff' => "Vous ne pouvez pas voir ce diff parce quune des versions a été '''effacée'''.
+'rev-deleted-no-diff' => "Vous ne pouvez pas voir ce diff parce qu'une des versions a été '''effacée'''.
 Des détails sont disponibles dans le [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} journal des effacements].",
 'rev-suppressed-no-diff' => "Vous ne pouvez pas voir cette différence car une des révisions a été '''supprimée'''.",
 'rev-deleted-unhide-diff' => "Une des révisions de cette différence a été '''effacée'''.
@@ -2182,8 +2182,8 @@ Les entrées <del>barrées</del> ont été résolues.',
 'wantedpages' => 'Pages les plus demandées',
 'wantedpages-badtitle' => 'Titre invalide dans les résultats : $1',
 'wantedfiles' => 'Fichiers les plus demandés',
-'wantedfiletext-cat' => "Les fichiers suivants sont utilisés, mais il n'existent pas. Les fichiers de dépôts à distance peuvent être listés malgré qu'ils existent. Tout ces faux positifs seront <del>barrés</del>. En outre, les pages qui intègrent des fichiers qui n'existent pas sont répertoriés dans [[:$1]].",
-'wantedfiletext-nocat' => "Les fichiers suivants sont utilisés, mais n'existent pas. Les fichiers de dépôts à distance peuvent être listés malgré qu'ils existent. Tout ces faux positifs seront <del>barrés</del>.",
+'wantedfiletext-cat' => 'Les fichiers suivants sont utilisés, mais n’existent pas. Les fichiers d’autres dépôts peuvent être listés malgré qu’ils existent. Tous ces faux positifs seront <del>barrés</del>. En outre, les pages qui intègrent des fichiers qui n’existent pas sont répertoriées dans [[:$1]].',
+'wantedfiletext-nocat' => 'Les fichiers suivants sont utilisés, mais n’existent pas. Les fichiers d’autres dépôts peuvent être listés malgré qu’ils existent. Tous ces faux positifs seront <del>barrés</del>.',
 'wantedtemplates' => 'Modèles demandés',
 'mostlinked' => 'Pages les plus liées',
 'mostlinkedcategories' => 'Catégories les plus utilisées',
@@ -3286,6 +3286,7 @@ Si vous l’exécutez, votre système peut être compromis.",
 'sp-newimages-showfrom' => 'Afficher les nouveaux fichiers à partir du $1 à $2',
 
 # Video information, used by Language::formatTimePeriod() to format lengths in the above messages
+'days-abbrev' => '$1 j',
 'seconds' => '{{PLURAL:$1|$1 seconde|$1 secondes}}',
 'minutes' => '{{PLURAL:$1|$1 minute|$1 minutes}}',
 'hours' => '{{PLURAL:$1|$1 heure|$1 heures}}',
index 60cf4e3..4d8d0d7 100644 (file)
@@ -61,7 +61,7 @@ $defaultDateFormat = 'dmy';
 $dateFormats = array(
        'dmy time' => 'H:i',
        'dmy date' => 'j \d\e F \d\e Y',
-       'dmy both' => 'j \d\e F \d\e Y "ás" H:i',
+       'dmy both' => 'j \d\e F \d\e Y "ás" H:i',
 );
 
 $specialPageAliases = array(
@@ -356,8 +356,8 @@ $messages = array(
 'newwindow' => '(abre unha ventá nova)',
 'cancel' => 'Cancelar',
 'moredotdotdot' => 'Máis...',
-'mypage' => 'A miña páxina',
-'mytalk' => 'A miña conversa',
+'mypage' => 'Páxina',
+'mytalk' => 'Conversa',
 'anontalk' => 'Conversa con este enderezo IP',
 'navigation' => 'Navegación',
 'and' => '&#32;e',
@@ -1311,7 +1311,7 @@ Note que os seus índices do contido de {{SITENAME}} poden estar desactualizados
 
 # Preferences page
 'preferences' => 'Preferencias',
-'mypreferences' => 'As miñas preferencias',
+'mypreferences' => 'Preferencias',
 'prefs-edits' => 'Número de edicións:',
 'prefsnologin' => 'Non accedeu ao sistema',
 'prefsnologintext' => 'Debe <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} acceder ao sistema]</span> para modificar as preferencias de usuario.',
@@ -2263,7 +2263,7 @@ O enderezo de correo electrónico que inseriu [[Special:Preferences|nas súas pr
 
 # Watchlist
 'watchlist' => 'A miña lista de vixilancia',
-'mywatchlist' => 'A miña lista de vixilancia',
+'mywatchlist' => 'Lista de vixilancia',
 'watchlistfor2' => 'De $1 $2',
 'nowatchlist' => 'Non ten elementos na súa lista de vixilancia.',
 'watchlistanontext' => 'Faga o favor de $1 ao sistema para ver ou editar os elementos da súa lista de vixilancia.',
@@ -2527,7 +2527,7 @@ $1',
 # Contributions
 'contributions' => 'Contribucións {{GENDER:{{BASEPAGENAME}}|do usuario|da usuaria}}',
 'contributions-title' => 'Contribucións de $1',
-'mycontris' => 'As miñas contribucións',
+'mycontris' => 'Contribucións',
 'contribsub2' => 'De $1 ($2)',
 'nocontribs' => 'Non se deron atopado cambios con eses criterios.',
 'uctop' => '(última revisión)',
@@ -2567,7 +2567,7 @@ Velaquí está a última entrada do rexistro de bloqueos, por se quere consultal
 'whatlinkshere-hideredirs' => '$1 as redireccións',
 'whatlinkshere-hidetrans' => '$1 as inclusións',
 'whatlinkshere-hidelinks' => '$1 as ligazóns',
-'whatlinkshere-hideimages' => '$1 as ligazóns á imaxe',
+'whatlinkshere-hideimages' => '$1 as ligazóns ao ficheiro',
 'whatlinkshere-filters' => 'Filtros',
 
 # Block/unblock
@@ -3025,7 +3025,7 @@ Pode ver o código fonte.',
 'nostalgia.js' => '/* Calquera JavaScript que haxa aquí será cargado para os usuarios que usen a aparencia Morriña */',
 'cologneblue.js' => '/* Calquera JavaScript que haxa aquí será cargado para os usuarios que usen a aparencia Azul colonial */',
 'monobook.js' => '/* Calquera JavaScript que haxa aquí será cargado para os usuarios que usen a aparencia MonoBook */',
-'myskin.js' => '/* Calquera JavaScript que haxa aquí será cargado para os usuarios que usen a aparencia A miña aparencia */',
+'myskin.js' => '/* O JavaScript que se coloque aquí afectará a quen use a aparencia A miña aparencia */',
 'chick.js' => '/* Calquera JavaScript que haxa aquí será cargado para os usuarios que usen a aparencia Parrulo */',
 'simple.js' => '/* Calquera JavaScript que haxa aquí será cargado para os usuarios que usen a aparencia Sinxela */',
 'modern.js' => '/* Calquera JavaScript que haxa aquí será cargado para os usuarios que usen a aparencia Moderna */',
@@ -4019,4 +4019,6 @@ En caso contrario, pode empregar o formulario sinxelo inferior. O seu comentario
 'duration-centuries' => '$1 {{PLURAL:$1|século|séculos}}',
 'duration-millennia' => '$1 {{PLURAL:$1|milenio|milenios}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'conversa',
 );
index 41fddb3..e046694 100644 (file)
@@ -181,7 +181,7 @@ $messages = array(
 
 'underline-always' => 'immer',
 'underline-never' => 'nie',
-'underline-default' => 'Browser-Vorystellig',
+'underline-default' => 'Voryystellig vu dr Benutzeroberfleichi oder em Brwoser',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Schriftfamilie fir dr Text im Bearbeitigsfänschter:',
@@ -266,8 +266,8 @@ $messages = array(
 'newwindow' => '(imene nöie Fänschter)',
 'cancel' => 'Abbräche',
 'moredotdotdot' => 'Meh …',
-'mypage' => 'Myyni Syte',
-'mytalk' => 'Myyni Diskussionsyte',
+'mypage' => 'Syte',
+'mytalk' => 'Diskussionsyte',
 'anontalk' => 'Diskussionssyste vo sellere IP',
 'navigation' => 'Navigation',
 'and' => '&#32;un',
@@ -815,7 +815,7 @@ As Information chunnt do ne aktuälle Uuszug us em Benutzersperr-Logbuech:',
 'note' => "'''Obacht: '''",
 'previewnote' => "'''Das isch numen e Vorschau und nonig gspycheret!'''
 Die Syte isch nonig gspycheret wore!",
-'continue-editing' => 'Wyter bearbeite',
+'continue-editing' => 'Zum Bearbeitigsfäld',
 'previewconflict' => 'Die Vorschau zeigt dr Inhalt vum obere Täxtfäld. Eso siht dr Artikel us, wän Du jetz uf Spychere drucksch.',
 'session_fail_preview' => "'''Dyyni Bearbeitig het nid chenne gspycheret wäre, wel Sitzigsdate verlore gange sin.
 Bitte versuech s nomol. Derzue drucksch unter däre Täxtvorschau nomol uf „Syte spychere“.
@@ -1185,7 +1185,7 @@ Einzelheite chasch im [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}
 
 # Preferences page
 'preferences' => 'Yystellige',
-'mypreferences' => 'Ystellige',
+'mypreferences' => 'Yystellige',
 'prefs-edits' => 'Aazahl vu dr Bearbeitige:',
 'prefsnologin' => 'Nid aagmäldet',
 'prefsnologintext' => 'Du muesch <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} aagmäldet]</span> sy, für Benutzerystellige chönne z ändere',
@@ -1414,6 +1414,9 @@ Des cha nimmi ruckgängig gmacht wäre.',
 'rightslogtext' => 'Des ischs Logbuech vun de Änderunge on Bnutzerrechte.',
 'rightslogentry' => 'het d Benutzerrächt fir „$1“ vu „$2“ uf „$3“ gänderet',
 'rightslogentry-autopromote' => 'd Zueornig zue dr Benutzergruppe isch automatisch vu $2 in $3 gänderet wore',
+'logentry-rights-rights' => '$1 het d Gruppezuegherigkeit fir $3 vu $4 uf $5 gänderet',
+'logentry-rights-rights-legacy' => '$1 het d Gruppezuegherigkeit fir $3 gänderet',
+'logentry-rights-autopromote' => '$1 isch automatisch vu $4 zue $5 zuegordnet wore',
 'rightsnone' => '(keini)',
 
 # Associated actions - in the sentence "You do not have permission to X"
@@ -2022,7 +2025,7 @@ Lueg au d Lischt vu dr [[Special:WantedCategories|gwinschte Kategorie]].',
 'linksearch-pat' => 'Suechmuschter:',
 'linksearch-ns' => 'Namensruum:',
 'linksearch-ok' => 'Sueche',
-'linksearch-text' => 'Die Spezialsyte macht d Suechi no Syte megli, wu s bstimmti Weblink din het. Doderby chenne Platzhalter wie zem Byschpel <code>*.byschpel.de</code> brucht wäre. S mueß zmindecht ei Top-Level-Domain, z. B. „*.org“. aagee wäre. <br />Unterstitzti Protokoll: <code>$1</code> (Die bitte nit bi dr Suechaafrog aagee.)',
+'linksearch-text' => 'Die Spezialsyte macht d Suechi no Syte megli, wu s bstimmti Weblink din het. Doderby chenne Platzhalter wie zem Byschpel <code>*.byschpel.de</code> brucht wäre. S mueß zmindecht ei Top-Level-Domain, z. B. „*.org“. aagee wäre. <br />Unterstitzti Protokoll: <code>$1</code> (Standard isch http, wänn kei Protokoll aagee isch).',
 'linksearch-line' => '$1 isch vo $2 verknüpft',
 'linksearch-error' => 'Platzhalter chönne numme am Aafang verwändet werre.',
 
@@ -2071,8 +2074,8 @@ Zuesätzligi Informatione iber einzelni Rächt git s [[{{MediaWiki:Listgrouprigh
 'emailuser-title-target' => 'E-Mail an {{GENDER:$1|dää Benutzer|die Benutzeri}} schicke',
 'emailuser-title-notarget' => 'E-Mail an Benutzer',
 'emailpage' => 'E-Mail an Benutzer',
-'emailpagetext' => 'Du chasch im Benutzer mit däm Formular e E-Mail schicke.
-As Absender wird d E-Mail-Adräss us Dyyne [[Special:Preferences|Yystellige]] yytrait, ass dr Benutzer Dir cha Antwort gee.',
+'emailpagetext' => 'Du chasch {{GENDER:$1|em Benutzer|dr Benutzeri}} mit däm Formular e E-Mail schicke.
+As Absender wird d E-Mail-Adräss us Dyyne [[Special:Preferences|Yystellige]] yytrait, ass {{GENDER:$1|dr Benutzer|d Benutzeri}} Dir cha Antwort gee.',
 'usermailererror' => 'S Mail-Objekt het e Fähler zruckgee:',
 'defemailsubject' => '{{SITENAME}}-E-Mail vum Benutzer „$1“',
 'usermaildisabled' => 'Benutzer-E-Mail abgstellt',
@@ -2396,7 +2399,7 @@ Do chunnt dr aktuäll Yytrag us em Benutzersperr-Logbuech:',
 'whatlinkshere-hideredirs' => 'Wyterleitige $1',
 'whatlinkshere-hidetrans' => 'Vorlageyybindige $1',
 'whatlinkshere-hidelinks' => 'Links $1',
-'whatlinkshere-hideimages' => 'Dateigleicher $1',
+'whatlinkshere-hideimages' => 'Dateilink $1',
 'whatlinkshere-filters' => 'Filter',
 
 # Block/unblock
@@ -2832,7 +2835,7 @@ Die uf em lokale Rächner spychere un derno do uffelade.',
 
 # Info page
 'pageinfo-title' => 'Informatione zue „$1“',
-'pageinfo-not-current' => 'Die Informatione chenne nume fir di nejscht Versions aazeigt wäre.',
+'pageinfo-not-current' => 'Die Informatione chenne leider nit fir alti Versionen aazeigt wäre.',
 'pageinfo-header-basic' => 'Basisinformatione',
 'pageinfo-header-edits' => 'Bearbeitige',
 'pageinfo-header-restrictions' => 'Syteschutz',
@@ -2841,6 +2844,7 @@ Die uf em lokale Rächner spychere un derno do uffelade.',
 'pageinfo-default-sort' => 'Standardsortierkriterium',
 'pageinfo-length' => 'Sytelengi (in Byte)',
 'pageinfo-article-id' => 'Syten-ID',
+'pageinfo-language' => 'Syteninhaltssproch',
 'pageinfo-robot-policy' => 'Suechmaschinestatus',
 'pageinfo-robot-index' => 'Indizierbar',
 'pageinfo-robot-noindex' => 'Nit indizierbar',
@@ -2861,6 +2865,13 @@ Die uf em lokale Rächner spychere un derno do uffelade.',
 'pageinfo-hidden-categories' => 'Versteckti {{PLURAL:$1|Kategori|Kategorie}} ($1)',
 'pageinfo-templates' => 'Yybundeni {{PLURAL:$1|Vorlag|Vorlage}} ($1)',
 'pageinfo-toolboxlink' => 'Informatione zue dr Syte',
+'pageinfo-redirectsto' => 'Weiterleitung nach',
+'pageinfo-redirectsto-info' => 'Information',
+'pageinfo-contentpage' => 'Zellt as Inhaltssyte',
+'pageinfo-contentpage-yes' => 'Jo',
+'pageinfo-protect-cascading' => 'Syte mit Kaskadeschutz vu do',
+'pageinfo-protect-cascading-yes' => 'Jo',
+'pageinfo-protect-cascading-from' => 'Syte mit Kaskadeschutz vu',
 
 # Patrolling
 'markaspatrolleddiff' => 'Als patrulyrt markyre',
@@ -3538,6 +3549,7 @@ Du chasch au d [[Special:EditWatchlist|Standard-Bearbeitigssyte]] bruuche.',
 'version-license' => 'Lizänz',
 'version-poweredby-credits' => "Die Websyte nutzt '''[//www.mediawiki.org/wiki/MediaWiki/de MediaWiki]''', Copyright © 2001–$1 $2.",
 'version-poweredby-others' => 'anderi',
+'version-credits-summary' => 'Mir danke däne Lyt fir ihri Bytreg zue [[Special:Version|MediaWiki]].',
 'version-license-info' => 'MediaWiki isch e freji Software, d. h. s cha, no dr Bedingige vu dr GNU General Public-Lizänz, wu vu dr Free Software Foundation vereffentligt woren isch, wyterverteilt un/oder modifiziert wäre. Doderbyy cha d Version 2, oder no eigenem Ermässe, jedi nejeri Version vu dr Lizänz brucht wäre.
 
 Des Programm wird in dr Hoffnig verteilt, ass es nitzli isch, aber OHNI JEDI GARANTI un sogar ohni di impliziert Garanti vun ere MÄRTGÄNGIGKEIT oder EIGNIG FIR E BSTIMMTE ZWÄCK. Doderzue git meh Hiiwys in dr GNU General Public-Lizänz.
index c74f3d6..6c513e1 100644 (file)
@@ -484,8 +484,8 @@ $messages = array(
 'newwindow' => '(נפתח בחלון חדש)',
 'cancel' => 'ביטול / יציאה',
 'moredotdotdot' => 'עוד…',
-'mypage' => '×\94×\93×£ ×©×\9c×\99',
-'mytalk' => '×\93×£ ×\94ש×\99×\97×\94 ×©×\9c×\99',
+'mypage' => '×\93×£ ×\9eשת×\9eש',
+'mytalk' => 'ש×\99×\97×\94',
 'anontalk' => 'השיחה עבור IP זה',
 'navigation' => 'ניווט',
 'and' => '&#32;וגם',
@@ -1430,7 +1430,7 @@ $1",
 
 # Preferences page
 'preferences' => 'העדפות',
-'mypreferences' => '×\94×\94×¢×\93פ×\95ת ×©×\9c×\99',
+'mypreferences' => '×\94×¢×\93פ×\95ת',
 'prefs-edits' => 'מספר עריכות:',
 'prefsnologin' => 'לא נכנסת לחשבון',
 'prefsnologintext' => 'עליכם <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} להיכנס לחשבון]</span> כדי לשנות העדפות משתמש.',
@@ -2381,7 +2381,7 @@ $1',
 
 # Watchlist
 'watchlist' => 'רשימת המעקב שלי',
-'mywatchlist' => 'רש×\99×\9eת ×\94×\9eעק×\91 ×©×\9c×\99',
+'mywatchlist' => 'רש×\99×\9eת ×\9eעק×\91',
 'watchlistfor2' => 'עבור $1 $2',
 'nowatchlist' => 'אין דפים ברשימת המעקב.',
 'watchlistanontext' => 'עליכם $1 כדי לצפות או לערוך פריטים ברשימת המעקב.',
@@ -2637,7 +2637,7 @@ $1',
 # Contributions
 'contributions' => 'תרומות המשתמש',
 'contributions-title' => 'תרומות של המשתמש $1',
-'mycontris' => '×\94תר×\95×\9e×\95ת ×©×\9c×\99',
+'mycontris' => 'תר×\95×\9e×\95ת',
 'contribsub2' => 'עבור $1 ($2)',
 'nocontribs' => 'לא נמצאו שינויים המתאימים לקריטריונים אלו.',
 'uctop' => '(אחרון)',
@@ -4186,4 +4186,6 @@ $5
 'duration-centuries' => '{{PLURAL:$1|מאה שנה|מאתיים שנה|$1 מאות שנים}}',
 'duration-millennia' => '{{PLURAL:$1|אלף שנה|אלפיים שנה|$1 אלפי שנים}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'שיחה',
 );
index 027c6fa..1667193 100644 (file)
@@ -286,8 +286,8 @@ $messages = array(
 'newwindow' => '(wočinja so w nowym woknje)',
 'cancel' => 'Přetorhnyć',
 'moredotdotdot' => 'Wjace…',
-'mypage' => 'Moja strona',
-'mytalk' => 'moja diskusija',
+'mypage' => 'Strona',
+'mytalk' => 'Diskusija',
 'anontalk' => 'Diskusijna strona tuteje IP.adresy',
 'navigation' => 'Nawigacija',
 'and' => '&#32;a',
@@ -1189,7 +1189,7 @@ Spytaj swoje naprašowanje z prefiksom ''all:'' wužiwać, zo by wšón wobsah (
 
 # Preferences page
 'preferences' => 'Nastajenja',
-'mypreferences' => 'nastajenja',
+'mypreferences' => 'Nastajenja',
 'prefs-edits' => 'Ličba změnow:',
 'prefsnologin' => 'Njepřizjewjeny',
 'prefsnologintext' => 'Dyrbiš <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} přizjewjeny]</span>  być, zo by móhł nastajenja postajić.',
@@ -2040,7 +2040,7 @@ Hlej tež [[Special:WantedCategories|požadane kategorije]].',
 'linksearch-ok' => 'Pytać',
 'linksearch-text' => 'Zastupniske znamješka kaž "*.wikipedia.org" móža so wužiwać.
 Znajmjeńša hłowna domena je trěbna, na přikład "*.org".<br />
-Podpěrowane protokole: <code>$1</code> (prošu njepodaj je w swojim pytanje).',
+Podpěrowane protokole: <code>$1</code> (standard je http://, jeli žadyn protokol njeje podaty).',
 'linksearch-line' => '$1 je z $2 wotkazany.',
 'linksearch-error' => 'Zastupniske znamjenja dadźa so jenož na spočatku URL wužiwać.',
 
@@ -2120,7 +2120,7 @@ E-mejlowa adresa, kotruž sy w [[Special:Preferences|swojich wužiwarskich nasta
 
 # Watchlist
 'watchlist' => 'wobkedźbowanki',
-'mywatchlist' => 'wobkedźbowanki',
+'mywatchlist' => 'Wobkedźbowanki',
 'watchlistfor2' => 'Za wužiwarja $1 $2',
 'nowatchlist' => 'Nimaš žane strony w swojich wobkedźbowankach.',
 'watchlistanontext' => 'Dyrbiš so $1, zo by swoje wobkedźbowanki wobhladać abo wobdźěłać móhł.',
@@ -2372,7 +2372,7 @@ $1',
 # Contributions
 'contributions' => 'Přinoški wužiwarja',
 'contributions-title' => 'Wužiwarske přinoški wot „$1“',
-'mycontris' => 'moje přinoški',
+'mycontris' => 'Přinoški',
 'contribsub2' => 'za wužiwarja $1 ($2)',
 'nocontribs' => 'Žane změny, kotrež podatym kriterijam wotpowěduja.',
 'uctop' => '(aktualnje)',
@@ -2412,7 +2412,7 @@ Najnowši zapisk w protokolu blokowanjow so deleka jako referenca podawa:',
 'whatlinkshere-hideredirs' => 'Daleposrědkowanja $1',
 'whatlinkshere-hidetrans' => 'Zapřijeća $1',
 'whatlinkshere-hidelinks' => 'Wotkazy $1',
-'whatlinkshere-hideimages' => 'wobrazowe wotkazy $1',
+'whatlinkshere-hideimages' => 'Datajowe wotkazy $1',
 'whatlinkshere-filters' => 'Filtry',
 
 # Block/unblock
@@ -3798,4 +3798,6 @@ Hewak móžeš slědowacy jednory formular wužiwać. Twój komentar přida so s
 'duration-centuries' => '$1 {{PLURAL:$1|lětstotk|lětstotkaj|lětstotki|lětstotkow}}',
 'duration-millennia' => '$1 {{PLURAL:$1|lěttysac|lěttysacaj|lěttysacy|lěttysacow}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'diskusija',
 );
index 739ca1a..9bbf3fa 100644 (file)
@@ -1073,6 +1073,12 @@ Nem lett magyarázat csatolva.',
 Már létezik.',
 'defaultmessagetext' => 'Alapértelmezett szöveg',
 
+# Content models
+'content-model-wikitext' => 'wikiszöveg',
+'content-model-text' => 'egyszerű szöveg',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
+
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Figyelem: ezen a lapon túl sok erőforrásigényes elemzőfüggvény-hívás található.
 
@@ -1344,7 +1350,7 @@ Győződj meg róla, hogy a laptörténet folytonossága megmarad.',
 
 # Preferences page
 'preferences' => 'Beállítások',
-'mypreferences' => 'Beállításaim',
+'mypreferences' => 'Beállítások',
 'prefs-edits' => 'Szerkesztéseid száma:',
 'prefsnologin' => 'Nem jelentkeztél be',
 'prefsnologintext' => 'Saját beállításaid elmentéséhez <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} be kell jelentkezned.] </span>',
@@ -2187,7 +2193,7 @@ Lásd még a [[Special:WantedCategories|keresett kategóriák]] listáját.',
 'linksearch-ns' => 'Névtér:',
 'linksearch-ok' => 'keresés',
 'linksearch-text' => 'Helyettesítő karaktereket is lehet használni, például "*.wikipedia.org". Legalább egy felső szintű tartománynak lennie kell, például "*.org"<br />
-Támogatott protokollok: <code>$1</code> (ezeket ne írd be a keresésbe).',
+Támogatott protokollok: <code>$1</code> (http:// az alapértelmezett, ha nincs protokoll megadva).',
 'linksearch-line' => '$1 hivatkozva innen: $2',
 'linksearch-error' => 'Helyettesítő karakterek csak a cím elején szerepelhetnek.',
 
@@ -2569,7 +2575,7 @@ A blokknapló legutóbbi ide vonatkozó bejegyzése a következő:',
 'whatlinkshere-hideredirs' => 'átirányítások $1',
 'whatlinkshere-hidetrans' => 'beillesztések $1',
 'whatlinkshere-hidelinks' => 'linkek $1',
-'whatlinkshere-hideimages' => 'képhivatkozás $1',
+'whatlinkshere-hideimages' => 'fájlhivatkozások $1',
 'whatlinkshere-filters' => 'Elemek szűrése',
 
 # Block/unblock
index 993e0ea..a082bc6 100644 (file)
@@ -649,9 +649,13 @@ $1',
 'cascadeprotected' => 'Այս էջը պաշտպանված է խմբագրումից, քանի որ ընդգրկված է հետևյալ {{PLURAL:$1|էջի|էջերի}} տեքստում, {{PLURAL:$1|որը|որոնք}} պաշտպանվել {{PLURAL:$1|է|են}} կասկադային հնարավորությամբ.
 $2',
 'namespaceprotected' => 'Դուք չունեք «$1» անվանատարածքի էջերի խմբագրման իրավունք։',
+'customcssprotected' => 'Դուք չեք կարող խմբագրել այս CSS էջը, քանի որ այն պարունակում է այլ մասնակցի անձնական նախընտրանքներ։',
+'customjsprotected' => 'Դուք չեք կարող խմբագրել այս ՋավաՍկրիպտ էջը, քանի որ այն պարունակում է այլ մասնակցի անձնական նախընտրանքներ։',
 'ns-specialprotected' => '«{{ns:special}}» անվանատարածքի էջերը չեն կարող խմբագրվել։',
 'titleprotected' => "Այս անվանմամբ էջի ստեղծումը արգելվել է [[User:$1|$1]] մասնակցի կողմից։
 Տրված պատճառն է՝ ''$2''։",
+'exception-nologin' => 'Չեք մտել համակարգ',
+'exception-nologin-text' => 'Այս էջը դիտելու կամ գործողություն կատարելու համար դուք պետք է մուտք գործեք այս վիքի։',
 
 # Virus scanner
 'virus-badscanner' => "Սխալ կարգավորւմ։ Անծանոթ վիրուսների զննիչ. ''$1''",
@@ -670,6 +674,7 @@ $2',
 'yourpasswordagain' => 'Կրկնեք գաղտնաբառը.',
 'remembermypassword' => 'Հիշել իմ մուտքագրված տվյալները այս համակարգչում ($1 {{PLURAL:$1|օրից|օրից}} ոչ ավել ժամկետով)',
 'yourdomainname' => 'Ձեր դոմենը.',
+'password-change-forbidden' => 'Այս վիքիում չեք կարող փոխել գաղտնաբառ։',
 'externaldberror' => 'Տեղի է ունեցել վավերացման արտաքին տվյալների բազայի սխալ, կամ դուք չունեք բավարար իրավունքներ ձեր արտաքին հաշվի փոփոխման համար։',
 'login' => 'Մտնել',
 'nav-login-createaccount' => 'Մտնել / Գրանցվել',
@@ -693,6 +698,8 @@ $2',
 'createaccounterror' => 'Չհաջողվեց ստեղծել մասնակցային հաշիվ. $1',
 'nocookiesnew' => 'Մասնակցային հաշիվը ստեղծված է, սակայն մուտքը համակարգ չհաջողվեց։ {{SITENAME}} կայքը օգտագործում է «քուքիներ» մասնակիցների վավերացման համար։ Ձեր մոտ «քուքիները» արգելված են։ Խնդրում ենք թույլատրել սրանք, ապա մտնել համակարգ ձեր նոր մասնակցի անունով և գաղտնաբառով։',
 'nocookieslogin' => '{{SITENAME}} կայքը օգտագործում է «քուքիներ» մասնակիցների վավերացման համար։ Ձեր մոտ «քուքիները» արգելված են։ Խնդրում ենք թույլատրել սրանք և փորձել կրկին։',
+'nocookiesfornew' => 'Մասնակցային հաշիվը չհաջողվեց ստեղծվել, քանի որ հնարավոր չեր վավերացնել աղբյուրը։
+Ստուգեք, որ ձեզ մոտ թույլատրված են քուկիները, վերբեռնեք էջը և փորձեք կրկին։',
 'noname' => 'Դուք չեք նշել թույլատրելի մասնակցային անուն։',
 'loginsuccesstitle' => 'Բարեհաջող մուտք',
 'loginsuccess' => "'''Դուք մուտք գործեցիք {{SITENAME}}, որպես \"\$1\"։'''",
@@ -729,6 +736,7 @@ $2',
 'noemailprefs' => 'Այս հնարավորության գործածման համար անհրաժեշտ է նշել էլ-փոստի հասցե։',
 'emailconfirmlink' => 'Վավերացնել ձեր էլ-փոստի հասցեն',
 'invalidemailaddress' => 'Նշված էլ-փոստի հասցեն անընդունելի է, քանի որ այն ունի անթույլատրելի ֆորմատ։ Խնդրում ենք նշել ճշմարիտ հասցե կամ այս դաշտը թողնել դատարկ։',
+'emaildisabled' => 'Այս կայքը չի կարող ուղարկել էլ․ նամակներ։',
 'accountcreated' => 'Հաշիվը ստեղծված է',
 'accountcreatedtext' => '$1 մասնակցի հաշիվը ստեղծված է։',
 'createaccount-title' => '{{SITENAME}}. մասնակցային հաշվի ստեղծում',
@@ -742,6 +750,7 @@ $2',
 
 # E-mail sending
 'php-mail-error-unknown' => 'Անհայտ սխալ PHP-ի mail() ֆունկցիայում',
+'user-mail-no-addy' => 'Փորձվեց ուղարկել էլ․ նամակ առանց էլ․ հասցեի։',
 
 # Change password dialog
 'resetpass' => 'Փոխել գաղտնաբառը',
@@ -766,9 +775,16 @@ $2',
 'passwordreset-username' => 'Մասնակցի անուն.',
 'passwordreset-emailelement' => 'Մասնակցային անուն. $1
 Ժամանակավոր գաղտնաբառ. $2',
+'passwordreset-emailsent' => 'Ուղարկվեց հիշեցնող էլ․ նամակ։',
+'passwordreset-emailsent-capture' => 'Ուղարկվեց հիշեցնող էլ․ նամակ։ Այն ներկայացված է ստորև։',
+'passwordreset-emailerror-capture' => 'Ուղարկվեց հիշեցնող էլ․ նամակ։ Այն ներկայացված է ստորև։ Սակայն մասնակցին ուղարկելը չհաջողվեց․',
 
 # Special:ChangeEmail
 'changeemail' => 'Փոխել էլ. հասցեն',
+'changeemail-header' => 'Փոխել հաշվի էլ․ հասցեն',
+'changeemail-oldemail' => 'Ներկա էլ․ հասցե․',
+'changeemail-newemail' => 'Նոր էլ․ հասցե․',
+'changeemail-none' => '(ոչ մի)',
 'changeemail-submit' => 'Խմբագրել էլ․ հասցեն',
 'changeemail-cancel' => 'Չեղարկել',
 
@@ -1675,13 +1691,19 @@ Also see [[Special:WantedCategories|wanted categories]].',
 'mailnologin' => 'Ուղարկման հասցե չկա',
 'mailnologintext' => 'Անհրաժեշտ է [[Special:UserLogin|մտնել համակարգ]] և ունենալ գործող էլ-փոստի հասցե ձեր [[Special:Preferences|նախընտրություններում]]՝ ուրիշ մասնակիցներին էլեկտրոնային նամակներ ուղարկելու համար։',
 'emailuser' => 'էլ-նամակ ուղարկել այս մասնակցին',
+'emailuser-title-target' => 'Ուղարկել էլ․ նամակ {{GENDER:$1|մասնակցին}}',
+'emailuser-title-notarget' => 'Ուղարկել էլ․ նամակ',
 'emailpage' => 'Էլ-նամակ ուղարկել մասնակցին',
-'emailpagetext' => 'Եթե այս մասնակիցը նշել է գործող էլ-փոստի հասցե իր նախընտրություններում, ապա ստորև բերված ձևով հնարավոր է ուղարկել նրան էլ-նամակ։
-Այն էլ-հասցեն, որը դուք նշել եք ձեր նախընտրություններում, կերևա «Ումից» դաշտում, ուստի ստացողը հնարավորություն կունենա պատասխանել։',
+'emailpagetext' => 'Դուք կարող եք օգտագործել ներքևի ձևը այս {{GENDER:$1|մասնակցին}} էլ-նամաակ ուղարկելու համար։
+
+Ձեր նախընտրանքներում նշված էլ-հասցեն կերևա «Ումից» դաշտում և ստացողը կարող է անմիջապես պատասխանել ձեզ։',
 'usermailererror' => 'Նամակն ուղարկելիս սխալ է վերադարձվել.',
-'defemailsubject' => '{{SITENAME}} e-mail',
+'defemailsubject' => '{{SITENAME}} էլ-նամակ',
+'usermaildisabled' => 'Էլ․ նամակ ուղարկելը թույլատրված չէ։',
+'usermaildisabledtext' => 'Այս վիքիում չեք կարղ էլ․ նամակ ուղարկել այլ մասնակիցների',
 'noemailtitle' => 'Չկա էլ-փոստի հասցե',
 'noemailtext' => 'Այս մասնակիցը չի նշել էլ-փոստի հասցե կամ նախընտրել է չստանալ էլ-նամակներ այլ մասնակիցներից։',
+'email-legend' => 'Ուղարկել էլ․ նամակ {{SITENAME}}յի այլ մասնակցի',
 'emailfrom' => 'Ումից.',
 'emailto' => 'Ում.',
 'emailsubject' => 'Թեմա.',
@@ -1904,10 +1926,12 @@ $NEWPAGE
 'undelete-bad-store-key' => 'Չհաջողվեց վերականգնել նիշքի $1 ժամդրոշմով տարբերակը. նիշքը բացակայում էր ջնջումից առաջ։',
 'undelete-cleanup-error' => 'Տեղի ունեցավ սխալ չօգտագործվող արխիվացված «$1» նիշքը ջնջելիս։',
 'undelete-missing-filearchive' => 'Չհաջողվեց վերականգնել $1 արխիվային իդենտիֆիկատորով նիշքը, քանի որ այն բացակայում է տվյալների բազայից։ Հնարավոր է այն արդեն վերականգնվել է։',
+'undelete-error' => 'Սխալ էջը վերականգնելիս։',
 'undelete-error-short' => 'Նայլի վերականգնման սխալ. $1',
 'undelete-error-long' => 'Տեղի են ունեցել սխալներ նիշքը վերականգնելու ընթացքում.
 
 $1',
+'undelete-show-file-submit' => 'Այո',
 
 # Namespace form on various pages
 'namespace' => 'Անվանատարածք.',
@@ -1934,6 +1958,10 @@ $1',
 'sp-contributions-logs' => 'տեղեկամատյաններ',
 'sp-contributions-talk' => 'քննարկում',
 'sp-contributions-userrights' => 'մասնակիցների իրավունքների կառավարում',
+'sp-contributions-blocked-notice' => 'Այս մասնակիցը ներկա պահին արգելափակված է։
+Ստորև ներկայացված է արգելափակման տեղեկամատյանի վերջին գրառումը.',
+'sp-contributions-blocked-notice-anon' => 'Այս IP հասցեն ներկա պահին արգելափակված է։
+Ստորև ներկայացված է արգելափակման տեղեկամատյանի վերջին գրառումը.',
 'sp-contributions-search' => 'Որոնել ներդրումները',
 'sp-contributions-username' => 'IP-հասե կամ մասնակցի անուն.',
 'sp-contributions-toponly' => 'Ցույց տալ միայն այն խմբագրումները, որոնք վերջին փոփոխություն են',
@@ -1955,10 +1983,15 @@ $1',
 'whatlinkshere-hideredirs' => '$1 վերահղում',
 'whatlinkshere-hidetrans' => '$1 ներառումները',
 'whatlinkshere-hidelinks' => '$1 հղում',
+'whatlinkshere-hideimages' => '$1 նիշքային հղումներ',
 'whatlinkshere-filters' => 'Զտիչներ',
 
 # Block/unblock
+'autoblockid' => 'Ավտոմատ արգելափակում #$1',
+'block' => 'Արգելափակել մասնակցին',
+'unblock' => 'Արգելափակումից հանել',
 'blockip' => 'Մասնակցի արգելափակում',
+'blockip-title' => 'Արգելափակել մասնակցին',
 'blockip-legend' => 'Մասնակցի արգելափակում',
 'blockiptext' => 'Օգտագործեք ստորև բերված ձևը որոշակի IP-հասցեից կամ մասնակցի անունից գրելու հնարավորությունը արգելափակելու համար։
 Նման բան հարկավոր է անել միայն վանդալության կանխարգելման նպատակով և համաձայն [[{{MediaWiki:Policy-url}}|կանոնակարգի]]։
@@ -1998,6 +2031,7 @@ $1',
 'ipusubmit' => 'Հանել արգելափակումը',
 'unblocked' => '[[User:$1|$1]] մասնակիցը անարգելված է։',
 'unblocked-id' => '$1 արգելափակումը հանված է',
+'blocklist' => 'Արգելափակված մասնակիցներ։',
 'ipblocklist' => 'Արգելափակված IP-հասցեները և մասնակիցները',
 'ipblocklist-legend' => 'Արգելափակված մասնակցի որոնում',
 'ipblocklist-submit' => 'Որոնել',
@@ -2089,6 +2123,7 @@ $1',
 'pagemovedsub' => 'Էջը վերանվանվեց',
 'movepage-moved' => "'''«$1» էջը վերանվանվել է «$2»'''",
 'movepage-moved-redirect' => 'Ստեղծվել է վերահղում։',
+'movepage-moved-noredirect' => 'Վերահղման ստեղծում թույլ չի տրվել',
 'articleexists' => 'Այդ անվանմամբ էջ արդեն գոյություն ունի կամ ձեր ընտրած անվանումը անթույլատրելի է։
 Խնդրում ենք ընտրել այլ անվանում։',
 'talkexists' => "'''Էջը հաջողությամբ տեղափոխվեց, սակայն կցված քննարկման էջը հնարավոր չէր տեղափոխել, քանի որ նոր անվանմամբ էջ արդեն գոյություն ուներ։ Խնդրում ենք միաձուլել դրանք ձեռքով։'''",
@@ -2546,6 +2581,7 @@ $3
 # Special:ComparePages
 'compare-page1' => 'Էջ 1',
 'compare-page2' => 'Էջ 2',
+'compare-submit' => 'Համեմատել',
 
 # Database error messages
 'dberr-header' => 'Այս վիքիում խնդիրներ են առաջացել',
@@ -2574,6 +2610,12 @@ $3
 'logentry-newusers-newusers' => '$1 մասնակիցը ստեղծեց նոր հաշիվ',
 'logentry-newusers-create' => '$1 մասնակիցը ստեղծեց նոր հաշիվ',
 'logentry-newusers-create2' => '$1 Ստեղծեց նոր հաշիվ $3',
+'newuserlog-byemail' => 'Գաղտնաբառն ուղարկված է էլ․ փոստով',
+
+# Feedback
+'feedback-subject' => 'Թեմա.',
+'feedback-message' => 'Հաղորդագրություն․',
+'feedback-close' => 'Արված է',
 
 # Search suggestions
 'searchsuggest-search' => 'Որոնել',
index b9f907a..d1d7ed2 100644 (file)
@@ -12,6 +12,7 @@
  * @author Malafaya
  * @author McDutchie
  * @author Reedy
+ * @author Yfdyh000
  * @author לערי ריינהארט
  */
 
@@ -1957,7 +1958,8 @@ Memora verificar que non existe altere ligamines al patronos ante que tu los del
 'statistics-mostpopular' => 'Le paginas plus visitate',
 
 'disambiguations' => 'Paginas con ligamines a paginas de disambiguation',
-'disambiguationspage' => 'Template:Disambiguation',
+'disambiguationspage' => 'Template:Disambig
+Template:Disambiguation',
 'disambiguations-text' => "Le sequente paginas contine al minus un ligamine a un '''pagina de disambiguation'''.
 Istes debe forsan ligar directemente al articulo sur le thema in question.<br />
 Un pagina se tracta como pagina de disambiguation si illo usa un patrono que es ligate ab [[MediaWiki:Disambiguationspage]].",
index 67e3451..44eff31 100644 (file)
@@ -83,7 +83,7 @@ $messages = array(
 
 'underline-always' => 'Kanayon',
 'underline-never' => 'Saan uray kaanoman',
-'underline-default' => 'Kasisigud a pagbasabasa',
+'underline-default' => 'Kasisigud a kudil wenno pagbasabasa',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Urnosen ti kita ti letra iti lugar:',
@@ -168,8 +168,8 @@ $messages = array(
 'newwindow' => '(aglukat iti sabali a tawa)',
 'cancel' => 'Ukasen',
 'moredotdotdot' => 'Adu pay...',
-'mypage' => 'Panidko',
-'mytalk' => 'Pakitungtungak',
+'mypage' => 'Panid',
+'mytalk' => 'Tungtungan',
 'anontalk' => 'Tungtungan para iti daytoy a pagtaengan ti IP',
 'navigation' => 'Pagdaliasatan',
 'and' => '&#32;ken',
@@ -750,7 +750,7 @@ Annawid a .css ken .js dagiti titulo ket agususar ti babassit a letra, a kas dag
 'note' => "'''Paammo:'''",
 'previewnote' => "'''Laglagipem a daytoy ket panagipadas laeng.'''
 Dagiti sinukatam ket saan pay a naidulin!",
-'continue-editing' => 'Agtultuloy nga agurnos',
+'continue-editing' => 'Mapan idiay pagurnosan a lugar',
 'previewconflict' => 'Daytoy a panagpadas ket agiparang ti testo dita ngato a panagurnos a lugar a kasla agparang no kayatmo nga idulin.',
 'session_fail_preview' => "'''Pasensia! Saanmi a maaramid ti panag-urnos gapu ngamin ta naawanan ti gimong ti data.'''
 Pangngaasi a padasem manen.
@@ -1136,7 +1136,7 @@ Laglagipem laeng a dagiti pagsurotan nagyan ti {{SITENAME}} ket baka baak.',
 
 # Preferences page
 'preferences' => 'Kaykayatan',
-'mypreferences' => 'Kaykayatko',
+'mypreferences' => 'Kaykayatan',
 'prefs-edits' => 'Bilang dagiti inurnos:',
 'prefsnologin' => 'Saan a nakastrek',
 'prefsnologintext' => 'Masapul a <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} nakastrekka]</span> tapno makapili kadagiti kaykayatmo.',
@@ -1152,7 +1152,7 @@ Laglagipem laeng a dagiti pagsurotan nagyan ti {{SITENAME}} ket baka baak.',
 'prefs-rc' => 'Kinaudi a binalbaliwan',
 'prefs-watchlist' => 'Listaan ti bambantayan',
 'prefs-watchlist-days' => 'Alaldaw nga iparang idiay listaan ti bambantayan:',
-'prefs-watchlist-days-max' => 'Kabayag nga $1 {{PLURAL:$1|nga aldaw|nga al-aldaw}}',
+'prefs-watchlist-days-max' => 'Kapaut nga $1 {{PLURAL:$1|nga aldaw|nga al-aldaw}}',
 'prefs-watchlist-edits' => 'Kaadu a bilang ti ipakita kadagiti sinukatan iti napadakkel a bambantayan:',
 'prefs-watchlist-edits-max' => 'Kaadu a bilang: 1000',
 'prefs-watchlist-token' => 'Tandaan ti bambantayan:',
@@ -1181,7 +1181,7 @@ Laglagipem laeng a dagiti pagsurotan nagyan ti {{SITENAME}} ket baka baak.',
 No adda makaammo daytoy a tulbek ditoy a pagikabilan ket mabalin da a basaen ti binambantayam, masapul nga agpilika ti pateg a seguridad.
 
 Adda ditoy ti pugto a pateg a mausarmo: $1',
-'savedprefs' => 'Naidulin dagitoy kaykayatmon.',
+'savedprefs' => 'Naidulinen dagiti kakaykayatam.',
 'timezonelegend' => 'Sona ti oras:',
 'localtime' => 'Lokal nga oras:',
 'timezoneuseserverdefault' => 'Usaren ti wiki a kasisigud ($1)',
@@ -1220,7 +1220,7 @@ Ngem saanto a mabalinen nga ipasubli.',
 'yourrealname' => 'Pudno a nagan:',
 'yourlanguage' => 'Pagsasao:',
 'yourvariant' => 'Linaon ti sabali a pagsasao:',
-'prefs-help-variant' => 'Ti kaykayatmo a sabsabali a panagsurat a maipakita kadagiti linaon ti panid daytoy a wiki.',
+'prefs-help-variant' => 'Ti kinaykayatmo a kita ti pagsasao wenno sabali a panagsurat a maipakita kadagiti linaon ti panid daytoy a wiki.',
 'yournick' => 'Baro a pirma:',
 'prefs-help-signature' => 'Komentario kadagiti  pakipatangan a panid ket  mapirmaan koma iti "<nowiki>~~~~</nowiki>" nga agpabalin ti pirmam ken ti petsa.',
 'badsig' => 'Saan a pudno a kilaw a pirma.
@@ -1372,6 +1372,9 @@ Ti e-surat a pagtaengam ket saan nga maipakita kadagiti agar-aramat nga agkontak
 'rightslogtext' => 'Listaan daytoy kadagiti sinukatan a karbengan ti agar-aramat.',
 'rightslogentry' => 'sinukatan ti panagkameng iti bunggoy ti $1 manipud $2 iti $3',
 'rightslogentry-autopromote' => 'naautomatiko a naipangato a naggapo iti $2 idiay $3',
+'logentry-rights-rights' => 'Ni $1 ket nangbaliw ti grupo a panakaikameng para kenni $3 manipud ti $4 iti $5',
+'logentry-rights-rights-legacy' => 'Ni $1 ket nangbaliw ti grupo a panakaikameng para kenni $3',
+'logentry-rights-autopromote' => 'Ni $1 ket automatiko idi a naipangato manipud ti $4 iti $5',
 'rightsnone' => '(awan)',
 
 # Associated actions - in the sentence "You do not have permission to X"
@@ -1998,7 +2001,7 @@ Kitaen met [[Special:WantedCategories|dagiti makidkiddaw a kategoria]].',
 'linksearch-ok' => 'Biruken',
 'linksearch-text' => 'Ti naataap a tarheta a kas "*.wikipedia.org" ket mabalin nga usaren.
 Masapul ti kangatuan a pagturayan, a kaspagarigan "*.org".<br />
-Natapayaen a protokol: <code>$1</code> (saanmo nga inayon dagitoy iti panagbirukmo) .',
+Dagiti nasuportaran a protokol: <code>$1</code> (naipakasigud ti http:// no awan ti protokol a nainaganan).',
 'linksearch-line' => 'Ti $1 ket nakasilpo idiay $2',
 'linksearch-error' => 'Ti naatap a tarheta ket agparang laeng iti pinagrugi ti nagan ti agsangaili.',
 
@@ -2047,7 +2050,7 @@ Adda pay ngata [[{{MediaWiki:Listgrouprights-helppage}}|adu pay a pakaammo]] a m
 'emailuser-title-target' => 'E-suratam daytoy nga {{GENDER:$1|agar-aramat}}',
 'emailuser-title-notarget' => 'E-suratan ti agar-aramat',
 'emailpage' => 'E-suratan ti agar-aramat',
-'emailpagetext' => 'Mabalinmo nga usaren ti kinabuklan dita baba nga agipatulod ti e-surat a mensahe daytoy nga agar-aramat.
+'emailpagetext' => 'Mabalinmo nga usaren ti kinabuklan dita baba nga agipatulod ti e-surat a mensahe ti daytoy nga {{GENDER:$1|agar-aramat}}.
 Ti e-surat nga inkabilmo idiay  [[Special:Preferences|kakaykayatam]] ket agparang a kas "Naggapu" a pagtaengan ti e-surat, tapno ti nagipatulodam ket makasungbat kenka.',
 'usermailererror' => 'Kita ti surat ket nangisubli ti biddut:',
 'defemailsubject' => '{{SITENAME}} e-surat naggapo ken ni "$1"',
@@ -2079,7 +2082,7 @@ Ti e-surat nga inkabilmo idiay  [[Special:Preferences|kakaykayatam]] ket agparan
 
 # Watchlist
 'watchlist' => 'Bambantayak',
-'mywatchlist' => 'Bambantayak',
+'mywatchlist' => 'Bambantayan',
 'watchlistfor2' => 'Para iti $1 $2',
 'nowatchlist' => 'Awan ti banag iti listaan dagiti bambantayam.',
 'watchlistanontext' => 'Pangngaasim ti $1 tapno makitam dagiti inurnosmo dita bambantayam.',
@@ -2346,7 +2349,7 @@ $1',
 # Contributions
 'contributions' => 'Naaramidan dagiti agar-aramat',
 'contributions-title' => 'Naaramidan ni $1',
-'mycontris' => 'Naaramidak',
+'mycontris' => 'Naar-aramid',
 'contribsub2' => 'Para iti $1 ($2)',
 'nocontribs' => 'Awan ti nasarakan a nasukatan a kapada daytoy a kita.',
 'uctop' => '(rabaw)',
@@ -2387,7 +2390,7 @@ Ti naudi a listaan ti panakaserra ket adda dita baba ta usaren a reperensia:',
 'whatlinkshere-hideredirs' => '$1 dagiti baw-ing',
 'whatlinkshere-hidetrans' => '$1 dagiti mailaklak-am',
 'whatlinkshere-hidelinks' => '$1 dagiti silpo',
-'whatlinkshere-hideimages' => '$1 dagiti silpo ti imahen',
+'whatlinkshere-hideimages' => '$1 a silsilpo ti papeles',
 'whatlinkshere-filters' => 'Dagiti sagat',
 
 # Block/unblock
@@ -2826,7 +2829,7 @@ Mabalinmo a kitaen ti taudanna.',
 'tooltip-upload' => 'Rugian ti agip-ipan',
 'tooltip-rollback' => '"Baliktaden"   isubli ti inurnos (dagiti inurnos) ti daytoy a panid ti kinaudi a nangaramid iti maysa a takla',
 'tooltip-undo' => '"Ibabawi" ipasubli daytoy nga urnos ken lukatanna ti kinabuklan ti urnos iti panagpadas. Agpabalin daytoy a mangikabil ti rason idiay pinakabuklan.',
-'tooltip-preferences-save' => 'Idulin dagiti kaykayatmo',
+'tooltip-preferences-save' => 'Idulin dagiti kakaykayatam',
 'tooltip-summary' => 'Ikabil ti bassit a pakabuklan',
 
 # Metadata
@@ -2856,7 +2859,7 @@ Daytoy ket mabalin a gapuanan babaen ti panilpo a naiparit ti akin ruar a pagsaa
 
 # Info page
 'pageinfo-title' => 'Pakaammo para iti "$1"',
-'pageinfo-not-current' => 'Ti pakaammo ket mabalin laeng a maiparang para iti agdama a panagbalbaliw.',
+'pageinfo-not-current' => 'Pasensia, saan a mabalin ti mangited ti pakaammo para kadagiti daan a panagbalbaliw.',
 'pageinfo-header-basic' => 'Kangrunaan a pakaammuan',
 'pageinfo-header-edits' => 'Pakasaritaan ti inurnos',
 'pageinfo-header-restrictions' => 'Panagsalaknib ti panid',
@@ -2865,6 +2868,7 @@ Daytoy ket mabalin a gapuanan babaen ti panilpo a naiparit ti akin ruar a pagsaa
 'pageinfo-default-sort' => 'Kasisigud a kangrunaan a panagilasin',
 'pageinfo-length' => 'Kaatiddog ti panid (kadagiti byte)',
 'pageinfo-article-id' => 'ID ti panid',
+'pageinfo-language' => 'Pagsasao ti naglaon a panid',
 'pageinfo-robot-policy' => 'Kasasaad ti panagbiruk a makina',
 'pageinfo-robot-index' => 'Mabalin a maipasurotan',
 'pageinfo-robot-noindex' => 'Saan a mabalin a maipasurotan',
@@ -3572,6 +3576,7 @@ Mabalinmo pay nga [[Special:EditWatchlist|usaren ti dati a panagurnos]].',
 'version-license' => 'Lisensia',
 'version-poweredby-credits' => "Daytoy a wiki ket pinaandar ti '''[//www.mediawiki.org/ MediaWiki]''', karbengan a kopia © 2001-$1 $2.",
 'version-poweredby-others' => 'dadduma pay',
+'version-credits-summary' => 'Kayat mi kuma a pammadayawan dagiti sumaganad a tao para kadagiti inparawadda ti [[Special:Version|MediaWiki]].',
 'version-license-info' => 'Ti MediaWiki ket nawaya a software; maiwarasmo ken/wenno mabaliwam babaen ti banag iti GNU General Public License a naipablaak babaen ti Free Software Foundation; nupay iti bersion 2 iti Lisensia, wenno (ti panagpilim) ti  ania man a bersion.
 
 Ti MediaWiki ket naiwarwaras nga adda ti namnama a makatulong, ngem AWAN TI ANIA MAN A GARANTIA; nga awan pay ti naibagbaga a PANAKAILAKO wenno KALAINGAN NA ITI DAYTOY A PANGGEP. Kitaen ti GNU Sapasap a  Publiko a Lisensia para kadagiti adu pay a salaysay.
@@ -3790,4 +3795,6 @@ Nupay kasta, mau-sarmo ti nakabuklan dita baba. Ti komentario nga itedmo ket mai
 'duration-centuries' => '$1 {{PLURAL:$1|siglo|sig-siglo}}',
 'duration-millennia' => '$1 {{PLURAL:$1|milenio|mil-milenio}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'tungtungan',
 );
index 0aa8d2c..0cba9d3 100644 (file)
@@ -401,8 +401,8 @@ $messages = array(
 'newwindow' => '(si apre in una nuova finestra)',
 'cancel' => 'Annulla',
 'moredotdotdot' => 'Altro...',
-'mypage' => 'La mia pagina',
-'mytalk' => 'mie discussioni',
+'mypage' => 'Pagina',
+'mytalk' => 'discussioni',
 'anontalk' => 'Discussioni per questo IP',
 'navigation' => 'Navigazione',
 'and' => '&#32;e',
@@ -2487,7 +2487,7 @@ $1',
 # Contributions
 'contributions' => 'Contributi utente',
 'contributions-title' => 'Contributi di $1',
-'mycontris' => 'miei contributi',
+'mycontris' => 'contributi',
 'contribsub2' => 'Per $1 ($2)',
 'nocontribs' => 'Non sono state trovate modifiche che soddisfino i criteri di ricerca.',
 'uctop' => '(ultima per la pagina)',
@@ -3019,7 +3019,7 @@ Tutte le operazioni di importazione trans-wiki sono registrate nel [[Special:Log
 'pageinfo-robot-index' => 'Indicizzabile',
 'pageinfo-robot-noindex' => 'Non indicizzabile',
 'pageinfo-views' => 'Numero di visualizzazioni',
-'pageinfo-watchers' => 'Numero di utenti che hanno la pagina nei loro Osservati Speciali',
+'pageinfo-watchers' => 'Numero di utenti che hanno la pagina nei loro osservati speciali',
 'pageinfo-redirects-name' => 'Redirect a questa pagina',
 'pageinfo-subpages-name' => 'Sottopagine di questa pagina',
 'pageinfo-subpages-value' => '$1 ($2 {{PLURAL:$2|redirect}}; $3 {{PLURAL:$3|non redirect}})',
@@ -3957,4 +3957,6 @@ Le immagini vengono mostrate alla massima risoluzione disponibile, per gli altri
 'duration-centuries' => '$1 {{PLURAL:$1|secolo|secoli}}',
 'duration-millennia' => '$1 {{PLURAL:$1|millennio|millenni}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'discussioni',
 );
index 3e7f8c7..91102b6 100644 (file)
@@ -495,8 +495,8 @@ $messages = array(
 'newwindow' => '(新しいウィンドウで開きます)',
 'cancel' => '中止',
 'moredotdotdot' => '続き...',
-'mypage' => '自分のページ',
-'mytalk' => '自分のトーク',
+'mypage' => 'ページ',
+'mytalk' => 'トーク',
 'anontalk' => 'このIPアドレスのトーク',
 'navigation' => '案内',
 'and' => '&#32;および&#32;',
@@ -1569,7 +1569,7 @@ $1 {{PLURAL:$1|文字}}以下である必要があります。',
 この情報は公開されます。',
 'email' => 'メール',
 'prefs-help-realname' => '本名は省略できます。
-入力すると、あなたの著作物の帰属表記に本名を使用します。',
+入力すると、あなたの著作物の帰属表示に使われます。',
 'prefs-help-email' => 'メールアドレスは省略できますが、パスワードを忘れた際にパスワードをリセットするのに必要です。',
 'prefs-help-email-others' => '利用者ページやトークページ上のリンクを通じて、他の利用者があなたにメールで連絡を取れるようにすることもできます。
 他の利用者が連絡を取る際にあなたのメールアドレスが開示されることはありません。',
@@ -2708,7 +2708,7 @@ $1',
 # Contributions
 'contributions' => '利用者の投稿記録',
 'contributions-title' => '$1の投稿記録',
-'mycontris' => '自分の投稿記録',
+'mycontris' => '投稿記録',
 'contribsub2' => '利用者: $1 ($2)',
 'nocontribs' => 'これらの条件に一致する変更は見つかりませんでした。',
 'uctop' => '(最新)',
index a0fa0a4..fc13f17 100644 (file)
@@ -303,7 +303,7 @@ $messages = array(
 'newwindow' => '(ახალ ფანჯარაში)',
 'cancel' => 'გაუქმება',
 'moredotdotdot' => 'ვრცლად...',
-'mypage' => 'á\83©á\83\94á\83\9bá\83\98 á\83\92á\83\95á\83\94á\83 á\83\93á\83\98',
+'mypage' => 'გვერდი',
 'mytalk' => 'ჩემი განხილვა',
 'anontalk' => 'ამ IP-ს განხილვა',
 'navigation' => 'ნავიგაცია',
index cb79b93..7dd9664 100644 (file)
@@ -1290,7 +1290,7 @@ Tı şikina sewiya sevekiyaena na pele bıvurnê, hema yê nae sevekiyaena qedem
 'whatlinkshere-hideredirs' => 'peyser sono $1',
 'whatlinkshere-hidetrans' => 'İlawekerdê çaprazi $1',
 'whatlinkshere-hidelinks' => '$1 girey',
-'whatlinkshere-hideimages' => 'girê resmu $1',
+'whatlinkshere-hideimages' => 'Girê dosya $1',
 'whatlinkshere-filters' => 'Filtrey',
 
 # Block/unblock
index e0c126a..d97991a 100644 (file)
@@ -477,8 +477,8 @@ $messages = array(
 'newwindow' => '(새 창으로 열림)',
 'cancel' => '취소',
 'moredotdotdot' => '더 보기...',
-'mypage' => 'ë\82´ ì\82¬ì\9a©ì\9e\90 ë¬¸ì\84\9c',
-'mytalk' => '내 사용자 토론',
+'mypage' => '문서',
+'mytalk' => '토론',
 'anontalk' => '익명 사용자 토론',
 'navigation' => '둘러보기',
 'and' => ',',
@@ -1436,7 +1436,7 @@ $1",
 
 # Preferences page
 'preferences' => '사용자 환경 설정',
-'mypreferences' => '사용자 환경 설정',
+'mypreferences' => '환경 설정',
 'prefs-edits' => '편집 횟수:',
 'prefsnologin' => '로그인하지 않음',
 'prefsnologintext' => '사용자 환경 설정을 바꾸려면 먼저 <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} 로그인]</span>해야 합니다.',
@@ -2400,7 +2400,7 @@ URL이 맞고 해당 웹사이트가 작동하는지 확인해주세요.',
 
 # Watchlist
 'watchlist' => '주시문서 목록',
-'mywatchlist' => '내 주시문서 목록',
+'mywatchlist' => '주시문서 목록',
 'watchlistfor2' => '사용자:$1 $2',
 'nowatchlist' => '주시하는 문서가 아직 없습니다.',
 'watchlistanontext' => '주시문서 목록을 보거나 고치려면 $1 하세요.',
@@ -2665,7 +2665,7 @@ $1',
 # Contributions
 'contributions' => '사용자 기여',
 'contributions-title' => '$1 사용자의 기여 목록',
-'mycontris' => '내 기여 목록',
+'mycontris' => '기여 목록',
 'contribsub2' => '$1($2)의 기여',
 'nocontribs' => '이 사용자는 아무 것도 기여하지 않았습니다.',
 'uctop' => '(최신)',
@@ -4181,4 +4181,6 @@ $5
 'duration-centuries' => '$1{{PLURAL:$1|세기}}',
 'duration-millennia' => '$1{{PLURAL:$1|천년}}',
 
+# Unknown messages
+'mytalk-parenthetical' => '토론',
 );
index 6ba2d82..414eada 100644 (file)
@@ -100,15 +100,15 @@ $messages = array(
 # Dates
 'sunday' => 'Ыйых кюн',
 'monday' => 'Баш кюн',
-'tuesday' => 'Геурге кюн',
-'wednesday' => 'Барас кюн',
+'tuesday' => 'Гюрге кюн',
+'wednesday' => 'Бараз кюн',
 'thursday' => 'Орта кюн',
 'friday' => 'Байрым кюн',
 'saturday' => 'Шабат кюн',
 'sun' => 'Ыйых кюн',
 'mon' => 'Баш кюн',
-'tue' => 'Геурге кюн',
-'wed' => 'Барас кюн',
+'tue' => 'Гр',
+'wed' => 'Брз',
 'thu' => 'Орта кюн',
 'fri' => 'Байрым кюн',
 'sat' => 'Шабат кюн',
@@ -302,6 +302,9 @@ $1',
 'youhavenewmessages' => 'Сизге $1 келдиле ($2).',
 'newmessageslink' => 'джангы билдириуле',
 'newmessagesdifflink' => 'сюзюу бетигизни ахыр тюрлениую',
+'youhavenewmessagesmanyusers' => 'Талай къошулуучудан $1 барды. ($2)',
+'newmessageslinkplural' => '{{PLURAL:$1|джангы билдириуюгюз|джангы билдириулеригиз}}',
+'newmessagesdifflinkplural' => 'ахыр {{PLURAL:$1|тюрлениу|тюрлениу}}',
 'youhavenewmessagesmulti' => '$1 бетде джангы билдириуле бардыла.',
 'editsection' => 'тюрлендир',
 'editold' => 'тюрлендир',
@@ -2583,6 +2586,7 @@ MediaWiki локализациясына юлюш къошаргъа излей
 'pageinfo-watchers' => 'Кёргенлени саны',
 'pageinfo-edits' => 'Тюрлендириулени саны',
 'pageinfo-authors' => 'Авторланы саны',
+'pageinfo-toolboxlink' => 'Бетни юсюнден',
 
 # Skin names
 'skinname-standard' => 'Стандарт',
index 8ee5883..7e9bd87 100644 (file)
@@ -1488,7 +1488,7 @@ Ene zohfällesch ußjewörfelte Schlößel, dää De nämme künnß, wöhr: <cod
 'yourgender' => 'Do bes *',
 'gender-unknown' => 'wesse mer nit',
 'gender-male' => 'Kääl odder Jung',
-'gender-female' => 'Möhn, Weech odder Mädche',
+'gender-female' => 'Möhn, Weesch odder Mädsche',
 'prefs-help-gender' => '* Moß mer nit aanjevve, un wann et aanjejovve eß, dann kallt et Wiki övver Desch als „dä Pitter“ udder „dat Tiina“, sönß uns „Metmaacher Pütz“. Dat kritt de janne Welt ze sinn, nit nur Do allein.',
 'email' => '<i lang="en">e-mail</i>',
 'prefs-help-realname' => '* Dinge richtije Name — kanns De fott looße — wann De en ävver nenne wells, dann weed dä jebruch, öm Ding Beidräch domet ze schmöcke.',
@@ -1628,6 +1628,8 @@ Ene zohfällesch ußjewörfelte Schlößel, dää De nämme künnß, wöhr: <cod
 'rightslogtext' => 'Hee sin de Änderunge an Metmaacher ehre Räächde opjeliss. Op de Sigge üvver Metmaacher, Wiki-Köbesse, Bürrokrade, Stewards, un esu, kanns De nohlese, wat domet es.',
 'rightslogentry' => 'hät däm Metmaacher „$1“ sing Räächde vun „$2“ op „$3“ ömjestallt.',
 'rightslogentry-autopromote' => 'wood automattesch vun $2 zohm $3 jemaat.',
+'logentry-rights-rights-legacy' => '{{GENDER:$1|Dä|Et|Dä Metmaacher|De|Dat}} $1 hät däm Metmaacher $3 sing Räääschte-Jroppe verändert.',
+'logentry-rights-autopromote' => '{{GENDER:$1|Dä|Et|Dä Metmaacher|De|Dat}} $1 wood automattesch vum $4 zom $5 jemaat.',
 'rightsnone' => '(nix)',
 
 # Associated actions - in the sentence "You do not have permission to X"
@@ -2366,11 +2368,10 @@ schecke.',
 'emailuser-title-target' => '<i lang="en">E-mail</i> aan {{GENDER:$1|dä Metmaacher|di Metmaacherėn|dä Metmaacher|di Metmaacherėn|dä Metmaacher}} $1',
 'emailuser-title-notarget' => 'Verschegg en <i lang="en">e-mail</i> aan ene Metmaacher',
 'emailpage' => 'Verscheck <i lang="en">e-mail</i> aan ene Metmaacher',
-'emailpagetext' => 'Wann heh dä Metmaacher en Adräß för sing <i lang="en">e-mail</i> aanjejovve hätt en singe Enstellunge,
-un die deit et och, dann kanns De met däm Fomular hee unge en einzel <i lang="en">e-mail</i> aan dä Metmaacher schecke.
+'emailpagetext' => 'Wann {{GENDER:$1|dä Metmaacher heh|dat heh|heh dä Metmaacher|sei|dat heh}} en Adräß för sing <i lang="en">e-mail</i> aanjejovve hätt en singe Enstellunge, un die deit et och, dann kanns De met däm Fomular heh unge en einzel <i lang="en">e-mail</i> aan {{GENDER:$1|inn|it|dä Metmaacher|heh di Metmaacherėn|et}} schecke.
 
 Ding <i lang="en">e-mail</i>-Adräß, di De en [[Special:Preferences|Ding eije Enstellunge]] aanjejovve häs,
-di weed als em Afsender sing Adräß en Ding <i lang="en">e-mail</i> enjedrage.
+di weed als em Afsender sing Adräß enjedrare.
 Domet kann, wä di <i lang="en">e-mail</i> kritt, drop antwoote, un di Antwood jeiht tirek aan Desch.
 Alles klor?',
 'usermailererror' => 'Dat E-Mail-Objek jov ene Fähler us:',
@@ -2628,7 +2629,9 @@ Versione för die neu Sigg enjerich. Die neu Sigg weed nit ersetz.',
 'undeletedrevisions' => '{{PLURAL:$1|ein Version|$1 Versione}} zeröckjehollt',
 'undeletedrevisions-files' => 'Zesammejenomme {{PLURAL:$1|Ein Version|<strong>$1</strong> Versione|<strong>Kein</strong> Version}} vun {{PLURAL:$2|eine Datei|<strong>$2</strong> Dateie|<strong>nix</strong>}} zeröckjehollt',
 'undeletedfiles' => '{{PLURAL:$1|Ein Datei|<strong>$1</strong> Dateie|<strong>Kein</strong> Dateie}} zeröckjehollt',
-'cannotundelete' => '<strong>Dä.</strong> Et Zeröckholle jing donevve. Maach sinn, dat ene andere Metmaacher flöcker wor, un et et eets jedon hät, un jetz es die Sigg ald widder do jewäse.',
+'cannotundelete' => '<strong>Dä.</strong> Et Zeröckholle jing donävve.
+
+$1',
 'undeletedpage' => '<strong>De Sigg „$1“ es jetz widder do</strong>
 Luur Der et [[Special:Log/delete|Logboch met de fottjeschmesse Sigge]] aan, do häs De de Neuste fottjeschmesse
 un widder herjehollte Sigge.',
@@ -3221,6 +3224,7 @@ Esu kam_mer noch en Aanmerkung en „{{int:summary}}“ maache.',
 'pageinfo-default-sort' => 'Shtandattmääßesch zottiere met däm Schlößel',
 'pageinfo-length' => 'Bytes en dä Sigg',
 'pageinfo-article-id' => 'Dä Sigg ier Nommer en dä Daatebangk',
+'pageinfo-language' => 'De Schprooch vum Sigge-Enhallt',
 'pageinfo-robot-policy' => 'Eijeschaffte för de Söhkmaschiine',
 'pageinfo-robot-index' => 'kammer opnämme',
 'pageinfo-robot-noindex' => 'kammer nit opnämme',
@@ -4020,6 +4024,7 @@ Dä Shtanndat-Zoot-Schlößel „$1“ övverschriif dä älldere Zoot-Schlöße
 'version-license' => 'Lizänz',
 'version-poweredby-credits' => "Dat Wiki heh löp met '''[//www.mediawiki.org/ MediaWiki]''', copyright © 2001–$1 $2.",
 'version-poweredby-others' => 'sönß wää',
+'version-credits-summary' => 'Mer bedanke ons för iehr Beidrähsch zom [[Special:Version|MediaWiki]] bei:',
 'version-license-info' => 'MediaWiki es e frei Projramm. Mer kann et unmolesteet wigger verdeile, un mer kann et verändere, wi mer löstich es, wam_mer sesch dobei aan de <i lang="en">GNU General Public License</i> (jenerälle öffentlesche Lizänz noh GNU) hallde deiht, wi se vun der <i lang="en">Free Software Foundation</i> (Steftung för frei Soffwäer) veröffentlesch woode es. Dobei kam_mer sesch ußsöhke of mer sesch aan de Version 2 dovun hallde deiht, udder öhnz en späädere Fassung.
 
 MediaWiki weed verdeilt met dä Hoffnung, dat et för jet jood es, ävver <span style="text-transform:uppercase">der ohne jeede Jarantie</span>, un esujaa ohne ene unjesaate Jedangke, et künnt <span style="text-transform:uppercase">ze verkoufe</span> sin udder <span style="text-transform:uppercase;">för öhndsene bestemmpte Zweck ze jebruche</span>. Loor Der de jenannte Lizänz aan, wann De mieh Einzelheite weße wells.
index b86c095..fac70e6 100644 (file)
@@ -346,6 +346,9 @@ $messages = array(
 'youhavenewmessages' => '$1 yên te hene ($2).',
 'newmessageslink' => 'Peyamên nû',
 'newmessagesdifflink' => 'cudayî ji guhertoya berê',
+'youhavenewmessagesfromusers' => 'Ji {{PLURAL:$3|bikarhênereke/î din|$3 bikarhêneran}}, ji bo te $1 hene ($2).',
+'newmessageslinkplural' => '{{PLURAL:$1|peyameke nû|peyamên nû}}',
+'newmessagesdifflinkplural' => '{{PLURAL:$1|guherandin|guherandinên dawî}}',
 'youhavenewmessagesmulti' => 'Peyamên nû li $1 ji te re hene.',
 'editsection' => 'biguherîne',
 'editold' => 'biguherîne',
@@ -733,8 +736,7 @@ Sedema qedexekirina $3 ev e: ''$2''",
 'last' => 'berê',
 'page_first' => 'ya pêşîn',
 'page_last' => 'ya paşîn',
-'histlegend' => 'Rênîşan: (cudahî) = cudahiya nav vê û versiyona niha,
-(berê) = cudahiya nav vê û ya berî vê, B = guhertina biçûk',
+'histlegend' => "Rênîşan: ({{int:cur}}) = cudahiya nav vê û versiyona niha, ({{int:last}}) = cudahiya nav vê û ya berî vê, '''{{int:minoreditletter}}''' = guhertina biçûk",
 'history-fieldset-title' => 'Li dîrokê bigere',
 'history-show-deleted' => 'Tenê yên jêbirî',
 'histfirst' => 'Kevintirîn',
index b2ea2a7..0ea887c 100644 (file)
@@ -11,6 +11,7 @@
  * @author Aidabishkek
  * @author Amire80
  * @author Chorobek
+ * @author Growingup
  * @author Muratjumashev
  * @author Ztimur
  */
@@ -40,7 +41,7 @@ $messages = array(
 'tog-editondblclick' => 'Эки басып баракты оңдоо (JavaScript талап кылынат)',
 'tog-editsection' => 'Ар бир секция үчүн «оңдоо» шилтемеси',
 
-'underline-always' => 'Дайым',
+'underline-always' => 'Дайыма',
 'underline-never' => 'Эч качан',
 
 # Font style option in Special:Preferences
@@ -131,7 +132,7 @@ $messages = array(
 'and' => '&#32;жана',
 
 # Cologne Blue skin
-'qbfind' => 'Ð\98зде',
+'qbfind' => 'ТабÑ\83Ñ\83',
 'qbbrowse' => 'Сереп сал',
 'qbedit' => 'Оңдоо',
 'qbpageoptions' => 'Бул барак',
@@ -142,15 +143,15 @@ $messages = array(
 
 # Vector skin
 'vector-action-addsection' => 'Тема кошумчала',
-'vector-action-delete' => 'Өчүр',
+'vector-action-delete' => 'Өчүрүү',
 'vector-action-move' => 'Аталышын өзгөрт',
-'vector-action-protect' => 'Корго',
+'vector-action-protect' => 'Коргоо',
 'vector-action-undelete' => 'Калыбына келтирүү',
 'vector-action-unprotect' => 'Коргоону өзгөртүү',
-'vector-view-create' => 'Ð\91аÑ\88Ñ\82а',
-'vector-view-edit' => 'Оңдо',
+'vector-view-create' => 'Ð\96аÑ\80аÑ\82Ñ\83Ñ\83',
+'vector-view-edit' => 'Оңдоо',
 'vector-view-history' => 'Тарыхын кара',
-'vector-view-view' => 'Оку',
+'vector-view-view' => 'Окуу',
 'vector-view-viewsource' => 'Кайнарын кара',
 'actions' => 'Аракеттер',
 'namespaces' => 'Аталыш топтому',
@@ -160,24 +161,24 @@ $messages = array(
 'returnto' => '$1 барагына кайт.',
 'tagline' => '{{SITENAME}} дан',
 'help' => 'Жардам',
-'search' => 'Изде',
-'searchbutton' => 'Изде',
-'go' => 'Таап бер',
+'search' => 'Издөө',
+'searchbutton' => 'Издөө',
+'go' => 'Өтүү',
 'searcharticle' => 'Алга',
 'history' => 'Барактын тарыхы',
-'history_short' => 'Тарыхы',
+'history_short' => 'Тарых',
 'printableversion' => 'Басма үлгүсү',
 'permalink' => 'Туруктуу шилтеме',
 'print' => 'Басып чыгаруу',
 'view' => 'Кароо',
 'edit' => 'Оңдоо',
-'create' => 'Ð\91аÑ\88Ñ\82а',
+'create' => 'Ð\96аÑ\80аÑ\82Ñ\83Ñ\83',
 'editthispage' => 'Бул баракты оңдо',
 'create-this-page' => 'Бул баракты түзүү',
 'delete' => 'Өчүрүү',
-'deletethispage' => 'Бул баракты өчүрүп кой',
+'deletethispage' => 'Бул баракты өчүрүү',
 'protect' => 'Коргоо',
-'protect_change' => 'өзгөрт',
+'protect_change' => 'өзгөртүү',
 'protectthispage' => 'Бул баракты коргоо',
 'unprotect' => 'Коргоону өзгөртүү',
 'newpage' => 'Жаңы барак',
@@ -189,7 +190,7 @@ $messages = array(
 'articlepage' => 'Макаланы кароо',
 'talk' => 'Талкуу',
 'views' => 'Көрсөтүүлөр',
-'toolbox' => 'Аспап кутусу',
+'toolbox' => 'Аспаптар',
 'userpage' => 'Катышуучунун барагын кароо',
 'projectpage' => 'Долбоор барагын кароо',
 'imagepage' => 'Файлдын барагын кароо',
@@ -204,7 +205,7 @@ $messages = array(
 'lastmodifiedat' => 'Бул барак соңку жолу $1, $2 өзгөртүлгөн.',
 'viewcount' => 'Бул барак {{PLURAL:$1|$1|$1}} жолу ачылды.',
 'protectedpage' => 'Корголгон барак',
-'jumpto' => 'Атта:',
+'jumpto' => 'Өтүү:',
 'jumptonavigation' => 'багыттоо',
 'jumptosearch' => 'издөө',
 
@@ -218,7 +219,7 @@ $messages = array(
 'disclaimerpage' => 'Project:Жалпы жоопкерчиликтен баш тартуу',
 'edithelp' => 'Оңдоого жардам',
 'edithelppage' => 'Help:Оңдоо',
-'helppage' => 'Help:Мазмуну',
+'helppage' => 'Help:Мазмун',
 'mainpage' => 'Башбарак',
 'mainpage-description' => 'Башбарак',
 'portal' => 'Жамаат порталы',
@@ -231,15 +232,15 @@ $messages = array(
 'newmessageslink' => 'жаңы билдирүүлөр',
 'newmessagesdifflink' => 'соңку өзгөрүү',
 'youhavenewmessagesmulti' => 'Сизге $1 жаңы кат бар.',
-'editsection' => 'оңдо',
-'editold' => 'оңдо',
+'editsection' => 'оңдоо',
+'editold' => 'оңдоо',
 'viewsourceold' => 'байкоо',
-'editlink' => 'оңдо',
+'editlink' => 'оңдоо',
 'viewsourcelink' => 'Байкоо',
-'editsectionhint' => '$1 бөлүмүн оңдо',
-'toc' => 'Мазмуну',
-'showtoc' => 'Ð\9aÓ©Ñ\80Ñ\81Ó©Ñ\82',
-'hidetoc' => 'Жашыр',
+'editsectionhint' => '$1 бөлүмүн оңдоо',
+'toc' => 'Мазмун',
+'showtoc' => 'көÑ\80Ñ\81Ó©Ñ\82Ò¯Ò¯',
+'hidetoc' => 'Жашыруу',
 'site-rss-feed' => '$1 RSS тилкеси',
 'site-atom-feed' => '$1 Atom агымы',
 'page-atom-feed' => '"$1" Atom агымы',
@@ -248,16 +249,17 @@ $messages = array(
 # Short words for each namespace, by default used in the namespace tab in monobook
 'nstab-main' => 'Макала',
 'nstab-user' => 'Колдонуучунун барагы',
+'nstab-media' => 'Мультимедиа',
 'nstab-special' => 'Атайын барак',
 'nstab-project' => 'Долбоордун барагы',
 'nstab-image' => 'Файл',
-'nstab-mediawiki' => 'Билдирүү',
-'nstab-template' => 'Ð\9aалÑ\8bп',
+'nstab-mediawiki' => 'Билдирме',
+'nstab-template' => 'Шаблон',
 'nstab-help' => 'Жардам',
 'nstab-category' => 'Категория',
 
 # General errors
-'error' => 'Ð\96аңÑ\8bлÑ\8bÑ\88',
+'error' => 'Ð\9aаÑ\82а',
 'missing-article' => 'Табылууга тийиш «$1» $2 деп аталган баракта текст маалыматтар базасында табылган жок.
 
 Бул сыяктуу абал өчүрүлгөн барактын өзгөрүүлөрдүн тарыхына эски шилтеме менен өткөндө учурайт.
@@ -271,7 +273,7 @@ $messages = array(
 'filecopyerror' => '"$1" файлы "$2" файлына көчүрүлбөдү.',
 'filedeleteerror' => '"$1" файлын өчүрүүгө болбоду.',
 'directorycreateerror' => '"$1" каталогун түзүүгө болбоду.',
-'filenotfound' => '"$1" файлы табылбады.',
+'filenotfound' => '"$1" файлын табууга мүмкүн эмес.',
 'fileexistserror' => '"$1" файлына жазууга болбоду: Мурдатан бар.',
 'unexpected' => 'Күтүлбөгөн маани: "$1"="$2".',
 'formerror' => 'Ката: Форманы жөнөтүүгө болбоду.',
@@ -280,7 +282,7 @@ $messages = array(
 'badtitle' => 'Ыксыз аталыш',
 'badtitletext' => 'Талап кылынган барак аталышы туура эмес, бош, же тилдер-аралык же уики-аралык аталышы туура эмес шилтемеленген.
 Балким аталышта колдонулбай турган бир же андан көп белги камтылган.',
-'viewsource' => 'Кайнарын кара',
+'viewsource' => 'Кароо',
 
 # Login and logout pages
 'welcomecreation' => '== Кош келиңиз, $1! ==
@@ -299,9 +301,9 @@ $messages = array(
 'logout' => 'Чыгуу',
 'userlogout' => 'Чыгуу',
 'notloggedin' => 'Сиз системага кире элексиз',
-'nologin' => 'Ð\9aаÑ\82Ñ\82ала элексизби? $1.',
+'nologin' => 'Ð\9aаÑ\82Ñ\82ай элексизби? $1.',
 'nologinlink' => 'Каттоону башта',
-'createaccount' => 'Ð\96аңÑ\8b ÐºÐ¾Ð»Ð´Ð¾Ð½Ñ\83Ñ\83Ñ\87Ñ\83нÑ\83 ÐºÐ°Ñ\82Ñ\82а',
+'createaccount' => 'ЭÑ\81еп Ð¶Ð°Ð·Ñ\83Ñ\83Ñ\81Ñ\83н Ð¶Ð°Ñ\80аÑ\82Ñ\83Ñ\83',
 'gotaccount' => 'Катталгансызбы? $1.',
 'gotaccountlink' => 'Кирүү',
 'userlogin-resetlink' => 'Кирүүчү маалыматарыңызды унутуп калдыңызбы?',
@@ -314,25 +316,37 @@ $messages = array(
 'loginsuccesstitle' => 'Сиз ийгиликтүү кирдиңиз',
 'wrongpassword' => 'Ката сырсөз киргизилди. Кайтадан аракет кылып көрүңүз.',
 'wrongpasswordempty' => 'Сырсөз киргизилген жок. Кайтадан аракет кылып көрүңүз.',
-'mailmypassword' => 'Жаңы сырсөздү электрондук дарекке жибер',
+'mailmypassword' => 'Жаңы сырсөздү e-mail аркылуу жиберүү',
 'emailconfirmlink' => 'Электрондук дарегиңизди ырастаңыз',
-'accountcreated' => 'Ð\9aаÑ\82Ñ\82алды',
+'accountcreated' => 'ЭÑ\81еп Ð¶Ð°Ð·Ñ\83Ñ\83Ñ\81Ñ\83 Ð¶Ð°Ñ\80аÑ\82Ñ\8bлды',
 'loginlanguagelabel' => 'Тил: $1',
 
 # Change password dialog
 'oldpassword' => 'Эски сырсөз:',
 'newpassword' => 'Жаңы сырсөз:',
 
+# Special:PasswordReset
+'passwordreset-emailelement' => 'Колдонуучу аты: $1
+Убактылуу сырсөз: $2',
+
+# Special:ChangeEmail
+'changeemail' => 'E-mail даректи өзгөртүү',
+'changeemail-oldemail' => 'Кезектеги e-mail дарек:',
+'changeemail-newemail' => 'Жаңы e-mail дарек:',
+'changeemail-none' => '(жок)',
+'changeemail-submit' => "E-mail'ди өзгөртүү",
+'changeemail-cancel' => 'Айнуу',
+
 # Edit page toolbar
-'bold_sample' => 'Калың тамга',
-'bold_tip' => 'Калың тамга',
-'italic_sample' => 'Ð\96анÑ\82Ñ\8bк Ñ\82амга',
-'italic_tip' => 'Ð\96анÑ\82Ñ\8bк Ñ\82амга',
-'link_sample' => 'Шилтеменин аталышы',
+'bold_sample' => 'Кара текст',
+'bold_tip' => 'Кара текст',
+'italic_sample' => 'Ð\9aÑ\83Ñ\80Ñ\81ив Ñ\82екÑ\81Ñ\82',
+'italic_tip' => 'Ð\9aÑ\83Ñ\80Ñ\81ив Ñ\82екÑ\81Ñ\82',
+'link_sample' => 'Шилтеме аты',
 'link_tip' => 'Ички шилтеме',
 'extlink_sample' => 'http://www.example.com шилтеме аталышы',
 'extlink_tip' => 'Сырткы шилтемелерге (http:// префиксин койгонду унутпаңыз)',
-'headline_sample' => 'Аталыштын тексти',
+'headline_sample' => 'Ат тексти',
 'headline_tip' => '2-деңгээлдеги баш аты',
 'nowiki_sample' => 'Форматталбаган текстти бул жерге киргизиңиз',
 'nowiki_tip' => 'Уики-форматтоого көңүл бөлбө',
@@ -344,16 +358,16 @@ $messages = array(
 # Edit pages
 'summary' => 'Кыска түшүндүрүү:',
 'minoredit' => 'Майда оңдоо',
-'watchthis' => 'Бул баракты көзөмөлдө',
-'savearticle' => 'Ð\91аÑ\80акÑ\82Ñ\8b Ñ\81акÑ\82ап ÐºÐ¾Ð¹',
+'watchthis' => 'Бул баракты көзөмөлдөө',
+'savearticle' => 'Ð\91аÑ\80акÑ\82Ñ\8b Ñ\81акÑ\82оо',
 'preview' => 'Алдын ала көрүү',
-'showpreview' => 'Алдын ала көрсөт',
+'showpreview' => 'Алдын ала көрсөтүү',
 'showlivepreview' => 'Ылдам карап чыгуу',
-'showdiff' => 'Өзгөртүүлөрдү көрсөт',
+'showdiff' => 'Өзгөртүүлөрдү көрсөтүү',
 'anoneditwarning' => "'''Эскертүү:''' Сиз каттоодон өткөн жоксуз.
 IP дарегиңиз бул барактын оңдоо тарыхына жазылат.",
 'blockedtext' => 'Сиздин колдонуучу атыңыз же IP дарегиңиз тосмолонгон',
-'blockednoreason' => 'себеби көрсөтүлгөн эмес',
+'blockednoreason' => 'себеби көрсөтүлгөн жок',
 'loginreqtitle' => 'Колдонуучунун аты талап кылынат',
 'loginreqlink' => 'Кирүү',
 'accmailtitle' => 'Сырсөз жөнөтүлдү.',
@@ -370,6 +384,7 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 Сиз башка барактардан [[Special:Search/{{PAGENAME}}|ушул аталыш менен баракты издөө]] салып,
 же <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} тийиштүү жазууларды таба аласыз]</span>.',
 'userpage-userdoesnotexist' => '"$1" Мындай колдонуучу катталган эмес. Ушул баракты түзүүнү же оңдогонду каалганыңыз анык болсун',
+'updated' => '(Жаңыртылды)',
 'previewnote' => "'''Бул алдын ала көрүнүшү гана болгонун эсиңизге алыңыз.'''
 Өзгөртүүлөрүңүз сактала элек!",
 'continue-editing' => 'Өзгөртүүүлөрдү улантабыз',
@@ -394,6 +409,10 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'edit-conflict' => 'Өзгөртүүлөрдүн конфликти',
 'edit-already-exists' => 'Жаңы барак түзүү мүмкүн эмес. Мындай барак бар',
 
+# Content models
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
+
 # Parser/template warnings
 'post-expand-template-inclusion-warning' => "'''Эскертүү:''' Камтылган калыптардын өлчөмү өтө чоң.
 Кээ бир калыптар камтылбайт.",
@@ -404,7 +423,7 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'parser-template-loop-warning' => 'Калыптарда айланма бар:[[$1]]',
 
 # History pages
-'viewpagelogs' => 'Бул барак үчүн тизмелерди кара',
+'viewpagelogs' => 'Бул барак үчүн журналды көрсөтүү',
 'nohistory' => 'Бул барактын өзгөртүүлөр тарыхы жок',
 'currentrev' => 'Акыркы версиясы',
 'currentrev-asof' => '$1 -га соңку версиясы',
@@ -420,7 +439,7 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'page_last' => 'акыркы',
 'histlegend' => "Айырмаларды тандоо: Салыштырыла турган версияларлын тушундагы тегеректерди белгилеп туруп \"Enter\"-ди же астындагы баскычты бас.<br />
 Түшүндүрүү: '''({{int:cur}})''' = соңку версиясынан айырма, '''({{int:last}})''' = мурунку версиясынан айырма, '''{{int:minoreditletter}}''' = майда оңдоо.",
-'history-fieldset-title' => 'ТаÑ\80Ñ\8bÑ\85Ñ\8bн ÐºÐ°Ñ\80а',
+'history-fieldset-title' => 'ТаÑ\80Ñ\8bÑ\85Ñ\8bн ÐºÐ°Ñ\80оо',
 'history-show-deleted' => 'Өчүрүлгөндөрдү гана',
 'histfirst' => 'Эң эски',
 'histlast' => 'Соңку',
@@ -436,15 +455,22 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'revdel-restore' => 'көрүнүшүн өзгөрт',
 'revdel-restore-deleted' => 'өчүрүлгөн версиялар',
 'revdel-restore-visible' => 'көрүнүүчү версиялары',
+'revdelete-reasonotherlist' => 'Башка себеп',
+'revdelete-offender' => 'Барак версиясынын автору:',
+
+# History merging
+'mergehistory-from' => 'Баштапкы барак:',
+'mergehistory-submit' => 'Версияларды бириктирүү',
+'mergehistory-reason' => 'Себеп',
 
 # Merge log
-'revertmerge' => 'Бөл',
+'revertmerge' => 'Бөлүү',
 
 # Diffs
 'history-title' => '"$1" өзгөрүүлөр тарыхы',
 'lineno' => '$1 -сап:',
-'compareselectedversions' => 'Тандалган версияларды салыштыр',
-'editundo' => 'жокко чыгар',
+'compareselectedversions' => 'Тандалган версияларды салыштыруу',
+'editundo' => 'жокко чыгаруу',
 'diff-multi' => '({{PLURAL:$2|колдонуучу|$2 колдонуучу}} тарабынан жасалган {{PLURAL:$1|аралык версия|$1 аралык версия}} көрсөтүлгөн жок)',
 
 # Search results
@@ -452,20 +478,22 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'searchresults-title' => '"$1" үчүн издөө жыйынтыктары',
 'prevn' => 'мурунку {{PLURAL:$1|$1}}',
 'nextn' => 'кийинки{{PLURAL:$1|$1}}',
-'prevn-title' => 'Мурунку $1 {{PLURAL:$1|жыйынтык|жыйынтык}}',
-'nextn-title' => 'Кийинки $1 {{PLURAL:$1|жыйынтык|жыйынтык}}',
-'shown-title' => 'Бир баракка $1 {{PLURAL:$1|жыйынтык|жыйынтык}} көрсөт',
-'viewprevnext' => '($1 {{int:pipe-separator}} $2) ($3) кара',
+'prevn-title' => 'Мурунку $1 {{PLURAL:$1|жыйынтык}}',
+'nextn-title' => 'Кийинки $1 {{PLURAL:$1|жыйынтык}}',
+'shown-title' => 'Барактан $1 {{PLURAL:$1|жыйынтыкты}} көрсөтүү',
+'viewprevnext' => '($1 {{int:pipe-separator}} $2) ($3) кароо',
+'searchmenu-legend' => 'Издөө опциялары',
 'searchmenu-exists' => "'''Бул Уикиде \"[[:\$1]]\" деп аталган барак бар.'''",
 'searchmenu-new' => "'''Бул Уикиде \"[[:\$1]]\" барагын түз!'''",
+'searchhelp-url' => 'Help:Мазмун',
 'searchprofile-articles' => 'Негизги барактар',
-'searchprofile-project' => 'Ð\96аÑ\80дам Ð¶Ð°Ð½Ð° Ð\94олбоор барактары',
+'searchprofile-project' => 'Ð\96аÑ\80дам Ð¶Ð°Ð½Ð° Ð´олбоор барактары',
 'searchprofile-images' => 'Мултимедиа',
 'searchprofile-everything' => 'Баары',
 'searchprofile-advanced' => 'Кеңейтилген',
-'searchprofile-articles-tooltip' => '$1 -де изде',
-'searchprofile-project-tooltip' => '$1 -де изде',
-'searchprofile-images-tooltip' => 'Файлдарды изде',
+'searchprofile-articles-tooltip' => '$1 -де издөө',
+'searchprofile-project-tooltip' => '$1 -де издөө',
+'searchprofile-images-tooltip' => 'Файлдарды издөө',
 'searchprofile-everything-tooltip' => 'Бардык барактарда (талкуу барактарды кошо) изде',
 'searchprofile-advanced-tooltip' => 'Белгиленген аталыш топтомдорунда изде',
 'search-result-size' => '$1 ({{PLURAL:$2|1 сөз|$2 сөз}})',
@@ -478,7 +506,10 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'showingresultsheader' => "'''$4''' үчүн {{PLURAL:$5|'''$3''' жыйынтыктан '''$1'''-и|'''$1 - $2''' -дан '''$3''' жыйынтык}}",
 'search-nonefound' => 'Талапка төп маалымат табылган жок.',
 'powersearch' => 'Издөө',
-'powersearch-legend' => 'Кеңиртип изде',
+'powersearch-legend' => 'Кеңейтилген издөө',
+
+# Quickbar
+'qbsettings-none' => 'Көрсөтпөө',
 
 # Preferences page
 'preferences' => 'Ыңгайлаштыруу',
@@ -487,11 +518,24 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'changepassword' => 'Сырсөздү өзгөртүү',
 'prefs-datetime' => 'Дата жана убакыт',
 'prefs-rc' => 'Соңку өзгөрүүлөр',
-'prefs-watchlist' => 'Байкоо тизме',
-'saveprefs' => 'СакÑ\82ап ÐºÐ¾Ð¹',
+'prefs-watchlist' => 'Байкоо тизмеси',
+'saveprefs' => 'СакÑ\82оо',
 'prefs-editing' => 'Оңдоо',
 'searchresultshead' => 'Издөө',
 'localtime' => 'Жергиликтүү убакыт',
+'servertime' => 'Сервер убагы:',
+'timezoneregion-africa' => 'Африка',
+'timezoneregion-america' => 'Америка',
+'timezoneregion-antarctica' => 'Антарктика',
+'timezoneregion-arctic' => 'Арктика',
+'timezoneregion-asia' => 'Азия',
+'timezoneregion-atlantic' => 'Атлантика океаны',
+'timezoneregion-australia' => 'Австралия',
+'timezoneregion-europe' => 'Европа',
+'timezoneregion-indian' => 'Индий океаны',
+'timezoneregion-pacific' => 'Тынч океаны',
+'prefs-searchoptions' => 'Издөө',
+'default' => 'жарыяланбасча',
 'prefs-files' => 'Файлдар',
 'youremail' => 'Электрондук дарек:',
 'username' => 'Колдонуучунун аты:',
@@ -500,9 +544,14 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'yourlanguage' => 'Тил:',
 'yourvariant' => 'Вариант:',
 'yournick' => 'Такма атыңыз:',
+'yourgender' => 'Жыныс:',
+'gender-male' => 'Эркек',
+'gender-female' => 'Аял',
+'email' => 'Электрондук дарек',
 'prefs-help-email' => 'Электрондук дарек милдетүү эмес, бирок сырсөздү унутуп калсаңыз ал сырсөздү жиберүүгө керек.',
 'prefs-help-email-others' => 'Ошондой эле башкалар сиз менен колдонуучу же талкуу барактарыңыздагы шилтеме аркылуу байланыш түзүүгө уруксат берүүнү тандай аласыз.
 Электрондук дарегиңиз башка кодонуучуларга байланыш түзгөндө көрүнбөйт.',
+'prefs-info' => 'Негизги маалыматтары',
 'prefs-advancedediting' => 'Кеңейтилген',
 'prefs-advancedrc' => 'Кеңейтилген',
 'prefs-advancedrendering' => 'Кеңейтилген',
@@ -510,14 +559,19 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'prefs-advancedwatchlist' => 'Кеңейтилген',
 'prefs-displayrc' => 'Көрсөтүүнү тууралоо',
 
+# User rights
+'userrights-reason' => 'Себеп:',
+
 # Groups
 'group' => 'Топ:',
+'group-user' => 'Катышуучулар',
+'group-sysop' => 'Администраторлор',
 'group-bureaucrat' => 'Бюрократтар',
 
 'group-bureaucrat-member' => 'Бюрократ',
 
 # Associated actions - in the sentence "You do not have permission to X"
-'action-edit' => 'бул баракты оңдо',
+'action-edit' => 'бул баракты оңдоо',
 
 # Recent changes
 'nchanges' => '$1 {{PLURAL:$1|өзгөрүү|өзгөрүү}}',
@@ -531,23 +585,23 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'recentchanges-label-unpatrolled' => 'Бул оңдоо көзөмөлдөн өтө элек.',
 'rcnote' => "Ылдый жакта $5, $4 карата соңку {{PLURAL:$2|күндө|'''$2''' күндө}} жасалган {{PLURAL:$1| '''1''' өзгөрүү| '''$1''' өзгөрүү}}.",
 'rcnotefrom' => "'''$2''' -тан өзгөрүүлөр ылдый жакта ('''$1''' чейин көрсөтүлдү).",
-'rclistfrom' => '$1 күнүнөн баштап жаңы өзгөртүүлөрдү көрсөт',
+'rclistfrom' => '$1 күнүнөн баштап жаңы өзгөртүүлөрдү көрсөтүү',
 'rcshowhideminor' => 'Майда оңдоолорду $1',
 'rcshowhidebots' => 'ботторду $1',
 'rcshowhideliu' => '$1 катталган колдонуучу',
 'rcshowhideanons' => 'Жашыруун колдонуучулар $1',
 'rcshowhidepatr' => 'Көзөмөл алдындагы оңдоолорду $1',
 'rcshowhidemine' => 'Оңдоолорумду $1',
-'rclinks' => 'Соңку $2 кундө жасалган акыркы $1 өзгөртүүлөрдү көрсөт<br />$3',
+'rclinks' => 'Соңку $2 күндө жасалган акыркы $1 өзгөртүүлөрдү көрсөтүү<br />$3',
 'diff' => 'айырма',
-'hist' => 'тарыхы',
-'hide' => 'Жашыр',
-'show' => 'Көрсөт',
+'hist' => 'тарых',
+'hide' => 'Жашыруу',
+'show' => 'Көрсөтүү',
 'minoreditletter' => 'м',
 'newpageletter' => 'Ж',
 'boteditletter' => 'б',
-'rc-enhanced-expand' => 'Ð\91өлүкÑ\82Ó©Ñ\80үн ÐºÓ©Ñ\80Ñ\81Ó©Ñ\82 (JavaScript талап кылынат)',
-'rc-enhanced-hide' => 'Ð\91өлүкÑ\82Ó©Ñ\80үн Ð¶Ð°Ñ\88Ñ\8bÑ\80',
+'rc-enhanced-expand' => 'Ð\9aоÑ\88Ñ\83мÑ\87а Ð¼Ð°Ð°Ð»Ñ\8bмаÑ\82Ñ\82аÑ\80дÑ\8b ÐºÓ©Ñ\80Ñ\81Ó©Ñ\82Ò¯Ò¯ (JavaScript талап кылынат)',
+'rc-enhanced-hide' => 'Ð\9aоÑ\88Ñ\83мÑ\87а Ð¼Ð°Ð°Ð»Ñ\8bмаÑ\82Ñ\82аÑ\80дÑ\8b Ð¶Ð°Ñ\88Ñ\8bÑ\80Ñ\83Ñ\83',
 
 # Recent changes linked
 'recentchangeslinked' => 'Тиешелүү өзгөрүүлөр',
@@ -558,11 +612,12 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'recentchangeslinked-summary' => 'Бул көрсөтүлгөн (же көрсөтүлгөн категорияга кирген) барактан шилтемеленген барактардагы жакын арада жасалган өзгөрүүлөрдүн тизмеси.
 [[Special:Watchlist|Байкоо тизмеңиз]]деги барактар калын арип менен белгиленген.',
 'recentchangeslinked-page' => 'Барактын аталышы',
-'recentchangeslinked-to' => 'Белгиленген барактан шилтемеленген барактардын ордуна өзгөртүулөрдү көрсөт',
+'recentchangeslinked-to' => 'Белгиленген барактан шилтемеленген барактардын ордуна өзгөртүулөрдү көрсөтүү',
 
 # Upload
-'upload' => 'Файл жүктөө',
-'uploadbtn' => 'Файл жүктөө',
+'upload' => 'Файлды жүктөө',
+'uploadbtn' => 'Файлды жүктөө',
+'uploaderror' => 'Жүктөө катасы',
 'uploadlogpage' => 'Жүктөөлөрдүн тизмеси',
 'filedesc' => 'Кыска түшүндүрмө',
 'fileuploadsummary' => 'Кыска түшүндүрмө:',
@@ -595,6 +650,14 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'sharedupload-desc-here' => 'Бул файл $1 -дан  жана башка долбоорлордо пайдаланылышы мүмкүн.
 Төмөндө анын [$2 файлды сыпаттоо барагы]нан сыпаттамасы көрсөтүлгөн.',
 
+# File reversion
+'filerevert-comment' => 'Себеп:',
+
+# File deletion
+'filedelete-legend' => 'Файлды өчүрүү',
+'filedelete-comment' => 'Себеп:',
+'filedelete-submit' => 'Өчүрүү',
+
 # Unused templates
 'unusedtemplates' => 'Колдонулбаган нускалар',
 'unusedtemplateswlh' => 'Башка шилтемелер',
@@ -605,14 +668,20 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 # Statistics
 'statistics' => 'Статистика',
 'statistics-header-users' => 'Колдонуучулардын статистикасы',
+'statistics-pages' => 'Барак',
 
 'disambiguationspage' => 'Template:көп маанилүү',
 
+'brokenredirects-delete' => 'өчүрүү',
+
+'withoutinterwiki-submit' => 'Көрсөтүү',
+
 # Miscellaneous special pages
 'nbytes' => '$1 {{PLURAL:$1|байт|байт}}',
 'nmembers' => '$1{{PLURAL:$1|мүчө|мүчө}}',
 'unusedcategories' => 'Колдонулбаган категориялар',
 'unusedimages' => 'Колдонулбаган файлдар',
+'popularpages' => 'Популярдуу барактар',
 'prefixindex' => 'Префикс менен бардык барактар',
 'shortpages' => 'Кыска макалалар',
 'listusers' => 'Колдонуучулар тизмеси',
@@ -629,7 +698,7 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'booksources-go' => 'Алга',
 
 # Special:Log
-'specialloguserlabel' => 'Ð\9aолдонуучу:',
+'specialloguserlabel' => 'Ð\90Ñ\82каÑ\80уучу:',
 'speciallogtitlelabel' => 'Аталышы:',
 'log' => 'Тизмелер',
 
@@ -637,19 +706,23 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'allpages' => 'Бардык барактар',
 'alphaindexline' => '$1 -дан $2 чейин',
 'nextpage' => 'Кийинки барак ($1)',
-'allpagesfrom' => '-дан башталган барактарды көрсөт:',
+'allpagesfrom' => '-дан башталган барактарды көрсөтүү:',
 'allarticles' => 'Бардык макалалар',
-'allpagesprev' => 'Ð\9cÑ\83Ñ\80Ñ\83нкÑ\83',
+'allpagesprev' => 'Ð\90балкÑ\8b',
 'allpagesnext' => 'Кийинки',
 'allpagessubmit' => 'Алга',
-'allpagesprefix' => '- префикси менен барактарды көрсөт',
+'allpagesprefix' => '- префикси менен барактарды көрсөтүү',
 
 # Special:Categories
 'categories' => 'Категориялар',
 
 # Special:LinkSearch
+'linksearch-ok' => 'Издөө',
 'linksearch-line' => '$1-га $2-дан шилтеме берилди',
 
+# Special:ListUsers
+'listusers-submit' => 'Көрсөтүү',
+
 # Special:Log/newusers
 'newuserlogpage' => 'Жаңы колдонуучулардын тизмеси',
 
@@ -657,27 +730,29 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'listgrouprights-members' => '(мүчөлөрдүн тизмеси)',
 
 # E-mail user
-'emailuser' => 'Бул колдонуучуга кат жибер',
+'emailuser' => 'Бул колдонуучуга кат жиберүү',
 'emailfrom' => '- дан',
-'emailmessage' => 'Кат',
+'emailto' => 'Кимге:',
+'emailsubject' => 'Тема:',
+'emailmessage' => 'Билдирме',
 
 # Watchlist
 'watchlist' => 'Көзөмөл тизмем',
 'mywatchlist' => 'Көзөмөл тизмем',
 'watchlistfor2' => '$1 үчүн $2',
 'watchnologin' => 'Катталган жок',
-'watch' => 'Көзөмөлдө',
-'unwatch' => 'Көзөлдөбө',
+'watch' => 'Көзөмөлдөө',
+'unwatch' => 'Көзөлдөбөө',
 'watchlist-details' => 'Талкуу барактарын эсепке албаганда көзөмөл тизмеңизде {{PLURAL:$1|$1 барак|$1 барак}} бар.',
 'watchlistcontains' => 'Байкоо тизмеңизде $1 {{PLURAL:$1|барак бар|барак бар}}.',
-'wlshowlast' => 'Соңку $1 саат $2 күн $3 көрсөт.',
+'wlshowlast' => 'Соңку $1 саат $2 күн $3 көрсөтүү.',
 'watchlist-options' => 'Көзөмөл тизменин ырастоолору',
 
 'changed' => 'өзгөртүлдү',
 'created' => 'түзүлдү',
 
 # Delete
-'deletepage' => 'Баракты өчүрүп кой',
+'deletepage' => 'Баракты өчүрүү',
 'confirm' => 'Ырастоо',
 'actioncomplete' => 'Иш-аракет жыйынтыкталды',
 'actionfailed' => 'Аракет натыйжасыз болду',
@@ -685,24 +760,29 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'deletecomment' => 'Себеп',
 
 # Rollback
-'rollbacklink' => 'кайтар',
+'rollbacklink' => 'кайтаруу',
 
 # Protect
 'protectlogpage' => 'Коргоо тизмеси',
 'protectedarticle' => '"[[$1]]" корголгон',
+'restriction-type' => 'Укуктар:',
 
 # Restrictions (nouns)
 'restriction-edit' => 'Оңдоо',
+'restriction-create' => 'Жаратуу',
+'restriction-upload' => 'Жүктөө',
 
 # Undelete
-'undeletebtn' => 'Калыбына келтир',
-'undeletelink' => 'көрсөт/калыбына келтир',
-'undeleteviewlink' => 'көрсөт',
-'undeletecomment' => 'Түшүндүрмө:',
+'undeletebtn' => 'Калыбына келтирүү',
+'undeletelink' => 'кароо/калыбына келтирүү',
+'undeleteviewlink' => 'кароо',
+'undeletereset' => 'Түшүрүү',
+'undeletecomment' => 'Себеп:',
+'undelete-search-submit' => 'Издөө',
 
 # Namespace form on various pages
 'namespace' => 'Аталыштар мейкиндиги:',
-'invert' => 'Белгиленгенди кайтар',
+'invert' => 'Белгиленгенди текскерилетүү',
 'blanknamespace' => '(Негизги)',
 
 # Contributions
@@ -719,10 +799,10 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'sp-contributions-uploads' => 'жүктөөлөр',
 'sp-contributions-logs' => 'тизме',
 'sp-contributions-talk' => 'талкуу',
-'sp-contributions-search' => 'СалÑ\8bмдаÑ\80Ñ\8bн Ð¸Ð·Ð´Ðµ',
+'sp-contributions-search' => 'СалÑ\8bмдаÑ\80Ñ\8bмдÑ\8b Ð¸Ð·Ð´Ó©Ó©',
 'sp-contributions-username' => 'IP дареги же колдонуучунун аты:',
 'sp-contributions-toponly' => 'Соңку версиялары болгон оңдоолорду гана көрсөт',
-'sp-contributions-submit' => 'Изде',
+'sp-contributions-submit' => 'Издөө',
 
 # What links here
 'whatlinkshere' => 'Жетелеме шилтемелер',
@@ -731,13 +811,13 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'linkshere' => "'''[[:$1]]''' барагына шилтеме берген барактар:",
 'nolinkshere' => "'''[[:$1]]''' барагына шилтеме берген барак жок.",
 'isredirect' => 'кайра багыттоо барагы',
-'istemplate' => 'кошкуч',
+'istemplate' => 'кошуу',
 'isimage' => 'файл шилтемеси',
 'whatlinkshere-prev' => '{{PLURAL:$1|мурунку|мурунку $1}}',
 'whatlinkshere-next' => '{{PLURAL:$1|кийинки|кийинки $1}}',
 'whatlinkshere-links' => '← шилтемелер',
 'whatlinkshere-hideredirs' => 'Багыттоолорду $1',
-'whatlinkshere-hidetrans' => 'Кошкучтарды $1',
+'whatlinkshere-hidetrans' => '$1 кошуулары',
 'whatlinkshere-hidelinks' => 'Шилтемелерди $1',
 'whatlinkshere-hideimages' => 'Сүрөт шилтемелерин $1',
 'whatlinkshere-filters' => 'Чыпкалар',
@@ -747,10 +827,13 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 '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',
 'ipbotheroption' => 'башка',
 'ipblocklist' => 'Тосмолонгон колдонуучулар',
-'blocklink' => 'тосмоло',
-'unblocklink' => 'тосмолоону алып сал',
-'change-blocklink' => 'тосмолоону өзгөрт',
-'contribslink' => 'салымдары',
+'blocklist-reason' => 'Себеп',
+'ipblocklist-submit' => 'Издөө',
+'blocklink' => 'тосмолоо',
+'unblocklink' => 'тосмолоону алуу',
+'change-blocklink' => 'тосмолоону өзгөртүү',
+'contribslink' => 'салым',
+'emaillink' => 'кат жиберүү',
 'blocklogpage' => 'Тосмоолордун тизмеси',
 'blocklogentry' => '[[$1]] тосмолонду, тосмолоо мөөнөтү: $2 $3',
 'block-log-flags-nocreate' => 'Каттоо мүмкүн эмес',
@@ -758,11 +841,13 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 # Move page
 'movelogpage' => 'Өзгөртүлгөн аталыштардын тизмеси',
 'movereason' => 'Себеп',
-'revertmove' => 'кайÑ\82аÑ\80Ñ\8bп Ð°Ð»',
-'delete_and_move_confirm' => 'Ооба, бул баракты өчүр',
+'revertmove' => 'кайÑ\82аÑ\80Ñ\83Ñ\83',
+'delete_and_move_confirm' => 'Ооба, бул баракты өчүрөм',
 
 # Export
-'export' => 'Барактарды чыгар',
+'export' => 'Барактарды экспорттоо',
+'export-addcat' => 'Кошуу',
+'export-addns' => 'Кошуу',
 
 # Namespace 8 related
 'allmessages' => 'Система билдирүүлөрү',
@@ -774,12 +859,15 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'allmessages-filter-submit' => 'Алга',
 
 # Thumbnails
-'thumbnail-more' => 'Чоңойт',
+'thumbnail-more' => 'Чоңойтуу',
 'thumbnail_error' => 'Кичирейтилген сүрөттү түзүүдө ката: $1',
 
+# Special:Import
+'import-interwiki-submit' => 'Импорттоо',
+
 # Tooltip help for the actions
-'tooltip-pt-userpage' => 'Ð\9aолдонуучу барагыңыз',
-'tooltip-pt-mytalk' => 'Талкуу барагыңыз',
+'tooltip-pt-userpage' => 'Ð\9aаÑ\82Ñ\8bÑ\88уучу барагыңыз',
+'tooltip-pt-mytalk' => 'Талкуулоо барагыңыз',
 'tooltip-pt-preferences' => 'Ырастоолоруңуз',
 'tooltip-pt-watchlist' => 'Өзгөрүүлөрүн көзөмөлгө алган барактардын тизмеси',
 'tooltip-pt-mycontris' => 'Салымдарыңыздын тизмеси',
@@ -787,64 +875,64 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'tooltip-pt-logout' => 'Чыгуу',
 'tooltip-ca-talk' => 'Барактын мазмуну боюнча талкуу',
 'tooltip-ca-edit' => 'Сиз бул баракты оңдой аласыз. Кичи пейилдикке, сактоодон мурда алдын ала көрсөтүү нукуурун колдонуңуз.',
-'tooltip-ca-addsection' => 'Жаңы бөлүм башта',
+'tooltip-ca-addsection' => 'Жаңы бөлүмдү баштөө',
 'tooltip-ca-viewsource' => 'Бул барак корголгон.
 Сиз анын кайнарын көрө аласыз',
 'tooltip-ca-history' => 'Бул барактын мурунку оңдоолору',
-'tooltip-ca-protect' => 'Бул баракты корго',
-'tooltip-ca-delete' => 'Бул баракты өчүр',
-'tooltip-ca-move' => 'Барак аталышын өзгөрт',
+'tooltip-ca-protect' => 'Бул баракты коргоо',
+'tooltip-ca-delete' => 'Бул баракты өчүрүү',
+'tooltip-ca-move' => 'Баракты көчүрүү',
 'tooltip-ca-watch' => 'Бул баракты көзөмөл тизмеңизге кошуңуз',
 'tooltip-ca-unwatch' => 'Бул баракты көзөмөл тизмеңизден алып салыңыз',
-'tooltip-search' => '{{SITENAME}} изде',
-'tooltip-search-go' => 'Так ушундай аталыштагы баракты көрсөт',
-'tooltip-search-fulltext' => 'Ушул текст менен барактарды изде',
-'tooltip-p-logo' => 'Башбаракка кайрыл',
-'tooltip-n-mainpage' => 'Башбаракка кайрыл',
-'tooltip-n-mainpage-description' => 'Башбаракка кайрыл',
-'tooltip-n-portal' => 'Ð\94олбооÑ\80 Ñ\82Ñ\83Ñ\83Ñ\80алÑ\83Ñ\83, Ñ\8dмне Ð¶Ð°Ñ\81ай Ð°Ð»Ð°Ñ\81Ñ\8bз, ÐºÐ°Ð¹Ñ\81Ñ\8b Ð¶ÐµÑ\80де Ñ\82абÑ\8bлаÑ\82',
-'tooltip-n-currentevents' => 'УÑ\87Ñ\83Ñ\80дагÑ\8b Ð¾ÐºÑ\83Ñ\8fлаÑ\80 Ñ\82Ñ\83Ñ\83Ñ\80алÑ\83Ñ\83 ÐºÐ¾Ñ\88Ñ\83мÑ\87а Ð¼Ð°Ð°Ð»Ñ\8bмаÑ\82 Ñ\82ап',
+'tooltip-search' => '{{SITENAME}} издөө',
+'tooltip-search-go' => 'Так ушундай аталыштагы баракты көрсөтүү',
+'tooltip-search-fulltext' => 'Ушул текст менен барактарды издөө',
+'tooltip-p-logo' => 'Башбаракка өтүү',
+'tooltip-n-mainpage' => 'Башбаракка өтүү',
+'tooltip-n-mainpage-description' => 'Башбаракка өтүү',
+'tooltip-n-portal' => 'Ð\94олбооÑ\80 Ñ\82Ñ\83Ñ\83Ñ\80алÑ\83Ñ\83, Ñ\8dмне Ð¶Ð°Ñ\81ай Ð°Ð»Ð°Ñ\81Ñ\8bз, ÐºÐ°Ð¹Ñ\81Ñ\8b Ð¶ÐµÑ\80де Ñ\8dмне Ð±Ð°Ñ\80 Ð¶Ó©Ð½Ò¯Ð½Ð´Ó©',
+'tooltip-n-currentevents' => 'УÑ\87Ñ\83Ñ\80дагÑ\8b Ð¾ÐºÑ\83Ñ\8fлаÑ\80 Ñ\82Ñ\83Ñ\83Ñ\80алÑ\83Ñ\83 ÐºÐ¾Ñ\88Ñ\83мÑ\87а Ð¼Ð°Ð°Ð»Ñ\8bмаÑ\82 Ñ\82абÑ\83Ñ\83',
 'tooltip-n-recentchanges' => 'Уикидеги соңку өзгөртүүлөрдүн тизмеси',
-'tooltip-n-randompage' => 'ТÑ\83Ñ\88 ÐºÐµÐ»Ð´Ð¸ Ð±Ð°Ñ\80акÑ\82Ñ\8b Ð¶Ò¯ÐºÑ\82Ó©',
+'tooltip-n-randompage' => 'Ð\98Ñ\80еÑ\82Ñ\81из Ñ\82Ò¯Ñ\80дө Ð±Ð¸Ñ\80 Ð±Ð°Ñ\80акÑ\82Ñ\8b Ð°Ñ\87Ñ\83Ñ\83',
 'tooltip-n-help' => 'Маалымат алуу үчүн',
 'tooltip-t-whatlinkshere' => 'Ушул жерге шилтемеси бар бардык уики барактардын тизмеси',
 'tooltip-t-recentchangeslinked' => 'Бул барактан шилтеме берилген барактардагы соңку өзгөрүүлөр',
 'tooltip-feed-atom' => 'Бул барак үчүн Atom агымы',
 'tooltip-t-contributions' => 'Бул колдонуучунун салымдарынын тизмеси',
-'tooltip-t-emailuser' => 'Бул колдонуучуга кат жибер',
-'tooltip-t-upload' => 'Файлдарды жүктө',
+'tooltip-t-emailuser' => 'Бул колдонуучуга кат жиберүү',
+'tooltip-t-upload' => 'Файлдарды жүктөө',
 'tooltip-t-specialpages' => 'Бардык атайын барактардын тизмеси',
 'tooltip-t-print' => 'Бул барактын басып чыгарууга ылайыктуу түрү',
 'tooltip-t-permalink' => 'Барактын бул версиясына туруктуу шилтеме',
-'tooltip-ca-nstab-main' => 'Ð\91аÑ\80акÑ\82Ñ\8bн Ð¼Ð°Ð·Ð¼Ñ\83нÑ\83н ÐºÐ°Ñ\80а',
-'tooltip-ca-nstab-user' => 'Ð\9aолдонÑ\83Ñ\83Ñ\87Ñ\83нÑ\83н Ð¶ÐµÐºÐµ Ð±Ð°Ñ\80агÑ\8bн ÐºÓ©Ñ\80Ñ\81Ó©Ñ\82',
+'tooltip-ca-nstab-main' => 'Ð\91аÑ\80акÑ\82Ñ\8bн Ð¼Ð°Ð·Ð¼Ñ\83нÑ\83н ÐºÐ°Ñ\80оо',
+'tooltip-ca-nstab-user' => 'Ð\9aаÑ\82Ñ\8bÑ\88Ñ\83Ñ\83Ñ\87Ñ\83нÑ\83н Ð±Ð°Ñ\80агÑ\8bн ÐºÓ©Ñ\80Ñ\81Ó©Ñ\82Ò¯Ò¯',
 'tooltip-ca-nstab-special' => 'Бул атайын барак, аны оңдой албайсыз',
-'tooltip-ca-nstab-project' => 'Долбоор барагын кара',
-'tooltip-ca-nstab-image' => 'Файл барагын көрсөт',
-'tooltip-ca-nstab-template' => 'Ð\9aалÑ\8bпÑ\82Ñ\8b ÐºÓ©Ñ\80Ñ\81Ó©Ñ\82',
-'tooltip-ca-nstab-category' => 'Категория барагын көрсөт',
-'tooltip-minoredit' => 'Муну майда оңдоо деп белгиле',
-'tooltip-save' => 'ӨзгөÑ\80Ñ\82үүлөÑ\80дү Ñ\81акÑ\82ап ÐºÐ¾Ð¹',
+'tooltip-ca-nstab-project' => 'Долбоор барагын көрүү',
+'tooltip-ca-nstab-image' => 'Файл барагын көрүү',
+'tooltip-ca-nstab-template' => 'ШаблондÑ\83 ÐºÓ©Ñ\80Ò¯Ò¯',
+'tooltip-ca-nstab-category' => 'Категория барагын көрүү',
+'tooltip-minoredit' => 'Муну майда оңдоо деп белгилөө',
+'tooltip-save' => 'ӨзгөÑ\80Ñ\82үүлөÑ\80дү Ñ\81акÑ\82оо',
 'tooltip-preview' => 'Кичи пейлдикке, өзгөртүүлөрдү алдын ала көрсөтүүнү сактоодон мурун колдонуңуз!',
-'tooltip-diff' => 'Тексттке киргизген өзгөртүүлөрдү көрсөт',
-'tooltip-compareselectedversions' => 'Ð\91Ñ\83л Ð±Ð°Ñ\80акÑ\82Ñ\8bн Ñ\82андалган Ñ\8dки Ð²ÐµÑ\80Ñ\81иÑ\8fÑ\81Ñ\8bнÑ\8bн Ð°Ð¹Ñ\8bÑ\80малаÑ\80Ñ\8bн ÐºÐ°Ñ\80а',
+'tooltip-diff' => 'Тексттке киргизген өзгөртүүлөрдү көрсөтүү',
+'tooltip-compareselectedversions' => 'Ð\91Ñ\83л Ð±Ð°Ñ\80акÑ\82Ñ\8bн Ñ\82андалган Ñ\8dки Ð²ÐµÑ\80Ñ\81иÑ\8fÑ\81Ñ\8bнÑ\8bн Ð°Ð¹Ñ\8bÑ\80малаÑ\80Ñ\8bн ÐºÐ°Ñ\80оо',
 'tooltip-watch' => 'Бул баракты көзөмөл тизмеңизге кошуңуз',
 'tooltip-rollback' => '"Кайтар" бир баскыч менен бул барактын соңку оңдоочусунун өзгөртүүлөрүн алып салат',
 'tooltip-undo' => 'Киргизилген оңдоону алып салат жана жокко чыгаруунун себебин белгилөөгө мүмкүнчүлүк берип алдын ала көрсөтүүнү ачат',
-'tooltip-summary' => 'Ð\9aÑ\8bÑ\81ка ÐºÐ¾Ñ\80Ñ\83Ñ\82Ñ\83ндÑ\83 ÐºÐ¸Ñ\80гиз',
+'tooltip-summary' => 'Ð\9aÑ\8bÑ\81ка Ð±Ð°Ñ\8fндаманÑ\8b ÐºÐ¸Ñ\80гизиңиз',
 
 # Attribution
 'others' => 'башкалар',
 
 # Browsing diffs
-'previousdiff' => 'â\86\90 Ð\9cÑ\83Ñ\80Ñ\83нкÑ\83 оңдоо',
-'nextdiff' => 'Жаңы түзөтүү →',
+'previousdiff' => 'â\86\90 Ð­Ñ\81киÑ\81ин оңдоо',
+'nextdiff' => 'Жаңысын оңдоо →',
 
 # Media information
-'file-info-size' => '$1 × $2 пиксел, файлдын көлөмү: $3, MIME тиби: $4',
+'file-info-size' => '$1 × $2 пиксель, файлдын көлөмү: $3, MIME түрү: $4',
 'file-nohires' => 'Мындан дагы толук чечилиши жок.',
 'svg-long-desc' => 'SVG файл, шарттуу түрдө $1 × $2 пиксел, файлдын көлөмү: $3',
-'show-big-image' => 'ТолÑ\83к Ñ\87еÑ\87илиÑ\88и',
+'show-big-image' => 'ТолÑ\83к Ñ\87еÑ\87ими',
 
 # Special:NewFiles
 'newimages' => 'Жаңы файлдардын галлереясы',
@@ -888,7 +976,7 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'exif-focalplaneresolutionunit-2' => 'дюйм',
 
 # External editor support
-'edit-externally' => 'Бул файлды сырткы программа колдонуу аркылуу оңдо',
+'edit-externally' => 'Бул файлды сырткы программа колдонуу аркылуу оңдоо',
 'edit-externally-help' => '(Толук маалымат алуу үчүн [//www.mediawiki.org/wiki/Manual:External_editors setup instructions] барагына кайрылсаңыз болот)',
 
 # 'all' in various places, this might be different for inflected languages
@@ -901,9 +989,9 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'confirmemail_loggedin' => 'Электрондук дарегиңиз ырасталды.',
 
 # Watchlist editing tools
-'watchlisttools-view' => 'Тийиштүү өзгөрүүлөрдү көрсөт',
-'watchlisttools-edit' => 'Көзөмөл тизмени кара жана оңдо',
-'watchlisttools-raw' => 'Жетиле элек көзөмөл тизмени оңдо',
+'watchlisttools-view' => 'Тийиштүү өзгөрүүлөрдү көрсөтүү',
+'watchlisttools-edit' => 'Көзөмөл тизмени кара жана оңдоо',
+'watchlisttools-raw' => 'Жетиле элек көзөмөл тизмени оңдоо',
 
 # Core parser functions
 'duplicate-defaultsort' => '\'\'\'Эскертүү:\'\'\' "$2" белгиленген ылгоочу ачкыч "$1" мурунку белгиленген ылгоочу ачкычты жокко чыгарат.',
@@ -915,16 +1003,25 @@ IP дарегиңиз бул барактын оңдоо тарыхына жаз
 'specialpages' => 'Атайын барактар',
 
 # External image whitelist
-'external_image_whitelist' => ' #Бул сапты болгондой калтыр<pre>
-#Туруктуу айтылыштардын бөлүмдөрүн (// арасындагы бөлүмүн гана) астына жайгаштыр 
+'external_image_whitelist' => ' #Бул сапты болгондой калтыруу<pre>
+#Туруктуу айтылыштардын бөлүмдөрүн (// арасындагы бөлүмүн гана) астына жайгаштыру 
 #Алар сырткы сүрөттөрдүн URL менен байланыштырылат
 #Ылайыктуулары сүрөт болуп көрсөтүлөт, калгандары сүрөттөргө шилтеме болуп көрсөтүлөт
 ## менен башталган саптар, түшүндүрмө болуп эсептелет
 #Баш же кичине тамга айырмасыз
 
-#Туруктуу айтылыштардын бөлүмдөрүн ушул саптын үстүнө жайгаштыр. Бул сапты болгондой калтыр.</pre>',
+#Туруктуу айтылыштардын бөлүмдөрүн ушул саптын үстүнө жайгаштыр. Бул сапты болгондой калтыруу.</pre>',
 
 # Special:Tags
 'tag-filter' => '[[Special:Tags|Энбелги]] чыпкасы:',
 
+# Feedback
+'feedback-subject' => 'Тема:',
+'feedback-message' => 'Билдирме:',
+'feedback-cancel' => 'Айнуу',
+'feedback-close' => 'Даяр',
+
+# Search suggestions
+'searchsuggest-search' => 'Издөө',
+
 );
index 9b37238..abcaeab 100644 (file)
@@ -279,8 +279,8 @@ $messages = array(
 'newwindow' => '(in fenestra nova aperietur)',
 'cancel' => 'Abrogare',
 'moredotdotdot' => 'Plus...',
-'mypage' => 'Pagina mea',
-'mytalk' => 'Disputatio mea',
+'mypage' => 'Pagina',
+'mytalk' => 'Disputatio',
 'anontalk' => 'Disputatio huius IP',
 'navigation' => 'Navigatio',
 'and' => '&#32;et',
@@ -878,7 +878,7 @@ Conare praefixare tua inquisitionem cum ''all:'' ut quaeras contenta omnia (pagi
 
 # Preferences page
 'preferences' => 'Praeferentiae',
-'mypreferences' => 'Praeferentiae meae',
+'mypreferences' => 'Praeferentiae',
 'prefs-edits' => 'Numerus recensionum:',
 'prefsnologin' => 'Conventum non est apertum',
 'prefsnologintext' => '<span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} Conventum aperire]</span> debes ad praeferentias tuas modificandum.',
@@ -1657,7 +1657,7 @@ Si pagina nova cum ipso nomine post deletionem creata est, emendationes restitut
 # Contributions
 'contributions' => 'Conlationes usoris',
 'contributions-title' => 'Conlationes usoris $1',
-'mycontris' => 'Conlationes meae',
+'mycontris' => 'Conlationes',
 'contribsub2' => 'Pro $1 ($2)',
 'nocontribs' => 'Nullae mutationes inventae sunt ex his indiciis.',
 'uctop' => ' (vertex)',
index d74b3db..82aaefe 100644 (file)
@@ -314,8 +314,8 @@ $messages = array(
 'newwindow' => '(geet an enger neier Fënster op)',
 'cancel' => 'Zréck',
 'moredotdotdot' => 'Méi …',
-'mypage' => 'Meng Säit',
-'mytalk' => 'Meng Diskussioun',
+'mypage' => 'Säit',
+'mytalk' => 'Diskussioun',
 'anontalk' => 'Diskussioun fir dës IP Adress',
 'navigation' => 'Navigatioun',
 'and' => '&#32;a(n)',
@@ -1226,7 +1226,7 @@ Denkt w.e.g drunn datt d'Navigatiounslinken d'Wiel vun de Versiounen nees zréck
 
 # Preferences page
 'preferences' => 'Astellungen',
-'mypreferences' => 'Meng Astellungen',
+'mypreferences' => 'Astellungen',
 'prefs-edits' => 'Zuel vun den Ännerungen:',
 'prefsnologin' => 'Net ageloggt',
 'prefsnologintext' => 'Dir musst <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}}ageloggt]</span> sinn, fir Är Astellungen änneren ze kënnen.',
@@ -2140,7 +2140,7 @@ D\'E-Mailadress, déi Dir an [[Special:Preferences|Ären Astellungen]] aginn hut
 
 # Watchlist
 'watchlist' => 'Meng Iwwerwaachungslëscht',
-'mywatchlist' => 'Meng Iwwerwaachungslëscht',
+'mywatchlist' => 'Iwwerwaachungslëscht',
 'watchlistfor2' => 'Vum $1 $2',
 'nowatchlist' => 'Är Iwwerwaachungslëscht ass eidel.',
 'watchlistanontext' => "Dir musst $1 fir Säiten op ärer Iwwerwaachungslëscht ze gesinn oder z'änneren.",
@@ -2402,7 +2402,7 @@ $1',
 # Contributions
 'contributions' => 'Kontributioune vum Benotzer',
 'contributions-title' => 'Kontributioune vum $1',
-'mycontris' => 'Meng Kontributiounen',
+'mycontris' => 'Kontributiounen',
 'contribsub2' => 'Fir $1 ($2)',
 'nocontribs' => 'Et goufe keng Ännerunge fonnt, déi dëse Kritèren entspriechen.',
 'uctop' => '(aktuell)',
index a92dfec..834a00d 100644 (file)
@@ -2110,6 +2110,7 @@ Protokoly zaka <code>$1</code> aza ampiana ao amin'ny karokao izy ireo.",
 'mailnologin' => 'Tsy misy adiresy handefasana ny tenimiafina',
 'mailnologintext' => "Mila [[Special:UserLogin|miditra]] ianao sady manana imailaka mandeha sy voamarina ao amin'ny [[Special:Preferences|mombamomba anao]] vao afaka mandefa imailaka amin'ny mpikambana hafa.",
 'emailuser' => 'Andefaso imailaka io mpikambana io',
+'emailuser-title-target' => "Handefa mailaka any amin'ity mpikambana ity{{GENDER:$1}}",
 'emailuser-title-notarget' => "Handefa imailaka an'ilay mpikambana",
 'emailpage' => 'Andefaso imailaka io mpikambana io',
 'emailpagetext' => "Raha nametraka adiresy tena miasa tao amin'ny [[Special:Preferences|mombamomba azy io mpikambana io]],
@@ -2258,6 +2259,7 @@ ataovy am-pitandremana ity tao ity.",
 'rollback' => 'Foano indray ilay fanovana',
 'rollback_short' => 'Aza ovaina indray',
 'rollbacklink' => 'foano',
+'rollbacklinkcount' => 'hamoana fanovana{{PLURAL:$1}} $1',
 'rollbackfailed' => "Tsy voaverina amin'ny teo aloha",
 'cantrollback' => "Tsy afaka iverenana ny fanovana; ny mpanova farany ihany no tompon'ny pejy.",
 'alreadyrolled' => "Tsy afaka foanana ny fanovana ny pejy « [[:$1]] » nataon'i [[User:$2|$2]] ([[User talk:$2|Dinika]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]])
@@ -2440,7 +2442,7 @@ Aseho eo ambany ny iditra farany ao amin'ny laogim-panakanana  mba hampahalala :
 'whatlinkshere-hideredirs' => '$1 ny fihodinana',
 'whatlinkshere-hidetrans' => '$1 ny tsofo-pejy',
 'whatlinkshere-hidelinks' => '$1 ny rohy',
-'whatlinkshere-hideimages' => '$1 rakitra mirohy',
+'whatlinkshere-hideimages' => '$1 ny rakitra mirohy',
 'whatlinkshere-filters' => 'sivana',
 
 # Block/unblock
@@ -2937,6 +2939,13 @@ Raha alefanao ilay izy, mety ho simban'io renifango io ny solosainao.",
 'bydate' => 'araka ny daty',
 'sp-newimages-showfrom' => "Aseho ny rakitra vaovao manomboka amin'ny $1 tamin'ny $2",
 
+# Video information, used by Language::formatTimePeriod() to format lengths in the above messages
+'seconds' => 'segondra{{PLURAL:$1}}',
+'minutes' => 'minitra{{PLURAL:$1}}',
+'hours' => 'ora{{PLURAL:$1}}',
+'days' => 'andro{{PLURAL:$1}}',
+'ago' => '$1 lasa izay',
+
 # Bad image list
 'bad_image_list' => "Ity ny andrefiny :
 
index 2e4b7a2..9a5aa18 100644 (file)
@@ -482,8 +482,8 @@ $messages = array(
 'newwindow' => '(се отвора во нов прозорец)',
 'cancel' => 'Откажи',
 'moredotdotdot' => 'Повеќе...',
-'mypage' => 'Ð\9cоÑ\98а Ñ\81траница',
-'mytalk' => 'мои Ñ\80азговоÑ\80и',
+'mypage' => 'Страница',
+'mytalk' => 'РазговоÑ\80',
 'anontalk' => 'Разговор за оваа IP-адреса',
 'navigation' => 'Навигација',
 'and' => '&#32;и',
@@ -1440,7 +1440,7 @@ $1",
 
 # Preferences page
 'preferences' => 'Нагодувања',
-'mypreferences' => 'мои Ð½агодувања',
+'mypreferences' => 'Ð\9dагодувања',
 'prefs-edits' => 'Број на уредувања:',
 'prefsnologin' => 'Не сте најавени',
 'prefsnologintext' => 'Мора да бидете <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} најавени]</span> за да ги менувате вашите кориснички нагодувања.',
@@ -2399,7 +2399,7 @@ $1',
 
 # Watchlist
 'watchlist' => 'мои набљудувања',
-'mywatchlist' => 'мои Ð½абљудувања',
+'mywatchlist' => 'Ð\9dабљудувања',
 'watchlistfor2' => 'За $1 $2',
 'nowatchlist' => 'Немате ништо во списокот на набљудувања.',
 'watchlistanontext' => 'Се бара $1 за да можете да го прегледувате и уредувате списокот на набљудувања.',
@@ -2665,7 +2665,7 @@ $1',
 # Contributions
 'contributions' => 'Кориснички придонеси',
 'contributions-title' => 'Придонеси на корисникот $1',
-'mycontris' => 'мои Ð¿ридонеси',
+'mycontris' => 'Ð\9fридонеси',
 'contribsub2' => 'За $1 ($2)',
 'nocontribs' => 'Не се пронајдени промени што одговараат на овој критериум.',
 'uctop' => ' (врв)',
@@ -4318,4 +4318,6 @@ $5
 'duration-centuries' => '$1 {{PLURAL:$1|век|века}}',
 'duration-millennia' => '$1 {{PLURAL:$1|милениум|милениуми}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'разговор',
 );
index 997d30b..4d35104 100644 (file)
@@ -465,8 +465,8 @@ $messages = array(
 'newwindow' => '(പുതിയ ജാലകത്തിൽ തുറന്നു വരും)',
 'cancel' => 'റദ്ദാക്കുക',
 'moredotdotdot' => 'കൂടുതൽ...',
-'mypage' => 'à´\8eà´¨àµ\8dà´±àµ\86 à´¤à´¾àµ¾',
-'mytalk' => 'à´\8eà´¨àµ\8dà´±àµ\86 à´¸à´\82വാദതàµ\8dതാൾ',
+'mypage' => 'താൾ',
+'mytalk' => 'സംവാദത്താൾ',
 'anontalk' => 'ഈ ഐ.പി.യുടെ സം‌വാദം താൾ',
 'navigation' => 'ഉള്ളടക്കം',
 'and' => '&#32;ഒപ്പം',
@@ -594,7 +594,7 @@ $1',
 'youhavenewmessages' => 'താങ്കൾക്ക് $1 ഉണ്ട് ($2).',
 'newmessageslink' => 'പുതിയ സന്ദേശങ്ങൾ',
 'newmessagesdifflink' => 'അവസാന മാറ്റം',
-'youhavenewmessagesfromusers' => 'താà´\99àµ\8dà´\95ൾà´\95àµ\8dà´\95àµ\8d {{PLURAL:$3|മറàµ\8dà´±àµ\8aà´°àµ\81 à´\89പയàµ\8bà´\95àµ\8dതാവàµ\8d|മറàµ\8dà´±àµ\8d $3 ഉപയോക്താക്കൾ}} $1 ചേർത്തിട്ടുണ്ട് ($2).',
+'youhavenewmessagesfromusers' => 'താà´\99àµ\8dà´\95ൾà´\95àµ\8dà´\95àµ\8d {{PLURAL:$3|à´\92à´°àµ\81 à´\89പയàµ\8bà´\95àµ\8dതാവàµ\8d|$3 ഉപയോക്താക്കൾ}} $1 ചേർത്തിട്ടുണ്ട് ($2).',
 'youhavenewmessagesmanyusers' => 'താങ്കൾക്ക് പലർ $1 ചേർത്തിട്ടുണ്ട് ($2).',
 'newmessageslinkplural' => '{{PLURAL:$1|പുതിയ സന്ദേശം|പുതിയ സന്ദേശങ്ങൾ}}',
 'newmessagesdifflinkplural' => 'അവസാന {{PLURAL:$1|മാറ്റം|മാറ്റങ്ങൾ}}',
@@ -1376,7 +1376,7 @@ $1",
 
 # Preferences page
 'preferences' => 'ക്രമീകരണങ്ങൾ',
-'mypreferences' => 'à´\8eà´¨àµ\8dà´±àµ\86 à´\95àµ\8dà´°à´®àµ\80à´\95à´°à´£à´\99àµ\8dà´\99ൾ',
+'mypreferences' => 'ക്രമീകരണങ്ങൾ',
 'prefs-edits' => 'ആകെ തിരുത്തലുകൾ:',
 'prefsnologin' => 'ലോഗിൻ ചെയ്തിട്ടില്ല',
 'prefsnologintext' => 'ഉപയോക്തൃക്രമീകരണങ്ങൾ മാറ്റാൻ താങ്കൾ <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} ലോഗിൻ]</span> ചെയ്തിരിക്കണം.',
@@ -2310,7 +2310,7 @@ https://www.mediawiki.org/wiki/Manual:Image_Authorization കാണുക.',
 
 # Watchlist
 'watchlist' => 'ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടിക',
-'mywatchlist' => 'à´\9eാൻ à´¶àµ\8dà´°à´¦àµ\8dധിà´\95àµ\8dà´\95àµ\81à´¨àµ\8dനവ',
+'mywatchlist' => 'ശ്രദ്ധിക്കുന്നവ',
 'watchlistfor2' => 'ഉപയോക്താവ്:$1 $2',
 'nowatchlist' => 'താങ്കൾ ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടികയിൽ ഇനങ്ങളൊന്നുമില്ല.',
 'watchlistanontext' => 'താങ്കൾ ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടിക കാണുവാനോ തിരുത്തുവാനോ $1.',
@@ -2564,7 +2564,7 @@ $1',
 # Contributions
 'contributions' => 'ഉപയോക്താവിന്റെ സംഭാവനകൾ',
 'contributions-title' => '$1 എന്ന ഉപയോക്താവിന്റെ സംഭാവനകൾ',
-'mycontris' => 'à´\8eà´¨àµ\8dà´±àµ\86 à´¸à´\82ഭാവനà´\95ൾ',
+'mycontris' => 'സംഭാവനകൾ',
 'contribsub2' => '$1 എന്ന ഉപയോക്താവിന്റെ $2.',
 'nocontribs' => 'ഈ മാനദണ്ഡങ്ങളുമായി യോജിക്കുന്ന മാറ്റങ്ങൾ ഒന്നും കണ്ടില്ല.',
 'uctop' => '(അവസാനത്തെ തിരുത്തൽ)',
index b4fde5e..adfdef0 100644 (file)
@@ -326,8 +326,8 @@ $messages = array(
 'newwindow' => '(dibuka di tetingkap baru)',
 'cancel' => 'Batalkan',
 'moredotdotdot' => 'Lagi...',
-'mypage' => 'Laman saya',
-'mytalk' => 'Perbualan saya',
+'mypage' => 'Halaman',
+'mytalk' => 'Perbualan',
 'anontalk' => 'Perbualan bagi IP ini',
 'navigation' => 'Pandu arah',
 'and' => '&#32;dan',
@@ -1250,7 +1250,7 @@ Cuba berikan awalan ''all:'' untuk mencari semua kandungan (termasuk laman perbi
 
 # Preferences page
 'preferences' => 'Keutamaan',
-'mypreferences' => 'Keutamaan saya',
+'mypreferences' => 'Keutamaan',
 'prefs-edits' => 'Jumlah suntingan:',
 'prefsnologin' => 'Belum log masuk',
 'prefsnologintext' => 'Anda hendaklah <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} log masuk]</span> terlebih dahulu untuk menetapkan keutamaan.',
@@ -2106,7 +2106,7 @@ Lihat juga [[Special:WantedCategories|kategori yang dikehendaki]].',
 'linksearch-ok' => 'Cari',
 'linksearch-text' => 'Kad bebas seperti "*.wikipedia.org" dibenarkan.<br />
 Memerlukan sekurang-kurangnya satu domain peringkat tinggi, cth. "*.org".<br />
-Protokol yang disokong: <code>$1</code> (jangan bubuh sebarang protokol ini dalam carian anda)',
+Protokol yang disokong: <code>$1</code> (menjadi http:// jika tiada protokol dinyatakan).',
 'linksearch-line' => '$1 dipaut dari $2',
 'linksearch-error' => 'Kad bebas hanya boleh digunakan pada permulaan nama hos.',
 
@@ -2190,7 +2190,7 @@ Alamat e-mel yang ditetapkan dalam [[Special:Preferences|keutamaan anda]] akan d
 
 # Watchlist
 'watchlist' => 'Senarai pantau',
-'mywatchlist' => 'Senarai pantau saya',
+'mywatchlist' => 'Senarai pantau',
 'watchlistfor2' => 'Bagi $1 $2',
 'nowatchlist' => 'Tiada item dalam senarai pantau anda.',
 'watchlistanontext' => 'Sila $1 terlebih dahulu untuk melihat atau menyunting senarai pantau anda.',
@@ -2451,7 +2451,7 @@ $1',
 # Contributions
 'contributions' => 'Sumbangan pengguna',
 'contributions-title' => 'Sumbangan oleh $1',
-'mycontris' => 'Sumbangan saya',
+'mycontris' => 'Sumbangan',
 'contribsub2' => 'Oleh $1 ($2)',
 'nocontribs' => 'Tiada sebarang perubahan yang sepadan dengan kriteria-kriteria ini.',
 'uctop' => '(puncak)',
@@ -2490,7 +2490,7 @@ $1',
 'whatlinkshere-hideredirs' => '$1 pelencongan',
 'whatlinkshere-hidetrans' => '$1 penyertaan',
 'whatlinkshere-hidelinks' => '$1 pautan',
-'whatlinkshere-hideimages' => '$1 pautan imej',
+'whatlinkshere-hideimages' => '$1 pautan fail',
 'whatlinkshere-filters' => 'Penapis',
 
 # Block/unblock
index 8974aed..82cf54d 100644 (file)
@@ -40,6 +40,7 @@
  * @author Sjurhamre
  * @author Stigmj
  * @author Teak
+ * @author Wouterkoch
  * @author לערי ריינהארט
  */
 
@@ -362,7 +363,7 @@ $messages = array(
 
 'underline-always' => 'Alltid',
 'underline-never' => 'Aldri',
-'underline-default' => 'Bruk nettleserstandard',
+'underline-default' => 'Nettleserens standardinnstillinger',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Skrifttype i redigeringsboksen:',
@@ -447,8 +448,8 @@ $messages = array(
 'newwindow' => '(åpnes i et nytt vindu)',
 'cancel' => 'Avbryt',
 'moredotdotdot' => 'Mer …',
-'mypage' => 'Min side',
-'mytalk' => 'Min diskusjonsside',
+'mypage' => 'Egen brukerside',
+'mytalk' => 'Egen brukerdiskusjonsside',
 'anontalk' => 'Brukerdiskusjon for denne IP-adressen',
 'navigation' => 'Navigasjon',
 'and' => '&#32;og',
@@ -1383,7 +1384,7 @@ For å søke i alle, bruk prefikset ''all:'' (inkluderer diskusjonssider, maler,
 
 # Preferences page
 'preferences' => 'Innstillinger',
-'mypreferences' => 'Innstillinger',
+'mypreferences' => 'Egne brukerinnstillinger',
 'prefs-edits' => 'Antall redigeringer:',
 'prefsnologin' => 'Ikke logget inn',
 'prefsnologintext' => 'Du må være <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} logget inn]</span> for å endre brukerinnstillingene.',
@@ -2238,7 +2239,7 @@ Se også [[Special:WantedCategories|ønskede kategorier]].',
 'linksearch-pat' => 'Søkemønster:',
 'linksearch-ns' => 'Navnerom:',
 'linksearch-ok' => 'Søk',
-'linksearch-text' => 'Jokertegn som «*.wikipedia.org» kan brukes.
+'linksearch-text' => 'Jokertegn slik som i «*.wikipedia.org» kan brukes.
 Det kreves at det oppgis minst et toppnivådomene, for eksempel «*.org».<br />
 Støttede protokoller: <code>$1</code> (ikke legg til noen av disse i søket ditt).',
 'linksearch-line' => '$1 lenkes fra $2',
@@ -2321,7 +2322,7 @@ E-postadressen du har satt i [[Special:Preferences|innstillingene dine]] vil vis
 
 # Watchlist
 'watchlist' => 'Overvåkningsliste',
-'mywatchlist' => 'Overvåkningsliste',
+'mywatchlist' => 'Egen brukers overvåkningsliste',
 'watchlistfor2' => 'For $1 $2',
 'nowatchlist' => 'Du har ingenting i overvåkningslisten.',
 'watchlistanontext' => 'Vennligst $1 for å vise eller redigere sider på overvåkningslisten din.',
@@ -2572,7 +2573,7 @@ $1',
 # Contributions
 'contributions' => 'Brukerbidrag',
 'contributions-title' => 'Brukerbidrag av $1',
-'mycontris' => 'Mine bidrag',
+'mycontris' => 'Mine redigeringer',
 'contribsub2' => 'For $1 ($2)',
 'nocontribs' => 'Ingen endringer er funnet som passer disse kriteriene.',
 'uctop' => '(siste)',
index 72994b6..c9de2fe 100644 (file)
@@ -486,8 +486,8 @@ $messages = array(
 'newwindow' => '(opent in een nieuw venster)',
 'cancel' => 'Annuleren',
 'moredotdotdot' => 'Meer…',
-'mypage' => 'Mijn gebruikerspagina',
-'mytalk' => 'Mijn overleg',
+'mypage' => 'Gebruikerspagina',
+'mytalk' => 'Overleg',
 'anontalk' => 'Overlegpagina voor dit IP-adres',
 'navigation' => 'Navigatie',
 'and' => '&#32;en',
@@ -1459,7 +1459,7 @@ De gegevens over {{SITENAME}} zijn mogelijk niet bijgewerkt.',
 
 # Preferences page
 'preferences' => 'Voorkeuren',
-'mypreferences' => 'Mijn voorkeuren',
+'mypreferences' => 'Voorkeuren',
 'prefs-edits' => 'Aantal bewerkingen:',
 'prefsnologin' => 'Niet aangemeld',
 'prefsnologintext' => 'U moet <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} aangemeld]</span> zijn om uw voorkeuren te kunnen instellen.',
@@ -2427,7 +2427,7 @@ De ontvanger kan dus direct naar u reageren.',
 
 # Watchlist
 'watchlist' => 'Volglijst',
-'mywatchlist' => 'Mijn volglijst',
+'mywatchlist' => 'Volglijst',
 'watchlistfor2' => 'Voor $1 $2',
 'nowatchlist' => 'Uw volglijst is leeg.',
 'watchlistanontext' => 'Om uw volglijst te bekijken of te bewerken moet u zich $1.',
@@ -2690,7 +2690,7 @@ $1',
 # Contributions
 'contributions' => 'Gebruikersbijdragen',
 'contributions-title' => 'Bijdragen van $1',
-'mycontris' => 'Mijn bijdragen',
+'mycontris' => 'Bijdragen',
 'contribsub2' => 'Voor $1 ($2)',
 'nocontribs' => 'Geen wijzigingen gevonden die aan de gestelde criteria voldoen.',
 'uctop' => '(laatste wijziging)',
@@ -4207,4 +4207,6 @@ Anders kunt u ook het eenvoudige formulier hieronder gebruiken. Uw reactie wordt
 'duration-centuries' => '$1 {{PLURAL:$1|eeuw|eeuwen}}',
 'duration-millennia' => '$1 {{PLURAL:$1|millennium|millennia}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'overleg',
 );
index ec1086b..be74d0d 100644 (file)
@@ -450,7 +450,7 @@ $messages = array(
 'cancel' => 'Avbryt',
 'moredotdotdot' => 'Meir …',
 'mypage' => 'Sida mi',
-'mytalk' => 'Diskusjonssida mi',
+'mytalk' => 'Diskusjon',
 'anontalk' => 'Diskusjonside for denne IP-adressa',
 'navigation' => 'Navigering',
 'and' => '&#32;og',
@@ -937,11 +937,9 @@ Han kan ha vorten flytta eller sletta medan du såg på sida.',
 
 Passordet for den nye kontoen kan verta endra på ''[[Special:ChangePassword|endra passord]]''-sida etter innlogging.",
 'newarticle' => '(Ny)',
-'newarticletext' => "'''{{SITENAME}} har ikkje noka side med namnet {{PAGENAME}} enno.'''
-* For å opprette ei slik side kan du skrive i boksen under og klikke på «Lagre». Endringane vil vere synlege med det same.
-* Om du er ny her er det tilrådd å sjå på [[{{MediaWiki:Helppage}}|hjelpesida]] først.
-* Om du lagrar ei testside, vil du ikkje kunne slette henne sjølv.
-* Dersom du ikkje ønskjer å endre sida, kan du utan risiko klikke på '''attende'''-knappen i nettlesaren din.",
+'newarticletext' => "Du har følgt ei lenkje til ei side som ikkje finst enno.
+For å opprette sida, kan du skrive i boksen under (sjå [[{{MediaWiki:Helppage}}|hjelpesida]] for meir informasjon).
+Dersom du ikkje ønskjer å opprette sida, kan du utan risiko klikke 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.
 Vi 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.''",
 'noarticletext' => 'Det er nett no ikkje noko tekst på denne sida.
@@ -1346,7 +1344,7 @@ Ver merksam på at registra deira kan vera utdaterte.',
 
 # Preferences page
 'preferences' => 'Innstillingar',
-'mypreferences' => 'Innstillingane mine',
+'mypreferences' => 'Innstillingar',
 'prefs-edits' => 'Tal på endringar:',
 'prefsnologin' => 'Ikkje innlogga',
 'prefsnologintext' => 'Du må vere <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} logga inn]</span> for å endre brukarinnstillingane.',
@@ -2273,7 +2271,7 @@ E-postadressa du har sett i [[Special:Preferences|innstillingane dine]] vil dukk
 
 # Watchlist
 'watchlist' => 'Overvakingsliste',
-'mywatchlist' => 'Overvakingslista mi',
+'mywatchlist' => 'Overvakingsliste',
 'watchlistfor2' => 'For $1 $2',
 'nowatchlist' => 'Du har ikkje noko i overvakingslista di.',
 'watchlistanontext' => 'Du lyt $1 for å vise eller endre sider på overvakingslista di.',
@@ -2523,7 +2521,7 @@ $1',
 # Contributions
 'contributions' => 'Brukarbidrag',
 'contributions-title' => 'Bidrag av $1',
-'mycontris' => 'Eigne bidrag',
+'mycontris' => 'Bidrag',
 'contribsub2' => 'For $1 ($2)',
 'nocontribs' => 'Det vart ikkje funne nokon endringar gjorde av denne brukaren.',
 'uctop' => ' (øvst)',
@@ -2765,7 +2763,7 @@ I desse falla lyt du flytta eller fletta sida manuelt, om ynskeleg.",
 'delete_and_move' => 'Slett og flytt',
 'delete_and_move_text' => '== Sletting påkravd ==
 
-Målsida «[[:$1]]» finst alt. Vil du sletta henne for å gjeva rom for flytting?',
+Målsida «[[:$1]]» finst allereie. Vil du slette ho for å gje rom for flytting?',
 'delete_and_move_confirm' => 'Ja, slett sida',
 'delete_and_move_reason' => 'Sletta for å gje rom for flytting frå «[[$1]]»',
 'selfmove' => 'Kjelde- og måltitlane er like; kan ikkje flytte sida over seg sjølv.',
@@ -3747,9 +3745,14 @@ Du kan òg [[Special:EditWatchlist|nytte standardverktøyet]].',
 'version-hook-subscribedby' => 'Brukt av',
 'version-version' => '(versjon $1)',
 'version-license' => 'Lisens',
-'version-poweredby-credits' => "Denne wikien er dreven av '''[//www.mediawiki.org/ MediaWiki]''', copyright © 2001-$1 $2.",
+'version-poweredby-credits' => "Denne wikien er driven av '''[//www.mediawiki.org/ MediaWiki]''', copyright © 2001-$1 $2.",
 'version-poweredby-others' => 'andre',
 'version-credits-summary' => 'Me ynskjer godskriva desse personane for tilskotet deira til [[Special:Version|MediaWiki]].',
+'version-license-info' => 'MediaWiki er fri programvare; du kan redistribuera det og/eller modifisera det under krava i GNU General Public License som publisert av Free Software Foundation; anten versjon 2 av lisensen, eller (om du ynskjer det) ein kvar seinare versjon.
+
+MediaWiki er distribuert i håp om at det vil vera nyttig, men UTAN NOKON GARANTI; ikkje eingong ein implisitt garanti for at det KAN SELJAST eller at det EIGNAR SEG TIL EIT VISST FØREMÅL. Sjå GNU General Public License for fleire detaljar.
+
+Du skal ha motteke [{{SERVER}}{{SCRIPTPATH}}/COPYING ein kopi av GNU General Public License] saman med dette programmet; om ikkje, skriv til Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA eller [//www.gnu.org/licenses/old-licenses/gpl-2.0.html les det på nettet].',
 'version-software' => 'Installert programvare',
 'version-software-product' => 'Produkt',
 'version-software-version' => 'Versjon',
@@ -3961,4 +3964,6 @@ Om ikkje kan du nytta det enkle skjemaet under. Merknaden din vert lagd til på
 'duration-centuries' => '$1 {{PLURAL:$1|hundreår|hundreår}}',
 'duration-millennia' => '$1 {{PLURAL:$1|tusenår|tusenår}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'diskusjon',
 );
index 5be7b31..41a9597 100644 (file)
@@ -121,6 +121,7 @@ $messages = array(
 'category-file-count' => "{{PLURAL:$2|Chol catégorie o seulemint chol fichié-lo.|{{PLURAL:$1|Ech fichier-lo est|$1 Chés fichiés-lo sont}} din l'catégorie-lo, pou un total éd $2 fichiés.}}",
 'category-file-count-limited' => "{{PLURAL:$1|Ech fichié d'apré est|Chés $1 fichiés d'apré sont}} dins l'catégorie-lo.",
 'listingcontinuesabbrev' => 'cont.',
+'noindex-category' => 'Paches nin indécsées',
 'broken-file-category' => "Paches aveuc des loïens d'fichiés bérzillés",
 
 'about' => 'À pérpos',
@@ -128,7 +129,7 @@ $messages = array(
 'newwindow' => '(ouvrir din eune nouvèle fernéte)',
 'cancel' => 'Canchler',
 'moredotdotdot' => 'Plu...',
-'mypage' => 'Em pache',
+'mypage' => 'Pache',
 'mytalk' => 'Min bavouér',
 'anontalk' => "Bavouér pou chl'IP-lo",
 'navigation' => 'Navigachon',
@@ -330,6 +331,7 @@ Si s'n'est poin ch'cas-lo, pététe éq ch'est un bogue din ch'businkillache. <b
 'createaccount' => 'Créer un conpte',
 'gotaccount' => "Jou qu'os avez piécha un conpte? '''$1'''.",
 'gotaccountlink' => 'Intrer',
+'userlogin-resetlink' => "Vos avez oblié vous détals d'connécsion ?",
 'createaccountmail' => 'par imèle',
 'badretype' => "Chés mots d'passe intrés, is sont poin bon.",
 'userexists' => "Nom d’utilisateur entré déjà utilisé.
@@ -394,6 +396,10 @@ Si vos ètes ichi par bérlure, bukez su l'bouton '''értour''' du navigateu.",
 Os povez [[Special:Search/{{PAGENAME}}|foaire eune érchérche du tite del pache]] din chés eutes paches,
 <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} érchércher din chés érliées opéracions]
 ou [{{fullurl:{{FULLPAGENAME}}|action=edit}} créer chol pache]</span>.',
+'noarticletext-nopermission' => "Achteure i n’y o autchun teske dseur l'pache-lo.
+Os povez [[Special:Search/{{PAGENAME}}|foaire eune érchérche du tite del pache]] din chés eutes paches,
+o bin <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} érchércher din chés érliées gazètes]</span>
+mais vos n'avez poin l'droué d'créer chol pache.",
 'previewnote' => "'''Afute! ch'teske-lo ch'est seulemint eune prévue.'''
 
 Vos cangemints, is sont poin coèr inrégistrés!",
@@ -408,10 +414,16 @@ Os prométtez auchi éq vos avez écrit ch'teske vous-méme, ou éq vos l’avez
 'template-semiprotected' => '(semi-garanti)',
 'hiddencategories' => '{{PLURAL:$1|Catégorie muchée|Catégories muchées}} pou chol pache:',
 'permissionserrorstext-withaction' => "Vos n’avez poin l'pérmichon éd $2, pou {{PLURAL:$1|ch'motif suivant|chés motifs suivants}}:",
+'recreate-moveddeleted-warn' => "'''Afute ! : Os ètes in route à ércréer eune pache qu'o té abolie édvant.'''
+
+Controler qu'ch'est pértinint d' porsuire chés modificacions édseur chol pache. L'jornal des défacions pi des déplachemints l'est affiké chi-édsous :",
+'moveddeleted-notice' => "Chol pache ale o té abolie. L'jornal des défacions pi des déplachemints il est affiké chi-édsous pour référinche.",
 
 # Parser/template warnings
 'post-expand-template-inclusion-warning' => "Affute : Chèle pache ale a trop d’modèles. Des inclusions n'sront poin foaites.",
 'post-expand-template-inclusion-category' => "Paches aveuc granmint d'modèles",
+'post-expand-template-argument-warning' => "Afute : Chol pache ale o au moins un paramète d'modèle dont l'inclusion est rindue impossibe. Apré éstinsion, chti-chi il éroait produit un résultat trop long, i n'a donc poin té inclus.",
+'post-expand-template-argument-category' => "Paches aveuc des paramètes d'modèle mie évalués",
 
 # History pages
 'viewpagelogs' => 'Vir chés gasètes del pache-lo',
@@ -428,9 +440,13 @@ Os prométtez auchi éq vos avez écrit ch'teske vous-méme, ou éq vos l’avez
 'histlegend' => "Diff séléccion: buke chés boétes d'chés canjemints à comparète pi détriquer intrer ou ch'bouton édsou.<br />
 Léginde : ({{MediaWiki:Cur}}) = différinches aveuc el vérchon à ch'momint-chi, ({{MediaWiki:Last}}) = différinches aveuc el vérchon édvant, <b>m</b> = tiot canjemint.",
 'history-fieldset-title' => "S'déplacher din l'historique",
+'history-show-deleted' => 'Défacés seulemint',
 'histfirst' => 'preumières paches',
 'histlast' => 'Darin',
 
+# Revision feed
+'history-feed-item-nocomment' => '$1 à $2',
+
 # Revision deletion
 'rev-delundel' => 'montrer/mucher',
 'revdel-restore' => 'cange écmint vir',
@@ -442,10 +458,11 @@ Léginde : ({{MediaWiki:Cur}}) = différinches aveuc el vérchon à ch'momint-ch
 'revertmerge' => "N'poin mélinger",
 
 # Diffs
-'history-title' => 'Histoère des cangemints éd "$1"',
+'history-title' => 'Historike des canjemints éd "$1"',
 'lineno' => 'Line $1:',
 'compareselectedversions' => 'Compérer chés couésies contérbuchons',
 'editundo' => "n'poin foaire",
+'diff-multi' => '({{PLURAL:$1|Un canjemint intarmédiaire|$1 canjemints intarmédiaires}} par {{PLURAL:$2|un uzeu|$2 uzeus}} {{PLURAL:$1|est muché|sont muchées}})',
 
 # Search results
 'searchresults' => 'Tracher chés résultats',
@@ -459,7 +476,10 @@ Léginde : ({{MediaWiki:Cur}}) = différinches aveuc el vérchon à ch'momint-ch
 'prevn' => 'dvant {{PLURAL:$1|$1}}',
 'nextn' => 'apreu {{PLURAL:$1|$1}}',
 'prevn-title' => 'Dvant $1 {{PLURAL:$1|résultat|résultats}}',
+'nextn-title' => "$1 {{PLURAL:$1|résultat d'apré|résultats d'apré}}",
+'shown-title' => 'Montrer $1 résultat{{PLURAL:$1||s}} pèr pache',
 'viewprevnext' => 'Vir ($1 {{int:pipe-separator}} $2) ($3)',
+'searchmenu-exists' => "'''Il y o eune pache lonmée « [[:$1]] » édseur ch'wiki'''",
 'searchmenu-new' => "'''Créer l'pache « [[:$1|$1]] » édseur ech wiki !'''",
 'searchprofile-articles' => "Paches d'étnu",
 'searchprofile-project' => "Paches d’aïude et pi d'prodjé",
@@ -472,13 +492,16 @@ Léginde : ({{MediaWiki:Cur}}) = différinches aveuc el vérchon à ch'momint-ch
 'searchprofile-everything-tooltip' => "Tracher dins tout ch'wikipédia (et ochi dins chés paches éd distchucion)",
 'searchprofile-advanced-tooltip' => "Couésir chés éspaches d'noms pour l'értrache",
 'search-result-size' => '$1 ({{PLURAL:$2|1 mot|$2 mots}})',
+'search-result-category-size' => '$1 mimbe{{PLURAL:$1||s}} ($2 édsous-catégorie{{PLURAL:$2||s}}, $3 fichié{{PLURAL:$3||s}})',
 'search-redirect' => '(érdirection $1)',
 'search-section' => '(sekchon $1)',
 'search-suggest' => 'Cha vo ti dire: $1',
 'search-interwiki-caption' => 'Proujé analocq',
 'search-interwiki-default' => '$1 résultats:',
 'search-interwiki-more' => '(pus)',
+'searchrelated' => 'relaté',
 'searchall' => 'tout',
+'showingresultsheader' => "{{PLURAL:$5|Résultat '''$1'''|Résultats '''$1–$2'''}} éd '''$3''' pour '''$4'''",
 'nonefound' => "'''Note''': il y o tasseulemint quéques éspaces éd noms éq sont trachés pèr défeut. <br /> Pou tracher din tous chés contnus (paches éd pérlache, modéles, etc... comprins) insséyer in imploéyant ch'préfixe ''all:'' o bin imploéyer echl éspace éd noms édmindé conme préfixe.",
 'search-nonefound' => 'Y a autchun résultat pour chol dmanne.',
 'powersearch' => 'Érvue avanchée',
@@ -502,6 +525,8 @@ Ale doét mie éte pu longue éq $1 {{PLURAL:$1|caracter|caractéres}}.',
 'gender-male' => 'Marle',
 'gender-female' => 'Femelle',
 'email' => 'Imèle',
+'prefs-help-email' => "L’adrèche du courrièl est facultative, mais ale est nécessaire pour artreuver vote mot d'passe, si vos vnoète à l’oblier.",
+'prefs-help-email-others' => "Os pouvez auchi couésir d'laicher les eutes vos contacter par imèle aveuc un loïen édseur vote pache éd distchussion d'uzeu sans qu'i soèche nécessaire ed révéler vote idintité.",
 'prefs-help-email-required' => 'I feut eune iméle adérche',
 
 # User rights
@@ -550,12 +575,18 @@ Ale doét mie éte pu longue éq $1 {{PLURAL:$1|caracter|caractéres}}.',
 'recentchanges' => 'Darins canjemints',
 'recentchanges-legend' => 'Opchons éd chés nouvieus canjemints',
 'recentchanges-feed-description' => 'Tracher chés pus darins cangemints du wiki din chol alimintachon.',
+'recentchanges-label-newpage' => 'Chol modificacion ale o créé eune nouvèle pache',
+'recentchanges-label-minor' => "C'est un tiot canjemint",
+'recentchanges-label-bot' => 'Chol modificacion ale o té foaite pèr un robot.',
+'recentchanges-label-unpatrolled' => 'Chol modificacion ale n’o poin coèr té controlée.',
 'rcnote' => "Vlo {{PLURAL:$1|ech darin canjemint foait|chés $1 darins canjemints foaits}} din {{PLURAL:$2|l'darinne jornèe|chés <b>$2</b> darins jours}} dusque  l' $4 à $5.",
+'rcnotefrom' => "Vlo chés modificacions foaites édpuis l' '''$2''' (dousqu'à '''$1''' au plus).",
 'rclistfrom' => "Montrer chés nouvieus cangemints d'puis $1",
 'rcshowhideminor' => '$1 tiotes éditions',
 'rcshowhidebots' => '$1 bots',
 'rcshowhideliu' => '$1 lodjés uzeus',
 'rcshowhideanons' => '$1 uzeus anonimes',
+'rcshowhidepatr' => '$1 chés modificacions wardées',
 'rcshowhidemine' => '$1 ems éditions',
 'rclinks' => 'Afiqher chés $1 darins canjemints din chés $2 darins jours<br />$3',
 'diff' => 'dif',
@@ -570,7 +601,9 @@ Ale doét mie éte pu longue éq $1 {{PLURAL:$1|caracter|caractéres}}.',
 
 # Recent changes linked
 'recentchangeslinked' => 'Darins canjemints érliés',
+'recentchangeslinked-toolbox' => 'Suivi des paches loïées',
 'recentchangeslinked-title' => 'Cangemints à pérpos éd "$1"',
+'recentchangeslinked-noresult' => "I n’y a poin d' modificacion des paches loïées pindant l'période couésie.",
 'recentchangeslinked-summary' => "Ch'est eune lisse d'chés darins canjemints su chés paches qu'ont un loïen aveuc l'pache-lo. Chés paches din vote [[Special:Watchlist|''lisse à suire'']] il sont in '''cros'''.",
 'recentchangeslinked-page' => 'Nom del pache:',
 'recentchangeslinked-to' => "Vir putot chés canjemints d'chés paches aveuc un loïen su l'pache-lo",
@@ -578,8 +611,12 @@ Ale doét mie éte pu longue éq $1 {{PLURAL:$1|caracter|caractéres}}.',
 # Upload
 'upload' => 'Quértcher chés fichiés',
 'uploadlogpage' => 'Jornal éd chés quértchémints',
+'filedesc' => 'Résumè',
 'uploadedimage' => '"[[$1]]" quértchée',
 
+'license' => 'Licince',
+'license-header' => 'Licince',
+
 # File description page
 'file-anchor-link' => 'Fichié',
 'filehist' => 'Histoère dech fichié',
@@ -594,6 +631,7 @@ Ale doét mie éte pu longue éq $1 {{PLURAL:$1|caracter|caractéres}}.',
 'filehist-comment' => 'Fichié éd chés conmints',
 'imagelinks' => 'Usage dech fichié',
 'linkstoimage' => "{{PLURAL:$1|L'pache d'apreu est liée|Chés $1 paches d'apreu sont liées}} à ch'fichié-lo :",
+'nolinkstoimage' => "Autchune pache n'est loïée aveuc ch'fichié-lo",
 'sharedupload' => "Cht'fichié vient éd $1 pi i put ète imploïé par d'eutes proujés.",
 'sharedupload-desc-here' => "Ch'fichié i vient éd $1. I put ète uzer pèr d’eutes prodjés.
 Vir apré ([$2 pache]).",
@@ -605,6 +643,8 @@ Vir apré ([$2 pache]).",
 # Statistics
 'statistics' => 'Éstatistikes',
 
+'disambiguationspage' => 'Template:Omonymie',
+
 # Miscellaneous special pages
 'nbytes' => '$1 {{PLURAL:$1|octé|octés}}',
 'nmembers' => '$1 {{PLURAL:$1|mimbe|mimbes}}',
@@ -638,8 +678,12 @@ Vir apré ([$2 pache]).",
 'allpagessubmit' => 'Aler',
 'allpagesprefix' => "Foaire vir chés paches aveuc ch'préfix:",
 
+# Special:Categories
+'categories' => 'Lisse des catégories',
+
 # Special:LinkSearch
 'linksearch' => 'Loïens éstérieurs',
+'linksearch-line' => '$1 est loïé édpuis $2',
 
 # Special:Log/newusers
 'newuserlogpage' => "Jornal éd chés créachons d'comptes d'uzeu",
@@ -672,6 +716,7 @@ Vir apré ([$2 pache]).",
 'deletepage' => "Défacer l'pache",
 'confirmdeletetext' => "Vos alez défacer eune pache ou un fichié aveuc toutes chés antieusses vérchons.<br /> Confreumer éq ch'est cho éq vos voulez foaire, éq vos conprindez chés consécanches et pi éq ch'est bin s'lon el [[{{MediaWiki:Policy-url}}|politique éd MédiaWiki]].",
 'actioncomplete' => 'Plònne acchon',
+'actionfailed' => "L’action n'a poin réussi",
 'deletedtext' => "« $1 » o té défacé.
 Vir $2 pou eune lisse d'chés darinnes défachons.",
 'dellogpage' => 'jornal éd chés défacions',
@@ -732,6 +777,7 @@ Vlo chés réglages del pache '''$1''' à ch'momint-chi:",
 
 'sp-contributions-newbies' => 'Montrer chés contérbuchons éd chés nouvieus conptes seulemint',
 'sp-contributions-blocklog' => 'jornal éd chés blotcåjhes',
+'sp-contributions-uploads' => "téléquértch'mints",
 'sp-contributions-logs' => 'Gasètes',
 'sp-contributions-talk' => 'Dviser',
 'sp-contributions-search' => 'Tracher pou chés contérbuchons',
@@ -748,7 +794,7 @@ Vlo chés réglages del pache '''$1''' à ch'momint-chi:",
 'nolinkshere-ns' => "i n'y o poin d'pache aveuc un loïen vers '''[[:$1]]''' dins echl'éspace d'noms coési.",
 'isredirect' => 'pache érdirigée',
 'istemplate' => 'transclusion',
-'isimage' => "Loïen aveuc l'imache",
+'isimage' => "Loïen aveuc l'fichié",
 'whatlinkshere-prev' => '{{PLURAL:$1|édvant|édvants $1}}',
 'whatlinkshere-next' => "{{PLURAL:$1|d'apreu|d'apreu $1}}",
 'whatlinkshere-links' => '← loïens',
@@ -808,9 +854,11 @@ Din chés cas-lo, I feut érlonmer ou ratatouiller l'pache aveuc l'main.",
 
 # Namespace 8 related
 'allmessagesname' => 'Nom',
+'allmessagesdefault' => 'Messache pèr défeut',
 
 # Thumbnails
 'thumbnail-more' => 'Pu grand',
+'thumbnail_error' => "Bérlurage tandir l'créachon éd la miniature : $1",
 
 # Tooltip help for the actions
 'tooltip-pt-userpage' => 'Vote pache éd uzeu',
@@ -930,6 +978,9 @@ Chés eutes cans is s'ront muchés pèr défeut.
 'watchlisttools-edit' => "Vir pi éditer l'lisse à suire",
 'watchlisttools-raw' => 'Éditer eune brute lisse à suire',
 
+# Core parser functions
+'duplicate-defaultsort' => "Afute : él cleu d'tri pèr défeut « $2 » écrase l'précédinte « $1 ».",
+
 # Special:Version
 'version-specialpages' => 'Paches éspéchiales',
 
@@ -944,6 +995,19 @@ Chés eutes cans is s'ront muchés pèr défeut.
 # Special:BlankPage
 'blankpage' => 'Blanke pache',
 
+# External image whitelist
+'external_image_whitelist' => " #Laicher chol line egzactemint telle quelle.<pre>
+#Dire chés bérlukes d’éspressions rationnelles (juste l'partie désignée inte chés //) chi-édsous.
+#I correspondront aveuc chés URL des images éstérnes.
+#Chelles qui corresponde'te s’affikeront conme des images, sinon seul un loïen vers l’image i s'ra affiké.
+#Les lines conmençant par un # s'ront considérées conme des conmintaires.
+#Chol lisse n’est mie sensibe à la casse.
+
+#Mettez tous chés bérlukes d’éspressions rationnelles au-d'sus éd chol line. Laichez chol darin.ne line telle quelle.</pre>",
+
+# Special:Tags
+'tag-filter' => 'Filtrer chés [[Special:Tags|balises]] :',
+
 # Special:ComparePages
 'compare-page1' => 'Pache 1',
 'compare-page2' => 'Pache 2',
index 5d5adb7..74e293c 100644 (file)
@@ -138,7 +138,7 @@ $messages = array(
 'cancel' => 'Zerick',
 'moredotdotdot' => 'Mehner…',
 'mypage' => 'Mei Blatt',
-'mytalk' => 'Mei Gschwetz-Blatt',
+'mytalk' => 'Mei Dischbedutt',
 'anontalk' => 'Gschwetz-Blatt fer die IP',
 'navigation' => 'Faahre-Gnepp',
 'and' => '&#32;unn',
@@ -187,7 +187,7 @@ $messages = array(
 'protectthispage' => 'Des Blatt schitze',
 'newpage' => 'Neies Blatt',
 'talkpage' => 'Sell Blatt dischbediere',
-'talkpagelinktext' => 'Gschwetz',
+'talkpagelinktext' => 'Dischbedutt',
 'specialpage' => 'Besunneres Blatt',
 'personaltools' => 'Paerseenlich Gscharr',
 'articlepage' => 'Inhalt vun dem Blatt aagucke',
@@ -425,7 +425,7 @@ Paesswatt fer nau: $2',
 
 # Preferences page
 'preferences' => 'Paerseenlich Profil',
-'mypreferences' => 'Mei Uffschtelling',
+'mypreferences' => 'Uffschtellinge',
 'changepassword' => 'Paesswatt ennere',
 'skin-preview' => 'Aagucke',
 'prefs-personal' => 'Yuuser Profile',
@@ -691,7 +691,7 @@ Paesswatt fer nau: $2',
 
 # Watchlist
 'watchlist' => 'Mei Watsch-Lischt',
-'mywatchlist' => 'Mei Watsch-Lischt',
+'mywatchlist' => 'Watsch-Lischt',
 'watchlistfor2' => 'Vun $1 $2',
 'watch' => 'watsche',
 'watchthispage' => 'watsch des Blatt',
@@ -764,7 +764,7 @@ Guck $2 fer e Lischt vun de letscht Leschunge.',
 'month' => 'unn Munet:',
 'year' => 'bis Yaahr:',
 
-'sp-contributions-talk' => 'Gschwetz',
+'sp-contributions-talk' => 'Dischbedutt',
 'sp-contributions-search' => 'Guck fer Ardickel',
 'sp-contributions-username' => 'IP-Adress odder Yuusernaame:',
 'sp-contributions-submit' => 'Guck uff',
index c352658..5aff86f 100644 (file)
@@ -426,8 +426,8 @@ $messages = array(
 'newwindow' => '(otwiera się w nowym oknie)',
 'cancel' => 'Anuluj',
 'moredotdotdot' => 'Więcej...',
-'mypage' => 'Moja strona',
-'mytalk' => 'Moja dyskusja',
+'mypage' => 'Strona',
+'mytalk' => 'Dyskusja',
 'anontalk' => 'Dyskusja tego IP',
 'navigation' => 'Nawigacja',
 'and' => '&#32;oraz',
index 4ccd524..52dfba7 100644 (file)
@@ -175,8 +175,8 @@ $messages = array(
 'newwindow' => '(as deurb ant na fnestra neuva)',
 'cancel' => 'Scancela',
 'moredotdotdot' => 'Dë pì...',
-'mypage' => 'Mia pàgina',
-'mytalk' => 'Mie ciaciarade',
+'mypage' => 'Pàgina',
+'mytalk' => 'Ciaciarade',
 'anontalk' => "Ciaciarade për st'adrëssa IP-sì",
 'navigation' => 'Navigassion',
 'and' => '&#32;e',
@@ -1102,7 +1102,7 @@ Ch'a preuva a gionté dnans a soa arserca ël prefiss ''all:'' për sërché an
 
 # Preferences page
 'preferences' => 'Mè gust',
-'mypreferences' => 'mè gust',
+'mypreferences' => 'Gust',
 'prefs-edits' => 'Nùmer ëd modìfiche fàite:',
 'prefsnologin' => "A l'é ancó pa rintrà ant ël sistema",
 'prefsnologintext' => 'A deuv esse <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} intrà ant ël sistema]</span> për amposté ij sò gust.',
@@ -2053,7 +2053,7 @@ L'adrëssa ëd pòsta eletrònica ch'a l'ha butà ant ij [[Special:Preferences|s
 
 # Watchlist
 'watchlist' => 'Ròba che im ten-o sot-euj',
-'mywatchlist' => 'Ròba che im ten-o sot-euj',
+'mywatchlist' => 'Ròba che as ten sot euj',
 'watchlistfor2' => 'Për $1 $2',
 'nowatchlist' => "A l'ha ancó pa marcà dj'artìcoj coma ròba da tnì sot-euj.",
 'watchlistanontext' => "Për piasì, $1 për ës-ciairé ò pura modifiché j'element ëd soa lista dla ròba che as ten sot-euj.",
@@ -2311,7 +2311,7 @@ $1",
 # Contributions
 'contributions' => "Contribussion dë st'Utent-sì",
 'contributions-title' => 'Contribussion ëd $1',
-'mycontris' => 'Mie contribussion',
+'mycontris' => 'Contribussion',
 'contribsub2' => 'Për $1 ($2)',
 'nocontribs' => "A l'é pa trovasse gnun-a modìfica che a fussa conforma a costi criteri-sì",
 'uctop' => ' (ùltima dla pàgina)',
@@ -2351,7 +2351,7 @@ L'ùltima intrada dël registr dij blocagi a l'é butà sì-sota për arferiment
 'whatlinkshere-hideredirs' => '$1 le ridiression',
 'whatlinkshere-hidetrans' => '$1 anclusion',
 'whatlinkshere-hidelinks' => '$1 anliura',
-'whatlinkshere-hideimages' => '$1 anliure ëd figure',
+'whatlinkshere-hideimages' => "$1 j'archivi lijà",
 'whatlinkshere-filters' => 'Filtr',
 
 # Block/unblock
@@ -3364,7 +3364,7 @@ J'àutri a saran stërmà coma stàndard.
 
 # External editor support
 'edit-externally' => "Modifiché st'archivi con un programa estern",
-'edit-externally-help' => "(Lese [//www.mediawiki.org/wiki/Manual:External_editors setup j'anstrussion d'anstalassion] për avèj pì d'anformassion)",
+'edit-externally-help' => "(Lese [//www.mediawiki.org/wiki/Manual:External_editors j'anstrussion d'anstalassion] për avèj pì d'anformassion)",
 
 # 'all' in various places, this might be different for inflected languages
 'watchlistall2' => 'tute',
@@ -3375,70 +3375,70 @@ J'àutri a saran stërmà coma stàndard.
 # E-mail address confirmation
 'confirmemail' => "Confermé l'adrëssa postal",
 'confirmemail_noemail' => "A l'ha pa butà gnun-a adrëssa vàlida ëd pòsta eletrònica ant ij [[Special:Preferences|sò gust]].",
-'confirmemail_text' => "Costa wiki a ciama che chiel a convalida n'adrëssa postal anans che
-dovré lòn che toca la pòsta. Che a sgnaca ël boton ambelessì sota
-për fesse mandé un messa ëd conferma a soa adrëssa eletrònica.
-Andrinta al messagi a-i sara n'anliura (URL) con andrinta un còdes.
-Che a deurba st'anliura andrinta a sò programa ëd navigassion (browser)
+'confirmemail_text' => "Costa wiki a ciama che chiel a convàlida n'adrëssa ëd pòsta eletrònica anans che
+dovré lòn che a toca la pòsta. Che a sgnaca ël boton ambelessì-sota
+për fesse mandé un mëssage ëd conferma a soa adrëssa eletrònica.
+Andrinta al messagi a-i sara n'anliura con andrinta un còdes.
+Che a deurba st'anliura andrinta a sò programa ëd navigassion
 për confermé che soa adrëssa a l'é pròpe cola.",
 'confirmemail_pending' => "I l'oma già mandaje sò còdes ëd conferma;
-se a l'ha pen-a creasse sò cont, miraco a venta che a speta dontre minute che a-j riva ant la pòsta, nopà che ciamene un neuv.",
-'confirmemail_send' => 'Manda un còdes ëd conferma për pòsta eletrònica',
-'confirmemail_sent' => "Ël messagi ëd conferma a l'é stait mandà.",
-'confirmemail_oncreate' => "Un còdes ëd conferma a l'é stait mandà a soa adrëssa ëd pòsta eletrònica.
-D'ës còdes a fa pa dë manca për rintré ant ël sistema, ma a ventrà che a lo mostra al sistema për podej abilité cole funsion dla wiki che a son basà ant sla pòsta eletrònica.",
-'confirmemail_sendfailed' => "{{SITENAME}} a l'ha pa podù mandete l'e-mail ëd conferma.
+se a l'ha pen-a creasse sò cont, miraco a venta che a speta dontré minute che a-j riva ant la pòsta, nopà che ciamene un neuv.",
+'confirmemail_send' => 'Mandé un còdes ëd conferma për pòsta eletrònica',
+'confirmemail_sent' => "Ël mëssagi ëd conferma a l'é stàit mandà.",
+'confirmemail_oncreate' => "Un còdes ëd conferma a l'é stàit mandà a soa adrëssa ëd pòsta eletrònica.
+D'ës còdes a fa pa dë manca për rintré ant ël sistema, ma a ventrà che a lo mostra al sistema për podèj abilité cole funsion dla wiki che a son basà ant sla pòsta eletrònica.",
+'confirmemail_sendfailed' => "{{SITENAME}} a l'ha pa podù mandeje ël mëssagi ëd conferma.
 Che a controla l'adrëssa che a l'ha dane, mai che a-i fusso dij caràter nen vàlid.
 
-Ël programa ëd pòsta a l'ha arspondù: $1",
+Ël programa ëd pòsta a l'ha spondù: $1",
 'confirmemail_invalid' => 'Còdes ëd conferma nen vàlid. A podrìa ëdcò mach esse scadù.',
-'confirmemail_needlogin' => 'A venta che a fasa $1 për confermé soa addrëssa postal eletrònica.',
-'confirmemail_success' => "Soa adrëssa postal a l'é staita confermà, adess a peul rintré ant ël sistema e i-j auguroma da fessla bin ant la wiki!",
+'confirmemail_needlogin' => 'A venta $1 për confermé soa adrëssa ëd pòsta eletrònica.',
+'confirmemail_success' => "Soa adrëssa a l'é stàita confermà, adess a peul [[Special:UserLogin|rintré ant ël sistema]] e i-j auguroma da fessla bin ant la wiki!",
 'confirmemail_loggedin' => "Motobin mersì. Soa adrëssa ëd pòsta eletrònica adess a l'é confermà.",
-'confirmemail_error' => "Cheich-còs a l'é andà mal ën salvand soa conferma.",
+'confirmemail_error' => "Cheicòs a l'é andà mal ën salvand soa conferma.",
 'confirmemail_subject' => "Conferma dl'adrëssa postal da 'nt la {{SITENAME}}",
-'confirmemail_body' => "Cheidun, a l'é belfé che a sia stait pròpe chiel (ò chila), da 'nt l'adrëssa IP \$1,
-a l'ha doertà un cont utent \"\$2\" ansima a {{SITENAME}}, lassand-ne st'adrëssa ëd pòsta eletrònica-sì.
+'confirmemail_body' => "Cheidun, a l'é belfé che a sia stàit pròpe chiel, da 'nt l'adrëssa IP $1,
+a l'ha duvertà un cont utent «$2» ansima a {{SITENAME}}, lassand-ne st'adrëssa ëd pòsta eletrònica-sì.
 
 Për confermé che ës cont a l'é da bon sò e për ativé
-le possibilità corelà a la pòsta eletrònica ansima a {{SITENAME}}, che a deurba st'adrëssa-sì andrinta a sò programa ëd navigassion (browser):
+le possibilità gropà a la pòsta eletrònica ansima a {{SITENAME}}, che a deurba st'adrëssa-sì andrinta a sò programa ëd navigassion:
 
-\$3
+$3
 
-Se a fussa *nen* stait chiel a deurbe ël cont, anlora che a vada daré a sto colegament-sì
-për scanselé la conferma ëd l'adrëssa e-mail:
+Se a fussa *nen* stàit chiel a deurbe ël cont, anlora che a vada dapress a la liura sì-sota
+për scancelé la conferma ëd l'adrëssa ëd pòsta eletrònica:
 
-\$5
+$5
 
-Cost còdes ëd conferma a l'é bon fin-a al \$4.",
-'confirmemail_body_changed' => "Cheidun, a l'é belfé ch'a sia chiel, da l'adrëssa IP \$1,
-a l'ha cangià l'adrëssa ëd pòsta eletrònica dël cont \"\$2\" con st'adrëssa-sì dzora a {{SITENAME}}.
+Cost còdes ëd conferma a l'é bon fin-a al $4.",
+'confirmemail_body_changed' => "Cheidun, a l'é belfé ch'a sia chiel, da l'adrëssa IP $1,
+a l'ha cangià l'adrëssa ëd pòsta eletrònica dël cont «$2» con st'adrëssa-sì dzora a {{SITENAME}}.
 
 Për confirmé che sto cont-sì a l'é pròpi sò e për riativé
-le possibilità ëd pòsta eletrònica dzora a {{SITENAME}}, ch'a deurba sto colegament-sì an sò navigador:
+le fonsion ëd pòsta eletrònica dzora a {{SITENAME}}, ch'a deurba costa liura-sì an sò navigador:
 
-\$3
+$3
 
-Se ël cont a l'é *nen* sò, ch'a vada andré a sto colegament-sì
+Se ël cont a l'é *nen* sò, ch'a-i vada dapress a costa liura-sì
 për scancelé la conferma dl'adrëssa ëd pòsta eletrònica:
 
-\$5
+$5
 
-Ës còdes ëd conferma a scadrà a \$4.",
-'confirmemail_body_set' => "Quaidun, miraco chiel, da l'adrëssa IP \$1,
-a l'ha ampostà l'adrëssa ëd pòsta eletrònica dël cont \"\$2\" con costa adrëssa su {{SITENAME}}.
+Ës còdes ëd conferma a scadrà ël $4.",
+'confirmemail_body_set' => "Quaidun, miraco chiel, da l'adrëssa IP $1,
+a l'ha ampostà l'adrëssa ëd pòsta eletrònica dël cont «$2» con costa adrëssa su {{SITENAME}}.
 
 Për confirmé che sto cont a l'é pròpi sò e ativé torna
 le funsion ëd pòsta eletrònica su {{SITENAME}}, ch'a duverta cost'anliura an sò navigador:
 
-\$3
+$3
 
 Se ël cont a l'é *pa* sò, ch'a-j vada dapress a st'anliura
 për scancelé la conferma ëd l'adrëssa ëd pòsta eletrònica:
 
-\$5
+$5
 
-Cost còdes ëd conferma a scad ai \$4.",
+Cost còdes ëd conferma a scad ai $4.",
 'confirmemail_invalidated' => "Conferma ëd l'adrëssa e-mail scanselà",
 'invalidateemail' => "Scansela l'e-mail ëd conferma",
 
index 4ae5911..e85ff8e 100644 (file)
@@ -442,7 +442,7 @@ $messages = array(
 'newwindow' => '(abre numa janela nova)',
 'cancel' => 'Cancelar',
 'moredotdotdot' => 'Mais...',
-'mypage' => 'Utilizador',
+'mypage' => 'Página',
 'mytalk' => 'Discussão',
 'anontalk' => 'Discussão para este IP',
 'navigation' => 'Navegação',
index 48c68c1..0fbe91e 100644 (file)
@@ -446,8 +446,8 @@ $messages = array(
 'newwindow' => '(abre em uma nova janela)',
 'cancel' => 'Cancelar',
 'moredotdotdot' => 'Mais...',
-'mypage' => 'Minha página',
-'mytalk' => 'Minha discussão',
+'mypage' => 'Página',
+'mytalk' => 'Discussão',
 'anontalk' => 'Discussão para este IP',
 'navigation' => 'Navegação',
 'and' => '&#32;e',
@@ -1374,7 +1374,7 @@ Note que os índices do sistema de busca externo poderão conter referências de
 
 # Preferences page
 'preferences' => 'Preferências',
-'mypreferences' => 'Minhas preferências',
+'mypreferences' => 'Preferências',
 'prefs-edits' => 'Número de edições:',
 'prefsnologin' => 'Não autenticado',
 'prefsnologintext' => 'É necessário estar <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} autenticado]</span> para definir as suas preferências.',
@@ -2580,7 +2580,7 @@ $1',
 # Contributions
 'contributions' => 'Contribuições {{GENDER:{{BASEPAGENAME}}|do usuário|da usuária}}',
 'contributions-title' => 'Contribuições {{GENDER:$1|do usuário|da usuária}} $1',
-'mycontris' => 'Minhas contribuições',
+'mycontris' => 'Contribuições',
 'contribsub2' => 'Para $1 ($2)',
 'nocontribs' => 'Não foram encontradas mudanças com este critério.',
 'uctop' => '(atual)',
index e975098..14e3886 100644 (file)
@@ -346,7 +346,10 @@ Possible alternatives to the word 'content' are 'subject matter' or 'wiki subjec
 
 {{Identical|Cancel}}',
 'moredotdotdot' => '{{Identical|More...}}',
-'mytalk' => 'In the personal urls page section - right upper corner.',
+'mypage' => "A text for the link to the user's user page in the links at the top of the page.",
+'mytalk' => 'In the personal urls page section - right upper corner.
+
+Used as link title in "Personal tools" toolbar.',
 'anontalk' => 'Link to the talk page appearing in [[mw:Help:Navigation#User_Links|user links]] for each anonymous users when [[mw:Manual:$wgShowIPinHeader|$wgShowIPinHeader]] is true.',
 'navigation' => 'This is shown as a section header in the sidebar of most skins.
 
@@ -1496,7 +1499,7 @@ This is a search result (and I guess search engine) dependent messages. I do not
 'preferences' => 'Title of the Special:Preferences page.
 
 {{Identical|Preferences}}',
-'mypreferences' => 'Action link label that leads to Special:Preferences; appears in the top menu (e.g. "Username My talk My preferences My watchlist My contributions Log out").
+'mypreferences' => 'Action link label that leads to Special:Preferences; appears in the top menu (e.g. "Username Talk Preferences Watchlist Contributions Log out").
 
 {{Identical|My preferences}}',
 'prefs-edits' => 'In user preferences.',
@@ -5028,4 +5031,6 @@ $4 is the gender of the target user.',
 'api-error-uploaddisabled' => 'API error message that can be used for client side localisation of API errors.',
 'api-error-verification-error' => 'The word "extension" refers to the part behind the last dot in a file name, that by convention gives a hint about the kind of data format which a files contents are in.',
 
+# Unknown messages
+'mytalk-parenthetical' => 'When user page and talk combined into single label, link title for talk label',
 );
index e85a226..6979782 100644 (file)
@@ -434,7 +434,7 @@ pe titlul secțiunii (JavaScript)',
 'newwindow' => '(se deschide într-o fereastră nouă)',
 'cancel' => 'Revocare',
 'moredotdotdot' => 'Mai mult…',
-'mypage' => 'Pagina mea',
+'mypage' => 'Pagină',
 'mytalk' => 'Discuții',
 'anontalk' => 'Discuția pentru această adresă IP',
 'navigation' => 'Navigare',
@@ -4040,4 +4040,6 @@ Imaginile sunt afișate la rezoluția lor maximă, în timp ce alte tipuri de fi
 'duration-centuries' => '$1 {{PLURAL:$1|secol|secole|de secole}}',
 'duration-millennia' => '$1 {{PLURAL:$1|mileniu|milenii|de milenii}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'discuție',
 );
index cc3e1ba..95b5d9c 100644 (file)
@@ -516,11 +516,11 @@ $messages = array(
 'category-empty' => "''Эта категория в данный момент пуста.''",
 'hidden-categories' => '{{PLURAL:$1|Скрытая категория|Скрытые категории}}',
 'hidden-category-category' => 'Скрытые категории',
-'category-subcat-count' => '{{PLURAL:$2|Данная категория содержит только следующую подкатегорию.|{{PLURAL:$1|Показана $1 подкатегория|Показано $1 подкатегории|Показано $1 подкатегорий}} из $2.}}',
+'category-subcat-count' => '{{PLURAL:$2|Данная категория содержит только следующую подкатегорию.|{{PLURAL:$1|Показана $1 подкатегория|Показано $1 подкатегории|Показано $1 подкатегорий}} из $2, находящихся в этой категории.}}',
 'category-subcat-count-limited' => 'В этой категории {{PLURAL:$1|$1 подкатегория|$1 подкатегории|$1 подкатегорий}}.',
-'category-article-count' => '{{PLURAL:$2|Эта категория содержит только одну страницу.|{{PLURAL:$1|Показана $1 страница|Показано $1 страницы|Показано $1 страниц}} этой категории из $2.}}',
+'category-article-count' => '{{PLURAL:$2|Эта категория содержит только одну страницу.|{{PLURAL:$1|Показана $1 страница|Показано $1 страницы|Показано $1 страниц}} из $2, находящихся в этой категории.}}',
 'category-article-count-limited' => 'В этой категории {{PLURAL:$1|$1 страница|$1 страницы|$1 страниц}}.',
-'category-file-count' => '{{PLURAL:$2|Эта категория содержит только один файл.|{{PLURAL:$1|Показан $1 файл|Показано $1 файла|Показано $1 файлов}} этой категории  из $2.}}',
+'category-file-count' => '{{PLURAL:$2|Эта категория содержит только один файл.|{{PLURAL:$1|Показан $1 файл|Показано $1 файла|Показано $1 файлов}} из $2, находящихся в этой категории.}}',
 'category-file-count-limited' => 'В этой категории {{PLURAL:$1|$1 файл|$1 файла|$1 файлов}}.',
 'listingcontinuesabbrev' => '(продолжение)',
 'index-category' => 'Индексируемые страницы',
@@ -533,7 +533,7 @@ $messages = array(
 'cancel' => 'Отменить',
 'moredotdotdot' => 'Далее…',
 'mypage' => 'Личная страница',
-'mytalk' => 'Ð\9cоÑ\8f Ñ\81Ñ\82Ñ\80аниÑ\86а Ð¾бсуждения',
+'mytalk' => 'Ð\9eбсуждения',
 'anontalk' => 'Обсуждение для этого IP-адреса',
 'navigation' => 'Навигация',
 'and' => '&#32;и',
@@ -559,7 +559,7 @@ $messages = array(
 'vector-view-create' => 'Создание',
 'vector-view-edit' => 'Правка',
 'vector-view-history' => 'История',
-'vector-view-view' => 'Чтение',
+'vector-view-view' => 'Читать',
 'vector-view-viewsource' => 'Просмотр разметки',
 'actions' => 'Действия',
 'namespaces' => 'Пространства имён',
@@ -597,7 +597,7 @@ $messages = array(
 'talkpage' => 'Обсудить эту страницу',
 'talkpagelinktext' => 'обсуждение',
 'specialpage' => 'Служебная страница',
-'personaltools' => 'Ð\9bиÑ\87ные инструменты',
+'personaltools' => 'Ð\9fеÑ\80Ñ\81оналÑ\8cные инструменты',
 'postcomment' => 'Новый раздел',
 'articlepage' => 'Просмотреть статью',
 'talk' => 'Обсуждение',
@@ -644,7 +644,7 @@ $1',
 'mainpage' => 'Заглавная страница',
 'mainpage-description' => 'Заглавная страница',
 'policy-url' => 'Project:Правила',
-'portal' => 'СообÑ\89еÑ\81Ñ\82во',
+'portal' => 'Ð\9fоÑ\80Ñ\82ал Ñ\81ообÑ\89еÑ\81Ñ\82ва',
 'portal-url' => 'Project:Портал сообщества',
 'privacy' => 'Политика конфиденциальности',
 'privacypage' => 'Project:Политика конфиденциальности',
@@ -672,7 +672,7 @@ $1',
 'viewsourceold' => 'просмотреть исходный код',
 'editlink' => 'править',
 'viewsourcelink' => 'просмотреть исходный код',
-'editsectionhint' => 'Ð\9fÑ\80авиÑ\82Ñ\8c Ñ\81екÑ\86иÑ\8e «$1»',
+'editsectionhint' => 'РедакÑ\82иÑ\80оваÑ\82Ñ\8c Ñ\80аздел «$1»',
 'toc' => 'Содержание',
 'showtoc' => 'показать',
 'hidetoc' => 'убрать',
@@ -761,7 +761,7 @@ $1',
 'delete-hook-aborted' => 'Правка отменена процедурой-перехватчиком.
 Дополнительных пояснений не приведено.',
 'badtitle' => 'Недопустимое название',
-'badtitletext' => 'Ð\97апÑ\80аÑ\88иваемое Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\8b Ð½ÐµÐ¿Ñ\80авилÑ\8cно, Ð¿Ñ\83Ñ\81Ñ\82о, Ð»Ð¸Ð±Ð¾ Ð½ÐµÐ¿Ñ\80авилÑ\8cно указано межъязыковое или интервики название. Возможно, в названии используются недопустимые символы.',
+'badtitletext' => 'Ð\97апÑ\80аÑ\88иваемое Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ðµ Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\8b Ð½ÐµÐ¿Ñ\80авилÑ\8cно, Ð¿Ñ\83Ñ\81Ñ\82о, Ð»Ð¸Ð±Ð¾ Ð½ÐµÐ²ÐµÑ\80но указано межъязыковое или интервики название. Возможно, в названии используются недопустимые символы.',
 'perfcached' => 'Следующие данные взяты из кэша и могут не учитывать последних изменений. В кэше хранится не более $1 {{PLURAL:$1|записи|записей|записей}}.',
 'perfcachedts' => 'Следующие данные взяты из кэша, последний раз он обновлялся в $1. В кэше хранится не более $4 {{PLURAL:$4|записи|записей|записей}}.',
 'querypage-no-updates' => 'Обновление этой страницы сейчас отключено.
@@ -811,7 +811,7 @@ $2',
 'welcomecreation' => '== Добро пожаловать, $1! ==
 Ваша учётная запись создана.
 Не забудьте провести [[Special:Preferences|персональную настройку]] сайта.',
-'yourname' => 'Имя участника:',
+'yourname' => 'Имя учётной записи:',
 'yourpassword' => 'Пароль:',
 'yourpasswordagain' => 'Повторный набор пароля:',
 'remembermypassword' => 'Помнить мою учётную запись на этом компьютере (не более $1 {{PLURAL:$1|дня|дней|дней}})',
@@ -827,9 +827,9 @@ $2',
 'logout' => 'Завершение сеанса',
 'userlogout' => 'Завершение сеанса',
 'notloggedin' => 'Вы не представились системе',
-'nologin' => "Нет учётной записи? '''$1'''.",
+'nologin' => 'Нет учётной записи? $1.',
 'nologinlink' => 'Создать учётную запись',
-'createaccount' => 'Ð\97аÑ\80егиÑ\81Ñ\82Ñ\80иÑ\80оваÑ\82Ñ\8c Ð½Ð¾Ð²Ð¾Ð³Ð¾ Ñ\83Ñ\87аÑ\81Ñ\82ника',
+'createaccount' => 'СоздаÑ\82Ñ\8c Ñ\83Ñ\87Ñ\91Ñ\82нÑ\83Ñ\8e Ð·Ð°Ð¿Ð¸Ñ\81Ñ\8c',
 'gotaccount' => "Вы уже зарегистрированы? '''$1'''.",
 'gotaccountlink' => 'Представьтесь',
 'userlogin-resetlink' => 'Забыли данные для входа?',
@@ -1006,8 +1006,8 @@ $2
 'showpreview' => 'Предварительный просмотр',
 'showlivepreview' => 'Быстрый предпросмотр',
 'showdiff' => 'Внесённые изменения',
-'anoneditwarning' => "'''Внимание:''' Вы не представились системе.
аш IP-адрес будет записан в историю изменений этой страницы.",
+'anoneditwarning' => "'''Внимание!''' Вы не авторизовались на сайте.
 истории изменений этой страницы будет записан ваш IP-адрес.",
 'anonpreviewwarning' => "''Вы не представились системе. Сохранение приведёт к записи вашего IP-адреса в историю изменений страницы.''",
 'missingsummary' => "'''Напоминание.''' Вы не дали краткого описания изменений. При повторном нажатии на кнопку «{{int:savearticle}}», ваши изменения будут сохранены без комментария.",
 'missingcommenttext' => 'Пожалуйста, введите ниже ваше сообщение.',
@@ -1151,12 +1151,12 @@ $2
 'cascadeprotectedwarning' => "'''Предупреждение:''' Данную страницу могут редактировать только участники группы «Администраторы», поскольку она включена {{PLURAL:$1|в следующую страницу, для которой|в следующие страницы, для которых}} включена каскадная защита:",
 'titleprotectedwarning' => "'''Предупреждение.  Это название защищено. Создать эту страницу могут только участники с [[Special:ListGroupRights|соответствующими правами]].'''
 Ниже для справки приведена последняя запись журнала:",
-'templatesused' => '{{PLURAL:$1|Шаблон, Ð¸Ñ\81полÑ\8cзованнÑ\8bй|ШаблонÑ\8b, Ð¸Ñ\81полÑ\8cзованнÑ\8bе}} Ð½Ð° Ñ\82екÑ\83Ñ\89ей Ð²ÐµÑ\80Ñ\81ии Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\8b:',
+'templatesused' => '{{PLURAL:$1|Шаблон, Ð¸Ñ\81полÑ\8cзованнÑ\8bй|ШаблонÑ\8b, Ð¸Ñ\81полÑ\8cзованнÑ\8bе}} Ð½Ð° Ñ\8dÑ\82ой Ñ\81Ñ\82Ñ\80аниÑ\86е:',
 'templatesusedpreview' => '{{PLURAL:$1|Шаблон, используемый|Шаблоны, используемые}} в предпросматриваемой странице:',
 'templatesusedsection' => '{{PLURAL:$1|Шаблон, используемый|Шаблоны, использованные}} в этом разделе:',
 'template-protected' => '(защищено)',
 'template-semiprotected' => '(частично защищено)',
-'hiddencategories' => 'Эта страница относится к $1 {{PLURAL:$1|скрытой категории|скрытым категориям|скрытым категориям}}:',
+'hiddencategories' => 'Эта страница относится к $1 {{PLURAL:$1|скрытой категории|скрытым категориям}}:',
 'edittools' => '<!-- Расположенный здесь текст будет показываться под формой редактирования и формой загрузки. -->',
 'nocreatetitle' => 'Создание страниц ограничено',
 'nocreatetext' => 'На этом сайте ограничена возможность создания новых страниц.
@@ -1166,7 +1166,7 @@ $2
 'sectioneditnotsupported-text' => 'На этой странице не поддерживается редактирование разделов',
 'permissionserrors' => 'Ошибки прав доступа',
 'permissionserrorstext' => 'У вас нет прав на выполнение этой операции по {{PLURAL:$1|следующей причине|следующим причинам}}:',
-'permissionserrorstext-withaction' => "У вас нет разрешения на «'''$2'''» по {{PLURAL:$1|следующей причине|следующим причинам}}:",
+'permissionserrorstext-withaction' => 'У вас нет прав на $2 по {{PLURAL:$1|следующей причине|следующим причинам}}:',
 'recreate-moveddeleted-warn' => "'''Внимание. Вы пытаетесь воссоздать страницу, которая ранее удалялась.'''
 
 Проверьте, действительно ли вам нужно воссоздавать эту страницу.
@@ -1194,9 +1194,9 @@ $2
 'content-model-css' => 'CSS',
 
 # Parser/template warnings
-'expensive-parserfunction-warning' => 'Внимание. Эта страница содержит слишком много вызовов ресурсоёмких функций.
+'expensive-parserfunction-warning' => "'''Внимание!''' Эта страница содержит слишком много вызовов ресурсоёмких функций.
 
\9eгÑ\80аниÑ\87ение Ð½Ð° ÐºÐ¾Ð»Ð¸Ñ\87еÑ\81Ñ\82во Ð²Ñ\8bзовов Ñ\83Ñ\81Ñ\82ановлено Ð½Ð° Ñ\83Ñ\80овне $2 {{PLURAL:$2|вÑ\8bзова|вÑ\8bзовов|вÑ\8bзовов}}, Ð² Ð´Ð°Ð½Ð½Ð¾Ð¼ Ñ\81лÑ\83Ñ\87ае Ñ\82Ñ\80ебÑ\83еÑ\82Ñ\81Ñ\8f Ñ\81делаÑ\82Ñ\8c $1 {{PLURAL:$1|вÑ\8bзов|вÑ\8bзова|вÑ\8bзовов}}.',
\94олжно Ð±Ñ\8bÑ\82Ñ\8c Ð½Ðµ Ð±Ð¾Ð»ÐµÐµ $2 {{PLURAL:$2|вÑ\8bзова|вÑ\8bзовов}}, Ð² Ñ\82о Ð²Ñ\80емÑ\8f ÐºÐ°Ðº Ñ\81ейÑ\87аÑ\81 Ð·Ð´ÐµÑ\81Ñ\8c $1 {{PLURAL:$1|вÑ\8bзов|вÑ\8bзова|вÑ\8bзовов}}.",
 'expensive-parserfunction-category' => 'Страницы со слишком большим количеством вызовов ресурсоёмких функций',
 'post-expand-template-inclusion-warning' => 'Предупреждение: суммарный размер включаемых шаблонов слишком велик.
 Некоторые шаблоны не будут включены.',
@@ -1352,7 +1352,7 @@ $1",
 ** Потенциально клеветнические сведения',
 'revdelete-otherreason' => 'Другая/дополнительная причина:',
 'revdelete-reasonotherlist' => 'Другая причина',
-'revdelete-edit-reasonlist' => 'Ð\9fÑ\80авить список причин',
+'revdelete-edit-reasonlist' => 'РедакÑ\82иÑ\80овать список причин',
 'revdelete-offender' => 'Автор версии страницы:',
 
 # Suppression log
@@ -1402,7 +1402,7 @@ $1",
 'diff-multi-manyusers' => '(не {{PLURAL:$1|показана $1 промежуточная версия|показаны $1 промежуточные версии|показаны $1 промежуточных версий}}, сделанные более чем $2 {{PLURAL:$2|участником|участниками}})',
 'difference-missing-revision' => '{{PLURAL:$2|$2 версия|$2 версии|$2 версий}} для этого сравнения ($1) {{PLURAL:$2|не обнаружена|не обнаружены}}.
 
-ЭÑ\82о Ð¾Ð±Ñ\8bÑ\87но Ð±Ñ\8bваеÑ\82, ÐµÑ\81ли Ð¿Ð¾Ñ\81ледоваÑ\82Ñ\8c Ð¿Ð¾ Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88ей Ñ\81Ñ\81Ñ\8bлке Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83, которая была удалена.
+ЭÑ\82о Ð¾Ð±Ñ\8bÑ\87но Ð±Ñ\8bваеÑ\82, ÐµÑ\81ли Ð¿ÐµÑ\80ейÑ\82и Ð¿Ð¾ Ñ\83Ñ\81Ñ\82аÑ\80евÑ\88ей Ñ\81Ñ\81Ñ\8bлке Ñ\81Ñ\80авнениÑ\8f Ð²ÐµÑ\80Ñ\81ий Ð´Ð»Ñ\8f Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\8b, которая была удалена.
 Подробности могут быть в [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале удалений].',
 
 # Search results
@@ -1411,7 +1411,7 @@ $1",
 'searchresulttext' => 'Для получения более подробной информации о поиске на страницах проекта, см. [[{{MediaWiki:Helppage}}|справочный раздел]].',
 'searchsubtitle' => 'По запросу «[[:$1]]» ([[Special:Prefixindex/$1|страницы, начинающиеся с этого названия]]{{int:pipe-separator}}[[Special:WhatLinksHere/$1|ссылающиеся на это название]])',
 'searchsubtitleinvalid' => 'По запросу «$1»',
-'toomanymatches' => 'Найдено слишком много соответствий, пожалуйста, попробуйте другой запрос',
+'toomanymatches' => 'Найдено слишком много соответствий; пожалуйста, попробуйте сформулировать запрос иначе',
 'titlematches' => 'Совпадения в названиях страниц',
 'notitlematches' => 'Нет совпадений в названиях страниц',
 'textmatches' => 'Совпадения в текстах страниц',
@@ -1423,7 +1423,7 @@ $1",
 'shown-title' => 'Показывать $1 {{PLURAL:$1|запись|записи|записей}} на странице',
 'viewprevnext' => 'Просмотреть ($1 {{int:pipe-separator}} $2) ($3)',
 'searchmenu-legend' => 'Настройки поиска',
-'searchmenu-exists' => "'''Ð\92 Ñ\8dÑ\82ом Ð²Ð¸ÐºÐ¸-пÑ\80оекÑ\82е есть страница «[[:$1]]»'''",
+'searchmenu-exists' => "'''Ð\92 Ñ\8dÑ\82ой Ð²Ð¸ÐºÐ¸ есть страница «[[:$1]]»'''",
 'searchmenu-new' => "'''Создать страницу «[[:$1]]» в этом вики-проекте!'''",
 'searchhelp-url' => 'Help:Содержание',
 'searchmenu-prefix' => '[[Special:PrefixIndex/$1|Показать страницы с этим префиксом]]',
@@ -1435,10 +1435,10 @@ $1",
 'searchprofile-articles-tooltip' => 'Поиск в $1',
 'searchprofile-project-tooltip' => 'Поиск в $1',
 'searchprofile-images-tooltip' => 'Поиск файлов',
-'searchprofile-everything-tooltip' => 'Поиск на всех страницах (включая страницы обсуждения)',
+'searchprofile-everything-tooltip' => 'Поиск на всех страницах (включая страницы обсуждений)',
 'searchprofile-advanced-tooltip' => 'Искать в заданных пространствах имён',
 'search-result-size' => '$1 ({{PLURAL:$2|$2 слово|$2 слова|$2 слов}})',
-'search-result-category-size' => '$1 {{PLURAL:$1|член|члена|членов}} ($2 {{PLURAL:$2|подкатегория|подкатегории|подкатегорий}}, $3 {{PLURAL:$3|файл|файла|файлов}}).',
+'search-result-category-size' => '$1 {{PLURAL:$1|вхождение|вхождения|вхождений}} ($2 {{PLURAL:$2|подкатегория|подкатегории|подкатегорий}}, $3 {{PLURAL:$3|файл|файла|файлов}}).',
 'search-result-score' => 'Релевантность: $1%.',
 'search-redirect' => '(перенаправление с $1)',
 'search-section' => '(раздел «$1»)',
@@ -1540,7 +1540,7 @@ $1",
 'timezoneregion-europe' => 'Европа',
 'timezoneregion-indian' => 'Индийский океан',
 'timezoneregion-pacific' => 'Тихий океан',
-'allowemail' => 'Разрешить приём электронной почты от других участников',
+'allowemail' => 'Разрешить получение электронной почты от других участников',
 'prefs-searchoptions' => 'Поиск',
 'prefs-namespaces' => 'Пространства имён',
 'defaultns' => 'Иначе искать в следующих пространствах имён:',
@@ -1554,11 +1554,11 @@ $1",
 'prefs-emailconfirm-label' => 'Подтверждение электронной почты:',
 'prefs-textboxsize' => 'Размер окна редактирования',
 'youremail' => 'Электронная почта:',
-'username' => 'РегиÑ\81Ñ\82Ñ\80аÑ\86ионное Ð¸Ð¼Ñ\8f:',
+'username' => 'Ð\98мÑ\8f Ñ\83Ñ\87Ñ\91Ñ\82ной Ð·Ð°Ð¿Ð¸Ñ\81и:',
 'uid' => 'Идентификатор участника:',
 'prefs-memberingroups' => 'Член {{PLURAL:$1|группы|групп}}:',
 'prefs-registration' => 'Время регистрации:',
-'yourrealname' => 'Ð\92аÑ\88е Ð½астоящее имя:',
+'yourrealname' => 'Ð\9dастоящее имя:',
 'yourlanguage' => 'Язык интерфейса:',
 'yourvariant' => 'Вариант языка содержания:',
 'prefs-help-variant' => 'Предпочитаемый для отображения содержимого страниц вики вариант языка или орфография.',
@@ -1577,7 +1577,7 @@ $1",
 'prefs-help-realname' => 'Настоящее имя (необязательное поле).
 Если вы укажете его, то оно будет использовано для того, чтобы показать, кем была внесена правка страницы.',
 'prefs-help-email' => 'Адрес электронной почты указывать необязательно, но он будет необходим в том случае, если вы забудете пароль.',
-'prefs-help-email-others' => 'Он также позволит другим участникам связаться с вами через ссылку на вашей личной странице без необходимости раскрытия адреса вашей электронной почты.',
+'prefs-help-email-others' => 'Он также позволит другим участникам связаться с вами по электронной почте с помощью ссылки на вашей персональной странице или на вашей странице обсуждения. При этом ваш адрес электронной почты не будет никому раскрыт.',
 'prefs-help-email-required' => 'Необходимо указать адрес электронной почты.',
 'prefs-info' => 'Основные сведения',
 'prefs-i18n' => 'Интернационализация',
@@ -1596,22 +1596,22 @@ $1",
 
 # User preference: e-mail validation using jQuery
 'email-address-validity-valid' => 'Выглядит корректно',
-'email-address-validity-invalid' => 'ТÑ\80ебÑ\83еÑ\82Ñ\81Ñ\8f ÐºÐ¾Ñ\80Ñ\80екÑ\82нÑ\8bй Ð°Ð´Ñ\80еÑ\81!',
+'email-address-validity-invalid' => 'Ð\92ведиÑ\82е ÐºÐ¾Ñ\80Ñ\80екÑ\82нÑ\8bй Ð°Ð´Ñ\80еÑ\81 Ñ\8dлекÑ\82Ñ\80онной Ð¿Ð¾Ñ\87Ñ\82Ñ\8b!',
 
 # User rights
 'userrights' => 'Управление правами участника',
 'userrights-lookup-user' => 'Управление группами участников',
-'userrights-user-editname' => 'Введите имя участника:',
+'userrights-user-editname' => 'Введите имя учётной записи:',
 'editusergroup' => 'Изменить членство в группах',
 'editinguser' => "Изменение прав {{GENDER:$1|участника|участницы}} '''[[User:$1|$1]]''' $2",
 'userrights-editusergroup' => 'Изменение членства в группах',
 'saveusergroups' => 'Сохранить группы участника',
-'userrights-groupsmember' => 'Член Ð³Ñ\80Ñ\83пп:',
-'userrights-groupsmember-auto' => 'Неявный член:',
+'userrights-groupsmember' => 'СоÑ\81Ñ\82оиÑ\82 Ð² Ð³Ñ\80Ñ\83ппаÑ\85:',
+'userrights-groupsmember-auto' => 'Неявно состоит в группах:',
 'userrights-groups-help' => 'Вы можете изменить группы, в которые входит этот участник.
 * Если около названия группы стоит отметка, значит участник входит в эту группу.
 * Если отметка не стоит — участник не относится к соответствующей группе.
-* Знак * отмечает, что вы не можете удалить из группы участника, если добавите его в неё или наоборот.',
+* Знак * отмечает, что вы не сможете удалить участника из группы, если добавите его в неё, или наоборот.',
 'userrights-reason' => 'Причина:',
 'userrights-no-interwiki' => 'У вас нет разрешения изменять права участников на других вики.',
 'userrights-nodatabase' => 'База данных $1 не существует или не является локальной.',
@@ -1677,7 +1677,7 @@ $1",
 'right-undelete' => 'восстановление страниц',
 'right-suppressrevision' => 'просмотр и восстановление скрытых от администраторов версий страниц',
 'right-suppressionlog' => 'просмотр частных журналов',
-'right-block' => 'Ñ\83Ñ\81Ñ\82ановка Ð·Ð°Ð¿Ñ\80еÑ\82а Ð½Ð° Ñ\80едакÑ\82иÑ\80ование Ð´Ñ\80Ñ\83гим Ñ\83Ñ\87аÑ\81Ñ\82никам',
+'right-block' => 'Ñ\83Ñ\81Ñ\82ановка Ð¾Ð³Ñ\80аниÑ\87ений Ð½Ð° Ñ\80едакÑ\82иÑ\80ование Ð´Ð»Ñ\8f Ð´Ñ\80Ñ\83гиÑ\85 Ñ\83Ñ\87аÑ\81Ñ\82ников',
 'right-blockemail' => 'установка запрета на отправку электронной почты',
 'right-hideuser' => 'запрет имени участника и его сокрытие',
 'right-ipblock-exempt' => 'обход блокировок по IP, автоблокировок и блокировок диапазонов',
@@ -1721,16 +1721,16 @@ $1",
 'action-edit' => 'редактирование этой страницы',
 'action-createpage' => 'создание страниц',
 'action-createtalk' => 'создание страниц обсуждений',
-'action-createaccount' => 'создание этой учётной записи участника',
-'action-minoredit' => 'оÑ\82меÑ\82ка этой правки как малой',
+'action-createaccount' => 'создание этой учётной записи',
+'action-minoredit' => 'помеÑ\82кÑ\83 этой правки как малой',
 'action-move' => 'переименование этой страницы',
 'action-move-subpages' => 'переименование этой страницы со всеми её подстраницами',
 'action-move-rootuserpages' => 'переименование корневых страниц участников',
 'action-movefile' => 'переименовать этот файл',
-'action-upload' => 'загрузка этого файла',
+'action-upload' => 'загрузку этого файла',
 'action-reupload' => 'перезапись существующего файла',
 'action-reupload-shared' => 'перекрытие файла из общего хранилища',
-'action-upload_by_url' => 'загрузка этого файла с адреса URL',
+'action-upload_by_url' => 'загрузку этого файла с адреса URL',
 'action-writeapi' => 'использование API для правок',
 'action-delete' => 'удаление этой страницы',
 'action-deleterevision' => 'удаление этой версии страницы',
@@ -1739,9 +1739,9 @@ $1",
 'action-undelete' => 'восстановление этой страницы',
 'action-suppressrevision' => 'просмотр и восстановление этой скрытой версии страницы',
 'action-suppressionlog' => 'просмотр этого частного журнала',
-'action-block' => 'блокиÑ\80овка участника',
+'action-block' => 'огÑ\80аниÑ\87иваÑ\82Ñ\8c Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñ\81Ñ\82Ñ\8c Ñ\80едакÑ\82иÑ\80ованиÑ\8f Ð´Ð»Ñ\8f Ñ\8dÑ\82ого участника',
 'action-protect' => 'изменение уровня защиты этой страницы',
-'action-rollback' => 'быстрый откат изменений последнего пользователя, который редактировал страницу',
+'action-rollback' => 'быстрый откат изменений участника, который последним редактировал страницу',
 'action-import' => 'импорт этой страницы из другой вики',
 'action-importupload' => 'импорт этой страницы из загруженного файла',
 'action-patrol' => 'отметка чужих правок как отпатрулированных',
@@ -1758,13 +1758,13 @@ $1",
 'recentchanges' => 'Свежие правки',
 'recentchanges-legend' => 'Настройки свежих правок',
 'recentchanges-summary' => 'Ниже в хронологическом порядке перечислены последние изменения на страницах {{grammar:genitive|{{SITENAME}}}}.',
-'recentchanges-feed-description' => 'Ð\9eÑ\82Ñ\81леживаÑ\82Ñ\8c Ð¿Ð¾Ñ\81ледние Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\8f Ð² Ð²Ð¸ÐºÐ¸ Ð² Ñ\8dÑ\82ом Ð¿Ð¾Ñ\82оке.',
+'recentchanges-feed-description' => 'Ð\9eÑ\82Ñ\81леживаÑ\82Ñ\8c Ð² Ñ\8dÑ\82ом Ð¿Ð¾Ñ\82оке Ð¿Ð¾Ñ\81ледние Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\8f Ð² Ð²Ð¸ÐºÐ¸.',
 'recentchanges-label-newpage' => 'Этой правкой была создана новая страница.',
 'recentchanges-label-minor' => 'Это незначительное изменение',
 'recentchanges-label-bot' => 'Эта правка сделана ботом',
-'recentchanges-label-unpatrolled' => 'Эту правку ещё не отпатрулировали',
+'recentchanges-label-unpatrolled' => 'Эта правку ещё никем не патрулировалась',
 'rcnote' => "{{PLURAL:$1|Последнее '''$1''' изменение|Последние '''$1''' изменения|Последние '''$1''' изменений}} за '''$2''' {{PLURAL:$2|день|дня|дней}}, на момент времени $5 $4.",
-'rcnotefrom' => 'Ниже перечислены изменения с <strong>$2</strong> (по <strong>$1</strong>).',
+'rcnotefrom' => "Ниже перечислены изменения с '''$2''' (не более '''$1''').",
 'rclistfrom' => 'Показать изменения с $1.',
 'rcshowhideminor' => '$1 малые правки',
 'rcshowhidebots' => '$1 ботов',
@@ -2203,7 +2203,7 @@ $1',
 
 'withoutinterwiki' => 'Страницы без интервики-ссылок',
 'withoutinterwiki-summary' => 'Следующие страницы не имеют интервики-ссылок:',
-'withoutinterwiki-legend' => 'Ð\9fÑ\80иÑ\81Ñ\82авка',
+'withoutinterwiki-legend' => 'Ð\9fÑ\80еÑ\84икÑ\81',
 'withoutinterwiki-submit' => 'Показать',
 
 'fewestrevisions' => 'Страницы с наименьшим количеством версий',
@@ -2373,7 +2373,7 @@ $1',
 'listgrouprights-group' => 'Группа',
 'listgrouprights-rights' => 'Права',
 'listgrouprights-helppage' => 'Help:Права групп',
-'listgrouprights-members' => '(список группы)',
+'listgrouprights-members' => '(список участников)',
 'listgrouprights-right-display' => '<span class="listgrouprights-granted">$1 (<code>$2</code>)</span>',
 'listgrouprights-right-revoked' => '<span class="listgrouprights-revoked">$1 (<code>$2</code>)</span>',
 'listgrouprights-addgroup' => 'может добавлять в {{PLURAL:$2|группу|группы}}: $1',
@@ -2681,10 +2681,10 @@ $1',
 # Contributions
 'contributions' => 'Вклад участника',
 'contributions-title' => 'Вклад {{GENDER:$1|участника|участницы}} $1',
-'mycontris' => 'Ð\9cой Ð²клад',
+'mycontris' => 'Ð\92клад',
 'contribsub2' => 'Вклад $1 ($2)',
 'nocontribs' => 'Изменений, соответствующих заданным условиям, найдено не было.',
-'uctop' => ' (последняя)',
+'uctop' => '(последняя)',
 'month' => 'С месяца (и ранее):',
 'year' => 'С года (и ранее):',
 
@@ -2715,13 +2715,13 @@ $1',
 'isredirect' => 'страница-перенаправление',
 'istemplate' => 'включение',
 'isimage' => 'файловая ссылка',
-'whatlinkshere-prev' => '{{PLURAL:$1|предыдущая|предыдущие|предыдущие}} $1',
-'whatlinkshere-next' => '{{PLURAL:$1|следующая|следующие|следующие}} $1',
+'whatlinkshere-prev' => '{{PLURAL:$1|предыдущая|предыдущие}} $1',
+'whatlinkshere-next' => '{{PLURAL:$1|следующая|следующие}} $1',
 'whatlinkshere-links' => '← ссылки',
 'whatlinkshere-hideredirs' => '$1 перенаправления',
 'whatlinkshere-hidetrans' => '$1 включения',
 'whatlinkshere-hidelinks' => '$1 ссылки',
-'whatlinkshere-hideimages' => '$1 Ñ\81Ñ\81Ñ\8bлки Ð´Ð»Ñ\8f Ð¸Ð·Ð¾Ð±Ñ\80ажений',
+'whatlinkshere-hideimages' => '$1 Ñ\84айловÑ\8bе Ñ\81Ñ\81Ñ\8bлки',
 'whatlinkshere-filters' => 'Фильтры',
 
 # Block/unblock
@@ -3002,7 +3002,7 @@ $1',
 'allmessages-filter-unmodified' => 'Неизменённые',
 'allmessages-filter-all' => 'Все',
 'allmessages-filter-modified' => 'Изменённые',
-'allmessages-prefix' => 'ФилÑ\8cÑ\82Ñ\80 Ð¿Ð¾ Ð¿Ñ\80иÑ\81Ñ\82авке:',
+'allmessages-prefix' => 'ФилÑ\8cÑ\82Ñ\80 Ð¿Ð¾ Ð¿Ñ\80еÑ\84икÑ\81Ñ\83:',
 'allmessages-language' => 'Язык:',
 'allmessages-filter-submit' => 'Перейти',
 
@@ -3096,8 +3096,8 @@ $1',
 'tooltip-pt-login' => 'Здесь можно зарегистрироваться в системе, но это необязательно.',
 'tooltip-pt-anonlogin' => 'Здесь можно зарегистрироваться в системе, но это необязательно.',
 'tooltip-pt-logout' => 'Завершить сеанс работы',
-'tooltip-ca-talk' => 'Обсуждение содержания страницы',
-'tooltip-ca-edit' => 'ЭÑ\82Ñ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83 Ð¼Ð¾Ð¶Ð½Ð¾ Ð¸Ð·Ð¼ÐµÐ½Ñ\8fÑ\82Ñ\8c. Ð\98Ñ\81полÑ\8cзÑ\83йÑ\82е, Ð¿Ð¾Ð¶Ð°Ð»Ñ\83йÑ\81Ñ\82а, Ð¿Ñ\80едваÑ\80иÑ\82елÑ\8cнÑ\8bй Ð¿Ñ\80оÑ\81моÑ\82Ñ\80 Ð¿ÐµÑ\80ед Ñ\81оÑ\85Ñ\80анением',
+'tooltip-ca-talk' => 'Обсуждение основной страницы',
+'tooltip-ca-edit' => 'Ð\92Ñ\8b Ð¼Ð¾Ð¶ÐµÑ\82е Ñ\80едакÑ\82иÑ\80оваÑ\82Ñ\8c Ñ\8dÑ\82Ñ\83 Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\83. Ð\9fеÑ\80ед Ñ\82ем, ÐºÐ°Ðº Ð·Ð°Ð¿Ð¸Ñ\81аÑ\82Ñ\8c Ñ\81вои Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\8f, Ð²Ð¾Ñ\81полÑ\8cзÑ\83йÑ\82еÑ\81Ñ\8c, Ð¿Ð¾Ð¶Ð°Ð»Ñ\83йÑ\81Ñ\82а, ÐºÐ½Ð¾Ð¿ÐºÐ¾Ð¹ Ð¿Ñ\80едваÑ\80иÑ\82елÑ\8cного Ð¿Ñ\80оÑ\81моÑ\82Ñ\80а.',
 'tooltip-ca-addsection' => 'Создать новый раздел',
 'tooltip-ca-viewsource' => 'Эта страница защищена от изменений, но вы можете посмотреть и скопировать её исходный текст',
 'tooltip-ca-history' => 'Журнал изменений страницы',
@@ -3115,21 +3115,21 @@ $1',
 'tooltip-n-mainpage' => 'Перейти на заглавную страницу',
 'tooltip-n-mainpage-description' => 'Перейти на заглавную страницу',
 'tooltip-n-portal' => 'О проекте, о том, что вы можете сделать, где что находится',
-'tooltip-n-currentevents' => 'СпиÑ\81ок Ñ\82екÑ\83Ñ\89иÑ\85 Ñ\81обÑ\8bÑ\82ий',
+'tooltip-n-currentevents' => 'Ð\98нÑ\84оÑ\80маÑ\86иÑ\8f Ð¾ Ñ\82екÑ\83Ñ\89иÑ\85 Ñ\81обÑ\8bÑ\82иÑ\8fÑ\85',
 'tooltip-n-recentchanges' => 'Список последних изменений',
 'tooltip-n-randompage' => 'Посмотреть случайную страницу',
 'tooltip-n-help' => 'Справочник по проекту «{{SITENAME}}»',
-'tooltip-t-whatlinkshere' => 'Список всех страниц, которые ссылаются на эту страницу',
+'tooltip-t-whatlinkshere' => 'Список всех страниц, ссылающихся на данную',
 'tooltip-t-recentchangeslinked' => 'Последние изменения в страницах, на которые ссылается эта страница',
 'tooltip-feed-rss' => 'Трансляция в RSS для этой страницы',
 'tooltip-feed-atom' => 'Трансляция в Atom для этой страницы',
 'tooltip-t-contributions' => 'Список страниц, которые изменял этот участник',
 'tooltip-t-emailuser' => 'Отправить письмо этому участнику',
-'tooltip-t-upload' => 'Загрузить изображения или мультимедиа-файлы',
+'tooltip-t-upload' => 'Загрузить файлы',
 'tooltip-t-specialpages' => 'Список служебных страниц',
 'tooltip-t-print' => 'Версия этой страницы для печати',
 'tooltip-t-permalink' => 'Постоянная ссылка на эту версию страницы',
-'tooltip-ca-nstab-main' => 'СодеÑ\80жание Ñ\81Ñ\82аÑ\82Ñ\8cи',
+'tooltip-ca-nstab-main' => 'Ð\9fÑ\80оÑ\81моÑ\82Ñ\80 Ð¾Ñ\81новной Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\8b',
 'tooltip-ca-nstab-user' => 'Персональная страница участника',
 'tooltip-ca-nstab-media' => 'Медиа-файл',
 'tooltip-ca-nstab-special' => 'Это служебная страница, она недоступна для редактирования',
@@ -3944,8 +3944,8 @@ $5
 
 # Watchlist editing tools
 'watchlisttools-view' => 'Изменения на страницах из списка',
-'watchlisttools-edit' => 'Смотреть/править список',
-'watchlisttools-raw' => 'Ð\9fÑ\80авиÑ\82Ñ\8c ÐºÐ°Ðº текст',
+'watchlisttools-edit' => 'Смотреть и редактировать список',
+'watchlisttools-raw' => 'РедакÑ\82иÑ\80оваÑ\82Ñ\8c ÐºÐ°Ðº Ð¾Ð±Ñ\8bÑ\87нÑ\8bй текст',
 
 # Iranian month names
 'iranian-calendar-m1' => 'Фарвардин',
@@ -4149,7 +4149,7 @@ MediaWiki распространяется в надежде, что она бу
 'sqlite-no-fts' => '$1 без поддержки полнотекстового поиска',
 
 # New logging system
-'logentry-delete-delete' => '$1 {{GENDER:$1|удалил|удалила}} страницу $3',
+'logentry-delete-delete' => '$1 {{GENDER:$2|удалил|удалила}} страницу $3',
 'logentry-delete-restore' => '$1 {{GENDER:$1|восстановил|восстановила}} страницу $3',
 'logentry-delete-event' => '$1 {{GENDER:$1|изменил|изменила}} видимость {{PLURAL:$5|$5 записи|$5 записей|$5 записей}} журнала на $3: $4',
 'logentry-delete-revision' => '$1 {{GENDER:$1|изменил|изменила}} видимость {{PLURAL:$5|$5 версии|$5 версий|$5 версий}} на странице $3: $4',
index 3c24068..4c07e55 100644 (file)
@@ -91,7 +91,7 @@ $messages = array(
 
 'underline-always' => 'Куруук',
 'underline-never' => 'Аннынан тардыма',
-'underline-default' => 'Браузер настройкатынан',
+'underline-default' => 'Браузер туруоруутунан',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Эрэдээксийэлиир түннүк бичигэ:',
@@ -307,6 +307,7 @@ $1',
 'newmessagesdifflink' => 'кэлиҥҥи уларытыы',
 'youhavenewmessagesfromusers' => 'Маны $1 {{PLURAL:$3|соҕотох кыттааччыттан|$3 кыттааччыттан}} туппуккун ($2).',
 'youhavenewmessagesmanyusers' => 'Маны $1 элбэх кыттааччыттан туппуккун ($2).',
+'newmessageslinkplural' => '{{PLURAL:$1|саҥа этии|саҥа этии}}',
 'newmessagesdifflinkplural' => 'тиһэх {{PLURAL:$1|уларытыы|уларытыылар}}',
 'youhavenewmessagesmulti' => '$1, саҥа суруктар кэллилэр',
 'editsection' => 'уларыт',
@@ -2272,7 +2273,7 @@ $1',
 # Contributions
 'contributions' => 'Кыттааччы суруйуута (вклад)',
 'contributions-title' => '$1 кыттааччы киллэрбит уларытыылара',
-'mycontris' => 'Суруйуум тиһигэ',
+'mycontris' => 'Суруйуу тиһигэ',
 'contribsub2' => 'Вклад $1 ($2)',
 'nocontribs' => 'Эппит критерийгэр эппиэттиир уларытыылар көстүбэтилэр.',
 'uctop' => '(бүтэһик)',
@@ -2312,7 +2313,7 @@ $1',
 'whatlinkshere-hideredirs' => '$1 утаарыы',
 'whatlinkshere-hidetrans' => '$1 киллэриилэр',
 'whatlinkshere-hidelinks' => '$1 сигэ (ыйынньык)',
-'whatlinkshere-hideimages' => '$1 Ð¾Ð¹Ñ\83Ñ\83 сигэтэ',
+'whatlinkshere-hideimages' => '$1 Ð±Ð¸Ð»Ñ\8d сигэтэ',
 'whatlinkshere-filters' => 'Фильтрдар',
 
 # Block/unblock
@@ -3479,6 +3480,7 @@ MediaWiki туһалаах буоллун диэн тарҕатыллар, ол
 'version-software' => 'Туруоруллубут бырагырааммалар',
 'version-software-product' => 'Бородуукта',
 'version-software-version' => 'Барыл (торум)',
+'version-entrypoints' => 'Киирэр аадырыстар (URL)',
 'version-entrypoints-header-entrypoint' => 'Киирии сирэ',
 'version-entrypoints-header-url' => 'URL',
 
@@ -3651,7 +3653,8 @@ MediaWiki туһалаах буоллун диэн тарҕатыллар, ол
 'api-error-file-too-large' => 'Ыыппыт билэҥ наһаа улахан эбит.',
 'api-error-filename-tooshort' => 'Билэҥ аата наһаа кылгас.',
 'api-error-filetype-banned' => 'Маннык көрүҥнээх билэлэр бобуулаахтар.',
-'api-error-filetype-banned-type' => '$1 — {{PLURAL:$4|билэ бобуллубут көрүҥэ|билэ бобуллубут көрүҥнэрэ}}.. Көҥүллэммит билэ {{PLURAL:$3|көрүҥэ маннык|көрүҥнэрэ манныктар}}: $2.',
+'api-error-filetype-banned-type' => '$1 — {{PLURAL:$4|билэ бобуллубут көрүҥэ|билэ бобуллубут көрүҥнэрэ}}. 
+Көҥүллэммит билэ {{PLURAL:$3|көрүҥэ маннык|көрүҥнэрэ манныктар}}: $2.',
 'api-error-filetype-missing' => 'Бу билэ тэнитиитэ (расширение) суох эбит.',
 'api-error-hookaborted' => 'Эн киллэрбит уларытыыгын кэҥэтии таҥастааччыта оннугар төннөрбүт.',
 'api-error-http' => 'Ис алҕас: Сиэрбэргэ холбонор табыллыбата.',
index 4a26e3a..c7d4211 100644 (file)
@@ -1648,7 +1648,7 @@ Musí obsahovať menej ako $1 {{PLURAL:$1|znak|znaky|znakov}}.',
 'hist' => 'história',
 'hide' => 'skryť',
 'show' => 'zobraziť',
-'minoreditletter' => 'D',
+'minoreditletter' => 'd',
 'newpageletter' => 'N',
 'boteditletter' => 'b',
 'number_of_watching_users_pageview' => '[$1 {{PLURAL:$1|sledujúci používateľ|sledujúci používatelia|sledujúcich používateľov}}]',
index 8911498..afd5f12 100644 (file)
@@ -318,7 +318,7 @@ $messages = array(
 'newwindow' => '(odpre se novo okno)',
 'cancel' => 'Prekliči',
 'moredotdotdot' => 'Več ...',
-'mypage' => 'Moja stran',
+'mypage' => 'Stran',
 'mytalk' => 'Pogovor',
 'anontalk' => 'Pogovorna stran IP',
 'navigation' => 'Navigacija',
index f330092..ae5009b 100644 (file)
@@ -455,7 +455,7 @@ $messages = array(
 'cancel' => 'Avbryt',
 'moredotdotdot' => 'Mer...',
 'mypage' => 'Min sida',
-'mytalk' => 'Min diskussion',
+'mytalk' => 'Diskussion',
 'anontalk' => 'Diskussionssida för denna IP-adress',
 'navigation' => 'Navigering',
 'and' => '&#32;och',
@@ -1385,7 +1385,7 @@ Notera dock att deras indexering av {{SITENAME}} kan vara något föråldrad.',
 
 # Preferences page
 'preferences' => 'Inställningar',
-'mypreferences' => 'Mina inställningar',
+'mypreferences' => 'Inställningar',
 'prefs-edits' => 'Antal redigeringar:',
 'prefsnologin' => 'Inte inloggad',
 'prefsnologintext' => 'Du måste vara <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} inloggad]</span> för att kunna ändra dina inställningar.',
@@ -2242,8 +2242,8 @@ Se även [[Special:WantedCategories|önskade kategorier]].',
 'linksearch-ns' => 'Namnrymd:',
 'linksearch-ok' => 'Sök',
 'linksearch-text' => 'Jokertecken (wildcards) som t.ex. "*.wikipedia.org" kan användas.
-Det krävs åtminstone en toppnivå-domän, t.ex. "*.org".<br />
-Protokoll som stöds: <code>$1</code> (lägg inte till något av dessa i din sökning).',
+Det krävs åtminstone en toppdomän, t.ex. "*.org".<br />
+Protokoll som stöds: <code>$1</code> (lägg inte till någon av dessa i din sökning).',
 'linksearch-line' => '$1 länkas från $2',
 'linksearch-error' => 'Jokertecken kan bara användas i början av domännamnet.',
 
@@ -2324,7 +2324,7 @@ Den e-postadress du har angivit i [[Special:Preferences|dina användarinställni
 
 # Watchlist
 'watchlist' => 'Bevakningslista',
-'mywatchlist' => 'Min bevakningslista',
+'mywatchlist' => 'Bevakningslista',
 'watchlistfor2' => 'För $1 $2',
 'nowatchlist' => 'Du har inga sidor i din bevakningslista.',
 'watchlistanontext' => 'Du måste $1 för att se eller redigera din bevakningslista.',
@@ -2579,7 +2579,7 @@ $1',
 # Contributions
 'contributions' => 'Användarbidrag',
 'contributions-title' => 'Bidrag av $1',
-'mycontris' => 'Mina bidrag',
+'mycontris' => 'Bidrag',
 'contribsub2' => 'För $1 ($2)',
 'nocontribs' => 'Inga ändringar som motsvarar dessa kriterier hittades.',
 'uctop' => '(senaste)',
@@ -3848,6 +3848,7 @@ Du kan också [[Special:EditWatchlist|använda standardeditorn]].',
 'version-license' => 'Licens',
 'version-poweredby-credits' => "Den här wikin drivs av '''[//www.mediawiki.org/ MediaWiki]''', copyright © 2001-$1 $2.",
 'version-poweredby-others' => 'andra',
+'version-credits-summary' => 'Vi skulle vilja tacka följande personer för deras bidrag till [[Special:Version|MediaWiki]].',
 'version-license-info' => 'MediaWiki är fri programvara; du kan distribuera det och/eller modifiera det under villkoren i GNU General Public License, publicerad av Free Software Foundation; antingen version 2 av licensen, eller (om du önskar) någon senare version. 
 
 MediaWiki distribueras i hopp om att det ska vara användbart, men UTAN NÅGON GARANTI, även utan underförstådd garanti om SÄLJBARHET eller LÄMPLIGHET FÖR ETT VISST SYFTE. Se GNU General Public License för fler detaljer. 
@@ -4065,4 +4066,6 @@ Annars kan du använda det enkla formuläret nedan. Din kommentar kommer att lä
 'duration-centuries' => '$1 {{PLURAL:$1|sekel|sekel}}',
 'duration-millennia' => '$1 {{PLURAL:$1|millennium|millennier}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'diskussion',
 );
index ee81d3a..a341854 100644 (file)
@@ -259,7 +259,7 @@ $messages = array(
 'cancel' => 'Batilisha',
 'moredotdotdot' => 'Zaidi...',
 'mypage' => 'Ukurasa wangu',
-'mytalk' => 'Majadiliano yangu',
+'mytalk' => 'Majadiliano',
 'anontalk' => 'Majadiliano ya IP hii',
 'navigation' => 'Urambazaji',
 'and' => '&#32;na',
@@ -778,7 +778,7 @@ Labda itakusumbua kwamba kuna maoni mengine yanawekwa hapa na unaamini kwamba ha
 '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.
 Unaweza [[Special:Search/{{PAGENAME}}|kutafuta jina la ukurasa huu]] katika kurasa nyingine,
-au <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tafuta ingizo linalofanana]</span>.',
+au <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.
 Ukitaka kuanzisha au kuhariri ukurasa huu tafadhali ucheki jina la akaunti.',
 'userpage-userdoesnotexist-view' => 'Akaunti ya mtumiaji "$1" haijasajilishwa.',
@@ -1131,7 +1131,7 @@ Ujue lakini kwamba kumbukumbu za {{SITENAME}} kule Google labda zilipitwa na wak
 
 # Preferences page
 'preferences' => 'Mapendekezo',
-'mypreferences' => 'Mapendekezo yangu',
+'mypreferences' => 'Mapendekezo',
 'prefs-edits' => 'Idadi ya marekebisho:',
 'prefsnologin' => 'Hujaingia',
 'prefsnologintext' => 'Inabidi <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} uingie akaunti yako]</span> ili ubadilishe mapendekezo yako.',
@@ -1980,7 +1980,7 @@ Anwani yako ya barua pepe ulioitaja katika [[Special:Preferences|mapendekezo yak
 
 # Watchlist
 'watchlist' => 'Maangalizi yangu',
-'mywatchlist' => 'Maangalizi yangu',
+'mywatchlist' => 'Maangalizi',
 'watchlistfor2' => 'Kwa ajili ya $1 $2',
 'nowatchlist' => 'Hamna vitu katika maangalizi yako.',
 'watchlistanontext' => 'Tafadhali $1 ili kutazama au kuhariri vitu vilivyopo katika orodha yako ya maangalizi.',
@@ -2201,7 +2201,7 @@ $1',
 # Contributions
 'contributions' => 'Michango ya mtumiaji',
 'contributions-title' => 'Michango ya mtumiaji $1',
-'mycontris' => 'Michango yangu',
+'mycontris' => 'Michango',
 'contribsub2' => 'Kwa $1 ($2)',
 'nocontribs' => 'Mabadiliko yanayolingana na vigezo vilivyoulizwa hayakupatikana.',
 'uctop' => '(juu)',
index f8fca7a..2263f04 100644 (file)
@@ -129,7 +129,7 @@ $messages = array(
 
 'underline-always' => 'எப்பொழுதும்',
 'underline-never' => 'எப்போதுமில்லை',
-'underline-default' => 'உலாவி இயல்பிருப்பு',
+'underline-default' => 'தà¯\8bலà¯\8d à®\85லà¯\8dலதà¯\81 à®\89லாவி à®\87யலà¯\8dபிரà¯\81பà¯\8dபà¯\81',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'தொகுத்தல் பெட்டி எழுத்துரு:',
@@ -214,8 +214,8 @@ $messages = array(
 'newwindow' => '(புதிய சாளரத்துள் திறக்கும்)',
 'cancel' => 'சேமிக்காமல் திரும்பு',
 'moredotdotdot' => 'மேலும்...',
-'mypage' => 'à®\8eனதà¯\81 à®ªà®\95à¯\8dà®\95à®®à¯\8d',
-'mytalk' => 'à®\8eனà¯\8d à®ªà¯\87à®\9aà¯\8dà®\9aà¯\81',
+'mypage' => 'பக்கம்',
+'mytalk' => 'பேச்சு',
 'anontalk' => 'இந்த ஐ.பி. முகவரிக்கான பேச்சு',
 'navigation' => 'வழிசெலுத்தல்',
 'and' => ' மற்றும்',
@@ -345,6 +345,7 @@ $1',
 'youhavenewmessages' => 'உங்களுக்குப் $1 உள்ளன ($2).',
 'newmessageslink' => 'புதிய செய்திகள்',
 'newmessagesdifflink' => 'கடைசி மாற்றம்',
+'youhavenewmessagesfromusers' => 'உங்களுக்கு $1 {{PLURAL:$3|வேறொரு பயனரிடம்|$3 பயனர்களிடம்}} இருந்து உள்ளது ($2).',
 'newmessageslinkplural' => '{{PLURAL:$1|ஒரு புதிய செய்தி|புதிய செய்திகள்}}',
 'newmessagesdifflinkplural' => 'கடைசி {{PLURAL:$1|மாற்றம்|மாற்றங்கள்}}',
 'youhavenewmessagesmulti' => '$1 இல் உங்களுக்கு புதிய செய்திகள் காத்திருக்கின்றன',
@@ -681,7 +682,7 @@ $2
 * தடை செய்யப்பட்டவர்: $7
 
 $1 பயனரையோ அல்லது வேறு [[{{MediaWiki:Grouppage-sysop}}|நிர்வாகி]] ஒருவரையோ அனுகி தடைப் பற்றி கலந்துரையாடலாம். 'இப் பயனருக்கு மின்னஞ்சல் செய்' என்ற வசதியை நீங்கள் பயன்படுத்துவதுலிருந்து தடைச் செய்யப்பட்டிருந்தாலோ அல்லது [[Special:Preferences|என் விருப்பத்தேர்வுகள்]] பக்கத்தில் இயங்குநிலையிலுள்ள மின்னஞ்சல் முகவரியை தராத போதோ பயனருக்கு மின்னஞ்சல் செய்ய முடியாது. உங்களது தற்போதைய ஐ.பி. முகவரி $3 மற்றும் தடை எண்  #$5 என்பவற்றை கேள்விகள் கேட்கும் போது கட்டாயம் குறிப்பிடவும்.",
-'autoblockedtext' => '$1 ஆல் தடைச்செய்யப்பட்ட வேறு பயனரால் பயன்படுத்தபட்டதால், உங்கள் ஐ.பி. முகவரி தானியக்கமாக தடுக்கப்பட்டுள்ளது. அதற்கான காரணம் பின்வருமாறு:
+'autoblockedtext' => 'உங்கள் ஐ.பி. முகவரி தடை செய்யப்பட்டுள்ளது. அதே முகவரியைப் பயன்படுத்தித் தொக்குத்த யாரோ ஒரு பயனர் பின்வரும் காரணங்களுக்காகத் தடை செய்யப்பட்டுள்ளார். அதனால் உங்களால் தொகுக்க முடியவில்லை. அதற்கான காரணம் பின்வருமாறு:
 
 :\'\'$2\'\'
 
@@ -689,11 +690,11 @@ $1 பயனரையோ அல்லது வேறு [[{{MediaWiki:Grouppage
 * தடை முடிவு: $6
 * தடை செய்யப்பட்டவர்: $7
 
-$1 à®ªà®¯à®©à®°à¯\88யà¯\8b à®\85லà¯\8dலதà¯\81 à®µà¯\87à®±à¯\81 [[{{MediaWiki:Grouppage-sysop}}|நிரà¯\8dவாà®\95ி]] à®\92à®°à¯\81வரà¯\88யà¯\8b à®\85னà¯\81à®\95ி à®¤à®\9fைப் பற்றி கலந்துரையாடலாம்.
+$1 à®\8eனà¯\81à®®à¯\8d à®ªà®¯à®©à®°à¯\88யà¯\8b à®µà¯\87à®±à¯\81 [[{{MediaWiki:Grouppage-sysop}}|நிரà¯\8dவாà®\95ி]] à®\92à®°à¯\81வரà¯\88யà¯\8b à®\85னà¯\81à®\95ிதà¯\8d à®¤à®\9fà¯\88யைப் பற்றி கலந்துரையாடலாம்.
 
-"à®\87பà¯\8d à®ªà®¯à®©à®°à¯\81à®\95à¯\8dà®\95à¯\81 à®®à®¿à®©à¯\8dனà®\9eà¯\8dà®\9aலà¯\8d à®\9aà¯\86யà¯\8d" à®\8eனà¯\8dà®± à®µà®\9aதியà¯\88 à®¨à¯\80à®\99à¯\8dà®\95ளà¯\8d à®ªà®¯à®©à¯\8dபà®\9fà¯\81தà¯\81வதிலிரà¯\81நà¯\8dதà¯\81 à®¤à®\9fà¯\88à®\9aà¯\8d à®\9aà¯\86யà¯\8dயபà¯\8dபà®\9fà¯\8dà®\9fிரà¯\81நà¯\8dதாலà¯\8b à®\85லà¯\8dலதà¯\81 [[Special:Preferences|à®\8eனà¯\8d à®µà®¿à®°à¯\81பà¯\8dபதà¯\8dதà¯\87à®°à¯\8dவà¯\81à®\95ளà¯\8d]] à®ªà®\95à¯\8dà®\95தà¯\8dதிலà¯\8d à®\87யà®\99à¯\8dà®\95à¯\81நிலà¯\88யிலà¯\81ளà¯\8dள à®®à®¿à®©à¯\8dனà®\9eà¯\8dà®\9aலà¯\8d à®®à¯\81à®\95வரியà¯\88 à®¤à®°à®¾à®¤ போதோ பயனருக்கு மின்னஞ்சல் செய்ய முடியாது.
+"à®\87பà¯\8d à®ªà®¯à®©à®°à¯\81à®\95à¯\8dà®\95à¯\81 à®®à®¿à®©à¯\8dனà®\9eà¯\8dà®\9aலà¯\8d à®\9aà¯\86யà¯\8d" à®\8eனà¯\8dà®± à®µà®\9aதியà¯\88 à®¨à¯\80à®\99à¯\8dà®\95ளà¯\8d à®ªà®¯à®©à¯\8dபà®\9fà¯\81தà¯\8dதà¯\81வதிலிரà¯\81நà¯\8dதà¯\81 à®¤à®\9fà¯\88à®\9aà¯\8d à®\9aà¯\86யà¯\8dயபà¯\8dபà®\9fà¯\8dà®\9fிரà¯\81நà¯\8dதாலà¯\8b à®\85லà¯\8dலதà¯\81 [[Special:Preferences|à®\8eனà¯\8d à®µà®¿à®°à¯\81பà¯\8dபதà¯\8dதà¯\87à®°à¯\8dவà¯\81à®\95ளà¯\8d]] à®ªà®\95à¯\8dà®\95தà¯\8dதிலà¯\8d à®\87யà®\99à¯\8dà®\95à¯\81நிலà¯\88யிலà¯\81ளà¯\8dள à®®à®¿à®©à¯\8dனà®\9eà¯\8dà®\9aலà¯\8d à®®à¯\81à®\95வரியà¯\88தà¯\8d à®¤à®°à®¾à®¤போதோ பயனருக்கு மின்னஞ்சல் செய்ய முடியாது.
 
-à®\89à®\99à¯\8dà®\95ளதà¯\81 à®¤à®±à¯\8dபà¯\8bதà¯\88ய à®\90.பி. à®®à¯\81à®\95வரி $3 à®®à®±à¯\8dà®±à¯\81à®®à¯\8d à®¤à®\9fà¯\88 à®\8eணà¯\8d #$5 à®\8eனà¯\8dபவறà¯\8dà®±à¯\88 à®\95à¯\87ளà¯\8dவிà®\95ளà¯\8d à®\95à¯\87à®\9fà¯\8dà®\95à¯\81à®®à¯\8d à®ªà¯\8bதà¯\81 கட்டாயம் குறிப்பிடவும்.',
+à®\87தà¯\88பà¯\8d à®ªà®±à¯\8dறிய à®\89à®\99à¯\8dà®\95ளà¯\8d à®\95à¯\87ளà¯\8dவிà®\95ளà¯\88à®\95à¯\8d à®\95à¯\87à®\9fà¯\8dà®\95à¯\81à®®à¯\8dபà¯\8bதà¯\81 à®\89à®\99à¯\8dà®\95ளதà¯\81 à®¤à®±à¯\8dபà¯\8bதà¯\88ய à®\90.பி. à®®à¯\81à®\95வரி $3 à®®à®±à¯\8dà®±à¯\81à®®à¯\8d à®¤à®\9fà¯\88 à®\8eணà¯\8d #$5 à®\86à®\95ியவறà¯\8dà®±à¯\88à®\95à¯\8d கட்டாயம் குறிப்பிடவும்.',
 'blockednoreason' => 'காரணம் தரப்படவில்லை',
 'whitelistedittext' => 'நீங்கள் பக்கங்களத் தொகுக்க $1 செய்யவேண்டும்.',
 'confirmedittext' => 'நீங்கள் பக்கங்களைத் தொகுக்க முன்னர் மின்னஞ்சல் முகவரியை உறுதிப்படுத்த வேண்டும். உங்கள் [[Special:Preferences|விருப்பத்தேர்வுகள்]] பக்கத்தில் செல்லுபடியான மின்னஞ்சலைக் கொடுத்து அதனை உறுதிப்படுத்துங்கள்.',
@@ -1103,7 +1104,7 @@ $1",
 
 # Preferences page
 'preferences' => 'விருப்பங்கள்',
-'mypreferences' => 'à®\8eனà¯\8d à®µà®¿à®°à¯\81பà¯\8dபதà¯\8dதà¯\87à®°à¯\8dவà¯\81à®\95ளà¯\8d',
+'mypreferences' => 'விருப்பத்தேர்வுகள்',
 'prefs-edits' => 'தொகுப்புகளின் எண்ணிக்கை:',
 'prefsnologin' => 'புகுபதிகை செய்யப்படவில்லை',
 'prefsnologintext' => 'பயனர் விருப்பத்தேர்வுகளை அமைப்பதற்கு நீங்கள் <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} புகுபதிகை ]</span> செய்திருக்க வேண்டும்.',
@@ -1989,7 +1990,7 @@ $1',
 
 # Watchlist
 'watchlist' => 'என் கவனிப்புப் பட்டியல்',
-'mywatchlist' => 'à®\8eனà¯\8d à®\95வனிபà¯\8dபà¯\81பà¯\8d à®ªà®\9fà¯\8dà®\9fியலà¯\8d',
+'mywatchlist' => 'கவனிப்புப் பட்டியல்',
 'watchlistfor2' => '$1 பயனரின் ($2)',
 'nowatchlist' => 'உங்களுடைய கவனிப்புப் பட்டியலில் ஒரு விடயமும் இல்லை.',
 'watchlistanontext' => 'உங்கள் கவனிப்புப் பட்டியலைப் பார்க்க அல்லது தொகுக்க அருள் கூர்ந்து $1 செய்யுங்கள்.',
@@ -2234,7 +2235,7 @@ $1',
 # Contributions
 'contributions' => 'பயனர் பங்களிப்புக்கள்',
 'contributions-title' => '$1 இற்கான பயனர் பங்களிப்புகள்',
-'mycontris' => 'à®\8eனà¯\8d à®ªà®\99à¯\8dà®\95ளிபà¯\8dபà¯\81à®\95à¯\8dà®\95ளà¯\8d',
+'mycontris' => 'பங்களிப்புக்கள்',
 'contribsub2' => '$1 பயனரின் ($2)',
 'nocontribs' => 'இந்த நிபந்தனையுடன் ஒத்துப்போகும் வகையில் மாற்றங்களெதுவும் காணப்படவில்லை.',
 'uctop' => '(மேல்)',
@@ -2275,7 +2276,7 @@ $1',
 'whatlinkshere-hideredirs' => 'வழிமாற்றுகளை $1',
 'whatlinkshere-hidetrans' => 'உள்ளிடப்பட்டவைகளை $1',
 'whatlinkshere-hidelinks' => 'இணைப்புகள் $1',
-'whatlinkshere-hideimages' => '$1உருவ இணைப்புகள்',
+'whatlinkshere-hideimages' => '$1 கோப்பிணைப்புக்கள்',
 'whatlinkshere-filters' => 'வடிகட்டிகள்',
 
 # Block/unblock
@@ -2722,7 +2723,7 @@ $1',
 'pageinfo-watchers' => 'பார்வையாளர்கள் எண்ணிக்கை',
 'pageinfo-firstuser' => 'பக்க உருவாக்குநர்',
 'pageinfo-firsttime' => 'பக்கம் உருவாக்கப்பட்ட காலம்',
-'pageinfo-lastuser' => 'பிநà¯\8dதிய தொகுப்பாளர்',
+'pageinfo-lastuser' => 'à®\85ணà¯\8dà®®à¯\88ய தொகுப்பாளர்',
 'pageinfo-edits' => 'தொகுப்புகளின் எண்ணிக்கை:',
 'pageinfo-authors' => 'சாதகமான அம்சங்களை பெற்றிருக்கும் எழுத்தாளர்கள் எண்ணிக்கை',
 
index 4c08f5c..5894fa9 100644 (file)
@@ -12,6 +12,7 @@
  * @author Jprmvnvijay5
  * @author Kaganer
  * @author Kiranmayee
+ * @author Malkum
  * @author Meno25
  * @author Mpradeep
  * @author Praveen Illa
index d4600e0..c58fd6a 100644 (file)
@@ -156,7 +156,7 @@ $messages = array(
 'cancel' => 'Para',
 'moredotdotdot' => 'Barak liu...',
 'mypage' => "Ha'u-nia pájina",
-'mytalk' => "Ha'u-nia diskusaun",
+'mytalk' => 'Diskusaun',
 'anontalk' => "Diskusaun ba IP ne'e",
 'navigation' => 'Hatudu-dalan',
 'and' => '&#32;ho',
@@ -419,7 +419,7 @@ Ita-nia mudansa la armazenadu seidauk!",
 
 # Preferences page
 'preferences' => 'Preferénsia',
-'mypreferences' => "Ha'u-nia preferénsia",
+'mypreferences' => 'Preferénsia',
 'prefs-rc' => 'Mudansa foufoun sira',
 'prefs-watchlist' => 'Lista hateke',
 'prefs-editing' => 'Edita',
@@ -648,7 +648,7 @@ Ita-nia mudansa la armazenadu seidauk!",
 
 # Watchlist
 'watchlist' => "Ha'u-nia lista hateke",
-'mywatchlist' => "Ha'u-nia lista hateke",
+'mywatchlist' => 'Lista hateke',
 'removedwatchtext' => 'La hateke pájina "[[:$1]]" ona (haree [[Special:Watchlist|"lista hateke"]]).',
 'watch' => 'Hateke',
 'watchthispage' => "Hateke pájina ne'e",
@@ -721,7 +721,7 @@ Ita-nia mudansa la armazenadu seidauk!",
 # Contributions
 'contributions' => "Kontribuisaun uza-na'in",
 'contributions-title' => 'Kontribuisaun "$1" nian',
-'mycontris' => "Ha'u-nia kontribuisaun",
+'mycontris' => 'Kontribuisaun',
 'contribsub2' => 'Ba $1 ($2)',
 'uctop' => '(versaun atuál)',
 'month' => 'Fulan (ho molok):',
index 45104e7..2d932e3 100644 (file)
@@ -195,7 +195,7 @@ $messages = array(
 
 'underline-always' => 'Palagi',
 'underline-never' => 'Hindi magpakailanman',
-'underline-default' => 'Tinakda ng pambasa-basa',
+'underline-default' => 'Tinakda ng pambasa-basa o balat',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Baguhin ang estilong pantitik ng lugar:',
@@ -284,7 +284,7 @@ $messages = array(
 'cancel' => 'Kanselahin',
 'moredotdotdot' => 'Damihan pa...',
 'mypage' => 'Pahina ko',
-'mytalk' => 'Usapan ko',
+'mytalk' => 'Usapan',
 'anontalk' => 'Usapan para sa IP na ito',
 'navigation' => 'Paglilibot (nabigasyon)',
 'and' => ',&#32;at',
@@ -865,7 +865,7 @@ Tandaang gumagamit ang pinasadyang mga pahinang .css at .js ng mga pamagat na ma
 'note' => "'''Paunawa:'''",
 'previewnote' => "'''Tandaan na isa lamang itong paunang tingin.'''
 Hindi pa nasasagip ang mga binago mo!",
-'continue-editing' => 'Ipagpatuloy ang pamamatnugot',
+'continue-editing' => 'Pumunta sa pook ng pamamatnugot',
 'previewconflict' => 'Ipinamamalas ng paunang tinging ito ang teksto sa loob ng pangitaas na pook-patnugutan ng teksto ayon sa lilitaw na anyo nito kapag pinili mo ang pagsagip.',
 'session_fail_preview' => "'''Paumanhin! Hindi namin maproseso ang iyong pagbabago hinggil sa pagkawala ng sesyon ng datos.
 Paki ulit muli. Kung hindi ito gumana, subukang umalis sa pagkalagda at bumalik muli.'''",
@@ -1238,7 +1238,7 @@ Subuking lagyan ng unlapi/paunang ''all:'' upang hanapin ang lahat ng mga nialal
 
 # Preferences page
 'preferences' => 'Mga kagustuhan',
-'mypreferences' => 'Mga nais ko',
+'mypreferences' => 'Mga nais',
 'prefs-edits' => 'Bilang ng mga pagbabago:',
 'prefsnologin' => 'Hindi nakalagda/nakatala',
 'prefsnologintext' => 'Kailangan mong <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} lumagda/tumala]</span> para makapagtakda ng mga kagustuhang ng tagagamit.',
@@ -1299,7 +1299,7 @@ Subuking lagyan ng unlapi/paunang ''all:'' upang hanapin ang lahat ng mga nialal
 'timezoneregion-indian' => 'Karagatang Indyano',
 'timezoneregion-pacific' => 'Karagatang Pasipiko',
 'allowemail' => 'Pahintulutan ang e-liham mula sa ibang mga tagagamit',
-'prefs-searchoptions' => 'Mga pagpipilian para sa paghahanap',
+'prefs-searchoptions' => 'Paghahanap',
 'prefs-namespaces' => 'Mga espasyo ng pangalan',
 'defaultns' => 'O kaya maghanap sa mga pangalan ng espasyong ito:',
 'default' => 'Likas na pagtatakda',
@@ -2446,7 +2446,7 @@ $1',
 # Contributions
 'contributions' => 'Mga ambag ng tagagamit',
 'contributions-title' => 'Mga ambag ng tagagamit na si $1',
-'mycontris' => 'Mga ambag ko',
+'mycontris' => 'Mga ambag',
 'contribsub2' => 'Para kay $1 ($2)',
 'nocontribs' => 'Walang pagbabagong nakita sa binigay na kondisyon.',
 'uctop' => ' (itaas)',
@@ -2984,6 +2984,7 @@ Maaaring dahil ito sa isang kawing sa isang nakatalang hinarang dahil di-kinaisn
 
 # Info page
 'pageinfo-title' => 'Kabatiran para sa "$1"',
+'pageinfo-not-current' => 'Maaari lamang ipakita ang impormasyon para sa kasalukuyang rebisyon.',
 'pageinfo-header-basic' => 'Saligang kabatiran',
 'pageinfo-header-edits' => 'Kasaysayan ng pamamatnugot',
 'pageinfo-header-restrictions' => 'Pruteksiyon ng pahina',
index 143affb..69778c2 100644 (file)
@@ -481,8 +481,8 @@ $messages = array(
 'newwindow' => '(yeni bir pencerede açılır)',
 'cancel' => 'İptal',
 'moredotdotdot' => 'Daha...',
-'mypage' => 'sayfam',
-'mytalk' => 'Mesaj sayfam',
+'mypage' => 'Sayfa',
+'mytalk' => 'Mesaj',
 'anontalk' => "Bu IP'nin iletileri",
 'navigation' => 'Gezinti',
 'and' => '&#32;ve',
@@ -1391,7 +1391,7 @@ Aramanızın başına '''all:''' önekini ekleyerek tüm içeriği aramayı (tar
 
 # Preferences page
 'preferences' => 'Tercihler',
-'mypreferences' => 'Tercihlerim',
+'mypreferences' => 'Tercihler',
 'prefs-edits' => 'Değişiklik sayısı:',
 'prefsnologin' => 'Oturum açık değil',
 'prefsnologintext' => 'Kullanıcı tercihlerinizi ayarlamak için <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} giriş yapmalısınız]</span>.',
@@ -2285,7 +2285,7 @@ Bireysel haklarla ilgili [[{{MediaWiki:Listgrouprights-helppage}}|daha fazla bil
 
 # Watchlist
 'watchlist' => 'İzleme listem',
-'mywatchlist' => 'İzleme listem',
+'mywatchlist' => 'İzleme listesi',
 'watchlistfor2' => '$1 için $2',
 'nowatchlist' => 'İzleme listesinde hiçbir madde bulunmuyor.',
 'watchlistanontext' => 'Lütfen izleme listenizdeki maddeleri görmek ya da değiştirmek için $1.',
@@ -2542,7 +2542,7 @@ $1',
 # Contributions
 'contributions' => 'Kullanıcının katkıları',
 'contributions-title' => '$1 için kullanıcı katkıları',
-'mycontris' => 'Katkılarım',
+'mycontris' => 'Katkılar',
 'contribsub2' => '$1 ($2)',
 'nocontribs' => 'Bu kriterlere uyan değişiklik bulunamadı',
 'uctop' => '(son)',
index db77b87..9866885 100644 (file)
@@ -83,7 +83,7 @@ $messages = array(
 
 'underline-always' => 'Кезээде',
 'underline-never' => 'Кажан-даа',
-'underline-default' => 'Ð\92еб-браузерниң ниити үнези',
+'underline-default' => 'Ð\9aеÑ\88Ñ\82иң Ð°Ð·Ñ\8b Ð²еб-браузерниң ниити үнези',
 
 # Font style option in Special:Preferences
 'editfont-default' => 'Веб-браузерниң ниити үнези',
@@ -158,8 +158,8 @@ $messages = array(
 'newwindow' => '(чаа көзенээ ажыытынар)',
 'cancel' => 'Соксаары',
 'moredotdotdot' => 'Артык...',
-'mypage' => 'Ð\9cÑ\8dÑ\8dÒ£ Ð°Ñ\80Ñ\8bнÑ\8bм',
-'mytalk' => 'Ð\9cÑ\8dÑ\8dÒ£ Ñ\87Ñ\83гаам',
+'mypage' => 'Ð\90Ñ\80Ñ\8bн',
+'mytalk' => 'ЧÑ\83гаа',
 'anontalk' => 'Бо ИП-адрестиң чугаазы',
 'navigation' => 'Навигация',
 'and' => '&#32;болгаш',
@@ -208,7 +208,7 @@ $messages = array(
 'create' => 'Чогаадыры',
 'editthispage' => 'Бо арынны өскертири',
 'create-this-page' => 'Бо арынны чогаадыры',
-'delete' => 'ЫÑ\80адÑ\8bры',
+'delete' => 'ЫÑ\80аары',
 'deletethispage' => 'Бо арынны ырадыры',
 'undelete_short' => '$1 {{PLURAL:$1|эдигни|эдиглерни}} катап үндүрери',
 'viewdeleted_short' => '{{PLURAL:$1|Бир ыраткан өскерлиишкинни|$1 ыраткан өскерлиишкиннерни}} көөрү',
@@ -331,6 +331,7 @@ $messages = array(
 'viewsource' => 'Дөзүн көөрү',
 'actionthrottled' => 'Шеглээн дүрген',
 'sqlhidden' => '(SQL айтырыгны чажырган)',
+'exception-nologin' => 'Кирбес',
 
 # Login and logout pages
 'welcomecreation' => '== Кирип моорлаңар, $1! ==
@@ -386,6 +387,7 @@ Do not forget to change your [[Special:Preferences|{{SITENAME}} preferences]].',
 'resetpass-temp-password' => 'Түр чажыт сөс:',
 
 # Special:PasswordReset
+'passwordreset' => 'Чажыт сөстү дүжүрү',
 'passwordreset-legend' => 'Чажыт атты дүжүр',
 'passwordreset-username' => 'Aжыглакчының ады:',
 'passwordreset-domain' => 'Домен:',
@@ -547,6 +549,7 @@ Please check if you want to create/edit this page.',
 'searchprofile-everything-tooltip' => 'Шупту арыннардан дилээри (сумележиишкиннерден база)',
 'searchprofile-advanced-tooltip' => 'Айыткан аттар делгемнеринден дилээри',
 'search-result-size' => '$1 ({{PLURAL:$2|$2 сөс}})',
+'search-result-category-size' => '{{PLURAL:$1|1 кежигүн|$1 кежигүн}} ({{PLURAL:$2|1 aдаккы бөлүк|$2 aдаккы бөлүк}}, {{PLURAL:$3|1 файл|$3 файл}})',
 'search-redirect' => '($1-н шиглелге)',
 'search-section' => '(«$1» деп салбыр)',
 'search-suggest' => 'Силер «$1» деп бодадыңар чадавас',
@@ -561,7 +564,7 @@ Please check if you want to create/edit this page.',
 
 # Preferences page
 'preferences' => 'Шилилгелер',
-'mypreferences' => 'Ð\9cÑ\8dÑ\8dÒ£ Ñ\88илилгелеÑ\80им',
+'mypreferences' => 'ШилилгелеÑ\80',
 'prefs-edits' => 'Өскерлиишкиннериңерниң саны:',
 'changepassword' => 'Чажыт сөстү өскертири',
 'prefs-skin' => 'Кеш',
@@ -898,7 +901,7 @@ It must not be more than $1 {{PLURAL:$1|character|characters}} long.',
 
 # Watchlist
 'watchlist' => 'Мээң хайгаарал даңзым',
-'mywatchlist' => 'Ð\9cÑ\8dÑ\8dÒ£ Ñ\85айгааÑ\80ал Ð´Ð°Ò£Ð·Ñ\8bм',
+'mywatchlist' => 'ХайгааÑ\80ал Ð´Ð°Ò£Ð·Ñ\8b',
 'watchlistfor2' => '$1, силерге $2',
 'nowatchlist' => 'Силерниң хайгаарал даңзыңар куруг.',
 'watchnologin' => 'Кирбес',
@@ -965,7 +968,7 @@ It must not be more than $1 {{PLURAL:$1|character|characters}} long.',
 # Contributions
 'contributions' => 'Ажыглакчыниң салыышкыннары',
 'contributions-title' => '«$1» деп ажыглакчының салыышкыннары',
-'mycontris' => 'Ð\9cÑ\8dÑ\8dÒ£ Ñ\81алÑ\8bÑ\8bÑ\88кÑ\8bннаÑ\80Ñ\8bм',
+'mycontris' => 'СалÑ\8bÑ\8bÑ\88кÑ\8bннаÑ\80',
 'contribsub2' => '$1 ($2)',
 'uctop' => '(баш)',
 'month' => 'Айдан:',
@@ -996,7 +999,7 @@ It must not be more than $1 {{PLURAL:$1|character|characters}} long.',
 'whatlinkshere-hideredirs' => '$1-че шиглиглер',
 'whatlinkshere-hidetrans' => '$1 даңзылааннар',
 'whatlinkshere-hidelinks' => 'холбааларны $1',
-'whatlinkshere-hideimages' => 'Файлдың холбаалары $1',
+'whatlinkshere-hideimages' => 'Файлдың холбааларын $1',
 'whatlinkshere-filters' => 'Шүүрлер',
 
 # Block/unblock
@@ -1313,4 +1316,6 @@ It must not be more than $1 {{PLURAL:$1|character|characters}} long.',
 'duration-decades' => '$1 {{PLURAL:$1|он хонук|он хонук}}',
 'duration-centuries' => '$1 {{PLURAL:$1|чүс чыл|чүс чыл}}',
 
+# Unknown messages
+'mytalk-parenthetical' => 'чугаалажыры',
 );
index e6cf4ff..b538baf 100644 (file)
@@ -400,7 +400,7 @@ $messages = array(
 
 'underline-always' => 'Завжди',
 'underline-never' => 'Ніколи',
-'underline-default' => 'Використати налаштування браузера',
+'underline-default' => 'Ð\92икоÑ\80иÑ\81Ñ\82овÑ\83ваÑ\82и Ð½Ð°Ð»Ð°Ñ\88Ñ\82Ñ\83ваннÑ\8f Ð±Ñ\80аÑ\83зеÑ\80а',
 
 # Font style option in Special:Preferences
 'editfont-style' => 'Тип шрифту в полі редагування:',
@@ -487,8 +487,8 @@ $messages = array(
 'newwindow' => '(відкривається в новому вікні)',
 'cancel' => 'Скасувати',
 'moredotdotdot' => 'Детальніше…',
-'mypage' => 'Ð\9cоÑ\8f Ð¾Ñ\81обиÑ\81Ñ\82а Ñ\81торінка',
-'mytalk' => 'Ð\9cоÑ\8f Ñ\81Ñ\82оÑ\80Ñ\96нка Ð¾бговорення',
+'mypage' => 'Сторінка',
+'mytalk' => 'Ð\9eбговорення',
 'anontalk' => 'Обговорення для цієї IP-адреси',
 'navigation' => 'Навігація',
 'and' => '&#32;і',
@@ -1434,7 +1434,7 @@ $1",
 # Preferences page
 'preferences' => 'Налаштування',
 'mypreferences' => 'Налаштування',
-'prefs-edits' => 'Ð\9aÑ\96лÑ\8cкÑ\96Ñ\81Ñ\82Ñ\8c редагувань:',
+'prefs-edits' => 'ЧиÑ\81ло редагувань:',
 'prefsnologin' => 'Ви не ввійшли в систему',
 'prefsnologintext' => 'Щоб змінити налаштування користувача, ви повинні <span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} ввійти до системи]</span>.',
 'changepassword' => 'Змінити пароль',
@@ -1670,6 +1670,9 @@ $1",
 'rightslogtext' => 'Це протокол зміни прав користувачів.',
 'rightslogentry' => 'змінив права доступу для користувача $1 з $2 на $3',
 'rightslogentry-autopromote' => 'був автоматично переведений з $2 до $3',
+'logentry-rights-rights' => '$1 {{GENDER:$1|змінив|змінила}} членство в групах для $3 із $4 на $5',
+'logentry-rights-rights-legacy' => '$1 {{GENDER:$1|змінив|змінила}} членство в групах для $3',
+'logentry-rights-autopromote' => '$1 було автоматично переведено із $4 в $5',
 'rightsnone' => '(нема)',
 
 # Associated actions - in the sentence "You do not have permission to X"
@@ -2307,8 +2310,8 @@ $1',
 'linksearch-ns' => 'Простір назв:',
 'linksearch-ok' => 'Знайти',
 'linksearch-text' => 'Можна використовувати підстановочні символи (шаблони), наприклад, "*.wikipedia.org".
-Необхідний домен якнайменше верхнього рівня, наприклад "*.org"<br />
\9fÑ\96дÑ\82Ñ\80имÑ\83ванÑ\96 Ð¿Ñ\80оÑ\82околи: <code>$1</code> (не Ð´Ð¾Ð´Ð°Ð²Ð°Ð¹Ñ\82е Ð¶Ð¾Ð´ÐµÐ½ Ð· Ð½Ð¸Ñ\85 Ñ\83 Ð²Ð°Ñ\88омÑ\83 Ð¿Ð¾Ñ\88Ñ\83кÑ\83)',
+Необхідний домен принаймні верхнього рівня, наприклад "*.org"<br />
\9fÑ\96дÑ\82Ñ\80имÑ\83ванÑ\96 Ð¿Ñ\80оÑ\82околи: <code>$1</code> (за Ð·Ð°Ð¼Ð¾Ð²Ñ\87Ñ\83ваннÑ\8fм http:// Ñ\8fкÑ\89о Ð¶Ð¾Ð´ÐµÐ½ Ð¿Ñ\80оÑ\82окол Ð½Ðµ Ð²ÐºÐ°Ð·Ð°Ð½Ð¾)',
 'linksearch-line' => 'Посилання на $1 із $2',
 'linksearch-error' => 'Підстановочні знаки можуть використовуватися лише на початку адрес.',
 
@@ -2356,11 +2359,11 @@ $1',
 'mailnologin' => 'Відсутня адреса для відправки',
 'mailnologintext' => 'Ви повинні [[Special:UserLogin|ввійти до системи]] і мати підтверджену адресу електронної пошти у ваших [[Special:Preferences|налаштуваннях]], щоб мати змогу надсилати електронну пошту іншим користувачам.',
 'emailuser' => 'Надіслати листа',
-'emailuser-title-target' => 'Надіслати електронного листа користувачеві',
+'emailuser-title-target' => 'Надіслати електронного листа {{GENDER:$1|користувачеві|користувачці}}',
 'emailuser-title-notarget' => 'Надіслати електронного листа користувачеві',
 'emailpage' => 'Лист користувачеві',
-'emailpagetext' => 'Заповнивши наведену нижче форму, можна надіслати повідомлення цьому користувачу.
\95лекÑ\82Ñ\80онна Ð°Ð´Ñ\80еÑ\81а, Ñ\8fкÑ\83 Ð²и зазначили у [[Special:Preferences|своїх налаштуваннях]], буде зазначена в полі «Від кого» листа, тому одержувач матиме можливість відповісти безпосередньо вам.',
+'emailpagetext' => 'Заповнивши наведену нижче форму, можна надіслати повідомлення {{GENDER:$1|цьому користувачу|цій користувачці}}.
\95лекÑ\82Ñ\80онна Ð°Ð´Ñ\80еÑ\81а, Ñ\8fкÑ\83 Ð\92и зазначили у [[Special:Preferences|своїх налаштуваннях]], буде зазначена в полі «Від кого» листа, тому одержувач матиме можливість відповісти безпосередньо вам.',
 'usermailererror' => 'При відправці повідомлення електронної пошти сталася помилка:',
 'defemailsubject' => '{{SITENAME}} - електронний лист від користувача " $1 "',
 'usermaildisabled' => 'Електронне листування між користувачами вимкнене',
@@ -2614,7 +2617,8 @@ $UNWATCHURL
 'undeletedrevisions' => '$1 {{PLURAL:$1|редагування|редагування|редагувань}} відновлено',
 'undeletedrevisions-files' => '$1 {{PLURAL:$1|версія|версії|версій}} та $2 {{PLURAL:$2|файл|файли|файлів}} відновлено',
 'undeletedfiles' => '$1 {{PLURAL:$1|файл|файли|файлів}} відновлено',
-'cannotundelete' => 'Не вдалося скасувати видалення, хтось інший вже міг відмінити видалення сторінки.',
+'cannotundelete' => 'Помилка відновлення:
+$1',
 'undeletedpage' => "'''Сторінка «$1» відновлена'''
 
 Див. [[Special:Log/delete|список вилучень]], щоб дізнатися про останні вилучення та відновлення.",
@@ -2647,7 +2651,7 @@ $1',
 # Contributions
 'contributions' => 'Внесок користувача',
 'contributions-title' => 'Внесок користувача $1',
-'mycontris' => 'Ð\9cÑ\96й Ð²несок',
+'mycontris' => 'Ð\92несок',
 'contribsub2' => 'Внесок $1 ($2)',
 'nocontribs' => 'Редагувань, що задовольняють заданим умовам не знайдено.',
 'uctop' => ' (остання)',
@@ -3192,7 +3196,7 @@ The wiki server can't provide data in a format your client can read.",
 
 # Info page
 'pageinfo-title' => 'Інформація про " $1 "',
-'pageinfo-not-current' => 'Ð\94анÑ\96 Ð¼Ð¾Ð¶Ñ\83Ñ\82Ñ\8c Ð±Ñ\83Ñ\82и Ð¿Ð¾ÐºÐ°Ð·Ð°Ð½Ñ\96 Ð»Ð¸Ñ\88е Ð´Ð»Ñ\8f Ð¿Ð¾Ñ\82оÑ\87ноÑ\97 Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\97',
+'pageinfo-not-current' => 'Ð\92ибаÑ\87Ñ\82е, Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ Ð¿ÐµÑ\80еглÑ\8fнÑ\83Ñ\82и Ñ\86Ñ\8e Ñ\96нÑ\84оÑ\80маÑ\86Ñ\96Ñ\8e Ð´Ð»Ñ\8f Ñ\81Ñ\82аÑ\80иÑ\85 Ð²ÐµÑ\80Ñ\81Ñ\96й.',
 'pageinfo-header-basic' => 'Основна інформація',
 'pageinfo-header-edits' => 'Історія редагувань',
 'pageinfo-header-restrictions' => 'Захист сторінки',
@@ -4208,7 +4212,7 @@ MediaWiki поширюється в надії, що вона буде кори
 'sqlite-no-fts' => '$1 без підтримки повнотекстового пошуку',
 
 # New logging system
-'logentry-delete-delete' => '$1 вилучив сторінку $3',
+'logentry-delete-delete' => '$1 {{GENDER:$2|вилучив|вилучила}} сторінку $3',
 'logentry-delete-restore' => '$1 відновив сторінку $3',
 'logentry-delete-event' => '$1 змінив видимість {{PLURAL:$5 запису журнала|$5 записів журналу}} на $3: $4',
 'logentry-delete-revision' => '$1 змінив видимість {{PLURAL:$5 версії|$5 версій}} на сторінці $3: $4',
index 0e29e0b..73f891a 100644 (file)
@@ -167,7 +167,7 @@ $messages = array(
 'newwindow' => '(yangi oynada ochiladi)',
 'cancel' => 'Bekor qilish',
 'moredotdotdot' => 'Batafsil...',
-'mypage' => 'Shaxsiy sahifa',
+'mypage' => 'Sahifa',
 'mytalk' => 'Suhbatim',
 'anontalk' => 'Bu IP uchun suhbat',
 'navigation' => 'Saytda harakatlanish',
index 3e60870..878c82e 100644 (file)
@@ -429,8 +429,8 @@ $messages = array(
 'newwindow' => '(mở cửa sổ mới)',
 'cancel' => 'Hủy bỏ',
 'moredotdotdot' => 'Thêm nữa…',
-'mypage' => 'Trang của tôi',
-'mytalk' => 'Thảo luận với tôi',
+'mypage' => 'Trang cá nhân',
+'mytalk' => 'Thảo luận',
 'anontalk' => 'Thảo luận với IP này',
 'navigation' => 'Xem nhanh',
 'and' => '&#32;và',
@@ -2294,7 +2294,7 @@ Có [[{{MediaWiki:Listgrouprights-helppage}}|thông tin thêm]] về từng nhó
 
 # Watchlist
 'watchlist' => 'Trang tôi theo dõi',
-'mywatchlist' => 'Trang tôi theo dõi',
+'mywatchlist' => 'Trang theo dõi',
 'watchlistfor2' => 'Của $1 $2',
 'nowatchlist' => 'Danh sách theo dõi của bạn không có gì.',
 'watchlistanontext' => 'Xin hãy $1 để xem hay sửa đổi các trang được theo dõi.',
@@ -2553,7 +2553,7 @@ $1',
 # Contributions
 'contributions' => 'Đóng góp của thành viên',
 'contributions-title' => 'Đóng góp của thành viên $1',
-'mycontris' => 'Đóng góp của tôi',
+'mycontris' => 'Đóng góp',
 'contribsub2' => 'Của $1 ($2)',
 'nocontribs' => 'Không tìm thấy thay đổi nào khớp với yêu cầu.',
 'uctop' => '(mới nhất)',
@@ -4153,4 +4153,6 @@ Nếu không thì bạn có thể điền biểu mẫu đơn giản ở dưới.
 'duration-centuries' => '$1 thế kỷ',
 'duration-millennia' => '$1 thiên niên kỷ',
 
+# Unknown messages
+'mytalk-parenthetical' => 'thảo luận',
 );
index 09beb54..e68ad03 100644 (file)
@@ -317,7 +317,7 @@ $messages = array(
 'cancel' => 'זיי מבטל',
 'moredotdotdot' => 'נאך…',
 'mypage' => 'מײַן בלאט',
-'mytalk' => '×\9eײַ×\9f ×©×\9e×\95עס',
+'mytalk' => 'שמועס',
 'anontalk' => 'דאס רעדן פון דעם IP',
 'navigation' => 'נאַוויגאַציע',
 'and' => '&#32;און',
@@ -2102,7 +2102,7 @@ $1",
 
 # Watchlist
 'watchlist' => 'מיין אויפפַּאסונג ליסטע',
-'mywatchlist' => '×\9e×\99×\99×\9f ×\90×\95×\99פפַּ×\90ס×\95× ×\92 ×\9c×\99ס×\98×¢',
+'mywatchlist' => 'אויפפַּאסונג ליסטע',
 'watchlistfor2' => 'פֿאַר $1 $2',
 'nowatchlist' => 'איר האט נישט קיין שום בלעטער אין אייער אויפפַּאסונג ליסטע.',
 'watchlistanontext' => 'ביטע $1 כדי צו זען אדער ענדערן בלעטער אין אייער אַכטגעבן ליסטע.',
@@ -2352,7 +2352,7 @@ $1',
 # Contributions
 'contributions' => "באניצער'ס בײַשטײַערונגען",
 'contributions-title' => 'בײַשטײַערונגען פֿון באַניצער $1',
-'mycontris' => '×\9eײַנע ×\91ײַש×\98ײַער×\95× ×\92×¢×\9f',
+'mycontris' => 'בײַשטײַערונגען',
 'contribsub2' => 'וועגן $1 ($2)',
 'nocontribs' => 'נישט געטראפן קיין ענדערונגען צוזאמעגעפאסט מיט די קריטעריעס.',
 'uctop' => '(לעצטע)',
@@ -2392,7 +2392,7 @@ $1',
 'whatlinkshere-hideredirs' => '$1 ווײַטערפֿירונגען',
 'whatlinkshere-hidetrans' => '$1 אַריבערשליסונגען',
 'whatlinkshere-hidelinks' => '$1 פֿאַרבינדונגען',
-'whatlinkshere-hideimages' => '$1 ×\91×\99×\9c×\93ער פֿאַרבינדונגען',
+'whatlinkshere-hideimages' => '$1 ×\98עקע פֿאַרבינדונגען',
 'whatlinkshere-filters' => 'פֿילטערס',
 
 # Block/unblock
@@ -2862,6 +2862,7 @@ $1',
 
 # Info page
 'pageinfo-title' => 'אינפֿאָרמאַציע פֿאַר "$1"',
+'pageinfo-not-current' => 'קען ווייזן אינפארמאציע נאר פאר דער לויפיקער רעוויזיע.',
 'pageinfo-header-basic' => 'גרונטלעכע אינפֿארמאַציע',
 'pageinfo-header-edits' => '!רעדאַקטירן היסטאריע',
 'pageinfo-header-restrictions' => 'בלאט באַשיצונג',
@@ -2871,6 +2872,8 @@ $1',
 'pageinfo-length' => 'בלאט לענג (אין בייטן)',
 'pageinfo-article-id' => 'בלאט נומער',
 'pageinfo-robot-policy' => 'זוכמאשין סטאטוס',
+'pageinfo-robot-index' => 'אינדעקסירבאר',
+'pageinfo-robot-noindex' => 'נישט אינדעקסירבאר',
 'pageinfo-views' => 'צאַל קוקן',
 'pageinfo-watchers' => '!צאָל בלאט אויפֿפאַסער',
 'pageinfo-redirects-name' => 'ווײַטערפירונגען צו דעם בלאט',
@@ -3015,6 +3018,11 @@ $1',
 'exif-orientation' => 'אריענטאַציע',
 'exif-samplesperpixel' => 'צאל קאמאפאנענטן',
 'exif-planarconfiguration' => 'דאטן איינארדנונג',
+'exif-xresolution' => 'האריזאנטאלע רעזאלוציע',
+'exif-yresolution' => 'ווערטיקאלע רעזאלוציע',
+'exif-stripoffsets' => 'בילדדאטן פלאציר',
+'exif-rowsperstrip' => 'צאל שורות אין א שטרייף',
+'exif-stripbytecounts' => 'בייטן אין א קאמפרימירטן שטרייף',
 'exif-jpeginterchangeformatlength' => 'בייטן פון JPEG דאטן',
 'exif-datetime' => 'טעקע ענדערונג דאטע און צײַט',
 'exif-imagedescription' => 'בילד טיטל',
index 52c289f..c90ee97 100644 (file)
@@ -390,7 +390,7 @@ $messages = array(
 
 'underline-always' => '总是使用',
 'underline-never' => '从不使用',
-'underline-default' => '浏览器默认',
+'underline-default' => '浏览器默认设置',
 
 # Font style option in Special:Preferences
 'editfont-style' => '编辑区字体样式:',
@@ -475,8 +475,8 @@ $messages = array(
 'newwindow' => '(将于新窗口中打开)',
 'cancel' => '取消',
 'moredotdotdot' => '更多',
-'mypage' => '我的页面',
-'mytalk' => '我的讨论',
+'mypage' => '页面',
+'mytalk' => '讨论',
 'anontalk' => '该IP地址的讨论',
 'navigation' => '导航',
 'and' => '和',
@@ -498,7 +498,7 @@ $messages = array(
 'vector-action-protect' => '保护',
 'vector-action-undelete' => '恢复',
 'vector-action-unprotect' => '更改保护',
-'vector-simplesearch-preference' => '启用简化搜索栏(仅适用Vector皮肤)',
+'vector-simplesearch-preference' => '启用简化搜索栏(仅Vector皮肤)',
 'vector-view-create' => '创建',
 'vector-view-edit' => '编辑',
 'vector-view-history' => '查看历史',
@@ -518,7 +518,7 @@ $messages = array(
 'searcharticle' => '提交',
 'history' => '页面历史',
 'history_short' => '历史',
-'updatedmarker' => 'æ\88\91ä¸\8a次访é\97®ä»¥æ\9d¥ç\9a\84ä¿®æ\94¹',
+'updatedmarker' => 'æ\88\91ä¸\8a次访é\97®ä¹\8bå\90\8eç\9a\84æ\9b´æ\96°',
 'printableversion' => '打印版本',
 'permalink' => '永久链接',
 'print' => '打印',
@@ -1065,9 +1065,12 @@ $2
 'edit-already-exists' => '不可以建立一个新页面。
 它已经存在。',
 'defaultmessagetext' => '默认消息文本',
+'content-failed-to-parse' => '未能将 $2 内容转换为 $1:$3',
 'invalid-content-data' => '无效的内容数据',
+'content-not-allowed-here' => '[[$2]]页面上不允许“$1”内容',
 
 # Content models
+'content-model-wikitext' => 'wiki语法',
 'content-model-text' => '纯文本',
 'content-model-javascript' => 'JavaScript',
 'content-model-css' => 'CSS',
@@ -1339,7 +1342,7 @@ $1",
 
 # Preferences page
 'preferences' => '系统设置',
-'mypreferences' => '我的设置',
+'mypreferences' => '系统设置',
 'prefs-edits' => '编辑数量:',
 'prefsnologin' => '尚未登录',
 'prefsnologintext' => '您必须先<span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} 登录]</span>才能设置个人参数。',
@@ -2484,7 +2487,7 @@ $1',
 # Contributions
 'contributions' => '用户贡献',
 'contributions-title' => '$1的用户贡献',
-'mycontris' => '我的贡献',
+'mycontris' => '贡献记录',
 'contribsub2' => '$1的贡献($2)',
 'nocontribs' => '没有找到符合特征的更改。',
 'uctop' => '(最后更改)',
@@ -2525,7 +2528,7 @@ $1',
 'whatlinkshere-hideredirs' => '$1重定向',
 'whatlinkshere-hidetrans' => '$1包含',
 'whatlinkshere-hidelinks' => '$1链接',
-'whatlinkshere-hideimages' => '$1文件链接',
+'whatlinkshere-hideimages' => '$1文件链接',
 'whatlinkshere-filters' => '过滤器',
 
 # Block/unblock
@@ -3027,7 +3030,7 @@ $1被封禁的理由是:“$2”',
 'pageinfo-subpages-value' => '$1 ($2个重定向;$3个非重定向)',
 'pageinfo-firstuser' => '页面创建者',
 'pageinfo-firsttime' => '页面创建日期',
-'pageinfo-lastuser' => '最近的编者',
+'pageinfo-lastuser' => '最后编辑',
 'pageinfo-lasttime' => '最后编辑的日期',
 'pageinfo-edits' => '总编辑次数',
 'pageinfo-authors' => '不同编者总计',
@@ -3043,6 +3046,7 @@ $1被封禁的理由是:“$2”',
 'pageinfo-contentpage-yes' => '是',
 'pageinfo-protect-cascading' => '从这里开始连锁保护',
 'pageinfo-protect-cascading-yes' => '是',
+'pageinfo-protect-cascading-from' => '保护级联自',
 
 # Skin names
 'skinname-standard' => '标准',
@@ -3083,8 +3087,7 @@ $1',
 'nextdiff' => '下一编辑→',
 
 # Media information
-'mediawarning' => "'''警告''':该文件类型可能包含恶意代码。
-运行它可能对您的系统带来危险。",
+'mediawarning' => "'''警告''':该文件类型可能含有恶意代码。执行后你的系统可能受损。",
 'imagemaxsize' => '图像大小限制:<br /><u>(文件描述页)</u>',
 'thumbsize' => '缩略图大小:',
 'widthheightpage' => '$1×$2,$3页',
@@ -3301,7 +3304,7 @@ Variants for Chinese language
 'exif-worldregiondest' => '世界区域显示',
 'exif-countrydest' => '所示的国家',
 'exif-countrycodedest' => '国家代码',
-'exif-provinceorstatedest' => '省或状态显示',
+'exif-provinceorstatedest' => '省或',
 'exif-citydest' => '所示的城市',
 'exif-sublocationdest' => '显示城市中的详细地点',
 'exif-objectname' => '简称',
@@ -3958,8 +3961,8 @@ MediaWiki是基于使用目的而加以发布,然而不负任何担保责任
 'api-error-unknown-error' => '内部错误:尝试上传文件时出错。',
 'api-error-unknown-warning' => '未知的警告:$1',
 'api-error-unknownerror' => '未知错误:$1。',
-'api-error-uploaddisabled' => '此wiki关闭了上传功能。',
-'api-error-verification-error' => '此文件可能已损坏,或有错误的扩展名。',
+'api-error-uploaddisabled' => '该wiki停用上传。',
+'api-error-verification-error' => '该文件可能损坏或扩展名错误。',
 
 # Durations
 'duration-seconds' => '$1秒',
index df249c1..6b4df4a 100644 (file)
@@ -343,8 +343,8 @@ $messages = array(
 'newwindow' => '(以新視窗開啟)',
 'cancel' => '取消',
 'moredotdotdot' => '更多...',
-'mypage' => '我的頁面',
-'mytalk' => '我的對話頁',
+'mypage' => '頁面',
+'mytalk' => '對話頁',
 'anontalk' => '該IP的對話頁',
 'navigation' => '導覽',
 'and' => '和',
@@ -1242,7 +1242,7 @@ $1",
 
 # Preferences page
 'preferences' => '偏好設定',
-'mypreferences' => '我的偏好設定',
+'mypreferences' => '偏好設定',
 'prefs-edits' => '編輯數量:',
 'prefsnologin' => '還未登入',
 'prefsnologintext' => '您必須先<span class="plainlinks">[{{fullurl:{{#Special:UserLogin}}|returnto=$1}} 登入]</span>才能設置個人參數。',
@@ -2167,7 +2167,7 @@ Template:消除歧義',
 
 # Watchlist
 'watchlist' => '監視列表',
-'mywatchlist' => '我的監視列表',
+'mywatchlist' => '監視列表',
 'watchlistfor2' => '$1的監視列表 $2',
 'nowatchlist' => '您的監視列表為空。',
 'watchlistanontext' => '請$1以檢視或編輯您的監視列表。',
@@ -2421,7 +2421,7 @@ $1',
 # Contributions
 'contributions' => '用戶貢獻',
 'contributions-title' => '$1的用戶貢獻',
-'mycontris' => '我的貢獻',
+'mycontris' => '貢獻',
 'contribsub2' => '$1的貢獻 ($2)',
 'nocontribs' => '沒有找到符合特徵的更改。',
 'uctop' => '(最新修改)',
diff --git a/maintenance/checkAutoLoader.php b/maintenance/checkAutoLoader.php
deleted file mode 100644 (file)
index 8d0e442..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
- * Check the autoloader
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-require_once( __DIR__ . '/Maintenance.php' );
-
-/**
- * Maintenance script to check classes definitions in the autoloader.
- *
- * @ingroup Maintenance
- */
-class CheckAutoLoader extends Maintenance {
-       public function __construct() {
-               parent::__construct();
-               $this->mDescription = "AutoLoader sanity checks";
-       }
-       public function execute() {
-               global $wgAutoloadLocalClasses, $IP;
-               $files = array_unique( $wgAutoloadLocalClasses );
-
-               foreach ( $files as $file ) {
-                       if ( function_exists( 'parsekit_compile_file' ) ) {
-                               $parseInfo = parsekit_compile_file( "$IP/$file" );
-                               $classes = array_keys( $parseInfo['class_table'] );
-                       } else {
-                               $contents = file_get_contents( "$IP/$file" );
-                               $m = array();
-                               preg_match_all( '/\n\s*class\s+([a-zA-Z0-9_]+)/', $contents, $m, PREG_PATTERN_ORDER );
-                               $classes = $m[1];
-                       }
-                       foreach ( $classes as $class ) {
-                               if ( !isset( $wgAutoloadLocalClasses[$class] ) ) {
-                                       // printf( "%-50s Unlisted, in %s\n", $class, $file );
-                                       $this->output( "\t'$class' => '$file',\n" );
-                               } elseif ( $wgAutoloadLocalClasses[$class] !== $file ) {
-                                       $this->output( "$class: Wrong file: found in $file, listed in " . $wgAutoloadLocalClasses[$class] . "\n" );
-                               }
-                       }
-               }
-       }
-}
-
-$maintClass = "CheckAutoLoader";
-require_once( RUN_MAINTENANCE_IF_MAIN );
index 75018de..875b93d 100644 (file)
@@ -38,21 +38,31 @@ class nextJobDB extends Maintenance {
 
        public function execute() {
                global $wgMemc;
+
                $type = $this->getOption( 'type', false );
 
-               $memcKey = 'jobqueue:dbs:v2';
-               $pendingDBs = $wgMemc->get( $memcKey );
+               $memcKey = 'jobqueue:dbs:v3';
+               $pendingDbInfo = $wgMemc->get( $memcKey );
 
                // If the cache entry wasn't present, or in 1% of cases otherwise,
-               // regenerate the cache.
-               if ( !$pendingDBs || mt_rand( 0, 100 ) == 0 ) {
-                       $pendingDBs = $this->getPendingDbs();
-                       $wgMemc->set( $memcKey, $pendingDBs, 300 );
+               // regenerate the cache. Use any available stale cache if another
+               // process is currently regenerating the pending DB information.
+               if ( !$pendingDbInfo || mt_rand( 0, 100 ) == 0 ) {
+                       $lock = $wgMemc->add( 'jobqueue:dbs:v3:lock', 1, 1800 ); // lock
+                       if ( $lock ) {
+                               $pendingDbInfo = array(
+                                       'pendingDBs' => $this->getPendingDbs(),
+                                       'timestamp'  => time()
+                               );
+                               $wgMemc->set( $memcKey, $pendingDbInfo );
+                               $wgMemc->delete( 'jobqueue:dbs:v3:lock' ); // unlock
+                       }
                }
 
-               if ( !$pendingDBs ) {
-                       return;
+               if ( !$pendingDbInfo || !$pendingDbInfo['pendingDBs'] ) {
+                       return; // no DBs with jobs or cache is both empty and locked
                }
+               $pendingDBs = $pendingDbInfo['pendingDBs'];
 
                do {
                        $again = false;
@@ -97,24 +107,17 @@ class nextJobDB extends Maintenance {
         * @return bool
         */
        function checkJob( $type, $dbName ) {
-               global $wgJobTypesExcludedFromDefaultQueue;
-
+               $group = JobQueueGroup::singleton( $dbName );
                if ( $type === false ) {
-                       $lb = wfGetLB( $dbName );
-                       $db = $lb->getConnection( DB_MASTER, array(), $dbName );
-                       $conds = array();
-                       if ( count( $wgJobTypesExcludedFromDefaultQueue ) > 0 ) {
-                               foreach ( $wgJobTypesExcludedFromDefaultQueue as $cmdType ) {
-                                       $conds[] = "job_cmd != " . $db->addQuotes( $cmdType );
+                       foreach ( $group->getDefaultQueueTypes() as $type ) {
+                               if ( !$group->get( $type )->isEmpty() ) {
+                                       return true;
                                }
                        }
-                       $exists = (bool)$db->selectField( 'job', '1', $conds, __METHOD__ );
-                       $lb->reuseConnection( $db );
+                       return false;
                } else {
-                       $exists = !JobQueueGroup::singleton( $dbName )->get( $type )->isEmpty();
+                       return !$group->get( $type )->isEmpty();
                }
-
-               return $exists;
        }
 
        /**
@@ -123,42 +126,15 @@ class nextJobDB extends Maintenance {
         */
        private function getPendingDbs() {
                global $wgLocalDatabases;
-               $pendingDBs = array();
-               # Cross-reference DBs by master DB server
-               $dbsByMaster = array();
-               foreach ( $wgLocalDatabases as $db ) {
-                       $lb = wfGetLB( $db );
-                       $dbsByMaster[$lb->getServerName( 0 )][] = $db;
-               }
-
-               foreach ( $dbsByMaster as $dbs ) {
-                       $dbConn = wfGetDB( DB_MASTER, array(), $dbs[0] );
 
-                       # Padding row for MySQL bug
-                       $pad = str_repeat( '-', 40 );
-                       $sql = "(SELECT '$pad' as db, '$pad' as job_cmd)";
-                       foreach ( $dbs as $wikiId ) {
-                               if ( $sql != '' ) {
-                                       $sql .= ' UNION ';
-                               }
-
-                               list( $dbName, $tablePrefix ) = wfSplitWikiID( $wikiId );
-                               $dbConn->tablePrefix( $tablePrefix );
-                               $jobTable = $dbConn->tableName( 'job' );
-
-                               $sql .= "(SELECT DISTINCT '$wikiId' as db, job_cmd FROM $dbName.$jobTable GROUP BY job_cmd)";
-                       }
-                       $res = $dbConn->query( $sql, __METHOD__ );
-                       $first = true;
-                       foreach ( $res as $row ) {
-                               if ( $first ) {
-                                       // discard padding row
-                                       $first = false;
-                                       continue;
-                               }
-                               $pendingDBs[$row->job_cmd][] = $row->db;
+               $pendingDBs = array(); // (job type => (db list))
+               foreach ( $wgLocalDatabases as $db ) {
+                       $types = JobQueueGroup::singleton( $db )->getQueuesWithJobs();
+                       foreach ( $types as $type ) {
+                               $pendingDBs[$type][] = $db;
                        }
                }
+
                return $pendingDBs;
        }
 }
index 92e7255..7dd2198 100644 (file)
@@ -1,29 +1,23 @@
 .mw-badge {
-       min-width: 8px;
-       height: 14px;
-       border: 1px solid white;
-       -moz-border-radius: 8px;
-       -webkit-border-radius: 8px;
-       border-radius: 8px;
+       min-width: 7px;
+       -moz-border-radius: 2px;
+       -webkit-border-radius: 2px;
+       border-radius: 2px;
        -moz-box-shadow: 0px 1px 4px #ccc;
        -webkit-box-shadow: 0px 1px 4px #ccc;
        box-shadow: 0px 1px 4px #ccc;
-       background-color: #b60a00;
-       background-image: -o-linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
-       background-image: -moz-linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
-       background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #a70802), color-stop(1, #cf0e00));
-       background-image: -webkit-linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
-       background-image: -ms-linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
-       background-image: linear-gradient(bottom, #a70802 0%, #cf0e00 100%);
+       background-color: #cc0000;
        padding: 0 3px;
        text-align: center;
+       font-size: 12px;
+       line-height: 12px;
 }
 
 .mw-badge-content {
-       font-size: 12px;
-       line-height: 14px;
+       font-weight: bold;
        color: white;
-       vertical-align: top;
+       vertical-align: baseline;
+       text-shadow: 0 1px rgba(0, 0, 0, 0.4);
 }
 
 .mw-badge-inline {
index 04495b7..c8073d1 100644 (file)
@@ -1,8 +1,6 @@
 /**
  * jQuery Badge plugin
  *
- * Based on Badger plugin by Daniel Raftery (http://thrivingkings.com/badger).
- *
  * @license MIT
  */
 
  * This program is distributed WITHOUT ANY WARRANTY.
  */
 ( function ( $ ) {
-
        /**
-        * Allows you to put a numeric "badge" on an item on the page.
+        * Allows you to put a "badge" on an item on the page. The badge container
+        * will be appended to the selected element(s).
         * See mediawiki.org/wiki/ResourceLoader/Default_modules#jQuery.badge
         *
-        * @param {string|number} badgeCount An explicit number, or "+n"/ "-n"
-        *  to modify the existing value. If the new value is equal or lower than 0,
-        *  any existing badge will be removed. The badge container will be appended
-        *  to the selected element(s).
-        * @param {Object} options Optional parameters specified below
-        *   type: 'inline' or 'overlay' (default)
-        *   callback: will be called with the number now shown on the badge as a parameter
+        * @param text The value to display in the badge. If the value is falsey (0,
+        *   null, false, '', etc.), any existing badge will be removed.
+        * @param boolean inline True if the badge should be displayed inline, false
+        *   if the badge should overlay the parent element (default is inline)
         */
-       $.fn.badge = function ( badgeCount, options ) {
-               var $badge,
-                       oldBadgeCount,
-                       newBadgeCount,
-                       $existingBadge = this.find( '.mw-badge' );
-
-               options = $.extend( { type : 'overlay' }, options );
-
-               // If there is no existing badge, this will give an empty string
-               oldBadgeCount = Number( $existingBadge.text() );
-               if ( isNaN( oldBadgeCount ) ) {
-                       oldBadgeCount = 0;
-               }
+       $.fn.badge = function ( text, inline ) {
+               var $badge = this.find( '.mw-badge' );
 
-               // If badgeCount is a number, use that as the new badge
-               if ( typeof badgeCount === 'number' ) {
-                       newBadgeCount = badgeCount;
-               } else if ( typeof badgeCount === 'string' ) {
-                       // If badgeCount is "+x", add x to the old badge
-                       if ( badgeCount.charAt(0) === '+' ) {
-                               newBadgeCount = oldBadgeCount + Number( badgeCount.substr(1) );
-                       // If badgeCount is "-x", subtract x from the old badge
-                       } else if ( badgeCount.charAt(0) === '-' ) {
-                               newBadgeCount = oldBadgeCount - Number( badgeCount.substr(1) );
-                       // If badgeCount can be converted into a number, convert it
-                       } else if ( !isNaN( Number( badgeCount ) ) ) {
-                               newBadgeCount = Number( badgeCount );
+               if ( text ) {
+                       // If a badge already exists, reuse it
+                       if ( $badge.length ) {
+                               $badge.find( '.mw-badge-content' ).text( text );
                        } else {
-                               newBadgeCount = 0;
+                               // Otherwise, create a new badge with the specified text and style
+                               $badge = $( '<div class="mw-badge mw-badge-' + ( inline ? 'inline' : 'overlay' ) + '"></div>' )
+                                       .append( $( '<span class="mw-badge-content"></span>' ).text ( text ) )
+                                       .appendTo( this );
                        }
-               // Other types are not supported, fall back to 0.
-               } else {
-                       newBadgeCount = 0;
-               }
-
-               // Badge count must be a whole number
-               newBadgeCount = Math.round( newBadgeCount );
-
-               if ( newBadgeCount <= 0 ) {
-                       // Badges should only exist for values > 0.
-                       $existingBadge.remove();
                } else {
-                       // Don't add duplicates
-                       if ( $existingBadge.length ) {
-                               $badge = $existingBadge;
-                               // Insert the new count into the badge
-                               this.find( '.mw-badge-content' ).text( newBadgeCount );
-                       } else {
-                               // Contruct a new badge with the count
-                               $badge = $( '<div>' )
-                                       .addClass( 'mw-badge' )
-                                       .append(
-                                               $( '<span>' )
-                                                       .addClass( 'mw-badge-content' )
-                                                       .text( newBadgeCount )
-                                       );
-                               this.append( $badge );
-                       }
-
-                       if ( options.type === 'inline' ) {
-                               $badge
-                                       .removeClass( 'mw-badge-overlay' )
-                                       .addClass( 'mw-badge-inline' );
-                       // Default: overlay
-                       } else {
-                               $badge
-                                       .removeClass( 'mw-badge-inline' )
-                                       .addClass( 'mw-badge-overlay' );
-
-                       }
-
-                       // If a callback was specified, call it with the badge count
-                       if ( $.isFunction( options.callback ) ) {
-                               options.callback( newBadgeCount );
-                       }
+                       $badge.remove();
                }
+               return this;
        };
 }( jQuery ) );
index 1990dc0..aced063 100644 (file)
@@ -1,14 +1,16 @@
 /**
  * jQuery checkboxShiftClick
  *
- * This will enable checkboxes to be checked or unchecked in a row by clicking one, holding shift and clicking another one
+ * This will enable checkboxes to be checked or unchecked in a row by clicking one,
+ * holding shift and clicking another one.
  *
- * @author Krinkle <krinklemail@gmail.com>
+ * @author Timo Tijhof, 2011 - 2012
  * @license GPL v2
  */
 ( function ( $ ) {
-       $.fn.checkboxShiftClick = function ( text ) {
-               var prevCheckbox = null, $box = this;
+       $.fn.checkboxShiftClick = function () {
+               var prevCheckbox = null,
+                       $box = this;
                // When our boxes are clicked..
                $box.click( function ( e ) {
                        // And one has been clicked before...
index 24f8959..b35dbbb 100644 (file)
                        // Use the cached version if possible
                        if ( profileCache[nav.userAgent] === undefined ) {
 
-                               /* Configuration */
-
-                               // Name of browsers or layout engines we don't recognize
-                               var uk = 'unknown';
-                               // Generic version digit
-                               var x = 'x';
-                               // Strings found in user agent strings that need to be conformed
-                               var wildUserAgents = ['Opera', 'Navigator', 'Minefield', 'KHTML', 'Chrome', 'PLAYSTATION 3'];
-                               // Translations for conforming user agent strings
-                               var userAgentTranslations = [
-                                       // Tons of browsers lie about being something they are not
-                                       [/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/, ''],
-                                       // Chrome lives in the shadow of Safari still
-                                       ['Chrome Safari', 'Chrome'],
-                                       // KHTML is the layout engine not the browser - LIES!
-                                       ['KHTML', 'Konqueror'],
-                                       // Firefox nightly builds
-                                       ['Minefield', 'Firefox'],
-                                       // This helps keep differnt versions consistent
-                                       ['Navigator', 'Netscape'],
-                                       // This prevents version extraction issues, otherwise translation would happen later
-                                       ['PLAYSTATION 3', 'PS3']
-                               ];
-                               // Strings which precede a version number in a user agent string - combined and used as match 1 in
-                               // version detectection
-                               var versionPrefixes = [
-                                       'camino', 'chrome', 'firefox', 'netscape', 'netscape6', 'opera', 'version', 'konqueror',
-                                       'lynx', 'msie', 'safari', 'ps3'
-                               ];
-                               // Used as matches 2, 3 and 4 in version extraction - 3 is used as actual version number
-                               var versionSuffix = '(\\/|\\;?\\s|)([a-z0-9\\.\\+]*?)(\\;|dev|rel|\\)|\\s|$)';
-                               // Names of known browsers
-                               var names = [
-                                       'camino', 'chrome', 'firefox', 'netscape', 'konqueror', 'lynx', 'msie', 'opera',
-                                       'safari', 'ipod', 'iphone', 'blackberry', 'ps3', 'rekonq'
-                               ];
-                               // Tanslations for conforming browser names
-                               var nameTranslations = [];
-                               // Names of known layout engines
-                               var layouts = ['gecko', 'konqueror', 'msie', 'opera', 'webkit'];
-                               // Translations for conforming layout names
-                               var layoutTranslations = [['konqueror', 'khtml'], ['msie', 'trident'], ['opera', 'presto']];
-                               // Names of supported layout engines for version number
-                               var layoutVersions = ['applewebkit', 'gecko'];
-                               // Names of known operating systems
-                               var platforms = ['win', 'mac', 'linux', 'sunos', 'solaris', 'iphone'];
-                               // Translations for conforming operating system names
-                               var platformTranslations = [['sunos', 'solaris']];
-
-                               /* Methods */
-
-                               /**
-                                * Performs multiple replacements on a string
-                                */
-                               var translate = function ( source, translations ) {
-                                       var i;
-                                       for ( i = 0; i < translations.length; i++ ) {
-                                               source = source.replace( translations[i][0], translations[i][1] );
-                                       }
-                                       return source;
-                               };
-
-                               /* Pre-processing */
-
-                               var     ua = nav.userAgent,
+                               var
+                                       versionNumber,
+
+                                       /* Configuration */
+
+                                       // Name of browsers or layout engines we don't recognize
+                                       uk = 'unknown',
+                                       // Generic version digit
+                                       x = 'x',
+                                       // Strings found in user agent strings that need to be conformed
+                                       wildUserAgents = ['Opera', 'Navigator', 'Minefield', 'KHTML', 'Chrome', 'PLAYSTATION 3'],
+                                       // Translations for conforming user agent strings
+                                       userAgentTranslations = [
+                                               // Tons of browsers lie about being something they are not
+                                               [/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/, ''],
+                                               // Chrome lives in the shadow of Safari still
+                                               ['Chrome Safari', 'Chrome'],
+                                               // KHTML is the layout engine not the browser - LIES!
+                                               ['KHTML', 'Konqueror'],
+                                               // Firefox nightly builds
+                                               ['Minefield', 'Firefox'],
+                                               // This helps keep differnt versions consistent
+                                               ['Navigator', 'Netscape'],
+                                               // This prevents version extraction issues, otherwise translation would happen later
+                                               ['PLAYSTATION 3', 'PS3']
+                                       ],
+                                       // Strings which precede a version number in a user agent string - combined and used as match 1 in
+                                       // version detectection
+                                       versionPrefixes = [
+                                               'camino', 'chrome', 'firefox', 'netscape', 'netscape6', 'opera', 'version', 'konqueror',
+                                               'lynx', 'msie', 'safari', 'ps3'
+                                       ],
+                                       // Used as matches 2, 3 and 4 in version extraction - 3 is used as actual version number
+                                       versionSuffix = '(\\/|\\;?\\s|)([a-z0-9\\.\\+]*?)(\\;|dev|rel|\\)|\\s|$)',
+                                       // Names of known browsers
+                                       names = [
+                                               'camino', 'chrome', 'firefox', 'netscape', 'konqueror', 'lynx', 'msie', 'opera',
+                                               'safari', 'ipod', 'iphone', 'blackberry', 'ps3', 'rekonq'
+                                       ],
+                                       // Tanslations for conforming browser names
+                                       nameTranslations = [],
+                                       // Names of known layout engines
+                                       layouts = ['gecko', 'konqueror', 'msie', 'opera', 'webkit'],
+                                       // Translations for conforming layout names
+                                       layoutTranslations = [ ['konqueror', 'khtml'], ['msie', 'trident'], ['opera', 'presto'] ],
+                                       // Names of supported layout engines for version number
+                                       layoutVersions = ['applewebkit', 'gecko'],
+                                       // Names of known operating systems
+                                       platforms = ['win', 'mac', 'linux', 'sunos', 'solaris', 'iphone'],
+                                       // Translations for conforming operating system names
+                                       platformTranslations = [ ['sunos', 'solaris'] ],
+
+                                       /* Methods */
+
+                                       /**
+                                        * Performs multiple replacements on a string
+                                        */
+                                       translate = function ( source, translations ) {
+                                               var i;
+                                               for ( i = 0; i < translations.length; i++ ) {
+                                                       source = source.replace( translations[i][0], translations[i][1] );
+                                               }
+                                               return source;
+                                       },
+
+                                       /* Pre-processing */
+
+                                       ua = nav.userAgent,
                                        match,
                                        name = uk,
                                        layout = uk,
                                if ( name === 'opera' && version >= 9.8) {
                                        version = ua.match( /version\/([0-9\.]*)/i )[1] || 10;
                                }
-                               var versionNumber = parseFloat( version, 10 ) || 0.0;
+                               versionNumber = parseFloat( version, 10 ) || 0.0;
 
                                /* Caching */
 
                 * @return Boolean true if browser known or assumed to be supported, false if blacklisted
                 */
                test: function ( map, profile ) {
-                       /*jshint evil:true */
+                       /*jshint evil: true */
 
                        var conditions, dir, i, op, val;
                        profile = $.isPlainObject( profile ) ? profile : $.client.profile();
index cb25796..9b8f8fc 100644 (file)
                        }
                        return $settings;
                },
-               handleResize: function ( e ) {
+               /**
+                * @param {jQuery.Event} e
+                */
+               handleResize: function () {
                        $.collapsibleTabs.instances.each( function () {
                                var $el = $( this ),
                                        data = $.collapsibleTabs.getSettings( $el );
index c1fe7fe..9c6f9ec 100644 (file)
                 * @return      Array                   The HSL representation
                 */
                rgbToHsl: function ( R, G, B ) {
-                       var r = R / 255,
+                       var d,
+                               r = R / 255,
                                g = G / 255,
-                               b = B / 255;
-                       var max = Math.max( r, g, b ), min = Math.min( r, g, b );
-                       var h, s, l = (max + min) / 2;
+                               b = B / 255,
+                               max = Math.max( r, g, b ), min = Math.min( r, g, b ),
+                               h,
+                               s,
+                               l = (max + min) / 2;
 
                        if ( max === min ) {
                                // achromatic
                                h = s = 0;
                        } else {
-                               var d = max - min;
+                               d = max - min;
                                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                                switch ( max ) {
                                        case r:
                 * @return      Array                   The RGB representation
                 */
                hslToRgb: function ( h, s, l ) {
-                       var r, g, b;
+                       var r, g, b, hue2rgb, q, p;
 
                        if ( s === 0 ) {
                                r = g = b = l; // achromatic
                        } else {
-                               var hue2rgb = function ( p, q, t ) {
+                               hue2rgb = function ( p, q, t ) {
                                        if ( t < 0 ) {
                                                t += 1;
                                        }
                                        return p;
                                };
 
-                               var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
-                               var p = 2 * l - q;
+                               q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+                               p = 2 * l - q;
                                r = hue2rgb( p, q, h + 1/3 );
                                g = hue2rgb( p, q, h );
                                b = hue2rgb( p, q, h - 1/3 );
index 063f260..9e532e5 100644 (file)
                                context = {
                                        config: {
                                                // callback function for before collapse
-                                               beforeCondense: function ( context ) {},
+                                               beforeCondense: function () {},
 
                                                // callback function for before expand
-                                               beforeExpand: function ( context ) {},
+                                               beforeExpand: function () {},
 
                                                // callback function for after collapse
-                                               afterCondense: function ( context ) {},
+                                               afterCondense: function () {},
 
                                                // callback function for after expand
-                                               afterExpand: function ( context ) {},
+                                               afterExpand: function () {},
 
                                                // Whether the field should expand to the left or the right -- defaults to left
                                                expandToLeft: true
index b7335ff..70bfc4e 100644 (file)
@@ -105,9 +105,7 @@ $.matchSrcSet = function ( devicePixelRatio, srcset ) {
                if ( bits.length > 1 && bits[1].charAt( bits[1].length - 1 ) === 'x' ) {
                        ratioStr = bits[1].substr( 0, bits[1].length - 1 );
                        ratio = parseFloat( ratioStr );
-                       if ( ratio > devicePixelRatio ) {
-                               // Too big, skip!
-                       } else if ( ratio > selectedRatio ) {
+                       if ( ratio <= devicePixelRatio && ratio > selectedRatio ) {
                                selectedRatio = ratio;
                                selectedSrc = src;
                        }
index f720e07..cda2765 100644 (file)
@@ -29,7 +29,7 @@
                                // non latin characters can make regex think a new word has begun: do not use \b
                                // http://stackoverflow.com/questions/3787072/regex-wordwrap-with-utf8-characters-in-js
                                // look for an occurrence of our pattern and store the starting position
-                               match = node.data.match( new RegExp( "(^|\\s)" + $.escapeRE( pat ), "i" ) );
+                               match = node.data.match( new RegExp( '(^|\\s)' + $.escapeRE( pat ), 'i' ) );
                                if ( match ) {
                                        pos = match.index + match[1].length; // include length of any matched spaces
                                        // create the span wrapper for the matched text
index 36b6690..e286834 100644 (file)
@@ -1,12 +1,12 @@
 /**
  * JavaScript to show jump links to motor-impaired users when they are focused.
  */
-jQuery( function( $ ) {
+jQuery( function ( $ ) {
 
-       $('.mw-jump').delegate( 'a', 'focus blur', function( e ) {
-               // Confusingly jQuery leaves e.type as "focusout" for delegated blur events
-               if ( e.type === "blur" || e.type === "focusout" ) {
-                       $( this ).closest( '.mw-jump' ).css({ height: '0' });
+       $( '.mw-jump' ).on( 'focus blur', 'a', function ( e ) {
+               // Confusingly jQuery leaves e.type as focusout for delegated blur events
+               if ( e.type === 'blur' || e.type === 'focusout' ) {
+                       $( this ).closest( '.mw-jump' ).css({ height: 0 });
                } else {
                        $( this ).closest( '.mw-jump' ).css({ height: 'auto' });
                }
index bbffd7b..de39978 100644 (file)
                        return str.charAt( 0 ).toUpperCase() + str.substr( 1 );
                },
                escapeRE: function ( str ) {
-                       return str.replace ( /([\\{}()|.?*+\-\^$\[\]])/g, "\\$1" );
+                       return str.replace ( /([\\{}()|.?*+\-\^$\[\]])/g, '\\$1' );
                },
                isDomElement: function ( el ) {
                        return !!el && !!el.nodeType;
                },
                isEmpty: function ( v ) {
+                       var key;
                        if ( v === '' || v === 0 || v === '0' || v === null
                                || v === false || v === undefined )
                        {
@@ -32,7 +33,7 @@
                                return true;
                        }
                        if ( typeof v === 'object' ) {
-                               for ( var key in v ) {
+                               for ( key in v ) {
                                        return false;
                                }
                                return true;
index 1475af2..ef28948 100644 (file)
@@ -15,7 +15,7 @@
 /*global jQuery, QUnit */
 /*jshint eqeqeq:false, eqnull:false, forin:false */
 ( function ( $ ) {
-       "use strict";
+       'use strict';
 
        var util,
                hasOwn = Object.prototype.hasOwnProperty,
index d80680f..edc18a7 100644 (file)
  *
  * Options:
  *
- * fetch(query): Callback that should fetch suggestions and set the suggestions property. Executed in the context of the
- *             textbox
+ * fetch(query): Callback that should fetch suggestions and set the suggestions property.
+ *      Executed in the context of the textbox
  *             Type: Function
- * cancel: Callback function to call when any pending asynchronous suggestions fetches should be canceled.
- *             Executed in the context of the textbox
+ * cancel: Callback function to call when any pending asynchronous suggestions fetches
+ *      should be canceled. Executed in the context of the textbox
  *             Type: Function
  * special: Set of callbacks for rendering and selecting
  *             Type: Object of Functions 'render' and 'select'
  *             Type: Number, Range: 0 - 1200, Default: 120
  * submitOnClick: Whether to submit the form containing the textbox when a suggestion is clicked
  *             Type: Boolean, Default: false
- * maxExpandFactor: Maximum suggestions box width relative to the textbox width. If set to e.g. 2, the suggestions box
- *             will never be grown beyond 2 times the width of the textbox.
+ * maxExpandFactor: Maximum suggestions box width relative to the textbox width. If set
+ *      to e.g. 2, the suggestions box will never be grown beyond 2 times the width of the textbox.
  *             Type: Number, Range: 1 - infinity, Default: 3
  * expandFrom: Which direction to offset the suggestion box from.
- *      Values 'start' and 'end' translate to left and right respectively depending on the directionality
- *      of the current document, according to $( 'html' ).css( 'direction' ).
+ *      Values 'start' and 'end' translate to left and right respectively depending on the
+ *      directionality of the current document, according to $( 'html' ).css( 'direction' ).
  *      Type: String, default: 'auto', options: 'left', 'right', 'start', 'end', 'auto'.
  * positionFromLeft: Sets expandFrom=left, for backwards compatibility
  *             Type: Boolean, Default: true
@@ -60,18 +60,22 @@ $.suggestions = {
                        context.config.cancel.call( context.data.$textbox );
                }
        },
+
        /**
-        * Restore the text the user originally typed in the textbox, before it was overwritten by highlight(). This
-        * restores the value the currently displayed suggestions are based on, rather than the value just before
+        * Restore the text the user originally typed in the textbox, before it
+        * was overwritten by highlight(). This restores the value the currently
+        * displayed suggestions are based on, rather than the value just before
         * highlight() overwrote it; the former is arguably slightly more sensible.
         */
        restore: function ( context ) {
                context.data.$textbox.val( context.data.prevText );
        },
+
        /**
-        * Ask the user-specified callback for new suggestions. Any previous delayed call to this function still pending
-        * will be canceled. If the value in the textbox is empty or hasn't changed since the last time suggestions were fetched, this
-        * function does nothing.
+        * Ask the user-specified callback for new suggestions. Any previous delayed
+        * call to this function still pending will be canceled. If the value in the
+        * textbox is empty or hasn't changed since the last time suggestions were fetched,
+        * this function does nothing.
         * @param {Boolean} delayed Whether or not to delay this by the currently configured amount of time
         */
        update: function ( context, delayed ) {
@@ -101,6 +105,7 @@ $.suggestions = {
                }
                $.suggestions.special( context );
        },
+
        special: function ( context ) {
                // Allow custom rendering - but otherwise don't do any rendering
                if ( typeof context.config.special.render === 'function' ) {
@@ -112,13 +117,17 @@ $.suggestions = {
                        }, 1 );
                }
        },
+
        /**
         * Sets the value of a property, and updates the widget accordingly
         * @param property String Name of property
         * @param value Mixed Value to set property with
         */
        configure: function ( context, property, value ) {
-               var newCSS;
+               var newCSS,
+                       $autoEllipseMe, $result, $results, $span,
+                       i, expWidth, matchedText, maxWidth, text;
+
                // Validate creation using fallback values
                switch( property ) {
                        case 'fetch':
@@ -212,22 +221,24 @@ $.suggestions = {
                                                }
 
                                                context.data.$container.css( newCSS );
-                                               var $results = context.data.$container.children( '.suggestions-results' );
+                                               $results = context.data.$container.children( '.suggestions-results' );
                                                $results.empty();
-                                               var expWidth = -1;
-                                               var $autoEllipseMe = $( [] );
-                                               var matchedText = null;
-                                               for ( var i = 0; i < context.config.suggestions.length; i++ ) {
+                                               expWidth = -1;
+                                               $autoEllipseMe = $( [] );
+                                               matchedText = null;
+                                               for ( i = 0; i < context.config.suggestions.length; i++ ) {
                                                        /*jshint loopfunc:true */
-                                                       var text = context.config.suggestions[i];
-                                                       var $result = $( '<div>' )
+                                                       text = context.config.suggestions[i];
+                                                       $result = $( '<div>' )
                                                                .addClass( 'suggestions-result' )
                                                                .attr( 'rel', i )
                                                                .data( 'text', context.config.suggestions[i] )
-                                                               .mousemove( function ( e ) {
+                                                               .mousemove( function () {
                                                                        context.data.selectedWithMouse = true;
                                                                        $.suggestions.highlight(
-                                                                               context, $(this).closest( '.suggestions-results div' ), false
+                                                                               context,
+                                                                               $(this).closest( '.suggestions-results div' ),
+                                                                               false
                                                                        );
                                                                } )
                                                                .appendTo( $results );
@@ -246,7 +257,7 @@ $.suggestions = {
 
                                                                // Widen results box if needed
                                                                // New width is only calculated here, applied later
-                                                               var $span = $result.children( 'span' );
+                                                               $span = $result.children( 'span' );
                                                                if ( $span.outerWidth() > $result.width() && $span.outerWidth() > expWidth ) {
                                                                        // factor in any padding, margin, or border space on the parent
                                                                        expWidth = $span.outerWidth() + ( context.data.$container.width() - $span.parent().width());
@@ -256,11 +267,15 @@ $.suggestions = {
                                                }
                                                // Apply new width for results box, if any
                                                if ( expWidth > context.data.$container.width() ) {
-                                                       var maxWidth = context.config.maxExpandFactor*context.data.$textbox.width();
+                                                       maxWidth = context.config.maxExpandFactor*context.data.$textbox.width();
                                                        context.data.$container.width( Math.min( expWidth, maxWidth ) );
                                                }
                                                // autoEllipse the results. Has to be done after changing the width
-                                               $autoEllipseMe.autoEllipsis( { hasSpan: true, tooltip: true, matchText: matchedText } );
+                                               $autoEllipseMe.autoEllipsis( {
+                                                       hasSpan: true,
+                                                       tooltip: true,
+                                                       matchText: matchedText
+                                               } );
                                        }
                                }
                                break;
@@ -280,6 +295,7 @@ $.suggestions = {
                                break;
                }
        },
+
        /**
         * Highlight a result in the results table
         * @param result <tr> to highlight: jQuery object, or 'prev' or 'next'
@@ -338,13 +354,16 @@ $.suggestions = {
                        context.data.$textbox.trigger( 'change' );
                }
        },
+
        /**
         * Respond to keypress event
         * @param key Integer Code of key pressed
         */
        keypress: function ( e, context, key ) {
-               var wasVisible = context.data.$container.is( ':visible' ),
+               var selected,
+                       wasVisible = context.data.$container.is( ':visible' ),
                        preventDefault = false;
+
                switch ( key ) {
                        // Arrow down
                        case 40:
@@ -376,7 +395,7 @@ $.suggestions = {
                        case 13:
                                context.data.$container.hide();
                                preventDefault = wasVisible;
-                               var selected = context.data.$container.find( '.suggestions-result-current' );
+                               selected = context.data.$container.find( '.suggestions-result-current' );
                                if ( selected.length === 0 || context.data.selectedWithMouse ) {
                                        // if nothing is selected OR if something was selected with the mouse,
                                        // cancel any current requests and submit the form
@@ -420,18 +439,18 @@ $.fn.suggestions = function () {
                if ( context === undefined || context === null ) {
                        context = {
                                config: {
-                                       'fetch' : function () {},
-                                       'cancel': function () {},
-                                       'special': {},
-                                       'result': {},
-                                       '$region': $(this),
-                                       'suggestions': [],
-                                       'maxRows': 7,
-                                       'delay': 120,
-                                       'submitOnClick': false,
-                                       'maxExpandFactor': 3,
-                                       'expandFrom': 'auto',
-                                       'highlightInput': false
+                                       fetch: function () {},
+                                       cancel: function () {},
+                                       special: {},
+                                       result: {},
+                                       $region: $(this),
+                                       suggestions: [],
+                                       maxRows: 7,
+                                       delay: 120,
+                                       submitOnClick: false,
+                                       maxExpandFactor: 3,
+                                       expandFrom: 'auto',
+                                       highlightInput: false
                                }
                        };
                }
@@ -480,14 +499,16 @@ $.fn.suggestions = function () {
                                .addClass( 'suggestions' )
                                .append(
                                        $( '<div>' ).addClass( 'suggestions-results' )
-                                               // Can't use click() because the container div is hidden when the textbox loses focus. Instead,
-                                               // listen for a mousedown followed by a mouseup on the same div
+                                               // Can't use click() because the container div is hidden when the
+                                               // textbox loses focus. Instead, listen for a mousedown followed
+                                               // by a mouseup on the same div.
                                                .mousedown( function ( e ) {
                                                        context.data.mouseDownOn = $( e.target ).closest( '.suggestions-results div' );
                                                } )
                                                .mouseup( function ( e ) {
-                                                       var $result = $( e.target ).closest( '.suggestions-results div' );
-                                                       var $other = context.data.mouseDownOn;
+                                                       var $result = $( e.target ).closest( '.suggestions-results div' ),
+                                                               $other = context.data.mouseDownOn;
+
                                                        context.data.mouseDownOn = $( [] );
                                                        if ( $result.get( 0 ) !== $other.get( 0 ) ) {
                                                                return;
@@ -502,14 +523,16 @@ $.fn.suggestions = function () {
                                )
                                .append(
                                        $( '<div>' ).addClass( 'suggestions-special' )
-                                               // Can't use click() because the container div is hidden when the textbox loses focus. Instead,
-                                               // listen for a mousedown followed by a mouseup on the same div
+                                               // Can't use click() because the container div is hidden when the
+                                               // textbox loses focus. Instead, listen for a mousedown followed
+                                               // by a mouseup on the same div.
                                                .mousedown( function ( e ) {
                                                        context.data.mouseDownOn = $( e.target ).closest( '.suggestions-special' );
                                                } )
                                                .mouseup( function ( e ) {
-                                                       var $special = $( e.target ).closest( '.suggestions-special' );
-                                                       var $other = context.data.mouseDownOn;
+                                                       var $special = $( e.target ).closest( '.suggestions-special' ),
+                                                               $other = context.data.mouseDownOn;
+
                                                        context.data.mouseDownOn = $( [] );
                                                        if ( $special.get( 0 ) !== $other.get( 0 ) ) {
                                                                return;
index abb0fa3..17fd0cd 100644 (file)
        }
 
        $.fn.textSelection = function ( command, options ) {
+               var fn,
+                       context,
+                       hasIframe,
+                       needSave,
+                       retval;
 
                /**
                 * Helper function to get an IE TextRange object for an element
@@ -52,7 +57,7 @@
                        }
                }
 
-               var fn = {
+               fn = {
                        /**
                         * Get the contents of the textarea
                         */
                                                        range2.collapse();
                                                        range2.moveStart( 'character', -1 );
                                                        // FIXME: Which check is correct?
-                                                       if ( range2.text !== "\r" && range2.text !== "\n" && range2.text !== "" ) {
-                                                               insertText = "\n" + insertText;
-                                                               pre += "\n";
+                                                       if ( range2.text !== '\r' && range2.text !== '\n' && range2.text !== '' ) {
+                                                               insertText = '\n' + insertText;
+                                                               pre += '\n';
                                                        }
                                                        range3 = document.selection.createRange();
                                                        range3.collapse( false );
                                                        range3.moveEnd( 'character', 1 );
-                                                       if ( range3.text !== "\r" && range3.text !== "\n" && range3.text !== "" ) {
-                                                               insertText += "\n";
-                                                               post += "\n";
+                                                       if ( range3.text !== '\r' && range3.text !== '\n' && range3.text !== '' ) {
+                                                               insertText += '\n';
+                                                               post += '\n';
                                                        }
                                                }
 
                                                        insertText = doSplitLines( selText, pre, post );
                                                }
                                                if ( options.ownline ) {
-                                                       if ( startPos !== 0 && this.value.charAt( startPos - 1 ) !== "\n" && this.value.charAt( startPos - 1 ) !== "\r" ) {
-                                                               insertText = "\n" + insertText;
-                                                               pre += "\n";
+                                                       if ( startPos !== 0 && this.value.charAt( startPos - 1 ) !== '\n' && this.value.charAt( startPos - 1 ) !== '\r' ) {
+                                                               insertText = '\n' + insertText;
+                                                               pre += '\n';
                                                        }
-                                                       if ( this.value.charAt( endPos ) !== "\n" && this.value.charAt( endPos ) !== "\r" ) {
-                                                               insertText += "\n";
-                                                               post += "\n";
+                                                       if ( this.value.charAt( endPos ) !== '\n' && this.value.charAt( endPos ) !== '\r' ) {
+                                                               insertText += '\n';
+                                                               post += '\n';
                                                        }
                                                }
                                                this.value = this.value.substring( 0, startPos ) + insertText +
                                                // Setting this.value scrolls the textarea to the top, restore the scroll position
                                                this.scrollTop = scrollTop;
                                                if ( window.opera ) {
-                                                       pre = pre.replace( /\r?\n/g, "\r\n" );
-                                                       selText = selText.replace( /\r?\n/g, "\r\n" );
-                                                       post = post.replace( /\r?\n/g, "\r\n" );
+                                                       pre = pre.replace( /\r?\n/g, '\r\n' );
+                                                       selText = selText.replace( /\r?\n/g, '\r\n' );
+                                                       post = post.replace( /\r?\n/g, '\r\n' );
                                                }
                                                if ( isSample && options.selectPeri && !options.splitlines ) {
                                                        this.selectionStart = startPos + pre.length;
                         */
                         getCaretPosition: function ( options ) {
                                function getCaret( e ) {
-                                       var caretPos = 0, endPos = 0;
+                                       var caretPos = 0,
+                                               endPos = 0,
+                                               preText, rawPreText, periText,
+                                               rawPeriText, postText, rawPostText,
+                                               // IE Support
+                                               preFinished,
+                                               periFinished,
+                                               postFinished,
+                                               // Range containing text in the selection
+                                               periRange,
+                                               // Range containing text before the selection
+                                               preRange,
+                                               // Range containing text after the selection
+                                               postRange;
+
                                        if ( document.selection && document.selection.createRange ) {
                                                // IE doesn't properly report non-selected caret position through
                                                // the selection ranges when textarea isn't focused. This can
                                                // whatever we do later (bug 31847).
                                                activateElementOnIE( e );
 
-                                               var
-                                                       preText, rawPreText, periText,
-                                                       rawPeriText, postText, rawPostText,
-
-                                                       // IE Support
-                                                       preFinished = false,
-                                                       periFinished = false,
-                                                       postFinished = false,
-                                                       // Range containing text in the selection
-                                                       periRange = document.selection.createRange().duplicate(),
-                                                       // Range containing text before the selection
-                                                       preRange,
-                                                       // Range containing text after the selection
-                                                       postRange;
+                                               preFinished = false;
+                                               periFinished = false;
+                                               postFinished = false;
+                                               periRange = document.selection.createRange().duplicate();
 
                                                preRange = rangeForElementIE( e ),
                                                // Move the end where we need it
                                                                } else {
                                                                        preRange.moveEnd( 'character', -1 );
                                                                        if ( preRange.text === preText ) {
-                                                                               rawPreText += "\r\n";
+                                                                               rawPreText += '\r\n';
                                                                        } else {
                                                                                preFinished = true;
                                                                        }
                                                                } else {
                                                                        periRange.moveEnd( 'character', -1 );
                                                                        if ( periRange.text === periText ) {
-                                                                               rawPeriText += "\r\n";
+                                                                               rawPeriText += '\r\n';
                                                                        } else {
                                                                                periFinished = true;
                                                                        }
                                                                } else {
                                                                        postRange.moveEnd( 'character', -1 );
                                                                        if ( postRange.text === postText ) {
-                                                                               rawPostText += "\r\n";
+                                                                               rawPostText += '\r\n';
                                                                        } else {
                                                                                postFinished = true;
                                                                        }
                                                                }
                                                        }
                                                } while ( ( !preFinished || !periFinished || !postFinished ) );
-                                               caretPos = rawPreText.replace( /\r\n/g, "\n" ).length;
-                                               endPos = caretPos + rawPeriText.replace( /\r\n/g, "\n" ).length;
+                                               caretPos = rawPreText.replace( /\r\n/g, '\n' ).length;
+                                               endPos = caretPos + rawPeriText.replace( /\r\n/g, '\n' ).length;
                                        } else if ( e.selectionStart || e.selectionStart === 0 ) {
                                                // Firefox support
                                                caretPos = e.selectionStart;
                                        return Math.floor( e.scrollWidth / ( $.client.profile().platform === 'linux' ? 7 : 8 ) );
                                }
                                function getCaretScrollPosition( e ) {
-                                       var i, j;
                                        // FIXME: This functions sucks and is off by a few lines most
                                        // of the time. It should be replaced by something decent.
-                                       var text = e.value.replace( /\r/g, '' );
-                                       var caret = $( e ).textSelection( 'getCaretPosition' );
-                                       var lineLength = getLineLength( e );
-                                       var row = 0;
-                                       var charInLine = 0;
-                                       var lastSpaceInLine = 0;
+                                       var i, j,
+                                               nextSpace,
+                                               text = e.value.replace( /\r/g, '' ),
+                                               caret = $( e ).textSelection( 'getCaretPosition' ),
+                                               lineLength = getLineLength( e ),
+                                               row = 0,
+                                               charInLine = 0,
+                                               lastSpaceInLine = 0;
+
                                        for ( i = 0; i < caret; i++ ) {
                                                charInLine++;
                                                if ( text.charAt( i ) === ' ' ) {
                                                        lastSpaceInLine = charInLine;
-                                               } else if ( text.charAt( i ) === "\n" ) {
+                                               } else if ( text.charAt( i ) === '\n' ) {
                                                        lastSpaceInLine = 0;
                                                        charInLine = 0;
                                                        row++;
                                                        }
                                                }
                                        }
-                                       var nextSpace = 0;
+                                       nextSpace = 0;
                                        for ( j = caret; j < caret + lineLength; j++ ) {
                                                if (
                                                        text.charAt( j ) === ' ' ||
-                                                       text.charAt( j ) === "\n" ||
+                                                       text.charAt( j ) === '\n' ||
                                                        caret === text.length
                                                ) {
                                                        nextSpace = j;
                                break;
                }
 
-               var context = $(this).data( 'wikiEditor-context' );
-               var hasIframe = typeof context !== 'undefined' && context && typeof context.$iframe !== 'undefined';
+               context = $(this).data( 'wikiEditor-context' );
+               hasIframe = context !== undefined && context && context.$iframe !== undefined;
 
                // IE selection restore voodoo
-               var needSave = false;
+               needSave = false;
                if ( hasIframe && context.savedSelection !== null ) {
                        context.fn.restoreSelection();
                        needSave = true;
                }
-               var retval = ( hasIframe ? context.fn : fn )[command].call( this, options );
+               retval = ( hasIframe ? context.fn : fn )[command].call( this, options );
                if ( hasIframe && needSave ) {
                        context.fn.saveSelection();
                }
index 1c51c97..2835c9c 100644 (file)
@@ -71,7 +71,7 @@
                 * Apply tagOpen/tagClose to selection in textarea,
                 * use sampleText instead of selection if there is none.
                 */
-               insertTags: function ( tagOpen, tagClose, sampleText, selectText ) {
+               insertTags: function ( tagOpen, tagClose, sampleText ) {
                        if ( currentFocused && currentFocused.length ) {
                                currentFocused.textSelection(
                                        'encapsulateSelection', {
index 10473be..31ca107 100644 (file)
@@ -1,8 +1,36 @@
 /*
 ** Diff rendering
 */
-table.diff, td.diff-otitle, td.diff-ntitle {
+table.diff {
        background-color: white;
+       border: none;
+       border-spacing: 4px;
+       margin: 0;
+       width: 100%;
+       /* Ensure that colums are of equal width */
+       table-layout: fixed;
+}
+
+table.diff td {
+       padding: 0.33em 0.5em;
+}
+
+table.diff td.diff-marker {
+       /* Compensate padding for increased font-size */
+       padding: 0.25em;
+}
+
+table.diff col.diff-marker {
+       width: 2%;
+}
+
+table.diff col.diff-content {
+       width: 48%;
+}
+
+table.diff td div {
+       /* Force-wrap very long lines such as URLs or page-widening char strings */
+       word-wrap: break-word;
 }
 
 td.diff-otitle,
@@ -10,14 +38,14 @@ td.diff-ntitle {
        text-align: center;
 }
 
-td.diff-marker {
-       text-align: right;
+td.diff-lineno {
        font-weight: bold;
-       font-size: 1.25em;
 }
 
-td.diff-lineno {
+td.diff-marker {
+       text-align: right;
        font-weight: bold;
+       font-size: 1.25em;
 }
 
 td.diff-addedline,
@@ -27,10 +55,6 @@ td.diff-context {
        vertical-align: top;
        white-space: -moz-pre-wrap;
        white-space: pre-wrap;
-}
-
-td.diff-addedline,
-td.diff-deletedline {
        border-style: solid;
        border-width: 1px 1px 1px 4px;
        border-radius: 0.33em;
@@ -45,12 +69,9 @@ td.diff-deletedline {
 }
 
 td.diff-context {
-       background: #f3f3f3;
-       color: #333333;
-       border-style: solid;
-       border-width: 1px 1px 1px 4px;
+       background: #f9f9f9;
        border-color: #e6e6e6;
-       border-radius: 0.33em;
+       color: #333333;
 }
 
 .diffchange {
@@ -58,15 +79,6 @@ td.diff-context {
        text-decoration: none;
 }
 
-table.diff {
-       border: none;
-       width: 98%;
-       border-spacing: 4px;
-
-       /* Ensure that colums are of equal width */
-       table-layout: fixed;
-}
-
 td.diff-addedline .diffchange,
 td.diff-deletedline .diffchange {
        border-radius: 0.33em;
@@ -80,25 +92,3 @@ td.diff-addedline .diffchange {
 td.diff-deletedline .diffchange {
        background: #feeec8;
 }
-
-table.diff td {
-       padding: 0.33em 0.66em;
-}
-
-table.diff col.diff-marker {
-       width: 2%;
-}
-
-table.diff col.diff-content {
-       width: 48%;
-}
-
-table.diff td div {
-       /* Force-wrap very long lines such as URLs or page-widening char strings.*/
-       word-wrap: break-word;
-
-       /* As fallback (FF<3.5, Opera <10.5), scrollbars will be added for very wide cells
-          instead of text overflowing or widening
-       */
-       overflow: auto;
-}
index 6660eca..c3023cd 100644 (file)
@@ -1,8 +1,8 @@
 /**
- *  CLDR related utility methods
+ *  CLDR related utility methods.
  */
-( function( mw ) {
-       "use strict";
+( function ( mw ) {
+       'use strict';
 
        var cldr = {
                /**
                 * In case none of the rules passed, we return pluralRules.length
                 * That means it is the "other" form.
                 * @param number
-                * @param pluralRules
-                * @return plural form index
+                * @param {Array} pluralRules
+                * @return {number} plural form index
                 */
-               getPluralForm: function( number, pluralRules ) {
-                       var pluralFormIndex = 0;
-                       for ( pluralFormIndex = 0; pluralFormIndex < pluralRules.length; pluralFormIndex++ ) {
-                               if ( mw.libs.pluralRuleParser( pluralRules[pluralFormIndex], number ) ) {
+               getPluralForm: function ( number, pluralRules ) {
+                       var i;
+                       for ( i = 0; i < pluralRules.length; i++ ) {
+                               if ( mw.libs.pluralRuleParser( pluralRules[i], number ) ) {
                                        break;
                                }
                        }
-                       return pluralFormIndex;
+                       return i;
                }
        };
 
        mw.cldr = cldr;
-} )( mediaWiki );
+
+}( mediaWiki ) );
index 30307a3..937b89b 100644 (file)
@@ -2,7 +2,7 @@
  * Base language object with methods for storing and getting
  * language data.
  */
-( function ( mw, $ ) {
+( function ( mw ) {
 
        var language = {
                /**
@@ -58,4 +58,4 @@
 
        mw.language = language;
 
-}( mediaWiki, jQuery ) );
+}( mediaWiki ) );
index 935d4ff..514dbd5 100644 (file)
@@ -43,12 +43,14 @@ var language = {
         * @param forms array List of plural forms
         * @return string Correct form for quantifier in this language
         */
-       convertPlural: function( count, forms ) {
-               var pluralFormIndex = 0;
+       convertPlural: function ( count, forms ) {
+               var pluralRules,
+                       pluralFormIndex = 0;
+
                if ( !forms || forms.length === 0 ) {
                        return '';
                }
-               var pluralRules = mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'pluralRules' );
+               pluralRules = mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'pluralRules' );
                if ( !pluralRules ) {
                        // default fallback.
                        return ( count === 1 ) ? forms[0] : forms[1];
@@ -78,8 +80,8 @@ var language = {
         * @param {num} number Value to be converted
         * @param {boolean} integer Convert the return value to an integer
         */
-       convertNumber: function( num, integer ) {
-               var i, tmp, transformTable;
+       convertNumber: function ( num, integer ) {
+               var i, tmp, transformTable, numberString, convertedNumber;
 
                if ( !mw.language.digitTransformTable ) {
                        return num;
@@ -97,8 +99,8 @@ var language = {
                        }
                        transformTable = tmp;
                }
-               var numberString = '' + num;
-               var convertedNumber = '';
+               numberString = '' + num;
+               convertedNumber = '';
                for ( i = 0; i < numberString.length; i++ ) {
                        if ( transformTable[ numberString[i] ] ) {
                                convertedNumber += transformTable[numberString[i]];
@@ -121,7 +123,7 @@ var language = {
         *
         * @return string
         */
-       gender: function( gender, forms ) {
+       gender: function ( gender, forms ) {
                if ( !forms || forms.length === 0 ) {
                        return '';
                }
index 370c3a1..684f582 100644 (file)
@@ -1,24 +1,28 @@
-jQuery( document ).ready( function( $ ) {
+( function ( mw, $ ) {
+       $( function () {
+               var $sortableTables;
 
-       /* Emulate placeholder if not supported by browser */
-       if ( !( 'placeholder' in document.createElement( 'input' ) ) ) {
-               $( 'input[placeholder]' ).placeholder();
-       }
+               /* Emulate placeholder if not supported by browser */
+               if ( !( 'placeholder' in document.createElement( 'input' ) ) ) {
+                       $( 'input[placeholder]' ).placeholder();
+               }
 
-       /* Enable makeCollapsible */
-       $( '.mw-collapsible' ).makeCollapsible();
+               /* Enable makeCollapsible */
+               $( '.mw-collapsible' ).makeCollapsible();
 
-       /* Lazy load jquery.tablesorter */
-       if ( $( 'table.sortable' ).length ) {
-               mw.loader.using( 'jquery.tablesorter', function() {
-                       $( 'table.sortable' ).tablesorter();
-               });
-       }
+               /* Lazy load jquery.tablesorter */
+               $sortableTables = $( 'table.sortable' );
+               if ( $sortableTables.length ) {
+                       mw.loader.using( 'jquery.tablesorter', function () {
+                               $sortableTables.tablesorter();
+                       });
+               }
 
-       /* Enable CheckboxShiftClick */
-       $( 'input[type=checkbox]:not(.noshiftselect)' ).checkboxShiftClick();
+               /* Enable CheckboxShiftClick */
+               $( 'input[type=checkbox]:not(.noshiftselect)' ).checkboxShiftClick();
 
-       /* Add accesskey hints to the tooltips */
-       mw.util.updateTooltipAccessKeys();
+               /* Add accesskey hints to the tooltips */
+               mw.util.updateTooltipAccessKeys();
 
-} );
+       } );
+}( mediaWiki, jQuery ) );
index a7e059c..3957493 100644 (file)
                otherAction = action === 'watch' ? 'unwatch' : 'watch';
                accesskeyTip = $link.attr( 'title' ).match( mw.util.tooltipAccessKeyRegexp );
                $li = $link.closest( 'li' );
+
                /**
                 * Trigger a 'watchpage' event for this List item.
                 * Announce the otherAction value as the first param.
                 * Used to monitor the state of watch link.
                 * TODO: Revise when system wide hooks are implemented
                 */
-               if( state === undefined ) {
+               if ( state === undefined ) {
                        $li.trigger( 'watchpage.mw', otherAction );
                }
 
@@ -96,7 +97,7 @@
 
        // Expose local methods
        mw.page.watch = {
-               'updateWatchLink': updateWatchLink
+               updateWatchLink: updateWatchLink
        };
 
        $( document ).ready( function () {
                                        otherAction = action === 'watch' ? 'unwatch' : 'watch';
                                        $li = $link.closest( 'li' );
 
-                                       mw.notify( $.parseHTML( watchResponse.message ), { tag: 'watch-self' } );
+                                       mw.notify( $.parseHTML( watchResponse.message ), {
+                                               tag: 'watch-self'
+                                       } );
 
                                        // Set link to opposite
                                        updateWatchLink( $link, otherAction );
                                        if ( watchResponse.watched !== undefined ) {
                                                $( '#wpWatchthis' ).prop( 'checked', true );
                                        } else {
-                                               $( '#wpWatchthis' ).removeProp( 'checked' );
+                                               $( '#wpWatchthis' ).prop( 'checked', false );
                                        }
                                },
                                // Error
 
                                }
                        );
-               });
-       });
+               } );
+       } );
 
 }( mediaWiki, jQuery ) );
index 6f79929..077adcd 100644 (file)
@@ -1,46 +1,49 @@
-/* JavaScript for Special:Block */
+/**
+ * JavaScript for Special:Block
+ */
+( function ( mw, $ ) {
+       $( function ( $ ) {
 
-jQuery( function( $ ) {
+               var $blockTarget = $( '#mw-bi-target' ),
+                       $anonOnlyRow = $( '#mw-input-wpHardBlock' ).closest( 'tr' ),
+                       $enableAutoblockRow = $( '#mw-input-wpAutoBlock' ).closest( 'tr' ),
+                       $hideUser = $( '#mw-input-wpHideUser' ).closest( 'tr' ),
+                       $watchUser = $( '#mw-input-wpWatch' ).closest( 'tr' );
 
-       var     DO_INSTANT = true,
-               $blockTarget = $( '#mw-bi-target' ),
-               $anonOnlyRow = $( '#mw-input-wpHardBlock' ).closest( 'tr' ),
-               $enableAutoblockRow = $( '#mw-input-wpAutoBlock' ).closest( 'tr' ),
-               $hideUser = $( '#mw-input-wpHideUser' ).closest( 'tr' ),
-               $watchUser = $( '#mw-input-wpWatch' ).closest( 'tr' );
+               function updateBlockOptions( instant ) {
+                       if ( !$blockTarget.length ) {
+                               return;
+                       }
 
-       var updateBlockOptions = function( instant ) {
-               if ( !$blockTarget.length ) {
-                       return;
-               }
-
-               var blocktarget = $.trim( $blockTarget.val() );
-               var isEmpty = ( blocktarget === '' );
-               var isIp = mw.util.isIPv4Address( blocktarget, true ) || mw.util.isIPv6Address( blocktarget, true );
-               var isIpRange = isIp && blocktarget.match( /\/\d+$/ );
+                       var blocktarget = $.trim( $blockTarget.val() ),
+                               isEmpty = blocktarget === '',
+                               isIp = mw.util.isIPv4Address( blocktarget, true ) || mw.util.isIPv6Address( blocktarget, true ),
+                               isIpRange = isIp && blocktarget.match( /\/\d+$/ );
 
-               if ( isIp && !isEmpty ) {
-                       $enableAutoblockRow.goOut( instant );
-                       $hideUser.goOut( instant );
-               } else {
-                       $enableAutoblockRow.goIn( instant );
-                       $hideUser.goIn( instant );
-               }
-               if ( !isIp && !isEmpty ) {
-                       $anonOnlyRow.goOut( instant );
-               } else {
-                       $anonOnlyRow.goIn( instant );
+                       if ( isIp && !isEmpty ) {
+                               $enableAutoblockRow.goOut( instant );
+                               $hideUser.goOut( instant );
+                       } else {
+                               $enableAutoblockRow.goIn( instant );
+                               $hideUser.goIn( instant );
+                       }
+                       if ( !isIp && !isEmpty ) {
+                               $anonOnlyRow.goOut( instant );
+                       } else {
+                               $anonOnlyRow.goIn( instant );
+                       }
+                       if ( isIpRange && !isEmpty ) {
+                               $watchUser.goOut( instant );
+                       } else {
+                               $watchUser.goIn( instant );
+                       }
                }
-               if ( isIpRange && !isEmpty ) {
-                       $watchUser.goOut( instant );
-               } else {
-                       $watchUser.goIn( instant );
-               }
-       };
 
-       // Bind functions so they're checked whenever stuff changes
-       $blockTarget.keyup( updateBlockOptions );
+               // Bind functions so they're checked whenever stuff changes
+               $blockTarget.keyup( updateBlockOptions );
+
+               // Call them now to set initial state (ie. Special:Block/Foobar?wpBlockExpiry=2+hours)
+               updateBlockOptions( /* instant= */ true );
+       } );
+}( mediaWiki, jQuery ) );
 
-       // Call them now to set initial state (ie. Special:Block/Foobar?wpBlockExpiry=2+hours)
-       updateBlockOptions( DO_INSTANT );
-});
index 808d5fe..a560ca9 100644 (file)
@@ -8,7 +8,7 @@
                // (only if a framework was found, not on error pages).
                $( '#mw-javascripttest-summary.mw-javascripttest-frameworkfound' ).append( function () {
 
-                       var     $html = $( '<p><label for="useskin">'
+                       var $html = $( '<p><label for="useskin">'
                                        + mw.message( 'javascripttest-pagetext-skins' ).escaped()
                                        + ' '
                                        + '</label></p>' ),
index 3526cef..8edb1cb 100644 (file)
@@ -1 +1,5 @@
-mw.special = {};
+/*
+ * Namespace for mediawiki.special.* modules
+ */
+
+mediaWiki.special = {};
index 68c2ed0..7a55806 100644 (file)
@@ -1,5 +1,7 @@
-/* JavaScript for Special:MovePage */
+/**
+ * JavaScript for Special:MovePage
+ */
 
 jQuery( function( $ ) {
        $( '#wpReason, #wpNewTitleMain' ).byteLimit();
-});
+} );
index 0804825..989a986 100644 (file)
  * JavaScript for Special:Preferences
  */
 jQuery( document ).ready( function ( $ ) {
-$( '#prefsubmit' ).attr( 'id', 'prefcontrol' );
-var $preftoc = $('<ul id="preftoc"></ul>');
-var $preferences = $( '#preferences' )
-       .addClass( 'jsprefs' )
-       .before( $preftoc );
-
-var $fieldsets = $preferences.children( 'fieldset' )
-       .hide()
-       .addClass( 'prefsection' );
-
-var $legends = $fieldsets.children( 'legend' )
-       .addClass( 'mainLegend' );
-
-/**
- * It uses document.getElementById for security reasons (html injections in
- * jQuery()).
- *
- * @param String name: the name of a tab without the prefix ("mw-prefsection-")
- * @param String mode: [optional] A hash will be set according to the current
- * open section. Set mode 'noHash' to surpress this.
- */
-function switchPrefTab( name, mode ) {
-       var $tab, scrollTop;
-       // Handle hash manually to prevent jumping,
-       // therefore save and restore scrollTop to prevent jumping.
-       scrollTop = $( window ).scrollTop();
-       if ( mode !== 'noHash' ) {
-               window.location.hash = '#mw-prefsection-' + name;
-       }
-       $( window ).scrollTop( scrollTop );
-
-       $preftoc.find( 'li' ).removeClass( 'selected' );
-       $tab = $( document.getElementById( 'preftab-' + name ) );
-       if ( $tab.length ) {
-               $tab.parent().addClass( 'selected' );
-               $preferences.children( 'fieldset' ).hide();
-               $( document.getElementById( 'mw-prefsection-' + name ) ).show();
+       var $preftoc, $preferences, $fieldsets, $legends,
+               hash,
+               $tzSelect, $tzTextbox, $localtimeHolder, servertime;
+
+       $( '#prefsubmit' ).attr( 'id', 'prefcontrol' );
+
+               $preftoc = $('<ul id="preftoc"></ul>'),
+               $preferences = $( '#preferences' )
+                       .addClass( 'jsprefs' )
+                       .before( $preftoc ),
+               $fieldsets = $preferences.children( 'fieldset' )
+                       .hide()
+                       .addClass( 'prefsection' ),
+               $legends = $fieldsets
+                       .children( 'legend' )
+                       .addClass( 'mainLegend' );
+
+       /**
+        * It uses document.getElementById for security reasons (html injections in
+        * jQuery()).
+        *
+        * @param String name: the name of a tab without the prefix ("mw-prefsection-")
+        * @param String mode: [optional] A hash will be set according to the current
+        * open section. Set mode 'noHash' to surpress this.
+        */
+       function switchPrefTab( name, mode ) {
+               var $tab, scrollTop;
+               // Handle hash manually to prevent jumping,
+               // therefore save and restore scrollTop to prevent jumping.
+               scrollTop = $( window ).scrollTop();
+               if ( mode !== 'noHash' ) {
+                       window.location.hash = '#mw-prefsection-' + name;
+               }
+               $( window ).scrollTop( scrollTop );
+
+               $preftoc.find( 'li' ).removeClass( 'selected' );
+               $tab = $( document.getElementById( 'preftab-' + name ) );
+               if ( $tab.length ) {
+                       $tab.parent().addClass( 'selected' );
+                       $preferences.children( 'fieldset' ).hide();
+                       $( document.getElementById( 'mw-prefsection-' + name ) ).show();
+               }
        }
-}
 
-// Populate the prefToc
-$legends.each( function ( i, legend ) {
-       var $legend = $(legend);
-       if ( i === 0 ) {
-               $legend.parent().show();
+       // Populate the prefToc
+       $legends.each( function ( i, legend ) {
+               var $legend = $(legend),
+                       ident, $li, $a;
+               if ( i === 0 ) {
+                       $legend.parent().show();
+               }
+               ident = $legend.parent().attr( 'id' );
+
+               $li = $( '<li>' )
+                       .addClass( i === 0 ? 'selected' : '' );
+               $a = $( '<a>' )
+                       .attr( {
+                               id: ident.replace( 'mw-prefsection', 'preftab' ),
+                               href: '#' + ident
+                       } )
+                       .text( $legend.text() );
+               $li.append( $a );
+               $preftoc.append( $li );
+       } );
+
+       // If we've reloaded the page or followed an open-in-new-window,
+       // make the selected tab visible.
+       hash = window.location.hash;
+       if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
+               switchPrefTab( hash.replace( '#mw-prefsection-' , '' ) );
        }
-       var ident = $legend.parent().attr( 'id' );
-
-       var $li = $( '<li/>', {
-               'class' : ( i === 0 ) ? 'selected' : null
-       });
-       var $a = $( '<a/>', {
-               text : $legend.text(),
-               id : ident.replace( 'mw-prefsection', 'preftab' ),
-               href : '#' + ident
-       });
-       $li.append( $a );
-       $preftoc.append( $li );
-} );
 
-// If we've reloaded the page or followed an open-in-new-window,
-// make the selected tab visible.
-var hash = window.location.hash;
-if ( hash.match( /^#mw-prefsection-[\w-]+/ ) ) {
-       switchPrefTab( hash.replace( '#mw-prefsection-' , '' ) );
-}
-
-// In browsers that support the onhashchange event we will not bind click
-// handlers and instead let the browser do the default behavior (clicking the
-// <a href="#.."> will naturally set the hash, handled by onhashchange.
-// But other things that change the hash will also be catched (e.g. using
-// the Back and Forward browser navigation).
-if ( 'onhashchange' in window ) {
-       $(window).on( 'hashchange' , function () {
-               var hash = window.location.hash;
-               if ( hash.match( /^#mw-prefsection-[\w-]+/ ) ) {
-                       switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
-               } else if ( hash === '' ) {
-                       switchPrefTab( 'personal', 'noHash' );
-               }
-       });
-// In older browsers we'll bind a click handler as fallback.
-// We must not have onhashchange *and* the click handlers, other wise
-// the click handler calls switchPrefTab() which sets the hash value,
-// which triggers onhashcange and calls switchPrefTab() again.
-} else {
-       $preftoc.on( 'click', 'li a', function ( e ) {
-               switchPrefTab( $( this ).attr( 'href' ).replace( '#mw-prefsection-', '' ) );
-               e.preventDefault();
-       });
-}
-
-/**
-* Timezone functions.
-* Guesses Timezone from browser and updates fields onchange
-*/
-
-var $tzSelect = $( '#mw-input-wptimecorrection' );
-var $tzTextbox = $( '#mw-input-wptimecorrection-other' );
-
-var $localtimeHolder = $( '#wpLocalTime' );
-var servertime = parseInt( $( 'input[name=wpServerTime]' ).val(), 10 );
-var minuteDiff = 0;
-
-var minutesToHours = function ( min ) {
-       var tzHour = Math.floor( Math.abs( min ) / 60 );
-       var tzMin = Math.abs( min ) % 60;
-       var tzString = ( ( min >= 0 ) ? '' : '-' ) + ( ( tzHour < 10 ) ? '0' : '' ) + tzHour +
-               ':' + ( ( tzMin < 10 ) ? '0' : '' ) + tzMin;
-       return tzString;
-};
-
-var hoursToMinutes = function ( hour ) {
-       var arr = hour.split( ':' );
-       arr[0] = parseInt( arr[0], 10 );
-
-       var minutes;
-       if ( arr.length == 1 ) {
-               // Specification is of the form [-]XX
-               minutes = arr[0] * 60;
+       // In browsers that support the onhashchange event we will not bind click
+       // handlers and instead let the browser do the default behavior (clicking the
+       // <a href="#.."> will naturally set the hash, handled by onhashchange.
+       // But other things that change the hash will also be catched (e.g. using
+       // the Back and Forward browser navigation).
+       if ( 'onhashchange' in window ) {
+               $(window).on( 'hashchange' , function () {
+                       var hash = window.location.hash;
+                       if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
+                               switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
+                       } else if ( hash === '' ) {
+                               switchPrefTab( 'personal', 'noHash' );
+                       }
+               });
+       // In older browsers we'll bind a click handler as fallback.
+       // We must not have onhashchange *and* the click handlers, other wise
+       // the click handler calls switchPrefTab() which sets the hash value,
+       // which triggers onhashcange and calls switchPrefTab() again.
        } else {
-               // Specification is of the form [-]XX:XX
-               minutes = Math.abs( arr[0] ) * 60 + parseInt( arr[1], 10 );
-               if ( arr[0] < 0 ) {
-                       minutes *= -1;
-               }
+               $preftoc.on( 'click', 'li a', function ( e ) {
+                       switchPrefTab( $( this ).attr( 'href' ).replace( '#mw-prefsection-', '' ) );
+                       e.preventDefault();
+               });
        }
-       // Gracefully handle non-numbers.
-       if ( isNaN( minutes ) ) {
-               return 0;
-       } else {
-               return minutes;
+
+       /**
+       * Timezone functions.
+       * Guesses Timezone from browser and updates fields onchange
+       */
+
+       $tzSelect = $( '#mw-input-wptimecorrection' );
+       $tzTextbox = $( '#mw-input-wptimecorrection-other' );
+       $localtimeHolder = $( '#wpLocalTime' );
+       servertime = parseInt( $( 'input[name="wpServerTime"]' ).val(), 10 );
+
+       function minutesToHours( min ) {
+               var tzHour = Math.floor( Math.abs( min ) / 60 ),
+                       tzMin = Math.abs( min ) % 60,
+                       tzString = ( ( min >= 0 ) ? '' : '-' ) + ( ( tzHour < 10 ) ? '0' : '' ) + tzHour +
+                               ':' + ( ( tzMin < 10 ) ? '0' : '' ) + tzMin;
+               return tzString;
        }
-};
-
-var updateTimezoneSelection = function () {
-       var type = $tzSelect.val();
-       if ( type == 'guess' ) {
-               // Get browser timezone & fill it in
-               minuteDiff = -new Date().getTimezoneOffset();
-               $tzTextbox.val( minutesToHours( minuteDiff ) );
-               $tzSelect.val( 'other' );
-               $tzTextbox.get( 0 ).disabled = false;
-       } else if ( type == 'other' ) {
-               // Grab data from the textbox, parse it.
-               minuteDiff = hoursToMinutes( $tzTextbox.val() );
-       } else {
-               // Grab data from the $tzSelect value
-               minuteDiff = parseInt( type.split( '|' )[1], 10 ) || 0;
-               $tzTextbox.val( minutesToHours( minuteDiff ) );
+
+       function hoursToMinutes( hour ) {
+               var minutes,
+                       arr = hour.split( ':' );
+
+               arr[0] = parseInt( arr[0], 10 );
+
+               if ( arr.length === 1 ) {
+                       // Specification is of the form [-]XX
+                       minutes = arr[0] * 60;
+               } else {
+                       // Specification is of the form [-]XX:XX
+                       minutes = Math.abs( arr[0] ) * 60 + parseInt( arr[1], 10 );
+                       if ( arr[0] < 0 ) {
+                               minutes *= -1;
+                       }
+               }
+               // Gracefully handle non-numbers.
+               if ( isNaN( minutes ) ) {
+                       return 0;
+               } else {
+                       return minutes;
+               }
        }
 
-       // Determine local time from server time and minutes difference, for display.
-       var localTime = servertime + minuteDiff;
+       function updateTimezoneSelection () {
+               var minuteDiff, localTime,
+                       type = $tzSelect.val();
+
+               if ( type === 'guess' ) {
+                       // Get browser timezone & fill it in
+                       minuteDiff = -( new Date().getTimezoneOffset() );
+                       $tzTextbox.val( minutesToHours( minuteDiff ) );
+                       $tzSelect.val( 'other' );
+                       $tzTextbox.prop( 'disabled', false );
+               } else if ( type === 'other' ) {
+                       // Grab data from the textbox, parse it.
+                       minuteDiff = hoursToMinutes( $tzTextbox.val() );
+               } else {
+                       // Grab data from the $tzSelect value
+                       minuteDiff = parseInt( type.split( '|' )[1], 10 ) || 0;
+                       $tzTextbox.val( minutesToHours( minuteDiff ) );
+               }
 
-       // Bring time within the [0,1440) range.
-       while ( localTime < 0 ) {
-               localTime += 1440;
+               // Determine local time from server time and minutes difference, for display.
+               localTime = servertime + minuteDiff;
+
+               // Bring time within the [0,1440) range.
+               while ( localTime < 0 ) {
+                       localTime += 1440;
+               }
+               while ( localTime >= 1440 ) {
+                       localTime -= 1440;
+               }
+               $localtimeHolder.text( minutesToHours( localTime ) );
        }
-       while ( localTime >= 1440 ) {
-               localTime -= 1440;
+
+       if ( $tzSelect.length && $tzTextbox.length ) {
+               $tzSelect.change( updateTimezoneSelection );
+               $tzTextbox.blur( updateTimezoneSelection );
+               updateTimezoneSelection();
        }
-       $localtimeHolder.text( minutesToHours( localTime ) );
-};
-
-if ( $tzSelect.length && $tzTextbox.length ) {
-       $tzSelect.change( function () { updateTimezoneSelection(); } );
-       $tzTextbox.blur( function () { updateTimezoneSelection(); } );
-       updateTimezoneSelection();
-}
 } );
index 7996d93..3cba9d3 100644 (file)
@@ -1,14 +1,12 @@
-/* JavaScript for Special:RecentChanges */
+/**
+ * JavaScript for Special:RecentChanges
+ */
 ( function ( mw, $ ) {
+       var rc,
+               $checkboxes,
+               $select;
 
-       var checkboxes = [ 'nsassociated', 'nsinvert' ];
-
-       /**
-        * @var select {jQuery}
-        */
-       var $select = null;
-
-       var rc = mw.special.recentchanges = {
+       rc = {
 
                /**
                 * Handler to disable/enable the namespace selector checkboxes when the
                 */
                updateCheckboxes: function () {
                        // The option element for the 'all' namespace has an empty value
-                       var isAllNS = $select.find('option:selected').val() === '';
+                       var isAllNS = $select.find( 'option:selected' ).val() === '';
 
                        // Iterates over checkboxes and propagate the selected option
-                       $.each( checkboxes, function ( i, id ) {
-                               $( '#' + id ).prop( 'disabled', isAllNS );
-                       });
+                       $checkboxes.prop( 'disabled', isAllNS );
                },
 
                init: function () {
-                       // Populate
                        $select = $( '#namespace' );
+                       $checkboxes = $( '#nsassociated, #nsinvert' );
 
                        // Bind to change event, and trigger once to set the initial state of the checkboxes.
-                       $select.change( rc.updateCheckboxes ).change();
+                       rc.updateCheckboxes();
+                       $select.change( rc.updateCheckboxes );
                }
        };
 
-       // Run when document is ready
        $( rc.init );
 
+       mw.special.recentchanges = rc;
+
 }( mediaWiki, jQuery ) );
index 04954e8..0cca26d 100644 (file)
@@ -1,49 +1,53 @@
 /*
  * JavaScript for Special:Search
  */
-( function( $, mw ) { $( function() {
+( function ( $, mw ) {
+       $( function () {
+               var $checkboxes, $headerLinks;
 
-// Emulate HTML5 autofocus behavior in non HTML5 compliant browsers
-if ( !( 'autofocus' in document.createElement( 'input' ) ) ) {
-       $( 'input[autofocus]:first' ).focus();
-}
+               // Emulate HTML5 autofocus behavior in non HTML5 compliant browsers
+               if ( !( 'autofocus' in document.createElement( 'input' ) ) ) {
+                       $( 'input[autofocus]' ).eq( 0 ).focus();
+               }
 
-// Create check all/none button
-var $checkboxes = $('#powersearch input[id^=mw-search-ns]');
-$('#mw-search-togglebox').append(
-       $('<label />')
-               .text(mw.msg('powersearch-togglelabel'))
-).append(
-       $('<input type="button" />')
-               .attr('id', 'mw-search-toggleall')
-               .attr('value', mw.msg('powersearch-toggleall'))
-               .click( function() {
-                       $checkboxes.prop('checked', true);
-               } )
-).append(
-       $('<input type="button" />')
-               .attr('id', 'mw-search-togglenone')
-               .attr('value', mw.msg('powersearch-togglenone'))
-               .click( function() {
-                       $checkboxes.prop('checked', false);
-               } )
-);
+               // Create check all/none button
+               $checkboxes = $('#powersearch input[id^=mw-search-ns]');
+               $('#mw-search-togglebox').append(
+                       $('<label>')
+                               .text(mw.msg('powersearch-togglelabel'))
+               ).append(
+                       $('<input type="button" />')
+                               .attr( 'id', 'mw-search-toggleall' )
+                               .prop( 'value', mw.msg('powersearch-toggleall' ) )
+                               .click( function () {
+                                       $checkboxes.prop('checked', true);
+                               } )
+               ).append(
+                       $('<input type="button" />')
+                               .attr( 'id', 'mw-search-togglenone' )
+                               .prop( 'value', mw.msg('powersearch-togglenone' ) )
+                               .click( function() {
+                                       $checkboxes.prop( 'checked', false );
+                               } )
+               );
 
-// Change the header search links to what user entered
-var headerLinks = $('.search-types a');
-$('#searchText, #powerSearchText').change(function() {
-       var searchterm = $(this).val();
-       headerLinks.each( function() {
-               var parts = $(this).attr('href').split( 'search=' );
-               var lastpart = '';
-               var prefix = 'search=';
-               if( parts.length > 1 && parts[1].indexOf('&') >= 0 ) {
-                       lastpart = parts[1].substring( parts[1].indexOf('&') );
-               } else {
-                       prefix = '&search=';
-               }
-               this.href = parts[0] + prefix + encodeURIComponent( searchterm ) + lastpart;
-       });
-}).trigger('change');
+               // Change the header search links to what user entered
+               $headerLinks = $( '.search-types a' );
+               $( '#searchText, #powerSearchText' ).change( function () {
+                       var searchterm = $(this).val();
+                       $headerLinks.each( function () {
+                               var parts = $(this).attr('href').split( 'search=' ),
+                                       lastpart = '',
+                                       prefix = 'search=';
+                               if ( parts.length > 1 && parts[1].indexOf('&') >= 0 ) {
+                                       lastpart = parts[1].substring( parts[1].indexOf('&') );
+                               } else {
+                                       prefix = '&search=';
+                               }
+                               this.href = parts[0] + prefix + encodeURIComponent( searchterm ) + lastpart;
+                       });
+               }).trigger( 'change' );
+
+       } );
 
-} ); } )( jQuery, mediaWiki );
+}( jQuery, mediaWiki ) );
index 33b8027..c6e5d61 100644 (file)
@@ -1,10 +1,11 @@
 /*
  * JavaScript for Specical:Undelete
  */
-jQuery( document ).ready( function( $ ) {
-       $( '#mw-undelete-invert' ).click( function( e ) {
+jQuery( document ).ready( function ( $ ) {
+       $( '#mw-undelete-invert' ).click( function ( e ) {
                e.preventDefault();
-               $( '#undelete' ).find( 'input:checkbox' )
-                       .prop( 'checked', function( i, val ) { return !val; } );
+               $( '#undelete input[type="checkbox"]' ).prop( 'checked', function ( i, val ) {
+                       return !val;
+               } );
        } );
 } );
index 63e8971..b05fd71 100644 (file)
@@ -11,7 +11,7 @@
                 * Is the FileAPI available with sufficient functionality?
                 */
                function hasFileAPI() {
-                       return typeof window.FileReader !== 'undefined';
+                       return window.FileReader !== undefined;
                }
 
                /**
                 * @param {File} file
                 */
                function showPreview( file ) {
-                       var     previewSize = 180,
+                       var $canvas,
+                               ctx,
+                               meta,
+                               previewSize = 180,
                                thumb = $( '<div id="mw-upload-thumbnail" class="thumb tright">' +
                                                        '<div class="thumbinner">' +
                                                                '<div class="mw-small-spinner" style="width: 180px; height: 180px"></div>' +
                                                                '<div class="thumbcaption"><div class="filename"></div><div class="fileinfo"></div></div>' +
                                                        '</div>' +
                                                '</div>' );
+
                        thumb.find( '.filename' ).text( file.name ).end()
                                .find( '.fileinfo' ).text( prettySize( file.size ) ).end();
 
-                       var     $canvas = $('<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>'),
-                               ctx = $canvas[0].getContext( '2d' );
+                       $canvas = $('<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>');
+                       ctx = $canvas[0].getContext( '2d' );
                        $( '#mw-htmlform-source' ).parent().prepend( thumb );
 
-                       var meta;
-                       fetchPreview( file, function( dataURL ) {
+                       fetchPreview( file, function ( dataURL ) {
                                var     img = new Image(),
                                        rotation = 0;
 
@@ -79,7 +82,8 @@
                                }
 
                                img.onload = function () {
-                                       var width, height, x, y, dx, dy, logicalWidth, logicalHeight;
+                                       var info, width, height, x, y, dx, dy, logicalWidth, logicalHeight;
+
                                        // Fit the image within the previewSizexpreviewSize box
                                        if ( img.width > img.height ) {
                                                width = previewSize;
                                        thumb.find('.mw-small-spinner').replaceWith($canvas);
 
                                        // Image size
-                                       var info = mw.msg( 'widthheight', logicalWidth, logicalHeight ) +
+                                       info = mw.msg( 'widthheight', logicalWidth, logicalHeight ) +
                                                ', ' + prettySize( file.size );
+
                                        $( '#mw-upload-thumbnail .fileinfo' ).text( info );
                                };
                                img.src = dataURL;
                        }, mw.config.get( 'wgFileCanRotate' ) ? function ( data ) {
+                               /*jshint camelcase: false, nomen: false */
                                try {
                                        meta = mw.libs.jpegmeta( data, file.fileName );
                                        meta._binary_data = null;
                                // However, our JPEG metadata library wants a string.
                                // So, this is going to be an ugly conversion.
                                reader.onload = function() {
-                                       var buffer = new Uint8Array( reader.result ),
+                                       var i,
+                                               buffer = new Uint8Array( reader.result ),
                                                string = '';
-                                       for ( var i = 0; i < buffer.byteLength; i++ ) {
+                                       for ( i = 0; i < buffer.byteLength; i++ ) {
                                                string += String.fromCharCode( buffer[i] );
                                        }
                                        callbackBinary( string );
                        } else {
                                // This ends up decoding the file to base-64 and back again, which
                                // feels horribly inefficient.
-                               reader.onload = function() {
+                               reader.onload = function () {
                                        callback( reader.result );
                                };
                                reader.readAsDataURL( file );
                 * Check if the file does not exceed the maximum size
                 */
                function checkMaxUploadSize( file ) {
+                       var maxSize, $error;
+
                        function getMaxUploadSize( type ) {
                                var sizes = mw.config.get( 'wgMaxUploadSize' );
+
                                if ( sizes[type] !== undefined ) {
                                        return sizes[type];
                                }
                                return sizes['*'];
                        }
+
                        $( '.mw-upload-source-error' ).remove();
 
-                       var maxSize = getMaxUploadSize( 'file' );
+                       maxSize = getMaxUploadSize( 'file' );
                        if ( file.size > maxSize ) {
-                               var error = $( '<p class="error mw-upload-source-error" id="wpSourceTypeFile-error">' +
-                                               mw.message( 'largefileserver', file.size, maxSize ).escaped() + '</p>' );
-                               $( '#wpUploadFile' ).after( error );
+                               $error = $( '<p class="error mw-upload-source-error" id="wpSourceTypeFile-error">' +
+                                       mw.message( 'largefileserver', file.size, maxSize ).escaped() + '</p>' );
+
+                               $( '#wpUploadFile' ).after( $error );
+
                                return false;
                        }
+
                        return true;
                }
 
         * Disable all upload source fields except the selected one
         */
        $( function ( $ ) {
-               var i, row,
-                       rows = $( '.mw-htmlform-field-UploadSourceField' );
-               for ( i = rows.length; i; i-- ) {
-                       row = rows[i - 1];
-                       $( 'input[name="wpSourceType"]', row ).change( ( function () {
-                               var currentRow = row; // Store current row in our own scope
-                               return function () {
-                                       $( '.mw-upload-source-error' ).remove();
-                                       if ( this.checked ) {
-                                               // Disable all inputs
-                                               $( 'input[name!="wpSourceType"]', rows ).prop( 'disabled', true );
-                                               // Re-enable the current one
-                                               $( 'input', currentRow ).prop( 'disabled', false );
-                                       }
-                               };
-                       }() ) );
+               var i, $row,
+                       $rows = $( '.mw-htmlform-field-UploadSourceField' );
+
+               function createHandler( $currentRow ) {
+                       /**
+                        * @param {jQuery.Event}
+                        */
+                       return function () {
+                               $( '.mw-upload-source-error' ).remove();
+                               if ( this.checked ) {
+                                       // Disable all inputs
+                                       $rows.find( 'input[name!="wpSourceType"]' ).prop( 'disabled', true );
+                                       // Re-enable the current one
+                                       $currentRow.find( 'input' ).prop( 'disabled', false );
+                               }
+                       };
+               }
+
+               for ( i = $rows.length; i; i-- ) {
+                       $row = $rows.eq(i - 1);
+                       $row
+                               .find( 'input[name="wpSourceType"]' )
+                               .change( createHandler( $row ) );
                }
        } );
 
index 33cca58..dad6021 100644 (file)
@@ -133,11 +133,11 @@ var
                // In normal browsers the match-array contains null/undefined if there's no match,
                // IE returns an empty string.
                var matches = s.match( /^(?:([^:]+):)?(.*?)(?:\.(\w+))?$/ ),
-                       ns_match = getNsIdByName( matches[1] );
+                       nsMatch = getNsIdByName( matches[1] );
 
                // Namespace must be valid, and title must be a non-empty string.
-               if ( ns_match && typeof matches[2] === 'string' && matches[2] !== '' ) {
-                       title.ns = ns_match;
+               if ( nsMatch && typeof matches[2] === 'string' && matches[2] !== '' ) {
+                       title.ns = nsMatch;
                        title.name = fixName( matches[2] );
                        if ( typeof matches[3] === 'string' && matches[3] !== '' ) {
                                title.ext = fixExt( matches[3] );
index 634d02b..1afe51e 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * mediawiki.Feedback
+ * mediawiki.feedback
  *
  * @author Ryan Kaldari, 2010
  * @author Neil Kandalgaonkar, 2010-11
 
        mw.Feedback.prototype = {
                setup: function () {
-                       var fb = this;
+                       var $feedbackPageLink,
+                               $bugNoteLink,
+                               $bugsListLink,
+                               fb = this;
 
-                       var $feedbackPageLink = $( '<a>' )
-                               .attr( { 'href': fb.title.getUrl(), 'target': '_blank' } )
-                               .css( { 'white-space': 'nowrap' } );
+                       $feedbackPageLink = $( '<a>' )
+                               .attr( {
+                                       href: fb.title.getUrl(),
+                                       target: '_blank'
+                               } )
+                               .css( {
+                                       whiteSpace: 'nowrap'
+                               } );
 
-                       var $bugNoteLink = $( '<a>' ).attr( { 'href': '#' } ).click( function () {
+                       $bugNoteLink = $( '<a>' ).attr( { href: '#' } ).click( function () {
                                fb.displayBugs();
                        } );
 
-                       var $bugsListLink = $( '<a>' ).attr( { 'href': fb.bugsListLink, 'target': '_blank' } );
+                       $bugsListLink = $( '<a>' ).attr( {
+                               href: fb.bugsListLink,
+                               target: '_blank'
+                       } );
 
                        // TODO: Use a stylesheet instead of these inline styles
                        this.$dialog =
                                        ),
                                        $( '<div class="feedback-mode feedback-submitting" style="text-align: center; margin: 3em 0;"></div>' ).append(
                                                mw.msg( 'feedback-adding' ),
-                                               $( '<br/>' ),
+                                               $( '<br>' ),
                                                $( '<span class="feedback-spinner"></span>' )
                                        ),
                                        $( '<div class="feedback-mode feedback-thanks" style="text-align: center; margin:1em"></div>' ).msg(
                },
 
                displayBugs: function () {
-                       var fb = this;
+                       var fb = this,
+                               bugsButtons = {};
                        this.display( 'bugs' );
-                       var bugsButtons = {};
                        bugsButtons[ mw.msg( 'feedback-bugnew' ) ] = function () {
                                window.open( fb.bugsLink, '_blank' );
                        };
                },
 
                displayThanks: function () {
-                       var fb = this;
+                       var fb = this,
+                               closeButton = {};
                        this.display( 'thanks' );
-                       var closeButton = {};
                        closeButton[ mw.msg( 'feedback-close' ) ] = function () {
                                fb.$dialog.dialog( 'close' );
                        };
                 *      message: {String}
                 */
                displayForm: function ( contents ) {
-                       var fb = this;
+                       var fb = this,
+                               formButtons = {};
                        this.subjectInput.value = ( contents && contents.subject ) ? contents.subject : '';
                        this.messageInput.value = ( contents && contents.message ) ? contents.message : '';
 
                        this.display( 'form' );
 
                        // Set up buttons for dialog box. We have to do it the hard way since the json keys are localized
-                       var formButtons = {};
                        formButtons[ mw.msg( 'feedback-submit' ) ] = function () {
                                fb.submit();
                        };
                },
 
                displayError: function ( message ) {
-                       var fb = this;
+                       var fb = this,
+                               closeButton = {};
                        this.display( 'error' );
                        this.$dialog.find( '.feedback-error-msg' ).msg( message );
-                       var closeButton = {};
                        closeButton[ mw.msg( 'feedback-close' ) ] = function () {
                                fb.$dialog.dialog( 'close' );
                        };
                                }
                        }
 
-                       function err( code, info ) {
+                       function err() {
                                // ajax request failed
                                fb.displayError( 'feedback-error3' );
                        }
index 1979573..ecee450 100644 (file)
@@ -1,5 +1,5 @@
-$( function() {
+jQuery( function ( $ ) {
        // Apply hidpi images on DOM-ready
        // Some may have already partly preloaded at low resolution.
        $( 'body' ).hidpi();
-} );
\ No newline at end of file
+} );
index a4753b9..83bf2e3 100644 (file)
@@ -1,64 +1,62 @@
 /**
- * Utility functions for jazzing up HTMLForm elements
+ * Utility functions for jazzing up HTMLForm elements.
  */
 ( function ( $ ) {
 
-/**
- * jQuery plugin to fade or snap to visible state.
- *
- * @param boolean instantToggle (optional)
- * @return jQuery
- */
-$.fn.goIn = function ( instantToggle ) {
-       if ( instantToggle === true ) {
-               return $(this).show();
-       }
-       return $(this).stop( true, true ).fadeIn();
-};
-
-/**
- * jQuery plugin to fade or snap to hiding state.
- *
- * @param boolean instantToggle (optional)
- * @return jQuery
- */
-$.fn.goOut = function ( instantToggle ) {
-       if ( instantToggle === true ) {
-               return $(this).hide();
-       }
-       return $(this).stop( true, true ).fadeOut();
-};
-
-/**
- * Bind a function to the jQuery object via live(), and also immediately trigger
- * the function on the objects with an 'instant' parameter set to true
- * @param callback function taking one parameter, which is Bool true when the event
- *     is called immediately, and the EventArgs object when triggered from an event
- */
-$.fn.liveAndTestAtStart = function ( callback ){
-       $(this)
-               .live( 'change', callback )
-               .each( function ( index, element ){
-                       callback.call( this, true );
-               } );
-};
-
-// Document ready:
-$( function () {
-
-       // Animate the SelectOrOther fields, to only show the text field when
-       // 'other' is selected.
-       $( '.mw-htmlform-select-or-other' ).liveAndTestAtStart( function ( instant ) {
-               var $other = $( '#' + $(this).attr( 'id' ) + '-other' );
-               $other = $other.add( $other.siblings( 'br' ) );
-               if ( $(this).val() === 'other' ) {
-                       $other.goIn( instant );
-               } else {
-                       $other.goOut( instant );
+       /**
+        * jQuery plugin to fade or snap to visible state.
+        *
+        * @param {boolean} instantToggle [optional]
+        * @return {jQuery}
+        */
+       $.fn.goIn = function ( instantToggle ) {
+               if ( instantToggle === true ) {
+                       return $(this).show();
                }
-       });
-
-});
-
+               return $(this).stop( true, true ).fadeIn();
+       };
+
+       /**
+        * jQuery plugin to fade or snap to hiding state.
+        *
+        * @param {boolean} instantToggle [optional]
+        * @return jQuery
+        */
+       $.fn.goOut = function ( instantToggle ) {
+               if ( instantToggle === true ) {
+                       return $(this).hide();
+               }
+               return $(this).stop( true, true ).fadeOut();
+       };
+
+       /**
+        * Bind a function to the jQuery object via live(), and also immediately trigger
+        * the function on the objects with an 'instant' parameter set to true.
+        * @param {Function} callback Takes one parameter, which is {true} when the
+        *  event is called immediately, and {jQuery.Event} when triggered from an event.
+        */
+       $.fn.liveAndTestAtStart = function ( callback ){
+               $(this)
+                       .live( 'change', callback )
+                       .each( function () {
+                               callback.call( this, true );
+                       } );
+       };
+
+       $( function () {
+
+               // Animate the SelectOrOther fields, to only show the text field when
+               // 'other' is selected.
+               $( '.mw-htmlform-select-or-other' ).liveAndTestAtStart( function ( instant ) {
+                       var $other = $( '#' + $(this).attr( 'id' ) + '-other' );
+                       $other = $other.add( $other.siblings( 'br' ) );
+                       if ( $(this).val() === 'other' ) {
+                               $other.goIn( instant );
+                       } else {
+                               $other.goOut( instant );
+                       }
+               });
+
+       } );
 
 }( jQuery ) );
index 7364829..6e2d3b4 100644 (file)
@@ -5,7 +5,8 @@
 * @author neilk@wikimedia.org
 */
 ( function ( mw, $ ) {
-       var slice = Array.prototype.slice,
+       var oldParser,
+               slice = Array.prototype.slice,
                parserDefaults = {
                        magic : {
                                'SITENAME' : mw.config.get( 'wgSiteName' )
@@ -30,8 +31,8 @@
                 * @return {jQuery}
                 */
                return function ( args ) {
-                       var key = args[0];
-                       var argsArray = $.isArray( args[1] ) ? args[1] : slice.call( args, 1 );
+                       var key = args[0],
+                               argsArray = $.isArray( args[1] ) ? args[1] : slice.call( args, 1 );
                        try {
                                return parser.parse( key, argsArray );
                        } catch ( e ) {
                 * is equivalent to
                 *    somefunction(a, [b, c, d])
                 *
-                * @param {String} message key
-                * @param {Array} optional replacements (can also specify variadically)
-                * @return {String} rendered HTML as string
+                * @param {string} key Message key.
+                * @param {Array|mixed} replacements Optional variable replacements (variadically or an array).
+                * @return {string} Rendered HTML.
                 */
-               return function ( /* key, replacements */ ) {
+               return function () {
                        return failableParserFn( arguments ).html();
                };
        };
                 *    somefunction(a, [b, c, d])
                 *
                 * We append to 'this', which in a jQuery plugin context will be the selected elements.
-                * @param {String} message key
-                * @param {Array} optional replacements (can also specify variadically)
+                * @param {string} key Message key.
+                * @param {Array|mixed} replacements Optional variable replacements (variadically or an array).
                 * @return {jQuery} this
                 */
-               return function ( /* key, replacements */ ) {
+               return function () {
                        var $target = this.empty();
                        $.each( failableParserFn( arguments ).contents(), function ( i, node ) {
                                $target.append( node );
                 * Where the magic happens.
                 * Parses a message from the key, and swaps in replacements as necessary, wraps in jQuery
                 * If an error is thrown, returns original key, and logs the error
-                * @param {String} message key
-                * @param {Array} replacements for $1, $2... $n
+                * @param {String} key Message key.
+                * @param {Array} replacements Variable replacements for $1, $2... $n
                 * @return {jQuery}
                 */
                parse: function ( key, replacements ) {
                        if ( this.astCache[ key ] === undefined ) {
                                var wikiText = this.settings.messages.get( key );
                                if ( typeof wikiText !== 'string' ) {
-                                       wikiText = "\\[" + key + "\\]";
+                                       wikiText = '\\[' + key + '\\]';
                                }
                                this.astCache[ key ] = this.wikiTextToAst( wikiText );
                        }
                 * @return {Mixed} abstract syntax tree
                 */
                wikiTextToAst: function ( input ) {
+                       var pos,
+                               regularLiteral, regularLiteralWithoutBar, regularLiteralWithoutSpace, backslash, anyCharacter,
+                               escapedOrLiteralWithoutSpace, escapedOrLiteralWithoutBar, escapedOrRegularLiteral,
+                               whitespace, dollar, digits,
+                               openExtlink, closeExtlink, openLink, closeLink, templateName, pipe, colon,
+                               templateContents, openTemplate, closeTemplate,
+                               nonWhitespaceExpression, paramExpression, expression, result;
 
                        // Indicates current position in input as we parse through it.
                        // Shared among all parsing functions below.
-                       var pos = 0;
+                       pos = 0;
+
                        // =========================================================
                        // parsing combinators - could be a library on its own
                        // =========================================================
                        // Try parsers until one works, if none work return null
                        function choice( ps ) {
                                return function () {
-                                       for ( var i = 0; i < ps.length; i++ ) {
-                                               var result = ps[i]();
+                                       var i, result;
+                                       for ( i = 0; i < ps.length; i++ ) {
+                                               result = ps[i]();
                                                if ( result !== null ) {
                                                         return result;
                                                }
                        // try several ps in a row, all must succeed or return null
                        // this is the only eager one
                        function sequence( ps ) {
-                               var originalPos = pos;
-                               var result = [];
-                               for ( var i = 0; i < ps.length; i++ ) {
-                                       var res = ps[i]();
+                               var i, res,
+                                       originalPos = pos,
+                                       result = [];
+                               for ( i = 0; i < ps.length; i++ ) {
+                                       res = ps[i]();
                                        if ( res === null ) {
                                                pos = originalPos;
                                                return null;
                        // must succeed a minimum of n times or return null
                        function nOrMore( n, p ) {
                                return function () {
-                                       var originalPos = pos;
-                                       var result = [];
-                                       var parsed = p();
+                                       var originalPos = pos,
+                                               result = [],
+                                               parsed = p();
                                        while ( parsed !== null ) {
                                                result.push( parsed );
                                                parsed = p();
                        // but some debuggers can't tell you exactly where they come from. Also the mutually
                        // recursive functions seem not to work in all browsers then. (Tested IE6-7, Opera, Safari, FF)
                        // This may be because, to save code, memoization was removed
-                       var regularLiteral = makeRegexParser( /^[^{}\[\]$\\]/ );
-                       var regularLiteralWithoutBar = makeRegexParser(/^[^{}\[\]$\\|]/);
-                       var regularLiteralWithoutSpace = makeRegexParser(/^[^{}\[\]$\s]/);
-                       var backslash = makeStringParser( "\\" );
-                       var anyCharacter = makeRegexParser( /^./ );
+                       regularLiteral = makeRegexParser( /^[^{}\[\]$\\]/ );
+                       regularLiteralWithoutBar = makeRegexParser(/^[^{}\[\]$\\|]/);
+                       regularLiteralWithoutSpace = makeRegexParser(/^[^{}\[\]$\s]/);
+                       backslash = makeStringParser( '\\' );
+                       anyCharacter = makeRegexParser( /^./ );
                        function escapedLiteral() {
                                var result = sequence( [
                                        backslash,
                                ] );
                                return result === null ? null : result[1];
                        }
-                       var escapedOrLiteralWithoutSpace = choice( [
+                       escapedOrLiteralWithoutSpace = choice( [
                                escapedLiteral,
                                regularLiteralWithoutSpace
                        ] );
-                       var escapedOrLiteralWithoutBar = choice( [
+                       escapedOrLiteralWithoutBar = choice( [
                                escapedLiteral,
                                regularLiteralWithoutBar
                        ] );
-                       var escapedOrRegularLiteral = choice( [
+                       escapedOrRegularLiteral = choice( [
                                escapedLiteral,
                                regularLiteral
                        ] );
                                 var result = nOrMore( 1, escapedOrRegularLiteral )();
                                 return result === null ? null : result.join('');
                        }
-                       var whitespace = makeRegexParser( /^\s+/ );
-                       var dollar = makeStringParser( '$' );
-                       var digits = makeRegexParser( /^\d+/ );
+                       whitespace = makeRegexParser( /^\s+/ );
+                       dollar = makeStringParser( '$' );
+                       digits = makeRegexParser( /^\d+/ );
 
                        function replacement() {
                                var result = sequence( [
                                }
                                return [ 'REPLACE', parseInt( result[1], 10 ) - 1 ];
                        }
-                       var openExtlink = makeStringParser( '[' );
-                       var closeExtlink = makeStringParser( ']' );
+                       openExtlink = makeStringParser( '[' );
+                       closeExtlink = makeStringParser( ']' );
                        // this extlink MUST have inner text, e.g. [foo] not allowed; [foo bar] is allowed
                        function extlink() {
-                               var result = null;
-                               var parsedResult = sequence( [
+                               var result, parsedResult;
+                               result = null;
+                               parsedResult = sequence( [
                                        openExtlink,
                                        nonWhitespaceExpression,
                                        whitespace,
                                }
                                return [ 'LINKPARAM', parseInt( result[2], 10 ) - 1, result[4] ];
                        }
-                       var openLink = makeStringParser( '[[' );
-                       var closeLink = makeStringParser( ']]' );
+                       openLink = makeStringParser( '[[' );
+                       closeLink = makeStringParser( ']]' );
                        function link() {
-                               var result = null;
-                               var parsedResult = sequence( [
+                               var result, parsedResult;
+                               result = null;
+                               parsedResult = sequence( [
                                        openLink,
                                        expression,
                                        closeLink
                                }
                                return result;
                        }
-                       var templateName = transform(
+                       templateName = transform(
                                // see $wgLegalTitleChars
                                // not allowing : due to the need to catch "PLURAL:$1"
                                makeRegexParser( /^[ !"$&'()*,.\/0-9;=?@A-Z\^_`a-z~\x80-\xFF+\-]+/ ),
                                function ( result ) { return result.toString(); }
                        );
                        function templateParam() {
-                               var result = sequence( [
+                               var expr, result;
+                               result = sequence( [
                                        pipe,
                                        nOrMore( 0, paramExpression )
                                ] );
                                if ( result === null ) {
                                        return null;
                                }
-                               var expr = result[1];
-                               // use a "CONCAT" operator if there are multiple nodes, otherwise return the first node, raw.
-                               return expr.length > 1 ? [ "CONCAT" ].concat( expr ) : expr[0];
+                               expr = result[1];
+                               // use a CONCAT operator if there are multiple nodes, otherwise return the first node, raw.
+                               return expr.length > 1 ? [ 'CONCAT' ].concat( expr ) : expr[0];
                        }
-                       var pipe = makeStringParser( '|' );
+                       pipe = makeStringParser( '|' );
                        function templateWithReplacement() {
                                var result = sequence( [
                                        templateName,
                                ] );
                                return result === null ? null : [ result[0], result[2] ];
                        }
-                       var colon = makeStringParser(':');
-                       var templateContents = choice( [
+                       colon = makeStringParser(':');
+                       templateContents = choice( [
                                function () {
                                        var res = sequence( [
                                                // templates can have placeholders for dynamic replacement eg: {{PLURAL:$1|one car|$1 cars}}
                                        return [ res[0] ].concat( res[1] );
                                }
                        ] );
-                       var openTemplate = makeStringParser('{{');
-                       var closeTemplate = makeStringParser('}}');
+                       openTemplate = makeStringParser('{{');
+                       closeTemplate = makeStringParser('}}');
                        function template() {
                                var result = sequence( [
                                        openTemplate,
                                ] );
                                return result === null ? null : result[1];
                        }
-                       var nonWhitespaceExpression = choice( [
+                       nonWhitespaceExpression = choice( [
                                template,
                                link,
                                extLinkParam,
                                replacement,
                                literalWithoutSpace
                        ] );
-                       var paramExpression = choice( [
+                       paramExpression = choice( [
                                template,
                                link,
                                extLinkParam,
                                replacement,
                                literalWithoutBar
                        ] );
-                       var expression = choice( [
+                       expression = choice( [
                                template,
                                link,
                                extLinkParam,
                                if ( result === null ) {
                                        return null;
                                }
-                               return [ "CONCAT" ].concat( result );
+                               return [ 'CONCAT' ].concat( result );
                        }
                        // everything above this point is supposed to be stateless/static, but
                        // I am deferring the work of turning it into prototypes & objects. It's quite fast enough
                        // finally let's do some actual work...
-                       var result = start();
+                       result = start();
 
                        /*
                         * For success, the p must have gotten to the end of the input
                         * and returned a non-null.
                         * n.b. This is part of language infrastructure, so we do not throw an internationalizable message.
                         */
-                       if (result === null || pos !== input.length) {
-                               throw new Error( "Parse error at position " + pos.toString() + " in input: " + input );
+                       if ( result === null || pos !== input.length ) {
+                               throw new Error( 'Parse error at position ' + pos.toString() + ' in input: ' + input );
                        }
                        return result;
                }
                 * @return {Mixed} single-string node or array of nodes suitable for jQuery appending
                 */
                this.emit = function ( node, replacements ) {
-                       var ret = null;
-                       var jmsg = this;
+                       var ret, subnodes, operation,
+                               jmsg = this;
                        switch ( typeof node ) {
                                case 'string':
                                case 'number':
                                        ret = node;
                                        break;
-                               case 'object': // node is an array of nodes
-                                       var subnodes = $.map( node.slice( 1 ), function ( n ) {
+                               // typeof returns object for arrays
+                               case 'object':
+                                       // node is an array of nodes
+                                       subnodes = $.map( node.slice( 1 ), function ( n ) {
                                                return jmsg.emit( n, replacements );
                                        } );
-                                       var operation = node[0].toLowerCase();
+                                       operation = node[0].toLowerCase();
                                        if ( typeof jmsg[operation] === 'function' ) {
                                                ret = jmsg[ operation ]( subnodes, replacements );
                                        } else {
                /**
                 * Transform wiki-link
                 * TODO unimplemented
+                * @param nodes
                 */
-               wlink: function ( nodes ) {
+               wlink: function () {
                        return 'unimplemented';
                },
 
                 * @return {jQuery}
                 */
                link: function ( nodes ) {
-                       var arg = nodes[0];
-                       var contents = nodes[1];
-                       var $el;
+                       var $el,
+                               arg = nodes[0],
+                               contents = nodes[1];
                        if ( arg instanceof jQuery ) {
                                $el = arg;
                        } else {
                 * @return {String} selected pluralized form according to current language
                 */
                plural: function ( nodes ) {
-                       var count = parseFloat( this.language.convertNumber( nodes[0], true ) );
-                       var forms = nodes.slice(1);
+                       var forms, count;
+                       count = parseFloat( this.language.convertNumber( nodes[0], true ) );
+                       forms = nodes.slice(1);
                        return forms.length ? this.language.convertPlural( count, forms ) : '';
                },
 
                 * @return {String} selected grammatical form according to current language
                 */
                grammar: function ( nodes ) {
-                       var form = nodes[0];
-                       var word = nodes[1];
+                       var form = nodes[0],
+                               word = nodes[1];
                        return word && form && this.language.convertGrammar( word, form );
                }
        };
        $.fn.msg = mw.jqueryMsg.getPlugin();
 
        // Replace the default message parser with jqueryMsg
-       var oldParser = mw.Message.prototype.parser;
+       oldParser = mw.Message.prototype.parser;
        mw.Message.prototype.parser = function () {
                // TODO: should we cache the message function so we don't create a new one every time? Benchmark this maybe?
                // Caching is somewhat problematic, because we do need different message functions for different maps, so
index 690138c..b0abc9e 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 var mw = ( function ( $, undefined ) {
-       "use strict";
+       'use strict';
 
        /* Private Members */
 
@@ -290,14 +290,14 @@ var mw = ( function ( $, undefined ) {
                 * Gets a message object, similar to wfMessage()
                 *
                 * @param key string Key of message to get
-                * @param parameter_1 mixed First argument in a list of variadic arguments,
+                * @param parameter1 mixed First argument in a list of variadic arguments,
                 *  each a parameter for $N replacement in messages.
                 * @return Message
                 */
-               message: function ( key, parameter_1 /* [, parameter_2] */ ) {
+               message: function ( key, parameter1 ) {
                        var parameters;
                        // Support variadic arguments
-                       if ( parameter_1 !== undefined ) {
+                       if ( parameter1 !== undefined ) {
                                parameters = slice.call( arguments );
                                parameters.shift();
                        } else {
@@ -473,32 +473,14 @@ var mw = ( function ( $, undefined ) {
                                }
                        }
 
-                       function compare( a, b ) {
-                               var i;
-                               if ( a.length !== b.length ) {
-                                       return false;
-                               }
-                               for ( i = 0; i < b.length; i += 1 ) {
-                                       if ( $.isArray( a[i] ) ) {
-                                               if ( !compare( a[i], b[i] ) ) {
-                                                       return false;
-                                               }
-                                       }
-                                       if ( a[i] !== b[i] ) {
-                                               return false;
-                                       }
-                               }
-                               return true;
-                       }
-
                        /**
                         * Generates an ISO8601 "basic" string from a UNIX timestamp
                         */
                        function formatVersionNumber( timestamp ) {
-                               var     pad = function ( a, b, c ) {
-                                               return [a < 10 ? '0' + a : a, b < 10 ? '0' + b : b, c < 10 ? '0' + c : c].join( '' );
-                                       },
-                                       d = new Date();
+                               var     d = new Date();
+                               function pad( a, b, c ) {
+                                       return [a < 10 ? '0' + a : a, b < 10 ? '0' + b : b, c < 10 ? '0' + c : c].join( '' );
+                               }
                                d.setTime( timestamp * 1000 );
                                return [
                                        pad( d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate() ), 'T',
@@ -712,7 +694,7 @@ var mw = ( function ( $, undefined ) {
                                                j -= 1;
                                                try {
                                                        if ( hasErrors ) {
-                                                               throw new Error ("Module " + module + " failed.");
+                                                               throw new Error( 'Module ' + module + ' failed.');
                                                        } else {
                                                                if ( $.isFunction( job.ready ) ) {
                                                                        job.ready();
@@ -957,7 +939,7 @@ var mw = ( function ( $, undefined ) {
                         *  document ready has not yet occurred
                         */
                        function request( dependencies, ready, error, async ) {
-                               var regItemDeps, regItemDepLen, n;
+                               var n;
 
                                // Allow calling by single module name
                                if ( typeof dependencies === 'string' ) {
@@ -1029,7 +1011,7 @@ var mw = ( function ( $, undefined ) {
                         */
                        function doRequest( moduleMap, currReqBase, sourceLoadScript, async ) {
                                var request = $.extend(
-                                       { 'modules': buildModulesString( moduleMap ) },
+                                       { modules: buildModulesString( moduleMap ) },
                                        currReqBase
                                );
                                request = sortQuery( request );
@@ -1126,7 +1108,7 @@ var mw = ( function ( $, undefined ) {
 
                                                        currReqBase = $.extend( { version: formatVersionNumber( maxVersion ) }, reqBase );
                                                        // For user modules append a user name to the request.
-                                                       if ( group === "user" && mw.config.get( 'wgUserName' ) !== null ) {
+                                                       if ( group === 'user' && mw.config.get( 'wgUserName' ) !== null ) {
                                                                currReqBase.user = mw.config.get( 'wgUserName' );
                                                        }
                                                        currReqBaseLength = $.param( currReqBase ).length;
@@ -1513,7 +1495,7 @@ var mw = ( function ( $, undefined ) {
                html: ( function () {
                        function escapeCallback( s ) {
                                switch ( s ) {
-                                       case "'":
+                                       case '\'':
                                                return '&#039;';
                                        case '"':
                                                return '&quot;';
index 58a3ab6..35cc6d8 100644 (file)
@@ -4,7 +4,8 @@
 ( function ( mw, $ ) {
        'use strict';
 
-       var isPageReady = false,
+       var notification,
+               isPageReady = false,
                isInitialized = false,
                preReadyNotifQueue = [],
                /**
@@ -88,7 +89,9 @@
                        // Other notification elements matching the same tag
                        $tagMatches,
                        outerHeight,
-                       placeholderHeight;
+                       placeholderHeight,
+                       autohideCount,
+                       notif;
 
                if ( this.isOpen ) {
                        return;
                                                }
                                        } );
 
+                       notif = this;
+
                        // Create a clear placeholder we can use to make the notifications around the notification that is being
                        // replaced expand or contract gracefully to fit the height of the new notification.
-                       var self = this;
-                       self.$replacementPlaceholder = $( '<div>' )
+                       notif.$replacementPlaceholder = $( '<div>' )
                                // Set the height to the space the previous notification or placeholder took
                                .css( 'height', outerHeight )
                                // Make sure that this placeholder is at the very end of this tagged notification group
                                                        // Reset the notification position after we've finished the space animation
                                                        // However do not do it if the placeholder was removed because another tagged
                                                        // notification went and closed this one.
-                                                       if ( self.$replacementPlaceholder ) {
+                                                       if ( notif.$replacementPlaceholder ) {
                                                                $notification.css( 'position', '' );
                                                        }
                                                        // Finally, remove the placeholder from the DOM
                // By default a notification is paused.
                // If this notification is within the first {autoHideLimit} notifications then
                // start the auto-hide timer as soon as it's created.
-               var autohideCount = $area.find( '.mw-notification-autohide' ).length;
+               autohideCount = $area.find( '.mw-notification-autohide' ).length;
                if ( autohideCount <= notification.autoHideLimit ) {
                        this.resume();
                }
                }
        }
 
-       var notification = {
+       notification = {
                /**
                 * Pause auto-hide timers for all notifications.
                 * Notifications will not auto-hide until resume is called.
index 4e515bc..4bb004a 100644 (file)
@@ -62,7 +62,8 @@
 
                        /* Fill $content var */
                        util.$content = ( function () {
-                               var $content, selectors = [
+                               var i, l, $content, selectors;
+                               selectors = [
                                        // The preferred standard for setting $content (class="mw-body")
                                        // You may also use (class="mw-body mw-body-primary") if you use
                                        // mw-body in multiple locations.
@@ -94,7 +95,7 @@
                                        // not inserted bodytext yet. But in any case <body> should always exist
                                        'body'
                                ];
-                               for ( var i = 0, l = selectors.length; i < l; i++ ) {
+                               for ( i = 0, l = selectors.length; i < l; i++ ) {
                                        $content = $( selectors[i] ).first();
                                        if ( $content.length ) {
                                                return $content;
                 * is determined by validation.
                 */
                validateEmail: function ( mailtxt ) {
-                       var rfc5322_atext, rfc1034_ldh_str, HTML5_email_regexp;
+                       var rfc5322Atext, rfc1034LdhStr, html5EmailRegexp;
 
                        if ( mailtxt === '' ) {
                                return null;
                                                 "|" / "}" /
                                                 "~"
                        */
-                       rfc5322_atext = "a-z0-9!#$%&'*+\\-/=?^_`{|}~";
+                       rfc5322Atext = 'a-z0-9!#$%&\'*+\\-/=?^_`{|}~';
 
                        /**
                         * Next define the RFC 1034 'ldh-str'
                         *      <let-dig-hyp> ::= <let-dig> | "-"
                         *      <let-dig> ::= <letter> | <digit>
                         */
-                       rfc1034_ldh_str = "a-z0-9\\-";
+                       rfc1034LdhStr = 'a-z0-9\\-';
 
-                       HTML5_email_regexp = new RegExp(
+                       html5EmailRegexp = new RegExp(
                                // start of string
                                '^'
                                +
                                // User part which is liberal :p
-                               '[' + rfc5322_atext + '\\.]+'
+                               '[' + rfc5322Atext + '\\.]+'
                                +
                                // 'at'
                                '@'
                                +
                                // Domain first part
-                               '[' + rfc1034_ldh_str + ']+'
+                               '[' + rfc1034LdhStr + ']+'
                                +
                                // Optional second part and following are separated by a dot
-                               '(?:\\.[' + rfc1034_ldh_str + ']+)*'
+                               '(?:\\.[' + rfc1034LdhStr + ']+)*'
                                +
                                // End of string
                                '$',
                                // RegExp is case insensitive
                                'i'
                        );
-                       return (null !== mailtxt.match( HTML5_email_regexp ) );
+                       return (null !== mailtxt.match( html5EmailRegexp ) );
                },
 
                /**
index 7951af0..deff7e6 100644 (file)
@@ -3,19 +3,22 @@
  * continue loading the jquery and mediawiki modules. This code should work on
  * even the most ancient of browsers, so be very careful when editing.
  */
+
 /**
  * Returns false when run in a black-listed browser
  *
  * This function will be deleted after it's used, so do not expand it to be
- * generally useful beyond startup
+ * generally useful beyond startup.
  *
- * jQuery has minimum requirements of:
- * * Internet Explorer 6.0+
- * * Firefox 3.6+
- * * Safari 5.0+
- * * Opera 11+
- * * Chrome
+ * MediaWiki & jQuery compatibility:
+ * - Internet Explorer 6.0+
+ * - Firefox 10+
+ * - Safari 5.0+
+ * - Opera 11+
+ * - Chrome
  */
+
+/*jshint unused: false */
 function isCompatible() {
        // IE < 6.0
        if ( navigator.appVersion.indexOf( 'MSIE' ) !== -1
@@ -23,11 +26,9 @@ function isCompatible() {
        {
                return false;
        }
-       // @todo FIXME: Firefox < 3.6
-       // @todo FIXME: Safari < 5.0
-       // @todo FIXME: Opera < 11
        return true;
 }
+
 /**
- * The startUp() function will be generated and added here (at the bottom)
+ * The startUp() function will be auto-generated and added below.
  */
index 7fbca41..227d18d 100644 (file)
@@ -361,7 +361,7 @@ class VectorTemplate extends BaseTemplate {
         * @param $elements array
         */
        protected function renderNavigation( $elements ) {
-               global $wgVectorUseSimpleSearch;
+               global $wgVectorUseSimpleSearch, $wgVectorCombineUserTalk;
 
                // If only one element was given, wrap it in an array, allowing more
                // flexible arguments
@@ -444,10 +444,26 @@ class VectorTemplate extends BaseTemplate {
 <div id="p-personal" class="<?php if ( count( $this->data['personal_urls'] ) == 0 ) echo ' emptyPortlet'; ?>">
        <h5><?php $this->msg( 'personaltools' ) ?></h5>
        <ul<?php $this->html( 'userlangattributes' ) ?>>
-<?php                  foreach( $this->getPersonalTools() as $key => $item ) { ?>
-               <?php echo $this->makeListItem( $key, $item ); ?>
-
-<?php                  } ?>
+<?php
+                                       $personalTools = $this->getPersonalTools();
+                                       if ( $wgVectorCombineUserTalk && isset( $personalTools['userpage'] ) ) {
+?>
+               <li>
+<?php
+                                               echo $this->makeListItem( 'userpage', $personalTools['userpage'], array( 'tag' => 'span' ) );
+?> <?php
+                                               $personalTools['mytalk']['links'][0]['text'] = $this->getMsg( 'mytalk-parenthetical' )->text();
+                                               $talkItem = $this->makeListItem( 'mytalk', $personalTools['mytalk'], array( 'tag' => 'span' ) );
+                                               echo $this->getMsg( 'parentheses' )->rawParams( $talkItem )->escaped();
+                                               unset( $personalTools['userpage'], $personalTools['mytalk'] );
+?>
+               </li>
+<?php
+                                       }
+                                       foreach ( $personalTools as $key => $item ) {
+                                               echo $this->makeListItem( $key, $item );
+                                       }
+?>
        </ul>
 </div>
 <?php
index 8ed24bb..01d7b2a 100644 (file)
  */
 
 global $wgAutoloadClasses;
-$testFolder = __DIR__;
+$testDir = __DIR__;
 
 $wgAutoloadClasses += array(
 
-       //PHPUnit
-       'MediaWikiTestCase' => "$testFolder/phpunit/MediaWikiTestCase.php",
-       'MediaWikiPHPUnitCommand' => "$testFolder/phpunit/MediaWikiPHPUnitCommand.php",
-       'MediaWikiLangTestCase' => "$testFolder/phpunit/MediaWikiLangTestCase.php",
-       'NewParserTest' => "$testFolder/phpunit/includes/parser/NewParserTest.php",
+       # tests
+       'DbTestPreviewer' => "$testDir/testHelpers.inc",
+       'DbTestRecorder' => "$testDir/testHelpers.inc",
+       'DelayedParserTest' => "$testDir/testHelpers.inc",
+       'TestFileIterator' => "$testDir/testHelpers.inc",
+       'TestRecorder' => "$testDir/testHelpers.inc",
 
-       //includes
-       'BlockTest' => "$testFolder/phpunit/includes/BlockTest.php",
+       # tests/phpunit
+       'MediaWikiTestCase' => "$testDir/phpunit/MediaWikiTestCase.php",
+       'MediaWikiPHPUnitCommand' => "$testDir/phpunit/MediaWikiPHPUnitCommand.php",
+       'MediaWikiLangTestCase' => "$testDir/phpunit/MediaWikiLangTestCase.php",
+       'MediaWikiProvide' => "$testDir/phpunit/includes/Providers.php",
+       'TestUser' => "$testDir/phpunit/includes/TestUser.php",
 
-       //API
-       'ApiFormatTestBase' => "$testFolder/phpunit/includes/api/format/ApiFormatTestBase.php",
-       'ApiTestCase' => "$testFolder/phpunit/includes/api/ApiTestCase.php",
-       'TestUser' => "$testFolder/phpunit/includes/TestUser.php",
-       'MockApi' => "$testFolder/phpunit/includes/api/ApiTestCase.php",
-       'RandomImageGenerator' => "$testFolder/phpunit/includes/api/RandomImageGenerator.php",
-       'UserWrapper' => "$testFolder/phpunit/includes/api/ApiTestCase.php",
+       # tests/phpunit/includes
+       'BlockTest' => "$testDir/phpunit/includes/BlockTest.php",
+       'RevisionStorageTest' => "$testDir/phpunit/includes/RevisionStorageTest.php",
+       'WikiPageTest' => "$testDir/phpunit/includes/WikiPageTest.php",
+
+       //db
+       'ORMTableTest' => "$testDir/phpunit/includes/db/ORMTableTest.php",
 
        //Selenium
-       'SeleniumTestConstants' => "$testFolder/selenium/SeleniumTestConstants.php",
+       'SeleniumTestConstants' => "$testDir/selenium/SeleniumTestConstants.php",
+
+       # tests/phpunit/includes/api
+       'ApiFormatTestBase' => "$testDir/phpunit/includes/api/format/ApiFormatTestBase.php",
+       'ApiTestCase' => "$testDir/phpunit/includes/api/ApiTestCase.php",
+       'ApiTestContext' => "$testDir/phpunit/includes/api/ApiTestCase.php",
+       'MockApi' => "$testDir/phpunit/includes/api/ApiTestCase.php",
+       'RandomImageGenerator' => "$testDir/phpunit/includes/api/RandomImageGenerator.php",
+       'UserWrapper' => "$testDir/phpunit/includes/api/ApiTestCase.php",
+
+       # tests/phpunit/includes/content
+       'DummyContentHandlerForTesting' => "$testDir/phpunit/includes/content/ContentHandlerTest.php",
+       'DummyContentForTesting' => "$testDir/phpunit/includes/content/ContentHandlerTest.php",
+       'ContentHandlerTest' => "$testDir/phpunit/includes/content/ContentHandlerTest.php",
+       'JavascriptContentTest' => "$testDir/phpunit/includes/content/JavascriptContentTest.php",
+       'TextContentTest' => "$testDir/phpunit/includes/content/TextContentTest.php",
+
+       # tests/phpunit/includes/db
+       'ORMRowTest' => "$testDir/phpunit/includes/db/ORMRowTest.php",
+
+       # tests/phpunit/includes/parser
+       'NewParserTest' => "$testDir/phpunit/includes/parser/NewParserTest.php",
+
+       # tests/phpunit/includes/libs
+       'GenericArrayObjectTest' => "$testDir/phpunit/includes/libs/GenericArrayObjectTest.php",
+
+       # tests/phpunit/includes/site
+       'SiteObjectTest' => "$testDir/phpunit/includes/site/SiteObjectTest.php",
+       'TestSites' => "$testDir/phpunit/includes/site/TestSites.php",
+
+       # tests/phpunit/languages
+       'LanguageClassesTestCase' => "$testDir/phpunit/languages/LanguageClassesTestCase.php",
 
-       //maintenance
-       'DumpTestCase' => "$testFolder/phpunit/maintenance/DumpTestCase.php",
-       'BackupDumper' => "$testFolder/../maintenance/backup.inc",
+       # tests/phpunit/maintenance
+       'DumpTestCase' => "$testDir/phpunit/maintenance/DumpTestCase.php",
 
-       //language
-       'LanguageClassesTestCase' => "$testFolder/phpunit/languages/LanguageClassesTestCase.php",
+       # tests/parser
+       'ParserTest' => "$testDir/parser/parserTest.inc",
+       'ParserTestParserHook' => "$testDir/parser/parserTestsParserHook.php",
 
-       //Generic providers
-       'MediaWikiProvide' => "$testFolder/phpunit/includes/Providers.php",
+       # tests/selenium
+       'Selenium' => "$testDir/selenium/Selenium.php",
+       'SeleniumLoader' => "$testDir/selenium/SeleniumLoader.php",
+       'SeleniumTestCase' => "$testDir/selenium/SeleniumTestCase.php",
+       'SeleniumTestConsoleLogger' => "$testDir/selenium/SeleniumTestConsoleLogger.php",
+       'SeleniumTestConstants' => "$testDir/selenium/SeleniumTestConstants.php",
+       'SeleniumTestHTMLLogger' => "$testDir/selenium/SeleniumTestHTMLLogger.php",
+       'SeleniumTestListener' => "$testDir/selenium/SeleniumTestListener.php",
+       'SeleniumTestSuite' => "$testDir/selenium/SeleniumTestSuite.php",
+       'SeleniumConfig' => "$testDir/selenium/SeleniumConfig.php",
 );
 
index 2f20fbc..4690e1a 100644 (file)
@@ -48,7 +48,7 @@ Template:Blank
 !! endarticle
 
 !! article
-Template:!
+Template:pipe
 !! text
 |
 !! endarticle
@@ -65,6 +65,12 @@ Template:inner list
 * item 1
 !! endarticle
 
+!! article
+Template:!
+!! text
+|
+!! endarticle
+
 !! article
 Template:echo
 !! text
@@ -89,6 +95,13 @@ Template:attr_str
 {{{1}}}="{{{2}}}"
 !! endarticle
 
+!! article
+Template:table_attribs
+!! text
+<noinclude>
+|</noinclude>style="color: red"| Foo
+!! endarticle
+
 ###
 ### Basic tests
 ###
@@ -908,6 +921,15 @@ Bug 6200: Preformatted in <blockquote>
 </p>
 !! end
 
+!! test
+</pre> inside nowiki
+!! input
+<nowiki></pre></nowiki>
+!! result
+<p>&lt;/pre&gt;
+</p>
+!! end
+
 !!test
 Templates: Pre: 1a. Templates that break a line should suppress <pre>
 !!input
@@ -964,6 +986,8 @@ Templates: Pre: 1e. Wrapping should be based on expanded content
 !!input
 {{echo| foo}}
 
+{{echo| foo}}{{echo| bar}}
+
 {{echo| foo}}
 {{echo| bar}}
 
@@ -975,6 +999,8 @@ Templates: Pre: 1e. Wrapping should be based on expanded content
 !!result
 <pre>foo
 </pre>
+<pre>foo bar
+</pre>
 <pre>foo
 bar
 </pre>
@@ -986,6 +1012,92 @@ bar
 </pre>
 !!end
 
+!! test
+Templates: Pre: 1f: Wrapping should be based on expanded content
+!! input
+{{echo| }}a
+
+{{echo|
+ }}a
+
+{{echo|
+ b}}
+
+{{echo|a
+ }}b
+
+{{echo|a
+}} b
+!!result
+<pre>a
+</pre>
+<p><br />
+</p>
+<pre>a
+</pre>
+<p><br />
+</p>
+<pre>b
+</pre>
+<p>a
+</p>
+<pre>b
+</pre>
+<p>a
+</p>
+<pre>b
+</pre>
+!!end
+
+!! test
+Templates: Single-line variant of parameter whitespace stripping test
+!! input
+{{echo| a}}
+
+{{echo|1= a}}
+
+{{echo|{{echo| a}}}}
+
+{{echo|1={{echo| a}}}}
+!! result
+<pre>a
+</pre>
+<p>a
+</p>
+<pre>a
+</pre>
+<p>a
+</p>
+!! end
+
+!! test
+Templates: Strip whitespace from named parameters, but not positional ones
+!! input
+{{echo|
+ foo}}
+
+{{echo|
+* foo}}
+
+{{echo| 1 =
+ foo}}
+
+{{echo| 1 =
+* foo}}
+!! result
+<pre>foo
+</pre>
+<p><br />
+</p>
+<ul><li> foo
+</li></ul>
+<p>foo
+</p>
+<ul><li> foo
+</li></ul>
+
+!! end
+
 ###
 ### Parsoid-centric tests for testing RT edge cases for pre
 ###
@@ -1067,7 +1179,7 @@ c
 !!end
 
 !!test
-3. Pre and block tags
+3a. Pre and block tags (single-line html)
 !!input
  <p> foo </p>
  <div> foo </div>
@@ -1079,6 +1191,58 @@ c
 </pre>
 !!end
 
+!!test
+3b. Pre and block tags (pre-content on separate line)
+!!input
+<p>
+ foo
+</p>
+
+<div>
+ foo
+</div>
+
+<center>
+ foo
+</center>
+
+<blockquote>
+ foo
+</blockquote>
+
+<table><tr><td>
+ foo
+</td></tr></table>
+
+<ul><li>
+  foo
+</li></ul>
+
+!!result
+<p>
+ foo
+</p>
+<div>
+<pre>foo
+</pre>
+</div>
+<center>
+<pre>foo
+</pre>
+</center>
+<blockquote>
+ foo
+</blockquote>
+<table><tr><td>
+<pre>foo
+</pre>
+</td></tr></table>
+<ul><li>
+  foo
+</li></ul>
+
+!!end
+
 !!test
 4. Multiple spaces at start-of-line
 !!input
@@ -1235,13 +1399,13 @@ Bug 11748: Literal closing tags
 Definition and unordered list using wiki syntax nested in unordered list using html tags.
 !! input
 <ul><li>
-; term : description 
+; term : description
 * unordered
 </li>
 </ul>
 !! result
 <ul><li>
-<dl><dt> term&#160;</dt><dd> description 
+<dl><dt> term&#160;</dt><dd> description
 </dd></dl>
 <ul><li> unordered
 </li></ul>
@@ -2105,6 +2269,15 @@ http:/example.com
 </p>
 !! end
 
+!! test
+Bracketed external links with template-generated invalid target
+!! input
+[{{echo|http:/example.com}} title]
+!! result
+<p>[http:/example.com title]
+</p>
+!! end
+
 !! test
 Bug 2702: Mismatched <i>, <b> and <a> tags are invalid
 !! input
@@ -2364,9 +2537,9 @@ A table with nothing but a caption
 !! test
 Simple table
 !! input
-{| 
+{|
 | 1 || 2
-|- 
+|-
 | 3 || 4
 |}
 !! result
@@ -2385,7 +2558,7 @@ Simple table
 !! test
 Simple table but with multiple dashes for row wikitext
 !! input
-{| 
+{|
 | foo
 |-----
 | bar
@@ -2498,12 +2671,12 @@ Allow +/- in 2nd and later cells in a row
 Table rowspan
 !! input
 {| border=1
-| Cell 1, row 1 
-|rowspan=2| Cell 2, row 1 (and 2) 
-| Cell 3, row 1 
-|- 
-| Cell 1, row 2 
-| Cell 3, row 2 
+| Cell 1, row 1
+|rowspan=2| Cell 2, row 1 (and 2)
+| Cell 3, row 1
+|-
+| Cell 1, row 2
+| Cell 3, row 2
 |}
 !! result
 <table border="1">
@@ -2608,6 +2781,19 @@ Indented table markup mixed with indented pre content (proposed in bug 6200)
 
 !! end
 
+!! test
+Template-generated table cell attributes and cell content
+!! input
+{|
+|{{table_attribs}}
+|}
+!! result
+<table>
+<tr>
+<td style="color: red"> Foo
+</td></tr></table>
+
+!! end
 
 ###
 ### Internal links
@@ -3155,6 +3341,15 @@ language=ln
 </p>
 !! end
 
+!! test
+Broken br tag sanitization
+!! input
+</br>
+!! result
+<p>&lt;/br&gt;
+</p>
+!! end
+
 !! test
 Incorrecly removing closing slashes from correctly formed XHTML
 !! input
@@ -4199,7 +4394,7 @@ Template with complex arguments
 !! test
 BUG 553: link with two variables in a piped link
 !! input
-{| 
+{|
 |[[{{{1}}}|{{{2}}}]]
 |}
 !! result
@@ -4307,9 +4502,9 @@ Template from main namespace
 !! article
 Template:table
 !! text
-{| 
+{|
 | 1 || 2
-|- 
+|-
 | 3 || 4
 |}
 !! endarticle
@@ -4801,7 +4996,7 @@ Templates: HTML Tag: 6. Generation of end piece of HTML attr value
 !!end
 
 !!test
-Templates: Tables: 1. Generating start of a HTML table
+Templates: HTML Tables: 1. Generating start of a HTML table
 !!input
 {{echo|<table><tr><td>foo</td>}}</tr></table>
 !!result
@@ -4810,7 +5005,7 @@ Templates: Tables: 1. Generating start of a HTML table
 !!end
 
 !!test
-Templates: Tables: 2a. Generating middle of a HTML table
+Templates: HTML Tables: 2a. Generating middle of a HTML table
 !!input
 <table><tr>{{echo|<td>foo</td>}}</tr></table>
 !!result
@@ -4819,7 +5014,7 @@ Templates: Tables: 2a. Generating middle of a HTML table
 !!end
 
 !!test
-Templates: Tables: 2b. Generating middle of a HTML table
+Templates: HTML Tables: 2b. Generating middle of a HTML table
 !!input
 <table>{{echo|<tr><td>foo</td></tr>}}</table>
 !!result
@@ -4828,7 +5023,7 @@ Templates: Tables: 2b. Generating middle of a HTML table
 !!end
 
 !!test
-Templates: Tables: 3. Generating end of a HTML table
+Templates: HTML Tables: 3. Generating end of a HTML table
 !!input
 <table><tr>{{echo|<td>foo</td></tr></table>}}
 !!result
@@ -4837,7 +5032,7 @@ Templates: Tables: 3. Generating end of a HTML table
 !!end
 
 !!test
-Templates: Tables: 4a. Generating a single tag of a HTML table
+Templates: HTML Tables: 4a. Generating a single tag of a HTML table
 !!input
 {{echo|<table>}}<tr><td>foo</td></tr></table>
 !!result
@@ -4846,7 +5041,7 @@ Templates: Tables: 4a. Generating a single tag of a HTML table
 !!end
 
 !!test
-Templates: Tables: 4b. Generating a single tag of a HTML table
+Templates: HTML Tables: 4b. Generating a single tag of a HTML table
 !!input
 <table>{{echo|<tr>}}<td>foo</td></tr></table>
 !!result
@@ -4855,7 +5050,7 @@ Templates: Tables: 4b. Generating a single tag of a HTML table
 !!end
 
 !!test
-Templates: Tables: 4c. Generating a single tag of a HTML table
+Templates: HTML Tables: 4c. Generating a single tag of a HTML table
 !!input
 <table><tr>{{echo|<td>}}foo</td></tr></table>
 !!result
@@ -4864,7 +5059,7 @@ Templates: Tables: 4c. Generating a single tag of a HTML table
 !!end
 
 !!test
-Templates: Tables: 4d. Generating a single tag of a HTML table
+Templates: HTML Tables: 4d. Generating a single tag of a HTML table
 !!input
 <table><tr><td>foo{{echo|</td>}}</tr></table>
 !!result
@@ -4873,7 +5068,7 @@ Templates: Tables: 4d. Generating a single tag of a HTML table
 !!end
 
 !!test
-Templates: Tables: 4e. Generating a single tag of a HTML table
+Templates: HTML Tables: 4e. Generating a single tag of a HTML table
 !!input
 <table><tr><td>foo</td>{{echo|</tr>}}</table>
 !!result
@@ -4882,7 +5077,7 @@ Templates: Tables: 4e. Generating a single tag of a HTML table
 !!end
 
 !!test
-Templates: Tables: 4f. Generating a single tag of a HTML table
+Templates: HTML Tables: 4f. Generating a single tag of a HTML table
 !!input
 <table><tr><td>foo</td></tr>{{echo|</table>}}
 !!result
@@ -4890,6 +5085,62 @@ Templates: Tables: 4f. Generating a single tag of a HTML table
 
 !!end
 
+!!test
+Templates: Wiki Tables: 1. Fostering of entire template content
+!!input
+{|
+{{echo|a}}
+|}
+!!result
+<table>
+a
+<tr><td></td></tr></table>
+
+!!end
+
+!!test
+Templates: Wiki Tables: 2. Fostering of partial template content
+!!input
+{|
+{{echo|a
+<div>b</div>}}
+|}
+!!result
+<table>
+a
+<div>b</div>
+<tr><td></td></tr></table>
+
+!!end
+
+!!test
+Templates: Wiki Tables: 3. td-content via multiple templates
+!!input
+{|
+{{echo|{{pipe}}a}}{{echo|b}}
+|}
+!!result
+<table>
+<tr>
+<td>ab
+</td></tr></table>
+
+!!end
+
+!!test
+Templates: Lists: Multi-line list-items via templates
+!!input
+*{{echo|a {{nonexistent|
+unused}}}}
+*{{echo|b {{nonexistent|
+unused}}}}
+!!result
+<ul><li>a <a href="/index.php?title=Template:Nonexistent&amp;action=edit&amp;redlink=1" class="new" title="Template:Nonexistent (page does not exist)">Template:Nonexistent</a>
+</li><li>b <a href="/index.php?title=Template:Nonexistent&amp;action=edit&amp;redlink=1" class="new" title="Template:Nonexistent (page does not exist)">Template:Nonexistent</a>
+</li></ul>
+
+!!end
+
 !!test
 Templates: Ugly nesting: 1. Quotes opened/closed across templates (echo)
 !!input
@@ -10176,6 +10427,29 @@ Bug 529: Uncovered bullet
 
 !! end
 
+# Plain MediaWiki does not remove empty lists, but tidy actually does.
+# Templates in Wikipedia rely on this behavior, as tidy has always been
+# enabled there. These tests are normally run *without* tidy, so specify the
+# full output here. 
+# To test realistic parsing behavior, apply a tidy-like transformation to both
+# the expected output and your parser's output.
+!! test
+Bug 529: Uncovered bullet leaving empty list, normally removed by tidy
+!! input
+******* Foo {{bullet}}
+!! result
+<ul><li><ul><li><ul><li><ul><li><ul><li><ul><li><ul><li> Foo 
+</li></ul>
+</li></ul>
+</li></ul>
+</li></ul>
+</li></ul>
+</li></ul>
+</li><li> Bar
+</li></ul>
+
+!! end
+
 !! test
 Bug 529: Uncovered table already at line-start
 !! input
@@ -11587,7 +11861,7 @@ Headings: 0. Unnested
 !!end
 
 !! test
-Headings: 1. Nested inside html 
+Headings: 1. Nested inside html
 !! options
 disabled
 !! input
@@ -11624,7 +11898,7 @@ disabled
 !!end
 
 !! test
-Headings: 3. Nested inside html with wikitext split by html tags 
+Headings: 3. Nested inside html with wikitext split by html tags
 !! options
 disabled
 !! input
@@ -11696,7 +11970,7 @@ disabled
 #### ----------------------------------------
 
 !! test
-Lists: 0. Outside nests 
+Lists: 0. Outside nests
 !! input
 <nowiki>*foo</nowiki>
 
@@ -11840,7 +12114,7 @@ disabled
 !!end
 
 !! test
-Lists: 7. Escape bullets in a multi-line context 
+Lists: 7. Escape bullets in a multi-line context
 !! input
 <nowiki>a
 *b</nowiki>
@@ -11855,7 +12129,7 @@ Lists: 7. Escape bullets in a multi-line context
 #### -----------------------------------
 
 !! test
-HRs: 1. Single line 
+HRs: 1. Single line
 !! options
 disabled
 !! input
@@ -12189,7 +12463,7 @@ disabled
 
 !! test
 2. Link fragments inside <i> and <b>
-(FIXME: Escaping one or both of [[ and ]] is also acceptable -- 
+(FIXME: Escaping one or both of [[ and ]] is also acceptable --
  this is one of the shortcomings of this format)
 !! input
 ''[[foo''<nowiki>]]</nowiki>
diff --git a/tests/phpunit/AutoLoaderTest.php b/tests/phpunit/AutoLoaderTest.php
new file mode 100644 (file)
index 0000000..c8f3868
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+class AutoLoaderTest extends MediaWikiTestCase {
+
+       public function testAutoLoadConfig() {
+               $results = self::checkAutoLoadConf();
+
+               $this->assertEquals(
+                       $results['expected'],
+                       $results['actual']
+               );
+       }
+
+       protected static function checkAutoLoadConf() {
+               global $wgAutoloadLocalClasses, $wgAutoloadClasses, $IP;
+               static $supportsParsekit;
+               $supportsParsekit = function_exists( 'parsekit_compile_file' );
+
+               // wgAutoloadLocalClasses has precedence, just like in includes/AutoLoader.php
+               $expected = $wgAutoloadLocalClasses + $wgAutoloadClasses;
+               $actual = array();
+
+               $files = array_unique( $expected );
+
+               foreach ( $files as $file ) {
+                       // Only prefix $IP if it doesn't have it already.
+                       // Generally local classes don't have it, and those from extensions and test suites do.
+                       if ( substr( $file, 0, 1 ) != '/' && substr( $file, 1, 1 ) != ':' ) {
+                               $filePath = "$IP/$file";
+                       } else {
+                               $filePath = $file;
+                       }
+                       if ( $supportsParsekit ) {
+                               $parseInfo = parsekit_compile_file( "$filePath" );
+                               $classes = array_keys( $parseInfo['class_table'] );
+                       } else {
+                               $contents = file_get_contents( "$filePath" );
+                               $m = array();
+                               preg_match_all( '/\n\s*(?:final)?\s*(?:abstract)?\s*(?:class|interface)\s+([a-zA-Z0-9_]+)/', $contents, $m, PREG_PATTERN_ORDER );
+                               $classes = $m[1];
+                       }
+                       foreach ( $classes as $class ) {
+                               $actual[$class] = $file;
+                       }
+               }
+
+               return array(
+                       'expected' => $expected,
+                       'actual' => $actual,
+               );
+       }
+}
index eee5f37..b02b08a 100644 (file)
@@ -1,7 +1,13 @@
 <?php
 
 /**
- * @group Editing      
+ * @group Editing
+ *
+ * @group Database
+ *        ^--- tell jenkins this test needs the database
+ *
+ * @group medium
+ *        ^--- tell phpunit that these test cases may take longer than 2 seconds.
  */
 class EditPageTest extends MediaWikiTestCase {
 
@@ -37,4 +43,387 @@ class EditPageTest extends MediaWikiTestCase {
                        ),
                );
        }
+
+       protected function forceRevisionDate( WikiPage $page, $timestamp ) {
+               $dbw = wfGetDB( DB_MASTER );
+
+               $dbw->update( 'revision',
+                       array( 'rev_timestamp' => $timestamp ),
+                       array( 'rev_id' => $page->getLatest() ) );
+
+               $page->clear();
+       }
+
+       /**
+        * User input text is passed to rtrim() by edit page. This is a simple
+        * wrapper around assertEquals() which calls rrtrim() to normalize the
+        * expected and actual texts.
+        */
+       function assertEditedTextEquals( $expected, $actual, $msg='' ) {
+               return $this->assertEquals( rtrim($expected), rtrim($actual), $msg );
+       }
+
+       /**
+        * Performs an edit and checks the result.
+        *
+        * @param String|Title $title The title of the page to edit
+        * @param String|null $baseText Some text to create the page with before attempting the edit.
+        * @param User|String|null $user The user to perform the edit as.
+        * @param array $edit An array of request parameters used to define the edit to perform.
+        *              Some well known fields are:
+        *              * wpTextbox1: the text to submit
+        *              * wpSummary: the edit summary
+        *              * wpEditToken: the edit token (will be inserted if not provided)
+        *              * wpEdittime: timestamp of the edit's base revision (will be inserted if not provided)
+        *              * wpStarttime: timestamp when the edit started (will be inserted if not provided)
+        *              * wpSectionTitle: the section to edit
+        *              * wpMinorEdit: mark as minor edit
+        *              * wpWatchthis: whether to watch the page
+        * @param int|null $expectedCode The expected result code (EditPage::AS_XXX constants).
+        *                  Set to null to skip the check. Defaults to EditPage::AS_OK.
+        * @param String|null $expectedText The text expected to be on the page after the edit.
+        *                  Set to null to skip the check.
+        * @param String|null $message An optional message to show along with any error message.
+        *
+        * @return WikiPage The page that was just edited, useful for getting the edit's rev_id, etc.
+        */
+       protected function assertEdit( $title, $baseText, $user = null, array $edit,
+               $expectedCode = EditPage::AS_OK, $expectedText = null, $message = null
+       ) {
+               if ( is_string( $title ) ) {
+                       $ns = $this->getDefaultWikitextNS();
+                       $title = Title::newFromText( $title, $ns );
+               }
+
+               if ( is_string( $user ) ) {
+                       $user = User::newFromName( $user );
+
+                       if ( $user->getId() === 0 ) {
+                               $user->addToDatabase();
+                       }
+               }
+
+               $page = WikiPage::factory( $title );
+
+               if ( $baseText !== null ) {
+                       $content = ContentHandler::makeContent( $baseText, $title );
+                       $page->doEditContent( $content, "base text for test" );
+                       $this->forceRevisionDate( $page, '20120101000000' );
+
+                       //sanity check
+                       $page->clear();
+                       $currentText = ContentHandler::getContentText( $page->getContent() );
+
+                       # EditPage rtrim() the user input, so we alter our expected text
+                       # to reflect that.
+                       $this->assertEditedTextEquals( $baseText, $currentText );
+               }
+
+               if ( $user == null ) {
+                       $user = $GLOBALS['wgUser'];
+               } else {
+                       $this->setMwGlobals( 'wgUser', $user );
+               }
+
+               if ( !isset( $edit['wpEditToken'] ) ) {
+                       $edit['wpEditToken'] = $user->getEditToken();
+               }
+
+               if ( !isset( $edit['wpEdittime'] ) ) {
+                       $edit['wpEdittime'] = $page->exists() ? $page->getTimestamp() : '';
+               }
+
+               if ( !isset( $edit['wpStarttime'] ) ) {
+                       $edit['wpStarttime'] = wfTimestampNow();
+               }
+
+               $req = new FauxRequest( $edit, true ); // session ??
+
+               $ep = new EditPage( new Article( $title ) );
+               $ep->setContextTitle( $title );
+               $ep->importFormData( $req );
+
+               $bot = isset( $edit['bot'] ) ? (bool)$edit['bot'] : false;
+
+               // this is where the edit happens!
+               // Note: don't want to use EditPage::AttemptSave, because it messes with $wgOut
+               // and throws exceptions like PermissionsError
+               $status = $ep->internalAttemptSave( $result, $bot );
+
+               if ( $expectedCode !== null ) {
+                       // check edit code
+                       $this->assertEquals( $expectedCode, $status->value,
+                               "Expected result code mismatch. $message" );
+               }
+
+               $page = WikiPage::factory( $title );
+
+               if ( $expectedText !== null ) {
+                       // check resulting page text
+                       $content = $page->getContent();
+                       $text = ContentHandler::getContentText( $content );
+
+                       # EditPage rtrim() the user input, so we alter our expected text
+                       # to reflect that.
+                       $this->assertEditedTextEquals( $expectedText, $text,
+                               "Expected article text mismatch. $message" );
+               }
+
+               return $page;
+       }
+
+       public function testCreatePage() {
+               $text = "Hello World!";
+               $edit = array(
+                       'wpTextbox1' => $text,
+                       'wpSummary' => 'just testing',
+               );
+
+               $this->assertEdit( 'EditPageTest_testCreatePafe', null, null, $edit,
+                       EditPage::AS_SUCCESS_NEW_ARTICLE, $text,
+                       "expected successfull creation with given text" );
+       }
+
+       public function testUpdatePage() {
+               $text = "one";
+               $edit = array(
+                       'wpTextbox1' => $text,
+                       'wpSummary' => 'first update',
+               );
+
+               $page = $this->assertEdit( 'EditPageTest_testUpdatePage', "zero", null, $edit,
+                       EditPage::AS_SUCCESS_UPDATE, $text,
+                       "expected successfull update with given text" );
+
+               $this->forceRevisionDate( $page, '20120101000000' );
+
+               $text = "two";
+               $edit = array(
+                       'wpTextbox1' => $text,
+                       'wpSummary' => 'second update',
+               );
+
+               $this->assertEdit( 'EditPageTest_testUpdatePage', null, null, $edit,
+                       EditPage::AS_SUCCESS_UPDATE, $text,
+                       "expected successfull update with given text" );
+       }
+
+       public static function provideSectionEdit() {
+               $text =
+'Intro
+
+== one ==
+first section.
+
+== two ==
+second section.
+';
+
+               $sectionOne =
+'== one ==
+hello
+';
+
+               $newSection =
+'== new section ==
+
+hello
+';
+
+               $textWithNewSectionOne = preg_replace( '/== one ==.*== two ==/ms',
+                                                                               "$sectionOne\n== two ==", $text );
+
+               $textWithNewSectionAdded = "$text\n$newSection";
+
+               return array(
+                       array( #0
+                               $text,
+                               '',
+                               'hello',
+                               'replace all',
+                               'hello'
+                       ),
+
+                       array( #1
+                               $text,
+                               '1',
+                               $sectionOne,
+                               'replace first section',
+                               $textWithNewSectionOne,
+                       ),
+
+                       array( #2
+                               $text,
+                               'new',
+                               'hello',
+                               'new section',
+                               $textWithNewSectionAdded,
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider provideSectionEdit
+        */
+       public function testSectionEdit( $base, $section, $text, $summary, $expected ) {
+               $edit = array(
+                       'wpTextbox1' => $text,
+                       'wpSummary' => $summary,
+                       'wpSection' => $section,
+               );
+
+               $this->assertEdit( 'EditPageTest_testSectionEdit', $base, null, $edit,
+                       EditPage::AS_SUCCESS_UPDATE, $expected,
+                       "expected successfull update of section" );
+       }
+
+       public static function provideAutoMerge() {
+               $tests = array();
+
+               $tests[] = array( #0: plain conflict
+                       "Elmo", # base edit user
+                       "one\n\ntwo\n\nthree\n",
+                       array( #adam's edit
+                               'wpStarttime' => 1,
+                               'wpTextbox1' => "ONE\n\ntwo\n\nthree\n",
+                       ),
+                       array( #berta's edit
+                               'wpStarttime' => 2,
+                               'wpTextbox1' => "(one)\n\ntwo\n\nthree\n",
+                       ),
+                       EditPage::AS_CONFLICT_DETECTED, # expected code
+                       "ONE\n\ntwo\n\nthree\n", # expected text
+                       'expected edit conflict', # message
+               );
+
+               $tests[] = array( #1: successful merge
+                       "Elmo", # base edit user
+                       "one\n\ntwo\n\nthree\n",
+                       array( #adam's edit
+                               'wpStarttime' => 1,
+                               'wpTextbox1' => "ONE\n\ntwo\n\nthree\n",
+                       ),
+                       array( #berta's edit
+                               'wpStarttime' => 2,
+                               'wpTextbox1' => "one\n\ntwo\n\nTHREE\n",
+                       ),
+                       EditPage::AS_SUCCESS_UPDATE, # expected code
+                       "ONE\n\ntwo\n\nTHREE\n", # expected text
+                       'expected automatic merge', # message
+               );
+
+               $text = "Intro\n\n";
+               $text .= "== first section ==\n\n";
+               $text .= "one\n\ntwo\n\nthree\n\n";
+               $text .= "== second section ==\n\n";
+               $text .= "four\n\nfive\n\nsix\n\n";
+
+               // extract the first section.
+               $section = preg_replace( '/.*(== first section ==.*)== second section ==.*/sm', '$1', $text );
+
+               // generate expected text after merge
+               $expected = str_replace( 'one', 'ONE', str_replace( 'three', 'THREE', $text ) );
+
+               $tests[] = array( #2: merge in section
+                       "Elmo", # base edit user
+                       $text,
+                       array( #adam's edit
+                               'wpStarttime' => 1,
+                               'wpTextbox1' => str_replace( 'one', 'ONE', $section ),
+                               'wpSection' => '1'
+                       ),
+                       array( #berta's edit
+                               'wpStarttime' => 2,
+                               'wpTextbox1' => str_replace( 'three', 'THREE', $section ),
+                               'wpSection' => '1'
+                       ),
+                       EditPage::AS_SUCCESS_UPDATE, # expected code
+                       $expected, # expected text
+                       'expected automatic section merge', # message
+               );
+
+               // see whether it makes a difference who did the base edit
+               $testsWithAdam = array_map( function( $test ) {
+                       $test[0] = 'Adam'; // change base edit user
+                       return $test;
+               }, $tests );
+
+               $testsWithBerta = array_map( function( $test ) {
+                       $test[0] = 'Berta'; // change base edit user
+                       return $test;
+               }, $tests );
+
+               return array_merge( $tests, $testsWithAdam, $testsWithBerta );
+       }
+
+       function testHasValidDiff3() {
+               global $wgDiff3;
+
+               if ( !$wgDiff3 ) {
+                       $this->markTestSkipped( "Can't test conflict resolution because \$wgDiff3 is not configured" );
+               } elseif ( !file_exists( $wgDiff3 ) ) {
+                       #XXX: this sucks, since it uses arcane internal knowledge about TextContentHandler::merge3 and wfMerge.
+                       $this->markTestSkipped( "Can't test conflict resolution because \$wgDiff3 is misconfigured: can't find $wgDiff3" );
+               }
+               $this->assertTrue( true );
+       }
+
+       /**
+        * @depend testHasValidDiff3
+        * @dataProvider provideAutoMerge
+        */
+       public function testAutoMerge( $baseUser, $text, $adamsEdit, $bertasEdit,
+                               $expectedCode, $expectedText, $message = null
+       ) {
+
+               //create page
+               $ns = $this->getDefaultWikitextNS();
+               $title = Title::newFromText( 'EditPageTest_testAutoMerge', $ns );
+               $page = WikiPage::factory( $title );
+
+               if ( $page->exists() ) {
+                       $page->doDeleteArticle( "clean slate for testing" );
+               }
+
+               $baseEdit = array(
+                       'wpTextbox1' => $text,
+               );
+
+               $page = $this->assertEdit( 'EditPageTest_testAutoMerge', null,
+                                       $baseUser, $baseEdit, null, null, __METHOD__ );
+
+               $this->forceRevisionDate( $page, '20120101000000' );
+
+               $edittime = $page->getTimestamp();
+
+               // start timestamps for conflict detection
+               if ( !isset( $adamsEdit['wpStarttime'] ) ) {
+                       $adamsEdit['wpStarttime'] = 1;
+               }
+
+               if ( !isset( $bertasEdit['wpStarttime'] ) ) {
+                       $bertasEdit['wpStarttime'] = 2;
+               }
+
+               $starttime = wfTimestampNow();
+               $adamsTime = wfTimestamp( TS_MW, (int)wfTimestamp( TS_UNIX, $starttime ) + (int)$adamsEdit['wpStarttime'] );
+               $bertasTime = wfTimestamp( TS_MW, (int)wfTimestamp( TS_UNIX, $starttime ) + (int)$bertasEdit['wpStarttime'] );
+
+               $adamsEdit['wpStarttime'] = $adamsTime;
+               $bertasEdit['wpStarttime'] = $bertasTime;
+
+               $adamsEdit['wpSummary'] = 'Adam\'s edit';
+               $bertasEdit['wpSummary'] = 'Bertas\'s edit';
+
+               $adamsEdit['wpEdittime'] = $edittime;
+               $bertasEdit['wpEdittime'] = $edittime;
+
+               // first edit
+               $this->assertEdit( 'EditPageTest_testAutoMerge', null, 'Adam', $adamsEdit,
+                       EditPage::AS_SUCCESS_UPDATE, null, "expected successfull update" );
+
+               // second edit
+               $this->assertEdit( 'EditPageTest_testAutoMerge', null, 'Berta', $bertasEdit,
+                       $expectedCode, $expectedText, $message );
+       }
 }
index e8aabfd..7304bd9 100644 (file)
@@ -488,6 +488,86 @@ class GlobalTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @param String $old: Text as it was in the database
+        * @param String $mine: Text submitted while user was editing
+        * @param String $yours: Text submitted by the user
+        * @param Boolean $expectedMergeResult Whether the merge should be a success
+        * @param String $expectedText: Text after merge has been completed
+        *
+        * @dataProvider provideMerge()
+        */
+       public function testMerge( $old, $mine, $yours, $expectedMergeResult, $expectedText ) {
+               $mergedText = null;
+               $isMerged = wfMerge( $old, $mine, $yours, $mergedText );
+
+               $msg = 'Merge should be a ';
+               $msg .= $expectedMergeResult ? 'success' : 'failure';
+               $this->assertEquals( $expectedMergeResult, $isMerged, $msg );
+
+               if( $isMerged ) {
+                       // Verify the merged text
+                       $this->assertEquals( $expectedText, $mergedText,
+                               'is merged text as expected?' );
+               }
+       }
+
+       public static function provideMerge() {
+               $EXPECT_MERGE_SUCCESS = true;
+               $EXPECT_MERGE_FAILURE = false;
+
+               return array(
+
+                       // #0: clean merge
+                       array(
+                               // old:
+                               "one one one\n" . // trimmed
+                               "\n" .
+                               "two two two",
+
+                               // mine:
+                               "one one one ONE ONE\n" .
+                               "\n" .
+                               "two two two\n", // with tailing whitespace
+
+                               // yours:
+                               "one one one\n" .
+                               "\n" .
+                               "two two TWO TWO", // trimmed
+
+                               // ok:
+                               $EXPECT_MERGE_SUCCESS,
+
+                               // result:
+                               "one one one ONE ONE\n" .
+                               "\n" .
+                               "two two TWO TWO\n", // note: will always end in a newline
+                       ),
+
+                       // #1: conflict, fail
+                       array(
+                               // old:
+                               "one one one", // trimmed
+
+                               // mine:
+                               "one one one ONE ONE\n" .
+                               "\n" .
+                               "bla bla\n" .
+                               "\n", // with tailing whitespace
+
+                               // yours:
+                               "one one one\n" .
+                               "\n" .
+                               "two two", // trimmed
+
+                               $EXPECT_MERGE_FAILURE,
+
+                               // result:
+                               null,
+                       ),
+               );
+       }
+
        /**
         * @dataProvider provideMakeUrlIndexes()
         */
diff --git a/tests/phpunit/includes/RequestContextTest.php b/tests/phpunit/includes/RequestContextTest.php
new file mode 100644 (file)
index 0000000..48cf6dc
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+class RequestContextTest extends MediaWikiTestCase {
+
+       /**
+        * Test the relationship between title and wikipage in RequestContext
+        */
+       public function testWikiPageTitle() {
+               $context = new RequestContext();
+
+               $curTitle = Title::newFromText( "A" );
+               $context->setTitle( $curTitle );
+               $this->assertTrue( $curTitle->equals( $context->getWikiPage()->getTitle() ),
+                       "When a title is first set WikiPage should be created on-demand for that title." );
+
+               $curTitle = Title::newFromText( "B" );
+               $context->setWikiPage( WikiPage::factory( $curTitle ) );
+               $this->assertTrue( $curTitle->equals( $context->getTitle() ),
+                       "Title must be updated when a new WikiPage is provided." );
+
+               $curTitle = Title::newFromText( "C" );
+               $context->setTitle( $curTitle );
+               $this->assertTrue( $curTitle->equals( $context->getWikiPage()->getTitle() ),
+                       "When a title is updated the WikiPage should be purged and recreated on-demand with the new title." );
+
+       }
+
+}
index fbaa34c..4fa42f3 100644 (file)
@@ -268,6 +268,25 @@ class RevisionStorageTest extends MediaWikiTestCase {
                $this->assertEquals( 'hello hello.', $rev->getText() );
        }
 
+       /**
+        * @covers Revision::getContent
+        */
+       public function testGetContent_failure()
+       {
+               $rev = new Revision( array(
+                       'page'       =>  $this->the_page->getId(),
+                       'content_model' => $this->the_page->getContentModel(),
+                       'text_id' => 123456789, // not in the test DB
+               ) );
+
+               $this->assertNull( $rev->getContent(),
+                       "getContent() should return null if the revision's text blob could not be loaded." );
+
+               //NOTE: check this twice, once for lazy initialization, and once with the cached value.
+               $this->assertNull( $rev->getContent(),
+                       "getContent() should return null if the revision's text blob could not be loaded." );
+       }
+
        /**
         * @covers Revision::getContent
         */
index 0a3f6f6..8647954 100644 (file)
@@ -126,11 +126,11 @@ class TitleTest extends MediaWikiTestCase {
                # - wgDefaultLanguageVariant
                # - Optional message
                return array(
-                       array( 'fr', 'Main_page', 'fr', 'fr', false ),
-                       array( 'es', 'Main_page', 'es', 'zh-tw', false ),
-                       array( 'zh', 'Main_page', 'zh', 'zh-tw', false ),
+                       array( 'fr', 'Help:I_need_somebody', 'fr', 'fr', false ),
+                       array( 'es', 'Help:I_need_somebody', 'es', 'zh-tw', false ),
+                       array( 'zh', 'Help:I_need_somebody', 'zh', 'zh-tw', false ),
 
-                       array( 'es',    'Main_page',                 'es', 'zh-tw', 'zh-cn' ),
+                       array( 'es',    'Help:I_need_somebody',      'es', 'zh-tw', 'zh-cn' ),
                        array( 'es',    'MediaWiki:About',           'es', 'zh-tw', 'zh-cn' ),
                        array( 'es',    'MediaWiki:About/',          'es', 'zh-tw', 'zh-cn' ),
                        array( 'de',    'MediaWiki:About/de',        'es', 'zh-tw', 'zh-cn' ),
@@ -139,7 +139,7 @@ class TitleTest extends MediaWikiTestCase {
                        array( 'en',    'User:JohnDoe/Common.js',    'es', 'zh-tw', 'zh-cn' ),
                        array( 'en',    'User:JohnDoe/Monobook.css', 'es', 'zh-tw', 'zh-cn' ),
 
-                       array( 'zh-cn', 'Main_page',                 'zh', 'zh-tw', 'zh-cn' ),
+                       array( 'zh-cn', 'Help:I_need_somebody',      'zh', 'zh-tw', 'zh-cn' ),
                        array( 'zh',    'MediaWiki:About',           'zh', 'zh-tw', 'zh-cn' ),
                        array( 'zh',    'MediaWiki:About/',          'zh', 'zh-tw', 'zh-cn' ),
                        array( 'de',    'MediaWiki:About/de',        'zh', 'zh-tw', 'zh-cn' ),
index bf9468a..e5a014d 100644 (file)
@@ -173,7 +173,7 @@ class UserTest extends MediaWikiTestCase {
                $user->addToDatabase();
 
                // let the user have a few (3) edits
-               $page = WikiPage::factory( Title::newFromText( 'UserTest_EditCount' ) );
+               $page = WikiPage::factory( Title::newFromText( 'Help:UserTest_EditCount' ) );
                for( $i = 0; $i < 3; $i++ ) {
                        $page->doEdit( (string) $i, 'test', 0, false, $user );
                }
index c867a83..52e168b 100644 (file)
@@ -21,7 +21,8 @@ class TextContentTest extends MediaWikiTestCase {
                                CONTENT_MODEL_WIKITEXT,
                                CONTENT_MODEL_CSS,
                                CONTENT_MODEL_JAVASCRIPT,
-                       )
+                       ),
+                       'wgAlwaysUseTidy' => false,
                ) );
 
                $this->context = new RequestContext( new FauxRequest() );
@@ -378,4 +379,49 @@ class TextContentTest extends MediaWikiTestCase {
                }
        }
 
+       public static function provideConvert() {
+               return array(
+                       array( // #0
+                               'Hallo Welt',
+                               CONTENT_MODEL_WIKITEXT,
+                               'lossless',
+                               'Hallo Welt'
+                       ),
+                       array( // #1
+                               'Hallo Welt',
+                               CONTENT_MODEL_WIKITEXT,
+                               'lossless',
+                               'Hallo Welt'
+                       ),
+                       array( // #1
+                               'Hallo Welt',
+                               CONTENT_MODEL_CSS,
+                               'lossless',
+                               'Hallo Welt'
+                       ),
+                       array( // #1
+                               'Hallo Welt',
+                               CONTENT_MODEL_JAVASCRIPT,
+                               'lossless',
+                               'Hallo Welt'
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider provideConvert
+        */
+       public function testConvert( $text, $model, $lossy, $expectedNative ) {
+               $content = $this->newContent( $text );
+
+               $converted = $content->convert( $model, $lossy );
+
+               if ( $expectedNative === false ) {
+                       $this->assertFalse( $converted, "conversion to $model was expected to fail!" );
+               } else {
+                       $this->assertInstanceOf( 'Content', $converted );
+                       $this->assertEquals( $expectedNative, $converted->getNativeData() );
+               }
+       }
+
 }
index 9dcaf2b..cd970b3 100644 (file)
@@ -155,12 +155,11 @@ abstract class ORMRowTest extends \MediaWikiTestCase {
 
        /**
         * @dataProvider constructorTestProvider
+        * @depends testSave()
         */
        public function testRemove( array $data, $loadDefaults ) {
                $item = $this->getRowInstance( $data, $loadDefaults );
 
-               $this->assertTrue( $item->save() );
-
                $this->assertTrue( $item->remove() );
 
                $this->assertFalse( $item->hasIdField() );
diff --git a/tests/phpunit/includes/db/ORMTableTest.php b/tests/phpunit/includes/db/ORMTableTest.php
new file mode 100644 (file)
index 0000000..2ed3dd3
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Abstract class to construct tests for ORMTable deriving classes.
+ *
+ * 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.21
+ *
+ * @ingroup Test
+ *
+ * @group ORM
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+abstract class ORMTableTest extends MediaWikiTestCase {
+
+       /**
+        * @since 1.21
+        * @return string
+        */
+       protected abstract function getTableClass();
+
+       /**
+        * @since 1.21
+        * @return IORMTable
+        */
+       public function getTable() {
+               $class = $this->getTableClass();
+               return $class::singleton();
+       }
+
+       /**
+        * @since 1.21
+        * @return string
+        */
+       public function getRowClass() {
+               return $this->getTable()->getRowClass();
+       }
+
+       /**
+        * @since 1.21
+        */
+       public function testSingleton() {
+               $class = $this->getTableClass();
+
+               $this->assertInstanceOf( $class, $class::singleton() );
+               $this->assertTrue( $class::singleton() === $class::singleton() );
+       }
+
+}
index c7bea3b..e33ae01 100644 (file)
@@ -87,6 +87,7 @@ class TestORMRowTest extends ORMRowTest {
                        array(
                                array(
                                        'name' => 'Foobar',
+                                       'time' => '20120101020202',
                                        'age' => 42,
                                        'height' => 9000.1,
                                        'awesome' => true,
index da36e90..b6d44fd 100644 (file)
@@ -1181,6 +1181,50 @@ class FileBackendTest extends MediaWikiTestCase {
                $this->assertEquals( null, $tmpFile, "Local ref of not existing file is null ($backendName)." );
        }
 
+       /**
+        * @dataProvider provider_testGetFileHttpUrl
+        */
+       public function testGetFileHttpUrl( $source, $content ) {
+               $this->backend = $this->singleBackend;
+               $this->tearDownFiles();
+               $this->doTestGetFileHttpUrl( $source, $content );
+               $this->tearDownFiles();
+
+               $this->backend = $this->multiBackend;
+               $this->tearDownFiles();
+               $this->doTestGetFileHttpUrl( $source, $content );
+               $this->tearDownFiles();
+       }
+
+       private function doTestGetFileHttpUrl( $source, $content ) {
+               $backendName = $this->backendClass();
+
+               $this->prepare( array( 'dir' => dirname( $source ) ) );
+               $status = $this->backend->doOperation(
+                       array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
+               $this->assertGoodStatus( $status,
+                       "Creation of file at $source succeeded ($backendName)." );
+
+               $url = $this->backend->getFileHttpUrl( array( 'src' => $source ) );
+
+               if ( $url !== null ) { // supported
+                       $data = Http::request( "GET", $url );
+                       $this->assertEquals( $content, $data,
+                               "HTTP GET of URL has right contents ($backendName)." );
+               }
+       }
+
+       function provider_testGetFileHttpUrl() {
+               $cases = array();
+
+               $base = self::baseStorePath();
+               $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
+               $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
+               $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
+
+               return $cases;
+       }
+
        /**
         * @dataProvider provider_testPrepareAndClean
         */
index d089aff..292f13a 100644 (file)
@@ -12,7 +12,13 @@ class TagHookTest extends MediaWikiTestCase {
        public static function provideBadNames() {
                return array( array( "foo<bar" ), array( "foo>bar" ), array( "foo\nbar" ),  array( "foo\rbar" ) );
        }
-               
+
+       protected function setUp() {
+               parent::setUp();
+
+               $this->setMwGlobals( 'wgAlwaysUseTidy', false );
+       }
+
        /**
         * @dataProvider provideValidNames
         */
index e8358f3..207f46c 100644 (file)
@@ -25,6 +25,7 @@
  * @ingroup Test
  *
  * @group Site
+ * @group Database
  *
  * @licence GNU GPL v2+
  * @author Jeroen De Dauw < jeroendedauw@gmail.com >
@@ -57,9 +58,9 @@ class SiteObjectTest extends ORMRowTest {
        public function constructorTestProvider() {
                $argLists = array();
 
-               $argLists[] = array( 'global_key' => '42' );
+               $argLists[] = array( 'global_key' => 'foo' );
 
-               $argLists[] = array( 'global_key' => '42', 'type' => Site::TYPE_MEDIAWIKI );
+               $argLists[] = array( 'global_key' => 'bar', 'type' => Site::TYPE_MEDIAWIKI );
 
                $constructorArgs = array();
 
@@ -229,6 +230,17 @@ class SiteObjectTest extends ORMRowTest {
                $this->assertEquals( $path, $site->getPath( 'foo' ) );
        }
 
+       public function testProtocolRelativePath() {
+               /* @var SiteObject $site */
+               $site = $this->getRowInstance( $this->getMockFields(), false );
+
+               $type = $site->getLinkPathType();
+               $path = '//acme.com/'; // protocol-relative URL
+               $site->setPath( $type, $path );
+
+               $this->assertEquals( '', $site->getProtocol() );
+       }
+
        public function provideGetPageUrl() {
                //NOTE: the assumption that the URL is built by replacing $1
                //      with the urlencoded version of $page
index 5ca2bc9..575b277 100644 (file)
@@ -37,4 +37,41 @@ class LanguageHeTest extends LanguageClassesTestCase {
                        array( 'other', 3 ), // Plural
                );
        }
+
+       /** @dataProvider providerGrammar */
+       function testGrammar( $result, $word, $case ) {
+               $this->assertEquals( $result, $this->getLang()->convertGrammar( $word, $case ) );
+       }
+
+       // The comments in the beginning of the line help avoid RTL problems
+       // with text editors.
+       function providerGrammar() {
+               return array (
+                       array(
+                               /* result */ 'וויקיפדיה',
+                               /* word   */ 'ויקיפדיה',
+                               /* case   */ 'תחילית',
+                       ),
+                       array(
+                               /* result */ 'וולפגנג',
+                               /* word   */ 'וולפגנג',
+                               /* case   */ 'prefixed',
+                       ),
+                       array(
+                               /* result */ 'קובץ',
+                               /* word   */ 'הקובץ',
+                               /* case   */ 'תחילית',
+                       ),
+                       array(
+                               /* result */ '־Wikipedia',
+                               /* word   */ 'Wikipedia',
+                               /* case   */ 'תחילית',
+                       ),
+                       array(
+                               /* result */ '־1995',
+                               /* word   */ '1995',
+                               /* case   */ 'תחילית',
+                       ),
+               );
+       }
 }
index 7079e0e..911dc3a 100644 (file)
@@ -135,6 +135,9 @@ class GenerateJqueryMsgData extends Maintenance {
                        . "// languages, and parser modes. Intended for use by a unit test framework by looping\n"
                        . "// through the object and comparing its parser return value with the 'result' property.\n"
                        . '// Last generated with ' . basename( __FILE__ ) . ' at ' . gmdate( 'r' ) . "\n"
+                       // This file will contain unquoted JSON strings as javascript native object literals,
+                       // flip the quotemark convention for this file.
+                       . "/*jshint quotmark: double */\n"
                        . "\n"
                        . 'mediaWiki.libs.phpParserData = ' . FormatJson::encode( $phpParserData, true ) . ";\n";
 
index 05bb5c8..776ee24 100644 (file)
@@ -1,7 +1,8 @@
 // This file stores the output from the PHP parser for various messages, arguments,
 // languages, and parser modes. Intended for use by a unit test framework by looping
 // through the object and comparing its parser return value with the 'result' property.
-// Last generated with generateJqueryMsgData.php at Sun, 07 Oct 2012 07:30:16 +0000
+// Last generated with generateJqueryMsgData.php at Sat, 03 Nov 2012 21:32:01 +0000
+/*jshint quotmark: double */
 
 mediaWiki.libs.phpParserData = {
        "messages": {
index efa6549..0c3d364 100644 (file)
-( function ( $, mw, QUnit, undefined ) {
 /*global CompletenessTest */
-/*jshint evil:true */
-'use strict';
-
-var mwTestIgnore, mwTester, addons;
-
-/**
- * Add bogus to url to prevent IE crazy caching
- *
- * @param value {String} a relative path (eg. 'data/foo.js'
- * or 'data/test.php?foo=bar').
- * @return {String} Such as 'data/foo.js?131031765087663960'
- */
-QUnit.fixurl = function ( value ) {
-       return value + (/\?/.test( value ) ? '&' : '?')
-               + String( new Date().getTime() )
-               + String( parseInt( Math.random() * 100000, 10 ) );
-};
-
-/**
- * Configuration
- */
-
-// When a test() indicates asynchronicity with stop(),
-// allow 10 seconds to pass before killing the test(),
-// and assuming failure.
-QUnit.config.testTimeout = 10 * 1000;
-
-// Add a checkbox to QUnit header to toggle MediaWiki ResourceLoader debug mode.
-QUnit.config.urlConfig.push( {
-       id: 'debug',
-       label: 'Enable ResourceLoaderDebug',
-       tooltip: 'Enable debug mode in ResourceLoader'
-} );
-
-/**
- * Load TestSwarm agent
- */
-// Only if the current url indicates that there is a TestSwarm instance watching us
-// (TestSwarm appends swarmURL to the test suites url it loads in iframes).
-// Otherwise this is just a simple view of Special:JavaScriptTest/qunit directly,
-// no point in loading inject.js in that case. Also, make sure that this instance
-// of MediaWiki has actually been configured with the required url to that inject.js
-// script. By default it is false.
-if ( QUnit.urlParams.swarmURL && mw.config.get( 'QUnitTestSwarmInjectJSPath' ) ) {
-       document.write( "<scr" + "ipt src='" + QUnit.fixurl( mw.config.get( 'QUnitTestSwarmInjectJSPath' ) ) + "'></scr" + "ipt>" );
-}
-
-/**
- * CompletenessTest
- */
-// Adds toggle checkbox to header
-QUnit.config.urlConfig.push( {
-       id: 'completenesstest',
-       label: 'Run CompletenessTest',
-       tooltip: 'Run the completeness test'
-} );
-
-// Initiate when enabled
-if ( QUnit.urlParams.completenesstest ) {
-
-       // Return true to ignore
-       mwTestIgnore = function ( val, tester, funcPath ) {
-
-               // Don't record methods of the properties of constructors,
-               // to avoid getting into a loop (prototype.constructor.prototype..).
-               // Since we're therefor skipping any injection for
-               // "new mw.Foo()", manually set it to true here.
-               if ( val instanceof mw.Map ) {
-                       tester.methodCallTracker.Map = true;
-                       return true;
-               }
-               if ( val instanceof mw.Title ) {
-                       tester.methodCallTracker.Title = true;
-                       return true;
-               }
-
-               // Don't record methods of the properties of a jQuery object
-               if ( val instanceof $ ) {
-                       return true;
-               }
-
-               return false;
+/*jshint evil: true */
+( function ( $, mw, QUnit, undefined ) {
+       'use strict';
+
+       var mwTestIgnore, mwTester,
+               addons,
+               envExecCount;
+
+       /**
+        * Add bogus to url to prevent IE crazy caching
+        *
+        * @param value {String} a relative path (eg. 'data/foo.js'
+        * or 'data/test.php?foo=bar').
+        * @return {String} Such as 'data/foo.js?131031765087663960'
+        */
+       QUnit.fixurl = function ( value ) {
+               return value + (/\?/.test( value ) ? '&' : '?')
+                       + String( new Date().getTime() )
+                       + String( parseInt( Math.random() * 100000, 10 ) );
        };
 
-       mwTester = new CompletenessTest( mw, mwTestIgnore );
-}
-
-/**
- * Test environment recommended for all QUnit test modules
- */
-// Whether to log environment changes to the console
-QUnit.config.urlConfig.push( 'mwlogenv' );
-
-/**
- * Reset mw.config and others to a fresh copy of the live config for each test(),
- * and restore it back to the live one afterwards.
- * @param localEnv {Object} [optional]
- * @example (see test suite at the bottom of this file)
- * </code>
- */
-QUnit.newMwEnvironment = ( function () {
-       var log, liveConfig, liveMessages;
-
-       liveConfig = mw.config.values;
-       liveMessages = mw.messages.values;
-
-       function freshConfigCopy( custom ) {
-               // "deep=true" is important here.
-               // Otherwise we just create a new object with values referring to live config.
-               // e.g. mw.config.set( 'wgFileExtensions', [] ) would not effect liveConfig,
-               // but mw.config.get( 'wgFileExtensions' ).push( 'png' ) would as the array
-               // was passed by reference in $.extend's loop.
-               return $.extend( {}, liveConfig, custom, /*deep=*/true );
+       /**
+        * Configuration
+        */
+
+       // When a test() indicates asynchronicity with stop(),
+       // allow 10 seconds to pass before killing the test(),
+       // and assuming failure.
+       QUnit.config.testTimeout = 10 * 1000;
+
+       // Add a checkbox to QUnit header to toggle MediaWiki ResourceLoader debug mode.
+       QUnit.config.urlConfig.push( {
+               id: 'debug',
+               label: 'Enable ResourceLoaderDebug',
+               tooltip: 'Enable debug mode in ResourceLoader'
+       } );
+
+       /**
+        * Load TestSwarm agent
+        */
+       // Only if the current url indicates that there is a TestSwarm instance watching us
+       // (TestSwarm appends swarmURL to the test suites url it loads in iframes).
+       // Otherwise this is just a simple view of Special:JavaScriptTest/qunit directly,
+       // no point in loading inject.js in that case. Also, make sure that this instance
+       // of MediaWiki has actually been configured with the required url to that inject.js
+       // script. By default it is false.
+       if ( QUnit.urlParams.swarmURL && mw.config.get( 'QUnitTestSwarmInjectJSPath' ) ) {
+               document.write( '<scr' + 'ipt src="' + QUnit.fixurl( mw.config.get( 'QUnitTestSwarmInjectJSPath' ) ) + '"></scr' + 'ipt>' );
        }
 
-       function freshMessagesCopy( custom ) {
-               return $.extend( {}, liveMessages, custom, /*deep=*/true );
+       /**
+        * CompletenessTest
+        */
+       // Adds toggle checkbox to header
+       QUnit.config.urlConfig.push( {
+               id: 'completenesstest',
+               label: 'Run CompletenessTest',
+               tooltip: 'Run the completeness test'
+       } );
+
+       // Initiate when enabled
+       if ( QUnit.urlParams.completenesstest ) {
+
+               // Return true to ignore
+               mwTestIgnore = function ( val, tester ) {
+
+                       // Don't record methods of the properties of constructors,
+                       // to avoid getting into a loop (prototype.constructor.prototype..).
+                       // Since we're therefor skipping any injection for
+                       // "new mw.Foo()", manually set it to true here.
+                       if ( val instanceof mw.Map ) {
+                               tester.methodCallTracker.Map = true;
+                               return true;
+                       }
+                       if ( val instanceof mw.Title ) {
+                               tester.methodCallTracker.Title = true;
+                               return true;
+                       }
+
+                       // Don't record methods of the properties of a jQuery object
+                       if ( val instanceof $ ) {
+                               return true;
+                       }
+
+                       return false;
+               };
+
+               mwTester = new CompletenessTest( mw, mwTestIgnore );
        }
 
-       log = QUnit.urlParams.mwlogenv ? mw.log : function () {};
+       /**
+        * Test environment recommended for all QUnit test modules
+        */
+       // Whether to log environment changes to the console
+       QUnit.config.urlConfig.push( 'mwlogenv' );
+
+       /**
+        * Reset mw.config and others to a fresh copy of the live config for each test(),
+        * and restore it back to the live one afterwards.
+        * @param localEnv {Object} [optional]
+        * @example (see test suite at the bottom of this file)
+        * </code>
+        */
+       QUnit.newMwEnvironment = ( function () {
+               var log, liveConfig, liveMessages;
+
+               liveConfig = mw.config.values;
+               liveMessages = mw.messages.values;
+
+               function freshConfigCopy( custom ) {
+                       // "deep=true" is important here.
+                       // Otherwise we just create a new object with values referring to live config.
+                       // e.g. mw.config.set( 'wgFileExtensions', [] ) would not effect liveConfig,
+                       // but mw.config.get( 'wgFileExtensions' ).push( 'png' ) would as the array
+                       // was passed by reference in $.extend's loop.
+                       return $.extend( {}, liveConfig, custom, /*deep=*/true );
+               }
 
-       return function ( localEnv ) {
-               localEnv = $.extend( {
-                       // QUnit
-                       setup: $.noop,
-                       teardown: $.noop,
-                       // MediaWiki
-                       config: {},
-                       messages: {}
-               }, localEnv );
+               function freshMessagesCopy( custom ) {
+                       return $.extend( {}, liveMessages, custom, /*deep=*/true );
+               }
 
-               return {
-                       setup: function () {
-                               log( 'MwEnvironment> SETUP    for "' + QUnit.config.current.module
-                                       + ': ' + QUnit.config.current.testName + '"' );
+               log = QUnit.urlParams.mwlogenv ? mw.log : function () {};
+
+               return function ( localEnv ) {
+                       localEnv = $.extend( {
+                               // QUnit
+                               setup: $.noop,
+                               teardown: $.noop,
+                               // MediaWiki
+                               config: {},
+                               messages: {}
+                       }, localEnv );
+
+                       return {
+                               setup: function () {
+                                       log( 'MwEnvironment> SETUP    for "' + QUnit.config.current.module
+                                               + ': ' + QUnit.config.current.testName + '"' );
+
+                                       // Greetings, mock environment!
+                                       mw.config.values = freshConfigCopy( localEnv.config );
+                                       mw.messages.values = freshMessagesCopy( localEnv.messages );
+
+                                       localEnv.setup();
+                               },
+
+                               teardown: function () {
+                                       log( 'MwEnvironment> TEARDOWN for "' + QUnit.config.current.module
+                                               + ': ' + QUnit.config.current.testName + '"' );
+
+                                       localEnv.teardown();
+
+                                       // Farewell, mock environment!
+                                       mw.config.values = liveConfig;
+                                       mw.messages.values = liveMessages;
+                               }
+                       };
+               };
+       }() );
 
-                               // Greetings, mock environment!
-                               mw.config.values = freshConfigCopy( localEnv.config );
-                               mw.messages.values = freshMessagesCopy( localEnv.messages );
+       // $.when stops as soon as one fails, which makes sense in most
+       // practical scenarios, but not in a unit test where we really do
+       // need to wait until all of them are finished.
+       QUnit.whenPromisesComplete = function () {
+               var altPromises = [];
 
-                               localEnv.setup();
-                       },
+               $.each( arguments, function ( i, arg ) {
+                       var alt = $.Deferred();
+                       altPromises.push( alt );
 
-                       teardown: function () {
-                               log( 'MwEnvironment> TEARDOWN for "' + QUnit.config.current.module
-                                       + ': ' + QUnit.config.current.testName + '"' );
+                       // Whether this one fails or not, forwards it to
+                       // the 'done' (resolve) callback of the alternative promise.
+                       arg.always( alt.resolve );
+               });
 
-                               localEnv.teardown();
+               return $.when.apply( $, altPromises );
+       };
 
-                               // Farewell, mock environment!
-                               mw.config.values = liveConfig;
-                               mw.messages.values = liveMessages;
-                       }
-               };
+       /**
+        * Add-on assertion helpers
+        */
+       // Define the add-ons
+       addons = {
+
+               // Expect boolean true
+               assertTrue: function ( actual, message ) {
+                       QUnit.push( actual === true, actual, true, message );
+               },
+
+               // Expect boolean false
+               assertFalse: function ( actual, message ) {
+                       QUnit.push( actual === false, actual, false, message );
+               },
+
+               // Expect numerical value less than X
+               lt: function ( actual, expected, message ) {
+                       QUnit.push( actual < expected, actual, 'less than ' + expected, message );
+               },
+
+               // Expect numerical value less than or equal to X
+               ltOrEq: function ( actual, expected, message ) {
+                       QUnit.push( actual <= expected, actual, 'less than or equal to ' + expected, message );
+               },
+
+               // Expect numerical value greater than X
+               gt: function ( actual, expected, message ) {
+                       QUnit.push( actual > expected, actual, 'greater than ' + expected, message );
+               },
+
+               // Expect numerical value greater than or equal to X
+               gtOrEq: function ( actual, expected, message ) {
+                       QUnit.push( actual >= expected, actual, 'greater than or equal to ' + expected, message );
+               }
        };
-}() );
 
-// $.when stops as soon as one fails, which makes sense in most
-// practical scenarios, but not in a unit test where we really do
-// need to wait until all of them are finished.
-QUnit.whenPromisesComplete = function () {
-       var altPromises = [];
+       $.extend( QUnit.assert, addons );
+
+       /**
+        * Small test suite to confirm proper functionality of the utilities and
+        * initializations defined above in this file.
+        */
+       envExecCount = 0;
+       QUnit.module( 'mediawiki.tests.qunit.testrunner', QUnit.newMwEnvironment({
+               setup: function () {
+                       envExecCount += 1;
+                       this.mwHtmlLive = mw.html;
+                       mw.html = {
+                               escape: function () {
+                                       return 'mocked-' + envExecCount;
+                               }
+                       };
+               },
+               teardown: function () {
+                       mw.html = this.mwHtmlLive;
+               },
+               config: {
+                       testVar: 'foo'
+               },
+               messages: {
+                       testMsg: 'Foo.'
+               }
+       }) );
 
-       $.each( arguments, function ( i, arg ) {
-               var alt = $.Deferred();
-               altPromises.push( alt );
+       QUnit.test( 'Setup', 3, function ( assert ) {
+               assert.equal( mw.html.escape( 'foo' ), 'mocked-1', 'extra setup() callback was ran.' );
+               assert.equal( mw.config.get( 'testVar' ), 'foo', 'config object applied' );
+               assert.equal( mw.messages.get( 'testMsg' ), 'Foo.', 'messages object applied' );
 
-               // Whether this one fails or not, forwards it to
-               // the 'done' (resolve) callback of the alternative promise.
-               arg.always( alt.resolve );
+               mw.config.set( 'testVar', 'bar' );
+               mw.messages.set( 'testMsg', 'Bar.' );
        });
 
-       return $.when.apply( $, altPromises );
-};
-
-/**
- * Add-on assertion helpers
- */
-// Define the add-ons
-addons = {
-
-       // Expect boolean true
-       assertTrue: function ( actual, message ) {
-               QUnit.push( actual === true, actual, true, message );
-       },
-
-       // Expect boolean false
-       assertFalse: function ( actual, message ) {
-               QUnit.push( actual === false, actual, false, message );
-       },
-
-       // Expect numerical value less than X
-       lt: function ( actual, expected, message ) {
-               QUnit.push( actual < expected, actual, 'less than ' + expected, message );
-       },
-
-       // Expect numerical value less than or equal to X
-       ltOrEq: function ( actual, expected, message ) {
-               QUnit.push( actual <= expected, actual, 'less than or equal to ' + expected, message );
-       },
-
-       // Expect numerical value greater than X
-       gt: function ( actual, expected, message ) {
-               QUnit.push( actual > expected, actual, 'greater than ' + expected, message );
-       },
-
-       // Expect numerical value greater than or equal to X
-       gtOrEq: function ( actual, expected, message ) {
-               QUnit.push( actual >= expected, actual, 'greater than or equal to ' + expected, message );
-       }
-};
-
-$.extend( QUnit.assert, addons );
-
-/**
- * Small test suite to confirm proper functionality of the utilities and
- * initializations in this file.
- */
-var envExecCount = 0;
-QUnit.module( 'mediawiki.tests.qunit.testrunner', QUnit.newMwEnvironment({
-       setup: function () {
-               envExecCount += 1;
-               this.mwHtmlLive = mw.html;
-               mw.html = {
-                       escape: function () {
-                               return 'mocked-' + envExecCount;
-                       }
-               };
-       },
-       teardown: function () {
-               mw.html = this.mwHtmlLive;
-       },
-       config: {
-               testVar: 'foo'
-       },
-       messages: {
-               testMsg: 'Foo.'
-       }
-}) );
-
-QUnit.test( 'Setup', 3, function ( assert ) {
-       assert.equal( mw.html.escape( 'foo' ), 'mocked-1', 'extra setup() callback was ran.' );
-       assert.equal( mw.config.get( 'testVar' ), 'foo', 'config object applied' );
-       assert.equal( mw.messages.get( 'testMsg' ), 'Foo.', 'messages object applied' );
-
-       mw.config.set( 'testVar', 'bar' );
-       mw.messages.set( 'testMsg', 'Bar.' );
-});
-
-QUnit.test( 'Teardown', 3, function ( assert ) {
-       assert.equal( mw.html.escape( 'foo' ), 'mocked-2', 'extra setup() callback was re-ran.' );
-       assert.equal( mw.config.get( 'testVar' ), 'foo', 'config object restored and re-applied after test()' );
-       assert.equal( mw.messages.get( 'testMsg' ), 'Foo.', 'messages object restored and re-applied after test()' );
-});
-
-QUnit.module( 'mediawiki.tests.qunit.testrunner-after', QUnit.newMwEnvironment() );
-
-QUnit.test( 'Teardown', 3, function ( assert ) {
-       assert.equal( mw.html.escape( '<' ), '&lt;', 'extra teardown() callback was ran.' );
-       assert.equal( mw.config.get( 'testVar' ), null, 'config object restored to live in next module()' );
-       assert.equal( mw.messages.get( 'testMsg' ), null, 'messages object restored to live in next module()' );
-});
+       QUnit.test( 'Teardown', 3, function ( assert ) {
+               assert.equal( mw.html.escape( 'foo' ), 'mocked-2', 'extra setup() callback was re-ran.' );
+               assert.equal( mw.config.get( 'testVar' ), 'foo', 'config object restored and re-applied after test()' );
+               assert.equal( mw.messages.get( 'testMsg' ), 'Foo.', 'messages object restored and re-applied after test()' );
+       });
+
+       QUnit.module( 'mediawiki.tests.qunit.testrunner-after', QUnit.newMwEnvironment() );
+
+       QUnit.test( 'Teardown', 3, function ( assert ) {
+               assert.equal( mw.html.escape( '<' ), '&lt;', 'extra teardown() callback was ran.' );
+               assert.equal( mw.config.get( 'testVar' ), null, 'config object restored to live in next module()' );
+               assert.equal( mw.messages.get( 'testMsg' ), null, 'messages object restored to live in next module()' );
+       });
 
 }( jQuery, mediaWiki, QUnit ) );
index 0dee2ef..feeec55 100644 (file)
@@ -1,52 +1,58 @@
-( function ( mw, $ ) {
+( function ( $ ) {
 
-QUnit.module( 'jquery.autoEllipsis', QUnit.newMwEnvironment() );
+       QUnit.module( 'jquery.autoEllipsis', QUnit.newMwEnvironment() );
 
-function createWrappedDiv( text, width ) {
-       var $wrapper = $( '<div>' ).css( 'width', width );
-       var $div = $( '<div>' ).text( text );
-       $wrapper.append( $div );
-       return $wrapper;
-}
-
-function findDivergenceIndex( a, b ) {
-       var i = 0;
-       while ( i < a.length && i < b.length && a[i] === b[i] ) {
-               i++;
+       function createWrappedDiv( text, width ) {
+               var $wrapper = $( '<div>' ).css( 'width', width ),
+                       $div = $( '<div>' ).text( text );
+               $wrapper.append( $div );
+               return $wrapper;
        }
-       return i;
-}
-
-QUnit.test( 'Position right', 4, function ( assert ) {
-       // We need this thing to be visible, so append it to the DOM
-       var origText = 'This is a really long random string and there is no way it fits in 100 pixels.';
-       var $wrapper = createWrappedDiv( origText, '100px' );
-       $( '#qunit-fixture' ).append( $wrapper );
-       $wrapper.autoEllipsis( { position: 'right' } );
-
-       // Verify that, and only one, span element was created
-       var $span = $wrapper.find( '> span' );
-       assert.strictEqual( $span.length, 1, 'autoEllipsis wrapped the contents in a span element' );
-
-       // Check that the text fits by turning on word wrapping
-       $span.css( 'whiteSpace', 'nowrap' );
-       assert.ltOrEq( $span.width(), $span.parent().width(), "Text fits (making the span 'white-space:nowrap' does not make it wider than its parent)" );
-
-       // Add two characters using scary black magic
-       var spanText = $span.text();
-       var d = findDivergenceIndex( origText, spanText );
-       var spanTextNew = spanText.substr( 0, d ) + origText[d] + origText[d] + '...';
-
-       assert.gt( spanTextNew.length, spanText.length, 'Verify that the new span-length is indeed greater' );
-
-       // Put this text in the span and verify it doesn't fit
-       $span.text( spanTextNew );
-       // In IE6 width works like min-width, allow IE6's width to be "equal to"
-       if ( $.browser.msie && Number( $.browser.version ) === 6 ) {
-               assert.gtOrEq( $span.width(), $span.parent().width(), 'Fit is maximal (adding two characters makes it not fit any more) - IE6: Maybe equal to as well due to width behaving like min-width in IE6' );
-       } else {
-               assert.gt( $span.width(), $span.parent().width(), 'Fit is maximal (adding two characters makes it not fit any more)' );
+
+       function findDivergenceIndex( a, b ) {
+               var i = 0;
+               while ( i < a.length && i < b.length && a[i] === b[i] ) {
+                       i++;
+               }
+               return i;
        }
-});
 
-}( mediaWiki, jQuery ) );
+       QUnit.test( 'Position right', 4, function ( assert ) {
+               // We need this thing to be visible, so append it to the DOM
+               var $span, spanText, d, spanTextNew,
+                       origText = 'This is a really long random string and there is no way it fits in 100 pixels.',
+                       $wrapper = createWrappedDiv( origText, '100px' );
+
+               $( '#qunit-fixture' ).append( $wrapper );
+               $wrapper.autoEllipsis( { position: 'right' } );
+
+               // Verify that, and only one, span element was created
+               $span = $wrapper.find( '> span' );
+               assert.strictEqual( $span.length, 1, 'autoEllipsis wrapped the contents in a span element' );
+
+               // Check that the text fits by turning on word wrapping
+               $span.css( 'whiteSpace', 'nowrap' );
+               assert.ltOrEq(
+                       $span.width(),
+                       $span.parent().width(),
+                       'Text fits (making the span "white-space: nowrap" does not make it wider than its parent)'
+               );
+
+               // Add two characters using scary black magic
+               spanText = $span.text();
+               d = findDivergenceIndex( origText, spanText );
+               spanTextNew = spanText.substr( 0, d ) + origText[d] + origText[d] + '...';
+
+               assert.gt( spanTextNew.length, spanText.length, 'Verify that the new span-length is indeed greater' );
+
+               // Put this text in the span and verify it doesn't fit
+               $span.text( spanTextNew );
+               // In IE6 width works like min-width, allow IE6's width to be "equal to"
+               if ( $.browser.msie && Number( $.browser.version ) === 6 ) {
+                       assert.gtOrEq( $span.width(), $span.parent().width(), 'Fit is maximal (adding two characters makes it not fit any more) - IE6: Maybe equal to as well due to width behaving like min-width in IE6' );
+               } else {
+                       assert.gt( $span.width(), $span.parent().width(), 'Fit is maximal (adding two characters makes it not fit any more)' );
+               }
+       });
+
+}( jQuery ) );
index 8d4ac03..378ea4b 100644 (file)
@@ -1,33 +1,35 @@
-QUnit.module( 'jquery.byteLength', QUnit.newMwEnvironment() );
+( function ( $ ) {
+       QUnit.module( 'jquery.byteLength', QUnit.newMwEnvironment() );
 
-QUnit.test( 'Simple text', 5, function ( assert ) {
-       var     azLc = 'abcdefghijklmnopqrstuvwxyz',
-               azUc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
-               num = '0123456789',
-               x = '*',
-               space = '   ';
+       QUnit.test( 'Simple text', 5, function ( assert ) {
+               var     azLc = 'abcdefghijklmnopqrstuvwxyz',
+                       azUc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+                       num = '0123456789',
+                       x = '*',
+                       space = '   ';
 
-       assert.equal( $.byteLength( azLc ), 26, 'Lowercase a-z' );
-       assert.equal( $.byteLength( azUc ), 26, 'Uppercase A-Z' );
-       assert.equal( $.byteLength( num ), 10, 'Numbers 0-9' );
-       assert.equal( $.byteLength( x ), 1, 'An asterisk' );
-       assert.equal( $.byteLength( space ), 3, '3 spaces' );
+               assert.equal( $.byteLength( azLc ), 26, 'Lowercase a-z' );
+               assert.equal( $.byteLength( azUc ), 26, 'Uppercase A-Z' );
+               assert.equal( $.byteLength( num ), 10, 'Numbers 0-9' );
+               assert.equal( $.byteLength( x ), 1, 'An asterisk' );
+               assert.equal( $.byteLength( space ), 3, '3 spaces' );
 
-} );
+       } );
 
-QUnit.test( 'Special text', 5, function ( assert ) {
-       // http://en.wikipedia.org/wiki/UTF-8
-       var     U_0024 = '\u0024',
-               U_00A2 = '\u00A2',
-               U_20AC = '\u20AC',
-               U_024B62 = '\u024B62',
-               // The normal one doesn't display properly, try the below which is the same
-               // according to http://www.fileformat.info/info/unicode/char/24B62/index.htm
-               U_024B62_alt = '\uD852\uDF62';
+       QUnit.test( 'Special text', 5, function ( assert ) {
+               // http://en.wikipedia.org/wiki/UTF-8
+               var u0024 = '$',
+                       u00A2 = '\u00A2',
+                       u20AC = '\u20AC',
+                       u024B62 = '\u024B62',
+                       // The normal one doesn't display properly, try the below which is the same
+                       // according to http://www.fileformat.info/info/unicode/char/24B62/index.htm
+                       u024B62alt = '\uD852\uDF62';
 
-       assert.strictEqual( $.byteLength( U_0024 ), 1, 'U+0024: 1 byte. \u0024 (dollar sign)' );
-       assert.strictEqual( $.byteLength( U_00A2 ), 2, 'U+00A2: 2 bytes. \u00A2 (cent sign)' );
-       assert.strictEqual( $.byteLength( U_20AC ), 3, 'U+20AC: 3 bytes. \u20AC (euro sign)' );
-       assert.strictEqual( $.byteLength( U_024B62 ), 4, 'U+024B62: 4 bytes. \uD852\uDF62 (a Han character)' );
-       assert.strictEqual( $.byteLength( U_024B62_alt ), 4, 'U+024B62: 4 bytes. \uD852\uDF62 (a Han character) - alternative method' );
-} );
+               assert.strictEqual( $.byteLength( u0024 ), 1, 'U+0024: 1 byte. $ (dollar sign)' );
+               assert.strictEqual( $.byteLength( u00A2 ), 2, 'U+00A2: 2 bytes. \u00A2 (cent sign)' );
+               assert.strictEqual( $.byteLength( u20AC ), 3, 'U+20AC: 3 bytes. \u20AC (euro sign)' );
+               assert.strictEqual( $.byteLength( u024B62 ), 4, 'U+024B62: 4 bytes. \uD852\uDF62 (a Han character)' );
+               assert.strictEqual( $.byteLength( u024B62alt ), 4, 'U+024B62: 4 bytes. \uD852\uDF62 (a Han character) - alternative method' );
+       } );
+}( jQuery ) );
index 4f86eb9..4fe6770 100644 (file)
        // Basic sendkey-implementation
        function addChars( $input, charstr ) {
                var c, len;
+               function x( $input, i ) {
+                       // Add character to the value
+                       return $input.val() + charstr.charAt( i );
+               }
                for ( c = 0, len = charstr.length; c < len; c += 1 ) {
                        $input
-                               .val( function ( i, val ) {
-                                       // Add character to the value
-                                       return val + charstr.charAt( c );
-                               } )
+                               .val( x( $input, c ) )
                                .trigger( 'change' );
                }
        }
index bf62b39..bbc8852 100644 (file)
-QUnit.module( 'jquery.client', QUnit.newMwEnvironment() );
+( function ( $ ) {
+       var uacount, uas, testMap;
 
-/** Number of user-agent defined */
-var uacount = 0;
+       QUnit.module( 'jquery.client', QUnit.newMwEnvironment() );
 
-var uas = (function () {
+       /** Number of user-agent defined */
+       uacount = 0;
 
-       // Object keyed by userAgent. Value is an array (human-readable name, client-profile object, navigator.platform value)
-       // Info based on results from http://toolserver.org/~krinkle/testswarm/job/174/
-       var uas = {
-               // Internet Explorer 6
-               // Internet Explorer 7
-               'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)': {
-                       title: 'Internet Explorer 7',
-                       platform: 'Win32',
-                       profile: {
-                               "name": "msie",
-                               "layout": "trident",
-                               "layoutVersion": "unknown",
-                               "platform": "win",
-                               "version": "7.0",
-                               "versionBase": "7",
-                               "versionNumber": 7
-                       },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: false
-                       }
-               },
-               // Internet Explorer 8
-               // Internet Explorer 9
-               // Internet Explorer 10
-               'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)': {
-                       title: 'Internet Explorer 10',
-                       platform: 'Win32',
-                       profile: {
-                               "name": "msie",
-                               "layout": "trident",
-                               "layoutVersion": "unknown", // should be able to report 6?
-                               "platform": "win",
-                               "version": "10.0",
-                               "versionBase": "10",
-                               "versionNumber": 10
+       uas = ( function () {
+
+               // Object keyed by userAgent. Value is an array (human-readable name, client-profile object, navigator.platform value)
+               // Info based on results from http://toolserver.org/~krinkle/testswarm/job/174/
+               var uas = {
+                       // Internet Explorer 6
+                       // Internet Explorer 7
+                       'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)': {
+                               title: 'Internet Explorer 7',
+                               platform: 'Win32',
+                               profile: {
+                                       name: 'msie',
+                                       layout: 'trident',
+                                       layoutVersion: 'unknown',
+                                       platform: 'win',
+                                       version: '7.0',
+                                       versionBase: '7',
+                                       versionNumber: 7
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: false
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
-                       }
-               },
-               // Firefox 2
-               // Firefox 3.5
-               'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.19) Gecko/20110420 Firefox/3.5.19': {
-                       title: 'Firefox 3.5',
-                       platform: 'MacIntel',
-                       profile: {
-                               "name": "firefox",
-                               "layout": "gecko",
-                               "layoutVersion": 20110420,
-                               "platform": "mac",
-                               "version": "3.5.19",
-                               "versionBase": "3",
-                               "versionNumber": 3.5
+                       // Internet Explorer 8
+                       // Internet Explorer 9
+                       // Internet Explorer 10
+                       'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)': {
+                               title: 'Internet Explorer 10',
+                               platform: 'Win32',
+                               profile: {
+                                       name: 'msie',
+                                       layout: 'trident',
+                                       layoutVersion: 'unknown', // should be able to report 6?
+                                       platform: 'win',
+                                       version: '10.0',
+                                       versionBase: '10',
+                                       versionNumber: 10
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
-                       }
-               },
-               // Firefox 3.6
-               'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110422 Ubuntu/10.10 (maverick) Firefox/3.6.17': {
-                       title: 'Firefox 3.6',
-                       platform: 'Linux i686',
-                       profile: {
-                               "name": "firefox",
-                               "layout": "gecko",
-                               "layoutVersion": 20110422,
-                               "platform": "linux",
-                               "version": "3.6.17",
-                               "versionBase": "3",
-                               "versionNumber": 3.6
+                       // Firefox 2
+                       // Firefox 3.5
+                       'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.19) Gecko/20110420 Firefox/3.5.19': {
+                               title: 'Firefox 3.5',
+                               platform: 'MacIntel',
+                               profile: {
+                                       name: 'firefox',
+                                       layout: 'gecko',
+                                       layoutVersion: 20110420,
+                                       platform: 'mac',
+                                       version: '3.5.19',
+                                       versionBase: '3',
+                                       versionNumber: 3.5
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
-                       }
-               },
-               // Firefox 4
-               'Mozilla/5.0 (Windows NT 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1': {
-                       title: 'Firefox 4',
-                       platform: 'Win32',
-                       profile: {
-                               "name": "firefox",
-                               "layout": "gecko",
-                               "layoutVersion": 20100101,
-                               "platform": "win",
-                               "version": "4.0.1",
-                               "versionBase": "4",
-                               "versionNumber": 4
+                       // Firefox 3.6
+                       'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110422 Ubuntu/10.10 (maverick) Firefox/3.6.17': {
+                               title: 'Firefox 3.6',
+                               platform: 'Linux i686',
+                               profile: {
+                                       name: 'firefox',
+                                       layout: 'gecko',
+                                       layoutVersion: 20110422,
+                                       platform: 'linux',
+                                       version: '3.6.17',
+                                       versionBase: '3',
+                                       versionNumber: 3.6
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
-                       }
-               },
-               // Firefox 10 nightly build
-               'Mozilla/5.0 (X11; Linux x86_64; rv:10.0a1) Gecko/20111103 Firefox/10.0a1': {
-                       title: 'Firefox 10 nightly',
-                       platform: 'Linux',
-                       profile: {
-                               "name": "firefox",
-                               "layout": "gecko",
-                               "layoutVersion": 20111103,
-                               "platform": "linux",
-                               "version": "10.0a1",
-                               "versionBase": "10",
-                               "versionNumber": 10
+                       // Firefox 4
+                       'Mozilla/5.0 (Windows NT 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1': {
+                               title: 'Firefox 4',
+                               platform: 'Win32',
+                               profile: {
+                                       name: 'firefox',
+                                       layout: 'gecko',
+                                       layoutVersion: 20100101,
+                                       platform: 'win',
+                                       version: '4.0.1',
+                                       versionBase: '4',
+                                       versionNumber: 4
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
-                       }
-               },
-               // Firefox 5
-               // Safari 3
-               // Safari 4
-               'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; nl-nl) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7': {
-                       title: 'Safari 4',
-                       platform: 'MacIntel',
-                       profile: {
-                               "name": "safari",
-                               "layout": "webkit",
-                               "layoutVersion": 531,
-                               "platform": "mac",
-                               "version": "4.0.5",
-                               "versionBase": "4",
-                               "versionNumber": 4
+                       // Firefox 10 nightly build
+                       'Mozilla/5.0 (X11; Linux x86_64; rv:10.0a1) Gecko/20111103 Firefox/10.0a1': {
+                               title: 'Firefox 10 nightly',
+                               platform: 'Linux',
+                               profile: {
+                                       name: 'firefox',
+                                       layout: 'gecko',
+                                       layoutVersion: 20111103,
+                                       platform: 'linux',
+                                       version: '10.0a1',
+                                       versionBase: '10',
+                                       versionNumber: 10
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
-                       }
-               },
-               'Mozilla/5.0 (Windows; U; Windows NT 6.0; cs-CZ) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7': {
-                       title: 'Safari 4',
-                       platform: 'Win32',
-                       profile: {
-                               "name": "safari",
-                               "layout": "webkit",
-                               "layoutVersion": 533,
-                               "platform": "win",
-                               "version": "4.0.5",
-                               "versionBase": "4",
-                               "versionNumber": 4
+                       // Firefox 5
+                       // Safari 3
+                       // Safari 4
+                       'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; nl-nl) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7': {
+                               title: 'Safari 4',
+                               platform: 'MacIntel',
+                               profile: {
+                                       name: 'safari',
+                                       layout: 'webkit',
+                                       layoutVersion: 531,
+                                       platform: 'mac',
+                                       version: '4.0.5',
+                                       versionBase: '4',
+                                       versionNumber: 4
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
-                       }
-               },
-               // Safari 5
-               // Opera 10
-               // Chrome 5
-               // Chrome 6
-               // Chrome 7
-               // Chrome 8
-               // Chrome 9
-               // Chrome 10
-               // Chrome 11
-               // Chrome 12
-               'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30': {
-                       title: 'Chrome 12',
-                       platform: 'MacIntel',
-                       profile: {
-                               "name": "chrome",
-                               "layout": "webkit",
-                               "layoutVersion": 534,
-                               "platform": "mac",
-                               "version": "12.0.742.112",
-                               "versionBase": "12",
-                               "versionNumber": 12
+                       'Mozilla/5.0 (Windows; U; Windows NT 6.0; cs-CZ) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7': {
+                               title: 'Safari 4',
+                               platform: 'Win32',
+                               profile: {
+                                       name: 'safari',
+                                       layout: 'webkit',
+                                       layoutVersion: 533,
+                                       platform: 'win',
+                                       version: '4.0.5',
+                                       versionBase: '4',
+                                       versionNumber: 4
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
-                       }
-               },
-               'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30': {
-                       title: 'Chrome 12',
-                       platform: 'Linux i686',
-                       profile: {
-                               "name": "chrome",
-                               "layout": "webkit",
-                               "layoutVersion": 534,
-                               "platform": "linux",
-                               "version": "12.0.742.68",
-                               "versionBase": "12",
-                               "versionNumber": 12
+                       // Safari 5
+                       // Opera 10
+                       // Chrome 5
+                       // Chrome 6
+                       // Chrome 7
+                       // Chrome 8
+                       // Chrome 9
+                       // Chrome 10
+                       // Chrome 11
+                       // Chrome 12
+                       'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30': {
+                               title: 'Chrome 12',
+                               platform: 'MacIntel',
+                               profile: {
+                                       name: 'chrome',
+                                       layout: 'webkit',
+                                       layoutVersion: 534,
+                                       platform: 'mac',
+                                       version: '12.0.742.112',
+                                       versionBase: '12',
+                                       versionNumber: 12
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
-                       }
-               },
-               // Bug #34924
-               'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.34 (KHTML, like Gecko) rekonq Safari/534.34': {
-                       title: 'Rekonq',
-                       platform: 'Linux i686',
-                       profile: {
-                               "name": "rekonq",
-                               "layout": "webkit",
-                               "layoutVersion": 534,
-                               "platform": "linux",
-                               "version": "534.34",
-                               "versionBase": "534",
-                               "versionNumber": 534.34
+                       'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30': {
+                               title: 'Chrome 12',
+                               platform: 'Linux i686',
+                               profile: {
+                                       name: 'chrome',
+                                       layout: 'webkit',
+                                       layoutVersion: 534,
+                                       platform: 'linux',
+                                       version: '12.0.742.68',
+                                       versionBase: '12',
+                                       versionNumber: 12
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        },
-                       wikiEditor: {
-                               ltr: true,
-                               rtl: true
+                       // Bug #34924
+                       'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.34 (KHTML, like Gecko) rekonq Safari/534.34': {
+                               title: 'Rekonq',
+                               platform: 'Linux i686',
+                               profile: {
+                                       name: 'rekonq',
+                                       layout: 'webkit',
+                                       layoutVersion: 534,
+                                       platform: 'linux',
+                                       version: '534.34',
+                                       versionBase: '534',
+                                       versionNumber: 534.34
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
                        }
-               }
-       };
-       $.each( uas, function () {
-               uacount++;
-       });
-       return uas;
-}());
+               };
+               $.each( uas, function () {
+                       uacount++;
+               });
+               return uas;
+       }() );
 
-QUnit.test( 'profile userAgent support', uacount, function ( assert ) {
-       // Generate a client profile object and compare recursively
-       var uaTest = function( rawUserAgent, data ) {
-               var ret = $.client.profile( {
-                       userAgent: rawUserAgent,
-                       platform: data.platform
-               } );
-               assert.deepEqual( ret, data.profile, 'Client profile support check for ' + data.title + ' (' + data.platform + '): ' + rawUserAgent );
-       };
+       QUnit.test( 'profile userAgent support', uacount, function ( assert ) {
+               // Generate a client profile object and compare recursively
+               var uaTest = function( rawUserAgent, data ) {
+                       var ret = $.client.profile( {
+                               userAgent: rawUserAgent,
+                               platform: data.platform
+                       } );
+                       assert.deepEqual( ret, data.profile, 'Client profile support check for ' + data.title + ' (' + data.platform + '): ' + rawUserAgent );
+               };
 
-       // Loop through and run tests
-       $.each( uas, uaTest );
-} );
+               // Loop through and run tests
+               $.each( uas, uaTest );
+       } );
 
-QUnit.test( 'profile return validation for current user agent', 7, function ( assert ) {
-       var p = $.client.profile();
-       function unknownOrType( val, type, summary ) {
-               assert.ok( typeof val === type || val === 'unknown', summary );
-       }
+       QUnit.test( 'profile return validation for current user agent', 7, function ( assert ) {
+               var p = $.client.profile();
+               function unknownOrType( val, type, summary ) {
+                       assert.ok( typeof val === type || val === 'unknown', summary );
+               }
 
-       assert.equal( typeof p, 'object', 'profile returns an object' );
-       unknownOrType( p.layout, 'string', 'p.layout is a string (or "unknown")' );
-       unknownOrType( p.layoutVersion, 'number', 'p.layoutVersion is a number (or "unknown")' );
-       unknownOrType( p.platform, 'string', 'p.platform is a string (or "unknown")' );
-       unknownOrType( p.version, 'string', 'p.version is a string (or "unknown")' );
-       unknownOrType( p.versionBase, 'string', 'p.versionBase is a string (or "unknown")' );
-       assert.equal( typeof p.versionNumber, 'number', 'p.versionNumber is a number' );
-});
+               assert.equal( typeof p, 'object', 'profile returns an object' );
+               unknownOrType( p.layout, 'string', 'p.layout is a string (or "unknown")' );
+               unknownOrType( p.layoutVersion, 'number', 'p.layoutVersion is a number (or "unknown")' );
+               unknownOrType( p.platform, 'string', 'p.platform is a string (or "unknown")' );
+               unknownOrType( p.version, 'string', 'p.version is a string (or "unknown")' );
+               unknownOrType( p.versionBase, 'string', 'p.versionBase is a string (or "unknown")' );
+               assert.equal( typeof p.versionNumber, 'number', 'p.versionNumber is a number' );
+       });
 
-// Example from WikiEditor
-// Make sure to use raw numbers, a string like "7.0" would fail on a
-// version 10 browser since in string comparaison "10" is before "7.0" :)
-var testMap = {
-       'ltr': {
-               'msie': [['>=', 7.0]],
-               'firefox': [['>=', 2]],
-               'opera': [['>=', 9.6]],
-               'safari': [['>=', 3]],
-               'chrome': [['>=', 3]],
-               'netscape': [['>=', 9]],
-               'blackberry': false,
-               'ipod': false,
-               'iphone': false
-       },
-       'rtl': {
-               'msie': [['>=', 8]],
-               'firefox': [['>=', 2]],
-               'opera': [['>=', 9.6]],
-               'safari': [['>=', 3]],
-               'chrome': [['>=', 3]],
-               'netscape': [['>=', 9]],
-               'blackberry': false,
-               'ipod': false,
-               'iphone': false
-       }
-};
+       // Example from WikiEditor
+       // Make sure to use raw numbers, a string like "7.0" would fail on a
+       // version 10 browser since in string comparaison "10" is before "7.0" :)
+       testMap = {
+               'ltr': {
+                       'msie': [['>=', 7.0]],
+                       'firefox': [['>=', 2]],
+                       'opera': [['>=', 9.6]],
+                       'safari': [['>=', 3]],
+                       'chrome': [['>=', 3]],
+                       'netscape': [['>=', 9]],
+                       'blackberry': false,
+                       'ipod': false,
+                       'iphone': false
+               },
+               'rtl': {
+                       'msie': [['>=', 8]],
+                       'firefox': [['>=', 2]],
+                       'opera': [['>=', 9.6]],
+                       'safari': [['>=', 3]],
+                       'chrome': [['>=', 3]],
+                       'netscape': [['>=', 9]],
+                       'blackberry': false,
+                       'ipod': false,
+                       'iphone': false
+               }
+       };
 
-QUnit.test( 'test', 1, function ( assert ) {
-       // .test() uses eval, make sure no exceptions are thrown
-       // then do a basic return value type check
-       var testMatch = $.client.test( testMap );
+       QUnit.test( 'test', 1, function ( assert ) {
+               // .test() uses eval, make sure no exceptions are thrown
+               // then do a basic return value type check
+               var testMatch = $.client.test( testMap );
 
-       assert.equal( typeof testMatch, 'boolean', 'test returns a boolean value' );
+               assert.equal( typeof testMatch, 'boolean', 'test returns a boolean value' );
 
-});
+       });
 
-QUnit.test( 'User-agent matches against WikiEditor\'s compatibility map', uacount * 2, function ( assert ) {
-       var     $body = $( 'body' ),
-               bodyClasses = $body.attr( 'class' );
+       QUnit.test( 'User-agent matches against WikiEditor\'s compatibility map', uacount * 2, function ( assert ) {
+               var     $body = $( 'body' ),
+                       bodyClasses = $body.attr( 'class' );
 
-       // Loop through and run tests
-       $.each( uas, function ( agent, data ) {
-               $.each( ['ltr', 'rtl'], function ( i, dir ) {
-                       $body.removeClass( 'ltr rtl' ).addClass( dir );
-                       var profile = $.client.profile( {
-                               userAgent: agent,
-                               platform: data.platform
-                       } );
-                       var testMatch = $.client.test( testMap, profile );
-                       $body.removeClass( dir );
+               // Loop through and run tests
+               $.each( uas, function ( agent, data ) {
+                       $.each( ['ltr', 'rtl'], function ( i, dir ) {
+                               var profile, testMatch;
+                               $body.removeClass( 'ltr rtl' ).addClass( dir );
+                               profile = $.client.profile( {
+                                       userAgent: agent,
+                                       platform: data.platform
+                               } );
+                               testMatch = $.client.test( testMap, profile );
+                               $body.removeClass( dir );
 
-                       assert.equal( testMatch, data.wikiEditor[dir], 'testing comparison based on ' + dir + ', ' + agent );
+                               assert.equal( testMatch, data.wikiEditor[dir], 'testing comparison based on ' + dir + ', ' + agent );
+                       });
                });
-       });
-
-       // Restore body classes
-       $body.attr( 'class', bodyClasses );
-});
 
+               // Restore body classes
+               $body.attr( 'class', bodyClasses );
+       });
+}( jQuery ) );
index 7b37f5a..51a892e 100644 (file)
@@ -1,58 +1,62 @@
-QUnit.module( 'jquery.colorUtil', QUnit.newMwEnvironment() );
-
-QUnit.test( 'getRGB', 18, function ( assert ) {
-       assert.strictEqual( $.colorUtil.getRGB(), undefined, 'No arguments' );
-       assert.strictEqual( $.colorUtil.getRGB( '' ), undefined, 'Empty string' );
-       assert.deepEqual( $.colorUtil.getRGB( [0, 100, 255] ), [0, 100, 255], 'Parse array of rgb values' );
-       assert.deepEqual( $.colorUtil.getRGB( 'rgb(0,100,255)' ), [0, 100, 255], 'Parse simple rgb string' );
-       assert.deepEqual( $.colorUtil.getRGB( 'rgb(0, 100, 255)' ), [0, 100, 255], 'Parse simple rgb string with spaces' );
-       assert.deepEqual( $.colorUtil.getRGB( 'rgb(0%,20%,40%)' ), [0, 51, 102], 'Parse rgb string with percentages' );
-       assert.deepEqual( $.colorUtil.getRGB( 'rgb(0%, 20%, 40%)' ), [0, 51, 102], 'Parse rgb string with percentages and spaces' );
-       assert.deepEqual( $.colorUtil.getRGB( '#f2ddee' ), [242, 221, 238], 'Hex string: 6 char lowercase' );
-       assert.deepEqual( $.colorUtil.getRGB( '#f2DDEE' ), [242, 221, 238], 'Hex string: 6 char uppercase' );
-       assert.deepEqual( $.colorUtil.getRGB( '#f2DdEe' ), [242, 221, 238], 'Hex string: 6 char mixed' );
-       assert.deepEqual( $.colorUtil.getRGB( '#eee' ), [238, 238, 238], 'Hex string: 3 char lowercase' );
-       assert.deepEqual( $.colorUtil.getRGB( '#EEE' ), [238, 238, 238], 'Hex string: 3 char uppercase' );
-       assert.deepEqual( $.colorUtil.getRGB( '#eEe' ), [238, 238, 238], 'Hex string: 3 char mixed' );
-       assert.deepEqual( $.colorUtil.getRGB( 'rgba(0, 0, 0, 0)' ), [255, 255, 255], 'Zero rgba for Safari 3; Transparent (whitespace)' );
-
-       // Perhaps this is a bug in colorUtil, but it is the current behaviour so, let's keep
-       // track of it, so we will know in case it would ever change.
-       assert.strictEqual( $.colorUtil.getRGB( 'rgba(0,0,0,0)' ), undefined, 'Zero rgba without whitespace' );
-
-       assert.deepEqual( $.colorUtil.getRGB( 'lightGreen' ), [144, 238, 144], 'Color names (lightGreen)' );
-       assert.deepEqual( $.colorUtil.getRGB( 'transparent' ), [255, 255, 255], 'Color names (transparent)' );
-       assert.strictEqual( $.colorUtil.getRGB( 'mediaWiki' ), undefined, 'Inexisting color name' );
-});
-
-QUnit.test( 'rgbToHsl', 1, function ( assert ) {
-       var hsl = $.colorUtil.rgbToHsl( 144, 238, 144 );
-
-       // Cross-browser differences in decimals...
-       // Round to two decimals so they can be more reliably checked.
-       var dualDecimals = function(a,b){
-               return Math.round(a*100)/100;
-       };
-       // Re-create the rgbToHsl return array items, limited to two decimals.
-       var ret = [dualDecimals(hsl[0]), dualDecimals(hsl[1]), dualDecimals(hsl[2])];
-
-       assert.deepEqual( ret, [0.33, 0.73, 0.75], 'rgb(144, 238, 144): hsl(0.33, 0.73, 0.75)' );
-});
-
-QUnit.test( 'hslToRgb', 1, function ( assert ) {
-       var rgb = $.colorUtil.hslToRgb( 0.3, 0.7, 0.8 );
-
-       // Cross-browser differences in decimals...
-       // Re-create the hslToRgb return array items, rounded to whole numbers.
-       var ret = [Math.round(rgb[0]), Math.round(rgb[1]), Math.round(rgb[2])];
-
-       assert.deepEqual( ret ,[183, 240, 168], 'hsl(0.3, 0.7, 0.8): rgb(183, 240, 168)' );
-});
-
-QUnit.test( 'getColorBrightness', 2, function ( assert ) {
-       var a = $.colorUtil.getColorBrightness( 'red', +0.1 );
-       assert.equal( a, 'rgb(255,50,50)', 'Start with named color "red", brighten 10%' );
-
-       var b = $.colorUtil.getColorBrightness( 'rgb(200,50,50)', -0.2 );
-       assert.equal( b, 'rgb(118,29,29)', 'Start with rgb string "rgb(200,50,50)", darken 20%' );
-});
+( function ( $ ) {
+       QUnit.module( 'jquery.colorUtil', QUnit.newMwEnvironment() );
+
+       QUnit.test( 'getRGB', 18, function ( assert ) {
+               assert.strictEqual( $.colorUtil.getRGB(), undefined, 'No arguments' );
+               assert.strictEqual( $.colorUtil.getRGB( '' ), undefined, 'Empty string' );
+               assert.deepEqual( $.colorUtil.getRGB( [0, 100, 255] ), [0, 100, 255], 'Parse array of rgb values' );
+               assert.deepEqual( $.colorUtil.getRGB( 'rgb(0,100,255)' ), [0, 100, 255], 'Parse simple rgb string' );
+               assert.deepEqual( $.colorUtil.getRGB( 'rgb(0, 100, 255)' ), [0, 100, 255], 'Parse simple rgb string with spaces' );
+               assert.deepEqual( $.colorUtil.getRGB( 'rgb(0%,20%,40%)' ), [0, 51, 102], 'Parse rgb string with percentages' );
+               assert.deepEqual( $.colorUtil.getRGB( 'rgb(0%, 20%, 40%)' ), [0, 51, 102], 'Parse rgb string with percentages and spaces' );
+               assert.deepEqual( $.colorUtil.getRGB( '#f2ddee' ), [242, 221, 238], 'Hex string: 6 char lowercase' );
+               assert.deepEqual( $.colorUtil.getRGB( '#f2DDEE' ), [242, 221, 238], 'Hex string: 6 char uppercase' );
+               assert.deepEqual( $.colorUtil.getRGB( '#f2DdEe' ), [242, 221, 238], 'Hex string: 6 char mixed' );
+               assert.deepEqual( $.colorUtil.getRGB( '#eee' ), [238, 238, 238], 'Hex string: 3 char lowercase' );
+               assert.deepEqual( $.colorUtil.getRGB( '#EEE' ), [238, 238, 238], 'Hex string: 3 char uppercase' );
+               assert.deepEqual( $.colorUtil.getRGB( '#eEe' ), [238, 238, 238], 'Hex string: 3 char mixed' );
+               assert.deepEqual( $.colorUtil.getRGB( 'rgba(0, 0, 0, 0)' ), [255, 255, 255], 'Zero rgba for Safari 3; Transparent (whitespace)' );
+
+               // Perhaps this is a bug in colorUtil, but it is the current behaviour so, let's keep
+               // track of it, so we will know in case it would ever change.
+               assert.strictEqual( $.colorUtil.getRGB( 'rgba(0,0,0,0)' ), undefined, 'Zero rgba without whitespace' );
+
+               assert.deepEqual( $.colorUtil.getRGB( 'lightGreen' ), [144, 238, 144], 'Color names (lightGreen)' );
+               assert.deepEqual( $.colorUtil.getRGB( 'transparent' ), [255, 255, 255], 'Color names (transparent)' );
+               assert.strictEqual( $.colorUtil.getRGB( 'mediaWiki' ), undefined, 'Inexisting color name' );
+       });
+
+       QUnit.test( 'rgbToHsl', 1, function ( assert ) {
+               var hsl, ret;
+
+               // Cross-browser differences in decimals...
+               // Round to two decimals so they can be more reliably checked.
+               function dualDecimals( a ) {
+                       return Math.round( a * 100 ) / 100;
+               }
+               // Re-create the rgbToHsl return array items, limited to two decimals.
+               hsl = $.colorUtil.rgbToHsl( 144, 238, 144 );
+               ret = [ dualDecimals( hsl[0] ), dualDecimals( hsl[1] ), dualDecimals( hsl[2] ) ];
+
+               assert.deepEqual( ret, [0.33, 0.73, 0.75], 'rgb(144, 238, 144): hsl(0.33, 0.73, 0.75)' );
+       });
+
+       QUnit.test( 'hslToRgb', 1, function ( assert ) {
+               var rgb, ret;
+               rgb = $.colorUtil.hslToRgb( 0.3, 0.7, 0.8 );
+
+               // Re-create the hslToRgb return array items, rounded to whole numbers.
+               ret = [ Math.round(rgb[0]), Math.round(rgb[1]), Math.round(rgb[2]) ];
+
+               assert.deepEqual( ret ,[183, 240, 168], 'hsl(0.3, 0.7, 0.8): rgb(183, 240, 168)' );
+       });
+
+       QUnit.test( 'getColorBrightness', 2, function ( assert ) {
+               var a, b;
+               a = $.colorUtil.getColorBrightness( 'red', +0.1 );
+               assert.equal( a, 'rgb(255,50,50)', 'Start with named color "red", brighten 10%' );
+
+               b = $.colorUtil.getColorBrightness( 'rgb(200,50,50)', -0.2 );
+               assert.equal( b, 'rgb(118,29,29)', 'Start with rgb string "rgb(200,50,50)", darken 20%' );
+       });
+}( jQuery ) );
index a307983..3e7d5ff 100644 (file)
@@ -1,35 +1,37 @@
-QUnit.asyncTest('jquery.delayedBind with data option', 2, function ( assert ) {
-       var $fixture = $('<div>').appendTo('#qunit-fixture'),
-               data = { magic: "beeswax" },
-               delay = 50;
+( function ( $ ) {
+       QUnit.asyncTest('jquery.delayedBind with data option', 2, function ( assert ) {
+               var $fixture = $('<div>').appendTo('#qunit-fixture'),
+                       data = {
+                               magic: 'beeswax'
+                       },
+                       delay = 50;
 
-       $fixture.delayedBind(delay, 'testevent', data, function ( e ) {
-               QUnit.start(); // continue!
-               assert.ok( true, 'testevent fired');
-               assert.ok( e.data === data, 'data is passed through delayedBind');
+               $fixture.delayedBind(delay, 'testevent', data, function ( e ) {
+                       assert.ok( true, 'testevent fired');
+                       assert.ok( e.data === data, 'data is passed through delayedBind');
+                       QUnit.start();
+               });
+
+               // We'll trigger it thrice, but it should only happen once.
+               $fixture.trigger( 'testevent', {} );
+               $fixture.trigger( 'testevent', {} );
+               $fixture.trigger( 'testevent', {} );
+               $fixture.trigger( 'testevent', {} );
        });
 
-       // We'll trigger it thrice, but it should only happen once.
-       $fixture.trigger( 'testevent', {} );
-       $fixture.trigger( 'testevent', {} );
-       $fixture.trigger( 'testevent', {} );
-       $fixture.trigger( 'testevent', {} );
-});
+       QUnit.asyncTest('jquery.delayedBind without data option', 1, function ( assert ) {
+               var $fixture = $('<div>').appendTo('#qunit-fixture'),
+                       delay = 50;
 
-QUnit.asyncTest('jquery.delayedBind without data option', 1, function ( assert ) {
-       var $fixture = $('<div>').appendTo('#qunit-fixture'),
-               data = { magic: "beeswax" },
-               delay = 50;
+               $fixture.delayedBind(delay, 'testevent', function () {
+                       assert.ok(true, 'testevent fired');
+                       QUnit.start();
+               });
 
-       $fixture.delayedBind(delay, 'testevent', function ( e ) {
-               QUnit.start(); // continue!
-               assert.ok(true, 'testevent fired');
+               // We'll trigger it thrice, but it should only happen once.
+               $fixture.trigger( 'testevent', {} );
+               $fixture.trigger( 'testevent', {} );
+               $fixture.trigger( 'testevent', {} );
+               $fixture.trigger( 'testevent', {} );
        });
-
-       // We'll trigger it thrice, but it should only happen once.
-       $fixture.trigger( 'testevent', {} );
-       $fixture.trigger( 'testevent', {} );
-       $fixture.trigger( 'testevent', {} );
-       $fixture.trigger( 'testevent', {} );
-});
-
+}( jQuery ) );
index 6eef1ab..82566c2 100644 (file)
@@ -1,11 +1,13 @@
-QUnit.module( 'jquery.getAttrs', QUnit.newMwEnvironment() );
+( function ( $ ) {
+       QUnit.module( 'jquery.getAttrs', QUnit.newMwEnvironment() );
 
-QUnit.test( 'Check', 1, function ( assert ) {
-       var     attrs = {
-                       foo: 'bar',
-                       'class': 'lorem'
-               },
-               $el = jQuery( '<div>', attrs );
+       QUnit.test( 'Check', 1, function ( assert ) {
+               var     attrs = {
+                               foo: 'bar',
+                               'class': 'lorem'
+                       },
+                       $el = $( '<div>' ).attr( attrs );
 
-       assert.deepEqual( $el.getAttrs(), attrs, 'getAttrs() return object should match the attributes set, no more, no less' );
-} );
+               assert.deepEqual( $el.getAttrs(), attrs, 'getAttrs() return object should match the attributes set, no more, no less' );
+       } );
+}( jQuery ) );
index cf309df..d75c378 100644 (file)
@@ -1,20 +1,22 @@
-QUnit.module( 'jquery.hidpi', QUnit.newMwEnvironment() );
+( function ( $ ) {
+       QUnit.module( 'jquery.hidpi', QUnit.newMwEnvironment() );
 
-QUnit.test( 'devicePixelRatio', function ( assert ) {
-       var devicePixelRatio = $.devicePixelRatio();
-       assert.equal( typeof devicePixelRatio, 'number', '$.devicePixelRatio() returns a number' );
-});
+       QUnit.test( 'devicePixelRatio', function ( assert ) {
+               var devicePixelRatio = $.devicePixelRatio();
+               assert.equal( typeof devicePixelRatio, 'number', '$.devicePixelRatio() returns a number' );
+       });
 
-QUnit.test( 'matchSrcSet', function ( assert ) {
-       var srcset = 'onefive.png 1.5x, two.png 2x';
+       QUnit.test( 'matchSrcSet', function ( assert ) {
+               var srcset = 'onefive.png 1.5x, two.png 2x';
 
-       // Nice exact matches
-       assert.equal( $.matchSrcSet( 1, srcset ), null, '1.0 gives no match' );
-       assert.equal( $.matchSrcSet( 1.5, srcset ), 'onefive.png', '1.5 gives match' );
-       assert.equal( $.matchSrcSet( 2, srcset ), 'two.png', '2 gives match' );
+               // Nice exact matches
+               assert.equal( $.matchSrcSet( 1, srcset ), null, '1.0 gives no match' );
+               assert.equal( $.matchSrcSet( 1.5, srcset ), 'onefive.png', '1.5 gives match' );
+               assert.equal( $.matchSrcSet( 2, srcset ), 'two.png', '2 gives match' );
 
-       // Non-exact matches; should return the next-biggest specified
-       assert.equal( $.matchSrcSet( 1.25, srcset ), null, '1.25 gives no match' );
-       assert.equal( $.matchSrcSet( 1.75, srcset ), 'onefive.png', '1.75 gives match to 1.5' );
-       assert.equal( $.matchSrcSet( 2.25, srcset ), 'two.png', '2.25 gives match to 2' );
-});
+               // Non-exact matches; should return the next-biggest specified
+               assert.equal( $.matchSrcSet( 1.25, srcset ), null, '1.25 gives no match' );
+               assert.equal( $.matchSrcSet( 1.75, srcset ), 'onefive.png', '1.75 gives match to 1.5' );
+               assert.equal( $.matchSrcSet( 2.25, srcset ), 'two.png', '2.25 gives match to 2' );
+       });
+}( jQuery ) );
index a94dca3..e1fb96d 100644 (file)
-QUnit.module( 'jquery.highlightText', QUnit.newMwEnvironment() );
+( function ( $ ) {
+       QUnit.module( 'jquery.highlightText', QUnit.newMwEnvironment() );
 
-QUnit.test( 'Check', function ( assert ) {
-       var $fixture, cases = [
-               {
-                       desc: 'Test 001',
-                       text: 'Blue Öyster Cult',
-                       highlight: 'Blue',
-                       expected: '<span class="highlight">Blue</span> Öyster Cult'
-               },
-               {
-                       desc: 'Test 002',
-                       text: 'Blue Öyster Cult',
-                       highlight: 'Blue ',
-                       expected: '<span class="highlight">Blue</span> Öyster Cult'
-               },
-               {
-                       desc: 'Test 003',
-                       text: 'Blue Öyster Cult',
-                       highlight: 'Blue Ö',
-                       expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
-               },
-               {
-                       desc: 'Test 004',
-                       text: 'Blue Öyster Cult',
-                       highlight: 'Blue Öy',
-                       expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
-               },
-               {
-                       desc: 'Test 005',
-                       text: 'Blue Öyster Cult',
-                       highlight: ' Blue',
-                       expected: '<span class="highlight">Blue</span> Öyster Cult'
-               },
-               {
-                       desc: 'Test 006',
-                       text: 'Blue Öyster Cult',
-                       highlight: ' Blue ',
-                       expected: '<span class="highlight">Blue</span> Öyster Cult'
-               },
-               {
-                       desc: 'Test 007',
-                       text: 'Blue Öyster Cult',
-                       highlight: ' Blue Ö',
-                       expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
-               },
-               {
-                       desc: 'Test 008',
-                       text: 'Blue Öyster Cult',
-                       highlight: ' Blue Öy',
-                       expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
-               },
-               {
-                       desc: 'Test 009: Highlighter broken on starting Umlaut?',
-                       text: 'Österreich',
-                       highlight: 'Österreich',
-                       expected: '<span class="highlight">Österreich</span>'
-               },
-               {
-                       desc: 'Test 010: Highlighter broken on starting Umlaut?',
-                       text: 'Österreich',
-                       highlight: 'Ö',
-                       expected: '<span class="highlight">Ö</span>sterreich'
-               },
-               {
-                       desc: 'Test 011: Highlighter broken on starting Umlaut?',
-                       text: 'Österreich',
-                       highlight: 'Öst',
-                       expected: '<span class="highlight">Öst</span>erreich'
-               },
-               {
-                       desc: 'Test 012: Highlighter broken on starting Umlaut?',
-                       text: 'Österreich',
-                       highlight: 'Oe',
-                       expected: 'Österreich'
-               },
-               {
-                       desc: 'Test 013: Highlighter broken on punctuation mark?',
-                       text: 'So good. To be there',
-                       highlight: 'good',
-                       expected: 'So <span class="highlight">good</span>. To be there'
-               },
-               {
-                       desc: 'Test 014: Highlighter broken on space?',
-                       text: 'So good. To be there',
-                       highlight: 'be',
-                       expected: 'So good. To <span class="highlight">be</span> there'
-               },
-               {
-                       desc: 'Test 015: Highlighter broken on space?',
-                       text: 'So good. To be there',
-                       highlight: ' be',
-                       expected: 'So good. To <span class="highlight">be</span> there'
-               },
-               {
-                       desc: 'Test 016: Highlighter broken on space?',
-                       text: 'So good. To be there',
-                       highlight: 'be ',
-                       expected: 'So good. To <span class="highlight">be</span> there'
-               },
-               {
-                       desc: 'Test 017: Highlighter broken on space?',
-                       text: 'So good. To be there',
-                       highlight: ' be ',
-                       expected: 'So good. To <span class="highlight">be</span> there'
-               },
-               {
-                       desc: 'Test 018: en de Highlighter broken on special character at the end?',
-                       text: 'So good. xbß',
-                       highlight: 'xbß',
-                       expected: 'So good. <span class="highlight">xbß</span>'
-               },
-               {
-                       desc: 'Test 019: en de Highlighter broken on special character at the end?',
-                       text: 'So good. xbß.',
-                       highlight: 'xbß.',
-                       expected: 'So good. <span class="highlight">xbß.</span>'
-               },
-               {
-                       desc: 'Test 020: RTL he Hebrew',
-                       text: 'חסיד אומות העולם',
-                       highlight: 'חסיד אומות העולם',
-                       expected: '<span class="highlight">חסיד</span> <span class="highlight">אומות</span> <span class="highlight">העולם</span>'
-               },
-               {
-                       desc: 'Test 021: RTL he Hebrew',
-                       text: 'חסיד אומות העולם',
-                       highlight: 'חסי',
-                       expected: '<span class="highlight">חסי</span>ד אומות העולם'
-               },
-               {
-                       desc: 'Test 022: ja Japanese',
-                       text: '諸国民の中の正義の人',
-                       highlight: '諸国民の中の正義の人',
-                       expected: '<span class="highlight">諸国民の中の正義の人</span>'
-               },
-               {
-                       desc: 'Test 023: ja Japanese',
-                       text: '諸国民の中の正義の人',
-                       highlight: '諸国',
-                       expected: '<span class="highlight">諸国</span>民の中の正義の人'
-               },
-               {
-                       desc: 'Test 024: fr French text and « french quotes » (guillemets)',
-                       text: "« L'oiseau est sur l’île »",
-                       highlight: "« L'oiseau est sur l’île »",
-                       expected: '<span class="highlight">«</span> <span class="highlight">L\'oiseau</span> <span class="highlight">est</span> <span class="highlight">sur</span> <span class="highlight">l’île</span> <span class="highlight">»</span>'
-               },
-               {
-                       desc: 'Test 025: fr French text and « french quotes » (guillemets)',
-                       text: "« L'oiseau est sur l’île »",
-                       highlight: "« L'oise",
-                       expected: '<span class="highlight">«</span> <span class="highlight">L\'oise</span>au est sur l’île »'
-               },
-               {
-                       desc: 'Test 025a: fr French text and « french quotes » (guillemets) - does it match the single strings "«" and "L" separately?',
-                       text: "« L'oiseau est sur l’île »",
-                       highlight: "« L",
-                       expected: '<span class="highlight">«</span> <span class="highlight">L</span>\'oiseau est sur <span class="highlight">l</span>’île »'
-               },
-               {
-                       desc: 'Test 026: ru Russian',
-                       text: 'Праведники мира',
-                       highlight: 'Праведники мира',
-                       expected: '<span class="highlight">Праведники</span> <span class="highlight">мира</span>'
-               },
-               {
-                       desc: 'Test 027: ru Russian',
-                       text: 'Праведники мира',
-                       highlight: 'Праве',
-                       expected: '<span class="highlight">Праве</span>дники мира'
-               },
-               {
-                       desc: 'Test 028 ka Georgian',
-                       text: 'მთავარი გვერდი',
-                       highlight: 'მთავარი გვერდი',
-                       expected: '<span class="highlight">მთავარი</span> <span class="highlight">გვერდი</span>'
-               },
-               {
-                       desc: 'Test 029 ka Georgian',
-                       text: 'მთავარი გვერდი',
-                       highlight: 'მთა',
-                       expected: '<span class="highlight">მთა</span>ვარი გვერდი'
-               },
-               {
-                       desc: 'Test 030 hy Armenian',
-                       text: 'Նոնա Գափրինդաշվիլի',
-                       highlight: 'Նոնա Գափրինդաշվիլի',
-                       expected: '<span class="highlight">Նոնա</span> <span class="highlight">Գափրինդաշվիլի</span>'
-               },
-               {
-                       desc: 'Test 031 hy Armenian',
-                       text: 'Նոնա Գափրինդաշվիլի',
-                       highlight: 'Նոն',
-                       expected: '<span class="highlight">Նոն</span>ա Գափրինդաշվիլի'
-               },
-               {
-                       desc: 'Test 032: th Thai',
-                       text: 'พอล แอร์ดิช',
-                       highlight: 'พอล แอร์ดิช',
-                       expected: '<span class="highlight">พอล</span> <span class="highlight">แอร์ดิช</span>'
-               },
-               {
-                       desc: 'Test 033: th Thai',
-                       text: 'พอล แอร์ดิช',
-                       highlight: 'พอ',
-                       expected: '<span class="highlight">พอ</span>ล แอร์ดิช'
-               },
-               {
-                       desc: 'Test 034: RTL ar Arabic',
-                       text: 'بول إيردوس',
-                       highlight: 'بول إيردوس',
-                       expected: '<span class="highlight">بول</span> <span class="highlight">إيردوس</span>'
-               },
-               {
-                       desc: 'Test 035: RTL ar Arabic',
-                       text: 'بول إيردوس',
-                       highlight: 'بو',
-                       expected: '<span class="highlight">بو</span>ل إيردوس'
-               }
-       ];
-       QUnit.expect( cases.length );
+       QUnit.test( 'Check', function ( assert ) {
+               var $fixture, cases = [
+                       {
+                               desc: 'Test 001',
+                               text: 'Blue Öyster Cult',
+                               highlight: 'Blue',
+                               expected: '<span class="highlight">Blue</span> Öyster Cult'
+                       },
+                       {
+                               desc: 'Test 002',
+                               text: 'Blue Öyster Cult',
+                               highlight: 'Blue ',
+                               expected: '<span class="highlight">Blue</span> Öyster Cult'
+                       },
+                       {
+                               desc: 'Test 003',
+                               text: 'Blue Öyster Cult',
+                               highlight: 'Blue Ö',
+                               expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
+                       },
+                       {
+                               desc: 'Test 004',
+                               text: 'Blue Öyster Cult',
+                               highlight: 'Blue Öy',
+                               expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
+                       },
+                       {
+                               desc: 'Test 005',
+                               text: 'Blue Öyster Cult',
+                               highlight: ' Blue',
+                               expected: '<span class="highlight">Blue</span> Öyster Cult'
+                       },
+                       {
+                               desc: 'Test 006',
+                               text: 'Blue Öyster Cult',
+                               highlight: ' Blue ',
+                               expected: '<span class="highlight">Blue</span> Öyster Cult'
+                       },
+                       {
+                               desc: 'Test 007',
+                               text: 'Blue Öyster Cult',
+                               highlight: ' Blue Ö',
+                               expected: '<span class="highlight">Blue</span> <span class="highlight">Ö</span>yster Cult'
+                       },
+                       {
+                               desc: 'Test 008',
+                               text: 'Blue Öyster Cult',
+                               highlight: ' Blue Öy',
+                               expected: '<span class="highlight">Blue</span> <span class="highlight">Öy</span>ster Cult'
+                       },
+                       {
+                               desc: 'Test 009: Highlighter broken on starting Umlaut?',
+                               text: 'Österreich',
+                               highlight: 'Österreich',
+                               expected: '<span class="highlight">Österreich</span>'
+                       },
+                       {
+                               desc: 'Test 010: Highlighter broken on starting Umlaut?',
+                               text: 'Österreich',
+                               highlight: 'Ö',
+                               expected: '<span class="highlight">Ö</span>sterreich'
+                       },
+                       {
+                               desc: 'Test 011: Highlighter broken on starting Umlaut?',
+                               text: 'Österreich',
+                               highlight: 'Öst',
+                               expected: '<span class="highlight">Öst</span>erreich'
+                       },
+                       {
+                               desc: 'Test 012: Highlighter broken on starting Umlaut?',
+                               text: 'Österreich',
+                               highlight: 'Oe',
+                               expected: 'Österreich'
+                       },
+                       {
+                               desc: 'Test 013: Highlighter broken on punctuation mark?',
+                               text: 'So good. To be there',
+                               highlight: 'good',
+                               expected: 'So <span class="highlight">good</span>. To be there'
+                       },
+                       {
+                               desc: 'Test 014: Highlighter broken on space?',
+                               text: 'So good. To be there',
+                               highlight: 'be',
+                               expected: 'So good. To <span class="highlight">be</span> there'
+                       },
+                       {
+                               desc: 'Test 015: Highlighter broken on space?',
+                               text: 'So good. To be there',
+                               highlight: ' be',
+                               expected: 'So good. To <span class="highlight">be</span> there'
+                       },
+                       {
+                               desc: 'Test 016: Highlighter broken on space?',
+                               text: 'So good. To be there',
+                               highlight: 'be ',
+                               expected: 'So good. To <span class="highlight">be</span> there'
+                       },
+                       {
+                               desc: 'Test 017: Highlighter broken on space?',
+                               text: 'So good. To be there',
+                               highlight: ' be ',
+                               expected: 'So good. To <span class="highlight">be</span> there'
+                       },
+                       {
+                               desc: 'Test 018: en de Highlighter broken on special character at the end?',
+                               text: 'So good. xbß',
+                               highlight: 'xbß',
+                               expected: 'So good. <span class="highlight">xbß</span>'
+                       },
+                       {
+                               desc: 'Test 019: en de Highlighter broken on special character at the end?',
+                               text: 'So good. xbß.',
+                               highlight: 'xbß.',
+                               expected: 'So good. <span class="highlight">xbß.</span>'
+                       },
+                       {
+                               desc: 'Test 020: RTL he Hebrew',
+                               text: 'חסיד אומות העולם',
+                               highlight: 'חסיד אומות העולם',
+                               expected: '<span class="highlight">חסיד</span> <span class="highlight">אומות</span> <span class="highlight">העולם</span>'
+                       },
+                       {
+                               desc: 'Test 021: RTL he Hebrew',
+                               text: 'חסיד אומות העולם',
+                               highlight: 'חסי',
+                               expected: '<span class="highlight">חסי</span>ד אומות העולם'
+                       },
+                       {
+                               desc: 'Test 022: ja Japanese',
+                               text: '諸国民の中の正義の人',
+                               highlight: '諸国民の中の正義の人',
+                               expected: '<span class="highlight">諸国民の中の正義の人</span>'
+                       },
+                       {
+                               desc: 'Test 023: ja Japanese',
+                               text: '諸国民の中の正義の人',
+                               highlight: '諸国',
+                               expected: '<span class="highlight">諸国</span>民の中の正義の人'
+                       },
+                       {
+                               desc: 'Test 024: fr French text and « french quotes » (guillemets)',
+                               text: '« L\'oiseau est sur l’île »',
+                               highlight: '« L\'oiseau est sur l’île »',
+                               expected: '<span class="highlight">«</span> <span class="highlight">L\'oiseau</span> <span class="highlight">est</span> <span class="highlight">sur</span> <span class="highlight">l’île</span> <span class="highlight">»</span>'
+                       },
+                       {
+                               desc: 'Test 025: fr French text and « french quotes » (guillemets)',
+                               text: '« L\'oiseau est sur l’île »',
+                               highlight: '« L\'oise',
+                               expected: '<span class="highlight">«</span> <span class="highlight">L\'oise</span>au est sur l’île »'
+                       },
+                       {
+                               desc: 'Test 025a: fr French text and « french quotes » (guillemets) - does it match the single strings "«" and "L" separately?',
+                               text: '« L\'oiseau est sur l’île »',
+                               highlight: '« L',
+                               expected: '<span class="highlight">«</span> <span class="highlight">L</span>\'oiseau est sur <span class="highlight">l</span>’île »'
+                       },
+                       {
+                               desc: 'Test 026: ru Russian',
+                               text: 'Праведники мира',
+                               highlight: 'Праведники мира',
+                               expected: '<span class="highlight">Праведники</span> <span class="highlight">мира</span>'
+                       },
+                       {
+                               desc: 'Test 027: ru Russian',
+                               text: 'Праведники мира',
+                               highlight: 'Праве',
+                               expected: '<span class="highlight">Праве</span>дники мира'
+                       },
+                       {
+                               desc: 'Test 028 ka Georgian',
+                               text: 'მთავარი გვერდი',
+                               highlight: 'მთავარი გვერდი',
+                               expected: '<span class="highlight">მთავარი</span> <span class="highlight">გვერდი</span>'
+                       },
+                       {
+                               desc: 'Test 029 ka Georgian',
+                               text: 'მთავარი გვერდი',
+                               highlight: 'მთა',
+                               expected: '<span class="highlight">მთა</span>ვარი გვერდი'
+                       },
+                       {
+                               desc: 'Test 030 hy Armenian',
+                               text: 'Նոնա Գափրինդաշվիլի',
+                               highlight: 'Նոնա Գափրինդաշվիլի',
+                               expected: '<span class="highlight">Նոնա</span> <span class="highlight">Գափրինդաշվիլի</span>'
+                       },
+                       {
+                               desc: 'Test 031 hy Armenian',
+                               text: 'Նոնա Գափրինդաշվիլի',
+                               highlight: 'Նոն',
+                               expected: '<span class="highlight">Նոն</span>ա Գափրինդաշվիլի'
+                       },
+                       {
+                               desc: 'Test 032: th Thai',
+                               text: 'พอล แอร์ดิช',
+                               highlight: 'พอล แอร์ดิช',
+                               expected: '<span class="highlight">พอล</span> <span class="highlight">แอร์ดิช</span>'
+                       },
+                       {
+                               desc: 'Test 033: th Thai',
+                               text: 'พอล แอร์ดิช',
+                               highlight: 'พอ',
+                               expected: '<span class="highlight">พอ</span>ล แอร์ดิช'
+                       },
+                       {
+                               desc: 'Test 034: RTL ar Arabic',
+                               text: 'بول إيردوس',
+                               highlight: 'بول إيردوس',
+                               expected: '<span class="highlight">بول</span> <span class="highlight">إيردوس</span>'
+                       },
+                       {
+                               desc: 'Test 035: RTL ar Arabic',
+                               text: 'بول إيردوس',
+                               highlight: 'بو',
+                               expected: '<span class="highlight">بو</span>ل إيردوس'
+                       }
+               ];
+               QUnit.expect( cases.length );
 
-       $.each( cases, function ( i, item ) {
-               $fixture = $( '<p>' ).text( item.text ).highlightText( item.highlight );
-               assert.equal(
-                       $fixture.html(),
-                       $( '<p>' ).html( item.expected ).html(), // re-parse to normalize!
-                       item.desc || undefined
-               );
+               $.each( cases, function ( i, item ) {
+                       $fixture = $( '<p>' ).text( item.text ).highlightText( item.highlight );
+                       assert.equal(
+                               $fixture.html(),
+                               // Re-parse to normalize
+                               $( '<p>' ).html( item.expected ).html(),
+                               item.desc || undefined
+                       );
+               } );
        } );
-} );
+}( jQuery ) );
index c8e1d9f..3810a04 100644 (file)
-QUnit.module( 'jquery.localize', QUnit.newMwEnvironment() );
+( function ( $, mw ) {
+       QUnit.module( 'jquery.localize', QUnit.newMwEnvironment() );
 
-QUnit.test( 'Handle basic replacements', 4, function ( assert ) {
-       var html, $lc;
-       mw.messages.set( 'basic', 'Basic stuff' );
+       QUnit.test( 'Handle basic replacements', 4, function ( assert ) {
+               var html, $lc;
+               mw.messages.set( 'basic', 'Basic stuff' );
 
-       // Tag: html:msg
-       html = '<div><span><html:msg key="basic" /></span></div>';
-       $lc = $( html ).localize().find( 'span' );
+               // Tag: html:msg
+               html = '<div><span><html:msg key="basic" /></span></div>';
+               $lc = $( html ).localize().find( 'span' );
 
-       assert.strictEqual( $lc.text(), 'Basic stuff', 'Tag: html:msg' );
+               assert.strictEqual( $lc.text(), 'Basic stuff', 'Tag: html:msg' );
 
-       // Attribute: title-msg
-       html = '<div><span title-msg="basic"></span></div>';
-       $lc = $( html ).localize().find( 'span' );
+               // Attribute: title-msg
+               html = '<div><span title-msg="basic"></span></div>';
+               $lc = $( html ).localize().find( 'span' );
 
-       assert.strictEqual( $lc.attr( 'title' ), 'Basic stuff', 'Attribute: title-msg' );
+               assert.strictEqual( $lc.attr( 'title' ), 'Basic stuff', 'Attribute: title-msg' );
 
-       // Attribute: alt-msg
-       html = '<div><span alt-msg="basic"></span></div>';
-       $lc = $( html ).localize().find( 'span' );
+               // Attribute: alt-msg
+               html = '<div><span alt-msg="basic"></span></div>';
+               $lc = $( html ).localize().find( 'span' );
 
-       assert.strictEqual( $lc.attr( 'alt' ), 'Basic stuff', 'Attribute: alt-msg' );
+               assert.strictEqual( $lc.attr( 'alt' ), 'Basic stuff', 'Attribute: alt-msg' );
 
-       // Attribute: placeholder-msg
-       html = '<div><input placeholder-msg="basic" /></div>';
-       $lc = $( html ).localize().find( 'input' );
+               // Attribute: placeholder-msg
+               html = '<div><input placeholder-msg="basic" /></div>';
+               $lc = $( html ).localize().find( 'input' );
 
-       assert.strictEqual( $lc.attr( 'placeholder' ), 'Basic stuff', 'Attribute: placeholder-msg' );
-} );
+               assert.strictEqual( $lc.attr( 'placeholder' ), 'Basic stuff', 'Attribute: placeholder-msg' );
+       } );
+
+       QUnit.test( 'Proper escaping', 2, function ( assert ) {
+               var html, $lc;
+               mw.messages.set( 'properfoo', '<proper esc="test">' );
+
+               // This is handled by jQuery inside $.fn.localize, just a simple sanity checked
+               // making sure it is actually using text() and attr() (or something with the same effect)
 
-QUnit.test( 'Proper escaping', 2, function ( assert ) {
-       var html, $lc;
-       mw.messages.set( 'properfoo', '<proper esc="test">' );
+               // Text escaping
+               html = '<div><span><html:msg key="properfoo"></span></div>';
+               $lc = $( html ).localize().find( 'span' );
 
-       // This is handled by jQuery inside $.fn.localize, just a simple sanity checked
-       // making sure it is actually using text() and attr() (or something with the same effect)
+               assert.strictEqual( $lc.text(), mw.msg( 'properfoo' ), 'Content is inserted as text, not as html.' );
 
-       // Text escaping
-       html = '<div><span><html:msg key="properfoo"></span></div>';
-       $lc = $( html ).localize().find( 'span' );
+               // Attribute escaping
+               html = '<div><span title-msg="properfoo"></span></div>';
+               $lc = $( html ).localize().find( 'span' );
 
-       assert.strictEqual( $lc.text(), mw.msg( 'properfoo' ), 'Content is inserted as text, not as html.' );
+               assert.strictEqual( $lc.attr( 'title' ), mw.msg( 'properfoo' ), 'Attributes are not inserted raw.' );
+       } );
 
-       // Attribute escaping
-       html = '<div><span title-msg="properfoo"></span></div>';
-       $lc = $( html ).localize().find( 'span' );
+       QUnit.test( 'Options', 7, function ( assert ) {
+               mw.messages.set( {
+                       'foo-lorem': 'Lorem',
+                       'foo-ipsum': 'Ipsum',
+                       'foo-bar-title': 'Read more about bars',
+                       'foo-bar-label': 'The Bars',
+                       'foo-bazz-title': 'Read more about bazz at $1 (last modified: $2)',
+                       'foo-bazz-label': 'The Bazz ($1)',
+                       'foo-welcome': 'Welcome to $1! (last visit: $2)'
+               } );
+               var html, $lc, x, sitename = 'Wikipedia';
+
+               // Message key prefix
+               html = '<div><span title-msg="lorem"><html:msg key="ipsum"></span></div>';
+               $lc = $( html ).localize( {
+                       prefix: 'foo-'
+               } ).find( 'span' );
+
+               assert.strictEqual( $lc.attr( 'title' ), 'Lorem', 'Message key prefix - attr' );
+               assert.strictEqual( $lc.text(), 'Ipsum', 'Message key prefix - text' );
+
+               // Variable keys mapping
+               x = 'bar';
+               html = '<div><span title-msg="title"><html:msg key="label"></span></div>';
+               $lc = $( html ).localize( {
+                       keys: {
+                               'title': 'foo-' + x + '-title',
+                               'label': 'foo-' + x + '-label'
+                       }
+               } ).find( 'span' );
+
+               assert.strictEqual( $lc.attr( 'title' ), 'Read more about bars', 'Variable keys mapping - attr' );
+               assert.strictEqual( $lc.text(), 'The Bars', 'Variable keys mapping - text' );
+
+               // Passing parameteters to mw.msg
+               html = '<div><span><html:msg key="foo-welcome"></span></div>';
+               $lc = $( html ).localize( {
+                       params: {
+                               'foo-welcome': [sitename, 'yesterday']
+                       }
+               } ).find( 'span' );
+
+               assert.strictEqual( $lc.text(), 'Welcome to Wikipedia! (last visit: yesterday)', 'Passing parameteters to mw.msg' );
+
+               // Combination of options prefix, params and keys
+               x = 'bazz';
+               html = '<div><span title-msg="title"><html:msg key="label"></span></div>';
+               $lc = $( html ).localize( {
+                       prefix: 'foo-',
+                       keys: {
+                               'title': x + '-title',
+                               'label': x + '-label'
+                       },
+                       params: {
+                               'title': [sitename, '3 minutes ago'],
+                               'label': [sitename, '3 minutes ago']
+
+                       }
+               } ).find( 'span' );
+
+               assert.strictEqual( $lc.text(), 'The Bazz (Wikipedia)', 'Combination of options prefix, params and keys - text' );
+               assert.strictEqual( $lc.attr( 'title' ), 'Read more about bazz at Wikipedia (last modified: 3 minutes ago)', 'Combination of options prefix, params and keys - attr' );
+       } );
 
-       assert.strictEqual( $lc.attr( 'title' ), mw.msg( 'properfoo' ), 'Attributes are not inserted raw.' );
-} );
+       QUnit.test( 'Handle data text', 2, function ( assert ) {
+               var html, $lc;
+               mw.messages.set( 'option-one', 'Item 1' );
+               mw.messages.set( 'option-two', 'Item 2' );
+               html = '<select><option data-msg-text="option-one"></option><option data-msg-text="option-two"></option></select>';
+               $lc = $( html ).localize().find( 'option' );
+               assert.strictEqual( $lc.eq( 0 ).text(), mw.msg( 'option-one' ), 'data-msg-text becomes text of options' );
+               assert.strictEqual( $lc.eq( 1 ).text(), mw.msg( 'option-two' ), 'data-msg-text becomes text of options' );
+       } );
 
-QUnit.test( 'Options', 7, function ( assert ) {
-       mw.messages.set( {
-               'foo-lorem': 'Lorem',
-               'foo-ipsum': 'Ipsum',
-               'foo-bar-title': 'Read more about bars',
-               'foo-bar-label': 'The Bars',
-               'foo-bazz-title': 'Read more about bazz at $1 (last modified: $2)',
-               'foo-bazz-label': 'The Bazz ($1)',
-               'foo-welcome': 'Welcome to $1! (last visit: $2)'
+       QUnit.test( 'Handle data html', 2, function ( assert ) {
+               var html, $lc;
+               mw.messages.set( 'html', 'behold... there is a <a>link</a> here!!' );
+               html = '<div><div data-msg-html="html"></div></div>';
+               $lc = $( html ).localize().find( 'a' );
+               assert.strictEqual( $lc.length, 1, 'link is created' );
+               assert.strictEqual( $lc.text(), 'link', 'the link text got added' );
        } );
-       var html, $lc, attrs, x, sitename = 'Wikipedia';
-
-       // Message key prefix
-       html = '<div><span title-msg="lorem"><html:msg key="ipsum"></span></div>';
-       $lc = $( html ).localize( {
-               prefix: 'foo-'
-       } ).find( 'span' );
-
-       assert.strictEqual( $lc.attr( 'title' ), 'Lorem', 'Message key prefix - attr' );
-       assert.strictEqual( $lc.text(), 'Ipsum', 'Message key prefix - text' );
-
-       // Variable keys mapping
-       x = 'bar';
-       html = '<div><span title-msg="title"><html:msg key="label"></span></div>';
-       $lc = $( html ).localize( {
-               keys: {
-                       'title': 'foo-' + x + '-title',
-                       'label': 'foo-' + x + '-label'
-               }
-       } ).find( 'span' );
-
-       assert.strictEqual( $lc.attr( 'title' ), 'Read more about bars', 'Variable keys mapping - attr' );
-       assert.strictEqual( $lc.text(), 'The Bars', 'Variable keys mapping - text' );
-
-       // Passing parameteters to mw.msg
-       html = '<div><span><html:msg key="foo-welcome"></span></div>';
-       $lc = $( html ).localize( {
-               params: {
-                       'foo-welcome': [sitename, 'yesterday']
-               }
-       } ).find( 'span' );
-
-       assert.strictEqual( $lc.text(), 'Welcome to Wikipedia! (last visit: yesterday)', 'Passing parameteters to mw.msg' );
-
-       // Combination of options prefix, params and keys
-       x = 'bazz';
-       html = '<div><span title-msg="title"><html:msg key="label"></span></div>';
-       $lc = $( html ).localize( {
-               prefix: 'foo-',
-               keys: {
-                       'title': x + '-title',
-                       'label': x + '-label'
-               },
-               params: {
-                       'title': [sitename, '3 minutes ago'],
-                       'label': [sitename, '3 minutes ago']
-
-               }
-       } ).find( 'span' );
-
-       assert.strictEqual( $lc.text(), 'The Bazz (Wikipedia)', 'Combination of options prefix, params and keys - text' );
-       assert.strictEqual( $lc.attr( 'title' ), 'Read more about bazz at Wikipedia (last modified: 3 minutes ago)', 'Combination of options prefix, params and keys - attr' );
-} );
-
-QUnit.test( 'Handle data text', 2, function ( assert ) {
-       var html, $lc;
-       mw.messages.set( 'option-one', 'Item 1' );
-       mw.messages.set( 'option-two', 'Item 2' );
-       html = '<select><option data-msg-text="option-one"></option><option data-msg-text="option-two"></option></select>';
-       $lc = $( html ).localize().find( 'option' );
-       assert.strictEqual( $lc.eq( 0 ).text(), mw.msg( 'option-one' ), 'data-msg-text becomes text of options' );
-       assert.strictEqual( $lc.eq( 1 ).text(), mw.msg( 'option-two' ), 'data-msg-text becomes text of options' );
-} );
-
-QUnit.test( 'Handle data html', 2, function ( assert ) {
-       var html, $lc;
-       mw.messages.set( 'html', 'behold... there is a <a>link</a> here!!' );
-       html = '<div><div data-msg-html="html"></div></div>';
-       $lc = $( html ).localize().find( 'a' );
-       assert.strictEqual( $lc.length, 1, 'link is created' );
-       assert.strictEqual( $lc.text(), 'link', 'the link text got added' );
-} );
+}( jQuery, mediaWiki ) ) ;
index 5b566ae..3ffcbf5 100644 (file)
@@ -1,58 +1,60 @@
-QUnit.module( 'jquery.mwExtension', QUnit.newMwEnvironment() );
-
-QUnit.test( 'String functions', function ( assert ) {
-
-       assert.equal( $.trimLeft( '  foo bar  ' ), 'foo bar  ', 'trimLeft' );
-       assert.equal( $.trimRight( '  foo bar  ' ), '  foo bar', 'trimRight' );
-       assert.equal( $.ucFirst( 'foo' ), 'Foo', 'ucFirst' );
-
-       assert.equal( $.escapeRE( '<!-- ([{+mW+}]) $^|?>' ),
-        '<!\\-\\- \\(\\[\\{\\+mW\\+\\}\\]\\) \\$\\^\\|\\?>', 'escapeRE - Escape specials' );
-       assert.equal( $.escapeRE( 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ),
-        'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'escapeRE - Leave uppercase alone' );
-       assert.equal( $.escapeRE( 'abcdefghijklmnopqrstuvwxyz' ),
-        'abcdefghijklmnopqrstuvwxyz', 'escapeRE - Leave lowercase alone' );
-       assert.equal( $.escapeRE( '0123456789' ), '0123456789', 'escapeRE - Leave numbers alone' );
-});
-
-QUnit.test( 'Is functions', function ( assert ) {
-
-       assert.strictEqual( $.isDomElement( document.getElementById( 'qunit-header' ) ), true,
-        'isDomElement: #qunit-header Node' );
-       assert.strictEqual( $.isDomElement( document.getElementById( 'random-name' ) ), false,
-        'isDomElement: #random-name (null)' );
-       assert.strictEqual( $.isDomElement( document.getElementsByTagName( 'div' ) ), false,
-        'isDomElement: getElementsByTagName Array' );
-       assert.strictEqual( $.isDomElement( document.getElementsByTagName( 'div' )[0] ), true,
-        'isDomElement: getElementsByTagName(..)[0] Node' );
-       assert.strictEqual( $.isDomElement( $( 'div' ) ), false,
-        'isDomElement: jQuery object' );
-       assert.strictEqual( $.isDomElement( $( 'div' ).get(0) ), true,
-        'isDomElement: jQuery object > Get node' );
-       assert.strictEqual( $.isDomElement( document.createElement( 'div' ) ), true,
-        'isDomElement: createElement' );
-       assert.strictEqual( $.isDomElement( { foo: 1 } ), false,
-        'isDomElement: Object' );
-
-       assert.strictEqual( $.isEmpty( 'string' ), false, 'isEmptry: "string"' );
-       assert.strictEqual( $.isEmpty( '0' ), true, 'isEmptry: "0"' );
-       assert.strictEqual( $.isEmpty( '' ), true, 'isEmptry: ""' );
-       assert.strictEqual( $.isEmpty( 1 ), false, 'isEmptry: 1' );
-       assert.strictEqual( $.isEmpty( [] ), true, 'isEmptry: []' );
-       assert.strictEqual( $.isEmpty( {} ), true, 'isEmptry: {}' );
-
-       // Documented behaviour
-       assert.strictEqual( $.isEmpty( { length: 0 } ), true, 'isEmptry: { length: 0 }' );
-});
-
-QUnit.test( 'Comparison functions', function ( assert ) {
-
-       assert.ok( $.compareArray( [0, 'a', [], [2, 'b'] ], [0, "a", [], [2, "b"] ] ),
-        'compareArray: Two deep arrays that are excactly the same' );
-       assert.ok( !$.compareArray( [1], [2] ), 'compareArray: Two different arrays (false)' );
-
-       assert.ok( $.compareObject( {}, {} ), 'compareObject: Two empty objects' );
-       assert.ok( $.compareObject( { foo: 1 }, { foo: 1 } ), 'compareObject: Two the same objects' );
-       assert.ok( !$.compareObject( { bar: true }, { baz: false } ),
-        'compareObject: Two different objects (false)' );
-});
+( function ( $ ) {
+       QUnit.module( 'jquery.mwExtension', QUnit.newMwEnvironment() );
+
+       QUnit.test( 'String functions', function ( assert ) {
+
+               assert.equal( $.trimLeft( '  foo bar  ' ), 'foo bar  ', 'trimLeft' );
+               assert.equal( $.trimRight( '  foo bar  ' ), '  foo bar', 'trimRight' );
+               assert.equal( $.ucFirst( 'foo' ), 'Foo', 'ucFirst' );
+
+               assert.equal( $.escapeRE( '<!-- ([{+mW+}]) $^|?>' ),
+                '<!\\-\\- \\(\\[\\{\\+mW\\+\\}\\]\\) \\$\\^\\|\\?>', 'escapeRE - Escape specials' );
+               assert.equal( $.escapeRE( 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ),
+                'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'escapeRE - Leave uppercase alone' );
+               assert.equal( $.escapeRE( 'abcdefghijklmnopqrstuvwxyz' ),
+                'abcdefghijklmnopqrstuvwxyz', 'escapeRE - Leave lowercase alone' );
+               assert.equal( $.escapeRE( '0123456789' ), '0123456789', 'escapeRE - Leave numbers alone' );
+       });
+
+       QUnit.test( 'Is functions', function ( assert ) {
+
+               assert.strictEqual( $.isDomElement( document.getElementById( 'qunit-header' ) ), true,
+                'isDomElement: #qunit-header Node' );
+               assert.strictEqual( $.isDomElement( document.getElementById( 'random-name' ) ), false,
+                'isDomElement: #random-name (null)' );
+               assert.strictEqual( $.isDomElement( document.getElementsByTagName( 'div' ) ), false,
+                'isDomElement: getElementsByTagName Array' );
+               assert.strictEqual( $.isDomElement( document.getElementsByTagName( 'div' )[0] ), true,
+                'isDomElement: getElementsByTagName(..)[0] Node' );
+               assert.strictEqual( $.isDomElement( $( 'div' ) ), false,
+                'isDomElement: jQuery object' );
+               assert.strictEqual( $.isDomElement( $( 'div' ).get(0) ), true,
+                'isDomElement: jQuery object > Get node' );
+               assert.strictEqual( $.isDomElement( document.createElement( 'div' ) ), true,
+                'isDomElement: createElement' );
+               assert.strictEqual( $.isDomElement( { foo: 1 } ), false,
+                'isDomElement: Object' );
+
+               assert.strictEqual( $.isEmpty( 'string' ), false, 'isEmptry: "string"' );
+               assert.strictEqual( $.isEmpty( '0' ), true, 'isEmptry: "0"' );
+               assert.strictEqual( $.isEmpty( '' ), true, 'isEmptry: ""' );
+               assert.strictEqual( $.isEmpty( 1 ), false, 'isEmptry: 1' );
+               assert.strictEqual( $.isEmpty( [] ), true, 'isEmptry: []' );
+               assert.strictEqual( $.isEmpty( {} ), true, 'isEmptry: {}' );
+
+               // Documented behaviour
+               assert.strictEqual( $.isEmpty( { length: 0 } ), true, 'isEmptry: { length: 0 }' );
+       });
+
+       QUnit.test( 'Comparison functions', function ( assert ) {
+
+               assert.ok( $.compareArray( [0, 'a', [], [2, 'b'] ], [0, 'a', [], [2, 'b'] ] ),
+                'compareArray: Two deep arrays that are excactly the same' );
+               assert.ok( !$.compareArray( [1], [2] ), 'compareArray: Two different arrays (false)' );
+
+               assert.ok( $.compareObject( {}, {} ), 'compareObject: Two empty objects' );
+               assert.ok( $.compareObject( { foo: 1 }, { foo: 1 } ), 'compareObject: Two the same objects' );
+               assert.ok( !$.compareObject( { bar: true }, { baz: false } ),
+                'compareObject: Two different objects (false)' );
+       });
+}( jQuery ) );
index 161f0cd..e31fc63 100644 (file)
@@ -1,33 +1,37 @@
-QUnit.module( 'jquery.tabIndex', QUnit.newMwEnvironment() );
+( function ( $ ) {
+       QUnit.module( 'jquery.tabIndex', QUnit.newMwEnvironment() );
 
-QUnit.test( 'firstTabIndex', 2, function ( assert ) {
-       var testEnvironment =
-'<form>' +
-       '<input tabindex="7" />' +
-       '<input tabindex="9" />' +
-       '<textarea tabindex="2">Foobar</textarea>' +
-       '<textarea tabindex="5">Foobar</textarea>' +
-'</form>';
+       QUnit.test( 'firstTabIndex', 2, function ( assert ) {
+               var html, $testA, $testB;
+               html =
+       '<form>' +
+               '<input tabindex="7" />' +
+               '<input tabindex="9" />' +
+               '<textarea tabindex="2">Foobar</textarea>' +
+               '<textarea tabindex="5">Foobar</textarea>' +
+       '</form>';
 
-       var $testA = $( '<div>' ).html( testEnvironment ).appendTo( '#qunit-fixture' );
-       assert.strictEqual( $testA.firstTabIndex(), 2, 'First tabindex should be 2 within this context.' );
+               $testA = $( '<div>' ).html( html ).appendTo( '#qunit-fixture' );
+               assert.strictEqual( $testA.firstTabIndex(), 2, 'First tabindex should be 2 within this context.' );
 
-       var $testB = $( '<div>' );
-       assert.strictEqual( $testB.firstTabIndex(), null, 'Return null if none available.' );
-});
+               $testB = $( '<div>' );
+               assert.strictEqual( $testB.firstTabIndex(), null, 'Return null if none available.' );
+       });
 
-QUnit.test( 'lastTabIndex', 2, function ( assert ) {
-       var testEnvironment =
-'<form>' +
-       '<input tabindex="7" />' +
-       '<input tabindex="9" />' +
-       '<textarea tabindex="2">Foobar</textarea>' +
-       '<textarea tabindex="5">Foobar</textarea>' +
-'</form>';
+       QUnit.test( 'lastTabIndex', 2, function ( assert ) {
+               var html, $testA, $testB;
+               html =
+       '<form>' +
+               '<input tabindex="7" />' +
+               '<input tabindex="9" />' +
+               '<textarea tabindex="2">Foobar</textarea>' +
+               '<textarea tabindex="5">Foobar</textarea>' +
+       '</form>';
 
-       var $testA = $( '<div>' ).html( testEnvironment ).appendTo( '#qunit-fixture' );
-       assert.strictEqual( $testA.lastTabIndex(), 9, 'Last tabindex should be 9 within this context.' );
+               $testA = $( '<div>' ).html( html ).appendTo( '#qunit-fixture' );
+               assert.strictEqual( $testA.lastTabIndex(), 9, 'Last tabindex should be 9 within this context.' );
 
-       var $testB = $( '<div>' );
-       assert.strictEqual( $testB.lastTabIndex(), null, 'Return null if none available.' );
-});
+               $testB = $( '<div>' );
+               assert.strictEqual( $testB.lastTabIndex(), null, 'Return null if none available.' );
+       });
+}( jQuery ) );
index 291c6b8..b04a213 100644 (file)
 ( function ( $, mw ) {
-
-var config = {
-       wgMonthNames: ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
-       wgMonthNamesShort: ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
-       wgDefaultDateFormat: 'dmy',
-       wgContentLanguage: 'en'
-};
-
-QUnit.module( 'jquery.tablesorter', QUnit.newMwEnvironment({ config: config }) );
-
-/**
- * Create an HTML table from an array of row arrays containing text strings.
- * First row will be header row. No fancy rowspan/colspan stuff.
- *
- * @param {String[]} header
- * @param {String[][]} data
- * @return jQuery
- */
-function tableCreate(  header, data ) {
-       var i,
-               $table = $( '<table class="sortable"><thead></thead><tbody></tbody></table>' ),
-               $thead = $table.find( 'thead' ),
-               $tbody = $table.find( 'tbody' ),
-               $tr = $( '<tr>' );
-
-       $.each( header, function ( i, str ) {
-               var $th = $( '<th>' );
-               $th.text( str ).appendTo( $tr );
-       });
-       $tr.appendTo( $thead );
-
-       for ( i = 0; i < data.length; i++ ) {
-               $tr = $( '<tr>' );
-               $.each( data[i], function ( j, str ) {
-                       var $td = $( '<td>' );
-                       $td.text( str ).appendTo( $tr );
+       /*jshint onevar: false */
+
+       var config = {
+               wgMonthNames: ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
+               wgMonthNamesShort: ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+               wgDefaultDateFormat: 'dmy',
+               wgContentLanguage: 'en'
+       };
+
+       QUnit.module( 'jquery.tablesorter', QUnit.newMwEnvironment({ config: config }) );
+
+       /**
+        * Create an HTML table from an array of row arrays containing text strings.
+        * First row will be header row. No fancy rowspan/colspan stuff.
+        *
+        * @param {String[]} header
+        * @param {String[][]} data
+        * @return jQuery
+        */
+       function tableCreate(  header, data ) {
+               var i,
+                       $table = $( '<table class="sortable"><thead></thead><tbody></tbody></table>' ),
+                       $thead = $table.find( 'thead' ),
+                       $tbody = $table.find( 'tbody' ),
+                       $tr = $( '<tr>' );
+
+               $.each( header, function ( i, str ) {
+                       var $th = $( '<th>' );
+                       $th.text( str ).appendTo( $tr );
                });
-               $tr.appendTo( $tbody );
+               $tr.appendTo( $thead );
+
+               for ( i = 0; i < data.length; i++ ) {
+                       /*jshint loopfunc: true */
+                       $tr = $( '<tr>' );
+                       $.each( data[i], function ( j, str ) {
+                               var $td = $( '<td>' );
+                               $td.text( str ).appendTo( $tr );
+                       });
+                       $tr.appendTo( $tbody );
+               }
+               return $table;
        }
-       return $table;
-}
-
-/**
- * Extract text from table.
- *
- * @param {jQuery} $table
- * @return String[][]
- */
-function tableExtract( $table ) {
-       var data = [];
-
-       $table.find( 'tbody' ).find( 'tr' ).each( function( i, tr ) {
-               var row = [];
-               $( tr ).find( 'td,th' ).each( function( i, td ) {
-                       row.push( $( td ).text() );
+
+       /**
+        * Extract text from table.
+        *
+        * @param {jQuery} $table
+        * @return String[][]
+        */
+       function tableExtract( $table ) {
+               var data = [];
+
+               $table.find( 'tbody' ).find( 'tr' ).each( function( i, tr ) {
+                       var row = [];
+                       $( tr ).find( 'td,th' ).each( function( i, td ) {
+                               row.push( $( td ).text() );
+                       });
+                       data.push( row );
                });
-               data.push( row );
-       });
-       return data;
-}
-
-/**
- * Run a table test by building a table with the given data,
- * running some callback on it, then checking the results.
- *
- * @param {String} msg text to pass on to qunit for the comparison
- * @param {String[]} header cols to make the table
- * @param {String[][]} data rows/cols to make the table
- * @param {String[][]} expected rows/cols to compare against at end
- * @param {function($table)} callback something to do with the table before we compare
- */
-function tableTest( msg, header, data, expected, callback ) {
-       QUnit.test( msg, 1, function ( assert ) {
-               var $table = tableCreate( header, data );
-
-               // Give caller a chance to set up sorting and manipulate the table.
-               callback( $table );
-
-               // Table sorting is done synchronously; if it ever needs to change back
-               // to asynchronous, we'll need a timeout or a callback here.
-               var extracted = tableExtract( $table );
-               assert.deepEqual( extracted, expected, msg );
-       });
-}
-
-function reversed(arr) {
-       // Clone array
-       var arr2 = arr.slice(0);
-
-       arr2.reverse();
-
-       return arr2;
-}
-
-// Sample data set using planets named and their radius
-var header  = [ 'Planet' , 'Radius (km)'],
-       mercury = [ 'Mercury', '2439.7' ],
-       venus   = [ 'Venus'  , '6051.8' ],
-       earth   = [ 'Earth'  , '6371.0' ],
-       mars    = [ 'Mars'   , '3390.0' ],
-       jupiter = [ 'Jupiter',  '69911' ],
-       saturn  = [ 'Saturn' ,  '58232' ];
-
-// Initial data set
-var planets         = [mercury, venus, earth, mars, jupiter, saturn];
-var ascendingName   = [earth, jupiter, mars, mercury, saturn, venus];
-var ascendingRadius = [mercury, mars, venus, earth, saturn, jupiter];
-
-tableTest(
-       'Basic planet table: sorting initially - ascending by name',
-       header,
-       planets,
-       ascendingName,
-       function ( $table ) {
-               $table.tablesorter( { sortList: [ { 0: 'asc' } ] } );
-       }
-);
-tableTest(
-       'Basic planet table: sorting initially - descending by radius',
-       header,
-       planets,
-       reversed(ascendingRadius),
-       function ( $table ) {
-               $table.tablesorter( { sortList: [ { 1: 'desc' } ] } );
-       }
-);
-tableTest(
-       'Basic planet table: ascending by name',
-       header,
-       planets,
-       ascendingName,
-       function ( $table ) {
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-tableTest(
-       'Basic planet table: ascending by name a second time',
-       header,
-       planets,
-       ascendingName,
-       function ( $table ) {
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-tableTest(
-       'Basic planet table: descending by name',
-       header,
-       planets,
-       reversed(ascendingName),
-       function ( $table ) {
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click().click();
+               return data;
        }
-);
-tableTest(
-       'Basic planet table: ascending radius',
-       header,
-       planets,
-       ascendingRadius,
-       function ( $table ) {
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(1)' ).click();
+
+       /**
+        * Run a table test by building a table with the given data,
+        * running some callback on it, then checking the results.
+        *
+        * @param {String} msg text to pass on to qunit for the comparison
+        * @param {String[]} header cols to make the table
+        * @param {String[][]} data rows/cols to make the table
+        * @param {String[][]} expected rows/cols to compare against at end
+        * @param {function($table)} callback something to do with the table before we compare
+        */
+       function tableTest( msg, header, data, expected, callback ) {
+               QUnit.test( msg, 1, function ( assert ) {
+                       var $table = tableCreate( header, data );
+
+                       // Give caller a chance to set up sorting and manipulate the table.
+                       callback( $table );
+
+                       // Table sorting is done synchronously; if it ever needs to change back
+                       // to asynchronous, we'll need a timeout or a callback here.
+                       var extracted = tableExtract( $table );
+                       assert.deepEqual( extracted, expected, msg );
+               });
        }
-);
-tableTest(
-       'Basic planet table: descending radius',
-       header,
-       planets,
-       reversed(ascendingRadius),
-       function ( $table ) {
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(1)' ).click().click();
+
+       function reversed(arr) {
+               // Clone array
+               var arr2 = arr.slice(0);
+
+               arr2.reverse();
+
+               return arr2;
        }
-);
-
-// Sample data set to test multiple column sorting
-var header  = [ 'column1' , 'column2'],
-       a1 = [ 'A', '1' ],
-       a2 = [ 'A', '2' ],
-       a3 = [ 'A', '3' ],
-       b1 = [ 'B', '1' ],
-       b2 = [ 'B', '2' ],
-       b3 = [ 'B', '3' ];
-var initial = [a2, b3, a1, a3, b2, b1];
-var asc = [a1, a2, a3, b1, b2, b3];
-var descasc = [b1, b2, b3, a1, a2, a3];
-
-tableTest(
-       'Sorting multiple columns by passing sort list',
-       header,
-       initial,
-       asc,
-       function ( $table ) {
+
+       // Sample data set using planets named and their radius
+       var header  = [ 'Planet' , 'Radius (km)'],
+               mercury = [ 'Mercury', '2439.7' ],
+               venus   = [ 'Venus'  , '6051.8' ],
+               earth   = [ 'Earth'  , '6371.0' ],
+               mars    = [ 'Mars'   , '3390.0' ],
+               jupiter = [ 'Jupiter',  '69911' ],
+               saturn  = [ 'Saturn' ,  '58232' ];
+
+       // Initial data set
+       var planets         = [mercury, venus, earth, mars, jupiter, saturn];
+       var ascendingName   = [earth, jupiter, mars, mercury, saturn, venus];
+       var ascendingRadius = [mercury, mars, venus, earth, saturn, jupiter];
+
+       tableTest(
+               'Basic planet table: sorting initially - ascending by name',
+               header,
+               planets,
+               ascendingName,
+               function ( $table ) {
+                       $table.tablesorter( { sortList: [ { 0: 'asc' } ] } );
+               }
+       );
+       tableTest(
+               'Basic planet table: sorting initially - descending by radius',
+               header,
+               planets,
+               reversed(ascendingRadius),
+               function ( $table ) {
+                       $table.tablesorter( { sortList: [ { 1: 'desc' } ] } );
+               }
+       );
+       tableTest(
+               'Basic planet table: ascending by name',
+               header,
+               planets,
+               ascendingName,
+               function ( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
+       );
+       tableTest(
+               'Basic planet table: ascending by name a second time',
+               header,
+               planets,
+               ascendingName,
+               function ( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
+       );
+       tableTest(
+               'Basic planet table: descending by name',
+               header,
+               planets,
+               reversed(ascendingName),
+               function ( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click().click();
+               }
+       );
+       tableTest(
+               'Basic planet table: ascending radius',
+               header,
+               planets,
+               ascendingRadius,
+               function ( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(1)' ).click();
+               }
+       );
+       tableTest(
+               'Basic planet table: descending radius',
+               header,
+               planets,
+               reversed(ascendingRadius),
+               function ( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(1)' ).click().click();
+               }
+       );
+
+       // Sample data set to test multiple column sorting
+       header = [ 'column1' , 'column2'];
+       var
+               a1 = [ 'A', '1' ],
+               a2 = [ 'A', '2' ],
+               a3 = [ 'A', '3' ],
+               b1 = [ 'B', '1' ],
+               b2 = [ 'B', '2' ],
+               b3 = [ 'B', '3' ];
+       var initial = [a2, b3, a1, a3, b2, b1];
+       var asc = [a1, a2, a3, b1, b2, b3];
+       var descasc = [b1, b2, b3, a1, a2, a3];
+
+       tableTest(
+               'Sorting multiple columns by passing sort list',
+               header,
+               initial,
+               asc,
+               function ( $table ) {
+                       $table.tablesorter(
+                               { sortList: [ { 0: 'asc' }, { 1: 'asc' } ] }
+                       );
+               }
+       );
+       tableTest(
+               'Sorting multiple columns by programmatically triggering sort()',
+               header,
+               initial,
+               descasc,
+               function ( $table ) {
+                       $table.tablesorter();
+                       $table.data( 'tablesorter' ).sort(
+                               [ { 0: 'desc' }, { 1: 'asc' } ]
+                       );
+               }
+       );
+       tableTest(
+               'Reset to initial sorting by triggering sort() without any parameters',
+               header,
+               initial,
+               asc,
+               function ( $table ) {
+                       $table.tablesorter(
+                               { sortList: [ { 0: 'asc' }, { 1: 'asc' } ] }
+                       );
+                       $table.data( 'tablesorter' ).sort(
+                               [ { 0: 'desc' }, { 1: 'asc' } ]
+                       );
+                       $table.data( 'tablesorter' ).sort();
+               }
+       );
+       QUnit.test( 'Reset sorting making table appear unsorted', 3, function ( assert ) {
+               var $table = tableCreate( header, initial );
                $table.tablesorter(
-                       { sortList: [ { 0: 'asc' }, { 1: 'asc' } ] }
+                       { sortList: [ { 0: 'desc' }, { 1: 'asc' } ] }
                );
-       }
-);
-tableTest(
-       'Sorting multiple columns by programmatically triggering sort()',
-       header,
-       initial,
-       descasc,
-       function ( $table ) {
-               $table.tablesorter();
-               $table.data( 'tablesorter' ).sort(
-                       [ { 0: 'desc' }, { 1: 'asc' } ]
+               $table.data( 'tablesorter' ).sort( [] );
+
+               assert.equal(
+                       $table.find( 'th.headerSortUp' ).length + $table.find( 'th.headerSortDown' ).length,
+                       0,
+                       'No sort specific sort classes addign to header cells'
                );
-       }
-);
-tableTest(
-       'Reset to initial sorting by triggering sort() without any parameters',
-       header,
-       initial,
-       asc,
-       function ( $table ) {
-               $table.tablesorter(
-                       { sortList: [ { 0: 'asc' }, { 1: 'asc' } ] }
+
+               assert.equal(
+                       $table.find( 'th' ).first().attr( 'title' ),
+                       mw.msg( 'sort-ascending' ),
+                       'First header cell has default title'
                );
-               $table.data( 'tablesorter' ).sort(
-                       [ { 0: 'desc' }, { 1: 'asc' } ]
+
+               assert.equal(
+                       $table.find( 'th' ).first().attr( 'title' ),
+                       $table.find( 'th' ).last().attr( 'title' ),
+                       'Both header cells\' titles match'
                );
-               $table.data( 'tablesorter' ).sort();
-       }
-);
-QUnit.test( 'Reset sorting making table appear unsorted', 3, function ( assert ) {
-       var $table = tableCreate( header, initial );
-       $table.tablesorter(
-               { sortList: [ { 0: 'desc' }, { 1: 'asc' } ] }
+       } );
+
+       // Regression tests!
+       tableTest(
+               'Bug 28775: German-style (dmy) short numeric dates',
+               ['Date'],
+               [ // German-style dates are day-month-year
+                       ['11.11.2011'],
+                       ['01.11.2011'],
+                       ['02.10.2011'],
+                       ['03.08.2011'],
+                       ['09.11.2011']
+               ],
+               [ // Sorted by ascending date
+                       ['03.08.2011'],
+                       ['02.10.2011'],
+                       ['01.11.2011'],
+                       ['09.11.2011'],
+                       ['11.11.2011']
+               ],
+               function ( $table ) {
+                       mw.config.set( 'wgDefaultDateFormat', 'dmy' );
+                       mw.config.set( 'wgContentLanguage', 'de' );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
        );
-       $table.data( 'tablesorter' ).sort( [] );
 
-       assert.equal(
-               $table.find( 'th.headerSortUp' ).length + $table.find( 'th.headerSortDown' ).length,
-               0,
-               'No sort specific sort classes addign to header cells'
+       tableTest(
+               'Bug 28775: American-style (mdy) short numeric dates',
+               ['Date'],
+               [ // American-style dates are month-day-year
+                       ['11.11.2011'],
+                       ['01.11.2011'],
+                       ['02.10.2011'],
+                       ['03.08.2011'],
+                       ['09.11.2011']
+               ],
+               [ // Sorted by ascending date
+                       ['01.11.2011'],
+                       ['02.10.2011'],
+                       ['03.08.2011'],
+                       ['09.11.2011'],
+                       ['11.11.2011']
+               ],
+               function ( $table ) {
+                       mw.config.set( 'wgDefaultDateFormat', 'mdy' );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
        );
 
-       assert.equal(
-               $table.find( 'th' ).first().attr( 'title' ),
-               mw.msg( 'sort-ascending' ),
-               'First header cell has default title'
+       var ipv4 = [
+               // Some randomly generated fake IPs
+               ['45.238.27.109'],
+               ['44.172.9.22'],
+               ['247.240.82.209'],
+               ['204.204.132.158'],
+               ['170.38.91.162'],
+               ['197.219.164.9'],
+               ['45.68.154.72'],
+               ['182.195.149.80']
+       ];
+       var ipv4Sorted = [
+               // Sort order should go octet by octet
+               ['44.172.9.22'],
+               ['45.68.154.72'],
+               ['45.238.27.109'],
+               ['170.38.91.162'],
+               ['182.195.149.80'],
+               ['197.219.164.9'],
+               ['204.204.132.158'],
+               ['247.240.82.209']
+       ];
+
+       tableTest(
+               'Bug 17141: IPv4 address sorting',
+               ['IP'],
+               ipv4,
+               ipv4Sorted,
+               function ( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
        );
-
-       assert.equal(
-               $table.find( 'th' ).first().attr( 'title' ),
-               $table.find( 'th' ).last().attr( 'title' ),
-               'Both header cells\' titles match'
+       tableTest(
+               'Bug 17141: IPv4 address sorting (reverse)',
+               ['IP'],
+               ipv4,
+               reversed(ipv4Sorted),
+               function ( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click().click();
+               }
        );
-} );
-
-// Regression tests!
-tableTest(
-       'Bug 28775: German-style (dmy) short numeric dates',
-       ['Date'],
-       [ // German-style dates are day-month-year
-               ['11.11.2011'],
-               ['01.11.2011'],
-               ['02.10.2011'],
-               ['03.08.2011'],
-               ['09.11.2011']
-       ],
-       [ // Sorted by ascending date
-               ['03.08.2011'],
-               ['02.10.2011'],
-               ['01.11.2011'],
-               ['09.11.2011'],
-               ['11.11.2011']
-       ],
-       function ( $table ) {
-               mw.config.set( 'wgDefaultDateFormat', 'dmy' );
-               mw.config.set( 'wgContentLanguage', 'de' );
 
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-
-tableTest(
-       'Bug 28775: American-style (mdy) short numeric dates',
-       ['Date'],
-       [ // American-style dates are month-day-year
-               ['11.11.2011'],
-               ['01.11.2011'],
-               ['02.10.2011'],
-               ['03.08.2011'],
-               ['09.11.2011']
-       ],
-       [ // Sorted by ascending date
-               ['01.11.2011'],
-               ['02.10.2011'],
-               ['03.08.2011'],
-               ['09.11.2011'],
-               ['11.11.2011']
-       ],
-       function ( $table ) {
-               mw.config.set( 'wgDefaultDateFormat', 'mdy' );
-
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-
-var ipv4 = [
-       // Some randomly generated fake IPs
-       ['45.238.27.109'],
-       ['44.172.9.22'],
-       ['247.240.82.209'],
-       ['204.204.132.158'],
-       ['170.38.91.162'],
-       ['197.219.164.9'],
-       ['45.68.154.72'],
-       ['182.195.149.80']
-];
-var ipv4Sorted = [
-       // Sort order should go octet by octet
-       ['44.172.9.22'],
-       ['45.68.154.72'],
-       ['45.238.27.109'],
-       ['170.38.91.162'],
-       ['182.195.149.80'],
-       ['197.219.164.9'],
-       ['204.204.132.158'],
-       ['247.240.82.209']
-];
-
-tableTest(
-       'Bug 17141: IPv4 address sorting',
-       ['IP'],
-       ipv4,
-       ipv4Sorted,
-       function ( $table ) {
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-tableTest(
-       'Bug 17141: IPv4 address sorting (reverse)',
-       ['IP'],
-       ipv4,
-       reversed(ipv4Sorted),
-       function ( $table ) {
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click().click();
-       }
-);
-
-var umlautWords = [
-       // Some words with Umlauts
-       ['Günther'],
-       ['Peter'],
-       ['Björn'],
-       ['Bjorn'],
-       ['Apfel'],
-       ['Äpfel'],
-       ['Strasse'],
-       ['Sträßschen']
-];
-
-var umlautWordsSorted = [
-       // Some words with Umlauts
-       ['Äpfel'],
-       ['Apfel'],
-       ['Björn'],
-       ['Bjorn'],
-       ['Günther'],
-       ['Peter'],
-       ['Sträßschen'],
-       ['Strasse']
-];
-
-tableTest(
-       'Accented Characters with custom collation',
-       ['Name'],
-       umlautWords,
-       umlautWordsSorted,
-       function ( $table ) {
-               mw.config.set( 'tableSorterCollation', {
-                       'ä': 'ae',
-                       'ö': 'oe',
-                       'ß': 'ss',
-                       'ü':'ue'
-               } );
-
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-
-var planetsRowspan = [["Earth","6051.8"], jupiter, ["Mars","6051.8"], mercury, saturn, venus];
-var planetsRowspanII = [jupiter, mercury, saturn, venus, ['Venus', '6371.0'], ['Venus', '3390.0']];
-
-tableTest(
-       'Basic planet table: same value for multiple rows via rowspan',
-       header,
-       planets,
-       planetsRowspan,
-       function ( $table ) {
-               // Modify the table to have a multiple-row-spanning cell:
-               // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
-               $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
-               // - Set rowspan for 2nd cell of 3rd row to 3.
-               //   This covers the removed cell in the 4th and 5th row.
-               $table.find( 'tr:eq(2) td:eq(1)' ).prop( 'rowspan', '3' );
-
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-tableTest(
-       'Basic planet table: same value for multiple rows via rowspan (sorting initially)',
-       header,
-       planets,
-       planetsRowspan,
-       function ( $table ) {
-               // Modify the table to have a multiple-row-spanning cell:
-               // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
-               $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
-               // - Set rowspan for 2nd cell of 3rd row to 3.
-               //   This covers the removed cell in the 4th and 5th row.
-               $table.find( 'tr:eq(2) td:eq(1)' ).prop( 'rowspan', '3' );
-
-               $table.tablesorter( { sortList: [ { 0: 'asc' } ] } );
-       }
-);
-tableTest(
-       'Basic planet table: Same value for multiple rows via rowspan II',
-       header,
-       planets,
-       planetsRowspanII,
-       function ( $table ) {
-               // Modify the table to have a multiple-row-spanning cell:
-               // - Remove 1st cell of 4th row, and, 1st cell or 5th row.
-               $table.find( 'tr:eq(3) td:eq(0), tr:eq(4) td:eq(0)' ).remove();
-               // - Set rowspan for 1st cell of 3rd row to 3.
-               //   This covers the removed cell in the 4th and 5th row.
-               $table.find( 'tr:eq(2) td:eq(0)' ).prop( 'rowspan', '3' );
-
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-
-var complexMDYDates = [
-       // Some words with Umlauts
-       ['January, 19 2010'],
-       ['April 21 1991'],
-       ['04 22 1991'],
-       ['5.12.1990'],
-       ['December 12 \'10']
-];
-
-var complexMDYSorted = [
-       ['5.12.1990'],
-       ['April 21 1991'],
-       ['04 22 1991'],
-       ['January, 19 2010'],
-       ['December 12 \'10']
-];
-
-tableTest(
-       'Complex date parsing I',
-       ['date'],
-       complexMDYDates,
-       complexMDYSorted,
-       function ( $table ) {
-               mw.config.set( 'wgDefaultDateFormat', 'mdy' );
+       var umlautWords = [
+               // Some words with Umlauts
+               ['Günther'],
+               ['Peter'],
+               ['Björn'],
+               ['Bjorn'],
+               ['Apfel'],
+               ['Äpfel'],
+               ['Strasse'],
+               ['Sträßschen']
+       ];
+
+       var umlautWordsSorted = [
+               // Some words with Umlauts
+               ['Äpfel'],
+               ['Apfel'],
+               ['Björn'],
+               ['Bjorn'],
+               ['Günther'],
+               ['Peter'],
+               ['Sträßschen'],
+               ['Strasse']
+       ];
+
+       tableTest(
+               'Accented Characters with custom collation',
+               ['Name'],
+               umlautWords,
+               umlautWordsSorted,
+               function ( $table ) {
+                       mw.config.set( 'tableSorterCollation', {
+                               'ä': 'ae',
+                               'ö': 'oe',
+                               'ß': 'ss',
+                               'ü':'ue'
+                       } );
 
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-
-var currencyUnsorted = [
-       ['1.02 $'],
-       ['$ 3.00'],
-       ['€ 2,99'],
-       ['$ 1.00'],
-       ['$3.50'],
-       ['$ 1.50'],
-       ['€ 0.99']
-];
-
-var currencySorted = [
-       ['€ 0.99'],
-       ['$ 1.00'],
-       ['1.02 $'],
-       ['$ 1.50'],
-       ['$ 3.00'],
-       ['$3.50'],
-       // Comma's sort after dots
-       // Not intentional but test to detect changes
-       ['€ 2,99']
-];
-
-tableTest(
-       'Currency parsing I',
-       ['currency'],
-       currencyUnsorted,
-       currencySorted,
-       function ( $table ) {
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-
-var ascendingNameLegacy = ascendingName.slice(0);
-ascendingNameLegacy[4] = ascendingNameLegacy[5];
-ascendingNameLegacy.pop();
-
-tableTest(
-       'Legacy compat with .sortbottom',
-       header,
-       planets,
-       ascendingNameLegacy,
-       function( $table ) {
-               $table.find( 'tr:last' ).addClass( 'sortbottom' );
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-
-QUnit.test( 'Test detection routine', function ( assert ) {
-       var $table;
-       $table = $(
-               '<table class="sortable">' +
-               '<caption>CAPTION</caption>' +
-               '<tr><th>THEAD</th></tr>' +
-               '<tr><td>1</td></tr>' +
-               '<tr class="sortbottom"><td>text</td></tr>' +
-               '</table>'
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
        );
-       $table.tablesorter();
 
-       assert.equal(
-               $table.data( 'tablesorter' ).config.parsers[0].id,
-               'number',
-               'Correctly detected column content skipping sortbottom'
+       var planetsRowspan = [ [ 'Earth', '6051.8' ], jupiter, [ 'Mars', '6051.8' ], mercury, saturn, venus ];
+       var planetsRowspanII = [ jupiter, mercury, saturn, venus, [ 'Venus', '6371.0' ], [ 'Venus', '3390.0' ] ];
+
+       tableTest(
+               'Basic planet table: same value for multiple rows via rowspan',
+               header,
+               planets,
+               planetsRowspan,
+               function ( $table ) {
+                       // Modify the table to have a multiple-row-spanning cell:
+                       // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
+                       $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
+                       // - Set rowspan for 2nd cell of 3rd row to 3.
+                       //   This covers the removed cell in the 4th and 5th row.
+                       $table.find( 'tr:eq(2) td:eq(1)' ).prop( 'rowspan', '3' );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
        );
-} );
-
-/** FIXME: the diff output is not very readeable. */
-QUnit.test( 'bug 32047 - caption must be before thead', function ( assert ) {
-       var $table;
-       $table = $(
-               '<table class="sortable">' +
-               '<caption>CAPTION</caption>' +
-               '<tr><th>THEAD</th></tr>' +
-               '<tr><td>A</td></tr>' +
-               '<tr><td>B</td></tr>' +
-               '<tr class="sortbottom"><td>TFOOT</td></tr>' +
-               '</table>'
-               );
-       $table.tablesorter();
-
-       assert.equal(
-               $table.children( ).get( 0 ).nodeName,
-               'CAPTION',
-               'First element after <thead> must be <caption> (bug 32047)'
+       tableTest(
+               'Basic planet table: same value for multiple rows via rowspan (sorting initially)',
+               header,
+               planets,
+               planetsRowspan,
+               function ( $table ) {
+                       // Modify the table to have a multiple-row-spanning cell:
+                       // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
+                       $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
+                       // - Set rowspan for 2nd cell of 3rd row to 3.
+                       //   This covers the removed cell in the 4th and 5th row.
+                       $table.find( 'tr:eq(2) td:eq(1)' ).prop( 'rowspan', '3' );
+
+                       $table.tablesorter( { sortList: [ { 0: 'asc' } ] } );
+               }
        );
-});
-
-QUnit.test( 'data-sort-value attribute, when available, should override sorting position', function ( assert ) {
-       var $table, data;
-
-       // Example 1: All cells except one cell without data-sort-value,
-       // which should be sorted at it's text content value.
-       $table = $(
-               '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
-                       '<tbody>' +
-                       '<tr><td>Cheetah</td></tr>' +
-                       '<tr><td data-sort-value="Apple">Bird</td></tr>' +
-                       '<tr><td data-sort-value="Bananna">Ferret</td></tr>' +
-                       '<tr><td data-sort-value="Drupe">Elephant</td></tr>' +
-                       '<tr><td data-sort-value="Cherry">Dolphin</td></tr>' +
-               '</tbody></table>'
+       tableTest(
+               'Basic planet table: Same value for multiple rows via rowspan II',
+               header,
+               planets,
+               planetsRowspanII,
+               function ( $table ) {
+                       // Modify the table to have a multiple-row-spanning cell:
+                       // - Remove 1st cell of 4th row, and, 1st cell or 5th row.
+                       $table.find( 'tr:eq(3) td:eq(0), tr:eq(4) td:eq(0)' ).remove();
+                       // - Set rowspan for 1st cell of 3rd row to 3.
+                       //   This covers the removed cell in the 4th and 5th row.
+                       $table.find( 'tr:eq(2) td:eq(0)' ).prop( 'rowspan', '3' );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
        );
-       $table.tablesorter().find( '.headerSort:eq(0)' ).click();
-
-       data = [];
-       $table.find( 'tbody > tr' ).each( function( i, tr ) {
-               $( tr ).find( 'td' ).each( function( i, td ) {
-                       data.push( {
-                               data: $( td ).data( 'sortValue' ),
-                               text: $( td ).text()
-                       } );
-               });
-       });
 
-       assert.deepEqual( data, [
-               {
-                       data: 'Apple',
-                       text: 'Bird'
-               }, {
-                       data: 'Bananna',
-                       text: 'Ferret'
-               }, {
-                       data: undefined,
-                       text: 'Cheetah'
-               }, {
-                       data: 'Cherry',
-                       text: 'Dolphin'
-               }, {
-                       data: 'Drupe',
-                       text: 'Elephant'
+       var complexMDYDates = [
+               // Some words with Umlauts
+               ['January, 19 2010'],
+               ['April 21 1991'],
+               ['04 22 1991'],
+               ['5.12.1990'],
+               ['December 12 \'10']
+       ];
+
+       var complexMDYSorted = [
+               ['5.12.1990'],
+               ['April 21 1991'],
+               ['04 22 1991'],
+               ['January, 19 2010'],
+               ['December 12 \'10']
+       ];
+
+       tableTest(
+               'Complex date parsing I',
+               ['date'],
+               complexMDYDates,
+               complexMDYSorted,
+               function ( $table ) {
+                       mw.config.set( 'wgDefaultDateFormat', 'mdy' );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
                }
-       ], 'Order matches expected order (based on data-sort-value attribute values)' );
-
-       // Example 2
-       $table = $(
-               '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
-                       '<tbody>' +
-                       '<tr><td>D</td></tr>' +
-                       '<tr><td data-sort-value="E">A</td></tr>' +
-                       '<tr><td>B</td></tr>' +
-                       '<tr><td>G</td></tr>' +
-                       '<tr><td data-sort-value="F">C</td></tr>' +
-               '</tbody></table>'
        );
-       $table.tablesorter().find( '.headerSort:eq(0)' ).click();
-
-       data = [];
-       $table.find( 'tbody > tr' ).each( function ( i, tr ) {
-               $( tr ).find( 'td' ).each( function ( i, td ) {
-                       data.push( {
-                               data: $( td ).data( 'sortValue' ),
-                               text: $( td ).text()
-                       } );
-               });
-       });
 
-       assert.deepEqual( data, [
-               {
-                       data: undefined,
-                       text: 'B'
-               }, {
-                       data: undefined,
-                       text: 'D'
-               }, {
-                       data: 'E',
-                       text: 'A'
-               }, {
-                       data: 'F',
-                       text: 'C'
-               }, {
-                       data: undefined,
-                       text: 'G'
+       var currencyUnsorted = [
+               ['1.02 $'],
+               ['$ 3.00'],
+               ['€ 2,99'],
+               ['$ 1.00'],
+               ['$3.50'],
+               ['$ 1.50'],
+               ['€ 0.99']
+       ];
+
+       var currencySorted = [
+               ['€ 0.99'],
+               ['$ 1.00'],
+               ['1.02 $'],
+               ['$ 1.50'],
+               ['$ 3.00'],
+               ['$3.50'],
+               // Comma's sort after dots
+               // Not intentional but test to detect changes
+               ['€ 2,99']
+       ];
+
+       tableTest(
+               'Currency parsing I',
+               ['currency'],
+               currencyUnsorted,
+               currencySorted,
+               function ( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
                }
-       ], 'Order matches expected order (based on data-sort-value attribute values)' );
-
-       // Example 3: Test that live changes are used from data-sort-value,
-       // even if they change after the tablesorter is constructed (bug 38152).
-       $table = $(
-               '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
-                       '<tbody>' +
-                       '<tr><td>D</td></tr>' +
-                       '<tr><td data-sort-value="1">A</td></tr>' +
-                       '<tr><td>B</td></tr>' +
-                       '<tr><td data-sort-value="2">G</td></tr>' +
-                       '<tr><td>C</td></tr>' +
-               '</tbody></table>'
        );
-       // initialize table sorter and sort once
-       $table
-               .tablesorter()
-               .find( '.headerSort:eq(0)' ).click();
-
-       // Change the sortValue data properties (bug 38152)
-       // - change data
-       $table.find( 'td:contains(A)' ).data( 'sortValue', 3 );
-       // - add data
-       $table.find( 'td:contains(B)' ).data( 'sortValue', 1 );
-       // - remove data, bring back attribute: 2
-       $table.find( 'td:contains(G)' ).removeData( 'sortValue' );
-
-       // Now sort again (twice, so it is back at Ascending)
-       $table.find( '.headerSort:eq(0)' ).click();
-       $table.find( '.headerSort:eq(0)' ).click();
-
-       data = [];
-       $table.find( 'tbody > tr' ).each( function( i, tr ) {
-               $( tr ).find( 'td' ).each( function( i, td ) {
-                       data.push( {
-                               data: $( td ).data( 'sortValue' ),
-                               text: $( td ).text()
-                       } );
-               });
-       });
 
-       assert.deepEqual( data, [
-               {
-                       data: 1,
-                       text: "B"
-               }, {
-                       data: 2,
-                       text: "G"
-               }, {
-                       data: 3,
-                       text: "A"
-               }, {
-                       data: undefined,
-                       text: "C"
-               }, {
-                       data: undefined,
-                       text: "D"
+       var ascendingNameLegacy = ascendingName.slice(0);
+       ascendingNameLegacy[4] = ascendingNameLegacy[5];
+       ascendingNameLegacy.pop();
+
+       tableTest(
+               'Legacy compat with .sortbottom',
+               header,
+               planets,
+               ascendingNameLegacy,
+               function( $table ) {
+                       $table.find( 'tr:last' ).addClass( 'sortbottom' );
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
                }
-       ], 'Order matches expected order, using the current sortValue in $.data()' );
-
-});
-
-var numbers = [
-       [ '12'    ],
-       [  '7'    ],
-       [ '13,000'],
-       [  '9'    ],
-       [ '14'    ],
-       [  '8.0'  ]
-];
-var numbersAsc = [
-       [  '7'    ],
-       [  '8.0'  ],
-       [  '9'    ],
-       [ '12'    ],
-       [ '14'    ],
-       [ '13,000']
-];
-
-tableTest( 'bug 8115: sort numbers with commas (ascending)',
-       ['Numbers'], numbers, numbersAsc,
-       function( $table ) {
+       );
+
+       QUnit.test( 'Test detection routine', function ( assert ) {
+               var $table;
+               $table = $(
+                       '<table class="sortable">' +
+                       '<caption>CAPTION</caption>' +
+                       '<tr><th>THEAD</th></tr>' +
+                       '<tr><td>1</td></tr>' +
+                       '<tr class="sortbottom"><td>text</td></tr>' +
+                       '</table>'
+               );
                $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
 
-tableTest( 'bug 8115: sort numbers with commas (descending)',
-       ['Numbers'], numbers, reversed(numbersAsc),
-       function( $table ) {
+               assert.equal(
+                       $table.data( 'tablesorter' ).config.parsers[0].id,
+                       'number',
+                       'Correctly detected column content skipping sortbottom'
+               );
+       } );
+
+       /** FIXME: the diff output is not very readeable. */
+       QUnit.test( 'bug 32047 - caption must be before thead', function ( assert ) {
+               var $table;
+               $table = $(
+                       '<table class="sortable">' +
+                       '<caption>CAPTION</caption>' +
+                       '<tr><th>THEAD</th></tr>' +
+                       '<tr><td>A</td></tr>' +
+                       '<tr><td>B</td></tr>' +
+                       '<tr class="sortbottom"><td>TFOOT</td></tr>' +
+                       '</table>'
+                       );
                $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click().click();
-       }
-);
-// TODO add numbers sorting tests for bug 8115 with a different language
-
-QUnit.test( 'bug 32888 - Tables inside a tableheader cell', 2, function ( assert ) {
-       var $table;
-       $table = $(
-               '<table class="sortable" id="mw-bug-32888">' +
-               '<tr><th>header<table id="mw-bug-32888-2">'+
-                       '<tr><th>1</th><th>2</th></tr>' +
-               '</table></th></tr>' +
-               '<tr><td>A</td></tr>' +
-               '<tr><td>B</td></tr>' +
-               '</table>'
+
+               assert.equal(
+                       $table.children( ).get( 0 ).nodeName,
+                       'CAPTION',
+                       'First element after <thead> must be <caption> (bug 32047)'
                );
-       $table.tablesorter();
+       });
 
-       assert.equal(
-               $table.find('> thead:eq(0) > tr > th.headerSort').length,
-               1,
-               'Child tables inside a headercell should not interfere with sortable headers (bug 32888)'
-       );
-       assert.equal(
-               $( '#mw-bug-32888-2' ).find('th.headerSort').length,
-               0,
-               'The headers of child tables inside a headercell should not be sortable themselves (bug 32888)'
-       );
-});
+       QUnit.test( 'data-sort-value attribute, when available, should override sorting position', function ( assert ) {
+               var $table, data;
+
+               // Example 1: All cells except one cell without data-sort-value,
+               // which should be sorted at it's text content value.
+               $table = $(
+                       '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
+                               '<tbody>' +
+                               '<tr><td>Cheetah</td></tr>' +
+                               '<tr><td data-sort-value="Apple">Bird</td></tr>' +
+                               '<tr><td data-sort-value="Bananna">Ferret</td></tr>' +
+                               '<tr><td data-sort-value="Drupe">Elephant</td></tr>' +
+                               '<tr><td data-sort-value="Cherry">Dolphin</td></tr>' +
+                       '</tbody></table>'
+               );
+               $table.tablesorter().find( '.headerSort:eq(0)' ).click();
+
+               data = [];
+               $table.find( 'tbody > tr' ).each( function( i, tr ) {
+                       $( tr ).find( 'td' ).each( function( i, td ) {
+                               data.push( {
+                                       data: $( td ).data( 'sortValue' ),
+                                       text: $( td ).text()
+                               } );
+                       });
+               });
 
+               assert.deepEqual( data, [
+                       {
+                               data: 'Apple',
+                               text: 'Bird'
+                       }, {
+                               data: 'Bananna',
+                               text: 'Ferret'
+                       }, {
+                               data: undefined,
+                               text: 'Cheetah'
+                       }, {
+                               data: 'Cherry',
+                               text: 'Dolphin'
+                       }, {
+                               data: 'Drupe',
+                               text: 'Elephant'
+                       }
+               ], 'Order matches expected order (based on data-sort-value attribute values)' );
+
+               // Example 2
+               $table = $(
+                       '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
+                               '<tbody>' +
+                               '<tr><td>D</td></tr>' +
+                               '<tr><td data-sort-value="E">A</td></tr>' +
+                               '<tr><td>B</td></tr>' +
+                               '<tr><td>G</td></tr>' +
+                               '<tr><td data-sort-value="F">C</td></tr>' +
+                       '</tbody></table>'
+               );
+               $table.tablesorter().find( '.headerSort:eq(0)' ).click();
+
+               data = [];
+               $table.find( 'tbody > tr' ).each( function ( i, tr ) {
+                       $( tr ).find( 'td' ).each( function ( i, td ) {
+                               data.push( {
+                                       data: $( td ).data( 'sortValue' ),
+                                       text: $( td ).text()
+                               } );
+                       });
+               });
 
-var correctDateSorting1 = [
-       ['01 January 2010'],
-       ['05 February 2010'],
-       ['16 January 2010']
-];
+               assert.deepEqual( data, [
+                       {
+                               data: undefined,
+                               text: 'B'
+                       }, {
+                               data: undefined,
+                               text: 'D'
+                       }, {
+                               data: 'E',
+                               text: 'A'
+                       }, {
+                               data: 'F',
+                               text: 'C'
+                       }, {
+                               data: undefined,
+                               text: 'G'
+                       }
+               ], 'Order matches expected order (based on data-sort-value attribute values)' );
+
+               // Example 3: Test that live changes are used from data-sort-value,
+               // even if they change after the tablesorter is constructed (bug 38152).
+               $table = $(
+                       '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
+                               '<tbody>' +
+                               '<tr><td>D</td></tr>' +
+                               '<tr><td data-sort-value="1">A</td></tr>' +
+                               '<tr><td>B</td></tr>' +
+                               '<tr><td data-sort-value="2">G</td></tr>' +
+                               '<tr><td>C</td></tr>' +
+                       '</tbody></table>'
+               );
+               // initialize table sorter and sort once
+               $table
+                       .tablesorter()
+                       .find( '.headerSort:eq(0)' ).click();
+
+               // Change the sortValue data properties (bug 38152)
+               // - change data
+               $table.find( 'td:contains(A)' ).data( 'sortValue', 3 );
+               // - add data
+               $table.find( 'td:contains(B)' ).data( 'sortValue', 1 );
+               // - remove data, bring back attribute: 2
+               $table.find( 'td:contains(G)' ).removeData( 'sortValue' );
+
+               // Now sort again (twice, so it is back at Ascending)
+               $table.find( '.headerSort:eq(0)' ).click();
+               $table.find( '.headerSort:eq(0)' ).click();
 
-var correctDateSortingSorted1 = [
-       ['01 January 2010'],
-       ['16 January 2010'],
-       ['05 February 2010']
-];
+               data = [];
+               $table.find( 'tbody > tr' ).each( function( i, tr ) {
+                       $( tr ).find( 'td' ).each( function( i, td ) {
+                               data.push( {
+                                       data: $( td ).data( 'sortValue' ),
+                                       text: $( td ).text()
+                               } );
+                       });
+               });
 
-tableTest(
-       'Correct date sorting I',
-       ['date'],
-       correctDateSorting1,
-       correctDateSortingSorted1,
-       function ( $table ) {
-               mw.config.set( 'wgDefaultDateFormat', 'mdy' );
+               assert.deepEqual( data, [
+                       {
+                               data: 1,
+                               text: 'B'
+                       }, {
+                               data: 2,
+                               text: 'G'
+                       }, {
+                               data: 3,
+                               text: 'A'
+                       }, {
+                               data: undefined,
+                               text: 'C'
+                       }, {
+                               data: undefined,
+                               text: 'D'
+                       }
+               ], 'Order matches expected order, using the current sortValue in $.data()' );
 
-               $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
-
-var correctDateSorting2 = [
-       ['January 01 2010'],
-       ['February 05 2010'],
-       ['January 16 2010']
-];
-
-var correctDateSortingSorted2 = [
-       ['January 01 2010'],
-       ['January 16 2010'],
-       ['February 05 2010']
-];
-
-tableTest(
-       'Correct date sorting II',
-       ['date'],
-       correctDateSorting2,
-       correctDateSortingSorted2,
-       function ( $table ) {
-               mw.config.set( 'wgDefaultDateFormat', 'dmy' );
+       });
 
+       var numbers = [
+               [ '12'    ],
+               [  '7'    ],
+               [ '13,000'],
+               [  '9'    ],
+               [ '14'    ],
+               [  '8.0'  ]
+       ];
+       var numbersAsc = [
+               [  '7'    ],
+               [  '8.0'  ],
+               [  '9'    ],
+               [ '12'    ],
+               [ '14'    ],
+               [ '13,000']
+       ];
+
+       tableTest( 'bug 8115: sort numbers with commas (ascending)',
+               ['Numbers'], numbers, numbersAsc,
+               function( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
+       );
+
+       tableTest( 'bug 8115: sort numbers with commas (descending)',
+               ['Numbers'], numbers, reversed(numbersAsc),
+               function( $table ) {
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click().click();
+               }
+       );
+       // TODO add numbers sorting tests for bug 8115 with a different language
+
+       QUnit.test( 'bug 32888 - Tables inside a tableheader cell', 2, function ( assert ) {
+               var $table;
+               $table = $(
+                       '<table class="sortable" id="mw-bug-32888">' +
+                       '<tr><th>header<table id="mw-bug-32888-2">'+
+                               '<tr><th>1</th><th>2</th></tr>' +
+                       '</table></th></tr>' +
+                       '<tr><td>A</td></tr>' +
+                       '<tr><td>B</td></tr>' +
+                       '</table>'
+                       );
                $table.tablesorter();
-               $table.find( '.headerSort:eq(0)' ).click();
-       }
-);
+
+               assert.equal(
+                       $table.find('> thead:eq(0) > tr > th.headerSort').length,
+                       1,
+                       'Child tables inside a headercell should not interfere with sortable headers (bug 32888)'
+               );
+               assert.equal(
+                       $( '#mw-bug-32888-2' ).find('th.headerSort').length,
+                       0,
+                       'The headers of child tables inside a headercell should not be sortable themselves (bug 32888)'
+               );
+       });
+
+
+       var correctDateSorting1 = [
+               ['01 January 2010'],
+               ['05 February 2010'],
+               ['16 January 2010']
+       ];
+
+       var correctDateSortingSorted1 = [
+               ['01 January 2010'],
+               ['16 January 2010'],
+               ['05 February 2010']
+       ];
+
+       tableTest(
+               'Correct date sorting I',
+               ['date'],
+               correctDateSorting1,
+               correctDateSortingSorted1,
+               function ( $table ) {
+                       mw.config.set( 'wgDefaultDateFormat', 'mdy' );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
+       );
+
+       var correctDateSorting2 = [
+               ['January 01 2010'],
+               ['February 05 2010'],
+               ['January 16 2010']
+       ];
+
+       var correctDateSortingSorted2 = [
+               ['January 01 2010'],
+               ['January 16 2010'],
+               ['February 05 2010']
+       ];
+
+       tableTest(
+               'Correct date sorting II',
+               ['date'],
+               correctDateSorting2,
+               correctDateSortingSorted2,
+               function ( $table ) {
+                       mw.config.set( 'wgDefaultDateFormat', 'dmy' );
+
+                       $table.tablesorter();
+                       $table.find( '.headerSort:eq(0)' ).click();
+               }
+       );
 
 }( jQuery, mediaWiki ) );
index f0a210f..1795b95 100644 (file)
-QUnit.module( 'jquery.textSelection', QUnit.newMwEnvironment() );
-
-/**
- * Test factory for $.fn.textSelection( 'encapsulateText' )
- *
- * @param options {object} associative array containing:
- *   description {string}
- *   input {string}
- *   output {string}
- *   start {int} starting char for selection
- *   end {int} ending char for selection
- *   params {object} add'l parameters for $().textSelection( 'encapsulateText' )
- */
-function encapsulateTest( options ) {
-       var opt = $.extend({
-               description: '',
-               before: {},
-               after: {},
-               replace: {}
-       }, options);
-
-       opt.before = $.extend({
-               text: '',
-               start: 0,
-               end: 0
-       }, opt.before);
-       opt.after = $.extend({
-               text: '',
-               selected: null
-       }, opt.after);
-
-       QUnit.test( opt.description, function ( assert ) {
-               var tests = 1;
-               if ( opt.after.selected !== null ) {
-                       tests++;
-               }
-               QUnit.expect( tests );
-
-               var $textarea = $( '<textarea>' );
-
-               $( '#qunit-fixture' ).append( $textarea );
-
-               //$textarea.textSelection( 'setContents', opt.before.text); // this method is actually missing atm...
-               $textarea.val( opt.before.text ); // won't work with the WikiEditor iframe?
-
-               var     start = opt.before.start,
-                       end = opt.before.end;
-               if ( window.opera ) {
-                       // Compensate for Opera's craziness converting "\n" to "\r\n" and counting that as two chars
-                       var     newLinesBefore = opt.before.text.substring( 0, start ).split( "\n" ).length - 1,
-                               newLinesInside = opt.before.text.substring( start, end ).split( "\n" ).length - 1;
-                       start += newLinesBefore;
-                       end += newLinesBefore + newLinesInside;
-               }
-
-               var options = $.extend( {}, opt.replace ); // Clone opt.replace
-               options.selectionStart = start;
-               options.selectionEnd = end;
-               $textarea.textSelection( 'encapsulateSelection', options );
-
-               var text = $textarea.textSelection( 'getContents' ).replace( /\r\n/g, "\n" );
-
-               assert.equal( text, opt.after.text, 'Checking full text after encapsulation' );
-
-               if (opt.after.selected !== null) {
-                       var selected = $textarea.textSelection( 'getSelection' );
-                       assert.equal( selected, opt.after.selected, 'Checking selected text after encapsulation.' );
-               }
-
-       } );
-}
-
-var sig = {
-       'pre': "--~~~~"
-}, bold = {
-       pre: "'''",
-       peri: 'Bold text',
-       post: "'''"
-}, h2 = {
-       'pre': '== ',
-       'peri': 'Heading 2',
-       'post': ' ==',
-       'regex': /^(\s*)(={1,6})(.*?)\2(\s*)$/,
-       'regexReplace': "$1==$3==$4",
-       'ownline': true
-}, ulist = {
-       'pre': "* ",
-       'peri': 'Bulleted list item',
-       'post': "",
-       'ownline': true,
-       'splitlines': true
-};
-
-encapsulateTest({
-       description: "Adding sig to end of text",
-       before: {
-               text: "Wikilove dude! ",
-               start: 15,
-               end: 15
-       },
-       after: {
-               text: "Wikilove dude! --~~~~",
-               selected: ""
-       },
-       replace: sig
-});
-
-encapsulateTest({
-       description: "Adding bold to empty",
-       before: {
-               text: "",
-               start: 0,
-               end: 0
-       },
-       after: {
-               text: "'''Bold text'''",
-               selected: "Bold text" // selected because it's the default
-       },
-       replace: bold
-});
-
-encapsulateTest({
-       description: "Adding bold to existing text",
-       before: {
-               text: "Now is the time for all good men to come to the aid of their country",
-               start: 20,
-               end: 32
-       },
-       after: {
-               text: "Now is the time for '''all good men''' to come to the aid of their country",
-               selected: "" // empty because it's not the default'
-       },
-       replace: bold
-});
-
-encapsulateTest({
-       description: "ownline option: adding new h2",
-       before: {
-               text:"Before\nAfter",
-               start: 7,
-               end: 7
-       },
-       after: {
-               text: "Before\n== Heading 2 ==\nAfter",
-               selected: "Heading 2"
-       },
-       replace: h2
-});
-
-encapsulateTest({
-       description: "ownline option: turn a whole line into new h2",
-       before: {
-               text:"Before\nMy heading\nAfter",
-               start: 7,
-               end: 17
-       },
-       after: {
-               text: "Before\n== My heading ==\nAfter",
-               selected: ""
-       },
-       replace: h2
-});
-
-
-encapsulateTest({
-       description: "ownline option: turn a partial line into new h2",
-       before: {
-               text:"BeforeMy headingAfter",
-               start: 6,
-               end: 16
-       },
-       after: {
-               text: "Before\n== My heading ==\nAfter",
-               selected: ""
-       },
-       replace: h2
-});
-
-
-encapsulateTest({
-       description: "splitlines option: no selection, insert new list item",
-       before: {
-               text: "Before\nAfter",
-               start: 7,
-               end: 7
-       },
-       after: {
-               text: "Before\n* Bulleted list item\nAfter"
-       },
-       replace: ulist
-});
-
-encapsulateTest({
-       description: "splitlines option: single partial line selection, insert new list item",
-       before: {
-               text: "BeforeMy List ItemAfter",
-               start: 6,
-               end: 18
-       },
-       after: {
-               text: "Before\n* My List Item\nAfter"
-       },
-       replace: ulist
-});
-
-encapsulateTest({
-       description: "splitlines option: multiple lines",
-       before: {
-               text: "Before\nFirst\nSecond\nThird\nAfter",
-               start: 7,
-               end: 25
-       },
-       after: {
-               text: "Before\n* First\n* Second\n* Third\nAfter"
-       },
-       replace: ulist
-});
-
-
-function caretTest( options ) {
-       QUnit.test( options.description, 2, function ( assert ) {
-               var $textarea = $( '<textarea>' ).text( options.text );
-
-               $( '#qunit-fixture' ).append( $textarea );
-
-               if ( options.mode === 'set' ) {
-                       $textarea.textSelection('setSelection', {
-                               start: options.start,
-                               end: options.end
-                       });
-               }
-
-               function among( actual, expected, message ) {
-                       if ( $.isArray( expected ) ) {
-                               assert.ok( $.inArray( actual, expected ) !== -1 , message + ' (got ' + actual + '; expected one of ' + expected.join(', ') + ')' );
-                       } else {
-                               assert.equal( actual, expected, message );
+( function ( $ ) {
+
+       QUnit.module( 'jquery.textSelection', QUnit.newMwEnvironment() );
+
+       /**
+        * Test factory for $.fn.textSelection( 'encapsulateText' )
+        *
+        * @param options {object} associative array containing:
+        *   description {string}
+        *   input {string}
+        *   output {string}
+        *   start {int} starting char for selection
+        *   end {int} ending char for selection
+        *   params {object} add'l parameters for $().textSelection( 'encapsulateText' )
+        */
+       function encapsulateTest( options ) {
+               var opt = $.extend({
+                       description: '',
+                       before: {},
+                       after: {},
+                       replace: {}
+               }, options);
+
+               opt.before = $.extend({
+                       text: '',
+                       start: 0,
+                       end: 0
+               }, opt.before);
+               opt.after = $.extend({
+                       text: '',
+                       selected: null
+               }, opt.after);
+
+               QUnit.test( opt.description, function ( assert ) {
+                       /*jshint onevar: false */
+                       var tests = 1;
+                       if ( opt.after.selected !== null ) {
+                               tests++;
+                       }
+                       QUnit.expect( tests );
+
+                       var $textarea = $( '<textarea>' );
+
+                       $( '#qunit-fixture' ).append( $textarea );
+
+                       //$textarea.textSelection( 'setContents', opt.before.text); // this method is actually missing atm...
+                       $textarea.val( opt.before.text ); // won't work with the WikiEditor iframe?
+
+                       var     start = opt.before.start,
+                               end = opt.before.end;
+                       if ( window.opera ) {
+                               // Compensate for Opera's craziness converting \n to \r\n and counting that as two chars
+                               var     newLinesBefore = opt.before.text.substring( 0, start ).split( '\n' ).length - 1,
+                                       newLinesInside = opt.before.text.substring( start, end ).split( '\n' ).length - 1;
+                               start += newLinesBefore;
+                               end += newLinesBefore + newLinesInside;
+                       }
+
+                       var options = $.extend( {}, opt.replace ); // Clone opt.replace
+                       options.selectionStart = start;
+                       options.selectionEnd = end;
+                       $textarea.textSelection( 'encapsulateSelection', options );
+
+                       var text = $textarea.textSelection( 'getContents' ).replace( /\r\n/g, '\n' );
+
+                       assert.equal( text, opt.after.text, 'Checking full text after encapsulation' );
+
+                       if ( opt.after.selected !== null ) {
+                               var selected = $textarea.textSelection( 'getSelection' );
+                               assert.equal( selected, opt.after.selected, 'Checking selected text after encapsulation.' );
+                       }
+
+               } );
+       }
+
+       var caretSample,
+               sig = {
+                       pre: '--~~~~'
+               },
+               bold = {
+                       pre: '\'\'\'',
+                       peri: 'Bold text',
+                       post: '\'\'\''
+               },
+               h2 = {
+                       pre: '== ',
+                       peri: 'Heading 2',
+                       post: ' ==',
+                       regex: /^(\s*)(={1,6})(.*?)\2(\s*)$/,
+                       regexReplace: '$1==$3==$4',
+                       ownline: true
+               },
+               ulist = {
+                       pre: '* ',
+                       peri: 'Bulleted list item',
+                       post: '',
+                       ownline: true,
+                       splitlines: true
+               };
+
+       encapsulateTest({
+               description: 'Adding sig to end of text',
+               before: {
+                       text: 'Wikilove dude! ',
+                       start: 15,
+                       end: 15
+               },
+               after: {
+                       text: 'Wikilove dude! --~~~~',
+                       selected: ''
+               },
+               replace: sig
+       });
+
+       encapsulateTest({
+               description: 'Adding bold to empty',
+               before: {
+                       text: '',
+                       start: 0,
+                       end: 0
+               },
+               after: {
+                       text: '\'\'\'Bold text\'\'\'',
+                       selected: 'Bold text' // selected because it's the default
+               },
+               replace: bold
+       });
+
+       encapsulateTest({
+               description: 'Adding bold to existing text',
+               before: {
+                       text: 'Now is the time for all good men to come to the aid of their country',
+                       start: 20,
+                       end: 32
+               },
+               after: {
+                       text: 'Now is the time for \'\'\'all good men\'\'\' to come to the aid of their country',
+                       selected: '' // empty because it's not the default'
+               },
+               replace: bold
+       });
+
+       encapsulateTest({
+               description: 'ownline option: adding new h2',
+               before: {
+                       text:'Before\nAfter',
+                       start: 7,
+                       end: 7
+               },
+               after: {
+                       text: 'Before\n== Heading 2 ==\nAfter',
+                       selected: 'Heading 2'
+               },
+               replace: h2
+       });
+
+       encapsulateTest({
+               description: 'ownline option: turn a whole line into new h2',
+               before: {
+                       text:'Before\nMy heading\nAfter',
+                       start: 7,
+                       end: 17
+               },
+               after: {
+                       text: 'Before\n== My heading ==\nAfter',
+                       selected: ''
+               },
+               replace: h2
+       });
+
+
+       encapsulateTest({
+               description: 'ownline option: turn a partial line into new h2',
+               before: {
+                       text:'BeforeMy headingAfter',
+                       start: 6,
+                       end: 16
+               },
+               after: {
+                       text: 'Before\n== My heading ==\nAfter',
+                       selected: ''
+               },
+               replace: h2
+       });
+
+
+       encapsulateTest({
+               description: 'splitlines option: no selection, insert new list item',
+               before: {
+                       text: 'Before\nAfter',
+                       start: 7,
+                       end: 7
+               },
+               after: {
+                       text: 'Before\n* Bulleted list item\nAfter'
+               },
+               replace: ulist
+       });
+
+       encapsulateTest({
+               description: 'splitlines option: single partial line selection, insert new list item',
+               before: {
+                       text: 'BeforeMy List ItemAfter',
+                       start: 6,
+                       end: 18
+               },
+               after: {
+                       text: 'Before\n* My List Item\nAfter'
+               },
+               replace: ulist
+       });
+
+       encapsulateTest({
+               description: 'splitlines option: multiple lines',
+               before: {
+                       text: 'Before\nFirst\nSecond\nThird\nAfter',
+                       start: 7,
+                       end: 25
+               },
+               after: {
+                       text: 'Before\n* First\n* Second\n* Third\nAfter'
+               },
+               replace: ulist
+       });
+
+
+       function caretTest( options ) {
+               QUnit.test( options.description, 2, function ( assert ) {
+                       var pos, $textarea = $( '<textarea>' ).text( options.text );
+
+                       $( '#qunit-fixture' ).append( $textarea );
+
+                       if ( options.mode === 'set' ) {
+                               $textarea.textSelection('setSelection', {
+                                       start: options.start,
+                                       end: options.end
+                               });
+                       }
+
+                       function among( actual, expected, message ) {
+                               if ( $.isArray( expected ) ) {
+                                       assert.ok( $.inArray( actual, expected ) !== -1 , message + ' (got ' + actual + '; expected one of ' + expected.join(', ') + ')' );
+                               } else {
+                                       assert.equal( actual, expected, message );
+                               }
                        }
-               }
 
-               var pos = $textarea.textSelection('getCaretPosition', {startAndEnd: true});
-               among(pos[0], options.start, 'Caret start should be where we set it.');
-               among(pos[1], options.end, 'Caret end should be where we set it.');
+                       pos = $textarea.textSelection( 'getCaretPosition', { startAndEnd: true });
+                       among(pos[0], options.start, 'Caret start should be where we set it.');
+                       among(pos[1], options.end, 'Caret end should be where we set it.');
+               });
+       }
+
+       caretSample = 'Some big text that we like to work with. Nothing fancy... you know what I mean?';
+
+       /*
+       // @broken: Disabled per bug 34820
+       caretTest({
+               description: 'getCaretPosition with original/empty selection - bug 31847 with IE 6/7/8',
+               text: caretSample,
+               start: [0, caretSample.length], // Opera and Firefox (prior to FF 6.0) default caret to the end of the box (caretSample.length)
+               end: [0, caretSample.length], // Other browsers default it to the beginning (0), so check both.
+               mode: 'get'
+       });
+       */
+
+       caretTest({
+               description: 'set/getCaretPosition with forced empty selection',
+               text: caretSample,
+               start: 7,
+               end: 7,
+               mode: 'set'
        });
-}
-
-var caretSample = "Some big text that we like to work with. Nothing fancy... you know what I mean?";
-
-/*
- // @broken: Disabled per bug 34820
-caretTest({
-       description: 'getCaretPosition with original/empty selection - bug 31847 with IE 6/7/8',
-       text: caretSample,
-       start: [0, caretSample.length], // Opera and Firefox (prior to FF 6.0) default caret to the end of the box (caretSample.length)
-       end: [0, caretSample.length], // Other browsers default it to the beginning (0), so check both.
-       mode: 'get'
-});
-*/
-
-caretTest({
-       description: 'set/getCaretPosition with forced empty selection',
-       text: caretSample,
-       start: 7,
-       end: 7,
-       mode: 'set'
-});
-
-caretTest({
-       description: 'set/getCaretPosition with small selection',
-       text: caretSample,
-       start: 6,
-       end: 11,
-       mode: 'set'
-});
 
+       caretTest({
+               description: 'set/getCaretPosition with small selection',
+               text: caretSample,
+               start: 6,
+               end: 11,
+               mode: 'set'
+       });
+}( jQuery ) );
index 3d3f630..ec7179e 100644 (file)
@@ -1,26 +1,28 @@
-QUnit.module( 'mediawiki.api.parse', QUnit.newMwEnvironment() );
+( function ( mw, $ ) {
+       QUnit.module( 'mediawiki.api.parse', QUnit.newMwEnvironment() );
 
-QUnit.asyncTest( 'Hello world', function ( assert ) {
-       var api;
-       QUnit.expect( 6 );
+       QUnit.asyncTest( 'Hello world', function ( assert ) {
+               var api;
+               QUnit.expect( 6 );
 
-       api = new mw.Api();
+               api = new mw.Api();
 
-       api.parse( "'''Hello world'''" )
-               .done( function ( html ) {
-                       // Parse into a document fragment instead of comparing HTML, due to
-                       // presence of Tidy influencing whitespace.
-                       // Html also contains "NewPP report" comment.
-                       var $res = $( '<div>' ).html( html ).children(),
-                               res = $res.get( 0 );
-                       assert.equal( $res.length, 1, 'Response contains 1 element' );
-                       assert.equal( res.nodeName.toLowerCase(), 'p', 'Response is a paragraph' );
-                       assert.equal( $res.children().length, 1, 'Response has 1 child element' );
-                       assert.equal( $res.children().get( 0 ).nodeName.toLowerCase(), 'b', 'Child element is a bold tag' );
-                       // Trim since Tidy may or may not mess with the spacing here
-                       assert.equal( $.trim( $res.text() ), 'Hello world', 'Response contains given text' );
-                       assert.equal( $res.find( 'b' ).text(), 'Hello world', 'Bold tag wraps the entire, same, text' );
+               api.parse( '\'\'\'Hello world\'\'\'' )
+                       .done( function ( html ) {
+                               // Parse into a document fragment instead of comparing HTML, due to
+                               // presence of Tidy influencing whitespace.
+                               // Html also contains "NewPP report" comment.
+                               var $res = $( '<div>' ).html( html ).children(),
+                                       res = $res.get( 0 );
+                               assert.equal( $res.length, 1, 'Response contains 1 element' );
+                               assert.equal( res.nodeName.toLowerCase(), 'p', 'Response is a paragraph' );
+                               assert.equal( $res.children().length, 1, 'Response has 1 child element' );
+                               assert.equal( $res.children().get( 0 ).nodeName.toLowerCase(), 'b', 'Child element is a bold tag' );
+                               // Trim since Tidy may or may not mess with the spacing here
+                               assert.equal( $.trim( $res.text() ), 'Hello world', 'Response contains given text' );
+                               assert.equal( $res.find( 'b' ).text(), 'Hello world', 'Bold tag wraps the entire, same, text' );
 
-                       QUnit.start();
-               });
-});
+                               QUnit.start();
+                       });
+       });
+}( mediaWiki, jQuery ) );
index 79bd730..50bbfd7 100644 (file)
@@ -1,59 +1,61 @@
-QUnit.module( 'mediawiki.api', QUnit.newMwEnvironment() );
+( function ( mw ) {
+       QUnit.module( 'mediawiki.api', QUnit.newMwEnvironment() );
+
+       QUnit.asyncTest( 'Basic functionality', function ( assert ) {
+               var api, d1, d2, d3;
+               QUnit.expect( 3 );
+
+               api = new mw.Api();
+
+               d1 = api.get( {} )
+                       .done( function ( data ) {
+                               assert.deepEqual( data, [], 'If request succeeds without errors, resolve deferred' );
+                       });
+
+               d2 = api.get({
+                               action: 'doesntexist'
+                       })
+                       .fail( function ( errorCode ) {
+                               assert.equal( errorCode, 'unknown_action', 'API error (e.g. "unknown_action") should reject the deferred' );
+                       });
+
+               d3 = api.post( {} )
+                       .done( function ( data ) {
+                               assert.deepEqual( data, [], 'Simple POST request' );
+                       });
+
+               // After all are completed, continue the test suite.
+               QUnit.whenPromisesComplete( d1, d2, d3 ).always( function () {
+                       QUnit.start();
+               });
+       });
 
-QUnit.asyncTest( 'Basic functionality', function ( assert ) {
-       var api, d1, d2, d3;
-       QUnit.expect( 3 );
+       QUnit.asyncTest( 'Deprecated callback methods', function ( assert ) {
+               var api, d1, d2, d3;
+               QUnit.expect( 3 );
 
-       api = new mw.Api();
+               api = new mw.Api();
 
-       d1 = api.get( {} )
-               .done( function ( data ) {
-                       assert.deepEqual( data, [], 'If request succeeds without errors, resolve deferred' );
+               d1 = api.get( {}, function () {
+                       assert.ok( true, 'Function argument treated as success callback.' );
                });
 
-       d2 = api.get({
-                       action: 'doesntexist'
-               })
-               .fail( function ( errorCode, details ) {
-                       assert.equal( errorCode, 'unknown_action', 'API error (e.g. "unknown_action") should reject the deferred' );
+               d2 = api.get( {}, {
+                       ok: function () {
+                               assert.ok( true, '"ok" property treated as success callback.' );
+                       }
                });
 
-       d3 = api.post( {} )
-               .done( function ( data ) {
-                       assert.deepEqual( data, [], 'Simple POST request' );
+               d3 = api.get({
+                               action: 'doesntexist'
+                       }, {
+                       err: function () {
+                               assert.ok( true, '"err" property treated as error callback.' );
+                       }
                });
 
-       // After all are completed, continue the test suite.
-       QUnit.whenPromisesComplete( d1, d2, d3 ).always( function () {
-               QUnit.start();
-       });
-});
-
-QUnit.asyncTest( 'Deprecated callback methods', function ( assert ) {
-       var api, d1, d2, d3;
-       QUnit.expect( 3 );
-
-       api = new mw.Api();
-
-       d1 = api.get( {}, function () {
-               assert.ok( true, 'Function argument treated as success callback.' );
-       });
-
-       d2 = api.get( {}, {
-               ok: function ( data ) {
-                       assert.ok( true, '"ok" property treated as success callback.' );
-               }
-       });
-
-       d3 = api.get({
-                       action: 'doesntexist'
-               }, {
-               err: function ( data ) {
-                       assert.ok( true, '"err" property treated as error callback.' );
-               }
-       });
-
-       QUnit.whenPromisesComplete( d1, d2, d3 ).always( function () {
-               QUnit.start();
+               QUnit.whenPromisesComplete( d1, d2, d3 ).always( function () {
+                       QUnit.start();
+               });
        });
-});
+}( mediaWiki ) );
index 7fe7baf..d7b0cb7 100644 (file)
@@ -1,62 +1,65 @@
-QUnit.module( 'mediawiki.special.recentchanges', QUnit.newMwEnvironment() );
-
-// TODO: verify checkboxes == [ 'nsassociated', 'nsinvert' ]
-
-QUnit.test( '"all" namespace disable checkboxes', function ( assert ) {
-
-       // from Special:Recentchanges
-       var select =
-       '<select id="namespace" name="namespace" class="namespaceselector">'
-       + '<option value="" selected="selected">all</option>'
-       + '<option value="0">(Main)</option>'
-       + '<option value="1">Talk</option>'
-       + '<option value="2">User</option>'
-       + '<option value="3">User talk</option>'
-       + '<option value="4">ProjectName</option>'
-       + '<option value="5">ProjectName talk</option>'
-       + '</select>'
-       + '<input name="invert" type="checkbox" value="1" id="nsinvert" title="no title" />'
-       + '<label for="nsinvert" title="no title">Invert selection</label>'
-       + '<input name="associated" type="checkbox" value="1" id="nsassociated" title="no title" />'
-       + '<label for="nsassociated" title="no title">Associated namespace</label>'
-       + '<input type="submit" value="Go" />'
-       + '<input type="hidden" value="Special:RecentChanges" name="title" />'
-       ;
-
-       var $env = $( '<div>' ).html( select ).appendTo( 'body' );
-
-       // TODO abstract the double strictEquals
-
-       // At first checkboxes are enabled
-       assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), false );
-       assert.strictEqual( $( '#nsassociated' ).prop( 'disabled' ), false );
-
-       // Initiate the recentchanges module
-       mw.special.recentchanges.init();
-
-       // By default
-       assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), true );
-       assert.strictEqual( $( '#nsassociated' ).prop( 'disabled' ), true );
-
-       // select second option...
-       var $options = $( '#namespace' ).find( 'option' );
-       $options.eq(0).removeProp( 'selected' );
-       $options.eq(1).prop( 'selected', true );
-       $( '#namespace' ).change();
-
-       // ... and checkboxes should be enabled again
-       assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), false );
-       assert.strictEqual( $( '#nsassociated' ).prop( 'disabled' ), false );
-
-       // select first option ( 'all' namespace)...
-       $options.eq(1).removeProp( 'selected' );
-       $options.eq(0).prop( 'selected', true );
-       $( '#namespace' ).change();
-
-       // ... and checkboxes should now be disabled
-       assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), true );
-       assert.strictEqual( $( '#nsassociated' ).prop( 'disabled' ), true );
-
-       // DOM cleanup
-       $env.remove();
-});
+( function ( mw, $ ) {
+       QUnit.module( 'mediawiki.special.recentchanges', QUnit.newMwEnvironment() );
+
+       // TODO: verify checkboxes == [ 'nsassociated', 'nsinvert' ]
+
+       QUnit.test( '"all" namespace disable checkboxes', function ( assert ) {
+               var selectHtml, $env, $options;
+
+               // from Special:Recentchanges
+               selectHtml =
+               '<select id="namespace" name="namespace" class="namespaceselector">'
+               + '<option value="" selected="selected">all</option>'
+               + '<option value="0">(Main)</option>'
+               + '<option value="1">Talk</option>'
+               + '<option value="2">User</option>'
+               + '<option value="3">User talk</option>'
+               + '<option value="4">ProjectName</option>'
+               + '<option value="5">ProjectName talk</option>'
+               + '</select>'
+               + '<input name="invert" type="checkbox" value="1" id="nsinvert" title="no title" />'
+               + '<label for="nsinvert" title="no title">Invert selection</label>'
+               + '<input name="associated" type="checkbox" value="1" id="nsassociated" title="no title" />'
+               + '<label for="nsassociated" title="no title">Associated namespace</label>'
+               + '<input type="submit" value="Go" />'
+               + '<input type="hidden" value="Special:RecentChanges" name="title" />'
+               ;
+
+               $env = $( '<div>' ).html( selectHtml ).appendTo( 'body' );
+
+               // TODO abstract the double strictEquals
+
+               // At first checkboxes are enabled
+               assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), false );
+               assert.strictEqual( $( '#nsassociated' ).prop( 'disabled' ), false );
+
+               // Initiate the recentchanges module
+               mw.special.recentchanges.init();
+
+               // By default
+               assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), true );
+               assert.strictEqual( $( '#nsassociated' ).prop( 'disabled' ), true );
+
+               // select second option...
+               $options = $( '#namespace' ).find( 'option' );
+               $options.eq(0).removeProp( 'selected' );
+               $options.eq(1).prop( 'selected', true );
+               $( '#namespace' ).change();
+
+               // ... and checkboxes should be enabled again
+               assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), false );
+               assert.strictEqual( $( '#nsassociated' ).prop( 'disabled' ), false );
+
+               // select first option ( 'all' namespace)...
+               $options.eq(1).removeProp( 'selected' );
+               $options.eq(0).prop( 'selected', true );
+               $( '#namespace' ).change();
+
+               // ... and checkboxes should now be disabled
+               assert.strictEqual( $( '#nsinvert' ).prop( 'disabled' ), true );
+               assert.strictEqual( $( '#nsassociated' ).prop( 'disabled' ), true );
+
+               // DOM cleanup
+               $env.remove();
+       });
+}( mediaWiki, jQuery ) );
index a736e12..52f0538 100644 (file)
@@ -1,58 +1,59 @@
-( function () {
+( function ( mw ) {
 
 // mw.Title relies on these three config vars
 // Restore them after each test run
 var config = {
-       "wgFormattedNamespaces": {
-               "-2": "Media",
-               "-1": "Special",
-               "0": "",
-               "1": "Talk",
-               "2": "User",
-               "3": "User talk",
-               "4": "Wikipedia",
-               "5": "Wikipedia talk",
-               "6": "File",
-               "7": "File talk",
-               "8": "MediaWiki",
-               "9": "MediaWiki talk",
-               "10": "Template",
-               "11": "Template talk",
-               "12": "Help",
-               "13": "Help talk",
-               "14": "Category",
-               "15": "Category talk",
+       wgFormattedNamespaces: {
+               '-2': 'Media',
+               '-1': 'Special',
+               0: '',
+               1: 'Talk',
+               2: 'User',
+               3: 'User talk',
+               4: 'Wikipedia',
+               5: 'Wikipedia talk',
+               6: 'File',
+               7: 'File talk',
+               8: 'MediaWiki',
+               9: 'MediaWiki talk',
+               10: 'Template',
+               11: 'Template talk',
+               12: 'Help',
+               13: 'Help talk',
+               14: 'Category',
+               15: 'Category talk',
                // testing custom / localized namespace
-               "100": "Penguins"
+               100: 'Penguins'
        },
-       "wgNamespaceIds": {
-               "media": -2,
-               "special": -1,
-               "": 0,
-               "talk": 1,
-               "user": 2,
-               "user_talk": 3,
-               "wikipedia": 4,
-               "wikipedia_talk": 5,
-               "file": 6,
-               "file_talk": 7,
-               "mediawiki": 8,
-               "mediawiki_talk": 9,
-               "template": 10,
-               "template_talk": 11,
-               "help": 12,
-               "help_talk": 13,
-               "category": 14,
-               "category_talk": 15,
-               "image": 6,
-               "image_talk": 7,
-               "project": 4,
-               "project_talk": 5,
+       wgNamespaceIds: {
+               /*jshint camelcase: false */
+               media: -2,
+               special: -1,
+               '': 0,
+               talk: 1,
+               user: 2,
+               user_talk: 3,
+               wikipedia: 4,
+               wikipedia_talk: 5,
+               file: 6,
+               file_talk: 7,
+               mediawiki: 8,
+               mediawiki_talk: 9,
+               template: 10,
+               template_talk: 11,
+               help: 12,
+               help_talk: 13,
+               category: 14,
+               category_talk: 15,
+               image: 6,
+               image_talk: 7,
+               project: 4,
+               project_talk: 5,
                /* testing custom / alias */
-               "penguins": 100,
-               "antarctic_waterfowl": 100
+               penguins: 100,
+               antarctic_waterfowl: 100
        },
-       "wgCaseSensitiveNamespaces": []
+       wgCaseSensitiveNamespaces: []
 };
 
 QUnit.module( 'mediawiki.Title', QUnit.newMwEnvironment({ config: config }) );
@@ -78,7 +79,7 @@ QUnit.test( 'Transformation', 8, function ( assert ) {
 
        title = new mw.Title( '   MediaWiki:  Foo   bar   .js   ' );
        // Don't ask why, it's the way the backend works. One space is kept of each set
-       assert.equal( title.getName(), 'Foo_bar_.js', "Merge multiple spaces to a single space." );
+       assert.equal( title.getName(), 'Foo_bar_.js', 'Merge multiple spaces to a single space.' );
 });
 
 QUnit.test( 'Main text for filename', 8, function ( assert ) {
@@ -116,7 +117,7 @@ QUnit.test( 'Namespace detection and conversion', 6, function ( assert ) {
 
 QUnit.test( 'Throw error on invalid title', 1, function ( assert ) {
        assert.throws(function () {
-               var title = new mw.Title( '' );
+               return new mw.Title( '' );
        }, 'Throw error on empty string' );
 });
 
@@ -197,4 +198,4 @@ QUnit.test( 'getUrl', 2, function ( assert ) {
        assert.equal( title.getUrl(), '/wiki/User_talk:John_Doe', 'Escaping in title and namespace for urls' );
 });
 
-}() );
\ No newline at end of file
+}( mediaWiki ) );
\ No newline at end of file
index b2026c1..f9927f0 100644 (file)
-QUnit.module( 'mediawiki.Uri', QUnit.newMwEnvironment({
-       setup: function () {
-               this.mwUriOrg = mw.Uri;
-               mw.Uri = mw.UriRelative( 'http://example.org/w/index.php' );
-       },
-       teardown: function () {
-               mw.Uri = this.mwUriOrg;
-               delete this.mwUriOrg;
-       }
-}) );
-
-$.each( [true, false], function ( i, strictMode ) {
-       QUnit.test( 'Basic mw.Uri object test in ' + ( strictMode ? '' : 'non-' ) + 'strict mode for a simple HTTP URI', 2, function ( assert ) {
-               var uriString, uri;
-               uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
-               uri = new mw.Uri( uriString, {
-                       strictMode: strictMode
+( function ( mw, $ ) {
+       QUnit.module( 'mediawiki.Uri', QUnit.newMwEnvironment({
+               setup: function () {
+                       this.mwUriOrg = mw.Uri;
+                       mw.Uri = mw.UriRelative( 'http://example.org/w/index.php' );
+               },
+               teardown: function () {
+                       mw.Uri = this.mwUriOrg;
+                       delete this.mwUriOrg;
+               }
+       }) );
+
+       $.each( [true, false], function ( i, strictMode ) {
+               QUnit.test( 'Basic mw.Uri object test in ' + ( strictMode ? '' : 'non-' ) + 'strict mode for a simple HTTP URI', 2, function ( assert ) {
+                       var uriString, uri;
+                       uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
+                       uri = new mw.Uri( uriString, {
+                               strictMode: strictMode
+                       });
+
+                       assert.deepEqual(
+                               {
+                                       protocol: uri.protocol,
+                                       host: uri.host,
+                                       port: uri.port,
+                                       path: uri.path,
+                                       query: uri.query,
+                                       fragment: uri.fragment
+                               }, {
+                                       protocol: 'http',
+                                       host: 'www.ietf.org',
+                                       port: undefined,
+                                       path: '/rfc/rfc2396.txt',
+                                       query: {},
+                                       fragment: undefined
+                               },
+                               'basic object properties'
+                       );
+
+                       assert.deepEqual(
+                               {
+                                       userInfo: uri.getUserInfo(),
+                                       authority: uri.getAuthority(),
+                                       hostPort: uri.getHostPort(),
+                                       queryString: uri.getQueryString(),
+                                       relativePath: uri.getRelativePath(),
+                                       toString: uri.toString()
+                               },
+                               {
+                                       userInfo: '',
+                                       authority: 'www.ietf.org',
+                                       hostPort: 'www.ietf.org',
+                                       queryString: '',
+                                       relativePath: '/rfc/rfc2396.txt',
+                                       toString: uriString
+                               },
+                               'construct composite components of URI on request'
+                       );
+
                });
+       });
+
+       QUnit.test( 'Parse an ftp URI correctly with user and password', 1, function ( assert ) {
+               var uri = new mw.Uri( 'ftp://usr:pwd@192.0.2.16/' );
 
                assert.deepEqual(
                        {
                                protocol: uri.protocol,
+                               user: uri.user,
+                               password: uri.password,
                                host: uri.host,
                                port: uri.port,
                                path: uri.path,
                                query: uri.query,
                                fragment: uri.fragment
-                       }, {
-                               protocol: 'http',
-                               host: 'www.ietf.org',
+                       },
+                       {
+                               protocol: 'ftp',
+                               user: 'usr',
+                               password: 'pwd',
+                               host: '192.0.2.16',
                                port: undefined,
-                               path: '/rfc/rfc2396.txt',
+                               path: '/',
                                query: {},
                                fragment: undefined
                        },
                        'basic object properties'
                );
+       } );
+
+       QUnit.test( 'Parse a uri with simple querystring', 1, function ( assert ) {
+               var uri = new mw.Uri( 'http://www.google.com/?q=uri' );
 
                assert.deepEqual(
                        {
-                               userInfo: uri.getUserInfo(),
-                               authority: uri.getAuthority(),
-                               hostPort: uri.getHostPort(),
-                               queryString: uri.getQueryString(),
-                               relativePath: uri.getRelativePath(),
-                               toString: uri.toString()
+                               protocol: uri.protocol,
+                               host: uri.host,
+                               port: uri.port,
+                               path: uri.path,
+                               query: uri.query,
+                               fragment: uri.fragment,
+                               queryString: uri.getQueryString()
                        },
                        {
-                               userInfo: '',
-                               authority: 'www.ietf.org',
-                               hostPort: 'www.ietf.org',
-                               queryString: '',
-                               relativePath: '/rfc/rfc2396.txt',
-                               toString: uriString
+                               protocol: 'http',
+                               host: 'www.google.com',
+                               port: undefined,
+                               path: '/',
+                               query: { q: 'uri' },
+                               fragment: undefined,
+                               queryString: 'q=uri'
                        },
-                       'construct composite components of URI on request'
+                       'basic object properties'
                );
+       } );
 
-       });
-});
-
-QUnit.test( 'Parse an ftp URI correctly with user and password', 1, function ( assert ) {
-       var uri = new mw.Uri( 'ftp://usr:pwd@192.0.2.16/' );
-
-       assert.deepEqual(
-               {
-                       protocol: uri.protocol,
-                       user: uri.user,
-                       password: uri.password,
-                       host: uri.host,
-                       port: uri.port,
-                       path: uri.path,
-                       query: uri.query,
-                       fragment: uri.fragment
-               },
-               {
-                       protocol: 'ftp',
-                       user: 'usr',
-                       password: 'pwd',
-                       host: '192.0.2.16',
-                       port: undefined,
-                       path: '/',
-                       query: {},
-                       fragment: undefined
-               },
-               'basic object properties'
-       );
-} );
-
-QUnit.test( 'Parse a uri with simple querystring', 1, function ( assert ) {
-       var uri = new mw.Uri( 'http://www.google.com/?q=uri' );
-
-       assert.deepEqual(
-               {
-                       protocol: uri.protocol,
-                       host: uri.host,
-                       port: uri.port,
-                       path: uri.path,
-                       query: uri.query,
-                       fragment: uri.fragment,
-                       queryString: uri.getQueryString()
-               },
-               {
-                       protocol: 'http',
-                       host: 'www.google.com',
-                       port: undefined,
-                       path: '/',
-                       query: { q: 'uri' },
-                       fragment: undefined,
-                       queryString: 'q=uri'
-               },
-               'basic object properties'
-       );
-} );
+       QUnit.test( 'Handle multiple query parameter (overrideKeys on)', 5, function ( assert ) {
+               var uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
+                       overrideKeys: true
+               });
 
-QUnit.test( 'Handle multiple query parameter (overrideKeys on)', 5, function ( assert ) {
-       var uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
-               overrideKeys: true
-       });
+               assert.equal( uri.query.n, '1', 'multiple parameters are parsed' );
+               assert.equal( uri.query.m, 'bar', 'last key overrides earlier keys' );
 
-       assert.equal( uri.query.n, '1', 'multiple parameters are parsed' );
-       assert.equal( uri.query.m, 'bar', 'last key overrides earlier keys' );
+               uri.query.n = [ 'x', 'y', 'z' ];
 
-       uri.query.n = [ 'x', 'y', 'z' ];
+               // Verify parts and total length instead of entire string because order
+               // of iteration can vary.
+               assert.ok( uri.toString().indexOf( 'm=bar' ), 'toString preserves other values' );
+               assert.ok( uri.toString().indexOf( 'n=x&n=y&n=z' ), 'toString parameter includes all values of an array query parameter' );
+               assert.equal( uri.toString().length, 'http://www.example.com/dir/?m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
+       } );
 
-       // Verify parts and total length instead of entire string because order
-       // of iteration can vary.
-       assert.ok( uri.toString().indexOf( 'm=bar' ), 'toString preserves other values' );
-       assert.ok( uri.toString().indexOf( 'n=x&n=y&n=z' ), 'toString parameter includes all values of an array query parameter' );
-       assert.equal( uri.toString().length, 'http://www.example.com/dir/?m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
-} );
+       QUnit.test( 'Handle multiple query parameter (overrideKeys off)', 9, function ( assert ) {
+               var uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
+                       overrideKeys: false
+               });
 
-QUnit.test( 'Handle multiple query parameter (overrideKeys off)', 9, function ( assert ) {
-       var uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
-               overrideKeys: false
-       });
+               // Strict comparison so that types are also verified (n should be string '1')
+               assert.strictEqual( uri.query.m.length, 2, 'multi-value query should be an array with 2 items' );
+               assert.strictEqual( uri.query.m[0], 'foo', 'order and value is correct' );
+               assert.strictEqual( uri.query.m[1], 'bar', 'order and value is correct' );
+               assert.strictEqual( uri.query.n, '1', 'n=1 is parsed with the correct value of the expected type' );
 
-       // Strict comparison so that types are also verified (n should be string '1')
-       assert.strictEqual( uri.query.m.length, 2, 'multi-value query should be an array with 2 items' );
-       assert.strictEqual( uri.query.m[0], 'foo', 'order and value is correct' );
-       assert.strictEqual( uri.query.m[1], 'bar', 'order and value is correct' );
-       assert.strictEqual( uri.query.n, '1', 'n=1 is parsed with the correct value of the expected type' );
-
-       // Change query values
-       uri.query.n = [ 'x', 'y', 'z' ];
-
-       // Verify parts and total length instead of entire string because order
-       // of iteration can vary.
-       assert.ok( uri.toString().indexOf( 'm=foo&m=bar' ) >= 0, 'toString preserves other values' );
-       assert.ok( uri.toString().indexOf( 'n=x&n=y&n=z' ) >= 0, 'toString parameter includes all values of an array query parameter' );
-       assert.equal( uri.toString().length, 'http://www.example.com/dir/?m=foo&m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
-
-       // Remove query values
-       uri.query.m.splice( 0, 1 );
-       delete uri.query.n;
-
-       assert.equal( uri.toString(), 'http://www.example.com/dir/?m=bar', 'deletion properties' );
-
-       // Remove more query values, leaving an empty array
-       uri.query.m.splice( 0, 1 );
-       assert.equal( uri.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' );
-} );
-
-QUnit.test( 'All-dressed URI with everything', 11, function ( assert ) {
-       var uri, queryString, relativePath;
-
-       uri = new mw.Uri( 'http://auth@www.example.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
-
-       assert.deepEqual(
-               {
-                       protocol: uri.protocol,
-                       user: uri.user,
-                       password: uri.password,
-                       host: uri.host,
-                       port: uri.port,
-                       path: uri.path,
-                       query: uri.query,
-                       fragment: uri.fragment
-               },
-               {
-                       protocol: 'http',
-                       user: 'auth',
-                       password: undefined,
-                       host: 'www.example.com',
-                       port: '81',
-                       path: '/dir/dir.2/index.htm',
-                       query: { q1: '0', test1: null, test2: 'value (escaped)' },
-                       fragment: 'top'
-               },
-               'basic object properties'
-       );
+               // Change query values
+               uri.query.n = [ 'x', 'y', 'z' ];
 
-       assert.equal( uri.getUserInfo(), 'auth', 'user info' );
+               // Verify parts and total length instead of entire string because order
+               // of iteration can vary.
+               assert.ok( uri.toString().indexOf( 'm=foo&m=bar' ) >= 0, 'toString preserves other values' );
+               assert.ok( uri.toString().indexOf( 'n=x&n=y&n=z' ) >= 0, 'toString parameter includes all values of an array query parameter' );
+               assert.equal( uri.toString().length, 'http://www.example.com/dir/?m=foo&m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
 
-       assert.equal( uri.getAuthority(), 'auth@www.example.com:81', 'authority equal to auth@hostport' );
+               // Remove query values
+               uri.query.m.splice( 0, 1 );
+               delete uri.query.n;
 
-       assert.equal( uri.getHostPort(), 'www.example.com:81', 'hostport equal to host:port' );
+               assert.equal( uri.toString(), 'http://www.example.com/dir/?m=bar', 'deletion properties' );
 
-       queryString = uri.getQueryString();
-       assert.ok( queryString.indexOf( 'q1=0' ) >= 0, 'query param with numbers' );
-       assert.ok( queryString.indexOf( 'test1' ) >= 0, 'query param with null value is included' );
-       assert.ok( queryString.indexOf( 'test1=' ) === -1, 'query param with null value does not generate equals sign' );
-       assert.ok( queryString.indexOf( 'test2=value+%28escaped%29' ) >= 0, 'query param is url escaped' );
+               // Remove more query values, leaving an empty array
+               uri.query.m.splice( 0, 1 );
+               assert.equal( uri.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' );
+       } );
 
-       relativePath = uri.getRelativePath();
-       assert.ok( relativePath.indexOf( uri.path ) >= 0, 'path in relative path' );
-       assert.ok( relativePath.indexOf( uri.getQueryString() ) >= 0, 'query string in relative path' );
-       assert.ok( relativePath.indexOf( uri.fragment ) >= 0, 'fragement in relative path' );
-} );
+       QUnit.test( 'All-dressed URI with everything', 11, function ( assert ) {
+               var uri, queryString, relativePath;
 
-QUnit.test( 'Cloning', 6, function ( assert ) {
-       var original, clone;
+               uri = new mw.Uri( 'http://auth@www.example.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
 
-       original = new mw.Uri( 'http://foo.example.org/index.php?one=1&two=2' );
-       clone = original.clone();
+               assert.deepEqual(
+                       {
+                               protocol: uri.protocol,
+                               user: uri.user,
+                               password: uri.password,
+                               host: uri.host,
+                               port: uri.port,
+                               path: uri.path,
+                               query: uri.query,
+                               fragment: uri.fragment
+                       },
+                       {
+                               protocol: 'http',
+                               user: 'auth',
+                               password: undefined,
+                               host: 'www.example.com',
+                               port: '81',
+                               path: '/dir/dir.2/index.htm',
+                               query: { q1: '0', test1: null, test2: 'value (escaped)' },
+                               fragment: 'top'
+                       },
+                       'basic object properties'
+               );
 
-       assert.deepEqual( clone, original, 'clone has equivalent properties' );
-       assert.equal( original.toString(), clone.toString(), 'toString matches original' );
+               assert.equal( uri.getUserInfo(), 'auth', 'user info' );
 
-       assert.notStrictEqual( clone, original, 'clone is a different object when compared by reference' );
+               assert.equal( uri.getAuthority(), 'auth@www.example.com:81', 'authority equal to auth@hostport' );
 
-       clone.host = 'bar.example.org';
-       assert.notEqual( original.host, clone.host, 'manipulating clone did not effect original' );
-       assert.notEqual( original.toString(), clone.toString(), 'Stringified url no longer matches original' );
+               assert.equal( uri.getHostPort(), 'www.example.com:81', 'hostport equal to host:port' );
 
-       clone.query.three = 3;
+               queryString = uri.getQueryString();
+               assert.ok( queryString.indexOf( 'q1=0' ) >= 0, 'query param with numbers' );
+               assert.ok( queryString.indexOf( 'test1' ) >= 0, 'query param with null value is included' );
+               assert.ok( queryString.indexOf( 'test1=' ) === -1, 'query param with null value does not generate equals sign' );
+               assert.ok( queryString.indexOf( 'test2=value+%28escaped%29' ) >= 0, 'query param is url escaped' );
 
-       assert.deepEqual(
-               original.query,
-               { 'one': '1', 'two': '2' },
-               'Properties is deep cloned (bug 37708)'
-       );
-} );
+               relativePath = uri.getRelativePath();
+               assert.ok( relativePath.indexOf( uri.path ) >= 0, 'path in relative path' );
+               assert.ok( relativePath.indexOf( uri.getQueryString() ) >= 0, 'query string in relative path' );
+               assert.ok( relativePath.indexOf( uri.fragment ) >= 0, 'fragement in relative path' );
+       } );
 
-QUnit.test( 'Constructing mw.Uri from plain object', 3, function ( assert ) {
-       var uri = new mw.Uri({
-               protocol: 'http',
-               host: 'www.foo.local',
-               path: '/this'
-       });
-       assert.equal( uri.toString(), 'http://www.foo.local/this', 'Basic properties' );
-
-       uri = new mw.Uri({
-               protocol: 'http',
-               host: 'www.foo.local',
-               path: '/this',
-               query: { hi: 'there' },
-               fragment: 'blah'
-       });
-       assert.equal( uri.toString(), 'http://www.foo.local/this?hi=there#blah', 'More complex properties' );
+       QUnit.test( 'Cloning', 6, function ( assert ) {
+               var original, clone;
 
-       assert.throws(
-               function () {
-                       var uri = new mw.Uri({
-                               protocol: 'http',
-                               host: 'www.foo.local'
-                       });
-               },
-               function ( e ) {
-                       return e.message === 'Bad constructor arguments';
-               },
-               'Construction failed when missing required properties'
-       );
-} );
+               original = new mw.Uri( 'http://foo.example.org/index.php?one=1&two=2' );
+               clone = original.clone();
 
-QUnit.test( 'Manipulate properties', 8, function ( assert ) {
-       var uriBase, uri;
+               assert.deepEqual( clone, original, 'clone has equivalent properties' );
+               assert.equal( original.toString(), clone.toString(), 'toString matches original' );
 
-       uriBase = new mw.Uri( 'http://en.wiki.local/w/api.php' );
+               assert.notStrictEqual( clone, original, 'clone is a different object when compared by reference' );
 
-       uri = uriBase.clone();
-       uri.fragment = 'frag';
-       assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php#frag', 'add a fragment' );
+               clone.host = 'bar.example.org';
+               assert.notEqual( original.host, clone.host, 'manipulating clone did not effect original' );
+               assert.notEqual( original.toString(), clone.toString(), 'Stringified url no longer matches original' );
 
-       uri = uriBase.clone();
-       uri.host = 'fr.wiki.local';
-       uri.port = '8080';
-       assert.equal( uri.toString(), 'http://fr.wiki.local:8080/w/api.php', 'change host and port' );
+               clone.query.three = 3;
 
-       uri = uriBase.clone();
-       uri.query.foo = 'bar';
-       assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'add query arguments' );
+               assert.deepEqual(
+                       original.query,
+                       { 'one': '1', 'two': '2' },
+                       'Properties is deep cloned (bug 37708)'
+               );
+       } );
 
-       delete uri.query.foo;
-       assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php', 'delete query arguments' );
+       QUnit.test( 'Constructing mw.Uri from plain object', 3, function ( assert ) {
+               var uri = new mw.Uri({
+                       protocol: 'http',
+                       host: 'www.foo.local',
+                       path: '/this'
+               });
+               assert.equal( uri.toString(), 'http://www.foo.local/this', 'Basic properties' );
 
-       uri = uriBase.clone();
-       uri.query.foo = 'bar';
-       assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'extend query arguments' );
-       uri.extend({
-               foo: 'quux',
-               pif: 'paf'
-       });
-       assert.ok( uri.toString().indexOf( 'foo=quux' ) >= 0, 'extend query arguments' );
-       assert.ok( uri.toString().indexOf( 'foo=bar' ) === -1, 'extend query arguments' );
-       assert.ok( uri.toString().indexOf( 'pif=paf' ) >= 0 , 'extend query arguments' );
-} );
+               uri = new mw.Uri({
+                       protocol: 'http',
+                       host: 'www.foo.local',
+                       path: '/this',
+                       query: { hi: 'there' },
+                       fragment: 'blah'
+               });
+               assert.equal( uri.toString(), 'http://www.foo.local/this?hi=there#blah', 'More complex properties' );
+
+               assert.throws(
+                       function () {
+                               return new mw.Uri({
+                                       protocol: 'http',
+                                       host: 'www.foo.local'
+                               });
+                       },
+                       function ( e ) {
+                               return e.message === 'Bad constructor arguments';
+                       },
+                       'Construction failed when missing required properties'
+               );
+       } );
 
-QUnit.test( 'Handle protocol-relative URLs', 5, function ( assert ) {
-       var UriRel, uri;
+       QUnit.test( 'Manipulate properties', 8, function ( assert ) {
+               var uriBase, uri;
 
-       UriRel = mw.UriRelative( 'glork://en.wiki.local/foo.php' );
+               uriBase = new mw.Uri( 'http://en.wiki.local/w/api.php' );
 
-       uri = new UriRel( '//en.wiki.local/w/api.php' );
-       assert.equal( uri.protocol, 'glork', 'create protocol-relative URLs with same protocol as document' );
+               uri = uriBase.clone();
+               uri.fragment = 'frag';
+               assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php#frag', 'add a fragment' );
 
-       uri = new UriRel( '/foo.com' );
-       assert.equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in loose mode' );
+               uri = uriBase.clone();
+               uri.host = 'fr.wiki.local';
+               uri.port = '8080';
+               assert.equal( uri.toString(), 'http://fr.wiki.local:8080/w/api.php', 'change host and port' );
 
-       uri = new UriRel( 'http:/foo.com' );
-       assert.equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in loose mode' );
+               uri = uriBase.clone();
+               uri.query.foo = 'bar';
+               assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'add query arguments' );
 
-       uri = new UriRel( '/foo.com', true );
-       assert.equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in strict mode' );
+               delete uri.query.foo;
+               assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php', 'delete query arguments' );
 
-       uri = new UriRel( 'http:/foo.com', true );
-       assert.equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in strict mode' );
-} );
+               uri = uriBase.clone();
+               uri.query.foo = 'bar';
+               assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'extend query arguments' );
+               uri.extend({
+                       foo: 'quux',
+                       pif: 'paf'
+               });
+               assert.ok( uri.toString().indexOf( 'foo=quux' ) >= 0, 'extend query arguments' );
+               assert.ok( uri.toString().indexOf( 'foo=bar' ) === -1, 'extend query arguments' );
+               assert.ok( uri.toString().indexOf( 'pif=paf' ) >= 0 , 'extend query arguments' );
+       } );
 
-QUnit.test( 'Bad calls', 3, function ( assert ) {
-       var uri;
+       QUnit.test( 'Handle protocol-relative URLs', 5, function ( assert ) {
+               var UriRel, uri;
 
-       assert.throws(
-               function () {
-                       new mw.Uri( 'glaswegian penguins' );
-               },
-               function ( e ) {
-                       return e.message === 'Bad constructor arguments';
-               },
-               'throw error on non-URI as argument to constructor'
-       );
+               UriRel = mw.UriRelative( 'glork://en.wiki.local/foo.php' );
 
-       assert.throws(
-               function () {
-                       new mw.Uri( 'foo.com/bar/baz', {
-                               strictMode: true
-                       });
-               },
-               function ( e ) {
-                       return e.message === 'Bad constructor arguments';
-               },
-               'throw error on URI without protocol or // or leading / in strict mode'
-       );
+               uri = new UriRel( '//en.wiki.local/w/api.php' );
+               assert.equal( uri.protocol, 'glork', 'create protocol-relative URLs with same protocol as document' );
+
+               uri = new UriRel( '/foo.com' );
+               assert.equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in loose mode' );
+
+               uri = new UriRel( 'http:/foo.com' );
+               assert.equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in loose mode' );
+
+               uri = new UriRel( '/foo.com', true );
+               assert.equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in strict mode' );
+
+               uri = new UriRel( 'http:/foo.com', true );
+               assert.equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in strict mode' );
+       } );
 
-       uri = new mw.Uri( 'foo.com/bar/baz', {
-               strictMode: false
+       QUnit.test( 'Bad calls', 3, function ( assert ) {
+               var uri;
+
+               assert.throws(
+                       function () {
+                               return new mw.Uri( 'glaswegian penguins' );
+                       },
+                       function ( e ) {
+                               return e.message === 'Bad constructor arguments';
+                       },
+                       'throw error on non-URI as argument to constructor'
+               );
+
+               assert.throws(
+                       function () {
+                               return new mw.Uri( 'foo.com/bar/baz', {
+                                       strictMode: true
+                               });
+                       },
+                       function ( e ) {
+                               return e.message === 'Bad constructor arguments';
+                       },
+                       'throw error on URI without protocol or // or leading / in strict mode'
+               );
+
+               uri = new mw.Uri( 'foo.com/bar/baz', {
+                       strictMode: false
+               });
+               assert.equal( uri.toString(), 'http://foo.com/bar/baz', 'normalize URI without protocol or // in loose mode' );
        });
-       assert.equal( uri.toString(), 'http://foo.com/bar/baz', 'normalize URI without protocol or // in loose mode' );
-});
 
-QUnit.test( 'bug 35658', 2, function ( assert ) {
-       var testProtocol, testServer, testPort, testPath, UriClass, uri, href;
+       QUnit.test( 'bug 35658', 2, function ( assert ) {
+               var testProtocol, testServer, testPort, testPath, UriClass, uri, href;
 
-       testProtocol = 'https://';
-       testServer = 'foo.example.org';
-       testPort = '3004';
-       testPath = '/!1qy';
+               testProtocol = 'https://';
+               testServer = 'foo.example.org';
+               testPort = '3004';
+               testPath = '/!1qy';
 
-       UriClass = mw.UriRelative( testProtocol + testServer + '/some/path/index.html' );
-       uri = new UriClass( testPath );
-       href = uri.toString();
-       assert.equal( href, testProtocol + testServer + testPath, 'Root-relative URL gets host & protocol supplied' );
+               UriClass = mw.UriRelative( testProtocol + testServer + '/some/path/index.html' );
+               uri = new UriClass( testPath );
+               href = uri.toString();
+               assert.equal( href, testProtocol + testServer + testPath, 'Root-relative URL gets host & protocol supplied' );
 
-       UriClass = mw.UriRelative( testProtocol + testServer + ':' + testPort + '/some/path.php' );
-       uri = new UriClass( testPath );
-       href = uri.toString();
-       assert.equal( href, testProtocol + testServer + ':' + testPort + testPath, 'Root-relative URL gets host, protocol, and port supplied' );
+               UriClass = mw.UriRelative( testProtocol + testServer + ':' + testPort + '/some/path.php' );
+               uri = new UriClass( testPath );
+               href = uri.toString();
+               assert.equal( href, testProtocol + testServer + ':' + testPort + testPath, 'Root-relative URL gets host, protocol, and port supplied' );
 
-} );
+       } );
 
-QUnit.test( 'Constructor falls back to default location', 4, function ( assert ) {
-       var testuri, MyUri, uri;
+       QUnit.test( 'Constructor falls back to default location', 4, function ( assert ) {
+               var testuri, MyUri, uri;
 
-       testuri = 'http://example.org/w/index.php';
-       MyUri = mw.UriRelative( testuri );
+               testuri = 'http://example.org/w/index.php';
+               MyUri = mw.UriRelative( testuri );
 
-       uri = new MyUri();
-       assert.equal( uri.toString(), testuri, 'no arguments' );
+               uri = new MyUri();
+               assert.equal( uri.toString(), testuri, 'no arguments' );
 
-       uri = new MyUri( undefined );
-       assert.equal( uri.toString(), testuri, 'undefined' );
+               uri = new MyUri( undefined );
+               assert.equal( uri.toString(), testuri, 'undefined' );
 
-       uri = new MyUri( null );
-       assert.equal( uri.toString(), testuri, 'null' );
+               uri = new MyUri( null );
+               assert.equal( uri.toString(), testuri, 'null' );
 
-       uri = new MyUri( '' );
-       assert.equal( uri.toString(), testuri, 'empty string' );
-} );
+               uri = new MyUri( '' );
+               assert.equal( uri.toString(), testuri, 'empty string' );
+       } );
+}( mediaWiki, jQuery ) );
index e2c6668..b745fb4 100644 (file)
@@ -1,74 +1,76 @@
-QUnit.module( 'mediawiki.cldr', QUnit.newMwEnvironment() );
+( function ( mw, $ ) {
+       QUnit.module( 'mediawiki.cldr', QUnit.newMwEnvironment() );
 
-var pluralTestcases = {
-       /*
-        * Sample:
-        * "languagecode" : [
-        *   [ number, [ "form1", "form2", ... ],  "expected", "description" ]
-        * ];
-        */
-       "en": [
-               [ 0, [ "one", "other" ], "other", "English plural test- 0 is other" ],
-               [ 1, [ "one", "other" ], "one", "English plural test- 1 is one" ]
-       ],
-       "fa": [
-               [ 0, [ "one", "other" ], "other", "Persian plural test- 0 is other" ],
-               [ 1, [ "one", "other" ], "one", "Persian plural test- 1 is one" ],
-               [ 2, [ "one", "other" ], "other", "Persian plural test- 2 is other" ]
-       ],
-       "fr": [
-               [ 0, [ "one", "other" ], "other", "French plural test- 0 is other" ],
-               [ 1, [ "one", "other" ], "one", "French plural test- 1 is one" ]
-       ],
-       "hi": [
-               [ 0, [ "one", "other" ], "one", "Hindi plural test- 0 is one" ],
-               [ 1, [ "one", "other" ], "one", "Hindi plural test- 1 is one" ],
-               [ 2, [ "one", "other" ], "other", "Hindi plural test- 2 is other" ]
-       ],
-       "he": [
-               [ 0, [ "one", "other" ], "other", "Hebrew plural test- 0 is other" ],
-               [ 1, [ "one", "other" ], "one", "Hebrew plural test- 1 is one" ],
-               [ 2, [ "one", "other" ], "other", "Hebrew plural test- 2 is other with 2 forms" ],
-               [ 2, [ "one", "dual", "other" ], "dual", "Hebrew plural test- 2 is dual with 3 forms" ]
-       ],
-       "hu": [
-               [ 0, [ "one", "other" ], "other", "Hungarian plural test- 0 is other" ],
-               [ 1, [ "one", "other" ], "one", "Hungarian plural test- 1 is one" ],
-               [ 2, [ "one", "other" ], "other", "Hungarian plural test- 2 is other" ]
-       ],
-       "ar": [
-               [ 0, [ "zero", "one", "two", "few", "many", "other" ], "zero", "Arabic plural test - 0 is zero" ],
-               [ 1, [ "zero", "one", "two", "few", "many", "other" ], "one", "Arabic plural test - 1 is one" ],
-               [ 2, [ "zero", "one", "two", "few", "many", "other" ], "two", "Arabic plural test - 2 is two" ],
-               [ 3, [ "zero", "one", "two", "few", "many", "other" ], "few", "Arabic plural test - 3 is few" ],
-               [ 9, [ "zero", "one", "two", "few", "many", "other" ], "few", "Arabic plural test - 9 is few" ],
-               [ "9", [ "zero", "one", "two", "few", "many", "other" ], "few", "Arabic plural test - 9 is few" ],
-               [ 110, [ "zero", "one", "two", "few", "many", "other" ], "few", "Arabic plural test - 110 is few" ],
-               [ 11, [ "zero", "one", "two", "few", "many", "other" ], "many", "Arabic plural test - 11 is many" ],
-               [ 15, [ "zero", "one", "two", "few", "many", "other" ], "many", "Arabic plural test - 15 is many" ],
-               [ 99, [ "zero", "one", "two", "few", "many", "other" ], "many", "Arabic plural test - 99 is many" ],
-               [ 9999, [ "zero", "one", "two", "few", "many", "other" ], "many", "Arabic plural test - 9999 is many" ],
-               [ 100, [ "zero", "one", "two", "few", "many", "other" ], "other", "Arabic plural test - 100 is other" ],
-               [ 102, [ "zero", "one", "two", "few", "many", "other" ], "other", "Arabic plural test - 102 is other" ],
-               [ 1000, [ "zero", "one", "two", "few", "many", "other" ], "other", "Arabic plural test - 1000 is other" ],
-               [ 1.7, [ "zero", "one", "two", "few", "many", "other" ], "other", "Arabic plural test - 1.7 is other" ]
-       ]
-};
+       var pluralTestcases = {
+               /*
+                * Sample:
+                * languagecode : [
+                *   [ number, [ 'form1', 'form2', ... ],  'expected', 'description' ]
+                * ];
+                */
+               en: [
+                       [ 0, [ 'one', 'other' ], 'other', 'English plural test- 0 is other' ],
+                       [ 1, [ 'one', 'other' ], 'one', 'English plural test- 1 is one' ]
+               ],
+               fa: [
+                       [ 0, [ 'one', 'other' ], 'other', 'Persian plural test- 0 is other' ],
+                       [ 1, [ 'one', 'other' ], 'one', 'Persian plural test- 1 is one' ],
+                       [ 2, [ 'one', 'other' ], 'other', 'Persian plural test- 2 is other' ]
+               ],
+               fr: [
+                       [ 0, [ 'one', 'other' ], 'other', 'French plural test- 0 is other' ],
+                       [ 1, [ 'one', 'other' ], 'one', 'French plural test- 1 is one' ]
+               ],
+               hi: [
+                       [ 0, [ 'one', 'other' ], 'one', 'Hindi plural test- 0 is one' ],
+                       [ 1, [ 'one', 'other' ], 'one', 'Hindi plural test- 1 is one' ],
+                       [ 2, [ 'one', 'other' ], 'other', 'Hindi plural test- 2 is other' ]
+               ],
+               he: [
+                       [ 0, [ 'one', 'other' ], 'other', 'Hebrew plural test- 0 is other' ],
+                       [ 1, [ 'one', 'other' ], 'one', 'Hebrew plural test- 1 is one' ],
+                       [ 2, [ 'one', 'other' ], 'other', 'Hebrew plural test- 2 is other with 2 forms' ],
+                       [ 2, [ 'one', 'dual', 'other' ], 'dual', 'Hebrew plural test- 2 is dual with 3 forms' ]
+               ],
+               hu: [
+                       [ 0, [ 'one', 'other' ], 'other', 'Hungarian plural test- 0 is other' ],
+                       [ 1, [ 'one', 'other' ], 'one', 'Hungarian plural test- 1 is one' ],
+                       [ 2, [ 'one', 'other' ], 'other', 'Hungarian plural test- 2 is other' ]
+               ],
+               ar: [
+                       [ 0, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'zero', 'Arabic plural test - 0 is zero' ],
+                       [ 1, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'one', 'Arabic plural test - 1 is one' ],
+                       [ 2, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'two', 'Arabic plural test - 2 is two' ],
+                       [ 3, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'few', 'Arabic plural test - 3 is few' ],
+                       [ 9, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'few', 'Arabic plural test - 9 is few' ],
+                       [ '9', [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'few', 'Arabic plural test - 9 is few' ],
+                       [ 110, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'few', 'Arabic plural test - 110 is few' ],
+                       [ 11, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'many', 'Arabic plural test - 11 is many' ],
+                       [ 15, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'many', 'Arabic plural test - 15 is many' ],
+                       [ 99, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'many', 'Arabic plural test - 99 is many' ],
+                       [ 9999, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'many', 'Arabic plural test - 9999 is many' ],
+                       [ 100, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'other', 'Arabic plural test - 100 is other' ],
+                       [ 102, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'other', 'Arabic plural test - 102 is other' ],
+                       [ 1000, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'other', 'Arabic plural test - 1000 is other' ],
+                       [ 1.7, [ 'zero', 'one', 'two', 'few', 'many', 'other' ], 'other', 'Arabic plural test - 1.7 is other' ]
+               ]
+       };
 
-function pluralTest( langCode, tests ) {
-       QUnit.test( 'Plural Test for ' + langCode, tests.length, function ( assert ) {
-               for ( var i = 0; i < tests.length; i++ ) {
-                       assert.equal(
-                               mw.language.convertPlural( tests[i][0], tests[i][1] ),
-                               tests[i][2],
-                               tests[i][3]
-                       );
+       function pluralTest( langCode, tests ) {
+               QUnit.test( 'Plural Test for ' + langCode, tests.length, function ( assert ) {
+                       for ( var i = 0; i < tests.length; i++ ) {
+                               assert.equal(
+                                       mw.language.convertPlural( tests[i][0], tests[i][1] ),
+                                       tests[i][2],
+                                       tests[i][3]
+                               );
+                       }
+               } );
+       }
+
+       $.each( pluralTestcases, function ( langCode, tests ) {
+               if ( langCode === mw.config.get( 'wgUserLanguage' ) ) {
+                       pluralTest( langCode, tests );
                }
        } );
-}
-
-$.each( pluralTestcases, function ( langCode, tests ) {
-       if ( langCode === mw.config.get( 'wgUserLanguage' ) ) {
-               pluralTest( langCode, tests );
-       }
-} );
+}( mediaWiki, jQuery ) );
index 2baa4f3..bc6fafe 100644 (file)
@@ -1,62 +1,70 @@
-/* Some misc JavaScript compatibility tests, just to make sure the environments we run in are consistent */
-
-QUnit.module( 'mediawiki.jscompat', QUnit.newMwEnvironment() );
-
-QUnit.test( 'Variable with Unicode letter in name', 3, function ( assert ) {
-       var orig = "some token";
-       var ŝablono = orig;
-
-       assert.deepEqual( ŝablono, orig, 'ŝablono' );
-       assert.deepEqual( \u015dablono, orig, '\\u015dablono' );
-       assert.deepEqual( \u015Dablono, orig, '\\u015Dablono' );
-});
-
-/*
-// Not that we need this. ;)
-// This fails on IE 6-8
-// Works on IE 9, Firefox 6, Chrome 14
-QUnit.test( 'Keyword workaround: "if" as variable name using Unicode escapes', function ( assert ) {
-       var orig = "another token";
-       \u0069\u0066 = orig;
-       assert.deepEqual( \u0069\u0066, orig, '\\u0069\\u0066' );
-});
-*/
-
-/*
-// Not that we need this. ;)
-// This fails on IE 6-9
-// Works on Firefox 6, Chrome 14
-QUnit.test( 'Keyword workaround: "if" as member variable name using Unicode escapes', function ( assert ) {
-       var orig = "another token";
-       var foo = {};
-       foo.\u0069\u0066 = orig;
-       assert.deepEqual( foo.\u0069\u0066, orig, 'foo.\\u0069\\u0066' );
-});
-*/
-
-QUnit.test( 'Stripping of single initial newline from textarea\'s literal contents (bug 12130)', function ( assert ) {
-       var maxn = 4;
-       QUnit.expect( maxn * 2 );
-
-       function repeat( str, n ) {
-               if ( n <= 0 ) {
-                       return '';
-               } else {
-                       var out = new Array(n);
-                       for ( var i = 0; i < n; i++ ) {
-                               out[i] = str;
+/**
+ * Some misc JavaScript compatibility tests,
+ * just to make sure the environments we run in are consistent.
+ */
+( function ( $ ) {
+       QUnit.module( 'mediawiki.jscompat', QUnit.newMwEnvironment() );
+
+       QUnit.test( 'Variable with Unicode letter in name', 3, function ( assert ) {
+               var orig, ŝablono;
+
+               orig = 'some token';
+               ŝablono = orig;
+
+               assert.deepEqual( ŝablono, orig, 'ŝablono' );
+               assert.deepEqual( \u015dablono, orig, '\\u015dablono' );
+               assert.deepEqual( \u015Dablono, orig, '\\u015Dablono' );
+       });
+
+       /*
+       // Not that we need this. ;)
+       // This fails on IE 6-8
+       // Works on IE 9, Firefox 6, Chrome 14
+       QUnit.test( 'Keyword workaround: "if" as variable name using Unicode escapes', function ( assert ) {
+               var orig = "another token";
+               \u0069\u0066 = orig;
+               assert.deepEqual( \u0069\u0066, orig, '\\u0069\\u0066' );
+       });
+       */
+
+       /*
+       // Not that we need this. ;)
+       // This fails on IE 6-9
+       // Works on Firefox 6, Chrome 14
+       QUnit.test( 'Keyword workaround: "if" as member variable name using Unicode escapes', function ( assert ) {
+               var orig = "another token";
+               var foo = {};
+               foo.\u0069\u0066 = orig;
+               assert.deepEqual( foo.\u0069\u0066, orig, 'foo.\\u0069\\u0066' );
+       });
+       */
+
+       QUnit.test( 'Stripping of single initial newline from textarea\'s literal contents (bug 12130)', function ( assert ) {
+               var maxn, n,
+                       expected, $textarea;
+
+               maxn = 4;
+               QUnit.expect( maxn * 2 );
+
+               function repeat( str, n ) {
+                       var out;
+                       if ( n <= 0 ) {
+                               return '';
+                       } else {
+                               out = [];
+                               out.length = n + 1;
+                               return out.join( str );
                        }
-                       return out.join('');
                }
-       }
 
-       for ( var n = 0; n < maxn; n++ ) {
-               var expected = repeat('\n', n) + 'some text';
+               for ( n = 0; n < maxn; n++ ) {
+                       expected = repeat('\n', n) + 'some text';
 
-               var $textarea = $('<textarea>\n' + expected + '</textarea>');
-               assert.equal( $textarea.val(), expected, 'Expecting ' + n + ' newlines (HTML contained ' + (n + 1) + ')' );
+                       $textarea = $('<textarea>\n' + expected + '</textarea>');
+                       assert.equal( $textarea.val(), expected, 'Expecting ' + n + ' newlines (HTML contained ' + (n + 1) + ')' );
 
-               var $textarea2 = $('<textarea>').val(expected);
-               assert.equal( $textarea2.val(), expected, 'Expecting ' + n + ' newlines (from DOM set with ' + n + ')' );
-       }
-});
+                       $textarea = $('<textarea>').val( expected );
+                       assert.equal( $textarea.val(), expected, 'Expecting ' + n + ' newlines (from DOM set with ' + n + ')' );
+               }
+       });
+}( jQuery ) );
index 3fa2b09..869ebe4 100644 (file)
-QUnit.module( 'mediawiki.language', QUnit.newMwEnvironment({
-       setup: function () {
-               this.liveLangData = mw.language.data.values;
-               mw.language.data.values = $.extend( true, {}, this.liveLangData );
-       },
-       teardown: function () {
-               // Restore
-               mw.language.data.values = this.liveLangData;
-       }
-}) );
+( function ( mw, $ ) {
 
-QUnit.test( 'mw.language getData and setData', function ( assert ) {
-       QUnit.expect( 2 );
+       QUnit.module( 'mediawiki.language', QUnit.newMwEnvironment({
+               setup: function () {
+                       this.liveLangData = mw.language.data.values;
+                       mw.language.data.values = $.extend( true, {}, this.liveLangData );
+               },
+               teardown: function () {
+                       mw.language.data.values = this.liveLangData;
+               }
+       }) );
 
-       mw.language.setData( 'en', 'testkey', 'testvalue' );
-       assert.equal(  mw.language.getData( 'en', 'testkey' ), 'testvalue', 'Getter setter test for mw.language' );
-       assert.equal(  mw.language.getData( 'en', 'invalidkey' ), undefined, 'Getter setter test for mw.language with invalid key' );
-} );
+       QUnit.test( 'mw.language getData and setData', 2, function ( assert ) {
+               mw.language.setData( 'en', 'testkey', 'testvalue' );
+               assert.equal(  mw.language.getData( 'en', 'testkey' ), 'testvalue', 'Getter setter test for mw.language' );
+               assert.equal(  mw.language.getData( 'en', 'invalidkey' ), undefined, 'Getter setter test for mw.language with invalid key' );
+       } );
 
-function grammarTest( langCode, test ) {
-       // The test works only if the content language is opt.language
-       // because it requires [lang].js to be loaded.
-       QUnit.test( 'Grammar test for lang=' + langCode, function ( assert ) {
-               QUnit.expect( test.length );
+       function grammarTest( langCode, test ) {
+               // The test works only if the content language is opt.language
+               // because it requires [lang].js to be loaded.
+               QUnit.test( 'Grammar test for lang=' + langCode, function ( assert ) {
+                       QUnit.expect( test.length );
 
-               for ( var i = 0 ; i < test.length; i++ ) {
-                       assert.equal(
-                               mw.language.convertGrammar( test[i].word, test[i].grammarForm ),
-                               test[i].expected,
-                               test[i].description
-                       );
-               }
-       });
-}
+                       for ( var i = 0 ; i < test.length; i++ ) {
+                               assert.equal(
+                                       mw.language.convertGrammar( test[i].word, test[i].grammarForm ),
+                                       test[i].expected,
+                                       test[i].description
+                               );
+                       }
+               });
+       }
 
-var grammarTests = {
-       bs: [
-               {
-                       word: 'word',
-                       grammarForm: 'instrumental',
-                       expected: 's word',
-                       description: 'Grammar test for instrumental case'
-               },
-               {
-                       word: 'word',
-                       grammarForm: 'lokativ',
-                       expected: 'o word',
-                       description: 'Grammar test for lokativ case'
-               }
-       ],
+       var grammarTests = {
+               bs: [
+                       {
+                               word: 'word',
+                               grammarForm: 'instrumental',
+                               expected: 's word',
+                               description: 'Grammar test for instrumental case'
+                       },
+                       {
+                               word: 'word',
+                               grammarForm: 'lokativ',
+                               expected: 'o word',
+                               description: 'Grammar test for lokativ case'
+                       }
+               ],
 
-       he: [
-               {
-                       word: "ויקיפדיה",
-                       grammarForm: 'prefixed',
-                       expected: "וויקיפדיה",
-                       description: 'Duplicate the "Waw" if prefixed'
-               },
-               {
-                       word: "וולפגנג",
-                       grammarForm: 'prefixed',
-                       expected: "וולפגנג",
-                       description: 'Duplicate the "Waw" if prefixed, but not if it is already duplicated.'
-               },
-               {
-                       word: "הקובץ",
-                       grammarForm: 'prefixed',
-                       expected: "קובץ",
-                       description: 'Remove the "He" if prefixed'
-               },
-               {
-                       word: 'Wikipedia',
-                       grammarForm: 'תחילית',
-                       expected: '־Wikipedia',
-                       description: 'GAdd a hyphen (maqaf) before non-Hebrew letters'
-               },
-               {
-                       word: '1995',
-                       grammarForm: 'תחילית',
-                       expected: '־1995',
-                       description: 'Add a hyphen (maqaf) before numbers'
-               }
-       ],
+               he: [
+                       {
+                               word: 'ויקיפדיה',
+                               grammarForm: 'prefixed',
+                               expected: 'וויקיפדיה',
+                               description: 'Duplicate the "Waw" if prefixed'
+                       },
+                       {
+                               word: 'וולפגנג',
+                               grammarForm: 'prefixed',
+                               expected: 'וולפגנג',
+                               description: 'Duplicate the "Waw" if prefixed, but not if it is already duplicated.'
+                       },
+                       {
+                               word: 'הקובץ',
+                               grammarForm: 'prefixed',
+                               expected: 'קובץ',
+                               description: 'Remove the "He" if prefixed'
+                       },
+                       {
+                               word: 'Wikipedia',
+                               grammarForm: 'תחילית',
+                               expected: '־Wikipedia',
+                               description: 'GAdd a hyphen (maqaf) before non-Hebrew letters'
+                       },
+                       {
+                               word: '1995',
+                               grammarForm: 'תחילית',
+                               expected: '־1995',
+                               description: 'Add a hyphen (maqaf) before numbers'
+                       }
+               ],
 
-       hsb: [
-               {
-                       word: 'word',
-                       grammarForm: 'instrumental',
-                       expected: 'z word',
-                       description: 'Grammar test for instrumental case'
-               },
-               {
-                       word: 'word',
-                       grammarForm: 'lokatiw',
-                       expected: 'wo word',
-                       description: 'Grammar test for lokatiw case'
-               }
-       ],
+               hsb: [
+                       {
+                               word: 'word',
+                               grammarForm: 'instrumental',
+                               expected: 'z word',
+                               description: 'Grammar test for instrumental case'
+                       },
+                       {
+                               word: 'word',
+                               grammarForm: 'lokatiw',
+                               expected: 'wo word',
+                               description: 'Grammar test for lokatiw case'
+                       }
+               ],
 
-       dsb: [
-               {
-                       word: 'word',
-                       grammarForm: 'instrumental',
-                       expected: 'z word',
-                       description: 'Grammar test for instrumental case'
-               },
-               {
-                       word: 'word',
-                       grammarForm: 'lokatiw',
-                       expected: 'wo word',
-                       description: 'Grammar test for lokatiw case'
-               }
-       ],
+               dsb: [
+                       {
+                               word: 'word',
+                               grammarForm: 'instrumental',
+                               expected: 'z word',
+                               description: 'Grammar test for instrumental case'
+                       },
+                       {
+                               word: 'word',
+                               grammarForm: 'lokatiw',
+                               expected: 'wo word',
+                               description: 'Grammar test for lokatiw case'
+                       }
+               ],
 
-       hy: [
-               {
-                       word: 'Մաունա',
-                       grammarForm: 'genitive',
-                       expected: 'Մաունայի',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'հետո',
-                       grammarForm: 'genitive',
-                       expected: 'հետոյի',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'գիրք',
-                       grammarForm: 'genitive',
-                       expected: 'գրքի',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'ժամանակի',
-                       grammarForm: 'genitive',
-                       expected: 'ժամանակիի',
-                       description: 'Grammar test for genitive case'
-               }
-       ],
+               hy: [
+                       {
+                               word: 'Մաունա',
+                               grammarForm: 'genitive',
+                               expected: 'Մաունայի',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'հետո',
+                               grammarForm: 'genitive',
+                               expected: 'հետոյի',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'գիրք',
+                               grammarForm: 'genitive',
+                               expected: 'գրքի',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'ժամանակի',
+                               grammarForm: 'genitive',
+                               expected: 'ժամանակիի',
+                               description: 'Grammar test for genitive case'
+                       }
+               ],
 
-       fi: [
-               {
-                       word: 'talo',
-                       grammarForm: 'genitive',
-                       expected: 'talon',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'linux',
-                       grammarForm: 'genitive',
-                       expected: 'linuxin',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'talo',
-                       grammarForm: 'elative',
-                       expected: 'talosta',
-                       description: 'Grammar test for elative case'
-               },
-               {
-                       word: 'pastöroitu',
-                       grammarForm: 'partitive',
-                       expected: 'pastöroitua',
-                       description: 'Grammar test for partitive case'
-               },
-               {
-                       word: 'talo',
-                       grammarForm: 'partitive',
-                       expected: 'taloa',
-                       description: 'Grammar test for partitive case'
-               },
-               {
-                       word: 'talo',
-                       grammarForm: 'illative',
-                       expected: 'taloon',
-                       description: 'Grammar test for illative case'
-               },
-               {
-                       word: 'linux',
-                       grammarForm: 'inessive',
-                       expected: 'linuxissa',
-                       description: 'Grammar test for inessive case'
-               }
-       ],
+               fi: [
+                       {
+                               word: 'talo',
+                               grammarForm: 'genitive',
+                               expected: 'talon',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'linux',
+                               grammarForm: 'genitive',
+                               expected: 'linuxin',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'talo',
+                               grammarForm: 'elative',
+                               expected: 'talosta',
+                               description: 'Grammar test for elative case'
+                       },
+                       {
+                               word: 'pastöroitu',
+                               grammarForm: 'partitive',
+                               expected: 'pastöroitua',
+                               description: 'Grammar test for partitive case'
+                       },
+                       {
+                               word: 'talo',
+                               grammarForm: 'partitive',
+                               expected: 'taloa',
+                               description: 'Grammar test for partitive case'
+                       },
+                       {
+                               word: 'talo',
+                               grammarForm: 'illative',
+                               expected: 'taloon',
+                               description: 'Grammar test for illative case'
+                       },
+                       {
+                               word: 'linux',
+                               grammarForm: 'inessive',
+                               expected: 'linuxissa',
+                               description: 'Grammar test for inessive case'
+                       }
+               ],
 
-       ru: [
-               {
-                       word: 'тесть',
-                       grammarForm: 'genitive',
-                       expected: 'тестя',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'привилегия',
-                       grammarForm: 'genitive',
-                       expected: 'привилегии',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'установка',
-                       grammarForm: 'genitive',
-                       expected: 'установки',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'похоти',
-                       grammarForm: 'genitive',
-                       expected: 'похотей',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'доводы',
-                       grammarForm: 'genitive',
-                       expected: 'доводов',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'песчаник',
-                       grammarForm: 'genitive',
-                       expected: 'песчаника',
-                       description: 'Grammar test for genitive case'
-               }
-       ],
+               ru: [
+                       {
+                               word: 'тесть',
+                               grammarForm: 'genitive',
+                               expected: 'тестя',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'привилегия',
+                               grammarForm: 'genitive',
+                               expected: 'привилегии',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'установка',
+                               grammarForm: 'genitive',
+                               expected: 'установки',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'похоти',
+                               grammarForm: 'genitive',
+                               expected: 'похотей',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'доводы',
+                               grammarForm: 'genitive',
+                               expected: 'доводов',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'песчаник',
+                               grammarForm: 'genitive',
+                               expected: 'песчаника',
+                               description: 'Grammar test for genitive case'
+                       }
+               ],
 
 
-       hu: [
-               {
-                       word: 'Wikipédiá',
-                       grammarForm: 'rol',
-                       expected: 'Wikipédiáról',
-                       description: 'Grammar test for rol case'
-               },
-               {
-                       word: 'Wikipédiá',
-                       grammarForm: 'ba',
-                       expected: 'Wikipédiába',
-                       description: 'Grammar test for ba case'
-               },
-               {
-                       word: 'Wikipédiá',
-                       grammarForm: 'k',
-                       expected: 'Wikipédiák',
-                       description: 'Grammar test for k case'
-               }
-       ],
+               hu: [
+                       {
+                               word: 'Wikipédiá',
+                               grammarForm: 'rol',
+                               expected: 'Wikipédiáról',
+                               description: 'Grammar test for rol case'
+                       },
+                       {
+                               word: 'Wikipédiá',
+                               grammarForm: 'ba',
+                               expected: 'Wikipédiába',
+                               description: 'Grammar test for ba case'
+                       },
+                       {
+                               word: 'Wikipédiá',
+                               grammarForm: 'k',
+                               expected: 'Wikipédiák',
+                               description: 'Grammar test for k case'
+                       }
+               ],
 
-       ga: [
-               {
-                       word: 'an Domhnach',
-                       grammarForm: 'ainmlae',
-                       expected: 'Dé Domhnaigh',
-                       description: 'Grammar test for ainmlae case'
-               },
-               {
-                       word: 'an Luan',
-                       grammarForm: 'ainmlae',
-                       expected: 'Dé Luain',
-                       description: 'Grammar test for ainmlae case'
-               },
-               {
-                       word: 'an Satharn',
-                       grammarForm: 'ainmlae',
-                       expected: 'Dé Sathairn',
-                       description: 'Grammar test for ainmlae case'
-               }
-       ],
+               ga: [
+                       {
+                               word: 'an Domhnach',
+                               grammarForm: 'ainmlae',
+                               expected: 'Dé Domhnaigh',
+                               description: 'Grammar test for ainmlae case'
+                       },
+                       {
+                               word: 'an Luan',
+                               grammarForm: 'ainmlae',
+                               expected: 'Dé Luain',
+                               description: 'Grammar test for ainmlae case'
+                       },
+                       {
+                               word: 'an Satharn',
+                               grammarForm: 'ainmlae',
+                               expected: 'Dé Sathairn',
+                               description: 'Grammar test for ainmlae case'
+                       }
+               ],
 
-       uk: [
-               {
-                       word: 'тесть',
-                       grammarForm: 'genitive',
-                       expected: 'тестя',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'Вікіпедія',
-                       grammarForm: 'genitive',
-                       expected: 'Вікіпедії',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'установка',
-                       grammarForm: 'genitive',
-                       expected: 'установки',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'похоти',
-                       grammarForm: 'genitive',
-                       expected: 'похотей',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'доводы',
-                       grammarForm: 'genitive',
-                       expected: 'доводов',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'песчаник',
-                       grammarForm: 'genitive',
-                       expected: 'песчаника',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'Вікіпедія',
-                       grammarForm: 'accusative',
-                       expected: 'Вікіпедію',
-                       description: 'Grammar test for accusative case'
-               }
-       ],
+               uk: [
+                       {
+                               word: 'тесть',
+                               grammarForm: 'genitive',
+                               expected: 'тестя',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'Вікіпедія',
+                               grammarForm: 'genitive',
+                               expected: 'Вікіпедії',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'установка',
+                               grammarForm: 'genitive',
+                               expected: 'установки',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'похоти',
+                               grammarForm: 'genitive',
+                               expected: 'похотей',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'доводы',
+                               grammarForm: 'genitive',
+                               expected: 'доводов',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'песчаник',
+                               grammarForm: 'genitive',
+                               expected: 'песчаника',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'Вікіпедія',
+                               grammarForm: 'accusative',
+                               expected: 'Вікіпедію',
+                               description: 'Grammar test for accusative case'
+                       }
+               ],
 
-       sl: [
-               {
-                       word: 'word',
-                       grammarForm: 'orodnik',
-                       expected: 'z word',
-                       description: 'Grammar test for orodnik case'
-               },
-               {
-                       word: 'word',
-                       grammarForm: 'mestnik',
-                       expected: 'o word',
-                       description: 'Grammar test for mestnik case'
-               }
-       ],
+               sl: [
+                       {
+                               word: 'word',
+                               grammarForm: 'orodnik',
+                               expected: 'z word',
+                               description: 'Grammar test for orodnik case'
+                       },
+                       {
+                               word: 'word',
+                               grammarForm: 'mestnik',
+                               expected: 'o word',
+                               description: 'Grammar test for mestnik case'
+                       }
+               ],
 
-       os: [
-               {
-                       word: 'бæстæ',
-                       grammarForm: 'genitive',
-                       expected: 'бæсты',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'бæстæ',
-                       grammarForm: 'allative',
-                       expected: 'бæстæм',
-                       description: 'Grammar test for allative case'
-               },
-               {
-                       word: 'Тигр',
-                       grammarForm: 'dative',
-                       expected: 'Тигрæн',
-                       description: 'Grammar test for dative case'
-               },
-               {
-                       word: 'цъити',
-                       grammarForm: 'dative',
-                       expected: 'цъитийæн',
-                       description: 'Grammar test for dative case'
-               },
-               {
-                       word: 'лæппу',
-                       grammarForm: 'genitive',
-                       expected: 'лæппуйы',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: '2011',
-                       grammarForm: 'equative',
-                       expected: '2011-ау',
-                       description: 'Grammar test for equative case'
-               }
-       ],
+               os: [
+                       {
+                               word: 'бæстæ',
+                               grammarForm: 'genitive',
+                               expected: 'бæсты',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'бæстæ',
+                               grammarForm: 'allative',
+                               expected: 'бæстæм',
+                               description: 'Grammar test for allative case'
+                       },
+                       {
+                               word: 'Тигр',
+                               grammarForm: 'dative',
+                               expected: 'Тигрæн',
+                               description: 'Grammar test for dative case'
+                       },
+                       {
+                               word: 'цъити',
+                               grammarForm: 'dative',
+                               expected: 'цъитийæн',
+                               description: 'Grammar test for dative case'
+                       },
+                       {
+                               word: 'лæппу',
+                               grammarForm: 'genitive',
+                               expected: 'лæппуйы',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: '2011',
+                               grammarForm: 'equative',
+                               expected: '2011-ау',
+                               description: 'Grammar test for equative case'
+                       }
+               ],
 
-       la: [
-               {
-                       word: 'Translatio',
-                       grammarForm: 'genitive',
-                       expected: 'Translationis',
-                       description: 'Grammar test for genitive case'
-               },
-               {
-                       word: 'Translatio',
-                       grammarForm: 'accusative',
-                       expected: 'Translationem',
-                       description: 'Grammar test for accusative case'
-               },
-               {
-                       word: 'Translatio',
-                       grammarForm: 'ablative',
-                       expected: 'Translatione',
-                       description: 'Grammar test for ablative case'
-               }
-       ]
-};
+               la: [
+                       {
+                               word: 'Translatio',
+                               grammarForm: 'genitive',
+                               expected: 'Translationis',
+                               description: 'Grammar test for genitive case'
+                       },
+                       {
+                               word: 'Translatio',
+                               grammarForm: 'accusative',
+                               expected: 'Translationem',
+                               description: 'Grammar test for accusative case'
+                       },
+                       {
+                               word: 'Translatio',
+                               grammarForm: 'ablative',
+                               expected: 'Translatione',
+                               description: 'Grammar test for ablative case'
+                       }
+               ]
+       };
 
-$.each( grammarTests, function ( langCode, test ) {
-       if ( langCode === mw.config.get( 'wgUserLanguage' ) ) {
-               grammarTest( langCode, test );
-       }
-});
+       $.each( grammarTests, function ( langCode, test ) {
+               if ( langCode === mw.config.get( 'wgUserLanguage' ) ) {
+                       grammarTest( langCode, test );
+               }
+       });
+}( mediaWiki, jQuery ) );
index be59f1a..9286558 100644 (file)
@@ -1,4 +1,4 @@
-( function ( mw ) {
+( function ( mw, $ ) {
 
 QUnit.module( 'mediawiki', QUnit.newMwEnvironment() );
 
@@ -215,7 +215,7 @@ QUnit.asyncTest( 'mw.loader', 2, function ( assert ) {
 
                // /sample/awesome.js declares the "mw.loader.testCallback" function
                // which contains a call to start() and ok()
-               assert.strictEqual( isAwesomeDone, true, "test.callback module should've caused isAwesomeDone to be true" );
+               assert.strictEqual( isAwesomeDone, true, 'test.callback module should\'ve caused isAwesomeDone to be true' );
                delete mw.loader.testCallback;
 
        }, function () {
@@ -481,8 +481,8 @@ QUnit.test( 'mw.loader missing dependency', 13, function ( assert ) {
        mw.loader.using(
                ['test.module7'],
                function () {
-                       assert.ok( false, "Success fired despite missing dependency" );
-                       assert.ok( true , "QUnit expected() count dummy" );
+                       assert.ok( false, 'Success fired despite missing dependency' );
+                       assert.ok( true , 'QUnit expected() count dummy' );
                },
                function ( e, dependencies ) {
                        assert.strictEqual( $.isArray( dependencies ), true, 'Expected array of dependencies' );
@@ -492,8 +492,8 @@ QUnit.test( 'mw.loader missing dependency', 13, function ( assert ) {
        mw.loader.using(
                ['test.module9'],
                function () {
-                       assert.ok( false, "Success fired despite missing dependency" );
-                       assert.ok( true , "QUnit expected() count dummy" );
+                       assert.ok( false, 'Success fired despite missing dependency' );
+                       assert.ok( true , 'QUnit expected() count dummy' );
                },
                function ( e, dependencies ) {
                        assert.strictEqual( $.isArray( dependencies ), true, 'Expected array of dependencies' );
@@ -646,4 +646,4 @@ QUnit.test( 'mw.html', 13, function ( assert ) {
 
 });
 
-}( mediaWiki ) );
+}( mediaWiki, jQuery ) );
index 16c97df..a9bbbf7 100644 (file)
@@ -1,4 +1,4 @@
-( function ( mw ) {
+( function ( mw, $ ) {
 
 QUnit.module( 'mediawiki.user', QUnit.newMwEnvironment() );
 
@@ -47,10 +47,9 @@ QUnit.asyncTest( 'getGroups', 3, function ( assert ) {
 
 QUnit.asyncTest( 'getRights', 1, function ( assert ) {
        mw.user.getRights( function ( rights ) {
-               // First group should always be '*'
                assert.equal( $.type( rights ), 'array', 'Callback gets an array' );
                QUnit.start();
        });
 });
 
-}( mediaWiki ) );
+}( mediaWiki, jQuery ) );
index ababa8d..c4212df 100644 (file)
-QUnit.module( 'mediawiki.util', QUnit.newMwEnvironment() );
-
-QUnit.test( 'rawurlencode', 1, function ( assert ) {
-       assert.equal( mw.util.rawurlencode( 'Test:A & B/Here' ), 'Test%3AA%20%26%20B%2FHere' );
-});
-
-QUnit.test( 'wikiUrlencode', 1, function ( assert ) {
-       assert.equal( mw.util.wikiUrlencode( 'Test:A & B/Here' ), 'Test:A_%26_B/Here' );
-});
-
-QUnit.test( 'wikiGetlink', 3, function ( assert ) {
-       // Not part of startUp module
-       mw.config.set( 'wgArticlePath', '/wiki/$1' );
-       mw.config.set( 'wgPageName', 'Foobar' );
-
-       var hrefA = mw.util.wikiGetlink( 'Sandbox' );
-       assert.equal( hrefA, '/wiki/Sandbox', 'Simple title; Get link for "Sandbox"' );
-
-       var hrefB = mw.util.wikiGetlink( 'Foo:Sandbox ? 5+5=10 ! (test)/subpage' );
-       assert.equal( hrefB, '/wiki/Foo:Sandbox_%3F_5%2B5%3D10_%21_%28test%29/subpage',
-               'Advanced title; Get link for "Foo:Sandbox ? 5+5=10 ! (test)/subpage"' );
-
-       var hrefC = mw.util.wikiGetlink();
-       assert.equal( hrefC, '/wiki/Foobar', 'Default title; Get link for current page ("Foobar")' );
-});
-
-QUnit.test( 'wikiScript', 4, function ( assert ) {
-       mw.config.set({
-               'wgScript': '/w/i.php', // customized wgScript for bug 39103
-               'wgLoadScript': '/w/l.php', // customized wgLoadScript for bug 39103
-               'wgScriptPath': '/w',
-               'wgScriptExtension': '.php'
+( function ( mw, $ ) {
+       QUnit.module( 'mediawiki.util', QUnit.newMwEnvironment() );
+
+       QUnit.test( 'rawurlencode', 1, function ( assert ) {
+               assert.equal( mw.util.rawurlencode( 'Test:A & B/Here' ), 'Test%3AA%20%26%20B%2FHere' );
+       });
+
+       QUnit.test( 'wikiUrlencode', 1, function ( assert ) {
+               assert.equal( mw.util.wikiUrlencode( 'Test:A & B/Here' ), 'Test:A_%26_B/Here' );
        });
 
-       assert.equal( mw.util.wikiScript(), mw.config.get( 'wgScript' ), 'wikiScript() returns wgScript' );
-       assert.equal( mw.util.wikiScript( 'index' ), mw.config.get( 'wgScript' ), "wikiScript( 'index' ) returns wgScript" );
-       assert.equal( mw.util.wikiScript( 'load' ), mw.config.get( 'wgLoadScript' ), "wikiScript( 'load' ) returns wgLoadScript" );
-       assert.equal( mw.util.wikiScript( 'api' ), '/w/api.php', 'API path' );
-});
-
-QUnit.test( 'addCSS', 3, function ( assert ) {
-       var $testEl = $( '<div>' ).attr( 'id', 'mw-addcsstest' ).appendTo( '#qunit-fixture' );
-
-       var style = mw.util.addCSS( '#mw-addcsstest { visibility: hidden; }' );
-       assert.equal( typeof style, 'object', 'addCSS returned an object' );
-       assert.strictEqual( style.disabled, false, 'property "disabled" is available and set to false' );
-
-       assert.equal( $testEl.css( 'visibility' ), 'hidden', 'Added style properties are in effect' );
-
-       // Clean up
-       $( style.ownerNode ).remove();
-});
-
-QUnit.asyncTest( 'toggleToc', 4, function ( assert ) {
-       assert.strictEqual( mw.util.toggleToc(), null, 'Return null if there is no table of contents on the page.' );
-
-       var     tocHtml =
-       '<table id="toc" class="toc"><tr><td>' +
-               '<div id="toctitle">' +
-                       '<h2>Contents</h2>' +
-                       '<span class="toctoggle">&nbsp;[<a href="#" class="internal" id="togglelink">Hide</a>&nbsp;]</span>' +
-               '</div>' +
-               '<ul><li></li></ul>' +
-       '</td></tr></table>',
-               $toc = $(tocHtml).appendTo( '#qunit-fixture' ),
+       QUnit.test( 'wikiGetlink', 3, function ( assert ) {
+               // Not part of startUp module
+               mw.config.set( 'wgArticlePath', '/wiki/$1' );
+               mw.config.set( 'wgPageName', 'Foobar' );
+
+               var href = mw.util.wikiGetlink( 'Sandbox' );
+               assert.equal( href, '/wiki/Sandbox', 'Simple title; Get link for "Sandbox"' );
+
+               href = mw.util.wikiGetlink( 'Foo:Sandbox ? 5+5=10 ! (test)/subpage' );
+               assert.equal( href, '/wiki/Foo:Sandbox_%3F_5%2B5%3D10_%21_%28test%29/subpage',
+                       'Advanced title; Get link for "Foo:Sandbox ? 5+5=10 ! (test)/subpage"' );
+
+               href = mw.util.wikiGetlink();
+               assert.equal( href, '/wiki/Foobar', 'Default title; Get link for current page ("Foobar")' );
+       });
+
+       QUnit.test( 'wikiScript', 4, function ( assert ) {
+               mw.config.set({
+                       'wgScript': '/w/i.php', // customized wgScript for bug 39103
+                       'wgLoadScript': '/w/l.php', // customized wgLoadScript for bug 39103
+                       'wgScriptPath': '/w',
+                       'wgScriptExtension': '.php'
+               });
+
+               assert.equal( mw.util.wikiScript(), mw.config.get( 'wgScript' ),
+                       'wikiScript() returns wgScript'
+               );
+               assert.equal( mw.util.wikiScript( 'index' ), mw.config.get( 'wgScript' ),
+                       'wikiScript( index ) returns wgScript'
+               );
+               assert.equal( mw.util.wikiScript( 'load' ), mw.config.get( 'wgLoadScript' ),
+                       'wikiScript( load ) returns wgLoadScript'
+               );
+               assert.equal( mw.util.wikiScript( 'api' ), '/w/api.php', 'API path' );
+       });
+
+       QUnit.test( 'addCSS', 3, function ( assert ) {
+               var $el, style;
+               $el = $( '<div>' ).attr( 'id', 'mw-addcsstest' ).appendTo( '#qunit-fixture' );
+
+               style = mw.util.addCSS( '#mw-addcsstest { visibility: hidden; }' );
+               assert.equal( typeof style, 'object', 'addCSS returned an object' );
+               assert.strictEqual( style.disabled, false, 'property "disabled" is available and set to false' );
+
+               assert.equal( $el.css( 'visibility' ), 'hidden', 'Added style properties are in effect' );
+
+               // Clean up
+               $( style.ownerNode ).remove();
+       });
+
+       QUnit.asyncTest( 'toggleToc', 4, function ( assert ) {
+               var tocHtml, $toggleLink;
+
+               function actionC() {
+                       QUnit.start();
+               }
+
+               function actionB() {
+                       assert.strictEqual( mw.util.toggleToc( $toggleLink, actionC ), true, 'Return boolean true if the TOC is now visible.' );
+               }
+
+               function actionA() {
+                       assert.strictEqual( mw.util.toggleToc( $toggleLink, actionB ), false, 'Return boolean false if the TOC is now hidden.' );
+               }
+
+               assert.strictEqual( mw.util.toggleToc(), null, 'Return null if there is no table of contents on the page.' );
+
+               tocHtml =
+                       '<table id="toc" class="toc"><tr><td>' +
+                               '<div id="toctitle">' +
+                                       '<h2>Contents</h2>' +
+                                       '<span class="toctoggle">&nbsp;[<a href="#" class="internal" id="togglelink">Hide</a>&nbsp;]</span>' +
+                               '</div>' +
+                               '<ul><li></li></ul>' +
+                       '</td></tr></table>';
+               $(tocHtml).appendTo( '#qunit-fixture' ),
                $toggleLink = $( '#togglelink' );
 
-       assert.strictEqual( $toggleLink.length, 1, 'Toggle link is appended to the page.' );
-
-       var actionC = function() {
-               QUnit.start();
-       };
-       var actionB = function() {
-               assert.strictEqual( mw.util.toggleToc( $toggleLink, actionC ), true, 'Return boolean true if the TOC is now visible.' );
-       };
-       var actionA = function() {
-               assert.strictEqual( mw.util.toggleToc( $toggleLink, actionB ), false, 'Return boolean false if the TOC is now hidden.' );
-       };
-
-       actionA();
-});
-
-QUnit.test( 'getParamValue', 5, function ( assert ) {
-       var     url1 = 'http://example.org/?foo=wrong&foo=right#&foo=bad';
-
-       assert.equal( mw.util.getParamValue( 'foo', url1 ), 'right', 'Use latest one, ignore hash' );
-       assert.strictEqual( mw.util.getParamValue( 'bar', url1 ), null, 'Return null when not found' );
-
-       var url2 = 'http://example.org/#&foo=bad';
-       assert.strictEqual( mw.util.getParamValue( 'foo', url2 ), null, 'Ignore hash if param is not in querystring but in hash (bug 27427)' );
-
-       var url3 = 'example.org?' + $.param({ 'TEST': 'a b+c' });
-       assert.strictEqual( mw.util.getParamValue( 'TEST', url3 ), 'a b+c', 'Bug 30441: getParamValue must understand "+" encoding of space' );
-
-       var url4 = 'example.org?' + $.param({ 'TEST': 'a b+c d' }); // check for sloppy code from r95332 :)
-       assert.strictEqual( mw.util.getParamValue( 'TEST', url4 ), 'a b+c d', 'Bug 30441: getParamValue must understand "+" encoding of space (multiple spaces)' );
-});
-
-QUnit.test( 'tooltipAccessKey', 3, function ( assert ) {
-       assert.equal( typeof mw.util.tooltipAccessKeyPrefix, 'string', 'mw.util.tooltipAccessKeyPrefix must be a string' );
-       assert.ok( mw.util.tooltipAccessKeyRegexp instanceof RegExp, 'mw.util.tooltipAccessKeyRegexp instance of RegExp' );
-       assert.ok( mw.util.updateTooltipAccessKeys, 'mw.util.updateTooltipAccessKeys' );
-});
-
-QUnit.test( '$content', 2, function ( assert ) {
-       assert.ok( mw.util.$content instanceof jQuery, 'mw.util.$content instance of jQuery' );
-       assert.strictEqual( mw.util.$content.length, 1, 'mw.util.$content must have length of 1' );
-});
-
-
-/**
- * Portlet names are prefixed with 'p-test' to avoid conflict with core
- * when running the test suite under a wiki page.
- * Previously, test elements where invisible to the selector since only
- * one element can have a given id.
- */
-QUnit.test( 'addPortletLink', 8, function ( assert ) {
-       var pTestTb, pCustom, vectorTabs, tbRL, cuQuux, $cuQuux, tbMW, $tbMW, tbRLDM, caFoo;
-       pTestTb = '\
-       <div class="portlet" id="p-test-tb">\
-               <h5>Toolbox</h5>\
-               <ul class="body"></ul>\
-       </div>';
-       pCustom = '\
-       <div class="portlet" id="p-test-custom">\
-               <h5>Views</h5>\
-               <ul class="body">\
-                       <li id="c-foo"><a href="#">Foo</a></li>\
-                       <li id="c-barmenu">\
-                               <ul>\
-                                       <li id="c-bar-baz"><a href="#">Baz</a></a>\
-                               </ul>\
-                       </li>\
-               </ul>\
-       </div>';
-       vectorTabs = '\
-       <div id="p-test-views" class="vectorTabs">\
-               <h5>Views</h5>\
-               <ul></ul>\
-       </div>';
-
-       $( '#qunit-fixture' ).append( pTestTb, pCustom, vectorTabs );
-
-       tbRL = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/wiki/ResourceLoader',
-               'ResourceLoader', 't-rl', 'More info about ResourceLoader on MediaWiki.org ', 'l' );
-
-       assert.ok( $.isDomElement( tbRL ), 'addPortletLink returns a valid DOM Element according to $.isDomElement' );
-
-       tbMW = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/',
-               'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', tbRL );
-       $tbMW = $( tbMW );
-
-
-       assert.equal( $tbMW.attr( 'id' ), 't-mworg', 'Link has correct ID set' );
-       assert.equal( $tbMW.closest( '.portlet' ).attr( 'id' ), 'p-test-tb', 'Link was inserted within correct portlet' );
-       assert.equal( $tbMW.next().attr( 'id' ), 't-rl', 'Link is in the correct position (by passing nextnode)' );
-
-       cuQuux = mw.util.addPortletLink( 'p-test-custom', '#', 'Quux' );
-       $cuQuux = $(cuQuux);
-
-       assert.equal(
-               $( '#p-test-custom #c-barmenu ul li' ).length,
-               1,
-               'addPortletLink did not add the item to all <ul> elements in the portlet (bug 35082)'
-       );
-
-       tbRLDM = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/wiki/RL/DM',
-               'Default modules', 't-rldm', 'List of all default modules ', 'd', '#t-rl' );
-
-       assert.equal( $( tbRLDM ).next().attr( 'id' ), 't-rl', 'Link is in the correct position (by passing CSS selector)' );
-
-       caFoo = mw.util.addPortletLink( 'p-test-views', '#', 'Foo' );
-
-       assert.strictEqual( $tbMW.find( 'span').length, 0, 'No <span> element should be added for porlets without vectorTabs class.' );
-       assert.strictEqual( $( caFoo ).find( 'span').length, 1, 'A <span> element should be added for porlets with vectorTabs class.' );
-});
-
-QUnit.test( 'jsMessage', 1, function ( assert ) {
-       var a = mw.util.jsMessage( "MediaWiki is <b>Awesome</b>." );
-       assert.ok( a, 'Basic checking of return value' );
-
-       // Clean up
-       $( '#mw-js-message' ).remove();
-});
-
-QUnit.test( 'validateEmail', 6, function ( assert ) {
-       assert.strictEqual( mw.util.validateEmail( "" ), null, 'Should return null for empty string ' );
-       assert.strictEqual( mw.util.validateEmail( "user@localhost" ), true, 'Return true for a valid e-mail address' );
-
-       // testEmailWithCommasAreInvalids
-       assert.strictEqual( mw.util.validateEmail( "user,foo@example.org" ), false, 'Emails with commas are invalid' );
-       assert.strictEqual( mw.util.validateEmail( "userfoo@ex,ample.org" ), false, 'Emails with commas are invalid' );
-
-       // testEmailWithHyphens
-       assert.strictEqual( mw.util.validateEmail( "user-foo@example.org" ), true, 'Emails may contain a hyphen' );
-       assert.strictEqual( mw.util.validateEmail( "userfoo@ex-ample.org" ), true, 'Emails may contain a hyphen' );
-});
-
-QUnit.test( 'isIPv6Address', 40, function ( assert ) {
-       // Shortcuts
-       function assertFalseIPv6( addy, summary ) {
-               return assert.strictEqual( mw.util.isIPv6Address( addy ), false, summary );
-       }
-       function assertTrueIPv6( addy, summary ) {
-               return assert.strictEqual( mw.util.isIPv6Address( addy ), true, summary );
-       }
-
-       // Based on IPTest.php > testisIPv6
-       assertFalseIPv6( ':fc:100::', 'IPv6 starting with lone ":"' );
-       assertFalseIPv6( 'fc:100:::', 'IPv6 ending with a ":::"' );
-       assertFalseIPv6( 'fc:300', 'IPv6 with only 2 words' );
-       assertFalseIPv6( 'fc:100:300', 'IPv6 with only 3 words' );
-
-       $.each(
-       ['fc:100::',
-       'fc:100:a::',
-       'fc:100:a:d::',
-       'fc:100:a:d:1::',
-       'fc:100:a:d:1:e::',
-       'fc:100:a:d:1:e:ac::'], function ( i, addy ){
-               assertTrueIPv6( addy, addy + ' is a valid IP' );
+               assert.strictEqual( $toggleLink.length, 1, 'Toggle link is appended to the page.' );
+
+               actionA();
        });
 
-       assertFalseIPv6( 'fc:100:a:d:1:e:ac:0::', 'IPv6 with 8 words ending with "::"' );
-       assertFalseIPv6( 'fc:100:a:d:1:e:ac:0:1::', 'IPv6 with 9 words ending with "::"' );
-
-       assertFalseIPv6( ':::' );
-       assertFalseIPv6( '::0:', 'IPv6 ending in a lone ":"' );
-
-       assertTrueIPv6( '::', 'IPv6 zero address' );
-       $.each(
-       ['::0',
-       '::fc',
-       '::fc:100',
-       '::fc:100:a',
-       '::fc:100:a:d',
-       '::fc:100:a:d:1',
-       '::fc:100:a:d:1:e',
-       '::fc:100:a:d:1:e:ac',
-
-       'fc:100:a:d:1:e:ac:0'], function ( i, addy ){
-               assertTrueIPv6( addy, addy + ' is a valid IP' );
+       QUnit.test( 'getParamValue', 5, function ( assert ) {
+               var     url;
+
+               url = 'http://example.org/?foo=wrong&foo=right#&foo=bad';
+               assert.equal( mw.util.getParamValue( 'foo', url ), 'right', 'Use latest one, ignore hash' );
+               assert.strictEqual( mw.util.getParamValue( 'bar', url ), null, 'Return null when not found' );
+
+               url = 'http://example.org/#&foo=bad';
+               assert.strictEqual( mw.util.getParamValue( 'foo', url ), null, 'Ignore hash if param is not in querystring but in hash (bug 27427)' );
+
+               url = 'example.org?' + $.param({ 'TEST': 'a b+c' });
+               assert.strictEqual( mw.util.getParamValue( 'TEST', url ), 'a b+c', 'Bug 30441: getParamValue must understand "+" encoding of space' );
+
+               url = 'example.org?' + $.param({ 'TEST': 'a b+c d' }); // check for sloppy code from r95332 :)
+               assert.strictEqual( mw.util.getParamValue( 'TEST', url ), 'a b+c d', 'Bug 30441: getParamValue must understand "+" encoding of space (multiple spaces)' );
+       });
+
+       QUnit.test( 'tooltipAccessKey', 3, function ( assert ) {
+               assert.equal( typeof mw.util.tooltipAccessKeyPrefix, 'string', 'mw.util.tooltipAccessKeyPrefix must be a string' );
+               assert.ok( mw.util.tooltipAccessKeyRegexp instanceof RegExp, 'mw.util.tooltipAccessKeyRegexp instance of RegExp' );
+               assert.ok( mw.util.updateTooltipAccessKeys, 'mw.util.updateTooltipAccessKeys' );
+       });
+
+       QUnit.test( '$content', 2, function ( assert ) {
+               assert.ok( mw.util.$content instanceof jQuery, 'mw.util.$content instance of jQuery' );
+               assert.strictEqual( mw.util.$content.length, 1, 'mw.util.$content must have length of 1' );
+       });
+
+
+       /**
+        * Portlet names are prefixed with 'p-test' to avoid conflict with core
+        * when running the test suite under a wiki page.
+        * Previously, test elements where invisible to the selector since only
+        * one element can have a given id.
+        */
+       QUnit.test( 'addPortletLink', 8, function ( assert ) {
+               var pTestTb, pCustom, vectorTabs, tbRL, cuQuux, $cuQuux, tbMW, $tbMW, tbRLDM, caFoo;
+
+               pTestTb = '\
+               <div class="portlet" id="p-test-tb">\
+                       <h5>Toolbox</h5>\
+                       <ul class="body"></ul>\
+               </div>';
+               pCustom = '\
+               <div class="portlet" id="p-test-custom">\
+                       <h5>Views</h5>\
+                       <ul class="body">\
+                               <li id="c-foo"><a href="#">Foo</a></li>\
+                               <li id="c-barmenu">\
+                                       <ul>\
+                                               <li id="c-bar-baz"><a href="#">Baz</a></a>\
+                                       </ul>\
+                               </li>\
+                       </ul>\
+               </div>';
+               vectorTabs = '\
+               <div id="p-test-views" class="vectorTabs">\
+                       <h5>Views</h5>\
+                       <ul></ul>\
+               </div>';
+
+               $( '#qunit-fixture' ).append( pTestTb, pCustom, vectorTabs );
+
+               tbRL = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/wiki/ResourceLoader',
+                       'ResourceLoader', 't-rl', 'More info about ResourceLoader on MediaWiki.org ', 'l' );
+
+               assert.ok( $.isDomElement( tbRL ), 'addPortletLink returns a valid DOM Element according to $.isDomElement' );
+
+               tbMW = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/',
+                       'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', tbRL );
+               $tbMW = $( tbMW );
+
+
+               assert.equal( $tbMW.attr( 'id' ), 't-mworg', 'Link has correct ID set' );
+               assert.equal( $tbMW.closest( '.portlet' ).attr( 'id' ), 'p-test-tb', 'Link was inserted within correct portlet' );
+               assert.equal( $tbMW.next().attr( 'id' ), 't-rl', 'Link is in the correct position (by passing nextnode)' );
+
+               cuQuux = mw.util.addPortletLink( 'p-test-custom', '#', 'Quux' );
+               $cuQuux = $(cuQuux);
+
+               assert.equal(
+                       $( '#p-test-custom #c-barmenu ul li' ).length,
+                       1,
+                       'addPortletLink did not add the item to all <ul> elements in the portlet (bug 35082)'
+               );
+
+               tbRLDM = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/wiki/RL/DM',
+                       'Default modules', 't-rldm', 'List of all default modules ', 'd', '#t-rl' );
+
+               assert.equal( $( tbRLDM ).next().attr( 'id' ), 't-rl', 'Link is in the correct position (by passing CSS selector)' );
+
+               caFoo = mw.util.addPortletLink( 'p-test-views', '#', 'Foo' );
+
+               assert.strictEqual( $tbMW.find( 'span').length, 0, 'No <span> element should be added for porlets without vectorTabs class.' );
+               assert.strictEqual( $( caFoo ).find( 'span').length, 1, 'A <span> element should be added for porlets with vectorTabs class.' );
        });
 
-       assertFalseIPv6( '::fc:100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words' );
-       assertFalseIPv6( '::fc:100:a:d:1:e:ac:0:1', 'IPv6 with 9 words' );
-
-       assertFalseIPv6( ':fc::100', 'IPv6 starting with lone ":"' );
-       assertFalseIPv6( 'fc::100:', 'IPv6 ending with lone ":"' );
-       assertFalseIPv6( 'fc:::100', 'IPv6 with ":::" in the middle' );
-
-       assertTrueIPv6( 'fc::100', 'IPv6 with "::" and 2 words' );
-       assertTrueIPv6( 'fc::100:a', 'IPv6 with "::" and 3 words' );
-       assertTrueIPv6( 'fc::100:a:d', 'IPv6 with "::" and 4 words' );
-       assertTrueIPv6( 'fc::100:a:d:1', 'IPv6 with "::" and 5 words' );
-       assertTrueIPv6( 'fc::100:a:d:1:e', 'IPv6 with "::" and 6 words' );
-       assertTrueIPv6( 'fc::100:a:d:1:e:ac', 'IPv6 with "::" and 7 words' );
-       assertTrueIPv6( '2001::df', 'IPv6 with "::" and 2 words' );
-       assertTrueIPv6( '2001:5c0:1400:a::df', 'IPv6 with "::" and 5 words' );
-       assertTrueIPv6( '2001:5c0:1400:a::df:2', 'IPv6 with "::" and 6 words' );
-
-       assertFalseIPv6( 'fc::100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words' );
-       assertFalseIPv6( 'fc::100:a:d:1:e:ac:0:1', 'IPv6 with 9 words' );
-});
-
-QUnit.test( 'isIPv4Address', 11, function ( assert ) {
-       // Shortcuts
-       function assertFalseIPv4( addy, summary ) {
-               assert.strictEqual( mw.util.isIPv4Address( addy ), false, summary );
-       }
-       function assertTrueIPv4( addy, summary ) {
-               assert.strictEqual( mw.util.isIPv4Address( addy ), true, summary );
-       }
-
-       // Based on IPTest.php > testisIPv4
-       assertFalseIPv4( false, 'Boolean false is not an IP' );
-       assertFalseIPv4( true, 'Boolean true is not an IP' );
-       assertFalseIPv4( '', 'Empty string is not an IP' );
-       assertFalseIPv4( 'abc', '"abc" is not an IP' );
-       assertFalseIPv4( ':', 'Colon is not an IP' );
-       assertFalseIPv4( '124.24.52', 'IPv4 not enough quads' );
-       assertFalseIPv4( '24.324.52.13', 'IPv4 out of range' );
-       assertFalseIPv4( '.24.52.13', 'IPv4 starts with period' );
-
-       assertTrueIPv4( '124.24.52.13', '124.24.52.134 is a valid IP' );
-       assertTrueIPv4( '1.24.52.13', '1.24.52.13 is a valid IP' );
-       assertFalseIPv4( '74.24.52.13/20', 'IPv4 ranges are not recogzized as valid IPs' );
-});
+       QUnit.test( 'jsMessage', 1, function ( assert ) {
+               var a = mw.util.jsMessage( 'MediaWiki is <b>Awesome</b>.' );
+               assert.ok( a, 'Basic checking of return value' );
+
+               // Clean up
+               $( '#mw-js-message' ).remove();
+       });
+
+       QUnit.test( 'validateEmail', 6, function ( assert ) {
+               assert.strictEqual( mw.util.validateEmail( '' ), null, 'Should return null for empty string ' );
+               assert.strictEqual( mw.util.validateEmail( 'user@localhost' ), true, 'Return true for a valid e-mail address' );
+
+               // testEmailWithCommasAreInvalids
+               assert.strictEqual( mw.util.validateEmail( 'user,foo@example.org' ), false, 'Emails with commas are invalid' );
+               assert.strictEqual( mw.util.validateEmail( 'userfoo@ex,ample.org' ), false, 'Emails with commas are invalid' );
+
+               // testEmailWithHyphens
+               assert.strictEqual( mw.util.validateEmail( 'user-foo@example.org' ), true, 'Emails may contain a hyphen' );
+               assert.strictEqual( mw.util.validateEmail( 'userfoo@ex-ample.org' ), true, 'Emails may contain a hyphen' );
+       });
+
+       QUnit.test( 'isIPv6Address', 40, function ( assert ) {
+               // Shortcuts
+               function assertFalseIPv6( addy, summary ) {
+                       return assert.strictEqual( mw.util.isIPv6Address( addy ), false, summary );
+               }
+               function assertTrueIPv6( addy, summary ) {
+                       return assert.strictEqual( mw.util.isIPv6Address( addy ), true, summary );
+               }
+
+               // Based on IPTest.php > testisIPv6
+               assertFalseIPv6( ':fc:100::', 'IPv6 starting with lone ":"' );
+               assertFalseIPv6( 'fc:100:::', 'IPv6 ending with a ":::"' );
+               assertFalseIPv6( 'fc:300', 'IPv6 with only 2 words' );
+               assertFalseIPv6( 'fc:100:300', 'IPv6 with only 3 words' );
+
+               $.each(
+               ['fc:100::',
+               'fc:100:a::',
+               'fc:100:a:d::',
+               'fc:100:a:d:1::',
+               'fc:100:a:d:1:e::',
+               'fc:100:a:d:1:e:ac::'], function ( i, addy ){
+                       assertTrueIPv6( addy, addy + ' is a valid IP' );
+               });
+
+               assertFalseIPv6( 'fc:100:a:d:1:e:ac:0::', 'IPv6 with 8 words ending with "::"' );
+               assertFalseIPv6( 'fc:100:a:d:1:e:ac:0:1::', 'IPv6 with 9 words ending with "::"' );
+
+               assertFalseIPv6( ':::' );
+               assertFalseIPv6( '::0:', 'IPv6 ending in a lone ":"' );
+
+               assertTrueIPv6( '::', 'IPv6 zero address' );
+               $.each(
+               ['::0',
+               '::fc',
+               '::fc:100',
+               '::fc:100:a',
+               '::fc:100:a:d',
+               '::fc:100:a:d:1',
+               '::fc:100:a:d:1:e',
+               '::fc:100:a:d:1:e:ac',
+
+               'fc:100:a:d:1:e:ac:0'], function ( i, addy ){
+                       assertTrueIPv6( addy, addy + ' is a valid IP' );
+               });
+
+               assertFalseIPv6( '::fc:100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words' );
+               assertFalseIPv6( '::fc:100:a:d:1:e:ac:0:1', 'IPv6 with 9 words' );
+
+               assertFalseIPv6( ':fc::100', 'IPv6 starting with lone ":"' );
+               assertFalseIPv6( 'fc::100:', 'IPv6 ending with lone ":"' );
+               assertFalseIPv6( 'fc:::100', 'IPv6 with ":::" in the middle' );
+
+               assertTrueIPv6( 'fc::100', 'IPv6 with "::" and 2 words' );
+               assertTrueIPv6( 'fc::100:a', 'IPv6 with "::" and 3 words' );
+               assertTrueIPv6( 'fc::100:a:d', 'IPv6 with "::" and 4 words' );
+               assertTrueIPv6( 'fc::100:a:d:1', 'IPv6 with "::" and 5 words' );
+               assertTrueIPv6( 'fc::100:a:d:1:e', 'IPv6 with "::" and 6 words' );
+               assertTrueIPv6( 'fc::100:a:d:1:e:ac', 'IPv6 with "::" and 7 words' );
+               assertTrueIPv6( '2001::df', 'IPv6 with "::" and 2 words' );
+               assertTrueIPv6( '2001:5c0:1400:a::df', 'IPv6 with "::" and 5 words' );
+               assertTrueIPv6( '2001:5c0:1400:a::df:2', 'IPv6 with "::" and 6 words' );
+
+               assertFalseIPv6( 'fc::100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words' );
+               assertFalseIPv6( 'fc::100:a:d:1:e:ac:0:1', 'IPv6 with 9 words' );
+       });
+
+       QUnit.test( 'isIPv4Address', 11, function ( assert ) {
+               // Shortcuts
+               function assertFalseIPv4( addy, summary ) {
+                       assert.strictEqual( mw.util.isIPv4Address( addy ), false, summary );
+               }
+               function assertTrueIPv4( addy, summary ) {
+                       assert.strictEqual( mw.util.isIPv4Address( addy ), true, summary );
+               }
+
+               // Based on IPTest.php > testisIPv4
+               assertFalseIPv4( false, 'Boolean false is not an IP' );
+               assertFalseIPv4( true, 'Boolean true is not an IP' );
+               assertFalseIPv4( '', 'Empty string is not an IP' );
+               assertFalseIPv4( 'abc', '"abc" is not an IP' );
+               assertFalseIPv4( ':', 'Colon is not an IP' );
+               assertFalseIPv4( '124.24.52', 'IPv4 not enough quads' );
+               assertFalseIPv4( '24.324.52.13', 'IPv4 out of range' );
+               assertFalseIPv4( '.24.52.13', 'IPv4 starts with period' );
+
+               assertTrueIPv4( '124.24.52.13', '124.24.52.134 is a valid IP' );
+               assertTrueIPv4( '1.24.52.13', '1.24.52.13 is a valid IP' );
+               assertFalseIPv4( '74.24.52.13/20', 'IPv4 ranges are not recogzized as valid IPs' );
+       });
+}( mediaWiki, jQuery ) );
index b0d72f3..15fbf07 100644 (file)
--- a/thumb.php
+++ b/thumb.php
@@ -38,6 +38,7 @@ if ( defined( 'THUMB_HANDLER' ) ) {
        // Called directly, use $_REQUEST params
        wfThumbHandleRequest();
 }
+
 wfLogProfilingData();
 
 //--------------------------------------------------------------------------
@@ -61,28 +62,21 @@ function wfThumbHandleRequest() {
  * @return void
  */
 function wfThumbHandle404() {
-       # lighttpd puts the original request in REQUEST_URI, while sjs sets
-       # that to the 404 handler, and puts the original request in REDIRECT_URL.
-       if ( isset( $_SERVER['REDIRECT_URL'] ) ) {
-               # The URL is un-encoded, so put it back how it was
-               $uriPath = str_replace( "%2F", "/", urlencode( $_SERVER['REDIRECT_URL'] ) );
-       } else {
-               $uriPath = $_SERVER['REQUEST_URI'];
-       }
-       # Just get the URI path (REDIRECT_URL/REQUEST_URI is either a full URL or a path)
-       if ( substr( $uriPath, 0, 1 ) !== '/' ) {
-               $bits = wfParseUrl( $uriPath );
-               if ( $bits && isset( $bits['path'] ) ) {
-                       $uriPath = $bits['path'];
-               } else {
-                       wfThumbError( 404, 'The source file for the specified thumbnail does not exist.' );
-                       return;
-               }
+       global $wgArticlePath;
+
+       # Set action base paths so that WebRequest::getPathInfo()
+       # recognizes the "X" as the 'title' in ../thumb_handler.php/X urls.
+       $wgArticlePath = false; # Don't let a "/*" article path clober our action path
+
+       $matches = WebRequest::getPathInfo();
+       if ( !isset( $matches['title'] ) ) {
+               wfThumbError( 404, 'Could not determine the name of the requested thumbnail.' );
+               return;
        }
 
-       $params = wfExtractThumbParams( $uriPath ); // basic wiki URL param extracting
+       $params = wfExtractThumbParams( $matches['title'] ); // basic wiki URL param extracting
        if ( $params == null ) {
-               wfThumbError( 404, 'The source file for the specified thumbnail does not exist.' );
+               wfThumbError( 400, 'The specified thumbnail parameters are not recognized.' );
                return;
        }
 
@@ -299,43 +293,28 @@ function wfStreamThumb( array $params ) {
  * Extract the required params for thumb.php from the thumbnail request URI.
  * At least 'width' and 'f' should be set if the result is an array.
  *
- * @param $uriPath String Thumbnail request URI path
+ * @param $thumbRel String Thumbnail path relative to the thumb zone
  * @return Array|null associative params array or null
  */
-function wfExtractThumbParams( $uriPath ) {
+function wfExtractThumbParams( $thumbRel ) {
        $repo = RepoGroup::singleton()->getLocalRepo();
 
-       // Zone URL might be relative ("/images") or protocol-relative ("//lang.site/image")
-       $zoneUriPath = $repo->getZoneHandlerUrl( 'thumb' )
-               ? $repo->getZoneHandlerUrl( 'thumb' ) // custom URL
-               : $repo->getZoneUrl( 'thumb' ); // default to main URL
-       $bits = wfParseUrl( wfExpandUrl( $zoneUriPath, PROTO_INTERNAL ) );
-       if ( $bits && isset( $bits['path'] ) ) {
-               $zoneUriPath = $bits['path'];
-       } else {
-               return null; // not a valid thumbnail URL
-       }
-
        $hashDirReg = $subdirReg = '';
        for ( $i = 0; $i < $repo->getHashLevels(); $i++ ) {
                $subdirReg .= '[0-9a-f]';
                $hashDirReg .= "$subdirReg/";
        }
-       $zoneReg = preg_quote( $zoneUriPath ); // regex for thumb zone URI
 
        // Check if this is a thumbnail of an original in the local file repo
-       if ( preg_match( "!^$zoneReg/((archive/)?$hashDirReg([^/]*)/([^/]*))$!", $uriPath, $m ) ) {
+       if ( preg_match( "!^((archive/)?$hashDirReg([^/]*)/([^/]*))$!", $thumbRel, $m ) ) {
                list( /*all*/, $rel, $archOrTemp, $filename, $thumbname ) = $m;
        // Check if this is a thumbnail of an temp file in the local file repo
-       } elseif ( preg_match( "!^$zoneReg/(temp/)($hashDirReg([^/]*)/([^/]*))$!", $uriPath, $m ) ) {
+       } elseif ( preg_match( "!^(temp/)($hashDirReg([^/]*)/([^/]*))$!", $thumbRel, $m ) ) {
                list( /*all*/, $archOrTemp, $rel, $filename, $thumbname ) = $m;
        } else {
                return null; // not a valid looking thumbnail request
        }
 
-       $filename = urldecode( $filename );
-       $thumbname = urldecode( $thumbname );
-
        $params = array( 'f' => $filename, 'rel404' => $rel );
        if ( $archOrTemp === 'archive/' ) {
                $params['archived'] = 1;