TranslatorExtension   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 123
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 66
c 0
b 0
f 0
dl 0
loc 123
rs 10
wmc 17

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getConfigSchema() 0 22 3
B beforeCompile() 0 35 7
A loadConfiguration() 0 44 3
A __construct() 0 9 4
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Nette extension for bckp/translator
7
 * (c) Radovan Kepák
8
 *
9
 * For the full copyright and license information, please view the file license.md that was distributed with this source code.
10
 *
11
 * @author Radovan Kepak <[email protected]>
12
 *  --------------------------------------------------------------------------
13
 */
14
15
namespace Bckp\Translator\Nette\Bridges\TranslatorDI;
16
17
use Bckp\Translator\CatalogueBuilder;
18
use Bckp\Translator\Nette\Diagnostics\TranslatorPanel;
19
use Bckp\Translator\Nette\LocaleProvider;
20
use Bckp\Translator\Nette\NetteTranslator;
21
use Bckp\Translator\Nette\Resolvers\LocaleResolver;
22
use Bckp\Translator\Nette\TranslatorProvider;
23
use Bckp\Translator\PluralProvider;
24
use Latte\Essential\TranslatorExtension as LatteTranslatorExtension;
25
use Nette\DI\CompilerExtension;
26
use Nette\DI\Definitions\FactoryDefinition;
27
use Nette\DI\Definitions\Reference;
28
use Nette\DI\Definitions\ServiceDefinition;
29
use Nette\DI\Definitions\Statement;
30
use Nette\Localization\Translator;
31
use Nette\Schema\Context;
32
use Nette\Schema\Expect;
33
use Nette\Schema\Schema;
34
use Nette\Utils\Finder;
35
36
/**
37
 * @api
38
 * @method object{languages: string[], resolvers: LocaleResolver[], pluralProvider: class-string, paths: string[], debugger: bool, injectLatte: bool } getConfig()
39
 */
40
final class TranslatorExtension extends CompilerExtension
41
{
42
	public function __construct(
43
		private readonly string $tempDir
44
	) {
45
		// Create temp directory
46
		if (!is_dir($this->tempDir) && !mkdir($concurrentDirectory = $this->tempDir, 0o777, true)
47
			&& !is_dir(
48
				$concurrentDirectory
49
			)) {
50
			throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
51
		}
52
	}
53
54
	#[\Override]
55
	public function getConfigSchema(): Schema
56
	{
57
		return Expect::structure([
58
			'languages' => Expect::listOf('string')->transform(static function (array $languages, Context $context): ?array {
59
				$languages = array_map('strtolower', $languages);
60
				$languages = array_unique($languages);
61
62
				foreach ($languages as $language) {
63
					if (!preg_match('/^[a-z]{2}(_[A-Z]{2})?$/', $language)) {
64
						$context->addError("Invalid language code: $language", 'translator.languages.validation');
65
						return null;
66
					}
67
				}
68
69
				return $languages;
70
			})->default([])->required(),
71
			'resolvers' => Expect::listOf('string|Nette\DI\Definitions\Statement')->default([]),
72
			'pluralProvider' => Expect::type('string|Nette\DI\Definitions\Statement')->default(PluralProvider::class),
73
			'paths' => Expect::arrayOf('string')->required(),
74
			'debugger' => Expect::bool()->default('%debugMode%'),
75
			'injectLatte' => Expect::bool()->default(true),
76
		]);
77
	}
78
79
	#[\Override]
80
	public function loadConfiguration(): void
81
	{
82
		$config = $this->getConfig();
83
		$builder = $this->getContainerBuilder();
84
85
		// Setup translator
86
		if ($config->debugger) {
87
			$builder->addDefinition($this->prefix('diagnostics'))
88
					->setFactory(TranslatorPanel::class)
89
					->addSetup('setResolvers', [$config->languages, ...$config->resolvers]);
90
91
		}
92
93
		// Setup LocaleProvider
94
		$builder->addDefinition($this->prefix('localeProvider'))
95
			->setFactory(LocaleProvider::class, [$config->languages, ...$config->resolvers]);
96
97
		// Translator provider
98
		$translatorProvider = $builder->addDefinition($this->prefix('translatorProvider'))
99
			->setFactory(TranslatorProvider::class)
100
			->setAutowired(false);
101
102
		// Plural provider
103
		$pluralProvider = $builder->addDefinition($this->prefix('pluralProvider'))
104
			->setFactory($config->pluralProvider)
105
			->setAutowired(false);
106
107
		// Translator itself
108
		$builder->addDefinition($this->prefix('translator'))
109
			->setFactory(NetteTranslator::class, [
110
				'@' . $this->prefix('translatorProvider'),
111
				'@' . $this->prefix('localeProvider'),
112
			])
113
			->setAutowired();
114
115
		// Catalogues
116
		foreach ($config->languages as $language) {
117
			$translatorProvider->addSetup('addCatalogueBuilder', [
118
				$builder->addDefinition($this->prefix('catalogue.' . $language))
119
						->setFactory(CatalogueBuilder::class, [
120
							$pluralProvider,
121
							$this->tempDir,
122
							$language,
123
						]),
124
			]);
125
		}
126
	}
127
128
	#[\Override]
129
	public function beforeCompile(): void
130
	{
131
		$config = $this->getConfig();
132
		$builder = $this->getContainerBuilder();
133
134
		# Setup catalogue files
135
		foreach ($config->languages as $language) {
136
			/** @var ServiceDefinition $catalogue */
137
			$catalogue = $builder->getDefinition($this->prefix('catalogue.' . $language));
138
139
			foreach (Finder::findFiles("*.{$language}.neon")->in(...$config->paths) as $file) {
140
				$catalogue->addSetup('addFile', [$file->getPathname()]);
141
			}
142
		}
143
144
		# Setup bar
145
		if (
146
			$config->debugger
147
			&& $builder->hasDefinition($this->prefix('diagnostics'))
148
		) {
149
			/** @var ServiceDefinition $translatorProvider */
150
			$translatorProvider = $builder->getDefinition($this->prefix('translatorProvider'));
151
			$translatorProvider->addSetup('@Tracy\Bar::addPanel', [$builder->getDefinition($this->prefix('diagnostics'))]);
152
		}
153
154
		# Auto setup nette translator to latte
155
		if ($config->injectLatte && $builder->hasDefinition('latte.latteFactory')) {
156
			/** @var FactoryDefinition $latteFactory */
157
			$latteFactory = $builder->getDefinition('latte.latteFactory');
158
			$latteFactory->getResultDefinition()
159
				->addSetup('addExtension', [
160
					new Statement(LatteTranslatorExtension::class, [new Reference(Translator::class)]),
161
				])
162
				->setAutowired(false);
163
		}
164
	}
165
166
}
167