fix #8131 - chinese 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      * USED? - this is in updateBJSTemplate ?
96      * @param base (should be full path to template directory)
97      * @param subdir = empty for top or subpath.
98      */
99     /*
100     function syncTemplateDir($base = false,  $subdir = '', $force = false)
101     {
102         echo "syncTemplateDir: $base , $subdir, $force \n";
103         //print_r(func_get_args());
104         if (!$base) {
105             $ff = HTML_FlexyFramework::get();
106             if (!isset($ff->Pman_Core)) {
107                 echo "[ERROR] Not scanning template directory - no set in Pman_Core[templateDir]\n";
108                 return;
109             }
110             $opts = $ff->Pman_Core;
111             if (is_array($opts['templateDir'])) {
112                 foreach($opts['templateDir'] as $type=>$dir) {
113                     $this->syncTemplateDir($dir, '', $force);
114                 }
115                 return;
116             }
117             
118             $base = $opts['templateDir'];
119             
120             
121         }
122         if($force){
123             $tmpls = DB_DataObject::factory('core_template');
124             $this->tmpls = $tmpls->fetchAll('template','id'); // dupes??
125         }
126         
127         $tmp_dir = $base . (empty($subdir) ? '' : '/') . $subdir;
128         
129         if(!is_dir($tmp_dir)){
130             return;
131         }
132         
133         $dh = opendir($tmp_dir);
134         if(!$dh){
135             return; // something went wrong!?
136         }
137         
138         while (($fn = readdir($dh)) !== false) {
139             // do we care that it will try and parse the template directory??? - not really..
140             // as we are only looking for php files..
141             if(empty($fn) || $fn[0] == '.'){
142                 continue;
143             }
144
145             $fullpath = $tmp_dir."/".$fn;
146 //            echo "filename: ".$fullpath." \n";    
147              
148             $relpath = $subdir . (empty($subdir) ? '' : '/') . $fn;
149             
150             if(is_dir($fullpath)){
151                 // then recursively call self...
152 //                var_Dump($base);
153 //                var_Dump($subdir . (empty($subdir) ? '' : '/') . $fn);
154                 $this->syncTemplateDir($base, $subdir . (empty($subdir) ? '' : '/') . $fn );
155                 
156                 continue;
157             }
158             if (!preg_match('/(\.html|\.txt|\.abw)$/', $fn)) {
159                 continue;
160             }
161             
162              
163 //            var_dump($tmp);
164 //            var_dump($tmp_path);
165 //            $fn = basename($fn);
166             if (isset($this->tmpls[$relpath])) {
167                 unset($this->tmpls[$relpath]);
168             }
169             
170             
171             
172                
173             $template = $this->syncTemplate($relpath, true, false);
174 //            var_dump($template);
175             if (is_a($template, 'PEAR_Error')) {
176                 continue;
177             }
178         }
179         closedir($dh);
180 //        
181  
182         if($force){
183             foreach($this->tmpls as $id) {
184                 $x = DB_DataObject::factory($this->tableName());
185                 if ($x->get($id)) {
186                     $x->delete();
187                 }
188             }
189         }
190     }
191     */
192     /* compile a html template  - called by UpdateBjsTemplates - scan Pman Templates
193      *  
194      *  @param template_dir  << the path to the template dir ... Pman/XXX/template ...
195      *  @param template   << name of template used by name field)
196      *  @param base  << view name (module ? + templates?)
197      *  @param force << optional - forces even if database is newer.
198      *  
199      *  
200      */
201     
202     function syncTemplatePage($pgdata)
203     {
204         //print_r($pgdata);
205         
206         $force = true;
207          //echo "compiling:"; print_r($pgdata);
208         // read the template and extract the translatable strings.
209         ini_set('memory_limit', '512M');
210         
211         //var_dump($n);
212         $n = $pgdata['template'];  // remove trailing slash..
213         
214         $fopts = HTML_FlexyFramework::get()->HTML_Template_Flexy;
215         $opts = HTML_FlexyFramework::get()->Pman_Core;
216         //print_R($opts);
217         //$dir = $opts['templateDir'] . '/' . $node;
218         $oo = array(
219             'fatalError'    => PEAR_ERROR_EXCEPTION,  
220             'disableTranslate' => false,
221             'templateDir' => $pgdata['template_dir'],
222             'compileDir' => $fopts['compileDir'] . '_translation_files',
223             'forceCompile' => true, //?? only for force above???
224         );
225          
226         // non-html templates - treat as such..
227         // abiword - treat as html?
228         if (!preg_match('/\.(html|abw)$/i', $pgdata['template'])) {
229             $oo['nonHTML'] = true;
230         }
231         
232         //print_r(array($oo, $n));
233         
234         
235         $flexy = new HTML_Template_Flexy( $oo );
236           
237         if (!$flexy->resolvePath ($pgdata['template'])) {
238             //echo "SKIP - could not resolve path?\n"; print_r($oo);
239             return false;
240         }
241         
242         // attempt to find the template... record.
243         $tmpl = DB_DataObject::Factory($this->tableName());
244        
245         $tmpl->view_name = $pgdata['base'];
246         if ($tmpl->get('template',  $pgdata['template'])) {
247             clearstatcache();
248             if (strtotime($tmpl->updated) >= filemtime($flexy->resolvePath ($pgdata['template']) . '/'. $pgdata['template'])) {
249                 if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != 'html') {
250                     $oo = clone($tmpl);
251                     $tmpl->is_deleted = 0;
252                     $tmpl->filetype = 'html';
253                     $tmpl->update($oo);
254                 }
255                 if (empty($pgdata['force'])) {
256                   //  echo "SKIP NO UPDATE: " . $pgdata['template'] ."\n";
257                    // echo $flexy->resolvePath ($pgdata['template']).  ':'. $tmpl->updated  . ">=" .  date('Y-m-d H:i:s',filemtime($flexy->resolvePath ($pgdata['template']))) . "\n";
258                     return $tmpl;
259                 }
260             }
261         }
262         
263         //die("got here");
264         
265         try {
266             $r = $flexy->compile($pgdata['template']);
267            
268             
269         } catch(Exception $e) {
270             $old = clone($tmpl);
271             $tmpl->updated   = date('Y-m-d H:i:s',filemtime($flexy->resolvePath ($pgdata['template']) . '/'. $pgdata['template']));
272             if ($tmpl->id) {
273                 $tmpl->is_deleted = 0;
274                 $tmpl->filetype = 'html';
275                 $tmpl->update($tmpl);
276             } else {
277                 $tmpl->is_deleted = 0;
278                 $tmpl->filetype = 'html';
279                 $tmpl->lang = 'en';
280                 $tmpl->insert();
281             }
282             //echo "SKIP: " . $pgdata['template'] ."\n";
283            //   echo "SKIP - exception\n"; print_r($e);
284             return false;
285         }
286        
287       
288         if (is_a($r,'PEAR_Error')) {
289             //echo "SKIP: " . $pgdata['template'] ."\n";
290             //echo $r->toString(). "\n";
291             return $r;
292         }
293           
294         $tmpl = DB_DataObject::Factory($this->tableName());
295         $tmpl->words = file_exists($flexy->getTextStringsFile) ?
296                 unserialize(file_get_contents($flexy->getTextStringsFile)) :
297                 array();
298         
299         $tmpl->contentStrings   = $flexy->compiler->contentStrings;
300         //var_dump(file_exists($flexy->getTextStringsFile));
301         //print_r($tmpl->words);
302         $tmpl->currentTemplate  = $flexy->currentTemplate;
303         
304         $tmpl->view_name = $pgdata['base'];
305         
306         //echo $pgdata['template'] ."\n";
307         if (!$tmpl->get('template',  $pgdata['template'])) {
308             $tmpl->is_deleted = 0;
309             $tmpl->filetype = 'html';
310             $tmpl->template = $pgdata['template'];
311             $tmpl->lang = 'en'; /// ??? hard coded??
312             $tmpl->updated = date('Y-m-d H:i:s', filemtime($flexy->currentTemplate));
313             $tmpl->insert();
314         } else {
315             $xx =clone($tmpl);
316             // has it been cahnged...
317             //if (!$force && filemtime($flexy->currentTemplate) == strtotime($tmpl->updated)) {
318                 // nothing changed..
319             //    return $tmpl;
320             //}
321             if (empty($tmpl->lang))  {
322                 //echo "FIX LANG?";exit;
323                 $tmpl->lang = 'en'; /// ??? hard coded??
324             }
325             $tmpl->filetype = 'html';
326             $tmpl->is_deleted = 0;
327             $tmpl->updated = date('Y-m-d H:i:s', filemtime($flexy->currentTemplate));
328             $tmpl->update($xx);
329         }
330       
331         
332         $x = DB_DataObject::Factory('core_templatestr');
333         $x->syncTemplateWords($tmpl);
334         
335         // if file_exists ( template/path/name.php << eg. a matching view..)
336         // then create a system page for this. 
337         
338         
339         
340         $x = DB_DataObject::Factory('core_template_element');
341         $tmpl->elements = $x->syncTemplateElement($tmpl,
342                 file_get_contents($flexy->currentTemplate),
343                 $flexy->compiler->contentStrings,
344                 false);
345         
346         
347         
348         return clone($tmpl);
349     
350     }
351     
352     // allow reuse in cms templatstr
353     function factoryStr()
354     {
355         return DB_DataObject::factory('core_templatestr');
356     }
357
358     function syncFileWord($pgdata, $filetype)
359     {
360         $tmpl = DB_DataObject::Factory($this->tableName());
361         $tmpl->view_name = $pgdata['base'];
362         $tmpl->currentTemplate = $pgdata['template_dir'] . '/'. $pgdata['template'];
363         
364         if ($tmpl->get('template',  $pgdata['template'])) {
365             if (strtotime($tmpl->updated) >= filemtime( $tmpl->currentTemplate )) {
366                 if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != $filetype) {
367                     $oo = clone($tmpl);
368                     $tmpl->is_deleted = 0;
369                     $tmpl->filetype = $filetype;
370                     $tmpl->update($oo);
371                 }
372                 return $tmpl;
373             }
374         }
375
376         $words = array();
377
378         switch($filetype) {
379             case "php":
380                 $ar = token_get_all(file_get_contents( $tmpl->currentTemplate  ));
381                 foreach( $ar as $i=> $tok) {
382                     if (!is_array($tok) || $tok[0] != T_CONSTANT_ENCAPSED_STRING) {
383                         continue;
384                     }
385                     if ($i < 2) {
386                         continue;
387                     }
388                     if (is_array($ar[$i-1]) || $ar[$i-1] != '(') {
389                         continue;
390                     }
391                     if (!is_array($ar[$i-2]) || $ar[$i-2][1] != '_') {
392                         continue;
393                     }
394                     $ct = $tok[1][0];
395                     $words[] =  str_replace('\\'. $ct, $ct, trim($tok[1] , $ct));
396                     
397                 }
398                 break;
399             case "js":
400                 $fc = file_get_contents( $tmpl->currentTemplate );
401         
402                 preg_match_all('/\._\("([^"]+)"\)/', $fc, $outd);
403                 $words = $outd[1];
404                  
405                 preg_match_all('/\._\(\'([^\']+)\'\)/', $fc, $outs);
406                 
407                 // ?? seriously adding two arrays?
408                 $words =  array_diff(array_merge($words, $outs[1]), array_intersect($words, $outs[1]));
409                 break;
410             case "xml":
411                 $words = $pgdata['words'];
412                 break;
413         }
414
415         $words = array_unique($words);
416
417         if(empty($words)) {
418             return;
419         }
420
421         if ($tmpl->id) {
422             $oo = clone($tmpl);
423             $tmpl->is_deleted = 0;
424             $tmpl->filetype = $filetype;
425             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
426             $tmpl->update($oo);
427         } else {
428             $tmpl->is_deleted = 0;
429             $tmpl->filetype = $filetype;
430             $tmpl->lang = 'en';
431             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
432             $tmpl->insert();
433         }
434
435         $tmpl->words = $words;
436
437         $this->factoryStr()->syncTemplateWords($tmpl);
438
439         return $tmpl;
440     }
441
442     function syncPhpGetText($pgdata)
443     {
444         return $this->syncFileWord($pgdata, 'php'); 
445     }
446
447     /**
448      * plain JS files use ._(....) to flag 
449      * it does not support quoted strings or anything really
450      * very simple strings only
451      */ 
452     
453     function syncJsWords($pgdata)
454     {
455         return $this->syncFileWord($pgdata, 'js');   
456     }
457
458     function syncPowerpointXMLText($pgdata) 
459     {
460         return $this->syncFileWord($pgdata, 'xml');
461     }
462     
463     /*
464     SELECT LOWER(
465 CONCAT(
466 REPLACE(view_name, '.','_'),
467 '_',
468 REPLACE(template,'/','_')
469 )
470 )
471 FROM core_template
472
473 WHERE (
474  = 'release_pressrelease_distributionreportnew_journalistdistribution.php'
475 )
476 */
477
478     
479     function genGetText($clsname, $lang=false)
480     {
481         static $done = array();
482         $clsname = strtolower($clsname);
483
484         textdomain($clsname);
485      
486
487         $ff = HTML_FlexyFramework::get();
488         $lang = $lang ? $lang : (isset($ff->locale) ? $ff->locale : 'en');
489         
490
491         if (!empty($done[$clsname.':'.$lang])) {
492             return true; // already sent headers and everything.
493         }
494         
495         putenv("LANGUAGE=$lang");
496         if ($lang != 'en') {
497             if (!setlocale(LC_ALL, $lang.'.UTF-8')) {
498                 $ff->page->jerr("Language is not available {$lang}");
499             }
500         }
501         
502         
503         $d = DB_DataObject::factory($this->tableName());
504         $d->whereAdd("
505             LOWER(
506                 CONCAT(
507                       REPLACE(view_name, '.','_'),
508                     '_',
509                     REPLACE(template,'/','_')
510                 )
511             ) = '{$clsname}.php'
512        ");
513         $d->filetype = 'php';
514         if (! $d->find(true) ){
515             $done[$clsname.':'.$lang] = true;
516             return false;
517         }
518         $user = 'www-data'; // ?? do we need other ones
519         $compileDir = ini_get('session.save_path') .'/' . 
520             $user . '_gettext_' . $ff->project;
521         
522         if ($ff->appNameShort) {
523             $compileDir .= '_' . $ff->appNameShort;
524         }
525         if ($ff->version) {
526             $compileDir .= '.' . $ff->version;
527         }
528         $lang = $lang ? $lang : $ff->locale;
529         $fdir = "{$compileDir}/{$lang}/LC_MESSAGES";
530         $fname = "{$fdir}/{$clsname}.mo";
531         
532          
533         //exit;
534         bindtextdomain($clsname, $compileDir) ;
535         bind_textdomain_codeset($clsname, 'UTF-8');
536
537         textdomain($clsname);
538
539         
540         //textdomain($clsname);
541         
542         $done[$clsname.':'.$lang] = 1;
543         
544         // do we need to compile the file..
545         $ts = $this->factoryStr();
546         $ts->selectAdd('COALESCE(MAX(updated), "1000-01-01") as updated');
547         $ts->lang = $lang;
548         $ts->template_id = $d->id;
549         if (!$ts->find(true)) {
550             // then in theory there are no translations
551             return false;
552         }
553         if (file_exists($fname) && strtotime($ts->updated) < filemtime($fname)) {
554             return $fname; // file exists and is newer than our updated line.
555         }
556         //DB_DataObject::debugLevel(1);
557
558         $ts = $this->factoryStr();
559         $ts->autoJoin();
560         $ts->selectAdd("join_src_id_id.txt as src_id_txt, {$ts->tableName()}.txt as txt");
561         $ts->lang = $lang;
562         $ts->template_id = $d->id;
563         $ts->whereAdd("LENGTH(join_src_id_id.txt) > 0 AND LENGTH({$ts->tableName()}.txt) > 0");
564         $words = $ts->fetchAll('src_id_txt', 'txt' );
565                
566         if (!file_exists($fdir)) {
567             //var_dump($fdir);
568             mkdir($fdir, 0700, true);
569         }
570         
571         require_once 'File/Gettext.php';
572         $gt = File_Gettext::factory('PO', preg_replace('/\.mo$/', '.po', $fname));
573         $gt->fromArray(
574             
575             array(
576                 'meta' => array(
577                     "Language" =>  $lang,
578                     'Content-Type'      => 'text/plain; charset=UTF-8',
579                     'Content-Transfer-Encoding'      => ' 8bit',
580                      'PO-Revision-Date'  => date('Y-m-d H:iO'),
581                  ),
582                 'strings' => $words
583             )
584             
585         );
586         $gt->save();
587         
588         // mo DOESNT WORK!!
589         require_once 'System.php';
590         $poname = preg_replace('/\.mo$/', '.po', $fname);
591         $msgfmt = System::which('msgfmt');
592         $cmd = "{$msgfmt} {$poname}  -o {$fname}";
593         //echo $cmd;
594         
595         `$cmd`;
596         
597         
598          
599         
600         return $fname;
601         
602         require_once 'File/Gettext.php';
603         $gt = File_Gettext::factory('MO', $fname);
604         $gt->fromArray(
605             
606             array(
607                 'meta' => array(
608                      "Language" =>  $lang,
609                     'Content-Type'      => 'text/plain; charset=UTF-8',
610                     'Content-Transfer-Encoding'      => ' 8bit',
611                      'PO-Revision-Date'  => date('Y-m-d H:iO'),
612                 ),
613                 'strings' => $words
614             )
615             
616         );
617         $gt->save(); 
618         
619     }
620 }