Smarty Forum Index Smarty
WARNING: All discussion is moving to https://reddit.com/r/smarty, please go there! This forum will be closing soon.

Substitute for Smarty_Compiler reference

 
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Smarty Forum Index -> Smarty 3
View previous topic :: View next topic  
Author Message
felic
Smarty Rookie


Joined: 22 Jul 2003
Posts: 9

PostPosted: Tue Mar 13, 2012 5:41 pm    Post subject: Substitute for Smarty_Compiler reference Reply with quote

Hi,

i currently upgrading from 2 -> 3. I have a compile plugin (which implements i18n gettext translation) that needs a reference to the origin smarty compiler (class Smarty_Compiler). That is because i like to interpolate template vars thru a helper class (Smarty_GettextHelper) which handles the translate and mapping stuff.

Former syntax is fine with Smarty 2:

Code:

/**
 * Smarty {i18n} compiler function plugin
 *
 * Type:     compiler function
 * Name:     i18n
 * Purpose:  Translate string into requested language using gettext
 *
 * @param string containing var-attribute and value-attribute
 * @param Smarty_Compiler
 * @return Template code
 */
function smarty_compiler_i18n ($tag_attrs, &$compiler)
{
  // make sure that we have access to the smarty compiler
  // within Smarty_GettextHelper, because we need it to interpolate
  // the template vars.

  if (!(Smarty_GettextHelper::$compiler instanceof Smarty_Compiler)) {
    Smarty_GettextHelper::$compiler = &$compiler;
  }

  /* ... quit few further code ... */
}


As there is no longer a dedicated Smarty_Compiler class in the current version of smarty, i am not sure how to substitute this. Hopefully there is a simple solution without a plugin rewrite from scratch. It seems i quit miss the spot where to look at within the new API.

Any hints are much appreciated.

greets
Olaf
Back to top
View user's profile Send private message
U.Tews
Administrator


Joined: 22 Nov 2006
Posts: 5068
Location: Hamburg / Germany

PostPosted: Tue Mar 13, 2012 6:19 pm    Post subject: Reply with quote

Smarty3 internals work completely different.

Without knowing what Smarty_GettextHelper and the rest of the plugin does I can't give hints.
Back to top
View user's profile Send private message
felic
Smarty Rookie


Joined: 22 Jul 2003
Posts: 9

PostPosted: Tue Mar 13, 2012 7:53 pm    Post subject: Reply with quote

As the source code is well commented, i just post the two related files. Thanks for digging in.

Code:

File: compiler.i18.php

/**
 * Smarty {i18n} compiler function plugin
 *
 * Type:     compiler function
 * Name:     i18n
 * Purpose:  Translate string into requested language using gettext
 *
 * @param string containing var-attribute and value-attribute
 * @param Smarty_Compiler
 * @return Template code
 */
function smarty_compiler_i18n ($tag_attrs, &$compiler)
{
   // make sure that we have access to the smarty compiler
   // within Smarty_GettextHelper, because we need it to interpolate
   // the template vars.
   if (!(Smarty_GettextHelper::$compiler instanceof Smarty_Compiler)) {
      Smarty_GettextHelper::$compiler = &$compiler;
   }
   
   // skip processing if tag_attrs is empty
   if (empty($tag_attrs)) {
      $smarty->trigger_error("i18n: No message supplied", E_USER_WARNING);
      return false;
   }
   
   if (preg_match(SMARTY_GETTEXT_REGEX_PLURAL_MATCH, $tag_attrs, $matches)) {
      // import found strings to translate
      $singular_string = $matches[1];
      $plural_string = $matches[3];
      $count = $matches[5];
      
      // substitute escaped pipes
      $singular_string = str_replace('\|', '|', $singular_string);
      $plural_string = str_replace('\|', '|', $plural_string);
      
      // do the first preg_replace run. we can go over the whole string, because the translator
      // callback survives not used template vars.
      preg_replace_callback(SMARTY_GETTEXT_REGEX_PLURAL_SUBSTITUTION, array("Smarty_GettextHelper",
         "preg_collector_callback"), $tag_attrs);
      
      // prepare first part of template code. we have to keep a serialized copy
      // of the var map, because we don't have access to the compiler from the compiled
      // template.
      
      $template_code = "
         \$map = '".addslashes(serialize(Smarty_GettextHelper::$map))."';
         Smarty_GettextHelper::\$map = unserialize(stripslashes(\$map));
         \$printf_args = array();
      ";
      
      // now we need to write all variable->value mappings down, so that
      // they can be used in vprintf(). we have to do that now, because
      // otherwise it's impossible to access the template vars from the compiled
      // template without using eval.
      foreach (Smarty_GettextHelper::$map as $_key => $_value) {
         $template_code .= "\$printf_args[".$_value['counter']."] = ".$_value['value'].";";
      }
      
      // last but not least we can complete the required code for the ngettext() call
      // and for the variable substitution.
      $template_code .= "
         \$translated = ngettext(stripslashes('".addslashes($singular_string)."'),
             stripslashes('".addslashes($plural_string)."'), ".$compiler->_parse_var_props($count).");
         \$prepared = preg_replace_callback('".SMARTY_GETTEXT_REGEX_PLURAL_SUBSTITUTION."',
             array('Smarty_GettextHelper', 'preg_translator_callback'), \$translated);
         ksort(\$printf_args);
         vprintf(\$prepared, \$printf_args);
      ";
      
      // reset the map and the counter in our gettext helper class. if we don't do
      // that, we'll waste resources and get weired results.
      Smarty_GettextHelper::$map = array();
      Smarty_GettextHelper::$counter = 1;

      //return the created template code to the compiler
      return $template_code;
   } else {
      // it's time to do our first preg_replace run to find all template vars we
      // have to substitute and to create the map for the substitution that can
      // be used by the compiled template.
      preg_replace_callback(SMARTY_GETTEXT_REGEX_SINGULAR_SUBSTITUTION, array("Smarty_GettextHelper",
         "preg_collector_callback"), $tag_attrs);
      
      // prepare first part of template code. we have to keep a serialized copy
      // of the var map, because we don't have access to the compiler from the compiled
      // template.
      
      $template_code = "
         \$map = '".addslashes(serialize(Smarty_GettextHelper::$map))."';
         Smarty_GettextHelper::\$map = unserialize(stripslashes(\$map));
         \$printf_args = array();
      ";
      
      // now we need to write all variable->value mappings down, so that
      // they can be used in vprintf(). we have to do that now, because
      // otherwise it's impossible to access the template vars from the compiled
      // template without using eval.
      foreach (Smarty_GettextHelper::$map as $_key => $_value) {
         $template_code .= "\$printf_args[".$_value['counter']."] = ".$_value['value'].";";
      }
      
      // last but not least we can complete the required code for the gettext() call
      // and for the variable substitution.
      $template_code .= "
         \$translated = gettext(stripslashes('".addslashes($tag_attrs)."'));
         \$prepared = preg_replace_callback('".SMARTY_GETTEXT_REGEX_SINGULAR_SUBSTITUTION."',
             array('Smarty_GettextHelper', 'preg_translator_callback'), \$translated);
         ksort(\$printf_args);
         vprintf(\$prepared, \$printf_args);
      ";
      
      // reset the map and the counter in our gettext helper class. if we don't do
      // that, we'll waste resources and get weired results.
      Smarty_GettextHelper::$map = array();
      Smarty_GettextHelper::$counter = 1;

      // return the created template code to the compiler
      return $template_code;
   }   
}


Code:

File: Smarty_GettextHelper.class.php


/**
 * Regex constant for Smarty::Gettext defining the match regex for plural forms
 *
 * @var string
 */
define('SMARTY_GETTEXT_REGEX_PLURAL_MATCH',
   '=^((.*?)[^\x5c])\|((.*?)[^\x5c])\|\W*([0-9]+|\$[a-z0-9_.\x7c]+)$=im');

/**
 * Regex constant for Smarty::Gettext defining the search pattern for template
 * variables in singular phrases.
 *
 * @var string
 */
define('SMARTY_GETTEXT_REGEX_SINGULAR_SUBSTITUTION', '=`%([a-z0-9_.\x3a]+?)`=i');

/**
 * Regex constant for Smarty::Gettext defining the search pattern for template
 * variables in plural phrases.
 *
 * @var string
 */
define('SMARTY_GETTEXT_REGEX_PLURAL_SUBSTITUTION', '=`%([a-z0-9_.\x3a]+?)`=i');

class Smarty_GettextHelper
{
   /**
    * Smarty_Compiler instance
    *
    * @var object
     */
   public static $compiler = null;

   /**
    * Temporary map for template vars
    *
    * @var array
    */
   public static $map = array();

   /**
    * Template var counter
    *
    * @var int
    */
   public static $counter = 1;

   /**
    * Callback for preg_replace_callback(). Searches preg matches for template vars.
    * Found vars will be added to the template var map. Takes array with preg matches
    * as first argument.
    *
    * @param array Preg matches
    */
   public static function preg_collector_callback ($matches)
   {
      // make sure we add a var only once
      if (!array_key_exists($matches[0], Smarty_GettextHelper::$map)) {
         $matches[1] = str_replace(':', '|', $matches[1]);
         Smarty_GettextHelper::$map[$matches[0]] = array(
            'counter' => Smarty_GettextHelper::$counter,
            'value' => Smarty_GettextHelper::$compiler->_parse_var_props('$'.$matches[1])
         );

         Smarty_GettextHelper::$counter++;
      }
   }

   /**
    * Callback for preg_replace_callback(). Searches preg matches for template vars
    * and replaces them with sprintf() placeholders. Takes array with preg matches
    * as first argument, returns string.
    *
    * @param array Preg matches
    * @return string
    */
   public static function preg_translator_callback ($matches)
   {   
      return ' %'.Smarty_GettextHelper::$map[$matches[0]]['counter'].'$s';
   }
   
}
[/quote]
Back to top
View user's profile Send private message
U.Tews
Administrator


Joined: 22 Nov 2006
Posts: 5068
Location: Hamburg / Germany

PostPosted: Tue Mar 13, 2012 10:21 pm    Post subject: Reply with quote

As I see it you needed the compiler to for the passed attribute values as Smarty 2 did pass the complete source string.

Smarty 3 works different for compiled plugins. you will receive an array of attributes where the parameter ´values are already precompiled.

template example:
Code:
{example  foo=$bar buh="something"}


Smarty 3 compiler.example.php
Code:
function smarty_compiler_example($params, $smarty)
{
    var_dump($params);
    return '<?php echo '.$params['foo'].';?>';
}


The var_dump will show the precompiled attribute values like:
array(2) { ["foo"]=> string(36) "$_smarty_tpl->tpl_vars['bar']->value" ["buh"]=> string(11) ""something"" }

The returned compiled output will be:
'<?php echo $_smarty_tpl->tpl_vars['bar']->value;?>'

So there should be no need to access the compiler itself in Smarty 3.
Back to top
View user's profile Send private message
felic
Smarty Rookie


Joined: 22 Jul 2003
Posts: 9

PostPosted: Wed Mar 14, 2012 5:36 pm    Post subject: Reply with quote

Thanks a lot for your answer. Marvelous, this spares a lot of code at least Wink

And if i quote the string like that

Code:

{i18n 'String'}



i get nearly the same portions of source strings which fits the .mo translation strings.

Thx again, greets
Back to top
View user's profile Send private message
Display posts from previous:   
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Smarty Forum Index -> Smarty 3 All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP