TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
form/Classes/Service/TranslationService.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types=1);
3 namespace TYPO3\CMS\Form\Service;
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
30 
40 {
41 
47  protected $LOCAL_LANG = [];
48 
57  protected $LOCAL_LANG_UNSET = [];
58 
64  protected $languageKey = null;
65 
71  protected $alternativeLanguageKeys = [];
72 
76  protected $configurationManager = null;
77 
84  public static function getInstance()
85  {
86  return GeneralUtility::makeInstance(ObjectManager::class)->get(self::class);
87  }
88 
100  public function translate(
101  $key,
102  array $arguments = null,
103  string $locallangPathAndFilename = null,
104  string $language = null,
105  $defaultValue = ''
106  ) {
107  $value = null;
108  $key = (string)$key;
109 
110  if ($locallangPathAndFilename) {
111  $key = $locallangPathAndFilename . ':' . $key;
112  }
113 
114  $keyParts = explode(':', $key);
115  if (GeneralUtility::isFirstPartOfStr($key, 'LLL:')) {
116  $locallangPathAndFilename = $keyParts[1] . ':' . $keyParts[2];
117  $key = $keyParts[3];
118  } elseif (GeneralUtility::isFirstPartOfStr($key, 'EXT:')) {
119  $locallangPathAndFilename = $keyParts[0] . ':' . $keyParts[1];
120  $key = $keyParts[2];
121  } else {
122  if (count($keyParts) === 2) {
123  $locallangPathAndFilename = $keyParts[0];
124  $key = $keyParts[1];
125  }
126  }
127 
128  if ($language) {
129  $this->languageKey = $language;
130  }
131 
132  $this->initializeLocalization($locallangPathAndFilename);
133 
134  // The "from" charset of csConv() is only set for strings from TypoScript via _LOCAL_LANG
135  if (!empty($this->LOCAL_LANG[$this->languageKey][$key][0]['target'])
136  || isset($this->LOCAL_LANG_UNSET[$this->languageKey][$key])
137  ) {
138  // Local language translation for key exists
139  $value = $this->LOCAL_LANG[$this->languageKey][$key][0]['target'];
140  } elseif (!empty($this->alternativeLanguageKeys)) {
141  $languages = array_reverse($this->alternativeLanguageKeys);
142  foreach ($languages as $language) {
143  if (!empty($this->LOCAL_LANG[$language][$key][0]['target'])
144  || isset($this->LOCAL_LANG_UNSET[$language][$key])
145  ) {
146  // Alternative language translation for key exists
147  $value = $this->LOCAL_LANG[$language][$key][0]['target'];
148  break;
149  }
150  }
151  }
152 
153  if ($value === null && (!empty($this->LOCAL_LANG['default'][$key][0]['target'])
154  || isset($this->LOCAL_LANG_UNSET['default'][$key]))
155  ) {
156  // Default language translation for key exists
157  // No charset conversion because default is English and thereby ASCII
158  $value = $this->LOCAL_LANG['default'][$key][0]['target'];
159  }
160 
161  if (is_array($arguments) && $value !== null) {
162  $value = vsprintf($value, $arguments);
163  } else {
164  if (empty($value)) {
165  $value = $defaultValue;
166  }
167  }
168 
169  return $value;
170  }
171 
180  public function translateValuesRecursive(array $array, string $translationFile = null): array
181  {
182  $result = $array;
183  foreach ($result as $key => $value) {
184  if (is_array($value)) {
185  $result[$key] = $this->translateValuesRecursive($value, $translationFile);
186  } else {
187  $result[$key] = $this->translate($value, null, $translationFile, null, $value);
188  }
189  }
190  return $result;
191  }
192 
203  public function translateFinisherOption(
204  FormRuntime $formRuntime,
205  string $finisherIdentifier,
206  string $optionKey,
207  string $optionValue,
208  array $renderingOptions = []
209  ): string {
210  if (empty($finisherIdentifier)) {
211  throw new \InvalidArgumentException('The argument "finisherIdentifier" is empty', 1476216059);
212  }
213  if (empty($optionKey)) {
214  throw new \InvalidArgumentException('The argument "optionKey" is empty', 1476216060);
215  }
216 
217  $finisherIdentifier = preg_replace('/Finisher$/', '', $finisherIdentifier);
218  $translationFile = $renderingOptions['translationFile'];
219  if (isset($renderingOptions['translatePropertyValueIfEmpty'])) {
220  $translatePropertyValueIfEmpty = (bool)$renderingOptions['translatePropertyValueIfEmpty'];
221  } else {
222  $translatePropertyValueIfEmpty = true;
223  }
224 
225  if (empty($optionValue) && !$translatePropertyValueIfEmpty) {
226  return $optionValue;
227  }
228 
229  $language = null;
230  if (isset($renderingOptions['language'])) {
231  $language = $renderingOptions['language'];
232  }
233 
234  $translationKeyChain = [
235  sprintf('%s:%s.finisher.%s.%s', $translationFile, $formRuntime->getIdentifier(), $finisherIdentifier, $optionKey),
236  sprintf('%s:finisher.%s.%s', $translationFile, $finisherIdentifier, $optionKey)
237  ];
238  $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
239  $translatedValue = (empty($translatedValue)) ? $optionValue : $translatedValue;
240 
241  return $translatedValue;
242  }
243 
252  public function translateFormElementValue(
253  RootRenderableInterface $element,
254  string $property,
255  FormRuntime $formRuntime
256  ) {
257  if (empty($property)) {
258  throw new \InvalidArgumentException('The argument "property" is empty', 1476216007);
259  }
260 
261  $propertyType = 'properties';
262  $renderingOptions = $element->getRenderingOptions();
263 
264  if ($property === 'label') {
265  $defaultValue = $element->getLabel();
266  } else {
267  if ($element instanceof FormElementInterface) {
268  try {
269  $defaultValue = ArrayUtility::getValueByPath($element->getProperties(), $property, '.');
270  } catch (\RuntimeException $exception) {
271  $defaultValue = null;
272  }
273  } else {
274  $propertyType = 'renderingOptions';
275  try {
276  $defaultValue = ArrayUtility::getValueByPath($renderingOptions, $property, '.');
277  } catch (\RuntimeException $exception) {
278  $defaultValue = null;
279  }
280  }
281  }
282 
283  if (isset($renderingOptions['translation']['translatePropertyValueIfEmpty'])) {
284  $translatePropertyValueIfEmpty = $renderingOptions['translation']['translatePropertyValueIfEmpty'];
285  } else {
286  $translatePropertyValueIfEmpty = true;
287  }
288 
289  if (empty($defaultValue) && !$translatePropertyValueIfEmpty) {
290  return $defaultValue;
291  }
292 
293  $defaultValue = empty($defaultValue) ? '' : $defaultValue;
294  $translationFile = $renderingOptions['translation']['translationFile'];
295 
296  $language = null;
297  if (isset($renderingOptions['translation']['language'])) {
298  $language = $renderingOptions['translation']['language'];
299  }
300  $translationKeyChain = [];
301  if ($property === 'options' && is_array($defaultValue)) {
302  foreach ($defaultValue as $optionValue => &$optionLabel) {
303  $translationKeyChain = [
304  sprintf('%s:%s.element.%s.%s.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $propertyType, $property, $optionValue),
305  sprintf('%s:element.%s.%s.%s.%s', $translationFile, $element->getIdentifier(), $propertyType, $property, $optionValue)
306  ];
307  $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
308  $optionLabel = (empty($translatedValue)) ? $optionLabel : $translatedValue;
309  }
310  $translatedValue = $defaultValue;
311  } else {
312  $translationKeyChain = [
313  sprintf('%s:%s.element.%s.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $propertyType, $property),
314  sprintf('%s:element.%s.%s.%s', $translationFile, $element->getIdentifier(), $propertyType, $property),
315  sprintf('%s:element.%s.%s.%s', $translationFile, $element->getType(), $propertyType, $property),
316  ];
317  $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
318  $translatedValue = (empty($translatedValue)) ? $defaultValue : $translatedValue;
319  }
320 
321  return $translatedValue;
322  }
323 
328  public function setLanguage(string $languageKey)
329  {
330  $this->languageKey = $languageKey;
331  }
332 
337  public function getLanguage(): string
338  {
339  return $this->languageKey;
340  }
341 
347  protected function processTranslationChain(array $translationKeyChain, string $language = null)
348  {
349  $translatedValue = null;
350  foreach ($translationKeyChain as $translationKey) {
351  $translatedValue = $this->translate($translationKey, null, null, $language);
352  if (!empty($translatedValue)) {
353  break;
354  }
355  }
356  return $translatedValue;
357  }
358 
363  protected function initializeLocalization(string $locallangPathAndFilename)
364  {
365  if (empty($this->languageKey)) {
366  $this->setLanguageKeys();
367  }
368 
369  if (!empty($locallangPathAndFilename)) {
371  $languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class);
372 
373  $this->LOCAL_LANG = $languageFactory->getParsedData($locallangPathAndFilename, $this->languageKey, 'utf-8');
374 
375  foreach ($this->alternativeLanguageKeys as $language) {
376  $tempLL = $languageFactory->getParsedData($locallangPathAndFilename, $language, 'utf-8');
377  if ($this->languageKey !== 'default' && isset($tempLL[$language])) {
378  $this->LOCAL_LANG[$language] = $tempLL[$language];
379  }
380  }
381  }
382  $this->loadTypoScriptLabels();
383  }
384 
391  protected function setLanguageKeys()
392  {
393  $this->languageKey = 'default';
394 
395  $this->alternativeLanguageKeys = [];
396  if (TYPO3_MODE === 'FE') {
397  if (isset($this->getTypoScriptFrontendController()->config['config']['language'])) {
398  $this->languageKey = $this->getTypoScriptFrontendController()->config['config']['language'];
399  if (isset($this->getTypoScriptFrontendController()->config['config']['language_alt'])) {
400  $this->alternativeLanguageKeys[] = $this->getTypoScriptFrontendController()->config['config']['language_alt'];
401  } else {
403  $locales = GeneralUtility::makeInstance(Locales::class);
404  if (in_array($this->languageKey, $locales->getLocales(), true)) {
405  foreach ($locales->getLocaleDependencies($this->languageKey) as $language) {
406  $this->alternativeLanguageKeys[] = $language;
407  }
408  }
409  }
410  }
411  } elseif (!empty($GLOBALS['BE_USER']->uc['lang'])) {
412  $this->languageKey = $GLOBALS['BE_USER']->uc['lang'];
413  } elseif (!empty($this->getLanguageService()->lang)) {
414  $this->languageKey = $this->getLanguageService()->lang;
415  }
416  }
417 
425  protected function loadTypoScriptLabels()
426  {
427  $frameworkConfiguration = $this->getConfigurationManager()
429 
430  if (!is_array($frameworkConfiguration['_LOCAL_LANG'])) {
431  return;
432  }
433  $this->LOCAL_LANG_UNSET = [];
434  foreach ($frameworkConfiguration['_LOCAL_LANG'] as $languageKey => $labels) {
435  if (!(is_array($labels) && isset($this->LOCAL_LANG[$languageKey]))) {
436  continue;
437  }
438  foreach ($labels as $labelKey => $labelValue) {
439  if (is_string($labelValue)) {
440  $this->LOCAL_LANG[$languageKey][$labelKey][0]['target'] = $labelValue;
441  if ($labelValue === '') {
442  $this->LOCAL_LANG_UNSET[$languageKey][$labelKey] = '';
443  }
444  } elseif (is_array($labelValue)) {
445  $labelValue = $this->flattenTypoScriptLabelArray($labelValue, $labelKey);
446  foreach ($labelValue as $key => $value) {
447  $this->LOCAL_LANG[$languageKey][$key][0]['target'] = $value;
448  if ($value === '') {
449  $this->LOCAL_LANG_UNSET[$languageKey][$key] = '';
450  }
451  }
452  }
453  }
454  }
455  }
456 
468  protected function flattenTypoScriptLabelArray(array $labelValues, string $parentKey = ''): array
469  {
470  $result = [];
471  foreach ($labelValues as $key => $labelValue) {
472  if (!empty($parentKey)) {
473  $key = $parentKey . '.' . $key;
474  }
475  if (is_array($labelValue)) {
476  $labelValue = $this->flattenTypoScriptLabelArray($labelValue, $key);
477  $result = array_merge($result, $labelValue);
478  } else {
479  $result[$key] = $labelValue;
480  }
481  }
482  return $result;
483  }
484 
491  {
492  if ($this->configurationManager !== null) {
494  }
495 
496  $this->configurationManager = GeneralUtility::makeInstance(ObjectManager::class)
497  ->get(ConfigurationManagerInterface::class);
499  }
500 
504  protected function getLanguageService(): LanguageService
505  {
506  return $GLOBALS['LANG'];
507  }
508 
513  {
514  return $GLOBALS['TSFE'];
515  }
516 }
processTranslationChain(array $translationKeyChain, string $language=null)
translateFinisherOption(FormRuntime $formRuntime, string $finisherIdentifier, string $optionKey, string $optionValue, array $renderingOptions=[])
translateValuesRecursive(array $array, string $translationFile=null)
static isFirstPartOfStr($str, $partStr)
static getValueByPath(array $array, $path, $delimiter= '/')
translate($key, array $arguments=null, string $locallangPathAndFilename=null, string $language=null, $defaultValue= '')
flattenTypoScriptLabelArray(array $labelValues, string $parentKey= '')
translateFormElementValue(RootRenderableInterface $element, string $property, FormRuntime $formRuntime)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)