1<?php
2
3namespace Gettext;
4
5/**
6 * Class to manage a translation string.
7 */
8class Translation
9{
10    protected $id;
11    protected $context;
12    protected $original;
13    protected $translation = '';
14    protected $plural;
15    protected $pluralTranslation = [];
16    protected $references = [];
17    protected $comments = [];
18    protected $extractedComments = [];
19    protected $flags = [];
20    protected $disabled = false;
21
22    /**
23     * Generates the id of a translation (context + glue + original).
24     *
25     * @param string $context
26     * @param string $original
27     *
28     * @return string
29     */
30    public static function generateId($context, $original)
31    {
32        return "{$context}\004{$original}";
33    }
34
35    /**
36     * Create a new instance of a Translation object.
37     *
38     * This is a factory method that will work even when Translation is extended.
39     *
40     * @param string $context  The context of the translation
41     * @param string $original The original string
42     * @param string $plural   The original plural string
43     * @return static New Translation instance
44     */
45    public static function create($context, $original, $plural = '')
46    {
47        return new static($context, $original, $plural);
48    }
49
50    /**
51     * Construct.
52     *
53     * @param string $context  The context of the translation
54     * @param string $original The original string
55     * @param string $plural   The original plural string
56     */
57    public function __construct($context, $original, $plural = '')
58    {
59        $this->context = (string) $context;
60        $this->original = (string) $original;
61
62        $this->setPlural($plural);
63    }
64
65    /**
66     * Clones this translation.
67     *
68     * @param null|string $context  Optional new context
69     * @param null|string $original Optional new original
70     *
71     * @return Translation
72     */
73    public function getClone($context = null, $original = null)
74    {
75        $new = clone $this;
76
77        if ($context !== null) {
78            $new->context = (string) $context;
79        }
80
81        if ($original !== null) {
82            $new->original = (string) $original;
83        }
84
85        return $new;
86    }
87
88    /**
89     * Sets the id of this translation.
90     * @warning The use of this function to set a custom ID will prevent
91     *  Translations::find from matching this translation.
92     *
93     * @param string $id
94     */
95    public function setId($id)
96    {
97        $this->id = $id;
98    }
99
100
101    /**
102     * Returns the id of this translation.
103     *
104     * @return string
105     */
106    public function getId()
107    {
108        if ($this->id === null) {
109            return static::generateId($this->context, $this->original);
110        }
111        return $this->id;
112    }
113
114    /**
115     * Checks whether the translation matches with the arguments.
116     *
117     * @param string $context
118     * @param string $original
119     *
120     * @return bool
121     */
122    public function is($context, $original = '')
123    {
124        return (($this->context === $context) && ($this->original === $original)) ? true : false;
125    }
126
127    /**
128     * Enable or disable the translation
129     *
130     * @param bool $disabled
131     *
132     * @return self
133     */
134    public function setDisabled($disabled)
135    {
136        $this->disabled = (bool) $disabled;
137
138        return $this;
139    }
140
141    /**
142     * Returns whether the translation is disabled
143     *
144     * @return bool
145     */
146    public function isDisabled()
147    {
148        return $this->disabled;
149    }
150
151    /**
152     * Gets the original string.
153     *
154     * @return string
155     */
156    public function getOriginal()
157    {
158        return $this->original;
159    }
160
161    /**
162     * Checks if the original string is empty or not.
163     *
164     * @return bool
165     */
166    public function hasOriginal()
167    {
168        return ($this->original !== '') ? true : false;
169    }
170
171    /**
172     * Sets the translation string.
173     *
174     * @param string $translation
175     *
176     * @return self
177     */
178    public function setTranslation($translation)
179    {
180        $this->translation = (string) $translation;
181
182        return $this;
183    }
184
185    /**
186     * Gets the translation string.
187     *
188     * @return string
189     */
190    public function getTranslation()
191    {
192        return $this->translation;
193    }
194
195    /**
196     * Checks if the translation string is empty or not.
197     *
198     * @return bool
199     */
200    public function hasTranslation()
201    {
202        return ($this->translation !== '') ? true : false;
203    }
204
205    /**
206     * Sets the plural translation string.
207     *
208     * @param string $plural
209     *
210     * @return self
211     */
212    public function setPlural($plural)
213    {
214        $this->plural = (string) $plural;
215
216        return $this;
217    }
218
219    /**
220     * Gets the plural translation string.
221     *
222     * @return string
223     */
224    public function getPlural()
225    {
226        return $this->plural;
227    }
228
229    /**
230     * Checks if the plural translation string is empty or not.
231     *
232     * @return bool
233     */
234    public function hasPlural()
235    {
236        return ($this->plural !== '') ? true : false;
237    }
238
239    /**
240     * Set a new plural translation.
241     *
242     * @param array $plural
243     *
244     * @return self
245     */
246    public function setPluralTranslations(array $plural)
247    {
248        $this->pluralTranslation = $plural;
249
250        return $this;
251    }
252
253    /**
254     * Gets all plural translations.
255     *
256     * @param int $size
257     *
258     * @return array
259     */
260    public function getPluralTranslations($size = null)
261    {
262        if ($size === null) {
263            return $this->pluralTranslation;
264        }
265
266        $current = count($this->pluralTranslation);
267
268        if ($size > $current) {
269            return $this->pluralTranslation + array_fill(0, $size, '');
270        }
271
272        if ($size < $current) {
273            return array_slice($this->pluralTranslation, 0, $size);
274        }
275
276        return $this->pluralTranslation;
277    }
278
279    /**
280     * Checks if there are any plural translation.
281     *
282     * @param bool $checkContent
283     *
284     * @return bool
285     */
286    public function hasPluralTranslations($checkContent = false)
287    {
288        if ($checkContent) {
289            return implode('', $this->pluralTranslation) !== '';
290        }
291
292        return !empty($this->pluralTranslation);
293    }
294
295    /**
296     * Removes all plural translations.
297     *
298     * @return self
299     */
300    public function deletePluralTranslation()
301    {
302        $this->pluralTranslation = [];
303
304        return $this;
305    }
306
307    /**
308     * Gets the context of this translation.
309     *
310     * @return string
311     */
312    public function getContext()
313    {
314        return $this->context;
315    }
316
317    /**
318     * Checks if the context is empty or not.
319     *
320     * @return bool
321     */
322    public function hasContext()
323    {
324        return (isset($this->context) && ($this->context !== '')) ? true : false;
325    }
326
327    /**
328     * Adds a new reference for this translation.
329     *
330     * @param string   $filename The file path where the translation has been found
331     * @param null|int $line     The line number where the translation has been found
332     *
333     * @return self
334     */
335    public function addReference($filename, $line = null)
336    {
337        $key = "{$filename}:{$line}";
338        $this->references[$key] = [$filename, $line];
339
340        return $this;
341    }
342
343    /**
344     * Checks if the translation has any reference.
345     *
346     * @return bool
347     */
348    public function hasReferences()
349    {
350        return !empty($this->references);
351    }
352
353    /**
354     * Return all references for this translation.
355     *
356     * @return array
357     */
358    public function getReferences()
359    {
360        return array_values($this->references);
361    }
362
363    /**
364     * Removes all references.
365     *
366     * @return self
367     */
368    public function deleteReferences()
369    {
370        $this->references = [];
371
372        return $this;
373    }
374
375    /**
376     * Adds a new comment for this translation.
377     *
378     * @param string $comment
379     *
380     * @return self
381     */
382    public function addComment($comment)
383    {
384        if (!in_array($comment, $this->comments, true)) {
385            $this->comments[] = $comment;
386        }
387
388        return $this;
389    }
390
391    /**
392     * Checks if the translation has any comment.
393     *
394     * @return bool
395     */
396    public function hasComments()
397    {
398        return isset($this->comments[0]);
399    }
400
401    /**
402     * Returns all comments for this translation.
403     *
404     * @return array
405     */
406    public function getComments()
407    {
408        return $this->comments;
409    }
410
411    /**
412     * Removes all comments.
413     *
414     * @return self
415     */
416    public function deleteComments()
417    {
418        $this->comments = [];
419
420        return $this;
421    }
422
423    /**
424     * Adds a new extracted comment for this translation.
425     *
426     * @param string $comment
427     *
428     * @return self
429     */
430    public function addExtractedComment($comment)
431    {
432        if (!in_array($comment, $this->extractedComments, true)) {
433            $this->extractedComments[] = $comment;
434        }
435
436        return $this;
437    }
438
439    /**
440     * Checks if the translation has any extracted comment.
441     *
442     * @return bool
443     */
444    public function hasExtractedComments()
445    {
446        return isset($this->extractedComments[0]);
447    }
448
449    /**
450     * Returns all extracted comments for this translation.
451     *
452     * @return array
453     */
454    public function getExtractedComments()
455    {
456        return $this->extractedComments;
457    }
458
459    /**
460     * Removes all extracted comments.
461     *
462     * @return self
463     */
464    public function deleteExtractedComments()
465    {
466        $this->extractedComments = [];
467
468        return $this;
469    }
470
471    /**
472     * Adds a new flag for this translation.
473     *
474     * @param string $flag
475     *
476     * @return self
477     */
478    public function addFlag($flag)
479    {
480        if (!in_array($flag, $this->flags, true)) {
481            $this->flags[] = $flag;
482        }
483
484        return $this;
485    }
486
487    /**
488     * Checks if the translation has any flag.
489     *
490     * @return bool
491     */
492    public function hasFlags()
493    {
494        return isset($this->flags[0]);
495    }
496
497    /**
498     * Returns all extracted flags for this translation.
499     *
500     * @return array
501     */
502    public function getFlags()
503    {
504        return $this->flags;
505    }
506
507    /**
508     * Removes all flags.
509     *
510     * @return self
511     */
512    public function deleteFlags()
513    {
514        $this->flags = [];
515
516        return $this;
517    }
518
519    /**
520     * Merges this translation with other translation.
521     *
522     * @param Translation $translation The translation to merge with
523     * @param int         $options
524     *
525     * @return self
526     */
527    public function mergeWith(Translation $translation, $options = Merge::DEFAULTS)
528    {
529        Merge::mergeTranslation($translation, $this, $options);
530        Merge::mergeReferences($translation, $this, $options);
531        Merge::mergeComments($translation, $this, $options);
532        Merge::mergeExtractedComments($translation, $this, $options);
533        Merge::mergeFlags($translation, $this, $options);
534
535        return $this;
536    }
537}
538