@@ -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? ' );
0 commit comments