LanguageManager.php 14.6 KB
Newer Older
1 2 3 4
<?php

/**
 * @file
5
 * Contains \Drupal\Core\Language\LanguageManager.
6 7 8 9
 */

namespace Drupal\Core\Language;

10
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
11
use Drupal\Core\StringTranslation\TranslatableMarkup;
12
use Drupal\Core\Url;
13 14

/**
15
 * Class responsible for providing language support on language-unaware sites.
16
 */
17 18
class LanguageManager implements LanguageManagerInterface {
  use DependencySerializationTrait;
19

20
  /**
21 22 23 24 25
   * A static cache of translated language lists.
   *
   * Array of arrays to cache the result of self::getLanguages() keyed by the
   * language the list is translated to (first level) and the flags provided to
   * the method (second level).
26
   *
27
   * @var \Drupal\Core\Language\LanguageInterface[]
28 29
   *
   * @see \Drupal\Core\Language\LanguageManager::getLanguages()
30
   */
31
  protected $languages = array();
32

33
  /**
34
   * The default language object.
35
   *
36
   * @var \Drupal\Core\Language\LanguageDefault
37
   */
38
  protected $defaultLanguage;
39

40 41 42
  /**
   * Constructs the language manager.
   *
43
   * @param \Drupal\Core\Language\LanguageDefault $default_language
44 45 46 47 48 49
   *   The default language.
   */
  public function __construct(LanguageDefault $default_language) {
    $this->defaultLanguage = $default_language;
  }

50
  /**
51
   * {@inheritdoc}
52
   */
53 54
  public function isMultilingual() {
    return FALSE;
55 56
  }

57
  /**
58
   * {@inheritdoc}
59
   */
60
  public function getLanguageTypes() {
61
    return array(LanguageInterface::TYPE_INTERFACE, LanguageInterface::TYPE_CONTENT, LanguageInterface::TYPE_URL);
62 63
  }

64
  /**
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
   * Returns information about all defined language types.
   *
   * Defines the three core language types:
   * - Interface language is the only configurable language type in core. It is
   *   used by t() as the default language if none is specified.
   * - Content language is by default non-configurable and inherits the
   *   interface language negotiated value. It is used by the Field API to
   *   determine the display language for fields if no explicit value is
   *   specified.
   * - URL language is by default non-configurable and is determined through the
   *   URL language negotiation method or the URL fallback language negotiation
   *   method if no language can be detected. It is used by l() as the default
   *   language if none is specified.
   *
   * @return array
   *   An associative array of language type information arrays keyed by
   *   language type machine name, in the format of
   *   hook_language_types_info().
83 84
   */
  public function getDefinedLanguageTypesInfo() {
85
    $this->definedLanguageTypesInfo = array(
86
      LanguageInterface::TYPE_INTERFACE => array(
87 88
        'name' => new TranslatableMarkup('Interface text'),
        'description' => new TranslatableMarkup('Order of language detection methods for interface text. If a translation of interface text is available in the detected language, it will be displayed.'),
89 90 91
        'locked' => TRUE,
      ),
      LanguageInterface::TYPE_CONTENT => array(
92 93
        'name' => new TranslatableMarkup('Content'),
        'description' => new TranslatableMarkup('Order of language detection methods for content. If a version of content is available in the detected language, it will be displayed.'),
94 95 96 97 98 99
        'locked' => TRUE,
      ),
      LanguageInterface::TYPE_URL => array(
        'locked' => TRUE,
      ),
    );
100 101

    return $this->definedLanguageTypesInfo;
102 103
  }

104
  /**
105
   * {@inheritdoc}
106
   */
107
  public function getCurrentLanguage($type = LanguageInterface::TYPE_INTERFACE) {
108
    return $this->getDefaultLanguage();
109 110
  }

111
  /**
112
   * {@inheritdoc}
113
   */
114
  public function reset($type = NULL) {
115
    return $this;
116
  }
117

118 119 120 121
  /**
   * {@inheritdoc}
   */
  public function getDefaultLanguage() {
122
    return $this->defaultLanguage->get();
123 124
  }

125
  /**
126
   * {@inheritdoc}
127
   */
128
  public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) {
129 130 131 132 133
    $static_cache_id = $this->getCurrentLanguage()->getId();
    if (!isset($this->languages[$static_cache_id][$flags])) {
      // If this language manager is used, there are no configured languages.
      // The default language and locked languages comprise the full language
      // list.
134
      $default = $this->getDefaultLanguage();
135 136
      $languages = array($default->getId() => $default);
      $languages += $this->getDefaultLockedLanguages($default->getWeight());
137

138 139
      // Filter the full list of languages based on the value of $flags.
      $this->languages[$static_cache_id][$flags] = $this->filterLanguages($languages, $flags);
140
    }
141
    return $this->languages[$static_cache_id][$flags];
142
  }
143

144 145 146 147 148 149 150 151
  /**
   * {@inheritdoc}
   */
  public function getNativeLanguages() {
    // In a language unaware site we don't have translated languages.
    return $this->getLanguages();
  }

152
  /**
153
   * {@inheritdoc}
154
   */
155
  public function getLanguage($langcode) {
156
    $languages = $this->getLanguages(LanguageInterface::STATE_ALL);
157
    return isset($languages[$langcode]) ? $languages[$langcode] : NULL;
158 159
  }

160
  /**
161
   * {@inheritdoc}
162
   */
163
  public function getLanguageName($langcode) {
164
    if ($langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) {
165
      return new TranslatableMarkup('None');
166 167
    }
    if ($language = $this->getLanguage($langcode)) {
168
      return $language->getName();
169
    }
170
    if (empty($langcode)) {
171
      return new TranslatableMarkup('Unknown');
172
    }
173
    return new TranslatableMarkup('Unknown (@langcode)', array('@langcode' => $langcode));
174 175 176 177 178 179 180 181 182 183 184
  }

  /**
   * {@inheritdoc}
   */
  public function getDefaultLockedLanguages($weight = 0) {
    $languages = array();

    $locked_language = array(
      'default' => FALSE,
      'locked' => TRUE,
185
      'direction' => LanguageInterface::DIRECTION_LTR,
186
    );
187
    // This is called very early while initializing the language system. Prevent
188
    // early t() calls by using the TranslatableMarkup.
189 190
    $languages[LanguageInterface::LANGCODE_NOT_SPECIFIED] = new Language(array(
      'id' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
191
      'name' => new TranslatableMarkup('Not specified'),
192 193 194
      'weight' => ++$weight,
    ) + $locked_language);

195 196
    $languages[LanguageInterface::LANGCODE_NOT_APPLICABLE] = new Language(array(
      'id' => LanguageInterface::LANGCODE_NOT_APPLICABLE,
197
      'name' => new TranslatableMarkup('Not applicable'),
198 199 200 201 202
      'weight' => ++$weight,
    ) + $locked_language);

    return $languages;
  }
203

204 205 206 207 208
  /**
   * {@inheritdoc}
   */
  public function isLanguageLocked($langcode) {
    $language = $this->getLanguage($langcode);
209
    return ($language ? $language->isLocked() : FALSE);
210 211
  }

212
  /**
213
   * {@inheritdoc}
214
   */
215
  public function getFallbackCandidates(array $context = array()) {
216
    return array(LanguageInterface::LANGCODE_DEFAULT);
217 218 219
  }

  /**
220
   * {@inheritdoc}
221
   */
222
  public function getLanguageSwitchLinks($type, Url $url) {
223
    return array();
224 225
  }

226
  /**
227
   * {@inheritdoc}
228 229
   */
  public static function getStandardLanguageList() {
230 231 232 233 234 235
    // This list is based on languages available from localize.drupal.org. See
    // http://localize.drupal.org/issues for information on how to add languages
    // there.
    //
    // The "Left-to-right marker" comments and the enclosed UTF-8 markers are to
    // make otherwise strange looking PHP syntax natural (to not be displayed in
236
    // right to left). See https://www.drupal.org/node/128866#comment-528929.
237 238 239
    return array(
      'af' => array('Afrikaans', 'Afrikaans'),
      'am' => array('Amharic', 'አማርኛ'),
240
      'ar' => array('Arabic', /* Left-to-right marker "‭" */ 'العربية', LanguageInterface::DIRECTION_RTL),
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
      'ast' => array('Asturian', 'Asturianu'),
      'az' => array('Azerbaijani', 'Azərbaycanca'),
      'be' => array('Belarusian', 'Беларуская'),
      'bg' => array('Bulgarian', 'Български'),
      'bn' => array('Bengali', 'বাংলা'),
      'bo' => array('Tibetan', 'བོད་སྐད་'),
      'bs' => array('Bosnian', 'Bosanski'),
      'ca' => array('Catalan', 'Català'),
      'cs' => array('Czech', 'Čeština'),
      'cy' => array('Welsh', 'Cymraeg'),
      'da' => array('Danish', 'Dansk'),
      'de' => array('German', 'Deutsch'),
      'dz' => array('Dzongkha', 'རྫོང་ཁ'),
      'el' => array('Greek', 'Ελληνικά'),
      'en' => array('English', 'English'),
      'eo' => array('Esperanto', 'Esperanto'),
      'es' => array('Spanish', 'Español'),
      'et' => array('Estonian', 'Eesti'),
      'eu' => array('Basque', 'Euskera'),
260
      'fa' => array('Persian, Farsi', /* Left-to-right marker "‭" */ 'فارسی', LanguageInterface::DIRECTION_RTL),
261 262 263 264
      'fi' => array('Finnish', 'Suomi'),
      'fil' => array('Filipino', 'Filipino'),
      'fo' => array('Faeroese', 'Føroyskt'),
      'fr' => array('French', 'Français'),
265 266
      'fy' => array('Frisian, Western', 'Frysk'),
      'ga' => array('Irish', 'Gaeilge'),
267 268 269 270
      'gd' => array('Scots Gaelic', 'Gàidhlig'),
      'gl' => array('Galician', 'Galego'),
      'gsw-berne' => array('Swiss German', 'Schwyzerdütsch'),
      'gu' => array('Gujarati', 'ગુજરાતી'),
271
      'he' => array('Hebrew', /* Left-to-right marker "‭" */ 'עברית', LanguageInterface::DIRECTION_RTL),
272 273 274 275
      'hi' => array('Hindi', 'हिन्दी'),
      'hr' => array('Croatian', 'Hrvatski'),
      'ht' => array('Haitian Creole', 'Kreyòl ayisyen'),
      'hu' => array('Hungarian', 'Magyar'),
276
      'hy' => array('Armenian', 'Հայերեն'),
277 278 279 280 281 282 283
      'id' => array('Indonesian', 'Bahasa Indonesia'),
      'is' => array('Icelandic', 'Íslenska'),
      'it' => array('Italian', 'Italiano'),
      'ja' => array('Japanese', '日本語'),
      'jv' => array('Javanese', 'Basa Java'),
      'ka' => array('Georgian', 'ქართული ენა'),
      'kk' => array('Kazakh', 'Қазақ'),
284
      'km' => array('Khmer', 'ភាសាខ្មែរ'),
285 286 287 288 289 290 291 292 293 294 295 296
      'kn' => array('Kannada', 'ಕನ್ನಡ'),
      'ko' => array('Korean', '한국어'),
      'ku' => array('Kurdish', 'Kurdî'),
      'ky' => array('Kyrgyz', 'Кыргызча'),
      'lo' => array('Lao', 'ພາສາລາວ'),
      'lt' => array('Lithuanian', 'Lietuvių'),
      'lv' => array('Latvian', 'Latviešu'),
      'mg' => array('Malagasy', 'Malagasy'),
      'mk' => array('Macedonian', 'Македонски'),
      'ml' => array('Malayalam', 'മലയാളം'),
      'mn' => array('Mongolian', 'монгол'),
      'mr' => array('Marathi', 'मराठी'),
297
      'ms' => array('Bahasa Malaysia', 'بهاس ملايو'),
298 299 300
      'my' => array('Burmese', 'ဗမာစကား'),
      'ne' => array('Nepali', 'नेपाली'),
      'nl' => array('Dutch', 'Nederlands'),
301 302
      'nb' => array('Norwegian Bokmål', 'Norsk, bokmål'),
      'nn' => array('Norwegian Nynorsk', 'Norsk, nynorsk'),
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
      'oc' => array('Occitan', 'Occitan'),
      'pa' => array('Punjabi', 'ਪੰਜਾਬੀ'),
      'pl' => array('Polish', 'Polski'),
      'pt-pt' => array('Portuguese, Portugal', 'Português, Portugal'),
      'pt-br' => array('Portuguese, Brazil', 'Português, Brasil'),
      'ro' => array('Romanian', 'Română'),
      'ru' => array('Russian', 'Русский'),
      'sco' => array('Scots', 'Scots'),
      'se' => array('Northern Sami', 'Sámi'),
      'si' => array('Sinhala', 'සිංහල'),
      'sk' => array('Slovak', 'Slovenčina'),
      'sl' => array('Slovenian', 'Slovenščina'),
      'sq' => array('Albanian', 'Shqip'),
      'sr' => array('Serbian', 'Српски'),
      'sv' => array('Swedish', 'Svenska'),
318
      'sw' => array('Swahili', 'Kiswahili'),
319 320 321 322 323 324 325 326
      'ta' => array('Tamil', 'தமிழ்'),
      'ta-lk' => array('Tamil, Sri Lanka', 'தமிழ், இலங்கை'),
      'te' => array('Telugu', 'తెలుగు'),
      'th' => array('Thai', 'ภาษาไทย'),
      'tr' => array('Turkish', 'Türkçe'),
      'tyv' => array('Tuvan', 'Тыва дыл'),
      'ug' => array('Uyghur', 'Уйғур'),
      'uk' => array('Ukrainian', 'Українська'),
327
      'ur' => array('Urdu', /* Left-to-right marker "‭" */ 'اردو', LanguageInterface::DIRECTION_RTL),
328 329 330 331 332 333 334
      'vi' => array('Vietnamese', 'Tiếng Việt'),
      'xx-lolspeak' => array('Lolspeak', 'Lolspeak'),
      'zh-hans' => array('Chinese, Simplified', '简体中文'),
      'zh-hant' => array('Chinese, Traditional', '繁體中文'),
    );
  }

335 336 337
  /**
   * {@inheritdoc}
   *
338
   * This function is a noop since the configuration cannot be overridden by
339
   * language unless the Language module is enabled. That replaces the default
340
   * language manager with a configurable language manager.
341 342 343
   *
   * @see \Drupal\language\ConfigurableLanguageManager::setConfigOverrideLanguage()
   */
344
  public function setConfigOverrideLanguage(LanguageInterface $language = NULL) {
345 346 347 348 349 350 351 352 353 354
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getConfigOverrideLanguage() {
    return $this->getCurrentLanguage();
  }

355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
  /**
   * Filters the full list of languages based on the value of the flag.
   *
   * The locked languages are removed by default.
   *
   * @param \Drupal\Core\Language\LanguageInterface[] $languages
   *    Array with languages to be filtered.
   * @param int $flags
   *   (optional) Specifies the state of the languages that have to be returned.
   *   It can be: LanguageInterface::STATE_CONFIGURABLE,
   *   LanguageInterface::STATE_LOCKED, or LanguageInterface::STATE_ALL.
   *
   * @return \Drupal\Core\Language\LanguageInterface[]
   *   An associative array of languages, keyed by the language code.
   */
  protected function filterLanguages(array $languages, $flags = LanguageInterface::STATE_CONFIGURABLE) {
    // STATE_ALL means we don't actually filter, so skip the rest of the method.
    if ($flags == LanguageInterface::STATE_ALL) {
      return $languages;
    }

    $filtered_languages = array();
    // Add the site's default language if requested.
    if ($flags & LanguageInterface::STATE_SITE_DEFAULT) {
379 380 381 382 383 384 385

      // Setup a language to have the defaults with data appropriate of the
      // default language only for runtime.
      $defaultLanguage = $this->getDefaultLanguage();
      $default = new Language(
        array(
          'id' => $defaultLanguage->getId(),
386
          'name' => new TranslatableMarkup("Site's default language (@lang_name)",
387 388 389 390 391
            array('@lang_name' => $defaultLanguage->getName())),
          'direction' => $defaultLanguage->getDirection(),
          'weight' => $defaultLanguage->getWeight(),
        )
      );
392 393 394 395 396 397 398 399 400 401 402 403
      $filtered_languages[LanguageInterface::LANGCODE_SITE_DEFAULT] = $default;
    }

    foreach ($languages as $id => $language) {
      if (($language->isLocked() && ($flags & LanguageInterface::STATE_LOCKED)) || (!$language->isLocked() && ($flags & LanguageInterface::STATE_CONFIGURABLE))) {
        $filtered_languages[$id] = $language;
      }
    }

    return $filtered_languages;
  }

Crell's avatar
Crell committed
404
}