Parse the file type names.

@param \Gettext\Translations $translations
@param string                $rootDirectory
@param string                $prefix
@param string[]              $directoryAlternatives
423329
private function parseFileTypes(\Gettext\Translations $translations, $rootDirectory, $prefix, $directoryAlternatives)
    {
        foreach ($directoryAlternatives as $subDir) {
            $rel = ($subDir === '') ? 'app.php' : "$subDir/app.php";
            $fileAbs = $rootDirectory.'/'.$rel;
            if (!is_file($fileAbs)) {
                continue;
            }
            $fileRel = $prefix.$rel;
            $configFile = new \C5TL\Util\ConfigFile($fileAbs);
            $config = $configFile->getArray();
            if (isset($config['file_types']) && is_array($config['file_types'])) {
                $fileTypes = $config['file_types'];
                foreach (array_keys($fileTypes) as $fileType) {
                    $translation = $translations->insert('', $fileType);
                    $translation->addReference($fileRel);
                }
            }
        }
    }
1201624
static public function parseFile($file, KTranslatorInterface $translator)
    {
        $strings   = array();
        $catalogue = $translator->getCatalogue();

        // Catch exceptions if any.
        try {
            $translations = $translator->getObject('object.config.factory')->fromFile($file);
        }  catch (Exception $e) {
            $translations = array();
        }

        foreach ($translations as $key => $value) {
            $strings[$catalogue->getPrefix() . $catalogue->generateKey($key)] = $value;
        }

        return $strings;
    }
616308
public static function getLangFiles( $dir_lang , $json_langs = null )
	{
		$langs = array();

		// scan genuine folders first
		foreach ( scandir( $dir_lang ) as $lang )
		{
			if ( ! Tools::isValidDirectory( $dir_lang , $lang ) )
			{
				continue;
			}

			if ( in_array( $lang , self::$vendorsFolders ) )
			{
				$langs[] = new LangFileTypeGenuineVendor( $lang );
			}
			else
			{
				$langs[] = new LangFileTypeGenuine( $lang );
			}

		}

		// generate json langs
		if ( is_array( $json_langs ) )
		{
			foreach ( $json_langs as $lang )
			{
				$langs[] = new LangFileTypeJson( $lang );
			}
		}

		return $langs;
	}
879534
private function loadAndParseFile($fileName, $rootDir)
    {
        if (!$this->configuration->isRemoteFileInclusionEnabled()) {
            $rootDir = \realpath($rootDir);
            $fullPath = \realpath($rootDir . '/' . $fileName);

            if (!\is_readable($fullPath)) {
                throw new FileNotFoundException($fileName);
            }
        } else {
            $fullPath = $rootDir . '/' . $fileName;
            if (!\filter_var($fullPath, FILTER_VALIDATE_URL) && !\is_readable($fullPath)) {
                throw new FileNotFoundException($fileName);
            }
        }

        // Prevent LFI directory traversal attacks
        if (!$this->configuration->isDirectoryTraversalAllowed() &&
            \substr($fullPath, 0, \strlen($rootDir)) !== $rootDir
        ) {
            throw new FileNotFoundException($fileName);
        }

        $cacheKey = \md5($fullPath);

        // cache based on file name, prevents including/parsing the same file multiple times
        if (isset($this->cachedFiles[$cacheKey])) {
            return $this->cachedFiles[$cacheKey];
        }

        $fileExtension = (\pathinfo($fileName, PATHINFO_EXTENSION));

        if (\in_array($fileExtension, ['yaml', 'yml', 'raml'], true)) {
            $rootDir = \dirname($rootDir . '/' . $fileName);

            // RAML and YAML files are always parsed
            $fileData = $this->parseRamlString(
                \file_get_contents($fullPath),
                $rootDir
            );
            $fileData = $this->includeAndParseFiles($fileData, $rootDir);
        } else {
            $loader = \array_key_exists($fileExtension, $this->fileLoaders) ? $this->fileLoaders[$fileExtension] : $this->fileLoaders['*'];

            $fileData = $loader->loadFile($fullPath);
            $this->cachedFilesPaths[\md5($fileData)] = $fullPath;
        }

        // cache before returning
        $this->cachedFiles[$cacheKey] = $fileData;

        $this->includedFiles[] = $fullPath;

        return $fileData;
    }
1322233
private function loadTranslationsFromDefaultPath()
    {
        /** @var DirectoryInterface $baseDir */
        $baseDir = $this->getBaseDirectory();
        /** @var Filesystem $filesystem */
        $filesystem = $this->getBaseDirectory()->getFilesystem();
        if ($filesystem->has($baseDir->getFullPath() . '/translations') === false) {
            return null;
        }
        $translations = [];
        /** @var Local $local */
        $local = $filesystem->getAdapter();
        $basePath = $local->getPathPrefix();

        /** @var DirectoryInterface $translationDirectory */
        $translationDirectory = $filesystem->get($baseDir->getFullPath() . '/translations');
        foreach ($translationDirectory->getContents(true) as $fileInfo) {
            if ($fileInfo->isFile() === false) {
                continue;
            }

            $format = $fileInfo->getExtension();
            $resource = $basePath . $fileInfo->getPath();
            $locale = $fileInfo->getFilename('.' . $format);

            $translations[] = [$format, $resource, $locale];
        }

        return $translations;
    }
940530
private function extractGettextStrings()
    {
        $translation = null;
        $translationObjects = array();
        $lookupDirectories = array(
            Strata::getVendorPath() . 'strata-mvc' . DIRECTORY_SEPARATOR . 'strata' . DIRECTORY_SEPARATOR . 'src',
            Strata::getSrcPath(),
            Strata::getThemesPath(),
        );

        foreach ($lookupDirectories as $directory) {
            $translationObjects = $this->recurseThroughDirectory($directory);

            // Merge all translation objects into a bigger one
            foreach ($translationObjects as $t) {
                if (is_null($translation)) {
                    $translation = $t;
                } else {
                    $translation->mergeWith($t);
                }
            }
        }

        return $translation;
    }
4402
public function translator(string $locale, string $domain, string $directory): ?TranslatorInterface
    {
        $class = GETTEXT_EXTENSION ? GettextTranslator::class : Translator::class;

        $previous = self::$translator;
        self::$translator = new $class($locale, $domain, $directory);

        if ($previous === null) {
            require __DIR__ . DIRECTORY_SEPARATOR . 'helpers.php';
        }

        $this->locale = $locale;

        return $previous;
    }
748575
private static function fromArray(array $messages, Translations $translations)
    {
        if (!empty($messages['domain'])) {
            $translations->setDomain($messages['domain']);
        }

        if (!empty($messages['plural-forms'])) {
            $translations->setHeader(Translations::HEADER_PLURAL, $messages['plural-forms']);
        }

        foreach ($messages['messages'] as $context => $contextTranslations) {
            foreach ($contextTranslations as $original => $value) {
                if ($context === '' && $original === '') {
                    self::extractHeaders(is_array($value) ? array_shift($value) : $value, $translations);
                    continue;
                }

                $translation = $translations->insert($context, $original);

                if (is_array($value)) {
                    $translation->setTranslation(array_shift($value));
                    $translation->setPluralTranslations($value);
                } else {
                    $translation->setTranslation($value);
                }
            }
        }
    }
29155
public static function languageFolder(string $extensionKey, string $prefix = 'EXT:'): string {
    $privateFolder = self::privateFolder($extensionKey, $prefix);

    return "${privateFolder}/Language";
  }
397016
final private static function getDirectoryStructureDo($relativePath, $rootDirectory, $exclude3rdParty)
    {
        $thisRoot = $rootDirectory;
        if ($relativePath !== '') {
            $thisRoot .= '/'.$relativePath;
        }
        $subDirs = array();
        $hDir = @opendir($thisRoot);
        if ($hDir === false) {
            throw new \Exception("Unable to open directory $rootDirectory");
        }
        while (($entry = @readdir($hDir)) !== false) {
            if ($entry[0] === '.') {
                continue;
            }
            $fullPath = $thisRoot.'/'.$entry;
            if (!is_dir($fullPath)) {
                continue;
            }
            if ($exclude3rdParty) {
                if (($entry === 'vendor') || preg_match('%/libraries/3rdparty$%', $fullPath)) {
                    continue;
                }
            }
            $subDirs[] = $entry;
        }
        @closedir($hDir);
        $result = array();
        foreach ($subDirs as $subDir) {
            $rel = ($relativePath === '') ? $subDir : "$relativePath/$subDir";
            $result = array_merge($result, static::getDirectoryStructureDo($rel, $rootDirectory, $exclude3rdParty));
            $result[] = $rel;
        }

        return $result;
    }
1061790
public function saveGettextFunctions(Translations $translations, array $options)
    {
        $functions = $options['functions'];
        $file = $options['file'];

        foreach ($this->getFunctions($options['constants']) as $function) {
            list($name, $line, $args) = $function;

            if (isset($options['lineOffset'])) {
                $line += $options['lineOffset'];
            }

            if (!isset($functions[$name])) {
                continue;
            }

            $domain = $context = $original = $plural = null;

            switch ($functions[$name]) {
                case 'noop':
                case 'gettext':
                    if (!isset($args[0])) {
                        continue 2;
                    }

                    $original = $args[0];
                    break;

                case 'ngettext':
                    if (!isset($args[1])) {
                        continue 2;
                    }

                    list($original, $plural) = $args;
                    break;

                case 'pgettext':
                    if (!isset($args[1])) {
                        continue 2;
                    }

                    list($context, $original) = $args;
                    break;

                case 'dgettext':
                    if (!isset($args[1])) {
                        continue 2;
                    }

                    list($domain, $original) = $args;
                    break;

                case 'dpgettext':
                    if (!isset($args[2])) {
                        continue 2;
                    }

                    list($domain, $context, $original) = $args;
                    break;

                case 'npgettext':
                    if (!isset($args[2])) {
                        continue 2;
                    }

                    list($context, $original, $plural) = $args;
                    break;

                case 'dnpgettext':
                    if (!isset($args[3])) {
                        continue 2;
                    }

                    list($domain, $context, $original, $plural) = $args;
                    break;

                case 'dngettext':
                    if (!isset($args[2])) {
                        continue 2;
                    }

                    list($domain, $original, $plural) = $args;
                    break;

                default:
                    throw new Exception(sprintf('Not valid function %s', $functions[$name]));
            }

            if ((string)$original === '') {
                continue;
            }

            $isDefaultDomain = $domain === null;
            $isMatchingDomain = $domain === $translations->getDomain();

            if (!empty($options['domainOnly']) && $isDefaultDomain) {
                // If we want to find translations for a specific domain, skip default domain messages
                continue;
            }

            if (!$isDefaultDomain && !$isMatchingDomain) {
                continue;
            }

            $translation = $translations->insert($context, $original, $plural);
            $translation->addReference($file, $line);

            if (isset($function[3])) {
                foreach ($function[3] as $extractedComment) {
                    $translation->addExtractedComment($extractedComment);
                }
            }
        }
    }
1095234
protected function parseDirectoryDo(\Gettext\Translations $translations, $rootDirectory, $relativePath, $subParsersFilter, $exclude3rdParty)
    {
        $themesPresets = array();
        $prefix = ($relativePath === '') ? '' : "$relativePath/";
        $matches = null;
        foreach (array_merge(array(''), $this->getDirectoryStructure($rootDirectory, $exclude3rdParty)) as $child) {
            $presetsAbsDirectory = ($child === '') ? $rootDirectory : "$rootDirectory/$child";
            if (preg_match('%(?:^|/)themes/\w+/css/presets$%', $presetsAbsDirectory, $matches)) {
                $dirList = @scandir($presetsAbsDirectory);
                if ($dirList === false) {
                    throw new \Exception("Unable to parse directory $presetsAbsDirectory");
                }
                $shownChild = ($child === '') ? rtrim($prefix, '/') : ($prefix.$child);
                foreach ($dirList as $file) {
                    if (($file[0] !== '.') && preg_match('/[^.].*\.less$/i', $file)) {
                        $fileAbs = "$presetsAbsDirectory/$file";
                        if (is_file($fileAbs)) {
                            $content = @file_get_contents($fileAbs);
                            if ($content === false) {
                                throw new \Exception("Error reading file '$fileAbs'");
                            }
                            $content = str_replace("\r", "\n", str_replace("\r\n", "\n", $content));
                            // Strip multiline comments
                            $content = preg_replace_callback(
                                '|/\*.*?\*/|s',
                                function ($matches) {
                                    return str_repeat("\n", substr_count($matches[0], "\n"));
                                },
                                $content
                            );
                            foreach (array("'", '"') as $quote) {
                                if (preg_match('%(?:^|\\n|;)[ \\t]*@preset-name:\\s*'.$quote.'([^'.$quote.']*)'.$quote.'\\s*(?:;|$)%s', $content, $matches)) {
                                    $presetName = $matches[1];
                                    $presetLine = null;
                                    $p = strpos($content, $matches[0]);
                                    if ($p !== false) {
                                        $presetLine = substr_count(substr($content, 0, $p), "\n") + 1;
                                    }
                                    if (!isset($themesPresets[$presetName])) {
                                        $themesPresets[$presetName] = array();
                                    }
                                    $themesPresets[$presetName][] = array($shownChild."/$file", $presetLine);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        foreach ($themesPresets as $themesPreset => $references) {
            $translation = $translations->insert('PresetName', ucwords(str_replace(array('_', '-', '/'), ' ', $themesPreset)));
            foreach ($references as $reference) {
                $translation->addReference($reference[0], $reference[1]);
            }
        }
    }
1240941
public function parseManual(\Gettext\Translations $translations, $concrete5version)
    {
        if (class_exists('\PermissionKeyCategory', true) && method_exists('\PermissionKeyCategory', 'getList')) {
            foreach (\PermissionKeyCategory::getList() as $pkc) {
                $pkcHandle = $pkc->getPermissionKeyCategoryHandle();
                foreach (\PermissionKey::getList($pkcHandle) as $pk) {
                    $this->addTranslation($translations, $pk->getPermissionKeyName(), 'PermissionKeyName');
                    $this->addTranslation($translations, $pk->getPermissionKeyDescription(), 'PermissionKeyDescription');
                }
            }
        }
    }
1035041
public static function parseLanguageFiles($dir = null)
    {
        $languages = array();

        // add search for symlinks too
        $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::FOLLOW_SYMLINKS));

        foreach ($iterator as $file)
        {
            $langs    = array();
            $fileName = $file->getFilename();

            if (!$file->isFile() || !preg_match("/^([-_A-Za-z]*)\.xml$/", $fileName))
            {
                continue;
            }

            try
            {
                $metadata = self::parseXMLLanguageFile($file->getRealPath());

                if ($metadata)
                {
                    $lang = str_replace('.xml', '', $fileName);
                    $langs[$lang] = $metadata;
                }

                $languages = array_merge($languages, $langs);
            }
            catch (RuntimeException $e)
            {
            }
        }

        return $languages;
    }
429393
public function parseManual(\Gettext\Translations $translations, $concrete5version)
    {
        $pkcNameMap = array(
            'page' => 'Page',
            'single_page' => 'Single page',
            'stack' => 'Stack',
            'composer_page' => 'Composer page',
            'user' => 'User',
            'file_set' => 'File set',
            'file' => 'File',
            'area' => 'Area',
            'block_type' => 'Block type',
            'block' => 'Block',
            'admin' => 'Administration',
            'sitemap' => 'Site map',
            'marketplace_newsflow' => 'MarketPlace newsflow',
            'basic_workflow' => 'Basic workflow',
        );
        if (version_compare($concrete5version, '5.7') < 0) {
            $pkcClass = '\PermissionKeyCategory';
        } else {
            $pkcClass = '\Concrete\Core\Permission\Category';
        }
        if (class_exists($pkcClass, true) && method_exists($pkcClass, 'getList')) {
            foreach (call_user_func($pkcClass.'::getList') as $pkc) {
                $pkcHandle = $pkc->getPermissionKeyCategoryHandle();
                $this->addTranslation($translations, isset($pkcNameMap[$pkcHandle]) ? $pkcNameMap[$pkcHandle] : ucwords(str_replace(array('_', '-', '/'), ' ', $pkcHandle)));
            }
        }
    }
225381
protected function parseDirectoryDo(\Gettext\Translations $translations, $rootDirectory, $relativePath, $subParsersFilter, $exclude3rdParty)
    {
        $phpFiles = array();
        foreach (array_merge(array(''), $this->getDirectoryStructure($rootDirectory, $exclude3rdParty)) as $child) {
            $fullDirectoryPath = ($child === '') ? $rootDirectory : "$rootDirectory/$child";
            $contents = @scandir($fullDirectoryPath);
            if ($contents === false) {
                throw new \Exception("Unable to parse directory $fullDirectoryPath");
            }
            foreach ($contents as $file) {
                if ($file[0] !== '.') {
                    $fullFilePath = "$fullDirectoryPath/$file";
                    if (preg_match('/^(.*)\.php$/i', $file) && is_file($fullFilePath)) {
                        $phpFiles[] = ($child === '') ? $file : "$child/$file";
                    }
                }
            }
        }
        if (count($phpFiles) > 0) {
            if (\C5TL\Gettext::commandIsAvailable('xgettext')) {
                $newTranslations = static::parseDirectoryDo_xgettext($rootDirectory, $phpFiles);
            } else {
                $newTranslations = static::parseDirectoryDo_php($rootDirectory, $phpFiles);
            }
            if ($newTranslations->count() > 0) {
                if ($relativePath !== '') {
                    foreach ($newTranslations as $newTranslation) {
                        static::fixExtractedComments($newTranslation);
                        $references = $newTranslation->getReferences();
                        $newTranslation->deleteReferences();
                        foreach ($references as $reference) {
                            $newTranslation->addReference($relativePath.'/'.$reference[0], $reference[1]);
                        }
                        $translations[] = $newTranslation;
                    }
                } else {
                    foreach ($newTranslations as $newTranslation) {
                        static::fixExtractedComments($newTranslation);
                        $translations[] = $newTranslation;
                    }
                }
            }
        }
    }
897106
public static function getAll($prefix = '')
		{

			// Make backend load all
			$backend = static::getBackend();
			$backend->loadAll($prefix);

			// Now return requested translations
			return $backend->translations($prefix);

		}