MediaWiki REL1_34
LanguageLibrary.php
Go to the documentation of this file.
1<?php
2
4
6 public $langCache = [];
7 public $timeCache = [];
9
10 public function register() {
11 // Pre-populate the language cache
12 global $wgContLang;
13 $this->langCache[$wgContLang->getCode()] = $wgContLang;
14 $this->maxLangCacheSize = $this->getEngine()->getOption( 'maxLangCacheSize' );
15
16 $statics = [
17 'getContLangCode',
18 'isSupportedLanguage',
19 'isKnownLanguageTag',
20 'isValidCode',
21 'isValidBuiltInCode',
22 'fetchLanguageName',
23 'fetchLanguageNames',
24 'getFallbacksFor',
25 ];
26 $methods = [
27 'lcfirst',
28 'ucfirst',
29 'lc',
30 'uc',
31 'caseFold',
32 'formatNum',
33 'formatDate',
34 'formatDuration',
35 'getDurationIntervals',
36 'parseFormattedNumber',
37 'convertPlural',
38 'convertGrammar',
39 'gender',
40 'isRTL',
41 ];
42 $lib = [];
43 foreach ( $statics as $name ) {
44 $lib[$name] = [ $this, $name ];
45 }
46 $ths = $this;
47 foreach ( $methods as $name ) {
48 $lib[$name] = function () use ( $ths, $name ) {
49 $args = func_get_args();
50 return $ths->languageMethod( $name, $args );
51 };
52 }
53 return $this->getEngine()->registerInterface( 'mw.language.lua', $lib );
54 }
55
61 public function getContLangCode() {
62 global $wgContLang;
63 return [ $wgContLang->getCode() ];
64 }
65
72 public function isSupportedLanguage( $code ) {
73 $this->checkType( 'isSupportedLanguage', 1, $code, 'string' );
74 try {
75 // There's no good reason this should throw, but it does. Sigh.
76 return [ Language::isSupportedLanguage( $code ) ];
77 } catch ( MWException $ex ) {
78 return [ false ];
79 }
80 }
81
88 public function isKnownLanguageTag( $code ) {
89 $this->checkType( 'isKnownLanguageTag', 1, $code, 'string' );
90 return [ Language::isKnownLanguageTag( $code ) ];
91 }
92
99 public function isValidCode( $code ) {
100 $this->checkType( 'isValidCode', 1, $code, 'string' );
101 return [ Language::isValidCode( $code ) ];
102 }
103
110 public function isValidBuiltInCode( $code ) {
111 $this->checkType( 'isValidBuiltInCode', 1, $code, 'string' );
112 return [ (bool)Language::isValidBuiltInCode( $code ) ];
113 }
114
122 public function fetchLanguageName( $code, $inLanguage ) {
123 $this->checkType( 'fetchLanguageName', 1, $code, 'string' );
124 $this->checkTypeOptional( 'fetchLanguageName', 2, $inLanguage, 'string', null );
125 return [ Language::fetchLanguageName( $code, $inLanguage ) ];
126 }
127
135 public function fetchLanguageNames( $inLanguage, $include ) {
136 $this->checkTypeOptional( 'fetchLanguageNames', 1, $inLanguage, 'string', null );
137 $this->checkTypeOptional( 'fetchLanguageNames', 2, $include, 'string', 'mw' );
138 return [ Language::fetchLanguageNames( $inLanguage, $include ) ];
139 }
140
147 public function getFallbacksFor( $code ) {
148 $this->checkType( 'getFallbacksFor', 1, $code, 'string' );
149 $ret = Language::getFallbacksFor( $code );
150 // Make 1-based
151 if ( count( $ret ) ) {
152 $ret = array_combine( range( 1, count( $ret ) ), $ret );
153 }
154 return [ $ret ];
155 }
156
165 public function languageMethod( $name, $args ) {
166 $name = strval( $name );
167 $code = array_shift( $args );
168 if ( !isset( $this->langCache[$code] ) ) {
169 if ( count( $this->langCache ) > $this->maxLangCacheSize ) {
170 throw new Scribunto_LuaError( 'too many language codes requested' );
171 }
172 try {
173 $this->langCache[$code] = Language::factory( $code );
174 } catch ( MWException $ex ) {
175 throw new Scribunto_LuaError( "language code '$code' is invalid" );
176 }
177 }
178 $lang = $this->langCache[$code];
179 switch ( $name ) {
180 // Zero arguments
181 case 'isRTL':
182 return [ $lang->$name() ];
183
184 // One string argument passed straight through
185 case 'lcfirst':
186 case 'ucfirst':
187 case 'lc':
188 case 'uc':
189 case 'caseFold':
190 $this->checkType( $name, 1, $args[0], 'string' );
191 return [ $lang->$name( $args[0] ) ];
192
193 case 'parseFormattedNumber':
194 if ( is_numeric( $args[0] ) ) {
195 $args[0] = strval( $args[0] );
196 }
197 if ( $this->getLuaType( $args[0] ) !== 'string' ) {
198 // Be like tonumber(), return nil instead of erroring out
199 return [ null ];
200 }
201 return [ $lang->$name( $args[0] ) ];
202
203 // Custom handling
204 default:
205 return $this->$name( $lang, $args );
206 }
207 }
208
216 public function convertPlural( $lang, $args ) {
217 $number = array_shift( $args );
218 $this->checkType( 'convertPlural', 1, $number, 'number' );
219 if ( is_array( $args[0] ) ) {
220 $args = $args[0];
221 }
222 $forms = array_values( array_map( 'strval', $args ) );
223 return [ $lang->convertPlural( $number, $forms ) ];
224 }
225
233 public function convertGrammar( $lang, $args ) {
234 $this->checkType( 'convertGrammar', 1, $args[0], 'string' );
235 $this->checkType( 'convertGrammar', 2, $args[1], 'string' );
236 return [ $lang->convertGrammar( $args[0], $args[1] ) ];
237 }
238
246 public function gender( $lang, $args ) {
247 $this->checkType( 'gender', 1, $args[0], 'string' );
248 $username = trim( array_shift( $args ) );
249
250 if ( is_array( $args[0] ) ) {
251 $args = $args[0];
252 }
253 $forms = array_values( array_map( 'strval', $args ) );
254
255 // Shortcuts
256 if ( count( $forms ) === 0 ) {
257 return [ '' ];
258 } elseif ( count( $forms ) === 1 ) {
259 return [ $forms[0] ];
260 }
261
262 if ( $username === 'male' || $username === 'female' ) {
263 $gender = $username;
264 } else {
265 // default
266 $gender = User::getDefaultOption( 'gender' );
267
268 // Check for "User:" prefix
269 $title = Title::newFromText( $username );
270 if ( $title && $title->getNamespace() == NS_USER ) {
271 $username = $title->getText();
272 }
273
274 // check parameter, or use the ParserOptions if in interface message
275 $user = User::newFromName( $username );
276 if ( $user ) {
277 $genderCache = MediaWikiServices::getInstance()->getGenderCache();
278 $gender = $genderCache->getGenderOf( $user, __METHOD__ );
279 } elseif ( $username === '' ) {
280 $parserOptions = $this->getParserOptions();
281 if ( $parserOptions->getInterfaceMessage() ) {
282 $genderCache = MediaWikiServices::getInstance()->getGenderCache();
283 $gender = $genderCache->getGenderOf( $parserOptions->getUser(), __METHOD__ );
284 }
285 }
286 }
287 return [ $lang->gender( $gender, $forms ) ];
288 }
289
297 public function formatNum( $lang, $args ) {
298 $num = $args[0];
299 $this->checkType( 'formatNum', 1, $num, 'number' );
300
301 $noCommafy = false;
302 if ( isset( $args[1] ) ) {
303 $this->checkType( 'formatNum', 2, $args[1], 'table' );
304 $options = $args[1];
305 $noCommafy = !empty( $options['noCommafy'] );
306 }
307 return [ $lang->formatNum( $num, $noCommafy ) ];
308 }
309
318 public function formatDate( $lang, $args ) {
319 $this->checkType( 'formatDate', 1, $args[0], 'string' );
320 $this->checkTypeOptional( 'formatDate', 2, $args[1], 'string', '' );
321 $this->checkTypeOptional( 'formatDate', 3, $args[2], 'boolean', false );
322
323 list( $format, $date, $local ) = $args;
324 $langcode = $lang->getCode();
325
326 if ( $date === '' ) {
327 $cacheKey = $this->getParserOptions()->getTimestamp();
328 $timestamp = new MWTimestamp( $cacheKey );
329 $date = $timestamp->getTimestamp( TS_ISO_8601 );
330 $useTTL = true;
331 } else {
332 # Correct for DateTime interpreting 'XXXX' as XX:XX o'clock
333 if ( preg_match( '/^[0-9]{4}$/', $date ) ) {
334 $date = '00:00 ' . $date;
335 }
336
337 $cacheKey = $date;
338 $useTTL = false;
339 }
340
341 if ( isset( $this->timeCache[$format][$cacheKey][$langcode][$local] ) ) {
342 $ttl = $this->timeCache[$format][$cacheKey][$langcode][$local][1];
343 if ( $useTTL && $ttl !== null ) {
344 $this->getEngine()->setTTL( $ttl );
345 }
346 return [ $this->timeCache[$format][$cacheKey][$langcode][$local][0] ];
347 }
348
349 # Default input timezone is UTC.
350 try {
351 $utc = new DateTimeZone( 'UTC' );
352 $dateObject = new DateTime( $date, $utc );
353 } catch ( Exception $ex ) {
354 throw new Scribunto_LuaError( "bad argument #2 to 'formatDate' (not a valid timestamp)" );
355 }
356
357 # Set output timezone.
358 if ( $local ) {
359 global $wgLocaltimezone;
360 if ( isset( $wgLocaltimezone ) ) {
361 $tz = new DateTimeZone( $wgLocaltimezone );
362 } else {
363 $tz = new DateTimeZone( date_default_timezone_get() );
364 }
365 } else {
366 $tz = $utc;
367 }
368 $dateObject->setTimezone( $tz );
369 # Generate timestamp
370 $ts = $dateObject->format( 'YmdHis' );
371
372 if ( $ts < 0 ) {
373 throw new Scribunto_LuaError( "mw.language:formatDate() only supports years from 0" );
374 } elseif ( $ts >= 100000000000000 ) {
375 throw new Scribunto_LuaError( "mw.language:formatDate() only supports years up to 9999" );
376 }
377
378 $ttl = null;
379 $ret = $lang->sprintfDate( $format, $ts, $tz, $ttl );
380 $this->timeCache[$format][$cacheKey][$langcode][$local] = [ $ret, $ttl ];
381 if ( $useTTL && $ttl !== null ) {
382 $this->getEngine()->setTTL( $ttl );
383 }
384 return [ $ret ];
385 }
386
394 public function formatDuration( $lang, $args ) {
395 $this->checkType( 'formatDuration', 1, $args[0], 'number' );
396 $this->checkTypeOptional( 'formatDuration', 2, $args[1], 'table', [] );
397
398 list( $seconds, $chosenIntervals ) = $args;
399 $langcode = $lang->getCode();
400 $chosenIntervals = array_values( $chosenIntervals );
401
402 $ret = $lang->formatDuration( $seconds, $chosenIntervals );
403 return [ $ret ];
404 }
405
413 public function getDurationIntervals( $lang, $args ) {
414 $this->checkType( 'getDurationIntervals', 1, $args[0], 'number' );
415 $this->checkTypeOptional( 'getDurationIntervals', 2, $args[1], 'table', [] );
416
417 list( $seconds, $chosenIntervals ) = $args;
418 $langcode = $lang->getCode();
419 $chosenIntervals = array_values( $chosenIntervals );
420
421 $ret = $lang->getDurationIntervals( $seconds, $chosenIntervals );
422 return [ $ret ];
423 }
424}
$wgLocaltimezone
Fake out the timezone that the server thinks it's in.
$wgContLang
Definition Setup.php:800
if( $line===false) $args
Definition cdb.php:64
MediaWiki exception.
Library for creating and parsing MW-style timestamps.
MediaWikiServices is the service locator for the application scope of MediaWiki.
convertGrammar( $lang, $args)
convertGrammar handler
convertPlural( $lang, $args)
convertPlural handler
formatDate( $lang, $args)
formatDate handler
getDurationIntervals( $lang, $args)
getDurationIntervals handler
formatNum( $lang, $args)
formatNum handler
isValidBuiltInCode( $code)
Handler for isValidBuiltInCode.
formatDuration( $lang, $args)
formatDuration handler
fetchLanguageName( $code, $inLanguage)
Handler for fetchLanguageName.
getContLangCode()
Handler for getContLangCode.
isValidCode( $code)
Handler for isValidCode.
fetchLanguageNames( $inLanguage, $include)
Handler for fetchLanguageNames.
getFallbacksFor( $code)
Handler for fetchLanguageNames.
isSupportedLanguage( $code)
Handler for isSupportedLanguage.
gender( $lang, $args)
gender handler
isKnownLanguageTag( $code)
Handler for isKnownLanguageTag.
languageMethod( $name, $args)
Language object method handler.
This class provides some basic services that Lua libraries will probably need.
getLuaType( $var)
Get the Lua type corresponding to the type of the variable.
checkType( $name, $argIdx, $arg, $expectType)
Check the type of a variable.
getEngine()
Get the engine.
checkTypeOptional( $name, $argIdx, &$arg, $expectType, $default)
Check the type of a variable, with default if null.
getParserOptions()
Get the parser options.
const NS_USER
Definition Defines.php:71
if(!isset( $args[0])) $lang