Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 1 | <?php |
| 2 | |
| 3 | /* |
| 4 | * This file is part of the Symfony package. |
| 5 | * |
| 6 | * (c) Fabien Potencier <fabien@symfony.com> |
| 7 | * |
| 8 | * For the full copyright and license information, please view the LICENSE |
| 9 | * file that was distributed with this source code. |
| 10 | */ |
| 11 | |
| 12 | namespace Symfony\Component\Translation\Dumper; |
| 13 | |
| 14 | use Symfony\Component\Translation\MessageCatalogue; |
| 15 | |
| 16 | /** |
| 17 | * PoFileDumper generates a gettext formatted string representation of a message catalogue. |
| 18 | * |
| 19 | * @author Stealth35 |
| 20 | */ |
| 21 | class PoFileDumper extends FileDumper |
| 22 | { |
| 23 | /** |
| 24 | * {@inheritdoc} |
| 25 | */ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame^] | 26 | public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 27 | { |
| 28 | $output = 'msgid ""'."\n"; |
| 29 | $output .= 'msgstr ""'."\n"; |
| 30 | $output .= '"Content-Type: text/plain; charset=UTF-8\n"'."\n"; |
| 31 | $output .= '"Content-Transfer-Encoding: 8bit\n"'."\n"; |
| 32 | $output .= '"Language: '.$messages->getLocale().'\n"'."\n"; |
| 33 | $output .= "\n"; |
| 34 | |
| 35 | $newLine = false; |
| 36 | foreach ($messages->all($domain) as $source => $target) { |
| 37 | if ($newLine) { |
| 38 | $output .= "\n"; |
| 39 | } else { |
| 40 | $newLine = true; |
| 41 | } |
| 42 | $metadata = $messages->getMetadata($source, $domain); |
| 43 | |
| 44 | if (isset($metadata['comments'])) { |
| 45 | $output .= $this->formatComments($metadata['comments']); |
| 46 | } |
| 47 | if (isset($metadata['flags'])) { |
| 48 | $output .= $this->formatComments(implode(',', (array) $metadata['flags']), ','); |
| 49 | } |
| 50 | if (isset($metadata['sources'])) { |
| 51 | $output .= $this->formatComments(implode(' ', (array) $metadata['sources']), ':'); |
| 52 | } |
| 53 | |
| 54 | $sourceRules = $this->getStandardRules($source); |
| 55 | $targetRules = $this->getStandardRules($target); |
| 56 | if (2 == \count($sourceRules) && [] !== $targetRules) { |
| 57 | $output .= sprintf('msgid "%s"'."\n", $this->escape($sourceRules[0])); |
| 58 | $output .= sprintf('msgid_plural "%s"'."\n", $this->escape($sourceRules[1])); |
| 59 | foreach ($targetRules as $i => $targetRule) { |
| 60 | $output .= sprintf('msgstr[%d] "%s"'."\n", $i, $this->escape($targetRule)); |
| 61 | } |
| 62 | } else { |
| 63 | $output .= sprintf('msgid "%s"'."\n", $this->escape($source)); |
| 64 | $output .= sprintf('msgstr "%s"'."\n", $this->escape($target)); |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | return $output; |
| 69 | } |
| 70 | |
| 71 | private function getStandardRules(string $id) |
| 72 | { |
| 73 | // Partly copied from TranslatorTrait::trans. |
| 74 | $parts = []; |
| 75 | if (preg_match('/^\|++$/', $id)) { |
| 76 | $parts = explode('|', $id); |
| 77 | } elseif (preg_match_all('/(?:\|\||[^\|])++/', $id, $matches)) { |
| 78 | $parts = $matches[0]; |
| 79 | } |
| 80 | |
| 81 | $intervalRegexp = <<<'EOF' |
| 82 | /^(?P<interval> |
| 83 | ({\s* |
| 84 | (\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*) |
| 85 | \s*}) |
| 86 | |
| 87 | | |
| 88 | |
| 89 | (?P<left_delimiter>[\[\]]) |
| 90 | \s* |
| 91 | (?P<left>-Inf|\-?\d+(\.\d+)?) |
| 92 | \s*,\s* |
| 93 | (?P<right>\+?Inf|\-?\d+(\.\d+)?) |
| 94 | \s* |
| 95 | (?P<right_delimiter>[\[\]]) |
| 96 | )\s*(?P<message>.*?)$/xs |
| 97 | EOF; |
| 98 | |
| 99 | $standardRules = []; |
| 100 | foreach ($parts as $part) { |
| 101 | $part = trim(str_replace('||', '|', $part)); |
| 102 | |
| 103 | if (preg_match($intervalRegexp, $part)) { |
| 104 | // Explicit rule is not a standard rule. |
| 105 | return []; |
| 106 | } else { |
| 107 | $standardRules[] = $part; |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | return $standardRules; |
| 112 | } |
| 113 | |
| 114 | /** |
| 115 | * {@inheritdoc} |
| 116 | */ |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame^] | 117 | protected function getExtension(): string |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 118 | { |
| 119 | return 'po'; |
| 120 | } |
| 121 | |
| 122 | private function escape(string $str): string |
| 123 | { |
| 124 | return addcslashes($str, "\0..\37\42\134"); |
| 125 | } |
| 126 | |
Matthias Andreas Benkard | 1ba5381 | 2022-12-27 17:32:58 +0100 | [diff] [blame^] | 127 | private function formatComments(string|array $comments, string $prefix = ''): ?string |
Matthias Andreas Benkard | 7b2a3a1 | 2021-08-16 10:57:25 +0200 | [diff] [blame] | 128 | { |
| 129 | $output = null; |
| 130 | |
| 131 | foreach ((array) $comments as $comment) { |
| 132 | $output .= sprintf('#%s %s'."\n", $prefix, $comment); |
| 133 | } |
| 134 | |
| 135 | return $output; |
| 136 | } |
| 137 | } |