X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FLocalisationCache.php;h=d8e5d3a368648e9e5851c1cbf4c69339ba2cb11a;hb=8fc8ddfa80ddc06ab9dab54288118288468fffcd;hp=9ce26d000be567dd63f3dab3bc543725774dd276;hpb=50927f376bc56fceade18c1670aec4f9fe2d207d;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/LocalisationCache.php b/includes/LocalisationCache.php index 9ce26d000b..d8e5d3a368 100644 --- a/includes/LocalisationCache.php +++ b/includes/LocalisationCache.php @@ -110,7 +110,7 @@ class LocalisationCache { 'dateFormats', 'datePreferences', 'datePreferenceMigrationMap', 'defaultDateFormat', 'extraUserToggles', 'specialPageAliases', 'imageFiles', 'preloadedMessages', 'namespaceGenderAliases', - 'digitGroupingPattern' + 'digitGroupingPattern', 'pluralRules', 'compiledPluralRules', ); /** @@ -118,7 +118,7 @@ class LocalisationCache { * by a fallback sequence. */ static public $mergeableMapKeys = array( 'messages', 'namespaceNames', - 'dateFormats', 'imageFiles', 'preloadedMessages', + 'dateFormats', 'imageFiles', 'preloadedMessages' ); /** @@ -154,6 +154,12 @@ class LocalisationCache { */ static public $preloadedKeys = array( 'dateFormats', 'namespaceNames' ); + /** + * Associative array of cached plural rules. The key is the language code, + * the value is an array of plural rules for that language. + */ + var $pluralRules = null; + var $mergeableKeys = null; /** @@ -234,9 +240,9 @@ class LocalisationCache { */ public function getItem( $code, $key ) { if ( !isset( $this->loadedItems[$code][$key] ) ) { - wfProfileIn( __METHOD__.'-load' ); + wfProfileIn( __METHOD__ . '-load' ); $this->loadItem( $code, $key ); - wfProfileOut( __METHOD__.'-load' ); + wfProfileOut( __METHOD__ . '-load' ); } if ( $key === 'fallback' && isset( $this->shallowFallbacks[$code] ) ) { @@ -256,9 +262,9 @@ class LocalisationCache { public function getSubitem( $code, $key, $subkey ) { if ( !isset( $this->loadedSubitems[$code][$key][$subkey] ) && !isset( $this->loadedItems[$code][$key] ) ) { - wfProfileIn( __METHOD__.'-load' ); + wfProfileIn( __METHOD__ . '-load' ); $this->loadSubitem( $code, $key, $subkey ); - wfProfileOut( __METHOD__.'-load' ); + wfProfileOut( __METHOD__ . '-load' ); } if ( isset( $this->data[$code][$key][$subkey] ) ) { @@ -367,7 +373,7 @@ class LocalisationCache { */ public function isExpired( $code ) { if ( $this->forceRecache && !isset( $this->recachedLangs[$code] ) ) { - wfDebug( __METHOD__."($code): forced reload\n" ); + wfDebug( __METHOD__ . "($code): forced reload\n" ); return true; } @@ -376,7 +382,7 @@ class LocalisationCache { $preload = $this->store->get( $code, 'preload' ); // Different keys may expire separately, at least in LCStore_Accel if ( $deps === null || $keys === null || $preload === null ) { - wfDebug( __METHOD__."($code): cache missing, need to make one\n" ); + wfDebug( __METHOD__ . "($code): cache missing, need to make one\n" ); return true; } @@ -386,7 +392,7 @@ class LocalisationCache { // anymore (e.g. uninstalled extensions) // When this happens, always expire the cache if ( !$dep instanceof CacheDependency || $dep->isExpired() ) { - wfDebug( __METHOD__."($code): cache for $code expired due to " . + wfDebug( __METHOD__ . "($code): cache for $code expired due to " . get_class( $dep ) . "\n" ); return true; } @@ -481,9 +487,95 @@ class LocalisationCache { } elseif ( $_fileType == 'aliases' ) { $data = compact( 'aliases' ); } else { - throw new MWException( __METHOD__.": Invalid file type: $_fileType" ); + throw new MWException( __METHOD__ . ": Invalid file type: $_fileType" ); + } + return $data; + } + + /** + * Get the compiled plural rules for a given language from the XML files. + * @since 1.20 + */ + public function getCompiledPluralRules( $code ) { + $rules = $this->getPluralRules( $code ); + if ( $rules === null ) { + return null; + } + try { + $compiledRules = CLDRPluralRuleEvaluator::compile( $rules ); + } catch( CLDRPluralRuleError $e ) { + wfDebugLog( 'l10n', $e->getMessage() . "\n" ); + return array(); + } + return $compiledRules; + } + + /** + * Get the plural rules for a given language from the XML files. + * Cached. + * @since 1.20 + */ + public function getPluralRules( $code ) { + if ( $this->pluralRules === null ) { + $cldrPlural = __DIR__ . "/../languages/data/plurals.xml"; + $mwPlural = __DIR__ . "/../languages/data/plurals-mediawiki.xml"; + // Load CLDR plural rules + $this->loadPluralFile( $cldrPlural ); + if ( file_exists( $mwPlural ) ) { + // Override or extend + $this->loadPluralFile( $mwPlural ); + } + } + if ( !isset( $this->pluralRules[$code] ) ) { + return null; + } else { + return $this->pluralRules[$code]; + } + } + + + /** + * Load a plural XML file with the given filename, compile the relevant + * rules, and save the compiled rules in a process-local cache. + */ + protected function loadPluralFile( $fileName ) { + $doc = new DOMDocument; + $doc->load( $fileName ); + $rulesets = $doc->getElementsByTagName( "pluralRules" ); + foreach ( $rulesets as $ruleset ) { + $codes = $ruleset->getAttribute( 'locales' ); + $rules = array(); + $ruleElements = $ruleset->getElementsByTagName( "pluralRule" ); + foreach ( $ruleElements as $elt ) { + $rules[] = $elt->nodeValue; + } + foreach ( explode( ' ', $codes ) as $code ) { + $this->pluralRules[$code] = $rules; + } + } + } + + /** + * 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; } @@ -585,14 +677,12 @@ class LocalisationCache { $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" ); + $data = $this->readSourceFilesAndRegisterDeps( $code, $deps ); + if ( $data === false ) { + 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" ); + wfDebug( __METHOD__ . ": got localisation for $code from source\n" ); # Merge primary localisation foreach ( $data as $key => $value ) { @@ -605,7 +695,6 @@ class LocalisationCache { if ( is_null( $coreData['fallback'] ) ) { $coreData['fallback'] = $code === 'en' ? false : 'en'; } - if ( $coreData['fallback'] === false ) { $coreData['fallbackSequence'] = array(); } else { @@ -621,15 +710,11 @@ class LocalisationCache { foreach ( $coreData['fallbackSequence'] as $fbCode ) { # Load the secondary localisation from the source file to # avoid infinite cycles on cyclic fallbacks - $fbFilename = Language::getMessagesFileName( $fbCode ); - - if ( !file_exists( $fbFilename ) ) { + $fbData = $this->readSourceFilesAndRegisterDeps( $fbCode, $deps ); + if ( $fbData === false ) { continue; } - $deps[] = new FileDependency( $fbFilename ); - $fbData = $this->readPHPFile( $fbFilename, 'core' ); - foreach ( self::$allKeys as $key ) { if ( !isset( $fbData[$key] ) ) { continue; @@ -654,7 +739,7 @@ class LocalisationCache { $used = false; foreach ( $data as $key => $item ) { - if( $this->mergeExtensionItem( $codeSequence, $key, $allData[$key], $item ) ) { + if ( $this->mergeExtensionItem( $codeSequence, $key, $allData[$key], $item ) ) { $used = true; } } @@ -684,19 +769,26 @@ class LocalisationCache { $page = str_replace( ' ', '_', $page ); } # Decouple the reference to prevent accidental damage - unset($page); + 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(); + } # 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! ' . + throw new MWException( __METHOD__ . ': Localisation data failed sanity check! ' . 'Check that your languages/messages/MessagesEn.php file is intact.' ); } @@ -924,7 +1016,7 @@ class LCStore_DB implements LCStore { } if ( !$code ) { - throw new MWException( __METHOD__.": Invalid language \"$code\"" ); + throw new MWException( __METHOD__ . ": Invalid language \"$code\"" ); } $this->dbw = wfGetDB( DB_MASTER ); @@ -968,7 +1060,7 @@ class LCStore_DB implements LCStore { } if ( is_null( $this->currentLang ) ) { - throw new MWException( __CLASS__.': must call startWrite() before calling set()' ); + throw new MWException( __CLASS__ . ': must call startWrite() before calling set()' ); } $this->batch[] = array( @@ -1040,7 +1132,7 @@ class LCStore_CDB implements LCStore { } // Close reader to stop permission errors on write - if( !empty($this->readers[$code]) ) { + if ( !empty( $this->readers[$code] ) ) { $this->readers[$code]->close(); } @@ -1058,14 +1150,14 @@ class LCStore_CDB implements LCStore { public function set( $key, $value ) { if ( is_null( $this->writer ) ) { - throw new MWException( __CLASS__.': must call startWrite() before calling set()' ); + throw new MWException( __CLASS__ . ': must call startWrite() before calling set()' ); } $this->writer->set( $key, serialize( $value ) ); } protected function getFileName( $code ) { if ( !$code || strpos( $code, '/' ) !== false ) { - throw new MWException( __METHOD__.": Invalid language \"$code\"" ); + throw new MWException( __METHOD__ . ": Invalid language \"$code\"" ); } return "{$this->directory}/l10n_cache-$code.cdb"; } @@ -1181,8 +1273,9 @@ class LocalisationCache_BulkLoad extends LocalisationCache { while ( count( $this->data ) > $this->maxLoadedLangs && count( $this->mruLangs ) ) { reset( $this->mruLangs ); $code = key( $this->mruLangs ); - wfDebug( __METHOD__.": unloading $code\n" ); + wfDebug( __METHOD__ . ": unloading $code\n" ); $this->unload( $code ); } } + }