‪TYPO3CMS  11.5
LanguageService.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
24 
42 {
48  public ‪$lang = 'default';
49 
55  public ‪$debugKey = false;
56 
63  protected ‪$languageDependencies = [];
64 
68  protected ‪$labels = [];
69 
70  protected ‪Locales ‪$locales;
73 
78  {
79  $this->locales = ‪$locales;
80  $this->localizationFactory = ‪$localizationFactory;
81  $this->runtimeCache = ‪$runtimeCache;
82  $this->debugKey = (bool)‪$GLOBALS['TYPO3_CONF_VARS']['BE']['languageDebug'];
83  }
84 
93  public function ‪init($languageKey)
94  {
95  // Find the requested language in this list based on the $languageKey
96  // Language is found. Configure it:
97  if (in_array($languageKey, $this->locales->getLocales(), true)) {
98  // The current language key
99  $this->lang = $languageKey;
100  $this->languageDependencies[] = $languageKey;
101  foreach ($this->locales->getLocaleDependencies($languageKey) as $language) {
102  $this->languageDependencies[] = $language;
103  }
104  }
105  }
106 
113  protected function ‪debugLL($value)
114  {
115  return $this->debugKey ? '[' . $value . ']' : '';
116  }
117 
125  public function ‪getLL($index)
126  {
127  return $this->‪getLLL($index, $this->labels);
128  }
129 
137  protected function ‪getLLL($index, $localLanguage)
138  {
139  // Get Local Language. Special handling for all extensions that
140  // read PHP LL files and pass arrays here directly.
141  if (isset($localLanguage[$this->lang][$index])) {
142  $value = is_string($localLanguage[$this->lang][$index])
143  ? $localLanguage[‪$this->lang][$index]
144  : $localLanguage[‪$this->lang][$index][0]['target'];
145  } elseif (isset($localLanguage['default'][$index])) {
146  $value = is_string($localLanguage['default'][$index])
147  ? $localLanguage['default'][$index]
148  : $localLanguage['default'][$index][0]['target'];
149  } else {
150  $value = '';
151  }
152  return $value . $this->‪debugLL($index);
153  }
154 
165  public function ‪sL($input): string
166  {
167  $input = (string)$input;
168  // early return for empty input to avoid cache and language file reading on first hit.
169  if ($input === '') {
170  return $input;
171  }
172  $cacheIdentifier = 'labels_' . $this->lang . '_' . md5($input . '_' . (int)$this->debugKey);
173  $cacheEntry = $this->runtimeCache->get($cacheIdentifier);
174  if ($cacheEntry !== false) {
175  return $cacheEntry;
176  }
177  if (strpos(trim($input), 'LLL:') === 0) {
178  $restStr = substr(trim($input), 4);
179  $extPrfx = '';
180  // ll-file referred to is found in an extension.
181  if (‪PathUtility::isExtensionPath(trim($restStr))) {
182  $restStr = substr(trim($restStr), 4);
183  $extPrfx = 'EXT:';
184  }
185  $parts = explode(':', trim($restStr));
186  $parts[0] = $extPrfx . $parts[0];
187  ‪$output = $this->‪getLLL($parts[1] ?? '', $this->‪readLLfile($parts[0]));
188  } else {
189  // Use a constant non-localizable label
190  ‪$output = $input;
191  }
192  ‪$output .= $this->‪debugLL($input);
193  $this->runtimeCache->set($cacheIdentifier, ‪$output);
194  return ‪$output;
195  }
196 
205  public function ‪loadSingleTableDescription($table)
206  {
207  // First the 'table' cannot already be loaded in [columns]
208  // and secondly there must be a references to locallang files available in [refs]
209  if (is_array(‪$GLOBALS['TCA_DESCR'][$table] ?? null)
210  && !isset(‪$GLOBALS['TCA_DESCR'][$table]['columns'])
211  && is_array(‪$GLOBALS['TCA_DESCR'][$table]['refs'] ?? null)) {
212  // Init $TCA_DESCR for $table-key
213  ‪$GLOBALS['TCA_DESCR'][$table]['columns'] = [];
214  // Get local-lang for each file in $TCA_DESCR[$table]['refs'] as they are ordered.
215  foreach (‪$GLOBALS['TCA_DESCR'][$table]['refs'] as $llfile) {
216  $localLanguage = $this->‪includeLanguageFileRaw($llfile);
217  // Traverse all keys
218  if (is_array($localLanguage['default'])) {
219  foreach ($localLanguage['default'] as $lkey => $lVal) {
220  // Exploding by '.':
221  // 0-n => fieldname,
222  // n+1 => type from (alttitle, description, details, syntax, image_descr,image,seeAlso),
223  // n+2 => special instruction, if any
224  $keyParts = explode('.', $lkey);
225  $keyPartsCount = count($keyParts);
226  // Check if last part is special instruction
227  // Only "+" is currently supported
228  $specialInstruction = $keyParts[$keyPartsCount - 1] === '+';
229  if ($specialInstruction) {
230  array_pop($keyParts);
231  }
232  // If there are more than 2 parts, get the type from the last part
233  // and merge back the other parts with a dot (.)
234  // Otherwise just get type and field name straightaway
235  if ($keyPartsCount > 2) {
236  $type = array_pop($keyParts);
237  $fieldName = implode('.', $keyParts);
238  } else {
239  $fieldName = $keyParts[0];
240  // not having the second part is an error in the xliff file, but we should avoid
241  // undefined array key access warning for PHP8.0+ anyway.
242  $type = $keyParts[1] ?? '';
243  }
244  // Detecting 'hidden' labels, converting to normal fieldname
245  if ($fieldName === '_') {
246  $fieldName = '';
247  }
248  if ($fieldName !== '' && $fieldName[0] === '_') {
249  $fieldName = substr($fieldName, 1);
250  }
251  // Append label
252  $label = $lVal[0]['target'] ?: $lVal[0]['source'];
253  if (!isset(‪$GLOBALS['TCA_DESCR'][$table]['columns'][$fieldName])) {
254  ‪$GLOBALS['TCA_DESCR'][$table]['columns'][$fieldName] = [$type => ''];
255  }
256  if ($specialInstruction) {
257  ‪$GLOBALS['TCA_DESCR'][$table]['columns'][$fieldName][$type] .= LF . $label;
258  } else {
259  // Substitute label
260  ‪$GLOBALS['TCA_DESCR'][$table]['columns'][$fieldName][$type] = $label;
261  }
262  }
263  }
264  }
265  }
266  }
267 
275  public function ‪includeLLFile($fileRef)
276  {
277  $localLanguage = $this->‪readLLfile($fileRef);
278  if (!empty($localLanguage)) {
279  $this->labels = array_replace_recursive($this->labels, $localLanguage);
280  }
281  return $localLanguage;
282  }
283 
291  protected function ‪includeLanguageFileRaw($fileRef)
292  {
293  ‪$labels = $this->‪readLLfile($fileRef);
294  if (!empty(‪$labels)) {
295  // Merge local onto default
296  if ($this->lang !== 'default' && is_array(‪$labels[$this->lang]) && is_array(‪$labels['default'])) {
297  // array_merge can be used so far the keys are not
298  // numeric - which we assume they are not...
299  ‪$labels['default'] = array_merge(‪$labels['default'], ‪$labels[$this->lang]);
300  unset(‪$labels[$this->lang]);
301  }
302  }
303  return ‪$labels;
304  }
305 
312  protected function ‪readLLfile($fileRef): array
313  {
314  $cacheIdentifier = 'labels_file_' . md5($fileRef . $this->lang);
315  $cacheEntry = $this->runtimeCache->get($cacheIdentifier);
316  if (is_array($cacheEntry)) {
317  return $cacheEntry;
318  }
319 
320  if ($this->lang !== 'default') {
321  $languages = array_reverse($this->languageDependencies);
322  } else {
323  $languages = ['default'];
324  }
325  $localLanguage = [];
326  foreach ($languages as $language) {
327  $tempLL = $this->localizationFactory->getParsedData($fileRef, $language);
328  $localLanguage['default'] = $tempLL['default'];
329  if (!isset($localLanguage[$this->lang])) {
330  $localLanguage[‪$this->lang] = $localLanguage['default'];
331  }
332  if ($this->lang !== 'default' && isset($tempLL[$language])) {
333  // Merge current language labels onto labels from previous language
334  // This way we have a labels with fall back applied
335  ‪ArrayUtility::mergeRecursiveWithOverrule($localLanguage[$this->lang], $tempLL[$language], true, false);
336  }
337  }
338 
339  $this->runtimeCache->set($cacheIdentifier, $localLanguage);
340  return $localLanguage;
341  }
342 
350  public static function ‪create(string $locale): self
351  {
352  trigger_error('Method ' . __METHOD__ . ' is deprecated and will be removed in TYPO3 12.0 Use LanguageServiceFactory instead.', E_USER_DEPRECATED);
353  return GeneralUtility::makeInstance(LanguageServiceFactory::class)->create($locale);
354  }
355 
359  public static function ‪createFromUserPreferences(?‪AbstractUserAuthentication $user): self
360  {
361  trigger_error('Method ' . __METHOD__ . ' is deprecated and will be removed in TYPO3 12.0 Use LanguageServiceFactory instead.', E_USER_DEPRECATED);
362  return GeneralUtility::makeInstance(LanguageServiceFactory::class)->createFromUserPreferences($user);
363  }
364 
368  public static function ‪createFromSiteLanguage(‪SiteLanguage $language): self
369  {
370  trigger_error('Method ' . __METHOD__ . ' is deprecated and will be removed in TYPO3 12.0 Use LanguageServiceFactory instead.', E_USER_DEPRECATED);
371  return GeneralUtility::makeInstance(LanguageServiceFactory::class)->createFromSiteLanguage($language);
372  }
373 }
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:25
‪TYPO3\CMS\Core\Localization\LanguageService\$lang
‪string $lang
Definition: LanguageService.php:47
‪TYPO3\CMS\Core\Localization\LocalizationFactory
Definition: LocalizationFactory.php:31
‪TYPO3\CMS\Core\Utility\PathUtility\isExtensionPath
‪static bool isExtensionPath(string $path)
Definition: PathUtility.php:121
‪TYPO3\CMS\Core\Localization\LanguageService\$localizationFactory
‪LocalizationFactory $localizationFactory
Definition: LanguageService.php:67
‪TYPO3\CMS\Core\Localization\LanguageService\$labels
‪string[][] $labels
Definition: LanguageService.php:64
‪TYPO3\CMS\Core\Localization\Locales
Definition: Locales.php:30
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:654
‪TYPO3\CMS\Core\Localization\LanguageService\readLLfile
‪array readLLfile($fileRef)
Definition: LanguageService.php:308
‪TYPO3\CMS\Core\Localization\LanguageService\sL
‪string sL($input)
Definition: LanguageService.php:161
‪TYPO3\CMS\Core\Localization
Definition: CacheWarmer.php:18
‪TYPO3\CMS\Core\Localization\LanguageService\loadSingleTableDescription
‪loadSingleTableDescription($table)
Definition: LanguageService.php:201
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:26
‪TYPO3\CMS\Core\Localization\LanguageService\createFromUserPreferences
‪static createFromUserPreferences(?AbstractUserAuthentication $user)
Definition: LanguageService.php:355
‪TYPO3\CMS\Core\Localization\LanguageService\$runtimeCache
‪FrontendInterface $runtimeCache
Definition: LanguageService.php:68
‪TYPO3\CMS\Core\Localization\LanguageService\$debugKey
‪bool $debugKey
Definition: LanguageService.php:53
‪TYPO3\CMS\Core\Localization\LanguageService\getLLL
‪string getLLL($index, $localLanguage)
Definition: LanguageService.php:133
‪TYPO3\CMS\Core\Localization\LanguageService\init
‪init($languageKey)
Definition: LanguageService.php:89
‪TYPO3\CMS\Core\Localization\LanguageService\debugLL
‪string debugLL($value)
Definition: LanguageService.php:109
‪TYPO3\CMS\Core\Localization\LanguageService\createFromSiteLanguage
‪static createFromSiteLanguage(SiteLanguage $language)
Definition: LanguageService.php:364
‪TYPO3\CMS\Core\Localization\LanguageService\__construct
‪__construct(Locales $locales, LocalizationFactory $localizationFactory, FrontendInterface $runtimeCache)
Definition: LanguageService.php:73
‪TYPO3\CMS\Core\Localization\LanguageService\includeLanguageFileRaw
‪array includeLanguageFileRaw($fileRef)
Definition: LanguageService.php:287
‪$output
‪$output
Definition: annotationChecker.php:122
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Localization\LanguageService\includeLLFile
‪array includeLLFile($fileRef)
Definition: LanguageService.php:271
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Localization\LanguageService\$locales
‪Locales $locales
Definition: LanguageService.php:66
‪TYPO3\CMS\Core\Localization\LanguageService\$languageDependencies
‪array $languageDependencies
Definition: LanguageService.php:60
‪TYPO3\CMS\Core\Localization\LanguageService\getLL
‪string getLL($index)
Definition: LanguageService.php:121
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Authentication\AbstractUserAuthentication
Definition: AbstractUserAuthentication.php:56
‪TYPO3\CMS\Core\Localization\LanguageService\create
‪static static create(string $locale)
Definition: LanguageService.php:346