Browse Source

`yii\console\controllers\MessageController` improved allowing extraction of nested translator calls

tags/2.0.6
Klimov Paul 10 years ago
parent
commit
72ec914992
  1. 1
      framework/CHANGELOG.md
  2. 78
      framework/console/controllers/MessageController.php
  3. 21
      tests/framework/console/controllers/BaseMessageControllerTest.php

1
framework/CHANGELOG.md

@ -5,6 +5,7 @@ Yii Framework 2 Change Log
-----------------------
- Bug #8322: `yii\behaviors\TimestampBehavior::touch()` now throws an exception if owner is new record (klimov-paul)
- Enh #8286: `yii\console\controllers\MessageController` improved allowing extraction of nested translator calls (klimov-paul)
2.0.4 May 10, 2015

78
framework/console/controllers/MessageController.php

@ -248,33 +248,55 @@ class MessageController extends Controller
{
$coloredFileName = Console::ansiFormat($fileName, [Console::FG_CYAN]);
$this->stdout("Extracting messages from $coloredFileName...\n");
$subject = file_get_contents($fileName);
$messages = [];
foreach ((array)$translator as $currentTranslator) {
$translatorTokens = token_get_all('<?php ' . $currentTranslator);
array_shift($translatorTokens);
$tokens = token_get_all($subject);
$messages = array_merge_recursive($messages, $this->extractMessagesFromTokens($tokens, $translatorTokens, $ignoreCategories));
}
$translatorTokensCount = count($translatorTokens);
$matchedTokensCount = 0;
$buffer = [];
$this->stdout("\n");
$tokens = token_get_all($subject);
foreach ($tokens as $token) {
// finding out translator call
if ($matchedTokensCount < $translatorTokensCount) {
if ($this->tokensEqual($token, $translatorTokens[$matchedTokensCount])) {
$matchedTokensCount++;
} else {
$matchedTokensCount = 0;
}
} elseif ($matchedTokensCount === $translatorTokensCount) {
// translator found
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.
*/
private function extractMessagesFromTokens(array $tokens, array $translatorTokens, array $ignoreCategories)
{
$messages = [];
$translatorTokensCount = count($translatorTokens);
$matchedTokensCount = 0;
$buffer = [];
$pendingParenthesisCount = 0;
foreach ($tokens as $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--;
// end of translator call or end of something that we can't extract
if ($this->tokensEqual(')', $token)) {
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, mb_strlen($category) - 2);
@ -284,9 +306,14 @@ class MessageController extends Controller
$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");
@ -294,17 +321,24 @@ class MessageController extends Controller
// prepare for the next match
$matchedTokensCount = 0;
$pendingParenthesisCount = 0;
$buffer = [];
} elseif ($token !== '(' && isset($token[0]) && !in_array($token[0], [T_WHITESPACE, T_COMMENT])) {
// ignore comments, whitespaces and beginning of function call
} else {
$buffer[] = $token;
}
} elseif ($this->tokensEqual('(', $token)) {
// count beginning of function call, skipping translator beginning
if ($pendingParenthesisCount > 0) {
$buffer[] = $token;
}
$pendingParenthesisCount++;
} elseif (isset($token[0]) && !in_array($token[0], [T_WHITESPACE, T_COMMENT])) {
// ignore comments and whitespaces
$buffer[] = $token;
}
}
}
$this->stdout("\n");
return $messages;
}

21
tests/framework/console/controllers/BaseMessageControllerTest.php

@ -377,6 +377,27 @@ abstract class BaseMessageControllerTest extends TestCase
$this->assertArrayNotHasKey($message3, $messages2, "message3 not found in category2. Command output:\n\n" . $out);
$this->assertArrayNotHasKey($message2, $messages2, "message2 found in category2. Command output:\n\n" . $out);
}
/**
* @depends testCreateTranslation
*
* @see https://github.com/yiisoft/yii2/issues/8286
*/
public function testCreateTranslationFromNested()
{
$category = 'test.category1';
$mainMessage = 'main message';
$nestedMessage = 'nested message';
$sourceFileContent = "Yii::t('{$category}', '{$mainMessage}', ['param' => Yii::t('{$category}', '{$nestedMessage}')]);";
$this->createSourceFile($sourceFileContent);
$this->saveConfigFile($this->getConfig());
$out = $this->runMessageControllerAction('extract', [$this->configFileName]);
$messages = $this->loadMessages($category);
$this->assertArrayHasKey($mainMessage, $messages, "\"$mainMessage\" is missing in translation file. Command output:\n\n" . $out);
$this->assertArrayHasKey($nestedMessage, $messages, "\"$nestedMessage\" is missing in translation file. Command output:\n\n" . $out);
}
}
class MessageControllerMock extends MessageController

Loading…
Cancel
Save