2121 */
2222final 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 ;
0 commit comments