PageRenderTime 29ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/Translate/Adapter.php

http://digitalus-site-manager.googlecode.com/
PHP | 544 lines | 274 code | 42 blank | 228 comment | 58 complexity | 3eca08496a6cbe4ae7a8c74c03627827 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  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. $found = false;
  149. $parts = explode('.', $filename);
  150. $parts2 = array();
  151. foreach($parts as $token) {
  152. $parts2 += explode('_', $token);
  153. }
  154. $parts = array_merge($parts, $parts2);
  155. $parts2 = array();
  156. foreach($parts as $token) {
  157. $parts2 += explode('-', $token);
  158. }
  159. $parts = array_merge($parts, $parts2);
  160. $parts = array_unique($parts);
  161. $prev = '';
  162. foreach($parts as $token) {
  163. if (Zend_Locale::isLocale($token)) {
  164. if (strlen($prev) <= strlen($token)) {
  165. $locale = $token;
  166. $prev = $token;
  167. }
  168. }
  169. }
  170. }
  171. }
  172. try {
  173. $this->_addTranslationData($info->getPathname(), $locale, $this->_options);
  174. if ((isset($this->_translate[$locale]) === true) and (count($this->_translate[$locale]) > 0)) {
  175. $this->setLocale($locale);
  176. }
  177. } catch (Zend_Translate_Exception $e) {
  178. // ignore failed sources while scanning
  179. }
  180. }
  181. }
  182. } else {
  183. $this->_addTranslationData($data, $locale, $this->_options);
  184. if ((isset($this->_translate[$locale]) === true) and (count($this->_translate[$locale]) > 0)) {
  185. $this->setLocale($locale);
  186. }
  187. }
  188. if ((isset($translate[$originate]) === true) and (count($this->_translate[$originate]) > 0)) {
  189. $this->setLocale($originate);
  190. }
  191. return $this;
  192. }
  193. /**
  194. * Sets new adapter options
  195. *
  196. * @param array $options Adapter options
  197. * @throws Zend_Translate_Exception
  198. * @return Zend_Translate_Adapter Provides a fluid interface
  199. */
  200. public function setOptions(array $options = array())
  201. {
  202. foreach ($options as $key => $option) {
  203. if ($key == "locale") {
  204. $this->setLocale($option);
  205. } else {
  206. $this->_options[strtolower($key)] = $option;
  207. }
  208. }
  209. return $this;
  210. }
  211. /**
  212. * Returns the adapters name and it's options
  213. *
  214. * @param string|null $optionKey String returns this option
  215. * null returns all options
  216. * @return integer|string|array|null
  217. */
  218. public function getOptions($optionKey = null)
  219. {
  220. if ($optionKey === null) {
  221. return $this->_options;
  222. }
  223. $optionKey = strtolower($optionKey);
  224. if (isset($this->_options[$optionKey]) === true) {
  225. return $this->_options[$optionKey];
  226. }
  227. return null;
  228. }
  229. /**
  230. * Gets locale
  231. *
  232. * @return Zend_Locale|string|null
  233. */
  234. public function getLocale()
  235. {
  236. return $this->_options['locale'];
  237. }
  238. /**
  239. * Sets locale
  240. *
  241. * @param string|Zend_Locale $locale Locale to set
  242. * @throws Zend_Translate_Exception
  243. * @return Zend_Translate_Adapter Provides a fluid interface
  244. */
  245. public function setLocale($locale)
  246. {
  247. if ($locale instanceof Zend_Locale) {
  248. $locale = $locale->toString();
  249. } else if (!$locale = Zend_Locale::isLocale($locale)) {
  250. /**
  251. * @see Zend_Translate_Exception
  252. */
  253. require_once 'Zend/Translate/Exception.php';
  254. throw new Zend_Translate_Exception("The given Language ({$locale}) does not exist");
  255. }
  256. if (empty($this->_translate[$locale]) === true) {
  257. $temp = explode('_', $locale);
  258. if (isset($this->_translate[$temp[0]]) === false) {
  259. /**
  260. * @see Zend_Translate_Exception
  261. */
  262. require_once 'Zend/Translate/Exception.php';
  263. throw new Zend_Translate_Exception("Language ({$locale}) has to be added before it can be used.");
  264. }
  265. $locale = $temp[0];
  266. }
  267. $this->_options['locale'] = $locale;
  268. if ($locale === "auto") {
  269. $this->_automatic = true;
  270. } else {
  271. $this->_automatic = false;
  272. }
  273. return $this;
  274. }
  275. /**
  276. * Returns the available languages from this adapter
  277. *
  278. * @return array
  279. */
  280. public function getList()
  281. {
  282. $list = array_keys($this->_translate);
  283. $result = null;
  284. foreach($list as $key => $value) {
  285. if (!empty($this->_translate[$value])) {
  286. $result[$value] = $value;
  287. }
  288. }
  289. return $result;
  290. }
  291. /**
  292. * Returns all available message ids from this adapter
  293. * If no locale is given, the actual language will be used
  294. *
  295. * @param string|Zend_Locale $locale (optional) Language to return the message ids from
  296. * @return array
  297. */
  298. public function getMessageIds($locale = null)
  299. {
  300. if (empty($locale) or !$this->isAvailable($locale)) {
  301. $locale = $this->_options['locale'];
  302. }
  303. return array_keys($this->_translate[(string) $locale]);
  304. }
  305. /**
  306. * Returns all available translations from this adapter
  307. * If no locale is given, the actual language will be used
  308. * If 'all' is given the complete translation dictionary will be returned
  309. *
  310. * @param string|Zend_Locale $locale (optional) Language to return the messages from
  311. * @return array
  312. */
  313. public function getMessages($locale = null)
  314. {
  315. if ($locale === 'all') {
  316. return $this->_translate;
  317. }
  318. if ((empty($locale) === true) or ($this->isAvailable($locale) === false)) {
  319. $locale = $this->_options['locale'];
  320. }
  321. return $this->_translate[(string) $locale];
  322. }
  323. /**
  324. * Is the wished language available ?
  325. *
  326. * @see Zend_Locale
  327. * @param string|Zend_Locale $locale Language to search for, identical with locale identifier,
  328. * @see Zend_Locale for more information
  329. * @return boolean
  330. */
  331. public function isAvailable($locale)
  332. {
  333. $return = isset($this->_translate[(string) $locale]);
  334. return $return;
  335. }
  336. /**
  337. * Load translation data
  338. *
  339. * @param mixed $data
  340. * @param string|Zend_Locale $locale
  341. * @param array $options (optional)
  342. * @return void
  343. */
  344. abstract protected function _loadTranslationData($data, $locale, array $options = array());
  345. /**
  346. * Internal function for adding translation data
  347. *
  348. * It may be a new language or additional data for existing language
  349. * If $clear parameter is true, then translation data for specified
  350. * language is replaced and added otherwise
  351. *
  352. * @see Zend_Locale
  353. * @param array|string $data Translation data
  354. * @param string|Zend_Locale $locale Locale/Language to add data for, identical with locale identifier,
  355. * @see Zend_Locale for more information
  356. * @param array $options (optional) Option for this Adapter
  357. * @throws Zend_Translate_Exception
  358. * @return Zend_Translate_Adapter Provides a fluid interface
  359. */
  360. private function _addTranslationData($data, $locale, array $options = array())
  361. {
  362. if (!$locale = Zend_Locale::isLocale($locale)) {
  363. /**
  364. * @see Zend_Translate_Exception
  365. */
  366. require_once 'Zend/Translate/Exception.php';
  367. throw new Zend_Translate_Exception("The given Language ({$locale}) does not exist");
  368. }
  369. if (isset($this->_translate[$locale]) === false) {
  370. $this->_translate[$locale] = array();
  371. }
  372. $this->_loadTranslationData($data, $locale, $options);
  373. if ($this->_automatic === true) {
  374. $find = new Zend_Locale($locale);
  375. $browser = $find->getEnvironment() + $find->getBrowser();
  376. arsort($browser);
  377. foreach($browser as $language => $quality) {
  378. if (isset($this->_translate[$language]) === true) {
  379. $this->_options['locale'] = $language;
  380. break;
  381. }
  382. }
  383. }
  384. if (isset(self::$_cache)) {
  385. $id = 'Zend_Translate_' . $this->toString();
  386. $temp = $this->_translate;
  387. $temp['_options_'] = $this->_options;
  388. self::$_cache->save( serialize($temp), $id);
  389. }
  390. return $this;
  391. }
  392. /**
  393. * Translates the given string
  394. * returns the translation
  395. *
  396. * @see Zend_Locale
  397. * @param string $messageId Translation string
  398. * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with
  399. * locale identifier, @see Zend_Locale for more information
  400. * @return string
  401. */
  402. public function translate($messageId, $locale = null)
  403. {
  404. if ($locale === null) {
  405. $locale = $this->_options['locale'];
  406. }
  407. if (!$locale = Zend_Locale::isLocale($locale)) {
  408. // language does not exist, return original string
  409. return $messageId;
  410. }
  411. if (isset($this->_translate[$locale][$messageId]) === true) {
  412. // return original translation
  413. return $this->_translate[$locale][$messageId];
  414. } else if (strlen($locale) != 2) {
  415. // faster than creating a new locale and separate the leading part
  416. $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
  417. if (isset($this->_translate[$locale][$messageId]) === true) {
  418. // return regionless translation (en_US -> en)
  419. return $this->_translate[$locale][$messageId];
  420. }
  421. }
  422. // no translation found, return original
  423. return $messageId;
  424. }
  425. /**
  426. * Translates the given string
  427. * returns the translation
  428. *
  429. * @param string $messageId Translation string
  430. * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with locale
  431. * identifier, @see Zend_Locale for more information
  432. * @return string
  433. */
  434. public function _($messageId, $locale = null)
  435. {
  436. return $this->translate($messageId, $locale);
  437. }
  438. /**
  439. * Checks if a string is translated within the source or not
  440. * returns boolean
  441. *
  442. * @param string $messageId Translation string
  443. * @param boolean $original (optional) Allow translation only for original language
  444. * when true, a translation for 'en_US' would give false when it can
  445. * be translated with 'en' only
  446. * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with locale identifier,
  447. * see Zend_Locale for more information
  448. * @return boolean
  449. */
  450. public function isTranslated($messageId, $original = false, $locale = null)
  451. {
  452. if (($original !== false) and ($original !== true)) {
  453. $locale = $original;
  454. $original = false;
  455. }
  456. if ($locale === null) {
  457. $locale = $this->_options['locale'];
  458. } else {
  459. if (!$locale = Zend_Locale::isLocale($locale)) {
  460. // language does not exist, return original string
  461. return false;
  462. }
  463. }
  464. if (isset($this->_translate[$locale][$messageId]) === true) {
  465. // return original translation
  466. return true;
  467. } else if ((strlen($locale) != 2) and ($original === false)) {
  468. // faster than creating a new locale and separate the leading part
  469. $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
  470. if (isset($this->_translate[$locale][$messageId]) === true) {
  471. // return regionless translation (en_US -> en)
  472. return true;
  473. }
  474. }
  475. // No translation found, return original
  476. return false;
  477. }
  478. /**
  479. * Sets a cache for all Zend_Translate_Adapters
  480. *
  481. * @param Zend_Cache_Core $cache Cache to store to
  482. */
  483. public static function setCache(Zend_Cache_Core $cache)
  484. {
  485. self::$_cache = $cache;
  486. }
  487. /**
  488. * Returns the set cache
  489. *
  490. * @return Zend_Cache_Core The set cache
  491. */
  492. public static function getCache()
  493. {
  494. return self::$_cache;
  495. }
  496. /**
  497. * Returns the adapter name
  498. *
  499. * @return string
  500. */
  501. abstract public function toString();
  502. }