From 9d7e9c314159752e1eb6e433ef667c65d3b44870 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Thu, 28 Mar 2013 11:24:19 +0100 Subject: [PATCH] Revert changes in fallback behavior This patch set reverts the following: * Iaaf6ccebd8c40c9602748c58c3a5c73c29e7aa4d * Ib607a446d3499a3c042dce408db5cbaf12fa9e3d * Ic59fd20856eb0489d70f3469a56ebce0efb3db13 (partially) Bug 46579 comment 17 describes a desired solution. In If88923119179924a5ec091394ccab000ade16b3e we are working on a fix, but it is taking longer than we anticipated. There was a deployment window planned about now, but we didn't make it. It makes sense to revert for now, and commit a proper solution somewhere next week. Bug: 46579 Bug: 1495 Change-Id: Iac7ac4357dd80e8cdb238a6a207393f0712b3fe5 --- includes/cache/MessageCache.php | 96 ++++++--------- languages/Language.php | 40 ------ .../includes/cache/MessageCacheTest.php | 114 ------------------ 3 files changed, 34 insertions(+), 216 deletions(-) delete mode 100644 tests/phpunit/includes/cache/MessageCacheTest.php diff --git a/includes/cache/MessageCache.php b/includes/cache/MessageCache.php index 7425978a10..746cb0a3aa 100644 --- a/includes/cache/MessageCache.php +++ b/includes/cache/MessageCache.php @@ -586,70 +586,50 @@ class MessageCache { } /** - * Get a message from either the content language or the user language. The fallback - * language order is the users language fallback union the content language fallback. - * This list is then applied to find keys in the following order - * 1) MediaWiki:$key/$langcode (for every language except the content language where - * we look at MediaWiki:$key) - * 2) Built-in messages via the l10n cache which is also in fallback order + * Get a message from either the content language or the user language. * - * @param string $key the message cache key - * @param $useDB Boolean: If true will look for the message in the DB, false only - * get the message from 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 $key String: the message cache key + * @param $useDB Boolean: get the message from the DB, false to use only + * the localisation + * @param bool|string $langcode Code of the language to get the message for, if + * it is a valid code create a language for that language, + * if it is a string but not a valid code then make a basic + * language object, if it is a false boolean then use the + * current users language (as a fallback for the old + * parameter functionality), or if it is a true boolean + * then use the wikis content language (also as a + * fallback). * @param $isFullKey Boolean: specifies whether $key is a two part key * "msg/lang". * * @throws MWException - * @return string|bool False if the message doesn't exist, otherwise the message + * @return string|bool */ function get( $key, $useDB = true, $langcode = true, $isFullKey = false ) { global $wgLanguageCode, $wgContLang; - wfProfileIn( __METHOD__ ); - if ( is_int( $key ) ) { // "Non-string key given" exception sometimes happens for numerical strings that become ints somewhere on their way here $key = strval( $key ); } if ( !is_string( $key ) ) { - wfProfileOut( __METHOD__ ); throw new MWException( 'Non-string key given' ); } if ( strval( $key ) === '' ) { # Shortcut: the empty key is always missing - wfProfileOut( __METHOD__ ); return false; } - - # Obtain the initial language object - if ( $isFullKey ) { - $keyParts = explode( '/', $key ); - if ( count( $keyParts ) < 2 ) { - throw new MWException( "Message key '$key' does not appear to be a full key." ); - } - - $langcode = array_pop( $keyParts ); - $key = implode( '/', $keyParts ); - } - - # Obtain a language object for the requested language from the passed language code - # Note that the language code could in fact be a language object already but we assume - # it's a string further below. - $requestedLangObj = wfGetLangObj( $langcode ); - if ( !$requestedLangObj ) { - wfProfileOut( __METHOD__ ); + $lang = wfGetLangObj( $langcode ); + if ( !$lang ) { throw new MWException( "Bad lang code $langcode given" ); } - $langcode = $requestedLangObj->getCode(); + + $langcode = $lang->getCode(); + + $message = false; # Normalise title-case input (with some inlining) $lckey = str_replace( ' ', '_', $key ); @@ -661,37 +641,24 @@ class MessageCache { $uckey = $wgContLang->ucfirst( $lckey ); } - # Loop through each language in the fallback list until we find something useful - $message = false; - # Try the MediaWiki namespace - if ( !$this->mDisable && $useDB ) { - $fallbackChain = Language::getFallbacksIncludingSiteLanguage( $langcode ); - array_unshift( $fallbackChain, $langcode ); - - foreach ( $fallbackChain as $langcode ) { - if ( $langcode === $wgLanguageCode ) { - # Messages created in the content language will not have the /lang extension - $message = $this->getMsgFromNamespace( $uckey, $langcode ); - } else { - $message = $this->getMsgFromNamespace( "$uckey/$langcode", $langcode ); - } - - if ( $message !== false ) { - break; - } + if( !$this->mDisable && $useDB ) { + $title = $uckey; + if( !$isFullKey && ( $langcode != $wgLanguageCode ) ) { + $title .= '/' . $langcode; } + $message = $this->getMsgFromNamespace( $title, $langcode ); } # Try the array in the language object if ( $message === false ) { - $message = $requestedLangObj->getMessage( $lckey ); - if ( is_null ( $message ) ) { + $message = $lang->getMessage( $lckey ); + if ( is_null( $message ) ) { $message = false; } } - # If we still have no message, maybe the key was in fact a full key so try that + # Try the array of another language if( $message === false ) { $parts = explode( '/', $lckey ); # We may get calls for things that are http-urls from sidebar @@ -705,9 +672,15 @@ class MessageCache { } } + # Is this a custom message? Try the default language in the db... + if( ( $message === false || $message === '-' ) && + !$this->mDisable && $useDB && + !$isFullKey && ( $langcode != $wgLanguageCode ) ) { + $message = $this->getMsgFromNamespace( $uckey, $wgLanguageCode ); + } + # Final fallback if( $message === false ) { - wfProfileOut( __METHOD__ ); return false; } @@ -721,7 +694,6 @@ class MessageCache { ' ' => "\xc2\xa0", ) ); - wfProfileOut( __METHOD__ ); return $message; } diff --git a/languages/Language.php b/languages/Language.php index 16de816465..57d456a6d7 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -3983,46 +3983,6 @@ class Language { } } - /** - * Get the ordered list of fallback languages, ending with the fallback - * language chain for the site language. - * - * @since 1.21 - * @param $code string Language code - * @return array - */ - public static function getFallbacksIncludingSiteLanguage( $code ) { - global $wgLanguageCode; - - // Usually, we will only store a tiny number of fallback chains, so we - // keep them in static memory. - static $fallbackLanguageCache = array(); - $cacheKey = "{$code}-{$wgLanguageCode}"; - - if ( !array_key_exists( $cacheKey, $fallbackLanguageCache ) ) { - $fallbacks = self::getFallbacksFor( $code ); - - // Take the final 'en' off of the array before splicing - if ( end( $fallbacks ) === 'en' ) { - array_pop( $fallbacks ); - } - // Append the site's fallback chain, including the site language itself - $siteFallbacks = self::getFallbacksFor( $wgLanguageCode ); - array_unshift( $siteFallbacks, $wgLanguageCode ); - - // Eliminate any languages already included in the chain - $siteFallbacks = array_intersect( array_diff( $siteFallbacks, $fallbacks ), $siteFallbacks ); - if ( $siteFallbacks ) { - $fallbacks = array_merge( $fallbacks, $siteFallbacks ); - } - if ( end( $fallbacks ) !== 'en' ) { - $fallbacks[] = 'en'; - } - $fallbackLanguageCache[$cacheKey] = $fallbacks; - } - return $fallbackLanguageCache[$cacheKey]; - } - /** * Get all messages for a given language * WARNING: this may take a long time. If you just need all message *keys* diff --git a/tests/phpunit/includes/cache/MessageCacheTest.php b/tests/phpunit/includes/cache/MessageCacheTest.php deleted file mode 100644 index ada453c208..0000000000 --- a/tests/phpunit/includes/cache/MessageCacheTest.php +++ /dev/null @@ -1,114 +0,0 @@ -configureLanguages(); - MessageCache::singleton()->enable(); - } - - /** - * Helper function -- setup site language for testing - */ - protected function configureLanguages() { - // for the test, we need the content language to be anything but English, - // let's choose e.g. German (de) - $langCode = 'de'; - $langObj = Language::factory( $langCode ); - - $this->setMwGlobals( array( - 'wgLanguageCode' => $langCode, - 'wgLang' => $langObj, - 'wgContLang' => $langObj, - ) ); - } - - function addDBData() { - $this->configureLanguages(); - - // Set up messages and fallbacks ab -> ru -> de -> en - $this->makePage( 'FallbackLanguageTest-Full', 'ab' ); - $this->makePage( 'FallbackLanguageTest-Full', 'ru' ); - $this->makePage( 'FallbackLanguageTest-Full', 'de' ); - $this->makePage( 'FallbackLanguageTest-Full', 'en' ); - - // Fallbacks where ab does not exist - $this->makePage( 'FallbackLanguageTest-Partial', 'ru' ); - $this->makePage( 'FallbackLanguageTest-Partial', 'de' ); - $this->makePage( 'FallbackLanguageTest-Partial', 'en' ); - - // Fallback to the content language - $this->makePage( 'FallbackLanguageTest-ContLang', 'de' ); - $this->makePage( 'FallbackLanguageTest-ContLang', 'en' ); - - // Fallback to english - $this->makePage( 'FallbackLanguageTest-English', 'en' ); - - // Full key tests -- always want russian - $this->makePage( 'MessageCacheTest-FullKeyTest', 'ab' ); - $this->makePage( 'MessageCacheTest-FullKeyTest', 'ru' ); - } - - /** - * Helper function for addDBData -- adds a simple page to the database - * - * @param string $title Title of page to be created - * @param string $lang Language and content of the created page - */ - protected function makePage( $title, $lang ) { - global $wgContLang; - - $title = Title::newFromText( - ( $lang == $wgContLang->getCode() ) ? $title : "$title/$lang", - NS_MEDIAWIKI - ); - $wikiPage = new WikiPage( $title ); - $content = ContentHandler::makeContent( $lang, $title ); - $wikiPage->doEditContent( $content, "$lang translation test case" ); - } - - /** - * Test message fallbacks, bug #1495 - * - * @dataProvider provideMessagesForFallback - */ - function testMessageFallbacks( $message, $lang, $expectedContent ) { - $result = MessageCache::singleton()->get( $message, true, $lang ); - $this->assertEquals( $expectedContent, $result, "Message fallback failed." ); - } - - public static function provideMessagesForFallback() { - return array( - array( 'FallbackLanguageTest-Full', 'ab', 'ab' ), - array( 'FallbackLanguageTest-Partial', 'ab', 'ru' ), - array( 'FallbackLanguageTest-ContLang', 'ab', 'de' ), - array( 'FallbackLanguageTest-English', 'ab', 'en' ), - array( 'FallbackLanguageTest-None', 'ab', false ), - ); - } - - /** - * There's a fallback case where the message key is given as fully qualified -- this - * should ignore the passed $lang and use the language from the key - * - * @dataProvider provideMessagesForFullKeys - */ - function testFullKeyBehaviour( $message, $lang, $expectedContent ) { - $result = MessageCache::singleton()->get( $message, true, $lang, true ); - $this->assertEquals( $expectedContent, $result, "Full key message fallback failed." ); - } - - public static function provideMessagesForFullKeys() { - return array( - array( 'MessageCacheTest-FullKeyTest/ru', 'ru', 'ru' ), - array( 'MessageCacheTest-FullKeyTest/ru', 'ab', 'ru' ), - array( 'MessageCacheTest-FullKeyTest/ru/foo', 'ru', false ), - ); - } - -} -- 2.20.1