framework/console/controllers/MessageController.php
protected function extractMessagesFromTokens(array $tokens, array $translatorTokens, array $ignoreCategories)
    {
        $messages = [];
        $translatorTokensCount = count($translatorTokens);
        $matchedTokensCount = 0;
        $buffer = [];
        $pendingParenthesisCount = 0;

        foreach ($tokens as $tokenIndex => $token) {
            // finding out translator call
            if ($matchedTokensCount < $translatorTokensCount) {
                if ($this->tokensEqual($token, $translatorTokens[$matchedTokensCount])) {
                    $matchedTokensCount++;
                } else {
                    $matchedTokensCount = 0;
                }
            } elseif ($matchedTokensCount === $translatorTokensCount) {
                // translator found

                // end of function call
                if ($this->tokensEqual(')', $token)) {
                    $pendingParenthesisCount--;

                    if ($pendingParenthesisCount === 0) {
                        // end of translator call or end of something that we can't extract
                        if (isset($buffer[0][0], $buffer[1], $buffer[2][0]) && $buffer[0][0] === T_CONSTANT_ENCAPSED_STRING && $buffer[1] === ',' && $buffer[2][0] === T_CONSTANT_ENCAPSED_STRING) {
                            // is valid call we can extract
                            $category = stripcslashes($buffer[0][1]);
                            $category = mb_substr($category, 1, -1);

                            if (!$this->isCategoryIgnored($category, $ignoreCategories)) {
                                $fullMessage = mb_substr($buffer[2][1], 1, -1);
                                $i = 3;
                                while ($i < count($buffer) - 1 && !is_array($buffer[$i]) && $buffer[$i] === '.') {
                                    $fullMessage .= mb_substr($buffer[$i + 1][1], 1, -1);
                                    $i += 2;
                                }

                                $message = stripcslashes($fullMessage);
                                $messages[$category][] = $message;
                            }

                            $nestedTokens = array_slice($buffer, 3);
                            if (count($nestedTokens) > $translatorTokensCount) {
                                // search for possible nested translator calls
                                $messages = array_merge_recursive($messages, $this->extractMessagesFromTokens($nestedTokens, $translatorTokens, $ignoreCategories));
                            }
                        } else {
                            // invalid call or dynamic call we can't extract
                            $line = Console::ansiFormat($this->getLine($buffer), [Console::FG_CYAN]);
                            $skipping = Console::ansiFormat('Skipping line', [Console::FG_YELLOW]);
                            $this->stdout("$skipping $line. Make sure both category and message are static strings.\n");
                        }

                        // prepare for the next match
                        $matchedTokensCount = 0;
                        $pendingParenthesisCount = 0;
                        $buffer = [];
                    } else {
                        $buffer[] = $token;
                    }
                } elseif ($this->tokensEqual('(', $token)) {
                    // count beginning of function call, skipping translator beginning

                    // If we are not yet inside the translator, make sure that it's beginning of the real translator.
                    // See https://github.com/yiisoft/yii2/issues/16828
                    if ($pendingParenthesisCount === 0) {
                        $previousTokenIndex = $tokenIndex - $matchedTokensCount - 1;
                        if (is_array($tokens[$previousTokenIndex])) {
                            $previousToken = $tokens[$previousTokenIndex][0];
                            if (in_array($previousToken, [T_OBJECT_OPERATOR, T_PAAMAYIM_NEKUDOTAYIM], true)) {
                                $matchedTokensCount = 0;
                                continue;
                            }
                        }
                    }

                    if ($pendingParenthesisCount > 0) {
                        $buffer[] = $token;
                    }
                    $pendingParenthesisCount++;
                } elseif (isset($token[0]) && !in_array($token[0], [T_WHITESPACE, T_COMMENT])) {
                    // ignore comments and whitespaces
                    $buffer[] = $token;
                }
            }
        }

        return $messages;
    }
protected function extractMessagesFromTokens(array $tokens, array $translatorTokens, array $ignoreCategories)
    {
        $messages = [];
        $translatorTokensCount = count($translatorTokens);
        $matchedTokensCount = 0;
        $buffer = [];
        $pendingParenthesisCount = 0;

        foreach ($tokens as $tokenIndex => $token) {
            // finding out translator call
            if ($matchedTokensCount < $translatorTokensCount) {
                if ($this->tokensEqual($token, $translatorTokens[$matchedTokensCount])) {
                    $matchedTokensCount++;
                } else {
                    $matchedTokensCount = 0;
                }
            } elseif ($matchedTokensCount === $translatorTokensCount) {
                // translator found

                // end of function call
                if ($this->tokensEqual(')', $token)) {
                    $pendingParenthesisCount--;

                    if ($pendingParenthesisCount === 0) {
                        // end of translator call or end of something that we can't extract
                        if (isset($buffer[0][0], $buffer[1], $buffer[2][0]) && $buffer[0][0] === T_CONSTANT_ENCAPSED_STRING && $buffer[1] === ',' && $buffer[2][0] === T_CONSTANT_ENCAPSED_STRING) {
                            // is valid call we can extract
                            $category = stripcslashes($buffer[0][1]);
                            $category = mb_substr($category, 1, -1);

                            if (!$this->isCategoryIgnored($category, $ignoreCategories)) {
                                $fullMessage = mb_substr($buffer[2][1], 1, -1);
                                $i = 3;
                                while ($i < count($buffer) - 1 && !is_array($buffer[$i]) && $buffer[$i] === '.') {
                                    $fullMessage .= mb_substr($buffer[$i + 1][1], 1, -1);
                                    $i += 2;
                                }

                                $message = stripcslashes($fullMessage);
                                $messages[$category][] = $message;
                            }

                            $nestedTokens = array_slice($buffer, 3);
                            if (count($nestedTokens) > $translatorTokensCount) {
                                // search for possible nested translator calls
                                $messages = array_merge_recursive($messages, $this->extractMessagesFromTokens($nestedTokens, $translatorTokens, $ignoreCategories));
                            }
                        } else {
                            // invalid call or dynamic call we can't extract
                            $line = Console::ansiFormat($this->getLine($buffer), [Console::FG_CYAN]);
                            $skipping = Console::ansiFormat('Skipping line', [Console::FG_YELLOW]);
                            $this->stdout("$skipping $line. Make sure both category and message are static strings.\n");
                        }

                        // prepare for the next match
                        $matchedTokensCount = 0;
                        $pendingParenthesisCount = 0;
                        $buffer = [];
                    } else {
                        $buffer[] = $token;
                    }
                } elseif ($this->tokensEqual('(', $token)) {
                    // count beginning of function call, skipping translator beginning

                    // If we are not yet inside the translator, make sure that it's beginning of the real translator.
                    // See https://github.com/yiisoft/yii2/issues/16828
                    if ($pendingParenthesisCount === 0) {
                        $previousTokenIndex = $tokenIndex - $matchedTokensCount - 1;
                        if (is_array($tokens[$previousTokenIndex])) {
                            $previousToken = $tokens[$previousTokenIndex][0];
                            if (in_array($previousToken, [T_OBJECT_OPERATOR, T_PAAMAYIM_NEKUDOTAYIM], true)) {
                                $matchedTokensCount = 0;
                                continue;
                            }
                        }
                    }

                    if ($pendingParenthesisCount > 0) {
                        $buffer[] = $token;
                    }
                    $pendingParenthesisCount++;
                } elseif (isset($token[0]) && !in_array($token[0], [T_WHITESPACE, T_COMMENT])) {
                    // ignore comments and whitespaces
                    $buffer[] = $token;
                }
            }
        }

        return $messages;
    }
protected function extractMessagesFromTokens ( array $ tokens , array $ translatorTokens , array $ ignoreCategories ) { $ messages = [ ] ; $ translatorTokensCount = count ( $ translatorTokens ) ; $ matchedTokensCount = 0 ; $ buffer = [ ] ; $ pendingParenthesisCount = 0 ; foreach ( $ tokens as $ tokenIndex => $ token ) { // finding out translator call if ( $ matchedTokensCount < $ translatorTokensCount ) { if ( $ this -> tokensEqual ( $ token , $ translatorTokens [ $ matchedTokensCount ] ) ) { $ matchedTokensCount ++ ; } else { $ matchedTokensCount = 0 ; } } elseif ( $ matchedTokensCount === $ translatorTokensCount ) { // translator found // end of function call if ( $ this -> tokensEqual ( ')' , $ token ) ) { $ pendingParenthesisCount -- ; if ( $ pendingParenthesisCount === 0 ) { // end of translator call or end of something that we can't extract if ( isset ( $ buffer [ 0 ] [ 0 ] , $ buffer [ 1 ] , $ buffer [ 2 ] [ 0 ] ) && $ buffer [ 0 ] [ 0 ] === T_CONSTANT_ENCAPSED_STRING && $ buffer [ 1 ] === ',' && $ buffer [ 2 ] [ 0 ] === T_CONSTANT_ENCAPSED_STRING ) { // is valid call we can extract $ category = stripcslashes ( $ buffer [ 0 ] [ 1 ] ) ; $ category = mb_substr ( $ category , 1 , - 1 ) ; if ( ! $ this -> isCategoryIgnored ( $ category , $ ignoreCategories ) ) { $ fullMessage = mb_substr ( $ buffer [ 2 ] [ 1 ] , 1 , - 1 ) ; $ i = 3 ; while ( $ i < count ( $ buffer ) - 1 && ! is_array ( $ buffer [ $ i ] ) && $ buffer [ $ i ] === '.' ) { $ fullMessage .= mb_substr ( $ buffer [ $ i + 1 ] [ 1 ] , 1 , - 1 ) ; $ i += 2 ; } $ message = stripcslashes ( $ fullMessage ) ; $ messages [ $ category ] [ ] = $ message ; } $ nestedTokens = array_slice ( $ buffer , 3 ) ; if ( count ( $ nestedTokens ) > $ translatorTokensCount ) { // search for possible nested translator calls $ messages = array_merge_recursive ( $ messages , $ this -> extractMessagesFromTokens ( $ nestedTokens , $ translatorTokens , $ ignoreCategories ) ) ; } } else { // invalid call or dynamic call we can't extract $ line = Console :: ansiFormat ( $ this -> getLine ( $ buffer ) , [ Console :: FG_CYAN ] ) ; $ skipping = Console :: ansiFormat ( 'Skipping line' , [ Console :: FG_YELLOW ] ) ; $ this -> stdout ( "$skipping $line. Make sure both category and message are static strings.\n" ) ; } // prepare for the next match $ matchedTokensCount = 0 ; $ pendingParenthesisCount = 0 ; $ buffer = [ ] ; } else { $ buffer [ ] = $ token ; } } elseif ( $ this -> tokensEqual ( '(' , $ token ) ) { // count beginning of function call, skipping translator beginning // If we are not yet inside the translator, make sure that it's beginning of the real translator. // See https://github.com/yiisoft/yii2/issues/16828 if ( $ pendingParenthesisCount === 0 ) { $ previousTokenIndex = $ tokenIndex - $ matchedTokensCount - 1 ; if ( is_array ( $ tokens [ $ previousTokenIndex ] ) ) { $ previousToken = $ tokens [ $ previousTokenIndex ] [ 0 ] ; if ( in_array ( $ previousToken , [ T_OBJECT_OPERATOR , T_PAAMAYIM_NEKUDOTAYIM ] , true ) ) { $ matchedTokensCount = 0 ; continue ; } } } if ( $ pendingParenthesisCount > 0 ) { $ buffer [ ] = $ token ; } $ pendingParenthesisCount ++ ; } elseif ( isset ( $ token [ 0 ] ) && ! in_array ( $ token [ 0 ] , [ T_WHITESPACE , T_COMMENT ] ) ) { // ignore comments and whitespaces $ buffer [ ] = $ token ; } } } return $ messages ; }
Extracts messages from a parsed PHP tokens list.
@param array $tokens tokens to be processed.
@param array $translatorTokens translator tokens.
@param array $ignoreCategories message categories to ignore.
@return array messages.
Extracts messages from a parsed PHP tokens list .