MediaWiki  1.34.0
LanguageNameUtils.php
Go to the documentation of this file.
1 <?php
30 
31 use HashBagOStuff;
32 use Hooks;
35 use MWException;
36 use Wikimedia\Assert\Assert;
37 
49  const AUTONYMS = null;
50 
54  const ALL = 'all';
55 
59  const DEFINED = 'mw';
60 
64  const SUPPORTED = 'mwfile';
65 
67  private $options;
68 
74 
79  private $validCodeCache = [];
80 
81  public const CONSTRUCTOR_OPTIONS = [
82  'ExtraLanguageNames',
83  'UsePigLatinVariant',
84  ];
85 
89  public function __construct( ServiceOptions $options ) {
90  $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
91  $this->options = $options;
92  }
93 
101  public function isSupportedLanguage( $code ) {
102  if ( !$this->isValidBuiltInCode( $code ) ) {
103  return false;
104  }
105 
106  if ( $code === 'qqq' ) {
107  // Special code for internal use, not supported even though there is a qqq.json
108  return false;
109  }
110 
111  return is_readable( $this->getMessagesFileName( $code ) ) ||
112  is_readable( $this->getJsonMessagesFileName( $code ) );
113  }
114 
123  public function isValidCode( $code ) {
124  Assert::parameterType( 'string', $code, '$code' );
125  if ( !isset( $this->validCodeCache[$code] ) ) {
126  // People think language codes are HTML-safe, so enforce it. Ideally we should only
127  // allow a-zA-Z0-9- but .+ and other chars are often used for {{int:}} hacks. See bugs
128  // T39564, T39587, T38938.
129  $this->validCodeCache[$code] =
130  // Protect against path traversal
131  strcspn( $code, ":/\\\000&<>'\"" ) === strlen( $code ) &&
132  !preg_match( MediaWikiTitleCodec::getTitleInvalidRegex(), $code );
133  }
134  return $this->validCodeCache[$code];
135  }
136 
144  public function isValidBuiltInCode( $code ) {
145  Assert::parameterType( 'string', $code, '$code' );
146 
147  return (bool)preg_match( '/^[a-z0-9-]{2,}$/', $code );
148  }
149 
157  public function isKnownLanguageTag( $tag ) {
158  // Quick escape for invalid input to avoid exceptions down the line when code tries to
159  // process tags which are not valid at all.
160  if ( !$this->isValidBuiltInCode( $tag ) ) {
161  return false;
162  }
163 
164  if ( isset( Data\Names::$names[$tag] ) || $this->getLanguageName( $tag, $tag ) !== '' ) {
165  return true;
166  }
167 
168  return false;
169  }
170 
182  public function getLanguageNames( $inLanguage = self::AUTONYMS, $include = self::DEFINED ) {
183  $cacheKey = $inLanguage === self::AUTONYMS ? 'null' : $inLanguage;
184  $cacheKey .= ":$include";
185  if ( !$this->languageNameCache ) {
186  $this->languageNameCache = new HashBagOStuff( [ 'maxKeys' => 20 ] );
187  }
188 
189  $ret = $this->languageNameCache->get( $cacheKey );
190  if ( !$ret ) {
191  $ret = $this->getLanguageNamesUncached( $inLanguage, $include );
192  $this->languageNameCache->set( $cacheKey, $ret );
193  }
194  return $ret;
195  }
196 
203  private function getLanguageNamesUncached( $inLanguage, $include ) {
204  // If passed an invalid language code to use, fallback to en
205  if ( $inLanguage !== self::AUTONYMS && !$this->isValidCode( $inLanguage ) ) {
206  $inLanguage = 'en';
207  }
208 
209  $names = [];
210 
211  if ( $inLanguage !== self::AUTONYMS ) {
212  # TODO: also include for self::AUTONYMS, when this code is more efficient
213  Hooks::run( 'LanguageGetTranslatedLanguageNames', [ &$names, $inLanguage ] );
214  }
215 
216  $mwNames = $this->options->get( 'ExtraLanguageNames' ) + Data\Names::$names;
217  if ( $this->options->get( 'UsePigLatinVariant' ) ) {
218  // Pig Latin (for variant development)
219  $mwNames['en-x-piglatin'] = 'Igpay Atinlay';
220  }
221 
222  foreach ( $mwNames as $mwCode => $mwName ) {
223  # - Prefer own MediaWiki native name when not using the hook
224  # - For other names just add if not added through the hook
225  if ( $mwCode === $inLanguage || !isset( $names[$mwCode] ) ) {
226  $names[$mwCode] = $mwName;
227  }
228  }
229 
230  if ( $include === self::ALL ) {
231  ksort( $names );
232  return $names;
233  }
234 
235  $returnMw = [];
236  $coreCodes = array_keys( $mwNames );
237  foreach ( $coreCodes as $coreCode ) {
238  $returnMw[$coreCode] = $names[$coreCode];
239  }
240 
241  if ( $include === self::SUPPORTED ) {
242  $namesMwFile = [];
243  # We do this using a foreach over the codes instead of a directory loop so that messages
244  # files in extensions will work correctly.
245  foreach ( $returnMw as $code => $value ) {
246  if ( is_readable( $this->getMessagesFileName( $code ) ) ||
247  is_readable( $this->getJsonMessagesFileName( $code ) )
248  ) {
249  $namesMwFile[$code] = $names[$code];
250  }
251  }
252 
253  ksort( $namesMwFile );
254  return $namesMwFile;
255  }
256 
257  ksort( $returnMw );
258  # self::DEFINED option; default if it's not one of the other two options
259  # (self::ALL/self::SUPPORTED)
260  return $returnMw;
261  }
262 
272  public function getLanguageName( $code, $inLanguage = self::AUTONYMS, $include = self::ALL ) {
273  $code = strtolower( $code );
274  $array = $this->getLanguageNames( $inLanguage, $include );
275  return $array[$code] ?? '';
276  }
277 
286  public function getFileName( $prefix, $code, $suffix = '.php' ) {
287  if ( !$this->isValidBuiltInCode( $code ) ) {
288  throw new MWException( "Invalid language code \"$code\"" );
289  }
290 
291  return $prefix . str_replace( '-', '_', ucfirst( $code ) ) . $suffix;
292  }
293 
298  public function getMessagesFileName( $code ) {
299  global $IP;
300  $file = $this->getFileName( "$IP/languages/messages/Messages", $code, '.php' );
301  Hooks::run( 'Language::getMessagesFileName', [ $code, &$file ] );
302  return $file;
303  }
304 
310  public function getJsonMessagesFileName( $code ) {
311  global $IP;
312 
313  if ( !$this->isValidBuiltInCode( $code ) ) {
314  throw new MWException( "Invalid language code \"$code\"" );
315  }
316 
317  return "$IP/languages/i18n/$code.json";
318  }
319 }
MediaWiki\Languages\LanguageNameUtils\$validCodeCache
array $validCodeCache
Cache for validity of language codes.
Definition: LanguageNameUtils.php:79
MediaWikiTitleCodec
A codec for MediaWiki page titles.
Definition: MediaWikiTitleCodec.php:38
HashBagOStuff
Simple store for keeping values in an associative array for the current process.
Definition: HashBagOStuff.php:31
MediaWiki\Languages
Definition: LanguageNameUtils.php:29
MediaWiki\Languages\LanguageNameUtils\getFileName
getFileName( $prefix, $code, $suffix='.php')
Get the name of a file for a certain language code.
Definition: LanguageNameUtils.php:286
MediaWikiTitleCodec\getTitleInvalidRegex
static getTitleInvalidRegex()
Returns a simple regex that will match on characters and sequences invalid in titles.
Definition: MediaWikiTitleCodec.php:512
$file
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
MediaWiki\Languages\LanguageNameUtils\ALL
const ALL
Return all known languages in getLanguageName(s).
Definition: LanguageNameUtils.php:54
MediaWiki\Languages\LanguageNameUtils\getMessagesFileName
getMessagesFileName( $code)
Definition: LanguageNameUtils.php:298
MediaWiki\Languages\LanguageNameUtils\isValidBuiltInCode
isValidBuiltInCode( $code)
Returns true if a language code is of a valid form for the purposes of internal customisation of Medi...
Definition: LanguageNameUtils.php:144
MediaWiki\Languages\LanguageNameUtils
Definition: LanguageNameUtils.php:45
MediaWiki\Languages\LanguageNameUtils\CONSTRUCTOR_OPTIONS
const CONSTRUCTOR_OPTIONS
Definition: LanguageNameUtils.php:81
MediaWiki\Languages\LanguageNameUtils\__construct
__construct(ServiceOptions $options)
Definition: LanguageNameUtils.php:89
MWException
MediaWiki exception.
Definition: MWException.php:26
MediaWiki\Config\ServiceOptions
A class for passing options to services.
Definition: ServiceOptions.php:25
$IP
$IP
Definition: update.php:3
MediaWiki\Languages\LanguageNameUtils\isValidCode
isValidCode( $code)
Returns true if a language code string is of a valid form, whether or not it exists.
Definition: LanguageNameUtils.php:123
MediaWiki\Languages\LanguageNameUtils\$options
ServiceOptions $options
Definition: LanguageNameUtils.php:67
MediaWiki\Languages\LanguageNameUtils\getJsonMessagesFileName
getJsonMessagesFileName( $code)
Definition: LanguageNameUtils.php:310
MediaWiki\Languages\LanguageNameUtils\getLanguageNamesUncached
getLanguageNamesUncached( $inLanguage, $include)
Uncached helper for getLanguageNames.
Definition: LanguageNameUtils.php:203
MediaWiki\Languages\LanguageNameUtils\isSupportedLanguage
isSupportedLanguage( $code)
Checks whether any localisation is available for that language tag in MediaWiki (MessagesXx....
Definition: LanguageNameUtils.php:101
MediaWiki\Languages\LanguageNameUtils\SUPPORTED
const SUPPORTED
Return in getLanguageName(s) only the languages for which we have at least some localisation.
Definition: LanguageNameUtils.php:64
MediaWiki\Languages\LanguageNameUtils\DEFINED
const DEFINED
Return in getLanguageName(s) only the languages that are defined by MediaWiki.
Definition: LanguageNameUtils.php:59
MediaWiki\Languages\LanguageNameUtils\AUTONYMS
const AUTONYMS
Return autonyms in getLanguageName(s).
Definition: LanguageNameUtils.php:49
MediaWiki\Languages\Data\Names\$names
static $names
Definition: Names.php:48
MediaWiki\Languages\LanguageNameUtils\getLanguageNames
getLanguageNames( $inLanguage=self::AUTONYMS, $include=self::DEFINED)
Get an array of language names, indexed by code.
Definition: LanguageNameUtils.php:182
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
MediaWiki\Languages\LanguageNameUtils\$languageNameCache
HashBagOStuff null $languageNameCache
Cache for language names.
Definition: LanguageNameUtils.php:73
Hooks
Hooks class.
Definition: Hooks.php:34
MediaWiki\Languages\LanguageNameUtils\getLanguageName
getLanguageName( $code, $inLanguage=self::AUTONYMS, $include=self::ALL)
Definition: LanguageNameUtils.php:272
MediaWiki\Config\ServiceOptions\assertRequiredOptions
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
Definition: ServiceOptions.php:62
MediaWiki\Languages\LanguageNameUtils\isKnownLanguageTag
isKnownLanguageTag( $tag)
Returns true if a language code is an IETF tag known to MediaWiki.
Definition: LanguageNameUtils.php:157