/** * @dataProvider provideNormalizeKey */ public function testNormalizeKey($key, $expected) { $actual = MessageCache::normalizeKey($key); $this->assertEquals($expected, $actual); }
/** * Get a message from either the content language or the user language. * * First, assemble a list of languages to attempt getting the message from. This * chain begins with the requested language and its fallbacks and then continues with * the content language and its fallbacks. For each language in the chain, the following * process will occur (in this order): * 1. If a language-specific override, i.e., [[MW:msg/lang]], is available, use that. * Note: for the content language, there is no /lang subpage. * 2. Fetch from the static CDB cache. * 3. If available, check the database for fallback language overrides. * * This process provides a number of guarantees. When changing this code, make sure all * of these guarantees are preserved. * * If the requested language is *not* the content language, then the CDB cache for that * specific language will take precedence over the root database page ([[MW:msg]]). * * Fallbacks will be just that: fallbacks. A fallback language will never be reached if * the message is available *anywhere* in the language for which it is a fallback. * * @param string $key The message key * @param bool $useDB If true, look for the message in the DB, false * to use only the compiled l10n cache. * @param bool|string|object $langcode Code of the language to get the message for. * - If string and a valid code, will create a standard language object * - If string but not a valid code, will create a basic language object * - If boolean and false, create object from the current users language * - If boolean and true, create object from the wikis content language * - If language object, use it as given * @param bool $isFullKey Specifies whether $key is a two part key "msg/lang". * * @throws MWException When given an invalid key * @return string|bool False if the message doesn't exist, otherwise the * message (which can be empty) */ function get($key, $useDB = true, $langcode = true, $isFullKey = false) { global $wgContLang; if (is_int($key)) { // Fix numerical strings that somehow become ints // on their way here $key = (string) $key; } elseif (!is_string($key)) { throw new MWException('Non-string key given'); } elseif ($key === '') { // Shortcut: the empty key is always missing return false; } // For full keys, get the language code from the key $pos = strrpos($key, '/'); if ($isFullKey && $pos !== false) { $langcode = substr($key, $pos + 1); $key = substr($key, 0, $pos); } // Normalise title-case input (with some inlining) $lckey = MessageCache::normalizeKey($key); Hooks::run('MessageCache::get', array(&$lckey)); if (ord($lckey) < 128) { $uckey = ucfirst($lckey); } else { $uckey = $wgContLang->ucfirst($lckey); } // Loop through each language in the fallback list until we find something useful $lang = wfGetLangObj($langcode); $message = $this->getMessageFromFallbackChain($lang, $lckey, $uckey, !$this->mDisable && $useDB); // If we still have no message, maybe the key was in fact a full key so try that if ($message === false) { $parts = explode('/', $lckey); // We may get calls for things that are http-urls from sidebar // Let's not load nonexistent languages for those // They usually have more than one slash. if (count($parts) == 2 && $parts[1] !== '') { $message = Language::getMessageFor($parts[0], $parts[1]); if ($message === null) { $message = false; } } } // Post-processing if the message exists if ($message !== false) { // Fix whitespace $message = str_replace(array(' ', ' ', ' '), array(' ', " ", " "), $message); } return $message; }
public function execute() { $params = $this->extractRequestParams(); if (is_null($params['lang'])) { $langObj = $this->getLanguage(); } elseif (!Language::isValidCode($params['lang'])) { $this->dieUsage('Invalid language code for parameter lang', 'invalidlang'); } else { $langObj = Language::factory($params['lang']); } if ($params['enableparser']) { if (!is_null($params['title'])) { $title = Title::newFromText($params['title']); if (!$title || $title->isExternal()) { $this->dieUsageMsg(['invalidtitle', $params['title']]); } } else { $title = Title::newFromText('API'); } } $prop = array_flip((array) $params['prop']); // Determine which messages should we print if (in_array('*', $params['messages'])) { $message_names = Language::getMessageKeysFor($langObj->getCode()); if ($params['includelocal']) { $message_names = array_unique(array_merge($message_names, MessageCache::singleton()->getAllMessageKeys($this->getConfig()->get('LanguageCode')))); } sort($message_names); $messages_target = $message_names; } else { $messages_target = $params['messages']; } // Filter messages that have the specified prefix // Because we sorted the message array earlier, they will appear in a clump: if (isset($params['prefix'])) { $skip = false; $messages_filtered = []; foreach ($messages_target as $message) { // === 0: must be at beginning of string (position 0) if (strpos($message, $params['prefix']) === 0) { if (!$skip) { $skip = true; } $messages_filtered[] = $message; } elseif ($skip) { break; } } $messages_target = $messages_filtered; } // Filter messages that contain specified string if (isset($params['filter'])) { $messages_filtered = []; foreach ($messages_target as $message) { // !== is used because filter can be at the beginning of the string if (strpos($message, $params['filter']) !== false) { $messages_filtered[] = $message; } } $messages_target = $messages_filtered; } // Whether we have any sort of message customisation filtering $customiseFilterEnabled = $params['customised'] !== 'all'; if ($customiseFilterEnabled) { global $wgContLang; $customisedMessages = AllMessagesTablePager::getCustomisedStatuses(array_map([$langObj, 'ucfirst'], $messages_target), $langObj->getCode(), !$langObj->equals($wgContLang)); $customised = $params['customised'] === 'modified'; } // Get all requested messages and print the result $skip = !is_null($params['from']); $useto = !is_null($params['to']); $result = $this->getResult(); foreach ($messages_target as $message) { // Skip all messages up to $params['from'] if ($skip && $message === $params['from']) { $skip = false; } if ($useto && $message > $params['to']) { break; } if (!$skip) { $a = ['name' => $message, 'normalizedname' => MessageCache::normalizeKey($message)]; $args = []; if (isset($params['args']) && count($params['args']) != 0) { $args = $params['args']; } if ($customiseFilterEnabled) { $messageIsCustomised = isset($customisedMessages['pages'][$langObj->ucfirst($message)]); if ($customised === $messageIsCustomised) { if ($customised) { $a['customised'] = true; } } else { continue; } } $msg = wfMessage($message, $args)->inLanguage($langObj); if (!$msg->exists()) { $a['missing'] = true; } else { // Check if the parser is enabled: if ($params['enableparser']) { $msgString = $msg->title($title)->text(); } else { $msgString = $msg->plain(); } if (!$params['nocontent']) { ApiResult::setContentValue($a, 'content', $msgString); } if (isset($prop['default'])) { $default = wfMessage($message)->inLanguage($langObj)->useDatabase(false); if (!$default->exists()) { $a['defaultmissing'] = true; } elseif ($default->plain() != $msgString) { $a['default'] = $default->plain(); } } } $fit = $result->addValue(['query', $this->getModuleName()], null, $a); if (!$fit) { $this->setContinueEnumParameter('from', $message); break; } } } $result->addIndexedTagName(['query', $this->getModuleName()], 'message'); }