Beta#206
Draft
TheAngryRaven wants to merge 57 commits into
Draft
Conversation
Plan a clean, phased internationalization overhaul for the (currently English-only) app, targeting an international sim-racing/karting audience. Decisions captured: react-i18next as the engine (lazy vendor-i18n chunk, locale JSON precached by the SW for offline-first), a committed re-runnable LLM seeding script to machine-generate locales for later hand-tuning, and a phase-1 target set of es/fr/de/it/pt-BR/ja alongside English source. Documents the architecture (provider placement, language-as-setting, namespaced public/locales loading, Intl-based formatting, TS key safety), the ~3,100-string extraction strategy, pluralization/interpolation handling, the seeding pipeline, a per-surface phased rollout, testing, and risks. No runtime code ships in this PR; docs/plans only.
Introduce an internationalization system (i18next + react-i18next) and migrate the landing page and Settings panel as the reference surfaces. Engine & wiring: - src/lib/i18n: config (languages/namespaces + pure resolveInitialLanguage), index (init with English bundled as the zero-flash fallback + a lazy dynamic-import backend for other languages), format (Intl date/number/list), seedUtils (pure key-parity + placeholder-preservation checks). - Language is an AppSettings field (persisted), browser-detected on first run, bridged to i18n.changeLanguage from useSettings; <html lang> kept in sync. - I18nextProvider in App.tsx; i18n initialized before render in main.tsx. - Typed keys via src/types/i18next.d.ts so tsc -b catches missing/renamed keys. - vendor-i18n manualChunk; resolveJsonModule enabled. Languages: en (source of truth, bundled) + es/fr/de/it/pt-BR/ja, the latter machine-seeded (flagged _machine) and lazily loaded as SW-precached chunks — fully offline. New Language picker in Settings. Seeding: scripts/seed-translations.mjs (npm run i18n:seed) + motorsport glossary — re-runnable, only translates new/changed keys, never overwrites reviewed strings, validates placeholders. Maintainer tool only (never in the app or standard CI build). Tests: locale parity + placeholder preservation across all languages, config resolution, seedUtils, and Intl formatters. Lint/typecheck/test/build/coverage all green; i18n bootstrap module excluded from coverage like main.tsx. Docs: CLAUDE.md i18n section + map entries, README languages/credits/env, CHANGELOG, plan status. Legal pages stay English by design.
Cloudflare Workers Builds installs with bun --frozen-lockfile; the bun.lock was not regenerated when i18next/react-i18next were added, so the deploy failed with 'lockfile had changes, but lockfile is frozen'. Sync bun.lock (verified with bun install --frozen-lockfile).
The dual lockfile (package-lock.json + bun.lock) was the root cause of the deploy break: the Cloudflare deploy installs with `bun install --frozen-lockfile`, so an npm-only dependency change left bun.lock stale. Use Bun as the single package manager everywhere. - Delete package-lock.json; gitignore npm/yarn/pnpm lockfiles so a second lockfile can't drift again. bun.lock is now the sole source of truth. - CI: all five workflows (lint/typecheck/test/build/coverage) switch from setup-node + `npm ci` + `npm run` to oven-sh/setup-bun + `bun install --frozen-lockfile` + `bun run`. - package.json: helper scripts (coverage:badge/summary, i18n:seed) run via `bun` instead of `node`, so CI needs no Node toolchain. - Docs: README + CLAUDE.md commands use bun; both note the single-lockfile rule and that it's `bun run test`, not `bun test` (Bun's own runner). Verified: `bun install --frozen-lockfile` is clean and lint/typecheck/test/ build/coverage all pass under Bun.
…planning-34myab i18n / translation system: plan + Phase 0 (engine, landing & settings, 7 languages)
Migrate the lap-analysis control surface to i18next under a new `session` namespace, and ship all six languages for it: - Index.tsx — view tab bar (Simple/Pro/Lap Times/Labs/Coach/Tools), play/pause tooltip, lap dropdown, Garage/Overlay buttons, setup-indicator tooltips. - LapTable.tsx — column headers, Simple/Full + sector-sums toggles, Set Ref, and the Best/Optimal/Delta/Avg-lap-length summary (interpolated values). - LapSnapshotControls.tsx — dialog, save/load actions, toasts, and the overwrite confirm (interpolated lap time). - OverlaysMenu.tsx — three sections, per-lap labels, errors, nav. - SectorCropSelect.tsx — crop dropdown + sector options. Wiring: register `session` in config NAMESPACES, bundle en + type it (i18next.d.ts), so tsc -b gates key integrity. Unit symbols (S1/S2/S3, ft, m, Hz, mph/kph) and dynamic data (engine/file/sector names) stay literal. Languages: en source + es/fr/de/it/pt-BR/ja seeded (flagged _machine); the locale-parity test now covers session × 7 langs (placeholders preserved). Deferred to the next slice: RaceLineView map chrome, pro graphs, video. Docs: CLAUDE.md (migrated surfaces + namespace list), CHANGELOG, plan status. lint / typecheck / test / build / coverage all green under Bun.
i18n Phase 1: translate the core in-session UI (session namespace)
Extend the `session` namespace to the in-session map and pro GraphView, and ship all six languages for them: - RaceLineView + MiniMap — map style toggle, satellite imagery-date picker, speed-event + braking-zone legends, the overlay legend (collapse/align + pluralized "N overlays"), the session stats panel (lap time / avg speeds / Δ rows), weather + offline indicators, and the dropped-packet / rejected-row diagnostics (pluralized + reason breakdown). Canvas-drawn G-G labels redraw on language change (t in the draw effect deps). - GraphView — GraphViewPanel (Hide/Show Map), GraphPanel (Add Graph picker + Speed/Pace/Brake%/G-G source labels), SingleSeriesChart (Remove graph), GGDiagram (axis labels, cloud/axis toggles, Session/Reference), InfoBox (tabs, Data stats, vehicle summary + linking controls), and the simple-mode TelemetryChart legend. Channel ids/labels (from channels.ts), unit symbols, and the source-tagged G labels (Lat G (GPS) etc.) stay literal. Diagnostic codes (NaN, OOR, …) are kept verbatim across languages. The InfoBox SetupDetails table (tire/PSI labels) is deferred to the garage/SetupsTab phase to keep those labels consistent. New session sub-namespaces: map, stats, graphs, gg, infoBox (en source + es/fr/de/it/pt-BR/ja, flagged _machine). Plural keys (overlayCount, pktDropped, rowsRejected) ship _one/_other for every language; the locale-parity test covers them with placeholders preserved. Docs: CLAUDE.md, CHANGELOG, plan status. lint/typecheck/test/build/coverage all green under Bun.
…phs-video i18n Phase 2: translate the live analysis views (map + pro graphs)
Add a `video` namespace and migrate the synced video feature, with all six languages: - VideoPlayer — empty state, load/replace, mute, sync lock + frame step + set sync point, overlay lock, overlay-settings dialog, export button, out-of-range message. - VideoExportDialog — title, stored-video description, overlay bake-in warning (<Trans> with <strong>), quality/range selects, progress, Save to App/Device, and the info note. describeStoredVideo() now takes t. - OverlaySettingsPanel — add/remove chrome, data-source/theme/mode/opacity/color/ history/animation/pace/sector-color controls, plus overlay-type + theme display names mapped through t by stable id (registry/themes keep their English data defaults; translated at the UI boundary). - PaceOverlay / LapTimeOverlay — the text-bearing overlay widgets (SLOW/FAST, LAP TIME/DELTA/BEST), which therefore localize in exported video too. Left literal: channel/data-source labels (consistent with channels.ts staying literal), "—" null markers, and sector codes. The InfoBox setup-detail table is still deferred to the garage/SetupsTab phase. en source + es/fr/de/it/pt-BR/ja (flagged _machine); locale-parity test now covers the `video` namespace across all languages with placeholders preserved. Docs: CLAUDE.md, CHANGELOG, plan status. lint/typecheck/test/build/coverage all green under Bun; no dependency changes.
A throwaway scratch route at /gps-test (not linked from the app, lazy-loaded so its Leaflet weight stays off the initial bundle) to prove the browser Geolocation API can feed a lap-timing library when the phone is the logger. - High-accuracy, never-cached fixes: watchPosition with enableHighAccuracy: true (precise GNSS, not coarse network positioning) and maximumAge: 0 (every fix fresh — no stale cached position). - Leaflet map: live position marker, accuracy circle, and trail polyline, auto-centering until the user drags. - Shows every field the API exposes (lat/lon/accuracy/altitude/ altitudeAccuracy/heading/speed/timestamp) plus live permission state. - Derives what the API does not give us, in a pure, unit-tested helper (lib/gpsTestMetrics): sample rate in Hz (instant + rolling average from fix timestamps), and best-available speed/heading that fall back to point-to-point haversine/bearing math when the device reports null. - Captures samples into a GpsSample-shaped feed and downloads them as JSON for handing to the timing library. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
i18n Phase 3: translate the video player + overlay/export system
Open the `drawer` namespace and migrate the garage drawer's shell and its
Files + Vehicles surfaces, with all six languages:
- FileManagerDrawer — top tabs (Garage/Profile/Device), garage + device
sub-tab labels, disconnect/battery, and the Device empty/connect states.
- FilesTab — file browser chrome, the load/delete confirm banners (filename
kept in a styled span via <Trans>), storage usage, upload, video badge, the
cloud-row labels, and the download-failed toast.
- SessionBrowser — the Group-by filter labels + default empty text.
- VehiclesTab — list, delete confirm, and the add/edit form.
- EngineCombobox — combobox + the manage-engines dialog.
The pure `fileBrowserTree.computeBrowserView` gained an optional labels arg
({ allSessions, untagged }) defaulting to English, so the UI passes translated
values while the module and its unit tests stay i18n-free (the cloud-logs panel
keeps the defaults for now — it's a later phase). KartsTab is dead code (not
rendered anywhere) and was skipped.
en source + es/fr/de/it/pt-BR/ja (flagged _machine); locale-parity test now
covers `drawer` across all languages, including the <Trans> markup placeholders
in the confirm banners.
Docs: CLAUDE.md, CHANGELOG, plan status. lint/typecheck/test/build/coverage all
green under Bun; no dependency changes.
…files-vehicles i18n Phase 4 (garage 1/2): drawer shell + Files + Vehicles
Add a MountSlot.Landing extension point so plugins can contribute to the
home screen — the first off-session plugin surface. The landing page renders
a <PluginMount slot={Landing}> in its action-tile grid (inert when no plugin
targets it), and the first-party Tools plugin contributes a Tools tile there.
- mounts.ts: new MountSlot.Landing + empty LandingContext.
- LandingPage.tsx: render the Landing mount point in the tile grid (the only
core change).
- tools plugin: contribute a lazy ToolsLandingTile to MountSlot.Landing. The
tile opens the Tools surface in a half-screen right drawer (Garage-style
markup) and hosts PanelSlot.Tools sessionless — reads the OPTIONAL
session/settings contexts with null fallbacks (landing is outside those
providers), mirroring ProfileTab. In-session Tools tab is unchanged.
- toolList.ts: add a "Phone Datalogger" skeleton tool (blank stub). The real
GPS capture is prototyped at the standalone /gps-test route.
All new code stays lazy (own chunks), so nothing rides the initial bundle;
fully offline. Docs (CLAUDE.md, CHANGELOG.md) updated.
https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
Extend the `drawer` namespace to the garage's Setups + Notes surfaces, plus the shared setup-detail table, with all six languages: - SetupsTab — list, delete confirm, the add/edit form (vehicle/type selectors, the Tires/PSI/Width/Diameter sections + Single/Halves/Quarters mode toggles), and the revision-hash tooltip. Template-driven section/field names stay literal. - TemplateCreator — the vehicle-type builder (wheel config, tire toggle, section/field editor, validation messages). - NotesTab — the session setup/vehicle linker, the frozen-revision note, and the notes list/editor. - InfoBox SetupDetails — the read-only tire/PSI/diameter table deferred from Phase 2, now translated under `drawer.setupDetails` so its labels match SetupsTab. Tire position codes (FL/FR/RL/RR) stay literal across languages; descriptive words are translated. en source + es/fr/de/it/pt-BR/ja (flagged _machine); the locale-parity test now covers the expanded `drawer` namespace across all languages. KartsTab remains dead code (untouched). Docs: CLAUDE.md, CHANGELOG, plan status. lint/typecheck/test/build/coverage all green under Bun; no dependency changes.
First step toward the phone-as-datalogger: a professional, host-agnostic capture layer that mirrors how the physical DovesDataLogger reads its GPS, but emits a typed record instead of NMEA sentences. No lap-timing logic yet — data layer only. - gpsFix.ts: the pure GpsFix record — one normalized browser fix, the NMEA-sentence replacement. The browser gives no satellites/HDOP, so quality is a GpsFixQuality bucket classified from horizontal accuracy (the phone's HDOP analog); structurally-invalid coords force NoFix. deriveMotion() computes the cross-fix quantities the API withholds (dt, instant Hz, distance, best speed/course preferring the device value, falling back to haversine/bearing), and averageHz() gives a rolling-window rate. Reuses parserUtils (haversine/bearing/validateGpsCoords/normalizeHeading). - customGps.ts: the CustomGps source class — software analog of the logger's GPS reader. Drives watchPosition (high-accuracy, never-cached by default), geolocation is injectable for tests, owns the sequence counter + t=0 time origin + rolling-rate window + observation buffer, and emits GpsObservations (fix + motion + elapsedMs + averageHz). Normalized error codes, idempotent start/stop, post-stop callback guard, sub/unsub listeners. - index.ts barrel. - Hardened unit tests for both (32 cases): quality boundaries, coord validity, motion derivation incl. zero-gap/no-move/negative-speed/heading normalization, rolling Hz windowing, lifecycle (unsupported/idempotency/ stop-race), capture/origin/clear, and W3C error mapping with a fake Geolocation. CLAUDE.md updated. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
…setups-notes i18n Phase 4 (garage 2/3): Setups + Notes
Finish the garage drawer (Device sub-tabs) and translate the weather UI, with all six languages: - DeviceSettingsTab — chrome (loading/retry/empty/reset/cancel + toasts). The schema-driven setting labels stay sourced from deviceSettingsSchema.ts (data; unknown device keys still pass through as raw labels) — schema-level i18n is a deliberate follow-up. - FirmwareUpdateSection — version display, check-for-updates, the confirm dialog (battery checklist, beta note, version blurbs as whole sentences), the progress phase labels, and the complete/error dialogs. - DeviceTracksTab — the full track-sync manager: status loading view, course + track lists, Send/Get/Compare actions, the delete/resync confirms, the course-diff dialog, and ~12 toasts (interpolated names/errors, pluralized counts). - WeatherPanel + LocalWeatherDialog — new `weather` namespace (shared by the in-session panel and the landing-page METAR dialog): labels, search/GPS UI, error states, station info, and the density-altitude tuning notes. Unit symbols stay in lib/units.ts. New: `weather` namespace + `drawer.device`/`drawer.firmware`/`drawer.deviceTracks`. en source + es/fr/de/it/pt-BR/ja (flagged _machine); locale-parity test covers both across all languages (incl. plural keys). The whole garage drawer is now translated. Docs: CLAUDE.md, CHANGELOG, plan status. lint/typecheck/test/build/coverage all green under Bun; no dependency changes.
…weather i18n Phase 4 (garage 3/3): Device + weather
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
dovesdataviewer | 2aa26ac | Commit Preview URL Branch Preview URL |
Jun 14 2026, 02:57 PM |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Coverage SummaryLines: 59.23% (5584/9427) · Statements: 58.33% · Functions: 56.15% · Branches: 53.79% Per-file coverage
|
) Open the new `tracks` namespace and migrate the full track-management UI: the track/course editor + manager (TrackEditor, AddTrackDialog, AddCourseDialog, SectorListEditor, VisualEditor, TrackPromptDialog) and the community submission flow (SubmitTrackDialog). English is the source of truth; es/fr/de/it/pt-BR/ja are machine-seeded with placeholders, units, and sector labels preserved. Sector numbering labels (sectorLabels()), the pure courseSectors validation strings, and deviceSettingsSchema labels stay English data. Docs: CLAUDE.md migrated-surfaces + namespace list, CHANGELOG, plan status. Co-authored-by: Claude <noreply@anthropic.com>
Phase 1 of the phone-as-datalogger. Rough UI (tuned next phase), solid core. Capture/timing/format foundation (lib/gps, pure + heavily unit-tested): - observationSample: GpsObservation → core GpsSample bridge. - sessionGate: pure arm/auto-idle state machine — record above 5 mph, auto-end after 5 min stopped (caller passes the clock; deterministic). - realtimeTimer (RealtimeLapTimer): incremental engine that re-drives the app's batch timing fns (autoDetectCourse / calculateLaps / calculateOptimalLap / computePositionDelta) over a growing buffer to surface current/last/best/ optimal laps, the major-sector rollup, and a live position delta vs the best lap. Track/course/direction detection with waypoint fallback. - dovepWriter: serializes the session to ".dovep" (Dove-phone) — byte-compatible with .dovex so the existing parser reads it unchanged (content-based routing already matches). Carries only channels a phone can measure (timestamp,lat,lng,speed_mph,altitude_m,heading_deg,h_acc_m); omits the device-only sats/hdop/rpm/accel rather than faking them. Round-trip tested through parseDovexFile. Tool + UI: - DataloggerTool: live Leaflet map + readouts (speed, delta colored red when slower / green when faster, current/best/last/optimal/laps). Starts on open, records above 5 mph, red End → confirm dialog, auto-end after idle. - useDatalogger: thin browser glue (CustomGps + IndexedDB). Saves the .dovep log + FileMetadata on end so it reopens/processes like any upload. - Landing Tools panel is now FULL-SCREEN (was half-drawer) — tools need the room. - logFileType: ".dovep" → "Dovep" browser badge. Docs: README formats table, CLAUDE.md (lib/gps, Tools, .dovex/.dovep), CHANGELOG. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
Reworked the Datalogger tool per feedback to read like an actual lap timer: - Removed the live map — this is a heads-up timer, not a map view. - Delta to best lap is now the dominant field (large, red slower / green faster); dropped the recorded-points count. - Added a header toggle: "Datalogger" (live readout) and "Lap Times" (a list of completed laps with their MAJOR sector splits; fine-grained sectors stay in the full session viewer). - Renamed the tool "Phone Datalogger" → "Datalogger". Fix: ending a session with no recorded data left a stuck "saving" spinner behind a blurred screen. The ended overlay now resolves cleanly — saving / saved (with filename) / "no lap data recorded" — and every terminal state offers a "New session" action. useDatalogger gains reset() (fresh gate + timer + GPS buffer) and an explicit `saving` flag, and its GPS listener now reads the timer via a ref so reset can swap it. Exposes `laps` for the list. Docs: CLAUDE.md + CHANGELOG updated. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
The lucide `Square` icon rendered as an empty outlined square next to "End", which read like a missing/placeholder glyph. Fill it (`fill-current`) so it's a solid square — the conventional stop symbol. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
Open the new `plugins` namespace and migrate the entire cloud-sync user surface: the Profile-tab panels (Account/StoragePanel, LapSnapshotsPanel, CloudLogsPanel, DataPrivacyPanel), the per-file sync + delete toggles, and the two non-React modules (autoSync quota/offline notices, accountExport progress phases) via direct i18n.t. Panel titles become i18n keys: PluginPanelHost now resolves t(panel.title) at render (a literal non-key title falls through unchanged), so the host's error/loading chrome is translated as well. English is the source of truth; es/fr/de/it/pt-BR/ja machine-seeded with placeholders, <b> tags, and _one/_other plurals preserved. Brand/feature names (Cloud Sync, Google, ZIP) stay literal. Docs: CLAUDE.md migrated surfaces + namespace list, CHANGELOG, plan status. Co-authored-by: Claude <noreply@anthropic.com>
…plugin Translate the Tools tab (picker + tool catalog labels) and the kart seat-position visualizer (SeatPositionTool + SeatDiagram). Introduce a plugin-local i18n seam so a plugin that's destined for its own repo owns its strings: registerPluginLocale (lib/i18n/pluginLocales.ts) registers a plugin's namespace — English added eagerly via addResourceBundle, other languages lazy-imported from the plugin's own locales/ folder through the backend read hook (still offline-precached). The host backend consults the plugin registry before the src/locales path. Tools strings now live in src/plugins/tools/locales/<lng>.json (namespace tools), keys typed off the plugin's own en.json (useToolsT), with a plugin-local parity test. Nothing about Tools depends on the host locale files. en is the source; es/fr/de/it/pt-BR/ja machine-seeded with placeholders, <em> markup, and unit symbols preserved. Docs: CLAUDE.md (migrated surfaces, i18n map, plugin-local note), CHANGELOG, plan status.
i18n (Phase 6, slice 2): plugin-local translations for the Tools plugin
docs: note deferred cloud-sync plugin-local i18n retrofit
…ession Handles the remaining deep-dive items (translations deferred to a later pass). Perf — bound the per-fix recompute cost (realtimeTimer): - The two O(n) operations (full calculateLaps over the buffer + the position-delta search) now run at most every 200 ms of session time; the cheap O(lapCount) derive (current-lap elapsed, speed, best/last/optimal, major sectors) still runs every fix. At ~1 Hz phone GPS every fix already clears the gate so behavior is unchanged — it only caps cost if a higher-rate source (BLE GPS) is fed later. Added a dense-sampling test proving laps are still detected under the throttle. Cleanup — retire the throwaway prototype: - Remove pages/GpsTest.tsx, lib/gpsTestMetrics.ts(+test), and the /gps-test route. It was a scratch page that predated and is fully superseded by lib/gps/*. Testability — extract orchestration into a pure controller: - New DataloggerSession (datalogger/dataloggerSession.ts): the session lifecycle (gate → record → timer → persist) with every dependency injected (GPS source, timer, save fns), so it's unit-tested with a fake geolocation + fake persistence. useDatalogger is now a thin React adapter that subscribes to snapshots. - RealtimeLapTimer gains reset() (clear session, keep tracks) for new sessions. - 10 controller tests incl. the empty-end regression (no data → not stuck saving, nothing written), record→save, idempotent end, reset/re-arm, save-error, and auto-idle end. Net: coverage up (59.45% lines), 1638 tests green, build clean. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
Answers "does it still log without a track?" — yes, recording is gated only by speed (the session gate), independent of detection, so the .dovep always saves. Adds the explicit far-from-track UX: RealtimeLapTimer now tracks `nearKnownTrack` (within ~10 mi of any known track's start/finish, via findNearestTrack). When false, it stops attempting detection/waypoint timing and just keeps logging; the Datalogger live view then shows speed prominently + a note "Data being logged for post-race analysis. No track within ~10 mi — create one here later to get lap times." `null` until tracks load (no premature note). Reset clears it. Tests: null-until-loaded, far → flagged + no course + still logging, near → not flagged. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
Sitting still it was hard to tell GPS was working. The live view now runs as a plain digital speedometer during the `waiting` phase (and keeps the same treatment for the far-from-track log-only case), showing big live speed + a hint + a GPS accuracy/quality readout, or an "Acquiring GPS…" spinner before the first fix. Logging stays locked behind 5 mph — only the readout runs early. `latest` already streams every fix pre-arm, so this is a view-only change. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
The no-track speedometer now leads with "Speedometer mode — no tracks found nearby" above the speed, so it's clear why timing isn't shown, with the post-race-analysis note below. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
Bring this branch up to current BETA so the plugin-local i18n system it added
(lib/i18n/pluginLocales.ts + the tools namespace, registerToolsLocale/useToolsT,
src/plugins/tools/locales/*.json, already-translated ToolsPanel + seat-position)
becomes the base, then translate the new Datalogger surfaces on top — so this
drops in cleanly with no add/add conflicts.
- toolList: datalogger entry → nameKey/descriptionKey/badgeKey (BETA's ToolDef
shape).
- DataloggerTool + ToolsLandingTile: every user-facing string → useToolsT keys.
- tools/locales/en.json: new `landing` + `datalogger` key sets (English source).
- es/fr/de/it/pt-BR/ja: machine-style translations of the same keys, placeholders
({{n}}/{{accuracy}}/{{quality}}) + unit symbols (m, mph, ±, ·) preserved; the
plugin parity test (i18n.test.ts) stays green.
- Conflict resolution: tools/index.ts keeps both the Landing mount contribution
and registerToolsLocale().
https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
In speedometer-only mode (waiting to arm, or recording far from any known track) there's no timing, so the Lap Times tab is now hidden — only the speedometer shows. Restructured SpeedometerView so the speed is centered and dominant and the message (speedometer-mode title + hint + GPS readout) sits pinned to the bottom of the screen. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
On a non-installed mobile browser the panel let touch gestures scroll the landing page behind it — toggling the chrome bar, rubber-banding/snapping, and revealing the page footer. Fixes: - Portal the full-screen overlay to <body> so it's a top-level layer, not nested in the landing page's scroll/stacking context. - Lock body scroll while the panel is open (restore on close). - Size it to the dynamic viewport (h-[100dvh]) so the bottom-pinned message stays put as the chrome bar shows/hides; overscroll-none/-contain stop scroll chaining (incl. the lap-list scroll area). https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
…-screen map fix (#210) * fix(track-editor): make the start/finish line placeable on a new course After the sector-editor overhaul a brand-new course had no coordinates for its start/finish line, so it never rendered on the map and couldn't be created or dragged — it effectively sat at null-island. Drop the start/finish line into the center of the chosen map view: automatically once the venue is known (GPS-loaded session, or right after a location search / use-my-location), gated on 'no S/F yet' so it never clobbers a placed line. Add a reset button on the start/finish row (new-track flow) that re-drops it in the current view, so it can always be (re)placed and dragged into position like the other sector lines. Adds the tracks:sectors.resetStartFinish key across all locales. * fix(track-editor): smoother sector/back-button UX - Tapping the start/finish row on a new course drops the line at the current view center when none exists yet, so the user doesn't have to find the reset button first. - Remove the redundant secondary close (x) in the course editor and rename 'Back to Selection' to 'Back', hidden while editing a course (which has its own Back to the course list). 'Back' now steps back one level at a time without leaving the edited course open underneath, so reopening Manage no longer jumps back into the previously-edited course. - Rename the tracks:trackEditor.backToSelection key to .back across all locales. * fix(track-editor): load Leaflet CSS in the editor map (home-screen fix) The track editor map broke when opened from the landing-page track manager with no session loaded: scattered tiles, off-centre zoom, runaway width. Root cause: leaflet/dist/leaflet.css was only imported by the in-session maps (RaceLineView, MiniMap), which don't mount on the landing page. Without the stylesheet the map's panes/tiles lose position:absolute and fall back to document flow. Import leaflet/dist/leaflet.css in VisualEditor (the component that owns the editor map) so it's present whenever the editor renders, with or without a session — the same pattern RaceLineView and MiniMap already use. Drops the four speculative band-aid commits (deferred init, redraw timers, resize-observer rework, dialog min-w-0/overflow-x-hidden) that were chasing this symptom; none are needed once the CSS loads. --------- Co-authored-by: Claude <noreply@anthropic.com>
…ecording The speedometer-mode message only appeared once recording AND far from a track — but while stationary in Waiting mode the timer never ran, so nearKnownTrack stayed null and the message never showed. - RealtimeLapTimer.nearTrack(lat,lon): pure proximity probe (no recording). - DataloggerSession: evaluate proximity on every fix, surfacing nearKnownTrack in the snapshot during the waiting phase too. - DataloggerTool: show the "Speedometer mode — no tracks found nearby" title whenever far from a track, including while waiting. Tests for the probe + the waiting-phase proximity surfacing. https://claude.ai/code/session_017JrfA3dpTdF6fyuSzdFyPA
…mo-x7skdl Phone Datalogger tool (.dovep) + plugin landing-page surface
Add an 'auth' namespace and migrate the account pages — Login, Register, ForgotPassword, ResetPassword, and AuthCallback — to i18n: every visible string, toast/validation message, and useDocumentHead title/description. The age-confirmation line (with Terms/Privacy links) uses <Trans>. Brand name stays literal. Wire-up: 'auth' added to config NAMESPACES, bundled English in i18n/index.ts, and the typed resources in types/i18next.d.ts. en is the source; es/fr/de/it/ pt-BR/ja machine-seeded with placeholders/markup preserved (parity test green). Docs: CLAUDE.md (migrated surfaces + namespace list), CHANGELOG, plan status. Co-authored-by: Claude <noreply@anthropic.com>
On the BETA branch, source @theangryraven/eye-in-the-sky directly from the coach repo's BETA branch as a git optionalDependency instead of the published npm package, so beta builds always track the latest coach beta without cutting a tag/release per iteration. - package.json: optionalDependencies -> github:TheAngryRaven/DataViewer_coach#BETA (replaces @perchwerks/eye-in-the-sky ~0.4.1; the BETA package renamed to the @TheAngryRaven scope) - vite.config.ts: DEFAULT_PLUGIN_PACKAGES retargeted to the new package name so the external-plugins loader discovers and bundles it - bun.lock: re-pinned to the resolved BETA commit - src/plugins/README.md: document the BETA-only git-dep arrangement and the commit-SHA re-pin tradeoff; main stays on the published npm package The coach's new i18next/react-i18next peer deps are already satisfied by the host on BETA. Build, typecheck, and lint all pass.
Migrate the two landing-page content dialogs (AboutDialog, SupportedFilesDialog) to the existing 'landing' namespace (about.*, supportedFiles.*). Rich-text bodies use <Trans>; format names, file extensions and brand/library links (DovesDataLogger, libxrk) stay literal. The About feature list is an array via returnObjects. en is the source; es/fr/de/it/pt-BR/ja machine-seeded (merged into the existing landing.json files), with all markup/placeholders preserved (parity test green). Docs: CLAUDE.md, CHANGELOG, plan status. Co-authored-by: Claude <noreply@anthropic.com>
Add a prominent SUPER IMPORTANT callout documenting that BETA pulls the coach from the coach repo's BETA branch (git dep) while main stays on the published npm package, with the maintainer-requested product-cut dance (flip to tagged npm release -> test -> merge to main -> flip BETA back) and the bun.lock commit-SHA re-pin note.
…-cjkuh6 beta: pull AI coach from coach repo BETA branch (git dep)
#214) Migrate the last three landing-page dialogs into the 'landing' namespace. - Credits: only the chrome/intro is translated; the open-source library names and their GitHub links stay literal by design. - Contact: full form + toasts. Category VALUES stay English (the submitted/admin key); only their displayed labels are translated. - BrowserCompat: refactor lib/browserCompat.ts to return stable feature/status ids (typed unions) so the dialog translates them, keeping the lib i18n-free. en is the source; es/fr/de/it/pt-BR/ja merged into the existing landing.json files, markup/placeholders preserved (parity test green). Docs: CLAUDE.md, CHANGELOG, plan status. Co-authored-by: Claude <noreply@anthropic.com>
Migrate FileImport (the landing page's primary drop zone) into the 'landing' namespace (fileImport.*): heading, drag/drop prompt, the locally-processed format note (<Trans>, format list kept literal), the progress fallback, and the loaded/error lines. en is the source; es/fr/de/it/pt-BR/ja merged into the existing landing.json files (parity test green). With this the entire landing page is localized. Docs: CHANGELOG, plan status. Co-authored-by: Claude <noreply@anthropic.com>
…nned IPs Add an 'admin' namespace and migrate the admin panel shell (Admin.tsx: login gate, header, tab bar) and four tabs — Messages, Tracks, Tools, Banned IPs — including all toasts, form labels, placeholders and the duration select. The Messages contact-category badge is translated via an English-value->key map so the value stored/queried in the DB stays English. Wire-up: 'admin' added to config NAMESPACES, bundled English in i18n/index.ts, and typed resources in types/i18next.d.ts. en is the source; es/fr/de/it/pt-BR/ja machine-seeded (technical tokens — tracks.json, ZIP, field names, IP — kept literal). Parity test green. The Submissions and Courses tabs (the two largest) follow in a separate PR. Docs: CLAUDE.md, CHANGELOG, plan status.
Translate PricingCards (plans grid: tier cards, feature lists, interval toggle, CTAs, footnote) and PlanCheckout/PlanCheckoutSummary (storage-tier picker, billing switch, live price readout) into the auth namespace (pricing.* / planCheckout.*). Feature copy is sourced from the locale (returnObjects for the bullet lists); the footnote's bold spans use <Trans>. Storage sizes (50 MB, 10 GB…), currency from Stripe, and the billing tier logic stay literal/unchanged. en is the source; es/fr/de/it/pt-BR/ja merged into the existing auth.json files (parity test green). Docs: CHANGELOG.
i18n: translate the registration pricing section
i18n (Phase 8a): admin shell + Messages/Tracks/Tools/Banned IPs tabs
…function' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Finish the admin panel — the SubmissionsTab (filters, batch approve/deny, status badges, drawing apply, IP/date lines, bulk-upload summary) and CoursesTab (course form, sector/layout badges, length overrides, layouts overview map, all toasts) — in the admin namespace. DB-stored submission status uses an English-value->key map so the stored value stays English. Plural strings use i18next _one/_other, replicated across all languages. en is the source; es/fr/de/it/pt-BR/ja merged into the existing admin.json files (parity test green). With this every user-facing surface is translated — the i18n migration is complete (legal pages stay English by design). Docs: CLAUDE.md, CHANGELOG, plan status (marked COMPLETE).
…ons-courses i18n (Phase 8b): translate admin Submissions + Courses tabs
While stationary the tool shows a bare speedometer (logging only arms above 5 mph), which was indistinguishable from the genuine "no tracks found nearby" state. Surface the nearest known track's name in the waiting speedometer so it's clear the track list loaded and detection worked — you're just waiting to move. Adds RealtimeLapTimer.nearestTrackName + a nearbyTrackName field on TimingState, plumbs it through the session into the speedometer title, and a trackDetected string across all locales. Tests cover the timer probe and the waiting snapshot. https://claude.ai/code/session_014pk2etibihm7WSLPZSYc36
Force-refresh @theangryraven/eye-in-the-sky to BETA HEAD (a867b3f -> f8c6ff4). The new build imports formatDecimal/formatInteger/formatSignedDelta from the host's i18n format module, so add those locale-aware formatters (with tests) to keep the production build green. https://claude.ai/code/session_014pk2etibihm7WSLPZSYc36
…st-load-wwodsb Datalogger: confirm recognised track while parked + bump coach plugin to BETA HEAD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.