Chris@0: t() calls in Drupal 8. Chris@0: * Chris@0: * @var bool Chris@0: */ Chris@0: protected $includeMethodCalls = true; Chris@0: Chris@0: Chris@0: /** Chris@0: * Returns an array of function names this test wants to listen for. Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: public function registerFunctionNames() Chris@0: { Chris@0: return array( Chris@0: 't', Chris@0: 'TranslatableMarkup', Chris@0: 'TranslationWrapper', Chris@0: ); Chris@0: Chris@0: }//end registerFunctionNames() Chris@0: Chris@0: Chris@0: /** Chris@0: * Processes this function call. Chris@0: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. Chris@17: * @param int $stackPtr The position of the function call in Chris@17: * the stack. Chris@17: * @param int $openBracket The position of the opening Chris@17: * parenthesis in the stack. Chris@17: * @param int $closeBracket The position of the closing Chris@17: * parenthesis in the stack. Chris@0: * Chris@0: * @return void Chris@0: */ Chris@0: public function processFunctionCall( Chris@17: File $phpcsFile, Chris@0: $stackPtr, Chris@0: $openBracket, Chris@0: $closeBracket Chris@0: ) { Chris@0: $tokens = $phpcsFile->getTokens(); Chris@0: $argument = $this->getArgument(1); Chris@0: Chris@0: if ($argument === false) { Chris@0: $error = 'Empty calls to t() are not allowed'; Chris@0: $phpcsFile->addError($error, $stackPtr, 'EmptyT'); Chris@0: return; Chris@0: } Chris@0: Chris@0: if ($tokens[$argument['start']]['code'] !== T_CONSTANT_ENCAPSED_STRING) { Chris@0: // Not a translatable string literal. Chris@0: $warning = 'Only string literals should be passed to t() where possible'; Chris@0: $phpcsFile->addWarning($warning, $argument['start'], 'NotLiteralString'); Chris@0: return; Chris@0: } Chris@0: Chris@0: $string = $tokens[$argument['start']]['content']; Chris@0: if ($string === '""' || $string === "''") { Chris@0: $warning = 'Do not pass empty strings to t()'; Chris@0: $phpcsFile->addWarning($warning, $argument['start'], 'EmptyString'); Chris@0: return; Chris@0: } Chris@0: Chris@17: $concatAfter = $phpcsFile->findNext(Tokens::$emptyTokens, ($closeBracket + 1), null, true, null, true); Chris@0: if ($concatAfter !== false && $tokens[$concatAfter]['code'] === T_STRING_CONCAT) { Chris@17: $stringAfter = $phpcsFile->findNext(Tokens::$emptyTokens, ($concatAfter + 1), null, true, null, true); Chris@0: if ($stringAfter !== false Chris@0: && $tokens[$stringAfter]['code'] === T_CONSTANT_ENCAPSED_STRING Chris@0: && $this->checkConcatString($tokens[$stringAfter]['content']) === false Chris@0: ) { Chris@0: $warning = 'Do not concatenate strings to translatable strings, they should be part of the t() argument and you should use placeholders'; Chris@0: $phpcsFile->addWarning($warning, $stringAfter, 'ConcatString'); Chris@0: } Chris@0: } Chris@0: Chris@0: $lastChar = substr($string, -1); Chris@0: if ($lastChar === '"' || $lastChar === "'") { Chris@0: $message = substr($string, 1, -1); Chris@0: if ($message !== trim($message)) { Chris@0: $warning = 'Translatable strings must not begin or end with white spaces, use placeholders with t() for variables'; Chris@0: $phpcsFile->addWarning($warning, $argument['start'], 'WhiteSpace'); Chris@0: } Chris@0: } Chris@0: Chris@0: $concatFound = $phpcsFile->findNext(T_STRING_CONCAT, $argument['start'], $argument['end']); Chris@0: if ($concatFound !== false) { Chris@0: $error = 'Concatenating translatable strings is not allowed, use placeholders instead and only one string literal'; Chris@0: $phpcsFile->addError($error, $concatFound, 'Concat'); Chris@0: } Chris@0: Chris@0: // Check if there is a backslash escaped single quote in the string and Chris@0: // if the string makes use of double quotes. Chris@0: if ($string{0} === "'" && strpos($string, "\'") !== false Chris@0: && strpos($string, '"') === false Chris@0: ) { Chris@0: $warn = 'Avoid backslash escaping in translatable strings when possible, use "" quotes instead'; Chris@0: $phpcsFile->addWarning($warn, $argument['start'], 'BackslashSingleQuote'); Chris@0: return; Chris@0: } Chris@0: Chris@0: if ($string{0} === '"' && strpos($string, '\"') !== false Chris@0: && strpos($string, "'") === false Chris@0: ) { Chris@0: $warn = "Avoid backslash escaping in translatable strings when possible, use '' quotes instead"; Chris@0: $phpcsFile->addWarning($warn, $argument['start'], 'BackslashDoubleQuote'); Chris@0: } Chris@0: Chris@0: }//end processFunctionCall() Chris@0: Chris@0: Chris@0: /** Chris@0: * Checks if a string can be concatenated with a translatable string. Chris@0: * Chris@0: * @param string $string The string that is concatenated to a t() call. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the string is allowed to be concatenated with a translatable Chris@0: * string, FALSE if not. Chris@0: */ Chris@0: protected function checkConcatString($string) Chris@0: { Chris@0: // Remove outer quotes, spaces and HTML tags from the original string. Chris@0: $string = trim($string, '"\''); Chris@0: $string = trim(strip_tags($string)); Chris@0: Chris@0: if ($string === '') { Chris@0: return true; Chris@0: } Chris@0: Chris@17: $allowed_items = array( Chris@17: '(', Chris@17: ')', Chris@17: '[', Chris@17: ']', Chris@17: '-', Chris@17: '<', Chris@17: '>', Chris@17: '«', Chris@17: '»', Chris@17: '\n', Chris@17: ); Chris@17: foreach ($allowed_items as $item) { Chris@17: if ($item === $string) { Chris@17: return true; Chris@17: } Chris@0: } Chris@0: Chris@0: return false; Chris@0: Chris@0: }//end checkConcatString() Chris@0: Chris@0: Chris@0: }//end class