src/Duality/Service/Localization.php
<?php
/**
* Localization service
*
* PHP Version 5.3.4
*
* @author Marco Afonso <mafonso333@gmail.com>
* @license http://opensource.org/licenses/MIT MIT
* @link http://github.com/taviroquai/duality
* @since 0.7.0
*/
namespace Duality\Service;
use Duality\Core\DualityException;
use Duality\Core\AbstractService;
use Duality\Core\InterfaceLocalization;
use Duality\Structure\Storage;
/**
* Default localization service
*
* Provides functionality for localization operations
*
* PHP Version 5.3.4
*
* @author Marco Afonso <mafonso333@gmail.com>
* @license http://opensource.org/licenses/MIT MIT
* @link http://github.com/taviroquai/duality
* @since 0.7.0
*/
class Localization
extends AbstractService
implements InterfaceLocalization
{
/**
* Holds the directory for translations
*
* @var string Holds the base directory for translations
*/
protected $directory = './data/lang/';
/**
* Holds the messages storage
*
* @var \Duality\Core\InterfaceStorage Holds the translation messages
*/
protected $storage;
/**
* Holds the current iso localization parameters
*
* @var string Holds the current locale string
*/
protected $current;
/**
* Holds the number formatter
*
* @var \NumberFormatter Holds the locale number formater
*/
protected $numberFormatter;
/**
* Holds the date/time formatter
*
* @var \IntlDateFormatter Holds the locale date formatter
*/
protected $datetimeFormatter;
/**
* Holds the calendar
* TODO: Release 2.0 (PHP5.5)
*
* @var \IntlCalendar Holds the locale calendar
*/
protected $calendar;
/**
* Holds the time zone
* TODO: Release 2.0 (PHP5.5)
*
* @var \IntlTimeZone Holds the current timezone
*/
protected $timezone;
/**
* Initiates the service
*
* @return void
*/
public function init()
{
if (!extension_loaded('intl')) {
throw new DualityException(
"Error: intl extension not loaded",
DualityException::E_EXTENSION_NOTFOUND
);
}
$this->storage = new Storage;
$this->storage->reset();
if ($this->app->getConfigItem('locale.default') == null) {
throw new DualityException(
"Error: locale configuration missing",
DualityException::E_CONFIG_NOTFOUND
);
}
$this->directory = $this->app->getPath()
. DIRECTORY_SEPARATOR
. $this->directory;
if ($this->app->getConfigItem('locale.dir')) {
$this->directory = $this->app->getPath()
. DIRECTORY_SEPARATOR
. $this->app->getConfigItem('locale.dir');
}
if (!is_dir($this->directory) || !is_readable($this->directory)) {
throw new DualityException(
"Error: directory not readable: " . $this->directory,
DualityException::E_FILE_NOTWRITABLE
);
}
$timezone = null;
if ($this->app->getConfigItem('locale.timezone')) {
$timezone = $this->app->getConfigItem('locale.timezone');
}
$this->current = $this->app->getConfigItem('locale.default');
$this->setLocale($this->current, $timezone);
}
/**
* Terminates the service
*
* @return void
*/
public function terminate()
{
}
/**
* Loads all locale settings
*
* @param string $code Give the locale code
* @param string $timezone Give the timezone string
*
* @return void
*/
public function setLocale($code, $timezone = 'Europe/Lisbon')
{
$this->current = \Locale::canonicalize($code);
// Validate locale and translations directory
$directory = $this->directory
. DIRECTORY_SEPARATOR
. $this->current;
if ($this->current === null || !is_dir($directory)) {
$this->current = \Locale::canonicalize(
$this->app->getConfigItem('locale.default')
);
}
// Validate messages file
$directory = $this->directory
. DIRECTORY_SEPARATOR
. $this->current;
if (!file_exists($directory.DIRECTORY_SEPARATOR.'messages.php')) {
throw new DualityException(
"Error locale: invalid messages file ".$this->current,
DualityException::E_FILE_NOTFOUND
);
}
// Define default locale
\Locale::setDefault($this->current);
$this->storage->importArray(
include($directory.DIRECTORY_SEPARATOR.'messages.php')
);
// Create a number formater
$this->numberFormatter = \NumberFormatter::create(
$this->current, \NumberFormatter::DECIMAL
);
// Create a time zone
// TODO: Release 2.0 (PHP5.5)
//$this->timezone = \IntlTimeZone::createTimeZone($timezone);
// Create a calendar
// TODO: Release 2.0 (PHP5.5)
/*
$this->calendar = \IntlCalendar::createInstance(
$this->timezone, $this->current
);
*/
// Create a DateTimeFormater
$this->datetimeFormatter = new \IntlDateFormatter(
$this->current,
\IntlDateFormatter::FULL,
\IntlDateFormatter::FULL,
$timezone,
\IntlDateFormatter::GREGORIAN
);
}
/**
* Returns the current language display name
*
* @return string The locale language to display
*/
public function getDisplayLanguage()
{
return \Locale::getDisplayLanguage($this->current, $this->current);
}
/**
* Returns a formated number
*
* @param int $value Give the number to format
* @param int $style Give the constant \NumberFormatter style
* @param string $pattern Give pattern if required by style parameter
*
* @return string The resulting string
*/
public function getNumber(
$value,
$style = \NumberFormatter::DECIMAL,
$pattern = null
) {
$this->numberFormatter = \NumberFormatter::create(
$this->current, $style, $pattern
);
return $this->getNumberFormatter()->format($value);
}
/**
* Returns a real number
*
* @param string $value The string to parse
* @param int $type The type of format as \NumberFormatter
*
* @return int The resulting number
*/
public function parseNumber(
$value,
$type = \NumberFormatter::TYPE_DOUBLE
) {
return $this->getNumberFormatter()->parse($value, $type);
}
/**
* Returns a formated currency
*
* @param float $value The number to format
* @param string $currency The target currency to format
*
* @return string The resulting string
*/
public function getCurrency($value, $currency = 'EUR')
{
$this->numberFormatter = \NumberFormatter::create(
$this->current, \NumberFormatter::CURRENCY
);
return $this->getNumberFormatter()->formatCurrency($value, $currency);
}
/**
* Returns the number formatter
*
* @return \NumberFormatter The current number formatter instance
*/
public function getNumberFormatter()
{
return $this->numberFormatter;
}
/**
* Returns the date/time formatter
*
* @return \IntlDateFormatter The current date formatter instance
*/
public function getDateFormatter()
{
return $this->datetimeFormatter;
}
/**
* Returns the calendar
* TODO: Release 2.0 (PHP5.5)
*
* @return \IntlCalendar The current calendar instance
*/
public function getCalendar()
{
return $this->calendar;
}
/**
* Returns the time zone
* TODO: Release 2.0 (PHP5.5)
*
* @return \IntlTimeZone The current timezone instance
*/
public function getTimeZone()
{
return $this->timezone;
}
/**
* Returns translated string
*
* @param string $key The key to translate
* @param array $params The string values to passe in
* @param string $target The target locale string if diferent than current
*
* @return string The resulting string
*/
public function translate($key, $params = array(), $target = null)
{
// Load defauts
$current = $this->current;
$directory = $this->directory.DIRECTORY_SEPARATOR.$current;
$params = (array) $params;
// Validate and load different $target
if (!empty($target) && $target != $current) {
$current = $target;
$directory = $this->directory.DIRECTORY_SEPARATOR.$current;
// Validate locale and translations directory
if (\Locale::canonicalize($current) === null
|| !is_dir($this->directory.DIRECTORY_SEPARATOR.$current)
) {
throw new DualityException(
"Error Locale: target code ",
DualityException::E_LOCALE_NOTFOUND
);
}
}
// Finally, return result
$storage = new Storage;
$storage->importArray(
include($directory.DIRECTORY_SEPARATOR.'messages.php')
);
return \MessageFormatter::formatMessage(
$current, $storage->get($key), $params
);
}
/**
* Translate alias
*
* @param string $key Give the message key
* @param array $params Give the message values
* @param string $target Give the target locale
*
* @return string The translated message
*/
public function t($key, $params = array(), $target = null)
{
return $this->translate($key, $params, $target);
}
}