@whiteslove/parsing-lexicon 0.5.2 → 0.5.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whiteslove/parsing-lexicon",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Shared deterministic multilingual parsing lexicon for WhitesLove housing and hiring services",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,6 +27,10 @@
27
27
  "types": "./src/geography-display.d.ts",
28
28
  "import": "./src/geography-display.js"
29
29
  },
30
+ "./geography-zone-display": {
31
+ "types": "./src/geography-zone-display.d.ts",
32
+ "import": "./src/geography-zone-display.js"
33
+ },
30
34
  "./geography-detection": {
31
35
  "types": "./src/geography-detection.d.ts",
32
36
  "import": "./src/geography-detection.js"
@@ -0,0 +1,7 @@
1
+ import type { GeographyDisplayContext } from './geography-display.js';
2
+
3
+ export function geographyZoneDisplayName(
4
+ value: unknown,
5
+ locale?: string,
6
+ context?: GeographyDisplayContext | null,
7
+ ): string;
@@ -0,0 +1,154 @@
1
+ import { geographyDisplayName } from './geography-display.js';
2
+ import { dictionaryFor } from './locations.js';
3
+ import { aliasesOf, findCanonical } from './normalization.js';
4
+ import { canonicalCountryCode } from './countries.js';
5
+
6
+ const ZONE_KINDS = Object.freeze([
7
+ ['city', []],
8
+ ['district', ['districts']],
9
+ ['microdistrict', ['microdistricts']],
10
+ ['metro', ['metro']],
11
+ ['mahalla', ['mahallas']],
12
+ ['local_area', ['localAreas']],
13
+ ['development_area', ['developmentAreas']],
14
+ ['residential_complex', ['residentialComplexes']],
15
+ ['settlement', ['settlements']],
16
+ ['suburb', ['suburbs']],
17
+ ]);
18
+
19
+ const CYRILLIC_RE = /\p{Script=Cyrillic}/u;
20
+ const NON_RUSSIAN_CYRILLIC_RE = /[ІіЇїЄєҐґЎўҚқҒғҲҳӘәӨөҰұҮүҢң]/u;
21
+ const UZBEK_LOCALITY_SUFFIX_RE = /\b(?:массиви|махалласи|даҳаси|дахаси|мавзеси)\b/iu;
22
+ const COMPACT_ZONE_SUFFIX_RE = /\s+(?:массив|массиви|микрорайон|мкр|квартал|махалла|махалласи|даха|дахаси|даҳаси|мавзе|мавзеси|massiv|massivi|daha|dahasi|mahalla|mahallasi|mavze|mavzesi)$/iu;
23
+
24
+ function compactBase(label) {
25
+ const compact = String(label || '').replace(COMPACT_ZONE_SUFFIX_RE, '').trim();
26
+ return compact || String(label || '').trim();
27
+ }
28
+
29
+ function languageKey(locale) {
30
+ const key = String(locale || 'en').toLowerCase().split(/[-_]/)[0];
31
+ return key === 'ru' || key === 'uz' ? key : 'en';
32
+ }
33
+
34
+ function dictionaryForContext(context) {
35
+ const country = canonicalCountryCode(context?.country);
36
+ const city = String(context?.city || '').trim();
37
+ if (!country || !city) return null;
38
+ return dictionaryFor(country, city);
39
+ }
40
+
41
+ function preferredFallbackAlias(entry, locale) {
42
+ const language = languageKey(locale);
43
+ const canonical = entry?.canonical || entry?.name || null;
44
+ if (!entry || !canonical || language === 'en') return canonical;
45
+
46
+ const aliases = aliasesOf(entry).map((value) => String(value || '').trim()).filter(Boolean);
47
+ if (language === 'ru') {
48
+ const candidates = aliases
49
+ .filter((alias) => CYRILLIC_RE.test(alias) && !NON_RUSSIAN_CYRILLIC_RE.test(alias))
50
+ .sort((a, b) => {
51
+ const suffixPenalty = Number(UZBEK_LOCALITY_SUFFIX_RE.test(a)) - Number(UZBEK_LOCALITY_SUFFIX_RE.test(b));
52
+ if (suffixPenalty) return suffixPenalty;
53
+ return compactBase(a).length - compactBase(b).length || a.length - b.length;
54
+ });
55
+ return candidates[0] || canonical;
56
+ }
57
+
58
+ return entry.labels?.uz || canonical;
59
+ }
60
+
61
+ function localizedEntryLabel(entry, locale, kind, compact = false) {
62
+ if (!entry) return null;
63
+ const canonical = entry.canonical || entry.name;
64
+ if (!canonical) return null;
65
+
66
+ const established = geographyDisplayName(canonical, locale, kind, null);
67
+ const label = established !== canonical
68
+ ? established
69
+ : preferredFallbackAlias(entry, locale);
70
+ return compact ? compactBase(label) : label;
71
+ }
72
+
73
+ function resolveDictionaryZone(raw, locale, context, compact = false) {
74
+ const dictionary = dictionaryForContext(context);
75
+ if (!dictionary) return null;
76
+
77
+ for (const [kind, keys] of ZONE_KINDS) {
78
+ for (const key of keys) {
79
+ const entries = dictionary[key] || [];
80
+ const entry = findCanonical(raw, entries, { transliteration: true });
81
+ if (!entry) continue;
82
+ return localizedEntryLabel(entry, locale, kind, compact);
83
+ }
84
+ }
85
+ return null;
86
+ }
87
+
88
+ function directZoneLabel(raw, locale, context) {
89
+ // Preserve the existing consumer precedence: stable shared presentation names
90
+ // win first, then the selected city dictionary fills aliases that those tables
91
+ // do not know. This keeps canonical geo-catalog values such as Karasu usable
92
+ // even when the listing lexicon canonical is Qorasuv.
93
+ for (const [kind] of ZONE_KINDS) {
94
+ const translated = geographyDisplayName(raw, locale, kind, null);
95
+ if (translated && translated !== raw) return compactBase(translated);
96
+ }
97
+
98
+ const scoped = resolveDictionaryZone(raw, locale, context, true);
99
+ return scoped && scoped !== raw ? scoped : null;
100
+ }
101
+
102
+ function compositeBaseLabel(rawBase, locale, context) {
103
+ const direct = directZoneLabel(rawBase, locale, context);
104
+ if (direct) return compactBase(direct);
105
+
106
+ const probes = [
107
+ rawBase,
108
+ `${rawBase} massiv`,
109
+ `${rawBase} massivi`,
110
+ `${rawBase} массив`,
111
+ `${rawBase} массиви`,
112
+ `${rawBase} daha`,
113
+ `${rawBase} dahasi`,
114
+ `${rawBase} даха`,
115
+ `${rawBase} дахаси`,
116
+ `${rawBase} даҳаси`,
117
+ `${rawBase} mahalla`,
118
+ `${rawBase} mahallasi`,
119
+ `${rawBase} махалла`,
120
+ `${rawBase} махалласи`,
121
+ ];
122
+
123
+ for (const probe of probes) {
124
+ const label = resolveDictionaryZone(probe, locale, context, true);
125
+ if (label) return label;
126
+ }
127
+ return null;
128
+ }
129
+
130
+ /**
131
+ * Resolve a visible label for a canonical or source-provided housing/map zone.
132
+ *
133
+ * This API intentionally owns multilingual alias/script/transliteration rules so
134
+ * UI consumers do not need to inspect location dictionaries or understand Uzbek
135
+ * locality suffixes. The returned value is presentation-only; callers should keep
136
+ * the original canonical/filter value for routing and queries.
137
+ */
138
+ export function geographyZoneDisplayName(value, locale = 'en', context = null) {
139
+ const raw = String(value || '').trim();
140
+ if (!raw) return '';
141
+
142
+ const direct = directZoneLabel(raw, locale, context);
143
+ if (direct) return direct;
144
+
145
+ const separatorIndex = raw.indexOf('-');
146
+ if (separatorIndex > 0) {
147
+ const base = raw.slice(0, separatorIndex).trim();
148
+ const suffix = raw.slice(separatorIndex);
149
+ const label = compositeBaseLabel(base, locale, context);
150
+ if (label) return `${label}${suffix}`;
151
+ }
152
+
153
+ return raw;
154
+ }
package/src/locations.js CHANGED
@@ -14,6 +14,7 @@ import { UA_MAJOR_LOCATION_EXTENSIONS } from './ua-location-extensions-major.js'
14
14
  import { UA_REGIONAL_LOCATION_EXTENSIONS } from './ua-location-extensions-regional.js';
15
15
  import { UA_SECONDARY_LOCATION_EXTENSIONS } from './ua-secondary-cities.js';
16
16
  import { UA_METRO_LOCATION_EXTENSIONS } from './ua-location-extensions-metro.js';
17
+ import { UA_KHARKIV_LOCATION_TRANSLATIONS } from './ua-kharkiv-location-translations.js';
17
18
 
18
19
  export const UA_EXTRA_LOCATION_DICTIONARIES = Object.freeze({
19
20
  ...RAW_UA_EXTRA_LOCATION_DICTIONARIES,
@@ -92,8 +93,6 @@ function normalizeUzSemanticLocations(country) {
92
93
  const qorasuv = (tashkent?.microdistricts || []).find(({ name }) => name === 'Qorasuv');
93
94
 
94
95
  if (tashkent && qorasuv) {
95
- // Bare Qorasuv is ambiguous with numbered Qorasuv/Karasu blocks. The
96
- // umbrella area therefore requires an area/massif/daha form in free text.
97
96
  const qorasuvAliases = Object.freeze([...new Set([
98
97
  ...(qorasuv.aliases || []).filter((alias) => !/^(?:qorasuv|korasuv|корасув|карасу)$/iu.test(String(alias).trim())),
99
98
  'Qorasuv dahasi',
@@ -129,10 +128,6 @@ function normalizeUzSemanticLocations(country) {
129
128
  const landmarks = samarkand.landmarks || [];
130
129
  const localAreas = samarkand.localAreas || [];
131
130
  const streets = samarkand.streets || [];
132
-
133
- // Legacy UZ seeds contain a few Samarkand listing labels as separate
134
- // canonicals or under the wrong semantic collection. Normalize them to the
135
- // single physical subjects already represented by geo-catalog.
136
131
  const centralPark = landmarks.find(({ name }) => name === 'Central Park');
137
132
  const alisherPark = landmarks.find(({ name }) => name === 'Alisher Navoiy Park');
138
133
  const canonicalPark = centralPark || alisherPark;
@@ -205,8 +200,6 @@ function normalizeUzSemanticLocations(country) {
205
200
  const oldCity = localAreas.find(({ name }) => name === 'Old City');
206
201
 
207
202
  if (ichanKala && oldCity) {
208
- // UNESCO identifies Itchan Kala as the historic inner-city of Khiva.
209
- // Keep listing-friendly Old City forms as aliases of that one place.
210
203
  const normalizedIchanKala = semanticEntry(ichanKala, 'Ichan Kala', [
211
204
  ...(ichanKala.aliases || []),
212
205
  ...(oldCity.aliases || []),
@@ -317,9 +310,6 @@ function normalizeUaSemanticLocations(country) {
317
310
  const odesa = country?.Odesa;
318
311
  if (!odesa) return country;
319
312
 
320
- // “5–16 station of Velykyi Fontan” are traditional listing/locality zones
321
- // anchored to the Fontanska Road transit stops, not twelve standalone city
322
- // microdistricts. Keep their parsing value but expose them as local areas.
323
313
  const fontanStationAreas = Object.freeze(
324
314
  (odesa.microdistricts || [])
325
315
  .filter(({ name }) => ODESA_FONTAN_STATION_RE.test(name))
@@ -351,6 +341,9 @@ const UZ_LOCATION_DICTIONARIES = normalizeUzSemanticLocations(mergeLocationCount
351
341
  ));
352
342
 
353
343
  const UA_SEMANTIC_LOCATION_EXTENSIONS = normalizeUaSemanticLocations(UA_MAJOR_LOCATION_EXTENSIONS);
344
+ const UA_KHARKIV_TRANSLATION_EXTENSIONS = Object.freeze({
345
+ Kharkiv: UA_KHARKIV_LOCATION_TRANSLATIONS,
346
+ });
354
347
 
355
348
  const COUNTRY_LOCATION_DICTIONARIES = Object.freeze({
356
349
  ...BASE_LOCATION_DICTIONARIES,
@@ -365,14 +358,13 @@ const COUNTRY_LOCATION_DICTIONARIES = Object.freeze({
365
358
  UA_REGIONAL_LOCATION_EXTENSIONS,
366
359
  UA_SECONDARY_LOCATION_EXTENSIONS,
367
360
  UA_METRO_LOCATION_EXTENSIONS,
361
+ UA_KHARKIV_TRANSLATION_EXTENSIONS,
368
362
  ),
369
363
  });
370
364
 
371
365
  /** Canonical country -> city -> location dictionary registry. */
372
366
  export const LOCATION_DICTIONARIES = COUNTRY_LOCATION_DICTIONARIES;
373
367
 
374
- // Compatibility exports. Legacy seeds are not canonical ownership; consumers
375
- // should use LOCATION_DICTIONARIES/locationCities().
376
368
  export {
377
369
  UA_REGION_ENTRIES,
378
370
  UA_SECONDARY_CITIES,
@@ -0,0 +1,91 @@
1
+ import { locationEntries } from './location-merge.js';
2
+
3
+ // Kharkiv-specific multilingual aliases that are useful in listing text and
4
+ // benefit from explicit UA/RU coverage. Canonicals intentionally match the
5
+ // major Ukraine location layer so mergeLocationEntries enriches one subject
6
+ // instead of creating parallel parser entities.
7
+ const numberedMicrodistricts = Object.freeze([
8
+ '455','519','520','521','522','524','531','533','536','537','601','602','603','604','605','606','607','608','614','615','616','624','625','626','627','656',
9
+ ]);
10
+
11
+ const NUMBERED_EXTRA_ALIASES = Object.freeze({
12
+ 536: Object.freeze(['Містечко Будівельників', 'Містечко будівельників', 'Городок Строителей', 'Городок строителей']),
13
+ 537: Object.freeze(['537 м.р.', '537 м.р']),
14
+ });
15
+
16
+ const numberedMicrodistrictRow = (number) => [
17
+ `${number} microdistrict`,
18
+ `${number}-й мікрорайон`,
19
+ `${number} мікрорайон`,
20
+ `${number}-й микрорайон`,
21
+ `${number} микрорайон`,
22
+ `${number} мкр`,
23
+ `${number} мкр.`,
24
+ `${number}-й мкр`,
25
+ `${number}-й мкр.`,
26
+ `${number} м/р`,
27
+ `${number}-й м/р`,
28
+ `${number} мрн`,
29
+ `${number} мрн.`,
30
+ ...(NUMBERED_EXTRA_ALIASES[number] || []),
31
+ ];
32
+
33
+ export const UA_KHARKIV_LOCATION_TRANSLATIONS = Object.freeze({
34
+ microdistricts: locationEntries([
35
+ ...numberedMicrodistricts.map(numberedMicrodistrictRow),
36
+ ['535A', '535 microdistrict', '535-й мікрорайон', '535 мікрорайон', '535-й микрорайон', '535 микрорайон', '535 мкр', '535 мкр.', '535-й мкр', '535-й мкр.', '535 м/р', '535 мрн', '535A мкр', '535А мкр', '535а мкр', '535A мкр.', '535А мкр.', '535а мкр.', '535A м/р', '535А м/р', '535а м/р', '535A мрн', '535А мрн', '535а мрн'],
37
+ ['606A', '606A мкр', '606А мкр', '606а мкр', '606A мкр.', '606А мкр.', '606а мкр.', '606A м/р', '606А м/р', '606а м/р', '606A мрн', '606А мрн', '606а мрн'],
38
+ ['627 microdistrict', '624A', '624А', '624а', '624A microdistrict', '624А мікрорайон', '624а мікрорайон', '624А микрорайон', '624а микрорайон', '624А мкр', '624а мкр'],
39
+ ['Horizont', 'Обрій', 'Обрий', 'Obrii', 'Горизонт'],
40
+ ]),
41
+ streets: locationEntries([
42
+ ['Hvardiitsiv-Shyronintsiv Street', 'вулиця Гвардійців-Широнінців', 'вул. Гвардійців-Широнінців', 'Гвардійців-Широнінців', 'улица Гвардейцев-Широнинцев', 'ул. Гвардейцев-Широнинцев', 'Гвардейцев-Широнинцев', 'Гвардейцев Широнинцев'],
43
+ ['Yuvileinyi Avenue', 'проспект Ювілейний', 'пр-т Ювілейний', 'Ювілейний проспект', 'проспект Юбилейный', 'пр-т Юбилейный', 'Юбилейный проспект', 'проспект 50-річчя ВЛКСМ', 'проспект 50-летия ВЛКСМ'],
44
+ ['Traktorobudivnykiv Avenue', 'проспект Тракторобудівників', 'пр-т Тракторобудівників', 'Тракторобудівників проспект', 'проспект Тракторостроителей', 'пр-т Тракторостроителей', 'Тракторостроителей проспект'],
45
+ ['Lva Landau Avenue', 'проспект Льва Ландау', 'пр-т Льва Ландау', 'Льва Ландау', 'Lva Landau Ave', 'проспект 50-річчя СРСР', 'проспект 50-летия СССР'],
46
+ ['Aerokosmichnyi Avenue', 'Аерокосмічний проспект', 'проспект Аерокосмічний', 'пр-т Аерокосмічний', 'Аэрокосмический проспект', 'проспект Аэрокосмический', 'пр-т Аэрокосмический', 'проспект Гагаріна', 'проспект Гагарина', 'Haharina Avenue', 'Gagarina Avenue'],
47
+ ['Amosova Street', 'вулиця Амосова', 'вул. Амосова', 'Амосова', 'улица Амосова', 'ул. Амосова', 'вулиця Корчагінців', 'Корчагінців', 'улица Корчагинцев', 'Корчагинцев'],
48
+ ['Valentynivska Street', 'вулиця Валентинівська', 'вул. Валентинівська', 'Валентинівська', 'улица Валентиновская', 'ул. Валентиновская', 'Валентиновская', 'вулиця Блюхера', 'вул. Блюхера', 'улица Блюхера', 'ул. Блюхера'],
49
+ ['Sobornosti Ukrainy Street', 'вулиця Соборності України', 'вул. Соборності України', 'Соборності України', 'улица Соборности Украины', 'ул. Соборности Украины', 'Соборности Украины', 'вулиця Дружби Народів', 'вул. Дружби Народів', 'Дружби Народів', 'улица Дружбы Народов', 'ул. Дружбы Народов', 'Дружбы Народов'],
50
+ ]),
51
+ residentialComplexes: locationEntries([
52
+ ['Pavlovsky Kvartal', 'Павлівський квартал', 'ЖК Павлівський квартал', 'Павловский квартал', 'ЖК Павловский квартал'],
53
+ ['Dim na Sumskii', 'Будинок на Сумській', 'Дім на Сумській', 'ЖК Будинок на Сумській', 'Дом на Сумской', 'ЖК Дом на Сумской'],
54
+ ['Myronosytska', 'Мироносицька', 'ЖК Мироносицька', 'Мироносицкая', 'ЖК Мироносицкая'],
55
+ ['Felicita', 'Феліціта', 'ЖК Феліціта', 'Феличита', 'ЖК Феличита'],
56
+ ['Rezidentsiia', 'Резиденція', 'ЖК Резиденція', 'Резиденция', 'ЖК Резиденция'],
57
+ ['Hydropark', 'ЖК Гідропарк', 'ЖК Гидропарк'],
58
+ ['Ovis', 'Овіс', 'ЖК Овіс', 'Овис', 'ЖК Овис', 'OVIS', 'ЖК OVIS'],
59
+ ['Flagman', 'Флагман', 'ЖК Флагман'],
60
+ ['Kvant', 'Квант', 'ЖК Квант'],
61
+ ['Crystal', 'Кристал', 'Кристалл', 'ЖК Кристал', 'ЖК Кристалл', 'ЖК Crystal'],
62
+ ['Sokolnyky', 'ЖК Сокільники', 'ЖК Сокольники'],
63
+ ['Rohatynskyi', 'Рогатинський', 'ЖК Рогатинський', 'Рогатинский', 'ЖК Рогатинский'],
64
+ ['Mlechnyi Shliakh', 'Млечний шлях', 'ЖК Млечний шлях', 'Млечный путь', 'ЖК Млечный путь'],
65
+ ['Levada', 'ЖК Левада', 'ЖК Levada', 'Levada ЖК'],
66
+ ['Newton 2', 'Ньютон 2', 'Ньютона 2', 'ЖК Ньютон 2', 'ЖК Ньютона 2', 'ЖК Ньютона-2', 'ЖК Newton 2'],
67
+ ['Saltivskyi', 'ЖК Салтівський', 'ЖК Салтовский'],
68
+ ['Raiduzhnyi', 'ЖК Райдужний', 'ЖК Радужный', 'ЖК Радужний', 'ЖК Райдужный', 'ЖК Радужный 1', 'ЖК Райдужний 1'],
69
+ ['Makiivska', 'Макіївська', 'ЖК Макіївська', 'Макеевская', 'ЖК Макеевская', 'ЖК на Макіївській', 'ЖК на Макеевской'],
70
+ ['River Town', 'ЖК River Town', 'Ривер Таун', 'ЖК Ривер Таун'],
71
+ ]),
72
+ landmarks: locationEntries([
73
+ ['Sarzhyn Yar', 'Саржин Яр', 'Саржин яр'],
74
+ ['Lisopark', 'Лісопарк', 'Харківський лісопарк', 'Лесопарк', 'Харьковский лесопарк'],
75
+ ['Machine Builders Park', 'Парк Машинобудівників', 'Парк Машиностроителей', 'парк Артема', 'парк Артёма'],
76
+ ['Zelenyi Hai', 'Зелений Гай', 'Зеленый Гай', 'Зелёный Гай'],
77
+ ['Karpivskyi Garden', 'Карпівський сад', 'Карповский сад'],
78
+ ['Pokrovskyi Square', 'Покровський сквер', 'Покровский сквер'],
79
+ ['Derzhprom', 'Держпром', 'Госпром', 'Gosprom', 'Будинок державної промисловості', 'Дом государственной промышленности'],
80
+ ['Pokrovskyi Monastery', 'Покровський монастир', 'Покровский монастырь'],
81
+ ['Kharkiv Zoo', 'Харківський зоопарк', 'Харьковский зоопарк'],
82
+ ['KhAI', 'ХАІ', 'ХАИ', 'Харківський авіаційний інститут', 'Харьковский авиационный институт'],
83
+ ['KhPI', 'ХПІ', 'ХПИ', 'Харківський політехнічний інститут', 'Харьковский политехнический институт'],
84
+ ['KhNURE', 'ХНУРЕ', 'ХНУРЭ', 'Харківський національний університет радіоелектроніки', 'Харьковский национальный университет радиоэлектроники'],
85
+ ['French Boulevard', 'Французький бульвар', 'Французский бульвар', 'ТРЦ Французький бульвар', 'ТРЦ Французский бульвар'],
86
+ ['Barabashovo Market', 'ринок Барабашово', 'ринок Барабашова', 'рынок Барабашово', 'Барабашово', 'Барабашова'],
87
+ ['Horse Market', 'Кінний ринок', 'ринок Кінний', 'Конный рынок', 'рынок Конный'],
88
+ ['Central Market', 'Центральний ринок', 'Центральный рынок', 'Благбаз', 'Благовіщенський базар', 'Благовещенский базар'],
89
+ ['Sumskyi Market', 'Сумський ринок', 'Сумской рынок', 'ТЦ Сумський ринок', 'ТЦ Сумской рынок'],
90
+ ]),
91
+ });
@@ -17,7 +17,6 @@ export const UA_MAJOR_LOCATION_EXTENSIONS = Object.freeze({
17
17
  ],
18
18
  microdistricts: [
19
19
  ['Podil','Поділ','Подол'],['Pechersk','Печерськ','Печерск'],['Lipky','Липки'],['Zvirynets','Звіринець','Зверинец'],['Chorna Hora','Чорна гора','Черная гора'],['Busove Pole','Бусово поле'],['Nova Zabudova','Нова забудова','Новое строение'],['Saperne Pole','Саперне поле','Саперное поле'],['Center','Центр','Старий Київ','Старый Киев'],['Lukianivka',"Лук'янівка",'Лукьяновка'],['Tatarka','Татарка'],['Syrets','Сирець','Сырец'],['Nyvky','Нивки'],['Shuliavka','Шулявка','КПИ','Политех'],['Solomianka',"Солом'янка",'Соломенка'],['Chokolivka','Чоколівка','Чоколовка'],['Vidradnyi','Відрадний','Отрадный'],['Karavaievi Dachi','Караваєві Дачі','Караваевы Дачи'],['Zhuliany','Жуляни','Жуляны'],['Sovky','Совки'],['Oleksandrivska Slobidka','Олександрівська Слобідка','Александровская Слободка'],['Protasiv Yar','Протасов Яр'],['Holosiiv','Голосіїв','Голосеево'],['Demiivka','Деміївка','Демеевка'],['Teremky','Теремки'],['Teremky-1','Теремки-1'],['Teremky-2','Теремки-2'],['Feofaniia','Феофанія','Феофания'],['Korchuvate','Корчувате','Корчеватое'],['Mysholovka','Мишоловка','Мышеловка'],['Vydubychi','Видубичі','Выдубичи'],['Bahrynova Hora','Багринова гора'],['Obolon','Оболонь'],['Minskyi Masyv','Мінський масив','Минский массив'],['Priorka','Пріорка','Приорка'],['Kurenivka','Куренівка','Куреневка'],['Vynohradar','Виноградар','Виноградарь'],['Vitriani Hory','Вітряні гори','Ветряные горы'],['Pushcha-Vodytsia','Пуща-Водиця','Пуща-Водица'],['Troyeshchyna','Троєщина','Троещина','Вигурівщина-Троєщина','Вигуровщина-Троещина'],['Lisovyi Masyv','Лісовий масив','Лесной массив'],['Bykivnia','Биківня','Быковня'],['Voskresenka','Воскресенка'],['Raiduzhnyi','Райдужний','Радужный'],['Mykilska Slobidka','Микільська Слобідка','Микольская Слободка'],['Rusanivka','Русанівка','Русановка'],['Berezniaky','Березняки'],['Sotsmisto','Соцмісто','Соцгород'],['Darnytsia','Дарниця','Дарница'],['Nova Darnytsia','Нова Дарниця','Новая Дарница'],['Stara Darnytsia','Стара Дарниця','Старая Дарница'],['Kharkivskyi','Харківський масив','Харьковский массив'],['Pozniaky','Позняки'],['Osokorky','Осокорки'],['Bortnychi','Бортничі','Бортничи'],['Chervonyi Khutir','Червоний Хутір','Красный Хутор'],['Rembaza','Рембаза'],['DVRZ','ДВРЗ','ДВРЗ массив'],['Sviatoshyn','Святошин','Святошино'],['Borshchahivka','Борщагівка','Борщаговка'],['Pivdenna Borshchahivka','Південна Борщагівка','Южная Борщаговка'],['Mykilska Borshchahivka','Микільська Борщагівка','Никольская Борщаговка'],['Akademmistechko','Академмістечко','Академгородок'],['Bilychi','Біличі','Беличи'],['Novobilychi','Новобіличі','Новобеличи'],
20
- ['Kulynychi','Кулиничі','Кулиничи'],['524 microdistrict','524-й мікрорайон','524 микрорайон'],['North Saltivka 1','Північна Салтівка 1','Северная Салтівка 1','Северная Салтовка-1'],['North Saltivka 2','Північна Салтівка 2','Северная Салтівка 2','Северная Салтовка-2'],['North Saltivka 3','Північна Салтівка 3','Северная Салтівка 3','Северная Салтовка-3'],['North Saltivka 4','Північна Салтівка 4','Северная Салтівка 4','Северная Салтовка-4'],['North Saltivka 5','Північна Салтівка 5','Северная Салтівка 5','Северная Салтовка-5'],
21
20
  ],
22
21
  residentialComplexes: [
23
22
  ['Respublika','Respublika ЖК','Respublika Residential Complex','Respublika City','Республика','Республіка ЖК','Республика ЖК'],['French Quarter','Французький квартал','Французский квартал'],['French Quarter 2','Французький квартал 2','Французский квартал 2'],['Novopecherski Lypky','Новопечерські Липки','Новопечерские Липки'],['Taryan Towers','Taryan'],['Bulvar Fontaniv','Бульвар Фонтанів','Бульвар Фонтанов'],['Central Park'],['Greenville Park','Greenville на Печерську','Greenville на Печерске'],['Manhattan City','Manhattan'],['Chicago Central House','Chicago'],['Jack House','JackHouse'],['Skyline'],['Royal Tower'],['Signature','Signature Residence'],['Creator City','Creator','Креатор Сіті'],['UNIT.Home','Unit.Home','UNIT Home','UNIT','Юнит Хоум'],['Fayna Town','Файна Таун','Faina Town'],['Varshavskyi','Варшавський','Варшавский'],['Warszawski Plus','Варшавський Плюс','Варшавский Плюс'],['Varshavskyi 2','Варшавський 2','Варшавский 2','Варшавський Мікрорайон'],['Seven','Seven ЖК','ЖК Seven'],['RiverStone','River Stone'],['Zarichnyi','Зарічний','Заречный'],['Slavutych','Славутич'],['Slavutych 2.0'],['Great','GREAT','ЖК Great'],['Rusaniv Residence'],['Rusanivska Havan','Русанівська гавань','Русановская гавань'],['Comfort Town','Комфорт Таун'],['Nova Anhliia','Нова Англія','Новая Англия'],['ParkLand','Park Land'],['Liko-Grad','Ліко-Град','Лико-Град'],['Venice','Венеція','Венеция'],['Metropolis','Метрополіс','Метрополис'],['Kryshtalevi Dzherela','Кришталеві Джерела','Хрустальные источники'],['Lucky Land','LuckyLand'],['Dibrova Park','Діброва Парк'],['Nyvky Park','Нивки-Парк'],['White Lines','WhiteLines'],['Poetica','Поэтика'],['Greenville'],['Crystal Park'],['Crystal Park Tower'],['Smart Plaza Polytech'],['Smart Plaza Obolon'],['Obolon Residences','Obolon Residence'],['Oasis','Оазис'],['Parus','Парус'],['Podil Plaza & Residence','Podil Plaza'],['Rybalsky','Рибальський','Рыбальский','RYBALSKY'],['Dock 32','DOCK32'],['Navigator','Навигатор'],['Navigator 2','Навигатор 2'],['Ministerskyi','Міністерський','Министерский'],['Henesi House','Genesis','Henesi'],['Tetris Hall','Тетрис Холл'],
@@ -26,19 +25,19 @@ export const UA_MAJOR_LOCATION_EXTENSIONS = Object.freeze({
26
25
  ['Khreshchatyk Street','вулиця Хрещатик','улица Крещатик'],['Velyka Vasylkivska Street','Велика Васильківська','Большая Васильковская','Червоноармійська'],['Beresteiskyi Avenue','Берестейський проспект','проспект Берестейский','проспект Перемоги','проспект Победы'],['Lesi Ukrainky Boulevard','бульвар Лесі Українки','бульвар Леси Украинки'],['Saksahanskoho Street','вулиця Саксаганського','улица Саксаганского'],['Antonovycha Street','вулиця Антоновича','улица Антоновича','Горького'],['Dniprovska Naberezhna','Дніпровська набережна','Днепровская набережная'],['Mykoly Bazhana Avenue','проспект Миколи Бажана','проспект Николая Бажана'],['Hlybochytska Street','вулиця Глибочицька','улица Глубочицкая'],
27
26
  ],
28
27
  landmarks: [
29
- ['Shevchenko Park','Парк Тараса Шевченка','Парк Шевченко'],['Mariinsky Park','Маріїнський парк','Мариинский парк'],['Volodymyrska Hirka','Володимирська гірка','Владимирская горка'],['Park of Eternal Glory','Парк Вічної Слави','Парк Вечной Славы','Парк Славы'],['Holosiivskyi Park','Голосіївський парк','Голосеевский парк','Парк Рильського','Парк Рыльского'],['Feofaniia Park','Феофанія','Феофания'],['Natalka Park','Парк Наталка'],['Peremoha Park','Парк Перемога','Парк Победа'],['Kyoto Park','Парк Киото','Кіото'],['Nyvky Park','Парк Нивки'],['Syretskyi Park','Сирецький парк','Сырецкий парк'],['Partisan Glory Park','Парк Партизанської слави','Парк Партизанской славы'],['Hydropark','Гідропарк','Гидропарк'],['Trukhaniv Island','Труханів острів','Труханов остров'],['Maidan Nezalezhnosti','Майдан Незалежності','Майдан Незалежности','Independence Square','Майдан','Площадь Независимости'],['Khreshchatyk','Хрещатик','Крещатик'],['Sofiiska Square','Софійська площа','Софийская площадь','Софія Київська','София Киевская'],['Mykhailivska Square','Михайлівська площа','Михайловская площадь','Михайловский Златоверхий'],['Andriyivskyy Descent','Андріївський узвіз','Андреевский спуск'],['Golden Gate','Золоті ворота','Золотые ворота'],['Kyiv-Pechersk Lavra','Києво-Печерська лавра','Киево-Печерская лавра','Kyiv Pechersk Lavra'],['Mother Ukraine','Батьківщина-Мати','Родина-Мать'],['Arch of Freedom','Арка Свободи українського народу','Арка Свободы украинского народа'],['Kontraktova Square','Контрактова площа','Контрактовая площадь'],['Poshtova Square','Поштова площа','Почтовая площадь'],['European Square','Європейська площа','Европейская площадь'],['Olimpiyskiy Stadium','НСК Олімпійський','НСК Олимпийский','Олимпийский'],['Palats Ukraina','Палац Україна','Дворец Украина'],['VDNH','ВДНХ','Експоцентр','Экспоцентр'],['Kyiv Zoo','Київський зоопарк','Киевский зоопарк'],['Gulliver','Гулливер'],['Ocean Plaza'],['Ocean Mall'],['Respublika Park'],['Dream Town','DREAM','DREAM yellow','DREAM berry'],['Blockbuster Mall'],['River Mall'],['Retroville'],['Lavina Mall'],['Caravan','Караван'],['SkyMall','Sky Mall'],['Globus','Глобус'],['TSUM Kyiv','ЦУМ Киев','ЦУМ Київ','ЦУМ'],['Bessarabskiy Market','Бессарабський ринок','Бессарабский рынок'],['Zhytnyi Market','Житній ринок','Житный рынок'],['Volodymyrskyi Market','Володимирський ринок','Владимирский рынок'],['Darnytskyi Market','Дарницький ринок','Дарницкий рынок'],['Kyiv Central Railway Station','Центральний вокзал Київ','Киевский вокзал'],
28
+ ['Shevchenko Park','Парк Тараса Шевченка','Парк Шевченко'],['Mariinsky Park','Маріїнський парк','Мариинский парк'],['Volodymyrska Hirka','Володимирська гірка','Владимирская горка'],['Park of Eternal Glory','Парк Вічної Слави','Парк Вечной Славы','Парк Славы'],['Holosiivskyi Park','Голосіївський парк','Голосеевский парк','Парк Рильського','Парк Рыльского'],['Feofaniia Park','Феофанія','Феофания'],['Natalka Park','Парк Наталка'],['Peremoha Park','Парк Перемога','Парк Победы'],['Kyoto Park','Парк Киото','Кіото'],['Nyvky Park','Парк Нивки'],['Syretskyi Park','Сирецький парк','Сырецкий парк'],['Partisan Glory Park','Парк Партизанської слави','Парк Партизанской славы'],['Hydropark','Гідропарк','Гидропарк'],['Trukhaniv Island','Труханів острів','Труханов остров'],['Maidan Nezalezhnosti','Майдан Незалежності','Майдан Незалежности','Independence Square','Майдан','Площадь Независимости'],['Khreshchatyk','Хрещатик','Крещатик'],['Sofiiska Square','Софійська площа','Софийская площадь','Софія Київська','София Киевская'],['Mykhailivska Square','Михайлівська площа','Михайловская площадь','Михайловский Златоверхий'],['Andriyivskyy Descent','Андріївський узвіз','Андреевский спуск'],['Golden Gate','Золоті ворота','Золотые ворота'],['Kyiv-Pechersk Lavra','Києво-Печерська лавра','Киево-Печерская лавра','Kyiv Pechersk Lavra'],['Mother Ukraine','Батьківщина-Мати','Родина-Мать'],['Arch of Freedom','Арка Свободи українського народу','Арка Свободы украинского народа'],['Kontraktova Square','Контрактова площа','Контрактовая площадь'],['Poshtova Square','Поштова площа','Почтовая площадь'],['European Square','Європейська площа','Европейская площадь'],['Olimpiyskiy Stadium','НСК Олімпійський','НСК Олимпийский','Олимпийский'],['Palats Ukraina','Палац Україна','Дворец Украина'],['VDNH','ВДНХ','Експоцентр','Экспоцентр'],['Kyiv Zoo','Київський зоопарк','Киевский зоопарк'],['Gulliver','Гулливер'],['Ocean Plaza'],['Ocean Mall'],['Respublika Park'],['Dream Town','DREAM','DREAM yellow','DREAM berry'],['Blockbuster Mall'],['River Mall'],['Retroville'],['Lavina Mall'],['Caravan','Караван'],['SkyMall','Sky Mall'],['Globus','Глобус'],['TSUM Kyiv','ЦУМ Киев','ЦУМ Київ','ЦУМ'],['Bessarabskiy Market','Бессарабський ринок','Бессарабский рынок'],['Zhytnyi Market','Житній ринок','Житный рынок'],['Volodymyrskyi Market','Володимирський ринок','Владимирский рынок'],['Darnytskyi Market','Дарницький ринок','Дарницкий рынок'],['Kyiv Central Railway Station','Центральний вокзал Київ','Киевский вокзал'],
30
29
  ],
31
30
  }),
32
31
 
33
32
  Kharkiv: city({
34
33
  streets: [
35
- ['Sumska Street','вул. Сумська','вулиця Сумська','Сумська','ул. Сумская','улица Сумская','Сумская','Sumska Street','Sumska'],['Nauky Avenue','проспект Науки'],['Heroiv Kharkova Avenue','проспект Героїв Харкова','проспект Героев Харькова','Московський проспект','Московский проспект'],['Saltivske Highway','Салтівське шосе','Салтовское шоссе'],['Poltavskyi Shliakh Street','Полтавський Шлях','Полтавский Шлях'],['Klochkivska Street','вулиця Клочківська','улица Клочковская'],
34
+ ['Sumska Street','вул. Сумська','вулиця Сумська','Сумська','ул. Сумская','улица Сумская','Сумская','Sumska Street','Sumska'],['Nauky Avenue','проспект Науки','пр-т Науки','Nauky Ave','Prospekt Nauky'],['Heroiv Kharkova Avenue','проспект Героїв Харкова','проспект Героев Харькова','Московський проспект','Московский проспект','Heroiv Kharkova Ave','Moskovskyi Avenue','Moskovsky Prospekt'],['Saltivske Highway','Салтівське шосе','Салтовское шоссе','Салтівське ш.','Салтовское ш.'],['Poltavskyi Shliakh Street','Полтавський Шлях','Полтавский Шлях','вулиця Полтавський Шлях','улица Полтавский Шлях'],['Klochkivska Street','вулиця Клочківська','улица Клочковская','Клочківська','Клочковская','Klochkivska'],
36
35
  ],
37
36
  districts: [
38
37
  ['Shevchenkivskyi','Шевченківський','Шевченковский','Шевченківський район','Шевченковский район','Дзержинский'],['Kyivskyi','Київський','Киевский','Київський район','Киевский район'],['Saltivskyi','Салтівський','Салтовский','Салтівський район','Салтовский район','Московский'],['Nemyshlianskyi','Немишлянський','Немышлянский','Немишлянський район','Немышлянский район','Фрунзенский'],['Industrialnyi','Індустріальний','Индустриальный','Індустріальний район','Индустриальный район','Орджоникидзевский'],['Slobidskyi','Слобідський','Слободской','Слобідський район','Слободской район','Коминтерновский'],['Osnovianskyi',"Основ'янський",'Основянский','Основ’янський район','Основянский район','Червонозаводский'],['Novobavarskyi','Новобаварський','Новобаварский','Новобаварський район','Новобаварский район','Октябрьский'],['Kholodnohirskyi','Холодногірський','Холодногорский','Холодногірський район','Холодногорский район','Ленинский'],
39
38
  ],
40
39
  microdistricts: [
41
- ['Saltivka','Салтівка','Салтовка'],['North Saltivka','Північна Салтівка','Северная Салтовка'],...['1','2','3','4','5'].map((n)=>[`North Saltivka-${n}`,`Северная Салтовка-${n}`]),...['520','521','522','524','531','533','602','603','604','605','606','607','608','616','625','626','627','656'].map((n)=>[`${n} microdistrict`,`${n} микрорайон`]),['535A','535А'],['Pavlove Pole','Павлове Поле','Павлово Поле'],['Oleksiivka','Олексіївка','Алексеевка','Alexeyevka','Алексеевская'],['Botanical Garden','Ботанический сад','Ботсад'],['Shatylivka','Шатилівка','Шатиловка'],['Derzhprom','Держпром','Госпром'],['Center','Центр','Нагірний','Нагорный'],['Zhuravlivka','Журавлівка','Журавлевка'],['Velyka Danylivka','Велика Данилівка','Большая Даниловка'],['Piatykhatky',"П'ятихатки",'Пятихатки'],['Pomerky','Померки'],['Sokolnyky','Сокольники'],['Karavan','Караван'],['Heroiv Pratsi','Героїв Праці','Героев Труда'],['Studentska','Студентська','Студенческая'],['Barabashovo','Барабашово','Барабашова'],['Akademika Pavlova','Академіка Павлова','Академика Павлова'],['HTZ','ХТЗ'],['Novi Budynky','Нові Будинки','Новые Дома'],['23 Serpnia','23 Серпня','23 Августа'],['Kholodna Hora','Холодна Гора','Холодная Гора'],['Pivdennyi Vokzal','Південний вокзал','Южный вокзал'],['Zaliutyne','Залютине','Залютино'],['Nova Bavariia','Нова Баварія','Новая Бавария','Баварія','Бавария'],['Moskalevka','Москалівка','Москалевка'],['Osnova','Основа'],['Odeska','Одеська','Одесская'],['Haharina','Гагарина'],['Levada','Левада'],['Sportyvna','Спортивна','Спортивная'],['Metalist','Металіст','Металлист'],['Zakhysnykiv Ukrainy','Захисників України','Защитников Украины'],['Rohan','Рогань','Роганский жилмассив'],['Horizont','Горизонт'],['Skhidnyi','Східний','Восточный'],['Industrialna','Індустріальна','Индустриальная'],['Zhykhar','Жихор'],
40
+ ['Saltivka','Салтівка','Салтовка','Салтівський масив','Салтовский жилмассив'],['North Saltivka','Північна Салтівка','Северная Салтовка','Северная Салтівка'],...['1','2','3','4','5'].map((n)=>[`North Saltivka-${n}`,`Північна Салтівка ${n}`,`Північна Салтівка-${n}`,`Северная Салтовка ${n}`,`Северная Салтовка-${n}`,`Северная Салтівка ${n}`,`Северная Салтівка-${n}`]),...['520','521','522','524','531','533','602','603','604','605','606','607','608','616','625','626','627','656'].map((n)=>[`${n} microdistrict`,`${n} мікрорайон`,`${n} мікрорайон`,`${n}-й микрорайон`,`${n} микрорайон`]),['535A','535А','535а','535A microdistrict','535А мікрорайон','535а мікрорайон','535А микрорайон','535а микрорайон','Мікрорайон 535а','Микрорайон 535а'],['Kulynychi','Кулиничі','Кулиничи'],['Pavlove Pole','Павлове Поле','Павлово Поле'],['Oleksiivka','Олексіївка','Алексеевка','Alexeyevka','Алексеевская'],['Botanical Garden','Ботанічний сад','Ботанический сад','Ботсад'],['Shatylivka','Шатилівка','Шатиловка'],['Derzhprom','Держпром','Госпром'],['Center','Центр','Нагірний','Нагорный'],['Zhuravlivka','Журавлівка','Журавлевка'],['Velyka Danylivka','Велика Данилівка','Большая Даниловка'],['Piatykhatky',"П'ятихатки",'П’ятихатки','Пятихатки'],['Pomerky','Померки'],['Sokolnyky','Сокільники','Сокольники'],['Karavan','Караван'],['Heroiv Pratsi','Героїв Праці','Героев Труда'],['Studentska','Студентська','Студенческая'],['Barabashovo','Барабашово','Барабашова'],['Akademika Pavlova','Академіка Павлова','Академика Павлова'],['HTZ','ХТЗ'],['Novi Budynky','Нові Будинки','Новые Дома'],['23 Serpnia','23 Серпня','23 Августа'],['Kholodna Hora','Холодна Гора','Холодная Гора'],['Pivdennyi Vokzal','Південний вокзал','Южный вокзал'],['Zaliutyne','Залютине','Залютино'],['Nova Bavariia','Нова Баварія','Новая Бавария','Баварія','Бавария'],['Moskalevka','Москалівка','Москалевка'],['Osnova','Основа'],['Odeska','Одеська','Одесская'],['Haharina','Гагаріна','Гагарина'],['Levada','Левада'],['Sportyvna','Спортивна','Спортивная'],['Metalist','Металіст','Металлист'],['Zakhysnykiv Ukrainy','Захисників України','Защитников Украины'],['Rohan','Рогань','Роганский жилмассив'],['Horizont','Горизонт'],['Skhidnyi','Східний','Восточный'],['Industrialna','Індустріальна','Индустриальная'],['Zhykhar','Жихор'],
42
41
  ],
43
42
  residentialComplexes: [
44
43
  ['Pavlovsky Kvartal','Павлівський квартал','Павловский квартал'],['Kliuch','ЖК Ключ'],['Dim na Sumskii','Будинок на Сумській','ЖК Дом на Сумской'],['Myronosytska','ЖК Мироносицька','ЖК Мироносицкая'],['Rezidentsiia','Резиденція','Резиденция'],['Felicita','Феліціта','Феличита'],['Nimeckyi Proekt','Німецький проект','Немецкий проект'],['Hydropark','ЖК Гідропарк','ЖК Гидропарк'],['Sokolnyky','ЖК Сокільники','ЖК Сокольники'],['Flagman','ЖК Флагман'],['Ovis','ЖК Овис'],['Oasis','ЖК Оазис'],['Mlechnyi Shliakh','ЖК Млечний шлях','ЖК Млечный путь'],['Levada','ЖК Левада'],['Levada 2','ЖК Левада 2'],['Rohatynskyi','ЖК Рогатинський','ЖК Рогатинский'],['Rohatynskyi Kvartal','ЖК Рогатинський квартал','ЖК Рогатинский квартал'],['Kvant','ЖК Квант'],['Crystal','ЖК Кристал','ЖК Кристалл'],['Vorobiovi Hory','ЖК Воробьевы горы','ЖК Воробьёвы Горы','Воробйові гори','Воробьевы горы'],['Vorobiovi Hory Family','ЖК Воробьевы Горы Family'],['Ptashka','ЖК Пташка','ЖК Птичка'],['Saltivskyi','ЖК Салтівський','ЖК Салтовский'],['Meridian','ЖК Меридіан','ЖК Меридиан'],['Raiduzhnyi','ЖК Райдужний','ЖК Радужный'],['Newton','ЖК Ньютона'],['Newton 2','ЖК Ньютона 2'],['Makiivska','ЖК Макіївська','ЖК Макеевская'],['Kazka','ЖК Казка','ЖК Сказка'],['Manhattan','ЖК Манхеттен'],['River Town','Ривер Таун'],['Mira','ЖК Миру','ЖК Мира'],
@@ -128,4 +127,4 @@ export const UA_MAJOR_LOCATION_EXTENSIONS = Object.freeze({
128
127
  ['95 Kvartal','95 квартал'],['Liberation Square','площа Визволення','площадь Освобождения'],['Heroes Park','парк Героїв','парк Героев'],['Flower Clock','Квітковий годинник','Цветочные часы'],['Mershavtsev Park','парк Мершавцева'],['Haharina Park','парк Гагаріна','парк Гагарина'],['Boat Station','човнова станція','лодочная станция'],['Metalurh Stadium','стадіон Металург','стадион Металлург'],['Kryvyi Rih Botanical Garden','Криворізький ботанічний сад','Криворожский ботанический сад'],
129
128
  ],
130
129
  }),
131
- });
130
+ });
@@ -1,4 +1,5 @@
1
1
  import { locationEntries } from './location-merge.js';
2
+ import { UA_KHARKIV_LOCATION_TRANSLATIONS } from './ua-kharkiv-location-translations.js';
2
3
 
3
4
  export const UA_METRO_LOCATION_EXTENSIONS = Object.freeze({
4
5
  Kyiv: Object.freeze({
@@ -18,6 +19,22 @@ export const UA_METRO_LOCATION_EXTENSIONS = Object.freeze({
18
19
  ]),
19
20
  }),
20
21
  Kharkiv: Object.freeze({
22
+ ...UA_KHARKIV_LOCATION_TRANSLATIONS,
23
+ // This extension is merged after the legacy UA seeds. Keep late verified
24
+ // Kharkiv quarter canonicals here so they cannot be shadowed by old seed
25
+ // vocabulary while the broader Kharkiv location layer is being expanded.
26
+ microdistricts: locationEntries([
27
+ ...['455','519','601','614','615','624'].map((n) => [
28
+ `${n} microdistrict`,
29
+ `${n}-й мікрорайон`, `${n} мікрорайон`, `Мікрорайон ${n}`,
30
+ `${n}-й микрорайон`, `${n} микрорайон`, `Микрорайон ${n}`,
31
+ ]),
32
+ ['606A',
33
+ '606А', '606а', '606A microdistrict',
34
+ '606А мікрорайон', '606а мікрорайон', 'Мікрорайон 606А', 'Мікрорайон 606а',
35
+ '606А микрорайон', '606а микрорайон', 'Микрорайон 606А', 'Микрорайон 606а',
36
+ ],
37
+ ]),
21
38
  metro: locationEntries([
22
39
  ['Kholodna Hora', 'Холодна гора', 'Холодная гора'],
23
40
  ['Vokzalna', 'Вокзальна', 'Вокзальная', 'Південний вокзал', 'Южный вокзал'],