3 namespace Drupal\Core\Language;
5 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
6 use Drupal\Core\StringTranslation\TranslatableMarkup;
10 * Class responsible for providing language support on language-unaware sites.
12 class LanguageManager implements LanguageManagerInterface {
13 use DependencySerializationTrait;
16 * A static cache of translated language lists.
18 * Array of arrays to cache the result of self::getLanguages() keyed by the
19 * language the list is translated to (first level) and the flags provided to
20 * the method (second level).
22 * @var \Drupal\Core\Language\LanguageInterface[]
24 * @see \Drupal\Core\Language\LanguageManager::getLanguages()
26 protected $languages = [];
29 * The default language object.
31 * @var \Drupal\Core\Language\LanguageDefault
33 protected $defaultLanguage;
36 * Constructs the language manager.
38 * @param \Drupal\Core\Language\LanguageDefault $default_language
39 * The default language.
41 public function __construct(LanguageDefault $default_language) {
42 $this->defaultLanguage = $default_language;
48 public function isMultilingual() {
55 public function getLanguageTypes() {
56 return [LanguageInterface::TYPE_INTERFACE, LanguageInterface::TYPE_CONTENT, LanguageInterface::TYPE_URL];
60 * Returns information about all defined language types.
62 * Defines the three core language types:
63 * - Interface language is the only configurable language type in core. It is
64 * used by t() as the default language if none is specified.
65 * - Content language is by default non-configurable and inherits the
66 * interface language negotiated value. It is used by the Field API to
67 * determine the display language for fields if no explicit value is
69 * - URL language is by default non-configurable and is determined through the
70 * URL language negotiation method or the URL fallback language negotiation
71 * method if no language can be detected. It is used by l() as the default
72 * language if none is specified.
75 * An associative array of language type information arrays keyed by
76 * language type machine name, in the format of
77 * hook_language_types_info().
79 public function getDefinedLanguageTypesInfo() {
80 $this->definedLanguageTypesInfo = [
81 LanguageInterface::TYPE_INTERFACE => [
82 'name' => new TranslatableMarkup('Interface text'),
83 '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.'),
86 LanguageInterface::TYPE_CONTENT => [
87 'name' => new TranslatableMarkup('Content'),
88 '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.'),
91 LanguageInterface::TYPE_URL => [
96 return $this->definedLanguageTypesInfo;
102 public function getCurrentLanguage($type = LanguageInterface::TYPE_INTERFACE) {
103 return $this->getDefaultLanguage();
109 public function reset($type = NULL) {
116 public function getDefaultLanguage() {
117 return $this->defaultLanguage->get();
123 public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) {
124 $static_cache_id = $this->getCurrentLanguage()->getId();
125 if (!isset($this->languages[$static_cache_id][$flags])) {
126 // If this language manager is used, there are no configured languages.
127 // The default language and locked languages comprise the full language
129 $default = $this->getDefaultLanguage();
130 $languages = [$default->getId() => $default];
131 $languages += $this->getDefaultLockedLanguages($default->getWeight());
133 // Filter the full list of languages based on the value of $flags.
134 $this->languages[$static_cache_id][$flags] = $this->filterLanguages($languages, $flags);
136 return $this->languages[$static_cache_id][$flags];
142 public function getNativeLanguages() {
143 // In a language unaware site we don't have translated languages.
144 return $this->getLanguages();
150 public function getLanguage($langcode) {
151 $languages = $this->getLanguages(LanguageInterface::STATE_ALL);
152 return isset($languages[$langcode]) ? $languages[$langcode] : NULL;
158 public function getLanguageName($langcode) {
159 if ($langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) {
160 return new TranslatableMarkup('None');
162 if ($language = $this->getLanguage($langcode)) {
163 return $language->getName();
165 if (empty($langcode)) {
166 return new TranslatableMarkup('Unknown');
168 return new TranslatableMarkup('Unknown (@langcode)', ['@langcode' => $langcode]);
174 public function getDefaultLockedLanguages($weight = 0) {
180 'direction' => LanguageInterface::DIRECTION_LTR,
182 // This is called very early while initializing the language system. Prevent
183 // early t() calls by using the TranslatableMarkup.
184 $languages[LanguageInterface::LANGCODE_NOT_SPECIFIED] = new Language([
185 'id' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
186 'name' => new TranslatableMarkup('Not specified'),
187 'weight' => ++$weight,
188 ] + $locked_language);
190 $languages[LanguageInterface::LANGCODE_NOT_APPLICABLE] = new Language([
191 'id' => LanguageInterface::LANGCODE_NOT_APPLICABLE,
192 'name' => new TranslatableMarkup('Not applicable'),
193 'weight' => ++$weight,
194 ] + $locked_language);
202 public function isLanguageLocked($langcode) {
203 $language = $this->getLanguage($langcode);
204 return ($language ? $language->isLocked() : FALSE);
210 public function getFallbackCandidates(array $context = []) {
211 return [LanguageInterface::LANGCODE_DEFAULT];
217 public function getLanguageSwitchLinks($type, Url $url) {
224 public static function getStandardLanguageList() {
225 // This list is based on languages available from localize.drupal.org. See
226 // http://localize.drupal.org/issues for information on how to add languages
229 // The "Left-to-right marker" comments and the enclosed UTF-8 markers are to
230 // make otherwise strange looking PHP syntax natural (to not be displayed in
231 // right to left). See https://www.drupal.org/node/128866#comment-528929.
233 'af' => ['Afrikaans', 'Afrikaans'],
234 'am' => ['Amharic', 'አማርኛ'],
235 'ar' => ['Arabic', /* Left-to-right marker "" */ 'العربية', LanguageInterface::DIRECTION_RTL],
236 'ast' => ['Asturian', 'Asturianu'],
237 'az' => ['Azerbaijani', 'Azərbaycanca'],
238 'be' => ['Belarusian', 'Беларуская'],
239 'bg' => ['Bulgarian', 'Български'],
240 'bn' => ['Bengali', 'বাংলা'],
241 'bo' => ['Tibetan', 'བོད་སྐད་'],
242 'bs' => ['Bosnian', 'Bosanski'],
243 'ca' => ['Catalan', 'Català'],
244 'cs' => ['Czech', 'Čeština'],
245 'cy' => ['Welsh', 'Cymraeg'],
246 'da' => ['Danish', 'Dansk'],
247 'de' => ['German', 'Deutsch'],
248 'dz' => ['Dzongkha', 'རྫོང་ཁ'],
249 'el' => ['Greek', 'Ελληνικά'],
250 'en' => ['English', 'English'],
251 'en-x-simple' => ['Simple English', 'Simple English'],
252 'eo' => ['Esperanto', 'Esperanto'],
253 'es' => ['Spanish', 'Español'],
254 'et' => ['Estonian', 'Eesti'],
255 'eu' => ['Basque', 'Euskera'],
256 'fa' => ['Persian, Farsi', /* Left-to-right marker "" */ 'فارسی', LanguageInterface::DIRECTION_RTL],
257 'fi' => ['Finnish', 'Suomi'],
258 'fil' => ['Filipino', 'Filipino'],
259 'fo' => ['Faeroese', 'Føroyskt'],
260 'fr' => ['French', 'Français'],
261 'fy' => ['Frisian, Western', 'Frysk'],
262 'ga' => ['Irish', 'Gaeilge'],
263 'gd' => ['Scots Gaelic', 'Gàidhlig'],
264 'gl' => ['Galician', 'Galego'],
265 'gsw-berne' => ['Swiss German', 'Schwyzerdütsch'],
266 'gu' => ['Gujarati', 'ગુજરાતી'],
267 'he' => ['Hebrew', /* Left-to-right marker "" */ 'עברית', LanguageInterface::DIRECTION_RTL],
268 'hi' => ['Hindi', 'हिन्दी'],
269 'hr' => ['Croatian', 'Hrvatski'],
270 'ht' => ['Haitian Creole', 'Kreyòl ayisyen'],
271 'hu' => ['Hungarian', 'Magyar'],
272 'hy' => ['Armenian', 'Հայերեն'],
273 'id' => ['Indonesian', 'Bahasa Indonesia'],
274 'is' => ['Icelandic', 'Íslenska'],
275 'it' => ['Italian', 'Italiano'],
276 'ja' => ['Japanese', '日本語'],
277 'jv' => ['Javanese', 'Basa Java'],
278 'ka' => ['Georgian', 'ქართული ენა'],
279 'kk' => ['Kazakh', 'Қазақ'],
280 'km' => ['Khmer', 'ភាសាខ្មែរ'],
281 'kn' => ['Kannada', 'ಕನ್ನಡ'],
282 'ko' => ['Korean', '한국어'],
283 'ku' => ['Kurdish', 'Kurdî'],
284 'ky' => ['Kyrgyz', 'Кыргызча'],
285 'lo' => ['Lao', 'ພາສາລາວ'],
286 'lt' => ['Lithuanian', 'Lietuvių'],
287 'lv' => ['Latvian', 'Latviešu'],
288 'mg' => ['Malagasy', 'Malagasy'],
289 'mk' => ['Macedonian', 'Македонски'],
290 'ml' => ['Malayalam', 'മലയാളം'],
291 'mn' => ['Mongolian', 'монгол'],
292 'mr' => ['Marathi', 'मराठी'],
293 'ms' => ['Bahasa Malaysia', 'بهاس ملايو'],
294 'my' => ['Burmese', 'ဗမာစကား'],
295 'ne' => ['Nepali', 'नेपाली'],
296 'nl' => ['Dutch', 'Nederlands'],
297 'nb' => ['Norwegian Bokmål', 'Norsk, bokmål'],
298 'nn' => ['Norwegian Nynorsk', 'Norsk, nynorsk'],
299 'oc' => ['Occitan', 'Occitan'],
300 'pa' => ['Punjabi', 'ਪੰਜਾਬੀ'],
301 'pl' => ['Polish', 'Polski'],
302 'pt-pt' => ['Portuguese, Portugal', 'Português, Portugal'],
303 'pt-br' => ['Portuguese, Brazil', 'Português, Brasil'],
304 'ro' => ['Romanian', 'Română'],
305 'ru' => ['Russian', 'Русский'],
306 'sco' => ['Scots', 'Scots'],
307 'se' => ['Northern Sami', 'Sámi'],
308 'si' => ['Sinhala', 'සිංහල'],
309 'sk' => ['Slovak', 'Slovenčina'],
310 'sl' => ['Slovenian', 'Slovenščina'],
311 'sq' => ['Albanian', 'Shqip'],
312 'sr' => ['Serbian', 'Српски'],
313 'sv' => ['Swedish', 'Svenska'],
314 'sw' => ['Swahili', 'Kiswahili'],
315 'ta' => ['Tamil', 'தமிழ்'],
316 'ta-lk' => ['Tamil, Sri Lanka', 'தமிழ், இலங்கை'],
317 'te' => ['Telugu', 'తెలుగు'],
318 'th' => ['Thai', 'ภาษาไทย'],
319 'tr' => ['Turkish', 'Türkçe'],
320 'tyv' => ['Tuvan', 'Тыва дыл'],
321 'ug' => ['Uyghur', /* Left-to-right marker "" */ 'ئۇيغۇرچە', LanguageInterface::DIRECTION_RTL],
322 'uk' => ['Ukrainian', 'Українська'],
323 'ur' => ['Urdu', /* Left-to-right marker "" */ 'اردو', LanguageInterface::DIRECTION_RTL],
324 'vi' => ['Vietnamese', 'Tiếng Việt'],
325 'xx-lolspeak' => ['Lolspeak', 'Lolspeak'],
326 'zh-hans' => ['Chinese, Simplified', '简体中文'],
327 'zh-hant' => ['Chinese, Traditional', '繁體中文'],
332 * The 6 official languages used at the United Nations.
334 * This list is based on
335 * http://www.un.org/en/sections/about-un/official-languages/index.html and it
336 * uses the same format as getStandardLanguageList().
339 * An array with language codes as keys, and English and native language
342 public static function getUnitedNationsLanguageList() {
344 'ar' => ['Arabic', /* Left-to-right marker "" */ 'العربية', LanguageInterface::DIRECTION_RTL],
345 'zh-hans' => ['Chinese, Simplified', '简体中文'],
346 'en' => ['English', 'English'],
347 'fr' => ['French', 'Français'],
348 'ru' => ['Russian', 'Русский'],
349 'es' => ['Spanish', 'Español'],
356 * This function is a noop since the configuration cannot be overridden by
357 * language unless the Language module is enabled. That replaces the default
358 * language manager with a configurable language manager.
360 * @see \Drupal\language\ConfigurableLanguageManager::setConfigOverrideLanguage()
362 public function setConfigOverrideLanguage(LanguageInterface $language = NULL) {
369 public function getConfigOverrideLanguage() {
370 return $this->getCurrentLanguage();
374 * Filters the full list of languages based on the value of the flag.
376 * The locked languages are removed by default.
378 * @param \Drupal\Core\Language\LanguageInterface[] $languages
379 * Array with languages to be filtered.
381 * (optional) Specifies the state of the languages that have to be returned.
382 * It can be: LanguageInterface::STATE_CONFIGURABLE,
383 * LanguageInterface::STATE_LOCKED, or LanguageInterface::STATE_ALL.
385 * @return \Drupal\Core\Language\LanguageInterface[]
386 * An associative array of languages, keyed by the language code.
388 protected function filterLanguages(array $languages, $flags = LanguageInterface::STATE_CONFIGURABLE) {
389 // STATE_ALL means we don't actually filter, so skip the rest of the method.
390 if ($flags == LanguageInterface::STATE_ALL) {
394 $filtered_languages = [];
395 // Add the site's default language if requested.
396 if ($flags & LanguageInterface::STATE_SITE_DEFAULT) {
398 // Setup a language to have the defaults with data appropriate of the
399 // default language only for runtime.
400 $defaultLanguage = $this->getDefaultLanguage();
401 $default = new Language(
403 'id' => $defaultLanguage->getId(),
404 'name' => new TranslatableMarkup("Site's default language (@lang_name)",
405 ['@lang_name' => $defaultLanguage->getName()]),
406 'direction' => $defaultLanguage->getDirection(),
407 'weight' => $defaultLanguage->getWeight(),
410 $filtered_languages[LanguageInterface::LANGCODE_SITE_DEFAULT] = $default;
413 foreach ($languages as $id => $language) {
414 if (($language->isLocked() && ($flags & LanguageInterface::STATE_LOCKED)) || (!$language->isLocked() && ($flags & LanguageInterface::STATE_CONFIGURABLE))) {
415 $filtered_languages[$id] = $language;
419 return $filtered_languages;