Translations::getHeaders()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Gettext;
4
5
use Gettext\Languages\Language;
6
use BadMethodCallException;
7
use InvalidArgumentException;
8
use ArrayObject;
9
10
/**
11
 * Class to manage a collection of translations.
12
 *
13
 * @method static fromBladeFile(string $filename, array $options = [])
14
 * @method static fromBladeString(string $string, array $options = [])
15
 * @method addFromBladeFile(string $filename, array $options = [])
16
 * @method addFromBladeString(string $string, array $options = [])
17
 * @method static fromCsvFile(string $filename, array $options = [])
18
 * @method static fromCsvString(string $string, array $options = [])
19
 * @method addFromCsvFile(string $filename, array $options = [])
20
 * @method addFromCsvString(string $string, array $options = [])
21
 * @method toCsvFile(string $filename, array $options = [])
22
 * @method toCsvString(array $options = [])
23
 * @method static fromCsvDictionaryFile(string $filename, array $options = [])
24
 * @method static fromCsvDictionaryString(string $string, array $options = [])
25
 * @method addFromCsvDictionaryFile(string $filename, array $options = [])
26
 * @method addFromCsvDictionaryString(string $string, array $options = [])
27
 * @method toCsvDictionaryFile(string $filename, array $options = [])
28
 * @method toCsvDictionaryString(array $options = [])
29
 * @method static fromJedFile(string $filename, array $options = [])
30
 * @method static fromJedString(string $string, array $options = [])
31
 * @method addFromJedFile(string $filename, array $options = [])
32
 * @method addFromJedString(string $string, array $options = [])
33
 * @method toJedFile(string $filename, array $options = [])
34
 * @method toJedString(array $options = [])
35
 * @method static fromJsCodeFile(string $filename, array $options = [])
36
 * @method static fromJsCodeString(string $string, array $options = [])
37
 * @method addFromJsCodeFile(string $filename, array $options = [])
38
 * @method addFromJsCodeString(string $string, array $options = [])
39
 * @method static fromJsonFile(string $filename, array $options = [])
40
 * @method static fromJsonString(string $string, array $options = [])
41
 * @method addFromJsonFile(string $filename, array $options = [])
42
 * @method addFromJsonString(string $string, array $options = [])
43
 * @method toJsonFile(string $filename, array $options = [])
44
 * @method toJsonString(array $options = [])
45
 * @method static fromJsonDictionaryFile(string $filename, array $options = [])
46
 * @method static fromJsonDictionaryString(string $string, array $options = [])
47
 * @method addFromJsonDictionaryFile(string $filename, array $options = [])
48
 * @method addFromJsonDictionaryString(string $string, array $options = [])
49
 * @method toJsonDictionaryFile(string $filename, array $options = [])
50
 * @method toJsonDictionaryString(array $options = [])
51
 * @method static fromMoFile(string $filename, array $options = [])
52
 * @method static fromMoString(string $string, array $options = [])
53
 * @method addFromMoFile(string $filename, array $options = [])
54
 * @method addFromMoString(string $string, array $options = [])
55
 * @method toMoFile(string $filename, array $options = [])
56
 * @method toMoString(array $options = [])
57
 * @method static fromPhpArrayFile(string $filename, array $options = [])
58
 * @method static fromPhpArrayString(string $string, array $options = [])
59
 * @method addFromPhpArrayFile(string $filename, array $options = [])
60
 * @method addFromPhpArrayString(string $string, array $options = [])
61
 * @method toPhpArrayFile(string $filename, array $options = [])
62
 * @method toPhpArrayString(array $options = [])
63
 * @method static fromPhpCodeFile(string $filename, array $options = [])
64
 * @method static fromPhpCodeString(string $string, array $options = [])
65
 * @method addFromPhpCodeFile(string $filename, array $options = [])
66
 * @method addFromPhpCodeString(string $string, array $options = [])
67
 * @method static fromPoFile(string $filename, array $options = [])
68
 * @method static fromPoString(string $string, array $options = [])
69
 * @method addFromPoFile(string $filename, array $options = [])
70
 * @method addFromPoString(string $string, array $options = [])
71
 * @method toPoFile(string $filename, array $options = [])
72
 * @method toPoString(array $options = [])
73
 * @method static fromTwigFile(string $filename, array $options = [])
74
 * @method static fromTwigString(string $string, array $options = [])
75
 * @method addFromTwigFile(string $filename, array $options = [])
76
 * @method addFromTwigString(string $string, array $options = [])
77
 * @method static fromXliffFile(string $filename, array $options = [])
78
 * @method static fromXliffString(string $string, array $options = [])
79
 * @method addFromXliffFile(string $filename, array $options = [])
80
 * @method addFromXliffString(string $string, array $options = [])
81
 * @method toXliffFile(string $filename, array $options = [])
82
 * @method toXliffString(array $options = [])
83
 * @method static fromYamlFile(string $filename, array $options = [])
84
 * @method static fromYamlString(string $string, array $options = [])
85
 * @method addFromYamlFile(string $filename, array $options = [])
86
 * @method addFromYamlString(string $string, array $options = [])
87
 * @method toYamlFile(string $filename, array $options = [])
88
 * @method toYamlString(array $options = [])
89
 * @method static fromYamlDictionaryFile(string $filename, array $options = [])
90
 * @method static fromYamlDictionaryString(string $string, array $options = [])
91
 * @method addFromYamlDictionaryFile(string $filename, array $options = [])
92
 * @method addFromYamlDictionaryString(string $string, array $options = [])
93
 * @method toYamlDictionaryFile(string $filename, array $options = [])
94
 * @method toYamlDictionaryString(array $options = [])
95
 */
96
class Translations extends ArrayObject
97
{
98
    const HEADER_LANGUAGE = 'Language';
99
    const HEADER_PLURAL = 'Plural-Forms';
100
    const HEADER_DOMAIN = 'X-Domain';
101
102
    public static $options = [
103
        'defaultHeaders' => [
104
            'Project-Id-Version' => '',
105
            'Report-Msgid-Bugs-To' => '',
106
            'Last-Translator' => '',
107
            'Language-Team' => '',
108
            'MIME-Version' => '1.0',
109
            'Content-Type' => 'text/plain; charset=UTF-8',
110
            'Content-Transfer-Encoding' => '8bit',
111
        ],
112
        'headersSorting' => false,
113
        'defaultDateHeaders' => [
114
            'POT-Creation-Date',
115
            'PO-Revision-Date',
116
        ],
117
    ];
118
119
    private $headers;
120
121
    /**
122
     * @see ArrayObject::__construct()
123
     */
124
    public function __construct($input = [], $flags = 0, $iterator_class = 'ArrayIterator')
125
    {
126
        $this->headers = static::$options['defaultHeaders'];
127
128
        foreach (static::$options['defaultDateHeaders'] as $header) {
129
            $this->headers[$header] = date('c');
130
        }
131
132
        $this->headers[self::HEADER_LANGUAGE] = '';
133
134
        parent::__construct($input, $flags, $iterator_class);
135
    }
136
137
    /**
138
     * Magic method to create new instances using extractors
139
     * For example: Translations::fromMoFile($filename, $options);.
140
     *
141
     * @return Translations
142
     */
143
    public static function __callStatic($name, $arguments)
144
    {
145
        if (!preg_match('/^from(\w+)(File|String)$/i', $name, $matches)) {
146
            throw new BadMethodCallException("The method $name does not exists");
147
        }
148
149
        return call_user_func_array([new static(), 'add'.ucfirst($name)], $arguments);
150
    }
151
152
    /**
153
     * Magic method to import/export the translations to a specific format
154
     * For example: $translations->toMoFile($filename, $options);
155
     * For example: $translations->addFromMoFile($filename, $options);.
156
     *
157
     * @return self|bool
158
     */
159
    public function __call($name, $arguments)
160
    {
161
        if (!preg_match('/^(addFrom|to)(\w+)(File|String)$/i', $name, $matches)) {
162
            throw new BadMethodCallException("The method $name does not exists");
163
        }
164
165
        if ($matches[1] === 'addFrom') {
166
            $extractor = 'Gettext\\Extractors\\'.$matches[2].'::from'.$matches[3];
167
            $source = array_shift($arguments);
168
            $options = array_shift($arguments) ?: [];
169
170
            call_user_func($extractor, $source, $this, $options);
171
172
            return $this;
173
        }
174
175
        $generator = 'Gettext\\Generators\\'.$matches[2].'::to'.$matches[3];
176
177
        array_unshift($arguments, $this);
178
179
        return call_user_func_array($generator, $arguments);
180
    }
181
182
    /**
183
     * Magic method to clone each translation on clone the translations object.
184
     */
185
    public function __clone()
186
    {
187
        $array = [];
188
189
        foreach ($this as $key => $translation) {
190
            $array[$key] = clone $translation;
191
        }
192
193
        $this->exchangeArray($array);
194
    }
195
196
    /**
197
     * Control the new translations added.
198
     *
199
     * @param mixed       $index
200
     * @param Translation $value
201
     *
202
     * @throws InvalidArgumentException If the value is not an instance of Gettext\Translation
203
     *
204
     * @return Translation
205
     */
206
    public function offsetSet($index, $value)
207
    {
208
        if (!($value instanceof Translation)) {
209
            throw new InvalidArgumentException(
210
                'Only instances of Gettext\\Translation must be added to a Gettext\\Translations'
211
            );
212
        }
213
214
        $id = $value->getId();
215
216
        if ($this->offsetExists($id)) {
217
            $this[$id]->mergeWith($value);
218
219
            return $this[$id];
220
        }
221
222
        parent::offsetSet($id, $value);
223
224
        return $value;
225
    }
226
227
    /**
228
     * Set the plural definition.
229
     *
230
     * @param int    $count
231
     * @param string $rule
232
     *
233
     * @return self
234
     */
235
    public function setPluralForms($count, $rule)
236
    {
237
        $this->setHeader(self::HEADER_PLURAL, "nplurals={$count}; plural={$rule};");
238
239
        return $this;
240
    }
241
242
    /**
243
     * Returns the parsed plural definition.
244
     *
245
     * @param null|array [count, rule]
246
     */
247
    public function getPluralForms()
248
    {
249
        $header = $this->getHeader(self::HEADER_PLURAL);
250
251
        if (!empty($header)
252
            && preg_match('/^nplurals\s*=\s*(\d+)\s*;\s*plural\s*=\s*([^;]+)\s*;$/', $header, $matches)
253
        ) {
254
            return [intval($matches[1]), $matches[2]];
255
        }
256
    }
257
258
    /**
259
     * Set a new header.
260
     *
261
     * @param string $name
262
     * @param string $value
263
     *
264
     * @return self
265
     */
266
    public function setHeader($name, $value)
267
    {
268
        $name = trim($name);
269
        $this->headers[$name] = trim($value);
270
271
        return $this;
272
    }
273
274
    /**
275
     * Returns a header value.
276
     *
277
     * @param string $name
278
     *
279
     * @return null|string
280
     */
281
    public function getHeader($name)
282
    {
283
        return isset($this->headers[$name]) ? $this->headers[$name] : null;
284
    }
285
286
    /**
287
     * Returns all header for this translations (in alphabetic order).
288
     *
289
     * @return array
290
     */
291
    public function getHeaders()
292
    {
293
        if (static::$options['headersSorting']) {
294
            ksort($this->headers);
295
        }
296
297
        return $this->headers;
298
    }
299
300
    /**
301
     * Removes all headers.
302
     *
303
     * @return self
304
     */
305
    public function deleteHeaders()
306
    {
307
        $this->headers = [];
308
309
        return $this;
310
    }
311
312
    /**
313
     * Removes one header.
314
     *
315
     * @param string $name
316
     *
317
     * @return self
318
     */
319
    public function deleteHeader($name)
320
    {
321
        unset($this->headers[$name]);
322
323
        return $this;
324
    }
325
326
    /**
327
     * Returns the language value.
328
     *
329
     * @return string $language
330
     */
331
    public function getLanguage()
332
    {
333
        return $this->getHeader(self::HEADER_LANGUAGE);
334
    }
335
336
    /**
337
     * Sets the language and the plural forms.
338
     *
339
     * @param string $language
340
     *
341
     * @throws InvalidArgumentException if the language hasn't been recognized
342
     *
343
     * @return self
344
     */
345
    public function setLanguage($language)
346
    {
347
        $this->setHeader(self::HEADER_LANGUAGE, trim($language));
348
349
        if (($info = Language::getById($language))) {
350
            return $this->setPluralForms(count($info->categories), $info->formula);
351
        }
352
353
        throw new InvalidArgumentException(sprintf('The language "%s" is not valid', $language));
354
    }
355
356
    /**
357
     * Checks whether the language is empty or not.
358
     *
359
     * @return bool
360
     */
361
    public function hasLanguage()
362
    {
363
        $language = $this->getLanguage();
364
365
        return (is_string($language) && ($language !== '')) ? true : false;
366
    }
367
368
    /**
369
     * Set a new domain for this translations.
370
     *
371
     * @param string $domain
372
     *
373
     * @return self
374
     */
375
    public function setDomain($domain)
376
    {
377
        $this->setHeader(self::HEADER_DOMAIN, trim($domain));
378
379
        return $this;
380
    }
381
382
    /**
383
     * Returns the domain.
384
     *
385
     * @return string
386
     */
387
    public function getDomain()
388
    {
389
        return $this->getHeader(self::HEADER_DOMAIN);
390
    }
391
392
    /**
393
     * Checks whether the domain is empty or not.
394
     *
395
     * @return bool
396
     */
397
    public function hasDomain()
398
    {
399
        $domain = $this->getDomain();
400
401
        return (is_string($domain) && ($domain !== '')) ? true : false;
402
    }
403
404
    /**
405
     * Search for a specific translation.
406
     *
407
     * @param string|Translation $context  The context of the translation or a translation instance
408
     * @param string             $original The original string
409
     *
410
     * @return Translation|false
411
     */
412
    public function find($context, $original = '')
413
    {
414
        if ($context instanceof Translation) {
415
            $id = $context->getId();
416
        } else {
417
            $id = Translation::generateId($context, $original);
418
        }
419
420
        return $this->offsetExists($id) ? $this[$id] : false;
421
    }
422
423
    /**
424
     * Count all elements translated
425
     *
426
     * @return integer
427
     */
428
    public function countTranslated()
429
    {
430
        $callback = function (Translation $v) {
431
            return ($v->hasTranslation()) ? $v->getTranslation() : null;
432
        };
433
434
        return count(array_filter(get_object_vars($this), $callback));
435
    }
436
437
    /**
438
     * Creates and insert/merges a new translation.
439
     *
440
     * @param string $context  The translation context
441
     * @param string $original The translation original string
442
     * @param string $plural   The translation original plural string
443
     *
444
     * @return Translation The translation created
445
     */
446
    public function insert($context, $original, $plural = '')
447
    {
448
        return $this->offsetSet(null, new Translation($context, $original, $plural));
449
    }
450
451
    /**
452
     * Merges this translations with other translations.
453
     *
454
     * @param Translations $translations The translations instance to merge with
455
     * @param int          $options
456
     *
457
     * @return self
458
     */
459
    public function mergeWith(Translations $translations, $options = Merge::DEFAULTS)
460
    {
461
        Merge::mergeHeaders($translations, $this, $options);
462
        Merge::mergeTranslations($translations, $this, $options);
463
464
        return $this;
465
    }
466
}
467