Fix #7553 - translations
[Pman.Core] / DataObjects / Core_template.php
1 <?php
2 /**
3  * Table Definition for core_template 
4  *
5  *
6  * The idea here is that it contains all the strings in the templates with a language '' (empty)
7  * , it then generates a matching set of strings
8  * 
9  */
10 class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
11
12 class Pman_Core_DataObjects_Core_template  extends DB_DataObject 
13 {
14     ###START_AUTOCODE
15     /* the code below is auto generated do not remove the above tag */
16
17     public $__table = 'core_template';         // table name
18     public $id;                              // int(11)  not_null primary_key auto_increment
19     public $template;                           // string(64)  not_null
20
21     public $updated;                        // blob(65535)  blob
22     public $lang;    // text  NOT NULL;
23     public $view_name; // eg mobile or desktop
24     /* the code above is auto generated do not remove the tag below */
25     ###END_AUTOCODE
26     
27     
28     function applyFilters($q, $au, $roo)
29     {
30         //DB_DataObject::debugLEvel(1);
31 //        $x = DB_Dataobject::Factory($this->tableName());
32         
33         
34         // template scanning and syncing should be done by the UpdateDatabase Code.
35         //if (!$x->count() || !empty($q['_rescan'])) {
36             //DB_DataObject::debugLEvel(1);
37             //$tp = DB_DataObject::factory('core_template');
38             //$opts = HTML_FlexyFramework::get()->Pman_Core;
39             //$tp->syncTemplateDir(false, '', !empty($q['_rescan']));
40             //if (isset($q['lang'])) {
41             //    $this->syncLang($q['lang']);
42             //}
43         //} 
44 //        $this->whereAdd("
45 //                join_
46 //            ");
47         
48     }
49         
50     function toRooArray($req)
51     {
52         $ret = $this->toArray();
53         if (!empty($req['_clean_name']) ) {
54             $ret['template_clean'] = preg_replace('#\.html$#i', '', $this->template);
55             
56         }
57         return $ret;
58         
59     }
60     
61     function beforeUpdate($old, $q, $roo)
62     {
63         if (!empty($q['_rescan'])){
64             if ($this->filetype != 'html') {
65                 $roo->jerr("can not update a php source file currently - TDOD");
66             }
67             $pg = HTML_FlexyFramework::get()->page;
68             
69             $this->syncTemplatePage(array(
70                 'template_dir' => $pg->rootDir . '/'. str_replace('.', '/', $this->view_name). '/templates',
71                 'template' => $this->template,
72                 'base' => $this->view_name,
73                 'force' => true
74             ));
75             // update the different langage versions of this page.
76             $x = DB_Dataobject::Factory('core_templatestr');
77             $x->selectAdd();
78             $x->selectAdd('distinct(lang) as lang');
79             $x->whereAdd("lang != ''");
80             $langs  = $x->fetchAll('lang');
81             foreach($langs as $l) {
82                 $x = DB_Dataobject::Factory('core_templatestr');
83                 $x->syncLang($l, $this->id);
84             }
85            
86             
87             $roo->jok("updated -" .  $this->template);
88         }
89     }
90    
91     
92     
93     
94     /*
95      * @param base (should be full path to template directory)
96      * @param subdir = empty for top or subpath.
97      */
98     function syncTemplateDir($base = false,  $subdir = '', $force = false)
99     {
100         echo "syncTemplateDir: $base , $subdir, $force \n";
101         //print_r(func_get_args());
102         if (!$base) {
103             $ff = HTML_FlexyFramework::get();
104             if (!isset($ff->Pman_Core)) {
105                 echo "[ERROR] Not scanning template directory - no set in Pman_Core[templateDir]\n";
106                 return;
107             }
108             $opts = $ff->Pman_Core;
109             if (is_array($opts['templateDir'])) {
110                 foreach($opts['templateDir'] as $type=>$dir) {
111                     $this->syncTemplateDir($dir, '', $force);
112                 }
113                 return;
114             }
115             
116             $base = $opts['templateDir'];
117             
118             
119         }
120         if($force){
121             $tmpls = DB_DataObject::factory('core_template');
122             $this->tmpls = $tmpls->fetchAll('template','id'); // dupes??
123         }
124         
125         $tmp_dir = $base . (empty($subdir) ? '' : '/') . $subdir;
126         
127         if(!is_dir($tmp_dir)){
128             return;
129         }
130         
131         $dh = opendir($tmp_dir);
132         if(!$dh){
133             return; // something went wrong!?
134         }
135         
136         while (($fn = readdir($dh)) !== false) {
137             // do we care that it will try and parse the template directory??? - not really..
138             // as we are only looking for php files..
139             if(empty($fn) || $fn[0] == '.'){
140                 continue;
141             }
142
143             $fullpath = $tmp_dir."/".$fn;
144 //            echo "filename: ".$fullpath." \n";    
145              
146             $relpath = $subdir . (empty($subdir) ? '' : '/') . $fn;
147             
148             if(is_dir($fullpath)){
149                 // then recursively call self...
150 //                var_Dump($base);
151 //                var_Dump($subdir . (empty($subdir) ? '' : '/') . $fn);
152                 $this->syncTemplateDir($base, $subdir . (empty($subdir) ? '' : '/') . $fn );
153                 
154                 continue;
155             }
156             if (!preg_match('/(\.html|\.txt|\.abw)$/', $fn)) {
157                 continue;
158             }
159             
160              
161 //            var_dump($tmp);
162 //            var_dump($tmp_path);
163 //            $fn = basename($fn);
164             if (isset($this->tmpls[$relpath])) {
165                 unset($this->tmpls[$relpath]);
166             }
167             
168             
169             
170                
171             $template = $this->syncTemplate($relpath, true, false);
172 //            var_dump($template);
173             if (is_a($template, 'PEAR_Error')) {
174                 continue;
175             }
176         }
177         closedir($dh);
178 //        
179  
180         if($force){
181             foreach($this->tmpls as $id) {
182                 $x = DB_DataObject::factory($this->tableName());
183                 if ($x->get($id)) {
184                     $x->delete();
185                 }
186             }
187         }
188     }
189     
190     /* compile a html template
191      *  
192      *  @param template_dir  << the path to the template dir ... Pman/XXX/template ...
193      *  @param template   << name of template used by name field)
194      *  @param base  << view name (module ? + templates?)
195      *  @param force << optional - forces even if database is newer.
196      *  
197      *  
198      */
199     function syncTemplatePage($pgdata)
200     {
201         //print_r($pgdata);
202         
203         $force = true;
204          //echo "compiling:"; print_r($pgdata);
205         // read the template and extract the translatable strings.
206         ini_set('memory_limit', '512M');
207         
208         //var_dump($n);
209         $n = $pgdata['template'];  // remove trailing slash..
210         
211         $fopts = HTML_FlexyFramework::get()->HTML_Template_Flexy;
212         $opts = HTML_FlexyFramework::get()->Pman_Core;
213         //print_R($opts);
214         //$dir = $opts['templateDir'] . '/' . $node;
215         $oo = array(
216             'fatalError'    => PEAR_ERROR_EXCEPTION,  
217             'disableTranslate' => false,
218             'templateDir' => $pgdata['template_dir'],
219             'compileDir' => $fopts['compileDir'] . '_translation_files',
220             'forceCompile' => true, //?? only for force above???
221         );
222          
223         // non-html templates - treat as such..
224         // abiword - treat as html?
225         if (!preg_match('/\.(html|abw)$/i', $pgdata['template'])) {
226             $oo['nonHTML'] = true;
227         }
228         
229         //print_r(array($oo, $n));
230         
231         
232         $flexy = new HTML_Template_Flexy( $oo );
233           
234         if (!$flexy->resolvePath ($pgdata['template'])) {
235             //echo "SKIP - could not resolve path?\n"; print_r($oo);
236             return false;
237         }
238         
239         // attempt to find the template... record.
240         $tmpl = DB_DataObject::Factory($this->tableName());
241        
242         $tmpl->view_name = $pgdata['base'];
243         if ($tmpl->get('template',  $pgdata['template'])) {
244             clearstatcache();
245             if (strtotime($tmpl->updated) >= filemtime($flexy->resolvePath ($pgdata['template']) . '/'. $pgdata['template'])) {
246                 if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != 'html') {
247                     $oo = clone($tmpl);
248                     $tmpl->is_deleted = 0;
249                     $tmpl->filetype = 'html';
250                     $tmpl->update($oo);
251                 }
252                 if (empty($pgdata['force'])) {
253                   //  echo "SKIP NO UPDATE: " . $pgdata['template'] ."\n";
254                    // echo $flexy->resolvePath ($pgdata['template']).  ':'. $tmpl->updated  . ">=" .  date('Y-m-d H:i:s',filemtime($flexy->resolvePath ($pgdata['template']))) . "\n";
255                     return $tmpl;
256                 }
257             }
258         }
259         
260         //die("got here");
261         
262         try {
263             $r = $flexy->compile($pgdata['template']);
264            
265             
266         } catch(Exception $e) {
267             $old = clone($tmpl);
268             $tmpl->updated   = date('Y-m-d H:i:s',filemtime($flexy->resolvePath ($pgdata['template']) . '/'. $pgdata['template']));
269             if ($tmpl->id) {
270                 $tmpl->is_deleted = 0;
271                 $tmpl->filetype = 'html';
272                 $tmpl->update($tmpl);
273             } else {
274                 $tmpl->is_deleted = 0;
275                 $tmpl->filetype = 'html';
276                 $tmpl->lang = 'en';
277                 $tmpl->insert();
278             }
279             //echo "SKIP: " . $pgdata['template'] ."\n";
280            //   echo "SKIP - exception\n"; print_r($e);
281             return false;
282         }
283        
284       
285         if (is_a($r,'PEAR_Error')) {
286             //echo "SKIP: " . $pgdata['template'] ."\n";
287             //echo $r->toString(). "\n";
288             return $r;
289         }
290           
291         $tmpl = DB_DataObject::Factory($this->tableName());
292         $tmpl->words = file_exists($flexy->getTextStringsFile) ?
293                 unserialize(file_get_contents($flexy->getTextStringsFile)) :
294                 array();
295         
296         $tmpl->contentStrings   = $flexy->compiler->contentStrings;
297         //var_dump(file_exists($flexy->getTextStringsFile));
298         //print_r($tmpl->words);
299         $tmpl->currentTemplate  = $flexy->currentTemplate;
300         
301         $tmpl->view_name = $pgdata['base'];
302         
303         //echo $pgdata['template'] ."\n";
304         if (!$tmpl->get('template',  $pgdata['template'])) {
305             $tmpl->is_deleted = 0;
306             $tmpl->filetype = 'html';
307             $tmpl->template = $pgdata['template'];
308             $tmpl->lang = 'en'; /// ??? hard coded??
309             $tmpl->updated = date('Y-m-d H:i:s', filemtime($flexy->currentTemplate));
310             $tmpl->insert();
311         } else {
312             $xx =clone($tmpl);
313             // has it been cahnged...
314             //if (!$force && filemtime($flexy->currentTemplate) == strtotime($tmpl->updated)) {
315                 // nothing changed..
316             //    return $tmpl;
317             //}
318             if (empty($tmpl->lang))  {
319                 //echo "FIX LANG?";exit;
320                 $tmpl->lang = 'en'; /// ??? hard coded??
321             }
322             $tmpl->filetype = 'html';
323             $tmpl->is_deleted = 0;
324             $tmpl->updated = date('Y-m-d H:i:s', filemtime($flexy->currentTemplate));
325             $tmpl->update($xx);
326         }
327       
328         
329         $x = DB_DataObject::Factory('core_templatestr');
330         $x->syncTemplateWords($tmpl);
331         
332         // if file_exists ( template/path/name.php << eg. a matching view..)
333         // then create a system page for this. 
334         
335         
336         
337         $x = DB_DataObject::Factory('core_template_element');
338         $tmpl->elements = $x->syncTemplateElement($tmpl,
339                 file_get_contents($flexy->currentTemplate),
340                 $flexy->compiler->contentStrings,
341                 false);
342         
343         
344         
345         return clone($tmpl);
346     
347     }
348     function syncPhpGetText($pgdata)
349     {
350         $tmpl = DB_DataObject::Factory($this->tableName());
351         $tmpl->view_name = $pgdata['base'];
352         $tmpl->currentTemplate = $pgdata['template_dir'] . '/'. $pgdata['template'];
353         
354         if ($tmpl->get('template',  $pgdata['template'])) {
355             if (strtotime($tmpl->updated) >= filemtime( $tmpl->currentTemplate )) {
356                 if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != 'html') {
357                     $oo = clone($tmpl);
358                     $tmpl->is_deleted = 0;
359                     $tmpl->filetype = 'php';
360                     $tmpl->update($oo);
361                 }
362                 return $tmpl;
363             }
364         }
365         $words = array();
366         
367         $ar = token_get_all(file_get_contents( $tmpl->currentTemplate  ));
368         foreach( $ar as $i=> $tok) {
369             if (!is_array($tok) || $tok[0] != T_CONSTANT_ENCAPSED_STRING) {
370                 continue;
371             }
372             if ($i < 2) {
373                 continue;
374             }
375             if (is_array($ar[$i-1]) || $ar[$i-1] != '(') {
376                 continue;
377             }
378             if (!is_array($ar[$i-2]) || $ar[$i-2][1] != '_') {
379                 continue;
380             }
381             $ct = $tok[1][0];
382             $words[] =  str_replace('\\'. $ct, $ct, trim($tok[1] , $ct));
383             
384         }
385         // create the template...
386         
387         
388          if (!$tmpl->id) {
389             
390             $tmpl->template = $pgdata['template'];
391             $tmpl->lang = 'en'; /// ??? hard coded??
392             $tmpl->filetype = 'php';
393             $tmpl->is_deleted = 0;
394             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
395             $tmpl->insert();
396         } else {
397             $xx =clone($tmpl);
398             $tmpl->filetype = 'php';
399             $tmpl->is_deleted = 0;
400             $tmpl->lang = 'en'; /// ??? hard coded??
401             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
402             $tmpl->update($xx);
403         }
404       
405         $words = array_unique($words);
406         
407         if (!count($words)) {
408             return;
409         }
410         
411              
412         $tmpl->words = $words;
413             
414         $x = DB_DataObject::Factory('core_templatestr');
415         $x->syncTemplateWords($tmpl);    
416          
417         
418         return $tmpl;
419         
420         
421         
422     }
423     /*
424     SELECT LOWER(
425 CONCAT(
426 REPLACE(view_name, '.','_'),
427 '_',
428 REPLACE(template,'/','_')
429 )
430 )
431 FROM core_template
432
433 WHERE (
434  = 'release_pressrelease_distributionreportnew_journalistdistribution.php'
435 )
436 */
437
438     
439     function genGetText($clsname, $lang=false)
440     {
441         static $done = array();
442         $clsname = strtolower($clsname);
443
444         textdomain($clsname);
445      
446
447         $ff = HTML_FlexyFramework::get();
448         $lang = $lang ? $lang : (isset($ff->locale) ? $ff->locale : 'en');
449         
450
451         if (!empty($done[$clsname.':'.$lang])) {
452             return true; // already sent headers and everything.
453         }
454         
455         putenv("LANGUAGE=$lang");
456         if ($lang != 'en') {
457             if (!setlocale(LC_ALL, $lang.'.UTF-8')) {
458                 $ff->page->jerr("Language is not available {$lang}");
459             }
460         }
461         
462         
463         $d = DB_DataObject::factory($this->tableName());
464         $d->whereAdd("
465             LOWER(
466                 CONCAT(
467                       REPLACE(view_name, '.','_'),
468                     '_',
469                     REPLACE(template,'/','_')
470                 )
471             ) = '{$clsname}.php'
472        ");
473         $d->filetype = 'php';
474         if (! $d->find(true) ){
475             $done[$clsname.':'.$lang] = true;
476             return false;
477         }
478         $user = 'www-data'; // ?? do we need other ones
479         $compileDir = ini_get('session.save_path') .'/' . 
480             $user . '_gettext_' . $ff->project;
481         
482         if ($ff->appNameShort) {
483             $compileDir .= '_' . $ff->appNameShort;
484         }
485         if ($ff->version) {
486             $compileDir .= '.' . $ff->version;
487         }
488         $lang = $lang ? $lang : $ff->locale;
489         $fdir = "{$compileDir}/{$lang}/LC_MESSAGES";
490         $fname = "{$fdir}/{$clsname}.mo";
491         
492          
493         //exit;
494         bindtextdomain($clsname, $compileDir) ;
495         bind_textdomain_codeset($clsname, 'UTF-8');
496
497         textdomain($clsname);
498
499         
500         //textdomain($clsname);
501         
502         $done[$clsname.':'.$lang] = 1;
503         
504         // do we need to compile the file..
505         $ts = DB_DataObject::Factory('core_templatestr');
506         $ts->selectAdd('COALESCE(MAX(updated), "1000-01-01") as updated');
507         $ts->lang = $lang;
508         $ts->template_id = $d->id;
509         if (!$ts->find(true)) {
510             // then in theory there are no translations
511             return false;
512         }
513         if (file_exists($fname) && strtotime($ts->updated) < filemtime($fname)) {
514             return $fname; // file exists and is newer than our updated line.
515         }
516         //DB_DataObject::debugLevel(1);
517
518         $ts = DB_DataObject::Factory('core_templatestr');
519         $ts->autoJoin();
520         $ts->selectAdd('join_src_id_id.txt as src_id_txt, core_templatestr.txt as txt');
521         $ts->lang = $lang;
522         $ts->template_id = $d->id;
523         $ts->whereAdd("LENGTH(join_src_id_id.txt) > 0 AND LENGTH(core_templatestr.txt) > 0");
524         $words = $ts->fetchAll('src_id_txt', 'txt' );
525                
526         if (!file_exists($fdir)) {
527             //var_dump($fdir);
528             mkdir($fdir, 0700, true);
529         }
530         
531         require_once 'File/Gettext.php';
532         $gt = File_Gettext::factory('PO', preg_replace('/\.mo$/', '.po', $fname));
533         $gt->fromArray(
534             
535             array(
536                 'meta' => array(
537                     "Language" =>  $lang,
538                     'Content-Type'      => 'text/plain; charset=UTF-8',
539                     'Content-Transfer-Encoding'      => ' 8bit',
540                      'PO-Revision-Date'  => date('Y-m-d H:iO'),
541                  ),
542                 'strings' => $words
543             )
544             
545         );
546         $gt->save();
547         
548         // mo DOESNT WORK!!
549         require_once 'System.php';
550         $poname = preg_replace('/\.mo$/', '.po', $fname);
551         $msgfmt = System::which('msgfmt');
552         $cmd = "{$msgfmt} {$poname}  -o {$fname}";
553         //echo $cmd;
554         
555         `$cmd`;
556         
557         
558          
559         
560         return $fname;
561         
562         require_once 'File/Gettext.php';
563         $gt = File_Gettext::factory('MO', $fname);
564         $gt->fromArray(
565             
566             array(
567                 'meta' => array(
568                      "Language" =>  $lang,
569                     'Content-Type'      => 'text/plain; charset=UTF-8',
570                     'Content-Transfer-Encoding'      => ' 8bit',
571                      'PO-Revision-Date'  => date('Y-m-d H:iO'),
572                 ),
573                 'strings' => $words
574             )
575             
576         );
577         $gt->save(); 
578         
579     }
580 }