PluginProbe
Independent Analytics – WordPress Analytics Plugin / 1.28.2
Independent Analytics – WordPress Analytics Plugin v1.28.2
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 All 120 releases
independent-analytics / vendor / symfony / translation / Translator.php
Translator.php
407 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 namespace IAWP_SCOPED\Symfony\Component\Translation;
12
13 use IAWP_SCOPED\Symfony\Component\Config\ConfigCacheFactory;
14 use IAWP_SCOPED\Symfony\Component\Config\ConfigCacheFactoryInterface;
15 use IAWP_SCOPED\Symfony\Component\Config\ConfigCacheInterface;
16 use IAWP_SCOPED\Symfony\Component\Translation\Exception\InvalidArgumentException;
17 use IAWP_SCOPED\Symfony\Component\Translation\Exception\NotFoundResourceException;
18 use IAWP_SCOPED\Symfony\Component\Translation\Exception\RuntimeException;
19 use IAWP_SCOPED\Symfony\Component\Translation\Formatter\IntlFormatterInterface;
20 use IAWP_SCOPED\Symfony\Component\Translation\Formatter\MessageFormatter;
21 use IAWP_SCOPED\Symfony\Component\Translation\Formatter\MessageFormatterInterface;
22 use IAWP_SCOPED\Symfony\Component\Translation\Loader\LoaderInterface;
23 use IAWP_SCOPED\Symfony\Contracts\Translation\LocaleAwareInterface;
24 use IAWP_SCOPED\Symfony\Contracts\Translation\TranslatorInterface;
25 // Help opcache.preload discover always-needed symbols
26 \class_exists(MessageCatalogue::class);
27 /**
28 * @author Fabien Potencier <fabien@symfony.com>
29 */
30 class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface
31 {
32 /**
33 * @var MessageCatalogueInterface[]
34 */
35 protected $catalogues = [];
36 /**
37 * @var string
38 */
39 private $locale;
40 /**
41 * @var string[]
42 */
43 private $fallbackLocales = [];
44 /**
45 * @var LoaderInterface[]
46 */
47 private $loaders = [];
48 /**
49 * @var array
50 */
51 private $resources = [];
52 /**
53 * @var MessageFormatterInterface
54 */
55 private $formatter;
56 /**
57 * @var string
58 */
59 private $cacheDir;
60 /**
61 * @var bool
62 */
63 private $debug;
64 private $cacheVary;
65 /**
66 * @var ConfigCacheFactoryInterface|null
67 */
68 private $configCacheFactory;
69 /**
70 * @var array|null
71 */
72 private $parentLocales;
73 private $hasIntlFormatter;
74 /**
75 * @throws InvalidArgumentException If a locale contains invalid characters
76 */
77 public function __construct(string $locale, MessageFormatterInterface $formatter = null, string $cacheDir = null, bool $debug = \false, array $cacheVary = [])
78 {
79 $this->setLocale($locale);
80 if (null === $formatter) {
81 $formatter = new MessageFormatter();
82 }
83 $this->formatter = $formatter;
84 $this->cacheDir = $cacheDir;
85 $this->debug = $debug;
86 $this->cacheVary = $cacheVary;
87 $this->hasIntlFormatter = $formatter instanceof IntlFormatterInterface;
88 }
89 public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory)
90 {
91 $this->configCacheFactory = $configCacheFactory;
92 }
93 /**
94 * Adds a Loader.
95 *
96 * @param string $format The name of the loader (@see addResource())
97 */
98 public function addLoader(string $format, LoaderInterface $loader)
99 {
100 $this->loaders[$format] = $loader;
101 }
102 /**
103 * Adds a Resource.
104 *
105 * @param string $format The name of the loader (@see addLoader())
106 * @param mixed $resource The resource name
107 *
108 * @throws InvalidArgumentException If the locale contains invalid characters
109 */
110 public function addResource(string $format, $resource, string $locale, string $domain = null)
111 {
112 if (null === $domain) {
113 $domain = 'messages';
114 }
115 $this->assertValidLocale($locale);
116 $locale ?: ($locale = \class_exists(\Locale::class) ? \Locale::getDefault() : 'en');
117 $this->resources[$locale][] = [$format, $resource, $domain];
118 if (\in_array($locale, $this->fallbackLocales)) {
119 $this->catalogues = [];
120 } else {
121 unset($this->catalogues[$locale]);
122 }
123 }
124 /**
125 * {@inheritdoc}
126 */
127 public function setLocale(string $locale)
128 {
129 $this->assertValidLocale($locale);
130 $this->locale = $locale;
131 }
132 /**
133 * {@inheritdoc}
134 */
135 public function getLocale()
136 {
137 return $this->locale ?: (\class_exists(\Locale::class) ? \Locale::getDefault() : 'en');
138 }
139 /**
140 * Sets the fallback locales.
141 *
142 * @param string[] $locales
143 *
144 * @throws InvalidArgumentException If a locale contains invalid characters
145 */
146 public function setFallbackLocales(array $locales)
147 {
148 // needed as the fallback locales are linked to the already loaded catalogues
149 $this->catalogues = [];
150 foreach ($locales as $locale) {
151 $this->assertValidLocale($locale);
152 }
153 $this->fallbackLocales = $this->cacheVary['fallback_locales'] = $locales;
154 }
155 /**
156 * Gets the fallback locales.
157 *
158 * @internal
159 */
160 public function getFallbackLocales() : array
161 {
162 return $this->fallbackLocales;
163 }
164 /**
165 * {@inheritdoc}
166 */
167 public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null)
168 {
169 if (null === $id || '' === $id) {
170 return '';
171 }
172 if (null === $domain) {
173 $domain = 'messages';
174 }
175 $catalogue = $this->getCatalogue($locale);
176 $locale = $catalogue->getLocale();
177 while (!$catalogue->defines($id, $domain)) {
178 if ($cat = $catalogue->getFallbackCatalogue()) {
179 $catalogue = $cat;
180 $locale = $catalogue->getLocale();
181 } else {
182 break;
183 }
184 }
185 $len = \strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX);
186 if ($this->hasIntlFormatter && ($catalogue->defines($id, $domain . MessageCatalogue::INTL_DOMAIN_SUFFIX) || \strlen($domain) > $len && 0 === \substr_compare($domain, MessageCatalogue::INTL_DOMAIN_SUFFIX, -$len, $len))) {
187 return $this->formatter->formatIntl($catalogue->get($id, $domain), $locale, $parameters);
188 }
189 return $this->formatter->format($catalogue->get($id, $domain), $locale, $parameters);
190 }
191 /**
192 * {@inheritdoc}
193 */
194 public function getCatalogue(string $locale = null)
195 {
196 if (!$locale) {
197 $locale = $this->getLocale();
198 } else {
199 $this->assertValidLocale($locale);
200 }
201 if (!isset($this->catalogues[$locale])) {
202 $this->loadCatalogue($locale);
203 }
204 return $this->catalogues[$locale];
205 }
206 /**
207 * {@inheritdoc}
208 */
209 public function getCatalogues() : array
210 {
211 return \array_values($this->catalogues);
212 }
213 /**
214 * Gets the loaders.
215 *
216 * @return LoaderInterface[]
217 */
218 protected function getLoaders()
219 {
220 return $this->loaders;
221 }
222 protected function loadCatalogue(string $locale)
223 {
224 if (null === $this->cacheDir) {
225 $this->initializeCatalogue($locale);
226 } else {
227 $this->initializeCacheCatalogue($locale);
228 }
229 }
230 protected function initializeCatalogue(string $locale)
231 {
232 $this->assertValidLocale($locale);
233 try {
234 $this->doLoadCatalogue($locale);
235 } catch (NotFoundResourceException $e) {
236 if (!$this->computeFallbackLocales($locale)) {
237 throw $e;
238 }
239 }
240 $this->loadFallbackCatalogues($locale);
241 }
242 private function initializeCacheCatalogue(string $locale) : void
243 {
244 if (isset($this->catalogues[$locale])) {
245 /* Catalogue already initialized. */
246 return;
247 }
248 $this->assertValidLocale($locale);
249 $cache = $this->getConfigCacheFactory()->cache($this->getCatalogueCachePath($locale), function (ConfigCacheInterface $cache) use($locale) {
250 $this->dumpCatalogue($locale, $cache);
251 });
252 if (isset($this->catalogues[$locale])) {
253 /* Catalogue has been initialized as it was written out to cache. */
254 return;
255 }
256 /* Read catalogue from cache. */
257 $this->catalogues[$locale] = (include $cache->getPath());
258 }
259 private function dumpCatalogue(string $locale, ConfigCacheInterface $cache) : void
260 {
261 $this->initializeCatalogue($locale);
262 $fallbackContent = $this->getFallbackContent($this->catalogues[$locale]);
263 $content = \sprintf(<<<EOF
264 <?php
265
266 use Symfony\\Component\\Translation\\MessageCatalogue;
267
268 \$catalogue = new MessageCatalogue('%s', %s);
269
270 %s
271 return \$catalogue;
272
273 EOF
274 , $locale, \var_export($this->getAllMessages($this->catalogues[$locale]), \true), $fallbackContent);
275 $cache->write($content, $this->catalogues[$locale]->getResources());
276 }
277 private function getFallbackContent(MessageCatalogue $catalogue) : string
278 {
279 $fallbackContent = '';
280 $current = '';
281 $replacementPattern = '/[^a-z0-9_]/i';
282 $fallbackCatalogue = $catalogue->getFallbackCatalogue();
283 while ($fallbackCatalogue) {
284 $fallback = $fallbackCatalogue->getLocale();
285 $fallbackSuffix = \ucfirst(\preg_replace($replacementPattern, '_', $fallback));
286 $currentSuffix = \ucfirst(\preg_replace($replacementPattern, '_', $current));
287 $fallbackContent .= \sprintf(<<<'EOF'
288 $catalogue%s = new MessageCatalogue('%s', %s);
289 $catalogue%s->addFallbackCatalogue($catalogue%s);
290
291 EOF
292 , $fallbackSuffix, $fallback, \var_export($this->getAllMessages($fallbackCatalogue), \true), $currentSuffix, $fallbackSuffix);
293 $current = $fallbackCatalogue->getLocale();
294 $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();
295 }
296 return $fallbackContent;
297 }
298 private function getCatalogueCachePath(string $locale) : string
299 {
300 return $this->cacheDir . '/catalogue.' . $locale . '.' . \strtr(\substr(\base64_encode(\hash('sha256', \serialize($this->cacheVary), \true)), 0, 7), '/', '_') . '.php';
301 }
302 /**
303 * @internal
304 */
305 protected function doLoadCatalogue(string $locale) : void
306 {
307 $this->catalogues[$locale] = new MessageCatalogue($locale);
308 if (isset($this->resources[$locale])) {
309 foreach ($this->resources[$locale] as $resource) {
310 if (!isset($this->loaders[$resource[0]])) {
311 if (\is_string($resource[1])) {
312 throw new RuntimeException(\sprintf('No loader is registered for the "%s" format when loading the "%s" resource.', $resource[0], $resource[1]));
313 }
314 throw new RuntimeException(\sprintf('No loader is registered for the "%s" format.', $resource[0]));
315 }
316 $this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2]));
317 }
318 }
319 }
320 private function loadFallbackCatalogues(string $locale) : void
321 {
322 $current = $this->catalogues[$locale];
323 foreach ($this->computeFallbackLocales($locale) as $fallback) {
324 if (!isset($this->catalogues[$fallback])) {
325 $this->initializeCatalogue($fallback);
326 }
327 $fallbackCatalogue = new MessageCatalogue($fallback, $this->getAllMessages($this->catalogues[$fallback]));
328 foreach ($this->catalogues[$fallback]->getResources() as $resource) {
329 $fallbackCatalogue->addResource($resource);
330 }
331 $current->addFallbackCatalogue($fallbackCatalogue);
332 $current = $fallbackCatalogue;
333 }
334 }
335 protected function computeFallbackLocales(string $locale)
336 {
337 if (null === $this->parentLocales) {
338 $this->parentLocales = \json_decode(\file_get_contents(__DIR__ . '/Resources/data/parents.json'), \true);
339 }
340 $originLocale = $locale;
341 $locales = [];
342 while ($locale) {
343 $parent = $this->parentLocales[$locale] ?? null;
344 if ($parent) {
345 $locale = 'root' !== $parent ? $parent : null;
346 } elseif (\function_exists('locale_parse')) {
347 $localeSubTags = \locale_parse($locale);
348 $locale = null;
349 if (1 < \count($localeSubTags)) {
350 \array_pop($localeSubTags);
351 $locale = \locale_compose($localeSubTags) ?: null;
352 }
353 } elseif ($i = \strrpos($locale, '_') ?: \strrpos($locale, '-')) {
354 $locale = \substr($locale, 0, $i);
355 } else {
356 $locale = null;
357 }
358 if (null !== $locale) {
359 $locales[] = $locale;
360 }
361 }
362 foreach ($this->fallbackLocales as $fallback) {
363 if ($fallback === $originLocale) {
364 continue;
365 }
366 $locales[] = $fallback;
367 }
368 return \array_unique($locales);
369 }
370 /**
371 * Asserts that the locale is valid, throws an Exception if not.
372 *
373 * @throws InvalidArgumentException If the locale contains invalid characters
374 */
375 protected function assertValidLocale(string $locale)
376 {
377 if (!\preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) {
378 throw new InvalidArgumentException(\sprintf('Invalid "%s" locale.', $locale));
379 }
380 }
381 /**
382 * Provides the ConfigCache factory implementation, falling back to a
383 * default implementation if necessary.
384 */
385 private function getConfigCacheFactory() : ConfigCacheFactoryInterface
386 {
387 if (!$this->configCacheFactory) {
388 $this->configCacheFactory = new ConfigCacheFactory($this->debug);
389 }
390 return $this->configCacheFactory;
391 }
392 private function getAllMessages(MessageCatalogueInterface $catalogue) : array
393 {
394 $allMessages = [];
395 foreach ($catalogue->all() as $domain => $messages) {
396 if ($intlMessages = $catalogue->all($domain . MessageCatalogue::INTL_DOMAIN_SUFFIX)) {
397 $allMessages[$domain . MessageCatalogue::INTL_DOMAIN_SUFFIX] = $intlMessages;
398 $messages = \array_diff_key($messages, $intlMessages);
399 }
400 if ($messages) {
401 $allMessages[$domain] = $messages;
402 }
403 }
404 return $allMessages;
405 }
406 }
407