feat: translate all pages
This commit is contained in:
117
messages/de.json
117
messages/de.json
@ -5,5 +5,122 @@
|
||||
"school": "Schule",
|
||||
"work": "Arbeit",
|
||||
"no-location": "Kein {name} Speicherort gespeichert."
|
||||
},
|
||||
"location": {
|
||||
"unlock": "Standort entsperren",
|
||||
"lock": "Standort sperren",
|
||||
"code": "Standortcode",
|
||||
"start": "Standort teilen",
|
||||
"join": "Remote-Standort beitreten"
|
||||
},
|
||||
"vehicles": {
|
||||
"selector": {
|
||||
"title": "Fahrzeugauswahl",
|
||||
"description": "Wählen Sie Ihr Fahrzeug aus, um die Route individuell auf Sie abzustimmen.",
|
||||
"add": "Fahrzeug hinzufügen"
|
||||
},
|
||||
"types": {
|
||||
"car": "Auto",
|
||||
"moped": "Moped"
|
||||
},
|
||||
"add": {
|
||||
"name": "Fahrzeugname",
|
||||
"legal-speed": "Legale Geschwindigkeit",
|
||||
"actual-speed": "Tatsächliche Geschwindigkeit",
|
||||
"fuel": "Kraftstoffart",
|
||||
"preferred-fuel": "Bevorzugter Kraftstoff",
|
||||
"diesel": "Diesel",
|
||||
"petrol": "Benzin",
|
||||
"electric": "Elektrisch",
|
||||
"errors": {
|
||||
"enter-name": "Bitte geben Sie einen Fahrzeugnamen ein.",
|
||||
"enter-speeds": "Bitte geben Sie gültige Geschwindigkeiten ein.",
|
||||
"select-fuel": "Bitte wählen Sie eine gültige Kraftstoffart und den bevorzugten Kraftstoff aus."
|
||||
}
|
||||
},
|
||||
"default": "Standardfahrzeug"
|
||||
},
|
||||
"save": "Speichern",
|
||||
"cancel": "Abbrechen",
|
||||
"loading": "Laden...",
|
||||
"more": "Mehr",
|
||||
"error": "Fehler",
|
||||
"sidebar": {
|
||||
"about": {
|
||||
"header": "Über",
|
||||
"powered-by": "Angetrieben von",
|
||||
"contributors": "Mitwirkende"
|
||||
},
|
||||
"developer": {
|
||||
"header": "Entwicklereinstellungen"
|
||||
},
|
||||
"offline-maps": {
|
||||
"header": "Offline-Karten",
|
||||
"not-available": "Keine Offline-Karten verfügbar.",
|
||||
"only-mobile": "Offline-Karten sind nur auf Mobilgeräten verfügbar.",
|
||||
"downloaded": "{name} wurde heruntergeladen"
|
||||
},
|
||||
"language": {
|
||||
"header": "Sprache"
|
||||
},
|
||||
"map-style": {
|
||||
"header": "Kartenstil"
|
||||
},
|
||||
"settings": {
|
||||
"header": "Einstellungen",
|
||||
"general": "Allgemein",
|
||||
"map": "Karte"
|
||||
},
|
||||
"info": {
|
||||
"dropped": "Pin",
|
||||
"route": "Route",
|
||||
"email": "E-Mail",
|
||||
"website": "Webseite",
|
||||
"call": "Anrufen",
|
||||
"set-as": "Speichern als {name}",
|
||||
"payment-methods": "Zahlungsarten",
|
||||
"fuel-types": "Kraftstoffarten",
|
||||
"prices": "Kraftstoffpreise",
|
||||
"no-prices": "Keine Kraftstoffpreise verfügbar.",
|
||||
"error-loading-prices": "Fehler beim Laden der Kraftstoffpreise",
|
||||
"internet-access": "Internetzugang",
|
||||
"fee": "Gebühr",
|
||||
"opening-hours": "Öffnungszeiten",
|
||||
"open": "Offen",
|
||||
"closed": "Geschlossen",
|
||||
"restaurant": "Restaurant",
|
||||
"reviews": "Bewertungen",
|
||||
"no-reviews": "Keine Bewertungen.",
|
||||
"write-review": "Eigene Bewertung schreiben"
|
||||
},
|
||||
"mapai": {
|
||||
"ask-question": "Stellen Sie eine Frage zu diesem Ort ..."
|
||||
},
|
||||
"in-route": {
|
||||
"left": "links",
|
||||
"end-trip": "Route beenden",
|
||||
"share-code": "Code teilen",
|
||||
"stop-sharing": "Standortfreigabe beenden",
|
||||
"share-location": "Routenstatus und Standort teilen"
|
||||
},
|
||||
"route": {
|
||||
"header": "Route",
|
||||
"driving-with": "Fahren mit",
|
||||
"help": "Sie können <strong>aktuell</strong> für Ihren aktuellen Standort und <strong>home</strong>, <strong>school</strong> oder <strong>work</strong> für gespeicherte Standorte verwenden.",
|
||||
"calculate": "Berechnen"
|
||||
},
|
||||
"search": {
|
||||
"header": "Suchergebnisse für"
|
||||
},
|
||||
"trip": {
|
||||
"header": "Routendetails",
|
||||
"start": "Start",
|
||||
"save": "Speichern",
|
||||
"send": "Senden"
|
||||
},
|
||||
"user": {
|
||||
"header": "Benutzer",
|
||||
"login": "Login"
|
||||
}
|
||||
}
|
||||
}
|
||||
117
messages/en.json
117
messages/en.json
@ -1,9 +1,126 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/inlang-message-format",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"loading": "Loading...",
|
||||
"more": "More",
|
||||
"error": "Error",
|
||||
"saved": {
|
||||
"home": "Home",
|
||||
"school": "School",
|
||||
"work": "Work",
|
||||
"no-location": "No {name} location saved."
|
||||
},
|
||||
"location": {
|
||||
"unlock": "Unlock Location",
|
||||
"lock": "Lock Location",
|
||||
"code": "Advertise code",
|
||||
"start": "Advertise Location",
|
||||
"join": "Join Remote Location"
|
||||
},
|
||||
"vehicles": {
|
||||
"default": "Default Vehicle",
|
||||
"selector": {
|
||||
"title": "Vehicle Selector",
|
||||
"description": "Select your vehicle to customize routing just for you.",
|
||||
"add": "Add Vehicle"
|
||||
},
|
||||
"types": {
|
||||
"car": "Car",
|
||||
"moped": "Moped"
|
||||
},
|
||||
"add": {
|
||||
"name": "Vehicle Name",
|
||||
"legal-speed": "Legal Speed",
|
||||
"actual-speed": "Actual Speed",
|
||||
"fuel": "Fuel Type",
|
||||
"preferred-fuel": "Preferred Fuel",
|
||||
"diesel": "Diesel",
|
||||
"petrol": "Petrol",
|
||||
"electric": "Electric",
|
||||
"errors": {
|
||||
"enter-name": "Please enter a vehicle name.",
|
||||
"enter-speeds": "Please enter valid speeds.",
|
||||
"select-fuel": "Please select a valid fuel type and preferred fuel."
|
||||
}
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
"about": {
|
||||
"header": "About",
|
||||
"powered-by": "Powered by",
|
||||
"contributors": "contributors"
|
||||
},
|
||||
"developer": {
|
||||
"header": "Developer Settings"
|
||||
},
|
||||
"offline-maps": {
|
||||
"header": "Offline Maps",
|
||||
"not-available": "No offline maps available.",
|
||||
"only-mobile": "Offline maps are only available on mobile.",
|
||||
"downloaded": "Downloaded {name}"
|
||||
},
|
||||
"language": {
|
||||
"header": "Language"
|
||||
},
|
||||
"map-style": {
|
||||
"header": "Map Style"
|
||||
},
|
||||
"settings": {
|
||||
"header": "Settings",
|
||||
"general": "General",
|
||||
"map": "Map"
|
||||
},
|
||||
"info": {
|
||||
"dropped": "Dropped Pin",
|
||||
"route": "Route",
|
||||
"email": "Email",
|
||||
"website": "Website",
|
||||
"call": "Call",
|
||||
"set-as": "Set as {name}",
|
||||
"payment-methods": "Payment Methods",
|
||||
"fuel-types": "Fuel Types",
|
||||
"prices": "Fuel Prices",
|
||||
"no-prices": "No fuel prices available.",
|
||||
"error-loading-prices": "Error loading fuel prices",
|
||||
"internet-access": "Internet Access",
|
||||
"fee": "Fee",
|
||||
"opening-hours": "Opening Hours",
|
||||
"open": "Open",
|
||||
"closed": "Closed",
|
||||
"restaurant": "Restaurant",
|
||||
"reviews": "Reviews",
|
||||
"no-reviews": "No reviews.",
|
||||
"write-review": "Write a review"
|
||||
},
|
||||
"mapai": {
|
||||
"ask-question": "Ask a question about this place..."
|
||||
},
|
||||
"in-route": {
|
||||
"left": "left",
|
||||
"end-trip": "End Trip",
|
||||
"share-code": "Share Code",
|
||||
"stop-sharing": "Stop Sharing Location",
|
||||
"share-location": "Share Trip Status & Location"
|
||||
},
|
||||
"route": {
|
||||
"header": "Route",
|
||||
"driving-with": "Driving with",
|
||||
"help": "You can use <strong>current</strong> for your current location, <strong>home</strong>, <strong>school</strong> or <strong>work</strong> for saved locations.",
|
||||
"calculate": "Calculate"
|
||||
},
|
||||
"search": {
|
||||
"header": "Search Results for"
|
||||
},
|
||||
"trip": {
|
||||
"header": "Trip Details",
|
||||
"start": "Start Navigation",
|
||||
"save": "Save",
|
||||
"send": "Send"
|
||||
},
|
||||
"user": {
|
||||
"header": "User",
|
||||
"login": "Login"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@
|
||||
import * as Select from "../ui/select";
|
||||
import Input from "../ui/input/input.svelte";
|
||||
import EvConnectorSelect from "./EVConnectorSelect.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
let open = $state(false);
|
||||
|
||||
@ -62,7 +63,7 @@
|
||||
</Drawer.Trigger>
|
||||
<Drawer.Content>
|
||||
<Drawer.Header>
|
||||
<Drawer.Title>Add Vehicle</Drawer.Title>
|
||||
<Drawer.Title>{m["vehicles.selector.add"]()}</Drawer.Title>
|
||||
</Drawer.Header>
|
||||
<div class="p-4 pt-0 flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
@ -71,75 +72,75 @@
|
||||
{@const Icon = getVehicleIcon(vehicle.type)}
|
||||
<Icon />
|
||||
{vehicle.type === "car"
|
||||
? "Car"
|
||||
? m["vehicles.types.car"]()
|
||||
: vehicle.type === "motor_scooter"
|
||||
? "Moped"
|
||||
? m["vehicles.types.moped"]()
|
||||
: "?"}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="car">
|
||||
<CarIcon />
|
||||
Car
|
||||
{m["vehicles.types.car"]()}
|
||||
</Select.Item>
|
||||
<Select.Item value="motor_scooter">
|
||||
<TractorIcon />
|
||||
Moped
|
||||
{m["vehicles.types.moped"]()}
|
||||
</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Vehicle Name"
|
||||
placeholder={m["vehicles.add.name"]()}
|
||||
bind:value={vehicle.name}
|
||||
class="w-full"
|
||||
aria-label="Vehicle Name"
|
||||
aria-label={m["vehicles.add.name"]()}
|
||||
aria-required="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-around mt-4">
|
||||
<span>Legal Speed</span>
|
||||
<span>{m["vehicles.add.legal-speed"]()}</span>
|
||||
<span>/</span>
|
||||
<span>Actual Speed</span>
|
||||
<span>{m["vehicles.add.actual-speed"]()}</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Legal Speed"
|
||||
placeholder={m["vehicles.add.legal-speed"]()}
|
||||
bind:value={vehicle.legalMaxSpeed}
|
||||
class="w-full text-center"
|
||||
aria-label="Legal Max Speed"
|
||||
aria-label={m["vehicles.add.legal-speed"]()}
|
||||
aria-required="true"
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Actual Speed"
|
||||
placeholder={m["vehicles.add.actual-speed"]()}
|
||||
bind:value={vehicle.actualMaxSpeed}
|
||||
class="w-full text-center"
|
||||
aria-label="Actual Max Speed"
|
||||
aria-label={m["vehicles.add.actual-speed"]()}
|
||||
aria-required="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-around mt-4">
|
||||
<span>Fuel Type</span>
|
||||
<span>{m["vehicles.add.fuel"]()}</span>
|
||||
<span>/</span>
|
||||
<span>Preferred Fuel</span>
|
||||
<span>{m["vehicles.add.preferred-fuel"]()}</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<Select.Root type="single" bind:value={vehicle.fuelType}>
|
||||
<Select.Trigger class="w-full">
|
||||
{vehicle.fuelType === "diesel"
|
||||
? "Diesel"
|
||||
? m["vehicles.add.diesel"]()
|
||||
: vehicle.fuelType === "petrol"
|
||||
? "Petrol"
|
||||
: "Electric"}
|
||||
? m["vehicles.add.petrol"]()
|
||||
: m["vehicles.add.electric"]()}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="diesel">Diesel</Select.Item>
|
||||
<Select.Item value="petrol">Petrol</Select.Item>
|
||||
<Select.Item value="electric">Electric</Select.Item>
|
||||
<Select.Item value="diesel">{m["vehicles.add.diesel"]()}</Select.Item>
|
||||
<Select.Item value="petrol">{m["vehicles.add.petrol"]()}</Select.Item>
|
||||
<Select.Item value="electric">{m["vehicles.add.electric"]()}</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
|
||||
@ -165,15 +166,15 @@
|
||||
onclick={() => {
|
||||
open = false;
|
||||
if (vehicle.name.trim() === "") {
|
||||
alert("Please enter a vehicle name.");
|
||||
alert(m["vehicles.add.errors.enter-name"]());
|
||||
return;
|
||||
}
|
||||
if (vehicle.legalMaxSpeed <= 0 || vehicle.actualMaxSpeed <= 0) {
|
||||
alert("Please enter valid speeds.");
|
||||
alert(m["vehicles.add.errors.enter-speeds"]());
|
||||
return;
|
||||
}
|
||||
if (!isValidFuel(vehicle)) {
|
||||
alert("Please select a valid fuel type and preferred fuel.");
|
||||
alert(m["vehicles.add.errors.select-fuel"]());
|
||||
return;
|
||||
}
|
||||
setVehicles([...vehicles, vehicle]);
|
||||
@ -182,7 +183,7 @@
|
||||
}}
|
||||
>
|
||||
<SaveIcon />
|
||||
Save
|
||||
{m.save()}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
@ -191,7 +192,7 @@
|
||||
}}
|
||||
>
|
||||
<XIcon />
|
||||
Cancel
|
||||
{m.cancel()}
|
||||
</Button>
|
||||
</Drawer.Footer>
|
||||
</Drawer.Content>
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
import AboutSidebar from "./sidebar/settings/AboutSidebar.svelte";
|
||||
import OfflineMapsSidebar from "./sidebar/settings/OfflineMapsSidebar.svelte";
|
||||
import DeveloperSidebar from "./sidebar/settings/DeveloperSidebar.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const views: Record<string, Component<any>> = {
|
||||
@ -188,10 +189,10 @@
|
||||
location.toggleLock();
|
||||
}}
|
||||
>
|
||||
{location.locked ? "Unlock Location" : "Lock Location"}
|
||||
{location.locked ? m["location.unlock"]() : m["location.unlock"]()}
|
||||
</Button>
|
||||
{#if location.code}
|
||||
<span>Advertise code: {location.code}</span>
|
||||
<span>{m["location.code"]()}: {location.code}</span>
|
||||
{/if}
|
||||
<Button
|
||||
variant="outline"
|
||||
@ -199,7 +200,7 @@
|
||||
advertiseRemoteLocation();
|
||||
}}
|
||||
>
|
||||
Advertise Location
|
||||
{m["location.start"]()}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
@ -207,7 +208,7 @@
|
||||
remoteLocation(prompt("Code?") || "");
|
||||
}}
|
||||
>
|
||||
Join Remote Location
|
||||
{m["location.join"]()}
|
||||
</Button>
|
||||
</div>
|
||||
</Popover.Content>
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
type VehicleType,
|
||||
} from "$lib/vehicles/vehicles.svelte";
|
||||
import AddVehicleDrawer from "./AddVehicleDrawer.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
let open = $state(false);
|
||||
|
||||
@ -48,9 +49,9 @@
|
||||
</Drawer.Trigger>
|
||||
<Drawer.Content>
|
||||
<Drawer.Header>
|
||||
<Drawer.Title>Vehicle Selector</Drawer.Title>
|
||||
<Drawer.Title>{m["vehicles.selector.title"]()}</Drawer.Title>
|
||||
<Drawer.Description
|
||||
>Select your vehicle to customize routing just for you.</Drawer.Description
|
||||
>{m["vehicles.selector.description"]()}</Drawer.Description
|
||||
>
|
||||
</Drawer.Header>
|
||||
<div class="p-4 pt-0 flex flex-col gap-2">
|
||||
@ -72,7 +73,7 @@
|
||||
<AddVehicleDrawer>
|
||||
<Button variant="secondary" class="w-full p-5">
|
||||
<PlusCircleIcon />
|
||||
Add Vehicle
|
||||
{m["vehicles.selector.add"]()}
|
||||
</Button>
|
||||
</AddVehicleDrawer>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { m } from "$lang/messages";
|
||||
import Badge from "$lib/components/ui/badge/badge.svelte";
|
||||
import { getStations } from "$lib/services/MTSK";
|
||||
import RequiresCapability from "../RequiresCapability.svelte";
|
||||
@ -6,7 +7,7 @@
|
||||
let { tags, lat, lng } = $props();
|
||||
</script>
|
||||
|
||||
<h3 class="text-lg font-bold mt-2">Fuel Types</h3>
|
||||
<h3 class="text-lg font-bold mt-2">{m["sidebar.info.fuel-types"]()}</h3>
|
||||
<ul class="flex gap-2 flex-wrap">
|
||||
{#each Object.entries(tags).filter( ([key]) => key.startsWith("fuel:"), ) as [key, tag] (key)}
|
||||
<!-- <li>{key.replace("fuel:", "")}: {tag}</li> -->
|
||||
@ -19,9 +20,9 @@
|
||||
</ul>
|
||||
|
||||
<RequiresCapability capability="fuel">
|
||||
<h3 class="text-lg font-bold mt-2">Prices</h3>
|
||||
<h3 class="text-lg font-bold mt-2">{m["sidebar.info.prices"]()}</h3>
|
||||
{#await getStations(lat, lng)}
|
||||
<p>Loading fuel prices...</p>
|
||||
<p>{m.loading()}</p>
|
||||
{:then stations}
|
||||
{#if stations.stations.length > 0}
|
||||
{@const station = stations.stations[0]}
|
||||
@ -35,9 +36,9 @@
|
||||
<p>E5: {station.e5}</p>
|
||||
{/if}
|
||||
{:else}
|
||||
<p>No fuel prices available.</p>
|
||||
<p>{m["sidebar.info.no-prices"]()}</p>
|
||||
{/if}
|
||||
{:catch err}
|
||||
<p>Error loading fuel prices: {err.message}</p>
|
||||
<p>{m["sidebar.info.error-loading-prices"]()}: {err.message}</p>
|
||||
{/await}
|
||||
</RequiresCapability>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { m } from "$lang/messages";
|
||||
import Badge from "$lib/components/ui/badge/badge.svelte";
|
||||
|
||||
let { tags } = $props();
|
||||
@ -8,12 +9,12 @@
|
||||
</script>
|
||||
|
||||
{#if tag != "no"}
|
||||
<h3 class="text-lg font-bold mt-2">Internet Access</h3>
|
||||
<h3 class="text-lg font-bold mt-2">{m["sidebar.info.internet-access"]()}</h3>
|
||||
{#each splitter as value, _index (value)}
|
||||
<Badge>{value}</Badge>
|
||||
{/each}
|
||||
{#if tags["internet_access:fee"] && tags["internet_access:fee"] != "no"}
|
||||
<Badge>Fee: {tags["internet_access:fee"]}</Badge>
|
||||
<Badge>{m["sidebar.info.fee"]()}: {tags["internet_access:fee"]}</Badge>
|
||||
{/if}
|
||||
{#if tags["internet_access:ssid"]}
|
||||
<Badge>{tags["internet_access:ssid"]}</Badge>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { m } from "$lang/messages";
|
||||
import Input from "$lib/components/ui/input/input.svelte";
|
||||
import { ai } from "$lib/services/lnv";
|
||||
import { SparklesIcon } from "@lucide/svelte";
|
||||
@ -23,17 +24,17 @@
|
||||
<SparklesIcon />
|
||||
<div class="flex gap-2 flex-col w-full">
|
||||
{#await ai(question, { lat, lon })}
|
||||
<p>Loading...</p>
|
||||
<p>{m.loading()}</p>
|
||||
{:then data}
|
||||
{@const text = getText(data)}
|
||||
<p>{text}</p>
|
||||
{:catch error}
|
||||
<p>Error: {error.message}</p>
|
||||
<p>{m.error()}: {error.message}</p>
|
||||
{/await}
|
||||
<Input
|
||||
type="text"
|
||||
value=""
|
||||
placeholder="Ask a question about this place..."
|
||||
placeholder={m["sidebar.mapai.ask-question"]()}
|
||||
onchange={(e) => {
|
||||
question = (e.target! as HTMLInputElement).value;
|
||||
}}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { m } from "$lang/messages";
|
||||
import Badge from "$lib/components/ui/badge/badge.svelte";
|
||||
import opening_hours from "opening_hours";
|
||||
|
||||
@ -18,11 +19,11 @@
|
||||
</script>
|
||||
|
||||
<h3 class="text-lg font-bold mt-2">
|
||||
Opening Hours
|
||||
{m["sidebar.info.opening-hours"]()}
|
||||
{#if oh.getState()}
|
||||
<Badge>Open</Badge>
|
||||
<Badge>{m["sidebar.info.open"]()}</Badge>
|
||||
{:else}
|
||||
<Badge variant="destructive">Closed</Badge>
|
||||
<Badge variant="destructive">{m["sidebar.info.closed"]()}</Badge>
|
||||
{/if}
|
||||
</h3>
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { m } from "$lang/messages";
|
||||
import Badge from "$lib/components/ui/badge/badge.svelte";
|
||||
|
||||
let { tags } = $props();
|
||||
@ -15,7 +16,7 @@
|
||||
</script>
|
||||
|
||||
{#if matchingTags.length > 0}
|
||||
<h3 class="text-lg font-bold mt-2">Restaurant</h3>
|
||||
<h3 class="text-lg font-bold mt-2">{m["sidebar.info.restaurant"]()}</h3>
|
||||
<ul class="flex gap-2 flex-wrap">
|
||||
{#each matchingTags as tag, _index (tag)}
|
||||
{#if tag != "no"}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { m } from "$lang/messages";
|
||||
import * as Avatar from "$lib/components/ui/avatar";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { getReviews, postReview } from "$lib/services/lnv";
|
||||
@ -7,7 +8,7 @@
|
||||
let { lat, lng }: { lat: number; lng: number } = $props();
|
||||
</script>
|
||||
|
||||
<h3 class="text-lg font-bold mt-2">Reviews</h3>
|
||||
<h3 class="text-lg font-bold mt-2">{m["sidebar.info.reviews"]()}</h3>
|
||||
{#await getReviews({ lat, lon: lng }) then reviews}
|
||||
{#if reviews.length > 0}
|
||||
<ul class="list-disc pl-5">
|
||||
@ -25,7 +26,7 @@
|
||||
{/each}
|
||||
</ul>
|
||||
{:else}
|
||||
<p>No reviews available.</p>
|
||||
<p>{m["sidebar.info.no-reviews"]()}</p>
|
||||
{/if}
|
||||
<Button
|
||||
variant="secondary"
|
||||
@ -46,8 +47,8 @@
|
||||
alert("Review submission cancelled.");
|
||||
}
|
||||
}}
|
||||
disabled>Write a review</Button
|
||||
disabled>{m["sidebar.info.write-review"]()}</Button
|
||||
><br />
|
||||
{:catch error}
|
||||
<p>Error loading reviews: {error.message}</p>
|
||||
<p>{m.error()}: {error.message}</p>
|
||||
{/await}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { m } from "$lang/messages";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import {
|
||||
decodePolyline,
|
||||
@ -122,7 +123,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
{fullDistanceText} left
|
||||
{fullDistanceText} {m["sidebar.in-route.left"]()}
|
||||
|
||||
<Button
|
||||
onclick={() => {
|
||||
@ -133,12 +134,12 @@
|
||||
<Button
|
||||
onclick={() => {
|
||||
stopNavigation();
|
||||
}}>End Trip</Button
|
||||
}}>{m["sidebar.in-route.end-trip"]()}</Button
|
||||
>
|
||||
|
||||
<div class="flex flex-col gap-2 mt-5">
|
||||
{#if location.code}
|
||||
<span>Share Code: {location.code}</span>
|
||||
<span>{m["sidebar.in-route.share-code"]()}: {location.code}</span>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onclick={() => {
|
||||
@ -147,7 +148,7 @@
|
||||
location.code = null;
|
||||
}}
|
||||
>
|
||||
Stop Sharing Location
|
||||
{m["sidebar.in-route.stop-sharing"]()}
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
@ -156,7 +157,7 @@
|
||||
advertiseRemoteLocation();
|
||||
}}
|
||||
>
|
||||
Share Trip Status & Location
|
||||
{m["sidebar.in-route.share-location"]()}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
import { getDeveloperToggle } from "./settings/developer.svelte";
|
||||
import InternetAccess from "../info/InternetAccess.svelte";
|
||||
import RestaurantInfo from "../info/RestaurantInfo.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
// let { feature }: { feature: Feature } = $props();
|
||||
|
||||
@ -88,9 +89,9 @@
|
||||
pin.liftPin();
|
||||
}}
|
||||
>
|
||||
Dropped Pin
|
||||
{m["sidebar.info.dropped"]()}
|
||||
</SidebarHeader>
|
||||
<p>Loading...</p>
|
||||
<p>{m.loading()}</p>
|
||||
{:then res}
|
||||
{#if res.elements.length === 0}
|
||||
<SidebarHeader
|
||||
@ -98,7 +99,7 @@
|
||||
pin.liftPin();
|
||||
}}
|
||||
>
|
||||
Dropped Pin
|
||||
{m["sidebar.info.dropped"]()}
|
||||
</SidebarHeader>
|
||||
<span style="color: #acacac;">© OpenStreetMap</span>
|
||||
<pre>{JSON.stringify(res, null, 2)}</pre>
|
||||
@ -132,7 +133,7 @@
|
||||
}}
|
||||
>
|
||||
<RouteIcon />
|
||||
Route
|
||||
{m["sidebar.info.route"]()}
|
||||
</Button>
|
||||
{#if tags.email || tags["contact:email"]}
|
||||
<Button
|
||||
@ -141,7 +142,7 @@
|
||||
target="_blank"
|
||||
>
|
||||
<MailIcon />
|
||||
Email
|
||||
{m["sidebar.info.email"]()}
|
||||
</Button>
|
||||
{/if}
|
||||
{#if tags.website || tags["contact:website"]}
|
||||
@ -151,7 +152,7 @@
|
||||
target="_blank"
|
||||
>
|
||||
<GlobeIcon />
|
||||
Website
|
||||
{m["sidebar.info.website"]()}
|
||||
</Button>
|
||||
{/if}
|
||||
{#if tags.phone || tags["contact:phone"]}
|
||||
@ -161,14 +162,14 @@
|
||||
target="_blank"
|
||||
>
|
||||
<PhoneIcon />
|
||||
Call
|
||||
{m["sidebar.info.call"]()}
|
||||
</Button>
|
||||
{/if}
|
||||
<Popover.Root>
|
||||
<Popover.Trigger>
|
||||
<Button variant="secondary">
|
||||
<EllipsisIcon />
|
||||
More
|
||||
{m.more()}
|
||||
</Button>
|
||||
</Popover.Trigger>
|
||||
<Popover.Content>
|
||||
@ -185,7 +186,7 @@
|
||||
}}
|
||||
>
|
||||
<HomeIcon />
|
||||
Set as Home
|
||||
{m["sidebar.info.set-as"]({ name: m["saved.home"]() })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
@ -195,7 +196,7 @@
|
||||
}}
|
||||
>
|
||||
<SchoolIcon />
|
||||
Set as School
|
||||
{m["sidebar.info.set-as"]({ name: m["saved.school"]() })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
@ -209,7 +210,7 @@
|
||||
}}
|
||||
>
|
||||
<BriefcaseIcon />
|
||||
Set as Work
|
||||
{m["sidebar.info.set-as"]({ name: m["saved.work"]() })}
|
||||
</Button>
|
||||
{#if dev.current}
|
||||
<Button
|
||||
@ -255,7 +256,7 @@
|
||||
|
||||
<!-- any payment:* tag -->
|
||||
{#if Object.keys(tags).some((key) => key.startsWith("payment:"))}
|
||||
<h3 class="text-lg font-bold mt-2">Payment Methods</h3>
|
||||
<h3 class="text-lg font-bold mt-2">{m["sidebar.info.payment-methods"]()}</h3>
|
||||
<ul style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
|
||||
{#each Object.entries(tags).filter( ([key]) => key.startsWith("payment:"), ) as [key, value] (key)}
|
||||
<Badge
|
||||
|
||||
@ -22,12 +22,12 @@
|
||||
onclick={() => {
|
||||
const loc = saved.home;
|
||||
if (!loc) {
|
||||
alert(m["saved.no-location"](m["saved.home"]));
|
||||
alert(m["saved.no-location"]({ name: m["saved.home"]() }));
|
||||
return;
|
||||
}
|
||||
const { lat, lon } = loc;
|
||||
if (!lat || !lon) {
|
||||
alert(m["saved.no-location"](m["saved.home"]));
|
||||
alert(m["saved.no-location"]({ name: m["saved.home"]() }));
|
||||
return;
|
||||
}
|
||||
pin.dropPin(lat, lon);
|
||||
@ -48,12 +48,12 @@
|
||||
console.log(saved);
|
||||
const loc = saved.school;
|
||||
if (!loc) {
|
||||
alert(m["saved.no-location"](m["saved.school"]));
|
||||
alert(m["saved.no-location"]({ name: m["saved.school"]() }));
|
||||
return;
|
||||
}
|
||||
const { lat, lon } = loc;
|
||||
if (!lat || !lon) {
|
||||
alert(m["saved.no-location"](m["saved.school"]));
|
||||
alert(m["saved.no-location"]({ name: m["saved.school"]() }));
|
||||
return;
|
||||
}
|
||||
pin.dropPin(lat, lon);
|
||||
@ -73,12 +73,12 @@
|
||||
onclick={() => {
|
||||
const loc = saved.work;
|
||||
if (!loc) {
|
||||
alert(m["saved.no-location"](m["saved.work"]));
|
||||
alert(m["saved.no-location"]({ name: m["saved.work"]() }));
|
||||
return;
|
||||
}
|
||||
const { lat, lon } = loc;
|
||||
if (!lat || !lon) {
|
||||
alert(m["saved.no-location"](m["saved.work"]));
|
||||
alert(m["saved.no-location"]({ name: m["saved.work"]() }));
|
||||
return;
|
||||
}
|
||||
pin.dropPin(lat, lon);
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
} from "$lib/vehicles/vehicles.svelte";
|
||||
import { location } from "../location.svelte";
|
||||
import { saved } from "$lib/saved.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
let {
|
||||
from,
|
||||
@ -46,11 +47,11 @@
|
||||
removeAllRoutes();
|
||||
}}
|
||||
>
|
||||
Route
|
||||
{m["sidebar.route.header"]()}
|
||||
</SidebarHeader>
|
||||
|
||||
<span
|
||||
>Driving with <strong>{(selectedVehicle() ?? DefaultVehicle).name}</strong
|
||||
>{m["sidebar.route.driving-with"]()} <strong>{(selectedVehicle() ?? DefaultVehicle).name}</strong
|
||||
></span
|
||||
>
|
||||
<div class="flex flex-col gap-2 w-full mb-2">
|
||||
@ -66,9 +67,7 @@
|
||||
<Input bind:value={toLocation} />
|
||||
</div>
|
||||
<span>
|
||||
You can use <strong>current</strong> for your current location,
|
||||
<strong>home</strong>
|
||||
or <strong>work</strong> for saved locations.
|
||||
{@html m["sidebar.route.help"]()}
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
@ -110,7 +109,7 @@
|
||||
}
|
||||
drawAllRoutes(routes);
|
||||
zoomToPoints(FROM, TO, map.value!);
|
||||
}}>Calculate</Button
|
||||
}}>{m["sidebar.route.calculate"]()}</Button
|
||||
>
|
||||
|
||||
{#if routes}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
import type { Feature } from "$lib/services/Search";
|
||||
import SidebarHeader from "./SidebarHeader.svelte";
|
||||
import { searchbar } from "../view.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
let {
|
||||
results,
|
||||
@ -21,7 +22,7 @@
|
||||
searchbar.text = "";
|
||||
}}
|
||||
>
|
||||
Search Results for "{query}"
|
||||
{m["sidebar.search.header"]()} "{query}"
|
||||
</SidebarHeader>
|
||||
<div
|
||||
id="results"
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { RouteIcon, SaveIcon, SendIcon } from "@lucide/svelte";
|
||||
import { map } from "../map.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
let {
|
||||
route,
|
||||
@ -27,7 +28,7 @@
|
||||
removeAllRoutes();
|
||||
}}
|
||||
>
|
||||
Trip Details
|
||||
{m["sidebar.trip.header"]()}
|
||||
</SidebarHeader>
|
||||
|
||||
<div id="actions" class="flex gap-2">
|
||||
@ -40,15 +41,15 @@
|
||||
}}
|
||||
>
|
||||
<RouteIcon />
|
||||
Start Navigation
|
||||
{m["sidebar.trip.start"]()}
|
||||
</Button>
|
||||
<Button variant="secondary" disabled>
|
||||
<SaveIcon />
|
||||
Save
|
||||
{m["sidebar.trip.save"]()}
|
||||
</Button>
|
||||
<Button variant="secondary" disabled>
|
||||
<SendIcon />
|
||||
Send
|
||||
{m["sidebar.trip.send"]()}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
import Button from "$lib/components/ui/button/button.svelte";
|
||||
import { getAuthURL, getOIDCUser } from "$lib/services/oidc";
|
||||
import * as Avatar from "$lib/components/ui/avatar";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
interface OIDCUser {
|
||||
sub: string;
|
||||
@ -26,7 +27,7 @@
|
||||
</script>
|
||||
|
||||
{#if !user}
|
||||
<SidebarHeader>User</SidebarHeader>
|
||||
<SidebarHeader>{m["sidebar.user.header"]()}</SidebarHeader>
|
||||
|
||||
<Button
|
||||
onclick={async () => {
|
||||
@ -57,7 +58,7 @@
|
||||
atob((localStorage.getItem("lnv-id") || "").split(".")[1]),
|
||||
);
|
||||
});
|
||||
}}>Login</Button
|
||||
}}>{m["sidebar.user.login"]()}</Button
|
||||
>
|
||||
{:else}
|
||||
<SidebarHeader>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { m } from "$lang/messages";
|
||||
import SidebarHeader from "../SidebarHeader.svelte";
|
||||
import { getDeveloperToggle } from "./developer.svelte";
|
||||
|
||||
@ -6,7 +7,7 @@
|
||||
const dev = getDeveloperToggle();
|
||||
</script>
|
||||
|
||||
<SidebarHeader>About</SidebarHeader>
|
||||
<SidebarHeader>{m["sidebar.about.header"]()}</SidebarHeader>
|
||||
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
@ -21,9 +22,9 @@
|
||||
>
|
||||
TrafficCue
|
||||
</h1>
|
||||
<span>Powered by:</span>
|
||||
<span>{m["sidebar.about.powered-by"]()}:</span>
|
||||
<ul>
|
||||
<li>© OpenStreetMap contributors</li>
|
||||
<li>© OpenStreetMap {m["sidebar.about.contributors"]()}</li>
|
||||
<li>Natural Earth</li>
|
||||
<li>MapLibre</li>
|
||||
<li>OpenMapTiles</li>
|
||||
|
||||
@ -6,11 +6,12 @@
|
||||
import { downloadPMTiles } from "$lib/services/OfflineTiles";
|
||||
import { getDeveloperToggle } from "./developer.svelte";
|
||||
import { view } from "../../view.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
const dev = getDeveloperToggle();
|
||||
</script>
|
||||
|
||||
<SidebarHeader>Developer Settings</SidebarHeader>
|
||||
<SidebarHeader>{m["sidebar.developer.header"]()}</SidebarHeader>
|
||||
|
||||
<div id="sections">
|
||||
<section>
|
||||
|
||||
@ -3,22 +3,23 @@
|
||||
import { DownloadCloudIcon } from "@lucide/svelte";
|
||||
import SettingsButton from "./SettingsButton.svelte";
|
||||
import SidebarHeader from "../SidebarHeader.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
let progresses: Record<string, number> = $state({});
|
||||
</script>
|
||||
|
||||
<SidebarHeader>Offline Maps</SidebarHeader>
|
||||
<SidebarHeader>{m["sidebar.offline-maps.header"]()}</SidebarHeader>
|
||||
|
||||
{#await getRemoteList()}
|
||||
<p>Loading...</p>
|
||||
<p>{m.loading()}</p>
|
||||
{:then list}
|
||||
<div style="display: flex; flex-direction: column; gap: 0.5rem;">
|
||||
{#if list.length === 0}
|
||||
<p>No offline maps available.</p>
|
||||
<p>{m["sidebar.offline-maps.not-available"]()}</p>
|
||||
{/if}
|
||||
|
||||
{#if !window.__TAURI__}
|
||||
<p>Offline maps are only available on mobile.</p>
|
||||
<p>{m["sidebar.offline-maps.only-mobile"]()}</p>
|
||||
{/if}
|
||||
|
||||
{#each list as item, _index (item.file)}
|
||||
@ -35,7 +36,7 @@
|
||||
progresses[item.file] = (progress / total) * 100;
|
||||
},
|
||||
);
|
||||
alert(`Downloaded ${item.name}`);
|
||||
alert(m["sidebar.offline-maps.downloaded"]({ name: item.name }));
|
||||
location.reload();
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -9,34 +9,35 @@
|
||||
import SidebarHeader from "../SidebarHeader.svelte";
|
||||
import SettingsButton from "./SettingsButton.svelte";
|
||||
import { getDeveloperToggle } from "./developer.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
const dev = getDeveloperToggle();
|
||||
</script>
|
||||
|
||||
<SidebarHeader>Settings</SidebarHeader>
|
||||
<SidebarHeader>{m["sidebar.settings.header"]()}</SidebarHeader>
|
||||
|
||||
<div id="sections">
|
||||
<section>
|
||||
<h2>General</h2>
|
||||
<SettingsButton icon={LanguagesIcon} text="Language" disabled />
|
||||
<h2>{m["sidebar.settings.general"]()}</h2>
|
||||
<SettingsButton icon={LanguagesIcon} text={m["sidebar.language.header"]()} disabled />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Map</h2>
|
||||
<SettingsButton icon={MapIcon} text="Offline Maps" view="offline-maps" />
|
||||
<SettingsButton icon={PaintbrushIcon} text="Map Style" disabled />
|
||||
<h2>{m["sidebar.settings.map"]()}</h2>
|
||||
<SettingsButton icon={MapIcon} text={m["sidebar.offline-maps.header"]()} view="offline-maps" />
|
||||
<SettingsButton icon={PaintbrushIcon} text={m["sidebar.map-style.header"]()} disabled />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>About</h2>
|
||||
<h2>{m["sidebar.about.header"]()}</h2>
|
||||
{#if dev.current == "true"}
|
||||
<SettingsButton
|
||||
icon={CodeIcon}
|
||||
text="Developer Settings"
|
||||
text={m["sidebar.developer.header"]()}
|
||||
view="dev-options"
|
||||
/>
|
||||
{/if}
|
||||
<SettingsButton icon={InfoIcon} text="About" view="about" />
|
||||
<SettingsButton icon={InfoIcon} text={m["sidebar.about.header"]()} view="about" />
|
||||
</section>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { m } from "$lang/messages";
|
||||
|
||||
/*
|
||||
Valhalla costing:
|
||||
auto, prioritizes motorways = car, (truck), motorcycle
|
||||
@ -57,7 +59,7 @@ export interface Vehicle {
|
||||
}
|
||||
|
||||
export const DefaultVehicle: Vehicle = {
|
||||
name: "Default Vehicle",
|
||||
name: m["vehicles.default"](),
|
||||
legalMaxSpeed: 45,
|
||||
actualMaxSpeed: 45,
|
||||
type: "motor_scooter",
|
||||
|
||||
Reference in New Issue
Block a user