PageRenderTime 62ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/language/language.php

https://bitbucket.org/elin/joomla-platform
PHP | 1197 lines | 712 code | 108 blank | 377 comment | 72 complexity | 668dcd5ebdea30593e9dd94791c8aacd MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Language
  5. *
  6. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. /**
  11. * Allows for quoting in language .ini files.
  12. */
  13. define('_QQ_', '"');
  14. // import some libraries
  15. jimport('joomla.filesystem.stream');
  16. /**
  17. * Languages/translation handler class
  18. *
  19. * @package Joomla.Platform
  20. * @subpackage Language
  21. * @since 11.1
  22. */
  23. class JLanguage extends JObject
  24. {
  25. protected static $languages = array();
  26. /**
  27. * Debug language, If true, highlights if string isn't found
  28. *
  29. * @var boolean
  30. * @since 11.1
  31. */
  32. protected $debug = false;
  33. /**
  34. * The default language
  35. *
  36. * The default language is used when a language file in the requested language does not exist.
  37. *
  38. * @var string
  39. * @since 11.1
  40. */
  41. protected $default = 'en-GB';
  42. /**
  43. * An array of orphaned text
  44. *
  45. * @var array
  46. * @since 11.1
  47. */
  48. protected $orphans = array();
  49. /**
  50. * Array holding the language metadata
  51. *
  52. * @var array
  53. * @since 11.1
  54. */
  55. protected $metadata = null;
  56. /**
  57. * Array|boolean holding the language locale
  58. *
  59. * @var array|boolean
  60. * @since 11.1
  61. */
  62. protected $locale = null;
  63. /**
  64. * The language to load
  65. *
  66. * @var string
  67. * @since 11.1
  68. */
  69. protected $lang = null;
  70. /**
  71. * List of language files that have been loaded
  72. *
  73. * @var array of arrays
  74. * @since 11.1
  75. */
  76. protected $paths = array();
  77. /**
  78. * List of language files that are in error state
  79. *
  80. * @var array of string
  81. * @since 11.1
  82. */
  83. protected $errorfiles = array();
  84. /**
  85. * Translations
  86. *
  87. * @var array
  88. * @since 11.1
  89. */
  90. protected $strings = null;
  91. /**
  92. * An array of used text, used during debugging
  93. *
  94. * @var array
  95. * @since 11.1
  96. */
  97. protected $used = array();
  98. /**
  99. * Counter for number of loads
  100. *
  101. * @var integer
  102. * @since 11.1
  103. */
  104. protected $counter = 0;
  105. /**
  106. * An array used to store overrides
  107. *
  108. * @var array
  109. * @since 11.1
  110. */
  111. protected $override = array();
  112. /**
  113. * Name of the transliterator function for this language
  114. *
  115. * @var string
  116. * @since 11.1
  117. */
  118. protected $transliterator = null;
  119. /**
  120. * Name of the pluralSufficesCallback function for this language
  121. *
  122. * @var string
  123. * @since 11.1
  124. */
  125. protected $pluralSufficesCallback = null;
  126. /**
  127. * Name of the ignoredSearchWordsCallback function for this language
  128. *
  129. * @var string
  130. * @since 11.1
  131. */
  132. protected $ignoredSearchWordsCallback = null;
  133. /**
  134. * Name of the lowerLimitSearchWordCallback function for this language
  135. *
  136. * @var string
  137. * @since 11.1
  138. */
  139. protected $lowerLimitSearchWordCallback = null;
  140. /**
  141. * Name of the uppperLimitSearchWordCallback function for this language
  142. *
  143. * @var string
  144. * @since 11.1
  145. */
  146. protected $upperLimitSearchWordCallback = null;
  147. /**
  148. * Name of the searchDisplayedCharactersNumberCallback function for this language
  149. *
  150. * @var string
  151. * @since 11.1
  152. */
  153. protected $searchDisplayedCharactersNumberCallback = null;
  154. /**
  155. * Constructor activating the default information of the language
  156. */
  157. public function __construct($lang = null, $debug = false)
  158. {
  159. $this->strings = array ();
  160. if ($lang == null) {
  161. $lang = $this->default;
  162. }
  163. $this->setLanguage($lang);
  164. $this->setDebug($debug);
  165. $filename = JPATH_BASE . "/language/overrides/$lang.override.ini";
  166. if (file_exists($filename) && $contents = $this->parse($filename)) {
  167. if (is_array($contents)) {
  168. $this->override = $contents;
  169. }
  170. unset($contents);
  171. }
  172. // Look for a language specific localise class
  173. $class = str_replace('-', '_', $lang . 'Localise');
  174. if (!class_exists($class) && defined('JPATH_SITE')) {
  175. // Class does not exist. Try to find it in the Site Language Folder
  176. $localise = JPATH_SITE . "/language/$lang/$lang.localise.php";
  177. if (file_exists($localise)) {
  178. require_once $localise;
  179. }
  180. }
  181. if (!class_exists($class) && defined('JPATH_ADMINISTRATOR')) {
  182. // Class does not exist. Try to find it in the Administrator Language Folder
  183. $localise = JPATH_ADMINISTRATOR . "/language/$lang/$lang.localise.php";
  184. if (file_exists($localise)) {
  185. require_once $localise;
  186. }
  187. }
  188. if (class_exists($class)) {
  189. /* Class exists. Try to find
  190. * -a transliterate method,
  191. * -a getPluralSuffixes method,
  192. * -a getIgnoredSearchWords method
  193. * -a getLowerLimitSearchWord method
  194. * -a getUpperLimitSearchWord method
  195. * -a getSearchDisplayCharactersNumber method
  196. */
  197. if (method_exists($class, 'transliterate')) {
  198. $this->transliterator = array($class, 'transliterate');
  199. }
  200. if (method_exists($class, 'getPluralSuffixes')) {
  201. $this->pluralSufficesCallback = array($class, 'getPluralSuffixes');
  202. }
  203. if (method_exists($class, 'getIgnoredSearchWords')) {
  204. $this->ignoredSearchWordsCallback = array($class, 'getIgnoredSearchWords');
  205. }
  206. if (method_exists($class, 'getLowerLimitSearchWord')) {
  207. $this->lowerLimitSearchWordCallback = array($class, 'getLowerLimitSearchWord');
  208. }
  209. if (method_exists($class, 'getUpperLimitSearchWord')) {
  210. $this->upperLimitSearchWordCallback = array($class, 'getUpperLimitSearchWord');
  211. }
  212. if (method_exists($class, 'getSearchDisplayedCharactersNumber')) {
  213. $this->searchDisplayedCharactersNumberCallback = array($class, 'getSearchDisplayedCharactersNumber');
  214. }
  215. }
  216. $this->load();
  217. }
  218. /**
  219. * Returns a language object
  220. *
  221. * @param string $lang The language to use.
  222. * @param boolean $debug The debug mode
  223. * @return JLanguage The Language object.
  224. * @since 11.1
  225. */
  226. public static function getInstance($lang, $debug=false)
  227. {
  228. if (!isset(self::$languages[$lang.$debug])) {
  229. self::$languages[$lang.$debug] = new JLanguage($lang, $debug);
  230. }
  231. return self::$languages[$lang.$debug];
  232. }
  233. /**
  234. * Translate function, mimics the php gettext (alias _) function
  235. *
  236. * @param string $string The string to translate
  237. * @param boolean $jsSafe Make the result javascript safe
  238. * @param boolean $interpretBackslashes Interpret \t and \n
  239. * @return string The translation of the string
  240. * @note The function checks if $jsSafe is true then if $interpretBackslashes is true
  241. * @since 11.1
  242. */
  243. public function _($string, $jsSafe = false, $interpretBackSlashes = true)
  244. {
  245. $key = strtoupper($string);
  246. if (isset ($this->strings[$key])) {
  247. $string = $this->debug ? '**'.$this->strings[$key].'**' : $this->strings[$key];
  248. // Store debug information
  249. if ($this->debug) {
  250. $caller = $this->getCallerInfo();
  251. if (! array_key_exists($key, $this->used)) {
  252. $this->used[$key] = array();
  253. }
  254. $this->used[$key][] = $caller;
  255. }
  256. } else {
  257. if ($this->debug) {
  258. $caller = $this->getCallerInfo();
  259. $caller['string'] = $string;
  260. if (! array_key_exists($key, $this->orphans)) {
  261. $this->orphans[$key] = array();
  262. }
  263. $this->orphans[$key][] = $caller;
  264. $string = '??'.$string.'??';
  265. }
  266. }
  267. if ($jsSafe) {
  268. // javascript filter
  269. $string = addslashes($string);
  270. }
  271. elseif ($interpretBackSlashes) {
  272. // interpret \n and \t characters
  273. $string = str_replace(array('\\\\','\t','\n'),array("\\", "\t","\n"),$string);
  274. }
  275. return $string;
  276. }
  277. /**
  278. * Transliterate function
  279. *
  280. * This method processes a string and replaces all accented UTF-8 characters by unaccented
  281. * ASCII-7 "equivalents"
  282. *
  283. * @param string $string The string to transliterate
  284. * @return string The transliteration of the string
  285. * @since 11.1
  286. */
  287. public function transliterate($string)
  288. {
  289. include_once dirname(__FILE__) . '/latin_transliterate.php';
  290. if ($this->transliterator !== null) {
  291. return call_user_func($this->transliterator, $string);
  292. }
  293. $string = JLanguageTransliterate::utf8_latin_to_ascii($string);
  294. $string = JString::strtolower($string);
  295. return $string;
  296. }
  297. /**
  298. * Getter for transliteration function
  299. *
  300. * @return string|function Function name or the actual function for PHP 5.3
  301. * @since 11.1
  302. */
  303. public function getTransliterator()
  304. {
  305. return $this->transliterator;
  306. }
  307. /**
  308. * Set the transliteration function
  309. *
  310. * @return string|function Function name or the actual function for PHP 5.3
  311. * @since 11.1
  312. */
  313. public function setTransliterator($function)
  314. {
  315. $previous = $this->transliterator;
  316. $this->transliterator = $function;
  317. return $previous;
  318. }
  319. /**
  320. * pluralSuffixes function
  321. *
  322. * This method return an array of suffixes for plural rules
  323. *
  324. * @param int $count The count number
  325. * @return array The array of suffixes
  326. * @since 11.1
  327. */
  328. public function getPluralSuffixes($count) {
  329. if ($this->pluralSufficesCallback !== null) {
  330. return call_user_func($this->pluralSufficesCallback, $count);
  331. }
  332. else {
  333. return array((string)$count);
  334. }
  335. }
  336. /**
  337. * Getter for pluralSufficesCallback function
  338. *
  339. * @return string|function Function name or the actual function for PHP 5.3
  340. * @since 11.1
  341. */
  342. public function getPluralSuffixesCallback() {
  343. return $this->pluralSufficesCallback;
  344. }
  345. /**
  346. * Set the pluralSuffices function
  347. *
  348. * @return string|function Function name or the actual function for PHP 5.3
  349. * @since 11.1
  350. */
  351. public function setPluralSufficesCallback($function) {
  352. $previous = $this->pluralSufficesCallback;
  353. $this->pluralSufficesCallback = $function;
  354. return $previous;
  355. }
  356. /**
  357. * getIgnoredSearchWords function
  358. *
  359. * This method returns an array of ignored search words
  360. *
  361. * @return array The array of ignored search words
  362. * @since 11.1
  363. */
  364. public function getIgnoredSearchWords() {
  365. if ($this->ignoredSearchWordsCallback !== null) {
  366. return call_user_func($this->ignoredSearchWordsCallback);
  367. }
  368. else {
  369. return array();
  370. }
  371. }
  372. /**
  373. * Getter for ignoredSearchWordsCallback function
  374. *
  375. * @return string|function Function name or the actual function for PHP 5.3
  376. * @since 11.1
  377. */
  378. public function getIgnoredSearchWordsCallback() {
  379. return $this->ignoredSearchWordsCallback;
  380. }
  381. /**
  382. * Setter for the ignoredSearchWordsCallback function
  383. *
  384. * @return string|function Function name or the actual function for PHP 5.3
  385. * @since 11.1
  386. */
  387. public function setIgnoredSearchWordsCallback($function) {
  388. $previous = $this->ignoredSearchWordsCallback;
  389. $this->ignoredSearchWordsCallback = $function;
  390. return $previous;
  391. }
  392. /**
  393. * getLowerLimitSearchWord function
  394. *
  395. * This method returns a lower limit integer for length of search words
  396. *
  397. * @return integer The lower limit integer for length of search words (3 if no value was set for a specific language)
  398. * @since 11.1
  399. */
  400. public function getLowerLimitSearchWord() {
  401. if ($this->lowerLimitSearchWordCallback !== null) {
  402. return call_user_func($this->lowerLimitSearchWordCallback);
  403. }
  404. else {
  405. return 3;
  406. }
  407. }
  408. /**
  409. * Getter for lowerLimitSearchWordCallback function
  410. *
  411. * @return string|function Function name or the actual function for PHP 5.3
  412. * @since 11.1
  413. */
  414. public function getLowerLimitSearchWordCallback() {
  415. return $this->lowerLimitSearchWordCallback;
  416. }
  417. /**
  418. * Setter for the lowerLimitSearchWordCallback function
  419. *
  420. * @return string|function Function name or the actual function for PHP 5.3
  421. * @since 11.1
  422. */
  423. public function setLowerLimitSearchWordCallback($function) {
  424. $previous = $this->lowerLimitSearchWordCallback;
  425. $this->lowerLimitSearchWordCallback = $function;
  426. return $previous;
  427. }
  428. /**
  429. * getUpperLimitSearchWord function
  430. *
  431. * This method returns an upper limit integer for length of search words
  432. *
  433. * @return integer The upper limit integer for length of search words (20 if no value was set for a specific language)
  434. * @since 11.1
  435. */
  436. public function getUpperLimitSearchWord() {
  437. if ($this->upperLimitSearchWordCallback !== null) {
  438. return call_user_func($this->upperLimitSearchWordCallback);
  439. }
  440. else {
  441. return 20;
  442. }
  443. }
  444. /**
  445. * Getter for upperLimitSearchWordCallback function
  446. *
  447. * @return string|function Function name or the actual function for PHP 5.3
  448. * @since 11.1
  449. */
  450. public function getUpperLimitSearchWordCallback() {
  451. return $this->upperLimitSearchWordCallback;
  452. }
  453. /**
  454. * Setter for the upperLimitSearchWordCallback function
  455. *
  456. * @return string|function Function name or the actual function for PHP 5.3
  457. * @since 11.1
  458. */
  459. public function setUpperLimitSearchWordCallback($function) {
  460. $previous = $this->upperLimitSearchWordCallback;
  461. $this->upperLimitSearchWordCallback = $function;
  462. return $previous;
  463. }
  464. /**
  465. * getSearchDisplayedCharactersNumber function
  466. *
  467. * This method returns the number of characters displayed during research
  468. *
  469. * @return integer The number of characters displayed during research (200 if no value was set for a specific language)
  470. * @since 11.1
  471. */
  472. public function getSearchDisplayedCharactersNumber() {
  473. if ($this->searchDisplayedCharactersNumberCallback !== null) {
  474. return call_user_func($this->searchDisplayedCharactersNumberCallback);
  475. }
  476. else {
  477. return 200;
  478. }
  479. }
  480. /**
  481. * Getter for searchDisplayedCharactersNumberCallback function
  482. *
  483. * @return string|function Function name or the actual function for PHP 5.3
  484. * @since 11.1
  485. */
  486. public function getSearchDisplayedCharactersNumberCallback() {
  487. return $this->searchDisplayedCharactersNumberCallback;
  488. }
  489. /**
  490. * Setter for the searchDisplayedCharactersNumberCallback function
  491. *
  492. * @return string|function Function name or the actual function for PHP 5.3
  493. * @since 11.1
  494. */
  495. public function setSearchDisplayedCharactersNumberCallback($function) {
  496. $previous = $this->searchDisplayedCharactersNumberCallback;
  497. $this->searchDisplayedCharactersNumberCallback = $function;
  498. return $previous;
  499. }
  500. /**
  501. * Check if a language exists
  502. *
  503. * This is a simple, quick check for the directory that should contain language files for the given user.
  504. *
  505. * @param string $lang Language to check
  506. * @param string $basePath Optional path to check
  507. * @return boolean True if the language exists
  508. * @since 11.1
  509. */
  510. public static function exists($lang, $basePath = JPATH_BASE)
  511. {
  512. static $paths = array();
  513. // Return false if no language was specified
  514. if (! $lang) {
  515. return false;
  516. }
  517. $path = "$basePath/language/$lang";
  518. // Return previous check results if it exists
  519. if (isset($paths[$path]))
  520. {
  521. return $paths[$path];
  522. }
  523. // Check if the language exists
  524. jimport('joomla.filesystem.folder');
  525. $paths[$path] = JFolder::exists($path);
  526. return $paths[$path];
  527. }
  528. /**
  529. * Loads a single language file and appends the results to the existing strings
  530. *
  531. * @param string $extension The extension for which a language file should be loaded
  532. * @param string $basePath The basepath to use
  533. * @param string $lang The language to load, default null for the current language
  534. * @param boolean $reload Flag that will force a language to be reloaded if set to true
  535. * @param boolean $default Flag that force the default language to be loaded if the current does not exist
  536. * @return boolean True, if the file has successfully loaded.
  537. * @since 11.1
  538. */
  539. public function load($extension = 'joomla', $basePath = JPATH_BASE, $lang = null, $reload = false, $default = true)
  540. {
  541. if (! $lang) {
  542. $lang = $this->lang;
  543. }
  544. $path = self::getLanguagePath($basePath, $lang);
  545. $internal = $extension == 'joomla' || $extension == '';
  546. $filename = $internal ? $lang : $lang . '.' . $extension;
  547. $filename = "$path/$filename.ini";
  548. $result = false;
  549. if (isset($this->paths[$extension][$filename]) && ! $reload) {
  550. // Strings for this file have already been loaded
  551. $result = true;
  552. } else {
  553. // Load the language file
  554. $result = $this->loadLanguage($filename, $extension);
  555. // Check if there was a problem with loading the file
  556. if ($result === false && $default) {
  557. // No strings, so either file doesn't exist or the file is invalid
  558. $oldFilename = $filename;
  559. // Check the standard file name
  560. $path = self::getLanguagePath($basePath, $this->default);
  561. $filename = $internal ? $this->default : $this->default . '.' . $extension;
  562. $filename = "$path/$filename.ini";
  563. // If the one we tried is different than the new name, try again
  564. if ($oldFilename != $filename) {
  565. $result = $this->loadLanguage($filename, $extension, false);
  566. }
  567. }
  568. }
  569. return $result;
  570. }
  571. /**
  572. * Loads a language file
  573. *
  574. * This method will not note the successful loading of a file - use load() instead
  575. *
  576. * @param string The name of the file
  577. * @param string The name of the extension
  578. * @return boolean True if new strings have been added to the language
  579. * @see JLanguage::load()
  580. * @since 11.1
  581. */
  582. protected function loadLanguage($filename, $extension = 'unknown', $overwrite = true)
  583. {
  584. $this->counter++;
  585. $result = false;
  586. $strings = false;
  587. if (file_exists($filename)) {
  588. $strings = $this->parse($filename);
  589. }
  590. if ($strings) {
  591. if (is_array($strings)) {
  592. $this->strings = array_merge($this->strings, $strings);
  593. }
  594. if (is_array($strings) && count($strings)) {
  595. $this->strings = array_merge($this->strings, $this->override);
  596. $result = true;
  597. }
  598. }
  599. // Record the result of loading the extension's file.
  600. if (! isset($this->paths[$extension])) {
  601. $this->paths[$extension] = array();
  602. }
  603. $this->paths[$extension][$filename] = $result;
  604. return $result;
  605. }
  606. /**
  607. * Parses a language file
  608. *
  609. * @param string $filename The name of the file.
  610. *
  611. * @return array The array of parsed strings.
  612. * @since 11.1
  613. */
  614. protected function parse($filename)
  615. {
  616. $version = phpversion();
  617. // Capture hidden PHP errors from the parsing.
  618. $php_errormsg = null;
  619. $track_errors = ini_get('track_errors');
  620. ini_set('track_errors', true);
  621. if ($version >= '5.3.1') {
  622. $contents = file_get_contents($filename);
  623. $contents = str_replace('_QQ_','"\""',$contents);
  624. $strings = @parse_ini_string($contents);
  625. }
  626. else {
  627. $strings = @parse_ini_file($filename);
  628. if ($version == '5.3.0' && is_array($strings)) {
  629. foreach($strings as $key => $string) {
  630. $strings[$key]=str_replace('_QQ_','"',$string);
  631. }
  632. }
  633. }
  634. // Restore error tracking to what it was before.
  635. ini_set('track_errors',$track_errors);
  636. if (!is_array($strings)) {
  637. $strings = array();
  638. }
  639. if ($this->debug) {
  640. // Initialise variables for manually parsing the file for common errors.
  641. $blacklist = array('YES','NO','NULL','FALSE','ON','OFF','NONE','TRUE');
  642. $regex = '/^(|(\[[^\]]*\])|([A-Z][A-Z0-9_\-]*\s*=(\s*(("[^"]*")|(_QQ_)))+))\s*(;.*)?$/';
  643. $this->debug = false;
  644. $errors = array();
  645. $lineNumber = 0;
  646. // Open the file as a stream.
  647. $stream = new JStream();
  648. $stream->open($filename);
  649. while (!$stream->eof())
  650. {
  651. $line = $stream->gets();
  652. $lineNumber++;
  653. // Check that the key is not in the blacklist and that the line format passes the regex.
  654. $key = strtoupper(trim(substr($line, 0, strpos($line, '='))));
  655. if (!preg_match($regex, $line) || in_array($key, $blacklist)) {
  656. $errors[] = $lineNumber;
  657. }
  658. }
  659. $stream->close();
  660. // Check if we encountered any errors.
  661. if (count($errors)) {
  662. if (basename($filename) != $this->lang.'.ini') {
  663. $this->errorfiles[$filename] = $filename.JText::sprintf('JERROR_PARSING_LANGUAGE_FILE', implode(', ', $errors));
  664. }
  665. else {
  666. $this->errorfiles[$filename] = $filename . '&#160;: error(s) in line(s) ' . implode(', ', $errors);
  667. }
  668. }
  669. else if ($php_errormsg) {
  670. // We didn't find any errors but there's probably a parse notice.
  671. $this->errorfiles['PHP'.$filename] = 'PHP parser errors :'.$php_errormsg;
  672. }
  673. $this->debug = true;
  674. }
  675. return $strings;
  676. }
  677. /**
  678. * Get a matadata language property
  679. *
  680. * @param string $property The name of the property
  681. * @param mixed $default The default value
  682. * @return mixed The value of the property
  683. * @since 11.1
  684. */
  685. public function get($property, $default = null)
  686. {
  687. if (isset ($this->metadata[$property])) {
  688. return $this->metadata[$property];
  689. }
  690. return $default;
  691. }
  692. /**
  693. * Determine who called JLanguage or JText
  694. *
  695. * @return array Caller information
  696. * @since 11.1
  697. */
  698. protected function getCallerInfo()
  699. {
  700. // Try to determine the source if none was provided
  701. if (!function_exists('debug_backtrace')) {
  702. return null;
  703. }
  704. $backtrace = debug_backtrace();
  705. $info = array();
  706. // Search through the backtrace to our caller
  707. $continue = true;
  708. while ($continue && next($backtrace)) {
  709. $step = current($backtrace);
  710. $class = @ $step['class'];
  711. // We're looking for something outside of language.php
  712. if ($class != 'JLanguage' && $class != 'JText') {
  713. $info['function'] = @ $step['function'];
  714. $info['class'] = $class;
  715. $info['step'] = prev($backtrace);
  716. // Determine the file and name of the file
  717. $info['file'] = @ $step['file'];
  718. $info['line'] = @ $step['line'];
  719. $continue = false;
  720. }
  721. }
  722. return $info;
  723. }
  724. /**
  725. * Getter for Name
  726. *
  727. * @return string Official name element of the language
  728. * @since 11.1
  729. */
  730. public function getName() {
  731. return $this->metadata['name'];
  732. }
  733. /**
  734. * Get a list of language files that have been loaded
  735. *
  736. * @param string $extension An option extension name
  737. * @return array
  738. * @since 11.1
  739. */
  740. public function getPaths($extension = null)
  741. {
  742. if (isset($extension)) {
  743. if (isset($this->paths[$extension])) {
  744. return $this->paths[$extension];
  745. }
  746. return null;
  747. } else {
  748. return $this->paths;
  749. }
  750. }
  751. /**
  752. * Get a list of language files that are in error state
  753. *
  754. * @return array
  755. * @since 11.1
  756. */
  757. public function getErrorFiles()
  758. {
  759. return $this->errorfiles;
  760. }
  761. /**
  762. * Get for the language tag (as defined in RFC 3066)
  763. *
  764. * @return string The language tag
  765. * @since 11.1
  766. */
  767. public function getTag() {
  768. return $this->metadata['tag'];
  769. }
  770. /**
  771. * Get the RTL property
  772. *
  773. * @return boolean True is it an RTL language
  774. * @since 11.1
  775. */
  776. public function isRTL()
  777. {
  778. return $this->metadata['rtl'];
  779. }
  780. /**
  781. * Set the Debug property
  782. *
  783. * @return boolean Previous value
  784. * @since 11.1
  785. */
  786. public function setDebug($debug)
  787. {
  788. $previous = $this->debug;
  789. $this->debug = $debug;
  790. return $previous;
  791. }
  792. /**
  793. * Get the Debug property
  794. *
  795. * @return boolean True is in debug mode
  796. * @since 11.1
  797. */
  798. public function getDebug()
  799. {
  800. return $this->debug;
  801. }
  802. /**
  803. * Get the default language code
  804. *
  805. * @return string Language code
  806. * @since 11.1
  807. */
  808. public function getDefault()
  809. {
  810. return $this->default;
  811. }
  812. /**
  813. * Set the default language code
  814. *
  815. * @return string Previous value
  816. * @since 11.1
  817. */
  818. public function setDefault($lang)
  819. {
  820. $previous = $this->default;
  821. $this->default = $lang;
  822. return $previous;
  823. }
  824. /**
  825. * Get the list of orphaned strings if being tracked
  826. *
  827. * @return array Orphaned text
  828. * @since 11.1
  829. */
  830. public function getOrphans()
  831. {
  832. return $this->orphans;
  833. }
  834. /**
  835. * Get the list of used strings
  836. *
  837. * Used strings are those strings requested and found either as a string or a constant
  838. *
  839. * @return array Used strings
  840. * @since 11.1
  841. */
  842. public function getUsed()
  843. {
  844. return $this->used;
  845. }
  846. /**
  847. * Determines is a key exists
  848. *
  849. * @param key $key The key to check
  850. * @return boolean True, if the key exists
  851. * @since 11.1
  852. */
  853. function hasKey($string)
  854. {
  855. $key = strtoupper($string);
  856. return isset ($this->strings[$key]);
  857. }
  858. /**
  859. * Returns a associative array holding the metadata
  860. *
  861. * @param string The name of the language
  862. * @return mixed If $lang exists return key/value pair with the language metadata,
  863. * otherwise return NULL
  864. * @since 11.1
  865. */
  866. public static function getMetadata($lang)
  867. {
  868. $path = self::getLanguagePath(JPATH_BASE, $lang);
  869. $file = "$lang.xml";
  870. $result = null;
  871. if (is_file("$path/$file")) {
  872. $result = self::parseXMLLanguageFile("$path/$file");
  873. }
  874. return $result;
  875. }
  876. /**
  877. * Returns a list of known languages for an area
  878. *
  879. * @param string $basePath The basepath to use
  880. * @return array key/value pair with the language file and real name
  881. * @since 11.1
  882. */
  883. public static function getKnownLanguages($basePath = JPATH_BASE)
  884. {
  885. $dir = self::getLanguagePath($basePath);
  886. $knownLanguages = self::parseLanguageFiles($dir);
  887. return $knownLanguages;
  888. }
  889. /**
  890. * Get the path to a language
  891. *
  892. * @param string $basePath The basepath to use
  893. * @param string $language The language tag
  894. * @return string language related path or null
  895. * @since 11.1
  896. */
  897. public static function getLanguagePath($basePath = JPATH_BASE, $language = null)
  898. {
  899. $dir = "$basePath/language";
  900. if (!empty($language)) {
  901. $dir .= "/$language";
  902. }
  903. return $dir;
  904. }
  905. /**
  906. * Set the language attributes to the given language
  907. *
  908. * Once called, the language still needs to be loaded using JLanguage::load()
  909. *
  910. * @param string $lang Language code
  911. * @return string Previous value
  912. * @since 11.1
  913. */
  914. public function setLanguage($lang)
  915. {
  916. $previous = $this->lang;
  917. $this->lang = $lang;
  918. $this->metadata = $this->getMetadata($this->lang);
  919. return $previous;
  920. }
  921. /**
  922. * Get the language locale based on current language
  923. *
  924. * @return array|false The locale according to the language
  925. * @since 11.1
  926. */
  927. public function getLocale()
  928. {
  929. if (!isset($this->locale))
  930. {
  931. $locale = str_replace(' ', '', isset($this->metadata['locale']) ? $this->metadata['locale'] : '');
  932. if ($locale)
  933. {
  934. $this->locale = explode(',', $locale);
  935. }
  936. else
  937. {
  938. $this->locale = false;
  939. }
  940. }
  941. return $this->locale;
  942. }
  943. /**
  944. * Get the first day of the week for this language
  945. *
  946. * @return int The first day of the week according to the language
  947. * @since 11.1
  948. */
  949. public function getFirstDay()
  950. {
  951. return (int) (isset($this->metadata['firstDay']) ? $this->metadata['firstDay'] : 0);
  952. }
  953. /**
  954. * Searches for language directories within a certain base dir
  955. *
  956. * @param string $dir directory of files
  957. * @return array Array holding the found languages as filename => real name pairs
  958. * @deprecated use parseLanguageFiles instead
  959. * @since 11.1
  960. */
  961. public static function _parseLanguageFiles($dir = null)
  962. {
  963. return self::parseLanguageFiles($dir);
  964. }
  965. /**
  966. * Searches for language directories within a certain base dir
  967. *
  968. * @param string $dir directory of files
  969. * @return array Array holding the found languages as filename => real name pairs
  970. * @since 11.1
  971. */
  972. public static function parseLanguageFiles($dir = null)
  973. {
  974. jimport('joomla.filesystem.folder');
  975. $languages = array ();
  976. $subdirs = JFolder::folders($dir);
  977. foreach ($subdirs as $path) {
  978. $langs = self::parseXMLLanguageFiles("$dir/$path");
  979. $languages = array_merge($languages, $langs);
  980. }
  981. return $languages;
  982. }
  983. /**
  984. * Parses XML files for language information
  985. *
  986. * @param string $dir Directory of files
  987. * @return array Array holding the found languages as filename => metadata array
  988. * @deprecated use parseXMLLanguageFiles instead
  989. * @since 11.1
  990. */
  991. public static function _parseXMLLanguageFiles($dir = null)
  992. {
  993. return self::parseXMLLanguageFiles($dir);
  994. }
  995. /**
  996. * Parses XML files for language information
  997. *
  998. * @param string $dir Directory of files
  999. * @return array Array holding the found languages as filename => metadata array
  1000. * @since 11.1
  1001. */
  1002. public static function parseXMLLanguageFiles($dir = null)
  1003. {
  1004. if ($dir == null) {
  1005. return null;
  1006. }
  1007. $languages = array ();
  1008. jimport('joomla.filesystem.folder');
  1009. $files = JFolder::files($dir, '^([-_A-Za-z]*)\.xml$');
  1010. foreach ($files as $file) {
  1011. if ($content = file_get_contents("$dir/$file")) {
  1012. if ($metadata = self::parseXMLLanguageFile("$dir/$file")) {
  1013. $lang = str_replace('.xml', '', $file);
  1014. $languages[$lang] = $metadata;
  1015. }
  1016. }
  1017. }
  1018. return $languages;
  1019. }
  1020. /**
  1021. * Parse XML file for language information.
  1022. *
  1023. * @param string $path Path to the xml files
  1024. * @return array Array holding the found metadata as a key => value pair
  1025. * @deprecated use parseXMLLanguageFile instead
  1026. * @since 11.1
  1027. */
  1028. public static function _parseXMLLanguageFile($path)
  1029. {
  1030. return self::parseXMLLanguageFile($path);
  1031. }
  1032. /**
  1033. * Parse XML file for language information.
  1034. *
  1035. * @param string $path Path to the xml files
  1036. * @return array Array holding the found metadata as a key => value pair
  1037. * @since 11.1
  1038. */
  1039. public static function parseXMLLanguageFile($path)
  1040. {
  1041. // Try to load the file
  1042. if (!$xml = JFactory::getXML($path)) {
  1043. return null;
  1044. }
  1045. // Check that it's a metadata file
  1046. if ((string)$xml->getName() != 'metafile') {
  1047. return null;
  1048. }
  1049. $metadata = array();
  1050. foreach ($xml->metadata->children() as $child) {
  1051. $metadata[$child->getName()] = (string) $child;
  1052. }
  1053. return $metadata;
  1054. }
  1055. }