diff --git a/AGENTS.md b/AGENTS.md index 51dc0ff..7d3cfcc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1642,14 +1642,23 @@ similar are internal endpoints/hook names, not credits — leave them.) chain) fails the build if any literal `t('…')` key is missing from `en` OR `es`, or if `en`/`es` drift. Dynamic template keys (`t(\`ns.${x}\`)`) are NOT checked — keep those few in sync by hand. -- **Coverage (2026-10-01, batch 1 done):** ~1,680 new keys (2,297 total) and ~65 - files wired — **Map (`mapUi`)**, **spots (`spotUi`)** incl. detail/create/edit/ - chat, **Marketplace/trades/offers/escrow/shipping (`marketUi`)**, and **Lab/ - `/become/*`/coaches/skaters (`labUi`)**. **Still to do (batch 2+):** Settings, - auth (LoginArea/dialogs), Onboarding, Events, Shops, Tours, Crews, DMs/group, - Stash, Newsletter, Community Stats, legal (About/FAQ/Privacy/License/Glossary), - Wallet/Mints, App Shop, Food, Bounties/leaderboards, Admin review. Untranslated - text falls back to English, so partial coverage degrades gracefully. +- **Coverage (2026-10-02, batches 1–2 done):** **~5,770 keys** (EN=ES) and ~180 + files wired. Namespaces: batch 1 — `mapUi`, `spotUi`, `marketUi`, `labUi`; + batch 2 — `nav` (header/More/burger labels) + `chromeUi` (footer, toolbar + widgets, spot-type labels), `placesUi` (events/shops/tours/food), `socialUi` + (crews/DMs/notifications/collectives), `settingsUi` (settings/auth/signup/ + onboarding/profile/legal), `walletUi` (wallet/Cashu, stash, mints, app shop, + newsletter, community stats, leaderboards, profile page). +- **Still to translate (batch 3):** `RouteDialog`/`StopDepartures`/`TripItineraryCard` + (routing UI), the Sasquatch panel/dialogs (`SasquatchGuide`, `SasquatchProDialog`, + `SasquatchActionCard`, `SasquatchAiStatusCard`), `AddToCollectionDialog` edge + copy, `SplashScreen`/`LazyMount`, and **shared data-module labels** that live + outside components (`SPOT_TYPE_LABELS`/`SPOT_CATEGORIES` in `src/lib/types.ts`, + `src/lib/skateTags.ts`, `src/lib/spotStatus.ts`, `src/lib/sortOptions.ts`). + **Dates & relative times** are still English (no localized date layer yet). +- ⚠️ A batch-2 agent dropped the `socialUi.` namespace prefix in ~36 files — the + `check:i18n` guard caught all 738 usages. **Always run `node scripts/check-i18n.mjs` + (it's in `npm test`) after wiring a file.** - ⚠️ **When wiring a file, keep `en.ts`/`es.ts` key-for-key in sync** and run `node scripts/check-i18n.mjs` before committing. diff --git a/src/components/AddToCalendar.tsx b/src/components/AddToCalendar.tsx index fc52a6f..1eaf391 100644 --- a/src/components/AddToCalendar.tsx +++ b/src/components/AddToCalendar.tsx @@ -12,6 +12,7 @@ import { type CalendarEventInput, } from '@/lib/calendar'; import { cn } from '@/lib/utils'; +import { useTranslation } from '@/contexts/language'; interface AddToCalendarProps { event: CalendarEventInput; @@ -25,6 +26,7 @@ interface AddToCalendarProps { * Offers a native .ics download (Apple/Outlook) and a Google Calendar link. */ export function AddToCalendar({ event, color = '#06b6d4', className }: AddToCalendarProps) { + const { t } = useTranslation(); return ( @@ -35,7 +37,7 @@ export function AddToCalendar({ event, color = '#06b6d4', className }: AddToCale style={{ borderColor: `${color}55`, color }} > - Add to Calendar + {t('placesUi.addToCalendar.add')} @@ -44,7 +46,7 @@ export function AddToCalendar({ event, color = '#06b6d4', className }: AddToCale className="cursor-pointer" > - Apple / Outlook (.ics) + {t('placesUi.addToCalendar.appleOutlook')} - Google Calendar + {t('placesUi.addToCalendar.google')} diff --git a/src/components/AddToCollectionDialog.tsx b/src/components/AddToCollectionDialog.tsx index 4570b9d..aec4644 100644 --- a/src/components/AddToCollectionDialog.tsx +++ b/src/components/AddToCollectionDialog.tsx @@ -12,6 +12,7 @@ import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Skeleton } from '@/components/ui/skeleton'; import { useToast } from '@/hooks/useToast'; +import { useTranslation } from '@/contexts/language'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useMySpotCollections, @@ -29,6 +30,7 @@ interface AddToCollectionDialogProps { } export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollectionDialogProps) { + const { t } = useTranslation(); const { user } = useCurrentUser(); const { data: collections, isLoading } = useMySpotCollections(); const { createCollection, isPending: isCreating } = useCreateSpotCollection(); @@ -45,8 +47,8 @@ export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollect const handleAddToCollection = async (collection: SpotCollection) => { if (collection.spotRefs.includes(spotRef)) { toast({ - title: 'Already saved', - description: `"${spot.title}" is already in "${collection.title}"`, + title: t('walletUi.addToCollection.alreadySaved'), + description: t('walletUi.addToCollection.alreadySavedDesc', { spot: spot.title, collection: collection.title }), }); return; } @@ -59,14 +61,14 @@ export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollect spotIdentifier: spot.identifier, }); toast({ - title: 'Spot saved!', - description: `Added "${spot.title}" to "${collection.title}"`, + title: t('walletUi.addToCollection.saved'), + description: t('walletUi.addToCollection.savedDesc', { spot: spot.title, collection: collection.title }), }); onOpenChange(false); } catch (error) { toast({ - title: 'Failed to save', - description: error instanceof Error ? error.message : 'Something went wrong', + title: t('walletUi.addToCollection.saveFailed'), + description: error instanceof Error ? error.message : t('walletUi.addToCollection.somethingWrong'), variant: 'destructive', }); } finally { @@ -85,8 +87,8 @@ export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollect spotRefs: [spotRef], // Add the current spot to the new collection }); toast({ - title: 'Collection created!', - description: `"${spot.title}" added to your new collection "${newTitle}"`, + title: t('walletUi.addToCollection.created'), + description: t('walletUi.addToCollection.createdDesc', { spot: spot.title, collection: newTitle }), }); setNewTitle(''); setNewDescription(''); @@ -94,8 +96,8 @@ export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollect onOpenChange(false); } catch (error) { toast({ - title: 'Failed to create collection', - description: error instanceof Error ? error.message : 'Something went wrong', + title: t('walletUi.addToCollection.createFailed'), + description: error instanceof Error ? error.message : t('walletUi.addToCollection.somethingWrong'), variant: 'destructive', }); } @@ -108,11 +110,11 @@ export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollect - Save to Collection + {t('walletUi.addToCollection.title')}
-

Please log in to save spots to collections

+

{t('walletUi.addToCollection.loginRequired')}

@@ -125,10 +127,10 @@ export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollect - Save to Collection + {t('walletUi.addToCollection.title')} - Save "{spot.title}" to one of your collections + {t('walletUi.addToCollection.desc', { spot: spot.title })} @@ -179,8 +181,8 @@ export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollect

- {collection.spotRefs.length} spot{collection.spotRefs.length !== 1 ? 's' : ''} - {isInCollection && ' · Already saved'} + {t('walletUi.addToCollection.spotCount', { count: collection.spotRefs.length })} + {isInCollection && ` · ${t('walletUi.addToCollection.alreadySavedTag')}`}

@@ -190,8 +192,8 @@ export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollect ) : !showNewForm ? (
-

You don't have any collections yet

-

Create your first one below!

+

{t('walletUi.addToCollection.noCollections')}

+

{t('walletUi.addToCollection.createFirst')}

) : null} @@ -199,7 +201,7 @@ export function AddToCollectionDialog({ open, onOpenChange, spot }: AddToCollect {showNewForm ? (
- +
- +