MediaWiki  master
LanguageFallback.php
Go to the documentation of this file.
1 <?php
21 namespace MediaWiki\Languages;
22 
23 use InvalidArgumentException;
25 use Wikimedia\Assert\Assert;
26 
36  public const MESSAGES = 0;
37 
42  public const STRICT = 1;
43 
45  private $siteLangCode;
46 
48  private $localisationCache;
49 
51  private $langNameUtils;
52 
54  private $fallbackCache = [];
55 
64  public function __construct(
65  $siteLangCode,
66  LocalisationCache $localisationCache,
67  LanguageNameUtils $langNameUtils
68  ) {
69  $this->siteLangCode = $siteLangCode;
70  $this->localisationCache = $localisationCache;
71  $this->langNameUtils = $langNameUtils;
72  }
73 
81  public function getFirst( $code ) {
82  return $this->getAll( $code )[0] ?? null;
83  }
84 
95  public function getAll( $code, $mode = self::MESSAGES ) {
96  // XXX The LanguageNameUtils dependency is just because of this line, is it needed?
97  // Especially because isValidBuiltInCode() is just a one-line regex anyway, maybe it should
98  // actually be static?
99  if ( $code === 'en' || !$this->langNameUtils->isValidBuiltInCode( $code ) ) {
100  return [];
101  }
102  switch ( $mode ) {
103  case self::MESSAGES:
104  // For unknown languages, fallbackSequence returns an empty array. Hardcode fallback
105  // to 'en' in that case, as English messages are always defined.
106  $ret = $this->localisationCache->getItem( $code, 'fallbackSequence' ) ?: [ 'en' ];
107  break;
108 
109  case self::STRICT:
110  // Use this mode when you don't want to fall back to English unless explicitly
111  // defined, for example when you have language-variant icons and an international
112  // language-independent fallback.
113  $ret = $this->localisationCache->getItem( $code, 'originalFallbackSequence' );
114  break;
115 
116  default:
117  throw new InvalidArgumentException( "Invalid fallback mode \"$mode\"" );
118  }
119 
120  foreach ( $ret as $fallbackCode ) {
121  Assert::postcondition( $this->langNameUtils->isValidBuiltInCode( $fallbackCode ),
122  "Invalid fallback code '$fallbackCode' in fallback sequence for '$code'" );
123  }
124 
125  return $ret;
126  }
127 
136  public function getAllIncludingSiteLanguage( $code ) {
137  // Usually, we will only store a tiny number of fallback chains, so we cache in a member.
138  $cacheKey = "{$code}-{$this->siteLangCode}";
139 
140  if ( !array_key_exists( $cacheKey, $this->fallbackCache ) ) {
141  $fallbacks = $this->getAll( $code );
142 
143  if ( $code === $this->siteLangCode ) {
144  // Don't bother hitting the localisation cache a second time
145  $siteFallbacks = [ $code ];
146  } else {
147  // Append the site's fallback chain, including the site language itself
148  $siteFallbacks = $this->getAll( $this->siteLangCode );
149  array_unshift( $siteFallbacks, $this->siteLangCode );
150 
151  // Eliminate any languages already included in the chain
152  $siteFallbacks = array_diff( $siteFallbacks, $fallbacks );
153  }
154 
155  $this->fallbackCache[$cacheKey] = [ $fallbacks, $siteFallbacks ];
156  }
157  return $this->fallbackCache[$cacheKey];
158  }
159 }
Caching for the contents of localisation files.
getAllIncludingSiteLanguage( $code)
Get the ordered list of fallback languages, ending with the fallback language chain for the site lang...
const STRICT
Return a strict fallback chain in getAll.
getFirst( $code)
Get the first fallback for a given language.
const MESSAGES
Return a fallback chain for messages in getAll.
__construct( $siteLangCode, LocalisationCache $localisationCache, LanguageNameUtils $langNameUtils)
Do not call this directly.
getAll( $code, $mode=self::MESSAGES)
Get the ordered list of fallback languages.
A service that provides utilities to do with language names and codes.