Skip to content

Commit 6e78b44

Browse files
llupanicolas-grekas
authored andcommitted
[Intl] Optionally allow Kosovo as a component region
1 parent 01f0faf commit 6e78b44

File tree

216 files changed

+1897
-17
lines changed

Some content is hidden

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

216 files changed

+1897
-17
lines changed

.github/workflows/intl-data-tests.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@ jobs:
8484
run: uconv -V && php -i | grep 'ICU version'
8585

8686
- name: Run intl-data tests
87-
run: ./phpunit --group intl-data -v
87+
run: |
88+
./phpunit --group intl-data --exclude-group intl-data-isolate -v
89+
./phpunit --group intl-data --filter testWhenEnvVarNotSet -v
90+
./phpunit --group intl-data --filter testWhenEnvVarSetFalse -v
91+
./phpunit --group intl-data --filter testWhenEnvVarSetTrue -v
8892
8993
- name: Test intl-data with compressed data
9094
run: |

src/Symfony/Component/Intl/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.4
5+
---
6+
7+
* Allow Kosovo as a component region, controlled by the `SYMFONY_INTL_WITH_USER_ASSIGNED` env var
8+
49
7.1
510
---
611

src/Symfony/Component/Intl/Countries.php

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
*/
2222
final class Countries extends ResourceBundle
2323
{
24+
private static bool $withUserAssigned;
25+
2426
/**
2527
* Returns all available countries.
2628
*
@@ -35,7 +37,11 @@ final class Countries extends ResourceBundle
3537
*/
3638
public static function getCountryCodes(): array
3739
{
38-
return self::readEntry(['Regions'], 'meta');
40+
if (!self::withUserAssigned()) {
41+
return self::readEntry(['Regions'], 'meta');
42+
}
43+
44+
return array_merge(self::readEntry(['Regions'], 'meta'), self::readEntry(['UserAssignedRegions'], 'meta'));
3945
}
4046

4147
/**
@@ -49,7 +55,11 @@ public static function getCountryCodes(): array
4955
*/
5056
public static function getAlpha3Codes(): array
5157
{
52-
return self::readEntry(['Alpha2ToAlpha3'], 'meta');
58+
if (!self::withUserAssigned()) {
59+
return self::readEntry(['Alpha2ToAlpha3'], 'meta');
60+
}
61+
62+
return array_merge(self::readEntry(['Alpha2ToAlpha3'], 'meta'), self::readEntry(['UserAssignedAlpha2ToAlpha3'], 'meta'));
5363
}
5464

5565
/**
@@ -65,34 +75,66 @@ public static function getAlpha3Codes(): array
6575
*/
6676
public static function getNumericCodes(): array
6777
{
68-
return self::readEntry(['Alpha2ToNumeric'], 'meta');
78+
if (!self::withUserAssigned()) {
79+
return self::readEntry(['Alpha2ToNumeric'], 'meta');
80+
}
81+
82+
return array_merge(self::readEntry(['Alpha2ToNumeric'], 'meta'), self::readEntry(['UserAssignedAlpha2ToNumeric'], 'meta'));
6983
}
7084

7185
public static function getAlpha3Code(string $alpha2Code): string
7286
{
87+
if (self::withUserAssigned()) {
88+
try {
89+
return self::readEntry(['UserAssignedAlpha2ToAlpha3', $alpha2Code], 'meta');
90+
} catch (MissingResourceException) {
91+
}
92+
}
93+
7394
return self::readEntry(['Alpha2ToAlpha3', $alpha2Code], 'meta');
7495
}
7596

7697
public static function getAlpha2Code(string $alpha3Code): string
7798
{
99+
if (self::withUserAssigned()) {
100+
try {
101+
return self::readEntry(['UserAssignedAlpha3ToAlpha2', $alpha3Code], 'meta');
102+
} catch (MissingResourceException) {
103+
}
104+
}
105+
78106
return self::readEntry(['Alpha3ToAlpha2', $alpha3Code], 'meta');
79107
}
80108

81109
public static function getNumericCode(string $alpha2Code): string
82110
{
111+
if (self::withUserAssigned()) {
112+
try {
113+
return self::readEntry(['UserAssignedAlpha2ToNumeric', $alpha2Code], 'meta');
114+
} catch (MissingResourceException) {
115+
}
116+
}
117+
83118
return self::readEntry(['Alpha2ToNumeric', $alpha2Code], 'meta');
84119
}
85120

86121
public static function getAlpha2FromNumeric(string $numericCode): string
87122
{
123+
if (self::withUserAssigned()) {
124+
try {
125+
return self::readEntry(['UserAssignedNumericToAlpha2', '_'.$numericCode], 'meta');
126+
} catch (MissingResourceException) {
127+
}
128+
}
129+
88130
// Use an underscore prefix to force numeric strings with leading zeros to remain as strings
89131
return self::readEntry(['NumericToAlpha2', '_'.$numericCode], 'meta');
90132
}
91133

92134
public static function exists(string $alpha2Code): bool
93135
{
94136
try {
95-
self::readEntry(['Names', $alpha2Code]);
137+
self::getAlpha3Code($alpha2Code);
96138

97139
return true;
98140
} catch (MissingResourceException) {
@@ -129,6 +171,13 @@ public static function numericCodeExists(string $numericCode): bool
129171
*/
130172
public static function getName(string $country, ?string $displayLocale = null): string
131173
{
174+
if (self::withUserAssigned()) {
175+
try {
176+
return self::readEntry(['UserAssignedNames', $country], $displayLocale);
177+
} catch (MissingResourceException) {
178+
}
179+
}
180+
132181
return self::readEntry(['Names', $country], $displayLocale);
133182
}
134183

@@ -149,7 +198,11 @@ public static function getAlpha3Name(string $alpha3Code, ?string $displayLocale
149198
*/
150199
public static function getNames(?string $displayLocale = null): array
151200
{
152-
return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale);
201+
if (!self::withUserAssigned()) {
202+
return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale);
203+
}
204+
205+
return self::asort(array_merge(self::readEntry(['Names'], $displayLocale), self::readEntry(['UserAssignedNames'], $displayLocale)), $displayLocale);
153206
}
154207

155208
/**
@@ -170,6 +223,23 @@ public static function getAlpha3Names(?string $displayLocale = null): array
170223
return $alpha3Names;
171224
}
172225

226+
/**
227+
* Sets the internal `withUserAssigned` flag, overriding the default `SYMFONY_INTL_WITH_USER_ASSIGNED` env var.
228+
*
229+
* The ISO 3166/MA has received information that the CE Commission has allocated the alpha-2 user-assigned code "XK"
230+
* to represent Kosovo in the interim of being recognized by the UN as a member state.
231+
*
232+
* Set `$withUserAssigned` to true to have `XK`, `XKK` and `983` available in the other functions of this class.
233+
*/
234+
public static function withUserAssigned(?bool $withUserAssigned = null): bool
235+
{
236+
if (null === $withUserAssigned) {
237+
return self::$withUserAssigned ??= filter_var($_ENV['SYMFONY_INTL_WITH_USER_ASSIGNED'] ?? $_SERVER['SYMFONY_INTL_WITH_USER_ASSIGNED'] ?? getenv('SYMFONY_INTL_WITH_USER_ASSIGNED'), FILTER_VALIDATE_BOOLEAN);
238+
}
239+
240+
return self::$withUserAssigned = $withUserAssigned;
241+
}
242+
173243
protected static function getPath(): string
174244
{
175245
return Intl::getDataDirectory().'/'.Intl::REGION_DIR;

src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,14 @@ class RegionDataGenerator extends AbstractDataGenerator
5656
'QO' => true, // Outlying Oceania
5757
'XA' => true, // Pseudo-Accents
5858
'XB' => true, // Pseudo-Bidi
59-
'XK' => true, // Kosovo
6059
// Misc
6160
'ZZ' => true, // Unknown Region
6261
];
6362

63+
private const USER_ASSIGNED = [
64+
'XK' => true, // Kosovo
65+
];
66+
6467
// @see https://en.wikipedia.org/wiki/ISO_3166-1_numeric#Withdrawn_codes
6568
private const WITHDRAWN_CODES = [
6669
128, // Canton and Enderbury Islands
@@ -97,7 +100,7 @@ class RegionDataGenerator extends AbstractDataGenerator
97100

98101
public static function isValidCountryCode(int|string|null $region): bool
99102
{
100-
if (isset(self::DENYLIST[$region])) {
103+
if (isset(self::DENYLIST[$region]) || isset(self::USER_ASSIGNED[$region])) {
101104
return false;
102105
}
103106

@@ -109,6 +112,11 @@ public static function isValidCountryCode(int|string|null $region): bool
109112
return true;
110113
}
111114

115+
public static function isUserAssignedCountryCode(int|string|null $region): bool
116+
{
117+
return isset(self::USER_ASSIGNED[$region]);
118+
}
119+
112120
protected function scanLocales(LocaleScanner $scanner, string $sourceDir): array
113121
{
114122
return $scanner->scanLocales($sourceDir.'/region');
@@ -131,9 +139,7 @@ protected function generateDataForLocale(BundleEntryReaderInterface $reader, str
131139

132140
// isset() on \ResourceBundle returns true even if the value is null
133141
if (isset($localeBundle['Countries']) && null !== $localeBundle['Countries']) {
134-
$data = [
135-
'Names' => $this->generateRegionNames($localeBundle),
136-
];
142+
$data = $this->generateRegionNames($localeBundle);
137143

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

@@ -153,23 +159,39 @@ protected function generateDataForMeta(BundleEntryReaderInterface $reader, strin
153159
$metadataBundle = $reader->read($tempDir, 'metadata');
154160

155161
$this->regionCodes = array_unique($this->regionCodes);
156-
157162
sort($this->regionCodes);
158163

159164
$alpha2ToAlpha3 = $this->generateAlpha2ToAlpha3Mapping(array_flip($this->regionCodes), $metadataBundle);
165+
$userAssignedAlpha2ToAlpha3 = $this->generateAlpha2ToAlpha3Mapping(self::USER_ASSIGNED, $metadataBundle);
166+
160167
$alpha3ToAlpha2 = array_flip($alpha2ToAlpha3);
161168
asort($alpha3ToAlpha2);
169+
$userAssignedAlpha3toAlpha2 = array_flip($userAssignedAlpha2ToAlpha3);
170+
asort($userAssignedAlpha3toAlpha2);
162171

163172
$alpha2ToNumeric = $this->generateAlpha2ToNumericMapping(array_flip($this->regionCodes), $metadataBundle);
173+
$userAssignedAlpha2ToNumeric = $this->generateAlpha2ToNumericMapping(self::USER_ASSIGNED, $metadataBundle);
174+
164175
$numericToAlpha2 = [];
165176
foreach ($alpha2ToNumeric as $alpha2 => $numeric) {
166177
// Add underscore prefix to force keys with leading zeros to remain as string keys.
167178
$numericToAlpha2['_'.$numeric] = $alpha2;
168179
}
180+
$userAssignedNumericToAlpha2 = [];
181+
foreach ($userAssignedAlpha2ToNumeric as $alpha2 => $numeric) {
182+
// Add underscore prefix to force keys with leading zeros to remain as string keys.
183+
$userAssignedNumericToAlpha2['_'.$numeric] = $alpha2;
184+
}
169185

170186
asort($numericToAlpha2);
187+
asort($userAssignedNumericToAlpha2);
171188

172189
return [
190+
'UserAssignedRegions' => array_keys(self::USER_ASSIGNED),
191+
'UserAssignedAlpha2ToAlpha3' => $userAssignedAlpha2ToAlpha3,
192+
'UserAssignedAlpha3ToAlpha2' => $userAssignedAlpha3toAlpha2,
193+
'UserAssignedAlpha2ToNumeric' => $userAssignedAlpha2ToNumeric,
194+
'UserAssignedNumericToAlpha2' => $userAssignedNumericToAlpha2,
173195
'Regions' => $this->regionCodes,
174196
'Alpha2ToAlpha3' => $alpha2ToAlpha3,
175197
'Alpha3ToAlpha2' => $alpha3ToAlpha2,
@@ -181,14 +203,19 @@ protected function generateDataForMeta(BundleEntryReaderInterface $reader, strin
181203
protected function generateRegionNames(ArrayAccessibleResourceBundle $localeBundle): array
182204
{
183205
$unfilteredRegionNames = iterator_to_array($localeBundle['Countries']);
184-
$regionNames = [];
206+
$regionNames = ['UserAssignedNames' => [], 'Names' => []];
185207

186208
foreach ($unfilteredRegionNames as $region => $regionName) {
187-
if (!self::isValidCountryCode($region)) {
209+
if (!self::isValidCountryCode($region) && !self::isUserAssignedCountryCode($region)) {
188210
continue;
189211
}
190212

191-
$regionNames[$region] = $regionName;
213+
if (self::isUserAssignedCountryCode($region)) {
214+
$regionNames['UserAssignedNames'][$region] = $regionName;
215+
continue;
216+
}
217+
218+
$regionNames['Names'][$region] = $regionName;
192219
}
193220

194221
return $regionNames;
@@ -204,7 +231,9 @@ private function generateAlpha2ToAlpha3Mapping(array $countries, ArrayAccessible
204231
$country = $data['replacement'];
205232

206233
if (2 === \strlen($country) && 3 === \strlen($alias) && 'overlong' === $data['reason']) {
207-
if (isset(self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$country])) {
234+
if (isset($countries[$country]) && self::isUserAssignedCountryCode($country)) {
235+
$alpha2ToAlpha3[$country] = $alias;
236+
} elseif (isset($countries[$country]) && !self::isUserAssignedCountryCode($country) && isset(self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$country])) {
208237
// Validate to prevent typos
209238
if (!isset($aliases[self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$country]])) {
210239
throw new RuntimeException('The statically set three-letter mapping '.self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$country].' for the country code '.$country.' seems to be invalid. Typo?');

src/Symfony/Component/Intl/Resources/data/regions/af.php

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Intl/Resources/data/regions/ak.php

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Intl/Resources/data/regions/am.php

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Intl/Resources/data/regions/ar.php

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Intl/Resources/data/regions/ar_LY.php

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/Intl/Resources/data/regions/ar_SA.php

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy