Completed
Branch develop (bb7c03)
by
unknown
34:20
created

Translate::loadFromDatabase()   F

Complexity

Conditions 25
Paths 652

Size

Total Lines 128
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 56
nc 652
nop 1
dl 0
loc 128
rs 2.2307
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 2001      Eric Seigne         <[email protected]>
3
 * Copyright (C) 2004-2015 Destailleur Laurent <[email protected]>
4
 * Copyright (C) 2005-2010 Regis Houssin       <[email protected]>
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
20
/**
21
 *   	\file       htdocs/core/class/translate.class.php
22
 *      \ingroup    core
23
 *		\brief      File for Tanslate class
24
 */
25
26
27
/**
28
 *		Class to manage translations
29
 */
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
45
	/**
46
	 *	Constructor
47
	 *
48
	 *  @param	string	$dir            Force directory that contains /langs subdirectory (value is sometine '..' like into install/* pages or support/* pages).
49
	 *  @param  Conf	$conf			Object with Dolibarr configuration
50
	 */
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
59
	/**
60
	 *  Set accessor for this->defaultlang
61
	 *
62
	 *  @param	string	$srclang     	Language to use. If '' or 'auto', we use browser lang.
63
	 *  @return	void
64
	 */
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
128
	/**
129
	 *  Return active language code for current user
130
	 * 	It's an accessor for this->defaultlang
131
	 *
132
	 *  @param	int		$mode       0=Long language code, 1=Short language code
133
	 *  @return string      		Language code used (en_US, en_AU, fr_FR, ...)
134
	 */
135
	function getDefaultLang($mode=0)
136
	{
137
	    if (empty($mode)) return $this->defaultlang;
138
	    else return substr($this->defaultlang,0,2);
139
	}
140
141
142
	/**
143
	 *  Load translation files.
144
     *
145
	 *  @param	array	$domains      		Array of lang files to load
146
	 *	@return	int							<0 if KO, 0 if already loaded or loading not required, >0 if OK
147
	 */
148
	function loadLangs($domains)
149
	{
150
	    foreach($domains as $domain)
151
	    {
152
	        $this->load($domain);
153
	    }
154
	}
155
156
	/**
157
	 *  Load translation key-value for a particular file, into a memory array.
158
	 *  If data for file already loaded, do nothing.
159
	 * 	All data in translation array are stored in UTF-8 format.
160
     *  tab_loaded is completed with $domain key.
161
     *  rule "we keep first entry found with we keep last entry found" so it is probably not what you want to do.
162
     *
163
     *  Value for hash are: 1:Loaded from disk, 2:Not found, 3:Loaded from cache
164
     *
165
	 *  @param	string	$domain      		File name to load (.lang file). Must be "file" or "file@module" for module language files:
166
 	 *										If $domain is "file@module" instead of "file" then we look for module lang file
167
	 *										in htdocs/custom/modules/mymodule/langs/code_CODE/file.lang
168
	 *										then in htdocs/module/langs/code_CODE/file.lang instead of htdocs/langs/code_CODE/file.lang
169
	 *  @param	integer	$alt         		0 (try xx_ZZ then 1), 1 (try xx_XX then 2), 2 (try en_US)
170
	 * 	@param	int		$stopafterdirection	Stop when the DIRECTION tag is found (optimize speed)
171
	 * 	@param	int		$forcelangdir		To force a different lang directory
172
	 *  @param  int     $loadfromfileonly   1=Do not load overwritten translation from file or old conf.
173
	 *	@return	int							<0 if KO, 0 if already loaded or loading not required, >0 if OK
174
	 *  @see loadLangs
175
	 */
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
277
						/**
278
						 * Read each lines until a '=' (with any combination of spaces around it)
279
						 * and split the rest until a line feed.
280
						 * This is more efficient than fgets + explode + trim by a factor of ~2.
281
						 */
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;
0 ignored issues
show
Bug introduced by
The variable $tabtranslatedomain does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
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
389
	/**
390
	 *  Load translation key-value from database into a memory array.
391
	 *  If data already loaded, do nothing.
392
	 * 	All data in translation array are stored in UTF-8 format.
393
     *  tab_loaded is completed with $domain key.
394
     *  rule "we keep first entry found with we keep last entry found" so it is probably not what you want to do.
395
     *
396
     *  Value for hash are: 1:Loaded from disk, 2:Not found, 3:Loaded from cache
397
     *
398
     *  @param  Database    $db             Database handler
399
	 *	@return	int							<0 if KO, 0 if already loaded or loading not required, >0 if OK
400
	 */
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);
0 ignored issues
show
Bug introduced by
The variable $forcelangdir seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
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
0 ignored issues
show
Bug introduced by
The variable $file_lang does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
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
0 ignored issues
show
Bug introduced by
The variable $tabtranslatedomain does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
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
532
	/**
533
	 * Return translated value of key for special keys ("Currency...", "Civility...", ...).
534
	 * Search in lang file, then into database. Key must be any complete entry into lang file: CurrencyEUR, ...
535
	 * If not found, return key.
536
	 * The string return is not formated (translated with transnoentitiesnoconv)
537
	 * NOTE: To avoid infinite loop (getLabelFromKey->transnoentities->getTradFromKey), if you modify this function,
538
	 * check that getLabelFromKey is not called with same value than input.
539
	 *
540
	 * @param	string		$key		Key to translate
541
	 * @return 	string					Translated string (translated with transnoentitiesnoconv)
542
	 */
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
583
	/**
584
	 *  Return text translated of text received as parameter (and encode it into HTML)
585
	 *              Si il n'y a pas de correspondance pour ce texte, on cherche dans fichier alternatif
586
	 *              et si toujours pas trouve, il est retourne tel quel
587
	 *              Les parametres de cette methode peuvent contenir de balises HTML.
588
	 *
589
	 *  @param	string	$key        Key to translate
590
	 *  @param  string	$param1     chaine de param1
591
	 *  @param  string	$param2     chaine de param2
592
	 *  @param  string	$param3     chaine de param3
593
	 *  @param  string	$param4     chaine de param4
594
	 *	@param	int		$maxsize	Max length of text
595
	 *  @return string      		Translated string (encoded into HTML entities and UTF8)
596
	 */
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
644
	/**
645
	 *  Return translated value of a text string
646
	 *               Si il n'y a pas de correspondance pour ce texte, on cherche dans fichier alternatif
647
	 *               et si toujours pas trouve, il est retourne tel quel.
648
	 *               Parameters of this method must not contains any HTML tags.
649
	 *
650
	 *  @param	string	$key        Key to translate
651
	 *  @param  string	$param1     chaine de param1
652
	 *  @param  string	$param2     chaine de param2
653
	 *  @param  string	$param3     chaine de param3
654
	 *  @param  string	$param4     chaine de param4
655
	 *  @return string      		Translated string (encoded into UTF8)
656
	 */
657
	function transnoentities($key, $param1='', $param2='', $param3='', $param4='')
658
	{
659
		return $this->convToOutputCharset($this->transnoentitiesnoconv($key, $param1, $param2, $param3, $param4));
660
	}
661
662
663
	/**
664
	 *  Return translated value of a text string
665
	 *               Si il n'y a pas de correspondance pour ce texte, on cherche dans fichier alternatif
666
	 *               et si toujours pas trouve, il est retourne tel quel.
667
	 *               No convert to encoding charset of lang object is done.
668
	 *               Parameters of this method must not contains any HTML tags.
669
	 *
670
	 *  @param	string	$key        Key to translate
671
	 *  @param  string	$param1     chaine de param1
672
	 *  @param  string	$param2     chaine de param2
673
	 *  @param  string	$param3     chaine de param3
674
	 *  @param  string	$param4     chaine de param4
675
	 *  @return string      		Translated string
676
	 */
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
713
	/**
714
	 *  Return translation of a key depending on country
715
	 *
716
	 *  @param	string	$str            string root to translate
717
	 *  @param  string	$countrycode    country code (FR, ...)
718
	 *  @return	string         			translated string
719
	 */
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
727
	/**
728
	 *  Retourne la version traduite du texte passe en parametre complete du code pays
729
	 *
730
	 *  @param	string	$str            string root to translate
731
	 *  @param  string	$countrycode    country code (FR, ...)
732
	 *  @return string         			translated string
733
	 */
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
741
	/**
742
	 *  Convert a string into output charset (this->charset_output that should be defined to conf->file->character_set_client)
743
	 *
744
	 *  @param	string	$str            String to convert
745
	 *  @param	string	$pagecodefrom	Page code of src string
746
	 *  @return string         			Converted string
747
	 */
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
756
	/**
757
	 *  Return list of all available languages
758
	 *
759
	 * 	@param	string	$langdir		Directory to scan
760
	 *  @param  integer	$maxlength   	Max length for each value in combo box (will be truncated)
761
	 *  @param	int		$usecode		1=Show code instead of country name for language variant, 2=Show only code
762
	 *  @return array     				List of languages
763
	 */
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
795
	/**
796
	 *  Return if a filename $filename exists for current language (or alternate language)
797
	 *
798
	 *  @param	string	$filename       Language filename to search
799
	 *  @param  integer	$searchalt      Search also alernate language file
800
	 *  @return boolean         		true if exists and readable
801
	 */
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;
0 ignored issues
show
Bug introduced by
The variable $filenamealt does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
815
			}
816
		}
817
818
		return false;
819
	}
820
821
822
	/**
823
	 *      Return full text translated to language label for a key. Store key-label in a cache.
824
     *      This function need module "numberwords" to be installed. If not it will return
825
     *      same number (this module is not provided by default as it use non GPL source code).
826
	 *
827
	 *		@param	int		$number		Number to encode in full text
828
	 * 		@param	int		$isamount	1=It's an amount, 0=it's just a number
829
	 *      @return string				Label translated in UTF8 (but without entities)
830
	 * 									10 if setDefaultLang was en_US => ten
831
	 * 									123 if setDefaultLang was fr_FR => cent vingt trois
832
	 */
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
861
	/**
862
	 *      Return a label for a key.
863
	 *      Search into translation array, then into cache, then if still not found, search into database.
864
	 *      Store key-label found into cache variable $this->cache_labels to save SQL requests to get labels.
865
	 *
866
	 * 		@param	DoliDB	$db				Database handler
867
	 * 		@param	string	$key			Translation key to get label (key in language file)
868
	 * 		@param	string	$tablename		Table name without prefix
869
	 * 		@param	string	$fieldkey		Field for key
870
	 * 		@param	string	$fieldlabel		Field for label
871
	 *      @param	string	$keyforselect	Use another value than the translation key for the where into select
872
	 *      @param  int		$filteronentity	Use a filter on entity
873
	 *      @return string					Label in UTF8 (but without entities)
874
	 *      @see dol_getIdFromCode
875
	 */
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
919
	/**
920
	 *	Return a currency code into its symbol
921
	 *
922
	 *  @param	string	$currency_code		Currency Code
923
	 *  @param	string	$amount				If not '', show currency + amount according to langs ($10, 10€).
924
	 *  @return	string						Amount + Currency symbol encoded into UTF8
925
	 *  @deprecated							Use method price to output a price
926
	 *  @see price()
927
	 */
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
936
	/**
937
	 *	Return a currency code into its symbol.
938
	 *  If mb_convert_encoding is not available, return currency code.
939
	 *
940
	 *  @param	string	$currency_code		Currency code
941
	 *  @param	integer	$forceloadall		1=Force to load all currencies into cache. We know we need to use all of them. By default read and cache only required currency.
942
	 *  @return	string						Currency symbol encoded into UTF8
943
	 */
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
964
	/**
965
	 *  Load into the cache this->cache_currencies, all currencies
966
	 *
967
	 *	@param	string	$currency_code		Get only currency. Get all if ''.
968
	 *  @return int             			Nb of loaded lines, 0 if already loaded, <0 if KO
969
	 */
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
1018
	/**
1019
	 * Return an array with content of all loaded translation keys (found into this->tab_translate) so
1020
	 * we get a substitution array we can use for substitutions (for mail or ODT generation for example)
1021
	 *
1022
	 * @return array	Array of translation keys lang_key => string_translation_loaded
1023
	 */
1024
	function get_translations_for_substitutions()
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
}
1035