mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
This commit is contained in:
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'وقت النهاية قبل وقت البداية',
|
||||
'places.timeCollision': 'تداخل في الوقت مع:',
|
||||
'places.formWebsite': 'الموقع الإلكتروني',
|
||||
'places.formPhone': 'الهاتف',
|
||||
'places.formEmail': 'البريد الإلكتروني',
|
||||
'places.hoursAdd': 'إضافة ساعات العمل',
|
||||
'places.hoursClosed': 'مغلق',
|
||||
'places.hoursOpens': 'يفتح',
|
||||
'places.hoursCloses': 'يغلق',
|
||||
'places.hoursCopyFirst': 'استخدم ساعات {day} لكل الأيام',
|
||||
'places.hoursRemove': 'إزالة ساعات العمل',
|
||||
'places.formNotes': 'ملاحظات',
|
||||
'places.formNotesPlaceholder': 'ملاحظات شخصية...',
|
||||
'places.assignmentNotes': 'ملاحظات لهذا اليوم',
|
||||
|
||||
@@ -104,6 +104,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Bitmə vaxtı başlanğıc vaxtından əvvəldir',
|
||||
'places.timeCollision': 'Vaxt üst-üstə düşür:',
|
||||
'places.formWebsite': 'Veb-sayt',
|
||||
'places.formPhone': 'Telefon',
|
||||
'places.formEmail': 'E-poçt',
|
||||
'places.hoursAdd': 'İş saatlarını əlavə et',
|
||||
'places.hoursClosed': 'Bağlı',
|
||||
'places.hoursOpens': 'açılır',
|
||||
'places.hoursCloses': 'bağlanır',
|
||||
'places.hoursCopyFirst': '{day} saatlarını bütün günlərə tətbiq et',
|
||||
'places.hoursRemove': 'İş saatlarını sil',
|
||||
'places.formNotes': 'Qeydlər',
|
||||
'places.formNotesPlaceholder': 'Şəxsi qeydlər...',
|
||||
'places.assignmentNotes': 'Bu gün üçün qeydlər',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'O horário de fim é antes do início',
|
||||
'places.timeCollision': 'Sobreposição de horário com:',
|
||||
'places.formWebsite': 'Site',
|
||||
'places.formPhone': 'Telefone',
|
||||
'places.formEmail': 'E-mail',
|
||||
'places.hoursAdd': 'Adicionar horário de funcionamento',
|
||||
'places.hoursClosed': 'Fechado',
|
||||
'places.hoursOpens': 'abre',
|
||||
'places.hoursCloses': 'fecha',
|
||||
'places.hoursCopyFirst': 'Usar o horário de {day} em todos os dias',
|
||||
'places.hoursRemove': 'Remover horário de funcionamento',
|
||||
'places.formNotes': 'Notas',
|
||||
'places.formNotesPlaceholder': 'Notas pessoais...',
|
||||
'places.assignmentNotes': 'Notas para este dia',
|
||||
|
||||
@@ -93,6 +93,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': "L'hora de fi és anterior a la d'inici",
|
||||
'places.timeCollision': 'Solapament horari amb:',
|
||||
'places.formWebsite': 'Lloc web',
|
||||
'places.formPhone': 'Telèfon',
|
||||
'places.formEmail': 'Correu electrònic',
|
||||
'places.hoursAdd': "Afegeix l'horari",
|
||||
'places.hoursClosed': 'Tancat',
|
||||
'places.hoursOpens': 'obre',
|
||||
'places.hoursCloses': 'tanca',
|
||||
'places.hoursCopyFirst': "Fes servir l'horari de {day} per a tots els dies",
|
||||
'places.hoursRemove': "Elimina l'horari",
|
||||
'places.formNotes': 'Notes',
|
||||
'places.formNotesPlaceholder': 'Notes personals...',
|
||||
'places.assignmentNotes': 'Notes per a aquest dia',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Čas konce je před časem začátku',
|
||||
'places.timeCollision': 'Časový překryv s:',
|
||||
'places.formWebsite': 'Webové stránky',
|
||||
'places.formPhone': 'Telefon',
|
||||
'places.formEmail': 'E-mail',
|
||||
'places.hoursAdd': 'Přidat otevírací dobu',
|
||||
'places.hoursClosed': 'Zavřeno',
|
||||
'places.hoursOpens': 'otevírá',
|
||||
'places.hoursCloses': 'zavírá',
|
||||
'places.hoursCopyFirst': 'Použít časy z {day} pro všechny dny',
|
||||
'places.hoursRemove': 'Odebrat otevírací dobu',
|
||||
'places.formNotes': 'Poznámky',
|
||||
'places.formNotesPlaceholder': 'Osobní poznámky...',
|
||||
'places.assignmentNotes': 'Poznámky pro tento den',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Endzeit liegt vor der Startzeit',
|
||||
'places.timeCollision': 'Zeitliche Überschneidung mit:',
|
||||
'places.formWebsite': 'Website',
|
||||
'places.formPhone': 'Telefon',
|
||||
'places.formEmail': 'E-Mail',
|
||||
'places.hoursAdd': 'Öffnungszeiten hinzufügen',
|
||||
'places.hoursClosed': 'Geschlossen',
|
||||
'places.hoursOpens': 'öffnet',
|
||||
'places.hoursCloses': 'schließt',
|
||||
'places.hoursCopyFirst': 'Zeiten vom {day} für alle Tage übernehmen',
|
||||
'places.hoursRemove': 'Öffnungszeiten entfernen',
|
||||
'places.formNotes': 'Notizen',
|
||||
'places.formNotesPlaceholder': 'Persönliche Notizen...',
|
||||
'places.assignmentNotes': 'Notizen für diesen Tag',
|
||||
|
||||
@@ -98,6 +98,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'End time is before start time',
|
||||
'places.timeCollision': 'Time overlap with:',
|
||||
'places.formWebsite': 'Website',
|
||||
'places.formPhone': 'Phone',
|
||||
'places.formEmail': 'E-mail',
|
||||
'places.hoursAdd': 'Add opening hours',
|
||||
'places.hoursClosed': 'Closed',
|
||||
'places.hoursOpens': 'opens',
|
||||
'places.hoursCloses': 'closes',
|
||||
'places.hoursCopyFirst': "Use {day}'s hours for every day",
|
||||
'places.hoursRemove': 'Remove opening hours',
|
||||
'places.formNotes': 'Notes',
|
||||
'places.formNotesPlaceholder': 'Personal notes...',
|
||||
'places.assignmentNotes': 'Notes for this day',
|
||||
|
||||
@@ -95,6 +95,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'La hora de fin es anterior a la de inicio',
|
||||
'places.timeCollision': 'Solapamiento horario con:',
|
||||
'places.formWebsite': 'Página web',
|
||||
'places.formPhone': 'Teléfono',
|
||||
'places.formEmail': 'Correo electrónico',
|
||||
'places.hoursAdd': 'Añadir horario',
|
||||
'places.hoursClosed': 'Cerrado',
|
||||
'places.hoursOpens': 'abre',
|
||||
'places.hoursCloses': 'cierra',
|
||||
'places.hoursCopyFirst': 'Usar el horario del {day} para todos los días',
|
||||
'places.hoursRemove': 'Quitar horario',
|
||||
'places.formNotes': 'Notas',
|
||||
'places.formNotesPlaceholder': 'Notas personales...',
|
||||
'places.assignmentNotes': 'Notas para este día',
|
||||
|
||||
@@ -95,6 +95,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Lõpuaeg on algusajast varasem',
|
||||
'places.timeCollision': 'Ajaline kattuvus:',
|
||||
'places.formWebsite': 'Veebisait',
|
||||
'places.formPhone': 'Telefon',
|
||||
'places.formEmail': 'E-post',
|
||||
'places.hoursAdd': 'Lisa lahtiolekuajad',
|
||||
'places.hoursClosed': 'Suletud',
|
||||
'places.hoursOpens': 'avatakse',
|
||||
'places.hoursCloses': 'suletakse',
|
||||
'places.hoursCopyFirst': 'Kasuta päeva {day} aegu kõigil päevadel',
|
||||
'places.hoursRemove': 'Eemalda lahtiolekuajad',
|
||||
'places.formNotes': 'Märkmed',
|
||||
'places.formNotesPlaceholder': 'Isiklikud märkmed...',
|
||||
'places.assignmentNotes': 'Selle päeva märkmed',
|
||||
|
||||
@@ -95,6 +95,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': "L'heure de fin est antérieure à l'heure de début",
|
||||
'places.timeCollision': 'Chevauchement horaire avec :',
|
||||
'places.formWebsite': 'Site web',
|
||||
'places.formPhone': 'Téléphone',
|
||||
'places.formEmail': 'E-mail',
|
||||
'places.hoursAdd': 'Ajouter les horaires',
|
||||
'places.hoursClosed': 'Fermé',
|
||||
'places.hoursOpens': 'ouvre',
|
||||
'places.hoursCloses': 'ferme',
|
||||
'places.hoursCopyFirst': 'Appliquer les horaires du {day} à tous les jours',
|
||||
'places.hoursRemove': 'Supprimer les horaires',
|
||||
'places.formNotes': 'Notes',
|
||||
'places.formNotesPlaceholder': 'Notes personnelles…',
|
||||
'places.assignmentNotes': 'Notes pour ce jour',
|
||||
|
||||
@@ -95,6 +95,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Η ώρα λήξης είναι πριν την ώρα έναρξης',
|
||||
'places.timeCollision': 'Επικάλυψη ώρας με:',
|
||||
'places.formWebsite': 'Ιστοσελίδα',
|
||||
'places.formPhone': 'Τηλέφωνο',
|
||||
'places.formEmail': 'Email',
|
||||
'places.hoursAdd': 'Προσθήκη ωραρίου',
|
||||
'places.hoursClosed': 'Κλειστό',
|
||||
'places.hoursOpens': 'ανοίγει',
|
||||
'places.hoursCloses': 'κλείνει',
|
||||
'places.hoursCopyFirst': 'Χρήση του ωραρίου της ημέρας {day} για όλες τις ημέρες',
|
||||
'places.hoursRemove': 'Αφαίρεση ωραρίου',
|
||||
'places.formNotes': 'Σημειώσεις',
|
||||
'places.formNotesPlaceholder': 'Προσωπικές σημειώσεις...',
|
||||
'places.assignmentNotes': 'Σημειώσεις για αυτή την ημέρα',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'A befejezési idő a kezdési idő előtt van',
|
||||
'places.timeCollision': 'Időbeli átfedés:',
|
||||
'places.formWebsite': 'Weboldal',
|
||||
'places.formPhone': 'Telefon',
|
||||
'places.formEmail': 'E-mail',
|
||||
'places.hoursAdd': 'Nyitvatartás hozzáadása',
|
||||
'places.hoursClosed': 'Zárva',
|
||||
'places.hoursOpens': 'nyit',
|
||||
'places.hoursCloses': 'zár',
|
||||
'places.hoursCopyFirst': 'A(z) {day} nyitvatartása minden napra',
|
||||
'places.hoursRemove': 'Nyitvatartás törlése',
|
||||
'places.formNotes': 'Jegyzetek',
|
||||
'places.formNotesPlaceholder': 'Személyes jegyzetek...',
|
||||
'places.assignmentNotes': 'Jegyzetek erre a napra',
|
||||
|
||||
@@ -93,6 +93,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Waktu selesai lebih awal dari waktu mulai',
|
||||
'places.timeCollision': 'Waktu tumpang tindih dengan:',
|
||||
'places.formWebsite': 'Situs web',
|
||||
'places.formPhone': 'Telepon',
|
||||
'places.formEmail': 'Email',
|
||||
'places.hoursAdd': 'Tambah jam buka',
|
||||
'places.hoursClosed': 'Tutup',
|
||||
'places.hoursOpens': 'buka',
|
||||
'places.hoursCloses': 'tutup',
|
||||
'places.hoursCopyFirst': 'Pakai jam {day} untuk semua hari',
|
||||
'places.hoursRemove': 'Hapus jam buka',
|
||||
'places.formNotes': 'Catatan',
|
||||
'places.formNotesPlaceholder': 'Catatan pribadi...',
|
||||
'places.assignmentNotes': 'Catatan untuk hari ini',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': "L'ora di fine è precedente all'ora di inizio",
|
||||
'places.timeCollision': 'Sovrapposizione di orario con:',
|
||||
'places.formWebsite': 'Sito web',
|
||||
'places.formPhone': 'Telefono',
|
||||
'places.formEmail': 'E-mail',
|
||||
'places.hoursAdd': 'Aggiungi orari di apertura',
|
||||
'places.hoursClosed': 'Chiuso',
|
||||
'places.hoursOpens': 'apre',
|
||||
'places.hoursCloses': 'chiude',
|
||||
'places.hoursCopyFirst': 'Usa gli orari di {day} per tutti i giorni',
|
||||
'places.hoursRemove': 'Rimuovi orari di apertura',
|
||||
'places.formNotes': 'Note',
|
||||
'places.formNotesPlaceholder': 'Note personali...',
|
||||
'places.assignmentNotes': 'Note per questo giorno',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': '終了時間が開始時間より前です',
|
||||
'places.timeCollision': '時間が重複しています:',
|
||||
'places.formWebsite': 'ウェブサイト',
|
||||
'places.formPhone': '電話',
|
||||
'places.formEmail': 'メール',
|
||||
'places.hoursAdd': '営業時間を追加',
|
||||
'places.hoursClosed': '定休日',
|
||||
'places.hoursOpens': '開店',
|
||||
'places.hoursCloses': '閉店',
|
||||
'places.hoursCopyFirst': '{day}の時間を全曜日に適用',
|
||||
'places.hoursRemove': '営業時間を削除',
|
||||
'places.formNotes': 'メモ',
|
||||
'places.formNotesPlaceholder': '個人的なメモ…',
|
||||
'places.assignmentNotes': 'この日のメモ',
|
||||
|
||||
@@ -93,6 +93,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': '종료 시간이 시작 시간보다 앞입니다',
|
||||
'places.timeCollision': '시간 겹침:',
|
||||
'places.formWebsite': '웹사이트',
|
||||
'places.formPhone': '전화',
|
||||
'places.formEmail': '이메일',
|
||||
'places.hoursAdd': '영업시간 추가',
|
||||
'places.hoursClosed': '휴무',
|
||||
'places.hoursOpens': '오픈',
|
||||
'places.hoursCloses': '마감',
|
||||
'places.hoursCopyFirst': '{day} 시간을 모든 요일에 적용',
|
||||
'places.hoursRemove': '영업시간 삭제',
|
||||
'places.formNotes': '메모',
|
||||
'places.formNotesPlaceholder': '개인 메모...',
|
||||
'places.assignmentNotes': '이 날의 메모',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Eindtijd is vóór de starttijd',
|
||||
'places.timeCollision': 'Tijdoverlap met:',
|
||||
'places.formWebsite': 'Website',
|
||||
'places.formPhone': 'Telefoon',
|
||||
'places.formEmail': 'E-mail',
|
||||
'places.hoursAdd': 'Openingstijden toevoegen',
|
||||
'places.hoursClosed': 'Gesloten',
|
||||
'places.hoursOpens': 'opent',
|
||||
'places.hoursCloses': 'sluit',
|
||||
'places.hoursCopyFirst': 'Tijden van {day} voor alle dagen gebruiken',
|
||||
'places.hoursRemove': 'Openingstijden verwijderen',
|
||||
'places.formNotes': 'Notities',
|
||||
'places.formNotesPlaceholder': 'Persoonlijke notities...',
|
||||
'places.assignmentNotes': 'Notities voor deze dag',
|
||||
|
||||
@@ -84,6 +84,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Godzina zakończenia jest przed godziną rozpoczęcia',
|
||||
'places.timeCollision': 'Nakładanie się godzin z:',
|
||||
'places.formWebsite': 'Strona internetowa',
|
||||
'places.formPhone': 'Telefon',
|
||||
'places.formEmail': 'E-mail',
|
||||
'places.hoursAdd': 'Dodaj godziny otwarcia',
|
||||
'places.hoursClosed': 'Zamknięte',
|
||||
'places.hoursOpens': 'otwarcie',
|
||||
'places.hoursCloses': 'zamknięcie',
|
||||
'places.hoursCopyFirst': 'Użyj godzin z dnia {day} dla wszystkich dni',
|
||||
'places.hoursRemove': 'Usuń godziny otwarcia',
|
||||
'places.formNotes': 'Notatki',
|
||||
'places.formNotesPlaceholder': 'Osobiste notatki...',
|
||||
'places.assignmentNotes': 'Notatki na ten dzień',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Время окончания раньше времени начала',
|
||||
'places.timeCollision': 'Пересечение по времени с:',
|
||||
'places.formWebsite': 'Сайт',
|
||||
'places.formPhone': 'Телефон',
|
||||
'places.formEmail': 'Эл. почта',
|
||||
'places.hoursAdd': 'Добавить часы работы',
|
||||
'places.hoursClosed': 'Закрыто',
|
||||
'places.hoursOpens': 'открывается',
|
||||
'places.hoursCloses': 'закрывается',
|
||||
'places.hoursCopyFirst': 'Применить часы дня «{day}» ко всем дням',
|
||||
'places.hoursRemove': 'Удалить часы работы',
|
||||
'places.formNotes': 'Заметки',
|
||||
'places.formNotesPlaceholder': 'Личные заметки...',
|
||||
'places.assignmentNotes': 'Заметки на этот день',
|
||||
|
||||
@@ -95,6 +95,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Čas konca je pred časom začiatku',
|
||||
'places.timeCollision': 'Časový prekryv s:',
|
||||
'places.formWebsite': 'Webová stránka',
|
||||
'places.formPhone': 'Telefón',
|
||||
'places.formEmail': 'E-mail',
|
||||
'places.hoursAdd': 'Pridať otváracie hodiny',
|
||||
'places.hoursClosed': 'Zatvorené',
|
||||
'places.hoursOpens': 'otvára',
|
||||
'places.hoursCloses': 'zatvára',
|
||||
'places.hoursCopyFirst': 'Použiť časy z {day} pre všetky dni',
|
||||
'places.hoursRemove': 'Odstrániť otváracie hodiny',
|
||||
'places.formNotes': 'Poznámky',
|
||||
'places.formNotesPlaceholder': 'Osobné poznámky...',
|
||||
'places.assignmentNotes': 'Poznámky pre tento deň',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Sluttiden infaller före starttiden',
|
||||
'places.timeCollision': 'Tidsöverlappning med:',
|
||||
'places.formWebsite': 'Hemsida',
|
||||
'places.formPhone': 'Telefon',
|
||||
'places.formEmail': 'E-post',
|
||||
'places.hoursAdd': 'Lägg till öppettider',
|
||||
'places.hoursClosed': 'Stängt',
|
||||
'places.hoursOpens': 'öppnar',
|
||||
'places.hoursCloses': 'stänger',
|
||||
'places.hoursCopyFirst': 'Använd tiderna för {day} alla dagar',
|
||||
'places.hoursRemove': 'Ta bort öppettider',
|
||||
'places.formNotes': 'Noteringar',
|
||||
'places.formNotesPlaceholder': 'Personliga anteckningar...',
|
||||
'places.assignmentNotes': 'Anteckningar för denna dag',
|
||||
|
||||
@@ -88,6 +88,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'เวลาสิ้นสุดอยู่ก่อนเวลาเริ่มต้น',
|
||||
'places.timeCollision': 'เวลาที่ทับซ้อนกันกับ:',
|
||||
'places.formWebsite': 'เว็บไซต์',
|
||||
'places.formPhone': 'โทรศัพท์',
|
||||
'places.formEmail': 'อีเมล',
|
||||
'places.hoursAdd': 'เพิ่มเวลาทำการ',
|
||||
'places.hoursClosed': 'ปิด',
|
||||
'places.hoursOpens': 'เปิด',
|
||||
'places.hoursCloses': 'ปิด',
|
||||
'places.hoursCopyFirst': 'ใช้เวลาของวัน{day}กับทุกวัน',
|
||||
'places.hoursRemove': 'ลบเวลาทำการ',
|
||||
'places.formNotes': 'หมายเหตุ',
|
||||
'places.formNotesPlaceholder': 'บันทึกส่วนตัว...',
|
||||
'places.assignmentNotes': 'หมายเหตุสำหรับวันนี้',
|
||||
|
||||
@@ -96,6 +96,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Bitiş zamanı başlangıç zamanından önce',
|
||||
'places.timeCollision': 'Zaman şununla çakışıyor:',
|
||||
'places.formWebsite': 'Web sitesi',
|
||||
'places.formPhone': 'Telefon',
|
||||
'places.formEmail': 'E-posta',
|
||||
'places.hoursAdd': 'Çalışma saatleri ekle',
|
||||
'places.hoursClosed': 'Kapalı',
|
||||
'places.hoursOpens': 'açılış',
|
||||
'places.hoursCloses': 'kapanış',
|
||||
'places.hoursCopyFirst': '{day} saatlerini tüm günlere uygula',
|
||||
'places.hoursRemove': 'Çalışma saatlerini kaldır',
|
||||
'places.formNotes': 'Notlar',
|
||||
'places.formNotesPlaceholder': 'Kişisel notlar...',
|
||||
'places.assignmentNotes': 'Bu gün için notlar',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Час закінчення раніше за час початку',
|
||||
'places.timeCollision': 'Перетин за часом із:',
|
||||
'places.formWebsite': 'Веб-сайт',
|
||||
'places.formPhone': 'Телефон',
|
||||
'places.formEmail': 'Ел. пошта',
|
||||
'places.hoursAdd': 'Додати години роботи',
|
||||
'places.hoursClosed': 'Зачинено',
|
||||
'places.hoursOpens': 'відкривається',
|
||||
'places.hoursCloses': 'зачиняється',
|
||||
'places.hoursCopyFirst': 'Застосувати години дня «{day}» до всіх днів',
|
||||
'places.hoursRemove': 'Видалити години роботи',
|
||||
'places.formNotes': 'Нотатки',
|
||||
'places.formNotesPlaceholder': 'Особисті нотатки...',
|
||||
'places.assignmentNotes': 'Нотатки на цей день',
|
||||
|
||||
@@ -94,6 +94,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': 'Thời gian kết thúc trước thời gian bắt đầu',
|
||||
'places.timeCollision': 'Thời gian trùng lặp với:',
|
||||
'places.formWebsite': 'Trang web',
|
||||
'places.formPhone': 'Điện thoại',
|
||||
'places.formEmail': 'Email',
|
||||
'places.hoursAdd': 'Thêm giờ mở cửa',
|
||||
'places.hoursClosed': 'Đóng cửa',
|
||||
'places.hoursOpens': 'mở cửa',
|
||||
'places.hoursCloses': 'đóng cửa',
|
||||
'places.hoursCopyFirst': 'Dùng giờ của {day} cho mọi ngày',
|
||||
'places.hoursRemove': 'Xóa giờ mở cửa',
|
||||
'places.formNotes': 'Ghi chú',
|
||||
'places.formNotesPlaceholder': 'Ghi chú cá nhân...',
|
||||
'places.assignmentNotes': 'Ghi chú cho ngày này',
|
||||
|
||||
@@ -93,6 +93,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': '結束時間早於開始時間',
|
||||
'places.timeCollision': '時間衝突:',
|
||||
'places.formWebsite': '網站',
|
||||
'places.formPhone': '電話',
|
||||
'places.formEmail': '電子郵件',
|
||||
'places.hoursAdd': '新增營業時間',
|
||||
'places.hoursClosed': '公休',
|
||||
'places.hoursOpens': '開門',
|
||||
'places.hoursCloses': '關門',
|
||||
'places.hoursCopyFirst': '將{day}的時間套用到每一天',
|
||||
'places.hoursRemove': '移除營業時間',
|
||||
'places.formNotes': '備註',
|
||||
'places.formNotesPlaceholder': '個人備註...',
|
||||
'places.assignmentNotes': '當天備註',
|
||||
|
||||
@@ -93,6 +93,14 @@ const places: TranslationStrings = {
|
||||
'places.endTimeBeforeStart': '结束时间早于开始时间',
|
||||
'places.timeCollision': '时间冲突:',
|
||||
'places.formWebsite': '网站',
|
||||
'places.formPhone': '电话',
|
||||
'places.formEmail': '电子邮件',
|
||||
'places.hoursAdd': '添加营业时间',
|
||||
'places.hoursClosed': '休息',
|
||||
'places.hoursOpens': '开门',
|
||||
'places.hoursCloses': '关门',
|
||||
'places.hoursCopyFirst': '将{day}的时间用于每一天',
|
||||
'places.hoursRemove': '移除营业时间',
|
||||
'places.formNotes': '备注',
|
||||
'places.formNotesPlaceholder': '个人备注...',
|
||||
'places.assignmentNotes': '当天备注',
|
||||
|
||||
@@ -50,6 +50,7 @@ export * from './place/track-colors';
|
||||
export * from './collection/collection.schema';
|
||||
export * from './collection/collection-file.schema';
|
||||
export * from './trip/trip.schema';
|
||||
export * from './place/place-hours';
|
||||
export * from './trip/day-grid';
|
||||
export * from './trip-invite/trip-invite.schema';
|
||||
export * from './collab/collab.schema';
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { hasPlaceHours, parsePlaceHours, placeEmailField, placeOpeningHoursField } from './place-hours';
|
||||
import { placeCreateRequestSchema, placeUpdateRequestSchema } from './place.schema';
|
||||
|
||||
const WEEK = '[{"closed":false,"open":"09:00","close":"17:00"},{"closed":false},{"closed":false},{"closed":false},{"closed":false},{"closed":true},{"closed":true}]';
|
||||
|
||||
describe('place hours and e-mail (#2472)', () => {
|
||||
it('parses seven days and refuses anything else', () => {
|
||||
expect(parsePlaceHours(WEEK)).toHaveLength(7);
|
||||
expect(parsePlaceHours('[]')).toBeNull();
|
||||
expect(parsePlaceHours('{nope')).toBeNull();
|
||||
expect(parsePlaceHours('[{"closed":false,"open":"25:00"},{},{},{},{},{},{}]')).toBeNull();
|
||||
expect(parsePlaceHours('')).toBeNull();
|
||||
expect(parsePlaceHours(null)).toBeNull();
|
||||
});
|
||||
|
||||
it('tells a week that says something from an empty one', () => {
|
||||
expect(hasPlaceHours(parsePlaceHours(WEEK))).toBe(true);
|
||||
expect(hasPlaceHours(Array.from({ length: 7 }, () => ({ closed: false })))).toBe(false);
|
||||
expect(hasPlaceHours(null)).toBe(false);
|
||||
});
|
||||
|
||||
it('validates both fields on the request bodies, empty meaning clear', () => {
|
||||
expect(placeOpeningHoursField.safeParse(WEEK).success).toBe(true);
|
||||
expect(placeOpeningHoursField.safeParse('').success).toBe(true);
|
||||
expect(placeOpeningHoursField.safeParse('[1,2]').success).toBe(false);
|
||||
expect(placeEmailField.safeParse('a@b.co').success).toBe(true);
|
||||
expect(placeEmailField.safeParse('').success).toBe(true);
|
||||
expect(placeEmailField.safeParse('nope').success).toBe(false);
|
||||
expect(placeCreateRequestSchema.safeParse({ name: 'X', email: 'nope' }).success).toBe(false);
|
||||
expect(placeUpdateRequestSchema.safeParse({ opening_hours: WEEK, email: null }).success).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* A place's own opening hours and e-mail, typed in by hand (#2472). The search
|
||||
* fills phone and website when it knows them; when it does not, or for a place
|
||||
* nobody has listed, these are how the traveller adds what they found out.
|
||||
*
|
||||
* Hours are stored as JSON text on the place: seven days, Monday first, the
|
||||
* same order Google's weekday lines come in, so the inspector shows either the
|
||||
* same way.
|
||||
*/
|
||||
export const PLACE_HOURS_DAYS = 7;
|
||||
|
||||
const TIME = /^([01]\d|2[0-3]):[0-5]\d$/;
|
||||
|
||||
export const placeHoursDaySchema = z.object({
|
||||
closed: z.boolean(),
|
||||
open: z.string().regex(TIME).optional(),
|
||||
close: z.string().regex(TIME).optional(),
|
||||
});
|
||||
export type PlaceHoursDay = z.infer<typeof placeHoursDaySchema>;
|
||||
|
||||
export const placeOpeningHoursSchema = z.array(placeHoursDaySchema).length(PLACE_HOURS_DAYS);
|
||||
export type PlaceOpeningHours = z.infer<typeof placeOpeningHoursSchema>;
|
||||
|
||||
/** The stored text as seven days, or null when it is empty or not hours at all. */
|
||||
export function parsePlaceHours(raw: unknown): PlaceOpeningHours | null {
|
||||
if (typeof raw !== 'string' || raw.trim() === '') return null;
|
||||
try {
|
||||
const parsed = placeOpeningHoursSchema.safeParse(JSON.parse(raw));
|
||||
return parsed.success ? parsed.data : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Whether a week says anything: a day that is closed or has a time. */
|
||||
export function hasPlaceHours(hours: PlaceOpeningHours | null): boolean {
|
||||
return !!hours && hours.some(d => d.closed || !!d.open || !!d.close);
|
||||
}
|
||||
|
||||
/** The request field: the JSON text, empty or null to clear it. */
|
||||
export const placeOpeningHoursField = z
|
||||
.string()
|
||||
.max(1000)
|
||||
.refine(v => v === '' || parsePlaceHours(v) !== null, { message: 'opening_hours must be seven days, Monday first' })
|
||||
.nullable()
|
||||
.optional();
|
||||
|
||||
const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
|
||||
/** An e-mail address, or empty to clear it. */
|
||||
export const placeEmailField = z
|
||||
.string()
|
||||
.max(254)
|
||||
.refine(v => v === '' || EMAIL.test(v.trim()), { message: 'email must be an e-mail address' })
|
||||
.nullable()
|
||||
.optional();
|
||||
@@ -1,5 +1,6 @@
|
||||
import { tagSchema } from '../tag/tag.schema';
|
||||
import { PLACE_WEBSITE_MAX_LENGTH, normalizePlaceWebsite } from './place-website';
|
||||
import { placeEmailField, placeOpeningHoursField } from './place-hours';
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -178,6 +179,10 @@ export const placeSchema = z.object({
|
||||
fill_percent: fillPercentSchema,
|
||||
website: z.string().nullable().optional(),
|
||||
phone: z.string().nullable().optional(),
|
||||
/** Typed in by hand (#2472). */
|
||||
email: z.string().nullable().optional(),
|
||||
/** Hand-kept hours as JSON text, seven days Monday first (#2472); see place-hours.ts. */
|
||||
opening_hours: z.string().nullable().optional(),
|
||||
transport_mode: z.string().nullable().optional(),
|
||||
created_at: z.string().optional(),
|
||||
updated_at: z.string().optional(),
|
||||
@@ -251,6 +256,10 @@ export type AssignmentPlace = z.infer<typeof assignmentPlaceSchema>;
|
||||
* service already reads it that way rather than as "leave alone".
|
||||
*/
|
||||
const stopTypeField = z.object({
|
||||
// Named on the open body like the two below: an e-mail and the hand-kept hours have a
|
||||
// fixed shape, and a malformed one would otherwise sit on the place unseen (#2472).
|
||||
email: placeEmailField,
|
||||
opening_hours: placeOpeningHoursField,
|
||||
stop_type: roadtripStopTypeSchema.nullable().optional(),
|
||||
// Named for the same reason: a bounded vocabulary on an otherwise open body. Zero is
|
||||
// outside it on purpose — a stop that fills nothing is not a stop, and letting one
|
||||
|
||||
Reference in New Issue
Block a user