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     
353     function syncPhpGetText($pgdata)
354     {
355         $tmpl = DB_DataObject::Factory($this->tableName());
356         $tmpl->view_name = $pgdata['base'];
357         $tmpl->currentTemplate = $pgdata['template_dir'] . '/'. $pgdata['template'];
358         
359         if ($tmpl->get('template',  $pgdata['template'])) {
360             if (strtotime($tmpl->updated) >= filemtime( $tmpl->currentTemplate )) {
361                 if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != 'html') {
362                     $oo = clone($tmpl);
363                     $tmpl->is_deleted = 0;
364                     $tmpl->filetype = 'php';
365                     $tmpl->update($oo);
366                 }
367                 return $tmpl;
368             }
369         }
370         $words = array();
371         
372         $ar = token_get_all(file_get_contents( $tmpl->currentTemplate  ));
373         foreach( $ar as $i=> $tok) {
374             if (!is_array($tok) || $tok[0] != T_CONSTANT_ENCAPSED_STRING) {
375                 continue;
376             }
377             if ($i < 2) {
378                 continue;
379             }
380             if (is_array($ar[$i-1]) || $ar[$i-1] != '(') {
381                 continue;
382             }
383             if (!is_array($ar[$i-2]) || $ar[$i-2][1] != '_') {
384                 continue;
385             }
386             $ct = $tok[1][0];
387             $words[] =  str_replace('\\'. $ct, $ct, trim($tok[1] , $ct));
388             
389         }
390         // create the template...
391         
392         
393         if (!$tmpl->id) {
394             
395             $tmpl->template = $pgdata['template'];
396             $tmpl->lang = 'en'; /// ??? hard coded??
397             $tmpl->filetype = 'php';
398             $tmpl->is_deleted = 0;
399             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
400             $tmpl->insert();
401         } else {
402             $xx =clone($tmpl);
403             $tmpl->filetype = 'php';
404             $tmpl->is_deleted = 0;
405             $tmpl->lang = 'en'; /// ??? hard coded??
406             $tmpl->updated = date('Y-m-d H:i:s', filemtime($tmpl->currentTemplate));
407             $tmpl->update($xx);
408         }
409       
410         $words = array_unique($words);
411         
412         if (!count($words)) {
413             return;
414         }
415         
416              
417         $tmpl->words = $words;
418             
419         $x = DB_DataObject::Factory('core_templatestr');
420         $this->factoryStr()->syncTemplateWords($tmpl);     
421          
422         
423         return $tmpl;
424         
425         
426         
427     }
428     // allow reuse in cms templatstr
429     function factoryStr()
430     {
431         return DB_DataObject::factory('core_templatestr');
432     }
433     
434     /**
435      * plain JS files use ._(....) to flag 
436      * it does not support quoted strings or anything really
437      * very simple strings only
438      */ 
439     
440     function syncJsWords($pgdata)
441     {
442         $tmpl = DB_DataObject::Factory($this->tableName());
443         $tmpl->view_name = $pgdata['base'];
444         $tmpl->currentTemplate = $pgdata['template_dir'] . '/'. $pgdata['template'];
445         
446         if ($tmpl->get('template',  $pgdata['template'])) {
447             if (strtotime($tmpl->updated) >= filemtime( $tmpl->currentTemplate )) {
448                 if ($tmpl->is_deleted != 0 ||  $tmpl->filetype != 'js') {
449                     $oo = clone($tmpl);
450                     $tmpl->is_deleted = 0;
451                     $tmpl->filetype = 'js';
452                     $tmpl->update($oo);
453                 }
454                 return $tmpl;
455             }
456         }
457         $words = array();
458         
459         $fc = file_get_contents( $tmpl->currentTemplate );
460         
461         preg_match_all('/\._\("([^"]+)"\)/', $fc, $outd);
462         $words = $outd[1];
463          
464         preg_match_all('/\._\(\'([^\']+)\'\)/', $fc, $outs);
465         
466         // ?? seriously adding two arrays?
467         $words =  array_diff(array_merge($words, $outs[1]), array_intersect($words, $outs[1]));
468         $words = array_unique($words);
469         
470         if (empty($words)) {
471             return;
472         }
473         if ($tmpl->id) {
474             $tmpl->is_deleted = 0;
475             $tmpl->filetype = 'js';
476             $tmpl->update($tmpl);
477         } else {
478             $tmpl->is_deleted = 0;
479             $tmpl->filetype = 'js';
480             $tmpl->lang = 'en';
481             $tmpl->insert();
482         }
483         
484              
485         $tmpl->words = $words;
486             
487         $this->factoryStr()->syncTemplateWords($tmpl);    
488          
489         
490         return $tmpl;
491         
492         
493         
494     }
495     
496     /*
497     SELECT LOWER(
498 CONCAT(
499 REPLACE(view_name, '.','_'),
500 '_',
501 REPLACE(template,'/','_')
502 )
503 )
504 FROM core_template
505
506 WHERE (
507  = 'release_pressrelease_distributionreportnew_journalistdistribution.php'
508 )
509 */
510
511     
512     function genGetText($clsname, $lang=false)
513     {
514         static $done = array();
515         $clsname = strtolower($clsname);
516
517         textdomain($clsname);
518      
519
520         $ff = HTML_FlexyFramework::get();
521         $lang = $lang ? $lang : (isset($ff->locale) ? $ff->locale : 'en');
522         
523
524         if (!empty($done[$clsname.':'.$lang])) {
525             return true; // already sent headers and everything.
526         }
527         
528         putenv("LANGUAGE=$lang");
529         if ($lang != 'en') {
530             if (!setlocale(LC_ALL, $lang.'.UTF-8')) {
531                 $ff->page->jerr("Language is not available {$lang}");
532             }
533         }
534         
535         
536         $d = DB_DataObject::factory($this->tableName());
537         $d->whereAdd("
538             LOWER(
539                 CONCAT(
540                       REPLACE(view_name, '.','_'),
541                     '_',
542                     REPLACE(template,'/','_')
543                 )
544             ) = '{$clsname}.php'
545        ");
546         $d->filetype = 'php';
547         if (! $d->find(true) ){
548             $done[$clsname.':'.$lang] = true;
549             return false;
550         }
551         $user = 'www-data'; // ?? do we need other ones
552         $compileDir = ini_get('session.save_path') .'/' . 
553             $user . '_gettext_' . $ff->project;
554         
555         if ($ff->appNameShort) {
556             $compileDir .= '_' . $ff->appNameShort;
557         }
558         if ($ff->version) {
559             $compileDir .= '.' . $ff->version;
560         }
561         $lang = $lang ? $lang : $ff->locale;
562         $fdir = "{$compileDir}/{$lang}/LC_MESSAGES";
563         $fname = "{$fdir}/{$clsname}.mo";
564         
565          
566         //exit;
567         bindtextdomain($clsname, $compileDir) ;
568         bind_textdomain_codeset($clsname, 'UTF-8');
569
570         textdomain($clsname);
571
572         
573         //textdomain($clsname);
574         
575         $done[$clsname.':'.$lang] = 1;
576         
577         // do we need to compile the file..
578         $ts = $this->factoryStr();
579         $ts->selectAdd('COALESCE(MAX(updated), "1000-01-01") as updated');
580         $ts->lang = $lang;
581         $ts->template_id = $d->id;
582         if (!$ts->find(true)) {
583             // then in theory there are no translations
584             return false;
585         }
586         if (file_exists($fname) && strtotime($ts->updated) < filemtime($fname)) {
587             return $fname; // file exists and is newer than our updated line.
588         }
589         //DB_DataObject::debugLevel(1);
590
591         $ts = $this->factoryStr();
592         $ts->autoJoin();
593         $ts->selectAdd("join_src_id_id.txt as src_id_txt, {$ts->tableName()}.txt as txt");
594         $ts->lang = $lang;
595         $ts->template_id = $d->id;
596         $ts->whereAdd("LENGTH(join_src_id_id.txt) > 0 AND LENGTH({$ts->tableName()}.txt) > 0");
597         $words = $ts->fetchAll('src_id_txt', 'txt' );
598                
599         if (!file_exists($fdir)) {
600             //var_dump($fdir);
601             mkdir($fdir, 0700, true);
602         }
603         
604         require_once 'File/Gettext.php';
605         $gt = File_Gettext::factory('PO', preg_replace('/\.mo$/', '.po', $fname));
606         $gt->fromArray(
607             
608             array(
609                 'meta' => array(
610                     "Language" =>  $lang,
611                     'Content-Type'      => 'text/plain; charset=UTF-8',
612                     'Content-Transfer-Encoding'      => ' 8bit',
613                      'PO-Revision-Date'  => date('Y-m-d H:iO'),
614                  ),
615                 'strings' => $words
616             )
617             
618         );
619         $gt->save();
620         
621         // mo DOESNT WORK!!
622         require_once 'System.php';
623         $poname = preg_replace('/\.mo$/', '.po', $fname);
624         $msgfmt = System::which('msgfmt');
625         $cmd = "{$msgfmt} {$poname}  -o {$fname}";
626         //echo $cmd;
627         
628         `$cmd`;
629         
630         
631          
632         
633         return $fname;
634         
635         require_once 'File/Gettext.php';
636         $gt = File_Gettext::factory('MO', $fname);
637         $gt->fromArray(
638             
639             array(
640                 'meta' => array(
641                      "Language" =>  $lang,
642                     'Content-Type'      => 'text/plain; charset=UTF-8',
643                     'Content-Transfer-Encoding'      => ' 8bit',
644                      'PO-Revision-Date'  => date('Y-m-d H:iO'),
645                 ),
646                 'strings' => $words
647             )
648             
649         );
650         $gt->save(); 
651         
652     }
653 }