mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
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
This commit is contained in:
@@ -118,5 +118,22 @@ const reservations: TranslationStrings = {
|
||||
'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;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'استيراد خرائط Naver',
|
||||
'undo.addPlace': 'تمت إضافة المكان',
|
||||
'undo.done': 'تم التراجع: {action}',
|
||||
'undo.importBooking': 'استيراد تأكيد الحجز',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -119,5 +119,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'A data/hora final deve ser posterior à data/hora inicial',
|
||||
'reservations.addBooking': 'Adicionar reserva',
|
||||
'reservations.import.title': 'Importar confirmações de reserva',
|
||||
'reservations.import.cta': 'Importar de arquivo',
|
||||
'reservations.import.dropHere': 'Solte os arquivos de confirmação de reserva aqui ou clique para selecionar',
|
||||
'reservations.import.dropActive': 'Solte os arquivos para importar',
|
||||
'reservations.import.acceptedFormats': 'Aceitos: EML, PDF, PKPass, HTML, TXT (máx. 10 MB cada, até 5 arquivos)',
|
||||
'reservations.import.parsing': 'Analisando arquivos…',
|
||||
'reservations.import.previewHeading': '{count} reserva(s) encontrada(s)',
|
||||
'reservations.import.previewEmpty': 'Nenhuma reserva pôde ser extraída dos arquivos enviados.',
|
||||
'reservations.import.removeItem': 'Remover',
|
||||
'reservations.import.confirm': 'Importar {count} reserva(s)',
|
||||
'reservations.import.back': 'Voltar',
|
||||
'reservations.import.success': '{count} reserva(s) importada(s)',
|
||||
'reservations.import.partialFailure': '{created} importada(s), {failed} falhou/falharam',
|
||||
'reservations.import.error': 'Falha na análise. Verifique se o arquivo é uma confirmação de reserva válida.',
|
||||
'reservations.import.unavailable': 'A importação de reservas não está disponível neste servidor.',
|
||||
'reservations.import.unsupportedFormat': 'Formato de arquivo não suportado. Use EML, PDF, PKPass, HTML ou TXT.',
|
||||
'reservations.import.fileTooLarge': 'O arquivo "{name}" excede o limite de 10 MB.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Importação do Naver Maps',
|
||||
'undo.addPlace': 'Local adicionado',
|
||||
'undo.done': 'Desfeito: {action}',
|
||||
'undo.importBooking': 'Importação de confirmação de reserva',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -118,5 +118,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'Datum/čas konce musí být po datu/čase začátku',
|
||||
'reservations.addBooking': 'Přidat rezervaci',
|
||||
'reservations.import.title': 'Importovat potvrzení rezervace',
|
||||
'reservations.import.cta': 'Importovat ze souboru',
|
||||
'reservations.import.dropHere': 'Přetáhněte soubory s potvrzením rezervace sem nebo klikněte pro výběr',
|
||||
'reservations.import.dropActive': 'Pusťte soubory pro import',
|
||||
'reservations.import.acceptedFormats': 'Přijímané formáty: EML, PDF, PKPass, HTML, TXT (max. 10 MB každý, až 5 souborů)',
|
||||
'reservations.import.parsing': 'Zpracování souborů…',
|
||||
'reservations.import.previewHeading': 'Nalezeno {count} rezervace/í',
|
||||
'reservations.import.previewEmpty': 'Z nahraných souborů se nepodařilo extrahovat žádné rezervace.',
|
||||
'reservations.import.removeItem': 'Odebrat',
|
||||
'reservations.import.confirm': 'Importovat {count} rezervaci/í',
|
||||
'reservations.import.back': 'Zpět',
|
||||
'reservations.import.success': '{count} rezervace/í importováno',
|
||||
'reservations.import.partialFailure': '{created} importováno, {failed} selhalo',
|
||||
'reservations.import.error': 'Zpracování selhalo. Ujistěte se, že soubor je platným potvrzením rezervace.',
|
||||
'reservations.import.unavailable': 'Import rezervací není na tomto serveru k dispozici.',
|
||||
'reservations.import.unsupportedFormat': 'Nepodporovaný formát souboru. Použijte EML, PDF, PKPass, HTML nebo TXT.',
|
||||
'reservations.import.fileTooLarge': 'Soubor „{name}" překračuje limit 10 MB.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Import z Naver Maps',
|
||||
'undo.addPlace': 'Místo přidáno',
|
||||
'undo.done': 'Vráceno zpět: {action}',
|
||||
'undo.importBooking': 'Import potvrzení rezervace',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -120,5 +120,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'Enddatum/-zeit muss nach dem Startdatum/-zeit liegen',
|
||||
'reservations.addBooking': 'Buchung hinzufügen',
|
||||
'reservations.import.title': 'Buchungsbestätigungen importieren',
|
||||
'reservations.import.cta': 'Aus Datei importieren',
|
||||
'reservations.import.dropHere': 'Buchungsbestätigungsdateien hier ablegen oder klicken zum Auswählen',
|
||||
'reservations.import.dropActive': 'Dateien zum Importieren ablegen',
|
||||
'reservations.import.acceptedFormats': 'Akzeptiert: EML, PDF, PKPass, HTML, TXT (max. 10 MB pro Datei, bis zu 5 Dateien)',
|
||||
'reservations.import.parsing': 'Dateien werden verarbeitet…',
|
||||
'reservations.import.previewHeading': '{count} Reservierung(en) gefunden',
|
||||
'reservations.import.previewEmpty': 'Aus den hochgeladenen Dateien konnten keine Reservierungen extrahiert werden.',
|
||||
'reservations.import.removeItem': 'Entfernen',
|
||||
'reservations.import.confirm': '{count} Reservierung(en) importieren',
|
||||
'reservations.import.back': 'Zurück',
|
||||
'reservations.import.success': '{count} Reservierung(en) importiert',
|
||||
'reservations.import.partialFailure': '{created} importiert, {failed} fehlgeschlagen',
|
||||
'reservations.import.error': 'Verarbeitung fehlgeschlagen. Stellen Sie sicher, dass die Datei eine gültige Buchungsbestätigung ist.',
|
||||
'reservations.import.unavailable': 'Buchungsimport ist auf diesem Server nicht verfügbar.',
|
||||
'reservations.import.unsupportedFormat': 'Nicht unterstütztes Dateiformat. Verwenden Sie EML, PDF, PKPass, HTML oder TXT.',
|
||||
'reservations.import.fileTooLarge': 'Datei „{name}" überschreitet das 10-MB-Limit.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Naver Maps-Import',
|
||||
'undo.addPlace': 'Ort hinzugefügt',
|
||||
'undo.done': 'Rückgängig gemacht: {action}',
|
||||
'undo.importBooking': 'Buchungsbestätigung-Import',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -119,5 +119,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'End date/time must be after start date/time',
|
||||
'reservations.addBooking': 'Add booking',
|
||||
'reservations.import.title': 'Import booking confirmations',
|
||||
'reservations.import.cta': 'Import from file',
|
||||
'reservations.import.dropHere': 'Drop booking confirmation files here, or click to select',
|
||||
'reservations.import.dropActive': 'Drop files to import',
|
||||
'reservations.import.acceptedFormats': 'Accepted: EML, PDF, PKPass, HTML, TXT (max 10 MB each, up to 5 files)',
|
||||
'reservations.import.parsing': 'Parsing files…',
|
||||
'reservations.import.previewHeading': '{count} reservation(s) found',
|
||||
'reservations.import.previewEmpty': 'No reservations could be extracted from the uploaded files.',
|
||||
'reservations.import.removeItem': 'Remove',
|
||||
'reservations.import.confirm': 'Import {count} reservation(s)',
|
||||
'reservations.import.back': 'Back',
|
||||
'reservations.import.success': '{count} reservation(s) imported',
|
||||
'reservations.import.partialFailure': '{created} imported, {failed} failed',
|
||||
'reservations.import.error': 'Parsing failed. Make sure the file is a valid booking confirmation.',
|
||||
'reservations.import.unavailable': 'Booking import is not available on this server.',
|
||||
'reservations.import.unsupportedFormat': 'Unsupported file format. Use EML, PDF, PKPass, HTML, or TXT.',
|
||||
'reservations.import.fileTooLarge': 'File "{name}" exceeds 10 MB limit.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -15,6 +15,7 @@ const undo: TranslationStrings = {
|
||||
'undo.importKeyholeMarkup': 'KMZ/KML import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
'undo.importNaverList': 'Naver Maps import',
|
||||
'undo.importBooking': 'Booking confirmation import',
|
||||
'undo.addPlace': 'Place added',
|
||||
'undo.done': 'Undone: {action}',
|
||||
};
|
||||
|
||||
@@ -119,5 +119,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.meta.fromDay': 'Desde',
|
||||
'reservations.meta.toDay': 'Hasta',
|
||||
'reservations.meta.selectDay': 'Seleccionar día',
|
||||
'reservations.import.title': 'Importar confirmaciones de reserva',
|
||||
'reservations.import.cta': 'Importar desde archivo',
|
||||
'reservations.import.dropHere': 'Suelta los archivos de confirmación de reserva aquí o haz clic para seleccionar',
|
||||
'reservations.import.dropActive': 'Suelta los archivos para importar',
|
||||
'reservations.import.acceptedFormats': 'Aceptados: EML, PDF, PKPass, HTML, TXT (máx. 10 MB por archivo, hasta 5 archivos)',
|
||||
'reservations.import.parsing': 'Analizando archivos…',
|
||||
'reservations.import.previewHeading': '{count} reserva(s) encontrada(s)',
|
||||
'reservations.import.previewEmpty': 'No se pudieron extraer reservas de los archivos subidos.',
|
||||
'reservations.import.removeItem': 'Eliminar',
|
||||
'reservations.import.confirm': 'Importar {count} reserva(s)',
|
||||
'reservations.import.back': 'Atrás',
|
||||
'reservations.import.success': '{count} reserva(s) importada(s)',
|
||||
'reservations.import.partialFailure': '{created} importada(s), {failed} fallida(s)',
|
||||
'reservations.import.error': 'Error al analizar. Asegúrate de que el archivo sea una confirmación de reserva válida.',
|
||||
'reservations.import.unavailable': 'La importación de reservas no está disponible en este servidor.',
|
||||
'reservations.import.unsupportedFormat': 'Formato de archivo no compatible. Usa EML, PDF, PKPass, HTML o TXT.',
|
||||
'reservations.import.fileTooLarge': 'El archivo «{name}» supera el límite de 10 MB.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Importación de Naver Maps',
|
||||
'undo.addPlace': 'Lugar agregado',
|
||||
'undo.done': 'Deshecho: {action}',
|
||||
'undo.importBooking': 'Importar confirmación de reserva',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -120,5 +120,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'La date/heure de fin doit être postérieure à la date/heure de début',
|
||||
'reservations.addBooking': 'Ajouter une réservation',
|
||||
'reservations.import.title': 'Importer des confirmations de réservation',
|
||||
'reservations.import.cta': 'Importer depuis un fichier',
|
||||
'reservations.import.dropHere': 'Déposez les fichiers de confirmation de réservation ici ou cliquez pour sélectionner',
|
||||
'reservations.import.dropActive': 'Déposez les fichiers pour importer',
|
||||
'reservations.import.acceptedFormats': "Acceptés : EML, PDF, PKPass, HTML, TXT (max. 10 Mo chacun, jusqu'à 5 fichiers)",
|
||||
'reservations.import.parsing': 'Analyse des fichiers…',
|
||||
'reservations.import.previewHeading': '{count} réservation(s) trouvée(s)',
|
||||
'reservations.import.previewEmpty': "Aucune réservation n'a pu être extraite des fichiers envoyés.",
|
||||
'reservations.import.removeItem': 'Supprimer',
|
||||
'reservations.import.confirm': 'Importer {count} réservation(s)',
|
||||
'reservations.import.back': 'Retour',
|
||||
'reservations.import.success': '{count} réservation(s) importée(s)',
|
||||
'reservations.import.partialFailure': '{created} importée(s), {failed} échouée(s)',
|
||||
'reservations.import.error': 'Analyse échouée. Assurez-vous que le fichier est une confirmation de réservation valide.',
|
||||
'reservations.import.unavailable': "L'import de réservations n'est pas disponible sur ce serveur.",
|
||||
'reservations.import.unsupportedFormat': 'Format de fichier non pris en charge. Utilisez EML, PDF, PKPass, HTML ou TXT.',
|
||||
'reservations.import.fileTooLarge': 'Le fichier « {name} » dépasse la limite de 10 Mo.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Import Naver Maps',
|
||||
'undo.addPlace': 'Lieu ajouté',
|
||||
'undo.done': 'Annulé : {action}',
|
||||
'undo.importBooking': 'Import de confirmation de réservation',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -121,5 +121,22 @@ const reservations: TranslationStrings = {
|
||||
'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 MB το καθένα, έως 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 MB.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Εισαγωγή Naver Maps',
|
||||
'undo.addPlace': 'Η τοποθεσία προστέθηκε',
|
||||
'undo.done': 'Αναιρέθηκε: {action}',
|
||||
'undo.importBooking': 'Εισαγωγή επιβεβαίωσης κράτησης',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -120,5 +120,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'A befejezés dátuma/időpontja a kezdés utáni kell legyen',
|
||||
'reservations.addBooking': 'Foglalás hozzáadása',
|
||||
'reservations.import.title': 'Foglalási visszaigazolások importálása',
|
||||
'reservations.import.cta': 'Importálás fájlból',
|
||||
'reservations.import.dropHere': 'Dobja ide a foglalási visszaigazolás fájlokat, vagy kattintson a kiválasztáshoz',
|
||||
'reservations.import.dropActive': 'Dobja ide a fájlokat az importáláshoz',
|
||||
'reservations.import.acceptedFormats': 'Elfogadott: EML, PDF, PKPass, HTML, TXT (max. 10 MB darabonként, legfeljebb 5 fájl)',
|
||||
'reservations.import.parsing': 'Fájlok feldolgozása…',
|
||||
'reservations.import.previewHeading': '{count} foglalás találva',
|
||||
'reservations.import.previewEmpty': 'A feltöltött fájlokból nem sikerült foglalásokat kinyerni.',
|
||||
'reservations.import.removeItem': 'Eltávolítás',
|
||||
'reservations.import.confirm': '{count} foglalás importálása',
|
||||
'reservations.import.back': 'Vissza',
|
||||
'reservations.import.success': '{count} foglalás importálva',
|
||||
'reservations.import.partialFailure': '{created} importálva, {failed} sikertelen',
|
||||
'reservations.import.error': 'A feldolgozás sikertelen. Győződjön meg arról, hogy a fájl érvényes foglalási visszaigazolás.',
|
||||
'reservations.import.unavailable': 'A foglalásimportálás nem érhető el ezen a kiszolgálón.',
|
||||
'reservations.import.unsupportedFormat': 'Nem támogatott fájlformátum. Használjon EML, PDF, PKPass, HTML vagy TXT formátumot.',
|
||||
'reservations.import.fileTooLarge': 'A(z) „{name}" fájl meghaladja a 10 MB-os korlátot.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Naver Maps importálás',
|
||||
'undo.addPlace': 'Hely hozzáadva',
|
||||
'undo.done': 'Visszavonva: {action}',
|
||||
'undo.importBooking': 'Foglalási visszaigazolás importálása',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -119,5 +119,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'Tanggal/waktu selesai harus setelah tanggal/waktu mulai',
|
||||
'reservations.addBooking': 'Tambah pemesanan',
|
||||
'reservations.import.title': 'Impor konfirmasi pemesanan',
|
||||
'reservations.import.cta': 'Impor dari file',
|
||||
'reservations.import.dropHere': 'Seret file konfirmasi pemesanan ke sini atau klik untuk memilih',
|
||||
'reservations.import.dropActive': 'Lepaskan file untuk mengimpor',
|
||||
'reservations.import.acceptedFormats': 'Diterima: EML, PDF, PKPass, HTML, TXT (maks. 10 MB per file, hingga 5 file)',
|
||||
'reservations.import.parsing': 'Memproses file…',
|
||||
'reservations.import.previewHeading': '{count} pemesanan ditemukan',
|
||||
'reservations.import.previewEmpty': 'Tidak ada pemesanan yang dapat diekstrak dari file yang diunggah.',
|
||||
'reservations.import.removeItem': 'Hapus',
|
||||
'reservations.import.confirm': 'Impor {count} pemesanan',
|
||||
'reservations.import.back': 'Kembali',
|
||||
'reservations.import.success': '{count} pemesanan berhasil diimpor',
|
||||
'reservations.import.partialFailure': '{created} berhasil diimpor, {failed} gagal',
|
||||
'reservations.import.error': 'Pemrosesan gagal. Pastikan file adalah konfirmasi pemesanan yang valid.',
|
||||
'reservations.import.unavailable': 'Impor pemesanan tidak tersedia di server ini.',
|
||||
'reservations.import.unsupportedFormat': 'Format file tidak didukung. Gunakan EML, PDF, PKPass, HTML, atau TXT.',
|
||||
'reservations.import.fileTooLarge': 'File "{name}" melebihi batas 10 MB.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Impor Naver Maps',
|
||||
'undo.addPlace': 'Tempat ditambahkan',
|
||||
'undo.done': 'Dibatalkan: {action}',
|
||||
'undo.importBooking': 'Impor konfirmasi pemesanan',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -121,5 +121,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'La data/ora di fine deve essere successiva alla data/ora di inizio',
|
||||
'reservations.addBooking': 'Aggiungi prenotazione',
|
||||
'reservations.import.title': 'Importa conferme di prenotazione',
|
||||
'reservations.import.cta': 'Importa da file',
|
||||
'reservations.import.dropHere': 'Trascina i file di conferma prenotazione qui o clicca per selezionare',
|
||||
'reservations.import.dropActive': 'Rilascia i file per importare',
|
||||
'reservations.import.acceptedFormats': 'Accettati: EML, PDF, PKPass, HTML, TXT (max 10 MB ciascuno, fino a 5 file)',
|
||||
'reservations.import.parsing': 'Analisi dei file in corso…',
|
||||
'reservations.import.previewHeading': '{count} prenotazione/i trovata/e',
|
||||
'reservations.import.previewEmpty': 'Nessuna prenotazione è stata estratta dai file caricati.',
|
||||
'reservations.import.removeItem': 'Rimuovi',
|
||||
'reservations.import.confirm': 'Importa {count} prenotazione/i',
|
||||
'reservations.import.back': 'Indietro',
|
||||
'reservations.import.success': '{count} prenotazione/i importata/e',
|
||||
'reservations.import.partialFailure': '{created} importata/e, {failed} fallita/e',
|
||||
'reservations.import.error': "Analisi fallita. Assicurati che il file sia una conferma di prenotazione valida.",
|
||||
'reservations.import.unavailable': "L'importazione di prenotazioni non è disponibile su questo server.",
|
||||
'reservations.import.unsupportedFormat': 'Formato file non supportato. Usa EML, PDF, PKPass, HTML o TXT.',
|
||||
'reservations.import.fileTooLarge': 'Il file "{name}" supera il limite di 10 MB.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Importazione Naver Maps',
|
||||
'undo.addPlace': 'Luogo aggiunto',
|
||||
'undo.done': 'Annullato: {action}',
|
||||
'undo.importBooking': 'Importazione conferma prenotazione',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -117,5 +117,22 @@ const reservations: TranslationStrings = {
|
||||
'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 MB、最大 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 MB の制限を超えています。',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Naverマップをインポート',
|
||||
'undo.addPlace': '場所を追加',
|
||||
'undo.done': '元に戻しました: {action}',
|
||||
'undo.importBooking': '予約確認書インポート',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -117,5 +117,22 @@ const reservations: TranslationStrings = {
|
||||
'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 MB, 최대 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 MB 제한을 초과합니다.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': '네이버 지도 가져오기',
|
||||
'undo.addPlace': '장소가 추가되었습니다',
|
||||
'undo.done': '실행 취소됨: {action}',
|
||||
'undo.importBooking': '예약 확인서 가져오기',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -120,5 +120,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'Einddatum/-tijd moet na de startdatum/-tijd liggen',
|
||||
'reservations.addBooking': 'Boeking toevoegen',
|
||||
'reservations.import.title': 'Boekingsbevestigingen importeren',
|
||||
'reservations.import.cta': 'Importeren vanuit bestand',
|
||||
'reservations.import.dropHere': 'Zet hier bevestigingsbestanden neer of klik om te selecteren',
|
||||
'reservations.import.dropActive': 'Laat bestanden los om te importeren',
|
||||
'reservations.import.acceptedFormats': 'Geaccepteerd: EML, PDF, PKPass, HTML, TXT (max. 10 MB per stuk, tot 5 bestanden)',
|
||||
'reservations.import.parsing': 'Bestanden verwerken…',
|
||||
'reservations.import.previewHeading': '{count} reservering(en) gevonden',
|
||||
'reservations.import.previewEmpty': 'Er konden geen reserveringen worden geëxtraheerd uit de geüploade bestanden.',
|
||||
'reservations.import.removeItem': 'Verwijderen',
|
||||
'reservations.import.confirm': '{count} reservering(en) importeren',
|
||||
'reservations.import.back': 'Terug',
|
||||
'reservations.import.success': '{count} reservering(en) geïmporteerd',
|
||||
'reservations.import.partialFailure': '{created} geïmporteerd, {failed} mislukt',
|
||||
'reservations.import.error': 'Verwerking mislukt. Zorg ervoor dat het bestand een geldige boekingsbevestiging is.',
|
||||
'reservations.import.unavailable': 'Boeking importeren is niet beschikbaar op deze server.',
|
||||
'reservations.import.unsupportedFormat': 'Niet-ondersteund bestandsformaat. Gebruik EML, PDF, PKPass, HTML of TXT.',
|
||||
'reservations.import.fileTooLarge': 'Bestand "{name}" overschrijdt de limiet van 10 MB.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Naver Maps-import',
|
||||
'undo.addPlace': 'Locatie toegevoegd',
|
||||
'undo.done': 'Ongedaan gemaakt: {action}',
|
||||
'undo.importBooking': 'Boekingsbevestiging importeren',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -120,5 +120,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'Data/godzina zakończenia musi być późniejsza niż data/godzina rozpoczęcia',
|
||||
'reservations.addBooking': 'Dodaj rezerwację',
|
||||
'reservations.import.title': 'Importuj potwierdzenia rezerwacji',
|
||||
'reservations.import.cta': 'Importuj z pliku',
|
||||
'reservations.import.dropHere': 'Upuść pliki potwierdzeń rezerwacji tutaj lub kliknij, aby wybrać',
|
||||
'reservations.import.dropActive': 'Upuść pliki, aby zaimportować',
|
||||
'reservations.import.acceptedFormats': 'Akceptowane: EML, PDF, PKPass, HTML, TXT (maks. 10 MB każdy, do 5 plików)',
|
||||
'reservations.import.parsing': 'Przetwarzanie plików…',
|
||||
'reservations.import.previewHeading': 'Znaleziono {count} rezerwację/rezerwacje',
|
||||
'reservations.import.previewEmpty': 'Nie udało się wyodrębnić rezerwacji z przesłanych plików.',
|
||||
'reservations.import.removeItem': 'Usuń',
|
||||
'reservations.import.confirm': 'Importuj {count} rezerwację/rezerwacje',
|
||||
'reservations.import.back': 'Wstecz',
|
||||
'reservations.import.success': 'Zaimportowano {count} rezerwację/rezerwacje',
|
||||
'reservations.import.partialFailure': '{created} zaimportowano, {failed} nieudane',
|
||||
'reservations.import.error': 'Przetwarzanie nieudane. Upewnij się, że plik jest prawidłowym potwierdzeniem rezerwacji.',
|
||||
'reservations.import.unavailable': 'Import rezerwacji nie jest dostępny na tym serwerze.',
|
||||
'reservations.import.unsupportedFormat': 'Nieobsługiwany format pliku. Użyj EML, PDF, PKPass, HTML lub TXT.',
|
||||
'reservations.import.fileTooLarge': 'Plik „{name}" przekracza limit 10 MB.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Import Naver Maps',
|
||||
'undo.addPlace': 'Miejsce dodane',
|
||||
'undo.done': 'Cofnięto: {action}',
|
||||
'undo.importBooking': 'Import potwierdzenia rezerwacji',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -120,5 +120,22 @@ const reservations: TranslationStrings = {
|
||||
'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;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Импорт из Naver Maps',
|
||||
'undo.addPlace': 'Место добавлено',
|
||||
'undo.done': 'Отменено: {action}',
|
||||
'undo.importBooking': 'Импорт подтверждения бронирования',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -120,5 +120,22 @@ const reservations: TranslationStrings = {
|
||||
'reservations.validation.endBeforeStart':
|
||||
'Bitiş tarihi/saati başlangıçtan sonra olmalı',
|
||||
'reservations.addBooking': 'Rezervasyon ekle',
|
||||
'reservations.import.title': 'Rezervasyon onaylarını içe aktar',
|
||||
'reservations.import.cta': 'Dosyadan içe aktar',
|
||||
'reservations.import.dropHere': 'Rezervasyon onay dosyalarını buraya sürükleyin veya seçmek için tıklayın',
|
||||
'reservations.import.dropActive': 'İçe aktarmak için dosyaları bırakın',
|
||||
'reservations.import.acceptedFormats': 'Kabul edilenler: EML, PDF, PKPass, HTML, TXT (her biri maks. 10 MB, en fazla 5 dosya)',
|
||||
'reservations.import.parsing': 'Dosyalar işleniyor…',
|
||||
'reservations.import.previewHeading': '{count} rezervasyon bulundu',
|
||||
'reservations.import.previewEmpty': 'Yüklenen dosyalardan hiçbir rezervasyon çıkarılamadı.',
|
||||
'reservations.import.removeItem': 'Kaldır',
|
||||
'reservations.import.confirm': '{count} rezervasyonu içe aktar',
|
||||
'reservations.import.back': 'Geri',
|
||||
'reservations.import.success': '{count} rezervasyon içe aktarıldı',
|
||||
'reservations.import.partialFailure': '{created} içe aktarıldı, {failed} başarısız',
|
||||
'reservations.import.error': 'İşlem başarısız. Dosyanın geçerli bir rezervasyon onayı olduğundan emin olun.',
|
||||
'reservations.import.unavailable': 'Rezervasyon içe aktarma bu sunucuda mevcut değil.',
|
||||
'reservations.import.unsupportedFormat': 'Desteklenmeyen dosya biçimi. EML, PDF, PKPass, HTML veya TXT kullanın.',
|
||||
'reservations.import.fileTooLarge': '"{name}" dosyası 10 MB sınırını aşıyor.',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Naver Haritalar içe aktarma',
|
||||
'undo.addPlace': 'Yer eklendi',
|
||||
'undo.done': 'Geri alındı: {action}',
|
||||
'undo.importBooking': 'Rezervasyon onayı içe aktarma',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -120,5 +120,22 @@ const reservations: TranslationStrings = {
|
||||
'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;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Імпорт з Naver Maps',
|
||||
'undo.addPlace': 'Місце додано',
|
||||
'undo.done': 'Відмінено: {action}',
|
||||
'undo.importBooking': 'Імпорт підтвердження бронювання',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -116,5 +116,22 @@ const reservations: TranslationStrings = {
|
||||
'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 MB,最多 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 MB 限制。',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Naver 地圖匯入',
|
||||
'undo.addPlace': '地點已新增',
|
||||
'undo.done': '已撤銷:{action}',
|
||||
'undo.importBooking': '匯入訂位確認',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -116,5 +116,22 @@ const reservations: TranslationStrings = {
|
||||
'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 MB,最多 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 MB 限制。',
|
||||
};
|
||||
export default reservations;
|
||||
|
||||
@@ -17,5 +17,6 @@ const undo: TranslationStrings = {
|
||||
'undo.importNaverList': 'Naver 地图导入',
|
||||
'undo.addPlace': '地点已添加',
|
||||
'undo.done': '已撤销:{action}',
|
||||
'undo.importBooking': '导入预订确认',
|
||||
};
|
||||
export default undo;
|
||||
|
||||
@@ -141,3 +141,66 @@ export const accommodationUpdateRequestSchema = open;
|
||||
export type AccommodationUpdateRequest = z.infer<
|
||||
typeof accommodationUpdateRequestSchema
|
||||
>;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Booking import (KItinerary)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const bookingImportEndpointSchema = z.object({
|
||||
role: z.enum(['from', 'to', 'stop']),
|
||||
sequence: z.number(),
|
||||
name: z.string(),
|
||||
code: z.string().nullable(),
|
||||
lat: z.number(),
|
||||
lng: z.number(),
|
||||
timezone: z.string().nullable(),
|
||||
local_time: z.string().nullable(),
|
||||
local_date: z.string().nullable(),
|
||||
});
|
||||
|
||||
const bookingImportVenueSchema = z.object({
|
||||
name: z.string(),
|
||||
lat: z.number().optional(),
|
||||
lng: z.number().optional(),
|
||||
address: z.string().optional(),
|
||||
website: z.string().optional(),
|
||||
phone: z.string().optional(),
|
||||
});
|
||||
|
||||
const bookingImportAccommodationSchema = z.object({
|
||||
check_in: z.string().optional(),
|
||||
check_out: z.string().optional(),
|
||||
confirmation: z.string().optional(),
|
||||
});
|
||||
|
||||
export const bookingImportPreviewItemSchema = z.object({
|
||||
type: z.string(),
|
||||
title: z.string().min(1),
|
||||
reservation_time: z.string().nullable().optional(),
|
||||
reservation_end_time: z.string().nullable().optional(),
|
||||
confirmation_number: z.string().nullable().optional(),
|
||||
location: z.string().nullable().optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
endpoints: z.array(bookingImportEndpointSchema).optional(),
|
||||
needs_review: z.boolean().optional(),
|
||||
_venue: bookingImportVenueSchema.optional(),
|
||||
_accommodation: bookingImportAccommodationSchema.optional(),
|
||||
source: z.object({ fileName: z.string(), index: z.number() }),
|
||||
});
|
||||
export type BookingImportPreviewItem = z.infer<typeof bookingImportPreviewItemSchema>;
|
||||
|
||||
export const bookingImportPreviewResponseSchema = z.object({
|
||||
items: z.array(bookingImportPreviewItemSchema),
|
||||
warnings: z.array(z.string()),
|
||||
});
|
||||
export type BookingImportPreviewResponse = z.infer<typeof bookingImportPreviewResponseSchema>;
|
||||
|
||||
export const bookingImportConfirmRequestSchema = z.object({
|
||||
items: z.array(bookingImportPreviewItemSchema).min(1),
|
||||
});
|
||||
export type BookingImportConfirmRequest = z.infer<typeof bookingImportConfirmRequestSchema>;
|
||||
|
||||
export const bookingImportConfirmResponseSchema = z.object({
|
||||
created: z.array(reservationSchema),
|
||||
});
|
||||
export type BookingImportConfirmResponse = z.infer<typeof bookingImportConfirmResponseSchema>;
|
||||
|
||||
Reference in New Issue
Block a user