Completed
Push — 3 ( bc9e38...39c73e )
by Robbie
05:15 queued 10s
created

Zend_Translate_Adapter   F

Complexity

Total Complexity 177

Size/Duplication

Total Lines 957
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 0
loc 957
rs 1.643
c 0
b 0
f 0
wmc 177
lcom 1
cbo 5

25 Methods

Rating   Name   Duplication   Size   Complexity  
F __construct() 0 57 14
F addTranslation() 0 141 38
C setOptions() 0 39 13
A getOptions() 0 12 3
A getLocale() 0 4 1
C setLocale() 0 55 15
A getList() 0 11 3
A getMessageId() 0 8 3
A getMessageIds() 0 8 3
A getMessages() 0 12 4
A isAvailable() 0 5 1
_loadTranslationData() 0 1 ?
F _addTranslationData() 0 104 29
F translate() 0 110 21
A plural() 0 4 1
A _log() 0 11 3
A _() 0 4 1
C isTranslated() 0 37 14
A getCache() 0 4 1
A setCache() 0 5 1
A hasCache() 0 8 2
A removeCache() 0 4 1
A clearCache() 0 13 3
toString() 0 1 ?
A _getTagSupportForCache() 0 12 2

How to fix   Complexity   

Complex Class

Complex classes like Zend_Translate_Adapter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Zend_Translate_Adapter, and based on these observations, apply Extract Interface, too.

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 [email protected] 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-2011 Zend Technologies USA Inc. (http://www.zend.com)
19
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
20
 * @version    $Id: Adapter.php 24268 2011-07-25 14:47:42Z guilhermeblanco $
21
 */
22
23
/**
24
 * @see Zend_Locale
25
 */
26
require_once 'Zend/Locale.php';
27
28
/**
29
 * @see Zend_Translate_Plural
30
 */
31
require_once 'Zend/Translate/Plural.php';
32
33
/**
34
 * Basic adapter class for each translation source adapter
35
 *
36
 * @category   Zend
37
 * @package    Zend_Translate
38
 * @subpackage Zend_Translate_Adapter
39
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
40
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
41
 */
42
abstract class Zend_Translate_Adapter {
43
    /**
44
     * Shows if locale detection is in automatic level
45
     * @var boolean
46
     */
47
    private $_automatic = true;
48
49
    /**
50
     * Internal value to see already routed languages
51
     * @var array()
52
     */
53
    private $_routed = array();
54
55
    /**
56
     * Internal cache for all adapters
57
     * @var Zend_Cache_Core
58
     */
59
    protected static $_cache     = null;
60
61
    /**
62
     * Internal value to remember if cache supports tags
63
     *
64
     * @var boolean
65
     */
66
    private static $_cacheTags = false;
67
68
    /**
69
     * Scans for the locale within the name of the directory
70
     * @constant integer
71
     */
72
    const LOCALE_DIRECTORY = 'directory';
73
74
    /**
75
     * Scans for the locale within the name of the file
76
     * @constant integer
77
     */
78
    const LOCALE_FILENAME  = 'filename';
79
80
    /**
81
     * Array with all options, each adapter can have own additional options
82
     *   'clear'           => when true, clears already loaded translations when adding new files
83
     *   'content'         => content to translate or file or directory with content
84
     *   'disableNotices'  => when true, omits notices from being displayed
85
     *   'ignore'          => a prefix for files and directories which are not being added
86
     *   'locale'          => the actual set locale to use
87
     *   'log'             => a instance of Zend_Log where logs are written to
88
     *   'logMessage'      => message to be logged
89
     *   'logPriority'     => priority which is used to write the log message
90
     *   'logUntranslated' => when true, untranslated messages are not logged
91
     *   'reload'          => reloads the cache by reading the content again
92
     *   'scan'            => searches for translation files using the LOCALE constants
93
     *   'tag'             => tag to use for the cache
94
     *
95
     * @var array
96
     */
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
113
    /**
114
     * Translation table
115
     * @var array
116
     */
117
    protected $_translate = array();
118
119
    /**
120
     * Generates the adapter
121
     *
122
     * @param  array|Zend_Config $options Translation options for this adapter
123
     * @throws Zend_Translate_Exception
124
     * @return void
125
     */
126
    public function __construct($options = array())
127
    {
128
        if ($options instanceof Zend_Config) {
129
            $options = $options->toArray();
130
        } else if (func_num_args() > 1) {
131
            $args               = func_get_args();
132
            $options            = array();
133
            $options['content'] = array_shift($args);
134
135
            if (!empty($args)) {
136
                $options['locale'] = array_shift($args);
137
            }
138
139
            if (!empty($args)) {
140
                $opt     = array_shift($args);
141
                $options = array_merge($opt, $options);
142
            }
143
        } else if (!is_array($options)) {
144
            $options = array('content' => $options);
145
        }
146
147
        if (array_key_exists('cache', $options)) {
148
            self::setCache($options['cache']);
149
            unset($options['cache']);
150
        }
151
152
        if (isset(self::$_cache)) {
153
            $id = 'Zend_Translate_' . $this->toString() . '_Options';
154
            $result = self::$_cache->load($id);
155
            if ($result) {
156
                $this->_options = $result;
157
            }
158
        }
159
160
        if (empty($options['locale']) || ($options['locale'] === "auto")) {
161
            $this->_automatic = true;
162
        } else {
163
            $this->_automatic = false;
164
        }
165
166
        $locale = null;
167
        if (!empty($options['locale'])) {
168
            $locale = $options['locale'];
169
            unset($options['locale']);
170
        }
171
172
        $this->setOptions($options);
173
        $options['locale'] = $locale;
174
175
        if (!empty($options['content'])) {
176
            $this->addTranslation($options);
177
        }
178
179
        if ($this->getLocale() !== (string) $options['locale']) {
180
            $this->setLocale($options['locale']);
181
        }
182
    }
183
184
    /**
185
     * Add translations
186
     *
187
     * This may be a new language or additional content for an existing language
188
     * If the key 'clear' is true, then translations for the specified
189
     * language will be replaced and added otherwise
190
     *
191
     * @param  array|Zend_Config $options Options and translations to be added
192
     * @throws Zend_Translate_Exception
193
     * @return Zend_Translate_Adapter Provides fluent interface
194
     */
195
    public function addTranslation($options = array())
196
    {
197
        if ($options instanceof Zend_Config) {
198
            $options = $options->toArray();
199
        } else if (func_num_args() > 1) {
200
            $args = func_get_args();
201
            $options            = array();
202
            $options['content'] = array_shift($args);
203
204
            if (!empty($args)) {
205
                $options['locale'] = array_shift($args);
206
            }
207
208
            if (!empty($args)) {
209
                $opt     = array_shift($args);
210
                $options = array_merge($opt, $options);
211
            }
212
        } else if (!is_array($options)) {
213
            $options = array('content' => $options);
214
        }
215
        
216
        if (!isset($options['content']) || empty($options['content'])) {
217
            require_once 'Zend/Translate/Exception.php';
218
            throw new Zend_Translate_Exception("Required option 'content' is missing");
219
        }
220
221
        $originate = null;
222
        if (!empty($options['locale'])) {
223
            $originate = (string) $options['locale'];
224
        }
225
226
        if ((array_key_exists('log', $options)) && !($options['log'] instanceof Zend_Log)) {
227
            require_once 'Zend/Translate/Exception.php';
228
            throw new Zend_Translate_Exception('Instance of Zend_Log expected for option log');
229
        }
230
231
        try {
232
            if (!($options['content'] instanceof Zend_Translate) && !($options['content'] instanceof Zend_Translate_Adapter)) {
233
                if (empty($options['locale'])) {
234
                    $options['locale'] = null;
235
                }
236
237
                $options['locale'] = Zend_Locale::findLocale($options['locale']);
238
            }
239
        } catch (Zend_Locale_Exception $e) {
240
            require_once 'Zend/Translate/Exception.php';
241
            throw new Zend_Translate_Exception("The given Language '{$options['locale']}' does not exist", 0, $e);
242
        }
243
244
        $options  = $options + $this->_options;
245
        if (is_string($options['content']) and is_dir($options['content'])) {
246
            $options['content'] = realpath($options['content']);
247
            $prev = '';
248
            $iterator = new RecursiveIteratorIterator(
249
                new RecursiveRegexIterator(
250
                    new RecursiveDirectoryIterator($options['content'], RecursiveDirectoryIterator::KEY_AS_PATHNAME),
251
                    '/^(?!.*(\.svn|\.cvs)).*$/', RecursiveRegexIterator::MATCH
252
                ),
253
                RecursiveIteratorIterator::SELF_FIRST
254
            );
255
            
256
            foreach ($iterator as $directory => $info) {
257
                $file = $info->getFilename();
258
                if (is_array($options['ignore'])) {
259
                    foreach ($options['ignore'] as $key => $ignore) {
260
                        if (strpos($key, 'regex') !== false) {
261
                            if (preg_match($ignore, $directory)) {
262
                                // ignore files matching the given regex from option 'ignore' and all files below
263
                                continue 2;
264
                            }
265
                        } else if (strpos($directory, DIRECTORY_SEPARATOR . $ignore) !== false) {
266
                            // ignore files matching first characters from option 'ignore' and all files below
267
                            continue 2;
268
                        }
269
                    }
270
                } else {
271
                    if (strpos($directory, DIRECTORY_SEPARATOR . $options['ignore']) !== false) {
272
                        // ignore files matching first characters from option 'ignore' and all files below
273
                        continue;
274
                    }
275
                }
276
277
                if ($info->isDir()) {
278
                    // pathname as locale
279
                    if (($options['scan'] === self::LOCALE_DIRECTORY) and (Zend_Locale::isLocale($file, true, false))) {
280
                        $options['locale'] = $file;
281
                        $prev              = (string) $options['locale'];
282
                    }
283
                } else if ($info->isFile()) {
284
                    // filename as locale
285
                    if ($options['scan'] === self::LOCALE_FILENAME) {
286
                        $filename = explode('.', $file);
287
                        array_pop($filename);
288
                        $filename = implode('.', $filename);
289
                        if (Zend_Locale::isLocale((string) $filename, true, false)) {
290
                            $options['locale'] = (string) $filename;
291
                        } else {
292
                            $parts  = explode('.', $file);
293
                            $parts2 = array();
294
                            foreach($parts as $token) {
295
                                $parts2 += explode('_', $token);
296
                            }
297
                            $parts  = array_merge($parts, $parts2);
298
                            $parts2 = array();
299
                            foreach($parts as $token) {
300
                                $parts2 += explode('-', $token);
301
                            }
302
                            $parts = array_merge($parts, $parts2);
303
                            $parts = array_unique($parts);
304
                            $prev  = '';
305
                            foreach($parts as $token) {
306
                                if (Zend_Locale::isLocale($token, true, false)) {
307
                                    if (strlen($prev) <= strlen($token)) {
308
                                        $options['locale'] = $token;
309
                                        $prev              = $token;
310
                                    }
311
                                }
312
                            }
313
                        }
314
                    }
315
316
                    try {
317
                        $options['content'] = $info->getPathname();
318
                        $this->_addTranslationData($options);
319
                    } catch (Zend_Translate_Exception $e) {
320
                        // ignore failed sources while scanning
321
                    }
322
                }
323
            }
324
            
325
            unset($iterator);
326
        } else {
327
            $this->_addTranslationData($options);
328
        }
329
330
        if ((isset($this->_translate[$originate]) === true) and (count($this->_translate[$originate]) > 0)) {
331
            $this->setLocale($originate);
332
        }
333
334
        return $this;
335
    }
336
337
    /**
338
     * Sets new adapter options
339
     *
340
     * @param  array $options Adapter options
341
     * @throws Zend_Translate_Exception
342
     * @return Zend_Translate_Adapter Provides fluent interface
343
     */
344
    public function setOptions(array $options = array())
345
    {
346
        $change = false;
347
        $locale = null;
348
        foreach ($options as $key => $option) {
349
            if ($key == 'locale') {
350
                $locale = $option;
351
            } else if ((isset($this->_options[$key]) and ($this->_options[$key] != $option)) or
352
                    !isset($this->_options[$key])) {
353
                if (($key == 'log') && !($option instanceof Zend_Log)) {
354
                    require_once 'Zend/Translate/Exception.php';
355
                    throw new Zend_Translate_Exception('Instance of Zend_Log expected for option log');
356
                }
357
358
                if ($key == 'cache') {
359
                    self::setCache($option);
360
                    continue;
361
                }
362
363
                $this->_options[$key] = $option;
364
                $change = true;
365
            }
366
        }
367
368
        if ($locale !== null) {
369
            $this->setLocale($locale);
370
        }
371
372
        if (isset(self::$_cache) and ($change == true)) {
373
            $id = 'Zend_Translate_' . $this->toString() . '_Options';
374
            if (self::$_cacheTags) {
375
                self::$_cache->save($this->_options, $id, array($this->_options['tag']));
376
            } else {
377
                self::$_cache->save($this->_options, $id);
378
            }
379
        }
380
381
        return $this;
382
    }
383
384
    /**
385
     * Returns the adapters name and it's options
386
     *
387
     * @param  string|null $optionKey String returns this option
388
     *                                null returns all options
389
     * @return integer|string|array|null
390
     */
391
    public function getOptions($optionKey = null)
392
    {
393
        if ($optionKey === null) {
394
            return $this->_options;
395
        }
396
397
        if (isset($this->_options[$optionKey]) === true) {
398
            return $this->_options[$optionKey];
399
        }
400
401
        return null;
402
    }
403
404
    /**
405
     * Gets locale
406
     *
407
     * @return Zend_Locale|string|null
408
     */
409
    public function getLocale()
410
    {
411
        return $this->_options['locale'];
412
    }
413
414
    /**
415
     * Sets locale
416
     *
417
     * @param  string|Zend_Locale $locale Locale to set
418
     * @throws Zend_Translate_Exception
419
     * @return Zend_Translate_Adapter Provides fluent interface
420
     */
421
    public function setLocale($locale)
422
    {
423
        if (($locale === "auto") or ($locale === null)) {
424
            $this->_automatic = true;
425
        } else {
426
            $this->_automatic = false;
427
        }
428
429
        try {
430
            $locale = Zend_Locale::findLocale($locale);
431
        } catch (Zend_Locale_Exception $e) {
432
            require_once 'Zend/Translate/Exception.php';
433
            throw new Zend_Translate_Exception("The given Language ({$locale}) does not exist", 0, $e);
434
        }
435
436
        if (!isset($this->_translate[$locale])) {
437
            $temp = explode('_', $locale);
438
            if (!isset($this->_translate[$temp[0]]) and !isset($this->_translate[$locale])) {
439
                if (!$this->_options['disableNotices']) {
440
                    if ($this->_options['log']) {
441
                        $this->_options['log']->log("The language '{$locale}' has to be added before it can be used.", $this->_options['logPriority']);
442
                    } else {
443
                        trigger_error("The language '{$locale}' has to be added before it can be used.", E_USER_NOTICE);
444
                    }
445
                }
446
            }
447
448
            $locale = $temp[0];
449
        }
450
451
        if (empty($this->_translate[$locale])) {
452
            if (!$this->_options['disableNotices']) {
453
                if ($this->_options['log']) {
454
                    $this->_options['log']->log("No translation for the language '{$locale}' available.", $this->_options['logPriority']);
455
                } else {
456
                    trigger_error("No translation for the language '{$locale}' available.", E_USER_NOTICE);
457
                }
458
            }
459
        }
460
461
        if ($this->_options['locale'] != $locale) {
462
            $this->_options['locale'] = $locale;
463
464
            if (isset(self::$_cache)) {
465
                $id = 'Zend_Translate_' . $this->toString() . '_Options';
466
                if (self::$_cacheTags) {
467
                    self::$_cache->save($this->_options, $id, array($this->_options['tag']));
468
                } else {
469
                    self::$_cache->save($this->_options, $id);
470
                }
471
            }
472
        }
473
474
        return $this;
475
    }
476
477
    /**
478
     * Returns the available languages from this adapter
479
     *
480
     * @return array|null
481
     */
482
    public function getList()
483
    {
484
        $list = array_keys($this->_translate);
485
        $result = null;
486
        foreach($list as $value) {
487
            if (!empty($this->_translate[$value])) {
488
                $result[$value] = $value;
489
            }
490
        }
491
        return $result;
492
    }
493
494
    /**
495
     * Returns the message id for a given translation
496
     * If no locale is given, the actual language will be used
497
     *
498
     * @param  string             $message Message to get the key for
499
     * @param  string|Zend_Locale $locale (optional) Language to return the message ids from
500
     * @return string|array|false
501
     */
502
    public function getMessageId($message, $locale = null)
503
    {
504
        if (empty($locale) or !$this->isAvailable($locale)) {
505
            $locale = $this->_options['locale'];
506
        }
507
508
        return array_search($message, $this->_translate[(string) $locale]);
509
    }
510
511
    /**
512
     * Returns all available message ids from this adapter
513
     * If no locale is given, the actual language will be used
514
     *
515
     * @param  string|Zend_Locale $locale (optional) Language to return the message ids from
516
     * @return array
517
     */
518
    public function getMessageIds($locale = null)
519
    {
520
        if (empty($locale) or !$this->isAvailable($locale)) {
521
            $locale = $this->_options['locale'];
522
        }
523
524
        return array_keys($this->_translate[(string) $locale]);
525
    }
526
527
    /**
528
     * Returns all available translations from this adapter
529
     * If no locale is given, the actual language will be used
530
     * If 'all' is given the complete translation dictionary will be returned
531
     *
532
     * @param  string|Zend_Locale $locale (optional) Language to return the messages from
533
     * @return array
534
     */
535
    public function getMessages($locale = null)
536
    {
537
        if ($locale === 'all') {
538
            return $this->_translate;
539
        }
540
541
        if ((empty($locale) === true) or ($this->isAvailable($locale) === false)) {
542
            $locale = $this->_options['locale'];
543
        }
544
545
        return $this->_translate[(string) $locale];
546
    }
547
548
    /**
549
     * Is the wished language available ?
550
     *
551
     * @see    Zend_Locale
552
     * @param  string|Zend_Locale $locale Language to search for, identical with locale identifier,
553
     *                                    @see Zend_Locale for more information
554
     * @return boolean
555
     */
556
    public function isAvailable($locale)
557
    {
558
        $return = isset($this->_translate[(string) $locale]);
559
        return $return;
560
    }
561
562
    /**
563
     * Load translation data
564
     *
565
     * @param  mixed              $data
566
     * @param  string|Zend_Locale $locale
567
     * @param  array              $options (optional)
568
     * @return array
569
     */
570
    abstract protected function _loadTranslationData($data, $locale, array $options = array());
571
572
    /**
573
     * Internal function for adding translation data
574
     *
575
     * This may be a new language or additional data for an existing language
576
     * If the options 'clear' is true, then the translation data for the specified
577
     * language is replaced and added otherwise
578
     *
579
     * @see    Zend_Locale
580
     * @param  array|Zend_Config $content Translation data to add
581
     * @throws Zend_Translate_Exception
582
     * @return Zend_Translate_Adapter Provides fluent interface
583
     */
584
    private function _addTranslationData($options = array())
585
    {
586
        if ($options instanceof Zend_Config) {
587
            $options = $options->toArray();
588
        } else if (func_num_args() > 1) {
589
            $args = func_get_args();
590
            $options['content'] = array_shift($args);
591
592
            if (!empty($args)) {
593
                $options['locale'] = array_shift($args);
594
            }
595
596
            if (!empty($args)) {
597
                $options += array_shift($args);
598
            }
599
        }
600
601
        if (($options['content'] instanceof Zend_Translate) || ($options['content'] instanceof Zend_Translate_Adapter)) {
602
            $options['usetranslateadapter'] = true;
603
            if (!empty($options['locale']) && ($options['locale'] !== 'auto')) {
604
                $options['content'] = $options['content']->getMessages($options['locale']);
605
            } else {
606
                $content = $options['content'];
607
                $locales = $content->getList();
608
                foreach ($locales as $locale) {
609
                    $options['locale']  = $locale;
610
                    $options['content'] = $content->getMessages($locale);
611
                    $this->_addTranslationData($options);
612
                }
613
614
                return $this;
615
            }
616
        }
617
618
        try {
619
            $options['locale'] = Zend_Locale::findLocale($options['locale']);
620
        } catch (Zend_Locale_Exception $e) {
621
            require_once 'Zend/Translate/Exception.php';
622
            throw new Zend_Translate_Exception("The given Language '{$options['locale']}' does not exist", 0, $e);
623
        }
624
625
        if ($options['clear'] || !isset($this->_translate[$options['locale']])) {
626
            $this->_translate[$options['locale']] = array();
627
        }
628
629
        $read = true;
630
        if (isset(self::$_cache)) {
631
            $id = 'Zend_Translate_' . md5(serialize($options['content'])) . '_' . $this->toString();
632
            $temp = self::$_cache->load($id);
633
            if ($temp) {
634
                $read = false;
635
            }
636
        }
637
638
        if ($options['reload']) {
639
            $read = true;
640
        }
641
642
        if ($read) {
643
            if (!empty($options['usetranslateadapter'])) {
644
                $temp = array($options['locale'] => $options['content']);
645
            } else {
646
                $temp = $this->_loadTranslationData($options['content'], $options['locale'], $options);
647
            }
648
        }
649
650
        if (empty($temp)) {
651
            $temp = array();
652
        }
653
654
        $keys = array_keys($temp);
655
        foreach($keys as $key) {
656
            if (!isset($this->_translate[$key])) {
657
                $this->_translate[$key] = array();
658
            }
659
660
            if (array_key_exists($key, $temp) && is_array($temp[$key])) {
661
                $this->_translate[$key] = $temp[$key] + $this->_translate[$key];
662
            }
663
        }
664
665
        if ($this->_automatic === true) {
666
            $find = new Zend_Locale($options['locale']);
667
            $browser = $find->getEnvironment() + $find->getBrowser();
668
            arsort($browser);
669
            foreach($browser as $language => $quality) {
670
                if (isset($this->_translate[$language])) {
671
                    $this->_options['locale'] = $language;
672
                    break;
673
                }
674
            }
675
        }
676
677
        if (($read) and (isset(self::$_cache))) {
678
            $id = 'Zend_Translate_' . md5(serialize($options['content'])) . '_' . $this->toString();
679
            if (self::$_cacheTags) {
680
                self::$_cache->save($temp, $id, array($this->_options['tag']));
681
            } else {
682
                self::$_cache->save($temp, $id);
683
            }
684
        }
685
686
        return $this;
687
    }
688
689
    /**
690
     * Translates the given string
691
     * returns the translation
692
     *
693
     * @see Zend_Locale
694
     * @param  string|array       $messageId Translation string, or Array for plural translations
695
     * @param  string|Zend_Locale $locale    (optional) Locale/Language to use, identical with
696
     *                                       locale identifier, @see Zend_Locale for more information
697
     * @return string
698
     */
699
    public function translate($messageId, $locale = null)
700
    {
701
        if ($locale === null) {
702
            $locale = $this->_options['locale'];
703
        }
704
705
        $plural = null;
706
        if (is_array($messageId)) {
707
            if (count($messageId) > 2) {
708
                $number = array_pop($messageId);
709
                if (!is_numeric($number)) {
710
                    $plocale = $number;
711
                    $number  = array_pop($messageId);
712
                } else {
713
                    $plocale = 'en';
714
                }
715
716
                $plural    = $messageId;
717
                $messageId = $messageId[0];
718
            } else {
719
                $messageId = $messageId[0];
720
            }
721
        }
722
723
        // CUSTOM ischommer: Skip locale checks, too computationally expensive.
724
        // Assume correct locale value is passed in.
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
743
        //         $rule = Zend_Translate_Plural::getPlural($number, $plocale);
744
        //         if (!isset($plural[$rule])) {
745
        //             $rule = 0;
746
        //         }
747
748
        //         return $plural[$rule];
749
        //     }
750
751
        //     $locale = new Zend_Locale($locale);
752
        // }
753
        // CUSTOM END
754
755
        $locale = (string) $locale;
756
        if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) {
757
            // return original translation
758
            if ($plural === null) {
759
                $this->_routed = array();
760
                return $this->_translate[$locale][$messageId];
761
            }
762
763
            $rule = Zend_Translate_Plural::getPlural($number, $locale);
764
            if (isset($this->_translate[$locale][$plural[0]][$rule])) {
765
                $this->_routed = array();
766
                return $this->_translate[$locale][$plural[0]][$rule];
767
            }
768
        } else if (strlen($locale) != 2) {
769
            // faster than creating a new locale and separate the leading part
770
            $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
771
772
            if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) {
773
                // return regionless translation (en_US -> en)
774
                if ($plural === null) {
775
                    $this->_routed = array();
776
                    return $this->_translate[$locale][$messageId];
777
                }
778
779
                $rule = Zend_Translate_Plural::getPlural($number, $locale);
780
                if (isset($this->_translate[$locale][$plural[0]][$rule])) {
781
                    $this->_routed = array();
782
                    return $this->_translate[$locale][$plural[0]][$rule];
783
                }
784
            }
785
        }
786
787
        $this->_log($messageId, $locale);
788
        // use rerouting when enabled
789
        if (!empty($this->_options['route'])) {
790
            if (array_key_exists($locale, $this->_options['route']) &&
791
                !array_key_exists($locale, $this->_routed)) {
792
                $this->_routed[$locale] = true;
793
                return $this->translate($messageId, $this->_options['route'][$locale]);
794
            }
795
        }
796
797
        $this->_routed = array();
798
        if ($plural === null) {
799
            return $messageId;
800
        }
801
802
        $rule = Zend_Translate_Plural::getPlural($number, $plocale);
803
        if (!isset($plural[$rule])) {
804
            $rule = 0;
805
        }
806
807
        return $plural[$rule];
808
    }
809
810
    /**
811
     * Translates the given string using plural notations
812
     * Returns the translated string
813
     *
814
     * @see Zend_Locale
815
     * @param  string             $singular Singular translation string
816
     * @param  string             $plural   Plural translation string
817
     * @param  integer            $number   Number for detecting the correct plural
818
     * @param  string|Zend_Locale $locale   (Optional) Locale/Language to use, identical with
819
     *                                      locale identifier, @see Zend_Locale for more information
820
     * @return string
821
     */
822
    public function plural($singular, $plural, $number, $locale = null)
823
    {
824
        return $this->translate(array($singular, $plural, $number), $locale);
825
    }
826
827
    /**
828
     * Logs a message when the log option is set
829
     *
830
     * @param string $message Message to log
831
     * @param String $locale  Locale to log
832
     */
833
    protected function _log($message, $locale) {
834
        if ($this->_options['logUntranslated']) {
835
            $message = str_replace('%message%', $message, $this->_options['logMessage']);
836
            $message = str_replace('%locale%', $locale, $message);
837
            if ($this->_options['log']) {
838
                $this->_options['log']->log($message, $this->_options['logPriority']);
839
            } else {
840
                trigger_error($message, E_USER_NOTICE);
841
            }
842
        }
843
    }
844
845
    /**
846
     * Translates the given string
847
     * returns the translation
848
     *
849
     * @param  string             $messageId Translation string
850
     * @param  string|Zend_Locale $locale    (optional) Locale/Language to use, identical with locale
851
     *                                       identifier, @see Zend_Locale for more information
852
     * @return string
853
     */
854
    public function _($messageId, $locale = null)
855
    {
856
        return $this->translate($messageId, $locale);
857
    }
858
859
    /**
860
     * Checks if a string is translated within the source or not
861
     * returns boolean
862
     *
863
     * @param  string             $messageId Translation string
864
     * @param  boolean            $original  (optional) Allow translation only for original language
865
     *                                       when true, a translation for 'en_US' would give false when it can
866
     *                                       be translated with 'en' only
867
     * @param  string|Zend_Locale $locale    (optional) Locale/Language to use, identical with locale identifier,
868
     *                                       see Zend_Locale for more information
869
     * @return boolean
870
     */
871
    public function isTranslated($messageId, $original = false, $locale = null)
872
    {
873
        if (($original !== false) and ($original !== true)) {
874
            $locale   = $original;
875
            $original = false;
876
        }
877
878
        if ($locale === null) {
879
            $locale = $this->_options['locale'];
880
        }
881
882
        if (!Zend_Locale::isLocale($locale, true, false)) {
883
            if (!Zend_Locale::isLocale($locale, false, false)) {
884
                // language does not exist, return original string
885
                return false;
886
            }
887
888
            $locale = new Zend_Locale($locale);
889
        }
890
891
        $locale = (string) $locale;
892
        if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) {
893
            // return original translation
894
            return true;
895
        } else if ((strlen($locale) != 2) and ($original === false)) {
896
            // faster than creating a new locale and separate the leading part
897
            $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
898
899
            if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) {
900
                // return regionless translation (en_US -> en)
901
                return true;
902
            }
903
        }
904
905
        // No translation found, return original
906
        return false;
907
    }
908
909
    /**
910
     * Returns the set cache
911
     *
912
     * @return Zend_Cache_Core The set cache
913
     */
914
    public static function getCache()
915
    {
916
        return self::$_cache;
917
    }
918
919
    /**
920
     * Sets a cache for all Zend_Translate_Adapters
921
     *
922
     * @param Zend_Cache_Core $cache Cache to store to
923
     */
924
    public static function setCache(Zend_Cache_Core $cache)
925
    {
926
        self::$_cache = $cache;
927
        self::_getTagSupportForCache();
928
    }
929
930
    /**
931
     * Returns true when a cache is set
932
     *
933
     * @return boolean
934
     */
935
    public static function hasCache()
936
    {
937
        if (self::$_cache !== null) {
938
            return true;
939
        }
940
941
        return false;
942
    }
943
944
    /**
945
     * Removes any set cache
946
     *
947
     * @return void
948
     */
949
    public static function removeCache()
950
    {
951
        self::$_cache = null;
952
    }
953
954
    /**
955
     * Clears all set cache data
956
     *
957
     * @param string $tag Tag to clear when the default tag name is not used
958
     * @return void
959
     */
960
    public static function clearCache($tag = null)
961
    {
962
        require_once 'Zend/Cache.php';
963
        if (self::$_cacheTags) {
964
            if ($tag == null) {
965
                $tag = 'Zend_Translate';
966
            }
967
968
            self::$_cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array($tag));
969
        } else {
970
            self::$_cache->clean(Zend_Cache::CLEANING_MODE_ALL);
971
        }
972
    }
973
974
    /**
975
     * Returns the adapter name
976
     *
977
     * @return string
978
     */
979
    abstract public function toString();
980
981
    /**
982
     * Internal method to check if the given cache supports tags
983
     *
984
     * @param Zend_Cache $cache
985
     */
986
    private static function _getTagSupportForCache()
987
    {
988
        $backend = self::$_cache->getBackend();
989
        if ($backend instanceof Zend_Cache_Backend_ExtendedInterface) {
990
            $cacheOptions = $backend->getCapabilities();
991
            self::$_cacheTags = $cacheOptions['tags'];
992
        } else {
993
            self::$_cacheTags = false;
994
        }
995
996
        return self::$_cacheTags;
997
    }
998
}
999