PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/source/core/oxlang.php

https://github.com/GM-Alex/oxideshop_ce
PHP | 1379 lines | 684 code | 197 blank | 498 comment | 126 complexity | 2612117775276b45fdcb77e3f10b404c MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, GPL-3.0
  1. <?php
  2. /**
  3. * This file is part of OXID eShop Community Edition.
  4. *
  5. * OXID eShop Community Edition is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * OXID eShop Community Edition is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with OXID eShop Community Edition. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * @link http://www.oxid-esales.com
  19. * @copyright (C) OXID eSales AG 2003-2014
  20. * @version OXID eShop CE
  21. */
  22. /**
  23. * Language related utility class
  24. */
  25. class oxLang extends oxSuperCfg
  26. {
  27. /**
  28. * Language parameter name
  29. *
  30. * @var string
  31. */
  32. protected $_sName = 'lang';
  33. /**
  34. * Current shop base language Id
  35. *
  36. * @var int
  37. */
  38. protected $_iBaseLanguageId = null;
  39. /**
  40. * Templates language Id
  41. *
  42. * @var int
  43. */
  44. protected $_iTplLanguageId = null;
  45. /**
  46. * Editing object language Id
  47. *
  48. * @var int
  49. */
  50. protected $_iEditLanguageId = null;
  51. /**
  52. * Language translations array cache
  53. *
  54. * @var array
  55. */
  56. protected $_aLangCache = array();
  57. /**
  58. * Array containing possible admin template translations
  59. *
  60. * @var array
  61. */
  62. protected $_aAdminTplLanguageArray = null;
  63. /**
  64. * Language abbreviation array
  65. *
  66. * @var array
  67. */
  68. protected $_aLangAbbr = null;
  69. /**
  70. * registered additional language filesets to load
  71. *
  72. * @var array
  73. */
  74. protected $_aAdditionalLangFiles = array();
  75. /**
  76. * registered additional language filesets to load
  77. *
  78. * @var array
  79. */
  80. protected $_aLangMap = array();
  81. /**
  82. * Active module Ids and paths array
  83. *
  84. * @var array
  85. */
  86. protected $_aActiveModuleInfo = null;
  87. /**
  88. * Disabled module Ids and paths array
  89. *
  90. * @var array
  91. */
  92. protected $_aDisabledModuleInfo = null;
  93. /**
  94. * State is string translated or not
  95. *
  96. * @var bool
  97. */
  98. protected $_blIsTranslated = true;
  99. /**
  100. * Template language id.
  101. *
  102. * @var int
  103. */
  104. protected $_iObjectTplLanguageId = null;
  105. /**
  106. * Set translation state
  107. *
  108. * @param bool $blIsTranslated State is string translated or not. Default true.
  109. */
  110. public function setIsTranslated($blIsTranslated = true)
  111. {
  112. $this->_blIsTranslated = $blIsTranslated;
  113. }
  114. /**
  115. * Set translation state
  116. *
  117. * @return bool
  118. */
  119. public function isTranslated()
  120. {
  121. return $this->_blIsTranslated;
  122. }
  123. /**
  124. * resetBaseLanguage resets base language id cache
  125. *
  126. * @access public
  127. */
  128. public function resetBaseLanguage()
  129. {
  130. $this->_iBaseLanguageId = null;
  131. }
  132. /**
  133. * Returns active shop language id
  134. *
  135. * @return string
  136. */
  137. public function getBaseLanguage()
  138. {
  139. if ($this->_iBaseLanguageId === null) {
  140. $myConfig = $this->getConfig();
  141. $blAdmin = $this->isAdmin();
  142. // languages and search engines
  143. if ($blAdmin && (($iSeLang = oxRegistry::getConfig()->getRequestParameter('changelang')) !== null)) {
  144. $this->_iBaseLanguageId = $iSeLang;
  145. }
  146. if (is_null($this->_iBaseLanguageId)) {
  147. $this->_iBaseLanguageId = oxRegistry::getConfig()->getRequestParameter('lang');
  148. }
  149. //or determining by domain
  150. $aLanguageUrls = $myConfig->getConfigParam('aLanguageURLs');
  151. if (!$blAdmin && is_array($aLanguageUrls)) {
  152. foreach ($aLanguageUrls as $iId => $sUrl) {
  153. if ($sUrl && $myConfig->isCurrentUrl($sUrl)) {
  154. $this->_iBaseLanguageId = $iId;
  155. break;
  156. }
  157. }
  158. }
  159. if (is_null($this->_iBaseLanguageId)) {
  160. $this->_iBaseLanguageId = oxRegistry::getConfig()->getRequestParameter('language');
  161. if (!isset($this->_iBaseLanguageId)) {
  162. $this->_iBaseLanguageId = oxRegistry::getSession()->getVariable('language');
  163. }
  164. }
  165. // if language still not set and not search engine browsing,
  166. // getting language from browser
  167. if (is_null($this->_iBaseLanguageId) && !$blAdmin && !oxRegistry::getUtils()->isSearchEngine()) {
  168. // getting from cookie
  169. $this->_iBaseLanguageId = oxRegistry::get("oxUtilsServer")->getOxCookie('language');
  170. // getting from browser
  171. if (is_null($this->_iBaseLanguageId)) {
  172. $this->_iBaseLanguageId = $this->detectLanguageByBrowser();
  173. }
  174. }
  175. if (is_null($this->_iBaseLanguageId)) {
  176. $this->_iBaseLanguageId = $myConfig->getConfigParam('sDefaultLang');
  177. }
  178. $this->_iBaseLanguageId = (int) $this->_iBaseLanguageId;
  179. // validating language
  180. $this->_iBaseLanguageId = $this->validateLanguage($this->_iBaseLanguageId);
  181. oxRegistry::get("oxUtilsServer")->setOxCookie('language', $this->_iBaseLanguageId);
  182. }
  183. return $this->_iBaseLanguageId;
  184. }
  185. /**
  186. * Returns language id used to load objects according to current template language
  187. *
  188. * @return int
  189. */
  190. public function getObjectTplLanguage()
  191. {
  192. if ($this->_iObjectTplLanguageId === null) {
  193. $this->_iObjectTplLanguageId = $this->getTplLanguage();
  194. $aLanguages = $this->getAdminTplLanguageArray();
  195. if (!isset($aLanguages[$this->_iObjectTplLanguageId]) ||
  196. $aLanguages[$this->_iObjectTplLanguageId]->active == 0
  197. ) {
  198. $this->_iObjectTplLanguageId = key($aLanguages);
  199. }
  200. }
  201. return $this->_iObjectTplLanguageId;
  202. }
  203. /**
  204. * Returns active shop templates language id
  205. * If it is not an admin area, template language id is same
  206. * as base shop language id
  207. *
  208. * @return string
  209. */
  210. public function getTplLanguage()
  211. {
  212. if ($this->_iTplLanguageId === null) {
  213. $iSessLang = oxRegistry::getSession()->getVariable('tpllanguage');
  214. $this->_iTplLanguageId = $this->isAdmin() ? $this->setTplLanguage($iSessLang) : $this->getBaseLanguage();
  215. }
  216. return $this->_iTplLanguageId;
  217. }
  218. /**
  219. * Returns editing object working language id
  220. *
  221. * @return string
  222. */
  223. public function getEditLanguage()
  224. {
  225. if ($this->_iEditLanguageId === null) {
  226. if (!$this->isAdmin()) {
  227. $this->_iEditLanguageId = $this->getBaseLanguage();
  228. } else {
  229. $iLang = null;
  230. // choosing language ident
  231. // check if we really need to set the new language
  232. if ("saveinnlang" == $this->getConfig()->getActiveView()->getFncName()) {
  233. $iLang = oxRegistry::getConfig()->getRequestParameter("new_lang");
  234. }
  235. $iLang = ($iLang === null) ? oxRegistry::getConfig()->getRequestParameter('editlanguage') : $iLang;
  236. $iLang = ($iLang === null) ? oxRegistry::getSession()->getVariable('editlanguage') : $iLang;
  237. $iLang = ($iLang === null) ? $this->getBaseLanguage() : $iLang;
  238. // validating language
  239. $this->_iEditLanguageId = $this->validateLanguage($iLang);
  240. // writing to session
  241. oxRegistry::getSession()->setVariable('editlanguage', $this->_iEditLanguageId);
  242. }
  243. }
  244. return $this->_iEditLanguageId;
  245. }
  246. /**
  247. * Returns array of available languages.
  248. *
  249. * @param integer $iLanguage Number if current language (default null)
  250. * @param bool $blOnlyActive load only current language or all
  251. * @param bool $blSort enable sorting or not
  252. *
  253. * @return array
  254. */
  255. public function getLanguageArray($iLanguage = null, $blOnlyActive = false, $blSort = false)
  256. {
  257. $myConfig = $this->getConfig();
  258. if (is_null($iLanguage)) {
  259. $iLanguage = $this->_iBaseLanguageId;
  260. }
  261. $aLanguages = array();
  262. $aConfLanguages = $myConfig->getConfigParam('aLanguages');
  263. $aLangParams = $myConfig->getConfigParam('aLanguageParams');
  264. if (is_array($aConfLanguages)) {
  265. $i = 0;
  266. reset($aConfLanguages);
  267. while (list($key, $val) = each($aConfLanguages)) {
  268. if ($blOnlyActive && is_array($aLangParams)) {
  269. //skipping non active languages
  270. if (!$aLangParams[$key]['active']) {
  271. $i++;
  272. continue;
  273. }
  274. }
  275. if ($val) {
  276. $oLang = new stdClass();
  277. $oLang->id = isset($aLangParams[$key]['baseId']) ? $aLangParams[$key]['baseId'] : $i;
  278. $oLang->oxid = $key;
  279. $oLang->abbr = $key;
  280. $oLang->name = $val;
  281. if (is_array($aLangParams)) {
  282. $oLang->active = $aLangParams[$key]['active'];
  283. $oLang->sort = $aLangParams[$key]['sort'];
  284. }
  285. $oLang->selected = (isset($iLanguage) && $oLang->id == $iLanguage) ? 1 : 0;
  286. $aLanguages[$oLang->id] = $oLang;
  287. }
  288. ++$i;
  289. }
  290. }
  291. if ($blSort && is_array($aLangParams)) {
  292. uasort($aLanguages, array($this, '_sortLanguagesCallback'));
  293. }
  294. return $aLanguages;
  295. }
  296. /**
  297. * Returns languages array containing possible admin template translations
  298. *
  299. * @return array
  300. */
  301. public function getAdminTplLanguageArray()
  302. {
  303. if ($this->_aAdminTplLanguageArray === null) {
  304. $myConfig = $this->getConfig();
  305. $aLangArray = $this->getLanguageArray();
  306. $this->_aAdminTplLanguageArray = array();
  307. $sSourceDir = $myConfig->getAppDir() . 'views/admin/';
  308. foreach ($aLangArray as $iLangKey => $oLang) {
  309. $sFilePath = "{$sSourceDir}{$oLang->abbr}/lang.php";
  310. if (file_exists($sFilePath) && is_readable($sFilePath)) {
  311. $this->_aAdminTplLanguageArray[$iLangKey] = $oLang;
  312. }
  313. }
  314. }
  315. // moving pointer to beginning
  316. reset($this->_aAdminTplLanguageArray);
  317. return $this->_aAdminTplLanguageArray;
  318. }
  319. /**
  320. * Returns selected language abbreviation
  321. *
  322. * @param int $iLanguage language id [optional]
  323. *
  324. * @return string
  325. */
  326. public function getLanguageAbbr($iLanguage = null)
  327. {
  328. if ($this->_aLangAbbr === null) {
  329. $this->_aLangAbbr = $this->getLanguageIds();
  330. }
  331. $iLanguage = isset($iLanguage) ? (int) $iLanguage : $this->getBaseLanguage();
  332. if (isset($this->_aLangAbbr[$iLanguage])) {
  333. $iLanguage = $this->_aLangAbbr[$iLanguage];
  334. }
  335. return $iLanguage;
  336. }
  337. /**
  338. * getLanguageNames returns array of language names e.g. array('Deutch', 'English')
  339. *
  340. * @access public
  341. * @return array
  342. */
  343. public function getLanguageNames()
  344. {
  345. $aConfLanguages = $this->getConfig()->getConfigParam('aLanguages');
  346. $aLangIds = $this->getLanguageIds();
  347. $aLanguages = array();
  348. foreach ($aLangIds as $iId => $sValue) {
  349. $aLanguages[$iId] = $aConfLanguages[$sValue];
  350. }
  351. return $aLanguages;
  352. }
  353. /**
  354. * Searches for translation string in file and on success returns translation,
  355. * otherwise returns initial string.
  356. *
  357. * @param string $sStringToTranslate Initial string
  358. * @param int $iLang optional language number
  359. * @param bool $blAdminMode on special case you can force mode, to load language constant from admin/shops language file
  360. *
  361. * @throws oxLanguageException in debug mode
  362. *
  363. * @return string
  364. */
  365. public function translateString($sStringToTranslate, $iLang = null, $blAdminMode = null)
  366. {
  367. $this->setIsTranslated();
  368. // checking if in cache exist
  369. $aLang = $this->_getLangTranslationArray($iLang, $blAdminMode);
  370. if (isset($aLang[$sStringToTranslate])) {
  371. return $aLang[$sStringToTranslate];
  372. }
  373. // checking if in map exist
  374. $aMap = $this->_getLanguageMap($iLang, $blAdminMode);
  375. if (isset($aLang[$aMap[$sStringToTranslate]])) {
  376. return $aLang[$aMap[$sStringToTranslate]];
  377. }
  378. // checking if in theme options exist
  379. if (count($this->_aAdditionalLangFiles)) {
  380. $aLang = $this->_getLangTranslationArray($iLang, $blAdminMode, $this->_aAdditionalLangFiles);
  381. if (isset($aLang[$sStringToTranslate])) {
  382. return $aLang[$sStringToTranslate];
  383. }
  384. }
  385. $this->setIsTranslated(false);
  386. return $sStringToTranslate;
  387. }
  388. /**
  389. * Iterates through given array ($aData) and collects data if array key is similar as
  390. * searchable key ($sKey*). If you pass $aCollection, it will be appended with found items
  391. *
  392. * @param array $aData array to search in
  393. * @param string $sKey key to look for (looking for similar with strpos)
  394. * @param array $aCollection array to append found items [optional]
  395. *
  396. * @return array
  397. */
  398. protected function _collectSimilar($aData, $sKey, $aCollection = array())
  399. {
  400. foreach ($aData as $sValKey => $sValue) {
  401. if (strpos($sValKey, $sKey) === 0) {
  402. $aCollection[$sValKey] = $sValue;
  403. }
  404. }
  405. return $aCollection;
  406. }
  407. /**
  408. * Returns array( "MY_TRANSLATION_KEY" => "MY_TRANSLATION_VALUE", ... ) by
  409. * given filter "MY_TRANSLATION_" from language files
  410. *
  411. * @param string $sKey key to look
  412. * @param int $iLang language files to search [optional]
  413. * @param bool $blAdmin admin/non admin mode [optional]
  414. *
  415. * @return array
  416. */
  417. public function getSimilarByKey($sKey, $iLang = null, $blAdmin = null)
  418. {
  419. startProfile("getSimilarByKey");
  420. $iLang = isset($iLang) ? $iLang : $this->getTplLanguage();
  421. $blAdmin = isset($blAdmin) ? $blAdmin : $this->isAdmin();
  422. // checking if exists in cache
  423. $aLang = $this->_getLangTranslationArray($iLang, $blAdmin);
  424. $aSimilarConst = $this->_collectSimilar($aLang, $sKey);
  425. // checking if in map exist
  426. $aMap = $this->_getLanguageMap($iLang, $blAdmin);
  427. $aSimilarConst = $this->_collectSimilar($aMap, $sKey, $aSimilarConst);
  428. // checking if in theme options exist
  429. if (count($this->_aAdditionalLangFiles)) {
  430. $aLang = $this->_getLangTranslationArray($iLang, $blAdmin, $this->_aAdditionalLangFiles);
  431. $aSimilarConst = $this->_collectSimilar($aLang, $sKey, $aSimilarConst);
  432. }
  433. stopProfile("getSimilarByKey");
  434. return $aSimilarConst;
  435. }
  436. /**
  437. * Returns formatted number, according to active currency formatting standards.
  438. *
  439. * @param float $dValue Plain price
  440. * @param object $oActCur Object of active currency
  441. *
  442. * @return string
  443. */
  444. public function formatCurrency($dValue, $oActCur = null)
  445. {
  446. if (!$oActCur) {
  447. $oActCur = $this->getConfig()->getActShopCurrencyObject();
  448. }
  449. $sValue = oxRegistry::getUtils()->fRound($dValue, $oActCur);
  450. return number_format((double) $sValue, $oActCur->decimal, $oActCur->dec, $oActCur->thousand);
  451. }
  452. /**
  453. * Returns formatted vat value, according to formatting standards.
  454. *
  455. * @param float $dValue Plain price
  456. * @param object $oActCur Object of active currency
  457. *
  458. * @return string
  459. */
  460. public function formatVat($dValue, $oActCur = null)
  461. {
  462. $iDecPos = 0;
  463. $sValue = ( string ) $dValue;
  464. /** @var oxStrRegular $oStr */
  465. $oStr = getStr();
  466. if (($iDotPos = $oStr->strpos($sValue, '.')) !== false) {
  467. $iDecPos = $oStr->strlen($oStr->substr($sValue, $iDotPos + 1));
  468. }
  469. $oActCur = $oActCur ? $oActCur : $this->getConfig()->getActShopCurrencyObject();
  470. $iDecPos = ($iDecPos < $oActCur->decimal) ? $iDecPos : $oActCur->decimal;
  471. return number_format((double) $dValue, $iDecPos, $oActCur->dec, $oActCur->thousand);
  472. }
  473. /**
  474. * According to user configuration forms and return language prefix.
  475. *
  476. * @param integer $iLanguage User selected language (default null)
  477. *
  478. * @return string
  479. */
  480. public function getLanguageTag($iLanguage = null)
  481. {
  482. if (!isset($iLanguage)) {
  483. $iLanguage = $this->getBaseLanguage();
  484. }
  485. $iLanguage = (int) $iLanguage;
  486. return (($iLanguage) ? "_$iLanguage" : "");
  487. }
  488. /**
  489. * Validate language id. If not valid id, returns default value
  490. *
  491. * @param int $iLang Language id
  492. *
  493. * @return int
  494. */
  495. public function validateLanguage($iLang = null)
  496. {
  497. $iLang = (int) $iLang;
  498. // checking if this language is valid
  499. $aLanguages = $this->getLanguageArray(null, !$this->isAdmin());
  500. if (!isset($aLanguages[$iLang]) && is_array($aLanguages)) {
  501. $oLang = current($aLanguages);
  502. if (isset($oLang->id)) {
  503. $iLang = $oLang->id;
  504. }
  505. }
  506. return $iLang;
  507. }
  508. /**
  509. * Set base shop language
  510. *
  511. * @param int $iLang Language id
  512. */
  513. public function setBaseLanguage($iLang = null)
  514. {
  515. if (is_null($iLang)) {
  516. $iLang = $this->getBaseLanguage();
  517. } else {
  518. $this->_iBaseLanguageId = (int) $iLang;
  519. }
  520. if (defined('OXID_PHP_UNIT')) {
  521. modSession::getInstance();
  522. }
  523. oxRegistry::getSession()->setVariable('language', $iLang);
  524. }
  525. /**
  526. * Validates and sets templates language id
  527. *
  528. * @param int $iLang Language id
  529. *
  530. * @return null
  531. */
  532. public function setTplLanguage($iLang = null)
  533. {
  534. $this->_iTplLanguageId = isset($iLang) ? (int) $iLang : $this->getBaseLanguage();
  535. if ($this->isAdmin()) {
  536. $aLanguages = $this->getAdminTplLanguageArray();
  537. if (!isset($aLanguages[$this->_iTplLanguageId])) {
  538. $this->_iTplLanguageId = key($aLanguages);
  539. }
  540. }
  541. if (defined('OXID_PHP_UNIT')) {
  542. modSession::getInstance();
  543. }
  544. oxRegistry::getSession()->setVariable('tpllanguage', $this->_iTplLanguageId);
  545. return $this->_iTplLanguageId;
  546. }
  547. /**
  548. * Goes through language array and recodes its values. Returns recoded data
  549. *
  550. * @param array $aLangArray language data
  551. * @param string $sCharset charset which was used while making file
  552. * @param bool $blRecodeKeys leave keys untouched or recode it
  553. *
  554. * @return array
  555. */
  556. protected function _recodeLangArray($aLangArray, $sCharset, $blRecodeKeys = false)
  557. {
  558. $aLangs = array();
  559. foreach ($aLangArray as $sKey => $sValue) {
  560. $sItemKey = $sKey;
  561. if ($blRecodeKeys === true) {
  562. $sItemKey = iconv($sCharset, 'UTF-8', $sItemKey);
  563. }
  564. $aLangs[$sItemKey] = iconv($sCharset, 'UTF-8', $sValue);
  565. unset($aLangArray[$sKey]);
  566. }
  567. return $aLangs;
  568. }
  569. /**
  570. * Returns array with paths where frontend language files are stored
  571. *
  572. * @param int $iLang active language
  573. *
  574. * @return array
  575. */
  576. protected function _getLangFilesPathArray($iLang)
  577. {
  578. $oConfig = $this->getConfig();
  579. $aLangFiles = array();
  580. $sAppDir = $oConfig->getAppDir();
  581. $sLang = oxRegistry::getLang()->getLanguageAbbr($iLang);
  582. $sTheme = $oConfig->getConfigParam("sTheme");
  583. $sCustomTheme = $oConfig->getConfigParam("sCustomTheme");
  584. $sShopId = $oConfig->getShopId();
  585. $aModulePaths = $this->_getActiveModuleInfo();
  586. //get generic lang files
  587. $sGenericPath = $sAppDir . 'translations/' . $sLang;
  588. if ($sGenericPath) {
  589. $aLangFiles[] = $sGenericPath . "/lang.php";
  590. $aLangFiles = $this->_appendLangFile($aLangFiles, $sGenericPath);
  591. }
  592. //get theme lang files
  593. if ($sTheme) {
  594. $sThemePath = $sAppDir . 'views/' . $sTheme . '/' . $sLang;
  595. $aLangFiles[] = $sThemePath . "/lang.php";
  596. $aLangFiles = $this->_appendLangFile($aLangFiles, $sThemePath);
  597. }
  598. //get custom theme lang files
  599. if ($sCustomTheme) {
  600. $sCustPath = $sAppDir . 'views/' . $sCustomTheme . '/' . $sLang;
  601. $aLangFiles[] = $sCustPath . "/lang.php";
  602. $aLangFiles = $this->_appendLangFile($aLangFiles, $sCustPath);
  603. }
  604. // custom theme shop languages
  605. // modules language files
  606. $aLangFiles = $this->_appendModuleLangFiles($aLangFiles, $aModulePaths, $sLang);
  607. // custom language files
  608. $aLangFiles = $this->_appendCustomLangFiles($aLangFiles, $sLang);
  609. return count($aLangFiles) ? $aLangFiles : false;
  610. }
  611. /**
  612. * Returns array with paths where admin language files are stored
  613. *
  614. * @param int $iLang active language
  615. *
  616. * @return array
  617. */
  618. protected function _getAdminLangFilesPathArray($iLang)
  619. {
  620. $oConfig = $this->getConfig();
  621. $aLangFiles = array();
  622. $sAppDir = $oConfig->getAppDir();
  623. $sLang = oxRegistry::getLang()->getLanguageAbbr($iLang);
  624. $aModulePaths = array();
  625. $aModulePaths = array_merge($aModulePaths, $this->_getActiveModuleInfo());
  626. $aModulePaths = array_merge($aModulePaths, $this->_getDisabledModuleInfo());
  627. // admin lang files
  628. $sAdminPath = $sAppDir . 'views/admin/' . $sLang;
  629. $aLangFiles[] = $sAdminPath . "/lang.php";
  630. $aLangFiles[] = $sAppDir . 'translations/' . $sLang . '/translit_lang.php';
  631. $aLangFiles = $this->_appendLangFile($aLangFiles, $sAdminPath);
  632. // themes options lang files
  633. $sThemePath = $sAppDir . 'views/*/' . $sLang;
  634. $aLangFiles = $this->_appendLangFile($aLangFiles, $sThemePath, "options");
  635. // module language files
  636. $aLangFiles = $this->_appendModuleLangFiles($aLangFiles, $aModulePaths, $sLang, true);
  637. // custom language files
  638. $aLangFiles = $this->_appendCustomLangFiles($aLangFiles, $sLang, true);
  639. return count($aLangFiles) ? $aLangFiles : false;
  640. }
  641. /**
  642. * Appends lang or options files if exists, except custom lang files
  643. *
  644. * @param array $aLangFiles existing language files
  645. * @param string $sFullPath path to language files to append
  646. * @param string $sFilePattern file pattern to search for, default is "lang"
  647. *
  648. * @return array
  649. */
  650. protected function _appendLangFile($aLangFiles, $sFullPath, $sFilePattern = "lang")
  651. {
  652. $aFiles = glob($sFullPath . "/*_{$sFilePattern}.php");
  653. if (is_array($aFiles) && count($aFiles)) {
  654. foreach ($aFiles as $sFile) {
  655. if (!strpos($sFile, 'cust_lang.php')) {
  656. $aLangFiles[] = $sFile;
  657. }
  658. }
  659. }
  660. return $aLangFiles;
  661. }
  662. /**
  663. * Appends Custom language files cust_lang.php
  664. *
  665. * @param array $aLangFiles existing language files
  666. * @param string $sLang language abbreviation
  667. * @param bool $blForAdmin add files for admin
  668. *
  669. * @return array
  670. */
  671. protected function _appendCustomLangFiles($aLangFiles, $sLang, $blForAdmin = false)
  672. {
  673. $oConfig = $this->getConfig();
  674. $sAppDir = $oConfig->getAppDir();
  675. $sTheme = $oConfig->getConfigParam("sTheme");
  676. $sCustomTheme = $oConfig->getConfigParam("sCustomTheme");
  677. if ($blForAdmin) {
  678. $aLangFiles[] = $sAppDir . 'views/admin/' . $sLang . '/cust_lang.php';
  679. } else {
  680. if ($sTheme) {
  681. $aLangFiles[] = $sAppDir . 'views/' . $sTheme . '/' . $sLang . '/cust_lang.php';
  682. }
  683. if ($sCustomTheme) {
  684. $aLangFiles[] = $sAppDir . 'views/' . $sCustomTheme . '/' . $sLang . '/cust_lang.php';
  685. }
  686. }
  687. return $aLangFiles;
  688. }
  689. /**
  690. * Appends module lang or options files if exists
  691. *
  692. * @param array $aLangFiles existing language files
  693. * @param array $aModulePaths module language file paths
  694. * @param string $sLang language abbreviation
  695. * @param bool $blForAdmin add files for admin
  696. *
  697. * @return array
  698. */
  699. protected function _appendModuleLangFiles($aLangFiles, $aModulePaths, $sLang, $blForAdmin = false)
  700. {
  701. if (is_array($aModulePaths)) {
  702. $oConfig = $this->getConfig();
  703. foreach ($aModulePaths as $sPath) {
  704. $sFullPath = $oConfig->getModulesDir() . $sPath;
  705. if (file_exists($sFullPath . '/application/')) {
  706. $sFullPath .= '/application';
  707. }
  708. $sFullPath .= ($blForAdmin) ? '/views/admin/' : '/translations/';
  709. $sFullPath .= $sLang;
  710. $aLangFiles = $this->_appendLangFile($aLangFiles, $sFullPath);
  711. //load admin modules options lang files
  712. if ($blForAdmin) {
  713. $aLangFiles[] = $sFullPath . '/module_options.php';
  714. }
  715. }
  716. }
  717. return $aLangFiles;
  718. }
  719. /**
  720. * Returns language cache file name
  721. *
  722. * @param bool $blAdmin admin or not
  723. * @param int $iLang current language id
  724. * @param array $aLangFiles language files to load [optional]
  725. *
  726. * @return string
  727. */
  728. protected function _getLangFileCacheName($blAdmin, $iLang, $aLangFiles = null)
  729. {
  730. $myConfig = $this->getConfig();
  731. $sLangFilesIdent = '_default';
  732. if (is_array($aLangFiles) && $aLangFiles) {
  733. $sLangFilesIdent = '_' . md5(implode('+', $aLangFiles));
  734. }
  735. return "langcache_" . ((int) $blAdmin) . "_{$iLang}_" . $myConfig->getShopId() . "_" . $myConfig->getConfigParam('sTheme') . $sLangFilesIdent;
  736. }
  737. /**
  738. * Returns language cache array
  739. *
  740. * @param bool $blAdmin admin or not [optional]
  741. * @param int $iLang current language id [optional]
  742. * @param array $aLangFiles language files to load [optional]
  743. *
  744. * @return array
  745. */
  746. protected function _getLanguageFileData($blAdmin = false, $iLang = 0, $aLangFiles = null)
  747. {
  748. $myConfig = $this->getConfig();
  749. $myUtils = oxRegistry::getUtils();
  750. $sCacheName = $this->_getLangFileCacheName($blAdmin, $iLang, $aLangFiles);
  751. $aLangCache = $myUtils->getLangCache($sCacheName);
  752. if (!$aLangCache && $aLangFiles === null) {
  753. if ($blAdmin) {
  754. $aLangFiles = $this->_getAdminLangFilesPathArray($iLang);
  755. } else {
  756. $aLangFiles = $this->_getLangFilesPathArray($iLang);
  757. }
  758. }
  759. if (!$aLangCache && $aLangFiles) {
  760. $aLangCache = array();
  761. $sBaseCharset = false;
  762. $aLang = array();
  763. $aLangSeoReplaceChars = array();
  764. foreach ($aLangFiles as $sLangFile) {
  765. if (file_exists($sLangFile) && is_readable($sLangFile)) {
  766. $aSeoReplaceChars = array();
  767. include $sLangFile;
  768. // including only (!) those, which has charset defined
  769. if (isset($aLang['charset'])) {
  770. // recoding only in utf
  771. if ($myConfig->isUtf()) {
  772. $aLang = $this->_recodeLangArray($aLang, $aLang['charset']);
  773. if (isset($aSeoReplaceChars) && is_array($aSeoReplaceChars)) {
  774. $aSeoReplaceChars = $this->_recodeLangArray($aSeoReplaceChars, $aLang['charset'], true);
  775. }
  776. // overriding charset
  777. $aLang['charset'] = 'UTF-8';
  778. }
  779. if (isset($aSeoReplaceChars) && is_array($aSeoReplaceChars)) {
  780. $aLangSeoReplaceChars = array_merge($aLangSeoReplaceChars, $aSeoReplaceChars);
  781. }
  782. if (!$sBaseCharset) {
  783. $sBaseCharset = $aLang['charset'];
  784. }
  785. $aLangCache = array_merge($aLangCache, $aLang);
  786. }
  787. }
  788. }
  789. // setting base charset
  790. if ($sBaseCharset) {
  791. $aLangCache['charset'] = $sBaseCharset;
  792. }
  793. // special character replacement list
  794. $aLangCache['_aSeoReplaceChars'] = $aLangSeoReplaceChars;
  795. //save to cache
  796. $myUtils->setLangCache($sCacheName, $aLangCache);
  797. }
  798. return $aLangCache;
  799. }
  800. /**
  801. * Returns language map array
  802. *
  803. * @param int $iLang language index
  804. * @param bool $blAdmin admin mode [default NULL]
  805. *
  806. * @return array
  807. */
  808. protected function _getLanguageMap($iLang, $blAdmin = null)
  809. {
  810. $blAdmin = isset($blAdmin) ? $blAdmin : $this->isAdmin();
  811. $sKey = $iLang . ((int) $blAdmin);
  812. if (!isset($this->_aLangMap[$sKey])) {
  813. $this->_aLangMap[$sKey] = array();
  814. $myConfig = $this->getConfig();
  815. $sMapFile = '';
  816. $sParentMapFile = $myConfig->getAppDir() . '/views/' . ($blAdmin ? 'admin' : $myConfig->getConfigParam("sTheme")) . '/' . oxRegistry::getLang()->getLanguageAbbr($iLang) . '/map.php';
  817. $sCustomThemeMapFile = $myConfig->getAppDir() . '/views/' . ($blAdmin ? 'admin' : $myConfig->getConfigParam("sCustomTheme")) . '/' . oxRegistry::getLang()->getLanguageAbbr($iLang) . '/map.php';
  818. if (file_exists($sCustomThemeMapFile) && is_readable($sCustomThemeMapFile)) {
  819. $sMapFile = $sCustomThemeMapFile;
  820. } elseif (file_exists($sParentMapFile) && is_readable($sParentMapFile)) {
  821. $sMapFile = $sParentMapFile;
  822. }
  823. if ($sMapFile) {
  824. include $sMapFile;
  825. $this->_aLangMap[$sKey] = $aMap;
  826. }
  827. }
  828. return $this->_aLangMap[$sKey];
  829. }
  830. /**
  831. * Returns current language cache language id
  832. *
  833. * @param bool $blAdmin admin mode
  834. * @param int $iLang language id [optional]
  835. *
  836. * @return int
  837. */
  838. protected function _getCacheLanguageId($blAdmin, $iLang = null)
  839. {
  840. $iLang = ($iLang === null && $blAdmin) ? $this->getTplLanguage() : $iLang;
  841. if (!isset($iLang)) {
  842. $iLang = $this->getBaseLanguage();
  843. if (!isset($iLang)) {
  844. $iLang = 0;
  845. }
  846. }
  847. return (int) $iLang;
  848. }
  849. /**
  850. * get language array from lang translation file
  851. *
  852. * @param int $iLang optional language
  853. * @param bool $blAdmin admin mode switch
  854. * @param array $aLangFiles language files to load [optional]
  855. *
  856. * @return array
  857. */
  858. protected function _getLangTranslationArray($iLang = null, $blAdmin = null, $aLangFiles = null)
  859. {
  860. startProfile("_getLangTranslationArray");
  861. $blAdmin = isset($blAdmin) ? $blAdmin : $this->isAdmin();
  862. $iLang = $this->_getCacheLanguageId($blAdmin, $iLang);
  863. $sCacheName = $this->_getLangFileCacheName($blAdmin, $iLang, $aLangFiles);
  864. if (!isset($this->_aLangCache[$sCacheName])) {
  865. $this->_aLangCache[$sCacheName] = array();
  866. }
  867. if (!isset($this->_aLangCache[$sCacheName][$iLang])) {
  868. // loading main lang files data
  869. $this->_aLangCache[$sCacheName][$iLang] = $this->_getLanguageFileData($blAdmin, $iLang, $aLangFiles);
  870. }
  871. stopProfile("_getLangTranslationArray");
  872. // if language array exists ..
  873. return (isset($this->_aLangCache[$sCacheName][$iLang]) ? $this->_aLangCache[$sCacheName][$iLang] : array());
  874. }
  875. /**
  876. * Language sorting callback function
  877. *
  878. * @param object $a1 first value to check
  879. * @param object $a2 second value to check
  880. *
  881. * @return bool
  882. */
  883. protected function _sortLanguagesCallback($a1, $a2)
  884. {
  885. return ($a1->sort > $a2->sort);
  886. }
  887. /**
  888. * Returns language id param name
  889. *
  890. * @return string
  891. */
  892. public function getName()
  893. {
  894. return $this->_sName;
  895. }
  896. /**
  897. * Returns form hidden language parameter
  898. *
  899. * @return string
  900. */
  901. public function getFormLang()
  902. {
  903. $sLang = null;
  904. if (!$this->isAdmin()) {
  905. $sLang = "<input type=\"hidden\" name=\"" . $this->getName() . "\" value=\"" . $this->getBaseLanguage() . "\" />";
  906. }
  907. return $sLang;
  908. }
  909. /**
  910. * Returns url language parameter
  911. *
  912. * @param int $iLang language id [optional]
  913. *
  914. * @return string
  915. */
  916. public function getUrlLang($iLang = null)
  917. {
  918. $sLang = null;
  919. if (!$this->isAdmin()) {
  920. $iLang = isset($iLang) ? $iLang : $this->getBaseLanguage();
  921. $sLang = $this->getName() . "=" . $iLang;
  922. }
  923. return $sLang;
  924. }
  925. /**
  926. * Is needed appends url with language parameter
  927. * Direct usage of this method to retrieve end url result is discouraged - instead
  928. * see oxUtilsUrl::processUrl
  929. *
  930. * @param string $sUrl url to process
  931. * @param int $iLang language id [optional]
  932. *
  933. * @see oxUtilsUrl::processUrl
  934. *
  935. * @return string
  936. */
  937. public function processUrl($sUrl, $iLang = null)
  938. {
  939. $iLang = isset($iLang) ? $iLang : $this->getBaseLanguage();
  940. /** @var oxStrRegular $oStr */
  941. $oStr = getStr();
  942. if (!$this->isAdmin()) {
  943. $sParam = $this->getUrlLang($iLang);
  944. if (!$oStr->preg_match('/(\?|&(amp;)?)lang=[0-9]+/', $sUrl) && ($iLang != oxRegistry::getConfig()->getConfigParam('sDefaultLang'))) {
  945. if ($sUrl) {
  946. if ($oStr->strpos($sUrl, '?') === false) {
  947. $sUrl .= "?";
  948. } elseif (!$oStr->preg_match('/(\?|&(amp;)?)$/', $sUrl)) {
  949. $sUrl .= "&amp;";
  950. }
  951. }
  952. $sUrl .= $sParam . "&amp;";
  953. } else {
  954. $sUrl = $oStr->preg_replace('/(\?|&(amp;)?)lang=[0-9]+/', '\1' . $sParam, $sUrl);
  955. }
  956. }
  957. return $sUrl;
  958. }
  959. /**
  960. * Detect language by user browser settings. Returns language ID if
  961. * detected, otherwise returns null.
  962. *
  963. * @return int
  964. */
  965. public function detectLanguageByBrowser()
  966. {
  967. $sBrowserLanguage = $this->_getBrowserLanguage();
  968. if (!is_null($sBrowserLanguage)) {
  969. $aLanguages = $this->getLanguageArray(null, true);
  970. foreach ($aLanguages as $oLang) {
  971. if ($oLang->abbr == $sBrowserLanguage) {
  972. return $oLang->id;
  973. }
  974. }
  975. }
  976. }
  977. /**
  978. * Returns all multi language tables
  979. *
  980. * @return array
  981. */
  982. public function getMultiLangTables()
  983. {
  984. $aTables = array("oxarticles", "oxartextends", "oxattribute",
  985. "oxcategories", "oxcontents", "oxcountry",
  986. "oxdelivery", "oxdiscount", "oxgroups",
  987. "oxlinks", "oxnews", "oxobject2attribute",
  988. "oxpayments", "oxselectlist", "oxshops",
  989. "oxactions", "oxwrapping", "oxdeliveryset",
  990. "oxvendor", "oxmanufacturers", "oxmediaurls",
  991. "oxstates");
  992. $aMultiLangTables = $this->getConfig()->getConfigParam('aMultiLangTables');
  993. if (is_array($aMultiLangTables)) {
  994. $aTables = array_merge($aTables, $aMultiLangTables);
  995. }
  996. return $aTables;
  997. }
  998. /**
  999. * Get SEO spec. chars replacement list for current language
  1000. *
  1001. * @param int $iLang language ID
  1002. *
  1003. * @return null
  1004. */
  1005. public function getSeoReplaceChars($iLang)
  1006. {
  1007. // get language replace chars
  1008. $aSeoReplaceChars = $this->translateString('_aSeoReplaceChars', $iLang);
  1009. if (!is_array($aSeoReplaceChars)) {
  1010. $aSeoReplaceChars = array();
  1011. }
  1012. return $aSeoReplaceChars;
  1013. }
  1014. /**
  1015. * Returns active module Ids with paths
  1016. *
  1017. * @return array
  1018. */
  1019. protected function _getActiveModuleInfo()
  1020. {
  1021. if ($this->_aActiveModuleInfo === null) {
  1022. $oModuleList = oxNew('oxModuleList');
  1023. $this->_aActiveModuleInfo = $oModuleList->getActiveModuleInfo();
  1024. }
  1025. return $this->_aActiveModuleInfo;
  1026. }
  1027. /**
  1028. * Returns active module Ids with paths
  1029. *
  1030. * @return array
  1031. */
  1032. protected function _getDisabledModuleInfo()
  1033. {
  1034. if ($this->_aDisabledModuleInfo === null) {
  1035. $oModuleList = oxNew('oxModuleList');
  1036. $this->_aDisabledModuleInfo = $oModuleList->getDisabledModuleInfo();
  1037. }
  1038. return $this->_aDisabledModuleInfo;
  1039. }
  1040. /**
  1041. * Gets browser language.
  1042. *
  1043. * @return string
  1044. */
  1045. protected function _getBrowserLanguage()
  1046. {
  1047. $sBrowserLang = null;
  1048. if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && $_SERVER['HTTP_ACCEPT_LANGUAGE']) {
  1049. $sBrowserLang = strtolower(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2));
  1050. }
  1051. return $sBrowserLang;
  1052. }
  1053. /**
  1054. * Returns available language IDs (abbreviations) for all sub shops
  1055. *
  1056. * @return array
  1057. */
  1058. public function getAllShopLanguageIds()
  1059. {
  1060. $aLanguages = $this->_getLanguageIdsFromDatabase();
  1061. return $aLanguages;
  1062. }
  1063. /**
  1064. * Get current Shop language ids.
  1065. *
  1066. * @param int $iShopId shop id
  1067. *
  1068. * @return array
  1069. */
  1070. public function getLanguageIds($iShopId = null)
  1071. {
  1072. if (empty($iShopId) || $iShopId == $this->getConfig()->getShopId()) {
  1073. $aLanguages = $this->getActiveShopLanguageIds();
  1074. } else {
  1075. $aLanguages = $this->_getLanguageIdsFromDatabase($iShopId);
  1076. }
  1077. return $aLanguages;
  1078. }
  1079. /**
  1080. * Returns available language IDs (abbreviations)
  1081. *
  1082. * @return array
  1083. */
  1084. public function getActiveShopLanguageIds()
  1085. {
  1086. $oConfig = $this->getConfig();
  1087. //if exists language parameters array, extract lang id's from there
  1088. $aLangParams = $oConfig->getConfigParam('aLanguageParams');
  1089. if (is_array($aLangParams)) {
  1090. $aIds = $this->_getLanguageIdsFromLanguageParamsArray($aLangParams);
  1091. } else {
  1092. $aIds = $this->_getLanguageIdsFromLanguagesArray($oConfig->getConfigParam('aLanguages'));
  1093. }
  1094. return $aIds;
  1095. }
  1096. /**
  1097. * Gets language Ids for given shopId or for all subshops
  1098. *
  1099. * @param null $iShopId
  1100. *
  1101. * @return array
  1102. */
  1103. protected function _getLanguageIdsFromDatabase($iShopId = null)
  1104. {
  1105. $aLanguages = $this->getLanguageIds();
  1106. return $aLanguages;
  1107. }
  1108. /**
  1109. * Returns list of all language codes taken from config values of given 'aLanguages' (for all subshops)
  1110. *
  1111. * @param string $sLanguageParameterName language config parameter name
  1112. * @param int $iShopId shop id
  1113. *
  1114. * @return array
  1115. */
  1116. protected function _getConfigLanguageValues($sLanguageParameterName, $iShopId = null)
  1117. {
  1118. $aConfigDecodedValues = array();
  1119. $aConfigValues = $this->_selectLanguageParamValues($sLanguageParameterName, $iShopId);
  1120. foreach ($aConfigValues as $sConfigValue) {
  1121. $aConfigLanguages = unserialize($sConfigValue['oxvarvalue']);
  1122. $aLanguages = array();
  1123. if ($sLanguageParameterName == 'aLanguageParams') {
  1124. $aLanguages = $this->_getLanguageIdsFromLanguageParamsArray($aConfigLanguages);
  1125. } elseif ($sLanguageParameterName == 'aLanguages') {
  1126. $aLanguages = $this->_getLanguageIdsFromLanguagesArray($aConfigLanguages);
  1127. }
  1128. $aConfigDecodedValues = array_unique(array_merge($aConfigDecodedValues, $aLanguages));
  1129. }
  1130. return $aConfigDecodedValues;
  1131. }
  1132. /**
  1133. * Returns array of all config values of given paramName
  1134. *
  1135. * @param string $sParamName Parameter name
  1136. * @param string|null $sShopId Shop id
  1137. *
  1138. * @return array
  1139. */
  1140. protected function _selectLanguageParamValues($sParamName, $sShopId = null)
  1141. {
  1142. $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
  1143. $oConfig = oxRegistry::getConfig();
  1144. $sQuery = "
  1145. select " . $oConfig->getDecodeValueQuery() . " as oxvarvalue
  1146. from oxconfig
  1147. where oxvarname = '{$sParamName}' ";
  1148. if (!empty($sShopId)) {
  1149. $sQuery .= " and oxshopid = '{$sShopId}' limit 1";
  1150. }
  1151. return $oDb->getArray($sQuery);
  1152. }
  1153. /**
  1154. * gets language code array from aLanguageParams array
  1155. *
  1156. * @param array $aLanguageParams Language parameters
  1157. *
  1158. * @return array
  1159. */
  1160. protected function _getLanguageIdsFromLanguageParamsArray($aLanguageParams)
  1161. {
  1162. $aLanguages = array();
  1163. foreach ($aLanguageParams as $sAbbr => $aValue) {
  1164. $iBaseId = (int) $aValue['baseId'];
  1165. $aLanguages[$iBaseId] = $sAbbr;
  1166. }
  1167. return $aLanguages;
  1168. }
  1169. /**
  1170. * gets language code array from aLanguages array
  1171. *
  1172. * @param array $aLanguages Languages
  1173. *
  1174. * @return array
  1175. */
  1176. protected function _getLanguageIdsFromLanguagesArray($aLanguages)
  1177. {
  1178. return array_keys($aLanguages);
  1179. }
  1180. }