/**
  * @param string $code
  *
  * @return array
  */
 protected function getSpecialPageAliases($code)
 {
     $file = Language::getMessagesFileName($code);
     if (is_readable($file)) {
         include $file;
         if (isset($specialPageAliases) && $specialPageAliases !== null) {
             return $specialPageAliases;
         }
     }
     return [];
 }
示例#2
0
 public function execute()
 {
     foreach ($this->mLangs as $code) {
         $filename = Language::getMessagesFileName($code);
         $this->output("Loading language [{$code}] ... ");
         unset($digitTransformTable);
         require_once $filename;
         if (!isset($digitTransformTable)) {
             $this->error("\$digitTransformTable not found for lang: {$code}");
             continue;
         }
         $this->output("OK\n\$digitTransformTable = array(\n");
         foreach ($digitTransformTable as $latin => $translation) {
             $htmlent = utf8ToHexSequence($translation);
             $this->output("'{$latin}' => '{$translation}', # &#x{$htmlent};\n");
         }
         $this->output(");\n");
     }
 }
示例#3
0
/**
 * Rewrite a messages array.
 *
 * @param $code The language code.
 * @param $write Write to the messages file?
 */
function rebuildLanguage($code, $write)
{
    global $wgLanguages, $wg;
    # Get messages
    $messages = $wgLanguages->getMessages($code);
    $messages = $messages['all'];
    # Rewrite messages array
    $messagesText = writeMessagesArray($messages, $code == 'en');
    # Write to the file
    if ($write) {
        $filename = Language::getMessagesFileName($code);
        $contents = file_get_contents($filename);
        if (strpos($contents, '$messages') !== false) {
            $new = explode('$messages', $contents);
            $new = $new[0];
            $new .= $messagesText;
            $new .= "\n?>\n";
            file_put_contents($filename, $new);
            echo "Generated and wrote messages in language {$code}.\n";
        }
    } else {
        echo "Generated messages in language {$code}.\n";
    }
}
示例#4
0
<?php

/**
 * @file
 * @ingroup MaintenanceLanguage
 */
require '../commandLine.inc';
# A list of unicode numerals is available at:
# http://www.fileformat.info/info/unicode/category/Nd/list.htm
$langs = array('Ar', 'As', 'Bh', 'Bo', 'Dz', 'Fa', 'Gu', 'Hi', 'Km', 'Kn', 'Ks', 'Lo', 'Ml', 'Mr', 'Ne', 'New', 'Or', 'Pa', 'Pi', 'Sa');
foreach ($langs as $code) {
    $filename = Language::getMessagesFileName($code);
    echo "Loading language [{$code}] ... ";
    unset($digitTransformTable);
    require_once $filename;
    if (!isset($digitTransformTable)) {
        print "\$digitTransformTable not found\n";
        continue;
    }
    print "OK\n\$digitTransformTable = array(\n";
    foreach ($digitTransformTable as $latin => $translation) {
        $htmlent = utf8ToHexSequence($translation);
        print "'{$latin}' => '{$translation}', # &#x{$htmlent};\n";
    }
    print ");\n";
}
 /**
  * Read the data from the source files for a given language, and register
  * the relevant dependencies in the $deps array. If the localisation
  * exists, the data array is returned, otherwise false is returned.
  */
 protected function readSourceFilesAndRegisterDeps($code, &$deps)
 {
     global $IP;
     wfProfileIn(__METHOD__);
     // This reads in the PHP i18n file with non-messages l10n data
     $fileName = Language::getMessagesFileName($code);
     if (!file_exists($fileName)) {
         $data = array();
     } else {
         $deps[] = new FileDependency($fileName);
         $data = $this->readPHPFile($fileName, 'core');
     }
     # Load CLDR plural rules for JavaScript
     $data['pluralRules'] = $this->getPluralRules($code);
     # And for PHP
     $data['compiledPluralRules'] = $this->getCompiledPluralRules($code);
     # Load plural rule types
     $data['pluralRuleTypes'] = $this->getPluralRuleTypes($code);
     $deps['plurals'] = new FileDependency("{$IP}/languages/data/plurals.xml");
     $deps['plurals-mw'] = new FileDependency("{$IP}/languages/data/plurals-mediawiki.xml");
     wfProfileOut(__METHOD__);
     return $data;
 }
 /**
  * Update the MediaWiki Core Messages.
  *
  * @param $verbose Boolean
  *
  * @return Integer: the amount of updated messages
  */
 public static function updateMediawikiMessages($verbose, $coreUrl)
 {
     // Find the changed English strings (as these messages won't be updated in ANY language).
     $localUrl = Language::getMessagesFileName('en');
     $repoUrl = str_replace('$2', 'languages/messages/MessagesEn.php', $coreUrl);
     $changedEnglishStrings = self::compareFiles($repoUrl, $localUrl, $verbose);
     // Count the changes.
     $changedCount = 0;
     $languages = Language::fetchLanguageNames(null, 'mwfile');
     foreach (array_keys($languages) as $code) {
         $localUrl = Language::getMessagesFileName($code);
         // Not prefixed with $IP
         $filename = Language::getFilename('languages/messages/Messages', $code);
         $repoUrl = str_replace('$2', $filename, $coreUrl);
         // Compare the files.
         $changedCount += self::compareFiles($repoUrl, $localUrl, $verbose, $changedEnglishStrings, false, true);
     }
     // Log some nice info.
     self::myLog("{$changedCount} MediaWiki messages are updated");
     return $changedCount;
 }
 /**
  * Read the data from the source files for a given language, and register
  * the relevant dependencies in the $deps array. If the localisation
  * exists, the data array is returned, otherwise false is returned.
  */
 protected function readSourceFilesAndRegisterDeps($code, &$deps)
 {
     $fileName = Language::getMessagesFileName($code);
     if (!file_exists($fileName)) {
         return false;
     }
     $deps[] = new FileDependency($fileName);
     $data = $this->readPHPFile($fileName, 'core');
     # Load CLDR plural rules for JavaScript
     $data['pluralRules'] = $this->getPluralRules($code);
     # And for PHP
     $data['compiledPluralRules'] = $this->getCompiledPluralRules($code);
     $deps['plurals'] = new FileDependency(__DIR__ . "/../languages/data/plurals.xml");
     $deps['plurals-mw'] = new FileDependency(__DIR__ . "/../languages/data/plurals-mediawiki.xml");
     return $data;
 }
示例#8
0
 /**
  * Load localisation data for a given language for both core and extensions
  * and save it to the persistent cache store and the process cache
  */
 public function recache($code)
 {
     static $recursionGuard = array();
     global $wgExtensionMessagesFiles, $wgExtensionAliasesFiles;
     wfProfileIn(__METHOD__);
     if (!$code) {
         throw new MWException("Invalid language code requested");
     }
     $this->recachedLangs[$code] = true;
     # Initial values
     $initialData = array_combine(self::$allKeys, array_fill(0, count(self::$allKeys), null));
     $coreData = $initialData;
     $deps = array();
     # Load the primary localisation from the source file
     $fileName = Language::getMessagesFileName($code);
     if (!file_exists($fileName)) {
         wfDebug(__METHOD__ . ": no localisation file for {$code}, using fallback to en\n");
         $coreData['fallback'] = 'en';
     } else {
         $deps[] = new FileDependency($fileName);
         $data = $this->readPHPFile($fileName, 'core');
         wfDebug(__METHOD__ . ": got localisation for {$code} from source\n");
         # Merge primary localisation
         foreach ($data as $key => $value) {
             $this->mergeItem($key, $coreData[$key], $value);
         }
     }
     # Fill in the fallback if it's not there already
     if (is_null($coreData['fallback'])) {
         $coreData['fallback'] = $code === 'en' ? false : 'en';
     }
     if ($coreData['fallback'] !== false) {
         # Guard against circular references
         if (isset($recursionGuard[$code])) {
             throw new MWException("Error: Circular fallback reference in language code {$code}");
         }
         $recursionGuard[$code] = true;
         # Load the fallback localisation item by item and merge it
         $deps = array_merge($deps, $this->getItem($coreData['fallback'], 'deps'));
         foreach (self::$allKeys as $key) {
             if (is_null($coreData[$key]) || $this->isMergeableKey($key)) {
                 $fallbackValue = $this->getItem($coreData['fallback'], $key);
                 $this->mergeItem($key, $coreData[$key], $fallbackValue);
             }
         }
         $fallbackSequence = $this->getItem($coreData['fallback'], 'fallbackSequence');
         array_unshift($fallbackSequence, $coreData['fallback']);
         $coreData['fallbackSequence'] = $fallbackSequence;
         unset($recursionGuard[$code]);
     } else {
         $coreData['fallbackSequence'] = array();
     }
     $codeSequence = array_merge(array($code), $coreData['fallbackSequence']);
     # Load the extension localisations
     # This is done after the core because we know the fallback sequence now.
     # But it has a higher precedence for merging so that we can support things
     # like site-specific message overrides.
     $allData = $initialData;
     foreach ($wgExtensionMessagesFiles as $fileName) {
         $data = $this->readPHPFile($fileName, 'extension');
         $used = false;
         foreach ($data as $key => $item) {
             if ($this->mergeExtensionItem($codeSequence, $key, $allData[$key], $item)) {
                 $used = true;
             }
         }
         if ($used) {
             $deps[] = new FileDependency($fileName);
         }
     }
     # Load deprecated $wgExtensionAliasesFiles
     foreach ($wgExtensionAliasesFiles as $fileName) {
         $data = $this->readPHPFile($fileName, 'aliases');
         if (!isset($data['aliases'])) {
             continue;
         }
         $used = $this->mergeExtensionItem($codeSequence, 'specialPageAliases', $allData['specialPageAliases'], $data['aliases']);
         if ($used) {
             $deps[] = new FileDependency($fileName);
         }
     }
     # Merge core data into extension data
     foreach ($coreData as $key => $item) {
         $this->mergeItem($key, $allData[$key], $item);
     }
     # Add cache dependencies for any referenced globals
     $deps['wgExtensionMessagesFiles'] = new GlobalDependency('wgExtensionMessagesFiles');
     $deps['wgExtensionAliasesFiles'] = new GlobalDependency('wgExtensionAliasesFiles');
     $deps['version'] = new ConstantDependency('MW_LC_VERSION');
     # Add dependencies to the cache entry
     $allData['deps'] = $deps;
     # Replace spaces with underscores in namespace names
     $allData['namespaceNames'] = str_replace(' ', '_', $allData['namespaceNames']);
     # And do the same for special page aliases. $page is an array.
     foreach ($allData['specialPageAliases'] as &$page) {
         $page = str_replace(' ', '_', $page);
     }
     # Decouple the reference to prevent accidental damage
     unset($page);
     # Fix broken defaultUserOptionOverrides
     if (!is_array($allData['defaultUserOptionOverrides'])) {
         $allData['defaultUserOptionOverrides'] = array();
     }
     # Set the list keys
     $allData['list'] = array();
     foreach (self::$splitKeys as $key) {
         $allData['list'][$key] = array_keys($allData[$key]);
     }
     # Run hooks
     wfRunHooks('LocalisationCacheRecache', array($this, $code, &$allData));
     if (is_null($allData['defaultUserOptionOverrides'])) {
         throw new MWException(__METHOD__ . ': Localisation data failed sanity check! ' . 'Check that your languages/messages/MessagesEn.php file is intact.');
     }
     # Set the preload key
     $allData['preload'] = $this->buildPreload($allData);
     # Save to the process cache and register the items loaded
     $this->data[$code] = $allData;
     foreach ($allData as $key => $item) {
         $this->loadedItems[$code][$key] = true;
     }
     # Save to the persistent cache
     $this->store->startWrite($code);
     foreach ($allData as $key => $value) {
         if (in_array($key, self::$splitKeys)) {
             foreach ($value as $subkey => $subvalue) {
                 $this->store->set("{$key}:{$subkey}", $subvalue);
             }
         } else {
             $this->store->set($key, $value);
         }
     }
     $this->store->finishWrite();
     # Clear out the MessageBlobStore
     # HACK: If using a null (i.e. disabled) storage backend, we
     # can't write to the MessageBlobStore either
     if (!$this->store instanceof LCStore_Null) {
         MessageBlobStore::clear();
     }
     wfProfileOut(__METHOD__);
 }
 function generatePatch()
 {
     global $wgOut, $wgRequest, $wgTmpDirectory, $IP;
     $originalMsgs = $wgRequest->getVal('originalMsgs');
     if (!$originalMsgs) {
         throw new MWException('Bad form input: no originalMsgs');
     }
     $originalMsgs = json_decode(gzinflate(base64_decode($originalMsgs)));
     if (!$originalMsgs) {
         throw new MWException('Bad form input: originalMsgs invalid');
     }
     $newMsgs = $wgRequest->getArray('msg');
     $messageName = $wgRequest->getVal('messageName');
     if (!$newMsgs) {
         throw new MWException('Bad form input: msg missing');
     }
     if (!$messageName) {
         throw new MWException('Bad form input: messageName missing');
     }
     $quote = "['\"]";
     $encMsgName = preg_quote($messageName, '/');
     $warnings = array();
     //( 'parse' => array(), 'file' => array(), 'mismatch' => array() );
     $escapedChars = array('single' => array("'", "\\"), 'double' => array('n', 'r', 't', 'v', 'f', "\\", '$', '"'));
     $dcRegex = '/[0-7]{1,3}|x[0-9A-Fa-f]{1,2}/';
     wfMkdirParents("{$wgTmpDirectory}/EditMessages");
     $out = '';
     foreach ($originalMsgs as $lang => $origValue) {
         if (!isset($newMsgs[$lang])) {
             continue;
         }
         $newValue = $newMsgs[$lang];
         if ($newValue === $origValue) {
             # No change requested
             continue;
         }
         $fileName = Language::getMessagesFileName($lang);
         $text = file_get_contents($fileName);
         if (!$text) {
             $warnings['file'][] = $lang;
             continue;
         }
         # Find the message name in the file text
         if (!preg_match("/^\\s*{$quote}{$encMsgName}{$quote}\\s*=>\\s*/m", $text, $m, PREG_OFFSET_CAPTURE)) {
             $warnings['parse1'][] = $lang;
             continue;
         }
         # Determine the starting quote character
         $i = $startPos = $m[0][1] + strlen($m[0][0]);
         $quoteChar = substr($text, $i, 1);
         if ($quoteChar == '"') {
             $mode = 'double';
         } elseif ($quoteChar == "'") {
             $mode = 'single';
         } else {
             $warnings['parse2'][] = $lang;
             continue;
         }
         # Search for the end of the string, respecting escaping
         $i++;
         $found = false;
         do {
             $curChar = substr($text, $i, 1);
             if ($curChar === '\\') {
                 $nextChar = substr($text, $i + 1, 1);
                 if (in_array($nextChar, $escapedChars[$mode])) {
                     $i += 2;
                     continue;
                 }
                 if ($mode == 'double' && preg_match($dcRegex, $text, $m, 0, $i + 1)) {
                     $i += strlen($m[0]) + 1;
                     continue;
                 }
             } elseif ($curChar === $quoteChar) {
                 $found = true;
                 break;
             }
             ++$i;
         } while ($i < strlen($text));
         if (!$found) {
             $warnings['parse3'][] = $lang;
             continue;
         }
         $length = $i - $startPos + 1;
         # Evaluate the string that we just got from the message file, so that we can
         # see if it matches the expected starting value
         $fileValue = eval('return ' . substr($text, $startPos, $length) . ';');
         if ($fileValue !== $origValue) {
             $warnings['mismatch'][] = $lang;
             continue;
         }
         # Escape the new value, keeping the same quoting style
         if ($mode == 'single') {
             $encNewValue = var_export($newValue, true);
         } else {
             $encNewValue = '"' . strtr($newValue, array('\\' => '\\\\', '"' => '\\"', '$' => '\\$')) . '"';
         }
         # Replace the string with the new value
         $newText = substr_replace($text, $encNewValue, $startPos, $length);
         # Generate the diff
         $tempName = "{$wgTmpDirectory}/EditMessages/" . basename($fileName);
         file_put_contents($tempName, $newText);
         $cmd = "diff -u " . wfEscapeShellArg($fileName, $tempName);
         $diff = "{$cmd}\n" . wfShellExec($cmd);
         $diff = str_replace("{$IP}/", '', $diff);
         $diff = str_replace("\r", '', $diff);
         $out .= $diff;
     }
     foreach ($warnings as $warningType => $warnings2) {
         if (count($warnings2)) {
             $wgOut->addWikiMsg('editmsg-warning-' . $warningType, implode(', ', $warnings2));
         }
     }
     if ($out !== '') {
         $wgOut->addHTML('<pre><bdo dir="ltr">' . htmlspecialchars($out) . '</bdo></pre>');
         $encodedValue = chunk_split(base64_encode(gzdeflate($out)), 120, ' ');
         $encAction = $this->getTitle()->escapeFullUrl();
         $wgOut->addHTML("<p>\n" . "<form method=\"POST\" action=\"{$encAction}\">" . "<input type=\"hidden\" name=\"diffText\" value=\"{$encodedValue}\"/>" . '<input type="submit" name="editmsg_apply_patch" value="' . htmlspecialchars(wfMsg('editmsg-apply-patch')) . '"/>' . '</form></p>');
     }
 }
 public function __construct($code)
 {
     parent::__construct($code);
     $this->data['core'] = array('label' => 'MediaWiki Core', 'var' => 'namespaceNames', 'file' => Language::getMessagesFileName(self::PLACEHOLDER), 'code' => false);
 }
示例#11
0
 /**
  * Load localisation data for a given language for both core and extensions
  * and save it to the persistent cache store and the process cache
  * @param $code
  */
 public function recache($code)
 {
     global $wgExtensionMessagesFiles;
     wfProfileIn(__METHOD__);
     if (!$code) {
         throw new MWException("Invalid language code requested");
     }
     $this->recachedLangs[$code] = true;
     # Initial values
     $initialData = array_combine(self::$allKeys, array_fill(0, count(self::$allKeys), null));
     $coreData = $initialData;
     $deps = array();
     # Load the primary localisation from the source file
     $fileName = Language::getMessagesFileName($code);
     $addFileName = Language::getAdditionalMessagesFileName($code, 'core');
     if (!file_exists($fileName)) {
         wfDebug(__METHOD__ . ": no localisation file for {$code}, using fallback to en\n");
         $coreData['fallback'] = 'en';
     } else {
         $deps[] = new FileDependency($fileName);
         $data = $this->readPHPFile($fileName, 'core');
         // wikia changes begin
         if (file_exists($addFileName)) {
             $deps[] = new FileDependency($addFileName);
             $addData = $this->readPHPFile($addFileName, 'core');
             if (!empty($addData['messages'])) {
                 $data['messages'] = array_merge($data['messages'], $addData['messages']);
             }
         }
         // wikia changes end
         wfDebug(__METHOD__ . ": got localisation for {$code} from source\n");
         # Merge primary localisation
         foreach ($data as $key => $value) {
             $this->mergeItem($key, $coreData[$key], $value);
         }
     }
     # Fill in the fallback if it's not there already
     if (is_null($coreData['fallback'])) {
         $coreData['fallback'] = $code === 'en' ? false : 'en';
     }
     if ($coreData['fallback'] === false) {
         $coreData['fallbackSequence'] = array();
     } else {
         $coreData['fallbackSequence'] = array_map('trim', explode(',', $coreData['fallback']));
         $len = count($coreData['fallbackSequence']);
         # Ensure that the sequence ends at en
         if ($coreData['fallbackSequence'][$len - 1] !== 'en') {
             $coreData['fallbackSequence'][] = 'en';
         }
         # Load the fallback localisation item by item and merge it
         foreach ($coreData['fallbackSequence'] as $fbCode) {
             # Load the secondary localisation from the source file to
             # avoid infinite cycles on cyclic fallbacks
             $fbFilename = Language::getMessagesFileName($fbCode);
             $fbAddFileName = Language::getAdditionalMessagesFileName($fbCode, 'core');
             if (!file_exists($fbFilename)) {
                 continue;
             }
             $deps[] = new FileDependency($fbFilename);
             $fbData = $this->readPHPFile($fbFilename, 'core');
             // wikia changes begin
             if (file_exists($fbAddFileName)) {
                 $deps[] = new FileDependency($fbAddFileName);
                 $addData = $this->readPHPFile($fbAddFileName, 'core');
                 if (!empty($addData['messages'])) {
                     $fbData['messages'] = array_merge($fbData['messages'], $addData['messages']);
                 }
             }
             // wikia changes end
             wfDebug(__METHOD__ . ": got fallback localisation for {$fbCode} from source\n");
             foreach (self::$allKeys as $key) {
                 if (!isset($fbData[$key])) {
                     continue;
                 }
                 if (is_null($coreData[$key]) || $this->isMergeableKey($key)) {
                     $this->mergeItem($key, $coreData[$key], $fbData[$key]);
                 }
             }
         }
     }
     $codeSequence = array_merge(array($code), $coreData['fallbackSequence']);
     // wikia change begin
     // author: mech
     // allow extensions to use hook to add messages files
     // this can be used in cases when enumerating message files is expensive so it shouldn't be done in setup file
     wfRunHooks('BeforeExtensionMessagesRecache', array(&$wgExtensionMessagesFiles));
     // wikia change end
     # Load the extension localisations
     # This is done after the core because we know the fallback sequence now.
     # But it has a higher precedence for merging so that we can support things
     # like site-specific message overrides.
     $allData = $initialData;
     foreach ($wgExtensionMessagesFiles as $fileName) {
         $data = $this->readPHPFile($fileName, 'extension');
         $used = false;
         foreach ($data as $key => $item) {
             if ($this->mergeExtensionItem($codeSequence, $key, $allData[$key], $item)) {
                 $used = true;
             }
         }
         if ($used) {
             $deps[] = new FileDependency($fileName);
         }
     }
     # Merge core data into extension data
     foreach ($coreData as $key => $item) {
         $this->mergeItem($key, $allData[$key], $item);
     }
     # Add cache dependencies for any referenced globals
     $deps['wgExtensionMessagesFiles'] = new GlobalDependency('wgExtensionMessagesFiles');
     $deps['version'] = new ConstantDependency('MW_LC_VERSION');
     # Add dependencies to the cache entry
     $allData['deps'] = $deps;
     # Replace spaces with underscores in namespace names
     $allData['namespaceNames'] = str_replace(' ', '_', $allData['namespaceNames']);
     # And do the same for special page aliases. $page is an array.
     foreach ($allData['specialPageAliases'] as &$page) {
         $page = str_replace(' ', '_', $page);
     }
     # Decouple the reference to prevent accidental damage
     unset($page);
     # Set the list keys
     $allData['list'] = array();
     foreach (self::$splitKeys as $key) {
         $allData['list'][$key] = array_keys($allData[$key]);
     }
     # Run hooks
     wfRunHooks('LocalisationCacheRecache', array($this, $code, &$allData));
     if (is_null($allData['namespaceNames'])) {
         throw new MWException(__METHOD__ . ': Localisation data failed sanity check! ' . 'Check that your languages/messages/MessagesEn.php file is intact.');
     }
     # Set the preload key
     $allData['preload'] = $this->buildPreload($allData);
     # Save to the process cache and register the items loaded
     $this->data[$code] = $allData;
     foreach ($allData as $key => $item) {
         $this->loadedItems[$code][$key] = true;
     }
     # Save to the persistent cache
     $this->store->startWrite($code);
     foreach ($allData as $key => $value) {
         if (in_array($key, self::$splitKeys)) {
             foreach ($value as $subkey => $subvalue) {
                 $this->store->set("{$key}:{$subkey}", $subvalue);
             }
         } else {
             $this->store->set($key, $value);
         }
     }
     $this->store->finishWrite();
     # Clear out the MessageBlobStore
     # HACK: If using a null (i.e. disabled) storage backend, we
     # can't write to the MessageBlobStore either
     if (!$this->store instanceof LCStore_Null) {
         MessageBlobStore::clear();
     }
     wfProfileOut(__METHOD__);
 }