1<?php
2
3namespace Drupal\Core\Language;
4
5use Drupal\Core\StringTranslation\TranslatableMarkup;
6
7/**
8 * An object containing the information for an interface language.
9 *
10 * @see \Drupal\Core\Language\LanguageManager::getLanguage()
11 */
12class Language implements LanguageInterface {
13
14  /**
15   * The values to use to instantiate the default language.
16   *
17   * @var array
18   */
19  public static $defaultValues = [
20    'id' => 'en',
21    'name' => 'English',
22    'direction' => self::DIRECTION_LTR,
23    'weight' => 0,
24    'locked' => FALSE,
25  ];
26
27  // Properties within the Language are set up as the default language.
28
29  /**
30   * The human readable English name.
31   *
32   * @var string
33   */
34  protected $name = '';
35
36  /**
37   * The ID, langcode.
38   *
39   * @var string
40   */
41  protected $id = '';
42
43  /**
44   * The direction, left-to-right, or right-to-left.
45   *
46   * Defined using constants, either self::DIRECTION_LTR or self::DIRECTION_RTL.
47   *
48   * @var int
49   */
50  protected $direction = self::DIRECTION_LTR;
51
52  /**
53   * The weight, used for ordering languages in lists, like selects or tables.
54   *
55   * @var int
56   */
57  protected $weight = 0;
58
59  /**
60   * Locked indicates a language used by the system, not an actual language.
61   *
62   * Examples of locked languages are, LANGCODE_NOT_SPECIFIED, und, and
63   * LANGCODE_NOT_APPLICABLE, zxx, which are usually shown in language selects
64   * but hidden in places like the Language configuration and cannot be deleted.
65   *
66   * @var bool
67   */
68  protected $locked = FALSE;
69
70  /**
71   * Constructs a new class instance.
72   *
73   * @param array $values
74   *   An array of property values, keyed by property name, used to construct
75   *   the language.
76   */
77  public function __construct(array $values = []) {
78    // Set all the provided properties for the language.
79    foreach ($values as $key => $value) {
80      if (property_exists($this, $key)) {
81        $this->{$key} = $value;
82      }
83    }
84    // If some values were not set, set sane defaults of a predefined language.
85    if (!isset($values['name']) || !isset($values['direction'])) {
86      $predefined = LanguageManager::getStandardLanguageList();
87      if (isset($predefined[$this->id])) {
88        if (!isset($values['name'])) {
89          $this->name = $predefined[$this->id][0];
90        }
91        if (!isset($values['direction']) && isset($predefined[$this->id][2])) {
92          $this->direction = $predefined[$this->id][2];
93        }
94      }
95    }
96  }
97
98  /**
99   * {@inheritdoc}
100   */
101  public function getName() {
102    return $this->name;
103  }
104
105  /**
106   * {@inheritdoc}
107   */
108  public function getId() {
109    return $this->id;
110  }
111
112  /**
113   * {@inheritdoc}
114   */
115  public function getDirection() {
116    return $this->direction;
117  }
118
119  /**
120   * {@inheritdoc}
121   */
122  public function getWeight() {
123    return $this->weight;
124  }
125
126  /**
127   * {@inheritdoc}
128   */
129  public function isDefault() {
130    return static::getDefaultLangcode() == $this->getId();
131  }
132
133  /**
134   * {@inheritdoc}
135   */
136  public function isLocked() {
137    return (bool) $this->locked;
138  }
139
140  /**
141   * Sort language objects.
142   *
143   * @param \Drupal\Core\Language\LanguageInterface[] $languages
144   *   The array of language objects keyed by langcode.
145   */
146  public static function sort(&$languages) {
147    uasort($languages, function (LanguageInterface $a, LanguageInterface $b) {
148      $a_weight = $a->getWeight();
149      $b_weight = $b->getWeight();
150      if ($a_weight == $b_weight) {
151        $a_name = $a->getName();
152        $b_name = $b->getName();
153        // If either name is a TranslatableMarkup object it can not be converted
154        // to a string. This is because translation requires a sorted list of
155        // languages thereby causing an infinite loop. Determine the order based
156        // on ID if this is the case.
157        if ($a_name instanceof TranslatableMarkup || $b_name instanceof TranslatableMarkup) {
158          $a_name = $a->getId();
159          $b_name = $b->getId();
160        }
161        return strnatcasecmp($a_name, $b_name);
162      }
163      return ($a_weight < $b_weight) ? -1 : 1;
164    });
165  }
166
167  /**
168   * Gets the default langcode.
169   *
170   * @return string
171   *   The current default langcode.
172   */
173  protected static function getDefaultLangcode() {
174    $language = \Drupal::service('language.default')->get();
175    return $language->getId();
176  }
177
178}
179