src/Viserio/Component/Parser/Parser/PoParser.php
public function parse(string $payload): array
    {
        $lines = \explode("\n", $payload);
        $i     = 0;

        $entries         = [];
        $headers         = [];
        $entry           = [];
        $justNewEntry    = false; // A new entries has been just inserted.
        $lastPreviousKey = null; // Used to remember last key in a multiline previous entries.
        $state           = null;
        $firstLine       = true;

        for ($n = \count($lines); $i < $n; $i++) {
            $line      = \trim($lines[$i]);
            $splitLine = \preg_split('/\s+/', $line, 2);
            $key       = $splitLine[0];

            if ($line === '' || ($key === 'msgid' && isset($entry['msgid']))) {
                // Two consecutive blank lines
                if ($justNewEntry) {
                    continue;
                }

                if ($firstLine) {
                    $firstLine = false;

                    if (isset($entry['msgstr']) && self::isHeader($entry)) {
                        $headers = $entry['msgstr'];
                    } else {
                        $entries[] = $entry;
                    }
                } else {
                    $entries[] = $entry;
                }

                $state           = null;
                $justNewEntry    = true;
                $lastPreviousKey = null;
                $entry           = [];

                if ($line === '') {
                    continue;
                }
            } else {
                $justNewEntry = false;
            }

            $data = $splitLine[1] ?? '';

            switch ($key) {
                case '#': // # Translator comments
                    $entry['tcomment'][] = self::convertString($data);

                    break;
                case '#.': // #. Comments extracted from source code
                    $entry['ccomment'][] = self::convertString($data);

                    break;
                case '#,': // Flagged translation
                    $entry['flags'] = \preg_split('/,\s*/', $data);
                    $entry['fuzzy'] = \in_array('fuzzy', $entry['flags'], true);

                    break;
                case '#:':
                    $entry = self::addReferences($data, $entry);

                    break;
                case '#|':  // Previous untranslated string
                case '#~':  // Old entries
                case '#~|': // Previous-Old untranslated string.
                    if ($key === '#|') {
                        $key = 'previous';
                    } elseif ($key === '#~') {
                        $key = 'obsolete';
                    } elseif ($key === '#~|') {
                        $key = 'previous-obsolete';
                    }

                    $tmpParts = \explode(' ', $data);
                    $tmpKey   = $tmpParts[0];

                    if (! \in_array($tmpKey, ['msgid', 'msgid_plural', 'msgstr', 'msgctxt'], true)) {
                        $tmpKey = $lastPreviousKey;
                        $str    = $data;
                    } else {
                        $str = \implode(' ', \array_slice($tmpParts, 1));
                    }

                    $entry[$key] = $entry[$key] ?? ['msgid' => [], 'msgstr' => []];

                    if ($key === 'obsolete' || $key === 'previous-obsolete') {
                        [$entry, $lastPreviousKey] = self::processObsoleteEntry($lastPreviousKey, $tmpKey, $str, $entry);
                    }

                    if ($key === 'previous') {
                        [$entry, $lastPreviousKey] = self::processPreviousEntry($lastPreviousKey, $tmpKey, $str, $entry, $key);
                    }

                    break;
                case '#@': // ignore #@ default
                    $entry['@'] = self::convertString($data);

                    break;
                // Allows disambiguation of different messages that have same msgid.
                case 'msgctxt':
                case 'msgid':        // untranslated-string
                case 'msgid_plural': // untranslated-string-plural
                    $state           = $key;
                    $entry[$state][] = self::convertString($data);

                    break;
                case 'msgstr':       // translated-string
                    $state           = 'msgstr';
                    $entry[$state][] = self::convertString($data);

                    break;

                default:
                    if (\mb_strpos($key, 'msgstr[') !== false) {
                        // translated-string-case-n
                        $state           = $key;
                        $entry[$state][] = self::convertString($data);
                    } else {
                        // "multiline" lines
                        $entry = self::extractMultiLines($state, $entry, $line, $key, $i);
                    }

                    break;
            }
        }

        if ($state === 'msgstr') {
            $entries[] = $entry;
        }

        foreach ($entries as $key => $entry) {
            $entries[$key] = \array_merge(self::DEFAULT_ENTRY, $entry);
        }

        $entries['headers'] = [];

        return self::extractHeaders($headers, $entries);
    }
public function parse(string $payload): array
    {
        $lines = \explode("\n", $payload);
        $i     = 0;

        $entries         = [];
        $headers         = [];
        $entry           = [];
        $justNewEntry    = false; // A new entries has been just inserted.
        $lastPreviousKey = null; // Used to remember last key in a multiline previous entries.
        $state           = null;
        $firstLine       = true;

        for ($n = \count($lines); $i < $n; $i++) {
            $line      = \trim($lines[$i]);
            $splitLine = \preg_split('/\s+/', $line, 2);
            $key       = $splitLine[0];

            if ($line === '' || ($key === 'msgid' && isset($entry['msgid']))) {
                // Two consecutive blank lines
                if ($justNewEntry) {
                    continue;
                }

                if ($firstLine) {
                    $firstLine = false;

                    if (isset($entry['msgstr']) && self::isHeader($entry)) {
                        $headers = $entry['msgstr'];
                    } else {
                        $entries[] = $entry;
                    }
                } else {
                    $entries[] = $entry;
                }

                $state           = null;
                $justNewEntry    = true;
                $lastPreviousKey = null;
                $entry           = [];

                if ($line === '') {
                    continue;
                }
            } else {
                $justNewEntry = false;
            }

            $data = $splitLine[1] ?? '';

            switch ($key) {
                case '#': // # Translator comments
                    $entry['tcomment'][] = self::convertString($data);

                    break;
                case '#.': // #. Comments extracted from source code
                    $entry['ccomment'][] = self::convertString($data);

                    break;
                case '#,': // Flagged translation
                    $entry['flags'] = \preg_split('/,\s*/', $data);
                    $entry['fuzzy'] = \in_array('fuzzy', $entry['flags'], true);

                    break;
                case '#:':
                    $entry = self::addReferences($data, $entry);

                    break;
                case '#|':  // Previous untranslated string
                case '#~':  // Old entries
                case '#~|': // Previous-Old untranslated string.
                    if ($key === '#|') {
                        $key = 'previous';
                    } elseif ($key === '#~') {
                        $key = 'obsolete';
                    } elseif ($key === '#~|') {
                        $key = 'previous-obsolete';
                    }

                    $tmpParts = \explode(' ', $data);
                    $tmpKey   = $tmpParts[0];

                    if (! \in_array($tmpKey, ['msgid', 'msgid_plural', 'msgstr', 'msgctxt'], true)) {
                        $tmpKey = $lastPreviousKey;
                        $str    = $data;
                    } else {
                        $str = \implode(' ', \array_slice($tmpParts, 1));
                    }

                    $entry[$key] = $entry[$key] ?? ['msgid' => [], 'msgstr' => []];

                    if ($key === 'obsolete' || $key === 'previous-obsolete') {
                        [$entry, $lastPreviousKey] = self::processObsoleteEntry($lastPreviousKey, $tmpKey, $str, $entry);
                    }

                    if ($key === 'previous') {
                        [$entry, $lastPreviousKey] = self::processPreviousEntry($lastPreviousKey, $tmpKey, $str, $entry, $key);
                    }

                    break;
                case '#@': // ignore #@ default
                    $entry['@'] = self::convertString($data);

                    break;
                // Allows disambiguation of different messages that have same msgid.
                case 'msgctxt':
                case 'msgid':        // untranslated-string
                case 'msgid_plural': // untranslated-string-plural
                    $state           = $key;
                    $entry[$state][] = self::convertString($data);

                    break;
                case 'msgstr':       // translated-string
                    $state           = 'msgstr';
                    $entry[$state][] = self::convertString($data);

                    break;

                default:
                    if (\mb_strpos($key, 'msgstr[') !== false) {
                        // translated-string-case-n
                        $state           = $key;
                        $entry[$state][] = self::convertString($data);
                    } else {
                        // "multiline" lines
                        $entry = self::extractMultiLines($state, $entry, $line, $key, $i);
                    }

                    break;
            }
        }

        if ($state === 'msgstr') {
            $entries[] = $entry;
        }

        foreach ($entries as $key => $entry) {
            $entries[$key] = \array_merge(self::DEFAULT_ENTRY, $entry);
        }

        $entries['headers'] = [];

        return self::extractHeaders($headers, $entries);
    }
{@inheritdoc}

array[]
['headers']        array  If a multi-line header is provided
than the value is a array else a string
array[]
['msgid']        array  ID of the message.
['msgstr']       array  Message translation.
['msgctxt']      array  Message context.
['tcomment']     array  Comment from translator.
['ccomment']     array  Extracted comments from code.
['references']   array  Location of string in code.
['obsolete']     bool   Is the message obsolete?
['fuzzy']        bool   Is the message "fuzzy"?
['flags']        array  Flags of the entry.
['previous']     array
['msgid']    string This is a previous string
['msgstr']   string This is a previous translation string
['msgid_plural'] array  The plural string
['msgstr[0]']    array  The string when the number is equal
['msgstr[1]']    array  The string when the number is equal