Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Translation; Chris@0: Chris@0: use Symfony\Component\Translation\Exception\InvalidArgumentException; Chris@0: Chris@0: /** Chris@0: * MessageSelector. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: * @author Bernhard Schussek Chris@0: */ Chris@0: class MessageSelector Chris@0: { Chris@0: /** Chris@0: * Given a message with different plural translations separated by a Chris@0: * pipe (|), this method returns the correct portion of the message based Chris@0: * on the given number, locale and the pluralization rules in the message Chris@0: * itself. Chris@0: * Chris@0: * The message supports two different types of pluralization rules: Chris@0: * Chris@0: * interval: {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples Chris@0: * indexed: There is one apple|There are %count% apples Chris@0: * Chris@0: * The indexed solution can also contain labels (e.g. one: There is one apple). Chris@0: * This is purely for making the translations more clear - it does not Chris@0: * affect the functionality. Chris@0: * Chris@0: * The two methods can also be mixed: Chris@0: * {0} There are no apples|one: There is one apple|more: There are %count% apples Chris@0: * Chris@0: * @param string $message The message being translated Chris@0: * @param int $number The number of items represented for the message Chris@0: * @param string $locale The locale to use for choosing Chris@0: * Chris@0: * @return string Chris@0: * Chris@0: * @throws InvalidArgumentException Chris@0: */ Chris@0: public function choose($message, $number, $locale) Chris@0: { Chris@17: $parts = []; Chris@14: if (preg_match('/^\|++$/', $message)) { Chris@14: $parts = explode('|', $message); Chris@14: } elseif (preg_match_all('/(?:\|\||[^\|])++/', $message, $matches)) { Chris@14: $parts = $matches[0]; Chris@14: } Chris@14: Chris@17: $explicitRules = []; Chris@17: $standardRules = []; Chris@14: foreach ($parts as $part) { Chris@0: $part = trim(str_replace('||', '|', $part)); Chris@0: Chris@0: if (preg_match('/^(?P'.Interval::getIntervalRegexp().')\s*(?P.*?)$/xs', $part, $matches)) { Chris@0: $explicitRules[$matches['interval']] = $matches['message']; Chris@0: } elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) { Chris@0: $standardRules[] = $matches[1]; Chris@0: } else { Chris@0: $standardRules[] = $part; Chris@0: } Chris@0: } Chris@0: Chris@0: // try to match an explicit rule, then fallback to the standard ones Chris@0: foreach ($explicitRules as $interval => $m) { Chris@0: if (Interval::test($number, $interval)) { Chris@0: return $m; Chris@0: } Chris@0: } Chris@0: Chris@0: $position = PluralizationRules::get($number, $locale); Chris@0: Chris@0: if (!isset($standardRules[$position])) { Chris@0: // when there's exactly one rule given, and that rule is a standard Chris@0: // rule, use this rule Chris@17: if (1 === \count($parts) && isset($standardRules[0])) { Chris@0: return $standardRules[0]; Chris@0: } Chris@0: Chris@0: throw new InvalidArgumentException(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").', $message, $locale, $number)); Chris@0: } Chris@0: Chris@0: return $standardRules[$position]; Chris@0: } Chris@0: }