/**
  * Return the json array for a given locale, sourceCatalog, xliffPath and package.
  * The json will be cached.
  *
  * @param Locale $locale The locale
  * @return Result
  * @throws Exception
  */
 public function getCachedJson(Locale $locale)
 {
     $cacheIdentifier = md5($locale);
     if ($this->xliffToJsonTranslationsCache->has($cacheIdentifier)) {
         $json = $this->xliffToJsonTranslationsCache->get($cacheIdentifier);
     } else {
         $labels = [];
         $localeChain = $this->localizationService->getLocaleChain($locale);
         foreach ($this->packagesRegisteredForAutoInclusion as $packageKey => $sourcesToBeIncluded) {
             if (!is_array($sourcesToBeIncluded)) {
                 continue;
             }
             $translationBasePath = Files::concatenatePaths([$this->packageManager->getPackage($packageKey)->getResourcesPath(), $this->xliffBasePath]);
             // We merge labels in the chain from the worst choice to best choice
             foreach (array_reverse($localeChain) as $allowedLocale) {
                 $localeSourcePath = Files::getNormalizedPath(Files::concatenatePaths([$translationBasePath, $allowedLocale]));
                 foreach ($sourcesToBeIncluded as $sourceName) {
                     foreach (glob($localeSourcePath . $sourceName . '.xlf') as $xliffPathAndFilename) {
                         $xliffPathInfo = pathinfo($xliffPathAndFilename);
                         $sourceName = str_replace($localeSourcePath, '', $xliffPathInfo['dirname'] . '/' . $xliffPathInfo['filename']);
                         $labels = Arrays::arrayMergeRecursiveOverrule($labels, $this->parseXliffToArray($xliffPathAndFilename, $packageKey, $sourceName));
                     }
                 }
             }
         }
         $json = json_encode($labels);
         $this->xliffToJsonTranslationsCache->set($cacheIdentifier, $json);
     }
     return $json;
 }
 /**
  * Checks if the given value is a valid number.
  *
  * @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 I18n\Locale($this->options['locale']);
     } elseif ($this->options['locale'] instanceof I18n\Locale) {
         $locale = $this->options['locale'];
     } else {
         $this->addError('The "locale" option can be only set to string identifier, or Locale object.', 1281286579);
         return;
     }
     $strictMode = $this->options['strictMode'];
     $formatLength = $this->options['formatLength'];
     NumbersReader::validateFormatLength($formatLength);
     $formatType = $this->options['formatType'];
     NumbersReader::validateFormatType($formatType);
     if ($formatType === 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);
         }
     }
 }
 /**
  * Translaterates UTF-8 string to ASCII. (北京 to 'Bei Jing')
  *
  * Accepts language parameter that maps to a configurable array of special transliteration rules if present.
  *
  * @param string $text Text to transliterate
  * @param string $language Optional language for specific rules (falls back to current locale if not provided)
  * @return string
  */
 public function transliterate($text, $language = null)
 {
     $language = $language ?: $this->localizationService->getConfiguration()->getCurrentLocale()->getLanguage();
     if (isset($this->transliterationRules[$language])) {
         // Apply special transliteration (not supported in library)
         $text = strtr($text, $this->transliterationRules[$language]);
     }
     // Transliterate (transform 北京 to 'Bei Jing')
     if (preg_match('/[\\x80-\\xff]/', $text) && Transliterator::validUtf8($text)) {
         $text = Transliterator::utf8ToAscii($text);
     }
     return $text;
 }
 /**
  * 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 Locale $locale Locale to use (NULL for default one)
  * @return string The $text with placeholders resolved
  * @throws Exception\InvalidFormatPlaceholderException When encountered incorrectly formatted placeholder
  * @throws Exception\IndexOutOfBoundsException When trying to format nonexistent value
  * @api
  */
 public function resolvePlaceholders($textWithPlaceholders, array $arguments, Locale $locale = null)
 {
     if ($locale === null) {
         $locale = $this->localizationService->getConfiguration()->getDefaultLocale();
     }
     $lastPlaceHolderAt = 0;
     while ($lastPlaceHolderAt < strlen($textWithPlaceholders) && ($startOfPlaceholder = strpos($textWithPlaceholders, '{', $lastPlaceHolderAt)) !== false) {
         $endOfPlaceholder = strpos($textWithPlaceholders, '}', $lastPlaceHolderAt);
         $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 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 = $placeholderElements[0];
         if (!array_key_exists($valueIndex, $arguments)) {
             throw new Exception\IndexOutOfBoundsException('Placeholder "' . $valueIndex . '" was not provided, make sure you provide values for every placeholder.', 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);
         $lastPlaceHolderAt = $startOfPlaceholder + strlen($formattedPlaceholder);
     }
     return $textWithPlaceholders;
 }
 /**
  * Render the URI to the resource. The filename is used from child content.
  *
  * @param string $path The location of the resource, can be either a path relative to the Public resource directory of the package or a resource://... URI
  * @param string $package Target package key. If not set, the current package key will be used
  * @param PersistentResource $resource If specified, this resource object is used instead of the path and package information
  * @param boolean $localize Whether resource localization should be attempted or not
  * @return string The absolute URI to the resource
  * @throws InvalidVariableException
  * @api
  */
 public function render($path = null, $package = null, PersistentResource $resource = null, $localize = true)
 {
     if ($resource !== null) {
         $uri = $this->resourceManager->getPublicPersistentResourceUri($resource);
         if ($uri === false) {
             $uri = '404-Resource-Not-Found';
         }
     } else {
         if ($path === null) {
             throw new InvalidVariableException('The ResourceViewHelper did neither contain a valuable "resource" nor "path" argument.', 1353512742);
         }
         if ($package === null) {
             $package = $this->controllerContext->getRequest()->getControllerPackageKey();
         }
         if (strpos($path, 'resource://') === 0) {
             try {
                 list($package, $path) = $this->resourceManager->getPackageAndPathByPublicPath($path);
             } catch (Exception $exception) {
                 throw new InvalidVariableException(sprintf('The specified path "%s" does not point to a public resource.', $path), 1386458851);
             }
         }
         if ($localize === true) {
             $resourcePath = 'resource://' . $package . '/Public/' . $path;
             $localizedResourcePathData = $this->i18nService->getLocalizedFilename($resourcePath);
             $matches = array();
             if (preg_match('#resource://([^/]+)/Public/(.*)#', current($localizedResourcePathData), $matches) === 1) {
                 $package = $matches[1];
                 $path = $matches[2];
             }
         }
         $uri = $this->resourceManager->getPublicPackageResourceUri($package, $path);
     }
     return $uri;
 }
 /**
  * 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 Locale $locale The template Locale object
  * @return Locale Best-matching existing Locale instance
  * @api
  */
 public function detectLocaleFromTemplateLocale(Locale $locale)
 {
     $bestMatchingLocale = $this->localeCollection->findBestMatchingLocale($locale);
     if ($bestMatchingLocale !== null) {
         return $bestMatchingLocale;
     }
     return $this->localizationService->getConfiguration()->getDefaultLocale();
 }
 /**
  * Get the locale to use for all locale specific functionality.
  *
  * @throws InvalidVariableException
  * @return I18n\Locale The locale to use or NULL if locale should not be used
  */
 protected function getLocale()
 {
     if (!$this->hasArgument('forceLocale')) {
         return null;
     }
     $forceLocale = $this->arguments['forceLocale'];
     $useLocale = null;
     if ($forceLocale instanceof I18n\Locale) {
         $useLocale = $forceLocale;
     } elseif (is_string($forceLocale)) {
         try {
             $useLocale = new I18n\Locale($forceLocale);
         } catch (I18n\Exception $exception) {
             throw new InvalidVariableException('"' . $forceLocale . '" is not a valid locale identifier.', 1342610148, $exception);
         }
     } elseif ($forceLocale === true) {
         $useLocale = $this->localizationService->getConfiguration()->getCurrentLocale();
     }
     return $useLocale;
 }
 /**
  * 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 I18n\Locale $locale Locale object
  * @return XliffModel New or existing instance
  * @throws I18n\Exception
  */
 protected function getModel($packageKey, $sourceName, I18n\Locale $locale)
 {
     $sourcePath = Files::concatenatePaths(['resource://' . $packageKey, $this->xliffBasePath]);
     list($sourcePath, $foundLocale) = $this->localizationService->getXliffFilenameAndPath($sourcePath, $sourceName, $locale);
     if ($sourcePath === false) {
         throw new 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 XliffModel($sourcePath, $foundLocale);
 }
 /**
  * Renders the view
  *
  * @return string The rendered view
  * @throws \Exception if no node is given
  * @api
  */
 public function render()
 {
     $currentNode = $this->getCurrentNode();
     $currentSiteNode = $currentNode->getContext()->getCurrentSiteNode();
     $typoScriptRuntime = $this->getTypoScriptRuntime($currentSiteNode);
     $dimensions = $currentNode->getContext()->getDimensions();
     if (array_key_exists('language', $dimensions) && $dimensions['language'] !== array()) {
         $currentLocale = new Locale($dimensions['language'][0]);
         $this->i18nService->getConfiguration()->setCurrentLocale($currentLocale);
         $this->i18nService->getConfiguration()->setFallbackRule(array('strict' => false, 'order' => array_reverse($dimensions['language'])));
     }
     $typoScriptRuntime->pushContextArray(array('node' => $currentNode, 'documentNode' => $this->getClosestDocumentNode($currentNode) ?: $currentNode, 'site' => $currentSiteNode, 'editPreviewMode' => isset($this->variables['editPreviewMode']) ? $this->variables['editPreviewMode'] : null));
     try {
         $output = $typoScriptRuntime->render($this->typoScriptPath);
         $output = $this->mergeHttpResponseFromOutput($output, $typoScriptRuntime);
     } catch (RuntimeException $exception) {
         throw $exception->getPrevious();
     }
     $typoScriptRuntime->popContext();
     return $output;
 }
 /**
  * @param string $resourcePath
  * @return string
  */
 protected function getStaticResourceWebBaseUri($resourcePath)
 {
     $localizedResourcePathData = $this->i18nService->getLocalizedFilename($resourcePath);
     $matches = array();
     try {
         if (preg_match('#resource://([^/]+)/Public/(.*)#', current($localizedResourcePathData), $matches) === 1) {
             $packageKey = $matches[1];
             $path = $matches[2];
             return $this->resourceManager->getPublicPackageResourceUri($packageKey, $path);
         }
     } catch (\Exception $exception) {
         $this->systemLogger->logException($exception);
     }
     return '';
 }
 /**
  * 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.
  *
  * @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 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 NULL on failure
  * @api
  * @see Translator::translateByOriginalLabel()
  */
 public function translateById($labelId, array $arguments = [], $quantity = null, Locale $locale = null, $sourceName = 'Main', $packageKey = 'Neos.Flow')
 {
     if ($locale === null) {
         $locale = $this->localizationService->getConfiguration()->getCurrentLocale();
     }
     $pluralForm = $this->getPluralForm($quantity, $locale);
     $translatedMessage = $this->translationProvider->getTranslationById($labelId, $locale, $pluralForm, $sourceName, $packageKey);
     if ($translatedMessage === false) {
         return null;
     }
     if (!empty($arguments)) {
         return $this->formatResolver->resolvePlaceholders($translatedMessage, $arguments, $locale);
     }
     return $translatedMessage;
 }
 /**
  * Returns the absolute URL of a resource
  *
  * @return string
  * @throws TypoScriptException
  */
 public function evaluate()
 {
     $resource = $this->getResource();
     if ($resource !== null) {
         $uri = false;
         if ($resource instanceof PersistentResource) {
             $uri = $this->resourceManager->getPublicPersistentResourceUri($resource);
         }
         if ($uri === false) {
             throw new TypoScriptException('The specified resource is invalid', 1386458728);
         }
         return $uri;
     }
     $path = $this->getPath();
     if ($path === null) {
         throw new TypoScriptException('Neither "resource" nor "path" were specified', 1386458763);
     }
     if (strpos($path, 'resource://') === 0) {
         $matches = array();
         if (preg_match('#^resource://([^/]+)/Public/(.*)#', $path, $matches) !== 1) {
             throw new TypoScriptException(sprintf('The specified path "%s" does not point to a public resource.', $path), 1386458851);
         }
         $package = $matches[1];
         $path = $matches[2];
     } else {
         $package = $this->getPackage();
         if ($package === null) {
             $controllerContext = $this->tsRuntime->getControllerContext();
             /** @var $actionRequest ActionRequest */
             $actionRequest = $controllerContext->getRequest();
             $package = $actionRequest->getControllerPackageKey();
         }
     }
     $localize = $this->isLocalize();
     if ($localize === true) {
         $resourcePath = 'resource://' . $package . '/Public/' . $path;
         $localizedResourcePathData = $this->i18nService->getLocalizedFilename($resourcePath);
         $matches = array();
         if (preg_match('#resource://([^/]+)/Public/(.*)#', current($localizedResourcePathData), $matches) === 1) {
             $package = $matches[1];
             $path = $matches[2];
         }
     }
     return $this->resourceManager->getPublicPackageResourceUri($package, $path);
 }
 /**
  * @test
  */
 public function evaluateLocalizesFilenameIfLocalize()
 {
     $this->mockTsRuntime->expects($this->any())->method('evaluate')->will($this->returnCallback(function ($evaluatePath, $that) {
         $relativePath = str_replace('resourceUri/test/', '', $evaluatePath);
         switch ($relativePath) {
             case 'localize':
                 return true;
             case 'path':
                 return 'resource://Some.Package/Public/SomeResource';
             case 'package':
                 return 'Specified.Package';
         }
         return null;
     }));
     $this->mockI18nService->expects($this->atLeastOnce())->method('getLocalizedFilename')->will($this->returnValue(array('resource://Some.Package/Public/LocalizedFilename')));
     $this->mockResourceManager->expects($this->atLeastOnce())->method('getPublicPackageResourceUri')->will($this->returnValue('Static/Resources/Packages/Some.Package/LocalizedFilename'));
     $this->assertSame('Static/Resources/Packages/Some.Package/LocalizedFilename', $this->resourceUriImplementation->evaluate());
 }
 /**
  * @test
  */
 public function getLocalizedFilenameReturnsOriginalFilenameInStrictModeIfNoLocalizedFileExists()
 {
     $filename = 'vfs://Foo/Bar/Public/images/foobar.png';
     $service = new I18n\Service();
     list($result, ) = $service->getLocalizedFilename($filename, new I18n\Locale('pl'), true);
     $this->assertEquals($filename, $result);
 }
 /**
  * Tries to parse the input using the NumberParser.
  *
  * @param string $source
  * @param PropertyMappingConfigurationInterface $configuration
  * @return float|\Neos\Flow\Validation\Error Parsed float number or error
  * @throws \Neos\Flow\Property\Exception\InvalidPropertyMappingConfigurationException
  */
 protected function parseUsingLocaleIfConfigured($source, PropertyMappingConfigurationInterface $configuration)
 {
     $configuration = $this->getConfigurationKeysAndValues($configuration, ['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 Locale($configuration['locale']);
     } elseif ($configuration['locale'] instanceof Locale) {
         $locale = $configuration['locale'];
     }
     if (!$locale instanceof Locale) {
         $exceptionMessage = 'Determined locale is not of type "\\Neos\\Flow\\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'];
         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;
 }
 /**
  * Set the locale according to the user settings
  *
  * @return void
  */
 protected function initializeObject()
 {
     $this->_localizationService->getConfiguration()->setCurrentLocale(new Locale($this->_userService->getInterfaceLanguage()));
 }