@mailwoman/codex 7.2.0 → 7.2.1
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/address-system-conventions.ts +68 -0
- package/au/delivery-service.ts +179 -0
- package/au/index.ts +15 -0
- package/au/level-designator.ts +209 -0
- package/au/postcode.ts +51 -0
- package/au/state.ts +35 -0
- package/ca/index.ts +12 -0
- package/ca/postal-code.ts +121 -0
- package/ca/province.ts +99 -0
- package/ca/street-type.ts +167 -0
- package/country/codes.ts +534 -0
- package/country/country.ts +125 -0
- package/country/index.ts +14 -0
- package/country/names.ts +274 -0
- package/country/official-languages.ts +397 -0
- package/country/reference-data.ts +267 -0
- package/country/reference.ts +47 -0
- package/de/bundesland.ts +102 -0
- package/de/index.ts +12 -0
- package/de/postleitzahl.ts +91 -0
- package/de/street-type.ts +83 -0
- package/fr/cedex.ts +56 -0
- package/fr/code-postal.ts +105 -0
- package/fr/departement.ts +142 -0
- package/fr/index.ts +14 -0
- package/fr/region.ts +93 -0
- package/fr/voie.ts +98 -0
- package/gb/country.ts +74 -0
- package/gb/index.ts +14 -0
- package/gb/postcode-area.ts +107 -0
- package/gb/postcode.ts +109 -0
- package/gb/street-type.ts +90 -0
- package/index.ts +38 -0
- package/jp/address-unit.ts +87 -0
- package/jp/index.ts +13 -0
- package/jp/postal-code.ts +93 -0
- package/jp/prefecture.ts +173 -0
- package/level-semantics.ts +623 -0
- package/nz/delivery-service.ts +211 -0
- package/nz/index.ts +12 -0
- package/nz/postcode.ts +42 -0
- package/package.json +81 -37
- package/postcode-systems.ts +68 -0
- package/tools/build-country-surface-lexicon.ts +166 -0
- package/tools/export-country-surfaces.ts +46 -0
- package/tools/generate-country-reference.ts +153 -0
- package/tools/generate-official-languages.ts +188 -0
- package/tools/index.ts +12 -0
- package/us/floor-designator.ts +119 -0
- package/us/index.ts +19 -0
- package/us/military-address.ts +199 -0
- package/us/po-box.ts +82 -0
- package/us/state.ts +156 -0
- package/us/street-directional.ts +220 -0
- package/us/street-suffix.ts +345 -0
- package/us/unit-designator.ts +223 -0
- package/us/zipcode.ts +212 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* GENERATED — do not edit by hand. Country calling codes (E.164) + currencies (ISO 4217), derived
|
|
7
|
+
* from mledoze/countries (https://github.com/mledoze/countries, ODbL). NANP members map to 1.
|
|
8
|
+
* Regenerate with: mailwoman dev generate country-reference
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Static per-country reference: calling code + currency. */
|
|
12
|
+
export interface CountryReference {
|
|
13
|
+
callingCode?: number
|
|
14
|
+
currency?: { isoCode: string; name?: string; symbol?: string }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** ISO 3166-1 alpha-2 → reference. */
|
|
18
|
+
export const COUNTRY_REFERENCE: Record<string, CountryReference> = {
|
|
19
|
+
AD: { callingCode: 376, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
20
|
+
AE: { callingCode: 971, currency: { isoCode: "AED", name: "United Arab Emirates dirham", symbol: "د.إ" } },
|
|
21
|
+
AF: { callingCode: 93, currency: { isoCode: "AFN", name: "Afghan afghani", symbol: "؋" } },
|
|
22
|
+
AG: { callingCode: 1, currency: { isoCode: "XCD", name: "Eastern Caribbean dollar", symbol: "$" } },
|
|
23
|
+
AI: { callingCode: 1, currency: { isoCode: "XCD", name: "Eastern Caribbean dollar", symbol: "$" } },
|
|
24
|
+
AL: { callingCode: 355, currency: { isoCode: "ALL", name: "Albanian lek", symbol: "L" } },
|
|
25
|
+
AM: { callingCode: 374, currency: { isoCode: "AMD", name: "Armenian dram", symbol: "֏" } },
|
|
26
|
+
AO: { callingCode: 244, currency: { isoCode: "AOA", name: "Angolan kwanza", symbol: "Kz" } },
|
|
27
|
+
AR: { callingCode: 54, currency: { isoCode: "ARS", name: "Argentine peso", symbol: "$" } },
|
|
28
|
+
AS: { callingCode: 1, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
29
|
+
AT: { callingCode: 43, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
30
|
+
AU: { callingCode: 61, currency: { isoCode: "AUD", name: "Australian dollar", symbol: "$" } },
|
|
31
|
+
AW: { callingCode: 297, currency: { isoCode: "AWG", name: "Aruban florin", symbol: "ƒ" } },
|
|
32
|
+
AX: { callingCode: 35818, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
33
|
+
AZ: { callingCode: 994, currency: { isoCode: "AZN", name: "Azerbaijani manat", symbol: "₼" } },
|
|
34
|
+
BA: { callingCode: 387, currency: { isoCode: "BAM", name: "Bosnia and Herzegovina convertible mark", symbol: "KM" } },
|
|
35
|
+
BB: { callingCode: 1, currency: { isoCode: "BBD", name: "Barbadian dollar", symbol: "$" } },
|
|
36
|
+
BD: { callingCode: 880, currency: { isoCode: "BDT", name: "Bangladeshi taka", symbol: "৳" } },
|
|
37
|
+
BE: { callingCode: 32, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
38
|
+
BF: { callingCode: 226, currency: { isoCode: "XOF", name: "West African CFA franc", symbol: "Fr" } },
|
|
39
|
+
BG: { callingCode: 359, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
40
|
+
BH: { callingCode: 973, currency: { isoCode: "BHD", name: "Bahraini dinar", symbol: ".د.ب" } },
|
|
41
|
+
BI: { callingCode: 257, currency: { isoCode: "BIF", name: "Burundian franc", symbol: "Fr" } },
|
|
42
|
+
BJ: { callingCode: 229, currency: { isoCode: "XOF", name: "West African CFA franc", symbol: "Fr" } },
|
|
43
|
+
BL: { callingCode: 590, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
44
|
+
BM: { callingCode: 1, currency: { isoCode: "BMD", name: "Bermudian dollar", symbol: "$" } },
|
|
45
|
+
BN: { callingCode: 673, currency: { isoCode: "BND", name: "Brunei dollar", symbol: "$" } },
|
|
46
|
+
BO: { callingCode: 591, currency: { isoCode: "BOB", name: "Bolivian boliviano", symbol: "Bs." } },
|
|
47
|
+
BQ: { callingCode: 599, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
48
|
+
BR: { callingCode: 55, currency: { isoCode: "BRL", name: "Brazilian real", symbol: "R$" } },
|
|
49
|
+
BS: { callingCode: 1, currency: { isoCode: "BSD", name: "Bahamian dollar", symbol: "$" } },
|
|
50
|
+
BT: { callingCode: 975, currency: { isoCode: "BTN", name: "Bhutanese ngultrum", symbol: "Nu." } },
|
|
51
|
+
BV: { callingCode: 47 },
|
|
52
|
+
BW: { callingCode: 267, currency: { isoCode: "BWP", name: "Botswana pula", symbol: "P" } },
|
|
53
|
+
BY: { callingCode: 375, currency: { isoCode: "BYN", name: "Belarusian ruble", symbol: "Br" } },
|
|
54
|
+
BZ: { callingCode: 501, currency: { isoCode: "BZD", name: "Belize dollar", symbol: "$" } },
|
|
55
|
+
CA: { callingCode: 1, currency: { isoCode: "CAD", name: "Canadian dollar", symbol: "$" } },
|
|
56
|
+
CC: { callingCode: 61, currency: { isoCode: "AUD", name: "Australian dollar", symbol: "$" } },
|
|
57
|
+
CD: { callingCode: 243, currency: { isoCode: "CDF", name: "Congolese franc", symbol: "FC" } },
|
|
58
|
+
CF: { callingCode: 236, currency: { isoCode: "XAF", name: "Central African CFA franc", symbol: "Fr" } },
|
|
59
|
+
CG: { callingCode: 242, currency: { isoCode: "XAF", name: "Central African CFA franc", symbol: "Fr" } },
|
|
60
|
+
CH: { callingCode: 41, currency: { isoCode: "CHF", name: "Swiss franc", symbol: "Fr." } },
|
|
61
|
+
CI: { callingCode: 225, currency: { isoCode: "XOF", name: "West African CFA franc", symbol: "Fr" } },
|
|
62
|
+
CK: { callingCode: 682, currency: { isoCode: "CKD", name: "Cook Islands dollar", symbol: "$" } },
|
|
63
|
+
CL: { callingCode: 56, currency: { isoCode: "CLP", name: "Chilean peso", symbol: "$" } },
|
|
64
|
+
CM: { callingCode: 237, currency: { isoCode: "XAF", name: "Central African CFA franc", symbol: "Fr" } },
|
|
65
|
+
CN: { callingCode: 86, currency: { isoCode: "CNY", name: "Chinese yuan", symbol: "¥" } },
|
|
66
|
+
CO: { callingCode: 57, currency: { isoCode: "COP", name: "Colombian peso", symbol: "$" } },
|
|
67
|
+
CR: { callingCode: 506, currency: { isoCode: "CRC", name: "Costa Rican colón", symbol: "₡" } },
|
|
68
|
+
CU: { callingCode: 53, currency: { isoCode: "CUC", name: "Cuban convertible peso", symbol: "$" } },
|
|
69
|
+
CV: { callingCode: 238, currency: { isoCode: "CVE", name: "Cape Verdean escudo", symbol: "Esc" } },
|
|
70
|
+
CW: { callingCode: 599, currency: { isoCode: "ANG", name: "Netherlands Antillean guilder", symbol: "ƒ" } },
|
|
71
|
+
CX: { callingCode: 61, currency: { isoCode: "AUD", name: "Australian dollar", symbol: "$" } },
|
|
72
|
+
CY: { callingCode: 357, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
73
|
+
CZ: { callingCode: 420, currency: { isoCode: "CZK", name: "Czech koruna", symbol: "Kč" } },
|
|
74
|
+
DE: { callingCode: 49, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
75
|
+
DJ: { callingCode: 253, currency: { isoCode: "DJF", name: "Djiboutian franc", symbol: "Fr" } },
|
|
76
|
+
DK: { callingCode: 45, currency: { isoCode: "DKK", name: "Danish krone", symbol: "kr" } },
|
|
77
|
+
DM: { callingCode: 1, currency: { isoCode: "XCD", name: "Eastern Caribbean dollar", symbol: "$" } },
|
|
78
|
+
DO: { callingCode: 1, currency: { isoCode: "DOP", name: "Dominican peso", symbol: "$" } },
|
|
79
|
+
DZ: { callingCode: 213, currency: { isoCode: "DZD", name: "Algerian dinar", symbol: "د.ج" } },
|
|
80
|
+
EC: { callingCode: 593, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
81
|
+
EE: { callingCode: 372, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
82
|
+
EG: { callingCode: 20, currency: { isoCode: "EGP", name: "Egyptian pound", symbol: "£" } },
|
|
83
|
+
EH: { callingCode: 2, currency: { isoCode: "DZD", name: "Algerian dinar", symbol: "دج" } },
|
|
84
|
+
ER: { callingCode: 291, currency: { isoCode: "ERN", name: "Eritrean nakfa", symbol: "Nfk" } },
|
|
85
|
+
ES: { callingCode: 34, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
86
|
+
ET: { callingCode: 251, currency: { isoCode: "ETB", name: "Ethiopian birr", symbol: "Br" } },
|
|
87
|
+
FI: { callingCode: 358, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
88
|
+
FJ: { callingCode: 679, currency: { isoCode: "FJD", name: "Fijian dollar", symbol: "$" } },
|
|
89
|
+
FK: { callingCode: 500, currency: { isoCode: "FKP", name: "Falkland Islands pound", symbol: "£" } },
|
|
90
|
+
FM: { callingCode: 691 },
|
|
91
|
+
FO: { callingCode: 298, currency: { isoCode: "DKK", name: "Danish krone", symbol: "kr" } },
|
|
92
|
+
FR: { callingCode: 33, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
93
|
+
GA: { callingCode: 241, currency: { isoCode: "XAF", name: "Central African CFA franc", symbol: "Fr" } },
|
|
94
|
+
GB: { callingCode: 44, currency: { isoCode: "GBP", name: "British pound", symbol: "£" } },
|
|
95
|
+
GD: { callingCode: 1, currency: { isoCode: "XCD", name: "Eastern Caribbean dollar", symbol: "$" } },
|
|
96
|
+
GE: { callingCode: 995, currency: { isoCode: "GEL", name: "lari", symbol: "₾" } },
|
|
97
|
+
GF: { callingCode: 594, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
98
|
+
GG: { callingCode: 44, currency: { isoCode: "GBP", name: "British pound", symbol: "£" } },
|
|
99
|
+
GH: { callingCode: 233, currency: { isoCode: "GHS", name: "Ghanaian cedi", symbol: "₵" } },
|
|
100
|
+
GI: { callingCode: 350, currency: { isoCode: "GIP", name: "Gibraltar pound", symbol: "£" } },
|
|
101
|
+
GL: { callingCode: 299, currency: { isoCode: "DKK", name: "krone", symbol: "kr." } },
|
|
102
|
+
GM: { callingCode: 220, currency: { isoCode: "GMD", name: "dalasi", symbol: "D" } },
|
|
103
|
+
GN: { callingCode: 224, currency: { isoCode: "GNF", name: "Guinean franc", symbol: "Fr" } },
|
|
104
|
+
GP: { callingCode: 590, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
105
|
+
GQ: { callingCode: 240, currency: { isoCode: "XAF", name: "Central African CFA franc", symbol: "Fr" } },
|
|
106
|
+
GR: { callingCode: 30, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
107
|
+
GS: { callingCode: 500, currency: { isoCode: "SHP", name: "Saint Helena pound", symbol: "£" } },
|
|
108
|
+
GT: { callingCode: 502, currency: { isoCode: "GTQ", name: "Guatemalan quetzal", symbol: "Q" } },
|
|
109
|
+
GU: { callingCode: 1, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
110
|
+
GW: { callingCode: 245, currency: { isoCode: "XOF", name: "West African CFA franc", symbol: "Fr" } },
|
|
111
|
+
GY: { callingCode: 592, currency: { isoCode: "GYD", name: "Guyanese dollar", symbol: "$" } },
|
|
112
|
+
HK: { callingCode: 852, currency: { isoCode: "HKD", name: "Hong Kong dollar", symbol: "$" } },
|
|
113
|
+
HN: { callingCode: 504, currency: { isoCode: "HNL", name: "Honduran lempira", symbol: "L" } },
|
|
114
|
+
HR: { callingCode: 385, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
115
|
+
HT: { callingCode: 509, currency: { isoCode: "HTG", name: "Haitian gourde", symbol: "G" } },
|
|
116
|
+
HU: { callingCode: 36, currency: { isoCode: "HUF", name: "Hungarian forint", symbol: "Ft" } },
|
|
117
|
+
ID: { callingCode: 62, currency: { isoCode: "IDR", name: "Indonesian rupiah", symbol: "Rp" } },
|
|
118
|
+
IE: { callingCode: 353, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
119
|
+
IL: { callingCode: 972, currency: { isoCode: "ILS", name: "Israeli new shekel", symbol: "₪" } },
|
|
120
|
+
IM: { callingCode: 44, currency: { isoCode: "GBP", name: "British pound", symbol: "£" } },
|
|
121
|
+
IN: { callingCode: 91, currency: { isoCode: "INR", name: "Indian rupee", symbol: "₹" } },
|
|
122
|
+
IO: { callingCode: 246, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
123
|
+
IQ: { callingCode: 964, currency: { isoCode: "IQD", name: "Iraqi dinar", symbol: "ع.د" } },
|
|
124
|
+
IR: { callingCode: 98, currency: { isoCode: "IRR", name: "Iranian rial", symbol: "﷼" } },
|
|
125
|
+
IS: { callingCode: 354, currency: { isoCode: "ISK", name: "Icelandic króna", symbol: "kr" } },
|
|
126
|
+
IT: { callingCode: 39, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
127
|
+
JE: { callingCode: 44, currency: { isoCode: "GBP", name: "British pound", symbol: "£" } },
|
|
128
|
+
JM: { callingCode: 1, currency: { isoCode: "JMD", name: "Jamaican dollar", symbol: "$" } },
|
|
129
|
+
JO: { callingCode: 962, currency: { isoCode: "JOD", name: "Jordanian dinar", symbol: "د.ا" } },
|
|
130
|
+
JP: { callingCode: 81, currency: { isoCode: "JPY", name: "Japanese yen", symbol: "¥" } },
|
|
131
|
+
KE: { callingCode: 254, currency: { isoCode: "KES", name: "Kenyan shilling", symbol: "Sh" } },
|
|
132
|
+
KG: { callingCode: 996, currency: { isoCode: "KGS", name: "Kyrgyzstani som", symbol: "с" } },
|
|
133
|
+
KH: { callingCode: 855, currency: { isoCode: "KHR", name: "Cambodian riel", symbol: "៛" } },
|
|
134
|
+
KI: { callingCode: 686, currency: { isoCode: "AUD", name: "Australian dollar", symbol: "$" } },
|
|
135
|
+
KM: { callingCode: 269, currency: { isoCode: "KMF", name: "Comorian franc", symbol: "Fr" } },
|
|
136
|
+
KN: { callingCode: 1, currency: { isoCode: "XCD", name: "Eastern Caribbean dollar", symbol: "$" } },
|
|
137
|
+
KP: { callingCode: 850, currency: { isoCode: "KPW", name: "North Korean won", symbol: "₩" } },
|
|
138
|
+
KR: { callingCode: 82, currency: { isoCode: "KRW", name: "South Korean won", symbol: "₩" } },
|
|
139
|
+
KW: { callingCode: 965, currency: { isoCode: "KWD", name: "Kuwaiti dinar", symbol: "د.ك" } },
|
|
140
|
+
KY: { callingCode: 1, currency: { isoCode: "KYD", name: "Cayman Islands dollar", symbol: "$" } },
|
|
141
|
+
KZ: { callingCode: 7, currency: { isoCode: "KZT", name: "Kazakhstani tenge", symbol: "₸" } },
|
|
142
|
+
LA: { callingCode: 856, currency: { isoCode: "LAK", name: "Lao kip", symbol: "₭" } },
|
|
143
|
+
LB: { callingCode: 961, currency: { isoCode: "LBP", name: "Lebanese pound", symbol: "ل.ل" } },
|
|
144
|
+
LC: { callingCode: 1, currency: { isoCode: "XCD", name: "Eastern Caribbean dollar", symbol: "$" } },
|
|
145
|
+
LI: { callingCode: 423, currency: { isoCode: "CHF", name: "Swiss franc", symbol: "Fr" } },
|
|
146
|
+
LK: { callingCode: 94, currency: { isoCode: "LKR", name: "Sri Lankan rupee", symbol: "Rs රු" } },
|
|
147
|
+
LR: { callingCode: 231, currency: { isoCode: "LRD", name: "Liberian dollar", symbol: "$" } },
|
|
148
|
+
LS: { callingCode: 266, currency: { isoCode: "LSL", name: "Lesotho loti", symbol: "L" } },
|
|
149
|
+
LT: { callingCode: 370, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
150
|
+
LU: { callingCode: 352, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
151
|
+
LV: { callingCode: 371, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
152
|
+
LY: { callingCode: 218, currency: { isoCode: "LYD", name: "Libyan dinar", symbol: "ل.د" } },
|
|
153
|
+
MA: { callingCode: 212, currency: { isoCode: "MAD", name: "Moroccan dirham", symbol: "د.م." } },
|
|
154
|
+
MC: { callingCode: 377, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
155
|
+
MD: { callingCode: 373, currency: { isoCode: "MDL", name: "Moldovan leu", symbol: "L" } },
|
|
156
|
+
ME: { callingCode: 382, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
157
|
+
MF: { callingCode: 590, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
158
|
+
MG: { callingCode: 261, currency: { isoCode: "MGA", name: "Malagasy ariary", symbol: "Ar" } },
|
|
159
|
+
MH: { callingCode: 692, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
160
|
+
MK: { callingCode: 389, currency: { isoCode: "MKD", name: "denar", symbol: "den" } },
|
|
161
|
+
ML: { callingCode: 223, currency: { isoCode: "XOF", name: "West African CFA franc", symbol: "Fr" } },
|
|
162
|
+
MM: { callingCode: 95, currency: { isoCode: "MMK", name: "Burmese kyat", symbol: "Ks" } },
|
|
163
|
+
MN: { callingCode: 976, currency: { isoCode: "MNT", name: "Mongolian tögrög", symbol: "₮" } },
|
|
164
|
+
MO: { callingCode: 853, currency: { isoCode: "MOP", name: "Macanese pataca", symbol: "P" } },
|
|
165
|
+
MP: { callingCode: 1, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
166
|
+
MQ: { callingCode: 596, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
167
|
+
MR: { callingCode: 222, currency: { isoCode: "MRU", name: "Mauritanian ouguiya", symbol: "UM" } },
|
|
168
|
+
MS: { callingCode: 1, currency: { isoCode: "XCD", name: "Eastern Caribbean dollar", symbol: "$" } },
|
|
169
|
+
MT: { callingCode: 356, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
170
|
+
MU: { callingCode: 230, currency: { isoCode: "MUR", name: "Mauritian rupee", symbol: "₨" } },
|
|
171
|
+
MV: { callingCode: 960, currency: { isoCode: "MVR", name: "Maldivian rufiyaa", symbol: ".ރ" } },
|
|
172
|
+
MW: { callingCode: 265, currency: { isoCode: "MWK", name: "Malawian kwacha", symbol: "MK" } },
|
|
173
|
+
MX: { callingCode: 52, currency: { isoCode: "MXN", name: "Mexican peso", symbol: "$" } },
|
|
174
|
+
MY: { callingCode: 60, currency: { isoCode: "MYR", name: "Malaysian ringgit", symbol: "RM" } },
|
|
175
|
+
MZ: { callingCode: 258, currency: { isoCode: "MZN", name: "Mozambican metical", symbol: "MT" } },
|
|
176
|
+
NA: { callingCode: 264, currency: { isoCode: "NAD", name: "Namibian dollar", symbol: "$" } },
|
|
177
|
+
NC: { callingCode: 687, currency: { isoCode: "XPF", name: "CFP franc", symbol: "₣" } },
|
|
178
|
+
NE: { callingCode: 227, currency: { isoCode: "XOF", name: "West African CFA franc", symbol: "Fr" } },
|
|
179
|
+
NF: { callingCode: 672, currency: { isoCode: "AUD", name: "Australian dollar", symbol: "$" } },
|
|
180
|
+
NG: { callingCode: 234, currency: { isoCode: "NGN", name: "Nigerian naira", symbol: "₦" } },
|
|
181
|
+
NI: { callingCode: 505, currency: { isoCode: "NIO", name: "Nicaraguan córdoba", symbol: "C$" } },
|
|
182
|
+
NL: { callingCode: 31, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
183
|
+
NO: { callingCode: 47, currency: { isoCode: "NOK", name: "Norwegian krone", symbol: "kr" } },
|
|
184
|
+
NP: { callingCode: 977, currency: { isoCode: "NPR", name: "Nepalese rupee", symbol: "₨" } },
|
|
185
|
+
NR: { callingCode: 674, currency: { isoCode: "AUD", name: "Australian dollar", symbol: "$" } },
|
|
186
|
+
NU: { callingCode: 683, currency: { isoCode: "NZD", name: "New Zealand dollar", symbol: "$" } },
|
|
187
|
+
NZ: { callingCode: 64, currency: { isoCode: "NZD", name: "New Zealand dollar", symbol: "$" } },
|
|
188
|
+
OM: { callingCode: 968, currency: { isoCode: "OMR", name: "Omani rial", symbol: "ر.ع." } },
|
|
189
|
+
PA: { callingCode: 507, currency: { isoCode: "PAB", name: "Panamanian balboa", symbol: "B/." } },
|
|
190
|
+
PE: { callingCode: 51, currency: { isoCode: "PEN", name: "Peruvian sol", symbol: "S/." } },
|
|
191
|
+
PF: { callingCode: 689, currency: { isoCode: "XPF", name: "CFP franc", symbol: "₣" } },
|
|
192
|
+
PG: { callingCode: 675, currency: { isoCode: "PGK", name: "Papua New Guinean kina", symbol: "K" } },
|
|
193
|
+
PH: { callingCode: 63, currency: { isoCode: "PHP", name: "Philippine peso", symbol: "₱" } },
|
|
194
|
+
PK: { callingCode: 92, currency: { isoCode: "PKR", name: "Pakistani rupee", symbol: "₨" } },
|
|
195
|
+
PL: { callingCode: 48, currency: { isoCode: "PLN", name: "Polish złoty", symbol: "zł" } },
|
|
196
|
+
PM: { callingCode: 508, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
197
|
+
PN: { callingCode: 64, currency: { isoCode: "NZD", name: "New Zealand dollar", symbol: "$" } },
|
|
198
|
+
PR: { callingCode: 1, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
199
|
+
PS: { callingCode: 970, currency: { isoCode: "EGP", name: "Egyptian pound", symbol: "E£" } },
|
|
200
|
+
PT: { callingCode: 351, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
201
|
+
PW: { callingCode: 680, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
202
|
+
PY: { callingCode: 595, currency: { isoCode: "PYG", name: "Paraguayan guaraní", symbol: "₲" } },
|
|
203
|
+
QA: { callingCode: 974, currency: { isoCode: "QAR", name: "Qatari riyal", symbol: "ر.ق" } },
|
|
204
|
+
RE: { callingCode: 262, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
205
|
+
RO: { callingCode: 40, currency: { isoCode: "RON", name: "Romanian leu", symbol: "lei" } },
|
|
206
|
+
RS: { callingCode: 381, currency: { isoCode: "RSD", name: "Serbian dinar", symbol: "дин." } },
|
|
207
|
+
RU: { callingCode: 7, currency: { isoCode: "RUB", name: "Russian ruble", symbol: "₽" } },
|
|
208
|
+
RW: { callingCode: 250, currency: { isoCode: "RWF", name: "Rwandan franc", symbol: "Fr" } },
|
|
209
|
+
SA: { callingCode: 966, currency: { isoCode: "SAR", name: "Saudi riyal", symbol: "ر.س" } },
|
|
210
|
+
SB: { callingCode: 677, currency: { isoCode: "SBD", name: "Solomon Islands dollar", symbol: "$" } },
|
|
211
|
+
SC: { callingCode: 248, currency: { isoCode: "SCR", name: "Seychellois rupee", symbol: "₨" } },
|
|
212
|
+
SD: { callingCode: 249, currency: { isoCode: "SDG", name: "Sudanese pound", symbol: "PT" } },
|
|
213
|
+
SE: { callingCode: 46, currency: { isoCode: "SEK", name: "Swedish krona", symbol: "kr" } },
|
|
214
|
+
SG: { callingCode: 65, currency: { isoCode: "SGD", name: "Singapore dollar", symbol: "$" } },
|
|
215
|
+
SH: { callingCode: 2, currency: { isoCode: "GBP", name: "Pound sterling", symbol: "£" } },
|
|
216
|
+
SI: { callingCode: 386, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
217
|
+
SJ: { callingCode: 4779, currency: { isoCode: "NOK", name: "krone", symbol: "kr" } },
|
|
218
|
+
SK: { callingCode: 421, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
219
|
+
SL: { callingCode: 232, currency: { isoCode: "SLL", name: "Sierra Leonean leone", symbol: "Le" } },
|
|
220
|
+
SM: { callingCode: 378, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
221
|
+
SN: { callingCode: 221, currency: { isoCode: "XOF", name: "West African CFA franc", symbol: "Fr" } },
|
|
222
|
+
SO: { callingCode: 252, currency: { isoCode: "SOS", name: "Somali shilling", symbol: "Sh" } },
|
|
223
|
+
SR: { callingCode: 597, currency: { isoCode: "SRD", name: "Surinamese dollar", symbol: "$" } },
|
|
224
|
+
SS: { callingCode: 211, currency: { isoCode: "SSP", name: "South Sudanese pound", symbol: "£" } },
|
|
225
|
+
ST: { callingCode: 239, currency: { isoCode: "STN", name: "São Tomé and Príncipe dobra", symbol: "Db" } },
|
|
226
|
+
SV: { callingCode: 503, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
227
|
+
SX: { callingCode: 1, currency: { isoCode: "ANG", name: "Netherlands Antillean guilder", symbol: "ƒ" } },
|
|
228
|
+
SY: { callingCode: 963, currency: { isoCode: "SYP", name: "Syrian pound", symbol: "£" } },
|
|
229
|
+
SZ: { callingCode: 268, currency: { isoCode: "SZL", name: "Swazi lilangeni", symbol: "L" } },
|
|
230
|
+
TC: { callingCode: 1, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
231
|
+
TD: { callingCode: 235, currency: { isoCode: "XAF", name: "Central African CFA franc", symbol: "Fr" } },
|
|
232
|
+
TF: { callingCode: 262, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
233
|
+
TG: { callingCode: 228, currency: { isoCode: "XOF", name: "West African CFA franc", symbol: "Fr" } },
|
|
234
|
+
TH: { callingCode: 66, currency: { isoCode: "THB", name: "Thai baht", symbol: "฿" } },
|
|
235
|
+
TJ: { callingCode: 992, currency: { isoCode: "TJS", name: "Tajikistani somoni", symbol: "ЅМ" } },
|
|
236
|
+
TK: { callingCode: 690, currency: { isoCode: "NZD", name: "New Zealand dollar", symbol: "$" } },
|
|
237
|
+
TL: { callingCode: 670, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
238
|
+
TM: { callingCode: 993, currency: { isoCode: "TMT", name: "Turkmenistan manat", symbol: "m" } },
|
|
239
|
+
TN: { callingCode: 216, currency: { isoCode: "TND", name: "Tunisian dinar", symbol: "د.ت" } },
|
|
240
|
+
TO: { callingCode: 676, currency: { isoCode: "TOP", name: "Tongan paʻanga", symbol: "T$" } },
|
|
241
|
+
TR: { callingCode: 90, currency: { isoCode: "TRY", name: "Turkish lira", symbol: "₺" } },
|
|
242
|
+
TT: { callingCode: 1, currency: { isoCode: "TTD", name: "Trinidad and Tobago dollar", symbol: "$" } },
|
|
243
|
+
TV: { callingCode: 688, currency: { isoCode: "AUD", name: "Australian dollar", symbol: "$" } },
|
|
244
|
+
TW: { callingCode: 886, currency: { isoCode: "TWD", name: "New Taiwan dollar", symbol: "$" } },
|
|
245
|
+
TZ: { callingCode: 255, currency: { isoCode: "TZS", name: "Tanzanian shilling", symbol: "Sh" } },
|
|
246
|
+
UA: { callingCode: 380, currency: { isoCode: "UAH", name: "Ukrainian hryvnia", symbol: "₴" } },
|
|
247
|
+
UG: { callingCode: 256, currency: { isoCode: "UGX", name: "Ugandan shilling", symbol: "Sh" } },
|
|
248
|
+
UM: { callingCode: 268, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
249
|
+
US: { callingCode: 1, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
250
|
+
UY: { callingCode: 598, currency: { isoCode: "UYU", name: "Uruguayan peso", symbol: "$" } },
|
|
251
|
+
UZ: { callingCode: 998, currency: { isoCode: "UZS", name: "Uzbekistani soʻm", symbol: "so'm" } },
|
|
252
|
+
VA: { callingCode: 3, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
253
|
+
VC: { callingCode: 1, currency: { isoCode: "XCD", name: "Eastern Caribbean dollar", symbol: "$" } },
|
|
254
|
+
VE: { callingCode: 58, currency: { isoCode: "VES", name: "Venezuelan bolívar soberano", symbol: "Bs.S." } },
|
|
255
|
+
VG: { callingCode: 1, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
256
|
+
VI: { callingCode: 1, currency: { isoCode: "USD", name: "United States dollar", symbol: "$" } },
|
|
257
|
+
VN: { callingCode: 84, currency: { isoCode: "VND", name: "Vietnamese đồng", symbol: "₫" } },
|
|
258
|
+
VU: { callingCode: 678, currency: { isoCode: "VUV", name: "Vanuatu vatu", symbol: "Vt" } },
|
|
259
|
+
WF: { callingCode: 681, currency: { isoCode: "XPF", name: "CFP franc", symbol: "₣" } },
|
|
260
|
+
WS: { callingCode: 685, currency: { isoCode: "WST", name: "Samoan tālā", symbol: "T" } },
|
|
261
|
+
XK: { callingCode: 383, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
262
|
+
YE: { callingCode: 967, currency: { isoCode: "YER", name: "Yemeni rial", symbol: "﷼" } },
|
|
263
|
+
YT: { callingCode: 262, currency: { isoCode: "EUR", name: "Euro", symbol: "€" } },
|
|
264
|
+
ZA: { callingCode: 27, currency: { isoCode: "ZAR", name: "South African rand", symbol: "R" } },
|
|
265
|
+
ZM: { callingCode: 260, currency: { isoCode: "ZMW", name: "Zambian kwacha", symbol: "ZK" } },
|
|
266
|
+
ZW: { callingCode: 263, currency: { isoCode: "BWP", name: "Botswana pula", symbol: "P" } },
|
|
267
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Country-reference annotators. The flag emoji is a pure function of the ISO 3166-1 alpha-2 code
|
|
7
|
+
* (two Regional Indicator Symbols); calling code + currency come from {@link COUNTRY_REFERENCE}, a
|
|
8
|
+
* table generated from mledoze/countries (provenance-tracked, not hand-typed — the
|
|
9
|
+
* no-load-bearing-trivia rule).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { AnnotationSet, Annotator } from "@mailwoman/annotations"
|
|
13
|
+
|
|
14
|
+
import { COUNTRY_REFERENCE } from "./reference-data.ts"
|
|
15
|
+
|
|
16
|
+
const REGIONAL_INDICATOR_BASE = 0x1f1e6
|
|
17
|
+
const A_UPPER = "A".charCodeAt(0)
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The flag emoji for an ISO 3166-1 alpha-2 country code, formed from the two Regional Indicator Symbols (`US` → 🇺🇸).
|
|
21
|
+
* Returns `""` for anything that is not two ASCII letters.
|
|
22
|
+
*/
|
|
23
|
+
export function countryFlag(alpha2: string): string {
|
|
24
|
+
const code = alpha2.toUpperCase()
|
|
25
|
+
|
|
26
|
+
if (!/^[A-Z]{2}$/.test(code)) return ""
|
|
27
|
+
|
|
28
|
+
return String.fromCodePoint(...[...code].map((c) => REGIONAL_INDICATOR_BASE + c.charCodeAt(0) - A_UPPER))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Fill the country-reference slice (ISO 3166 alpha-2, flag, calling code, currency) from a resolved country code.
|
|
33
|
+
* Abstains on anything that isn't two ASCII letters.
|
|
34
|
+
*/
|
|
35
|
+
export const countryReferenceAnnotator: Annotator = ({ countryCode }): Partial<AnnotationSet> => {
|
|
36
|
+
if (!countryCode || !/^[A-Za-z]{2}$/.test(countryCode)) return {}
|
|
37
|
+
const alpha2 = countryCode.toUpperCase()
|
|
38
|
+
const ref = COUNTRY_REFERENCE[alpha2]
|
|
39
|
+
const flag = countryFlag(alpha2)
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
iso3166: { alpha2 },
|
|
43
|
+
...(flag ? { flag } : {}),
|
|
44
|
+
...(ref?.callingCode != null ? { callingCode: ref.callingCode } : {}),
|
|
45
|
+
...(ref?.currency ? { currency: ref.currency } : {}),
|
|
46
|
+
}
|
|
47
|
+
}
|
package/de/bundesland.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* The 16 German federal states (Bundesländer), keyed by their ISO 3166-2:DE subdivision code.
|
|
7
|
+
*
|
|
8
|
+
* The US analog is `us/state.ts`. The informative difference: a US state's two-letter code (`CA`)
|
|
9
|
+
* is the USPS abbreviation people actually write in an address, whereas a German address almost
|
|
10
|
+
* never carries the Bundesland at all — it is `PLZ City`, and the state is inferred. So these
|
|
11
|
+
* codes matter for resolver region-matching and display, not for parsing the surface string.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** Per-state record: ISO 3166-2:DE code, native German name, and the common English exonym. */
|
|
15
|
+
export interface GermanStateInfo {
|
|
16
|
+
/** ISO 3166-2:DE subdivision code without the `DE-` prefix (e.g. `BY` for `DE-BY`). */
|
|
17
|
+
code: string
|
|
18
|
+
/** Native German name (e.g. `Bayern`). */
|
|
19
|
+
name: string
|
|
20
|
+
/** Common English name (e.g. `Bavaria`). */
|
|
21
|
+
english: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* ISO 3166-2:DE code → state info, for all 16 Bundesländer. Codes are the official subdivision codes minus the `DE-`
|
|
26
|
+
* prefix.
|
|
27
|
+
*/
|
|
28
|
+
export const DE_BUNDESLAENDER = {
|
|
29
|
+
BW: { code: "BW", name: "Baden-Württemberg", english: "Baden-Württemberg" },
|
|
30
|
+
BY: { code: "BY", name: "Bayern", english: "Bavaria" },
|
|
31
|
+
BE: { code: "BE", name: "Berlin", english: "Berlin" },
|
|
32
|
+
BB: { code: "BB", name: "Brandenburg", english: "Brandenburg" },
|
|
33
|
+
HB: { code: "HB", name: "Bremen", english: "Bremen" },
|
|
34
|
+
HH: { code: "HH", name: "Hamburg", english: "Hamburg" },
|
|
35
|
+
HE: { code: "HE", name: "Hessen", english: "Hesse" },
|
|
36
|
+
MV: { code: "MV", name: "Mecklenburg-Vorpommern", english: "Mecklenburg-Western Pomerania" },
|
|
37
|
+
NI: { code: "NI", name: "Niedersachsen", english: "Lower Saxony" },
|
|
38
|
+
NW: { code: "NW", name: "Nordrhein-Westfalen", english: "North Rhine-Westphalia" },
|
|
39
|
+
RP: { code: "RP", name: "Rheinland-Pfalz", english: "Rhineland-Palatinate" },
|
|
40
|
+
SL: { code: "SL", name: "Saarland", english: "Saarland" },
|
|
41
|
+
SN: { code: "SN", name: "Sachsen", english: "Saxony" },
|
|
42
|
+
ST: { code: "ST", name: "Sachsen-Anhalt", english: "Saxony-Anhalt" },
|
|
43
|
+
SH: { code: "SH", name: "Schleswig-Holstein", english: "Schleswig-Holstein" },
|
|
44
|
+
TH: { code: "TH", name: "Thüringen", english: "Thuringia" },
|
|
45
|
+
} as const satisfies Record<string, GermanStateInfo>
|
|
46
|
+
|
|
47
|
+
/** An ISO 3166-2:DE state code (`BW`, `BY`, `BE`, …). */
|
|
48
|
+
export type GermanStateCode = keyof typeof DE_BUNDESLAENDER
|
|
49
|
+
|
|
50
|
+
const STATE_CODE_SET: ReadonlySet<string> = new Set(Object.keys(DE_BUNDESLAENDER))
|
|
51
|
+
|
|
52
|
+
/** Type-predicate for an ISO 3166-2:DE state code. Case-insensitive. */
|
|
53
|
+
export function isGermanStateCode(input: unknown): input is GermanStateCode {
|
|
54
|
+
return typeof input === "string" && STATE_CODE_SET.has(input.toUpperCase())
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Name (native German, English exonym, or common alias) → ISO 3166-2:DE code, lowercase-keyed. Includes the everyday
|
|
59
|
+
* aliases a parser actually meets: `NRW` for Nordrhein-Westfalen, `Bavaria` for Bayern, `Saxony` for Sachsen. The point
|
|
60
|
+
* is resolver region-matching: a German parse emits a region surface form, and the eval needs to map it to a code
|
|
61
|
+
* without a US-USPS-shaped matcher.
|
|
62
|
+
*/
|
|
63
|
+
export const DE_STATE_NAME_TO_CODE: ReadonlyMap<string, GermanStateCode> = (() => {
|
|
64
|
+
const out = new Map<string, GermanStateCode>()
|
|
65
|
+
|
|
66
|
+
for (const code of Object.keys(DE_BUNDESLAENDER) as GermanStateCode[]) {
|
|
67
|
+
const info = DE_BUNDESLAENDER[code]
|
|
68
|
+
out.set(info.name.toLowerCase(), code)
|
|
69
|
+
out.set(info.english.toLowerCase(), code)
|
|
70
|
+
out.set(code.toLowerCase(), code)
|
|
71
|
+
}
|
|
72
|
+
// Everyday aliases that are neither the ISO code nor the canonical name.
|
|
73
|
+
const aliases: Record<string, GermanStateCode> = {
|
|
74
|
+
nrw: "NW",
|
|
75
|
+
"nordrhein westfalen": "NW",
|
|
76
|
+
"baden wurttemberg": "BW",
|
|
77
|
+
"baden-wuerttemberg": "BW",
|
|
78
|
+
"baden wuerttemberg": "BW",
|
|
79
|
+
thueringen: "TH",
|
|
80
|
+
"freie hansestadt bremen": "HB",
|
|
81
|
+
"freie und hansestadt hamburg": "HH",
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for (const [alias, code] of Object.entries(aliases)) {
|
|
85
|
+
out.set(alias, code)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return out
|
|
89
|
+
})()
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Resolve a German state surface form (code, German name, English name, or common alias) to its ISO 3166-2:DE code.
|
|
93
|
+
* Returns null when unrecognized.
|
|
94
|
+
*/
|
|
95
|
+
export function lookupGermanState(input: string | null | undefined): GermanStateCode | null {
|
|
96
|
+
if (!input || typeof input !== "string") return null
|
|
97
|
+
const key = input.trim().toLowerCase()
|
|
98
|
+
|
|
99
|
+
if (STATE_CODE_SET.has(key.toUpperCase())) return key.toUpperCase() as GermanStateCode
|
|
100
|
+
|
|
101
|
+
return DE_STATE_NAME_TO_CODE.get(key) ?? null
|
|
102
|
+
}
|
package/de/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* The German address system (Deutsche Post / ISO 3166-2:DE): street types, postal codes
|
|
7
|
+
* (Postleitzahl), and the federal states (Bundesländer).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export * from "./bundesland.ts"
|
|
11
|
+
export * from "./postleitzahl.ts"
|
|
12
|
+
export * from "./street-type.ts"
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* German postal codes (Postleitzahl, PLZ): the branded type, the shape, normalization, and the
|
|
7
|
+
* first-digit → Leitzone geographic prior.
|
|
8
|
+
*
|
|
9
|
+
* The US analog is `us/zipcode.ts`, and the contrast is the informative part. A US ZIP's first
|
|
10
|
+
* digit maps cleanly to a band of states (`StateAbbreviationZipCodePrefixRecord`). A German PLZ's
|
|
11
|
+
* first digit maps to a **Leitzone** — a postal routing region that deliberately **crosses
|
|
12
|
+
* Bundesland borders** (Leitzone 6 covers Frankfurt in Hessen, Saarbrücken in Saarland, and Mainz
|
|
13
|
+
* in Rheinland-Pfalz). So the PLZ prior narrows geography, but it does NOT narrow the state the
|
|
14
|
+
* way a US ZIP does — a lesson for any code that tries to derive a German region from a postcode
|
|
15
|
+
* alone.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { Tagged } from "type-fest"
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A German postal code: five digits since the 1993 reform (`12623`). A bare 5-digit string, same shape as a US ZIP or a
|
|
22
|
+
* French code postal — disambiguation is the parser's job, not the shape's.
|
|
23
|
+
*
|
|
24
|
+
* @category Postal
|
|
25
|
+
* @type string
|
|
26
|
+
* @title Postleitzahl
|
|
27
|
+
* @pattern ^\d{5}$
|
|
28
|
+
*/
|
|
29
|
+
export type Postleitzahl = Tagged<string, "Postleitzahl">
|
|
30
|
+
|
|
31
|
+
/** The PLZ shape: exactly five digits. */
|
|
32
|
+
export const PLZ_PATTERN = /^\d{5}$/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Normalize a PLZ surface form to the bare five digits: strip the `D-` / `DE-` country courtesy prefix and surrounding
|
|
36
|
+
* whitespace (`D-68161` → `68161`). Returns null if the result is not a PLZ.
|
|
37
|
+
*/
|
|
38
|
+
export function normalizePLZ(raw: unknown): Postleitzahl | null {
|
|
39
|
+
if (typeof raw !== "string") return null
|
|
40
|
+
const s = raw.trim().toUpperCase().replace(/^DE?-/, "")
|
|
41
|
+
|
|
42
|
+
return PLZ_PATTERN.test(s) ? (s as Postleitzahl) : null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Type-predicate for a (normalized) German postal code. */
|
|
46
|
+
export function isPostleitzahl(input: unknown): input is Postleitzahl {
|
|
47
|
+
return typeof input === "string" && PLZ_PATTERN.test(input)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** A PLZ Leitzone first digit. */
|
|
51
|
+
export type LeitzoneDigit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
|
52
|
+
|
|
53
|
+
/** Per-Leitzone descriptor: the routing region and a few anchor cities (coarse, postal not admin). */
|
|
54
|
+
export interface LeitzoneInfo {
|
|
55
|
+
digit: LeitzoneDigit
|
|
56
|
+
/** Coarse routing-region label. */
|
|
57
|
+
region: string
|
|
58
|
+
/** Well-known anchor cities in the zone (illustrative, not exhaustive). */
|
|
59
|
+
cities: readonly string[]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* PLZ first digit → Leitzone. A coarse, postal-routing prior: these zones cross Bundesland borders, so the label is
|
|
64
|
+
* "which corner of Germany", not "which state". Anchor cities are the safe, well-known way to pin a zone without
|
|
65
|
+
* over-claiming a boundary the routing geography does not actually follow.
|
|
66
|
+
*/
|
|
67
|
+
export const PLZ_LEITZONEN = {
|
|
68
|
+
0: { digit: 0, region: "Sachsen / Ostthüringen", cities: ["Leipzig", "Dresden", "Chemnitz"] },
|
|
69
|
+
1: { digit: 1, region: "Berlin / Brandenburg / Mecklenburg-Vorpommern", cities: ["Berlin", "Potsdam", "Rostock"] },
|
|
70
|
+
2: { digit: 2, region: "Hamburg / Schleswig-Holstein / Bremen", cities: ["Hamburg", "Kiel", "Bremen"] },
|
|
71
|
+
3: { digit: 3, region: "Niedersachsen / Nordhessen", cities: ["Hannover", "Braunschweig", "Kassel"] },
|
|
72
|
+
4: { digit: 4, region: "nördliches Nordrhein-Westfalen", cities: ["Düsseldorf", "Dortmund", "Münster"] },
|
|
73
|
+
5: { digit: 5, region: "südliches NRW / nördliches Rheinland-Pfalz", cities: ["Köln", "Bonn", "Aachen"] },
|
|
74
|
+
6: {
|
|
75
|
+
digit: 6,
|
|
76
|
+
region: "Südhessen / Rheinland-Pfalz / Saarland",
|
|
77
|
+
cities: ["Frankfurt am Main", "Mainz", "Saarbrücken"],
|
|
78
|
+
},
|
|
79
|
+
7: { digit: 7, region: "Baden-Württemberg", cities: ["Stuttgart", "Karlsruhe", "Freiburg"] },
|
|
80
|
+
8: { digit: 8, region: "südliches Bayern", cities: ["München", "Augsburg", "Ingolstadt"] },
|
|
81
|
+
9: { digit: 9, region: "nördliches Bayern / Oberpfalz", cities: ["Nürnberg", "Würzburg", "Regensburg"] },
|
|
82
|
+
} as const satisfies Record<LeitzoneDigit, LeitzoneInfo>
|
|
83
|
+
|
|
84
|
+
/** The Leitzone of a PLZ (its first digit's routing region), or null if the input is not a PLZ. */
|
|
85
|
+
export function leitzoneOf(plz: unknown): LeitzoneInfo | null {
|
|
86
|
+
const normalized = normalizePLZ(plz)
|
|
87
|
+
|
|
88
|
+
if (!normalized) return null
|
|
89
|
+
|
|
90
|
+
return PLZ_LEITZONEN[Number(normalized[0]) as LeitzoneDigit]
|
|
91
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* German street types (Straßentypen).
|
|
7
|
+
*
|
|
8
|
+
* The US analog is `us/street-suffix.ts`, and the structural contrast is the whole lesson of this
|
|
9
|
+
* file. A US street type is a separate trailing word with a USPS-standardized abbreviation (`Main
|
|
10
|
+
* Street` → `ST`). A German street type is overwhelmingly an **agglutinative suffix** fused onto
|
|
11
|
+
* the name (`Straußstraße`, `Karl-Liebknecht-Straße`), with only one abbreviation in real use
|
|
12
|
+
* (`Str.`). So detection is by suffix, not by a trailing token, and there is no Pub-28-style
|
|
13
|
+
* abbreviation table to salvage.
|
|
14
|
+
*
|
|
15
|
+
* The second lesson is the collision, the German cousin of the US `KY` = Key / Kentucky problem.
|
|
16
|
+
* Many German PLACE names end in what look like street suffixes — `-berg` (Nürnberg), `-burg`
|
|
17
|
+
* (Hamburg), `-dorf` (Düsseldorf), `-feld`, `-hof`, `-stadt`. If those counted as street markers,
|
|
18
|
+
* the city token in a `PLZ City` segment would masquerade as a street and wrongly flag the
|
|
19
|
+
* postcode as a house number. {@link DE_STREET_SUFFIXES} is therefore a curated, place-name-SAFE
|
|
20
|
+
* set — the suffixes that are distinctively streets and (almost) never the tail of a city name.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Canonical German street type → recognized written variants (including the `Str.` abbreviation and the `ß`/`ss`
|
|
25
|
+
* spelling split). The full reference table, used for synthesis/expansion. For the "is this token part of a street"
|
|
26
|
+
* test, use {@link DE_STREET_SUFFIXES} / {@link isGermanStreetToken}, which exclude the place-name-colliding suffixes.
|
|
27
|
+
*/
|
|
28
|
+
export const DE_STREET_TYPE_VARIANTS = {
|
|
29
|
+
Straße: ["Str.", "Str", "Strasse"],
|
|
30
|
+
Weg: [],
|
|
31
|
+
Platz: ["Pl.", "Pl"],
|
|
32
|
+
Gasse: [],
|
|
33
|
+
Allee: [],
|
|
34
|
+
Ring: [],
|
|
35
|
+
Damm: [],
|
|
36
|
+
Ufer: [],
|
|
37
|
+
Steig: [],
|
|
38
|
+
Stieg: [],
|
|
39
|
+
Pfad: [],
|
|
40
|
+
Chaussee: ["Chaussée"],
|
|
41
|
+
Twiete: [],
|
|
42
|
+
} as const satisfies Record<string, readonly string[]>
|
|
43
|
+
|
|
44
|
+
/** A canonical German street type (e.g. `Straße`, `Weg`, `Platz`). */
|
|
45
|
+
export type GermanStreetType = keyof typeof DE_STREET_TYPE_VARIANTS
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Place-name-SAFE street suffixes for "is this token part of a street" detection, lowercase, with the `ß`/`ss` split
|
|
49
|
+
* spelled out and `str` for the `Str.` abbreviation. Deliberately EXCLUDES the suffixes that also end German city names
|
|
50
|
+
* — `-berg`, `-burg`, `-dorf`, `-feld`, `-hof`, `-stadt`, `-heim`, `-bach`, `-tal` — so a city token in a `PLZ City`
|
|
51
|
+
* segment is not mistaken for a street.
|
|
52
|
+
*/
|
|
53
|
+
export const DE_STREET_SUFFIXES = [
|
|
54
|
+
"straße",
|
|
55
|
+
"strasse",
|
|
56
|
+
"str",
|
|
57
|
+
"weg",
|
|
58
|
+
"platz",
|
|
59
|
+
"gasse",
|
|
60
|
+
"allee",
|
|
61
|
+
"ring",
|
|
62
|
+
"damm",
|
|
63
|
+
"ufer",
|
|
64
|
+
"steig",
|
|
65
|
+
"stieg",
|
|
66
|
+
"pfad",
|
|
67
|
+
"chaussee",
|
|
68
|
+
"twiete",
|
|
69
|
+
] as const
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* True when a token reads as (part of) a German street: it ends with one of the place-name-safe
|
|
73
|
+
* {@link DE_STREET_SUFFIXES}. Handles both the fused compound (`Straußstraße` → ends `straße`) and the standalone type
|
|
74
|
+
* word or `Str.` abbreviation (`Platz`, `Str` → end `platz` / `str`).
|
|
75
|
+
*/
|
|
76
|
+
export function isGermanStreetToken(token: unknown): boolean {
|
|
77
|
+
if (typeof token !== "string") return false
|
|
78
|
+
const t = token.toLowerCase().replace(/[^a-zà-ÿß]/g, "")
|
|
79
|
+
|
|
80
|
+
if (t.length < 3) return false
|
|
81
|
+
|
|
82
|
+
return DE_STREET_SUFFIXES.some((s) => t.endsWith(s))
|
|
83
|
+
}
|