feat(train): Halkyon Train's shell, Todo's copied and renamed (ADR 0030, D12)
apps/train with halkyon_train_server, _client and _flutter, as Todo's:
halkyon_base configured by trainBase(), its own register alone and a
member of the instance's where the operator names one, the app on
halkyon_app's gates with Train's frame, account sheet and About, texts
in British English and German that speak of workouts, app.halkyon.train
on Android, iOS, Linux, macOS and Windows.
Where it differs from Todo: development ports of its own (8180 to 8190),
so it runs beside Learn's server; one initial migration with the schema
Todo's migrations end at (the same tables, compared line by line), not
Todo's seventeen; and Todo's icon as a placeholder until the icon tool
of ADR 0031 draws Train's bike. The workspace, the licences, the READMEs
and AGENTS.md name it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 10:26:49 +01:00
{
"@@locale": "de",
"appTitle": "Halkyon Train",
"launchProduct": "Train",
"instanceFirstStartSubtitle": "Wähle die Instanz, auf der deine Trainings liegen sollen. Jede betreibt jemand; weitere kannst du später hinzufügen.",
feat(train): the workouts listed, and each one's page with its map (ADR 0030, D22-D24)
Home lists the person's workouts newest first under their months, each
with its activity's icon, its name (else the time of day's and the
activity's), when it started, its distance, moving time and pace or
speed; those this device can't open come last, locked. A workout's page
shows its track on the instance's map source (flutter_map with
vector_map_tiles, pinned at 9.0.0-beta.13), in pieces between its
pauses, start and end marked; its totals with the elevation gained;
its splits per kilometre on foot, per 5 km cycling; pace or speed and
elevation over the distance, drawn by the app's own painter; and what
the map's source sees. Its name and notes are edited there; deleting
asks first and can be undone for a moment from home (halkyon_app's
DelayedDeletions, TrainPerson.deletions).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 14:29:39 +01:00
"homeEmptyTitle": "Noch keine Trainings",
"homeEmptyHint": "Trainings, die du auf deinem Telefon aufzeichnest, erscheinen hier.",
feat(train): Halkyon Train's shell, Todo's copied and renamed (ADR 0030, D12)
apps/train with halkyon_train_server, _client and _flutter, as Todo's:
halkyon_base configured by trainBase(), its own register alone and a
member of the instance's where the operator names one, the app on
halkyon_app's gates with Train's frame, account sheet and About, texts
in British English and German that speak of workouts, app.halkyon.train
on Android, iOS, Linux, macOS and Windows.
Where it differs from Todo: development ports of its own (8180 to 8190),
so it runs beside Learn's server; one initial migration with the schema
Todo's migrations end at (the same tables, compared line by line), not
Todo's seventeen; and Todo's icon as a placeholder until the icon tool
of ADR 0031 draws Train's bike. The workspace, the licences, the READMEs
and AGENTS.md name it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 10:26:49 +01:00
"accountTitle": "Konto",
"accountDeleteMessage": "Dein Konto wird auf dem Server und auf all deinen Geräten gelöscht. Dies kann nicht rückgängig gemacht werden.",
feat(train): recording a workout on Android (ADR 0030, D13, D16, D19, D21)
RecorderService, a foreground service of the types location and health
started from the open app, takes fixes from LocationManager's GPS and
steps from the step detector, pauses by itself (AutoPause, tested on the
JVM) and appends each sample to the person's recording file, flushed
every five seconds. MainActivity asks for location, notifications and,
for auto-pause on foot, physical activity, never background location
(D19), and bridges the service to the app.
The app follows the file's lines with RecordingBloc and shows the moving
time, the distance, the pace or speed and GPS's state; the notification
shows the time and the distance with Pause or Resume. Stop is held down;
a stopped recording is saved as a workout and its series, or discarded
after asking, and one cut off or left unsaved is offered as the app
opens. Home has the Record button where the device records.
Three choices of the implementation's are recorded under D21 for review:
rowing waits for 5f, auto-pause on foot without steps goes by GPS speed
(below 2 km/h, on above 3 km/h), and Stop's hint shows above the button.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 13:24:56 +01:00
"aboutTitle": "Über",
feat(train): the workouts listed, and each one's page with its map (ADR 0030, D22-D24)
Home lists the person's workouts newest first under their months, each
with its activity's icon, its name (else the time of day's and the
activity's), when it started, its distance, moving time and pace or
speed; those this device can't open come last, locked. A workout's page
shows its track on the instance's map source (flutter_map with
vector_map_tiles, pinned at 9.0.0-beta.13), in pieces between its
pauses, start and end marked; its totals with the elevation gained;
its splits per kilometre on foot, per 5 km cycling; pace or speed and
elevation over the distance, drawn by the app's own painter; and what
the map's source sees. Its name and notes are edited there; deleting
asks first and can be undone for a moment from home (halkyon_app's
DelayedDeletions, TrainPerson.deletions).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 14:29:39 +01:00
"homeRecordHint": "Zeichne eins mit dem Knopf unten auf.",
feat(train): recording a workout on Android (ADR 0030, D13, D16, D19, D21)
RecorderService, a foreground service of the types location and health
started from the open app, takes fixes from LocationManager's GPS and
steps from the step detector, pauses by itself (AutoPause, tested on the
JVM) and appends each sample to the person's recording file, flushed
every five seconds. MainActivity asks for location, notifications and,
for auto-pause on foot, physical activity, never background location
(D19), and bridges the service to the app.
The app follows the file's lines with RecordingBloc and shows the moving
time, the distance, the pace or speed and GPS's state; the notification
shows the time and the distance with Pause or Resume. Stop is held down;
a stopped recording is saved as a workout and its series, or discarded
after asking, and one cut off or left unsaved is offered as the app
opens. Home has the Record button where the device records.
Three choices of the implementation's are recorded under D21 for review:
rowing waits for 5f, auto-pause on foot without steps goes by GPS speed
(below 2 km/h, on above 3 km/h), and Stop's hint shows above the button.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 13:24:56 +01:00
"recordAction": "Aufzeichnen",
"recordBack": "Zurück zur Aufzeichnung",
"recordSheetTitle": "Training aufzeichnen",
"activityRunning": "Laufen",
"activityWalking": "Gehen",
"activityHiking": "Wandern",
"activityCycling": "Radfahren",
"activityIndoorRowing": "Rudern drinnen",
"recordAutoPause": "Von selbst pausieren",
"recordAutoPauseHint": "Wenn du stehst, und weiter, sobald du dich wieder bewegst",
"recordStart": "Start",
"recordLocationRefused": "Train braucht deinen Standort, um das aufzuzeichnen. Du kannst ihn in den Einstellungen des Systems erlauben.",
"recordingWaitingForGps": "Warte auf GPS",
"recordingWaitingForGpsAccuracy": "Warte auf GPS · ±{metres} m",
"recordingGpsAccuracy": "GPS ±{metres} m",
"recordingMovingTime": "Zeit in Bewegung",
"recordingDistance": "Strecke",
"recordingPace": "Tempo",
"recordingSpeed": "Geschwindigkeit",
"recordingDistanceValue": "{km} km",
"recordingPaceValue": "{pace} /km",
"recordingSpeedValue": "{kmh} km/h",
"recordingPausedAuto": "Pausiert: keine Bewegung",
"recordingPausedByHand": "Pausiert",
"recordingPause": "Pause",
"recordingResume": "Weiter",
"recordingStop": "Stopp",
"recordingHoldToStop": "Halte Stopp gedrückt, um das Training zu beenden",
"recordingStoppedTitle": "Dieses Training speichern?",
"recordingSave": "Speichern",
"recordingDiscard": "Verwerfen",
"recordingDiscardTitle": "Dieses Training verwerfen?",
"recordingDiscardMessage": "Seine Zeit und Strecke werden von diesem Gerät gelöscht. Dies kann nicht rückgängig gemacht werden.",
"recordingSaveFailed": "Es kann auf diesem Gerät nicht gespeichert werden, da es die Schlüssel deines Kontos nicht hat. Es bleibt hier, bis es gespeichert werden kann.",
"recordingCutOffTitle": "Eine Aufzeichnung wurde abgebrochen",
"recordingCutOffMessage": "Eine Aufzeichnung von {start} wurde abgebrochen. Bis {end} speichern oder verwerfen?",
"recordingNotificationChannel": "Aufzeichnung",
feat(train): the workouts listed, and each one's page with its map (ADR 0030, D22-D24)
Home lists the person's workouts newest first under their months, each
with its activity's icon, its name (else the time of day's and the
activity's), when it started, its distance, moving time and pace or
speed; those this device can't open come last, locked. A workout's page
shows its track on the instance's map source (flutter_map with
vector_map_tiles, pinned at 9.0.0-beta.13), in pieces between its
pauses, start and end marked; its totals with the elevation gained;
its splits per kilometre on foot, per 5 km cycling; pace or speed and
elevation over the distance, drawn by the app's own painter; and what
the map's source sees. Its name and notes are edited there; deleting
asks first and can be undone for a moment from home (halkyon_app's
DelayedDeletions, TrainPerson.deletions).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 14:29:39 +01:00
"recordingNotificationPaused": "{activity} · pausiert",
"workoutName": "{when, select, morning_running{Morgenlauf} morning_walking{Morgenspaziergang} morning_hiking{Morgenwanderung} morning_cycling{Morgenradfahrt} morning_indoorRowing{Rudern am Morgen} afternoon_running{Nachmittagslauf} afternoon_walking{Nachmittagsspaziergang} afternoon_hiking{Nachmittagswanderung} afternoon_cycling{Nachmittagsradfahrt} afternoon_indoorRowing{Rudern am Nachmittag} evening_running{Abendlauf} evening_walking{Abendspaziergang} evening_hiking{Abendwanderung} evening_cycling{Abendradfahrt} evening_indoorRowing{Rudern am Abend} night_running{Nachtlauf} night_walking{Nachtspaziergang} night_hiking{Nachtwanderung} night_cycling{Nachtradfahrt} night_indoorRowing{Rudern in der Nacht} other{Training}}",
"workoutLocked": "Gesperrtes Training",
"workoutLockedHint": "Dieses Gerät hat den Schlüssel nicht, mit dem es versiegelt ist.",
"workoutEdit": "Bearbeiten",
"workoutEditTitle": "Training bearbeiten",
"workoutNameLabel": "Name",
"workoutNotesLabel": "Notizen",
"workoutSave": "Speichern",
"workoutDelete": "Löschen",
"workoutDeleteTitle": "Dieses Training löschen?",
"workoutDeleteMessage": "Es wird auf all deinen Geräten gelöscht.",
"workoutDeleted": "Training gelöscht",
"workoutMovingTime": "Zeit in Bewegung",
"workoutTotalTime": "ganze Zeit",
"workoutDistance": "Strecke",
"workoutPace": "Tempo",
"workoutSpeed": "Geschwindigkeit",
"workoutClimb": "Aufstieg",
"workoutClimbValue": "{metres} m",
"workoutSplits": "Abschnitte",
"workoutSplitKm": "km {number}",
"workoutSplitFiveKm": "{from}– {to} km",
"workoutPaceChart": "Tempo",
"workoutSpeedChart": "Geschwindigkeit",
"workoutElevationChart": "Höhe",
"workoutMapSource": "Karte von {name}: sieht die Adresse deines Geräts und den gezeigten Ausschnitt, nicht deine Strecke.",
"workoutMapSourceAbout": "Was {name} speichert",
"workoutMapUnavailable": "Die Karte kann gerade nicht geladen werden.",
feat(train): the heart-rate strap, recorded by the service itself (ADR 0030, D25-D27)
The Record sheet gains a Heart rate row: a sheet looks for straps
advertising the Heart Rate Service, the nearest first, once nearby
devices are allowed, and the one chosen is remembered in the person's
folder; it records with every workout unless switched off for one.
The recorder service connects to it with Android's own Bluetooth API,
no package (D26), parses Heart Rate Measurement in Kotlin (tested on
the JVM), writes each rate and the strap's state to the recording
file, and asks for a lost strap again for as long as it records. The
recording screen shows the heart rate, and "Strap lost" while it is
gone; a workout's page shows the heart's average and highest rate,
each split's average and its chart.
iOS's recording waits for a Mac (D25), after the rower.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 15:50:36 +01:00
"workoutNotFound": "Dieses Training gibt es nicht mehr.",
"recordHeartRate": "Herzfrequenz",
"recordNoStrap": "Kein Brustgurt",
"strapSheetTitle": "Brustgurt",
"strapSearching": "Suche Brustgurte in der Nähe …",
"strapSearchingHint": "Leg den Gurt an: Die meisten wachen erst auf, wenn sie die Haut berühren.",
"strapNear": "ganz nah",
"strapFar": "weiter weg",
"strapUnnamed": "Brustgurt ohne Namen",
"strapForget": "Brustgurt vergessen",
"strapRefused": "Train braucht Geräte in der Nähe, um deinen Brustgurt zu finden. Du kannst das in den Systemeinstellungen erlauben.",
feat(train): rowing on the WP 5000 over FTMS (ADR 0030, D28)
Rowing indoors is offered again, with the rower chosen on the Record
sheet: a sheet looks for Fitness Machine Service rowers, and the one
chosen is remembered in the person's folder. The recorder service
connects to it as to the strap (one NotifyLink for both), parses
FTMS's Rower Data in Kotlin (tested on the JVM on frames written from
the specification and D8's), counts its totals from its first frame,
pauses 5 s after the last stroke, and gets the connectedDevice type. A
row's screen shows its metres, split per 500 m, stroke rate and watts;
its page its average split, stroke rate and power, the highest power,
its strokes, splits per 500 m and charts of the split, stroke rate and
power. Not yet tried on the WP 5000.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 16:20:37 +01:00
"strapBluetoothOff": "Bluetooth ist aus. Schalte es ein, um nach Geräten in der Nähe zu suchen.",
feat(train): the heart-rate strap, recorded by the service itself (ADR 0030, D25-D27)
The Record sheet gains a Heart rate row: a sheet looks for straps
advertising the Heart Rate Service, the nearest first, once nearby
devices are allowed, and the one chosen is remembered in the person's
folder; it records with every workout unless switched off for one.
The recorder service connects to it with Android's own Bluetooth API,
no package (D26), parses Heart Rate Measurement in Kotlin (tested on
the JVM), writes each rate and the strap's state to the recording
file, and asks for a lost strap again for as long as it records. The
recording screen shows the heart rate, and "Strap lost" while it is
gone; a workout's page shows the heart's average and highest rate,
each split's average and its chart.
iOS's recording waits for a Mac (D25), after the rower.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 15:50:36 +01:00
"recordingHeartRate": "Herzfrequenz",
"recordingStrapLost": "Brustgurt nicht verbunden",
"workoutAverageHeartRate": "mittlere Herzfrequenz",
"workoutMaxHeartRate": "höchste Herzfrequenz",
"workoutBpmValue": "{bpm} bpm",
feat(train): rowing on the WP 5000 over FTMS (ADR 0030, D28)
Rowing indoors is offered again, with the rower chosen on the Record
sheet: a sheet looks for Fitness Machine Service rowers, and the one
chosen is remembered in the person's folder. The recorder service
connects to it as to the strap (one NotifyLink for both), parses
FTMS's Rower Data in Kotlin (tested on the JVM on frames written from
the specification and D8's), counts its totals from its first frame,
pauses 5 s after the last stroke, and gets the connectedDevice type. A
row's screen shows its metres, split per 500 m, stroke rate and watts;
its page its average split, stroke rate and power, the highest power,
its strokes, splits per 500 m and charts of the split, stroke rate and
power. Not yet tried on the WP 5000.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 16:20:37 +01:00
"workoutHeartRateChart": "Herzfrequenz",
"recordRower": "Rudergerät",
"recordNoRower": "Wähle dein Rudergerät",
"recordRowerRefused": "Train braucht Geräte in der Nähe, um von deinem Rudergerät aufzuzeichnen. Du kannst das in den Systemeinstellungen erlauben.",
"rowerSheetTitle": "Rudergerät",
"rowerSearching": "Suche Rudergeräte in der Nähe …",
"rowerSearchingHint": "Weck die Konsole: Die meisten erscheinen, sobald du ziehst oder eine Taste drückst. Eines, das eine andere App hält (Christopeit Connect, Kinomap), ist nicht zu finden: Schließ diese App zuerst.",
"rowerUnnamed": "Rudergerät ohne Namen",
"rowerForget": "Rudergerät vergessen",
"rowerRefused": "Train braucht Geräte in der Nähe, um dein Rudergerät zu finden. Du kannst das in den Systemeinstellungen erlauben.",
"recordingRowerConnecting": "Suche das Rudergerät",
"recordingRowerLost": "Rudergerät nicht verbunden",
"recordingSplit": "Zeit pro 500 m",
"recordingStrokeRate": "Schläge pro Minute",
"recordingWatts": "Watt",
"workoutSplitValue": "{split} /500 m",
"workoutAverageSplit": "mittlere Zeit pro 500 m",
"workoutAverageStrokeRate": "mittlere Schlagzahl",
"workoutStrokeRateValue": "{rate} /min",
"workoutAveragePower": "mittlere Leistung",
"workoutMaxPower": "höchste Leistung",
"workoutWattsValue": "{watts} W",
"workoutStrokes": "Schläge",
"workoutSplitMetres": "{from}– {to} m",
"workoutSplitChart": "Zeit pro 500 m",
"workoutStrokeRateChart": "Schlagzahl",
"workoutPowerChart": "Leistung",
"recordAutoPauseRowingHint": "Wenn du aufhörst zu rudern, weiter mit dem nächsten Schlag",
feat(train): workouts written to Health Connect (ADR 0030, D31)
A Health Connect row in the account sheet opens its screen: Write my
workouts, off until turned on, Health Connect asking as it is. Then
every workout this phone holds is written there (its session with its
pauses and route, heart rate, speed and the rower's watts as samples,
distance and elevation gained), and written again or deleted as it
changes, here or through a sync, and as the app opens. Client IDs come
from the workout's ID, a version counts up with each change; what was
written is kept in the person's health_connect.json, never synced. A
permission taken back in Health Connect turns writing off and says so;
Health Connect's link to Train's rationale opens a screen of its own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 17:06:31 +01:00
"recordingMetres": "Meter",
"healthTitle": "Health Connect",
"healthHint": "Trainings mit anderen Apps auf diesem Telefon teilen",
"healthUnavailable": "Health Connect ist auf diesem Telefon nicht da. Ab Android 14 ist es eingebaut, davor eine eigene App.",
"healthNeedsUpdate": "Aktualisiere die App Health Connect, um sie mit Train zu nutzen.",
"healthWrite": "Meine Trainings schreiben",
"healthWriteHint": "Jedes Training auf diesem Telefon, auf dem neuesten Stand, wenn du es bearbeitest oder löschst",
feat(train): other apps' workouts read from Health Connect (ADR 0030, D31)
Read from other apps, off until turned on, asks for reading with the
history; the apps that wrote sessions are listed, each off. One turned
on brings its sessions, earlier ones at once and later ones through the
changes token as the app opens and comes to the front: each a workout
of Train's own store, sealed and synced, its origin in its payload, its
heart rate, pauses and a row's power as series, named by its app in the
list and on its page. A double of a workout Train has brings at most its
heart rate; one deleted in Train stays out; a track comes only when
asked for on the page, Health Connect asking for consent. What came from
Health Connect is never written back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 17:17:59 +01:00
"healthTakenBack": "Health Connect hat das zurückgenommen. Erlaube es dort, um es wieder einzuschalten.",
feat(train): workouts written to Health Connect (ADR 0030, D31)
A Health Connect row in the account sheet opens its screen: Write my
workouts, off until turned on, Health Connect asking as it is. Then
every workout this phone holds is written there (its session with its
pauses and route, heart rate, speed and the rower's watts as samples,
distance and elevation gained), and written again or deleted as it
changes, here or through a sync, and as the app opens. Client IDs come
from the workout's ID, a version counts up with each change; what was
written is kept in the person's health_connect.json, never synced. A
permission taken back in Health Connect turns writing off and says so;
Health Connect's link to Train's rationale opens a screen of its own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 17:06:31 +01:00
"healthRefused": "Health Connect hat es nicht erlaubt. Du kannst es in seinen Einstellungen erlauben.",
"healthOpenSettings": "Health Connect öffnen",
"healthWhy": "Warum Train fragt",
"healthRationaleTitle": "Train und Health Connect",
"healthRationaleWrite": "Train schreibt deine Trainings erst in Health Connect, wenn du es einschaltest: jedes mit Strecke, Herzfrequenz, Tempo, Leistung, Distanz und Anstieg, damit andere Apps auf diesem Telefon sie nutzen können. Bearbeitest oder löschst du ein Training in Train, geschieht das dort auch.",
"healthRationaleRead": "Train liest die Trainings anderer Apps erst, wenn du es einschaltest, und nur von den Apps, die du wählst: Ihre Herzfrequenz, Distanz und Leistung kommen als Trainings in Train, mit deinem Schlüssel versiegelt, bevor sie mit deiner Instanz abgeglichen werden, die sie nicht lesen kann.",
feat(train): other apps' workouts read from Health Connect (ADR 0030, D31)
Read from other apps, off until turned on, asks for reading with the
history; the apps that wrote sessions are listed, each off. One turned
on brings its sessions, earlier ones at once and later ones through the
changes token as the app opens and comes to the front: each a workout
of Train's own store, sealed and synced, its origin in its payload, its
heart rate, pauses and a row's power as series, named by its app in the
list and on its page. A double of a workout Train has brings at most its
heart rate; one deleted in Train stays out; a track comes only when
asked for on the page, Health Connect asking for consent. What came from
Health Connect is never written back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 17:17:59 +01:00
"healthRationaleNothingElse": "Was Train dort liest, wird dir gezeigt und niemandem sonst, und für nichts anderes genutzt. Schaltest du einen Schalter aus oder nimmst eine Erlaubnis in Health Connect zurück, hört es auf.",
"healthRead": "Von anderen Apps lesen",
"healthReadHint": "Ihre Trainings kommen in Train, von den Apps, die du unten wählst",
"healthApps": "Apps",
"healthAppsEmpty": "Noch keine App hat Trainings in Health Connect geschrieben.",
"workoutFromList": "von {app}",
"workoutFrom": "Von {app}, über Health Connect",
"workoutBringTrack": "Strecke holen",
feat(train): the body's figures in a sealed, synced profile (ADR 0030, D33, D34)
A person's profile, one row per person (its ID derived from theirs),
sealed like a workout: sex, birth date, height, weight, resting and
maximum heart rate, VO2max, training background, typical day and sleep
goal, each optional. "Your body" in the account sheet edits it; the
Loop's setup is to reuse its form. The migration only adds the synced
table `profile`, deleted with the person's sync space.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 18:02:04 +01:00
"workoutNoTrack": "Health Connect hat keine Strecke dazu gegeben.",
"profileTitle": "Dein Körper",
"profileHint": "Woraus dein Armband und deine Herzfrequenzzonen rechnen",
"profileIntro": "Jede Angabe ist freiwillig und mit deinem Schlüssel versiegelt, wie deine Trainings; deine Instanz kann sie nicht lesen.",
"profileLocked": "Dein Profil ist mit einem Schlüssel versiegelt, den dieses Gerät nicht hat.",
"profileSex": "Geschlecht",
"profileSexHint": "Wie Polars Formeln es nehmen: das, dem die Werte deines Körpers folgen",
"profileSexFemale": "Weiblich",
"profileSexMale": "Männlich",
"profileNotGiven": "Keine Angabe",
"profileBirthDate": "Geburtsdatum",
"profileHeight": "Größe",
"profileHeightUnit": "cm",
"profileWeight": "Gewicht",
"profileWeightUnit": "kg",
"profileRestingHeartRate": "Ruhepuls",
"profileMaxHeartRate": "Höchste Herzfrequenz",
"profileBpmUnit": "S/min",
"profileVo2Max": "VO2max",
"profileVo2MaxUnit": "ml/kg/min",
"profileTrainingBackground": "Trainingshintergrund",
"trainingOccasional": "Gelegentlich",
"trainingRegular": "Regelmäßig",
"trainingFrequent": "Häufig",
"trainingHeavy": "Intensiv",
"trainingSemiPro": "Halbprofi",
"trainingPro": "Profi",
"profileTypicalDay": "Typischer Tag",
"typicalDaySitting": "Meist sitzend",
"typicalDayStanding": "Meist stehend",
"typicalDayMoving": "Meist in Bewegung",
"profileSleepGoal": "Schlafziel",
"profileSave": "Speichern",
"profileSaved": "Gespeichert",
feat(train): setting up and keeping the Polar Loop (ADR 0030, D34–D36)
On Android, the Loop through Polar's BLE SDK 8.3.0 (from JitPack, asked
for Polar's group alone, its files pinned by SHA-256 in Gradle's
verification metadata): LoopBridge.kt over app.halkyon.train/loop, the
first-time use's figures mapped and checked in LoopSetup.kt, tested on
the JVM. PolarLoop per person remembers the band in loop.json, connects
while the app is open, sets its clock at each connection, keeps what it
tells (battery, charging, firmware), offers a changed profile and sends
it only when asked (D35: first-time use writes a new user identifier
each time), and lets the band go by a factory reset after asking. The
setup sheet finds Loops nearest first and asks only for what the
profile lacks; Polar's defaults (60, 220 less the age, a VO2max from
Polar's fitness tables) go to the band alone.
Polar's SDK is not free software (D36, correcting D32): the app's AGPL
gains a section 7 permission for linking it, LICENSE.md names it, and
its licence and bundled notices join the licence list on Android.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 18:58:02 +01:00
"profileInvalid": "Prüfe die markierten Angaben.",
"profileNeeded": "Braucht dein Band",
"loopTitle": "Polar Loop",
"loopHint": "Dein Band: Einrichtung, Akku und Uhrzeit",
"loopNone": "Train richtet einen Polar Loop ein und betreut ihn selbst, ohne Polar Flow und ohne Polar-Konto. Ein Band, das mit Polar Flow verbunden war, braucht zuerst einen Werksreset.",
"loopSetUp": "Loop einrichten",
"loopSetUpAgain": "Neu einrichten",
"loopLetGo": "Band freigeben",
"loopLetGoTitle": "Band freigeben?",
"loopLetGoText": "Das Band wird auf Werkseinstellungen zurückgesetzt, und was es hält und noch nicht bei Train angekommen ist, geht verloren. Danach kannst du es mit einem anderen Handy oder mit Polar Flow koppeln.",
"loopLetGoConfirm": "Band zurücksetzen",
"loopConnected": "Verbunden",
"loopLastSeen": "Zuletzt gesehen {when}",
"loopNotInReach": "Nicht in Reichweite",
"loopBattery": "Akku {level} %",
"loopCharging": "Akku {level} %, lädt",
"loopFirmware": "Firmware {version}",
"loopProfileChanged": "Dein Körper hat sich geändert, seit das Band eingerichtet wurde",
"loopProfileChangedHint": "Senden richtet das Band mit deinen jetzigen Angaben neu ein.",
"loopSend": "Ans Band senden",
"loopSent": "Ans Band gesendet.",
"loopFailed": "Das Band hat nicht geantwortet. Halte es nah und versuch es noch mal.",
"loopSearching": "Suche Loops in der Nähe",
"loopSearchingHint": "Halte das Band nah; tipp darauf, um es zu wecken.",
"loopRefused": "Ohne Geräte in der Nähe kann Train dein Band nicht suchen. Erlaube sie in den Android-Einstellungen.",
"loopUnnamed": "Polar Loop",
"loopSettingUp": "Richte das Band ein …",
"loopSettingUpHint": "Android fragt dich vielleicht, ob du es koppeln willst.",
"loopSetUpDone": "Das Band ist eingerichtet.",
"loopFormTitle": "Für dein Band",
"loopFormIntro": "Dein Band braucht diese Angaben. Sie bleiben in „Dein Körper“, mit deinem Schlüssel versiegelt. Für einen Ruhe- oder Maximalpuls oder eine VO2max, die du nicht angegeben hast, nimmt das Band Polars Standardwerte, und „Dein Körper“ bleibt, wie er ist.",
"loopFormSave": "Band einrichten"
feat(train): Halkyon Train's shell, Todo's copied and renamed (ADR 0030, D12)
apps/train with halkyon_train_server, _client and _flutter, as Todo's:
halkyon_base configured by trainBase(), its own register alone and a
member of the instance's where the operator names one, the app on
halkyon_app's gates with Train's frame, account sheet and About, texts
in British English and German that speak of workouts, app.halkyon.train
on Android, iOS, Linux, macOS and Windows.
Where it differs from Todo: development ports of its own (8180 to 8190),
so it runs beside Learn's server; one initial migration with the schema
Todo's migrations end at (the same tables, compared line by line), not
Todo's seventeen; and Todo's icon as a placeholder until the icon tool
of ADR 0031 draws Train's bike. The workspace, the licences, the READMEs
and AGENTS.md name it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 10:26:49 +01:00
}