@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
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { lexiconEntity } from './lexicon-core.js';
|
|
2
|
+
|
|
3
|
+
const entity = (canonical, aliases, extra = {}) => lexiconEntity(canonical, aliases, { type: 'city', ...extra });
|
|
4
|
+
|
|
5
|
+
export const UZ_CITIES = Object.freeze([
|
|
6
|
+
entity('Tashkent', { uzLatn: ['Toshkent'], uzCyrl: ['Тошкент'], ru: ['Ташкент'], en: ['Tashkent'] }, { country: 'UZ' }),
|
|
7
|
+
entity('Samarkand', { uzLatn: ['Samarqand'], uzCyrl: ['Самарқанд'], ru: ['Самарканд'], en: ['Samarkand'] }, { country: 'UZ' }),
|
|
8
|
+
entity('Bukhara', { uzLatn: ['Buxoro'], uzCyrl: ['Бухоро'], ru: ['Бухара'], en: ['Bukhara'] }, { country: 'UZ' }),
|
|
9
|
+
entity('Namangan', { uzLatn: ['Namangan'], uzCyrl: ['Наманган'], ru: ['Наманган'], en: ['Namangan'] }, { country: 'UZ' }),
|
|
10
|
+
entity('Andijan', { uzLatn: ['Andijon', 'Andijan', 'Anjon', 'Anjan'], uzCyrl: ['Андижон'], ru: ['Андижан'], en: ['Andijan'] }, { country: 'UZ' }),
|
|
11
|
+
entity('Fergana', { uzLatn: ["Farg'ona", 'Farg‘ona', 'Fargʻona', 'Fargona'], uzCyrl: ['Фарғона'], ru: ['Фергана', 'Фаргана'], en: ['Fergana'] }, { country: 'UZ' }),
|
|
12
|
+
entity('Nukus', { uzLatn: ['Nukus'], uzCyrl: ['Нукус'], ru: ['Нукус'], en: ['Nukus'] }, { country: 'UZ' }),
|
|
13
|
+
entity('Qarshi', { uzLatn: ['Qarshi', 'Karshi'], uzCyrl: ['Қарши'], ru: ['Карши'], en: ['Qarshi', 'Karshi'] }, { country: 'UZ' }),
|
|
14
|
+
entity('Urgench', { uzLatn: ['Urganch', 'Urgench'], uzCyrl: ['Урганч'], ru: ['Ургенч'], en: ['Urgench'] }, { country: 'UZ' }),
|
|
15
|
+
entity('Khiva', { uzLatn: ['Xiva', 'Khiva'], uzCyrl: ['Хива'], ru: ['Хива'], en: ['Khiva'] }, { country: 'UZ' }),
|
|
16
|
+
entity('Navoiy', { uzLatn: ['Navoiy', 'Navoi'], uzCyrl: ['Навоий'], ru: ['Навои'], en: ['Navoiy', 'Navoi'] }, { country: 'UZ' }),
|
|
17
|
+
entity('Jizzakh', { uzLatn: ['Jizzax', 'Jizzakh'], uzCyrl: ['Жиззах'], ru: ['Джизак'], en: ['Jizzakh'] }, { country: 'UZ' }),
|
|
18
|
+
entity('Termez', { uzLatn: ['Termiz', 'Termez'], uzCyrl: ['Термиз'], ru: ['Термез'], en: ['Termez'] }, { country: 'UZ' }),
|
|
19
|
+
entity('Gulistan', { uzLatn: ['Guliston', 'Gulistan'], uzCyrl: ['Гулистон'], ru: ['Гулистан'], en: ['Gulistan'] }, { country: 'UZ' }),
|
|
20
|
+
entity('Chirchiq', { uzLatn: ['Chirchiq', 'Chirchik'], uzCyrl: ['Чирчиқ'], ru: ['Чирчик'], en: ['Chirchiq'] }, { country: 'UZ' }),
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
export const KZ_CITIES = Object.freeze([
|
|
24
|
+
entity('Almaty', { kk: ['Алматы'], ru: ['Алматы', 'Алма-Ата', 'Алма Ата'], en: ['Almaty', 'Alma-Ata', 'Alma Ata'] }, { country: 'KZ' }),
|
|
25
|
+
entity('Astana', { kk: ['Астана', 'Нұр-Сұлтан', 'Нұр Сұлтан'], ru: ['Астана', 'Нур-Султан', 'Нур Султан'], en: ['Astana', 'Nur-Sultan', 'Nur Sultan'] }, { country: 'KZ' }),
|
|
26
|
+
entity('Shymkent', { kk: ['Шымкент'], ru: ['Шымкент', 'Чимкент'], en: ['Shymkent', 'Chimkent'] }, { country: 'KZ' }),
|
|
27
|
+
entity('Karaganda', { kk: ['Қарағанды'], ru: ['Караганда'], en: ['Karaganda', 'Qaragandy'] }, { country: 'KZ' }),
|
|
28
|
+
entity('Aktobe', { kk: ['Ақтөбе'], ru: ['Актобе'], en: ['Aktobe', 'Aqtobe'] }, { country: 'KZ' }),
|
|
29
|
+
entity('Atyrau', { kk: ['Атырау'], ru: ['Атырау'], en: ['Atyrau'] }, { country: 'KZ' }),
|
|
30
|
+
entity('Oral', { kk: ['Орал'], ru: ['Уральск', 'Орал'], en: ['Oral', 'Uralsk'] }, { country: 'KZ' }),
|
|
31
|
+
entity('Taraz', { kk: ['Тараз'], ru: ['Тараз', 'Джамбул'], en: ['Taraz'] }, { country: 'KZ' }),
|
|
32
|
+
entity('Pavlodar', { kk: ['Павлодар'], ru: ['Павлодар'], en: ['Pavlodar'] }, { country: 'KZ' }),
|
|
33
|
+
entity('Semey', { kk: ['Семей'], ru: ['Семей', 'Семипалатинск'], en: ['Semey', 'Semipalatinsk'] }, { country: 'KZ' }),
|
|
34
|
+
entity('Kostanay', { kk: ['Қостанай'], ru: ['Костанай'], en: ['Kostanay', 'Qostanay'] }, { country: 'KZ' }),
|
|
35
|
+
entity('Kyzylorda', { kk: ['Қызылорда'], ru: ['Кызылорда'], en: ['Kyzylorda', 'Qyzylorda'] }, { country: 'KZ' }),
|
|
36
|
+
entity('Aktau', { kk: ['Ақтау'], ru: ['Актау'], en: ['Aktau', 'Aqtau'] }, { country: 'KZ' }),
|
|
37
|
+
entity('Oskemen', { kk: ['Өскемен'], ru: ['Усть-Каменогорск'], en: ['Oskemen', 'Ust-Kamenogorsk'] }, { country: 'KZ' }),
|
|
38
|
+
entity('Petropavl', { kk: ['Петропавл'], ru: ['Петропавловск'], en: ['Petropavl', 'Petropavlovsk'] }, { country: 'KZ' }),
|
|
39
|
+
entity('Turkistan', { kk: ['Түркістан'], ru: ['Туркестан'], en: ['Turkistan', 'Turkestan'] }, { country: 'KZ' }),
|
|
40
|
+
entity('Taldykorgan', { kk: ['Талдықорған'], ru: ['Талдыкорган'], en: ['Taldykorgan', 'Taldyqorgan'] }, { country: 'KZ' }),
|
|
41
|
+
entity('Kokshetau', { kk: ['Көкшетау'], ru: ['Кокшетау'], en: ['Kokshetau'] }, { country: 'KZ' }),
|
|
42
|
+
]);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type DetectedCity = Readonly<{
|
|
2
|
+
canonical: string;
|
|
3
|
+
country: string | null;
|
|
4
|
+
}>;
|
|
5
|
+
|
|
6
|
+
export const HIRING_GLOBAL_CITIES: readonly Readonly<{
|
|
7
|
+
canonical: string;
|
|
8
|
+
country: string;
|
|
9
|
+
type: 'city';
|
|
10
|
+
aliases: Readonly<Record<string, readonly string[]>>;
|
|
11
|
+
}>[];
|
|
12
|
+
|
|
13
|
+
export function detectCountryCodeFromText(value: unknown): string | null;
|
|
14
|
+
export function detectCityFromText(value: unknown, country?: string | null): DetectedCity | null;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { COUNTRIES, canonicalCountryCode } from './countries.js';
|
|
2
|
+
import { CITIES } from './geography.js';
|
|
3
|
+
import { aliasesOf, aliasesToRegex, normalizeForMatch } from './normalization.js';
|
|
4
|
+
|
|
5
|
+
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
6
|
+
|
|
7
|
+
function cityInflectionRegex(aliases) {
|
|
8
|
+
const cyrillic = [...new Set(aliases.filter((alias) => /\p{Script=Cyrillic}/u.test(alias)))];
|
|
9
|
+
if (!cyrillic.length) return null;
|
|
10
|
+
const patterns = cyrillic.map((alias) => {
|
|
11
|
+
const maxSuffix = alias.replace(/[^\p{L}\p{N}]/gu, '').length > 3 ? 5 : 3;
|
|
12
|
+
return `${escapeRegex(alias)}(?:\\p{Script=Cyrillic}{0,${maxSuffix}})`;
|
|
13
|
+
});
|
|
14
|
+
return new RegExp(`(?<![\\p{L}\\p{N}])(?:${patterns.join('|')})(?![\\p{L}\\p{N}])`, 'iu');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const CITY_MATCHERS = CITIES.map((item) => {
|
|
18
|
+
const aliases = [item.canonical, ...aliasesOf(item)];
|
|
19
|
+
return Object.freeze({
|
|
20
|
+
item,
|
|
21
|
+
exact: aliasesToRegex(aliases),
|
|
22
|
+
inflected: cityInflectionRegex(aliases),
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const COUNTRY_MATCHERS = COUNTRIES.map((item) => {
|
|
27
|
+
// Two-letter country codes are intentionally excluded from arbitrary prose:
|
|
28
|
+
// e.g. English "us" must not make a vacancy a US role. Exact ISO-2 values
|
|
29
|
+
// are still handled by canonicalCountryCode().
|
|
30
|
+
const aliases = [item.canonical, ...aliasesOf(item)]
|
|
31
|
+
.filter((alias) => normalizeForMatch(alias).replace(/\s/g, '').length > 2);
|
|
32
|
+
return Object.freeze({ item, re: aliasesToRegex(aliases) });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const US_STATE_RE = /\b[A-Z][A-Za-z.'-]+(?:\s+[A-Z][A-Za-z.'-]+){0,3}\s*,?\s+(?:AL|AK|AZ|AR|CA|CO|CT|DE|FL|GA|HI|ID|IL|IN|IA|KS|KY|LA|ME|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VT|VA|WA|WV|WI|WY|DC)\b/;
|
|
36
|
+
|
|
37
|
+
/** Detect an ISO-2 country from a country alias, known city alias, or US city/state location. */
|
|
38
|
+
export function detectCountryCodeFromText(value) {
|
|
39
|
+
const text = String(value || '').trim();
|
|
40
|
+
if (!text) return null;
|
|
41
|
+
|
|
42
|
+
const exact = canonicalCountryCode(text);
|
|
43
|
+
if (exact) return exact;
|
|
44
|
+
|
|
45
|
+
const country = COUNTRY_MATCHERS.find(({ re }) => re.test(text))?.item;
|
|
46
|
+
if (country?.code) return country.code;
|
|
47
|
+
|
|
48
|
+
// Keep dotted U.S. and explicit "remote US" support without treating the
|
|
49
|
+
// ordinary English pronoun "us" as a geography signal.
|
|
50
|
+
if (/\bU\.S\.?\b/.test(text) || /\bremote\s+us\b/i.test(text) || US_STATE_RE.test(text)) return 'US';
|
|
51
|
+
|
|
52
|
+
return detectCityFromText(text)?.country || null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Detect a known city in free text, including common Cyrillic case inflections. */
|
|
56
|
+
export function detectCityFromText(value, country = null) {
|
|
57
|
+
const text = String(value || '');
|
|
58
|
+
if (!text) return null;
|
|
59
|
+
const code = country ? canonicalCountryCode(country) : null;
|
|
60
|
+
const match = CITY_MATCHERS.find(({ item, exact, inflected }) =>
|
|
61
|
+
(!code || item.country === code) && (exact.test(text) || Boolean(inflected?.test(text))));
|
|
62
|
+
if (!match) return null;
|
|
63
|
+
return Object.freeze({ canonical: match.item.canonical, country: match.item.country || null });
|
|
64
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type GeographyDisplayKind = 'country' | 'region' | 'city' | 'district' | 'metro' | 'any';
|
|
2
|
+
|
|
3
|
+
export const GEOGRAPHY_DISPLAY_NAMES: Readonly<Record<string, Readonly<{
|
|
4
|
+
country: Readonly<Record<string, string>>;
|
|
5
|
+
city: Readonly<Record<string, string>>;
|
|
6
|
+
region?: Readonly<Record<string, string>>;
|
|
7
|
+
district: Readonly<Record<string, string>>;
|
|
8
|
+
metro: Readonly<Record<string, string>>;
|
|
9
|
+
metroAlias: Readonly<Record<string, string>>;
|
|
10
|
+
}>>>;
|
|
11
|
+
|
|
12
|
+
export function geographyDisplayName(value: unknown, locale?: string, kind?: GeographyDisplayKind): string;
|
|
13
|
+
export function geographyMetroLabelWithAlias(value: unknown, locale?: string): string;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { COUNTRIES } from './countries.js';
|
|
2
|
+
import { CITIES, REGIONS } from './geography.js';
|
|
3
|
+
|
|
4
|
+
// Centralized presentation names for canonical geography values.
|
|
5
|
+
// Consumers must not maintain their own country/city/district/metro display dictionaries.
|
|
6
|
+
|
|
7
|
+
export const GEOGRAPHY_DISPLAY_NAMES = Object.freeze({
|
|
8
|
+
ru: Object.freeze({
|
|
9
|
+
country: Object.freeze({ UZ: 'Узбекистан', KZ: 'Казахстан', UA: 'Украина', RO: 'Румыния', KG: 'Кыргызстан' }),
|
|
10
|
+
city: Object.freeze({
|
|
11
|
+
Tashkent: 'Ташкент', Samarkand: 'Самарканд', Bukhara: 'Бухара', Namangan: 'Наманган',
|
|
12
|
+
Andijan: 'Андижан', Fergana: 'Фергана', Nukus: 'Нукус', Navoi: 'Навои', Navoiy: 'Навои', Jizzakh: 'Джизак',
|
|
13
|
+
Termez: 'Термез', Qarshi: 'Карши', Urgench: 'Ургенч', Gulistan: 'Гулистан', Chirchiq: 'Чирчик',
|
|
14
|
+
'Tashkent Region': 'Ташкентская область', Karakalpakstan: 'Каракалпакстан', Kashkadarya: 'Кашкадарья',
|
|
15
|
+
Surkhandarya: 'Сурхандарья', Syrdarya: 'Сырдарья', Khorezm: 'Хорезм',
|
|
16
|
+
Almaty: 'Алматы', Astana: 'Астана', Shymkent: 'Шымкент', Karaganda: 'Караганда',
|
|
17
|
+
Aktobe: 'Актобе', Atyrau: 'Атырау', Oral: 'Уральск', Taraz: 'Тараз', Pavlodar: 'Павлодар',
|
|
18
|
+
Semey: 'Семей', Kostanay: 'Костанай', Kyzylorda: 'Кызылорда', Aktau: 'Актау', Oskemen: 'Усть-Каменогорск',
|
|
19
|
+
Kyiv: 'Киев', Lviv: 'Львов', Odesa: 'Одесса', Kharkiv: 'Харьков', Dnipro: 'Днепр',
|
|
20
|
+
Vinnytsia: 'Винница', 'Ivano-Frankivsk': 'Ивано-Франковск', Lutsk: 'Луцк', Chernivtsi: 'Черновцы',
|
|
21
|
+
Zaporizhzhia: 'Запорожье', Poltava: 'Полтава', Rivne: 'Ровно', Ternopil: 'Тернополь',
|
|
22
|
+
Uzhhorod: 'Ужгород', Khmelnytskyi: 'Хмельницкий', Zhytomyr: 'Житомир', Cherkasy: 'Черкассы',
|
|
23
|
+
Chernihiv: 'Чернигов', Sumy: 'Сумы', Mykolaiv: 'Николаев', Kropyvnytskyi: 'Кропивницкий',
|
|
24
|
+
Kherson: 'Херсон', 'Kryvyi Rih': 'Кривой Рог', Kremenchuk: 'Кременчуг', 'Bila Tserkva': 'Белая Церковь',
|
|
25
|
+
Kamianske: 'Каменское', Vyshneve: 'Вишневое', Boryspil: 'Борисполь', Vyshhorod: 'Вышгород',
|
|
26
|
+
Oleksandriia: 'Александрия', Pavlohrad: 'Павлоград', Nikopol: 'Никополь', Drohobych: 'Дрогобыч',
|
|
27
|
+
Stryi: 'Стрый', Kolomyia: 'Коломыя', Kalush: 'Калуш', 'Kamianets-Podilskyi': 'Каменец-Подольский',
|
|
28
|
+
Izmail: 'Измаил',
|
|
29
|
+
Bucharest: 'Бухарест', 'Cluj-Napoca': 'Клуж-Напока', Timisoara: 'Тимишоара', Iasi: 'Яссы',
|
|
30
|
+
Brasov: 'Брашов', Constanta: 'Констанца', Oradea: 'Орадя', Sibiu: 'Сибиу',
|
|
31
|
+
}),
|
|
32
|
+
district: Object.freeze({
|
|
33
|
+
Chilanzar: 'Чиланзар', Yunusabad: 'Юнусабад', 'Mirzo Ulugbek': 'Мирзо-Улугбек',
|
|
34
|
+
Yakkasaray: 'Яккасарай', Shaykhantahur: 'Шайхантахур', Yashnobod: 'Яшнабад', Sergeli: 'Сергели',
|
|
35
|
+
Uchtepa: 'Учтепа', Mirobod: 'Мирабад', Bektemir: 'Бектемир', Olmazor: 'Алмазар',
|
|
36
|
+
Almaly: 'Алмалинский', Bostandyk: 'Бостандыкский', Medeu: 'Медеуский', Auezov: 'Ауэзовский',
|
|
37
|
+
Turksib: 'Турксибский', Nauryzbay: 'Наурызбайский', Alatau: 'Алатауский', Zhetysu: 'Жетысуский',
|
|
38
|
+
Podil: 'Подол', Pechersk: 'Печерск', Pecherskyi: 'Печерский', Obolon: 'Оболонь',
|
|
39
|
+
Shevchenkivskyi: 'Шевченковский', Solomianskyi: 'Соломенский', Darnytskyi: 'Дарницкий',
|
|
40
|
+
Holosiivskyi: 'Голосеевский', Dniprovskyi: 'Днепровский', Sviatoshynskyi: 'Святошинский',
|
|
41
|
+
Desnianskyi: 'Деснянский', Prymorskyi: 'Приморский', Frankivskyi: 'Франковский',
|
|
42
|
+
Tsentralnyi: 'Центральный', 'Tsentralno-Miskyi': 'Центрально-Городской', Tsentr: 'Центр',
|
|
43
|
+
Prospekt: 'Проспект', Ruska: 'Русская', Hraviton: 'Гравитон', Komarova: 'Комарова', Roscha: 'Роща',
|
|
44
|
+
Sadgora: 'Садгора', Avtovokzal: 'Автовокзал', Pipera: 'Пипера', Militari: 'Милитари',
|
|
45
|
+
'Drumul Taberei': 'Друмул Таберей', Titan: 'Титан', Berceni: 'Берчень', Floreasca: 'Флоряска',
|
|
46
|
+
Dorobanti: 'Доробанць', Cotroceni: 'Котрочень',
|
|
47
|
+
}),
|
|
48
|
+
metro: Object.freeze({
|
|
49
|
+
'Buyuk Ipak Yoli': 'Буюк Ипак Йули', Pushkin: 'Пушкин', 'Hamid Olimjon': 'Хамид Алимджан',
|
|
50
|
+
'Amir Temur Xiyoboni': 'Амир Темур Хиёбони', 'Mustaqillik Maydoni': 'Мустакиллик майдони',
|
|
51
|
+
Paxtakor: 'Пахтакор', 'Xalqlar Dostligi': 'Халклар Дустлиги', 'Milliy Bog': 'Миллий Бог', Novza: 'Новза',
|
|
52
|
+
'Mirzo Ulugbek': 'Мирзо Улугбек', Chilonzor: 'Чиланзар', Olmazor: 'Алмазар', Choshtepa: 'Чаштепа',
|
|
53
|
+
Ozgarish: 'Узгариш', Sergeli: 'Сергели', Yangihayot: 'Янгихаёт', Chinor: 'Чинар', Beruniy: 'Беруни',
|
|
54
|
+
Tinchlik: 'Тинчлик', Chorsu: 'Чорсу', 'Gafur Gulom': 'Гафур Гулям', 'Alisher Navoi': 'Алишер Навои',
|
|
55
|
+
Ozbekiston: 'Узбекистан', Kosmonavtlar: 'Космонавтлар', Oybek: 'Ойбек', Toshkent: 'Ташкент',
|
|
56
|
+
Mashinasozlar: 'Машинасозлар', Dostlik: 'Дустлик', Turkiston: 'Туркистон', Yunusobod: 'Юнусабад',
|
|
57
|
+
Shahriston: 'Шахристан', Bodomzor: 'Бадамзар', Minor: 'Минор', 'Abdulla Qodiriy': 'Абдулла Кадыри',
|
|
58
|
+
'Yunus Rajabiy': 'Юнус Раджаби', 'Ming Orik': 'Мингурик', Texnopark: 'Технопарк', Yashnobod: 'Яшнабад',
|
|
59
|
+
Tuzel: 'Тузель', Olmos: 'Алмас', Rohat: 'Рохат', Yangiobod: 'Янгиабад', Qoyliq: 'Куйлюк', Matonat: 'Матонат',
|
|
60
|
+
Qiyot: 'Кият', Tolariq: 'Толарык', Xonobod: 'Хонабад', Quruvchilar: 'Курувчилар', Turon: 'Туран', Qipchoq: 'Кипчак',
|
|
61
|
+
}),
|
|
62
|
+
metroAlias: Object.freeze({
|
|
63
|
+
'Buyuk Ipak Yoli': 'Максим Горький', Novza: 'Хамза',
|
|
64
|
+
'Amir Temur Xiyoboni': 'Сквер Октябрьской Революции', 'Mustaqillik Maydoni': 'Площадь Ленина',
|
|
65
|
+
'Milliy Bog': 'Национальный парк', Yunusobod: 'Фахрийлар чойхонаси',
|
|
66
|
+
'Xalqlar Dostligi': 'Дружба народов', Ozbekiston: 'Узбекистан', Mashinasozlar: 'Машиностроителей',
|
|
67
|
+
Dostlik: 'Дружба', Tinchlik: 'Мир',
|
|
68
|
+
}),
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
function languageKey(locale) {
|
|
73
|
+
return String(locale || 'en').toLowerCase().split(/[-_]/)[0];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function preferredEntityLabel(entry, locale) {
|
|
77
|
+
if (!entry) return null;
|
|
78
|
+
const key = languageKey(locale);
|
|
79
|
+
const aliases = entry.aliases?.[key] || entry.aliases?.all || entry.aliases?.en || [];
|
|
80
|
+
return aliases[0] || entry.canonical || null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function canonicalEntityLabel(catalog, value, locale) {
|
|
84
|
+
const entry = catalog.find((item) => item.canonical === value);
|
|
85
|
+
return preferredEntityLabel(entry, locale);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function geographyDisplayName(value, locale = 'en', kind = 'any') {
|
|
89
|
+
const text = String(value || '').trim();
|
|
90
|
+
if (!text) return '';
|
|
91
|
+
const language = languageKey(locale);
|
|
92
|
+
const tables = GEOGRAPHY_DISPLAY_NAMES[language];
|
|
93
|
+
if (kind === 'country') {
|
|
94
|
+
const code = text.toUpperCase();
|
|
95
|
+
const explicit = tables?.country?.[code];
|
|
96
|
+
if (explicit) return explicit;
|
|
97
|
+
return preferredEntityLabel(COUNTRIES.find((item) => item.code === code || item.canonical === text), locale) || text;
|
|
98
|
+
}
|
|
99
|
+
if (kind === 'city') return tables?.city?.[text] || canonicalEntityLabel(CITIES, text, locale) || text;
|
|
100
|
+
if (kind === 'region') return tables?.region?.[text] || canonicalEntityLabel(REGIONS, text, locale) || text;
|
|
101
|
+
if (kind === 'district') return tables?.district?.[text] || text;
|
|
102
|
+
if (kind === 'metro') return tables?.metro?.[text] || text;
|
|
103
|
+
return tables?.country?.[text.toUpperCase()] || tables?.city?.[text] || tables?.region?.[text] || tables?.district?.[text] || tables?.metro?.[text] || canonicalEntityLabel(CITIES, text, locale) || canonicalEntityLabel(REGIONS, text, locale) || preferredEntityLabel(COUNTRIES.find((item) => item.code === text.toUpperCase() || item.canonical === text), locale) || text;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function geographyMetroLabelWithAlias(value, locale = 'en') {
|
|
107
|
+
const text = String(value || '').trim();
|
|
108
|
+
if (!text) return '';
|
|
109
|
+
const label = geographyDisplayName(text, locale, 'metro');
|
|
110
|
+
const tables = GEOGRAPHY_DISPLAY_NAMES[languageKey(locale)];
|
|
111
|
+
const alias = tables?.metroAlias?.[text];
|
|
112
|
+
return alias && alias !== label ? `${label} (${alias})` : label;
|
|
113
|
+
}
|
package/src/geography.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { UZ_CITIES, KZ_CITIES } from './geography-central-asia.js';
|
|
2
|
+
import { findCanonical } from './normalization.js';
|
|
3
|
+
import { canonicalCountryCode } from './countries.js';
|
|
4
|
+
import { lexiconEntity } from './lexicon-core.js';
|
|
5
|
+
import { RO_CITY_EXTENSIONS } from './romania-geography.js';
|
|
6
|
+
|
|
7
|
+
const entity = (canonical, aliases, extra = {}) => lexiconEntity(canonical, aliases, extra);
|
|
8
|
+
|
|
9
|
+
export const UA_CITIES = Object.freeze([
|
|
10
|
+
entity('Kyiv', { uk: ['Київ'], ru: ['Киев'], en: ['Kyiv', 'Kiev'], ro: ['Kiev'] }, { country: 'UA', type: 'city' }),
|
|
11
|
+
entity('Kharkiv', { uk: ['Харків'], ru: ['Харьков'], en: ['Kharkiv', 'Kharkov'], ro: ['Harkiv'] }, { country: 'UA', type: 'city' }),
|
|
12
|
+
entity('Odesa', { uk: ['Одеса'], ru: ['Одесса'], en: ['Odesa', 'Odessa'], ro: ['Odesa'] }, { country: 'UA', type: 'city' }),
|
|
13
|
+
entity('Dnipro', { uk: ['Дніпро'], ru: ['Днепр'], en: ['Dnipro', 'Dnepr'], ro: ['Dnipro'] }, { country: 'UA', type: 'city' }),
|
|
14
|
+
entity('Lviv', { uk: ['Львів'], ru: ['Львов'], en: ['Lviv', 'Lvov'], ro: ['Liov', 'Lviv'] }, { country: 'UA', type: 'city' }),
|
|
15
|
+
entity('Zaporizhzhia', { uk: ['Запоріжжя'], ru: ['Запорожье'], en: ['Zaporizhzhia', 'Zaporozhye'], ro: ['Zaporijjea'] }, { country: 'UA', type: 'city' }),
|
|
16
|
+
entity('Vinnytsia', { uk: ['Вінниця'], ru: ['Винница'], en: ['Vinnytsia', 'Vinnitsa'], ro: ['Vinița', 'Vinnytsia'] }, { country: 'UA', type: 'city' }),
|
|
17
|
+
entity('Ivano-Frankivsk', { uk: ['Івано-Франківськ', 'Франківськ'], ru: ['Ивано-Франковск'], en: ['Ivano-Frankivsk', 'Frankivsk'], ro: ['Ivano-Frankivsk'] }, { country: 'UA', type: 'city' }),
|
|
18
|
+
entity('Chernivtsi', { uk: ['Чернівці'], ru: ['Черновцы'], en: ['Chernivtsi', 'Chernovtsy'], ro: ['Cernăuți', 'Cernivți'] }, { country: 'UA', type: 'city' }),
|
|
19
|
+
entity('Uzhhorod', { uk: ['Ужгород'], ru: ['Ужгород'], en: ['Uzhhorod', 'Uzhgorod'], ro: ['Ujhorod'] }, { country: 'UA', type: 'city' }),
|
|
20
|
+
entity('Mukachevo', { uk: ['Мукачево', 'Мукачеве'], ru: ['Мукачево'], en: ['Mukachevo', 'Mukacheve'], ro: ['Muncaci', 'Mukachevo'] }, { country: 'UA', type: 'city' }),
|
|
21
|
+
entity('Lutsk', { uk: ['Луцьк'], ru: ['Луцк'], en: ['Lutsk'], ro: ['Luțk'] }, { country: 'UA', type: 'city' }),
|
|
22
|
+
entity('Rivne', { uk: ['Рівне'], ru: ['Ровно'], en: ['Rivne', 'Rovno'], ro: ['Rivne'] }, { country: 'UA', type: 'city' }),
|
|
23
|
+
entity('Ternopil', { uk: ['Тернопіль'], ru: ['Тернополь'], en: ['Ternopil', 'Ternopol'], ro: ['Ternopil'] }, { country: 'UA', type: 'city' }),
|
|
24
|
+
entity('Khmelnytskyi', { uk: ['Хмельницький'], ru: ['Хмельницкий'], en: ['Khmelnytskyi', 'Khmelnitsky'], ro: ['Hmelnițki'] }, { country: 'UA', type: 'city' }),
|
|
25
|
+
entity('Zhytomyr', { uk: ['Житомир'], ru: ['Житомир'], en: ['Zhytomyr', 'Zhitomir'], ro: ['Jîtomîr'] }, { country: 'UA', type: 'city' }),
|
|
26
|
+
entity('Cherkasy', { uk: ['Черкаси'], ru: ['Черкассы'], en: ['Cherkasy', 'Cherkassy'], ro: ['Cerkasî'] }, { country: 'UA', type: 'city' }),
|
|
27
|
+
entity('Poltava', { uk: ['Полтава'], ru: ['Полтава'], en: ['Poltava'], ro: ['Poltava'] }, { country: 'UA', type: 'city' }),
|
|
28
|
+
entity('Chernihiv', { uk: ['Чернігів'], ru: ['Чернигов'], en: ['Chernihiv', 'Chernigov'], ro: ['Cernihiv'] }, { country: 'UA', type: 'city' }),
|
|
29
|
+
entity('Sumy', { uk: ['Суми'], ru: ['Сумы'], en: ['Sumy'], ro: ['Sumî'] }, { country: 'UA', type: 'city' }),
|
|
30
|
+
entity('Mykolaiv', { uk: ['Миколаїв'], ru: ['Николаев'], en: ['Mykolaiv', 'Nikolaev'], ro: ['Mîkolaiiv'] }, { country: 'UA', type: 'city' }),
|
|
31
|
+
entity('Kherson', { uk: ['Херсон'], ru: ['Херсон'], en: ['Kherson'], ro: ['Herson'] }, { country: 'UA', type: 'city' }),
|
|
32
|
+
entity('Kropyvnytskyi', { uk: ['Кропивницький'], ru: ['Кропивницкий', 'Кировоград'], en: ['Kropyvnytskyi', 'Kirovohrad'], ro: ['Kropîvnîțkîi'] }, { country: 'UA', type: 'city' }),
|
|
33
|
+
entity('Irpin', { uk: ['Ірпінь'], ru: ['Ирпень'], en: ['Irpin'], ro: ['Irpin'] }, { country: 'UA', type: 'city' }),
|
|
34
|
+
entity('Bucha', { uk: ['Буча'], ru: ['Буча'], en: ['Bucha'], ro: ['Bucea'] }, { country: 'UA', type: 'city' }),
|
|
35
|
+
entity('Brovary', { uk: ['Бровари'], ru: ['Бровары'], en: ['Brovary'], ro: ['Brovary'] }, { country: 'UA', type: 'city' }),
|
|
36
|
+
entity('Bila Tserkva', { uk: ['Біла Церква'], ru: ['Белая Церковь'], en: ['Bila Tserkva'], ro: ['Bila Țerkva'] }, { country: 'UA', type: 'city' }),
|
|
37
|
+
entity('Kryvyi Rih', { uk: ['Кривий Ріг'], ru: ['Кривой Рог'], en: ['Kryvyi Rih', 'Krivoy Rog'], ro: ['Krîvîi Rih'] }, { country: 'UA', type: 'city' }),
|
|
38
|
+
entity('Kremenchuk', { uk: ['Кременчук'], ru: ['Кременчуг'], en: ['Kremenchuk'], ro: ['Kremenciuk'] }, { country: 'UA', type: 'city' }),
|
|
39
|
+
entity('Uman', { uk: ['Умань'], ru: ['Умань'], en: ['Uman'], ro: ['Uman'] }, { country: 'UA', type: 'city' }),
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
const RO_CITIES_BASE = Object.freeze([
|
|
43
|
+
entity('Bucharest', { ro: ['București', 'Bucuresti'], en: ['Bucharest'], ru: ['Бухарест'], uk: ['Бухарест'] }, { country: 'RO', type: 'city' }),
|
|
44
|
+
entity('Cluj-Napoca', { ro: ['Cluj-Napoca', 'Cluj'], en: ['Cluj-Napoca', 'Cluj'], ru: ['Клуж-Напока', 'Клуж'], uk: ['Клуж-Напока'] }, { country: 'RO', type: 'city' }),
|
|
45
|
+
entity('Timisoara', { ro: ['Timișoara', 'Timisoara'], en: ['Timisoara', 'Timișoara'], ru: ['Тимишоара'], uk: ['Тімішоара'] }, { country: 'RO', type: 'city' }),
|
|
46
|
+
entity('Iasi', { ro: ['Iași', 'Iasi'], en: ['Iasi', 'Iași'], ru: ['Яссы'], uk: ['Ясси'] }, { country: 'RO', type: 'city' }),
|
|
47
|
+
entity('Brasov', { ro: ['Brașov', 'Brasov'], en: ['Brasov', 'Brașov'], ru: ['Брашов'], uk: ['Брашов'] }, { country: 'RO', type: 'city' }),
|
|
48
|
+
entity('Constanta', { ro: ['Constanța', 'Constanta'], en: ['Constanta', 'Constanța'], ru: ['Констанца'], uk: ['Констанца'] }, { country: 'RO', type: 'city' }),
|
|
49
|
+
entity('Oradea', { ro: ['Oradea'], en: ['Oradea'], ru: ['Орадя'], uk: ['Орадя'] }, { country: 'RO', type: 'city' }),
|
|
50
|
+
entity('Sibiu', { ro: ['Sibiu'], en: ['Sibiu'], ru: ['Сибиу'], uk: ['Сібіу'] }, { country: 'RO', type: 'city' }),
|
|
51
|
+
entity('Craiova', { ro: ['Craiova'], en: ['Craiova'], ru: ['Крайова'], uk: ['Крайова'] }, { country: 'RO', type: 'city' }),
|
|
52
|
+
entity('Ploiesti', { ro: ['Ploiești', 'Ploiesti'], en: ['Ploiesti', 'Ploiești'], ru: ['Плоешти'], uk: ['Плоєшті'] }, { country: 'RO', type: 'city' }),
|
|
53
|
+
entity('Galati', { ro: ['Galați', 'Galati'], en: ['Galati', 'Galați'], ru: ['Галац'], uk: ['Галац'] }, { country: 'RO', type: 'city' }),
|
|
54
|
+
entity('Arad', { ro: ['Arad'], en: ['Arad'], ru: ['Арад'], uk: ['Арад'] }, { country: 'RO', type: 'city' }),
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
export const RO_CITIES = Object.freeze([...RO_CITIES_BASE, ...RO_CITY_EXTENSIONS]);
|
|
58
|
+
|
|
59
|
+
export const KG_CITIES = Object.freeze([
|
|
60
|
+
entity('Bishkek', { ru: ['Бишкек'], en: ['Bishkek'], kk: ['Бішкек'], uzLatn: ['Bishkek'] }, { country: 'KG', type: 'city' }),
|
|
61
|
+
entity('Osh', { ru: ['Ош'], en: ['Osh'], kk: ['Ош'], uzLatn: ['Osh'] }, { country: 'KG', type: 'city' }),
|
|
62
|
+
entity('Karakol', { ru: ['Каракол'], en: ['Karakol'], kk: ['Қаракөл'], uzLatn: ['Karakol'] }, { country: 'KG', type: 'city' }),
|
|
63
|
+
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
/** Canonical cities used across global hiring and housing ingestion. */
|
|
67
|
+
export const GLOBAL_CITIES = Object.freeze([
|
|
68
|
+
entity('Tbilisi', { en: ['Tbilisi'], ru: ['Тбилиси'] }, { country: 'GE', type: 'city' }),
|
|
69
|
+
entity('Batumi', { en: ['Batumi'], ru: ['Батуми'] }, { country: 'GE', type: 'city' }),
|
|
70
|
+
entity('Baku', { en: ['Baku'], ru: ['Баку'] }, { country: 'AZ', type: 'city' }),
|
|
71
|
+
entity('Yerevan', { en: ['Yerevan'], ru: ['Ереван'], uk: ['Єреван'] }, { country: 'AM', type: 'city' }),
|
|
72
|
+
entity('Chisinau', { en: ['Chisinau'], ro: ['Chișinău', 'Chişinău'], ru: ['Кишинёв', 'Кишинев'] }, { country: 'MD', type: 'city' }),
|
|
73
|
+
entity('Dushanbe', { en: ['Dushanbe'], ru: ['Душанбе'] }, { country: 'TJ', type: 'city' }),
|
|
74
|
+
entity('Ashgabat', { en: ['Ashgabat'], ru: ['Ашхабад'] }, { country: 'TM', type: 'city' }),
|
|
75
|
+
entity('Warsaw', { en: ['Warsaw'], all: ['Warszawa'], ru: ['Варшава'] }, { country: 'PL', type: 'city' }),
|
|
76
|
+
entity('Krakow', { en: ['Krakow'], all: ['Kraków'], ru: ['Краков'] }, { country: 'PL', type: 'city' }),
|
|
77
|
+
entity('Berlin', { en: ['Berlin'], ru: ['Берлин'] }, { country: 'DE', type: 'city' }),
|
|
78
|
+
entity('Munich', { en: ['Munich'], all: ['München'], ru: ['Мюнхен'] }, { country: 'DE', type: 'city' }),
|
|
79
|
+
entity('London', { en: ['London'], ru: ['Лондон'] }, { country: 'GB', type: 'city' }),
|
|
80
|
+
entity('New York', { en: ['New York', 'New York City', 'NYC'], ru: ['Нью-Йорк', 'Нью Йорк'] }, { country: 'US', type: 'city' }),
|
|
81
|
+
entity('Beijing', { en: ['Beijing'], ru: ['Пекин'], all: ['北京'] }, { country: 'CN', type: 'city' }),
|
|
82
|
+
entity('Shanghai', { en: ['Shanghai'], ru: ['Шанхай'], all: ['上海'] }, { country: 'CN', type: 'city' }),
|
|
83
|
+
entity('Shenzhen', { en: ['Shenzhen'], ru: ['Шэньчжэнь'], all: ['深圳'] }, { country: 'CN', type: 'city' }),
|
|
84
|
+
entity('Guangzhou', { en: ['Guangzhou'], ru: ['Гуанчжоу'], all: ['广州'] }, { country: 'CN', type: 'city' }),
|
|
85
|
+
entity('Hangzhou', { en: ['Hangzhou'], ru: ['Ханчжоу'], all: ['杭州'] }, { country: 'CN', type: 'city' }),
|
|
86
|
+
entity('Tokyo', { en: ['Tokyo'], ru: ['Токио'], all: ['東京'] }, { country: 'JP', type: 'city' }),
|
|
87
|
+
entity('Osaka', { en: ['Osaka'], ru: ['Осака'], all: ['大阪'] }, { country: 'JP', type: 'city' }),
|
|
88
|
+
entity('Kyoto', { en: ['Kyoto'], ru: ['Киото'], all: ['京都'] }, { country: 'JP', type: 'city' }),
|
|
89
|
+
entity('Seoul', { en: ['Seoul'], ru: ['Сеул'], all: ['서울'] }, { country: 'KR', type: 'city' }),
|
|
90
|
+
entity('Busan', { en: ['Busan'], ru: ['Пусан'], all: ['부산'] }, { country: 'KR', type: 'city' }),
|
|
91
|
+
entity('Taipei', { en: ['Taipei'], ru: ['Тайбэй'], all: ['台北'] }, { country: 'TW', type: 'city' }),
|
|
92
|
+
entity('Kaohsiung', { en: ['Kaohsiung'], ru: ['Гаосюн'], all: ['高雄'] }, { country: 'TW', type: 'city' }),
|
|
93
|
+
entity('Taichung', { en: ['Taichung'], ru: ['Тайчжун'], all: ['台中'] }, { country: 'TW', type: 'city' }),
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
export const CITIES = Object.freeze([...UZ_CITIES, ...KZ_CITIES, ...UA_CITIES, ...RO_CITIES, ...KG_CITIES, ...GLOBAL_CITIES]);
|
|
97
|
+
export const CITIES_BY_COUNTRY = Object.freeze(Object.fromEntries(
|
|
98
|
+
[...new Set(CITIES.map((item) => item.country).filter(Boolean))].map((code) => [
|
|
99
|
+
code,
|
|
100
|
+
Object.freeze(CITIES.filter((item) => item.country === code)),
|
|
101
|
+
]),
|
|
102
|
+
));
|
|
103
|
+
|
|
104
|
+
export function canonicalCity(value, country = null) {
|
|
105
|
+
const code = country ? canonicalCountryCode(country) : null;
|
|
106
|
+
const catalog = country ? (code ? (CITIES_BY_COUNTRY[code] || []) : []) : CITIES;
|
|
107
|
+
return findCanonical(value, catalog)?.canonical || null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Backward-compatible aliases. New code should use CITIES/CITIES_BY_COUNTRY/canonicalCity.
|
|
111
|
+
export const GEOGRAPHY_CITIES = CITIES;
|
|
112
|
+
export const GEOGRAPHY_CITIES_BY_COUNTRY = CITIES_BY_COUNTRY;
|
|
113
|
+
export function canonicalAnyCity(value, country = null) {
|
|
114
|
+
return canonicalCity(value, country);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export const UA_REGIONS = Object.freeze([
|
|
118
|
+
entity('Vinnytsia Oblast', { uk: ['Вінницька область'], ru: ['Винницкая область'], en: ['Vinnytsia Oblast'] }, { country: 'UA', type: 'region' }),
|
|
119
|
+
entity('Volyn Oblast', { uk: ['Волинська область'], ru: ['Волынская область'], en: ['Volyn Oblast'] }, { country: 'UA', type: 'region' }),
|
|
120
|
+
entity('Dnipropetrovsk Oblast', { uk: ['Дніпропетровська область'], ru: ['Днепропетровская область'], en: ['Dnipropetrovsk Oblast'] }, { country: 'UA', type: 'region' }),
|
|
121
|
+
entity('Donetsk Oblast', { uk: ['Донецька область'], ru: ['Донецкая область'], en: ['Donetsk Oblast'] }, { country: 'UA', type: 'region' }),
|
|
122
|
+
entity('Zhytomyr Oblast', { uk: ['Житомирська область'], ru: ['Житомирская область'], en: ['Zhytomyr Oblast'] }, { country: 'UA', type: 'region' }),
|
|
123
|
+
entity('Zakarpattia Oblast', { uk: ['Закарпатська область'], ru: ['Закарпатская область'], en: ['Zakarpattia Oblast', 'Transcarpathia'] }, { country: 'UA', type: 'region' }),
|
|
124
|
+
entity('Zaporizhzhia Oblast', { uk: ['Запорізька область'], ru: ['Запорожская область'], en: ['Zaporizhzhia Oblast'] }, { country: 'UA', type: 'region' }),
|
|
125
|
+
entity('Ivano-Frankivsk Oblast', { uk: ['Івано-Франківська область'], ru: ['Ивано-Франковская область'], en: ['Ivano-Frankivsk Oblast'] }, { country: 'UA', type: 'region' }),
|
|
126
|
+
entity('Kyiv Oblast', { uk: ['Київська область', 'Київщина'], ru: ['Киевская область', 'Киевщина'], en: ['Kyiv Oblast', 'Kyiv Region'] }, { country: 'UA', type: 'region' }),
|
|
127
|
+
entity('Kirovohrad Oblast', { uk: ['Кіровоградська область'], ru: ['Кировоградская область'], en: ['Kirovohrad Oblast'] }, { country: 'UA', type: 'region' }),
|
|
128
|
+
entity('Luhansk Oblast', { uk: ['Луганська область'], ru: ['Луганская область'], en: ['Luhansk Oblast'] }, { country: 'UA', type: 'region' }),
|
|
129
|
+
entity('Lviv Oblast', { uk: ['Львівська область', 'Львівщина'], ru: ['Львовская область'], en: ['Lviv Oblast'] }, { country: 'UA', type: 'region' }),
|
|
130
|
+
entity('Mykolaiv Oblast', { uk: ['Миколаївська область'], ru: ['Николаевская область'], en: ['Mykolaiv Oblast'] }, { country: 'UA', type: 'region' }),
|
|
131
|
+
entity('Odesa Oblast', { uk: ['Одеська область', 'Одещина'], ru: ['Одесская область'], en: ['Odesa Oblast', 'Odessa Oblast'] }, { country: 'UA', type: 'region' }),
|
|
132
|
+
entity('Poltava Oblast', { uk: ['Полтавська область'], ru: ['Полтавская область'], en: ['Poltava Oblast'] }, { country: 'UA', type: 'region' }),
|
|
133
|
+
entity('Rivne Oblast', { uk: ['Рівненська область'], ru: ['Ровенская область'], en: ['Rivne Oblast'] }, { country: 'UA', type: 'region' }),
|
|
134
|
+
entity('Sumy Oblast', { uk: ['Сумська область'], ru: ['Сумская область'], en: ['Sumy Oblast'] }, { country: 'UA', type: 'region' }),
|
|
135
|
+
entity('Ternopil Oblast', { uk: ['Тернопільська область'], ru: ['Тернопольская область'], en: ['Ternopil Oblast'] }, { country: 'UA', type: 'region' }),
|
|
136
|
+
entity('Kharkiv Oblast', { uk: ['Харківська область', 'Харківщина'], ru: ['Харьковская область'], en: ['Kharkiv Oblast'] }, { country: 'UA', type: 'region' }),
|
|
137
|
+
entity('Kherson Oblast', { uk: ['Херсонська область'], ru: ['Херсонская область'], en: ['Kherson Oblast'] }, { country: 'UA', type: 'region' }),
|
|
138
|
+
entity('Khmelnytskyi Oblast', { uk: ['Хмельницька область'], ru: ['Хмельницкая область'], en: ['Khmelnytskyi Oblast'] }, { country: 'UA', type: 'region' }),
|
|
139
|
+
entity('Cherkasy Oblast', { uk: ['Черкаська область'], ru: ['Черкасская область'], en: ['Cherkasy Oblast'] }, { country: 'UA', type: 'region' }),
|
|
140
|
+
entity('Chernivtsi Oblast', { uk: ['Чернівецька область'], ru: ['Черновицкая область'], ro: ['Regiunea Cernăuți'], en: ['Chernivtsi Oblast'] }, { country: 'UA', type: 'region' }),
|
|
141
|
+
entity('Chernihiv Oblast', { uk: ['Чернігівська область'], ru: ['Черниговская область'], en: ['Chernihiv Oblast'] }, { country: 'UA', type: 'region' }),
|
|
142
|
+
entity('Autonomous Republic of Crimea', { uk: ['Автономна Республіка Крим', 'АР Крим'], ru: ['Автономная Республика Крым', 'АР Крым'], en: ['Autonomous Republic of Crimea', 'Crimea'] }, { country: 'UA', type: 'region' }),
|
|
143
|
+
entity('Kyiv City', { uk: ['місто Київ', 'м. Київ'], ru: ['город Киев', 'г. Киев'], en: ['Kyiv City'] }, { country: 'UA', type: 'region' }),
|
|
144
|
+
entity('Sevastopol City', { uk: ['місто Севастополь', 'м. Севастополь'], ru: ['город Севастополь', 'г. Севастополь'], en: ['Sevastopol City'] }, { country: 'UA', type: 'region' }),
|
|
145
|
+
]);
|
|
146
|
+
|
|
147
|
+
const RO_COUNTY_NAMES = [
|
|
148
|
+
['Alba','Alba'],['Arad','Arad'],['Arges','Argeș'],['Bacau','Bacău'],['Bihor','Bihor'],['Bistrita-Nasaud','Bistrița-Năsăud'],['Botosani','Botoșani'],['Braila','Brăila'],['Brasov','Brașov'],['Buzau','Buzău'],
|
|
149
|
+
['Calarasi','Călărași'],['Caras-Severin','Caraș-Severin'],['Cluj','Cluj'],['Constanta','Constanța'],['Covasna','Covasna'],['Dambovita','Dâmbovița'],['Dolj','Dolj'],['Galati','Galați'],['Giurgiu','Giurgiu'],['Gorj','Gorj'],
|
|
150
|
+
['Harghita','Harghita'],['Hunedoara','Hunedoara'],['Ialomita','Ialomița'],['Iasi','Iași'],['Ilfov','Ilfov'],['Maramures','Maramureș'],['Mehedinti','Mehedinți'],['Mures','Mureș'],['Neamt','Neamț'],['Olt','Olt'],
|
|
151
|
+
['Prahova','Prahova'],['Salaj','Sălaj'],['Satu Mare','Satu Mare'],['Sibiu','Sibiu'],['Suceava','Suceava'],['Teleorman','Teleorman'],['Timis','Timiș'],['Tulcea','Tulcea'],['Valcea','Vâlcea'],['Vaslui','Vaslui'],['Vrancea','Vrancea'],
|
|
152
|
+
];
|
|
153
|
+
export const RO_REGIONS = Object.freeze([
|
|
154
|
+
...RO_COUNTY_NAMES.map(([canonical, native]) => entity(`${canonical} County`, { ro: [`județul ${native}`, `județ ${native}`, native], en: [`${canonical} County`], ru: [`жудец ${native}`], uk: [`жудець ${native}`] }, { country: 'RO', type: 'region' })),
|
|
155
|
+
entity('Bucharest Municipality', { ro: ['Municipiul București', 'București'], en: ['Bucharest Municipality'], ru: ['муниципий Бухарест'], uk: ['муніципій Бухарест'] }, { country: 'RO', type: 'region' }),
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
export const UZ_REGIONS = Object.freeze([
|
|
159
|
+
entity('Tashkent Region', { uzLatn: ['Toshkent viloyati'], uzCyrl: ['Тошкент вилояти'], ru: ['Ташкентская область'], en: ['Tashkent Region'] }, { country: 'UZ', type: 'region' }),
|
|
160
|
+
entity('Andijan Region', { uzLatn: ['Andijon viloyati'], uzCyrl: ['Андижон вилояти'], ru: ['Андижанская область'], en: ['Andijan Region'] }, { country: 'UZ', type: 'region' }),
|
|
161
|
+
entity('Bukhara Region', { uzLatn: ['Buxoro viloyati'], uzCyrl: ['Бухоро вилояти'], ru: ['Бухарская область'], en: ['Bukhara Region'] }, { country: 'UZ', type: 'region' }),
|
|
162
|
+
entity('Fergana Region', { uzLatn: ["Farg'ona viloyati", 'Farg‘ona viloyati'], uzCyrl: ['Фарғона вилояти'], ru: ['Ферганская область'], en: ['Fergana Region'] }, { country: 'UZ', type: 'region' }),
|
|
163
|
+
entity('Jizzakh Region', { uzLatn: ['Jizzax viloyati'], uzCyrl: ['Жиззах вилояти'], ru: ['Джизакская область'], en: ['Jizzakh Region'] }, { country: 'UZ', type: 'region' }),
|
|
164
|
+
entity('Namangan Region', { uzLatn: ['Namangan viloyati'], uzCyrl: ['Наманган вилояти'], ru: ['Наманганская область'], en: ['Namangan Region'] }, { country: 'UZ', type: 'region' }),
|
|
165
|
+
entity('Navoiy Region', { uzLatn: ['Navoiy viloyati'], uzCyrl: ['Навоий вилояти'], ru: ['Навоийская область'], en: ['Navoiy Region'] }, { country: 'UZ', type: 'region' }),
|
|
166
|
+
entity('Qashqadaryo Region', { uzLatn: ['Qashqadaryo viloyati'], uzCyrl: ['Қашқадарё вилояти'], ru: ['Кашкадарьинская область'], en: ['Qashqadaryo Region', 'Kashkadarya Region'] }, { country: 'UZ', type: 'region' }),
|
|
167
|
+
entity('Samarqand Region', { uzLatn: ['Samarqand viloyati'], uzCyrl: ['Самарқанд вилояти'], ru: ['Самаркандская область'], en: ['Samarqand Region', 'Samarkand Region'] }, { country: 'UZ', type: 'region' }),
|
|
168
|
+
entity('Surxondaryo Region', { uzLatn: ['Surxondaryo viloyati'], uzCyrl: ['Сурхондарё вилояти'], ru: ['Сурхандарьинская область'], en: ['Surxondaryo Region', 'Surkhandarya Region'] }, { country: 'UZ', type: 'region' }),
|
|
169
|
+
entity('Sirdaryo Region', { uzLatn: ['Sirdaryo viloyati'], uzCyrl: ['Сирдарё вилояти'], ru: ['Сырдарьинская область'], en: ['Sirdaryo Region', 'Syrdarya Region'] }, { country: 'UZ', type: 'region' }),
|
|
170
|
+
entity('Xorazm Region', { uzLatn: ['Xorazm viloyati'], uzCyrl: ['Хоразм вилояти'], ru: ['Хорезмская область'], en: ['Xorazm Region', 'Khorezm Region'] }, { country: 'UZ', type: 'region' }),
|
|
171
|
+
entity('Karakalpakstan', { uzLatn: ["Qoraqalpog'iston Respublikasi", 'Qoraqalpog‘iston Respublikasi'], uzCyrl: ['Қорақалпоғистон Республикаси'], ru: ['Республика Каракалпакстан', 'Каракалпакстан'], en: ['Republic of Karakalpakstan', 'Karakalpakstan'] }, { country: 'UZ', type: 'region' }),
|
|
172
|
+
entity('Tashkent City', { uzLatn: ['Toshkent shahri'], uzCyrl: ['Тошкент шаҳри'], ru: ['город Ташкент', 'г. Ташкент'], en: ['Tashkent City'] }, { country: 'UZ', type: 'region' }),
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
export const KZ_REGIONS = Object.freeze([
|
|
176
|
+
entity('Abai Region', { kk: ['Абай облысы'], ru: ['Абайская область'], en: ['Abai Region'] }, { country: 'KZ', type: 'region' }),
|
|
177
|
+
entity('Akmola Region', { kk: ['Ақмола облысы'], ru: ['Акмолинская область'], en: ['Akmola Region'] }, { country: 'KZ', type: 'region' }),
|
|
178
|
+
entity('Aktobe Region', { kk: ['Ақтөбе облысы'], ru: ['Актюбинская область'], en: ['Aktobe Region'] }, { country: 'KZ', type: 'region' }),
|
|
179
|
+
entity('Almaty Region', { kk: ['Алматы облысы'], ru: ['Алматинская область'], en: ['Almaty Region'] }, { country: 'KZ', type: 'region' }),
|
|
180
|
+
entity('Atyrau Region', { kk: ['Атырау облысы'], ru: ['Атырауская область'], en: ['Atyrau Region'] }, { country: 'KZ', type: 'region' }),
|
|
181
|
+
entity('East Kazakhstan Region', { kk: ['Шығыс Қазақстан облысы'], ru: ['Восточно-Казахстанская область'], en: ['East Kazakhstan Region'] }, { country: 'KZ', type: 'region' }),
|
|
182
|
+
entity('Jambyl Region', { kk: ['Жамбыл облысы'], ru: ['Жамбылская область'], en: ['Jambyl Region', 'Zhambyl Region'] }, { country: 'KZ', type: 'region' }),
|
|
183
|
+
entity('Jetisu Region', { kk: ['Жетісу облысы'], ru: ['Жетысуская область'], en: ['Jetisu Region', 'Zhetysu Region'] }, { country: 'KZ', type: 'region' }),
|
|
184
|
+
entity('Karaganda Region', { kk: ['Қарағанды облысы'], ru: ['Карагандинская область'], en: ['Karaganda Region'] }, { country: 'KZ', type: 'region' }),
|
|
185
|
+
entity('Kostanay Region', { kk: ['Қостанай облысы'], ru: ['Костанайская область'], en: ['Kostanay Region'] }, { country: 'KZ', type: 'region' }),
|
|
186
|
+
entity('Kyzylorda Region', { kk: ['Қызылорда облысы'], ru: ['Кызылординская область'], en: ['Kyzylorda Region'] }, { country: 'KZ', type: 'region' }),
|
|
187
|
+
entity('Mangystau Region', { kk: ['Маңғыстау облысы'], ru: ['Мангистауская область'], en: ['Mangystau Region'] }, { country: 'KZ', type: 'region' }),
|
|
188
|
+
entity('North Kazakhstan Region', { kk: ['Солтүстік Қазақстан облысы'], ru: ['Северо-Казахстанская область'], en: ['North Kazakhstan Region'] }, { country: 'KZ', type: 'region' }),
|
|
189
|
+
entity('Pavlodar Region', { kk: ['Павлодар облысы'], ru: ['Павлодарская область'], en: ['Pavlodar Region'] }, { country: 'KZ', type: 'region' }),
|
|
190
|
+
entity('Turkistan Region', { kk: ['Түркістан облысы'], ru: ['Туркестанская область'], en: ['Turkistan Region'] }, { country: 'KZ', type: 'region' }),
|
|
191
|
+
entity('Ulytau Region', { kk: ['Ұлытау облысы'], ru: ['Улытауская область'], en: ['Ulytau Region'] }, { country: 'KZ', type: 'region' }),
|
|
192
|
+
entity('West Kazakhstan Region', { kk: ['Батыс Қазақстан облысы'], ru: ['Западно-Казахстанская область'], en: ['West Kazakhstan Region'] }, { country: 'KZ', type: 'region' }),
|
|
193
|
+
entity('Astana City', { kk: ['Астана қаласы'], ru: ['город Астана'], en: ['Astana City'] }, { country: 'KZ', type: 'region' }),
|
|
194
|
+
entity('Almaty City', { kk: ['Алматы қаласы'], ru: ['город Алматы'], en: ['Almaty City'] }, { country: 'KZ', type: 'region' }),
|
|
195
|
+
entity('Shymkent City', { kk: ['Шымкент қаласы'], ru: ['город Шымкент'], en: ['Shymkent City'] }, { country: 'KZ', type: 'region' }),
|
|
196
|
+
]);
|
|
197
|
+
|
|
198
|
+
export const REGIONS = Object.freeze([...UZ_REGIONS, ...KZ_REGIONS, ...UA_REGIONS, ...RO_REGIONS]);
|
|
199
|
+
export const REGIONS_BY_COUNTRY = Object.freeze(Object.fromEntries(
|
|
200
|
+
[...new Set(REGIONS.map((item) => item.country).filter(Boolean))].map((code) => [
|
|
201
|
+
code,
|
|
202
|
+
Object.freeze(REGIONS.filter((item) => item.country === code)),
|
|
203
|
+
]),
|
|
204
|
+
));
|
|
205
|
+
|
|
206
|
+
export function canonicalRegion(value, country = null) {
|
|
207
|
+
const code = country ? canonicalCountryCode(country) : null;
|
|
208
|
+
const catalog = country ? (code ? (REGIONS_BY_COUNTRY[code] || []) : []) : REGIONS;
|
|
209
|
+
return findCanonical(value, catalog, { partial: true })?.canonical || null;
|
|
210
|
+
}
|