/** * Replaces all placeholders in text with corresponding values. * * A placeholder is a group of elements separated with comma. First element * is required and defines index of value to insert (numeration starts from * 0, and is directly used to access element from $values array). Second * element is a name of formatter to use. It's optional, and if not given, * value will be simply string-casted. Remaining elements are formatter- * specific and they are directly passed to the formatter class. * * @param string $textWithPlaceholders String message with placeholder(s) * @param array $arguments An array of values to replace placeholders with * @param \TYPO3\FLOW3\I18n\Locale $locale Locale to use (NULL for default one) * @return string The $text with placeholders resolved * @throws \TYPO3\FLOW3\I18n\Exception\InvalidFormatPlaceholderException When encountered incorrectly formatted placeholder * @throws \TYPO3\FLOW3\I18n\Exception\IndexOutOfBoundsException When trying to format nonexistent value * @api */ public function resolvePlaceholders($textWithPlaceholders, array $arguments, \TYPO3\FLOW3\I18n\Locale $locale = NULL) { if ($locale === NULL) { $locale = $this->localizationService->getConfiguration()->getDefaultLocale(); } while (($startOfPlaceholder = strpos($textWithPlaceholders, '{')) !== FALSE) { $endOfPlaceholder = strpos($textWithPlaceholders, '}'); $startOfNextPlaceholder = strpos($textWithPlaceholders, '{', $startOfPlaceholder + 1); if ($endOfPlaceholder === FALSE || $startOfPlaceholder + 1 >= $endOfPlaceholder || $startOfNextPlaceholder !== FALSE && $startOfNextPlaceholder < $endOfPlaceholder) { // There is no closing bracket, or it is placed before the opening bracket, or there is nothing between brackets throw new \TYPO3\FLOW3\I18n\Exception\InvalidFormatPlaceholderException('Text provided contains incorrectly formatted placeholders. Please make sure you conform the placeholder\'s syntax.', 1278057790); } $contentBetweenBrackets = substr($textWithPlaceholders, $startOfPlaceholder + 1, $endOfPlaceholder - $startOfPlaceholder - 1); $placeholderElements = explode(',', str_replace(' ', '', $contentBetweenBrackets)); $valueIndex = (int) $placeholderElements[0]; if ($valueIndex < 0 || $valueIndex >= count($arguments)) { throw new \TYPO3\FLOW3\I18n\Exception\IndexOutOfBoundsException('Placeholder has incorrect index or not enough values provided. Please make sure you try to access existing values.', 1278057791); } if (isset($placeholderElements[1])) { $formatterName = $placeholderElements[1]; $formatter = $this->getFormatter($formatterName); $formattedPlaceholder = $formatter->format($arguments[$valueIndex], $locale, array_slice($placeholderElements, 2)); } else { // No formatter defined, just string-cast the value $formattedPlaceholder = (string) $arguments[$valueIndex]; } $textWithPlaceholders = str_replace('{' . $contentBetweenBrackets . '}', $formattedPlaceholder, $textWithPlaceholders); } return $textWithPlaceholders; }
/** * Returns best-matching Locale object based on the template Locale object * provided as parameter. System default locale will be returned if no * successful matches were done. * * @param \TYPO3\FLOW3\I18n\Locale $locale The template Locale object * @return \TYPO3\FLOW3\I18n\Locale Best-matching existing Locale instance * @api */ public function detectLocaleFromTemplateLocale(\TYPO3\FLOW3\I18n\Locale $locale) { $bestMatchingLocale = $this->localeCollection->findBestMatchingLocale($locale); if ($bestMatchingLocale !== NULL) { return $bestMatchingLocale; } return $this->localizationService->getConfiguration()->getDefaultLocale(); }
/** * Checks if the given value is a valid DateTime object. * Note: a value of NULL or empty string ('') is considered valid * * @param mixed $value The value that should be validated * @return void * @api */ protected function isValid($value) { if ($value instanceof \DateTime) { return; } if (!isset($this->options['locale'])) { $locale = $this->localizationService->getConfiguration()->getDefaultLocale(); } elseif (is_string($this->options['locale'])) { $locale = new \TYPO3\FLOW3\I18n\Locale($this->options['locale']); } elseif ($this->options['locale'] instanceof \TYPO3\FLOW3\I18n\Locale) { $locale = $this->options['locale']; } else { $this->addError('The "locale" option can be only set to string identifier, or Locale object.', 1281454676); return; } if (!isset($this->options['strictMode']) || $this->options['strictMode'] === TRUE) { $strictMode = TRUE; } else { $strictMode = FALSE; } if (isset($this->options['formatLength'])) { $formatLength = $this->options['formatLength']; \TYPO3\FLOW3\I18n\Cldr\Reader\DatesReader::validateFormatLength($formatLength); } else { $formatLength = \TYPO3\FLOW3\I18n\Cldr\Reader\DatesReader::FORMAT_LENGTH_DEFAULT; } if (isset($this->options['formatType'])) { $formatType = $this->options['formatType']; \TYPO3\FLOW3\I18n\Cldr\Reader\DatesReader::validateFormatType($formatType); } else { $formatType = \TYPO3\FLOW3\I18n\Cldr\Reader\DatesReader::FORMAT_TYPE_DATE; } if ($formatType === \TYPO3\FLOW3\I18n\Cldr\Reader\DatesReader::FORMAT_TYPE_TIME) { if ($this->datetimeParser->parseTime($value, $locale, $formatLength, $strictMode) === FALSE) { $this->addError('A valid time is expected.', 1281454830); } } elseif ($formatType === \TYPO3\FLOW3\I18n\Cldr\Reader\DatesReader::FORMAT_TYPE_DATETIME) { if ($this->datetimeParser->parseDateAndTime($value, $locale, $formatLength, $strictMode) === FALSE) { $this->addError('A valid date and time is expected.', 1281454831); } } else { if ($this->datetimeParser->parseDate($value, $locale, $formatLength, $strictMode) === FALSE) { $this->addError('A valid date is expected.', 1281454832); } } }
/** * Returns a XliffModel instance representing desired XLIFF file. * * Will return existing instance if a model for given $sourceName was already * requested before. Returns FALSE when $sourceName doesn't point to existing * file. * * @param string $packageKey Key of the package containing the source file * @param string $sourceName Relative path to existing CLDR file * @param \TYPO3\FLOW3\I18n\Locale $locale Locale object * @return \TYPO3\FLOW3\I18n\Xliff\XliffModel New or existing instance * @throws \TYPO3\FLOW3\I18n\Exception */ protected function getModel($packageKey, $sourceName, \TYPO3\FLOW3\I18n\Locale $locale) { $sourcePath = \TYPO3\FLOW3\Utility\Files::concatenatePaths(array('resource://' . $packageKey, $this->xliffBasePath)); list($sourcePath, $foundLocale) = $this->localizationService->getXliffFilenameAndPath($sourcePath, $sourceName, $locale); if ($sourcePath === FALSE) { throw new \TYPO3\FLOW3\I18n\Exception('No XLIFF file is available for ' . $packageKey . '::' . $sourceName . '::' . $locale . ' in the locale chain.', 1334759591); } if (isset($this->models[$sourcePath])) { return $this->models[$sourcePath]; } return $this->models[$sourcePath] = new \TYPO3\FLOW3\I18n\Xliff\XliffModel($sourcePath, $foundLocale); }
/** * Checks if the given value is a valid number. * Note: a value of NULL or empty string ('') is considered valid * * @param mixed $value The value that should be validated * @return void * @api * @todo Currency support should be added when it will be supported by NumberParser */ protected function isValid($value) { if (!isset($this->options['locale'])) { $locale = $this->localizationService->getConfiguration()->getDefaultLocale(); } elseif (is_string($this->options['locale'])) { $locale = new \TYPO3\FLOW3\I18n\Locale($this->options['locale']); } elseif ($this->options['locale'] instanceof \TYPO3\FLOW3\I18n\Locale) { $locale = $this->options['locale']; } else { $this->addError('The "locale" option can be only set to string identifier, or Locale object.', 1281286579); return; } if (!isset($this->options['strictMode']) || $this->options['strictMode'] === TRUE) { $strictMode = TRUE; } else { $strictMode = FALSE; } if (isset($this->options['formatLength'])) { $formatLength = $this->options['formatLength']; \TYPO3\FLOW3\I18n\Cldr\Reader\NumbersReader::validateFormatLength($formatLength); } else { $formatLength = \TYPO3\FLOW3\I18n\Cldr\Reader\NumbersReader::FORMAT_LENGTH_DEFAULT; } if (isset($this->options['formatType'])) { $formatType = $this->options['formatType']; \TYPO3\FLOW3\I18n\Cldr\Reader\NumbersReader::validateFormatType($formatType); } else { $formatType = \TYPO3\FLOW3\I18n\Cldr\Reader\NumbersReader::FORMAT_TYPE_DECIMAL; } if ($formatType === \TYPO3\FLOW3\I18n\Cldr\Reader\NumbersReader::FORMAT_TYPE_PERCENT) { if ($this->numberParser->parsePercentNumber($value, $locale, $formatLength, $strictMode) === FALSE) { $this->addError('A valid percent number is expected.', 1281452093); } return; } else { if ($this->numberParser->parseDecimalNumber($value, $locale, $formatLength, $strictMode) === FALSE) { $this->addError('A valid decimal number is expected.', 1281452094); } } }
/** * Returns translated string found under the $labelId. * * Searches for a translation in the source as defined by $sourceName * (interpretation depends on concrete translation provider used). * * If any arguments are provided in the $arguments array, they will be inserted * to the translated string (in place of corresponding placeholders, with * format defined by these placeholders). * * If $quantity is provided, correct plural form for provided $locale will * be chosen and used to choose correct translation variant. If $arguments * contains exactly one numeric element, it is automatically used as the * $quantity. * * @param string $labelId Key to use for finding translation * @param array $arguments An array of values to replace placeholders with * @param mixed $quantity A number to find plural form for (float or int), NULL to not use plural forms * @param \TYPO3\FLOW3\I18n\Locale $locale Locale to use (NULL for default one) * @param string $sourceName Name of file with translations, base path is $packageKey/Resources/Private/Locale/Translations/ * @param string $packageKey Key of the package containing the source file * @return string Translated message or $labelId on failure * @api * @see \TYPO3\FLOW3\I18n\Translator::translateByOriginalLabel() */ public function translateById($labelId, array $arguments = array(), $quantity = NULL, \TYPO3\FLOW3\I18n\Locale $locale = NULL, $sourceName = 'Main', $packageKey = 'TYPO3.FLOW3') { if ($locale === NULL) { $locale = $this->localizationService->getConfiguration()->getCurrentLocale(); } $pluralForm = $this->getPluralForm($quantity, $arguments, $locale); $translatedMessage = $this->translationProvider->getTranslationById($labelId, $locale, $pluralForm, $sourceName, $packageKey); if ($translatedMessage === FALSE) { return $labelId; } elseif ($arguments !== array()) { return $this->formatResolver->resolvePlaceholders($translatedMessage, $arguments, $locale); } return $translatedMessage; }
/** * Tries to parse the input using the NumberParser. * * @param string $source * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration * @return float|\TYPO3\FLOW3\Validation\Error Parsed float number or error */ protected function parseUsingLocaleIfConfigured($source, \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration) { $configuration = $this->getConfigurationKeysAndValues($configuration, array('locale', 'strictMode', 'formatLength', 'formatType')); if ($configuration['locale'] === NULL) { return $source; } elseif ($configuration['locale'] === TRUE) { $locale = $this->localizationService->getConfiguration()->getCurrentLocale(); } elseif (is_string($configuration['locale'])) { $locale = new \TYPO3\FLOW3\I18n\Locale($configuration['locale']); } elseif ($configuration['locale'] instanceof \TYPO3\FLOW3\I18n\Locale) { $locale = $configuration['locale']; } if (!$locale instanceof \TYPO3\FLOW3\I18n\Locale) { $exceptionMessage = 'Determined locale is not of type "\\TYPO3\\FLOW3\\I18n\\Locale", but of type "' . (is_object($locale) ? get_class($locale) : gettype($locale)) . '".'; throw new InvalidPropertyMappingConfigurationException($exceptionMessage, 1334837413); } if ($configuration['strictMode'] === NULL || $configuration['strictMode'] === TRUE) { $strictMode = TRUE; } else { $strictMode = FALSE; } if ($configuration['formatLength'] !== NULL) { $formatLength = $configuration['formatLength']; NumbersReader::validateFormatLength($formatLength); } else { $formatLength = NumbersReader::FORMAT_LENGTH_DEFAULT; } if ($configuration['formatType'] !== NULL) { $formatType = $configuration['formatType']; \TYPO3\FLOW3\I18n\Cldr\Reader\NumbersReader::validateFormatType($formatType); } else { $formatType = NumbersReader::FORMAT_TYPE_DECIMAL; } if ($formatType === NumbersReader::FORMAT_TYPE_PERCENT) { $return = $this->numberParser->parsePercentNumber($source, $locale, $formatLength, $strictMode); if ($return === FALSE) { $return = new Error('A valid percent number is expected.', 1334839253); } } else { $return = $this->numberParser->parseDecimalNumber($source, $locale, $formatLength, $strictMode); if ($return === FALSE) { $return = new Error('A valid decimal number is expected.', 1334839260); } } return $return; }