Translator::warn()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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