Merge "Remove a bunch of trailing spaces and unneeded newlines"
authorMaxSem <maxsem.wiki@gmail.com>
Fri, 12 Oct 2012 18:36:46 +0000 (18:36 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 12 Oct 2012 18:36:46 +0000 (18:36 +0000)
109 files changed:
RELEASE-NOTES-1.21
docs/contenthandler.txt
docs/hooks.txt
includes/AutoLoader.php
includes/DefaultSettings.php
includes/Defines.php
includes/EditPage.php
includes/Html.php
includes/Linker.php
includes/OutputPage.php
includes/Title.php
includes/User.php
includes/WikiPage.php
includes/actions/InfoAction.php
includes/api/ApiUpload.php
includes/content/TextContent.php
includes/db/IORMTable.php
includes/db/ORMTable.php
includes/diff/DifferenceEngine.php
includes/installer/MysqlUpdater.php
includes/installer/OracleInstaller.php
includes/installer/OracleUpdater.php
includes/installer/PostgresUpdater.php
includes/installer/SqliteUpdater.php
includes/media/MediaTransformOutput.php
includes/site/MediaWikiSite.php [new file with mode: 0644]
includes/site/Site.php [new file with mode: 0644]
includes/site/SiteArray.php [new file with mode: 0644]
includes/site/SiteList.php [new file with mode: 0644]
includes/site/SiteObject.php [new file with mode: 0644]
includes/site/Sites.php [new file with mode: 0644]
includes/site/SitesTable.php [new file with mode: 0644]
languages/LanguageConverter.php
languages/classes/LanguageGan.php
languages/classes/LanguageIu.php
languages/classes/LanguageKk.php
languages/classes/LanguageKu.php
languages/classes/LanguageShi.php
languages/classes/LanguageSr.php
languages/classes/LanguageUz.php
languages/classes/LanguageZh.php
languages/messages/MessagesArc.php
languages/messages/MessagesCa.php
languages/messages/MessagesCs.php
languages/messages/MessagesDe.php
languages/messages/MessagesDiq.php
languages/messages/MessagesDsb.php
languages/messages/MessagesFi.php
languages/messages/MessagesFr.php
languages/messages/MessagesGl.php
languages/messages/MessagesGu.php
languages/messages/MessagesHe.php
languages/messages/MessagesHsb.php
languages/messages/MessagesIt.php
languages/messages/MessagesJa.php
languages/messages/MessagesKab.php
languages/messages/MessagesKo.php
languages/messages/MessagesMg.php
languages/messages/MessagesMk.php
languages/messages/MessagesMl.php
languages/messages/MessagesMs.php
languages/messages/MessagesNl.php
languages/messages/MessagesNn.php
languages/messages/MessagesPms.php
languages/messages/MessagesQqq.php
languages/messages/MessagesRo.php
languages/messages/MessagesSa.php
languages/messages/MessagesSi.php
languages/messages/MessagesSk.php
languages/messages/MessagesSl.php
languages/messages/MessagesSv.php
languages/messages/MessagesTg_cyrl.php
languages/messages/MessagesUg_arab.php
languages/messages/MessagesUz.php
languages/messages/MessagesYi.php
languages/messages/MessagesZh_hant.php
maintenance/archives/patch-sites.sql [new file with mode: 0644]
maintenance/findHooks.php
maintenance/oracle/archives/patch-archive-ar_content_format.sql [new file with mode: 0644]
maintenance/oracle/archives/patch-archive-ar_content_model.sql [new file with mode: 0644]
maintenance/oracle/archives/patch-cat_hidden.sql [new file with mode: 0644]
maintenance/oracle/archives/patch-page-page_content_model.sql [new file with mode: 0644]
maintenance/oracle/archives/patch-rc_moved.sql [new file with mode: 0644]
maintenance/oracle/archives/patch-revision-rev_content_format.sql [new file with mode: 0644]
maintenance/oracle/archives/patch-revision-rev_content_model.sql [new file with mode: 0644]
maintenance/oracle/archives/patch-ss_admins.sql [new file with mode: 0644]
maintenance/oracle/tables.sql
maintenance/postgres/tables.sql
maintenance/sqlite/archives/patch-sites.sql [new file with mode: 0644]
maintenance/tables.sql
resources/Resources.php
resources/jquery/jquery.hidpi.js [new file with mode: 0644]
resources/mediawiki/mediawiki.hidpi.js [new file with mode: 0644]
tests/parser/parserTest.inc
tests/parser/parserTests.txt
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/TitlePermissionTest.php
tests/phpunit/includes/libs/GenericArrayObjectTest.php
tests/phpunit/includes/parser/NewParserTest.php
tests/phpunit/includes/search/SearchEngineTest.php
tests/phpunit/includes/site/MediaWikiSiteTest.php [new file with mode: 0644]
tests/phpunit/includes/site/SiteArrayTest.php [new file with mode: 0644]
tests/phpunit/includes/site/SiteListTest.php [new file with mode: 0644]
tests/phpunit/includes/site/SiteObjectTest.php [new file with mode: 0644]
tests/phpunit/includes/site/SitesTest.php [new file with mode: 0644]
tests/phpunit/includes/site/TestSites.php [new file with mode: 0644]
tests/qunit/QUnitTestResources.php
tests/qunit/suites/resources/jquery/jquery.hidpi.test.js [new file with mode: 0644]
thumb.php

index a1fa4ca..987d645 100644 (file)
@@ -19,6 +19,8 @@ production.
 * (bug 34876) jquery.makeCollapsible has been improved in performance.
 * Added ContentHandler facility to allow extensions to support other content than wikitext.
   See docs/contenthandler.txt for details.
+* $wgResponsiveImages is added to support images on high-DPI mobile and desktop displays.
+* Added new backend to represent and store information about sites and site specific configuration.
 
 === Bug fixes in 1.21 ===
 * (bug 40353) SpecialDoubleRedirect should support interwiki redirects.
index 3561432..5a63460 100644 (file)
@@ -115,9 +115,9 @@ Besides some functions, some hooks have also been replaced by new versions (see
 These hooks will now trigger a warning when used:
 
 * ArticleAfterFetchContent was replaced by ArticleAfterFetchContentObject
-* ArticleInsertComplete was replaced by ArticleContentInsertComplete
-* ArticleSave was replaced by ArticleContentSave
-* ArticleSaveComplete was replaced by ArticleContentSaveComplete
+* ArticleInsertComplete was replaced by PageContentInsertComplete
+* ArticleSave was replaced by PageContentSave
+* ArticleSaveComplete was replaced by PageContentSaveComplete
 * ArticleViewCustom was replaced by ArticleContentViewCustom (also consider a custom implementation of the view action)
 * EditFilterMerged was replaced by EditFilterMergedContent
 * EditPageGetDiffText was replaced by EditPageGetDiffContent
index a4b4e57..10a341d 100644 (file)
@@ -491,7 +491,7 @@ Wiki::articleFromTitle()
 $title: title (object) used to create the article object
 $article: article (object) that will be returned
 
-'ArticleInsertComplete': After a new article is created. DEPRECATED, use ArticleContentInsertComplete
+'ArticleInsertComplete': After a new article is created. DEPRECATED, use PageContentInsertComplete
 $article: WikiPage created
 $user: User creating the article
 $text: New content
@@ -502,7 +502,7 @@ $section: (No longer used)
 $flags: Flags passed to WikiPage::doEditContent()
 $revision: New Revision of the article
 
-'ArticleContentInsertComplete': After a new article is created
+'PageContentInsertComplete': After a new article is created
 $article: WikiPage created
 $user: User creating the article
 $content: New content as a Content object
@@ -561,7 +561,7 @@ $user: the user who did the rollback
 $revision: the revision the page was reverted back to
 $current: the reverted revision
 
-'ArticleSave': before an article is saved. DEPRECATED, use ArticleContentSave instead
+'ArticleSave': before an article is saved. DEPRECATED, use PageContentSave instead
 $article: the WikiPage (object) being saved
 $user: the user (object) saving the article
 $text: the new article text
@@ -570,7 +570,7 @@ $isminor: minor flag
 $iswatch: watch flag
 $section: section #
 
-'ArticleContentSave': before an article is saved.
+'PageContentSave': before an article is saved.
 $article: the WikiPage (object) being saved
 $user: the user (object) saving the article
 $content: the new article content, as a Content object
@@ -579,7 +579,7 @@ $isminor: minor flag
 $iswatch: watch flag
 $section: section #
 
-'ArticleSaveComplete': After an article has been updated. DEPRECATED, use ArticleContentSaveComplete instead.
+'ArticleSaveComplete': After an article has been updated. DEPRECATED, use PageContentSaveComplete instead.
 $article: WikiPage modified
 $user: User performing the modification
 $text: New content
@@ -592,7 +592,7 @@ $revision: New Revision of the article
 $status: Status object about to be returned by doEditContent()
 $baseRevId: the rev ID (or false) this edit was based on
 
-'ArticleContentSaveComplete': After an article has been updated
+'PageContentSaveComplete': After an article has been updated
 $article: WikiPage modified
 $user: User performing the modification
 $content: New content, as a Content object
@@ -1223,6 +1223,10 @@ $reader: XMLReader object
 $revisionInfo: Array of information
 Return false to stop further processing of the tag
 
+'InfoAction': When building information to display on the action=info page
+$context: IContextSource object
+&$pageInfo: Array of information
+
 'InitializeArticleMaybeRedirect': MediaWiki check to see if title is a redirect
 $title: Title object ($wgTitle)
 $request: WebRequest
index 7deeec0..e8df8d4 100644 (file)
@@ -874,6 +874,15 @@ $wgAutoloadLocalClasses = array(
        'SqliteSearchResultSet' => 'includes/search/SearchSqlite.php',
        'SqlSearchResultSet' => 'includes/search/SearchEngine.php',
 
+       # includes/site
+       'MediaWikiSite' => 'includes/site/MediaWikiSite.php',
+       'Site' => 'includes/site/Site.php',
+       'SiteArray' => 'includes/site/SiteArray.php',
+       'SiteList' => 'includes/site/SiteList.php',
+       'SiteObject' => 'includes/site/SiteObject.php',
+       'Sites' => 'includes/site/Sites.php',
+       'SitesTable' => 'includes/site/SitesTable.php',
+
        # includes/specials
        'ActiveUsersPager' => 'includes/specials/SpecialActiveusers.php',
        'AllmessagesTablePager' => 'includes/specials/SpecialAllmessages.php',
@@ -1092,6 +1101,10 @@ $wgAutoloadLocalClasses = array(
        # 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',
index 2e1e82f..159ed29 100644 (file)
@@ -1088,6 +1088,16 @@ $wgThumbUpright = 0.75;
  */
 $wgDirectoryMode = 0777;
 
+/**
+ * Generate and use thumbnails suitable for screens with 1.5 and 2.0 pixel densities.
+ *
+ * This means a 320x240 use of an image on the wiki will also generate 480x360 and 640x480
+ * thumbnails, output via data-src-1-5 and data-src-2-0. Runtime JavaScript switches the
+ * images in after loading the original low-resolution versions depending on the reported
+ * window.devicePixelRatio.
+ */
+$wgResponsiveImages = true;
+
 /**
  * @name DJVU settings
  * @{
@@ -6283,6 +6293,14 @@ $wgContentHandlerUseDB = true;
  */
 $wgRequirePasswordforEmailChange = true;
 
+/**
+ * Register handlers for specific types of sites.
+ *
+ * @since 1.20
+ */
+$wgSiteTypes = array();
+$wgSiteTypes['mediawiki'] = 'MediaWikiSite';
+
 /**
  * For really cool vim folding this needs to be at the end:
  * vim: foldmarker=@{,@} foldmethod=marker
index 1bcb058..2ddd053 100644 (file)
@@ -213,6 +213,7 @@ require_once __DIR__.'/normal/UtfNormalDefines.php';
 define( 'MW_SUPPORTS_EDITFILTERMERGED', 1 );
 define( 'MW_SUPPORTS_PARSERFIRSTCALLINIT', 1 );
 define( 'MW_SUPPORTS_LOCALISATIONCACHE', 1 );
+define( 'MW_SUPPORTS_CONTENTHANDLER', 1 );
 /**@}*/
 
 /** Support for $wgResourceModules */
index 35328f8..f2bab7d 100644 (file)
@@ -1007,7 +1007,7 @@ class EditPage {
         * @since 1.21
         */
        public function setPreloadedContent( Content $content ) {
-               $this->mPreloadedContent = $content;
+               $this->mPreloadContent = $content;
        }
 
        /**
@@ -1921,13 +1921,18 @@ class EditPage {
         * an exception will be raised. Set $this->allowNonTextContent to true to allow editing of non-textual
         * content.
         *
-        * @param String $text Text to unserialize
-        * @return Content the content object created from $text
+        * @param String|null|false $text Text to unserialize
+        * @return Content The content object created from $text. If $text was false or null, false resp. null will be
+        *                 returned instead.
         *
         * @throws MWException if unserializing the text results in a Content object that is not an instance of TextContent
         *          and $this->allowNonTextContent is not true.
         */
        protected function toEditContent( $text ) {
+               if ( $text === false || $text === null ) {
+                       return $text;
+               }
+
                $content = ContentHandler::makeContent( $text, $this->getTitle(),
                        $this->contentModel, $this->contentFormat );
 
index 8cb99f5..a07dd4c 100644 (file)
@@ -942,4 +942,22 @@ class Html {
 
                return $s;
        }
+
+       /**
+        * Generate a srcset attribute value from an array mapping pixel densities
+        * to URLs. Note that srcset supports width and height values as well, which
+        * are not used here.
+        *
+        * @param array $urls
+        * @return string
+        */
+       static function srcSet( $urls ) {
+               $candidates = array();
+               foreach( $urls as $density => $url ) {
+                       // Image candidate syntax per current whatwg live spec, 2012-09-23:
+                       // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-1.html#attr-img-srcset
+                       $candidates[] = "{$url} {$density}x";
+               }
+               return implode( ", ", $candidates );
+       }
 }
index c17e2d1..0f45165 100644 (file)
@@ -676,6 +676,7 @@ class Linker {
                if ( !$thumb ) {
                        $s = self::makeBrokenImageLinkObj( $title, $fp['title'], '', '', '', $time == true );
                } else {
+                       self::processResponsiveImages( $file, $thumb, $hp );
                        $params = array(
                                'alt' => $fp['alt'],
                                'title' => $fp['title'],
@@ -796,6 +797,7 @@ class Linker {
                        $hp['width'] = isset( $fp['upright'] ) ? 130 : 180;
                }
                $thumb = false;
+               $noscale = false;
 
                if ( !$exists ) {
                        $outerWidth = $hp['width'] + 2;
@@ -814,6 +816,7 @@ class Linker {
                        } elseif ( isset( $fp['framed'] ) ) {
                                // Use image dimensions, don't scale
                                $thumb = $file->getUnscaledThumb( $hp );
+                               $noscale = true;
                        } else {
                                # Do not present an image bigger than the source, for bitmap-style images
                                # This is a hack to maintain compatibility with arbitrary pre-1.10 behaviour
@@ -847,6 +850,9 @@ class Linker {
                        $s .= wfMessage( 'thumbnail_error', '' )->escaped();
                        $zoomIcon = '';
                } else {
+                       if ( !$noscale ) {
+                               self::processResponsiveImages( $file, $thumb, $hp );
+                       }
                        $params = array(
                                'alt' => $fp['alt'],
                                'title' => $fp['title'],
@@ -873,6 +879,37 @@ class Linker {
                return str_replace( "\n", ' ', $s );
        }
 
+       /**
+        * Process responsive images: add 1.5x and 2x subimages to the thumbnail, where
+        * applicable.
+        *
+        * @param File $file
+        * @param MediaOutput $thumb
+        * @param array $hp image parameters
+        */
+       protected static function processResponsiveImages( $file, $thumb, $hp ) {
+               global $wgResponsiveImages;
+               if ( $wgResponsiveImages ) {
+                       $hp15 = $hp;
+                       $hp15['width'] = round( $hp['width'] * 1.5 );
+                       $hp20 = $hp;
+                       $hp20['width'] = $hp['width'] * 2;
+                       if ( isset( $hp['height'] ) ) {
+                               $hp15['height'] = round( $hp['height'] * 1.5 );
+                               $hp20['height'] = $hp['height'] * 2;
+                       }
+
+                       $thumb15 = $file->transform( $hp15 );
+                       $thumb20 = $file->transform( $hp20 );
+                       if ( $thumb15->url !== $thumb->url ) {
+                               $thumb->responsiveUrls['1.5'] = $thumb15->url;
+                       }
+                       if ( $thumb20->url !== $thumb->url ) {
+                               $thumb->responsiveUrls['2'] = $thumb20->url;
+                       }
+               }
+       }
+
        /**
         * Make a "broken" link to an image
         *
index dd9c9e3..3578568 100644 (file)
@@ -2462,7 +2462,7 @@ $templates
         */
        private function addDefaultModules() {
                global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil, $wgUseAjax,
-                       $wgAjaxWatch;
+                       $wgAjaxWatch, $wgResponsiveImages;
 
                // Add base resources
                $this->addModules( array(
@@ -2503,6 +2503,11 @@ $templates
                if ( $this->isArticle() && $this->getUser()->getOption( 'editondblclick' ) ) {
                        $this->addModules( 'mediawiki.action.view.dblClickEdit' );
                }
+
+               // Support for high-density display images
+               if ( $wgResponsiveImages ) {
+                       $this->addModules( 'mediawiki.hidpi' );
+               }
        }
 
        /**
index 3212f54..cb0a13f 100644 (file)
@@ -2916,10 +2916,10 @@ class Title {
 
                $linkCache = LinkCache::singleton();
                $cached = $linkCache->getGoodLinkFieldObj( $this, 'redirect' );
-               if ( $cached === null ) { # check the assumption that the cache actually knows about this title
-                       # XXX: this does apparently happen, see https://bugzilla.wikimedia.org/show_bug.cgi?id=37209
-                       #      as a stop gap, perhaps log this, but don't throw an exception?
-                       throw new MWException( "LinkCache doesn't currently know about this title: " . $this->getPrefixedDBkey() );
+               if ( $cached === null ) { 
+                       // TODO: check the assumption that the cache actually knows about this title
+                       // and handle this, such as get the title from the database.
+                       // See https://bugzilla.wikimedia.org/show_bug.cgi?id=37209
                }
 
                $this->mRedirect = (bool)$cached;
index 2afe326..f80319d 100644 (file)
@@ -893,7 +893,7 @@ class User {
                if( $loggedOut !== null ) {
                        $this->mTouched = wfTimestamp( TS_MW, $loggedOut );
                } else {
-                       $this->mTouched = '0'; # Allow any pages to be cached
+                       $this->mTouched = '1'; # Allow any pages to be cached
                }
 
                $this->mToken = null; // Don't run cryptographic functions till we need a token
index 770c37a..f79c249 100644 (file)
@@ -1647,7 +1647,7 @@ class WikiPage extends Page implements IDBAccessObject {
                $hook_args = array( &$this, &$user, &$content, &$summary,
                                                        $flags & EDIT_MINOR, null, null, &$flags, &$status );
 
-               if ( !wfRunHooks( 'ArticleContentSave', $hook_args )
+               if ( !wfRunHooks( 'PageContentSave', $hook_args )
                        || !ContentHandler::runLegacyHooks( 'ArticleSave', $hook_args ) ) {
 
                        wfDebug( __METHOD__ . ": ArticleSave or ArticleSaveContent hook aborted save!\n" );
@@ -1878,7 +1878,7 @@ class WikiPage extends Page implements IDBAccessObject {
                                                                $flags & EDIT_MINOR, null, null, &$flags, $revision );
 
                        ContentHandler::runLegacyHooks( 'ArticleInsertComplete', $hook_args );
-                       wfRunHooks( 'ArticleContentInsertComplete', $hook_args );
+                       wfRunHooks( 'PageContentInsertComplete', $hook_args );
                }
 
                # Do updates right now unless deferral was requested
@@ -1893,7 +1893,7 @@ class WikiPage extends Page implements IDBAccessObject {
                                                        $flags & EDIT_MINOR, null, null, &$flags, $revision, &$status, $baseRevId );
 
                ContentHandler::runLegacyHooks( 'ArticleSaveComplete', $hook_args );
-               wfRunHooks( 'ArticleContentSaveComplete', $hook_args );
+               wfRunHooks( 'PageContentSaveComplete', $hook_args );
 
                # Promote user to any groups they meet the criteria for
                $user->addAutopromoteOnceGroups( 'onEdit' );
index a4b0cb7..b573b1a 100644 (file)
@@ -75,7 +75,7 @@ class InfoAction extends FormlessAction {
                $pageInfo = $this->pageInfo();
 
                // Allow extensions to add additional information
-               wfRunHooks( 'InfoAction', array( &$pageInfo ) );
+               wfRunHooks( 'InfoAction', array( $this->getContext(), &$pageInfo ) );
 
                // Render page information
                foreach ( $pageInfo as $header => $infoTable ) {
@@ -149,7 +149,7 @@ class InfoAction extends FormlessAction {
         * @return array
         */
        protected function pageInfo() {
-               global $wgContLang, $wgDisableCounters, $wgRCMaxAge;
+               global $wgContLang, $wgRCMaxAge;
 
                $user = $this->getUser();
                $lang = $this->getLanguage();
@@ -157,8 +157,7 @@ class InfoAction extends FormlessAction {
                $id = $title->getArticleID();
 
                // Get page information that would be too "expensive" to retrieve by normal means
-               $userCanViewUnwatchedPages = $user->isAllowed( 'unwatchedpages' );
-               $pageCounts = self::pageCounts( $title, $userCanViewUnwatchedPages, $wgDisableCounters );
+               $pageCounts = self::pageCounts( $title, $user );
 
                // Get page properties
                $dbr = wfGetDB( DB_SLAVE );
@@ -216,14 +215,14 @@ class InfoAction extends FormlessAction {
                        $this->msg( 'pageinfo-robot-policy' ), $this->msg( "pageinfo-robot-${policy['index']}" )
                );
 
-               if ( !$wgDisableCounters ) {
+               if ( isset( $pageCounts['views'] ) ) {
                        // Number of views
                        $pageInfo['header-basic'][] = array(
                                $this->msg( 'pageinfo-views' ), $lang->formatNum( $pageCounts['views'] )
                        );
                }
 
-               if ( $userCanViewUnwatchedPages ) {
+               if ( isset( $pageCounts['watchers'] ) ) {
                        // Number of page watchers
                        $pageInfo['header-basic'][] = array(
                                $this->msg( 'pageinfo-watchers' ), $lang->formatNum( $pageCounts['watchers'] )
@@ -402,12 +401,11 @@ class InfoAction extends FormlessAction {
         * Returns page counts that would be too "expensive" to retrieve by normal means.
         *
         * @param $title Title object
-        * @param $canViewUnwatched bool
-        * @param $disableCounter bool
+        * @param $user User object
         * @return array
         */
-       protected static function pageCounts( $title, $canViewUnwatched, $disableCounter ) {
-               global $wgRCMaxAge;
+       protected static function pageCounts( $title, $user ) {
+               global $wgRCMaxAge, $wgDisableCounters;
 
                wfProfileIn( __METHOD__ );
                $id = $title->getArticleID();
@@ -415,7 +413,7 @@ class InfoAction extends FormlessAction {
                $dbr = wfGetDB( DB_SLAVE );
                $result = array();
 
-               if ( !$disableCounter ) {
+               if ( !$wgDisableCounters ) {
                        // Number of views
                        $views = (int) $dbr->selectField(
                                'page',
@@ -426,7 +424,7 @@ class InfoAction extends FormlessAction {
                        $result['views'] = $views;
                }
 
-               if ( $canViewUnwatched ) {
+               if ( $user->isAllowed( 'unwatchedpages' ) ) {
                        // Number of page watchers
                        $watchers = (int) $dbr->selectField(
                                'watchlist',
index 0454bb3..6b8639c 100644 (file)
@@ -86,6 +86,9 @@ class ApiUpload extends ApiBase {
                        if( $this->mParams['filesize'] > $maxSize ) {
                                $this->dieUsage( 'The file you submitted was too large', 'file-too-large' );
                        }
+                       if ( !$this->mUpload->getTitle() ) {
+                               $this->dieUsage( 'Invalid file title supplied', 'internal-error' );
+                       }
                } else {
                        $this->verifyUpload();
                }
index 68e6c39..e98584f 100644 (file)
@@ -12,6 +12,10 @@ abstract class TextContent extends AbstractContent {
        public function __construct( $text, $model_id = null ) {
                parent::__construct( $model_id );
 
+               if ( !is_string( $text ) ) {
+                       throw new MWException( "TextContent expects a string in the constructor." );
+               }
+
                $this->mText = $text;
        }
 
index 99413f9..9693789 100644 (file)
@@ -298,6 +298,72 @@ interface IORMTable {
         */
        public function setReadDb( $db );
 
+
+       /**
+        * Get the ID of the any foreign wiki to use as a target for database operations
+        *
+        * @since 1.20
+        *
+        * @return String|bool The target wiki, in a form that  LBFactory understands (or false if the local wiki is used)
+        */
+       public function getTargetWiki();
+
+       /**
+        * Set the ID of the any foreign wiki to use as a target for database operations
+        *
+        * @param String|bool $wiki The target wiki, in a form that  LBFactory understands (or false if the local wiki shall be used)
+        *
+        * @since 1.20
+        */
+       public function setTargetWiki( $wiki );
+
+       /**
+        * Get the database type used for read operations.
+        * This is to be used instead of wfGetDB.
+        *
+        * @see LoadBalancer::getConnection
+        *
+        * @since 1.20
+        *
+        * @return DatabaseBase The database object
+        */
+       public function getReadDbConnection();
+
+       /**
+        * Get the database type used for read operations.
+        * This is to be used instead of wfGetDB.
+        *
+        * @see LoadBalancer::getConnection
+        *
+        * @since 1.20
+        *
+        * @return DatabaseBase The database object
+        */
+       public function getWriteDbConnection();
+
+       /**
+        * Get the database type used for read operations.
+        *
+        * @see wfGetLB
+        *
+        * @since 1.20
+        *
+        * @return LoadBalancer The database load balancer object
+        */
+       public function getLoadBalancer();
+
+       /**
+        * Releases the lease on the given database connection. This is useful mainly
+        * for connections to a foreign wiki. It does nothing for connections to the local wiki.
+        *
+        * @see LoadBalancer::reuseConnection
+        *
+        * @param DatabaseBase $db the database
+        *
+        * @since 1.20
+        */
+       public function releaseConnection( DatabaseBase $db );
+
        /**
         * Update the records matching the provided conditions by
         * setting the fields that are keys in the $values param to
index 39f16a0..e3a3434 100644 (file)
@@ -47,7 +47,7 @@ abstract class ORMTable implements IORMTable {
        protected static $instanceCache = array();
 
        /**
-        * The database connection to use for read operations.
+        * ID of the database connection to use for read operations.
         * Can be changed via @see setReadDb.
         *
         * @since 1.20
@@ -55,6 +55,15 @@ abstract class ORMTable implements IORMTable {
         */
        protected $readDb = DB_SLAVE;
 
+       /**
+        * The ID of any foreign wiki to use as a target for database operations,
+        * or false to use the local wiki.
+        *
+        * @since 1.20
+        * @var String|bool
+        */
+       protected $wiki = false;
+
        /**
         * Returns a list of default field values.
         * field name => field value
@@ -145,13 +154,17 @@ abstract class ORMTable implements IORMTable {
                        $fields = (array)$fields;
                }
 
-               return wfGetDB( $this->getReadDb() )->select(
+               $dbr = $this->getReadDbConnection();
+               $result = $dbr->select(
                        $this->getName(),
                        $this->getPrefixedFields( $fields ),
                        $this->getPrefixedValues( $conditions ),
                        is_null( $functionName ) ? __METHOD__ : $functionName,
                        $options
                );
+
+               $this->releaseConnection( $dbr );
+               return $result;
        }
 
        /**
@@ -241,15 +254,18 @@ abstract class ORMTable implements IORMTable {
         */
        public function rawSelectRow( array $fields, array $conditions = array(),
                                                                  array $options = array(), $functionName = null ) {
-               $dbr = wfGetDB( $this->getReadDb() );
+               $dbr = $this->getReadDbConnection();
 
-               return $dbr->selectRow(
+               $result = $dbr->selectRow(
                        $this->getName(),
                        $fields,
                        $conditions,
                        is_null( $functionName ) ? __METHOD__ : $functionName,
                        $options
                );
+
+               $this->releaseConnection( $dbr );
+               return $result;
        }
 
        /**
@@ -327,11 +343,16 @@ abstract class ORMTable implements IORMTable {
         * @return boolean Success indicator
         */
        public function delete( array $conditions, $functionName = null ) {
-               return wfGetDB( DB_MASTER )->delete(
+               $dbw = $this->getWriteDbConnection();
+
+               $result = $dbw->delete(
                        $this->getName(),
                        $conditions === array() ? '*' : $this->getPrefixedValues( $conditions ),
                        $functionName
                ) !== false; // DatabaseBase::delete does not always return true for success as documented...
+
+               $this->releaseConnection( $dbw );
+               return $result;
        }
 
        /**
@@ -397,7 +418,7 @@ abstract class ORMTable implements IORMTable {
        }
 
        /**
-        * Get the database type used for read operations.
+        * Get the database ID used for read operations.
         *
         * @since 1.20
         *
@@ -408,7 +429,7 @@ abstract class ORMTable implements IORMTable {
        }
 
        /**
-        * Set the database type to use for read operations.
+        * Set the database ID to use for read operations, use DB_XXX constants or an index to the load balancer setup.
         *
         * @param integer $db
         *
@@ -418,6 +439,86 @@ abstract class ORMTable implements IORMTable {
                $this->readDb = $db;
        }
 
+       /**
+        * Get the ID of the any foreign wiki to use as a target for database operations
+        *
+        * @since 1.20
+        *
+        * @return String|bool The target wiki, in a form that  LBFactory understands (or false if the local wiki is used)
+        */
+       public function getTargetWiki() {
+               return $this->wiki;
+       }
+
+       /**
+        * Set the ID of the any foreign wiki to use as a target for database operations
+        *
+        * @param String|bool $wiki The target wiki, in a form that  LBFactory understands (or false if the local wiki shall be used)
+        *
+        * @since 1.20
+        */
+       public function setTargetWiki( $wiki ) {
+               $this->wiki = $wiki;
+       }
+
+       /**
+        * Get the database type used for read operations.
+        * This is to be used instead of wfGetDB.
+        *
+        * @see LoadBalancer::getConnection
+        *
+        * @since 1.20
+        *
+        * @return DatabaseBase The database object
+        */
+       public function getReadDbConnection() {
+               return $this->getLoadBalancer()->getConnection( $this->getReadDb(), array(), $this->getTargetWiki() );
+       }
+
+       /**
+        * Get the database type used for read operations.
+        * This is to be used instead of wfGetDB.
+        *
+        * @see LoadBalancer::getConnection
+        *
+        * @since 1.20
+        *
+        * @return DatabaseBase The database object
+        */
+       public function getWriteDbConnection() {
+               return $this->getLoadBalancer()->getConnection( DB_MASTER, array(), $this->getTargetWiki() );
+       }
+
+       /**
+        * Get the database type used for read operations.
+        *
+        * @see wfGetLB
+        *
+        * @since 1.20
+        *
+        * @return LoadBalancer The database load balancer object
+        */
+       public function getLoadBalancer() {
+               return wfGetLB( $this->getTargetWiki() );
+       }
+
+       /**
+        * Releases the lease on the given database connection. This is useful mainly
+        * for connections to a foreign wiki. It does nothing for connections to the local wiki.
+        *
+        * @see LoadBalancer::reuseConnection
+        *
+        * @param DatabaseBase $db the database
+        *
+        * @since 1.20
+        */
+       public function releaseConnection( DatabaseBase $db ) {
+               if ( $this->wiki !== false ) {
+                       // recycle connection to foreign wiki
+                       $this->getLoadBalancer()->reuseConnection( $db );
+               }
+       }
+
        /**
         * Update the records matching the provided conditions by
         * setting the fields that are keys in the $values param to
@@ -431,14 +532,17 @@ abstract class ORMTable implements IORMTable {
         * @return boolean Success indicator
         */
        public function update( array $values, array $conditions = array() ) {
-               $dbw = wfGetDB( DB_MASTER );
+               $dbw = $this->getWriteDbConnection();
 
-               return $dbw->update(
+               $result = $dbw->update(
                        $this->getName(),
                        $this->getPrefixedValues( $values ),
                        $this->getPrefixedValues( $conditions ),
                        __METHOD__
                ) !== false; // DatabaseBase::update does not always return true for success as documented...
+
+               $this->releaseConnection( $dbw );
+               return $result;
        }
 
        /**
@@ -450,6 +554,7 @@ abstract class ORMTable implements IORMTable {
         * @param array $conditions
         */
        public function updateSummaryFields( $summaryFields = null, array $conditions = array() ) {
+               $slave = $this->getReadDb();
                $this->setReadDb( DB_MASTER );
 
                /**
@@ -461,7 +566,7 @@ abstract class ORMTable implements IORMTable {
                        $item->save();
                }
 
-               $this->setReadDb( DB_SLAVE );
+               $this->setReadDb( $slave );
        }
 
        /**
index 18dcfe9..d638c48 100644 (file)
@@ -544,8 +544,19 @@ class DifferenceEngine extends ContextSource {
 
                                $parserOutput = $this->getParserOutput( $wikiPage, $this->mNewRev );
 
-                               # WikiPage::getParserOutput() should not return false, but just in case
-                               if( $parserOutput ) {
+                               # Also try to load it as a redirect
+                               $rt = $this->mNewContent->getRedirectTarget();
+
+                               if ( $rt ) {
+                                       $article = Article::newFromTitle( $this->mNewPage, $this->getContext() );
+                                       $out->addHTML( $article->viewRedirect( $rt ) );
+
+                                       # WikiPage::getParserOutput() should not return false, but just in case
+                                       if ( $parserOutput ) {
+                                               # Show categories etc.
+                                               $out->addParserOutputNoText( $parserOutput );
+                                       }
+                               } else if ( $parserOutput ) {
                                        $out->addParserOutput( $parserOutput );
                                }
                        }
index 68a3922..c9ee446 100644 (file)
@@ -223,6 +223,7 @@ class MysqlUpdater extends DatabaseUpdater {
                        array( 'addField',      'page',     'page_content_model',               'patch-page-page_content_model.sql' ),
                        array( 'dropField', 'site_stats',   'ss_admins',        'patch-drop-ss_admins.sql' ),
                        array( 'dropField', 'recentchanges', 'rc_moved_to_title',            'patch-rc_moved.sql' ),
+                       array( 'addTable', 'sites',                            'patch-sites.sql' ),
                );
        }
 
index 72ec800..845816e 100644 (file)
@@ -40,7 +40,7 @@ class OracleInstaller extends DatabaseInstaller {
        protected $internalDefaults = array(
                '_OracleDefTS' => 'USERS',
                '_OracleTempTS' => 'TEMP',
-               '_InstallUser' => 'SYSDBA',
+               '_InstallUser' => 'SYSTEM',
        );
 
        public $minimumVersion = '9.0.1'; // 9iR1
index 2f20135..f946d59 100644 (file)
@@ -70,6 +70,7 @@ class OracleUpdater extends DatabaseUpdater {
                        array( 'addTable', 'config', 'patch-config.sql' ),
                        array( 'addIndex', 'ipblocks', 'i05', 'patch-ipblocks_i05_index.sql' ),
                        array( 'addIndex', 'revision', 'i05', 'patch-revision_i05_index.sql' ),
+                       array( 'dropField', 'category', 'cat_hidden', 'patch-cat_hidden.sql' ),
 
                        //1.21
                        array( 'addField',      'revision',     'rev_content_format',           'patch-revision-rev_content_format.sql' ),
@@ -77,6 +78,8 @@ class OracleUpdater extends DatabaseUpdater {
                        array( 'addField',      'archive',      'ar_content_format',            'patch-archive-ar_content_format.sql' ),
                        array( 'addField',      'archive',      'ar_content_model',                 'patch-archive-ar_content_model.sql' ),
                        array( 'addField',      'page',     'page_content_model',               'patch-page-page_content_model.sql' ),
+                       array( 'dropField', 'site_stats', 'ss_admins',  'patch-ss_admins.sql' ),
+                       array( 'dropField', 'recentchanges', 'rc_moved_to_title', 'patch-rc_moved.sql' ),
 
                        // KEEP THIS AT THE BOTTOM!!
                        array( 'doRebuildDuplicateFunction' ),
index 499a2d6..9ad91b7 100644 (file)
@@ -101,6 +101,8 @@ class PostgresUpdater extends DatabaseUpdater {
                        array( 'addPgField', 'archive',       'ar_len',               'INTEGER' ),
                        array( 'addPgField', 'archive',       'ar_page_id',           'INTEGER' ),
                        array( 'addPgField', 'archive',       'ar_parent_id',         'INTEGER' ),
+                       array( 'addPgField', 'archive',       'ar_content_model',     'TEXT' ),
+                       array( 'addPgField', 'archive',       'ar_content_format',    'TEXT' ),
                        array( 'addPgField', 'categorylinks', 'cl_sortkey_prefix',    "TEXT NOT NULL DEFAULT ''"),
                        array( 'addPgField', 'categorylinks', 'cl_collation',         "TEXT NOT NULL DEFAULT 0"),
                        array( 'addPgField', 'categorylinks', 'cl_type',              "TEXT NOT NULL DEFAULT 'page'"),
@@ -125,6 +127,7 @@ class PostgresUpdater extends DatabaseUpdater {
                        array( 'addPgField', 'oldimage',      'oi_metadata',          "BYTEA NOT NULL DEFAULT ''" ),
                        array( 'addPgField', 'oldimage',      'oi_minor_mime',        "TEXT NOT NULL DEFAULT 'unknown'" ),
                        array( 'addPgField', 'oldimage',      'oi_sha1',              "TEXT NOT NULL DEFAULT ''" ),
+                       array( 'addPgField', 'page',          'page_content_model',   'TEXT' ),
                        array( 'addPgField', 'page_restrictions', 'pr_id',            "INTEGER NOT NULL UNIQUE DEFAULT nextval('page_restrictions_pr_id_seq')" ),
                        array( 'addPgField', 'profiling',     'pf_memory',            'NUMERIC(18,10) NOT NULL DEFAULT 0' ),
                        array( 'addPgField', 'recentchanges', 'rc_deleted',           'SMALLINT NOT NULL DEFAULT 0' ),
@@ -139,6 +142,8 @@ class PostgresUpdater extends DatabaseUpdater {
                        array( 'addPgField', 'revision',      'rev_deleted',          'SMALLINT NOT NULL DEFAULT 0' ),
                        array( 'addPgField', 'revision',      'rev_len',              'INTEGER' ),
                        array( 'addPgField', 'revision',      'rev_parent_id',        'INTEGER DEFAULT NULL' ),
+                       array( 'addPgField', 'revision',      'rev_content_model',    'TEXT' ),
+                       array( 'addPgField', 'revision',      'rev_content_format',   'TEXT' ),
                        array( 'addPgField', 'site_stats',    'ss_active_users',      "INTEGER DEFAULT '-1'" ),
                        array( 'addPgField', 'user_newtalk',  'user_last_timestamp',  'TIMESTAMPTZ' ),
                        array( 'addPgField', 'logging',       'log_user_text',        "TEXT NOT NULL DEFAULT ''" ),
index ab38055..6ec4706 100644 (file)
@@ -103,6 +103,7 @@ class SqliteUpdater extends DatabaseUpdater {
 
                        array( 'dropField', 'site_stats',    'ss_admins',         'patch-drop-ss_admins.sql' ),
                        array( 'dropField', 'recentchanges', 'rc_moved_to_title', 'patch-rc_moved.sql' ),
+                       array( 'addTable', 'sites',                            'patch-sites.sql' ),
                );
        }
 
index c5e4566..69bdc2f 100644 (file)
@@ -33,6 +33,13 @@ abstract class MediaTransformOutput {
        var $file;
 
        var $width, $height, $url, $page, $path;
+
+       /**
+        * @var array Associative array mapping optional supplementary image files
+        * from pixel density (eg 1.5 or 2) to additional URLs.
+        */
+       public $responsiveUrls = array();
+
        protected $storagePath = false;
 
        /**
@@ -324,7 +331,7 @@ class ThumbnailImage extends MediaTransformOutput {
                        'alt' => $alt,
                        'src' => $this->url,
                        'width' => $this->width,
-                       'height' => $this->height,
+                       'height' => $this->height
                );
                if ( !empty( $options['valign'] ) ) {
                        $attribs['style'] = "vertical-align: {$options['valign']}";
@@ -332,6 +339,11 @@ class ThumbnailImage extends MediaTransformOutput {
                if ( !empty( $options['img-class'] ) ) {
                        $attribs['class'] = $options['img-class'];
                }
+
+               // Additional densities for responsive images, if specified.
+               if ( !empty( $this->responsiveUrls ) ) {
+                       $attribs['srcset'] = Html::srcSet( $this->responsiveUrls );
+               }
                return $this->linkWrap( $linkAttribs, Xml::element( 'img', $attribs ) );
        }
 
diff --git a/includes/site/MediaWikiSite.php b/includes/site/MediaWikiSite.php
new file mode 100644 (file)
index 0000000..b05c421
--- /dev/null
@@ -0,0 +1,320 @@
+<?php
+
+/**
+ * Class representing a MediaWiki site.
+ *
+ * @since 1.21
+ *
+ * @file
+ * @ingroup Site
+ *
+ * @licence GNU GPL v2+
+ * @author John Erling Blad < jeblad@gmail.com >
+ * @author Daniel Kinzler
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class MediaWikiSite extends SiteObject {
+
+       const PATH_FILE = 'file_path';
+       const PATH_PAGE = 'page_path';
+
+       /**
+        * @since 1.21
+        *
+        * @param integer $globalId
+        *
+        * @return MediaWikiSite
+        */
+       public static function newFromGlobalId( $globalId ) {
+               return SitesTable::singleton()->newRow( array(
+                       'type' => Site::TYPE_MEDIAWIKI,
+                       'global_key' => $globalId,
+               ), true );
+       }
+
+       /**
+        * Returns the database form of the given title.
+        *
+        * @since 1.21
+        *
+        * @param String $title the target page's title, in normalized form.
+        *
+        * @return String
+        */
+       public function toDBKey( $title ) {
+               return str_replace( ' ', '_', $title );
+       }
+
+       /**
+        * Returns the normalized form of the given page title, using the normalization rules of the given site.
+        * If the given title is a redirect, the redirect weill be resolved and the redirect target is returned.
+        *
+        * @note  : This actually makes an API request to the remote site, so beware that this function is slow and depends
+        *          on an external service.
+        *
+        * @note  : If MW_PHPUNIT_TEST is defined or $egWBRemoteTitleNormalization is set to false, the call to the
+        *          external site is skipped, and the title is normalized using the local normalization rules as
+        *          implemented by the Title class.
+        *
+        * @see Site::normalizePageName
+        *
+        * @since 1.21
+        *
+        * @param string $pageName
+        *
+        * @return string
+        * @throws MWException
+        */
+       public function normalizePageName( $pageName ) {
+               global $egWBRemoteTitleNormalization;
+
+               // Check if we have strings as arguments.
+               if ( !is_string( $pageName ) ) {
+                       throw new MWException( '$pageName must be a string' );
+               }
+
+               // Go on call the external site
+               if ( defined( 'MW_PHPUNIT_TEST' ) ) {
+                       // If the code is under test, don't call out to other sites, just normalize locally.
+                       // Note: this may cause results to be inconsistent with the actual normalization used by the respective remote site!
+
+                       $t = Title::newFromText( $pageName );
+                       return $t->getPrefixedText();
+               } else {
+
+                       // Make sure the string is normalized into NFC (due to the bug 40017)
+                       // but do nothing to the whitespaces, that should work appropriately.
+                       // @see https://bugzilla.wikimedia.org/show_bug.cgi?id=40017
+                       $pageName = UtfNormal::cleanUp( $pageName );
+
+                       // Build the args for the specific call
+                       $args = array(
+                               'action' => 'query',
+                               'prop' => 'info',
+                               'redirects' => true,
+                               'converttitles' => true,
+                               'format' => 'json',
+                               'titles' => $pageName,
+                               //@todo: options for maxlag and maxage
+                               // Note that maxlag will lead to a long delay before a reply is made,
+                               // but that maxage can avoid the extreme delay. On the other hand
+                               // maxage could be nice to use anyhow as it stops unnecessary requests.
+                               // Also consider smaxage if maxage is used.
+                       );
+
+                       $url = $this->getFileUrl( 'api.php' ) . '?' . wfArrayToCgi( $args );
+
+                       // Go on call the external site
+                       //@todo: we need a good way to specify a timeout here.
+                       $ret = Http::get( $url );
+               }
+
+               if ( $ret === false ) {
+                       wfDebugLog( "MediaWikiSite", "call to external site failed: $url" );
+                       return false;
+               }
+
+               $data = FormatJson::decode( $ret, true );
+
+               if ( !is_array( $data ) ) {
+                       wfDebugLog( "MediaWikiSite", "call to <$url> returned bad json: " . $ret );
+                       return false;
+               }
+
+               $page = static::extractPageRecord( $data, $pageName );
+
+               if ( isset( $page['missing'] ) ) {
+                       wfDebugLog( "MediaWikiSite", "call to <$url> returned a missing page title! " . $ret );
+                       return false;
+               }
+
+               if ( !isset( $page['title'] ) ) {
+                       wfDebugLog( "MediaWikiSite", "call to <$url> did not return a page title! " . $ret );
+                       return false;
+               }
+
+               return $page['title'];
+       }
+
+
+       /**
+        * Get normalization record for a given page title from an API response.
+        *
+        * @since 1.21
+        *
+        * @param array $externalData A reply from the API on a external server.
+        * @param string $pageTitle Identifies the page at the external site, needing normalization.
+        *
+        * @return array|false a 'page' structure representing the page identified by $pageTitle.
+        */
+       private static function extractPageRecord( $externalData, $pageTitle ) {
+               // If there is a special case with only one returned page
+               // we can cheat, and only return
+               // the single page in the "pages" substructure.
+               if ( isset( $externalData['query']['pages'] ) ) {
+                       $pages = array_values( $externalData['query']['pages'] );
+                       if ( count( $pages) === 1 ) {
+                               return $pages[0];
+                       }
+               }
+               // This is only used during internal testing, as it is assumed
+               // a more optimal (and lossfree) storage.
+               // Make initial checks and return if prerequisites are not meet.
+               if ( !is_array( $externalData ) || !isset( $externalData['query'] ) ) {
+                       return false;
+               }
+               // Loop over the tree different named structures, that otherwise are similar
+               $structs = array(
+                       'normalized' => 'from',
+                       'converted' => 'from',
+                       'redirects' => 'from',
+                       'pages' => 'title'
+               );
+               foreach ( $structs as $listId => $fieldId ) {
+                       // Check if the substructure exist at all.
+                       if ( !isset( $externalData['query'][$listId] ) ) {
+                               continue;
+                       }
+                       // Filter the substructure down to what we actually are using.
+                       $collectedHits = array_filter(
+                               array_values( $externalData['query'][$listId] ),
+                               function( $a ) use ( $fieldId, $pageTitle ) {
+                                       return $a[$fieldId] === $pageTitle;
+                               }
+                       );
+                       // If still looping over normalization, conversion or redirects,
+                       // then we need to keep the new page title for later rounds.
+                       if ( $fieldId === 'from' && is_array( $collectedHits ) ) {
+                               switch ( count( $collectedHits ) ) {
+                                       case 0:
+                                               break;
+                                       case 1:
+                                               $pageTitle = $collectedHits[0]['to'];
+                                               break;
+                                       default:
+                                               return false;
+                               }
+                       }
+                       // If on the pages structure we should prepare for returning.
+                       elseif ( $fieldId === 'title' && is_array( $collectedHits ) ) {
+                               switch ( count( $collectedHits ) ) {
+                                       case 0:
+                                               return false;
+                                       case 1:
+                                               return array_shift( $collectedHits );
+                                       default:
+                                               return false;
+                               }
+                       }
+               }
+               // should never be here
+               return false;
+       }
+
+       /**
+        * @see Site::getLinkPathType
+        * Returns Site::PATH_PAGE
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getLinkPathType() {
+               return self::PATH_PAGE;
+       }
+
+       /**
+        * Returns the relative page path.
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getRelativePagePath() {
+               return parse_url( $this->getPath( self::PATH_PAGE ), PHP_URL_PATH );
+       }
+
+       /**
+        * Returns the relative file path.
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getRelativeFilePath() {
+               return parse_url( $this->getPath( self::PATH_FILE ), PHP_URL_PATH );
+       }
+
+       /**
+        * Sets the relative page path.
+        *
+        * @since 1.21
+        *
+        * @param string $path
+        */
+       public function setPagePath( $path ) {
+               $this->setPath( self::PATH_PAGE, $path );
+       }
+
+       /**
+        * Sets the relative file path.
+        *
+        * @since 1.21
+        *
+        * @param string $path
+        */
+       public function setFilePath( $path ) {
+               $this->setPath( self::PATH_FILE, $path );
+       }
+
+       /**
+        * @see Site::getPagePath
+        *
+        * This implementation returns a URL constructed using the path returned by getLinkPath().
+        * In addition to the default behaviour implemented by SiteObject::getPageUrl(), this
+        * method converts the $pageName to DBKey-format by replacing spaces with underscores
+        * before using it in the URL.
+        *
+        * @since 1.21
+        *
+        * @param string|false
+        *
+        * @return string
+        */
+       public function getPageUrl( $pageName = false ) {
+               $url = $this->getLinkPath();
+
+               if ( $url === false ) {
+                       return false;
+               }
+
+               if ( $pageName !== false ) {
+                       $pageName = $this->toDBKey( trim( $pageName ) );
+                       $url = str_replace( '$1', wfUrlencode( $pageName ), $url ) ;
+               }
+
+               return $url;
+       }
+
+       /**
+        * Returns the full file path (ie site url + relative file path).
+        * The path should go at the $1 marker. If the $path
+        * argument is provided, the marker will be replaced by it's value.
+        *
+        * @since 1.21
+        *
+        * @param string|false $path
+        *
+        * @return string
+        */
+       public function getFileUrl( $path = false ) {
+               $filePath = $this->getPath( self::PATH_FILE );
+
+               if ( $filePath !== false ) {
+                       $filePath = str_replace( '$1', $path, $filePath );
+               }
+
+               return $filePath;
+       }
+
+}
diff --git a/includes/site/Site.php b/includes/site/Site.php
new file mode 100644 (file)
index 0000000..350a19d
--- /dev/null
@@ -0,0 +1,316 @@
+<?php
+
+/**
+ * Interface for site objects.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @since 1.21
+ *
+ * @file
+ * @ingroup Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+interface Site {
+
+       const TYPE_UNKNOWN = 'unknown';
+       const TYPE_MEDIAWIKI = 'mediawiki';
+
+       const GROUP_NONE = 'none';
+
+       const ID_INTERWIKI = 'interwiki';
+       const ID_EQUIVALENT = 'equivalent';
+
+       const SOURCE_LOCAL = 'local';
+
+       /**
+        * Returns the global site identifier (ie enwiktionary).
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getGlobalId();
+
+       /**
+        * Sets the global site identifier (ie enwiktionary).
+        *
+        * @since 1.21
+        *
+        * @param string $globalId
+        */
+       public function setGlobalId( $globalId );
+
+       /**
+        * Returns the type of the site (ie mediawiki).
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getType();
+
+       /**
+        * Sets the type of the site (ie mediawiki).
+        * TODO: remove, we cannot change this after instantiation
+        *
+        * @since 1.21
+        *
+        * @param string $type
+        */
+       public function setType( $type );
+
+       /**
+        * Gets the type of the site (ie wikipedia).
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getGroup();
+
+       /**
+        * Sets the type of the site (ie wikipedia).
+        *
+        * @since 1.21
+        *
+        * @param string $group
+        */
+       public function setGroup( $group );
+
+       /**
+        * Returns the source of the site data (ie 'local', 'wikidata', 'my-magical-repo').
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getSource();
+
+       /**
+        * Sets the source of the site data (ie 'local', 'wikidata', 'my-magical-repo').
+        *
+        * @since 1.21
+        *
+        * @param string $source
+        */
+       public function setSource( $source );
+
+       /**
+        * Returns the protocol of the site, ie 'http://', 'irc://', '//'
+        * Or false if it's not known.
+        *
+        * @since 1.21
+        *
+        * @return string|false
+        */
+       public function getProtocol();
+
+       /**
+        * Returns the domain of the site, ie en.wikipedia.org
+        * Or false if it's not known.
+        *
+        * @since 1.21
+        *
+        * @return string|false
+        */
+       public function getDomain();
+
+       /**
+        * Returns the full URL for the given page on the site.
+        * Or false if the needed information is not known.
+        *
+        * This generated URL is usually based upon the path returned by getLinkPath(),
+        * but this is not a requirement.
+        *
+        * @since 1.21
+        * @see Site::getLinkPath()
+        *
+        * @param bool|String $page
+        *
+        * @return string|false
+        */
+       public function getPageUrl( $page = false );
+
+       /**
+        * Returns language code of the sites primary language.
+        * Or false if it's not known.
+        *
+        * @since 1.21
+        *
+        * @return string|false
+        */
+       public function getLanguageCode();
+
+       /**
+        * Sets language code of the sites primary language.
+        *
+        * @since 1.21
+        *
+        * @param string $languageCode
+        */
+       public function setLanguageCode( $languageCode );
+
+       /**
+        * Returns the normalized, canonical form of the given page name.
+        * How normalization is performed or what the properties of a normalized name are depends on the site.
+        * The general contract of this method is that the normalized form shall refer to the same content
+        * as the original form, and any other page name referring to the same content will have the same normalized form.
+        *
+        * Note that this method may call out to the target site to perform the normalization, so it may be slow
+        * and fail due to IO errors.
+        *
+        * @since 1.21
+        *
+        * @param string $pageName
+        *
+        * @return string the normalized page name
+        */
+       public function normalizePageName( $pageName );
+
+       /**
+        * Returns the interwiki link identifiers that can be used for this site.
+        *
+        * @since 1.21
+        *
+        * @return array of string
+        */
+       public function getInterwikiIds();
+
+       /**
+        * Returns the equivalent link identifiers that can be used to make
+        * the site show up in interfaces such as the "language links" section.
+        *
+        * @since 1.21
+        *
+        * @return array of string
+        */
+       public function getNavigationIds();
+
+       /**
+        * Adds an local identifier to the site.
+        *
+        * @since 1.21
+        *
+        * @param string $type The type of the identifier, element of the Site::ID_ enum
+        * @param string $identifier
+        */
+       public function addLocalId( $type, $identifier );
+
+       /**
+        * Adds an interwiki id to the site.
+        *
+        * @since 1.21
+        *
+        * @param string $identifier
+        */
+       public function addInterwikiId( $identifier );
+
+       /**
+        * Adds a navigation id to the site.
+        *
+        * @since 1.21
+        *
+        * @param string $identifier
+        */
+       public function addNavigationId( $identifier );
+
+       /**
+        * Saves the site.
+        *
+        * @since 1.21
+        *
+        * @param string|null $functionName
+        */
+       public function save( $functionName = null );
+
+       /**
+        * Returns the internal ID of the site.
+        *
+        * @since 1.21
+        *
+        * @return integer
+        */
+       public function getInternalId();
+
+       /**
+        * Sets the provided url as path of the specified type.
+        *
+        * @since 1.21
+        *
+        * @param string $pathType
+        * @param string $fullUrl
+        */
+       public function setPath( $pathType, $fullUrl );
+
+       /**
+        * Returns the path of the provided type or false if there is no such path.
+        *
+        * @since 1.21
+        *
+        * @param string $pathType
+        *
+        * @return string|false
+        */
+       public function getPath( $pathType );
+
+       /**
+        * Sets the path used to construct links with.
+        * Shall be equivalent to setPath( getLinkPathType(), $fullUrl ).
+        *
+        * @param string $fullUrl
+        *
+        * @since 1.21
+        */
+       public function setLinkPath( $fullUrl );
+
+       /**
+        * Returns the path used to construct links with or false if there is no such path.
+        * Shall be equivalent to getPath( getLinkPathType() ).
+        *
+        * @return string|false
+        */
+       public function getLinkPath();
+
+       /**
+        * Returns the path type used to construct links with.
+        *
+        * @return string|false
+        */
+       public function getLinkPathType();
+
+       /**
+        * Returns the paths as associative array.
+        * The keys are path types, the values are the path urls.
+        *
+        * @since 1.21
+        *
+        * @return array of string
+        */
+       public function getAllPaths();
+
+       /**
+        * Removes the path of the provided type if it's set.
+        *
+        * @since 1.21
+        *
+        * @param string $pathType
+        */
+       public function removePath( $pathType );
+
+}
\ No newline at end of file
diff --git a/includes/site/SiteArray.php b/includes/site/SiteArray.php
new file mode 100644 (file)
index 0000000..df43148
--- /dev/null
@@ -0,0 +1,205 @@
+<?php
+
+/**
+ * Implementation of SiteList using GenericArrayObject.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @since 1.21
+ *
+ * @file
+ * @ingroup Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class SiteArray extends GenericArrayObject implements SiteList {
+
+       /**
+        * Internal site identifiers pointing to their sites offset value.
+        *
+        * @since 1.21
+        *
+        * @var array of integer
+        */
+       protected $byInternalId = array();
+
+       /**
+        * Global site identifiers pointing to their sites offset value.
+        *
+        * @since 1.21
+        *
+        * @var array of string
+        */
+       protected $byGlobalId = array();
+
+       /**
+        * @see GenericArrayObject::getObjectType
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getObjectType() {
+               return 'Site';
+       }
+
+       /**
+        * @see GenericArrayObject::preSetElement
+        *
+        * @since 1.21
+        *
+        * @param int|string $index
+        * @param Site $site
+        *
+        * @return boolean
+        */
+       protected function preSetElement( $index, $site ) {
+               if ( $this->hasSite( $site->getGlobalId() ) ) {
+                       $this->removeSite( $site->getGlobalId() );
+               }
+
+               $this->byGlobalId[$site->getGlobalId()] = $index;
+               $this->byInternalId[$site->getInternalId()] = $index;
+
+               return true;
+       }
+
+       /**
+        * @see ArrayObject::offsetUnset()
+        *
+        * @since 1.21
+        *
+        * @param mixed $index
+        */
+       public function offsetUnset( $index ) {
+               /**
+                * @var Site $site
+                */
+               $site = $this->offsetGet( $index );
+
+               if ( $site !== false ) {
+                       unset( $this->byGlobalId[$site->getGlobalId()] );
+                       unset( $this->byInternalId[$site->getInternalId()] );
+               }
+
+               parent::offsetUnset( $index );
+       }
+
+       /**
+        * @see SiteList::getGlobalIdentifiers
+        *
+        * @since 1.21
+        *
+        * @return array
+        */
+       public function getGlobalIdentifiers() {
+               return array_keys( $this->byGlobalId );
+       }
+
+       /**
+        * @see SiteList::hasSite
+        *
+        * @param string $globalSiteId
+        *
+        * @return boolean
+        */
+       public function hasSite( $globalSiteId ) {
+               return array_key_exists( $globalSiteId, $this->byGlobalId );
+       }
+
+       /**
+        * @see SiteList::getSite
+        *
+        * @since 1.21
+        *
+        * @param string $globalSiteId
+        *
+        * @return Site
+        */
+       public function getSite( $globalSiteId ) {
+               return $this->offsetGet( $this->byGlobalId[$globalSiteId] );
+       }
+
+       /**
+        * @see SiteList::removeSite
+        *
+        * @since 1.21
+        *
+        * @param string $globalSiteId
+        */
+       public function removeSite( $globalSiteId ) {
+               $this->offsetUnset( $this->byGlobalId[$globalSiteId] );
+       }
+
+       /**
+        * @see SiteList::isEmpty
+        *
+        * @since 1.21
+        *
+        * @return boolean
+        */
+       public function isEmpty() {
+               return $this->byGlobalId === array();
+       }
+
+       /**
+        * @see SiteList::hasInternalId
+        *
+        * @param integer $id
+        *
+        * @return boolean
+        */
+       public function hasInternalId( $id ) {
+               return array_key_exists( $id, $this->byInternalId );
+       }
+
+       /**
+        * @see SiteList::getSiteByInternalId
+        *
+        * @since 1.21
+        *
+        * @param integer $id
+        *
+        * @return Site
+        */
+       public function getSiteByInternalId( $id ) {
+               return $this->offsetGet( $this->byInternalId[$id] );
+       }
+
+       /**
+        * @see SiteList::removeSiteByInternalId
+        *
+        * @since 1.21
+        *
+        * @param integer $id
+        */
+       public function removeSiteByInternalId( $id ) {
+               $this->offsetUnset( $this->byInternalId[$id] );
+       }
+
+       /**
+        * @see SiteList::setSite
+        *
+        * @since 1.21
+        *
+        * @param Site $site
+        */
+       public function setSite( Site $site ) {
+               $this[] = $site;
+       }
+
+}
diff --git a/includes/site/SiteList.php b/includes/site/SiteList.php
new file mode 100644 (file)
index 0000000..68bd106
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * Interface for lists of Site objects.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @since 1.21
+ *
+ * @file
+ * @ingroup Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+interface SiteList extends Countable, Traversable, Serializable, ArrayAccess {
+
+       /**
+        * Returns all the global site identifiers.
+        * Optionally only those belonging to the specified group.
+        *
+        * @since 1.21
+        *
+        * @return array
+        */
+       public function getGlobalIdentifiers();
+
+       /**
+        * Returns if the list contains the site with the provided global site identifier.
+        *
+        * @param string $globalSiteId
+        *
+        * @return boolean
+        */
+       public function hasSite( $globalSiteId );
+
+       /**
+        * Returns the Site with the provided global site identifier.
+        * The site needs to exist, so if not sure, call hasGlobalId first.
+        *
+        * @since 1.21
+        *
+        * @param string $globalSiteId
+        *
+        * @return Site
+        */
+       public function getSite( $globalSiteId );
+
+       /**
+        * Removes the site with the specified global site identifier.
+        * The site needs to exist, so if not sure, call hasGlobalId first.
+        *
+        * @since 1.21
+        *
+        * @param string $globalSiteId
+        */
+       public function removeSite( $globalSiteId );
+
+       /**
+        * Returns if the list contains the site with the provided site id.
+        *
+        * @param integer $id
+        *
+        * @return boolean
+        */
+       public function hasInternalId( $id );
+
+       /**
+        * Returns the Site with the provided site id.
+        * The site needs to exist, so if not sure, call has first.
+        *
+        * @since 1.21
+        *
+        * @param integer $id
+        *
+        * @return Site
+        */
+       public function getSiteByInternalId( $id );
+
+       /**
+        * Removes the site with the specified site id.
+        * The site needs to exist, so if not sure, call has first.
+        *
+        * @since 1.21
+        *
+        * @param integer $id
+        */
+       public function removeSiteByInternalId( $id );
+
+       /**
+        * Sets a site in the list. If the site was not there,
+        * it will be added. If it was, it will be updated.
+        *
+        * @since 1.21
+        *
+        * @param Site $site
+        */
+       public function setSite( Site $site );
+
+       /**
+        * Returns if the site list contains no sites.
+        *
+        * @since 1.21
+        *
+        * @return boolean
+        */
+       public function isEmpty();
+
+}
\ No newline at end of file
diff --git a/includes/site/SiteObject.php b/includes/site/SiteObject.php
new file mode 100644 (file)
index 0000000..7f143d1
--- /dev/null
@@ -0,0 +1,537 @@
+<?php
+
+/**
+ * Class representing a single site.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @since 1.21
+ *
+ * @file
+ * @ingroup Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author Daniel Werner
+ */
+class SiteObject extends ORMRow implements Site {
+
+       const PATH_LINK = 'link';
+
+       /**
+        * Holds the local ids for this site.
+        * You can obtain them via @see getLocalIds
+        *
+        * @since 1.21
+        *
+        * @var array|false
+        */
+       protected $localIds = false;
+
+       /**
+        * @see Site::getGlobalId
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getGlobalId() {
+               return $this->getField( 'global_key' );
+       }
+
+       /**
+        * @see Site::setGlobalId
+        *
+        * @since 1.21
+        *
+        * @param string $globalId
+        */
+       public function setGlobalId( $globalId ) {
+               $this->setField( 'global_key', $globalId );
+       }
+
+       /**
+        * @see Site::getType
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getType() {
+               return $this->getField( 'type' );
+       }
+
+       /**
+        * @see Site::setType
+        *
+        * @since 1.21
+        *
+        * @param string $type
+        */
+       public function setType( $type ) {
+               $this->setField( 'type', $type );
+       }
+
+       /**
+        * @see Site::getGroup
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getGroup() {
+               return $this->getField( 'group' );
+       }
+
+       /**
+        * @see Site::setGroup
+        *
+        * @since 1.21
+        *
+        * @param string $group
+        */
+       public function setGroup( $group ) {
+               $this->setField( 'group', $group );
+       }
+
+       /**
+        * @see Site::getSource
+        *
+        * @since 1.21
+        *
+        * @return string
+        */
+       public function getSource() {
+               return $this->getField( 'source' );
+       }
+
+       /**
+        * @see Site::setSource
+        *
+        * @since 1.21
+        *
+        * @param string $source
+        */
+       public function setSource( $source ) {
+               $this->setField( 'source', $source );
+       }
+
+       /**
+        * @see Site::getDomain
+        *
+        * @since 1.21
+        *
+        * @return string|false
+        */
+       public function getDomain() {
+               $path = $this->getLinkPath();
+
+               if ( $path === false ) {
+                       return false;
+               }
+
+               return parse_url( $path, PHP_URL_HOST );
+       }
+
+       /**
+        * @see Site::getProtocol
+        *
+        * @since 1.21
+        *
+        * @return string|false
+        */
+       public function getProtocol() {
+               $path = $this->getLinkPath();
+
+               if ( $path === false ) {
+                       return false;
+               }
+
+               return parse_url( $path, PHP_URL_SCHEME );
+       }
+
+       /**
+        * Sets the path used to construct links with.
+        * @see Site::setLinkPath
+        *
+        * @param string $fullUrl
+        *
+        * @since 1.21
+        *
+        * @throws MWException
+        */
+       public function setLinkPath( $fullUrl ) {
+               $type = $this->getLinkPathType();
+
+               if ( $type === false ) {
+                       throw new MWException( "This SiteObject does not support link paths." );
+               }
+
+               $this->setPath( $type, $fullUrl );
+       }
+
+       /**
+        * Returns the path path used to construct links with or false if there is no such path.
+        *
+        * @see Site::getLinkPath
+        *
+        * @return string|false
+        */
+       public function getLinkPath() {
+               $type = $this->getLinkPathType();
+               return $type === false ? false : $this->getPath( $type );
+       }
+
+       /**
+        * @see Site::getLinkPathType
+        *
+        * Returns the main path type, that is the type of the path that should generally be used to construct links
+        * to the target site.
+        *
+        * This default implementation returns SiteObject::PATH_LINK as the default path type. Subclasses can override this
+        * to define a different default path type, or return false to disable site links.
+        *
+        * @since 1.21
+        *
+        * @return string|false
+        */
+       public function getLinkPathType() {
+               return self::PATH_LINK;
+       }
+
+       /**
+        * @see Site::getPageUrl
+        *
+        * This implementation returns a URL constructed using the path returned by getLinkPath().
+        *
+        * @since 1.21
+        *
+        * @param bool|String $pageName
+        *
+        * @return string|false
+        */
+       public function getPageUrl( $pageName = false ) {
+               $url = $this->getLinkPath();
+
+               if ( $url === false ) {
+                       return false;
+               }
+
+               if ( $pageName !== false ) {
+                       $url = str_replace( '$1', rawurlencode( $pageName ), $url ) ;
+               }
+
+               return $url;
+       }
+
+       /**
+        * Returns $pageName without changes.
+        * Subclasses may override this to apply some kind of normalization.
+        *
+        * @see Site::normalizePageName
+        *
+        * @since 1.21
+        *
+        * @param string $pageName
+        *
+        * @return string
+        */
+       public function normalizePageName( $pageName ) {
+               return $pageName;
+       }
+
+       /**
+        * Returns the value of a type specific field, or the value
+        * of the $default parameter in case it's not set.
+        *
+        * @since 1.21
+        *
+        * @param string $fieldName
+        * @param mixed $default
+        *
+        * @return array
+        */
+       protected function getExtraData( $fieldName, $default = null ) {
+               $data = $this->getField( 'data', array() );
+               return array_key_exists( $fieldName,$data ) ? $data[$fieldName] : $default;
+       }
+
+       /**
+        * Sets the value of a type specific field.
+        * @since 1.21
+        *
+        * @param string $fieldName
+        * @param mixed $value
+        */
+       protected function setExtraData( $fieldName, $value = null ) {
+               $data = $this->getField( 'data', array() );
+               $data[$fieldName] = $value;
+               $this->setField( 'data', $data );
+       }
+
+       /**
+        * @see Site::getLanguageCode
+        *
+        * @since 1.21
+        *
+        * @return string|false
+        */
+       public function getLanguageCode() {
+               return $this->getField( 'language', false );
+       }
+
+       /**
+        * @see Site::setLanguageCode
+        *
+        * @since 1.21
+        *
+        * @param string $languageCode
+        */
+       public function setLanguageCode( $languageCode ) {
+               $this->setField( 'language', $languageCode );
+       }
+
+       /**
+        * Returns the local identifiers of this site.
+        *
+        * @since 1.21
+        *
+        * @param string $type
+        *
+        * @return array
+        */
+       protected function getLocalIds( $type ) {
+               if ( $this->localIds === false ) {
+                       $this->loadLocalIds();
+               }
+
+               return array_key_exists( $type, $this->localIds ) ? $this->localIds[$type] : array();
+       }
+
+       /**
+        * Loads the local ids for the site.
+        *
+        * @since 1.21
+        */
+       protected function loadLocalIds() {
+               $dbr = wfGetDB( $this->getTable()->getReadDb() );
+
+               $ids = $dbr->select(
+                       'site_identifiers',
+                       array(
+                               'si_type',
+                               'si_key',
+                       ),
+                       array(
+                               'si_site' => $this->getId(),
+                       ),
+                       __METHOD__
+               );
+
+               $this->localIds = array();
+
+               foreach ( $ids as $id ) {
+                       $this->addLocalId( $id->si_type, $id->si_key );
+               }
+       }
+
+       /**
+        * Adds a local identifier.
+        *
+        * @since 1.21
+        *
+        * @param string $type
+        * @param string $identifier
+        */
+       public function addLocalId( $type, $identifier ) {
+               if ( $this->localIds === false ) {
+                       $this->localIds = array();
+               }
+
+               if ( !array_key_exists( $type, $this->localIds ) ) {
+                       $this->localIds[$type] = array();
+               }
+
+               if ( !in_array( $identifier, $this->localIds[$type] ) ) {
+                       $this->localIds[$type][] = $identifier;
+               }
+       }
+
+       /**
+        * @see Site::addInterwikiId
+        *
+        * @since 1.21
+        *
+        * @param string $identifier
+        */
+       public function addInterwikiId( $identifier ) {
+               $this->addLocalId( 'interwiki', $identifier );
+       }
+
+       /**
+        * @see Site::addNavigationId
+        *
+        * @since 1.21
+        *
+        * @param string $identifier
+        */
+       public function addNavigationId( $identifier ) {
+               $this->addLocalId( 'equivalent', $identifier );
+       }
+
+       /**
+        * @see Site::getInterwikiIds
+        *
+        * @since 1.21
+        *
+        * @return array of string
+        */
+       public function getInterwikiIds() {
+               return $this->getLocalIds( 'interwiki' );
+       }
+
+       /**
+        * @see Site::getNavigationIds
+        *
+        * @since 1.21
+        *
+        * @return array of string
+        */
+       public function getNavigationIds() {
+               return $this->getLocalIds( 'equivalent' );
+       }
+
+       /**
+        * @see Site::getInternalId
+        *
+        * @since 1.21
+        *
+        * @return integer
+        */
+       public function getInternalId() {
+               return $this->getId();
+       }
+
+       /**
+        * @see ORMRow::save
+        * @see Site::save
+        *
+        * @since 1.21
+        *
+        * @param string|null $functionName
+        *
+        * @return boolean Success indicator
+        */
+       public function save( $functionName = null ) {
+               $dbw = wfGetDB( DB_MASTER );
+
+               $trx = $dbw->trxLevel();
+
+               if ( $trx == 0 ) {
+                       $dbw->begin( __METHOD__ );
+               }
+
+               $this->setField( 'protocol', $this->getProtocol() );
+               $this->setField( 'domain', strrev( $this->getDomain() ) . '.' );
+
+               $existedAlready = $this->hasIdField();
+
+               $success = parent::save( $functionName );
+
+               if ( $success && $existedAlready ) {
+                       $dbw->delete(
+                               'site_identifiers',
+                               array( 'si_site' => $this->getId() ),
+                               __METHOD__
+                       );
+               }
+
+               if ( $success && $this->localIds !== false ) {
+                       foreach ( $this->localIds as $type => $ids ) {
+                               foreach ( $ids as $id ) {
+                                       $dbw->insert(
+                                               'site_identifiers',
+                                               array(
+                                                       'si_site' => $this->getId(),
+                                                       'si_type' => $type,
+                                                       'si_key' => $id,
+                                               ),
+                                               __METHOD__
+                                       );
+                               }
+                       }
+               }
+
+               if ( $trx == 0 ) {
+                       $dbw->commit( __METHOD__ );
+               }
+
+               return $success;
+       }
+
+       /**
+        * @see Site::setPath
+        *
+        * @since 1.21
+        *
+        * @param string $pathType
+        * @param string $fullUrl
+        */
+       public function setPath( $pathType, $fullUrl ) {
+               $paths = $this->getExtraData( 'paths', array() );
+               $paths[$pathType] = $fullUrl;
+               $this->setExtraData( 'paths', $paths );
+       }
+
+       /**
+        * @see Sitres::getPath
+        *
+        * @since 1.21
+        *
+        * @param string $pathType
+        *
+        * @return string|false
+        */
+       public function getPath( $pathType ) {
+               $paths = $this->getExtraData( 'paths', array() );
+               return array_key_exists( $pathType, $paths ) ? $paths[$pathType] : false;
+       }
+
+       /**
+        * @see Sitres::getAll
+        *
+        * @since 1.21
+        *
+        * @return array of string
+        */
+       public function getAllPaths() {
+               return $this->getExtraData( 'paths', array() );
+       }
+
+       /**
+        * @see Sitres::removePath
+        *
+        * @since 1.21
+        *
+        * @param string $pathType
+        */
+       public function removePath( $pathType ) {
+               $paths = $this->getExtraData( 'paths', array() );
+               unset( $paths[$pathType] );
+               $this->setExtraData( 'paths', $paths );
+       }
+
+}
diff --git a/includes/site/Sites.php b/includes/site/Sites.php
new file mode 100644 (file)
index 0000000..9e87ed9
--- /dev/null
@@ -0,0 +1,194 @@
+<?php
+
+/**
+ * Represents the site configuration of a wiki.
+ * Holds a list of sites (ie SiteList) and takes care
+ * of retrieving and caching site information when appropriate.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @since 1.21
+ *
+ * @file
+ * @ingroup Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class Sites {
+
+       /**
+        * @since 1.21
+        * @var SiteList|false
+        */
+       protected $sites = false;
+
+       /**
+        * Constructor.
+        *
+        * @since 1.21
+        */
+       protected function __construct() {}
+
+       /**
+        * Returns an instance of Sites.
+        *
+        * @since 1.21
+        *
+        * @return Sites
+        */
+       public static function singleton() {
+               static $instance = false;
+
+               if ( $instance === false ) {
+                       $instance = new static();
+               }
+
+               return $instance;
+       }
+
+       /**
+        * Factory for creating new site objects.
+        *
+        * @since 1.21
+        *
+        * @param string|false $globalId
+        *
+        * @return Site
+        */
+       public static function newSite( $globalId = false ) {
+               /**
+                * @var Site $site
+                */
+               $site = SitesTable::singleton()->newRow( array(), true );
+
+               if ( $globalId !== false ) {
+                       $site->setGlobalId( $globalId );
+               }
+
+               return $site;
+       }
+
+       /**
+        * Returns a list of all sites. By default this site is
+        * fetched from the cache, which can be changed to loading
+        * the list from the database using the $useCache parameter.
+        *
+        * @since 1.21
+        *
+        * @param string $source either 'cache' or 'recache'
+        *
+        * @return SiteList
+        */
+       public function getSites( $source = 'cache' ) {
+               if ( $source === 'cache' ) {
+                       if ( $this->sites === false ) {
+                               $cache = wfGetMainCache();
+                               $sites = $cache->get( 'sites-cache' );
+
+                               if ( is_object( $sites ) ) {
+                                       $this->sites = $sites;
+                               }
+                               else {
+                                       $this->loadSites();
+                               }
+                       }
+               }
+               else {
+                       $this->loadSites();
+               }
+
+               return $this->sites;
+       }
+
+       /**
+        * Returns a list of sites in the given group. Calling getGroup() on any of
+        * the sites in the resulting SiteList shall return $group.
+        *
+        * @since 1.21
+        *
+        * @param string $group th group to get.
+        *
+        * @return SiteList
+        */
+       public function getSiteGroup( $group ) {
+               $sites = self::getSites();
+
+               $siteGroup = new SiteArray();
+
+               /* @var Site $site */
+               foreach ( $sites as $site ) {
+                       if ( $site->getGroup() == $group ) {
+                               $siteGroup->append( $site );
+                       }
+               }
+
+               return $siteGroup;
+       }
+
+       /**
+        * Fetches the site from the database and loads them into the sites field.
+        *
+        * @since 1.21
+        */
+       protected function loadSites() {
+               $this->sites = new SiteArray( SitesTable::singleton()->select() );
+
+               // Batch load the local site identifiers.
+               $dbr = wfGetDB( SitesTable::singleton()->getReadDb() );
+
+               $ids = $dbr->select(
+                       'site_identifiers',
+                       array(
+                               'si_site',
+                               'si_type',
+                               'si_key',
+                       ),
+                       array(),
+                       __METHOD__
+               );
+
+               foreach ( $ids as $id ) {
+                       if ( $this->sites->hasInternalId( $id->si_site ) ) {
+                               $site = $this->sites->getSiteByInternalId( $id->si_site );
+                               $site->addLocalId( $id->si_type, $id->si_key );
+                               $this->sites->setSite( $site );
+                       }
+               }
+
+               $cache = wfGetMainCache();
+               $cache->set( 'sites-cache', $this->sites );
+       }
+
+       /**
+        * Returns the site with provided global id, or false if there is no such site.
+        *
+        * @since 1.21
+        *
+        * @param string $globalId
+        * @param string $source
+        *
+        * @return Site|false
+        */
+       public function getSite( $globalId, $source = 'cache' ) {
+               if ( $source === 'cache' && $this->sites !== false ) {
+                       return $this->sites->hasSite( $globalId ) ? $this->sites->getSite( $globalId ) : false;
+               }
+
+               return SitesTable::singleton()->selectRow( null, array( 'global_key' => $globalId ) );
+       }
+
+}
diff --git a/includes/site/SitesTable.php b/includes/site/SitesTable.php
new file mode 100644 (file)
index 0000000..71e55f8
--- /dev/null
@@ -0,0 +1,135 @@
+<?php
+
+/**
+ * Represents the sites database table.
+ * All access to this table should be done through this class.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @since 1.21
+ *
+ * @file
+ * @ingroup Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class SitesTable extends ORMTable {
+
+       /**
+        * @see IORMTable::getName()
+        * @since 1.21
+        * @return string
+        */
+       public function getName() {
+               return 'sites';
+       }
+
+       /**
+        * @see IORMTable::getFieldPrefix()
+        * @since 1.21
+        * @return string
+        */
+       public function getFieldPrefix() {
+               return 'site_';
+       }
+
+       /**
+        * @see IORMTable::getRowClass()
+        * @since 1.21
+        * @return string
+        */
+       public function getRowClass() {
+               return 'SiteObject';
+       }
+
+       /**
+        * @see IORMTable::getFields()
+        * @since 1.21
+        * @return array
+        */
+       public function getFields() {
+               return array(
+                       'id' => 'id',
+
+                       // Site data
+                       'global_key' => 'str',
+                       'type' => 'str',
+                       'group' => 'str',
+                       'source' => 'str',
+                       'language' => 'str',
+                       'protocol' => 'str',
+                       'domain' => 'str',
+                       'data' => 'array',
+
+                       // Site config
+                       'forward' => 'bool',
+                       'config' => 'array',
+               );
+       }
+
+       /**
+        * @see IORMTable::getDefaults()
+        * @since 1.21
+        * @return array
+        */
+       public function getDefaults() {
+               return array(
+                       'type' => Site::TYPE_UNKNOWN,
+                       'group' => Site::GROUP_NONE,
+                       'source' => Site::SOURCE_LOCAL,
+                       'data' => array(),
+
+                       'forward' => false,
+                       'config' => array(),
+               );
+       }
+
+       /**
+        * Returns the class name for the provided site type.
+        *
+        * @since 1.21
+        *
+        * @param integer $siteType
+        *
+        * @return string
+        */
+       protected static function getClassForType( $siteType ) {
+               global $wgSiteTypes;
+               return array_key_exists( $siteType, $wgSiteTypes ) ? $wgSiteTypes[$siteType] : 'SiteObject';
+       }
+
+       /**
+        * Factory method to construct a new Site instance.
+        *
+        * @since 1.21
+        *
+        * @param array $data
+        * @param boolean $loadDefaults
+        *
+        * @return Site
+        */
+       public function newRow( array $data, $loadDefaults = false ) {
+               if ( !array_key_exists( 'type', $data ) ) {
+                       $data['type'] = Site::TYPE_UNKNOWN;
+               }
+
+               $class = static::getClassForType( $data['type'] );
+
+               return new $class( $this, $data, $loadDefaults );
+       }
+
+}
\ No newline at end of file
index 09e850e..6016605 100644 (file)
@@ -1071,7 +1071,7 @@ class LanguageConverter {
         * @param $revision Object: new Revision object or null
         * @return Boolean: true
         */
-       function OnArticleContentSaveComplete( $page, $user, $content, $summary, $isMinor,
+       function OnPageContentSaveComplete( $page, $user, $content, $summary, $isMinor,
                        $isWatch, $section, $flags, $revision ) {
                $titleobj = $page->getTitle();
                if ( $titleobj->getNamespace() == NS_MEDIAWIKI ) {
index 0c8bd22..6482070 100644 (file)
@@ -116,7 +116,7 @@ class LanguageGan extends LanguageZh {
                                                                array(),
                                                                $ml );
 
-               $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+               $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
        }
 
        /**
index 3ff336b..79e5582 100644 (file)
@@ -233,6 +233,6 @@ class LanguageIu extends Language {
 
                $flags = array();
                $this->mConverter = new IuConverter( $this, 'iu', $variants, $variantfallbacks, $flags );
-               $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+               $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
        }
 }
index a7e5866..bdaf2f4 100644 (file)
@@ -440,7 +440,7 @@ class LanguageKk extends LanguageKk_cyrl {
 
                $this->mConverter = new KkConverter( $this, 'kk', $variants, $variantfallbacks );
 
-               $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+               $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
        }
 
        /**
index 9150663..0eac439 100644 (file)
@@ -273,6 +273,6 @@ class LanguageKu extends LanguageKu_ku {
                );
 
                $this->mConverter = new KuConverter( $this, 'ku', $variants, $variantfallbacks );
-               $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+               $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
        }
 }
index 335d551..4833d1c 100644 (file)
@@ -212,6 +212,6 @@ class LanguageShi extends Language {
 
                $flags = array();
                $this->mConverter = new ShiConverter( $this, 'shi', $variants, $variantfallbacks, $flags );
-               $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+               $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
        }
 }
index b043778..b472743 100644 (file)
@@ -246,7 +246,7 @@ class LanguageSr extends LanguageSr_ec {
                        'W' => 'W', 'реч'   => 'W', 'reč'   => 'W', 'ријеч' => 'W', 'riječ' => 'W'
                );
                $this->mConverter = new SrConverter( $this, 'sr', $variants, $variantfallbacks, $flags );
-               $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+               $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
        }
 
        /**
index 2db64a7..a2c917c 100644 (file)
@@ -132,6 +132,6 @@ class LanguageUz extends Language {
                );
 
                $this->mConverter = new UzConverter( $this, 'uz', $variants, $variantfallbacks );
-               $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+               $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
        }
 }
index 11cf0cf..8bf66a3 100644 (file)
@@ -146,7 +146,7 @@ class LanguageZh extends LanguageZh_hans {
                                                                array(),
                                                                $ml );
 
-               $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+               $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
        }
 
        /**
index 6314006..a2e739f 100644 (file)
@@ -192,7 +192,7 @@ $messages = array(
 'category-subcat-count-limited' => 'ܣܕܪܐ ܗܢܐ ܐܝܬ ܒܗ {{PLURAL:$1|ܣܕܪܐ ܦܪܥܝܐ ܗܢܐ|$1 ܣܕܪ̈ܐ ܦܪ̈ܥܝܐ ܗܠܝܢ}}.',
 'category-article-count' => '{{PLURAL:$2|ܣܕܪܐ ܗܢܐ ܐܝܬ ܒܗ ܦܐܬܐ ܗܕܐ ܒܠܚܘܕ.|ܐܝܬ {{PLURAL:$1|ܦܐܬܐ|$1 ܦܐܬܬ̈ܐ}} ܒܣܕܪܐ ܗܢܐ، ܡܢ ܣܘܝܟܐ ܕ$2.}}',
 'category-article-count-limited' => '{{PLURAL:$1|ܦܐܬܐ ܗܕܐ|$1 ܦܐܬܬ̈ܐ ܗܠܝܢ}} ܒܣܕܪܐ ܗܢܐ.',
-'category-file-count' => '{{PLURAL:$2|ܣܕܪܐ ܗܢܐ ܐܝܬ ܒܗ ܠܦܦܐ ܗܢܐ ܒܠܚܘܕ.|{{PLURAL:$1|ܠܦܦܐ ܕܐܬܐ ܐܝܬܘܗܝ|$1 ܠܦܦ̈ܐ ܕܐܬܝܢ ܐܝܬܝܗܘܢ}} ܒܣܕܪܐ ܗܢܐ، ܡܢ ܣܘܝܟܐ ܕ$2.}}',
+'category-file-count' => '{{PLURAL:$2|ܣܕܪܐ ܗܢܐ ܐܝܬ ܒܗ ܠܦܦܐ ܗܢܐ ܒܠܚܘܕ.|{{PLURAL:$1|ܠܦܦܐ ܕܐܬܐ ܐܝܬܘܗܝ|$1 ܠܦܦ̈ܐ ܕܐܬܝܢ ܐܝܬܝܗܘܢ}} ܒܣܕܪܐ ܗܢܐ، ܡܢ ܣܘܝܟܐ ܕ$2 ܟܠܢܐܝܬ.}}',
 'category-file-count-limited' => 'ܐܝܬ {{PLURAL:$1|ܠܦܦܐ ܕܐܬܐ|$1 ܠܦܦ̈ܐ ܕܐܬܝܢ}} ܒܣܕܪܐ ܗܫܝܐ.',
 'listingcontinuesabbrev' => '(ܫܘܠܡܐ)',
 
@@ -862,7 +862,7 @@ $1',
 'minlength1' => 'ܫܡܗ̈ܐ ܕܠܦܦܐ ܘܠܐ ܕܢܗܘܐ ܒܪܝܐ ܡܢ ܐܬܘܬܐ ܚܕܐ ܟܕ ܙܥܘܪ',
 'uploadwarning' => 'ܐܣܩ ܙܘܗܪܐ',
 'savefile' => 'ܠܒܘܟ ܠܦܦܐ',
-'uploadedimage' => '',
+'uploadedimage' => 'ܐܣܩ "[[$1]]"',
 'uploadvirus' => 'ܠܦܦܐ ܐܝܬ ܒܗ ܒܝܪܘܣ!
 ܐܪ̈ܝܟܬܐ: $1',
 'upload-source' => 'ܡܒܘܥܐ ܕܠܦܦܐ',
index 931a0b4..034df79 100644 (file)
@@ -1008,8 +1008,8 @@ El motiu donat per $3 és ''$2''",
 (prev) = diferència amb la versió anterior, m = modificació menor',
 'history-fieldset-title' => "Cerca a l'historial",
 'history-show-deleted' => 'Només esborrats',
-'histfirst' => 'El primer',
-'histlast' => 'El darrer',
+'histfirst' => 'Primeres',
+'histlast' => 'Últimes',
 'historysize' => '({{PLURAL:$1|1 octet|$1 octets}})',
 'historyempty' => '(buit)',
 
index ce8cf6e..2c9c6ad 100644 (file)
@@ -1119,6 +1119,15 @@ Zřejmě byla smazána.',
 'edit-no-change' => 'Vaše editace byla ignorována, protože nedošlo k žádné změně textu.',
 'edit-already-exists' => 'Nepodařilo se vytvořit novou stránku, protože již existuje.',
 'defaultmessagetext' => 'Výchozí text hlášení',
+'content-failed-to-parse' => 'Nepodařilo se zpracovat data $2 do modelu $1: $3',
+'invalid-content-data' => 'Obsažená data jsou chybná',
+'content-not-allowed-here' => 'Obsah typu $1 není na stránce [[$2]] dovolen.',
+
+# Content models
+'content-model-wikitext' => 'wikitext',
+'content-model-text' => 'čistý text',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Varování: Tato stránka obsahuje příliš mnoho volání výkonnostně náročných funkcí parseru.
@@ -2554,7 +2563,8 @@ Pro částečné obnovení zaškrtněte čtverečky u obnovovaných revizí a kl
 'undeletedrevisions' => '{{PLURAL:$1|Obnovena $1 verze|Obnoveny $1 verze|Obnoveno $1 verzí}}',
 'undeletedrevisions-files' => '{{PLURAL:$1|Obnovena jedna verze|Obnoveny $1 verze|Obnoveno $1 verzí}} a $2 {{PLURAL:$2|soubor|soubory|souborů}}.',
 'undeletedfiles' => '{{PLURAL:$1|obnoven $1 soubor|obnoveny $1 soubory|obnoveno $1 souborů}}',
-'cannotundelete' => 'Obnovení se nepovedlo; stránku již pravděpodobně obnovil někdo jiný.',
+'cannotundelete' => 'Obnovení se nezdařilo:
+$1',
 'undeletedpage' => "'''$1 byla obnovena'''
 
 Záznam o posledních mazáních a obnoveních najdete v [[Special:Log/delete|knize smazaných stránek]].",
@@ -2848,6 +2858,7 @@ Cílová stránka „[[:$1]]“ již existuje. Přejete si ji smazat pro uvolně
 'immobile-target-namespace-iw' => 'Mezijazykový odkaz není validní cíl při přesouvání stránky.',
 'immobile-source-page' => 'Tuto stránku nelze přesouvat.',
 'immobile-target-page' => 'Stránku nelze přesunout na zadaný název.',
+'bad-target-model' => 'Požadovaný cíl používá jiný model obsahu. Nelze převést $1 na $2.',
 'imagenocrossnamespace' => 'Nelze přesunout mimo jmenný prostor Soubor:',
 'nonfile-cannot-move-to-file' => 'Do jmenného prostoru {{ns:file}} nelze přesouvat stránky nepřináležející k souboru',
 'imagetypemismatch' => 'Nová přípona souboru neodpovídá jeho typu',
index 74ce9f5..12ec1c5 100644 (file)
@@ -2611,7 +2611,7 @@ Der aktuelle Text der gelöschten Seite ist nur Administratoren zugänglich.',
 'undeletedrevisions' => '{{PLURAL:$1|1 Version wurde|$1 Versionen wurden}} wiederhergestellt',
 'undeletedrevisions-files' => '{{PLURAL:$1|1 Version|$1 Versionen}} und {{PLURAL:$2|1 Datei|$2 Dateien}} wurden wiederhergestellt',
 'undeletedfiles' => '{{PLURAL:$1|1 Datei wurde|$1 Dateien wurden}} wiederhergestellt',
-'cannotundelete' => 'Wiederherstellung fehlgeschlagen:
+'cannotundelete' => 'Die Wiederherstellung ist fehlgeschlagen:
 $1',
 'undeletedpage' => "'''„$1“''' wurde wiederhergestellt.
 
@@ -2910,6 +2910,7 @@ Eine Seite kann nicht auf sich selbst verschoben werden.',
 'immobile-target-namespace-iw' => 'Interwiki-Link ist kein gültiges Ziel für Seitenverschiebungen.',
 'immobile-source-page' => 'Diese Seite ist nicht verschiebbar.',
 'immobile-target-page' => 'Es kann nicht auf diese Zielseite verschoben werden.',
+'bad-target-model' => 'Die gewünschte Zielseite verwendet ein abweichendes Inhaltsmodell. Das Inhaltsmodell $1 kann nicht in das Inhaltsmodell $2 umgewandelt werden.',
 'imagenocrossnamespace' => 'Dateien können nicht aus dem {{ns:file}}-Namensraum heraus verschoben werden',
 'nonfile-cannot-move-to-file' => 'Nichtdateien können nicht in den {{ns:file}}-Namensraum hinein verschoben werden',
 'imagetypemismatch' => 'Die neue Dateierweiterung ist nicht mit der alten identisch',
@@ -4133,6 +4134,4 @@ 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
-'bad-target-model' => 'Die gewünschte Zielseite verwendet ein abweichendes Inhaltsmodell. Das Inhaltsmodell $1 kann nicht in das Inhaltsmodell $2 umgewandelt werden.',
 );
index bd5de5c..158e138 100644 (file)
@@ -2536,7 +2536,8 @@ Revizyoni ya hewn a biyê ya arşiw ra veciyayê ya zi cıresayişê şımayi ş
 'undeletedrevisions' => 'pêro piya{{PLURAL:$1|1 qeyd|$1 qeyd}} tepiya anciya.',
 'undeletedrevisions-files' => '{{PLURAL:$1|1 revizyon|$1 revizyon}} u {{PLURAL:$2|1 dosya|$2 dosya}} ameyê halê xo yê verıni',
 'undeletedfiles' => '{{PLURAL:$1|1 dosya|$1 dosya}} tepiya anciyayi.',
-'cannotundelete' => 'şıma ya ver yewna ten pel u medya tepiya ard u ê ra tepiya ardışê şıma meqbul niyo.',
+'cannotundelete' => 'Besternayışo nêbeno:
+$1',
 'undeletedpage' => "'''$1 pel tepiya anciya'''
 
 qey karê tepiya ardışi u qey karê hewn a kerdışê verıni bıewnê [[Special:Log/delete|qeydê hewn a kerdışi]].",
@@ -2842,6 +2843,7 @@ Yewna name bınus.',
 'immobile-target-namespace-iw' => 'xetê benatê wikiyan, hedefê pelkırıştış niyo',
 'immobile-source-page' => 'nameyê no peli nêvuriyeno',
 'immobile-target-page' => 'sernameyê no hedefi re nêkırışiyeno',
+'bad-target-model' => 'Hedefo ke waştiyayo zerreke cı babetna model karneno. Ke nêşeno $1 ra açarno $2.',
 'imagenocrossnamespace' => 'Dosya, ca yo ke qey nameyê dosyayan nêbıbo nêkırışiyeno',
 'nonfile-cannot-move-to-file' => 'Ekê dosya niyê, cade namande dosyaya nêahulneyênê',
 'imagetypemismatch' => 'tipa dosyaya neweyi re pênêgıneno/nêgıneno pê',
@@ -4729,6 +4731,4 @@ Ena sita dı newke xırabiya teknik esta.',
 'duration-centuries' => '$1 {{PLURAL:$1|seserre|seserri}}',
 'duration-millennia' => '$1 {{PLURAL:$1|milenyum|milenyumi}}',
 
-# Unknown messages
-'bad-target-model' => 'Hedefo ke waştiyayo zerreke cı babetna model karneno. Ke nêşeno $1 ra açarno $2.',
 );
index bf2393c..cb60050 100644 (file)
@@ -898,6 +898,15 @@ Zda sem až jo wulašowany.',
 'edit-already-exists' => 'Njejo móžno było nowy bok napóraś.
 Eksistěrujo južo.',
 'defaultmessagetext' => 'Standardny tekst powěźeńki',
+'content-failed-to-parse' => 'Parsowanje wopśimjeśa $2 za model $1 jo se njeraźiło: $3',
+'invalid-content-data' => 'Njepłaśiwe wopśimjeśowe daty',
+'content-not-allowed-here' => 'Wopśimjeśe "$1" njejo na boku [[$2]] dowólone',
+
+# Content models
+'content-model-wikitext' => 'wikitekst',
+'content-model-text' => 'lutny tekst',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Warnowanje: Toś ten bok wopśimujo pśewjele wołanjow parserowych funkcijow wupominajucych wusoke wugbaśe.
@@ -2324,7 +2333,8 @@ W takich padach dejš nejnowše wulašowane wersije markěroanje abo schowanje w
 'undeletedrevisions' => '{{PLURAL:$1|1 wersija jo se nawrośiła|$1 wersiji stej se nawrośiłej|$1 wersije su se nawrośili}}.',
 'undeletedrevisions-files' => '{{PLURAL:$1|1 wersija|$1 wersiji|$1 wersije}} a {{PLURAL:$2|1 dataja|$2 dataji|$2 dataje}} {{PLURAL:$2|jo se nawrośiła|stej se nawrośiłej|su se nawrośili}}.',
 'undeletedfiles' => '{{PLURAL:$1|1 dataja jo se nawrośiła|$1 dataji stej se nawrośiłej|$1 dataje su se nawrośili}}.',
-'cannotundelete' => 'Nawrośenje njejo se zglucyło; něchten drugi jo bok južo nawrośił.',
+'cannotundelete' => 'Wótnowjenje jo se njeraźiło:
+$1',
 'undeletedpage' => "Bok '''$1''' jo se nawrośił.
 
 W [[Special:Log/delete|log-lisćinje wulašowanjow]] namakajoš pśeglěd wulašowanych a nawrośonych bokow.",
@@ -2614,6 +2624,7 @@ Bok „[[:$1]]“ južo eksistěrujo. Coš jen wulašowaś, aby mógał toś ten
 'immobile-target-namespace-iw' => 'Interwiki-wótkaz njejo płaśiwy cel za pśesunjenja bokow.',
 'immobile-source-page' => 'Toś ten bok njedajo se pśesunuś.',
 'immobile-target-page' => 'Njejo móžno na toś ten celowy bok pśesunuś.',
+'bad-target-model' => 'Póžedany cel wužywa drugi wopśimjeśowy model. $1 njedajo se do $2 konwertěrowaś.',
 'imagenocrossnamespace' => 'Dataja njedajo se pśesunuś do mjenjowego ruma, kótarež njejo za dataje.',
 'nonfile-cannot-move-to-file' => 'Njedataje njedaje se do datajowego mjenjowego ruma pśesunuś',
 'imagetypemismatch' => 'Nowy datajowy sufiks swójomu typoju njewótpowědujo',
index b02562f..729edf0 100644 (file)
@@ -1050,6 +1050,11 @@ Se on ilmeisesti poistettu.',
 'edit-already-exists' => 'Uuden sivun luominen ei onnistunut.
 Se on jo olemassa.',
 'defaultmessagetext' => 'Viestin oletusteksti',
+'content-not-allowed-here' => '$1 ei ole sallittua sisältöä sivulla [[$2]]',
+
+# Content models
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Tällä sivulla on liian monta hitaiden laajennusfunktioiden kutsua.
@@ -2465,7 +2470,8 @@ Tiedostoversioita, joihin sinulla ei ole katseluoikeutta (''häivytetyt versiot'
 'undeletedrevisions' => '{{PLURAL:$1|Yksi versio|$1 versiota}} palautettiin',
 'undeletedrevisions-files' => '{{PLURAL:$1|Yksi versio|$1 versiota}} ja {{PLURAL:$2|yksi tiedosto|$2 tiedostoa}} palautettiin',
 'undeletedfiles' => '{{PLURAL:$1|1 tiedosto|$1 tiedostoa}} palautettiin',
-'cannotundelete' => 'Palauttaminen epäonnistui; joku muu on voinut jo palauttaa sivun.',
+'cannotundelete' => 'Palauttaminen epäonnistui:
+$1',
 'undeletedpage' => "'''$1 on palautettu.'''
 
 [[Special:Log/delete|Poistolokista]] löydät listan viimeisimmistä poistoista ja palautuksista.",
index d21a9d2..e7e025e 100644 (file)
@@ -1135,6 +1135,15 @@ Il semble qu’elle ait été supprimée.',
 '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',
+'content-not-allowed-here' => 'Le contenu "$1" n\'est pas autorisé sur la page [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'wikitexte',
+'content-model-text' => 'texte brut',
+'content-model-javascript' => 'JavaScript',
+'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.
@@ -2589,8 +2598,8 @@ Vous avez peut-être un mauvais lien, ou la version a pu être restaurée ou sup
 'undeletedrevisions' => '$1 {{PLURAL:$1|version restaurée|versions restaurées}}',
 'undeletedrevisions-files' => '$1 version{{PLURAL:$1||s}} et $2 fichier{{PLURAL:$2||s}} restauré{{PLURAL:$2||s}}',
 'undeletedfiles' => '$1 {{PLURAL:$1|fichier restauré|fichiers restaurés}}',
-'cannotundelete' => 'La restauration a échoué ;
-un autre utilisateur a probablement déjà restauré la page.',
+'cannotundelete' => 'Échec de la restauration:
+$1',
 'undeletedpage' => "'''La page $1 a été restaurée.'''
 
 Consultez le [[Special:Log/delete|journal des suppressions]] pour obtenir la liste des récentes suppressions et restaurations.",
@@ -2889,6 +2898,7 @@ impossible de renommer une page sur elle-même.',
 'immobile-target-namespace-iw' => 'Les destinations interwikis ne sont pas une cible valide pour les déplacements.',
 'immobile-source-page' => 'Cette page n’est pas renommable.',
 'immobile-target-page' => 'Il n’est pas possible de renommer la page vers ce titre.',
+'bad-target-model' => 'La destination souhaitée utilise un autre modèle de contenu. Impossible de convertir de $1 vers $2.',
 'imagenocrossnamespace' => 'Impossible de renommer un fichier vers un espace de noms autre que fichier.',
 'nonfile-cannot-move-to-file' => "Impossible de renommer quelque chose d’autre qu'un fichier vers l’espace de noms fichier.",
 'imagetypemismatch' => 'La nouvelle extension de ce fichier ne correspond pas à son type.',
index d994775..19a787c 100644 (file)
@@ -489,7 +489,7 @@ $1',
 'newmessagesdifflink' => 'diferenzas coa revisión anterior',
 'youhavenewmessagesfromusers' => 'Ten $1 {{PLURAL:$3|doutro usuario|de $3 usuarios}} ($2).',
 'youhavenewmessagesmanyusers' => 'Ten $1 de moitos usuarios ($2).',
-'newmessageslinkplural' => '{{PLURAL:$1|unha mensaxe nova|$1 mensaxes novas}}',
+'newmessageslinkplural' => '{{PLURAL:$1|unha mensaxe nova|mensaxes novas}}',
 'newmessagesdifflinkplural' => '{{PLURAL:$1|última modificación|últimas modificacións}}',
 'youhavenewmessagesmulti' => 'Ten mensaxes novas en $1',
 'editsection' => 'editar',
@@ -587,8 +587,8 @@ Se cadra, xa a borrou alguén.',
 'delete-hook-aborted' => 'O borrado foi abortado polo asociador.
 Este non deu ningunha explicación.',
 'badtitle' => 'Título incorrecto',
-'badtitletext' => 'O título da páxina pedida non era válido, estaba baleiro ou proviña dunha ligazón interlingua ou interwiki incorrecta.
-Pode conter un ou máis caracteres dos que non se poden empregar nos títulos.',
+'badtitletext' => 'O título da páxina pedida non era válido, estaba baleiro ou proviña dunha ligazón interlingüística ou interwiki incorrecta.
+Poida que conteña un ou máis caracteres dos que non se poden empregar nos títulos.',
 'perfcached' => 'Esta información é da memoria caché e pode ser que non estea completamente actualizada. Hai un máximo de {{PLURAL:$1|$1 resultado dispoñible|$1 resultados dispoñibles}} na caché.',
 'perfcachedts' => 'Esta información é da memoria caché. Última actualización: $2 ás $3. Hai un máximo de {{PLURAL:$4|$4 resultado dispoñible|$4 resultados dispoñibles}} na caché.',
 'querypage-no-updates' => 'Neste momento están desactivadas as actualizacións nesta páxina. O seu contido non se modificará.',
@@ -1013,6 +1013,15 @@ Semella que foi borrada.',
 'edit-already-exists' => 'Non se pode crear a nova páxina.
 Esta xa existe.',
 'defaultmessagetext' => 'Texto predeterminado',
+'content-failed-to-parse' => 'Erro ao analizar o contido de "$2" para o modelo de $1: $3',
+'invalid-content-data' => 'Datos de contido inválidos',
+'content-not-allowed-here' => 'O contido "$1" non está permitido na páxina "[[$2]]"',
+
+# Content models
+'content-model-wikitext' => 'texto wiki',
+'content-model-text' => 'texto simple',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''Aviso:''' Esta páxina contén demasiados analizadores de funcións de chamadas.
@@ -2141,7 +2150,8 @@ Pode precisar máis a vista seleccionando o tipo de rexistro, o nome do usuario
 'allpagesnext' => 'Seguinte',
 'allpagessubmit' => 'Mostrar',
 'allpagesprefix' => 'Mostrar as páxinas que comezan co prefixo:',
-'allpagesbadtitle' => 'O título dado á páxina non era válido ou contiña un prefixo inter-linguas ou inter-wikis. Pode que conteña un ou máis caracteres que non se poden empregar nos títulos.',
+'allpagesbadtitle' => 'O título dado á páxina non era válido ou tiña un prefixo interlingüístico ou interwiki.
+Poida que conteña un ou máis caracteres dos que non se poden empregar nos títulos.',
 'allpages-bad-ns' => '{{SITENAME}} carece do espazo de nomes "$1".',
 'allpages-hide-redirects' => 'Agochar as redireccións',
 
@@ -2481,7 +2491,8 @@ O texto destas revisións eliminadas só está á disposición dos administrador
 'undeletedrevisions' => '$1 {{PLURAL:$1|revisión restaurada|revisións restauradas}}',
 'undeletedrevisions-files' => '$1 {{PLURAL:$1|revisión|revisións}} e $2 {{PLURAL:$2|ficheiro restaurado|ficheiros restaurados}}',
 'undeletedfiles' => '$1 {{PLURAL:$1|ficheiro restaurado|ficheiros restaurados}}',
-'cannotundelete' => 'Non se restaurou a páxina porque alguén xa o fixo antes.',
+'cannotundelete' => 'Houbo un erro durante a restauración:
+$1',
 'undeletedpage' => "'''A páxina \"\$1\" foi restaurada'''
 
 Comprobe o [[Special:Log/delete|rexistro de borrados]] para ver as entradas recentes no rexistro de páxinas eliminadas e restauradas.",
@@ -2784,6 +2795,7 @@ Quérea borrar para deixar sitio para facer o traslado?',
 'immobile-target-namespace-iw' => 'A ligazón interwiki non é válida para o movemento da páxina.',
 'immobile-source-page' => 'Esta páxina non se pode mover.',
 'immobile-target-page' => 'Non se pode mover a ese título.',
+'bad-target-model' => 'O destino desexado utiliza un modelo de contido diferente. Non se pode facer a conversión entre $1 e $2.',
 'imagenocrossnamespace' => 'Non se pode mover o ficheiro a un espazo de nomes que non o admite',
 'nonfile-cannot-move-to-file' => 'Non se pode mover algo que non é un ficheiro ao espazo de nomes reservado aos ficheiros',
 'imagetypemismatch' => 'A nova extensión do fiheiro non coincide co seu tipo',
index e416c8c..05c08eb 100644 (file)
@@ -1953,18 +1953,19 @@ https://www.mediawiki.org/wiki/Manual:Image_Authorization. જુઓ',
 'wantedfiles' => 'ઇચ્છિત ફાઈલો',
 'wantedfiletext-cat' => 'નીચેની ફાઈલ વપરાઈ છે પણ તે વિહરમન નથી. ફાઈલ અહીં હોવા તેવી ફાઈલોને પણ પરદેશી રીપોસીટરીમાંથી ફાઈલો યાદીમાં જોઈ શકાય છે. આવા પુનરાવર્તનોને  <del>struck out</del> કાઢી નાખવામાં આવશે.વધારામાં, અસ્તિત્વમાં નહોય તેવી ફાઈલધરાવતાં પાનાની યાદી [[:$1]].',
 'wantedfiletext-nocat' => 'નીચેની ફાઈલ વપરાઈ છે પણ તે અસ્તિત્વમાં નથી. ફાઈલ અહીં હોવા તેવી ફાઈલોને પણ પરદેશી રીપોસીટરીમાંથી ફાઈલો યાદીમાં જોઈ શકાય છે. આવા પુનરાવર્તનોને  <del>struck out</del> કાઢી નાખવામાં આવશે.',
-'wantedtemplates' => 'àª\9cà«\8bàª\88તા ઢાંચા',
+'wantedtemplates' => 'àª\87àª\9aà«\8dàª\9bિત ઢાંચા',
 'mostlinked' => 'સૌથી વધુ કડીઓ દ્વારા જોડાયેલ પાનું',
 'mostlinkedcategories' => 'સૌથી વધુ શ્રેણીઓ દ્વારા જોડાયેલ પાનું',
 'mostlinkedtemplates' => 'સૌથી વધુ ઢાંચાઓ  દ્વારા જોડાયેલ પાનું',
 'mostcategories' => 'સૌથી વધુ શ્રેણીઓ ધરાવતાં પાનાં',
 'mostimages' => 'સૌથી વધુ કડીઓ દ્વારા જોડાયેલી ફાઇલ',
+'mostinterwikis' => 'સૌથી વધુ આંતરવિકી કડીઓ ધરાવતાં પાના',
 'mostrevisions' => 'સૌથી વધુ ફેરફાર થયેલા પાનાં',
 'prefixindex' => 'પૂર્વાક્ષર સૂચિ',
 'prefixindex-namespace' => 'શરૂઆતમાં ($1 namespace) ધરાવતા પાનાં',
 'shortpages' => 'નાનાં પાનાં',
 'longpages' => 'લાંબા પાનાઓ',
-'deadendpages' => 'લà«\87àª\96 àª¸àª®àª¾àªªà«\8dતિ પાના',
+'deadendpages' => 'મà«\83તાàª\82ત પાના',
 'deadendpagestext' => 'નીચેના પાના {{SITENAME}}ના અન્ય પાનાને કડીઓ દ્વારા નથી જોડતાં.',
 'protectedpages' => 'સંરક્ષિત પાનાઓ',
 'protectedpages-indef' => 'ફક્ત અનિશ્ચિત સુરક્ષા ધરાવતા પાના',
index f640749..6a0b5cb 100644 (file)
@@ -1135,6 +1135,15 @@ $2
 'edit-already-exists' => 'לא ניתן ליצור דף חדש.
 הוא כבר קיים.',
 'defaultmessagetext' => 'טקסט ההודעה המקורי',
+'content-failed-to-parse' => 'פענוח $2 כתוכן מסוג $1 נכשל: $3',
+'invalid-content-data' => 'מידע שגוי על התוכן',
+'content-not-allowed-here' => 'תוכן מסוג "$1" אינו מותר בדף [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'טקסט ויקי',
+'content-model-text' => 'טקסט פשוט',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''אזהרה:''' דף זה כולל יותר מדי קריאות לפונקציות מפענח שגוזלות משאבים.
@@ -2594,7 +2603,8 @@ $UNWATCHURL
 'undeletedrevisions' => '{{PLURAL:$1|שוחזרה גרסה אחת|שוחזרו $1 גרסאות}}',
 'undeletedrevisions-files' => '{{PLURAL:$1|גרסה אחת|$1 גרסאות}} ו{{PLURAL:$2|קובץ אחד|־$2 קבצים}} שוחזרו',
 'undeletedfiles' => '{{PLURAL:$1|שוחזר קובץ אחד|שוחזרו $1 קבצים}}',
-'cannotundelete' => 'השחזור נכשל; ייתכן שמישהו אחר כבר שחזר את הדף.',
+'cannotundelete' => 'השחזור נכשל:
+$1',
 'undeletedpage' => "'''הדף $1 שוחזר בהצלחה.'''
 
 ראו את [[Special:Log/delete|יומן המחיקות]] לרשימה של מחיקות ושחזורים אחרונים.",
@@ -2897,6 +2907,7 @@ $1',
 'immobile-target-namespace-iw' => 'קישור בינוויקי אינו יעד תקין להעברת דף.',
 'immobile-source-page' => 'דף זה אינו ניתן להעברה.',
 'immobile-target-page' => 'לא ניתן להעביר אל כותרת יעד זו.',
+'bad-target-model' => 'היעד המבוקש משתמש בסוג תוכן שונה. לא ניתן להמיר $1 ל{{grammar:תחילית|$2}}.',
 'imagenocrossnamespace' => 'לא ניתן להעביר קובץ למרחב שם אחר',
 'nonfile-cannot-move-to-file' => 'לא ניתן להעביר דף שאינו קובץ למרחב קובץ',
 'imagetypemismatch' => 'סיומת הקובץ החדשה אינה מתאימה לסוג הקובץ',
@@ -3769,7 +3780,7 @@ $5
 # Scary transclusion
 'scarytranscludedisabled' => '[הכללת דפים בין אתרים מבוטלת]',
 'scarytranscludefailed' => '[אחזור התבנית נכשל עבור $1]',
-'scarytranscludefailed-httpstatus' => '[×\94×\9b×\9c×\9cת ×\94ת×\91× ×\99ת × ×\9bש×\9c×\94 עבור $1&rlm;: HTTP $2]',
+'scarytranscludefailed-httpstatus' => '[×\90×\97×\96×\95ר ×\94ת×\91× ×\99ת × ×\9bש×\9c עבור $1&rlm;: HTTP $2]',
 'scarytranscludetoolong' => '[כתובת ה־URL ארוכה מדי]',
 
 # Delete conflict
index a775eef..0c59316 100644 (file)
@@ -897,6 +897,15 @@ Zda so, zo je hîžo wušmórnjena.',
 'edit-already-exists' => 'Njebě móžno nowu stronu wutworić.
 Eksistuje hižo.',
 'defaultmessagetext' => 'Standardny tekst zdźělenki',
+'content-failed-to-parse' => 'Parsowanje wobsaha $2 za model $1 je so njeporadźiło: $3',
+'invalid-content-data' => 'Njepłaćiwe wobsahowe daty',
+'content-not-allowed-here' => 'Wobsah "$1" njeje na stronje [[$2]] dowoleny',
+
+# Content models
+'content-model-wikitext' => 'wikitekst',
+'content-model-text' => 'luty tekst',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Warnowanje: Tuta strona wobsahuje přewjele parserowych wołanjow.
@@ -2327,7 +2336,8 @@ W tutym padźe dyrbiš najnowšu wušmórnjenu wersiju znjemóžnić abo pokaza
 'undeletedrevisions' => '$1 {{PLURAL:$1|wersija|wersiji|wersije|wersijow}} {{PLURAL:$1|wobnowjena|wobnowjenej|wobnowjene|wobnowjene}}',
 'undeletedrevisions-files' => '$1 {{PLURAL:$1|wersija|wersiji|wersije|wersijow}} a $2 {{PLURAL:$2|dataja|dataji|dataje|datajow}} {{PLURAL:$2|wobnowjena|wobnowjenej|wobnowjene|wobnowjene}}',
 'undeletedfiles' => '$1 {{PLURAL:$1|dataja|dataji|dataje|datajow}} {{PLURAL:$1|wobnowjena|wobnowjenej|wobnowjene|wobnowjene}}.',
-'cannotundelete' => 'Wobnowjenje zwrěšćiło; něchtó druhi je stronu prjedy wobnowił.',
+'cannotundelete' => 'Wobnowjenje zwrěšćiło:
+$1',
 'undeletedpage' => "'''Strona $1 bu z wuspěchom wobnowjena.'''
 
 Hlej [[Special:Log/delete|protokol]] za lisćinu aktualnych wušmórnjenjow a wobnowjenjow.",
@@ -2613,6 +2623,7 @@ Cilowa strona „[[:$1]]” hižo eksistuje. Chceš ju wušmórnyć, zo by so p
 'immobile-target-namespace-iw' => 'Interwiki-wotkaz njeje płaćiwy cil za přesunjenja stronow.',
 'immobile-source-page' => 'Strona njeda so přesunyć.',
 'immobile-target-page' => 'Njemóžno do teje ciloweje strony přesunyć.',
+'bad-target-model' => 'Požadany cil wužiwa druhi wobsahowy model. $1 njeda so do $2 konwertować.',
 'imagenocrossnamespace' => 'Wobraz njeda so do druheho mjenoweho ruma hač wobraz přesunyć',
 'nonfile-cannot-move-to-file' => 'Njedataje njedadźa so do datajoweho mjenoweho ruma přesunyć',
 'imagetypemismatch' => 'Nowa dataja swojemu typej njewotpowěduje',
index 817262b..45cad9a 100644 (file)
@@ -1021,6 +1021,15 @@ Sembra che sia stata cancellata.',
 'edit-already-exists' => 'Impossibile creare una nuova pagina.
 Esiste già.',
 'defaultmessagetext' => 'Testo predefinito',
+'content-failed-to-parse' => 'Impossibile analizzare $2 per il modello $1: $3',
+'invalid-content-data' => 'Dati contenuti non validi',
+'content-not-allowed-here' => 'Contenuto in "$1" non consentito nella pagine [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'wikitesto',
+'content-model-text' => 'testo normale',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''Attenzione:''' Questa pagina contiene troppe chiamate alle parser functions.
@@ -2442,7 +2451,8 @@ Il testo contenuto nelle revisioni cancellate è disponibile solo agli amministr
 'undeletedrevisions' => '{{PLURAL:$1|Una revisione recuperata|$1 revisioni recuperate}}',
 'undeletedrevisions-files' => '{{PLURAL:$1|Una revisione|$1 revisioni}} e $2 file recuperati',
 'undeletedfiles' => '{{PLURAL:$1|Un file recuperato|$1 file recuperati}}',
-'cannotundelete' => 'Ripristino non riuscito; è possibile che la pagina sia già stata recuperata da un altro utente.',
+'cannotundelete' => 'Ripristino non riuscito:
+$1',
 'undeletedpage' => "'''La pagina $1 è stata recuperata'''
 
 Consultare il [[Special:Log/delete|log delle cancellazioni]] per vedere le cancellazioni e i recuperi più recenti.",
@@ -2730,6 +2740,7 @@ La pagina specificata come destinazione "[[:$1]]" esiste già. Vuoi cancellarla
 'immobile-target-namespace-iw' => 'Un collegamento interwiki non è una destinazione valida per spostare la pagina.',
 'immobile-source-page' => 'Questa pagina non può essere spostata.',
 'immobile-target-page' => 'Non è possibile spostare sul titolo indicato.',
+'bad-target-model' => 'La destinazione desiderata utilizza un modello di contenuti diverso. Non è possibile convertire da $1 a $2.',
 'imagenocrossnamespace' => 'Non è possibile spostare un file fuori dal relativo namespace.',
 'nonfile-cannot-move-to-file' => 'Non è possibile spostare un file fuori dal relativo namespace.',
 'imagetypemismatch' => 'La nuova estensione del file non corrisponde al tipo dello stesso',
index 37cf5f9..fcd28ec 100644 (file)
@@ -1117,10 +1117,10 @@ IP アドレスは複数の利用者で共有されている場合がありま
 'editingold' => "'''警告:このページの古い版を編集しています。'''
 保存すると、この版以降に追加されていた変更がすべて失われます。",
 'yourdiff' => '差分',
-'copyrightwarning' => "{{SITENAME}}への投稿は、すべて$2(詳細は$1を参照)のもとで公開したと見なされることにご注意ください。
+'copyrightwarning' => "{{SITENAME}}への投稿は、すべて$2 (詳細は$1を参照) のもとで公開したと見なされることにご注意ください。
 あなたが投稿したものを、他人がよって遠慮なく編集し、それを自由に配布するのを望まない場合は、ここには投稿しないでください。<br />
 また、投稿するのは、あなたが書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください。
-'''著作権保護されている作品を、許諾なしに投稿しないでください'''",
+'''著作権保護されている作品を、許諾なしに投稿しないでください!'''",
 'copyrightwarning2' => "{{SITENAME}}へのすべての投稿は、他の利用者が編集、変更、除去する可能性があります。
 あなたの投稿を、他人が遠慮なく編集するのを望まない場合は、ここには投稿しないでください。<br />
 また、投稿するのは、あなたが書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細は$1を参照)。
@@ -1170,6 +1170,15 @@ IP アドレスは複数の利用者で共有されている場合がありま
 'edit-already-exists' => '新しいページを作成できませんでした。
 そのページは既に存在しています。',
 'defaultmessagetext' => '既定のメッセージ文',
+'content-failed-to-parse' => '$2 の本文を$1モデルとして構文解析できませんでした。',
+'invalid-content-data' => '本文データが無効です',
+'content-not-allowed-here' => 'ページ [[$2]] では、「$1」コンテンツは許可されていません',
+
+# Content models
+'content-model-wikitext' => 'ウィキテキスト',
+'content-model-text' => 'プレーンテキスト',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''警告:'''このページでの高負荷なパーサー関数の呼び出し回数が多過ぎます。
@@ -2619,7 +2628,7 @@ $2による直前の版へ変更されました。',
 'restriction-level' => '制限レベル:',
 'minimum-size' => '最小サイズ',
 'maximum-size' => '最大サイズ:',
-'pagesize' => '(バイト)',
+'pagesize' => '(バイト)',
 
 # Restrictions (nouns)
 'restriction-edit' => '編集',
@@ -2663,8 +2672,8 @@ $2による直前の版へ変更されました。',
 'undeletedrevisions' => '{{PLURAL:$1|$1版}}を復元しました',
 'undeletedrevisions-files' => '{{PLURAL:$1|$1版}}と{{PLURAL:$2|$2ファイル}}を復元しました',
 'undeletedfiles' => '{{PLURAL:$1|$1ファイル}}を復元しました',
-'cannotundelete' => '復元に失敗しました
-他の誰かがこのページを既に復元した可能性があります。',
+'cannotundelete' => '復元に失敗しました:
+$1',
 'undeletedpage' => "'''$1を復元しました。'''
 
 最近の削除と復元の記録については[[Special:Log/delete|削除記録]]を参照してください。",
@@ -2973,6 +2982,7 @@ $1 のブロックの理由は「''$2''」です。",
 'immobile-target-namespace-iw' => 'ウィキ間リンクは、ページの移動先には指定できません。',
 'immobile-source-page' => 'このページは移動できません。',
 'immobile-target-page' => '移動先ページ名に移動させることができません。',
+'bad-target-model' => '指定した移動先では、異なるコンテンツ モデルを使用しています。$1から$2には変換できません。',
 'imagenocrossnamespace' => 'ファイルを、ファイル名前空間以外に移動させることはできません',
 'nonfile-cannot-move-to-file' => 'ファイルではないものを、ファイル名前空間に移動させることはできません',
 'imagetypemismatch' => '新しいファイルの拡張子がファイルのタイプと一致していません',
index 9b6621e..bf20238 100644 (file)
@@ -960,15 +960,20 @@ Senked d akken tamhelt agi ad eǧǧ amezruy n usebtar ad ikemmel.',
 'mergehistory-go' => 'Ẓeṛ ibeddilen i nezmer an zdi',
 'mergehistory-submit' => 'Azday n ileqman',
 'mergehistory-empty' => 'Ulac lqem i nezmer an zdi.',
+'mergehistory-success' => '$3 {{PLURAL:$3|lqem|ileqman}} n [[:$1]] {{PLURAL:$3|yezdukel|zdukelen}} deg [[:$2]].',
+'mergehistory-fail' => 'Ulamek an zdukel imezruyen. Fru tikkelt nniḍen asebter d iɣewwaren is n uzmez.',
 'mergehistory-no-source' => 'Azar n usebter $1 ulac-it.',
 'mergehistory-no-destination' => 'Aserken n usebter $1 ulac-it',
 'mergehistory-invalid-source' => 'Azar n usebter ilaq ad i sɛu azwel i ɣbelen.',
 'mergehistory-invalid-destination' => 'Aserken n usebter ilaq ad i sɛu azwel i ɣbelen.',
+'mergehistory-autocomment' => '[[:$1]] yezdukel s [[:$2]]',
+'mergehistory-comment' => '[[:$1]] yezdukel s [[:$2]] : $3',
 'mergehistory-same-destination' => 'Asebter n azar d usebter n userken ur zemren ara ad illin d yiwen',
 'mergehistory-reason' => 'Ayɣer',
 
 # Merge log
 'mergelog' => 'Aɣmis n izdayen',
+'pagemerge-logentry' => '[[$1]] yezdukel s [[$2]] (lqem alama d $3)',
 'revertmerge' => 'Fru',
 'mergelogpagetext' => 'Attan tebdart n wesdukel umezruy usebtar deg win n usebtar nniḍen amaynut.',
 
@@ -994,6 +999,7 @@ Tzemreḍ ad affeḍ tilɣa deg [{{fullurl:{{#Special:Log}}/delete|page={{FULLPA
 'searchresulttext' => 'Akken ad tessneḍ amek ara tnadiḍ deg {{SITENAME}}, ẓer [[{{MediaWiki:Helppage}}|{{int:help}}]].',
 'searchsubtitle' => "Tnudaḍ « '''[[:$1]]''' » ([[Special:Prefixindex/$1|akkw isebtar i zwiren s « $1 »]]{{int:pipe-separator}}[[Special:WhatLinksHere/$1|Akkw isebtar yesɛan azday ɣer « $1 »]])",
 'searchsubtitleinvalid' => "Tnadiḍ ɣef '''$1'''",
+'toomanymatches' => 'Teceggeɛeḍ amḍan ameqqṛan n igemmaḍ, ilaq ad ceggeɛeḍ tuttra nniḍen.',
 'titlematches' => 'Ayen yecban azwel n umegrad',
 'notitlematches' => 'Ulac ayen yecban azwel n umegrad',
 'textmatches' => 'Ayen yecban azwel n usebter',
@@ -1021,6 +1027,7 @@ Tzemreḍ ad affeḍ tilɣa deg [{{fullurl:{{#Special:Log}}/delete|page={{FULLPA
 'searchprofile-advanced-tooltip' => 'Fren ideggen n isemawen i unadi',
 'search-result-size' => '$1 ({{PLURAL:$2|1 awal|$2 awalen}})',
 'search-result-category-size' => '$1 {{PLURAL:$1|amseqdac|imseqdacen}} $2 ({{PLURAL:$2|adu-taggayt|adu-tiggayin}}, $3 {{PLURAL:$3|afaylu|ifuyla}})',
+'search-result-score' => 'Taflest : $1%',
 'search-redirect' => '(asemmimeḍ $1)',
 'search-section' => '(tigezmi $1)',
 'search-suggest' => 'D awal $1 i tnadiḍ ?',
@@ -1041,7 +1048,7 @@ Tzemreḍ ad affeḍ tilɣa deg [{{fullurl:{{#Special:Log}}/delete|page={{FULLPA
 'powersearch' => 'Anadi amahlan',
 'powersearch-legend' => 'Anadi amahlan',
 'powersearch-ns' => 'Nadi deg tallunin n isemawen',
-'powersearch-redir' => 'Beqqeḍ alsinamuden',
+'powersearch-redir' => 'Beqqeḍ isemmimḍen',
 'powersearch-field' => 'Nadi',
 'powersearch-togglelabel' => 'Ɛellem :',
 'powersearch-toggleall' => 'Akkw',
@@ -1095,11 +1102,15 @@ Tzemreḍ ad affeḍ tilɣa deg [{{fullurl:{{#Special:Log}}/delete|page={{FULLPA
 'columns' => 'Tigejda:',
 'searchresultshead' => 'Anadi',
 'resultsperpage' => 'Geddac n tiririyin i mkul asebter:',
+'stub-threshold' => 'Talast timinegt i <a href="#" class="stub">izdayen ɣer ibegzan</a> (itamḍanen) :',
 'stub-threshold-disabled' => 'Yensa',
 'recentchangesdays' => 'Amḍan n ussan an beqqeḍ deg ibeddilen ineggura.',
 'recentchangesdays-max' => 'Afellay $1 {{PLURAL:$1|ass|ussan}}',
 'recentchangescount' => 'Amḍan n ibeddilen i ubeqqeḍ s lexṣas :',
 'prefs-help-recentchangescount' => 'Wagi yesɛa deg-es ibeddilen ineggura, isebtar n umezruy d iɣmisen.',
+'prefs-help-watchlist-token' => 'Ččuṛ taɣzut agi s azal lbaḍna dɣa asuddem RSS ad yetwarew i umuɣ inek/inem n uɛassi.
+Akkw amdan yesnen tiddest agi ad yezmer ad i ɣeṛ umuɣ inek/inem n uɛassi, ihi ilaq ad xtiṛeḍ azal yegdelen.
+Ha-t-an azal agacuran i tzemreḍ ad seqdeceḍ : $1',
 'savedprefs' => 'Isemyifiyen inek yettusmektan.',
 'timezonelegend' => 'Iẓḍi n ukud :',
 'localtime' => 'Asrag adigan :',
@@ -1148,6 +1159,7 @@ Ur ilaq ara ad i sɛu ugar n $1 {{PLURAL:$1|asekkil|isekkilen}}.',
 'gender-unknown' => 'Ulac tumlin',
 'gender-male' => 'Amalay',
 'gender-female' => 'Untay',
+'prefs-help-gender' => 'Axetṛan : yetseqdec iwakken ad yefk tawsit i inzan n ugrudem. Talɣut agi at illi tazayert.',
 'email' => 'E-mail',
 'prefs-help-realname' => '* Isem n ṣṣeḥ (am tebɣiḍ): ma textareḍ a t-tefkeḍ, ad yettuseqdac iwakken ad snen medden anwa yura tikkin inek.',
 'prefs-help-email' => '* E-mail (am tebɣiḍ): Teǧǧi imseqdacen wiyaḍ a k-aznen email mebla ma ẓren tansa email inek.',
@@ -1169,6 +1181,7 @@ Ur ilaq ara ad i sɛu ugar n $1 {{PLURAL:$1|asekkil|isekkilen}}.',
 'prefs-diffs' => 'Timeẓliwin',
 
 # User preference: e-mail validation using jQuery
+'email-address-validity-valid' => 'E-mail agi teɣbel',
 'email-address-validity-invalid' => 'Telaq tansa e-mail i ɣbelen !',
 
 # User rights
@@ -1180,7 +1193,11 @@ Ur ilaq ara ad i sɛu ugar n $1 {{PLURAL:$1|asekkil|isekkilen}}.',
 'userrights-editusergroup' => 'Beddel iderman n wemseqdac',
 'saveusergroups' => 'Smekti iderman n yimseqdacen',
 'userrights-groupsmember' => 'Amaslad deg:',
+'userrights-groupsmember-auto' => 'Aεeggal udrig n :',
 'userrights-reason' => 'Ayɣer',
+'userrights-nodatabase' => 'Taffa n isefka « $1 » ulac itt naɣ mačči d tadigant.',
+'userrights-nologin' => 'Ilaq ad [[Special:UserLogin|qqeneḍ]] s yiwen umiḍan anedbal iwakken ad beddeleḍ izerfan n useqdac.',
+'userrights-notallowed' => 'Amiḍan inek/inem ur yesɛa ara turagt iwakken ad beddeleḍ izerfan n useqdac.',
 'userrights-changeable-col' => 'Igrawen i tzemreḍ ad beddeleḍ',
 'userrights-unchangeable-col' => 'Igrawen ur tzemreḍ ara ad beddeleḍ',
 
@@ -1219,6 +1236,7 @@ Ur ilaq ara ad i sɛu ugar n $1 {{PLURAL:$1|asekkil|isekkilen}}.',
 'right-move-subpages' => 'Beddel isem n isebtar d adu-isebtar nsen',
 'right-move-rootuserpages' => 'Beddel isem n usebtar amenzawi n useqdac',
 'right-movefile' => 'Beddel isem n ifuyla',
+'right-suppressredirect' => 'Ur snulfu ara asemmimeḍ seg azwel amezwaru s ubeddel n isem usebter',
 'right-upload' => 'Azen ifuyla',
 'right-reupload' => 'Sefxes afaylu yellan',
 'right-reupload-own' => 'Sefxes afaylu id n-azen.',
@@ -1688,6 +1706,8 @@ Asebter yella d asebter n tiynisemt lukan yetseqdac talɣa i qqenen ar [[MediaWi
 'withoutinterwiki-legend' => 'Adat',
 'withoutinterwiki-submit' => 'Ssken',
 
+'fewestrevisions' => 'Isebtar yesɛan cwiṭ ibeddilen',
+
 # Miscellaneous special pages
 'nbytes' => '$1 {{PLURAL:$1|byte/octet|bytes/octets}}',
 'ncategories' => '$1 {{PLURAL:$1|Taggayt|Taggayin}}',
@@ -1708,20 +1728,32 @@ Asebter yella d asebter n tiynisemt lukan yetseqdac talɣa i qqenen ar [[MediaWi
 'wantedcategories' => 'Taggayin mmebɣant',
 'wantedpages' => 'Isebtar mmebɣan',
 'wantedfiles' => 'Ifuyla yettwasutren s waṭas.',
+'wantedtemplates' => 'Talɣiwin yetsuteren',
 'mostlinked' => 'Isebtar myezdin aṭas',
 'mostlinkedcategories' => 'Taggayin myezdint aṭas',
+'mostlinkedtemplates' => 'Talɣiwin yetseqdacen aṭas.',
 'mostcategories' => 'Isebtar i yesɛan aṭṭas taggayin',
 'mostimages' => 'Ifuyla i seqdacen aṭas',
+'mostinterwikis' => 'Isebtar yesɛan aṭas interwikis',
 'mostrevisions' => 'Isebtar i yettubedlen aṭas',
 'prefixindex' => 'Akk isebtaren s yisekkilen imezwura',
+'prefixindex-namespace' => 'Akkw isebtar s adat (tallunt n isemawe $1)',
 'shortpages' => 'isebtar imecṭuḥen',
 'longpages' => 'Isebtar imeqqranen',
 'deadendpages' => 'isebtar mebla izdayen',
 'deadendpagestext' => 'Isebtar agi ur sɛan ara izdayen ɣer isebtar nniḍen n {{SITENAME}}.',
 'protectedpages' => 'isebtar yettwaḥerzen',
+'protectedpages-indef' => 'Imestenen imeɣlalen kan',
+'protectedpages-cascade' => 'Imestenen s uceṛcuṛ kan',
 'protectedpagestext' => 'isebtar-agi yettwaḥerzen seg ubeddel neɣ asemmimeḍ',
 'protectedpagesempty' => 'isebtar-agi ttwaḥerzen s imsektayen -agi.',
+'protectedtitles' => 'Izwal ugdilen',
+'protectedtitlestext' => 'Izwal agi ugdilen deg usnulfu nsen',
+'protectedtitlesempty' => 'Ulac azwel yesɛan asegdel s iɣewwaren agi.',
 'listusers' => 'Umuɣ n yimseqdacen',
+'listusers-editsonly' => 'Sekned kan iseqdacen yesɛan asekcem naɣ ugar',
+'listusers-creationsort' => 'Fren s azmez n usnulfu',
+'usereditcount' => '$1 {{PLURAL:$1|abeddel|ibeddilen}}',
 'usercreated' => '{{GENDER:$3|Yesnulfu-d}} ass n $1 ar $2',
 'newpages' => 'isebtar imaynuten',
 'newpages-username' => 'Isem n wemseqdac:',
@@ -1733,14 +1765,19 @@ Ahat llan ismal nniḍen yesɛan azday ɣer afaylu, ihi yezmer ad yiqqim afaylu
 'unusedcategoriestext' => 'Taggayin-agi weǧden meɛna ulac isebtar neɣ taggayin i sseqdacen-iten.',
 'notargettitle' => 'Ulac nnican',
 'notargettext' => 'Ur textareḍ ara asebter d nnican neɣ asebter n wemseqdac d nnican.',
+'nopagetitle' => 'Ulac asebter asaḍas am wagi',
+'nopagetext' => 'Asebter asaḍas agi ulac-it.',
 'pager-newer-n' => '{{PLURAL:$1|amaynut|$1 imaynuten}}',
 'pager-older-n' => '{{PLURAL:$1|aqbur|$1 iqburen}}',
+'suppress' => 'Mdi',
+'querypage-disabled' => 'Asebter uslig agi yensa , taɣzint : timellal is.',
 
 # Book sources
 'booksources' => 'Iɣbula n yidlisen',
 'booksources-search-legend' => 'Nadi ɣef iɣbula n yidlisen',
 'booksources-go' => 'Ruḥ',
 'booksources-text' => 'Deg ukessar, yella wumuɣ n yizdayen iberraniyen izzenzen idlisen (imaynuten akk d weqdimen), yernu ahat sɛan kter talɣut ɣef idlisen i tettnadiḍ fell-asen:',
+'booksources-invalid-isbn' => 'ISBN agi ur yeɣbel ara ; selken ma ulac anezri deg-es.',
 
 # Special:Log
 'specialloguserlabel' => 'Ameskar :',
@@ -1751,6 +1788,7 @@ Ahat llan ismal nniḍen yesɛan azday ɣer afaylu, ihi yezmer ad yiqqim afaylu
 Tzemreḍ ad sageneḍ abeqqeḍ s tixtiṛit n tawsit n uɣmis, isem n useqdac naɣ asebter nni.',
 'logempty' => 'Ur yufi ara deg uɣmis.',
 'log-title-wildcard' => 'Nadi ɣef izwal i yebdan s uḍris-agi',
+'showhideselectedlogentries' => 'Beqqeḍ/ffer isekcam n uɣmis agi',
 
 # Special:AllPages
 'allpages' => 'Akk isebtar',
@@ -1758,6 +1796,7 @@ Tzemreḍ ad sageneḍ abeqqeḍ s tixtiṛit n tawsit n uɣmis, isem n useqdac
 'nextpage' => 'Asebter ameḍfir ($1)',
 'prevpage' => 'Asebter ssabeq ($1)',
 'allpagesfrom' => 'Ssken isebtar seg:',
+'allpagesto' => 'Beqqeḍ isebtar alama :',
 'allarticles' => 'Akk imagraden',
 'allinnamespace' => 'Akk isebtar ($1 isem n taɣult)',
 'allnotinnamespace' => 'Akk isebtar (mačči deg $1 isem n taɣult)',
@@ -1767,6 +1806,10 @@ Tzemreḍ ad sageneḍ abeqqeḍ s tixtiṛit n tawsit n uɣmis, isem n useqdac
 'allpagesprefix' => 'Ssken isebtar s uzwir:',
 'allpagesbadtitle' => 'Azwel n usebter mačči ṣaḥiḥ neɣ yesɛa azwir inter-wiki. Waqila yesɛa isekkilen ur ttuseqdacen ara deg izwal.',
 'allpages-bad-ns' => '{{SITENAME}} ur yesɛi ara isem n taɣult "$1".',
+'allpages-hide-redirects' => 'Ffer isemmimḍen',
+
+# SpecialCachedPage
+'cachedspecial-refresh-now' => 'Ẓeṛ aneggaru.',
 
 # Special:Categories
 'categories' => 'Taggayin',
@@ -1777,6 +1820,11 @@ Tzemreḍ ad sageneḍ abeqqeḍ s tixtiṛit n tawsit n uɣmis, isem n useqdac
 'special-categories-sort-count' => 'Afran s amḍan n iferdisen',
 'special-categories-sort-abc' => 'Afran s ugemmay',
 
+# Special:DeletedContributions
+'deletedcontributions' => 'Isekcam yemḥan',
+'deletedcontributions-title' => 'Isekcam yemḥan',
+'sp-deletedcontributions-contribs' => 'Isekcam',
+
 # Special:LinkSearch
 'linksearch' => 'Anadi n izdayen yeffɣen',
 'linksearch-pat' => 'Anadi n tanfalit :',
@@ -1789,6 +1837,10 @@ Tzemreḍ ad sageneḍ abeqqeḍ s tixtiṛit n tawsit n uɣmis, isem n useqdac
 'listusers-submit' => 'Ssken',
 'listusers-noresult' => 'Ur yufi ḥedd (amseqdac).',
 
+# Special:ActiveUsers
+'activeusers-from' => 'Ssken iseqdacen seg :',
+'activeusers-noresult' => 'Ur yufi aseqdac.',
+
 # Special:Log/newusers
 'newuserlogpage' => 'Aɣmis n isnulfan n  imiḍanen n imseqdacen',
 
@@ -1927,6 +1979,8 @@ Tuɣalin d tadhelt :
 'excontentauthor' => "Ayen yella: '$1' ('[[Special:Contributions/$2|$2]]' kan i yekken deg-s)",
 'exbeforeblank' => "Ayen yella uqbal ma yettumḥa: '$1'",
 'exblank' => 'asebter yella d ilem',
+'delete-confirm' => 'Kkes "$1"',
+'delete-legend' => 'Ekkes',
 'historywarning' => 'Ɣur-wet : Asebter i ara temḥuḍ yesɛa amezruy s azal alemmas n $1 {{PLURAL:$1|lqem|ileqman}} :',
 'actioncomplete' => 'Axdam yekfa',
 'actionfailed' => 'Tigawt agi texser',
@@ -1937,9 +1991,14 @@ Tuɣalin d tadhelt :
 'deletionlog' => 'Aɣmis n umḥay',
 'reverted' => 'Asuɣal i tasiwel taqdimt',
 'deletecomment' => 'Ayɣer',
+'deleteotherreason' => 'Taɣẓint nniḍen / taɣzint tamarnant :',
+'deletereasonotherlist' => 'Taɣẓint nniḍen',
+'delete-edit-reasonlist' => 'Beddel tiɣẓinin n umḥu n usebter',
 
 # Rollback
+'rollback_short' => 'Semmet',
 'rollbacklink' => 'semmet',
+'rollbacklinkcount' => 'semmet $1 {{PLURAL:$1|abeddel|ibeddilen}}',
 'cantrollback' => 'Ur yezmir ara ad yessuɣal; yella yiwen kan amseqdac iwumi ibeddel/yexleq asebter-agi.',
 'editcomment' => "Agzul n ubeddel yella: \"''\$1''\".",
 'revertpage' => 'Yessuɣal ibeddlen n [[Special:Contributions/$2|$2]] ([[User talk:$2|Meslay]]); yettubeddel ɣer tasiwelt taneggarut n [[User:$1|$1]]',
@@ -1955,19 +2014,32 @@ G leɛnayek wekki ɣef taqeffalt "Back/Précédent" n browser/explorateur inek,
 'protect-title' => 'Ad yeḥrez "$1"',
 'prot_1movedto2' => '[[$1]] yettusmimeḍ ar [[$2]]',
 'protect-legend' => 'Sentem tiḥḥerzi',
+'protectcomment' => 'Taɣẓint :',
 'protect-default' => '(ameslugen)',
 'protect-level-sysop' => 'Inedbalen kan',
 'protect-summary-cascade' => 'acercur',
 'protect-expiring' => 'yemmut deg $1 (UTC)',
+'protect-otherreason' => 'Taɣẓint nniḍen / taɣzint tamarnant :',
+'protect-otherreason-op' => 'Taɣẓint nniḍen',
+'protect-edit-reasonlist' => 'Beddel tiɣẓinin n usegdel',
+'protect-expiry-options' => '1 asrag:1 hour,1 ass:1 day,1 imalas:1 week,2 imalasen:2 weeks,1 aggur:1 month,3 agguren:3 months,6 agguren:6 months,1 assegwas:1 year,adfi:infinite',
 'restriction-type' => 'Turagt',
 'minimum-size' => 'Tiddi minimum',
 
 # Restrictions (nouns)
 'restriction-edit' => 'Beddel',
 'restriction-move' => 'Smimeḍ',
+'restriction-create' => 'Snulfu',
+
+# Restriction levels
+'restriction-level-autoconfirmed' => 'adu-asegdel',
 
 # Undelete
+'undelete' => 'Ẓer isebtar yettumḥan',
+'undeletepage' => 'Ẓeṛ dɣa erred isebtar yetwekkesen',
+'undeletepagetitle' => "'''Umuɣ agi yesɛa ileqman yetwekkesen n [[:$1|$1]]'''.",
 'viewdeletedpage' => 'Ẓer isebtar yettumḥan',
+'undelete-fieldset-title' => 'Erred ileqman',
 'undeletelink' => 'ẓeṛ/uɣaled',
 'undeleteviewlink' => 'ẓeṛ',
 'undeletecomment' => 'Taɣẓint :',
@@ -2028,15 +2100,43 @@ G leɛnayek wekki ɣef taqeffalt "Back/Précédent" n browser/explorateur inek,
 'ipadressorusername' => 'Tansa IP neɣ isem n wemseqdac',
 'ipbreason' => 'Ayɣer',
 'ipbsubmit' => 'Ɛekkel amseqdac-agi',
-'ipboptions' => '2 isragen:2 hours,1 ass:1 day,3 ussan:3 days,1 imalas:1 week,2  imulas:2 weeks,1 aggur:1 month,3 igguren:3 months,6 igguren:6 months,1 aseggwas:1 year,afdi:infinite',
+'ipboptions' => '2 isragen:2 hours,1 ass:1 day,3 ussan:3 days,1 imalas:1 week,2  imalasen:2 weeks,1 aggur:1 month,3 agguren:3 months,6 agguren:6 months,1 aseggwas:1 year,afdi:infinite',
 'ipbotheroption' => 'nniḍen',
 'badipaddress' => 'Tansa IP mačči d ṣaḥiḥ',
+'ipusubmit' => 'Ekkes akyaf agi',
+'unblocked' => 'Yetwekkes akyaf n [[User:$1|$1]]',
+'unblocked-range' => 'Yetwekkes akyaf n $1',
+'unblocked-id' => 'Akyaf $1 yetwekkes',
+'blocklist' => 'Iseqdacen id yetkyefen',
 'ipblocklist' => 'imseqdacen isewḥelen',
+'ipblocklist-legend' => 'Nadi aseqdac id yetkyefen',
+'blocklist-userblocks' => 'Ffer ikyafen n imiḍanen',
+'blocklist-tempblocks' => 'Ffer ikyafen ikudanen',
+'blocklist-addressblocks' => 'Ffer ikyafen n tansa IP tisuftin',
+'blocklist-rangeblocks' => 'Ffer iḥedran n azrag',
+'blocklist-timestamp' => 'Azmez d usrag',
+'blocklist-target' => 'Asaḍas',
+'blocklist-expiry' => 'Azmez n tasewti',
+'blocklist-by' => 'Anedbal i sexdemen akyaf',
+'blocklist-params' => 'Iɣewwaren n ukyaf',
+'blocklist-reason' => 'Taɣẓint',
 'ipblocklist-submit' => 'Nadi',
+'ipblocklist-localblock' => 'Akyaf adigan',
+'ipblocklist-otherblocks' => '{{PLURAL:$1|Akyaf nniḍen|Ikyafen nniḍen}}',
+'infiniteblock' => 'ameɣlal',
+'expiringblock' => 'tasewti ass n $1 af $2',
+'anononlyblock' => 'iseqdacen ur sɛan ara amiḍan kan',
+'noautoblockblock' => 'akyaf awurman yensa',
+'createaccountblock' => 'asnulfu n umiḍan yekyef',
+'emailblock' => 'e-mail yekyef',
+'blocklist-nousertalk' => 'ur yezmer ara ad yebeddel asebter-is n umeslay',
+'ipblocklist-empty' => 'Umuɣ n tansiwin IP i kyefen d-ilem.',
+'ipblocklist-no-results' => 'Tansa IP naɣ aseqdac i sutereḍ ur yekyef ara.',
 'blocklink' => 'ɛekkel',
 'unblocklink' => 'ekkes asewḥel',
 'change-blocklink' => 'beddel asewḥel',
 'contribslink' => 'tikkin',
+'emaillink' => 'Ceggaɛ e-mail',
 'blocklogpage' => 'Aɣmis n isewḥelen',
 'blocklogentry' => 'yesewḥel [[$1]] ; alama : $2 $3',
 'block-log-flags-anononly' => 'Imseqdacen udrigen kan',
@@ -2406,8 +2506,94 @@ Izdayen nniḍen ɣef yiwen ajerriḍ llan d tisuraf, am isebtar ɣef anta tugna
 'exif-originaltransmissionref' => 'Tangalt n usideg n tuzzna tamezwarut',
 'exif-identifier' => 'Asulay',
 
+'exif-subjectdistance-value' => '$1 lmitra',
+
+'exif-meteringmode-0' => 'Warisem',
+'exif-meteringmode-1' => 'Alemmas',
+'exif-meteringmode-2' => 'Allal amnekna deg agwans',
+'exif-meteringmode-3' => 'Asfaw',
+'exif-meteringmode-4' => 'Aget-asfaw',
+'exif-meteringmode-5' => 'Talɣa',
+'exif-meteringmode-6' => 'Aḥric',
 'exif-meteringmode-255' => 'Nniḍen',
 
+'exif-lightsource-0' => 'Warisem',
+'exif-lightsource-1' => 'Tafukt n ass',
+'exif-lightsource-2' => 'Arafaw afliyuṛi',
+'exif-lightsource-3' => 'Tungsten (tafat tanesfawt)',
+'exif-lightsource-4' => 'Lebṛaq',
+'exif-lightsource-9' => 'Akud aceεlal',
+'exif-lightsource-10' => 'Akud isignew',
+'exif-lightsource-11' => 'Tili',
+'exif-lightsource-12' => 'Asfaw afliyuṛi  « tafukt n ass » (D 5700 – 7100 K)',
+'exif-lightsource-13' => 'Asfaw afliyuṛi amellal « ass » (N 4600 – 5400 K)',
+'exif-lightsource-14' => 'Asfaw afliyuṛi amellal « asemmaḍ » (W 3900 – 4500 K)',
+'exif-lightsource-15' => 'Asfaw afliyuṛi amellal (WW 3200 – 3700 K)',
+'exif-lightsource-17' => 'Tafat talugent A',
+'exif-lightsource-18' => 'Tafat talugent B',
+'exif-lightsource-19' => 'Tafat talugent C',
+'exif-lightsource-24' => 'Tungsten ISU n usakwen',
+'exif-lightsource-255' => 'Aɣbalu nniḍen n tafat',
+
+# Flash modes
+'exif-flash-fired-0' => 'Lebṛaq ur yendeḥ ara',
+'exif-flash-fired-1' => 'Lebṛaq yendeḥ',
+'exif-flash-mode-1' => 'Tafat n lebaq yuwren',
+'exif-flash-mode-2' => 'Tukksa n lebaq yuwren',
+'exif-flash-mode-3' => 'askar awurman',
+'exif-flash-function-1' => 'Ulac tasɣent n lebṛaq',
+'exif-flash-redeye-1' => 'Tasɣent mgel-allen izeggwaɣen',
+
+'exif-focalplaneresolutionunit-2' => 'Idebbuzen',
+
+'exif-sensingmethod-1' => 'Aranbadu',
+'exif-sensingmethod-2' => 'Amaṭṭaf n ini s yiwen aceṛṛun',
+'exif-sensingmethod-3' => 'Amaṭṭaf n ini s sin iceṛṛunen',
+'exif-sensingmethod-4' => 'Amaṭṭaf n ini s kṛaḍ iceṛṛunen',
+'exif-sensingmethod-5' => 'Amaṭṭaf n ini ulkim',
+'exif-sensingmethod-7' => 'Amaṭṭaf kṛaḍimzireg',
+'exif-sensingmethod-8' => 'Amaṭṭaf n ini imzireg ulkim',
+
+'exif-filesource-3' => 'Taweṣṣaft tumḍint',
+
+'exif-scenetype-1' => 'Tugna n tafarut tusridt',
+
+'exif-customrendered-0' => 'Akala alugen',
+'exif-customrendered-1' => 'Akala yesagen',
+
+'exif-exposuremode-0' => 'Awurman',
+'exif-exposuremode-1' => 'Awfus',
+'exif-exposuremode-2' => 'Tazercet tawurmant',
+
+'exif-whitebalance-0' => 'Awurman',
+'exif-whitebalance-1' => 'Awfus',
+
+'exif-scenecapturetype-0' => 'Alugen',
+'exif-scenecapturetype-1' => 'Agama',
+'exif-scenecapturetype-2' => 'Tafrist',
+'exif-scenecapturetype-3' => 'Asayes n iḍ',
+
+'exif-gaincontrol-0' => 'Ulac',
+'exif-gaincontrol-1' => 'Rrbeḥ ufrir s ubedlez',
+'exif-gaincontrol-2' => 'Rrbeḥ ufrir s aṭas',
+'exif-gaincontrol-3' => 'Rrbeḥ uzdir s ubedlez',
+'exif-gaincontrol-4' => 'Rrbeḥ uzdir s aṭas',
+
+'exif-contrast-0' => 'Amagnu',
+'exif-contrast-1' => 'Abadlaz',
+'exif-contrast-2' => 'Aẓayan',
+
+'exif-saturation-0' => 'Amagnu',
+'exif-saturation-1' => 'Abadlaz',
+'exif-saturation-2' => 'Tameqqṛant',
+
+'exif-sharpness-0' => 'Amagnu',
+'exif-sharpness-1' => 'Alegɣan',
+'exif-sharpness-2' => 'Aẓayan',
+
+'exif-subjectdistancerange-0' => 'Warisem',
+'exif-subjectdistancerange-1' => 'Amɣer',
+
 # Pseudotags used for GPSSpeedRef
 'exif-gpsspeed-k' => 'Kilometr deg ssaɛa',
 'exif-gpsspeed-m' => 'Miles deg usrag',
index 33d7793..8c134a2 100644 (file)
@@ -1137,6 +1137,15 @@ IP 주소는 여러 사용자가 공유할 수 있습니다.
 'edit-already-exists' => '새 문서를 만들 수 없습니다.
 그 문서는 이미 존재합니다.',
 'defaultmessagetext' => '기본 메세지 내용',
+'content-failed-to-parse' => '$1 모델에 대한 $2 내용을 구문 분석하는 데 실패했습니다: $3',
+'invalid-content-data' => '잘못된 내용 데이터입니다',
+'content-not-allowed-here' => '"$1" 내용은 [[$2]] 문서예 허용하지 않습니다',
+
+# Content models
+'content-model-wikitext' => '위키텍스트',
+'content-model-text' => '일반 텍스트',
+'content-model-javascript' => '자바스크립트',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''경고:''' 이 문서는 너무 많은 파서 함수를 포함하고 있습니다.
@@ -2619,8 +2628,8 @@ $UNWATCHURL
 'undeletedrevisions' => '판 $1개를 복구했습니다',
 'undeletedrevisions-files' => '판 $1개와 파일 $2개를 복구했습니다.',
 'undeletedfiles' => '파일 $1개를 복구했습니다',
-'cannotundelete' => '복구에 실패했습니다.
-다른 사용자가 이미 복구했을 수도 있습니다.',
+'cannotundelete' => '복구하는 데 실패했습니다:
+$1',
 'undeletedpage' => "'''$1 문서를 복구했습니다.'''
 
 [[Special:Log/delete|삭제 기록]]에서 최근의 삭제와 복구 기록을 볼 수 있습니다.",
@@ -2637,7 +2646,7 @@ $UNWATCHURL
 이미 복구되었을 수 있습니다.',
 'undelete-error' => '문서 복구 중 오류',
 'undelete-error-short' => '파일 복구 오류: $1',
-'undelete-error-long' => '파일을 복구하는  오류가 발생했습니다:
+'undelete-error-long' => '파일을 복구하는 동안 오류가 발생했습니다:
 
 $1',
 'undelete-show-file-confirm' => '정말 "<nowiki>$1</nowiki>" 파일의 삭제된 $2 $3 버전을 보시겠습니까?',
@@ -2930,6 +2939,7 @@ $1 사용자가 차단된 이유는 다음과 같습니다: "$2"',
 'immobile-target-namespace-iw' => '인터위키 링크를 넘어 문서를 이동할 수 없습니다.',
 'immobile-source-page' => '이 문서는 이동할 수 없습니다.',
 'immobile-target-page' => '새 이름으로 옮길 수 없습니다.',
+'bad-target-model' => '원하는 대상은 다른 내용 모델을 사용합니다. $1에서 $2로 변환할 수 없습니다.',
 'imagenocrossnamespace' => '파일을 파일이 아닌 이름공간으로 옮길 수 없습니다.',
 'nonfile-cannot-move-to-file' => '파일이 아닌 문서를 파일 이름공간으로 옮길 수 없습니다.',
 'imagetypemismatch' => '새 파일의 확장자가 원래의 확장자와 일치하지 않습니다.',
index ec6defb..288f118 100644 (file)
@@ -601,6 +601,7 @@ $2',
 'ns-specialprotected' => "Tsy afaka ovaina ny pejy anatin'ny toeran'anarana « {{ns:special}} » .",
 'titleprotected' => "Voaaron'i [[User:$1|$1]] ity lohateny ity mba tsy hamorona pejy mitondra ity anarana ity.
 Ny antony napetraka dia : « ''$2'' ».",
+'invalidtitle-knownnamespace' => 'Lohateny tsy miady amin\'ny fepetra miaraka amin\'ny anaram-balam-pejy "$2" ary soratra "$3"',
 'exception-nologin' => 'Tsy tafiditra',
 
 # Virus scanner
@@ -697,6 +698,7 @@ mba hanaporofoana fa anao io kaonty io.",
 'invalidemailaddress' => 'Tsy mety io imailaka nalefanao io satria tsy manaraka ny firafitra tokony ho izy.
 Azafady manomeza adiresy voasoratra tsara na avelao ho banga io toerana io.',
 'cannotchangeemail' => "Tsy afaka ovaina eto amin'ity wiki ity ny adiresy imailaky ny kaonty.",
+'emaildisabled' => 'Tsy afaka mandefa imailaka ity tranonkala ity.',
 'accountcreated' => 'Kaonty voaforona',
 'accountcreatedtext' => "Voasokatra ilay kaonty hoan'i $1.",
 'createaccount-title' => "Fanokafana kaonty ho an'ny/i {{SITENAME}}",
@@ -862,7 +864,7 @@ Azonao atao ny [[Special:Search/{{PAGENAME}}||Tadiavo ny momba ny {{PAGENAME}}]]
 * '''[{{SERVER}}{{localurl:{{NAMESPACE}}:{{PAGENAME}}|action=edit}} Na forony eto ny lahatsoratra momba ny {{PAGENAME}}]'''.",
 'noarticletext-nopermission' => "Mbola tsy misy lahatsoratra ao amin'io pejy io.
 
-Azonao atao ny [[Special:Search/{{PAGENAME}}|Mikaroka momba ny lohatenin'io pejy io]] ao amin'ny pejy hafa, mitady <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} anatin'ny laogy mikasika azy]</span>",
+Azonao atao ny [[Special:Search/{{PAGENAME}}|mikaroka ity lohateny ity]] eny amin'ny pejy hafa na <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mitady ao amin'ny laogy misy fifandraisana]</span>, fa tsy azonao atao ny mamorona ity pejy ity.",
 'userpage-userdoesnotexist' => 'Mbola tsy nisoratra anarana ato i « <nowiki>$1</nowiki> ». Marino raha tena hamorona ity pejy ity ianao.',
 'userpage-userdoesnotexist-view' => 'Tsy nisoratra anarana ato i « $1 ».',
 'blocked-notice-logextract' => "Ankehitriny ity mpikambana ity dia voasakana.
@@ -966,6 +968,7 @@ Mety voafafa angamba izy.',
 'edit-already-exists' => 'Tsy afaka amboarina ilay pejy vaovao.
 Efa misy izy.',
 'defaultmessagetext' => 'Hafatra raha tsy misy',
+'invalid-content-data' => "Data anaty votoatiny tsy miady amin'ny fepetra",
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Tandremo : Betsaka loatra ny fanantsoana ny tao parser.
@@ -1693,10 +1696,12 @@ Raha mbola misy foana ilay  olana, manorata any amin'ny [[Special:ListUsers/syso
 'upload-too-many-redirects' => "Be loatra ny fihodinan'ny URL.",
 'upload-unknown-size' => 'tsy fantatra ny habe',
 'upload-http-error' => 'Nisy tsy fetezana HTTP nitranga : $1',
+'upload-copy-upload-invalid-domain' => "Tsy misy eto amin'ity dômenina ity ny tahaky ny upload.",
 
 # File backend
 'backend-fail-stream' => 'Tsy afaka mamaky ilay rakitra $1.',
 'backend-fail-backup' => 'Tsy afaka mitahiry ilay rakitra $1.',
+'backend-fail-notexists' => 'Tsy misy ilay rakitra $1.',
 'backend-fail-hashes' => "Tsy azo ilay hash an-drakitra ho an'ny fampitahana.",
 'backend-fail-notsame' => "Efa misy rakitra samihafa ho an'i $1",
 'backend-fail-invalidpath' => '$1 dia lalam-pitahirizana tsy azo raisina.',
@@ -1957,6 +1962,7 @@ Aza manadino manamarina raha tsy misy rohy makany amin'ny endrika hafa alohan'ny
 'mostlinkedtemplates' => "Misy firohizana betsaka amin'ny endrika",
 'mostcategories' => 'Lahatsoratra misy sokajy betsaka indrindra',
 'mostimages' => "Misy firohizana betsaka amin'ny sary",
+'mostinterwikis' => 'Pejy be interwiki indrindra',
 'mostrevisions' => 'Lahatsoratra niova im-betsaka indrindra',
 'prefixindex' => "Pejy manomboka amin'ny...",
 'prefixindex-namespace' => 'Ny pejy rehetra mitondra ny tovona (anaran-tsehatra $1)',
@@ -2010,6 +2016,7 @@ wiki ity aza izy.</p>",
 Azonao ferana ny fahitana ny tao amin'ny fisafidianana karazana laogy iray, anaram-pikambana iray na pejy iray (samihafa ny sorabaventy sy soramadinika).",
 'logempty' => 'Tsy nahitana.',
 'log-title-wildcard' => "Hitady amin'ny lohateny manomboka amin'io soratra io",
+'showhideselectedlogentries' => 'Haneho/Hanafina ny iditry ny laogy nofidiana',
 
 # Special:AllPages
 'allpages' => 'Pejy rehetra',
@@ -2027,6 +2034,10 @@ Azonao ferana ny fahitana ny tao amin'ny fisafidianana karazana laogy iray, anar
 'allpagesprefix' => "Asehoy ny pejy miantomboka amin'ny:",
 'allpagesbadtitle' => 'Tsy mety ny anaram-pejy : misy tovona iraisam-piteny na interwiki natokana, na misy soratra iray na maro tsy azo ampiasaina anaty anaram-pejy.',
 'allpages-bad-ns' => '{{SITENAME}} dia tsy manana anaran-tsehatra mitondra anarana « $1 ».',
+'allpages-hide-redirects' => 'Haneho ny fihodinana',
+
+# SpecialCachedPage
+'cachedspecial-refresh-now' => 'Hijery ny farany indrindra',
 
 # Special:Categories
 'categories' => 'Sokajy',
@@ -2089,6 +2100,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-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]],
 dia ahafahana mandefa hafatra tokana ho any aminy ity fisy eto ambany ity.
index e856db5..c531689 100644 (file)
@@ -2626,7 +2626,8 @@ $UNWATCHURL
 'undeletedrevisions' => '{{PLURAL:$1|1 измена е обновена|$1 измени се обновени}}',
 'undeletedrevisions-files' => '{{PLURAL:$1|1 измена|$1 измени}} и {{PLURAL:$2|1 податотека|$2 податотеки}} се вратени',
 'undeletedfiles' => '{{PLURAL:$1|1 податотека е вратена|$1 податотеки се вратени}}',
-'cannotundelete' => 'Враќањето не успеа. Можеби некој друг веќе ја вратил страницата.',
+'cannotundelete' => 'Враќањето не успеа:
+$1',
 'undeletedpage' => "'''$1 беше обновена'''
 
 Погледнете го [[Special:Log/delete|дневникот на бришења]] за попис на претходни бришења и обновувања.",
@@ -2935,6 +2936,7 @@ $1',
 'immobile-target-namespace-iw' => 'Меѓувики-врска не може да се користи за преименување на страници.',
 'immobile-source-page' => 'Оваа страница не може да се преместува.',
 'immobile-target-page' => 'Не може да се премести под бараниот наслов.',
+'bad-target-model' => 'Саканата одредница користи друг содржински модел. Не можам да претворам од $1 во $2.',
 'imagenocrossnamespace' => 'Не може да се премести податотека во неподатотечен именски простор',
 'nonfile-cannot-move-to-file' => 'Не можам да преместам неподатотека во податотечен именски простор',
 'imagetypemismatch' => 'Новата наставка на податотеката не соодветствува на нејзиниот тип',
@@ -4302,6 +4304,4 @@ $5
 'duration-centuries' => '$1 {{PLURAL:$1|век|века}}',
 'duration-millennia' => '$1 {{PLURAL:$1|милениум|милениуми}}',
 
-# Unknown messages
-'bad-target-model' => 'Саканата одредница користи друг содржински модел. Не можам да претворам од $1 во $2.',
 );
index 0266cbc..097e531 100644 (file)
@@ -1076,6 +1076,15 @@ $1 ആണ് ഈ തടയൽ നടത്തിയത്. ''$2'' എന്ന
 'edit-already-exists' => 'പുതിയ താൾ സൃഷ്ടിക്കാൻ കഴിഞ്ഞില്ല.
 താൾ ഇപ്പോൾ തന്നെ നിലവിലുണ്ട്.',
 'defaultmessagetext' => 'സ്വതേയുള്ള സന്ദേശ എഴുത്ത്',
+'content-failed-to-parse' => '$2 ഉള്ളടക്കം $1 മാതൃകയിൽ പാഴ്സ് ചെയ്യൽ പരാജയപ്പെട്ടു: $3',
+'invalid-content-data' => 'അസാധുവായ ഉള്ളടക്ക ഡേറ്റ',
+'content-not-allowed-here' => '"$1" ഉള്ളടക്കം [[$2]] താളിൽ അനുവദിക്കുന്നില്ല',
+
+# Content models
+'content-model-wikitext' => 'വിക്കിഎഴുത്ത്',
+'content-model-text' => 'ശുദ്ധ എഴുത്ത്',
+'content-model-javascript' => 'ജാവാസ്ക്രിപ്റ്റ്',
+'content-model-css' => 'സി.എസ്.എസ്.',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''മുന്നറിയിപ്പ്:''' ഈ താളിൽ വളരെക്കൂടുതൽ പാഴ്സർ ഫങ്ഷനുകൾ വിളിച്ചിരിക്കുന്നു.
@@ -2515,7 +2524,8 @@ $UNWATCHURL
 'undeletedrevisions' => '{{PLURAL:$1|ഒരു പതിപ്പ്|$1 പതിപ്പുകൾ}} പുനഃസ്ഥാപിച്ചിരിക്കുന്നു',
 'undeletedrevisions-files' => '{{PLURAL:$1|ഒരു പതിപ്പും|$1 പതിപ്പുകളും}} {{PLURAL:$2|ഒരു പ്രമാണവും|$2 പ്രമാണങ്ങളും}} പുനഃസ്ഥാപിച്ചിരിക്കുന്നു',
 'undeletedfiles' => '{{PLURAL:$1|ഒരു പ്രമാണം|$1 പ്രമാണങ്ങൾ}} പുനഃസ്ഥാപിച്ചു',
-'cannotundelete' => 'മായ്ക്കൽ തിരസ്ക്കരിക്കാനുള്ള ശ്രമം പരാജയപ്പെട്ടു. മറ്റാരെങ്കിലും ഇതിനു മുൻപ് മായ്ക്കൽ തിരസ്ക്കരിച്ചിരിക്കാം.',
+'cannotundelete' => 'മായ്ക്കൽ തിരസ്കരണം പരാജയപ്പെട്ടു:
+$1',
 'undeletedpage' => "'''$1 പുനഃസ്ഥാപിച്ചിരിക്കുന്നു'''
 
 പുതിയതായി നടന്ന ഒഴിവാക്കലുകളുടേയും പുനഃസ്ഥാപനങ്ങളുടേയും വിവരങ്ങൾ കാണാൻ [[Special:Log/delete|മായ്ക്കൽ ലോഗ്]] കാണുക.",
@@ -2821,6 +2831,7 @@ $1',
 'immobile-target-namespace-iw' => 'അന്തർവിക്കി കണ്ണി താൾ മാറ്റാനുള്ള സാധുവായ ലക്ഷ്യമല്ല.',
 'immobile-source-page' => 'ഈ താൾ മാറ്റാൻ സാദ്ധ്യമല്ല',
 'immobile-target-page' => 'ലക്ഷ്യമാക്കിയ തലക്കെട്ടിലേക്ക് മാറ്റാൻ സാധിക്കില്ല.',
+'bad-target-model' => 'ആഗ്രഹിക്കുന്ന ലക്ഷ്യം മറ്റൊരു ഉള്ളടക്ക മാതൃകയാണ് ഉപയോഗിക്കുന്നത്. $1 എന്നതിനെ $2 ആക്കി മാറ്റാൻ കഴിയില്ല.',
 'imagenocrossnamespace' => 'പ്രമാണം അതിനായി അല്ലാത്ത നാമമേഖലയിലേയ്ക്ക് മാറ്റാൻ കഴിയില്ല',
 'nonfile-cannot-move-to-file' => 'പ്രമാണമല്ലാത്തവ പ്രമാണം നാമമേഖലയിലേയ്ക്ക് മാറ്റാൻ കഴിയില്ല.',
 'imagetypemismatch' => 'പുതിയ പ്രമാണത്തിന്റെ എക്സ്റ്റെൻഷൻ അതിന്റെ തരവുമായി ഒത്തുപോകുന്നില്ല.',
index f1bed2f..d41d9ea 100644 (file)
@@ -953,6 +953,15 @@ Log penghapusan bagi laman ini dilampirkan di bawah untuk rujukan.',
 'edit-no-change' => 'Suntingan anda diabaikan kerana tiada perubahan dibuat pada teks tersebut.',
 'edit-already-exists' => 'Tidak dapat mencipta laman baru kerana ia telah wujud.',
 'defaultmessagetext' => 'Teks mesej asal',
+'content-failed-to-parse' => 'Kandungan $2 tidak dapat dihuraikan untuk model $1: $3',
+'invalid-content-data' => 'Data kandungan tidak sah',
+'content-not-allowed-here' => 'Kandungan "$1" tidak dibenarkan di halaman [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'wikiteks',
+'content-model-text' => 'teks biasa',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Amaran: Laman ini mengandungi terlalu banyak panggilan fungsi penghurai yang intensif.
@@ -2408,7 +2417,7 @@ atau semakan tersebut telah dipulihkan atau dibuang daripada arkib.',
 'undeletedrevisions' => '$1 semakan dipulihkan',
 'undeletedrevisions-files' => '$1 semakan dan $2 fail dipulihkan',
 'undeletedfiles' => '$1 fail dipulihkan',
-'cannotundelete' => 'Penyahhapusan gagal; mungkin orang lain telah pun mengnyahhapuskannya.',
+'cannotundelete' => 'Penyahhapusan gagal: $1',
 'undeletedpage' => "'''$1 telah dipulihkan'''
 
 Sila rujuk [[Special:Log/delete|log penghapusan]] untuk rekod penghapusan terkini.",
@@ -2712,6 +2721,7 @@ Laman destinasi "[[:$1]]" telah pun wujud. Adakah anda mahu menghapuskannya supa
 'immobile-target-namespace-iw' => 'Pautan interwiki tidak boleh dijadikan sasaran untuk pemindahan laman.',
 'immobile-source-page' => 'Anda tidak boleh memindahkan laman ini.',
 'immobile-target-page' => 'Anda tidak boleh memindahkan laman ke tajuk itu.',
+'bad-target-model' => 'Destinasi yang dikehendaki menggunakan model kandungan yang berlainan. $1 tidak dapat ditukar kepada $2.',
 'imagenocrossnamespace' => 'Anda tidak boleh memindahkan fail ke ruang nama bukan fail',
 'nonfile-cannot-move-to-file' => 'Laman bukan fail tidak boleh dipindahkan ke ruang nama fail',
 'imagetypemismatch' => 'Sambungan baru fail tersebut tidak sepadan dengan jenisnya',
index 40952c6..74ec4ab 100644 (file)
@@ -1154,6 +1154,12 @@ Deze lijkt verwijderd te zijn.',
 Deze bestaat al.',
 'defaultmessagetext' => 'Standaardinhoud',
 
+# Content models
+'content-model-wikitext' => 'wikitekst',
+'content-model-text' => 'platte tekst',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
+
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''Waarschuwing:''' deze pagina gebruikt te veel kostbare parserfuncties.
 
index 5856cf6..d94b030 100644 (file)
@@ -1024,7 +1024,7 @@ Det siste loggelementet er oppgjeve under som referanse:",
 Det siste loggelementet er oppgjeve under som referanse:",
 'templatesused' => '{{PLURAL:$1|Mal|Malar}} som er brukte på denne sida:',
 'templatesusedpreview' => '{{PLURAL:$1|Mal som er brukt|Malar som er brukte}} i førehandsvisinga:',
-'templatesusedsection' => '{{PLURAL:$1|Mal|Malar}} som er brukte i denne bolken:',
+'templatesusedsection' => '{{PLURAL:$1|Mal som er brukt|Malar som er brukte}} i denne bolken:',
 'template-protected' => '(verna)',
 'template-semiprotected' => '(delvis verna)',
 'hiddencategories' => 'Denne sida er med i {{PLURAL:$1|éin gøymd kategori|$1 gøymde kategoriar}}:',
@@ -1042,7 +1042,7 @@ Du kan gå attende og endre ei eksisterande side, [[Special:UserLogin|logge inn
 
 Du bør tenkje over om det er høveleg å halde fram med å endre denne sida.
 Sletteloggen for sida finn du her:",
-'moveddeleted-notice' => 'Denne sida er vorten sletta. Sletteloggen og flytteloggen er vist nedanfor for referanse.',
+'moveddeleted-notice' => 'Sida er vorten sletta. Sletteloggen og flytteloggen er viste nedanfor for referanse.',
 'log-fulllog' => 'Sjå full loggføring',
 'edit-hook-aborted' => 'Endring avbroten av ein funksjon, utan forklaring.',
 'edit-gone-missing' => 'Kunne ikkje oppdatere sida.
@@ -1679,7 +1679,7 @@ For å bruke ei fil på ei side, bruk ei lenkje på eit liknande format:
 'filestatus' => 'Opphavsrettsstatus:',
 'filesource' => 'Kjelde:',
 'uploadedfiles' => 'Filer som er opplasta',
-'ignorewarning' => 'Oversjå åtvaringa og lagre fila',
+'ignorewarning' => 'Sjå bort frå åtvaringa og lagre fila likevel',
 'ignorewarnings' => 'Oversjå åtvaringar',
 'minlength1' => 'Filnamn må ha minst eitt teikn.',
 'illegalfilename' => 'Filnamnet «$1» inneheld teikn som ikkje er tillatne i sidetitlar. Skift namn på fila og prøv på nytt.',
@@ -2084,7 +2084,7 @@ Merk at andre internettsider kan ha direkte lenkjer til filer, og difor kan file
 'log' => 'Loggar',
 'all-logs-page' => 'Alle offentlege loggar',
 'alllogstext' => 'Kombinert vising av alle loggane på {{SITENAME}}. Du kan avgrense resultatet ved å velje loggtype, brukarnamn eller den sida som er påverka (hugs å skilje mellom store og små bokstavar)',
-'logempty' => 'Ingen treff i loggane.',
+'logempty' => 'Ingen element i loggen passar.',
 'log-title-wildcard' => 'Søk i titlar som byrjar med denne teksten',
 'showhideselectedlogentries' => 'Vis/gøym valde loggoppføringar',
 
@@ -2231,18 +2231,19 @@ Om du seinare vil fjerne sida frå overvakingslista, klikk på «Fjern overvakin
 'watchnochange' => 'Ingen av sidene i overvakingslista er endra i den valde perioden.',
 'watchlist-details' => '{{PLURAL:$1|Éi side|$1 sider}} er overvaka, utanom diskusjonssider.',
 'wlheader-enotif' => '* Funksjonen for endringsmeldingar per e-post er på.',
-'wlheader-showupdated' => "* Sider som har blitt endra sidan du sist såg på dei er '''utheva'''",
+'wlheader-showupdated' => "* Sider som har vorte endra sidan du sist såg på dei er '''utheva'''",
 'watchmethod-recent' => 'sjekkar siste endringar for dei overvaka sidene',
 'watchmethod-list' => 'sjekkar om dei overvaka sidene har blitt endra i det siste',
 'watchlistcontains' => 'Overvakingslista di inneheld {{PLURAL:$1|éi side|$1 sider}}.',
 'iteminvalidname' => 'Problem med «$1», ugyldig namn...',
 'wlnote' => "Nedanfor er {{PLURAL:$1|den siste endringa|dei siste '''$1''' endringane}} {{PLURAL:$2|den siste timen|dei siste '''$2''' timane}}, for $3, kl. $4.",
-'wlshowlast' => 'Vis siste $1 timar $2 dagar $3',
+'wlshowlast' => 'Vis siste $1 timane $2 dagane $3',
 'watchlist-options' => 'Alternativ for overvakingslista',
 
 # Displayed when you click the "watch" button and it is in the process of watching
 'watching' => 'Overvakar...',
 'unwatching' => 'Fjernar frå overvakinglista...',
+'watcherrortext' => 'Det oppstod ein feil under endringa av overvakingsinnstillingane dine for «$1».',
 
 'enotif_mailer' => '{{SITENAME}}-endringsmeldingssendar',
 'enotif_reset' => 'Merk alle sidene som vitja',
@@ -2343,6 +2344,7 @@ Sjå [[Special:ProtectedPages|lista over verna sider]] for lista over vern som n
 'protect-title-notallowed' => 'Sjå vernenivået til «$1»',
 'prot_1movedto2' => '«[[$1]]» flytt til «[[$2]]»',
 'protect-badnamespace-title' => 'Namnerommet kan ikkje vernast',
+'protect-badnamespace-text' => 'Sider i dette namnerommet kan ikkje vernast.',
 'protect-legend' => 'Stadfest vern',
 'protectcomment' => 'Grunngjeving:',
 'protectexpiry' => 'Endar:',
@@ -2782,6 +2784,7 @@ Vitja [//www.mediawiki.org/wiki/Localisation MediaWiki Localisation] og [//trans
 'import-interwiki-templates' => 'Inkluder alle malar',
 'import-interwiki-submit' => 'Importer',
 'import-interwiki-namespace' => 'Målnamnerom:',
+'import-interwiki-rootpage' => 'Målrotside (valfri):',
 'import-upload-filename' => 'Filnamn:',
 'import-comment' => 'Kommentar:',
 'importtext' => 'Lagre fila frå kjeldewikien med [[Special:Export|eksporteringsverktøyet]] på din eigen datamaskin, og last henne så opp her.',
@@ -2813,6 +2816,9 @@ Vitja [//www.mediawiki.org/wiki/Localisation MediaWiki Localisation] og [//trans
 'import-error-interwiki' => 'Sida «$1» vart ikkje importert sidan namnet hennar er reservert for ekstern lenking (interwiki).',
 'import-error-special' => 'Sida «$1» vart ikkje importert sidan ho høyrer til eit spesialnamnerom som ikkje tillèt sider.',
 'import-error-invalid' => 'Sida «$1» vart ikkje importert sidan namnet er ugildt.',
+'import-options-wrong' => '{{PLURAL:$2|Galt val|Gale val}}: <nowiki>$1</nowiki>',
+'import-rootpage-invalid' => 'Den oppgjevne rotsida er ein ugild tittel',
+'import-rootpage-nosubpage' => 'Namnerommet «$1» til rotsida tillèt ikkje undersider.',
 
 # Import log
 'importlogpage' => 'Importeringslogg',
@@ -2965,6 +2971,7 @@ Vitja [//www.mediawiki.org/wiki/Localisation MediaWiki Localisation] og [//trans
 'pageinfo-watchers' => 'Tal på overvakarar av sida',
 'pageinfo-redirects-name' => 'Omdirigeringar til sida',
 'pageinfo-subpages-name' => 'Undersider av sida',
+'pageinfo-subpages-value' => '$1 ({{PLURAL:$2|éi omdirigering|$2 omdirigeringar}}; {{PLURAL:$3|éi ikkje-omdirigering|$3 ikkje-omdirigeringar}})',
 'pageinfo-firstuser' => 'Sideopprettar',
 'pageinfo-firsttime' => 'Dato for opprettinga av sida',
 'pageinfo-lastuser' => 'Siste forfattaren',
@@ -3028,6 +3035,7 @@ $1',
 'file-info-size-pages' => '$1 × $2 pikslar, filstorleik: $3, MIME-type: $4, {{PLURAL:$5|éi side|$5 sider}}',
 'file-nohires' => 'Høgare oppløysing er ikkje tilgjengeleg.',
 'svg-long-desc' => 'SVG-fil, standardoppløysing: $1 × $2 pikslar, filstorleik: $3',
+'svg-long-desc-animated' => 'Animert SVG-fil, standardoppløysing $1 × $2 pikslar, filstorleik: $3',
 'show-big-image' => 'Full oppløysing',
 'show-big-image-preview' => 'Storleik på førehandsvising: $1.',
 'show-big-image-other' => '{{PLURAL:$2|Anna oppløysing|Andre oppløysingar}}: $1.',
@@ -3037,6 +3045,8 @@ $1',
 'file-info-png-looped' => '↓oppatteke',
 'file-info-png-repeat' => 'spela av {{PLURAL:$1|éin gong|$1 gonger}}',
 'file-info-png-frames' => '$1 {{PLURAL:$1|bilete|bilete}}',
+'file-no-thumb-animation' => "'''Merk: Grunna tekniske avgrensingar vil ikkje miniatyrbilete av fila verta animerte.'''",
+'file-no-thumb-animation-gif' => "'''Merk: Grunna tekniska avgrensingar vil ikkje miniatyrbilete av høgoppløyselege GIF-bilete som dette verta animerte.'''",
 
 # Special:NewFiles
 'newimages' => 'Filgalleri',
@@ -3225,6 +3235,8 @@ Andre er gøymde som standard.
 'exif-languagecode' => 'Språk',
 'exif-iimversion' => 'IIM-versjon',
 'exif-iimcategory' => 'Kategori',
+'exif-datetimeexpires' => 'Skal ikkje nyttast etter',
+'exif-datetimereleased' => 'Frigjeve',
 'exif-lens' => 'Objektiv',
 'exif-cameraownername' => 'Eigar av kameraet',
 'exif-label' => 'Merkelapp',
index 4643c41..09f182b 100644 (file)
@@ -3119,11 +3119,11 @@ J'àutri a saran stërmà coma stàndard.
 'exif-event' => 'Event fotografà',
 'exif-organisationinimage' => 'Organisassion fotografà',
 'exif-personinimage' => 'Përson-a fotografà',
-'exif-originalimageheight' => "Autëssa dla figura prima ch'a sia ritajà",
-'exif-originalimagewidth' => "Larghëssa dla figura prima ch'a sia ritajà",
+'exif-originalimageheight' => "Autëssa dla figura prima ch'a fussa ritajà",
+'exif-originalimagewidth' => "Larghëssa dla figura prima ch'a fussa ritajà",
 
 # EXIF attributes
-'exif-compression-1' => 'Pa compress',
+'exif-compression-1' => 'Nen comprimù',
 'exif-compression-2' => "CCITT Partìa 3 longheur dla codìfica d'esecussion dla codìfica Huffman modificà ëd dimension 1",
 'exif-compression-3' => 'CCITT Partìa 3 codìfica dël fax',
 'exif-compression-4' => 'CCITT Partìa 4 codìfica dël fax',
@@ -3134,7 +3134,7 @@ J'àutri a saran stërmà coma stàndard.
 'exif-unknowndate' => 'Data nen conossùa',
 
 'exif-orientation-1' => 'Normal',
-'exif-orientation-2' => 'Specolar',
+'exif-orientation-2' => 'A specc',
 'exif-orientation-3' => 'Arvirà ëd 180°',
 'exif-orientation-4' => 'Arvirà dzorsuta',
 'exif-orientation-5' => 'Arvirà dzorsota e ëd 90° contramostra',
index 30e1ec1..180538f 100644 (file)
@@ -1035,7 +1035,9 @@ Example: [http://translatewiki.net/w/i.php?title=Project:News&oldid=9999999 Perm
 'explainconflict' => 'Appears at the top of a page when there is an edit conflict.',
 'storedversion' => 'This is used in an edit conflict as the label for the top revision that has been stored, as opposed to your version that has not been stored which is shown at the bottom of the page.',
 'yourdiff' => '',
-'copyrightwarning' => 'Copyright warning displayed under the edit box in editor',
+'copyrightwarning' => 'Copyright warning displayed under the edit box in editor
+*$1 - ...
+*$2 - ...',
 'longpageerror' => 'Warning displayed when trying to save a text larger than the maximum size allowed',
 'protectedpagewarning' => '{{Related|Semiprotectedpagewarning}}',
 'semiprotectedpagewarning' => '{{Related|Semiprotectedpagewarning}}',
@@ -1060,11 +1062,36 @@ Please report at [[Support]] if you are unable to properly translate this messag
 'moveddeleted-notice' => 'Shown on top of a deleted page in normal view modus ([http://translatewiki.net/wiki/Test example]).',
 'edit-conflict' => "An 'Edit conflict' happens when more than one edit is being made to a page at the same time. This would usually be caused by separate individuals working on the same page. However, if the system is slow, several edits from one individual could back up and attempt to apply simultaneously - causing the conflict.",
 'defaultmessagetext' => 'Caption above the default message text shown on the left-hand side of a diff displayed after clicking “Show changes” when creating a new page in the MediaWiki: namespace',
-'content-failed-to-parse' => "Error message indicating that the page\'s content can not be saved because it is syntactically invalid. This may occurr for content types using serialization or a strict markup syntax.",
-'invalid-content-data'             => 'Error message indicating that the page\'s content can not be saved because it is invalid. This may occurr for content types with internal consistency constraints.',
-'content-not-allowed-here'         => 'Error message indicating that the desired content model is not supported in given localtion.
-* $1 is the human readable name of the content model
-* $1 is the title of the page in question.',
+'content-failed-to-parse' => "Error message indicating that the page's content can not be saved because it is syntactically invalid. This may occurr for content types using serialization or a strict markup syntax.
+*$1 – content model ({{msg-mw|Content-model-wikitext}}, {{msg-mw|Content-model-javascript}}, {{msg-mw|Content-model-css}} or {{msg-mw|Content-model-text}})
+*$2 – content format as MIME type (e.g. <tt>text/css</tt>)
+*$3 – specific error message",
+'invalid-content-data' => "Error message indicating that the page's content can not be saved because it is invalid. This may occurr for content types with internal consistency constraints.",
+'content-not-allowed-here' => 'Error message indicating that the desired content model is not supported in given localtion.
+* $1 is the human readable name of the content model: {{msg-mw|Content-model-wikitext}}, {{msg-mw|Content-model-javascript}}, {{msg-mw|Content-model-css}} or {{msg-mw|Content-model-text}}
+* $2 is the title of the page in question.',
+
+# Content models
+'content-model-wikitext' => 'Name for the wikitext content model, used when decribing what type of content a page contains.
+
+This message is substituted in:
+*{{msg-mw|Bad-target-model}}
+*{{msg-mw|Content-not-allowed-here}}',
+'content-model-text' => 'Name for the plain text content model, used when decribing what type of content a page contains.
+
+This message is substituted in:
+*{{msg-mw|Bad-target-model}}
+*{{msg-mw|Content-not-allowed-here}}',
+'content-model-javascript' => 'Name for the JavaScript content model, used when decribing what type of content a page contains.
+
+This message is substituted in:
+*{{msg-mw|Bad-target-model}}
+*{{msg-mw|Content-not-allowed-here}}',
+'content-model-css' => 'Name for the CSS content model, used when decribing what type of content a page contains.
+
+This message is substituted in:
+*{{msg-mw|Bad-target-model}}
+*{{msg-mw|Content-not-allowed-here}}',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'On some (expensive) [[MetaWikipedia:Help:ParserFunctions|parser functions]] (e.g. <code><nowiki>{{#ifexist:}}</nowiki></code>) there is a limit of how many times it may be used. This is an error message shown when the limit is exceeded.
@@ -3200,10 +3227,12 @@ Parameters:
 'immobile-target-namespace-iw' => "This message appears when attempting to move a page, if a person has typed an interwiki link as a namespace prefix in the input box labelled 'To new title'.  The special page 'Movepage' cannot be used to move a page to another wiki.
 
 'Destination' can be used instead of 'target' in this message.",
-'bad-target-model'             => "This message is shown when attempting to move a page, but the move would change the page's content model.
-This may be the case when \$wgContentHandlerUseDB is set to false, because then a page's content model is derived from the page's title.
-* $1: The localized name of the original page's content model.
-* $2: The localized name of the content model used by the destination title.",
+'bad-target-model' => 'This message is shown when attempting to move a page, but the move would change the page\'s content model.
+This may be the case when [[mw:Manual:$wgContentHandlerUseDB|$wgContentHandlerUseDB]] is set to false, because then a page\'s content model is derived from the page\'s title.
+* $1: The localized name of the original page\'s content model:
+**{{msg-mw|Content-model-wikitext}}, {{msg-mw|Content-model-javascript}}, {{msg-mw|Content-model-css}} or {{msg-mw|Content-model-text}}
+* $2: The localized name of the content model used by the destination title:
+**{{msg-mw|Content-model-wikitext}}, {{msg-mw|Content-model-javascript}}, {{msg-mw|Content-model-css}} or {{msg-mw|Content-model-text}}',
 'fix-double-redirects' => 'This is a checkbox in [[Special:MovePage]] which allows to move all redirects from the old title to the new title.',
 'protectedpagemovewarning' => 'Related message: [[MediaWiki:protectedpagewarning/{{#titleparts:{{PAGENAME}}|1|2}}]]
 {{Related|Semiprotectedpagewarning}}',
@@ -4913,10 +4942,4 @@ $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.',
 
-# Content model IDs for the ContentHandler facility; used by ContentHandler::getContentModel()
-'content-model-wikitext' => 'Name for the wikitext content model, used when decribing what type of content a page contains.',
-'content-model-javascript' => 'Name for the JavaScript content model, used when decribing what type of content a page contains.',
-'content-model-css' => 'Name for the CSS content model, used when decribing what type of content a page contains.',
-'content-model-text' => 'Name for the plain text content model, used when decribing what type of content a page contains.',
-
 );
index 88fbdca..dd972bb 100644 (file)
@@ -1077,6 +1077,15 @@ Se pare că a fost ștearsă.',
 'edit-already-exists' => 'Pagina nouă nu a putut fi creată.
 Ea există deja.',
 'defaultmessagetext' => 'Textul implicit',
+'content-failed-to-parse' => 'Nu s-a putut analiza conținutul de tip $2 pentru modelul $1: $3',
+'invalid-content-data' => 'Date de conținut invalide',
+'content-not-allowed-here' => 'Conținutul de tip „$1” nu este permis pe pagina [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'wikitext',
+'content-model-text' => 'text simplu',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Atenție: Această pagină conține prea multe apelări costisitoare ale funcțiilor parser.
@@ -2529,7 +2538,8 @@ S-ar putea ca legătura să fie greșită, ori versiunea să fi fost restaurată
 'undeletedrevisions' => '{{PLURAL:$1|o versiune restaurată|$1 versiuni restaurate|$1 de versiuni restaurate}}',
 'undeletedrevisions-files' => '{{PLURAL:$1|O versiune|$1 versiuni|$1 de versiuni}} și {{PLURAL:$2|un fișier|$2 fișiere|$2 de fișiere}} recuperate',
 'undeletedfiles' => '{{PLURAL:$1|O versiune recuperată|$1 versiuni recuperate|$1 de versiuni recuperate}}',
-'cannotundelete' => 'Recuperarea a eșuat; este posibil ca altcineva să fi recuperat pagina deja.',
+'cannotundelete' => 'Recuperarea a eșuat:
+$1',
 'undeletedpage' => "'''$1 a fost recuperat'''
 
 Consultați [[Special:Log/delete|jurnalul ștergerilor]] pentru a vedea toate ștergerile și recuperările recente.",
@@ -2841,6 +2851,7 @@ Pagina destinație „[[:$1]]” există deja. Doriți să o ștergeți pentru a
 'immobile-target-namespace-iw' => 'Legătura interwiki nu este o țintă validă pentru redenumire.',
 'immobile-source-page' => 'Această pagină nu poate fi redenumită.',
 'immobile-target-page' => 'Imposibil de redenumit pagina la acel titlu.',
+'bad-target-model' => 'Destinația dorită folosește un alt model de conținut. Nu se poate converti $1 în $2.',
 'imagenocrossnamespace' => 'Fișierul nu poate fi mutat la un spațiu de nume care nu este destinat fișierelor',
 'nonfile-cannot-move-to-file' => 'Entitatea (care nu este un fișier) nu poate fi mutată în spațiul de nume destinat fișierelor',
 'imagetypemismatch' => 'Extensia nouă a fișierului nu se potrivește cu tipul acestuia',
index e6a1910..39bd1d2 100644 (file)
@@ -1075,7 +1075,7 @@ $2
 'viewpagelogs' => 'अस्य पृष्ठस्य लॉंग् इत्येतद् दर्शयतु',
 'nohistory' => 'अस्य पृष्ठस्य कृते पृष्ठेतिहासः न वर्तते।',
 'currentrev' => 'सद्यःकालीना आवृत्तिः',
-'currentrev-asof' => 'वरà¥\8dतमतà¥\80 आवृत्तिः $1 इति समये',
+'currentrev-asof' => 'वरà¥\8dतमाना आवृत्तिः $1 इति समये',
 'revisionasof' => '$1 इत्यस्य आवृत्तिः',
 'revision-info' => '$1इति समयस्य आवृत्तिः $2 इत्यनेन',
 'previousrevision' => '← पुरातनानि संस्करणानि',
@@ -1889,7 +1889,7 @@ See https://www.mediawiki.org/wiki/Manual:Image_Authorization.',
 'filehist-current' => 'सद्योजातम्',
 'filehist-datetime' => 'दिनाङ्कः/समयः',
 'filehist-thumb' => 'अंगुष्ठनखाकारम्',
-'filehist-thumbtext' => '$1 à¤¸à¤®à¤¯à¥\87 à¤µà¤¿à¤¦à¥\8dयमतà¥\8dयाः आवृत्तेः अंगुष्ठनखाकारम्',
+'filehist-thumbtext' => '$1 à¤¸à¤®à¤¯à¥\87 à¤µà¤¿à¤¦à¥\8dयमानायाः आवृत्तेः अंगुष्ठनखाकारम्',
 'filehist-nothumb' => 'अङ्गुष्टनखाकारकं नाश्ति ।',
 'filehist-user' => 'योजकः',
 'filehist-dimensions' => 'आयामाः',
index c7ed509..2ac8d0f 100644 (file)
@@ -866,7 +866,6 @@ $2
 * '''ෆයර්ෆොක්ස්/ සෆාරි:''' ''Reload'' ඔබන අතරතුර ''Shift'' ඔබන්න, නැතහොත්  ''Ctrl-F5'' හෝ''Ctrl-R'' (මැක්හීදී ''Command-R'' ) ඔබන්න
 * '''ගූගල් ක්‍රෝම්:''' ''Ctrl-Shift-R'' ඔබන්න(මැක්හී ''Command-Shift-R'' )
 * '''ඉන්ටර්නෙට් එක්ස්ප්ලෝර:''' ''Refresh'' ඔබන අතරතුර  ''Ctrl''  ඔබන්න, නැතහොත් ''Ctrl-F5'' ඔබන්න
-* '''කොන්කරර්:''' ''Reload'' ඔබන්න හෝ  ''F5'' ඔබන්න
 * '''ඔපෙරා:''' ''Tools → Preferences'' හි කෑෂය හිස් කරන්න",
 'usercssyoucanpreview' => "'''හෝඩුවාව:'''සුරැකුමට පෙර, ඔබගේ නව  CSS පරික්ෂා කරනු වස්, \"{{int:පෙර-දසුන පෙන්වන්න}}\" බොත්තම භාවිතා කරන්න.",
 'userjsyoucanpreview' => "'''හෝඩුවාව:'''සුරැකුමට පෙර, ඔබගේ නව  ජාවා ස්ක්‍රිප්ට් පරික්ෂා කරනු වස්, \"{{int:පෙර-දසුන පෙන්වන්න}}\" බොත්තම භාවිතා කරන්න.",
@@ -1115,7 +1114,8 @@ $1",
 'revdelete-only-restricted' => '$2 දිනැති අයිතමය සැඟවීමේ දෝෂය , $1:අනෙකුත් සැඟවීම් විකල්පයන් අතුරින් එකක් තෝරාගන්නේ නැතිව, පරිපාලකයන්ගේ දර්ශනයෙන් අයිතමයන් සැඟවීම  ඔබහට සිදුකල නොහැක.',
 'revdelete-reason-dropdown' => '*මකා දැමීමේ පොදු හේතු
 **කතු හිමිකම් උල්ලංඝනය
-**නුසුදුසු පුද්ගලික කොරතුරු
+**නුසුදුසු පරිකථන හෝ පුද්ගලික කොරතුරු
+**නුසුදුසු පරිශීලක නම
 **අපහාසාත්මක විය හැකි තොරතුරු',
 'revdelete-otherreason' => 'වෙනත්/අමතර හේතු:',
 'revdelete-reasonotherlist' => 'වෙනත් හේතු',
@@ -1125,7 +1125,7 @@ $1",
 # Suppression log
 'suppressionlog' => 'යටපත්කිරීම් පිළිබඳ සටහන',
 'suppressionlogtext' => 'පරිපාලකයන්ගෙන් සැඟවුනු අන්තර්ගතය සම්බන්ධ මකාදැමීම් හා වාරණ ලැයිස්තුවක් මෙහි පහත දැක්වේ.
-දà·\90නට à¶\9aà·\8aâ\80\8dරà·\92යà·\8fතà·\8aමà¶\9a à·\80න à¶­à·\84නමà·\8a à·\84à·\8f à·\80à·\8fරණයනà·\8a à¶½à·\90යà·\92à·\83à·\8aතà·\94à·\80à¶\9aà·\8a à·\83ඳà·\84à·\8f [[Special:BlockList|à\85නà·\8aතරà·\8aජà·\8fල à·\80à·\8fරණ à¶½à·\90යà·\92à·\83à·\8aතà·\94à·\80]] à¶¶à¶½à¶±à·\8aන.',
+දැනට ක්‍රියාත්මක වන තහනම් හා වාරණයන් ලැයිස්තුවක් සඳහා [[Special:BlockList|වාරණ ලැයිස්තුව]] බලන්න.',
 
 # History merging
 'mergehistory' => 'පිටු ඉතිහාසයන් ඒකාබද්ධ කරන්න',
@@ -1732,7 +1732,7 @@ URLහි නීතික බව හා ප්‍රවේශ්‍ය බව 
 'backend-fail-create' => '$1 ගොනුව ලිවිය නොහැකි විය.',
 'backend-fail-maxsize' => '{{PLURAL:$2|බයිට එකකට|බයිට $2 කට}} වඩා විහාල බැවින්  $1 ගොනුව ලිවිය නොහැකි විය.',
 'backend-fail-readonly' => 'ගබඩා බැක්එන්ඩය "$1" දැනට කියවීම-පමණක් සඳහා වෙයි. දක්වා ඇති හේතුව නම්: "\'\'$2\'\'"',
-'backend-fail-usable' => 'අවසර ප්‍රමාණවත් නොවීම නිසාවෙන් හෝ නාමාවලී/බහාලුම් නොමැති වීම නිසාවෙන් $1 ගොනුව ලිවිය නොහැකි විය.',
+'backend-fail-usable' => 'අවසර ප්‍රමාණවත් නොවීම නිසාවෙන් හෝ නාමාවලී/බහාලුම් නොමැති වීම නිසාවෙන් "$1" ගොනුව කියවිය හෝ ලිවිය හෝ නොහැකි විය.',
 
 # Lock manager
 'lockmanager-notlocked' => '"$1" හී අගුළු ඇරිය නොහැක; එය අගුළු දමාද නොමැත.',
index 5fcadbf..712c6c1 100644 (file)
@@ -439,7 +439,7 @@ $messages = array(
 'vector-action-protect' => 'Zamknúť',
 'vector-action-undelete' => 'Obnoviť',
 'vector-action-unprotect' => 'Zmeniť stav ochrany',
-'vector-simplesearch-preference' => 'Povoliť rozšírené návrhy hľadania (iba pre tému Vector)',
+'vector-simplesearch-preference' => 'Povoliť zjednodušené pole hľadania (iba pre tému Vector)',
 'vector-view-create' => 'Vytvoriť',
 'vector-view-edit' => 'Upraviť',
 'vector-view-history' => 'Zobraziť históriu',
@@ -659,8 +659,11 @@ Požiadavka: $2',
 'protectedpagetext' => 'Táto stránka bola zamknutá aby sa zamedzilo úpravám.',
 'viewsourcetext' => 'Môžete si zobraziť a kopírovať zdroj tejto stránky:',
 'viewyourtext' => "Môžete si prehliadnuť a skopírovať zdrojový kód '''vašich zmien''' tejto stránky:",
-'protectedinterface' => 'Táto stránka poskytuje text používateľského rozhrania a je zamknutá, aby sa predišlo jej zneužitiu.',
-'editinginterface' => "'''Upozornenie:''' Upravujete stránku, ktorá poskytuje text používateľského rozhrania. Zmeny tejto stránky ovplyvnia vzhľad používateľského rozhrania ostatných používateľov. Zmeny prosím vykonávajte prostredníctvom [//translatewiki.net/wiki/Main_Page?setlang=sk translatewiki.net], projektu pre lokalizáciu MediaWiki.",
+'protectedinterface' => 'Táto stránka poskytuje text používateľského rozhrania tejto wiki a je zamknutá, aby sa predišlo jej zneužitiu.
+Ak chcete pridať alebo zmeniť preklady pre všetky wiki, prosím, použite [//translatewiki.net/wiki/Main_Page?setlang=sk translatewiki.net], projekt lokalizácie MediaWiki.',
+'editinginterface' => "'''Upozornenie:''' Upravujete stránku, ktorá poskytuje text používateľského rozhrania.
+Zmeny tejto stránky ovplyvnia vzhľad používateľského rozhrania ostatným používateľom.
+Ak chcete pridať alebo zmeniť preklady pre všetky wiki, prosím, použite [//translatewiki.net/wiki/Main_Page?setlang=sk translatewiki.net], projekt lokalizácie MediaWiki.",
 'sqlhidden' => '(SQL príkaz je skrytý)',
 'cascadeprotected' => 'Táto stránka bola zamknutá proti úpravám, pretože je použitá na {{PLURAL:$1|nasledovnej stránke, ktorá je zamknutá|nasledovných stránkach, ktoré sú zamknuté}} voľbou „kaskádového zamknutia“:
 $2',
@@ -950,7 +953,7 @@ Môžete [[Special:Search/{{PAGENAME}}|vyhľadávať názov tejto stránky]] v o
 alebo [{{fullurl:{{FULLPAGENAME}}|action=edit}} upravovať túto stránku]</span>.',
 'noarticletext-nopermission' => 'Táto stránka momentálne neobsahuje žiadny text.
 Môžete [[Special:Search/{{PAGENAME}}|hľadať názov tejto stránky]] v texte iných stránok
-alebo <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} si pozrieť súvisiace záznamy]</span>.',
+alebo <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} hľadať v súvisiacich záznamoch]</span>, ale nemáte oprávnenie túto stránku vytvoriť.',
 'missing-revision' => 'Revízia #$1 stránky s názvom „{{PAGENAME}}“ neexistuje.
 
 Pravdepodobne ste nasledovali zastaraný odkaz na historickú verziu stránky, ktorá bola medzičasom odstránená.
@@ -1057,6 +1060,15 @@ Zdá sa, že bola zmazaná.',
 'edit-already-exists' => 'Nebolo možné vytvoriť novú stránku.
 Už existuje.',
 'defaultmessagetext' => 'Predvolený text správy',
+'content-failed-to-parse' => 'Nepodarilo sa spracovať obsah $2 pre model $1: $3',
+'invalid-content-data' => 'Neplatné dáta obsahu',
+'content-not-allowed-here' => 'Obsah „$1“ nie je povolený na stránke [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'wikitext',
+'content-model-text' => 'čistý text',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Upozornenie: Táto stránka obsahuje príliš mnoho volaní funkcií syntaktického analyzátora, ktoré nadmerne zaťažujú server.
@@ -1078,6 +1090,7 @@ Tieto argumenty boli vynechané.',
 'expansion-depth-exceeded-warning' => 'Stránka prekročila povolenú hĺbku expanzie',
 'parser-unstrip-loop-warning' => 'Zistené zacyklenie volania rozširovacej značky',
 'parser-unstrip-recursion-limit' => 'Prektočený limit rekurzie volania rozširovacej značky ($1)',
+'converter-manual-rule-error' => 'Bola zistená chyba v pravidle manuálnej konverzie jazyka',
 
 # "Undo" feature
 'undo-success' => 'Úpravu je možné vrátiť. Prosím skontrolujte tento rozdiel, čím overíte, že táto úprava je tá, ktorú chcete, a následne uložte zmeny, čím ukončíte vrátenie.',
@@ -1405,7 +1418,7 @@ Tu je náhodne vytvorená hodnota, ktorú môžete použiť: $1',
 'timezoneregion-indian' => 'Indický oceán',
 'timezoneregion-pacific' => 'Tichý oceán',
 'allowemail' => 'Povoliť prijímanie e-mailov od iných používateľov',
-'prefs-searchoptions' => 'Voľby hľadania',
+'prefs-searchoptions' => 'Hľadanie',
 'prefs-namespaces' => 'Menné priestory',
 'defaultns' => 'Inak vyhľadávať v týchto menných priestoroch:',
 'default' => 'predvolený',
@@ -2495,7 +2508,8 @@ Ak bola od zmazania vytvorená nová stránka s rovnakým názvom, obnovené rev
 'undeletedrevisions' => '{{PLURAL:$1|jedna verzia bola obnovená|$1 verzie boli obnovené|$1 verzií bolo obnovených}}',
 'undeletedrevisions-files' => '{{PLURAL:$1|Jedna revízia|$1 revízie|$1 revízií}} a {{PLURAL:$2|jeden súbor bol obnovený|$2 súbory boli obnovené|$2 súborov bolo obnovených}}',
 'undeletedfiles' => '{{PLURAL:$1|Jeden súbor bol obnovený|$1 súbory boli obnovené|$1 súborov bolo obnovených}}',
-'cannotundelete' => 'Obnovenie sa nepodarilo; pravdepodobne niekto iný obnovil stránku skôr ako vy.',
+'cannotundelete' => 'Obnovenie sa nepodarilo:
+$1',
 'undeletedpage' => "'''$1 bol obnovený'''
 
 Zoznam posledných mazaní a obnovení nájdete v [[Special:Log/delete|Zázname mazaní]].",
@@ -2809,6 +2823,7 @@ Cieľová stránka „[[:$1]]“ už existuje. Chcete ho vymazať a vytvoriť ta
 'immobile-target-namespace-iw' => 'Interwiki odkaz nie je platným cieľom na presun stránky.',
 'immobile-source-page' => 'Túto stránku nemožno presunúť.',
 'immobile-target-page' => 'Nie je možné presunúť na cieľovú stránku z daným názvom.',
+'bad-target-model' => 'Požadovaný cieľ používa iný model obsahu. Nie je možné konvertovať z $1 na $2.',
 'imagenocrossnamespace' => 'Obrázok nemožno presunúť mimo menného priestoru obrázkov',
 'nonfile-cannot-move-to-file' => 'Nie je možné presunúť objekt, ktorý nie je súbor do menného priestoru Súbor',
 'imagetypemismatch' => 'Nová prípona súboru nezodpovedá jeho typu',
@@ -2887,6 +2902,7 @@ Všetky transwiki importy sa zaznamenávajú v [[Special:Log/import|Zázname imp
 'import-interwiki-templates' => 'Vložiť všetky šablóny',
 'import-interwiki-submit' => 'Importovať',
 'import-interwiki-namespace' => 'Cieľový menný priestor:',
+'import-interwiki-rootpage' => 'Koreňová stránka cieľa (nepovinné):',
 'import-upload-filename' => 'Názov súboru:',
 'import-comment' => 'komentár:',
 'importtext' => 'Prosím, exportujte súbor zo zdrojovej wiki použitím [[Special:Export|nástroja na export]].
@@ -2919,6 +2935,9 @@ Uložte ho na svoj disk a nahrajte sem.',
 'import-error-interwiki' => 'Stránka „$1“ nie je importovaná, pretože jej názov je vyhradený pre externé odkazy (interwiki).',
 'import-error-special' => 'Stránka „$1“ nie je importovaná, pretože patrí do špeciálneho menného priestoru, ktorý nepovoľuje stránky.',
 'import-error-invalid' => 'Stránka „$1“ nie je importovaná, pretože jej názov je neplatný.',
+'import-options-wrong' => '{{PLURAL:$2|Nesprávna voľba|Nesprávne voľby}}: <nowiki>$1</nowiki>',
+'import-rootpage-invalid' => 'Uvedená koreňová stránka nie je platný názov stránky.',
+'import-rootpage-nosubpage' => 'Menný priestor „$1“ koreňovej stránky nepodporuje podstránky.',
 
 # Import log
 'importlogpage' => 'Záznam importov',
@@ -3072,12 +3091,32 @@ Pravdepodobne to spôsobil odkaz na externú internetovú lokalitu, ktorá sa na
 'pageinfo-title' => 'Informácie o „$1“',
 'pageinfo-header-basic' => 'Základné údaje',
 'pageinfo-header-edits' => 'História úprav',
+'pageinfo-header-restrictions' => 'Ochrana stránky',
+'pageinfo-header-properties' => 'Vlastnosti stránky',
+'pageinfo-display-title' => 'Zobraziť názov',
+'pageinfo-default-sort' => 'Predvolený kľúč zoraďovania:',
+'pageinfo-length' => 'Dĺžka stránky (v bajtoch)',
 'pageinfo-article-id' => 'ID stránky',
+'pageinfo-robot-policy' => 'Stav vyhľadávača',
+'pageinfo-robot-index' => 'Indexovať stránku',
+'pageinfo-robot-noindex' => 'Neindexovať stránku',
 'pageinfo-views' => 'Počet zobrazení',
-'pageinfo-watchers' => 'Počet sledovateľov',
+'pageinfo-watchers' => 'Počet používateľov sledujúcich stránku',
+'pageinfo-redirects-name' => 'Presmerovania na túto stránku',
+'pageinfo-subpages-name' => 'Podstránky tejto stránky',
+'pageinfo-subpages-value' => '$1 ($2 {{PLURAL:$2|presmerovanie|presmerovania|presmerovaní}}; $3 {{PLURAL:$3|nie je presmerovanie|nie sú presmerovania}})',
+'pageinfo-firstuser' => 'Tvorca stránky',
+'pageinfo-firsttime' => 'Dátum vytvorenia stránky',
+'pageinfo-lastuser' => 'Naposledy upravil',
 'pageinfo-lasttime' => 'Dátum poslednej úpravy',
 'pageinfo-edits' => 'Celkový počet úprav',
 'pageinfo-authors' => 'Celkový počet autorov',
+'pageinfo-recent-edits' => 'Počet nedávnych úprav (za posledných $1)',
+'pageinfo-recent-authors' => 'Počet nedávnych jedinečných autorov',
+'pageinfo-magic-words' => 'Magické {{PLURAL:$1|slovo|slová}} ($1)',
+'pageinfo-hidden-categories' => '{{PLURAL:$1|Skrytá kategória|Skryté kategórie}} ($1)',
+'pageinfo-templates' => '{{PLURAL:$1|Vložená šablóna|Vložené šablóny}} ($1)',
+'pageinfo-toolboxlink' => 'Informácie o stránke',
 
 # Skin names
 'skinname-standard' => 'Klasický',
@@ -3132,6 +3171,7 @@ Jeho spustením môžete kompromitovať svoj systém.",
 'file-info-size-pages' => '$1 × $2 pixlov, veľkosť súboru: $3, typ MIME: $4, $5 {{PLURAL:$5|stránka|stránky|stránok}}',
 'file-nohires' => 'Nie je dostupné vyššie rozlíšenie.',
 'svg-long-desc' => 'SVG súbor, $1 × $2 pixelov, veľkosť súboru: $3',
+'svg-long-desc-animated' => 'Animovaný súbor SVG, nominálne $1 × $2 pixlov, veľkosť súboru: $3',
 'show-big-image' => 'Obrázok vo vyššom rozlíšení',
 'show-big-image-preview' => 'Veľkosť tohto náhľadu: $1.',
 'show-big-image-other' => 'Iné {{PLURAL:$2|rozlíšenie|rozlíšenia}}: $1 .',
@@ -3141,6 +3181,8 @@ Jeho spustením môžete kompromitovať svoj systém.",
 'file-info-png-looped' => 'opakované',
 'file-info-png-repeat' => 'prehrané $1-krát{{PLURAL:$1|||}}',
 'file-info-png-frames' => '$1 {{PLURAL:$1|rámec|rámce|rámcov}}',
+'file-no-thumb-animation' => "'''Pozn.: Z dôvodu technických obmedzení nebudú náhľady tohto súboru animované.'''",
+'file-no-thumb-animation-gif' => "'''Pozn.: Z dôvodu technických obmedzení nebudú náhľady súborov GIF vo vysokom rozlíšení (ako je tento súbor) animované.'''",
 
 # Special:NewFiles
 'newimages' => 'Galéria nových obrázkov',
@@ -3661,6 +3703,7 @@ Platnosť tohto potvrdzovacieho kódu vyprší $4.',
 # Scary transclusion
 'scarytranscludedisabled' => '[Transklúzia interwiki je vypnutá]',
 'scarytranscludefailed' => '[Nepodarilo sa priniesť šablónu pre $1]',
+'scarytranscludefailed-httpstatus' => '[Stiahnutie šablóny zlyhalo pre $1: HTTP $2]',
 'scarytranscludetoolong' => '[URL je príliš dlhé]',
 
 # Delete conflict
index ea0db4d..75b2bdc 100644 (file)
@@ -973,6 +973,12 @@ Izgleda, da je bila izbrisana.',
 'edit-already-exists' => 'Ni bilo mogoče ustvariti nove strani, ker že obstaja.',
 'defaultmessagetext' => 'Prednastavljeno besedilo',
 
+# Content models
+'content-model-wikitext' => 'wikibesedilo',
+'content-model-text' => 'golo besedilo',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
+
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''Opozorilo:''' Ta stran vsebuje preveč klicev funkcije razčlenjevalnika kode.
 
@@ -1905,7 +1911,7 @@ Morda želite urediti njeno opisno stran na tamkajšnji [$2 opisni strani datote
 'filerevert-legend' => 'Vrni datoteko',
 'filerevert-intro' => "Vračate datoteko '''[[Media:$1|$1]]''' na [$4 različico $3, $2].",
 'filerevert-comment' => 'Razlog:',
-'filerevert-defaultcomment' => 'Vrnjeno na različico $2, $1',
+'filerevert-defaultcomment' => 'Vrnjeno na različico $2, $1.',
 'filerevert-submit' => 'Vrni',
 'filerevert-success' => "Datoteka '''[[Media:$1|$1]]''' je bila vrnjena na [$4 različico $3, $2].",
 'filerevert-badversion' => 'Ne najdem preteklih lokalnih verzij datoteke s podanim časovnim žigom.',
@@ -2312,7 +2318,7 @@ Za zapise nedavnih brisanj glej $2.',
 'dellogpage' => 'Dnevnik brisanja',
 'dellogpagetext' => 'Spodaj je prikazan seznam nedavnih brisanj.',
 'deletionlog' => 'dnevnik brisanja',
-'reverted' => 'Obnovljeno na prejšnjo redakcijo',
+'reverted' => 'Vrnjeno na prejšnjo redakcijo.',
 'deletecomment' => 'Razlog:',
 'deleteotherreason' => 'Drugi/dodatni razlogi:',
 'deletereasonotherlist' => 'Drug razlog',
@@ -2447,8 +2453,8 @@ Morda imate napačno povezavo ali pa je bila redakcija obnovljena ali odstranjen
 'undeletedrevisions' => '{{PLURAL:$1|obnovljena $1 redakcija|obnovljeni $1 redakciji|obnovljene $1 redakcije|obnovljenih $1 redakcij}}',
 'undeletedrevisions-files' => '$1 {{PLURAL:$1|redakcija|redakciji|redakcije|redakcij}} in $2 {{PLURAL:$2|datoteka|datoteki|datoteke|datotek}} {{PLURAL:$1+$2|obnovljena|obnovljeni|obnovljene|obnovljenih}}',
 'undeletedfiles' => '{{PLURAL:$1|obnovljena je $1 datoteka|obnovljeni sta $1 datoteki|obnovljene so $1 datoteke|obnovljenih je $1 datotek}}',
-'cannotundelete' => 'Obnova ni uspela;
-morda je stran obnovil že kdo drug.',
+'cannotundelete' => 'Obnova je spodletela:
+$1',
 'undeletedpage' => "'''Obnovili ste stran $1.'''
 
 Nedavna brisanja in obnove so zapisani v [[Special:Log/delete|dnevniku brisanja]].",
@@ -2959,7 +2965,7 @@ Prosimo, poskusite znova.',
 'tooltip-watchlistedit-raw-submit' => 'Posodobi spisek nadzorov',
 'tooltip-recreate' => 'Ponovno ustvari stran, čeprav je bila izbrisana',
 'tooltip-upload' => 'Pričnite z nalaganjem',
-'tooltip-rollback' => 'Funkcija »Vrni« z enim klikom povrne vsa urejanja zadnjega urejevalca te strani',
+'tooltip-rollback' => 'Možnost »Vrni« z enim klikom povrne vsa urejanja zadnjega urejevalca te strani.',
 'tooltip-undo' => '"Razveljavi" vrne to urejanje in odpre predogled v oknu za urejanje.
 Omogoča vnos pojasnila v povzetku urejanja.',
 'tooltip-preferences-save' => 'Shrani nastavitve',
index 8a57dcd..757211e 100644 (file)
@@ -40,6 +40,7 @@
  * @author Rotsee
  * @author S.Örvarr.S
  * @author Sannab
+ * @author Sendelbach
  * @author Sertion
  * @author Skalman
  * @author Stefan2
@@ -1085,6 +1086,15 @@ Det verkar som att den har raderats.',
 'edit-already-exists' => 'Sidan kunde inte skapas.
 Den finns redan.',
 'defaultmessagetext' => 'Standardtext för meddelande',
+'content-failed-to-parse' => 'Det gick inte att parsa $2 innehåll för $1 modell: $3',
+'invalid-content-data' => 'Ogiltig innehållsdata',
+'content-not-allowed-here' => 'innehåll av "$1" är inte tillåtet på sidan [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'wikitext',
+'content-model-text' => 'oformaterad text',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => 'Varning: Denna sida innehåller för många anrop av resurskrävande parserfunktioner.
@@ -2536,7 +2546,8 @@ I sådana fall måste du se till att den senaste raderade versionen inte är ikr
 'undeletedrevisions' => '{{PLURAL:$1|en version återställd|$1 versioner återställda}}',
 'undeletedrevisions-files' => '$1 {{PLURAL:$1|version|versioner}} och $2 {{PLURAL:$2|fil|filer}} återställda',
 'undeletedfiles' => '{{PLURAL:$1|en fil återställd|$1 filer återställda}}',
-'cannotundelete' => 'Återställning misslyckades; kanske någon redan har återställt sidan.',
+'cannotundelete' => 'Återställning misslyckades:
+$1',
 'undeletedpage' => "'''$1 har återställts'''
 
 Se [[Special:Log/delete|raderingsloggen]] för en förteckning över de senaste raderingarna och återställningarna.",
@@ -2838,6 +2849,7 @@ Den titel du vill flytta sidan till, "[[:$1]]", finns redan. Vill du radera den
 'immobile-target-namespace-iw' => 'Interwikilänk är inte ett giltigt mål för sidflyttar.',
 'immobile-source-page' => 'Denna sida är inte flyttbar.',
 'immobile-target-page' => 'Kan inte flytta till det målnamnet.',
+'bad-target-model' => 'Den önskade destinationen använder en annan innehållsmodell. Kan inte konvertera från $1 till $2.',
 'imagenocrossnamespace' => 'Kan inte flytta filer till andra namnrymder än filnamnrymden',
 'nonfile-cannot-move-to-file' => 'Kan inte flytta icke-fil till filnamnrymden',
 'imagetypemismatch' => 'Den nya filändelsen motsvarar inte filtypen',
index 827dd6d..e582b50 100644 (file)
@@ -760,6 +760,7 @@ $1',
 'revdelete-success' => "'''Тағйири намоёнии нусха бо муваффақият анҷом шуд.'''",
 'logdelete-success' => "'''Тағйири намоёнии маврид бо муваффақият анҷом шуд.'''",
 'revdel-restore' => 'Тағйири падидорӣ',
+'revdel-restore-visible' => 'нусхаҳои намоён',
 'pagehist' => 'Таърихи саҳифа',
 'deletedhist' => 'Таърихи ҳазфшуда',
 'revdelete-edit-reasonlist' => 'Вироиш ҳазф далелҳо',
@@ -1177,7 +1178,7 @@ $1',
 'filehist-dimensions' => 'Андоза',
 'filehist-filesize' => 'Андозаи парванда',
 'filehist-comment' => 'Тавзеҳ',
-'imagelinks' => 'Ð\9fайвандҳои парванда',
+'imagelinks' => 'Ð\98Ñ\81Ñ\82иÑ\84одаи парванда',
 'linkstoimage' => '{{PLURAL:$1|Саҳифаҳои|$1 Саҳифаи}} зерин ба ин акс пайванданд:',
 'nolinkstoimage' => 'Ҳеҷ саҳифае ба ин акс пайванд надорад.',
 'sharedupload' => 'Ин парванда аз $1 мебошад ва шояд аз тарафи дигар лоиҳаҳо истифода шавад.',
index 44df07a..23fd023 100644 (file)
@@ -8,6 +8,7 @@
  * @file
  *
  * @author Alfredie
+ * @author Arlin
  * @author Kaganer
  * @author Reedy
  * @author Sahran
@@ -108,45 +109,45 @@ $messages = array(
 'thu' => 'پ',
 'fri' => 'ج',
 'sat' => 'ش',
-'january' => 'Ù\82Û\95ھرÙ\89تاÙ\86',
-'february' => 'ھۇت',
-'march' => 'Ù\86Û\95Û\8bرÛ\87ز',
-'april' => 'ئۇمۇت',
-'may_long' => 'باھار',
-'june' => 'سÛ\95Ù¾Û\95ر',
-'july' => 'چىللە',
-'august' => 'تÙ\88Ù\85Û\87ز',
-'september' => 'مىزان',
-'october' => 'ئوغۇز',
-'november' => 'ئوغلاق',
-'december' => 'كۆنەك',
-'january-gen' => 'Ù\82Û\95ھرÙ\89تاÙ\86',
-'february-gen' => 'ھۇت',
-'march-gen' => 'Ù\86Û\95Û\8bرÛ\87ز',
-'april-gen' => 'ئۇمۇت',
-'may-gen' => 'باھار',
-'june-gen' => 'سÛ\95Ù¾Û\95ر',
-'july-gen' => 'چىللە',
-'august-gen' => 'تÙ\88Ù\85Û\87ز',
-'september-gen' => 'مىزان',
-'october-gen' => 'ئوغۇز',
-'november-gen' => 'ئوغلاق',
-'december-gen' => 'كۆنەك',
-'jan' => 'Ù\82Û\95ھرÙ\89تاÙ\86',
-'feb' => 'ھۇت',
-'mar' => 'Ù\86Û\95Û\8bرÛ\87ز',
-'apr' => 'ئۇمۇت',
-'may' => 'باھار',
-'jun' => 'سÛ\95Ù¾Û\95ر',
-'jul' => 'چىللە',
-'aug' => 'تÙ\88Ù\85Û\87ز',
-'sep' => 'مىزان',
-'oct' => 'ئوغۇز',
-'nov' => 'ئوغلاق',
-'dec' => 'كۆنەك',
+'january' => 'Ù\8aاÙ\86Û\8bار',
+'february' => 'فېۋرال',
+'march' => 'Ù\85ارت',
+'april' => 'ئاپرېل',
+'may_long' => 'ماي',
+'june' => 'ئÙ\89Ù\8aÛ\87Ù\86',
+'july' => 'ئىيۇل',
+'august' => 'ئاÛ\8bغÛ\87ست',
+'september' => 'سىنتەبىر',
+'october' => 'ئۆكتەبىر',
+'november' => 'نويابىر',
+'december' => 'دېكابىر',
+'january-gen' => 'Ù\8aاÙ\86Û\8bار',
+'february-gen' => 'فېۋرال',
+'march-gen' => 'Ù\85ارت',
+'april-gen' => 'ئاپرېل',
+'may-gen' => 'ماي',
+'june-gen' => 'ئÙ\89Ù\8aÛ\87Ù\86',
+'july-gen' => 'ئىيۇل',
+'august-gen' => 'ئاÛ\8bغÛ\87ست',
+'september-gen' => 'سىنتەبىر',
+'october-gen' => 'ئۆكتەبىر',
+'november-gen' => 'نويابىر',
+'december-gen' => 'دېكابىر',
+'jan' => 'Ù\8aاÙ\86Û\8bار',
+'feb' => 'فېۋرال',
+'mar' => 'Ù\85ارت',
+'apr' => 'ئاپرېل',
+'may' => 'ماي',
+'jun' => 'ئÙ\89Ù\8aÛ\87Ù\86',
+'jul' => 'ئىيۇل',
+'aug' => 'ئاÛ\8bغÛ\87ست',
+'sep' => 'سىنتەبىر',
+'oct' => 'ئۆكتەبىر',
+'nov' => 'نويابىر',
+'dec' => 'دېكابىر',
 
 # Categories related messages
-'pagecategories' => '{{PLURAL:$1|تۈر|تۈر}}',
+'pagecategories' => '{{PLURAL:$1|تۈر|تۈرلەر}}',
 'category_header' => '"$1" تۈردىكى بەتلەر',
 'subcategories' => 'تارماق تۈر',
 'category-media-header' => '"$1" تۈردىكى ۋاسىتە',
@@ -168,7 +169,7 @@ $messages = array(
 'linkprefix' => '/^(.*?)([a-zA-Z\\x80-\\xff]+)$/sD',
 
 'about' => 'ھەققىدە',
-'article' => 'Ù\85Û\95زÙ\85Û\87Ù\86 Ø¨Û\90تÙ\89',
+'article' => 'Ù\85Û\87Ù\86دÛ\95رÙ\89جÛ\95',
 'newwindow' => '(يېڭى كۆزنەكتە ئاچ)',
 'cancel' => 'ۋاز كەچ',
 'moredotdotdot' => 'تەپسىلىي…',
@@ -2246,6 +2247,7 @@ $2 نىڭ ئاخىرقى تۈزىتىلگەن نەشرىگە ئۆزگەرتىل
 
  [[Special:Log/delete|ئۆچۈرۈش خاتىرىسى]]دىن پايدىلىنىپ ئۆچۈر ۋە ئەسلىگە كەلتۈر خاتىرىسىنى كۆرۈڭ.",
 'undelete-header' => 'يېقىنقى خاتىرىنى سۈرۈشتۈرمەكچى بولسىڭىز [[Special:Log/delete|ئۆچۈرۈش خاتىرىسى]]دىن پايدىلىنىڭ.',
+'undelete-search-title' => 'ئۆچۈرۈئتلگەن بەتنى ئزدەش',
 'undelete-search-box' => 'ئۆچۈرۈلگەن بەتنى ئىزدە',
 'undelete-search-prefix' => 'باشلانغان بەتنى كۆرسەت:',
 'undelete-search-submit' => 'ئىزدەش',
index c54ceea..86fbd08 100644 (file)
@@ -1037,7 +1037,8 @@ Also see [[Special:WantedCategories|wanted categories]].',
 'listgrouprights-members' => '(a’zolar ro‘yxati)',
 
 # E-mail user
-'emailuser' => 'Bu foydalanuvchiga e-maktub',
+'emailuser' => 'Foydalanuvchiga maktub',
+'defemailsubject' => '{{SITENAME}} — $1 tomonidan maktub',
 'noemailtitle' => 'Elektron pochta manzili mavjud emas',
 'noemailtext' => "Bu foydalanuvchi e-mail manzil ko'rsatgani yo'q.",
 'emailtarget' => 'Oluvchi ishtirokchining ismini kiriting',
@@ -1049,7 +1050,9 @@ Also see [[Special:WantedCategories|wanted categories]].',
 'emailsubject' => 'Sarlavha:',
 'emailmessage' => 'Xabar',
 'emailsend' => 'Joʻnatish',
+'emailccsubject' => '$1ga maktubingizning nusxasi: $2',
 'emailsent' => "Xat jo'natildi",
+'emailsenttext' => "Sizning elektron maktubingiz jo'natildi.",
 
 # User Messenger
 'usermessage-summary' => 'Tizimli xabar qoldirish.',
@@ -1496,6 +1499,7 @@ Yaqinda sodir etilgan yoʻqotishlar uchun $2ni koʻring.',
 
 # New logging system
 'logentry-move-move' => '$1 $3 sahifasini $4ga koʻchirdi',
+'logentry-patrol-patrol-auto' => '$1 $3 sahifasining $4 versiyasini avtomatik patrulladi',
 'logentry-newusers-newusers' => '$1 ishtirokchisining hisob yozuvi yaratildi',
 'logentry-newusers-create' => '$1 ishtirokchisining hisob yozuvi yaratildi',
 
index cc7e5a6..1e92b44 100644 (file)
@@ -341,7 +341,7 @@ $messages = array(
 'vector-action-protect' => 'שיצן',
 'vector-action-undelete' => 'מבטל זיין אויסמעקן',
 'vector-action-unprotect' => 'ענדערונג באַשיצונג',
-'vector-simplesearch-preference' => '×\90ַק×\98×\99×\95×\95×\99ר×\9f ×¤Ö¿×\90ַר×\91ר×\99×\99×\98ער×\98×¢ ×\96×\95×\9a ×¤Ö¿×\90רש×\9c×\90Ö¸×\92×\9f (נאר וועקטאר)',
+'vector-simplesearch-preference' => '×\93ער×\9e×¢×\92×\9c×¢×\9b×\9f ×¤Ö¿×\90ַרפש×\95×\98ער×\98×\9f ×\96×\95×\9a ×¤×\90ַס (נאר וועקטאר)',
 'vector-view-create' => 'שאַפֿן',
 'vector-view-edit' => 'רעדאַקטירן',
 'vector-view-history' => 'ווײַזן היסטאָריע',
@@ -969,6 +969,7 @@ $2
 'edit-already-exists' => 'נישט מעגליך צו שאַפֿן נייע בלאט.
 ער עקזיסטירט שוין.',
 'defaultmessagetext' => 'גרונטלעכער מעלדונג טעקסט',
+'invalid-content-data' => 'אומגילטיקע אינהאלט דאטן',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => "'''אזהרה:''' דער בלאט אנטהאלט צופיל טייערע פארזירער רופן.
@@ -1624,6 +1625,9 @@ $1",
 * נאמען פון דער טעקע וואס ווערט ארויפגעלאָדן: <strong>[[:$1]]</strong>
 * נאמען פון דער פֿאראנענער טעקע: <strong>[[:$2]]</strong>
 זײַט אזוי גוט און קלויבט אן אנדער נאמען.',
+'file-thumbnail-no' => "דער טעקע־נאמען הייבט אן מיט <strong>$1</strong>.
+זי זעט אויס ווי א פארקלענערט בילד ''(מיניאטור)''.
+טאמער האט איר דאס בילד אין פולער רעזאלוציע טוט עס ארויפלאדן, אנדערשט זייט אזוי גוט און ענדערט דעם טעקע־נאמען.",
 'fileexists-forbidden' => 'א טעקע מיט דעם נאָמען עקזיסטירט שוין, און מען קען זי נישט אַריבערשרײַבן. 
 אויב איר ווילט דאך אַרויפֿלאָדן אײַער טעקע, ביטע גיין צוריק און ניצן אַן אַנדער נאָמען. 
 [[File:$1|thumb|center|$1]]',
@@ -2314,7 +2318,7 @@ $UNWATCHURL
 'undeletedrevisions' => '{{PLURAL:$1|1 רעוויזיע|$1 רעוויזיעס}} צוריקגעשטעלט',
 'undeletedrevisions-files' => '{{PLURAL:$1|1 רעוויזיע|$1 רעוויזיעס}} און  {{PLURAL:$2|1 טעקע|$2 טעקעס}} צוריקגעשטעלט',
 'undeletedfiles' => '{{PLURAL:$1|1 טעקע|$1 טעקעס}} צוריקגעשטעלט',
-'cannotundelete' => 'צוריקשטעלונג איז דורכגעפאלן; עס איז מעגליך אז אן אנדערע האט דאס שוין צוריקגעשטעלט.',
+'cannotundelete' => 'צוריקשטעלונג איז דורכגעפאלן: $1',
 'undeletedpage' => "'''דער בלאט $1 איז געווארן צוריקגעשטעלט.'''
 
 זעט דעם [[Special:Log/delete| אויסמעקן לאג]] פֿאר א ליסטע פון די לעצטע אויסגעמעקטע און צוריקגעשטעלטע בלעטער.",
@@ -2323,6 +2327,7 @@ $UNWATCHURL
 'undelete-search-box' => 'זוכן אויסגעמעקטע בלעטער',
 'undelete-search-prefix' => 'ווײַז בלעטער וואס הייבן אן מיט:',
 'undelete-search-submit' => 'זוכן',
+'undelete-no-results' => 'נישט געטראפן קיין צוגעפאסטע בלעטער אין אויסמעקונג ארכיוו.',
 'undelete-error' => 'גרייז ביים צוריקשטעלן בלאט',
 'undelete-error-short' => 'טעות ביים צוריקשטעלן טעקע: $1',
 'undelete-error-long' => 'גרײַזן געטראפֿן בײַם ווידערשטעלן די טעקע:
@@ -2721,6 +2726,7 @@ $1',
 'import-error-interwiki' => 'דעם בלאט "$1"  קען מען נישט אימפארטירן ווייל זיין נאמען איז רעזערווירט פאר דרויסנדיקער פארבינדונג (אינטערוויקי).',
 'import-error-special' => 'דעם בלאט "$1" קען מען נישט אימפארטירן ווייל ער געהערט צו א באזונדערן נאמענטייל וואס אנטהאלט נישט קיין בלעטער.',
 'import-error-invalid' => 'דעם בלאט "$1" קען מען נישט אימפארטירן ווייל זיין נאמען איז אומגילטיק.',
+'import-rootpage-nosubpage' => 'נאמענטייל "$1" פונעם שטאמבלאט ערלויבט נישט קיין אונטערבלעטער.',
 
 # Import log
 'importlogpage' => 'אימפארט לאגבוך',
@@ -3083,6 +3089,7 @@ $1',
 'exif-keywords' => 'שליסלווערטער',
 'exif-worldregioncreated' => "וועלטראיאן וואו מ'האט גענומען דאס בילד",
 'exif-countrycreated' => "לאנד וואו מ'האט געמאכט דאס בילד",
+'exif-countrycodecreated' => "קאד פארן לאנד וואו מ'האט געמאכט דאס בילד",
 'exif-provinceorstatecreated' => "פראווינץ אדער שטאַט וואו מ'האט גענומען דאס בילד",
 'exif-citycreated' => "שטאָט וואו מ'האט געמאכט דאס בילד",
 'exif-worldregiondest' => 'וועלטראיאן געוויזן',
index 1be7036..58252ee 100644 (file)
@@ -965,6 +965,14 @@ $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-text' => '純文字',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
 
 # Parser/template warnings
 'expensive-parserfunction-warning' => '警告: 這個頁面有太多耗費的語法功能呼叫。
@@ -2380,7 +2388,7 @@ $UNWATCHURL
 'undeletedrevisions' => '$1個修訂版本已經恢復',
 'undeletedrevisions-files' => '$1 個版本和 $2 個檔案被恢復',
 'undeletedfiles' => '$1 個檔案被恢復',
-'cannotundelete' => 'æ\81¢å¾©å¤±æ\95\97ï¼\9bå\8f¯è\83½ä¹\8bå\89\8då·²ç¶\93被å\85¶ä»\96人æ\81¢å¾©ã\80\82',
+'cannotundelete' => 'æ\81¢å¾©å¤±æ\95\97ï¼\9a$1',
 'undeletedpage' => "'''$1已經被恢復''' 請參考[[Special:Log/delete|刪除日誌]]來查詢刪除及恢復記錄。",
 'undelete-header' => '如要查詢最近的記錄請參閱[[Special:Log/delete|刪除日誌]]。',
 'undelete-search-title' => '搜索已刪除頁面',
@@ -2683,6 +2691,7 @@ $1被封禁的理由是“$2”',
 'immobile-target-namespace-iw' => '垮維基連結在移動頁面中是無效的目標。',
 'immobile-source-page' => '這個頁面不能移動。',
 'immobile-target-page' => '無法移動至目標標題中。',
+'bad-target-model' => '所需的目的地使用不同的內容模式。不可以從$1轉換到 $2 。',
 'imagenocrossnamespace' => '不可以移動檔案到非檔案名字空間',
 'nonfile-cannot-move-to-file' => '不可以移動非檔案到檔案名字空間',
 'imagetypemismatch' => '該新副檔名不匹配它的類型',
diff --git a/maintenance/archives/patch-sites.sql b/maintenance/archives/patch-sites.sql
new file mode 100644 (file)
index 0000000..8839274
--- /dev/null
@@ -0,0 +1,71 @@
+-- Patch to add the sites and site_identifiers tables.
+-- Licence: GNU GPL v2+
+-- Author: Jeroen De Dauw < jeroendedauw@gmail.com >
+
+
+-- Holds all the sites known to the wiki.
+CREATE TABLE IF NOT EXISTS /*_*/sites (
+-- Numeric id of the site
+  site_id                    INT UNSIGNED        NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+  -- Global identifier for the site, ie 'enwiktionary'
+  site_global_key            varbinary(32)       NOT NULL,
+
+  -- Type of the site, ie 'mediawiki'
+  site_type                  varbinary(32)       NOT NULL,
+
+  -- Group of the site, ie 'wikipedia'
+  site_group                 varbinary(32)       NOT NULL,
+
+  -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo'
+  site_source                varbinary(32)       NOT NULL,
+
+  -- Language code of the sites primary language.
+  site_language              varbinary(32)       NOT NULL,
+
+  -- Protocol of the site, ie 'http://', 'irc://', '//'
+  -- This field is an index for lookups and is build from type specific data in site_data.
+  site_protocol              varbinary(32)       NOT NULL,
+
+  -- Domain of the site in reverse order, ie 'org.mediawiki.www.'
+  -- This field is an index for lookups and is build from type specific data in site_data.
+  site_domain                VARCHAR(255)        NOT NULL,
+
+  -- Type dependent site data.
+  site_data                  BLOB                NOT NULL,
+
+  -- If site.tld/path/key:pageTitle should forward users to  the page on
+  -- the actual site, where "key" is the local identifier.
+  site_forward              bool                NOT NULL,
+
+  -- Type dependent site config.
+  -- For instance if template transclusion should be allowed if it's a MediaWiki.
+  site_config               BLOB                NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/sites_global_key ON /*_*/sites (site_global_key);
+CREATE INDEX /*i*/sites_type ON /*_*/sites (site_type);
+CREATE INDEX /*i*/sites_group ON /*_*/sites (site_group);
+CREATE INDEX /*i*/sites_source ON /*_*/sites (site_source);
+CREATE INDEX /*i*/sites_language ON /*_*/sites (site_language);
+CREATE INDEX /*i*/sites_protocol ON /*_*/sites (site_protocol);
+CREATE INDEX /*i*/sites_domain ON /*_*/sites (site_domain);
+CREATE INDEX /*i*/sites_forward ON /*_*/sites (site_forward);
+
+
+
+-- Links local site identifiers to their corresponding site.
+CREATE TABLE IF NOT EXISTS /*_*/site_identifiers (
+  -- Key on site.site_id
+  si_site                    INT UNSIGNED        NOT NULL,
+
+  -- local key type, ie 'interwiki' or 'langlink'
+  si_type                    varbinary(32)       NOT NULL,
+
+  -- local key value, ie 'en' or 'wiktionary'
+  si_key                     varbinary(32)       NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/site_ids_type ON /*_*/site_identifiers (si_type, si_key);
+CREATE INDEX /*i*/site_ids_site ON /*_*/site_identifiers (si_site);
+CREATE INDEX /*i*/site_ids_key ON /*_*/site_identifiers (si_key);
\ No newline at end of file
index e273c54..9ad4df4 100644 (file)
@@ -64,6 +64,7 @@ class FindHooks extends Maintenance {
                        $IP . '/includes/actions/',
                        $IP . '/includes/api/',
                        $IP . '/includes/cache/',
+                       $IP . '/includes/content/',
                        $IP . '/includes/context/',
                        $IP . '/includes/db/',
                        $IP . '/includes/diff/',
@@ -170,7 +171,7 @@ class FindHooks extends Maintenance {
        private function getHooksFromFile( $file ) {
                $content = file_get_contents( $file );
                $m = array();
-               preg_match_all( '/(?:wfRunHooks|Hooks\:\:run)\(\s*([\'"])(.*?)\1/', $content, $m );
+               preg_match_all( '/(?:wfRunHooks|Hooks\:\:run|ContentHandler\:\:runLegacyHooks)\(\s*([\'"])(.*?)\1/', $content, $m );
                return $m[2];
        }
 
diff --git a/maintenance/oracle/archives/patch-archive-ar_content_format.sql b/maintenance/oracle/archives/patch-archive-ar_content_format.sql
new file mode 100644 (file)
index 0000000..0c0c0d9
--- /dev/null
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.archive ADD ar_content_format VARCHAR2(64);
diff --git a/maintenance/oracle/archives/patch-archive-ar_content_model.sql b/maintenance/oracle/archives/patch-archive-ar_content_model.sql
new file mode 100644 (file)
index 0000000..d18fc9e
--- /dev/null
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.archive ADD ar_content_model VARCHAR2(32);
diff --git a/maintenance/oracle/archives/patch-cat_hidden.sql b/maintenance/oracle/archives/patch-cat_hidden.sql
new file mode 100644 (file)
index 0000000..d1649c7
--- /dev/null
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.category DROP COLUMN cat_hidden;
+
diff --git a/maintenance/oracle/archives/patch-page-page_content_model.sql b/maintenance/oracle/archives/patch-page-page_content_model.sql
new file mode 100644 (file)
index 0000000..e5839d9
--- /dev/null
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.page ADD page_content_model VARCHAR2(32);
diff --git a/maintenance/oracle/archives/patch-rc_moved.sql b/maintenance/oracle/archives/patch-rc_moved.sql
new file mode 100644 (file)
index 0000000..2a71315
--- /dev/null
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.recentchanges DROP ( rc_moved_to_ns, rc_moved_to_title );
+
diff --git a/maintenance/oracle/archives/patch-revision-rev_content_format.sql b/maintenance/oracle/archives/patch-revision-rev_content_format.sql
new file mode 100644 (file)
index 0000000..ebde71c
--- /dev/null
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.revision ADD rev_content_format VARCHAR2(64);
diff --git a/maintenance/oracle/archives/patch-revision-rev_content_model.sql b/maintenance/oracle/archives/patch-revision-rev_content_model.sql
new file mode 100644 (file)
index 0000000..dd22642
--- /dev/null
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.revision ADD rev_content_model VARCHAR2(32);
diff --git a/maintenance/oracle/archives/patch-ss_admins.sql b/maintenance/oracle/archives/patch-ss_admins.sql
new file mode 100644 (file)
index 0000000..c2e9242
--- /dev/null
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.site_stats DROP COLUMN ss_admins;
+
index 3f9b376..d0712e3 100644 (file)
@@ -73,7 +73,8 @@ CREATE TABLE &mw_prefix.page (
   page_random        NUMBER(15,14) NOT NULL,
   page_touched       TIMESTAMP(6) WITH TIME ZONE,
   page_latest        NUMBER        DEFAULT 0 NOT NULL, -- FK?
-  page_len           NUMBER        DEFAULT 0 NOT NULL
+  page_len           NUMBER        DEFAULT 0 NOT NULL,
+  page_content_model VARCHAR2(32)
 );
 ALTER TABLE &mw_prefix.page ADD CONSTRAINT &mw_prefix.page_pk PRIMARY KEY (page_id);
 CREATE UNIQUE INDEX &mw_prefix.page_u01 ON &mw_prefix.page (page_namespace,page_title);
@@ -83,7 +84,7 @@ CREATE INDEX &mw_prefix.page_i03 ON &mw_prefix.page (page_is_redirect, page_name
 
 -- Create a dummy page to satisfy fk contraints especially with revisions
 INSERT INTO &mw_prefix.page
-  VALUES (0, 0, ' ', NULL, 0, 0, 0, 0, current_timestamp, 0, 0);
+  VALUES (0, 0, ' ', NULL, 0, 0, 0, 0, current_timestamp, 0, 0, NULL);
 
 /*$mw$*/
 CREATE TRIGGER &mw_prefix.page_set_random BEFORE INSERT ON &mw_prefix.page
@@ -106,7 +107,9 @@ CREATE TABLE &mw_prefix.revision (
   rev_deleted     CHAR(1)         DEFAULT '0' NOT NULL,
   rev_len         NUMBER          NULL,
   rev_parent_id   NUMBER          DEFAULT NULL,
-  rev_sha1               VARCHAR2(32)    NULL
+  rev_sha1               VARCHAR2(32)    NULL,
+  rev_content_model VARCHAR2(32),
+  rev_content_format VARCHAR2(64)
 );
 ALTER TABLE &mw_prefix.revision ADD CONSTRAINT &mw_prefix.revision_pk PRIMARY KEY (rev_id);
 ALTER TABLE &mw_prefix.revision ADD CONSTRAINT &mw_prefix.revision_fk1 FOREIGN KEY (rev_page) REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
@@ -142,7 +145,9 @@ CREATE TABLE &mw_prefix.archive (
   ar_len         NUMBER,
   ar_page_id     NUMBER,
   ar_parent_id   NUMBER,
-  ar_sha1                VARCHAR2(32)    NULL
+  ar_sha1                VARCHAR2(32),
+  ar_content_model VARCHAR2(32),
+  ar_content_format VARCHAR2(64)
 );
 ALTER TABLE &mw_prefix.archive ADD CONSTRAINT &mw_prefix.archive_fk1 FOREIGN KEY (ar_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED;
 CREATE INDEX &mw_prefix.archive_i01 ON &mw_prefix.archive (ar_namespace,ar_title,ar_timestamp);
@@ -197,8 +202,7 @@ CREATE TABLE &mw_prefix.category (
   cat_title VARCHAR2(255) NOT NULL,
   cat_pages NUMBER DEFAULT 0 NOT NULL,
   cat_subcats NUMBER DEFAULT 0 NOT NULL,
-  cat_files NUMBER DEFAULT 0 NOT NULL,
-  cat_hidden NUMBER DEFAULT 0 NOT NULL
+  cat_files NUMBER DEFAULT 0 NOT NULL
 );
 ALTER TABLE &mw_prefix.category ADD CONSTRAINT &mw_prefix.category_pk PRIMARY KEY (cat_id);
 CREATE UNIQUE INDEX &mw_prefix.category_u01 ON &mw_prefix.category (cat_title);
@@ -246,7 +250,6 @@ CREATE TABLE &mw_prefix.site_stats (
   ss_total_pages    NUMBER            DEFAULT -1,
   ss_users          NUMBER            DEFAULT -1,
   ss_active_users   NUMBER            DEFAULT -1,
-  ss_admins         NUMBER            DEFAULT -1,
   ss_images         NUMBER            DEFAULT 0
 );
 CREATE UNIQUE INDEX &mw_prefix.site_stats_u01 ON &mw_prefix.site_stats (ss_row_id);
index 1e3eecb..8c91f29 100644 (file)
@@ -79,7 +79,8 @@ CREATE TABLE page (
   page_random        NUMERIC(15,14) NOT NULL  DEFAULT RANDOM(),
   page_touched       TIMESTAMPTZ,
   page_latest        INTEGER        NOT NULL, -- FK?
-  page_len           INTEGER        NOT NULL
+  page_len           INTEGER        NOT NULL,
+  page_content_model TEXT
 );
 CREATE UNIQUE INDEX page_unique_name ON page (page_namespace, page_title);
 CREATE INDEX page_main_title         ON page (page_title text_pattern_ops) WHERE page_namespace = 0;
@@ -104,18 +105,20 @@ CREATE TRIGGER page_deleted AFTER DELETE ON page
 
 CREATE SEQUENCE revision_rev_id_seq;
 CREATE TABLE revision (
-  rev_id          INTEGER      NOT NULL  UNIQUE DEFAULT nextval('revision_rev_id_seq'),
-  rev_page        INTEGER          NULL  REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
-  rev_text_id     INTEGER          NULL, -- FK
-  rev_comment     TEXT,
-  rev_user        INTEGER      NOT NULL  REFERENCES mwuser(user_id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED,
-  rev_user_text   TEXT         NOT NULL,
-  rev_timestamp   TIMESTAMPTZ  NOT NULL,
-  rev_minor_edit  SMALLINT     NOT NULL  DEFAULT 0,
-  rev_deleted     SMALLINT     NOT NULL  DEFAULT 0,
-  rev_len         INTEGER          NULL,
-  rev_parent_id   INTEGER          NULL,
-  rev_sha1        TEXT         NOT NULL DEFAULT ''
+  rev_id             INTEGER      NOT NULL  UNIQUE DEFAULT nextval('revision_rev_id_seq'),
+  rev_page           INTEGER          NULL  REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+  rev_text_id        INTEGER          NULL, -- FK
+  rev_comment        TEXT,
+  rev_user           INTEGER      NOT NULL  REFERENCES mwuser(user_id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED,
+  rev_user_text      TEXT         NOT NULL,
+  rev_timestamp      TIMESTAMPTZ  NOT NULL,
+  rev_minor_edit     SMALLINT     NOT NULL  DEFAULT 0,
+  rev_deleted        SMALLINT     NOT NULL  DEFAULT 0,
+  rev_len            INTEGER          NULL,
+  rev_parent_id      INTEGER          NULL,
+  rev_sha1           TEXT         NOT NULL DEFAULT '',
+  rev_content_model  TEXT,
+  rev_content_format TEXT
 );
 CREATE UNIQUE INDEX revision_unique ON revision (rev_page, rev_id);
 CREATE INDEX rev_text_id_idx        ON revision (rev_text_id);
@@ -153,22 +156,24 @@ ALTER TABLE page_props ADD CONSTRAINT page_props_pk PRIMARY KEY (pp_page,pp_prop
 CREATE INDEX page_props_propname ON page_props (pp_propname);
 
 CREATE TABLE archive (
-  ar_namespace   SMALLINT     NOT NULL,
-  ar_title       TEXT         NOT NULL,
-  ar_text        TEXT, -- technically should be bytea, but not used anymore
-  ar_page_id     INTEGER          NULL,
-  ar_parent_id   INTEGER          NULL,
-  ar_sha1        TEXT         NOT NULL DEFAULT '',
-  ar_comment     TEXT,
-  ar_user        INTEGER          NULL  REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
-  ar_user_text   TEXT         NOT NULL,
-  ar_timestamp   TIMESTAMPTZ  NOT NULL,
-  ar_minor_edit  SMALLINT     NOT NULL  DEFAULT 0,
-  ar_flags       TEXT,
-  ar_rev_id      INTEGER,
-  ar_text_id     INTEGER,
-  ar_deleted     SMALLINT     NOT NULL  DEFAULT 0,
-  ar_len         INTEGER          NULL
+  ar_namespace      SMALLINT     NOT NULL,
+  ar_title          TEXT         NOT NULL,
+  ar_text           TEXT, -- technically should be bytea, but not used anymore
+  ar_page_id        INTEGER          NULL,
+  ar_parent_id      INTEGER          NULL,
+  ar_sha1           TEXT         NOT NULL DEFAULT '',
+  ar_comment        TEXT,
+  ar_user           INTEGER          NULL  REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
+  ar_user_text      TEXT         NOT NULL,
+  ar_timestamp      TIMESTAMPTZ  NOT NULL,
+  ar_minor_edit     SMALLINT     NOT NULL  DEFAULT 0,
+  ar_flags          TEXT,
+  ar_rev_id         INTEGER,
+  ar_text_id        INTEGER,
+  ar_deleted        SMALLINT     NOT NULL  DEFAULT 0,
+  ar_len            INTEGER          NULL,
+  ar_content_model  TEXT,
+  ar_content_format TEXT
 );
 CREATE INDEX archive_name_title_timestamp ON archive (ar_namespace,ar_title,ar_timestamp);
 CREATE INDEX archive_user_text            ON archive (ar_user_text);
diff --git a/maintenance/sqlite/archives/patch-sites.sql b/maintenance/sqlite/archives/patch-sites.sql
new file mode 100644 (file)
index 0000000..8839274
--- /dev/null
@@ -0,0 +1,71 @@
+-- Patch to add the sites and site_identifiers tables.
+-- Licence: GNU GPL v2+
+-- Author: Jeroen De Dauw < jeroendedauw@gmail.com >
+
+
+-- Holds all the sites known to the wiki.
+CREATE TABLE IF NOT EXISTS /*_*/sites (
+-- Numeric id of the site
+  site_id                    INT UNSIGNED        NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+  -- Global identifier for the site, ie 'enwiktionary'
+  site_global_key            varbinary(32)       NOT NULL,
+
+  -- Type of the site, ie 'mediawiki'
+  site_type                  varbinary(32)       NOT NULL,
+
+  -- Group of the site, ie 'wikipedia'
+  site_group                 varbinary(32)       NOT NULL,
+
+  -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo'
+  site_source                varbinary(32)       NOT NULL,
+
+  -- Language code of the sites primary language.
+  site_language              varbinary(32)       NOT NULL,
+
+  -- Protocol of the site, ie 'http://', 'irc://', '//'
+  -- This field is an index for lookups and is build from type specific data in site_data.
+  site_protocol              varbinary(32)       NOT NULL,
+
+  -- Domain of the site in reverse order, ie 'org.mediawiki.www.'
+  -- This field is an index for lookups and is build from type specific data in site_data.
+  site_domain                VARCHAR(255)        NOT NULL,
+
+  -- Type dependent site data.
+  site_data                  BLOB                NOT NULL,
+
+  -- If site.tld/path/key:pageTitle should forward users to  the page on
+  -- the actual site, where "key" is the local identifier.
+  site_forward              bool                NOT NULL,
+
+  -- Type dependent site config.
+  -- For instance if template transclusion should be allowed if it's a MediaWiki.
+  site_config               BLOB                NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/sites_global_key ON /*_*/sites (site_global_key);
+CREATE INDEX /*i*/sites_type ON /*_*/sites (site_type);
+CREATE INDEX /*i*/sites_group ON /*_*/sites (site_group);
+CREATE INDEX /*i*/sites_source ON /*_*/sites (site_source);
+CREATE INDEX /*i*/sites_language ON /*_*/sites (site_language);
+CREATE INDEX /*i*/sites_protocol ON /*_*/sites (site_protocol);
+CREATE INDEX /*i*/sites_domain ON /*_*/sites (site_domain);
+CREATE INDEX /*i*/sites_forward ON /*_*/sites (site_forward);
+
+
+
+-- Links local site identifiers to their corresponding site.
+CREATE TABLE IF NOT EXISTS /*_*/site_identifiers (
+  -- Key on site.site_id
+  si_site                    INT UNSIGNED        NOT NULL,
+
+  -- local key type, ie 'interwiki' or 'langlink'
+  si_type                    varbinary(32)       NOT NULL,
+
+  -- local key value, ie 'en' or 'wiktionary'
+  si_key                     varbinary(32)       NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/site_ids_type ON /*_*/site_identifiers (si_type, si_key);
+CREATE INDEX /*i*/site_ids_site ON /*_*/site_identifiers (si_site);
+CREATE INDEX /*i*/site_ids_key ON /*_*/site_identifiers (si_key);
\ No newline at end of file
index 4a707fd..51115f1 100644 (file)
@@ -1498,4 +1498,69 @@ CREATE TABLE /*_*/config (
 -- Should cover *most* configuration - strings, ints, bools, etc.
 CREATE INDEX /*i*/cf_name_value ON /*_*/config (cf_name,cf_value(255));
 
+-- Holds all the sites known to the wiki.
+CREATE TABLE /*_*/sites (
+-- Numeric id of the site
+  site_id                    INT UNSIGNED        NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+  -- Global identifier for the site, ie 'enwiktionary'
+  site_global_key            varbinary(32)       NOT NULL,
+
+  -- Type of the site, ie 'mediawiki'
+  site_type                  varbinary(32)       NOT NULL,
+
+  -- Group of the site, ie 'wikipedia'
+  site_group                 varbinary(32)       NOT NULL,
+
+  -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo'
+  site_source                varbinary(32)       NOT NULL,
+
+  -- Language code of the sites primary language.
+  site_language              varbinary(32)       NOT NULL,
+
+  -- Protocol of the site, ie 'http://', 'irc://', '//'
+  -- This field is an index for lookups and is build from type specific data in site_data.
+  site_protocol              varbinary(32)       NOT NULL,
+
+  -- Domain of the site in reverse order, ie 'org.mediawiki.www.'
+  -- This field is an index for lookups and is build from type specific data in site_data.
+  site_domain                VARCHAR(255)        NOT NULL,
+
+  -- Type dependent site data.
+  site_data                  BLOB                NOT NULL,
+
+  -- If site.tld/path/key:pageTitle should forward users to  the page on
+  -- the actual site, where "key" is the local identifier.
+  site_forward              bool                NOT NULL,
+
+  -- Type dependent site config.
+  -- For instance if template transclusion should be allowed if it's a MediaWiki.
+  site_config               BLOB                NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/sites_global_key ON /*_*/sites (site_global_key);
+CREATE INDEX /*i*/sites_type ON /*_*/sites (site_type);
+CREATE INDEX /*i*/sites_group ON /*_*/sites (site_group);
+CREATE INDEX /*i*/sites_source ON /*_*/sites (site_source);
+CREATE INDEX /*i*/sites_language ON /*_*/sites (site_language);
+CREATE INDEX /*i*/sites_protocol ON /*_*/sites (site_protocol);
+CREATE INDEX /*i*/sites_domain ON /*_*/sites (site_domain);
+CREATE INDEX /*i*/sites_forward ON /*_*/sites (site_forward);
+
+-- Links local site identifiers to their corresponding site.
+CREATE TABLE /*_*/site_identifiers (
+  -- Key on site.site_id
+  si_site                    INT UNSIGNED        NOT NULL,
+
+  -- local key type, ie 'interwiki' or 'langlink'
+  si_type                    varbinary(32)       NOT NULL,
+
+  -- local key value, ie 'en' or 'wiktionary'
+  si_key                     varbinary(32)       NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/site_ids_type ON /*_*/site_identifiers (si_type, si_key);
+CREATE INDEX /*i*/site_ids_site ON /*_*/site_identifiers (si_site);
+CREATE INDEX /*i*/site_ids_key ON /*_*/site_identifiers (si_key);
+
 -- vim: sw=2 sts=2 et
index cccc645..c906143 100644 (file)
@@ -178,6 +178,9 @@ return array(
        'jquery.getAttrs' => array(
                'scripts' => 'resources/jquery/jquery.getAttrs.js',
        ),
+       'jquery.hidpi' => array(
+               'scripts' => 'resources/jquery/jquery.hidpi.js',
+       ),
        'jquery.highlightText' => array(
                'scripts' => 'resources/jquery/jquery.highlightText.js',
                'dependencies' => 'jquery.mwExtension',
@@ -621,6 +624,12 @@ return array(
                        'feedback-bugnew',
                ),
        ),
+       'mediawiki.hidpi' => array(
+               'scripts' => 'resources/mediawiki/mediawiki.hidpi.js',
+               'dependencies' => array(
+                       'jquery.hidpi',
+               ),
+       ),
        'mediawiki.htmlform' => array(
                'scripts' => 'resources/mediawiki/mediawiki.htmlform.js',
        ),
diff --git a/resources/jquery/jquery.hidpi.js b/resources/jquery/jquery.hidpi.js
new file mode 100644 (file)
index 0000000..b7335ff
--- /dev/null
@@ -0,0 +1,119 @@
+/**
+ * Responsive images based on 'srcset' and 'window.devicePixelRatio' emulation where needed.
+ *
+ * Call $().hidpi() on a document or part of a document to replace image srcs in that section.
+ *
+ * $.devicePixelRatio() can be used to supplement window.devicePixelRatio with support on
+ * some additional browsers.
+ */
+( function ( $ ) {
+
+/**
+ * Detect reported or approximate device pixel ratio.
+ * 1.0 means 1 CSS pixel is 1 hardware pixel
+ * 2.0 means 1 CSS pixel is 2 hardware pixels
+ * etc
+ *
+ * Uses window.devicePixelRatio if available, or CSS media queries on IE.
+ *
+ * @method
+ * @returns {number} Device pixel ratio
+ */
+$.devicePixelRatio = function () {
+       if ( window.devicePixelRatio !== undefined ) {
+               // Most web browsers:
+               // * WebKit (Safari, Chrome, Android browser, etc)
+               // * Opera
+               // * Firefox 18+
+               return window.devicePixelRatio;
+       } else if ( window.msMatchMedia !== undefined ) {
+               // Windows 8 desktops / tablets, probably Windows Phone 8
+               //
+               // IE 10 doesn't report pixel ratio directly, but we can get the
+               // screen DPI and divide by 96. We'll bracket to [1, 1.5, 2.0] for
+               // simplicity, but you may get different values depending on zoom
+               // factor, size of screen and orientation in Metro IE.
+               if ( window.msMatchMedia( '(min-resolution: 192dpi)' ).matches ) {
+                       return 2;
+               } else if ( window.msMatchMedia( '(min-resolution: 144dpi)' ).matches ) {
+                       return 1.5;
+               } else {
+                       return 1;
+               }
+       } else {
+               // Legacy browsers...
+               // Assume 1 if unknown.
+               return 1;
+       }
+};
+
+/**
+ * Implement responsive images based on srcset attributes, if browser has no
+ * native srcset support.
+ *
+ * @method
+ * @returns {jQuery} This selection
+ */
+$.fn.hidpi = function () {
+       var $target = this,
+               // @todo add support for dpi media query checks on Firefox, IE
+               devicePixelRatio = $.devicePixelRatio(),
+               testImage = new Image();
+
+       if ( devicePixelRatio > 1 && testImage.srcset === undefined ) {
+               // No native srcset support.
+               $target.find( 'img' ).each( function () {
+                       var $img = $( this ),
+                               srcset = $img.attr( 'srcset' ),
+                               match;
+                       if ( typeof srcset === 'string' && srcset !== '' ) {
+                               match = $.matchSrcSet( devicePixelRatio, srcset );
+                               if (match !== null ) {
+                                       $img.attr( 'src', match );
+                               }
+                       }
+               });
+       }
+
+       return $target;
+};
+
+/**
+ * Match a srcset entry for the given device pixel ratio
+ *
+ * @param {number} devicePixelRatio
+ * @param {string} srcset
+ * @return {mixed} null or the matching src string
+ *
+ * Exposed for testing.
+ */
+$.matchSrcSet = function ( devicePixelRatio, srcset ) {
+       var candidates,
+               candidate,
+               bits,
+               src,
+               i,
+               ratioStr,
+               ratio,
+               selectedRatio = 1,
+               selectedSrc = null;
+       candidates = srcset.split( / *, */ );
+       for ( i = 0; i < candidates.length; i++ ) {
+               candidate = candidates[i];
+               bits = candidate.split( / +/ );
+               src = bits[0];
+               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 ) {
+                               selectedRatio = ratio;
+                               selectedSrc = src;
+                       }
+               }
+       }
+       return selectedSrc;
+};
+
+}( jQuery ) );
diff --git a/resources/mediawiki/mediawiki.hidpi.js b/resources/mediawiki/mediawiki.hidpi.js
new file mode 100644 (file)
index 0000000..1979573
--- /dev/null
@@ -0,0 +1,5 @@
+$( 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 fb0c848..cd2289d 100644 (file)
@@ -671,7 +671,7 @@ class ParserTest {
                        'wgNoFollowLinks' => true,
                        'wgNoFollowDomainExceptions' => array(),
                        'wgThumbnailScriptPath' => false,
-                       'wgUseImageResize' => false,
+                       'wgUseImageResize' => true,
                        'wgLocaltimezone' => 'UTC',
                        'wgAllowExternalImages' => true,
                        'wgUseTidy' => false,
index 61cf508..826df81 100644 (file)
@@ -71,6 +71,12 @@ Template:echo
 {{{1}}}
 !! endarticle
 
+!! article
+Template:attr_str
+!! text
+{{{1}}}="{{{2}}}"
+!! endarticle
+
 ###
 ### Basic tests
 ###
@@ -4046,6 +4052,14 @@ Template parameter as link source
 </p>
 !! end
 
+!!test
+Template-generated attribute string (k='v')
+!!input
+<span {{attr_str|id|v1}}>bar</span>
+!!result
+<p><span id="v1">bar</span>
+</p>
+!!end
 
 !!article
 Template:paramtest2
@@ -4325,6 +4339,15 @@ section=1
 ###
 ### <includeonly> and <noinclude> in attributes
 ###
+!!test
+0. includeonly around the entire attribute
+!!input
+<span <includeonly>id="v1"</includeonly><noinclude>id="v2"</noinclude>>bar</span>
+!!result
+<p><span id="v2">bar</span>
+</p>
+!!end
+
 !!test
 1. includeonly in html attr key
 !!input
@@ -5363,6 +5386,15 @@ Image with caption
 
 !! end
 
+!! test
+Image with empty attribute
+!! input
+[[Image:foobar.jpg|right||Caption text]]
+!! result
+<div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption text"><img alt="Caption text" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div>
+
+!! end
+
 !! test
 Image with link parameter, wiki target
 !! input
@@ -5457,7 +5489,7 @@ Thumbnail image with link parameter
 !! input
 [[Image:foobar.jpg|thumb|link=http://example.com/|Title]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="http://example.com/"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>Title</div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="http://example.com/"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>Title</div></div></div>
 
 !! end
 
@@ -5531,7 +5563,7 @@ Thumbnail image caption with a free URL
 !! input
 [[Image:foobar.jpg|thumb|http://example.com]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div>
 
 !! end
 
@@ -5540,7 +5572,7 @@ Thumbnail image caption with a free URL and explicit alt
 !! input
 [[Image:foobar.jpg|thumb|http://example.com|alt=Alteration]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Alteration" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Alteration" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div>
 
 !! end
 
@@ -5549,7 +5581,7 @@ BUG 1887: A ISBN with a thumbnail
 !! input
 [[Image:foobar.jpg|thumb|ISBN 1235467890]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a href="/wiki/Special:BookSources/1235467890" class="internal mw-magiclink-isbn">ISBN 1235467890</a></div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a href="/wiki/Special:BookSources/1235467890" class="internal mw-magiclink-isbn">ISBN 1235467890</a></div></div></div>
 
 !! end
 
@@ -5558,7 +5590,7 @@ BUG 1887: A RFC with a thumbnail
 !! input
 [[Image:foobar.jpg|thumb|This is RFC 12354]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This is <a class="external mw-magiclink-rfc" href="//tools.ietf.org/html/rfc12354">RFC 12354</a></div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This is <a class="external mw-magiclink-rfc" href="//tools.ietf.org/html/rfc12354">RFC 12354</a></div></div></div>
 
 !! end
 
@@ -5567,7 +5599,7 @@ BUG 1887: A mailto link with a thumbnail
 !! input
 [[Image:foobar.jpg|thumb|Please mailto:nobody@example.com]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>Please <a rel="nofollow" class="external free" href="mailto:nobody@example.com">mailto:nobody@example.com</a></div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>Please <a rel="nofollow" class="external free" href="mailto:nobody@example.com">mailto:nobody@example.com</a></div></div></div>
 
 !! end
 
@@ -5640,7 +5672,7 @@ Image caption containing another image
 !! input
 [[Image:Foobar.jpg|thumb|This is a caption with another [[Image:icon.png|image]] inside it!]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This is a caption with another <a href="/index.php?title=Special:Upload&amp;wpDestFile=Icon.png" class="new" title="File:Icon.png">image</a> inside it!</div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This is a caption with another <a href="/index.php?title=Special:Upload&amp;wpDestFile=Icon.png" class="new" title="File:Icon.png">image</a> inside it!</div></div></div>
 
 !! end
 
@@ -5660,7 +5692,7 @@ Bug 3090: External links other than http: in image captions
 !! input
 [[Image:Foobar.jpg|thumb|200px|This caption has [irc://example.net irc] and [https://example.com Secure] ext links in it.]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:202px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="200" height="23" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This caption has <a rel="nofollow" class="external text" href="irc://example.net">irc</a> and <a rel="nofollow" class="external text" href="https://example.com">Secure</a> ext links in it.</div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:202px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" width="200" height="23" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This caption has <a rel="nofollow" class="external text" href="irc://example.net">irc</a> and <a rel="nofollow" class="external text" href="https://example.com">Secure</a> ext links in it.</div></div></div>
 
 !! end
 
@@ -8823,19 +8855,19 @@ image:foobar.jpg|Blabla|alt=This is a foo-bar.|blabla.
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 105px"><div style="width: 105px">
-                       <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="70" height="8" /></a></div></div>
+                       <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg" width="70" height="8" /></a></div></div>
                        <div class="gallerytext">
 <p>some <b>caption</b> <a href="/wiki/Main_Page" title="Main Page">Main Page</a>
 </p>
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 105px"><div style="width: 105px">
-                       <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="70" height="8" /></a></div></div>
+                       <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg" width="70" height="8" /></a></div></div>
                        <div class="gallerytext">
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 105px"><div style="width: 105px">
-                       <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="This is a foo-bar." src="http://example.com/images/3/3a/Foobar.jpg" width="70" height="8" /></a></div></div>
+                       <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="This is a foo-bar." src="http://example.com/images/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg" width="70" height="8" /></a></div></div>
                        <div class="gallerytext">
 <p>Blabla|blabla.
 </p>
@@ -8855,14 +8887,14 @@ File:foobar.jpg|{{Test|unamedParam|alt=param}}|alt=galleryalt
 !! result
 <ul class="gallery">
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="galleryalt" src="http://example.com/images/3/3a/Foobar.jpg" width="120" height="14" /></a></div></div>
+                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div>
                        <div class="gallerytext">
-<p><a href="/wiki/File:Foobar.jpg" class="image" title="desc"><img alt="inneralt" src="http://example.com/images/3/3a/Foobar.jpg" width="20" height="2" /></a>
+<p><a href="/wiki/File:Foobar.jpg" class="image" title="desc"><img alt="inneralt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/20px-Foobar.jpg" width="20" height="2" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/30px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/40px-Foobar.jpg 2x" /></a>
 </p>
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="galleryalt" src="http://example.com/images/3/3a/Foobar.jpg" width="120" height="14" /></a></div></div>
+                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div>
                        <div class="gallerytext">
 <p>This is a test template
 </p>
@@ -8899,7 +8931,7 @@ caption
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="120" height="14" /></a></div></div>
+                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div>
                        <div class="gallerytext">
 <p><a href="/wiki/File:Foobar.jpg" title="File:Foobar.jpg">Foobar.jpg</a><br />
 some <b>caption</b> <a href="/wiki/Main_Page" title="Main Page">Main Page</a>
@@ -8907,7 +8939,7 @@ some <b>caption</b> <a href="/wiki/Main_Page" title="Main Page">Main Page</a>
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="120" height="14" /></a></div></div>
+                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div>
                        <div class="gallerytext">
 <p><a href="/wiki/File:Foobar.jpg" title="File:Foobar.jpg">Foobar.jpg</a><br />
 </p>
@@ -8939,12 +8971,12 @@ foobar.jpg
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="120" height="14" /></a></div></div>
+                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div>
                        <div class="gallerytext">
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="120" height="14" /></a></div></div>
+                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div>
                        <div class="gallerytext">
                        </div>
                </div></li>
@@ -9075,7 +9107,7 @@ Width + Height sized image (using px) (height is ignored)
 !! input
 [[Image:foobar.jpg|640x480px]]
 !! result
-<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="640" height="73" /></a>
+<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg" width="640" height="73" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/960px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/1280px-Foobar.jpg 2x" /></a>
 </p>
 !!end
 
@@ -9084,7 +9116,7 @@ Width-sized image (using px, no following whitespace)
 !! input
 [[Image:foobar.jpg|640px]]
 !! result
-<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="640" height="73" /></a>
+<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg" width="640" height="73" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/960px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/1280px-Foobar.jpg 2x" /></a>
 </p>
 !!end
 
@@ -9093,7 +9125,7 @@ Width-sized image (using px, with following whitespace - test regression from r3
 !! input
 [[Image:foobar.jpg|640px ]]
 !! result
-<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="640" height="73" /></a>
+<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg" width="640" height="73" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/960px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/1280px-Foobar.jpg 2x" /></a>
 </p>
 !!end
 
@@ -9102,7 +9134,7 @@ Width-sized image (using px, with preceding whitespace - test regression from r3
 !! input
 [[Image:foobar.jpg| 640px]]
 !! result
-<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="640" height="73" /></a>
+<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg" width="640" height="73" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/960px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/1280px-Foobar.jpg 2x" /></a>
 </p>
 !!end
 
@@ -9142,7 +9174,7 @@ Images with the "|" character in the comment
 !! input
 [[image:Foobar.jpg|thumb|An [http://test/?param1=|left|&param2=|x external] URL]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>An <a rel="nofollow" class="external text" href="http://test/?param1=%7Cleft%7C&amp;param2=%7Cx">external</a> URL</div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>An <a rel="nofollow" class="external text" href="http://test/?param1=%7Cleft%7C&amp;param2=%7Cx">external</a> URL</div></div></div>
 
 !!end
 
@@ -10136,7 +10168,7 @@ Free external link invading image caption
 !! input
 [[Image:Foobar.jpg|thumb|http://x|hello]]
 !! result
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>hello</div></div></div>
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a>  <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>hello</div></div></div>
 
 !! end
 
@@ -11059,7 +11091,7 @@ File:foobar.jpg|caption|alt=galleryalt|link=InterWikiLink
 !! result
 <ul class="gallery">
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/InterWikiLink"><img alt="galleryalt" src="http://example.com/images/3/3a/Foobar.jpg" width="120" height="14" /></a></div></div>
+                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/InterWikiLink"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div>
                        <div class="gallerytext">
 <p>caption
 </p>
@@ -11078,7 +11110,7 @@ File:foobar.jpg|caption|alt=galleryalt|link=http://www.example.org
 !! result
 <ul class="gallery">
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="http://www.example.org"><img alt="galleryalt" src="http://example.com/images/3/3a/Foobar.jpg" width="120" height="14" /></a></div></div>
+                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="http://www.example.org"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div>
                        <div class="gallerytext">
 <p>caption
 </p>
@@ -11097,7 +11129,7 @@ File:foobar.jpg|caption|alt=galleryalt|link=" onclick="alert('malicious javascri
 !! result
 <ul class="gallery">
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/%22_onclick%3D%22alert(%27malicious_javascript_code!%27);"><img alt="galleryalt" src="http://example.com/images/3/3a/Foobar.jpg" width="120" height="14" /></a></div></div>
+                       <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/%22_onclick%3D%22alert(%27malicious_javascript_code!%27);"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div>
                        <div class="gallerytext">
 <p>caption
 </p>
@@ -11158,31 +11190,8 @@ HttP://MediaWiki.Org/
 ### Parsoids-specific tests
 ### Parsoid-PHP parser incompatibilities
 ###
-
-!!test
-1. includeonly around the entire attribute
-!!options
-disabled
-!!input
-<span <includeonly>id="v1"</includeonly><noinclude>id="v2"</noinclude>>bar</span>
-!!result
-<p><span>bar</span>
-</p>
-!!end
-
-!!test
-2. template around the entire attribute
-!!options
-disabled
-!!input
-<span {{echo|id="v1"}}>bar</span>
-!!result
-<p><span>bar</span>
-</p>
-!!end
-
 !!test
-3. SOL-sensitive wikitext tokens as template-args
+1. SOL-sensitive wikitext tokens as template-args
 !!options
 disabled
 !!input
index ff13702..9c2fb69 100644 (file)
@@ -666,4 +666,22 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                }
        }
 
+       /**
+        * Returns true iff the given namespace defaults to Wikitext
+        * according to $wgNamespaceContentModels
+        *
+        * @param int $ns The namespace ID to check
+        *
+        * @return bool
+        * @since 1.21
+        */
+       protected function isWikitextNS( $ns ) {
+               global $wgNamespaceContentModels;
+
+               if ( isset( $wgNamespaceContentModels[$ns] ) ) {
+                       return $wgNamespaceContentModels[$ns] === CONTENT_MODEL_WIKITEXT;
+               }
+
+               return true;
+       }
 }
index 5df8fe1..f7387e1 100644 (file)
@@ -236,30 +236,35 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                $this->runGroupPermissions( 'move', array( array( 'movenotallowedfile' ), array( 'movenotallowed' ) ),
                        array( array( 'movenotallowedfile' ), array( 'movenologintext' ) ) );
 
-               $this->setTitle( NS_MAIN );
-               $this->setUser( 'anon' );
-               $this->setUserPerm( "move" );
-               $this->runGroupPermissions( 'move', array(  ) );
-
-               $this->setUserPerm( "" );
-               $this->runGroupPermissions( 'move', array( array( 'movenotallowed' ) ),
-                       array( array( 'movenologintext' ) ) );
-
-               $this->setUser( $this->userName );
-               $this->setUserPerm( "" );
-               $this->runGroupPermissions( 'move', array( array( 'movenotallowed' ) ) );
-
-               $this->setUserPerm( "move" );
-               $this->runGroupPermissions( 'move', array( ) );
-
-               $this->setUser( 'anon' );
-               $this->setUserPerm( 'move' );
-               $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
-               $this->assertEquals( array( ), $res );
-
-               $this->setUserPerm( '' );
-               $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
-               $this->assertEquals( array( array( 'movenotallowed' ) ), $res );
+               if ( $this->isWikitextNS( NS_MAIN ) ) {
+                       //NOTE: some content models don't allow moving
+                       //@todo: find a Wikitext namespace for testing
+
+                       $this->setTitle( NS_MAIN );
+                       $this->setUser( 'anon' );
+                       $this->setUserPerm( "move" );
+                       $this->runGroupPermissions( 'move', array(  ) );
+
+                       $this->setUserPerm( "" );
+                       $this->runGroupPermissions( 'move', array( array( 'movenotallowed' ) ),
+                               array( array( 'movenologintext' ) ) );
+
+                       $this->setUser( $this->userName );
+                       $this->setUserPerm( "" );
+                       $this->runGroupPermissions( 'move', array( array( 'movenotallowed' ) ) );
+
+                       $this->setUserPerm( "move" );
+                       $this->runGroupPermissions( 'move', array( ) );
+
+                       $this->setUser( 'anon' );
+                       $this->setUserPerm( 'move' );
+                       $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
+                       $this->assertEquals( array( ), $res );
+
+                       $this->setUserPerm( '' );
+                       $res = $this->title->getUserPermissionsErrors( 'move-target', $this->user );
+                       $this->assertEquals( array( array( 'movenotallowed' ) ), $res );
+               }
 
                $this->setTitle( NS_USER );
                $this->setUser( $this->userName );
@@ -582,7 +587,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                $this->assertEquals( array( array( 'immobile-source-namespace', 'Media' ) ),
                                                         $this->title->getUserPermissionsErrors( 'move', $this->user ) );
 
-               $this->setTitle( NS_MAIN, "test page" );
+               $this->setTitle( NS_HELP, "test page" );
                $this->assertEquals( array( ),
                                                         $this->title->getUserPermissionsErrors( 'move', $this->user ) );
                $this->assertEquals( true,
@@ -600,7 +605,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                $this->assertEquals( array( array( 'immobile-target-namespace', 'Media' ) ),
                                                         $this->title->getUserPermissionsErrors( 'move-target', $this->user ) );
 
-               $this->setTitle( NS_MAIN, "test page" );
+               $this->setTitle( NS_HELP, "test page" );
                $this->assertEquals( array( ),
                                                         $this->title->getUserPermissionsErrors( 'move-target', $this->user ) );
                $this->assertEquals( true,
@@ -621,7 +626,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                $wgUser = $this->user;
 
                $this->setUserPerm( array( "createpage", "move" ) );
-               $this->setTitle( NS_MAIN, "test page" );
+               $this->setTitle( NS_HELP, "test page" );
 
                # $short
                $this->assertEquals( array( array( 'confirmedittext' ) ),
index 70fce11..398ad2d 100644 (file)
@@ -58,7 +58,7 @@ abstract class GenericArrayObjectTest extends MediaWikiTestCase {
                $instances = array();
 
                foreach ( $this->elementInstancesProvider() as $elementInstances ) {
-                       $instances[] = $this->getNew( $elementInstances );
+                       $instances[] = $this->getNew( $elementInstances[0] );
                }
 
                return $this->arrayWrap( $instances );
index 848991e..804726b 100644 (file)
@@ -303,7 +303,7 @@ class NewParserTest extends MediaWikiTestCase {
                        'wgNoFollowLinks' => true,
                        'wgNoFollowDomainExceptions' => array(),
                        'wgThumbnailScriptPath' => false,
-                       'wgUseImageResize' => false,
+                       'wgUseImageResize' => true,
                        'wgUseTeX' => isset( $opts['math'] ),
                        'wgMathDirectory' => $uploadDir . '/math',
                        'wgLocaltimezone' => 'UTC',
@@ -524,6 +524,14 @@ class NewParserTest extends MediaWikiTestCase {
                        return;
                }
 
+               if ( !$this->isWikitextNS( NS_MAIN ) ) {
+                       // parser tests frequently assume that the main namespace contains wikitext.
+                       // @todo: When setting up pages, force the content model. Only skip if
+                       //        $wgtContentModelUseDB is false.
+                       $this->markTestSkipped( "Main namespace does not support wikitext,"
+                                       . "skipping parser test: $desc" );
+               }
+
                wfDebug( "Running parser test: $desc\n" );
 
                $opts = $this->parseOptions( $opts );
index 879e41f..395e1a0 100644 (file)
@@ -40,6 +40,12 @@ class SearchEngineTest extends MediaWikiTestCase {
                if ( $this->pageExists( 'Not_Main_Page' ) ) {
                        return;
                }
+
+               if ( !$this->isWikitextNS( NS_MAIN ) ) {
+                       //@todo: cover the case of non-wikitext content in the main namespace
+                       return;
+               }
+
                $this->insertPage( "Not_Main_Page",     "This is not a main page", 0 );
                $this->insertPage( 'Talk:Not_Main_Page',        'This is not a talk page to the main page, see [[smithee]]', 1 );
                $this->insertPage( 'Smithee',   'A smithee is one who smiths. See also [[Alan Smithee]]', 0 );
@@ -60,6 +66,11 @@ class SearchEngineTest extends MediaWikiTestCase {
        }
 
        function fetchIds( $results ) {
+               if ( !$this->isWikitextNS( NS_MAIN ) ) {
+                       $this->markTestIncomplete( __CLASS__ . " does no yet support non-wikitext content "
+                               . "in the main namespace");
+               }
+
                $this->assertTrue( is_object( $results ) );
 
                $matches = array();
@@ -84,7 +95,7 @@ class SearchEngineTest extends MediaWikiTestCase {
         * @param $n Integer: unused
         */
        function insertPage( $pageName, $text, $ns ) {
-               $title = Title::newFromText( $pageName );
+               $title = Title::newFromText( $pageName, $ns );
 
                $user = User::newFromName( 'WikiSysop' );
                $comment = 'Search Test';
diff --git a/tests/phpunit/includes/site/MediaWikiSiteTest.php b/tests/phpunit/includes/site/MediaWikiSiteTest.php
new file mode 100644 (file)
index 0000000..208ab1e
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * Tests for the MediaWikiSite class.
+ *
+ * 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 Site
+ * @ingroup Test
+ *
+ * @group Site
+ * @group Database
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class MediaWikiSiteTest extends SiteObjectTest {
+
+       public function setUp() {
+               parent::setUp();
+
+               static $hasSites = false;
+
+               if ( !$hasSites ) {
+                       TestSites::insertIntoDb();
+                       $hasSites = true;
+               }
+       }
+
+       public function testFactoryConstruction() {
+               $this->assertInstanceOf( 'MediaWikiSite', MediaWikiSite::newFromGlobalId( 'enwiki' ) );
+               $this->assertInstanceOf( 'Site', MediaWikiSite::newFromGlobalId( 'enwiki' ) );
+               $this->assertInstanceOf( 'MediaWikiSite', SitesTable::singleton()->newRow( array( 'type' => Site::TYPE_MEDIAWIKI ) ) );
+       }
+
+       public function testNormalizePageTitle() {
+               $site = MediaWikiSite::newFromGlobalId( 'enwiki' );
+
+               //NOTE: this does not actually call out to the enwiki site to perform the normalization,
+               //      but uses a local Title object to do so. This is hardcoded on SiteLink::normalizePageTitle
+               //      for the case that MW_PHPUNIT_TEST is set.
+               $this->assertEquals( 'Foo', $site->normalizePageName( ' foo ' ) );
+       }
+
+       public function fileUrlProvider() {
+               return array(
+                       // url, filepath, path arg, expected
+                       array( 'https://en.wikipedia.org', '/w/$1', 'api.php', 'https://en.wikipedia.org/w/api.php' ),
+                       array( 'https://en.wikipedia.org', '/w/', 'api.php', 'https://en.wikipedia.org/w/' ),
+                       array( 'https://en.wikipedia.org', '/foo/page.php?name=$1', 'api.php', 'https://en.wikipedia.org/foo/page.php?name=api.php' ),
+                       array( 'https://en.wikipedia.org', '/w/$1', '', 'https://en.wikipedia.org/w/' ),
+                       array( 'https://en.wikipedia.org', '/w/$1', 'foo/bar/api.php', 'https://en.wikipedia.org/w/foo/bar/api.php' ),
+               );
+       }
+
+       /**
+        * @dataProvider fileUrlProvider
+        */
+       public function testGetFileUrl( $url, $filePath, $pathArgument, $expected ) {
+               $site = MediaWikiSite::newFromGlobalId( 'enwiki' );
+
+               $site->setFilePath( $url . $filePath );
+
+               $this->assertEquals( $expected, $site->getFileUrl( $pathArgument ) );
+       }
+
+       public function provideGetPageUrl() {
+               return array(
+                       // path, page, expected substring
+                       array( 'http://acme.test/wiki/$1', 'Berlin', '/wiki/Berlin' ),
+                       array( 'http://acme.test/wiki/', 'Berlin', '/wiki/' ),
+                       array( 'http://acme.test/w/index.php?title=$1', 'Berlin', '/w/index.php?title=Berlin' ),
+                       array( 'http://acme.test/wiki/$1', '', '/wiki/' ),
+                       array( 'http://acme.test/wiki/$1', 'Berlin/sub page', '/wiki/Berlin/sub_page' ),
+                       array( 'http://acme.test/wiki/$1', 'Cork (city)   ', '/Cork_(city)' ),
+                       array( 'http://acme.test/wiki/$1', 'M&M', '/wiki/M%26M' ),
+               );
+       }
+
+       /**
+        * @dataProvider provideGetPageUrl
+        */
+       public function testGetPageUrl( $path, $page, $expected ) {
+               /* @var MediaWikiSite $site */
+               $site = MediaWikiSite::newFromGlobalId( 'enwiki' );
+
+               $site->setLinkPath( $path );
+               $this->assertContains( $path, $site->getPageUrl() );
+               $this->assertContains( $expected, $site->getPageUrl( $page ) );
+       }
+
+}
diff --git a/tests/phpunit/includes/site/SiteArrayTest.php b/tests/phpunit/includes/site/SiteArrayTest.php
new file mode 100644 (file)
index 0000000..021691a
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * Tests for the SiteArray class.
+ * The tests for methods defined in the SiteList interface are in SiteListTest.
+ *
+ * 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
+ *Both
+ * Bith
+ * @file
+ * @since 1.21
+ *
+ * @ingroup Site
+ * @ingroup Test
+ *
+ * @group Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class SiteArrayTest extends GenericArrayObjectTest {
+
+       /**
+        * @see GenericArrayObjectTest::elementInstancesProvider
+        *
+        * @since 1.21
+        *
+        * @return array
+        */
+       public function elementInstancesProvider() {
+               $sites = TestSites::getSites();
+
+               $siteArrays = array();
+
+               $siteArrays[] = $sites;
+
+               $siteArrays[] = array( array_shift( $sites ) );
+
+               $siteArrays[] = array( array_shift( $sites ), array_shift( $sites ) );
+
+               return $this->arrayWrap( $siteArrays );
+       }
+
+       /**
+        * @see GenericArrayObjectTest::getInstanceClass
+        *
+        * @since 1.21
+        *
+        * @return array
+        */
+       public function getInstanceClass() {
+               return 'SiteArray';
+       }
+
+}
\ No newline at end of file
diff --git a/tests/phpunit/includes/site/SiteListTest.php b/tests/phpunit/includes/site/SiteListTest.php
new file mode 100644 (file)
index 0000000..c7a1934
--- /dev/null
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * Tests for the SiteList implementing 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 Site
+ * @ingroup Test
+ *
+ * @group Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class SiteListTest extends MediaWikiTestCase {
+
+       /**
+        * Returns instances of SiteList implementing objects.
+        * @return array
+        */
+       public function siteListProvider() {
+               $sitesArrays = $this->siteArrayProvider();
+
+               $listInstances = array();
+
+               foreach ( $sitesArrays as $sitesArray ) {
+                       $listInstances[] = new SiteArray( $sitesArray[0] );
+               }
+
+               return $this->arrayWrap( $listInstances );
+       }
+
+       /**
+        * Returns arrays with instances of Site implementing objects.
+        * @return array
+        */
+       public function siteArrayProvider() {
+               $sites = TestSites::getSites();
+
+               $siteArrays = array();
+
+               $siteArrays[] = $sites;
+
+               $siteArrays[] = array( array_shift( $sites ) );
+
+               $siteArrays[] = array( array_shift( $sites ), array_shift( $sites ) );
+
+               return $this->arrayWrap( $siteArrays );
+       }
+
+       /**
+        * @dataProvider siteListProvider
+        * @param SiteList $sites
+        */
+       public function testIsEmpty( SiteList $sites ) {
+               $this->assertEquals( count( $sites ) === 0, $sites->isEmpty() );
+       }
+
+       /**
+        * @dataProvider siteListProvider
+        * @param SiteList $sites
+        */
+       public function testGetSiteByGlobalId( SiteList $sites ) {
+               if ( $sites->isEmpty() ) {
+                       $this->assertTrue( true );
+               }
+               else {
+                       /**
+                        * @var Site $site
+                        */
+                       foreach ( $sites as $site ) {
+                               $this->assertEquals( $site, $sites->getSite( $site->getGlobalId() ) );
+                       }
+               }
+       }
+
+       /**
+        * @dataProvider siteListProvider
+        * @param SiteList $sites
+        */
+       public function testGetSiteByInternalId( $sites ) {
+               /**
+                * @var Site $site
+                */
+               foreach ( $sites as $site ) {
+                       if ( is_integer( $site->getInternalId() ) ) {
+                               $this->assertEquals( $site, $sites->getSiteByInternalId( $site->getInternalId() ) );
+                       }
+               }
+
+               $this->assertTrue( true );
+       }
+
+       /**
+        * @dataProvider siteListProvider
+        * @param SiteList $sites
+        */
+       public function testHasGlobalId( $sites ) {
+               $this->assertFalse( $sites->hasSite( 'non-existing-global-id' ) );
+               $this->assertFalse( $sites->hasInternalId( 72010101010 ) );
+
+               if ( !$sites->isEmpty() ) {
+                       /**
+                        * @var Site $site
+                        */
+                       foreach ( $sites as $site ) {
+                               $this->assertTrue( $sites->hasSite( $site->getGlobalId() ) );
+                       }
+               }
+       }
+
+       /**
+        * @dataProvider siteListProvider
+        * @param SiteList $sites
+        */
+       public function testHasInternallId( $sites ) {
+               /**
+                * @var Site $site
+                */
+               foreach ( $sites as $site ) {
+                       if ( is_integer( $site->getInternalId() ) ) {
+                               $this->assertTrue( $site, $sites->hasInternalId( $site->getInternalId() ) );
+                       }
+               }
+
+               $this->assertFalse( $sites->hasInternalId( -1 ) );
+       }
+
+       /**
+        * @dataProvider siteListProvider
+        * @param SiteList $sites
+        */
+       public function testGetGlobalIdentifiers( SiteList $sites ) {
+               $identifiers = $sites->getGlobalIdentifiers();
+
+               $this->assertTrue( is_array( $identifiers ) );
+
+               $expected = array();
+
+               /**
+                * @var Site $site
+                */
+               foreach ( $sites as $site ) {
+                       $expected[] = $site->getGlobalId();
+               }
+
+               $this->assertArrayEquals( $expected, $identifiers );
+       }
+
+
+}
\ No newline at end of file
diff --git a/tests/phpunit/includes/site/SiteObjectTest.php b/tests/phpunit/includes/site/SiteObjectTest.php
new file mode 100644 (file)
index 0000000..e8358f3
--- /dev/null
@@ -0,0 +1,282 @@
+<?php
+
+/**
+ * Tests for the SiteObject class.
+ *
+ * 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 Site
+ * @ingroup Test
+ *
+ * @group Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class SiteObjectTest extends ORMRowTest {
+
+       /**
+        * @see ORMRowTest::getRowClass
+        * @since 1.21
+        * @return string
+        */
+       protected function getRowClass() {
+               return 'SiteObject';
+       }
+
+       /**
+        * @see ORMRowTest::getTableInstance
+        * @since 1.21
+        * @return IORMTable
+        */
+       protected function getTableInstance() {
+               return SitesTable::singleton();
+       }
+
+       /**
+        * @see ORMRowTest::constructorTestProvider
+        * @since 1.21
+        * @return array
+        */
+       public function constructorTestProvider() {
+               $argLists = array();
+
+               $argLists[] = array( 'global_key' => '42' );
+
+               $argLists[] = array( 'global_key' => '42', 'type' => Site::TYPE_MEDIAWIKI );
+
+               $constructorArgs = array();
+
+               foreach ( $argLists as $argList ) {
+                       $constructorArgs[] = array( $argList, true );
+               }
+
+               return $constructorArgs;
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testGetInterwikiIds( Site $site ) {
+               $this->assertInternalType( 'array', $site->getInterwikiIds() );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testGetNavigationIds( Site $site ) {
+               $this->assertInternalType( 'array', $site->getNavigationIds() );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testAddNavigationId( Site $site ) {
+               $site->addNavigationId( 'foobar' );
+               $this->assertTrue( in_array( 'foobar', $site->getNavigationIds(), true ) );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testAddInterwikiId( Site $site ) {
+               $site->addInterwikiId( 'foobar' );
+               $this->assertTrue( in_array( 'foobar', $site->getInterwikiIds(), true ) );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testGetLanguageCode( Site $site ) {
+               $this->assertTypeOrFalse( 'string', $site->getLanguageCode() );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testSetLanguageCode( Site $site ) {
+               $site->setLanguageCode( 'en' );
+               $this->assertEquals( 'en', $site->getLanguageCode() );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testNormalizePageName( Site $site ) {
+               $this->assertInternalType( 'string', $site->normalizePageName( 'Foobar' ) );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testGetGlobalId( Site $site ) {
+               $this->assertInternalType( 'string', $site->getGlobalId() );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testSetGlobalId( Site $site ) {
+               $site->setGlobalId( 'foobar' );
+               $this->assertEquals( 'foobar', $site->getGlobalId() );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testGetType( Site $site ) {
+               $this->assertInternalType( 'string', $site->getType() );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testGetPath( Site $site ) {
+               $this->assertTypeOrFalse( 'string', $site->getPath( 'page_path' ) );
+               $this->assertTypeOrFalse( 'string', $site->getPath( 'file_path' ) );
+               $this->assertTypeOrFalse( 'string', $site->getPath( 'foobar' ) );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testGetAllPaths( Site $site ) {
+               $this->assertInternalType( 'array', $site->getAllPaths() );
+       }
+
+       /**
+        * @dataProvider instanceProvider
+        * @param Site $site
+        */
+       public function testSetAndRemovePath( Site $site ) {
+               $count = count( $site->getAllPaths() );
+
+               $site->setPath( 'spam', 'http://www.wikidata.org/$1' );
+               $site->setPath( 'spam', 'http://www.wikidata.org/foo/$1' );
+               $site->setPath( 'foobar', 'http://www.wikidata.org/bar/$1' );
+
+               $this->assertEquals( $count + 2, count( $site->getAllPaths() ) );
+
+               $this->assertInternalType( 'string', $site->getPath( 'foobar' ) );
+               $this->assertEquals( 'http://www.wikidata.org/foo/$1', $site->getPath( 'spam' ) );
+
+               $site->removePath( 'spam' );
+               $site->removePath( 'foobar' );
+
+               $this->assertEquals( $count, count( $site->getAllPaths() ) );
+
+               $this->assertFalse( $site->getPath( 'foobar' ) );
+               $this->assertFalse( $site->getPath( 'spam' ) );
+       }
+
+       public function testSetLinkPath() {
+               /* @var SiteObject $site */
+               $site = $this->getRowInstance( $this->getMockFields(), false );
+               $path = "TestPath/$1";
+
+               $site->setLinkPath( $path );
+               $this->assertEquals( $path, $site->getLinkPath() );
+       }
+
+       public function testGetLinkPathType() {
+               /* @var SiteObject $site */
+               $site = $this->getRowInstance( $this->getMockFields(), false );
+
+               $path = 'TestPath/$1';
+               $site->setLinkPath( $path );
+               $this->assertEquals( $path, $site->getPath( $site->getLinkPathType() ) );
+
+               $path = 'AnotherPath/$1';
+               $site->setPath( $site->getLinkPathType(), $path );
+               $this->assertEquals( $path, $site->getLinkPath() );
+       }
+
+       public function testSetPath() {
+               /* @var SiteObject $site */
+               $site = $this->getRowInstance( $this->getMockFields(), false );
+
+               $path = 'TestPath/$1';
+               $site->setPath( 'foo', $path );
+
+               $this->assertEquals( $path, $site->getPath( 'foo' ) );
+       }
+
+       public function provideGetPageUrl() {
+               //NOTE: the assumption that the URL is built by replacing $1
+               //      with the urlencoded version of $page
+               //      is true for SiteObject but not guaranteed for subclasses.
+               //      Subclasses need to override this provider appropriately.
+
+               return array(
+                       array( #0
+                               'http://acme.test/TestPath/$1',
+                               'Foo',
+                               '/TestPath/Foo',
+                       ),
+                       array( #1
+                               'http://acme.test/TestScript?x=$1&y=bla',
+                               'Foo',
+                               'TestScript?x=Foo&y=bla',
+                       ),
+                       array( #2
+                               'http://acme.test/TestPath/$1',
+                               'foo & bar/xyzzy (quux-shmoox?)',
+                               '/TestPath/foo%20%26%20bar%2Fxyzzy%20%28quux-shmoox%3F%29',
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider provideGetPageUrl
+        */
+       public function testGetPageUrl( $path, $page, $expected ) {
+               /* @var SiteObject $site */
+               $site = $this->getRowInstance( $this->getMockFields(), false );
+
+               //NOTE: the assumption that getPageUrl is based on getLinkPath
+               //      is true for SiteObject but not guaranteed for subclasses.
+               //      Subclasses need to override this test case appropriately.
+               $site->setLinkPath( $path );
+               $this->assertContains( $path, $site->getPageUrl() );
+
+               $this->assertContains( $expected, $site->getPageUrl( $page ) );
+       }
+
+       protected function assertTypeOrFalse( $type, $value ) {
+               if ( $value === false ) {
+                       $this->assertTrue( true );
+               }
+               else {
+                       $this->assertInternalType( $type, $value );
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/tests/phpunit/includes/site/SitesTest.php b/tests/phpunit/includes/site/SitesTest.php
new file mode 100644 (file)
index 0000000..7675d42
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+
+/**
+ * Tests for the Sites class.
+ *
+ * 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 Site
+ * @ingroup Test
+ *
+ * @group Site
+ * @group Database
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class SitesTest extends MediaWikiTestCase {
+
+       public function setUp() {
+               parent::setUp();
+               TestSites::insertIntoDb();
+       }
+
+       public function testSingleton() {
+               $this->assertInstanceOf( 'Sites', Sites::singleton() );
+               $this->assertTrue( Sites::singleton() === Sites::singleton() );
+       }
+
+       public function testGetSites() {
+               $this->assertInstanceOf( 'SiteList', Sites::singleton()->getSites() );
+       }
+
+
+       public function testGetSite() {
+               $count = 0;
+               $sites = Sites::singleton()->getSites();
+
+               /**
+                * @var Site $site
+                */
+               foreach ( $sites as $site ) {
+                       $this->assertInstanceOf( 'Site', $site );
+
+                       $this->assertEquals(
+                               $site,
+                               Sites::singleton()->getSite( $site->getGlobalId() )
+                       );
+
+                       if ( ++$count > 100 ) {
+                               break;
+                       }
+               }
+       }
+
+       public function testNewSite() {
+               $this->assertInstanceOf( 'Site', Sites::newSite() );
+               $this->assertInstanceOf( 'Site', Sites::newSite( 'enwiki' ) );
+       }
+
+       public function testGetGroup() {
+               $wikipedias = Sites::singleton()->getSiteGroup( "wikipedia" );
+
+               $this->assertFalse( $wikipedias->isEmpty() );
+
+               /* @var Site $site */
+               foreach ( $wikipedias as $site ) {
+                       $this->assertEquals( 'wikipedia', $site->getGroup() );
+               }
+       }
+
+}
diff --git a/tests/phpunit/includes/site/TestSites.php b/tests/phpunit/includes/site/TestSites.php
new file mode 100644 (file)
index 0000000..6003a8d
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Holds sites for testing purposes.
+ *
+ * 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 Site
+ * @ingroup Test
+ *
+ * @group Site
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class TestSites {
+
+       /**
+        * @since 1.21
+        *
+        * @return array
+        */
+       public static function getSites() {
+               $sites = array();
+
+               $site = Sites::newSite( 'foobar' );
+               $sites[] = $site;
+
+               $site = Sites::newSite( 'enwiktionary' );
+               $site->setGroup( 'wiktionary' );
+               $site->setType( Site::TYPE_MEDIAWIKI );
+               $site->setLanguageCode( 'en' );
+               $site->addNavigationId( 'enwiktionary' );
+               $site->setPath( MediaWikiSite::PATH_PAGE, "https://en.wiktionary.org/wiki/$1" );
+               $site->setPath( MediaWikiSite::PATH_FILE, "https://en.wiktionary.org/w/$1" );
+               $sites[] = $site;
+
+               $site = Sites::newSite( 'dewiktionary' );
+               $site->setGroup( 'wiktionary' );
+               $site->setType( Site::TYPE_MEDIAWIKI );
+               $site->setLanguageCode( 'de' );
+               $site->addInterwikiId( 'dewiktionary' );
+               $site->addInterwikiId( 'wiktionaryde' );
+               $site->setPath( MediaWikiSite::PATH_PAGE, "https://de.wiktionary.org/wiki/$1" );
+               $site->setPath( MediaWikiSite::PATH_FILE, "https://de.wiktionary.org/w/$1" );
+               $sites[] = $site;
+
+               $site = Sites::newSite( 'spam' );
+               $site->setGroup( 'spam' );
+               $site->setType( Site::TYPE_UNKNOWN );
+               $site->setLanguageCode( 'en' );
+               $site->addNavigationId( 'spam' );
+               $site->addNavigationId( 'spamz' );
+               $site->addInterwikiId( 'spamzz' );
+               $site->setLinkPath( "http://spamzz.test/testing/" );
+               $sites[] = $site;
+
+               foreach ( array( 'en', 'de', 'nl', 'sv', 'sr', 'no', 'nn' ) as $langCode ) {
+                       $site = Sites::newSite( $langCode . 'wiki' );
+                       $site->setGroup( 'wikipedia' );
+                       $site->setType( Site::TYPE_MEDIAWIKI );
+                       $site->setLanguageCode( $langCode );
+                       $site->addInterwikiId( $langCode );
+                       $site->addNavigationId( $langCode );
+                       $site->setPath( MediaWikiSite::PATH_PAGE, "https://$langCode.wikipedia.org/wiki/$1" );
+                       $site->setPath( MediaWikiSite::PATH_FILE, "https://$langCode.wikipedia.org/w/$1" );
+                       $sites[] = $site;
+               }
+
+               return $sites;
+       }
+
+       /**
+        * Inserts sites into the database for the unit tests that need them.
+        *
+        * @since 0.1
+        */
+       public static function insertIntoDb() {
+               $dbw = wfGetDB( DB_MASTER );
+
+               $dbw->begin( __METHOD__ );
+
+               $dbw->delete( 'sites', '*', __METHOD__ );
+               $dbw->delete( 'site_identifiers', '*', __METHOD__ );
+
+               /**
+                * @var Site $site
+                */
+               foreach ( TestSites::getSites() as $site ) {
+                       $site->save();
+               }
+
+               $dbw->commit( __METHOD__ );
+
+               Sites::singleton()->getSites( false ); // re-cache
+       }
+
+}
\ No newline at end of file
index be5f4ac..01072d8 100644 (file)
@@ -13,6 +13,7 @@ return array(
                        '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',
@@ -41,6 +42,7 @@ return array(
                        'jquery.colorUtil',
                        'jquery.delayedBind',
                        'jquery.getAttrs',
+                       'jquery.hidpi',
                        'jquery.highlightText',
                        'jquery.localize',
                        'jquery.mwExtension',
diff --git a/tests/qunit/suites/resources/jquery/jquery.hidpi.test.js b/tests/qunit/suites/resources/jquery/jquery.hidpi.test.js
new file mode 100644 (file)
index 0000000..cf309df
--- /dev/null
@@ -0,0 +1,20 @@
+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( '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' );
+
+       // 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' );
+});
index 068ec01..362f304 100644 (file)
--- a/thumb.php
+++ b/thumb.php
@@ -153,6 +153,13 @@ function wfStreamThumb( array $params ) {
                $img = wfLocalFile( $fileName );
        }
 
+       // Check the source file title
+       if ( !$img ) {
+               wfThumbError( 404, wfMessage( 'badtitletext' )->text() );
+               wfProfileOut( __METHOD__ );
+               return;
+       }
+
        // Check permissions if there are read restrictions
        $varyHeader = array();
        if ( !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) ) {
@@ -167,11 +174,6 @@ function wfStreamThumb( array $params ) {
        }
 
        // Check the source file storage path
-       if ( !$img ) {
-               wfThumbError( 404, wfMessage( 'badtitletext' )->text() );
-               wfProfileOut( __METHOD__ );
-               return;
-       }
        if ( !$img->exists() ) {
                wfThumbError( 404, 'The source file for the specified thumbnail does not exist.' );
                wfProfileOut( __METHOD__ );