Index: trunk/phase3/tests/LanguageConverterTest.php |
— | — | @@ -0,0 +1,121 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class LanguageConverterTest extends PHPUnit_Framework_TestCase { |
| 5 | + protected $lang = null; |
| 6 | + protected $lc = null; |
| 7 | + |
| 8 | + function setUp() { |
| 9 | + $this->lang = new LanguageTest(); |
| 10 | + $this->lc = new TestConverter( $this->lang, 'tg', |
| 11 | + array( 'tg', 'tg-latn' ) ); |
| 12 | + } |
| 13 | + |
| 14 | + function tearDown() { |
| 15 | + unset($this->lc); |
| 16 | + unset($this->lang); |
| 17 | + } |
| 18 | + |
| 19 | + function testGetPreferredVariant() { |
| 20 | + global $wgRequest, $wgUsePathInfo, $wgLanguageCode, |
| 21 | + $wgVariantArticlePath, $wgUser, $wgContLang, |
| 22 | + $wgDefaultLanguageVariant; |
| 23 | + |
| 24 | + $wgRequest = new FauxRequest(array()); |
| 25 | + $wgUser = new User; |
| 26 | + $wgContLang = Language::factory( 'tg-latn' ); |
| 27 | + |
| 28 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false)); |
| 29 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(false, true)); |
| 30 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false)); |
| 31 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(true, true)); |
| 32 | + |
| 33 | + $wgRequest->setHeader('Accept-Language', 'tg-latn'); |
| 34 | + $this->lc = new TestConverter( $this->lang, 'tg', |
| 35 | + array( 'tg', 'tg-latn' ) ); |
| 36 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false)); |
| 37 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true)); |
| 38 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false)); |
| 39 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true)); |
| 40 | + |
| 41 | + $wgRequest->setHeader('Accept-Language', 'tg;q=1'); |
| 42 | + $this->lc = new TestConverter( $this->lang, 'tg', |
| 43 | + array( 'tg', 'tg-latn' ) ); |
| 44 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false)); |
| 45 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(false, true)); |
| 46 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false)); |
| 47 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(true, true)); |
| 48 | + |
| 49 | + $wgRequest->setHeader('Accept-Language', 'tg-latn;q=1'); |
| 50 | + $this->lc = new TestConverter( $this->lang, 'tg', |
| 51 | + array( 'tg', 'tg-latn' ) ); |
| 52 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false)); |
| 53 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true)); |
| 54 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false)); |
| 55 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true)); |
| 56 | + |
| 57 | + $wgRequest->setHeader('Accept-Language', 'en, tg-latn;q=1'); |
| 58 | + $this->lc = new TestConverter( $this->lang, 'tg', |
| 59 | + array( 'tg', 'tg-latn' ) ); |
| 60 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false)); |
| 61 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true)); |
| 62 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false)); |
| 63 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true)); |
| 64 | + $wgRequest->setHeader('Accept-Language', ''); |
| 65 | + |
| 66 | + $wgUser = User::newFromId("admin"); |
| 67 | + $wgContLang = Language::factory( 'tg-latn' ); |
| 68 | + $wgUser->setId(1); |
| 69 | + $wgUser->setOption('variant', 'tg-latn'); |
| 70 | + $this->lc = new TestConverter( $this->lang, 'tg', |
| 71 | + array( 'tg', 'tg-latn' ) ); |
| 72 | + |
| 73 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false)); |
| 74 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(false, true)); |
| 75 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, false)); |
| 76 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true)); |
| 77 | + |
| 78 | + $wgRequest->setVal('variant', 'tg'); |
| 79 | + $this->lc = new TestConverter( $this->lang, 'tg', |
| 80 | + array( 'tg', 'tg-latn' ) ); |
| 81 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false)); |
| 82 | + $this->assertEquals('tg', $this->lc->getPreferredVariant(true, true)); |
| 83 | + |
| 84 | + $wgRequest->setVal('variant', null); |
| 85 | + $wgDefaultLanguageVariant = 'tg-latn'; |
| 86 | + $this->lc = new TestConverter( $this->lang, 'tg', |
| 87 | + array( 'tg', 'tg-latn' ) ); |
| 88 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, false)); |
| 89 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true)); |
| 90 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, false)); |
| 91 | + $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true)); |
| 92 | + |
| 93 | + |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +/** |
| 98 | + * Test converter (from Tajiki to latin orthography) |
| 99 | + */ |
| 100 | +class TestConverter extends LanguageConverter { |
| 101 | + private $table = array( |
| 102 | + 'б' => 'b', |
| 103 | + 'в' => 'v', |
| 104 | + 'г' => 'g', |
| 105 | + ); |
| 106 | + |
| 107 | + function loadDefaultTables() { |
| 108 | + $this->mTables = array( |
| 109 | + 'tg-latn' => new ReplacementArray( $this->table ), |
| 110 | + 'tg' => new ReplacementArray() |
| 111 | + ); |
| 112 | + } |
| 113 | + |
| 114 | +} |
| 115 | + |
| 116 | +class LanguageTest extends Language { |
| 117 | + function __construct() { |
| 118 | + parent::__construct(); |
| 119 | + $variants = array( 'tg', 'tg-latn' ); |
| 120 | + $this->mConverter = new TestConverter( $this, 'tg', $variants ); |
| 121 | + } |
| 122 | +} |
Property changes on: trunk/phase3/tests/LanguageConverterTest.php |
___________________________________________________________________ |
Name: svn:eol-syle |
1 | 123 | + native |
Index: trunk/phase3/tests/bootstrap.php |
— | — | @@ -1,8 +1,18 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -$IP = realpath(dirname( __FILE__ ) . '/..'); |
| 4 | +global $wgCommandLineMode, $IP, $wgMemc; |
| 5 | +$wgCommandLineMode = true; |
5 | 6 | define('MEDIAWIKI', 1); |
6 | | -global $optionsWithArgs; |
7 | | -$optionsWithArgs = array(); |
8 | 7 | |
9 | | -require_once( '../maintenance/commandLine.inc' ); |
| 8 | +require dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR."LocalSettings.php"; |
| 9 | + |
| 10 | +require "Defines.php"; |
| 11 | +require "ProfilerStub.php"; |
| 12 | +require 'GlobalFunctions.php'; |
| 13 | +require 'Hooks.php'; |
| 14 | +require "AutoLoader.php"; |
| 15 | +require 'ProxyTools.php'; |
| 16 | +require 'ObjectCache.php'; |
| 17 | +require 'ImageFunctions.php'; |
| 18 | + |
| 19 | +$wgMemc =& wfGetMainCache(); |
Index: trunk/phase3/tests/ArticleTest.php |
— | — | @@ -4,6 +4,8 @@ |
5 | 5 | var $saveGlobals = array(); |
6 | 6 | |
7 | 7 | function setUp() { |
| 8 | + global $wgContLang; |
| 9 | + $wgContLang = Language::factory( 'en' ); |
8 | 10 | $globalSet = array( |
9 | 11 | 'wgLegacyEncoding' => false, |
10 | 12 | 'wgCompressRevisions' => false, |
Index: trunk/phase3/includes/WebRequest.php |
— | — | @@ -762,6 +762,10 @@ |
763 | 763 | return isset( $this->headers[$name] ) ? $this->headers[$name] : false; |
764 | 764 | } |
765 | 765 | |
| 766 | + public function setHeader( $name, $val ) { |
| 767 | + $this->headers[$name] = $val; |
| 768 | + } |
| 769 | + |
766 | 770 | public function getSessionData( $key ) { |
767 | 771 | if( !isset( $this->session[$key] ) ) |
768 | 772 | return null; |
Index: trunk/phase3/languages/LanguageConverter.php |
— | — | @@ -16,7 +16,7 @@ |
17 | 17 | * @maintainers fdcn <fdcn64@gmail.com>, shinjiman <shinjiman@gmail.com>, PhiLiP <philip.npc@gmail.com> |
18 | 18 | */ |
19 | 19 | class LanguageConverter { |
20 | | - var $mPreferredVariant = ''; |
| 20 | + var $mPreferredVariant = ''; // The User's preferred variant |
21 | 21 | var $mMainLanguageCode; |
22 | 22 | var $mVariants, $mVariantFallbacks, $mVariantNames; |
23 | 23 | var $mTablesLoaded = false; |
— | — | @@ -34,6 +34,7 @@ |
35 | 35 | var $mUcfirst = false; |
36 | 36 | var $mTitleOriginal = ''; |
37 | 37 | var $mTitleDisplay = ''; |
| 38 | + var $mHeaderVariant = null; |
38 | 39 | |
39 | 40 | const CACHE_VERSION_KEY = 'VERSION 6'; |
40 | 41 | |
— | — | @@ -142,44 +143,48 @@ |
143 | 144 | global $wgUser, $wgRequest, $wgVariantArticlePath, |
144 | 145 | $wgDefaultLanguageVariant, $wgOut; |
145 | 146 | |
146 | | - // bug 21974, don't return $this->mPreferredVariant if $fromUser = false |
147 | | - if ( $fromUser && $this->mPreferredVariant ) { |
| 147 | + // see if the preference is set in the request |
| 148 | + $req = $wgRequest->getText( 'variant' ); |
| 149 | + if ( in_array( $req, $this->mVariants ) ) { |
| 150 | + $this->mPreferredVariant = $req; |
148 | 151 | return $this->mPreferredVariant; |
149 | 152 | } |
150 | 153 | |
151 | | - // figure out user lang without constructing wgLang to avoid |
152 | | - // infinite recursion |
153 | | - if ( $fromUser ) { |
| 154 | + if ( $fromUser ) { |
| 155 | + // bug 21974, don't return $this->mPreferredVariant if |
| 156 | + // $fromUser = false |
| 157 | + if ( $this->mPreferredVariant ) { |
| 158 | + return $this->mPreferredVariant; |
| 159 | + } |
| 160 | + |
| 161 | + // figure out user lang without constructing wgLang to avoid |
| 162 | + // infinite recursion |
154 | 163 | $defaultUserLang = $wgUser->getOption( 'language' ); |
| 164 | + |
| 165 | + // get language variant preference from logged in users |
| 166 | + // Don't call this on stub objects because that causes infinite |
| 167 | + // recursion during initialisation |
| 168 | + if ( $wgUser->isLoggedIn() ) { |
| 169 | + $this->mPreferredVariant = $wgUser->getOption( 'variant' ); |
| 170 | + } |
| 171 | + |
155 | 172 | } else { |
156 | 173 | $defaultUserLang = $this->mMainLanguageCode; |
157 | 174 | } |
| 175 | + $userLang = $wgRequest->getVal( 'uselang', $defaultUserLang ); |
158 | 176 | |
159 | | - $userLang = $wgRequest->getVal( 'uselang', $defaultUserLang ); |
160 | 177 | // see if interface language is same as content, if not, prevent |
161 | 178 | // conversion |
162 | | - |
163 | 179 | if ( ! in_array( $userLang, $this->mVariants ) ) { |
164 | 180 | // no conversion |
165 | 181 | $this->mPreferredVariant = $this->mMainLanguageCode; |
166 | 182 | return $this->mPreferredVariant; |
167 | | - } |
168 | | - |
169 | | - // see if the preference is set in the request |
170 | | - $req = $wgRequest->getText( 'variant' ); |
171 | | - if ( in_array( $req, $this->mVariants ) ) { |
172 | | - $this->mPreferredVariant = $req; |
| 183 | + } elseif ( $this->mPreferredVariant ) { |
| 184 | + // if the variant was set above and it iss a variant of |
| 185 | + // the content language |
173 | 186 | return $this->mPreferredVariant; |
174 | 187 | } |
175 | 188 | |
176 | | - // get language variant preference from logged in users |
177 | | - // Don't call this on stub objects because that causes infinite |
178 | | - // recursion during initialisation |
179 | | - if ( $fromUser && $wgUser->isLoggedIn() ) { |
180 | | - $this->mPreferredVariant = $wgUser->getOption( 'variant' ); |
181 | | - return $this->mPreferredVariant; |
182 | | - } |
183 | | - |
184 | 189 | // see if default variant is globaly set |
185 | 190 | if ( $wgDefaultLanguageVariant != false |
186 | 191 | && in_array( $wgDefaultLanguageVariant, $this->mVariants ) ) { |
— | — | @@ -187,60 +192,81 @@ |
188 | 193 | return $this->mPreferredVariant; |
189 | 194 | } |
190 | 195 | |
191 | | - if ( !$this->mPreferredVariant ) { |
192 | | - // see if some supported language variant is set in the |
193 | | - // http header, but we don't set the mPreferredVariant |
194 | | - // variable in case this is called before the user's |
195 | | - // preference is loaded |
| 196 | + $headerVariant = $this->getHeaderVariant(); |
| 197 | + if ( $fromHeader && $headerVariant ) { |
| 198 | + return $headerVariant; |
| 199 | + } |
196 | 200 | |
197 | | - $acceptLanguage = $wgRequest->getHeader( 'Accept-Language' ); |
198 | | - if ( $fromHeader && $acceptLanguage ) { |
199 | | - // explode by comma |
200 | | - $result = explode( ',', strtolower( $acceptLanguage ) ); |
| 201 | + return $this->mMainLanguageCode; |
| 202 | + } |
201 | 203 | |
202 | | - $languages = array(); |
| 204 | + /** |
| 205 | + * Determine the language variant from the Accept-Language header. |
| 206 | + * |
| 207 | + * @returns mixed variant if one found, false otherwise. |
| 208 | + */ |
| 209 | + function getHeaderVariant() { |
| 210 | + global $wgRequest; |
203 | 211 | |
204 | | - foreach ( $result as $elem ) { |
205 | | - // if $elem likes 'zh-cn;q=0.9' |
206 | | - if ( ( $posi = strpos( $elem, ';' ) ) !== false ) { |
207 | | - // get the real language code likes 'zh-cn' |
208 | | - $languages[] = substr( $elem, 0, $posi ); |
209 | | - } else { |
210 | | - $languages[] = $elem; |
211 | | - } |
212 | | - } |
| 212 | + if ( $this->mHeaderVariant ) { |
| 213 | + return $this->mHeaderVariant; |
| 214 | + } |
213 | 215 | |
214 | | - $fallback_languages = array(); |
215 | | - foreach ( $languages as $language ) { |
216 | | - // strip whitespace |
217 | | - $language = trim( $language ); |
218 | | - if ( in_array( $language, $this->mVariants ) ) { |
219 | | - return $language; |
220 | | - } else { |
221 | | - // To see if there are fallbacks of current language. |
222 | | - // We record these fallback variants, and process |
223 | | - // them later. |
224 | | - $fallbacks = $this->getVariantFallbacks( $language ); |
225 | | - if ( is_string( $fallbacks ) ) { |
226 | | - $fallback_languages[] = $fallbacks; |
227 | | - } elseif ( is_array( $fallbacks ) ) { |
228 | | - $fallback_languages = |
229 | | - array_merge( $fallback_languages, |
230 | | - $fallbacks ); |
231 | | - } |
232 | | - } |
233 | | - } |
| 216 | + // see if some supported language variant is set in the |
| 217 | + // http header, but we don't set the mPreferredVariant |
| 218 | + // variable in case this is called before the user's |
| 219 | + // preference is loaded |
234 | 220 | |
235 | | - // process fallback languages now |
236 | | - $fallback_languages = array_unique( $fallback_languages ); |
237 | | - foreach ( $fallback_languages as $language ) { |
238 | | - if ( in_array( $language, $this->mVariants ) ) { |
239 | | - return $language; |
240 | | - } |
| 221 | + $acceptLanguage = $wgRequest->getHeader( 'Accept-Language' ); |
| 222 | + if ( !$acceptLanguage ) { |
| 223 | + return false; |
| 224 | + } |
| 225 | + |
| 226 | + // explode by comma |
| 227 | + $result = explode( ',', strtolower( $acceptLanguage ) ); |
| 228 | + |
| 229 | + $languages = array(); |
| 230 | + |
| 231 | + foreach ( $result as $elem ) { |
| 232 | + // if $elem likes 'zh-cn;q=0.9' |
| 233 | + if ( ( $posi = strpos( $elem, ';' ) ) !== false ) { |
| 234 | + // get the real language code likes 'zh-cn' |
| 235 | + $languages[] = substr( $elem, 0, $posi ); |
| 236 | + } else { |
| 237 | + $languages[] = $elem; |
| 238 | + } |
| 239 | + } |
| 240 | + |
| 241 | + $fallback_languages = array(); |
| 242 | + foreach ( $languages as $language ) { |
| 243 | + // strip whitespace |
| 244 | + $language = trim( $language ); |
| 245 | + if ( in_array( $language, $this->mVariants ) ) { |
| 246 | + $this->mHeaderVariant = $language; |
| 247 | + return $language; |
| 248 | + } else { |
| 249 | + // To see if there are fallbacks of current language. |
| 250 | + // We record these fallback variants, and process |
| 251 | + // them later. |
| 252 | + $fallbacks = $this->getVariantFallbacks( $language ); |
| 253 | + if ( is_string( $fallbacks ) ) { |
| 254 | + $fallback_languages[] = $fallbacks; |
| 255 | + } elseif ( is_array( $fallbacks ) ) { |
| 256 | + $fallback_languages = |
| 257 | + array_merge( $fallback_languages, |
| 258 | + $fallbacks ); |
241 | 259 | } |
242 | 260 | } |
243 | 261 | } |
244 | | - return $this->mMainLanguageCode; |
| 262 | + |
| 263 | + // process fallback languages now |
| 264 | + $fallback_languages = array_unique( $fallback_languages ); |
| 265 | + foreach ( $fallback_languages as $language ) { |
| 266 | + if ( in_array( $language, $this->mVariants ) ) { |
| 267 | + $this->mHeaderVariant = $language; |
| 268 | + return $language; |
| 269 | + } |
| 270 | + } |
245 | 271 | } |
246 | 272 | |
247 | 273 | /** |