Passed
Pull Request — master (#5)
by Radovan
02:14
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
20
use function array_key_exists;
21
use function array_key_last;
22
use function is_array;
23
use function vsprintf;
24
25
/**
26
 * Class Translator
27
 *
28
 * @package Bckp\Translator
29
 */
30
class Translator implements Interfaces\Translator
31
{
32
	/** @var callable function(string $string): string */
33
	private $normalizeCallback;
34
35
	public function __construct(
36
		private readonly Catalogue $catalogue,
37
		private readonly ?Diagnostics $diagnostics = null
38
	) {
39
		$this->normalizeCallback = [$this, 'normalize'];
40
		$this->diagnostics?->setLocale($catalogue->locale());
41
	}
42
43
	public function normalize(string $string): string
44
	{
45
		return str_replace(
46
			['%label', '%value', '%name'],
47
			['%%label', '%%value', '%%name'],
48
			$string
49
		);
50
	}
51
52
	public function setNormalizeCallback(callable $callback): void
53
	{
54
		$this->normalizeCallback = $callback;
55
	}
56
57
	public function translate(string|Stringable $message, mixed ...$parameters): string
58
	{
59
		$message = (string) $message;
60
61
		if (empty($message)) {
62
			return '';
63
		}
64
65
		$translation = $this->catalogue->get($message);
66
		if (!$translation) {
67
			$this->untranslated($message);
68
			return $message;
69
		}
70
71
		// Plural option is returned, we need to choose the right one
72
		if (is_array($translation)) {
73
			$plural = is_numeric($parameters[0] ?? null) ? $this->catalogue->plural((int) $parameters[0]) : Plural::Other;
74
			$translation = $this->getVariant($message, $translation, $plural);
75
		}
76
77
		if (!empty($parameters)) {
78
			$translation = ($this->normalizeCallback)($translation);
79
			$translation = @vsprintf($translation, $parameters);
80
		}
81
82
		return $translation;
83
	}
84
85
	/**
86
	 * @param array<string, string> $translations
87
	 */
88
	public function getVariant(string $message, array $translations, Plural $plural): string
89
	{
90
		if (!array_key_exists($plural->value, $translations)) {
91
			$this->warn(
92
				'Plural form not defined. (message: %s, form: %s)',
93
				$message,
94
				$plural->value,
95
			);
96
		}
97
98
		return $translations[$plural->value] ?? $translations[array_key_last($translations)];
99
	}
100
101
	/**
102
	 * @param string $message
103
	 */
104
	protected function untranslated(string $message): void
105
	{
106
		$this->diagnostics?->untranslated($message);
107
	}
108
109
	/**
110
	 * @param string $message
111
	 * @param mixed ...$parameters
112
	 * @return string
113
	 */
114
	protected function warn(string $message, ...$parameters): string
115
	{
116
		if (!empty($parameters)) {
117
			$message = @vsprintf($message, $parameters);
118
		} // Intentionally @ as parameter count can mismatch
119
120
		$this->diagnostics?->warning($message);
121
122
		return $message;
123
	}
124
}
125