Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit bfdb4ed

Browse filesBrowse files
committed
[Intl] Revise timezone name generation
1 parent 7a53e8d commit bfdb4ed
Copy full SHA for bfdb4ed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner

136 files changed

+3900
-6778
lines changed

‎src/Symfony/Component/Intl/Data/Generator/TimezoneDataGenerator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Intl/Data/Generator/TimezoneDataGenerator.php
+111-96Lines changed: 111 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,24 @@
2828
*/
2929
class TimezoneDataGenerator extends AbstractDataGenerator
3030
{
31+
use FallbackTrait;
32+
3133
/**
3234
* Collects all available zone IDs.
3335
*
3436
* @var string[]
3537
*/
3638
private $zoneIds = [];
39+
private $zoneToCountryMapping = [];
40+
private $localeAliases = [];
3741

3842
/**
3943
* {@inheritdoc}
4044
*/
4145
protected function scanLocales(LocaleScanner $scanner, $sourceDir)
4246
{
47+
$this->localeAliases = $scanner->scanAliases($sourceDir.'/locales');
48+
4349
return $scanner->scanLocales($sourceDir.'/zone');
4450
}
4551

@@ -63,50 +69,71 @@ protected function compileTemporaryBundles(BundleCompilerInterface $compiler, $s
6369
protected function preGenerate()
6470
{
6571
$this->zoneIds = [];
72+
$this->zoneToCountryMapping = [];
6673
}
6774

6875
/**
6976
* {@inheritdoc}
7077
*/
7178
protected function generateDataForLocale(BundleEntryReaderInterface $reader, $tempDir, $displayLocale)
7279
{
73-
$localeBundle = $reader->read($tempDir, $displayLocale);
80+
if (!$this->zoneToCountryMapping) {
81+
$this->zoneToCountryMapping = self::generateZoneToCountryMapping($reader->read($tempDir, 'windowsZones'));
82+
}
7483

75-
if (isset($localeBundle['zoneStrings']) && null !== $localeBundle['zoneStrings']) {
76-
$localeBundles = [$localeBundle];
77-
$fallback = $displayLocale;
78-
while (null !== ($fallback = Locale::getFallback($fallback))) {
79-
$localeBundles[] = $reader->read($tempDir, $fallback);
80-
}
81-
$metadata = [];
82-
$data = [
83-
'Version' => $localeBundle['Version'],
84-
'Names' => $this->generateZones(
85-
$reader,
86-
$tempDir,
87-
$displayLocale,
88-
$localeBundles,
89-
$metadata
90-
),
91-
];
92-
93-
if (!$data['Names'] && !$metadata) {
94-
return;
95-
}
84+
// Don't generate aliases, as they are resolved during runtime
85+
// Unless an alias is needed as fallback for de-duplication purposes
86+
if (isset($this->localeAliases[$displayLocale]) && !$this->generatingFallback) {
87+
return;
88+
}
9689

97-
$data['Meta'] = $metadata;
90+
$localeBundle = $reader->read($tempDir, $displayLocale);
91+
92+
if (!isset($localeBundle['zoneStrings']) || null === $localeBundle['zoneStrings']) {
93+
return;
94+
}
9895

99-
$this->zoneIds = array_merge($this->zoneIds, array_keys($data['Names']));
96+
$data = [
97+
'Version' => $localeBundle['Version'],
98+
'Names' => $this->generateZones($reader, $tempDir, $displayLocale),
99+
'Meta' => self::generateZoneMetadata($localeBundle),
100+
];
100101

102+
// Don't de-duplicate a fallback locale
103+
// Ensures the display locale can be de-duplicated on itself
104+
if ($this->generatingFallback) {
101105
return $data;
102106
}
107+
108+
// Process again to de-duplicate locales and their fallback locales
109+
// Only keep the differences
110+
$fallback = $this->generateFallbackData($reader, $tempDir, $displayLocale);
111+
if (isset($fallback['Names'])) {
112+
$data['Names'] = array_diff($data['Names'], $fallback['Names']);
113+
}
114+
if (isset($fallback['Meta'])) {
115+
$data['Meta'] = array_diff($data['Meta'], $fallback['Meta']);
116+
}
117+
if (!$data['Names'] && !$data['Meta']) {
118+
return;
119+
}
120+
121+
$this->zoneIds = array_merge($this->zoneIds, array_keys($data['Names']));
122+
123+
return $data;
103124
}
104125

105126
/**
106127
* {@inheritdoc}
107128
*/
108129
protected function generateDataForRoot(BundleEntryReaderInterface $reader, $tempDir)
109130
{
131+
$rootBundle = $reader->read($tempDir, 'root');
132+
133+
return [
134+
'Version' => $rootBundle['Version'],
135+
'Meta' => self::generateZoneMetadata($rootBundle),
136+
];
110137
}
111138

112139
/**
@@ -119,66 +146,21 @@ protected function generateDataForMeta(BundleEntryReaderInterface $reader, $temp
119146
$this->zoneIds = array_unique($this->zoneIds);
120147

121148
sort($this->zoneIds);
149+
ksort($this->zoneToCountryMapping);
122150

123151
$data = [
124152
'Version' => $rootBundle['Version'],
125153
'Zones' => $this->zoneIds,
126-
'ZoneToCountry' => self::generateZoneToCountryMapping($reader->read($tempDir, 'windowsZones')),
154+
'ZoneToCountry' => $this->zoneToCountryMapping,
155+
'CountryToZone' => self::generateCountryToZoneMapping($this->zoneToCountryMapping),
127156
];
128157

129-
$data['CountryToZone'] = self::generateCountryToZoneMapping($data['ZoneToCountry']);
130-
131158
return $data;
132159
}
133160

134-
/**
135-
* @param ArrayAccessibleResourceBundle[] $localeBundles
136-
*/
137-
private function generateZones(BundleEntryReaderInterface $reader, string $tempDir, string $locale, array $localeBundles, array &$metadata = []): array
161+
private function generateZones(BundleEntryReaderInterface $reader, string $tempDir, string $locale): array
138162
{
139163
$typeBundle = $reader->read($tempDir, 'timezoneTypes');
140-
$metaBundle = $reader->read($tempDir, 'metaZones');
141-
$windowsZonesBundle = $reader->read($tempDir, 'windowsZones');
142-
$accessor = static function (ArrayAccessibleResourceBundle $resourceBundle, array $indices) {
143-
$result = $resourceBundle;
144-
foreach ($indices as $indice) {
145-
$result = $result[$indice] ?? null;
146-
}
147-
148-
return $result;
149-
};
150-
$accessor = static function (array $indices, &$inherited = false) use ($localeBundles, $accessor) {
151-
$inherited = false;
152-
foreach ($localeBundles as $i => $localeBundle) {
153-
$nextLocaleBundle = $localeBundles[$i + 1] ?? null;
154-
$result = $accessor($localeBundle, $indices);
155-
if (null !== $result && (null === $nextLocaleBundle || $result !== $accessor($nextLocaleBundle, $indices))) {
156-
$inherited = 0 !== $i;
157-
158-
return $result;
159-
}
160-
}
161-
162-
return null;
163-
};
164-
$regionFormat = $reader->readEntry($tempDir, $locale, ['zoneStrings', 'regionFormat']);
165-
$fallbackFormat = $reader->readEntry($tempDir, $locale, ['zoneStrings', 'fallbackFormat']);
166-
$zoneToCountry = self::generateZoneToCountryMapping($windowsZonesBundle);
167-
$resolveName = function (string $id, string $city = null) use ($reader, $tempDir, $locale, $regionFormat, $fallbackFormat, $zoneToCountry): ?string {
168-
if (isset($zoneToCountry[$id])) {
169-
try {
170-
$country = $reader->readEntry($tempDir.'/region', $locale, ['Countries', $zoneToCountry[$id]]);
171-
} catch (MissingResourceException $e) {
172-
return null;
173-
}
174-
175-
return null === $city ? str_replace('{0}', $country, $regionFormat) : str_replace(['{0}', '{1}'], [$city, $country], $fallbackFormat);
176-
} elseif (null !== $city) {
177-
return str_replace('{0}', $city, $regionFormat);
178-
} else {
179-
return str_replace(['/', '_'], ' ', 0 === strrpos($id, 'Etc/') ? substr($id, 4) : $id);
180-
}
181-
};
182164
$available = [];
183165
foreach ($typeBundle['typeMap']['timezone'] as $zone => $_) {
184166
if ('Etc:Unknown' === $zone || preg_match('~^Etc:GMT[-+]\d+$~', $zone)) {
@@ -188,64 +170,97 @@ private function generateZones(BundleEntryReaderInterface $reader, string $tempD
188170
$available[$zone] = true;
189171
}
190172

173+
$metaBundle = $reader->read($tempDir, 'metaZones');
191174
$metazones = [];
192175
foreach ($metaBundle['metazoneInfo'] as $zone => $info) {
193176
foreach ($info as $metazone) {
194177
$metazones[$zone] = $metazone->get(0);
195178
}
196179
}
197180

198-
$isBase = false === strpos($locale, '_');
181+
$regionFormat = $reader->readEntry($tempDir, $locale, ['zoneStrings', 'regionFormat']);
182+
$fallbackFormat = $reader->readEntry($tempDir, $locale, ['zoneStrings', 'fallbackFormat']);
183+
$resolveName = function (string $id, string $city = null) use ($reader, $tempDir, $locale, $regionFormat, $fallbackFormat): ?string {
184+
// Resolve default name as described per http://cldr.unicode.org/translation/timezones
185+
if (isset($this->zoneToCountryMapping[$id])) {
186+
try {
187+
$country = $reader->readEntry($tempDir.'/region', $locale, ['Countries', $this->zoneToCountryMapping[$id]]);
188+
} catch (MissingResourceException $e) {
189+
return null;
190+
}
191+
192+
$name = str_replace('{0}', $country, $regionFormat);
193+
194+
return null === $city ? $name : str_replace(['{0}', '{1}'], [$city, $name], $fallbackFormat);
195+
}
196+
if (null !== $city) {
197+
return str_replace('{0}', $city, $regionFormat);
198+
}
199+
200+
return null;
201+
};
202+
$accessor = static function (array $indices, array ...$fallbackIndices) use ($locale, $reader, $tempDir) {
203+
foreach (\func_get_args() as $indices) {
204+
try {
205+
return $reader->readEntry($tempDir, $locale, $indices);
206+
} catch (MissingResourceException $e) {
207+
}
208+
}
209+
210+
return null;
211+
};
199212
$zones = [];
200213
foreach (array_keys($available) as $zone) {
201214
// lg: long generic, e.g. "Central European Time"
202215
// ls: long specific (not DST), e.g. "Central European Standard Time"
203216
// ld: long DST, e.g. "Central European Summer Time"
204217
// ec: example city, e.g. "Amsterdam"
205-
$name = $accessor(['zoneStrings', $zone, 'lg'], $nameInherited) ?? $accessor(['zoneStrings', $zone, 'ls'], $nameInherited);
206-
$city = $accessor(['zoneStrings', $zone, 'ec'], $cityInherited);
218+
$name = $accessor(['zoneStrings', $zone, 'lg'], ['zoneStrings', $zone, 'ls']);
219+
$city = $accessor(['zoneStrings', $zone, 'ec']);
207220
$id = str_replace(':', '/', $zone);
208221

209222
if (null === $name && isset($metazones[$zone])) {
210223
$meta = 'meta:'.$metazones[$zone];
211-
$name = $accessor(['zoneStrings', $meta, 'lg'], $nameInherited) ?? $accessor(['zoneStrings', $meta, 'ls'], $nameInherited);
224+
$name = $accessor(['zoneStrings', $meta, 'lg'], ['zoneStrings', $meta, 'ls']);
212225
}
226+
227+
// Infer a default English named city for all locales
228+
// Ensures each timezone ID has a distinctive name
213229
if (null === $city && 0 !== strrpos($zone, 'Etc:') && false !== $i = strrpos($zone, ':')) {
214230
$city = str_replace('_', ' ', substr($zone, $i + 1));
215-
$cityInherited = !$isBase;
216231
}
217-
if ($isBase && null === $name) {
232+
if (null === $name) {
218233
$name = $resolveName($id, $city);
219234
$city = null;
220235
}
221-
if (
222-
($nameInherited && $cityInherited)
223-
|| (null === $name && null === $city)
224-
|| ($nameInherited && null === $city)
225-
|| ($cityInherited && null === $name)
226-
) {
236+
if (null === $name) {
227237
continue;
228238
}
229-
if (null === $name) {
230-
$name = $resolveName($id, $city);
231-
} elseif (null !== $city && false === mb_stripos(str_replace('-', ' ', $name), str_replace('-', ' ', $city))) {
239+
240+
// Ensure no duplicated content is generated
241+
if (null !== $city && false === mb_stripos(str_replace('-', ' ', $name), str_replace('-', ' ', $city))) {
232242
$name = str_replace(['{0}', '{1}'], [$city, $name], $fallbackFormat);
233243
}
234244

235245
$zones[$id] = $name;
236246
}
237247

238-
$gmtFormat = $accessor(['zoneStrings', 'gmtFormat'], $gmtFormatInherited) ?? 'GMT{0}';
239-
if (!$gmtFormatInherited || $isBase) {
240-
$metadata['GmtFormat'] = str_replace('{0}', '%s', $gmtFormat);
241-
}
248+
return $zones;
249+
}
242250

243-
$hourFormat = $accessor(['zoneStrings', 'hourFormat'], $hourFormatInherited) ?? '+HH:mm;-HH:mm';
244-
if (!$hourFormatInherited || $isBase) {
245-
$metadata['HourFormat'] = explode(';', str_replace(['HH', 'mm', 'H', 'm'], ['%02d', '%02d', '%d', '%d'], $hourFormat), 2);
251+
private static function generateZoneMetadata(ArrayAccessibleResourceBundle $localeBundle): array
252+
{
253+
$metadata = [];
254+
if (isset($localeBundle['zoneStrings']['gmtFormat'])) {
255+
$metadata['GmtFormat'] = str_replace('{0}', '%s', $localeBundle['zoneStrings']['gmtFormat']);
256+
}
257+
if (isset($localeBundle['zoneStrings']['hourFormat'])) {
258+
$hourFormat = explode(';', str_replace(['HH', 'mm', 'H', 'm'], ['%02d', '%02d', '%d', '%d'], $localeBundle['zoneStrings']['hourFormat']), 2);
259+
$metadata['HourFormatPos'] = $hourFormat[0];
260+
$metadata['HourFormatNeg'] = $hourFormat[1];
246261
}
247262

248-
return $zones;
263+
return $metadata;
249264
}
250265

251266
private static function generateZoneToCountryMapping(ArrayAccessibleResourceBundle $windowsZoneBundle): array

‎src/Symfony/Component/Intl/Resources/data/timezones/af.json

Copy file name to clipboardExpand all lines: src/Symfony/Component/Intl/Resources/data/timezones/af.json
+9-15Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
"America\/Detroit": "Noord-Amerikaanse oostelike tyd (Detroit)",
100100
"America\/Dominica": "Atlantiese tyd (Dominica)",
101101
"America\/Edmonton": "Noord-Amerikaanse bergtyd (Edmonton)",
102-
"America\/Eirunepe": "Brasilië (Eirunepe)",
102+
"America\/Eirunepe": "Brasilië-tyd (Eirunepe)",
103103
"America\/El_Salvador": "Noord-Amerikaanse sentrale tyd (El Salvador)",
104104
"America\/Fort_Nelson": "Noord-Amerikaanse bergtyd (Fort Nelson)",
105105
"America\/Fortaleza": "Brasilia-tyd (Fortaleza)",
@@ -151,7 +151,7 @@
151151
"America\/Moncton": "Atlantiese tyd (Moncton)",
152152
"America\/Monterrey": "Noord-Amerikaanse sentrale tyd (Monterrey)",
153153
"America\/Montevideo": "Uruguay-tyd (Montevideo)",
154-
"America\/Montreal": "Kanada (Montreal)",
154+
"America\/Montreal": "Kanada-tyd (Montreal)",
155155
"America\/Montserrat": "Atlantiese tyd (Montserrat)",
156156
"America\/Nassau": "Noord-Amerikaanse oostelike tyd (Nassau)",
157157
"America\/New_York": "Noord-Amerikaanse oostelike tyd (New York)",
@@ -176,7 +176,7 @@
176176
"America\/Recife": "Brasilia-tyd (Recife)",
177177
"America\/Regina": "Noord-Amerikaanse sentrale tyd (Regina)",
178178
"America\/Resolute": "Noord-Amerikaanse sentrale tyd (Resolute)",
179-
"America\/Rio_Branco": "Brasilië (Rio Branco)",
179+
"America\/Rio_Branco": "Brasilië-tyd (Rio Branco)",
180180
"America\/Santa_Isabel": "Noordwes-Meksiko-tyd (Santa Isabel)",
181181
"America\/Santarem": "Brasilia-tyd (Santarem)",
182182
"America\/Santiago": "Chili-tyd (Santiago)",
@@ -226,7 +226,7 @@
226226
"Asia\/Bahrain": "Arabiese tyd (Bahrein)",
227227
"Asia\/Baku": "Aserbeidjan-tyd (Bakoe)",
228228
"Asia\/Bangkok": "Indosjina-tyd (Bangkok)",
229-
"Asia\/Barnaul": "Rusland (Barnaul)",
229+
"Asia\/Barnaul": "Rusland-tyd (Barnaul)",
230230
"Asia\/Beirut": "Oos-Europese tyd (Beiroet)",
231231
"Asia\/Bishkek": "Kirgistan-tyd (Bisjkek)",
232232
"Asia\/Brunei": "Broenei Darussalam-tyd",
@@ -288,9 +288,9 @@
288288
"Asia\/Tehran": "Iran-tyd (Tehran)",
289289
"Asia\/Thimphu": "Bhoetan-tyd (Thimphu)",
290290
"Asia\/Tokyo": "Japan-tyd (Tokio)",
291-
"Asia\/Tomsk": "Rusland (Tomsk)",
291+
"Asia\/Tomsk": "Rusland-tyd (Tomsk)",
292292
"Asia\/Ulaanbaatar": "Ulaanbaatar-tyd",
293-
"Asia\/Urumqi": "Sjina (Urumqi)",
293+
"Asia\/Urumqi": "Sjina-tyd (Urumqi)",
294294
"Asia\/Ust-Nera": "Wladiwostok-tyd (Ust-Nera)",
295295
"Asia\/Vientiane": "Indosjina-tyd (Vientiane)",
296296
"Asia\/Vladivostok": "Wladiwostok-tyd",
@@ -341,11 +341,11 @@
341341
"Europe\/Guernsey": "Greenwich-tyd (Guernsey)",
342342
"Europe\/Helsinki": "Oos-Europese tyd (Helsinki)",
343343
"Europe\/Isle_of_Man": "Greenwich-tyd (Eiland Man)",
344-
"Europe\/Istanbul": "Turkye (Istanbul)",
344+
"Europe\/Istanbul": "Turkye-tyd (Istanbul)",
345345
"Europe\/Jersey": "Greenwich-tyd (Jersey)",
346346
"Europe\/Kaliningrad": "Oos-Europese tyd (Kaliningrad)",
347347
"Europe\/Kiev": "Oos-Europese tyd (Kiëf)",
348-
"Europe\/Kirov": "Rusland (Kirov)",
348+
"Europe\/Kirov": "Rusland-tyd (Kirov)",
349349
"Europe\/Lisbon": "Wes-Europese tyd (Lissabon)",
350350
"Europe\/Ljubljana": "Sentraal-Europese tyd (Ljubljana)",
351351
"Europe\/London": "Greenwich-tyd (Londen)",
@@ -436,11 +436,5 @@
436436
"Pacific\/Wake": "Wake-eiland-tyd",
437437
"Pacific\/Wallis": "Wallis en Futuna-tyd (Mata-Utu)"
438438
},
439-
"Meta": {
440-
"GmtFormat": "GMT%s",
441-
"HourFormat": [
442-
"+%02d:%02d",
443-
"-%02d:%02d"
444-
]
445-
}
439+
"Meta": []
446440
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.