* (bug 11142) Improve file extension blacklist error reporting in API upload.
* (bug 39665) List of query generators is now not built using reflection, instead it is
defined in code.
+* (bug 35993) Deprecated gettoken parameter - support will be removed in 1.22.
=== Languages updated in 1.20 ===
* (bug 43964) Invalid value of "link" parameter in <gallery> no longer produces
a fatal error.
* (bug 44775) The username field is not pre-filled when creating an account.
+* (bug 45069) wfParseUrl() no longer produces a PHP notice if passed a "mailto:"
+ URL without address
+* (bug 45012) Creating an account by e-mail can no longer show a
+ "password mismatch" error.
+* (bug 44599) On Special:Version, HEADs for submodule checkouts (e.g. for
+ extensions) performed using Git 1.7.8+ should now appear.
=== API changes in 1.21 ===
* prop=revisions can now report the contentmodel and contentformat.
iicontinue).
* Add supports for all pageset capabilities - generators, redirects, converttitles to
action=purge and action=setnotificationtimestamp.
+* (bug 43251) prop=pageprops&ppprop= now accepts multiple props to query.
+* ApiQueryImageInfo will now limit the number of calls to File::transform made
+ in any one query. If there are too many, iicontinue will be returned.
=== API internal changes in 1.21 ===
* For debugging only, a new global $wgDebugAPI removes many API restrictions when true.
first one keeping its meaning. ApiPageSet is now derived from ApiBase.
* BREAKING CHANGE: ApiQuery::newGenerator() and executeGeneratorModule() were deleted.
* ApiQueryGeneratorBase::setGeneratorMode() now requires a pageset param.
+* $wgAPIGeneratorModules is now obsolete and will be ignored.
+* Added flags ApiResult::OVERRIDE and ADD_ON_TOP to setElement() and addValue()
=== Languages updated in 1.21 ===
/**
* Page on which we're performing the action
- * @var Page $page
+ * @var WikiPage|Article|ImagePage|CategoryPage|Page $page
*/
protected $page;
$wgAPIMetaModules = array();
$wgAPIPropModules = array();
$wgAPIListModules = array();
+
+/**
+ * This variable is ignored. To add your module to the API, please add it to $wgAPI*Modules
+ * @deprecated since 1.21
+ */
$wgAPIGeneratorModules = array();
/**
* @param $dir string The root directory of the repo where the .git dir can be found
*/
public function __construct( $dir ) {
- $this->basedir = "{$dir}/.git/";
+ $this->basedir = "{$dir}/.git";
+ if ( is_readable( $this->basedir ) ) {
+ $GITfile = file_get_contents( $this->basedir );
+ if ( strlen( $GITfile ) > 8 && substr( $GITfile, 0, 8 ) === 'gitdir: ' ) {
+ $path = rtrim( substr( $GITfile, 8 ), "\r\n" );
+ $isAbsolute = $path[0] === '/' || substr( $path, 1, 1 ) === ':';
+ $this->basedir = $isAbsolute ? $path : "{$dir}/{$path}";
+ }
+ }
}
/**
}
// If not a SHA1 it may be a ref:
- $REFfile = "{$this->basedir}{$HEAD}";
+ $REFfile = "{$this->basedir}/{$HEAD}";
if ( !is_readable( $REFfile ) ) {
return false;
}
if ( !isset( $bits['host'] ) ) {
$bits['host'] = '';
- /* parse_url loses the third / for file:///c:/ urls (but not on variants) */
- if ( substr( $bits['path'], 0, 1 ) !== '/' ) {
- $bits['path'] = '/' . $bits['path'];
+ // bug 45069
+ if ( isset( $bits['path'] ) ) {
+ /* parse_url loses the third / for file:///c:/ urls (but not on variants) */
+ if ( substr( $bits['path'], 0, 1 ) !== '/' ) {
+ $bits['path'] = '/' . $bits['path'];
+ }
+ } else {
+ $bits['path'] = '';
}
}
* @return string|bool The output number as a string, or false on error
*/
function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, $lowercase = true, $engine = 'auto' ) {
+ $input = (string)$input;
if(
$sourceBase < 2 ||
$sourceBase > 36 ||
* Make an HTML list of templates, and then add a "More..." link at
* the bottom. If $more is null, do not add a "More..." link. If $more
* is a Title, make a link to that title and use it. If $more is a string,
- * directly paste it in as the link.
+ * directly paste it in as the link (escaping needs to be done manually).
+ * Finally, if $more is a Message, call toString().
*
- * @param $templates Array of templates from Article::getUsedTemplate
- * or similar
+ * @param array $templates Array of templates from Article::getUsedTemplate or similar
* @param bool $preview Whether this is for a preview
* @param bool $section Whether this is for a section edit
- * @param Title|string|null $more A link for "More..." of the templates
+ * @param Title|Message|string|null $more An escaped link for "More..." of the templates
* @return String: HTML output
*/
public static function formatTemplates( $templates, $preview = false, $section = false, $more = null ) {
$this->language = $wgLang;
}
+ /**
+ * Returns the message key
+ *
+ * @since 1.21
+ *
+ * @return string
+ */
+ public function getKey() {
+ return $this->key;
+ }
+
+ /**
+ * Returns the message parameters
+ *
+ * @since 1.21
+ *
+ * @return string[]
+ */
+ public function getParams() {
+ return $this->parameters;
+ }
+
+ /**
+ * Returns the message format
+ *
+ * @since 1.21
+ *
+ * @return string
+ */
+ public function getFormat() {
+ return $this->format;
+ }
+
/**
* Factory function that is just wrapper for the real constructor. It is
* intented to be used instead of the real constructor, because it allows
/**
* Get the error message as HTML. This is done by parsing the wikitext error
* message.
+ *
+ * @note: this does not perform a full wikitext to HTML conversion, it merely applies
+ * a message transformation.
+ * @todo: figure out whether that is actually The Right Thing.
*/
public function getHTML( $shortContext = false, $longContext = false ) {
$text = $this->getWikiText( $shortContext, $longContext );
*/
private function checkQuickPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) {
if ( $action == 'create' ) {
- if ( ( $this->isTalkPage() && !$user->isAllowed( 'createtalk' ) ) ||
- ( !$this->isTalkPage() && !$user->isAllowed( 'createpage' ) ) ) {
+ if (
+ ( $this->isTalkPage() && !$user->isAllowed( 'createtalk' ) ) ||
+ ( !$this->isTalkPage() && !$user->isAllowed( 'createpage' ) )
+ ) {
$errors[] = $user->isAnon() ? array( 'nocreatetext' ) : array( 'nocreate-loggedin' );
}
} elseif ( $action == 'move' ) {
$errors = $this->resultToError( $errors, $result );
}
// Check getUserPermissionsErrorsExpensive hook
- if ( $doExpensiveQueries && !( $short && count( $errors ) > 0 ) &&
- !wfRunHooks( 'getUserPermissionsErrorsExpensive', array( &$this, &$user, $action, &$result ) ) ) {
+ if (
+ $doExpensiveQueries
+ && !( $short && count( $errors ) > 0 )
+ && !wfRunHooks( 'getUserPermissionsErrorsExpensive', array( &$this, &$user, $action, &$result ) )
+ ) {
$errors = $this->resultToError( $errors, $result );
}
public function userCanEditJsSubpage() {
global $wgUser;
wfDeprecated( __METHOD__, '1.19' );
- return ( ( $wgUser->isAllowedAll( 'editusercssjs', 'edituserjs' ) )
- || preg_match( '/^' . preg_quote( $wgUser->getName(), '/' ) . '\//', $this->mTextform ) );
+ return (
+ ( $wgUser->isAllowedAll( 'editusercssjs', 'edituserjs' ) )
+ || preg_match( '/^' . preg_quote( $wgUser->getName(), '/' ) . '\//', $this->mTextform )
+ );
}
/**
if ( $getPages ) {
$cols = array( 'pr_page', 'page_namespace', 'page_title',
- 'pr_expiry', 'pr_type', 'pr_level' );
+ 'pr_expiry', 'pr_type', 'pr_level' );
$where_clauses[] = 'page_id=pr_page';
$tables[] = 'page';
} else {
$pagerestrictions[$row->pr_type] = array();
}
- if ( isset( $pagerestrictions[$row->pr_type] ) &&
- !in_array( $row->pr_level, $pagerestrictions[$row->pr_type] ) ) {
+ if (
+ isset( $pagerestrictions[$row->pr_type] )
+ && !in_array( $row->pr_level, $pagerestrictions[$row->pr_type] )
+ ) {
$pagerestrictions[$row->pr_type][] = $row->pr_level;
}
} else {
# Pages with "/./" or "/../" appearing in the URLs will often be un-
# reachable due to the way web browsers deal with 'relative' URLs.
# Also, they conflict with subpage syntax. Forbid them explicitly.
- if ( strpos( $dbkey, '.' ) !== false &&
- ( $dbkey === '.' || $dbkey === '..' ||
- strpos( $dbkey, './' ) === 0 ||
- strpos( $dbkey, '../' ) === 0 ||
- strpos( $dbkey, '/./' ) !== false ||
- strpos( $dbkey, '/../' ) !== false ||
- substr( $dbkey, -2 ) == '/.' ||
- substr( $dbkey, -3 ) == '/..' ) )
- {
+ if (
+ strpos( $dbkey, '.' ) !== false &&
+ (
+ $dbkey === '.' || $dbkey === '..' ||
+ strpos( $dbkey, './' ) === 0 ||
+ strpos( $dbkey, '../' ) === 0 ||
+ strpos( $dbkey, '/./' ) !== false ||
+ strpos( $dbkey, '/../' ) !== false ||
+ substr( $dbkey, -2 ) == '/.' ||
+ substr( $dbkey, -3 ) == '/..'
+ )
+ ) {
return false;
}
# underlying database field. We make an exception for special pages, which
# don't need to be stored in the database, and may edge over 255 bytes due
# to subpage syntax for long titles, e.g. [[Special:Block/Long name]]
- if ( ( $this->mNamespace != NS_SPECIAL && strlen( $dbkey ) > 255 ) ||
- strlen( $dbkey ) > 512 )
- {
+ if (
+ ( $this->mNamespace != NS_SPECIAL && strlen( $dbkey ) > 255 )
+ || strlen( $dbkey ) > 512
+ ) {
return false;
}
if ( strlen( $nt->getDBkey() ) < 1 ) {
$errors[] = array( 'articleexists' );
}
- if ( ( $this->getDBkey() == '' ) ||
- ( !$oldid ) ||
- ( $nt->getDBkey() == '' ) ) {
+ if (
+ ( $this->getDBkey() == '' ) ||
+ ( !$oldid ) ||
+ ( $nt->getDBkey() == '' )
+ ) {
$errors[] = array( 'badarticleerror' );
}
}
$old_cmp = '>';
$new_cmp = '<';
- $options = (array) $options;
+ $options = (array)$options;
if ( in_array( 'include_old', $options ) ) {
$old_cmp = '>=';
}
/**
* Set the password and reset the random token unconditionally.
*
- * @param $str String New password to set
+ * @param $str string|null New password to set or null to set an invalid
+ * password hash meaning that the user will not be able to log in
+ * through the web interface.
*/
public function setInternalPassword( $str ) {
$this->load();
// Hide "This page is a member of # hidden categories" explanation
$content .= Html::element( 'style', array(),
- '.mw-hiddenCategoriesExplanation { display: none; }' );
+ '.mw-hiddenCategoriesExplanation { display: none; }' ) . "\n";
// Hide "Templates used on this page" explanation
$content .= Html::element( 'style', array(),
- '.mw-templatesUsedExplanation { display: none; }' );
+ '.mw-templatesUsedExplanation { display: none; }' ) . "\n";
// Get page information
$pageInfo = $this->pageInfo();
// Render page information
foreach ( $pageInfo as $header => $infoTable ) {
- $content .= $this->makeHeader( $this->msg( "pageinfo-${header}" )->escaped() );
- $table = '';
+ $content .= $this->makeHeader( $this->msg( "pageinfo-${header}" )->escaped() ) . "\n";
+ $table = "\n";
foreach ( $infoTable as $infoRow ) {
$name = ( $infoRow[0] instanceof Message ) ? $infoRow[0]->escaped() : $infoRow[0];
$value = ( $infoRow[1] instanceof Message ) ? $infoRow[1]->escaped() : $infoRow[1];
- $table = $this->addRow( $table, $name, $value );
+ $table = $this->addRow( $table, $name, $value ) . "\n";
}
- $content = $this->addTable( $content, $table );
+ $content = $this->addTable( $content, $table ) . "\n";
}
// Page footer
public function setWarning( $warning ) {
$result = $this->getResult();
$data = $result->getData();
- if ( isset( $data['warnings'][$this->getModuleName()] ) ) {
+ $moduleName = $this->getModuleName();
+ if ( isset( $data['warnings'][$moduleName] ) ) {
// Don't add duplicate warnings
- $warn_regex = preg_quote( $warning, '/' );
- if ( preg_match( "/{$warn_regex}(\\n|$)/", $data['warnings'][$this->getModuleName()]['*'] ) ) {
- return;
+ $oldWarning = $data['warnings'][$moduleName]['*'];
+ $warnPos = strpos( $oldWarning, $warning );
+ // If $warning was found in $oldWarning, check if it starts at 0 or after "\n"
+ if ( $warnPos !== false && ( $warnPos === 0 || $oldWarning[$warnPos - 1] === "\n" ) ) {
+ // Check if $warning is followed by "\n" or the end of the $oldWarning
+ $warnPos += strlen( $warning );
+ if ( strlen( $oldWarning ) <= $warnPos || $oldWarning[$warnPos] === "\n" ) {
+ return;
+ }
}
- $oldwarning = $data['warnings'][$this->getModuleName()]['*'];
// If there is a warning already, append it to the existing one
- $warning = "$oldwarning\n$warning";
- $result->unsetValue( 'warnings', $this->getModuleName() );
+ $warning = "$oldWarning\n$warning";
}
$msg = array();
ApiResult::setContent( $msg, $warning );
$result->disableSizeCheck();
- $result->addValue( 'warnings', $this->getModuleName(), $msg );
+ $result->addValue( 'warnings', $moduleName,
+ $msg, ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP );
$result->enableSizeCheck();
}
$wgTitle = $titleObj;
$articleObject = new Article( $titleObj );
+
+ $articleContext = new RequestContext;
+ $articleContext->setRequest( $req );
+ $articleContext->setTitle( $titleObj );
+ $articleObject->setContext( $articleContext );
+
$ep = new EditPage( $articleObject );
// allow editing of non-textual content.
/**
* Initialize the printer function and prepare the output headers, etc.
- * This method must be the first outputing method during execution.
- * A help screen's header is printed for the HTML-based output
- * @param $isError bool Whether an error message is printed
+ * This method must be the first outputting method during execution.
+ * A human-targeted notice about available formats is printed for the HTML-based output,
+ * except for help screens (caused by either an error in the API parameters,
+ * the calling of action=help, or requesting the root script api.php).
+ * @param $isHelpScreen bool Whether a help screen is going to be shown
*/
- function initPrinter( $isError ) {
+ function initPrinter( $isHelpScreen ) {
if ( $this->mDisabled ) {
return;
}
<?php
- if ( !$isError ) {
+ if ( !$isHelpScreen ) {
?>
<br />
<small>
See the <a href='https://www.mediawiki.org/wiki/API'>complete documentation</a>, or
<a href='<?php echo( $script ); ?>'>API help</a> for more information.
</small>
+<pre style='white-space: pre-wrap;'>
<?php
- }
+ } else { // don't wrap the contents of the <pre> for help screens
+ // because these are actually formatted to rely on
+ // the monospaced font for layout purposes
?>
<pre>
<?php
-
+ }
}
}
}
/**
- * Sets whether the pretty-printer should format *bold* and $italics$
+ * Sets whether the pretty-printer should format *bold*
* @param $help bool
*/
public function setHelp( $help = true ) {
protected function formatHTML( $text ) {
// Escape everything first for full coverage
$text = htmlspecialchars( $text );
-
// encode all comments or tags as safe blue strings
$text = str_replace( '<', '<span style="color:blue;"><', $text );
$text = str_replace( '>', '></span>', $text );
- // identify URLs
- $protos = wfUrlProtocolsWithoutProtRel();
- // This regex hacks around bug 13218 (" included in the URL)
- $text = preg_replace( "#(((?i)$protos).*?)(")?([ \\'\"<>\n]|<|>|")#", '<a href="\\1">\\1</a>\\3\\4', $text );
// identify requests to api.php
$text = preg_replace( "#api\\.php\\?[^ <\n\t]+#", '<a href="\\0">\\0</a>', $text );
if ( $this->mHelp ) {
// make strings inside * bold
$text = preg_replace( "#\\*[^<>\n]+\\*#", '<b>\\0</b>', $text );
- // make strings inside $ italic
- $text = preg_replace( "#\\$[^<>\n]+\\$#", '<b><i>\\0</i></b>', $text );
}
+ // identify URLs
+ $protos = wfUrlProtocolsWithoutProtRel();
+ // This regex hacks around bug 13218 (" included in the URL)
+ $text = preg_replace( "#(((?i)$protos).*?)(")?([ \\'\"<>\n]|<|>|")#", '<a href="\\1">\\1</a>\\3\\4', $text );
/**
* Temporary fix for bad links in help messages. As a special case,
* tell the printer not to escape ampersands so that our links do
* not break.
*/
- $printer->setUnescapeAmps( ( $this->mAction == 'help' || $isError )
- && $printer->getFormat() == 'XML' && $printer->getIsHtml() );
+ $isHelp = $isError || $this->mAction == 'help';
+ $printer->setUnescapeAmps( $isHelp && $printer->getFormat() == 'XML' && $printer->getIsHtml() );
- $printer->initPrinter( $isError );
+ $printer->initPrinter( $isHelp );
$printer->execute();
$printer->closePrinter();
'converttitles' => false,
);
if ( $this->mAllowGenerator ) {
- $result['generator'] = array(
- ApiBase::PARAM_TYPE => $this->getGenerators() );
+ if ( $flags & ApiBase::GET_VALUES_FOR_HELP ) {
+ $result['generator'] = array(
+ ApiBase::PARAM_TYPE => $this->getGenerators()
+ );
+ } else {
+ $result['generator'] = null;
+ }
}
return $result;
}
// we must create it to get module manager
$query = $this->getMain()->getModuleManager()->getModule( 'query' );
}
- $gens = array_keys( $query->getGenerators() );
+ $gens = array();
+ $mgr = $query->getModuleManager();
+ foreach ( $mgr->getNamesWithClasses() as $name => $class ) {
+ if ( is_subclass_of( $class, 'ApiQueryGeneratorBase' ) ) {
+ $gens[] = $name;
+ }
+ }
sort( $gens );
self::$generators = $gens;
}
'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',
- 'alltransclusions' => 'ApiQueryAllLinks',
- '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',
- );
-
/**
* @var ApiPageSet
*/
$this->mModuleMgr->addModules( self::$QueryMetaModules, 'meta' );
$this->mModuleMgr->addModules( $wgAPIMetaModules, 'meta' );
- global $wgAPIGeneratorModules;
- if ( is_array( $wgAPIGeneratorModules ) ) {
- foreach ( $wgAPIGeneratorModules as $moduleName => $moduleClass ) {
- $this->mQueryGenerators[$moduleName] = $moduleClass;
- }
- }
-
// Create PageSet that will process titles/pageids/revids/generator
$this->mPageSet = new ApiPageSet( $this );
}
/**
* Get the generators array mapping module names to class names
+ * @deprecated since 1.21, list of generators is maintained by ApiPageSet
* @return array array(modulename => classname)
*/
public function getGenerators() {
- return $this->mQueryGenerators;
+ wfDeprecated( __METHOD__, '1.21' );
+ $gens = array();
+ foreach ( $this->mModuleMgr->getNamesWithClasses() as $name => $class ) {
+ if ( is_subclass_of( $class, 'ApiQueryGeneratorBase' ) ) {
+ $gens[$name] = $class;
+ }
+ }
+ return $gens;
}
/**
'exportnowrap' => false,
'iwurl' => false,
);
- if( $flags ) {
+ if ( $flags ) {
$result += $this->getPageSet()->getFinalParams( $flags );
}
return $result;
$msg = array( $paramName => $paramValue );
$result = $this->getResult();
$result->disableSizeCheck();
- $result->addValue( 'query-continue', $this->getModuleName(), $msg );
+ $result->addValue( 'query-continue', $this->getModuleName(), $msg, ApiResult::ADD_ON_TOP );
$result->enableSizeCheck();
}
* @ingroup API
*/
class ApiQueryImageInfo extends ApiQueryBase {
+ const TRANSFORM_LIMIT = 50;
+ private static $transformCount = 0;
public function __construct( $query, $moduleName, $prefix = 'ii' ) {
// We allow a subclass to override the prefix, to create a related API module.
$img = $images[$title];
+ if ( self::getTransformCount() >= self::TRANSFORM_LIMIT ) {
+ if ( count( $pageIds[NS_FILE] ) == 1 ) {
+ // See the 'the user is screwed' comment below
+ $this->setContinueEnumParameter( 'start',
+ $start !== null ? $start : wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
+ );
+ } else {
+ $this->setContinueEnumParameter( 'continue',
+ $this->getContinueStr( $img, $start ) );
+ }
+ break;
+ }
+
$fit = $result->addValue(
array( 'query', 'pages', intval( $pageId ) ),
'imagerepository', $img->getRepoName()
if ( $url ) {
if ( !is_null( $thumbParams ) ) {
$mto = $file->transform( $thumbParams );
+ self::$transformCount++;
if ( $mto && !$mto->isError() ) {
$vals['thumburl'] = wfExpandUrl( $mto->getUrl(), PROTO_CURRENT );
return $vals;
}
+ /**
+ * Get the count of image transformations performed
+ *
+ * If this is >= TRANSFORM_LIMIT, you should probably stop processing images.
+ *
+ * @return integer count
+ */
+ static function getTransformCount() {
+ return self::$transformCount;
+ }
+
/**
*
* @param $metadata Array
}
# Force a sort order to ensure that properties are grouped by page
- $this->addOption( 'ORDER BY', 'pp_page' );
+ # But only if pp_page is not constant in the WHERE clause.
+ if ( count( $pages ) > 1 ) {
+ $this->addOption( 'ORDER BY', 'pp_page' );
+ }
$res = $this->select( __METHOD__ );
$currentPage = 0; # Id of the page currently processed
public function getAllowedParams() {
return array(
'continue' => null,
- 'prop' => null,
+ 'prop' => array(
+ ApiBase::PARAM_ISMULTI => true,
+ ),
);
}
public function getParamDescription() {
return array(
'continue' => 'When more results are available, use this to continue',
- 'prop' => 'Page prop to look on the page for. Useful for checking whether a certain page uses a certain page prop.'
+ 'prop' => 'Only list these props. Useful for checking whether a certain page uses a certain page prop',
);
}
*/
class ApiResult extends ApiBase {
+ /**
+ * override existing value in addValue() and setElement()
+ * @since 1.21
+ */
+ const OVERRIDE = 1;
+
+ /**
+ * For addValue() and setElement(), if the value does not exist, add it as the first element.
+ * In case the new value has no name (numerical index), all indexes will be renumbered.
+ * @since 1.21
+ */
+ const ADD_ON_TOP = 2;
+
private $mData, $mIsRawMode, $mSize, $mCheckingSize;
/**
* @param $arr array to add $value to
* @param $name string Index of $arr to add $value at
* @param $value mixed
- * @param $overwrite bool Whether overwriting an existing element is allowed
+ * @param $flags int Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP. This parameter used to be
+ * boolean, and the value of OVERRIDE=1 was specifically chosen so that it would be backwards
+ * compatible with the new method signature.
+ *
+ * @since 1.21 int $flags replaced boolean $override
*/
- public static function setElement( &$arr, $name, $value, $overwrite = false ) {
+ public static function setElement( &$arr, $name, $value, $flags = 0 ) {
if ( $arr === null || $name === null || $value === null || !is_array( $arr ) || is_array( $name ) ) {
ApiBase::dieDebug( __METHOD__, 'Bad parameter' );
}
- if ( !isset ( $arr[$name] ) || $overwrite ) {
- $arr[$name] = $value;
+ $exists = isset( $arr[$name] );
+ if ( !$exists || ( $flags & ApiResult::OVERRIDE ) ) {
+ if ( !$exists && ( $flags & ApiResult::ADD_ON_TOP ) ) {
+ $arr = array( $name => $value ) + $arr;
+ } else {
+ $arr[$name] = $value;
+ }
} elseif ( is_array( $arr[$name] ) && is_array( $value ) ) {
$merged = array_intersect_key( $arr[$name], $value );
if ( !count( $merged ) ) {
* @param $path array|string|null
* @param $name string
* @param $value mixed
- * @param $overwrite bool
- *
+ * @param $flags int Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP. This parameter used to be
+ * boolean, and the value of OVERRIDE=1 was specifically chosen so that it would be backwards
+ * compatible with the new method signature.
* @return bool True if $value fits in the result, false if not
+ *
+ * @since 1.21 int $flags replaced boolean $override
*/
- public function addValue( $path, $name, $value, $overwrite = false ) {
+ public function addValue( $path, $name, $value, $flags = 0 ) {
global $wgAPIMaxResultSize;
$data = &$this->mData;
$this->mSize = $newsize;
}
- if ( !is_null( $path ) ) {
- if ( is_array( $path ) ) {
- foreach ( $path as $p ) {
- if ( !isset( $data[$p] ) ) {
+ $addOnTop = $flags & ApiResult::ADD_ON_TOP;
+ if ( $path !== null ) {
+ foreach ( (array) $path as $p ) {
+ if ( !isset( $data[$p] ) ) {
+ if ( $addOnTop ) {
+ $data = array( $p => array() ) + $data;
+ $addOnTop = false;
+ } else {
$data[$p] = array();
}
- $data = &$data[$p];
}
- } else {
- if ( !isset( $data[$path] ) ) {
- $data[$path] = array();
- }
- $data = &$data[$path];
+ $data = &$data[$p];
}
}
if ( !$name ) {
- $data[] = $value; // Add list element
+ // Add list element
+ if ( $addOnTop ) {
+ // This element needs to be inserted in the beginning
+ // Numerical indexes will be renumbered
+ array_unshift( $data, $value );
+ } else {
+ // Add new value at the end
+ $data[] = $value;
+ }
} else {
- self::setElement( $data, $name, $value, $overwrite ); // Add named element
+ // Add named element
+ self::setElement( $data, $name, $value, $flags );
}
return true;
}
*/
public function setParsedLimit( $moduleName, $limit ) {
// Add value, allowing overwriting
- $this->addValue( 'limits', $moduleName, $limit, true );
+ $this->addValue( 'limits', $moduleName, $limit, ApiResult::OVERRIDE );
}
/**
* @return string|bool The text stored or false on error
* @throws MWException
*/
- public abstract function fetchFromURL( $url );
+ abstract public function fetchFromURL( $url );
/**
* Insert a data item into a given location
* @return string|bool The URL of the stored data item, or false on error
* @throws MWException
*/
- public abstract function store( $location, $data );
+ abstract public function store( $location, $data );
}
* $opts is an associative of boolean flags, including:
* - force : Operation precondition errors no longer trigger an abort.
* Any remaining operations are still attempted. Unexpected
- * failures may still cause remaning operations to be aborted.
+ * failures may still cause remaining operations to be aborted.
* - nonLocking : No locks are acquired for the operations.
* This can increase performance for non-critical writes.
* This has no effect unless the 'force' flag is set.
}
/**
- * @return bool
+ * @return bool Whether only one of each identical set of jobs should be run
*/
public function ignoreDuplicates() {
return $this->removeDuplicates;
}
+ /**
+ * @return bool Whether this job can be retried on failure by job runners
+ */
+ public function allowRetries() {
+ return true;
+ }
+
/**
* Subclasses may need to override this to make duplication detection work
*
return false;
}
+ $user = $this->getUser();
+ if ( !$user ) {
+ $this->setLastError( 'Invalid user' );
+ return false;
+ }
+
# Save it
global $wgUser;
$oldUser = $wgUser;
- $wgUser = $this->getUser();
+ $wgUser = $user;
$article = WikiPage::factory( $this->title );
$reason = wfMessage( 'double-redirect-fixed-' . $this->reason,
$this->redirTitle->getPrefixedText(), $newTitle->getPrefixedText()
)->inContentLanguage()->text();
- $article->doEditContent( $newContent, $reason, EDIT_UPDATE | EDIT_SUPPRESS_RC, false, $this->getUser() );
+ $article->doEditContent( $newContent, $reason, EDIT_UPDATE | EDIT_SUPPRESS_RC, false, $user );
$wgUser = $oldUser;
return true;
/**
* Get a user object for doing edits, from a request-lifetime cache
- * @return User
+ * False will be returned if the user name specified in the
+ * 'double-redirect-fixer' message is invalid.
+ *
+ * @return User|bool
*/
function getUser() {
if ( !self::$user ) {
- self::$user = User::newFromName( wfMessage( 'double-redirect-fixer' )->inContentLanguage()->text(), false );
- # FIXME: newFromName could return false on a badly configured wiki.
- if ( !self::$user->isLoggedIn() ) {
+ self::$user = User::newFromName( wfMessage( 'double-redirect-fixer' )->inContentLanguage()->text() );
+ # User::newFromName() can return false on a badly configured wiki.
+ if ( self::$user && !self::$user->isLoggedIn() ) {
self::$user->addToDatabase();
}
}
/** */
+if ( PHP_SAPI != 'cli' ) {
+ die( "Run me from the command line please.\n" );
+}
+
require_once 'UtfNormalDefines.php';
require_once 'UtfNormalUtil.php';
require_once 'UtfNormal.php';
$verbose = false;
#$verbose = true;
-if( PHP_SAPI != 'cli' ) {
- die( "Run me from the command line please.\n" );
-}
$in = fopen( "UTF-8-test.txt", "rt" );
if( !$in ) {
* @ingroup UtfNormal
*/
+if( PHP_SAPI != 'cli' ) {
+ die( "Run me from the command line please.\n" );
+}
+
if( isset( $_SERVER['argv'] ) && in_array( '--icu', $_SERVER['argv'] ) ) {
dl( 'php_utfnormal.so' );
}
define( 'BENCH_CYCLES', 5 );
-if( PHP_SAPI != 'cli' ) {
- die( "Run me from the command line please.\n" );
-}
-
$testfiles = array(
'testdata/washington.txt' => 'English text',
'testdata/berlin.txt' => 'German text',
* @ingroup UtfNormal
*/
+if( PHP_SAPI != 'cli' ) {
+ die( "Run me from the command line please.\n" );
+}
+
if( isset( $_SERVER['argv'] ) && in_array( '--icu', $_SERVER['argv'] ) ) {
dl( 'php_utfnormal.so' );
}
define( 'BIGSIZE', 1024 * 1024 * 10); // 10m
ini_set('memory_limit', BIGSIZE + 120 * 1024 * 1024);
-if( PHP_SAPI != 'cli' ) {
- die( "Run me from the command line please.\n" );
-}
-
$testfiles = array(
'testdata/washington.txt' => 'English text',
'testdata/berlin.txt' => 'German text',
* @ingroup UtfNormal
*/
+if( PHP_SAPI != 'cli' ) {
+ die( "Run me from the command line please.\n" );
+}
+
$verbose = true;
#define( 'PRETTY_UTF8', true );
require_once 'UtfNormalUtil.php';
require_once 'UtfNormal.php';
-if( PHP_SAPI != 'cli' ) {
- die( "Run me from the command line please.\n" );
-}
-
$in = fopen("NormalizationTest.txt", "rt");
if( !$in ) {
print "Couldn't open NormalizationTest.txt -- can't run tests.\n";
function execute( $code ) {
$this->setHeaders();
- if ( wfReadOnly() ) {
- throw new ReadOnlyError;
- }
+ $this->checkReadOnly();
$this->attemptInvalidate( $code );
}
return Status::newFatal( 'noname' );
} elseif ( 0 != $u->idForName() ) {
return Status::newFatal( 'userexists' );
- } elseif ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
- return Status::newFatal( 'badretype' );
}
- # check for minimal password length
- $valid = $u->getPasswordValidity( $this->mPassword );
- if ( $valid !== true ) {
- if ( !$this->mCreateaccountMail ) {
+ if ( $this->mCreateaccountMail ) {
+ # do not force a password for account creation by email
+ # set invalid password, it will be replaced later by a random generated password
+ $this->mPassword = null;
+ } else {
+ if ( $this->mPassword !== $this->mRetype ) {
+ return Status::newFatal( 'badretype' );
+ }
+
+ # check for minimal password length
+ $valid = $u->getPasswordValidity( $this->mPassword );
+ if ( $valid !== true ) {
if ( !is_array( $valid ) ) {
$valid = array( $valid, $wgMinimalPasswordLength );
}
return call_user_func_array( 'Status::newFatal', $valid );
- } else {
- # do not force a password for account creation by email
- # set invalid password, it will be replaced later by a random generated password
- $this->mPassword = null;
}
}
*/
private function IPInfo() {
$ip = str_replace( '--', ' - ', htmlspecialchars( $this->getRequest()->getIP() ) );
- return "<!-- visited from $ip -->\n" .
- "<span style='display:none'>visited from $ip</span>";
+ return "<!-- visited from $ip -->\n<span style='display:none'>visited from $ip</span>";
}
/**
# Extract variables from the request, falling back to user preferences or
# other default values if these don't exist
- $prefs['days'] = floatval( $user->getOption( 'watchlistdays' ) );
- $prefs['hideminor'] = $user->getBoolOption( 'watchlisthideminor' );
- $prefs['hidebots'] = $user->getBoolOption( 'watchlisthidebots' );
- $prefs['hideanons'] = $user->getBoolOption( 'watchlisthideanons' );
- $prefs['hideliu'] = $user->getBoolOption( 'watchlisthideliu' );
- $prefs['hideown'] = $user->getBoolOption( 'watchlisthideown' );
- $prefs['hidepatrolled'] = $user->getBoolOption( 'watchlisthidepatrolled' );
- $prefs['extended'] = $user->getBoolOption( 'extendwatchlist' );
-
- # Get query variables
$values = array();
- $values['days'] = $request->getVal( 'days', $prefs['days'] );
- $values['hideMinor'] = (int)$request->getBool( 'hideMinor', $prefs['hideminor'] );
- $values['hideBots'] = (int)$request->getBool( 'hideBots', $prefs['hidebots'] );
- $values['hideAnons'] = (int)$request->getBool( 'hideAnons', $prefs['hideanons'] );
- $values['hideLiu'] = (int)$request->getBool( 'hideLiu', $prefs['hideliu'] );
- $values['hideOwn'] = (int)$request->getBool( 'hideOwn', $prefs['hideown'] );
- $values['hidePatrolled'] = (int)$request->getBool( 'hidePatrolled', $prefs['hidepatrolled'] );
- $values['extended'] = (int)$request->getBool( 'extended', $prefs['extended'] );
+ $values['days'] = $request->getVal( 'days', $defaults['days'] );
+ $values['hideMinor'] = (int)$request->getBool( 'hideMinor', $defaults['hideMinor'] );
+ $values['hideBots'] = (int)$request->getBool( 'hideBots', $defaults['hideBots'] );
+ $values['hideAnons'] = (int)$request->getBool( 'hideAnons', $defaults['hideAnons'] );
+ $values['hideLiu'] = (int)$request->getBool( 'hideLiu', $defaults['hideLiu'] );
+ $values['hideOwn'] = (int)$request->getBool( 'hideOwn', $defaults['hideOwn'] );
+ $values['hidePatrolled'] = (int)$request->getBool( 'hidePatrolled', $defaults['hidePatrolled'] );
+ $values['extended'] = (int)$request->getBool( 'extended', $defaults['extended'] );
foreach( $this->customFilters as $key => $params ) {
$values[$key] = (int)$request->getBool( $key );
}
$form = Xml::fieldset( $this->msg( 'watchlist-options' )->text(), false, array( 'id' => 'mw-watchlist-options' ) );
# Show watchlist header
- $form .= $this->msg( 'watchlist-details' )->numParams( $nitems )->parse();
+ $form .= $this->msg( 'watchlist-details' )->numParams( $nitems )->parse() . "\n";
if( $user->getOption( 'enotifwatchlistpages' ) && $wgEnotifWatchlist) {
$form .= $this->msg( 'wlheader-enotif' )->parseAsBlock() . "\n";
if( $wgShowUpdatedMarker ) {
$form .= Xml::openElement( 'form', array( 'method' => 'post',
'action' => $this->getTitle()->getLocalUrl(),
- 'id' => 'mw-watchlist-resetbutton' ) ) .
- $this->msg( 'wlheader-showupdated' )->parse() . ' ' .
- Xml::submitButton( $this->msg( 'enotif_reset' )->text(), array( 'name' => 'dummy' ) ) .
- Html::hidden( 'reset', 'all' );
+ 'id' => 'mw-watchlist-resetbutton' ) ) . "\n" .
+ $this->msg( 'wlheader-showupdated' )->parse() .
+ Xml::submitButton( $this->msg( 'enotif_reset' )->text(), array( 'name' => 'dummy' ) ) . "\n" .
+ Html::hidden( 'reset', 'all' ) . "\n";
foreach ( $nondefaults as $key => $value ) {
- $form .= Html::hidden( $key, $value );
+ $form .= Html::hidden( $key, $value ) . "\n";
}
- $form .= Xml::closeElement( 'form' );
+ $form .= Xml::closeElement( 'form' ) . "\n";
}
- $form .= '<hr />';
+ $form .= "<hr />\n";
$tables = array( 'recentchanges', 'watchlist' );
$fields = RecentChange::selectFields();
if( $values['days'] > 0 ) {
$timestamp = wfTimestampNow();
$wlInfo = $this->msg( 'wlnote' )->numParams( $numRows, round( $values['days'] * 24 ) )->params(
- $lang->userDate( $timestamp, $user ), $lang->userTime( $timestamp, $user ) )->parse() . '<br />';
+ $lang->userDate( $timestamp, $user ), $lang->userTime( $timestamp, $user ) )->parse() . "<br />\n";
}
- $cutofflinks = "\n" . $this->cutoffLinks( $values['days'], $nondefaults ) . "<br />\n";
+ $cutofflinks = $this->cutoffLinks( $values['days'], $nondefaults ) . "<br />\n";
# Spit out some control panel links
$filters = array(
$links[] = $this->showHideLink( $nondefaults, $msg, $name, $values[$name] );
}
+ $hiddenFields = $nondefaults;
+ unset( $hiddenFields['namespace'] );
+ unset( $hiddenFields['invert'] );
+ unset( $hiddenFields['associated'] );
+
# Namespace filter and put the whole form together.
$form .= $wlInfo;
$form .= $cutofflinks;
- $form .= $lang->pipeList( $links );
- $form .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getTitle()->getLocalUrl(), 'id' => 'mw-watchlist-form-namespaceselector' ) );
- $form .= '<hr /><p>';
+ $form .= $lang->pipeList( $links ) . "\n";
+ $form .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getTitle()->getLocalUrl(), 'id' => 'mw-watchlist-form-namespaceselector' ) ) . "\n";
+ $form .= "<hr />\n<p>";
$form .= Html::namespaceSelector(
array(
'selected' => $nameSpace,
$associated,
array( 'title' => $this->msg( 'tooltip-namespace_association' )->text() )
) . ' ';
- $form .= Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . '</p>';
- $form .= Html::hidden( 'days', $values['days'] );
- foreach ( $filters as $key => $msg ) {
- if ( $values[$key] ) {
- $form .= Html::hidden( $key, 1 );
- }
+ $form .= Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . "</p>\n";
+ foreach ( $hiddenFields as $key => $value ) {
+ $form .= Html::hidden( $key, $value ) . "\n";
}
- $form .= Xml::closeElement( 'form' );
- $form .= Xml::closeElement( 'fieldset' );
+ $form .= Xml::closeElement( 'form' ) . "\n";
+ $form .= Xml::closeElement( 'fieldset' ) . "\n";
$output->addHTML( $form );
# If there's nothing to show, stop here
# Namespace 8 related
'allmessages' => 'ܐܓܪ̈ܬܐ ܕܛܟܣܐ',
'allmessagesname' => 'ܫܡܐ',
+'allmessagesdefault' => 'ܐܓܪܬܐ ܕܟܬܒܬܐ ܡܬܚܫܒܢܝܬܐ',
'allmessagescurrent' => 'ܟܬܒܬܐ ܗܫܝܬܐ ܕܐܓܪܬܐ',
'allmessages-filter-legend' => 'ܡܨܦܝܢܝܬܐ',
+'allmessages-filter' => 'ܨܦܝ ܐܝܟ ܐܝܟܢܝܘܬܐ ܕܡܬܕܝܠܢܘܬܐ:',
+'allmessages-filter-unmodified' => 'ܠܐ ܫܘܓܢܝܐ',
'allmessages-filter-all' => 'ܟܠ',
+'allmessages-filter-modified' => 'ܫܘܓܢܝܐ',
'allmessages-prefix' => 'ܡܨܦܝܢܝܬܐ ܐܝܟ ܫܘܪܝܐ',
'allmessages-language' => 'ܠܫܢܐ:',
'allmessages-filter-submit' => 'ܙܠ',
'specialpages-group-highuse' => 'ܦܐܬܬ̈ܐ ܕܡܬܚܫܚܢܘܬܐ ܥܠܝܬܐ',
'specialpages-group-pages' => 'ܡܟܬܒܘܬ̈ܐ ܕܦܐܬܬ̈ܐ',
'specialpages-group-pagetools' => 'ܡܐܢ̈ܐ ܕܦܐܬܐ',
-'specialpages-group-wiki' => 'ܠܝܬ̈ܐ ܘܡܐܢ̈ܐ',
+'specialpages-group-wiki' => 'Ü\93Ü Ü\9dܬÌ\88Ü\90 Ü\98Ü¡Ü\90Ü¢Ì\88Ü\90',
'specialpages-group-redirects' => 'ܨܘܝܒܐ ܕܦܐܬܐ ܕܝܠܢܝܬܐ',
# Special:BlankPage
'italic_sample' => 'इटालिक पाठ्य',
'italic_tip' => 'इटालिक पाठ्य',
'headline_sample' => 'शिर्षक पाठ्य',
+'headline_tip' => 'द्वितीय-श्रेणी के शीर्षक',
'image_sample' => 'उदाहरण.jpg',
'media_sample' => 'उदाहरण.ogg',
'media_tip' => 'फाईल लिंक',
'yourdiff' => 'अंतर',
'template-protected' => '(संरक्षित)',
+# Parser/template warnings
+'post-expand-template-inclusion-category' => 'अइसन पृष्ठ जे पर साँचा जोडे के सीमा पार हो गइल बा',
+
# History pages
'revisionasof' => '$1 के रुप में संशोधन',
'revision-info' => '$2 में से $1 के रुप में संशोधन',
# Recent changes
'recentchanges' => 'तुरंत भईल परिवर्तन',
+'recentchanges-legend' => 'हाल के परिवर्तन संबंधी विकल्प',
+'recentchanges-label-newpage' => 'ई सम्पादन से एगो नवका पृष्ठ तैयार हो गइल बा',
+'recentchanges-label-minor' => 'ई एगो छोटा सम्पाद बा',
'rcshowhideminor' => '$1 छोट सम्पादन',
'diff' => 'अन्तर',
'hist' => 'इति',
'booksources' => 'किताबी स्त्रोत',
# Special:AllPages
+'alphaindexline' => '$1 से $2',
'allpagessubmit' => 'जाईं',
'allpagesprefix' => 'उपसर्ग के साथे पन्ना प्रदर्शन:',
'tooltip-ca-nstab-template' => 'टेम्प्लेट देखीं',
'tooltip-ca-nstab-category' => 'श्रेणी के पन्ना देखीं',
'tooltip-save' => 'आपन बदलाव के सुरक्षित करीं',
+'tooltip-preview' => 'आपन द्वारा कियल गइल बदलाव के देखीं, संजोये से पहले ईका इस्तेमाल करीं!',
'tooltip-rollback' => '"वापिस लीं" ई पन्ना के पिछ्ला योगदाता के बदलाव एकही चटके मे गायब कर देवेला',
'tooltip-summary' => 'एगो संक्षिप्त सारांश दर्ज करीं',
# General errors
'error' => 'Chyba',
-'databaseerror' => 'Databázová chyba',
+'databaseerror' => 'Chyba databáze',
'dberrortext' => 'Při dotazu do databáze došlo k syntaktické chybě.
Příčinou může být chyba v programu.
Poslední dotaz byl:
'tog-enotifminoredits' => 'Gyrru e-bost ataf hefyd ar gyfer golygiadau bychain i dudalennau a ffeiliau',
'tog-enotifrevealaddr' => 'Datguddio fy nghyfeiriad e-bost mewn e-byst hysbysu',
'tog-shownumberswatching' => "Dangos y nifer o ddefnyddwyr sy'n gwylio",
-'tog-oldsig' => 'Llofnod cyfredol:',
+'tog-oldsig' => 'Y llofnod cyfredol:',
'tog-fancysig' => 'Trin y llofnod fel testun wici (heb gyswllt wici awtomatig)',
'tog-externaleditor' => 'Defnyddio golygydd allanol trwy ragosodiad (ar gyfer arbenigwyr yn unig; mae arno angen gosodiadau arbennig ar eich cyfrifiadur. [//www.mediawiki.org/wiki/Manual:External_editors Rhagor o wybodaeth.])',
'tog-externaldiff' => 'Defnyddio "external diff" trwy ragosodiad (ar gyfer arbenigwyr yn unig; mae arno angen gosodiadau arbennig ar eich cyfrifiadur. [//www.mediawiki.org/wiki/Manual:External_editors Rhagor o wybodaeth.])',
'immobile-target-namespace-iw' => 'Nid yw cyswllt rhyngwici yn nod dilys wrth symud tudalen.',
'immobile-source-page' => 'Ni ellir symud y dudalen hon.',
'immobile-target-page' => "Ddim yn gallu symud i'r teitl newydd hwn.",
+'bad-target-model' => "Mae'r cyrchfan dewisedig yn defnyddio model gwahanol i'w chynnwys. Ni ellir trawsnewid o $1 i $2.",
'imagenocrossnamespace' => 'Ni ellir symud ffeil i barth arall',
'nonfile-cannot-move-to-file' => 'Ni ellir symud unrhywbeth heblaw ffeil i barth y ffeiliau',
'imagetypemismatch' => "Nid yw'r estyniad ffeil newydd yn cyfateb i'r math o ffeil",
'pageinfo-magic-words' => '{{PLURAL:$1|Gair|Gair|Geiriau}} hud ($1)',
'pageinfo-hidden-categories' => '{{PLURAL:$1|Categori|Categori|Categorïau}} cudd ($1)',
'pageinfo-templates' => '{{PLURAL:$1|Nodyn|Nodyn|Nodiadau}} a drawsgynhwyswyd ($1)',
+'pageinfo-transclusions' => '{{PLURAL:$1|Tudalen|Tudalen|Tudalennau}} y trawsgynhwyswyd y dudalen hon arnynt ($1)',
'pageinfo-toolboxlink' => 'Gwybodaeth am y dudalen',
'pageinfo-redirectsto' => 'Yn ailgyfeirio i',
+'pageinfo-redirectsto-info' => 'manylion',
+'pageinfo-contentpage' => 'Ymhlith tudalennau pwnc y wici',
+'pageinfo-contentpage-yes' => 'Ydi',
+'pageinfo-protect-cascading' => "Mae diogelu sgydol yn deillio o'r dudalen hon",
+'pageinfo-protect-cascading-yes' => 'Oes',
+'pageinfo-protect-cascading-from' => "Mae'r diogelu sgydol yn dechrau ar",
'pageinfo-category-info' => 'Gwybodaeth am y categori',
'pageinfo-category-pages' => 'Nifer y tudalennau',
'pageinfo-category-subcats' => 'Nifer yr is-gategorïau',
'markedaspatrollederror' => 'Ni ellir gosod marc ymweliad patrôl',
'markedaspatrollederrortext' => "Rhaid nodi'r union olygiad sydd angen marc ymweliad patrôl.",
'markedaspatrollederror-noautopatrol' => "Ni chaniateir i chi farcio'ch newidiadau eich hunan fel rhai derbyniol.",
+'markedaspatrollednotify' => 'Nodwyd bod y newid hwn i $1 wedi derbyn ymweliad patrôl.',
+'markedaspatrollederrornotify' => 'Methwyd rhoi marc ymweliad patrôl arni.',
# Patrol log
'patrol-log-page' => 'Lòg patrolio',
'exif-pixelydimension' => 'Lled y ddelwedd',
'exif-pixelxdimension' => 'Uchder y ddelwedd',
'exif-usercomment' => "Sylwadau'r defnyddiwr",
-'exif-relatedsoundfile' => 'Ffeil sain cysylltiedig',
+'exif-relatedsoundfile' => 'Ffeil sain gysylltiedig',
'exif-datetimeoriginal' => 'Dyddiad ac amser y cynhyrchwyd y data',
'exif-datetimedigitized' => 'Dyddiad ac amser y digiteiddiwyd',
'exif-subsectime' => 'Manylyn iseiliad amser newid y ffeil',
'exif-originaldocumentid' => 'ID unigryw y ddogfen wreiddiol',
'exif-licenseurl' => 'URL y drwydded hawlfraint',
'exif-morepermissionsurl' => 'Gwybodaeth trwyddedu amgen',
-'exif-attributionurl' => "Wrth ail-ddefnyddio'r gwaith yma, darparwch ddolen at",
-'exif-preferredattributionname' => "Wrth ail-ddefnyddio'r gwaith yma, cydnabyddwch",
+'exif-attributionurl' => "Wrth ailddefnyddio'r gwaith yma, darparwch ddolen at",
+'exif-preferredattributionname' => "Wrth ailddefnyddio'r gwaith yma, cydnabyddwch",
'exif-pngfilecomment' => 'Sylwadau ar y ffeil PNG',
'exif-disclaimer' => 'Ymwadiad',
'exif-contentwarning' => 'Rhybudd am y cynnwys',
# Scary transclusion
'scarytranscludedisabled' => '[Analluogwyd cynhwysiad rhyng-wici]',
-'scarytranscludefailed' => '[Methwyd â nôl y nodyn ar gyfer $1]',
+'scarytranscludefailed' => '[Methwyd nôl y nodyn ar gyfer $1]',
+'scarytranscludefailed-httpstatus' => '[Methwyd nôl y nodyn ar gyfer $1: HTTP $2]',
'scarytranscludetoolong' => "[Mae'r URL yn rhy hir]",
# Delete conflict
'fewestrevisions' => 'Seiten mit den wenigsten Versionen',
# Miscellaneous special pages
-'nbytes' => '$1 {{PLURAL:$1|Byte|Byte}}',
+'nbytes' => '$1 {{PLURAL:$1|Byte|Bytes}}',
'ncategories' => '$1 {{PLURAL:$1|Kategorie|Kategorien}}',
'ninterwikis' => '{{PLURAL:$1|Ein Interwikilink|$1 Interwikilinks}}',
'nlinks' => '{{PLURAL:$1|1 Link|$1 Links}}',
'revdelete-radio-set' => 'Kyllä',
'revdelete-radio-unset' => 'Ei',
'revdelete-suppress' => 'Häivytä tiedot myös ylläpitäjien näkyviltä samalla kun piilotat ne muilta käyttäjiltä',
-'revdelete-unsuppress' => 'Poista rajoitukset palautetuilta versiolta',
+'revdelete-unsuppress' => 'Poista rajoitukset palautetuilta versioilta',
'revdelete-log' => 'Syy',
'revdelete-submit' => 'Toteuta {{PLURAL:$1|valittuun versioon|valittuihin versioihin}}',
'revdelete-success' => "'''Version näkyvyys päivitetty.'''",
'revdelete-failure' => "'''Version näkyvyyttä ei voitu päivittää:'''
$1",
-'logdelete-success' => 'Tapahtuman näkyvyys asetettu.',
+'logdelete-success' => "'''Lokitapahtuman näkyvyyttä on muutettu.'''",
'logdelete-failure' => "'''Lokin näkyvyyttä ei voitu asettaa:'''
$1",
'revdel-restore' => 'muuta näkyvyyttä',
-'revdel-restore-deleted' => 'poistetut muutokset',
-'revdel-restore-visible' => 'näkyvät muutokset',
+'revdel-restore-deleted' => 'poistetut versiot',
+'revdel-restore-visible' => 'näkyvät versiot',
'pagehist' => 'Sivun muutoshistoria',
'deletedhist' => 'Poistettujen versioiden historia',
'revdelete-hide-current' => 'Virhe tapahtui $2, $1 päivätyn kohteen piilottamisessa: tämä on nykyinen versio. Sitä ei voi piilottaa.',
Sinulla ei ole oikeutta siihen.',
'revdelete-modify-no-access' => 'Virhe tapahtui $2, $1 kohteen muokkauksessa: tämä kohde on merkitty "rajoitetuksi". Sinulla ei ole oikeuksia sen muokkaukseen.',
'revdelete-modify-missing' => 'Virhe muuttaessa kohdetta, jonka tunnus on $1: Se puuttuu tietokannasta.',
-'revdelete-no-change' => "'''Varoitus:''' kohdalle $2 kello $1 on asetettu valmiiksi näkyvyysasetuksia.",
+'revdelete-no-change' => "'''Varoitus:''' kohteessa $2 kello $1 on jo valmiiksi haluamasi näkyvyysasetukset.",
'revdelete-concurrent-change' => 'Virhe $2, $1 päivätyn kohteen muokkauksessa: sen tilan on näköjään muuttanut joku sillä aikaa kun yritit muokata sitä. Ole hyvä ja tarkista lokit.',
'revdelete-only-restricted' => 'Virhe piilotettaessa $1 kello $2 päivättyä kohdetta: Et voi poistaa kohteita ylläpitäjien näkyviltä valitsematta myös jotain muuta näkyvyysasetusta.',
'revdelete-reason-dropdown' => '*Yleiset poistosyyt
'youhavenewmessagesmulti' => 'Դուք նոր ուղերձներ եք ստացել $1 վրա',
'editsection' => 'խմբագրել',
'editold' => 'խմբագրել',
-'viewsourceold' => 'Õ¤Õ«Õ¿Õ¥Õ¬ Õ¥Õ¬Õ¡Õ¿Õ¥Ö\84Õ½Õ¿ը',
+'viewsourceold' => 'Õ¤Õ«Õ¿Õ¥Õ¬ Õ¾Õ«Ö\84Õ«Õ¯Õ¸Õ¤Õ¥Ö\80ը',
'editlink' => 'խմբագրել',
'viewsourcelink' => 'դիտել ելատեքստը',
'editsectionhint' => 'Խմբագրել բաժինը. $1',
'wrong_wfQuery_params' => 'Անթույլատրելի պարամետրեր wfQuery() ֆունկցիայի համար<br />
Ֆունկցիա՝ $1<br />
Հայցում՝ $2',
-'viewsource' => 'Ô´Õ«Õ¿Õ¥Õ¬ Õ¥Õ¬Õ¡Õ¿Õ¥Ö\84Õ½Õ¿ը',
+'viewsource' => 'Ô´Õ«Õ¿Õ¥Õ¬ Õ¾Õ«Ö\84Õ«Õ¯Õ¸Õ¤Õ¥Ö\80ը',
'viewsource-title' => 'Դիտել $1 էջի աղբյուրը',
'actionthrottled' => 'Գործողությունը արգելափակվեց',
'actionthrottledtext' => 'Որպես հակա-սպամային միջոց, այս գործողության չափից շատ կատարումը կարճ ժամանակահատվածի ընթացքում սահմանափակված է։ Խնդրում ենք փորձել կրկին մի քանի րոպե անց։',
'edit-no-change' => 'Ձեր խմբագրումը անտեսվել է, քանի որ ոչ մի փոփոխություն չի կատարվել տեքստի մեջ։',
'defaultmessagetext' => 'Լռելյան տեքստը',
+# Content models
+'content-model-wikitext' => 'վիքիտեքստ',
+
# "Undo" feature
'undo-success' => 'Խմբագրումը կարող է հետ շրջվել։ Ստուգեք տարբերակների համեմատությունը ստորև, որպեսզի համոզվեք, որ դա է ձեզ հետաքրքրող փոփոխությունը և մատնահարեք «Հիշել էջը»՝ գործողությունն ավարտելու համար։',
'undo-failure' => 'Խմբագրումը չի կարող հետ շրջվել միջանկյալ խմբագրումների ընդհարման պատճառով։',
# Associated actions - in the sentence "You do not have permission to X"
'action-edit' => 'խմբագրել այս էջը',
'action-createpage' => 'Ստեղծել էջ',
+'action-move-rootuserpages' => 'տեղափոխել մասնակցի էջի արմատը',
+'action-movefile' => 'տեղափոխել այս ֆայլը',
'action-upload' => 'Բեռնել այս ֆայլը',
'action-upload_by_url' => 'Բեռնել այս ֆայլը URL-ից',
'action-delete' => 'Ջնջել այս էջը',
'uploadvirus' => 'Նիշքը պարունակում է վիրո՜ւս։ Տես $1',
'upload-source' => 'Աղբյուրը ֆայլի',
'sourcefilename' => 'Սկզբնական նիշք՝',
+'sourceurl' => 'Այդ Տեղի URL-ն՝',
'destfilename' => 'Նիշքի նոր անվանում՝',
'upload-description' => 'Ֆայլի մեկնաբանություն',
'upload-options' => 'Բեռնման ընտրանքներ',
'filewasdeleted' => 'Այս անվանմամբ նիշք նախկինում բեռնվել է և հետագայում ջնջվել։ Այն կրկին բեռնելուց առաջ խնդրում ենք ստուգել $1։',
'filename-bad-prefix' => "Բեռնվող նիշքի անվանումը սկսվում է '''<tt>«$1»</tt>''' արտահայտությամբ, որը ոչ-նկարագրական է և սովորաբար տրվում է թվային լուսանկարչական ապարատների կողմից։ Խնդրում ենք ընտրել ավելի նկարագրական անվանում ձեր նիշքի համար։",
'upload-success-subj' => 'Բեռնումը կատարված է',
+'upload-failure-subj' => 'Ներբեռնման սխալ',
+'upload-warning-subj' => 'Ներբեռնման զգուշացում',
'upload-proto-error' => 'Սխալ պրոտոկոլ',
'upload-proto-error-text' => 'Հեռավոր բեռնումը պահանջում է URL-հասցե, որը սկսվում է <code>http://</code> կամ <code>ftp://</code> նախածանցով։',
'upload-file-error-text' => 'Տեղի ունեցավ ներքին սխալ՝ սերվերի վրա ժամանակավոր նիշք ստեղծելիս։ Խնդրում ենք կապվել համակարգային [[Special:ListUsers/sysop|ադմինիստրատորի]] հետ։',
'upload-misc-error' => 'Բեռնման անհայտ սխալ',
'upload-misc-error-text' => 'Տեղի ունեցավ անհայտ սխալ բեռնման ընթացքում։ Խնդրում ենք ստուգել URL-հասցեի ճշտությունն ու հասանելիությունը և փորձել կրկին։ Սխալի կրկնման դեպքում կապնվեք համակարգային ադմինիստրատորի հետ։',
+'upload-unknown-size' => 'Անհնար չափս',
# Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>
'upload-curl-error6' => 'URL-հասցեն անհասանելի է',
'protectedpagesempty' => 'Ներկայումս չկան պաշտպանված էջեր նշված պարամետրերով։',
'protectedtitles' => 'Պաշտպանված անվանումներ',
'listusers' => 'Մասնակիցների ցանկ',
+'usereditcount' => '
+$1 {{PLURAL:$1|խմբագրում|խմբագրումներ}}',
'usercreated' => '{{GENDER:$3|Ստեղծվել է}} $1-ին, ժամը $2-ին',
'newpages' => 'Նոր էջեր',
'newpages-username' => 'Մասնակից՝',
# Special:ActiveUsers
'activeusers' => 'Ակտիվ մասնակիցների ցանկ',
+'activeusers-noresult' => 'Այդպիսի մասնակիցներ չեն գտնվել։',
# Special:ListGroupRights
'listgrouprights-members' => '(անդամների ցանկ)',
'enotif_impersonal_salutation' => '{{grammar:genitive|{{SITENAME}}}} մասնակից',
'enotif_subject_deleted' => '{{SITENAME}} էջը $1 {{GENDER:$2|ջնջվել է}} $2-ի կողմից',
'enotif_subject_created' => '{{SITENAME}} էջը $1 {{GENDER:$2|ստեղծվել է}} $2-ի կողմից',
+'enotif_subject_moved' => '{{SITENAME}} էջը $1 {{GENDER:$2|վերահղվել է}} $2-ի կողմից',
+'enotif_body_intro_created' => '{{SITENAME}} էջը $1 {{GENDER:$2|ստեղծվել է}} ժամը $PAGEEDITDATE-ին $2-ի կողմից, նայիր $3 ընդացիկ տարբերակը:',
'enotif_lastvisited' => 'Տես $1՝ ձեր վերջին այցից ի վեր կատարված փոփոխությունների համար։',
'enotif_lastdiff' => 'Տես $1՝ այս փոփոխությունը դիտելու համար։',
'enotif_anon_editor' => 'անանուն մասնակից $1',
'blanknamespace' => '(Գլխավոր)',
# Contributions
-'contributions' => 'Մասնակցի ներդրում',
+'contributions' => ' {{GENDER:$1|Մասնակցի}} ներդրում',
'contributions-title' => '$1 մասնակցի ներդրումը',
'mycontris' => 'Ներդրում',
'contribsub2' => '$1-ի ներդրումները ($2)',
'dberr-problems' => 'Այս կայքում առաջացել են տեխնիկական խնդիրներ։ Հայցում ենք ձեր ներողությունը։',
'dberr-again' => 'Փորձեք մի քանի րոպե սպասել և վերաբեռնել էջը։',
+# HTML forms
+'htmlform-submit' => '
+Հաշվել',
+
# New logging system
'logentry-delete-delete' => '$1 ջնջեց էջը $3',
'logentry-delete-restore' => '$1 վերականգնեց էջը $3',
'tog-enotifrevealaddr' => 'Gefa upp netfang mitt í tilkynningarpóstum',
'tog-shownumberswatching' => 'Sýna fjölda vaktandi notenda',
'tog-oldsig' => 'Núverandi undirskrift:',
-'tog-fancysig' => 'Meðhöndla undirskrift sem wikitexti (án sjálfvirks tengils)',
-'tog-externaleditor' => 'Nota utanaðkomandi ritil sjálfgefið (eingöngu fyrir reynda, þarfnast sérstakra stillinga á tölvunni þinni)',
-'tog-externaldiff' => 'Nota utanaðkomandi mismun sjálfgefið (eingöngu fyrir reynda, þarfnast sérstakra stillinga á tölvunni þinni)',
+'tog-fancysig' => 'Meðhöndla undirskrift sem wikimál (án sjálfvirks tengils)',
+'tog-externaleditor' => 'Nota utanaðkomandi ritil sjálfgefið (eingöngu fyrir reynda, þarfnast sérstakra stillinga á tölvunni þinni. [//www.mediawiki.org/wiki/Manual:External_editors Frekari upplýsingar.])',
+'tog-externaldiff' => 'Nota utanaðkomandi mismun sjálfgefið (eingöngu fyrir reynda, þarfnast sérstakra stillinga á tölvunni þinni. [//www.mediawiki.org/wiki/Manual:External_editors Frekari upplýsingar.])',
'tog-showjumplinks' => 'Virkja „stökkva á“ aðgengitengla',
'tog-uselivepreview' => 'Nota beina forskoðun (JavaScript) (Á tilraunastigi)',
'tog-forceeditsummary' => 'Birta áminningu þegar breytingarágripið er tómt',
'october' => 'október',
'november' => 'nóvember',
'december' => 'desember',
-'january-gen' => 'janúar',
-'february-gen' => 'febrúar',
+'january-gen' => 'janúars',
+'february-gen' => 'febrúars',
'march-gen' => 'mars',
-'april-gen' => 'apríl',
+'april-gen' => 'apríls',
'may-gen' => 'maí',
'june-gen' => 'júní',
'july-gen' => 'júlí',
'category-subcat-count' => '{{PLURAL:$2|Þessi flokkur hefur einungis eftirfarandi undirflokk.|Þessi flokkur hefur eftirfarandi {{PLURAL:$1|undirflokk|$1 undirflokka}}, af alls $2.}}',
'category-subcat-count-limited' => 'Þessi flokkur hefur eftirfarandi {{PLURAL:$1|undirflokk|$1 undirflokka}}.',
'category-article-count' => '{{PLURAL:$2|Þessi flokkur inniheldur aðeins eftirfarandi síðu.|Eftirfarandi {{PLURAL:$1|síða er|síður eru}} í þessum flokki, af alls $1.}}',
-'category-article-count-limited' => 'Eftirfarndi {{PLURAL:$1|síða er|$1 síður eru}} í þessum flokki.',
+'category-article-count-limited' => 'Eftirfarandi {{PLURAL:$1|síða er|$1 síður eru}} í þessum flokki.',
'category-file-count' => '{{PLURAL:$2|Þessi flokkur inniheldur einungis eftirfarandi skrá.|Eftirfarandi {{PLURAL:$1|skrá er|$1 skrár eru}} í þessum flokki, af alls $2.}}',
'category-file-count-limited' => 'Eftirfarandi {{PLURAL:$1|skrá er|$1 skrár eru}} í þessum flokki.',
'listingcontinuesabbrev' => 'frh.',
** Yfirþyrmandi framkoma/áreitni
** Misnotkun á fjölda notandanafna
** Óásættanlegt notandanafn',
-'ipb-hardblock' => 'Hindra innskráðum notendum frá því að breyta frá þessu vistfangi.',
-'ipbcreateaccount' => 'Banna nýskráningu notanda',
+'ipb-hardblock' => 'Banna innskráðum notendum að breyta frá þessu vistfangi.',
+'ipbcreateaccount' => 'Banna nýskráningu notandanafns',
'ipbemailban' => 'Banna notanda að senda tölvupóst',
'ipbenableautoblock' => 'Banna síðasta vistfang notanda sjálfkrafa; og þau vistföng sem viðkomandi notar til að breyta síðum',
'ipbsubmit' => 'Banna notanda',
'ipbotherreason' => 'Önnur/auka ástæða:',
'ipbhidename' => 'Fela notandanafn úr breytingarskrá og listum',
'ipbwatchuser' => 'Vakta notanda- og spjallsíður þessa notanda',
-'ipb-disableusertalk' => 'Banna þessum notenda að breyta egin spjallsíðu',
+'ipb-disableusertalk' => 'Banna þessum notanda að breyta eigin spjallsíðu',
'ipb-change-block' => 'Endurbanna notanda með þessum stillingum',
'ipb-confirm' => 'Staðfesta bann',
'badipaddress' => 'Ógilt vistfang',
'blockipsuccesstext' => '[[Special:Contributions/$1|$1]] hefur verið bannaður/bönnuð.<br />
Sjá [[Special:BlockList|bannaðir notendur og vistföng]] fyrir yfirlit yfir núverandi bönn.',
'ipb-blockingself' => 'Þú ert í þann mund að banna sjálfan þig! Ertu viss um að þú viljir gera það?',
-'ipb-confirmhideuser' => 'Þú ert í þann mund að banna notenda sem er falinn. Notendanafn hans mun ekki birtast í listum og aðgerðarskrám. Ertu viss um að þú viljir gera það?',
+'ipb-confirmhideuser' => 'Þú ert í þann mund að banna notanda sem er falinn. Notandanafn hans mun ekki birtast í listum og aðgerðarskrám. Ertu viss um að þú viljir gera það?',
'ipb-edit-dropdown' => 'Breyta ástæðu fyrir banni',
'ipb-unblock-addr' => 'Afbanna $1',
'ipb-unblock' => 'Afbanna notanda eða vistfang',
'exif-gpslatitude' => 'Breiddargráða',
'exif-gpslongituderef' => 'Austur- eða vestur lengdargráða',
'exif-gpslongitude' => 'Lengdargráða',
+'exif-gpsaltituderef' => 'Hæðarviðmið',
'exif-gpsaltitude' => 'Stjörnuhæð',
'exif-gpstimestamp' => 'GPS tími (atómklukka)',
'exif-gpssatellites' => 'Gervihnettir sem voru notaðir við mælingu',
'statistics-pages' => 'გვერდები',
'statistics-pages-desc' => 'ვიკის ყველა გვერდი, განხილვის, გადამისამართების და სხვ. ჩათვლით.',
'statistics-files' => 'ატვირთული ფაილები',
-'statistics-edits' => 'გვერდის შესწორებები {{SITENAME}}-ის შექმნიდან',
+'statistics-edits' => 'გვერდის შესწორებები პროექტის {{SITENAME}} შექმნის შემდეგ',
'statistics-edits-average' => 'რედაქტირების საერთო რაოდენობა გვერდზე',
'statistics-views-total' => 'სულ ხილვა',
'statistics-views-total-desc' => 'სათვალავში არ მიიღება არარსებული და სამუშაო გვერდების გადახედვა',
'subject' => 'Тема/кьилинцIар',
'minoredit' => 'ГъвечIи дуьзар хъувун',
'watchthis' => 'И ччин гуьзетун',
-'savearticle' => 'ЧÑ\87ин Ñ\85Ñ\83Ñ\8cн',
+'savearticle' => 'ЧÑ\8aин Ñ\85вин',
'preview' => 'Сифтедин килигун',
'showpreview' => 'Сифтедин килигун къалурун',
'showlivepreview' => 'Фад сифтедин килигун',
'prefs-user-pages' => 'Кориснички страници',
'prefs-personal' => 'Кориснички профил',
'prefs-rc' => 'Скорешни промени',
-'prefs-watchlist' => 'Ð\9dабљудувања',
+'prefs-watchlist' => 'набљудувања',
'prefs-watchlist-days' => 'Број на денови за приказ во списокот на набљудувања:',
'prefs-watchlist-days-max' => 'Највеќе $1 {{PLURAL:$1|ден|дена}}',
'prefs-watchlist-edits' => 'Максимален број на прикажани промени во проширениот список на набљудувања:',
'search-interwiki-default' => '$1-resultat:',
'search-interwiki-more' => '(meir)',
'search-relatedarticle' => 'Relatert',
-'mwsuggest-disable' => 'Slå av AJAX-forslag',
+'mwsuggest-disable' => 'Slå av søkjeframlegg',
'searcheverything-enable' => 'Søk i alle namneroma',
'searchrelated' => 'relatert',
'searchall' => 'alle',
'pageinfo-robot-noindex' => 'Kan ikkje indekserast',
'pageinfo-views' => 'Tal på visningar',
'pageinfo-watchers' => 'Tal på overvakarar av sida',
+'pageinfo-few-watchers' => 'Færre enn $1 {{PLURAL:$1|som overvakar}}',
'pageinfo-redirects-name' => 'Omdirigeringar til sida',
'pageinfo-subpages-name' => 'Undersider av sida',
'pageinfo-subpages-value' => '$1 ({{PLURAL:$2|éi omdirigering|$2 omdirigeringar}}; {{PLURAL:$3|éi ikkje-omdirigering|$3 ikkje-omdirigeringar}})',
'fri' => 'ଶୁକ୍ର',
'sat' => 'ଶନି',
'january' => 'ଜାନୁଆରୀ',
-'february' => 'ଫà\87ବà\8dରà\81ଆରୀ',
+'february' => 'ଫà\87ବà\83ଆରୀ',
'march' => 'ମାର୍ଚ୍ଚ',
'april' => 'ଅପ୍ରେଲ',
'may_long' => 'ମଇ',
'november' => 'ନଭେମ୍ବର',
'december' => 'ଡିସେମ୍ବର',
'january-gen' => 'ଜାନୁଆରୀ',
-'february-gen' => 'ଫà\87ବà\8dରà\81ଆରୀ',
+'february-gen' => 'ଫà\87ବà\83ଆରୀ',
'march-gen' => 'ମାର୍ଚ୍ଚ',
'april-gen' => 'ଅପ୍ରେଲ',
'may-gen' => 'ମଇ',
'imagepage' => 'ଫାଇଲ ପୃଷ୍ଠାଗୁଡ଼ିକ ଦେଖନ୍ତୁ',
'mediawikipage' => 'ମେସେଜ ପୃଷ୍ଠାଟି ଦେଖାଇବେ',
'templatepage' => 'ଛାଞ୍ଚ ପୃଷ୍ଠାଗୁଡ଼ିକ ଦେଖନ୍ତୁ',
-'viewhelppage' => 'ସହାଯà\8bà¬\97 ପà\83ଷà\8dଠାà¬\97à\81ଡ଼ିà¬\95 ଦà\87à¬\96ନà\8dତà\81',
+'viewhelppage' => 'ସହଯୋଗ ପୃଷ୍ଠାଗୁଡ଼ିକ ଦେଖନ୍ତୁ',
'categorypage' => 'ଶ୍ରେଣୀ ପୃଷ୍ଠାଟିକୁ ଦେଖାଇବେ',
'viewtalkpage' => 'ଆଲୋଚନାଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ',
'otherlanguages' => 'ଅଲଗା ଭାଷା',
'mainpage' => 'ପ୍ରଧାନ ପୃଷ୍ଠା',
'mainpage-description' => 'ପ୍ରଧାନ ପୃଷ୍ଠା',
'policy-url' => 'Project:ନୀତି',
-'portal' => 'ସà¬\99à\8dଘ ସୂଚନା ଫଳକ',
-'portal-url' => 'Project:ସà¬\99à\8dଘ ସୂଚନା ଫଳକ',
+'portal' => 'ସà¬\82ଘ ସୂଚନା ଫଳକ',
+'portal-url' => 'Project:ସà¬\82ଘ ସୂଚନା ଫଳକ',
'privacy' => 'ଗୁମର ନୀତି',
'privacypage' => 'Project:ଗୁମର ନୀତି',
'badaccess' => 'ଅନୁମତି ମିଳିବାରେ ଅସୁବିଧା',
-'badaccess-group0' => 'à¬\86ପଣ à¬\85ନà\81ରà\8bଷ କରିଥିବା ପୃଷ୍ଠାଟିରେ କିଛି କାମ କରିବା ନିମନ୍ତେ ଆପଣଙ୍କୁ ଅନୁମତି ମିଳିନାହିଁ',
+'badaccess-group0' => 'à¬\86ପଣ à¬\85ନà\81ରà\8bଧ କରିଥିବା ପୃଷ୍ଠାଟିରେ କିଛି କାମ କରିବା ନିମନ୍ତେ ଆପଣଙ୍କୁ ଅନୁମତି ମିଳିନାହିଁ',
'badaccess-groups' => 'ଆପଣ ଅନୁରୋଧ କରିଥିବା କାମଟି କେବଳ {{PLURAL:$2|ଗୋଠ|ଗୋଠମାନଙ୍କ ଭିତରୁ ଗୋଟିଏ ଗୋଠ}}: $1 ର ସଭ୍ୟମାନଙ୍କ ଭିତରେ ସୀମିତ ।',
'versionrequired' => 'ମିଡ଼ିଆଉଇକି ର $1 ତମ ସଙ୍କଳନଟି ଲୋଡ଼ା',
# General errors
'error' => 'ଭୁଲ',
'databaseerror' => 'ଡାଟାବେସରେ ଭୁଲ',
-'dberrortext' => 'à¬\8fହା à¬\8fହି ସଫà\8dà¬\9fବେରରେ ଭୁଲଟିଏକୁ ମଧ୍ୟ ସୂଚାଇପାରେ ।
+'dberrortext' => 'à¬\8fହା à¬\8fହି ସଫà\8dà¬\9fà±େରରେ ଭୁଲଟିଏକୁ ମଧ୍ୟ ସୂଚାଇପାରେ ।
ଶେଷଥର ଖୋଜାଯାଇଥିବା ଡାଟାବେସ ପ୍ରଶ୍ନଟି ଥିଲା:
<blockquote><code>$1</code></blockquote>
ଯାହାକି "<code>$2</code>"ରୁ ଥିଲା
'protectedpagetext' => 'ଏହି ପୃଷ୍ଠାଟି ସମ୍ପାଦନା କିମ୍ବା ଅନ୍ୟକୌଣସି କାର୍ଯ୍ୟ କରିବାରୁ କିଳାଯାଇଛି ।',
'viewsourcetext' => 'ଆପଣ ଏହି ପୃଷ୍ଠାର ଲେଖା ଦେଖିପାରିବେ ଓ ନକଲ କରିପାରିବେ:',
'viewyourtext' => "ଆପଣ '''ଆପଣଙ୍କ ସମ୍ପାଦିତ ''' ଅଧରଟିକୁ ଦେଖିପାରିବେ ଓ ଏହି ପୃଷ୍ଠାକୁ ନକଲ କରି ପାରିବେ",
-'protectedinterface' => 'à¬\8fହି ପà\83ଷà\8dଠାà¬\9fି à¬\8fହି à¬\89à¬\87à¬\95ିରà\87 ଥିବା ସଫà\8dà¬\9fà±à\87ର ନିମନà\8dତà\87 à¬\87ଣà\8dà¬\9fରଫà\87ସ ଲà\87à¬\96ା ଯà\8bà¬\97ାà¬\87ଥାà¬\8f à¬\93 à¬\8fହା à¬\85ବà\8dପà\9fବହାରà¬\95à\81 ରà\8bà¬\95ିବା ନିମନà\8dତà\87 à¬\95ିଳାଯାà¬\87à¬\85à¬\9bି । ସମସà\8dତ à¬\89à¬\87à¬\95ିର à¬\85ନà\81ବାଦà¬\95à\81 ଯà\8bଡିବା à¬\8fବà¬\82 ବଦଳାà¬\87ବା ପାà¬\87à¬\81 ମà\87ଡିଆଉଇକିର ସ୍ଥାନୀୟ ପ୍ରକଳ୍ପରେ ଥିବା [//translatewiki.net/ translatewiki.net]କୁ ବ୍ୟବହାର କରନ୍ତୁ ।',
-'editinginterface' => "'''à¬\9aà\87ତାବନà\80:''' à¬\86ପଣ ସଫà\8dà¬\9fବେରର ଇଣ୍ଟରଫେସ ଲେଖା ଯୋଗାଇବା ନିମନ୍ତେ ବ୍ୟବହାର କରାଯାଉଥିବା ଏକ ପୃଷ୍ଠାର ସମ୍ପାଦନା କରୁଅଛନ୍ତି ।
+'protectedinterface' => 'à¬\8fହି ପà\83ଷà\8dଠାà¬\9fି à¬\8fହି à¬\89à¬\87à¬\95ିରà\87 ଥିବା ସଫà\8dà¬\9fà±à\87ର ନିମନà\8dତà\87 à¬\87ଣà\8dà¬\9fରଫà\87ସ ଲà\87à¬\96ା ଯà\8bà¬\97ାà¬\87ଥାà¬\8f à¬\93 à¬\8fହା à¬\85ପବà\8dà\9fବହାରà¬\95à\81 ରà\8bà¬\95ିବା ନିମନà\8dତà\87 à¬\95ିଳାଯାà¬\87à¬\85à¬\9bି । ସମସà\8dତ à¬\89à¬\87à¬\95ିର à¬\85ନà\81ବାଦà¬\95à\81 ଯà\8bଡ଼ିବା à¬\8fବà¬\82 ବଦଳାà¬\87ବା ପାà¬\87à¬\81 ମà\87ଡ଼ିଆଉଇକିର ସ୍ଥାନୀୟ ପ୍ରକଳ୍ପରେ ଥିବା [//translatewiki.net/ translatewiki.net]କୁ ବ୍ୟବହାର କରନ୍ତୁ ।',
+'editinginterface' => "'''à¬\9aà\87ତାବନà\80:''' à¬\86ପଣ ସଫà\8dà¬\9fà±େରର ଇଣ୍ଟରଫେସ ଲେଖା ଯୋଗାଇବା ନିମନ୍ତେ ବ୍ୟବହାର କରାଯାଉଥିବା ଏକ ପୃଷ୍ଠାର ସମ୍ପାଦନା କରୁଅଛନ୍ତି ।
ଏହି ଉଇକିପୃଷ୍ଠାର କିଛି ବି ବଦଳ ବାକି ସଭ୍ୟମାନଙ୍କ ଇଣ୍ଟରଫେସର ଦେଖଣାକୁ ପ୍ରଭାବିତ କରିବ ।
ସମସ୍ତ ଉଇକିର ଅନୁବାଦ ନିମନ୍ତେ, ଦୟାକରି ମିଡ଼ିଆଉଇକିର ସ୍ଥାନୀୟକରଣ ପ୍ରକଳ୍ପ [//translatewiki.net/wiki/Main_Page?setlang=en translatewiki.net] ବ୍ୟବହାର କରନ୍ତୁ ।",
'sqlhidden' => '(SQL ପ୍ରଶ୍ନ ଲୁଚାଯାଇଅଛି)',
ଆପଣ ବନାନ ପରଖି ନିଅନ୍ତୁ ।',
'nouserspecified' => 'ଆପଣଙ୍କୁ ଇଉଜର ନାମଟିଏ ଦେବାକୁ ପଡ଼ିବ ।',
'login-userblocked' => 'ଏହି ସଭ୍ୟଙ୍କୁ ଅଟକାଯାଇଛି । ଲଗ ଇନ କରିବାକୁ ଅନୁମତି ନାହିଁ ।',
-'wrongpassword' => 'ଦିà¬\86ଯାà¬\87ଥିବା ପାସବାର୍ଡ଼ଟି ଭୁଲ ଅଟେ ।
+'wrongpassword' => 'ଦିà¬\86ଯାà¬\87ଥିବା ପାସà±ାର୍ଡ଼ଟି ଭୁଲ ଅଟେ ।
ଦୟାକରି ଆଉଥରେ ଚେଷ୍ଟା କରନ୍ତୁ ।',
'wrongpasswordempty' => 'ଦିଆଯାଇଥିବା ପାସବାର୍ଡ଼ଟି ଖାଲି ଛଡ଼ାଯାଇଛି ।
ଦୟାକରି ଆଉଥରେ ଚେଷ୍ଟା କରନ୍ତୁ ।',
-'passwordtooshort' => 'ପାସବାର୍ଡ଼ଟି ଅତି କମରେ {{PLURAL:$1|ଗୋଟିଏ ଅକ୍ଷର|$1ଟି ଅକ୍ଷର}}ର ହୋଇଥିବା ଲୋଡ଼ା ।',
-'password-name-match' => 'à¬\86ପଣà¬\99à\8dà¬\95 ପାସବାର୍ଡ଼ଟି ଆପଣଙ୍କ ଇଉଜର ନାମ ଠାରୁ ଅଲଗା ହେବା ଉଚିତ ।',
-'password-login-forbidden' => 'à¬\8fହି à¬\87à¬\89à¬\9cର ନାମ à¬\93 ପାସବାର୍ଡ଼ର ବ୍ୟବହାରକୁ ବାରଣ କରାଯାଇଅଛି ।',
-'mailmypassword' => 'ପାସବାର୍ଡ଼ଟିକୁ ଇମେଲ କରି ପଠାଇବେ',
+'passwordtooshort' => 'ପାସà±ାର୍ଡ଼ଟି ଅତି କମରେ {{PLURAL:$1|ଗୋଟିଏ ଅକ୍ଷର|$1ଟି ଅକ୍ଷର}}ର ହୋଇଥିବା ଲୋଡ଼ା ।',
+'password-name-match' => 'à¬\86ପଣà¬\99à\8dà¬\95 ପାସà±ାର୍ଡ଼ଟି ଆପଣଙ୍କ ଇଉଜର ନାମ ଠାରୁ ଅଲଗା ହେବା ଉଚିତ ।',
+'password-login-forbidden' => 'à¬\8fହି à¬\87à¬\89à¬\9cର ନାମ à¬\93 ପାସà±ାର୍ଡ଼ର ବ୍ୟବହାରକୁ ବାରଣ କରାଯାଇଅଛି ।',
+'mailmypassword' => 'ପାସà±ାର୍ଡ଼ଟିକୁ ଇମେଲ କରି ପଠାଇବେ',
'passwordremindertitle' => '{{SITENAME}} ପାଇଁ ନୂଆ ଅଳ୍ପ କାଳର ପାସୱାର୍ଡ଼',
'passwordremindertext' => 'କେହିଜଣେ (ବୋଧେ ଆପଣ, $1 IP ଠିକଣାରୁ)
ନୂଆ ପାସବାର୍ଡ଼ଟିଏ ପାଇଁ {{SITENAME}} ($4) ରେ ଆବେଦନ କରିଅଛନ୍ତି । "$2"ଙ୍କ ପାଇଁ ଏକ ଅସ୍ଥାୟୀ ପାସବାର୍ଡ଼
continue using your old password.',
'noemail' => 'ସଭ୍ୟ "$1"ଙ୍କ ପାଇଁ କିଛି ବି ଇ-ମେଲ ଆଇ.ଡି. ସାଇତାଯାଇନାହିଁ ।',
'noemailcreate' => 'ଆପଣଙ୍କୁ ଏକ ସଚଳ ଇ-ମେଲ ଠିକଣା ଦେବାକୁ ପଡ଼ିବ',
-'passwordsent' => '"$1" ପାà¬\87à¬\81 ଥà\9f à¬\95ରାଯାà¬\87ଥିବା à¬\87-ମà\87ଲà¬\95à\81 ନà\82à¬\86 ପାସବାର୍ଡ଼ଟିଏ ପଠାଇଦିଆଗଲା ।
+'passwordsent' => '"$1" ପାà¬\87à¬\81 ଥà\9f à¬\95ରାଯାà¬\87ଥିବା à¬\87-ମà\87ଲà¬\95à\81 ନà\82à¬\86 ପାସà±ାର୍ଡ଼ଟିଏ ପଠାଇଦିଆଗଲା ।
ତାହା ମିଳିଲା ପରେ ଆଉଥରେ ଲଗ ଇନ କରନ୍ତୁ ।',
-'blocked-mailpassword' => 'à¬\86ପଣà¬\99à\8dà¬\95 IP ଠିà¬\95ଣାà¬\9fି ସମà\8dପାଦନାରà\87 à¬à¬¾à¬\97 ନà\87ବାରà\81 à¬\85à¬\9fà¬\95ାଯାà¬\87à¬\9bି, ତà\87ଣà\81 ପାସବାର୍ଡ଼ ଫେରନ୍ତା କାମ ବ୍ୟବହାର କରି ଅବ୍ୟବହାରକୁ ରୋକିବା ଅନୁମୋଦିତ ନୁହେଁ ।',
+'blocked-mailpassword' => 'à¬\86ପଣà¬\99à\8dà¬\95 IP ଠିà¬\95ଣାà¬\9fି ସମà\8dପାଦନାରà\87 à¬à¬¾à¬\97 ନà\87ବାରà\81 à¬\85à¬\9fà¬\95ାଯାà¬\87à¬\9bି, ତà\87ଣà\81 ପାସà±ାର୍ଡ଼ ଫେରନ୍ତା କାମ ବ୍ୟବହାର କରି ଅବ୍ୟବହାରକୁ ରୋକିବା ଅନୁମୋଦିତ ନୁହେଁ ।',
'eauthentsent' => 'ଆପଣଙ୍କ ବଛା ଇ-ମେଲ ଠିକଣାକୁ ଏକ ଥୟ କରିବା ଇ-ମେଲଟିଏ ପଠାଇଦିଆଗଲା ।
ଖାତାଟି ଆପଣଙ୍କର ବୋଲି ଥୟ କରିବା ନିମନ୍ତେ ଆଉ କେଉଁ ଇ-ମେଲ ଆପଣଙ୍କ ଖାତାକୁ ପଠାହେବା ଆଗରୁ ଆପଣଙ୍କୁ ସେହି ଇ-ମେଲରେ ଥିବା ସୂଚନା ଅନୁସରଣ କରିବାକୁ ପଡ଼ିବ ।',
-'throttled-mailpassword' => 'à¬\97ତ {{PLURAL:$1|à¬\8fà¬\95 à¬\98ଣà\8dà¬\9fାରà\87|$1 à¬\98ଣà\8dà¬\9fାରà\87}} à¬\86ପଣà¬\99à\8dà¬\95à\81 à¬\8fà¬\95 ପାସବାର୍ଡ଼ ମନେକରିବା ସୂଚନାଟିଏ ପଠାଯାଇଛି ।
-à¬\85ବà\8dà\9fବହାରà¬\95à\81 ରà\8bà¬\95ିବା ନିମନà\8dତà\87, {{PLURAL:$1|à¬\8fà¬\95 à¬\98ଣà\8dà¬\9fାରà\87|$1 à¬\98ଣà\8dà¬\9fାରà\87}} à¬\95à\87ବଳ à¬\97à\8bà¬\9fିà¬\8f ପାସବାର୍ଡ଼ ହିଁ ପଠାହେବ ।',
+'throttled-mailpassword' => 'à¬\97ତ {{PLURAL:$1|à¬\8fà¬\95 à¬\98ଣà\8dà¬\9fାରà\87|$1 à¬\98ଣà\8dà¬\9fାରà\87}} à¬\86ପଣà¬\99à\8dà¬\95à\81 à¬\8fà¬\95 ପାସà±ାର୍ଡ଼ ମନେକରିବା ସୂଚନାଟିଏ ପଠାଯାଇଛି ।
+à¬\85ବà\8dà\9fବହାରà¬\95à\81 ରà\8bà¬\95ିବା ନିମନà\8dତà\87, {{PLURAL:$1|à¬\8fà¬\95 à¬\98ଣà\8dà¬\9fାରà\87|$1 à¬\98ଣà\8dà¬\9fାରà\87}} à¬\95à\87ବଳ à¬\97à\8bà¬\9fିà¬\8f ପାସà±ାର୍ଡ଼ ହିଁ ପଠାହେବ ।',
'mailerror' => 'ମେଲ ପଠାଇବାରେ ଭୁଲ : $1',
'acct_creation_throttle_hit' => 'ଏହି ଉଇକିର ଦେଖଣାହାରୀ ମାନେ ଆପଣଙ୍କ IP ଠିକଣା ବ୍ୟବହାର କରି ବିଗତ ଦିନରେ {{PLURAL:$1|ଖାତାଟିଏ|$1 ଗୋଟି ଖାତା}} ତିଆରି କରିଛନ୍ତି ଯାହା ସେହି ସମୟସୀମା ଭିତରେ ସବୁଠାରୁ ଅଧିକ ଥିଲା ।
ତେଣୁ, ଏହି IP ଠିକଣାର ଦେଖଣାହାରୀ ଗଣ ଏବେ ଆଉ ଅଧିକ ଖାତା ଖୋଲିପାରିବେ ନାହିଁ ।',
'emailauthenticated' => '$2 ତାରିଖ $3 ଘଟିକା ବେଳେ ଆପଣଙ୍କ ଇ-ମେଲ ଠିକଣାଟି ଅନୁମୋଦିତ ହେଲା ।',
-'emailnotauthenticated' => 'à¬\86ପନà¬\99à\8dà¬\95 à¬\87-ମà\87ଲ ଠିà¬\95ଣାà¬\9fି à¬\85ନà\81ମà\8bଦିତà\8d ହୋଇନାହିଁ ।
+'emailnotauthenticated' => 'à¬\86ପଣà¬\99à\8dà¬\95 à¬\87-ମà\87ଲ ଠିà¬\95ଣାà¬\9fି à¬\85ନà\81ମà\8bଦିତ ହୋଇନାହିଁ ।
ଏହି ସବୁ ସୁବିଧାକୁ ନେଇ କିଛି ବି ଇ-ମେଲ ଆପଣଙ୍କୁ ପଠାଯିବ ନାହିଁ ।',
'noemailprefs' => 'ଆପଣଙ୍କ ପସନ୍ଦ ଭିତରେ ଏକ ଇ-ମେଲ ଠିକଣା ଦିଅନ୍ତୁ ଯାହା ଏହି ସବୁ ସୁବିଧାକୁ ସଚଳ କରାଇବ ।',
'emailconfirmlink' => 'ଆପଣଙ୍କ ଇମେଲ ଆଇ.ଡି.ଟି ଠିକ ବୋଲି ଥୟ କରନ୍ତୁ',
'accountcreated' => 'ଖାତାଟି ଖୋଲାହୋଇଗଲା',
'accountcreatedtext' => '$1 ପାଇଁ ନୂଆ ଖାତାଟିଏ ତିଆରି ହୋଇଗଲା ।',
'createaccount-title' => '{{SITENAME}} ପାଇଁ ଖାତା ଖୋଲା',
-'createaccount-text' => 'à¬\95à\87ହି à¬\9cଣà\87 à¬\86ପଣà¬\99à\8dà¬\95 à¬\87-ମà\87ଲ ଠିà¬\95ଣାରà\87 {{SITENAME}} ($4) ରà\87 "$2" ନାମରà\87, "$3" ପାସବାର୍ଡ଼ରେ ଖାତାଟିଏ ତିଆରି କରିଅଛି ।
+'createaccount-text' => 'à¬\95à\87ହି à¬\9cଣà\87 à¬\86ପଣà¬\99à\8dà¬\95 à¬\87-ମà\87ଲ ଠିà¬\95ଣାରà\87 {{SITENAME}} ($4) ରà\87 "$2" ନାମରà\87, "$3" ପାସà±ାର୍ଡ଼ରେ ଖାତାଟିଏ ତିଆରି କରିଅଛି ।
ଆପଣ ଏବେ ଲଗ ଇନ କରି ନିଜର ପାସବାର୍ଡ଼ଟିକୁ ବଦଳାଇଦିଅନ୍ତୁ ।
-ଯଦି ଭୁଲରେ ଏହି ଖାତାଟି ତିଆରି କରାଯାଇଥାଏ ତେବେ ଏହି ସୂଚନାଟିକୁ ଅଣଦେଖା କରିବେ ।',
+ଯଦି ଭୁଲରେ ଏହି ଖାତାଟି ତିଆରି କରାଯାଇଥାଏ, ତେବେ ଏହି ସୂଚନାଟିକୁ ଅଣଦେଖା କରିବେ ।',
'usernamehasherror' => 'ଇଉଜର ନାମରେ ହାସ ଅକ୍ଷର (hash characters) ରହି ପାରିବନାହିଁ',
'login-throttled' => 'ଆପଣ ବହୁ ଥର ଲଗ ଇନ କରିବାର ଉଦ୍ୟମ କରିଅଛନ୍ତି ।
ଦୟାକରି ଆଉଥରେ ଚେଷ୍ଟା କରିବା ଆଗରୁ କିଛି କାଳ ଅପେକ୍ଷ କରନ୍ତୁ ।',
'resetpass' => 'ପାସୱାର୍ଡ଼ ବଦଳାନ୍ତୁ',
'resetpass_announce' => 'ଆପଣ ଏକ ଅସ୍ଥାୟୀ ଇ-ମେଲରେ ଯାଇଥିବା କୋଡ଼ ସହାୟତାରେ ଲଗ ଇନ କରିଅଛନ୍ତି ।
ଲଗ ଇନ ଶେଷ କରିବା ନିମନ୍ତେ ଆପଣଙ୍କୁ ଏହିଠାରେ ନୂଆ ପାସବାର୍ଡ଼ଟିଏ ଦେବାକୁ ପଡ଼ିବ:',
-'resetpass_header' => 'à¬\96ାତାର ପାସବାର୍ଡ଼ଟିକୁ ବଦଳାଇ ଦିଅନ୍ତୁ',
+'resetpass_header' => 'à¬\96ାତାର ପାସà±ାର୍ଡ଼ଟିକୁ ବଦଳାଇ ଦିଅନ୍ତୁ',
'oldpassword' => 'ପୁରୁଣା ପାସୱାର୍ଡ଼:',
'newpassword' => 'ନୂଆ ପାସୱାର୍ଡ଼:',
'retypenew' => 'ପାସୱାର୍ଡ଼ ଆଉଥରେ ଦିଅନ୍ତୁ:',
-'resetpass_submit' => 'ପାସବାରà\8dଡ଼à¬\9fି ଦେଇ ଲଗ ଇନ କରନ୍ତୁ',
+'resetpass_submit' => 'ପାସà±à¬¾à¬°à\8dଡ଼à¬\9fିà¬\8f ଦେଇ ଲଗ ଇନ କରନ୍ତୁ',
'resetpass_success' => 'ଆପଣଙ୍କ ପାସବାର୍ଡ଼ଟି ବଦଳାଇ ଦିଆଗଲା !
ଏବେ ଲଗ ଇନ କରୁଅଛୁଁ...',
'resetpass_forbidden' => 'ପାସବାର୍ଡ଼ମାନ ବଦଳା ଯାଇପାରିବ ନାହିଁ',
'resetpass-no-info' => 'ଏହି ପୃଷ୍ଠାଟିକୁ ସିଧା ଖୋଲିବା ନିମନ୍ତେ ଆପଣଙ୍କୁ ଲଗ ଇନ କରିବାକୁ ପଡ଼ିବ ।',
'resetpass-submit-loggedin' => 'ପାସୱାର୍ଡ଼ ବଦଳାନ୍ତୁ',
'resetpass-submit-cancel' => 'ନାକଚ',
-'resetpass-wrong-oldpass' => 'à¬\85ସà\8dଥାà\9fà\80 ବା à¬\8fବà\87à¬\95ାର ପାସବାର୍ଡ଼ଟି ଭୁଲ ଅଟେ ।
-à¬\86ପଣ ବà\8bଧ ହà\81à¬\8f à¬\86à¬\97ରà\81 ସଫଳ à¬à¬¾à¬¬à¬°à\87 ନିà¬\9cର ପାସବାରà\8dଡ଼à¬\9fି ବଦଳାà¬\87ଦà\87à¬\87à¬\9bନà\8dତି ବା ନà\82à¬\86 à¬\85ସà\8dଥାà\9fà\80 ପାସବାର୍ଡ଼ଟିଏ ପାଇଁ ଆବେଦନ କରିଅଛନ୍ତି ।',
+'resetpass-wrong-oldpass' => 'à¬\85ସà\8dଥାà\9fà\80 ବା à¬\8fବà\87à¬\95ାର ପାସà±ାର୍ଡ଼ଟି ଭୁଲ ଅଟେ ।
+à¬\86ପଣ ବà\8bଧ ହà\81à¬\8f à¬\86à¬\97ରà\81 ସଫଳ à¬à¬¾à¬¬à¬°à\87 ନିà¬\9cର ପାସà±à¬¾à¬°à\8dଡ଼à¬\9fି ବଦଳାà¬\87ଦà\87à¬\87à¬\9bନà\8dତି ବା ନà\82à¬\86 à¬\85ସà\8dଥାà\9fà\80 ପାସà±ାର୍ଡ଼ଟିଏ ପାଇଁ ଆବେଦନ କରିଅଛନ୍ତି ।',
'resetpass-temp-password' => 'ଅସ୍ଥାୟୀ ପାସୱାର୍ଡ଼:',
# Special:PasswordReset
$2
-{{PLURAL:$3|à¬\8fହି à¬\85ସà\8dଥାà\9fà\80 ପାସବାରà\8dଡ଼à¬\9fି|à¬\8fହି à¬\85ସà\8dଥାà\9fà\80 ପାସବାର୍ଡ଼ସବୁ}} {{PLURAL:$5|ଦିନକରେ|$5 ଦିନରେ ଅଚଳ}} ହୋଇଯିବ ।
-à¬\86ପଣ à¬\8fବà\87 ଲà¬\97 à¬\87ନ à¬\95ରି ନà\82à¬\86 ପାସବାର୍ଡ଼ଟିଏ ବାଛନ୍ତୁ । ଯହି ଆଉ କେହି ଜଣେ ଏହି ଅନୁରୋଧ କରିଥାନ୍ତି
-à¬\95ିମà\8dବା à¬\86ପଣ à¬\8fବà\87 ନିà¬\9cର ମà\82ଳ ପାସବାରà\8dଡ଼ ମନà\87 ପà¬\95ାà¬\87 ପାରିଥାନà\8dତି ତà\87ବà\87 à¬\8fହି ପାସବାର୍ଡ଼ଟିକୁ ଆଉ ବଦଳାଇବା ଲୋଡ଼ା ନାହିଁ ।
-à¬\86ପଣ ନିà¬\9c ପà\81ରà\81ଣା ପାସବାର୍ଡ଼ଟି ଆଗପରି ବ୍ୟବହାର କରିପାରନ୍ତି ।',
-'passwordreset-emailtext-user' => '{{SITENAME}}ରà\87 ଥିବା ବà\8dà\9fà\9fବହାରà¬\95ାରà\80 $1 {{SITENAME}} ($4) ସାà¬\87à¬\9fରà\87 ଥିବା à¬\86ପଣà¬\99à\8dà¬\95 à¬\96ାତାର ସବିଶà\87ଷ à¬\9cାଣିବାà¬\95à\81 à¬\85ନà\81ରà\8bଧ à¬\95ରିà¬\9bନà\8dତି । à¬\8fହି à¬\87ମà\87ଲ ଠିà¬\95ଣା ସହିତ ତଳଲିà¬\96ିତ ବà\8dà\9fବହାରà¬\95ାରà\80à¬\99à\8dà¬\95 {{PLURAL:$3|à¬\96ାତା|à¬\96ାତାସମà\82ହ}} ଯà\8bଡ଼ା:
+{{PLURAL:$3|à¬\8fହି à¬\85ସà\8dଥାà\9fà\80 ପାସà±à¬¾à¬°à\8dଡ଼à¬\9fି|à¬\8fହି à¬\85ସà\8dଥାà\9fà\80 ପାସà±ାର୍ଡ଼ସବୁ}} {{PLURAL:$5|ଦିନକରେ|$5 ଦିନରେ ଅଚଳ}} ହୋଇଯିବ ।
+à¬\86ପଣ à¬\8fବà\87 ଲà¬\97 à¬\87ନ à¬\95ରି ନà\82à¬\86 ପାସà±ାର୍ଡ଼ଟିଏ ବାଛନ୍ତୁ । ଯହି ଆଉ କେହି ଜଣେ ଏହି ଅନୁରୋଧ କରିଥାନ୍ତି
+à¬\95ିମà\8dବା à¬\86ପଣ à¬\8fବà\87 ନିà¬\9cର ମà\82ଳ ପାସà±à¬¾à¬°à\8dଡ଼ ମନà\87 ପà¬\95ାà¬\87 ପାରିଥାନà\8dତି ତà\87ବà\87 à¬\8fହି ପାସà±ାର୍ଡ଼ଟିକୁ ଆଉ ବଦଳାଇବା ଲୋଡ଼ା ନାହିଁ ।
+à¬\86ପଣ ନିà¬\9c ପà\81ରà\81ଣା ପାସà±ାର୍ଡ଼ଟି ଆଗପରି ବ୍ୟବହାର କରିପାରନ୍ତି ।',
+'passwordreset-emailtext-user' => '{{SITENAME}}ରେ ଥିବା ବ୍ୟବହାରକାରୀ $1 {{SITENAME}} ($4) ସାଇଟରେ ଥିବା ଆପଣଙ୍କ ଖାତାର ସବିଶେଷ ଜାଣିବାକୁ ଅନୁରୋଧ କରିଛନ୍ତି । ଏହି ଇମେଲ ଠିକଣା ସହିତ ତଳଲିଖିତ ବ୍ୟବହାରକାରୀଙ୍କ {{PLURAL:$3|ଖାତା|ଖାତାସମୂହ}} ଯୋଡ଼ା:
$2
-{{PLURAL:$3|à¬\8fହି à¬\85ସà\8dଥାà\9fà\80 ପାସବାରà\8dଡ଼à¬\9fି|à¬\8fହି à¬\85ସà\8dଥାà\9fà\80 ପାସବାର୍ଡ଼ସବୁ}} {{PLURAL:$5|ଦିନକରେ|$5 ଦିନରେ ଅଚଳ}} ହୋଇଯିବ ।
-à¬\86ପଣ à¬\8fବà\87 ଲà¬\97 à¬\87ନ à¬\95ରି ନà\82à¬\86 ପାସବାର୍ଡ଼ଟିଏ ବାଛନ୍ତୁ । ଯହି ଆଉ କେହି ଜଣେ ଏହି ଅନୁରୋଧ କରିଥାନ୍ତି
-à¬\95ିମà\8dବା à¬\86ପଣ à¬\8fବà\87 ନିà¬\9cର ମà\82ଳ ପାସବାରà\8dଡ଼ ମନà\87 ପà¬\95ାà¬\87 ପାରିଥାନà\8dତି ତà\87ବà\87 à¬\8fହି ପାସବାର୍ଡ଼ଟିକୁ ଆଉ ବଦଳାଇବା ଲୋଡ଼ା ନାହିଁ ।
-à¬\86ପଣ ନିà¬\9c ପà\81ରà\81ଣା ପାସବାର୍ଡ଼ଟି ଆଗପରି ବ୍ୟବହାର କରିପାରନ୍ତି ।',
+{{PLURAL:$3|à¬\8fହି à¬\85ସà\8dଥାà\9fà\80 ପାସà±à¬¾à¬°à\8dଡ଼à¬\9fି|à¬\8fହି à¬\85ସà\8dଥାà\9fà\80 ପାସà±ାର୍ଡ଼ସବୁ}} {{PLURAL:$5|ଦିନକରେ|$5 ଦିନରେ ଅଚଳ}} ହୋଇଯିବ ।
+à¬\86ପଣ à¬\8fବà\87 ଲà¬\97 à¬\87ନ à¬\95ରି ନà\82à¬\86 ପାସà±ାର୍ଡ଼ଟିଏ ବାଛନ୍ତୁ । ଯହି ଆଉ କେହି ଜଣେ ଏହି ଅନୁରୋଧ କରିଥାନ୍ତି
+à¬\95ିମà\8dବା à¬\86ପଣ à¬\8fବà\87 ନିà¬\9cର ମà\82ଳ ପାସà±à¬¾à¬°à\8dଡ଼ ମନà\87 ପà¬\95ାà¬\87 ପାରିଥାନà\8dତି ତà\87ବà\87 à¬\8fହି ପାସà±ାର୍ଡ଼ଟିକୁ ଆଉ ବଦଳାଇବା ଲୋଡ଼ା ନାହିଁ ।
+à¬\86ପଣ ନିà¬\9c ପà\81ରà\81ଣା ପାସà±ାର୍ଡ଼ଟି ଆଗପରି ବ୍ୟବହାର କରିପାରନ୍ତି ।',
'passwordreset-emailelement' => 'ଇଉଜର ନାମ: $1
-à¬\85ସà\8dଥାà\9fà\80 ପାସବାର୍ଡ଼: $2',
+à¬\85ସà\8dଥାà\9fà\80 ପାସà±ାର୍ଡ଼: $2',
'passwordreset-emailsent' => 'ଏକ ମନେପକାଇବା ଇ-ମେଲ ପଠାଇଦିଆଯାଇଅଛି ।',
'passwordreset-emailsent-capture' => 'ତଳେ ଦିଆଯାଇଥିବା ଭଳି ମନେପକାଇବା ଇ-ମେଲଟିଏ ପଠାଦିଆଗଲା ।',
-'passwordreset-emailerror-capture' => 'à¬\97à\8bà¬\9fିà¬\8f ସବିଶà\87ଷ à¬\8fମà\87ଲà¬\9fିà¬\8f ବାହାରିà¬\9bି, ଯାହାକି ତଳେ ଅଛି, କିନ୍ତୁ ଏହାକୁ ବ୍ୟବହାରକାରୀକୁ ପଠାଇବାରେ ଅସଫଳ ହେଲା :$1',
+'passwordreset-emailerror-capture' => 'à¬\97à\8bà¬\9fିà¬\8f ମନà\87ପà¬\95ାà¬\87ବା à¬\87-ମà\87ଲ ତିà¬\86ରି à¬\95ରାଯାà¬\87ଥିଲା, ଯାହାକି ତଳେ ଅଛି, କିନ୍ତୁ ଏହାକୁ ବ୍ୟବହାରକାରୀକୁ ପଠାଇବାରେ ଅସଫଳ ହେଲା :$1',
# Special:ChangeEmail
'changeemail' => 'ଇ-ମେଲ ଠିକଣା ବଦଳାଇବେ',
'changeemail-header' => 'ଖାତା ଇ-ମେଲ ଠିକଣା ବଦଳାଇବେ',
-'changeemail-text' => 'à¬\86ପଣା à¬\87-ମà\87ଲ ଠିà¬\95ଣା ବଦଳାà¬\87ବା ନିମନà\8dତà\87 à¬\8fହି à¬\86ବà\87ଦନ ପତà\8dରà¬\9fି ପà\82ରଣ à¬\95ରନà\8dତà\81 । à¬\86ପଣà¬\99à\8dà¬\95à\81 à¬\8fହି ବଦଳ ଥà\9f à¬\95ରିବା ପାà¬\87à¬\81 ନିà¬\9cର ପାସବାର୍ଡ଼ ଦେବାକୁ ପଡ଼ିବ ।',
+'changeemail-text' => 'à¬\86ପଣା à¬\87-ମà\87ଲ ଠିà¬\95ଣା ବଦଳାà¬\87ବା ନିମନà\8dତà\87 à¬\8fହି à¬\86ବà\87ଦନ ପତà\8dରà¬\9fି ପà\82ରଣ à¬\95ରନà\8dତà\81 । à¬\86ପଣà¬\99à\8dà¬\95à\81 à¬\8fହି ବଦଳ ଥà\9f à¬\95ରିବା ପାà¬\87à¬\81 ନିà¬\9cର ପାସà±ାର୍ଡ଼ ଦେବାକୁ ପଡ଼ିବ ।',
'changeemail-no-info' => 'ଏହି ପୃଷ୍ଠାଟିକୁ ସିଧା ଖୋଲିବା ନିମନ୍ତେ ଆପଣଙ୍କୁ ଲଗ ଇନ କରିବାକୁ ପଡ଼ିବ ।',
'changeemail-oldemail' => 'ଏବେକାର ଇ-ମେଲ ଠିକଣା:',
'changeemail-newemail' => 'ନୂଆ ଇ-ମେଲ ଠିକଣା:',
'link_sample' => 'ଲିଙ୍କ ଶିରୋନାମା',
'link_tip' => 'ଭିତର ଲିଙ୍କ',
'extlink_sample' => 'http://www.example.com ଲିଙ୍କ ଶିରୋନାମା',
-'extlink_tip' => 'ବାହାର ଲିଙ୍କ (http:// ଆଗରେ ଲଗାଇବାକୁ ମନେରଖିଥିବେ)',
+'extlink_tip' => 'ବାହାର ଲିଙ୍କ (ଆରମ୍ଭରେ http:// ଲେଖିବାକୁ ମନେରଖିଥିବେ)',
'headline_sample' => 'ଶିରୋନାମା ଲେଖା',
'headline_tip' => '୨କ ଆକାରର ମୂଳଧାଡ଼ି',
'nowiki_sample' => 'ଅସଜଡ଼ା ଲେଖା ଏଠାରେ ଭରିବେ',
'nowiki_tip' => 'ଉଇକି ସଜାଣି ବିନା',
-'image_tip' => 'ଏମବେଡ଼ ହୋଇ ଥିବା ଫାଇଲ',
+'image_tip' => 'à¬\8fମà\8dବà\87ଡ଼ ହà\8bà¬\87 ଥିବା ଫାà¬\87ଲ',
'media_tip' => 'ଫାଇଲର ଲିଙ୍କ',
-'sig_tip' => 'ଲà\87à¬\96ାର ସମà\9f ସହ à¬\86ପଣà¬\99à\8dà¬\95 ସନà\8dତà¬\95',
+'sig_tip' => 'ସମୟ ସହ ଆପଣଙ୍କ ସନ୍ତକ',
'hr_tip' => 'ସମାନ୍ତରାଳ ରେଖା (ବେଳେବେଳେ ବ୍ୟବହାର କରିବେ)',
# Edit pages
'summary' => 'ସାରକଥା:',
-'subject' => 'ବିଷà\9f/ମà\82ଳ ଲà\87à¬\96ା',
+'subject' => 'ବିଷà\9f/ଶିରà\8bନାମା',
'minoredit' => 'ଏହା ଖୁବ ଛୋଟ ବଦଳଟିଏ',
'watchthis' => 'ଏହି ପୃଷ୍ଠାଟିକୁ ଦେଖିବେ',
'savearticle' => 'ସାଇତିବେ',
'showlivepreview' => 'ଜୀବନ୍ତ ଦେଖଣା',
'showdiff' => 'ବଦଳଗୁଡ଼ିକ ଦେଖାଇବେ',
'anoneditwarning' => "'''ଜାଣିରଖନ୍ତୁ:''' ଆପଣ ଲଗଇନ କରିନାହାନ୍ତି ।
-à¬\8fହି ଫରଦର '''à¬\87ତିହାସ''' ପà\83ଷà\8dଠାରେ ଆପଣଙ୍କ ଆଇପି ଠିକଣାଟି ସାଇତା ହୋଇଯିବ ।",
-'anonpreviewwarning' => "''à¬\86ପଣ ଲà¬\97 à¬\87ନ à¬\95ରି ନାହାନà\8dତି । à¬\86ପଣ ଯà\87à¬\89à¬\81 ବଦଳସବà\81 à¬\95ରିବେ ଆପଣଙ୍କର IP ଠିକଣା ଏହି ପୃଷ୍ଠାର ଇତିହାସରେ ସାଇତା ହୋଇଯିବ ।''",
+à¬\8fହି ପà\83ଷà\8dଠାର à¬\87ତିହାସରେ ଆପଣଙ୍କ ଆଇପି ଠିକଣାଟି ସାଇତା ହୋଇଯିବ ।",
+'anonpreviewwarning' => "''à¬\86ପଣ ଲà¬\97 à¬\87ନ à¬\95ରି ନାହାନà\8dତି । ବଦଳà¬\95ରି ସାà¬\87ତିଲେ ଆପଣଙ୍କର IP ଠିକଣା ଏହି ପୃଷ୍ଠାର ଇତିହାସରେ ସାଇତା ହୋଇଯିବ ।''",
'missingsummary' => "'''ଚେତାବନୀ:''' ଆପଣ ଏକ ସମ୍ପାଦନା ସାରକଥା ଦେଇନାହାନ୍ତି ।
ଯଦି ଆପଣ \"{{int:savearticle}}\"ରେ ଆଉଥରେ କ୍ଲିକ କରନ୍ତି, ତେବେ ଆପଣଙ୍କ ବଦଳ ସାରକଥା ବିନା ସାଇତା ହୋଇଯିବ ।",
'missingcommenttext' => 'ଦୟାକରି ତଳେ ଏକ ମତାମତ ଦିଅନ୍ତୁ ।',
Shown as legend of the second fieldset of the tab 'Search' in [[Special:Preferences]]",
'defaultns' => 'Used in [[Special:Preferences]], tab "Search".',
'default' => '{{Identical|Default}}',
-'prefs-files' => 'Title of a tab in [[Special:Preferences]].',
+'prefs-files' => 'Title of a tab in [[Special:Preferences]].
+{{Identical|File}}',
'prefs-custom-css' => 'visible on [[Special:Preferences]] -[Skins].',
'prefs-custom-js' => 'visible on [[Special:Preferences]] -[Skins].',
'prefs-common-css-js' => 'Used as label in [[Special:Preferences#mw-prefsection-rendering|preferences]], tab "Appearance", section "Skin".',
* {{msg-mw|prefs-help-email-others|help}}
* {{msg-mw|prefs-changeemail|link title}}
* {{msg-mw|prefs-setemail|link title}}',
-'prefs-info' => "Header for the box giving basic information on the user account, displayed on the 'user profile' tab of the [[Special:Preferences|user preferences]] special page.",
+'prefs-info' => "Header for the box giving basic information on the user account, displayed on the 'user profile' tab of the [[Special:Preferences|user preferences]] special page.
+{{Identical|Basic information}}",
'prefs-i18n' => 'Field set legend for user preferences regarding the interface language',
'prefs-signature' => '{{Identical|Signature}}',
'prefs-dateformat' => 'Used in [[Special:Preferences#mw-prefsection-datetime|Special:Preferences]], tab "Date and time".
'pageinfo-title' => 'Page title for action=info. Parameters:
* $1 is the page name',
'pageinfo-not-current' => 'Error message displayed when information for an old revision is requested. Example: [{{fullurl:Project:News|oldid=4266597&action=info}}]',
-'pageinfo-header-basic' => 'Table section header in action=info.',
+'pageinfo-header-basic' => 'Table section header in action=info. See [{{canonicalurl:MediaWiki:Pageinfo-header-basic/en|action=info}} example].
+{{Identical|Basic information}}',
'pageinfo-header-edits' => 'Table section header in action=info.',
'pageinfo-header-restrictions' => 'Table section header in action=info.',
'pageinfo-header-properties' => 'Table section header in action=info.',
'exif-iimcategory-rel' => 'Displayed as part of the iimcategory field if the 3 letter code is recognized, or as part {{msg-mw|exif-subjectnewscode-value}}',
'exif-iimcategory-sci' => 'Displayed as part of the iimcategory field if the 3 letter code is recognized, or as part {{msg-mw|exif-subjectnewscode-value}}',
'exif-iimcategory-soi' => 'Displayed as part of the iimcategory field if the 3 letter code is recognized, or as part {{msg-mw|exif-subjectnewscode-value}}',
-'exif-iimcategory-spo' => 'Displayed as part of the iimcategory field if the 3 letter code is recognized, or as part {{msg-mw|exif-subjectnewscode-value}}',
+'exif-iimcategory-spo' => 'Displayed as part of the iimcategory field if the 3 letter code is recognized, or as part {{msg-mw|exif-subjectnewscode-value}}.
+{{Identical|Sport}}',
'exif-iimcategory-war' => 'Displayed as part of the iimcategory field if the 3 letter code is recognized, or as part {{msg-mw|exif-subjectnewscode-value}}',
'exif-iimcategory-wea' => 'Displayed as part of the iimcategory field if the 3 letter code is recognized, or as part {{msg-mw|exif-subjectnewscode-value}}',
'searchhelp-url' => 'Help:Cuntinuti',
'searchmenu-prefix' => '[[Special:PrefixIndex/$1|Visualizza li pàggini cu stu prifissu]]',
'searchprofile-articles' => 'Pàggini di cuntinutu',
-'searchprofile-project' => "Pàggini d'aiutu e dô pruggettu",
+'searchprofile-project' => "Pàggini d'ajutu e dô pruggettu",
'searchprofile-images' => 'Multimedia',
'searchprofile-everything' => 'Tuttu',
'searchprofile-advanced' => 'Avanzata',
'tog-watchdefault' => "Hateke pájina sira-ne'ebé ha'u edita",
'tog-watchmoves' => "Hateke pájina sira-ne'ebé ha'u book",
'tog-watchdeletion' => "Hateke pájina sira-ne'ebé ha'u halakon",
+'tog-minordefault' => 'Edita hotu-hotu "ki\'ik"',
+'tog-oldsig' => 'Asinatura atuál',
'tog-watchlisthideown' => "La hatudu ha'u-nia edita iha lista hateke",
'tog-watchlisthidebots' => 'Hamsumik bot iha lista hateke',
'tog-watchlisthideminor' => "Hamsumik muda ki-ki'ik iha lista hateke",
'tog-watchlisthideliu' => 'La hatudu edita ema rejista nian iha lista hateke',
'tog-watchlisthideanons' => 'La hatudu edita ema anónimu nian iha lista hateke',
+'tog-watchlisthidepatrolled' => 'Hamsumik muda patrolada iha lista hateke',
+'tog-ccmeonemails' => "Haruka ba ha'u kopia korreiu eletróniku nian ne'ebé ha'u korreia",
'tog-showhiddencats' => "Hatudu kategoria sira-ne'ebé subar",
'underline-always' => 'Sempre',
# Displayed when you click the "watch" button and it is in the process of watching
'watching' => 'เฝ้าดู...',
'unwatching' => 'เลิกเฝ้าดู...',
+'watcherrortext' => 'เกิดข้อผิดพลาดขณะเปลี่ยนแปลงการตั้งค่ารายการเฝ้าดูของคุณ เพราะ "$1"',
'enotif_mailer' => 'แจ้งการแก้ไขจาก {{SITENAME}}',
'enotif_reset' => 'ทำเครื่องหมายว่าชมทุกหน้าแล้ว',
'enotif_subject_deleted' => '{{SITENAME}} หน้า $1 ถูกลบแล้วโดย {{gender:$2|$2}}',
'enotif_subject_created' => '{{SITENAME}} หน้า $1 ถูกสร้างแล้วโดย {{gender:$2|$2}}',
'enotif_subject_moved' => '{{SITENAME}} หน้า $1 ได้ย้ายแล้วโดย {{gender:$2|$2}}',
+'enotif_subject_restored' => 'หน้า $1 บน {{SITENAME}} ถูก{{GENDER:$2|กู้คืน}}โดย $2',
'enotif_subject_changed' => '{{SITENAME}} หน้า $1 ได้เปลี่ยนแล้วโดย {{gender:$2|$2}}',
+'enotif_body_intro_deleted' => 'หน้า $1 บน {{SITENAME}} ถูก{{GENDER:$2|ลบ}}เมื่อ $PAGEEDITDATE โดย $2 ดู $3',
+'enotif_body_intro_created' => 'หน้า $1 บน {{SITENAME}} ถูก{{GENDER:$2|สร้าง}}เมื่อ $PAGEEDITDATE โดย $2 ดูรุ่นปัจจุบันที่ $3',
+'enotif_body_intro_moved' => 'หน้า $1 บน {{SITENAME}} ถูก{{GENDER:$2|เปลี่ยนชื่อ}}เมื่อ $PAGEEDITDATE โดย $2 ดูรุ่นปัจจุบันที่ $3',
+'enotif_body_intro_restored' => 'หน้า $1 บน {{SITENAME}} ถูก{{GENDER:$2|กู้คืน}}เมื่อ $PAGEEDITDATE โดย $2 ดูรุ่นปัจจุบันที่ $3',
+'enotif_body_intro_changed' => 'หน้า $1 บน {{SITENAME}} ถูก{{GENDER:$2|เปลี่ยนแปลง}}เมื่อ $PAGEEDITDATE โดย $2 ดูรุ่นปัจจุบันที่ $3',
'enotif_lastvisited' => 'ดู $1 สำหรับการเปลี่ยนแปลงทั้งหมดตั้งแต่ครั้งล่าสุดที่คุณเข้าชม',
'enotif_lastdiff' => 'ดู $1 เพื่อดูการเปลี่ยนแปลงนี้',
'enotif_anon_editor' => 'ผู้ใช้นิรนาม $1',
'prot_1movedto2' => '[[$1]] ถูกเปลี่ยนชื่อเป็น [[$2]]',
'protect-badnamespace-title' => 'เนมสเปซป้องกันไม่ได้',
'protect-badnamespace-text' => 'หน้าในเนมสเปซนี้ไม่สามารถป้องกันได้',
+'protect-norestrictiontypes-text' => 'หน้านี้ไม่สามารถถูกล็อก เพราะไม่มีประเภทการจำกัดที่ใช้ได้',
+'protect-norestrictiontypes-title' => 'หน้าที่ล็อกไม่ได้',
'protect-legend' => 'ยืนยันการล็อก',
'protectcomment' => 'เหตุผล:',
'protectexpiry' => 'หมดอายุ:',
'blockipsuccesstext' => '[[Special:Contributions/$1|$1]] ถูกบล็อก<br />
ดู[[Special:BlockList|รายการบล็อก]]เพื่อทบทวนการบล็อก',
'ipb-blockingself' => 'คุณกำลังบล็อกตัวเอง! แน่ใจแล้วหรือว่าต้องการทำอย่างนั้น',
+'ipb-confirmhideuser' => 'คุณกำลังบล็อกผู้ใช้โดยเป็นผู้ใช้ "ซ่อนผู้ใช้" ซึ่งจะระงับชื่อผู้ใช้ในรายการและหน่วยปูมทั้งหมด คุณแน่ใจหรือว่าต้องการดำเนินการเช่นนั้น',
'ipb-edit-dropdown' => 'แก้ไขสาเหตุการบล็อก',
'ipb-unblock-addr' => 'เลิกบล็อก $1',
'ipb-unblock' => 'เลิกบล็อกผู้ใช้หรือเลขที่อยู่ไอพี',
'blocklist-userblocks' => 'ซ่อนบล็อกบัญชี',
'blocklist-tempblocks' => 'ซ่อนบล็อกชั่วคราว',
'blocklist-addressblocks' => 'ซ่อนบล็อกไอพีเดียว',
+'blocklist-rangeblocks' => 'ซ่อนการบล็อกช่วง',
'blocklist-timestamp' => 'ตราเวลา',
'blocklist-target' => 'เป้าหมาย',
'blocklist-expiry' => 'หมดอายุ',
'spambot_username' => 'กวาดล้างมีเดียวิกิสแปม',
'spam_reverting' => 'ย้อนกลับไปรุ่นก่อนหน้าที่ไม่มีลิงก์ไปยังเว็บ $1',
'spam_blanking' => 'รุ่นการปรับปรุงทุกรุ่นประกอบไปด้วยลิงก์ไปยังเว็บ $1 (ทำหน้าว่าง)',
+'spam_deleting' => 'ทุกรุ่นที่มีลิงก์ไปยัง $1 กำลังลบ',
# Info page
'pageinfo-title' => 'ข้อมูลสำหรับ "$1"',
* @defgroup Maintenance Maintenance
*/
+if( PHP_SAPI != 'cli' ) {
+ die( "Run me from the command line please.\n" );
+}
+
// Make sure we're on PHP5.3.2 or better
if ( !function_exists( 'version_compare' ) || version_compare( PHP_VERSION, '5.3.2' ) < 0 ) {
// We need to use dirname( __FILE__ ) here cause __DIR__ is PHP5.3+
* @ingroup Maintenance
*/
class DeleteArchivedFilesImplementation {
- static public function doDelete( $output, $force ) {
+ public static function doDelete( $output, $force ) {
# Data should come off the master, wrapped in a transaction
$dbw = wfGetDB( DB_MASTER );
$dbw->begin( __METHOD__ );
* purgeRedundantText(). See Maintenance for a description of
* those methods.
*/
- static public function doDelete( $maint ) {
+ public static function doDelete( $maint ) {
$dbw = wfGetDB( DB_MASTER );
$dbw->begin( __METHOD__ );
// Potentially debug globals
$maintenance->globals();
+ // Perform deferred updates.
+ DeferredUpdates::doUpdates( 'commit' );
+
// log profiling info
wfLogProfilingData();
+
+ // Commit and close up!
+ $factory = wfGetLBFactory();
+ $factory->commitMasterChanges();
+ $factory->shutdown();
} catch ( MWException $mwe ) {
echo( $mwe->getText() );
exit( 1 );
/**
** Randomly returns one element of the input array.
*/
- static public function chooseInput( array $input ) {
+ public static function chooseInput( array $input ) {
$randindex = wikiFuzz::randnum( count( $input ) - 1 );
return $input[$randindex];
}
* @param $start int
* @return int
*/
- static public function randnum( $finish, $start = 0 ) {
+ public static function randnum( $finish, $start = 0 ) {
return mt_rand( $start, $finish );
}
* Returns a mix of random text and random wiki syntax.
* @return string
*/
- static private function randstring() {
+ private static function randstring() {
$thestring = "";
for ( $i = 0; $i < 40; $i++ ) {
* or random data from "other".
* @return string
*/
- static private function makestring() {
+ private static function makestring() {
$what = wikiFuzz::randnum( 2 );
if ( $what == 0 ) {
return wikiFuzz::randstring();
* @param $matches
* @return string
*/
- static private function stringEscape( $matches ) {
+ private static function stringEscape( $matches ) {
return sprintf( "\\x%02x", ord( $matches[1] ) );
}
* @param $str string
* @return string
*/
- static public function makeTitleSafe( $str ) {
+ public static function makeTitleSafe( $str ) {
$legalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF";
return preg_replace_callback(
"/([^$legalTitleChars])/", 'wikiFuzz::stringEscape',
** Returns a string of fuzz text.
* @return string
*/
- static private function loop() {
+ private static function loop() {
switch ( wikiFuzz::randnum( 3 ) ) {
case 1: // an opening tag, with parameters.
$string = "";
* Returns one of the three styles of random quote: ', ", and nothing.
* @return string
*/
- static private function getRandQuote() {
+ private static function getRandQuote() {
switch ( wikiFuzz::randnum( 3 ) ) {
case 1 : return "'";
case 2 : return "\"";
* @param $maxtypes int
* @return string
*/
- static public function makeFuzz( $maxtypes = 2 ) {
+ public static function makeFuzz( $maxtypes = 2 ) {
$page = "";
for ( $k = 0; $k < $maxtypes; $k++ ) {
$page .= wikiFuzz::loop();
. "\n\n";
}
if ( !$ucdallPresent ) {
- $error = "Unable to find ucd.all.grouped.xml. "
+ $error .= "Unable to find ucd.all.grouped.xml. "
. "Download it, unzip, and specify its location with --data-dir=<DIR>. "
. "\n\n";
}
* @ingroup MaintenanceLanguage
*/
-require_once( __DIR__ . '/../Maintenance.php' );
-
require_once( __DIR__ . '/../../includes/normal/UtfNormalUtil.php' );
+require_once( __DIR__ . '/../Maintenance.php' );
+
/**
* Generates normalizer data files for Arabic and Malayalam.
* For NFC see includes/normal.
* @ingroup MaintenanceLanguage
*/
+if ( PHP_SAPI != 'cli' ) {
+ die( "Run me from the command line please.\n" );
+}
+
if ( !isset( $argv[1] ) ) {
print "Usage: php {$argv[0]} <filename>\n";
exit( 1 );
wfWarn( $job->getType() . " job failed to return a boolean." );
$status = true; // sanity
}
- if ( $status ) {
+ if ( $status || !$job->allowRetries() ) {
$group->ack( $job ); // done
}
/**
- * QUnit v1.10.0 - A JavaScript Unit Testing Framework
+ * QUnit v1.11.0 - A JavaScript Unit Testing Framework
*
* http://qunitjs.com
*
/** Resets */
-#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
+#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
margin: 0;
padding: 0;
}
color: #000;
}
-#qunit-tests ol {
+#qunit-tests li .runtime {
+ float: right;
+ font-size: smaller;
+}
+
+.qunit-assert-list {
margin-top: 0.5em;
padding: 0.5em;
-webkit-border-radius: 5px;
}
+.qunit-collapsed {
+ display: none;
+}
+
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
/**
- * QUnit v1.10.0 - A JavaScript Unit Testing Framework
+ * QUnit v1.11.0 - A JavaScript Unit Testing Framework
*
* http://qunitjs.com
*
(function( window ) {
var QUnit,
+ assert,
config,
onErrorFnPrev,
testId = 0,
// Keep a local reference to Date (GH-283)
Date = window.Date,
defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
+ setTimeout: typeof window.setTimeout !== "undefined",
+ sessionStorage: (function() {
+ var x = "qunit-test-string";
+ try {
+ sessionStorage.setItem( x, x );
+ sessionStorage.removeItem( x );
+ return true;
+ } catch( e ) {
+ return false;
+ }
+ }())
+ },
+ /**
+ * Provides a normalized error string, correcting an issue
+ * with IE 7 (and prior) where Error.prototype.toString is
+ * not properly implemented
+ *
+ * Based on http://es5.github.com/#x15.11.4.4
+ *
+ * @param {String|Error} error
+ * @return {String} error message
+ */
+ errorString = function( error ) {
+ var name, message,
+ errorString = error.toString();
+ if ( errorString.substring( 0, 7 ) === "[object" ) {
+ name = error.name ? error.name.toString() : "Error";
+ message = error.message ? error.message.toString() : "";
+ if ( name && message ) {
+ return name + ": " + message;
+ } else if ( name ) {
+ return name;
+ } else if ( message ) {
+ return message;
+ } else {
+ return "Error";
+ }
+ } else {
+ return errorString;
}
- }())
-};
+ },
+ /**
+ * Makes a clone of an object using only Array or Object as base,
+ * and copies over the own enumerable properties.
+ *
+ * @param {Object} obj
+ * @return {Object} New object with only the own properties (recursively).
+ */
+ objectValues = function( obj ) {
+ // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
+ /*jshint newcap: false */
+ var key, val,
+ vals = QUnit.is( "array", obj ) ? [] : {};
+ for ( key in obj ) {
+ if ( hasOwn.call( obj, key ) ) {
+ val = obj[key];
+ vals[key] = val === Object(val) ? objectValues(val) : val;
+ }
+ }
+ return vals;
+ };
function Test( settings ) {
extend( this, settings );
Test.prototype = {
init: function() {
var a, b, li,
- tests = id( "qunit-tests" );
+ tests = id( "qunit-tests" );
if ( tests ) {
b = document.createElement( "strong" );
- b.innerHTML = this.name;
+ b.innerHTML = this.nameHtml;
// `a` initialized at top of scope
a = document.createElement( "a" );
teardown: function() {}
}, this.moduleTestEnvironment );
+ this.started = +new Date();
runLoggingCallbacks( "testStart", QUnit, {
name: this.testName,
module: this.module
try {
this.testEnvironment.setup.call( this.testEnvironment );
} catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
+ QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
}
},
run: function() {
var running = id( "qunit-testresult" );
if ( running ) {
- running.innerHTML = "Running: <br/>" + this.name;
+ running.innerHTML = "Running: <br/>" + this.nameHtml;
}
if ( this.async ) {
QUnit.stop();
}
+ this.callbackStarted = +new Date();
+
if ( config.notrycatch ) {
this.callback.call( this.testEnvironment, QUnit.assert );
+ this.callbackRuntime = +new Date() - this.callbackStarted;
return;
}
try {
this.callback.call( this.testEnvironment, QUnit.assert );
+ this.callbackRuntime = +new Date() - this.callbackStarted;
} catch( e ) {
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace( e, 0 ) );
+ this.callbackRuntime = +new Date() - this.callbackStarted;
+
+ QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
// else next test will carry the responsibility
saveGlobal();
teardown: function() {
config.current = this;
if ( config.notrycatch ) {
+ if ( typeof this.callbackRuntime === "undefined" ) {
+ this.callbackRuntime = +new Date() - this.callbackStarted;
+ }
this.testEnvironment.teardown.call( this.testEnvironment );
return;
} else {
try {
this.testEnvironment.teardown.call( this.testEnvironment );
} catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
+ QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
}
}
checkPollution();
},
finish: function() {
config.current = this;
- if ( config.requireExpects && this.expected == null ) {
+ if ( config.requireExpects && this.expected === null ) {
QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected != null && this.expected != this.assertions.length ) {
+ } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected == null && !this.assertions.length ) {
+ } else if ( this.expected === null && !this.assertions.length ) {
QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
}
- var assertion, a, b, i, li, ol,
+ var i, assertion, a, b, time, li, ol,
test = this,
good = 0,
bad = 0,
tests = id( "qunit-tests" );
+ this.runtime = +new Date() - this.started;
config.stats.all += this.assertions.length;
config.moduleStats.all += this.assertions.length;
if ( tests ) {
ol = document.createElement( "ol" );
+ ol.className = "qunit-assert-list";
for ( i = 0; i < this.assertions.length; i++ ) {
assertion = this.assertions[i];
}
if ( bad === 0 ) {
- ol.style.display = "none";
+ addClass( ol, "qunit-collapsed" );
}
// `b` initialized at top of scope
b = document.createElement( "strong" );
- b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
+ b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
addEvent(b, "click", function() {
- var next = b.nextSibling.nextSibling,
- display = next.style.display;
- next.style.display = display === "none" ? "block" : "none";
+ var next = b.parentNode.lastChild,
+ collapsed = hasClass( next, "qunit-collapsed" );
+ ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
});
addEvent(b, "dblclick", function( e ) {
var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
+ if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
target = target.parentNode;
}
if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
}
});
+ // `time` initialized at top of scope
+ time = document.createElement( "span" );
+ time.className = "runtime";
+ time.innerHTML = this.runtime + " ms";
+
// `li` initialized at top of scope
li = id( this.id );
li.className = bad ? "fail" : "pass";
li.removeChild( li.firstChild );
a = li.firstChild;
li.appendChild( b );
- li.appendChild ( a );
+ li.appendChild( a );
+ li.appendChild( time );
li.appendChild( ol );
} else {
module: this.module,
failed: bad,
passed: this.assertions.length - bad,
- total: this.assertions.length
+ total: this.assertions.length,
+ duration: this.runtime
});
QUnit.reset();
test: function( testName, expected, callback, async ) {
var test,
- name = "<span class='test-name'>" + escapeInnerText( testName ) + "</span>";
+ nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
if ( arguments.length === 2 ) {
callback = expected;
}
if ( config.currentModule ) {
- name = "<span class='module-name'>" + config.currentModule + "</span>: " + name;
+ nameHtml = "<span class='module-name'>" + escapeText( config.currentModule ) + "</span>: " + nameHtml;
}
test = new Test({
- name: name,
+ nameHtml: nameHtml,
testName: testName,
expected: expected,
async: async,
},
start: function( count ) {
+ // QUnit hasn't been initialized yet.
+ // Note: RequireJS (et al) may delay onLoad
+ if ( config.semaphore === undefined ) {
+ QUnit.begin(function() {
+ // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
+ setTimeout(function() {
+ QUnit.start( count );
+ });
+ });
+ return;
+ }
+
config.semaphore -= count || 1;
// don't start until equal number of stop-calls
if ( config.semaphore > 0 ) {
// ignore if start is called more often then stop
if ( config.semaphore < 0 ) {
config.semaphore = 0;
+ QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
+ return;
}
// A slight delay, to avoid any current callbacks
if ( defined.setTimeout ) {
}
};
+// `assert` initialized at top of scope
// Asssert helpers
-// All of these must call either QUnit.push() or manually do:
+// All of these must either call QUnit.push() or manually do:
// - runLoggingCallbacks( "log", .. );
// - config.current.assertions.push({ .. });
-QUnit.assert = {
+// We attach it to the QUnit object *after* we expose the public API,
+// otherwise `assert` will become a global variable in browsers (#341).
+assert = {
/**
* Asserts rough true-ish result.
* @name ok
message: msg
};
- msg = escapeInnerText( msg || (result ? "okay" : "failed" ) );
+ msg = escapeText( msg || (result ? "okay" : "failed" ) );
msg = "<span class='test-message'>" + msg + "</span>";
if ( !result ) {
source = sourceFromStacktrace( 2 );
if ( source ) {
details.source = source;
- msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>";
+ msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr></table>";
}
}
runLoggingCallbacks( "log", QUnit, details );
* @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
*/
equal: function( actual, expected, message ) {
+ /*jshint eqeqeq:false */
QUnit.push( expected == actual, actual, expected, message );
},
* @function
*/
notEqual: function( actual, expected, message ) {
+ /*jshint eqeqeq:false */
QUnit.push( expected != actual, actual, expected, message );
},
+ /**
+ * @name propEqual
+ * @function
+ */
+ propEqual: function( actual, expected, message ) {
+ actual = objectValues(actual);
+ expected = objectValues(expected);
+ QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
+ },
+
+ /**
+ * @name notPropEqual
+ * @function
+ */
+ notPropEqual: function( actual, expected, message ) {
+ actual = objectValues(actual);
+ expected = objectValues(expected);
+ QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
+ },
+
/**
* @name deepEqual
* @function
QUnit.push( expected !== actual, actual, expected, message );
},
- throws: function( block, expected, message ) {
+ "throws": function( block, expected, message ) {
var actual,
+ expectedOutput = expected,
ok = false;
// 'expected' is optional
// we don't want to validate thrown error
if ( !expected ) {
ok = true;
+ expectedOutput = null;
// expected is a regexp
} else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( actual );
+ ok = expected.test( errorString( actual ) );
// expected is a constructor
} else if ( actual instanceof expected ) {
ok = true;
// expected is a validation function which returns true is validation passed
} else if ( expected.call( {}, actual ) === true ) {
+ expectedOutput = null;
ok = true;
}
- QUnit.push( ok, actual, null, message );
+ QUnit.push( ok, actual, expectedOutput, message );
} else {
QUnit.pushFailure( message, null, 'No exception was thrown.' );
}
/**
* @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility
+ * Kept assertion helpers in root for backwards compatibility.
*/
-extend( QUnit, QUnit.assert );
+extend( QUnit, assert );
/**
* @deprecated since 1.9.0
- * Kept global "raises()" for backwards compatibility
+ * Kept root "raises()" for backwards compatibility.
+ * (Note that we don't introduce assert.raises).
*/
-QUnit.raises = QUnit.assert.throws;
+QUnit.raises = assert[ "throws" ];
/**
* @deprecated since 1.0.0, replaced with error pushes since 1.3.0
moduleDone: []
};
+// Export global variables, unless an 'exports' object exists,
+// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
+if ( typeof exports === "undefined" ) {
+ extend( window, QUnit );
+
+ // Expose QUnit object
+ window.QUnit = QUnit;
+}
+
// Initialize more QUnit.config and QUnit.urlParams
(function() {
var i,
QUnit.isLocal = location.protocol === "file:";
}());
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
// Extend QUnit object,
// these after set here because they should not be exposed as global functions
extend( QUnit, {
+ assert: assert,
+
config: config,
// Initialize the configuration options
autorun: false,
filter: "",
queue: [],
- semaphore: 0
+ semaphore: 1
});
var tests, banner, result,
if ( qunit ) {
qunit.innerHTML =
- "<h1 id='qunit-header'>" + escapeInnerText( document.title ) + "</h1>" +
+ "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
"<h2 id='qunit-banner'></h2>" +
"<div id='qunit-testrunner-toolbar'></div>" +
"<h2 id='qunit-userAgent'></h2>" +
// Safe object type checking
is: function( type, obj ) {
- return QUnit.objectType( obj ) == type;
+ return QUnit.objectType( obj ) === type;
},
objectType: function( obj ) {
return "null";
}
- var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || "";
+ var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
+ type = match && match[1] || "";
switch ( type ) {
case "Number":
expected: expected
};
- message = escapeInnerText( message ) || ( result ? "okay" : "failed" );
+ message = escapeText( message ) || ( result ? "okay" : "failed" );
message = "<span class='test-message'>" + message + "</span>";
output = message;
if ( !result ) {
- expected = escapeInnerText( QUnit.jsDump.parse(expected) );
- actual = escapeInnerText( QUnit.jsDump.parse(actual) );
+ expected = escapeText( QUnit.jsDump.parse(expected) );
+ actual = escapeText( QUnit.jsDump.parse(actual) );
output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
- if ( actual != expected ) {
+ if ( actual !== expected ) {
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
}
if ( source ) {
details.source = source;
- output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>";
+ output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
}
output += "</table>";
message: message
};
- message = escapeInnerText( message ) || "error";
+ message = escapeText( message ) || "error";
message = "<span class='test-message'>" + message + "</span>";
output = message;
output += "<table>";
if ( actual ) {
- output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeInnerText( actual ) + "</pre></td></tr>";
+ output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
}
if ( source ) {
details.source = source;
- output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>";
+ output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
}
output += "</table>";
querystring += encodeURIComponent( key ) + "=" +
encodeURIComponent( params[ key ] ) + "&";
}
- return window.location.pathname + querystring.slice( 0, -1 );
+ return window.location.protocol + "//" + window.location.host +
+ window.location.pathname + querystring.slice( 0, -1 );
},
extend: extend,
// testStart: { name }
testStart: registerLoggingCallback( "testStart" ),
- // testDone: { name, failed, passed, total }
+ // testDone: { name, failed, passed, total, duration }
testDone: registerLoggingCallback( "testDone" ),
// moduleStart: { name }
runLoggingCallbacks( "begin", QUnit, {} );
// Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
+ var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
+ urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
+ numModules = 0,
+ moduleFilterHtml = "",
urlConfigHtml = "",
oldconfig = extend( {}, config );
};
}
config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "<input id='qunit-urlconfig-" + val.id + "' name='" + val.id + "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) + " title='" + val.tooltip + "'><label for='qunit-urlconfig-" + val.id + "' title='" + val.tooltip + "'>" + val.label + "</label>";
+ urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
+ "' name='" + escapeText( val.id ) +
+ "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) +
+ " title='" + escapeText( val.tooltip ) +
+ "'><label for='qunit-urlconfig-" + escapeText( val.id ) +
+ "' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
}
- moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " + ( config.module === undefined ? "selected" : "" ) + ">< All Modules ></option>";
+ moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
+ ( config.module === undefined ? "selected='selected'" : "" ) +
+ ">< All Modules ></option>";
+
for ( i in config.modules ) {
if ( config.modules.hasOwnProperty( i ) ) {
numModules += 1;
- moduleFilterHtml += "<option value='" + encodeURIComponent(i) + "' " + ( config.module === i ? "selected" : "" ) + ">" + i + "</option>";
+ moduleFilterHtml += "<option value='" + escapeText( encodeURIComponent(i) ) + "' " +
+ ( config.module === i ? "selected='selected'" : "" ) +
+ ">" + escapeText(i) + "</option>";
}
}
moduleFilterHtml += "</select>";
label.innerHTML = "Hide passed tests";
toolbar.appendChild( label );
- urlConfigCheckboxes = document.createElement( 'span' );
- urlConfigCheckboxes.innerHTML = urlConfigHtml;
- addEvent( urlConfigCheckboxes, "change", function( event ) {
- var params = {};
- params[ event.target.name ] = event.target.checked ? true : undefined;
+ urlConfigCheckboxesContainer = document.createElement("span");
+ urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
+ urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
+ // For oldIE support:
+ // * Add handlers to the individual elements instead of the container
+ // * Use "click" instead of "change"
+ // * Fallback from event.target to event.srcElement
+ addEvents( urlConfigCheckboxes, "click", function( event ) {
+ var params = {},
+ target = event.target || event.srcElement;
+ params[ target.name ] = target.checked ? true : undefined;
window.location = QUnit.url( params );
});
- toolbar.appendChild( urlConfigCheckboxes );
+ toolbar.appendChild( urlConfigCheckboxesContainer );
if (numModules > 1) {
moduleFilter = document.createElement( 'span' );
moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter, "change", function() {
+ addEvent( moduleFilter.lastChild, "change", function() {
var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
+ selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
});
" milliseconds.<br/>",
"<span class='passed'>",
passed,
- "</span> tests of <span class='total'>",
+ "</span> assertions of <span class='total'>",
config.stats.all,
"</span> passed, <span class='failed'>",
config.stats.bad,
function extractStacktrace( e, offset ) {
offset = offset === undefined ? 3 : offset;
- var stack, include, i, regex;
+ var stack, include, i;
if ( e.stacktrace ) {
// Opera
if ( fileName ) {
include = [];
for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) != -1 ) {
+ if ( stack[ i ].indexOf( fileName ) !== -1 ) {
break;
}
include.push( stack[ i ] );
}
}
-function escapeInnerText( s ) {
+/**
+ * Escape text for attribute or text content.
+ */
+function escapeText( s ) {
if ( !s ) {
return "";
}
s = s + "";
- return s.replace( /[\&<>]/g, function( s ) {
+ // Both single quotes and double quotes (for attributes)
+ return s.replace( /['"<>&]/g, function( s ) {
switch( s ) {
- case "&": return "&";
- case "<": return "<";
- case ">": return ">";
- default: return s;
+ case '\'':
+ return ''';
+ case '"':
+ return '"';
+ case '<':
+ return '<';
+ case '>':
+ return '>';
+ case '&':
+ return '&';
}
});
}
}
}
-function checkPollution( name ) {
+function checkPollution() {
var newGlobals,
deletedGlobals,
old = config.pollution;
return a;
}
+/**
+ * @param {HTMLElement} elem
+ * @param {string} type
+ * @param {Function} fn
+ */
function addEvent( elem, type, fn ) {
+ // Standards-based browsers
if ( elem.addEventListener ) {
elem.addEventListener( type, fn, false );
- } else if ( elem.attachEvent ) {
- elem.attachEvent( "on" + type, fn );
+ // IE
} else {
- fn();
+ elem.attachEvent( "on" + type, fn );
}
}
+/**
+ * @param {Array|NodeList} elems
+ * @param {string} type
+ * @param {Function} fn
+ */
+function addEvents( elems, type, fn ) {
+ var i = elems.length;
+ while ( i-- ) {
+ addEvent( elems[i], type, fn );
+ }
+}
+
+function hasClass( elem, name ) {
+ return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
+}
+
+function addClass( elem, name ) {
+ if ( !hasClass( elem, name ) ) {
+ elem.className += (elem.className ? " " : "") + name;
+ }
+}
+
+function removeClass( elem, name ) {
+ var set = " " + elem.className + " ";
+ // Class name may appear multiple times
+ while ( set.indexOf(" " + name + " ") > -1 ) {
+ set = set.replace(" " + name + " " , " ");
+ }
+ // If possible, trim it for prettiness, but not neccecarily
+ elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
+}
+
function id( name ) {
return !!( typeof document !== "undefined" && document && document.getElementById ) &&
document.getElementById( name );
// Supports deprecated method of completely overwriting logging callbacks
function runLoggingCallbacks( key, scope, args ) {
- //debugger;
var i, callbacks;
if ( QUnit.hasOwnProperty( key ) ) {
QUnit[ key ].call(scope, args );
// for string, boolean, number and null
function useStrictEquality( b, a ) {
+ /*jshint eqeqeq:false */
if ( b instanceof a.constructor || a instanceof b.constructor ) {
// to catch short annotaion VS 'new' annotation of a
// declaration
var reName = /^function (\w+)/,
jsDump = {
- parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
+ // type is used mostly internally, you can fix a (custom)type in advance
+ parse: function( obj, type, stack ) {
stack = stack || [ ];
var inStack, res,
parser = this.parsers[ type || this.typeOf(obj) ];
type = typeof parser;
inStack = inArray( obj, stack );
- if ( inStack != -1 ) {
+ if ( inStack !== -1 ) {
return "recursion(" + (inStack - stack.length) + ")";
}
- //else
- if ( type == "function" ) {
+ if ( type === "function" ) {
stack.push( obj );
res = parser.call( this, obj, stack );
stack.pop();
return res;
}
- // else
- return ( type == "string" ) ? parser : this.parsers.error;
+ return ( type === "string" ) ? parser : this.parsers.error;
},
typeOf: function( obj ) {
var type;
( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
) {
type = "array";
+ } else if ( obj.constructor === Error.prototype.constructor ) {
+ type = "error";
} else {
type = typeof obj;
}
separator: function() {
return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " ";
},
- indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
+ // extra can be a number, shortcut for increasing-calling-decreasing
+ indent: function( extra ) {
if ( !this.multiline ) {
return "";
}
parsers: {
window: "[Window]",
document: "[Document]",
- error: "[ERROR]", //when no parser is found, shouldn"t happen
+ error: function(error) {
+ return "Error(\"" + error.message + "\")";
+ },
unknown: "[Unknown]",
"null": "null",
"undefined": "undefined",
"function": function( fn ) {
var ret = "function",
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE
+ // functions never have name in IE
+ name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
if ( name ) {
ret += " " + name;
object: function( map, stack ) {
var ret = [ ], keys, key, val, i;
QUnit.jsDump.up();
- if ( Object.keys ) {
- keys = Object.keys( map );
- } else {
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
+ keys = [];
+ for ( key in map ) {
+ keys.push( key );
}
keys.sort();
for ( i = 0; i < keys.length; i++ ) {
return join( "{", ret, "}" );
},
node: function( node ) {
- var a, val,
+ var len, i, val,
open = QUnit.jsDump.HTML ? "<" : "<",
close = QUnit.jsDump.HTML ? ">" : ">",
tag = node.nodeName.toLowerCase(),
- ret = open + tag;
-
- for ( a in QUnit.jsDump.DOMAttrs ) {
- val = node[ QUnit.jsDump.DOMAttrs[a] ];
- if ( val ) {
- ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" );
+ ret = open + tag,
+ attrs = node.attributes;
+
+ if ( attrs ) {
+ for ( i = 0, len = attrs.length; i < len; i++ ) {
+ val = attrs[i].nodeValue;
+ // IE6 includes all attributes in .attributes, even ones not explicitly set.
+ // Those have values like undefined, null, 0, false, "" or "inherit".
+ if ( val && val !== "inherit" ) {
+ ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
+ }
}
}
- return ret + close + open + "/" + tag + close;
+ ret += close;
+
+ // Show content of TextNode or CDATASection
+ if ( node.nodeType === 3 || node.nodeType === 4 ) {
+ ret += node.nodeValue;
+ }
+
+ return ret + open + "/" + tag + close;
},
- functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function
+ // function calls it internally, it's the arguments part of the function
+ functionArgs: function( fn ) {
var args,
l = fn.length;
args = new Array(l);
while ( l-- ) {
- args[l] = String.fromCharCode(97+l);//97 is 'a'
+ // 97 is 'a'
+ args[l] = String.fromCharCode(97+l);
}
return " " + args.join( ", " ) + " ";
},
- key: quote, //object calls it internally, the key part of an item in a map
- functionCode: "[code]", //function calls it internally, it's the content of the function
- attribute: quote, //node calls it internally, it's an html attribute value
+ // object calls it internally, the key part of an item in a map
+ key: quote,
+ // function calls it internally, it's the content of the function
+ functionCode: "[code]",
+ // node calls it internally, it's an html attribute value
+ attribute: quote,
string: quote,
date: quote,
- regexp: literal, //regex
+ regexp: literal,
number: literal,
"boolean": literal
},
- DOMAttrs: {
- //attributes to dump from nodes, name=>realName
- id: "id",
- name: "name",
- "class": "className"
- },
- HTML: false,//if true, entities are escaped ( <, >, \t, space and \n )
- indentChar: " ",//indentation unit
- multiline: true //if true, items in a collection, are separated by a \n, else just a space.
+ // if true, entities are escaped ( <, >, \t, space and \n )
+ HTML: false,
+ // indentation unit
+ indentChar: " ",
+ // if true, items in a collection, are separated by a \n, else just a space.
+ multiline: true
};
return jsDump;
}());
-// from Sizzle.js
-function getText( elems ) {
- var i, elem,
- ret = "";
-
- for ( i = 0; elems[i]; i++ ) {
- elem = elems[i];
-
- // Get the text from text nodes and CDATA nodes
- if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
- ret += elem.nodeValue;
-
- // Traverse everything else, except comment nodes
- } else if ( elem.nodeType !== 8 ) {
- ret += getText( elem.childNodes );
- }
- }
-
- return ret;
-}
-
// from jquery.js
function inArray( elem, array ) {
if ( array.indexOf ) {
* QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
*/
QUnit.diff = (function() {
+ /*jshint eqeqeq:false, eqnull:true */
function diff( o, n ) {
var i,
ns = {},
os = {};
for ( i = 0; i < n.length; i++ ) {
- if ( ns[ n[i] ] == null ) {
+ if ( !hasOwn.call( ns, n[i] ) ) {
ns[ n[i] ] = {
rows: [],
o: null
}
for ( i = 0; i < o.length; i++ ) {
- if ( os[ o[i] ] == null ) {
+ if ( !hasOwn.call( os, o[i] ) ) {
os[ o[i] ] = {
rows: [],
n: null
if ( !hasOwn.call( ns, i ) ) {
continue;
}
- if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) {
+ if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
n[ ns[i].rows[0] ] = {
text: n[ ns[i].rows[0] ],
row: os[i].rows[0]
// for CommonJS enviroments, export everything
if ( typeof exports !== "undefined" ) {
- extend(exports, QUnit);
+ extend( exports, QUnit );
}
// get at whatever the global object is, like window in browsers
* Remove last character if it is a newline
* @group utility
*/
- static public function chomp( $s ) {
+ public static function chomp( $s ) {
if ( substr( $s, -1 ) === "\n" ) {
return substr( $s, 0, -1 );
} else {
* @param $line Integer: the input line number, for reporting errors
* @param $ignoreDuplicate Boolean: whether to silently ignore duplicate pages
*/
- static public function addArticle( $name, $text, $line = 'unknown', $ignoreDuplicate = '' ) {
+ public static function addArticle( $name, $text, $line = 'unknown', $ignoreDuplicate = '' ) {
global $wgCapitalLinks;
$oldCapitalLinks = $wgCapitalLinks;
<?php
$result = array (
- 'xmp-exif' =>
- array (
- 'CameraOwnerName' => 'Me!',
- ),
- 'xmp-general' =>
- array (
- 'LicenseUrl' => 'http://creativecommons.com/cc-by-2.9',
- 'ImageDescription' =>
- array (
- 'x-default' => 'Test image for the cc: xmp: xmpRights: namespaces in xmp',
- '_type' => 'lang',
- ),
- 'ObjectName' =>
- array (
- 'x-default' => 'xmp core/xmp rights/cc ns test',
- '_type' => 'lang',
- ),
- 'DateTimeDigitized' => '2005:04:03',
- 'Software' => 'The one true editor: Vi (ok i used gimp)',
- 'Identifier' =>
- array (
- 0 => 'http://example.com/identifierurl',
- 1 => 'urn:sha1:342524abcdef',
- '_type' => 'ul',
- ),
- 'Label' => 'Test image',
- 'DateTimeMetadata' => '2011:05:12',
- 'DateTime' => '2007:03:04 06:34:10',
- 'Nickname' => 'My little xmp test image',
- 'Rating' => '5',
- 'RightsCertificate' => 'http://example.com/rights-certificate/',
- 'Copyrighted' => 'True',
- 'CopyrightOwner' =>
- array (
- 0 => 'Bawolff is copyright owner',
- '_type' => 'ul',
- ),
- 'UsageTerms' =>
- array (
- 'x-default' => 'do whatever you want',
- 'en-gb' => 'Do whatever you want in british english',
- '_type' => 'lang',
- ),
- 'WebStatement' => 'http://example.com/web_statement',
- ),
- 'xmp-deprecated' =>
- array (
- 'Identifier' => 'http://example.com/identifierurl/wrong',
- ),
+ 'xmp-exif' =>
+ array (
+ 'CameraOwnerName' => 'Me!',
+ ),
+ 'xmp-general' =>
+ array (
+ 'LicenseUrl' => 'http://creativecommons.com/cc-by-2.9',
+ 'ImageDescription' =>
+ array (
+ 'x-default' => 'Test image for the cc: xmp: xmpRights: namespaces in xmp',
+ '_type' => 'lang',
+ ),
+ 'ObjectName' =>
+ array (
+ 'x-default' => 'xmp core/xmp rights/cc ns test',
+ '_type' => 'lang',
+ ),
+ 'DateTimeDigitized' => '2005:04:03',
+ 'Software' => 'The one true editor: Vi (ok i used gimp)',
+ 'Identifier' =>
+ array (
+ 0 => 'http://example.com/identifierurl',
+ 1 => 'urn:sha1:342524abcdef',
+ '_type' => 'ul',
+ ),
+ 'Label' => 'Test image',
+ 'DateTimeMetadata' => '2011:05:12',
+ 'DateTime' => '2007:03:04 06:34:10',
+ 'Nickname' => 'My little xmp test image',
+ 'Rating' => '5',
+ 'RightsCertificate' => 'http://example.com/rights-certificate/',
+ 'Copyrighted' => 'True',
+ 'CopyrightOwner' =>
+ array (
+ 0 => 'Bawolff is copyright owner',
+ '_type' => 'ul',
+ ),
+ 'UsageTerms' =>
+ array (
+ 'x-default' => 'do whatever you want',
+ 'en-gb' => 'Do whatever you want in british english',
+ '_type' => 'lang',
+ ),
+ 'WebStatement' => 'http://example.com/web_statement',
+ ),
+ 'xmp-deprecated' =>
+ array (
+ 'Identifier' => 'http://example.com/identifierurl/wrong',
+ ),
);
$router->add( "/$2/$1", array( 'restricted-to-y' => '$2' ), array( '$2' => 'y' ) );
foreach ( array(
- "/Foo" => array( 'title' => "Foo" ),
- "/Bar" => array( 'ping' => 'pong' ),
- "/Baz" => array( 'marco' => 'polo' ),
- "/asdf-foo" => array( 'title' => "qwerty-foo" ),
- "/qwerty-bar" => array( 'title' => "asdf-bar" ),
- "/a/Foo" => array( 'title' => "Foo" ),
- "/asdf/Foo" => array( 'title' => "Foo" ),
- "/qwerty/Foo" => array( 'title' => "Foo", 'qwerty' => 'qwerty' ),
- "/baz/Foo" => array( 'title' => "Foo", 'unrestricted' => 'baz' ),
- "/y/Foo" => array( 'title' => "Foo", 'restricted-to-y' => 'y' ),
- ) as $path => $result ) {
+ '/Foo' => array( 'title' => 'Foo' ),
+ '/Bar' => array( 'ping' => 'pong' ),
+ '/Baz' => array( 'marco' => 'polo' ),
+ '/asdf-foo' => array( 'title' => 'qwerty-foo' ),
+ '/qwerty-bar' => array( 'title' => 'asdf-bar' ),
+ '/a/Foo' => array( 'title' => 'Foo' ),
+ '/asdf/Foo' => array( 'title' => 'Foo' ),
+ '/qwerty/Foo' => array( 'title' => 'Foo', 'qwerty' => 'qwerty' ),
+ '/baz/Foo' => array( 'title' => 'Foo', 'unrestricted' => 'baz' ),
+ '/y/Foo' => array( 'title' => 'Foo', 'restricted-to-y' => 'y' ),
+ ) as $path => $result ) {
$this->assertEquals( $router->parse( $path ), $result );
}
}
*/
function escaped( $string ) {
$escaped = '';
- for ( $i = 0; $i < strlen( $string ); $i++ ) {
+ $length = strlen( $string );
+ for ( $i = 0; $i < $length; $i++ ) {
$char = $string[$i];
$val = ord( $char );
if ( $val > 127 ) {
+++ /dev/null
-<?php
-
-/**
- * @group API
- */
-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()->getModuleManager()->getNamesWithClasses();
- 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()->getModuleManager()->getNamesWithClasses();
- $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;
- }
-
-}
$cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "more file contents" );
$cases[] = array(
array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
- "$base/unittest-cont1/e/a/z.txt" ),
+ "$base/unittest-cont1/e/a/z.txt" ),
array( "contents xx", "contents xy", "contents xz" )
);
$cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
$cases[] = array(
array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
- "$base/unittest-cont1/e/a/z.txt" ),
+ "$base/unittest-cont1/e/a/z.txt" ),
array( "contents xx", "contents xy", "contents xz" )
);
$cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
$cases[] = array(
array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
- "$base/unittest-cont1/e/a/z.txt" ),
+ "$base/unittest-cont1/e/a/z.txt" ),
array( "contents xx", "contents xy", "contents xz" )
);
protected $file = false;
protected function setUp() {
- global $wgContLang, $wgLanguageCode;
global $wgNamespaceProtection, $wgNamespaceAliases;
global $wgHooks, $IP;
parent::setUp();
- $wgLanguageCode = 'en';
- $wgContLang = Language::factory( 'en' );
-
//Setup CLI arguments
if ( $this->getCliArg( 'regex=' ) ) {
$this->regex = $this->getCliArg( 'regex=' );
$tmpGlobals = array();
+ $tmpGlobals['wgLanguageCode'] = 'en';
+ $tmpGlobals['wgContLang'] = Language::factory( 'en' );
$tmpGlobals['wgScript'] = '/index.php';
$tmpGlobals['wgScriptPath'] = '/';
$tmpGlobals['wgArticlePath'] = '/wiki/$1';
* Set up the global variables for a consistent environment for each test.
* Ideally this should replace the global configuration entirely.
*/
- protected function setupGlobals( $opts = '', $config = '' ) {
+ protected function setupGlobals( $opts = array(), $config = '' ) {
global $wgFileBackends;
# Find out values for some special options.
$lang =
'wgRawHtml' => isset( $opts['rawhtml'] ),
'wgLang' => null,
'wgContLang' => null,
- 'wgNamespacesWithSubpages' => array( 0 => isset( $opts['subpage'] ) ),
+ 'wgNamespacesWithSubpages' => array( NS_MAIN => isset( $opts['subpage'] ) ),
'wgMaxTocLevel' => $maxtoclevel,
'wgCapitalLinks' => true,
'wgNoFollowLinks' => true,
liveMessages = mw.messages.values;
function freshConfigCopy( custom ) {
- // "deep=true" is important here.
- // Otherwise we just create a new object with values referring to live config.
- // e.g. mw.config.set( 'wgFileExtensions', [] ) would not effect liveConfig,
- // but mw.config.get( 'wgFileExtensions' ).push( 'png' ) would as the array
- // was passed by reference in $.extend's loop.
- return $.extend( /*deep=*/true, {}, liveConfig, custom );
+ // Tests should mock all factors that directly influence the tested code.
+ // For backwards compatibility though we set mw.config to a copy of the live config
+ // and extend it with the (optionally) given custom settings for this test
+ // (instead of starting blank with only the given custmo settings).
+ // This is a shallow copy, so we don't end up with settings taking an array value
+ // extended with the custom settings - setting a config property means you override it,
+ // not extend it.
+ return $.extend( {}, liveConfig, custom );
}
function freshMessagesCopy( custom ) {
self::$url = $url;
}
- static public function getUrl() {
+ public static function getUrl() {
return self::$url;
}
const RESULT_OK = 2;
const RESULT_ERROR = 3;
- public abstract function addTests();
+ abstract public function addTests();
public function setUp() {
// Hack because because PHPUnit version 3.0.6 which is on prototype does not