Files
TREK/shared/src/i18n/uk/reservations.ts
T
jubnl 6ef3c7ae6b feat(reservations): native booking-confirmation import via KDE KItinerary (#1102)
* feat(reservations): native booking-confirmation import via KDE KItinerary

Adds a two-step preview → confirm flow for importing booking emails,
PDFs, PKPass and HTML confirmations. The server invokes the KDE
kitinerary-extractor binary, maps JSON-LD schema.org output to TREK
reservation shapes, and persists via the existing createReservation
pipeline (accommodations, budget, places, WebSocket broadcasts).

- NestJS BookingImportModule: preview + confirm endpoints under
  /api/trips/:tripId/reservations/import/booking{,/confirm}
- KitineraryExtractorService: spawns the binary, filters stderr noise,
  handles QDateTime (@value) timezone-aware datetimes
- kitinerary-mapper: FlightReservation, TrainReservation, BusReservation,
  BoatReservation, LodgingReservation, FoodEstablishmentReservation,
  RentalCarReservation, EventReservation → typed preview items
- BookingImportService: auto-creates place rows; geocodes venues without
  coordinates via Nominatim (name+address → address → name fallback);
  resolves day IDs for accommodation linking
- BookingImportModal: drag-and-drop multi-file upload, preview cards
  with type icons, per-item exclude toggle, confirm step
- Shared Zod contracts: BookingImportPreviewItem, PreviewResponse,
  ConfirmRequest, ConfirmResponse — consumed by controller, service,
  API client and modal
- Dockerfile: node:24-trixie-slim runtime; amd64 downloads KDE static
  binary + locales; arm64 installs libkitinerary-bin + symlinks to
  fixed path; ENV KITINERARY_EXTRACTOR_PATH set for both arches
- /api/health/features exposes { bookingImport: boolean } so the UI
  hides the Import button when the binary is absent
- i18n keys (English), wiki docs, API.md, README one-liner

* i18n: add booking import translations for all 19 non-English locales

Adds 17 reservations.import.* keys and undo.importBooking to ar, br, cs,
de, es, fr, gr, hu, id, it, ja, ko, nl, pl, ru, tr, uk, zh, zh-TW.

* chore: enforce i18n parity

* docs(wiki): add KItinerary local setup instructions to dev environment guide
2026-06-04 20:40:57 +02:00

142 lines
9.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { TranslationStrings } from '../types';
const reservations: TranslationStrings = {
'reservations.title': 'Бронювання',
'reservations.empty': 'Поки немає бронювань',
'reservations.emptyHint': 'Додайте бронювання на авіаквитки, готелі та інше',
'reservations.add': 'Додати бронювання',
'reservations.addManual': 'Ручне бронювання',
'reservations.placeHint':
'Порада: бронювання краще створювати безпосередньо з місця, щоб пов’язати їх з планом дня.',
'reservations.confirmed': 'Підтверджено',
'reservations.pending': 'Очікування',
'reservations.summary': '{confirmed} підтвр., {pending} очікувань',
'reservations.fromPlan': 'З плану',
'reservations.showFiles': 'Показати файли',
'reservations.editTitle': 'Редагувати бронювання',
'reservations.status': 'Статус',
'reservations.datetime': 'Дата і час',
'reservations.startTime': 'Час початку',
'reservations.endTime': 'Час закінчення',
'reservations.date': 'Дата',
'reservations.time': 'Час',
'reservations.timeAlt': 'Час (альтернативний, напр. 19:30)',
'reservations.notes': 'Нотатки',
'reservations.notesPlaceholder': 'Додаткові нотатки...',
'reservations.meta.airline': 'Авіакомпанія',
'reservations.meta.flightNumber': 'Номер рейсу',
'reservations.meta.from': 'Звідки',
'reservations.meta.to': 'Куди',
'reservations.needsReview': 'Перевірити',
'reservations.needsReviewHint':
'Аеропорт не вдалося визначити автоматично — підтвердіть місцезнаходження.',
'reservations.searchLocation': 'Шукати станцію, порт, адресу...',
'reservations.meta.trainNumber': 'Номер поїзда',
'reservations.meta.platform': 'Платформа',
'reservations.meta.seat': 'Місце',
'reservations.meta.checkIn': 'Заїзд',
'reservations.meta.checkInUntil': 'Заселення до',
'reservations.meta.checkOut': 'Виїзд',
'reservations.meta.linkAccommodation': 'Житло',
'reservations.meta.pickAccommodation': 'Прив’язати до житла',
'reservations.meta.noAccommodation': 'Ні',
'reservations.meta.hotelPlace': 'Житло',
'reservations.meta.pickHotel': 'Оберіть житло',
'reservations.meta.fromDay': 'З',
'reservations.meta.toDay': 'По',
'reservations.meta.selectDay': 'Оберіть день',
'reservations.type.flight': 'Авіаквиток',
'reservations.type.hotel': 'Житло',
'reservations.type.restaurant': 'Ресторан',
'reservations.type.train': 'Поїзд',
'reservations.type.car': 'Автомобіль',
'reservations.type.cruise': 'Круїз',
'reservations.type.event': 'Заходи',
'reservations.type.tour': 'Екскурсія',
'reservations.type.other': 'Інше',
'reservations.type.bus': 'Автобус',
'reservations.type.ferry': 'Пором',
'reservations.type.bicycle': 'Велосипед',
'reservations.type.taxi': 'Таксі',
'reservations.type.transport_other': 'Інше',
'reservations.confirm.delete':
'Ви впевнені, що хочете видалити бронювання «{name}»?',
'reservations.confirm.deleteTitle': 'Видалити бронювання?',
'reservations.confirm.deleteBody': '«{name}» буде видалено назавжди.',
'reservations.toast.updated': 'Бронювання оновлено',
'reservations.toast.removed': 'Бронювання видалено',
'reservations.toast.fileUploaded': 'Файл завантажено',
'reservations.toast.uploadError': 'Помилка завантаження',
'reservations.newTitle': 'Нове бронювання',
'reservations.bookingType': 'Тип бронювання',
'reservations.titleLabel': 'Назва',
'reservations.titlePlaceholder':
'наприклад, Lufthansa LH123, Hotel Adlon, ...',
'reservations.locationAddress': 'Місцезнаходження / Адреса',
'reservations.locationPlaceholder': 'Адреса, аеропорт, готель...',
'reservations.confirmationCode': 'Код бронювання',
'reservations.confirmationPlaceholder': 'наприклад, ABC12345',
'reservations.day': 'День',
'reservations.noDay': 'Без дня',
'reservations.place': 'Місце',
'reservations.noPlace': 'Без місця',
'reservations.pendingSave': 'буде збережено…',
'reservations.uploading': 'Завантаження...',
'reservations.attachFile': 'Прикріпити файл',
'reservations.linkExisting': 'Прив’язати існуючий файл',
'reservations.toast.saveError': 'Помилка збереження',
'reservations.toast.updateError': 'Помилка оновлення',
'reservations.toast.deleteError': 'Помилка видалення',
'reservations.confirm.remove': 'Видалити бронювання для «{name}»?',
'reservations.linkAssignment': 'Прив’язати до призначення дня',
'reservations.pickAssignment': 'Оберіть призначення з вашого плану...',
'reservations.noAssignment': 'Без прив’язки (самостійно)',
'reservations.price': 'Ціна',
'reservations.budgetCategory': 'Категорія бюджету',
'reservations.budgetCategoryPlaceholder': 'наприклад, Транспорт, Проживання',
'reservations.budgetCategoryAuto': 'Авто (за типом бронювання)',
'reservations.budgetHint':
'При збереженні буде автоматично створено запис бюджету.',
'reservations.departureDate': 'Виліт',
'reservations.arrivalDate': 'Приліт',
'reservations.departureTime': 'Час вильоту',
'reservations.arrivalTime': 'Час прильоту',
'reservations.pickupDate': 'Отримання',
'reservations.returnDate': 'Повернення',
'reservations.pickupTime': 'Час отримання',
'reservations.returnTime': 'Час повернення',
'reservations.endDate': 'Дата закінчення',
'reservations.meta.departureTimezone': 'TZ вильоту',
'reservations.meta.arrivalTimezone': 'TZ прильоту',
'reservations.span.departure': 'Виліт',
'reservations.span.arrival': 'Приліт',
'reservations.span.inTransit': 'У дорозі',
'reservations.span.pickup': 'Отримання',
'reservations.span.return': 'Повернення',
'reservations.span.active': 'Активно',
'reservations.span.start': 'Початок',
'reservations.span.end': 'Кінець',
'reservations.span.ongoing': 'Триває',
'reservations.validation.endBeforeStart':
'Дата/час закінчення повинен бути пізніше дати/часу початку',
'reservations.addBooking': 'Добавить бронирование',
'reservations.import.title': 'Імпорт підтверджень бронювання',
'reservations.import.cta': 'Імпортувати з файлу',
'reservations.import.dropHere': 'Перетягніть файли підтверджень бронювання сюди або натисніть для вибору',
'reservations.import.dropActive': 'Відпустіть файли для імпорту',
'reservations.import.acceptedFormats': 'Підтримуються: EML, PDF, PKPass, HTML, TXT (макс. 10 МБ кожен, до 5 файлів)',
'reservations.import.parsing': 'Обробка файлів…',
'reservations.import.previewHeading': 'Знайдено {count} бронювання(нь)',
'reservations.import.previewEmpty': 'З завантажених файлів не вдалося витягти бронювання.',
'reservations.import.removeItem': 'Видалити',
'reservations.import.confirm': 'Імпортувати {count} бронювання(нь)',
'reservations.import.back': 'Назад',
'reservations.import.success': '{count} бронювання(нь) імпортовано',
'reservations.import.partialFailure': '{created} імпортовано, {failed} не вдалося',
'reservations.import.error': 'Обробка не вдалася. Переконайтесь, що файл є дійсним підтвердженням бронювання.',
'reservations.import.unavailable': 'Імпорт бронювань недоступний на цьому сервері.',
'reservations.import.unsupportedFormat': 'Непідтримуваний формат файлу. Використовуйте EML, PDF, PKPass, HTML або TXT.',
'reservations.import.fileTooLarge': 'Файл «{name}» перевищує обмеження в 10 МБ.',
};
export default reservations;