* (bug 38904) prop=revisions&rvstart=... no longer blows up when continuing.
* (bug 39032) ApiQuery generates help in constructor.
* (bug 11142) Improve file extension blacklist error reporting in API upload.
-* (bug 39665) Cache AllowedGenerator array so it doesn't autoload all query classes
- on every request.
+* (bug 39665) List of query generators is now not built using reflection, instead it is
+ defined in code.
=== Languages updated in 1.20 ===
* (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.
* action=edit and action=parse now support contentmodel and contentformat parameters to control the interpretation of
page content; See docs/contenthandler.txt for details.
* (bug 35693) ApiQueryImageInfo now suppresses errors when unserializing metadata.
+* (bug 40111) Disable minor edit for page/section creation by API
=== Languages updated in 1.21 ===
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
$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
$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
$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
$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
$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
$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
'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',
# 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',
protected function read( $length, $pos ) {
if ( fseek( $this->handle, $pos ) == -1 ) {
// This can easily happen if the internal pointers are incorrect
- throw new MWException(
+ throw new MWException(
'Seek failed, file "' . $this->fileName . '" may be corrupted.' );
}
protected function unpack31( $s ) {
$data = unpack( 'V', $s );
if ( $data[1] > 0x7fffffff ) {
- throw new MWException(
+ throw new MWException(
'Error in CDB file "' . $this->fileName . '", integer too big.' );
}
return $data[1];
/**
* Clean up the temp file and throw an exception
- *
+ *
* @param $msg string
* @throws MWException
*/
/**
* Unified CJK blocks.
*
- * The same definition of a CJK block must be used for both Collation and
- * generateCollationData.php. These blocks are omitted from the first
- * letter data, as an optimisation measure and because the default UCA table
- * is pretty useless for sorting Chinese text anyway. Japanese and Korean
+ * The same definition of a CJK block must be used for both Collation and
+ * generateCollationData.php. These blocks are omitted from the first
+ * letter data, as an optimisation measure and because the default UCA table
+ * is pretty useless for sorting Chinese text anyway. Japanese and Korean
* blocks are not included here, because they are smaller and more useful.
*/
static $cjkBlocks = array(
function __construct( $locale ) {
if ( !extension_loaded( 'intl' ) ) {
- throw new MWException( 'An ICU collation was requested, ' .
+ throw new MWException( 'An ICU collation was requested, ' .
'but the intl extension is not available.' );
}
$this->locale = $locale;
// Check for CJK
$firstChar = mb_substr( $string, 0, 1, 'UTF-8' );
- if ( ord( $firstChar ) > 0x7f
- && self::isCjk( utf8ToCodepoint( $firstChar ) ) )
+ if ( ord( $firstChar ) > 0x7f
+ && self::isCjk( utf8ToCodepoint( $firstChar ) ) )
{
return $firstChar;
}
// Sort the letters.
//
// It's impossible to have the precompiled data file properly sorted,
- // because the sort order changes depending on ICU version. If the
- // array is not properly sorted, the binary search will return random
- // results.
+ // because the sort order changes depending on ICU version. If the
+ // array is not properly sorted, the binary search will return random
+ // results.
//
// We also take this opportunity to remove primary collisions.
$letterMap = array();
}
/**
- * Do a binary search, and return the index of the largest item that sorts
+ * Do a binary search, and return the index of the largest item that sorts
* less than or equal to the target value.
*
* @param $valueCallback array A function to call to get the value with
// We hash the random state with more salt to avoid the state from leaking
// out and being used to predict the /randomness/ that follows.
if ( strlen( $buffer ) < $bytes ) {
- wfDebug( __METHOD__ . ": Falling back to using a pseudo random state to generate randomness.\n" );
+ wfDebug( __METHOD__ . ": Falling back to using a pseudo random state to generate randomness.\n" );
}
while ( strlen( $buffer ) < $bytes ) {
wfProfileIn( __METHOD__ . '-fallback' );
*/
$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
* @{
$wgAPIMetaModules = array();
$wgAPIPropModules = array();
$wgAPIListModules = array();
+$wgAPIGeneratorModules = array();
/**
* Maximum amount of rows to scan in a DB query in the API
*/
$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
define( 'MW_SUPPORTS_EDITFILTERMERGED', 1 );
define( 'MW_SUPPORTS_PARSERFIRSTCALLINIT', 1 );
define( 'MW_SUPPORTS_LOCALISATIONCACHE', 1 );
+define( 'MW_SUPPORTS_CONTENTHANDLER', 1 );
/**@}*/
/** Support for $wgResourceModules */
$this->isCssSubpage = $this->mTitle->isCssSubpage();
$this->isJsSubpage = $this->mTitle->isJsSubpage();
$this->isWrongCaseCssJsPage = $this->isWrongCaseCssJsPage();
- $this->isNew = !$this->mTitle->exists() || $this->section == 'new';
# Show applicable editing introductions
if ( $this->formtype == 'initial' || $this->firsttime ) {
# Section edit can come from either the form or a link
$this->section = $request->getVal( 'wpSection', $request->getVal( 'section' ) );
+ $this->isNew = !$this->mTitle->exists() || $this->section == 'new';
if ( $request->wasPosted() ) {
# These fields need to be checked for encoding.
* @since 1.21
*/
public function setPreloadedContent( Content $content ) {
- $this->mPreloadedContent = $content;
+ $this->mPreloadContent = $content;
}
/**
'eu_external_id' => $this->getId() ),
__METHOD__ );
}
-
+
/**
* Check whether this external user id is already linked with
* a local user.
? User::newFromId( $row->eu_local_id )
: null;
}
-
+
}
($row->rc_deleted & Revision::DELETED_COMMENT)
? wfMessage('rev-deleted-comment')->escaped()
: $row->rc_comment,
- $actiontext
+ $actiontext
);
}
*
* @file
* @author Niklas Laxström
- * @author Antoine Musso
+ * @author Antoine Musso
*/
/**
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 );
+ }
}
if ( !$thumb ) {
$s = self::makeBrokenImageLinkObj( $title, $fp['title'], '', '', '', $time == true );
} else {
+ self::processResponsiveImages( $file, $thumb, $hp );
$params = array(
'alt' => $fp['alt'],
'title' => $fp['title'],
$hp['width'] = isset( $fp['upright'] ) ? 130 : 180;
}
$thumb = false;
+ $noscale = false;
if ( !$exists ) {
$outerWidth = $hp['width'] + 2;
} 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
$s .= wfMessage( 'thumbnail_error', '' )->escaped();
$zoomIcon = '';
} else {
+ if ( !$noscale ) {
+ self::processResponsiveImages( $file, $thumb, $hp );
+ }
$params = array(
'alt' => $fp['alt'],
'title' => $fp['title'],
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
*
// Save the old and new blobs for later
$oldBlob = $row->mr_blob;
$newBlob = self::generateMessageBlob( $module, $lang );
-
+
$newRow = array(
'mr_resource' => $name,
'mr_lang' => $lang,
/**
* Standard output handler for use with ob_start
- *
+ *
* @param $s string
- *
+ *
* @return string
*/
function wfOutputHandler( $s ) {
/**
* Handler that compresses data with gzip if allowed by the Accept header.
* Unlike ob_gzhandler, it works for HEAD requests too.
- *
+ *
* @param $s string
*
* @return string
*/
private function addDefaultModules() {
global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil, $wgUseAjax,
- $wgAjaxWatch;
+ $wgAjaxWatch, $wgResponsiveImages;
// Add base resources
$this->addModules( array(
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' );
+ }
}
/**
global $wgUseRCPatrol, $wgEnableAPI, $wgRCMaxAge;
$watchlistdaysMax = ceil( $wgRCMaxAge / ( 3600 * 24 ) );
-
+
## Watchlist #####################################
$defaultPreferences['watchlistdays'] = array(
'type' => 'float',
$this->mArticle = $article;
$this->mTitle = $article->getTitle();
$this->mApplicableTypes = $this->mTitle->getRestrictionTypes();
-
+
// Check if the form should be disabled.
// If it is, the form will be available in read-only to show levels.
$this->mPermErrors = $this->mTitle->getUserPermissionsErrors( 'protect', $wgUser );
*/
/**
- * An HTTP 1.0 client built for the purposes of purging Squid and Varnish.
- * Uses asynchronous I/O, allowing purges to be done in a highly parallel
- * manner.
+ * An HTTP 1.0 client built for the purposes of purging Squid and Varnish.
+ * Uses asynchronous I/O, allowing purges to be done in a highly parallel
+ * manner.
*
* Could be replaced by curl_multi_exec() or some such.
*/
return array( $socket );
}
- /**
+ /**
* Get the host's IP address.
* Does not support IPv6 at present due to the lack of a convenient interface in PHP.
*/
$numReady = socket_select( $readSockets, $writeSockets, $exceptSockets, $timeout );
wfRestoreWarnings();
if ( $numReady === false ) {
- wfDebugLog( 'squid', __METHOD__.': Error in stream_select: ' .
+ wfDebugLog( 'squid', __METHOD__.': Error in stream_select: ' .
socket_strerror( socket_last_error() ) . "\n" );
break;
}
/**
* An iterator which works exactly like:
- *
+ *
* foreach ( explode( $delim, $s ) as $element ) {
* ...
* }
$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;
return $ret;
}
-
/**
* Unset an arbitrary value from our get/post data.
*
$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" );
$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
$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' );
/**
* Construct a language selector appropriate for use in a form or preferences
- *
+ *
* @param string $selected The language code of the selected language
* @param boolean $customisedOnly If true only languages which have some content are listed
* @param string $inLanguage The ISO code of the language to display the select list in (optional)
# Sift for real versus user names
foreach ( $contributors as $user ) {
- $cnt--;
+ $cnt--;
if ( $user->isLoggedIn() ) {
$link = $this->link( $user );
if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) {
$lang = $this->getLanguage();
$userDate = $lang->userDate( $timestamp, $user );
$userTime = $lang->userTime( $timestamp, $user );
-
+
$this->getOutput()->addWikiMsg( 'filerevert-success', $this->getTitle()->getText(),
$userDate, $userTime,
wfExpandUrl( $this->page->getFile()->getArchiveUrl( $this->getRequest()->getText( 'oldimage' ) ),
protected function getPageTitle() {
return $this->msg( 'filerevert', $this->getTitle()->getText() );
}
-
+
protected function getDescription() {
$this->getOutput()->addBacklinkSubtitle( $this->getTitle() );
return '';
// Need to pass a throwaway variable because generateReason expects
// a reference
$hasHistory = false;
- $reason = $page->getAutoDeleteReason( $hasHistory );
+ $reason = $page->getAutoDeleteReason( $hasHistory );
if ( $reason === false ) {
return array( array( 'cannotdelete', $title->getPrefixedText() ) );
}
protected function logRequest( $time ) {
$request = $this->getRequest();
$milliseconds = $time === null ? '?' : round( $time * 1000 );
- $s = 'API' .
+ $s = 'API' .
' ' . $request->getMethod() .
' ' . wfUrlencode( str_replace( ' ', '_', $this->getUser()->getName() ) ) .
' ' . $request->getIP() .
*/
public function getCheck( $name ) {
$this->mParamsUsed[$name] = true;
- return $this->getRequest()->getCheck( $name );
+ return $this->getRequest()->getCheck( $name );
}
/**
$popts->enableLimitReport( !$params['disablepp'] );
// Potentially cached
- $p_result = $this->getParsedContent( $pageObj, $popts, $pageid,
+ $p_result = $this->getParsedContent( $pageObj, $popts, $pageid,
isset( $prop['wikitext'] ) ) ;
}
} else { // Not $oldid, $pageid, $page. Hence based on $text
private $params, $redirects, $convertTitles, $iwUrl;
+ /**
+ * List of Api Query prop modules
+ * @var array
+ */
private $mQueryPropModules = array(
'categories' => 'ApiQueryCategories',
'categoryinfo' => 'ApiQueryCategoryInfo',
'templates' => 'ApiQueryLinks',
);
+ /**
+ * List of Api Query list modules
+ * @var array
+ */
private $mQueryListModules = array(
'allcategories' => 'ApiQueryAllCategories',
'allimages' => 'ApiQueryAllImages',
'watchlistraw' => 'ApiQueryWatchlistRaw',
);
+ /**
+ * List of Api Query meta modules
+ * @var array
+ */
private $mQueryMetaModules = array(
'allmessages' => 'ApiQueryAllMessages',
'siteinfo' => 'ApiQuerySiteinfo',
'userinfo' => 'ApiQueryUserInfo',
);
+ /**
+ * List of Api Query generator modules
+ * Defined in code, rather than being derived at runtime,
+ * due to performance reasons
+ * @var array
+ */
+ private $mQueryGenerators = array(
+ 'allcategories' => 'ApiQueryAllCategories',
+ 'allimages' => 'ApiQueryAllImages',
+ 'alllinks' => 'ApiQueryAllLinks',
+ 'allpages' => 'ApiQueryAllPages',
+ 'backlinks' => 'ApiQueryBacklinks',
+ 'categories' => 'ApiQueryCategories',
+ 'categorymembers' => 'ApiQueryCategoryMembers',
+ 'duplicatefiles' => 'ApiQueryDuplicateFiles',
+ 'embeddedin' => 'ApiQueryBacklinks',
+ 'exturlusage' => 'ApiQueryExtLinksUsage',
+ 'images' => 'ApiQueryImages',
+ 'imageusage' => 'ApiQueryBacklinks',
+ 'iwbacklinks' => 'ApiQueryIWBacklinks',
+ 'langbacklinks' => 'ApiQueryLangBacklinks',
+ 'links' => 'ApiQueryLinks',
+ 'protectedtitles' => 'ApiQueryProtectedTitles',
+ 'querypage' => 'ApiQueryQueryPage',
+ 'random' => 'ApiQueryRandom',
+ 'recentchanges' => 'ApiQueryRecentChanges',
+ 'search' => 'ApiQuerySearch',
+ 'templates' => 'ApiQueryLinks',
+ 'watchlist' => 'ApiQueryWatchlist',
+ 'watchlistraw' => 'ApiQueryWatchlistRaw',
+ );
+
private $mSlaveDB = null;
private $mNamedDB = array();
- protected $mAllowedGenerators = array();
+ protected $mAllowedGenerators;
/**
* @param $main ApiMain
parent::__construct( $main, $action );
// Allow custom modules to be added in LocalSettings.php
- global $wgAPIPropModules, $wgAPIListModules, $wgAPIMetaModules,
- $wgMemc, $wgAPICacheHelpTimeout;
+ global $wgAPIPropModules, $wgAPIListModules, $wgAPIMetaModules, $wgAPIGeneratorModules;
self::appendUserModules( $this->mQueryPropModules, $wgAPIPropModules );
self::appendUserModules( $this->mQueryListModules, $wgAPIListModules );
self::appendUserModules( $this->mQueryMetaModules, $wgAPIMetaModules );
+ self::appendUserModules( $this->mQueryGenerators, $wgAPIGeneratorModules );
$this->mPropModuleNames = array_keys( $this->mQueryPropModules );
$this->mListModuleNames = array_keys( $this->mQueryListModules );
$this->mMetaModuleNames = array_keys( $this->mQueryMetaModules );
-
- // Get array of query generators from cache if present
- $key = wfMemcKey( 'apiquerygenerators', SpecialVersion::getVersion( 'nodb' ) );
-
- if ( $wgAPICacheHelpTimeout > 0 ) {
- $cached = $wgMemc->get( $key );
- if ( $cached ) {
- $this->mAllowedGenerators = $cached;
- return;
- }
- }
- $this->makeGeneratorList( $this->mQueryPropModules );
- $this->makeGeneratorList( $this->mQueryListModules );
-
- if ( $wgAPICacheHelpTimeout > 0 ) {
- $wgMemc->set( $key, $this->mAllowedGenerators, $wgAPICacheHelpTimeout );
- }
+ $this->mAllowedGenerators = array_keys( $this->mQueryGenerators );
}
/**
* Get the array mapping module names to class names
* @return array array(modulename => classname)
*/
- function getModules() {
+ public function getModules() {
return array_merge( $this->mQueryPropModules, $this->mQueryListModules, $this->mQueryMetaModules );
}
+ /**
+ * Get the generators array mapping module names to class names
+ * @return array array(modulename => classname)
+ */
+ public function getGenerators() {
+ return $this->mQueryGenerators;
+ }
+
/**
* Get whether the specified module is a prop, list or a meta query module
* @param $moduleName string Name of the module to find type for
return implode( "\n", $moduleDescriptions );
}
- /**
- * Adds any classes that are a subclass of ApiQueryGeneratorBase
- * to the allowed generator list
- * @param $moduleList array()
- */
- private function makeGeneratorList( $moduleList ) {
- foreach( $moduleList as $moduleName => $moduleClass ) {
- if ( is_subclass_of( $moduleClass, 'ApiQueryGeneratorBase' ) ) {
- $this->mAllowedGenerators[] = $moduleName;
- }
- }
- }
-
/**
* Override to add extra parameters from PageSet
* @return string
} else {
$this->addWhereRange( 'cat_pages', 'older', $max, $min);
}
-
if ( isset( $params['prefix'] ) ) {
$this->addWhere( 'cat_title' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
public function incrMissesRecent( WebRequest $request ) {
global $wgMemc;
if ( mt_rand( 0, self::MISS_FACTOR - 1 ) == 0 ) {
- # Get a large IP range that should include the user even if that
+ # Get a large IP range that should include the user even if that
# person's IP address changes
$ip = $request->getIP();
if ( !IP::isValid( $ip ) ) {
static function expand( $url ) {
return wfExpandUrl( $url, PROTO_INTERNAL );
}
-
+
/**
* Find the HTCP routing rule to use for a given URL.
* @param $url string URL to match
}
return false;
}
-
}
*
* @param $name
* @param $value
- *
+ *
* @return bool
*/
protected function writeSetting( $name, $value ) {
$args = func_get_args();
return call_user_func_array( array( $this->getContext(), 'msg' ), $args );
}
-
}
-
public function getSkin() {
if ( $this->skin === null ) {
wfProfileIn( __METHOD__ . '-createskin' );
-
+
$skin = null;
wfRunHooks( 'RequestContextCreateSkin', array( $this, &$skin ) );
}
}
-
* Clone the table structure
*/
public function cloneTableStructure() {
-
foreach( $this->tablesToClone as $tbl ) {
# Clean up from previous aborted run. So that table escaping
# works correctly across DB engines, we need to change the pre-
# fix back and forth so tableName() works right.
-
+
self::changePrefix( $this->oldTablePrefix );
$oldTableName = $this->db->tableName( $tbl, 'raw' );
-
+
self::changePrefix( $this->newTablePrefix );
$newTableName = $this->db->tableName( $tbl, 'raw' );
-
+
if( $this->dropCurrentTables && !in_array( $this->db->getType(), array( 'postgres', 'oracle' ) ) ) {
$this->db->dropTable( $tbl, __METHOD__ );
wfDebug( __METHOD__." dropping {$newTableName}\n", true);
# Create new table
wfDebug( __METHOD__." duplicating $oldTableName to $newTableName\n", true );
$this->db->duplicateTableStructure( $oldTableName, $newTableName, $this->useTemporaryTables );
-
}
-
}
/**
*/
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
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
*/
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
$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;
}
/**
*/
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;
}
/**
* @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;
}
-
+
/**
* Get API parameters for the fields supported by this object.
*
}
/**
- * Get the database type used for read operations.
+ * Get the database ID used for read operations.
*
* @since 1.20
*
}
/**
- * 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
*
$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
* @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;
}
/**
* @param array $conditions
*/
public function updateSummaryFields( $summaryFields = null, array $conditions = array() ) {
+ $slave = $this->getReadDb();
$this->setReadDb( DB_MASTER );
/**
$item->save();
}
- $this->setReadDb( DB_SLAVE );
+ $this->setReadDb( $slave );
}
/**
array( 'modifyField', 'user_properties', 'up_property', 'patch-up_property.sql' ),
array( 'addTable', 'uploadstash', 'patch-uploadstash.sql' ),
array( 'addTable', 'user_former_groups', 'patch-user_former_groups.sql'),
- array( 'doRebuildLocalisationCache' ),
+ array( 'doRebuildLocalisationCache' ),
// 1.19
array( 'addIndex', 'logging', 'type_action', 'patch-logging-type-action-index.sql'),
array( 'modifyField', 'user_groups', 'ug_group', 'patch-ug_group-length-increase.sql' ),
array( 'addField', 'uploadstash', 'us_chunk_inx', 'patch-uploadstash_chunk.sql' ),
array( 'addfield', 'job', 'job_timestamp', 'patch-jobs-add-timestamp.sql' ),
-
array( 'modifyField', 'user_former_groups', 'ufg_group', 'patch-ufg_group-length-increase.sql' ),
// 1.20
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' ),
);
}
protected $internalDefaults = array(
'_OracleDefTS' => 'USERS',
'_OracleTempTS' => 'TEMP',
- '_InstallUser' => 'SYSDBA',
+ '_InstallUser' => 'SYSTEM',
);
public $minimumVersion = '9.0.1'; // 9iR1
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' ),
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' ),
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'"),
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' ),
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 ''" ),
array( 'modifyField', 'user_groups', 'ug_group', 'patch-ug_group-length-increase.sql' ),
array( 'addField', 'uploadstash', 'us_chunk_inx', 'patch-uploadstash_chunk.sql' ),
array( 'addfield', 'job', 'job_timestamp', 'patch-jobs-add-timestamp.sql' ),
-
array( 'modifyField', 'user_former_groups', 'ufg_group', 'patch-ug_group-length-increase.sql' ),
// 1.20
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' ),
);
}
/**
* Constructor.
- *
+ *
* @since 1.19
- *
+ *
* @param string $type
* @param string $subtype
*/
* '4:color' => 'blue',
* 'animal' => 'dog'
* );
- *
+ *
* @since 1.19
- *
+ *
* @param $parameters array Associative array
*/
public function setParameters( $parameters ) {
/**
* Set the user that performed the action being logged.
- *
+ *
* @since 1.19
- *
+ *
* @param User $performer
*/
public function setPerformer( User $performer ) {
/**
* Set the title of the object changed.
- *
+ *
* @since 1.19
- *
+ *
* @param Title $target
*/
public function setTarget( Title $target ) {
/**
* Set the timestamp of when the logged action took place.
- *
+ *
* @since 1.19
- *
+ *
* @param string $timestamp
*/
public function setTimestamp( $timestamp ) {
/**
* Set a comment associated with the action being logged.
- *
+ *
* @since 1.19
- *
+ *
* @param string $comment
*/
public function setComment( $comment ) {
/**
* TODO: document
- *
+ *
* @since 1.19
- *
+ *
* @param integer $deleted
*/
public function setDeleted( $deleted ) {
}
/**
- * Generate text for a log entry.
+ * Generate text for a log entry.
* Only LogFormatter should call this function.
*
* @param $type String: log type
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;
/**
'alt' => $alt,
'src' => $this->url,
'width' => $this->width,
- 'height' => $this->height,
+ 'height' => $this->height
);
if ( !empty( $options['valign'] ) ) {
$attribs['style'] = "vertical-align: {$options['valign']}";
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 ) );
}
$linked = true;
if ( isset( $this->mLinked ) )
$linked = $this->mLinked;
-
+
$bits = array();
$key = $this->keys[$this->mSource];
for ( $p=0; $p < strlen($key); $p++ ) {
*/
function formatDate( $bits, $link = true ) {
$format = $this->targets[$this->mTarget];
-
+
if (!$link) {
// strip piped links
$format = preg_replace( '/\[\[[^|]+\|([^\]]+)\]\]/', '$1', $format );
/**
* Don't serialize the parent object, it is big, and not needed when it is
- * a parameter to mergeForeign(), which is the only application of
+ * a parameter to mergeForeign(), which is the only application of
* serializing at present.
*
* Compact the titles, only serialize the text form.
}
/**
- * Merge a LinkHolderArray from another parser instance into this one. The
- * keys will not be preserved. Any text which went with the old
- * LinkHolderArray and needs to work with the new one should be passed in
+ * Merge a LinkHolderArray from another parser instance into this one. The
+ * keys will not be preserved. Any text which went with the old
+ * LinkHolderArray and needs to work with the new one should be passed in
* the $texts array. The strings in this array will have their link holders
* converted for use in the destination link holder. The resulting array of
* strings will be returned.
$maxId = $newKey > $maxId ? $newKey : $maxId;
}
}
- $texts = preg_replace_callback( '/(<!--LINK \d+:)(\d+)(-->)/',
+ $texts = preg_replace_callback( '/(<!--LINK \d+:)(\d+)(-->)/',
array( $this, 'mergeForeignCallback' ), $texts );
# Renumber interwiki links
$this->interwikis[$newKey] = $entry;
$maxId = $newKey > $maxId ? $newKey : $maxId;
}
- $texts = preg_replace_callback( '/(<!--IWLINK )(\d+)(-->)/',
+ $texts = preg_replace_callback( '/(<!--IWLINK )(\d+)(-->)/',
array( $this, 'mergeForeignCallback' ), $texts );
# Set the parent link ID to be beyond the highest used ID
# Internal links
$pos = 0;
while ( $pos < strlen( $text ) ) {
- if ( !preg_match( '/<!--LINK (\d+):(\d+)-->/',
- $text, $m, PREG_OFFSET_CAPTURE, $pos ) )
+ if ( !preg_match( '/<!--LINK (\d+):(\d+)-->/',
+ $text, $m, PREG_OFFSET_CAPTURE, $pos ) )
{
break;
}
wfDebug( "ParserOutput cache found.\n" );
- // The edit section preference may not be the appropiate one in
- // the ParserOutput, as we are not storing it in the parsercache
+ // The edit section preference may not be the appropiate one in
+ // the ParserOutput, as we are not storing it in the parsercache
// key. Force it here. See bug 31445.
$value->setEditSectionTokens( $popts->getEditSection() );
* @ingroup Parser
*/
class ParserOptions {
-
+
/**
* Use DateFormatter to format dates
*/
var $mUseDynamicDates;
-
+
/**
* Interlanguage links are removed and returned in an array
*/
var $mInterwikiMagic;
-
+
/**
* Allow external images inline?
*/
var $mAllowExternalImages;
-
+
/**
* If not, any exception?
*/
var $mAllowExternalImagesFrom;
-
+
/**
* If not or it doesn't match, should we check an on-wiki whitelist?
*/
var $mEnableImageWhitelist;
-
+
/**
* Date format index
*/
var $mDateFormat = null;
-
+
/**
* Create "edit section" links?
*/
var $mEditSection = true;
-
+
/**
* Allow inclusion of special pages?
*/
var $mAllowSpecialInclusion;
-
+
/**
* Use tidy to cleanup output HTML?
*/
var $mTidy = false;
-
+
/**
* Which lang to call for PLURAL and GRAMMAR
*/
var $mInterfaceMessage = false;
-
+
/**
* Overrides $mInterfaceMessage with arbitrary language
*/
var $mTargetLanguage = null;
-
+
/**
* Maximum size of template expansions, in bytes
*/
var $mMaxIncludeSize;
-
+
/**
* Maximum number of nodes touched by PPFrame::expand()
*/
* Maximum number of nodes generated by Preprocessor::preprocessToObj()
*/
var $mMaxGeneratedPPNodeCount;
-
+
/**
* Maximum recursion depth in PPFrame::expand()
*/
var $mMaxPPExpandDepth;
-
+
/**
* Maximum recursion depth for templates within templates
*/
var $mMaxTemplateDepth;
-
+
/**
* Maximum number of calls per parse to expensive parser functions
*/
var $mExpensiveParserFunctionLimit;
-
+
/**
* Remove HTML comments. ONLY APPLIES TO PREPROCESS OPERATIONS
*/
var $mRemoveComments = true;
-
+
/**
* Callback for template fetching. Used as first argument to call_user_func().
*/
var $mTemplateCallback =
array( 'Parser', 'statelessFetchTemplate' );
-
+
/**
* Enable limit report in an HTML comment on output
*/
var $mEnableLimitReport = false;
-
+
/**
* Timestamp used for {{CURRENTDAY}} etc.
*/
var $mTimestamp;
-
+
/**
* Target attribute for external links
*/
var $mExternalLinkTarget;
-
+
/**
- * Clean up signature texts?
+ * Clean up signature texts?
*
* 1) Strip ~~~, ~~~~ and ~~~~~ out of signatures
* 2) Substitute all transclusions
*/
var $mCleanSignatures;
-
+
/**
* Transform wiki markup when saving the page?
*/
* Automatically number headings?
*/
var $mNumberHeadings;
-
+
/**
* User math preference (as integer). Not used (1.19)
*/
var $mMath;
-
+
/**
* Thumb size preferred by the user.
*/
var $mThumbSize;
-
+
/**
* Maximum article size of an article to be marked as "stub"
*/
private $mStubThreshold;
-
+
/**
* Language object of the User language.
*/
var $mUserLang;
/**
- * @var User
+ * @var User
* Stored user object
*/
var $mUser;
-
+
/**
* Parsing the page for a "preview" operation?
*/
var $mIsPreview = false;
-
+
/**
* Parsing the page for a "preview" operation on a single section?
*/
var $mIsSectionPreview = false;
-
+
/**
* Parsing the printable version of the page?
*/
return new ParserOptions( $context->getUser(), $context->getLanguage() );
}
- /**
- * Get user options
+ /**
+ * Get user options
*
* @param $user User object
* @param $lang Language object
* can automatically discard old data.
*/
const VERSION = '1.6.4';
-
+
# Flags for Parser::setLinkHook
# Also available as global constants from Defines.php
const SLH_PATTERN = 1;
$this->mLinkHooks[$ns] = array( $callback, $flags );
return $oldVal;
}
-
+
/**
* Get all registered link hook identifiers
*
}
$holders = new LinkHolderArray( $this );
-
+
if( is_null( $this->mTitle ) ) {
wfProfileOut( __METHOD__ );
wfProfileOut( __METHOD__.'-setup' );
}
wfProfileOut( __METHOD__.'-setup' );
-
+
$offset = 0;
$offsetStack = array();
$markers = new LinkMarkerReplacer( $this, $holders, array( &$this, 'replaceInternalLinksCallback' ) );
$startBracketOffset = array_pop($offsetStack);
# Just to clean up the code, lets place offsets on the outer ends
$endBracketOffset += 2;
-
+
# Only do logic if we actually have a opening bracket for this
if( isset($startBracketOffset) ) {
# Extract text inside the link
# ToDO: Some LinkHooks use patterns rather than namespaces
# these need to be tested at this point here
}
-
}
# Bump our offset to after our current bracket
$offset = $bracketOffset+2;
}
-
-
+
# Now expand our tree
wfProfileIn( __METHOD__.'-expand' );
$s = $markers->expand( $s );
wfProfileOut( __METHOD__.'-expand' );
-
+
wfProfileOut( __METHOD__ );
return $holders;
}
-
+
function replaceInternalLinksCallback( $parser, $holders, $markers, $titleText, $paramText ) {
wfProfileIn( __METHOD__ );
$wt = isset($paramText) ? "[[$titleText|$paramText]]" : "[[$titleText]]";
wfProfileOut( __METHOD__ );
return $wt;
}
-
+
# Make subpage if necessary
if( $this->areSubpagesAllowed() ) {
$titleText = $this->maybeDoSubpageLink( $titleText, $paramText );
}
-
+
# Check for a leading colon and strip it if it is there
$leadingColon = $titleText[0] == ':';
if( $leadingColon ) $titleText = substr( $titleText, 1 );
-
+
wfProfileOut( __METHOD__."-misc" );
# Make title object
wfProfileIn( __METHOD__."-title" );
}
$ns = $title->getNamespace();
wfProfileOut( __METHOD__."-title" );
-
+
# Default for Namespaces is a default link
# ToDo: Default for patterns is plain wikitext
$return = true;
}
if( $return === true ) {
# True (treat as plain link) was returned, call the defaultLinkHook
- $return = CoreLinkFunctions::defaultLinkHook( $parser, $holders, $markers, $title,
+ $return = CoreLinkFunctions::defaultLinkHook( $parser, $holders, $markers, $title,
$titleText, $paramText, $leadingColon );
}
if( $return === false ) {
wfProfileOut( __METHOD__ );
return $return;
}
-
+
}
class LinkMarkerReplacer {
-
+
protected $markers, $nextId, $parser, $holders, $callback;
-
+
function __construct( $parser, $holders, $callback ) {
$this->nextId = 0;
$this->markers = array();
$this->holders = $holders;
$this->callback = $callback;
}
-
+
function addMarker($titleText, $paramText) {
$id = $this->nextId++;
$this->markers[$id] = array( $titleText, $paramText );
return "<!-- LINKMARKER $id -->";
}
-
+
function findMarker( $string ) {
return (bool) preg_match('/<!-- LINKMARKER [0-9]+ -->/', $string );
}
-
+
function expand( $string ) {
return StringUtils::delimiterReplaceCallback( "<!-- LINKMARKER ", " -->", array( &$this, 'callback' ), $string );
}
-
+
function callback( $m ) {
$id = intval($m[1]);
if( !array_key_exists($id, $this->markers) ) return $m[0];
array_unshift( $args, $this->parser );
return call_user_func_array( $this->callback, $args );
}
-
}
}
// Fail if the number of elements exceeds acceptable limits
- // Do not attempt to generate the DOM
+ // Do not attempt to generate the DOM
$this->parser->mGeneratedPPNodeCount += substr_count( $xml, '<' );
$max = $this->parser->mOptions->getMaxGeneratedPPNodeCount();
if ( $this->parser->mGeneratedPPNodeCount > $max ) {
* @return mixed
*/
protected function unstripType( $type, $text ) {
- // Shortcut
+ // Shortcut
if ( !count( $this->data[$type] ) ) {
return $text;
}
. '</span>';
}
if ( $this->recursionLevel >= self::UNSTRIP_RECURSION_LIMIT ) {
- return '<span class="error">' .
+ return '<span class="error">' .
wfMessage( 'parser-unstrip-recursion-limit' )
->numParams( self::UNSTRIP_RECURSION_LIMIT )->inContentLanguage()->text() .
'</span>';
}
/**
- * Get a StripState object which is sufficient to unstrip the given text.
+ * Get a StripState object which is sufficient to unstrip the given text.
* It will contain the minimum subset of strip items necessary.
*
* @param $text string
--- /dev/null
+<?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;
+ }
+
+}
--- /dev/null
+<?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
--- /dev/null
+<?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;
+ }
+
+}
--- /dev/null
+<?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
--- /dev/null
+<?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 );
+ }
+
+}
--- /dev/null
+<?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 ) );
+ }
+
+}
--- /dev/null
+<?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
$name = str_replace( ' ', '_', $user->getName() );
$lb->add( NS_USER, $name );
$lb->add( NS_USER_TALK, $name );
- }
+ }
$lb->execute();
wfProfileOut( __METHOD__ );
} else {
$pageSet = array(); // Inverted index of all pages to look up
-
+
// Split up and normalize input
foreach( explode( "\n", $page ) as $pageName ) {
$pageName = trim( $pageName );
$exists['normalizedFile']->getTitle()->getPrefixedText() )->parse();
} elseif ( $exists['warning'] == 'thumb' ) {
// Swapped argument order compared with other messages for backwards compatibility
- $warning = wfMessage( 'fileexists-thumbnail-yes',
+ $warning = wfMessage( 'fileexists-thumbnail-yes',
$exists['thumbFile']->getTitle()->getPrefixedText(), $filename )->parse();
} elseif ( $exists['warning'] == 'thumb-name' ) {
// Image w/o '180px-' does not exists, but we do not like these filenames
// now we should construct a File, so we can get mime and other such info in a standard way
// n.b. mimetype may be different from original (ogx original -> jpeg thumb)
- $thumbFile = new UnregisteredLocalFile( false,
+ $thumbFile = new UnregisteredLocalFile( false,
$this->stash->repo, $thumbnailImage->getStoragePath(), false );
if ( !$thumbFile ) {
throw new UploadStashFileNotFoundException( "couldn't create local file object for thumbnail" );
$catMessage = $this->msg( 'broken-file-category' )
->title( Title::newFromText( "Wanted Files", NS_MAIN ) )
->inContentLanguage();
-
+
if ( !$catMessage->isDisabled() ) {
$category = Title::makeTitleSafe( NS_CATEGORY, $catMessage->text() );
} else {
* @ingroup SpecialPage
*/
class WantedPagesPage extends WantedQueryPage {
-
+
function __construct( $name = 'Wantedpages' ) {
parent::__construct( $name );
}
* @return array
*/
public function verifyUpload() {
- # Check for a post_max_size or upload_max_size overflow, so that a
+ # Check for a post_max_size or upload_max_size overflow, so that a
# proper error can be shown to the user
if ( is_null( $this->mTempPath ) || $this->isEmptyFile() ) {
if ( $this->mUpload->isIniSizeOverflow() ) {
- return array(
+ return array(
'status' => UploadBase::FILE_TOO_LARGE,
- 'max' => min(
- self::getMaxUploadSize( $this->getSourceType() ),
- wfShorthandToInteger( ini_get( 'upload_max_filesize' ) ),
+ 'max' => min(
+ self::getMaxUploadSize( $this->getSourceType() ),
+ wfShorthandToInteger( ini_get( 'upload_max_filesize' ) ),
wfShorthandToInteger( ini_get( 'post_max_size' ) )
),
);
}
}
-
+
return parent::verifyUpload();
}
}
* @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 ) {
array(),
$ml );
- $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+ $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
}
/**
$flags = array();
$this->mConverter = new IuConverter( $this, 'iu', $variants, $variantfallbacks, $flags );
- $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+ $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
}
}
$this->mConverter = new KkConverter( $this, 'kk', $variants, $variantfallbacks );
- $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+ $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
}
/**
);
$this->mConverter = new KuConverter( $this, 'ku', $variants, $variantfallbacks );
- $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+ $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
}
}
$flags = array();
$this->mConverter = new ShiConverter( $this, 'shi', $variants, $variantfallbacks, $flags );
- $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+ $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
}
}
'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;
}
/**
);
$this->mConverter = new UzConverter( $this, 'uz', $variants, $variantfallbacks );
- $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+ $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
}
}
array(),
$ml );
- $wgHooks['ArticleContentSaveComplete'][] = $this->mConverter;
+ $wgHooks['PageContentSaveComplete'][] = $this->mConverter;
}
/**
'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' => '(ܫܘܠܡܐ)',
'rows' => 'ܨ̈ܦܐ',
'columns' => 'ܥܡܘܕ̈ܐ:',
'searchresultshead' => 'ܒܨܝ',
-'resultsperpage' => 'Ü¡Ü¢Ü\9dÜ¢Ü\90 Ü\95Ü¦Ü Ü\9bÌ\88Ü\90 Ü\92Ü\95ܦܐ:',
+'resultsperpage' => 'Ü¡Ü¢Ü\9dÜ¢Ü\90 Ü\95Ü¦Ü Ü\9bÌ\88Ü\90 Ü\92ܦÜ\90ܬܐ:',
'recentchangesdays' => 'ܝܘܡܬ̈ܐ ܠܚܙܝܐ ܒܫܘܚܠܦ̈ܐ ܚܕ̈ܬܐ:',
'recentchangescount' => 'ܡܢܝܢܐ ܕܫܘܚܠܦ̈ܐ ܠܚܙܝܐ ܪܫܐܝܬ:',
'savedprefs' => 'ܨܒܝܢܝܘܬ̈ܟ ܐܬܠܒܟܘ.',
'action-createaccount' => 'ܒܪܝܬܐ ܕܚܘܫܒܢܐ ܕܗܢܐ ܡܦܠܚܢܐ',
'action-minoredit' => 'ܫܘܕܥܬܐ ܥܠ ܫܘܚܠܦܐ ܗܢܐ ܐܝܟ ܙܥܘܪܐ',
'action-move' => 'ܫܢܝܬܐ ܕܦܐܬܐ ܗܕܐ',
-'action-move-rootuserpages' => 'Ü«Ü¢Ü\9dܬÜ\90 Ü\95Ü\95Ì\88ܦÜ\90 ܫܪÌ\88Ü«Ü\9dܐ ܕܡܦܠܚܢܐ',
+'action-move-rootuserpages' => 'Ü«Ü¢Ü\9dܬÜ\90 Ü\95ܦÜ\90ܬܬÌ\88Ü\90 ܫܪÌ\88Ü«Ü\9dܬܐ ܕܡܦܠܚܢܐ',
'action-movefile' => 'ܫܢܝܬܐ ܕܗܢܐ ܠܦܦܐ',
'action-upload' => 'ܐܣܩܬܐ ܕܗܢܐ ܠܦܦܐ',
'action-delete' => 'ܫܝܦܬܐ ܕܦܐܬܐ ܗܕܐ',
'minlength1' => 'ܫܡܗ̈ܐ ܕܠܦܦܐ ܘܠܐ ܕܢܗܘܐ ܒܪܝܐ ܡܢ ܐܬܘܬܐ ܚܕܐ ܟܕ ܙܥܘܪ',
'uploadwarning' => 'ܐܣܩ ܙܘܗܪܐ',
'savefile' => 'ܠܒܘܟ ܠܦܦܐ',
-'uploadedimage' => '',
+'uploadedimage' => 'ܐܣܩ "[[$1]]"',
'uploadvirus' => 'ܠܦܦܐ ܐܝܬ ܒܗ ܒܝܪܘܣ!
ܐܪ̈ܝܟܬܐ: $1',
'upload-source' => 'ܡܒܘܥܐ ܕܠܦܦܐ',
ܗܫܐ ܐܝܬܝܗܝ ܨܘܝܒܐ ܠ [[$2]].',
'brokenredirects' => 'ܨܘܝܒ̈ܐ ܬܒܝܪ̈ܐ',
-'brokenredirectstext' => 'ܨÜ\98Ì\88Ü\9dÜ\92Ü\90 Ü\97Ü Ü\9dÜ¢ Ü¡Ü\9bÜ\9dÜ¢ Ü Ü\95Ì\88ܦÜ\90 Ü\95Ü Ü\9dÜ¬Ü Ü\97Ü\98ܢ ܐܝܬܘܬܐ:',
+'brokenredirectstext' => 'ܨÜ\98Ì\88Ü\9dÜ\92Ü\90 Ü\97Ü Ü\9dÜ¢ Ü¡Ü\9bÜ\9dÜ¢ Ü Ü¦Ü\90ܬܬÌ\88Ü\90 Ü\95Ü Ü\9dÜ¬Ü Ü\97Ü\9dܢ ܐܝܬܘܬܐ:',
'brokenredirects-edit' => 'ܫܚܠܦ',
'brokenredirects-delete' => 'ܫܘܦ',
'tooltip-pt-mytalk' => 'ܦܐܬܐ ܕܡܡܠܘܟ',
'tooltip-pt-preferences' => 'Your preferences',
'tooltip-pt-watchlist' => 'ܡܟܬܒܢܘܬܐ ܕܦܐܬܬ̈ܐ ܕܒܪܗܝܬ ܐܢܬ ܫܘܚܠܦ̈ܐ ܕܬܗܘܐ ܒܗܘܢ',
-'tooltip-pt-mycontris' => 'ܡܟܬܒܢܘܬܐ ܕܫܘܬܦܘܝܬܘ̈ܟ',
+'tooltip-pt-mycontris' => 'ܡܟܬܒܢܘܬܐ ܕܫܘܬܦܘܝܬ̈ܟ',
'tooltip-pt-login' => 'ܢܠܒܒ ܠܟ ܕܣܓܠ ܐܢܬ ܥܠܠܐ ܕܝܠܟ، ܐܠܐ ܗܢܐ ܠܐ ܐܝܬܝܗܝ ܐܠܨܝܐ',
'tooltip-pt-logout' => 'ܦܠܛܐ',
'tooltip-ca-talk' => 'ܡܡܠܠܐ ܥܠ ܚܒܝܫܬܐ ܕܦܐܬܐ',
'tooltip-search' => 'ܒܨܝ ܒܓܘ {{SITENAME}}',
'tooltip-search-fulltext' => 'ܒܨܝ ܒܓܘ ܦܐܬܬ̈ܐ ܥܠ ܗܢܐ ܟܬܝܒܬܐ',
'tooltip-p-logo' => 'ܦܐܬܐ ܪܝܫܝܬܐ',
-'tooltip-n-mainpage' => 'ܬܪÜ\98ܩܬÜ\90 Ü\95ܦܐܬܐ ܪܝܫܝܬܐ',
+'tooltip-n-mainpage' => 'ܣܥܪ ܦܐܬܐ ܪܝܫܝܬܐ',
'tooltip-n-mainpage-description' => 'ܬܪܘܩܬܐ ܕܦܐܬܐ ܪܝܫܝܬܐ',
'tooltip-n-portal' => 'ܚܕܪ ܬܪܡܝܬܐ، ܡܢܐ ܡܫܟܚ ܐܢܬ ܠܥܒܕܐ، ܐܝܟܐ ܬܚܙܝ ܟܠ ܡܐ ܕܣܢܝܩ ܐܢܬ ܠܗ',
'tooltip-n-recentchanges' => 'ܡܟܬܒܢܘܬܐ ܒܫܘܚܠܦ̈ܐ ܚܕ̈ܬܐ ܒܓܘ ܘܝܩܝ.',
'tooltip-ca-nstab-main' => 'ܚܘܝ ܦܐܬܬܐ ܕܚܒ̈ܝܫܬܐ',
'tooltip-ca-nstab-user' => 'ܚܘܝ ܦܐܬܐ ܕܡܦܠܚܢܐ',
'tooltip-ca-nstab-image' => 'ܚܘܝ ܦܐܬܐ ܕܠܦܦܐ',
-'tooltip-ca-nstab-category' => 'ܚܘܝ ܦܐܬܐ ܕܣܕܪ̈ܐ',
+'tooltip-ca-nstab-category' => 'ܚܘܝ ܦܐܬܐ ܕܣܕܪܐ',
'tooltip-save' => 'ܠܒܘܟ ܫܘܚܠܦܟ',
-'tooltip-watch' => 'Ü\90Ü\98ܣܦ Ü\97Ü¢Ü\90 ܦÜ\90ܬÜ\90 Ü Ü¡Ü\9fܬÜ\92Ü¢Ü\98ܬÜ\90 Ü\95ܪÜ\97Ü\9dܬÜ\98ܟ',
+'tooltip-watch' => 'Ü\90Ü\98ܣܦ ܦÜ\90ܬÜ\90 Ü\97Ü\95Ü\90 Ü Ü¡Ü\9fܬÜ\92Ü¢Ü\98ܬÜ\90 Ü\95ܪÌ\88Ü\97Ü\9dܬܟ',
# Attribution
'anonymous' => '{{PLURAL:$1|ܡܦܠܚܢܐ ܠܐ ܝܕܝܥܐ|ܡܦܠܚܢ̈ܐ ܠܐ ܝܕ̈ܝܥܐ}} ܕ {{SITENAME}}',
'vector-action-protect' => 'Protexer',
'vector-action-undelete' => 'Restaurar',
'vector-action-unprotect' => 'Camudar la proteición',
-'vector-simplesearch-preference' => 'Activar suxerencies meyoraes de gueta (namái apariencia Vector)',
+'vector-simplesearch-preference' => 'Activar la barra de gueta simplificada (namái apariencia Vector)',
'vector-view-create' => 'Crear',
'vector-view-edit' => 'Editar',
'vector-view-history' => 'Ver historial',
'protectedpagetext' => 'Esta páxina ta candada pa torgar la so edición.',
'viewsourcetext' => "Pues ver y copiar la fonte d'esta páxina:",
'viewyourtext' => "Pues ver y copiar la fonte de '''les tos ediciones''' d'esta páxina:",
-'protectedinterface' => "Esta páxina proporciona testu d'interfaz de l'aplicación, y ta candada pa torgar abusos.",
-'editinginterface' => "'''Avisu:''' Tas editando una páxina que s'usa pa proporcionar el testu d'interfaz de l'aplicación.
-Los cambeos nesta páxina van afeutar l'apariencia de la interfaz pa otros usuarios.
-Si quies facer traducciones, por favor usa [//translatewiki.net/wiki/Main_Page?setlang=ast translatewiki.net], el proyeutu de traducción de MediaWiki.",
+'protectedinterface' => "Esta páxina proporciona'l testu de la interfaz del software d'esta wiki, y ta candada pa torgar abusos.
+P'amestar o cambiar les traducciones de toles wikis, por favor usa [//translatewiki.net/translatewiki.net], el proyeutu de llocalización de MediaWiki.",
+'editinginterface' => "'''Avisu:''' Tas editando una páxina que s'usa pa proporcionar el testu d'interfaz del programa.
+Los cambeos nesta páxina van afeutar l'apariencia de la interfaz pa otros usuarios d'esta wiki.
+P'amestar o camudar traducciones pa toles wikis, por favor, usa [//translatewiki.net/ translatewiki.net], el proyeutu de traducción de MediaWiki.",
'sqlhidden' => '(consulta SQL anubrida)',
'cascadeprotected' => "Esta páxina ta protexida d'ediciones porque ta enxerta {{PLURAL:$1|na siguiente páxina|nes siguientes páxines}}, que {{PLURAL:$1|ta protexida|tán protexíes}} cola opción «en cascada» activada:
$2",
<span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} guetar los rexistros rellacionaos],
o [{{fullurl:{{FULLPAGENAME}}|action=edit}} editar esta páxina equí]</span>.',
'noarticletext-nopermission' => 'Nestos momentos nun hai testu nesta páxina.
-Pues [[Special:Search/{{PAGENAME}}|guetar esti títulu de páxina]] n\'otres páxines,
-o <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} guetar los rexistros rellacionaos]</span>.',
+Pues [[Special:Search/{{PAGENAME}}|guetar esti títulu de páxina]] n\'otres páxines o <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} guetar los rexistros rellacionaos]</span>, pero nun tienes permisu pa crear esta páxina.',
'missing-revision' => 'La revisión #$1 de la páxina llamada "{{PAGENAME}}" nun esiste.
De vezu la causa d\'esto ye siguir un enllaz antiguu del historial a una páxina que se desanició.
'edit-already-exists' => 'Nun se pudo crear una páxina nueva.
Yá esiste.',
'defaultmessagetext' => 'Testu predetermináu',
+'content-failed-to-parse' => 'Fallu al analizar el conteníu $2 pal modelu $1: $3',
+'invalid-content-data' => 'Datos del conteníu inválidos',
+'content-not-allowed-here' => 'El conteníu «$1» nun se permite na páxina [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'testu wiki',
+'content-model-text' => 'testu simple',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
# Parser/template warnings
'expensive-parserfunction-warning' => "'''Avisu:''' Esta páxina contién demasiaes llamaes costoses a funciones d'análisis sintáuticu.
'timezoneregion-indian' => 'Océanu Índicu',
'timezoneregion-pacific' => 'Océanu Pacíficu',
'allowemail' => 'Dexar a los otros usuarios mandate correos',
-'prefs-searchoptions' => 'Opciones de busca',
+'prefs-searchoptions' => 'Guetar',
'prefs-namespaces' => 'Espacios de nome',
'defaultns' => "D'otra miente, guetar nestos espacios de nome:",
'default' => 'predetermináu',
'backend-fail-internal' => 'Hebo un fallu desconocíu nel motor d\'almacenamientu "$1".',
'backend-fail-contenttype' => 'Non se pudo determinar la triba de conteníu de ficheru a guardar en "$1".',
'backend-fail-batchsize' => "El motor d'almacenamientu dio un llote de $1 {{PLURAL:$1|operación|operaciones}} en ficheros; el llímite ye de $2 {{PLURAL:$2|operación|operaciones}}.",
-'backend-fail-usable' => 'Nun se pudo escribir el ficheru $1 porque nun hai permisos bastantes o falten los direutorios/contenedores.',
+'backend-fail-usable' => 'Nun se pudo llee o escribir el ficheru «$1» porque nun hai permisos bastantes o falten los direutorios/contenedores.',
# File journal errors
'filejournal-fail-dbconnect' => 'Nun se pudo coneutar cola base de datos del diariu pal sofitu d\'almacenamientu "$1".',
'undeletedrevisions' => '{{PLURAL:$1|1 revisión restaurada|$1 revisiones restauraes}}',
'undeletedrevisions-files' => '{{PLURAL:$1|1 revisión|$1 revisiones}} y {{PLURAL:$2|1 archivu|$2 archivos}} restauraos',
'undeletedfiles' => '{{PLURAL:$1|1 archivu restauráu|$1 archivos restauraos}}',
-'cannotundelete' => 'Falló la restauración; seique daquién yá restaurara la páxina enantes.',
+'cannotundelete' => 'Falló la restauración:
+$1',
'undeletedpage' => "'''Restauróse $1'''
Consulta'l [[Special:Log/delete|rexistru d'esborraos]] pa ver los esborraos y restauraciones de recién.",
'immobile-target-namespace-iw' => "Nun puedes mover una páxina a un enllaz d'Interwiki.",
'immobile-source-page' => 'Esta páxina nun ye treslladable.',
'immobile-target-page' => 'Nun se pue treslladar a esi títulu de destín.',
+'bad-target-model' => 'El destín deseáu utiliza un modelu de conteníu diferente. Nun se pue convertir de $1 a $2.',
'imagenocrossnamespace' => "Nun se pue treslladar una imaxe a nun espaciu de nomes que nun ye d'imáxenes",
'nonfile-cannot-move-to-file' => 'Nun se pue treslladar más que ficheros al espaciu de nomes de ficheros',
'imagetypemismatch' => 'La estensión nueva del archivu nun concueya cola so mena',
'pageinfo-magic-words' => '{{PLURAL:$1|Pallabra máxica|Pallabres máxiques}} ($1)',
'pageinfo-hidden-categories' => '{{PLURAL:$1|Categoría anubrida|Categoríes anubríes}} ($1)',
'pageinfo-templates' => '{{PLURAL:$1|Plantía incluída|Plantíes incluíes}} ($1)',
+'pageinfo-toolboxlink' => 'Información de la páxina',
# Skin names
'skinname-standard' => 'Clásicu',
# Scary transclusion
'scarytranscludedisabled' => '[La tresclusión interwiki ta desactivada]',
-'scarytranscludefailed' => '[La obtención de la plantía falló pa $1]',
+'scarytranscludefailed' => '[Falló la recuperación de la plantía pa $1]',
+'scarytranscludefailed-httpstatus' => '[Falló la recuperación de la plantía pa $1: HTTP $2]',
'scarytranscludetoolong' => '[La URL ye demasiao llarga]',
# Delete conflict
'tog-nocache' => 'Onemogući keširanje stranica u pregledniku',
'tog-enotifwatchlistpages' => 'Pošalji mi e-poštu kad se promijene stranice',
'tog-enotifusertalkpages' => 'Pošalji mi e-poštu kad se promijeni moja korisnička stranica za razgovor',
-'tog-enotifminoredits' => 'Pošalji mi e-poštu takođe za male izmjene stranica',
+'tog-enotifminoredits' => 'Pošalji mi e-poštu također za male izmjene u stranicama i datotekama',
'tog-enotifrevealaddr' => 'Otkrij adresu moje e-pošte u porukama obaviještenja',
'tog-shownumberswatching' => 'Prikaži broj korisnika koji prate',
'tog-oldsig' => 'Postojeći potpis:',
'youhavenewmessages' => 'Imate $1 ($2).',
'newmessageslink' => 'novih poruka',
'newmessagesdifflink' => 'posljednja promjena',
+'youhavenewmessagesfromusers' => 'Imate $1 od {{PLURAL:$3|drugog korisnika|$3 korisnika}} ($2).',
+'newmessageslinkplural' => '{{PLURAL:$1|novu poruku|nove poruke}}',
'youhavenewmessagesmulti' => 'Imate nove poruke na $1',
'editsection' => 'uredi',
'editsection-brackets' => '[$1]',
'protectedpagetext' => 'Ova stranica je zaključana da bi se spriječile izmjene.',
'viewsourcetext' => 'Možete vidjeti i kopirati izvorni tekst ove stranice:',
'viewyourtext' => "Možete da pogledate i kopirate izvor '''vaših izmjena''' na ovoj stranici:",
-'protectedinterface' => 'Ova stranica je zaštićena jer sadrži tekst MediaWiki programa.',
+'protectedinterface' => 'Ova stranica sadrži tekst korisničkog okruženja za softver na ovom wikiju i zaštićena je radi sprečavanja zloupotrebe.
+Da biste dodali ili izmjenili prijevode svih wikija, posjetite [//translatewiki.net/ translatewiki.net], projekat za lokalizaciju Mediawikija.',
'editinginterface' => "'''Upozorenje:''' Mijenjate stranicu koja sadrži aktivan tekst programa.
Promjene na ovoj stranici dovode i do promjena za druge korisnike.
Za prijevode, molimo Vas koristite [//translatewiki.net/wiki/Main_Page?setlang=bs translatewiki.net], projekt prijevoda za MediaWiki.",
'titleprotected' => 'Naslov stranice je zaštićen od postavljanja od strane korisnika [[User:$1|$1]].
Iz razloga "\'\'$2\'\'".',
'exception-nologin' => 'Niste prijavljeni',
+'exception-nologin-text' => 'Ova stranica ili aktivnost zahtijeva da budete prijavljeni na ovom wikiju.',
# Virus scanner
'virus-badscanner' => "Loša konfiguracija: nepoznati anti-virus program: ''$1''",
'remembermypassword' => 'Zapamti moju šifru na ovom računaru (najviše $1 {{PLURAL:$1|dan|dana|dana}})',
'securelogin-stick-https' => 'Ostani povezan na HTTPS nakon prijave',
'yourdomainname' => 'Vaš domen:',
+'password-change-forbidden' => 'Ne možete da promjenite lozinku na ovom wikiju.',
'externaldberror' => 'Došlo je do greške pri vanjskoj autorizaciji baze podataka ili vam nije dopušteno osvježavanje Vašeg vanjskog korisničkog računa.',
'login' => 'Prijavi se',
'nav-login-createaccount' => 'Prijavi se / Registruj se',
Možete [[Special:Search/{{PAGENAME}}|tražiti naslov ove stranice]] na drugim stranicama.
<span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tražiti u povezanim zapisima] ili [{{fullurl:{{FULLPAGENAME}}|action=edit}} urediti ovu stranicu]</span>.',
'noarticletext-nopermission' => 'Trenutno nema teksta na ovoj stranici.
-Možete [[Special:Search/{{PAGENAME}}|tražiti ovaj naslov stranice]] na drugim stranicama ili <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane zapisnike]</span>.',
+Možete [[Special:Search/{{PAGENAME}}|tražiti ovaj naslov stranice]] na drugim stranicama ili <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane zapisnike]</span>, ali nemate dozvolu da napravite ovu stranicu.',
'userpage-userdoesnotexist' => 'Korisnički račun "<nowiki>$1</nowiki>" nije registrovan.
Molimo provjerite da li želite napraviti/izmijeniti ovu stranicu.',
'userpage-userdoesnotexist-view' => 'Korisnički račun "$1" nije registrovan.',
*'''Firefox / Safari:''' držite ''Shift'' tipku i kliknite na ''Reload'' dugme ili pritisnite ''Ctrl-F5'' ili ''Ctrl-R'' (''⌘-R'' na Macu)
*'''Google Chrome:''' pritisnite ''Ctrl-Shift-R'' (''⌘-Shift-R'' na Macu)
*'''Internet Explorer:''' držite tipku ''Ctrl'' i kliknite na ''Refresh'' ili pritisnite ''Ctrl-F5''
-*'''Konqueror:''' klikni na ''Reload'' ili pritisnite dugme ''F5''
*'''Opera:''' očistite \"keš\" preko izbornika ''Tools → Preferences''",
'usercssyoucanpreview' => "'''Pažnja:''' Koristite dugme \"{{int:showpreview}}\" da testirate svoj novi CSS prije nego što sačuvate.",
'userjsyoucanpreview' => "'''Pažnja:''' Koristite dugme \"{{int:showpreview}}\" da testirate svoj novi JavaScript prije nego što sačuvate.",
Izgleda da već postoji.',
'defaultmessagetext' => 'Uobičajeni tekst poruke',
+# Content models
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
+
# Parser/template warnings
'expensive-parserfunction-warning' => 'Upozorenje: Ova stranica sadrži previše poziva opterećujućih parserskih funkcija.
'timezoneregion-indian' => 'Indijski okean',
'timezoneregion-pacific' => 'Tihi okean',
'allowemail' => 'Dozvoli e-poštu od ostalih korisnika',
-'prefs-searchoptions' => 'Opcije pretrage',
+'prefs-searchoptions' => 'Traži',
'prefs-namespaces' => 'Imenski prostori',
'defaultns' => 'Inače tražite u ovim imenskim prostorima:',
'default' => 'standardno',
'allpages-bad-ns' => '{{SITENAME}} nema imenski prostor "$1".',
'allpages-hide-redirects' => 'Sakrij preusmjerenja',
+# SpecialCachedPage
+'cachedspecial-refresh-now' => 'Pogledaj najnoviju.',
+
# Special:Categories
'categories' => 'Kategorije',
'categoriespagetext' => '{{PLURAL:$1|Slijedeća kategorija sadrži|Slijedeće kategorije sadrže}} stranice ili multimedijalne datoteke.
i imati ispravnu adresu e-pošte u vašim [[Special:Preferences|podešavanjima]]
da biste slali e-poštu drugim korisnicima.',
'emailuser' => 'Pošalji e-poštu ovom korisniku',
+'emailuser-title-notarget' => 'Pošalji e-mail korisniku',
'emailpage' => 'Pošalji e-mail korisniku',
'emailpagetext' => 'Možete korisiti formu ispod za slanje e-mail poruka ovom korisniku.
E-mail adresa koju ste unijeli u [[Special:Preferences|Vašim korisničkim postavkama]] će biti prikazana kao adresa pošiljaoca, tako da će primaoc poruke moći da Vam odgovori.',
# Durations
'duration-seconds' => '$1 {{PLURAL:$1|sekunda|sekunde}}',
+'duration-minutes' => '$1 {{PLURAL:$1|minut|minuta|minuta}}',
+'duration-hours' => '$1 {{PLURAL:$1|sat|sata|sati}}',
'duration-days' => '$1 {{PLURAL:$1|dan|dana}}',
+'duration-weeks' => '$1 {{PLURAL:$1|sedmica|sedmice|sedmica}}',
+'duration-years' => '$1 {{PLURAL:$1|godina|godine|godina}}',
+'duration-decades' => '$1 {{PLURAL:$1|decenija|decenije|decenija}}',
+'duration-centuries' => '$1 {{PLURAL:$1|vijek|vijeka|vijekova}}',
);
'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.',
'edit-no-change' => 'Din ændring ignoreredes, fordi der ikke var ændring af teksten.',
'edit-already-exists' => 'En ny side kunne ikke oprettes, fordi den allerede findes.',
'defaultmessagetext' => 'Standardtekst',
+'content-failed-to-parse' => 'Kunne ikke parse $2 indhold for $1 model: $3',
+'invalid-content-data' => 'Ugyldig indholdsdata',
+'content-not-allowed-here' => '"$1" indhold er ikke tilladt på siden [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'wikitekst',
+'content-model-text' => 'almindelig tekst',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
# Parser/template warnings
'expensive-parserfunction-warning' => 'Advarsel: Der er for mange beregningstunge oversætter-funktionskald på denne side.
'undeletedrevisions' => '$1 {{PLURAL:$1|version|versioner}} gendannet',
'undeletedrevisions-files' => '$1 {{plural:$1|version|versioner}} og $2 {{plural:$2|fil|filer}} gendannet',
'undeletedfiles' => '$1 {{plural:$1|fil|filer}} gendannet',
-'cannotundelete' => 'Gendannelse mislykkedes; en anden har allerede gendannet siden.',
+'cannotundelete' => 'Gendannelse mislykkedes:
+$1',
'undeletedpage' => "'''$1''' blev gendannet.
I [[Special:Log/delete|slette-loggen]] findes en oversigt over de nyligt slettede og gendannede sider.",
'immobile-target-namespace-iw' => 'En side kan ikke flyttes til en interwiki-henvisning.',
'immobile-source-page' => 'Denne side kan ikke flyttes.',
'immobile-target-page' => 'Kan ikke flytte til det navn.',
+'bad-target-model' => 'Den ønskede destination bruger en anden indholdsmodel. Kan ikke konvertere fra $1 til $2.',
'imagenocrossnamespace' => 'Filer kan ikke flyttes til et navnerum der ikke indeholder filer',
'nonfile-cannot-move-to-file' => 'Kan ikke flytte ikke-filer til fil-navnerummet',
'imagetypemismatch' => 'Den nye filendelse passer ikke til filtypen',
'edit-already-exists' => 'No se pudo crear una página nueva.
Ya existe.',
'defaultmessagetext' => 'Texto de mensaje predeterminado',
+'content-failed-to-parse' => 'No se pudo analizar el contenido $2 del modelo $1: $3',
+'invalid-content-data' => 'Datos de contenido inválidos',
+'content-not-allowed-here' => 'El contenido "$1" no está permitido en la página [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'texto wiki',
+'content-model-text' => 'Texto sin formato',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
# Parser/template warnings
'expensive-parserfunction-warning' => 'Aviso: Esta página contiene demasiadas llamadas a funciones sintácticas costosas (#ifexist: y similares)
'undeletedrevisions' => '{{PLURAL:$1|Una edición restaurada|$1 ediciones restauradas}}',
'undeletedrevisions-files' => '$1 {{PLURAL:$1|ediciones restauradas y $2 archivo restaurado|ediciones y $2 archivos restaurados}}',
'undeletedfiles' => '$1 {{PLURAL:$1|archivo restaurado|archivos restaurados}}',
-'cannotundelete' => 'Ha fallado el deshacer el borrado;
-alguien más puede haber deshecho el borrado antes.',
+'cannotundelete' => 'Hubo un error durante la restauración:
+$1',
'undeletedpage' => "'''Se ha restaurado $1'''
Consulta el [[Special:Log/delete|registro de borrados]] para ver una lista de los últimos borrados y restauraciones.",
'immobile-target-namespace-iw' => 'Un enlace interwiki no es un destino válido para trasladar una página.',
'immobile-source-page' => 'Esta página no se puede renombrar.',
'immobile-target-page' => 'No se puede trasladar a tal título.',
+'bad-target-model' => 'El destino deseado utiliza un modelo diferente de contenido. No se puede realizar la conversión de $1 a $2.',
'imagenocrossnamespace' => 'No se puede trasladar el fichero a otro espacio de nombres',
'nonfile-cannot-move-to-file' => 'No es posible mover un no-archivo al espacio de nombres de archivo',
'imagetypemismatch' => 'La nueva extensión de archivo no corresponde con su tipo',
'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',
'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',
'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á.',
'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.
'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',
'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.",
'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',
'edit-no-change' => 'Dyyni Bearbeitig isch ignoriert wore, wel kei Änderig am Täxt gmacht woren isch.',
'edit-already-exists' => 'Di nej Syte het nid chenne aaglait wäre, wel s si scho git.',
'defaultmessagetext' => 'Standardtext',
+'content-failed-to-parse' => 'Parse vum Inhalt $2 fir Modell $1 fählgschlaa: $3',
+'invalid-content-data' => 'Uugiltigi Inhaltsdate',
+'content-not-allowed-here' => 'Dr Inhalt „$1“ isch uf dr Syte [[$2]] nit erlaubt',
+
+# Content models
+'content-model-wikitext' => 'Wikitext',
+'content-model-text' => 'Klartext',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
# Parser/template warnings
'expensive-parserfunction-warning' => 'Achtig: In däre Syte het s z vyyl Ufruef vu ufwändige Parserfunktione.
'undeletedrevisions' => '{{PLURAL:$1|ei Revision|$1 Revisione}} wider zruckgholt.',
'undeletedrevisions-files' => '{{PLURAL:$1|1 Version|$1 Versione}} un {{PLURAL:$2|1 Datei|$2 Dateie}} sin widerhärgstellt wore',
'undeletedfiles' => '{{PLURAL:$1|1 Datei isch|$1 Dateie sin}} widerhärgstellt wore',
-'cannotundelete' => 'Widerhärstellig isch nit gange; eber ander het villicht d Syte scho widerhärgstellt.',
+'cannotundelete' => 'D Widerhärstellig isch nit gange:
+
+$1',
'undeletedpage' => "'''„$1“''' isch widerhärgstellt wore.
Im [[Special:Log/delete|Lesch-Logbuech]] findsch e Ibersicht vu dr gleschte un widerhärgstellte Syte.",
'immobile-target-namespace-iw' => 'E Interwiki-Link isch kei gültigs Ziil für e Syteverschiebig.',
'immobile-source-page' => 'Die Syte cha nüt verschobe werde.',
'immobile-target-page' => 'Uf die Ziilsyte cha nüt verschobe werde.',
+'bad-target-model' => 'Di gwinsche Ziilsyte brucht e ander Inhaltsmodell. S Inhaltsmodell $1 cha nit in s Inhaltsmodell $2 umgwandlet wäre.',
'imagenocrossnamespace' => 'Dateie chönne nüt ussem {{ns:file}}-Namensruum use verschobe werde',
'nonfile-cannot-move-to-file' => 'Nit-Dateie chenne nit in dr Datei-Namensruum verschobe wäre',
'imagetypemismatch' => 'D nöii Dateierwiiterig passt nüt zu sym Typ',
તમે [[Special:Search/{{PAGENAME}}|આ શબ્દ]] ધરાવતાં અન્ય લેખો શોધી શકો છો, <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} સંલગ્ન માહિતિ પત્રકોમાં શોધી શકો છો],
અથવા [{{fullurl:{{FULLPAGENAME}}|action=edit}} આ પાનામાં ફેરફાર કરી] માહિતિ ઉમેરવાનું શરૂ કરી શકો છો</span>.',
'noarticletext-nopermission' => 'આ પાનામાં હાલમાં કોઇ માહિતિ નથી.
-તમે [[Special:Search/{{PAGENAME}}|આ શબ્દ]] ધરાવતાં અન્ય લેખો શોધી શકો છો, <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} સંલગ્ન માહિતિ પત્રકોમાં શોધી શકો છો],
-અથવા [{{fullurl:{{FULLPAGENAME}}|action=edit}} આ પાનામાં ફેરફાર કરી] માહિતિ ઉમેરવાનું શરૂ કરી શકો છો</span>.',
+તમે [[Special:Search/{{PAGENAME}}|આ શબ્દ]] ધરાવતાં અન્ય લેખો શોધી શકો છો, અથવા <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} સંલગ્ન માહિતિ પત્રકોમાં શોધી શકો છો], પરંતુ તમને આ પાનું બનાવવાની મંજૂરી નથી.',
'userpage-userdoesnotexist' => 'સભ્ય ખાતું "<nowiki>$1</nowiki>"ની નોંધણીનથી થઈ.
શું તમે ખરેખર આ પાનાની રચના કે ફેરફાર કરવા માંગો છો',
'userpage-userdoesnotexist-view' => 'સભ્યના ખાતા $1 ની નોંધણી નથી થઈ',
'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' => 'ફક્ત અનિશ્ચિત સુરક્ષા ધરાવતા પાના',
'sp-deletedcontributions-contribs' => 'યોગદાન',
# Special:LinkSearch
-'linksearch' => 'બાહ્ય કડીઓ શોધ',
-'linksearch-pat' => 'શોધા આલેખ',
+'linksearch' => 'બાહ્ય કડીઓ શોધો',
+'linksearch-pat' => 'શોધ આલેખ',
'linksearch-ns' => 'નામાવકાશ:',
'linksearch-ok' => 'શોધ',
'linksearch-text' => '"*.wikipedia.org" જેવા વાઈલ્ડાકાર્ડ અહીં વાપર્યા હોઈ શકે છે.
'vector-action-protect' => 'Lapvédelem',
'vector-action-undelete' => 'Visszaállítás',
'vector-action-unprotect' => 'Védelem módosítása',
-'vector-simplesearch-preference' => 'Továbbfejlesztett keresési javaslatok engedélyezése (csak Vector felületen)',
+'vector-simplesearch-preference' => 'Egyszerűsített keresési sáv engedélyezése (csak Vector felületen)',
'vector-view-create' => 'Létrehozás',
'vector-view-edit' => 'Szerkesztés',
'vector-view-history' => 'Laptörténet',
'vector-action-protect' => 'Proteger',
'vector-action-undelete' => 'Restaurar',
'vector-action-unprotect' => 'Cambiar protection',
-'vector-simplesearch-preference' => 'Activar le suggestiones de recerca meliorate (solmente in apparentia Vector)',
+'vector-simplesearch-preference' => 'Activar le barra de recerca simplificate (solmente in apparentia Vector)',
'vector-view-create' => 'Crear',
'vector-view-edit' => 'Modificar',
'vector-view-history' => 'Vider historia',
'edit-already-exists' => 'Non poteva crear un nove pagina.
Illo existe ja.',
'defaultmessagetext' => 'Texto predefinite del message',
+'content-failed-to-parse' => 'Impossibile processar le contento $2 pro le modello $1: $3',
# Parser/template warnings
'expensive-parserfunction-warning' => 'Attention: Iste pagina contine troppo de appellos costose al functiones del analysator syntactic.
'viewyourtext' => "このページへの'''あなたの編集'''のソースの閲覧やコピーができます:",
'protectedinterface' => 'このページにはこのウィキのソフトウェアのインターフェイスに使用されるテキストが保存されており、いたずらなどの防止のために保護されています。
すべてのウィキに対して翻訳を追加/変更する場合は、MediaWiki の地域化プロジェクト [//translatewiki.net/ translatewiki.net] を使用してください。',
-'editinginterface' => "'''è¦å\91\8a:''' ã\82½ã\83\95ã\83\88ã\82¦ã\82§ã\82¢ã\81®ã\82¤ã\83³ã\82¿ã\83¼ã\83\95ã\82§ã\82¤ã\82¹ã\81«ä½¿ç\94¨ã\81\95ã\82\8cã\82\8bã\81®ã\83\86ã\82ã\82¹ã\83\88ã\81®ã\83\9aã\83¼ã\82¸ã\82\92ç·¨é\9b\86ã\81\97ã\81¦ã\81\84ã\81¾ã\81\99ã\80\82
+'editinginterface' => "'''警告:''' ソフトウェアのインターフェイスに使用されるテキストのページを編集しています。
このページを変更すると、このウィキの他の利用者のユーザーインターフェイスの外観に影響します。
すべてのウィキに対して翻訳を追加/変更する場合は、MediaWiki の地域化プロジェクト [//translatewiki.net/wiki/Main_Page?setlang=ja translatewiki.net] を使用してください。",
'sqlhidden' => '(SQL クエリ非表示)',
'restriction-level' => '制限レベル:',
'minimum-size' => '最小サイズ',
'maximum-size' => '最大サイズ:',
-'pagesize' => '(バイト)',
+'pagesize' => '(バイト)',
# Restrictions (nouns)
'restriction-edit' => '編集',
'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',
'edit-already-exists' => '새 문서를 만들 수 없습니다.
그 문서는 이미 존재합니다.',
'defaultmessagetext' => '기본 메세지 내용',
+'content-failed-to-parse' => '$1 모델에 대한 $2 내용을 구문 분석하는 데 실패했습니다: $3',
'invalid-content-data' => '잘못된 내용 데이터입니다',
'content-not-allowed-here' => '"$1" 내용은 [[$2]] 문서예 허용하지 않습니다',
'undeletedrevisions' => '판 $1개를 복구했습니다',
'undeletedrevisions-files' => '판 $1개와 파일 $2개를 복구했습니다.',
'undeletedfiles' => '파일 $1개를 복구했습니다',
-'cannotundelete' => '복구에 실패했습니다:
+'cannotundelete' => '복구하는 데 실패했습니다:
$1',
'undeletedpage' => "'''$1 문서를 복구했습니다.'''
이미 복구되었을 수 있습니다.',
'undelete-error' => '문서 복구 중 오류',
'undelete-error-short' => '파일 복구 오류: $1',
-'undelete-error-long' => '파일을 복구하는 중 오류가 발생했습니다:
+'undelete-error-long' => '파일을 복구하는 동안 오류가 발생했습니다:
$1',
'undelete-show-file-confirm' => '정말 "<nowiki>$1</nowiki>" 파일의 삭제된 $2 $3 버전을 보시겠습니까?',
'immobile-target-namespace-iw' => '인터위키 링크를 넘어 문서를 이동할 수 없습니다.',
'immobile-source-page' => '이 문서는 이동할 수 없습니다.',
'immobile-target-page' => '새 이름으로 옮길 수 없습니다.',
+'bad-target-model' => '원하는 대상은 다른 내용 모델을 사용합니다. $1에서 $2로 변환할 수 없습니다.',
'imagenocrossnamespace' => '파일을 파일이 아닌 이름공간으로 옮길 수 없습니다.',
'nonfile-cannot-move-to-file' => '파일이 아닌 문서를 파일 이름공간으로 옮길 수 없습니다.',
'imagetypemismatch' => '새 파일의 확장자가 원래의 확장자와 일치하지 않습니다.',
'tog-shownumberswatching' => 'Няфтемс мъзяра сувсида конат арафтозь лопать эсь мельгеваномазост',
'tog-oldsig' => 'Афкуксонь кядьтяшкс',
'tog-fancysig' => 'Кядьтяшкст улихть викитекстокс (эслек тиеви сюлмафксфтома)',
-'tog-externaleditor' => 'Нолдамс тевс ушеширень петнить мъзярс илякс изь мярьгов (аньцек тевонь содайхненди, сяс мес эрявихть башка кядьёнкст-арафнемат содама машинаса)',
-'tog-externaldiff' => 'Нолдамс тевс ушеширень програм верзиень ваксс путоманкса мъзярс илякс изь мярьгов (аньцек тевонь содайхненди, сяс мес эрявихть башка кядьёнкст-арафнемат содама машинаса)',
+'tog-externaleditor' => 'Нолдамс тевс ушеширень петнить мъзярс илякс изь мярьгов (аньцек тевонь содайхненди, сяс мес эрявихть башка кядьёнкст-арафнемат содама машинаса [//www.mediawiki.org/wiki/Manual:External_editors сяда тов.])',
+'tog-externaldiff' => 'Нолдамс тевс ушеширень програм верзиень ваксс путоманкса мъзярс илякс изь мярьгов (аньцек тевонь содайхненди, сяс мес эрявихть башка кядьёнкст-арафнемат содама машинаса[//www.mediawiki.org/wiki/Manual:External_editors сяда тов.])',
'tog-showjumplinks' => 'Мярьгомс "юпадемс" сатовома сюлмафкстненди',
'tog-uselivepreview' => 'Максомс эряй васень няфтемась (JavaScript) (Варжамань)',
'tog-forceeditsummary' => 'Няфтемс мондине мезе сёрмадомс шава петнема вальмас сувамста',
'tog-watchlisthideminor' => 'Кяшемс петнема анцяйнятне ванома лопаста',
'tog-watchlisthideliu' => 'Кяшемс сёрматфтф тиихнень петнемаснон мельгеваномаса',
'tog-watchlisthideanons' => 'Кяшемс лемфтома тиихнень петнемаснон мельгеваномаса',
+'tog-watchlisthidepatrolled' => 'Кяшемс лувонь кирдихнень видептемаснон мельгеваномаса',
'tog-ccmeonemails' => 'Кучт тейне копия электрононь сермане конатнень кучсайне иля тиихненди.',
'tog-diffonly' => 'Тят няфте лопань потмоц кафта верзиятнень ваксс путомать ала',
'tog-showhiddencats' => 'Няфтемс кяшф категориет',
'underline-never' => 'Мъзярдонга',
'underline-default' => 'Интернет полатксть кадомс апак полафтт',
+# Font style option in Special:Preferences
+'editfont-style' => 'Полафтомс тя паксянь сёрмадома стиленц',
+'editfont-default' => 'Интернетс вятись апак полафтт',
+'editfont-monospace' => 'Фкя келеса сёрмадома',
+'editfont-sansserif' => 'Сёрмадома Sans-serif',
+'editfont-serif' => 'Serif сёрмадома',
+
# Dates
'sunday' => 'Таргоши (Недляши)',
'monday' => 'Одговши (Панедельник)',
'category-file-count' => '{{PLURAL:$2|Тя категориеса аньцек фкя файл.|Вага {{PLURAL:$1|файл|$1 файлхт}} тя категориеса $2-нь эста.}}',
'category-file-count-limited' => 'Вага {{PLURAL:$1|файл|$1 файлхт}} тя категориеса.',
'listingcontinuesabbrev' => 'полатксоц',
+'index-category' => 'Индексыяф лопат',
'noindex-category' => '↓Индексфтома лопатне',
+'broken-file-category' => 'Лопат колаф сюлмафкснень мархта',
'about' => 'Колганза',
'article' => 'Сёрматфть потмонц лопац',
'vector-action-move' => 'Шашфтомс',
'vector-action-protect' => 'Араламс',
'vector-action-undelete' => 'Мърдафтомс',
-'vector-action-unprotect' => 'Аралама лоткамс',
+'vector-action-unprotect' => 'Араламать полафтомс',
+'vector-simplesearch-preference' => 'Нодамс тевс тёждялгтотф кядьёнксонь седяфксть (аньцек векторонь лангакс)',
'vector-view-create' => 'Тиемс',
'vector-view-edit' => 'Петнемс',
'vector-view-history' => 'История няфтемс',
'printableversion' => 'Лихтеви верзие',
'permalink' => 'Ялань сюлмафкс',
'print' => 'Нолдамс',
+'view' => 'Ваномс',
'edit' => 'Петнеме',
'create' => 'Тиемс',
'editthispage' => 'Петнемс тя лопать',
'delete' => 'Нардамс',
'deletethispage' => 'Нардамс тя лопать',
'undelete_short' => 'Мърдафтомс {{PLURAL:$1|петнема|$1 петнемат}}',
+'viewdeleted_short' => 'Ваномс {{PLURAL:$1|фкя нардаф видептема|$1 нардаф видептемат}}',
'protect' => 'Араламс',
'protect_change' => 'полафтомс прянь араламать',
'protectthispage' => 'Араламс тя лопать',
-'unprotect' => 'Ð\92алÑ\85Ñ\82омÑ\81 аÑ\80аламаÑ\82Ñ\8c',
-'unprotectthispage' => 'Ð\92алÑ\85Ñ\82омÑ\81 Ñ\82Ñ\8f лопаÑ\82Ñ\8c аÑ\80аламац',
+'unprotect' => 'Ð\90Ñ\80аламаÑ\82Ñ\8c полаÑ\84Ñ\82омÑ\81',
+'unprotectthispage' => 'Ð\9fолаÑ\84Ñ\82омÑ\81 Ñ\82Ñ\8f лопаÑ\82Ñ\8c аÑ\80аламанц',
'newpage' => 'Од лопа',
'talkpage' => 'Корхтамс тя лопать колга',
'talkpagelinktext' => 'Корхтама',
'jumpto' => 'Юпадемс тязк:',
'jumptonavigation' => 'навигацие',
'jumptosearch' => 'вешендема',
+'view-pool-error' => 'Ужяль, тя пингть серверхнень вийсна аф сатовихть.
+Вельф лама тиихть тяряфнихть ваномс тя лопать.
+Эняльттяма учт аф ламос тя лопанди одукс сама инголе.
+$1',
+'pool-timeout' => 'Пигонь кирдемась учи пякстаманц',
+'pool-queuefull' => 'Тяряфнемада вельф лама',
+'pool-errorunknown' => 'Аф содаф эльбятькс',
# All link text and link target definitions of links into project namespace that get used by other message strings, with the exception of user group pages (see grouppage) and the disambiguation template definition (see disambiguations).
'aboutsite' => '{{SITENAME}} колга',
'youhavenewmessages' => 'Тонь ули $1 ($2).',
'newmessageslink' => 'Од сёрмат',
'newmessagesdifflink' => 'мекольце полафтома',
+'youhavenewmessagesfromusers' => 'Тонь $1 {{PLURAL:$3|тага фкя тиить эзда|$3 тиихнень эзда}} ($2).',
+'youhavenewmessagesmanyusers' => 'Тонь $1 лама тиихнень эзда ($2).',
+'newmessageslinkplural' => '{{PLURAL:$1|од сёрма|од сёрмат}}',
+'newmessagesdifflinkplural' => 'мекольце {{PLURAL:$1|полафнема|полафнемат}}',
'youhavenewmessagesmulti' => 'Тонь улихть од сёрмат $1-са',
'editsection' => 'петнемс',
'editold' => 'петнемс',
'toc' => 'Лопань потмоц',
'showtoc' => 'няфтемс',
'hidetoc' => 'кяшемс',
+'collapsible-collapse' => 'Ёмлалгофтомс',
+'collapsible-expand' => 'Келептемс',
'thisisdeleted' => 'Ваномс эли мърдафтомс $1?',
'viewdeleted' => 'Ваномс $1?',
'restorelink' => '{{PLURAL:$1|нардаф петнема|$1 нардаф петнемат}}',
'page-rss-feed' => '"$1" RSS линия',
'page-atom-feed' => '"$1" Atom линия',
'red-link-title' => '$1 (стама лопась аш)',
+'sort-descending' => 'Арафтомс алу',
+'sort-ascending' => 'Арафтомс вяри',
# Short words for each namespace, by default used in the namespace tab in monobook
'nstab-main' => 'Лопа',
# General errors
'error' => 'Эльбятькс',
'databaseerror' => 'Датабаза эльбятькс',
-'dberrortext' => 'Ð\94аÑ\82абазанÑ\8c веÑ\88ендембаÑ\87к лиÑ\81Ñ\81Ñ\8c Ñ\81инÑ\82акÑ\81 эльбятькс.
-ТÑ\8f, Ñ\83лема, пÑ\80огÑ\80амонÑ\8c Ñ\8dлÑ\8cбÑ\8fÑ\82Ñ\8cкÑ\81.
-Мекольце датабазонь вешендема ульсь:
-<blockquote><tt>$1</tt></blockquote>
-функциеста "<tt>$2</tt>".
-Ð\94аÑ\82абазаÑ\81Ñ\8c мÑ\8aÑ\80даÑ\84Ñ\82озе Ñ\8dлÑ\8cбÑ\8fÑ\82Ñ\8cкÑ\81Ñ\82Ñ\8c "<tt>$3: $4</tt>".',
+'dberrortext' => 'СодамоÑ\88инÑ\8c паÑ\80ганÑ\8c веÑ\88ендембаÑ\87к лиÑ\81Ñ\81Ñ\8c Ñ\81инÑ\82акÑ\81онÑ\8c эльбятькс.
+ТÑ\8f, Ñ\83лема, пÑ\80огÑ\80амгÑ\8fÑ\80Ñ\8cкÑ\81онÑ\8c Ñ\81и.
+Мекольце содамошинь паргань вешема:
+<blockquote><code>$1</code></blockquote>
+функциеста "<code>$2</code>".
+СодамоÑ\88инÑ\8c паÑ\80гаÑ\81Ñ\8c паÑ\87Ñ\84Ñ\82еÑ\81Ñ\8c Ñ\8dлÑ\8cбÑ\8fÑ\82Ñ\8cкÑ\81 "<samp>$3: $4</samp>".',
'dberrortextcl' => 'Датабазонь вешендембачк лиссь синтакс эльбятькс.
Мекольце датабазонь вешендема ульсь:
"$1"
'readonly_lag' => 'Датабазась эслек пякстась мъзярс кядяла датабаза серверхт сотни прясерверть мархта',
'internalerror' => 'Потмонь эльбятькс',
'internalerror_info' => 'Потмонь эльбятькс: $1',
+'fileappenderrorread' => '"$1" файлась аф лувови поладома пингста.',
+'fileappenderror' => '"$1" файлась изь поладов "$2" файлти.',
'filecopyerror' => 'Аш кода копиямс файл "$1" файл "$2"с.',
'filerenameerror' => 'Аш кода "$1" файлти максомс од лем "$2".',
'filedeleteerror' => 'Файл "$1" аф нардави.',
'badarticleerror' => 'Тя лопаса тя аф тиеви.',
'cannotdelete' => 'Лопась эли кочкаф "$1" файлсь аф нардави.
Сонь, улема, кинге нардазе ни.',
+'cannotdelete-title' => '"$1" лопась аф нардави',
+'delete-hook-aborted' => 'Туворкс програм петнемать лоткафтозе.
+Пачфтемат тянь коряс аш.',
'badtitle' => 'Аф кондясти лем',
'badtitletext' => 'Вешф лопань лемоц аф тяфтама эли шава, шятьта кялень-ётка эли викинь-ётка лемсна аф лац сюлмафт. Сонь эса, улема ащи фкя эли сяда лама башка тяштькстт конат коняксонди аф кондястихть.',
-'perfcached' => 'Вешф програмонь информациесь сёрматфоль эслек ванфневи файлхнень эса ди, улема, сирелгодсь. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.',
-'perfcachedts' => 'Тя програмонь информациесь сёрматфоль эслек ванфневи файлхнень эса ди мекольцеда одонзаф $1. A maximum of {{PLURAL:$4|one result is|$4 results are}} available in the cache.',
+'perfcached' => 'Вешф програмонь информациесь сёрматфоль эслек ванфневи файлхнень эса ди, улема, сирелгодсь. Сяда {{PLURAL:$1|фкя муфкс|$1 муфкст}} эслек ванфневи файлань кярьксса.',
+'perfcachedts' => 'Тя програмонь информациесь сёрматфоль эслек ванфневи файлхнень эса ди мекольцеда одонзаф $1. Сяда {{PLURAL:$4|фкя муфкс|$4 муфкст}} эслек ванфневи файлонь кярьксса.',
'querypage-no-updates' => 'Тя лопать одонзапне тяни аф тиевихть. Информациесь тяса тяни аф одонзави.',
'wrong_wfQuery_params' => 'Аф кондясти параметратне функцияса wfQuery()<br />
Функцие: $1<br />
Вешфкс: $2',
'viewsource' => 'Ваномс лисьмоть',
+'viewsource-title' => 'Ванк $1 лисьмаста',
'actionthrottled' => 'Куроксшись кирьфтаф',
'actionthrottledtext' => 'Лудна мархта тюрема туфталонкса тя тевть ламоксть тиемась нюрьхконя ётка пингста кардаф. Эняльттяма мърдамс тя тевти мъзярошка минутода меле.',
'protectedpagetext' => 'Тя лопас сувама пякстаф лопань петнема кардамать сюнеда.',
'viewsourcetext' => 'Тейть ули кода ваномс эди копиямс тя лопать лисьмоц:',
-'protectedinterface' => 'Тя лопаса ащи лопать ванфонц програмонь текстоц, сон пякстаф кальдяв тевда араламать сюнеда.',
-'editinginterface' => "'''Инголе кардама:''' Тон петнесак лопать конань эса ащи лопать ванфонц програмонь текстоц. Петнематне полафтсазь сонь ванфоц кода сон няеви иля тиихненди. Ётафтома тиеманкса эняльттяма ваномс [//translatewiki.net/wiki/Main_Page?setlang=mdf translatewiki.net] МедиаВикить локализациеть проектть.",
+'viewyourtext' => "Тондейть ули кода тя лопань '''петнематнень''' ваномс ди тиемс копиянснон:",
+'protectedinterface' => 'Тя лопать эса интерфейс текстсь тя викить програмгярксти, сон аралаф кальдяв тиемада.
+Вики ётафтоматнень поладоманди полафнемандивок сувак [//translatewiki.net/ translatewiki.net], MediaWiki локализациень проектти.',
+'editinginterface' => "'''Инголи кардама:''' Тон петнесак лопать конань эса ащи интерфейс текст програмкярьксонди. Петнематне полафтсазь сонь ванфоц, кода сон няеви иля тиихненди. Вики ётафтоматнень поладоманди, полафтомандивок сувак [//translatewiki.net/ translatewiki.net] MediaWiki локализациень проектти.",
'sqlhidden' => '(SQL вешфкс кяшф)',
'cascadeprotected' => 'Тя лопать аралазь петнемада сяс мес сон сувафни {{PLURAL:$1|сай лопас, кона путфоль|сай лопас, конат путфольхть}} каскад араламас:
$2',
'namespaceprotected' => "Тондейть аф мярьгови петнемс лопатне '''$1''' лепнень мархта.",
+'customcssprotected' => 'Тейть аф мярьгови петнемс CSS лопать, сяс мес потмосонза иля тиить латцеманза.',
+'customjsprotected' => 'Тейть аф мярьгови петнемс JavaScript лопать, сяс мес потмосонза иля тиить латцеманза.',
'ns-specialprotected' => '{{ns:special}} лепнень мархта лопатне аф петневихть.',
'titleprotected' => "[[User:$1|$1]] кардазь тя лемсь мархта лопа тиемать.
Туфталсь ''$2''.",
+'filereadonlyerror' => '"$1" файлась аф полафтови сяс мес "$2" файлонь пърдафкссь аньцек морафтови форматса.
+
+Админць конась сёлгозе кадсь пачфтема: "$3".',
+'invalidtitle-knownnamespace' => 'Аф кондясти лем "$2" лемботмоса ди "$3" текстть эса',
+'invalidtitle-unknownnamespace' => 'Аф кондясти лем $1 лемботмоса ди "$2" текстть эса',
+'exception-nologin' => 'Апак сувак',
+'exception-nologin-text' => 'Тя лопать эли тиемать сатоманди васенда эряви сувамс викис.',
# Virus scanner
'virus-badscanner' => "Аф кондясти конфигурациесь: аф содаф вирусонь вешендема програмсь: ''$1''",
'yourpassword' => 'Сувама валце:',
'yourpasswordagain' => 'Сёрматк сувама валце омбоцекс:',
'remembermypassword' => 'Ванфтомс монь сувама лемозе тя содам машинаса (максимум $1 {{PLURAL:$1|шис|шис}})',
+'securelogin-stick-https' => 'Кадовомс сотфокс HTTPS вельде сувамада меле',
'yourdomainname' => 'Тонь доменце:',
+'password-change-forbidden' => 'Сувама валхне тя викить эса аф полафтовихть',
'externaldberror' => 'Лиссь эльбятькс ушеширень датабазонь вельде кемокстакшнембачк эли тондейть аф мярьгови полафнемс тонь ушеширень сёрматфтомацень.',
'login' => 'Сувама',
'nav-login-createaccount' => 'Сувама / сёрматфтома',
'loginprompt' => 'Тондейть эряви нолдамс тевс cookies {{SITENAME}}с суваманди.',
'userlogin' => 'Сувама / сёрматфтома',
+'userloginnocreate' => 'Сувамс',
'logout' => 'Лисема',
'userlogout' => 'Лисема',
'notloggedin' => 'Апак сувак',
'gotaccountlink' => 'Сувамс',
'userlogin-resetlink' => 'Сувама эрявикснень юкстайть?',
'createaccountmail' => 'электрононь сёрма вельде',
+'createaccountreason' => 'Туфтал:',
'badretype' => 'Сувама валхне тон путыть аф фкат.',
-'userexists' => 'Тя лемсь кой-кие сявозь ни. Эняльттяма, арьсек иля лемсь.',
+'userexists' => 'Тя лемть сявозь ни.
+Эняльттяма, арьсек эстейть иля.',
'loginerror' => 'Сувама эльбятькс',
+'createaccounterror' => 'Сёрматфтомась аф тиеви: $1',
'nocookiesnew' => 'Тиить сёрматфтомаце анок, аньцек тон изеть сува. {{SITENAME}}-са тиихнень содафтоманкса функцие cookies эряви. Тяни тонь содама машинаса функцие cookies кардаф. Эняльттяма нолдамс тевс cookies, меле сувак од эсь тиить лемцень эди сувама валцень мархта.',
'nocookieslogin' => '{{SITENAME}} лопаса тиихнень содафтоманкса функцие cookies эряви. Тяни тонь содама машинаса функцие cookies кардаф. Эняльттяма нолдамс тевс cookies, меле сувак тага весть.',
+'nocookiesfornew' => 'Тиить сёрматфтомась апак тик сяс мес лисьмонц аф кемокстави.
+Варжак cookies нолдафт эли аф, одонзафтк лопать ди тяряфтт одукс.',
'noname' => 'Тон изеть пута кемокстаф тиить лемоц.',
'loginsuccesstitle' => 'Сувамась ётась лац',
'loginsuccess' => "'''Тон сувать {{SITENAME}}-с кода \"\$1\".'''",
Илякс тондейть эряви [[Special:UserLogin/signup|сёрматфтомс одукс]].',
'nosuchusershort' => 'Тиись "$1" лемса аш. Ванк, улема, тон сёрмадыть лемть аф лац.',
'nouserspecified' => 'Тиить лемсь эряви.',
+'login-userblocked' => 'Тиись перяф. Сувама кардаф.',
'wrongpassword' => 'Сувама валсь сёрматф аф лац. Варжак тага весть.',
'wrongpasswordempty' => 'Сувама валсь кадовсь апак сёрматк. Сёрматк одукс.',
'passwordtooshort' => 'Тонь сувама валценди эряви улемс аф {{PLURAL:$1|1 тяшкста|$1 тяшкста}} кържа',
+'password-name-match' => 'Сувама лемце ди сувама сувама валце улемат аф фкат.',
+'password-login-forbidden' => 'Тя сувама лемсь эди сувама валсь кардафт.',
'mailmypassword' => 'Кучт од сувама вал',
'passwordremindertitle' => 'Од ёткопингонь сувама валсь {{SITENAME}}с суваманди',
'passwordremindertext' => 'Кивок (улема, тон IP адресста $1) вешсь од сувама валсь {{SITENAME}} ($4)с суваманди.
Улендяряй киге иля кучсь тя вешфксть эли тон мяляфтсак тонь сувама валцень эди тонь тяни аш мяльце сонь полафтома, тят тие мезеге тя пачфтемась самда меле ди киртть тонь ингольдень сувама валцень.',
'noemail' => '"$1" тиить электрононь адресоц аш.',
+'noemailcreate' => 'Эряви тяштемс афкукс е-парга',
'passwordsent' => 'Од сувама валсь кучфоль "$1" тиить электрононь адресонцты.
Сувак сонь кундамда меле.',
'blocked-mailpassword' => 'Петнемат тиемась тонь IP адрестот кардаф. Сувама валть кемокстама функциес кундама аф мярьгови кальдяв тиемада аралама туфталонкса.',
'noemailprefs' => 'Мъзярс тон ашеть пута тонь электрононь адресце Викить сёрматнень коряс програмсь кодамога сёрмат аф кучсыне.',
'emailconfirmlink' => 'Кемокстак тонь электрононь адресце',
'invalidemailaddress' => 'Электрононь адресть аф пьрьняндави сяс сонь аф кондясти электрононь адресоц. Путт кондясти электрононь адресонц эли катк тя паксянять шавакс.',
+'cannotchangeemail' => 'Сёрматфтомать е-паргоц аф полафтови тя викить эса',
+'emaildisabled' => 'Тя лопанди аш кода кучемс е-сёрмат.',
'accountcreated' => 'Сёрматфтомась тиф',
'accountcreatedtext' => '$1 тиить сёрматфтомась тиф.',
'createaccount-title' => 'Сёрматфнемась {{SITENAME}}-с',
'createaccount-text' => 'Кати-кие тизе сёрматфтомась $2 {{SITENAME}} ($4)-са. "$2" -ть сувама валсь "$3". Тондейть эряви сувамс тозк эди арафтомс од сувама валть.
Улендяряль тя сёрматфтомась эльбятьксокс мезеге тят тие.',
+'usernamehasherror' => 'Тиить лемозонза тяфтама тяшкст аф мярьговихть',
'login-throttled' => 'Тон улхкомба вельф ламос тяряфнеть сувамс тя сувама валть вельде.
Эняльттяма, учт аф ламос тага весть тяряфтома инголе.',
+'login-abort-generic' => 'Сувамацень апак тиевсь лац - Валхтф',
'loginlanguagelabel' => 'Кяль: $1',
+'suspicious-userlogout' => 'Вешфксце лисемс кардафоль сяс мес няеви тянь кучезь колаф интернетс вятиень эли ётка ёкамань сервер вельде.',
+
+# E-mail sending
+'php-mail-error-unknown' => 'Аф содаф эльбятькс PHP сёрмавятемань функциеса.',
+'user-mail-no-addy' => 'Тяряфтыхть кучемс е-сёрма е-паргафтома',
# Change password dialog
'resetpass' => 'Полафтомс сувама валцень',
'resetpass_forbidden' => 'Сувама валхнень полафтомс аш кода',
'resetpass-no-info' => 'Тондейть эряви сёрматфтомс тя лопас видеста суваманди.',
'resetpass-submit-loggedin' => 'Полафтомс сувама валцень',
+'resetpass-submit-cancel' => 'Валхтомс',
'resetpass-wrong-oldpass' => 'Аф виде ёткопингонь эли тяниень сувама валсь.
Улема тон полафтыть сувама валце ни эли кучеть вешфкс од ёткопингонь сувама вал кундаманкса.',
'resetpass-temp-password' => 'Пингонь сувама валсь:',
+# Special:PasswordReset
+'passwordreset' => 'Полафтомс сувама валцень',
+'passwordreset-text' => 'Эряви пяшкодемс тя формать е-сёрма сёрматфтомацень колга сявоманди.',
+'passwordreset-legend' => 'Полафтомс сувама валцень',
+'passwordreset-disabled' => 'Сувама валсь аф полафтови тя викить эса.',
+'passwordreset-pretext' => '{{PLURAL:$1||Тяштьк содама пялькснень эзда фкя алу}}',
+'passwordreset-username' => 'Тиить лемоц',
+'passwordreset-domain' => 'Домен:',
+'passwordreset-capture' => 'Ваномс мекольце е-сёрма?',
+'passwordreset-capture-help' => 'Путондярят тяшкс тя паксять эса е-сёрма (пингонь сувама вал мархта) кармай няфтевома кодак кучф тиенди.',
+
# Edit page toolbar
'bold_sample' => 'Эчке сёрмадома',
'bold_tip' => 'Эчке сёрмадома',
'edit-no-change' => 'Тонь петнемацень тевс изь нолда, сяс мес тон текстть ашеть полафта.',
'edit-already-exists' => 'Аш кода од лопа ушедомс.
Тя лопась ульсь ни.',
+'content-failed-to-parse' => 'Аш кода $2 сёрматфть нолдамс тевс $1 моделень коряс: $3',
# Parser/template warnings
'expensive-parserfunction-warning' => 'Инголе кардама: Тя лопаса пяк лама питни синтаксонь анализаторхнень тяшкста.
'allmessagestext' => 'Тя MediaWiki-са васьфневи системонь пачфтематнень лувомась.
Эняльттяма, сувак [//www.mediawiki.org/wiki/Localisation MediaWiki Локализациес] ди [//translatewiki.net translatewiki.net-с] кда тонь мяльце тиемс эсь путксце марстонь MediaWiki локализациес.',
'allmessagesnotsupportedDB' => "Тя лопас аш кода кунцемс сяс мес '''\$wgUseDatabaseMessages'''лоткафоль.",
+'allmessages-language' => 'Кяль:',
+'allmessages-filter-submit' => 'Ётамс',
# Thumbnails
'thumbnail-more' => 'Оцюлгофтомс',
'thumbnail_error' => 'Миниатюр тиема эльбятькс: $1',
'djvu_page_error' => 'DjVu лопась аф сатови',
'djvu_no_xml' => 'Аш кода латцемс XML DjVu файлти',
+'thumbnail-temp-create' => 'Пингонь миниатюрац аф тиеви',
+'thumbnail-dest-create' => 'Миниатюрась аф ванфтови коза эряви',
'thumbnail_invalid_params' => 'Аф кондясти миниатюронь арафнеманза',
'thumbnail_dest_directory' => 'Аш кода ушедомс од вастонь директориесь',
+'thumbnail_image-type' => 'Тя няйфкс форматсь аф нежедеви',
# Special:Import
'import' => 'Таргамс лопат',
'edit-no-change' => 'Redigeringen din ble ignorert fordi det ikke var noen endringer.',
'edit-already-exists' => 'Kunne ikke opprette ny side fordi den finnes fra før.',
'defaultmessagetext' => 'Standard meldingstekst',
+'content-failed-to-parse' => 'Klarte ikke å tolke innholdet $2 for innholdsmodellen $1: $3',
+'invalid-content-data' => 'Ugyldig innhold',
+'content-not-allowed-here' => 'Innholdsmodellen «$1» er ikke tillatt på siden [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'WikiTekst',
+'content-model-text' => 'Ren tekst',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
# Parser/template warnings
'expensive-parserfunction-warning' => 'Advarsel: Denne siden inneholder for mange prosesskrevende parserfunksjoner.
'undeletedrevisions' => '{{PLURAL:$1|Én revisjon|$1 revisjoner}} gjenopprettet',
'undeletedrevisions-files' => '{{PLURAL:$1|Én revisjon|$1 revisjoner}} og {{PLURAL:$2|én fil|$2 filer}} gjenopprettet',
'undeletedfiles' => '{{PLURAL:$1|Én fil|$1 filer}} gjenopprettet',
-'cannotundelete' => 'Kunne ikke gjenopprette siden (den kan være gjenopprettet av noen andre).',
+'cannotundelete' => 'Gjennoppretting feilet:
+$1',
'undeletedpage' => "'''$1 ble gjenopprettet'''
Sjekk [[Special:Log/delete|slettingsloggen]] for en liste over nylige slettinger og gjenopprettelser.",
'immobile-target-namespace-iw' => 'Du kan ikke flytte en side til et navn som er en interwikilenke.',
'immobile-source-page' => 'Denne siden kan ikke flyttes.',
'immobile-target-page' => 'Kan ikke flytte til det navnet.',
+'bad-target-model' => 'Det ønskede målet bruker en annen innholdsmodell. Kan ikke konvertere fra $1 til $2.',
'imagenocrossnamespace' => 'Kan ikke flytte filer til andre navnerom enn filnavnerommet',
'nonfile-cannot-move-to-file' => 'Kan ikke flytte ikke-filer til filnavnerom',
'imagetypemismatch' => 'Den nye filendelsen tilsvarer ikke filtypen',
* @author Trijnstel
* @author Troefkaart
* @author Tvdm
+ * @author Wiki13
* @author לערי ריינהארט
*/
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.
'undeletedrevisions' => '$1 {{PLURAL:$1|versie|versies}} teruggeplaatst',
'undeletedrevisions-files' => '{{PLURAL:$1|1 versie|$1 versies}} en {{PLURAL:$2|1 bestand|$2 bestanden}} teruggeplaatst',
'undeletedfiles' => '{{PLURAL:$1|1 bestand|$1 bestanden}} teruggeplaatst',
-'cannotundelete' => 'Het terugplaatsen is mislukt.
-Misschien heeft een andere gebruiker de pagina al teruggeplaatst.',
+'cannotundelete' => 'Het terugplaatsen is mislukt:
+$1',
'undeletedpage' => "'''$1 is teruggeplaatst'''
In het [[Special:Log/delete|verwijderingslogboek]] staan recente verwijderingen en herstelhandelingen.",
* @author Guttorm Flatabø
* @author H92
* @author Harald Khan
+ * @author Jeblad
* @author Jon Harald Søby
* @author Jorunn
* @author Kaganer
'edit-no-change' => 'Redigeringa di vart ignorert fordi det ikkje vart gjort endringar i teksten.',
'edit-already-exists' => 'Kunne ikkje opprette ny side fordi ho alt eksisterer.',
'defaultmessagetext' => 'Standard meldingstekst',
+'content-failed-to-parse' => 'Klarte ikkje å tolke innhaldet «$2» som innholdsmodellen «$1»: $3',
+'invalid-content-data' => 'Ugyldig innhald',
+'content-not-allowed-here' => 'Innhaldsmodellen «$1» er ikkje tillaten på sida [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'WikiTekst',
+'content-model-text' => 'Rein tekst',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
# Parser/template warnings
'expensive-parserfunction-warning' => 'Åtvaring: Denne sida inneheld for mange prosesskrevande parserfunksjonar.
'edit-already-exists' => 'As peul nen creesse la pàgina.
A esist già.',
'defaultmessagetext' => "Test che a-i sarìa se a-i fusso pa 'd modìfiche",
+'content-failed-to-parse' => "Faliment ëd l'anàlisi dël contnù ëd $2 për ël model $1: $3",
+'invalid-content-data' => 'Dat dël contnù pa bon',
+'content-not-allowed-here' => 'Contnù ëd "$1" pa përmëttù an sla pagina [[$2]]',
+
+# Content models
+'content-model-wikitext' => 'test wiki',
+'content-model-text' => 'mach test',
+'content-model-javascript' => 'JavaScript',
+'content-model-css' => 'CSS',
# Parser/template warnings
'expensive-parserfunction-warning' => "'''Atension:''' Costa pàgina a l'ha tròpe ciamà costose a le fonsions ëd parser.
'undeletedrevisions' => '{{PLURAL:$1|Na revision pijàita|$1 revision pijàite}} andré',
'undeletedrevisions-files' => "{{PLURAL:$1|Na|$1}} revision e {{PLURAL:$2|n'|$2 }}archivi pijàit andré",
'undeletedfiles' => "{{PLURAL:$1|N'|$1 }}archivi pijàit andaré",
-'cannotundelete' => "Riprìstin falì; a peul esse che i fusse antra doi a felo ant l'istess temp e l'àutr a sia riva prima.",
+'cannotundelete' => 'Riprìstin falì:
+$1',
'undeletedpage' => "'''$1 a l'é stàit pijait andaré'''
Che as varda ël [[Special:Log/delete|Registr djë scancelament]] për ës-ciairé j'ùltim scancelament e arcuperassion.",
'immobile-target-namespace-iw' => "Na liura interwiki a l'é pa na destinassion vàlida për tramudé na pàgina.",
'immobile-source-page' => 'Sta pàgina-sì as peul pa tramudesse.',
'immobile-target-page' => 'As peul pa tramudesse vers cost tìtol ëd destinassion.',
+'bad-target-model' => 'La destinassion vorsùa a dòvra un model ëd contnù diferent. As peul pa convertisse da $1 a $2.',
'imagenocrossnamespace' => "As peul pa tramudesse n'archivi a në spassi nominal diferent",
'nonfile-cannot-move-to-file' => "As peul nen tramudesse lòn ch'a l'é pa n'archivi a lë spassi nominal dj'archivi",
'imagetypemismatch' => "La neuva estension ëd l'archivi a corispond pa a sò tipo",
'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',
'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',
+'exif-orientation-4' => 'Arvirà dzor-sota',
+'exif-orientation-5' => 'Arvirà dzor-sota e ëd 90° contramostra',
'exif-orientation-6' => 'Arvirà ëd 90° contramostra',
'exif-orientation-7' => 'Arvirà dzorsota e ëd 90° ant ël sens dla mostra',
'exif-orientation-8' => 'Arvirà ëd 90° ant ël sens dla mostra',
'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.
-*$1 - localized name of content model: {{msg-mw|Content-model-wikitext}}, {{msg-mw|Content-model-javascript}}, {{msg-mw|Content-model-css}} or {{msg-mw|Content-model-text}}
-*$2 - ...",
+*$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}}
'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.
'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.",
'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',
* '''ෆයර්ෆොක්ස්/ සෆාරි:''' ''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:පෙර-දසුන පෙන්වන්න}}\" බොත්තම භාවිතා කරන්න.",
'revdelete-only-restricted' => '$2 දිනැති අයිතමය සැඟවීමේ දෝෂය , $1:අනෙකුත් සැඟවීම් විකල්පයන් අතුරින් එකක් තෝරාගන්නේ නැතිව, පරිපාලකයන්ගේ දර්ශනයෙන් අයිතමයන් සැඟවීම ඔබහට සිදුකල නොහැක.',
'revdelete-reason-dropdown' => '*මකා දැමීමේ පොදු හේතු
**කතු හිමිකම් උල්ලංඝනය
-**නුසුදුසු පුද්ගලික කොරතුරු
+**නුසුදුසු පරිකථන හෝ පුද්ගලික කොරතුරු
+**නුසුදුසු පරිශීලක නම
**අපහාසාත්මක විය හැකි තොරතුරු',
'revdelete-otherreason' => 'වෙනත්/අමතර හේතු:',
'revdelete-reasonotherlist' => 'වෙනත් හේතු',
# 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' => 'පිටු ඉතිහාසයන් ඒකාබද්ධ කරන්න',
'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" හී අගුළු ඇරිය නොහැක; එය අගුළු දමාද නොමැත.',
'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.',
'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',
'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',
'file-info' => 'Velikost datoteke: $1, MIME-vrsta: <code>$2</code>',
'file-info-size' => '$1 × $2 točk, velikost datoteke: $3, vrsta MIME: $4',
'file-info-size-pages' => '$1 × $2 točk, velikost datoteke: $3, vrsta MIME: $4, $5 {{PLURAL:$5|stran|strani}}',
-'file-nohires' => 'Višja ločljivost slike ni na razpolago.',
+'file-nohires' => 'Višja ločljivost slike ni na voljo.',
'svg-long-desc' => 'datoteka SVG, v izvirniku $1 × $2 slikovnih točk, velikost datoteke: $3',
'svg-long-desc-animated' => 'animirana datoteka SVG, v izvirniku $1 × $2 slikovnih točk, velikost datoteke: $3',
'show-big-image' => 'Slika v višji ločljivosti',
* @author Rotsee
* @author S.Örvarr.S
* @author Sannab
+ * @author Sendelbach
* @author Sertion
* @author Skalman
* @author Stefan2
'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]]',
'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',
'revdelete-success' => "'''Тағйири намоёнии нусха бо муваффақият анҷом шуд.'''",
'logdelete-success' => "'''Тағйири намоёнии маврид бо муваффақият анҷом шуд.'''",
'revdel-restore' => 'Тағйири падидорӣ',
+'revdel-restore-visible' => 'нусхаҳои намоён',
'pagehist' => 'Таърихи саҳифа',
'deletedhist' => 'Таърихи ҳазфшуда',
'revdelete-edit-reasonlist' => 'Вироиш ҳазф далелҳо',
'filehist-dimensions' => 'Андоза',
'filehist-filesize' => 'Андозаи парванда',
'filehist-comment' => 'Тавзеҳ',
-'imagelinks' => 'Ð\9fайвандҳои парванда',
+'imagelinks' => 'Ð\98Ñ\81Ñ\82иÑ\84одаи парванда',
'linkstoimage' => '{{PLURAL:$1|Саҳифаҳои|$1 Саҳифаи}} зерин ба ин акс пайванданд:',
'nolinkstoimage' => 'Ҳеҷ саҳифае ба ин акс пайванд надорад.',
'sharedupload' => 'Ин парванда аз $1 мебошад ва шояд аз тарафи дигар лоиҳаҳо истифода шавад.',
* @file
*
* @author Alfredie
+ * @author Arlin
* @author Kaganer
* @author Reedy
* @author Sahran
'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" تۈردىكى ۋاسىتە',
'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' => 'تەپسىلىي…',
'vector-action-protect' => 'قوغدا',
'vector-action-undelete' => 'ئەسلىگە قايتۇر',
'vector-action-unprotect' => 'قوغداش ئۆزگەرت',
-'vector-simplesearch-preference' => 'ئالىي ئىزدەش تەكلىپىنى ئاچ (Vector تېرىدىلا)',
+'vector-simplesearch-preference' => 'ئاددىي ئىزدەش ئىستون ئاچ (پەقەت ۋېكتور قېلىپ)',
'vector-view-create' => 'قۇر',
'vector-view-edit' => 'تەھرىر',
'vector-view-history' => 'تارىخ كۆرسەت',
[[Special:Version|نەشر بېتى]] نى كۆرۈڭ.',
'ok' => 'ماقۇل',
+'pagetitle' => '$1 - {{SITENAME}}',
'pagetitle-view-mainpage' => '{{SITENAME}}',
'backlinksubtitle' => '← $1',
'retrievedfrom' => '"$1" دىن ئېرىشكەن',
'site-atom-feed' => '$1 نىڭ Atom قانالى',
'page-rss-feed' => '"$1" نىڭ RSS قانىلى',
'page-atom-feed' => '"$1" نىڭ Atom قانىلى',
-'feed-atom' => 'ئاتوم',
+'feed-atom' => 'Atom',
'feed-rss' => 'RSS',
'red-link-title' => '$1 (بەت مەۋجۇد ئەمەس)',
'sort-descending' => 'كېمەيگۈچى تەرتىپ',
'dberrortext' => 'ساندان سۈرۈشتۈرۈشتە گرامماتىكىلىق خاتالىق يۈز بەردى.
يۇمشاق دېتالنىڭ ئۆزىدىكى خاتالىقتىن كېلىپ چىققان بولۇشى مۇمكىن.
ئاخىرقى قېتىملىق ساندان سۈرۈشتۈرۈش بۇيرۇقى:
-<blockquote><tt>$1</tt></blockquote>
- \\"<tt>$2</tt>\\"فۇنكسىيىدىن كەلگەن.
-MySQL قايتۇرغان خاتالىق \\"<tt>$3: $4</tt>\\".',
+<blockquote><code>$1</code></blockquote>
+ "<code>$2</code>"فۇنكسىيىدىن كەلگەن.
+ساندان قايتۇرغان خاتالىق "<samp>$3: $4</samp>".',
'dberrortextcl' => 'ساندان سۈرۈشتۈرۈشتە گرامماتىكىلىق خاتالىق يۈز بەردى.
ئاخىرقى قېتىملىق ساندان سۈرۈشتۈرۈش بۇيرۇقى:
"$1"
'protectedpagetext' => 'بۇ بەت تەھرىرلەشنىڭ ئالدىنى ئېلىش ئۈچۈن قۇلۇپلانغان.',
'viewsourcetext' => 'سىز بۇ بەتنى ئەسلى كودىنى كۆرەلەيسىز ۋە كۆچۈرەلەيسىز:',
'viewyourtext' => "بۇ بەتتىكى '''تەھرىرلىگەنلىرىڭىز'''نىڭ ئەسلى كودىنى كۆرۈپ كۆچۈرەلەيسىز.",
-'protectedinterface' => 'بۇ بەت يۇمشاق دېتالنىڭ كۆرۈنۈش تېكستىنى تەمىنلىگەن، خالىغانچە تەھرىرلەشتىن ساقلىنىش ئۈچۈن قۇلۇپلانغان.',
+'protectedinterface' => 'بۇ بەت يۇمشاق دېتالنىڭ كۆرۈنۈش تېكستىنى تەمىنلىگەن، خالىغانچە تەھرىرلەشتىن ساقلىنىش ئۈچۈن قۇلۇپلانغان.
+مەسىلەن ئەگەر تەرجىمە قىلسىڭىز [//translatewiki.net/wiki/Main_Page?setlang=ug translatewiki.net] ئۇنداقتا MediaWiki يەرلىكلەشتۈرۈش پىلانىنى ئىشلىتىشنى ئويلىشىڭ.',
'editinginterface' => "'''ئاگاھلاندۇرۇش:''' سىز تەھرىرلەۋاتقان بەت يۇمشاق دېتالنىڭ كۆرۈنۈش تېكستىگە ئىشلىتىلىدۇ.
بۇ بەت ئۆزگەرتىلسە باشقا ئىشلەتكۈچىلەرنىڭ كۆرۈنۈش ئۇسلۇبىغا تەسىر كۆرسىتىدۇ.
<span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} مۇناسىۋەتلىك خاتىرىسىنى ئىزدىيەلەيسىز،],
[{{fullurl:{{FULLPAGENAME}}|action=edit}} بۇ بەتنى تەھرىرلىيەلەيسىز]</span>',
'noarticletext-nopermission' => 'بۇ بەتتە ھازىرچە مەزمۇن يوق.
- سىز باشقا بەتتە [[Special:Search/{{PAGENAME}}|بۇ بەتنىڭ ماۋزۇسىنى ئىزدىيەلەيسىز]] ياكى <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}}] مۇناسىۋەتلىك خاتىرىسىنى ئىزدىيەلەيسىز،</span>',
+ سىز باشقا بەتتە [[Special:Search/{{PAGENAME}}|بۇ بەتنىڭ ماۋزۇسىنى ئىزدىيەلەيسىز]] ياكى <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}}] مۇناسىۋەتلىك خاتىرىسىنى ئىزدىيەلەيسىز،</span>لىكىن سزنىڭ بەت قۇرۇش ھوقوقىڭز يوق.',
'missing-revision' => '"{{PAGENAME}}" ئاتلىق بەتنىڭ تۈزىتىلگەن نەشرى #$1 مەۋجۇت ئەمەس.
ئادەتتە بۇ ئۆچۈرۈلگەن بىر بەتنىڭ ئۇلانمىسىغا كىرگەنلىك سەۋەبىدىن بولىدۇ.
* '''Mozilla / Firefox / Safari:''' دا ''Shift'' كۇنۇپكىسىنى بېسىپ تۇرۇپ ''قايتا يۈكلە''نى ياكى ''Ctrl-F5'' ياكى ''Ctrl-R'' (''Mac تا Command-R'')؛
* '''Google Chrome:''' دا ''Ctrl-Shift-R'' (''Command-Shift-R'' Mac)
*'''Internet Explorer:''' دا ''Ctrl'' نى بېسىپ تۇرۇپ ''يېڭىلا,'' ياكى ''Ctrl-F5''؛
-* '''Konqueror: دا ''' ''قايتا يۈكلە'' ياكى ''F5''؛
* '''Opera:''' دا ''قورال → مايىللىق''؛ نى بېسىپ غەملەكنى تازىلاڭ.",
'usercssyoucanpreview' => "ئەسكەرتىش:''' ساقلاشتىن ئىلگىرى \"{{int:showpreview}}\" توپچىنى ئىشلىتىپ يېڭى CSS نى سىناڭ.",
'userjsyoucanpreview' => "ئەسكەرتىش:''' ساقلاشتىن ئىلگىرى \"{{int:showpreview}}\" توپچىنى ئىشلىتىپ يېڭى JS نى سىناڭ.",
'edit-already-exists' => 'يېڭى بەت قۇرالمىدى
ئۇ مەۋجۇد.',
'defaultmessagetext' => 'كۆڭۈلدىكى ئۇچۇر تېكستى',
+'content-failed-to-parse' => '$2 نى $1 گە ئانالىز قلش مەغلۇپ بولدى: $3',
# Parser/template warnings
'expensive-parserfunction-warning' => "'''ئاگاھلاندۇرۇش:''' بۇ بەت ناھايىتى كۆپ يۇقىرى سەرپىياتتىكى گىرامماتىكىلىق ئىقتىدارنى چاقىرغان.\\n
'username' => 'ئىشلەتكۇچى ئىسمى:',
'uid' => 'ئىشلەتكۈچى كىملىك:',
'prefs-memberingroups' => '{{PLURAL:$1|بىر|كۆپ}} گۇرۇپپا ئەزاسى:',
+'prefs-memberingroups-type' => '$1',
'prefs-registration' => 'خەتلەتكەن ۋاقىت:',
+'prefs-registration-date-time' => '$1',
'yourrealname' => 'ﺗﻮﻟﯘﻕ ئىسىم:',
'yourlanguage' => 'تىل:',
'yourvariant' => 'مەزمۇن تىل شالغۇتى:',
'userrights-notallowed' => 'ھېساباتىڭىزنىڭ ئىشلەتكۈچى ھوقۇقىنى قوشۇش ياكى ئۆزگەرتىش ھوقۇقى يوق.',
'userrights-changeable-col' => 'سىز ئۆزگەرتەلەيدىغان گۇرۇپپا',
'userrights-unchangeable-col' => 'سىز ئۆزگەرتەلمەيدىغان گۇرۇپپا',
+'userrights-irreversible-marker' => '$1*',
# Groups
'group' => 'گۇرۇپپا:',
'minoreditletter' => 'ئازراقلا',
'newpageletter' => 'يېڭى',
'boteditletter' => 'ماشىنا ئادەم',
+'unpatrolledletter' => '!',
'number_of_watching_users_pageview' => '[$1 {{PLURAL:$1|ئىشلەتكۈچى|ئىشلەتكۈچى}}كۆزىتىۋاتىدۇ]',
'rc_categories' => 'تۈر چېگرىسى ("|" بىلەن ئايرىلىدۇ )',
'rc_categories_any' => 'خالىغان',
+'rc-change-size' => '$1',
'newsectionsummary' => '* $1 * يېڭى ئابزاس',
'rc-enhanced-expand' => 'تەپسىلاتىنى كۆرسەت (JavaScript قوللىشى زۆرۈر)',
'rc-enhanced-hide' => 'تەپسىلاتىنى يوشۇر',
# Book sources
'booksources' => 'كىتاب مەنبەسى',
'booksources-search-legend' => 'كىتاب مەنبەسى ئىزدە',
+'booksources-isbn' => 'ISBN:',
'booksources-go' => 'يۆتكەل',
'booksources-text' => 'تۆۋەندىكىسى بىر قىسىم تور كىتابخانىلىرىنىڭ تىزىملىكى، ئىچىدە سىز ئىزدىمەكچى بولغان كىتابلارنىڭ تېخىمۇ كۆپ ئۇچۇرى بولۇشى مۇمكىن:',
'booksources-invalid-isbn' => 'تەمىنلىگەن ISBN نومۇرى توغرا ئەمەس. ئەسلى كۆچۈرگەن مەنبەدىكى نومۇردا خاتالىق بار يوقلۇقىنى تەكشۈرۈڭ.',
'listgrouprights-rights' => 'ھوقۇق',
'listgrouprights-helppage' => 'Help: گۇرۇپپا ھوقۇقى',
'listgrouprights-members' => '(ئەزالار تىزىملىكى)',
+'listgrouprights-right-revoked' => '<span class="listgrouprights-revoked">$1 <code>($2)</code></span>',
'listgrouprights-addgroup' => ' {{PLURAL:$2|بىر|بىر قانچە}} گۇرۇپپىغا قوشالايدۇ: $1',
'listgrouprights-removegroup' => ' {{PLURAL:$2|بىر|بىر قانچە}} گۇرۇپپىدىن چىقىرىۋېتەلەيدۇ: $1',
'listgrouprights-addgroup-all' => 'ھەممە گۇرۇپپىغا قوش',
[[Special:Log/delete|ئۆچۈرۈش خاتىرىسى]]دىن پايدىلىنىپ ئۆچۈر ۋە ئەسلىگە كەلتۈر خاتىرىسىنى كۆرۈڭ.",
'undelete-header' => 'يېقىنقى خاتىرىنى سۈرۈشتۈرمەكچى بولسىڭىز [[Special:Log/delete|ئۆچۈرۈش خاتىرىسى]]دىن پايدىلىنىڭ.',
+'undelete-search-title' => 'ئۆچۈرۈئتلگەن بەتنى ئزدەش',
'undelete-search-box' => 'ئۆچۈرۈلگەن بەتنى ئىزدە',
'undelete-search-prefix' => 'باشلانغان بەتنى كۆرسەت:',
'undelete-search-submit' => 'ئىزدەش',
$1',
'undelete-show-file-confirm' => '$2 $3 دىكى \\"<nowiki>$1</nowiki>\\" نىڭ ئۆچۈرۈلگەن تۈزىتىلگەن نەشرىنى راستىنلا كۆرەمسىز؟',
'undelete-show-file-submit' => 'ھەئە',
+'undelete-revisionrow' => '$1 $2 ($3) $4 . . $5 $6 $7',
# Namespace form on various pages
'namespace' => 'ئات بوشلۇقى',
'proxyblockreason' => 'IP ئادرېسىڭىز ئوچۇق ۋاكالەتچى، ئۇ ئاللىبۇرۇن چەكلەنگەن.
ئىنتېرنېت مۇلازىمىتى تەمىنلىگۈچى سودىگەر ياكى تېخنىكىلىق قوللىغۇچى بىلەن ئالاقىلىشىڭ ھەمدە ئۇلارغا بۇ ئېغىر بىخەتەرلىك مەسىلىسىنى ئۇقتۇرۇڭ.',
'proxyblocksuccess' => 'تامام',
+'sorbs' => 'DNSBL',
'sorbsreason' => 'IP ئادرېسىڭىز {{SITENAME}} دا DNSBL تەرىپىدىن ئوچۇق ۋاكالەتچى تىزىملىكىگە قوشۇلغان.',
'sorbs_create_account_reason' => 'IP ئادرېسىڭىز {{SITENAME}} دا DNSBL تەرىپىدىن ئوچۇق ۋاكالەتچى تىزىملىكىگە قوشۇلغان.
شۇڭا سىز يېڭى ھېسابات قۇرالمايسىز.',
بەت چىقىرىشتا، تۆۋەندىكى تېكست رامكىسىغا بەت ماۋزۇسىنى كىرگۈزۈپ، ھەر بىر قۇردا بىر ماۋزۇ، ھەمدە بەت تارىخ بار ئىلگىرىكى تۈزىتىلگەن نەشرىنى تاللامسىز يوق، ياكى پەقەت ئاخىرقى قېتىملىق تەھرىر ئۇچۇرى بار نۆۋەتتىكى تۈزىتىلگەن نەشرىنى چىقىرىشنى تاللاڭ.
ئۇنىڭدىن باشقا ئۇلانمىدىن پايدىلىنىپ ھۆججەت چىقىرالايسىز، مەسىلەن سىز [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] دىن پايدىلىنىپ "[[{{MediaWiki:Mainpage}}]]"بەت چىقىرالايسىز.',
+'exportall' => 'بارلىق بەتنى چىقىرىش',
'exportcuronly' => 'ھەممە تارىخنى ئەمەس بەلكى نۆۋەتتىكى تۈزىتىلگەن نەشرىنىلا ئۆز ئىچىگە ئالىدۇ.',
'exportnohistory' => "----
'''دىققەت:''' ئىقتىدار سەۋەبلىك بۇ جەدۋەلدىن ھەممە تارىخنى چىقىرىش چەكلەنگەن.",
'thumbnail_error' => 'كىچىك رەسىم قۇرۇش خاتالىقى: $1',
'djvu_page_error' => 'DjVu بېتى دائىرىدىن ھالقىپ كەتتى',
'djvu_no_xml' => 'DjVu ھۆججىتىدىن XML گە ئېرىشەلمىدى',
+'thumbnail-dest-create' => 'قارار ھۈجەتتە ۋاقتلىق كىچىك ھۈجەت ساقلىغل بولمدى',
'thumbnail_invalid_params' => 'ئىناۋەتسىز كىچىك رەسىم پارامېتىرى',
'thumbnail_dest_directory' => 'نىشان مۇندەرىجە قۇرالمىدى',
'thumbnail_image-type' => 'سۈرەت فورماتىنى قوللىمايدۇ',
'tooltip-preferences-save' => 'مايىللىق ساقلا',
'tooltip-summary' => 'قىسقىچە ئۈزۈندە كىرگۈزۈڭ',
+# Stylesheets
+'common.css' => '/* CSS placed here will be applied to all skins */',
+'standard.css' => '/* CSS placed here will affect users of the Standard skin */',
+'nostalgia.css' => '/* CSS placed here will affect users of the Nostalgia skin */',
+'cologneblue.css' => '/* CSS placed here will affect users of the Cologne Blue skin */',
+'monobook.css' => '/* CSS placed here will affect users of the Monobook skin */',
+'myskin.css' => '/* CSS placed here will affect users of the MySkin skin */',
+'chick.css' => '/* CSS placed here will affect users of the Chick skin */',
+'simple.css' => '/* CSS placed here will affect users of the Simple skin */',
+'modern.css' => '/* CSS placed here will affect users of the Modern skin */',
+'vector.css' => '/* CSS placed here will affect users of the Vector skin */',
+'print.css' => '/* CSS placed here will affect the print output */',
+'noscript.css' => '/* CSS placed here will affect users with JavaScript disabled */',
+'group-autoconfirmed.css' => '/* CSS placed here will affect autoconfirmed users only */',
+'group-bot.css' => '/* CSS placed here will affect bots only */',
+'group-sysop.css' => '/* CSS placed here will affect sysops only */',
+'group-bureaucrat.css' => '/* CSS placed here will affect bureaucrats only */',
+
+# Scripts
+'common.js' => '/* Any JavaScript here will be loaded for all users on every page load. */',
+'standard.js' => '/* Any JavaScript here will be loaded for users using the Standard skin */',
+'nostalgia.js' => '/* Any JavaScript here will be loaded for users using the Nostalgia skin */',
+'cologneblue.js' => '/* Any JavaScript here will be loaded for users using the Cologne Blue skin */',
+'monobook.js' => '/* Any JavaScript here will be loaded for users using the MonoBook skin */',
+'myskin.js' => '/* Any JavaScript here will be loaded for users using the MySkin skin */',
+'chick.js' => '/* Any JavaScript here will be loaded for users using the Chick skin */',
+'simple.js' => '/* Any JavaScript here will be loaded for users using the Simple skin */',
+'modern.js' => '/* Any JavaScript here will be loaded for users using the Modern skin */',
+'vector.js' => '/* Any JavaScript here will be loaded for users using the Vector skin */',
+'group-autoconfirmed.js' => '/* Any JavaScript here will be loaded for autoconfirmed users only */',
+'group-bot.js' => '/* Any JavaScript here will be loaded for bots only */',
+'group-sysop.js' => '/* Any JavaScript here will be loaded for sysops only */',
+'group-bureaucrat.js' => '/* Any JavaScript here will be loaded for bureaucrats only */',
+
# Metadata
'notacceptable' => 'wiki مۇلازىمىتىرى سىزنىڭ خېرىدار تەرىپىڭىز ئوقۇيالايدىغان سانلىق مەلۇمات فورماتى بىلەن تەمىنلىيەلمەيدۇ.',
'pageinfo-header-edits' => 'تەھرىر',
'pageinfo-views' => 'كۆرۈنۈش سانى',
'pageinfo-watchers' => 'كۆزەتكۈچىلەر سانى',
+'pageinfo-redirects-value' => '$1',
'pageinfo-edits' => 'تەھرىر سانى',
'pageinfo-authors' => 'يازغۇچىلار سانى',
+# Skin names
+'skinname-standard' => 'Classic',
+'skinname-nostalgia' => 'Nostalgia',
+'skinname-cologneblue' => 'Cologne Blue',
+'skinname-monobook' => 'MonoBook',
+'skinname-myskin' => 'MySkin',
+'skinname-chick' => 'Chick',
+'skinname-simple' => 'Simple',
+'skinname-modern' => 'Modern',
+'skinname-vector' => 'Vector',
+
# Patrolling
'markaspatrolleddiff' => 'چارلاش بەلگىسى قوي',
'markaspatrolledtext' => 'بۇ بەتكە چارلاش بەلگىسى قوي',
'mediawarning' => "'''ئاگاھلاندۇرۇش''': بۇ ھۆججەتتە زەھەرخەندە كود بولۇشى مۇمكىن، ئۇنى ئىجرا قىلسىڭىز سىستېمىڭىزغا خەۋپ ئېلىپ كېلىشى مۇمكىن.",
'imagemaxsize' => "سۈرەت چوڭلۇق چەكلىمىسى: <br />''(ھۆججەت چۈشەندۈرۈش بېتى ئۈچۈن)''",
'thumbsize' => 'كىچىك سۈرەت چوڭلۇقى:',
+'widthheight' => '$1 × $2',
'widthheightpage' => '$1 × $2, $3 {{PLURAL:$3|بەت|بەت}}',
'file-info' => 'ھۆججەت چوڭلۇقى: $1, MIME تىپى: $2',
'file-info-size' => '$1 × $2 پىكسېل، ھۆججەت چوڭلۇقى: $3، MIME تىپى: $4',
'bydate' => 'چېسلا بويىچە',
'sp-newimages-showfrom' => '$2 دىن $1 باشلاپ يېڭى ھۆججەت كۆرسىتىۋاتىدۇ',
+# Video information, used by Language::formatTimePeriod() to format lengths in the above messages
+'video-dims' => '$1, $2 × $3',
+'seconds-abbrev' => '$1s',
+'minutes-abbrev' => '$1m',
+'hours-abbrev' => '$1h',
+'days-abbrev' => '$1d',
+
# Bad image list
'bad_image_list' => 'تۆۋەندىكى فورماتتا يېزىڭ:
بۇ ھۆججەت قايسى بەتلەردە كۆرسىتىلىشىدىن قەتئىي نەزەر،
ئوخشاش بىر قۇرنىڭ ئاخىرىدىكى ئۇلانما مۇستەسنا دەپ قارىلىدۇ،',
+/*
+Short names for language variants used for language conversion links.
+To disable showing a particular link, set it to 'disable', e.g.
+'variantname-zh-sg' => 'disable',
+Variants for Chinese language
+*/
+'variantname-zh-hans' => 'hans',
+'variantname-zh-hant' => 'hant',
+'variantname-zh-cn' => 'cn',
+'variantname-zh-tw' => 'tw',
+'variantname-zh-hk' => 'hk',
+'variantname-zh-mo' => 'mo',
+'variantname-zh-sg' => 'sg',
+'variantname-zh-my' => 'my',
+'variantname-zh' => 'zh',
+
+# Variants for Gan language
+'variantname-gan-hans' => 'hans',
+'variantname-gan-hant' => 'hant',
+'variantname-gan' => 'gan',
+
+# Variants for Serbian language
+'variantname-sr-ec' => 'sr-ec',
+'variantname-sr-el' => 'sr-el',
+'variantname-sr' => 'sr',
+
+# Variants for Kazakh language
+'variantname-kk-kz' => 'kk-kz',
+'variantname-kk-tr' => 'kk-tr',
+'variantname-kk-cn' => 'kk-cn',
+'variantname-kk-cyrl' => 'kk-cyrl',
+'variantname-kk-arab' => 'kk-arab',
+'variantname-kk' => 'kk',
+
# Metadata
'metadata' => 'مېتا سانلىق مەلۇماتى',
'metadata-help' => 'بۇ ھۆججەت كېڭەيتىلگەن تەپسىلاتنى ئۆز ئىچىگە ئالغان. بۇ ئۇچۇرلارنى رەقەملىك ئاپپارات ياكى سكاننېر قۇرغان ياكى رەقەملەشتۈرۈش جەريانىدا قوشۇلغان بولۇشى مۇمكىن.
'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' => 'ווײַזן היסטאָריע',
'edit-already-exists' => 'נישט מעגליך צו שאַפֿן נייע בלאט.
ער עקזיסטירט שוין.',
'defaultmessagetext' => 'גרונטלעכער מעלדונג טעקסט',
+'invalid-content-data' => 'אומגילטיקע אינהאלט דאטן',
# Parser/template warnings
'expensive-parserfunction-warning' => "'''אזהרה:''' דער בלאט אנטהאלט צופיל טייערע פארזירער רופן.
* נאמען פון דער טעקע וואס ווערט ארויפגעלאָדן: <strong>[[:$1]]</strong>
* נאמען פון דער פֿאראנענער טעקע: <strong>[[:$2]]</strong>
זײַט אזוי גוט און קלויבט אן אנדער נאמען.',
+'file-thumbnail-no' => "דער טעקע־נאמען הייבט אן מיט <strong>$1</strong>.
+זי זעט אויס ווי א פארקלענערט בילד ''(מיניאטור)''.
+טאמער האט איר דאס בילד אין פולער רעזאלוציע טוט עס ארויפלאדן, אנדערשט זייט אזוי גוט און ענדערט דעם טעקע־נאמען.",
'fileexists-forbidden' => 'א טעקע מיט דעם נאָמען עקזיסטירט שוין, און מען קען זי נישט אַריבערשרײַבן.
אויב איר ווילט דאך אַרויפֿלאָדן אײַער טעקע, ביטע גיין צוריק און ניצן אַן אַנדער נאָמען.
[[File:$1|thumb|center|$1]]',
'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| אויסמעקן לאג]] פֿאר א ליסטע פון די לעצטע אויסגעמעקטע און צוריקגעשטעלטע בלעטער.",
'undelete-search-box' => 'זוכן אויסגעמעקטע בלעטער',
'undelete-search-prefix' => 'ווײַז בלעטער וואס הייבן אן מיט:',
'undelete-search-submit' => 'זוכן',
+'undelete-no-results' => 'נישט געטראפן קיין צוגעפאסטע בלעטער אין אויסמעקונג ארכיוו.',
'undelete-error' => 'גרייז ביים צוריקשטעלן בלאט',
'undelete-error-short' => 'טעות ביים צוריקשטעלן טעקע: $1',
'undelete-error-long' => 'גרײַזן געטראפֿן בײַם ווידערשטעלן די טעקע:
'import-error-interwiki' => 'דעם בלאט "$1" קען מען נישט אימפארטירן ווייל זיין נאמען איז רעזערווירט פאר דרויסנדיקער פארבינדונג (אינטערוויקי).',
'import-error-special' => 'דעם בלאט "$1" קען מען נישט אימפארטירן ווייל ער געהערט צו א באזונדערן נאמענטייל וואס אנטהאלט נישט קיין בלעטער.',
'import-error-invalid' => 'דעם בלאט "$1" קען מען נישט אימפארטירן ווייל זיין נאמען איז אומגילטיק.',
+'import-rootpage-nosubpage' => 'נאמענטייל "$1" פונעם שטאמבלאט ערלויבט נישט קיין אונטערבלעטער.',
# Import log
'importlogpage' => 'אימפארט לאגבוך',
'exif-keywords' => 'שליסלווערטער',
'exif-worldregioncreated' => "וועלטראיאן וואו מ'האט גענומען דאס בילד",
'exif-countrycreated' => "לאנד וואו מ'האט געמאכט דאס בילד",
+'exif-countrycodecreated' => "קאד פארן לאנד וואו מ'האט געמאכט דאס בילד",
'exif-provinceorstatecreated' => "פראווינץ אדער שטאַט וואו מ'האט גענומען דאס בילד",
'exif-citycreated' => "שטאָט וואו מ'האט געמאכט דאס בילד",
'exif-worldregiondest' => 'וועלטראיאן געוויזן',
'pageinfo-lasttime' => '最后编辑的日期',
'pageinfo-edits' => '总编辑次数',
'pageinfo-authors' => '不同编者总计',
-'pageinfo-recent-edits' => '最近的编辑数 ($1天内)',
+'pageinfo-recent-edits' => '最近的编辑数($1内)',
'pageinfo-recent-authors' => '最近的不同编者数',
'pageinfo-magic-words' => '魔术字 ($1)',
'pageinfo-hidden-categories' => '隐藏分类 ($1)',
--- /dev/null
+-- 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
}
if ( $d > 1 ) {
$lb = wfGetLB();
- $serverCount = $lb->getServerCount();
+ $serverCount = $lb->getServerCount();
for ( $i = 0; $i < $serverCount; $i++ ) {
$server = $lb->getServerInfo( $i );
$server['flags'] |= DBO_DEBUG;
$IP . '/includes/actions/',
$IP . '/includes/api/',
$IP . '/includes/cache/',
+ $IP . '/includes/content/',
$IP . '/includes/context/',
$IP . '/includes/db/',
$IP . '/includes/diff/',
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];
}
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.archive ADD ar_content_format VARCHAR2(64);
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.archive ADD ar_content_model VARCHAR2(32);
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.category DROP COLUMN cat_hidden;
+
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.page ADD page_content_model VARCHAR2(32);
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.recentchanges DROP ( rc_moved_to_ns, rc_moved_to_title );
+
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.revision ADD rev_content_format VARCHAR2(64);
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.revision ADD rev_content_model VARCHAR2(32);
--- /dev/null
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.site_stats DROP COLUMN ss_admins;
+
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);
-- 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
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;
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);
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);
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);
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;
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);
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);
--- /dev/null
+-- 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
-- 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
* @file
*/
-require './opensearch_desc.php';
+require './opensearch_desc.php';
'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',
'feedback-bugnew',
),
),
+ 'mediawiki.hidpi' => array(
+ 'scripts' => 'resources/mediawiki/mediawiki.hidpi.js',
+ 'dependencies' => array(
+ 'jquery.hidpi',
+ ),
+ ),
'mediawiki.htmlform' => array(
'scripts' => 'resources/mediawiki/mediawiki.htmlform.js',
),
--- /dev/null
+/**
+ * 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 ) );
--- /dev/null
+$( function() {
+ // Apply hidpi images on DOM-ready
+ // Some may have already partly preloaded at low resolution.
+ $( 'body' ).hidpi();
+} );
\ No newline at end of file
'wgNoFollowLinks' => true,
'wgNoFollowDomainExceptions' => array(),
'wgThumbnailScriptPath' => false,
- 'wgUseImageResize' => false,
+ 'wgUseImageResize' => true,
'wgLocaltimezone' => 'UTC',
'wgAllowExternalImages' => true,
'wgUseTidy' => false,
{{{1}}}
!! endarticle
+!! article
+Template:attr_str
+!! text
+{{{1}}}="{{{2}}}"
+!! endarticle
+
###
### Basic tests
###
</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
###
### <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
!! 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
!! 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
!! 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
!! 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
!! 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
!! 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
!! 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
!! 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&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&wpDestFile=Icon.png" class="new" title="File:Icon.png">image</a> inside it!</div></div></div>
!! end
!! 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
</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>
!! 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>
</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>
</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>
</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>
!! 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
!! 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
!! 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
!! 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
!! input
[[image:Foobar.jpg|thumb|An [http://test/?param1=|left|¶m2=|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&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&param2=%7Cx">external</a> URL</div></div></div>
!!end
!! 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
!! 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>
!! 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>
!! 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>
### 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
}
}
+ /**
+ * 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;
+ }
}
$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 );
$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,
$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,
$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' ) ),
--- /dev/null
+<?php
+class ApiGeneratorTest extends MediaWikiTestCase {
+
+ /**
+ * Helper to easily get an ApiQuery object instance
+ */
+ function getApiQuery() {
+ // Initialize an ApiQuery object to play with
+ $main = new ApiMain( new FauxRequest() );
+ return new ApiQuery( $main, 'foo', 'bar' );
+ }
+
+ /**
+ * Test whether all registered query modules which are subclasses of
+ * ApiQueryGeneratorBase are listed as being a generator. Registration is
+ * done:
+ * - for core: add it to ApiQuery::$mQueryGenerators
+ * - for extension: by adding to $wgAPIGeneratorModules
+ *
+ * @dataProvider provideApiquerygeneratorbaseChilds
+ */
+ public function testApiquerygeneatorbaseModulesListedAsGenerators(
+ $moduleName, $moduleClass
+ ) {
+ $generators = $this->getApiQuery()->getGenerators();
+ $this->assertArrayHasKey( $moduleName, $generators,
+ "API module '$moduleName' of class '$moduleClass' (an ApiQueryGeneratorBase subclass) must be listed in ApiQuery::\$mQueryGenerators or added to \$wgAPIGeneratorModules."
+ );
+ }
+
+ /**
+ * Returns API modules which are subclassing ApiQueryGeneratorBase.
+ * Case format is:
+ * (moduleName, moduleClass)
+ */
+ public function provideApiquerygeneratorbaseChilds() {
+ $cases = array();
+ $modules = $this->getApiQuery()->getModules();
+ foreach( $modules as $moduleName => $moduleClass ) {
+ if( !is_subclass_of( $moduleClass, 'ApiQueryGeneratorBase' ) ) {
+ continue;
+ }
+ $cases[] = array( $moduleName, $moduleClass );
+ }
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provideListedApiqueryGenerators
+ */
+ public function testGeneratorsAreApiquerygeneratorbaseSubclasses(
+ $generatorName, $generatorClass
+ ) {
+ $modules = $this->getApiQuery()->getModules();
+ $this->assertArrayHasKey( $generatorName, $modules,
+ "Class '$generatorClass' of generator '$generatorName' must be a subclass of 'ApiQueryGeneratorBase'. Listed either in ApiQuery::\$mQueryGenerators or in \$wgAPIGeneratorModules."
+ );
+
+ }
+
+ /**
+ * Return ApiQuery generators, either listed in ApiQuery or registered
+ * via wgAPIGeneratorModules.
+ * Case format is:
+ * (moduleName, $moduleClass).
+ */
+ public function provideListedApiqueryGenerators() {
+ $cases = array();
+ $generators = $this->getApiQuery()->getGenerators();
+ foreach( $generators as $generatorName => $generatorClass ) {
+ $cases[] = array( $generatorName, $generatorClass );
+ }
+ return $cases;
+ }
+
+}
$instances = array();
foreach ( $this->elementInstancesProvider() as $elementInstances ) {
- $instances[] = $this->getNew( $elementInstances );
+ $instances[] = $this->getNew( $elementInstances[0] );
}
return $this->arrayWrap( $instances );
'wgNoFollowLinks' => true,
'wgNoFollowDomainExceptions' => array(),
'wgThumbnailScriptPath' => false,
- 'wgUseImageResize' => false,
+ 'wgUseImageResize' => true,
'wgUseTeX' => isset( $opts['math'] ),
'wgMathDirectory' => $uploadDir . '/math',
'wgLocaltimezone' => 'UTC',
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 );
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 );
}
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();
* @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';
--- /dev/null
+<?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 ) );
+ }
+
+}
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+<?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() );
+ }
+ }
+
+}
--- /dev/null
+<?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
'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',
'jquery.colorUtil',
'jquery.delayedBind',
'jquery.getAttrs',
+ 'jquery.hidpi',
'jquery.highlightText',
'jquery.localize',
'jquery.mwExtension',
--- /dev/null
+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' );
+});
* @ingroup Media
*/
-require './thumb.php';
+require './thumb.php';