*/
use MediaWiki\MediaWikiServices;
use Wikimedia\ScopedCallback;
-use MediaWiki\Logger\LoggerFactory;
/**
* MediaWiki message cache structure version.
*/
protected $mCache;
- /**
- * @var bool[] Map of (language code => boolean)
- */
- protected $mCacheVolatile = [];
-
/**
* Should mean that database cannot be used, but check
* @var bool $mDisable
protected $mExpiry;
/**
- * Message cache has its own parser which it uses to transform messages
- * @var ParserOptions
+ * Message cache has its own parser which it uses to transform
+ * messages.
*/
- protected $mParserOptions;
- /** @var Parser */
- protected $mParser;
+ protected $mParserOptions, $mParser;
/**
* Variable for tracking which variables are already loaded
*/
public static function normalizeKey( $key ) {
global $wgContLang;
-
$lckey = strtr( $key, ' ', '_' );
if ( ord( $lckey ) < 128 ) {
$lckey[0] = strtolower( $lckey[0] );
# Hash of the contents is stored in memcache, to detect if data-center cache
# or local cache goes out of date (e.g. due to replace() on some other server)
list( $hash, $hashVolatile ) = $this->getValidationHash( $code );
- $this->mCacheVolatile[$code] = $hashVolatile;
# Try the local cache and check against the cluster hash key...
$cache = $this->getLocalCache( $code );
$bigConds[] = 'page_len > ' . intval( $wgMaxMsgCacheEntrySize );
# Load titles for all oversized pages in the MediaWiki namespace
- $res = $dbr->select(
- 'page',
- [ 'page_title', 'page_latest' ],
- $bigConds,
- __METHOD__ . "($code)-big"
- );
+ $res = $dbr->select( 'page', 'page_title', $bigConds, __METHOD__ . "($code)-big" );
foreach ( $res as $row ) {
$cache[$row->page_title] = '!TOO BIG';
- // At least include revision ID so page changes are reflected in the hash
- $cache['EXCESSIVE'][$row->page_title] = $row->page_latest;
}
# Conditions to load the remaining pages with their contents
* Updates cache as necessary when message page is changed
*
* @param string|bool $title Name of the page changed (false if deleted)
- * @param string|bool $text New contents of the page (false if deleted)
+ * @param mixed $text New contents of the page.
*/
public function replace( $title, $text ) {
global $wgMaxMsgCacheEntrySize, $wgContLang, $wgLanguageCode;
// a self-deadlock. This is safe as no reads happen *directly* in this
// method between getReentrantScopedLock() and load() below. There is
// no risk of data "changing under our feet" for replace().
- $scopedLock = $this->getReentrantScopedLock( wfMemcKey( 'messages', $code ) );
- // Load the messages from the master DB to avoid race conditions
+ $cacheKey = wfMemcKey( 'messages', $code );
+ $scopedLock = $this->getReentrantScopedLock( $cacheKey );
$this->load( $code, self::FOR_UPDATE );
- // Load the new value into the process cache...
+ $titleKey = wfMemcKey( 'messages', 'individual', $title );
if ( $text === false ) {
+ // Article was deleted
$this->mCache[$code][$title] = '!NONEXISTENT';
+ $this->wanCache->delete( $titleKey );
} elseif ( strlen( $text ) > $wgMaxMsgCacheEntrySize ) {
+ // Check for size
$this->mCache[$code][$title] = '!TOO BIG';
- // Pre-fill the individual key cache with the known latest message text
- $key = $this->wanCache->makeKey( 'messages-big', $this->mCache[$code]['HASH'], $title );
- $this->wanCache->set( $key, " $text", $this->mExpiry );
+ $this->wanCache->set( $titleKey, ' ' . $text, $this->mExpiry );
} else {
$this->mCache[$code][$title] = ' ' . $text;
+ $this->wanCache->delete( $titleKey );
}
- // Mark this cache as definitely being "latest" (non-volatile) so
- // load() calls do not try to refresh the cache with replica DB data
+
+ // Mark this cache as definitely "latest" (non-volatile) so
+ // load() calls do try to refresh the cache with replica DB data
$this->mCache[$code]['LATEST'] = time();
// Update caches if the lock was acquired
if ( $scopedLock ) {
$this->saveToCaches( $this->mCache[$code], 'all', $code );
- } else {
- LoggerFactory::getInstance( 'MessageCache' )->error(
- __METHOD__ . ': could not acquire lock to update {title} ({code})',
- [ 'title' => $title, 'code' => $code ] );
}
ScopedCallback::consume( $scopedLock );
protected function getValidationHash( $code ) {
$curTTL = null;
$value = $this->wanCache->get(
- $this->wanCache->makeKey( 'messages', $code, 'hash', 'v1' ),
+ wfMemcKey( 'messages', $code, 'hash', 'v1' ),
$curTTL,
[ wfMemcKey( 'messages', $code ) ]
);
- if ( $value ) {
+ if ( !$value ) {
+ // No hash found at all; cache must regenerate to be safe
+ $hash = false;
+ $expired = true;
+ } else {
$hash = $value['hash'];
- if ( ( time() - $value['latest'] ) < WANObjectCache::TTL_MINUTE ) {
- // Cache was recently updated via replace() and should be up-to-date.
- // That method is only called in the primary datacenter and uses FOR_UPDATE.
- // Also, it is unlikely that the current datacenter is *now* secondary one.
+ if ( ( time() - $value['latest'] ) < WANObjectCache::HOLDOFF_TTL ) {
+ // Cache was recently updated via replace() and should be up-to-date
$expired = false;
} else {
// See if the "check" key was bumped after the hash was generated
$expired = ( $curTTL < 0 );
}
- } else {
- // No hash found at all; cache must regenerate to be safe
- $hash = false;
- $expired = true;
}
return [ $hash, $expired ];
* Set the md5 used to validate the local disk cache
*
* If $cache has a 'LATEST' UNIX timestamp key, then the hash will not
- * be treated as "volatile" by getValidationHash() for the next few seconds.
- * This is triggered when $cache is generated using FOR_UPDATE mode.
+ * be treated as "volatile" by getValidationHash() for the next few seconds
*
* @param string $code
* @param array $cache Cached messages with a version
*/
protected function setValidationHash( $code, array $cache ) {
$this->wanCache->set(
- $this->wanCache->makeKey( 'messages', $code, 'hash', 'v1' ),
+ wfMemcKey( 'messages', $code, 'hash', 'v1' ),
[
'hash' => $cache['HASH'],
'latest' => isset( $cache['LATEST'] ) ? $cache['LATEST'] : 0
*/
private function getMessageForLang( $lang, $lckey, $useDB, &$alreadyTried ) {
global $wgContLang;
-
$langcode = $lang->getCode();
// Try checking the database for the requested language
*/
private function getMessagePageName( $langcode, $uckey ) {
global $wgLanguageCode;
-
if ( $langcode === $wgLanguageCode ) {
// Messages created in the content language will not have the /lang extension
return $uckey;
if ( isset( $this->mCache[$code][$title] ) ) {
$entry = $this->mCache[$code][$title];
if ( substr( $entry, 0, 1 ) === ' ' ) {
- // The message exists, so make sure a string is returned.
+ // The message exists, so make sure a string
+ // is returned.
return (string)substr( $entry, 1 );
} elseif ( $entry === '!NONEXISTENT' ) {
return false;
}
// Try the individual message cache
- $titleKey = $this->wanCache->makeKey( 'messages-big', $this->mCache[$code]['HASH'], $title );
-
- if ( $this->mCacheVolatile[$code] ) {
- $entry = false;
- // Make sure that individual keys respect the WAN cache holdoff period too
- LoggerFactory::getInstance( 'MessageCache' )->debug(
- __METHOD__ . ': loading volatile key \'{titleKey}\'',
- [ 'titleKey' => $titleKey, 'code' => $code ] );
- } else {
- $entry = $this->wanCache->get( $titleKey );
- }
+ $titleKey = wfMemcKey( 'messages', 'individual', $title );
- if ( $entry !== false ) {
+ $curTTL = null;
+ $entry = $this->wanCache->get(
+ $titleKey,
+ $curTTL,
+ [ wfMemcKey( 'messages', $code ) ]
+ );
+ $entry = ( $curTTL >= 0 ) ? $entry : false;
+
+ if ( $entry ) {
if ( substr( $entry, 0, 1 ) === ' ' ) {
$this->mCache[$code][$title] = $entry;
// The message exists, so make sure a string is returned
}
}
- // Try loading the message from the database
+ // Try loading it from the database
$dbr = wfGetDB( DB_REPLICA );
$cacheOpts = Database::getCacheSetOptions( $dbr );
// Use newKnownCurrent() to avoid querying revision/user tables
if ( $revision ) {
$content = $revision->getContent();
- if ( $content ) {
- $message = $this->getMessageTextFromContent( $content );
- if ( is_string( $message ) ) {
+ if ( !$content ) {
+ // A possibly temporary loading failure.
+ wfDebugLog(
+ 'MessageCache',
+ __METHOD__ . ": failed to load message page text for {$title} ($code)"
+ );
+ $message = null; // no negative caching
+ } else {
+ // XXX: Is this the right way to turn a Content object into a message?
+ // NOTE: $content is typically either WikitextContent, JavaScriptContent or
+ // CssContent. MessageContent is *not* used for storing messages, it's
+ // only used for wrapping them when needed.
+ $message = $content->getWikitextForTransclusion();
+
+ if ( $message === false || $message === null ) {
+ wfDebugLog(
+ 'MessageCache',
+ __METHOD__ . ": message content doesn't provide wikitext "
+ . "(content model: " . $content->getModel() . ")"
+ );
+
+ $message = false; // negative caching
+ } else {
$this->mCache[$code][$title] = ' ' . $message;
$this->wanCache->set( $titleKey, ' ' . $message, $this->mExpiry, $cacheOpts );
}
- } else {
- // A possibly temporary loading failure
- LoggerFactory::getInstance( 'MessageCache' )->warning(
- __METHOD__ . ': failed to load message page text for \'{titleKey}\'',
- [ 'titleKey' => $titleKey, 'code' => $code ] );
- $message = null; // no negative caching
}
} else {
$message = false; // negative caching
*/
function getParser() {
global $wgParser, $wgParserConf;
-
if ( !$this->mParser && isset( $wgParser ) ) {
# Do some initialisation so that we don't have to do it twice
$wgParser->firstCallInit();
public function parse( $text, $title = null, $linestart = true,
$interface = false, $language = null
) {
- global $wgTitle;
-
if ( $this->mInParser ) {
return htmlspecialchars( $text );
}
$popts->setTargetLanguage( $language );
if ( !$title || !$title instanceof Title ) {
+ global $wgTitle;
wfDebugLog( 'GlobalTitleFail', __METHOD__ . ' called by ' .
wfGetAllCallers( 6 ) . ' with no title set.' );
$title = $wgTitle;
*/
public function getAllMessageKeys( $code ) {
global $wgContLang;
-
$this->load( $code );
if ( !isset( $this->mCache[$code] ) ) {
// Apparently load() failed
$cache = $this->mCache[$code];
unset( $cache['VERSION'] );
unset( $cache['EXPIRY'] );
- unset( $cache['EXCESSIVE'] );
// Remove any !NONEXISTENT keys
$cache = array_diff( $cache, [ '!NONEXISTENT' ] );
// Keys may appear with a capital first letter. lcfirst them.
return array_map( [ $wgContLang, 'lcfirst' ], array_keys( $cache ) );
}
-
- /**
- * Purge message caches when a MediaWiki: page is created, updated, or deleted
- *
- * @param Title $title Message page title
- * @param Content|null $content New content for edit/create, null on deletion
- * @since 1.29
- */
- public function updateMessageOverride( Title $title, Content $content = null ) {
- global $wgContLang;
-
- $msgText = $this->getMessageTextFromContent( $content );
- if ( $msgText === null ) {
- $msgText = false; // treat as not existing
- }
-
- $this->replace( $title->getDBkey(), $msgText );
-
- if ( $wgContLang->hasVariants() ) {
- $wgContLang->updateConversionTable( $title );
- }
- }
-
- /**
- * @param Content|null $content Content or null if the message page does not exist
- * @return string|bool|null Returns false if $content is null and null on error
- */
- private function getMessageTextFromContent( Content $content = null ) {
- // @TODO: could skip pseudo-messages like js/css here, based on content model
- if ( $content ) {
- // Message page exists...
- // XXX: Is this the right way to turn a Content object into a message?
- // NOTE: $content is typically either WikitextContent, JavaScriptContent or
- // CssContent. MessageContent is *not* used for storing messages, it's
- // only used for wrapping them when needed.
- $msgText = $content->getWikitextForTransclusion();
- if ( $msgText === false || $msgText === null ) {
- // This might be due to some kind of misconfiguration...
- $msgText = null;
- LoggerFactory::getInstance( 'MessageCache' )->warning(
- __METHOD__ . ": message content doesn't provide wikitext "
- . "(content model: " . $content->getModel() . ")" );
- }
- } else {
- // Message page does not exist...
- $msgText = false;
- }
-
- return $msgText;
- }
}
'.' => ','
];
-$fallback = 'ru';
$fallback8bitEncoding = 'windows-1251';
$linkPrefixExtension = true;
'Зображення' => NS_FILE,
'Обговорення_зображення' => NS_FILE_TALK,
'Обговорення_шаблона' => NS_TEMPLATE_TALK,
+ // Backwards compatibility from Russian
+ 'Медиа' => NS_MEDIA,
+ 'Служебная' => NS_SPECIAL,
+ 'Обсуждение' => NS_TALK,
+ 'Участник' => NS_USER,
+ 'Обсуждение_участника' => NS_USER_TALK,
+ 'Обсуждение_файла' => NS_FILE_TALK,
+ 'Обсуждение_MediaWiki' => NS_MEDIAWIKI_TALK,
+ 'Обсуждение_шаблона' => NS_TEMPLATE_TALK,
+ 'Справка' => NS_HELP,
+ 'Обсуждение_справки' => NS_HELP_TALK,
+ 'Категория' => NS_CATEGORY,
+ 'Обсуждение_категории' => NS_CATEGORY_TALK,
+ 'Изображение' => NS_FILE,
+ 'Обсуждение_изображения' => NS_FILE_TALK,
];
-// Remove Russian aliases
-$namespaceGenderAliases = [];
-
$dateFormats = [
'mdy time' => 'H:i',
'mdy date' => 'xg j, Y',
'Amazon.com' => 'http://www.amazon.com/exec/obidos/ISBN=$1'
];
+// Russian names are kept for backwards compatibility
$specialPageAliases = [
- 'Activeusers' => [ 'Активні_дописувачі' ],
- 'Allmessages' => [ 'Системні_повідомлення' ],
- 'AllMyUploads' => [ 'Усі_мої_файли' ],
- 'Allpages' => [ 'Усі_сторінки' ],
+ 'Activeusers' => [ 'Активні_дописувачі', 'Активные_участники' ],
+ 'Allmessages' => [ 'Системні_повідомлення', 'Системные_сообщения' ],
+ 'AllMyUploads' => [ 'Усі_мої_файли', 'Все_мои_файлы' ],
+ 'Allpages' => [ 'Усі_сторінки', 'Все_страницы' ],
'Ancientpages' => [ 'Давні_сторінки' ],
- 'Badtitle' => [ 'Помилковий_заголовок' ],
- 'Blankpage' => [ 'Порожня_сторінка' ],
- 'Block' => [ 'Заблокувати' ],
- 'Booksources' => [ 'Джерела_книг' ],
- 'BrokenRedirects' => [ 'Розірвані_перенаправлення' ],
- 'Categories' => [ 'Категорії' ],
- 'ChangeEmail' => [ 'Змінити_e-mail' ],
- 'ChangePassword' => [ 'Змінити_пароль' ],
- 'ComparePages' => [ 'Порівняння_сторінок' ],
- 'Confirmemail' => [ 'Підтвердити_e-mail' ],
- 'Contributions' => [ 'Внесок' ],
- 'CreateAccount' => [ 'Створити_обліковий_запис' ],
- 'Deadendpages' => [ 'Сторінки_без_посилань' ],
- 'DeletedContributions' => [ 'Вилучений_внесок' ],
- 'DoubleRedirects' => [ 'Подвійні_перенаправлення' ],
- 'EditWatchlist' => [ 'Редагувати_список_спостереження' ],
- 'Emailuser' => [ 'Лист_користувачеві' ],
- 'ExpandTemplates' => [ 'Розгортання_шаблонів' ],
- 'Export' => [ 'Експорт' ],
- 'Fewestrevisions' => [ 'Найменшредаговані' ],
- 'FileDuplicateSearch' => [ 'Пошук_дублікатів_файлів' ],
- 'Filepath' => [ 'Шлях_до_файлу' ],
- 'Import' => [ 'Імпорт' ],
- 'Invalidateemail' => [ 'Неперевірена_email-адреса' ],
- 'JavaScriptTest' => [ 'JavaScript_тест' ],
- 'BlockList' => [ 'Список_блокувань', 'Блокування', 'Блокування_IP-адрес' ],
- 'LinkSearch' => [ 'Пошук_посилань' ],
- 'Listadmins' => [ 'Список_адміністраторів' ],
- 'Listbots' => [ 'Список_ботів' ],
- 'Listfiles' => [ 'Список_файлів' ],
- 'Listgrouprights' => [ 'Список_прав_груп', 'Права_груп_користувачів' ],
- 'Listredirects' => [ 'Список_перенаправлень' ],
- 'ListDuplicatedFiles' => [ 'Список_дубльованих_файлів' ],
- 'Listusers' => [ 'Список_користувачів' ],
- 'Lockdb' => [ 'Заблокувати_базу_даних' ],
- 'Log' => [ 'Журнали' ],
- 'Lonelypages' => [ 'Ізольовані_сторінки' ],
- 'Longpages' => [ 'Найдовші_сторінки' ],
- 'MergeHistory' => [ 'Об\'єднання_історії' ],
- 'MIMEsearch' => [ 'Пошук_за_MIME' ],
- 'Mostcategories' => [ 'Найбільш_категоризовані' ],
- 'Mostimages' => [ 'Найуживаніші_файли' ],
- 'Mostinterwikis' => [ 'Найбільше_інтервікі' ],
- 'Mostlinked' => [ 'Найуживаніші_сторінки', 'Найбільше_посилань' ],
- 'Mostlinkedcategories' => [ 'Найуживаніші_категорії' ],
- 'Mostlinkedtemplates' => [ 'Найуживаніші_шаблони' ],
- 'Mostrevisions' => [ 'Найбільш_редаговані' ],
- 'Movepage' => [ 'Перейменувати' ],
- 'Mycontributions' => [ 'Мій_внесок' ],
- 'MyLanguage' => [ 'Моя_мова' ],
- 'Mypage' => [ 'Моя_сторінка' ],
- 'Mytalk' => [ 'Моє_обговорення' ],
- 'Myuploads' => [ 'Мої_завантаження' ],
- 'Newimages' => [ 'Нові_файли' ],
- 'Newpages' => [ 'Нові_сторінки' ],
- 'PasswordReset' => [ 'Скинути_пароль' ],
- 'PermanentLink' => [ 'Постійне_посилання' ],
- 'Preferences' => [ 'Налаштування' ],
- 'Prefixindex' => [ 'Покажчик_за_початком_назви' ],
- 'Protectedpages' => [ 'Захищені_сторінки' ],
- 'Protectedtitles' => [ 'Захищені_назви_сторінок' ],
- 'Randompage' => [ 'Випадкова_сторінка' ],
- 'Randomredirect' => [ 'Випадкове_перенаправлення' ],
- 'Recentchanges' => [ 'Нові_редагування' ],
- 'Recentchangeslinked' => [ 'Пов\'язані_редагування' ],
+ 'Badtitle' => [ 'Помилковий_заголовок', 'Недопустимое_название' ],
+ 'Blankpage' => [ 'Порожня_сторінка', 'Пустая_страница' ],
+ 'Block' => [ 'Заблокувати', 'Заблокировать' ],
+ 'Booksources' => [ 'Джерела_книг', 'Источники_книг' ],
+ 'BrokenRedirects' => [ 'Розірвані_перенаправлення', 'Разорванные_перенаправления' ],
+ 'Categories' => [ 'Категорії', 'Категории' ],
+ 'ChangeEmail' => [ 'Змінити_e-mail', 'Сменить_e-mail', 'Сменить_почту' ],
+ 'ChangePassword' => [ 'Змінити_пароль', 'Сменить_пароль' ],
+ 'ComparePages' => [ 'Порівняння_сторінок', 'Сравнение_страниц' ],
+ 'Confirmemail' => [ 'Підтвердити_e-mail', 'Подтвердить_e-mail', 'Подтвердить_почту' ],
+ 'Contributions' => [ 'Внесок', 'Вклад' ],
+ 'CreateAccount' => [ 'Створити_обліковий_запис', 'Создать_учётную_запись', 'Создать_пользователя', 'Зарегистрироваться' ],
+ 'Deadendpages' => [ 'Сторінки_без_посилань', 'Тупиковые_страницы' ],
+ 'DeletedContributions' => [ 'Вилучений_внесок', 'Удалённый_вклад' ],
+ 'DoubleRedirects' => [ 'Подвійні_перенаправлення', 'Двойные_перенаправления' ],
+ 'EditWatchlist' => [ 'Редагувати_список_спостереження', 'Править_список_наблюдения' ],
+ 'Emailuser' => [ 'Лист_користувачеві', 'Письмо_участнику', 'Отправить_письмо' ],
+ 'ExpandTemplates' => [ 'Розгортання_шаблонів', 'Развёртка_шаблонов' ],
+ 'Export' => [ 'Експорт', 'Экспорт', 'Выгрузка' ],
+ 'Fewestrevisions' => [ 'Найменшредаговані', 'Редко_редактируемые' ],
+ 'FileDuplicateSearch' => [ 'Пошук_дублікатів_файлів', 'Поиск_дубликатов_файлов' ],
+ 'Filepath' => [ 'Шлях_до_файлу', 'Путь_к_файлу' ],
+ 'Import' => [ 'Імпорт', 'Импорт' ],
+ 'Invalidateemail' => [ 'Неперевірена_email-адреса', 'Отменить_подтверждение_адреса' ],
+ 'JavaScriptTest' => [ 'JavaScript_тест', 'Тестирование_JavaScript' ],
+ 'BlockList' => [ 'Список_блокувань', 'Блокування', 'Блокування_IP-адрес', 'Список_блокировок', 'Блокировки' ],
+ 'LinkSearch' => [ 'Пошук_посилань', 'Поиск_ссылок' ],
+ 'Listadmins' => [ 'Список_адміністраторів', 'Список_администраторов' ],
+ 'Listbots' => [ 'Список_ботів', 'Список_ботов' ],
+ 'Listfiles' => [ 'Список_файлів', 'Список_файлов', 'Список_изображений' ],
+ 'Listgrouprights' => [ 'Список_прав_груп', 'Права_груп_користувачів', 'Права_групп_участников', 'Список_прав_групп' ],
+ 'Listredirects' => [ 'Список_перенаправлень', 'Список_перенаправлений' ],
+ 'ListDuplicatedFiles' => [ 'Список_дубльованих_файлів', 'Список_файлов-дубликатов' ],
+ 'Listusers' => [ 'Список_користувачів', 'Список_участников' ],
+ 'Lockdb' => [ 'Заблокувати_базу_даних', 'Заблокировать_БД', 'Заблокировать_базу_данных' ],
+ 'Log' => [ 'Журнали', 'Журналы', 'Журнал' ],
+ 'Lonelypages' => [ 'Ізольовані_сторінки', 'Изолированные_страницы' ],
+ 'Longpages' => [ 'Найдовші_сторінки', 'Длинные_страницы' ],
+ 'MergeHistory' => [ 'Об\'єднання_історії', 'Объединение_историй' ],
+ 'MIMEsearch' => [ 'Пошук_за_MIME', 'Поиск_по_MIME' ],
+ 'Mostcategories' => [ 'Найбільш_категоризовані', 'Самые_категоризованные' ],
+ 'Mostimages' => [ 'Найуживаніші_файли', 'Самые_используемые_файлы' ],
+ 'Mostinterwikis' => [ 'Найбільше_інтервікі', 'Наибольшее_количество_интервики-ссылок' ],
+ 'Mostlinked' => [ 'Найуживаніші_сторінки', 'Найбільше_посилань', 'Самые_используемые_страницы' ],
+ 'Mostlinkedcategories' => [ 'Найуживаніші_категорії', 'Самые_используемые_категории' ],
+ 'Mostlinkedtemplates' => [ 'Найуживаніші_шаблони', 'Самые_используемые_шаблоны' ],
+ 'Mostrevisions' => [ 'Найбільш_редаговані', 'Наибольшее_количество_версий' ],
+ 'Movepage' => [ 'Перейменувати', 'Переименовать_страницу', 'Переименование', 'Переименовать' ],
+ 'Mycontributions' => [ 'Мій_внесок', 'Мой_вклад' ],
+ 'MyLanguage' => [ 'Моя_мова', 'Мой_язык' ],
+ 'Mypage' => [ 'Моя_сторінка', 'Моя_страница' ],
+ 'Mytalk' => [ 'Моє_обговорення', 'Моё_обсуждение' ],
+ 'Myuploads' => [ 'Мої_завантаження', 'Мои_загрузки' ],
+ 'Newimages' => [ 'Нові_файли', 'Новые_файлы' ],
+ 'Newpages' => [ 'Нові_сторінки', 'Новые_страницы' ],
+ 'PasswordReset' => [ 'Скинути_пароль', 'Сброс_пароля' ],
+ 'PermanentLink' => [ 'Постійне_посилання', 'Постоянная_ссылка' ],
+ 'Preferences' => [ 'Налаштування', 'Настройки' ],
+ 'Prefixindex' => [ 'Покажчик_за_початком_назви', 'Указатель_по_началу_названия' ],
+ 'Protectedpages' => [ 'Захищені_сторінки', 'Защищённые_страницы' ],
+ 'Protectedtitles' => [ 'Захищені_назви_сторінок', 'Защищённые_названия' ],
+ 'Randompage' => [ 'Випадкова_сторінка', 'Случайная_страница', 'Случайная' ],
+ 'Randomredirect' => [ 'Випадкове_перенаправлення', 'Случайное_перенаправление' ],
+ 'Recentchanges' => [ 'Нові_редагування', 'Свежие_правки' ],
+ 'Recentchangeslinked' => [ 'Пов\'язані_редагування', 'Связанные_правки' ],
'Redirect' => [ 'Перенаправлення' ],
- 'Revisiondelete' => [ 'Вилучити_редагування' ],
- 'Search' => [ 'Пошук' ],
- 'Shortpages' => [ 'Короткі_сторінки' ],
- 'Specialpages' => [ 'Спеціальні_сторінки' ],
+ 'Revisiondelete' => [ 'Вилучити_редагування', 'Удаление_правки' ],
+ 'Search' => [ 'Пошук', 'Поиск' ],
+ 'Shortpages' => [ 'Короткі_сторінки', 'Короткие_страницы' ],
+ 'Specialpages' => [ 'Спеціальні_сторінки', 'Спецстраницы' ],
'Statistics' => [ 'Статистика' ],
- 'Tags' => [ 'Мітки' ],
- 'Unblock' => [ 'Розблокувати' ],
- 'Uncategorizedcategories' => [ 'Некатегоризовані_категорії' ],
- 'Uncategorizedimages' => [ 'Некатегоризовані_файли' ],
- 'Uncategorizedpages' => [ 'Некатегоризовані_сторінки' ],
- 'Uncategorizedtemplates' => [ 'Некатегоризовані_шаблони' ],
- 'Undelete' => [ 'Відновити' ],
- 'Unlockdb' => [ 'Розблокувати_базу_даних' ],
- 'Unusedcategories' => [ 'Порожні_категорії' ],
- 'Unusedimages' => [ 'Невикористані_файли' ],
- 'Unusedtemplates' => [ 'Невикористані_шаблони' ],
+ 'Tags' => [ 'Мітки', 'Метки' ],
+ 'Unblock' => [ 'Розблокувати', 'Разблокировка' ],
+ 'Uncategorizedcategories' => [ 'Некатегоризовані_категорії', 'Некатегоризованные_категории' ],
+ 'Uncategorizedimages' => [ 'Некатегоризовані_файли', 'Некатегоризованные_файлы' ],
+ 'Uncategorizedpages' => [ 'Некатегоризовані_сторінки', 'Некатегоризованные_страницы' ],
+ 'Uncategorizedtemplates' => [ 'Некатегоризовані_шаблони', 'Некатегоризованные_шаблоны' ],
+ 'Undelete' => [ 'Відновити', 'Восстановить', 'Восстановление' ],
+ 'Unlockdb' => [ 'Розблокувати_базу_даних', 'Разблокировка_БД' ],
+ 'Unusedcategories' => [ 'Порожні_категорії', 'Неиспользуемые_категории' ],
+ 'Unusedimages' => [ 'Невикористані_файли', 'Неиспользуемые_файлы' ],
+ 'Unusedtemplates' => [ 'Невикористані_шаблони', 'Неиспользуемые_шаблоны' ],
'Unwatchedpages' => [ 'Неспостережувані' ],
- 'Upload' => [ 'Завантаження' ],
- 'UploadStash' => [ 'Приховане_завантаження' ],
- 'Userlogin' => [ 'Вхід' ],
- 'Userlogout' => [ 'Вихід' ],
- 'Userrights' => [ 'Керування_правами_користувачів' ],
- 'Version' => [ 'Версія' ],
- 'Wantedcategories' => [ 'Потрібні_категорії' ],
- 'Wantedfiles' => [ 'Потрібні_файли' ],
- 'Wantedpages' => [ 'Потрібні_сторінки' ],
- 'Wantedtemplates' => [ 'Потрібні_шаблони' ],
- 'Watchlist' => [ 'Список_спостереження' ],
- 'Whatlinkshere' => [ 'Посилання_сюди' ],
- 'Withoutinterwiki' => [ 'Без_інтервікі' ],
+ 'Upload' => [ 'Завантаження', 'Загрузка' ],
+ 'UploadStash' => [ 'Приховане_завантаження', 'Скрытная_загрузка' ],
+ 'Userlogin' => [ 'Вхід', 'Вход' ],
+ 'Userlogout' => [ 'Вихід', 'Завершение_сеанса', 'Выход' ],
+ 'Userrights' => [ 'Керування_правами_користувачів', 'Управление_правами' ],
+ 'Version' => [ 'Версія', 'Версия' ],
+ 'Wantedcategories' => [ 'Потрібні_категорії', 'Требуемые_категории' ],
+ 'Wantedfiles' => [ 'Потрібні_файли', 'Требуемые_файлы' ],
+ 'Wantedpages' => [ 'Потрібні_сторінки', 'Требуемые_страницы' ],
+ 'Wantedtemplates' => [ 'Потрібні_шаблони', 'Требуемые_шаблоны' ],
+ 'Watchlist' => [ 'Список_спостереження', 'Список_наблюдения' ],
+ 'Whatlinkshere' => [ 'Посилання_сюди', 'Ссылки_сюда' ],
+ 'Withoutinterwiki' => [ 'Без_інтервікі', 'Без_интервики' ],
];
$magicWords = [
'pagesincategory_all' => [ '0', 'усе', 'все', 'all' ],
'pagesincategory_pages' => [ '0', 'сторінки', 'страницы', 'pages' ],
'pagesincategory_subcats' => [ '0', 'підкатегорії', 'подкатегории', 'subcats' ],
+ 'pagesincategory_files' => [ '0', 'файли', 'файлы', 'files' ],
];
$linkTrail = '/^([a-zабвгґдеєжзиіїйклмнопрстуфхцчшщьєюяёъы“»]+)(.*)$/sDu';
$linkPrefixCharset = '„«';
-