diff --git a/client/src/components/Map/RouteCalculator.ts b/client/src/components/Map/RouteCalculator.ts index 482321232..3638696c5 100644 --- a/client/src/components/Map/RouteCalculator.ts +++ b/client/src/components/Map/RouteCalculator.ts @@ -649,6 +649,19 @@ export interface RouteAlternative { divergence: { lat: number; lng: number } | null /** Set when this way exists because a road class was left out of it. */ avoids?: AvoidClass + /** + * Which engine priced this route, when it was not the one that priced the rest. + * + * Absent for everything OSRM answered, which is every route in a list except the + * avoidance offer on a default install. It exists because the two engines do not + * agree on speed: measured over twelve European legs the per-leg drive times run + * from 14.7 % under OSRM's to 13.2 % over, and the sign depends on the region: + * Valhalla is faster on Spanish autovía and slower through a city. So a figure from + * one of them subtracted from a figure from the other is not a difference in + * driving time, it is the gap between two speed models, and the reader has no way + * of telling the two apart. + */ + engine?: 'valhalla' } /** @@ -684,10 +697,12 @@ const SAME_ROAD_KM = 0.5 * Two lines are the same road. * * Length and duration used to decide this, and stopped being enough when a second engine - * started answering. Valhalla prices roads differently — measured over ten European legs - * its distances ran 2.8 % above OSRM's and its times 5.4 % — so on a 470 km leg the same - * road comes back thirteen kilometres apart and a 200 m tolerance calls it a discovery. - * Two identical blue lines on the map is exactly what that looks like. + * started answering. Valhalla prices roads differently: measured over twelve European + * legs its distances ran 1.8 % above OSRM's, so on a 470 km leg the same road comes back + * thirteen kilometres apart and a 200 m tolerance calls it a discovery. Two identical + * blue lines on the map is exactly what that looks like. Duration is the worse of the + * two to lean on: over the same twelve legs it ranged from 14.7 % under OSRM's to 13.2 % + * over, with the sign set by the region rather than by the road. * * The geometry does not care which engine drew it, so it decides whenever there is one. * The numbers stay as the fallback for a line with no shape to compare. @@ -778,6 +793,7 @@ async function valhallaExcluding( distance: leg.distance, duration: leg.duration, divergence: null, + engine: 'valhalla', } } diff --git a/client/src/components/Map/valhallaRoute.ts b/client/src/components/Map/valhallaRoute.ts index 4bbdbde7c..fe736c0fd 100644 --- a/client/src/components/Map/valhallaRoute.ts +++ b/client/src/components/Map/valhallaRoute.ts @@ -22,10 +22,14 @@ import type { Waypoint, SnappedWaypoint, RouteAvoidClass } from '../../types' * - it refuses a point it cannot bind to a road, where OSRM still snaps one. The * Stephansdom, in a pedestrian zone, answers `No path could be found for input` * until a search radius is allowed; - * - it prices roads differently. Over ten European legs its drive times sat 5.4 % - * above OSRM's on average and 36 % above on one, and those times feed the arrival - * clocks of a road trip day. Mixing engines inside one chain would move times - * nobody asked to move. + * - it prices roads differently, and not by a constant anybody could correct for. + * Over twelve European legs the per-leg drive time ran from 14.7 % under OSRM's to + * 13.2 % over, and the sign follows the region rather than the road: on Spanish + * autovía Valhalla is the faster of the two on every leg measured, through a city + * it is half again slower. Those times feed the arrival clocks of a road trip day, + * so mixing engines inside one chain would move times nobody asked to move, and + * subtracting one engine's figure from the other's, which is what an offer beside + * a route invites, measures the gap between two speed models and nothing else. * * Which leaves exactly the shape this module serves: two points, one avoidance, asked * on demand, drawn as an offer next to the route rather than replacing it. diff --git a/client/src/components/Roadtrip/RoadtripAlternativesBar.test.tsx b/client/src/components/Roadtrip/RoadtripAlternativesBar.test.tsx index e1e299513..fa9034809 100644 --- a/client/src/components/Roadtrip/RoadtripAlternativesBar.test.tsx +++ b/client/src/components/Roadtrip/RoadtripAlternativesBar.test.tsx @@ -25,6 +25,7 @@ const overlay = (over: Partial = {}): AlternativeOverlay => duration: 10_800, distance: 290_000, slowerThanQuickest: 0, + otherEngine: false, labelBg: '#0a84ff', at: { lat: 53, lng: 11 }, ...over, @@ -142,4 +143,19 @@ describe('RoadtripAlternativesBar', () => { fireEvent.click(screen.getByRole('button', { name: /close/i })) expect(onClose).toHaveBeenCalled() }) + + it('FE-ALTBAR-010: an offer the other engine timed says so, and the rest do not', () => { + render( + , + ) + expect(screen.getAllByLabelText(/avoidance router/i)).toHaveLength(1) + }) }) diff --git a/client/src/components/Roadtrip/RoadtripAlternativesBar.tsx b/client/src/components/Roadtrip/RoadtripAlternativesBar.tsx index 53d213c15..7b9ce1473 100644 --- a/client/src/components/Roadtrip/RoadtripAlternativesBar.tsx +++ b/client/src/components/Roadtrip/RoadtripAlternativesBar.tsx @@ -1,6 +1,7 @@ import React from 'react' -import { Shuffle, X, AlertTriangle } from 'lucide-react' +import { Shuffle, X, AlertTriangle, Info } from 'lucide-react' import { useTranslation } from '../../i18n/TranslationContext' +import { Tooltip } from '../shared/Tooltip' import { useSettingsStore } from '../../store/settingsStore' import { formatDistance } from '../../utils/units' import { formatDurationShort } from './roadtripModel' @@ -92,6 +93,17 @@ export default function RoadtripAlternativesBar({ : t('roadtrip.alt.slower', { time: formatDurationShort(alt.slowerThanQuickest) })} + {/* Only where the drive time on the map came from the other engine. The + road and the length are the same question either way; the time is not, + and two engines' times sitting next to each other on the map invite a + subtraction that means nothing. Saying so here, where the choice is + actually made, is cheaper than a second request per offer to restate + the whole list in one engine's terms. */} + {alt.otherEngine ? ( + + + + ) : null} ))} diff --git a/client/src/components/Roadtrip/alternativeOverlays.test.ts b/client/src/components/Roadtrip/alternativeOverlays.test.ts index 9aa94da40..3a2a78a44 100644 --- a/client/src/components/Roadtrip/alternativeOverlays.test.ts +++ b/client/src/components/Roadtrip/alternativeOverlays.test.ts @@ -143,4 +143,81 @@ describe('buildAlternativeOverlays', () => { ) expect(out.filter(o => o.color === ALT_PRIMARY)).toHaveLength(1) }) + + it('FE-ALTOVL-011: a route the other engine priced cannot win the quickest election', () => { + // The shape a default install actually produces: OSRM answered with the one road + // it likes, and the toll-free offer beside it came from the avoidance router, + // whose speed model reads a Spanish motorway a seventh faster. Electing across + // the two paints the detour blue and calls the road being driven the slow way + // round, on nothing but that gap. + const out = buildAlternativeOverlays( + [ + alt({ duration: 11_880, coordinates: line(20, 0) }), + alt({ duration: 10_140, coordinates: line(20, 1), avoids: 'toll', engine: 'valhalla' }), + ], + LABELS, + ) + expect(out[0].color).toBe(ALT_PRIMARY) + expect(out[1].color).toBe(ALT_SECONDARY) + expect(out[0].note).toBe('Fastest') + expect(out[1].note).toBe('No tolls') + }) + + it('FE-ALTOVL-012: no difference is printed across two engines', () => { + const out = buildAlternativeOverlays( + [ + alt({ duration: 11_880, coordinates: line(20, 0) }), + alt({ duration: 10_140, coordinates: line(20, 1), avoids: 'toll', engine: 'valhalla' }), + ], + LABELS, + ) + expect(out[0].slowerThanQuickest).toBe(0) + expect(out[1].slowerThanQuickest).toBe(0) + expect(out[0].otherEngine).toBe(false) + expect(out[1].otherEngine).toBe(true) + // Each route still reports its own time; it is only the subtraction that is refused. + expect(out[0].duration).toBe(11_880) + expect(out[1].duration).toBe(10_140) + }) + + it('FE-ALTOVL-013: an instance whose own router answers still gets a real difference', () => { + // A self-hosted OSRM built through the MLD pipeline answers `exclude` itself, so + // the avoidance offer carries no engine of its own and the two figures are the + // same engine's. That comparison is sound and must keep working. + const out = buildAlternativeOverlays( + [ + alt({ duration: 3600, coordinates: line(20, 0) }), + alt({ duration: 5400, coordinates: line(20, 1), avoids: 'toll' }), + ], + LABELS, + ) + expect(out[1].slowerThanQuickest).toBe(1800) + expect(out.every(o => o.otherEngine === false)).toBe(true) + }) + + it('FE-ALTOVL-014: a list with nothing comparable in it still names one road primary', () => { + const out = buildAlternativeOverlays( + [ + alt({ duration: 3600, coordinates: line(20, 0), engine: 'valhalla' }), + alt({ duration: 5400, coordinates: line(20, 1), avoids: 'toll', engine: 'valhalla' }), + ], + LABELS, + ) + expect(out.filter(o => o.color === ALT_PRIMARY)).toHaveLength(1) + expect(out[0].color).toBe(ALT_PRIMARY) + expect(out.every(o => o.slowerThanQuickest === 0)).toBe(true) + }) + + it('FE-ALTOVL-015: the road being driven stays blue whatever the other engine says', () => { + const out = buildAlternativeOverlays( + [ + alt({ duration: 11_880, coordinates: line(20, 0), current: true }), + alt({ duration: 10_140, coordinates: line(20, 1), avoids: 'toll', engine: 'valhalla' }), + ], + LABELS, + ) + expect(out[0].color).toBe(ALT_PRIMARY) + expect(out[0].note).toBe('Current') + expect(out[1].color).toBe(ALT_SECONDARY) + }) }) diff --git a/client/src/components/Roadtrip/alternativeOverlays.ts b/client/src/components/Roadtrip/alternativeOverlays.ts index df97f689f..5171a99ab 100644 --- a/client/src/components/Roadtrip/alternativeOverlays.ts +++ b/client/src/components/Roadtrip/alternativeOverlays.ts @@ -16,6 +16,13 @@ export interface AlternativeOverlay { distance: number /** Seconds more than the quickest offer; negative never happens by construction. */ slowerThanQuickest: number + /** + * True when this route's figures came from the other engine, so they cannot be read + * against the rest of the list. Nothing derived from a comparison is filled in for + * such a route: it takes no part in electing the quickest and its + * `slowerThanQuickest` stays zero. + */ + otherEngine: boolean labelBg: string /** Where to hang the label — a point on this route and on no other. */ at: { lat: number; lng: number } @@ -91,7 +98,21 @@ export function buildAlternativeOverlays( // The quickest of what came back, which is what Apple calls out — not necessarily the // first entry, since the road currently driven is put at the top when there is one. - const quickest = routes.reduce((best, r, i) => (r.duration < routes[best].duration ? i : best), 0) + // + // Only among the routes one engine priced. The avoidance offer on a default install + // comes from the second engine, whose speed model differs by up to a seventh either + // way depending on the region, so letting it into this election decides which road is + // blue and how much slower every other road is called on nothing but that gap. On a + // Spanish motorway leg that is enough to crown a toll-free B-road detour and label + // the motorway somebody is actually driving as the slower way round. + // + // Index 0 is the fallback rather than -1: the first entry is the road being driven + // when there is one and the router's own pick otherwise, so if a list ever held + // nothing but second-engine routes, that is still the one to call primary. + const comparable = routes.map((r, i) => (r.engine ? -1 : i)).filter(i => i >= 0) + const quickest = comparable.length + ? comparable.reduce((best, i) => (routes[i].duration < routes[best].duration ? i : best), comparable[0]) + : 0 const anyCurrent = routes.some(r => r.current) return routes.map((route, index) => { @@ -100,6 +121,7 @@ export function buildAlternativeOverlays( // Blue is the road you are on: the one currently driven, or the router's own pick // when nothing has been bent. Everything else is the pale blue of an offer. const primary = route.current || (!anyCurrent && index === quickest) + const otherEngine = !!route.engine return { index, coordinates: route.coordinates, @@ -119,7 +141,14 @@ export function buildAlternativeOverlays( : index === quickest ? labels.fastest : '', duration: route.duration, distance: route.distance, - slowerThanQuickest: Math.max(0, Math.round(route.duration - routes[quickest].duration)), + // Left at zero for a route the other engine priced, and for every route when + // that is the only thing to measure against. The bar reads a zero as "no + // difference worth printing" and falls back to naming what the road is, which + // for these is always the class left out of it. + slowerThanQuickest: otherEngine || !!routes[quickest].engine + ? 0 + : Math.max(0, Math.round(route.duration - routes[quickest].duration)), + otherEngine, labelBg: primary ? ALT_LABEL_PRIMARY_BG : ALT_LABEL_SECONDARY_BG, at: at ?? { lat: 0, lng: 0 }, } diff --git a/shared/src/i18n/ar/roadtrip.ts b/shared/src/i18n/ar/roadtrip.ts index eb0214c0a..1f3cdf9e2 100644 --- a/shared/src/i18n/ar/roadtrip.ts +++ b/shared/src/i18n/ar/roadtrip.ts @@ -204,6 +204,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'الأسرع', 'roadtrip.alt.slower': 'أبطأ بـ {time}', 'roadtrip.alt.quicker': 'أسرع بـ {time}', + 'roadtrip.alt.otherEngine': 'الزمن محسوب بمحرك التجنب، لا بالمحرك الرئيسي.', 'roadtrip.day': 'اليوم {number}', 'roadtrip.quietDay.empty': 'لا توجد محطات بعد — أفلِت واحدة هنا', 'roadtrip.quietDay.one': 'حتى الآن {name} فقط — أفلِت محطة هنا', diff --git a/shared/src/i18n/br/roadtrip.ts b/shared/src/i18n/br/roadtrip.ts index 02089c4e5..dc2e04542 100644 --- a/shared/src/i18n/br/roadtrip.ts +++ b/shared/src/i18n/br/roadtrip.ts @@ -209,6 +209,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Mais rápida', 'roadtrip.alt.slower': '{time} mais lenta', 'roadtrip.alt.quicker': '{time} mais rápida', + 'roadtrip.alt.otherEngine': 'Tempo do roteador de desvios, não do principal.', 'roadtrip.day': 'Dia {number}', 'roadtrip.quietDay.empty': 'Ainda sem paradas — solte uma aqui', 'roadtrip.quietDay.one': 'Até agora só {name} — solte uma parada aqui', diff --git a/shared/src/i18n/ca/roadtrip.ts b/shared/src/i18n/ca/roadtrip.ts index 24be49233..d97841fba 100644 --- a/shared/src/i18n/ca/roadtrip.ts +++ b/shared/src/i18n/ca/roadtrip.ts @@ -211,6 +211,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'La més ràpida', 'roadtrip.alt.slower': '{time} més lenta', 'roadtrip.alt.quicker': '{time} més ràpida', + 'roadtrip.alt.otherEngine': 'Temps de l’encaminador d’evitació, no del principal.', 'roadtrip.day': 'Dia {number}', 'roadtrip.quietDay.empty': 'Encara sense parades: deixa’n una aquí', 'roadtrip.quietDay.one': 'De moment només {name}: deixa una parada aquí', diff --git a/shared/src/i18n/cs/roadtrip.ts b/shared/src/i18n/cs/roadtrip.ts index 3c115cdba..12f597426 100644 --- a/shared/src/i18n/cs/roadtrip.ts +++ b/shared/src/i18n/cs/roadtrip.ts @@ -207,6 +207,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Nejrychlejší', 'roadtrip.alt.slower': 'o {time} déle', 'roadtrip.alt.quicker': 'o {time} rychleji', + 'roadtrip.alt.otherEngine': 'Čas spočítal server pro objížďky, ne ten hlavní.', 'roadtrip.day': 'Den {number}', 'roadtrip.quietDay.empty': 'Zatím žádné zastávky — přetáhněte sem', 'roadtrip.quietDay.one': 'Zatím jen {name} — přetáhněte sem zastávku', diff --git a/shared/src/i18n/de/roadtrip.ts b/shared/src/i18n/de/roadtrip.ts index ff4e88a0c..d19f2fc89 100644 --- a/shared/src/i18n/de/roadtrip.ts +++ b/shared/src/i18n/de/roadtrip.ts @@ -206,6 +206,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Schnellste', 'roadtrip.alt.slower': '{time} länger', 'roadtrip.alt.quicker': '{time} kürzer', + 'roadtrip.alt.otherEngine': 'Zeit vom Ausweich-Router, nicht vom Haupt-Router.', 'roadtrip.day': 'Tag {number}', 'roadtrip.quietDay.empty': 'Noch keine Stopps — hier ablegen', 'roadtrip.quietDay.one': 'Bisher nur {name} — hier einen Stopp ablegen', diff --git a/shared/src/i18n/en/roadtrip.ts b/shared/src/i18n/en/roadtrip.ts index bfec101a3..607f13b0d 100644 --- a/shared/src/i18n/en/roadtrip.ts +++ b/shared/src/i18n/en/roadtrip.ts @@ -203,6 +203,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Fastest', 'roadtrip.alt.slower': '{time} slower', 'roadtrip.alt.quicker': '{time} quicker', + 'roadtrip.alt.otherEngine': 'Timed by the avoidance router, not the main one.', 'roadtrip.day': 'Day {number}', 'roadtrip.quietDay.empty': 'No stops yet — drop one here', 'roadtrip.quietDay.one': 'Only {name} so far — drop a stop here', diff --git a/shared/src/i18n/es/roadtrip.ts b/shared/src/i18n/es/roadtrip.ts index 4dc64dcb9..f9f7353a6 100644 --- a/shared/src/i18n/es/roadtrip.ts +++ b/shared/src/i18n/es/roadtrip.ts @@ -210,6 +210,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'La más rápida', 'roadtrip.alt.slower': '{time} más', 'roadtrip.alt.quicker': '{time} menos', + 'roadtrip.alt.otherEngine': 'Tiempo del enrutador de evitación, no del principal.', 'roadtrip.day': 'Día {number}', 'roadtrip.quietDay.empty': 'Sin paradas todavía: suelta una aquí', 'roadtrip.quietDay.one': 'Por ahora solo {name}: suelta una parada aquí', diff --git a/shared/src/i18n/fr/roadtrip.ts b/shared/src/i18n/fr/roadtrip.ts index 29353a7e0..1c9a81abf 100644 --- a/shared/src/i18n/fr/roadtrip.ts +++ b/shared/src/i18n/fr/roadtrip.ts @@ -210,6 +210,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'La plus rapide', 'roadtrip.alt.slower': '{time} de plus', 'roadtrip.alt.quicker': '{time} de moins', + 'roadtrip.alt.otherEngine': 'Temps du routeur de contournement, pas du principal.', 'roadtrip.day': 'Jour {number}', 'roadtrip.quietDay.empty': 'Aucun arrêt — déposez-en un ici', 'roadtrip.quietDay.one': 'Seulement {name} pour l’instant — déposez un arrêt ici', diff --git a/shared/src/i18n/gr/roadtrip.ts b/shared/src/i18n/gr/roadtrip.ts index 22c443bcb..1fc7dc20d 100644 --- a/shared/src/i18n/gr/roadtrip.ts +++ b/shared/src/i18n/gr/roadtrip.ts @@ -212,6 +212,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Η ταχύτερη', 'roadtrip.alt.slower': '{time} πιο αργή', 'roadtrip.alt.quicker': '{time} πιο γρήγορη', + 'roadtrip.alt.otherEngine': 'Χρόνος από τον δρομολογητή αποφυγής, όχι τον κύριο.', 'roadtrip.day': 'Ημέρα {number}', 'roadtrip.quietDay.empty': 'Καμία στάση ακόμη — αφήστε μία εδώ', 'roadtrip.quietDay.one': 'Μέχρι στιγμής μόνο {name} — αφήστε μια στάση εδώ', diff --git a/shared/src/i18n/hu/roadtrip.ts b/shared/src/i18n/hu/roadtrip.ts index af2f577eb..d38b07667 100644 --- a/shared/src/i18n/hu/roadtrip.ts +++ b/shared/src/i18n/hu/roadtrip.ts @@ -208,6 +208,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Leggyorsabb', 'roadtrip.alt.slower': '{time}-cel lassabb', 'roadtrip.alt.quicker': '{time}-cel gyorsabb', + 'roadtrip.alt.otherEngine': 'Az időt a kerülő útvonaltervező számolta, nem a fő.', 'roadtrip.day': '{number}. nap', 'roadtrip.quietDay.empty': 'Még nincs megálló — húzzon ide egyet', 'roadtrip.quietDay.one': 'Egyelőre csak {name} — húzzon ide egy megállót', diff --git a/shared/src/i18n/id/roadtrip.ts b/shared/src/i18n/id/roadtrip.ts index 1b746dae6..1fff5806b 100644 --- a/shared/src/i18n/id/roadtrip.ts +++ b/shared/src/i18n/id/roadtrip.ts @@ -210,6 +210,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Tercepat', 'roadtrip.alt.slower': '{time} lebih lama', 'roadtrip.alt.quicker': '{time} lebih cepat', + 'roadtrip.alt.otherEngine': 'Waktu dihitung mesin penghindaran, bukan mesin utama.', 'roadtrip.day': 'Hari {number}', 'roadtrip.quietDay.empty': 'Belum ada perhentian — jatuhkan di sini', 'roadtrip.quietDay.one': 'Sejauh ini hanya {name} — jatuhkan perhentian di sini', diff --git a/shared/src/i18n/it/roadtrip.ts b/shared/src/i18n/it/roadtrip.ts index 9d7498128..0fb7ff695 100644 --- a/shared/src/i18n/it/roadtrip.ts +++ b/shared/src/i18n/it/roadtrip.ts @@ -210,6 +210,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'La più veloce', 'roadtrip.alt.slower': '{time} in più', 'roadtrip.alt.quicker': '{time} in meno', + 'roadtrip.alt.otherEngine': 'Tempo dal router delle esclusioni, non dal principale.', 'roadtrip.day': 'Giorno {number}', 'roadtrip.quietDay.empty': 'Ancora nessuna sosta: trascinane una qui', 'roadtrip.quietDay.one': 'Finora solo {name}: trascina qui una sosta', diff --git a/shared/src/i18n/ja/roadtrip.ts b/shared/src/i18n/ja/roadtrip.ts index e68b03e41..e94f710df 100644 --- a/shared/src/i18n/ja/roadtrip.ts +++ b/shared/src/i18n/ja/roadtrip.ts @@ -207,6 +207,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': '最速', 'roadtrip.alt.slower': '{time} 遅い', 'roadtrip.alt.quicker': '{time} 速い', + 'roadtrip.alt.otherEngine': '所要時間は主エンジンではなく回避用エンジンでの計算です。', 'roadtrip.day': '{number} 日目', 'roadtrip.quietDay.empty': 'まだ立ち寄り先がありません。ここにドロップ', 'roadtrip.quietDay.one': '今のところ {name} だけです。立ち寄り先をここにドロップ', diff --git a/shared/src/i18n/ko/roadtrip.ts b/shared/src/i18n/ko/roadtrip.ts index fe4be5971..e6699fd73 100644 --- a/shared/src/i18n/ko/roadtrip.ts +++ b/shared/src/i18n/ko/roadtrip.ts @@ -206,6 +206,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': '가장 빠름', 'roadtrip.alt.slower': '{time} 더 걸림', 'roadtrip.alt.quicker': '{time} 더 빠름', + 'roadtrip.alt.otherEngine': '기본 엔진이 아니라 회피 엔진이 계산한 시간입니다.', 'roadtrip.day': '{number}일차', 'roadtrip.quietDay.empty': '아직 경유지가 없습니다. 여기에 놓으세요', 'roadtrip.quietDay.one': '지금은 {name}뿐입니다. 경유지를 여기에 놓으세요', diff --git a/shared/src/i18n/nl/roadtrip.ts b/shared/src/i18n/nl/roadtrip.ts index 0e2d09307..c3bc29768 100644 --- a/shared/src/i18n/nl/roadtrip.ts +++ b/shared/src/i18n/nl/roadtrip.ts @@ -210,6 +210,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Snelste', 'roadtrip.alt.slower': '{time} langzamer', 'roadtrip.alt.quicker': '{time} sneller', + 'roadtrip.alt.otherEngine': 'Tijd van de vermijdingsrouter, niet van de hoofdrouter.', 'roadtrip.day': 'Dag {number}', 'roadtrip.quietDay.empty': 'Nog geen stops — laat er hier een vallen', 'roadtrip.quietDay.one': 'Voorlopig alleen {name} — laat hier een stop vallen', diff --git a/shared/src/i18n/pl/roadtrip.ts b/shared/src/i18n/pl/roadtrip.ts index f1d35f8c8..53b796e0d 100644 --- a/shared/src/i18n/pl/roadtrip.ts +++ b/shared/src/i18n/pl/roadtrip.ts @@ -208,6 +208,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Najszybsza', 'roadtrip.alt.slower': '{time} dłużej', 'roadtrip.alt.quicker': '{time} krócej', + 'roadtrip.alt.otherEngine': 'Czas policzony silnikiem omijania, nie głównym.', 'roadtrip.day': 'Dzień {number}', 'roadtrip.quietDay.empty': 'Brak przystanków — upuść tutaj', 'roadtrip.quietDay.one': 'Na razie tylko {name} — upuść tutaj przystanek', diff --git a/shared/src/i18n/ru/roadtrip.ts b/shared/src/i18n/ru/roadtrip.ts index e07f94e56..a8a7faf1d 100644 --- a/shared/src/i18n/ru/roadtrip.ts +++ b/shared/src/i18n/ru/roadtrip.ts @@ -210,6 +210,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Самый быстрый', 'roadtrip.alt.slower': 'на {time} дольше', 'roadtrip.alt.quicker': 'на {time} быстрее', + 'roadtrip.alt.otherEngine': 'Время посчитал маршрутизатор обхода, не основной.', 'roadtrip.day': 'День {number}', 'roadtrip.quietDay.empty': 'Остановок пока нет — перетащите сюда', 'roadtrip.quietDay.one': 'Пока только {name} — перетащите сюда остановку', diff --git a/shared/src/i18n/sv/roadtrip.ts b/shared/src/i18n/sv/roadtrip.ts index 47a1d1fc7..97cab4a5b 100644 --- a/shared/src/i18n/sv/roadtrip.ts +++ b/shared/src/i18n/sv/roadtrip.ts @@ -207,6 +207,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Snabbast', 'roadtrip.alt.slower': '{time} långsammare', 'roadtrip.alt.quicker': '{time} snabbare', + 'roadtrip.alt.otherEngine': 'Tid från undvikandemotorn, inte huvudmotorn.', 'roadtrip.day': 'Dag {number}', 'roadtrip.quietDay.empty': 'Inga stopp än – släpp ett här', 'roadtrip.quietDay.one': 'Hittills bara {name} – släpp ett stopp här', diff --git a/shared/src/i18n/tr/roadtrip.ts b/shared/src/i18n/tr/roadtrip.ts index b1d109999..2d7d95985 100644 --- a/shared/src/i18n/tr/roadtrip.ts +++ b/shared/src/i18n/tr/roadtrip.ts @@ -209,6 +209,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'En hızlı', 'roadtrip.alt.slower': '{time} daha uzun', 'roadtrip.alt.quicker': '{time} daha kısa', + 'roadtrip.alt.otherEngine': 'Süre, ana motorla değil kaçınma motoruyla hesaplandı.', 'roadtrip.day': '{number}. gün', 'roadtrip.quietDay.empty': 'Henüz mola yok — buraya bırakın', 'roadtrip.quietDay.one': 'Şimdilik yalnızca {name} — buraya bir mola bırakın', diff --git a/shared/src/i18n/uk/roadtrip.ts b/shared/src/i18n/uk/roadtrip.ts index 0a8b59f4c..4a47124e8 100644 --- a/shared/src/i18n/uk/roadtrip.ts +++ b/shared/src/i18n/uk/roadtrip.ts @@ -209,6 +209,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Найшвидший', 'roadtrip.alt.slower': 'на {time} довше', 'roadtrip.alt.quicker': 'на {time} швидше', + 'roadtrip.alt.otherEngine': 'Час порахував маршрутизатор обходів, а не основний.', 'roadtrip.day': 'День {number}', 'roadtrip.quietDay.empty': 'Зупинок ще немає — перетягніть сюди', 'roadtrip.quietDay.one': 'Поки лише {name} — перетягніть сюди зупинку', diff --git a/shared/src/i18n/vi/roadtrip.ts b/shared/src/i18n/vi/roadtrip.ts index 4396cc815..939000bf0 100644 --- a/shared/src/i18n/vi/roadtrip.ts +++ b/shared/src/i18n/vi/roadtrip.ts @@ -208,6 +208,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': 'Nhanh nhất', 'roadtrip.alt.slower': 'chậm hơn {time}', 'roadtrip.alt.quicker': 'nhanh hơn {time}', + 'roadtrip.alt.otherEngine': 'Giờ do máy chủ định tuyến tránh đường tính, không phải máy chính.', 'roadtrip.day': 'Ngày {number}', 'roadtrip.quietDay.empty': 'Chưa có điểm dừng — thả vào đây', 'roadtrip.quietDay.one': 'Hiện chỉ có {name} — thả một điểm dừng vào đây', diff --git a/shared/src/i18n/zh-TW/roadtrip.ts b/shared/src/i18n/zh-TW/roadtrip.ts index 08a393e12..1b127b71a 100644 --- a/shared/src/i18n/zh-TW/roadtrip.ts +++ b/shared/src/i18n/zh-TW/roadtrip.ts @@ -197,6 +197,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': '最快', 'roadtrip.alt.slower': '慢 {time}', 'roadtrip.alt.quicker': '快 {time}', + 'roadtrip.alt.otherEngine': '駕駛時間由避開專用的路徑服務計算,無法與其他項比較。', 'roadtrip.day': '第 {number} 天', 'roadtrip.quietDay.empty': '尚無停靠點 — 拖到這裡', 'roadtrip.quietDay.one': '目前只有 {name} — 把停靠點拖到這裡', diff --git a/shared/src/i18n/zh/roadtrip.ts b/shared/src/i18n/zh/roadtrip.ts index 8cbca9a94..f13eccc88 100644 --- a/shared/src/i18n/zh/roadtrip.ts +++ b/shared/src/i18n/zh/roadtrip.ts @@ -197,6 +197,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.alt.fastest': '最快', 'roadtrip.alt.slower': '慢 {time}', 'roadtrip.alt.quicker': '快 {time}', + 'roadtrip.alt.otherEngine': '用时由避开引擎计算,而非主引擎。', 'roadtrip.day': '第 {number} 天', 'roadtrip.quietDay.empty': '暂无停靠点 — 拖到这里', 'roadtrip.quietDay.one': '目前只有 {name} — 把停靠点拖到这里',