Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/translation/Translator.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
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 | |
12 namespace Symfony\Component\Translation; | |
13 | |
14 use Symfony\Component\Translation\Loader\LoaderInterface; | |
15 use Symfony\Component\Translation\Exception\NotFoundResourceException; | |
16 use Symfony\Component\Translation\Exception\InvalidArgumentException; | |
17 use Symfony\Component\Translation\Exception\RuntimeException; | |
18 use Symfony\Component\Config\ConfigCacheInterface; | |
19 use Symfony\Component\Config\ConfigCacheFactoryInterface; | |
20 use Symfony\Component\Config\ConfigCacheFactory; | |
21 | |
22 /** | |
23 * Translator. | |
24 * | |
25 * @author Fabien Potencier <fabien@symfony.com> | |
26 */ | |
27 class Translator implements TranslatorInterface, TranslatorBagInterface | |
28 { | |
29 /** | |
30 * @var MessageCatalogueInterface[] | |
31 */ | |
32 protected $catalogues = array(); | |
33 | |
34 /** | |
35 * @var string | |
36 */ | |
37 private $locale; | |
38 | |
39 /** | |
40 * @var array | |
41 */ | |
42 private $fallbackLocales = array(); | |
43 | |
44 /** | |
45 * @var LoaderInterface[] | |
46 */ | |
47 private $loaders = array(); | |
48 | |
49 /** | |
50 * @var array | |
51 */ | |
52 private $resources = array(); | |
53 | |
54 /** | |
55 * @var MessageSelector | |
56 */ | |
57 private $selector; | |
58 | |
59 /** | |
60 * @var string | |
61 */ | |
62 private $cacheDir; | |
63 | |
64 /** | |
65 * @var bool | |
66 */ | |
67 private $debug; | |
68 | |
69 /** | |
70 * @var ConfigCacheFactoryInterface|null | |
71 */ | |
72 private $configCacheFactory; | |
73 | |
74 /** | |
75 * Constructor. | |
76 * | |
77 * @param string $locale The locale | |
78 * @param MessageSelector|null $selector The message selector for pluralization | |
79 * @param string|null $cacheDir The directory to use for the cache | |
80 * @param bool $debug Use cache in debug mode ? | |
81 * | |
82 * @throws InvalidArgumentException If a locale contains invalid characters | |
83 */ | |
84 public function __construct($locale, MessageSelector $selector = null, $cacheDir = null, $debug = false) | |
85 { | |
86 $this->setLocale($locale); | |
87 $this->selector = $selector ?: new MessageSelector(); | |
88 $this->cacheDir = $cacheDir; | |
89 $this->debug = $debug; | |
90 } | |
91 | |
92 /** | |
93 * Sets the ConfigCache factory to use. | |
94 * | |
95 * @param ConfigCacheFactoryInterface $configCacheFactory | |
96 */ | |
97 public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory) | |
98 { | |
99 $this->configCacheFactory = $configCacheFactory; | |
100 } | |
101 | |
102 /** | |
103 * Adds a Loader. | |
104 * | |
105 * @param string $format The name of the loader (@see addResource()) | |
106 * @param LoaderInterface $loader A LoaderInterface instance | |
107 */ | |
108 public function addLoader($format, LoaderInterface $loader) | |
109 { | |
110 $this->loaders[$format] = $loader; | |
111 } | |
112 | |
113 /** | |
114 * Adds a Resource. | |
115 * | |
116 * @param string $format The name of the loader (@see addLoader()) | |
117 * @param mixed $resource The resource name | |
118 * @param string $locale The locale | |
119 * @param string $domain The domain | |
120 * | |
121 * @throws InvalidArgumentException If the locale contains invalid characters | |
122 */ | |
123 public function addResource($format, $resource, $locale, $domain = null) | |
124 { | |
125 if (null === $domain) { | |
126 $domain = 'messages'; | |
127 } | |
128 | |
129 $this->assertValidLocale($locale); | |
130 | |
131 $this->resources[$locale][] = array($format, $resource, $domain); | |
132 | |
133 if (in_array($locale, $this->fallbackLocales)) { | |
134 $this->catalogues = array(); | |
135 } else { | |
136 unset($this->catalogues[$locale]); | |
137 } | |
138 } | |
139 | |
140 /** | |
141 * {@inheritdoc} | |
142 */ | |
143 public function setLocale($locale) | |
144 { | |
145 $this->assertValidLocale($locale); | |
146 $this->locale = $locale; | |
147 } | |
148 | |
149 /** | |
150 * {@inheritdoc} | |
151 */ | |
152 public function getLocale() | |
153 { | |
154 return $this->locale; | |
155 } | |
156 | |
157 /** | |
158 * Sets the fallback locales. | |
159 * | |
160 * @param array $locales The fallback locales | |
161 * | |
162 * @throws InvalidArgumentException If a locale contains invalid characters | |
163 */ | |
164 public function setFallbackLocales(array $locales) | |
165 { | |
166 // needed as the fallback locales are linked to the already loaded catalogues | |
167 $this->catalogues = array(); | |
168 | |
169 foreach ($locales as $locale) { | |
170 $this->assertValidLocale($locale); | |
171 } | |
172 | |
173 $this->fallbackLocales = $locales; | |
174 } | |
175 | |
176 /** | |
177 * Gets the fallback locales. | |
178 * | |
179 * @return array $locales The fallback locales | |
180 */ | |
181 public function getFallbackLocales() | |
182 { | |
183 return $this->fallbackLocales; | |
184 } | |
185 | |
186 /** | |
187 * {@inheritdoc} | |
188 */ | |
189 public function trans($id, array $parameters = array(), $domain = null, $locale = null) | |
190 { | |
191 if (null === $domain) { | |
192 $domain = 'messages'; | |
193 } | |
194 | |
195 return strtr($this->getCatalogue($locale)->get((string) $id, $domain), $parameters); | |
196 } | |
197 | |
198 /** | |
199 * {@inheritdoc} | |
200 */ | |
201 public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) | |
202 { | |
203 $parameters = array_merge(array( | |
204 '%count%' => $number, | |
205 ), $parameters); | |
206 | |
207 if (null === $domain) { | |
208 $domain = 'messages'; | |
209 } | |
210 | |
211 $id = (string) $id; | |
212 $catalogue = $this->getCatalogue($locale); | |
213 $locale = $catalogue->getLocale(); | |
214 while (!$catalogue->defines($id, $domain)) { | |
215 if ($cat = $catalogue->getFallbackCatalogue()) { | |
216 $catalogue = $cat; | |
217 $locale = $catalogue->getLocale(); | |
218 } else { | |
219 break; | |
220 } | |
221 } | |
222 | |
223 return strtr($this->selector->choose($catalogue->get($id, $domain), (int) $number, $locale), $parameters); | |
224 } | |
225 | |
226 /** | |
227 * {@inheritdoc} | |
228 */ | |
229 public function getCatalogue($locale = null) | |
230 { | |
231 if (null === $locale) { | |
232 $locale = $this->getLocale(); | |
233 } else { | |
234 $this->assertValidLocale($locale); | |
235 } | |
236 | |
237 if (!isset($this->catalogues[$locale])) { | |
238 $this->loadCatalogue($locale); | |
239 } | |
240 | |
241 return $this->catalogues[$locale]; | |
242 } | |
243 | |
244 /** | |
245 * Gets the loaders. | |
246 * | |
247 * @return array LoaderInterface[] | |
248 */ | |
249 protected function getLoaders() | |
250 { | |
251 return $this->loaders; | |
252 } | |
253 | |
254 /** | |
255 * @param string $locale | |
256 */ | |
257 protected function loadCatalogue($locale) | |
258 { | |
259 if (null === $this->cacheDir) { | |
260 $this->initializeCatalogue($locale); | |
261 } else { | |
262 $this->initializeCacheCatalogue($locale); | |
263 } | |
264 } | |
265 | |
266 /** | |
267 * @param string $locale | |
268 */ | |
269 protected function initializeCatalogue($locale) | |
270 { | |
271 $this->assertValidLocale($locale); | |
272 | |
273 try { | |
274 $this->doLoadCatalogue($locale); | |
275 } catch (NotFoundResourceException $e) { | |
276 if (!$this->computeFallbackLocales($locale)) { | |
277 throw $e; | |
278 } | |
279 } | |
280 $this->loadFallbackCatalogues($locale); | |
281 } | |
282 | |
283 /** | |
284 * @param string $locale | |
285 */ | |
286 private function initializeCacheCatalogue($locale) | |
287 { | |
288 if (isset($this->catalogues[$locale])) { | |
289 /* Catalogue already initialized. */ | |
290 return; | |
291 } | |
292 | |
293 $this->assertValidLocale($locale); | |
294 $cache = $this->getConfigCacheFactory()->cache($this->getCatalogueCachePath($locale), | |
295 function (ConfigCacheInterface $cache) use ($locale) { | |
296 $this->dumpCatalogue($locale, $cache); | |
297 } | |
298 ); | |
299 | |
300 if (isset($this->catalogues[$locale])) { | |
301 /* Catalogue has been initialized as it was written out to cache. */ | |
302 return; | |
303 } | |
304 | |
305 /* Read catalogue from cache. */ | |
306 $this->catalogues[$locale] = include $cache->getPath(); | |
307 } | |
308 | |
309 private function dumpCatalogue($locale, ConfigCacheInterface $cache) | |
310 { | |
311 $this->initializeCatalogue($locale); | |
312 $fallbackContent = $this->getFallbackContent($this->catalogues[$locale]); | |
313 | |
314 $content = sprintf(<<<EOF | |
315 <?php | |
316 | |
317 use Symfony\Component\Translation\MessageCatalogue; | |
318 | |
319 \$catalogue = new MessageCatalogue('%s', %s); | |
320 | |
321 %s | |
322 return \$catalogue; | |
323 | |
324 EOF | |
325 , | |
326 $locale, | |
327 var_export($this->catalogues[$locale]->all(), true), | |
328 $fallbackContent | |
329 ); | |
330 | |
331 $cache->write($content, $this->catalogues[$locale]->getResources()); | |
332 } | |
333 | |
334 private function getFallbackContent(MessageCatalogue $catalogue) | |
335 { | |
336 $fallbackContent = ''; | |
337 $current = ''; | |
338 $replacementPattern = '/[^a-z0-9_]/i'; | |
339 $fallbackCatalogue = $catalogue->getFallbackCatalogue(); | |
340 while ($fallbackCatalogue) { | |
341 $fallback = $fallbackCatalogue->getLocale(); | |
342 $fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback)); | |
343 $currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current)); | |
344 | |
345 $fallbackContent .= sprintf(<<<'EOF' | |
346 $catalogue%s = new MessageCatalogue('%s', %s); | |
347 $catalogue%s->addFallbackCatalogue($catalogue%s); | |
348 | |
349 EOF | |
350 , | |
351 $fallbackSuffix, | |
352 $fallback, | |
353 var_export($fallbackCatalogue->all(), true), | |
354 $currentSuffix, | |
355 $fallbackSuffix | |
356 ); | |
357 $current = $fallbackCatalogue->getLocale(); | |
358 $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue(); | |
359 } | |
360 | |
361 return $fallbackContent; | |
362 } | |
363 | |
364 private function getCatalogueCachePath($locale) | |
365 { | |
366 return $this->cacheDir.'/catalogue.'.$locale.'.'.sha1(serialize($this->fallbackLocales)).'.php'; | |
367 } | |
368 | |
369 private function doLoadCatalogue($locale) | |
370 { | |
371 $this->catalogues[$locale] = new MessageCatalogue($locale); | |
372 | |
373 if (isset($this->resources[$locale])) { | |
374 foreach ($this->resources[$locale] as $resource) { | |
375 if (!isset($this->loaders[$resource[0]])) { | |
376 throw new RuntimeException(sprintf('The "%s" translation loader is not registered.', $resource[0])); | |
377 } | |
378 $this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2])); | |
379 } | |
380 } | |
381 } | |
382 | |
383 private function loadFallbackCatalogues($locale) | |
384 { | |
385 $current = $this->catalogues[$locale]; | |
386 | |
387 foreach ($this->computeFallbackLocales($locale) as $fallback) { | |
388 if (!isset($this->catalogues[$fallback])) { | |
389 $this->initializeCatalogue($fallback); | |
390 } | |
391 | |
392 $fallbackCatalogue = new MessageCatalogue($fallback, $this->catalogues[$fallback]->all()); | |
393 foreach ($this->catalogues[$fallback]->getResources() as $resource) { | |
394 $fallbackCatalogue->addResource($resource); | |
395 } | |
396 $current->addFallbackCatalogue($fallbackCatalogue); | |
397 $current = $fallbackCatalogue; | |
398 } | |
399 } | |
400 | |
401 protected function computeFallbackLocales($locale) | |
402 { | |
403 $locales = array(); | |
404 foreach ($this->fallbackLocales as $fallback) { | |
405 if ($fallback === $locale) { | |
406 continue; | |
407 } | |
408 | |
409 $locales[] = $fallback; | |
410 } | |
411 | |
412 if (strrchr($locale, '_') !== false) { | |
413 array_unshift($locales, substr($locale, 0, -strlen(strrchr($locale, '_')))); | |
414 } | |
415 | |
416 return array_unique($locales); | |
417 } | |
418 | |
419 /** | |
420 * Asserts that the locale is valid, throws an Exception if not. | |
421 * | |
422 * @param string $locale Locale to tests | |
423 * | |
424 * @throws InvalidArgumentException If the locale contains invalid characters | |
425 */ | |
426 protected function assertValidLocale($locale) | |
427 { | |
428 if (1 !== preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) { | |
429 throw new InvalidArgumentException(sprintf('Invalid "%s" locale.', $locale)); | |
430 } | |
431 } | |
432 | |
433 /** | |
434 * Provides the ConfigCache factory implementation, falling back to a | |
435 * default implementation if necessary. | |
436 * | |
437 * @return ConfigCacheFactoryInterface $configCacheFactory | |
438 */ | |
439 private function getConfigCacheFactory() | |
440 { | |
441 if (!$this->configCacheFactory) { | |
442 $this->configCacheFactory = new ConfigCacheFactory($this->debug); | |
443 } | |
444 | |
445 return $this->configCacheFactory; | |
446 } | |
447 } |