diff --git a/htdocs/core/class/translate.class.php b/htdocs/core/class/translate.class.php
index e477bdeb714..27bcb64da3c 100644
--- a/htdocs/core/class/translate.class.php
+++ b/htdocs/core/class/translate.class.php
@@ -29,17 +29,17 @@
*/
class Translate
{
- var $dir; // Directories that contains /langs subdirectory
+ var $dir; // Directories that contains /langs subdirectory
- var $defaultlang; // Current language for current user
- var $direction = 'ltr'; // Left to right or Right to left
- var $charset_output='UTF-8'; // Codage used by "trans" method outputs
+ var $defaultlang; // Current language for current user
+ var $direction = 'ltr'; // Left to right or Right to left
+ var $charset_output='UTF-8'; // Codage used by "trans" method outputs
- var $tab_translate=array(); // Array of all translations key=>value
- private $_tab_loaded=array(); // Array to store result after loading each language file
+ var $tab_translate=array(); // Array of all translations key=>value
+ private $_tab_loaded=array(); // Array to store result after loading each language file
- var $cache_labels=array(); // Cache for labels return by getLabelFromKey method
- var $cache_currencies=array(); // Cache to store currency symbols
+ var $cache_labels=array(); // Cache for labels return by getLabelFromKey method
+ var $cache_currencies=array(); // Cache to store currency symbols
@@ -157,9 +157,11 @@ class Translate
* @param int $forcelangdir To force a different lang directory
* @return int <0 if KO, 0 if already loaded or loading not required, >0 if OK
*/
- function Load($domain,$alt=0,$stopafterdirection=0,$forcelangdir='')
+ function load($domain,$alt=0,$stopafterdirection=0,$forcelangdir='')
{
- global $conf;
+ global $conf,$db;
+
+ if (count($this->tab_translate) == 0) $this->loadFromDatabase($db); // Nothing was loaded yet, so we load database.
// Check parameters
if (empty($domain))
@@ -239,7 +241,7 @@ class Translate
$tmparray=dol_getcache($usecachekey);
if (is_array($tmparray) && count($tmparray))
{
- $this->tab_translate=array_merge($tmparray,$this->tab_translate); // Already found values tab_translate overwrites duplicates
+ $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.
//print $newdomain."\n";
//var_dump($this->tab_translate);
if ($alt == 2) $fileread=1;
@@ -329,11 +331,12 @@ class Translate
if (empty($this->_tab_loaded[$newdomain])) $this->_tab_loaded[$newdomain]=2; // Marque ce fichier comme non trouve
}
-
- // Overwrite translation
+ // This part is deprecated and replaced with table llx_overwrite_trans
+ // Kept for backward compatibility.
$overwritekey='MAIN_OVERWRITE_TRANS_'.$this->defaultlang;
if (! empty($conf->global->$overwritekey)) // Overwrite translation with key1:newstring1,key2:newstring2
{
+ // Overwrite translation with param MAIN_OVERWRITE_TRANS_xx_XX
$tmparray=explode(',', $conf->global->$overwritekey);
foreach($tmparray as $tmp)
{
@@ -342,13 +345,167 @@ class Translate
}
}
- // Check to be sure that SeparatorDecimal differs from SeparatorThousand
+
+
+ // Check to be sure that SeparatorDecimal differs from SeparatorThousand
if (! empty($this->tab_translate["SeparatorDecimal"]) && ! empty($this->tab_translate["SeparatorThousand"])
&& $this->tab_translate["SeparatorDecimal"] == $this->tab_translate["SeparatorThousand"]) $this->tab_translate["SeparatorThousand"]='';
return 1;
}
+ /**
+ * 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.
+ * 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
+ *
+ * @param Database $db Database handler
+ * @return int <0 if KO, 0 if already loaded or loading not required, >0 if OK
+ */
+ function loadFromDatabase($db)
+ {
+ global $conf;
+
+ $domain='database';
+
+ if ($this->defaultlang == 'none_NONE') return 0; // Special language code to not translate keys
+
+ // Check parameters
+ if (empty($db)) return 0; // Database handler can't be used
+
+ //dol_syslog("Translate::Load Start domain=".$domain." alt=".$alt." forcelangdir=".$forcelangdir." this->defaultlang=".$this->defaultlang);
+
+ $newdomain = $domain;
+ $modulename = '';
+
+ // Check cache
+ if (! empty($this->_tab_loaded[$newdomain])) // File already loaded for this domain
+ {
+ //dol_syslog("Translate::Load already loaded for newdomain=".$newdomain);
+ return 0;
+ }
+
+ $this->_tab_loaded[$newdomain] = 1; // We want to be sure this function is called once only.
+
+ $fileread=0;
+ $langofdir=(empty($forcelangdir)?$this->defaultlang:$forcelangdir);
+
+ // Redefine alt
+ $alt=2;
+
+ if (empty($langofdir)) // This may occurs when load is called without setting the language and without providing a value for forcelangdir
+ {
+ dol_syslog("Error: ".get_class($this)."::Load was called but language was not set yet with langs->setDefaultLang(). Nothing will be loaded.", LOG_WARNING);
+ return -1;
+ }
+
+ // TODO Move cache read out of loop on dirs or at least filelangexists
+ $found=false;
+
+ // Enable caching of lang file in memory (not by default)
+ $usecachekey='';
+ // Using a memcached server
+ if (! empty($conf->memcached->enabled) && ! empty($conf->global->MEMCACHED_SERVER))
+ {
+ $usecachekey=$newdomain.'_'.$langofdir.'_'.md5($file_lang); // Should not contains special chars
+ }
+ // Using cache with shmop. Speed gain: 40ms - Memory overusage: 200ko (Size of session cache file)
+ else if (isset($conf->global->MAIN_OPTIMIZE_SPEED) && ($conf->global->MAIN_OPTIMIZE_SPEED & 0x02))
+ {
+ $usecachekey=$newdomain;
+ }
+
+ if ($usecachekey)
+ {
+ //dol_syslog('Translate::Load we will cache result into usecachekey '.$usecachekey);
+ //global $aaa; $aaa+=1;
+ //print $aaa." ".$usecachekey."\n";
+ require_once DOL_DOCUMENT_ROOT .'/core/lib/memory.lib.php';
+ $tmparray=dol_getcache($usecachekey);
+ if (is_array($tmparray) && count($tmparray))
+ {
+ $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.
+ //print $newdomain."\n";
+ //var_dump($this->tab_translate);
+ if ($alt == 2) $fileread=1;
+ $found=true; // Found in dolibarr PHP cache
+ }
+ }
+
+ if (! $found)
+ {
+ // Overwrite translation with database read
+ $sql="SELECT transkey, transvalue FROM ".MAIN_DB_PREFIX."overwrite_trans where lang='".$this->defaultlang."'";
+ $resql=$db->query($sql);
+
+ if ($resql)
+ {
+ $num = $db->num_rows($resql);
+ if ($num)
+ {
+ if ($usecachekey) $tabtranslatedomain=array(); // To save lang content in cache
+
+ $i = 0;
+ while ($i < $num) // Ex: Need 225ms for all fgets on all lang file for Third party page. Same speed than file_get_contents
+ {
+ $obj=$db->fetch_object($resql);
+
+ $key=$obj->transkey;
+ $value=$obj->transvalue;
+
+ //print "Domain=$domain, found a string for $tab[0] with value $tab[1]
";
+ 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)
+ {
+ $value=trim(preg_replace('/\\n/',"\n",$value));
+
+ $this->tab_translate[$key]=$value;
+ if ($usecachekey) $tabtranslatedomain[$key]=$value; // To save lang content in cache
+ }
+
+ $i++;
+ }
+
+ $fileread=1;
+
+ // TODO Move cache write out of loop on dirs
+ // 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);
+ }
+ }
+ }
+ }
+ else
+ {
+ dol_print_error($db);
+ }
+ }
+
+ if ($alt == 2)
+ {
+ if ($fileread) $this->_tab_loaded[$newdomain]=1; // Set domain file as loaded
+
+ if (empty($this->_tab_loaded[$newdomain])) $this->_tab_loaded[$newdomain]=2; // Marque ce cas comme non trouve (no lines found for language)
+ }
+
+ // Check to be sure that SeparatorDecimal differs from SeparatorThousand
+ if (! empty($this->tab_translate["SeparatorDecimal"]) && ! empty($this->tab_translate["SeparatorThousand"])
+ && $this->tab_translate["SeparatorDecimal"] == $this->tab_translate["SeparatorThousand"]) $this->tab_translate["SeparatorThousand"]='';
+
+ return 1;
+ }
+
+
+
/**
* 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, ...
diff --git a/htdocs/install/mysql/migration/3.8.0-3.9.0.sql b/htdocs/install/mysql/migration/3.8.0-3.9.0.sql
index dc778fd0eca..f9e649dfaf5 100755
--- a/htdocs/install/mysql/migration/3.8.0-3.9.0.sql
+++ b/htdocs/install/mysql/migration/3.8.0-3.9.0.sql
@@ -31,3 +31,13 @@ ALTER TABLE llx_accountingaccount RENAME TO llx_accounting_account;
ALTER TABLE llx_societe ADD COLUMN model_pdf varchar(255);
ALTER TABLE llx_societe_commerciaux ADD COLUMN import_key varchar(14) AFTER fk_user;
+
+
+create table llx_overwrite_trans
+(
+ rowid integer AUTO_INCREMENT PRIMARY KEY,
+ lang varchar(5), -- en_US, fr_FR ...
+ transkey varchar(128),
+ transvalue text
+)ENGINE=innodb;
+
diff --git a/htdocs/install/mysql/tables/llx_overwrite_trans.sql b/htdocs/install/mysql/tables/llx_overwrite_trans.sql
new file mode 100644
index 00000000000..152fe5e7a0c
--- /dev/null
+++ b/htdocs/install/mysql/tables/llx_overwrite_trans.sql
@@ -0,0 +1,27 @@
+-- ============================================================================
+-- Copyright (C) 2013 Laurent Destailleur
+--
+-- 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
+-- the Free Software Foundation; either version 3 of the License, or
+-- (at your option) 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
+-- along with this program. If not, see .
+-- ============================================================================
+
+
+create table llx_overwrite_trans
+(
+ rowid integer AUTO_INCREMENT PRIMARY KEY,
+ lang varchar(5), -- en_US, fr_FR ...
+ transkey varchar(128),
+ transvalue text
+)ENGINE=innodb;
+
+