Implements the activity-stats change (specs/activity-stats): - gpx: `movingTime(tracks)` — moving seconds from trackpoint timestamps, excluding stationary spans + long gaps; null when no timestamps. - stats.ts: pure formatters (distance/elevation/duration/speed/pace), sport-aware `deriveRate` (pace for foot sports, speed otherwise, speed default), and `activityStatItems` encoding the canonical order (distance · time · [moving] · pace/speed · ascent · descent; compact subset). - StatRow: one shared presentational component (size sm/lg), adopted on the activity detail (full set; loader derives moving time), route detail (distance/ascent/descent), feed card + profile list (compact). - i18n: journal.stats.* in en + de. Tests: movingTime (stationary/gap exclusion, moving ≤ elapsed), deriveRate, formatters, activityStatItems ordering + compact, StatRow render (jsdom). typecheck + lint + unit (gpx 63, journal 311) green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
641 lines
24 KiB
TypeScript
641 lines
24 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",
|
|
exportDays: "Export Day Segments",
|
|
exportDaysDesc: "One GPX file per day",
|
|
"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",
|
|
},
|
|
multiDay: {
|
|
dayLabel: "Day {{n}}",
|
|
dayCount: "{{count}} days",
|
|
dayCount_one: "1 day",
|
|
overnight: "Overnight",
|
|
markOvernight: "Mark as overnight stop",
|
|
removeOvernight: "Remove overnight stop",
|
|
distance: "Distance",
|
|
ascent: "Ascent",
|
|
descent: "Descent",
|
|
},
|
|
poi: {
|
|
toggle: "Points of Interest",
|
|
title: "Points of Interest",
|
|
loading: "Loading...",
|
|
zoomIn: "Zoom in to see POIs",
|
|
rateLimited: "POI data temporarily unavailable",
|
|
error: "Failed to load POIs",
|
|
drinkingWater: "Drinking water",
|
|
shelter: "Shelter",
|
|
camping: "Camping",
|
|
food: "Food & drink",
|
|
groceries: "Groceries",
|
|
bikeInfra: "Bike infrastructure",
|
|
accommodation: "Accommodation",
|
|
viewpoints: "Viewpoints",
|
|
toilets: "Toilets",
|
|
},
|
|
waypoint: {
|
|
notePlaceholder: "Add a note...",
|
|
noteCounter: "{{count}} / {{max}}",
|
|
},
|
|
nearbyPoi: {
|
|
heading: "Nearby",
|
|
loading: "Looking up nearby points of interest…",
|
|
empty: "No nearby points of interest found",
|
|
rateLimited: "POI lookup unavailable",
|
|
snap: "Snap here",
|
|
showMore: "Show more",
|
|
},
|
|
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",
|
|
grade: "Grade",
|
|
highway: "Road Type",
|
|
maxspeed: "Speed Limit",
|
|
smoothness: "Smoothness",
|
|
tracktype: "Track Type",
|
|
cycleway: "Cycleway",
|
|
bikeroute: "Bike Route",
|
|
surfaceLegend: "Color by road surface type",
|
|
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",
|
|
grade: "Grade Profile",
|
|
highway: "Road Type Profile",
|
|
maxspeed: "Speed Limit Profile",
|
|
smoothness: "Smoothness Profile",
|
|
tracktype: "Track Type Profile",
|
|
cycleway: "Cycleway Profile",
|
|
bikeroute: "Bike Route Profile",
|
|
low: "Low",
|
|
high: "High",
|
|
},
|
|
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: {
|
|
imprint: "Imprint",
|
|
privacy: "Privacy",
|
|
terms: "Terms",
|
|
source: "Source Code",
|
|
builtWith: "Built with BRouter and OpenStreetMap",
|
|
alpha: "Alpha version",
|
|
},
|
|
},
|
|
},
|
|
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",
|
|
home: {
|
|
heroTitle: "Federated outdoor journal",
|
|
heroSubtitle: "Plan routes, record activities, own your data.",
|
|
tryPlannerPrefix: "Or ",
|
|
tryPlannerLink: "try the Planner without an account",
|
|
tryPlannerSuffix: " →",
|
|
exploreLink: "Browse who's here →",
|
|
marketing: {
|
|
planner: {
|
|
title: "Plan routes together",
|
|
body: "Sketch hiking and cycling routes collaboratively in real time. No account needed.",
|
|
},
|
|
journal: {
|
|
title: "Record activities",
|
|
body: "Log your rides, hikes, and walks. Keep them private, share with friends, or publish to the world.",
|
|
},
|
|
federation: {
|
|
title: "Federated by design",
|
|
body: "Part of the fediverse via ActivityPub: Mastodon users can follow you and see your public activities, and you can follow trails users on any instance.",
|
|
},
|
|
ownership: {
|
|
title: "Your data, always",
|
|
body: "No ads, no tracking, no data sales. Export everything as GPX or JSON any time. MIT licensed and self-hostable.",
|
|
},
|
|
},
|
|
feed: {
|
|
heading: "Recent activity",
|
|
empty: "No public activities yet.",
|
|
},
|
|
dashboardEmpty: "No activities yet. Record or import your first one from the Activities tab.",
|
|
poweredBy: "Powered by trails.cool — about the project",
|
|
},
|
|
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",
|
|
sendToWahoo: "Send to Wahoo",
|
|
sendToWahooHelp: "This sends your route to Wahoo so it appears on your bike computer.",
|
|
sentToWahoo: "Sent to Wahoo on {{date}}",
|
|
sendToWahooFailed: "Last attempt failed: {{error}}",
|
|
sendToWahooSending: "Sending…",
|
|
onWahooNewer: "On Wahoo (v{{n}}) — local version is newer",
|
|
sendUpdatedVersion: "Send updated version",
|
|
sendToWahooBanner: {
|
|
success: "Route sent to Wahoo. Check your Wahoo App or bike computer.",
|
|
needsPermission: "We need your permission to send routes to Wahoo. Please reconnect.",
|
|
noConnection: "Connect your Wahoo account in Settings first.",
|
|
noGeometry: "This route has no geometry yet — plan a path before sending.",
|
|
validation: "We couldn't send this route — try editing the name or description.",
|
|
rateLimit: "Too many requests to Wahoo. Try again in a minute.",
|
|
tokenExpired: "Your Wahoo connection expired. Please reconnect in Settings.",
|
|
generic: "Couldn't send to Wahoo. Try again later.",
|
|
},
|
|
distance: "Distance",
|
|
elevationGain: "Elevation Gain",
|
|
dayBreakdown: "Day Breakdown",
|
|
dayLabel: "Day {{n}}",
|
|
waypoints: "Waypoints",
|
|
poi: {
|
|
phone: "Phone",
|
|
website: "Website",
|
|
openingHours: "Hours",
|
|
address: "Address",
|
|
},
|
|
noRoutesYet: "No routes yet. Create your first route!",
|
|
noMapPreview: "No map preview",
|
|
saveChanges: "Save Changes",
|
|
empty: {
|
|
heading: "This route is empty",
|
|
bodyOwner: "You haven't planned any waypoints yet. Open it in the Planner to sketch a path, or upload a GPX file.",
|
|
bodyViewer: "This route doesn't have any waypoints yet.",
|
|
openInPlanner: "Open in Planner",
|
|
uploadGpx: "or upload a GPX file",
|
|
},
|
|
visibility: {
|
|
label: "Visibility",
|
|
private: "Private",
|
|
unlisted: "Unlisted (only people with the link)",
|
|
public: "Public (anyone on the internet)",
|
|
privateHelp: "Only you can see this route.",
|
|
unlistedHelp: "Anyone with the URL can view it; it won't appear on your public profile.",
|
|
publicHelp: "Visible to anyone, including logged-out visitors; listed on your public profile.",
|
|
},
|
|
},
|
|
profile: {
|
|
ownNote: "This is your profile — visitors see only what you've marked public.",
|
|
privateNote: "Your profile is set to private (locked). Visitors see a stub with a Request-to-follow button; only accepted followers see your public content.",
|
|
goToSettings: "Go to settings",
|
|
noPublicRoutes: "No public routes yet.",
|
|
noPublicActivities: "No public activities yet.",
|
|
lockedBadge: "Private",
|
|
lockedTitle: "This profile is private. Follow requests need approval.",
|
|
privateStub: {
|
|
heading: "This profile is private",
|
|
bodyAuth: "Send a follow request to see their public routes and activities. They'll need to approve it.",
|
|
bodyAnon: "Sign in and request to follow them to see their public routes and activities.",
|
|
},
|
|
},
|
|
notifications: {
|
|
title: "Notifications",
|
|
empty: "No notifications yet.",
|
|
markAllRead: "Mark all read",
|
|
loadOlder: "Load older",
|
|
someone: "Someone",
|
|
tabs: {
|
|
activity: "Activity",
|
|
requests: "Requests",
|
|
},
|
|
summary: {
|
|
followRequestReceived: "{{name}} requested to follow you",
|
|
followReceived: "{{name}} started following you",
|
|
followRequestApproved: "{{name}} accepted your follow request",
|
|
activityPublished: "{{owner}} posted “{{activity}}”",
|
|
},
|
|
},
|
|
social: {
|
|
follow: "Follow",
|
|
unfollow: "Unfollow",
|
|
requestToFollow: "Request to follow",
|
|
pendingCancel: "Requested",
|
|
requests: {
|
|
title: "Follow requests",
|
|
empty: "No pending follow requests.",
|
|
approve: "Approve",
|
|
reject: "Reject",
|
|
receivedAt: "Requested {{date}}",
|
|
},
|
|
followers: {
|
|
label: "Followers",
|
|
heading: "Followers of {{user}}",
|
|
count: "{{count}} follower",
|
|
count_other: "{{count}} followers",
|
|
empty: "Nobody yet.",
|
|
},
|
|
following: {
|
|
label: "Following",
|
|
heading: "{{user}} is following",
|
|
count: "Following {{count}}",
|
|
count_other: "Following {{count}}",
|
|
empty: "Not following anyone yet.",
|
|
},
|
|
outgoing: {
|
|
heading: "Following across instances",
|
|
subtitle: "Follow people on other trails.cool instances. Requests stay pending until their instance accepts.",
|
|
handleLabel: "Their handle",
|
|
followButton: "Follow",
|
|
pendingBadge: "Pending",
|
|
acceptedBadge: "Following",
|
|
cancelRequest: "Cancel request",
|
|
unfollow: "Unfollow",
|
|
empty: "No follows on other instances yet. Enter a handle above to start.",
|
|
notTrails: "Outbound federation is currently trails-to-trails only — that instance doesn't run trails.cool.",
|
|
disabled: "Federation is not enabled on this instance.",
|
|
},
|
|
prevPage: "Previous",
|
|
nextPage: "Next",
|
|
pageOfTotal: "Page {{page}} of {{totalPages}}",
|
|
feed: {
|
|
title: "Feed",
|
|
heading: "Following",
|
|
empty: "You're not following anyone yet. Browse profiles and tap Follow to start building your feed.",
|
|
followRemote: "Follow someone on another trails instance →",
|
|
seePublic: "Or browse the instance public feed →",
|
|
toggle: {
|
|
followed: "Following",
|
|
public: "Public",
|
|
},
|
|
public: {
|
|
heading: "Public",
|
|
empty: "No public activities on this instance yet.",
|
|
},
|
|
},
|
|
},
|
|
demo: {
|
|
badge: "🐕 Demo account",
|
|
},
|
|
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}}",
|
|
sport: {
|
|
label: "Sport",
|
|
unspecified: "Unspecified",
|
|
hike: "Hike",
|
|
walk: "Walk",
|
|
run: "Run",
|
|
ride: "Ride",
|
|
gravel: "Gravel",
|
|
mtb: "Mountain bike",
|
|
ski: "Ski",
|
|
other: "Other",
|
|
verb: {
|
|
hike: "went hiking",
|
|
walk: "went for a walk",
|
|
run: "went for a run",
|
|
ride: "went for a ride",
|
|
gravel: "went gravel riding",
|
|
mtb: "went mountain biking",
|
|
ski: "went skiing",
|
|
other: "logged an activity",
|
|
},
|
|
},
|
|
sortByDate: "Activity date",
|
|
sortByAdded: "Date added",
|
|
visibility: {
|
|
label: "Visibility",
|
|
private: "Private",
|
|
unlisted: "Unlisted (only people with the link)",
|
|
public: "Public (anyone on the internet)",
|
|
},
|
|
},
|
|
stats: {
|
|
distance: "Distance",
|
|
duration: "Time",
|
|
movingTime: "Moving time",
|
|
avgSpeed: "Avg speed",
|
|
avgPace: "Avg pace",
|
|
ascent: "Ascent",
|
|
descent: "Descent",
|
|
},
|
|
settings: {
|
|
title: "Settings",
|
|
nav: {
|
|
profile: "Profile",
|
|
account: "Account",
|
|
security: "Security",
|
|
connections: "Connected services",
|
|
},
|
|
profile: {
|
|
title: "Profile",
|
|
displayName: "Display Name",
|
|
bio: "Bio",
|
|
saved: "Profile saved.",
|
|
visibility: {
|
|
label: "Profile visibility",
|
|
public: "Public",
|
|
publicHelp: "Anyone can view your profile and your public content. Follows auto-accept.",
|
|
private: "Private (locked)",
|
|
privateHelp: "Visitors see a stub with a Request-to-follow button. Only accepted followers see your public content. You manage requests in the Requests tab on /notifications.",
|
|
},
|
|
},
|
|
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}})",
|
|
errors: {
|
|
too_many_tokens:
|
|
"This provider has too many active authorizations for your account. Open the provider's app, revoke the trails.cool authorization there, then try connecting again.",
|
|
sync_failed: "Couldn't connect — the provider rejected the request. Please try again.",
|
|
generic: "Couldn't connect — the provider rejected the request. Please try again.",
|
|
},
|
|
},
|
|
},
|
|
komoot: {
|
|
title: "Komoot",
|
|
publicMode: "Public tours only",
|
|
authenticatedMode: "All tours",
|
|
publicSection: "Connect with Komoot bio verification",
|
|
publicInstructions:
|
|
'Add your trails.cool profile link to your Komoot bio ("Über dich"), then click Verify.',
|
|
profileUrlLabel: "Komoot profile URL or user ID",
|
|
profileUrlPlaceholder: "https://www.komoot.com/user/...",
|
|
verifyButton: "Verify",
|
|
verifying: "Verifying…",
|
|
verifyPending:
|
|
"Allow a few minutes for changes to your Komoot bio to propagate before verifying.",
|
|
verifySuccess: "Komoot account connected in public mode.",
|
|
verificationError:
|
|
"Could not verify ownership. Make sure your trails.cool profile link is in your Komoot bio and try again in a few minutes.",
|
|
invalidUrl: "Please enter a valid Komoot profile URL or user ID.",
|
|
authenticatedSection: "Connect with email & password",
|
|
emailLabel: "Komoot email",
|
|
passwordLabel: "Komoot password",
|
|
connectButton: "Connect",
|
|
connecting: "Connecting…",
|
|
connectSuccess: "Komoot account connected.",
|
|
authError: "Invalid Komoot credentials. Please check your email and password.",
|
|
modeBadge: "Mode: {{mode}}",
|
|
import: {
|
|
noImportYet: "No import has been run yet. Click the button below to import all your Komoot tours.",
|
|
startImport: "Import all tours",
|
|
starting: "Starting…",
|
|
runAgain: "Run again",
|
|
found: "Found",
|
|
imported: "Imported",
|
|
skipped: "Already imported",
|
|
completedIn: "Completed in {{duration}}",
|
|
viewActivities: "View your activities",
|
|
status: {
|
|
pending: "Queued",
|
|
running: "Importing…",
|
|
completed: "Completed",
|
|
failed: "Failed",
|
|
},
|
|
},
|
|
},
|
|
sync: {
|
|
garmin: {
|
|
title: "Import from Garmin",
|
|
subtitle:
|
|
"Garmin delivers activities to trails.cool as they happen. To pull in your history, request a date range below — Garmin sends those activities over asynchronously.",
|
|
notConnected: "Your Garmin account isn't connected yet.",
|
|
goConnect: "Connect Garmin in settings",
|
|
needsRelink: "Your Garmin connection needs to be re-linked before requesting imports.",
|
|
from: "From",
|
|
to: "To",
|
|
request: "Request import",
|
|
requesting: "Requesting…",
|
|
requested: "Requested! Activities will appear as Garmin delivers them.",
|
|
asyncNote:
|
|
"Garmin processes history requests on their side — large ranges can take a while to arrive. Re-requesting an overlapping range is safe; nothing gets imported twice.",
|
|
importedSince_one: "{{count}} activity imported since this request",
|
|
importedSince_other: "{{count}} activities imported since this request",
|
|
errors: {
|
|
not_connected: "Your Garmin account isn't connected.",
|
|
needs_relink: "Your Garmin connection needs to be re-linked first.",
|
|
invalid_range: "Pick a valid date range in the past (start before end).",
|
|
request_failed: "Garmin rejected the request — try again in a few minutes.",
|
|
},
|
|
},
|
|
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",
|
|
explore: "Explore",
|
|
login: "Sign In",
|
|
register: "Register",
|
|
profile: "Profile",
|
|
settings: "Settings",
|
|
logout: "Log Out",
|
|
openMenu: "Open menu",
|
|
closeMenu: "Close menu",
|
|
},
|
|
explore: {
|
|
heading: "Explore",
|
|
empty: "Nobody on this instance has a public profile yet.",
|
|
activeRecently: {
|
|
heading: "Active recently",
|
|
},
|
|
directory: {
|
|
heading: "Everyone",
|
|
},
|
|
},
|
|
alpha: {
|
|
message: "trails.cool is in early development — your data may be reset.",
|
|
},
|
|
footer: {
|
|
imprint: "Imprint",
|
|
privacy: "Privacy",
|
|
terms: "Terms",
|
|
source: "Source Code",
|
|
alpha: "Alpha version",
|
|
},
|
|
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.",
|
|
codeHelp: "Or enter the 6-digit code from the email:",
|
|
verifyCode: "Verify Code",
|
|
termsBefore: "I have read and accept the ",
|
|
termsLink: "Terms of Service",
|
|
termsAfter: ".",
|
|
termsRequired: "You must accept the Terms of Service to register.",
|
|
noAccount: "Don't have an account?",
|
|
alreadyHaveAccount: "Already have an account?",
|
|
handleWillBe: "Your handle will be {{handle}}",
|
|
passkeyNotFound: "No passkey found for this site. Register a new account or use a magic link instead.",
|
|
reaccept: {
|
|
heading: "Updated Terms of Service",
|
|
bodyUpdated: "The Terms of Service have been updated (from version {{from}} to {{to}}). Please review and accept to continue using trails.cool.",
|
|
bodyNew: "We now record which version of the Terms of Service you've accepted. Please review the current version ({{version}}) and accept to continue using trails.cool.",
|
|
submit: "Accept and continue",
|
|
logoutInstead: "Log out instead",
|
|
},
|
|
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",
|
|
},
|
|
},
|
|
mobile: {
|
|
routes: {
|
|
empty: "No routes yet",
|
|
emptyHint: "Create your first route in the Planner",
|
|
retry: "Retry",
|
|
},
|
|
activities: {
|
|
empty: "No activities yet",
|
|
emptyHint: "Record or import your first activity",
|
|
},
|
|
profile: {
|
|
logOut: "Log Out",
|
|
switchServer: "Switch Server",
|
|
switchServerConfirm: "This will log you out and clear local data. Continue?",
|
|
},
|
|
login: {
|
|
subtitle: "Sign in to your Journal",
|
|
signIn: "Sign In",
|
|
connectDifferentServer: "Connect to a different server",
|
|
serverUrl: "Server URL",
|
|
},
|
|
},
|
|
} as const;
|