PageRenderTime 735ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/DevApp/library/Zend/Translate/Adapter.php

http://firephp.googlecode.com/
PHP | 550 lines | 277 code | 44 blank | 229 comment | 60 complexity | 173fdfb0a1d060124acd6072906af8c6 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, MIT, Apache-2.0
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Translate
  17. * @subpackage Zend_Translate_Adapter
  18. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Date.php 2498 2006-12-23 22:13:38Z thomas $
  21. */
  22. /**
  23. * @see Zend_Locale
  24. */
  25. require_once 'Zend/Locale.php';
  26. /**
  27. * Basic adapter class for each translation source adapter
  28. *
  29. * @category Zend
  30. * @package Zend_Translate
  31. * @subpackage Zend_Translate_Adapter
  32. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. abstract class Zend_Translate_Adapter {
  36. /**
  37. * Shows if locale detection is in automatic level
  38. * @var boolean
  39. */
  40. private $_automatic = true;
  41. /**
  42. * Internal cache for all adapters
  43. * @var Zend_Cache_Core
  44. */
  45. protected static $_cache = null;
  46. /**
  47. * Scans for the locale within the name of the directory
  48. * @constant integer
  49. */
  50. const LOCALE_DIRECTORY = 1;
  51. /**
  52. * Scans for the locale within the name of the file
  53. * @constant integer
  54. */
  55. const LOCALE_FILENAME = 2;
  56. /**
  57. * Array with all options, each adapter can have own additional options
  58. * 'clear' => clears already loaded data when adding new files
  59. * 'scan' => searches for translation files using the LOCALE constants
  60. * 'locale' => the actual set locale to use
  61. * @var array
  62. */
  63. protected $_options = array(
  64. 'clear' => false,
  65. 'scan' => null,
  66. 'locale' => 'auto'
  67. );
  68. /**
  69. * Translation table
  70. * @var array
  71. */
  72. protected $_translate = array();
  73. /**
  74. * Generates the adapter
  75. *
  76. * @param string|array $data Translation data or filename for this adapter
  77. * @param string|Zend_Locale $locale (optional) Locale/Language to set, identical with Locale
  78. * identifiers see Zend_Locale for more information
  79. * @param array $options (optional) Options for the adaptor
  80. * @throws Zend_Translate_Exception
  81. * @return void
  82. */
  83. public function __construct($data, $locale = null, array $options = array())
  84. {
  85. if (isset(self::$_cache)) {
  86. $id = 'Zend_Translate_' . $this->toString();
  87. if ($result = self::$_cache->load($id)) {
  88. $this->_translate = unserialize($result);
  89. $this->_options = $this->_translate['_options_'];
  90. unset($this->_translate['_options_']);
  91. return;
  92. }
  93. }
  94. if (($locale === "auto") or ($locale === null)) {
  95. $this->_automatic = true;
  96. } else {
  97. $this->_automatic = false;
  98. }
  99. $this->addTranslation($data, $locale, $options);
  100. }
  101. /**
  102. * Add translation data
  103. *
  104. * It may be a new language or additional data for existing language
  105. * If $clear parameter is true, then translation data for specified
  106. * language is replaced and added otherwise
  107. *
  108. * @param array|string $data Translation data
  109. * @param string|Zend_Locale $locale (optional) Locale/Language to add data for, identical
  110. * with locale identifier, see Zend_Locale for more information
  111. * @param array $options (optional) Option for this Adapter
  112. * @throws Zend_Translate_Exception
  113. * @return Zend_Translate_Adapter Provides a fluid interface
  114. */
  115. public function addTranslation($data, $locale = null, array $options = array())
  116. {
  117. if ($locale === null) {
  118. $locale = new Zend_Locale();
  119. }
  120. if ($locale instanceof Zend_Locale) {
  121. $locale = $locale->toString();
  122. }
  123. $originate = $locale;
  124. $this->setOptions($options);
  125. if (is_string($data) and is_dir($data)) {
  126. $prev = '';
  127. foreach (new RecursiveIteratorIterator(
  128. new RecursiveDirectoryIterator($data, RecursiveDirectoryIterator::KEY_AS_PATHNAME),
  129. RecursiveIteratorIterator::SELF_FIRST) as $file => $info) {
  130. $file = $info->getFilename();
  131. if ($info->isDir()) {
  132. // pathname as locale
  133. if (($this->_options['scan'] === self::LOCALE_DIRECTORY) and (Zend_Locale::isLocale($file))) {
  134. if (strlen($prev) <= strlen($file)) {
  135. $locale = $file;
  136. $prev = $locale;
  137. }
  138. }
  139. } else if ($info->isFile()) {
  140. // filename as locale
  141. if ($this->_options['scan'] === self::LOCALE_FILENAME) {
  142. $filename = explode('.', $file);
  143. array_pop($filename);
  144. $filename = implode('.', $filename);
  145. if (Zend_Locale::isLocale((string) $filename)) {
  146. $locale = (string) $filename;
  147. } else {
  148. $parts = explode('.', $filename);
  149. $parts2 = array();
  150. foreach($parts as $token) {
  151. $parts2 += explode('_', $token);
  152. }
  153. $parts = array_merge($parts, $parts2);
  154. $parts2 = array();
  155. foreach($parts as $token) {
  156. $parts2 += explode('-', $token);
  157. }
  158. $parts = array_merge($parts, $parts2);
  159. $parts = array_unique($parts);
  160. $prev = '';
  161. foreach($parts as $token) {
  162. if (Zend_Locale::isLocale($token)) {
  163. if (strlen($prev) <= strlen($token)) {
  164. $locale = $token;
  165. $prev = $token;
  166. }
  167. }
  168. }
  169. }
  170. }
  171. try {
  172. $this->_addTranslationData($info->getPathname(), $locale, $this->_options);
  173. if ((isset($this->_translate[$locale]) === true) and (count($this->_translate[$locale]) > 0)) {
  174. $this->setLocale($locale);
  175. }
  176. } catch (Zend_Translate_Exception $e) {
  177. // ignore failed sources while scanning
  178. }
  179. }
  180. }
  181. } else {
  182. $this->_addTranslationData($data, $locale, $this->_options);
  183. if ((isset($this->_translate[$locale]) === true) and (count($this->_translate[$locale]) > 0)) {
  184. $this->setLocale($locale);
  185. }
  186. }
  187. if ((isset($this->_translate[$originate]) === true) and (count($this->_translate[$originate]) > 0)) {
  188. $this->setLocale($originate);
  189. }
  190. return $this;
  191. }
  192. /**
  193. * Sets new adapter options
  194. *
  195. * @param array $options Adapter options
  196. * @throws Zend_Translate_Exception
  197. * @return Zend_Translate_Adapter Provides a fluid interface
  198. */
  199. public function setOptions(array $options = array())
  200. {
  201. foreach ($options as $key => $option) {
  202. if ($key == "locale") {
  203. $this->setLocale($option);
  204. } else {
  205. $this->_options[strtolower($key)] = $option;
  206. }
  207. }
  208. return $this;
  209. }
  210. /**
  211. * Returns the adapters name and it's options
  212. *
  213. * @param string|null $optionKey String returns this option
  214. * null returns all options
  215. * @return integer|string|array|null
  216. */
  217. public function getOptions($optionKey = null)
  218. {
  219. if ($optionKey === null) {
  220. return $this->_options;
  221. }
  222. $optionKey = strtolower($optionKey);
  223. if (isset($this->_options[$optionKey]) === true) {
  224. return $this->_options[$optionKey];
  225. }
  226. return null;
  227. }
  228. /**
  229. * Gets locale
  230. *
  231. * @return Zend_Locale|string|null
  232. */
  233. public function getLocale()
  234. {
  235. return $this->_options['locale'];
  236. }
  237. /**
  238. * Sets locale
  239. *
  240. * @param string|Zend_Locale $locale Locale to set
  241. * @throws Zend_Translate_Exception
  242. * @return Zend_Translate_Adapter Provides a fluid interface
  243. */
  244. public function setLocale($locale)
  245. {
  246. if ($locale instanceof Zend_Locale) {
  247. $locale = $locale->toString();
  248. } else if (!$locale = Zend_Locale::isLocale($locale)) {
  249. /**
  250. * @see Zend_Translate_Exception
  251. */
  252. require_once 'Zend/Translate/Exception.php';
  253. throw new Zend_Translate_Exception("The given Language ({$locale}) does not exist");
  254. }
  255. $locale = (string) $locale;
  256. if (!isset($this->_translate[$locale])) {
  257. $temp = explode('_', $locale);
  258. if (!isset($this->_translate[$temp[0]]) and !isset($this->_translate[$locale])) {
  259. /**
  260. * @see Zend_Translate_Exception
  261. */
  262. require_once 'Zend/Translate/Exception.php';
  263. throw new Zend_Translate_Exception("The language '{$locale}' has to be added before it can be used.");
  264. }
  265. $locale = $temp[0];
  266. }
  267. if (empty($this->_translate[$locale])) {
  268. // throwing a notice due to possible problems on locale setting
  269. trigger_error("No translation for the language '{$locale}' available.", E_USER_NOTICE);
  270. }
  271. $this->_options['locale'] = $locale;
  272. if ($locale === "auto") {
  273. $this->_automatic = true;
  274. } else {
  275. $this->_automatic = false;
  276. }
  277. return $this;
  278. }
  279. /**
  280. * Returns the available languages from this adapter
  281. *
  282. * @return array
  283. */
  284. public function getList()
  285. {
  286. $list = array_keys($this->_translate);
  287. $result = null;
  288. foreach($list as $value) {
  289. if (!empty($this->_translate[$value])) {
  290. $result[$value] = $value;
  291. }
  292. }
  293. return $result;
  294. }
  295. /**
  296. * Returns all available message ids from this adapter
  297. * If no locale is given, the actual language will be used
  298. *
  299. * @param string|Zend_Locale $locale (optional) Language to return the message ids from
  300. * @return array
  301. */
  302. public function getMessageIds($locale = null)
  303. {
  304. if (empty($locale) or !$this->isAvailable($locale)) {
  305. $locale = $this->_options['locale'];
  306. }
  307. return array_keys($this->_translate[(string) $locale]);
  308. }
  309. /**
  310. * Returns all available translations from this adapter
  311. * If no locale is given, the actual language will be used
  312. * If 'all' is given the complete translation dictionary will be returned
  313. *
  314. * @param string|Zend_Locale $locale (optional) Language to return the messages from
  315. * @return array
  316. */
  317. public function getMessages($locale = null)
  318. {
  319. if ($locale === 'all') {
  320. return $this->_translate;
  321. }
  322. if ((empty($locale) === true) or ($this->isAvailable($locale) === false)) {
  323. $locale = $this->_options['locale'];
  324. }
  325. return $this->_translate[(string) $locale];
  326. }
  327. /**
  328. * Is the wished language available ?
  329. *
  330. * @see Zend_Locale
  331. * @param string|Zend_Locale $locale Language to search for, identical with locale identifier,
  332. * @see Zend_Locale for more information
  333. * @return boolean
  334. */
  335. public function isAvailable($locale)
  336. {
  337. $return = isset($this->_translate[(string) $locale]);
  338. return $return;
  339. }
  340. /**
  341. * Load translation data
  342. *
  343. * @param mixed $data
  344. * @param string|Zend_Locale $locale
  345. * @param array $options (optional)
  346. * @return void
  347. */
  348. abstract protected function _loadTranslationData($data, $locale, array $options = array());
  349. /**
  350. * Internal function for adding translation data
  351. *
  352. * It may be a new language or additional data for existing language
  353. * If $clear parameter is true, then translation data for specified
  354. * language is replaced and added otherwise
  355. *
  356. * @see Zend_Locale
  357. * @param array|string $data Translation data
  358. * @param string|Zend_Locale $locale Locale/Language to add data for, identical with locale identifier,
  359. * @see Zend_Locale for more information
  360. * @param array $options (optional) Option for this Adapter
  361. * @throws Zend_Translate_Exception
  362. * @return Zend_Translate_Adapter Provides a fluid interface
  363. */
  364. private function _addTranslationData($data, $locale, array $options = array())
  365. {
  366. if (!$locale = Zend_Locale::isLocale($locale)) {
  367. /**
  368. * @see Zend_Translate_Exception
  369. */
  370. require_once 'Zend/Translate/Exception.php';
  371. throw new Zend_Translate_Exception("The given Language ({$locale}) does not exist");
  372. }
  373. if (isset($this->_translate[$locale]) === false) {
  374. $this->_translate[$locale] = array();
  375. }
  376. $this->_loadTranslationData($data, $locale, $options);
  377. if ($this->_automatic === true) {
  378. $find = new Zend_Locale($locale);
  379. $browser = $find->getEnvironment() + $find->getBrowser();
  380. arsort($browser);
  381. foreach($browser as $language => $quality) {
  382. if (isset($this->_translate[$language]) === true) {
  383. $this->_options['locale'] = $language;
  384. break;
  385. }
  386. }
  387. }
  388. if (isset(self::$_cache)) {
  389. $id = 'Zend_Translate_' . $this->toString();
  390. $temp = $this->_translate;
  391. $temp['_options_'] = $this->_options;
  392. self::$_cache->save( serialize($temp), $id);
  393. }
  394. return $this;
  395. }
  396. /**
  397. * Translates the given string
  398. * returns the translation
  399. *
  400. * @see Zend_Locale
  401. * @param string $messageId Translation string
  402. * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with
  403. * locale identifier, @see Zend_Locale for more information
  404. * @return string
  405. */
  406. public function translate($messageId, $locale = null)
  407. {
  408. if ($locale === null) {
  409. $locale = $this->_options['locale'];
  410. }
  411. if (!$locale = Zend_Locale::isLocale($locale)) {
  412. // language does not exist, return original string
  413. return $messageId;
  414. }
  415. if (isset($this->_translate[$locale][$messageId]) === true) {
  416. // return original translation
  417. return $this->_translate[$locale][$messageId];
  418. } else if (strlen($locale) != 2) {
  419. // faster than creating a new locale and separate the leading part
  420. $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
  421. if (isset($this->_translate[$locale][$messageId]) === true) {
  422. // return regionless translation (en_US -> en)
  423. return $this->_translate[$locale][$messageId];
  424. }
  425. }
  426. // no translation found, return original
  427. return $messageId;
  428. }
  429. /**
  430. * Translates the given string
  431. * returns the translation
  432. *
  433. * @param string $messageId Translation string
  434. * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with locale
  435. * identifier, @see Zend_Locale for more information
  436. * @return string
  437. */
  438. public function _($messageId, $locale = null)
  439. {
  440. return $this->translate($messageId, $locale);
  441. }
  442. /**
  443. * Checks if a string is translated within the source or not
  444. * returns boolean
  445. *
  446. * @param string $messageId Translation string
  447. * @param boolean $original (optional) Allow translation only for original language
  448. * when true, a translation for 'en_US' would give false when it can
  449. * be translated with 'en' only
  450. * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with locale identifier,
  451. * see Zend_Locale for more information
  452. * @return boolean
  453. */
  454. public function isTranslated($messageId, $original = false, $locale = null)
  455. {
  456. if (($original !== false) and ($original !== true)) {
  457. $locale = $original;
  458. $original = false;
  459. }
  460. if ($locale === null) {
  461. $locale = $this->_options['locale'];
  462. } else {
  463. if (!$locale = Zend_Locale::isLocale($locale)) {
  464. // language does not exist, return original string
  465. return false;
  466. }
  467. }
  468. if (isset($this->_translate[$locale][$messageId]) === true) {
  469. // return original translation
  470. return true;
  471. } else if ((strlen($locale) != 2) and ($original === false)) {
  472. // faster than creating a new locale and separate the leading part
  473. $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
  474. if (isset($this->_translate[$locale][$messageId]) === true) {
  475. // return regionless translation (en_US -> en)
  476. return true;
  477. }
  478. }
  479. // No translation found, return original
  480. return false;
  481. }
  482. /**
  483. * Sets a cache for all Zend_Translate_Adapters
  484. *
  485. * @param Zend_Cache_Core $cache Cache to store to
  486. */
  487. public static function setCache(Zend_Cache_Core $cache)
  488. {
  489. self::$_cache = $cache;
  490. }
  491. /**
  492. * Returns the set cache
  493. *
  494. * @return Zend_Cache_Core The set cache
  495. */
  496. public static function getCache()
  497. {
  498. return self::$_cache;
  499. }
  500. /**
  501. * Returns the adapter name
  502. *
  503. * @return string
  504. */
  505. abstract public function toString();
  506. }