File size: 7,735 Bytes
dbb1bf9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import COMTRADE_REPORTER_OVERRIDES from '../../scripts/shared/comtrade-reporter-overrides.json';

export const ISO2_TO_ISO3: Record<string, string> = {
  AD: 'AND', AE: 'ARE', AF: 'AFG', AG: 'ATG', AI: 'AIA', AL: 'ALB', AM: 'ARM', AO: 'AGO',
  AQ: 'ATA', AR: 'ARG', AS: 'ASM', AT: 'AUT', AU: 'AUS', AW: 'ABW', AX: 'ALA', AZ: 'AZE',
  BA: 'BIH', BB: 'BRB', BD: 'BGD', BE: 'BEL', BF: 'BFA', BG: 'BGR', BH: 'BHR', BI: 'BDI',
  BJ: 'BEN', BL: 'BLM', BM: 'BMU', BN: 'BRN', BO: 'BOL', BR: 'BRA', BS: 'BHS', BT: 'BTN',
  BW: 'BWA', BY: 'BLR', BZ: 'BLZ', CA: 'CAN', CD: 'COD', CF: 'CAF', CG: 'COG', CH: 'CHE',
  CI: 'CIV', CK: 'COK', CL: 'CHL', CM: 'CMR', CN: 'CHN', CO: 'COL', CR: 'CRI', CU: 'CUB',
  CV: 'CPV', CW: 'CUW', CY: 'CYP', CZ: 'CZE', DE: 'DEU', DJ: 'DJI', DK: 'DNK', DM: 'DMA',
  DO: 'DOM', DZ: 'DZA', EC: 'ECU', EE: 'EST', EG: 'EGY', EH: 'ESH', ER: 'ERI', ES: 'ESP',
  ET: 'ETH', FI: 'FIN', FJ: 'FJI', FK: 'FLK', FM: 'FSM', FO: 'FRO', FR: 'FRA', GA: 'GAB',
  GB: 'GBR', GD: 'GRD', GE: 'GEO', GG: 'GGY', GH: 'GHA', GI: 'GIB', GL: 'GRL', GM: 'GMB',
  GN: 'GIN', GQ: 'GNQ', GR: 'GRC', GS: 'SGS', GT: 'GTM', GU: 'GUM', GW: 'GNB', GY: 'GUY',
  HK: 'HKG', HM: 'HMD', HN: 'HND', HR: 'HRV', HT: 'HTI', HU: 'HUN', ID: 'IDN', IE: 'IRL',
  IL: 'ISR', IM: 'IMN', IN: 'IND', IO: 'IOT', IQ: 'IRQ', IR: 'IRN', IS: 'ISL', IT: 'ITA',
  JE: 'JEY', JM: 'JAM', JO: 'JOR', JP: 'JPN', KE: 'KEN', KG: 'KGZ', KH: 'KHM', KI: 'KIR',
  KM: 'COM', KN: 'KNA', KP: 'PRK', KR: 'KOR', KW: 'KWT', KY: 'CYM', KZ: 'KAZ', LA: 'LAO',
  LB: 'LBN', LC: 'LCA', LI: 'LIE', LK: 'LKA', LR: 'LBR', LS: 'LSO', LT: 'LTU', LU: 'LUX',
  LV: 'LVA', LY: 'LBY', MA: 'MAR', MC: 'MCO', MD: 'MDA', ME: 'MNE', MF: 'MAF', MG: 'MDG',
  MH: 'MHL', MK: 'MKD', ML: 'MLI', MM: 'MMR', MN: 'MNG', MO: 'MAC', MP: 'MNP', MR: 'MRT',
  MS: 'MSR', MT: 'MLT', MU: 'MUS', MV: 'MDV', MW: 'MWI', MX: 'MEX', MY: 'MYS', MZ: 'MOZ',
  NA: 'NAM', NC: 'NCL', NE: 'NER', NF: 'NFK', NG: 'NGA', NI: 'NIC', NL: 'NLD', NO: 'NOR',
  NP: 'NPL', NR: 'NRU', NU: 'NIU', NZ: 'NZL', OM: 'OMN', PA: 'PAN', PE: 'PER', PF: 'PYF',
  PG: 'PNG', PH: 'PHL', PK: 'PAK', PL: 'POL', PM: 'SPM', PN: 'PCN', PR: 'PRI', PS: 'PSE',
  PT: 'PRT', PW: 'PLW', PY: 'PRY', QA: 'QAT', RO: 'ROU', RS: 'SRB', RU: 'RUS', RW: 'RWA',
  SA: 'SAU', SB: 'SLB', SC: 'SYC', SD: 'SDN', SE: 'SWE', SG: 'SGP', SH: 'SHN', SI: 'SVN',
  SK: 'SVK', SL: 'SLE', SM: 'SMR', SN: 'SEN', SO: 'SOM', SR: 'SUR', SS: 'SSD', ST: 'STP',
  SV: 'SLV', SX: 'SXM', SY: 'SYR', SZ: 'SWZ', TC: 'TCA', TD: 'TCD', TF: 'ATF', TG: 'TGO',
  TH: 'THA', TJ: 'TJK', TL: 'TLS', TM: 'TKM', TN: 'TUN', TO: 'TON', TR: 'TUR', TT: 'TTO',
  TV: 'TUV', TW: 'TWN', TZ: 'TZA', UA: 'UKR', UG: 'UGA', UM: 'UMI', US: 'USA', UY: 'URY',
  UZ: 'UZB', VA: 'VAT', VC: 'VCT', VE: 'VEN', VG: 'VGB', VI: 'VIR', VN: 'VNM', VU: 'VUT',
  WF: 'WLF', WS: 'WSM', XK: 'XKX', YE: 'YEM', ZA: 'ZAF', ZM: 'ZMB', ZW: 'ZWE',
};

const ISO2_TO_UN: Record<string, string> = {
  AD: '020', AE: '784', AF: '004', AG: '028', AI: '660', AL: '008', AM: '051', AO: '024',
  AQ: '010', AR: '032', AS: '016', AT: '040', AU: '036', AW: '533', AX: '248', AZ: '031',
  BA: '070', BB: '052', BD: '050', BE: '056', BF: '854', BG: '100', BH: '048', BI: '108',
  BJ: '204', BL: '652', BM: '060', BN: '096', BO: '068', BR: '076', BS: '044', BT: '064',
  BW: '072', BY: '112', BZ: '084', CA: '124', CD: '180', CF: '140', CG: '178', CH: '756',
  CI: '384', CK: '184', CL: '152', CM: '120', CN: '156', CO: '170', CR: '188', CU: '192',
  CV: '132', CW: '531', CY: '196', CZ: '203', DE: '276', DJ: '262', DK: '208', DM: '212',
  DO: '214', DZ: '012', EC: '218', EE: '233', EG: '818', EH: '732', ER: '232', ES: '724',
  ET: '231', FI: '246', FJ: '242', FK: '238', FM: '583', FO: '234', FR: '250', GA: '266',
  GB: '826', GD: '308', GE: '268', GG: '831', GH: '288', GI: '292', GL: '304', GM: '270',
  GN: '324', GQ: '226', GR: '300', GS: '239', GT: '320', GU: '316', GW: '624', GY: '328',
  HK: '344', HM: '334', HN: '340', HR: '191', HT: '332', HU: '348', ID: '360', IE: '372',
  IL: '376', IM: '833', IN: '356', IO: '086', IQ: '368', IR: '364', IS: '352', IT: '380',
  JE: '832', JM: '388', JO: '400', JP: '392', KE: '404', KG: '417', KH: '116', KI: '296',
  KM: '174', KN: '659', KP: '408', KR: '410', KW: '414', KY: '136', KZ: '398', LA: '418',
  LB: '422', LC: '662', LI: '438', LK: '144', LR: '430', LS: '426', LT: '440', LU: '442',
  LV: '428', LY: '434', MA: '504', MC: '492', MD: '498', ME: '499', MF: '663', MG: '450',
  MH: '584', MK: '807', ML: '466', MM: '104', MN: '496', MO: '446', MP: '580', MR: '478',
  MS: '500', MT: '470', MU: '480', MV: '462', MW: '454', MX: '484', MY: '458', MZ: '508',
  NA: '516', NC: '540', NE: '562', NF: '574', NG: '566', NI: '558', NL: '528', NO: '578',
  NP: '524', NR: '520', NU: '570', NZ: '554', OM: '512', PA: '591', PE: '604', PF: '258',
  PG: '598', PH: '608', PK: '586', PL: '616', PM: '666', PN: '612', PR: '630', PS: '275',
  PT: '620', PW: '585', PY: '600', QA: '634', RO: '642', RS: '688', RU: '643', RW: '646',
  SA: '682', SB: '090', SC: '690', SD: '729', SE: '752', SG: '702', SH: '654', SI: '705',
  SK: '703', SL: '694', SM: '674', SN: '686', SO: '706', SR: '740', SS: '728', ST: '678',
  SV: '222', SX: '534', SY: '760', SZ: '748', TC: '796', TD: '148', TF: '260', TG: '768',
  TH: '764', TJ: '762', TL: '626', TM: '795', TN: '788', TO: '776', TR: '792', TT: '780',
  TV: '798', TW: '158', TZ: '834', UA: '804', UG: '800', UM: '581', US: '840', UY: '858',
  UZ: '860', VA: '336', VC: '670', VE: '862', VG: '092', VI: '850', VN: '704', VU: '548',
  WF: '876', WS: '882', XK: '412', YE: '887', ZA: '710', ZM: '894', ZW: '716',
};

export function iso2ToIso3(iso2: string): string | null {
  return ISO2_TO_ISO3[iso2.toUpperCase()] ?? null;
}

export function iso2ToUnCode(iso2: string): string | null {
  return ISO2_TO_UN[iso2.toUpperCase()] ?? null;
}

// UN M49 codes mostly match UN Comtrade reporterCodes. Use the shared override
// file wherever an iso2 feeds into a Comtrade reporterCode lookup or seeded
// comtrade:* key so non-M49 reporters stay aligned with server/seed paths.
const ISO2_TO_COMTRADE_OVERRIDES: Readonly<Record<string, string>> = COMTRADE_REPORTER_OVERRIDES;
export function iso2ToComtradeReporterCode(iso2: string): string | null {
  const upper = iso2.toUpperCase();
  return ISO2_TO_COMTRADE_OVERRIDES[upper] ?? ISO2_TO_UN[upper] ?? null;
}

const ISO3_TO_ISO2: Record<string, string> = Object.fromEntries(
  Object.entries(ISO2_TO_ISO3).map(([iso2, iso3]) => [iso3, iso2]),
);

// Tight alias map for the most common name forms. Keep <30 entries; reject
// unknown rather than try to be a full geocoder. Keys are lowercase.
const NAME_ALIASES_TO_ISO2: Record<string, string> = {
  'united states': 'US',
  'united states of america': 'US',
  'usa': 'US',
  'u.s.': 'US',
  'u.s.a.': 'US',
  'america': 'US',
  'united kingdom': 'GB',
  'uk': 'GB',
  'u.k.': 'GB',
  'britain': 'GB',
  'great britain': 'GB',
  'england': 'GB',
  'russia': 'RU',
  'russian federation': 'RU',
  'south korea': 'KR',
  'korea, south': 'KR',
  'republic of korea': 'KR',
  'north korea': 'KP',
  'korea, north': 'KP',
  'czech republic': 'CZ',
  'czechia': 'CZ',
  'ivory coast': 'CI',
  "cote d'ivoire": 'CI',
  'vietnam': 'VN',
  'viet nam': 'VN',
  'iran': 'IR',
  'syria': 'SY',
  'taiwan': 'TW',
  'palestine': 'PS',
  'vatican': 'VA',
  'uae': 'AE',
};

export function toIso2(input: string | null | undefined): string | null {
  if (input == null) return null;
  const trimmed = input.trim();
  if (!trimmed) return null;
  const upper = trimmed.toUpperCase();
  if (upper.length === 2 && ISO2_TO_ISO3[upper]) return upper;
  if (upper.length === 3 && ISO3_TO_ISO2[upper]) return ISO3_TO_ISO2[upper];
  return NAME_ALIASES_TO_ISO2[trimmed.toLowerCase()] ?? null;
}