3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
22 * API module to enumerate language information.
26 class ApiQueryLanguageinfo
extends ApiQueryBase
{
29 * The maximum time for {@link execute()};
30 * if execution takes longer than this, apply continuation.
32 * If the localization cache is used, this time is not expected to ever be
33 * exceeded; on the other hand, if it is not used, a typical request will
34 * not yield more than a handful of languages before the time is exceeded
35 * and continuation is applied, if one of the expensive props is requested.
39 const MAX_EXECUTE_SECONDS
= 2.0;
41 /** @var callable|null */
42 private $microtimeFunction;
45 * @param ApiQuery $queryModule
46 * @param string $moduleName
47 * @param callable|null $microtimeFunction Function to use instead of microtime(), for testing.
48 * Should accept no arguments and return float seconds. (null means real microtime().)
50 public function __construct(
51 ApiQuery
$queryModule,
53 $microtimeFunction = null
55 parent
::__construct( $queryModule, $moduleName, 'li' );
56 $this->microtimeFunction
= $microtimeFunction;
60 private function microtime() {
61 if ( $this->microtimeFunction
) {
62 return ( $this->microtimeFunction
)();
64 return microtime( true );
68 public function execute() {
69 $endTime = $this->microtime() + self
::MAX_EXECUTE_SECONDS
;
71 $props = array_flip( $this->getParameter( 'prop' ) );
72 $includeCode = isset( $props['code'] );
73 $includeBcp47 = isset( $props['bcp47'] );
74 $includeDir = isset( $props['dir'] );
75 $includeAutonym = isset( $props['autonym'] );
76 $includeName = isset( $props['name'] );
77 $includeFallbacks = isset( $props['fallbacks'] );
78 $includeVariants = isset( $props['variants'] );
80 $targetLanguageCode = $this->getLanguage()->getCode();
83 $availableLanguageCodes = array_keys( Language
::fetchLanguageNames(
84 // MediaWiki and extensions may return different sets of language codes
85 // when asked for language names in different languages;
86 // asking for English language names is most likely to give us the full set,
87 // even though we may not need those at all
91 $selectedLanguageCodes = $this->getParameter( 'code' );
92 if ( $selectedLanguageCodes === [ '*' ] ) {
93 $languageCodes = $availableLanguageCodes;
95 $languageCodes = array_values( array_intersect(
96 $availableLanguageCodes,
97 $selectedLanguageCodes
99 $unrecognizedCodes = array_values( array_diff(
100 $selectedLanguageCodes,
101 $availableLanguageCodes
103 if ( $unrecognizedCodes !== [] ) {
105 'apiwarn-unrecognizedvalues',
106 $this->encodeParamName( 'code' ),
107 Message
::listParam( $unrecognizedCodes, 'comma' ),
108 count( $unrecognizedCodes ),
112 // order of $languageCodes is guaranteed by Language::fetchLanguageNames()
113 // and preserved by array_values() + array_intersect()
115 $continue = $this->getParameter( 'continue' );
116 if ( $continue === null ) {
117 $continue = reset( $languageCodes );
120 $result = $this->getResult();
122 $this->getQuery()->getModuleName(),
123 $this->getModuleName(),
125 $result->addArrayType( $rootPath, 'assoc' );
127 foreach ( $languageCodes as $languageCode ) {
128 if ( $languageCode < $continue ) {
132 $now = $this->microtime();
133 if ( $now >= $endTime ) {
134 $this->setContinueEnumParameter( 'continue', $languageCode );
139 ApiResult
::setArrayType( $info, 'assoc' );
141 if ( $includeCode ) {
142 $info['code'] = $languageCode;
145 if ( $includeBcp47 ) {
146 $bcp47 = LanguageCode
::bcp47( $languageCode );
147 $info['bcp47'] = $bcp47;
151 $dir = Language
::factory( $languageCode )->getDir();
155 if ( $includeAutonym ) {
156 $autonym = Language
::fetchLanguageName(
158 Language
::AS_AUTONYMS
,
161 $info['autonym'] = $autonym;
164 if ( $includeName ) {
165 $name = Language
::fetchLanguageName(
170 $info['name'] = $name;
173 if ( $includeFallbacks ) {
174 $fallbacks = Language
::getFallbacksFor(
176 // allow users to distinguish between implicit and explicit 'en' fallbacks
177 Language
::STRICT_FALLBACKS
179 ApiResult
::setIndexedTagName( $fallbacks, 'fb' );
180 $info['fallbacks'] = $fallbacks;
183 if ( $includeVariants ) {
184 $variants = Language
::factory( $languageCode )->getVariants();
185 ApiResult
::setIndexedTagName( $variants, 'var' );
186 $info['variants'] = $variants;
189 $fit = $result->addValue( $rootPath, $languageCode, $info );
191 $this->setContinueEnumParameter( 'continue', $languageCode );
197 public function getCacheMode( $params ) {
201 public function getAllowedParams() {
204 self
::PARAM_DFLT
=> 'code',
205 self
::PARAM_ISMULTI
=> true,
206 self
::PARAM_TYPE
=> [
215 self
::PARAM_HELP_MSG_PER_VALUE
=> [],
218 self
::PARAM_DFLT
=> '*',
219 self
::PARAM_ISMULTI
=> true,
222 self
::PARAM_HELP_MSG
=> 'api-help-param-continue',
227 protected function getExamplesMessages() {
228 $pathUrl = 'action=' . $this->getQuery()->getModuleName() .
229 '&meta=' . $this->getModuleName();
230 $pathMsg = $this->getModulePath();
231 $prefix = $this->getModulePrefix();
235 => "apihelp-$pathMsg-example-simple",
236 "$pathUrl&{$prefix}prop=autonym|name&lang=de"
237 => "apihelp-$pathMsg-example-autonym-name-de",
238 "$pathUrl&{$prefix}prop=fallbacks|variants&{$prefix}code=oc"
239 => "apihelp-$pathMsg-example-fallbacks-variants-oc",
240 "$pathUrl&{$prefix}prop=bcp47|dir"
241 => "apihelp-$pathMsg-example-bcp47-dir",