/**
  * @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('&#32;', '&nbsp;', '&#160;'), 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');
 }