Skip to content

[Intl] Provide translated timezone names #17636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions src/Symfony/Component/Intl/Data/Generator/TimezoneDataGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<?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\Data\Generator;

use Symfony\Component\Intl\Data\Bundle\Reader\BundleReaderInterface;
use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle;
use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler;
use Symfony\Component\Intl\Data\Util\LocaleScanner;

/**
* The rule for compiling the currency bundle.
*
* @internal
*/
class TimezoneDataGenerator extends AbstractDataGenerator
{
/**
* Collects all available timezones.
*
* @var string[]
*/
private $timezones = array();

/**
* {@inheritdoc}
*/
protected function scanLocales(LocaleScanner $scanner, $sourceDir)
{
return $scanner->scanLocales($sourceDir.'/zone');
}

/**
* {@inheritdoc}
*/
protected function compileTemporaryBundles(GenrbCompiler $compiler, $sourceDir, $tempDir)
{
$compiler->compile($sourceDir.'/zone', $tempDir);
}

/**
* {@inheritdoc}
*/
protected function preGenerate()
{
$this->timezones = array();
}

/**
* {@inheritdoc}
*/
protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir, $displayLocale)
{
$localeBundle = $reader->read($tempDir, $displayLocale);

if (isset($localeBundle['zoneStrings']) && null !== $localeBundle['zoneStrings']) {
$data = array(
'Version' => $localeBundle['Version'],
'Names' => $this->generateTimezoneNames($localeBundle),
);

$this->timezones = array_merge($this->timezones, array_keys($data['Names']));

return $data;
}

return;
}

/**
* {@inheritdoc}
*/
protected function generateDataForRoot(BundleReaderInterface $reader, $tempDir)
{
$rootBundle = $reader->read($tempDir, 'root');

$names = $this->generateTimezoneNames($rootBundle);

foreach ($this->timezones as $timezone) {
if (!isset($names[$timezone])) {
$names[$timezone] = $this->getFallbackName($timezone);
}
}

ksort($names);

return array(
'Version' => $rootBundle['Version'],
'Names' => $names,
);
}

/**
* {@inheritdoc}
*/
protected function generateDataForMeta(BundleReaderInterface $reader, $tempDir)
{
$rootBundle = $reader->read($tempDir, 'root');

$this->timezones = array_unique($this->timezones);

sort($this->timezones);

$data = array(
'Version' => $rootBundle['Version'],
'Timezones' => $this->timezones,
);

return $data;
}

/**
* @param ArrayAccessibleResourceBundle $rootBundle
*
* @return array
*/
private function generateTimezoneNames(ArrayAccessibleResourceBundle $rootBundle)
{
$timezoneNames = array();
foreach ($rootBundle['zoneStrings'] as $key => $zone) {
if (strpos($key, ':') !== false && substr($key, 5) != 'meta:') {
$identifier = str_replace(':', '/', $key);

$zone = iterator_to_array($zone);

if (isset($zone['ec'])) {
$timezoneNames[$identifier] = $zone['ec'];
}
}
}

return $timezoneNames;
}

/**
* Converts a timezone identifier to an English string.
*
* @param string $timezone
*
* @return string
*/
private function getFallbackName($timezone)
{
$parts = explode('/', $timezone);
if (count($parts) > 2) {
$name = $parts[2].', '.$parts[1];
} elseif (count($parts) > 1) {
$name = $parts[1];
} else {
$name = $parts[0];
}

return str_replace('_', ' ', $name);
}
}
80 changes: 80 additions & 0 deletions src/Symfony/Component/Intl/Data/Provider/TimezoneDataProvider.php
Original file line number Diff line number Diff line change
@@ -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\Data\Provider;

use Symfony\Component\Intl\Locale;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;

/**
* Data provider for timezone-related data.
*
* @internal
*/
class TimezoneDataProvider
{
/**
* @var string
*/
private $path;

/**
* @var BundleEntryReaderInterface
*/
private $reader;

/**
* Creates a data provider that reads timezone-related data from a
* resource bundle.
*
* @param string $path The path to the resource bundle.
* @param BundleEntryReaderInterface $reader The reader for reading the resource bundle.
*/
public function __construct($path, BundleEntryReaderInterface $reader)
{
$this->path = $path;
$this->reader = $reader;
}

public function getIDs()
{
return $this->reader->readEntry($this->path, 'meta', array('Timezones'));
}

public function getName($zoneID, $displayLocale = null)
{
if (null === $displayLocale) {
$displayLocale = Locale::getDefault();
}

return $this->reader->readEntry($this->path, $displayLocale, array('Names', $zoneID));
}

public function getNames($displayLocale = null)
{
if (null === $displayLocale) {
$displayLocale = Locale::getDefault();
}

$names = $this->reader->readEntry($this->path, $displayLocale, array('Names'));

if ($names instanceof \Traversable) {
$names = iterator_to_array($names);
}

// Sorting by value cannot be done during bundle generation, because
// binary bundles are always sorted by keys
$collator = new \Collator($displayLocale);
$collator->asort($names);

return $names;
}
}
30 changes: 30 additions & 0 deletions src/Symfony/Component/Intl/Intl.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
use Symfony\Component\Intl\ResourceBundle\LocaleBundleInterface;
use Symfony\Component\Intl\ResourceBundle\RegionBundle;
use Symfony\Component\Intl\ResourceBundle\RegionBundleInterface;
use Symfony\Component\Intl\ResourceBundle\TimezoneBundle;
use Symfony\Component\Intl\ResourceBundle\TimezoneBundleInterface;

/**
* Gives access to internationalization data.
Expand Down Expand Up @@ -63,6 +65,11 @@ final class Intl
*/
const REGION_DIR = 'regions';

/**
* The directory name of the timezone data.
*/
const TIMEZONE_DIR = 'timezones';

/**
* @var ResourceBundle\CurrencyBundleInterface
*/
Expand All @@ -83,6 +90,11 @@ final class Intl
*/
private static $regionBundle;

/**
* @var ResourceBundle\TimezoneBundleInterface
*/
private static $timezoneBundle;

/**
* @var string|bool|null
*/
Expand Down Expand Up @@ -183,6 +195,24 @@ public static function getRegionBundle()
return self::$regionBundle;
}

/**
* Returns the bundle containing timezone information.
*
* @return TimezoneBundleInterface The timezone resource bundle.
*/
public static function getTimezoneBundle()
{
if (null === self::$timezoneBundle) {
self::$timezoneBundle = new TimezoneBundle(
self::getDataDirectory().'/'.self::TIMEZONE_DIR,
self::getEntryReader(),
self::getLocaleBundle()
);
}

return self::$timezoneBundle;
}

/**
* Returns the version of the installed ICU library.
*
Expand Down
87 changes: 87 additions & 0 deletions src/Symfony/Component/Intl/ResourceBundle/TimezoneBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?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\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Provider\LocaleDataProvider;
use Symfony\Component\Intl\Data\Provider\TimezoneDataProvider;
use Symfony\Component\Intl\Exception\MissingResourceException;

/**
* Default implementation of {@link TimezoneBundleInterface}.
*
* @internal
*/
class TimezoneBundle extends TimezoneDataProvider implements TimezoneBundleInterface
{
/**
* Creates a new timezone bundle.
*
* @param string $path
* @param BundleEntryReaderInterface $reader
* @param LocaleDataProvider $localeProvider
*/
public function __construct($path, BundleEntryReaderInterface $reader, LocaleDataProvider $localeProvider)
{
parent::__construct($path, $reader);

$this->localeProvider = $localeProvider;
}

/**
* {@inheritdoc}
*/
public function getIDs()
{
try {
return parent::getIDs();
} catch (MissingResourceException $e) {
return array();
}
}

/**
* {@inheritdoc}
*/
public function getTimezoneName($zoneID, $displayLocale = null)
{
try {
return $this->getName($zoneID, $displayLocale);
} catch (MissingResourceException $e) {
return;
}
}

/**
* {@inheritdoc}
*/
public function getTimezoneNames($displayLocale = null)
{
try {
return $this->getNames($displayLocale);
} catch (MissingResourceException $e) {
return array();
}
}

/**
* {@inheritdoc}
*/
public function getLocales()
{
try {
return $this->localeProvider->getLocales();
} catch (MissingResourceException $e) {
return array();
}
}
}
Loading