Seth commited on
Commit
fe92a01
·
1 Parent(s): 635c08a
frontend/src/lib/countries.js CHANGED
@@ -1,3 +1,5 @@
 
 
1
  /** ISO 3166-1 alpha-2 → regional indicator symbols (flag emoji). */
2
  export function flagEmojiFromCode(code) {
3
  if (!code || typeof code !== 'string' || code.length !== 2) return '🏳️';
@@ -6,76 +8,34 @@ export function flagEmojiFromCode(code) {
6
  return String.fromCodePoint(...[...u].map((c) => 127397 + c.charCodeAt(0)));
7
  }
8
 
9
- const COMMON = [
10
- ['US', 'United States'],
11
- ['CA', 'Canada'],
12
- ['GB', 'United Kingdom'],
13
- ['AU', 'Australia'],
14
- ['DE', 'Germany'],
15
- ['FR', 'France'],
16
- ['IN', 'India'],
17
- ['JP', 'Japan'],
18
- ['CN', 'China'],
19
- ['BR', 'Brazil'],
20
- ['MX', 'Mexico'],
21
- ['ES', 'Spain'],
22
- ['IT', 'Italy'],
23
- ['NL', 'Netherlands'],
24
- ['SE', 'Sweden'],
25
- ['NO', 'Norway'],
26
- ['DK', 'Denmark'],
27
- ['FI', 'Finland'],
28
- ['CH', 'Switzerland'],
29
- ['AT', 'Austria'],
30
- ['BE', 'Belgium'],
31
- ['IE', 'Ireland'],
32
- ['NZ', 'New Zealand'],
33
- ['SG', 'Singapore'],
34
- ['KR', 'South Korea'],
35
- ['TW', 'Taiwan'],
36
- ['HK', 'Hong Kong'],
37
- ['ZA', 'South Africa'],
38
- ['AE', 'United Arab Emirates'],
39
- ['IL', 'Israel'],
40
- ['PL', 'Poland'],
41
- ['PT', 'Portugal'],
42
- ['AR', 'Argentina'],
43
- ['CL', 'Chile'],
44
- ['CO', 'Colombia'],
45
- ];
46
-
47
  let cached = null;
48
 
49
  /**
 
 
 
50
  * @returns {{ code: string, name: string }[]}
51
  */
52
  export function getAllCountries() {
53
  if (cached) return cached;
54
- if (typeof Intl !== 'undefined' && typeof Intl.supportedValuesOf === 'function') {
 
 
 
 
 
 
55
  try {
56
- const codes = Intl.supportedValuesOf('region').filter((c) => c.length === 2);
57
- const dn = new Intl.DisplayNames(['en'], { type: 'region' });
58
- const rows = codes
59
- .map((code) => {
60
- let name = '';
61
- try {
62
- name = dn.of(code) || '';
63
- } catch {
64
- name = '';
65
- }
66
- return { code, name: name && name !== code ? name : '' };
67
- })
68
- .filter((x) => x.name);
69
- rows.sort((a, b) => a.name.localeCompare(b.name));
70
- cached = rows;
71
- return cached;
72
  } catch {
73
- /* fallback */
74
  }
75
- }
76
- cached = COMMON.map(([code, name]) => ({ code, name })).sort((a, b) =>
77
- a.name.localeCompare(b.name)
78
- );
79
  return cached;
80
  }
81
 
@@ -89,9 +49,25 @@ export function matchCountry(stored, countries) {
89
  const s = stored.trim();
90
  if (!s) return null;
91
  const lower = s.toLowerCase();
 
92
  const byName = countries.find((c) => c.name.toLowerCase() === lower);
93
  if (byName) return byName;
 
94
  const byCode = countries.find((c) => c.code.toLowerCase() === lower);
95
  if (byCode) return byCode;
96
- return countries.find((c) => c.name.toLowerCase().includes(lower)) || null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  }
 
1
+ import { IANA_ISO3166 } from '@/lib/iso3166-iana';
2
+
3
  /** ISO 3166-1 alpha-2 → regional indicator symbols (flag emoji). */
4
  export function flagEmojiFromCode(code) {
5
  if (!code || typeof code !== 'string' || code.length !== 2) return '🏳️';
 
8
  return String.fromCodePoint(...[...u].map((c) => 127397 + c.charCodeAt(0)));
9
  }
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  let cached = null;
12
 
13
  /**
14
+ * Full country list: IANA iso3166.tab (every ISO alpha-2 region), display names
15
+ * upgraded via {@link Intl.DisplayNames} when available.
16
+ *
17
  * @returns {{ code: string, name: string }[]}
18
  */
19
  export function getAllCountries() {
20
  if (cached) return cached;
21
+ const dn =
22
+ typeof Intl !== 'undefined' && typeof Intl.DisplayNames === 'function'
23
+ ? new Intl.DisplayNames(['en'], { type: 'region' })
24
+ : null;
25
+
26
+ cached = IANA_ISO3166.map(({ code, name: ianaName }) => {
27
+ let name = ianaName;
28
  try {
29
+ if (dn) {
30
+ const intl = dn.of(code);
31
+ if (intl && intl !== code) name = intl;
32
+ }
 
 
 
 
 
 
 
 
 
 
 
 
33
  } catch {
34
+ /* keep IANA label */
35
  }
36
+ return { code, name };
37
+ }).sort((a, b) => a.name.localeCompare(b.name));
38
+
 
39
  return cached;
40
  }
41
 
 
49
  const s = stored.trim();
50
  if (!s) return null;
51
  const lower = s.toLowerCase();
52
+
53
  const byName = countries.find((c) => c.name.toLowerCase() === lower);
54
  if (byName) return byName;
55
+
56
  const byCode = countries.find((c) => c.code.toLowerCase() === lower);
57
  if (byCode) return byCode;
58
+
59
+ const iana = IANA_ISO3166.find((c) => c.name.toLowerCase() === lower);
60
+ if (iana) {
61
+ return countries.find((c) => c.code === iana.code) || iana;
62
+ }
63
+
64
+ const fuzzy = countries.find((c) => c.name.toLowerCase().includes(lower));
65
+ if (fuzzy) return fuzzy;
66
+
67
+ const ianaFuzzy = IANA_ISO3166.find((c) => c.name.toLowerCase().includes(lower));
68
+ if (ianaFuzzy) {
69
+ return countries.find((c) => c.code === ianaFuzzy.code) || ianaFuzzy;
70
+ }
71
+
72
+ return null;
73
  }
frontend/src/lib/iso3166-iana.js ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * ISO 3166-1 alpha-2 + English names from IANA tzdb iso3166.tab (public domain).
3
+ * Ensures the country picker lists every code regardless of Intl support.
4
+ */
5
+ export const IANA_ISO3166 = [
6
+ ['AD', 'Andorra'],
7
+ ['AE', 'United Arab Emirates'],
8
+ ['AF', 'Afghanistan'],
9
+ ['AG', 'Antigua & Barbuda'],
10
+ ['AI', 'Anguilla'],
11
+ ['AL', 'Albania'],
12
+ ['AM', 'Armenia'],
13
+ ['AO', 'Angola'],
14
+ ['AQ', 'Antarctica'],
15
+ ['AR', 'Argentina'],
16
+ ['AS', 'Samoa (American)'],
17
+ ['AT', 'Austria'],
18
+ ['AU', 'Australia'],
19
+ ['AW', 'Aruba'],
20
+ ['AX', 'Åland Islands'],
21
+ ['AZ', 'Azerbaijan'],
22
+ ['BA', 'Bosnia & Herzegovina'],
23
+ ['BB', 'Barbados'],
24
+ ['BD', 'Bangladesh'],
25
+ ['BE', 'Belgium'],
26
+ ['BF', 'Burkina Faso'],
27
+ ['BG', 'Bulgaria'],
28
+ ['BH', 'Bahrain'],
29
+ ['BI', 'Burundi'],
30
+ ['BJ', 'Benin'],
31
+ ['BL', 'St Barthelemy'],
32
+ ['BM', 'Bermuda'],
33
+ ['BN', 'Brunei'],
34
+ ['BO', 'Bolivia'],
35
+ ['BQ', 'Caribbean NL'],
36
+ ['BR', 'Brazil'],
37
+ ['BS', 'Bahamas'],
38
+ ['BT', 'Bhutan'],
39
+ ['BV', 'Bouvet Island'],
40
+ ['BW', 'Botswana'],
41
+ ['BY', 'Belarus'],
42
+ ['BZ', 'Belize'],
43
+ ['CA', 'Canada'],
44
+ ['CC', 'Cocos (Keeling) Islands'],
45
+ ['CD', 'Congo (Dem. Rep.)'],
46
+ ['CF', 'Central African Rep.'],
47
+ ['CG', 'Congo (Rep.)'],
48
+ ['CH', 'Switzerland'],
49
+ ['CI', "Côte d'Ivoire"],
50
+ ['CK', 'Cook Islands'],
51
+ ['CL', 'Chile'],
52
+ ['CM', 'Cameroon'],
53
+ ['CN', 'China'],
54
+ ['CO', 'Colombia'],
55
+ ['CR', 'Costa Rica'],
56
+ ['CU', 'Cuba'],
57
+ ['CV', 'Cape Verde'],
58
+ ['CW', 'Curaçao'],
59
+ ['CX', 'Christmas Island'],
60
+ ['CY', 'Cyprus'],
61
+ ['CZ', 'Czech Republic'],
62
+ ['DE', 'Germany'],
63
+ ['DJ', 'Djibouti'],
64
+ ['DK', 'Denmark'],
65
+ ['DM', 'Dominica'],
66
+ ['DO', 'Dominican Republic'],
67
+ ['DZ', 'Algeria'],
68
+ ['EC', 'Ecuador'],
69
+ ['EE', 'Estonia'],
70
+ ['EG', 'Egypt'],
71
+ ['EH', 'Western Sahara'],
72
+ ['ER', 'Eritrea'],
73
+ ['ES', 'Spain'],
74
+ ['ET', 'Ethiopia'],
75
+ ['FI', 'Finland'],
76
+ ['FJ', 'Fiji'],
77
+ ['FK', 'Falkland Islands'],
78
+ ['FM', 'Micronesia'],
79
+ ['FO', 'Faroe Islands'],
80
+ ['FR', 'France'],
81
+ ['GA', 'Gabon'],
82
+ ['GB', 'Britain (UK)'],
83
+ ['GD', 'Grenada'],
84
+ ['GE', 'Georgia'],
85
+ ['GF', 'French Guiana'],
86
+ ['GG', 'Guernsey'],
87
+ ['GH', 'Ghana'],
88
+ ['GI', 'Gibraltar'],
89
+ ['GL', 'Greenland'],
90
+ ['GM', 'Gambia'],
91
+ ['GN', 'Guinea'],
92
+ ['GP', 'Guadeloupe'],
93
+ ['GQ', 'Equatorial Guinea'],
94
+ ['GR', 'Greece'],
95
+ ['GS', 'South Georgia & the South Sandwich Islands'],
96
+ ['GT', 'Guatemala'],
97
+ ['GU', 'Guam'],
98
+ ['GW', 'Guinea-Bissau'],
99
+ ['GY', 'Guyana'],
100
+ ['HK', 'Hong Kong'],
101
+ ['HM', 'Heard Island & McDonald Islands'],
102
+ ['HN', 'Honduras'],
103
+ ['HR', 'Croatia'],
104
+ ['HT', 'Haiti'],
105
+ ['HU', 'Hungary'],
106
+ ['ID', 'Indonesia'],
107
+ ['IE', 'Ireland'],
108
+ ['IL', 'Israel'],
109
+ ['IM', 'Isle of Man'],
110
+ ['IN', 'India'],
111
+ ['IO', 'British Indian Ocean Territory'],
112
+ ['IQ', 'Iraq'],
113
+ ['IR', 'Iran'],
114
+ ['IS', 'Iceland'],
115
+ ['IT', 'Italy'],
116
+ ['JE', 'Jersey'],
117
+ ['JM', 'Jamaica'],
118
+ ['JO', 'Jordan'],
119
+ ['JP', 'Japan'],
120
+ ['KE', 'Kenya'],
121
+ ['KG', 'Kyrgyzstan'],
122
+ ['KH', 'Cambodia'],
123
+ ['KI', 'Kiribati'],
124
+ ['KM', 'Comoros'],
125
+ ['KN', 'St Kitts & Nevis'],
126
+ ['KP', 'Korea (North)'],
127
+ ['KR', 'Korea (South)'],
128
+ ['KW', 'Kuwait'],
129
+ ['KY', 'Cayman Islands'],
130
+ ['KZ', 'Kazakhstan'],
131
+ ['LA', 'Laos'],
132
+ ['LB', 'Lebanon'],
133
+ ['LC', 'St Lucia'],
134
+ ['LI', 'Liechtenstein'],
135
+ ['LK', 'Sri Lanka'],
136
+ ['LR', 'Liberia'],
137
+ ['LS', 'Lesotho'],
138
+ ['LT', 'Lithuania'],
139
+ ['LU', 'Luxembourg'],
140
+ ['LV', 'Latvia'],
141
+ ['LY', 'Libya'],
142
+ ['MA', 'Morocco'],
143
+ ['MC', 'Monaco'],
144
+ ['MD', 'Moldova'],
145
+ ['ME', 'Montenegro'],
146
+ ['MF', 'St Martin (French)'],
147
+ ['MG', 'Madagascar'],
148
+ ['MH', 'Marshall Islands'],
149
+ ['MK', 'North Macedonia'],
150
+ ['ML', 'Mali'],
151
+ ['MM', 'Myanmar (Burma)'],
152
+ ['MN', 'Mongolia'],
153
+ ['MO', 'Macau'],
154
+ ['MP', 'Northern Mariana Islands'],
155
+ ['MQ', 'Martinique'],
156
+ ['MR', 'Mauritania'],
157
+ ['MS', 'Montserrat'],
158
+ ['MT', 'Malta'],
159
+ ['MU', 'Mauritius'],
160
+ ['MV', 'Maldives'],
161
+ ['MW', 'Malawi'],
162
+ ['MX', 'Mexico'],
163
+ ['MY', 'Malaysia'],
164
+ ['MZ', 'Mozambique'],
165
+ ['NA', 'Namibia'],
166
+ ['NC', 'New Caledonia'],
167
+ ['NE', 'Niger'],
168
+ ['NF', 'Norfolk Island'],
169
+ ['NG', 'Nigeria'],
170
+ ['NI', 'Nicaragua'],
171
+ ['NL', 'Netherlands'],
172
+ ['NO', 'Norway'],
173
+ ['NP', 'Nepal'],
174
+ ['NR', 'Nauru'],
175
+ ['NU', 'Niue'],
176
+ ['NZ', 'New Zealand'],
177
+ ['OM', 'Oman'],
178
+ ['PA', 'Panama'],
179
+ ['PE', 'Peru'],
180
+ ['PF', 'French Polynesia'],
181
+ ['PG', 'Papua New Guinea'],
182
+ ['PH', 'Philippines'],
183
+ ['PK', 'Pakistan'],
184
+ ['PL', 'Poland'],
185
+ ['PM', 'St Pierre & Miquelon'],
186
+ ['PN', 'Pitcairn'],
187
+ ['PR', 'Puerto Rico'],
188
+ ['PS', 'Palestine'],
189
+ ['PT', 'Portugal'],
190
+ ['PW', 'Palau'],
191
+ ['PY', 'Paraguay'],
192
+ ['QA', 'Qatar'],
193
+ ['RE', 'Réunion'],
194
+ ['RO', 'Romania'],
195
+ ['RS', 'Serbia'],
196
+ ['RU', 'Russia'],
197
+ ['RW', 'Rwanda'],
198
+ ['SA', 'Saudi Arabia'],
199
+ ['SB', 'Solomon Islands'],
200
+ ['SC', 'Seychelles'],
201
+ ['SD', 'Sudan'],
202
+ ['SE', 'Sweden'],
203
+ ['SG', 'Singapore'],
204
+ ['SH', 'St Helena'],
205
+ ['SI', 'Slovenia'],
206
+ ['SJ', 'Svalbard & Jan Mayen'],
207
+ ['SK', 'Slovakia'],
208
+ ['SL', 'Sierra Leone'],
209
+ ['SM', 'San Marino'],
210
+ ['SN', 'Senegal'],
211
+ ['SO', 'Somalia'],
212
+ ['SR', 'Suriname'],
213
+ ['SS', 'South Sudan'],
214
+ ['ST', 'Sao Tome & Principe'],
215
+ ['SV', 'El Salvador'],
216
+ ['SX', 'St Maarten (Dutch)'],
217
+ ['SY', 'Syria'],
218
+ ['SZ', 'Eswatini (Swaziland)'],
219
+ ['TC', 'Turks & Caicos Is'],
220
+ ['TD', 'Chad'],
221
+ ['TF', 'French S. Terr.'],
222
+ ['TG', 'Togo'],
223
+ ['TH', 'Thailand'],
224
+ ['TJ', 'Tajikistan'],
225
+ ['TK', 'Tokelau'],
226
+ ['TL', 'East Timor'],
227
+ ['TM', 'Turkmenistan'],
228
+ ['TN', 'Tunisia'],
229
+ ['TO', 'Tonga'],
230
+ ['TR', 'Turkey'],
231
+ ['TT', 'Trinidad & Tobago'],
232
+ ['TV', 'Tuvalu'],
233
+ ['TW', 'Taiwan'],
234
+ ['TZ', 'Tanzania'],
235
+ ['UA', 'Ukraine'],
236
+ ['UG', 'Uganda'],
237
+ ['UM', 'US minor outlying islands'],
238
+ ['US', 'United States'],
239
+ ['UY', 'Uruguay'],
240
+ ['UZ', 'Uzbekistan'],
241
+ ['VA', 'Vatican City'],
242
+ ['VC', 'St Vincent'],
243
+ ['VE', 'Venezuela'],
244
+ ['VG', 'Virgin Islands (UK)'],
245
+ ['VI', 'Virgin Islands (US)'],
246
+ ['VN', 'Vietnam'],
247
+ ['VU', 'Vanuatu'],
248
+ ['WF', 'Wallis & Futuna'],
249
+ ['WS', 'Samoa (western)'],
250
+ ['YE', 'Yemen'],
251
+ ['YT', 'Mayotte'],
252
+ ['ZA', 'South Africa'],
253
+ ['ZM', 'Zambia'],
254
+ ['ZW', 'Zimbabwe'],
255
+ ].map(([code, name]) => ({ code, name }));