轉載php
我本身在寫項目的時候,不喜歡使用php自身的模板,主要是各類PHP標籤讓我煩,並且對Html的標籤兼容也不夠友好,因此我後面採用了twig模板,配置之類的也是很方便,寫起來也很順手,可是在Yii2語言國際化翻譯這塊就遇到了坑,當咱們指定文件類型,除了處理php擴展的以外,也處理twig擴展的文件的時候,就不會解析twig中的內容,由於不符合PHP的標籤處理邏輯,在PHP中咱們使用Yii::t(),可是在twig中使用的是Yii.t()這個函數在translator的配置中,顯得很乏力,並且看源碼也能夠發現,實際上也只處理php文件,網上找了不少針對這個問題的處理方式,彷佛也沒有幾個使用的。如今看下我是如何解決的git
將twig擴展加入進去,修改後以下:app
return [ 'color' => null, 'interactive' => true, 'help' => null, 'sourcePath' => '@app', 'messagePath' => '@app/messages', 'languages' => ['zh-CN', 'ru-RU'], 'translator' => 'Yii::t', // 翻譯器 'sort' => false, 'overwrite' => true, 'removeUnused' => false, 'markUnused' => true, 'except' => [ '.svn', '.git', '.gitignore', '.gitkeep', '.hgignore', '.hgkeep', '/messages', '/BaseYii.php', 'vendor', 'tests', 'runtime', 'migrations', ], 'only' => [ '*.php', '*.twig', // 添加模板擴展 ], 'format' => 'php', 'db' => 'db', 'sourceMessageTable' => '{{%source_message}}', 'messageTable' => '{{%message}}', 'catalog' => 'messages', 'ignoreCategories' => [], 'phpFileHeader' => '', 'phpDocBlock' => null, ];
建立文件app/commands/TranslatorController.php,內容以下yii
<?php namespace app\commands; use yii\console\controllers\MessageController; use yii\helpers\Console; /** * Extracts messages to be translated from source files. * * @author durban.zhang <durban.zhang@gmail.com> */ class TranslatorController extends MessageController { public function init() { parent::init(); } /** * This command echoes what you have entered as the message. * @param string $message the message to be echoed. */ protected function extractMessages($fileName, $translator, $ignoreCategories = []) { $messages = []; $extInfo = pathinfo($fileName, PATHINFO_EXTENSION); if ('twig' == $extInfo) { $coloredFileName = Console::ansiFormat($fileName, [Console::FG_CYAN]); $this->stdout("Extracting messages from $coloredFileName...\n"); $subject = file_get_contents($fileName); $preg = '/\{\{ Yii\.t\(\'(.*?)\', \'(.*?)\'\) \}\}/'; $content = preg_replace($preg, "<?php Yii::t('$1', '$2'); ?>", $subject); $tokens = token_get_all($content); foreach ((array) $translator as $currentTranslator) { $translatorTokens = token_get_all('<?php ' . $currentTranslator); array_shift($translatorTokens); $messages = array_merge_recursive( $messages, $this->extractMessagesFromTokens( $tokens, $translatorTokens, $ignoreCategories)); } $this->stdout("\n"); } else { $messages = parent::extractMessages($fileName, $translator, $ignoreCategories); } return $messages; } protected 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--; if (0 === $pendingParenthesisCount) { // end of translator call or end of something that we can't extract if (isset($buffer[0][0], $buffer[1], $buffer[2][0]) && T_CONSTANT_ENCAPSED_STRING === $buffer[0][0] && ',' === $buffer[1] && T_CONSTANT_ENCAPSED_STRING === $buffer[2][0]) { // is valid call we can extract $category = stripcslashes($buffer[0][1]); $category = mb_substr($category, 1, -1); if (!$this->isCategoryIgnored($category, $ignoreCategories)) { $message = stripcslashes($buffer[2][1]); $message = mb_substr($message, 1, -1); $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 ($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; } }
從上面的代碼能夠看出,實現了兩個方法
extractMessages和extractMessagesFromTokens
原本是不須要實現extractMessagesFromTokens這個方法的,可是父類中的private,試過了實例化類,可是須要傳遞須要的參數,爲了不出現問題,暫時沒用實例化的方式。
最後extractMessagesFromTokens 這個只是父類的copy版本。那麼重點就在extractMessages
判斷若是文件是twig文件,則進行處理,處理邏輯我寫的也很簡單,暫時能解決問題svn
$preg = '/\{\{ Yii\.t\(\'(.*?)\', \'(.*?)\'\) \}\}/'; $content = preg_replace($preg, "<?php Yii::t('$1', '$2'); ?>", $subject); $tokens = token_get_all($content);
主要是將Yii.t轉爲了含有PHP標籤的字符串,實際上父類也只是針對代碼進行字符串的過濾處理,以此類推的話,若是有其餘模板的話也能夠採用此方法函數
到這裏就處理完了,this
可是執行的命令不是下面這個spa
./yii message/extract @app/config/i18n.php
而是下面這個翻譯
./yii translator/extract @app/config/i18n.php
OK,問題解決,如您有其餘方案,請指教code