123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- <?php
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Symfony\Component\Intl\Data\Bundle\Reader;
- use Symfony\Component\Intl\Data\Util\RecursiveArrayAccess;
- use Symfony\Component\Intl\Exception\MissingResourceException;
- use Symfony\Component\Intl\Exception\OutOfBoundsException;
- use Symfony\Component\Intl\Exception\ResourceBundleNotFoundException;
- use Symfony\Component\Intl\Locale;
- /**
- * Default implementation of {@link BundleEntryReaderInterface}.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- *
- * @see BundleEntryReaderInterface
- *
- * @internal
- */
- class BundleEntryReader implements BundleEntryReaderInterface
- {
- private $reader;
- /**
- * A mapping of locale aliases to locales.
- */
- private $localeAliases = [];
- /**
- * Creates an entry reader based on the given resource bundle reader.
- */
- public function __construct(BundleReaderInterface $reader)
- {
- $this->reader = $reader;
- }
- /**
- * Stores a mapping of locale aliases to locales.
- *
- * This mapping is used when reading entries and merging them with their
- * fallback locales. If an entry is read for a locale alias (e.g. "mo")
- * that points to a locale with a fallback locale ("ro_MD"), the reader
- * can continue at the correct fallback locale ("ro").
- *
- * @param array $localeAliases A mapping of locale aliases to locales
- */
- public function setLocaleAliases(array $localeAliases)
- {
- $this->localeAliases = $localeAliases;
- }
- /**
- * {@inheritdoc}
- */
- public function read(string $path, string $locale)
- {
- return $this->reader->read($path, $locale);
- }
- /**
- * {@inheritdoc}
- */
- public function readEntry(string $path, string $locale, array $indices, bool $fallback = true)
- {
- $entry = null;
- $isMultiValued = false;
- $readSucceeded = false;
- $exception = null;
- $currentLocale = $locale;
- $testedLocales = [];
- while (null !== $currentLocale) {
- // Resolve any aliases to their target locales
- if (isset($this->localeAliases[$currentLocale])) {
- $currentLocale = $this->localeAliases[$currentLocale];
- }
- try {
- $data = $this->reader->read($path, $currentLocale);
- $currentEntry = RecursiveArrayAccess::get($data, $indices);
- $readSucceeded = true;
- $isCurrentTraversable = $currentEntry instanceof \Traversable;
- $isCurrentMultiValued = $isCurrentTraversable || \is_array($currentEntry);
- // Return immediately if fallback is disabled or we are dealing
- // with a scalar non-null entry
- if (!$fallback || (!$isCurrentMultiValued && null !== $currentEntry)) {
- return $currentEntry;
- }
- // =========================================================
- // Fallback is enabled, entry is either multi-valued or NULL
- // =========================================================
- // If entry is multi-valued, convert to array
- if ($isCurrentTraversable) {
- $currentEntry = iterator_to_array($currentEntry);
- }
- // If previously read entry was multi-valued too, merge them
- if ($isCurrentMultiValued && $isMultiValued) {
- $currentEntry = array_merge($currentEntry, $entry);
- }
- // Keep the previous entry if the current entry is NULL
- if (null !== $currentEntry) {
- $entry = $currentEntry;
- }
- // If this or the previous entry was multi-valued, we are dealing
- // with a merged, multi-valued entry now
- $isMultiValued = $isMultiValued || $isCurrentMultiValued;
- } catch (ResourceBundleNotFoundException $e) {
- // Continue if there is a fallback locale for the current
- // locale
- $exception = $e;
- } catch (OutOfBoundsException $e) {
- // Remember exception and rethrow if we cannot find anything in
- // the fallback locales either
- $exception = $e;
- }
- // Remember which locales we tried
- $testedLocales[] = $currentLocale;
- // Check whether fallback is allowed
- if (!$fallback) {
- break;
- }
- // Then determine fallback locale
- $currentLocale = Locale::getFallback($currentLocale);
- }
- // Multi-valued entry was merged
- if ($isMultiValued) {
- return $entry;
- }
- // Entry is still NULL, but no read error occurred
- if ($readSucceeded) {
- return $entry;
- }
- // Entry is still NULL, read error occurred. Throw an exception
- // containing the detailed path and locale
- $errorMessage = sprintf(
- 'Couldn\'t read the indices [%s] for the locale "%s" in "%s".',
- implode('][', $indices),
- $locale,
- $path
- );
- // Append fallback locales, if any
- if (\count($testedLocales) > 1) {
- // Remove original locale
- array_shift($testedLocales);
- $errorMessage .= sprintf(
- ' The indices also couldn\'t be found for the fallback locale(s) "%s".',
- implode('", "', $testedLocales)
- );
- }
- throw new MissingResourceException($errorMessage, 0, $exception);
- }
- }
|