FRED™  3.0
FRED™: Framework for Rapid and Easy Development
Trans.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Rsi\Fred;
4 
5 /**
6  * Translations component.
7  */
8 class Trans extends Component{
9 
10  const TYPE_TAG = '+'; //!< Add a tag to to the tags: [+tag|value].
11  const TYPE_OPTIONAL = '?'; //!< Optional sub-string (defaults to empty; no error): [?strId].
12  const TYPE_SUBSTR = '@'; //!< Points to a sub-string: [\@strId].
13  const TYPE_TRUE = '%'; //!< Show section when tag value is true: {[%tag]show when tag is not empty}.
14  const TYPE_FALSE = '!'; //!< Show section when tag value is false: {[!tag]show when tag is empty}.
15  const TYPE_COUNT = '#'; //!< Insert number of items in array: Array has [\#arrayTag] items.
16  const TYPE_SUM = '='; //!< Sum of an array column: [=array|column|formatting].
17  const TYPE_ARRAY = '*'; //!< Repeat section for each item (item aded to tags, including k = key, v = value - when record is
18  // not an array, i = index, r = reverse index): Values: [*arrayTag|{\\[i\\], }\\[v\\]].
19  const TYPE_DECODE = ':'; //!< Decode a value: [:intTag|1:foo|2:bar|default]. Set the value to '?' for a random selection.
20  const TYPE_JSON = '$'; //!< Insert a JSON encoded value.
21  const TYPE_RAW = '~'; //!< Insert value without inserting a conditional tag: [[~intTag],number].
22 
23  const MACRO_ESCAPE = 'escape'; //!< Escape the text between these tags (pre processing).
24  const MACRO_SPACE = 'space'; //!< Remove white-space between tags.
25  const MACRO_REPLACE = 'replace'; //!< Replace the text in attribute 'from' (regex) to 'to'.
26  const MACRO_UNITS = 'units'; //!< Split the value of the tag name into units, so it can be used as an array (units in desired
27  // order in the 'units' tag - e.g. 'km=1000,m=1,cm=0.01'; use the 'tolerance' tag to set a cut-off percentage; set the 'tag'
28  // attribute to choose a custom result tag - defaults to current tag + 'Units'; add an 'empty' attribute to include units
29  // without values, if there is a higher unit with a value; pre processing).
30  const MACRO_CONST = 'const'; //!< Replace the text with the value of the constant between the tags (pre processing).
31  const MACRO_CACHE = 'cache'; //!< Cache the (processed) text (set the 'ttl' tag to use the main cache; use the 'key'
32  // attribute to define a custom cache key, otherwise one is generated; the key can contain tags).
33  const MACRO_FRAGMENT = 'fragment'; //!< Replace the tag with a placeholder and replace it with the fragment later on (with
34  // 'delay' attribute) or on demand (set the 'id' attribute).
35  const MACRO_ROUTE = 'route'; //!< Create a (reverse) route for the controller name between the tags (attributes are params).
36  const MACRO_LOCATION = 'location'; //!< Rewrite the location between the tags (pre processing).
37  const MACRO_IMAGE = 'image'; //!< Generate an image tag for the image between the tags (the content is cached, set the 'ttl'
38  // attribute to deviate from the default $imageTtl).
39  const MACRO_URL = 'url'; //!< Load external content from the address between the tags (the content is cached, set the 'ttl'
40  // attribute to deviate from the default $urlTtl; pre processing)).
41  const MACRO_RIGHT = 'right'; //<! Only include the text when the user is authorized for the 'right' attribute (set an
42  // optional 'level'; add a 'not' attribute for the other way round; pre processing).
43 
44  const EVENT_FORMAT = 'trans:format:';
45 
46  public $namespace = 'trans';
47  public $maxNested = 10; //!< Maximum number of times a sub-string may be nested.
48  public $logPrio = Log::INFO; //!< Prio for translation related errors (invalid tags, format, etc).
49  public $imageTtl = 86400; //!< Default cache TTL for image tag generation.
50  public $imageKeyPrefix = 'trans-image-';
51  public $urlTtl = 86400; //!< Default cache TTL for external content.
52  public $urlKeyPrefix = 'trans-url-';
53  public $cacheKeyPrefix = 'trans-cache-';
54 
55  protected $_langId = null;
56  protected $_filename = null; //!< Filename for the translations (asterisk will be replace by the langId).
57  protected $_prefix = null;
58  protected $_strs = [];
59  protected $_tags = []; //!< Default tags to use with every translation.
60 
61  protected $_escape = [];
62  protected $_unescape = [];
63  protected $_cache = [];
64 
65  protected $_types = null;
66  protected $_regex = null;
67 
68  protected function init(){
69  parent::init();
70  if(!$this->_prefix) $this->_prefix = \Rsi\Str::random();
71  foreach(['{','[',']','}'] as $char) $this->_unescape[$this->_escape['\\' . $char] = $this->_prefix . bin2hex($char)] = $char;
72  $this->publish(['langId'],self::READWRITE);
73  }
74  /**
75  * Available languages.
76  * @return array Key = ID, value = description.
77  */
78  public function langs(){
79  return [$this->langId => null];
80  }
81 
82  protected function error($message,$file = null,$line_no = null,$context = null){
83  $this->component('log')->add($this->logPrio,$message,$file,$line_no,$context);
84  return 'error';
85  }
86  /**
87  * Get all strings.
88  * @param string $lang_id Language ID.
89  * @return array Key = string ID, value = string.
90  */
91  protected function getStrs($lang_id){
92  return array_change_key_case(require(str_replace('*',$lang_id,$this->_filename)));
93  }
94  /**
95  * Basic string getter.
96  * @param string $id String ID.
97  * @param string $default Default string when ID is not found.
98  * @return string
99  */
100  public function getStr($id,$default = false){
101  $id = explode('.',$id);
102  $lang_id = count($id) > 1 ? $id[1] : $this->langId;
103  if(!array_key_exists($lang_id,$this->_strs)) $this->_strs[$lang_id] = array_change_key_case($this->getStrs($lang_id));
104  return array_key_exists($id = strtolower($id[0]),$this->_strs[$lang_id]) ? $this->_strs[$lang_id][$id] : $default;
105  }
106 
107  protected function macro($str,$type,&$tags,$callback){
108  if(
109  strpos($str,'<' . ($tag = $this->namespace . ':' . $type)) &&
110  preg_match_all("/<$tag(?<attribs>(" . \Rsi\Str::ATTRIBUTES_PATTERN . ")*)>(?<str>.*?)<\\/$tag>/s",$str,$matches,PREG_SET_ORDER)
111  ) foreach($matches as $match) try{
112  $str = str_replace($match[0],call_user_func_array($callback,[$match['str'],\Rsi\Str::attributes($match['attribs']),&$tags]),$str);
113  }
114  catch(\Exception $e){
115  return $this->error($e,['macro' => $type]);
116  }
117  return $str;
118  }
119 
120  protected function preProcess($str,&$tags){
121  $str = strtr($this->macro($str,self::MACRO_ESCAPE,$tags,function($str){
122  return strtr($str,array_flip($this->_unescape));
123  }),$this->_escape);
124  $str = $this->macro($str,self::MACRO_CACHE,$tags,function($str,$attribs,&$tags){
125  if(!($key = $attribs['key'] ?? null)) $key = md5($str);
126  elseif(preg_match_all('/\\[([\\w\\-]+)\\]/',$key,$matches,PREG_SET_ORDER)) foreach($matches as list($full,$tag)){
127  if(is_array($value = $this->value($tag,null,$tags))) $value = md5(serialize($value));
128  $key = str_replace($full,$value,$key);
129  }
130  $key .= '-' . $this->langId;
131  $ttl = $attribs['ttl'] ?? 0;
132  if(!array_key_exists($key,$this->_cache)) $this->_cache[$key] = $ttl ? $this->component('cache')->fetch($this->cacheKeyPrefix . $key) : false;
133  $exists = $this->_cache[$key] !== false;
134  $tag = $this->namespace . ':' . self::MACRO_CACHE;
135  return "<$tag key='$key'" . ($exists ? '' : " ttl='$ttl'") . '>' . ($exists ? null : $str) . "</$tag>";
136  });
137  $str = $this->macro($str,self::MACRO_CONST,$tags,function($name){
138  return constant($name);
139  });
140  $str = $this->macro($str,self::MACRO_UNITS,$tags,function($tag,$attribs,&$tags){
141  $result = [];
142  foreach(\Rsi\Number::units($value = $tags[$tag] ?? 0,\Rsi\Record::explode($attribs['units'] ?? null,',','='),$value * ($attribs['tolerance'] ?? 0) / 100) as $unit => $count)
143  if($count || array_key_exists('empty',$attribs)) $result[] = compact('unit','count');
144  $tags[$attribs['tag'] ?? $tag . 'Units'] = $result;
145  return null;
146  });
147  $str = $this->macro($str,self::MACRO_LOCATION,$tags,function($str){
148  return htmlspecialchars($this->component('location')->rewrite($str));
149  });
150  $str = $this->macro($str,self::MACRO_URL,$tags,function($url,$attribs){
151  return $this->component('cache')->fetch($this->urlKeyPrefix . $url,$attribs['ttl'] ?? $this->urlTtl,function() use ($url){
152  $this->component('log')->debug("Loading external content from '$url'",__FILE__,__LINE__);
153  return preg_match('/^https?:\\/\\/(?!localhost|127\\.0\\.0\\.|\\[[0:]+1\\])/i',$url) ? file_get_contents($url) : $url;
154  });
155  });
156  $str = $this->macro($str,self::MACRO_RIGHT,$tags,function($str,$attribs){
157  return ($this->component('user')->authorized($attribs['right'] ?? null,$attribs['level'] ?? null) xor ($attribs['not'] ?? false)) ? $str : null;
158  });
159  return $str;
160  }
161 
162  protected function postProcess($str,&$tags){
163  if($str){
164  $str = $this->macro($str,self::MACRO_CACHE,$tags,function($str,$attribs){
165  $key = $attribs['key'];
166  if(($ttl = $attribs['ttl'] ?? false) === false) return $this->_cache[$key];
167  if($ttl) $this->component('cache')->save($this->cacheKeyPrefix . $key,$str,$ttl);
168  return $this->_cache[$key] = $str;
169  });
170  $str = $this->macro($str,self::MACRO_FRAGMENT,$tags,function($str,$attribs){
171  $fragments = $this->session->fragments ?: [];
172  $fragments[$id = $attribs['id'] ?? 'fragment-' . \Rsi\Str::random()] = $str;
173  $this->session->fragments = $fragments;
174  return ($delay = $attribs['delay'] ?? null)
175  ? "<div class='fred-fragment' id='$id'><script>document.addEventListener('DOMContentLoaded',function(){" .
176  "setTimeout(function(){ fred.controller.fragment('#$id','$id') },$delay * 1000)" .
177  "},true)</script></div>"
178  : null;
179  });
180  $str = $this->macro($str,self::MACRO_ROUTE,$tags,function($controller_name,$params){
181  $controller_name = explode('.',$controller_name);
182  if(array_key_exists('_',$params)){
183  foreach(($params['_'] == '*' ? array_keys($_GET) : explode(',',$params['_'])) as $key)
184  if(!array_key_exists($key,$params) && ($value = $this->component('request')->complex($key))) $params[$key] = $value;
185  unset($params['_']);
186  }
187  return htmlspecialchars($this->component('router')->reverse($controller_name[0],$controller_name[1] ?? null,$params));
188  });
189  $str = $this->macro($str,self::MACRO_SPACE,$tags,function($str){
190  return trim(preg_replace('/\\s*\\n\\s*/',"\n",preg_replace('/>\\s+</','><',$str)));
191  });
192  $str = $this->macro($str,self::MACRO_REPLACE,$tags,function($str,$attribs){
193  if(!array_key_exists('from',$attribs)) return $str;
194  if(substr($from = $attribs['from'],0,1) != '/') $from = '/' . preg_quote($from,'/') . '/';
195  return preg_replace($from,$attribs['to'] ?? null,$str);
196  });
197  $str = $this->macro($str,self::MACRO_IMAGE,$tags,function($url,$attribs){
198  return $this->component('cache')->fetch($this->imageKeyPrefix . $url . '?' . http_build_query($attribs),$attribs['ttl'] ?? $this->imageTtl,function() use ($url,$attribs){
199  unset($attribs['ttl']);
200  foreach(['width','height','background'] as $key) if(array_key_exists($key,$attribs) && ($attribs[$key] == 'auto')) $attribs[$key] = true;
201  return $this->component('html')->img($url,$attribs);
202  });
203  });
204  }
205  return $str;
206  }
207  /**
208  * Escape tag values (convert special characters to HTML entities).
209  * @param array $tags Tags with raw values (keys starting with '!' or not escaped - '!' is removed from key).
210  * @return array Escaped tags
211  */
212  public function escape($tags){
213  $escaped = [];
214  if($tags) foreach($tags as $tag => $value){
215  switch(substr($tag,0,1)){
216  case '!': $tag = substr($tag,1); //raw
217  case '@': break; //callback
218  default: if(!is_object($value)) $value = is_array($value) ? $this->escape($value) : htmlspecialchars($value);
219  }
220  $escaped[$tag] = $value;
221  }
222  return $escaped;
223  }
224 
225  protected function value($tag,$params,&$tags){
226  if(\Rsi\Str::numeric($tag)) return $tag;
227  $value = $tags;
228  $found = true;
229  foreach(explode('.',$tag) as $key){
230  if(is_object(($value))) try{
231  $value = $this->escape([$value->$key])[0];
232  }
233  catch(\Exception $e){
234  $this->error("Property '$key' does not exists for tag '$tag'",__FILE__,__LINE__,compact('value'));
235  $found = false;
236  break;
237  }
238  elseif(!array_key_exists($key,$value)){
239  $found = false;
240  break;
241  }
242  else $value = $value[$key];
243  }
244  if($found) try{
245  return is_object($value) ? strval($value) : $value;
246  }
247  catch(\Exception $e){
248  $this->error("Could not convert object for tag '$tag' to string",__FILE__,__LINE__,compact('value'));
249  }
250  foreach($tags as $key => $value) if((substr($key,0,1) == '@') && !strcasecmp($tag,trim($key,'@!'))){
251  $value = [$tag => call_user_func($value,$tag,$tags,$params)];
252  $tags += substr($key,1,1) == '!' ? $value : $this->escape($value);
253  return $tags[$tag];
254  }
255  return $tags[$tag] = null;
256  }
257 
258  protected function evaluate($expr,$tag,&$tags){
259  $expr = strtr($expr,[$this->_prefix . true => '','?' => is_array($tag) ? implode(',',$tag) : $tag]);
260  foreach($tags as $key => $value) if(preg_match($mask = '/\\b' . preg_quote($tag = trim($key,'@!'),'/') . '\\b/',$expr)){
261  if(is_array($value = $this->value($tag,null,$tags))) $value = implode(',',$value);
262  elseif(preg_match('/^\\d{4}-\\d{2}-\\d{2}/',$value)) $value = "'$value'";
263  $expr = preg_replace($mask,$value,$expr);
264  }
265  return \Rsi\Number::evaluate($expr);
266  }
267 
268  protected function formatSubstr($value,$start,$length = null){
269  return $length === null ? substr($value,$start) : substr($value,$start,$length);
270  }
271 
272  protected function formatReplace($value,$search,$replace){
273  return str_replace($search,$replace,$value);
274  }
275 
276  protected function formatRegex($value,$pattern,$replace){
277  return preg_replace($pattern,$replace,$value);
278  }
279  /**
280  * Format a value.
281  * @param string $tag Tag name.
282  * @param mixed $value Tag value.
283  * @param string $params Formatting params.
284  * @param array $tags Other tags.
285  * @return string Formatted value.
286  */
287  protected function format($tag,$value,$params,&$tags){
288  foreach(explode('|',$params) as $format) if($format) try{
289  if(substr($format,0,1) == '=') $value = $this->evaluate(substr($format,1),$tag,$tags);
290  elseif(preg_match('/(\w+)\\((.*)\\)$/',$format,$match)){
291  $func_name = 'format' . ucfirst($match[1]);
292  $params = array_merge([$value],$match[2] ? array_map('urldecode',explode(',',$match[2])) : []);
293  if(method_exists($component = $this,$func_name) || method_exists($component = $this->component('local'),$func_name))
294  $value = call_user_func_array([$component,$func_name],$params);
295  else $value = call_user_func_array(
296  [$this->component('event'),'trigger'],
297  array_merge([self::EVENT_FORMAT . $match[1],$this],$params)
298  );
299  }
300  else{
301  $value = \Rsi\Str::transform($value,$format,$count);
302  if(!$count) $value = date($format,strtotime($value));
303  }
304  }
305  catch(\Exception $e){
306  $value = $this->error($e,compact('tag','value','params'));
307  break;
308  }
309  return is_array($value) ? false : $value;
310  }
311  /**
312  * Replace a tag with its value.
313  * @param string $str String to replace tag in.
314  * @param string $full Full match for the tag (including brackets).
315  * @param string $type Type of tag (see TYPE_* constants).
316  * @param string $tag Name of the tag.
317  * @param string $operator Operator for the tag (e.g. '==').
318  * @param string $params Extra parameters in the tag.
319  * @param mixed $value Value for the tag.
320  * @param array $tags All available tags (values).
321  * @param array $strs Loaded sub-strings.
322  * @return string Original input string with the full tag replaced with its value.
323  */
324  protected function replace($str,$full,$type,$tag,$operator,$params,$value,&$tags,&$strs){
325  $default = $replace = $raw = false;
326  if($type) switch($type){
327  case self::TYPE_TAG:
328  $tags[$tag] = substr($params,1);
329  $raw = true;
330  break;
331  case self::TYPE_OPTIONAL:
332  $default = null; //fall through
333  case self::TYPE_SUBSTR:
334  if(!in_array($tag,$strs)) $strs[] = $tag;
335  $replace = \Rsi\Str::transform($this->preProcess($this->getStr($tag,$default),$tags),$params = explode('|',$params));
336  $raw = !in_array(self::MACRO_ESCAPE,$params);
337  break;
338  case self::TYPE_TRUE:
339  if(substr($params,0,2) == '|=') $value = $this->evaluate(substr($params,2),$tag,$tags);
340  if($value) $replace = $this->_prefix . true;
341  $raw = true;
342  break;
343  case self::TYPE_FALSE:
344  if(substr($params,0,2) == '|=') $value = $this->evaluate(substr($params,2),$tag,$tags);
345  if(!$value) $replace = $this->_prefix . true;
346  $raw = true;
347  break;
348  case self::TYPE_COUNT:
349  $replace = count($value);
350  $raw = true;
351  break;
352  case self::TYPE_SUM:
353  if(is_array($value)){
354  $params = explode('|',substr($params,1),2);
355  $replace = $this->format($tag,array_sum(\Rsi\Record::column($value,$params[0])),$params[1] ?? null,$tags) . $this->_prefix . true;
356  }
357  break;
358  case self::TYPE_ARRAY:
359  if($value && (is_array($value) || (is_numeric($value) && ($value > 0) && ($value = range(1,$value))))){
360  $replace = $this->_prefix . true;
361  $sub = strtr(substr($params,1),$this->_unescape);
362  $i = 0; //index
363  $r = count($value); //reverse
364  foreach($value as $key => $record) $replace .=
365  $this->trans($sub,(is_array($record) ? $record : []) + ['v' => $record,'k' => $key,'i' => $i++,'r' => --$r] + $tags);
366  }
367  break;
368  case self::TYPE_DECODE:
369  $options = explode('|',substr($params,1));
370  $random = $value == '?' ? rand(0,count($options) - 1) : false;
371  foreach($options as $index => $option){
372  $i = strpos($option,':');
373  if($i === false) $replace = $option; //default
374  elseif($random === false ? substr($option,0,$i) == $value : $index == $random){
375  $replace = substr($option,$i + 1);
376  break;
377  }
378  if(!\Rsi::nothing($replace)) $replace .= $this->_prefix . true;
379  }
380  $replace = $this->trans(strtr($replace,$this->_unescape),$tags);
381  break;
382  case self::TYPE_JSON:
383  $replace = json_encode($value);
384  break;
385  case self::TYPE_RAW:
386  $replace = $this->format($tag,$value,$params,$tags);
387  break;
388  }
389  elseif($operator){
390  if(\Rsi\Str::operator(strtr(is_array($value) ? count($value) : $value,array_flip($this->_unescape)),$operator,$params)) $replace = $this->_prefix . true;
391  $raw = true;
392  }
393  elseif(!\Rsi::nothing($value)) //standard tag
394  $replace = $this->format($tag,$value,$params,$tags) . $this->_prefix . true;
395  return str_replace($full,$raw ? $replace : strtr($replace,array_flip($this->_unescape)),$str);
396  }
397  /**
398  * Elaborate conditional parts.
399  * @param string $str String with conditional parts.
400  * @return string String with elaborated conditional parts.
401  */
402  protected function brush($str){
403  while($str && preg_match_all('/{([^{}]*?)}/',$str,$matches,PREG_SET_ORDER)) foreach($matches as list($full,$inner))
404  $str = str_replace($full,strpos($full,$this->_prefix . true) ? str_replace($this->_prefix . true,'',$inner) : '',$str);
405  return $str;
406  }
407  /**
408  * Translate a string.
409  * @param string $str Basic string with tags.
410  * @param array $tags Tags to use when translating the string. Values are automaticle escaped, except when the key starts
411  * with a '!'. For keys starting with a '@' the value is used as a callback function (only called when the tag is present
412  * in the string; use '@!' prefix for callback values that should not be escaped).
413  * @return string Translated string.
414  */
415  protected function trans($str,$tags = null){
416  if(!$str) return $str;
417  $tags = array_merge($this->_tags,$tags ?: []);
418  $count = $strs = [];
419  if(($str = $this->preProcess($str,$tags)) && $tags) foreach($tags as $key => $value)
420  if(is_scalar($value)) $str = str_replace("[$key]",\Rsi::nothing($value) ? false : strtr($value,array_flip($this->_unescape)) . $this->_prefix . true,$str);
421  while($str && preg_match_all($this->regex,$str,$matches,PREG_SET_ORDER)){
422  foreach($strs as $id){
423  if(!array_key_exists($id,$count)) $count[$id] = 0;
424  elseif(++$count[$id] >= $this->maxNested){
425  $this->error("Sub-string '$id' nested more than {$this->maxNested} times",__FILE__,__LINE__,compact('str','tags'));
426  break 2;
427  }
428  }
429  $strs = $done = [];
430  foreach($matches as $match){
431  list($full,$type,$tag,$operator,$params) = $match;
432  if(!in_array($full,$done)){
433  if(substr($type,0,1) == '{') $type = $this->types[substr($type,1,-1)] ?? null;
434  $value = in_array($type,[self::TYPE_TAG,self::TYPE_OPTIONAL,self::TYPE_SUBSTR]) ? null : $this->value($tag,$params,$tags);
435  $str = $this->replace($str,$full,$type,$tag,$operator,$params,$value,$tags,$strs);
436  $done[] = $full;
437  }
438  }
439  }
440  return $this->postProcess(str_replace($this->_prefix . true,'',strtr($this->brush($str),$this->_unescape)),$tags);
441  }
442  /**
443  * Translate a string.
444  * @param string $str Basic string with tags.
445  * @param array $tags Tags to use when translating the string.
446  * @return string Translated string.
447  */
448  public function str($str,$tags = null){
449  return $this->trans($str,$this->escape($tags));
450  }
451  /**
452  * Translate a string by ID.
453  * @param string $id String ID.
454  * @param array $tags Tags to use when translating the string.
455  * @param string $default Default string when ID is not found.
456  * @return string Translated string.
457  */
458  public function id($id,$tags = null,$default = false){
459  return $this->str($this->getStr($id,$default),$tags);
460  }
461 
462  public function fragment($id){
463  $fragments = $this->session->fragments ?: [];
464  $fragment = $fragments[$id] ?? false;
465  unset($fragments[$id]);
466  $this->session->fragments = $fragments;
467  return $fragment;
468  }
469 
470  protected function getRegex(){
471  if(!$this->_regex){
472  $this->_regex = '/\\[(';
473  foreach($this->types as $type) $this->_regex .= preg_quote($type,'/') . '|';
474  $this->_regex .=
475  '\\{\\w+\\})?' . //type
476  '(\\w[\\w\\-\\/\\.]*\\w|\\w+)' . //tag
477  '(==|!=|>=?|<=?|%|=%|-?\\*-?|\\/\\/)?' . //operator
478  '([^\\[\\]]*)' . //params
479  '\\]/';
480  }
481  return $this->_regex;
482  }
483 
484  protected function setTags($value){
485  $this->_tags = $value === false ? [] : array_merge($this->_tags,$value);
486  }
487 
488  protected function getTypes(){
489  if(!$this->_types){
490  $this->_types = [];
491  foreach($this->constants('TYPE_') as $name => $value) $this->_types[strtolower($name)] = $value;
492  }
493  return $this->_types;
494  }
495 
496  protected function _get($key){
497  return $this->id($key);
498  }
499 
500  public function __call($func_name,$params){
501  return $this->id($func_name,array_shift($params),array_shift($params));
502  }
503 
504  public function __invoke($str,$tags = null){
505  return $this->str($str,$tags);
506  }
507 
508 }
const TYPE_FALSE
Show section when tag value is false: {[!tag]show when tag is empty}.
Definition: Trans.php:14
const TYPE_SUBSTR
Points to a sub-string: [@strId].
Definition: Trans.php:12
format($tag, $value, $params, &$tags)
Format a value.
Definition: Trans.php:287
const TYPE_JSON
Insert a JSON encoded value.
Definition: Trans.php:20
const MACRO_SPACE
Remove white-space between tags.
Definition: Trans.php:24
replace($str, $full, $type, $tag, $operator,$params, $value, &$tags, &$strs)
Replace a tag with its value.
Definition: Trans.php:324
fragment($id)
Definition: Trans.php:462
$_tags
Default tags to use with every translation.
Definition: Trans.php:59
const MACRO_FRAGMENT
Replace the tag with a placeholder and replace it with the fragment later on (with.
Definition: Trans.php:33
preProcess($str, &$tags)
Definition: Trans.php:120
const INFO
Informational message.
Definition: Log.php:14
const TYPE_TRUE
Show section when tag value is true: {[tag]show when tag is not empty}.
Definition: Trans.php:13
$_filename
Filename for the translations (asterisk will be replace by the langId).
Definition: Trans.php:56
__call($func_name, $params)
Definition: Trans.php:500
formatRegex($value, $pattern, $replace)
Definition: Trans.php:276
formatReplace($value, $search, $replace)
Definition: Trans.php:272
const MACRO_RIGHT
Definition: Trans.php:41
const TYPE_SUM
Sum of an array column: [=array|column|formatting].
Definition: Trans.php:16
__invoke($str, $tags=null)
Definition: Trans.php:504
postProcess($str, &$tags)
Definition: Trans.php:162
const MACRO_LOCATION
Rewrite the location between the tags (pre processing).
Definition: Trans.php:36
const EVENT_FORMAT
Definition: Trans.php:44
trans($str, $tags=null)
Translate a string.
Definition: Trans.php:415
formatSubstr($value, $start, $length=null)
Definition: Trans.php:268
error($message, $file=null, $line_no=null, $context=null)
Definition: Trans.php:82
_get($key)
Definition: Trans.php:496
const TYPE_OPTIONAL
Optional sub-string (defaults to empty; no error): [?strId].
Definition: Trans.php:11
langs()
Available languages.
Definition: Trans.php:78
const TYPE_DECODE
Decode a value: [:intTag|1:foo|2:bar|default]. Set the value to &#39;?&#39; for a random selection.
Definition: Trans.php:19
$logPrio
Prio for translation related errors (invalid tags, format, etc).
Definition: Trans.php:48
constants($prefix=null)
Return all constants.
Definition: Thing.php:56
const MACRO_CONST
Replace the text with the value of the constant between the tags (pre processing).
Definition: Trans.php:30
const MACRO_IMAGE
Generate an image tag for the image between the tags (the content is cached, set the &#39;ttl&#39;...
Definition: Trans.php:37
const TYPE_ARRAY
Repeat section for each item (item aded to tags, including k = key, v = value - when record is...
Definition: Trans.php:17
const MACRO_ROUTE
Create a (reverse) route for the controller name between the tags (attributes are params)...
Definition: Trans.php:35
id($id, $tags=null, $default=false)
Translate a string by ID.
Definition: Trans.php:458
$maxNested
Maximum number of times a sub-string may be nested.
Definition: Trans.php:47
str($str, $tags=null)
Translate a string.
Definition: Trans.php:448
setTags($value)
Definition: Trans.php:484
const MACRO_REPLACE
Replace the text in attribute &#39;from&#39; (regex) to &#39;to&#39;.
Definition: Trans.php:25
publish($property, $visibility=self::READABLE)
Publish a property (or hide it again).
Definition: Thing.php:27
value($tag, $params, &$tags)
Definition: Trans.php:225
evaluate($expr, $tag, &$tags)
Definition: Trans.php:258
escape($tags)
Escape tag values (convert special characters to HTML entities).
Definition: Trans.php:212
Basic component class.
Definition: Component.php:8
const MACRO_URL
Load external content from the address between the tags (the content is cached, set the &#39;ttl&#39;...
Definition: Trans.php:39
$imageTtl
Default cache TTL for image tag generation.
Definition: Trans.php:49
brush($str)
Elaborate conditional parts.
Definition: Trans.php:402
getStrs($lang_id)
Get all strings.
Definition: Trans.php:91
Translations component.
Definition: Trans.php:8
const TYPE_COUNT
Insert number of items in array: Array has [#arrayTag] items.
Definition: Trans.php:15
macro($str, $type, &$tags, $callback)
Definition: Trans.php:107
$urlTtl
Default cache TTL for external content.
Definition: Trans.php:51
const MACRO_ESCAPE
Escape the text between these tags (pre processing).
Definition: Trans.php:23
getStr($id, $default=false)
Basic string getter.
Definition: Trans.php:100
const TYPE_TAG
Add a tag to to the tags: [+tag|value].
Definition: Trans.php:10
const MACRO_UNITS
Split the value of the tag name into units, so it can be used as an array (units in desired...
Definition: Trans.php:26
const TYPE_RAW
Insert value without inserting a conditional tag: [[~intTag],number].
Definition: Trans.php:21
component($name)
Get a component (local or default).
Definition: Component.php:80
const MACRO_CACHE
Cache the (processed) text (set the &#39;ttl&#39; tag to use the main cache; use the &#39;key&#39;.
Definition: Trans.php:31