@whiteslove/parsing-lexicon 0.2.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/LICENSE +21 -0
- package/README.md +137 -0
- package/index.d.ts +375 -0
- package/package.json +75 -0
- package/src/central-asia-locations.js +211 -0
- package/src/central-asia.js +233 -0
- package/src/contact.d.ts +44 -0
- package/src/contact.js +159 -0
- package/src/countries.js +175 -0
- package/src/country-context.d.ts +10 -0
- package/src/country-context.js +22 -0
- package/src/currency.d.ts +14 -0
- package/src/currency.js +66 -0
- package/src/geo.js +169 -0
- package/src/geography-central-asia.js +42 -0
- package/src/geography-detection.d.ts +14 -0
- package/src/geography-detection.js +64 -0
- package/src/geography-display.d.ts +13 -0
- package/src/geography-display.js +113 -0
- package/src/geography.js +210 -0
- package/src/hiring-advanced.js +147 -0
- package/src/hiring-candidate-fields.d.ts +9 -0
- package/src/hiring-candidate-fields.js +92 -0
- package/src/hiring-context.d.ts +64 -0
- package/src/hiring-context.js +412 -0
- package/src/hiring-language-extensions.d.ts +19 -0
- package/src/hiring-language-extensions.js +139 -0
- package/src/hiring-languages.js +135 -0
- package/src/hiring-location-fields.d.ts +3 -0
- package/src/hiring-location-fields.js +53 -0
- package/src/hiring-professions-ro.js +191 -0
- package/src/hiring-professions.js +437 -0
- package/src/hiring-requirements.d.ts +16 -0
- package/src/hiring-requirements.js +170 -0
- package/src/hiring-salary-context.d.ts +27 -0
- package/src/hiring-salary-context.js +76 -0
- package/src/hiring-semantics.d.ts +29 -0
- package/src/hiring-semantics.js +218 -0
- package/src/hiring-skills.d.ts +21 -0
- package/src/hiring-skills.js +315 -0
- package/src/hiring-source-aliases.d.ts +32 -0
- package/src/hiring-source-aliases.js +186 -0
- package/src/hiring-source-semantics.d.ts +31 -0
- package/src/hiring-source-semantics.js +293 -0
- package/src/hiring-temporal.d.ts +15 -0
- package/src/hiring-temporal.js +67 -0
- package/src/hiring-vacancy-fields.d.ts +5 -0
- package/src/hiring-vacancy-fields.js +23 -0
- package/src/hiring-work-semantics.d.ts +34 -0
- package/src/hiring-work-semantics.js +72 -0
- package/src/hiring.js +180 -0
- package/src/housing-address.d.ts +18 -0
- package/src/housing-address.js +210 -0
- package/src/housing-context.d.ts +36 -0
- package/src/housing-context.js +183 -0
- package/src/housing-features.js +30 -0
- package/src/housing-intent.d.ts +9 -0
- package/src/housing-intent.js +132 -0
- package/src/housing-listing-fields.js +131 -0
- package/src/housing-money.d.ts +7 -0
- package/src/housing-money.js +102 -0
- package/src/housing-source-aliases.d.ts +8 -0
- package/src/housing-source-aliases.js +51 -0
- package/src/housing-structured.d.ts +55 -0
- package/src/housing-structured.js +219 -0
- package/src/housing.js +200 -0
- package/src/index.js +44 -0
- package/src/kz-location-extensions.js +307 -0
- package/src/landmarks.js +21 -0
- package/src/lexicon-core.js +58 -0
- package/src/location-merge.js +106 -0
- package/src/locations.js +456 -0
- package/src/money-core.d.ts +10 -0
- package/src/money-core.js +81 -0
- package/src/money-lexicon.d.ts +5 -0
- package/src/money-lexicon.js +79 -0
- package/src/money.js +154 -0
- package/src/normalization.js +384 -0
- package/src/odesa-metropolitan.js +145 -0
- package/src/romania-geography.js +47 -0
- package/src/tashkent-colloquial.js +72 -0
- package/src/tashkent-housing-geography.d.ts +38 -0
- package/src/tashkent-housing-geography.js +211 -0
- package/src/tashkent-pois.js +215 -0
- package/src/tashkent-residential-complexes.js +272 -0
- package/src/ua-location-extensions-major.js +118 -0
- package/src/ua-location-extensions-metro.js +9 -0
- package/src/ua-location-extensions-regional.js +246 -0
- package/src/ua-secondary-cities.d.ts +2 -0
- package/src/ua-secondary-cities.js +57 -0
- package/src/ukraine.js +75 -0
- package/src/uz-location-extensions.js +259 -0
package/src/contact.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { parsePhoneNumberFromString } from 'libphonenumber-js/min';
|
|
2
|
+
|
|
3
|
+
// Broad phone-like detection used by other parsers for exclusion/classification.
|
|
4
|
+
// It deliberately stays tolerant and does not validate against a country plan.
|
|
5
|
+
const PHONE_LIKE_RE = /\+?\d(?:[\t \u00a0().-]*\d){9,}/g;
|
|
6
|
+
|
|
7
|
+
// Contact extraction may start from shorter national formats, but candidates are
|
|
8
|
+
// only returned after libphonenumber validation.
|
|
9
|
+
const PHONE_CANDIDATE_RE = /\+?\d(?:[\t \u00a0().-]*\d){6,}(?:[\t \u00a0]*(?:ext\.?|extension|x|доб\.?|дод\.?)\s*\d{1,6})?/giu;
|
|
10
|
+
const PHONE_EXTENSION_RE = /[\t \u00a0]*(?:ext\.?|extension|x|доб\.?|дод\.?)\s*(\d{1,6})$/iu;
|
|
11
|
+
|
|
12
|
+
const TELEGRAM_USERNAME_RE = /^[A-Za-z0-9_]{5,32}$/;
|
|
13
|
+
const TELEGRAM_LINK_RE = /(?:https?:\/\/)?(?:t\.me|telegram\.me|telegram\.dog)\/([A-Za-z0-9_]{5,32})(?:\/[0-9]+)?(?:[/?#][^\s]*)?/giu;
|
|
14
|
+
const TELEGRAM_TG_RE = /tg:\/\/resolve\?[^\s]*?\bdomain=([A-Za-z0-9_]{5,32})\b[^\s]*/giu;
|
|
15
|
+
const TELEGRAM_MENTION_RE = /(^|[^\p{L}\p{N}_@])@([A-Za-z0-9_]{5,32})\b/gu;
|
|
16
|
+
|
|
17
|
+
function normalizedCountryHint(value) {
|
|
18
|
+
const country = String(value || '').trim().toUpperCase();
|
|
19
|
+
return /^[A-Z]{2}$/.test(country) ? country : undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function splitPhoneExtension(raw) {
|
|
23
|
+
const match = String(raw || '').match(PHONE_EXTENSION_RE);
|
|
24
|
+
if (!match) return { base: String(raw || '').trim(), extension: null };
|
|
25
|
+
return {
|
|
26
|
+
base: String(raw || '').slice(0, match.index).trim(),
|
|
27
|
+
extension: match[1] || null,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function findPhoneLikeSpans(value) {
|
|
32
|
+
const text = String(value || '');
|
|
33
|
+
const spans = [];
|
|
34
|
+
for (const match of text.matchAll(PHONE_LIKE_RE)) {
|
|
35
|
+
const raw = match[0];
|
|
36
|
+
const digits = raw.replace(/\D/g, '');
|
|
37
|
+
if (digits.length < 10) continue;
|
|
38
|
+
const start = match.index ?? 0;
|
|
39
|
+
spans.push(Object.freeze({
|
|
40
|
+
start,
|
|
41
|
+
end: start + raw.length,
|
|
42
|
+
raw,
|
|
43
|
+
digits,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
return Object.freeze(spans);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function maskPhoneLikeSpans(value, replacement = ' ') {
|
|
50
|
+
const text = String(value || '');
|
|
51
|
+
const spans = findPhoneLikeSpans(text);
|
|
52
|
+
if (!spans.length) return text;
|
|
53
|
+
|
|
54
|
+
let out = '';
|
|
55
|
+
let cursor = 0;
|
|
56
|
+
for (const span of spans) {
|
|
57
|
+
out += text.slice(cursor, span.start);
|
|
58
|
+
out += replacement;
|
|
59
|
+
cursor = span.end;
|
|
60
|
+
}
|
|
61
|
+
return out + text.slice(cursor);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function parsePhoneNumbers(value, options = {}) {
|
|
65
|
+
const text = String(value || '');
|
|
66
|
+
const countryHint = normalizedCountryHint(options.countryHint);
|
|
67
|
+
const includePossible = options.includePossible === true;
|
|
68
|
+
const out = [];
|
|
69
|
+
const seen = new Set();
|
|
70
|
+
|
|
71
|
+
for (const match of text.matchAll(PHONE_CANDIDATE_RE)) {
|
|
72
|
+
const raw = match[0].trim();
|
|
73
|
+
const { base, extension } = splitPhoneExtension(raw);
|
|
74
|
+
const parsed = parsePhoneNumberFromString(base, countryHint);
|
|
75
|
+
if (!parsed) continue;
|
|
76
|
+
const valid = parsed.isValid();
|
|
77
|
+
const possible = parsed.isPossible();
|
|
78
|
+
if (!valid && !(includePossible && possible)) continue;
|
|
79
|
+
|
|
80
|
+
const key = `${parsed.number}:${extension || parsed.ext || ''}`;
|
|
81
|
+
if (seen.has(key)) continue;
|
|
82
|
+
seen.add(key);
|
|
83
|
+
|
|
84
|
+
const start = match.index ?? 0;
|
|
85
|
+
out.push(Object.freeze({
|
|
86
|
+
start,
|
|
87
|
+
end: start + match[0].length,
|
|
88
|
+
raw,
|
|
89
|
+
digits: base.replace(/\D/g, ''),
|
|
90
|
+
number: parsed.number,
|
|
91
|
+
nationalNumber: parsed.nationalNumber,
|
|
92
|
+
national: parsed.formatNational(),
|
|
93
|
+
international: parsed.formatInternational(),
|
|
94
|
+
country: parsed.country || null,
|
|
95
|
+
countryCallingCode: parsed.countryCallingCode,
|
|
96
|
+
extension: extension || parsed.ext || null,
|
|
97
|
+
valid,
|
|
98
|
+
possible,
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return Object.freeze(out);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function normalizePhone(value, options = {}) {
|
|
106
|
+
return parsePhoneNumbers(value, options)[0] || null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function telegramContact(username, raw, start, source) {
|
|
110
|
+
const normalized = String(username || '').replace(/^@/, '');
|
|
111
|
+
if (!TELEGRAM_USERNAME_RE.test(normalized)) return null;
|
|
112
|
+
return Object.freeze({
|
|
113
|
+
start,
|
|
114
|
+
end: start + raw.length,
|
|
115
|
+
raw,
|
|
116
|
+
username: normalized,
|
|
117
|
+
handle: `@${normalized}`,
|
|
118
|
+
url: `https://t.me/${normalized}`,
|
|
119
|
+
source,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Extract public Telegram username contacts from mentions and links.
|
|
125
|
+
* Message/channel transport parsing stays in consumers; this helper owns only
|
|
126
|
+
* reusable contact normalization.
|
|
127
|
+
*/
|
|
128
|
+
export function findTelegramContacts(value) {
|
|
129
|
+
const text = String(value || '');
|
|
130
|
+
const found = [];
|
|
131
|
+
const seen = new Set();
|
|
132
|
+
|
|
133
|
+
const push = (username, raw, start, source) => {
|
|
134
|
+
const contact = telegramContact(username, raw, start, source);
|
|
135
|
+
if (!contact) return;
|
|
136
|
+
const key = contact.username.toLowerCase();
|
|
137
|
+
if (seen.has(key)) return;
|
|
138
|
+
seen.add(key);
|
|
139
|
+
found.push(contact);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
for (const match of text.matchAll(TELEGRAM_LINK_RE)) {
|
|
143
|
+
push(match[1], match[0], match.index ?? 0, 'url');
|
|
144
|
+
}
|
|
145
|
+
for (const match of text.matchAll(TELEGRAM_TG_RE)) {
|
|
146
|
+
push(match[1], match[0], match.index ?? 0, 'tg');
|
|
147
|
+
}
|
|
148
|
+
for (const match of text.matchAll(TELEGRAM_MENTION_RE)) {
|
|
149
|
+
const prefix = match[1] || '';
|
|
150
|
+
const raw = `@${match[2]}`;
|
|
151
|
+
push(match[2], raw, (match.index ?? 0) + prefix.length, 'mention');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return Object.freeze(found.sort((a, b) => a.start - b.start));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function normalizeTelegramContact(value) {
|
|
158
|
+
return findTelegramContacts(value)[0] || null;
|
|
159
|
+
}
|
package/src/countries.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { findCanonical } from './normalization.js';
|
|
2
|
+
import { deepFreeze, freezeAliases } from './lexicon-core.js';
|
|
3
|
+
|
|
4
|
+
const country = (code, canonical, currency, aliases) => deepFreeze({
|
|
5
|
+
code,
|
|
6
|
+
canonical,
|
|
7
|
+
type: 'country',
|
|
8
|
+
currency,
|
|
9
|
+
aliases: freezeAliases(aliases),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
/** Canonical countries used by housing/hiring ingestion. */
|
|
13
|
+
export const COUNTRIES = Object.freeze([
|
|
14
|
+
country('UZ', 'Uzbekistan', 'UZS', {
|
|
15
|
+
en: ['Uzbekistan', 'Republic of Uzbekistan'],
|
|
16
|
+
ru: ['Узбекистан', 'Республика Узбекистан'],
|
|
17
|
+
uk: ['Узбекистан', 'Республіка Узбекистан'],
|
|
18
|
+
ro: ['Uzbekistan', 'Republica Uzbekistan'],
|
|
19
|
+
uzLatn: ["O'zbekiston", "O'zbekiston Respublikasi", 'Ozbekiston'],
|
|
20
|
+
uzCyrl: ['Ўзбекистон', 'Ўзбекистон Республикаси'],
|
|
21
|
+
kk: ['Өзбекстан', 'Өзбекстан Республикасы'],
|
|
22
|
+
}),
|
|
23
|
+
country('KZ', 'Kazakhstan', 'KZT', {
|
|
24
|
+
en: ['Kazakhstan', 'Republic of Kazakhstan'],
|
|
25
|
+
ru: ['Казахстан', 'Республика Казахстан'],
|
|
26
|
+
uk: ['Казахстан', 'Республіка Казахстан'],
|
|
27
|
+
ro: ['Kazahstan', 'Republica Kazahstan', 'Kazakhstan'],
|
|
28
|
+
uzLatn: ["Qozog'iston", "Qozog'iston Respublikasi"],
|
|
29
|
+
uzCyrl: ['Қозоғистон', 'Қозоғистон Республикаси'],
|
|
30
|
+
kk: ['Қазақстан', 'Қазақстан Республикасы'],
|
|
31
|
+
}),
|
|
32
|
+
country('UA', 'Ukraine', 'UAH', {
|
|
33
|
+
en: ['Ukraine'],
|
|
34
|
+
ru: ['Украина'],
|
|
35
|
+
uk: ['Україна'],
|
|
36
|
+
ro: ['Ucraina'],
|
|
37
|
+
uzLatn: ['Ukraina'],
|
|
38
|
+
uzCyrl: ['Украина'],
|
|
39
|
+
kk: ['Украина'],
|
|
40
|
+
}),
|
|
41
|
+
country('RO', 'Romania', 'RON', {
|
|
42
|
+
en: ['Romania'],
|
|
43
|
+
ru: ['Румыния'],
|
|
44
|
+
uk: ['Румунія'],
|
|
45
|
+
ro: ['România', 'Romania'],
|
|
46
|
+
uzLatn: ['Ruminiya'],
|
|
47
|
+
uzCyrl: ['Руминия'],
|
|
48
|
+
kk: ['Румыния'],
|
|
49
|
+
}),
|
|
50
|
+
country('KG', 'Kyrgyzstan', 'KGS', {
|
|
51
|
+
en: ['Kyrgyzstan', 'Kyrgyz Republic'],
|
|
52
|
+
ru: ['Кыргызстан', 'Киргизия', 'Кыргызская Республика'],
|
|
53
|
+
uk: ['Киргизстан', 'Киргизька Республіка'],
|
|
54
|
+
ro: ['Kârgâzstan', 'Kyrgyzstan'],
|
|
55
|
+
uzLatn: ["Qirg'iziston"],
|
|
56
|
+
uzCyrl: ['Қирғизистон'],
|
|
57
|
+
kk: ['Қырғызстан', 'Қырғыз Республикасы'],
|
|
58
|
+
}),
|
|
59
|
+
country('GE', 'Georgia', 'GEL', {
|
|
60
|
+
en: ['Georgia'],
|
|
61
|
+
ru: ['Грузия'],
|
|
62
|
+
uk: ['Грузія'],
|
|
63
|
+
ro: ['Georgia'],
|
|
64
|
+
}),
|
|
65
|
+
country('AZ', 'Azerbaijan', 'AZN', {
|
|
66
|
+
en: ['Azerbaijan'],
|
|
67
|
+
ru: ['Азербайджан'],
|
|
68
|
+
uk: ['Азербайджан'],
|
|
69
|
+
ro: ['Azerbaidjan'],
|
|
70
|
+
}),
|
|
71
|
+
country('AM', 'Armenia', 'AMD', {
|
|
72
|
+
en: ['Armenia'],
|
|
73
|
+
ru: ['Армения'],
|
|
74
|
+
uk: ['Вірменія'],
|
|
75
|
+
ro: ['Armenia'],
|
|
76
|
+
}),
|
|
77
|
+
country('MD', 'Moldova', 'MDL', {
|
|
78
|
+
en: ['Moldova', 'Republic of Moldova'],
|
|
79
|
+
ru: ['Молдова'],
|
|
80
|
+
uk: ['Молдова'],
|
|
81
|
+
ro: ['Moldova', 'Republica Moldova'],
|
|
82
|
+
}),
|
|
83
|
+
country('TJ', 'Tajikistan', 'TJS', {
|
|
84
|
+
en: ['Tajikistan'],
|
|
85
|
+
ru: ['Таджикистан'],
|
|
86
|
+
uk: ['Таджикистан'],
|
|
87
|
+
ro: ['Tadjikistan'],
|
|
88
|
+
}),
|
|
89
|
+
country('TM', 'Turkmenistan', 'TMT', {
|
|
90
|
+
en: ['Turkmenistan'],
|
|
91
|
+
ru: ['Туркменистан'],
|
|
92
|
+
uk: ['Туркменістан'],
|
|
93
|
+
ro: ['Turkmenistan'],
|
|
94
|
+
}),
|
|
95
|
+
country('PL', 'Poland', 'PLN', {
|
|
96
|
+
en: ['Poland'],
|
|
97
|
+
ru: ['Польша'],
|
|
98
|
+
uk: ['Польща'],
|
|
99
|
+
ro: ['Polonia'],
|
|
100
|
+
all: ['Polska'],
|
|
101
|
+
}),
|
|
102
|
+
country('DE', 'Germany', 'EUR', {
|
|
103
|
+
en: ['Germany'],
|
|
104
|
+
ru: ['Германия'],
|
|
105
|
+
uk: ['Німеччина'],
|
|
106
|
+
ro: ['Germania'],
|
|
107
|
+
all: ['Deutschland'],
|
|
108
|
+
}),
|
|
109
|
+
country('GB', 'United Kingdom', 'GBP', {
|
|
110
|
+
en: ['United Kingdom', 'UK', 'Great Britain', 'Britain', 'England'],
|
|
111
|
+
ru: ['Великобритания', 'Британия', 'Англия'],
|
|
112
|
+
uk: ['Велика Британія', 'Британія', 'Англія'],
|
|
113
|
+
ro: ['Regatul Unit', 'Marea Britanie'],
|
|
114
|
+
}),
|
|
115
|
+
country('US', 'United States', 'USD', {
|
|
116
|
+
en: ['United States', 'United States of America', 'USA', 'U.S.', 'US'],
|
|
117
|
+
ru: ['США', 'Соединенные Штаты', 'Соединённые Штаты'],
|
|
118
|
+
uk: ['США', 'Сполучені Штати'],
|
|
119
|
+
ro: ['Statele Unite', 'SUA'],
|
|
120
|
+
}),
|
|
121
|
+
country('CA', 'Canada', 'CAD', {
|
|
122
|
+
en: ['Canada'],
|
|
123
|
+
ru: ['Канада'],
|
|
124
|
+
uk: ['Канада'],
|
|
125
|
+
ro: ['Canada'],
|
|
126
|
+
}),
|
|
127
|
+
country('CN', 'China', 'CNY', {
|
|
128
|
+
en: ['China', "People's Republic of China", 'PRC'],
|
|
129
|
+
ru: ['Китай'],
|
|
130
|
+
uk: ['Китай'],
|
|
131
|
+
ro: ['China'],
|
|
132
|
+
all: ['中国', '中华人民共和国'],
|
|
133
|
+
}),
|
|
134
|
+
country('JP', 'Japan', 'JPY', {
|
|
135
|
+
en: ['Japan'],
|
|
136
|
+
ru: ['Япония'],
|
|
137
|
+
uk: ['Японія'],
|
|
138
|
+
ro: ['Japonia'],
|
|
139
|
+
all: ['日本'],
|
|
140
|
+
}),
|
|
141
|
+
country('KR', 'South Korea', 'KRW', {
|
|
142
|
+
en: ['South Korea', 'Republic of Korea', 'Korea'],
|
|
143
|
+
ru: ['Южная Корея', 'Корея'],
|
|
144
|
+
uk: ['Південна Корея', 'Корея'],
|
|
145
|
+
ro: ['Coreea de Sud', 'Coreea'],
|
|
146
|
+
all: ['대한민국', '한국'],
|
|
147
|
+
}),
|
|
148
|
+
country('TW', 'Taiwan', 'TWD', {
|
|
149
|
+
en: ['Taiwan'],
|
|
150
|
+
ru: ['Тайвань'],
|
|
151
|
+
uk: ['Тайвань'],
|
|
152
|
+
ro: ['Taiwan'],
|
|
153
|
+
all: ['臺灣', '台灣'],
|
|
154
|
+
}),
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
const COUNTRY_BY_CODE = new Map(COUNTRIES.map((item) => [item.code, item]));
|
|
158
|
+
|
|
159
|
+
export function canonicalCountry(value) {
|
|
160
|
+
if (!value) return null;
|
|
161
|
+
const direct = COUNTRY_BY_CODE.get(String(value).trim().toUpperCase());
|
|
162
|
+
if (direct) return direct.canonical;
|
|
163
|
+
return findCanonical(value, COUNTRIES)?.canonical || null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function canonicalCountryCode(value) {
|
|
167
|
+
if (!value) return null;
|
|
168
|
+
const direct = COUNTRY_BY_CODE.get(String(value).trim().toUpperCase());
|
|
169
|
+
if (direct) return direct.code;
|
|
170
|
+
return findCanonical(value, COUNTRIES)?.code || null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function countryByCode(value) {
|
|
174
|
+
return COUNTRY_BY_CODE.get(String(value || '').trim().toUpperCase()) || null;
|
|
175
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type CountryContext = Readonly<{
|
|
2
|
+
code: string;
|
|
3
|
+
country: string;
|
|
4
|
+
currency: string | null;
|
|
5
|
+
phoneCountry: string;
|
|
6
|
+
}>;
|
|
7
|
+
|
|
8
|
+
export function countryContext(value: unknown): CountryContext | null;
|
|
9
|
+
export function countryCurrency(value: unknown): string | null;
|
|
10
|
+
export function countryPhoneHint(value: unknown): string | null;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { canonicalCountryCode, countryByCode } from './countries.js';
|
|
2
|
+
|
|
3
|
+
export function countryContext(value) {
|
|
4
|
+
const code = canonicalCountryCode(value);
|
|
5
|
+
if (!code) return null;
|
|
6
|
+
const country = countryByCode(code);
|
|
7
|
+
if (!country) return null;
|
|
8
|
+
return Object.freeze({
|
|
9
|
+
code: country.code,
|
|
10
|
+
country: country.canonical,
|
|
11
|
+
currency: country.currency || null,
|
|
12
|
+
phoneCountry: country.code,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function countryCurrency(value) {
|
|
17
|
+
return countryContext(value)?.currency || null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function countryPhoneHint(value) {
|
|
21
|
+
return countryContext(value)?.phoneCountry || null;
|
|
22
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type CurrencyDisplay = Readonly<{
|
|
2
|
+
code: string;
|
|
3
|
+
symbol: string;
|
|
4
|
+
name: string;
|
|
5
|
+
}>;
|
|
6
|
+
|
|
7
|
+
export const CURRENCY_TERMS: readonly import('../index.d.ts').LexiconEntity[];
|
|
8
|
+
export const CURRENCY_SYMBOL_CANDIDATES: Readonly<Record<string, readonly string[]>>;
|
|
9
|
+
export function moneyCurrencyCandidatesFromText(value: unknown): readonly string[];
|
|
10
|
+
export function moneyCurrencyFromText(value: unknown, fallbackCurrency?: string | null): string | null;
|
|
11
|
+
export function moneyCurrencyPattern(): string;
|
|
12
|
+
export function currencyDisplay(code: unknown, locale?: string): CurrencyDisplay | null;
|
|
13
|
+
export function currencySymbol(code: unknown, locale?: string): string | null;
|
|
14
|
+
export function currencyName(code: unknown, locale?: string): string | null;
|
package/src/currency.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { CURRENCY_TERMS } from './money-lexicon.js';
|
|
2
|
+
|
|
3
|
+
export {
|
|
4
|
+
CURRENCY_SYMBOL_CANDIDATES,
|
|
5
|
+
CURRENCY_TERMS,
|
|
6
|
+
} from './money-lexicon.js';
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
moneyCurrencyCandidatesFromText,
|
|
10
|
+
moneyCurrencyFromText,
|
|
11
|
+
moneyCurrencyPattern,
|
|
12
|
+
} from './money-core.js';
|
|
13
|
+
|
|
14
|
+
const LOCALE_ALIASES = Object.freeze({
|
|
15
|
+
uzLatn: 'uz-Latn',
|
|
16
|
+
uzCyrl: 'uz-Cyrl',
|
|
17
|
+
kk: 'kk',
|
|
18
|
+
uk: 'uk',
|
|
19
|
+
ro: 'ro',
|
|
20
|
+
ru: 'ru',
|
|
21
|
+
en: 'en',
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
function normalizedLocale(locale) {
|
|
25
|
+
const raw = String(locale || 'en').trim();
|
|
26
|
+
return LOCALE_ALIASES[raw] || raw || 'en';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function supportedCurrency(code) {
|
|
30
|
+
const normalized = String(code || '').trim().toUpperCase();
|
|
31
|
+
return CURRENCY_TERMS.some((entry) => entry.canonical === normalized) ? normalized : null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function currencyPart(code, locale, currencyDisplay) {
|
|
35
|
+
try {
|
|
36
|
+
const parts = new Intl.NumberFormat(normalizedLocale(locale), {
|
|
37
|
+
style: 'currency',
|
|
38
|
+
currency: code,
|
|
39
|
+
currencyDisplay,
|
|
40
|
+
minimumFractionDigits: 0,
|
|
41
|
+
maximumFractionDigits: 0,
|
|
42
|
+
}).formatToParts(1);
|
|
43
|
+
return parts.find((part) => part.type === 'currency')?.value || code;
|
|
44
|
+
} catch {
|
|
45
|
+
return code;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Localized display metadata without a second hand-maintained currency catalog. */
|
|
50
|
+
export function currencyDisplay(code, locale = 'en') {
|
|
51
|
+
const canonical = supportedCurrency(code);
|
|
52
|
+
if (!canonical) return null;
|
|
53
|
+
return Object.freeze({
|
|
54
|
+
code: canonical,
|
|
55
|
+
symbol: currencyPart(canonical, locale, 'narrowSymbol'),
|
|
56
|
+
name: currencyPart(canonical, locale, 'name'),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function currencySymbol(code, locale = 'en') {
|
|
61
|
+
return currencyDisplay(code, locale)?.symbol || null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function currencyName(code, locale = 'en') {
|
|
65
|
+
return currencyDisplay(code, locale)?.name || null;
|
|
66
|
+
}
|
package/src/geo.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { aliasesToRegex, findCanonical } from './normalization.js';
|
|
2
|
+
import { deepFreeze, lexiconEntity } from './lexicon-core.js';
|
|
3
|
+
|
|
4
|
+
const entity = (canonical, aliases, extra = {}) => lexiconEntity(canonical, aliases, { type: extra.type || (extra.country ? 'city' : 'district'), ...(!extra.country ? { country: 'UZ', city: 'Tashkent' } : {}), ...extra });
|
|
5
|
+
|
|
6
|
+
export { UZ_CITIES, KZ_CITIES } from './geography-central-asia.js';
|
|
7
|
+
|
|
8
|
+
// Compatibility for the historical ./geo subpath. Canonical city ownership lives in geography.js.
|
|
9
|
+
export { CITIES, CITIES_BY_COUNTRY, canonicalCity } from './geography.js';
|
|
10
|
+
|
|
11
|
+
export const TASHKENT_DISTRICTS = Object.freeze([
|
|
12
|
+
entity('Almazar', { uzLatn: ['Olmazor', 'Olmazor tumani'], uzCyrl: ['Олмазор', 'Олмазор тумани'], ru: ['Алмазар', 'Алмазарский район'], en: ['Almazar', 'Olmazor district'] }),
|
|
13
|
+
entity('Bektemir', { uzLatn: ['Bektemir', 'Bektemir tumani'], uzCyrl: ['Бектемир', 'Бектемир тумани'], ru: ['Бектемир', 'Бектемирский район'], en: ['Bektemir'] }),
|
|
14
|
+
entity('Mirobod', { uzLatn: ['Mirobod', 'Mirobod tumani'], uzCyrl: ['Миробод', 'Миробод тумани'], ru: ['Мирабад', 'Мирабадский район'], en: ['Mirobod', 'Mirabad'] }),
|
|
15
|
+
entity('Mirzo Ulugbek', { uzLatn: ["Mirzo Ulug'bek", 'Mirzo Ulugbek', "Mirzo Ulug'bek tumani"], uzCyrl: ['Мирзо Улуғбек', 'Мирзо Улуғбек тумани'], ru: ['Мирзо-Улугбекский район', 'Мирзо Улугбек'], en: ['Mirzo Ulugbek', 'Mirzo Ulughbek'] }),
|
|
16
|
+
entity('Sergeli', { uzLatn: ['Sergeli', 'Sergeli tumani'], uzCyrl: ['Сергели', 'Сергели тумани'], ru: ['Сергелийский район', 'Сергели'], en: ['Sergeli'] }),
|
|
17
|
+
entity('Uchtepa', { uzLatn: ['Uchtepa', 'Uchtepa tumani'], uzCyrl: ['Учтепа', 'Учтепа тумани'], ru: ['Учтепинский район', 'Учтепа'], en: ['Uchtepa'] }),
|
|
18
|
+
entity('Chilanzar', { uzLatn: ['Chilonzor', 'Chilonzor tumani', 'Chilanzar'], uzCyrl: ['Чилонзор', 'Чилонзор тумани'], ru: ['Чиланзар', 'Чиланзарский район'], en: ['Chilanzar', 'Chilonzor'] }),
|
|
19
|
+
entity('Shaykhantahur', { uzLatn: ['Shayxontohur', 'Shayxontohur tumani', 'Shaykhantahur'], uzCyrl: ['Шайхонтоҳур', 'Шайхонтоҳур тумани', 'Шайхонтохур'], ru: ['Шайхантахур', 'Шайхантахурский район'], en: ['Shaykhantahur', 'Shayxontohur'] }),
|
|
20
|
+
entity('Yunusabad', { uzLatn: ['Yunusobod', 'Yunusobod tumani', 'Yunusabad'], uzCyrl: ['Юнусобод', 'Юнусобод тумани'], ru: ['Юнусабад', 'Юнусабадский район'], en: ['Yunusabad', 'Yunusobod'] }),
|
|
21
|
+
entity('Yakkasaray', { uzLatn: ['Yakkasaroy', 'Yakkasaroy tumani', 'Yakkasaray'], uzCyrl: ['Яккасарой', 'Яккасарой тумани'], ru: ['Яккасарай', 'Яккасарайский район'], en: ['Yakkasaray', 'Yakkasaroy'] }),
|
|
22
|
+
entity('Yangihayot', { uzLatn: ['Yangihayot', 'Yangihayot tumani'], uzCyrl: ['Янгиҳаёт', 'Янгиҳаёт тумани', 'Янгихаёт'], ru: ['Янгихаётский район', 'Янгихаёт'], en: ['Yangihayot'] }),
|
|
23
|
+
entity('Yashnobod', { uzLatn: ['Yashnobod', 'Yashnobod tumani'], uzCyrl: ['Яшнобод', 'Яшнобод тумани'], ru: ['Яшнабад', 'Яшнабадский район'], en: ['Yashnobod', 'Yashnabad'] }),
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
export function canonicalTashkentDistrict(value) {
|
|
27
|
+
return findCanonical(value, TASHKENT_DISTRICTS, { partial: true })?.canonical || null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function station(name, ru, en, line, aliases = []) {
|
|
31
|
+
const allAliases = [...new Set([name, ru, en, ...aliases])];
|
|
32
|
+
return deepFreeze({
|
|
33
|
+
canonical: name,
|
|
34
|
+
name,
|
|
35
|
+
type: 'metro',
|
|
36
|
+
country: 'UZ',
|
|
37
|
+
city: 'Tashkent',
|
|
38
|
+
line,
|
|
39
|
+
labels: { ru, en },
|
|
40
|
+
aliases: allAliases,
|
|
41
|
+
re: aliasesToRegex(allAliases),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const TASHKENT_METRO = Object.freeze([
|
|
46
|
+
station('Buyuk Ipak Yoli', 'Буюк Ипак Йули', 'Buyuk Ipak Yoli', 'chilonzor', ['Buyuk Ipak Yuli', "Buyuk Ipak Yo'li", 'Buyuk Ipak Yo‘li', 'Buyuk Ipak Yoʻli', 'Буюк Ипак Йўли', 'БИЙ', 'Максим Горький', 'Максима Горького', 'Горького', 'Maxim Gorky', 'Maksim Gorkiy']),
|
|
47
|
+
station('Pushkin', 'Пушкин', 'Pushkin', 'chilonzor'),
|
|
48
|
+
station('Hamid Olimjon', 'Хамид Алимджан', 'Hamid Olimjon', 'chilonzor', ['Хамид Олимжон', 'Hamid Alimjan', 'Hamid Alimjon']),
|
|
49
|
+
station('Amir Temur Xiyoboni', 'Амир Темур Хиёбони', 'Amir Temur Xiyoboni', 'chilonzor', ['Сквер', 'Amir Timur Square', 'Amir Temur']),
|
|
50
|
+
station('Mustaqillik Maydoni', 'Мустакиллик майдони', 'Mustaqillik Maydoni', 'chilonzor', ['Мустақиллик майдони', 'Площадь Независимости', 'Independence Square']),
|
|
51
|
+
station('Paxtakor', 'Пахтакор', 'Paxtakor', 'chilonzor', ['Pakhtakor']),
|
|
52
|
+
station('Xalqlar Dostligi', 'Халклар Дустлиги', 'Xalqlar Dostligi', 'chilonzor', ["Xalqlar Do'stligi", 'Xalqlar Do‘stligi', 'Xalqlar Doʻstligi', 'Халклар Дўстлиги', 'Халқлар Дўстлиги', 'Дружба народов', 'Bunyodkor', 'Бунёдкор']),
|
|
53
|
+
station('Milliy Bog', 'Миллий Бог', 'Milliy Bog', 'chilonzor', ["Milliy Bog'", 'Milliy Bog‘', 'Milliy Bogʻ', 'Миллий Боғ', 'Yoshlik', 'Ёшлик']),
|
|
54
|
+
station('Novza', 'Новза', 'Novza', 'chilonzor', ['Хамза', 'Hamza', 'Hamza metro', 'метро Хамза']),
|
|
55
|
+
station('Mirzo Ulugbek', 'Мирзо Улугбек', 'Mirzo Ulugbek', 'chilonzor', ["Mirzo Ulug'bek", 'Mirzo Ulug‘bek', 'Mirzo Ulugʻbek', 'Мирзо Улуғбек', 'М. Улугбек', 'метро М. Улугбек']),
|
|
56
|
+
station('Chilonzor', 'Чиланзар', 'Chilonzor', 'chilonzor', ['Чилонзор', 'Chilanzar', 'метро Чиланзар', 'Chilonzor metro']),
|
|
57
|
+
station('Olmazor', 'Алмазар', 'Olmazor', 'chilonzor', ['Олмазор', 'Almazar', 'Сабир Рахимов', 'Собир Рахимов', 'Sobir Raximov', 'Sabir Rakhimov']),
|
|
58
|
+
station('Choshtepa', 'Чаштепа', 'Choshtepa', 'chilonzor', ['Чоштепа']),
|
|
59
|
+
station('Ozgarish', 'Узгариш', 'Ozgarish', 'chilonzor', ["O'zgarish", 'O‘zgarish', 'Oʻzgarish', 'Ўзгариш']),
|
|
60
|
+
station('Sergeli', 'Сергели', 'Sergeli', 'chilonzor', ['метро Сергели', 'Sergeli metro']),
|
|
61
|
+
station('Yangihayot', 'Янгихаёт', 'Yangihayot', 'chilonzor', ['Янгиҳаёт', 'Янгихаят']),
|
|
62
|
+
station('Chinor', 'Чинар', 'Chinor', 'chilonzor', ['Чинор']),
|
|
63
|
+
station('Beruniy', 'Беруни', 'Beruniy', 'ozbekiston', ['Beruni']),
|
|
64
|
+
station('Tinchlik', 'Тинчлик', 'Tinchlik', 'ozbekiston'),
|
|
65
|
+
station('Chorsu', 'Чорсу', 'Chorsu', 'ozbekiston'),
|
|
66
|
+
station('Gafur Gulom', 'Гафур Гулям', 'Gafur Gulom', 'ozbekiston', ["G'afur G'ulom", 'G‘afur G‘ulom', 'Gʻafur Gʻulom', 'Ғафур Ғулом']),
|
|
67
|
+
station('Alisher Navoi', 'Алишер Навои', 'Alisher Navoi', 'ozbekiston', ['Alisher Navoiy', 'Алишер Навоий']),
|
|
68
|
+
station('Ozbekiston', 'Узбекистан', 'Ozbekiston', 'ozbekiston', ["O'zbekiston", 'O‘zbekiston', 'Oʻzbekiston', 'Ўзбекистон']),
|
|
69
|
+
station('Kosmonavtlar', 'Космонавтлар', 'Kosmonavtlar', 'ozbekiston', ['Космонавты']),
|
|
70
|
+
station('Oybek', 'Ойбек', 'Oybek', 'ozbekiston'),
|
|
71
|
+
station('Toshkent', 'Ташкент', 'Toshkent', 'ozbekiston', ['Тошкент', 'Tashkent metro', 'метро Ташкент']),
|
|
72
|
+
station('Mashinasozlar', 'Машинасозлар', 'Mashinasozlar', 'ozbekiston'),
|
|
73
|
+
station('Dostlik', 'Дустлик', 'Dostlik', 'ozbekiston', ["Do'stlik", 'Do‘stlik', 'Doʻstlik', 'Дўстлик']),
|
|
74
|
+
station('Turkiston', 'Туркистон', 'Turkiston', 'yunusobod', ['Туркестан']),
|
|
75
|
+
station('Yunusobod', 'Юнусабад', 'Yunusobod', 'yunusobod', ['Юнусобод', 'Yunusabad', 'метро Юнусабад', 'Yunusobod metro']),
|
|
76
|
+
station('Shahriston', 'Шахристан', 'Shahriston', 'yunusobod', ['Шахристон']),
|
|
77
|
+
station('Bodomzor', 'Бадамзар', 'Bodomzor', 'yunusobod', ['Бодомзор']),
|
|
78
|
+
station('Minor', 'Минор', 'Minor', 'yunusobod'),
|
|
79
|
+
station('Abdulla Qodiriy', 'Абдулла Кадыри', 'Abdulla Qodiriy', 'yunusobod', ['Абдулла Кодири', 'Абдулла Қодирий', 'Abdulla Kadiri']),
|
|
80
|
+
station('Yunus Rajabiy', 'Юнус Раджаби', 'Yunus Rajabiy', 'yunusobod', ['Yunus Rajabi']),
|
|
81
|
+
station('Ming Orik', 'Мингурик', 'Ming Orik', 'yunusobod', ["Ming O'rik", 'Ming O‘rik', 'Ming Oʻrik', 'Минг Урик', 'Мингўрик']),
|
|
82
|
+
station('Texnopark', 'Технопарк', 'Texnopark', 'circle', ['Technopark']),
|
|
83
|
+
station('Yashnobod', 'Яшнабад', 'Yashnobod', 'circle', ['Яшнобод']),
|
|
84
|
+
station('Tuzel', 'Тузель', 'Tuzel', 'circle'),
|
|
85
|
+
station('Olmos', 'Алмас', 'Olmos', 'circle', ['Олмос']),
|
|
86
|
+
station('Rohat', 'Рохат', 'Rohat', 'circle'),
|
|
87
|
+
station('Yangiobod', 'Янгиабад', 'Yangiobod', 'circle', ['Янгиобод']),
|
|
88
|
+
station('Qoyliq', 'Куйлюк', 'Qoyliq', 'circle', ['Qo‘yliq', "Qo'yliq", 'Qoʻyliq', 'Қўйлиқ', 'Куйлик', 'Куйлюк метро']),
|
|
89
|
+
station('Matonat', 'Матонат', 'Matonat', 'circle'),
|
|
90
|
+
station('Qiyot', 'Кият', 'Qiyot', 'circle', ['Киёт', 'Қиёт']),
|
|
91
|
+
station('Tolariq', 'Толарык', 'Tolariq', 'circle', ['Толарик', 'Толариқ']),
|
|
92
|
+
station('Xonobod', 'Хонабад', 'Xonobod', 'circle', ['Ханабад']),
|
|
93
|
+
station('Quruvchilar', 'Курувчилар', 'Quruvchilar', 'circle', ['Қурувчилар']),
|
|
94
|
+
station('Turon', 'Туран', 'Turon', 'circle', ['Турон']),
|
|
95
|
+
station('Qipchoq', 'Кипчак', 'Qipchoq', 'circle', ['Қипчоқ']),
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
const TASHKENT_METRO_BY_NAME = new Map(TASHKENT_METRO.map((item) => [item.name, item]));
|
|
99
|
+
|
|
100
|
+
export function tashkentMetroStation(value) {
|
|
101
|
+
if (!value) return null;
|
|
102
|
+
const direct = TASHKENT_METRO_BY_NAME.get(String(value));
|
|
103
|
+
if (direct) return direct;
|
|
104
|
+
return TASHKENT_METRO.find((item) => item.re.test(String(value))) || null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function canonicalTashkentMetro(value) {
|
|
108
|
+
return tashkentMetroStation(value)?.canonical || null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function tashkentMetroLabels() {
|
|
112
|
+
return Object.fromEntries(TASHKENT_METRO.map((item) => [item.name, { ru: item.labels.ru, en: item.labels.en, line: item.line }]));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const area = (name, aliases) => deepFreeze({ canonical: name, name, type: 'local_area', country: 'UZ', city: 'Tashkent', aliases });
|
|
116
|
+
|
|
117
|
+
export const TASHKENT_AREAS = Object.freeze({
|
|
118
|
+
Almazar: Object.freeze([
|
|
119
|
+
area('Sebzar', ['себзар', 'sebzar', 'ц 17', 'ц 18', 'c 17', 'c 18']),
|
|
120
|
+
area('Karakamysh-1/2', ['каракамыш 1 2', 'қорақамиш 1 2', 'qoraqamish 1 2', 'karakamish 1 2']),
|
|
121
|
+
area('Karakamysh-2/3', ['каракамыш 2 3', 'қорақамиш 2 3', 'qoraqamish 2 3', 'karakamish 2 3']),
|
|
122
|
+
area('Karakamysh-2/4', ['каракамыш 2 4', 'қорақамиш 2 4', 'qoraqamish 2 4', 'karakamish 2 4']),
|
|
123
|
+
area('Karakamysh-2/5', ['каракамыш 2 5', 'қорақамиш 2 5', 'qoraqamish 2 5', 'karakamish 2 5']),
|
|
124
|
+
area('Olympia', ['олимпия', 'olimpiya', 'olympia']), area('Vuzgorodok', ['вузгородок', 'вуз городок', 'vuzgorodok']),
|
|
125
|
+
area('Medgorodok', ['медгородок', 'мед городок', 'medgorodok']), area('Takhtapul', ['тахтапуль', 'тахтапул', 'taxtapul', 'takhtapul']),
|
|
126
|
+
area('Chimbay', ['чимбай', 'chimboy', 'chimbay']),
|
|
127
|
+
]),
|
|
128
|
+
Mirobod: Object.freeze([
|
|
129
|
+
area('Hospitalny', ['госпитальный', 'госпиталка', 'hospitalny']), area('Lolazor', ['лолазор', 'lolazor']),
|
|
130
|
+
area('Oltinkul', ['алтынкуль', 'олтинкул', 'олтинкўл', 'oltinkol', 'oltinkul']), area('Movarounnahr', ['мавераннахр', 'мовароуннахр', 'movarounnahr']),
|
|
131
|
+
]),
|
|
132
|
+
'Mirzo Ulugbek': Object.freeze([
|
|
133
|
+
area('Buyuk Ipak Yuli', ['буюк ипак йули', 'буюк ипак йўли', 'buyuk ipak yuli', "buyuk ipak yo'li", 'ц 1', 'c 1']),
|
|
134
|
+
area('Alay', ['олой', 'алайский', 'алайск', 'alay', 'ц 2', 'c 2']),
|
|
135
|
+
...[1, 2, 3, 4, 6].map((n) => area(`Karasu-${n}`, [`карасу ${n}`, `қорасув ${n}`, `qorasuv ${n}`, `karasu ${n}`])),
|
|
136
|
+
...[1, 2, 3, 4].map((n) => area(`TTZ-${n}`, [`ттз ${n}`, `ttz ${n}`])),
|
|
137
|
+
area('Yalangach', ['ялангач', 'yalangach', "yalang'och"]), area('Feruza', ['феруза', 'feruza']), area('Geofizika', ['геофизика', 'поселок геофизиков', 'geofizika']),
|
|
138
|
+
]),
|
|
139
|
+
Sergeli: Object.freeze([
|
|
140
|
+
area('Sergeli Car Bazaar', ['сергели машинный базар', 'сергели машина бозор', 'sergeli moshina bozor', 'sergile moshena bozor', 'sergele moshina bozor']),
|
|
141
|
+
area('Yangi Sergeli', ['янги сергели', 'yangi sergeli']), area('Stroygorod', ['стройгород', 'stroygorod']),
|
|
142
|
+
]),
|
|
143
|
+
Chilanzar: Object.freeze([
|
|
144
|
+
area('Nakkoshlik', ['наккошлык', 'наққошлик', 'naqqoshlik']), area('Al-Khorezmi-1', ['аль хорезми 1', 'ал хорезми 1', 'al xorazmiy 1', 'al khorezmi 1']),
|
|
145
|
+
]),
|
|
146
|
+
Shaykhantahur: Object.freeze([
|
|
147
|
+
area('Labzak', ['лабзак', 'labzak', 'ц 13', 'c 13']), area('Khadra', ['хадра', 'xadra', 'khadra', 'ц 14', 'c 14']),
|
|
148
|
+
area('Jangoh', ['джангох', 'жангох', 'jangoh', 'ц 15', 'c 15']), area('Karatash', ['караташ', 'қоратош', 'qoratosh', 'karatash']),
|
|
149
|
+
area('Chorsu', ['чорсу', 'chorsu']), area('Beshagach', ['бешагач', "beshyog'och", 'beshagach']), area('Beltepa', ['белтепа', 'beltepa']),
|
|
150
|
+
]),
|
|
151
|
+
Yunusabad: Object.freeze([
|
|
152
|
+
area('Kashgar', ['кашгар', 'қашқар', 'qashqar', 'kashgar', 'ц 4', 'c 4']), area('Kiyot', ['киёт', 'қиёт', 'qiyot', 'kiyot', 'ц 5', 'c 5']),
|
|
153
|
+
area('Minor', ['минор', 'minor', 'ц 6', 'c 6']), area('TashGRES', ['ташгрэс', 'tashgres']),
|
|
154
|
+
]),
|
|
155
|
+
Yakkasaray: Object.freeze([
|
|
156
|
+
area('Bashlyk', ['башлык', 'бошлиқ', 'boshliq', 'bashlyk']), area('Kushbegi', ['кушбеги', 'қушбеги', 'qushbegi', 'kushbegi']),
|
|
157
|
+
area('Rakat', ['ракат', 'rakat']), area('Rakatboshi', ['ракатбоши', 'rakatboshi']),
|
|
158
|
+
]),
|
|
159
|
+
Yangihayot: Object.freeze([
|
|
160
|
+
area('Uzgarish', ['узгарыш', 'ўзгариш', "o'zgarish", 'uzgarish']), area('Dustlik-1', ['дустлик 1', 'дўстлик 1', "do'stlik 1", 'dustlik 1']),
|
|
161
|
+
area('Dustlik-2', ['дустлик 2', 'дўстлик 2', "do'stlik 2", 'dustlik 2']), area('Yangi Choshtepa', ['янги чоштепа', 'yangi choshtepa']), area('Sputnik', ['спутник', 'йўлдош', "yo'ldosh", 'yoldosh']),
|
|
162
|
+
]),
|
|
163
|
+
Yashnobod: Object.freeze([
|
|
164
|
+
area('Kuylyuk Center', ['куйлюк центр', 'куйлик центр', "qo'yliq markaz", 'kuylyuk center']),
|
|
165
|
+
...[1, 2, 3, 4].map((n) => area(`Aviasozlar-${n}`, [`авиасозлар ${n}`, `городок авиастроителей ${n}`, `aviasozlar ${n}`])),
|
|
166
|
+
...[1, 2, 3, 4].map((n) => area(`Tuzel-${n}`, [`тузель ${n}`, `tuzel ${n}`])),
|
|
167
|
+
area('Tashselmash', ['ташсельмаш', 'tashselmash']), area('Alimkent', ['алимкент', 'olimkent', 'alimkent']), area('Shohimardon', ['шохимардон', 'shohimardon']),
|
|
168
|
+
]),
|
|
169
|
+
});
|