Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
 
3
/*
4
 * This file is part of the symfony package.
5
 * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
 
11
/**
12
 * sfI18N wraps the core i18n classes for a symfony context.
13
 *
14
 * @package    symfony
15
 * @subpackage i18n
16
 * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
17
 * @version    SVN: $Id: sfI18N.class.php 29520 2010-05-19 11:47:08Z fabien $
18
 */
19
class sfI18N
20
{
21
  protected
22
    $configuration = null,
23
    $dispatcher    = null,
24
    $cache         = null,
25
    $options       = array(),
26
    $culture       = 'en',
27
    $messageSource = null,
28
    $messageFormat = null;
29
 
30
  /**
31
   * Class constructor.
32
   *
33
   * @see initialize()
34
   */
35
  public function __construct(sfApplicationConfiguration $configuration, sfCache $cache = null, $options = array())
36
  {
37
    $this->initialize($configuration, $cache, $options);
38
  }
39
 
40
  /**
41
   * Initializes this class.
42
   *
43
   * Available options:
44
   *
45
   *  * culture:             The culture
46
   *  * source:              The i18n source (XLIFF by default)
47
   *  * debug:               Whether to enable debug or not (false by default)
48
   *  * database:            The database name (default by default)
49
   *  * untranslated_prefix: The prefix to use when a message is not translated
50
   *  * untranslated_suffix: The suffix to use when a message is not translated
51
   *
52
   * @param sfApplicationConfiguration $configuration   A sfApplicationConfiguration instance
53
   * @param sfCache                    $cache           A sfCache instance
54
   * @param array                      $options         An array of options
55
   */
56
  public function initialize(sfApplicationConfiguration $configuration, sfCache $cache = null, $options = array())
57
  {
58
    $this->configuration = $configuration;
59
    $this->dispatcher = $configuration->getEventDispatcher();
60
    $this->cache = $cache;
61
 
62
    if (isset($options['culture']))
63
    {
64
      $this->setCulture($options['culture']);
65
      unset($options['culture']);
66
    }
67
 
68
    $this->options = array_merge(array(
69
      'source'              => 'XLIFF',
70
      'debug'               => false,
71
      'database'            => 'default',
72
      'untranslated_prefix' => '[T]',
73
      'untranslated_suffix' => '[/T]',
74
    ), $options);
75
 
76
    $this->dispatcher->connect('user.change_culture', array($this, 'listenToChangeCultureEvent'));
77
 
78
    if($this->isMessageSourceFileBased($this->options['source']))
79
    {
80
      $this->dispatcher->connect('controller.change_action', array($this, 'listenToChangeActionEvent'));
81
    }
82
  }
83
 
84
  /**
85
   * Returns the initialization options
86
   *
87
   * @return array The options used to initialize sfI18n
88
   */
89
  public function getOptions()
90
  {
91
    return $this->options;
92
  }
93
 
94
  /**
95
   * Returns the configuration instance.
96
   *
97
   * @return sfApplicationConfiguration An sfApplicationConfiguration instance
98
   */
99
  public function getConfiguration()
100
  {
101
    return $this->configuration;
102
  }
103
 
104
  /**
105
   * Sets the message source.
106
   *
107
   * @param mixed  $dirs    An array of i18n directories if message source is a sfMessageSource_File subclass, null otherwise
108
   * @param string $culture The culture
109
   */
110
  public function setMessageSource($dirs, $culture = null)
111
  {
112
    if (null === $dirs)
113
    {
114
      $this->messageSource = $this->createMessageSource();
115
    }
116
    else
117
    {
118
      $this->messageSource = sfMessageSource::factory('Aggregate', array_map(array($this, 'createMessageSource'), $dirs));
119
    }
120
 
121
    if (null !== $this->cache)
122
    {
123
      $this->messageSource->setCache($this->cache);
124
    }
125
 
126
    if (null !== $culture)
127
    {
128
      $this->setCulture($culture);
129
    }
130
    else
131
    {
132
      $this->messageSource->setCulture($this->culture);
133
    }
134
 
135
    $this->messageFormat = null;
136
  }
137
 
138
  /**
139
   * Returns a new message source.
140
   *
141
   * @param  mixed $dir An array of i18n directories to create a XLIFF or gettext message source, null otherwise
142
   *
143
   * @return sfMessageSource A sfMessageSource object
144
   */
145
  public function createMessageSource($dir = null)
146
  {
147
    return sfMessageSource::factory($this->options['source'], self::isMessageSourceFileBased($this->options['source']) ? $dir : $this->options['database']);
148
  }
149
 
150
  /**
151
   * Gets the current culture for i18n format objects.
152
   *
153
   * @return string The culture
154
   */
155
  public function getCulture()
156
  {
157
    return $this->culture;
158
  }
159
 
160
  /**
161
   * Sets the current culture for i18n format objects.
162
   *
163
   * @param string $culture The culture
164
   */
165
  public function setCulture($culture)
166
  {
167
    $this->culture = $culture;
168
 
169
    // change user locale for formatting, collation, and internal error messages
170
    setlocale(LC_ALL, 'en_US.utf8', 'en_US.UTF8', 'en_US.utf-8', 'en_US.UTF-8');
171
    setlocale(LC_COLLATE, $culture.'.utf8', $culture.'.UTF8', $culture.'.utf-8', $culture.'.UTF-8');
172
    setlocale(LC_CTYPE, $culture.'.utf8', $culture.'.UTF8', $culture.'.utf-8', $culture.'.UTF-8');
173
    setlocale(LC_MONETARY, $culture.'.utf8', $culture.'.UTF8', $culture.'.utf-8', $culture.'.UTF-8');
174
    setlocale(LC_TIME, $culture.'.utf8', $culture.'.UTF8', $culture.'.utf-8', $culture.'.UTF-8');
175
 
176
    if ($this->messageSource)
177
    {
178
      $this->messageSource->setCulture($culture);
179
      $this->messageFormat = null;
180
    }
181
  }
182
 
183
  /**
184
   * Gets the message source.
185
   *
186
   * @return sfMessageSource A sfMessageSource object
187
   */
188
  public function getMessageSource()
189
  {
190
    if (!isset($this->messageSource))
191
    {
192
      $dirs = ($this->isMessageSourceFileBased($this->options['source'])) ? $this->configuration->getI18NGlobalDirs() : null;
193
      $this->setMessageSource($dirs, $this->culture);
194
    }
195
 
196
    return $this->messageSource;
197
  }
198
 
199
  /**
200
   * Gets the message format.
201
   *
202
   * @return sfMessageFormat A sfMessageFormat object
203
   */
204
  public function getMessageFormat()
205
  {
206
    if (!isset($this->messageFormat))
207
    {
208
      $this->messageFormat = new sfMessageFormat($this->getMessageSource(), sfConfig::get('sf_charset'));
209
 
210
      if ($this->options['debug'])
211
      {
212
        $this->messageFormat->setUntranslatedPS(array($this->options['untranslated_prefix'], $this->options['untranslated_suffix']));
213
      }
214
    }
215
 
216
    return $this->messageFormat;
217
  }
218
 
219
  /**
220
   * Gets the translation for the given string
221
   *
222
   * @param  string $string     The string to translate
223
   * @param  array  $args       An array of arguments for the translation
224
   * @param  string $catalogue  The catalogue name
225
   *
226
   * @return string The translated string
227
   */
228
  public function __($string, $args = array(), $catalogue = 'messages')
229
  {
230
    return $this->getMessageFormat()->format($string, $args, $catalogue);
231
  }
232
 
233
  /**
234
   * Gets a country name.
235
   *
236
   * @param  string $iso      The ISO code
237
   * @param  string $culture  The culture for the translation
238
   *
239
   * @return string The country name
240
   */
241
  public function getCountry($iso, $culture = null)
242
  {
243
    $c = sfCultureInfo::getInstance(null === $culture ? $this->culture : $culture);
244
    $countries = $c->getCountries();
245
 
246
    return (array_key_exists($iso, $countries)) ? $countries[$iso] : '';
247
  }
248
 
249
  /**
250
   * Gets a native culture name.
251
   *
252
   * @param  string $culture The culture
253
   *
254
   * @return string The culture name
255
   */
256
  public function getNativeName($culture)
257
  {
258
    return sfCultureInfo::getInstance($culture)->getNativeName();
259
  }
260
 
261
  /**
262
   * Returns a timestamp from a date with time formatted with a given culture.
263
   *
264
   * @param  string  $dateTime  The formatted date with time as string
265
   * @param  string  $culture The culture
266
   *
267
   * @return integer The timestamp
268
   */
269
  public function getTimestampForCulture($dateTime, $culture = null)
270
  {
271
    list($day, $month, $year) = $this->getDateForCulture($dateTime, null === $culture ? $this->culture : $culture);
272
    list($hour, $minute) = $this->getTimeForCulture($dateTime, null === $culture ? $this->culture : $culture);
273
 
274
    return null === $day ? null : mktime($hour, $minute, 0, $month, $day, $year);
275
  }
276
 
277
  /**
278
   * Returns the day, month and year from a date formatted with a given culture.
279
   *
280
   * @param  string  $date    The formatted date as string
281
   * @param  string  $culture The culture
282
   *
283
   * @return array   An array with the day, month and year
284
   */
285
  public function getDateForCulture($date, $culture = null)
286
  {
287
    if (!$date)
288
    {
289
      return null;
290
    }
291
 
292
    $dateFormatInfo = @sfDateTimeFormatInfo::getInstance(null === $culture ? $this->culture : $culture);
293
    $dateFormat = $dateFormatInfo->getShortDatePattern();
294
 
295
    // We construct the regexp based on date format
296
    $dateRegexp = preg_replace('/[dmy]+/i', '(\d+)', preg_quote($dateFormat));
297
 
298
    // We parse date format to see where things are (m, d, y)
299
    $a = array(
300
      'd' => strpos($dateFormat, 'd'),
301
      'm' => strpos($dateFormat, 'M'),
302
      'y' => strpos($dateFormat, 'y'),
303
    );
304
    $tmp = array_flip($a);
305
    ksort($tmp);
306
    $i = 0;
307
    $c = array();
308
    foreach ($tmp as $value) $c[++$i] = $value;
309
    $datePositions = array_flip($c);
310
 
311
    // We find all elements
312
    if (preg_match("~$dateRegexp~", $date, $matches))
313
    {
314
      // We get matching timestamp
315
      return array($matches[$datePositions['d']], $matches[$datePositions['m']], $matches[$datePositions['y']]);
316
    }
317
    else
318
    {
319
      return null;
320
    }
321
  }
322
 
323
  /**
324
   * Returns the hour, minute from a date formatted with a given culture.
325
   *
326
   * @param  string  $time    The formatted date as string
327
   * @param  string  $culture The culture
328
   *
329
   * @return array   An array with the hour and minute
330
   */
331
  public function getTimeForCulture($time, $culture = null)
332
  {
333
    if (!$time) return 0;
334
 
335
    $culture = null === $culture ? $this->culture : $culture;
336
 
337
    $timeFormatInfo = @sfDateTimeFormatInfo::getInstance($culture);
338
    $timeFormat = $timeFormatInfo->getShortTimePattern();
339
 
340
    // We construct the regexp based on time format
341
    $timeRegexp = preg_replace(array('/[hm]+/i', '/a/'), array('(\d+)', '(\w+)'), preg_quote($timeFormat));
342
 
343
    // We parse time format to see where things are (h, m)
344
    $timePositions = array(
345
      'h' => strpos($timeFormat, 'H') !== false ? strpos($timeFormat, 'H') : strpos($timeFormat, 'h'),
346
      'm' => strpos($timeFormat, 'm'),
347
      'a' => strpos($timeFormat, 'a')
348
    );
349
    asort($timePositions);
350
    $i = 0;
351
 
352
    // normalize positions to 0, 1, ...
353
    // positions that don't exist in the pattern remain false
354
    foreach ($timePositions as $key => $value)
355
    {
356
      if ($value !== false)
357
      {
358
        $timePositions[$key] = ++$i;
359
      }
360
    }
361
 
362
    // We find all elements
363
    if (preg_match("~$timeRegexp~", $time, $matches))
364
    {
365
      // repect am/pm setting if present
366
      if ($timePositions['a'] !== false)
367
      {
368
        if (strcasecmp($matches[$timePositions['a']], $timeFormatInfo->getAMDesignator()) == 0)
369
        {
370
          $hour = $matches[$timePositions['h']];
371
        }
372
        else if (strcasecmp($matches[$timePositions['a']], $timeFormatInfo->getPMDesignator()) == 0)
373
        {
374
          $hour = $matches[$timePositions['h']] + 12;
375
        }
376
        else
377
        {
378
          // am/pm marker is invalid
379
          // return null; would be the preferred solution but this might break a lot of code
380
          $hour = $matches[$timePositions['h']];
381
        }
382
      }
383
      else
384
      {
385
        $hour = $matches[$timePositions['h']];
386
      }
387
 
388
      // We get matching timestamp
389
      return array($hour, $matches[$timePositions['m']]);
390
    }
391
    else
392
    {
393
      return null;
394
    }
395
  }
396
 
397
  /**
398
   * Returns true if messages are stored in a file.
399
   *
400
   * @param  string  $source  The source name
401
   *
402
   * @return Boolean true if messages are stored in a file, false otherwise
403
   */
404
  static public function isMessageSourceFileBased($source)
405
  {
406
    $class = 'sfMessageSource_'.$source;
407
 
408
    return class_exists($class) && is_subclass_of($class, 'sfMessageSource_File');
409
  }
410
 
411
  /**
412
   * Listens to the user.change_culture event.
413
   *
414
   * @param sfEvent $event  An sfEvent instance
415
   *
416
   */
417
  public function listenToChangeCultureEvent(sfEvent $event)
418
  {
419
    // change the message format object with the new culture
420
    $this->setCulture($event['culture']);
421
  }
422
 
423
  /**
424
   * Listens to the controller.change_action event.
425
   *
426
   * @param sfEvent $event An sfEvent instance
427
   *
428
   */
429
  public function listenToChangeActionEvent(sfEvent $event)
430
  {
431
    // change message source directory to our module
432
    $this->setMessageSource($this->configuration->getI18NDirs($event['module']));
433
  }
434
 
435
}