Fix #7175 - refine translation code
[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             if (strtotime($tmpl->updated) >= filemtime($flexy->resolvePath ($pgdata['template']))) {
245                 if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != 'html') {
246                     $oo = clone($tmpl);
247                     $tmpl->is_deleted = 0;
248                     $tmpl->filetype = 'html';
249                     $tmpl->update($oo);
250                 }
251                 if (empty($pgdata['force'])) {
252                     return $tmpl;
253                 }
254             }
255         }
256         
257         //die("got here");
258         
259         try {
260             $r = $flexy->compile($pgdata['template']);
261            
262             
263         } catch(Exception $e) {
264             $old = clone($tmpl);
265             $tmpl->updated   = date('Y-m-d H:i:s',filemtime($flexy->resolvePath ($pgdata['template'])));
266             if ($tmpl->id) {
267                 $tmpl->is_deleted = 0;
268                 $tmpl->filetype = 'html';
269                 $tmpl->update($tmpl);
270             } else {
271                 $tmpl->is_deleted = 0;
272                 $tmpl->filetype = 'html';
273                 $tmpl->lang = 'en';
274                 $tmpl->insert();
275             }
276             
277             
278             return false;
279         }
280        
281       
282         if (is_a($r,'PEAR_Error')) {
283             
284            // echo $r->toString(). "\n";
285             return $r;
286         }
287           
288         $tmpl = DB_DataObject::Factory($this->tableName());
289         $tmpl->words = file_exists($flexy->getTextStringsFile) ?
290                 unserialize(file_get_contents($flexy->getTextStringsFile)) :
291                 array();
292         
293         $tmpl->contentStrings   = $flexy->compiler->contentStrings;
294         //var_dump(file_exists($flexy->getTextStringsFile));
295         //print_r($tmpl->words);
296         $tmpl->currentTemplate  = $flexy->currentTemplate;
297         
298         $tmpl->view_name = $pgdata['base'];
299         
300         
301         if (!$tmpl->get('template',  $pgdata['template'])) {
302             $tmpl->is_deleted = 0;
303             $tmpl->filetype = 'html';
304             $tmpl->template = $pgdata['template'];
305             $tmpl->lang = 'en'; /// ??? hard coded??
306             $tmpl->updated = date('Y-m-d H:i:s', filemtime($flexy->currentTemplate));
307             $tmpl->insert();
308         } else {
309             $xx =clone($tmpl);
310             // has it been cahnged...
311             //if (!$force && filemtime($flexy->currentTemplate) == strtotime($tmpl->updated)) {
312                 // nothing changed..
313             //    return $tmpl;
314             //}
315             if (empty($tmpl->lang))  {
316                 //echo "FIX LANG?";exit;
317                 $tmpl->lang = 'en'; /// ??? hard coded??
318             }
319             $tmpl->filetype = 'html';
320             $tmpl->is_deleted = 0;
321             $tmpl->updated = date('Y-m-d H:i:s', filemtime($flexy->currentTemplate));
322             $tmpl->update($xx);
323         }
324       
325         
326         $x = DB_DataObject::Factory('core_templatestr');
327         $x->syncTemplateWords($tmpl);
328         
329         // if file_exists ( template/path/name.php << eg. a matching view..)
330         // then create a system page for this. 
331         
332         
333         
334         $x = DB_DataObject::Factory('core_template_element');
335         $tmpl->elements = $x->syncTemplateElement($tmpl,
336                 file_get_contents($flexy->currentTemplate),
337                 $flexy->compiler->contentStrings,
338                 false);
339         
340         
341         
342         return clone($tmpl);
343     
344     }
345     function syncPhpGetText($pgdata)
346     {
347         $tmpl = DB_DataObject::Factory($this->tableName());
348         $tmpl->view_name = $pgdata['base'];
349         $tmpl->currentTemplate = $pgdata['template_dir'] . '/'. $pgdata['template'];
350         
351         if ($tmpl->get('template',  $pgdata['template'])) {
352             if (strtotime($tmpl->updated) >= filemtime( $tmpl->currentTemplate )) {
353                 if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != 'html') {
354                     $oo = clone($tmpl);
355                     $tmpl->is_deleted = 0;
356                     $tmpl->filetype = 'php';
357                     $tmpl->update($oo);
358                 }
359                 return $tmpl;
360             }
361         }
362         $words = array();
363         
364         $ar = token_get_all(file_get_contents( $tmpl->currentTemplate  ));
365         foreach( $ar as $i=> $tok) {
366             if (!is_array($tok) || $tok[0] != T_CONSTANT_ENCAPSED_STRING) {
367                 continue;
368             }
369             if ($i < 2) {
370                 continue;
371             }
372             if (is_array($ar[$i-1]) || $ar[$i-1] != '(') {
373                 continue;
374             }
375             if (!is_array($ar[$i-2]) || $ar[$i-2][1] != '_') {
376                 continue;
377             }
378             $ct = $tok[1][0];
379             $words[] =  str_replace('\\'. $ct, $ct, trim($tok[1] , $ct));
380             
381         }
382         // create the template...
383         
384         
385          if (!$tmpl->id) {
386             
387             $tmpl->template = $pgdata['template'];
388             $tmpl->lang = 'en'; /// ??? hard coded??
389             $tmpl->filetype = 'php';
390             $tmpl->is_deleted = 0;
391             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
392             $tmpl->insert();
393         } else {
394             $xx =clone($tmpl);
395             $tmpl->filetype = 'php';
396             $tmpl->is_deleted = 0;
397             $tmpl->lang = 'en'; /// ??? hard coded??
398             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
399             $tmpl->update($xx);
400         }
401       
402         $words = array_unique($words);
403         
404         if (!count($words)) {
405             return;
406         }
407         
408              
409         $tmpl->words = $words;
410             
411         $x = DB_DataObject::Factory('core_templatestr');
412         $x->syncTemplateWords($tmpl);    
413          
414         
415         return $tmpl;
416         
417         
418         
419     }
420     /*
421     SELECT LOWER(
422 CONCAT(
423 REPLACE(view_name, '.','_'),
424 '_',
425 REPLACE(template,'/','_')
426 )
427 )
428 FROM core_template
429
430 WHERE (
431  = 'release_pressrelease_distributionreportnew_journalistdistribution.php'
432 )
433 */
434
435     
436     function genGetText($clsname, $lang=false)
437     {
438         static $done = false;
439         $clsname = strtolower($clsname);
440
441         textdomain($clsname);
442      
443
444         $ff = HTML_FlexyFramework::get();
445         $lang = $lang ? $lang : (isset($ff->locale) ? $ff->locale : 'en');
446         
447
448         if (!empty($done[$clsname.':'.$lang])) {
449             return true; // already sent headers and everything.
450         }
451         
452         putenv("LANGUAGE=$lang");
453         if ($lang != 'en') {
454             if (!setlocale(LC_ALL, $lang.'.UTF-8')) {
455                 $ff->page->jerr("Language is not available {$lang}");
456             }
457         }
458         
459         
460         $d = DB_DataObject::factory($this->tableName());
461         $d->whereAdd("
462             LOWER(
463                 CONCAT(
464                       REPLACE(view_name, '.','_'),
465                     '_',
466                     REPLACE(template,'/','_')
467                 )
468             ) = '{$clsname}.php'
469        ");
470         $d->filetype = 'php';
471         if (! $d->find(true) ){
472             $done[$clsname.':'.$lang] = true;
473             return false;
474         }
475         $user = 'www-data'; // ?? do we need other ones
476         $compileDir = ini_get('session.save_path') .'/' . 
477             $user . '_gettext_' . $ff->project;
478         
479         if ($ff->appNameShort) {
480             $compileDir .= '_' . $ff->appNameShort;
481         }
482         if ($ff->version) {
483             $compileDir .= '.' . $ff->version;
484         }
485         $lang = $lang ? $lang : $ff->locale;
486         $fdir = "{$compileDir}/{$lang}/LC_MESSAGES";
487         $fname = "{$fdir}/{$clsname}.mo";
488         
489          
490         //exit;
491         bindtextdomain($clsname, $compileDir) ;
492         bind_textdomain_codeset($clsname, 'UTF-8');
493
494         textdomain($clsname);
495
496         
497         //textdomain($clsname);
498         
499         $done[$clsname.':'.$lang] = 1;
500         
501         // do we need to compile the file..
502         $ts = DB_DataObject::Factory('core_templatestr');
503         $ts->selectAdd('MAX(updated) as updated');
504         $ts->lang = $lang;
505         $ts->template_id = $d->id;
506         if (!$ts->find(true)) {
507             // then in theory there are no translations
508             return false;
509         }
510         if (file_exists($fname) && strtotime($ts->updated) < filemtime($fname)) {
511             return $fname; // file exists and is newer than our updated line.
512         }
513         //DB_DataObject::debugLevel(1);
514
515         $ts = DB_DataObject::Factory('core_templatestr');
516         $ts->autoJoin();
517         $ts->selectAdd('join_src_id_id.txt as src_id_txt, core_templatestr.txt as txt');
518         $ts->lang = $lang;
519         $ts->template_id = $d->id;
520         $ts->whereAdd("LENGTH(join_src_id_id.txt) > 0 AND LENGTH(core_templatestr.txt) > 0");
521         $words = $ts->fetchAll('src_id_txt', 'txt' );
522                
523         if (!file_exists($fdir)) {
524             //var_dump($fdir);
525             mkdir($fdir, 0700, true);
526         }
527         
528         require_once 'File/Gettext.php';
529         $gt = File_Gettext::factory('PO', preg_replace('/\.mo$/', '.po', $fname));
530         $gt->fromArray(
531             
532             array(
533                 'meta' => array(
534                     "Language" =>  $lang,
535                     'Content-Type'      => 'text/plain; charset=UTF-8',
536                     'Content-Transfer-Encoding'      => ' 8bit',
537                      'PO-Revision-Date'  => date('Y-m-d H:iO'),
538                  ),
539                 'strings' => $words
540             )
541             
542         );
543         $gt->save();
544         
545         // mo DOESNT WORK!!
546         require_once 'System.php';
547         $poname = preg_replace('/\.mo$/', '.po', $fname);
548         $msgfmt = System::which('msgfmt');
549         $cmd = "{$msgfmt} {$poname}  -o {$fname}";
550         //echo $cmd;
551         
552         `$cmd`;
553         
554         
555          
556         
557         return $fname;
558         
559         require_once 'File/Gettext.php';
560         $gt = File_Gettext::factory('MO', $fname);
561         $gt->fromArray(
562             
563             array(
564                 'meta' => array(
565                      "Language" =>  $lang,
566                     'Content-Type'      => 'text/plain; charset=UTF-8',
567                     'Content-Transfer-Encoding'      => ' 8bit',
568                      'PO-Revision-Date'  => date('Y-m-d H:iO'),
569                 ),
570                 'strings' => $words
571             )
572             
573         );
574         $gt->save(); 
575         
576     }
577 }