Пример #1
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 string $code
  * @throws MWException
  */
 public function recache($code)
 {
     global $wgExtensionMessagesFiles;
     if (!$code) {
         throw new MWException("Invalid language code requested");
     }
     $this->recachedLangs[$code] = true;
     # Initial values
     $initialData = array_fill_keys(self::$allKeys, null);
     $coreData = $initialData;
     $deps = [];
     # Load the primary localisation from the source file
     $data = $this->readSourceFilesAndRegisterDeps($code, $deps);
     if ($data === false) {
         wfDebug(__METHOD__ . ": no localisation file for {$code}, using fallback to en\n");
         $coreData['fallback'] = 'en';
     } else {
         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'] = [];
     } 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';
         }
     }
     $codeSequence = array_merge([$code], $coreData['fallbackSequence']);
     $messageDirs = $this->getMessagesDirs();
     # Load non-JSON localisation data for extensions
     $extensionData = array_fill_keys($codeSequence, $initialData);
     foreach ($wgExtensionMessagesFiles as $extension => $fileName) {
         if (isset($messageDirs[$extension])) {
             # This extension has JSON message data; skip the PHP shim
             continue;
         }
         $data = $this->readPHPFile($fileName, 'extension');
         $used = false;
         foreach ($data as $key => $item) {
             foreach ($codeSequence as $csCode) {
                 if (isset($item[$csCode])) {
                     $this->mergeItem($key, $extensionData[$csCode][$key], $item[$csCode]);
                     $used = true;
                 }
             }
         }
         if ($used) {
             $deps[] = new FileDependency($fileName);
         }
     }
     # Load the localisation data for each fallback, then merge it into the full array
     $allData = $initialData;
     foreach ($codeSequence as $csCode) {
         $csData = $initialData;
         # Load core messages and the extension localisations.
         foreach ($messageDirs as $dirs) {
             foreach ((array) $dirs as $dir) {
                 $fileName = "{$dir}/{$csCode}.json";
                 $data = $this->readJSONFile($fileName);
                 foreach ($data as $key => $item) {
                     $this->mergeItem($key, $csData[$key], $item);
                 }
                 $deps[] = new FileDependency($fileName);
             }
         }
         # Merge non-JSON extension data
         if (isset($extensionData[$csCode])) {
             foreach ($extensionData[$csCode] as $key => $item) {
                 $this->mergeItem($key, $csData[$key], $item);
             }
         }
         if ($csCode === $code) {
             # Merge core data into extension data
             foreach ($coreData as $key => $item) {
                 $this->mergeItem($key, $csData[$key], $item);
             }
         } else {
             # Load the secondary localisation from the source file to
             # avoid infinite cycles on cyclic fallbacks
             $fbData = $this->readSourceFilesAndRegisterDeps($csCode, $deps);
             if ($fbData !== false) {
                 # Only merge the keys that make sense to merge
                 foreach (self::$allKeys as $key) {
                     if (!isset($fbData[$key])) {
                         continue;
                     }
                     if (is_null($coreData[$key]) || $this->isMergeableKey($key)) {
                         $this->mergeItem($key, $csData[$key], $fbData[$key]);
                     }
                 }
             }
         }
         # Allow extensions an opportunity to adjust the data for this
         # fallback
         Hooks::run('LocalisationCacheRecacheFallback', [$this, $csCode, &$csData]);
         # Merge the data for this fallback into the final array
         if ($csCode === $code) {
             $allData = $csData;
         } else {
             foreach (self::$allKeys as $key) {
                 if (!isset($csData[$key])) {
                     continue;
                 }
                 if (is_null($allData[$key]) || $this->isMergeableKey($key)) {
                     $this->mergeItem($key, $allData[$key], $csData[$key]);
                 }
             }
         }
     }
     # Add cache dependencies for any referenced globals
     $deps['wgExtensionMessagesFiles'] = new GlobalDependency('wgExtensionMessagesFiles');
     // The 'MessagesDirs' config setting is used in LocalisationCache::getMessagesDirs().
     // We use the key 'wgMessagesDirs' for historical reasons.
     $deps['wgMessagesDirs'] = new MainConfigDependency('MessagesDirs');
     $deps['version'] = new ConstantDependency('LocalisationCache::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);
     # If there were no plural rules, return an empty array
     if ($allData['pluralRules'] === null) {
         $allData['pluralRules'] = [];
     }
     if ($allData['compiledPluralRules'] === null) {
         $allData['compiledPluralRules'] = [];
     }
     # If there were no plural rule types, return an empty array
     if ($allData['pluralRuleTypes'] === null) {
         $allData['pluralRuleTypes'] = [];
     }
     # Set the list keys
     $allData['list'] = [];
     foreach (self::$splitKeys as $key) {
         $allData['list'][$key] = array_keys($allData[$key]);
     }
     # Run hooks
     $purgeBlobs = true;
     Hooks::run('LocalisationCacheRecache', [$this, $code, &$allData, &$purgeBlobs]);
     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 ($purgeBlobs && !$this->store instanceof LCStoreNull) {
         $blobStore = new MessageBlobStore();
         $blobStore->clear();
     }
 }
Пример #2
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
  * @throws MWException
  */
 public function recache($code)
 {
     global $wgExtensionMessagesFiles, $wgMessagesDirs;
     wfProfileIn(__METHOD__);
     if (!$code) {
         wfProfileOut(__METHOD__);
         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
     $data = $this->readSourceFilesAndRegisterDeps($code, $deps);
     if ($data === false) {
         wfDebug(__METHOD__ . ": no localisation file for {$code}, using fallback to en\n");
         $coreData['fallback'] = 'en';
     } else {
         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
             $fbData = $this->readSourceFilesAndRegisterDeps($fbCode, $deps);
             if ($fbData === false) {
                 continue;
             }
             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']);
     # Load core messages and the extension localisations.
     wfProfileIn(__METHOD__ . '-extensions');
     $allData = $initialData;
     foreach ($wgMessagesDirs as $dirs) {
         foreach ((array) $dirs as $dir) {
             foreach ($codeSequence as $csCode) {
                 $fileName = "{$dir}/{$csCode}.json";
                 $data = $this->readJSONFile($fileName);
                 foreach ($data as $key => $item) {
                     $this->mergeItem($key, $allData[$key], $item);
                 }
                 $deps[] = new FileDependency($fileName);
             }
         }
     }
     foreach ($wgExtensionMessagesFiles as $extension => $fileName) {
         if (isset($wgMessagesDirs[$extension])) {
             # Already loaded the JSON files for this extension; skip the PHP shim
             continue;
         }
         $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);
     }
     wfProfileOut(__METHOD__ . '-extensions');
     # Add cache dependencies for any referenced globals
     $deps['wgExtensionMessagesFiles'] = new GlobalDependency('wgExtensionMessagesFiles');
     $deps['wgMessagesDirs'] = new GlobalDependency('wgMessagesDirs');
     $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);
     # If there were no plural rules, return an empty array
     if ($allData['pluralRules'] === null) {
         $allData['pluralRules'] = array();
     }
     if ($allData['compiledPluralRules'] === null) {
         $allData['compiledPluralRules'] = array();
     }
     # If there were no plural rule types, return an empty array
     if ($allData['pluralRuleTypes'] === null) {
         $allData['pluralRuleTypes'] = array();
     }
     # Set the list keys
     $allData['list'] = array();
     foreach (self::$splitKeys as $key) {
         $allData['list'][$key] = array_keys($allData[$key]);
     }
     # Run hooks
     $purgeBlobs = true;
     wfRunHooks('LocalisationCacheRecache', array($this, $code, &$allData, &$purgeBlobs));
     if (is_null($allData['namespaceNames'])) {
         wfProfileOut(__METHOD__);
         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
     wfProfileIn(__METHOD__ . '-write');
     $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();
     wfProfileOut(__METHOD__ . '-write');
     # Clear out the MessageBlobStore
     # HACK: If using a null (i.e. disabled) storage backend, we
     # can't write to the MessageBlobStore either
     if ($purgeBlobs && !$this->store instanceof LCStoreNull) {
         MessageBlobStore::clear();
     }
     wfProfileOut(__METHOD__);
 }
Пример #3
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']);
     # 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__);
 }