add open charging data and polish roadtrip warnings

This commit is contained in:
Maurice
2026-09-12 13:25:15 +02:00
parent ff5fa55fad
commit f56e7a161e
52 changed files with 820 additions and 32 deletions
+6
View File
@@ -1,6 +1,12 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'متاح',
'roadtrip.charging.unknown': 'لا تتوفر بيانات موثوقة',
'roadtrip.charging.stale': 'الحالة قديمة',
'roadtrip.charging.prices': 'التعريفات المنشورة',
'roadtrip.charging.note': 'تعريفة منشورة؛ قد تُطبق ضرائب وشروط ورسوم إضافية. قد يختلف سعر بطاقة الشحن.',
'roadtrip.charging.coverage': 'بيانات مفتوحة؛ تختلف التغطية حسب المنطقة والمشغل.',
'roadtrip.import.title': 'استيراد مسار Google Maps',
'roadtrip.import.note': 'تُضاف المحطات إلى اليوم المحدد. يعيد TREK حساب المسار.',
'roadtrip.import.unresolved': 'تعذر تحديد الموقع؛ سيتم تخطي هذه المحطة.',
+6
View File
@@ -1,6 +1,12 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': "disponíveis",
'roadtrip.charging.unknown': "Sem dados confiáveis",
'roadtrip.charging.stale': "Status desatualizado",
'roadtrip.charging.prices': "Tarifas publicadas",
'roadtrip.charging.note': "Tarifa publicada; impostos, condições e taxas extras podem se aplicar. O preço do seu cartão pode variar.",
'roadtrip.charging.coverage': "Dados abertos; cobertura varia por região e operador.",
'roadtrip.import.title': 'Importar rota do Google Maps',
'roadtrip.import.note': 'As paradas são adicionadas ao dia escolhido. O TREK recalcula a rota.',
'roadtrip.import.unresolved': 'Local não encontrado; esta parada será ignorada.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'disponibles',
'roadtrip.charging.unknown': 'No hi ha dades fiables',
'roadtrip.charging.stale': 'Estat desactualitzat',
'roadtrip.charging.prices': 'Tarifes publicades',
'roadtrip.charging.note':
'Tarifa publicada; pot haver-hi impostos, condicions i càrrecs addicionals. El preu de la targeta pot variar.',
'roadtrip.charging.coverage': 'Dades obertes; cobertura segons regió i operador.',
'roadtrip.import.title': 'Importa una ruta de Google Maps',
'roadtrip.import.note': 'Les parades s’afegeixen al dia triat. TREK recalcula la ruta.',
'roadtrip.import.unresolved': 'Ubicació no trobada; aquesta parada s’ometrà.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'volné',
'roadtrip.charging.unknown': 'Spolehlivá data nejsou dostupná',
'roadtrip.charging.stale': 'Zastaralý stav',
'roadtrip.charging.prices': 'Zveřejněné tarify',
'roadtrip.charging.note':
'Zveřejněný tarif; mohou platit daně, podmínky a další poplatky. Cena vaší karty se může lišit.',
'roadtrip.charging.coverage': 'Otevřená data; pokrytí závisí na regionu a provozovateli.',
'roadtrip.import.title': 'Importovat trasu z Google Maps',
'roadtrip.import.note': 'Zastávky se přidají ke zvolenému dni. TREK trasu přepočítá.',
'roadtrip.import.unresolved': 'Místo nenalezeno; tato zastávka bude přeskočena.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'frei',
'roadtrip.charging.unknown': 'Keine verlässlichen Daten verfügbar',
'roadtrip.charging.stale': 'Status veraltet',
'roadtrip.charging.prices': 'Veröffentlichte Tarife',
'roadtrip.charging.note':
'Veröffentlichter Tarif; Steuern, Bedingungen und Zusatzgebühren beachten. Dein Ladekartenpreis kann abweichen.',
'roadtrip.charging.coverage': 'Offene Daten; Abdeckung abhängig von Region und Betreiber.',
'roadtrip.import.title': 'Google-Maps-Route importieren',
'roadtrip.import.note': 'Stopps werden an den gewählten Tag angehängt. TREK berechnet die Route neu.',
'roadtrip.import.unresolved': 'Ort nicht gefunden; dieser Stopp wird übersprungen.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'available',
'roadtrip.charging.unknown': 'No reliable data available',
'roadtrip.charging.stale': 'Status outdated',
'roadtrip.charging.prices': 'Published tariffs',
'roadtrip.charging.note':
'Published tariff; taxes, conditions and extra fees may apply. Your charging-card price can differ.',
'roadtrip.charging.coverage': 'Open data; coverage varies by region and operator.',
'roadtrip.import.title': 'Import Google Maps route',
'roadtrip.import.note': 'Stops are appended to the selected day. TREK recalculates the route.',
'roadtrip.import.unresolved': 'Location unresolved; this stop will be skipped.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'disponibles',
'roadtrip.charging.unknown': 'No hay datos fiables',
'roadtrip.charging.stale': 'Estado desactualizado',
'roadtrip.charging.prices': 'Tarifas publicadas',
'roadtrip.charging.note':
'Tarifa publicada; pueden aplicarse impuestos, condiciones y cargos adicionales. El precio de tu tarjeta puede variar.',
'roadtrip.charging.coverage': 'Datos abiertos; cobertura según región y operador.',
'roadtrip.import.title': 'Importar ruta de Google Maps',
'roadtrip.import.note': 'Las paradas se añaden al día elegido. TREK recalcula la ruta.',
'roadtrip.import.unresolved': 'Ubicación no encontrada; se omitirá esta parada.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'disponibles',
'roadtrip.charging.unknown': 'Aucune donnée fiable disponible',
'roadtrip.charging.stale': 'État périmé',
'roadtrip.charging.prices': 'Tarifs publiés',
'roadtrip.charging.note':
'Tarif publié ; taxes, conditions et frais supplémentaires possibles. Le prix de votre carte peut différer.',
'roadtrip.charging.coverage': 'Données ouvertes ; couverture variable selon la région et l’opérateur.',
'roadtrip.import.title': 'Importer un itinéraire Google Maps',
'roadtrip.import.note': 'Les étapes sont ajoutées au jour choisi. TREK recalcule le trajet.',
'roadtrip.import.unresolved': 'Lieu introuvable ; cette étape sera ignorée.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'διαθέσιμα',
'roadtrip.charging.unknown': 'Δεν υπάρχουν αξιόπιστα δεδομένα',
'roadtrip.charging.stale': 'Παρωχημένη κατάσταση',
'roadtrip.charging.prices': 'Δημοσιευμένες χρεώσεις',
'roadtrip.charging.note':
'Δημοσιευμένη χρέωση· ενδέχεται να ισχύουν φόροι, όροι και πρόσθετα τέλη. Η τιμή της κάρτας σας μπορεί να διαφέρει.',
'roadtrip.charging.coverage': 'Ανοικτά δεδομένα· η κάλυψη εξαρτάται από την περιοχή και τον πάροχο.',
'roadtrip.import.title': 'Εισαγωγή διαδρομής Google Maps',
'roadtrip.import.note': 'Οι στάσεις προστίθενται στην επιλεγμένη ημέρα. Το TREK υπολογίζει ξανά τη διαδρομή.',
'roadtrip.import.unresolved': 'Η τοποθεσία δεν βρέθηκε· αυτή η στάση θα παραλειφθεί.',
+6
View File
@@ -1,6 +1,12 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'szabad',
'roadtrip.charging.unknown': 'Nincs megbízható adat',
'roadtrip.charging.stale': 'Elavult állapot',
'roadtrip.charging.prices': 'Közzétett díjak',
'roadtrip.charging.note': 'Közzétett díj; adók, feltételek és felárak lehetnek. A töltőkártya ára eltérhet.',
'roadtrip.charging.coverage': 'Nyílt adatok; a lefedettség régiónként és szolgáltatónként változik.',
'roadtrip.import.title': 'Google Maps-útvonal importálása',
'roadtrip.import.note': 'A megállók a kiválasztott naphoz kerülnek. A TREK újratervezi az útvonalat.',
'roadtrip.import.unresolved': 'A hely nem található; ez a megálló kimarad.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'tersedia',
'roadtrip.charging.unknown': 'Tidak ada data terpercaya',
'roadtrip.charging.stale': 'Status kedaluwarsa',
'roadtrip.charging.prices': 'Tarif yang dipublikasikan',
'roadtrip.charging.note':
'Tarif publik; pajak, syarat, dan biaya tambahan mungkin berlaku. Harga kartu pengisian Anda bisa berbeda.',
'roadtrip.charging.coverage': 'Data terbuka; cakupan bergantung wilayah dan operator.',
'roadtrip.import.title': 'Impor rute Google Maps',
'roadtrip.import.note': 'Perhentian ditambahkan ke hari yang dipilih. TREK menghitung ulang rute.',
'roadtrip.import.unresolved': 'Lokasi tidak ditemukan; perhentian ini akan dilewati.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'disponibili',
'roadtrip.charging.unknown': 'Nessun dato affidabile',
'roadtrip.charging.stale': 'Stato non aggiornato',
'roadtrip.charging.prices': 'Tariffe pubblicate',
'roadtrip.charging.note':
'Tariffa pubblicata; verificare tasse, condizioni e supplementi. Il prezzo della tua tessera può variare.',
'roadtrip.charging.coverage': 'Dati aperti; copertura variabile per regione e gestore.',
'roadtrip.import.title': 'Importa percorso Google Maps',
'roadtrip.import.note': 'Le tappe vengono aggiunte al giorno scelto. TREK ricalcola il percorso.',
'roadtrip.import.unresolved': 'Posizione non trovata; questa tappa verrà saltata.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': '空き',
'roadtrip.charging.unknown': '信頼できるデータがありません',
'roadtrip.charging.stale': '古い状態情報',
'roadtrip.charging.prices': '公開料金',
'roadtrip.charging.note':
'公開料金です。税金、条件、追加料金をご確認ください。充電カードの料金は異なる場合があります。',
'roadtrip.charging.coverage': 'オープンデータ。地域や事業者によって対応範囲が異なります。',
'roadtrip.import.title': 'Google Mapsのルートをインポート',
'roadtrip.import.note': '立ち寄り先を選択した日に追加し、TREKでルートを再計算します。',
'roadtrip.import.unresolved': '場所が見つからないため、この立ち寄り先はスキップされます。',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': '이용 가능',
'roadtrip.charging.unknown': '신뢰할 수 있는 데이터 없음',
'roadtrip.charging.stale': '오래된 상태',
'roadtrip.charging.prices': '공개 요금',
'roadtrip.charging.note':
'공개 요금입니다. 세금, 조건, 추가 요금이 적용될 수 있으며 충전 카드 요금은 다를 수 있습니다.',
'roadtrip.charging.coverage': '공개 데이터로 지역과 운영사에 따라 범위가 다릅니다.',
'roadtrip.import.title': 'Google Maps 경로 가져오기',
'roadtrip.import.note': '경유지를 선택한 날짜에 추가합니다. TREK이 경로를 다시 계산합니다.',
'roadtrip.import.unresolved': '위치를 찾을 수 없어 이 경유지를 건너뜁니다.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'beschikbaar',
'roadtrip.charging.unknown': 'Geen betrouwbare gegevens',
'roadtrip.charging.stale': 'Status verouderd',
'roadtrip.charging.prices': 'Gepubliceerde tarieven',
'roadtrip.charging.note':
'Gepubliceerd tarief; belastingen, voorwaarden en toeslagen kunnen gelden. Je laadpasprijs kan afwijken.',
'roadtrip.charging.coverage': 'Open data; dekking verschilt per regio en aanbieder.',
'roadtrip.import.title': 'Google Maps-route importeren',
'roadtrip.import.note': 'Stops worden aan de gekozen dag toegevoegd. TREK berekent de route opnieuw.',
'roadtrip.import.unresolved': 'Locatie niet gevonden; deze stop wordt overgeslagen.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'wolne',
'roadtrip.charging.unknown': 'Brak wiarygodnych danych',
'roadtrip.charging.stale': 'Nieaktualny status',
'roadtrip.charging.prices': 'Opublikowane taryfy',
'roadtrip.charging.note':
'Opublikowana taryfa; możliwe podatki, warunki i dodatkowe opłaty. Cena Twojej karty może się różnić.',
'roadtrip.charging.coverage': 'Otwarte dane; zasięg zależy od regionu i operatora.',
'roadtrip.import.title': 'Importuj trasę z Google Maps',
'roadtrip.import.note': 'Przystanki zostaną dodane do wybranego dnia. TREK przeliczy trasę.',
'roadtrip.import.unresolved': 'Nie znaleziono miejsca; ten przystanek zostanie pominięty.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'свободно',
'roadtrip.charging.unknown': 'Нет надёжных данных',
'roadtrip.charging.stale': 'Статус устарел',
'roadtrip.charging.prices': 'Опубликованные тарифы',
'roadtrip.charging.note':
'Опубликованный тариф; возможны налоги, условия и доплаты. Цена по вашей карте может отличаться.',
'roadtrip.charging.coverage': 'Открытые данные; охват зависит от региона и оператора.',
'roadtrip.import.title': 'Импорт маршрута Google Maps',
'roadtrip.import.note': 'Остановки добавляются в выбранный день. TREK пересчитает маршрут.',
'roadtrip.import.unresolved': 'Место не найдено; эта остановка будет пропущена.',
+6
View File
@@ -1,6 +1,12 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'lediga',
'roadtrip.charging.unknown': 'Inga tillförlitliga uppgifter',
'roadtrip.charging.stale': 'Inaktuell status',
'roadtrip.charging.prices': 'Publicerade priser',
'roadtrip.charging.note': 'Publicerat pris; skatter, villkor och tillägg kan gälla. Ditt laddkorts pris kan avvika.',
'roadtrip.charging.coverage': 'Öppna data; täckning varierar efter region och operatör.',
'roadtrip.import.title': 'Importera Google Maps-rutt',
'roadtrip.import.note': 'Stoppen läggs till på vald dag. TREK beräknar rutten på nytt.',
'roadtrip.import.unresolved': 'Platsen hittades inte; stoppet hoppas över.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'boş',
'roadtrip.charging.unknown': 'Güvenilir veri yok',
'roadtrip.charging.stale': 'Durum güncel değil',
'roadtrip.charging.prices': 'Yayımlanan tarifeler',
'roadtrip.charging.note':
'Yayımlanan tarife; vergi, koşullar ve ek ücretler uygulanabilir. Şarj kartı fiyatınız farklı olabilir.',
'roadtrip.charging.coverage': 'Açık veri; kapsam bölge ve operatöre göre değişir.',
'roadtrip.import.title': 'Google Maps rotasını içe aktar',
'roadtrip.import.note': 'Duraklar seçilen güne eklenir. TREK rotayı yeniden hesaplar.',
'roadtrip.import.unresolved': 'Konum bulunamadı; bu durak atlanacak.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'вільні',
'roadtrip.charging.unknown': 'Немає надійних даних',
'roadtrip.charging.stale': 'Статус застарів',
'roadtrip.charging.prices': 'Опубліковані тарифи',
'roadtrip.charging.note':
'Опублікований тариф; можливі податки, умови та доплати. Ціна за вашою карткою може відрізнятися.',
'roadtrip.charging.coverage': 'Відкриті дані; охоплення залежить від регіону й оператора.',
'roadtrip.import.title': 'Імпорт маршруту Google Maps',
'roadtrip.import.note': 'Зупинки додаються до вибраного дня. TREK перерахує маршрут.',
'roadtrip.import.unresolved': 'Місце не знайдено; цю зупинку буде пропущено.',
+7
View File
@@ -1,6 +1,13 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': 'còn trống',
'roadtrip.charging.unknown': 'Không có dữ liệu đáng tin cậy',
'roadtrip.charging.stale': 'Trạng thái đã cũ',
'roadtrip.charging.prices': 'Biểu giá công bố',
'roadtrip.charging.note':
'Biểu giá công bố; có thể áp dụng thuế, điều kiện và phụ phí. Giá thẻ sạc của bạn có thể khác.',
'roadtrip.charging.coverage': 'Dữ liệu mở; phạm vi phụ thuộc khu vực và nhà vận hành.',
'roadtrip.import.title': 'Nhập tuyến đường Google Maps',
'roadtrip.import.note': 'Các điểm dừng được thêm vào ngày đã chọn. TREK tính lại tuyến đường.',
'roadtrip.import.unresolved': 'Không tìm thấy vị trí; điểm dừng này sẽ bị bỏ qua.',
+6
View File
@@ -1,6 +1,12 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': '可用',
'roadtrip.charging.unknown': '暫無可靠資料',
'roadtrip.charging.stale': '狀態已過時',
'roadtrip.charging.prices': '公布的費率',
'roadtrip.charging.note': '公布的費率可能附帶稅費、條件和額外費用。您的充電卡價格可能不同。',
'roadtrip.charging.coverage': '開放資料,涵蓋範圍因地區和營運商而異。',
'roadtrip.import.title': '匯入 Google Maps 路線',
'roadtrip.import.note': '停靠點將新增至所選日期。TREK 將重新計算路線。',
'roadtrip.import.unresolved': '找不到位置;將略過此停靠點。',
+6
View File
@@ -1,6 +1,12 @@
import type { TranslationStrings } from '../types';
const roadtrip: TranslationStrings = {
'roadtrip.charging.available': '可用',
'roadtrip.charging.unknown': '暂无可靠数据',
'roadtrip.charging.stale': '状态已过时',
'roadtrip.charging.prices': '公布的费率',
'roadtrip.charging.note': '公布的费率可能附带税费、条件和额外费用。您的充电卡价格可能不同。',
'roadtrip.charging.coverage': '开放数据,覆盖范围因地区和运营商而异。',
'roadtrip.import.title': '导入 Google Maps 路线',
'roadtrip.import.note': '停靠点将添加到所选日期。TREK 将重新计算路线。',
'roadtrip.import.unresolved': '未找到位置;将跳过此停靠点。',
+1
View File
@@ -81,3 +81,4 @@ export * from './roadtrip/hazards.schema';
export * from './roadtrip/planning.schema';
export * from './roadtrip/search.schema';
export * from './roadtrip/google-import.schema';
export * from './roadtrip/charging.schema';
+32
View File
@@ -0,0 +1,32 @@
import { z } from 'zod';
export const chargingInfoSchema = z.object({
checkedAt: z.string(),
status: z.enum(['ok', 'unknown', 'ambiguous', 'unavailable']),
station: z.string().nullable(),
source: z.string().nullable(),
sourceUrl: z.string().nullable(),
license: z.string().nullable(),
updatedAt: z.string().nullable(),
stale: z.boolean(),
available: z.number().int().nonnegative().nullable(),
total: z.number().int().nonnegative(),
unknown: z.number().int().nonnegative(),
tariffs: z.array(
z.object({
currency: z.string(),
updatedAt: z.string(),
components: z.array(
z.object({
kind: z.string(),
price: z.number().nonnegative(),
taxIncluded: z.boolean(),
conditional: z.boolean(),
afterSeconds: z.number().nullable(),
}),
),
}),
),
pricesUnavailable: z.boolean(),
});
export type ChargingInfo = z.infer<typeof chargingInfoSchema>;
+1
View File
@@ -16,6 +16,7 @@ export const roadtripHazardSchema = z.object({
validUntil: z.string().datetime().nullable(),
url: z.string().url(),
geometry: hazardGeometrySchema,
alertScore: z.number().finite().nonnegative().optional(),
});
export const roadtripHazardsSchema = z.object({
fetchedAt: z.string().datetime(),