Root/
<?php /* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* # ***** BEGIN LICENSE BLOCK ***** # This file is part of Plume Framework, a simple PHP Application Framework. # Copyright (C) 2001-2007 Loic d'Anterroches and contributors. # # Plume Framework is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # Plume Framework is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # ***** END LICENSE BLOCK ***** */ /** * Class to extract the translation strings from the template. * * Based on Pluf_Template_Compiler with code: * Copyright (C) 2006 Laurent Jouanneau. */ class Pluf_Translation_TemplateExtractor { /** * Store the literal blocks. **/ protected $_literals ; /** * Variables. */ protected $_vartype = array (T_CHARACTER, T_CONSTANT_ENCAPSED_STRING, T_DNUMBER, T_ENCAPSED_AND_WHITESPACE, T_LNUMBER, T_OBJECT_OPERATOR, T_STRING, T_WHITESPACE, T_ARRAY); /** * Assignation operators. */ protected $_assignOp = array (T_AND_EQUAL, T_DIV_EQUAL, T_MINUS_EQUAL, T_MOD_EQUAL, T_MUL_EQUAL, T_OR_EQUAL, T_PLUS_EQUAL, T_PLUS_EQUAL, T_SL_EQUAL, T_SR_EQUAL, T_XOR_EQUAL); /** * Operators. */ protected $_op = array (T_BOOLEAN_AND, T_BOOLEAN_OR, T_EMPTY, T_INC, T_ISSET, T_IS_EQUAL, T_IS_GREATER_OR_EQUAL, T_IS_IDENTICAL, T_IS_NOT_EQUAL, T_IS_NOT_IDENTICAL, T_IS_SMALLER_OR_EQUAL, T_LOGICAL_AND, T_LOGICAL_OR, T_LOGICAL_XOR, T_SR, T_SL, T_DOUBLE_ARROW); /** * Authorized elements in variables. */ protected $_allowedInVar ; /** * Authorized elements in expression. */ protected $_allowedInExpr ; /** * Authorized elements in assignation. */ protected $_allowedAssign ; /** * Output filters. */ protected $_modifier = array ( 'upper' => 'strtoupper' , 'lower' => 'strtolower' , 'escxml' => 'htmlspecialchars' , 'escape' => 'Pluf_Template_htmlspecialchars' , 'strip_tags' => 'strip_tags' , 'escurl' => 'rawurlencode' , 'capitalize' => 'ucwords' , // Not var_export because of recursive issues. 'debug' => 'print_r' , 'fulldebug' => 'var_export' , 'count' => 'count' , 'nl2br' => 'nl2br' , 'trim' => 'trim' , 'unsafe' => 'Pluf_Template_unsafe' , 'safe' => 'Pluf_Template_unsafe' , 'date' => 'Pluf_Template_dateFormat' , 'time' => 'Pluf_Template_timeFormat' , ); /** * After the compilation is completed, this contains the list of * modifiers used in the template. The GetCompiledTemplate method * will add a series of Pluf::loadFunction at the top to preload * these modifiers. */ public $_usedModifiers = array (); /** * Default allowed extra tags/functions. * * These default tags are merged with the 'template_tags' defined * in the configuration of the application. */ protected $_allowedTags = array ( 'url' => 'Pluf_Template_Tag_Url' , ); /** * During compilation, all the tags are created once so to query * their interface easily. */ protected $_extraTags = array (); /** * The block stack to see if the blocks are correctly closed. */ protected $_blockStack = array (); /** * Special stack for the translation handling in blocktrans. */ protected $_transStack = array (); protected $_transPlural = false; /** * Current template source file. */ protected $_sourceFile ; /** * Current tag. */ protected $_currentTag ; /** * Template folders. */ public $templateFolders = array (); /** * Template content. It can be set directly from a string. */ public $templateContent = '' ; /** * Construct the compiler. * * @param string Basename of the template file. * @param array Base folders in which the templates files * should be found. (array()) * @param bool Load directly the template content. (true) */ function __construct( $template_file , $folders = array (), $load =true) { $allowedtags = Pluf::f( 'template_tags' , array ()); $this ->_allowedTags = array_merge ( $allowedtags , $this ->_allowedTags); $modifiers = Pluf::f( 'template_modifiers' , array ()); $this ->_modifier = array_merge ( $modifiers , $this ->_modifier); foreach ( $this ->_allowedTags as $name => $model ) { $this ->_extraTags[ $name ] = new $model (); } $this ->_sourceFile = $template_file ; $this ->_allowedInVar = array_merge ( $this ->_vartype, $this ->_op); $this ->_allowedInExpr = array_merge ( $this ->_vartype, $this ->_op); $this ->_allowedAssign = array_merge ( $this ->_vartype, $this ->_assignOp, $this ->_op); $this ->templateFolders = $folders ; if ( $load ) { $this ->loadTemplateFile( $template_file ); } } /** * Get blocktrans. */ function getBlockTrans() { $tplcontent = $this ->templateContent; $tplcontent = preg_replace( '!{\*(.*?)\*}!s' , '' , $tplcontent ); $match = array (); preg_match_all( '!{blocktrans(.*?){/blocktrans}!s' , $tplcontent , $match ); $res = array (); foreach ( $match [1] as $m ) { $res [] = '{blocktrans' . $m . '{/blocktrans}' ; } return $res ; } /** * Get simple trans call. */ function getSimpleTrans() { $tplcontent = $this ->templateContent; $tplcontent = preg_replace( '!{\*(.*?)\*}!s' , '' , $tplcontent ); $match = array (); preg_match_all( '!{trans(.*?)}!s' , $tplcontent , $match ); $res = array (); foreach ( $match [1] as $m ) { $res [] = '{trans' . $m . '}' ; } return $res ; } /** * Compile the template into a file ready to parse with xgettext. * * @return string PHP code of the compiled template. */ function compile() { $result = '' ; $blocktrans = $this ->getBlockTrans(); // Parse the blocktrans foreach ( $blocktrans as $block ) { $match = array (); if (preg_match( '!{blocktrans(.*?)}(.*?){plural}(.*?){/blocktrans}!s' , $block , $match )) { $sing = $match [2]; $plural = $match [3]; $sing = preg_replace_callback( '/{((.).*?)}/s' , array ( $this , '_callbackInTransBlock' ), $sing ); $plural = preg_replace_callback( '/{((.).*?)}/s' , array ( $this , '_callbackInTransBlock' ), $plural ); $result .= '_n(\'' . addcslashes ( $sing , "'" ).'\ ', \'' . addcslashes ( $plural , "'" ).'\ ', $n);' . "\n" ; } elseif (preg_match( '!{blocktrans}(.*?){/blocktrans}!s' , $block , $match )) { $sing = preg_replace_callback( '/{((.).*?)}/s' , array ( $this , '_callbackInTransBlock' ), $match [1]); $result .= '__(\'' . addcslashes ( $sing , "'" ).'\ ');' . "\n" ; } } $simpletrans = $this ->getSimpleTrans(); foreach ( $simpletrans as $content ) { $result .= preg_replace_callback( '/{((.).*?)}/s' , array ( $this , '_callback' ), $content ); } return '<?php # This is not a valid php code. It is just for gettext use' . "\n\n" . $result . ' ?>' ; } /** * Load a template file. * * The path to the file to load is relative and the file is found * in one of the $templateFolders array of folders. * * @param string Relative path of the file to load. */ function loadTemplateFile( $file ) { // FIXME: Very small security check, could be better. if ( strpos ( $file , '..' ) !== false) { throw new Exception(sprintf(__( 'Template file contains invalid characters: %s' ), $file )); } foreach ( $this ->templateFolders as $folder ) { if ( file_exists ( $folder . '/' . $file )) { $this ->templateContent = file_get_contents ( $folder . '/' . $file ); return ; } } // File not found in all the folders. throw new Exception(sprintf(__( 'Template file not found: %s' ), $file )); } function _callback( $matches ) { list(, $tag , $firstcar ) = $matches ; if ( $firstcar != 't' ) { trigger_error(sprintf(__( 'Invalid tag in translation extractor: %s' ), $tag ), E_USER_ERROR); return '' ; } $this ->_currentTag = $tag ; if (!preg_match( '/^(\/?[a-zA-Z0-9_]+)(?:(?:\s+(.*))|(?:\((.*)\)))?$/' , $tag , $m )) { trigger_error(sprintf(__( 'Invalid function syntax: %s' ), $tag ), E_USER_ERROR); return '' ; } if ( count ( $m ) == 4){ $m [2] = $m [3]; } if (!isset( $m [2])) $m [2] = '' ; if ( $m [1] == 'trans' ) { return $this ->_parseFunction( $m [1], $m [2]); } return '' ; } function _callbackInTransBlock( $matches ) { list(, $tag , $firstcar ) = $matches ; if (!preg_match( '/^\$|[\'"]|[a-zA-Z\/]$/' , $firstcar )) { trigger_error(sprintf(__( 'Invalid tag syntax: %s' ), $tag ), E_USER_ERROR); return '' ; } $this ->_currentTag = $tag ; if ( $firstcar == '$' ) { $tok = explode ( '|' , $tag ); $this ->_transStack[ substr ( $tok [0], 1)] = $this ->_parseVariable( $tag ); return '%%' . substr ( $tok [0], 1). '%%' ; } return '' ; } function _parseVariable( $expr ) { $tok = explode ( '|' , $expr ); $res = $this ->_parseFinal( array_shift ( $tok ), $this ->_allowedInVar); // We do not take into account the modifiers. return $res ; } function _parseFunction( $name , $args ) { switch ( $name ) { case 'trans' : $argfct = $this ->_parseFinal( $args , $this ->_allowedAssign); $res = '__(' . $argfct . ');' . "\n" ; break ; default : $res = '' ; break ; } return $res ; } /* ------- if: op, autre, var foreach: T_AS, T_DOUBLE_ARROW, T_VARIABLE, @locale@ for: autre, fin_instruction while: op, autre, var assign: T_VARIABLE puis assign puis autre, ponctuation, T_STRING echo: T_VARIABLE/@locale@ puis autre + ponctuation modificateur: serie de autre séparé par une virgule tous : T_VARIABLE, @locale@ */ function _parseFinal( $string , $allowed = array (), $exceptchar = array ( ';' )) { $tokens = token_get_all( '<?php ' . $string . '?>' ); $result = '' ; $first = true; $inDot = false; $firstok = array_shift ( $tokens ); $afterAs = false; $f_key = '' ; $f_val = '' ; $results = array (); // il y a un bug, parfois le premier token n'est pas T_OPEN_TAG... if ( $firstok == '<' && $tokens [0] == '?' && is_array ( $tokens [1]) && $tokens [1][0] == T_STRING && $tokens [1][1] == 'php' ) { array_shift ( $tokens ); array_shift ( $tokens ); } foreach ( $tokens as $tok ) { if ( is_array ( $tok )) { list( $type , $str ) = $tok ; $first = false; if ( $type == T_CLOSE_TAG){ continue ; } if ( $type == T_AS) { $afterAs = true; } if ( $type == T_STRING && $inDot ) { $result .= $str ; } elseif ( $type == T_VARIABLE) { $result .= '$t->_vars[\'' . substr ( $str , 1). '\']' ; } elseif ( $type == T_WHITESPACE || in_array( $type , $allowed )) { $result .= $str ; } else { trigger_error(sprintf(__( 'Invalid syntax: (%s) %s.' ), $this ->_currentTag, $str ), E_USER_ERROR); return '' ; } } else { if (in_array( $tok , $exceptchar )) { trigger_error(sprintf(__( 'Invalid character: (%s) %s.' ), $this ->_currentTag, $tok ), E_USER_ERROR); } elseif ( $tok == '.' ) { $inDot = true; $result .= '->' ; } elseif ( $tok == '~' ) { $result .= '.' ; } elseif ( $tok == '[' ) { $result .= $tok ; } elseif ( $tok == ']' ) { $result .= $tok ; } elseif ( $getAsArray && $tok == ',' ) { $results []= $result ; $result = '' ; } else { $result .= $tok ; } $first = false; } } return $result ; } } |