Development

/branches/1.1/lib/i18n/sfI18N.class.php

You must first sign up to be able to contribute.

root/branches/1.1/lib/i18n/sfI18N.class.php

Revision 13482, 11.4 kB (checked in by fabien, 6 years ago)

[1.1, 1.2] fixed i18n setlocale() problem (closes #)

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Rev Date
Line 
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$
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->culture = $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 (is_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 (!is_null($this->cache))
122     {
123       $this->messageSource->setCache($this->cache);
124     }
125
126     if (!is_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(is_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, is_null($culture) ? $this->culture : $culture);
272     list($hour, $minute) = $this->getTimeForCulture($dateTime, is_null($culture) ? $this->culture : $culture);
273
274     return is_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(is_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+)', $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  $date    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)
332   {
333     if (!$time) return 0;
334
335     $culture = is_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', '/[hm]+/i'), array('', '(\d+)'), $timeFormat);
342
343     // We parse time format to see where things are (h, m)
344     $a = array(
345       'h' => strpos($timeFormat, 'H') !== false ? strpos($timeFormat, 'H') : strpos($timeFormat, 'h'),
346       'm' => strpos($timeFormat, 'm')
347     );
348     $tmp = array_flip($a);
349     ksort($tmp);
350     $i = 0;
351     $c = array();
352     foreach ($tmp as $value) $c[++$i] = $value;
353     $timePositions = array_flip($c);
354
355     // We find all elements
356     if (preg_match("~$timeRegexp~", $time, $matches))
357     {
358       // We get matching timestamp
359       return array($matches[$timePositions['h']], $matches[$timePositions['m']]);
360     }
361     else
362     {
363       return null;
364     }
365   }
366
367   /**
368    * Returns true if messages are stored in a file.
369    *
370    * @param  string  $source  The source name
371    *
372    * @return Boolean true if messages are stored in a file, false otherwise
373    */
374   static public function isMessageSourceFileBased($source)
375   {
376     $class = 'sfMessageSource_'.$source;
377
378     return class_exists($class) && is_subclass_of($class, 'sfMessageSource_File');
379   }
380
381   /**
382    * Listens to the user.change_culture event.
383    *
384    * @param sfEvent $event  An sfEvent instance
385    *
386    */
387   public function listenToChangeCultureEvent(sfEvent $event)
388   {
389     // change the message format object with the new culture
390     $this->setCulture($event['culture']);
391   }
392
393   /**
394    * Listens to the controller.change_action event.
395    *
396    * @param sfEvent $event An sfEvent instance
397    *
398    */
399   public function listenToChangeActionEvent(sfEvent $event)
400   {
401     // change message source directory to our module
402     $this->setMessageSource($this->configuration->getI18NDirs($event['module']));
403   }
404
405 }
406
Note: See TracBrowser for help on using the browser.