trails/packages/i18n/src/locales/en.ts
Ullrich Schäfer 20b91ef511
Fix Wahoo import bugs, add Import All, update spec
Bugs fixed:
- FIT parser returns timestamps as Date objects, not strings — convert
  to ISO 8601 before passing to generateGpx (caused str.replace crash)
- FIT parser already converts semicircles to degrees — remove redundant
  conversion that produced near-zero coordinates
- Wahoo CDN URLs are pre-signed S3 URLs — remove Bearer auth header
  from download requests (caused 400 "Unsupported Authorization Type")
- Filter out third-party workouts (fitness_app_id >= 1000) since Wahoo
  does not share their data via the API

UX improvements:
- Individual imports use fetcher (no page refresh), button shows
  "Importing..." inline
- "Import all" button imports all unimported workouts on the page
  sequentially with progress indicator
- Add @vitejs/plugin-basic-ssl for local HTTPS dev (opt-in via HTTPS=1)

Also adds unit test for FIT-to-GPX conversion with real fixture file,
and updates wahoo-import spec to reflect all behaviors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 17:47:48 +02:00

228 lines
8.2 KiB
TypeScript

export default {
common: {
save: "Save",
cancel: "Cancel",
delete: "Delete",
edit: "Edit",
close: "Close",
loading: "Loading...",
error: "Something went wrong",
goHome: "Go home",
pageNotFound: "Page not found",
serviceUnavailable: "Service temporarily unavailable. Please try again later.",
},
planner: {
title: "trails.cool Planner",
subtitle: "Collaborative route planning",
home: "Home",
newSession: "New Session",
saveRoute: "Save Route",
exportGpx: "Export GPX",
exportRoute: "Export Route",
exportRouteDesc: "Clean GPX track for any app",
exportPlan: "Export Plan",
exportPlanDesc: "Includes waypoints and no-go areas",
"undo.tooltip": "Undo (Ctrl+Z)",
"redo.tooltip": "Redo (Ctrl+Shift+Z)",
importGpx: "Import GPX",
importGpxError: "Could not read GPX file. Please check the file format.",
dropGpxHere: "Drop GPX file here",
replaceRouteConfirm: "Replace current route with imported GPX?",
profile: "Profile",
connecting: "Connecting...",
loadingMap: "Loading map...",
computingRoute: "Computing route...",
routeError: "Route calculation failed. Please try again.",
noRouteFound: "No route found. Try moving the waypoint to a road or path.",
host: "Host",
connected: "Connected",
saveToJournal: "Save to Journal",
saving: "Saving...",
saved: "Saved!",
returnToJournal: "Return to Journal",
profiles: {
trekking: "Hiking",
fastbike: "Cycling (fast)",
safety: "Cycling (safe)",
shortest: "Shortest",
car: "Car",
},
participants: {
you: "(you)",
host: "Host",
editName: "Click to edit your name",
joined: "{{name}} joined",
left: "{{name}} left",
},
sidebar: {
waypoints: "Waypoints",
notes: "Notes",
},
noGoAreas: {
draw: "Draw no-go area",
cancel: "Cancel no-go area",
hint: "Right-click a no-go area to delete it",
},
notes: {
placeholder: "Add notes for this session...",
},
colorMode: {
label: "Route Color",
plain: "Plain",
elevation: "Elevation",
surface: "Surface",
surfaceUnavailable: "Surface data not available for this profile",
},
rateLimitExceeded: "Too many requests. Please try again later.",
elevation: {
gain: "Elevation Gain",
loss: "Elevation Loss",
profile: "Elevation Profile",
},
landing: {
startPlanning: "Start Planning",
heroDescription: "Plan hiking and cycling routes together in real-time. No account needed.",
featureCollaborative: "Real-Time Collaboration",
featureCollaborativeDesc: "Edit waypoints together — changes sync instantly across all participants.",
featureRouting: "Smart Routing",
featureRoutingDesc: "BRouter computes optimal routes for hiking, cycling, or driving with elevation awareness.",
featureElevation: "Elevation Profile",
featureElevationDesc: "See the full elevation profile of your route with gain and loss statistics.",
featureExport: "GPX Export",
featureExportDesc: "Export your route as GPX for use in any GPS device or app.",
featureNoAccount: "No Account Needed",
featureNoAccountDesc: "Start planning immediately. Share a link and anyone can join your session.",
saveRoutes: "Want to save your routes?",
saveRoutesDesc: "Create a free account on trails.cool to keep your routes, track activities, and more.",
goToJournal: "Go to trails.cool",
footer: {
privacy: "Privacy",
source: "Source Code",
builtWith: "Built with BRouter and OpenStreetMap",
},
},
},
journal: {
title: "trails.cool",
subtitle: "Your outdoor activity journal",
welcome: "Welcome,",
addPasskeyPrompt: "Add a passkey for faster sign-in on this device.",
addPasskey: "Add Passkey",
settingUp: "Setting up...",
passkeyAdded: "Passkey added! You can now sign in instantly on this device.",
passkeyStatus: "{{count}} passkey registered",
passkeyStatus_other: "{{count}} passkeys registered",
routes: {
title: "Routes",
myRoutes: "My Routes",
new: "New Route",
edit: "Edit Route",
editInPlanner: "Edit in Planner",
opening: "Opening...",
importGpx: "Import GPX",
exportGpx: "Export GPX",
delete: "Delete Route",
distance: "Distance",
elevationGain: "Elevation Gain",
noRoutesYet: "No routes yet. Create your first route!",
noMapPreview: "No map preview",
saveChanges: "Save Changes",
},
activities: {
title: "Activities",
new: "New Activity",
duration: "Duration",
linkToRoute: "Link to Route",
createRouteFromActivity: "Create Route from Activity",
delete: "Delete Activity",
deleteConfirm: "Are you sure you want to delete this activity?",
importedFrom: "Imported from {{provider}}",
},
settings: {
title: "Settings",
profile: {
title: "Profile",
displayName: "Display Name",
bio: "Bio",
saved: "Profile saved.",
},
security: {
title: "Security",
description: "Manage your passkeys for signing in.",
addPasskey: "Add Passkey",
passkey: "Passkey",
thisDevice: "This device",
securityKey: "Security key",
bluetooth: "Bluetooth",
phoneOrTablet: "Phone or tablet",
addedOn: "Added {{date}}",
noPasskeys: "No passkeys registered. You can sign in with magic links.",
deleteConfirm: "Are you sure you want to delete this passkey?",
deleteLastWarning: "This is your only passkey. You will need to use magic links to sign in. Delete anyway?",
},
account: {
title: "Account",
changeEmail: "Change",
newEmailPlaceholder: "New email address",
sendVerification: "Verify",
verificationSent: "Verification email sent. Check your inbox.",
dangerZone: "Danger Zone",
deleteDescription: "Permanently delete your account and all associated data.",
deleteAccount: "Delete Account",
deleteConfirmPrompt: "Type \"{{username}}\" to confirm deletion:",
confirmDelete: "Permanently Delete",
},
services: {
title: "Connected Services",
connect: "Connect",
disconnect: "Disconnect",
connectedAs: "Connected (ID: {{id}})",
},
},
sync: {
import: "Import",
importFrom: "Import from {{provider}}",
imported: "Imported",
noWorkouts: "No workouts found.",
noGps: "No GPS",
noGpsTooltip: "{{provider}} does not provide route data for this activity",
importing: "Importing...",
importAll: "Import all ({{count}})",
importingProgress: "Importing {{current}} of {{total}}...",
previous: "Previous",
next: "Next",
},
nav: {
routes: "Routes",
activities: "Activities",
login: "Sign In",
register: "Register",
profile: "Profile",
settings: "Settings",
logout: "Log Out",
},
auth: {
login: "Sign In",
register: "Register",
logout: "Log Out",
email: "Email",
username: "Username",
signInWithPasskey: "Sign in with Passkey",
authenticating: "Authenticating...",
useMagicLink: "No passkey on this device? Use a magic link instead",
magicLinkHelp: "We'll send a login link to your email.",
sendMagicLink: "Send Magic Link",
sending: "Sending...",
backToPasskey: "Back to passkey login",
checkEmail: "Check your email! We sent a login link to",
linkExpires: "The link expires in 15 minutes.",
noAccount: "Don't have an account?",
registerDescription: "Register with a passkey — no password needed.",
registerWithPasskey: "Register with Passkey",
creatingPasskey: "Creating passkey...",
passkeyNotSupported: "Your browser does not support passkeys. Please use a different browser to register.",
passkeyNotSupportedRegister: "Your browser doesn't support passkeys. You can register with a magic link instead and add a passkey later from a supported browser.",
registerWithMagicLink: "Register with Magic Link",
},
},
} as const;