@juit/vue-i18n 0.4.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +187 -0
- package/NOTICE.md +13 -0
- package/README.md +232 -93
- package/dist/index.d.ts +235 -174
- package/dist/index.js +147 -90
- package/dist/index.js.map +1 -1
- package/lib/index.ts +386 -0
- package/lib/iso-3166.ts +272 -0
- package/lib/iso-4217.ts +176 -0
- package/lib/iso-639.ts +205 -0
- package/lib/translator.ts +539 -0
- package/package.json +14 -12
package/lib/index.ts
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { inject } from 'vue'
|
|
2
|
+
|
|
3
|
+
import { isISOLanguage } from './iso-639'
|
|
4
|
+
import { makeTranslator } from './translator'
|
|
5
|
+
|
|
6
|
+
import type { App } from 'vue'
|
|
7
|
+
import type { ISOCurrency } from './iso-4217'
|
|
8
|
+
import type { ISOLanguage } from './iso-639'
|
|
9
|
+
import type { Translator } from './translator'
|
|
10
|
+
|
|
11
|
+
/* ===== REFERENCE LANGUAGES, COUNTRIES, AND CURRENCIES ====================== */
|
|
12
|
+
|
|
13
|
+
export { isISOCountry, ISO_COUNTRIES } from './iso-3166'
|
|
14
|
+
export { isISOCurrency, ISO_CURRENCIES } from './iso-4217'
|
|
15
|
+
export { isISOLanguage, ISO_LANGUAGES } from './iso-639'
|
|
16
|
+
|
|
17
|
+
export type * from './iso-3166'
|
|
18
|
+
export type * from './iso-4217'
|
|
19
|
+
export type * from './iso-639'
|
|
20
|
+
|
|
21
|
+
/* ===== TYPES FOR DECLARATION MERGING ====================================== */
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Application configuration types, supplied through declaration merging.
|
|
25
|
+
*
|
|
26
|
+
* This interface (intentionally empty) is used to merge the actual per-app
|
|
27
|
+
* configuration of the translation system, in order to provide the correct
|
|
28
|
+
* types to the rest of the system.
|
|
29
|
+
*
|
|
30
|
+
* The following properties can be defined as unions of string literals:
|
|
31
|
+
*
|
|
32
|
+
* * `languages`: the supported ISO 639-1 language codes. When configured
|
|
33
|
+
* with a subset of codes, each translation must include
|
|
34
|
+
* a message for every base language in that subset.
|
|
35
|
+
* * `translationKeys`: the translation keys known by the application.
|
|
36
|
+
* Those are the arbitrary keys used to identify the
|
|
37
|
+
* messages to be translated with the `t` and `tc`
|
|
38
|
+
* methods of `Translator`.
|
|
39
|
+
* * `dateTimeFormats`: the date and time format _aliases_ used by the
|
|
40
|
+
* application.
|
|
41
|
+
* * `numberFormats`: the number format _aliases_ used by the application.
|
|
42
|
+
*
|
|
43
|
+
* To configure the types, follow the example below:
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* const translations = {
|
|
47
|
+
* 'hello': { en: 'Hello, world!', de: 'Hallo, Welt!' }
|
|
48
|
+
* } as const satisfies Translations
|
|
49
|
+
*
|
|
50
|
+
* const dateTimeFormats = {
|
|
51
|
+
* // override the default format
|
|
52
|
+
* default: { dateStyle: 'short', timeStyle: 'short' },
|
|
53
|
+
* // add a new custom format
|
|
54
|
+
* custom: {
|
|
55
|
+
* day: '2-digit',
|
|
56
|
+
* month: '2-digit',
|
|
57
|
+
* year: 'numeric',
|
|
58
|
+
* weekday: 'short',
|
|
59
|
+
* timeZone: 'UTC',
|
|
60
|
+
* },
|
|
61
|
+
* } as const satisfies DateTimeFormats
|
|
62
|
+
*
|
|
63
|
+
* const numberFormats = {
|
|
64
|
+
* speed: { style: 'unit', unit: 'kilometer-per-hour' },
|
|
65
|
+
* } as const satisfies NumberFormats
|
|
66
|
+
*
|
|
67
|
+
* declare module '@juit/vue-i18n' {
|
|
68
|
+
* export interface I18nConfiguration {
|
|
69
|
+
* languages: 'de' | 'en',
|
|
70
|
+
* translationKeys: keyof typeof translations,
|
|
71
|
+
* dateTimeFormats: keyof typeof dateTimeFormats,
|
|
72
|
+
* numberFormats: keyof typeof numberFormats,
|
|
73
|
+
* }
|
|
74
|
+
* }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export interface I18nConfiguration {
|
|
78
|
+
// intentionally empty
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* ===== FROM CONFIG TO TRANSLATIONS ======================================== */
|
|
82
|
+
|
|
83
|
+
/** Extract `T[K]` when present and assignable to `R`; otherwise fall back to `R`. */
|
|
84
|
+
type ExtractConfig<T, R, K extends string> = T extends { [ X in K ]: infer V } ? V extends R ? V : R : R
|
|
85
|
+
|
|
86
|
+
/** The languages configured in `I18nConfiguration` or all ISO languages */
|
|
87
|
+
export type Language = ExtractConfig<I18nConfiguration, ISOLanguage, 'languages'>
|
|
88
|
+
|
|
89
|
+
/** A message with optional pipe-delimited variants, or a readonly tuple of one to three variants. */
|
|
90
|
+
export type TranslationMessage = string | readonly [string, string?, string?]
|
|
91
|
+
|
|
92
|
+
/** Base languages are required for a configured subset; otherwise all are optional. */
|
|
93
|
+
type BaseTranslation = ISOLanguage extends Language ? {
|
|
94
|
+
readonly [ key in ISOLanguage ]?: TranslationMessage
|
|
95
|
+
} : {
|
|
96
|
+
readonly [ key in Language ]: TranslationMessage
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Optional regional variants of each supported language. */
|
|
100
|
+
type ExtendedTranslation = {
|
|
101
|
+
readonly [ key in `${Language}-${string}` ]?: TranslationMessage
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Expand the properties of the exported `Translation` type for editor hints. */
|
|
105
|
+
type PrettifyTranslation<T> = { [ l in keyof T ]: T[l] }
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* A type describing the translations for a given translation key.
|
|
109
|
+
*
|
|
110
|
+
* When `I18nConfiguration.languages` specifies a subset of ISO languages,
|
|
111
|
+
* every base language in that subset is required. Regional variants are
|
|
112
|
+
* optional. When unconfigured, or configured with all ISO languages, every
|
|
113
|
+
* language is optional.
|
|
114
|
+
*/
|
|
115
|
+
export type Translation = PrettifyTranslation<BaseTranslation & ExtendedTranslation>
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* All known translation keys.
|
|
119
|
+
*
|
|
120
|
+
* `I18nConfiguration.translationKeys` restricts the keys accepted by the
|
|
121
|
+
* `t(...)` and `tc(...)` methods and by `utils.updateTranslations(...)`.
|
|
122
|
+
*
|
|
123
|
+
* When left unconfigured, this type will be `string`.
|
|
124
|
+
*/
|
|
125
|
+
export type TranslationKey = ExtractConfig<I18nConfiguration, string, 'translationKeys'>
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Supported date and time format aliases.
|
|
129
|
+
*
|
|
130
|
+
* `I18nConfiguration.dateTimeFormats` defines the custom aliases accepted
|
|
131
|
+
* by `d(...)`. Built-in aliases remain available.
|
|
132
|
+
*
|
|
133
|
+
* When left unconfigured, this type will be `string`.
|
|
134
|
+
*/
|
|
135
|
+
export type DateTimeFormatAlias = ExtractConfig<I18nConfiguration, string, 'dateTimeFormats'>
|
|
136
|
+
| 'default' | 'short' | 'medium' | 'long' | 'full'
|
|
137
|
+
| 'date' | 'shortDate' | 'mediumDate' | 'longDate' | 'fullDate'
|
|
138
|
+
| 'time' | 'shortTime' | 'mediumTime' | 'longTime' | 'fullTime'
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Supported number format aliases.
|
|
142
|
+
*
|
|
143
|
+
* `I18nConfiguration.numberFormats` defines the custom aliases accepted
|
|
144
|
+
* by `n(...)`. The `default` alias and currency code types remain available.
|
|
145
|
+
*
|
|
146
|
+
* When left unconfigured, this type will be `string`.
|
|
147
|
+
*/
|
|
148
|
+
export type NumberFormatAlias = ExtractConfig<I18nConfiguration, string, 'numberFormats'>
|
|
149
|
+
| 'default' | ISOCurrency
|
|
150
|
+
|
|
151
|
+
/* ===== MODULE INITIALIZATION ============================================== */
|
|
152
|
+
|
|
153
|
+
/* Export the translator types */
|
|
154
|
+
export type * from './translator'
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Options to initialize the translations handled by the translation system.
|
|
158
|
+
*
|
|
159
|
+
* Each key identifies a message, and its value maps languages and regional
|
|
160
|
+
* variants to message strings or plural tuples.
|
|
161
|
+
*/
|
|
162
|
+
export interface Translations {
|
|
163
|
+
readonly [ key: string ]: Translation
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Options to initialize the date and time format _aliases_ used by the
|
|
168
|
+
* translation system.
|
|
169
|
+
*
|
|
170
|
+
* The default aliases (each can be overridden) are:
|
|
171
|
+
*
|
|
172
|
+
* ```ts
|
|
173
|
+
* {
|
|
174
|
+
* default: { dateStyle: 'medium', timeStyle: 'medium' },
|
|
175
|
+
* short: { dateStyle: 'short', timeStyle: 'short' },
|
|
176
|
+
* medium: { dateStyle: 'medium', timeStyle: 'medium' },
|
|
177
|
+
* long: { dateStyle: 'long', timeStyle: 'long' },
|
|
178
|
+
* full: { dateStyle: 'full', timeStyle: 'full' },
|
|
179
|
+
*
|
|
180
|
+
* // Formats for dates only
|
|
181
|
+
* date: { dateStyle: 'medium' },
|
|
182
|
+
* shortDate: { dateStyle: 'short' },
|
|
183
|
+
* mediumDate: { dateStyle: 'medium' },
|
|
184
|
+
* longDate: { dateStyle: 'long' },
|
|
185
|
+
* fullDate: { dateStyle: 'full' },
|
|
186
|
+
*
|
|
187
|
+
* // Formats for times only
|
|
188
|
+
* time: { timeStyle: 'medium' },
|
|
189
|
+
* shortTime: { timeStyle: 'short' },
|
|
190
|
+
* mediumTime: { timeStyle: 'medium' },
|
|
191
|
+
* longTime: { timeStyle: 'long' },
|
|
192
|
+
* fullTime: { timeStyle: 'full' },
|
|
193
|
+
* }
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export interface DateTimeFormats {
|
|
197
|
+
readonly [ key: string ]: Intl.DateTimeFormatOptions
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Options to initialize the number format _aliases_ used by the translation
|
|
202
|
+
* system.
|
|
203
|
+
*
|
|
204
|
+
* The default aliases (each can be overridden) are:
|
|
205
|
+
*
|
|
206
|
+
* ```ts
|
|
207
|
+
* {
|
|
208
|
+
* default: { }, // use the default number format
|
|
209
|
+
* EUR: { style: 'currency', currency: 'EUR' },
|
|
210
|
+
* USD: { style: 'currency', currency: 'USD' },
|
|
211
|
+
* // ... codes from ISO_CURRENCIES are available as aliases
|
|
212
|
+
* }
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
export interface NumberFormats {
|
|
216
|
+
readonly [ key: string ]: Intl.NumberFormatOptions
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** The initial language or locale; only its language and region are retained. */
|
|
220
|
+
export type DefaultLanguage = ISOLanguage | `${ISOLanguage}-${string}` | Intl.Locale
|
|
221
|
+
|
|
222
|
+
/** Options to initialize the I18n plugin */
|
|
223
|
+
export interface I18nOptions {
|
|
224
|
+
defaultLanguage: DefaultLanguage,
|
|
225
|
+
defaultTimeZone?: string,
|
|
226
|
+
translations?: Translations,
|
|
227
|
+
dateTimeFormats?: DateTimeFormats,
|
|
228
|
+
numberFormats?: NumberFormats,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* ===== PUBLIC METHODS ===================================================== */
|
|
232
|
+
|
|
233
|
+
/** Symbol for Vue injections */
|
|
234
|
+
const injectionSymbol = Symbol.for('@juit/vue-i18n/translator')
|
|
235
|
+
|
|
236
|
+
/** Initialize the translation system plugin */
|
|
237
|
+
export function i18n(app: App, optionsOrLanguage: Language | I18nOptions): App {
|
|
238
|
+
const options = typeof optionsOrLanguage === 'string' ?
|
|
239
|
+
{ defaultLanguage: optionsOrLanguage } : optionsOrLanguage
|
|
240
|
+
|
|
241
|
+
const translator = makeTranslator(options)
|
|
242
|
+
|
|
243
|
+
app.config.globalProperties.$t = translator.t
|
|
244
|
+
app.config.globalProperties.$tc = translator.tc
|
|
245
|
+
app.config.globalProperties.$n = translator.n
|
|
246
|
+
app.config.globalProperties.$d = translator.d
|
|
247
|
+
|
|
248
|
+
app.provide(injectionSymbol, translator)
|
|
249
|
+
return app
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Retrieve the translator from the current Vue injection context, or throw if none is provided. */
|
|
253
|
+
export function useTranslator(): Translator {
|
|
254
|
+
const translator = inject(injectionSymbol)
|
|
255
|
+
if (! translator) throw new Error('No translator found in the Vue app')
|
|
256
|
+
return translator as Translator
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* ===== VUE EXTENSIONS ===================================================== */
|
|
260
|
+
|
|
261
|
+
// Extension to the Vue component interface
|
|
262
|
+
declare module 'vue' {
|
|
263
|
+
interface ComponentCustomProperties {
|
|
264
|
+
/** Translate a message according to the current language */
|
|
265
|
+
$t: Translator['t']
|
|
266
|
+
/**
|
|
267
|
+
* Return the (possibly parameterized) translation for the specified message
|
|
268
|
+
* in the current language, with pluralization.
|
|
269
|
+
*/
|
|
270
|
+
$tc: Translator['tc']
|
|
271
|
+
/** Format a number into a string according to the current locale. */
|
|
272
|
+
$n: Translator['n']
|
|
273
|
+
/**
|
|
274
|
+
* Format a date and time using the current locale and the specified
|
|
275
|
+
* format, or the configurable `default` alias when omitted.
|
|
276
|
+
*/
|
|
277
|
+
$d: Translator['d']
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* ===== UTILITIES ========================================================== */
|
|
282
|
+
|
|
283
|
+
function normalizeLanguage(language: unknown): ISOLanguage | undefined {
|
|
284
|
+
if (typeof language !== 'string') return undefined
|
|
285
|
+
|
|
286
|
+
const normalized = language.toLowerCase().split(/[-_]/)[0]
|
|
287
|
+
if (! normalized) return undefined // empty after normalization
|
|
288
|
+
|
|
289
|
+
return isISOLanguage(normalized) ? normalized : undefined
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
interface LanguageMatcherConstructor {
|
|
293
|
+
/**
|
|
294
|
+
* Create a new {@link LanguageMatcher} instance matching *only* the single
|
|
295
|
+
* language specified.
|
|
296
|
+
*
|
|
297
|
+
* At runtime, the input is normalized. If it does not resolve to a valid
|
|
298
|
+
* ISO language code, an error is thrown.
|
|
299
|
+
*/
|
|
300
|
+
new <L extends ISOLanguage>(availableLanguages: L): LanguageMatcher<[ L ]>
|
|
301
|
+
/**
|
|
302
|
+
* Create a new {@link LanguageMatcher} instance matching the specified set
|
|
303
|
+
* of available languages.
|
|
304
|
+
*
|
|
305
|
+
* Typed inputs must be valid ISO language codes. At runtime, inputs are
|
|
306
|
+
* normalized and invalid entries are filtered out. The resulting list is
|
|
307
|
+
* copied, so later changes to the input array do not affect the matcher.
|
|
308
|
+
*
|
|
309
|
+
* If no valid ISO languages are provided, an error will be thrown.
|
|
310
|
+
*/
|
|
311
|
+
new <const A extends readonly [ ISOLanguage, ...ISOLanguage[] ]>(availableLanguages: A): LanguageMatcher<A>
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* A language matcher that determines the best matching language from a set
|
|
316
|
+
* of available languages.
|
|
317
|
+
*/
|
|
318
|
+
export interface LanguageMatcher<T extends readonly [ ISOLanguage, ...ISOLanguage[] ]> {
|
|
319
|
+
/** The list of available languages, with the first one being the default */
|
|
320
|
+
readonly availableLanguages: Readonly<T>
|
|
321
|
+
/** The default language */
|
|
322
|
+
readonly defaultLanguage: T[0]
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Determine the best matching language from the available languages.
|
|
326
|
+
*
|
|
327
|
+
* The first supported language in the input preference order is returned.
|
|
328
|
+
* Empty input or an input with no matches returns the default language.
|
|
329
|
+
*
|
|
330
|
+
* All languages here will be *normalized* before matching (for example
|
|
331
|
+
* `en-US` will be normalized to `en`, and `JA` will be normalized to `ja`).
|
|
332
|
+
*
|
|
333
|
+
* @param languages The language or list of languages to match against the
|
|
334
|
+
* available languages.
|
|
335
|
+
* @returns The best matching language from the available languages, or the
|
|
336
|
+
* default language if no match is found.
|
|
337
|
+
*/
|
|
338
|
+
match(languages: readonly string[] | string | undefined | null): T[number]
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Implementation of the {@link LanguageMatcher} interface */
|
|
342
|
+
class LanguageMatcherImpl implements LanguageMatcher<readonly [ ISOLanguage, ...ISOLanguage[] ]> {
|
|
343
|
+
readonly availableLanguages: readonly [ ISOLanguage, ...ISOLanguage[] ]
|
|
344
|
+
readonly defaultLanguage: ISOLanguage
|
|
345
|
+
|
|
346
|
+
constructor(availableLanguages: ISOLanguage | readonly ISOLanguage[]) {
|
|
347
|
+
const languages = typeof availableLanguages === 'string' ?
|
|
348
|
+
[ availableLanguages ] : availableLanguages
|
|
349
|
+
|
|
350
|
+
const [ defaultLanguage, ...extraLanguages ] = languages
|
|
351
|
+
.map(normalizeLanguage) // Normalize each language, returning undefined for invalid entries.
|
|
352
|
+
.filter((language) => !! language) // Remove invalid entries.
|
|
353
|
+
|
|
354
|
+
if (!defaultLanguage) {
|
|
355
|
+
throw new Error(`At least one valid ISO language must be provided (${languages.join(', ')})`)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
this.defaultLanguage = defaultLanguage
|
|
359
|
+
this.availableLanguages = [ defaultLanguage, ...extraLanguages ]
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
match(languages: readonly string[] | string | undefined | null): ISOLanguage {
|
|
363
|
+
// Use the default when no preferences are supplied.
|
|
364
|
+
if (!languages) return this.defaultLanguage
|
|
365
|
+
|
|
366
|
+
// Normalize the input to an array of strings.
|
|
367
|
+
if (typeof languages === 'string') languages = [ languages ]
|
|
368
|
+
|
|
369
|
+
// Iterate over the provided languages in order of preference.
|
|
370
|
+
for (const language of languages) {
|
|
371
|
+
const normalized = normalizeLanguage(language)
|
|
372
|
+
if (! normalized) continue // empty after normalization
|
|
373
|
+
|
|
374
|
+
// Check if the normalized language is available. If so, we match!
|
|
375
|
+
if (this.availableLanguages.includes(normalized)) {
|
|
376
|
+
return normalized
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// None of the provided languages matched, so we return the default.
|
|
381
|
+
return this.defaultLanguage
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/** The {@link LanguageMatcher} constructor */
|
|
386
|
+
export const LanguageMatcher = LanguageMatcherImpl as LanguageMatcherConstructor
|
package/lib/iso-3166.ts
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/** Frozen, sorted ISO 3166-1 country codes, plus the CLDR code XK for Kosovo. */
|
|
2
|
+
export const ISO_COUNTRIES = Object.freeze([
|
|
3
|
+
...('ADAEAFAGAIALAMAOAQARASATAUAWAXAZBABBBDBEBFBGBHBIBJBLBMBNBOBQBRBSBTBVBW' +
|
|
4
|
+
'BYBZCACCCDCFCGCHCICKCLCMCNCOCRCUCVCWCXCYCZDEDJDKDMDODZECEEEGEHERESETFIFJFK' +
|
|
5
|
+
'FMFOFRGAGBGDGEGFGGGHGIGLGMGNGPGQGRGSGTGUGWGYHKHMHNHRHTHUIDIEILIMINIOIQIRIS' +
|
|
6
|
+
'ITJEJMJOJPKEKGKHKIKMKNKPKRKWKYKZLALBLCLILKLRLSLTLULVLYMAMCMDMEMFMGMHMKMLMM' +
|
|
7
|
+
'MNMOMPMQMRMSMTMUMVMWMXMYMZNANCNENFNGNINLNONPNRNUNZOMPAPEPFPGPHPKPLPMPNPRPS' +
|
|
8
|
+
'PTPWPYQARERORSRURWSASBSCSDSESGSHSISJSKSLSMSNSOSRSSSTSVSXSYSZTCTDTFTGTHTJTK' +
|
|
9
|
+
'TLTMTNTOTRTTTVTWTZUAUGUMUSUYUZVAVCVEVGVIVNVUWFWSXKYEYTZAZMZW').match(/../g)!,
|
|
10
|
+
].sort() as ISOCountry[])
|
|
11
|
+
|
|
12
|
+
/** Reference country codes and names, including the CLDR code XK for Kosovo. */
|
|
13
|
+
export type ISOCountries = {
|
|
14
|
+
AD: 'Andorra',
|
|
15
|
+
AE: 'United Arab Emirates',
|
|
16
|
+
AF: 'Afghanistan',
|
|
17
|
+
AG: 'Antigua and Barbuda',
|
|
18
|
+
AI: 'Anguilla',
|
|
19
|
+
AL: 'Albania',
|
|
20
|
+
AM: 'Armenia',
|
|
21
|
+
AO: 'Angola',
|
|
22
|
+
AQ: 'Antarctica',
|
|
23
|
+
AR: 'Argentina',
|
|
24
|
+
AS: 'American Samoa',
|
|
25
|
+
AT: 'Austria',
|
|
26
|
+
AU: 'Australia',
|
|
27
|
+
AW: 'Aruba',
|
|
28
|
+
AX: 'Åland Islands',
|
|
29
|
+
AZ: 'Azerbaijan',
|
|
30
|
+
BA: 'Bosnia and Herzegovina',
|
|
31
|
+
BB: 'Barbados',
|
|
32
|
+
BD: 'Bangladesh',
|
|
33
|
+
BE: 'Belgium',
|
|
34
|
+
BF: 'Burkina Faso',
|
|
35
|
+
BG: 'Bulgaria',
|
|
36
|
+
BH: 'Bahrain',
|
|
37
|
+
BI: 'Burundi',
|
|
38
|
+
BJ: 'Benin',
|
|
39
|
+
BL: 'Saint Barthélemy',
|
|
40
|
+
BM: 'Bermuda',
|
|
41
|
+
BN: 'Brunei Darussalam',
|
|
42
|
+
BO: 'Bolivia (Plurinational State of)',
|
|
43
|
+
BQ: 'Bonaire, Sint Eustatius and Saba',
|
|
44
|
+
BR: 'Brazil',
|
|
45
|
+
BS: 'Bahamas',
|
|
46
|
+
BT: 'Bhutan',
|
|
47
|
+
BV: 'Bouvet Island',
|
|
48
|
+
BW: 'Botswana',
|
|
49
|
+
BY: 'Belarus',
|
|
50
|
+
BZ: 'Belize',
|
|
51
|
+
CA: 'Canada',
|
|
52
|
+
CC: 'Cocos (Keeling) Islands',
|
|
53
|
+
CD: 'Congo (Democratic Republic of the)',
|
|
54
|
+
CF: 'Central African Republic',
|
|
55
|
+
CG: 'Congo',
|
|
56
|
+
CH: 'Switzerland',
|
|
57
|
+
CI: 'Côte d\'Ivoire',
|
|
58
|
+
CK: 'Cook Islands',
|
|
59
|
+
CL: 'Chile',
|
|
60
|
+
CM: 'Cameroon',
|
|
61
|
+
CN: 'China',
|
|
62
|
+
CO: 'Colombia',
|
|
63
|
+
CR: 'Costa Rica',
|
|
64
|
+
CU: 'Cuba',
|
|
65
|
+
CV: 'Cabo Verde',
|
|
66
|
+
CW: 'Curaçao',
|
|
67
|
+
CX: 'Christmas Island',
|
|
68
|
+
CY: 'Cyprus',
|
|
69
|
+
CZ: 'Czechia',
|
|
70
|
+
DE: 'Germany',
|
|
71
|
+
DJ: 'Djibouti',
|
|
72
|
+
DK: 'Denmark',
|
|
73
|
+
DM: 'Dominica',
|
|
74
|
+
DO: 'Dominican Republic',
|
|
75
|
+
DZ: 'Algeria',
|
|
76
|
+
EC: 'Ecuador',
|
|
77
|
+
EE: 'Estonia',
|
|
78
|
+
EG: 'Egypt',
|
|
79
|
+
EH: 'Western Sahara',
|
|
80
|
+
ER: 'Eritrea',
|
|
81
|
+
ES: 'Spain',
|
|
82
|
+
ET: 'Ethiopia',
|
|
83
|
+
FI: 'Finland',
|
|
84
|
+
FJ: 'Fiji',
|
|
85
|
+
FK: 'Falkland Islands (Malvinas)',
|
|
86
|
+
FM: 'Micronesia (Federated States of)',
|
|
87
|
+
FO: 'Faroe Islands',
|
|
88
|
+
FR: 'France',
|
|
89
|
+
GA: 'Gabon',
|
|
90
|
+
GB: 'United Kingdom of Great Britain and Northern Ireland',
|
|
91
|
+
GD: 'Grenada',
|
|
92
|
+
GE: 'Georgia',
|
|
93
|
+
GF: 'French Guiana',
|
|
94
|
+
GG: 'Guernsey',
|
|
95
|
+
GH: 'Ghana',
|
|
96
|
+
GI: 'Gibraltar',
|
|
97
|
+
GL: 'Greenland',
|
|
98
|
+
GM: 'Gambia',
|
|
99
|
+
GN: 'Guinea',
|
|
100
|
+
GP: 'Guadeloupe',
|
|
101
|
+
GQ: 'Equatorial Guinea',
|
|
102
|
+
GR: 'Greece',
|
|
103
|
+
GS: 'South Georgia and the South Sandwich Islands',
|
|
104
|
+
GT: 'Guatemala',
|
|
105
|
+
GU: 'Guam',
|
|
106
|
+
GW: 'Guinea-Bissau',
|
|
107
|
+
GY: 'Guyana',
|
|
108
|
+
HK: 'Hong Kong',
|
|
109
|
+
HM: 'Heard Island and McDonald Islands',
|
|
110
|
+
HN: 'Honduras',
|
|
111
|
+
HR: 'Croatia',
|
|
112
|
+
HT: 'Haiti',
|
|
113
|
+
HU: 'Hungary',
|
|
114
|
+
ID: 'Indonesia',
|
|
115
|
+
IE: 'Ireland',
|
|
116
|
+
IL: 'Israel',
|
|
117
|
+
IM: 'Isle of Man',
|
|
118
|
+
IN: 'India',
|
|
119
|
+
IO: 'British Indian Ocean Territory',
|
|
120
|
+
IQ: 'Iraq',
|
|
121
|
+
IR: 'Iran (Islamic Republic of)',
|
|
122
|
+
IS: 'Iceland',
|
|
123
|
+
IT: 'Italy',
|
|
124
|
+
JE: 'Jersey',
|
|
125
|
+
JM: 'Jamaica',
|
|
126
|
+
JO: 'Jordan',
|
|
127
|
+
JP: 'Japan',
|
|
128
|
+
KE: 'Kenya',
|
|
129
|
+
KG: 'Kyrgyzstan',
|
|
130
|
+
KH: 'Cambodia',
|
|
131
|
+
KI: 'Kiribati',
|
|
132
|
+
KM: 'Comoros',
|
|
133
|
+
KN: 'Saint Kitts and Nevis',
|
|
134
|
+
KP: 'Korea (Democratic People\'s Republic of)',
|
|
135
|
+
KR: 'Korea (Republic of)',
|
|
136
|
+
KW: 'Kuwait',
|
|
137
|
+
KY: 'Cayman Islands',
|
|
138
|
+
KZ: 'Kazakhstan',
|
|
139
|
+
LA: 'Lao People\'s Democratic Republic',
|
|
140
|
+
LB: 'Lebanon',
|
|
141
|
+
LC: 'Saint Lucia',
|
|
142
|
+
LI: 'Liechtenstein',
|
|
143
|
+
LK: 'Sri Lanka',
|
|
144
|
+
LR: 'Liberia',
|
|
145
|
+
LS: 'Lesotho',
|
|
146
|
+
LT: 'Lithuania',
|
|
147
|
+
LU: 'Luxembourg',
|
|
148
|
+
LV: 'Latvia',
|
|
149
|
+
LY: 'Libya',
|
|
150
|
+
MA: 'Morocco',
|
|
151
|
+
MC: 'Monaco',
|
|
152
|
+
MD: 'Moldova (Republic of)',
|
|
153
|
+
ME: 'Montenegro',
|
|
154
|
+
MF: 'Saint Martin (French part)',
|
|
155
|
+
MG: 'Madagascar',
|
|
156
|
+
MH: 'Marshall Islands',
|
|
157
|
+
MK: 'Macedonia (the former Yugoslav Republic of)',
|
|
158
|
+
ML: 'Mali',
|
|
159
|
+
MM: 'Myanmar',
|
|
160
|
+
MN: 'Mongolia',
|
|
161
|
+
MO: 'Macao',
|
|
162
|
+
MP: 'Northern Mariana Islands',
|
|
163
|
+
MQ: 'Martinique',
|
|
164
|
+
MR: 'Mauritania',
|
|
165
|
+
MS: 'Montserrat',
|
|
166
|
+
MT: 'Malta',
|
|
167
|
+
MU: 'Mauritius',
|
|
168
|
+
MV: 'Maldives',
|
|
169
|
+
MW: 'Malawi',
|
|
170
|
+
MX: 'Mexico',
|
|
171
|
+
MY: 'Malaysia',
|
|
172
|
+
MZ: 'Mozambique',
|
|
173
|
+
NA: 'Namibia',
|
|
174
|
+
NC: 'New Caledonia',
|
|
175
|
+
NE: 'Niger',
|
|
176
|
+
NF: 'Norfolk Island',
|
|
177
|
+
NG: 'Nigeria',
|
|
178
|
+
NI: 'Nicaragua',
|
|
179
|
+
NL: 'Netherlands',
|
|
180
|
+
NO: 'Norway',
|
|
181
|
+
NP: 'Nepal',
|
|
182
|
+
NR: 'Nauru',
|
|
183
|
+
NU: 'Niue',
|
|
184
|
+
NZ: 'New Zealand',
|
|
185
|
+
OM: 'Oman',
|
|
186
|
+
PA: 'Panama',
|
|
187
|
+
PE: 'Peru',
|
|
188
|
+
PF: 'French Polynesia',
|
|
189
|
+
PG: 'Papua New Guinea',
|
|
190
|
+
PH: 'Philippines',
|
|
191
|
+
PK: 'Pakistan',
|
|
192
|
+
PL: 'Poland',
|
|
193
|
+
PM: 'Saint Pierre and Miquelon',
|
|
194
|
+
PN: 'Pitcairn',
|
|
195
|
+
PR: 'Puerto Rico',
|
|
196
|
+
PS: 'Palestine, State of',
|
|
197
|
+
PT: 'Portugal',
|
|
198
|
+
PW: 'Palau',
|
|
199
|
+
PY: 'Paraguay',
|
|
200
|
+
QA: 'Qatar',
|
|
201
|
+
RE: 'Réunion',
|
|
202
|
+
RO: 'Romania',
|
|
203
|
+
RS: 'Serbia',
|
|
204
|
+
RU: 'Russian Federation',
|
|
205
|
+
RW: 'Rwanda',
|
|
206
|
+
SA: 'Saudi Arabia',
|
|
207
|
+
SB: 'Solomon Islands',
|
|
208
|
+
SC: 'Seychelles',
|
|
209
|
+
SD: 'Sudan',
|
|
210
|
+
SE: 'Sweden',
|
|
211
|
+
SG: 'Singapore',
|
|
212
|
+
SH: 'Saint Helena, Ascension and Tristan da Cunha',
|
|
213
|
+
SI: 'Slovenia',
|
|
214
|
+
SJ: 'Svalbard and Jan Mayen',
|
|
215
|
+
SK: 'Slovakia',
|
|
216
|
+
SL: 'Sierra Leone',
|
|
217
|
+
SM: 'San Marino',
|
|
218
|
+
SN: 'Senegal',
|
|
219
|
+
SO: 'Somalia',
|
|
220
|
+
SR: 'Suriname',
|
|
221
|
+
SS: 'South Sudan',
|
|
222
|
+
ST: 'Sao Tome and Principe',
|
|
223
|
+
SV: 'El Salvador',
|
|
224
|
+
SX: 'Sint Maarten (Dutch part)',
|
|
225
|
+
SY: 'Syrian Arab Republic',
|
|
226
|
+
SZ: 'Swaziland',
|
|
227
|
+
TC: 'Turks and Caicos Islands',
|
|
228
|
+
TD: 'Chad',
|
|
229
|
+
TF: 'French Southern Territories',
|
|
230
|
+
TG: 'Togo',
|
|
231
|
+
TH: 'Thailand',
|
|
232
|
+
TJ: 'Tajikistan',
|
|
233
|
+
TK: 'Tokelau',
|
|
234
|
+
TL: 'Timor-Leste',
|
|
235
|
+
TM: 'Turkmenistan',
|
|
236
|
+
TN: 'Tunisia',
|
|
237
|
+
TO: 'Tonga',
|
|
238
|
+
TR: 'Turkey',
|
|
239
|
+
TT: 'Trinidad and Tobago',
|
|
240
|
+
TV: 'Tuvalu',
|
|
241
|
+
TW: 'Taiwan, Province of China[a]',
|
|
242
|
+
TZ: 'Tanzania, United Republic of',
|
|
243
|
+
UA: 'Ukraine',
|
|
244
|
+
UG: 'Uganda',
|
|
245
|
+
UM: 'United States Minor Outlying Islands',
|
|
246
|
+
US: 'United States of America',
|
|
247
|
+
UY: 'Uruguay',
|
|
248
|
+
UZ: 'Uzbekistan',
|
|
249
|
+
VA: 'Holy See',
|
|
250
|
+
VC: 'Saint Vincent and the Grenadines',
|
|
251
|
+
VE: 'Venezuela (Bolivarian Republic of)',
|
|
252
|
+
VG: 'Virgin Islands (British)',
|
|
253
|
+
VI: 'Virgin Islands (U.S.)',
|
|
254
|
+
VN: 'Viet Nam',
|
|
255
|
+
VU: 'Vanuatu',
|
|
256
|
+
WF: 'Wallis and Futuna',
|
|
257
|
+
WS: 'Samoa',
|
|
258
|
+
XK: 'Kosovo', // CLDR code, not an officially assigned ISO 3166-1 code.
|
|
259
|
+
YE: 'Yemen',
|
|
260
|
+
YT: 'Mayotte',
|
|
261
|
+
ZA: 'South Africa',
|
|
262
|
+
ZM: 'Zambia',
|
|
263
|
+
ZW: 'Zimbabwe',
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Country code union derived from the reference table, including XK. */
|
|
267
|
+
export type ISOCountry = keyof ISOCountries
|
|
268
|
+
|
|
269
|
+
/** Check whether a value is a country code in ISO_COUNTRIES, including XK. */
|
|
270
|
+
export function isISOCountry(value: unknown): value is ISOCountry {
|
|
271
|
+
return ISO_COUNTRIES.includes(value as ISOCountry)
|
|
272
|
+
}
|