2003-05-02 12:33:06 +02:00
< ? php
2010-04-19 11:34:50 +02:00
/* Copyright ( C ) 2001 Eric Seigne < erics @ rycks . com >
2015-10-13 13:27:44 +02:00
* Copyright ( C ) 2004 - 2015 Destailleur Laurent < eldy @ users . sourceforge . net >
2018-10-27 14:43:12 +02:00
* Copyright ( C ) 2005 - 2010 Regis Houssin < regis . houssin @ inodbox . com >
2024-01-23 12:07:40 +01:00
* Copyright ( C ) 2024 MDW < mdeweerd @ users . noreply . github . com >
2024-11-04 23:53:20 +01:00
* Copyright ( C ) 2024 Frédéric France < frederic . france @ free . fr >
2003-05-02 12:33:06 +02:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
2013-01-16 15:36:08 +01:00
* the Free Software Foundation ; either version 3 of the License , or
2003-05-02 12:33:06 +02:00
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2019-09-23 21:55:30 +02:00
* along with this program . If not , see < https :// www . gnu . org / licenses />.
2010-04-19 11:34:50 +02:00
*/
2003-05-02 12:33:06 +02:00
2005-01-02 17:57:37 +01:00
/**
2010-06-08 01:52:43 +02:00
* \file htdocs / core / class / translate . class . php
2010-11-22 10:18:53 +01:00
* \ingroup core
2024-01-13 19:48:20 +01:00
* \brief File for Translate class
2008-08-07 08:33:35 +02:00
*/
2004-08-15 20:09:30 +02:00
2008-01-21 03:19:25 +01:00
/**
2012-01-27 16:10:44 +01:00
* Class to manage translations
2008-08-07 08:33:35 +02:00
*/
2012-01-14 14:27:27 +01:00
class Translate
{
2024-01-29 22:59:31 +01:00
/**
2024-02-28 22:56:00 +01:00
* @ var string [] Directory containing the / langs subdirectory
2024-01-29 22:59:31 +01:00
*/
public $dir ;
2008-03-31 17:17:39 +02:00
2024-01-29 22:59:31 +01:00
/**
* @ var string Current language for current user
*/
public $defaultlang ;
2005-02-06 19:41:45 +01:00
2024-01-29 22:59:31 +01:00
/**
* @ var string Short language code for current user
*/
public $shortlang ;
/**
* @ var string Codage used by " trans " method outputs
*/
public $charset_output = 'UTF-8' ;
2009-01-15 23:49:06 +01:00
2024-01-29 22:59:31 +01:00
/**
2024-10-29 22:44:47 +01:00
* @ var array < string , string > Array of all translations key => value
2024-01-29 22:59:31 +01:00
*/
public $tab_translate = array ();
/**
2024-10-29 22:44:47 +01:00
* @ var array < string , int < 1 , 2 >> Array to store result after loading each language file
2024-01-29 22:59:31 +01:00
*/
private $_tab_loaded = array ();
/**
2024-10-29 22:44:47 +01:00
* @ var array < string , array < string , string >> Cache for labels returned by getLabelFromKey method
2024-01-29 22:59:31 +01:00
*/
public $cache_labels = array ();
/**
2024-10-29 22:44:47 +01:00
* @ var array < string , array { label : string , unicode : string } > Cache to store currency symbols
2024-01-29 22:59:31 +01:00
*/
public $cache_currencies = array ();
/**
* @ var bool True if all currencies have been loaded in this -> cache_currencies
* @ see $cache_currencies
*/
2020-10-31 14:32:18 +01:00
private $cache_currencies_all_loaded = false ;
2024-01-29 22:59:31 +01:00
/**
* @ var string Language to use
*/
2023-02-22 22:17:39 +01:00
public $origlang ;
2024-01-29 22:59:31 +01:00
/**
* @ var string Error message
* @ see $errors
*/
2023-02-22 22:17:39 +01:00
public $error ;
2024-01-29 22:59:31 +01:00
/**
* @ var string [] Array of error messages
*/
2023-02-22 22:17:39 +01:00
public $errors = array ();
2009-01-15 23:49:06 +01:00
2003-05-02 12:33:06 +02:00
2009-05-11 18:26:54 +02:00
/**
2011-09-11 20:35:38 +02:00
* Constructor
2011-08-16 01:17:14 +02:00
*
2017-12-13 23:37:34 +01:00
* @ param string $dir Force directory that contains / langs subdirectory ( value is sometimes '..' like into install /* pages or support /* pages ) . Use '' by default .
2011-12-07 17:28:11 +01:00
* @ param Conf $conf Object with Dolibarr configuration
2009-05-11 18:26:54 +02:00
*/
2019-02-26 22:42:19 +01:00
public function __construct ( $dir , $conf )
2009-05-11 18:26:54 +02:00
{
2021-02-23 22:03:23 +01:00
if ( ! empty ( $conf -> file -> character_set_client )) {
$this -> charset_output = $conf -> file -> character_set_client ; // If charset output is forced
}
if ( $dir ) {
$this -> dir = array ( $dir );
} else {
$this -> dir = $conf -> file -> dol_document_root ;
}
2009-05-11 18:26:54 +02:00
}
2005-10-30 02:07:00 +01:00
2009-05-11 18:26:54 +02:00
/**
2011-01-30 14:35:00 +01:00
* Set accessor for this -> defaultlang
2011-08-16 01:17:14 +02:00
*
2013-02-24 02:42:37 +01:00
* @ param string $srclang Language to use . If '' or 'auto' , we use browser lang .
2012-01-14 14:27:27 +01:00
* @ return void
2009-05-11 18:26:54 +02:00
*/
2019-02-26 22:42:19 +01:00
public function setDefaultLang ( $srclang = 'en_US' )
2009-05-11 18:26:54 +02:00
{
2011-01-30 14:35:00 +01:00
global $conf ;
2011-03-08 16:14:42 +01:00
2012-01-14 14:27:27 +01:00
//dol_syslog(get_class($this)."::setDefaultLang srclang=".$srclang,LOG_DEBUG);
2009-05-11 18:26:54 +02:00
2011-01-30 14:35:00 +01:00
// If a module ask to force a priority on langs directories (to use its own lang files)
2023-11-27 11:24:19 +01:00
if ( getDolGlobalString ( 'MAIN_FORCELANGDIR' )) {
2020-01-16 02:54:00 +01:00
$more = array ();
$i = 0 ;
2021-02-23 22:03:23 +01:00
foreach ( $conf -> file -> dol_document_root as $dir ) {
2023-10-15 15:32:35 +02:00
$newdir = $dir . getDolGlobalString ( 'MAIN_FORCELANGDIR' ); // For example $conf->global->MAIN_FORCELANGDIR is '/mymodule' meaning we search files into '/mymodule/langs/xx_XX'
2021-02-23 22:03:23 +01:00
if ( ! in_array ( $newdir , $this -> dir )) {
2023-07-12 16:32:50 +02:00
$more [ 'module_' . $i ] = $newdir ;
2021-03-01 20:37:16 +01:00
$i ++ ; // We add the forced dir into the array $more. Just after, we add entries into $more to list of lang dir $this->dir.
2011-08-16 01:17:14 +02:00
}
2011-01-30 14:35:00 +01:00
}
2020-01-16 02:54:00 +01:00
$this -> dir = array_merge ( $more , $this -> dir ); // Forced dir ($more) are before standard dirs ($this->dir)
2011-01-30 14:35:00 +01:00
}
2011-03-08 16:14:42 +01:00
2020-01-16 02:54:00 +01:00
$this -> origlang = $srclang ;
2009-05-11 18:26:54 +02:00
2021-02-23 22:03:23 +01:00
if ( empty ( $srclang ) || $srclang == 'auto' ) {
2019-09-24 13:54:52 +02:00
// $_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
2020-01-16 02:54:00 +01:00
$langpref = empty ( $_SERVER [ 'HTTP_ACCEPT_LANGUAGE' ]) ? '' : $_SERVER [ 'HTTP_ACCEPT_LANGUAGE' ];
$langpref = preg_replace ( " /;([^,]*)/i " , " " , $langpref ); // Remove the 'q=x.y,' part
$langpref = str_replace ( " - " , " _ " , $langpref );
$langlist = preg_split ( " /[;,]/ " , $langpref );
$codetouse = preg_replace ( '/[^_a-zA-Z]/' , '' , $langlist [ 0 ]);
2021-02-23 22:03:23 +01:00
} else {
$codetouse = $srclang ;
}
2011-03-30 17:53:51 +02:00
2009-08-12 19:40:47 +02:00
// We redefine $srclang
2020-01-16 02:54:00 +01:00
$langpart = explode ( " _ " , $codetouse );
2017-11-19 21:22:14 +01:00
//print "Short code before _ : ".$langpart[0].' / Short code after _ : '.$langpart[1].'<br>';
2021-02-23 22:03:23 +01:00
if ( ! empty ( $langpart [ 1 ])) { // If it's for a codetouse that is a long code xx_YY
2011-03-31 17:11:53 +02:00
// Array force long code from first part, even if long code is defined
2023-07-12 16:32:50 +02:00
$longforshort = array ( 'ar' => 'ar_SA' );
2020-01-16 02:54:00 +01:00
$longforshortexcep = array ( 'ar_EG' );
2021-02-23 22:03:23 +01:00
if ( isset ( $longforshort [ strtolower ( $langpart [ 0 ])]) && ! in_array ( $codetouse , $longforshortexcep )) {
$srclang = $longforshort [ strtolower ( $langpart [ 0 ])];
} elseif ( ! is_numeric ( $langpart [ 1 ])) { // Second part YY may be a numeric with some Chrome browser
2023-07-12 16:32:50 +02:00
$srclang = strtolower ( $langpart [ 0 ]) . " _ " . strtoupper ( $langpart [ 1 ]);
$longforlong = array ( 'no_nb' => 'nb_NO' );
2021-02-23 22:03:23 +01:00
if ( isset ( $longforlong [ strtolower ( $srclang )])) {
$srclang = $longforlong [ strtolower ( $srclang )];
}
} else {
2023-07-12 16:32:50 +02:00
$srclang = strtolower ( $langpart [ 0 ]) . " _ " . strtoupper ( $langpart [ 0 ]);
2021-02-23 22:03:23 +01:00
}
2020-05-21 15:05:19 +02:00
} else { // If it's for a codetouse that is a short code xx
2020-10-31 14:32:18 +01:00
// Array to convert short lang code into long code.
2021-02-10 03:20:50 +01:00
$longforshort = array (
2023-07-12 16:32:50 +02:00
'am' => 'am_ET' , 'ar' => 'ar_SA' , 'bn' => 'bn_DB' , 'el' => 'el_GR' , 'ca' => 'ca_ES' , 'cs' => 'cs_CZ' , 'en' => 'en_US' , 'fa' => 'fa_IR' ,
'gl' => 'gl_ES' , 'he' => 'he_IL' , 'hi' => 'hi_IN' , 'ja' => 'ja_JP' ,
'ka' => 'ka_GE' , 'km' => 'km_KH' , 'kn' => 'kn_IN' , 'ko' => 'ko_KR' , 'lo' => 'lo_LA' , 'nb' => 'nb_NO' , 'no' => 'nb_NO' , 'ne' => 'ne_NP' ,
'sl' => 'sl_SI' , 'sq' => 'sq_AL' , 'sr' => 'sr_RS' , 'sv' => 'sv_SE' , 'uk' => 'uk_UA' , 'vi' => 'vi_VN' , 'zh' => 'zh_CN'
2021-02-10 03:20:50 +01:00
);
2021-02-23 22:03:23 +01:00
if ( isset ( $longforshort [ strtolower ( $langpart [ 0 ])])) {
$srclang = $longforshort [ strtolower ( $langpart [ 0 ])];
} elseif ( ! empty ( $langpart [ 0 ])) {
2023-07-12 16:32:50 +02:00
$srclang = strtolower ( $langpart [ 0 ]) . " _ " . strtoupper ( $langpart [ 0 ]);
2021-02-23 22:03:23 +01:00
} else {
$srclang = 'en_US' ;
}
2009-05-11 18:26:54 +02:00
}
2020-01-16 02:54:00 +01:00
$this -> defaultlang = $srclang ;
2020-04-27 18:38:11 +02:00
$this -> shortlang = substr ( $srclang , 0 , 2 );
2012-02-20 01:31:02 +01:00
//print 'this->defaultlang='.$this->defaultlang;
2009-05-11 18:26:54 +02:00
}
/**
2010-11-01 13:41:32 +01:00
* Return active language code for current user
* It ' s an accessor for this -> defaultlang
2011-08-16 01:17:14 +02:00
*
2018-02-13 20:13:35 +01:00
* @ param int $mode 0 = Long language code , 1 = Short language code ( en , fr , es , ... )
2011-12-07 17:28:11 +01:00
* @ return string Language code used ( en_US , en_AU , fr_FR , ... )
2009-05-11 18:26:54 +02:00
*/
2019-02-26 22:42:19 +01:00
public function getDefaultLang ( $mode = 0 )
2009-05-11 18:26:54 +02:00
{
2021-02-23 22:03:23 +01:00
if ( empty ( $mode )) {
return $this -> defaultlang ;
} else {
return substr ( $this -> defaultlang , 0 , 2 );
}
2009-05-11 18:26:54 +02:00
}
2017-03-03 13:27:51 +01:00
/**
* Load translation files .
2020-10-31 14:32:18 +01:00
*
2024-10-14 01:59:44 +02:00
* @ param string [] $domains Array of lang files to load
2023-12-06 15:46:39 +01:00
* @ return int Return integer < 0 if KO , 0 if already loaded or loading not required , > 0 if OK
2017-03-03 13:27:51 +01:00
*/
2019-02-26 22:42:19 +01:00
public function loadLangs ( $domains )
2017-03-03 13:27:51 +01:00
{
2023-07-12 16:32:50 +02:00
$loaded = 0 ;
2021-02-23 22:03:23 +01:00
foreach ( $domains as $domain ) {
2023-07-12 16:32:50 +02:00
$result = $this -> load ( $domain );
if ( $result > 0 ) {
$loaded = $result ;
} elseif ( $result < 0 ) {
return $result ;
}
2020-10-31 14:32:18 +01:00
}
2023-07-12 16:32:50 +02:00
return $loaded ;
2017-03-03 13:27:51 +01:00
}
2017-06-09 09:25:15 +02:00
2009-05-11 18:26:54 +02:00
/**
2010-11-22 10:18:53 +01:00
* Load translation key - value for a particular file , into a memory array .
* If data for file already loaded , do nothing .
* All data in translation array are stored in UTF - 8 format .
2020-10-31 14:32:18 +01:00
* tab_loaded is completed with $domain key .
* rule " we keep first entry found with we keep last entry found " so it is probably not what you want to do .
*
* Value for hash are : 1 : Loaded from disk , 2 : Not found , 3 : Loaded from cache
*
2020-09-10 10:41:16 +02:00
* @ param string $domain File name to load ( . lang file ) . Must be " file " or " file@module " for module language files :
2020-10-31 14:32:18 +01:00
* If $domain is " file@module " instead of " file " then we look for module lang file
2020-09-10 10:41:16 +02:00
* in htdocs / custom / modules / mymodule / langs / code_CODE / file . lang
* then in htdocs / module / langs / code_CODE / file . lang instead of htdocs / langs / code_CODE / file . lang
2024-10-14 01:59:44 +02:00
* @ param int $alt 0 ( try xx_ZZ then 1 ), 1 ( try xx_XX then 2 ), 2 ( try en_US )
2020-09-10 10:41:16 +02:00
* @ param int $stopafterdirection Stop when the DIRECTION tag is found ( optimize speed )
2024-01-12 18:02:05 +01:00
* @ param string $forcelangdir To force a different lang directory
2020-09-10 10:41:16 +02:00
* @ param int $loadfromfileonly 1 = Do not load overwritten translation from file or old conf .
* @ param int $forceloadifalreadynotfound Force attempt to reload lang file if it was previously not found
2024-10-14 01:59:44 +02:00
* @ param array < string , string > $tabtranslatedomain Store translations to be stored in cache
2024-02-28 22:56:00 +01:00
* @ param string $langkey To create key for cachekey in recursivity
2023-12-06 15:46:39 +01:00
* @ return int Return integer < 0 if KO , 0 if already loaded or loading not required , > 0 if OK
2019-03-11 12:07:28 +01:00
* @ see loadLangs ()
2008-03-31 17:17:39 +02:00
*/
2024-02-28 22:56:00 +01:00
public function load ( $domain , $alt = 0 , $stopafterdirection = 0 , $forcelangdir = '' , $loadfromfileonly = 0 , $forceloadifalreadynotfound = 0 , & $tabtranslatedomain = [], $langkey = '' )
2009-05-11 18:26:54 +02:00
{
2020-01-16 02:54:00 +01:00
global $conf , $db ;
2015-09-17 17:52:34 +02:00
2017-04-14 11:22:48 +02:00
//dol_syslog("Translate::Load Start domain=".$domain." alt=".$alt." forcelangdir=".$forcelangdir." this->defaultlang=".$this->defaultlang);
2017-06-09 09:25:15 +02:00
2008-02-19 22:04:23 +01:00
// Check parameters
2021-02-23 22:03:23 +01:00
if ( empty ( $domain )) {
2024-01-20 09:22:38 +01:00
dol_print_error ( null , get_class ( $this ) . " ::Load ErrorWrongParameters " );
2020-10-31 14:32:18 +01:00
return - 1 ;
2008-02-19 22:04:23 +01:00
}
2021-06-21 19:47:43 +02:00
if ( $this -> defaultlang === 'none_NONE' ) {
2021-02-23 22:03:23 +01:00
return 0 ; // Special language code to not translate keys
}
2017-06-09 09:25:15 +02:00
2017-04-14 11:22:48 +02:00
// Load $this->tab_translate[] from database
2021-02-23 22:03:23 +01:00
if ( empty ( $loadfromfileonly ) && count ( $this -> tab_translate ) == 0 ) {
$this -> loadFromDatabase ( $db ); // No translation was never loaded yet, so we load database.
}
2009-01-15 23:49:06 +01:00
2009-09-28 23:59:09 +02:00
2010-04-19 11:45:53 +02:00
$newdomain = $domain ;
2010-04-19 11:34:50 +02:00
$modulename = '' ;
2010-05-08 04:16:29 +02:00
2011-08-24 04:17:57 +02:00
// Search if a module directory name is provided into lang file name
2020-01-16 02:54:00 +01:00
$regs = array ();
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/^([^@]+)@([^@]+)$/i' , $domain , $regs )) {
2024-10-29 22:44:47 +01:00
$newdomain = ( string ) $regs [ 1 ];
$modulename = ( string ) $regs [ 2 ];
2010-04-19 11:34:50 +02:00
}
2009-09-28 04:53:19 +02:00
2020-10-31 14:32:18 +01:00
// Check cache
2023-07-12 16:32:50 +02:00
if (
! empty ( $this -> _tab_loaded [ $newdomain ])
&& ( $this -> _tab_loaded [ $newdomain ] != 2 || empty ( $forceloadifalreadynotfound ))
) { // File already loaded and found and not forced for this domain
2018-03-13 18:13:31 +01:00
//dol_syslog("Translate::Load already loaded for newdomain=".$newdomain);
2009-09-28 23:59:09 +02:00
return 0 ;
}
2020-10-31 14:32:18 +01:00
$fileread = 0 ;
2020-01-16 02:54:00 +01:00
$langofdir = ( empty ( $forcelangdir ) ? $this -> defaultlang : $forcelangdir );
2024-02-28 22:56:00 +01:00
$langkey = ( empty ( $langkey ) ? $langofdir : $langkey );
2009-09-28 23:59:09 +02:00
// Redefine alt
2020-01-16 02:54:00 +01:00
$langarray = explode ( '_' , $langofdir );
2021-02-23 22:03:23 +01:00
if ( $alt < 1 && isset ( $langarray [ 1 ]) && ( strtolower ( $langarray [ 0 ]) == strtolower ( $langarray [ 1 ]) || in_array ( strtolower ( $langofdir ), array ( 'el_gr' )))) {
$alt = 1 ;
}
if ( $alt < 2 && strtolower ( $langofdir ) == 'en_us' ) {
$alt = 2 ;
}
2012-02-01 13:28:19 +01:00
2021-02-23 22:03:23 +01:00
if ( empty ( $langofdir )) { // This may occurs when load is called without setting the language and without providing a value for forcelangdir
2023-07-12 16:32:50 +02:00
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 );
2014-11-12 10:25:56 +01:00
return - 1 ;
}
2024-02-28 22:56:00 +01:00
$usecachekey = '' ;
2021-02-23 22:03:23 +01:00
foreach ( $this -> dir as $searchdir ) {
2009-05-11 18:26:54 +02:00
// Directory of translation files
2023-07-12 16:32:50 +02:00
$file_lang = $searchdir . ( $modulename ? '/' . $modulename : '' ) . " /langs/ " . $langofdir . " / " . $newdomain . " .lang " ;
2020-01-16 02:54:00 +01:00
$file_lang_osencoded = dol_osencode ( $file_lang );
2012-12-01 15:45:05 +01:00
2023-08-14 23:09:40 +02:00
//$filelangexists = is_file($file_lang_osencoded);
$filelangexists = @ is_file ( $file_lang_osencoded ); // avoid [php:warn]
2009-01-02 23:02:52 +01:00
2018-11-26 13:31:05 +01:00
//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);
//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";
2009-01-02 23:02:52 +01:00
2021-02-23 22:03:23 +01:00
if ( $filelangexists ) {
2012-12-01 15:45:05 +01:00
// TODO Move cache read out of loop on dirs or at least filelangexists
2020-10-31 14:32:18 +01:00
$found = false ;
2010-01-13 17:26:19 +01:00
2011-08-16 01:17:14 +02:00
// Enable caching of lang file in memory (not by default)
2020-01-16 02:54:00 +01:00
$usecachekey = '' ;
2010-05-08 04:16:29 +02:00
// Using a memcached server
2023-11-27 11:24:19 +01:00
if ( isModEnabled ( 'memcached' ) && getDolGlobalString ( 'MEMCACHED_SERVER' )) {
2024-02-28 22:56:00 +01:00
$usecachekey = $newdomain . '_' . $langkey . '_' . md5 ( $file_lang ); // Should not contains special chars
2024-01-05 03:41:22 +01:00
} elseif ( getDolGlobalInt ( 'MAIN_OPTIMIZE_SPEED' ) & 0x02 ) {
2021-03-01 20:37:16 +01:00
// Using cache with shmop. Speed gain: 40ms - Memory overusage: 200ko (Size of session cache file)
2020-01-16 02:54:00 +01:00
$usecachekey = $newdomain ;
2010-05-08 04:16:29 +02:00
}
2010-01-13 17:26:19 +01:00
2021-02-23 22:03:23 +01:00
if ( $usecachekey ) {
2020-10-31 14:32:18 +01:00
//dol_syslog('Translate::Load we will cache result into usecachekey '.$usecachekey);
2023-07-12 16:32:50 +02:00
require_once DOL_DOCUMENT_ROOT . '/core/lib/memory.lib.php' ;
2020-01-16 02:54:00 +01:00
$tmparray = dol_getcache ( $usecachekey );
2021-02-23 22:03:23 +01:00
if ( is_array ( $tmparray ) && count ( $tmparray )) {
2020-10-31 14:32:18 +01:00
$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.
2021-02-23 22:03:23 +01:00
if ( $alt == 2 ) {
$fileread = 1 ;
}
2020-01-16 02:54:00 +01:00
$found = true ; // Found in dolibarr PHP cache
2008-12-07 20:19:32 +01:00
}
2008-01-20 17:05:50 +01:00
}
2009-12-16 19:57:51 +01:00
2021-02-23 22:03:23 +01:00
if ( ! $found ) {
if ( $fp = @ fopen ( $file_lang , " rt " )) {
2024-10-29 22:44:47 +01:00
// $tabtranslatedomain = array(); // To save lang content in cache when enabled (commented because initial = argument to function)
2010-01-13 17:26:19 +01:00
2016-12-22 17:09:25 +01:00
/**
* Read each lines until a '=' ( with any combination of spaces around it )
* and split the rest until a line feed .
* This is more efficient than fgets + explode + trim by a factor of ~ 2.
*/
2021-02-23 22:03:23 +01:00
while ( $line = fscanf ( $fp , " %[^= ]%*[ =]%[^ \n \r ] " )) {
if ( isset ( $line [ 1 ])) {
2016-12-22 17:09:25 +01:00
list ( $key , $value ) = $line ;
2016-07-06 13:26:49 +02:00
//if ($domain == 'orders') print "Domain=$domain, found a string for $tab[0] with value $tab[1]. Currently in cache ".$this->tab_translate[$key]."<br>";
//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>";
2021-02-23 22:03:23 +01:00
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)
2016-12-22 17:09:25 +01:00
if ( $key == 'DIRECTION' ) { // This is to declare direction of language
if ( $alt < 2 || empty ( $this -> tab_translate [ $key ])) { // We load direction only for primary files or if not yet loaded
$this -> tab_translate [ $key ] = $value ;
if ( $stopafterdirection ) {
break ; // We do not save tab if we stop after DIRECTION
} elseif ( $usecachekey ) {
$tabtranslatedomain [ $key ] = $value ;
}
2009-08-11 14:28:30 +02:00
}
2021-02-23 22:03:23 +01:00
} elseif ( $key [ 0 ] == '#' ) {
2020-10-31 14:32:18 +01:00
continue ;
2020-05-21 15:05:19 +02:00
} else {
2020-05-14 14:10:04 +02:00
// Convert some strings: Parse and render carriage returns. Also, change '\\s' into '\s' because transifex sync pull the string '\s' into string '\\s'
2020-01-13 13:11:25 +01:00
$this -> tab_translate [ $key ] = str_replace ( array ( '\\n' , '\\\\s' ), array ( " \n " , '\s' ), $value );
2016-12-22 17:09:25 +01:00
if ( $usecachekey ) {
$tabtranslatedomain [ $key ] = $value ;
} // To save lang content in cache
2008-12-07 20:19:32 +01:00
}
2009-05-11 18:26:54 +02:00
}
}
}
2008-12-07 20:19:32 +01:00
fclose ( $fp );
2020-01-16 02:54:00 +01:00
$fileread = 1 ;
2010-01-13 17:26:19 +01:00
2023-11-27 11:24:19 +01:00
if ( ! getDolGlobalString ( 'MAIN_FORCELANGDIR' )) {
2021-02-23 22:03:23 +01:00
break ; // Break loop on each root dir. If a module has forced dir, we do not stop loop.
}
2009-05-11 18:26:54 +02:00
}
2008-12-07 20:19:32 +01:00
}
2009-05-11 18:26:54 +02:00
}
2008-12-07 20:19:32 +01:00
}
2009-01-15 23:49:06 +01:00
2017-01-21 21:52:42 +01:00
// Now we complete with next file (fr_CA->fr_FR, es_MX->ex_ES, ...)
2021-02-23 22:03:23 +01:00
if ( $alt == 0 ) {
2009-09-28 23:59:09 +02:00
// This function MUST NOT contains call to syslog
//dol_syslog("Translate::Load loading alternate translation file (to complete ".$this->defaultlang."/".$newdomain.".lang file)", LOG_DEBUG);
2023-07-12 16:32:50 +02:00
$langofdir = strtolower ( $langarray [ 0 ]) . '_' . strtoupper ( $langarray [ 0 ]);
2021-02-23 22:03:23 +01:00
if ( $langofdir == 'el_EL' ) {
$langofdir = 'el_GR' ; // main parent for el_CY is not 'el_EL' but 'el_GR'
}
if ( $langofdir == 'ar_AR' ) {
$langofdir = 'ar_SA' ; // main parent for ar_EG is not 'ar_AR' but 'ar_SA'
}
2024-02-28 22:56:00 +01:00
$this -> load ( $domain , $alt + 1 , $stopafterdirection , $langofdir , 0 , 0 , $tabtranslatedomain , $langkey );
2009-09-28 23:59:09 +02:00
}
2017-01-21 21:52:42 +01:00
// Now we complete with reference file (en_US)
2021-02-23 22:03:23 +01:00
if ( $alt == 1 ) {
2009-09-28 23:59:09 +02:00
// This function MUST NOT contains call to syslog
//dol_syslog("Translate::Load loading alternate translation file (to complete ".$this->defaultlang."/".$newdomain.".lang file)", LOG_DEBUG);
2020-01-16 02:54:00 +01:00
$langofdir = 'en_US' ;
2024-02-28 22:56:00 +01:00
$this -> load ( $domain , $alt + 1 , $stopafterdirection , $langofdir , 0 , 0 , $tabtranslatedomain , $langkey );
2009-06-14 18:25:23 +02:00
}
2009-06-10 21:51:00 +02:00
2018-11-26 13:31:05 +01:00
// We are in the pass of the reference file. No more files to scan to complete.
2021-02-23 22:03:23 +01:00
if ( $alt == 2 ) {
if ( $fileread ) {
$this -> _tab_loaded [ $newdomain ] = 1 ; // Set domain file as found so loaded
}
2009-09-28 23:59:09 +02:00
2021-02-23 22:03:23 +01:00
if ( empty ( $this -> _tab_loaded [ $newdomain ])) {
$this -> _tab_loaded [ $newdomain ] = 2 ; // Set this file as not found
}
2009-09-28 23:59:09 +02:00
}
2009-01-15 23:49:06 +01:00
2015-09-17 17:52:34 +02:00
// This part is deprecated and replaced with table llx_overwrite_trans
// Kept for backward compatibility.
2021-02-23 22:03:23 +01:00
if ( empty ( $loadfromfileonly )) {
2023-07-12 16:32:50 +02:00
$overwritekey = 'MAIN_OVERWRITE_TRANS_' . $this -> defaultlang ;
2024-07-03 20:05:29 +02:00
if ( getDolGlobalString ( $overwritekey )) { // Overwrite translation with key1:newstring1,key2:newstring2
2020-10-31 14:32:18 +01:00
// Overwrite translation with param MAIN_OVERWRITE_TRANS_xx_XX
2023-12-13 15:20:53 +01:00
$tmparray = explode ( ',' , getDolGlobalString ( $overwritekey ));
2021-02-23 22:03:23 +01:00
foreach ( $tmparray as $tmp ) {
2020-10-31 14:32:18 +01:00
$tmparray2 = explode ( ':' , $tmp );
2021-02-23 22:03:23 +01:00
if ( ! empty ( $tmparray2 [ 1 ])) {
$this -> tab_translate [ $tmparray2 [ 0 ]] = $tmparray2 [ 1 ];
}
2020-10-31 14:32:18 +01:00
}
}
2017-06-09 09:25:15 +02:00
}
2024-02-28 22:56:00 +01:00
// To save lang content for usecachekey into cache
if ( $usecachekey && count ( $tabtranslatedomain )) {
$ressetcache = dol_setcache ( $usecachekey , $tabtranslatedomain );
if ( $ressetcache < 0 ) {
$error = 'Failed to set cache for usecachekey=' . $usecachekey . ' result=' . $ressetcache ;
dol_syslog ( $error , LOG_ERR );
}
}
2020-10-31 14:32:18 +01:00
// Check to be sure that SeparatorDecimal differs from SeparatorThousand
2023-07-12 16:32:50 +02:00
if (
! empty ( $this -> tab_translate [ " SeparatorDecimal " ]) && ! empty ( $this -> tab_translate [ " SeparatorThousand " ])
&& $this -> tab_translate [ " SeparatorDecimal " ] == $this -> tab_translate [ " SeparatorThousand " ]
) {
2021-02-23 22:03:23 +01:00
$this -> tab_translate [ " SeparatorThousand " ] = '' ;
}
2009-12-16 22:42:42 +01:00
2008-03-31 17:17:39 +02:00
return 1 ;
2009-05-11 18:26:54 +02:00
}
2005-10-30 02:07:00 +01:00
2015-09-17 17:52:34 +02:00
/**
* Load translation key - value from database into a memory array .
* If data already loaded , do nothing .
* All data in translation array are stored in UTF - 8 format .
2020-10-31 14:32:18 +01:00
* tab_loaded is completed with $domain key .
* rule " we keep first entry found with we keep last entry found " so it is probably not what you want to do .
*
* Value for hash are : 1 : Loaded from disk , 2 : Not found , 3 : Loaded from cache
*
2023-02-22 22:17:39 +01:00
* @ param DoliDB $db Database handler
2023-12-06 15:46:39 +01:00
* @ return int Return integer < 0 if KO , 0 if already loaded or loading not required , > 0 if OK
2015-09-17 17:52:34 +02:00
*/
2019-02-26 22:42:19 +01:00
public function loadFromDatabase ( $db )
2015-09-17 17:52:34 +02:00
{
global $conf ;
2020-01-16 02:54:00 +01:00
$domain = 'database' ;
2017-06-09 09:25:15 +02:00
2015-09-17 17:52:34 +02:00
// Check parameters
2021-02-23 22:03:23 +01:00
if ( empty ( $db )) {
return 0 ; // Database handler can't be used
}
2015-09-17 17:52:34 +02:00
//dol_syslog("Translate::Load Start domain=".$domain." alt=".$alt." forcelangdir=".$forcelangdir." this->defaultlang=".$this->defaultlang);
$newdomain = $domain ;
2018-11-26 13:31:05 +01:00
// Check cache
2021-02-23 22:03:23 +01:00
if ( ! empty ( $this -> _tab_loaded [ $newdomain ])) { // File already loaded for this domain 'database'
2015-09-17 17:52:34 +02:00
//dol_syslog("Translate::Load already loaded for newdomain=".$newdomain);
return 0 ;
}
2024-10-29 22:44:47 +01:00
$this -> _tab_loaded [ $newdomain ] = 2 ; // Preset the load as loaded and make sure this function is called once only for $newdomain='database'
2017-06-09 09:25:15 +02:00
2020-10-31 14:32:18 +01:00
$fileread = 0 ;
2020-01-16 02:54:00 +01:00
$langofdir = $this -> defaultlang ;
2015-09-17 17:52:34 +02:00
2021-02-23 22:03:23 +01:00
if ( empty ( $langofdir )) { // This may occurs when load is called without setting the language and without providing a value for forcelangdir
2023-07-12 16:32:50 +02:00
dol_syslog ( " Error: " . get_class ( $this ) . " ::loadFromDatabase was called but language was not set yet with langs->setDefaultLang(). Nothing will be loaded. " , LOG_WARNING );
2015-09-17 17:52:34 +02:00
return - 1 ;
}
// TODO Move cache read out of loop on dirs or at least filelangexists
2020-01-16 02:54:00 +01:00
$found = false ;
2015-09-17 17:52:34 +02:00
// Enable caching of lang file in memory (not by default)
2020-01-16 02:54:00 +01:00
$usecachekey = '' ;
2015-09-17 17:52:34 +02:00
// Using a memcached server
2023-11-27 11:24:19 +01:00
if ( isModEnabled ( 'memcached' ) && getDolGlobalString ( 'MEMCACHED_SERVER' )) {
2023-07-12 16:32:50 +02:00
$usecachekey = $newdomain . '_' . $langofdir ; // Should not contains special chars
2024-01-05 03:41:22 +01:00
} elseif ( getDolGlobalInt ( 'MAIN_OPTIMIZE_SPEED' ) & 0x02 ) {
2021-03-01 20:37:16 +01:00
// Using cache with shmop. Speed gain: 40ms - Memory overusage: 200ko (Size of session cache file)
2020-01-16 02:54:00 +01:00
$usecachekey = $newdomain ;
2015-09-17 17:52:34 +02:00
}
2021-02-23 22:03:23 +01:00
if ( $usecachekey ) {
2020-10-31 14:32:18 +01:00
//dol_syslog('Translate::Load we will cache result into usecachekey '.$usecachekey);
//global $aaa; $aaa+=1;
//print $aaa." ".$usecachekey."\n";
2023-07-12 16:32:50 +02:00
require_once DOL_DOCUMENT_ROOT . '/core/lib/memory.lib.php' ;
2020-01-16 02:54:00 +01:00
$tmparray = dol_getcache ( $usecachekey );
2021-02-23 22:03:23 +01:00
if ( is_array ( $tmparray ) && count ( $tmparray )) {
2021-02-20 17:23:03 +01:00
$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.
2015-09-17 17:52:34 +02:00
//print $newdomain."\n";
//var_dump($this->tab_translate);
2020-01-16 02:54:00 +01:00
$fileread = 1 ;
$found = true ; // Found in dolibarr PHP cache
2015-09-17 17:52:34 +02:00
}
}
2023-11-27 11:24:19 +01:00
if ( ! $found && getDolGlobalString ( 'MAIN_ENABLE_OVERWRITE_TRANSLATION' )) {
2020-10-31 14:32:18 +01:00
// Overwrite translation with database read
2023-08-17 13:53:13 +02:00
$sql = " SELECT transkey, transvalue FROM " . $db -> prefix () . " overwrite_trans where (lang=' " . $db -> escape ( $this -> defaultlang ) . " ' OR lang IS NULL) " ;
2020-10-31 14:32:18 +01:00
$sql .= " AND entity IN (0, " . getEntity ( 'overwrite_trans' ) . " ) " ;
$sql .= $db -> order ( " lang " , " DESC " );
2023-08-24 00:12:52 +02:00
2020-10-31 14:32:18 +01:00
$resql = $db -> query ( $sql );
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2020-10-31 14:32:18 +01:00
$num = $db -> num_rows ( $resql );
2021-02-23 22:03:23 +01:00
if ( $num ) {
2024-10-29 22:44:47 +01:00
$tabtranslatedomain = array (); // To save lang content in cache (when enabled)
2020-10-31 14:32:18 +01:00
$i = 0 ;
2021-02-23 22:03:23 +01:00
while ( $i < $num ) { // Ex: Need 225ms for all fgets on all lang file for Third party page. Same speed than file_get_contents
2020-10-31 14:32:18 +01:00
$obj = $db -> fetch_object ( $resql );
$key = $obj -> transkey ;
$value = $obj -> transvalue ;
2017-06-09 09:25:15 +02:00
2015-09-17 17:52:34 +02:00
//print "Domain=$domain, found a string for $tab[0] with value $tab[1]<br>";
2021-02-23 22:03:23 +01:00
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)
2020-01-13 13:11:25 +01:00
// Convert some strings: Parse and render carriage returns. Also, change '\\s' int '\s' because transifex sync pull the string '\s' into string '\\s'
$this -> tab_translate [ $key ] = str_replace ( array ( '\\n' , '\\\\s' ), array ( " \n " , '\s' ), $value );
2015-09-17 17:52:34 +02:00
2021-02-23 22:03:23 +01:00
if ( $usecachekey ) {
$tabtranslatedomain [ $key ] = $value ; // To save lang content in cache
}
2015-09-17 17:52:34 +02:00
}
2017-06-09 09:25:15 +02:00
2020-10-31 14:32:18 +01:00
$i ++ ;
}
$fileread = 1 ;
// TODO Move cache write out of loop on dirs
// To save lang content for usecachekey into cache
2021-02-23 22:03:23 +01:00
if ( $usecachekey && count ( $tabtranslatedomain )) {
2020-10-31 14:32:18 +01:00
$ressetcache = dol_setcache ( $usecachekey , $tabtranslatedomain );
2021-02-23 22:03:23 +01:00
if ( $ressetcache < 0 ) {
2023-07-12 16:32:50 +02:00
$error = 'Failed to set cache for usecachekey=' . $usecachekey . ' result=' . $ressetcache ;
2020-10-31 14:32:18 +01:00
dol_syslog ( $error , LOG_ERR );
}
}
}
} else {
dol_print_error ( $db );
}
2015-09-17 17:52:34 +02:00
}
2021-02-23 22:03:23 +01:00
if ( $fileread ) {
$this -> _tab_loaded [ $newdomain ] = 1 ; // Set domain file as loaded
}
2015-09-17 17:52:34 +02:00
return 1 ;
}
2017-06-09 09:25:15 +02:00
2020-09-09 15:14:52 +02:00
/**
* Get information with result of loading data for domain
*
* @ param string $domain Domain to check
2020-09-09 15:16:03 +02:00
* @ return int 0 , 1 , 2. ..
2020-09-09 15:14:52 +02:00
*/
public function isLoaded ( $domain )
{
return $this -> _tab_loaded [ $domain ];
}
2017-06-09 09:25:15 +02:00
2009-08-25 16:36:03 +02:00
/**
2015-06-30 01:34:17 +02:00
* Return translated value of key for special keys ( " Currency... " , " Civility... " , ... ) .
* Search in lang file , then into database . Key must be any complete entry into lang file : CurrencyEUR , ...
2011-01-23 23:39:48 +01:00
* If not found , return key .
2024-01-13 19:48:20 +01:00
* The string return is not formatted ( translated with transnoentitiesnoconv ) .
2022-01-09 20:25:10 +01:00
* NOTE : To avoid infinite loop ( getLabelFromKey -> transnoentities -> getTradFromKey -> getLabelFromKey ), if you modify this function ,
* check that getLabelFromKey is never called with the same value than $key .
2009-08-25 16:36:03 +02:00
*
2011-12-07 17:28:11 +01:00
* @ param string $key Key to translate
2014-08-01 14:26:13 +02:00
* @ return string Translated string ( translated with transnoentitiesnoconv )
2009-08-25 16:36:03 +02:00
*/
2020-10-31 14:32:18 +01:00
private function getTradFromKey ( $key )
{
2023-10-21 02:39:27 +02:00
global $db ;
2012-10-03 17:47:53 +02:00
2020-08-03 12:33:22 +02:00
if ( ! is_string ( $key )) {
//xdebug_print_function_stack('ErrorBadValueForParamNotAString');
return 'ErrorBadValueForParamNotAString' ; // Avoid multiple errors with code not using function correctly.
}
2014-06-20 16:20:39 +02:00
2020-01-16 02:54:00 +01:00
$newstr = $key ;
2021-03-12 15:34:31 +01:00
$reg = array ();
2024-12-10 21:20:53 +01:00
if ( preg_match ( '/^Civility([0-9A-Z_]+)$/i' , $key , $reg )) {
2020-10-31 14:32:18 +01:00
$newstr = $this -> getLabelFromKey ( $db , $reg [ 1 ], 'c_civility' , 'code' , 'label' );
2021-02-23 22:03:23 +01:00
} elseif ( preg_match ( '/^Currency([A-Z][A-Z][A-Z])$/i' , $key , $reg )) {
2020-01-16 02:54:00 +01:00
$newstr = $this -> getLabelFromKey ( $db , $reg [ 1 ], 'c_currencies' , 'code_iso' , 'label' );
2024-12-10 21:20:53 +01:00
} elseif ( preg_match ( '/^SendingMethod([0-9A-Z_]+)$/i' , $key , $reg )) {
2020-01-16 02:54:00 +01:00
$newstr = $this -> getLabelFromKey ( $db , $reg [ 1 ], 'c_shipment_mode' , 'code' , 'libelle' );
2024-12-10 21:20:53 +01:00
} elseif ( preg_match ( '/^PaymentType(?:Short)?([0-9A-Z_]+)$/i' , $key , $reg )) {
2020-10-31 14:32:18 +01:00
$newstr = $this -> getLabelFromKey ( $db , $reg [ 1 ], 'c_paiement' , 'code' , 'libelle' , '' , 1 );
2024-12-10 21:20:53 +01:00
} elseif ( preg_match ( '/^OppStatus([0-9A-Z_]+)$/i' , $key , $reg )) {
2020-10-31 14:32:18 +01:00
$newstr = $this -> getLabelFromKey ( $db , $reg [ 1 ], 'c_lead_status' , 'code' , 'label' );
2024-12-10 21:20:53 +01:00
} elseif ( preg_match ( '/^OrderSource([0-9A-Z_]+)$/i' , $key , $reg )) {
2020-10-31 14:32:18 +01:00
// TODO OrderSourceX must be replaced with content of table llx_c_input_reason or llx_c_input_method
2022-01-09 20:25:10 +01:00
//$newstr=$this->getLabelFromKey($db,$reg[1],'llx_c_input_reason','code','label');
2020-10-31 14:32:18 +01:00
}
2018-05-16 10:31:44 +02:00
2020-10-31 14:32:18 +01:00
/* Disabled . There is too many cases where translation of $newstr is not defined is normal ( like when output with setEventMessage an already translated string )
2021-11-05 14:23:19 +01:00
if ( getDolGlobalInt ( 'MAIN_FEATURES_LEVEL' ) >= 2 )
2021-02-23 22:03:23 +01:00
{
dol_syslog ( __METHOD__ . " MAIN_FEATURES_LEVEL=DEVELOP: missing translation for key ' " . $newstr . " ' in " . $_SERVER [ " PHP_SELF " ], LOG_DEBUG );
} */
2018-05-16 10:31:44 +02:00
2020-10-31 14:32:18 +01:00
return $newstr ;
}
2009-08-07 02:49:43 +02:00
2009-05-11 18:26:54 +02:00
/**
2010-10-18 20:18:12 +02:00
* Return text translated of text received as parameter ( and encode it into HTML )
2020-11-26 22:44:11 +01:00
* If there is no match for this text , we look in alternative file and if still not found , it is returned as it is .
* The parameters of this method should not contain HTML tags . If there is , they will be htmlencoded to have no effect .
2011-08-16 01:17:14 +02:00
*
2024-09-28 12:09:35 +02:00
* @ param string $key Key to translate
* @ param string | int $param1 param1 string
* @ param string | int $param2 param2 string
* @ param string | int $param3 param3 string
* @ param string | int $param4 param4 string
2020-11-26 22:44:11 +01:00
* @ param int $maxsize Max length of text . Warning : Will not work if paramX has HTML content . deprecated .
2011-12-07 17:28:11 +01:00
* @ return string Translated string ( encoded into HTML entities and UTF8 )
2019-10-20 18:44:07 +02:00
*/
2020-10-31 14:32:18 +01:00
public function trans ( $key , $param1 = '' , $param2 = '' , $param3 = '' , $param4 = '' , $maxsize = 0 )
{
2021-02-23 22:03:23 +01:00
if ( ! empty ( $this -> tab_translate [ $key ])) { // Translation is available
2020-10-31 14:32:18 +01:00
$str = $this -> tab_translate [ $key ];
// Make some string replacement after translation
2023-07-12 16:32:50 +02:00
$replacekey = 'MAIN_REPLACE_TRANS_' . $this -> defaultlang ;
2024-07-03 20:05:29 +02:00
if ( getDolGlobalString ( $replacekey )) { // Replacement translation variable with string1:newstring1;string2:newstring2
2023-12-13 15:20:53 +01:00
$tmparray = explode ( ';' , getDolGlobalString ( $replacekey ));
2021-02-23 22:03:23 +01:00
foreach ( $tmparray as $tmp ) {
2020-10-31 14:32:18 +01:00
$tmparray2 = explode ( ':' , $tmp );
2023-07-12 16:32:50 +02:00
$str = preg_replace ( '/' . preg_quote ( $tmparray2 [ 0 ]) . '/' , $tmparray2 [ 1 ], $str );
2020-10-31 14:32:18 +01:00
}
}
2020-11-26 22:44:11 +01:00
2025-01-28 13:55:25 +01:00
$str = preg_replace ( '/([^%])%([^%0sdmYIMpHSBb])/' , '\1__percent_with_bad_specifier__\2' , $str );
2025-01-08 16:19:06 +01:00
2021-02-23 22:03:23 +01:00
if ( strpos ( $key , 'Format' ) !== 0 ) {
2022-07-29 17:35:31 +02:00
try {
2024-03-17 18:02:44 +01:00
// @phan-suppress-next-line PhanPluginPrintfVariableFormatString
2022-07-29 17:35:31 +02:00
$str = sprintf ( $str , $param1 , $param2 , $param3 , $param4 ); // Replace %s and %d except for FormatXXX strings.
} catch ( Exception $e ) {
2022-08-11 00:47:37 +02:00
// No exception managed
2022-07-29 17:35:31 +02:00
}
2020-10-31 14:32:18 +01:00
}
2011-08-27 18:41:30 +02:00
2025-01-28 13:55:25 +01:00
$str = str_replace ( '__percent_with_bad_specifier__' , '%' , $str );
2025-01-08 16:19:06 +01:00
2025-01-28 14:00:55 +01:00
2025-01-12 22:33:20 +01:00
// We replace some HTML tags by __xx__ to avoid having them encoded by htmlentities because
// we want to keep '"' '<b>' '</b>' '<u>' '</u>' '<i>' '</i>' '<center> '</center>' '<strong' '</strong>' '<a ' '</a>' '<br>' '<span' '</span>' '< ' that are reliable HTML tags inside translation strings.
$str = str_replace (
array ( '"' , '<b>' , '</b>' , '<u>' , '</u>' , '<i>' , '</i>' , '<center>' , '</center>' , '<strong>' , '</strong>' , '<a ' , '</a>' , '<br>' , '<span' , '</span>' , '< ' , '>' ), // We accept '< ' but not '<'. We can accept however '>'
array ( '__quot__' , '__tagb__' , '__tagbend__' , '__tagu__' , '__taguend__' , '__tagi__' , '__tagiend__' , '__tagcenter__' , '__tagcenterend__' , '__tagb__' , '__tagbend__' , '__taga__' , '__tagaend__' , '__tagbr__' , '__tagspan__' , '__tagspanend__' , '__ltspace__' , '__gt__' ),
$str
);
2023-10-21 02:39:27 +02:00
// Encode string into HTML
2020-11-26 22:44:11 +01:00
$str = htmlentities ( $str , ENT_COMPAT , $this -> charset_output ); // Do not convert simple quotes in translation (strings in html are embraced by "). Use dol_escape_htmltag around text in HTML content
2009-05-11 18:26:54 +02:00
2020-11-26 22:44:11 +01:00
// Restore reliable HTML tags into original translation string
$str = str_replace (
2020-12-06 17:30:27 +01:00
array ( '__quot__' , '__tagb__' , '__tagbend__' , '__tagu__' , '__taguend__' , '__tagi__' , '__tagiend__' , '__tagcenter__' , '__tagcenterend__' , '__taga__' , '__tagaend__' , '__tagbr__' , '__tagspan__' , '__tagspanend__' , '__ltspace__' , '__gt__' ),
2025-01-12 22:33:20 +01:00
array ( '"' , '<b>' , '</b>' , '<u>' , '</u>' , '<i>' , '</i>' , '<center>' , '</center>' , '<a ' , '</a>' , '<br>' , '<span' , '</span>' , '< ' , '>' ),
2020-11-26 22:44:11 +01:00
$str
);
2023-10-21 02:39:27 +02:00
// Remove dangerous sequence we should never have. Not needed into a translated response.
// %27 is entity code for ' and is replaced by browser automatically when translation is inside a javascript code called by a click like on a href link.
$str = str_replace ( array ( '%27' , ''' ), '' , $str );
2021-02-23 22:03:23 +01:00
if ( $maxsize ) {
$str = dol_trunc ( $str , $maxsize );
}
2011-12-12 19:46:46 +01:00
2011-03-08 16:14:42 +01:00
return $str ;
2020-11-26 22:44:11 +01:00
} else { // Translation is not available
2011-12-07 18:10:24 +01:00
return $this -> getTradFromKey ( $key );
2007-05-26 00:23:03 +02:00
}
2020-10-31 14:32:18 +01:00
}
2008-07-28 11:09:03 +02:00
2009-01-15 23:49:06 +01:00
2008-10-20 03:05:41 +02:00
/**
2011-03-08 16:14:42 +01:00
* Return translated value of a text string
2019-10-20 18:44:07 +02:00
* If there is no match for this text , we look in alternative file and if still not found
* it is returned as is .
* Parameters of this method must not contain any HTML tags .
2011-08-16 01:17:14 +02:00
*
2011-12-07 18:10:24 +01:00
* @ param string $key Key to translate
* @ param string $param1 chaine de param1
* @ param string $param2 chaine de param2
* @ param string $param3 chaine de param3
* @ param string $param4 chaine de param4
2018-10-25 13:19:56 +02:00
* @ param string $param5 chaine de param5
2011-12-07 18:10:24 +01:00
* @ return string Translated string ( encoded into UTF8 )
2009-05-11 18:26:54 +02:00
*/
2019-02-26 22:42:19 +01:00
public function transnoentities ( $key , $param1 = '' , $param2 = '' , $param3 = '' , $param4 = '' , $param5 = '' )
2009-05-11 18:26:54 +02:00
{
2018-10-25 13:19:56 +02:00
return $this -> convToOutputCharset ( $this -> transnoentitiesnoconv ( $key , $param1 , $param2 , $param3 , $param4 , $param5 ));
2009-05-11 18:26:54 +02:00
}
/**
2010-11-13 02:58:19 +01:00
* Return translated value of a text string
2019-10-20 18:44:07 +02:00
* If there is no match for this text , we look in alternative file and if still not found ,
* it is returned as is .
* No conversion to encoding charset of lang object is done .
2009-05-11 18:26:54 +02:00
* Parameters of this method must not contains any HTML tags .
2011-08-16 01:17:14 +02:00
*
2011-12-07 18:10:24 +01:00
* @ param string $key Key to translate
* @ param string $param1 chaine de param1
* @ param string $param2 chaine de param2
* @ param string $param3 chaine de param3
* @ param string $param4 chaine de param4
2018-10-25 13:19:56 +02:00
* @ param string $param5 chaine de param5
2011-12-07 18:10:24 +01:00
* @ return string Translated string
2009-05-11 18:26:54 +02:00
*/
2025-01-08 18:24:46 +01:00
public function tr ( $key , $param1 = '' , $param2 = '' , $param3 = '' , $param4 = '' , $param5 = '' )
2009-05-11 18:26:54 +02:00
{
2025-01-08 18:24:46 +01:00
return $this -> transnoentitiesnoconv ( $key , $param1 , $param2 , $param3 , $param4 , $param5 );
}
2012-11-04 21:19:12 +01:00
2025-01-08 18:24:46 +01:00
/**
* Return translated value of a text string . Alias of tr () for backward compatibility .
* If there is no match for this text , we look in alternative file and if still not found ,
* it is returned as is .
* No conversion to encoding charset of lang object is done .
* Parameters of this method must not contains any HTML tags .
*
* @ param string $key Key to translate
* @ param string $param1 chaine de param1
* @ param string $param2 chaine de param2
* @ param string $param3 chaine de param3
* @ param string $param4 chaine de param4
* @ param string $param5 chaine de param5
* @ return string Translated string
*/
public function transnoentitiesnoconv ( $key , $param1 = '' , $param2 = '' , $param3 = '' , $param4 = '' , $param5 = '' )
{
2021-02-23 22:03:23 +01:00
if ( ! empty ( $this -> tab_translate [ $key ])) { // Translation is available
2020-10-31 14:32:18 +01:00
$str = $this -> tab_translate [ $key ];
// Make some string replacement after translation
2023-07-12 16:32:50 +02:00
$replacekey = 'MAIN_REPLACE_TRANS_' . $this -> defaultlang ;
2024-07-03 20:05:29 +02:00
if ( getDolGlobalString ( $replacekey )) { // Replacement translation variable with string1:newstring1;string2:newstring2
2023-12-13 15:20:53 +01:00
$tmparray = explode ( ';' , getDolGlobalString ( $replacekey ));
2021-02-23 22:03:23 +01:00
foreach ( $tmparray as $tmp ) {
2020-10-31 14:32:18 +01:00
$tmparray2 = explode ( ':' , $tmp );
2023-07-12 16:32:50 +02:00
$str = preg_replace ( '/' . preg_quote ( $tmparray2 [ 0 ]) . '/' , $tmparray2 [ 1 ], $str );
2020-10-31 14:32:18 +01:00
}
}
2021-02-23 22:03:23 +01:00
if ( ! preg_match ( '/^Format/' , $key )) {
2020-10-31 14:32:18 +01:00
//print $str;
2024-03-17 18:02:44 +01:00
// @phan-suppress-next-line PhanPluginPrintfVariableFormatString
2021-02-23 22:03:23 +01:00
$str = sprintf ( $str , $param1 , $param2 , $param3 , $param4 , $param5 ); // Replace %s and %d except for FormatXXX strings.
2020-10-31 14:32:18 +01:00
}
2023-10-21 02:39:27 +02:00
// Remove dangerous sequence we should never have. Not needed into a translated response.
// %27 is entity code for ' and is replaced by browser automatically when translation is inside a javascript code called by a click like on a href link.
$str = str_replace ( array ( '%27' , ''' ), '' , $str );
2020-10-31 14:32:18 +01:00
return $str ;
2020-05-21 15:05:19 +02:00
} else {
2012-11-04 21:19:12 +01:00
return $this -> getTradFromKey ( $key );
2009-05-11 18:26:54 +02:00
}
}
/**
2010-11-13 02:58:19 +01:00
* Return translation of a key depending on country
2011-08-16 01:17:14 +02:00
*
2012-01-14 14:27:27 +01:00
* @ param string $str string root to translate
* @ param string $countrycode country code ( FR , ... )
* @ return string translated string
2021-04-18 15:07:22 +02:00
* @ see transcountrynoentities (), picto_from_langcode ()
2009-05-11 18:26:54 +02:00
*/
2019-02-26 22:42:19 +01:00
public function transcountry ( $str , $countrycode )
2009-05-11 18:26:54 +02:00
{
2024-03-17 18:02:44 +01:00
$strLocaleKey = $str . $countrycode ;
2024-01-23 12:07:40 +01:00
if ( ! empty ( $this -> tab_translate [ $strLocaleKey ])) {
return $this -> trans ( $strLocaleKey );
2021-02-23 22:03:23 +01:00
} else {
return $this -> trans ( $str );
}
2009-05-11 18:26:54 +02:00
}
/**
2024-01-13 19:48:20 +01:00
* Retourne la version traduite du texte passe en parameter complete du code pays
2011-08-16 01:17:14 +02:00
*
2012-01-14 14:27:27 +01:00
* @ param string $str string root to translate
* @ param string $countrycode country code ( FR , ... )
* @ return string translated string
2021-04-18 15:07:22 +02:00
* @ see transcountry (), picto_from_langcode ()
2009-05-11 18:26:54 +02:00
*/
2019-02-26 22:42:19 +01:00
public function transcountrynoentities ( $str , $countrycode )
2009-05-11 18:26:54 +02:00
{
2024-03-17 18:02:44 +01:00
$strLocaleKey = $str . $countrycode ;
2024-01-23 12:07:40 +01:00
if ( ! empty ( $this -> tab_translate [ $strLocaleKey ])) {
return $this -> transnoentities ( $strLocaleKey );
2021-02-23 22:03:23 +01:00
} else {
return $this -> transnoentities ( $str );
}
2009-05-11 18:26:54 +02:00
}
/**
2010-11-13 02:58:19 +01:00
* Convert a string into output charset ( this -> charset_output that should be defined to conf -> file -> character_set_client )
2011-08-16 01:17:14 +02:00
*
2012-01-14 14:27:27 +01:00
* @ param string $str String to convert
* @ param string $pagecodefrom Page code of src string
2024-10-05 14:51:45 +02:00
* @ param string $pagecodeto Expected page code of returned string
2012-01-14 14:27:27 +01:00
* @ return string Converted string
2009-05-11 18:26:54 +02:00
*/
2024-10-05 14:51:45 +02:00
public function convToOutputCharset ( $str , $pagecodefrom = 'UTF-8' , $pagecodeto = '' )
2009-05-11 18:26:54 +02:00
{
2024-10-05 14:51:45 +02:00
if ( empty ( $pagecodeto )) {
$pagecodeto = $this -> charset_output ;
}
if ( $pagecodefrom == 'ISO-8859-1' && $pagecodeto == 'UTF-8' ) {
2023-12-07 03:37:05 +01:00
$str = mb_convert_encoding ( $str , 'UTF-8' , 'ISO-8859-1' );
2021-02-23 22:03:23 +01:00
}
2024-10-05 14:51:45 +02:00
if ( $pagecodefrom == 'UTF-8' && $pagecodeto == 'ISO-8859-1' ) {
2023-12-07 03:37:05 +01:00
$str = mb_convert_encoding ( str_replace ( '€' , chr ( 128 ), $str ), 'ISO-8859-1' );
2023-06-27 01:19:22 +02:00
// TODO Replace with iconv("UTF-8", "ISO-8859-1", str_replace('€', chr(128), $str)); ?
2021-02-23 22:03:23 +01:00
}
2007-05-26 00:23:03 +02:00
return $str ;
2009-05-11 18:26:54 +02:00
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-05-11 18:26:54 +02:00
/**
2010-11-13 02:58:19 +01:00
* Return list of all available languages
2011-08-16 01:17:14 +02:00
*
2024-10-14 01:59:44 +02:00
* @ param string $langdir Directory to scan
* @ param int $maxlength Max length for each value in combo box ( will be truncated )
* @ param int < 0 , 1 > $usecode 1 = Show code instead of country name for language variant , 2 = Show only code
* @ param int < 0 , 1 > $mainlangonly 1 = Show only main languages ( 'fr_FR' no ' fr_BE' , 'es_ES' not 'es_MX' , ... )
* @ return array < string , string > List of languages
2009-05-11 18:26:54 +02:00
*/
2020-02-21 11:36:16 +01:00
public function get_available_languages ( $langdir = DOL_DOCUMENT_ROOT , $maxlength = 0 , $usecode = 0 , $mainlangonly = 0 )
2020-10-31 14:32:18 +01:00
{
// phpcs:enable
2020-02-21 11:36:16 +01:00
$this -> load ( " languages " );
2009-05-11 18:26:54 +02:00
// We scan directory langs to detect available languages
2023-07-12 16:32:50 +02:00
$handle = opendir ( $langdir . " /langs " );
2020-01-16 02:54:00 +01:00
$langs_available = array ();
2021-02-23 22:03:23 +01:00
while ( $dir = trim ( readdir ( $handle ))) {
2020-02-21 11:36:16 +01:00
$regs = array ();
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/^([a-z]+)_([A-Z]+)/i' , $dir , $regs )) {
2020-02-21 11:36:16 +01:00
// We must keep only main languages
if ( $mainlangonly ) {
2020-02-27 21:43:11 +01:00
$arrayofspecialmainlanguages = array (
2023-07-12 16:32:50 +02:00
'en' => 'en_US' ,
'am' => 'am_ET' ,
'ar' => 'ar_SA' ,
'bn' => 'bn_DB' ,
'bs' => 'bs_BA' ,
'ca' => 'ca_ES' ,
'cs' => 'cs_CZ' ,
'da' => 'da_DK' ,
'et' => 'et_EE' ,
'el' => 'el_GR' ,
'eu' => 'eu_ES' ,
'fa' => 'fa_IR' ,
'he' => 'he_IL' ,
'ka' => 'ka_GE' ,
'km' => 'km_KH' ,
'kn' => 'kn_IN' ,
'ko' => 'ko_KR' ,
'ja' => 'ja_JP' ,
'lo' => 'lo_LA' ,
'nb' => 'nb_NO' ,
'sq' => 'sq_AL' ,
'sr' => 'sr_RS' ,
'sv' => 'sv_SE' ,
'sl' => 'sl_SI' ,
'uk' => 'uk_UA' ,
'vi' => 'vi_VN' ,
'zh' => 'zh_CN'
2020-02-27 21:43:11 +01:00
);
2021-02-23 22:03:23 +01:00
if ( strtolower ( $regs [ 1 ]) != strtolower ( $regs [ 2 ]) && ! in_array ( $dir , $arrayofspecialmainlanguages )) {
continue ;
}
2020-02-21 11:36:16 +01:00
}
// We must keep only languages into MAIN_LANGUAGES_ALLOWED
2023-12-13 15:20:53 +01:00
if ( getDolGlobalString ( 'MAIN_LANGUAGES_ALLOWED' ) && ! in_array ( $dir , explode ( ',' , getDolGlobalString ( 'MAIN_LANGUAGES_ALLOWED' )))) {
2021-02-23 22:03:23 +01:00
continue ;
}
2010-02-20 14:15:28 +01:00
2021-02-23 22:03:23 +01:00
if ( $usecode == 2 ) {
2020-10-31 14:32:18 +01:00
$langs_available [ $dir ] = $dir ;
2016-02-23 19:50:33 +01:00
}
2020-02-21 11:36:16 +01:00
2023-11-27 11:24:19 +01:00
if ( $usecode == 1 || getDolGlobalString ( 'MAIN_SHOW_LANGUAGE_CODE' )) {
2023-07-12 16:32:50 +02:00
$langs_available [ $dir ] = $dir . ': ' . dol_trunc ( $this -> trans ( 'Language_' . $dir ), $maxlength );
2020-05-21 15:05:19 +02:00
} else {
2023-07-12 16:32:50 +02:00
$langs_available [ $dir ] = $this -> trans ( 'Language_' . $dir );
2010-03-03 08:42:11 +01:00
}
2020-02-21 11:36:16 +01:00
if ( $mainlangonly ) {
$langs_available [ $dir ] = str_replace ( ' (United States)' , '' , $langs_available [ $dir ]);
}
2009-05-11 18:26:54 +02:00
}
}
return $langs_available ;
2020-10-31 14:32:18 +01:00
}
2009-05-11 18:26:54 +02:00
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-05-11 18:26:54 +02:00
/**
2010-11-13 02:58:19 +01:00
* Return if a filename $filename exists for current language ( or alternate language )
2011-08-16 01:17:14 +02:00
*
2012-01-14 14:27:27 +01:00
* @ param string $filename Language filename to search
2024-10-29 22:44:47 +01:00
* @ param int $searchalt Search also alternate language file
* @ return bool true if exists and readable
2009-05-11 18:26:54 +02:00
*/
2020-10-31 14:32:18 +01:00
public function file_exists ( $filename , $searchalt = 0 )
{
// phpcs:enable
2009-05-11 18:26:54 +02:00
// Test si fichier dans repertoire de la langue
2021-02-23 22:03:23 +01:00
foreach ( $this -> dir as $searchdir ) {
2023-07-12 16:32:50 +02:00
if ( is_readable ( dol_osencode ( $searchdir . " /langs/ " . $this -> defaultlang . " / " . $filename ))) {
2021-02-23 22:03:23 +01:00
return true ;
}
2009-05-11 18:26:54 +02:00
2021-02-23 22:03:23 +01:00
if ( $searchalt ) {
2024-10-29 22:44:47 +01:00
$filenamealt = null ;
2009-05-11 18:26:54 +02:00
// Test si fichier dans repertoire de la langue alternative
2021-02-23 22:03:23 +01:00
if ( $this -> defaultlang != " en_US " ) {
2023-07-12 16:32:50 +02:00
$filenamealt = $searchdir . " /langs/en_US/ " . $filename ;
2021-02-23 22:03:23 +01:00
}
2014-08-08 10:50:37 +02:00
//else $filenamealt = $searchdir."/langs/fr_FR/".$filename;
2024-10-29 22:44:47 +01:00
if ( $filenamealt !== null && is_readable ( dol_osencode ( $filenamealt ))) {
2021-02-23 22:03:23 +01:00
return true ;
}
2009-05-11 18:26:54 +02:00
}
2008-12-12 03:16:14 +01:00
}
2009-01-15 23:49:06 +01:00
2009-05-11 18:26:54 +02:00
return false ;
2020-10-31 14:32:18 +01:00
}
2009-05-11 18:26:54 +02:00
2009-08-25 16:36:03 +02:00
/**
2010-11-13 02:58:19 +01:00
* Return full text translated to language label for a key . Store key - label in a cache .
2020-10-31 14:32:18 +01:00
* This function need module " numberwords " to be installed . If not it will return
* same number ( this module is not provided by default as it use non GPL source code ) .
2011-08-16 01:17:14 +02:00
*
2022-07-24 13:44:47 +02:00
* @ param int | string $number Number to encode in full text
* @ param string $isamount '' = it 's just a number, ' 1 '=It' s an amount ( default currency ), 'currencycode' = It ' s an amount ( foreign currency )
* @ return string Label translated in UTF8 ( but without entities )
* 10 if setDefaultLang was en_US => ten
* 123 if setDefaultLang was fr_FR => cent vingt trois
2009-08-25 16:36:03 +02:00
*/
2020-10-31 14:32:18 +01:00
public function getLabelFromNumber ( $number , $isamount = '' )
{
2009-08-25 22:57:54 +02:00
global $conf ;
2020-01-16 02:54:00 +01:00
$newnumber = $number ;
2012-02-22 16:18:03 +01:00
2020-01-16 02:54:00 +01:00
$dirsubstitutions = array_merge ( array (), $conf -> modules_parts [ 'substitutions' ]);
2021-02-23 22:03:23 +01:00
foreach ( $dirsubstitutions as $reldir ) {
2020-10-31 14:32:18 +01:00
$dir = dol_buildpath ( $reldir , 0 );
$newdir = dol_osencode ( $dir );
2012-02-22 16:18:03 +01:00
2020-10-31 14:32:18 +01:00
// Check if directory exists
2021-02-23 22:03:23 +01:00
if ( ! is_dir ( $newdir )) {
continue ; // We must not use dol_is_dir here, function may not be loaded
}
2012-02-22 16:18:03 +01:00
2020-01-16 02:54:00 +01:00
$fonc = 'numberwords' ;
2023-07-12 16:32:50 +02:00
if ( file_exists ( $newdir . '/functions_' . $fonc . '.lib.php' )) {
include_once $newdir . '/functions_' . $fonc . '.lib.php' ;
2023-01-11 17:06:23 +01:00
if ( function_exists ( 'numberwords_getLabelFromNumber' )) {
$newnumber = numberwords_getLabelFromNumber ( $this , $number , $isamount );
break ;
}
2009-08-25 22:57:54 +02:00
}
}
2009-08-25 16:36:03 +02:00
2009-08-25 22:57:54 +02:00
return $newnumber ;
2020-10-31 14:32:18 +01:00
}
2009-08-25 16:36:03 +02:00
2009-05-11 18:26:54 +02:00
/**
2012-10-04 09:44:04 +02:00
* Return a label for a key .
* Search into translation array , then into cache , then if still not found , search into database .
* Store key - label found into cache variable $this -> cache_labels to save SQL requests to get labels .
2011-08-16 01:17:14 +02:00
*
2014-05-03 13:42:34 +02:00
* @ param DoliDB $db Database handler
2013-05-12 17:09:48 +02:00
* @ param string $key Translation key to get label ( key in language file )
2022-01-09 20:25:10 +01:00
* @ param string $tablename Table name without prefix . This value must always be a hardcoded string and not a value coming from user input .
* @ param string $fieldkey Field for key . This value must always be a hardcoded string and not a value coming from user input .
* @ param string $fieldlabel Field for label . This value must always be a hardcoded string and not a value coming from user input .
2013-05-12 17:09:48 +02:00
* @ param string $keyforselect Use another value than the translation key for the where into select
2017-10-03 17:41:22 +02:00
* @ param int $filteronentity Use a filter on entity
2024-07-29 01:21:08 +02:00
* @ return string | int Label in UTF8 ( not HTML entity encoded ) or - 1 if error
2019-03-11 12:07:28 +01:00
* @ see dol_getIdFromCode ()
2009-05-11 18:26:54 +02:00
*/
2020-10-31 14:32:18 +01:00
public function getLabelFromKey ( $db , $key , $tablename , $fieldkey , $fieldlabel , $keyforselect = '' , $filteronentity = 0 )
{
2009-05-11 18:26:54 +02:00
// If key empty
2021-02-23 22:03:23 +01:00
if ( $key == '' ) {
return '' ;
}
2022-01-09 20:25:10 +01:00
// Test should be useless because the 3 variables are never set from user input but we keep it in case of.
if ( preg_match ( '/[^0-9A-Z_]/i' , $tablename ) || preg_match ( '/[^0-9A-Z_]/i' , $fieldkey ) || preg_match ( '/[^0-9A-Z_]/i' , $fieldlabel )) {
$this -> error = 'Bad value for parameter tablename, fieldkey or fieldlabel' ;
return - 1 ;
}
2012-10-03 17:47:53 +02:00
2020-10-31 14:32:18 +01:00
//print 'param: '.$key.'-'.$keydatabase.'-'.$this->trans($key); exit;
2008-06-30 21:34:53 +02:00
2022-01-09 20:25:10 +01:00
// Check if a translation is available (Note: this can call getTradFromKey that can call getLabelFromKey)
2020-01-16 02:54:00 +01:00
$tmp = $this -> transnoentitiesnoconv ( $key );
2021-02-23 22:03:23 +01:00
if ( $tmp != $key && $tmp != 'ErrorBadValueForParamNotAString' ) {
2020-01-16 02:54:00 +01:00
return $tmp ; // Found in language array
2009-05-11 18:26:54 +02:00
}
2009-01-15 23:49:06 +01:00
2008-06-30 21:34:53 +02:00
// Check in cache
2021-02-23 22:03:23 +01:00
if ( isset ( $this -> cache_labels [ $tablename ][ $key ])) { // Can be defined to 0 or ''
2020-01-16 02:54:00 +01:00
return $this -> cache_labels [ $tablename ][ $key ]; // Found in cache
2009-05-11 18:26:54 +02:00
}
2022-01-09 20:25:10 +01:00
// Not found in loaded language file nor in cache. So we will take the label into database.
2023-07-12 16:32:50 +02:00
$sql = " SELECT " . $fieldlabel . " as label " ;
$sql .= " FROM " . $db -> prefix () . $tablename ;
$sql .= " WHERE " . $fieldkey . " = ' " . $db -> escape ( $keyforselect ? $keyforselect : $key ) . " ' " ;
2021-02-23 22:03:23 +01:00
if ( $filteronentity ) {
2023-07-12 16:32:50 +02:00
$sql .= " AND entity IN ( " . getEntity ( $tablename ) . ')' ;
2021-02-23 22:03:23 +01:00
}
2023-07-12 16:32:50 +02:00
dol_syslog ( get_class ( $this ) . '::getLabelFromKey' , LOG_DEBUG );
2009-05-11 18:26:54 +02:00
$resql = $db -> query ( $sql );
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2009-05-11 18:26:54 +02:00
$obj = $db -> fetch_object ( $resql );
2021-02-23 22:03:23 +01:00
if ( $obj ) {
2024-10-29 22:44:47 +01:00
$this -> cache_labels [ $tablename ][ $key ] = ( string ) $obj -> label ;
2021-02-23 22:03:23 +01:00
} else {
$this -> cache_labels [ $tablename ][ $key ] = $key ;
}
2010-10-18 20:18:12 +02:00
2009-05-11 18:26:54 +02:00
$db -> free ( $resql );
return $this -> cache_labels [ $tablename ][ $key ];
2020-05-21 15:05:19 +02:00
} else {
2020-01-16 02:54:00 +01:00
$this -> error = $db -> lasterror ();
2009-05-11 18:26:54 +02:00
return - 1 ;
}
2020-10-31 14:32:18 +01:00
}
2008-10-20 03:05:41 +02:00
2013-01-18 15:57:11 +01:00
/**
* Return a currency code into its symbol
*
2013-04-04 13:58:33 +02:00
* @ param string $currency_code Currency Code
2013-01-18 15:57:11 +01:00
* @ param string $amount If not '' , show currency + amount according to langs ( $ 10 , 10 € ) .
* @ return string Amount + Currency symbol encoded into UTF8
2014-10-16 01:26:44 +02:00
* @ deprecated Use method price to output a price
2015-04-23 23:21:06 +02:00
* @ see price ()
2013-01-18 15:57:11 +01:00
*/
2020-10-31 14:32:18 +01:00
public function getCurrencyAmount ( $currency_code , $amount )
2013-01-18 15:57:11 +01:00
{
2020-01-16 02:54:00 +01:00
$symbol = $this -> getCurrencySymbol ( $currency_code );
2013-01-18 15:57:11 +01:00
2021-02-23 22:03:23 +01:00
if ( in_array ( $currency_code , array ( 'USD' ))) {
2023-07-12 16:32:50 +02:00
return $symbol . $amount ;
2021-02-23 22:03:23 +01:00
} else {
2023-07-12 16:32:50 +02:00
return $amount . $symbol ;
2021-02-23 22:03:23 +01:00
}
2013-01-18 15:57:11 +01:00
}
2013-01-19 16:29:16 +01:00
/**
2017-06-09 09:25:15 +02:00
* Return a currency code into its symbol .
2016-04-30 14:09:00 +02:00
* If mb_convert_encoding is not available , return currency code .
2013-01-19 16:29:16 +01:00
*
2013-01-18 15:57:11 +01:00
* @ param string $currency_code Currency code
2019-03-14 11:48:25 +01:00
* @ 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 .
2013-01-19 16:29:16 +01:00
* @ return string Currency symbol encoded into UTF8
*/
2020-10-31 14:32:18 +01:00
public function getCurrencySymbol ( $currency_code , $forceloadall = 0 )
{
2020-01-16 02:54:00 +01:00
$currency_sign = '' ; // By default return iso code
2013-01-19 16:29:16 +01:00
2021-02-23 22:03:23 +01:00
if ( function_exists ( " mb_convert_encoding " )) {
2020-01-16 02:54:00 +01:00
$this -> loadCacheCurrencies ( $forceloadall ? '' : $currency_code );
2013-01-18 15:57:11 +01:00
2024-10-29 22:44:47 +01:00
if ( isset ( $this -> cache_currencies [ $currency_code ]) && ! empty ( $this -> cache_currencies [ $currency_code ][ 'unicode' ]) && is_array ( $this -> cache_currencies [ $currency_code ][ 'unicode' ])) { // @phan-suppress-current-line PhanTypeMismatchProperty
2021-02-23 22:03:23 +01:00
foreach ( $this -> cache_currencies [ $currency_code ][ 'unicode' ] as $unicode ) {
2023-07-12 16:32:50 +02:00
$currency_sign .= mb_convert_encoding ( " &# " . $unicode . " ; " , " UTF-8 " , 'HTML-ENTITIES' );
2013-01-18 15:57:11 +01:00
}
2013-01-19 16:29:16 +01:00
}
}
2020-01-16 02:54:00 +01:00
return ( $currency_sign ? $currency_sign : $currency_code );
2020-10-31 14:32:18 +01:00
}
2013-01-18 15:57:11 +01:00
2013-01-19 16:29:16 +01:00
/**
2014-05-01 16:11:29 +02:00
* Load into the cache this -> cache_currencies , all currencies
2013-01-18 15:57:11 +01:00
*
2013-01-19 16:29:16 +01:00
* @ param string $currency_code Get only currency . Get all if '' .
* @ return int Nb of loaded lines , 0 if already loaded , < 0 if KO
*/
2014-05-14 12:19:45 +02:00
public function loadCacheCurrencies ( $currency_code )
2013-01-18 15:57:11 +01:00
{
global $db ;
2013-01-19 16:29:16 +01:00
2021-02-23 22:03:23 +01:00
if ( $this -> cache_currencies_all_loaded ) {
return 0 ; // Cache already loaded for all
}
if ( ! empty ( $currency_code ) && isset ( $this -> cache_currencies [ $currency_code ])) {
return 0 ; // Cache already loaded for the currency
}
2013-01-19 16:29:16 +01:00
$sql = " SELECT code_iso, label, unicode " ;
2023-07-12 16:32:50 +02:00
$sql .= " FROM " . $db -> prefix () . " c_currencies " ;
2020-01-16 02:54:00 +01:00
$sql .= " WHERE active = 1 " ;
2021-02-23 22:03:23 +01:00
if ( ! empty ( $currency_code )) {
2023-07-12 16:32:50 +02:00
$sql .= " AND code_iso = ' " . $db -> escape ( $currency_code ) . " ' " ;
2021-02-23 22:03:23 +01:00
}
2013-01-19 16:29:16 +01:00
//$sql.= " ORDER BY code_iso ASC"; // Not required, a sort is done later
2023-07-12 16:32:50 +02:00
dol_syslog ( get_class ( $this ) . '::loadCacheCurrencies' , LOG_DEBUG );
2013-01-19 16:29:16 +01:00
$resql = $db -> query ( $sql );
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2013-01-18 15:57:11 +01:00
$this -> load ( " dict " );
2020-01-16 02:54:00 +01:00
$label = array ();
2021-02-23 22:03:23 +01:00
if ( ! empty ( $currency_code )) {
foreach ( $this -> cache_currencies as $key => $val ) {
$label [ $key ] = $val [ 'label' ]; // Label in already loaded cache
}
}
2013-01-18 15:57:11 +01:00
2013-01-19 16:29:16 +01:00
$num = $db -> num_rows ( $resql );
$i = 0 ;
2021-02-23 22:03:23 +01:00
while ( $i < $num ) {
2013-01-19 16:29:16 +01:00
$obj = $db -> fetch_object ( $resql );
2022-05-08 15:18:34 +02:00
if ( $obj ) {
// If a translation exists, we use it lese we use the default label
2023-07-12 16:32:50 +02:00
$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 : '' ));
2024-10-29 22:44:47 +01:00
$this -> cache_currencies [ $obj -> code_iso ][ 'unicode' ] = ( array ) json_decode (( empty ( $obj -> unicode ) ? '' : $obj -> unicode ), true ); // @phan-suppress-current-line PhanTypeMismatchProperty
2022-05-08 15:18:34 +02:00
$label [ $obj -> code_iso ] = $this -> cache_currencies [ $obj -> code_iso ][ 'label' ];
}
2013-01-19 16:29:16 +01:00
$i ++ ;
}
2021-02-23 22:03:23 +01:00
if ( empty ( $currency_code )) {
$this -> cache_currencies_all_loaded = true ;
}
2013-06-19 23:46:18 +02:00
//print count($label).' '.count($this->cache_currencies);
2017-04-14 18:08:02 +02:00
// Resort cache
2013-01-19 16:29:16 +01:00
array_multisort ( $label , SORT_ASC , $this -> cache_currencies );
2013-06-19 23:46:18 +02:00
//var_dump($this->cache_currencies); $this->cache_currencies is now sorted onto label
2013-01-19 16:29:16 +01:00
return $num ;
2020-05-21 15:05:19 +02:00
} else {
2013-01-19 16:29:16 +01:00
dol_print_error ( $db );
return - 1 ;
}
2013-01-18 15:57:11 +01:00
}
2013-10-08 09:17:04 +02:00
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2014-05-01 16:11:29 +02:00
/**
2015-10-19 13:23:45 +02:00
* Return an array with content of all loaded translation keys ( found into this -> tab_translate ) so
* we get a substitution array we can use for substitutions ( for mail or ODT generation for example )
2014-05-01 16:11:29 +02:00
*
2024-10-14 01:59:44 +02:00
* @ return array < string , string > Array of translation keys lang_key => string_translation_loaded
2014-05-01 16:11:29 +02:00
*/
2020-10-31 14:32:18 +01:00
public function get_translations_for_substitutions ()
{
// phpcs:enable
$substitutionarray = array ();
foreach ( $this -> tab_translate as $code => $label ) {
2023-07-12 16:32:50 +02:00
$substitutionarray [ 'lang_' . $code ] = $label ;
$substitutionarray [ '__(' . $code . ')__' ] = $label ;
2020-10-31 14:32:18 +01:00
}
return $substitutionarray ;
}
2003-05-02 12:33:06 +02:00
}