Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
91.89% |
34 / 37 |
|
50.00% |
2 / 4 |
CRAP | |
0.00% |
0 / 1 |
| ArticleCountryFiltersRegistry | |
91.89% |
34 / 37 |
|
50.00% |
2 / 4 |
11.06 | |
0.00% |
0 / 1 |
| getCountries | |
86.67% |
13 / 15 |
|
0.00% |
0 / 1 |
4.04 | |||
| getSupportedCountryCodes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getGroupedCountryCodes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getLocalizedRegionsAndCountries | |
95.00% |
19 / 20 |
|
0.00% |
0 / 1 |
5 | |||
| 1 | <?php |
| 2 | |
| 3 | declare( strict_types = 1 ); |
| 4 | |
| 5 | namespace MediaWiki\Extension\WikimediaMessages; |
| 6 | |
| 7 | use Collator; |
| 8 | use MediaWiki\Extension\CLDR\CountryNames; |
| 9 | use MediaWiki\MediaWikiServices; |
| 10 | use MediaWiki\Message\Message; |
| 11 | use UnexpectedValueException; |
| 12 | |
| 13 | class ArticleCountryFiltersRegistry { |
| 14 | |
| 15 | // From https://gitlab.wikimedia.org/repos/movement-insights/canonical-data/-/raw/main/country/countries.tsv |
| 16 | // Extracted on 2025-04-17 |
| 17 | private const SUPPORTED_COUNTRY_CODES = [ |
| 18 | 'AF', 'AX', 'AL', 'DZ', 'AS', 'AD', 'AO', 'AI', 'AQ', 'AG', |
| 19 | 'AR', 'AM', 'AW', 'AU', 'AT', 'AZ', 'BS', 'BH', 'BD', 'BB', |
| 20 | 'BY', 'BE', 'BZ', 'BJ', 'BM', 'BT', 'BO', 'BQ', 'BA', 'BW', |
| 21 | 'BV', 'BR', 'IO', 'VG', 'BN', 'BG', 'BF', 'BI', 'KH', 'CM', |
| 22 | 'CA', 'CV', 'KY', 'CF', 'TD', 'CL', 'CN', 'CX', 'CC', 'CO', |
| 23 | 'KM', 'CK', 'CR', 'HR', 'CU', 'CW', 'CY', 'CZ', 'CD', 'DK', |
| 24 | 'DJ', 'DM', 'DO', 'TL', 'EC', 'EG', 'SV', 'GQ', 'ER', 'EE', |
| 25 | 'SZ', 'ET', 'FK', 'FO', 'FM', 'FJ', 'FI', 'FR', 'GF', 'PF', |
| 26 | 'TF', 'GA', 'GM', 'GE', 'DE', 'GH', 'GI', 'GR', 'GL', 'GD', |
| 27 | 'GP', 'GU', 'GT', 'GG', 'GN', 'GW', 'GY', 'HT', 'HM', 'HN', |
| 28 | 'HK', 'HU', 'IS', 'IN', 'ID', 'IR', 'IQ', 'IE', 'IM', 'IL', |
| 29 | 'IT', 'CI', 'JM', 'JP', 'JE', 'JO', 'KZ', 'KE', 'KI', 'XK', |
| 30 | 'KW', 'KG', 'LA', 'LV', 'LB', 'LS', 'LR', 'LY', 'LI', 'LT', |
| 31 | 'LU', 'MO', 'MG', 'MW', 'MY', 'MV', 'ML', 'MT', 'MH', 'MQ', |
| 32 | 'MR', 'MU', 'YT', 'MX', 'MD', 'MC', 'MN', 'ME', 'MS', 'MA', |
| 33 | 'MZ', 'MM', 'NA', 'NR', 'NP', 'NL', 'NC', 'NZ', 'NI', 'NE', |
| 34 | 'NG', 'NU', 'NF', 'KP', 'MK', 'MP', 'NO', 'OM', 'PK', 'PW', |
| 35 | 'PS', 'PA', 'PG', 'PY', 'PE', 'PH', 'PN', 'PL', 'PT', 'PR', |
| 36 | 'QA', 'CG', 'RE', 'RO', 'RU', 'RW', 'BL', 'SH', 'KN', 'LC', |
| 37 | 'MF', 'PM', 'VC', 'WS', 'SM', 'ST', 'SA', 'SN', 'RS', 'SC', |
| 38 | 'SL', 'SG', 'SX', 'SK', 'SI', 'SB', 'SO', 'ZA', 'GS', 'KR', |
| 39 | 'SS', 'ES', 'LK', 'SD', 'SR', 'SJ', 'SE', 'CH', 'SY', 'TW', |
| 40 | 'TJ', 'TZ', 'TH', 'TG', 'TK', 'TO', 'TT', 'TN', 'TR', 'TM', |
| 41 | 'TC', 'TV', 'UG', 'UA', 'AE', 'GB', 'US', 'UM', 'VI', 'UY', |
| 42 | 'UZ', 'VU', 'VA', 'VE', 'VN', 'WF', 'EH', 'YE', 'ZM', 'ZW', |
| 43 | ]; |
| 44 | |
| 45 | // SUPPORTED_COUNTRY_CODES grouped by region manually. |
| 46 | // Region labels are reused from the article topic filters. |
| 47 | // In each group, 'countries' is a map of iso-a2 to iso-a3. |
| 48 | // iso-a2 is used for localization via CLDR. |
| 49 | // iso-a3 can be used with the articlecountry search keyword. |
| 50 | private const GROUPED_COUNTRY_CODES = [ |
| 51 | 'asia' => [ |
| 52 | 'msgKey' => 'wikimedia-articletopics-topic-asia', |
| 53 | 'countries' => [ |
| 54 | // Afghanistan |
| 55 | 'AF' => 'AFG', |
| 56 | // Armenia |
| 57 | 'AM' => 'ARM', |
| 58 | // Azerbaijan |
| 59 | 'AZ' => 'AZE', |
| 60 | // Bahrain |
| 61 | 'BH' => 'BHR', |
| 62 | // Bangladesh |
| 63 | 'BD' => 'BGD', |
| 64 | // Bhutan |
| 65 | 'BT' => 'BTN', |
| 66 | // Brunei |
| 67 | 'BN' => 'BRN', |
| 68 | // Cambodia |
| 69 | 'KH' => 'KHM', |
| 70 | // China |
| 71 | 'CN' => 'CHN', |
| 72 | // Christmas Island |
| 73 | 'CX' => 'CXR', |
| 74 | // Cocos (Keeling) Islands |
| 75 | 'CC' => 'CCK', |
| 76 | // Georgia |
| 77 | 'GE' => 'GEO', |
| 78 | // India |
| 79 | 'IN' => 'IND', |
| 80 | // Indonesia |
| 81 | 'ID' => 'IDN', |
| 82 | // Iran |
| 83 | 'IR' => 'IRN', |
| 84 | // Iraq |
| 85 | 'IQ' => 'IRQ', |
| 86 | // Israel |
| 87 | 'IL' => 'ISR', |
| 88 | // Japan |
| 89 | 'JP' => 'JPN', |
| 90 | // Kazakhstan |
| 91 | 'KZ' => 'KAZ', |
| 92 | // Kyrgyzstan |
| 93 | 'KG' => 'KGZ', |
| 94 | // North Korea |
| 95 | 'KP' => 'PRK', |
| 96 | // South Korea |
| 97 | 'KR' => 'KOR', |
| 98 | // Kuwait |
| 99 | 'KW' => 'KWT', |
| 100 | // Laos |
| 101 | 'LA' => 'LAO', |
| 102 | // Lebanon |
| 103 | 'LB' => 'LBN', |
| 104 | // Macau |
| 105 | 'MO' => 'MAC', |
| 106 | // Jordan |
| 107 | 'JO' => 'JOR', |
| 108 | // Mongolia |
| 109 | 'MN' => 'MNG', |
| 110 | // Myanmar |
| 111 | 'MM' => 'MMR', |
| 112 | // Maldives |
| 113 | 'MV' => 'MDV', |
| 114 | // Malaysia |
| 115 | 'MY' => 'MYS', |
| 116 | // Nepal |
| 117 | 'NP' => 'NPL', |
| 118 | // Oman |
| 119 | 'OM' => 'OMN', |
| 120 | // Pakistan |
| 121 | 'PK' => 'PAK', |
| 122 | // Philippines |
| 123 | 'PH' => 'PHL', |
| 124 | // Qatar |
| 125 | 'QA' => 'QAT', |
| 126 | // Saudi Arabia |
| 127 | 'SA' => 'SAU', |
| 128 | // Svalbard and Jan Mayen |
| 129 | 'SJ' => 'SJM', |
| 130 | // Singapore |
| 131 | 'SG' => 'SGP', |
| 132 | // Sri Lanka |
| 133 | 'LK' => 'LKA', |
| 134 | // Syria |
| 135 | 'SY' => 'SYR', |
| 136 | // Tajikistan |
| 137 | 'TJ' => 'TJK', |
| 138 | // Thailand |
| 139 | 'TH' => 'THA', |
| 140 | // Timor-Leste |
| 141 | 'TL' => 'TLS', |
| 142 | // Turkmenistan |
| 143 | 'TM' => 'TKM', |
| 144 | // Turkey |
| 145 | 'TR' => 'TUR', |
| 146 | // Uzbekistan |
| 147 | 'UZ' => 'UZB', |
| 148 | // Vietnam |
| 149 | 'VN' => 'VNM', |
| 150 | // Yemen |
| 151 | 'YE' => 'YEM', |
| 152 | // Taiwan |
| 153 | 'TW' => 'TWN', |
| 154 | // United Arab Emirates |
| 155 | 'AE' => 'ARE', |
| 156 | // Hong Kong |
| 157 | 'HK' => 'HKG', |
| 158 | // Palestine |
| 159 | 'PS' => 'PSE', |
| 160 | // British Indian Ocean Territory |
| 161 | 'IO' => 'IOT', |
| 162 | ], |
| 163 | ], |
| 164 | 'africa' => [ |
| 165 | 'msgKey' => 'wikimedia-articletopics-topic-africa', |
| 166 | 'countries' => [ |
| 167 | // Algeria |
| 168 | 'DZ' => 'DZA', |
| 169 | // Angola |
| 170 | 'AO' => 'AGO', |
| 171 | // Benin |
| 172 | 'BJ' => 'BEN', |
| 173 | // Botswana |
| 174 | 'BW' => 'BWA', |
| 175 | // Burkina Faso |
| 176 | 'BF' => 'BFA', |
| 177 | // Burundi |
| 178 | 'BI' => 'BDI', |
| 179 | // Cameroon |
| 180 | 'CM' => 'CMR', |
| 181 | // Cape Verde |
| 182 | 'CV' => 'CPV', |
| 183 | // Central African Republic |
| 184 | 'CF' => 'CAF', |
| 185 | // Chad |
| 186 | 'TD' => 'TCD', |
| 187 | // Comoros |
| 188 | 'KM' => 'COM', |
| 189 | // Democratic Republic of the Congo |
| 190 | 'CD' => 'COD', |
| 191 | // Republic of the Congo |
| 192 | 'CG' => 'COG', |
| 193 | // Côte d'Ivoire |
| 194 | 'CI' => 'CIV', |
| 195 | // Djibouti |
| 196 | 'DJ' => 'DJI', |
| 197 | // Egypt |
| 198 | 'EG' => 'EGY', |
| 199 | // Equatorial Guinea |
| 200 | 'GQ' => 'GNQ', |
| 201 | // Eritrea |
| 202 | 'ER' => 'ERI', |
| 203 | // Eswatini |
| 204 | 'SZ' => 'SWZ', |
| 205 | // Ethiopia |
| 206 | 'ET' => 'ETH', |
| 207 | // Gabon |
| 208 | 'GA' => 'GAB', |
| 209 | // Gambia |
| 210 | 'GM' => 'GMB', |
| 211 | // Ghana |
| 212 | 'GH' => 'GHA', |
| 213 | // Guinea |
| 214 | 'GN' => 'GIN', |
| 215 | // Guinea-Bissau |
| 216 | 'GW' => 'GNB', |
| 217 | // Kenya |
| 218 | 'KE' => 'KEN', |
| 219 | // Lesotho |
| 220 | 'LS' => 'LSO', |
| 221 | // Liberia |
| 222 | 'LR' => 'LBR', |
| 223 | // Libya |
| 224 | 'LY' => 'LBY', |
| 225 | // Madagascar |
| 226 | 'MG' => 'MDG', |
| 227 | // Malawi |
| 228 | 'MW' => 'MWI', |
| 229 | // Mali |
| 230 | 'ML' => 'MLI', |
| 231 | // Mauritania |
| 232 | 'MR' => 'MRT', |
| 233 | // Mauritius |
| 234 | 'MU' => 'MUS', |
| 235 | // Mayotte |
| 236 | 'YT' => 'MYT', |
| 237 | // Morocco |
| 238 | 'MA' => 'MAR', |
| 239 | // Mozambique |
| 240 | 'MZ' => 'MOZ', |
| 241 | // Namibia |
| 242 | 'NA' => 'NAM', |
| 243 | // Niger |
| 244 | 'NE' => 'NER', |
| 245 | // Nigeria |
| 246 | 'NG' => 'NGA', |
| 247 | // Rwanda |
| 248 | 'RW' => 'RWA', |
| 249 | // Réunion |
| 250 | 'RE' => 'REU', |
| 251 | // Sao Tome and Principe |
| 252 | 'ST' => 'STP', |
| 253 | // Senegal |
| 254 | 'SN' => 'SEN', |
| 255 | // Seychelles |
| 256 | 'SC' => 'SYC', |
| 257 | // Sierra Leone |
| 258 | 'SL' => 'SLE', |
| 259 | // Somalia |
| 260 | 'SO' => 'SOM', |
| 261 | // South Africa |
| 262 | 'ZA' => 'ZAF', |
| 263 | // South Sudan |
| 264 | 'SS' => 'SSD', |
| 265 | // Sudan |
| 266 | 'SD' => 'SDN', |
| 267 | // Tanzania |
| 268 | 'TZ' => 'TZA', |
| 269 | // Togo |
| 270 | 'TG' => 'TGO', |
| 271 | // Tunisia |
| 272 | 'TN' => 'TUN', |
| 273 | // Uganda |
| 274 | 'UG' => 'UGA', |
| 275 | // Western Sahara |
| 276 | 'EH' => 'ESH', |
| 277 | // Zambia |
| 278 | 'ZM' => 'ZMB', |
| 279 | // Zimbabwe |
| 280 | 'ZW' => 'ZWE', |
| 281 | ], |
| 282 | ], |
| 283 | 'north-america' => [ |
| 284 | 'msgKey' => 'wikimedia-articletopics-topic-north-america', |
| 285 | 'countries' => [ |
| 286 | // Canada |
| 287 | 'CA' => 'CAN', |
| 288 | // United States |
| 289 | 'US' => 'USA', |
| 290 | // Mexico |
| 291 | 'MX' => 'MEX', |
| 292 | // Cuba |
| 293 | 'CU' => 'CUB', |
| 294 | // Haiti |
| 295 | 'HT' => 'HTI', |
| 296 | // Jamaica |
| 297 | 'JM' => 'JAM', |
| 298 | // Bahamas |
| 299 | 'BS' => 'BHS', |
| 300 | // Barbados |
| 301 | 'BB' => 'BRB', |
| 302 | // Antigua and Barbuda |
| 303 | 'AG' => 'ATG', |
| 304 | // Dominica |
| 305 | 'DM' => 'DMA', |
| 306 | // Dominican Republic |
| 307 | 'DO' => 'DOM', |
| 308 | // Greenland |
| 309 | 'GL' => 'GRL', |
| 310 | // Puerto Rico |
| 311 | 'PR' => 'PRI', |
| 312 | // Anguilla |
| 313 | 'AI' => 'AIA', |
| 314 | // Aruba |
| 315 | 'AW' => 'ABW', |
| 316 | // Bermuda |
| 317 | 'BM' => 'BMU', |
| 318 | // Bonaire, Sint Eustatius and Saba |
| 319 | 'BQ' => 'BES', |
| 320 | // British Virgin Islands |
| 321 | 'VG' => 'VGB', |
| 322 | // Cayman Islands |
| 323 | 'KY' => 'CYM', |
| 324 | // Curaçao |
| 325 | 'CW' => 'CUW', |
| 326 | // Grenada |
| 327 | 'GD' => 'GRD', |
| 328 | // Guadeloupe |
| 329 | 'GP' => 'GLP', |
| 330 | // Martinique |
| 331 | 'MQ' => 'MTQ', |
| 332 | // Montserrat |
| 333 | 'MS' => 'MSR', |
| 334 | // Saint Barthélemy |
| 335 | 'BL' => 'BLM', |
| 336 | // Saint Helena, Ascension and Tristan da Cunha |
| 337 | 'SH' => 'SHN', |
| 338 | // Saint Kitts and Nevis |
| 339 | 'KN' => 'KNA', |
| 340 | // Saint Lucia |
| 341 | 'LC' => 'LCA', |
| 342 | // Saint Martin |
| 343 | 'MF' => 'MAF', |
| 344 | // Saint Pierre and Miquelon |
| 345 | 'PM' => 'SPM', |
| 346 | // Saint Vincent and the Grenadines |
| 347 | 'VC' => 'VCT', |
| 348 | // Sint Maarten |
| 349 | 'SX' => 'SXM', |
| 350 | // Turks and Caicos Islands |
| 351 | 'TC' => 'TCA', |
| 352 | // Virgin Islands (U.S.) |
| 353 | 'VI' => 'VIR', |
| 354 | ], |
| 355 | ], |
| 356 | 'south-america' => [ |
| 357 | 'msgKey' => 'wikimedia-articletopics-topic-south-america', |
| 358 | 'countries' => [ |
| 359 | // Argentina |
| 360 | 'AR' => 'ARG', |
| 361 | // Bolivia |
| 362 | 'BO' => 'BOL', |
| 363 | // Brazil |
| 364 | 'BR' => 'BRA', |
| 365 | // Chile |
| 366 | 'CL' => 'CHL', |
| 367 | // Colombia |
| 368 | 'CO' => 'COL', |
| 369 | // Guyana |
| 370 | 'GY' => 'GUY', |
| 371 | // Paraguay |
| 372 | 'PY' => 'PRY', |
| 373 | // Peru |
| 374 | 'PE' => 'PER', |
| 375 | // Suriname |
| 376 | 'SR' => 'SUR', |
| 377 | // Trinidad and Tobago |
| 378 | 'TT' => 'TTO', |
| 379 | // Uruguay |
| 380 | 'UY' => 'URY', |
| 381 | // Venezuela |
| 382 | 'VE' => 'VEN', |
| 383 | // Ecuador |
| 384 | 'EC' => 'ECU', |
| 385 | // Falkland Islands |
| 386 | 'FK' => 'FLK', |
| 387 | // French Guiana |
| 388 | 'GF' => 'GUF', |
| 389 | // South Georgia and the South Sandwich Islands |
| 390 | 'GS' => 'SGS', |
| 391 | ], |
| 392 | ], |
| 393 | 'europe' => [ |
| 394 | 'msgKey' => 'wikimedia-articletopics-topic-europe', |
| 395 | 'countries' => [ |
| 396 | // Ã…land Islands |
| 397 | 'AX' => 'ALA', |
| 398 | // Albania |
| 399 | 'AL' => 'ALB', |
| 400 | // Andorra |
| 401 | 'AD' => 'AND', |
| 402 | // Austria |
| 403 | 'AT' => 'AUT', |
| 404 | // Belarus |
| 405 | 'BY' => 'BLR', |
| 406 | // Belgium |
| 407 | 'BE' => 'BEL', |
| 408 | // Bosnia and Herzegovina |
| 409 | 'BA' => 'BIH', |
| 410 | // Bulgaria |
| 411 | 'BG' => 'BGR', |
| 412 | // Croatia |
| 413 | 'HR' => 'HRV', |
| 414 | // Cyprus |
| 415 | 'CY' => 'CYP', |
| 416 | // Czech Republic |
| 417 | 'CZ' => 'CZE', |
| 418 | // Denmark |
| 419 | 'DK' => 'DNK', |
| 420 | // Estonia |
| 421 | 'EE' => 'EST', |
| 422 | // Faroe Islands |
| 423 | 'FO' => 'FRO', |
| 424 | // Finland |
| 425 | 'FI' => 'FIN', |
| 426 | // France |
| 427 | 'FR' => 'FRA', |
| 428 | // Germany |
| 429 | 'DE' => 'DEU', |
| 430 | // Gibraltar |
| 431 | 'GI' => 'GIB', |
| 432 | // Greece |
| 433 | 'GR' => 'GRC', |
| 434 | // Guernsey |
| 435 | 'GG' => 'GGY', |
| 436 | // Hungary |
| 437 | 'HU' => 'HUN', |
| 438 | // Iceland |
| 439 | 'IS' => 'ISL', |
| 440 | // Ireland |
| 441 | 'IE' => 'IRL', |
| 442 | // Isle of Man |
| 443 | 'IM' => 'IMN', |
| 444 | // Italy |
| 445 | 'IT' => 'ITA', |
| 446 | // Jersey |
| 447 | 'JE' => 'JEY', |
| 448 | // Latvia |
| 449 | 'LV' => 'LVA', |
| 450 | // Lithuania |
| 451 | 'LT' => 'LTU', |
| 452 | // Liechtenstein |
| 453 | 'LI' => 'LIE', |
| 454 | // Luxembourg |
| 455 | 'LU' => 'LUX', |
| 456 | // Malta |
| 457 | 'MT' => 'MLT', |
| 458 | // Moldova |
| 459 | 'MD' => 'MDA', |
| 460 | // Monaco |
| 461 | 'MC' => 'MCO', |
| 462 | // North Macedonia |
| 463 | 'MK' => 'MKD', |
| 464 | // Montenegro |
| 465 | 'ME' => 'MNE', |
| 466 | // Netherlands |
| 467 | 'NL' => 'NLD', |
| 468 | // Norway |
| 469 | 'NO' => 'NOR', |
| 470 | // Poland |
| 471 | 'PL' => 'POL', |
| 472 | // Portugal |
| 473 | 'PT' => 'PRT', |
| 474 | // Romania |
| 475 | 'RO' => 'ROU', |
| 476 | // Russia |
| 477 | 'RU' => 'RUS', |
| 478 | // Serbia |
| 479 | 'RS' => 'SRB', |
| 480 | // Kosovo |
| 481 | 'XK' => 'XKX', |
| 482 | // Slovakia |
| 483 | 'SK' => 'SVK', |
| 484 | // Slovenia |
| 485 | 'SI' => 'SVN', |
| 486 | // Spain |
| 487 | 'ES' => 'ESP', |
| 488 | // Sweden |
| 489 | 'SE' => 'SWE', |
| 490 | // Switzerland |
| 491 | 'CH' => 'CHE', |
| 492 | // Ukraine |
| 493 | 'UA' => 'UKR', |
| 494 | // United Kingdom |
| 495 | 'GB' => 'GBR', |
| 496 | // San Marino |
| 497 | 'SM' => 'SMR', |
| 498 | // Vatican City |
| 499 | 'VA' => 'VAT', |
| 500 | ], |
| 501 | ], |
| 502 | 'oceania' => [ |
| 503 | 'msgKey' => 'wikimedia-articletopics-topic-oceania', |
| 504 | 'countries' => [ |
| 505 | // Australia |
| 506 | 'AU' => 'AUS', |
| 507 | // New Zealand |
| 508 | 'NZ' => 'NZL', |
| 509 | // Fiji |
| 510 | 'FJ' => 'FJI', |
| 511 | // Papua New Guinea |
| 512 | 'PG' => 'PNG', |
| 513 | // Solomon Islands |
| 514 | 'SB' => 'SLB', |
| 515 | // Vanuatu |
| 516 | 'VU' => 'VUT', |
| 517 | // Micronesia |
| 518 | 'FM' => 'FSM', |
| 519 | // Marshall Islands |
| 520 | 'MH' => 'MHL', |
| 521 | // Palau |
| 522 | 'PW' => 'PLW', |
| 523 | // Kiribati |
| 524 | 'KI' => 'KIR', |
| 525 | // Tuvalu |
| 526 | 'TV' => 'TUV', |
| 527 | // Tonga |
| 528 | 'TO' => 'TON', |
| 529 | // Niue |
| 530 | 'NU' => 'NIU', |
| 531 | // New Caledonia |
| 532 | 'NC' => 'NCL', |
| 533 | // French Polynesia |
| 534 | 'PF' => 'PYF', |
| 535 | // Tokelau |
| 536 | 'TK' => 'TKL', |
| 537 | // American Samoa |
| 538 | 'AS' => 'ASM', |
| 539 | // Cook Islands |
| 540 | 'CK' => 'COK', |
| 541 | // Guam |
| 542 | 'GU' => 'GUM', |
| 543 | // Nauru |
| 544 | 'NR' => 'NRU', |
| 545 | // Norfolk Island |
| 546 | 'NF' => 'NFK', |
| 547 | // Northern Mariana Islands |
| 548 | 'MP' => 'MNP', |
| 549 | // Samoa |
| 550 | 'WS' => 'WSM', |
| 551 | // United States Minor Outlying Islands |
| 552 | 'UM' => 'UMI', |
| 553 | // Wallis and Futuna |
| 554 | 'WF' => 'WLF', |
| 555 | // Pitcairn Islands |
| 556 | 'PN' => 'PCN', |
| 557 | // Antarctica |
| 558 | 'AQ' => 'ATA', |
| 559 | // Bouvet Island |
| 560 | 'BV' => 'BVT', |
| 561 | // French Southern Territories |
| 562 | 'TF' => 'ATF', |
| 563 | // Heard Island and McDonald Islands |
| 564 | 'HM' => 'HMD', |
| 565 | ], |
| 566 | ], |
| 567 | 'central-america' => [ |
| 568 | 'msgKey' => 'wikimedia-articletopics-topic-central-america', |
| 569 | 'countries' => [ |
| 570 | // Belize |
| 571 | 'BZ' => 'BLZ', |
| 572 | // Costa Rica |
| 573 | 'CR' => 'CRI', |
| 574 | // El Salvador |
| 575 | 'SV' => 'SLV', |
| 576 | // Guatemala |
| 577 | 'GT' => 'GTM', |
| 578 | // Honduras |
| 579 | 'HN' => 'HND', |
| 580 | // Nicaragua |
| 581 | 'NI' => 'NIC', |
| 582 | // Panama |
| 583 | 'PA' => 'PAN', |
| 584 | ], |
| 585 | ], |
| 586 | ]; |
| 587 | |
| 588 | /** |
| 589 | * Get a list of country codes with localized labels. |
| 590 | * |
| 591 | * @param array $countryCodes |
| 592 | * @param array $cldrA2toLabelMap |
| 593 | * @param Collator $collator |
| 594 | * @throws UnexpectedValueException When a requested country code is not supported. |
| 595 | * @return array [ |
| 596 | * [ |
| 597 | * 'id' => 'afg', |
| 598 | * 'label' => 'Afghanistan', |
| 599 | * ], |
| 600 | * ... |
| 601 | * ] |
| 602 | */ |
| 603 | private static function getCountries( |
| 604 | array $countryCodes, |
| 605 | array $cldrA2toLabelMap, |
| 606 | Collator $collator |
| 607 | ): array { |
| 608 | $countries = []; |
| 609 | |
| 610 | foreach ( $countryCodes as $a2 => $a3 ) { |
| 611 | if ( !in_array( $a2, self::SUPPORTED_COUNTRY_CODES, true ) ) { |
| 612 | throw new UnexpectedValueException( "Unsupported country code: $a2" ); |
| 613 | } |
| 614 | |
| 615 | if ( !isset( $cldrA2toLabelMap[$a2] ) ) { |
| 616 | // warning: missing localized label |
| 617 | continue; |
| 618 | } |
| 619 | $countries[] = [ |
| 620 | 'id' => strtolower( $a3 ), |
| 621 | 'label' => $cldrA2toLabelMap[$a2], |
| 622 | ]; |
| 623 | } |
| 624 | |
| 625 | usort( |
| 626 | $countries, |
| 627 | static fn ( array $a, array $b ) => $collator->compare( $a['label'], $b['label'] ) |
| 628 | ); |
| 629 | |
| 630 | return $countries; |
| 631 | } |
| 632 | |
| 633 | /** |
| 634 | * Get the list of supported country codes. |
| 635 | * |
| 636 | * @return array |
| 637 | */ |
| 638 | public static function getSupportedCountryCodes(): array { |
| 639 | return self::SUPPORTED_COUNTRY_CODES; |
| 640 | } |
| 641 | |
| 642 | /** |
| 643 | * Get the grouped country codes by region. |
| 644 | * |
| 645 | * @return array |
| 646 | */ |
| 647 | public static function getGroupedCountryCodes(): array { |
| 648 | return self::GROUPED_COUNTRY_CODES; |
| 649 | } |
| 650 | |
| 651 | /** |
| 652 | * Get a list of regions and their countries, with localized labels. |
| 653 | * |
| 654 | * @param string $languageCode |
| 655 | * @return array [ |
| 656 | * [ |
| 657 | * 'id' => 'asia', |
| 658 | * 'label' => 'Asia', |
| 659 | * 'countries' => [ |
| 660 | * [ |
| 661 | * 'id' => 'afg', |
| 662 | * 'label' => 'Afghanistan', |
| 663 | * ], |
| 664 | * ... |
| 665 | * ], |
| 666 | * ], |
| 667 | * ... |
| 668 | * ] |
| 669 | */ |
| 670 | public static function getLocalizedRegionsAndCountries( string $languageCode ): array { |
| 671 | $regions = []; |
| 672 | $services = MediaWikiServices::getInstance(); |
| 673 | $collator = Collator::create( $languageCode ) ?: Collator::create( 'root' ); |
| 674 | |
| 675 | if ( !( |
| 676 | $services->getExtensionRegistry()->isLoaded( 'cldr' ) |
| 677 | || $services->getExtensionRegistry()->isLoaded( 'CLDR' ) |
| 678 | ) ) { |
| 679 | // todo: warning: CLDR extension not loaded |
| 680 | return []; |
| 681 | } |
| 682 | |
| 683 | $cldrA2toLabelMap = CountryNames::getNames( $languageCode ); |
| 684 | |
| 685 | $language = $services->getLanguageFactory()->getLanguage( $languageCode ); |
| 686 | |
| 687 | foreach ( self::GROUPED_COUNTRY_CODES as $region => $regionInfo ) { |
| 688 | $labelMsg = new Message( $regionInfo['msgKey'], [], $language ); |
| 689 | $regions[] = [ |
| 690 | 'id' => $region, |
| 691 | 'label' => $labelMsg->text(), |
| 692 | 'countries' => self::getCountries( $regionInfo['countries'], $cldrA2toLabelMap, $collator ), |
| 693 | ]; |
| 694 | } |
| 695 | |
| 696 | usort( |
| 697 | $regions, |
| 698 | static fn ( array $a, array $b ) => $collator->compare( $a['label'], $b['label'] ) |
| 699 | ); |
| 700 | |
| 701 | return $regions; |
| 702 | } |
| 703 | } |