Completed
Push — v5-dev ( a42eb3...269a1b )
by Oscar
01:14
created

MoGenerator::includeHeaders()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Gettext\Generator;
4
5
use Gettext\Translations;
6
use Gettext\Translation;
7
8
final class MoGenerator extends Generator
9
{
10
    private $includeHeaders = true;
11
12
    public function includeHeaders(bool $includeHeaders = true): void
13
    {
14
        $this->includeHeaders = $includeHeaders;
15
    }
16
17
    public function generateString(Translations $translations): string
18
    {
19
        $messages = [];
20
21 View Code Duplication
        if ($this->includeHeaders) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
22
            $lines = [];
23
24
            foreach ($translations->getHeaders() as $name => $value) {
25
                $lines[] = sprintf('%s: %s', $name, $value);
26
            }
27
28
            $messages[''] = implode("\n", $lines);
29
        }
30
31
        foreach ($translations as $translation) {
32
            if (!$translation->getTranslation() || $translation->isDisabled()) {
33
                continue;
34
            }
35
36
            if ($context = $translation->getContext()) {
37
                $originalString = "{$context}\x04{$translation->getOriginal()}";
38
            } else {
39
                $originalString = $translation->getOriginal();
40
            }
41
42
            $messages[$originalString] = $translation;
43
        }
44
45
        ksort($messages);
46
        $numEntries = count($messages);
47
        $originalsTable = '';
48
        $translationsTable = '';
49
        $originalsIndex = [];
50
        $translationsIndex = [];
51
        $pluralForm = $translations->getHeaders()->getPluralForm();
52
        $pluralSize = is_array($pluralForm) ? ($pluralForm[0] - 1) : null;
53
54
        foreach ($messages as $originalString => $translation) {
55
            if (is_string($translation)) {
56
                $translationString = $translation;
57
            } elseif (self::hasPluralTranslations($translation)) {
58
                $originalString .= "\x00{$translation->getPlural()}";
59
                $translationString = "{$translation->getTranslation()}\x00".implode("\x00", $translation->getPluralTranslations($pluralSize));
60
            } else {
61
                $translationString = $translation->getTranslation();
62
            }
63
64
            $originalsIndex[] = [
65
                'relativeOffset' => strlen($originalsTable),
66
                'length' => strlen($originalString)
67
            ];
68
            $originalsTable .= $originalString."\x00";
69
            $translationsIndex[] = [
70
                'relativeOffset' => strlen($translationsTable),
71
                'length' => strlen($translationString)
72
            ];
73
            $translationsTable .= $translationString."\x00";
74
        }
75
76
        // Offset of table with the original strings index: right after the header (which is 7 words)
77
        $originalsIndexOffset = 7 * 4;
78
79
        // Size of table with the original strings index
80
        $originalsIndexSize = $numEntries * (4 + 4);
81
82
        // Offset of table with the translation strings index: right after the original strings index table
83
        $translationsIndexOffset = $originalsIndexOffset + $originalsIndexSize;
84
85
        // Size of table with the translation strings index
86
        $translationsIndexSize = $numEntries * (4 + 4);
87
88
        // Hashing table starts after the header and after the index table
89
        $originalsStringsOffset = $translationsIndexOffset + $translationsIndexSize;
90
91
        // Translations start after the keys
92
        $translationsStringsOffset = $originalsStringsOffset + strlen($originalsTable);
93
94
        // Let's generate the .mo file binary data
95
        $mo = '';
96
97
        // Magic number
98
        $mo .= pack('L', 0x950412de);
99
100
        // File format revision
101
        $mo .= pack('L', 0);
102
103
        // Number of strings
104
        $mo .= pack('L', $numEntries);
105
106
        // Offset of table with original strings
107
        $mo .= pack('L', $originalsIndexOffset);
108
109
        // Offset of table with translation strings
110
        $mo .= pack('L', $translationsIndexOffset);
111
112
        // Size of hashing table: we don't use it.
113
        $mo .= pack('L', 0);
114
115
        // Offset of hashing table: it would start right after the translations index table
116
        $mo .= pack('L', $translationsIndexOffset + $translationsIndexSize);
117
118
        // Write the lengths & offsets of the original strings
119 View Code Duplication
        foreach ($originalsIndex as $info) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
120
            $mo .= pack('L', $info['length']);
121
            $mo .= pack('L', $originalsStringsOffset + $info['relativeOffset']);
122
        }
123
124
        // Write the lengths & offsets of the translated strings
125 View Code Duplication
        foreach ($translationsIndex as $info) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
126
            $mo .= pack('L', $info['length']);
127
            $mo .= pack('L', $translationsStringsOffset + $info['relativeOffset']);
128
        }
129
130
        // Write original strings
131
        $mo .= $originalsTable;
132
133
        // Write translation strings
134
        $mo .= $translationsTable;
135
136
        return $mo;
137
    }
138
139
    private static function hasPluralTranslations(Translation $translation): bool
140
    {
141
        if (!$translation->getPlural()) {
142
            return false;
143
        }
144
145
        return implode('', $translation->getPluralTranslations()) !== '';
146
    }
147
}
148