dolibarr  7.0.0-beta
translate.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2001 Eric Seigne <erics@rycks.com>
3  * Copyright (C) 2004-2015 Destailleur Laurent <eldy@users.sourceforge.net>
4  * Copyright (C) 2005-2010 Regis Houssin <regis.houssin@capnetworks.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
30 class Translate
31 {
32  public $dir; // Directories that contains /langs subdirectory
33 
34  public $defaultlang; // Current language for current user
35  public $charset_output='UTF-8'; // Codage used by "trans" method outputs
36 
37  public $tab_translate=array(); // Array of all translations key=>value
38  private $_tab_loaded=array(); // Array to store result after loading each language file
39 
40  public $cache_labels=array(); // Cache for labels return by getLabelFromKey method
41  public $cache_currencies=array(); // Cache to store currency symbols
42  private $cache_currencies_all_loaded=false;
43 
44 
51  function __construct($dir, $conf)
52  {
53  if (! empty($conf->file->character_set_client)) $this->charset_output=$conf->file->character_set_client; // If charset output is forced
54  if ($dir) $this->dir=array($dir);
55  else $this->dir=$conf->file->dol_document_root;
56  }
57 
58 
65  function setDefaultLang($srclang='en_US')
66  {
67  global $conf;
68 
69  //dol_syslog(get_class($this)."::setDefaultLang srclang=".$srclang,LOG_DEBUG);
70 
71  // If a module ask to force a priority on langs directories (to use its own lang files)
72  if (! empty($conf->global->MAIN_FORCELANGDIR))
73  {
74  $more=array();
75  $i=0;
76  foreach($conf->file->dol_document_root as $dir)
77  {
78  $newdir=$dir.$conf->global->MAIN_FORCELANGDIR; // For example $conf->global->MAIN_FORCELANGDIR is '/mymodule' meaning we search files into '/mymodule/langs/xx_XX'
79  if (! in_array($newdir,$this->dir))
80  {
81  $more['module_'.$i]=$newdir; $i++; // We add the forced dir into the array $more. Just after, we add entries into $more to list of lang dir $this->dir.
82  }
83  }
84  $this->dir=array_merge($more,$this->dir); // Forced dir ($more) are before standard dirs ($this->dir)
85  }
86 
87  $this->origlang=$srclang;
88 
89  if (empty($srclang) || $srclang == 'auto')
90  {
91  $langpref=empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])?'':$_SERVER['HTTP_ACCEPT_LANGUAGE'];
92  $langpref=preg_replace("/;([^,]*)/i","",$langpref);
93  $langpref=str_replace("-","_",$langpref);
94  $langlist=preg_split("/[;,]/",$langpref);
95  $codetouse=$langlist[0];
96  }
97  else $codetouse=$srclang;
98 
99  // We redefine $srclang
100  $langpart=explode("_",$codetouse);
101  //print "Short code before _ : ".$langpart[0].' / Short code after _ : '.$langpart[1].'<br>';
102  if (! empty($langpart[1])) // If it's for a codetouse that is a long code xx_YY
103  {
104  // Array force long code from first part, even if long code is defined
105  $longforshort=array('ar'=>'ar_SA');
106  $longforshortexcep=array('ar_EG');
107  if (isset($longforshort[strtolower($langpart[0])]) && ! in_array($codetouse, $longforshortexcep)) $srclang=$longforshort[strtolower($langpart[0])];
108  else if (! is_numeric($langpart[1])) { // Second part YY may be a numeric with some Chrome browser
109  $srclang=strtolower($langpart[0])."_".strtoupper($langpart[1]);
110  $longforlong=array('no_nb'=>'nb_NO');
111  if (isset($longforlong[strtolower($srclang)])) $srclang=$longforlong[strtolower($srclang)];
112  }
113  else $srclang=strtolower($langpart[0])."_".strtoupper($langpart[0]);
114  }
115  else { // If it's for a codetouse that is a short code xx
116  // Array to convert short lang code into long code.
117  $longforshort=array('ar'=>'ar_SA', 'el'=>'el_GR', 'ca'=>'ca_ES', 'en'=>'en_US', 'nb'=>'nb_NO', 'no'=>'nb_NO');
118  if (isset($longforshort[strtolower($langpart[0])])) $srclang=$longforshort[strtolower($langpart[0])];
119  else if (! empty($langpart[0])) $srclang=strtolower($langpart[0])."_".strtoupper($langpart[0]);
120  else $srclang='en_US';
121  }
122 
123  $this->defaultlang=$srclang;
124  //print 'this->defaultlang='.$this->defaultlang;
125  }
126 
127 
135  function getDefaultLang($mode=0)
136  {
137  if (empty($mode)) return $this->defaultlang;
138  else return substr($this->defaultlang,0,2);
139  }
140 
141 
148  function loadLangs($domains)
149  {
150  foreach($domains as $domain)
151  {
152  $this->load($domain);
153  }
154  }
155 
176  function load($domain,$alt=0,$stopafterdirection=0,$forcelangdir='',$loadfromfileonly=0)
177  {
178  global $conf,$db;
179 
180  //dol_syslog("Translate::Load Start domain=".$domain." alt=".$alt." forcelangdir=".$forcelangdir." this->defaultlang=".$this->defaultlang);
181 
182  // Check parameters
183  if (empty($domain))
184  {
185  dol_print_error('',get_class($this)."::Load ErrorWrongParameters");
186  return -1;
187  }
188  if ($this->defaultlang == 'none_NONE') return 0; // Special language code to not translate keys
189 
190 
191  // Load $this->tab_translate[] from database
192  if (empty($loadfromfileonly) && count($this->tab_translate) == 0) $this->loadFromDatabase($db); // Nothing was loaded yet, so we load database.
193 
194 
195  $newdomain = $domain;
196  $modulename = '';
197 
198  // Search if a module directory name is provided into lang file name
199  if (preg_match('/^([^@]+)@([^@]+)$/i',$domain,$regs))
200  {
201  $newdomain = $regs[1];
202  $modulename = $regs[2];
203  }
204 
205  // Check cache
206  if (! empty($this->_tab_loaded[$newdomain])) // File already loaded for this domain
207  {
208  //dol_syslog("Translate::Load already loaded for newdomain=".$newdomain);
209  return 0;
210  }
211 
212  $fileread=0;
213  $langofdir=(empty($forcelangdir)?$this->defaultlang:$forcelangdir);
214 
215  // Redefine alt
216  $langarray=explode('_',$langofdir);
217  if ($alt < 1 && isset($langarray[1]) && (strtolower($langarray[0]) == strtolower($langarray[1]) || in_array(strtolower($langofdir), array('el_gr')))) $alt=1;
218  if ($alt < 2 && strtolower($langofdir) == 'en_us') $alt=2;
219 
220  if (empty($langofdir)) // This may occurs when load is called without setting the language and without providing a value for forcelangdir
221  {
222  dol_syslog("Error: ".get_class($this)."::Load was called but language was not set yet with langs->setDefaultLang(). Nothing will be loaded.", LOG_WARNING);
223  return -1;
224  }
225 
226  foreach($this->dir as $keydir => $searchdir)
227  {
228  // Directory of translation files
229  $file_lang = $searchdir.($modulename?'/'.$modulename:'')."/langs/".$langofdir."/".$newdomain.".lang";
230  $file_lang_osencoded=dol_osencode($file_lang);
231 
232  $filelangexists=is_file($file_lang_osencoded);
233 
234  //dol_syslog(get_class($this).'::Load Try to read for alt='.$alt.' langofdir='.$langofdir.' newdomain='.$domain.' modulename='.$modulename.' file_lang='.$file_lang." => filelangexists=".$filelangexists);
235 
236  if ($filelangexists)
237  {
238  // TODO Move cache read out of loop on dirs or at least filelangexists
239  $found=false;
240 
241  // Enable caching of lang file in memory (not by default)
242  $usecachekey='';
243  // Using a memcached server
244  if (! empty($conf->memcached->enabled) && ! empty($conf->global->MEMCACHED_SERVER))
245  {
246  $usecachekey=$newdomain.'_'.$langofdir.'_'.md5($file_lang); // Should not contains special chars
247  }
248  // Using cache with shmop. Speed gain: 40ms - Memory overusage: 200ko (Size of session cache file)
249  else if (isset($conf->global->MAIN_OPTIMIZE_SPEED) && ($conf->global->MAIN_OPTIMIZE_SPEED & 0x02))
250  {
251  $usecachekey=$newdomain;
252  }
253 
254  if ($usecachekey)
255  {
256  //dol_syslog('Translate::Load we will cache result into usecachekey '.$usecachekey);
257  //global $aaa; $aaa+=1;
258  //print $aaa." ".$usecachekey."\n";
259  require_once DOL_DOCUMENT_ROOT .'/core/lib/memory.lib.php';
260  $tmparray=dol_getcache($usecachekey);
261  if (is_array($tmparray) && count($tmparray))
262  {
263  $this->tab_translate+=$tmparray; // Faster than array_merge($tmparray,$this->tab_translate). Note: If a value already exists into tab_translate, value into tmparaay is not added.
264  //print $newdomain."\n";
265  //var_dump($this->tab_translate);
266  if ($alt == 2) $fileread=1;
267  $found=true; // Found in dolibarr PHP cache
268  }
269  }
270 
271  if (! $found)
272  {
273  if ($fp = @fopen($file_lang,"rt"))
274  {
275  if ($usecachekey) $tabtranslatedomain=array(); // To save lang content in cache
276 
282  while ($line = fscanf($fp, "%[^= ]%*[ =]%[^\n]"))
283  {
284  if (isset($line[1]))
285  {
286  list($key, $value) = $line;
287  //if ($domain == 'orders') print "Domain=$domain, found a string for $tab[0] with value $tab[1]. Currently in cache ".$this->tab_translate[$key]."<br>";
288  //if ($key == 'Order') print "Domain=$domain, found a string for key=$key=$tab[0] with value $tab[1]. Currently in cache ".$this->tab_translate[$key]."<br>";
289  if (empty($this->tab_translate[$key]))
290  { // If translation was already found, we must not continue, even if MAIN_FORCELANGDIR is set (MAIN_FORCELANGDIR is to replace lang dir, not to overwrite entries)
291  $value = preg_replace('/\\n/', "\n", $value); // Parse and render carriage returns
292  if ($key == 'DIRECTION') { // This is to declare direction of language
293  if ($alt < 2 || empty($this->tab_translate[$key])) { // We load direction only for primary files or if not yet loaded
294  $this->tab_translate[$key] = $value;
295  if ($stopafterdirection) {
296  break; // We do not save tab if we stop after DIRECTION
297  } elseif ($usecachekey) {
298  $tabtranslatedomain[$key] = $value;
299  }
300  }
301  }
302  elseif ($key[0] == '#')
303  {
304  continue;
305  }
306  else {
307  $this->tab_translate[$key] = $value;
308  //if ($domain == 'orders') print "$tab[0] value $value<br>";
309  if ($usecachekey) {
310  $tabtranslatedomain[$key] = $value;
311  } // To save lang content in cache
312  }
313  }
314  }
315  }
316  fclose($fp);
317  $fileread=1;
318 
319  // TODO Move cache write out of loop on dirs
320  // To save lang content for usecachekey into cache
321  if ($usecachekey && count($tabtranslatedomain))
322  {
323  $ressetcache=dol_setcache($usecachekey,$tabtranslatedomain);
324  if ($ressetcache < 0)
325  {
326  $error='Failed to set cache for usecachekey='.$usecachekey.' result='.$ressetcache;
327  dol_syslog($error, LOG_ERR);
328  }
329  }
330 
331  if (empty($conf->global->MAIN_FORCELANGDIR)) break; // Break loop on each root dir. If a module has forced dir, we do not stop loop.
332  }
333  }
334  }
335  }
336 
337  // Now we complete with next file (fr_CA->fr_FR, es_MX->ex_ES, ...)
338  if ($alt == 0)
339  {
340  // This function MUST NOT contains call to syslog
341  //dol_syslog("Translate::Load loading alternate translation file (to complete ".$this->defaultlang."/".$newdomain.".lang file)", LOG_DEBUG);
342  $langofdir=strtolower($langarray[0]).'_'.strtoupper($langarray[0]);
343  if ($langofdir == 'el_EL') $langofdir = 'el_GR'; // main parent for el_CY is not 'el_EL' but 'el_GR'
344  if ($langofdir == 'ar_AR') $langofdir = 'ar_SA'; // main parent for ar_EG is not 'ar_AR' but 'ar_SA'
345  $this->load($domain,$alt+1,$stopafterdirection,$langofdir);
346  }
347 
348  // Now we complete with reference file (en_US)
349  if ($alt == 1)
350  {
351  // This function MUST NOT contains call to syslog
352  //dol_syslog("Translate::Load loading alternate translation file (to complete ".$this->defaultlang."/".$newdomain.".lang file)", LOG_DEBUG);
353  $langofdir='en_US';
354  $this->load($domain,$alt+1,$stopafterdirection,$langofdir);
355  }
356 
357  // We already are the reference file. No more files to scan to complete.
358  if ($alt == 2)
359  {
360  if ($fileread) $this->_tab_loaded[$newdomain]=1; // Set domain file as loaded
361 
362  if (empty($this->_tab_loaded[$newdomain])) $this->_tab_loaded[$newdomain]=2; // Set this file as found
363  }
364 
365  // This part is deprecated and replaced with table llx_overwrite_trans
366  // Kept for backward compatibility.
367  if (empty($loadfromfileonly))
368  {
369  $overwritekey='MAIN_OVERWRITE_TRANS_'.$this->defaultlang;
370  if (! empty($conf->global->$overwritekey)) // Overwrite translation with key1:newstring1,key2:newstring2
371  {
372  // Overwrite translation with param MAIN_OVERWRITE_TRANS_xx_XX
373  $tmparray=explode(',', $conf->global->$overwritekey);
374  foreach($tmparray as $tmp)
375  {
376  $tmparray2=explode(':',$tmp);
377  if (! empty($tmparray2[1])) $this->tab_translate[$tmparray2[0]]=$tmparray2[1];
378  }
379  }
380  }
381 
382  // Check to be sure that SeparatorDecimal differs from SeparatorThousand
383  if (! empty($this->tab_translate["SeparatorDecimal"]) && ! empty($this->tab_translate["SeparatorThousand"])
384  && $this->tab_translate["SeparatorDecimal"] == $this->tab_translate["SeparatorThousand"]) $this->tab_translate["SeparatorThousand"]='';
385 
386  return 1;
387  }
388 
401  function loadFromDatabase($db)
402  {
403  global $conf;
404 
405  $domain='database';
406 
407  // Check parameters
408  if (empty($db)) return 0; // Database handler can't be used
409 
410  //dol_syslog("Translate::Load Start domain=".$domain." alt=".$alt." forcelangdir=".$forcelangdir." this->defaultlang=".$this->defaultlang);
411 
412  $newdomain = $domain;
413  $modulename = '';
414 
415  // Check cache
416  if (! empty($this->_tab_loaded[$newdomain])) // File already loaded for this domain
417  {
418  //dol_syslog("Translate::Load already loaded for newdomain=".$newdomain);
419  return 0;
420  }
421 
422  $this->_tab_loaded[$newdomain] = 1; // We want to be sure this function is called once only.
423 
424  $fileread=0;
425  $langofdir=(empty($forcelangdir)?$this->defaultlang:$forcelangdir);
426 
427  // Redefine alt
428  $alt=2;
429 
430  if (empty($langofdir)) // This may occurs when load is called without setting the language and without providing a value for forcelangdir
431  {
432  dol_syslog("Error: ".get_class($this)."::Load was called but language was not set yet with langs->setDefaultLang(). Nothing will be loaded.", LOG_WARNING);
433  return -1;
434  }
435 
436  // TODO Move cache read out of loop on dirs or at least filelangexists
437  $found=false;
438 
439  // Enable caching of lang file in memory (not by default)
440  $usecachekey='';
441  // Using a memcached server
442  if (! empty($conf->memcached->enabled) && ! empty($conf->global->MEMCACHED_SERVER))
443  {
444  $usecachekey=$newdomain.'_'.$langofdir.'_'.md5($file_lang); // Should not contains special chars
445  }
446  // Using cache with shmop. Speed gain: 40ms - Memory overusage: 200ko (Size of session cache file)
447  else if (isset($conf->global->MAIN_OPTIMIZE_SPEED) && ($conf->global->MAIN_OPTIMIZE_SPEED & 0x02))
448  {
449  $usecachekey=$newdomain;
450  }
451 
452  if ($usecachekey)
453  {
454  //dol_syslog('Translate::Load we will cache result into usecachekey '.$usecachekey);
455  //global $aaa; $aaa+=1;
456  //print $aaa." ".$usecachekey."\n";
457  require_once DOL_DOCUMENT_ROOT .'/core/lib/memory.lib.php';
458  $tmparray=dol_getcache($usecachekey);
459  if (is_array($tmparray) && count($tmparray))
460  {
461  $this->tab_translate+=$tmparray; // Faster than array_merge($tmparray,$this->tab_translate). Note: If a valuer already exists into tab_translate, value into tmparaay is not added.
462  //print $newdomain."\n";
463  //var_dump($this->tab_translate);
464  $fileread=1;
465  $found=true; // Found in dolibarr PHP cache
466  }
467  }
468 
469  if (! $found && ! empty($conf->global->MAIN_ENABLE_OVERWRITE_TRANSLATION))
470  {
471  // Overwrite translation with database read
472  $sql="SELECT transkey, transvalue FROM ".MAIN_DB_PREFIX."overwrite_trans where lang='".$db->escape($this->defaultlang)."'";
473  $resql=$db->query($sql);
474 
475  if ($resql)
476  {
477  $num = $db->num_rows($resql);
478  if ($num)
479  {
480  if ($usecachekey) $tabtranslatedomain=array(); // To save lang content in cache
481 
482  $i = 0;
483  while ($i < $num) // Ex: Need 225ms for all fgets on all lang file for Third party page. Same speed than file_get_contents
484  {
485  $obj=$db->fetch_object($resql);
486 
487  $key=$obj->transkey;
488  $value=$obj->transvalue;
489 
490  //print "Domain=$domain, found a string for $tab[0] with value $tab[1]<br>";
491  if (empty($this->tab_translate[$key])) // If translation was already found, we must not continue, even if MAIN_FORCELANGDIR is set (MAIN_FORCELANGDIR is to replace lang dir, not to overwrite entries)
492  {
493  $value=trim(preg_replace('/\\n/',"\n",$value));
494 
495  $this->tab_translate[$key]=$value;
496  if ($usecachekey) $tabtranslatedomain[$key]=$value; // To save lang content in cache
497  }
498 
499  $i++;
500  }
501 
502  $fileread=1;
503 
504  // TODO Move cache write out of loop on dirs
505  // To save lang content for usecachekey into cache
506  if ($usecachekey && count($tabtranslatedomain))
507  {
508  $ressetcache=dol_setcache($usecachekey,$tabtranslatedomain);
509  if ($ressetcache < 0)
510  {
511  $error='Failed to set cache for usecachekey='.$usecachekey.' result='.$ressetcache;
512  dol_syslog($error, LOG_ERR);
513  }
514  }
515  }
516  }
517  else
518  {
519  dol_print_error($db);
520  }
521  }
522 
523  if ($fileread) $this->_tab_loaded[$newdomain]=1; // Set domain file as loaded
524 
525  if (empty($this->_tab_loaded[$newdomain])) $this->_tab_loaded[$newdomain]=2; // Marque ce cas comme non trouve (no lines found for language)
526 
527  return 1;
528  }
529 
530 
531 
543  private function getTradFromKey($key)
544  {
545  global $db;
546 
547  if (! is_string($key)) return 'ErrorBadValueForParamNotAString'; // Avoid multiple errors with code not using function correctly.
548 
549  $newstr=$key;
550  if (preg_match('/^Civility([0-9A-Z]+)$/i',$key,$reg))
551  {
552  $newstr=$this->getLabelFromKey($db,$reg[1],'c_civility','code','label');
553  }
554  elseif (preg_match('/^Currency([A-Z][A-Z][A-Z])$/i',$key,$reg))
555  {
556  $newstr=$this->getLabelFromKey($db,$reg[1],'c_currencies','code_iso','label');
557  }
558  elseif (preg_match('/^SendingMethod([0-9A-Z]+)$/i',$key,$reg))
559  {
560  $newstr=$this->getLabelFromKey($db,$reg[1],'c_shipment_mode','code','libelle');
561  }
562  elseif (preg_match('/^PaymentTypeShort([0-9A-Z]+)$/i',$key,$reg))
563  {
564  $newstr=$this->getLabelFromKey($db,$reg[1],'c_paiement','code','libelle','',1);
565  }
566  elseif (preg_match('/^OppStatusShort([0-9A-Z]+)$/i',$key,$reg))
567  {
568  $newstr=$this->getLabelFromKey($db,$reg[1],'c_lead_status','code','label');
569  }
570  elseif (preg_match('/^OppStatus([0-9A-Z]+)$/i',$key,$reg))
571  {
572  $newstr=$this->getLabelFromKey($db,$reg[1],'c_lead_status','code','label');
573  }
574  elseif (preg_match('/^OrderSource([0-9A-Z]+)$/i',$key,$reg))
575  {
576  // TODO OrderSourceX must be replaced with content of table llx_c_input_reason or llx_c_input_method
577  //$newstr=$this->getLabelFromKey($db,$reg[1],'c_ordersource','code','label');
578  }
579  return $newstr;
580  }
581 
582 
597  function trans($key, $param1='', $param2='', $param3='', $param4='', $maxsize=0)
598  {
599  global $conf;
600 
601  if (! empty($this->tab_translate[$key])) // Translation is available
602  {
603  $str=$this->tab_translate[$key];
604 
605  // Make some string replacement after translation
606  $replacekey='MAIN_REPLACE_TRANS_'.$this->defaultlang;
607  if (! empty($conf->global->$replacekey)) // Replacement translation variable with string1:newstring1;string2:newstring2
608  {
609  $tmparray=explode(';', $conf->global->$replacekey);
610  foreach($tmparray as $tmp)
611  {
612  $tmparray2=explode(':',$tmp);
613  $str=preg_replace('/'.preg_quote($tmparray2[0]).'/',$tmparray2[1],$str);
614  }
615  }
616 
617  if (! preg_match('/^Format/',$key))
618  {
619  //print $str;
620  $str=sprintf($str,$param1,$param2,$param3,$param4); // Replace %s and %d except for FormatXXX strings.
621  }
622 
623  if ($maxsize) $str=dol_trunc($str,$maxsize);
624 
625  // We replace some HTML tags by __xx__ to avoid having them encoded by htmlentities
626  $str=str_replace(array('<','>','"',),array('__lt__','__gt__','__quot__'),$str);
627 
628  // Crypt string into HTML
629  $str=htmlentities($str, ENT_COMPAT, $this->charset_output); // Do not convert simple quotes in translation (strings in html are enmbraced by "). Use dol_escape_htmltag around text in HTML content
630 
631  // Restore HTML tags
632  $str=str_replace(array('__lt__','__gt__','__quot__'),array('<','>','"',),$str);
633 
634  return $str;
635  }
636  else // Translation is not available
637  {
638  //if ($key[0] == '$') { return dol_eval($key,1); }
639  return $this->getTradFromKey($key);
640  }
641  }
642 
643 
657  function transnoentities($key, $param1='', $param2='', $param3='', $param4='')
658  {
659  return $this->convToOutputCharset($this->transnoentitiesnoconv($key, $param1, $param2, $param3, $param4));
660  }
661 
662 
677  function transnoentitiesnoconv($key, $param1='', $param2='', $param3='', $param4='')
678  {
679  global $conf;
680 
681  if (! empty($this->tab_translate[$key])) // Translation is available
682  {
683  $str=$this->tab_translate[$key];
684 
685  // Make some string replacement after translation
686  $replacekey='MAIN_REPLACE_TRANS_'.$this->defaultlang;
687  if (! empty($conf->global->$replacekey)) // Replacement translation variable with string1:newstring1;string2:newstring2
688  {
689  $tmparray=explode(';', $conf->global->$replacekey);
690  foreach($tmparray as $tmp)
691  {
692  $tmparray2=explode(':',$tmp);
693  $str=preg_replace('/'.preg_quote($tmparray2[0]).'/',$tmparray2[1],$str);
694  }
695  }
696 
697  if (! preg_match('/^Format/',$key))
698  {
699  //print $str;
700  $str=sprintf($str,$param1,$param2,$param3,$param4); // Replace %s and %d except for FormatXXX strings.
701  }
702 
703  return $str;
704  }
705  else
706  {
707  if ($key[0] == '$') { return dol_eval($key,1); }
708  return $this->getTradFromKey($key);
709  }
710  }
711 
712 
720  function transcountry($str, $countrycode)
721  {
722  if ($this->tab_translate["$str$countrycode"]) return $this->trans("$str$countrycode");
723  else return $this->trans($str);
724  }
725 
726 
734  function transcountrynoentities($str, $countrycode)
735  {
736  if ($this->tab_translate["$str$countrycode"]) return $this->transnoentities("$str$countrycode");
737  else return $this->transnoentities($str);
738  }
739 
740 
748  function convToOutputCharset($str,$pagecodefrom='UTF-8')
749  {
750  if ($pagecodefrom == 'ISO-8859-1' && $this->charset_output == 'UTF-8') $str=utf8_encode($str);
751  if ($pagecodefrom == 'UTF-8' && $this->charset_output == 'ISO-8859-1') $str=utf8_decode(str_replace('€',chr(128),$str));
752  return $str;
753  }
754 
755 
764  function get_available_languages($langdir=DOL_DOCUMENT_ROOT,$maxlength=0,$usecode=0)
765  {
766  global $conf;
767 
768  // We scan directory langs to detect available languages
769  $handle=opendir($langdir."/langs");
770  $langs_available=array();
771  while ($dir = trim(readdir($handle)))
772  {
773  if (preg_match('/^[a-z]+_[A-Z]+/i',$dir))
774  {
775  $this->load("languages");
776 
777  if ($usecode == 2)
778  {
779  $langs_available[$dir] = $dir;
780  }
781  if ($usecode == 1 || ! empty($conf->global->MAIN_SHOW_LANGUAGE_CODE))
782  {
783  $langs_available[$dir] = $dir.': '.dol_trunc($this->trans('Language_'.$dir),$maxlength);
784  }
785  else
786  {
787  $langs_available[$dir] = $this->trans('Language_'.$dir);
788  }
789  }
790  }
791  return $langs_available;
792  }
793 
794 
802  function file_exists($filename,$searchalt=0)
803  {
804  // Test si fichier dans repertoire de la langue
805  foreach($this->dir as $searchdir)
806  {
807  if (is_readable(dol_osencode($searchdir."/langs/".$this->defaultlang."/".$filename))) return true;
808 
809  if ($searchalt)
810  {
811  // Test si fichier dans repertoire de la langue alternative
812  if ($this->defaultlang != "en_US") $filenamealt = $searchdir."/langs/en_US/".$filename;
813  //else $filenamealt = $searchdir."/langs/fr_FR/".$filename;
814  if (is_readable(dol_osencode($filenamealt))) return true;
815  }
816  }
817 
818  return false;
819  }
820 
821 
833  function getLabelFromNumber($number,$isamount=0)
834  {
835  global $conf;
836 
837  $newnumber=$number;
838 
839  $dirsubstitutions=array_merge(array(),$conf->modules_parts['substitutions']);
840  foreach($dirsubstitutions as $reldir)
841  {
842  $dir=dol_buildpath($reldir,0);
843  $newdir=dol_osencode($dir);
844 
845  // Check if directory exists
846  if (! is_dir($newdir)) continue; // We must not use dol_is_dir here, function may not be loaded
847 
848  $fonc='numberwords';
849  if (file_exists($newdir.'/functions_'.$fonc.'.lib.php'))
850  {
851  include_once $newdir.'/functions_'.$fonc.'.lib.php';
852  $newnumber=numberwords_getLabelFromNumber($this,$number,$isamount);
853  break;
854  }
855  }
856 
857  return $newnumber;
858  }
859 
860 
876  function getLabelFromKey($db,$key,$tablename,$fieldkey,$fieldlabel,$keyforselect='',$filteronentity=0)
877  {
878  // If key empty
879  if ($key == '') return '';
880 
881  //print 'param: '.$key.'-'.$keydatabase.'-'.$this->trans($key); exit;
882 
883  // Check if a translation is available (this can call getTradFromKey)
884  $tmp=$this->transnoentitiesnoconv($key);
885  if ($tmp != $key && $tmp != 'ErrorBadValueForParamNotAString')
886  {
887  return $tmp; // Found in language array
888  }
889 
890  // Check in cache
891  if (isset($this->cache_labels[$tablename][$key])) // Can be defined to 0 or ''
892  {
893  return $this->cache_labels[$tablename][$key]; // Found in cache
894  }
895 
896  $sql = "SELECT ".$fieldlabel." as label";
897  $sql.= " FROM ".MAIN_DB_PREFIX.$tablename;
898  $sql.= " WHERE ".$fieldkey." = '".($keyforselect?$keyforselect:$key)."'";
899  if ($filteronentity) $sql.= " AND entity IN (" . getEntity($tablename). ')';
900  dol_syslog(get_class($this).'::getLabelFromKey', LOG_DEBUG);
901  $resql = $db->query($sql);
902  if ($resql)
903  {
904  $obj = $db->fetch_object($resql);
905  if ($obj) $this->cache_labels[$tablename][$key]=$obj->label;
906  else $this->cache_labels[$tablename][$key]=$key;
907 
908  $db->free($resql);
909  return $this->cache_labels[$tablename][$key];
910  }
911  else
912  {
913  $this->error=$db->lasterror();
914  return -1;
915  }
916  }
917 
918 
928  function getCurrencyAmount($currency_code, $amount)
929  {
930  $symbol=$this->getCurrencySymbol($currency_code);
931 
932  if (in_array($currency_code, array('USD'))) return $symbol.$amount;
933  else return $amount.$symbol;
934  }
935 
944  function getCurrencySymbol($currency_code, $forceloadall=0)
945  {
946  $currency_sign = ''; // By default return iso code
947 
948  if (function_exists("mb_convert_encoding"))
949  {
950  $this->loadCacheCurrencies($forceloadall?'':$currency_code);
951 
952  if (isset($this->cache_currencies[$currency_code]) && ! empty($this->cache_currencies[$currency_code]['unicode']) && is_array($this->cache_currencies[$currency_code]['unicode']))
953  {
954  foreach($this->cache_currencies[$currency_code]['unicode'] as $unicode)
955  {
956  $currency_sign .= mb_convert_encoding("&#{$unicode};", "UTF-8", 'HTML-ENTITIES');
957  }
958  }
959  }
960 
961  return ($currency_sign?$currency_sign:$currency_code);
962  }
963 
970  public function loadCacheCurrencies($currency_code)
971  {
972  global $db;
973 
974  if ($this->cache_currencies_all_loaded) return 0; // Cache already loaded for all
975  if (! empty($currency_code) && isset($this->cache_currencies[$currency_code])) return 0; // Cache already loaded for the currency
976 
977  $sql = "SELECT code_iso, label, unicode";
978  $sql.= " FROM ".MAIN_DB_PREFIX."c_currencies";
979  $sql.= " WHERE active = 1";
980  if (! empty($currency_code)) $sql.=" AND code_iso = '".$currency_code."'";
981  //$sql.= " ORDER BY code_iso ASC"; // Not required, a sort is done later
982 
983  dol_syslog(get_class($this).'::loadCacheCurrencies', LOG_DEBUG);
984  $resql = $db->query($sql);
985  if ($resql)
986  {
987  $this->load("dict");
988  $label=array();
989  if (! empty($currency_code)) foreach($this->cache_currencies as $key => $val) $label[$key]=$val['label']; // Label in already loaded cache
990 
991  $num = $db->num_rows($resql);
992  $i = 0;
993  while ($i < $num)
994  {
995  $obj = $db->fetch_object($resql);
996 
997  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
998  $this->cache_currencies[$obj->code_iso]['label'] = ($obj->code_iso && $this->trans("Currency".$obj->code_iso)!="Currency".$obj->code_iso?$this->trans("Currency".$obj->code_iso):($obj->label!='-'?$obj->label:''));
999  $this->cache_currencies[$obj->code_iso]['unicode'] = (array) json_decode($obj->unicode, true);
1000  $label[$obj->code_iso] = $this->cache_currencies[$obj->code_iso]['label'];
1001  $i++;
1002  }
1003  if (empty($currency_code)) $this->cache_currencies_all_loaded=true;
1004  //print count($label).' '.count($this->cache_currencies);
1005 
1006  // Resort cache
1007  array_multisort($label, SORT_ASC, $this->cache_currencies);
1008  //var_dump($this->cache_currencies); $this->cache_currencies is now sorted onto label
1009  return $num;
1010  }
1011  else
1012  {
1013  dol_print_error($db);
1014  return -1;
1015  }
1016  }
1017 
1025  {
1026  $substitutionarray = array();
1027 
1028  foreach($this->tab_translate as $code => $label) {
1029  $substitutionarray['lang_'.$code] = $label;
1030  }
1031 
1032  return $substitutionarray;
1033  }
1034 }
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
setDefaultLang($srclang='en_US')
Set accessor for this->defaultlang.
dol_getcache($memoryid)
Read a memory area shared by all users, all sessions on server.
Definition: memory.lib.php:110
transnoentitiesnoconv($key, $param1='', $param2='', $param3='', $param4='')
Return translated value of a text string Si il n'y a pas de correspondance pour ce texte...
dol_eval($s, $returnvalue=0, $hideerrors=1)
Replace eval function to add more security.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '...' if string larger than length.
loadFromDatabase($db)
Load translation key-value from database into a memory array.
__construct($dir, $conf)
Constructor.
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
get_available_languages($langdir=DOL_DOCUMENT_ROOT, $maxlength=0, $usecode=0)
Return list of all available languages.
loadCacheCurrencies($currency_code)
Load into the cache this->cache_currencies, all currencies.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
transcountrynoentities($str, $countrycode)
Retourne la version traduite du texte passe en parametre complete du code pays.
file_exists($filename, $searchalt=0)
Return if a filename $filename exists for current language (or alternate language) ...
getCurrencySymbol($currency_code, $forceloadall=0)
Return a currency code into its symbol.
load($domain, $alt=0, $stopafterdirection=0, $forcelangdir='', $loadfromfileonly=0)
Load translation key-value for a particular file, into a memory array.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
convToOutputCharset($str, $pagecodefrom='UTF-8')
Convert a string into output charset (this->charset_output that should be defined to conf->file->char...
getLabelFromNumber($number, $isamount=0)
Return full text translated to language label for a key.
getEntity($element, $shared=1, $forceentity=null)
Get list of entity id to use.
dol_setcache($memoryid, $data)
Save data into a memory area shared by all users, all sessions on server.
Definition: memory.lib.php:42
Class to manage translations.
getLabelFromKey($db, $key, $tablename, $fieldkey, $fieldlabel, $keyforselect='', $filteronentity=0)
Return a label for a key.
getCurrencyAmount($currency_code, $amount)
Return a currency code into its symbol.
getDefaultLang($mode=0)
Return active language code for current user It's an accessor for this->defaultlang.
trans($key, $param1='', $param2='', $param3='', $param4='', $maxsize=0)
Return text translated of text received as parameter (and encode it into HTML) Si il n'y a pas de cor...
get_translations_for_substitutions()
Return an array with content of all loaded translation keys (found into this->tab_translate) so we ge...
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if(!empty($conf->fournisseur->enabled)&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->societe->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if(!empty($conf->fournisseur->enabled)&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1013
loadLangs($domains)
Load translation files.
getTradFromKey($key)
Return translated value of key for special keys ("Currency...", "Civility...", ...).
transnoentities($key, $param1='', $param2='', $param3='', $param4='')
Return translated value of a text string Si il n'y a pas de correspondance pour ce texte...
transcountry($str, $countrycode)
Return translation of a key depending on country.