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

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