vendor/symfony/translation-contracts/TranslatorTrait.php line 46

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Contracts\Translation;
  11. use Symfony\Component\Translation\Exception\InvalidArgumentException;
  12. /**
  13.  * A trait to help implement TranslatorInterface and LocaleAwareInterface.
  14.  *
  15.  * @author Fabien Potencier <fabien@symfony.com>
  16.  */
  17. trait TranslatorTrait
  18. {
  19.     private $locale;
  20.     /**
  21.      * {@inheritdoc}
  22.      */
  23.     public function setLocale(string $locale)
  24.     {
  25.         $this->locale $locale;
  26.     }
  27.     /**
  28.      * {@inheritdoc}
  29.      *
  30.      * @return string
  31.      */
  32.     public function getLocale()
  33.     {
  34.         return $this->locale ?: (class_exists(\Locale::class) ? \Locale::getDefault() : 'en');
  35.     }
  36.     /**
  37.      * {@inheritdoc}
  38.      */
  39.     public function trans(?string $id, array $parameters = [], string $domain nullstring $locale null): string
  40.     {
  41.         if (null === $id || '' === $id) {
  42.             return '';
  43.         }
  44.         if (!isset($parameters['%count%']) || !is_numeric($parameters['%count%'])) {
  45.             return strtr($id$parameters);
  46.         }
  47.         $number = (float) $parameters['%count%'];
  48.         $locale $locale ?: $this->getLocale();
  49.         $parts = [];
  50.         if (preg_match('/^\|++$/'$id)) {
  51.             $parts explode('|'$id);
  52.         } elseif (preg_match_all('/(?:\|\||[^\|])++/'$id$matches)) {
  53.             $parts $matches[0];
  54.         }
  55.         $intervalRegexp = <<<'EOF'
  56. /^(?P<interval>
  57.     ({\s*
  58.         (\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
  59.     \s*})
  60.         |
  61.     (?P<left_delimiter>[\[\]])
  62.         \s*
  63.         (?P<left>-Inf|\-?\d+(\.\d+)?)
  64.         \s*,\s*
  65.         (?P<right>\+?Inf|\-?\d+(\.\d+)?)
  66.         \s*
  67.     (?P<right_delimiter>[\[\]])
  68. )\s*(?P<message>.*?)$/xs
  69. EOF;
  70.         $standardRules = [];
  71.         foreach ($parts as $part) {
  72.             $part trim(str_replace('||''|'$part));
  73.             // try to match an explicit rule, then fallback to the standard ones
  74.             if (preg_match($intervalRegexp$part$matches)) {
  75.                 if ($matches[2]) {
  76.                     foreach (explode(','$matches[3]) as $n) {
  77.                         if ($number == $n) {
  78.                             return strtr($matches['message'], $parameters);
  79.                         }
  80.                     }
  81.                 } else {
  82.                     $leftNumber '-Inf' === $matches['left'] ? -\INF : (float) $matches['left'];
  83.                     $rightNumber is_numeric($matches['right']) ? (float) $matches['right'] : \INF;
  84.                     if (('[' === $matches['left_delimiter'] ? $number >= $leftNumber $number $leftNumber)
  85.                         && (']' === $matches['right_delimiter'] ? $number <= $rightNumber $number $rightNumber)
  86.                     ) {
  87.                         return strtr($matches['message'], $parameters);
  88.                     }
  89.                 }
  90.             } elseif (preg_match('/^\w+\:\s*(.*?)$/'$part$matches)) {
  91.                 $standardRules[] = $matches[1];
  92.             } else {
  93.                 $standardRules[] = $part;
  94.             }
  95.         }
  96.         $position $this->getPluralizationRule($number$locale);
  97.         if (!isset($standardRules[$position])) {
  98.             // when there's exactly one rule given, and that rule is a standard
  99.             // rule, use this rule
  100.             if (=== \count($parts) && isset($standardRules[0])) {
  101.                 return strtr($standardRules[0], $parameters);
  102.             }
  103.             $message sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").'$id$locale$number);
  104.             if (class_exists(InvalidArgumentException::class)) {
  105.                 throw new InvalidArgumentException($message);
  106.             }
  107.             throw new \InvalidArgumentException($message);
  108.         }
  109.         return strtr($standardRules[$position], $parameters);
  110.     }
  111.     /**
  112.      * Returns the plural position to use for the given locale and number.
  113.      *
  114.      * The plural rules are derived from code of the Zend Framework (2010-09-25),
  115.      * which is subject to the new BSD license (http://framework.zend.com/license/new-bsd).
  116.      * Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  117.      */
  118.     private function getPluralizationRule(float $numberstring $locale): int
  119.     {
  120.         $number abs($number);
  121.         switch ('pt_BR' !== $locale && 'en_US_POSIX' !== $locale && \strlen($locale) > substr($locale0strrpos($locale'_')) : $locale) {
  122.             case 'af':
  123.             case 'bn':
  124.             case 'bg':
  125.             case 'ca':
  126.             case 'da':
  127.             case 'de':
  128.             case 'el':
  129.             case 'en':
  130.             case 'en_US_POSIX':
  131.             case 'eo':
  132.             case 'es':
  133.             case 'et':
  134.             case 'eu':
  135.             case 'fa':
  136.             case 'fi':
  137.             case 'fo':
  138.             case 'fur':
  139.             case 'fy':
  140.             case 'gl':
  141.             case 'gu':
  142.             case 'ha':
  143.             case 'he':
  144.             case 'hu':
  145.             case 'is':
  146.             case 'it':
  147.             case 'ku':
  148.             case 'lb':
  149.             case 'ml':
  150.             case 'mn':
  151.             case 'mr':
  152.             case 'nah':
  153.             case 'nb':
  154.             case 'ne':
  155.             case 'nl':
  156.             case 'nn':
  157.             case 'no':
  158.             case 'oc':
  159.             case 'om':
  160.             case 'or':
  161.             case 'pa':
  162.             case 'pap':
  163.             case 'ps':
  164.             case 'pt':
  165.             case 'so':
  166.             case 'sq':
  167.             case 'sv':
  168.             case 'sw':
  169.             case 'ta':
  170.             case 'te':
  171.             case 'tk':
  172.             case 'ur':
  173.             case 'zu':
  174.                 return (== $number) ? 1;
  175.             case 'am':
  176.             case 'bh':
  177.             case 'fil':
  178.             case 'fr':
  179.             case 'gun':
  180.             case 'hi':
  181.             case 'hy':
  182.             case 'ln':
  183.             case 'mg':
  184.             case 'nso':
  185.             case 'pt_BR':
  186.             case 'ti':
  187.             case 'wa':
  188.                 return ($number 2) ? 1;
  189.             case 'be':
  190.             case 'bs':
  191.             case 'hr':
  192.             case 'ru':
  193.             case 'sh':
  194.             case 'sr':
  195.             case 'uk':
  196.                 return ((== $number 10) && (11 != $number 100)) ? : ((($number 10 >= 2) && ($number 10 <= 4) && (($number 100 10) || ($number 100 >= 20))) ? 2);
  197.             case 'cs':
  198.             case 'sk':
  199.                 return (== $number) ? : ((($number >= 2) && ($number <= 4)) ? 2);
  200.             case 'ga':
  201.                 return (== $number) ? : ((== $number) ? 2);
  202.             case 'lt':
  203.                 return ((== $number 10) && (11 != $number 100)) ? : ((($number 10 >= 2) && (($number 100 10) || ($number 100 >= 20))) ? 2);
  204.             case 'sl':
  205.                 return (== $number 100) ? : ((== $number 100) ? : (((== $number 100) || (== $number 100)) ? 3));
  206.             case 'mk':
  207.                 return (== $number 10) ? 1;
  208.             case 'mt':
  209.                 return (== $number) ? : (((== $number) || (($number 100 1) && ($number 100 11))) ? : ((($number 100 10) && ($number 100 20)) ? 3));
  210.             case 'lv':
  211.                 return (== $number) ? : (((== $number 10) && (11 != $number 100)) ? 2);
  212.             case 'pl':
  213.                 return (== $number) ? : ((($number 10 >= 2) && ($number 10 <= 4) && (($number 100 12) || ($number 100 14))) ? 2);
  214.             case 'cy':
  215.                 return (== $number) ? : ((== $number) ? : (((== $number) || (11 == $number)) ? 3));
  216.             case 'ro':
  217.                 return (== $number) ? : (((== $number) || (($number 100 0) && ($number 100 20))) ? 2);
  218.             case 'ar':
  219.                 return (== $number) ? : ((== $number) ? : ((== $number) ? : ((($number 100 >= 3) && ($number 100 <= 10)) ? : ((($number 100 >= 11) && ($number 100 <= 99)) ? 5))));
  220.             default:
  221.                 return 0;
  222.         }
  223.     }
  224. }