Completed
Pull Request — master (#71)
by
unknown
01:22
created

PoCompiler::compile()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 45
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 45
rs 8.439
c 0
b 0
f 0
cc 6
eloc 25
nc 10
nop 1
1
<?php
2
3
namespace Sepia\PoParser;
4
5
use Sepia\PoParser\Catalog\Entry;
6
use Sepia\PoParser\Catalog\Header;
7
8
class PoCompiler
9
{
10
    const TOKEN_OBSOLETE = '#~ ';
11
    /** @var int */
12
    protected $wrappingColumn;
13
14
    /** @var string */
15
    protected $lineEnding;
16
17
    /**
18
     * PoCompiler constructor.
19
     *
20
     * @param int    $wrappingColumn
21
     * @param string $lineEnding
22
     */
23
    public function __construct($wrappingColumn = 80, $lineEnding = "\n")
24
    {
25
        $this->wrappingColumn = $wrappingColumn;
26
        $this->lineEnding = $lineEnding;
27
    }
28
29
    /**
30
     * Compiles entries into a string
31
     *
32
     * @param Catalog $catalog
33
     *
34
     * @return string
35
     * @throws \Exception
36
     * @todo Write obsolete messages at the end of the file.
37
     */
38
    public function compile(Catalog $catalog)
39
    {
40
        $output = '';
41
42
        if (count($catalog->getHeaders()) > 0) {
43
            $output .= 'msgid ""'.$this->eol();
44
            $output .= 'msgstr ""'.$this->eol();
45
            foreach ($catalog->getHeaders() as $header) {
46
                $output .= $header.$this->eol();
47
            }
48
            $output .= $this->eol();
49
        }
50
51
52
        $entriesCount = count($catalog->getEntries());
53
        $counter = 0;
54
        foreach ($catalog->getEntries() as $entry) {
55
            if ($entry->isObsolete() === false) {
56
                $output .= $this->buildPreviousEntry($entry);
57
                $output .= $this->buildTranslatorComment($entry);
58
                $output .= $this->buildDeveloperComment($entry);
59
                $output .= $this->buildReference($entry);
60
            }
61
62
            $output .= $this->buildFlags($entry);
63
64
//            if (isset($entry['@'])) {
65
//                $output .= "#@ ".$entry['@'].$this->eol();
66
//            }
67
68
            $output .= $this->buildContext($entry);
69
            $output .= $this->buildMsgId($entry);
70
            $output .= $this->buildMsgIdPlural($entry);
71
            $output .= $this->buildMsgStr($entry, $catalog->getHeader());
72
73
74
            $counter++;
75
            // Avoid inserting an extra newline at end of file
76
            if ($counter < $entriesCount) {
77
                $output .= $this->eol();
78
            }
79
        }
80
81
        return $output;
82
    }
83
84
    /**
85
     * @return string
86
     */
87
    protected function eol()
88
    {
89
        return $this->lineEnding;
90
    }
91
92
    /**
93
     * @param $entry
94
     *
95
     * @return string
96
     */
97
    protected function buildPreviousEntry(Entry $entry)
98
    {
99
        $previous = $entry->getPreviousEntry();
100
        if ($previous === null) {
101
            return '';
102
        }
103
104
        return '#| msgid '.$this->cleanExport($previous->getMsgId()).$this->eol();
105
    }
106
107
    /**
108
     * @param $entry
109
     *
110
     * @return string
111
     */
112
    protected function buildTranslatorComment(Entry $entry)
113
    {
114
        if ($entry->getTranslatorComments() === null) {
115
            return '';
116
        }
117
118
        $output = '';
119
        foreach ($entry->getTranslatorComments() as $comment) {
120
            $output .= '# '.$comment.$this->eol();
121
        }
122
123
        return $output;
124
    }
125
126
    protected function buildDeveloperComment(Entry $entry)
127
    {
128
        if ($entry->getDeveloperComments() === null) {
129
            return '';
130
        }
131
132
        $output = '';
133
        foreach ($entry->getDeveloperComments() as $comment) {
134
            $output .= '#. '.$comment.$this->eol();
135
        }
136
137
        return $output;
138
    }
139
140
    protected function buildReference(Entry $entry)
141
    {
142
        $reference = $entry->getReference();
143
        if ($reference === null || count($reference) === 0) {
144
            return '';
145
        }
146
147
        $output = '';
148
        foreach ($reference as $ref) {
149
            $output .= '#: '.$ref.$this->eol();
150
        }
151
152
        return $output;
153
    }
154
155
    protected function buildFlags(Entry $entry)
156
    {
157
        $flags = $entry->getFlags();
158
        if ($flags === null || count($flags) === 0) {
159
            return '';
160
        }
161
162
        return '#, '.implode(', ', $flags).$this->eol();
163
    }
164
165
    protected function buildContext(Entry $entry)
166
    {
167
        if ($entry->getMsgCtxt() === null) {
168
            return '';
169
        }
170
171
        return
172
            ($entry->isObsolete() ? '#~ ' : '').
173
            'msgctxt '.$this->cleanExport($entry->getMsgCtxt()).$this->eol();
174
    }
175
176
    protected function buildMsgId(Entry $entry)
177
    {
178
        if ($entry->getMsgId() === null) {
179
            return '';
180
        }
181
182
        return $this->buildProperty('msgid', $entry->getMsgId(), $entry->isObsolete());
183
    }
184
185
    protected function buildMsgStr(Entry $entry, Header $headers)
186
    {
187
        $value = $entry->getMsgStr();
188
        $plurals = $entry->getMsgStrPlurals();
189
190
        if ($value === null && $plurals === null) {
191
            return '';
192
        }
193
194
        if ($entry->isPlural()) {
195
            $output = '';
196
            $nPlurals = $headers->getPluralFormsCount();
197
            $pluralsFound = count($plurals);
198
            $maxIterations = max($nPlurals, $pluralsFound);
199
            for ($i = 0; $i < $maxIterations; $i++) {
200
                $value = isset($plurals[$i]) ? $plurals[$i] : '';
201
                $output .= 'msgstr['.$i.'] '.$this->cleanExport($value).$this->eol();
202
            }
203
204
            return $output;
205
        }
206
207
        return $this->buildProperty('msgstr', $value, $entry->isObsolete());
208
    }
209
210
    /**
211
     * @param Entry $entry
212
     *
213
     * @return string
214
     */
215
    protected function buildMsgIdPlural(Entry $entry)
216
    {
217
        $value = $entry->getMsgIdPlural();
218
        if ($value === null) {
219
            return '';
220
        }
221
222
        return 'msgid_plural '.$this->cleanExport($value).$this->eol();
223
    }
224
225
    protected function buildProperty($property, $value, $obsolete = false)
226
    {
227
        $tokens = $this->wrapString($value);
228
229
        $output = '';
230
        if (count($tokens) > 1) {
231
            array_unshift($tokens, '');
232
        }
233
234
        foreach ($tokens as $i => $token) {
235
            $output .= $obsolete ? self::TOKEN_OBSOLETE : '';
236
            $output .= ($i === 0) ? $property.' ' : '';
237
            $output .= $this->cleanExport($token).$this->eol();
238
        }
239
240
        return $output;
241
    }
242
243
    /**
244
     * Prepares a string to be outputed into a file.
245
     *
246
     * @param string $string The string to be converted.
247
     *
248
     * @return string
249
     */
250
    protected function cleanExport($string)
251
    {
252
        $quote = '"';
253
        $slash = '\\';
254
        $newline = "\n";
255
256
        $replaces = array(
257
            "$slash" => "$slash$slash",
258
            "$quote" => "$slash$quote",
259
            "\t" => '\t',
260
        );
261
262
        $string = str_replace(array_keys($replaces), array_values($replaces), $string);
263
264
        $po = $quote.implode("${slash}n$quote$newline$quote", explode($newline, $string)).$quote;
265
266
        // remove empty strings
267
        return str_replace("$newline$quote$quote", '', $po);
268
    }
269
270
    /**
271
     * @param string $value
272
     *
273
     * @return array
274
     */
275
    private function wrapString($value)
276
    {
277
        if (strlen($value) > $this->wrappingColumn) {
278
            $tokens = str_split($value, $this->wrappingColumn);
279
        } else {
280
            $tokens = array($value);
281
        }
282
283
        return $tokens;
284
    }
285
}
286