MediaWiki  master
LanguageFactory.php
Go to the documentation of this file.
1 <?php
25 namespace MediaWiki\Languages;
26 
27 use Config;
28 use Language;
31 use MapCacheLRU;
35 use MWException;
36 use NamespaceInfo;
37 
47  private $options;
48 
50  private $namespaceInfo;
51 
54 
56  private $langNameUtils;
57 
59  private $langFallback;
60 
63 
65  private $hookContainer;
66 
68  private $langObjCache;
69 
71  private $config;
72 
74  private $parentLangCache = [];
75 
79  public const CONSTRUCTOR_OPTIONS = [
81  ];
82 
84  private const LANG_CACHE_SIZE = 10;
85 
96  public function __construct(
105  ) {
106  // We have both ServiceOptions and a Config object because
107  // the Language class hasn't (yet) been updated to use ServiceOptions
108  // and for now gets a full Config
109  $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
110 
111  $this->options = $options;
112  $this->namespaceInfo = $namespaceInfo;
113  $this->localisationCache = $localisationCache;
114  $this->langNameUtils = $langNameUtils;
115  $this->langFallback = $langFallback;
116  $this->langConverterFactory = $langConverterFactory;
117  $this->hookContainer = $hookContainer;
118  $this->langObjCache = new MapCacheLRU( self::LANG_CACHE_SIZE );
119  $this->config = $config;
120  }
121 
129  public function getLanguage( $code ): Language {
130  $code = $this->options->get( MainConfigNames::DummyLanguageCodes )[$code] ?? $code;
131  return $this->langObjCache->getWithSetCallback(
132  $code,
133  function () use ( $code ) {
134  return $this->newFromCode( $code );
135  }
136  );
137  }
138 
146  private function newFromCode( $code, $fallback = false ): Language {
147  if ( !$this->langNameUtils->isValidCode( $code ) ) {
148  throw new MWException( "Invalid language code \"$code\"" );
149  }
150 
151  $constructorArgs = [
152  $code,
153  $this->namespaceInfo,
154  $this->localisationCache,
155  $this->langNameUtils,
156  $this->langFallback,
157  $this->langConverterFactory,
158  $this->hookContainer,
160  ];
161 
162  if ( !$this->langNameUtils->isValidBuiltInCode( $code ) ) {
163  // It's not possible to customise this code with class files, so
164  // just return a Language object. This is to support uselang= hacks.
165  return new Language( ...$constructorArgs );
166  }
167 
168  // Check if there is a language class for the code
169  $class = $this->classFromCode( $code, $fallback );
170  // LanguageCode does not inherit Language
171  if ( class_exists( $class ) && is_a( $class, 'Language', true ) ) {
172  return new $class( ...$constructorArgs );
173  }
174 
175  // Keep trying the fallback list until we find an existing class
176  $fallbacks = $this->langFallback->getAll( $code );
177  foreach ( $fallbacks as $fallbackCode ) {
178  $class = $this->classFromCode( $fallbackCode );
179  if ( class_exists( $class ) ) {
180  // TODO allow additional dependencies to be injected for subclasses somehow
181  return new $class( ...$constructorArgs );
182  }
183  }
184 
185  throw new MWException( "Invalid fallback sequence for language '$code'" );
186  }
187 
193  private function classFromCode( $code, $fallback = true ) {
194  if ( $fallback && $code == 'en' ) {
195  return 'Language';
196  } else {
197  return 'Language' . str_replace( '-', '_', ucfirst( $code ) );
198  }
199  }
200 
209  public function getParentLanguage( $code ) {
210  // We deliberately use array_key_exists() instead of isset() because we cache null.
211  if ( !array_key_exists( $code, $this->parentLangCache ) ) {
212  if ( !$this->langNameUtils->isValidBuiltInCode( $code ) ) {
213  $this->parentLangCache[$code] = null;
214  return null;
215  }
216  foreach ( LanguageConverter::$languagesWithVariants as $mainCode ) {
217  $lang = $this->getLanguage( $mainCode );
218  $converter = $this->langConverterFactory->getLanguageConverter( $lang );
219  if ( $converter->hasVariant( $code ) ) {
220  $this->parentLangCache[$code] = $lang;
221  return $lang;
222  }
223  }
224  $this->parentLangCache[$code] = null;
225  }
226 
227  return $this->parentLangCache[$code];
228  }
229 }
$fallback
Definition: MessagesAb.php:11
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Definition: WebStart.php:82
Base class for multi-variant language conversion.
static array $languagesWithVariants
languages supporting variants
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:45
Class for caching the contents of localisation files, Messages*.php and *.i18n.php.
MediaWiki exception.
Definition: MWException.php:29
Handles a simple LRU key/value map with a maximum number of entries.
Definition: MapCacheLRU.php:36
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
An interface for creating language converters.
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
newFromCode( $code, $fallback=false)
Create a language object for a given language code.
__construct(ServiceOptions $options, NamespaceInfo $namespaceInfo, LocalisationCache $localisationCache, LanguageNameUtils $langNameUtils, LanguageFallback $langFallback, LanguageConverterFactory $langConverterFactory, HookContainer $hookContainer, Config $config)
LanguageConverterFactory $langConverterFactory
getLanguage( $code)
Get a cached or new language object for a given language code.
classFromCode( $code, $fallback=true)
const LANG_CACHE_SIZE
How many distinct Language objects to retain at most in memory (T40439).
getParentLanguage( $code)
Get the "parent" language which has a converter to convert a "compatible" language (in another varian...
A service that provides utilities to do with language names and codes.
A class containing constants representing the names of configuration variables.
const DummyLanguageCodes
Name constant for the DummyLanguageCodes setting, for use with Config::get()
Config $config
Definition: MediaWiki.php:44
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Interface for configuration instances.
Definition: Config.php:30
if(!isset( $args[0])) $lang