src/Intl/MessageFormatter/MessageFormatter.php
private static function parseToken(array $token, array $args, $locale)
    {
        if (!isset($args[$param = trim($token[0])])) {
            return '{'.$param.'}';
        }

        $arg = $args[$param];
        $type = isset($token[1]) ? trim($token[1]) : 'none';
        switch ($type) {
            case 'date': //XXX use DateFormatter?
            case 'time':
            case 'spellout':
            case 'ordinal':
            case 'duration':
            case 'choice':
            case 'selectordinal':
                throw new \DomainException(sprintf('The PHP intl extension is required to use the "%s" message format.', $type));

            case 'number':
                $format = isset($token[2]) ? trim($token[2]) : null;
                if (!is_numeric($arg) || (null !== $format && 'integer' !== $format)) {
                    throw new \DomainException('The PHP intl extension is required to use the "number" message format with non-integer values.');
                }

                $number = number_format($arg); //XXX use NumberFormatter?
                if (null === $format && false !== $pos = strpos($arg, '.')) {
                    // add decimals with unknown length
                    $number .= '.'.substr($arg, $pos + 1);
                }

                return $number;

            case 'none':
                return $arg;

            case 'select':
                /* http://icu-project.org/apiref/icu4c/classicu_1_1SelectFormat.html
                selectStyle = (selector '{' message '}')+
                */
                if (!isset($token[2])) {
                    throw new \DomainException('Message pattern is invalid.');
                }
                $select = self::tokenizePattern($token[2]);
                $c = \count($select);
                $message = false;
                for ($i = 0; 1 + $i < $c; ++$i) {
                    if (\is_array($select[$i]) || !\is_array($select[1 + $i])) {
                        throw new \DomainException('Message pattern is invalid.');
                    }
                    $selector = trim($select[$i++]);
                    if (false === $message && 'other' === $selector || $selector == $arg) {
                        $message = implode(',', $select[$i]);
                    }
                }
                if (false !== $message) {
                    return self::parseTokens(self::tokenizePattern($message), $args, $locale);
                }
                break;

            case 'plural': //TODO make it locale-dependent based on symfony/translation rules
                /* http://icu-project.org/apiref/icu4c/classicu_1_1PluralFormat.html
                pluralStyle = [offsetValue] (selector '{' message '}')+
                offsetValue = "offset:" number
                selector = explicitValue | keyword
                explicitValue = '=' number  // adjacent, no white space in between
                keyword = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
                message: see MessageFormat
                */
                if (!isset($token[2])) {
                    throw new \DomainException('Message pattern is invalid.');
                }
                $plural = self::tokenizePattern($token[2]);
                $c = \count($plural);
                $message = false;
                $offset = 0;
                for ($i = 0; 1 + $i < $c; ++$i) {
                    if (\is_array($plural[$i]) || !\is_array($plural[1 + $i])) {
                        throw new \DomainException('Message pattern is invalid.');
                    }
                    $selector = trim($plural[$i++]);

                    if (1 === $i && 0 === strncmp($selector, 'offset:', 7)) {
                        $pos = strpos(str_replace(array("\n", "\r", "\t"), ' ', $selector), ' ', 7);
                        $offset = (int) trim(substr($selector, 7, $pos - 7));
                        $selector = trim(substr($selector, 1 + $pos, \strlen($selector)));
                    }
                    if (false === $message && 'other' === $selector ||
                        '=' === $selector[0] && (int) substr($selector, 1, \strlen($selector)) === $arg ||
                        'one' === $selector && 1 == $arg - $offset
                    ) {
                        $message = implode(',', str_replace('#', $arg - $offset, $plural[$i]));
                    }
                }
                if (false !== $message) {
                    return self::parseTokens(self::tokenizePattern($message), $args, $locale);
                }
                break;
        }

        throw new \DomainException('Message pattern is invalid.');
    }
private static function parseToken(array $token, array $args, $locale)
    {
        if (!isset($args[$param = trim($token[0])])) {
            return '{'.$param.'}';
        }

        $arg = $args[$param];
        $type = isset($token[1]) ? trim($token[1]) : 'none';
        switch ($type) {
            case 'date': //XXX use DateFormatter?
            case 'time':
            case 'spellout':
            case 'ordinal':
            case 'duration':
            case 'choice':
            case 'selectordinal':
                throw new \DomainException(sprintf('The PHP intl extension is required to use the "%s" message format.', $type));

            case 'number':
                $format = isset($token[2]) ? trim($token[2]) : null;
                if (!is_numeric($arg) || (null !== $format && 'integer' !== $format)) {
                    throw new \DomainException('The PHP intl extension is required to use the "number" message format with non-integer values.');
                }

                $number = number_format($arg); //XXX use NumberFormatter?
                if (null === $format && false !== $pos = strpos($arg, '.')) {
                    // add decimals with unknown length
                    $number .= '.'.substr($arg, $pos + 1);
                }

                return $number;

            case 'none':
                return $arg;

            case 'select':
                /* http://icu-project.org/apiref/icu4c/classicu_1_1SelectFormat.html
                selectStyle = (selector '{' message '}')+
                */
                if (!isset($token[2])) {
                    throw new \DomainException('Message pattern is invalid.');
                }
                $select = self::tokenizePattern($token[2]);
                $c = \count($select);
                $message = false;
                for ($i = 0; 1 + $i < $c; ++$i) {
                    if (\is_array($select[$i]) || !\is_array($select[1 + $i])) {
                        throw new \DomainException('Message pattern is invalid.');
                    }
                    $selector = trim($select[$i++]);
                    if (false === $message && 'other' === $selector || $selector == $arg) {
                        $message = implode(',', $select[$i]);
                    }
                }
                if (false !== $message) {
                    return self::parseTokens(self::tokenizePattern($message), $args, $locale);
                }
                break;

            case 'plural': //TODO make it locale-dependent based on symfony/translation rules
                /* http://icu-project.org/apiref/icu4c/classicu_1_1PluralFormat.html
                pluralStyle = [offsetValue] (selector '{' message '}')+
                offsetValue = "offset:" number
                selector = explicitValue | keyword
                explicitValue = '=' number  // adjacent, no white space in between
                keyword = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
                message: see MessageFormat
                */
                if (!isset($token[2])) {
                    throw new \DomainException('Message pattern is invalid.');
                }
                $plural = self::tokenizePattern($token[2]);
                $c = \count($plural);
                $message = false;
                $offset = 0;
                for ($i = 0; 1 + $i < $c; ++$i) {
                    if (\is_array($plural[$i]) || !\is_array($plural[1 + $i])) {
                        throw new \DomainException('Message pattern is invalid.');
                    }
                    $selector = trim($plural[$i++]);

                    if (1 === $i && 0 === strncmp($selector, 'offset:', 7)) {
                        $pos = strpos(str_replace(array("\n", "\r", "\t"), ' ', $selector), ' ', 7);
                        $offset = (int) trim(substr($selector, 7, $pos - 7));
                        $selector = trim(substr($selector, 1 + $pos, \strlen($selector)));
                    }
                    if (false === $message && 'other' === $selector ||
                        '=' === $selector[0] && (int) substr($selector, 1, \strlen($selector)) === $arg ||
                        'one' === $selector && 1 == $arg - $offset
                    ) {
                        $message = implode(',', str_replace('#', $arg - $offset, $plural[$i]));
                    }
                }
                if (false !== $message) {
                    return self::parseTokens(self::tokenizePattern($message), $args, $locale);
                }
                break;
        }

        throw new \DomainException('Message pattern is invalid.');
    }
Parses pattern based on ICU grammar.

@see http://icu-project.org/apiref/icu4c/classMessageFormat.html#details