Passed
Pull Request — master (#5)
by Radovan
01:51
created

Translator::getMessage()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 8
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 16
rs 9.2222
1
<?php
2
3
/**
4
 * BCKP Translator
5
 * (c) Radovan Kepák
6
 *
7
 * For the full copyright and license information, please view
8
 * the file license.md that was distributed with this source code.
9
 *
10
 * @author Radovan Kepak <[email protected]>
11
 */
12
13
declare(strict_types=1);
14
15
namespace Bckp\Translator;
16
17
use Bckp\Translator\Interfaces\Diagnostics;
18
use Stringable;
19
use function array_key_exists;
20
use function array_key_last;
21
use function is_array;
22
use function vsprintf;
23
24
/**
25
 * Class Translator
26
 *
27
 * @package Bckp\Translator
28
 */
29
class Translator implements Interfaces\Translator
30
{
31
    /** @var callable function(string $string): string */
32
    private $normalizeCallback;
33
34
    public function __construct(
35
        private readonly Catalogue $catalogue,
36
        private readonly ?Diagnostics $diagnostics = null
37
    ) {
38
        $this->normalizeCallback = [$this, 'normalize'];
39
        $this->diagnostics?->setLocale($catalogue->locale());
40
    }
41
42
    public function normalize(string $string): string
43
    {
44
        return str_replace(
45
            ['%label', '%value', '%name'],
46
            ['%%label', '%%value', '%%name'],
47
            $string
48
        );
49
    }
50
51
    public function setNormalizeCallback(callable $callback): void
52
    {
53
        $this->normalizeCallback = $callback;
54
    }
55
56
    public function translate(string|Stringable $message, mixed ...$parameters): string
57
    {
58
        $message = (string) $message;
59
60
        if (empty($message)) {
61
            return '';
62
        }
63
64
        $translation = $this->catalogue->get($message);
65
        if (!$translation) {
66
            $this->untranslated($message);
67
            return $message;
68
        }
69
70
        // Plural option is returned, we need to choose the right one
71
        if (is_array($translation)) {
1 ignored issue
show
introduced by
The condition is_array($translation) is always false.
Loading history...
72
            $plural = is_numeric($parameters[0] ?? null) ? $this->catalogue->plural((int) $parameters[0]) : Plural::Other;
73
            $translation = $this->getVariant($message, $translation, $plural);
74
        }
75
76
        if (!empty($parameters)) {
77
            $translation = ($this->normalizeCallback)($translation);
78
            $translation = @vsprintf($translation, $parameters);
79
        }
80
81
        return $translation;
82
    }
83
84
    /**
85
     * @param array<string, string> $translations
86
     */
87
    public function getVariant(string $message, array $translations, Plural $plural): string
88
    {
89
        if (!array_key_exists($plural->value, $translations)) {
90
            $this->warn(
91
                'Plural form not defined. (message: %s, form: %s)',
92
                $message,
93
                $plural->value,
94
            );
95
        }
96
97
        return $translations[$plural->value] ?? $translations[array_key_last($translations)];
98
    }
99
100
    /**
101
     * @param string $message
102
     */
103
    protected function untranslated(string $message): void
104
    {
105
        $this->diagnostics?->untranslated($message);
106
    }
107
108
    /**
109
     * @param string $message
110
     * @param mixed ...$parameters
111
     * @return string
112
     */
113
    protected function warn(string $message, ...$parameters): string
114
    {
115
        if (!empty($parameters)) {
116
            $message = @vsprintf($message, $parameters);
117
        } // Intentionally @ as parameter count can mismatch
118
119
        $this->diagnostics?->warning($message);
120
121
        return $message;
122
    }
123
}
124