[Intl] Refactored Locale component into two new components Icu and Intl
This commit is contained in:
parent
a7c9863b3a
commit
5917a2e0cb
|
@ -14,5 +14,3 @@ before_script:
|
|||
- echo '' > ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini
|
||||
- echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
- COMPOSER_ROOT_VERSION=dev-master composer --prefer-source --dev install
|
||||
- php src/Symfony/Component/Locale/Resources/data/build-data.php
|
||||
- export USE_INTL_ICU_DATA_VERSION=1
|
||||
|
|
|
@ -10,8 +10,4 @@ $loader = require_once __DIR__.'/vendor/autoload.php';
|
|||
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
|
||||
if (!function_exists('intl_get_error_code')) {
|
||||
require_once __DIR__.'/src/Symfony/Component/Locale/Resources/stubs/functions.php';
|
||||
}
|
||||
|
||||
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
],
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/icu": ">=1.0",
|
||||
"doctrine/common": "~2.2",
|
||||
"twig/twig": "~1.11",
|
||||
"psr/log": "~1.0"
|
||||
|
@ -37,6 +38,7 @@
|
|||
"symfony/framework-bundle": "self.version",
|
||||
"symfony/http-foundation": "self.version",
|
||||
"symfony/http-kernel": "self.version",
|
||||
"symfony/intl": "self.version",
|
||||
"symfony/locale": "self.version",
|
||||
"symfony/monolog-bridge": "self.version",
|
||||
"symfony/options-resolver": "self.version",
|
||||
|
@ -68,8 +70,9 @@
|
|||
"psr-0": { "Symfony\\": "src/" },
|
||||
"classmap": [
|
||||
"src/Symfony/Component/HttpFoundation/Resources/stubs",
|
||||
"src/Symfony/Component/Locale/Resources/stubs"
|
||||
]
|
||||
"src/Symfony/Component/Intl/Resources/stubs"
|
||||
],
|
||||
"files": [ "src/Symfony/Component/Intl/Resources/stubs/functions.php" ]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
|
@ -0,0 +1,91 @@
|
|||
Contributing to the Intl component
|
||||
==================================
|
||||
|
||||
A very good way of contributing to the Intl component is by updating the
|
||||
included data for the ICU version you have installed on your system.
|
||||
|
||||
Preparation
|
||||
-----------
|
||||
|
||||
To prepare, you need to install the development dependencies of the component.
|
||||
|
||||
$ cd /path/to/Symfony/Component/Intl
|
||||
$ composer.phar install --dev
|
||||
|
||||
Determining your ICU version
|
||||
---------------------------
|
||||
|
||||
The ICU version installed in your PHP environment can be found by running
|
||||
icu-version.php:
|
||||
|
||||
$ php Resources/bin/icu-version.php
|
||||
|
||||
Updating the ICU data
|
||||
---------------------
|
||||
|
||||
To update the data files, run the update-icu-component.php script:
|
||||
|
||||
$ php Resources/bin/update-icu-component.php
|
||||
|
||||
The script needs the binaries "svn" and "make" to be available on your system.
|
||||
It will download the latest version of the ICU sources for the ICU version
|
||||
installed in your PHP environment. The script will then compile the "genrb"
|
||||
binary and use it to compile the ICU data files to binaries. The binaries are
|
||||
copied to the Resources/ directory of the Icu component found in the
|
||||
vendor/symfony/icu/ directory.
|
||||
|
||||
Updating the stub data
|
||||
----------------------
|
||||
|
||||
In the previous step you updated the Icu component for the ICU version
|
||||
installed on your system. If you are using the latest ICU version, you should
|
||||
also create the stub data files which will be used by people who don't have
|
||||
the intl extension installed.
|
||||
|
||||
To update the stub files, run the update-stubs.php script:
|
||||
|
||||
$ php Resources/bin/update-stubs.php
|
||||
|
||||
The script will fail if you don't have the latest ICU version. If you want to
|
||||
upgrade the ICU version, adjust the return value of the
|
||||
`Intl::getStubIcuVersion()` before you run the script.
|
||||
|
||||
The script creates copies of the binary resource bundles in the Icu component
|
||||
and stores them in the Resources/ directory of the Intl component. The copies
|
||||
are made for the locale "en" only and are stored in .php files, so that they
|
||||
can be read even if the intl extension is not available.
|
||||
|
||||
Creating a pull request
|
||||
-----------------------
|
||||
|
||||
You need to create up to two pull requests:
|
||||
|
||||
* If you updated the Icu component, you need to push that change and create a
|
||||
pull request in the `symfony/Icu` repository. Make sure to submit the pull
|
||||
request to the correct master branch. If you updated the ICU data for version
|
||||
4.8, your pull request goes to branch `48-master`, for version 49 to
|
||||
`49-master` and so on.
|
||||
|
||||
* If you updated the stub files of the Intl component, you need to push that
|
||||
change and create a pull request in the `symfony/symfony` repository. The
|
||||
pull request should be based on the `master` branch.
|
||||
|
||||
Combining .res files to a .dat-package
|
||||
--------------------------------------
|
||||
|
||||
The individual *.res files can be combined into a single .dat-file.
|
||||
Unfortunately, PHP's `ResourceBundle` class is currently not able to handle
|
||||
.dat-files.
|
||||
|
||||
Once it is, the following steps have to be followed to build the .dat-file:
|
||||
|
||||
1. Package the resource bundles into a single file
|
||||
|
||||
$ find . -name *.res | sed -e "s/\.\///g" > packagelist.txt
|
||||
$ pkgdata -p region -T build -d . packagelist.txt
|
||||
|
||||
2. Clean up
|
||||
|
||||
$ rm -rf build packagelist.txt
|
||||
|
||||
3. You can now move region.dat to replace the version bundled with Symfony2.
|
|
@ -0,0 +1,284 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Collator;
|
||||
|
||||
use Symfony\Component\Intl\Exception\MethodNotImplementedException;
|
||||
use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException;
|
||||
use Symfony\Component\Intl\Globals\StubIntlGlobals;
|
||||
use Symfony\Component\Intl\Locale\StubLocale;
|
||||
|
||||
/**
|
||||
* Provides a stub Collator for the 'en' locale.
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class StubCollator
|
||||
{
|
||||
/** Attribute constants */
|
||||
const FRENCH_COLLATION = 0;
|
||||
const ALTERNATE_HANDLING = 1;
|
||||
const CASE_FIRST = 2;
|
||||
const CASE_LEVEL = 3;
|
||||
const NORMALIZATION_MODE = 4;
|
||||
const STRENGTH = 5;
|
||||
const HIRAGANA_QUATERNARY_MODE = 6;
|
||||
const NUMERIC_COLLATION = 7;
|
||||
|
||||
/** Attribute constants values */
|
||||
const DEFAULT_VALUE = -1;
|
||||
|
||||
const PRIMARY = 0;
|
||||
const SECONDARY = 1;
|
||||
const TERTIARY = 2;
|
||||
const DEFAULT_STRENGTH = 2;
|
||||
const QUATERNARY = 3;
|
||||
const IDENTICAL = 15;
|
||||
|
||||
const OFF = 16;
|
||||
const ON = 17;
|
||||
|
||||
const SHIFTED = 20;
|
||||
const NON_IGNORABLE = 21;
|
||||
|
||||
const LOWER_FIRST = 24;
|
||||
const UPPER_FIRST = 25;
|
||||
|
||||
/** Sorting options */
|
||||
const SORT_REGULAR = 0;
|
||||
const SORT_NUMERIC = 2;
|
||||
const SORT_STRING = 1;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $locale The locale code
|
||||
*
|
||||
* @throws MethodArgumentValueNotImplementedException When $locale different than 'en' is passed
|
||||
*/
|
||||
public function __construct($locale)
|
||||
{
|
||||
if ('en' != $locale) {
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the \'en\' locale is supported');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static constructor
|
||||
*
|
||||
* @param string $locale The locale code
|
||||
*
|
||||
* @return StubCollator
|
||||
*
|
||||
* @throws MethodArgumentValueNotImplementedException When $locale different than 'en' is passed
|
||||
*/
|
||||
public static function create($locale)
|
||||
{
|
||||
return new self($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort array maintaining index association
|
||||
*
|
||||
* @param array &$array Input array
|
||||
* @param integer $sortFlag Flags for sorting, can be one of the following:
|
||||
* StubCollator::SORT_REGULAR - compare items normally (don't change types)
|
||||
* StubCollator::SORT_NUMERIC - compare items numerically
|
||||
* StubCollator::SORT_STRING - compare items as strings
|
||||
*
|
||||
* @return Boolean True on success or false on failure
|
||||
*/
|
||||
public function asort(&$array, $sortFlag = self::SORT_REGULAR)
|
||||
{
|
||||
$intlToPlainFlagMap = array(
|
||||
self::SORT_REGULAR => \SORT_REGULAR,
|
||||
self::SORT_NUMERIC => \SORT_NUMERIC,
|
||||
self::SORT_STRING => \SORT_STRING,
|
||||
);
|
||||
|
||||
$plainSortFlag = isset($intlToPlainFlagMap[$sortFlag]) ? $intlToPlainFlagMap[$sortFlag] : self::SORT_REGULAR;
|
||||
|
||||
return asort($array, $plainSortFlag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two Unicode strings
|
||||
*
|
||||
* @param string $str1 The first string to compare
|
||||
* @param string $str2 The second string to compare
|
||||
*
|
||||
* @return Boolean|int Return the comparison result or false on failure:
|
||||
* 1 if $str1 is greater than $str2
|
||||
* 0 if $str1 is equal than $str2
|
||||
* -1 if $str1 is less than $str2
|
||||
*
|
||||
* @see http://www.php.net/manual/en/collator.compare.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function compare($str1, $str2)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value of an integer collator attribute
|
||||
*
|
||||
* @param int $attr An attribute specifier, one of the attribute constants
|
||||
*
|
||||
* @return Boolean|int The attribute value on success or false on error
|
||||
*
|
||||
* @see http://www.php.net/manual/en/collator.getattribute.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function getAttribute($attr)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns collator's last error code. Always returns the U_ZERO_ERROR class constant value
|
||||
*
|
||||
* @return int The error code from last collator call
|
||||
*/
|
||||
public function getErrorCode()
|
||||
{
|
||||
return StubIntlGlobals::U_ZERO_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns collator's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value
|
||||
*
|
||||
* @return string The error message from last collator call
|
||||
*/
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return 'U_ZERO_ERROR';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collator's locale
|
||||
*
|
||||
* @param int $type The locale name type to return between valid or actual (StubLocale::VALID_LOCALE or StubLocale::ACTUAL_LOCALE, respectively)
|
||||
*
|
||||
* @return string The locale name used to create the collator
|
||||
*/
|
||||
public function getLocale($type = StubLocale::ACTUAL_LOCALE)
|
||||
{
|
||||
return 'en';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sorting key for a string
|
||||
*
|
||||
* @param string $string The string to produce the key from
|
||||
*
|
||||
* @return string The collation key for $string
|
||||
*
|
||||
* @see http://www.php.net/manual/en/collator.getsortkey.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function getSortKey($string)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current collator's strength
|
||||
*
|
||||
* @return Boolean|int The current collator's strength or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/collator.getstrength.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function getStrength()
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a collator's attribute
|
||||
*
|
||||
* @param int $attr An attribute specifier, one of the attribute constants
|
||||
* @param int $val The attribute value, one of the attribute value constants
|
||||
*
|
||||
* @return Boolean True on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/collator.setattribute.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function setAttribute($attr, $val)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the collator's strength
|
||||
*
|
||||
* @param int $strength Strength to set, possible values:
|
||||
* StubCollator::PRIMARY
|
||||
* StubCollator::SECONDARY
|
||||
* StubCollator::TERTIARY
|
||||
* StubCollator::QUATERNARY
|
||||
* StubCollator::IDENTICAL
|
||||
* StubCollator::DEFAULT
|
||||
*
|
||||
* @return Boolean True on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/collator.setstrength.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function setStrength($strength)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort array using specified collator and sort keys
|
||||
*
|
||||
* @param array &$arr Array of strings to sort
|
||||
*
|
||||
* @return Boolean True on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/collator.sortwithsortkeys.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function sortWithSortKeys(&$arr)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort array using specified collator
|
||||
*
|
||||
* @param array &$arr Array of string to sort
|
||||
* @param int $sortFlag Optional sorting type, one of the following:
|
||||
* StubCollator::SORT_REGULAR
|
||||
* StubCollator::SORT_NUMERIC
|
||||
* StubCollator::SORT_STRING
|
||||
*
|
||||
* @return Boolean True on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/collator.sort.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function sort(&$arr, $sortFlag = self::SORT_REGULAR)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for AM/PM markers format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class AmPmTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
return $dateTime->format('A');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return 'AM|PM';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'marker' => $matched
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for day of week format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class DayOfWeekTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
$dayOfWeek = $dateTime->format('l');
|
||||
switch ($length) {
|
||||
case 4:
|
||||
return $dayOfWeek;
|
||||
case 5:
|
||||
return $dayOfWeek[0];
|
||||
default:
|
||||
return substr($dayOfWeek, 0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
switch ($length) {
|
||||
case 4:
|
||||
return 'Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday';
|
||||
case 5:
|
||||
return '[MTWFS]';
|
||||
default:
|
||||
return 'Mon|Tue|Wed|Thu|Fri|Sat|Sun';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for day of year format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class DayOfYearTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
$dayOfYear = $dateTime->format('z') + 1;
|
||||
|
||||
return $this->padLeft($dayOfYear, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return '\d{'.$length.'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for day format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class DayTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
return $this->padLeft($dateTime->format('j'), $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return 1 === $length ? '\d{1,2}' : '\d{'.$length.'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'day' => (int) $matched,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,356 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
use Symfony\Component\Intl\Exception\NotImplementedException;
|
||||
use Symfony\Component\Intl\Globals\StubIntlGlobals;
|
||||
use Symfony\Component\Intl\DateFormatter\DateFormat\MonthTransformer;
|
||||
|
||||
/**
|
||||
* Parser and formatter for date formats
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class FullTransformer
|
||||
{
|
||||
private $quoteMatch = "'(?:[^']+|'')*'";
|
||||
private $implementedChars = 'MLydQqhDEaHkKmsz';
|
||||
private $notImplementedChars = 'GYuwWFgecSAZvVW';
|
||||
private $regExp;
|
||||
|
||||
/**
|
||||
* @var Transformer[]
|
||||
*/
|
||||
private $transformers;
|
||||
|
||||
private $pattern;
|
||||
private $timezone;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $pattern The pattern to be used to format and/or parse values
|
||||
* @param string $timezone The timezone to perform the date/time calculations
|
||||
*/
|
||||
public function __construct($pattern, $timezone)
|
||||
{
|
||||
$this->pattern = $pattern;
|
||||
$this->timezone = $timezone;
|
||||
|
||||
$implementedCharsMatch = $this->buildCharsMatch($this->implementedChars);
|
||||
$notImplementedCharsMatch = $this->buildCharsMatch($this->notImplementedChars);
|
||||
$this->regExp = "/($this->quoteMatch|$implementedCharsMatch|$notImplementedCharsMatch)/";
|
||||
|
||||
$this->transformers = array(
|
||||
'M' => new MonthTransformer(),
|
||||
'L' => new MonthTransformer(),
|
||||
'y' => new YearTransformer(),
|
||||
'd' => new DayTransformer(),
|
||||
'q' => new QuarterTransformer(),
|
||||
'Q' => new QuarterTransformer(),
|
||||
'h' => new Hour1201Transformer(),
|
||||
'D' => new DayOfYearTransformer(),
|
||||
'E' => new DayOfWeekTransformer(),
|
||||
'a' => new AmPmTransformer(),
|
||||
'H' => new Hour2400Transformer(),
|
||||
'K' => new Hour1200Transformer(),
|
||||
'k' => new Hour2401Transformer(),
|
||||
'm' => new MinuteTransformer(),
|
||||
's' => new SecondTransformer(),
|
||||
'z' => new TimeZoneTransformer(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array of Transformer objects
|
||||
*
|
||||
* @return Transformer[] Associative array of Transformer objects (format char => Transformer)
|
||||
*/
|
||||
public function getTransformers()
|
||||
{
|
||||
return $this->transformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a DateTime using ICU dateformat pattern
|
||||
*
|
||||
* @param \DateTime $dateTime A DateTime object to be used to generate the formatted value
|
||||
*
|
||||
* @return string The formatted value
|
||||
*/
|
||||
public function format(\DateTime $dateTime)
|
||||
{
|
||||
$that = $this;
|
||||
|
||||
$formatted = preg_replace_callback($this->regExp, function($matches) use ($that, $dateTime) {
|
||||
return $that->formatReplace($matches[0], $dateTime);
|
||||
}, $this->pattern);
|
||||
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the formatted ICU value for the matched date characters
|
||||
*
|
||||
* @param string $dateChars The date characters to be replaced with a formatted ICU value
|
||||
* @param DateTime $dateTime A DateTime object to be used to generate the formatted value
|
||||
*
|
||||
* @return string The formatted value
|
||||
*
|
||||
* @throws NotImplementedException When it encounters a not implemented date character
|
||||
*/
|
||||
public function formatReplace($dateChars, $dateTime)
|
||||
{
|
||||
$length = strlen($dateChars);
|
||||
|
||||
if ($this->isQuoteMatch($dateChars)) {
|
||||
return $this->replaceQuoteMatch($dateChars);
|
||||
}
|
||||
|
||||
if (isset($this->transformers[$dateChars[0]])) {
|
||||
$transformer = $this->transformers[$dateChars[0]];
|
||||
|
||||
return $transformer->format($dateTime, $length);
|
||||
}
|
||||
|
||||
// handle unimplemented characters
|
||||
if (false !== strpos($this->notImplementedChars, $dateChars[0])) {
|
||||
throw new NotImplementedException(sprintf("Unimplemented date character '%s' in format '%s'", $dateChars[0], $this->pattern));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a pattern based string to a timestamp value
|
||||
*
|
||||
* @param \DateTime $dateTime A configured DateTime object to use to perform the date calculation
|
||||
* @param string $value String to convert to a time value
|
||||
*
|
||||
* @return int The corresponding Unix timestamp
|
||||
*
|
||||
* @throws \InvalidArgumentException When the value can not be matched with pattern
|
||||
*/
|
||||
public function parse(\DateTime $dateTime, $value)
|
||||
{
|
||||
$reverseMatchingRegExp = $this->getReverseMatchingRegExp($this->pattern);
|
||||
$reverseMatchingRegExp = '/^'.$reverseMatchingRegExp.'$/';
|
||||
|
||||
$options = array();
|
||||
|
||||
if (preg_match($reverseMatchingRegExp, $value, $matches)) {
|
||||
$matches = $this->normalizeArray($matches);
|
||||
|
||||
foreach ($this->transformers as $char => $transformer) {
|
||||
if (isset($matches[$char])) {
|
||||
$length = strlen($matches[$char]['pattern']);
|
||||
$options = array_merge($options, $transformer->extractDateOptions($matches[$char]['value'], $length));
|
||||
}
|
||||
}
|
||||
|
||||
// reset error code and message
|
||||
StubIntlGlobals::setError(StubIntlGlobals::U_ZERO_ERROR);
|
||||
|
||||
return $this->calculateUnixTimestamp($dateTime, $options);
|
||||
}
|
||||
|
||||
// behave like the intl extension
|
||||
StubIntlGlobals::setError(StubIntlGlobals::U_PARSE_ERROR, 'Date parsing failed');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a regular expression to match with a formatted value.
|
||||
*
|
||||
* @param string $pattern The pattern to create the reverse matching regular expression
|
||||
*
|
||||
* @return string The reverse matching regular expression with named captures being formed by the
|
||||
* transformer index in the $transformer array
|
||||
*/
|
||||
public function getReverseMatchingRegExp($pattern)
|
||||
{
|
||||
$that = $this;
|
||||
|
||||
$escapedPattern = preg_quote($pattern, '/');
|
||||
|
||||
// ICU 4.8 recognizes slash ("/") in a value to be parsed as a dash ("-") and vice-versa
|
||||
// when parsing a date/time value
|
||||
$escapedPattern = preg_replace('/\\\[\-|\/]/', '[\/\-]', $escapedPattern);
|
||||
|
||||
$reverseMatchingRegExp = preg_replace_callback($this->regExp, function($matches) use ($that) {
|
||||
$length = strlen($matches[0]);
|
||||
$transformerIndex = $matches[0][0];
|
||||
|
||||
$dateChars = $matches[0];
|
||||
if ($that->isQuoteMatch($dateChars)) {
|
||||
return $that->replaceQuoteMatch($dateChars);
|
||||
}
|
||||
|
||||
$transformers = $that->getTransformers();
|
||||
if (isset($transformers[$transformerIndex])) {
|
||||
$transformer = $transformers[$transformerIndex];
|
||||
$captureName = str_repeat($transformerIndex, $length);
|
||||
|
||||
return "(?P<$captureName>".$transformer->getReverseMatchingRegExp($length).')';
|
||||
}
|
||||
}, $escapedPattern);
|
||||
|
||||
return $reverseMatchingRegExp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the first char of a string is a single quote
|
||||
*
|
||||
* @param string $quoteMatch The string to check
|
||||
*
|
||||
* @return Boolean true if matches, false otherwise
|
||||
*/
|
||||
public function isQuoteMatch($quoteMatch)
|
||||
{
|
||||
return ("'" === $quoteMatch[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces single quotes at the start or end of a string with two single quotes
|
||||
*
|
||||
* @param string $quoteMatch The string to replace the quotes
|
||||
*
|
||||
* @return string A string with the single quotes replaced
|
||||
*/
|
||||
public function replaceQuoteMatch($quoteMatch)
|
||||
{
|
||||
if (preg_match("/^'+$/", $quoteMatch)) {
|
||||
return str_replace("''", "'", $quoteMatch);
|
||||
}
|
||||
|
||||
return str_replace("''", "'", substr($quoteMatch, 1, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a chars match regular expression
|
||||
*
|
||||
* @param string $specialChars A string of chars to build the regular expression
|
||||
*
|
||||
* @return string The chars match regular expression
|
||||
*/
|
||||
protected function buildCharsMatch($specialChars)
|
||||
{
|
||||
$specialCharsArray = str_split($specialChars);
|
||||
|
||||
$specialCharsMatch = implode('|', array_map(function($char) {
|
||||
return $char.'+';
|
||||
}, $specialCharsArray));
|
||||
|
||||
return $specialCharsMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a preg_replace match array, removing the numeric keys and returning an associative array
|
||||
* with the value and pattern values for the matched Transformer
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function normalizeArray(array $data)
|
||||
{
|
||||
$ret = array();
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if (!is_string($key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ret[$key[0]] = array(
|
||||
'value' => $value,
|
||||
'pattern' => $key
|
||||
);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the Unix timestamp based on the matched values by the reverse matching regular
|
||||
* expression of parse()
|
||||
*
|
||||
* @param \DateTime $dateTime The DateTime object to be used to calculate the timestamp
|
||||
* @param array $options An array with the matched values to be used to calculate the timestamp
|
||||
*
|
||||
* @return Boolean|int The calculated timestamp or false if matched date is invalid
|
||||
*/
|
||||
protected function calculateUnixTimestamp(\DateTime $dateTime, array $options)
|
||||
{
|
||||
$options = $this->getDefaultValueForOptions($options);
|
||||
|
||||
$year = $options['year'];
|
||||
$month = $options['month'];
|
||||
$day = $options['day'];
|
||||
$hour = $options['hour'];
|
||||
$hourInstance = $options['hourInstance'];
|
||||
$minute = $options['minute'];
|
||||
$second = $options['second'];
|
||||
$marker = $options['marker'];
|
||||
$timezone = $options['timezone'];
|
||||
|
||||
// If month is false, return immediately (intl behavior)
|
||||
if (false === $month) {
|
||||
StubIntlGlobals::setError(StubIntlGlobals::U_PARSE_ERROR, 'Date parsing failed');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize hour
|
||||
if ($hourInstance instanceof HourTransformer) {
|
||||
$hour = $hourInstance->normalizeHour($hour, $marker);
|
||||
}
|
||||
|
||||
// Set the timezone if different from the default one
|
||||
if (null !== $timezone && $timezone !== $this->timezone) {
|
||||
$dateTime->setTimezone(new \DateTimeZone($timezone));
|
||||
}
|
||||
|
||||
// Normalize yy year
|
||||
preg_match_all($this->regExp, $this->pattern, $matches);
|
||||
if (in_array('yy', $matches[0])) {
|
||||
$dateTime->setTimestamp(time());
|
||||
$year = $year > $dateTime->format('y') + 20 ? 1900 + $year : 2000 + $year;
|
||||
}
|
||||
|
||||
$dateTime->setDate($year, $month, $day);
|
||||
$dateTime->setTime($hour, $minute, $second);
|
||||
|
||||
return $dateTime->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add sensible default values for missing items in the extracted date/time options array. The values
|
||||
* are base in the beginning of the Unix era
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getDefaultValueForOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'year' => isset($options['year']) ? $options['year'] : 1970,
|
||||
'month' => isset($options['month']) ? $options['month'] : 1,
|
||||
'day' => isset($options['day']) ? $options['day'] : 1,
|
||||
'hour' => isset($options['hour']) ? $options['hour'] : 0,
|
||||
'hourInstance' => isset($options['hourInstance']) ? $options['hourInstance'] : null,
|
||||
'minute' => isset($options['minute']) ? $options['minute'] : 0,
|
||||
'second' => isset($options['second']) ? $options['second'] : 0,
|
||||
'marker' => isset($options['marker']) ? $options['marker'] : null,
|
||||
'timezone' => isset($options['timezone']) ? $options['timezone'] : null,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for 12 hour format (0-11)
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class Hour1200Transformer extends HourTransformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
$hourOfDay = $dateTime->format('g');
|
||||
$hourOfDay = '12' == $hourOfDay ? '0' : $hourOfDay;
|
||||
|
||||
return $this->padLeft($hourOfDay, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function normalizeHour($hour, $marker = null)
|
||||
{
|
||||
if ('PM' === $marker) {
|
||||
$hour += 12;
|
||||
}
|
||||
|
||||
return $hour;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return '\d{1,2}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'hour' => (int) $matched,
|
||||
'hourInstance' => $this
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for 12 hour format (1-12)
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class Hour1201Transformer extends HourTransformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
return $this->padLeft($dateTime->format('g'), $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function normalizeHour($hour, $marker = null)
|
||||
{
|
||||
if ('PM' !== $marker && 12 === $hour) {
|
||||
$hour = 0;
|
||||
} elseif ('PM' === $marker && 12 !== $hour) {
|
||||
// If PM and hour is not 12 (1-12), sum 12 hour
|
||||
$hour += 12;
|
||||
}
|
||||
|
||||
return $hour;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return '\d{1,2}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'hour' => (int) $matched,
|
||||
'hourInstance' => $this
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for 24 hour format (0-23)
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class Hour2400Transformer extends HourTransformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
return $this->padLeft($dateTime->format('G'), $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function normalizeHour($hour, $marker = null)
|
||||
{
|
||||
if ('AM' == $marker) {
|
||||
$hour = 0;
|
||||
} elseif ('PM' == $marker) {
|
||||
$hour = 12;
|
||||
}
|
||||
|
||||
return $hour;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return '\d{1,2}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'hour' => (int) $matched,
|
||||
'hourInstance' => $this
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for 24 hour format (1-24)
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class Hour2401Transformer extends HourTransformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
$hourOfDay = $dateTime->format('G');
|
||||
$hourOfDay = ('0' == $hourOfDay) ? '24' : $hourOfDay;
|
||||
|
||||
return $this->padLeft($hourOfDay, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function normalizeHour($hour, $marker = null)
|
||||
{
|
||||
if ((null === $marker && 24 === $hour) || 'AM' == $marker) {
|
||||
$hour = 0;
|
||||
} elseif ('PM' == $marker) {
|
||||
$hour = 12;
|
||||
}
|
||||
|
||||
return $hour;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return '\d{1,2}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'hour' => (int) $matched,
|
||||
'hourInstance' => $this
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Base class for hour transformers
|
||||
*
|
||||
* @author Eriksen Costa <eriksen.costa@infranology.com.br>
|
||||
*/
|
||||
abstract class HourTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* Returns a normalized hour value suitable for the hour transformer type
|
||||
*
|
||||
* @param int $hour The hour value
|
||||
* @param string $marker An optional AM/PM marker
|
||||
*
|
||||
* @return int The normalized hour value
|
||||
*/
|
||||
abstract public function normalizeHour($hour, $marker = null);
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for minute format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class MinuteTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
$minuteOfHour = (int) $dateTime->format('i');
|
||||
|
||||
return $this->padLeft($minuteOfHour, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return 1 === $length ? '\d{1,2}' : '\d{'.$length.'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'minute' => (int) $matched,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for month format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class MonthTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $months = array(
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December'
|
||||
);
|
||||
|
||||
/**
|
||||
* Short months names (first 3 letters)
|
||||
* @var array
|
||||
*/
|
||||
protected static $shortMonths = array();
|
||||
|
||||
/**
|
||||
* Flipped $months array, $name => $index
|
||||
* @var array
|
||||
*/
|
||||
protected static $flippedMonths = array();
|
||||
|
||||
/**
|
||||
* Flipped $shortMonths array, $name => $index
|
||||
* @var array
|
||||
*/
|
||||
protected static $flippedShortMonths = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (0 === count(self::$shortMonths)) {
|
||||
self::$shortMonths = array_map(function($month) {
|
||||
return substr($month, 0, 3);
|
||||
}, self::$months);
|
||||
|
||||
self::$flippedMonths = array_flip(self::$months);
|
||||
self::$flippedShortMonths = array_flip(self::$shortMonths);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
$matchLengthMap = array(
|
||||
1 => 'n',
|
||||
2 => 'm',
|
||||
3 => 'M',
|
||||
4 => 'F',
|
||||
);
|
||||
|
||||
if (isset($matchLengthMap[$length])) {
|
||||
return $dateTime->format($matchLengthMap[$length]);
|
||||
}
|
||||
|
||||
if (5 === $length) {
|
||||
return substr($dateTime->format('M'), 0, 1);
|
||||
}
|
||||
|
||||
return $this->padLeft($dateTime->format('m'), $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
switch ($length) {
|
||||
case 1:
|
||||
$regExp = '\d{1,2}';
|
||||
break;
|
||||
case 3:
|
||||
$regExp = implode('|', self::$shortMonths);
|
||||
break;
|
||||
case 4:
|
||||
$regExp = implode('|', self::$months);
|
||||
break;
|
||||
case 5:
|
||||
$regExp = '[JFMASOND]';
|
||||
break;
|
||||
default:
|
||||
$regExp = '\d{'.$length.'}';
|
||||
break;
|
||||
}
|
||||
|
||||
return $regExp;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
if (!is_numeric($matched)) {
|
||||
if (3 === $length) {
|
||||
$matched = self::$flippedShortMonths[$matched] + 1;
|
||||
} elseif (4 === $length) {
|
||||
$matched = self::$flippedMonths[$matched] + 1;
|
||||
} elseif (5 === $length) {
|
||||
// IntlDateFormatter::parse() always returns false for MMMMM or LLLLL
|
||||
$matched = false;
|
||||
}
|
||||
} else {
|
||||
$matched = (int) $matched;
|
||||
}
|
||||
|
||||
return array(
|
||||
'month' => $matched,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for quarter format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class QuarterTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
$month = (int) $dateTime->format('n');
|
||||
$quarter = (int) floor(($month - 1) / 3) + 1;
|
||||
switch ($length) {
|
||||
case 1:
|
||||
case 2:
|
||||
return $this->padLeft($quarter, $length);
|
||||
case 3:
|
||||
return 'Q'.$quarter;
|
||||
default:
|
||||
$map = array(1 => '1st quarter', 2 => '2nd quarter', 3 => '3rd quarter', 4 => '4th quarter');
|
||||
|
||||
return $map[$quarter];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
switch ($length) {
|
||||
case 1:
|
||||
case 2:
|
||||
return '\d{'.$length.'}';
|
||||
case 3:
|
||||
return 'Q\d';
|
||||
default:
|
||||
return '(?:1st|2nd|3rd|4th) quarter';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for the second format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class SecondTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
$secondOfMinute = (int) $dateTime->format('s');
|
||||
|
||||
return $this->padLeft($secondOfMinute, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return 1 === $length ? '\d{1,2}' : '\d{'.$length.'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'second' => (int) $matched,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
use Symfony\Component\Intl\Exception\NotImplementedException;
|
||||
|
||||
/**
|
||||
* Parser and formatter for time zone format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class TimeZoneTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws NotImplementedException When time zone is different than UTC or GMT (Etc/GMT)
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
$timeZone = substr($dateTime->getTimezone()->getName(), 0, 3);
|
||||
|
||||
if (!in_array($timeZone, array('Etc', 'UTC'))) {
|
||||
throw new NotImplementedException('Time zone different than GMT or UTC is not supported as a formatting output.');
|
||||
}
|
||||
|
||||
// From ICU >= 4.8, the zero offset is not more used, example: GMT instead of GMT+00:00
|
||||
$format = (0 !== (int) $dateTime->format('O')) ? '\G\M\TP' : '\G\M\T';
|
||||
|
||||
return $dateTime->format($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return 'GMT[+-]\d{2}:?\d{2}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'timezone' => self::getEtcTimeZoneId($matched)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Etc/GMT timezone identifier for the specified timezone
|
||||
*
|
||||
* The PHP documentation for timezones states to not use the 'Other' time zones because them exists
|
||||
* "for backwards compatibility". However all Etc/GMT time zones are in the tz database 'etcetera' file,
|
||||
* which indicates they are not deprecated (neither are old names).
|
||||
*
|
||||
* Only GMT, Etc/Universal, Etc/Zulu, Etc/Greenwich, Etc/GMT-0, Etc/GMT+0 and Etc/GMT0 are old names and
|
||||
* are linked to Etc/GMT or Etc/UTC.
|
||||
*
|
||||
* @param string $formattedTimeZone A GMT timezone string (GMT-03:00, e.g.)
|
||||
*
|
||||
* @return string A timezone identifier
|
||||
*
|
||||
* @see http://php.net/manual/en/timezones.others.php
|
||||
* @see http://www.twinsun.com/tz/tz-link.htm
|
||||
*
|
||||
* @throws NotImplementedException When the GMT time zone have minutes offset different than zero
|
||||
* @throws \InvalidArgumentException When the value can not be matched with pattern
|
||||
*/
|
||||
public static function getEtcTimeZoneId($formattedTimeZone)
|
||||
{
|
||||
if (preg_match('/GMT(?P<signal>[+-])(?P<hours>\d{2}):?(?P<minutes>\d{2})/', $formattedTimeZone, $matches)) {
|
||||
$hours = (int) $matches['hours'];
|
||||
$minutes = (int) $matches['minutes'];
|
||||
$signal = $matches['signal'] == '-' ? '+' : '-';
|
||||
|
||||
if (0 < $minutes) {
|
||||
throw new NotImplementedException(sprintf(
|
||||
'It is not possible to use a GMT time zone with minutes offset different than zero (0). GMT time zone tried: %s.',
|
||||
$formattedTimeZone
|
||||
));
|
||||
}
|
||||
|
||||
return 'Etc/GMT'.($hours !== 0 ? $signal.$hours : '');
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('The GMT time zone \'%s\' does not match with the supported formats GMT[+-]HH:MM or GMT[+-]HHMM.');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for date formats
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
abstract class Transformer
|
||||
{
|
||||
/**
|
||||
* Format a value using a configured DateTime as date/time source
|
||||
*
|
||||
*
|
||||
* @param \DateTime $dateTime A DateTime object to be used to generate the formatted value
|
||||
* @param int $length The formatted value string length
|
||||
*
|
||||
* @return string The formatted value
|
||||
*/
|
||||
abstract public function format(\DateTime $dateTime, $length);
|
||||
|
||||
/**
|
||||
* Returns a reverse matching regular expression of a string generated by format()
|
||||
*
|
||||
* @param int $length The length of the value to be reverse matched
|
||||
*
|
||||
* @return string The reverse matching regular expression
|
||||
*/
|
||||
abstract public function getReverseMatchingRegExp($length);
|
||||
|
||||
/**
|
||||
* Extract date options from a matched value returned by the processing of the reverse matching
|
||||
* regular expression
|
||||
*
|
||||
* @param string $matched The matched value
|
||||
* @param int $length The length of the Transformer pattern string
|
||||
*
|
||||
* @return array An associative array
|
||||
*/
|
||||
abstract public function extractDateOptions($matched, $length);
|
||||
|
||||
/**
|
||||
* Pad a string with zeros to the left
|
||||
*
|
||||
* @param string $value The string to be padded
|
||||
* @param int $length The length to pad
|
||||
*
|
||||
* @return string The padded string
|
||||
*/
|
||||
protected function padLeft($value, $length)
|
||||
{
|
||||
return str_pad($value, $length, '0', STR_PAD_LEFT);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter\DateFormat;
|
||||
|
||||
/**
|
||||
* Parser and formatter for year format
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class YearTransformer extends Transformer
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function format(\DateTime $dateTime, $length)
|
||||
{
|
||||
if (2 === $length) {
|
||||
return $dateTime->format('y');
|
||||
}
|
||||
|
||||
return $this->padLeft($dateTime->format('Y'), $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReverseMatchingRegExp($length)
|
||||
{
|
||||
return 2 === $length ? '\d{2}' : '\d{4}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function extractDateOptions($matched, $length)
|
||||
{
|
||||
return array(
|
||||
'year' => (int) $matched,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,601 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\DateFormatter;
|
||||
|
||||
use Symfony\Component\Intl\Globals\StubIntlGlobals;
|
||||
use Symfony\Component\Intl\DateFormatter\DateFormat\FullTransformer;
|
||||
use Symfony\Component\Intl\Exception\MethodNotImplementedException;
|
||||
use Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException;
|
||||
use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException;
|
||||
use Symfony\Component\Intl\Locale\StubLocale;
|
||||
|
||||
/**
|
||||
* Provides a stub IntlDateFormatter for the 'en' locale.
|
||||
*
|
||||
* @author Igor Wiedler <igor@wiedler.ch>
|
||||
*/
|
||||
class StubIntlDateFormatter
|
||||
{
|
||||
/**
|
||||
* The error code from the last operation
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $errorCode = StubIntlGlobals::U_ZERO_ERROR;
|
||||
|
||||
/**
|
||||
* The error message from the last operation
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $errorMessage = 'U_ZERO_ERROR';
|
||||
|
||||
/* date/time format types */
|
||||
const NONE = -1;
|
||||
const FULL = 0;
|
||||
const LONG = 1;
|
||||
const MEDIUM = 2;
|
||||
const SHORT = 3;
|
||||
|
||||
/* calendar formats */
|
||||
const TRADITIONAL = 0;
|
||||
const GREGORIAN = 1;
|
||||
|
||||
/**
|
||||
* Patterns used to format the date when no pattern is provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $defaultDateFormats = array(
|
||||
self::NONE => '',
|
||||
self::FULL => 'EEEE, LLLL d, y',
|
||||
self::LONG => 'LLLL d, y',
|
||||
self::MEDIUM => 'LLL d, y',
|
||||
self::SHORT => 'M/d/yy',
|
||||
);
|
||||
|
||||
/**
|
||||
* Patterns used to format the time when no pattern is provided
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $defaultTimeFormats = array(
|
||||
self::FULL => 'h:mm:ss a zzzz',
|
||||
self::LONG => 'h:mm:ss a z',
|
||||
self::MEDIUM => 'h:mm:ss a',
|
||||
self::SHORT => 'h:mm a',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $datetype;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $timetype;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $pattern;
|
||||
|
||||
/**
|
||||
* @var \DateTimeZone
|
||||
*/
|
||||
private $dateTimeZone;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $unitializedTimeZoneId = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $timeZoneId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $locale The locale code
|
||||
* @param int $datetype Type of date formatting, one of the format type constants
|
||||
* @param int $timetype Type of time formatting, one of the format type constants
|
||||
* @param string $timezone Timezone identifier
|
||||
* @param int $calendar Calendar to use for formatting or parsing; default is Gregorian.
|
||||
* One of the calendar constants.
|
||||
* @param string $pattern Optional pattern to use when formatting
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.create.php
|
||||
* @see http://userguide.icu-project.org/formatparse/datetime
|
||||
*
|
||||
* @throws MethodArgumentValueNotImplementedException When $locale different than 'en' is passed
|
||||
* @throws MethodArgumentValueNotImplementedException When $calendar different than GREGORIAN is passed
|
||||
*/
|
||||
public function __construct($locale, $datetype, $timetype, $timezone = null, $calendar = self::GREGORIAN, $pattern = null)
|
||||
{
|
||||
if ('en' !== $locale) {
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the \'en\' locale is supported');
|
||||
}
|
||||
|
||||
if (self::GREGORIAN !== $calendar) {
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'calendar', $calendar, 'Only the GREGORIAN calendar is supported');
|
||||
}
|
||||
|
||||
$this->datetype = $datetype;
|
||||
$this->timetype = $timetype;
|
||||
|
||||
$this->setPattern($pattern);
|
||||
$this->setTimeZoneId($timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static constructor
|
||||
*
|
||||
* @param string $locale The locale code
|
||||
* @param int $datetype Type of date formatting, one of the format type constants
|
||||
* @param int $timetype Type of time formatting, one of the format type constants
|
||||
* @param string $timezone Timezone identifier
|
||||
* @param int $calendar Calendar to use for formatting or parsing; default is Gregorian.
|
||||
* One of the calendar constants.
|
||||
* @param string $pattern Optional pattern to use when formatting
|
||||
*
|
||||
* @return StubIntlDateFormatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.create.php
|
||||
* @see http://userguide.icu-project.org/formatparse/datetime
|
||||
*
|
||||
* @throws MethodArgumentValueNotImplementedException When $locale different than 'en' is passed
|
||||
*/
|
||||
public static function create($locale, $datetype, $timetype, $timezone = null, $calendar = self::GREGORIAN, $pattern = null)
|
||||
{
|
||||
return new self($locale, $datetype, $timetype, $timezone, $calendar, $pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the date/time value (timestamp) as a string
|
||||
*
|
||||
* @param mixed $timestamp Unix timestamp to format
|
||||
*
|
||||
* @return string The formatted value
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.format.php
|
||||
*
|
||||
* @throws MethodArgumentValueNotImplementedException If one of the formatting characters is not implemented
|
||||
*/
|
||||
public function format($timestamp)
|
||||
{
|
||||
// intl allows timestamps to be passed as arrays - we don't
|
||||
if (is_array($timestamp)) {
|
||||
$message = version_compare(PHP_VERSION, '5.3.4', '>=') ?
|
||||
'Only integer unix timestamps and DateTime objects are supported' :
|
||||
'Only integer unix timestamps are supported';
|
||||
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'timestamp', $timestamp, $message);
|
||||
}
|
||||
|
||||
// behave like the intl extension
|
||||
$argumentError = null;
|
||||
if (version_compare(PHP_VERSION, '5.3.4', '<') && !is_int($timestamp)) {
|
||||
$argumentError = 'datefmt_format: takes either an array or an integer timestamp value ';
|
||||
} elseif (version_compare(PHP_VERSION, '5.3.4', '>=') && !is_int($timestamp) && !$timestamp instanceof \DateTime) {
|
||||
$argumentError = 'datefmt_format: takes either an array or an integer timestamp value or a DateTime object';
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=') && !is_int($timestamp)) {
|
||||
$argumentError = sprintf('datefmt_format: string \'%s\' is not numeric, which would be required for it to be a valid date', $timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $argumentError) {
|
||||
StubIntlGlobals::setError(StubIntlGlobals::U_ILLEGAL_ARGUMENT_ERROR, $argumentError);
|
||||
$this->errorCode = StubIntlGlobals::getErrorCode();
|
||||
$this->errorMessage = StubIntlGlobals::getErrorMessage();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// As of PHP 5.3.4, IntlDateFormatter::format() accepts DateTime instances
|
||||
if (version_compare(PHP_VERSION, '5.3.4', '>=') && $timestamp instanceof \DateTime) {
|
||||
$timestamp = $timestamp->getTimestamp();
|
||||
}
|
||||
|
||||
$transformer = new FullTransformer($this->getPattern(), $this->getTimeZoneId());
|
||||
$formatted = $transformer->format($this->createDateTime($timestamp));
|
||||
|
||||
// behave like the intl extension
|
||||
StubIntlGlobals::setError(StubIntlGlobals::U_ZERO_ERROR);
|
||||
$this->errorCode = StubIntlGlobals::getErrorCode();
|
||||
$this->errorMessage = StubIntlGlobals::getErrorMessage();
|
||||
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an object
|
||||
*
|
||||
* @param object $object
|
||||
* @param mixed $format
|
||||
* @param string $locale
|
||||
*
|
||||
* @return string The formatted value
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.formatobject.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function formatObject($object, $format = null, $locale = null)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's calendar
|
||||
*
|
||||
* @return int The calendar being used by the formatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.getcalendar.php
|
||||
*/
|
||||
public function getCalendar()
|
||||
{
|
||||
return self::GREGORIAN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's calendar object
|
||||
*
|
||||
* @return object The calendar's object being used by the formatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.getcalendarobject.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function getCalendarObject()
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's datetype
|
||||
*
|
||||
* @return int The current value of the formatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.getdatetype.php
|
||||
*/
|
||||
public function getDateType()
|
||||
{
|
||||
return $this->datetype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns formatter's last error code. Always returns the U_ZERO_ERROR class constant value
|
||||
*
|
||||
* @return int The error code from last formatter call
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.geterrorcode.php
|
||||
*/
|
||||
public function getErrorCode()
|
||||
{
|
||||
return $this->errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns formatter's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value
|
||||
*
|
||||
* @return string The error message from last formatter call
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.geterrormessage.php
|
||||
*/
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return $this->errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's locale
|
||||
*
|
||||
* @param int $type The locale name type to return between valid or actual (StubLocale::VALID_LOCALE or StubLocale::ACTUAL_LOCALE, respectively)
|
||||
*
|
||||
* @return string The locale name used to create the formatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.getlocale.php
|
||||
*/
|
||||
public function getLocale($type = StubLocale::ACTUAL_LOCALE)
|
||||
{
|
||||
return 'en';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's pattern
|
||||
*
|
||||
* @return string The pattern string used by the formatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.getpattern.php
|
||||
*/
|
||||
public function getPattern()
|
||||
{
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's time type
|
||||
*
|
||||
* @return string The time type used by the formatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.gettimetype.php
|
||||
*/
|
||||
public function getTimeType()
|
||||
{
|
||||
return $this->timetype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's timezone identifier
|
||||
*
|
||||
* @return string The timezone identifier used by the formatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.gettimezoneid.php
|
||||
*/
|
||||
public function getTimeZoneId()
|
||||
{
|
||||
if (!$this->unitializedTimeZoneId) {
|
||||
return $this->timeZoneId;
|
||||
}
|
||||
|
||||
// In PHP 5.5 default timezone depends on `date_default_timezone_get()` method
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
return date_default_timezone_get();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's timezone
|
||||
*
|
||||
* @return mixed The timezone used by the formatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.gettimezone.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function getTimeZone()
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the formatter is lenient
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.islenient.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function isLenient()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse string to a field-based time value
|
||||
*
|
||||
* @param string $value String to convert to a time value
|
||||
* @param int $position Position at which to start the parsing in $value (zero-based).
|
||||
* If no error occurs before $value is consumed, $parse_pos will
|
||||
* contain -1 otherwise it will contain the position at which parsing
|
||||
* ended. If $parse_pos > strlen($value), the parse fails immediately.
|
||||
*
|
||||
* @return string Localtime compatible array of integers: contains 24 hour clock value in tm_hour field
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.localtime.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function localtime($value, &$position = 0)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse string to a timestamp value
|
||||
*
|
||||
* @param string $value String to convert to a time value
|
||||
* @param int $position Position at which to start the parsing in $value (zero-based).
|
||||
* If no error occurs before $value is consumed, $parse_pos will
|
||||
* contain -1 otherwise it will contain the position at which parsing
|
||||
* ended. If $parse_pos > strlen($value), the parse fails immediately.
|
||||
*
|
||||
* @return string Parsed value as a timestamp
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.parse.php
|
||||
*
|
||||
* @throws MethodArgumentNotImplementedException When $position different than null, behavior not implemented
|
||||
*/
|
||||
public function parse($value, &$position = null)
|
||||
{
|
||||
// We don't calculate the position when parsing the value
|
||||
if (null !== $position) {
|
||||
throw new MethodArgumentNotImplementedException(__METHOD__, 'position');
|
||||
}
|
||||
|
||||
$dateTime = $this->createDateTime(0);
|
||||
$transformer = new FullTransformer($this->getPattern(), $this->getTimeZoneId());
|
||||
|
||||
$timestamp = $transformer->parse($dateTime, $value);
|
||||
|
||||
// behave like the intl extension. FullTransformer::parse() set the proper error
|
||||
$this->errorCode = StubIntlGlobals::getErrorCode();
|
||||
$this->errorMessage = StubIntlGlobals::getErrorMessage();
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the formatter's calendar
|
||||
*
|
||||
* @param string $calendar The calendar to use. Default is IntlDateFormatter::GREGORIAN.
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.setcalendar.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function setCalendar($calendar)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the leniency of the parser
|
||||
*
|
||||
* Define if the parser is strict or lenient in interpreting inputs that do not match the pattern
|
||||
* exactly. Enabling lenient parsing allows the parser to accept otherwise flawed date or time
|
||||
* patterns, parsing as much as possible to obtain a value. Extra space, unrecognized tokens, or
|
||||
* invalid values ("February 30th") are not accepted.
|
||||
*
|
||||
* @param Boolean $lenient Sets whether the parser is lenient or not, default is false (strict)
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.setlenient.php
|
||||
*
|
||||
* @throws MethodArgumentValueNotImplementedException When $lenient is true
|
||||
*/
|
||||
public function setLenient($lenient)
|
||||
{
|
||||
if ($lenient) {
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'lenient', $lenient, 'Only the strict parser is supported');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the formatter's pattern
|
||||
*
|
||||
* @param string $pattern A pattern string in conformance with the ICU IntlDateFormatter documentation
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.setpattern.php
|
||||
* @see http://userguide.icu-project.org/formatparse/datetime
|
||||
*/
|
||||
public function setPattern($pattern)
|
||||
{
|
||||
if (null === $pattern) {
|
||||
$pattern = $this->getDefaultPattern();
|
||||
}
|
||||
|
||||
$this->pattern = $pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the formatter's timezone identifier
|
||||
*
|
||||
* @param string $timeZoneId The time zone ID string of the time zone to use.
|
||||
* If NULL or the empty string, the default time zone for the
|
||||
* runtime is used.
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.settimezoneid.php
|
||||
*/
|
||||
public function setTimeZoneId($timeZoneId)
|
||||
{
|
||||
if (null === $timeZoneId) {
|
||||
// In PHP 5.5 if $timeZoneId is null it fallbacks to `date_default_timezone_get()` method
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$timeZoneId = date_default_timezone_get();
|
||||
} else {
|
||||
// TODO: changes were made to ext/intl in PHP 5.4.4 release that need to be investigated since it will
|
||||
// use ini's date.timezone when the time zone is not provided. As a not well tested workaround, uses UTC.
|
||||
// See the first two items of the commit message for more information:
|
||||
// https://github.com/php/php-src/commit/eb346ef0f419b90739aadfb6cc7b7436c5b521d9
|
||||
$timeZoneId = getenv('TZ') ?: 'UTC';
|
||||
}
|
||||
|
||||
$this->unitializedTimeZoneId = true;
|
||||
}
|
||||
|
||||
// Backup original passed time zone
|
||||
$timeZone = $timeZoneId;
|
||||
|
||||
// Get an Etc/GMT time zone that is accepted for \DateTimeZone
|
||||
if ('GMT' !== $timeZoneId && 0 === strpos($timeZoneId, 'GMT')) {
|
||||
try {
|
||||
$timeZoneId = DateFormat\TimeZoneTransformer::getEtcTimeZoneId($timeZoneId);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// Does nothing, will fallback to UTC
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$this->dateTimeZone = new \DateTimeZone($timeZoneId);
|
||||
} catch (\Exception $e) {
|
||||
$this->dateTimeZone = new \DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
$this->timeZoneId = $timeZone;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was added in PHP 5.5 as replacement for `setTimeZoneId()`
|
||||
*
|
||||
* @param mixed $timeZone
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/intldateformatter.settimezone.php
|
||||
*/
|
||||
public function setTimeZone($timeZone)
|
||||
{
|
||||
return $this->setTimeZoneId($timeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and returns a DateTime object with the specified timestamp and with the
|
||||
* current time zone
|
||||
*
|
||||
* @param int $timestamp
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
protected function createDateTime($timestamp)
|
||||
{
|
||||
$dateTime = new \DateTime();
|
||||
$dateTime->setTimestamp($timestamp);
|
||||
$dateTime->setTimezone($this->dateTimeZone);
|
||||
|
||||
return $dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pattern string based in the datetype and timetype values
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultPattern()
|
||||
{
|
||||
$patternParts = array();
|
||||
if (self::NONE !== $this->datetype) {
|
||||
$patternParts[] = $this->defaultDateFormats[$this->datetype];
|
||||
}
|
||||
if (self::NONE !== $this->timetype) {
|
||||
$patternParts[] = $this->defaultTimeFormats[$this->timetype];
|
||||
}
|
||||
$pattern = implode(' ', $patternParts);
|
||||
|
||||
return $pattern;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Exception;
|
||||
|
||||
/**
|
||||
* Base BadMethodCallException for the Intl component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
|
||||
{
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Exception;
|
||||
|
||||
/**
|
||||
* Base ExceptionInterface for the Intl component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface ExceptionInterface
|
||||
{
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Exception;
|
||||
|
||||
/**
|
||||
* InvalidArgumentException for the Intl component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Exception;
|
||||
|
||||
use Symfony\Component\Intl\Exception\NotImplementedException;
|
||||
|
||||
/**
|
||||
* @author Eriksen Costa <eriksen.costa@infranology.com.br>
|
||||
*/
|
||||
class MethodArgumentNotImplementedException extends NotImplementedException
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $methodName The method name that raised the exception
|
||||
* @param string $argName The argument name that is not implemented
|
||||
*/
|
||||
public function __construct($methodName, $argName)
|
||||
{
|
||||
$message = sprintf('The %s() method\'s argument $%s behavior is not implemented.', $methodName, $argName);
|
||||
parent::__construct($message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Exception;
|
||||
|
||||
use Symfony\Component\Intl\Exception\NotImplementedException;
|
||||
|
||||
/**
|
||||
* @author Eriksen Costa <eriksen.costa@infranology.com.br>
|
||||
*/
|
||||
class MethodArgumentValueNotImplementedException extends NotImplementedException
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $methodName The method name that raised the exception
|
||||
* @param string $argName The argument name
|
||||
* @param string $argValue The argument value that is not implemented
|
||||
* @param string $additionalMessage An optional additional message to append to the exception message
|
||||
*/
|
||||
public function __construct($methodName, $argName, $argValue, $additionalMessage = '')
|
||||
{
|
||||
$message = sprintf(
|
||||
'The %s() method\'s argument $%s value %s behavior is not implemented.%s',
|
||||
$methodName,
|
||||
$argName,
|
||||
var_export($argValue, true),
|
||||
$additionalMessage !== '' ? ' '.$additionalMessage.'. ' : ''
|
||||
);
|
||||
|
||||
parent::__construct($message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Exception;
|
||||
|
||||
/**
|
||||
* @author Eriksen Costa <eriksen.costa@infranology.com.br>
|
||||
*/
|
||||
class MethodNotImplementedException extends NotImplementedException
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $methodName The name of the method
|
||||
*/
|
||||
public function __construct($methodName)
|
||||
{
|
||||
parent::__construct(sprintf('The %s() is not implemented.', $methodName));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Exception;
|
||||
|
||||
/**
|
||||
* Base exception class for not implemented behaviors of the intl extension in the Locale component.
|
||||
*
|
||||
* @author Eriksen Costa <eriksen.costa@infranology.com.br>
|
||||
*/
|
||||
class NotImplementedException extends RuntimeException
|
||||
{
|
||||
const INTL_INSTALL_MESSAGE = 'Please install the "intl" extension for full localization capabilities.';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $message The exception message. A note to install the intl extension is appended to this string
|
||||
*/
|
||||
public function __construct($message)
|
||||
{
|
||||
parent::__construct($message.' '.self::INTL_INSTALL_MESSAGE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Exception;
|
||||
|
||||
/**
|
||||
* Base OutOfBoundsException for the Intl component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
|
||||
{
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Exception;
|
||||
|
||||
/**
|
||||
* RuntimeException for the Intl component.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Globals;
|
||||
|
||||
/**
|
||||
* Provides fake static versions of the global functions in the intl extension
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
abstract class StubIntlGlobals
|
||||
{
|
||||
/**
|
||||
* Indicates that no error occurred
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const U_ZERO_ERROR = 0;
|
||||
|
||||
/**
|
||||
* Indicates that an invalid argument was passed
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const U_ILLEGAL_ARGUMENT_ERROR = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the parse() operation failed
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const U_PARSE_ERROR = 9;
|
||||
|
||||
/**
|
||||
* All known error codes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $errorCodes = array(
|
||||
self::U_ZERO_ERROR => 'U_ZERO_ERROR',
|
||||
self::U_ILLEGAL_ARGUMENT_ERROR => 'U_ILLEGAL_ARGUMENT_ERROR',
|
||||
self::U_PARSE_ERROR => 'U_PARSE_ERROR',
|
||||
);
|
||||
|
||||
/**
|
||||
* The error code of the last operation
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
private static $errorCode = self::U_ZERO_ERROR;
|
||||
|
||||
/**
|
||||
* The error code of the last operation
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
private static $errorMessage = 'U_ZERO_ERROR';
|
||||
|
||||
/**
|
||||
* Returns whether the error code indicates a failure
|
||||
*
|
||||
* @param integer $errorCode The error code returned by StubIntlGlobals::getErrorCode()
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public static function isFailure($errorCode)
|
||||
{
|
||||
return isset(self::$errorCodes[$errorCode])
|
||||
&& $errorCode > self::U_ZERO_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error code of the last operation
|
||||
*
|
||||
* Returns StubIntlGlobals::U_ZERO_ERROR if no error occurred.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function getErrorCode()
|
||||
{
|
||||
return self::$errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error message of the last operation
|
||||
*
|
||||
* Returns "U_ZERO_ERROR" if no error occurred.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getErrorMessage()
|
||||
{
|
||||
return self::$errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the symbolic name for a given error code
|
||||
*
|
||||
* @param integer $code The error code returned by StubIntlGlobals::getErrorCode()
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getErrorName($code)
|
||||
{
|
||||
if (isset(self::$errorCodes[$code])) {
|
||||
return self::$errorCodes[$code];
|
||||
}
|
||||
|
||||
return '[BOGUS UErrorCode]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current error
|
||||
*
|
||||
* @param integer $code One of the error constants in this class
|
||||
* @param string $message The ICU class error message
|
||||
*
|
||||
* @throws \InvalidArgumentException If the code is not one of the error constants in this class
|
||||
*/
|
||||
public static function setError($code, $message = '')
|
||||
{
|
||||
if (!isset(self::$errorCodes[$code])) {
|
||||
throw new \InvalidArgumentException(sprintf('No such error code: "%s"', $code));
|
||||
}
|
||||
|
||||
self::$errorMessage = $message ? sprintf('%s: %s', $message, self::$errorCodes[$code]) : self::$errorCodes[$code];
|
||||
self::$errorCode = $code;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl;
|
||||
|
||||
use Symfony\Component\Icu\IcuCurrencyBundle;
|
||||
use Symfony\Component\Icu\IcuData;
|
||||
use Symfony\Component\Icu\IcuLanguageBundle;
|
||||
use Symfony\Component\Icu\IcuLocaleBundle;
|
||||
use Symfony\Component\Icu\IcuRegionBundle;
|
||||
use Symfony\Component\Intl\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader;
|
||||
use Symfony\Component\Intl\ResourceBundle\Reader\BufferedReader;
|
||||
use Symfony\Component\Intl\ResourceBundle\Reader\PhpBundleReader;
|
||||
use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReader;
|
||||
use Symfony\Component\Intl\ResourceBundle\Stub\StubCurrencyBundle;
|
||||
use Symfony\Component\Intl\ResourceBundle\Stub\StubLanguageBundle;
|
||||
use Symfony\Component\Intl\ResourceBundle\Stub\StubLocaleBundle;
|
||||
use Symfony\Component\Intl\ResourceBundle\Stub\StubRegionBundle;
|
||||
|
||||
/**
|
||||
* Gives access to internationalization data.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class Intl
|
||||
{
|
||||
/**
|
||||
* Load data from the Icu component.
|
||||
*/
|
||||
const ICU = 0;
|
||||
|
||||
/**
|
||||
* Load data from the stub files of the Intl component.
|
||||
*/
|
||||
const STUB = 1;
|
||||
|
||||
/**
|
||||
* The number of resource bundles to buffer. Loading the same resource
|
||||
* bundle for n locales takes up n spots in the buffer.
|
||||
*/
|
||||
const BUFFER_SIZE = 10;
|
||||
|
||||
/**
|
||||
* The accepted values for the {@link $dataSource} property.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $allowedDataSources = array(
|
||||
self::ICU => 'Intl::ICU',
|
||||
self::STUB => 'Intl::STUB',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private static $dataSource;
|
||||
|
||||
/**
|
||||
* @var ResourceBundle\CurrencyBundleInterface
|
||||
*/
|
||||
private static $currencyBundle;
|
||||
|
||||
/**
|
||||
* @var ResourceBundle\LanguageBundleInterface
|
||||
*/
|
||||
private static $languageBundle;
|
||||
|
||||
/**
|
||||
* @var ResourceBundle\LocaleBundleInterface
|
||||
*/
|
||||
private static $localeBundle;
|
||||
|
||||
/**
|
||||
* @var ResourceBundle\RegionBundleInterface
|
||||
*/
|
||||
private static $regionBundle;
|
||||
|
||||
/**
|
||||
* @var string|Boolean|null
|
||||
*/
|
||||
private static $icuVersion = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $icuDataVersion = false;
|
||||
|
||||
/**
|
||||
* @var ResourceBundle\Reader\StructuredBundleReaderInterface
|
||||
*/
|
||||
private static $phpReader;
|
||||
|
||||
/**
|
||||
* @var ResourceBundle\Reader\StructuredBundleReaderInterface
|
||||
*/
|
||||
private static $binaryReader;
|
||||
|
||||
/**
|
||||
* Returns whether the intl extension is installed.
|
||||
*
|
||||
* @return Boolean Returns true if the intl extension is installed, false otherwise.
|
||||
*/
|
||||
public static function isExtensionLoaded()
|
||||
{
|
||||
return IcuData::isLoadable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source from which to load the resource bundles.
|
||||
*
|
||||
* @param integer $dataSource One of the constants {@link Intl::ICU} or
|
||||
* {@link Intl::STUB}.
|
||||
*
|
||||
* @throws InvalidArgumentException If the data source is invalid.
|
||||
*
|
||||
* @see getData>Source
|
||||
*/
|
||||
public static function setDataSource($dataSource)
|
||||
{
|
||||
if (!isset(self::$allowedDataSources[$dataSource])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The data sources should be one of %s',
|
||||
implode(', ', self::$allowedDataSources)
|
||||
));
|
||||
}
|
||||
|
||||
if (self::ICU === $dataSource && !IcuData::isLoadable()) {
|
||||
throw new InvalidArgumentException(
|
||||
'The data source cannot be set to Intl::ICU if the intl ' .
|
||||
'extension is not installed.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($dataSource !== self::$dataSource) {
|
||||
self::$currencyBundle = null;
|
||||
self::$languageBundle = null;
|
||||
self::$localeBundle = null;
|
||||
self::$regionBundle = null;
|
||||
}
|
||||
|
||||
self::$dataSource = $dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data source from which to load the resource bundles.
|
||||
*
|
||||
* If {@link setDataSource()} has not been called, the data source will be
|
||||
* chosen depending on whether the intl extension is installed or not:
|
||||
*
|
||||
* * If the extension is present, the bundles will be loaded from the Icu
|
||||
* component;
|
||||
* * Otherwise, the bundles will be loaded from the stub files in the
|
||||
* Intl component.
|
||||
*
|
||||
* @return integer One of the constants {@link Intl::ICU} or
|
||||
* {@link Intl::STUB}.
|
||||
*/
|
||||
public static function getDataSource()
|
||||
{
|
||||
if (null === self::$dataSource) {
|
||||
self::$dataSource = IcuData::isLoadable() ? self::ICU : self::STUB;
|
||||
}
|
||||
|
||||
return self::$dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle containing currency information.
|
||||
*
|
||||
* @return ResourceBundle\CurrencyBundleInterface The currency resource bundle.
|
||||
*/
|
||||
public static function getCurrencyBundle()
|
||||
{
|
||||
if (null === self::$currencyBundle) {
|
||||
self::$currencyBundle = self::ICU === self::getDataSource()
|
||||
? new IcuCurrencyBundle(self::getBinaryReader())
|
||||
: new StubCurrencyBundle(self::getPhpReader());
|
||||
}
|
||||
|
||||
return self::$currencyBundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle containing language information.
|
||||
*
|
||||
* @return ResourceBundle\LanguageBundleInterface The language resource bundle.
|
||||
*/
|
||||
public static function getLanguageBundle()
|
||||
{
|
||||
if (null === self::$languageBundle) {
|
||||
self::$languageBundle = self::ICU === self::getDataSource()
|
||||
? new IcuLanguageBundle(self::getBinaryReader())
|
||||
: new StubLanguageBundle(self::getPhpReader());
|
||||
}
|
||||
|
||||
return self::$languageBundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle containing locale information.
|
||||
*
|
||||
* @return ResourceBundle\LocaleBundleInterface The locale resource bundle.
|
||||
*/
|
||||
public static function getLocaleBundle()
|
||||
{
|
||||
if (null === self::$localeBundle) {
|
||||
self::$localeBundle = self::ICU === self::getDataSource()
|
||||
? new IcuLocaleBundle(self::getBinaryReader())
|
||||
: new StubLocaleBundle(self::getPhpReader());
|
||||
}
|
||||
|
||||
return self::$localeBundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle containing region information.
|
||||
*
|
||||
* @return ResourceBundle\RegionBundleInterface The region resource bundle.
|
||||
*/
|
||||
public static function getRegionBundle()
|
||||
{
|
||||
if (null === self::$regionBundle) {
|
||||
self::$regionBundle = self::ICU === self::getDataSource()
|
||||
? new IcuRegionBundle(self::getBinaryReader())
|
||||
: new StubRegionBundle(self::getPhpReader());
|
||||
}
|
||||
|
||||
return self::$regionBundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the installed ICU library.
|
||||
*
|
||||
* @return null|string The ICU version or NULL if it could not be determined.
|
||||
*/
|
||||
public static function getIcuVersion()
|
||||
{
|
||||
if (false === self::$icuVersion) {
|
||||
if (defined('INTL_ICU_VERSION')) {
|
||||
self::$icuVersion = INTL_ICU_VERSION;
|
||||
} else {
|
||||
try {
|
||||
$reflector = new \ReflectionExtension('intl');
|
||||
ob_start();
|
||||
$reflector->info();
|
||||
$output = strip_tags(ob_get_clean());
|
||||
preg_match('/^ICU version (?:=>)?(.*)$/m', $output, $matches);
|
||||
|
||||
self::$icuVersion = trim($matches[1]);
|
||||
} catch (\ReflectionException $e) {
|
||||
self::$icuVersion = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self::$icuVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the installed ICU data.
|
||||
*
|
||||
* @return string The version of the installed ICU data.
|
||||
*/
|
||||
public static function getIcuDataVersion()
|
||||
{
|
||||
if (false === self::$icuDataVersion) {
|
||||
self::$icuDataVersion = self::ICU === self::getDataSource()
|
||||
? IcuData::getVersion()
|
||||
: file_get_contents(__DIR__ . '/Resources/version.txt');
|
||||
}
|
||||
|
||||
return self::$icuDataVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ICU version that the stub classes mimic.
|
||||
*
|
||||
* @return string The ICU version of the stub classes.
|
||||
*/
|
||||
public static function getStubIcuVersion()
|
||||
{
|
||||
return '50.1.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a resource bundle reader for .php resource bundle files.
|
||||
*
|
||||
* @return ResourceBundle\Reader\StructuredBundleReaderInterface The resource reader.
|
||||
*/
|
||||
private static function getPhpReader()
|
||||
{
|
||||
if (null === self::$phpReader) {
|
||||
self::$phpReader = new StructuredBundleReader(new BufferedReader(
|
||||
new PhpBundleReader(),
|
||||
self::BUFFER_SIZE
|
||||
));
|
||||
}
|
||||
|
||||
return self::$phpReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a resource bundle reader for binary .res resource bundle files.
|
||||
*
|
||||
* @return ResourceBundle\Reader\StructuredBundleReaderInterface The resource reader.
|
||||
*/
|
||||
private static function getBinaryReader()
|
||||
{
|
||||
if (null === self::$binaryReader) {
|
||||
self::$binaryReader = new StructuredBundleReader(new BufferedReader(
|
||||
new BinaryBundleReader(),
|
||||
self::BUFFER_SIZE
|
||||
));
|
||||
}
|
||||
|
||||
return self::$binaryReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class must not be instantiated.
|
||||
*/
|
||||
private function __construct() {}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2004-2013 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,317 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Locale;
|
||||
|
||||
use Symfony\Component\Intl\Locale;
|
||||
use Symfony\Component\Intl\Exception\NotImplementedException;
|
||||
use Symfony\Component\Intl\Exception\MethodNotImplementedException;
|
||||
|
||||
/**
|
||||
* Provides a stub Locale for the 'en' locale.
|
||||
*
|
||||
* @author Eriksen Costa <eriksen.costa@infranology.com.br>
|
||||
*/
|
||||
class StubLocale
|
||||
{
|
||||
const DEFAULT_LOCALE = null;
|
||||
|
||||
/** Locale method constants */
|
||||
const ACTUAL_LOCALE = 0;
|
||||
const VALID_LOCALE = 1;
|
||||
|
||||
/** Language tags constants */
|
||||
const LANG_TAG = 'language';
|
||||
const EXTLANG_TAG = 'extlang';
|
||||
const SCRIPT_TAG = 'script';
|
||||
const REGION_TAG = 'region';
|
||||
const VARIANT_TAG = 'variant';
|
||||
const GRANDFATHERED_LANG_TAG = 'grandfathered';
|
||||
const PRIVATE_TAG = 'private';
|
||||
|
||||
/**
|
||||
* Returns the best available locale based on HTTP "Accept-Language" header according to RFC 2616
|
||||
*
|
||||
* @param string $header The string containing the "Accept-Language" header value
|
||||
*
|
||||
* @return string The corresponding locale code
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.acceptfromhttp.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function acceptFromHttp($header)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a correctly ordered and delimited locale code
|
||||
*
|
||||
* @param array $subtags A keyed array where the keys identify the particular locale code subtag
|
||||
*
|
||||
* @return string The corresponding locale code
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.composelocale.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function composeLocale(array $subtags)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a language tag filter matches with locale
|
||||
*
|
||||
* @param string $langtag The language tag to check
|
||||
* @param string $locale The language range to check against
|
||||
* @param Boolean $canonicalize
|
||||
*
|
||||
* @return string The corresponding locale code
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.filtermatches.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function filterMatches($langtag, $locale, $canonicalize = false)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the variants for the input locale
|
||||
*
|
||||
* @param string $locale The locale to extract the variants from
|
||||
*
|
||||
* @return array The locale variants
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getallvariants.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getAllVariants($locale)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default locale
|
||||
*
|
||||
* @return string The default locale code. Always returns 'en'
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getdefault.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getDefault()
|
||||
{
|
||||
return 'en';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the localized display name for the locale language
|
||||
*
|
||||
* @param string $locale The locale code to return the display language from
|
||||
* @param string $inLocale Optional format locale code to use to display the language name
|
||||
*
|
||||
* @return string The localized language display name
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getdisplaylanguage.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getDisplayLanguage($locale, $inLocale = null)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the localized display name for the locale
|
||||
*
|
||||
* @param string $locale The locale code to return the display locale name from
|
||||
* @param string $inLocale Optional format locale code to use to display the locale name
|
||||
*
|
||||
* @return string The localized locale display name
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getdisplayname.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getDisplayName($locale, $inLocale = null)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the localized display name for the locale region
|
||||
*
|
||||
* @param string $locale The locale code to return the display region from
|
||||
* @param string $inLocale Optional format locale code to use to display the region name
|
||||
*
|
||||
* @return string The localized region display name
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getdisplayregion.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getDisplayRegion($locale, $inLocale = null)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the localized display name for the locale script
|
||||
*
|
||||
* @param string $locale The locale code to return the display script from
|
||||
* @param string $inLocale Optional format locale code to use to display the script name
|
||||
*
|
||||
* @return string The localized script display name
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getdisplayscript.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getDisplayScript($locale, $inLocale = null)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the localized display name for the locale variant
|
||||
*
|
||||
* @param string $locale The locale code to return the display variant from
|
||||
* @param string $inLocale Optional format locale code to use to display the variant name
|
||||
*
|
||||
* @return string The localized variant display name
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getdisplayvariant.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getDisplayVariant($locale, $inLocale = null)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keywords for the locale
|
||||
*
|
||||
* @param string $locale The locale code to extract the keywords from
|
||||
*
|
||||
* @return array Associative array with the extracted variants
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getkeywords.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getKeywords($locale)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary language for the locale
|
||||
*
|
||||
* @param string $locale The locale code to extract the language code from
|
||||
*
|
||||
* @return string|null The extracted language code or null in case of error
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getprimarylanguage.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getPrimaryLanguage($locale)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the region for the locale
|
||||
*
|
||||
* @param string $locale The locale code to extract the region code from
|
||||
*
|
||||
* @return string|null The extracted region code or null if not present
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getregion.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getRegion($locale)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the script for the locale
|
||||
*
|
||||
* @param string $locale The locale code to extract the script code from
|
||||
*
|
||||
* @return string|null The extracted script code or null if not present
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.getscript.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function getScript($locale)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest language tag for the locale
|
||||
*
|
||||
* @param array $langtag A list of the language tags to compare to locale
|
||||
* @param string $locale The locale to use as the language range when matching
|
||||
* @param Boolean $canonicalize If true, the arguments will be converted to canonical form before matching
|
||||
* @param string $default The locale to use if no match is found
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.lookup.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function lookup(array $langtag, $locale, $canonicalize = false, $default = null)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an associative array of locale identifier subtags
|
||||
*
|
||||
* @param string $locale The locale code to extract the subtag array from
|
||||
*
|
||||
* @return array Associative array with the extracted subtags
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.parselocale.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function parseLocale($locale)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default runtime locale
|
||||
*
|
||||
* @param string $locale The locale code
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/locale.parselocale.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public static function setDefault($locale)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,869 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\NumberFormatter;
|
||||
|
||||
use Symfony\Component\Intl\Exception\NotImplementedException;
|
||||
use Symfony\Component\Intl\Exception\MethodNotImplementedException;
|
||||
use Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException;
|
||||
use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException;
|
||||
use Symfony\Component\Intl\Globals\StubIntlGlobals;
|
||||
use Symfony\Component\Intl\Intl;
|
||||
use Symfony\Component\Intl\Locale\StubLocale;
|
||||
|
||||
/**
|
||||
* Provides a stub NumberFormatter for the 'en' locale.
|
||||
*
|
||||
* @author Eriksen Costa <eriksen.costa@infranology.com.br>
|
||||
*/
|
||||
class StubNumberFormatter
|
||||
{
|
||||
/** Format style constants */
|
||||
const PATTERN_DECIMAL = 0;
|
||||
const DECIMAL = 1;
|
||||
const CURRENCY = 2;
|
||||
const PERCENT = 3;
|
||||
const SCIENTIFIC = 4;
|
||||
const SPELLOUT = 5;
|
||||
const ORDINAL = 6;
|
||||
const DURATION = 7;
|
||||
const PATTERN_RULEBASED = 9;
|
||||
const IGNORE = 0;
|
||||
const DEFAULT_STYLE = 1;
|
||||
|
||||
/** Format type constants */
|
||||
const TYPE_DEFAULT = 0;
|
||||
const TYPE_INT32 = 1;
|
||||
const TYPE_INT64 = 2;
|
||||
const TYPE_DOUBLE = 3;
|
||||
const TYPE_CURRENCY = 4;
|
||||
|
||||
/** Numeric attribute constants */
|
||||
const PARSE_INT_ONLY = 0;
|
||||
const GROUPING_USED = 1;
|
||||
const DECIMAL_ALWAYS_SHOWN = 2;
|
||||
const MAX_INTEGER_DIGITS = 3;
|
||||
const MIN_INTEGER_DIGITS = 4;
|
||||
const INTEGER_DIGITS = 5;
|
||||
const MAX_FRACTION_DIGITS = 6;
|
||||
const MIN_FRACTION_DIGITS = 7;
|
||||
const FRACTION_DIGITS = 8;
|
||||
const MULTIPLIER = 9;
|
||||
const GROUPING_SIZE = 10;
|
||||
const ROUNDING_MODE = 11;
|
||||
const ROUNDING_INCREMENT = 12;
|
||||
const FORMAT_WIDTH = 13;
|
||||
const PADDING_POSITION = 14;
|
||||
const SECONDARY_GROUPING_SIZE = 15;
|
||||
const SIGNIFICANT_DIGITS_USED = 16;
|
||||
const MIN_SIGNIFICANT_DIGITS = 17;
|
||||
const MAX_SIGNIFICANT_DIGITS = 18;
|
||||
const LENIENT_PARSE = 19;
|
||||
|
||||
/** Text attribute constants */
|
||||
const POSITIVE_PREFIX = 0;
|
||||
const POSITIVE_SUFFIX = 1;
|
||||
const NEGATIVE_PREFIX = 2;
|
||||
const NEGATIVE_SUFFIX = 3;
|
||||
const PADDING_CHARACTER = 4;
|
||||
const CURRENCY_CODE = 5;
|
||||
const DEFAULT_RULESET = 6;
|
||||
const PUBLIC_RULESETS = 7;
|
||||
|
||||
/** Format symbol constants */
|
||||
const DECIMAL_SEPARATOR_SYMBOL = 0;
|
||||
const GROUPING_SEPARATOR_SYMBOL = 1;
|
||||
const PATTERN_SEPARATOR_SYMBOL = 2;
|
||||
const PERCENT_SYMBOL = 3;
|
||||
const ZERO_DIGIT_SYMBOL = 4;
|
||||
const DIGIT_SYMBOL = 5;
|
||||
const MINUS_SIGN_SYMBOL = 6;
|
||||
const PLUS_SIGN_SYMBOL = 7;
|
||||
const CURRENCY_SYMBOL = 8;
|
||||
const INTL_CURRENCY_SYMBOL = 9;
|
||||
const MONETARY_SEPARATOR_SYMBOL = 10;
|
||||
const EXPONENTIAL_SYMBOL = 11;
|
||||
const PERMILL_SYMBOL = 12;
|
||||
const PAD_ESCAPE_SYMBOL = 13;
|
||||
const INFINITY_SYMBOL = 14;
|
||||
const NAN_SYMBOL = 15;
|
||||
const SIGNIFICANT_DIGIT_SYMBOL = 16;
|
||||
const MONETARY_GROUPING_SEPARATOR_SYMBOL = 17;
|
||||
|
||||
/** Rounding mode values used by NumberFormatter::setAttribute() with NumberFormatter::ROUNDING_MODE attribute */
|
||||
const ROUND_CEILING = 0;
|
||||
const ROUND_FLOOR = 1;
|
||||
const ROUND_DOWN = 2;
|
||||
const ROUND_UP = 3;
|
||||
const ROUND_HALFEVEN = 4;
|
||||
const ROUND_HALFDOWN = 5;
|
||||
const ROUND_HALFUP = 6;
|
||||
|
||||
/** Pad position values used by NumberFormatter::setAttribute() with NumberFormatter::PADDING_POSITION attribute */
|
||||
const PAD_BEFORE_PREFIX = 0;
|
||||
const PAD_AFTER_PREFIX = 1;
|
||||
const PAD_BEFORE_SUFFIX = 2;
|
||||
const PAD_AFTER_SUFFIX = 3;
|
||||
|
||||
/**
|
||||
* The error code from the last operation
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $errorCode = StubIntlGlobals::U_ZERO_ERROR;
|
||||
|
||||
/**
|
||||
* The error message from the last operation
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $errorMessage = 'U_ZERO_ERROR';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $locale;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $style;
|
||||
|
||||
/**
|
||||
* Default values for the en locale
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $attributes = array(
|
||||
self::FRACTION_DIGITS => 0,
|
||||
self::GROUPING_USED => 1,
|
||||
self::ROUNDING_MODE => self::ROUND_HALFEVEN
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds the initialized attributes code
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $initializedAttributes = array();
|
||||
|
||||
/**
|
||||
* The supported styles to the constructor $styles argument
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $supportedStyles = array(
|
||||
'CURRENCY' => self::CURRENCY,
|
||||
'DECIMAL' => self::DECIMAL
|
||||
);
|
||||
|
||||
/**
|
||||
* Supported attributes to the setAttribute() $attr argument
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $supportedAttributes = array(
|
||||
'FRACTION_DIGITS' => self::FRACTION_DIGITS,
|
||||
'GROUPING_USED' => self::GROUPING_USED,
|
||||
'ROUNDING_MODE' => self::ROUNDING_MODE
|
||||
);
|
||||
|
||||
/**
|
||||
* The available rounding modes for setAttribute() usage with
|
||||
* StubNumberFormatter::ROUNDING_MODE. StubNumberFormatter::ROUND_DOWN
|
||||
* and StubNumberFormatter::ROUND_UP does not have a PHP only equivalent
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $roundingModes = array(
|
||||
'ROUND_HALFEVEN' => self::ROUND_HALFEVEN,
|
||||
'ROUND_HALFDOWN' => self::ROUND_HALFDOWN,
|
||||
'ROUND_HALFUP' => self::ROUND_HALFUP
|
||||
);
|
||||
|
||||
/**
|
||||
* The mapping between NumberFormatter rounding modes to the available
|
||||
* modes in PHP's round() function.
|
||||
*
|
||||
* @see http://www.php.net/manual/en/function.round.php
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $phpRoundingMap = array(
|
||||
self::ROUND_HALFDOWN => \PHP_ROUND_HALF_DOWN,
|
||||
self::ROUND_HALFEVEN => \PHP_ROUND_HALF_EVEN,
|
||||
self::ROUND_HALFUP => \PHP_ROUND_HALF_UP
|
||||
);
|
||||
|
||||
/**
|
||||
* The maximum values of the integer type in 32 bit platforms.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $int32Range = array(
|
||||
'positive' => 2147483647,
|
||||
'negative' => -2147483648
|
||||
);
|
||||
|
||||
/**
|
||||
* The maximum values of the integer type in 64 bit platforms.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $int64Range = array(
|
||||
'positive' => 9223372036854775807,
|
||||
'negative' => -9223372036854775808
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $locale The locale code
|
||||
* @param int $style Style of the formatting, one of the format style constants
|
||||
* @param string $pattern A pattern string in case $style is NumberFormat::PATTERN_DECIMAL or
|
||||
* NumberFormat::PATTERN_RULEBASED. It must conform to the syntax
|
||||
* described in the ICU DecimalFormat or ICU RuleBasedNumberFormat documentation
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.create.php
|
||||
* @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
|
||||
* @see http://www.icu-project.org/apiref/icu4c/classRuleBasedNumberFormat.html#_details
|
||||
*
|
||||
* @throws MethodArgumentValueNotImplementedException When $locale different than 'en' is passed
|
||||
* @throws MethodArgumentValueNotImplementedException When the $style is not supported
|
||||
* @throws MethodArgumentNotImplementedException When the pattern value is different than null
|
||||
*/
|
||||
public function __construct($locale = 'en', $style = null, $pattern = null)
|
||||
{
|
||||
if ('en' != $locale) {
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the \'en\' locale is supported');
|
||||
}
|
||||
|
||||
if (!in_array($style, self::$supportedStyles)) {
|
||||
$message = sprintf('The available styles are: %s.', implode(', ', array_keys(self::$supportedStyles)));
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'style', $style, $message);
|
||||
}
|
||||
|
||||
if (null !== $pattern) {
|
||||
throw new MethodArgumentNotImplementedException(__METHOD__, 'pattern');
|
||||
}
|
||||
|
||||
$this->locale = $locale;
|
||||
$this->style = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static constructor
|
||||
*
|
||||
* @param string $locale The locale code
|
||||
* @param int $style Style of the formatting, one of the format style constants
|
||||
* @param string $pattern A pattern string in case $style is NumberFormat::PATTERN_DECIMAL or
|
||||
* NumberFormat::PATTERN_RULEBASED. It must conform to the syntax
|
||||
* described in the ICU DecimalFormat or ICU RuleBasedNumberFormat documentation
|
||||
*
|
||||
* @return StubNumberFormatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.create.php
|
||||
* @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
|
||||
* @see http://www.icu-project.org/apiref/icu4c/classRuleBasedNumberFormat.html#_details
|
||||
*
|
||||
* @throws MethodArgumentValueNotImplementedException When $locale different than 'en' is passed
|
||||
* @throws MethodArgumentValueNotImplementedException When the $style is not supported
|
||||
* @throws MethodArgumentNotImplementedException When the pattern value is different than null
|
||||
*/
|
||||
public static function create($locale = 'en', $style = null, $pattern = null)
|
||||
{
|
||||
return new self($locale, $style, $pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a currency value
|
||||
*
|
||||
* @param float $value The numeric currency value
|
||||
* @param string $currency The 3-letter ISO 4217 currency code indicating the currency to use
|
||||
*
|
||||
* @return string The formatted currency value
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.formatcurrency.php
|
||||
* @see http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm
|
||||
*/
|
||||
public function formatCurrency($value, $currency)
|
||||
{
|
||||
if ($this->style == self::DECIMAL) {
|
||||
return $this->format($value);
|
||||
}
|
||||
|
||||
$symbol = Intl::getCurrencyBundle()->getCurrencySymbol('en', $currency);
|
||||
$fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency);
|
||||
|
||||
$value = $this->roundCurrency($value, $currency);
|
||||
|
||||
$negative = false;
|
||||
if (0 > $value) {
|
||||
$negative = true;
|
||||
$value *= -1;
|
||||
}
|
||||
|
||||
$value = $this->formatNumber($value, $fractionDigits);
|
||||
|
||||
$ret = $symbol.$value;
|
||||
|
||||
return $negative ? '('.$ret.')' : $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a number
|
||||
*
|
||||
* @param number $value The value to format
|
||||
* @param int $type Type of the formatting, one of the format type constants
|
||||
*
|
||||
* @return Boolean|string The formatted value or false on error
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.format.php
|
||||
*
|
||||
* @throws \RuntimeException If the method is called with the class $style 'CURRENCY'
|
||||
* @throws MethodArgumentNotImplementedException If the $type is different than TYPE_DEFAULT
|
||||
*/
|
||||
public function format($value, $type = self::TYPE_DEFAULT)
|
||||
{
|
||||
// The original NumberFormatter does not support this format type
|
||||
if ($type == self::TYPE_CURRENCY) {
|
||||
trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->style == self::CURRENCY) {
|
||||
throw new NotImplementedException(sprintf(
|
||||
'%s() method does not support the formatting of currencies (instance with CURRENCY style). %s',
|
||||
__METHOD__, NotImplementedException::INTL_INSTALL_MESSAGE
|
||||
));
|
||||
}
|
||||
|
||||
// Only the default type is supported.
|
||||
if ($type != self::TYPE_DEFAULT) {
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'type', $type, 'Only TYPE_DEFAULT is supported');
|
||||
}
|
||||
|
||||
$fractionDigits = $this->getAttribute(self::FRACTION_DIGITS);
|
||||
|
||||
$value = $this->round($value, $fractionDigits);
|
||||
$value = $this->formatNumber($value, $fractionDigits);
|
||||
|
||||
// behave like the intl extension
|
||||
$this->resetError();
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an attribute value
|
||||
*
|
||||
* @param int $attr An attribute specifier, one of the numeric attribute constants
|
||||
*
|
||||
* @return Boolean|int The attribute value on success or false on error
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.getattribute.php
|
||||
*/
|
||||
public function getAttribute($attr)
|
||||
{
|
||||
return isset($this->attributes[$attr]) ? $this->attributes[$attr] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns formatter's last error code. Always returns the U_ZERO_ERROR class constant value
|
||||
*
|
||||
* @return int The error code from last formatter call
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.geterrorcode.php
|
||||
*/
|
||||
public function getErrorCode()
|
||||
{
|
||||
return $this->errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns formatter's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value
|
||||
*
|
||||
* @return string The error message from last formatter call
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.geterrormessage.php
|
||||
*/
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return $this->errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's locale
|
||||
*
|
||||
* @param int $type The locale name type to return between valid or actual (StubLocale::VALID_LOCALE or StubLocale::ACTUAL_LOCALE, respectively)
|
||||
*
|
||||
* @return string The locale name used to create the formatter
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.getlocale.php
|
||||
*/
|
||||
public function getLocale($type = StubLocale::ACTUAL_LOCALE)
|
||||
{
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter's pattern
|
||||
*
|
||||
* @return Boolean|string The pattern string used by the formatter or false on error
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.getpattern.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function getPattern()
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatter symbol value
|
||||
*
|
||||
* @param int $attr A symbol specifier, one of the format symbol constants
|
||||
*
|
||||
* @return Boolean|string The symbol value or false on error
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.getsymbol.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function getSymbol($attr)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatter text attribute value
|
||||
*
|
||||
* @param int $attr An attribute specifier, one of the text attribute constants
|
||||
*
|
||||
* @return Boolean|string The attribute value or false on error
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.gettextattribute.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function getTextAttribute($attr)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a currency number
|
||||
*
|
||||
* @param string $value The value to parse
|
||||
* @param string $currency Parameter to receive the currency name (reference)
|
||||
* @param int $position Offset to begin the parsing on return this value will hold the offset at which the parsing ended
|
||||
*
|
||||
* @return Boolean|string The parsed numeric value of false on error
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.parsecurrency.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function parseCurrency($value, &$currency, &$position = null)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a number
|
||||
*
|
||||
* @param string $value The value to parse
|
||||
* @param string $type Type of the formatting, one of the format type constants. NumberFormatter::TYPE_DOUBLE by default
|
||||
* @param int $position Offset to begin the parsing on return this value will hold the offset at which the parsing ended
|
||||
*
|
||||
* @return Boolean|string The parsed value of false on error
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.parse.php
|
||||
*
|
||||
* @throws MethodArgumentNotImplementedException When $position different than null, behavior not implemented
|
||||
*/
|
||||
public function parse($value, $type = self::TYPE_DOUBLE, &$position = null)
|
||||
{
|
||||
if ($type == self::TYPE_DEFAULT || $type == self::TYPE_CURRENCY) {
|
||||
trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't calculate the position when parsing the value
|
||||
if (null !== $position) {
|
||||
throw new MethodArgumentNotImplementedException(__METHOD__, 'position');
|
||||
}
|
||||
|
||||
preg_match('/^([^0-9\-]{0,})(.*)/', $value, $matches);
|
||||
|
||||
// Any string before the numeric value causes error in the parsing
|
||||
if (isset($matches[1]) && !empty($matches[1])) {
|
||||
StubIntlGlobals::setError(StubIntlGlobals::U_PARSE_ERROR, 'Number parsing failed');
|
||||
$this->errorCode = StubIntlGlobals::getErrorCode();
|
||||
$this->errorMessage = StubIntlGlobals::getErrorMessage();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove everything that is not number or dot (.)
|
||||
$value = preg_replace('/[^0-9\.\-]/', '', $value);
|
||||
$value = $this->convertValueDataType($value, $type);
|
||||
|
||||
// behave like the intl extension
|
||||
$this->resetError();
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an attribute
|
||||
*
|
||||
* @param int $attr An attribute specifier, one of the numeric attribute constants
|
||||
* @param int $value The attribute value
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.setattribute.php
|
||||
*
|
||||
* @throws MethodArgumentValueNotImplementedException When the $attr is not supported
|
||||
* @throws MethodArgumentValueNotImplementedException When the $value is not supported
|
||||
*/
|
||||
public function setAttribute($attr, $value)
|
||||
{
|
||||
if (!in_array($attr, self::$supportedAttributes)) {
|
||||
$message = sprintf(
|
||||
'The available attributes are: %s',
|
||||
implode(', ', array_keys(self::$supportedAttributes))
|
||||
);
|
||||
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'attr', $value, $message);
|
||||
}
|
||||
|
||||
if (self::$supportedAttributes['ROUNDING_MODE'] == $attr && $this->isInvalidRoundingMode($value)) {
|
||||
$message = sprintf(
|
||||
'The supported values for ROUNDING_MODE are: %s',
|
||||
implode(', ', array_keys(self::$roundingModes))
|
||||
);
|
||||
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'attr', $value, $message);
|
||||
}
|
||||
|
||||
if (self::$supportedAttributes['GROUPING_USED'] == $attr) {
|
||||
$value = $this->normalizeGroupingUsedValue($value);
|
||||
}
|
||||
|
||||
if (self::$supportedAttributes['FRACTION_DIGITS'] == $attr) {
|
||||
$value = $this->normalizeFractionDigitsValue($value);
|
||||
}
|
||||
|
||||
$this->attributes[$attr] = $value;
|
||||
$this->initializedAttributes[$attr] = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the formatter's pattern
|
||||
*
|
||||
* @param string $pattern A pattern string in conformance with the ICU DecimalFormat documentation
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.setpattern.php
|
||||
* @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function setPattern($pattern)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the formatter's symbol
|
||||
*
|
||||
* @param int $attr A symbol specifier, one of the format symbol constants
|
||||
* @param string $value The value for the symbol
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.setsymbol.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function setSymbol($attr, $value)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a text attribute
|
||||
*
|
||||
* @param int $attr An attribute specifier, one of the text attribute constants
|
||||
* @param int $value The attribute value
|
||||
*
|
||||
* @return Boolean true on success or false on failure
|
||||
*
|
||||
* @see http://www.php.net/manual/en/numberformatter.settextattribute.php
|
||||
*
|
||||
* @throws MethodNotImplementedException
|
||||
*/
|
||||
public function setTextAttribute($attr, $value)
|
||||
{
|
||||
throw new MethodNotImplementedException(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the error to the default U_ZERO_ERROR
|
||||
*/
|
||||
protected function resetError()
|
||||
{
|
||||
StubIntlGlobals::setError(StubIntlGlobals::U_ZERO_ERROR);
|
||||
$this->errorCode = StubIntlGlobals::getErrorCode();
|
||||
$this->errorMessage = StubIntlGlobals::getErrorMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds a currency value, applying increment rounding if applicable
|
||||
*
|
||||
* When a currency have a rounding increment, an extra round is made after the first one. The rounding factor is
|
||||
* determined in the ICU data and is explained as of:
|
||||
*
|
||||
* "the rounding increment is given in units of 10^(-fraction_digits)"
|
||||
*
|
||||
* The only actual rounding data as of this writing, is CHF.
|
||||
*
|
||||
* @param float $value The numeric currency value
|
||||
* @param string $currency The 3-letter ISO 4217 currency code indicating the currency to use
|
||||
*
|
||||
* @return string The rounded numeric currency value
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Swedish_rounding
|
||||
* @see http://www.docjar.com/html/api/com/ibm/icu/util/Currency.java.html#1007
|
||||
*/
|
||||
private function roundCurrency($value, $currency)
|
||||
{
|
||||
$fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency);
|
||||
$roundingIncrement = Intl::getCurrencyBundle()->getRoundingIncrement($currency);
|
||||
|
||||
// Round with the formatter rounding mode
|
||||
$value = $this->round($value, $fractionDigits);
|
||||
|
||||
// Swiss rounding
|
||||
if (0 < $roundingIncrement && 0 < $fractionDigits) {
|
||||
$roundingFactor = $roundingIncrement / pow(10, $fractionDigits);
|
||||
$value = round($value / $roundingFactor) * $roundingFactor;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds a value.
|
||||
*
|
||||
* @param integer|float $value The value to round
|
||||
* @param int $precision The number of decimal digits to round to
|
||||
*
|
||||
* @return integer|float The rounded value
|
||||
*/
|
||||
private function round($value, $precision)
|
||||
{
|
||||
$precision = $this->getUnitializedPrecision($value, $precision);
|
||||
|
||||
$roundingMode = self::$phpRoundingMap[$this->getAttribute(self::ROUNDING_MODE)];
|
||||
$value = round($value, $precision, $roundingMode);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a number.
|
||||
*
|
||||
* @param integer|float $value The numeric value to format
|
||||
* @param int $precision The number of decimal digits to use
|
||||
*
|
||||
* @return string The formatted number
|
||||
*/
|
||||
private function formatNumber($value, $precision)
|
||||
{
|
||||
$precision = $this->getUnitializedPrecision($value, $precision);
|
||||
|
||||
return number_format($value, $precision, '.', $this->getAttribute(self::GROUPING_USED) ? ',' : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the precision value if the the DECIMAL style is being used and the FRACTION_DIGITS attribute is unitialized.
|
||||
*
|
||||
* @param integer|float $value The value to get the precision from if the FRACTION_DIGITS attribute is unitialized
|
||||
* @param int $precision The precision value to returns if the FRACTION_DIGITS attribute is initialized
|
||||
*
|
||||
* @return int The precision value
|
||||
*/
|
||||
private function getUnitializedPrecision($value, $precision)
|
||||
{
|
||||
if ($this->style == self::CURRENCY) {
|
||||
return $precision;
|
||||
}
|
||||
|
||||
if (!$this->isInitializedAttribute(self::FRACTION_DIGITS)) {
|
||||
preg_match('/.*\.(.*)/', (string) $value, $digits);
|
||||
if (isset($digits[1])) {
|
||||
$precision = strlen($digits[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return $precision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the attribute is initialized (value set by client code).
|
||||
*
|
||||
* @param string $attr The attribute name
|
||||
*
|
||||
* @return Boolean true if the value was set by client, false otherwise
|
||||
*/
|
||||
private function isInitializedAttribute($attr)
|
||||
{
|
||||
return isset($this->initializedAttributes[$attr]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numeric value using the $type to convert to the right data type.
|
||||
*
|
||||
* @param mixed $value The value to be converted
|
||||
* @param int $type The type to convert. Can be TYPE_DOUBLE (float) or TYPE_INT32 (int)
|
||||
*
|
||||
* @return integer|float The converted value
|
||||
*/
|
||||
private function convertValueDataType($value, $type)
|
||||
{
|
||||
if ($type == self::TYPE_DOUBLE) {
|
||||
$value = (float) $value;
|
||||
} elseif ($type == self::TYPE_INT32) {
|
||||
$value = $this->getInt32Value($value);
|
||||
} elseif ($type == self::TYPE_INT64) {
|
||||
$value = $this->getInt64Value($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value data type to int or returns false if the value is out of the integer value range.
|
||||
*
|
||||
* @param mixed $value The value to be converted
|
||||
*
|
||||
* @return int The converted value
|
||||
*/
|
||||
private function getInt32Value($value)
|
||||
{
|
||||
if ($value > self::$int32Range['positive'] || $value < self::$int32Range['negative']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value data type to int or returns false if the value is out of the integer value range.
|
||||
*
|
||||
* @param mixed $value The value to be converted
|
||||
*
|
||||
* @return int|float The converted value
|
||||
*
|
||||
* @see https://bugs.php.net/bug.php?id=59597 Bug #59597
|
||||
*/
|
||||
private function getInt64Value($value)
|
||||
{
|
||||
if ($value > self::$int64Range['positive'] || $value < self::$int64Range['negative']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PHP_INT_SIZE !== 8 && ($value > self::$int32Range['positive'] || $value <= self::$int32Range['negative'])) {
|
||||
// Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
|
||||
// The negative PHP_INT_MAX was being converted to float
|
||||
if (
|
||||
$value == self::$int32Range['negative'] &&
|
||||
(
|
||||
(version_compare(PHP_VERSION, '5.4.0', '<') && version_compare(PHP_VERSION, '5.3.14', '>=')) ||
|
||||
version_compare(PHP_VERSION, '5.4.4', '>=')
|
||||
)
|
||||
) {
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
return (float) $value;
|
||||
}
|
||||
|
||||
if (PHP_INT_SIZE === 8) {
|
||||
// Bug #59597 was fixed on PHP 5.3.14 and 5.4.4
|
||||
// A 32 bit integer was being generated instead of a 64 bit integer
|
||||
if (
|
||||
($value > self::$int32Range['positive'] || $value < self::$int32Range['negative']) &&
|
||||
(
|
||||
(version_compare(PHP_VERSION, '5.3.14', '<')) ||
|
||||
(version_compare(PHP_VERSION, '5.4.0', '>=') && version_compare(PHP_VERSION, '5.4.4', '<'))
|
||||
)
|
||||
) {
|
||||
$value = (-2147483648 - ($value % -2147483648)) * ($value / abs($value));
|
||||
}
|
||||
}
|
||||
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the rounding mode is invalid.
|
||||
*
|
||||
* @param int $value The rounding mode value to check
|
||||
*
|
||||
* @return Boolean true if the rounding mode is invalid, false otherwise
|
||||
*/
|
||||
private function isInvalidRoundingMode($value)
|
||||
{
|
||||
if (in_array($value, self::$roundingModes, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the normalized value for the GROUPING_USED attribute. Any value that can be converted to int will be
|
||||
* cast to Boolean and then to int again. This way, negative values are converted to 1 and string values to 0.
|
||||
*
|
||||
* @param mixed $value The value to be normalized
|
||||
*
|
||||
* @return int The normalized value for the attribute (0 or 1)
|
||||
*/
|
||||
private function normalizeGroupingUsedValue($value)
|
||||
{
|
||||
return (int) (Boolean) (int) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the normalized value for the FRACTION_DIGITS attribute. The value is converted to int and if negative,
|
||||
* the returned value will be 0.
|
||||
*
|
||||
* @param mixed $value The value to be normalized
|
||||
*
|
||||
* @return int The normalized value for the attribute
|
||||
*/
|
||||
private function normalizeFractionDigitsValue($value)
|
||||
{
|
||||
$value = (int) $value;
|
||||
|
||||
return (0 > $value) ? 0 : $value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
Intl Component
|
||||
=============
|
||||
|
||||
A PHP replacement layer for the C intl extension that includes additional data
|
||||
from the ICU library.
|
||||
|
||||
The replacement layer is limited to the locale "en". If you want to use other
|
||||
locales, you should [install the intl extension] [10] instead.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
You can install the component in two different ways:
|
||||
|
||||
* Using the official Git repository (https://github.com/symfony/Intl);
|
||||
* [Install it via Composer] [0] (`symfony/intl` on [Packagist] [1]).
|
||||
|
||||
If you install the component via Composer, the following classes and functions
|
||||
of the intl extension will be automatically provided if the intl extension is
|
||||
not loaded:
|
||||
|
||||
* [`\Locale`] [2]
|
||||
* [`\NumberFormatter`] [3]
|
||||
* [`\IntlDateFormatter`] [4]
|
||||
* [`\Collator`] [5]
|
||||
* [`intl_is_failure()`] [6]
|
||||
* [`intl_get_error_code()`] [7]
|
||||
* [`intl_get_error_message()`] [8]
|
||||
* [`intl_error_name()`] [9]
|
||||
|
||||
If you don't use Composer but the Symfony ClassLoader component, you need to
|
||||
load them manually by adding the following lines to your autoload code:
|
||||
|
||||
if (!function_exists('intl_is_failure')) {
|
||||
require '/path/to/Icu/Resources/stubs/functions.php';
|
||||
|
||||
$loader->registerPrefixFallback('/path/to/Icu/Resources/stubs');
|
||||
}
|
||||
|
||||
Stubbed Classes
|
||||
---------------
|
||||
|
||||
The stubbed classes of the intl extension are limited to the locale "en" and
|
||||
will throw an exception if you try to use a different locale. For using other
|
||||
locales, [install the intl extension] [10] instead.
|
||||
|
||||
### Locale
|
||||
|
||||
The only method supported in the [´\Locale`] [2] class is `getDefault()` and
|
||||
will always return "en". All other methods will throw an exception when used.
|
||||
|
||||
### NumberFormatter
|
||||
|
||||
Numbers can be formatted with the [`\NumberFormatter`] [3] class. The following
|
||||
methods are supported. All other methods are not supported and will throw an
|
||||
exception when used.
|
||||
|
||||
##### __construct($locale = 'en', $style = null, $pattern = null)
|
||||
|
||||
The only supported locale is "en". The supported styles are
|
||||
`\NumberFormatter::DECIMAL` and `\NumberFormatter::CURRENCY`. The argument
|
||||
`$pattern` may not be used.
|
||||
|
||||
##### ::create($locale = 'en', $style = null, $pattern = null)
|
||||
|
||||
See `__construct()`.
|
||||
|
||||
##### formatCurrency($value, $currency)
|
||||
|
||||
Fully supported.
|
||||
|
||||
##### format($value, $type = \NumberFormatter::TYPE_DEFAULT)
|
||||
|
||||
Only type `\NumberFormatter::TYPE_DEFAULT` is supported.
|
||||
|
||||
##### getAttribute($attr)
|
||||
|
||||
Fully supported.
|
||||
|
||||
##### getErrorCode()
|
||||
|
||||
Fully supported.
|
||||
|
||||
##### getErrorMessage()
|
||||
|
||||
Fully supported.
|
||||
|
||||
##### getLocale($type = \Locale::ACTUAL_LOCALE)
|
||||
|
||||
The parameter `$type` is ignored.
|
||||
|
||||
##### parse($value, $type = \NumberFormatter::TYPE_DOUBLE, &$position = null)
|
||||
|
||||
The supported types are `\NumberFormatter::TYPE_DOUBLE`,
|
||||
`\NumberFormatter::TYPE_INT32` and `\NumberFormatter::TYPE_INT64`. The
|
||||
parameter `$position` must always be `null`.
|
||||
|
||||
##### setAttribute($attr, $value)
|
||||
|
||||
The only supported attributes are `\NumberFormatter::FRACTION_DIGITS`,
|
||||
`\NumberFormatter::GROUPING_USED` and `\NumberFormatter::ROUNDING_MODE`.
|
||||
|
||||
The only supported rounding modes are `\NumberFormatter::ROUND_HALFEVEN`,
|
||||
`\NumberFormatter::ROUND_HALFDOWN` and `\NumberFormatter::ROUND_HALFUP`.
|
||||
|
||||
Included Resource Bundles
|
||||
-------------------------
|
||||
|
||||
The ICU data is located in several "resource bundles". You can access a PHP
|
||||
wrapper of these bundles through the static Intl class.
|
||||
|
||||
Languages and Scripts
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The translations of language and script names can be found in the language
|
||||
bundle.
|
||||
|
||||
$languages = Intl::getLanguageBundle()->getLanguageNames('en');
|
||||
// => array('ab' => 'Abkhazian', ...)
|
||||
|
||||
$language = Intl::getLanguageBundle()->getLanguageName('en', 'de');
|
||||
// => 'German'
|
||||
|
||||
$language = Intl::getLanguageBundle()->getLanguageName('en', 'de', 'AT);
|
||||
// => 'Austrian German'
|
||||
|
||||
$scripts = Intl::getLanguageBundle()->getScriptNames('en');
|
||||
// => array('Arab' => 'Arabic', ...)
|
||||
|
||||
$script = Intl::getLanguageBundle()->getScriptName('en', 'Hans');
|
||||
// => 'Simplified'
|
||||
|
||||
Countries
|
||||
~~~~~~~~~
|
||||
|
||||
The translations of country names can be found in the region bundle.
|
||||
|
||||
$countries = Intl::getRegionBundle()->getCountryNames('en');
|
||||
// => array('AF' => 'Afghanistan', ...)
|
||||
|
||||
$country = Intl::getRegionBundle()->getCountryName('en', 'GB');
|
||||
// => 'United Kingdom'
|
||||
|
||||
Locales
|
||||
~~~~~~~
|
||||
|
||||
The translations of locale names can be found in the locale bundle.
|
||||
|
||||
$locales = Intl::getLocaleBundle()->getLocaleNames('en');
|
||||
// => array('af' => 'Afrikaans', ...)
|
||||
|
||||
$locale = Intl::getLocaleBundle()->getLocaleName('en', 'zh_Hans_MO');
|
||||
// => 'Chinese (Simplified, Macau SAR China)'
|
||||
|
||||
Currencies
|
||||
~~~~~~~~~~
|
||||
|
||||
The translations of currency names and other currency-related information can
|
||||
be found in the currency bundle.
|
||||
|
||||
$currencies = Intl::getCurrencyBundle()->getCurrencyNames('en');
|
||||
// => array('AFN' => 'Afghan Afghani', ...)
|
||||
|
||||
$currency = Intl::getCurrencyBundle()->getCurrencyNames('en', 'INR');
|
||||
// => 'Indian Rupee'
|
||||
|
||||
$symbol = Intl::getCurrencyBundle()->getCurrencyNames('en', 'INR');
|
||||
// => '₹'
|
||||
|
||||
$fractionDigits = Intl::getCurrencyBundle()->getFractionDigits('INR');
|
||||
// => 2
|
||||
|
||||
$roundingIncrement = Intl::getCurrencyBundle()->getRoundingIncrement('INR');
|
||||
// => 0
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
$ cd path/to/Symfony/Component/Intl/
|
||||
$ composer.phar install --dev
|
||||
$ phpunit
|
||||
|
||||
[0]: /components/using_components
|
||||
[1]: https://packagist.org/packages/symfony/intl
|
||||
[2]: http://www.php.net/manual/en/class.locale.php
|
||||
[3]: http://www.php.net/manual/en/class.numberformatter.php
|
||||
[4]: http://www.php.net/manual/en/class.intldateformatter.php
|
||||
[5]: http://www.php.net/manual/en/class.collator.php
|
||||
[6]: http://www.php.net/manual/en/function.intl-error-name.php
|
||||
[7]: http://www.php.net/manual/en/function.intl-get-error-code.php
|
||||
[8]: http://www.php.net/manual/en/function.intl-get-error-message.php
|
||||
[9]: http://www.php.net/manual/en/function.intl-is-failure.php
|
||||
[10]: http://www.php.net/manual/en/intl.setup.php
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
use Symfony\Component\Intl\Intl;
|
||||
use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
|
||||
|
||||
/**
|
||||
* Base class for {@link ResourceBundleInterface} implementations.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
abstract class AbstractBundle implements ResourceBundleInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* @var StructuredBundleReaderInterface
|
||||
*/
|
||||
private $reader;
|
||||
|
||||
/**
|
||||
* Creates a bundle at the given path using the given reader for reading
|
||||
* bundle entries.
|
||||
*
|
||||
* @param string $path The path to the bundle.
|
||||
* @param StructuredBundleReaderInterface $reader The reader for reading
|
||||
* the bundle.
|
||||
*/
|
||||
public function __construct($path, StructuredBundleReaderInterface $reader)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->reader = $reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocales()
|
||||
{
|
||||
return $this->reader->getLocales($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy method for {@link StructuredBundleReaderInterface#read}.
|
||||
*/
|
||||
protected function read($locale)
|
||||
{
|
||||
return $this->reader->read($this->path, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy method for {@link StructuredBundleReaderInterface#readEntry}.
|
||||
*/
|
||||
protected function readEntry($locale, array $indices, $mergeFallback = false)
|
||||
{
|
||||
return $this->reader->readEntry($this->path, $locale, $indices, $mergeFallback);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Compiler;
|
||||
|
||||
use Symfony\Component\Intl\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Compiles .txt resource bundles to binary .res files.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class BundleCompiler implements ResourceBundleCompilerInterface
|
||||
{
|
||||
/**
|
||||
* @var string The path to the "genrb" executable.
|
||||
*/
|
||||
private $genrb;
|
||||
|
||||
/**
|
||||
* Creates a new compiler based on the "genrb" executable.
|
||||
*
|
||||
* @param string $genrb Optional. The path to the "genrb" executable.
|
||||
*
|
||||
* @throws RuntimeException If the "genrb" cannot be found.
|
||||
*/
|
||||
public function __construct($genrb = 'genrb')
|
||||
{
|
||||
exec('which ' . $genrb, $output, $status);
|
||||
|
||||
if (0 !== $status) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'The command "%s" is not installed',
|
||||
$genrb
|
||||
));
|
||||
}
|
||||
|
||||
$this->genrb = $genrb;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function compile($sourcePath, $targetDir)
|
||||
{
|
||||
if (is_dir($sourcePath)) {
|
||||
$sourcePath .= '/*.txt';
|
||||
}
|
||||
|
||||
exec($this->genrb.' --quiet -e UTF-8 -d '.$targetDir.' '.$sourcePath, $output, $status);
|
||||
|
||||
if ($status !== 0) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'genrb failed with status %d while compiling %s to %s.',
|
||||
$status,
|
||||
$sourcePath,
|
||||
$targetDir
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Compiler;
|
||||
|
||||
/**
|
||||
* Compiles a resource bundle.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface ResourceBundleCompilerInterface
|
||||
{
|
||||
/**
|
||||
* Compiles a resource bundle at the given source to the given target
|
||||
* directory.
|
||||
*
|
||||
* @param string $sourcePath
|
||||
* @param string $targetDir
|
||||
*/
|
||||
public function compile($sourcePath, $targetDir);
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link CurrencyBundleInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class CurrencyBundle extends AbstractBundle implements CurrencyBundleInterface
|
||||
{
|
||||
const INDEX_NAME = 0;
|
||||
|
||||
const INDEX_SYMBOL = 1;
|
||||
|
||||
const INDEX_FRACTION_DIGITS = 2;
|
||||
|
||||
const INDEX_ROUNDING_INCREMENT = 3;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCurrencySymbol($locale, $currency)
|
||||
{
|
||||
return $this->readEntry($locale, array('Currencies', $currency, static::INDEX_SYMBOL));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCurrencyName($locale, $currency)
|
||||
{
|
||||
return $this->readEntry($locale, array('Currencies', $currency, static::INDEX_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCurrencyNames($locale)
|
||||
{
|
||||
if (null === ($currencies = $this->readEntry($locale, array('Currencies')))) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($currencies instanceof \Traversable) {
|
||||
$currencies = iterator_to_array($currencies);
|
||||
}
|
||||
|
||||
$index = static::INDEX_NAME;
|
||||
|
||||
array_walk($currencies, function (&$value) use ($index) {
|
||||
$value = $value[$index];
|
||||
});
|
||||
|
||||
return $currencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFractionDigits($currency)
|
||||
{
|
||||
return $this->readEntry('en', array('Currencies', $currency, static::INDEX_FRACTION_DIGITS));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRoundingIncrement($currency)
|
||||
{
|
||||
return $this->readEntry('en', array('Currencies', $currency, static::INDEX_ROUNDING_INCREMENT));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
/**
|
||||
* Gives access to currency-related ICU data.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface CurrencyBundleInterface extends ResourceBundleInterface
|
||||
{
|
||||
/**
|
||||
* Returns the symbol used for a currency.
|
||||
*
|
||||
* @param string $locale The locale to return the result in.
|
||||
* @param string $currency A currency code (e.g. "EUR").
|
||||
*
|
||||
* @return string|null The currency symbol or NULL if not found.
|
||||
*/
|
||||
public function getCurrencySymbol($locale, $currency);
|
||||
|
||||
/**
|
||||
* Returns the name of a currency.
|
||||
*
|
||||
* @param string $locale The locale to return the name in.
|
||||
* @param string $currency A currency code (e.g. "EUR").
|
||||
*
|
||||
* @return string|null The name of the currency or NULL if not found.
|
||||
*/
|
||||
public function getCurrencyName($locale, $currency);
|
||||
|
||||
/**
|
||||
* Returns the names of all known currencies.
|
||||
*
|
||||
* @param string $locale The locale to return the names in.
|
||||
*
|
||||
* @return string[] A list of currency names indexed by currency codes.
|
||||
*/
|
||||
public function getCurrencyNames($locale);
|
||||
|
||||
/**
|
||||
* Returns the number of digits after the comma of a currency.
|
||||
*
|
||||
* @param string $currency A currency code (e.g. "EUR").
|
||||
*
|
||||
* @return integer|null The number of digits after the comma or NULL if not found.
|
||||
*/
|
||||
public function getFractionDigits($currency);
|
||||
|
||||
/**
|
||||
* Returns the rounding increment of a currency.
|
||||
*
|
||||
* The rounding increment indicates to which number a currency is rounded.
|
||||
* For example, 1230 rounded to the nearest 50 is 1250. 1.234 rounded to the
|
||||
* nearest 0.65 is 1.3.
|
||||
*
|
||||
* @param string $currency A currency code (e.g. "EUR").
|
||||
*
|
||||
* @return float|integer|null The rounding increment or NULL if not found.
|
||||
*/
|
||||
public function getRoundingIncrement($currency);
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link LanguageBundleInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class LanguageBundle extends AbstractBundle implements LanguageBundleInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLanguageName($locale, $lang, $region = null)
|
||||
{
|
||||
if (null === ($languages = $this->readEntry($locale, array('Languages')))) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Some languages are translated together with their region,
|
||||
// i.e. "en_GB" is translated as "British English"
|
||||
if (null !== $region && isset($languages[$lang.'_'.$region])) {
|
||||
return $languages[$lang.'_'.$region];
|
||||
}
|
||||
|
||||
return $languages[$lang];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLanguageNames($locale)
|
||||
{
|
||||
if (null === ($languages = $this->readEntry($locale, array('Languages')))) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($languages instanceof \Traversable) {
|
||||
$languages = iterator_to_array($languages);
|
||||
}
|
||||
|
||||
return $languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScriptName($locale, $script, $lang = null)
|
||||
{
|
||||
$data = $this->read($locale);
|
||||
|
||||
// Some languages are translated together with their script,
|
||||
// e.g. "zh_Hans" is translated as "Simplified Chinese"
|
||||
if (null !== $lang && isset($data['Languages'][$lang.'_'.$script])) {
|
||||
$langName = $data['Languages'][$lang.'_'.$script];
|
||||
|
||||
// If the script is appended in braces, extract it, e.g. "zh_Hans"
|
||||
// is translated as "Chinesisch (vereinfacht)" in locale "de"
|
||||
if (strpos($langName, '(') !== false) {
|
||||
list($langName, $scriptName) = preg_split('/[\s()]/', $langName, null, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
return $scriptName;
|
||||
}
|
||||
}
|
||||
|
||||
// "af" (Afrikaans) has no "Scripts" block
|
||||
if (!isset($data['Scripts'][$script])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $data['Scripts'][$script];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScriptNames($locale)
|
||||
{
|
||||
if (null === ($scripts = $this->readEntry($locale, array('Scripts')))) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($scripts instanceof \Traversable) {
|
||||
$scripts = iterator_to_array($scripts);
|
||||
}
|
||||
|
||||
return $scripts;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
/**
|
||||
* Gives access to language-related ICU data.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface LanguageBundleInterface extends ResourceBundleInterface
|
||||
{
|
||||
/**
|
||||
* Returns the name of a language.
|
||||
*
|
||||
* @param string $locale The locale to return the name in.
|
||||
* @param string $lang A language code (e.g. "en").
|
||||
* @param string|null $region Optional. A region code (e.g. "US").
|
||||
*
|
||||
* @return string|null The name of the language or NULL if not found.
|
||||
*/
|
||||
public function getLanguageName($locale, $lang, $region = null);
|
||||
|
||||
/**
|
||||
* Returns the names of all known languages.
|
||||
*
|
||||
* @param string $locale The locale to return the names in.
|
||||
*
|
||||
* @return string[] A list of language names indexed by language codes.
|
||||
*/
|
||||
public function getLanguageNames($locale);
|
||||
|
||||
/**
|
||||
* Returns the name of a script.
|
||||
*
|
||||
* @param string $locale The locale to return the name in.
|
||||
* @param string $script A script code (e.g. "Hans").
|
||||
* @param string $lang Optional. A language code (e.g. "zh").
|
||||
*
|
||||
* @return string|null The name of the script or NULL if not found.
|
||||
*/
|
||||
public function getScriptName($locale, $script, $lang = null);
|
||||
|
||||
/**
|
||||
* Returns the names of all known scripts.
|
||||
*
|
||||
* @param string $locale The locale to return the names in.
|
||||
*
|
||||
* @return string[] A list of script names indexed by script codes.
|
||||
*/
|
||||
public function getScriptNames($locale);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link LocaleBundleInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class LocaleBundle extends AbstractBundle implements LocaleBundleInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocaleName($locale, $ofLocale)
|
||||
{
|
||||
return $this->readEntry($locale, array('Locales', $ofLocale));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocaleNames($locale)
|
||||
{
|
||||
if (null === ($locales = $this->readEntry($locale, array('Locales')))) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($locales instanceof \Traversable) {
|
||||
$locales = iterator_to_array($locales);
|
||||
}
|
||||
|
||||
return $locales;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
/**
|
||||
* Gives access to locale-related ICU data.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface LocaleBundleInterface extends ResourceBundleInterface
|
||||
{
|
||||
/**
|
||||
* Returns the name of a locale.
|
||||
*
|
||||
* @param string $locale The locale to return the name in.
|
||||
* @param string $ofLocale The locale to return the name of (e.g. "de_AT").
|
||||
*
|
||||
* @return string|null The name of the locale or NULL if not found.
|
||||
*/
|
||||
public function getLocaleName($locale, $ofLocale);
|
||||
|
||||
/**
|
||||
* Returns the names of all known locales.
|
||||
*
|
||||
* @param string $locale The locale to return the name in.
|
||||
*
|
||||
* @return string[] A list of locale names indexed by locale codes.
|
||||
*/
|
||||
public function getLocaleNames($locale);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Reader;
|
||||
|
||||
/**
|
||||
* Base class for {@link BundleReaderInterface} implementations.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
abstract class AbstractBundleReader implements BundleReaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocales($path)
|
||||
{
|
||||
$extension = '.' . $this->getFileExtension();
|
||||
$locales = glob($path . '/*' . $extension);
|
||||
|
||||
// Remove file extension and sort
|
||||
array_walk($locales, function (&$locale) use ($extension) { $locale = basename($locale, $extension); });
|
||||
sort($locales);
|
||||
|
||||
return $locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extension of locale files in this bundle.
|
||||
*
|
||||
* @return string The file extension (without leading dot).
|
||||
*/
|
||||
abstract protected function getFileExtension();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Reader;
|
||||
|
||||
use Symfony\Component\Intl\Exception\RuntimeException;
|
||||
use Symfony\Component\Intl\ResourceBundle\Util\ArrayAccessibleResourceBundle;
|
||||
|
||||
/**
|
||||
* Reads binary .res resource bundles.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class BinaryBundleReader extends AbstractBundleReader implements BundleReaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($path, $locale)
|
||||
{
|
||||
// Point for future extension: Modify this class so that it works also
|
||||
// if the \ResourceBundle class is not available.
|
||||
$bundle = new \ResourceBundle($locale, $path);
|
||||
|
||||
if (null === $bundle) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'Could not load the resource bundle "%s/%s.res".',
|
||||
$path,
|
||||
$locale
|
||||
));
|
||||
}
|
||||
|
||||
return new ArrayAccessibleResourceBundle($bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getFileExtension()
|
||||
{
|
||||
return 'res';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Reader;
|
||||
|
||||
use Symfony\Component\Intl\ResourceBundle\Util\RingBuffer;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class BufferedReader implements BundleReaderInterface
|
||||
{
|
||||
/**
|
||||
* @var BundleReaderInterface
|
||||
*/
|
||||
private $reader;
|
||||
|
||||
|
||||
private $buffer;
|
||||
|
||||
/**
|
||||
* Buffers a given reader.
|
||||
*
|
||||
* @param BundleReaderInterface $reader The reader to buffer.
|
||||
* @param integer $bufferSize The number of entries to store
|
||||
* in the buffer.
|
||||
*/
|
||||
public function __construct(BundleReaderInterface $reader, $bufferSize)
|
||||
{
|
||||
$this->reader = $reader;
|
||||
$this->buffer = new RingBuffer($bufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($path, $locale)
|
||||
{
|
||||
$hash = $path . '//' . $locale;
|
||||
|
||||
if (!isset($this->buffer[$hash])) {
|
||||
$this->buffer[$hash] = $this->reader->read($path, $locale);
|
||||
}
|
||||
|
||||
return $this->buffer[$hash];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocales($path)
|
||||
{
|
||||
return $this->reader->getLocales($path);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Reader;
|
||||
|
||||
/**
|
||||
* Reads resource bundle files.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface BundleReaderInterface
|
||||
{
|
||||
/**
|
||||
* Reads a resource bundle.
|
||||
*
|
||||
* @param string $path The path to the resource bundle.
|
||||
* @param string $locale The locale to read.
|
||||
*
|
||||
* @return mixed Returns an array or {@link \ArrayAccess} instance for
|
||||
* complex data, a scalar value otherwise.
|
||||
*/
|
||||
public function read($path, $locale);
|
||||
|
||||
/**
|
||||
* Reads the available locales of a resource bundle.
|
||||
*
|
||||
* @param string $path The path to the resource bundle.
|
||||
*
|
||||
* @return string[] A list of supported locale codes.
|
||||
*/
|
||||
public function getLocales($path);
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Reader;
|
||||
|
||||
use Symfony\Component\Intl\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Intl\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Reads .php resource bundles.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class PhpBundleReader extends AbstractBundleReader implements BundleReaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($path, $locale)
|
||||
{
|
||||
if ('en' !== $locale) {
|
||||
throw new InvalidArgumentException('Only the locale "en" is supported.');
|
||||
}
|
||||
|
||||
$fileName = $path . '/' . $locale . '.php';
|
||||
|
||||
if (!file_exists($fileName)) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'The resource bundle "%s/%s.php" does not exist.',
|
||||
$path,
|
||||
$locale
|
||||
));
|
||||
}
|
||||
|
||||
if (!is_file($fileName)) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'The resource bundle "%s/%s.php" is not a file.',
|
||||
$path,
|
||||
$locale
|
||||
));
|
||||
}
|
||||
|
||||
return include $fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getFileExtension()
|
||||
{
|
||||
return 'php';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Reader;
|
||||
|
||||
use Symfony\Component\Intl\ResourceBundle\Util\RecursiveArrayAccess;
|
||||
|
||||
/**
|
||||
* A structured reader wrapping an existing resource bundle reader.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @see StructuredResourceBundleBundleReaderInterface
|
||||
*/
|
||||
class StructuredBundleReader implements StructuredBundleReaderInterface
|
||||
{
|
||||
/**
|
||||
* @var BundleReaderInterface
|
||||
*/
|
||||
private $reader;
|
||||
|
||||
/**
|
||||
* Creates an entry reader based on the given resource bundle reader.
|
||||
*
|
||||
* @param BundleReaderInterface $reader A resource bundle reader to use.
|
||||
*/
|
||||
public function __construct(BundleReaderInterface $reader)
|
||||
{
|
||||
$this->reader = $reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($path, $locale)
|
||||
{
|
||||
return $this->reader->read($path, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocales($path)
|
||||
{
|
||||
return $this->reader->getLocales($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readEntry($path, $locale, array $indices, $mergeFallback = true)
|
||||
{
|
||||
$data = $this->reader->read($path, $locale);
|
||||
|
||||
$entry = RecursiveArrayAccess::get($data, $indices);
|
||||
$multivalued = is_array($entry) || $entry instanceof \Traversable;
|
||||
|
||||
if (!($mergeFallback && (null === $entry || $multivalued))) {
|
||||
return $entry;
|
||||
}
|
||||
|
||||
if (null !== ($fallbackLocale = $this->getFallbackLocale($locale))) {
|
||||
$parentEntry = $this->readEntry($path, $fallbackLocale, $indices, true);
|
||||
|
||||
if ($entry || $parentEntry) {
|
||||
$multivalued = $multivalued || is_array($parentEntry) || $parentEntry instanceof \Traversable;
|
||||
|
||||
if ($multivalued) {
|
||||
if ($entry instanceof \Traversable) {
|
||||
$entry = iterator_to_array($entry);
|
||||
}
|
||||
|
||||
if ($parentEntry instanceof \Traversable) {
|
||||
$parentEntry = iterator_to_array($parentEntry);
|
||||
}
|
||||
|
||||
$entry = array_merge(
|
||||
$parentEntry ?: array(),
|
||||
$entry ?: array()
|
||||
);
|
||||
} else {
|
||||
$entry = null === $entry ? $parentEntry : $entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fallback locale for a given locale, if any
|
||||
*
|
||||
* @param string $locale The locale to find the fallback for.
|
||||
*
|
||||
* @return string|null The fallback locale, or null if no parent exists
|
||||
*/
|
||||
private function getFallbackLocale($locale)
|
||||
{
|
||||
if (false === $pos = strrpos($locale, '_')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return substr($locale, 0, $pos);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Reader;
|
||||
|
||||
/**
|
||||
* Reads individual entries of a resource file.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface StructuredBundleReaderInterface extends BundleReaderInterface
|
||||
{
|
||||
/**
|
||||
* Reads an entry from a resource bundle.
|
||||
*
|
||||
* An entry can be selected from the resource bundle by passing the path
|
||||
* to that entry in the bundle. For example, if the bundle is structured
|
||||
* like this:
|
||||
*
|
||||
* TopLevel
|
||||
* NestedLevel
|
||||
* Entry: Value
|
||||
*
|
||||
* Then the value can be read by calling:
|
||||
*
|
||||
* $reader->readEntry('...', 'en', array('TopLevel', 'NestedLevel', 'Entry'));
|
||||
*
|
||||
* @param string $path The path to the resource bundle.
|
||||
* @param string $locale The locale to read.
|
||||
* @param string[] $indices The indices to read from the bundle.
|
||||
* @param Boolean $mergeFallback Whether to merge the value with the value
|
||||
* from the fallback locale (e.g. "en" for
|
||||
* "en_GB"). Only applicable if the result
|
||||
* is multivalued (array, \ArrayAccess).
|
||||
*
|
||||
* @return mixed Returns an array or {@link \ArrayAccess} instance for
|
||||
* complex data, a scalar value for simple data and NULL
|
||||
* if the given path could not be accessed.
|
||||
*/
|
||||
public function readEntry($path, $locale, array $indices, $mergeFallback = true);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link RegionBundleInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class RegionBundle extends AbstractBundle implements RegionBundleInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCountryName($locale, $country)
|
||||
{
|
||||
return $this->readEntry($locale, array('Countries', $country));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCountryNames($locale)
|
||||
{
|
||||
if (null === ($countries = $this->readEntry($locale, array('Countries')))) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($countries instanceof \Traversable) {
|
||||
$countries = iterator_to_array($countries);
|
||||
}
|
||||
|
||||
return $countries;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
/**
|
||||
* Gives access to region-related ICU data.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface RegionBundleInterface extends ResourceBundleInterface
|
||||
{
|
||||
/**
|
||||
* Returns the name of a country.
|
||||
*
|
||||
* @param string $locale The locale to return the name in.
|
||||
* @param string $country A country code (e.g. "US").
|
||||
*
|
||||
* @return string|null The name of the country or NULL if not found.
|
||||
*/
|
||||
public function getCountryName($locale, $country);
|
||||
|
||||
/**
|
||||
* Returns the names of all known countries.
|
||||
*
|
||||
* @param string $locale The locale to return the names in.
|
||||
*
|
||||
* @return string[] A list of country names indexed by country codes.
|
||||
*/
|
||||
public function getCountryNames($locale);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle;
|
||||
|
||||
/**
|
||||
* Gives access to ICU data.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface ResourceBundleInterface
|
||||
{
|
||||
/**
|
||||
* Returns the list of locales that this bundle supports.
|
||||
*
|
||||
* @return string[] A list of locale codes.
|
||||
*/
|
||||
public function getLocales();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Stub;
|
||||
|
||||
use Symfony\Component\Intl\ResourceBundle\CurrencyBundle;
|
||||
use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class StubCurrencyBundle extends CurrencyBundle
|
||||
{
|
||||
public function __construct(StructuredBundleReaderInterface $reader)
|
||||
{
|
||||
parent::__construct(realpath(__DIR__ . '/../../Resources/data/curr'), $reader);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Stub;
|
||||
|
||||
use Symfony\Component\Intl\ResourceBundle\LanguageBundle;
|
||||
use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class StubLanguageBundle extends LanguageBundle
|
||||
{
|
||||
public function __construct(StructuredBundleReaderInterface $reader)
|
||||
{
|
||||
parent::__construct(realpath(__DIR__ . '/../../Resources/data/lang'), $reader);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Stub;
|
||||
|
||||
use Symfony\Component\Intl\ResourceBundle\LocaleBundle;
|
||||
use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class StubLocaleBundle extends LocaleBundle
|
||||
{
|
||||
public function __construct(StructuredBundleReaderInterface $reader)
|
||||
{
|
||||
parent::__construct(realpath(__DIR__ . '/../../Resources/data/locales'), $reader);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Stub;
|
||||
|
||||
use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReaderInterface;
|
||||
use Symfony\Component\Intl\ResourceBundle\RegionBundle;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class StubRegionBundle extends RegionBundle
|
||||
{
|
||||
public function __construct(StructuredBundleReaderInterface $reader)
|
||||
{
|
||||
parent::__construct(realpath(__DIR__ . '/../../Resources/data/region'), $reader);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer;
|
||||
|
||||
use Symfony\Component\Intl\Exception\RuntimeException;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\TransformationRuleInterface;
|
||||
use Symfony\Component\Intl\ResourceBundle\Writer\PhpBundleWriter;
|
||||
|
||||
/**
|
||||
* Compiles a number of resource bundles based on predefined compilation rules.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class BundleTransformer
|
||||
{
|
||||
/**
|
||||
* @var TransformationRuleInterface[]
|
||||
*/
|
||||
private $rules = array();
|
||||
|
||||
/**
|
||||
* Adds a new compilation rule.
|
||||
*
|
||||
* @param TransformationRuleInterface $rule The compilation rule.
|
||||
*/
|
||||
public function addRule(TransformationRuleInterface $rule)
|
||||
{
|
||||
$this->rules[] = $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the compilation with the given compilation context.
|
||||
*
|
||||
* @param CompilationContextInterface $context The context storing information
|
||||
* needed to run the compilation.
|
||||
*
|
||||
* @throws RuntimeException If any of the files to be compiled by the loaded
|
||||
* compilation rules does not exist.
|
||||
*/
|
||||
public function compileBundles(CompilationContextInterface $context)
|
||||
{
|
||||
$filesystem = $context->getFilesystem();
|
||||
$compiler = $context->getCompiler();
|
||||
|
||||
$filesystem->remove($context->getBinaryDir());
|
||||
$filesystem->mkdir($context->getBinaryDir());
|
||||
|
||||
foreach ($this->rules as $rule) {
|
||||
$filesystem->mkdir($context->getBinaryDir() . '/' . $rule->getBundleName());
|
||||
|
||||
$resources = (array) $rule->beforeCompile($context);
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
if (!file_exists($resource)) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'The file "%s" to be compiled by %s does not exist.',
|
||||
$resource,
|
||||
get_class($rule)
|
||||
));
|
||||
}
|
||||
|
||||
$compiler->compile($resource, $context->getBinaryDir() . '/' . $rule->getBundleName());
|
||||
}
|
||||
|
||||
$rule->afterCompile($context);
|
||||
}
|
||||
}
|
||||
|
||||
public function createStubs(StubbingContextInterface $context)
|
||||
{
|
||||
$filesystem = $context->getFilesystem();
|
||||
$phpWriter = new PhpBundleWriter();
|
||||
|
||||
$filesystem->remove($context->getStubDir());
|
||||
$filesystem->mkdir($context->getStubDir());
|
||||
|
||||
foreach ($this->rules as $rule) {
|
||||
$filesystem->mkdir($context->getStubDir() . '/' . $rule->getBundleName());
|
||||
|
||||
$data = $rule->beforeCreateStub($context);
|
||||
|
||||
$phpWriter->write($context->getStubDir() . '/' . $rule->getBundleName(), 'en', $data);
|
||||
|
||||
$rule->afterCreateStub($context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer;
|
||||
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Intl\ResourceBundle\Compiler\ResourceBundleCompilerInterface;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link CompilationContextInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class CompilationContext implements CompilationContextInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sourceDir;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $binaryDir;
|
||||
|
||||
/**
|
||||
* @var FileSystem
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* @var ResourceBundleCompilerInterface
|
||||
*/
|
||||
private $compiler;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $icuVersion;
|
||||
|
||||
public function __construct($sourceDir, $binaryDir, Filesystem $filesystem, ResourceBundleCompilerInterface $compiler, $icuVersion)
|
||||
{
|
||||
$this->sourceDir = $sourceDir;
|
||||
$this->binaryDir = $binaryDir;
|
||||
$this->filesystem = $filesystem;
|
||||
$this->compiler = $compiler;
|
||||
$this->icuVersion = $icuVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSourceDir()
|
||||
{
|
||||
return $this->sourceDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBinaryDir()
|
||||
{
|
||||
return $this->binaryDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFilesystem()
|
||||
{
|
||||
return $this->filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCompiler()
|
||||
{
|
||||
return $this->compiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIcuVersion()
|
||||
{
|
||||
return $this->icuVersion;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer;
|
||||
|
||||
/**
|
||||
* Stores contextual information for resource bundle compilation.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface CompilationContextInterface
|
||||
{
|
||||
/**
|
||||
* Returns the directory where the source versions of the resource bundles
|
||||
* are stored.
|
||||
*
|
||||
* @return string An absolute path to a directory.
|
||||
*/
|
||||
public function getSourceDir();
|
||||
|
||||
/**
|
||||
* Returns the directory where the binary resource bundles are stored.
|
||||
*
|
||||
* @return string An absolute path to a directory.
|
||||
*/
|
||||
public function getBinaryDir();
|
||||
|
||||
/**
|
||||
* Returns a tool for manipulating the filesystem.
|
||||
*
|
||||
* @return \Symfony\Component\Filesystem\Filesystem The filesystem manipulator.
|
||||
*/
|
||||
public function getFilesystem();
|
||||
|
||||
/**
|
||||
* Returns a resource bundle compiler.
|
||||
*
|
||||
* @return \Symfony\Component\Intl\ResourceBundle\Compiler\ResourceBundleCompilerInterface The loaded resource bundle compiler.
|
||||
*/
|
||||
public function getCompiler();
|
||||
|
||||
/**
|
||||
* Returns the ICU version of the bundles being converted.
|
||||
*
|
||||
* @return string The ICU version string.
|
||||
*/
|
||||
public function getIcuVersion();
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
|
||||
|
||||
use Symfony\Component\Intl\Intl;
|
||||
use Symfony\Component\Intl\ResourceBundle\CurrencyBundle;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
|
||||
|
||||
/**
|
||||
* The rule for compiling the currency bundle.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class CurrencyBundleTransformationRule implements TransformationRuleInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBundleName()
|
||||
{
|
||||
return 'curr';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beforeCompile(CompilationContextInterface $context)
|
||||
{
|
||||
// The currency data is contained in the locales and misc bundles
|
||||
// in ICU <= 4.2
|
||||
if (version_compare($context->getIcuVersion(), '4.2', '<=')) {
|
||||
return array(
|
||||
$context->getSourceDir() . '/misc/supplementalData.txt',
|
||||
$context->getSourceDir() . '/locales'
|
||||
);
|
||||
}
|
||||
|
||||
return $context->getSourceDir() . '/curr';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function afterCompile(CompilationContextInterface $context)
|
||||
{
|
||||
// \ResourceBundle does not like locale names with uppercase chars, so rename
|
||||
// the resource file
|
||||
// See: http://bugs.php.net/bug.php?id=54025
|
||||
$fileName = $context->getBinaryDir() . '/curr/supplementalData.res';
|
||||
$fileNameLower = $context->getBinaryDir() . '/curr/supplementaldata.res';
|
||||
|
||||
$context->getFilesystem()->rename($fileName, $fileNameLower);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beforeCreateStub(StubbingContextInterface $context)
|
||||
{
|
||||
$currencies = array();
|
||||
$currencyBundle = Intl::getCurrencyBundle();
|
||||
|
||||
foreach ($currencyBundle->getCurrencyNames('en') as $code => $name) {
|
||||
$currencies[$code] = array(
|
||||
CurrencyBundle::INDEX_NAME => $name,
|
||||
CurrencyBundle::INDEX_SYMBOL => $currencyBundle->getCurrencySymbol('en', $code),
|
||||
CurrencyBundle::INDEX_FRACTION_DIGITS => $currencyBundle->getFractionDigits($code),
|
||||
CurrencyBundle::INDEX_ROUNDING_INCREMENT => $currencyBundle->getRoundingIncrement($code),
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'Currencies' => $currencies,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function afterCreateStub(StubbingContextInterface $context)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
|
||||
|
||||
use Symfony\Component\Intl\Intl;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
|
||||
|
||||
/**
|
||||
* The rule for compiling the language bundle.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class LanguageBundleTransformationRule implements TransformationRuleInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBundleName()
|
||||
{
|
||||
return 'lang';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beforeCompile(CompilationContextInterface $context)
|
||||
{
|
||||
// The language data is contained in the locales bundle in ICU <= 4.2
|
||||
if (version_compare($context->getIcuVersion(), '4.2', '<=')) {
|
||||
return $context->getSourceDir() . '/locales';
|
||||
}
|
||||
|
||||
return $context->getSourceDir() . '/lang';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function afterCompile(CompilationContextInterface $context)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beforeCreateStub(StubbingContextInterface $context)
|
||||
{
|
||||
return array(
|
||||
'Languages' => Intl::getLanguageBundle()->getLanguageNames('en'),
|
||||
'Scripts' => Intl::getLanguageBundle()->getScriptNames('en'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function afterCreateStub(StubbingContextInterface $context)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
|
||||
|
||||
use Symfony\Component\Intl\Exception\RuntimeException;
|
||||
use Symfony\Component\Intl\Intl;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
|
||||
use Symfony\Component\Intl\ResourceBundle\Writer\TextBundleWriter;
|
||||
|
||||
/**
|
||||
* The rule for compiling the locale bundle.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class LocaleBundleTransformationRule implements TransformationRuleInterface
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\Intl\ResourceBundle\LanguageBundleInterface
|
||||
*/
|
||||
private $languageBundle;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Intl\ResourceBundle\RegionBundleInterface
|
||||
*/
|
||||
private $regionBundle;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->languageBundle = Intl::getLanguageBundle();
|
||||
$this->regionBundle = Intl::getRegionBundle();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBundleName()
|
||||
{
|
||||
return 'locales';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beforeCompile(CompilationContextInterface $context)
|
||||
{
|
||||
$tempDir = sys_get_temp_dir() . '/icu-data-locales';
|
||||
|
||||
$context->getFilesystem()->remove($tempDir);
|
||||
$context->getFilesystem()->mkdir($tempDir);
|
||||
|
||||
$this->generateTextFiles($tempDir, $this->scanLocales($context));
|
||||
|
||||
return $tempDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function afterCompile(CompilationContextInterface $context)
|
||||
{
|
||||
$context->getFilesystem()->remove(sys_get_temp_dir() . '/icu-data-locales');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beforeCreateStub(StubbingContextInterface $context)
|
||||
{
|
||||
return array(
|
||||
'Locales' => Intl::getLocaleBundle()->getLocaleNames('en'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function afterCreateStub(StubbingContextInterface $context)
|
||||
{
|
||||
}
|
||||
|
||||
private function scanLocales(CompilationContextInterface $context)
|
||||
{
|
||||
$tempDir = sys_get_temp_dir() . '/icu-data-locales-source';
|
||||
|
||||
$context->getFilesystem()->remove($tempDir);
|
||||
$context->getFilesystem()->mkdir($tempDir);
|
||||
|
||||
// Temporarily generate the resource bundles
|
||||
$context->getCompiler()->compile($context->getSourceDir() . '/locales', $tempDir);
|
||||
|
||||
// Discover the list of supported locales, which are the names of the resource
|
||||
// bundles in the "locales" directory
|
||||
$locales = glob($tempDir . '/*.res');
|
||||
|
||||
// Remove file extension and sort
|
||||
array_walk($locales, function (&$locale) { $locale = basename($locale, '.res'); });
|
||||
sort($locales);
|
||||
|
||||
// Delete unneeded locales
|
||||
foreach ($locales as $key => $locale) {
|
||||
// Delete all aliases from the list
|
||||
// i.e., "az_AZ" is an alias for "az_Latn_AZ"
|
||||
$content = file_get_contents($context->getSourceDir() . '/locales/' . $locale . '.txt');
|
||||
|
||||
// The key "%%ALIAS" is not accessible through the \ResourceBundle class,
|
||||
// so look in the original .txt file instead
|
||||
if (strpos($content, '%%ALIAS') !== false) {
|
||||
unset($locales[$key]);
|
||||
}
|
||||
|
||||
// Delete locales that have no content (i.e. only "Version" key)
|
||||
$bundle = new \ResourceBundle($locale, $tempDir);
|
||||
|
||||
if (null === $bundle) {
|
||||
throw new RuntimeException('The resource bundle for locale ' . $locale . ' could not be loaded from directory ' . $tempDir);
|
||||
}
|
||||
|
||||
// There seems to be no other way for identifying all keys in this specific
|
||||
// resource bundle
|
||||
if (array_keys(iterator_to_array($bundle)) === array('Version')) {
|
||||
unset($locales[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$context->getFilesystem()->remove($tempDir);
|
||||
|
||||
return $locales;
|
||||
}
|
||||
|
||||
private function generateTextFiles($targetDirectory, array $locales)
|
||||
{
|
||||
$displayLocales = array_unique(array_merge(
|
||||
$this->languageBundle->getLocales(),
|
||||
$this->regionBundle->getLocales()
|
||||
));
|
||||
|
||||
$txtWriter = new TextBundleWriter();
|
||||
|
||||
// Generate a list of locale names in the language of each display locale
|
||||
// Each locale name has the form: "Language (Script, Region, Variant1, ...)
|
||||
// Script, Region and Variants are optional. If none of them is available,
|
||||
// the braces are not printed.
|
||||
foreach ($displayLocales as $displayLocale) {
|
||||
// Don't include ICU's root resource bundle
|
||||
if ('root' === $displayLocale) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$names = array();
|
||||
|
||||
foreach ($locales as $locale) {
|
||||
// Don't include ICU's root resource bundle
|
||||
if ($locale === 'root') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null !== ($name = $this->generateLocaleName($locale, $displayLocale))) {
|
||||
$names[$locale] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
// If no names could be generated for the current locale, skip it
|
||||
if (0 === count($names)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$txtWriter->write($targetDirectory, $displayLocale, array('Locales' => $names));
|
||||
}
|
||||
}
|
||||
|
||||
private function generateLocaleName($locale, $displayLocale)
|
||||
{
|
||||
$name = null;
|
||||
|
||||
$lang = \Locale::getPrimaryLanguage($locale);
|
||||
$script = \Locale::getScript($locale);
|
||||
$region = \Locale::getRegion($locale);
|
||||
$variants = \Locale::getAllVariants($locale);
|
||||
|
||||
// Currently the only available variant is POSIX, which we don't want
|
||||
// to include in the list
|
||||
if (count($variants) > 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Some languages are translated together with their region,
|
||||
// i.e. "en_GB" is translated as "British English"
|
||||
// we don't include these languages though because they mess up
|
||||
// the name sorting
|
||||
// $name = $this->langBundle->getLanguageName($displayLocale, $lang, $region);
|
||||
|
||||
// Some languages are simply not translated
|
||||
// Example: "az" (Azerbaijani) has no translation in "af" (Afrikaans)
|
||||
if (null === ($name = $this->languageBundle->getLanguageName($displayLocale, $lang))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// "as" (Assamese) has no "Variants" block
|
||||
//if (!$langBundle->get('Variants')) {
|
||||
// continue;
|
||||
//}
|
||||
|
||||
$extras = array();
|
||||
|
||||
// Discover the name of the script part of the locale
|
||||
// i.e. in zh_Hans_MO, "Hans" is the script
|
||||
if ($script) {
|
||||
// Some scripts are not translated into every language
|
||||
if (null === ($scriptName = $this->languageBundle->getScriptName($displayLocale, $script, $lang))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$extras[] = $scriptName;
|
||||
}
|
||||
|
||||
// Discover the name of the region part of the locale
|
||||
// i.e. in de_AT, "AT" is the region
|
||||
if ($region) {
|
||||
// Some regions are not translated into every language
|
||||
if (null === ($regionName = $this->regionBundle->getCountryName($displayLocale, $region))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$extras[] = $regionName;
|
||||
}
|
||||
|
||||
if (count($extras) > 0) {
|
||||
// Remove any existing extras
|
||||
// For example, in German, zh_Hans is "Chinesisch (vereinfacht)".
|
||||
// The latter is the script part which is already included in the
|
||||
// extras and will be appended again with the other extras.
|
||||
if (preg_match('/^(.+)\s+\([^\)]+\)$/', $name, $matches)) {
|
||||
$name = $matches[1];
|
||||
}
|
||||
|
||||
$name .= ' ('.implode(', ', $extras).')';
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
|
||||
|
||||
use Symfony\Component\Intl\Intl;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
|
||||
|
||||
/**
|
||||
* The rule for compiling the region bundle.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class RegionBundleTransformationRule implements TransformationRuleInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBundleName()
|
||||
{
|
||||
return 'region';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beforeCompile(CompilationContextInterface $context)
|
||||
{
|
||||
// The region data is contained in the locales bundle in ICU <= 4.2
|
||||
if (version_compare($context->getIcuVersion(), '4.2', '<=')) {
|
||||
return $context->getSourceDir() . '/locales';
|
||||
}
|
||||
|
||||
return $context->getSourceDir() . '/region';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function afterCompile(CompilationContextInterface $context)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function beforeCreateStub(StubbingContextInterface $context)
|
||||
{
|
||||
return array(
|
||||
'Countries' => Intl::getRegionBundle()->getCountryNames('en'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function afterCreateStub(StubbingContextInterface $context)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer\Rule;
|
||||
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContextInterface;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContextInterface;
|
||||
|
||||
/**
|
||||
* Contains instruction for compiling a resource bundle.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface TransformationRuleInterface
|
||||
{
|
||||
/**
|
||||
* Returns the name of the compiled resource bundle.
|
||||
*
|
||||
* @return string The name of the bundle.
|
||||
*/
|
||||
public function getBundleName();
|
||||
|
||||
/**
|
||||
* Runs instructions to be executed before compiling the sources of the
|
||||
* resource bundle.
|
||||
*
|
||||
* @param CompilationContextInterface $context The contextual information of
|
||||
* the compilation.
|
||||
*
|
||||
* @return string[] The source directories/files of the bundle.
|
||||
*/
|
||||
public function beforeCompile(CompilationContextInterface $context);
|
||||
|
||||
/**
|
||||
* Runs instructions to be executed after compiling the sources of the
|
||||
* resource bundle.
|
||||
*
|
||||
* @param CompilationContextInterface $context The contextual information of
|
||||
* the compilation.
|
||||
*/
|
||||
public function afterCompile(CompilationContextInterface $context);
|
||||
|
||||
/**
|
||||
* Runs instructions to be executed before creating the stub version of the
|
||||
* resource bundle.
|
||||
*
|
||||
* @param StubbingContextInterface $context The contextual information of
|
||||
* the compilation.
|
||||
*
|
||||
* @return mixed The data to include in the stub version.
|
||||
*/
|
||||
public function beforeCreateStub(StubbingContextInterface $context);
|
||||
|
||||
/**
|
||||
* Runs instructions to be executed after creating the stub version of the
|
||||
* resource bundle.
|
||||
*
|
||||
* @param StubbingContextInterface $context The contextual information of
|
||||
* the compilation.
|
||||
*/
|
||||
public function afterCreateStub(StubbingContextInterface $context);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer;
|
||||
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class StubbingContext implements StubbingContextInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $binaryDir;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $stubDir;
|
||||
|
||||
/**
|
||||
* @var Filesystem
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $icuVersion;
|
||||
|
||||
public function __construct($binaryDir, $stubDir, Filesystem $filesystem, $icuVersion)
|
||||
{
|
||||
$this->binaryDir = $binaryDir;
|
||||
$this->stubDir = $stubDir;
|
||||
$this->filesystem = $filesystem;
|
||||
$this->icuVersion = $icuVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBinaryDir()
|
||||
{
|
||||
return $this->binaryDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStubDir()
|
||||
{
|
||||
return $this->stubDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFilesystem()
|
||||
{
|
||||
return $this->filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIcuVersion()
|
||||
{
|
||||
return $this->icuVersion;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Transformer;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface StubbingContextInterface
|
||||
{
|
||||
/**
|
||||
* Returns the directory where the binary resource bundles are stored.
|
||||
*
|
||||
* @return string An absolute path to a directory.
|
||||
*/
|
||||
public function getBinaryDir();
|
||||
|
||||
/**
|
||||
* Returns the directory where the stub resource bundles are stored.
|
||||
*
|
||||
* @return string An absolute path to a directory.
|
||||
*/
|
||||
public function getStubDir();
|
||||
|
||||
/**
|
||||
* Returns a tool for manipulating the filesystem.
|
||||
*
|
||||
* @return \Symfony\Component\Filesystem\Filesystem The filesystem manipulator.
|
||||
*/
|
||||
public function getFilesystem();
|
||||
|
||||
/**
|
||||
* Returns the ICU version of the bundles being converted.
|
||||
*
|
||||
* @return string The ICU version string.
|
||||
*/
|
||||
public function getIcuVersion();
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Util;
|
||||
|
||||
use Symfony\Component\Intl\Exception\BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Work-around for a bug in PHP's \ResourceBundle implementation.
|
||||
*
|
||||
* More information can be found on https://bugs.php.net/bug.php?id=64356.
|
||||
* This class can be removed once that bug is fixed.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class ArrayAccessibleResourceBundle implements \ArrayAccess, \IteratorAggregate, \Countable
|
||||
{
|
||||
private $bundleImpl;
|
||||
|
||||
public function __construct(\ResourceBundle $bundleImpl)
|
||||
{
|
||||
$this->bundleImpl = $bundleImpl;
|
||||
}
|
||||
|
||||
public function get($offset, $fallback = null)
|
||||
{
|
||||
$value = $this->bundleImpl->get($offset, $fallback);
|
||||
|
||||
return $value instanceof \ResourceBundle ? new static($value) : $value;
|
||||
}
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return null !== $this->bundleImpl[$offset];
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
throw new BadMethodCallException('Resource bundles cannot be modified.');
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
throw new BadMethodCallException('Resource bundles cannot be modified.');
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
return $this->bundleImpl;
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
return $this->bundleImpl->count();
|
||||
}
|
||||
|
||||
public function getErrorCode()
|
||||
{
|
||||
return $this->bundleImpl->getErrorCode();
|
||||
}
|
||||
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return $this->bundleImpl->getErrorMessage();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Util;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class RecursiveArrayAccess
|
||||
{
|
||||
public static function get($array, array $indices)
|
||||
{
|
||||
foreach ($indices as $index) {
|
||||
if (!$array instanceof \ArrayAccess && !is_array($array)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$array = $array[$index];
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
private function __construct() {}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Util;
|
||||
|
||||
use Symfony\Component\Intl\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Implements a ring buffer.
|
||||
*
|
||||
* A ring buffer is an array-like structure with a fixed size. If the buffer
|
||||
* is full, the next written element overwrites the first bucket in the buffer,
|
||||
* then the second and so on.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class RingBuffer implements \ArrayAccess
|
||||
{
|
||||
private $values = array();
|
||||
|
||||
private $indices = array();
|
||||
|
||||
private $cursor = 0;
|
||||
|
||||
private $size;
|
||||
|
||||
public function __construct($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return isset($this->indices[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetGet($key)
|
||||
{
|
||||
if (!isset($this->indices[$key])) {
|
||||
throw new OutOfBoundsException(sprintf(
|
||||
'The index "%s" does not exist.',
|
||||
$key
|
||||
));
|
||||
}
|
||||
|
||||
return $this->values[$this->indices[$key]];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
if (false !== ($keyToRemove = array_search($this->cursor, $this->indices))) {
|
||||
unset($this->indices[$keyToRemove]);
|
||||
}
|
||||
|
||||
$this->values[$this->cursor] = $value;
|
||||
$this->indices[$key] = $this->cursor;
|
||||
|
||||
$this->cursor = ($this->cursor + 1) % $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
if (isset($this->indices[$key])) {
|
||||
$this->values[$this->indices[$key]] = null;
|
||||
unset($this->indices[$key]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Writer;
|
||||
|
||||
/**
|
||||
* Writes resource bundle files.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface BundleWriterInterface
|
||||
{
|
||||
/**
|
||||
* Writes data to a resource bundle.
|
||||
*
|
||||
* @param string $path The path to the resource bundle.
|
||||
* @param string $locale The locale to (over-)write.
|
||||
* @param mixed $data The data to write.
|
||||
*/
|
||||
public function write($path, $locale, $data);
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Writer;
|
||||
|
||||
/**
|
||||
* Writes .php resource bundles.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class PhpBundleWriter implements BundleWriterInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function write($path, $locale, $data)
|
||||
{
|
||||
$template = <<<TEMPLATE
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
return %s;
|
||||
|
||||
TEMPLATE;
|
||||
|
||||
$data = var_export($data, true);
|
||||
$data = preg_replace('/array \(/', 'array(', $data);
|
||||
$data = preg_replace('/\n {1,10}array\(/', 'array(', $data);
|
||||
$data = preg_replace('/ /', ' ', $data);
|
||||
$data = sprintf($template, $data);
|
||||
|
||||
file_put_contents($path.'/'.$locale.'.php', $data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\ResourceBundle\Writer;
|
||||
|
||||
/**
|
||||
* Writes .txt resource bundles.
|
||||
*
|
||||
* The resulting files can be converted to binary .res files using the
|
||||
* {@link \Symfony\Component\Intl\ResourceBundle\Transformer\BundleCompiler}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
|
||||
*/
|
||||
class TextBundleWriter implements BundleWriterInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write($path, $locale, $data)
|
||||
{
|
||||
$file = fopen($path.'/'.$locale.'.txt', 'w');
|
||||
|
||||
$this->writeResourceBundle($file, $locale, $data);
|
||||
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a "resourceBundle" node.
|
||||
*
|
||||
* @param resource $file The file handle to write to.
|
||||
* @param string $bundleName The name of the bundle.
|
||||
* @param mixed $value The value of the node.
|
||||
*
|
||||
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
|
||||
*/
|
||||
private function writeResourceBundle($file, $bundleName, $value)
|
||||
{
|
||||
fwrite($file, $bundleName);
|
||||
|
||||
$this->writeTable($file, $value, 0);
|
||||
|
||||
fwrite($file, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a "resource" node.
|
||||
*
|
||||
* @param resource $file The file handle to write to.
|
||||
* @param mixed $value The value of the node.
|
||||
* @param integer $indentation The number of levels to indent.
|
||||
* @param Boolean $requireBraces Whether to require braces to be printed
|
||||
* around the value.
|
||||
*
|
||||
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
|
||||
*/
|
||||
private function writeResource($file, $value, $indentation, $requireBraces = true)
|
||||
{
|
||||
if (is_int($value)) {
|
||||
$this->writeInteger($file, $value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
if (count($value) === count(array_filter($value, 'is_int'))) {
|
||||
$this->writeIntVector($file, $value, $indentation);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$keys = array_keys($value);
|
||||
|
||||
if (count($keys) === count(array_filter($keys, 'is_int'))) {
|
||||
$this->writeArray($file, $value, $indentation);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->writeTable($file, $value, $indentation);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_bool($value)) {
|
||||
$value = $value ? 'true' : 'false';
|
||||
}
|
||||
|
||||
$this->writeString($file, (string) $value, $requireBraces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an "integer" node.
|
||||
*
|
||||
* @param resource $file The file handle to write to.
|
||||
* @param integer $value The value of the node.
|
||||
*
|
||||
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
|
||||
*/
|
||||
private function writeInteger($file, $value)
|
||||
{
|
||||
fprintf($file, ':int{%d}', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an "intvector" node.
|
||||
*
|
||||
* @param resource $file The file handle to write to.
|
||||
* @param array $value The value of the node.
|
||||
* @param integer $indentation The number of levels to indent.
|
||||
*
|
||||
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
|
||||
*/
|
||||
private function writeIntVector($file, array $value, $indentation)
|
||||
{
|
||||
fwrite($file, ":intvector{\n");
|
||||
|
||||
foreach ($value as $int) {
|
||||
fprintf($file, "%s%d,\n", str_repeat(' ', $indentation + 1), $int);
|
||||
}
|
||||
|
||||
fprintf($file, "%s}", str_repeat(' ', $indentation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a "string" node.
|
||||
*
|
||||
* @param resource $file The file handle to write to.
|
||||
* @param string $value The value of the node.
|
||||
* @param Boolean $requireBraces Whether to require braces to be printed
|
||||
* around the value.
|
||||
*
|
||||
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
|
||||
*/
|
||||
private function writeString($file, $value, $requireBraces = true)
|
||||
{
|
||||
if ($requireBraces) {
|
||||
fprintf($file, '{"%s"}', $value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf($file, '"%s"', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an "array" node.
|
||||
*
|
||||
* @param resource $file The file handle to write to.
|
||||
* @param array $value The value of the node.
|
||||
* @param integer $indentation The number of levels to indent.
|
||||
*
|
||||
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
|
||||
*/
|
||||
private function writeArray($file, array $value, $indentation)
|
||||
{
|
||||
fwrite($file, "{\n");
|
||||
|
||||
foreach ($value as $entry) {
|
||||
fwrite($file, str_repeat(' ', $indentation + 1));
|
||||
|
||||
$this->writeResource($file, $entry, $indentation + 1, false);
|
||||
|
||||
fwrite($file, ",\n");
|
||||
}
|
||||
|
||||
fprintf($file, '%s}', str_repeat(' ', $indentation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a "table" node.
|
||||
*
|
||||
* @param resource $file The file handle to write to.
|
||||
* @param array $value The value of the node.
|
||||
* @param integer $indentation The number of levels to indent.
|
||||
*/
|
||||
private function writeTable($file, array $value, $indentation)
|
||||
{
|
||||
fwrite($file, "{\n");
|
||||
|
||||
foreach ($value as $key => $entry) {
|
||||
fwrite($file, str_repeat(' ', $indentation + 1));
|
||||
fwrite($file, $key);
|
||||
|
||||
$this->writeResource($file, $entry, $indentation + 1);
|
||||
|
||||
fwrite($file, "\n");
|
||||
}
|
||||
|
||||
fprintf($file, '%s}', str_repeat(' ', $indentation));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
define('LINE_WIDTH', 75);
|
||||
|
||||
define('LINE', str_repeat('-', LINE_WIDTH) . "\n");
|
||||
|
||||
function bailout($message)
|
||||
{
|
||||
echo wordwrap($message, LINE_WIDTH) . " Aborting.\n";
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
function strip_minor_versions($version)
|
||||
{
|
||||
preg_match('/^(?P<version>[0-9]\.[0-9]|[0-9]{2,})/', $version, $matches);
|
||||
|
||||
return $matches['version'];
|
||||
}
|
||||
|
||||
function centered($text)
|
||||
{
|
||||
$padding = (int) ((LINE_WIDTH - strlen($text))/2);
|
||||
|
||||
return str_repeat(' ', $padding) . $text;
|
||||
}
|
||||
|
||||
function cd($dir)
|
||||
{
|
||||
if (false === chdir($dir)) {
|
||||
bailout("Could not switch to directory $dir.");
|
||||
}
|
||||
}
|
||||
|
||||
function run($command)
|
||||
{
|
||||
exec($command, $output, $status);
|
||||
|
||||
if (0 !== $status) {
|
||||
$output = implode("\n", $output);
|
||||
echo "Error:\n" . LINE . "$output\n" . LINE;
|
||||
|
||||
bailout("\"$command\" failed.");
|
||||
}
|
||||
}
|
||||
|
||||
function get_icu_version_from_genrb($genrb)
|
||||
{
|
||||
exec($genrb . ' --version 2>&1', $output, $status);
|
||||
|
||||
if (0 !== $status) {
|
||||
bailout($genrb . ' failed.');
|
||||
}
|
||||
|
||||
if (!preg_match('/ICU version ([\d\.]+)/', implode('', $output), $matches)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Intl\Intl;
|
||||
|
||||
require_once __DIR__ . '/common.php';
|
||||
require_once __DIR__ . '/autoload.php';
|
||||
|
||||
echo "ICU version: ";
|
||||
echo Intl::getIcuVersion() . "\n";
|
|
@ -1,9 +1,9 @@
|
|||
; ICU data source URLs
|
||||
; We use always the latest release of a major version.
|
||||
4.0 = http://source.icu-project.org/repos/icu/icu/tags/release-4-0-1/source/data
|
||||
4.2 = http://source.icu-project.org/repos/icu/icu/tags/release-4-2-1/source/data
|
||||
4.4 = http://source.icu-project.org/repos/icu/icu/tags/release-4-4-2/source/data
|
||||
4.6 = http://source.icu-project.org/repos/icu/icu/tags/release-4-6-1/source/data
|
||||
4.8 = http://source.icu-project.org/repos/icu/icu/tags/release-4-8-1-1/source/data
|
||||
49 = http://source.icu-project.org/repos/icu/icu/tags/release-49-1-2/source/data
|
||||
50 = http://source.icu-project.org/repos/icu/icu/tags/release-50-1/source/data
|
||||
4.0 = http://source.icu-project.org/repos/icu/icu/tags/release-4-0-1/source
|
||||
4.2 = http://source.icu-project.org/repos/icu/icu/tags/release-4-2-1/source
|
||||
4.4 = http://source.icu-project.org/repos/icu/icu/tags/release-4-4-2/source
|
||||
4.6 = http://source.icu-project.org/repos/icu/icu/tags/release-4-6-1/source
|
||||
4.8 = http://source.icu-project.org/repos/icu/icu/tags/release-4-8-1-1/source
|
||||
49 = http://source.icu-project.org/repos/icu/icu/tags/release-49-1-2/source
|
||||
50 = http://source.icu-project.org/repos/icu/icu/tags/release-50-1/source
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Icu\IcuData;
|
||||
use Symfony\Component\Intl\Intl;
|
||||
use Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompiler;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\BundleTransformer;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\CompilationContext;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\CurrencyBundleTransformationRule;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LanguageBundleTransformationRule;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LocaleBundleTransformationRule;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\RegionBundleTransformationRule;
|
||||
use Symfony\Component\Intl\Util\SvnRepository;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
require_once __DIR__ . '/common.php';
|
||||
require_once __DIR__ . '/autoload.php';
|
||||
|
||||
if (1 !== $GLOBALS['argc']) {
|
||||
bailout(<<<MESSAGE
|
||||
Usage: php update-icu-component.php
|
||||
|
||||
Updates the ICU data for Symfony2 to the latest version of the ICU version
|
||||
included in the intl extension. For example, if your intl extension includes
|
||||
ICU 4.8, the script will download the latest data available for ICU 4.8.
|
||||
|
||||
For running this script, the intl extension must be loaded and all vendors
|
||||
must have been installed through composer:
|
||||
|
||||
composer install --dev
|
||||
|
||||
MESSAGE
|
||||
);
|
||||
}
|
||||
|
||||
echo LINE;
|
||||
echo centered("ICU Resource Bundle Compilation") . "\n";
|
||||
echo LINE;
|
||||
|
||||
if (!Intl::isExtensionLoaded()) {
|
||||
bailout('The intl extension for PHP is not installed.');
|
||||
}
|
||||
|
||||
if (!class_exists('\Symfony\Component\Icu\IcuData')) {
|
||||
bailout('You must run "composer update --dev" before running this script.');
|
||||
}
|
||||
|
||||
$icuVersionInPhp = Intl::getIcuVersion();
|
||||
|
||||
echo "Found intl extension with ICU version $icuVersionInPhp.\n";
|
||||
|
||||
$shortIcuVersion = strip_minor_versions($icuVersionInPhp);
|
||||
$urls = parse_ini_file(__DIR__ . '/icu.ini');
|
||||
|
||||
if (!isset($urls[$shortIcuVersion])) {
|
||||
bailout('The version ' . $shortIcuVersion . ' is not available in the icu.ini file.');
|
||||
}
|
||||
|
||||
echo "icu.ini parsed. Available versions:\n";
|
||||
|
||||
foreach ($urls as $urlVersion => $url) {
|
||||
echo " $urlVersion\n";
|
||||
}
|
||||
|
||||
echo "Starting SVN checkout for version $shortIcuVersion. This may take a while...\n";
|
||||
|
||||
$svn = SvnRepository::download($urls[$shortIcuVersion], $shortIcuVersion);
|
||||
|
||||
echo "SVN checkout to {$svn->getPath()} complete.\n";
|
||||
|
||||
// Always build genrb so that we can determine the ICU version of the
|
||||
// download by running genrb --version
|
||||
echo "Building genrb.\n";
|
||||
|
||||
cd($svn->getPath());
|
||||
|
||||
echo "Running make clean...\n";
|
||||
|
||||
run('make clean');
|
||||
|
||||
echo "Running configure...\n";
|
||||
|
||||
run('./configure 2>&1');
|
||||
|
||||
cd($svn->getPath() . '/tools');
|
||||
|
||||
echo "Running make...\n";
|
||||
|
||||
run('make 2>&1');
|
||||
|
||||
$genrb = $svn->getPath() . '/bin/genrb';
|
||||
|
||||
echo "Using $genrb.\n";
|
||||
|
||||
$icuVersionInDownload = get_icu_version_from_genrb($genrb);
|
||||
|
||||
echo "Preparing resource bundle compilation (version $icuVersionInDownload)...\n";
|
||||
|
||||
$context = new CompilationContext(
|
||||
$svn->getPath() . '/data',
|
||||
IcuData::getResourceDirectory(),
|
||||
new Filesystem(),
|
||||
new BundleCompiler($genrb),
|
||||
$icuVersionInDownload
|
||||
);
|
||||
|
||||
$transformer = new BundleTransformer();
|
||||
$transformer->addRule(new LanguageBundleTransformationRule());
|
||||
$transformer->addRule(new RegionBundleTransformationRule());
|
||||
$transformer->addRule(new CurrencyBundleTransformationRule());
|
||||
$transformer->addRule(new LocaleBundleTransformationRule());
|
||||
|
||||
echo "Starting resource bundle compilation. This may take a while...\n";
|
||||
|
||||
$transformer->compileBundles($context);
|
||||
|
||||
echo "Resource bundle compilation complete.\n";
|
||||
|
||||
$svnInfo = <<<SVN_INFO
|
||||
SVN information
|
||||
===============
|
||||
|
||||
URL: {$svn->getUrl()}
|
||||
Revision: {$svn->getLastCommit()->getRevision()}
|
||||
Author: {$svn->getLastCommit()->getAuthor()}
|
||||
Date: {$svn->getLastCommit()->getDate()}
|
||||
|
||||
SVN_INFO;
|
||||
|
||||
$svnInfoFile = $context->getBinaryDir() . '/svn-info.txt';
|
||||
|
||||
file_put_contents($svnInfoFile, $svnInfo);
|
||||
|
||||
echo "Wrote $svnInfoFile.\n";
|
||||
|
||||
$versionFile = $context->getBinaryDir() . '/version.txt';
|
||||
|
||||
file_put_contents($versionFile, "$icuVersionInDownload\n");
|
||||
|
||||
echo "Wrote $versionFile.\n";
|
||||
|
||||
echo "Done.\n";
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Icu\IcuData;
|
||||
use Symfony\Component\Intl\Intl;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\BundleTransformer;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\CurrencyBundleTransformationRule;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LanguageBundleTransformationRule;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\LocaleBundleTransformationRule;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\Rule\RegionBundleTransformationRule;
|
||||
use Symfony\Component\Intl\ResourceBundle\Transformer\StubbingContext;
|
||||
|
||||
require_once __DIR__ . '/common.php';
|
||||
require_once __DIR__ . '/autoload.php';
|
||||
|
||||
if (1 !== $GLOBALS['argc']) {
|
||||
bailout(<<<MESSAGE
|
||||
Usage: php update-stubs.php
|
||||
|
||||
Creates resource bundle stubs from the resource bundles in the Icu component.
|
||||
|
||||
For running this script, the intl extension must be loaded and all vendors
|
||||
must have been installed through composer:
|
||||
|
||||
composer install --dev
|
||||
|
||||
MESSAGE
|
||||
);
|
||||
}
|
||||
|
||||
echo LINE;
|
||||
echo centered("ICU Resource Bundle Stub Creation") . "\n";
|
||||
echo LINE;
|
||||
|
||||
if (!Intl::isExtensionLoaded()) {
|
||||
bailout('The intl extension for PHP is not installed.');
|
||||
}
|
||||
|
||||
if (!class_exists('\Symfony\Component\Icu\IcuData')) {
|
||||
bailout('You must run "composer update --dev" before running this script.');
|
||||
}
|
||||
|
||||
$shortIcuVersionInPhp = strip_minor_versions(Intl::getIcuVersion());
|
||||
$shortIcuVersionInIntlComponent = strip_minor_versions(Intl::getStubIcuVersion());
|
||||
$shortIcuVersionInIcuComponent = strip_minor_versions(IcuData::getVersion());
|
||||
|
||||
if ($shortIcuVersionInPhp !== $shortIcuVersionInIcuComponent) {
|
||||
bailout("The ICU version of the component ($shortIcuVersionInIcuComponent) does not match the ICU version in the intl extension ($shortIcuVersionInPhp).");
|
||||
}
|
||||
|
||||
if ($shortIcuVersionInIntlComponent !== $shortIcuVersionInIcuComponent) {
|
||||
bailout("The ICU version of the component ($shortIcuVersionInIcuComponent) does not match the ICU version of the stub classes in the Intl component ($shortIcuVersionInIntlComponent).");
|
||||
}
|
||||
|
||||
$icuVersionInIcuComponent = IcuData::getVersion();
|
||||
|
||||
echo "Compiling stubs for ICU version $icuVersionInIcuComponent.";
|
||||
|
||||
echo "Preparing stub creation...\n";
|
||||
|
||||
$context = new StubbingContext(
|
||||
IcuData::getResourceDirectory(),
|
||||
realpath(__DIR__ . '/../data'),
|
||||
new Filesystem(),
|
||||
$icuVersionInIcuComponent
|
||||
);
|
||||
|
||||
$transformer = new BundleTransformer();
|
||||
$transformer->addRule(new LanguageBundleTransformationRule());
|
||||
$transformer->addRule(new RegionBundleTransformationRule());
|
||||
$transformer->addRule(new CurrencyBundleTransformationRule());
|
||||
$transformer->addRule(new LocaleBundleTransformationRule());
|
||||
|
||||
echo "Starting stub creation...\n";
|
||||
|
||||
$transformer->createStubs($context);
|
||||
|
||||
echo "Stub creation complete.\n";
|
||||
|
||||
$versionFile = $context->getStubDir() . '/version.txt';
|
||||
|
||||
file_put_contents($versionFile, "$icuVersionInIcuComponent\n");
|
||||
|
||||
echo "Wrote $versionFile.\n";
|
||||
|
||||
echo "Done.\n";
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,707 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
return array(
|
||||
'Languages' => array(
|
||||
'ab' => 'Abkhazian',
|
||||
'ace' => 'Achinese',
|
||||
'ach' => 'Acoli',
|
||||
'ada' => 'Adangme',
|
||||
'ady' => 'Adyghe',
|
||||
'aa' => 'Afar',
|
||||
'afh' => 'Afrihili',
|
||||
'af' => 'Afrikaans',
|
||||
'afa' => 'Afro-Asiatic Language',
|
||||
'agq' => 'Aghem',
|
||||
'ain' => 'Ainu',
|
||||
'ak' => 'Akan',
|
||||
'akk' => 'Akkadian',
|
||||
'sq' => 'Albanian',
|
||||
'ale' => 'Aleut',
|
||||
'alg' => 'Algonquian Language',
|
||||
'tut' => 'Altaic Language',
|
||||
'am' => 'Amharic',
|
||||
'egy' => 'Ancient Egyptian',
|
||||
'grc' => 'Ancient Greek',
|
||||
'anp' => 'Angika',
|
||||
'apa' => 'Apache Language',
|
||||
'ar' => 'Arabic',
|
||||
'an' => 'Aragonese',
|
||||
'arc' => 'Aramaic',
|
||||
'arp' => 'Arapaho',
|
||||
'arn' => 'Araucanian',
|
||||
'arw' => 'Arawak',
|
||||
'hy' => 'Armenian',
|
||||
'rup' => 'Aromanian',
|
||||
'art' => 'Artificial Language',
|
||||
'as' => 'Assamese',
|
||||
'ast' => 'Asturian',
|
||||
'asa' => 'Asu',
|
||||
'ath' => 'Athapascan Language',
|
||||
'cch' => 'Atsam',
|
||||
'en_AU' => 'Australian English',
|
||||
'aus' => 'Australian Language',
|
||||
'de_AT' => 'Austrian German',
|
||||
'map' => 'Austronesian Language',
|
||||
'av' => 'Avaric',
|
||||
'ae' => 'Avestan',
|
||||
'awa' => 'Awadhi',
|
||||
'ay' => 'Aymara',
|
||||
'az' => 'Azerbaijani',
|
||||
'ksf' => 'Bafia',
|
||||
'ban' => 'Balinese',
|
||||
'bat' => 'Baltic Language',
|
||||
'bal' => 'Baluchi',
|
||||
'bm' => 'Bambara',
|
||||
'bai' => 'Bamileke Language',
|
||||
'bad' => 'Banda',
|
||||
'bnt' => 'Bantu',
|
||||
'bas' => 'Basaa',
|
||||
'ba' => 'Bashkir',
|
||||
'eu' => 'Basque',
|
||||
'btk' => 'Batak',
|
||||
'bej' => 'Beja',
|
||||
'be' => 'Belarusian',
|
||||
'bem' => 'Bemba',
|
||||
'bez' => 'Bena',
|
||||
'bn' => 'Bengali',
|
||||
'ber' => 'Berber',
|
||||
'bho' => 'Bhojpuri',
|
||||
'bh' => 'Bihari',
|
||||
'bik' => 'Bikol',
|
||||
'bin' => 'Bini',
|
||||
'bi' => 'Bislama',
|
||||
'byn' => 'Blin',
|
||||
'zbl' => 'Blissymbols',
|
||||
'brx' => 'Bodo',
|
||||
'bs' => 'Bosnian',
|
||||
'bra' => 'Braj',
|
||||
'pt_BR' => 'Brazilian Portuguese',
|
||||
'br' => 'Breton',
|
||||
'en_GB' => 'British English',
|
||||
'bug' => 'Buginese',
|
||||
'bg' => 'Bulgarian',
|
||||
'bua' => 'Buriat',
|
||||
'my' => 'Burmese',
|
||||
'cad' => 'Caddo',
|
||||
'en_CA' => 'Canadian English',
|
||||
'fr_CA' => 'Canadian French',
|
||||
'yue' => 'Cantonese',
|
||||
'car' => 'Carib',
|
||||
'ca' => 'Catalan',
|
||||
'cau' => 'Caucasian Language',
|
||||
'cay' => 'Cayuga',
|
||||
'ceb' => 'Cebuano',
|
||||
'cel' => 'Celtic Language',
|
||||
'cai' => 'Central American Indian Language',
|
||||
'tzm' => 'Central Morocco Tamazight',
|
||||
'chg' => 'Chagatai',
|
||||
'cmc' => 'Chamic Language',
|
||||
'ch' => 'Chamorro',
|
||||
'ce' => 'Chechen',
|
||||
'chr' => 'Cherokee',
|
||||
'chy' => 'Cheyenne',
|
||||
'chb' => 'Chibcha',
|
||||
'cgg' => 'Chiga',
|
||||
'zh' => 'Chinese',
|
||||
'chn' => 'Chinook Jargon',
|
||||
'chp' => 'Chipewyan',
|
||||
'cho' => 'Choctaw',
|
||||
'cu' => 'Church Slavic',
|
||||
'chk' => 'Chuukese',
|
||||
'cv' => 'Chuvash',
|
||||
'nwc' => 'Classical Newari',
|
||||
'syc' => 'Classical Syriac',
|
||||
'ksh' => 'Colognian',
|
||||
'swb' => 'Comorian',
|
||||
'swc' => 'Congo Swahili',
|
||||
'cop' => 'Coptic',
|
||||
'kw' => 'Cornish',
|
||||
'co' => 'Corsican',
|
||||
'cr' => 'Cree',
|
||||
'mus' => 'Creek',
|
||||
'crp' => 'Creole or Pidgin',
|
||||
'crh' => 'Crimean Turkish',
|
||||
'hr' => 'Croatian',
|
||||
'cus' => 'Cushitic Language',
|
||||
'cs' => 'Czech',
|
||||
'dak' => 'Dakota',
|
||||
'da' => 'Danish',
|
||||
'dar' => 'Dargwa',
|
||||
'day' => 'Dayak',
|
||||
'del' => 'Delaware',
|
||||
'din' => 'Dinka',
|
||||
'dv' => 'Divehi',
|
||||
'doi' => 'Dogri',
|
||||
'dgr' => 'Dogrib',
|
||||
'dra' => 'Dravidian Language',
|
||||
'dua' => 'Duala',
|
||||
'nl' => 'Dutch',
|
||||
'dyu' => 'Dyula',
|
||||
'dz' => 'Dzongkha',
|
||||
'frs' => 'Eastern Frisian',
|
||||
'efi' => 'Efik',
|
||||
'eka' => 'Ekajuk',
|
||||
'elx' => 'Elamite',
|
||||
'ebu' => 'Embu',
|
||||
'en' => 'English',
|
||||
'cpe' => 'English-based Creole or Pidgin',
|
||||
'myv' => 'Erzya',
|
||||
'eo' => 'Esperanto',
|
||||
'et' => 'Estonian',
|
||||
'ee' => 'Ewe',
|
||||
'ewo' => 'Ewondo',
|
||||
'fan' => 'Fang',
|
||||
'fat' => 'Fanti',
|
||||
'fo' => 'Faroese',
|
||||
'fj' => 'Fijian',
|
||||
'fil' => 'Filipino',
|
||||
'fi' => 'Finnish',
|
||||
'fiu' => 'Finno-Ugrian Language',
|
||||
'nl_BE' => 'Flemish',
|
||||
'fon' => 'Fon',
|
||||
'fr' => 'French',
|
||||
'cpf' => 'French-based Creole or Pidgin',
|
||||
'fur' => 'Friulian',
|
||||
'ff' => 'Fulah',
|
||||
'gaa' => 'Ga',
|
||||
'gl' => 'Galician',
|
||||
'lg' => 'Ganda',
|
||||
'gay' => 'Gayo',
|
||||
'gba' => 'Gbaya',
|
||||
'gez' => 'Geez',
|
||||
'ka' => 'Georgian',
|
||||
'de' => 'German',
|
||||
'gem' => 'Germanic Language',
|
||||
'gil' => 'Gilbertese',
|
||||
'gon' => 'Gondi',
|
||||
'gor' => 'Gorontalo',
|
||||
'got' => 'Gothic',
|
||||
'grb' => 'Grebo',
|
||||
'el' => 'Greek',
|
||||
'gn' => 'Guarani',
|
||||
'gu' => 'Gujarati',
|
||||
'guz' => 'Gusii',
|
||||
'gwi' => 'Gwichʼin',
|
||||
'hai' => 'Haida',
|
||||
'ht' => 'Haitian',
|
||||
'ha' => 'Hausa',
|
||||
'haw' => 'Hawaiian',
|
||||
'he' => 'Hebrew',
|
||||
'hz' => 'Herero',
|
||||
'hil' => 'Hiligaynon',
|
||||
'him' => 'Himachali',
|
||||
'hi' => 'Hindi',
|
||||
'ho' => 'Hiri Motu',
|
||||
'hit' => 'Hittite',
|
||||
'hmn' => 'Hmong',
|
||||
'hu' => 'Hungarian',
|
||||
'hup' => 'Hupa',
|
||||
'iba' => 'Iban',
|
||||
'pt_PT' => 'Iberian Portuguese',
|
||||
'es_ES' => 'Iberian Spanish',
|
||||
'is' => 'Icelandic',
|
||||
'io' => 'Ido',
|
||||
'ig' => 'Igbo',
|
||||
'ijo' => 'Ijo',
|
||||
'ilo' => 'Iloko',
|
||||
'smn' => 'Inari Sami',
|
||||
'inc' => 'Indic Language',
|
||||
'ine' => 'Indo-European Language',
|
||||
'id' => 'Indonesian',
|
||||
'inh' => 'Ingush',
|
||||
'ia' => 'Interlingua',
|
||||
'ie' => 'Interlingue',
|
||||
'iu' => 'Inuktitut',
|
||||
'ik' => 'Inupiaq',
|
||||
'ira' => 'Iranian Language',
|
||||
'ga' => 'Irish',
|
||||
'iro' => 'Iroquoian Language',
|
||||
'it' => 'Italian',
|
||||
'ja' => 'Japanese',
|
||||
'jv' => 'Javanese',
|
||||
'kaj' => 'Jju',
|
||||
'dyo' => 'Jola-Fonyi',
|
||||
'jrb' => 'Judeo-Arabic',
|
||||
'jpr' => 'Judeo-Persian',
|
||||
'kbd' => 'Kabardian',
|
||||
'kea' => 'Kabuverdianu',
|
||||
'kab' => 'Kabyle',
|
||||
'kac' => 'Kachin',
|
||||
'kl' => 'Kalaallisut',
|
||||
'kln' => 'Kalenjin',
|
||||
'xal' => 'Kalmyk',
|
||||
'kam' => 'Kamba',
|
||||
'kn' => 'Kannada',
|
||||
'kr' => 'Kanuri',
|
||||
'kaa' => 'Kara-Kalpak',
|
||||
'krc' => 'Karachay-Balkar',
|
||||
'krl' => 'Karelian',
|
||||
'kar' => 'Karen',
|
||||
'ks' => 'Kashmiri',
|
||||
'csb' => 'Kashubian',
|
||||
'kaw' => 'Kawi',
|
||||
'kk' => 'Kazakh',
|
||||
'kha' => 'Khasi',
|
||||
'km' => 'Khmer',
|
||||
'khi' => 'Khoisan Language',
|
||||
'kho' => 'Khotanese',
|
||||
'ki' => 'Kikuyu',
|
||||
'kmb' => 'Kimbundu',
|
||||
'rw' => 'Kinyarwanda',
|
||||
'ky' => 'Kirghiz',
|
||||
'tlh' => 'Klingon',
|
||||
'kv' => 'Komi',
|
||||
'kg' => 'Kongo',
|
||||
'kok' => 'Konkani',
|
||||
'ko' => 'Korean',
|
||||
'kfo' => 'Koro',
|
||||
'kos' => 'Kosraean',
|
||||
'khq' => 'Koyra Chiini',
|
||||
'ses' => 'Koyraboro Senni',
|
||||
'kpe' => 'Kpelle',
|
||||
'kro' => 'Kru',
|
||||
'kj' => 'Kuanyama',
|
||||
'kum' => 'Kumyk',
|
||||
'ku' => 'Kurdish',
|
||||
'kru' => 'Kurukh',
|
||||
'kut' => 'Kutenai',
|
||||
'nmg' => 'Kwasio',
|
||||
'lad' => 'Ladino',
|
||||
'lah' => 'Lahnda',
|
||||
'lam' => 'Lamba',
|
||||
'lag' => 'Langi',
|
||||
'lo' => 'Lao',
|
||||
'la' => 'Latin',
|
||||
'es_419' => 'Latin American Spanish',
|
||||
'lv' => 'Latvian',
|
||||
'lez' => 'Lezghian',
|
||||
'li' => 'Limburgish',
|
||||
'ln' => 'Lingala',
|
||||
'lt' => 'Lithuanian',
|
||||
'jbo' => 'Lojban',
|
||||
'nds' => 'Low German',
|
||||
'dsb' => 'Lower Sorbian',
|
||||
'loz' => 'Lozi',
|
||||
'lu' => 'Luba-Katanga',
|
||||
'lua' => 'Luba-Lulua',
|
||||
'lui' => 'Luiseno',
|
||||
'smj' => 'Lule Sami',
|
||||
'lun' => 'Lunda',
|
||||
'luo' => 'Luo',
|
||||
'lus' => 'Lushai',
|
||||
'lb' => 'Luxembourgish',
|
||||
'luy' => 'Luyia',
|
||||
'mk' => 'Macedonian',
|
||||
'jmc' => 'Machame',
|
||||
'mad' => 'Madurese',
|
||||
'mag' => 'Magahi',
|
||||
'mai' => 'Maithili',
|
||||
'mak' => 'Makasar',
|
||||
'mgh' => 'Makhuwa-Meetto',
|
||||
'kde' => 'Makonde',
|
||||
'mg' => 'Malagasy',
|
||||
'ms' => 'Malay',
|
||||
'ml' => 'Malayalam',
|
||||
'mt' => 'Maltese',
|
||||
'mnc' => 'Manchu',
|
||||
'mdr' => 'Mandar',
|
||||
'man' => 'Mandingo',
|
||||
'mni' => 'Manipuri',
|
||||
'mno' => 'Manobo Language',
|
||||
'gv' => 'Manx',
|
||||
'mi' => 'Maori',
|
||||
'mr' => 'Marathi',
|
||||
'chm' => 'Mari',
|
||||
'mh' => 'Marshallese',
|
||||
'mwr' => 'Marwari',
|
||||
'mas' => 'Masai',
|
||||
'myn' => 'Mayan Language',
|
||||
'men' => 'Mende',
|
||||
'mer' => 'Meru',
|
||||
'mic' => 'Micmac',
|
||||
'dum' => 'Middle Dutch',
|
||||
'enm' => 'Middle English',
|
||||
'frm' => 'Middle French',
|
||||
'gmh' => 'Middle High German',
|
||||
'mga' => 'Middle Irish',
|
||||
'min' => 'Minangkabau',
|
||||
'mwl' => 'Mirandese',
|
||||
'mis' => 'Miscellaneous Language',
|
||||
'moh' => 'Mohawk',
|
||||
'mdf' => 'Moksha',
|
||||
'mo' => 'Moldavian',
|
||||
'mkh' => 'Mon-Khmer Language',
|
||||
'lol' => 'Mongo',
|
||||
'mn' => 'Mongolian',
|
||||
'mfe' => 'Morisyen',
|
||||
'mos' => 'Mossi',
|
||||
'mun' => 'Munda Language',
|
||||
'mua' => 'Mundang',
|
||||
'nqo' => 'N’Ko',
|
||||
'nah' => 'Nahuatl',
|
||||
'naq' => 'Nama',
|
||||
'na' => 'Nauru',
|
||||
'nv' => 'Navajo',
|
||||
'ng' => 'Ndonga',
|
||||
'nap' => 'Neapolitan',
|
||||
'ne' => 'Nepali',
|
||||
'new' => 'Newari',
|
||||
'nia' => 'Nias',
|
||||
'nic' => 'Niger-Kordofanian Language',
|
||||
'ssa' => 'Nilo-Saharan Language',
|
||||
'niu' => 'Niuean',
|
||||
'zxx' => 'No linguistic content',
|
||||
'nog' => 'Nogai',
|
||||
'nai' => 'North American Indian Language',
|
||||
'nd' => 'North Ndebele',
|
||||
'frr' => 'Northern Frisian',
|
||||
'se' => 'Northern Sami',
|
||||
'nso' => 'Northern Sotho',
|
||||
'no' => 'Norwegian',
|
||||
'nb' => 'Norwegian Bokmål',
|
||||
'nn' => 'Norwegian Nynorsk',
|
||||
'nub' => 'Nubian Language',
|
||||
'nus' => 'Nuer',
|
||||
'nym' => 'Nyamwezi',
|
||||
'ny' => 'Nyanja',
|
||||
'nyn' => 'Nyankole',
|
||||
'tog' => 'Nyasa Tonga',
|
||||
'nyo' => 'Nyoro',
|
||||
'nzi' => 'Nzima',
|
||||
'oc' => 'Occitan',
|
||||
'oj' => 'Ojibwa',
|
||||
'ang' => 'Old English',
|
||||
'fro' => 'Old French',
|
||||
'goh' => 'Old High German',
|
||||
'sga' => 'Old Irish',
|
||||
'non' => 'Old Norse',
|
||||
'peo' => 'Old Persian',
|
||||
'pro' => 'Old Provençal',
|
||||
'or' => 'Oriya',
|
||||
'om' => 'Oromo',
|
||||
'osa' => 'Osage',
|
||||
'os' => 'Ossetic',
|
||||
'oto' => 'Otomian Language',
|
||||
'ota' => 'Ottoman Turkish',
|
||||
'pal' => 'Pahlavi',
|
||||
'pau' => 'Palauan',
|
||||
'pi' => 'Pali',
|
||||
'pam' => 'Pampanga',
|
||||
'pag' => 'Pangasinan',
|
||||
'pap' => 'Papiamento',
|
||||
'paa' => 'Papuan Language',
|
||||
'ps' => 'Pashto',
|
||||
'fa' => 'Persian',
|
||||
'phi' => 'Philippine Language',
|
||||
'phn' => 'Phoenician',
|
||||
'pon' => 'Pohnpeian',
|
||||
'pl' => 'Polish',
|
||||
'pt' => 'Portuguese',
|
||||
'cpp' => 'Portuguese-based Creole or Pidgin',
|
||||
'pra' => 'Prakrit Language',
|
||||
'pa' => 'Punjabi',
|
||||
'qu' => 'Quechua',
|
||||
'raj' => 'Rajasthani',
|
||||
'rap' => 'Rapanui',
|
||||
'rar' => 'Rarotongan',
|
||||
'roa' => 'Romance Language',
|
||||
'ro' => 'Romanian',
|
||||
'rm' => 'Romansh',
|
||||
'rom' => 'Romany',
|
||||
'rof' => 'Rombo',
|
||||
'root' => 'Root',
|
||||
'rn' => 'Rundi',
|
||||
'ru' => 'Russian',
|
||||
'rwk' => 'Rwa',
|
||||
'ssy' => 'Saho',
|
||||
'sah' => 'Sakha',
|
||||
'sal' => 'Salishan Language',
|
||||
'sam' => 'Samaritan Aramaic',
|
||||
'saq' => 'Samburu',
|
||||
'smi' => 'Sami Language',
|
||||
'sm' => 'Samoan',
|
||||
'sad' => 'Sandawe',
|
||||
'sg' => 'Sango',
|
||||
'sbp' => 'Sangu',
|
||||
'sa' => 'Sanskrit',
|
||||
'sat' => 'Santali',
|
||||
'sc' => 'Sardinian',
|
||||
'sas' => 'Sasak',
|
||||
'sco' => 'Scots',
|
||||
'gd' => 'Scottish Gaelic',
|
||||
'sel' => 'Selkup',
|
||||
'sem' => 'Semitic Language',
|
||||
'seh' => 'Sena',
|
||||
'see' => 'Seneca',
|
||||
'sr' => 'Serbian',
|
||||
'sh' => 'Serbo-Croatian',
|
||||
'srr' => 'Serer',
|
||||
'ksb' => 'Shambala',
|
||||
'shn' => 'Shan',
|
||||
'sn' => 'Shona',
|
||||
'ii' => 'Sichuan Yi',
|
||||
'scn' => 'Sicilian',
|
||||
'sid' => 'Sidamo',
|
||||
'sgn' => 'Sign Language',
|
||||
'bla' => 'Siksika',
|
||||
'zh_Hans' => 'Simplified Chinese',
|
||||
'sd' => 'Sindhi',
|
||||
'si' => 'Sinhala',
|
||||
'sit' => 'Sino-Tibetan Language',
|
||||
'sio' => 'Siouan Language',
|
||||
'sms' => 'Skolt Sami',
|
||||
'den' => 'Slave',
|
||||
'sla' => 'Slavic Language',
|
||||
'sk' => 'Slovak',
|
||||
'sl' => 'Slovenian',
|
||||
'xog' => 'Soga',
|
||||
'sog' => 'Sogdien',
|
||||
'so' => 'Somali',
|
||||
'son' => 'Songhai',
|
||||
'snk' => 'Soninke',
|
||||
'wen' => 'Sorbian Language',
|
||||
'sai' => 'South American Indian Language',
|
||||
'nr' => 'South Ndebele',
|
||||
'alt' => 'Southern Altai',
|
||||
'sma' => 'Southern Sami',
|
||||
'st' => 'Southern Sotho',
|
||||
'es' => 'Spanish',
|
||||
'srn' => 'Sranan Tongo',
|
||||
'suk' => 'Sukuma',
|
||||
'sux' => 'Sumerian',
|
||||
'su' => 'Sundanese',
|
||||
'sus' => 'Susu',
|
||||
'sw' => 'Swahili',
|
||||
'ss' => 'Swati',
|
||||
'sv' => 'Swedish',
|
||||
'fr_CH' => 'Swiss French',
|
||||
'gsw' => 'Swiss German',
|
||||
'de_CH' => 'Swiss High German',
|
||||
'syr' => 'Syriac',
|
||||
'shi' => 'Tachelhit',
|
||||
'tl' => 'Tagalog',
|
||||
'ty' => 'Tahitian',
|
||||
'tai' => 'Tai Language',
|
||||
'dav' => 'Taita',
|
||||
'tg' => 'Tajik',
|
||||
'tmh' => 'Tamashek',
|
||||
'ta' => 'Tamil',
|
||||
'trv' => 'Taroko',
|
||||
'twq' => 'Tasawaq',
|
||||
'tt' => 'Tatar',
|
||||
'te' => 'Telugu',
|
||||
'ter' => 'Tereno',
|
||||
'teo' => 'Teso',
|
||||
'tet' => 'Tetum',
|
||||
'th' => 'Thai',
|
||||
'bo' => 'Tibetan',
|
||||
'tig' => 'Tigre',
|
||||
'ti' => 'Tigrinya',
|
||||
'tem' => 'Timne',
|
||||
'tiv' => 'Tiv',
|
||||
'tli' => 'Tlingit',
|
||||
'tpi' => 'Tok Pisin',
|
||||
'tkl' => 'Tokelau',
|
||||
'to' => 'Tongan',
|
||||
'zh_Hant' => 'Traditional Chinese',
|
||||
'tsi' => 'Tsimshian',
|
||||
'ts' => 'Tsonga',
|
||||
'tn' => 'Tswana',
|
||||
'tum' => 'Tumbuka',
|
||||
'tup' => 'Tupi Language',
|
||||
'tr' => 'Turkish',
|
||||
'tk' => 'Turkmen',
|
||||
'tvl' => 'Tuvalu',
|
||||
'tyv' => 'Tuvinian',
|
||||
'tw' => 'Twi',
|
||||
'kcg' => 'Tyap',
|
||||
'en_US' => 'U.S. English',
|
||||
'udm' => 'Udmurt',
|
||||
'uga' => 'Ugaritic',
|
||||
'ug' => 'Uighur',
|
||||
'uk' => 'Ukrainian',
|
||||
'umb' => 'Umbundu',
|
||||
'und' => 'Unknown Language',
|
||||
'hsb' => 'Upper Sorbian',
|
||||
'ur' => 'Urdu',
|
||||
'uz' => 'Uzbek',
|
||||
'vai' => 'Vai',
|
||||
've' => 'Venda',
|
||||
'vi' => 'Vietnamese',
|
||||
'vo' => 'Volapük',
|
||||
'vot' => 'Votic',
|
||||
'vun' => 'Vunjo',
|
||||
'wak' => 'Wakashan Language',
|
||||
'wal' => 'Walamo',
|
||||
'wa' => 'Walloon',
|
||||
'wae' => 'Walser',
|
||||
'war' => 'Waray',
|
||||
'was' => 'Washo',
|
||||
'cy' => 'Welsh',
|
||||
'fy' => 'Western Frisian',
|
||||
'wo' => 'Wolof',
|
||||
'xh' => 'Xhosa',
|
||||
'yav' => 'Yangben',
|
||||
'yao' => 'Yao',
|
||||
'yap' => 'Yapese',
|
||||
'yi' => 'Yiddish',
|
||||
'yo' => 'Yoruba',
|
||||
'ypk' => 'Yupik Language',
|
||||
'znd' => 'Zande',
|
||||
'zap' => 'Zapotec',
|
||||
'dje' => 'Zarma',
|
||||
'zza' => 'Zaza',
|
||||
'zen' => 'Zenaga',
|
||||
'za' => 'Zhuang',
|
||||
'zu' => 'Zulu',
|
||||
'zun' => 'Zuni',
|
||||
),
|
||||
'Scripts' => array(
|
||||
'Arab' => 'Arabic',
|
||||
'Armn' => 'Armenian',
|
||||
'Avst' => 'Avestan',
|
||||
'Bali' => 'Balinese',
|
||||
'Bamu' => 'Bamum',
|
||||
'Batk' => 'Batak',
|
||||
'Beng' => 'Bengali',
|
||||
'Blis' => 'Blissymbols',
|
||||
'Phlv' => 'Book Pahlavi',
|
||||
'Bopo' => 'Bopomofo',
|
||||
'Brah' => 'Brahmi',
|
||||
'Brai' => 'Braille',
|
||||
'Bugi' => 'Buginese',
|
||||
'Buhd' => 'Buhid',
|
||||
'Cari' => 'Carian',
|
||||
'Cakm' => 'Chakma',
|
||||
'Cham' => 'Cham',
|
||||
'Cher' => 'Cherokee',
|
||||
'Cirt' => 'Cirth',
|
||||
'Zyyy' => 'Common',
|
||||
'Copt' => 'Coptic',
|
||||
'Cprt' => 'Cypriot',
|
||||
'Cyrl' => 'Cyrillic',
|
||||
'Dsrt' => 'Deseret',
|
||||
'Deva' => 'Devanagari',
|
||||
'Syrn' => 'Eastern Syriac',
|
||||
'Egyd' => 'Egyptian demotic',
|
||||
'Egyh' => 'Egyptian hieratic',
|
||||
'Egyp' => 'Egyptian hieroglyphs',
|
||||
'Syre' => 'Estrangelo Syriac',
|
||||
'Ethi' => 'Ethiopic',
|
||||
'Latf' => 'Fraktur Latin',
|
||||
'Lisu' => 'Fraser',
|
||||
'Latg' => 'Gaelic Latin',
|
||||
'Geor' => 'Georgian',
|
||||
'Geok' => 'Georgian Khutsuri',
|
||||
'Glag' => 'Glagolitic',
|
||||
'Goth' => 'Gothic',
|
||||
'Gran' => 'Grantha',
|
||||
'Grek' => 'Greek',
|
||||
'Gujr' => 'Gujarati',
|
||||
'Guru' => 'Gurmukhi',
|
||||
'Hani' => 'Han',
|
||||
'Hang' => 'Hangul',
|
||||
'Hano' => 'Hanunoo',
|
||||
'Hebr' => 'Hebrew',
|
||||
'Hira' => 'Hiragana',
|
||||
'Armi' => 'Imperial Aramaic',
|
||||
'Inds' => 'Indus',
|
||||
'Zinh' => 'Inherited',
|
||||
'Phli' => 'Inscriptional Pahlavi',
|
||||
'Prti' => 'Inscriptional Parthian',
|
||||
'Jpan' => 'Japanese',
|
||||
'Java' => 'Javanese',
|
||||
'Kthi' => 'Kaithi',
|
||||
'Knda' => 'Kannada',
|
||||
'Kana' => 'Katakana',
|
||||
'Hrkt' => 'Katakana or Hiragana',
|
||||
'Kali' => 'Kayah Li',
|
||||
'Khar' => 'Kharoshthi',
|
||||
'Khmr' => 'Khmer',
|
||||
'Kore' => 'Korean',
|
||||
'Lana' => 'Lanna',
|
||||
'Laoo' => 'Lao',
|
||||
'Latn' => 'Latin',
|
||||
'Lepc' => 'Lepcha',
|
||||
'Limb' => 'Limbu',
|
||||
'Lina' => 'Linear A',
|
||||
'Linb' => 'Linear B',
|
||||
'Lyci' => 'Lycian',
|
||||
'Lydi' => 'Lydian',
|
||||
'Mlym' => 'Malayalam',
|
||||
'Mand' => 'Mandaean',
|
||||
'Mani' => 'Manichaean',
|
||||
'Zmth' => 'Mathematical Notation',
|
||||
'Maya' => 'Mayan hieroglyphs',
|
||||
'Mtei' => 'Meitei Mayek',
|
||||
'Mero' => 'Meroitic',
|
||||
'Merc' => 'Meroitic Cursive',
|
||||
'Mong' => 'Mongolian',
|
||||
'Moon' => 'Moon',
|
||||
'Mymr' => 'Myanmar',
|
||||
'Nkoo' => 'N’Ko',
|
||||
'Nkgb' => 'Naxi Geba',
|
||||
'Talu' => 'New Tai Lue',
|
||||
'Ogam' => 'Ogham',
|
||||
'Olck' => 'Ol Chiki',
|
||||
'Cyrs' => 'Old Church Slavonic Cyrillic',
|
||||
'Hung' => 'Old Hungarian',
|
||||
'Ital' => 'Old Italic',
|
||||
'Perm' => 'Old Permic',
|
||||
'Xpeo' => 'Old Persian',
|
||||
'Sarb' => 'Old South Arabian',
|
||||
'Orya' => 'Oriya',
|
||||
'Orkh' => 'Orkhon',
|
||||
'Osma' => 'Osmanya',
|
||||
'Hmng' => 'Pahawh Hmong',
|
||||
'Phag' => 'Phags-pa',
|
||||
'Phnx' => 'Phoenician',
|
||||
'Plrd' => 'Pollard Phonetic',
|
||||
'Phlp' => 'Psalter Pahlavi',
|
||||
'Rjng' => 'Rejang',
|
||||
'Roro' => 'Rongorongo',
|
||||
'Runr' => 'Runic',
|
||||
'Samr' => 'Samaritan',
|
||||
'Sara' => 'Sarati',
|
||||
'Saur' => 'Saurashtra',
|
||||
'Shaw' => 'Shavian',
|
||||
'Sgnw' => 'SignWriting',
|
||||
'Hans' => 'Simplified',
|
||||
'Sinh' => 'Sinhala',
|
||||
'Xsux' => 'Sumero-Akkadian Cuneiform',
|
||||
'Sund' => 'Sundanese',
|
||||
'Sylo' => 'Syloti Nagri',
|
||||
'Zsym' => 'Symbols',
|
||||
'Syrc' => 'Syriac',
|
||||
'Tglg' => 'Tagalog',
|
||||
'Tagb' => 'Tagbanwa',
|
||||
'Tale' => 'Tai Le',
|
||||
'Tavt' => 'Tai Viet',
|
||||
'Taml' => 'Tamil',
|
||||
'Telu' => 'Telugu',
|
||||
'Teng' => 'Tengwar',
|
||||
'Thaa' => 'Thaana',
|
||||
'Thai' => 'Thai',
|
||||
'Tibt' => 'Tibetan',
|
||||
'Tfng' => 'Tifinagh',
|
||||
'Hant' => 'Traditional',
|
||||
'Ugar' => 'Ugaritic',
|
||||
'Cans' => 'Unified Canadian Aboriginal Syllabics',
|
||||
'Zzzz' => 'Unknown Script',
|
||||
'Zxxx' => 'Unwritten',
|
||||
'Vaii' => 'Vai',
|
||||
'Wara' => 'Varang Kshiti',
|
||||
'Visp' => 'Visible Speech',
|
||||
'Syrj' => 'Western Syriac',
|
||||
'Yiii' => 'Yi',
|
||||
),
|
||||
);
|
|
@ -0,0 +1,279 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
return array(
|
||||
'Locales' => array(
|
||||
'af' => 'Afrikaans',
|
||||
'af_NA' => 'Afrikaans (Namibia)',
|
||||
'agq' => 'Aghem',
|
||||
'ak' => 'Akan',
|
||||
'sq' => 'Albanian',
|
||||
'am' => 'Amharic',
|
||||
'ar' => 'Arabic',
|
||||
'ar_DZ' => 'Arabic (Algeria)',
|
||||
'ar_JO' => 'Arabic (Jordan)',
|
||||
'ar_LB' => 'Arabic (Lebanon)',
|
||||
'ar_MA' => 'Arabic (Morocco)',
|
||||
'ar_QA' => 'Arabic (Qatar)',
|
||||
'ar_SA' => 'Arabic (Saudi Arabia)',
|
||||
'ar_SY' => 'Arabic (Syria)',
|
||||
'ar_TN' => 'Arabic (Tunisia)',
|
||||
'ar_YE' => 'Arabic (Yemen)',
|
||||
'hy' => 'Armenian',
|
||||
'as' => 'Assamese',
|
||||
'asa' => 'Asu',
|
||||
'az' => 'Azerbaijani',
|
||||
'az_Cyrl' => 'Azerbaijani (Cyrillic)',
|
||||
'az_Latn' => 'Azerbaijani (Latin)',
|
||||
'ksf' => 'Bafia',
|
||||
'bm' => 'Bambara',
|
||||
'bas' => 'Basaa',
|
||||
'eu' => 'Basque',
|
||||
'be' => 'Belarusian',
|
||||
'bem' => 'Bemba',
|
||||
'bez' => 'Bena',
|
||||
'bn' => 'Bengali',
|
||||
'bn_IN' => 'Bengali (India)',
|
||||
'brx' => 'Bodo',
|
||||
'bs' => 'Bosnian',
|
||||
'br' => 'Breton',
|
||||
'bg' => 'Bulgarian',
|
||||
'my' => 'Burmese',
|
||||
'my_MM' => 'Burmese (Myanmar [Burma])',
|
||||
'ca' => 'Catalan',
|
||||
'tzm' => 'Central Morocco Tamazight',
|
||||
'tzm_Latn' => 'Central Morocco Tamazight (Latin)',
|
||||
'chr' => 'Cherokee',
|
||||
'chr_US' => 'Cherokee (United States)',
|
||||
'cgg' => 'Chiga',
|
||||
'zh' => 'Chinese',
|
||||
'zh_Hans_HK' => 'Chinese (Simplified, Hong Kong SAR China)',
|
||||
'zh_Hans_MO' => 'Chinese (Simplified, Macau SAR China)',
|
||||
'zh_Hans_SG' => 'Chinese (Simplified, Singapore)',
|
||||
'zh_Hans' => 'Chinese (Simplified)',
|
||||
'zh_Hant_HK' => 'Chinese (Traditional, Hong Kong SAR China)',
|
||||
'zh_Hant_MO' => 'Chinese (Traditional, Macau SAR China)',
|
||||
'zh_Hant' => 'Chinese (Traditional)',
|
||||
'swc' => 'Congo Swahili',
|
||||
'kw' => 'Cornish',
|
||||
'hr' => 'Croatian',
|
||||
'cs' => 'Czech',
|
||||
'da' => 'Danish',
|
||||
'dua' => 'Duala',
|
||||
'nl' => 'Dutch',
|
||||
'nl_BE' => 'Dutch (Belgium)',
|
||||
'ebu' => 'Embu',
|
||||
'en' => 'English',
|
||||
'en_AU' => 'English (Australia)',
|
||||
'en_BE' => 'English (Belgium)',
|
||||
'en_BZ' => 'English (Belize)',
|
||||
'en_BW' => 'English (Botswana)',
|
||||
'en_CA' => 'English (Canada)',
|
||||
'en_HK' => 'English (Hong Kong SAR China)',
|
||||
'en_IN' => 'English (India)',
|
||||
'en_IE' => 'English (Ireland)',
|
||||
'en_JM' => 'English (Jamaica)',
|
||||
'en_MT' => 'English (Malta)',
|
||||
'en_NA' => 'English (Namibia)',
|
||||
'en_NZ' => 'English (New Zealand)',
|
||||
'en_PK' => 'English (Pakistan)',
|
||||
'en_PH' => 'English (Philippines)',
|
||||
'en_SG' => 'English (Singapore)',
|
||||
'en_ZA' => 'English (South Africa)',
|
||||
'en_TT' => 'English (Trinidad and Tobago)',
|
||||
'en_GB' => 'English (United Kingdom)',
|
||||
'en_US' => 'English (United States)',
|
||||
'en_ZW' => 'English (Zimbabwe)',
|
||||
'eo' => 'Esperanto',
|
||||
'et' => 'Estonian',
|
||||
'ee' => 'Ewe',
|
||||
'ewo' => 'Ewondo',
|
||||
'fo' => 'Faroese',
|
||||
'fil' => 'Filipino',
|
||||
'fil_PH' => 'Filipino (Philippines)',
|
||||
'fi' => 'Finnish',
|
||||
'fr' => 'French',
|
||||
'fr_BE' => 'French (Belgium)',
|
||||
'fr_CA' => 'French (Canada)',
|
||||
'fr_LU' => 'French (Luxembourg)',
|
||||
'fr_CH' => 'French (Switzerland)',
|
||||
'ff' => 'Fulah',
|
||||
'gl' => 'Galician',
|
||||
'lg' => 'Ganda',
|
||||
'ka' => 'Georgian',
|
||||
'de' => 'German',
|
||||
'de_AT' => 'German (Austria)',
|
||||
'de_LI' => 'German (Liechtenstein)',
|
||||
'de_CH' => 'German (Switzerland)',
|
||||
'el' => 'Greek',
|
||||
'el_CY' => 'Greek (Cyprus)',
|
||||
'gu' => 'Gujarati',
|
||||
'guz' => 'Gusii',
|
||||
'ha' => 'Hausa',
|
||||
'ha_Latn' => 'Hausa (Latin)',
|
||||
'haw' => 'Hawaiian',
|
||||
'haw_US' => 'Hawaiian (United States)',
|
||||
'he' => 'Hebrew',
|
||||
'hi' => 'Hindi',
|
||||
'hu' => 'Hungarian',
|
||||
'is' => 'Icelandic',
|
||||
'ig' => 'Igbo',
|
||||
'id' => 'Indonesian',
|
||||
'ga' => 'Irish',
|
||||
'it' => 'Italian',
|
||||
'it_CH' => 'Italian (Switzerland)',
|
||||
'ja' => 'Japanese',
|
||||
'dyo' => 'Jola-Fonyi',
|
||||
'kea' => 'Kabuverdianu',
|
||||
'kab' => 'Kabyle',
|
||||
'kl' => 'Kalaallisut',
|
||||
'kln' => 'Kalenjin',
|
||||
'kam' => 'Kamba',
|
||||
'kn' => 'Kannada',
|
||||
'kk' => 'Kazakh',
|
||||
'kk_Cyrl' => 'Kazakh (Cyrillic)',
|
||||
'km' => 'Khmer',
|
||||
'ki' => 'Kikuyu',
|
||||
'rw' => 'Kinyarwanda',
|
||||
'kok' => 'Konkani',
|
||||
'ko' => 'Korean',
|
||||
'khq' => 'Koyra Chiini',
|
||||
'ses' => 'Koyraboro Senni',
|
||||
'nmg' => 'Kwasio',
|
||||
'lag' => 'Langi',
|
||||
'lv' => 'Latvian',
|
||||
'ln' => 'Lingala',
|
||||
'lt' => 'Lithuanian',
|
||||
'lu' => 'Luba-Katanga',
|
||||
'luo' => 'Luo',
|
||||
'luy' => 'Luyia',
|
||||
'mk' => 'Macedonian',
|
||||
'jmc' => 'Machame',
|
||||
'mgh' => 'Makhuwa-Meetto',
|
||||
'kde' => 'Makonde',
|
||||
'mg' => 'Malagasy',
|
||||
'ms' => 'Malay',
|
||||
'ms_BN' => 'Malay (Brunei)',
|
||||
'ml' => 'Malayalam',
|
||||
'mt' => 'Maltese',
|
||||
'gv' => 'Manx',
|
||||
'mr' => 'Marathi',
|
||||
'mas' => 'Masai',
|
||||
'mer' => 'Meru',
|
||||
'mfe' => 'Morisyen',
|
||||
'mua' => 'Mundang',
|
||||
'naq' => 'Nama',
|
||||
'ne' => 'Nepali',
|
||||
'ne_IN' => 'Nepali (India)',
|
||||
'nd' => 'North Ndebele',
|
||||
'nb' => 'Norwegian Bokmål',
|
||||
'nn' => 'Norwegian Nynorsk',
|
||||
'nus' => 'Nuer',
|
||||
'nyn' => 'Nyankole',
|
||||
'or' => 'Oriya',
|
||||
'om' => 'Oromo',
|
||||
'ps' => 'Pashto',
|
||||
'fa' => 'Persian',
|
||||
'fa_AF' => 'Persian (Afghanistan)',
|
||||
'pl' => 'Polish',
|
||||
'pt' => 'Portuguese',
|
||||
'pt_AO' => 'Portuguese (Angola)',
|
||||
'pt_GW' => 'Portuguese (Guinea-Bissau)',
|
||||
'pt_MZ' => 'Portuguese (Mozambique)',
|
||||
'pt_PT' => 'Portuguese (Portugal)',
|
||||
'pt_ST' => 'Portuguese (São Tomé and Príncipe)',
|
||||
'pa' => 'Punjabi',
|
||||
'pa_Arab' => 'Punjabi (Arabic)',
|
||||
'pa_Guru' => 'Punjabi (Gurmukhi)',
|
||||
'ro' => 'Romanian',
|
||||
'rm' => 'Romansh',
|
||||
'rof' => 'Rombo',
|
||||
'rn' => 'Rundi',
|
||||
'ru' => 'Russian',
|
||||
'ru_UA' => 'Russian (Ukraine)',
|
||||
'rwk' => 'Rwa',
|
||||
'saq' => 'Samburu',
|
||||
'sg' => 'Sango',
|
||||
'sbp' => 'Sangu',
|
||||
'seh' => 'Sena',
|
||||
'sr' => 'Serbian',
|
||||
'sr_Cyrl_BA' => 'Serbian (Cyrillic, Bosnia and Herzegovina)',
|
||||
'sr_Cyrl' => 'Serbian (Cyrillic)',
|
||||
'sr_Latn_ME' => 'Serbian (Latin, Montenegro)',
|
||||
'sr_Latn' => 'Serbian (Latin)',
|
||||
'ksb' => 'Shambala',
|
||||
'sn' => 'Shona',
|
||||
'ii' => 'Sichuan Yi',
|
||||
'si' => 'Sinhala',
|
||||
'sk' => 'Slovak',
|
||||
'sl' => 'Slovenian',
|
||||
'xog' => 'Soga',
|
||||
'so' => 'Somali',
|
||||
'es' => 'Spanish',
|
||||
'es_AR' => 'Spanish (Argentina)',
|
||||
'es_BO' => 'Spanish (Bolivia)',
|
||||
'es_CL' => 'Spanish (Chile)',
|
||||
'es_CO' => 'Spanish (Colombia)',
|
||||
'es_CR' => 'Spanish (Costa Rica)',
|
||||
'es_DO' => 'Spanish (Dominican Republic)',
|
||||
'es_EC' => 'Spanish (Ecuador)',
|
||||
'es_SV' => 'Spanish (El Salvador)',
|
||||
'es_GQ' => 'Spanish (Equatorial Guinea)',
|
||||
'es_GT' => 'Spanish (Guatemala)',
|
||||
'es_HN' => 'Spanish (Honduras)',
|
||||
'es_MX' => 'Spanish (Mexico)',
|
||||
'es_NI' => 'Spanish (Nicaragua)',
|
||||
'es_PA' => 'Spanish (Panama)',
|
||||
'es_PY' => 'Spanish (Paraguay)',
|
||||
'es_PE' => 'Spanish (Peru)',
|
||||
'es_PR' => 'Spanish (Puerto Rico)',
|
||||
'es_US' => 'Spanish (United States)',
|
||||
'es_UY' => 'Spanish (Uruguay)',
|
||||
'es_VE' => 'Spanish (Venezuela)',
|
||||
'sw' => 'Swahili',
|
||||
'sw_KE' => 'Swahili (Kenya)',
|
||||
'sv' => 'Swedish',
|
||||
'sv_FI' => 'Swedish (Finland)',
|
||||
'gsw' => 'Swiss German',
|
||||
'shi' => 'Tachelhit',
|
||||
'shi_Tfng' => 'Tachelhit (Tifinagh)',
|
||||
'dav' => 'Taita',
|
||||
'ta' => 'Tamil',
|
||||
'twq' => 'Tasawaq',
|
||||
'te' => 'Telugu',
|
||||
'teo' => 'Teso',
|
||||
'th' => 'Thai',
|
||||
'bo' => 'Tibetan',
|
||||
'ti' => 'Tigrinya',
|
||||
'ti_ER' => 'Tigrinya (Eritrea)',
|
||||
'to' => 'Tongan',
|
||||
'tr' => 'Turkish',
|
||||
'uk' => 'Ukrainian',
|
||||
'ur' => 'Urdu',
|
||||
'ur_IN' => 'Urdu (India)',
|
||||
'uz' => 'Uzbek',
|
||||
'uz_Arab' => 'Uzbek (Arabic)',
|
||||
'uz_Cyrl' => 'Uzbek (Cyrillic)',
|
||||
'uz_Latn' => 'Uzbek (Latin)',
|
||||
'vai' => 'Vai',
|
||||
'vai_Latn_LR' => 'Vai (Latin, Liberia)',
|
||||
'vai_Latn' => 'Vai (Latin)',
|
||||
'vai_Vaii_LR' => 'Vai (Vai, Liberia)',
|
||||
'vai_Vaii' => 'Vai (Vai)',
|
||||
'vi' => 'Vietnamese',
|
||||
'vun' => 'Vunjo',
|
||||
'cy' => 'Welsh',
|
||||
'yav' => 'Yangben',
|
||||
'yo' => 'Yoruba',
|
||||
'dje' => 'Zarma',
|
||||
'zu' => 'Zulu',
|
||||
),
|
||||
);
|
|
@ -0,0 +1,272 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
return array(
|
||||
'Countries' => array(
|
||||
'AF' => 'Afghanistan',
|
||||
'AX' => 'Åland Islands',
|
||||
'AL' => 'Albania',
|
||||
'DZ' => 'Algeria',
|
||||
'AS' => 'American Samoa',
|
||||
'AD' => 'Andorra',
|
||||
'AO' => 'Angola',
|
||||
'AI' => 'Anguilla',
|
||||
'AQ' => 'Antarctica',
|
||||
'AG' => 'Antigua and Barbuda',
|
||||
'AR' => 'Argentina',
|
||||
'AM' => 'Armenia',
|
||||
'AW' => 'Aruba',
|
||||
'AC' => 'Ascension Island',
|
||||
'AU' => 'Australia',
|
||||
'AT' => 'Austria',
|
||||
'AZ' => 'Azerbaijan',
|
||||
'BS' => 'Bahamas',
|
||||
'BH' => 'Bahrain',
|
||||
'BD' => 'Bangladesh',
|
||||
'BB' => 'Barbados',
|
||||
'BY' => 'Belarus',
|
||||
'BE' => 'Belgium',
|
||||
'BZ' => 'Belize',
|
||||
'BJ' => 'Benin',
|
||||
'BM' => 'Bermuda',
|
||||
'BT' => 'Bhutan',
|
||||
'BO' => 'Bolivia',
|
||||
'BA' => 'Bosnia and Herzegovina',
|
||||
'BW' => 'Botswana',
|
||||
'BV' => 'Bouvet Island',
|
||||
'BR' => 'Brazil',
|
||||
'IO' => 'British Indian Ocean Territory',
|
||||
'VG' => 'British Virgin Islands',
|
||||
'BN' => 'Brunei',
|
||||
'BG' => 'Bulgaria',
|
||||
'BF' => 'Burkina Faso',
|
||||
'BI' => 'Burundi',
|
||||
'KH' => 'Cambodia',
|
||||
'CM' => 'Cameroon',
|
||||
'CA' => 'Canada',
|
||||
'IC' => 'Canary Islands',
|
||||
'CV' => 'Cape Verde',
|
||||
'KY' => 'Cayman Islands',
|
||||
'CF' => 'Central African Republic',
|
||||
'EA' => 'Ceuta and Melilla',
|
||||
'TD' => 'Chad',
|
||||
'CL' => 'Chile',
|
||||
'CN' => 'China',
|
||||
'CX' => 'Christmas Island',
|
||||
'CP' => 'Clipperton Island',
|
||||
'CC' => 'Cocos [Keeling] Islands',
|
||||
'CO' => 'Colombia',
|
||||
'KM' => 'Comoros',
|
||||
'CG' => 'Congo - Brazzaville',
|
||||
'CD' => 'Congo - Kinshasa',
|
||||
'CK' => 'Cook Islands',
|
||||
'CR' => 'Costa Rica',
|
||||
'CI' => 'Côte d’Ivoire',
|
||||
'HR' => 'Croatia',
|
||||
'CU' => 'Cuba',
|
||||
'CW' => 'Curaçao',
|
||||
'CY' => 'Cyprus',
|
||||
'CZ' => 'Czech Republic',
|
||||
'DK' => 'Denmark',
|
||||
'DG' => 'Diego Garcia',
|
||||
'DJ' => 'Djibouti',
|
||||
'DM' => 'Dominica',
|
||||
'DO' => 'Dominican Republic',
|
||||
'EC' => 'Ecuador',
|
||||
'EG' => 'Egypt',
|
||||
'SV' => 'El Salvador',
|
||||
'GQ' => 'Equatorial Guinea',
|
||||
'ER' => 'Eritrea',
|
||||
'EE' => 'Estonia',
|
||||
'ET' => 'Ethiopia',
|
||||
'EU' => 'European Union',
|
||||
'FK' => 'Falkland Islands',
|
||||
'FO' => 'Faroe Islands',
|
||||
'FJ' => 'Fiji',
|
||||
'FI' => 'Finland',
|
||||
'FR' => 'France',
|
||||
'GF' => 'French Guiana',
|
||||
'PF' => 'French Polynesia',
|
||||
'TF' => 'French Southern Territories',
|
||||
'GA' => 'Gabon',
|
||||
'GM' => 'Gambia',
|
||||
'GE' => 'Georgia',
|
||||
'DE' => 'Germany',
|
||||
'GH' => 'Ghana',
|
||||
'GI' => 'Gibraltar',
|
||||
'GR' => 'Greece',
|
||||
'GL' => 'Greenland',
|
||||
'GD' => 'Grenada',
|
||||
'GP' => 'Guadeloupe',
|
||||
'GU' => 'Guam',
|
||||
'GT' => 'Guatemala',
|
||||
'GG' => 'Guernsey',
|
||||
'GN' => 'Guinea',
|
||||
'GW' => 'Guinea-Bissau',
|
||||
'GY' => 'Guyana',
|
||||
'HT' => 'Haiti',
|
||||
'HM' => 'Heard Island and McDonald Islands',
|
||||
'HN' => 'Honduras',
|
||||
'HK' => 'Hong Kong SAR China',
|
||||
'HU' => 'Hungary',
|
||||
'IS' => 'Iceland',
|
||||
'IN' => 'India',
|
||||
'ID' => 'Indonesia',
|
||||
'IR' => 'Iran',
|
||||
'IQ' => 'Iraq',
|
||||
'IE' => 'Ireland',
|
||||
'IM' => 'Isle of Man',
|
||||
'IL' => 'Israel',
|
||||
'IT' => 'Italy',
|
||||
'JM' => 'Jamaica',
|
||||
'JP' => 'Japan',
|
||||
'JE' => 'Jersey',
|
||||
'JO' => 'Jordan',
|
||||
'KZ' => 'Kazakhstan',
|
||||
'KE' => 'Kenya',
|
||||
'KI' => 'Kiribati',
|
||||
'KW' => 'Kuwait',
|
||||
'KG' => 'Kyrgyzstan',
|
||||
'LA' => 'Laos',
|
||||
'LV' => 'Latvia',
|
||||
'LB' => 'Lebanon',
|
||||
'LS' => 'Lesotho',
|
||||
'LR' => 'Liberia',
|
||||
'LY' => 'Libya',
|
||||
'LI' => 'Liechtenstein',
|
||||
'LT' => 'Lithuania',
|
||||
'LU' => 'Luxembourg',
|
||||
'MO' => 'Macau SAR China',
|
||||
'MK' => 'Macedonia',
|
||||
'MG' => 'Madagascar',
|
||||
'MW' => 'Malawi',
|
||||
'MY' => 'Malaysia',
|
||||
'MV' => 'Maldives',
|
||||
'ML' => 'Mali',
|
||||
'MT' => 'Malta',
|
||||
'MH' => 'Marshall Islands',
|
||||
'MQ' => 'Martinique',
|
||||
'MR' => 'Mauritania',
|
||||
'MU' => 'Mauritius',
|
||||
'YT' => 'Mayotte',
|
||||
'MX' => 'Mexico',
|
||||
'FM' => 'Micronesia',
|
||||
'MD' => 'Moldova',
|
||||
'MC' => 'Monaco',
|
||||
'MN' => 'Mongolia',
|
||||
'ME' => 'Montenegro',
|
||||
'MS' => 'Montserrat',
|
||||
'MA' => 'Morocco',
|
||||
'MZ' => 'Mozambique',
|
||||
'MM' => 'Myanmar [Burma]',
|
||||
'NA' => 'Namibia',
|
||||
'NR' => 'Nauru',
|
||||
'NP' => 'Nepal',
|
||||
'NL' => 'Netherlands',
|
||||
'AN' => 'Netherlands Antilles',
|
||||
'NC' => 'New Caledonia',
|
||||
'NZ' => 'New Zealand',
|
||||
'NI' => 'Nicaragua',
|
||||
'NE' => 'Niger',
|
||||
'NG' => 'Nigeria',
|
||||
'NU' => 'Niue',
|
||||
'NF' => 'Norfolk Island',
|
||||
'KP' => 'North Korea',
|
||||
'MP' => 'Northern Mariana Islands',
|
||||
'NO' => 'Norway',
|
||||
'OM' => 'Oman',
|
||||
'QO' => 'Outlying Oceania',
|
||||
'PK' => 'Pakistan',
|
||||
'PW' => 'Palau',
|
||||
'PS' => 'Palestinian Territories',
|
||||
'PA' => 'Panama',
|
||||
'PG' => 'Papua New Guinea',
|
||||
'PY' => 'Paraguay',
|
||||
'PE' => 'Peru',
|
||||
'PH' => 'Philippines',
|
||||
'PN' => 'Pitcairn Islands',
|
||||
'PL' => 'Poland',
|
||||
'PT' => 'Portugal',
|
||||
'PR' => 'Puerto Rico',
|
||||
'QA' => 'Qatar',
|
||||
'RE' => 'Réunion',
|
||||
'RO' => 'Romania',
|
||||
'RU' => 'Russia',
|
||||
'RW' => 'Rwanda',
|
||||
'BL' => 'Saint Barthélemy',
|
||||
'SH' => 'Saint Helena',
|
||||
'KN' => 'Saint Kitts and Nevis',
|
||||
'LC' => 'Saint Lucia',
|
||||
'MF' => 'Saint Martin',
|
||||
'PM' => 'Saint Pierre and Miquelon',
|
||||
'VC' => 'Saint Vincent and the Grenadines',
|
||||
'WS' => 'Samoa',
|
||||
'SM' => 'San Marino',
|
||||
'ST' => 'São Tomé and Príncipe',
|
||||
'SA' => 'Saudi Arabia',
|
||||
'SN' => 'Senegal',
|
||||
'RS' => 'Serbia',
|
||||
'CS' => 'Serbia and Montenegro',
|
||||
'SC' => 'Seychelles',
|
||||
'SL' => 'Sierra Leone',
|
||||
'SG' => 'Singapore',
|
||||
'SX' => 'Sint Maarten',
|
||||
'SK' => 'Slovakia',
|
||||
'SI' => 'Slovenia',
|
||||
'SB' => 'Solomon Islands',
|
||||
'SO' => 'Somalia',
|
||||
'ZA' => 'South Africa',
|
||||
'GS' => 'South Georgia and the South Sandwich Islands',
|
||||
'KR' => 'South Korea',
|
||||
'ES' => 'Spain',
|
||||
'LK' => 'Sri Lanka',
|
||||
'SD' => 'Sudan',
|
||||
'SR' => 'Suriname',
|
||||
'SJ' => 'Svalbard and Jan Mayen',
|
||||
'SZ' => 'Swaziland',
|
||||
'SE' => 'Sweden',
|
||||
'CH' => 'Switzerland',
|
||||
'SY' => 'Syria',
|
||||
'TW' => 'Taiwan',
|
||||
'TJ' => 'Tajikistan',
|
||||
'TZ' => 'Tanzania',
|
||||
'TH' => 'Thailand',
|
||||
'TL' => 'Timor-Leste',
|
||||
'TG' => 'Togo',
|
||||
'TK' => 'Tokelau',
|
||||
'TO' => 'Tonga',
|
||||
'TT' => 'Trinidad and Tobago',
|
||||
'TA' => 'Tristan da Cunha',
|
||||
'TN' => 'Tunisia',
|
||||
'TR' => 'Turkey',
|
||||
'TM' => 'Turkmenistan',
|
||||
'TC' => 'Turks and Caicos Islands',
|
||||
'TV' => 'Tuvalu',
|
||||
'UM' => 'U.S. Minor Outlying Islands',
|
||||
'VI' => 'U.S. Virgin Islands',
|
||||
'UG' => 'Uganda',
|
||||
'UA' => 'Ukraine',
|
||||
'AE' => 'United Arab Emirates',
|
||||
'GB' => 'United Kingdom',
|
||||
'US' => 'United States',
|
||||
'UY' => 'Uruguay',
|
||||
'UZ' => 'Uzbekistan',
|
||||
'VU' => 'Vanuatu',
|
||||
'VA' => 'Vatican City',
|
||||
'VE' => 'Venezuela',
|
||||
'VN' => 'Vietnam',
|
||||
'WF' => 'Wallis and Futuna',
|
||||
'EH' => 'Western Sahara',
|
||||
'YE' => 'Yemen',
|
||||
'ZM' => 'Zambia',
|
||||
'ZW' => 'Zimbabwe',
|
||||
),
|
||||
);
|
|
@ -0,0 +1 @@
|
|||
4.8.1.1
|
|
@ -9,15 +9,15 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Intl\Collator\StubCollator;
|
||||
|
||||
/**
|
||||
* Stub implementation for the Collator class of the intl extension
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
* @see Symfony\Component\Collator\Stub\StubCollator
|
||||
*
|
||||
* @see Symfony\Component\Intl\Collator\StubCollator
|
||||
*/
|
||||
|
||||
use Symfony\Component\Locale\Stub\StubCollator;
|
||||
|
||||
class Collator extends StubCollator
|
||||
{
|
||||
}
|
|
@ -9,15 +9,15 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Intl\DateFormatter\StubIntlDateFormatter;
|
||||
|
||||
/**
|
||||
* Stub implementation for the IntlDateFormatter class of the intl extension
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
* @see Symfony\Component\IntlDateFormatter\Stub\StubIntlDateFormatter
|
||||
*
|
||||
* @see Symfony\Component\Intl\DateFormatter\StubIntlDateFormatter
|
||||
*/
|
||||
|
||||
use Symfony\Component\Locale\Stub\StubIntlDateFormatter;
|
||||
|
||||
class IntlDateFormatter extends StubIntlDateFormatter
|
||||
{
|
||||
}
|
|
@ -9,15 +9,15 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Intl\Locale\StubLocale;
|
||||
|
||||
/**
|
||||
* Stub implementation for the Locale class of the intl extension
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
* @see Symfony\Component\Locale\Stub\StubLocale
|
||||
*
|
||||
* @see Symfony\Component\Intl\Locale\StubLocale
|
||||
*/
|
||||
|
||||
use Symfony\Component\Locale\Stub\StubLocale;
|
||||
|
||||
class Locale extends StubLocale
|
||||
{
|
||||
}
|
|
@ -9,15 +9,15 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Intl\NumberFormatter\StubNumberFormatter;
|
||||
|
||||
/**
|
||||
* Stub implementation for the NumberFormatter class of the intl extension
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
* @see Symfony\Component\Locale\Stub\StubNumberFormatter
|
||||
*
|
||||
* @see Symfony\Component\Intl\NumberFormatter\StubNumberFormatter
|
||||
*/
|
||||
|
||||
use Symfony\Component\Locale\Stub\StubNumberFormatter;
|
||||
|
||||
class NumberFormatter extends StubNumberFormatter
|
||||
{
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Intl\Globals\StubIntlGlobals;
|
||||
|
||||
if (!function_exists('intl_is_failure')) {
|
||||
|
||||
/**
|
||||
* Stub implementation for the {@link intl_is_failure()} function of the intl
|
||||
* extension.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @param integer $errorCode The error code returned by intl_get_error_code().
|
||||
*
|
||||
* @return Boolean Whether the error code indicates an error.
|
||||
*
|
||||
* @see \Symfony\Component\Intl\Globals\StubIntlGlobals::isFailure
|
||||
*/
|
||||
function intl_is_failure($errorCode)
|
||||
{
|
||||
return StubIntlGlobals::isFailure($errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub implementation for the {@link intl_get_error_code()} function of the
|
||||
* intl extension.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @return Boolean The error code of the last intl function call or
|
||||
* StubIntlGlobals::U_ZERO_ERROR if no error occurred.
|
||||
*
|
||||
* @see \Symfony\Component\Intl\Globals\StubIntlGlobals::getErrorCode
|
||||
*/
|
||||
function intl_get_error_code()
|
||||
{
|
||||
return StubIntlGlobals::getErrorCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub implementation for the {@link intl_get_error_code()} function of the
|
||||
* intl extension.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @return Boolean The error message of the last intl function call or
|
||||
* "U_ZERO_ERROR" if no error occurred.
|
||||
*
|
||||
* @see \Symfony\Component\Intl\Globals\StubIntlGlobals::getErrorMessage
|
||||
*/
|
||||
function intl_get_error_message()
|
||||
{
|
||||
return StubIntlGlobals::getErrorMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub implementation for the {@link intl_error_name()} function of the intl
|
||||
* extension.
|
||||
*
|
||||
* @param integer $errorCode The error code.
|
||||
*
|
||||
* @return string The name of the error code constant.
|
||||
*
|
||||
* @see \Symfony\Component\Intl\Globals\StubIntlGlobals::getErrorName
|
||||
*/
|
||||
function intl_error_name($errorCode)
|
||||
{
|
||||
return StubIntlGlobals::getErrorName($errorCode);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Tests\Collator;
|
||||
|
||||
use Symfony\Component\Intl\Collator\StubCollator;
|
||||
use Symfony\Component\Intl\Locale;
|
||||
use Symfony\Component\Intl\Tests\IntlTestCase;
|
||||
|
||||
/**
|
||||
* Test case for Collator implementations.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
abstract class AbstractCollatorTest extends IntlTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider asortProvider
|
||||
*/
|
||||
public function testAsort($array, $sortFlag, $expected)
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$collator->asort($array, $sortFlag);
|
||||
$this->assertSame($expected, $array);
|
||||
}
|
||||
|
||||
public function asortProvider()
|
||||
{
|
||||
return array(
|
||||
/* array, sortFlag, expected */
|
||||
array(
|
||||
array('a', 'b', 'c'),
|
||||
StubCollator::SORT_REGULAR,
|
||||
array('a', 'b', 'c'),
|
||||
),
|
||||
array(
|
||||
array('c', 'b', 'a'),
|
||||
StubCollator::SORT_REGULAR,
|
||||
array(2 => 'a', 1 => 'b', 0 => 'c'),
|
||||
),
|
||||
array(
|
||||
array('b', 'c', 'a'),
|
||||
StubCollator::SORT_REGULAR,
|
||||
array(2 => 'a', 0 => 'b', 1 => 'c'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $locale
|
||||
*
|
||||
* @return \Collator
|
||||
*/
|
||||
abstract protected function getCollator($locale);
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Tests\Collator;
|
||||
|
||||
use Symfony\Component\Intl\Collator\StubCollator;
|
||||
use Symfony\Component\Intl\Globals\StubIntlGlobals;
|
||||
|
||||
class StubCollatorTest extends AbstractCollatorTest
|
||||
{
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
|
||||
*/
|
||||
public function testConstructorWithUnsupportedLocale()
|
||||
{
|
||||
new StubCollator('pt_BR');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
|
||||
*/
|
||||
public function testCompare()
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$collator->compare('a', 'b');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
|
||||
*/
|
||||
public function testGetAttribute()
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$collator->getAttribute(StubCollator::NUMERIC_COLLATION);
|
||||
}
|
||||
|
||||
public function testGetErrorCode()
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$this->assertEquals(StubIntlGlobals::U_ZERO_ERROR, $collator->getErrorCode());
|
||||
}
|
||||
|
||||
public function testGetErrorMessage()
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$this->assertEquals('U_ZERO_ERROR', $collator->getErrorMessage());
|
||||
}
|
||||
|
||||
public function testGetLocale()
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$this->assertEquals('en', $collator->getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
|
||||
*/
|
||||
public function testGetSortKey()
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$collator->getSortKey('Hello');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
|
||||
*/
|
||||
public function testGetStrength()
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$collator->getStrength();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
|
||||
*/
|
||||
public function testSetAttribute()
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$collator->setAttribute(StubCollator::NUMERIC_COLLATION, StubCollator::ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
|
||||
*/
|
||||
public function testSetStrength()
|
||||
{
|
||||
$collator = $this->getCollator('en');
|
||||
$collator->setStrength(StubCollator::PRIMARY);
|
||||
}
|
||||
|
||||
public function testStaticCreate()
|
||||
{
|
||||
$collator = StubCollator::create('en');
|
||||
$this->assertInstanceOf('Symfony\Component\Intl\Collator\StubCollator', $collator);
|
||||
}
|
||||
|
||||
protected function getCollator($locale)
|
||||
{
|
||||
return new StubCollator($locale);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Tests\Collator\Verification;
|
||||
|
||||
use Symfony\Component\Intl\Locale;
|
||||
use Symfony\Component\Intl\Tests\Collator\AbstractCollatorTest;
|
||||
|
||||
/**
|
||||
* Verifies that {@link AbstractCollatorTest} matches the behavior of the
|
||||
* {@link \Collator} class in a specific version of ICU.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class CollatorTest extends AbstractCollatorTest
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$this->skipIfIntlExtensionNotLoaded();
|
||||
$this->skipIfInsufficientIcuVersion();
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
protected function getCollator($locale)
|
||||
{
|
||||
return new \Collator($locale);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,965 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Tests\DateFormatter;
|
||||
|
||||
use Symfony\Component\Intl\DateFormatter\StubIntlDateFormatter;
|
||||
use Symfony\Component\Intl\Globals\StubIntlGlobals;
|
||||
use Symfony\Component\Intl\Intl;
|
||||
use Symfony\Component\Intl\Tests\IntlTestCase;
|
||||
use Symfony\Component\Intl\Util\IcuVersion;
|
||||
use Symfony\Component\Intl\Util\Version;
|
||||
|
||||
/**
|
||||
* Test case for IntlDateFormatter implementations.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
abstract class AbstractIntlDateFormatterTest extends IntlTestCase
|
||||
{
|
||||
/**
|
||||
* When a time zone is not specified, it uses the system default however it returns null in the getter method
|
||||
* @covers Symfony\Component\Intl\Stub\StubIntlDateFormatter::getTimeZoneId
|
||||
* @covers Symfony\Component\Intl\Stub\StubIntlDateFormatter::setTimeZoneId
|
||||
* @see StubIntlDateFormatterTest::testDefaultTimeZoneIntl()
|
||||
*/
|
||||
public function testConstructorDefaultTimeZone()
|
||||
{
|
||||
$formatter = $this->getDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
|
||||
|
||||
// In PHP 5.5 default timezone depends on `date_default_timezone_get()` method
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$this->assertEquals(date_default_timezone_get(), $formatter->getTimeZoneId());
|
||||
} else {
|
||||
$this->assertNull($formatter->getTimeZoneId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider formatProvider
|
||||
*/
|
||||
public function testFormat($pattern, $timestamp, $expected)
|
||||
{
|
||||
$errorCode = StubIntlGlobals::U_ZERO_ERROR;
|
||||
$errorMessage = 'U_ZERO_ERROR';
|
||||
|
||||
$formatter = $this->getDefaultDateFormatter($pattern);
|
||||
$this->assertSame($expected, $formatter->format($timestamp));
|
||||
$this->assertIsIntlSuccess($formatter, $errorMessage, $errorCode);
|
||||
}
|
||||
|
||||
public function formatProvider()
|
||||
{
|
||||
$formatData = array(
|
||||
/* general */
|
||||
array('y-M-d', 0, '1970-1-1'),
|
||||
array("EEE, MMM d, ''yy", 0, "Thu, Jan 1, '70"),
|
||||
array('h:mm a', 0, '12:00 AM'),
|
||||
array('yyyyy.MMMM.dd hh:mm aaa', 0, '01970.January.01 12:00 AM'),
|
||||
|
||||
/* escaping */
|
||||
array("'M'", 0, 'M'),
|
||||
array("'yy'", 0, 'yy'),
|
||||
array("'''yy'", 0, "'yy"),
|
||||
array("''y", 0, "'1970"),
|
||||
array("''yy", 0, "'70"),
|
||||
array("H 'o'' clock'", 0, "0 o' clock"),
|
||||
|
||||
/* month */
|
||||
array('M', 0, '1'),
|
||||
array('MM', 0, '01'),
|
||||
array('MMM', 0, 'Jan'),
|
||||
array('MMMM', 0, 'January'),
|
||||
array('MMMMM', 0, 'J'),
|
||||
array('MMMMMM', 0, '000001'),
|
||||
|
||||
array('L', 0, '1'),
|
||||
array('LL', 0, '01'),
|
||||
array('LLL', 0, 'Jan'),
|
||||
array('LLLL', 0, 'January'),
|
||||
array('LLLLL', 0, 'J'),
|
||||
array('LLLLLL', 0, '000001'),
|
||||
|
||||
/* year */
|
||||
array('y', 0, '1970'),
|
||||
array('yy', 0, '70'),
|
||||
array('yyy', 0, '1970'),
|
||||
array('yyyy', 0, '1970'),
|
||||
array('yyyyy', 0, '01970'),
|
||||
array('yyyyyy', 0, '001970'),
|
||||
|
||||
/* day */
|
||||
array('d', 0, '1'),
|
||||
array('dd', 0, '01'),
|
||||
array('ddd', 0, '001'),
|
||||
|
||||
/* quarter */
|
||||
array('Q', 0, '1'),
|
||||
array('QQ', 0, '01'),
|
||||
array('QQQ', 0, 'Q1'),
|
||||
array('QQQQ', 0, '1st quarter'),
|
||||
array('QQQQQ', 0, '1st quarter'),
|
||||
|
||||
array('q', 0, '1'),
|
||||
array('qq', 0, '01'),
|
||||
array('qqq', 0, 'Q1'),
|
||||
array('qqqq', 0, '1st quarter'),
|
||||
array('qqqqq', 0, '1st quarter'),
|
||||
|
||||
// 4 months
|
||||
array('Q', 7776000, '2'),
|
||||
array('QQ', 7776000, '02'),
|
||||
array('QQQ', 7776000, 'Q2'),
|
||||
array('QQQQ', 7776000, '2nd quarter'),
|
||||
|
||||
// 7 months
|
||||
array('QQQQ', 15638400, '3rd quarter'),
|
||||
|
||||
// 10 months
|
||||
array('QQQQ', 23587200, '4th quarter'),
|
||||
|
||||
/* 12-hour (1-12) */
|
||||
array('h', 0, '12'),
|
||||
array('hh', 0, '12'),
|
||||
array('hhh', 0, '012'),
|
||||
|
||||
array('h', 1, '12'),
|
||||
array('h', 3600, '1'),
|
||||
array('h', 43200, '12'), // 12 hours
|
||||
|
||||
/* day of year */
|
||||
array('D', 0, '1'),
|
||||
array('D', 86400, '2'), // 1 day
|
||||
array('D', 31536000, '1'), // 1 year
|
||||
array('D', 31622400, '2'), // 1 year + 1 day
|
||||
|
||||
/* day of week */
|
||||
array('E', 0, 'Thu'),
|
||||
array('EE', 0, 'Thu'),
|
||||
array('EEE', 0, 'Thu'),
|
||||
array('EEEE', 0, 'Thursday'),
|
||||
array('EEEEE', 0, 'T'),
|
||||
array('EEEEEE', 0, 'Thu'),
|
||||
|
||||
array('E', 1296540000, 'Tue'), // 2011-02-01
|
||||
array('E', 1296950400, 'Sun'), // 2011-02-06
|
||||
|
||||
/* am/pm marker */
|
||||
array('a', 0, 'AM'),
|
||||
array('aa', 0, 'AM'),
|
||||
array('aaa', 0, 'AM'),
|
||||
array('aaaa', 0, 'AM'),
|
||||
|
||||
// 12 hours
|
||||
array('a', 43200, 'PM'),
|
||||
array('aa', 43200, 'PM'),
|
||||
array('aaa', 43200, 'PM'),
|
||||
array('aaaa', 43200, 'PM'),
|
||||
|
||||
/* 24-hour (0-23) */
|
||||
array('H', 0, '0'),
|
||||
array('HH', 0, '00'),
|
||||
array('HHH', 0, '000'),
|
||||
|
||||
array('H', 1, '0'),
|
||||
array('H', 3600, '1'),
|
||||
array('H', 43200, '12'),
|
||||
array('H', 46800, '13'),
|
||||
|
||||
/* 24-hour (1-24) */
|
||||
array('k', 0, '24'),
|
||||
array('kk', 0, '24'),
|
||||
array('kkk', 0, '024'),
|
||||
|
||||
array('k', 1, '24'),
|
||||
array('k', 3600, '1'),
|
||||
array('k', 43200, '12'),
|
||||
array('k', 46800, '13'),
|
||||
|
||||
/* 12-hour (0-11) */
|
||||
array('K', 0, '0'),
|
||||
array('KK', 0, '00'),
|
||||
array('KKK', 0, '000'),
|
||||
|
||||
array('K', 1, '0'),
|
||||
array('K', 3600, '1'),
|
||||
array('K', 43200, '0'), // 12 hours
|
||||
|
||||
/* minute */
|
||||
array('m', 0, '0'),
|
||||
array('mm', 0, '00'),
|
||||
array('mmm', 0, '000'),
|
||||
|
||||
array('m', 1, '0'),
|
||||
array('m', 60, '1'),
|
||||
array('m', 120, '2'),
|
||||
array('m', 180, '3'),
|
||||
array('m', 3600, '0'),
|
||||
array('m', 3660, '1'),
|
||||
array('m', 43200, '0'), // 12 hours
|
||||
|
||||
/* second */
|
||||
array('s', 0, '0'),
|
||||
array('ss', 0, '00'),
|
||||
array('sss', 0, '000'),
|
||||
|
||||
array('s', 1, '1'),
|
||||
array('s', 2, '2'),
|
||||
array('s', 5, '5'),
|
||||
array('s', 30, '30'),
|
||||
array('s', 59, '59'),
|
||||
array('s', 60, '0'),
|
||||
array('s', 120, '0'),
|
||||
array('s', 180, '0'),
|
||||
array('s', 3600, '0'),
|
||||
array('s', 3601, '1'),
|
||||
array('s', 3630, '30'),
|
||||
array('s', 43200, '0'), // 12 hours
|
||||
);
|
||||
|
||||
// Timezone
|
||||
if (Intl::isExtensionLoaded() && IcuVersion::compare(Intl::getIcuVersion(), '4.8', '>=')) {
|
||||
// general
|
||||
$formatData[] = array("yyyy.MM.dd 'at' HH:mm:ss zzz", 0, '1970.01.01 at 00:00:00 GMT');
|
||||
$formatData[] = array('K:mm a, z', 0, '0:00 AM, GMT');
|
||||
|
||||
// timezone
|
||||
$formatData[] = array('z', 0, 'GMT');
|
||||
$formatData[] = array('zz', 0, 'GMT');
|
||||
$formatData[] = array('zzz', 0, 'GMT');
|
||||
$formatData[] = array('zzzz', 0, 'GMT');
|
||||
$formatData[] = array('zzzzz', 0, 'GMT');
|
||||
}
|
||||
|
||||
// As of PHP 5.3.4, IntlDateFormatter::format() accepts DateTime instances
|
||||
if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
|
||||
$dateTime = new \DateTime('@0');
|
||||
|
||||
/* general, DateTime */
|
||||
$formatData[] = array('y-M-d', $dateTime, '1970-1-1');
|
||||
$formatData[] = array("EEE, MMM d, ''yy", $dateTime, "Thu, Jan 1, '70");
|
||||
$formatData[] = array('h:mm a', $dateTime, '12:00 AM');
|
||||
$formatData[] = array('yyyyy.MMMM.dd hh:mm aaa', $dateTime, '01970.January.01 12:00 AM');
|
||||
|
||||
if (Intl::isExtensionLoaded() && IcuVersion::compare(Intl::getIcuVersion(), '4.8', '>=')) {
|
||||
$formatData[] = array("yyyy.MM.dd 'at' HH:mm:ss zzz", $dateTime, '1970.01.01 at 00:00:00 GMT');
|
||||
$formatData[] = array('K:mm a, z', $dateTime, '0:00 AM, GMT');
|
||||
}
|
||||
}
|
||||
|
||||
return $formatData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider formatErrorProvider
|
||||
*/
|
||||
public function testFormatIllegalArgumentError($pattern, $timestamp, $errorMessage)
|
||||
{
|
||||
$errorCode = StubIntlGlobals::U_ILLEGAL_ARGUMENT_ERROR;
|
||||
|
||||
$formatter = $this->getDefaultDateFormatter($pattern);
|
||||
$this->assertFalse($formatter->format($timestamp));
|
||||
$this->assertIsIntlFailure($formatter, $errorMessage, $errorCode);
|
||||
}
|
||||
|
||||
public function formatErrorProvider()
|
||||
{
|
||||
// With PHP 5.5 IntlDateFormatter accepts empty values ('0')
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
return array(
|
||||
array('y-M-d', 'foobar', 'datefmt_format: string \'foobar\' is not numeric, which would be required for it to be a valid date: U_ILLEGAL_ARGUMENT_ERROR')
|
||||
);
|
||||
}
|
||||
|
||||
$message = 'datefmt_format: takes either an array or an integer timestamp value : U_ILLEGAL_ARGUMENT_ERROR';
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
|
||||
$message = 'datefmt_format: takes either an array or an integer timestamp value or a DateTime object: U_ILLEGAL_ARGUMENT_ERROR';
|
||||
}
|
||||
|
||||
return array(
|
||||
array('y-M-d', '0', $message),
|
||||
array('y-M-d', 'foobar', $message),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider formatWithTimezoneProvider
|
||||
*/
|
||||
public function testFormatWithTimezone($timestamp, $timezone, $expected)
|
||||
{
|
||||
$pattern = 'yyyy-MM-dd HH:mm:ss';
|
||||
$formatter = $this->getDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT, $timezone, StubIntlDateFormatter::GREGORIAN, $pattern);
|
||||
$this->assertSame($expected, $formatter->format($timestamp));
|
||||
}
|
||||
|
||||
public function formatWithTimezoneProvider()
|
||||
{
|
||||
$data = array(
|
||||
array(0, 'UTC', '1970-01-01 00:00:00'),
|
||||
array(0, 'GMT', '1970-01-01 00:00:00'),
|
||||
array(0, 'GMT-03:00', '1969-12-31 21:00:00'),
|
||||
array(0, 'GMT+03:00', '1970-01-01 03:00:00'),
|
||||
array(0, 'Europe/Zurich', '1970-01-01 01:00:00'),
|
||||
array(0, 'Europe/Paris', '1970-01-01 01:00:00'),
|
||||
array(0, 'Africa/Cairo', '1970-01-01 02:00:00'),
|
||||
array(0, 'Africa/Casablanca', '1970-01-01 00:00:00'),
|
||||
array(0, 'Africa/Djibouti', '1970-01-01 03:00:00'),
|
||||
array(0, 'Africa/Johannesburg', '1970-01-01 02:00:00'),
|
||||
array(0, 'America/Antigua', '1969-12-31 20:00:00'),
|
||||
array(0, 'America/Toronto', '1969-12-31 19:00:00'),
|
||||
array(0, 'America/Vancouver', '1969-12-31 16:00:00'),
|
||||
array(0, 'Asia/Aqtau', '1970-01-01 05:00:00'),
|
||||
array(0, 'Asia/Bangkok', '1970-01-01 07:00:00'),
|
||||
array(0, 'Asia/Dubai', '1970-01-01 04:00:00'),
|
||||
array(0, 'Australia/Brisbane', '1970-01-01 10:00:00'),
|
||||
array(0, 'Australia/Eucla', '1970-01-01 08:45:00'),
|
||||
array(0, 'Australia/Melbourne', '1970-01-01 10:00:00'),
|
||||
array(0, 'Europe/Berlin', '1970-01-01 01:00:00'),
|
||||
array(0, 'Europe/Dublin', '1970-01-01 01:00:00'),
|
||||
array(0, 'Europe/Warsaw', '1970-01-01 01:00:00'),
|
||||
array(0, 'Pacific/Fiji', '1970-01-01 12:00:00'),
|
||||
);
|
||||
|
||||
// As of PHP 5.5, intl ext no longer fallbacks invalid time zones to UTC
|
||||
if (!version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
// When time zone not exists, uses UTC by default
|
||||
$data[] = array(0, 'Foo/Bar', '1970-01-01 00:00:00');
|
||||
$data[] = array(0, 'UTC+04:30', '1970-01-01 00:00:00');
|
||||
$data[] = array(0, 'UTC+04:AA', '1970-01-01 00:00:00');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testFormatWithGmtTimezone()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter('zzzz');
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$formatter->setTimeZone('GMT+03:00');
|
||||
} else {
|
||||
$formatter->setTimeZoneId('GMT+03:00');
|
||||
}
|
||||
|
||||
$this->assertEquals('GMT+03:00', $formatter->format(0));
|
||||
}
|
||||
|
||||
public function testFormatWithGmtTimeZoneAndMinutesOffset()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter('zzzz');
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$formatter->setTimeZone('GMT+00:30');
|
||||
} else {
|
||||
$formatter->setTimeZoneId('GMT+00:30');
|
||||
}
|
||||
|
||||
$this->assertEquals('GMT+00:30', $formatter->format(0));
|
||||
}
|
||||
|
||||
public function testFormatWithNonStandardTimezone()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter('zzzz');
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$formatter->setTimeZone('Pacific/Fiji');
|
||||
} else {
|
||||
$formatter->setTimeZoneId('Pacific/Fiji');
|
||||
}
|
||||
|
||||
$this->assertEquals('Fiji Standard Time', $formatter->format(0));
|
||||
}
|
||||
|
||||
public function testFormatWithConstructorTimezone()
|
||||
{
|
||||
$formatter = $this->getDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT, 'UTC');
|
||||
$formatter->setPattern('yyyy-MM-dd HH:mm:ss');
|
||||
|
||||
$this->assertEquals(
|
||||
$this->getDateTime(0)->format('Y-m-d H:i:s'),
|
||||
$formatter->format(0)
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatWithTimezoneFromEnvironmentVariable()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$this->markTestSkipped('IntlDateFormatter in PHP 5.5 no longer depends on TZ environment.');
|
||||
}
|
||||
|
||||
$tz = getenv('TZ');
|
||||
putenv('TZ=Europe/London');
|
||||
|
||||
$formatter = $this->getDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
|
||||
$formatter->setPattern('yyyy-MM-dd HH:mm:ss');
|
||||
|
||||
$this->assertEquals(
|
||||
$this->getDateTime(0)->format('Y-m-d H:i:s'),
|
||||
$formatter->format(0)
|
||||
);
|
||||
|
||||
$this->assertEquals('Europe/London', getenv('TZ'));
|
||||
|
||||
// Restores TZ.
|
||||
putenv('TZ='.$tz);
|
||||
}
|
||||
|
||||
public function testFormatWithTimezoneFromPhp()
|
||||
{
|
||||
if (!version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$this->markTestSkipped('Only in PHP 5.5 IntlDateFormatter depends on default timezone (`date_default_timezone_get()`).');
|
||||
}
|
||||
|
||||
$tz = date_default_timezone_get();
|
||||
date_default_timezone_set('Europe/London');
|
||||
|
||||
$formatter = $this->getDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
|
||||
$formatter->setPattern('yyyy-MM-dd HH:mm:ss');
|
||||
|
||||
$this->assertEquals(
|
||||
$this->getDateTime(0)->format('Y-m-d H:i:s'),
|
||||
$formatter->format(0)
|
||||
);
|
||||
|
||||
$this->assertEquals('Europe/London', date_default_timezone_get());
|
||||
|
||||
// Restores TZ.
|
||||
date_default_timezone_set($tz);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dateAndTimeTypeProvider
|
||||
*/
|
||||
public function testDateAndTimeType($timestamp, $datetype, $timetype, $expected)
|
||||
{
|
||||
$formatter = $this->getDateFormatter('en', $datetype, $timetype, 'UTC');
|
||||
$this->assertSame($expected, $formatter->format($timestamp));
|
||||
}
|
||||
|
||||
public function dateAndTimeTypeProvider()
|
||||
{
|
||||
$data = array(
|
||||
array(0, StubIntlDateFormatter::FULL, StubIntlDateFormatter::NONE, 'Thursday, January 1, 1970'),
|
||||
array(0, StubIntlDateFormatter::LONG, StubIntlDateFormatter::NONE, 'January 1, 1970'),
|
||||
array(0, StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::NONE, 'Jan 1, 1970'),
|
||||
array(0, StubIntlDateFormatter::SHORT, StubIntlDateFormatter::NONE, '1/1/70'),
|
||||
);
|
||||
|
||||
if (Intl::isExtensionLoaded() && IcuVersion::compare(Intl::getIcuVersion(), '4.8', '>=')) {
|
||||
$data[] = array(0, StubIntlDateFormatter::NONE, StubIntlDateFormatter::FULL, '12:00:00 AM GMT');
|
||||
$data[] = array(0, StubIntlDateFormatter::NONE, StubIntlDateFormatter::LONG, '12:00:00 AM GMT');
|
||||
}
|
||||
|
||||
$data[] = array(0, StubIntlDateFormatter::NONE, StubIntlDateFormatter::MEDIUM, '12:00:00 AM');
|
||||
$data[] = array(0, StubIntlDateFormatter::NONE, StubIntlDateFormatter::SHORT, '12:00 AM');
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testGetCalendar()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$this->assertEquals(StubIntlDateFormatter::GREGORIAN, $formatter->getCalendar());
|
||||
}
|
||||
|
||||
public function testGetDateType()
|
||||
{
|
||||
$formatter = $this->getDateFormatter('en', StubIntlDateFormatter::FULL, StubIntlDateFormatter::NONE);
|
||||
$this->assertEquals(StubIntlDateFormatter::FULL, $formatter->getDateType());
|
||||
}
|
||||
|
||||
public function testGetLocale()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$this->assertEquals('en', $formatter->getLocale());
|
||||
}
|
||||
|
||||
public function testGetPattern()
|
||||
{
|
||||
$formatter = $this->getDateFormatter('en', StubIntlDateFormatter::FULL, StubIntlDateFormatter::NONE, 'UTC', StubIntlDateFormatter::GREGORIAN, 'yyyy-MM-dd');
|
||||
$this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
|
||||
}
|
||||
|
||||
public function testGetTimeType()
|
||||
{
|
||||
$formatter = $this->getDateFormatter('en', StubIntlDateFormatter::NONE, StubIntlDateFormatter::FULL);
|
||||
$this->assertEquals(StubIntlDateFormatter::FULL, $formatter->getTimeType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider parseProvider
|
||||
*/
|
||||
public function testParse($pattern, $value, $expected)
|
||||
{
|
||||
$errorCode = StubIntlGlobals::U_ZERO_ERROR;
|
||||
$errorMessage = 'U_ZERO_ERROR';
|
||||
|
||||
$formatter = $this->getDefaultDateFormatter($pattern);
|
||||
$this->assertSame($expected, $formatter->parse($value));
|
||||
$this->assertIsIntlSuccess($formatter, $errorMessage, $errorCode);
|
||||
}
|
||||
|
||||
public function parseProvider()
|
||||
{
|
||||
return array_merge(
|
||||
$this->parseYearProvider(),
|
||||
$this->parseQuarterProvider(),
|
||||
$this->parseMonthProvider(),
|
||||
$this->parseStandaloneMonthProvider(),
|
||||
$this->parseDayProvider(),
|
||||
$this->parseDayOfWeekProvider(),
|
||||
$this->parseDayOfYearProvider(),
|
||||
$this->parseHour12ClockOneBasedProvider(),
|
||||
$this->parseHour12ClockZeroBasedProvider(),
|
||||
$this->parseHour24ClockOneBasedProvider(),
|
||||
$this->parseHour24ClockZeroBasedProvider(),
|
||||
$this->parseMinuteProvider(),
|
||||
$this->parseSecondProvider(),
|
||||
$this->parseTimezoneProvider(),
|
||||
$this->parseAmPmProvider(),
|
||||
$this->parseStandaloneAmPmProvider(),
|
||||
$this->parseRegexMetaCharsProvider(),
|
||||
$this->parseQuoteCharsProvider(),
|
||||
$this->parseDashSlashProvider()
|
||||
);
|
||||
}
|
||||
|
||||
public function parseYearProvider()
|
||||
{
|
||||
return array(
|
||||
array('y-M-d', '1970-1-1', 0),
|
||||
array('yy-M-d', '70-1-1', 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseQuarterProvider()
|
||||
{
|
||||
return array(
|
||||
array('Q', '1', 0),
|
||||
array('QQ', '01', 0),
|
||||
array('QQQ', 'Q1', 0),
|
||||
array('QQQQ', '1st quarter', 0),
|
||||
array('QQQQQ', '1st quarter', 0),
|
||||
|
||||
array('Q', '2', 7776000),
|
||||
array('QQ', '02', 7776000),
|
||||
array('QQQ', 'Q2', 7776000),
|
||||
array('QQQQ', '2nd quarter', 7776000),
|
||||
array('QQQQQ', '2nd quarter', 7776000),
|
||||
|
||||
array('q', '1', 0),
|
||||
array('qq', '01', 0),
|
||||
array('qqq', 'Q1', 0),
|
||||
array('qqqq', '1st quarter', 0),
|
||||
array('qqqqq', '1st quarter', 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseMonthProvider()
|
||||
{
|
||||
return array(
|
||||
array('y-M-d', '1970-1-1', 0),
|
||||
array('y-MMM-d', '1970-Jan-1', 0),
|
||||
array('y-MMMM-d', '1970-January-1', 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseStandaloneMonthProvider()
|
||||
{
|
||||
return array(
|
||||
array('y-L-d', '1970-1-1', 0),
|
||||
array('y-LLL-d', '1970-Jan-1', 0),
|
||||
array('y-LLLL-d', '1970-January-1', 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseDayProvider()
|
||||
{
|
||||
return array(
|
||||
array('y-M-d', '1970-1-1', 0),
|
||||
array('y-M-dd', '1970-1-01', 0),
|
||||
array('y-M-ddd', '1970-1-001', 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseDayOfWeekProvider()
|
||||
{
|
||||
return array(
|
||||
array('E', 'Thu', 0),
|
||||
array('EE', 'Thu', 0),
|
||||
array('EEE', 'Thu', 0),
|
||||
array('EEEE', 'Thursday', 0),
|
||||
array('EEEEE', 'T', 432000),
|
||||
array('EEEEEE', 'Thu', 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseDayOfYearProvider()
|
||||
{
|
||||
return array(
|
||||
array('D', '1', 0),
|
||||
array('D', '2', 86400),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseHour12ClockOneBasedProvider()
|
||||
{
|
||||
return array(
|
||||
// 12 hours (1-12)
|
||||
array('y-M-d h', '1970-1-1 1', 3600),
|
||||
array('y-M-d h', '1970-1-1 10', 36000),
|
||||
array('y-M-d hh', '1970-1-1 11', 39600),
|
||||
array('y-M-d hh', '1970-1-1 12', 0),
|
||||
array('y-M-d hh a', '1970-1-1 0 AM', 0),
|
||||
array('y-M-d hh a', '1970-1-1 1 AM', 3600),
|
||||
array('y-M-d hh a', '1970-1-1 10 AM', 36000),
|
||||
array('y-M-d hh a', '1970-1-1 11 AM', 39600),
|
||||
array('y-M-d hh a', '1970-1-1 12 AM', 0),
|
||||
array('y-M-d hh a', '1970-1-1 23 AM', 82800),
|
||||
array('y-M-d hh a', '1970-1-1 24 AM', 86400),
|
||||
array('y-M-d hh a', '1970-1-1 0 PM', 43200),
|
||||
array('y-M-d hh a', '1970-1-1 1 PM', 46800),
|
||||
array('y-M-d hh a', '1970-1-1 10 PM', 79200),
|
||||
array('y-M-d hh a', '1970-1-1 11 PM', 82800),
|
||||
array('y-M-d hh a', '1970-1-1 12 PM', 43200),
|
||||
array('y-M-d hh a', '1970-1-1 23 PM', 126000),
|
||||
array('y-M-d hh a', '1970-1-1 24 PM', 129600),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseHour12ClockZeroBasedProvider()
|
||||
{
|
||||
return array(
|
||||
// 12 hours (0-11)
|
||||
array('y-M-d K', '1970-1-1 1', 3600),
|
||||
array('y-M-d K', '1970-1-1 10', 36000),
|
||||
array('y-M-d KK', '1970-1-1 11', 39600),
|
||||
array('y-M-d KK', '1970-1-1 12', 43200),
|
||||
array('y-M-d KK a', '1970-1-1 0 AM', 0),
|
||||
array('y-M-d KK a', '1970-1-1 1 AM', 3600),
|
||||
array('y-M-d KK a', '1970-1-1 10 AM', 36000),
|
||||
array('y-M-d KK a', '1970-1-1 11 AM', 39600),
|
||||
array('y-M-d KK a', '1970-1-1 12 AM', 43200),
|
||||
array('y-M-d KK a', '1970-1-1 23 AM', 82800),
|
||||
array('y-M-d KK a', '1970-1-1 24 AM', 86400),
|
||||
array('y-M-d KK a', '1970-1-1 0 PM', 43200),
|
||||
array('y-M-d KK a', '1970-1-1 1 PM', 46800),
|
||||
array('y-M-d KK a', '1970-1-1 10 PM', 79200),
|
||||
array('y-M-d KK a', '1970-1-1 11 PM', 82800),
|
||||
array('y-M-d KK a', '1970-1-1 12 PM', 86400),
|
||||
array('y-M-d KK a', '1970-1-1 23 PM', 126000),
|
||||
array('y-M-d KK a', '1970-1-1 24 PM', 129600),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseHour24ClockOneBasedProvider()
|
||||
{
|
||||
return array(
|
||||
// 24 hours (1-24)
|
||||
array('y-M-d k', '1970-1-1 1', 3600),
|
||||
array('y-M-d k', '1970-1-1 10', 36000),
|
||||
array('y-M-d kk', '1970-1-1 11', 39600),
|
||||
array('y-M-d kk', '1970-1-1 12', 43200),
|
||||
array('y-M-d kk', '1970-1-1 23', 82800),
|
||||
array('y-M-d kk', '1970-1-1 24', 0),
|
||||
array('y-M-d kk a', '1970-1-1 0 AM', 0),
|
||||
array('y-M-d kk a', '1970-1-1 1 AM', 0),
|
||||
array('y-M-d kk a', '1970-1-1 10 AM', 0),
|
||||
array('y-M-d kk a', '1970-1-1 11 AM', 0),
|
||||
array('y-M-d kk a', '1970-1-1 12 AM', 0),
|
||||
array('y-M-d kk a', '1970-1-1 23 AM', 0),
|
||||
array('y-M-d kk a', '1970-1-1 24 AM', 0),
|
||||
array('y-M-d kk a', '1970-1-1 0 PM', 43200),
|
||||
array('y-M-d kk a', '1970-1-1 1 PM', 43200),
|
||||
array('y-M-d kk a', '1970-1-1 10 PM', 43200),
|
||||
array('y-M-d kk a', '1970-1-1 11 PM', 43200),
|
||||
array('y-M-d kk a', '1970-1-1 12 PM', 43200),
|
||||
array('y-M-d kk a', '1970-1-1 23 PM', 43200),
|
||||
array('y-M-d kk a', '1970-1-1 24 PM', 43200),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseHour24ClockZeroBasedProvider()
|
||||
{
|
||||
return array(
|
||||
// 24 hours (0-23)
|
||||
array('y-M-d H', '1970-1-1 0', 0),
|
||||
array('y-M-d H', '1970-1-1 1', 3600),
|
||||
array('y-M-d H', '1970-1-1 10', 36000),
|
||||
array('y-M-d HH', '1970-1-1 11', 39600),
|
||||
array('y-M-d HH', '1970-1-1 12', 43200),
|
||||
array('y-M-d HH', '1970-1-1 23', 82800),
|
||||
array('y-M-d HH a', '1970-1-1 0 AM', 0),
|
||||
array('y-M-d HH a', '1970-1-1 1 AM', 0),
|
||||
array('y-M-d HH a', '1970-1-1 10 AM', 0),
|
||||
array('y-M-d HH a', '1970-1-1 11 AM', 0),
|
||||
array('y-M-d HH a', '1970-1-1 12 AM', 0),
|
||||
array('y-M-d HH a', '1970-1-1 23 AM', 0),
|
||||
array('y-M-d HH a', '1970-1-1 24 AM', 0),
|
||||
array('y-M-d HH a', '1970-1-1 0 PM', 43200),
|
||||
array('y-M-d HH a', '1970-1-1 1 PM', 43200),
|
||||
array('y-M-d HH a', '1970-1-1 10 PM', 43200),
|
||||
array('y-M-d HH a', '1970-1-1 11 PM', 43200),
|
||||
array('y-M-d HH a', '1970-1-1 12 PM', 43200),
|
||||
array('y-M-d HH a', '1970-1-1 23 PM', 43200),
|
||||
array('y-M-d HH a', '1970-1-1 24 PM', 43200),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseMinuteProvider()
|
||||
{
|
||||
return array(
|
||||
array('y-M-d HH:m', '1970-1-1 0:1', 60),
|
||||
array('y-M-d HH:mm', '1970-1-1 0:10', 600),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseSecondProvider()
|
||||
{
|
||||
return array(
|
||||
array('y-M-d HH:mm:s', '1970-1-1 00:01:1', 61),
|
||||
array('y-M-d HH:mm:ss', '1970-1-1 00:01:10', 70),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseTimezoneProvider()
|
||||
{
|
||||
return array(
|
||||
array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-03:00', 10800),
|
||||
array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-04:00', 14400),
|
||||
array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-00:00', 0),
|
||||
array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+03:00', -10800),
|
||||
array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+04:00', -14400),
|
||||
array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT-0300', 10800),
|
||||
array('y-M-d HH:mm:ss zzzz', '1970-1-1 00:00:00 GMT+0300', -10800),
|
||||
|
||||
// a previous timezone parsing should not change the timezone for the next parsing
|
||||
array('y-M-d HH:mm:ss', '1970-1-1 00:00:00', 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseAmPmProvider()
|
||||
{
|
||||
return array(
|
||||
// AM/PM (already covered by hours tests)
|
||||
array('y-M-d HH:mm:ss a', '1970-1-1 00:00:00 AM', 0),
|
||||
array('y-M-d HH:mm:ss a', '1970-1-1 00:00:00 PM', 43200),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseStandaloneAmPmProvider()
|
||||
{
|
||||
return array(
|
||||
array('a', 'AM', 0),
|
||||
array('a', 'PM', 43200),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseRegexMetaCharsProvider()
|
||||
{
|
||||
return array(
|
||||
// regexp meta chars in the pattern string
|
||||
array('y[M-d', '1970[1-1', 0),
|
||||
array('y[M/d', '1970[1/1', 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseQuoteCharsProvider()
|
||||
{
|
||||
return array(
|
||||
array("'M'", 'M', 0),
|
||||
array("'yy'", 'yy', 0),
|
||||
array("'''yy'", "'yy", 0),
|
||||
array("''y", "'1970", 0),
|
||||
array("H 'o'' clock'", "0 o' clock", 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function parseDashSlashProvider()
|
||||
{
|
||||
return array(
|
||||
array('y-M-d', '1970/1/1', 0),
|
||||
array('yy-M-d', '70/1/1', 0),
|
||||
array('y/M/d', '1970-1-1', 0),
|
||||
array('yy/M/d', '70-1-1', 0),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider parseErrorProvider
|
||||
*/
|
||||
public function testParseError($pattern, $value)
|
||||
{
|
||||
$errorCode = StubIntlGlobals::U_PARSE_ERROR;
|
||||
$errorMessage = 'Date parsing failed: U_PARSE_ERROR';
|
||||
|
||||
$formatter = $this->getDefaultDateFormatter($pattern);
|
||||
$this->assertFalse($formatter->parse($value));
|
||||
$this->assertIsIntlFailure($formatter, $errorMessage, $errorCode);
|
||||
}
|
||||
|
||||
public function parseErrorProvider()
|
||||
{
|
||||
$data = array(
|
||||
// 1 char month
|
||||
array('y-MMMMM-d', '1970-J-1'),
|
||||
array('y-MMMMM-d', '1970-S-1'),
|
||||
|
||||
// standalone 1 char month
|
||||
array('y-LLLLL-d', '1970-J-1'),
|
||||
array('y-LLLLL-d', '1970-S-1'),
|
||||
);
|
||||
|
||||
if (!Intl::isExtensionLoaded() || IcuVersion::compare(Intl::getIcuVersion(), '4.8', '<')) {
|
||||
$data[] = array('y-M-d', '1970/1/1');
|
||||
$data[] = array('yy-M-d', '70/1/1');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/*
|
||||
* https://github.com/symfony/symfony/issues/4242
|
||||
*/
|
||||
public function testParseAfterError()
|
||||
{
|
||||
$this->testParseError('y-MMMMM-d', '1970-J-1');
|
||||
$this->testParse('y-M-d', '1970-1-1', 0);
|
||||
}
|
||||
|
||||
public function testParseWithNullPositionValue()
|
||||
{
|
||||
$position = null;
|
||||
$formatter = $this->getDefaultDateFormatter('y');
|
||||
$this->assertSame(0, $formatter->parse('1970', $position));
|
||||
$this->assertNull($position);
|
||||
}
|
||||
|
||||
public function testSetPattern()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$formatter->setPattern('yyyy-MM-dd');
|
||||
$this->assertEquals('yyyy-MM-dd', $formatter->getPattern());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\Intl\Stub\StubIntlDateFormatter::getTimeZoneId
|
||||
* @dataProvider setTimeZoneIdProvider
|
||||
*/
|
||||
public function testSetTimeZoneId($timeZoneId, $expectedTimeZoneId)
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$formatter->setTimeZone($timeZoneId);
|
||||
} else {
|
||||
$formatter->setTimeZoneId($timeZoneId);
|
||||
}
|
||||
|
||||
$this->assertEquals($expectedTimeZoneId, $formatter->getTimeZoneId());
|
||||
}
|
||||
|
||||
public function setTimeZoneIdProvider()
|
||||
{
|
||||
$data = array(
|
||||
array('UTC', 'UTC'),
|
||||
array('GMT', 'GMT'),
|
||||
array('GMT-03:00', 'GMT-03:00'),
|
||||
array('Europe/Zurich', 'Europe/Zurich'),
|
||||
);
|
||||
|
||||
// When time zone not exists, uses UTC by default
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$data[] = array('GMT-0300', 'UTC');
|
||||
$data[] = array('Foo/Bar', 'UTC');
|
||||
$data[] = array('GMT+00:AA', 'UTC');
|
||||
$data[] = array('GMT+00AA', 'UTC');
|
||||
} else {
|
||||
$data[] = array('GMT-0300', 'GMT-0300');
|
||||
$data[] = array('Foo/Bar', 'Foo/Bar');
|
||||
$data[] = array('GMT+00:AA', 'GMT+00:AA');
|
||||
$data[] = array('GMT+00AA', 'GMT+00AA');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getDefaultDateFormatter($pattern = null)
|
||||
{
|
||||
return $this->getDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT, 'UTC', StubIntlDateFormatter::GREGORIAN, $pattern);
|
||||
}
|
||||
|
||||
protected function getDateTime($timestamp = null)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
|
||||
$timeZone = date_default_timezone_get();
|
||||
} else {
|
||||
$timeZone = getenv('TZ') ?: 'UTC';
|
||||
}
|
||||
|
||||
$dateTime = new \DateTime();
|
||||
$dateTime->setTimestamp(null === $timestamp ? time() : $timestamp);
|
||||
$dateTime->setTimeZone(new \DateTimeZone($timeZone));
|
||||
|
||||
return $dateTime;
|
||||
}
|
||||
|
||||
protected function assertIsIntlFailure($formatter, $errorMessage, $errorCode)
|
||||
{
|
||||
$this->assertSame($errorMessage, $this->getIntlErrorMessage());
|
||||
$this->assertSame($errorCode, $this->getIntlErrorCode());
|
||||
$this->assertTrue($this->isIntlFailure($this->getIntlErrorCode()));
|
||||
$this->assertSame($errorMessage, $formatter->getErrorMessage());
|
||||
$this->assertSame($errorCode, $formatter->getErrorCode());
|
||||
$this->assertTrue($this->isIntlFailure($formatter->getErrorCode()));
|
||||
}
|
||||
|
||||
protected function assertIsIntlSuccess($formatter, $errorMessage, $errorCode)
|
||||
{
|
||||
/* @var StubIntlDateFormatter $formatter */
|
||||
$this->assertSame($errorMessage, $this->getIntlErrorMessage());
|
||||
$this->assertSame($errorCode, $this->getIntlErrorCode());
|
||||
$this->assertFalse($this->isIntlFailure($this->getIntlErrorCode()));
|
||||
$this->assertSame($errorMessage, $formatter->getErrorMessage());
|
||||
$this->assertSame($errorCode, $formatter->getErrorCode());
|
||||
$this->assertFalse($this->isIntlFailure($formatter->getErrorCode()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $locale
|
||||
* @param $datetype
|
||||
* @param $timetype
|
||||
* @param null $timezone
|
||||
* @param int $calendar
|
||||
* @param null $pattern
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = StubIntlDateFormatter::GREGORIAN, $pattern = null);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getIntlErrorMessage();
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
abstract protected function getIntlErrorCode();
|
||||
|
||||
/**
|
||||
* @param integer $errorCode
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
abstract protected function isIntlFailure($errorCode);
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Tests\DateFormatter;
|
||||
|
||||
use Symfony\Component\Intl\DateFormatter\StubIntlDateFormatter;
|
||||
use Symfony\Component\Intl\Globals\StubIntlGlobals;
|
||||
use Symfony\Component\Intl\Util\Version;
|
||||
|
||||
class StubIntlDateFormatterTest extends AbstractIntlDateFormatterTest
|
||||
{
|
||||
public function testConstructor()
|
||||
{
|
||||
$formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT, 'UTC', StubIntlDateFormatter::GREGORIAN, 'y-M-d');
|
||||
$this->assertEquals('y-M-d', $formatter->getPattern());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
|
||||
*/
|
||||
public function testConstructorWithUnsupportedLocale()
|
||||
{
|
||||
new StubIntlDateFormatter('pt_BR', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
|
||||
}
|
||||
|
||||
public function testStaticCreate()
|
||||
{
|
||||
$formatter = StubIntlDateFormatter::create('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT);
|
||||
$this->assertInstanceOf('Symfony\Component\Intl\DateFormatter\StubIntlDateFormatter', $formatter);
|
||||
}
|
||||
|
||||
public function testFormatWithUnsupportedTimestampArgument()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
|
||||
$localtime = array(
|
||||
'tm_sec' => 59,
|
||||
'tm_min' => 3,
|
||||
'tm_hour' => 15,
|
||||
'tm_mday' => 15,
|
||||
'tm_mon' => 3,
|
||||
'tm_year' => 112,
|
||||
'tm_wday' => 0,
|
||||
'tm_yday' => 105,
|
||||
'tm_isdst' => 0
|
||||
);
|
||||
|
||||
try {
|
||||
$formatter->format($localtime);
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException', $e);
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
|
||||
$this->assertStringEndsWith('Only integer unix timestamps and DateTime objects are supported. Please install the "intl" extension for full localization capabilities.', $e->getMessage());
|
||||
} else {
|
||||
$this->assertStringEndsWith('Only integer unix timestamps are supported. Please install the "intl" extension for full localization capabilities.', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
|
||||
*/
|
||||
public function testFormatWithUnimplementedChars()
|
||||
{
|
||||
$pattern = 'Y';
|
||||
$formatter = new StubIntlDateFormatter('en', StubIntlDateFormatter::MEDIUM, StubIntlDateFormatter::SHORT, 'UTC', StubIntlDateFormatter::GREGORIAN, $pattern);
|
||||
$formatter->format(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
|
||||
*/
|
||||
public function testFormatWithNonIntegerTimestamp()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$formatter->format(array());
|
||||
}
|
||||
|
||||
public function testGetErrorCode()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$this->assertEquals(StubIntlGlobals::getErrorCode(), $formatter->getErrorCode());
|
||||
}
|
||||
|
||||
public function testGetErrorMessage()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$this->assertEquals(StubIntlGlobals::getErrorMessage(), $formatter->getErrorMessage());
|
||||
}
|
||||
|
||||
public function testIsLenient()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$this->assertFalse($formatter->isLenient());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
|
||||
*/
|
||||
public function testLocaltime()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$formatter->localtime('Wednesday, December 31, 1969 4:00:00 PM PT');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException
|
||||
*/
|
||||
public function testParseWithNotNullPositionValue()
|
||||
{
|
||||
$position = 0;
|
||||
$formatter = $this->getDefaultDateFormatter('y');
|
||||
$this->assertSame(0, $formatter->parse('1970', $position));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodNotImplementedException
|
||||
*/
|
||||
public function testSetCalendar()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$formatter->setCalendar(StubIntlDateFormatter::GREGORIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException
|
||||
*/
|
||||
public function testSetLenient()
|
||||
{
|
||||
$formatter = $this->getDefaultDateFormatter();
|
||||
$formatter->setLenient(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
|
||||
*/
|
||||
public function testFormatWithGmtTimeZoneAndMinutesOffset()
|
||||
{
|
||||
parent::testFormatWithGmtTimeZoneAndMinutesOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Intl\Exception\NotImplementedException
|
||||
*/
|
||||
public function testFormatWithNonStandardTimezone()
|
||||
{
|
||||
parent::testFormatWithNonStandardTimezone();
|
||||
}
|
||||
|
||||
public function parseStandaloneAmPmProvider()
|
||||
{
|
||||
return $this->notImplemented(parent::parseStandaloneAmPmProvider());
|
||||
}
|
||||
|
||||
public function parseDayOfWeekProvider()
|
||||
{
|
||||
return $this->notImplemented(parent::parseDayOfWeekProvider());
|
||||
}
|
||||
|
||||
public function parseDayOfYearProvider()
|
||||
{
|
||||
return $this->notImplemented(parent::parseDayOfYearProvider());
|
||||
}
|
||||
|
||||
public function parseQuarterProvider()
|
||||
{
|
||||
return $this->notImplemented(parent::parseQuarterProvider());
|
||||
}
|
||||
|
||||
protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = StubIntlDateFormatter::GREGORIAN, $pattern = null)
|
||||
{
|
||||
return new StubIntlDateFormatter($locale, $datetype, $timetype, $timezone, $calendar, $pattern);
|
||||
}
|
||||
|
||||
protected function getIntlErrorMessage()
|
||||
{
|
||||
return StubIntlGlobals::getErrorMessage();
|
||||
}
|
||||
|
||||
protected function getIntlErrorCode()
|
||||
{
|
||||
return StubIntlGlobals::getErrorCode();
|
||||
}
|
||||
|
||||
protected function isIntlFailure($errorCode)
|
||||
{
|
||||
return StubIntlGlobals::isFailure($errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Just to document the differences between the stub and the intl
|
||||
* implementations. The intl can parse any of the tested formats alone. The
|
||||
* stub does not implement them as it would be needed to add more
|
||||
* abstraction, passing more context to the transformers objects. Any of the
|
||||
* formats are ignored alone or with date/time data (years, months, days,
|
||||
* hours, minutes and seconds).
|
||||
*
|
||||
* Also in intl, format like 'ss E' for '10 2' (2nd day of year
|
||||
* + 10 seconds) are added, then we have 86,400 seconds (24h * 60min * 60s)
|
||||
* + 10 seconds
|
||||
*
|
||||
* @param array $dataSets
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function notImplemented(array $dataSets)
|
||||
{
|
||||
return array_map(function ($row) {
|
||||
return array($row[0], $row[1], 0);
|
||||
}, $dataSets);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Tests\DateFormatter\Verification;
|
||||
|
||||
use Symfony\Component\Intl\DateFormatter\StubIntlDateFormatter;
|
||||
use Symfony\Component\Intl\Tests\DateFormatter\AbstractIntlDateFormatterTest;
|
||||
|
||||
/**
|
||||
* Verifies that {@link AbstractIntlDateFormatterTest} matches the behavior of
|
||||
* the {@link \IntlDateFormatter} class in a specific version of ICU.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class IntlDateFormatterTest extends AbstractIntlDateFormatterTest
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$this->skipIfIntlExtensionNotLoaded();
|
||||
$this->skipIfInsufficientIcuVersion();
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* It seems IntlDateFormatter caches the timezone id when not explicitly set via constructor or by the
|
||||
* setTimeZoneId() method. Since testFormatWithDefaultTimezoneIntl() runs using the default environment
|
||||
* time zone, this test would use it too if not running in a separated process.
|
||||
*
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testFormatWithTimezoneFromEnvironmentVariable()
|
||||
{
|
||||
parent::testFormatWithTimezoneFromEnvironmentVariable();
|
||||
}
|
||||
|
||||
protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = StubIntlDateFormatter::GREGORIAN, $pattern = null)
|
||||
{
|
||||
return new \IntlDateFormatter($locale, $datetype, $timetype, $timezone, $calendar, $pattern);
|
||||
}
|
||||
|
||||
protected function getIntlErrorMessage()
|
||||
{
|
||||
return intl_get_error_message();
|
||||
}
|
||||
|
||||
protected function getIntlErrorCode()
|
||||
{
|
||||
return intl_get_error_code();
|
||||
}
|
||||
|
||||
protected function isIntlFailure($errorCode)
|
||||
{
|
||||
return intl_is_failure($errorCode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Intl\Tests\Globals;
|
||||
|
||||
use Symfony\Component\Intl\Tests\IntlTestCase;
|
||||
|
||||
/**
|
||||
* Test case for intl function implementations.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
abstract class AbstractIntlGlobalsTest extends IntlTestCase
|
||||
{
|
||||
public function errorNameProvider()
|
||||
{
|
||||
return array (
|
||||
array(-129, '[BOGUS UErrorCode]'),
|
||||
array(0, 'U_ZERO_ERROR'),
|
||||
array(1, 'U_ILLEGAL_ARGUMENT_ERROR'),
|
||||
array(9, 'U_PARSE_ERROR'),
|
||||
array(129, '[BOGUS UErrorCode]'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider errorNameProvider
|
||||
*/
|
||||
public function testGetErrorName($errorCode, $errorName)
|
||||
{
|
||||
$this->assertSame($errorName, $this->getIntlErrorName($errorCode));
|
||||
}
|
||||
|
||||
abstract protected function getIntlErrorName($errorCode);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue