1<?php
2
3namespace Gettext\Generators;
4
5use Gettext\Translations;
6
7class Po extends Generator implements GeneratorInterface
8{
9    public static $options = [
10        'noLocation' => false,
11    ];
12
13    /**
14     * {@parentDoc}.
15     */
16    public static function toString(Translations $translations, array $options = [])
17    {
18        $options += static::$options;
19
20        $pluralForm = $translations->getPluralForms();
21        $pluralSize = is_array($pluralForm) ? ($pluralForm[0] - 1) : null;
22        $lines = ['msgid ""', 'msgstr ""'];
23
24        foreach ($translations->getHeaders() as $name => $value) {
25            $lines[] = sprintf('"%s: %s\\n"', $name, $value);
26        }
27
28        $lines[] = '';
29
30        //Translations
31        foreach ($translations as $translation) {
32            if ($translation->hasComments()) {
33                foreach ($translation->getComments() as $comment) {
34                    $lines[] = '# '.$comment;
35                }
36            }
37
38            if ($translation->hasExtractedComments()) {
39                foreach ($translation->getExtractedComments() as $comment) {
40                    $lines[] = '#. '.$comment;
41                }
42            }
43
44            if (!$options['noLocation'] && $translation->hasReferences()) {
45                foreach ($translation->getReferences() as $reference) {
46                    $lines[] = '#: '.$reference[0].(!is_null($reference[1]) ? ':'.$reference[1] : null);
47                }
48            }
49
50            if ($translation->hasFlags()) {
51                $lines[] = '#, '.implode(',', $translation->getFlags());
52            }
53
54            $prefix = $translation->isDisabled() ? '#~ ' : '';
55
56            if ($translation->hasContext()) {
57                $lines[] = $prefix.'msgctxt '.static::convertString($translation->getContext());
58            }
59
60            static::addLines($lines, $prefix.'msgid', $translation->getOriginal());
61
62            if ($translation->hasPlural()) {
63                static::addLines($lines, $prefix.'msgid_plural', $translation->getPlural());
64                static::addLines($lines, $prefix.'msgstr[0]', $translation->getTranslation());
65
66                foreach ($translation->getPluralTranslations($pluralSize) as $k => $v) {
67                    static::addLines($lines, $prefix.'msgstr['.($k + 1).']', $v);
68                }
69            } else {
70                static::addLines($lines, $prefix.'msgstr', $translation->getTranslation());
71            }
72
73            $lines[] = '';
74        }
75
76        return implode("\n", $lines);
77    }
78
79    /**
80     * Escapes and adds double quotes to a string.
81     *
82     * @param string $string
83     *
84     * @return string
85     */
86    protected static function multilineQuote($string)
87    {
88        $lines = explode("\n", $string);
89        $last = count($lines) - 1;
90
91        foreach ($lines as $k => $line) {
92            if ($k === $last) {
93                $lines[$k] = static::convertString($line);
94            } else {
95                $lines[$k] = static::convertString($line."\n");
96            }
97        }
98
99        return $lines;
100    }
101
102    /**
103     * Add one or more lines depending whether the string is multiline or not.
104     *
105     * @param array  &$lines
106     * @param string $name
107     * @param string $value
108     */
109    protected static function addLines(array &$lines, $name, $value)
110    {
111        $newLines = static::multilineQuote($value);
112
113        if (count($newLines) === 1) {
114            $lines[] = $name.' '.$newLines[0];
115        } else {
116            $lines[] = $name.' ""';
117
118            foreach ($newLines as $line) {
119                $lines[] = $line;
120            }
121        }
122    }
123
124    /**
125     * Convert a string to its PO representation.
126     *
127     * @param string $value
128     *
129     * @return string
130     */
131    public static function convertString($value)
132    {
133        return '"'.strtr(
134            $value,
135            [
136                "\x00" => '',
137                '\\' => '\\\\',
138                "\t" => '\t',
139                "\r" => '\r',
140                "\n" => '\n',
141                '"' => '\\"',
142            ]
143        ).'"';
144    }
145}
146