Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/*** CultureInfo class file.** This program is free software; you can redistribute it and/or modify* it under the terms of the BSD License.** Copyright(c) 2004 by Qiang Xue. All rights reserved.** To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}* The latest version of PRADO can be obtained from:* {@link http://prado.sourceforge.net/}** @author Wei Zhuo <weizhuo[at]gmail[dot]com>* @version $Id: CultureInfo.php 2541 2008-10-21 15:05:13Z qiang.xue $* @package System.I18N.core*//*** CultureInfo class.** Represents information about a specific culture including the* names of the culture, the calendar used, as well as access to* culture-specific objects that provide methods for common operations,* such as formatting dates, numbers, and currency.** The CultureInfo class holds culture-specific information, such as the* associated language, sublanguage, country/region, calendar, and cultural* conventions. This class also provides access to culture-specific* instances of DateTimeFormatInfo and NumberFormatInfo. These objects* contain the information required for culture-specific operations,* such as formatting dates, numbers and currency.** The culture names follow the format "<languagecode>_<country/regioncode>",* where <languagecode> is a lowercase two-letter code derived from ISO 639* codes. You can find a full list of the ISO-639 codes at* http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt** The <country/regioncode2> is an uppercase two-letter code derived from* ISO 3166. A copy of ISO-3166 can be found at* http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html** For example, Australian English is "en_AU".** @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>* @version $Id: CultureInfo.php 2541 2008-10-21 15:05:13Z qiang.xue $* @package System.I18N.core*/class CultureInfo{/*** ICU data filename extension.* @var string*/private $dataFileExt = '.dat';/*** The ICU data array.* @var array*/private $data = array();/*** The current culture.* @var string*/private $culture;/*** Directory where the ICU data is stored.* @var string*/private $dataDir;/*** A list of ICU date files loaded.* @var array*/private $dataFiles = array();/*** The current date time format info.* @var DateTimeFormatInfo*/private $dateTimeFormat;/*** The current number format info.* @var NumberFormatInfo*/private $numberFormat;/*** A list of properties that are accessable/writable.* @var array*/protected $properties = array();/*** Culture type, all.* @see getCultures()* @var int*/const ALL = 0;/*** Culture type, neutral.* @see getCultures()* @var int*/const NEUTRAL = 1;/*** Culture type, specific.* @see getCultures()* @var int*/const SPECIFIC = 2;/*** Display the culture name.* @return string the culture name.* @see getName()*/function __toString(){return $this->getName();}/*** Allow functions that begins with 'set' to be called directly* as an attribute/property to retrieve the value.* @return mixed*/function __get($name){$getProperty = 'get'.$name;if(in_array($getProperty, $this->properties))return $this->$getProperty();elsethrow new Exception('Property '.$name.' does not exists.');}/*** Allow functions that begins with 'set' to be called directly* as an attribute/property to set the value.*/function __set($name, $value){$setProperty = 'set'.$name;if(in_array($setProperty, $this->properties))$this->$setProperty($value);elsethrow new Exception('Property '.$name.' can not be set.');}/*** Initializes a new instance of the CultureInfo class based on the* culture specified by name. E.g. <code>new CultureInfo('en_AU');</cdoe>* The culture indentifier must be of the form* "language_(country/region/variant)".* @param string a culture name, e.g. "en_AU".* @return return new CultureInfo.*/function __construct($culture='en'){$this->properties = get_class_methods($this);if(empty($culture))$culture = 'en';$this->dataDir = $this->dataDir();$this->dataFileExt = $this->fileExt();$this->setCulture($culture);$this->loadCultureData('root');$this->loadCultureData($culture);}/*** Get the default directory for the ICU data.* The default is the "data" directory for this class.* @return string directory containing the ICU data.*/protected static function dataDir(){return dirname(__FILE__).'/data/';}/*** Get the filename extension for ICU data. Default is ".dat".* @return string filename extension for ICU data.*/protected static function fileExt(){return '.dat';}/*** Gets the CultureInfo that for this culture string* @return CultureInfo invariant culture info is "en".*/public static function getInstance($culture){static $instances = array();if(!isset($instances[$culture]))$instances[$culture] = new CultureInfo($culture);return $instances[$culture];}/*** Determine if a given culture is valid. Simply checks that the* culture data exists.* @param string a culture* @return boolean true if valid, false otherwise.*/public function validCulture($culture){if(preg_match('/^[_\\w]+$/', $culture))return is_file(self::dataDir().$culture.self::fileExt());return false;}/*** Set the culture for the current instance. The culture indentifier* must be of the form "<language>_(country/region)".* @param string culture identifier, e.g. "fr_FR_EURO".*/protected function setCulture($culture){if(!empty($culture)){if (!preg_match('/^[_\\w]+$/', $culture))throw new Exception('Invalid culture supplied: ' . $culture);}$this->culture = $culture;}/*** Load the ICU culture data for the specific culture identifier.* @param string the culture identifier.*/protected function loadCultureData($culture){$file_parts = explode('_',$culture);$current_part = $file_parts[0];$files = array($current_part);for($i = 1, $k = count($file_parts); $i < $k; ++$i){$current_part .= '_'.$file_parts[$i];$files[] = $current_part;}foreach($files as $file){$filename = $this->dataDir.$file.$this->dataFileExt;if(is_file($filename) == false)throw new Exception('Data file for "'.$file.'" was not found.');if(in_array($filename, $this->dataFiles) === false){array_unshift($this->dataFiles, $file);$data = &$this->getData($filename);$this->data[$file] = &$data;if(isset($data['__ALIAS']))$this->loadCultureData($data['__ALIAS'][0]);unset($data);}}}/*** Get the data by unserializing the ICU data from disk.* The data files are cached in a static variable inside* this function.* @param string the ICU data filename* @return array ICU data*/protected function &getData($filename){static $data = array();static $files = array();if(!in_array($filename, $files)){$data[$filename] = unserialize(file_get_contents($filename));$files[] = $filename;}return $data[$filename];}/*** Find the specific ICU data information from the data.* The path to the specific ICU data is separated with a slash "/".* E.g. To find the default calendar used by the culture, the path* "calendar/default" will return the corresponding default calendar.* Use merge=true to return the ICU including the parent culture.* E.g. The currency data for a variant, say "en_AU" contains one* entry, the currency for AUD, the other currency data are stored* in the "en" data file. Thus to retrieve all the data regarding* currency for "en_AU", you need to use findInfo("Currencies,true);.* @param string the data you want to find.* @param boolean merge the data from its parents.* @return mixed the specific ICU data.*/protected function findInfo($path='/', $merge=false){$result = array();foreach($this->dataFiles as $section){$info = $this->searchArray($this->data[$section], $path);if($info){if($merge)$result = array_merge($info,$result);elsereturn $info;}}return $result;}/*** Search the array for a specific value using a path separated using* slash "/" separated path. e.g to find $info['hello']['world'],* the path "hello/world" will return the corresponding value.* @param array the array for search* @param string slash "/" separated array path.* @return mixed the value array using the path*/private function searchArray($info, $path='/'){$index = explode('/',$path);$array = $info;for($i = 0, $k = count($index); $i < $k; ++$i){$value = $index[$i];if($i < $k-1 && isset($array[$value]))$array = $array[$value];else if ($i == $k-1 && isset($array[$value]))return $array[$value];}}/*** Gets the culture name in the format* "<languagecode2>_(country/regioncode2)".* @return string culture name.*/function getName(){return $this->culture;}/*** Gets the DateTimeFormatInfo that defines the culturally appropriate* format of displaying dates and times.* @return DateTimeFormatInfo date time format information for the culture.*/function getDateTimeFormat(){if($this->dateTimeFormat === null){$calendar = $this->getCalendar();$info = $this->findInfo("calendar/{$calendar}", true);$this->setDateTimeFormat(new DateTimeFormatInfo($info));}return $this->dateTimeFormat;}/*** Set the date time format information.* @param DateTimeFormatInfo the new date time format info.*/function setDateTimeFormat($dateTimeFormat){$this->dateTimeFormat = $dateTimeFormat;}/*** Gets the default calendar used by the culture, e.g. "gregorian".* @return string the default calendar.*/function getCalendar(){$info = $this->findInfo('calendar/default');return $info[0];}/*** Gets the culture name in the language that the culture is set* to display. Returns <code>array('Language','Country');</code>* 'Country' is omitted if the culture is neutral.* @return array array with language and country as elements, localized.*/function getNativeName(){$lang = substr($this->culture,0,2);$reg = substr($this->culture,3,2);$language = $this->findInfo("Languages/{$lang}");$region = $this->findInfo("Countries/{$reg}");if($region)return $language[0].' ('.$region[0].')';elsereturn $language[0];}/*** Gets the culture name in English.* Returns <code>array('Language','Country');</code>* 'Country' is omitted if the culture is neutral.* @return string language (country), it may locale code string if english name does not exist.*/function getEnglishName(){$lang = substr($this->culture,0,2);$reg = substr($this->culture,3,2);$culture = $this->getInvariantCulture();$language = $culture->findInfo("Languages/{$lang}");if(count($language) == 0)return $this->culture;$region = $culture->findInfo("Countries/{$reg}");if($region)return $language[0].' ('.$region[0].')';elsereturn $language[0];}/*** Gets the CultureInfo that is culture-independent (invariant).* Any changes to the invariant culture affects all other* instances of the invariant culture.* The invariant culture is assumed to be "en";* @return CultureInfo invariant culture info is "en".*/static function getInvariantCulture(){static $invariant;if($invariant === null)$invariant = new CultureInfo();return $invariant;}/*** Gets a value indicating whether the current CultureInfo* represents a neutral culture. Returns true if the culture* only contains two characters.* @return boolean true if culture is neutral, false otherwise.*/function getIsNeutralCulture(){return strlen($this->culture) == 2;}/*** Gets the NumberFormatInfo that defines the culturally appropriate* format of displaying numbers, currency, and percentage.* @return NumberFormatInfo the number format info for current culture.*/function getNumberFormat(){if($this->numberFormat === null){$elements = $this->findInfo('NumberElements');$patterns = $this->findInfo('NumberPatterns');$currencies = $this->getCurrencies();$data = array( 'NumberElements'=>$elements,'NumberPatterns'=>$patterns,'Currencies' => $currencies);$this->setNumberFormat(new NumberFormatInfo($data));}return $this->numberFormat;}/*** Set the number format information.* @param NumberFormatInfo the new number format info.*/function setNumberFormat($numberFormat){$this->numberFormat = $numberFormat;}/*** Gets the CultureInfo that represents the parent culture of the* current CultureInfo* @return CultureInfo parent culture information.*/function getParent(){if(strlen($this->culture) == 2)return $this->getInvariantCulture();$lang = substr($this->culture,0,2);return new CultureInfo($lang);}/*** Gets the list of supported cultures filtered by the specified* culture type. This is an EXPENSIVE function, it needs to traverse* a list of ICU files in the data directory.* This function can be called statically.* @param int culture type, CultureInfo::ALL, CultureInfo::NEUTRAL* or CultureInfo::SPECIFIC.* @return array list of culture information available.*/static function getCultures($type=CultureInfo::ALL){$dataDir = CultureInfo::dataDir();$dataExt = CultureInfo::fileExt();$dir = dir($dataDir);$neutral = array();$specific = array();while (false !== ($entry = $dir->read())){if(is_file($dataDir.$entry)&& substr($entry,-4) == $dataExt&& $entry != 'root'.$dataExt){$culture = substr($entry,0,-4);if(strlen($culture) == 2)$neutral[] = $culture;else$specific[] = $culture;}}$dir->close();switch($type){case CultureInfo::ALL :$all = array_merge($neutral, $specific);sort($all);return $all;break;case CultureInfo::NEUTRAL :return $neutral;break;case CultureInfo::SPECIFIC :return $specific;break;}}/*** Simplify a single element array into its own value.* E.g. <code>array(0 => array('hello'), 1 => 'world');</code>* becomes <code>array(0 => 'hello', 1 => 'world');</code>* @param array with single elements arrays* @return array simplified array.*/private function simplify($array){for($i = 0, $k = count($array); $i<$k; ++$i){$key = key($array);if(is_array($array[$key])&& count($array[$key]) == 1)$array[$key] = $array[$key][0];next($array);}return $array;}/*** Get a list of countries in the language of the localized version.* @return array a list of localized country names.*/function getCountries(){return $this->simplify($this->findInfo('Countries',true));}/*** Get a list of currencies in the language of the localized version.* @return array a list of localized currencies.*/function getCurrencies(){return $this->findInfo('Currencies',true);}/*** Get a list of languages in the language of the localized version.* @return array list of localized language names.*/function getLanguages(){return $this->simplify($this->findInfo('Languages',true));}/*** Get a list of scripts in the language of the localized version.* @return array list of localized script names.*/function getScripts(){return $this->simplify($this->findInfo('Scripts',true));}/*** Get a list of timezones in the language of the localized version.* @return array list of localized timezones.*/function getTimeZones(){return $this->simplify($this->findInfo('zoneStrings',true));}}