Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Adapter.php
Go to the documentation of this file.
1 <?php
26 #require_once 'Zend/Locale.php';
27 
31 #require_once 'Zend/Translate/Plural.php';
32 
42 abstract class Zend_Translate_Adapter {
47  private $_automatic = true;
48 
53  private $_routed = array();
54 
59  protected static $_cache = null;
60 
66  private static $_cacheTags = false;
67 
72  const LOCALE_DIRECTORY = 'directory';
73 
78  const LOCALE_FILENAME = 'filename';
79 
97  protected $_options = array(
98  'clear' => false,
99  'content' => null,
100  'disableNotices' => false,
101  'ignore' => '.',
102  'locale' => 'auto',
103  'log' => null,
104  'logMessage' => "Untranslated message within '%locale%': %message%",
105  'logPriority' => 5,
106  'logUntranslated' => false,
107  'reload' => false,
108  'route' => null,
109  'scan' => null,
110  'tag' => 'Zend_Translate'
111  );
112 
117  protected $_translate = array();
118 
128  public function __construct($options = array())
129  {
130  if ($options instanceof Zend_Config) {
131  $options = $options->toArray();
132  } else if (func_num_args() > 1) {
133  $args = func_get_args();
134  $options = array();
135  $options['content'] = array_shift($args);
136 
137  if (!empty($args)) {
138  $options['locale'] = array_shift($args);
139  }
140 
141  if (!empty($args)) {
142  $opt = array_shift($args);
143  $options = array_merge($opt, $options);
144  }
145  } else if (!is_array($options)) {
146  $options = array('content' => $options);
147  }
148 
149  if (array_key_exists('cache', $options)) {
150  self::setCache($options['cache']);
151  unset($options['cache']);
152  }
153 
154  if (isset(self::$_cache)) {
155  $id = 'Zend_Translate_' . $this->toString() . '_Options';
156  $result = self::$_cache->load($id);
157  if ($result) {
158  $this->_options = $result;
159  }
160  }
161 
162  if (empty($options['locale']) || ($options['locale'] === "auto")) {
163  $this->_automatic = true;
164  } else {
165  $this->_automatic = false;
166  }
167 
168  $locale = null;
169  if (!empty($options['locale'])) {
170  $locale = $options['locale'];
171  unset($options['locale']);
172  }
173 
174  $this->setOptions($options);
175  $options['locale'] = $locale;
176 
177  if (!empty($options['content'])) {
178  $this->addTranslation($options);
179  }
180 
181  if ($this->getLocale() !== (string) $options['locale']) {
182  $this->setLocale($options['locale']);
183  }
184  }
185 
197  public function addTranslation($options = array())
198  {
199  if ($options instanceof Zend_Config) {
200  $options = $options->toArray();
201  } else if (func_num_args() > 1) {
202  $args = func_get_args();
203  $options = array();
204  $options['content'] = array_shift($args);
205 
206  if (!empty($args)) {
207  $options['locale'] = array_shift($args);
208  }
209 
210  if (!empty($args)) {
211  $opt = array_shift($args);
212  $options = array_merge($opt, $options);
213  }
214  } else if (!is_array($options)) {
215  $options = array('content' => $options);
216  }
217 
218  if (!isset($options['content']) || empty($options['content'])) {
219  #require_once 'Zend/Translate/Exception.php';
220  throw new Zend_Translate_Exception("Required option 'content' is missing");
221  }
222 
223  $originate = null;
224  if (!empty($options['locale'])) {
225  $originate = (string) $options['locale'];
226  }
227 
228  if ((array_key_exists('log', $options)) && !($options['log'] instanceof Zend_Log)) {
229  #require_once 'Zend/Translate/Exception.php';
230  throw new Zend_Translate_Exception('Instance of Zend_Log expected for option log');
231  }
232 
233  try {
234  if (!($options['content'] instanceof Zend_Translate) && !($options['content'] instanceof Zend_Translate_Adapter)) {
235  if (empty($options['locale'])) {
236  $options['locale'] = null;
237  }
238 
239  $options['locale'] = Zend_Locale::findLocale($options['locale']);
240  }
241  } catch (Zend_Locale_Exception $e) {
242  #require_once 'Zend/Translate/Exception.php';
243  throw new Zend_Translate_Exception("The given Language '{$options['locale']}' does not exist", 0, $e);
244  }
245 
247  if (is_string($options['content']) and is_dir($options['content'])) {
248  $options['content'] = realpath($options['content']);
249  $prev = '';
250  $iterator = new RecursiveIteratorIterator(
251  new RecursiveRegexIterator(
252  new RecursiveDirectoryIterator($options['content'], RecursiveDirectoryIterator::KEY_AS_PATHNAME),
253  '/^(?!.*(\.svn|\.cvs)).*$/', RecursiveRegexIterator::MATCH
254  ),
255  RecursiveIteratorIterator::SELF_FIRST
256  );
257 
258  foreach ($iterator as $directory => $info) {
259  $file = $info->getFilename();
260  if (is_array($options['ignore'])) {
261  foreach ($options['ignore'] as $key => $ignore) {
262  if (strpos($key, 'regex') !== false) {
263  if (preg_match($ignore, $directory)) {
264  // ignore files matching the given regex from option 'ignore' and all files below
265  continue 2;
266  }
267  } else if (strpos($directory, DIRECTORY_SEPARATOR . $ignore) !== false) {
268  // ignore files matching first characters from option 'ignore' and all files below
269  continue 2;
270  }
271  }
272  } else {
273  if (strpos($directory, DIRECTORY_SEPARATOR . $options['ignore']) !== false) {
274  // ignore files matching first characters from option 'ignore' and all files below
275  continue;
276  }
277  }
278 
279  if ($info->isDir()) {
280  // pathname as locale
281  if (($options['scan'] === self::LOCALE_DIRECTORY) and (Zend_Locale::isLocale($file, true, false))) {
282  $options['locale'] = $file;
283  $prev = (string) $options['locale'];
284  }
285  } else if ($info->isFile()) {
286  // filename as locale
287  if ($options['scan'] === self::LOCALE_FILENAME) {
288  $filename = explode('.', $file);
289  array_pop($filename);
290  $filename = implode('.', $filename);
291  if (Zend_Locale::isLocale((string) $filename, true, false)) {
292  $options['locale'] = (string) $filename;
293  } else {
294  $parts = explode('.', $file);
295  $parts2 = array();
296  foreach($parts as $token) {
297  $parts2 += explode('_', $token);
298  }
299  $parts = array_merge($parts, $parts2);
300  $parts2 = array();
301  foreach($parts as $token) {
302  $parts2 += explode('-', $token);
303  }
304  $parts = array_merge($parts, $parts2);
305  $parts = array_unique($parts);
306  $prev = '';
307  foreach($parts as $token) {
308  if (Zend_Locale::isLocale($token, true, false)) {
309  if (strlen($prev) <= strlen($token)) {
310  $options['locale'] = $token;
311  $prev = $token;
312  }
313  }
314  }
315  }
316  }
317 
318  try {
319  $options['content'] = $info->getPathname();
320  $this->_addTranslationData($options);
321  } catch (Zend_Translate_Exception $e) {
322  // ignore failed sources while scanning
323  }
324  }
325  }
326 
327  unset($iterator);
328  } else {
329  $this->_addTranslationData($options);
330  }
331 
332  if ((isset($this->_translate[$originate]) === true) and (count($this->_translate[$originate]) > 0)) {
333  $this->setLocale($originate);
334  }
335 
336  return $this;
337  }
338 
346  public function setOptions(array $options = array())
347  {
348  $change = false;
349  $locale = null;
350  foreach ($options as $key => $option) {
351  if ($key == 'locale') {
352  $locale = $option;
353  } else if ((isset($this->_options[$key]) and ($this->_options[$key] != $option)) or
354  !isset($this->_options[$key])) {
355  if (($key == 'log') && !($option instanceof Zend_Log)) {
356  #require_once 'Zend/Translate/Exception.php';
357  throw new Zend_Translate_Exception('Instance of Zend_Log expected for option log');
358  }
359 
360  if ($key == 'cache') {
362  continue;
363  }
364 
365  $this->_options[$key] = $option;
366  $change = true;
367  }
368  }
369 
370  if ($locale !== null) {
371  $this->setLocale($locale);
372  }
373 
374  if (isset(self::$_cache) and ($change == true)) {
375  $id = 'Zend_Translate_' . $this->toString() . '_Options';
376  if (self::$_cacheTags) {
377  self::$_cache->save($this->_options, $id, array($this->_options['tag']));
378  } else {
379  self::$_cache->save($this->_options, $id);
380  }
381  }
382 
383  return $this;
384  }
385 
393  public function getOptions($optionKey = null)
394  {
395  if ($optionKey === null) {
396  return $this->_options;
397  }
398 
399  if (isset($this->_options[$optionKey]) === true) {
400  return $this->_options[$optionKey];
401  }
402 
403  return null;
404  }
405 
411  public function getLocale()
412  {
413  return $this->_options['locale'];
414  }
415 
423  public function setLocale($locale)
424  {
425  if (($locale === "auto") or ($locale === null)) {
426  $this->_automatic = true;
427  } else {
428  $this->_automatic = false;
429  }
430 
431  try {
432  $locale = Zend_Locale::findLocale($locale);
433  } catch (Zend_Locale_Exception $e) {
434  #require_once 'Zend/Translate/Exception.php';
435  throw new Zend_Translate_Exception("The given Language ({$locale}) does not exist", 0, $e);
436  }
437 
438  if (!isset($this->_translate[$locale])) {
439  $temp = explode('_', $locale);
440  if (!isset($this->_translate[$temp[0]]) and !isset($this->_translate[$locale])) {
441  if (!$this->_options['disableNotices']) {
442  if ($this->_options['log']) {
443  $this->_options['log']->log("The language '{$locale}' has to be added before it can be used.", $this->_options['logPriority']);
444  } else {
445  trigger_error("The language '{$locale}' has to be added before it can be used.", E_USER_NOTICE);
446  }
447  }
448  }
449 
450  $locale = $temp[0];
451  }
452 
453  if (empty($this->_translate[$locale])) {
454  if (!$this->_options['disableNotices']) {
455  if ($this->_options['log']) {
456  $this->_options['log']->log("No translation for the language '{$locale}' available.", $this->_options['logPriority']);
457  } else {
458  trigger_error("No translation for the language '{$locale}' available.", E_USER_NOTICE);
459  }
460  }
461  }
462 
463  if ($this->_options['locale'] != $locale) {
464  $this->_options['locale'] = $locale;
465 
466  if (isset(self::$_cache)) {
467  $id = 'Zend_Translate_' . $this->toString() . '_Options';
468  if (self::$_cacheTags) {
469  self::$_cache->save($this->_options, $id, array($this->_options['tag']));
470  } else {
471  self::$_cache->save($this->_options, $id);
472  }
473  }
474  }
475 
476  return $this;
477  }
478 
484  public function getList()
485  {
486  $list = array_keys($this->_translate);
487  $result = null;
488  foreach($list as $value) {
489  if (!empty($this->_translate[$value])) {
490  $result[$value] = $value;
491  }
492  }
493  return $result;
494  }
495 
504  public function getMessageId($message, $locale = null)
505  {
506  if (empty($locale) or !$this->isAvailable($locale)) {
507  $locale = $this->_options['locale'];
508  }
509 
510  return array_search($message, $this->_translate[(string) $locale]);
511  }
512 
520  public function getMessageIds($locale = null)
521  {
522  if (empty($locale) or !$this->isAvailable($locale)) {
523  $locale = $this->_options['locale'];
524  }
525 
526  return array_keys($this->_translate[(string) $locale]);
527  }
528 
537  public function getMessages($locale = null)
538  {
539  if ($locale === 'all') {
540  return $this->_translate;
541  }
542 
543  if ((empty($locale) === true) or ($this->isAvailable($locale) === false)) {
544  $locale = $this->_options['locale'];
545  }
546 
547  return $this->_translate[(string) $locale];
548  }
549 
558  public function isAvailable($locale)
559  {
560  $return = isset($this->_translate[(string) $locale]);
561  return $return;
562  }
563 
572  abstract protected function _loadTranslationData($data, $locale, array $options = array());
573 
586  private function _addTranslationData($options = array())
587  {
588  if ($options instanceof Zend_Config) {
589  $options = $options->toArray();
590  } else if (func_num_args() > 1) {
591  $args = func_get_args();
592  $options['content'] = array_shift($args);
593 
594  if (!empty($args)) {
595  $options['locale'] = array_shift($args);
596  }
597 
598  if (!empty($args)) {
599  $options += array_shift($args);
600  }
601  }
602 
603  if (($options['content'] instanceof Zend_Translate) || ($options['content'] instanceof Zend_Translate_Adapter)) {
604  $options['usetranslateadapter'] = true;
605  if (!empty($options['locale']) && ($options['locale'] !== 'auto')) {
606  $options['content'] = $options['content']->getMessages($options['locale']);
607  } else {
608  $content = $options['content'];
609  $locales = $content->getList();
610  foreach ($locales as $locale) {
611  $options['locale'] = $locale;
612  $options['content'] = $content->getMessages($locale);
613  $this->_addTranslationData($options);
614  }
615 
616  return $this;
617  }
618  }
619 
620  try {
621  $options['locale'] = Zend_Locale::findLocale($options['locale']);
622  } catch (Zend_Locale_Exception $e) {
623  #require_once 'Zend/Translate/Exception.php';
624  throw new Zend_Translate_Exception("The given Language '{$options['locale']}' does not exist", 0, $e);
625  }
626 
627  if ($options['clear'] || !isset($this->_translate[$options['locale']])) {
628  $this->_translate[$options['locale']] = array();
629  }
630 
631  $read = true;
632  if (isset(self::$_cache)) {
633  $id = 'Zend_Translate_' . md5(serialize($options['content'])) . '_' . $this->toString();
634  $temp = self::$_cache->load($id);
635  if ($temp) {
636  $read = false;
637  }
638  }
639 
640  if ($options['reload']) {
641  $read = true;
642  }
643 
644  if ($read) {
645  if (!empty($options['usetranslateadapter'])) {
646  $temp = array($options['locale'] => $options['content']);
647  } else {
648  $temp = $this->_loadTranslationData($options['content'], $options['locale'], $options);
649  }
650  }
651 
652  if (empty($temp)) {
653  $temp = array();
654  }
655 
656  $keys = array_keys($temp);
657  foreach($keys as $key) {
658  if (!isset($this->_translate[$key])) {
659  $this->_translate[$key] = array();
660  }
661 
662  if (array_key_exists($key, $temp) && is_array($temp[$key])) {
663  $this->_translate[$key] = $temp[$key] + $this->_translate[$key];
664  }
665  }
666 
667  if ($this->_automatic === true) {
668  $find = new Zend_Locale($options['locale']);
669  $browser = $find->getEnvironment() + $find->getBrowser();
670  arsort($browser);
671  foreach($browser as $language => $quality) {
672  if (isset($this->_translate[$language])) {
673  $this->_options['locale'] = $language;
674  break;
675  }
676  }
677  }
678 
679  if (($read) and (isset(self::$_cache))) {
680  $id = 'Zend_Translate_' . md5(serialize($options['content'])) . '_' . $this->toString();
681  if (self::$_cacheTags) {
682  self::$_cache->save($temp, $id, array($this->_options['tag']));
683  } else {
684  self::$_cache->save($temp, $id);
685  }
686  }
687 
688  return $this;
689  }
690 
701  public function translate($messageId, $locale = null)
702  {
703  if ($locale === null) {
704  $locale = $this->_options['locale'];
705  }
706 
707  $plural = null;
708  if (is_array($messageId)) {
709  if (count($messageId) > 2) {
710  $number = array_pop($messageId);
711  if (!is_numeric($number)) {
712  $plocale = $number;
713  $number = array_pop($messageId);
714  } else {
715  $plocale = 'en';
716  }
717 
718  $plural = $messageId;
719  $messageId = $messageId[0];
720  } else {
721  $messageId = $messageId[0];
722  }
723  }
724 
725  if (!Zend_Locale::isLocale($locale, true, false)) {
726  if (!Zend_Locale::isLocale($locale, false, false)) {
727  // language does not exist, return original string
728  $this->_log($messageId, $locale);
729  // use rerouting when enabled
730  if (!empty($this->_options['route'])) {
731  if (array_key_exists($locale, $this->_options['route']) &&
732  !array_key_exists($locale, $this->_routed)) {
733  $this->_routed[$locale] = true;
734  return $this->translate($messageId, $this->_options['route'][$locale]);
735  }
736  }
737 
738  $this->_routed = array();
739  if ($plural === null) {
740  return $messageId;
741  }
742 
744  if (!isset($plural[$rule])) {
745  $rule = 0;
746  }
747 
748  return $plural[$rule];
749  }
750 
751  $locale = new Zend_Locale($locale);
752  }
753 
754  $locale = (string) $locale;
755  if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) {
756  // return original translation
757  if ($plural === null) {
758  $this->_routed = array();
759  return $this->_translate[$locale][$messageId];
760  }
761 
763  if (isset($this->_translate[$locale][$plural[0]][$rule])) {
764  $this->_routed = array();
765  return $this->_translate[$locale][$plural[0]][$rule];
766  }
767  } else if (strlen($locale) != 2) {
768  // faster than creating a new locale and separate the leading part
769  $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
770 
771  if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) {
772  // return regionless translation (en_US -> en)
773  if ($plural === null) {
774  $this->_routed = array();
775  return $this->_translate[$locale][$messageId];
776  }
777 
779  if (isset($this->_translate[$locale][$plural[0]][$rule])) {
780  $this->_routed = array();
781  return $this->_translate[$locale][$plural[0]][$rule];
782  }
783  }
784  }
785 
786  $this->_log($messageId, $locale);
787  // use rerouting when enabled
788  if (!empty($this->_options['route'])) {
789  if (array_key_exists($locale, $this->_options['route']) &&
790  !array_key_exists($locale, $this->_routed)) {
791  $this->_routed[$locale] = true;
792  return $this->translate($messageId, $this->_options['route'][$locale]);
793  }
794  }
795 
796  $this->_routed = array();
797  if ($plural === null) {
798  return $messageId;
799  }
800 
802  if (!isset($plural[$rule])) {
803  $rule = 0;
804  }
805 
806  return $plural[$rule];
807  }
808 
821  public function plural($singular, $plural, $number, $locale = null)
822  {
823  return $this->translate(array($singular, $plural, $number), $locale);
824  }
825 
832  protected function _log($message, $locale) {
833  if ($this->_options['logUntranslated']) {
834  $message = str_replace('%message%', $message, $this->_options['logMessage']);
835  $message = str_replace('%locale%', $locale, $message);
836  if ($this->_options['log']) {
837  $this->_options['log']->log($message, $this->_options['logPriority']);
838  } else {
839  trigger_error($message, E_USER_NOTICE);
840  }
841  }
842  }
843 
853  public function _($messageId, $locale = null)
854  {
855  return $this->translate($messageId, $locale);
856  }
857 
870  public function isTranslated($messageId, $original = false, $locale = null)
871  {
872  if (($original !== false) and ($original !== true)) {
873  $locale = $original;
874  $original = false;
875  }
876 
877  if ($locale === null) {
878  $locale = $this->_options['locale'];
879  }
880 
881  if (!Zend_Locale::isLocale($locale, true, false)) {
882  if (!Zend_Locale::isLocale($locale, false, false)) {
883  // language does not exist, return original string
884  return false;
885  }
886 
887  $locale = new Zend_Locale($locale);
888  }
889 
890  $locale = (string) $locale;
891  if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) {
892  // return original translation
893  return true;
894  } else if ((strlen($locale) != 2) and ($original === false)) {
895  // faster than creating a new locale and separate the leading part
896  $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
897 
898  if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) {
899  // return regionless translation (en_US -> en)
900  return true;
901  }
902  }
903 
904  // No translation found, return original
905  return false;
906  }
907 
913  public static function getCache()
914  {
915  return self::$_cache;
916  }
917 
923  public static function setCache(Zend_Cache_Core $cache)
924  {
925  self::$_cache = $cache;
926  self::_getTagSupportForCache();
927  }
928 
934  public static function hasCache()
935  {
936  if (self::$_cache !== null) {
937  return true;
938  }
939 
940  return false;
941  }
942 
948  public static function removeCache()
949  {
950  self::$_cache = null;
951  }
952 
959  public static function clearCache($tag = null)
960  {
961  #require_once 'Zend/Cache.php';
962  if (self::$_cacheTags) {
963  if ($tag == null) {
964  $tag = 'Zend_Translate';
965  }
966 
967  self::$_cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array($tag));
968  } else {
969  self::$_cache->clean(Zend_Cache::CLEANING_MODE_ALL);
970  }
971  }
972 
978  abstract public function toString();
979 
985  private static function _getTagSupportForCache()
986  {
987  $backend = self::$_cache->getBackend();
988  if ($backend instanceof Zend_Cache_Backend_ExtendedInterface) {
989  $cacheOptions = $backend->getCapabilities();
990  self::$_cacheTags = $cacheOptions['tags'];
991  } else {
992  self::$_cacheTags = false;
993  }
994 
995  return self::$_cacheTags;
996  }
997 }
getMessageIds($locale=null)
Definition: Adapter.php:520
getMessageId($message, $locale=null)
Definition: Adapter.php:504
$number
Definition: details.phtml:22
$id
Definition: fieldset.phtml:14
getOptions($optionKey=null)
Definition: Adapter.php:393
$message
__construct($options=array())
Definition: Adapter.php:128
_loadTranslationData($data, $locale, array $options=array())
translate($messageId, $locale=null)
Definition: Adapter.php:701
$locales
Definition: locales.php:14
$value
Definition: gender.phtml:16
static isLocale($locale, $strict=false, $compatible=true)
Definition: Locale.php:1683
plural($singular, $plural, $number, $locale=null)
Definition: Adapter.php:821
static findLocale($locale=null)
Definition: Locale.php:1740
const CLEANING_MODE_ALL
Definition: Cache.php:72
static clearCache($tag=null)
Definition: Adapter.php:959
addTranslation($options=array())
Definition: Adapter.php:197
setOptions(array $options=array())
Definition: Adapter.php:346
static setCache(Zend_Cache_Core $cache)
Definition: Adapter.php:923
isTranslated($messageId, $original=false, $locale=null)
Definition: Adapter.php:870
_($messageId, $locale=null)
Definition: Adapter.php:853
$change
_log($message, $locale)
Definition: Adapter.php:832
static getPlural($number, $locale)
Definition: Plural.php:46
getMessages($locale=null)
Definition: Adapter.php:537
const CLEANING_MODE_MATCHING_TAG
Definition: Cache.php:74
foreach( $_productCollection as $_product)() ?>" class $info
Definition: listing.phtml:52