languages
[ class tree: languages ] [ index: languages ] [ all elements ]

Source for file BitLanguage.php

Documentation is available at BitLanguage.php

  1. <?php
  2. /**
  3.  * @package languages
  4.  * @version $Header$
  5.  *
  6.  *  Copyright (c) 2005 bitweaver.org
  7.  *  Copyright (c) 2004-2005, Christian Fowler, et. al.
  8.  *  All Rights Reserved. See below for details and a complete list of authors.
  9.  *  Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See http://www.gnu.org/copyleft/lesser.html for details
  10.  * @author spider <spider@steelsun.com>
  11.  */
  12.  
  13. /**
  14.  * @package languages
  15.  */
  16. class BitLanguage extends BitSingleton {
  17.     // list of available (non-disabled) languages
  18.     var $mLanguageList;
  19.  
  20.     var $mLanguage;
  21.  
  22.     /**
  23.      * initiate BitLanguage
  24.      */
  25.     function __construct() {
  26.         parent::__construct();
  27.         global $gBitSystem;
  28.  
  29.         # TODO - put '@' here due to beta1->beta2 upgrades - wolff_borg
  30.         $this->mLanguageList = $this->listLanguages();
  31.  
  32.         if (isset($_SESSION['bitlanguage'])) {
  33.             // users not logged that change the preference
  34.             $this->setLanguage( $_SESSION['bitlanguage'] );
  35.         } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && $gBitSystem->isFeatureActive( 'i18n_browser_languages' )) {
  36.             // Get supported languages
  37.             if( $browserLangs = preg_split( '/,/', preg_replace('/;q=[0-9.]+/', '', $_SERVER['HTTP_ACCEPT_LANGUAGE']) ) ) {
  38.                 foreach( $browserLangs as $bl ) {
  39.                     if( !empty( $this->mLanguageList[$bl] ) ) {
  40.                         $this->setLanguage( $bl );
  41.                         break;
  42.                     } elseif( strpos( $bl, '-' ) )  {
  43.                         $baseLang = substr( $bl, 0, 2 );
  44.                         if( !empty( $this->mLanguageList[$baseLang] ) ) {
  45.                             $this->setLanguage( $baseLang );
  46.                             break;
  47.                         }
  48.                     }
  49.                 }
  50.             }
  51.         }
  52.         if( empty( $this->mLanguage ) ) {
  53.             $this->setLanguage( $gBitSystem->getConfig('bitlanguage', 'en') );
  54.         }
  55.     }
  56.  
  57.     /**
  58.      * getLanguage get acvtive language
  59.      * 
  60.      * @access public
  61.      * @return active language
  62.      */
  63.     function getLanguage() {
  64.         return( $this->mLanguage );
  65.     }
  66.  
  67.     /**
  68.      * setLanguage set active language
  69.      * 
  70.      * @param string $pLangCode Language code
  71.      * @access public
  72.      * @return void 
  73.      */
  74.     function setLanguage( $pLangCode ) {
  75.         $this->mLanguage = $pLangCode;
  76.         $this->mLanguageInfo = $this->mDb->getRow( "SELECT il.* FROM `".BIT_DB_PREFIX."i18n_languages` il WHERE `lang_code` = ?", array( $pLangCode ) );
  77.     }
  78.  
  79.     function isLanguageRTL () {
  80.         return( !empty( $this->mLanguageInfo['right_to_left'] ) );
  81.     }
  82.  
  83.     /**
  84.      * verifyLanguage verify language hash before storing it
  85.      * 
  86.      * @param array $pParamHash parameters that will be stored
  87.      * @access public
  88.      * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
  89.      */
  90.     function verifyLanguage( &$pParamHash ) {
  91.         $langs = $this->listLanguages();
  92.         if( empty( $pParamHash['lang_code'] ) || strlen( $pParamHash['lang_code'] ) < 2 ) {
  93.             $this->mErrors['lang_code'] = tra( 'The language code must be at least 2 characters.' );
  94.         } elseif( !empty( $langs[$pParamHash['lang_code']] ) && empty( $pParamHash['update_lang_code'] ) ) {
  95.             $this->mErrors['lang_code'] = tra( 'This language code is already used by ' ).$langs[$pParamHash['lang_code']]['native_name'];
  96.         }
  97.         if( empty( $pParamHash['native_name'] ) ) {
  98.             $this->mErrors['native_name'] = 'You must provide the native language name';
  99.         }
  100.         if( !isset( $pParamHash['english_name'] ) ) {
  101.             $pParamHash['english_name'] = NULL;
  102.         }
  103.         $pParamHash['is_disabled'] = !empty( $pParamHash['is_disabled'] ) ? 'y' : NULL;
  104.         return( count( $this->mErrors ) === 0 );
  105.     }
  106.  
  107.     /**
  108.      * storeLanguage store language in database
  109.      * 
  110.      * @param array $pParamHash parameters that will be stored
  111.      * @access public
  112.      * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
  113.      */
  114.     function storeLanguage( $pParamHash ) {
  115.         if( $this->verifyLanguage( $pParamHash ) ) {
  116.             if( empty( $pParamHash['update_lang_code'] ) ) {
  117.                 $query = "INSERT INTO `".BIT_DB_PREFIX."i18n_languages` (`lang_code`,`english_name`,`native_name`,`is_disabled`) values (?,?,?,?)";
  118.                 $result = $this->mDb->query( $query, array( $pParamHash['lang_code'], $pParamHash['english_name'], $pParamHash['native_name'], $pParamHash['is_disabled'] ) );
  119.             } else {
  120.                 $query = "UPDATE `".BIT_DB_PREFIX."i18n_languages` SET `lang_code`=?, `english_name`=?, `native_name`=?, `is_disabled`=? WHERE `lang_code`=?";
  121.                 $result = $this->mDb->query( $query, array( $pParamHash['lang_code'], $pParamHash['english_name'], $pParamHash['native_name'], $pParamHash['is_disabled'], $pParamHash['update_lang_code'] ) );
  122.             }
  123.         }
  124.         return( count( $this->mErrors ) == 0 );
  125.     }
  126.  
  127.     /**
  128.      * expungeLanguage remove language from database
  129.      * 
  130.      * @param string $pLangCode Language code
  131.      * @access public
  132.      * @return void 
  133.      */
  134.     function expungeLanguage( $pLangCode ) {
  135.         if( !empty( $pLangCode ) ) {
  136.             $this->mDb->StartTrans();
  137.             $query = "DELETE FROM `".BIT_DB_PREFIX."i18n_strings` WHERE `lang_code`=?";
  138.             $result = $this->mDb->query( $query, array( $pLangCode ) );
  139.             $query = "DELETE FROM `".BIT_DB_PREFIX."i18n_languages` WHERE `lang_code`=?";
  140.             $result = $this->mDb->query( $query, array( $pLangCode ) );
  141.             $this->mDb->CompleteTrans();
  142.         }
  143.     }
  144.  
  145.     /**
  146.      * expungeMasterString remove master string from database
  147.      * 
  148.      * @param string $pSourceHash MD5 hash of master string
  149.      * @access public
  150.      * @return TRUE on success, FALSE on failure
  151.      */
  152.     function expungeMasterString( $pSourceHash ) {
  153.         if( !empty( $pSourceHash ) ) {
  154.             $this->mDb->StartTrans();
  155.             $query = "DELETE FROM `".BIT_DB_PREFIX."i18n_strings` WHERE `source_hash`=?";
  156.             $result = $this->mDb->query( $query, array( $pSourceHash ) );
  157.             $query = "DELETE FROM `".BIT_DB_PREFIX."i18n_masters` WHERE `source_hash`=?";
  158.             $result = $this->mDb->query( $query, array( $pSourceHash ) );
  159.             $this->mDb->CompleteTrans();
  160.             return TRUE;
  161.         }
  162.     }
  163.  
  164.     /**
  165.      * getImportedLanguages get a list of languages that have been imported
  166.      * 
  167.      * @access public
  168.      * @return array of available languages
  169.      */
  170.     function getImportedLanguages() {
  171.         $ret = array();
  172.         if( $rs = $this->mDb->query( 'SELECT DISTINCT(`lang_code`) AS `lang_code` FROM `'.BIT_DB_PREFIX.'i18n_strings`' ) ) {
  173.             $res = array();
  174.             while( !$rs->EOF ) {
  175.                 $res[] = $rs->fields['lang_code'];
  176.                 $rs->MoveNext();
  177.             }
  178.             $langs = $this->listLanguages();
  179.             foreach( $res as $langCode ) {
  180.                 $ret[$langCode] = $langs[$langCode];
  181.             }
  182.         }
  183.         return $ret;
  184.     }
  185.  
  186.     /**
  187.      * listLanguages list languages
  188.      * 
  189.      * @param boolean $pListDisabled 
  190.      * @param boolean $pListOnlyImportable 
  191.      * @access public
  192.      * @return array of languages
  193.      */
  194.     function listLanguages( $pListDisabled=TRUE, $pListOnlyImportable=FALSE ) {
  195.         $whereSql = '';
  196.         $langs = array();
  197.         if( !$pListDisabled ) {
  198.             $whereSql = " WHERE `is_disabled` IS NULL ";
  199.         }
  200.         $ret = $this->mDb->getAssoc( "SELECT il.`lang_code` AS `hash_key`, il.* FROM `".BIT_DB_PREFIX."i18n_languages` il $whereSql ORDER BY il.`lang_code`" );
  201.         if( !empty( $ret ) ) {
  202.             foreach( array_keys( $ret ) as $langCode ) {
  203.                 if( $langCode != 'en' && !$this->isImportFileAvailable( $langCode ) && $pListOnlyImportable )
  204.                     continue;
  205.                 $ret[$langCode]['translated_name'] = $this->translate( $ret[$langCode]['english_name'] );
  206.                 $ret[$langCode]['full_name'] = $ret[$langCode]['native_name'].' ('.$this->translate( $ret[$langCode]['english_name'] ).', '.$langCode.')';
  207.                 $langs[$langCode] = $ret[$langCode];
  208.             }
  209.         }
  210.         return $langs;
  211.     }
  212.  
  213.  
  214.     /**
  215.      * verifyMastersLoaded verify that master strings are loaded
  216.      * 
  217.      * @access public
  218.      * @return void 
  219.      */
  220.     function verifyMastersLoaded() {
  221.         // see if there is anything in the table
  222.         $query = "SELECT COUNT(`source_hash`) FROM `".BIT_DB_PREFIX."i18n_masters`";
  223.         $count = $this->mDb->getOne( $query );
  224.         if( empty( $count )) {
  225.             $this->importMasterStrings();
  226.         }
  227.     }
  228.  
  229.     /**
  230.      * masterStringExists check to see if a given master string already exists
  231.      * 
  232.      * @param array $pSourceHash MD5 hash of string to be checked
  233.      * @access public
  234.      * @return TRUE if found, FALSE otherwise
  235.      */
  236.     function masterStringExists( $pSourceHash ) {
  237.         return( !empty( $this->mStrings['master'][$pSourceHash] ) );
  238.     }
  239.  
  240.     /**
  241.      * searchMasterStrings find master string in database
  242.      * 
  243.      * @param string $pQuerySource string
  244.      * @access public
  245.      * @return TRUE on success, FALSE on failure
  246.      */
  247.     function searchMasterStrings( $pQuerySource ) {
  248.         $query = "
  249.             SELECT im.`source_hash` AS `hash_key`, `source`, `package`, im.`source_hash`
  250.             FROM `".BIT_DB_PREFIX."i18n_masters` im
  251.             WHERE UPPER( `source` ) LIKE ? ORDER BY im.`source`";
  252.         return( $this->mDb->getAssoc( $query, array( '%'.strtoupper( $pQuerySource ).'%' ) ) );
  253.     }
  254.  
  255.     /**
  256.      * loadMasterStrings load all master strings
  257.      * 
  258.      * @param string $pSourceHash MD5 hash to load
  259.      * @param string $pFilter Limit strings loaded to unlimited (default), translated or untranslated
  260.      * @access public
  261.      * @return all master strings in $this->mStrings['master']
  262.      */
  263.     function loadMasterStrings( $pSourceHash = NULL, $pFilter = NULL, $pLangCode = NULL ) {
  264.         $this->verifyMastersLoaded();
  265.         $bindVars = $whereSql = $joinSql = NULL;
  266.  
  267.         if( $pSourceHash ) {
  268.             $whereSql = ' WHERE `source_hash`=? ';
  269.             $bindVars = array( $pSourceHash );
  270.         } else {
  271.             // some basic filter options
  272.             if( !empty( $pFilter )) {
  273.                 $joinSql = "LEFT OUTER JOIN `".BIT_DB_PREFIX."i18n_strings` ist ON( im.`source_hash` = ist.`source_hash` )";
  274.                 if( $pFilter == 'translated' ) {
  275.                     $whereSql = "WHERE ist.`trans` IS NOT NULL";
  276.                     if( !empty( $pLangCode )) {
  277.                         $whereSql .= " AND ist.`lang_code` = ?";
  278.                         $bindVars[] = $pLangCode;
  279.                     }
  280.                 } elseif( $pFilter == 'untranslated' ) {
  281.                     $whereSql = "WHERE ist.`trans` IS NULL";
  282.                     // can't work out SQL to do language limits in this filter
  283.                 }
  284.             }
  285.         }
  286.  
  287.         $query = "
  288.             SELECT im.`source_hash` AS `hash_key`, `source`, `package`, im.`source_hash`
  289.             FROM `".BIT_DB_PREFIX."i18n_masters` im
  290.             $joinSql $whereSql ORDER BY im.`source`";
  291.         $this->mStrings['master'] = $this->mDb->getAssoc( $query, $bindVars );
  292.     }
  293.  
  294.     /**
  295.      * storeMasterString store master string
  296.      * 
  297.      * @param array $pParamHash data to be stored
  298.      * @access public
  299.      * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
  300.      */
  301.     function storeMasterString( $pParamHash ) {
  302.         global $gBitSmarty;
  303.         if( !empty( $gBitSmarty->mCompileRsrc ) ) {
  304.             list($type, $location) = explode( ':', $gBitSmarty->mCompileRsrc );
  305.             list($package, $file) = explode( '/', $location );
  306.         } else {
  307.             $package = NULL;
  308.         }
  309.  
  310.         $this->mDb->StartTrans();
  311.         $newSourceHash = $this->getSourceHash( $pParamHash['new_source'] );
  312.         if( $this->masterStringExists( $newSourceHash ) ) {
  313.             $oldCount = $this->mDb->getOne( "SELECT COUNT(`source_hash`) FROM `".BIT_DB_PREFIX."i18n_strings` WHERE `source_hash`=?",  array( $pParamHash['source_hash'] ) );
  314.             $newCount = $this->mDb->getOne( "SELECT COUNT(`source_hash`) FROM `".BIT_DB_PREFIX."i18n_strings` WHERE `source_hash`=?",  array( $newSourceHash ) );
  315.             if( $newCount ) {
  316.                 $this->mErrors['master'] = 'There was a conflict updating the master string. The new string already has translations entered.';
  317.             } else {
  318.                 // we have updated a master string to an existing master string
  319.                 $query = "UPDATE `".BIT_DB_PREFIX."i18n_strings` SET `source_hash`=?, `last_modified`=? WHERE `source_hash`=?";
  320.                 $trans = $this->mDb->query($query, array( $newSourceHash, time(), $pParamHash['source_hash'] ) );
  321.                 $query = "DELETE FROM `".BIT_DB_PREFIX."i18n_masters` WHERE `source_hash`=?";
  322.                 $trans = $this->mDb->query($query, array( $pParamHash['source_hash'] ) );
  323.             }
  324.         } elseif( $this->masterStringExists( $pParamHash['source_hash'] ) ) {
  325.             $query = "UPDATE `".BIT_DB_PREFIX."i18n_strings` SET `source_hash`=?, `last_modified`=? WHERE `source_hash`=?";
  326.             $trans = $this->mDb->query($query, array( $newSourceHash, time(), $pParamHash['source_hash'] ) );
  327.             $query = "UPDATE `".BIT_DB_PREFIX."i18n_masters` SET `source_hash`=?, `source`=?, `created`=? WHERE `source_hash`=?";
  328.             $trans = $this->mDb->query($query, array( $newSourceHash, $pParamHash['new_source'], time(), $pParamHash['source_hash'] ) );
  329.             unset( $this->mStrings[$pParamHash['source_hash']] );
  330.         } else {
  331.             $query = "INSERT INTO `".BIT_DB_PREFIX."i18n_masters` (`source`,`source_hash`, `created`, `package`) VALUES (?,?,?,?)";
  332.             $trans = $this->mDb->query($query, array( $pParamHash['new_source'], $newSourceHash, time(), $package ) );
  333.         }
  334.         if( count( $this->mErrors ) == 0 ) {
  335.             $this->mStrings['master'][$newSourceHash]['source'] = $pParamHash['new_source'];
  336.             $this->mStrings['master'][$newSourceHash]['source_hash'] = $newSourceHash;
  337.         }
  338.         $this->mDb->CompleteTrans();
  339.         return( count( $this->mErrors ) == 0 );
  340.     }
  341.  
  342.  
  343.     /**
  344.      * importMasterStrings
  345.      * 
  346.      * @param boolean $pOverwrite 
  347.      * @access public
  348.      * @return TRUE on success, FALSE on failure
  349.      */
  350.     function importMasterStrings( $pOverwrite=FALSE ) {
  351.         global $lang;
  352.         $count = 0;
  353.         include_once ( LANGUAGES_PKG_PATH.'lang/masters.php' );
  354.  
  355.         foreach( $lang as $key=>$val ) {
  356.             $sourceHash = $this->getSourceHash( $key );
  357.             $query = "SELECT * FROM `".BIT_DB_PREFIX."i18n_masters` WHERE `source_hash`=?";
  358.             $trans = $this->mDb->getAssoc($query, array( $sourceHash ) );
  359.             if( $trans ) {
  360.                 if( $pOverwrite ) {
  361.                     $query = "UPDATE `".BIT_DB_PREFIX."i18n_masters` SET `source`=?, `created`=? WHERE `source_hash`=?";
  362.                     $trans = $this->mDb->query($query, array( $val, time(), $sourceHash ) );
  363.                     $count++;
  364.                 }
  365.             } else {
  366.                 $this->storeMasterString( array( 'new_source' => $val, 'source_hash' => $sourceHash ) );
  367.                 $count++;
  368.             }
  369.         }
  370.         return( $count );
  371.     }
  372.  
  373.     /**
  374.      * storeTranslationString
  375.      * 
  376.      * @param string $pLangCode Language code
  377.      * @param string $pString 
  378.      * @param string $pSourceHash MD5 hash of master string
  379.      * @access public
  380.      * @return void 
  381.      */
  382.     function storeTranslationString( $pLangCode, $pString, $pSourceHash ) {
  383.         $query = "DELETE FROM `".BIT_DB_PREFIX."i18n_strings` WHERE `source_hash`=? AND `lang_code`=?";
  384.         $result = $this->mDb->query( $query, array( $pSourceHash, $pLangCode ) );
  385.  
  386.         // we don't need things where '{$menu.menu_title}' is the full string in the database
  387.         // if you change this regexp, please modify the one in kernel/smarty_bit/prefilter.tr.php as well (approx line 76)
  388.         if( !empty( $pString ) && !preg_match( '!^(\{\$[^\}]*\})+$!', $pString ) ) {
  389.             $query = "INSERT INTO `".BIT_DB_PREFIX."i18n_strings` (`lang_code`,`trans`,`source_hash`, `last_modified`) values (?,?,?,?)";
  390.             $result = $this->mDb->query( $query, array( $pLangCode, $pString, $pSourceHash, time() ) );
  391.         }
  392.         // pretty brutal on mass-saving, but cache always needs purging after translation saved.
  393.         $this->clearCache();
  394.         $this->mStrings[$pLangCode][$pSourceHash]['trans'] = $pString;
  395.     }
  396.  
  397.     /**
  398.      * getTranslatedStrings
  399.      * 
  400.      * @param string $pSourceHash MD5 hash of master string
  401.      * @access public
  402.      * @return array of translated strings
  403.      */
  404.     function getTranslatedStrings( $pSourceHash ) {
  405.         $query = "
  406.             SELECT ist.`lang_code` AS `hash_key`, `trans`, ist.`source_hash`, ist.`lang_code`
  407.             FROM `".BIT_DB_PREFIX."i18n_strings` ist
  408.             WHERE ist.`source_hash`=?
  409.             ORDER BY ist.`lang_code`";
  410.         return( $this->mDb->getAssoc( $query, array( $pSourceHash ) ) );
  411.     }
  412.  
  413.     /**
  414.      * getTranslationString
  415.      * 
  416.      * @param string $pSourceHash MD5 hash of master string
  417.      * @param string $pLangCode Language code
  418.      * @access public
  419.      * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
  420.      */
  421.     function getTranslationString( $pSourceHash, $pLangCode ) {
  422.         $this->verifyTranslationLoaded( $pLangCode );
  423.         $query = "
  424.             SELECT im.`source_hash` AS `hash_key`, `source`, `trans`, im.`source_hash`
  425.             FROM `".BIT_DB_PREFIX."i18n_masters` im
  426.                 LEFT OUTER JOIN `".BIT_DB_PREFIX."i18n_strings` ist ON( ist.`source_hash`=im.`source_hash` AND ist.`lang_code`=? )
  427.             WHERE im.`source_hash`=?
  428.             ORDER BY im.`source`";
  429.         return( $this->mDb->getAssoc( $query, array( $pLangCode, $pSourceHash ) ) );
  430.     }
  431.  
  432.     /**
  433.      * getLanguageFile
  434.      * 
  435.      * @param string $pLangCode Language code
  436.      * @access public
  437.      * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
  438.      */
  439.     function getLanguageFile( $pLangCode ) {
  440.         return( LANGUAGES_PKG_PATH.'lang/'.$pLangCode.'/language.php' );
  441.     }
  442.  
  443.     /**
  444.      * isImportFileAvailable
  445.      * 
  446.      * @param string $pLangCode Language code
  447.      * @access public
  448.      * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
  449.      */
  450.     function isImportFileAvailable( $pLangCode ) {
  451.         return( file_exists( $this->getLanguageFile( $pLangCode ) ) );
  452.     }
  453.  
  454.     /**
  455.      * importTranslationStrings
  456.      * 
  457.      * @param string $pLangCode Language code
  458.      * @param boolean $pOverwrite 
  459.      * @param string $pTable 
  460.      * @param string $pFile path to file
  461.      * @access public
  462.      * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
  463.      */
  464.     function importTranslationStrings( $pLangCode, $pOverwrite=FALSE, $pTable='i18n_strings`', $pFile=FALSE ) {
  465.         $count = 0;
  466.  
  467.         if( empty( $pFile ) ) {
  468.             if( $this->isImportFileAvailable( $pLangCode ) ) {
  469.                 $pFile = $this->getLanguageFile( $pLangCode );
  470.             }
  471.         }
  472.  
  473.         if( !empty( $pFile ) && file_exists( $pFile ) ) {
  474.             $this->loadMasterStrings();
  475.  
  476.             // read the file and parse out the master/trans string pairs manually to prevent any evil shit from getting exec'ed
  477.             $handle = fopen( $pFile, "r" );
  478.             $line = '';
  479.             while (!feof($handle)) {
  480.                 $line .= fgets( $handle );
  481.                 if( preg_match( '/([\'"])(.*?)(?<!\\\\)\1[\n\r\s]*=>[\n\r\s]*([\'"])(.*?)(?<!\\\\)\3/msS', $line, $match )) {
  482.                     $lang[stripslashes( $match[2] )] = stripslashes( $match[4] );
  483.                     $line = '';
  484.                 }
  485.             }
  486.             fclose( $handle );
  487.  
  488.             foreach( $lang as $key=>$val ) {
  489.                 $hashKey = $this->getSourceHash( $key );
  490.                 if( !$this->masterStringExists( $hashKey ) ) {
  491.                     $this->storeMasterString( array( 'source_hash' => $hashKey, 'new_source' => $key ) );
  492.                 }
  493.                 $trans = $this->lookupTranslation( $key, $pLangCode, FALSE );
  494.                 if( !is_null( $trans ) ) {
  495.                     if( $pOverwrite ) {
  496.                         $query = "UPDATE `".BIT_DB_PREFIX."i18n_strings` SET `trans`=?, `last_modified`=? WHERE `source_hash`=? AND `lang_code`=?";
  497.                         $trans = $this->mDb->query($query, array( $val, time(), $hashKey, $pLangCode ) );
  498.                         $count++;
  499.                     } elseif( !empty( $val ) && strtolower( $trans ) != strtolower( $val ) ) {
  500.                         $this->mImportConflicts[$pLangCode][$hashKey]['import'] = $val;
  501.                         $this->mImportConflicts[$pLangCode][$hashKey]['existing'] = $trans;
  502.                         if( !empty( $this->mStrings['master'][$hashKey]['source'] ) ) {
  503.                             $this->mImportConflicts[$pLangCode][$hashKey]['master'] = $this->mStrings['master'][$hashKey]['source'];
  504.                         }
  505.                     }
  506.                 } elseif( !empty( $val ) && (strtolower( $key ) != strtolower( $val )) ) {
  507.                     $query = "INSERT INTO `".BIT_DB_PREFIX."i18n_strings` (`trans`,`source_hash`,`lang_code`,`last_modified`) VALUES (?,?,?,?)";
  508.                     $trans = $this->mDb->query($query, array( $val, $hashKey, $pLangCode, time() ) );
  509.                     $count++;
  510.                 }
  511.             }
  512.         }
  513.  
  514.         return( $count );
  515.     }
  516.  
  517.     /**
  518.      * verifyTranslationLoaded
  519.      * 
  520.      * @param string $pLangCode Language code
  521.      * @access public
  522.      * @return void 
  523.      */
  524.     function verifyTranslationLoaded( $pLangCode ) {
  525.         if ( $pLangCode ) {
  526.             // see if there is anything in the table
  527.             $query = "SELECT COUNT(`source_hash`) FROM `".BIT_DB_PREFIX."i18n_strings` ist WHERE ist.`lang_code`=?";
  528.             $count = $this->mDb->getOne($query, array( $pLangCode ) );
  529.             if( empty( $count ) ) {
  530.                 $this->importTranslationStrings( $pLangCode );
  531.             }
  532.         }
  533.     }
  534.  
  535.     /**
  536.      * loadLanguage
  537.      * 
  538.      * @param string $pLangCode Language code
  539.      * @access public
  540.      * @return void 
  541.      */
  542.     function loadLanguage( $pLangCode ) {
  543.         $this->verifyMastersLoaded();
  544.         $this->verifyTranslationLoaded( $pLangCode );
  545.         $query = "
  546.             SELECT im.`source_hash` AS `hash_key`, `source`, `trans`, im.`source_hash`, ivm.`version`
  547.             FROM `".BIT_DB_PREFIX."i18n_masters` im
  548.                 LEFT OUTER JOIN `".BIT_DB_PREFIX."i18n_strings` ist ON( ist.`source_hash`=im.`source_hash` AND ist.`lang_code`=? )
  549.                 LEFT OUTER JOIN `".BIT_DB_PREFIX."i18n_version_map` ivm ON( im.`source_hash`=ivm.`source_hash` )
  550.             ORDER BY im.`source`";
  551.         $this->mStrings[$pLangCode] = $this->mDb->getAssoc( $query, array( $pLangCode ) );
  552.     }
  553.  
  554.     /**
  555.      * translate
  556.      * 
  557.      * @param string $pString 
  558.      * @access public
  559.      * @return translation 
  560.      */
  561.     function translate( $pString ) {
  562.         global $gBitTranslationHash, $gBitSystem;
  563.         $sourceHash = $this->getSourceHash( $pString );
  564.         $cacheFile = TEMP_PKG_PATH."lang/".$this->mLanguage."/".$sourceHash;
  565.         if( $this->mLanguage == 'en' ) {
  566.             $ret = $pString;
  567.         } elseif( !empty( $this->mStrings[$this->mLanguage][$sourceHash] ) ) {
  568.             $ret = $this->mStrings[$this->mLanguage][$sourceHash]['trans'];
  569.         } elseif( file_exists( $cacheFile ) && !$gBitSystem->isFeatureActive( 'i18n_interactive_translation' ) ) {
  570.             $ret = file_get_contents( $cacheFile );
  571.         } else {
  572.             if( empty( $this->mStrings[$this->mLanguage] ) ) {
  573.                 $this->verifyTranslationLoaded( $this->mLanguage );
  574.             }
  575.             $tran = $this->lookupTranslation( $pString, $this->mLanguage );
  576.             if( empty( $tran ) ) {
  577.                 // lookup failed. let's snag the first part of the langCode if it is a dialect (e.g. pt-br )
  578.                 $dialect = strpos( $this->mLanguage, '-' );
  579.                 if( $dialect ) {
  580.                     $tran = $this->lookupTranslation( $pString, substr( $this->mLanguage, 0, $dialect ) );
  581.                 }
  582.                 if( empty( $tran ) ) {
  583.                     $tran = $pString;
  584.                 }
  585.             }
  586.             // write out the cache - translated or not so we don't keep hitting the database
  587.             mkdir_p( dirname( $cacheFile ) );
  588.             $fp = fopen( $cacheFile, 'w' );
  589.             fwrite( $fp, $tran );
  590.             fclose( $fp );
  591.             $this->mStrings[$this->mLanguage][$sourceHash]['trans'] = $tran;
  592.             $ret = $tran;
  593.         }
  594.  
  595.         // interactive translation process
  596.         if( $gBitSystem->isFeatureActive( 'i18n_interactive_translation' ) ) {
  597.             if( empty( $gBitTranslationHash ) ) {
  598.                 $gBitTranslationHash = array();
  599.             }
  600.             if( !$index = array_search( $sourceHash, $gBitTranslationHash ) ) {
  601.                 $gBitTranslationHash[] = $sourceHash;
  602.                 $index = count( $gBitTranslationHash ) - 1;
  603.             }
  604.             $ret .= '_'.$index;
  605.         }
  606.  
  607.         return $ret;
  608.     }
  609.  
  610.     /**
  611.      * lookupTranslation
  612.      * 
  613.      * @param string $pString 
  614.      * @param string $pLangCode Language code
  615.      * @param boolean $pOverrideUsage 
  616.      * @access public
  617.      * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
  618.      */
  619.     function lookupTranslation( $pString, $pLangCode, $pOverrideUsage = TRUE ) {
  620.         global $gBitSystem;
  621.         $sourceHash = $this->getSourceHash( $pString );
  622.         if ( $pLangCode ) {
  623.             $query = "SELECT `trans`, ivm.`version`, ivm.`source_hash` AS `usage_source_hash`
  624.                 FROM `".BIT_DB_PREFIX."i18n_masters` im
  625.                 LEFT OUTER JOIN `".BIT_DB_PREFIX."i18n_version_map` ivm ON( ivm.`source_hash`=im.`source_hash` AND ivm.`version`=? )
  626.                 LEFT OUTER JOIN `".BIT_DB_PREFIX."i18n_strings` ist ON( im.`source_hash`=ist.`source_hash` AND `lang_code`=? )
  627.                 WHERE im.`source_hash`=?";
  628.             $ret = $this->mDb->getRow($query, array( BIT_MAJOR_VERSION, $pLangCode, $sourceHash ) );
  629.             if( $pOverrideUsage && $gBitSystem->isFeatureActive( 'i18n_record_untranslated' ) ) {
  630.                 $query = "SELECT `source_hash` FROM `".BIT_DB_PREFIX."i18n_masters` WHERE `source_hash`=?";
  631.                 $source = $this->mDb->getOne($query, array( $sourceHash ) );
  632.                 if( empty( $source ) ) {
  633.                     $this->storeMasterString( array( 'source_hash' => $sourceHash, 'new_source' => $pString ) );
  634.                 }
  635.             }
  636.             if( $pOverrideUsage && $gBitSystem->isFeatureActive( 'i18n_track_translation_usage' ) ) {
  637.                 if( empty( $ret['usage_source_hash'] ) ) {
  638.                     $query = "INSERT INTO `".BIT_DB_PREFIX."i18n_version_map` (`source_hash`,`version`) VALUES (?,?)";
  639.                     $trans = $this->mDb->query($query, array( $sourceHash, BIT_MAJOR_VERSION ) );
  640.                 }
  641.             }
  642.         }
  643.         return (isset( $ret['trans'] ) ? $ret['trans'] : NULL );
  644.     }
  645.  
  646.     /**
  647.      * getMasterString
  648.      * 
  649.      * @param string $pSourceHash 
  650.      * @access public
  651.      * @return master string with given source hash
  652.      */
  653.     function getMasterString( $pSourceHash ) {
  654.         return( $this->mDb->getOne( "SELECT `source` FROM `" . BIT_DB_PREFIX . "i18n_masters` WHERE `source_hash` = ? ", array( $pSourceHash ) ) );
  655.     }
  656.  
  657.     /**
  658.      * getSourceHash
  659.      * 
  660.      * @param string $pString 
  661.      * @access public
  662.      * @return MD5 hash of string
  663.      */
  664.     function getSourceHash( $pString ) {
  665.         return( md5( strtolower( trim( $pString ))));
  666.     }
  667.  
  668.     /**
  669.      * clearCache
  670.      * 
  671.      * @access public
  672.      * @return void 
  673.      */
  674.     function clearCache() {
  675.         unlink_r( TEMP_PKG_PATH."lang/" );
  676.         unlink_r( TEMP_PKG_PATH."templates_c/" );
  677.     }
  678. }

Documentation generated on Wed, 29 Jul 2015 13:55:53 +0000 by phpDocumentor 1.5.0-lsces