Passed
Branch develop (803efa)
by
unknown
32:29
created

Translate::getCurrencyAmount()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 6
rs 10
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 <https://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 $shortlang; // Short language for current user
36
	public $charset_output = 'UTF-8'; // Codage used by "trans" method outputs
37
38
	public $tab_translate = array(); // Array of all translations key=>value
39
	private $_tab_loaded = array(); // Array to store result after loading each language file
40
41
	public $cache_labels = array(); // Cache for labels return by getLabelFromKey method
42
	public $cache_currencies = array(); // Cache to store currency symbols
43
    private $cache_currencies_all_loaded = false;
44
45
46
	/**
47
	 *	Constructor
48
	 *
49
	 *  @param	string	$dir            Force directory that contains /langs subdirectory (value is sometimes '..' like into install/* pages or support/* pages). Use '' by default.
50
	 *  @param  Conf	$conf			Object with Dolibarr configuration
51
	 */
52
	public function __construct($dir, $conf)
53
	{
54
		if (!empty($conf->file->character_set_client)) $this->charset_output = $conf->file->character_set_client; // If charset output is forced
55
		if ($dir) $this->dir = array($dir);
56
		else $this->dir = $conf->file->dol_document_root;
57
	}
58
59
60
	/**
61
	 *  Set accessor for this->defaultlang
62
	 *
63
	 *  @param	string	$srclang     	Language to use. If '' or 'auto', we use browser lang.
64
	 *  @return	void
65
	 */
66
	public function setDefaultLang($srclang = 'en_US')
67
	{
68
		global $conf;
69
70
		//dol_syslog(get_class($this)."::setDefaultLang srclang=".$srclang,LOG_DEBUG);
71
72
		// If a module ask to force a priority on langs directories (to use its own lang files)
73
		if (!empty($conf->global->MAIN_FORCELANGDIR))
74
		{
75
			$more = array();
76
			$i = 0;
77
			foreach ($conf->file->dol_document_root as $dir)
78
			{
79
				$newdir = $dir.$conf->global->MAIN_FORCELANGDIR; // For example $conf->global->MAIN_FORCELANGDIR is '/mymodule' meaning we search files into '/mymodule/langs/xx_XX'
80
				if (!in_array($newdir, $this->dir))
81
				{
82
				    $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.
83
				}
84
			}
85
			$this->dir = array_merge($more, $this->dir); // Forced dir ($more) are before standard dirs ($this->dir)
86
		}
87
88
		$this->origlang = $srclang;
89
90
		if (empty($srclang) || $srclang == 'auto')
91
		{
92
			// $_SERVER['HTTP_ACCEPT_LANGUAGE'] can be 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7,it;q=0.6' but can contains also malicious content
93
			$langpref = empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? '' : $_SERVER['HTTP_ACCEPT_LANGUAGE'];
94
			$langpref = preg_replace("/;([^,]*)/i", "", $langpref); // Remove the 'q=x.y,' part
95
			$langpref = str_replace("-", "_", $langpref);
96
			$langlist = preg_split("/[;,]/", $langpref);
97
			$codetouse = preg_replace('/[^_a-zA-Z]/', '', $langlist[0]);
98
		} else $codetouse = $srclang;
99
100
		// We redefine $srclang
101
		$langpart = explode("_", $codetouse);
102
		//print "Short code before _ : ".$langpart[0].' / Short code after _ : '.$langpart[1].'<br>';
103
		if (!empty($langpart[1]))	// If it's for a codetouse that is a long code xx_YY
104
		{
105
			// Array force long code from first part, even if long code is defined
106
			$longforshort = array('ar'=>'ar_SA');
107
			$longforshortexcep = array('ar_EG');
108
			if (isset($longforshort[strtolower($langpart[0])]) && !in_array($codetouse, $longforshortexcep)) $srclang = $longforshort[strtolower($langpart[0])];
109
			elseif (!is_numeric($langpart[1])) {		// Second part YY may be a numeric with some Chrome browser
110
				$srclang = strtolower($langpart[0])."_".strtoupper($langpart[1]);
111
				$longforlong = array('no_nb'=>'nb_NO');
112
				if (isset($longforlong[strtolower($srclang)])) $srclang = $longforlong[strtolower($srclang)];
113
			} else $srclang = strtolower($langpart[0])."_".strtoupper($langpart[0]);
114
		} else {						// If it's for a codetouse that is a short code xx
115
    	    // Array to convert short lang code into long code.
116
	        $longforshort = array('ar'=>'ar_SA', 'el'=>'el_GR', 'ca'=>'ca_ES', 'en'=>'en_US', 'nb'=>'nb_NO', 'no'=>'nb_NO');
117
			if (isset($longforshort[strtolower($langpart[0])])) $srclang = $longforshort[strtolower($langpart[0])];
118
			elseif (!empty($langpart[0])) $srclang = strtolower($langpart[0])."_".strtoupper($langpart[0]);
119
			else $srclang = 'en_US';
120
		}
121
122
		$this->defaultlang = $srclang;
123
		$this->shortlang = substr($srclang, 0, 2);
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 (en, fr, es, ...)
133
	 *  @return string      		Language code used (en_US, en_AU, fr_FR, ...)
134
	 */
135
	public 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
	public 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
	public 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); // No translation was never 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
		$regs = array();
200
		if (preg_match('/^([^@]+)@([^@]+)$/i', $domain, $regs))
201
		{
202
			$newdomain = $regs[1];
203
			$modulename = $regs[2];
204
		}
205
206
        // Check cache
207
		if (!empty($this->_tab_loaded[$newdomain]))	// File already loaded for this domain
208
		{
209
			//dol_syslog("Translate::Load already loaded for newdomain=".$newdomain);
210
			return 0;
211
		}
212
213
        $fileread = 0;
214
		$langofdir = (empty($forcelangdir) ? $this->defaultlang : $forcelangdir);
215
216
		// Redefine alt
217
		$langarray = explode('_', $langofdir);
218
		if ($alt < 1 && isset($langarray[1]) && (strtolower($langarray[0]) == strtolower($langarray[1]) || in_array(strtolower($langofdir), array('el_gr')))) $alt = 1;
219
		if ($alt < 2 && strtolower($langofdir) == 'en_us') $alt = 2;
220
221
		if (empty($langofdir))	// This may occurs when load is called without setting the language and without providing a value for forcelangdir
222
		{
223
			dol_syslog("Error: ".get_class($this)."::load was called for domain=".$domain." but language was not set yet with langs->setDefaultLang(). Nothing will be loaded.", LOG_WARNING);
224
			return -1;
225
		}
226
227
		foreach ($this->dir as $searchdir)
228
		{
229
			// Directory of translation files
230
			$file_lang = $searchdir.($modulename ? '/'.$modulename : '')."/langs/".$langofdir."/".$newdomain.".lang";
231
			$file_lang_osencoded = dol_osencode($file_lang);
232
233
			$filelangexists = is_file($file_lang_osencoded);
234
235
			//dol_syslog(get_class($this).'::Load Try to read for alt='.$alt.' langofdir='.$langofdir.' domain='.$domain.' newdomain='.$newdomain.' modulename='.$modulename.' file_lang='.$file_lang." => filelangexists=".$filelangexists);
236
			//print 'Try to read for alt='.$alt.' langofdir='.$langofdir.' domain='.$domain.' newdomain='.$newdomain.' modulename='.$modulename.' this->_tab_loaded[newdomain]='.$this->_tab_loaded[$newdomain].' file_lang='.$file_lang." => filelangexists=".$filelangexists."\n";
237
238
			if ($filelangexists)
239
			{
240
				// TODO Move cache read out of loop on dirs or at least filelangexists
241
			    $found = false;
242
243
				// Enable caching of lang file in memory (not by default)
244
				$usecachekey = '';
245
				// Using a memcached server
246
				if (!empty($conf->memcached->enabled) && !empty($conf->global->MEMCACHED_SERVER))
247
				{
248
					$usecachekey = $newdomain.'_'.$langofdir.'_'.md5($file_lang); // Should not contains special chars
249
				}
250
				// Using cache with shmop. Speed gain: 40ms - Memory overusage: 200ko (Size of session cache file)
251
				elseif (isset($conf->global->MAIN_OPTIMIZE_SPEED) && ($conf->global->MAIN_OPTIMIZE_SPEED & 0x02))
252
				{
253
					$usecachekey = $newdomain;
254
				}
255
256
				if ($usecachekey)
257
				{
258
			        //dol_syslog('Translate::Load we will cache result into usecachekey '.$usecachekey);
259
                    //global $aaa; $aaa+=1;
260
                    //print $aaa." ".$usecachekey."\n";
261
				    require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
262
					$tmparray = dol_getcache($usecachekey);
263
					if (is_array($tmparray) && count($tmparray))
264
					{
265
				        $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.
266
						//print $newdomain."\n";
267
						//var_dump($this->tab_translate);
268
						if ($alt == 2) $fileread = 1;
269
						$found = true; // Found in dolibarr PHP cache
270
					}
271
				}
272
273
				if (!$found)
274
				{
275
					if ($fp = @fopen($file_lang, "rt"))
276
					{
277
						if ($usecachekey) $tabtranslatedomain = array(); // To save lang content in cache
278
279
						/**
280
						 * Read each lines until a '=' (with any combination of spaces around it)
281
						 * and split the rest until a line feed.
282
						 * This is more efficient than fgets + explode + trim by a factor of ~2.
283
						 */
284
						while ($line = fscanf($fp, "%[^= ]%*[ =]%[^\n\r]"))
285
						{
286
							if (isset($line[1]))
287
							{
288
								list($key, $value) = $line;
289
								//if ($domain == 'orders') print "Domain=$domain, found a string for $tab[0] with value $tab[1]. Currently in cache ".$this->tab_translate[$key]."<br>";
290
								//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>";
291
								if (empty($this->tab_translate[$key]))
292
								{ // 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)
293
									if ($key == 'DIRECTION') { // This is to declare direction of language
294
										if ($alt < 2 || empty($this->tab_translate[$key])) { // We load direction only for primary files or if not yet loaded
295
											$this->tab_translate[$key] = $value;
296
											if ($stopafterdirection) {
297
												break; // We do not save tab if we stop after DIRECTION
298
											} elseif ($usecachekey) {
299
												$tabtranslatedomain[$key] = $value;
300
											}
301
										}
302
									} elseif ($key[0] == '#')
303
									{
304
									    continue;
305
									} else {
306
										// Convert some strings: Parse and render carriage returns. Also, change '\\s' into '\s' because transifex sync pull the string '\s' into string '\\s'
307
										$this->tab_translate[$key] = str_replace(array('\\n', '\\\\s'), array("\n", '\s'), $value);
308
										if ($usecachekey) {
309
											$tabtranslatedomain[$key] = $value;
310
										} // To save lang content in cache
311
									}
312
								}
313
							}
314
						}
315
						fclose($fp);
316
						$fileread = 1;
317
318
						// TODO Move cache write out of loop on dirs
319
						// To save lang content for usecachekey into cache
320
						if ($usecachekey && count($tabtranslatedomain))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tabtranslatedomain does not seem to be defined for all execution paths leading up to this point.
Loading history...
321
						{
322
							$ressetcache = dol_setcache($usecachekey, $tabtranslatedomain);
323
							if ($ressetcache < 0)
324
							{
325
							    $error = 'Failed to set cache for usecachekey='.$usecachekey.' result='.$ressetcache;
326
							    dol_syslog($error, LOG_ERR);
327
							}
328
						}
329
330
						if (empty($conf->global->MAIN_FORCELANGDIR)) break; // Break loop on each root dir. If a module has forced dir, we do not stop loop.
331
					}
332
				}
333
			}
334
		}
335
336
		// Now we complete with next file (fr_CA->fr_FR, es_MX->ex_ES, ...)
337
		if ($alt == 0)
338
		{
339
			// This function MUST NOT contains call to syslog
340
			//dol_syslog("Translate::Load loading alternate translation file (to complete ".$this->defaultlang."/".$newdomain.".lang file)", LOG_DEBUG);
341
			$langofdir = strtolower($langarray[0]).'_'.strtoupper($langarray[0]);
342
			if ($langofdir == 'el_EL') $langofdir = 'el_GR'; // main parent for el_CY is not 'el_EL' but 'el_GR'
343
			if ($langofdir == 'ar_AR') $langofdir = 'ar_SA'; // main parent for ar_EG is not 'ar_AR' but 'ar_SA'
344
			$this->load($domain, $alt + 1, $stopafterdirection, $langofdir);
345
		}
346
347
		// Now we complete with reference file (en_US)
348
		if ($alt == 1)
349
		{
350
			// This function MUST NOT contains call to syslog
351
			//dol_syslog("Translate::Load loading alternate translation file (to complete ".$this->defaultlang."/".$newdomain.".lang file)", LOG_DEBUG);
352
			$langofdir = 'en_US';
353
			$this->load($domain, $alt + 1, $stopafterdirection, $langofdir);
354
		}
355
356
		// We are in the pass of the reference file. No more files to scan to complete.
357
		if ($alt == 2)
358
		{
359
			if ($fileread) $this->_tab_loaded[$newdomain] = 1; // Set domain file as found so loaded
360
361
			if (empty($this->_tab_loaded[$newdomain])) $this->_tab_loaded[$newdomain] = 2; // Set this file as not found
362
		}
363
364
		// This part is deprecated and replaced with table llx_overwrite_trans
365
		// Kept for backward compatibility.
366
		if (empty($loadfromfileonly))
367
		{
368
    		$overwritekey = 'MAIN_OVERWRITE_TRANS_'.$this->defaultlang;
369
            if (!empty($conf->global->$overwritekey))    // Overwrite translation with key1:newstring1,key2:newstring2
370
            {
371
        		// Overwrite translation with param MAIN_OVERWRITE_TRANS_xx_XX
372
                $tmparray = explode(',', $conf->global->$overwritekey);
373
                foreach ($tmparray as $tmp)
374
                {
375
                    $tmparray2 = explode(':', $tmp);
376
                    if (!empty($tmparray2[1])) $this->tab_translate[$tmparray2[0]] = $tmparray2[1];
377
                }
378
            }
379
		}
380
381
        // Check to be sure that SeparatorDecimal differs from SeparatorThousand
382
		if (!empty($this->tab_translate["SeparatorDecimal"]) && !empty($this->tab_translate["SeparatorThousand"])
383
		&& $this->tab_translate["SeparatorDecimal"] == $this->tab_translate["SeparatorThousand"]) $this->tab_translate["SeparatorThousand"] = '';
384
385
		return 1;
386
	}
387
388
	/**
389
	 *  Load translation key-value from database into a memory array.
390
	 *  If data already loaded, do nothing.
391
	 * 	All data in translation array are stored in UTF-8 format.
392
     *  tab_loaded is completed with $domain key.
393
     *  rule "we keep first entry found with we keep last entry found" so it is probably not what you want to do.
394
     *
395
     *  Value for hash are: 1:Loaded from disk, 2:Not found, 3:Loaded from cache
396
     *
397
     *  @param  Database    $db             Database handler
398
	 *	@return	int							<0 if KO, 0 if already loaded or loading not required, >0 if OK
399
	 */
400
	public function loadFromDatabase($db)
401
	{
402
		global $conf;
403
404
		$domain = 'database';
405
406
		// Check parameters
407
		if (empty($db)) return 0; // Database handler can't be used
408
409
		//dol_syslog("Translate::Load Start domain=".$domain." alt=".$alt." forcelangdir=".$forcelangdir." this->defaultlang=".$this->defaultlang);
410
411
		$newdomain = $domain;
412
413
		// Check cache
414
		if (!empty($this->_tab_loaded[$newdomain]))	// File already loaded for this domain 'database'
415
		{
416
			//dol_syslog("Translate::Load already loaded for newdomain=".$newdomain);
417
			return 0;
418
		}
419
420
		$this->_tab_loaded[$newdomain] = 1; // We want to be sure this function is called once only for domain 'database'
421
422
        $fileread = 0;
423
		$langofdir = $this->defaultlang;
424
425
		if (empty($langofdir))	// This may occurs when load is called without setting the language and without providing a value for forcelangdir
426
		{
427
			dol_syslog("Error: ".get_class($this)."::loadFromDatabase was called but language was not set yet with langs->setDefaultLang(). Nothing will be loaded.", LOG_WARNING);
428
			return -1;
429
		}
430
431
		// TODO Move cache read out of loop on dirs or at least filelangexists
432
		$found = false;
433
434
		// Enable caching of lang file in memory (not by default)
435
		$usecachekey = '';
436
		// Using a memcached server
437
		if (!empty($conf->memcached->enabled) && !empty($conf->global->MEMCACHED_SERVER))
438
		{
439
			$usecachekey = $newdomain.'_'.$langofdir; // Should not contains special chars
440
		}
441
		// Using cache with shmop. Speed gain: 40ms - Memory overusage: 200ko (Size of session cache file)
442
		elseif (isset($conf->global->MAIN_OPTIMIZE_SPEED) && ($conf->global->MAIN_OPTIMIZE_SPEED & 0x02))
443
		{
444
			$usecachekey = $newdomain;
445
		}
446
447
		if ($usecachekey)
448
		{
449
	        //dol_syslog('Translate::Load we will cache result into usecachekey '.$usecachekey);
450
            //global $aaa; $aaa+=1;
451
            //print $aaa." ".$usecachekey."\n";
452
		    require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
453
			$tmparray = dol_getcache($usecachekey);
454
			if (is_array($tmparray) && count($tmparray))
0 ignored issues
show
introduced by
The condition is_array($tmparray) is always false.
Loading history...
455
			{
456
				$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.
457
				//print $newdomain."\n";
458
				//var_dump($this->tab_translate);
459
				$fileread = 1;
460
				$found = true; // Found in dolibarr PHP cache
461
			}
462
		}
463
464
		if (!$found && !empty($conf->global->MAIN_ENABLE_OVERWRITE_TRANSLATION))
0 ignored issues
show
introduced by
The condition $found is always false.
Loading history...
465
		{
466
    		// Overwrite translation with database read
467
            $sql = "SELECT transkey, transvalue FROM ".MAIN_DB_PREFIX."overwrite_trans where lang='".$db->escape($this->defaultlang)."' OR lang IS NULL";
468
            $sql .= " AND entity IN (0, ".getEntity('overwrite_trans').")";
469
            $sql .= $db->order("lang", "DESC");
470
		    $resql = $db->query($sql);
471
472
		    if ($resql)
473
		    {
474
    		    $num = $db->num_rows($resql);
475
    		    if ($num)
476
    		    {
477
    				if ($usecachekey) $tabtranslatedomain = array(); // To save lang content in cache
478
479
    				$i = 0;
480
    				while ($i < $num)	// Ex: Need 225ms for all fgets on all lang file for Third party page. Same speed than file_get_contents
481
    				{
482
    				    $obj = $db->fetch_object($resql);
483
484
    				    $key = $obj->transkey;
485
    					$value = $obj->transvalue;
486
487
						//print "Domain=$domain, found a string for $tab[0] with value $tab[1]<br>";
488
						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)
489
						{
490
							// Convert some strings: Parse and render carriage returns. Also, change '\\s' int '\s' because transifex sync pull the string '\s' into string '\\s'
491
							$this->tab_translate[$key] = str_replace(array('\\n', '\\\\s'), array("\n", '\s'), $value);
492
493
							if ($usecachekey) $tabtranslatedomain[$key] = $value; // To save lang content in cache
494
						}
495
496
    					$i++;
497
    				}
498
499
    				$fileread = 1;
500
501
    				// TODO Move cache write out of loop on dirs
502
    				// To save lang content for usecachekey into cache
503
    				if ($usecachekey && count($tabtranslatedomain))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tabtranslatedomain does not seem to be defined for all execution paths leading up to this point.
Loading history...
504
    				{
505
    					$ressetcache = dol_setcache($usecachekey, $tabtranslatedomain);
506
    					if ($ressetcache < 0)
507
    					{
508
    					    $error = 'Failed to set cache for usecachekey='.$usecachekey.' result='.$ressetcache;
509
    					    dol_syslog($error, LOG_ERR);
510
    					}
511
    				}
512
    			}
513
		    } else {
514
		        dol_print_error($db);
515
		    }
516
		}
517
518
		if ($fileread) $this->_tab_loaded[$newdomain] = 1; // Set domain file as loaded
519
520
		if (empty($this->_tab_loaded[$newdomain])) $this->_tab_loaded[$newdomain] = 2; // Mark this case as not found (no lines found for language)
521
522
		return 1;
523
	}
524
525
	/**
526
	 * Get information with result of loading data for domain
527
	 *
528
	 * @param	string		$domain		Domain to check
529
	 * @return 	int						0, 1, 2...
530
	 */
531
	public function isLoaded($domain)
532
	{
533
		return $this->_tab_loaded[$domain];
534
	}
535
536
	/**
537
	 * Return translated value of key for special keys ("Currency...", "Civility...", ...).
538
	 * Search in lang file, then into database. Key must be any complete entry into lang file: CurrencyEUR, ...
539
	 * If not found, return key.
540
	 * The string return is not formated (translated with transnoentitiesnoconv)
541
	 * NOTE: To avoid infinite loop (getLabelFromKey->transnoentities->getTradFromKey), if you modify this function,
542
	 * check that getLabelFromKey is not called with same value than input.
543
	 *
544
	 * @param	string		$key		Key to translate
545
	 * @return 	string					Translated string (translated with transnoentitiesnoconv)
546
	 */
547
    private function getTradFromKey($key)
548
    {
549
		global $conf, $db;
550
551
		if (!is_string($key)) {
552
			//xdebug_print_function_stack('ErrorBadValueForParamNotAString');
553
			return 'ErrorBadValueForParamNotAString'; // Avoid multiple errors with code not using function correctly.
554
		}
555
556
		$newstr = $key;
557
	    if (preg_match('/^Civility([0-9A-Z]+)$/i', $key, $reg))
558
        {
559
            $newstr = $this->getLabelFromKey($db, $reg[1], 'c_civility', 'code', 'label');
560
        } elseif (preg_match('/^Currency([A-Z][A-Z][A-Z])$/i', $key, $reg))
561
		{
562
			$newstr = $this->getLabelFromKey($db, $reg[1], 'c_currencies', 'code_iso', 'label');
563
		} elseif (preg_match('/^SendingMethod([0-9A-Z]+)$/i', $key, $reg))
564
		{
565
			$newstr = $this->getLabelFromKey($db, $reg[1], 'c_shipment_mode', 'code', 'libelle');
566
		} elseif (preg_match('/^PaymentTypeShort([0-9A-Z]+)$/i', $key, $reg))
567
        {
568
            $newstr = $this->getLabelFromKey($db, $reg[1], 'c_paiement', 'code', 'libelle', '', 1);
569
        } elseif (preg_match('/^OppStatus([0-9A-Z]+)$/i', $key, $reg))
570
        {
571
            $newstr = $this->getLabelFromKey($db, $reg[1], 'c_lead_status', 'code', 'label');
572
        } elseif (preg_match('/^OrderSource([0-9A-Z]+)$/i', $key, $reg))
573
        {
574
        	// TODO OrderSourceX must be replaced with content of table llx_c_input_reason or llx_c_input_method
575
            //$newstr=$this->getLabelFromKey($db,$reg[1],'c_ordersource','code','label');
576
        }
577
578
        /* Disabled. There is too many cases where translation of $newstr is not defined is normal (like when output with setEventMessage an already translated string)
579
        if (! empty($conf->global->MAIN_FEATURES_LEVEL) && $conf->global->MAIN_FEATURES_LEVEL >= 2)
580
        {
581
        	dol_syslog(__METHOD__." MAIN_FEATURES_LEVEL=DEVELOP: missing translation for key '".$newstr."' in ".$_SERVER["PHP_SELF"], LOG_DEBUG);
582
        }*/
583
584
        return $newstr;
585
    }
586
587
588
	/**
589
	 *  Return text translated of text received as parameter (and encode it into HTML)
590
	 *              If there is no match for this text, we look in alternative file and if still not found,
591
	 * 				it is returned as it is
592
	 *              The parameters of this method can contain HTML tags
593
	 *
594
	 *  @param	string	$key        Key to translate
595
	 *  @param  string	$param1     param1 string
596
	 *  @param  string	$param2     param2 string
597
	 *  @param  string	$param3     param3 string
598
	 *  @param  string	$param4     param4 string
599
	 *	@param	int		$maxsize	Max length of text
600
	 *  @return string      		Translated string (encoded into HTML entities and UTF8)
601
	 */
602
    public function trans($key, $param1 = '', $param2 = '', $param3 = '', $param4 = '', $maxsize = 0)
603
    {
604
        global $conf;
605
606
	    if (!empty($this->tab_translate[$key]))	// Translation is available
607
		{
608
            $str = $this->tab_translate[$key];
609
610
    		// Make some string replacement after translation
611
            $replacekey = 'MAIN_REPLACE_TRANS_'.$this->defaultlang;
612
            if (!empty($conf->global->$replacekey))    // Replacement translation variable with string1:newstring1;string2:newstring2
613
            {
614
                $tmparray = explode(';', $conf->global->$replacekey);
615
                foreach ($tmparray as $tmp)
616
                {
617
                    $tmparray2 = explode(':', $tmp);
618
                    $str = preg_replace('/'.preg_quote($tmparray2[0]).'/', $tmparray2[1], $str);
619
                }
620
            }
621
622
            if (strpos($key, 'Format') !== 0)
623
            {
624
            	$str = sprintf($str, $param1, $param2, $param3, $param4); // Replace %s and %d except for FormatXXX strings.
625
            }
626
627
			if ($maxsize) $str = dol_trunc($str, $maxsize);
628
629
			// We replace some HTML tags by __xx__ to avoid having them encoded by htmlentities
630
            $str = str_replace(array('<', '>', '"',), array('__lt__', '__gt__', '__quot__'), $str);
631
632
			// Crypt string into HTML
633
			$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
634
635
			// Restore HTML tags
636
            $str = str_replace(array('__lt__', '__gt__', '__quot__'), array('<', '>', '"',), $str);
637
638
			return $str;
639
		} else // Translation is not available
640
		{
641
		    //if ($key[0] == '$') { return dol_eval($key,1); }
642
			return $this->getTradFromKey($key);
643
		}
644
    }
645
646
647
	/**
648
	 *  Return translated value of a text string
649
	 *               If there is no match for this text, we look in alternative file and if still not found
650
	 *               it is returned as is.
651
	 *               Parameters of this method must not contain any HTML tags.
652
	 *
653
	 *  @param	string	$key        Key to translate
654
	 *  @param  string	$param1     chaine de param1
655
	 *  @param  string	$param2     chaine de param2
656
	 *  @param  string	$param3     chaine de param3
657
	 *  @param  string	$param4     chaine de param4
658
	 *  @param  string	$param5     chaine de param5
659
	 *  @return string      		Translated string (encoded into UTF8)
660
	 */
661
	public function transnoentities($key, $param1 = '', $param2 = '', $param3 = '', $param4 = '', $param5 = '')
662
	{
663
		return $this->convToOutputCharset($this->transnoentitiesnoconv($key, $param1, $param2, $param3, $param4, $param5));
664
	}
665
666
667
	/**
668
	 *  Return translated value of a text string
669
	 * 				 If there is no match for this text, we look in alternative file and if still not found,
670
	 * 				 it is returned as is.
671
	 *               No conversion to encoding charset of lang object is done.
672
	 *               Parameters of this method must not contains any HTML tags.
673
	 *
674
	 *  @param	string	$key        Key to translate
675
	 *  @param  string	$param1     chaine de param1
676
	 *  @param  string	$param2     chaine de param2
677
	 *  @param  string	$param3     chaine de param3
678
	 *  @param  string	$param4     chaine de param4
679
	 *  @param  string	$param5     chaine de param5
680
	 *  @return string      		Translated string
681
	 */
682
	public function transnoentitiesnoconv($key, $param1 = '', $param2 = '', $param3 = '', $param4 = '', $param5 = '')
683
	{
684
		global $conf;
685
686
		if (!empty($this->tab_translate[$key]))	// Translation is available
687
		{
688
		    $str = $this->tab_translate[$key];
689
690
    		// Make some string replacement after translation
691
            $replacekey = 'MAIN_REPLACE_TRANS_'.$this->defaultlang;
692
            if (!empty($conf->global->$replacekey))    // Replacement translation variable with string1:newstring1;string2:newstring2
693
            {
694
                $tmparray = explode(';', $conf->global->$replacekey);
695
                foreach ($tmparray as $tmp)
696
                {
697
                    $tmparray2 = explode(':', $tmp);
698
                    $str = preg_replace('/'.preg_quote($tmparray2[0]).'/', $tmparray2[1], $str);
699
                }
700
            }
701
702
            if (!preg_match('/^Format/', $key))
703
            {
704
            	//print $str;
705
           		$str = sprintf($str, $param1, $param2, $param3, $param4, $param5); // Replace %s and %d except for FormatXXX strings.
706
            }
707
708
            return $str;
709
		} else {
710
		    if ($key[0] == '$') { return dol_eval($key, 1); }
711
			return $this->getTradFromKey($key);
712
		}
713
	}
714
715
716
	/**
717
	 *  Return translation of a key depending on country
718
	 *
719
	 *  @param	string	$str            string root to translate
720
	 *  @param  string	$countrycode    country code (FR, ...)
721
	 *  @return	string         			translated string
722
	 */
723
	public function transcountry($str, $countrycode)
724
	{
725
		if ($this->tab_translate["$str$countrycode"]) return $this->trans("$str$countrycode");
726
		else return $this->trans($str);
727
	}
728
729
730
	/**
731
	 *  Retourne la version traduite du texte passe en parametre complete du code pays
732
	 *
733
	 *  @param	string	$str            string root to translate
734
	 *  @param  string	$countrycode    country code (FR, ...)
735
	 *  @return string         			translated string
736
	 */
737
	public function transcountrynoentities($str, $countrycode)
738
	{
739
		if ($this->tab_translate["$str$countrycode"]) return $this->transnoentities("$str$countrycode");
740
		else return $this->transnoentities($str);
741
	}
742
743
744
	/**
745
	 *  Convert a string into output charset (this->charset_output that should be defined to conf->file->character_set_client)
746
	 *
747
	 *  @param	string	$str            String to convert
748
	 *  @param	string	$pagecodefrom	Page code of src string
749
	 *  @return string         			Converted string
750
	 */
751
	public function convToOutputCharset($str, $pagecodefrom = 'UTF-8')
752
	{
753
		if ($pagecodefrom == 'ISO-8859-1' && $this->charset_output == 'UTF-8')  $str = utf8_encode($str);
754
		if ($pagecodefrom == 'UTF-8' && $this->charset_output == 'ISO-8859-1')	$str = utf8_decode(str_replace('€', chr(128), $str));
755
		return $str;
756
	}
757
758
759
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
760
	/**
761
	 *  Return list of all available languages
762
	 *
763
	 * 	@param	string	$langdir		Directory to scan
764
	 *  @param  integer	$maxlength   	Max length for each value in combo box (will be truncated)
765
	 *  @param	int		$usecode		1=Show code instead of country name for language variant, 2=Show only code
766
	 *  @param	int		$mainlangonly   1=Show only main languages ('fr_FR' no' fr_BE', 'es_ES' not 'es_MX', ...)
767
	 *  @return array     				List of languages
768
	 */
769
	public function get_available_languages($langdir = DOL_DOCUMENT_ROOT, $maxlength = 0, $usecode = 0, $mainlangonly = 0)
770
    {
771
        // phpcs:enable
772
		global $conf;
773
774
		$this->load("languages");
775
776
		// We scan directory langs to detect available languages
777
		$handle = opendir($langdir."/langs");
778
		$langs_available = array();
779
		while ($dir = trim(readdir($handle)))
780
		{
781
			$regs = array();
782
			if (preg_match('/^([a-z]+)_([A-Z]+)/i', $dir, $regs))
783
			{
784
				// We must keep only main languages
785
				if ($mainlangonly) {
786
					$arrayofspecialmainlanguages = array(
787
						'en'=>'en_US',
788
						'sq'=>'sq_AL',
789
						'ar'=>'ar_SA',
790
						'eu'=>'eu_ES',
791
						'bn'=>'bn_DB',
792
						'bs'=>'bs_BA',
793
						'ca'=>'ca_ES',
794
						'zh'=>'zh_TW',
795
						'cs'=>'cs_CZ',
796
						'da'=>'da_DK',
797
						'et'=>'et_EE',
798
						'ka'=>'ka_GE',
799
						'el'=>'el_GR',
800
						'he'=>'he_IL',
801
						'kn'=>'kn_IN',
802
						'km'=>'km_KH',
803
						'ko'=>'ko_KR',
804
						'lo'=>'lo_LA',
805
						'nb'=>'nb_NO',
806
						'fa'=>'fa_IR',
807
						'sr'=>'sr_RS',
808
						'sl'=>'sl_SI',
809
						'uk'=>'uk_UA',
810
						'vi'=>'vi_VN'
811
					);
812
					if (strtolower($regs[1]) != strtolower($regs[2]) && !in_array($dir, $arrayofspecialmainlanguages)) continue;
813
				}
814
				// We must keep only languages into MAIN_LANGUAGES_ALLOWED
815
				if (!empty($conf->global->MAIN_LANGUAGES_ALLOWED) && !in_array($dir, explode(',', $conf->global->MAIN_LANGUAGES_ALLOWED))) continue;
816
817
				if ($usecode == 2)
818
				{
819
				    $langs_available[$dir] = $dir;
820
				}
821
822
				if ($usecode == 1 || !empty($conf->global->MAIN_SHOW_LANGUAGE_CODE))
823
				{
824
				    $langs_available[$dir] = $dir.': '.dol_trunc($this->trans('Language_'.$dir), $maxlength);
825
				} else {
826
					$langs_available[$dir] = $this->trans('Language_'.$dir);
827
				}
828
				if ($mainlangonly) {
829
					$langs_available[$dir] = str_replace(' (United States)', '', $langs_available[$dir]);
830
				}
831
			}
832
		}
833
		return $langs_available;
834
    }
835
836
837
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
838
	/**
839
	 *  Return if a filename $filename exists for current language (or alternate language)
840
	 *
841
	 *  @param	string	$filename       Language filename to search
842
	 *  @param  integer	$searchalt      Search also alernate language file
843
	 *  @return boolean         		true if exists and readable
844
	 */
845
    public function file_exists($filename, $searchalt = 0)
846
    {
847
        // phpcs:enable
848
		// Test si fichier dans repertoire de la langue
849
		foreach ($this->dir as $searchdir)
850
		{
851
			if (is_readable(dol_osencode($searchdir."/langs/".$this->defaultlang."/".$filename))) return true;
852
853
			if ($searchalt)
854
			{
855
				// Test si fichier dans repertoire de la langue alternative
856
				if ($this->defaultlang != "en_US") $filenamealt = $searchdir."/langs/en_US/".$filename;
857
				//else $filenamealt = $searchdir."/langs/fr_FR/".$filename;
858
				if (is_readable(dol_osencode($filenamealt))) return true;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $filenamealt does not seem to be defined for all execution paths leading up to this point.
Loading history...
859
			}
860
		}
861
862
		return false;
863
    }
864
865
866
	/**
867
	 *      Return full text translated to language label for a key. Store key-label in a cache.
868
     *      This function need module "numberwords" to be installed. If not it will return
869
     *      same number (this module is not provided by default as it use non GPL source code).
870
	 *
871
	 *		@param	int		$number		Number to encode in full text
872
     *      @param  string	$isamount	''=it's just a number, '1'=It's an amount (default currency), 'currencycode'=It's an amount (foreign currency)
873
	 *      @return string				Label translated in UTF8 (but without entities)
874
	 * 									10 if setDefaultLang was en_US => ten
875
	 * 									123 if setDefaultLang was fr_FR => cent vingt trois
876
	 */
877
    public function getLabelFromNumber($number, $isamount = '')
878
    {
879
		global $conf;
880
881
		$newnumber = $number;
882
883
		$dirsubstitutions = array_merge(array(), $conf->modules_parts['substitutions']);
884
		foreach ($dirsubstitutions as $reldir)
885
		{
886
		    $dir = dol_buildpath($reldir, 0);
887
		    $newdir = dol_osencode($dir);
888
889
		    // Check if directory exists
890
		    if (!is_dir($newdir)) continue; // We must not use dol_is_dir here, function may not be loaded
891
892
			$fonc = 'numberwords';
893
			if (file_exists($newdir.'/functions_'.$fonc.'.lib.php'))
894
			{
895
				include_once $newdir.'/functions_'.$fonc.'.lib.php';
896
				$newnumber = numberwords_getLabelFromNumber($this, $number, $isamount);
0 ignored issues
show
Bug introduced by
The function numberwords_getLabelFromNumber was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

896
				$newnumber = /** @scrutinizer ignore-call */ numberwords_getLabelFromNumber($this, $number, $isamount);
Loading history...
897
				break;
898
			}
899
		}
900
901
		return $newnumber;
902
    }
903
904
905
	/**
906
	 *      Return a label for a key.
907
	 *      Search into translation array, then into cache, then if still not found, search into database.
908
	 *      Store key-label found into cache variable $this->cache_labels to save SQL requests to get labels.
909
	 *
910
	 * 		@param	DoliDB	$db				Database handler
911
	 * 		@param	string	$key			Translation key to get label (key in language file)
912
	 * 		@param	string	$tablename		Table name without prefix
913
	 * 		@param	string	$fieldkey		Field for key
914
	 * 		@param	string	$fieldlabel		Field for label
915
	 *      @param	string	$keyforselect	Use another value than the translation key for the where into select
916
	 *      @param  int		$filteronentity	Use a filter on entity
917
	 *      @return string					Label in UTF8 (but without entities)
918
	 *      @see dol_getIdFromCode()
919
	 */
920
    public function getLabelFromKey($db, $key, $tablename, $fieldkey, $fieldlabel, $keyforselect = '', $filteronentity = 0)
921
    {
922
		// If key empty
923
		if ($key == '') return '';
924
925
        //print 'param: '.$key.'-'.$keydatabase.'-'.$this->trans($key); exit;
926
927
		// Check if a translation is available (this can call getTradFromKey)
928
		$tmp = $this->transnoentitiesnoconv($key);
929
		if ($tmp != $key && $tmp != 'ErrorBadValueForParamNotAString')
930
		{
931
			return $tmp; // Found in language array
932
		}
933
934
		// Check in cache
935
		if (isset($this->cache_labels[$tablename][$key]))	// Can be defined to 0 or ''
936
		{
937
			return $this->cache_labels[$tablename][$key]; // Found in cache
938
		}
939
940
		$sql = "SELECT ".$fieldlabel." as label";
941
		$sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
942
		$sql .= " WHERE ".$fieldkey." = '".$db->escape($keyforselect ? $keyforselect : $key)."'";
943
		if ($filteronentity) $sql .= " AND entity IN (".getEntity($tablename).')';
944
		dol_syslog(get_class($this).'::getLabelFromKey', LOG_DEBUG);
945
		$resql = $db->query($sql);
946
		if ($resql)
947
		{
948
			$obj = $db->fetch_object($resql);
949
			if ($obj) $this->cache_labels[$tablename][$key] = $obj->label;
950
			else $this->cache_labels[$tablename][$key] = $key;
951
952
			$db->free($resql);
953
			return $this->cache_labels[$tablename][$key];
954
		} else {
955
			$this->error = $db->lasterror();
956
			return -1;
957
		}
958
    }
959
960
961
	/**
962
	 *	Return a currency code into its symbol
963
	 *
964
	 *  @param	string	$currency_code		Currency Code
965
	 *  @param	string	$amount				If not '', show currency + amount according to langs ($10, 10€).
966
	 *  @return	string						Amount + Currency symbol encoded into UTF8
967
	 *  @deprecated							Use method price to output a price
968
	 *  @see price()
969
	 */
970
    public function getCurrencyAmount($currency_code, $amount)
971
	{
972
		$symbol = $this->getCurrencySymbol($currency_code);
973
974
		if (in_array($currency_code, array('USD'))) return $symbol.$amount;
975
		else return $amount.$symbol;
976
	}
977
978
	/**
979
	 *	Return a currency code into its symbol.
980
	 *  If mb_convert_encoding is not available, return currency code.
981
	 *
982
	 *  @param	string	$currency_code		Currency code
983
	 *  @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 the requested currency.
984
	 *  @return	string						Currency symbol encoded into UTF8
985
	 */
986
    public function getCurrencySymbol($currency_code, $forceloadall = 0)
987
    {
988
		$currency_sign = ''; // By default return iso code
989
990
		if (function_exists("mb_convert_encoding"))
991
		{
992
			$this->loadCacheCurrencies($forceloadall ? '' : $currency_code);
993
994
			if (isset($this->cache_currencies[$currency_code]) && !empty($this->cache_currencies[$currency_code]['unicode']) && is_array($this->cache_currencies[$currency_code]['unicode']))
995
			{
996
				foreach ($this->cache_currencies[$currency_code]['unicode'] as $unicode)
997
				{
998
					$currency_sign .= mb_convert_encoding("&#{$unicode};", "UTF-8", 'HTML-ENTITIES');
999
				}
1000
			}
1001
		}
1002
1003
		return ($currency_sign ? $currency_sign : $currency_code);
1004
    }
1005
1006
	/**
1007
	 *  Load into the cache this->cache_currencies, all currencies
1008
	 *
1009
	 *	@param	string	$currency_code		Get only currency. Get all if ''.
1010
	 *  @return int             			Nb of loaded lines, 0 if already loaded, <0 if KO
1011
	 */
1012
	public function loadCacheCurrencies($currency_code)
1013
	{
1014
		global $db;
1015
1016
		if ($this->cache_currencies_all_loaded) return 0; // Cache already loaded for all
1017
		if (!empty($currency_code) && isset($this->cache_currencies[$currency_code])) return 0; // Cache already loaded for the currency
1018
1019
		$sql = "SELECT code_iso, label, unicode";
1020
		$sql .= " FROM ".MAIN_DB_PREFIX."c_currencies";
1021
		$sql .= " WHERE active = 1";
1022
		if (!empty($currency_code)) $sql .= " AND code_iso = '".$db->escape($currency_code)."'";
1023
		//$sql.= " ORDER BY code_iso ASC"; // Not required, a sort is done later
1024
1025
		dol_syslog(get_class($this).'::loadCacheCurrencies', LOG_DEBUG);
1026
		$resql = $db->query($sql);
1027
		if ($resql)
1028
		{
1029
			$this->load("dict");
1030
			$label = array();
1031
			if (!empty($currency_code)) foreach ($this->cache_currencies as $key => $val) $label[$key] = $val['label']; // Label in already loaded cache
1032
1033
			$num = $db->num_rows($resql);
1034
			$i = 0;
1035
			while ($i < $num)
1036
			{
1037
				$obj = $db->fetch_object($resql);
1038
1039
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1040
				$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 : ''));
1041
				$this->cache_currencies[$obj->code_iso]['unicode'] = (array) json_decode($obj->unicode, true);
1042
				$label[$obj->code_iso] = $this->cache_currencies[$obj->code_iso]['label'];
1043
				$i++;
1044
			}
1045
			if (empty($currency_code)) $this->cache_currencies_all_loaded = true;
1046
			//print count($label).' '.count($this->cache_currencies);
1047
1048
			// Resort cache
1049
			array_multisort($label, SORT_ASC, $this->cache_currencies);
1050
			//var_dump($this->cache_currencies);	$this->cache_currencies is now sorted onto label
1051
			return $num;
1052
		} else {
1053
			dol_print_error($db);
1054
			return -1;
1055
		}
1056
	}
1057
1058
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1059
	/**
1060
	 * Return an array with content of all loaded translation keys (found into this->tab_translate) so
1061
	 * we get a substitution array we can use for substitutions (for mail or ODT generation for example)
1062
	 *
1063
	 * @return array	Array of translation keys lang_key => string_translation_loaded
1064
	 */
1065
    public function get_translations_for_substitutions()
1066
    {
1067
        // phpcs:enable
1068
        $substitutionarray = array();
1069
1070
        foreach ($this->tab_translate as $code => $label) {
1071
            $substitutionarray['lang_'.$code] = $label;
1072
            $substitutionarray['__('.$code.')__'] = $label;
1073
        }
1074
1075
        return $substitutionarray;
1076
    }
1077
}
1078