summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php')
-rw-r--r--www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php364
1 files changed, 364 insertions, 0 deletions
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php
new file mode 100644
index 00000000..b3671e67
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/LanguageLibrary.php
@@ -0,0 +1,364 @@
+<?php
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+class Scribunto_LuaLanguageLibrary extends Scribunto_LuaLibraryBase {
+ public $langCache = [];
+ public $timeCache = [];
+ public $maxLangCacheSize;
+
+ function register() {
+ // Pre-populate the language cache
+ global $wgContLang;
+ $this->langCache[$wgContLang->getCode()] = $wgContLang;
+ $this->maxLangCacheSize = $this->getEngine()->getOption( 'maxLangCacheSize' );
+
+ $statics = [
+ 'getContLangCode',
+ 'isSupportedLanguage',
+ 'isKnownLanguageTag',
+ 'isValidCode',
+ 'isValidBuiltInCode',
+ 'fetchLanguageName',
+ 'fetchLanguageNames',
+ 'getFallbacksFor',
+ ];
+ $methods = [
+ 'lcfirst',
+ 'ucfirst',
+ 'lc',
+ 'uc',
+ 'caseFold',
+ 'formatNum',
+ 'formatDate',
+ 'formatDuration',
+ 'getDurationIntervals',
+ 'parseFormattedNumber',
+ 'convertPlural',
+ 'convertGrammar',
+ 'gender',
+ 'isRTL',
+ ];
+ $lib = [];
+ foreach ( $statics as $name ) {
+ $lib[$name] = [ $this, $name ];
+ }
+ $ths = $this;
+ foreach ( $methods as $name ) {
+ $lib[$name] = function () use ( $ths, $name ) {
+ $args = func_get_args();
+ return $ths->languageMethod( $name, $args );
+ };
+ }
+ return $this->getEngine()->registerInterface( 'mw.language.lua', $lib );
+ }
+
+ function getContLangCode() {
+ global $wgContLang;
+ return [ $wgContLang->getCode() ];
+ }
+
+ function isSupportedLanguage( $code ) {
+ $this->checkType( 'isSupportedLanguage', 1, $code, 'string' );
+ try {
+ // There's no good reason this should throw, but it does. Sigh.
+ return [ Language::isSupportedLanguage( $code ) ];
+ } catch ( MWException $ex ) {
+ return [ false ];
+ }
+ }
+
+ function isKnownLanguageTag( $code ) {
+ $this->checkType( 'isKnownLanguageTag', 1, $code, 'string' );
+ return [ Language::isKnownLanguageTag( $code ) ];
+ }
+
+ function isValidCode( $code ) {
+ $this->checkType( 'isValidCode', 1, $code, 'string' );
+ return [ Language::isValidCode( $code ) ];
+ }
+
+ function isValidBuiltInCode( $code ) {
+ $this->checkType( 'isValidBuiltInCode', 1, $code, 'string' );
+ return [ (bool)Language::isValidBuiltInCode( $code ) ];
+ }
+
+ function fetchLanguageName( $code, $inLanguage ) {
+ $this->checkType( 'fetchLanguageName', 1, $code, 'string' );
+ $this->checkTypeOptional( 'fetchLanguageName', 2, $inLanguage, 'string', null );
+ return [ Language::fetchLanguageName( $code, $inLanguage ) ];
+ }
+
+ function fetchLanguageNames( $inLanguage, $include ) {
+ $this->checkTypeOptional( 'fetchLanguageNames', 1, $inLanguage, 'string', null );
+ $this->checkTypeOptional( 'fetchLanguageNames', 2, $include, 'string', 'mw' );
+ return [ Language::fetchLanguageNames( $inLanguage, $include ) ];
+ }
+
+ function getFallbacksFor( $code ) {
+ $this->checkType( 'getFallbacksFor', 1, $code, 'string' );
+ $ret = Language::getFallbacksFor( $code );
+ // Make 1-based
+ if ( count( $ret ) ) {
+ $ret = array_combine( range( 1, count( $ret ) ), $ret );
+ }
+ return [ $ret ];
+ }
+
+ /**
+ * Language object method handler
+ * @param string $name
+ * @param array $args
+ * @return array
+ * @throws Scribunto_LuaError
+ */
+ function languageMethod( $name, $args ) {
+ $name = strval( $name );
+ $code = array_shift( $args );
+ if ( !isset( $this->langCache[$code] ) ) {
+ if ( count( $this->langCache ) > $this->maxLangCacheSize ) {
+ throw new Scribunto_LuaError( 'too many language codes requested' );
+ }
+ try {
+ $this->langCache[$code] = Language::factory( $code );
+ } catch ( MWException $ex ) {
+ throw new Scribunto_LuaError( "language code '$code' is invalid" );
+ }
+ }
+ $lang = $this->langCache[$code];
+ switch ( $name ) {
+ // Zero arguments
+ case 'isRTL':
+ return [ $lang->$name() ];
+
+ // One string argument passed straight through
+ case 'lcfirst':
+ case 'ucfirst':
+ case 'lc':
+ case 'uc':
+ case 'caseFold':
+ $this->checkType( $name, 1, $args[0], 'string' );
+ return [ $lang->$name( $args[0] ) ];
+
+ case 'parseFormattedNumber':
+ if ( is_numeric( $args[0] ) ) {
+ $args[0] = strval( $args[0] );
+ }
+ if ( $this->getLuaType( $args[0] ) !== 'string' ) {
+ // Be like tonumber(), return nil instead of erroring out
+ return [ null ];
+ }
+ return [ $lang->$name( $args[0] ) ];
+
+ // Custom handling
+ default:
+ return $this->$name( $lang, $args );
+ }
+ }
+
+ /**
+ * convertPlural handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function convertPlural( $lang, $args ) {
+ $number = array_shift( $args );
+ $this->checkType( 'convertPlural', 1, $number, 'number' );
+ if ( is_array( $args[0] ) ) {
+ $args = $args[0];
+ }
+ $forms = array_values( array_map( 'strval', $args ) );
+ return [ $lang->convertPlural( $number, $forms ) ];
+ }
+
+ /**
+ * convertGrammar handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function convertGrammar( $lang, $args ) {
+ $this->checkType( 'convertGrammar', 1, $args[0], 'string' );
+ $this->checkType( 'convertGrammar', 2, $args[1], 'string' );
+ return [ $lang->convertGrammar( $args[0], $args[1] ) ];
+ }
+
+ /**
+ * gender handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function gender( $lang, $args ) {
+ $this->checkType( 'gender', 1, $args[0], 'string' );
+ $username = trim( array_shift( $args ) );
+
+ if ( is_array( $args[0] ) ) {
+ $args = $args[0];
+ }
+ $forms = array_values( array_map( 'strval', $args ) );
+
+ // Shortcuts
+ if ( count( $forms ) === 0 ) {
+ return [ '' ];
+ } elseif ( count( $forms ) === 1 ) {
+ return [ $forms[0] ];
+ }
+
+ if ( $username === 'male' || $username === 'female' ) {
+ $gender = $username;
+ } else {
+ // default
+ $gender = User::getDefaultOption( 'gender' );
+
+ // Check for "User:" prefix
+ $title = Title::newFromText( $username );
+ if ( $title && $title->getNamespace() == NS_USER ) {
+ $username = $title->getText();
+ }
+
+ // check parameter, or use the ParserOptions if in interface message
+ $user = User::newFromName( $username );
+ if ( $user ) {
+ $gender = GenderCache::singleton()->getGenderOf( $user, __METHOD__ );
+ } elseif ( $username === '' ) {
+ $parserOptions = $this->getParserOptions();
+ if ( $parserOptions->getInterfaceMessage() ) {
+ $gender = GenderCache::singleton()->getGenderOf( $parserOptions->getUser(), __METHOD__ );
+ }
+ }
+ }
+ return [ $lang->gender( $gender, $forms ) ];
+ }
+
+ /**
+ * formatNum handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function formatNum( $lang, $args ) {
+ $num = $args[0];
+ $this->checkType( 'formatNum', 1, $num, 'number' );
+
+ $noCommafy = false;
+ if ( isset( $args[1] ) ) {
+ $this->checkType( 'formatNum', 2, $args[1], 'table' );
+ $options = $args[1];
+ $noCommafy = !empty( $options['noCommafy'] );
+ }
+ return [ $lang->formatNum( $num, $noCommafy ) ];
+ }
+
+ /**
+ * formatDate handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ * @throws Scribunto_LuaError
+ */
+ function formatDate( $lang, $args ) {
+ $this->checkType( 'formatDate', 1, $args[0], 'string' );
+ $this->checkTypeOptional( 'formatDate', 2, $args[1], 'string', '' );
+ $this->checkTypeOptional( 'formatDate', 3, $args[2], 'boolean', false );
+
+ list( $format, $date, $local ) = $args;
+ $langcode = $lang->getCode();
+
+ if ( $date === '' ) {
+ $cacheKey = $this->getParserOptions()->getTimestamp();
+ $timestamp = new MWTimestamp( $cacheKey );
+ $date = $timestamp->getTimestamp( TS_ISO_8601 );
+ $useTTL = true;
+ } else {
+ # Correct for DateTime interpreting 'XXXX' as XX:XX o'clock
+ if ( preg_match( '/^[0-9]{4}$/', $date ) ) {
+ $date = '00:00 '.$date;
+ }
+
+ $cacheKey = $date;
+ $useTTL = false;
+ }
+
+ if ( isset( $this->timeCache[$format][$cacheKey][$langcode][$local] ) ) {
+ $ttl = $this->timeCache[$format][$cacheKey][$langcode][$local][1];
+ if ( $useTTL && $ttl !== null ) {
+ $this->getEngine()->setTTL( $ttl );
+ }
+ return [ $this->timeCache[$format][$cacheKey][$langcode][$local][0] ];
+ }
+
+ # Default input timezone is UTC.
+ try {
+ $utc = new DateTimeZone( 'UTC' );
+ $dateObject = new DateTime( $date, $utc );
+ } catch ( Exception $ex ) {
+ throw new Scribunto_LuaError( "bad argument #2 to 'formatDate' (not a valid timestamp)" );
+ }
+
+ # Set output timezone.
+ if ( $local ) {
+ global $wgLocaltimezone;
+ if ( isset( $wgLocaltimezone ) ) {
+ $tz = new DateTimeZone( $wgLocaltimezone );
+ } else {
+ $tz = new DateTimeZone( date_default_timezone_get() );
+ }
+ } else {
+ $tz = $utc;
+ }
+ $dateObject->setTimezone( $tz );
+ # Generate timestamp
+ $ts = $dateObject->format( 'YmdHis' );
+
+ if ( $ts < 0 ) {
+ throw new Scribunto_LuaError( "mw.language:formatDate() only supports years from 0" );
+ } elseif ( $ts >= 100000000000000 ) {
+ throw new Scribunto_LuaError( "mw.language:formatDate() only supports years up to 9999" );
+ }
+
+ $ttl = null;
+ $ret = $lang->sprintfDate( $format, $ts, $tz, $ttl );
+ $this->timeCache[$format][$cacheKey][$langcode][$local] = [ $ret, $ttl ];
+ if ( $useTTL && $ttl !== null ) {
+ $this->getEngine()->setTTL( $ttl );
+ }
+ return [ $ret ];
+ }
+
+ /**
+ * formatDuration handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function formatDuration( $lang, $args ) {
+ $this->checkType( 'formatDuration', 1, $args[0], 'number' );
+ $this->checkTypeOptional( 'formatDuration', 2, $args[1], 'table', [] );
+
+ list( $seconds, $chosenIntervals ) = $args;
+ $langcode = $lang->getCode();
+ $chosenIntervals = array_values( $chosenIntervals );
+
+ $ret = $lang->formatDuration( $seconds, $chosenIntervals );
+ return [ $ret ];
+ }
+
+ /**
+ * getDurationIntervals handler
+ * @param Language $lang
+ * @param array $args
+ * @return array
+ */
+ function getDurationIntervals( $lang, $args ) {
+ $this->checkType( 'getDurationIntervals', 1, $args[0], 'number' );
+ $this->checkTypeOptional( 'getDurationIntervals', 2, $args[1], 'table', [] );
+
+ list( $seconds, $chosenIntervals ) = $args;
+ $langcode = $lang->getCode();
+ $chosenIntervals = array_values( $chosenIntervals );
+
+ $ret = $lang->getDurationIntervals( $seconds, $chosenIntervals );
+ return [ $ret ];
+ }
+}