Skip to content

Beta#206

Draft
TheAngryRaven wants to merge 57 commits into
mainfrom
BETA
Draft

Beta#206
TheAngryRaven wants to merge 57 commits into
mainfrom
BETA

Conversation

@TheAngryRaven

Copy link
Copy Markdown
Owner

No description provided.

claude and others added 20 commits June 13, 2026 13:59
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
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 14, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

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

@supabase

supabase Bot commented Jun 14, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project tdxloldxzvnzdivdazzd because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown

Coverage Summary

Lines: 59.23% (5584/9427) · Statements: 58.33% · Functions: 56.15% · Branches: 53.79%

Per-file coverage
File Lines Functions Branches
src/components/map/positionArrowMarker.ts 0% 0% 0%
src/components/video-overlays/dataSourceResolver.ts 85.07% 71.42% 80.82%
src/components/video-overlays/overlayUtils.ts 100% 100% 100%
src/components/video-overlays/registry.ts 100% 100% 100%
src/components/video-overlays/sectorUtils.ts 94.73% 100% 84.37%
src/components/video-overlays/themes.ts 100% 100% 100%
src/components/video-overlays/types.ts 100% 100% 100%
src/hooks/use-mobile.tsx 0% 0% 100%
src/hooks/use-toast.ts 0% 0% 0%
src/hooks/useAuth.ts 100% 100% 100%
src/hooks/useDataLoader.ts 15.66% 18.18% 16%
src/hooks/useDocumentHead.ts 0% 0% 0%
src/hooks/useEngineManager.ts 0% 0% 0%
src/hooks/useFileManager.ts 0% 0% 0%
src/hooks/useFirmwareUpdate.ts 0% 0% 0%
src/hooks/useKartManager.ts 100% 100% 100%
src/hooks/useLapManagement.ts 0% 0% 0%
src/hooks/useLapOverlays.ts 0% 0% 0%
src/hooks/useLapSnapshots.ts 0% 0% 0%
src/hooks/useNoteManager.ts 0% 0% 0%
src/hooks/useOnlineStatus.ts 0% 0% 0%
src/hooks/usePlayback.ts 0% 0% 0%
src/hooks/useReferenceLap.ts 0% 0% 0%
src/hooks/useSessionData.ts 0% 0% 0%
src/hooks/useSessionMetadata.ts 0% 0% 0%
src/hooks/useSettings.ts 0% 0% 0%
src/hooks/useSetupManager.ts 0% 0% 100%
src/hooks/useStripePrices.ts 0% 0% 0%
src/hooks/useSubscription.ts 0% 0% 0%
src/hooks/useTemplateManager.ts 0% 0% 0%
src/hooks/useTrackEditorForm.ts 0% 0% 0%
src/hooks/useVehicleManager.ts 0% 0% 100%
src/hooks/useVideoSync.ts 0% 0% 0%
src/hooks/useWaybackImagery.ts 0% 0% 0%
src/integrations/lovable/index.ts 0% 0% 0%
src/lib/test/idb.ts 100% 100% 100%
src/lib/aimParser.ts 95.85% 100% 81.46%
src/lib/alfanoParser.ts 83.22% 100% 61.9%
src/lib/billing.ts 96.55% 100% 97.36%
src/lib/billingClient.ts 0% 0% 0%
src/lib/ble/test/mockBle.ts 96% 90% 50%
src/lib/ble/battery.ts 93.33% 100% 87.5%
src/lib/ble/connection.ts 0% 0% 0%
src/lib/ble/dfu/dfuPackage.ts 96.66% 100% 71.87%
src/lib/ble/dfu/dfuTypes.ts 100% 100% 100%
src/lib/ble/dfu/firmwareManifest.ts 96.92% 92.85% 93.18%
src/lib/ble/dfu/index.ts 100% 100% 100%
src/lib/ble/dfu/version.ts 96.77% 100% 83.33%
src/lib/ble/fileTransfer.ts 90.69% 95% 72.91%
src/lib/ble/firmwareCrc.ts 100% 100% 100%
src/lib/ble/firmwareUpload.ts 90.4% 87.5% 84.31%
src/lib/ble/format.ts 50% 100% 66.66%
src/lib/ble/index.ts 100% 100% 100%
src/lib/ble/internal.ts 100% 100% 50%
src/lib/ble/settings.ts 93.6% 100% 85.29%
src/lib/ble/trackSync.ts 89.69% 90.9% 70.96%
src/lib/ble/types.ts 100% 100% 100%
src/lib/bleDatalogger.ts 100% 100% 100%
src/lib/brakingZones.ts 97.14% 100% 86.11%
src/lib/browserCompat.ts 0% 0% 0%
src/lib/buildInfo.ts 100% 100% 100%
src/lib/canvas2d.ts 100% 100% 91.66%
src/lib/channels.ts 100% 100% 84.61%
src/lib/chartAxis.ts 98% 100% 82.92%
src/lib/chartColors.ts 100% 100% 100%
src/lib/chartUtils.ts 100% 100% 97.05%
src/lib/courseDetection.ts 97.16% 100% 80.23%
src/lib/courseSectors.ts 100% 100% 94.59%
src/lib/datalogParser.ts 83.56% 80% 81.81%
src/lib/db/index.ts 0% 0% 0%
src/lib/db/supabaseAdapter.ts 0% 0% 0%
src/lib/db/types.ts 100% 100% 100%
src/lib/dbUtils.ts 75.75% 80% 16.48%
src/lib/debugConsole.ts 57.74% 61.11% 47.72%
src/lib/deviceSettingsSchema.ts 93.33% 100% 96.42%
src/lib/deviceTrackSync.ts 100% 100% 100%
src/lib/doveParser.ts 89.6% 72.72% 77.27%
src/lib/dovexParser.ts 90.62% 100% 80%
src/lib/emailValidation.ts 100% 100% 100%
src/lib/engineStorage.ts 100% 75% 100%
src/lib/engineUtils.ts 100% 100% 91.66%
src/lib/fieldResolver.ts 100% 100% 83.33%
src/lib/fileBrowserTree.ts 98.87% 97.5% 88.88%
src/lib/fileLoadingState.ts 100% 100% 100%
src/lib/fileStorage.ts 82.6% 78.12% 72.22%
src/lib/garageEvents.ts 100% 100% 100%
src/lib/gforceCalculation.ts 100% 100% 97.22%
src/lib/ggDiagram.ts 100% 100% 94.73%
src/lib/gps/customGps.ts 100% 100% 82.05%
src/lib/gps/dovepWriter.ts 100% 100% 92%
src/lib/gps/gpsFix.ts 100% 100% 100%
src/lib/gps/index.ts 100% 100% 100%
src/lib/gps/observationSample.ts 100% 100% 100%
src/lib/gps/realtimeTimer.ts 90.07% 100% 76.04%
src/lib/gps/sessionGate.ts 100% 100% 100%
src/lib/graphPrefsStorage.ts 100% 100% 100%
src/lib/i18n/config.ts 100% 100% 100%
src/lib/i18n/format.ts 100% 100% 85.71%
src/lib/i18n/pluginLocales.ts 0% 0% 100%
src/lib/i18n/seedUtils.ts 100% 100% 90.47%
src/lib/iracingParser.ts 91.93% 80% 76.47%
src/lib/kartStorage.ts 100% 75% 100%
src/lib/lapAlignment.ts 100% 80% 76.92%
src/lib/lapCalculation.ts 96.31% 100% 90.9%
src/lib/lapDelta.ts 99.2% 100% 85.07%
src/lib/lapOverlays.ts 100% 100% 86%
src/lib/lapSnapshot.ts 100% 100% 88.46%
src/lib/lapSnapshotStorage.ts 100% 83.33% 100%
src/lib/logFileType.ts 100% 100% 100%
src/lib/mapMarker.ts 100% 100% 100%
src/lib/motecParser.ts 89.61% 81.48% 55.71%
src/lib/nmeaParser.ts 85.62% 92.85% 71.22%
src/lib/noteStorage.ts 100% 80% 100%
src/lib/overlayCanvasRenderer.ts 0% 0% 0%
src/lib/parserUtils.ts 100% 100% 98.52%
src/lib/pendingCheckout.ts 58.82% 25% 100%
src/lib/profanity.ts 100% 100% 75%
src/lib/referenceUtils.ts 100% 100% 91.11%
src/lib/satelliteImagery.ts 100% 100% 90%
src/lib/setupRevision.ts 100% 100% 94.11%
src/lib/setupRevisionStorage.ts 84.48% 78.26% 36.84%
src/lib/setupStatus.ts 100% 100% 100%
src/lib/setupStorage.ts 81.35% 58.62% 100%
src/lib/speedBounds.ts 94.28% 66.66% 87.17%
src/lib/speedEvents.ts 86.56% 100% 76%
src/lib/speedHeatmap.ts 100% 100% 100%
src/lib/submittedTracksStorage.ts 0% 0% 0%
src/lib/templateStorage.ts 92.79% 68.75% 100%
src/lib/trackStorage.ts 16.4% 28.3% 18.18%
src/lib/trackSubmission.ts 100% 100% 95.91%
src/lib/trackUtils.ts 100% 100% 100%
src/lib/ubxParser.ts 99% 100% 89.58%
src/lib/units.ts 100% 100% 100%
src/lib/utils.ts 100% 100% 100%
src/lib/vboParser.ts 90.66% 100% 71.59%
src/lib/vehicleStorage.ts 100% 75% 100%
src/lib/videoExport.ts 0% 0% 0%
src/lib/videoExportTarget.ts 100% 100% 84.61%
src/lib/videoFileStorage.ts 100% 76% 61.11%
src/lib/videoStorage.ts 100% 76.92% 77.77%
src/lib/weatherService.ts 23.8% 35.29% 25.89%
src/lib/xrk/xrkClient.ts 3.57% 0% 0%
src/lib/xrk/xrkConfig.ts 100% 100% 100%
src/lib/xrk/xrkImporter.ts 70% 75% 80%
src/lib/xrk/xrkMapping.ts 98.7% 100% 82.81%
src/lib/xrk/xrkResample.ts 100% 100% 90.9%
src/lib/xrk/xrkTypes.ts 100% 100% 100%
src/lib/xrk/xrkWorker.ts 0% 0% 0%
src/plugins/cloud-sync/accountDeletion.ts 100% 100% 100%
src/plugins/cloud-sync/accountExport.ts 0% 0% 0%
src/plugins/cloud-sync/activeUser.ts 100% 100% 100%
src/plugins/cloud-sync/autoSync.ts 0% 0% 0%
src/plugins/cloud-sync/cloudClient.ts 69.23% 42.85% 87.5%
src/plugins/cloud-sync/CloudLogsPanel.tsx 0% 0% 0%
src/plugins/cloud-sync/DataPrivacyPanel.tsx 0% 0% 0%
src/plugins/cloud-sync/exportManifest.ts 100% 100% 100%
src/plugins/cloud-sync/FileDeleteToggle.tsx 0% 0% 0%
src/plugins/cloud-sync/fileSync.ts 100% 100% 100%
src/plugins/cloud-sync/FileSyncToggle.tsx 0% 0% 0%
src/plugins/cloud-sync/index.ts 0% 0% 0%
src/plugins/cloud-sync/LapSnapshotsPanel.tsx 0% 0% 0%
src/plugins/cloud-sync/localUsage.ts 100% 100% 75%
src/plugins/cloud-sync/merge.ts 100% 100% 100%
src/plugins/cloud-sync/pendingSync.ts 100% 100% 100%
src/plugins/cloud-sync/profile.ts 100% 100% 100%
src/plugins/cloud-sync/setupRevisionTombstones.ts 100% 100% 83.33%
src/plugins/cloud-sync/snapshotSync.ts 97.22% 87.5% 75%
src/plugins/cloud-sync/snapshotTombstones.ts 100% 100% 100%
src/plugins/cloud-sync/StoragePanel.tsx 0% 0% 0%
src/plugins/cloud-sync/storageTypes.ts 100% 100% 100%
src/plugins/cloud-sync/storeAccessors.ts 100% 100% 90%
src/plugins/cloud-sync/syncEngine.ts 98.9% 95% 80%
src/plugins/cloud-sync/syncStores.ts 100% 100% 100%
src/plugins/fileSources.ts 0% 0% 100%
src/plugins/index.ts 0% 0% 0%
src/plugins/mounts.ts 71.42% 75% 100%
src/plugins/panels.ts 75% 83.33% 100%
src/plugins/PluginMount.tsx 0% 0% 0%
src/plugins/PluginPanelHost.tsx 0% 0% 0%
src/plugins/registry.ts 77.27% 50% 100%
src/plugins/storage.ts 90.32% 70.83% 66.66%
src/plugins/tools/datalogger/dataloggerSession.ts 89.06% 80% 84.37%
src/plugins/tools/datalogger/DataloggerTool.tsx 0% 0% 0%
src/plugins/tools/datalogger/useDatalogger.ts 0% 0% 0%
src/plugins/tools/i18n.ts 0% 0% 100%
src/plugins/tools/index.ts 0% 0% 100%
src/plugins/tools/seat-position/model.ts 100% 100% 60%
src/plugins/tools/seat-position/SeatDiagram.tsx 0% 0% 0%
src/plugins/tools/seat-position/SeatPositionTool.tsx 0% 0% 0%
src/plugins/tools/toolList.ts 0% 0% 100%
src/plugins/tools/ToolsLandingTile.tsx 0% 0% 0%
src/plugins/tools/ToolsPanel.tsx 0% 0% 0%
src/plugins/types.ts 100% 100% 100%
src/types/racing.ts 0% 0% 0%

Comment thread scripts/seed-translations.mjs
TheAngryRaven and others added 6 commits June 13, 2026 21:14
)

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.
TheAngryRaven and others added 30 commits June 13, 2026 22:13
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants