i18n(es): translate SEO titles & descriptions across 40 pages (seoUi)
This commit is contained in:
parent
94a6628faa
commit
ae02f51d20
43 changed files with 234 additions and 75 deletions
|
|
@ -6864,6 +6864,7 @@ walletUi: {
|
|||
membersLabel: 'Members',
|
||||
dismissReport: 'Dismiss report',
|
||||
reportedBy: 'reported by',
|
||||
completingLoginAmber: 'Completing login with Amber...',
|
||||
entityMembersHint: 'Add the Nostr accounts of your crew. Each member confirms their own spot with their key — until then they show as “pending”.',
|
||||
entityVerifiedHint: 'Membership is verified per member — nobody can be added to your crew without confirming from their own account.',
|
||||
entityInvalidPubkey: 'Enter a valid npub, nprofile, or 64-char hex pubkey.',
|
||||
|
|
@ -6882,6 +6883,83 @@ walletUi: {
|
|||
offlineViewDetails: 'View cached spot details',
|
||||
offlineKeepActing: 'Keep acting — posts, RSVPs, listings and messages are queued and send when you reconnect',
|
||||
},
|
||||
seoUi: {
|
||||
becomeBuilderTitle: 'Become a Builder - SkateSpots',
|
||||
becomeBuilderDesc: 'List your ramp, park and DIY building services — what you build, materials and scale.',
|
||||
tradesTitle: 'My Trades — SkateSpots',
|
||||
tradesDesc: 'Manage your marketplace trades, confirmations and reputation.',
|
||||
eventsTitle: 'Skate Events & Tours - SkateSpots',
|
||||
eventsDesc: 'Discover skateboarding events, competitions, tours, and sessions near you.',
|
||||
editShopDesc: 'Edit your skate shop.',
|
||||
createTourDesc: 'Organize skate tours - local hidden gem tours, national road trips, international adventures, or KOTR-style destruction competitions.',
|
||||
deckDesignerTitle: 'Deck Designer — SkateSpots DIY',
|
||||
deckDesignerDesc: 'Design a skateboard or longboard outline, then export a printable 1:1 template, SVG or DXF — concave, kicks, wheelbase and truck holes included.',
|
||||
createEventTitle: 'Create a Skate Event - SkateSpots',
|
||||
createEventDesc: 'Create a new skateboarding event for the community.',
|
||||
editTourDesc: 'Edit your skate tour — update stops, dates and details.',
|
||||
walletTitle: 'Wallet - SkateSpots',
|
||||
walletDesc: 'Connect your Lightning wallet to send zaps to skaters and spot creators.',
|
||||
becomePhotographerTitle: 'Become a Photographer - SkateSpots',
|
||||
becomePhotographerDesc: 'Create your skate photography profile — cameras, lenses, lighting and services.',
|
||||
newsletterTitle: 'Newsletter - SkateSpots',
|
||||
newsletterDesc: 'Weekly drops from the SkateSpots community. App updates, new spots, events and the people keeping skateboarding alive.',
|
||||
homeTitle: 'SkateSpots - Discover Skateboarding Locations Worldwide',
|
||||
zapLeaderboardTitle: 'Zap Leaderboards - SkateSpots',
|
||||
zapLeaderboardDesc: 'Top zapped skate spots and the community members supporting them.',
|
||||
adminReviewTitle: 'Review queue — SkateSpots',
|
||||
gearSwapTitle: 'Gear Swap - SkateSpots',
|
||||
gearSwapDesc: 'Buy & sell used skate gear with other skaters. Decks, trucks, wheels, shoes, and more.',
|
||||
donateTitle: 'Donate — SkateSpots',
|
||||
donateDesc: 'Support SkateSpots — Lightning, private on-chain (silent payments), or fund the build on Angor.',
|
||||
verifyCardTitle: 'Verify — SkateSpots',
|
||||
verifyCardDesc: 'Verify a SkateSpots card or access pass.',
|
||||
mapTitle: 'Skate Spots Map - SkateSpots',
|
||||
mapDesc: 'Explore skateboarding spots around the world on our interactive map.',
|
||||
diyTitle: 'DIY — Make Your Own | SkateSpots',
|
||||
diyDesc: 'Guides, open tools and plans to make your own skateboards, ramps and concrete spots — and the people and places to do it with.',
|
||||
appShopTitle: 'App Shop — SkateSpots',
|
||||
becomeSkaterTitle: 'Join the Skater Directory - SkateSpots',
|
||||
becomeSkaterDesc: 'Create your skater profile so the community can find you.',
|
||||
marketplaceTitle: 'Marketplace - SkateSpots',
|
||||
marketplaceDesc: 'Buy and sell skateboarding gear on the decentralized Plebeian Market.',
|
||||
becomeEditorTitle: 'Become a Video Editor - SkateSpots',
|
||||
becomeEditorDesc: 'Create your skateboarding video editor profile on SkateSpots.',
|
||||
amberCallbackTitle: 'Signing in with Amber - SkateSpots',
|
||||
amberCallbackDesc: 'Completing your Amber (NIP-55) login.',
|
||||
supportersTitle: 'Supporters - SkateSpots',
|
||||
supportersDesc: 'The community keeping SkateSpots alive — supporters, collaborators, partners and friends.',
|
||||
becomeCoachTitle: 'Become a Coach - SkateSpots',
|
||||
becomeCoachDesc: 'Create your skateboarding coach profile.',
|
||||
riderCardTitle: 'Skater Card — SkateSpots',
|
||||
riderCardDesc: 'Create your printable SkateSpots Skater License or Park Access Card.',
|
||||
editEventDesc: 'Edit your skateboarding event.',
|
||||
createShopTitle: 'Add a Skate Shop - SkateSpots',
|
||||
createShopDesc: 'Add your skate shop to the community.',
|
||||
deckCostTitle: 'Deck Cost Calculator — SkateSpots DIY',
|
||||
deckCostDesc: 'Work out what a deck costs to make — labour, equipment, materials, process time, packaging and margin — and a fair selling price.',
|
||||
pyramidTitle: 'Pyramid Rankings - SkateSpots',
|
||||
pyramidDesc: 'Top contributors and community leaders.',
|
||||
foodTitle: 'Food Near Spots - SkateSpots',
|
||||
foodDesc: 'Find restaurants, cafés, and food options near skateboarding spots.',
|
||||
createListingTitle: 'List Gear - SkateSpots',
|
||||
createListingDesc: 'List skateboarding gear for sale or find gear you want to buy.',
|
||||
becomeFilmerTitle: 'Become a Filmer - SkateSpots',
|
||||
becomeFilmerDesc: 'Create your skateboarding filming profile.',
|
||||
skatersTitle: 'Skaters - SkateSpots',
|
||||
skatersDesc: 'Discover skaters in the SkateSpots community. Browse by style, stance, level and location.',
|
||||
communityStatsTitle: 'Community Stats — SkateSpots',
|
||||
communityStatsDesc: 'Live community metrics for SkateSpots — spots, events, coaches, filmers, editors, tours and growth over time. Pulled directly from Nostr.',
|
||||
labTitle: 'The Lab - SkateSpots',
|
||||
labDesc: 'Find skateboarding coaches, filmers, photographers, and video editors.',
|
||||
stashTitle: 'My Stash - SkateSpots',
|
||||
stashDesc: 'Manage your private gear inventory. Track what you own, what you want to sell or trade.',
|
||||
bountyLeaderboardTitle: 'Map & Earn - SkateSpots',
|
||||
bountyLeaderboardDesc: 'Map skate spots and shops, earn zaps from the community. See the top contributors.',
|
||||
spotCollectionsTitle: 'My Spot Collections - SkateSpots',
|
||||
spotCollectionsDesc: 'Organize your favorite skate spots into personalized collections',
|
||||
mintsTitle: 'Cashu Mints — SkateSpots',
|
||||
mintsDesc: 'Browse Cashu mints, check their health, and add one to your wallet.',
|
||||
},
|
||||
statusUi: {
|
||||
quickStatus: 'Quick Status',
|
||||
skating: 'Skating',
|
||||
|
|
|
|||
|
|
@ -6864,6 +6864,7 @@ walletUi: {
|
|||
membersLabel: 'Miembros',
|
||||
dismissReport: 'Descartar reporte',
|
||||
reportedBy: 'reportado por',
|
||||
completingLoginAmber: 'Completando el inicio de sesión con Amber...',
|
||||
entityMembersHint: 'Añade las cuentas Nostr de tu crew. Cada miembro confirma su propio spot con su clave — hasta entonces aparecen como “pendientes”.',
|
||||
entityVerifiedHint: 'La membresía se verifica por miembro — nadie puede añadirse a tu crew sin confirmarlo desde su propia cuenta.',
|
||||
entityInvalidPubkey: 'Introduce un npub, nprofile o clave hex de 64 caracteres válidos.',
|
||||
|
|
@ -6882,6 +6883,83 @@ walletUi: {
|
|||
offlineViewDetails: 'Ver detalles de spots en caché',
|
||||
offlineKeepActing: 'Sigue actuando — publicaciones, RSVPs, anuncios y mensajes se ponen en cola y se envían al reconectar',
|
||||
},
|
||||
seoUi: {
|
||||
becomeBuilderTitle: 'Ser Constructor - SkateSpots',
|
||||
becomeBuilderDesc: 'Publica tus servicios de construcción de rampas, parques y DIY — qué construyes, materiales y escala.',
|
||||
tradesTitle: 'Mis Tratos — SkateSpots',
|
||||
tradesDesc: 'Gestiona tus tratos del marketplace, confirmaciones y reputación.',
|
||||
eventsTitle: 'Eventos y Rutas de Skate - SkateSpots',
|
||||
eventsDesc: 'Descubre eventos, competiciones, rutas y sesiones de skate cerca de ti.',
|
||||
editShopDesc: 'Edita tu tienda de skate.',
|
||||
createTourDesc: 'Organiza rutas de skate: rutas locales a spots ocultos, viajes nacionales, aventuras internacionales o competiciones de destrucción estilo KOTR.',
|
||||
deckDesignerTitle: 'Diseñador de Tablas — SkateSpots DIY',
|
||||
deckDesignerDesc: 'Diseña el contorno de una tabla de skate o longboard y exporta una plantilla imprimible 1:1, SVG o DXF — con concave, colas, distancia entre ejes y agujeros de ejes.',
|
||||
createEventTitle: 'Crear un Evento de Skate - SkateSpots',
|
||||
createEventDesc: 'Crea un nuevo evento de skate para la comunidad.',
|
||||
editTourDesc: 'Edita tu ruta de skate — actualiza paradas, fechas y detalles.',
|
||||
walletTitle: 'Cartera - SkateSpots',
|
||||
walletDesc: 'Conecta tu cartera Lightning para enviar zaps a skaters y creadores de spots.',
|
||||
becomePhotographerTitle: 'Ser Fotógrafo - SkateSpots',
|
||||
becomePhotographerDesc: 'Crea tu perfil de fotografía de skate — cámaras, objetivos, iluminación y servicios.',
|
||||
newsletterTitle: 'Boletín - SkateSpots',
|
||||
newsletterDesc: 'Entregas semanales de la comunidad SkateSpots. Novedades de la app, nuevos spots, eventos y las personas que mantienen vivo el skate.',
|
||||
homeTitle: 'SkateSpots - Descubre Lugares de Skate en Todo el Mundo',
|
||||
zapLeaderboardTitle: 'Clasificación de Zaps - SkateSpots',
|
||||
zapLeaderboardDesc: 'Los spots más zapeados y los miembros de la comunidad que los apoyan.',
|
||||
adminReviewTitle: 'Cola de revisión — SkateSpots',
|
||||
gearSwapTitle: 'Intercambio de Equipo - SkateSpots',
|
||||
gearSwapDesc: 'Compra y vende equipo de skate usado con otros skaters. Tablas, ejes, ruedas, zapatillas y más.',
|
||||
donateTitle: 'Donar — SkateSpots',
|
||||
donateDesc: 'Apoya a SkateSpots — Lightning, on-chain privado (silent payments) o financia el desarrollo en Angor.',
|
||||
verifyCardTitle: 'Verificar — SkateSpots',
|
||||
verifyCardDesc: 'Verifica un carné de SkateSpots o un pase de acceso.',
|
||||
mapTitle: 'Mapa de Spots de Skate - SkateSpots',
|
||||
mapDesc: 'Explora spots de skate de todo el mundo en nuestro mapa interactivo.',
|
||||
diyTitle: 'DIY — Hazlo Tú Mismo | SkateSpots',
|
||||
diyDesc: 'Guías, herramientas abiertas y planos para hacer tus propias tablas, rampas y spots de hormigón — y la gente y los lugares para hacerlo.',
|
||||
appShopTitle: 'Tienda de la App — SkateSpots',
|
||||
becomeSkaterTitle: 'Únete al Directorio de Skaters - SkateSpots',
|
||||
becomeSkaterDesc: 'Crea tu perfil de skater para que la comunidad te encuentre.',
|
||||
marketplaceTitle: 'Marketplace - SkateSpots',
|
||||
marketplaceDesc: 'Compra y vende equipo de skate en el mercado descentralizado Plebeian.',
|
||||
becomeEditorTitle: 'Ser Editor de Vídeo - SkateSpots',
|
||||
becomeEditorDesc: 'Crea tu perfil de editor de vídeo de skate en SkateSpots.',
|
||||
amberCallbackTitle: 'Iniciando sesión con Amber - SkateSpots',
|
||||
amberCallbackDesc: 'Completando tu inicio de sesión con Amber (NIP-55).',
|
||||
supportersTitle: 'Colaboradores - SkateSpots',
|
||||
supportersDesc: 'La comunidad que mantiene vivo SkateSpots — colaboradores, socios y amigos.',
|
||||
becomeCoachTitle: 'Ser Coach - SkateSpots',
|
||||
becomeCoachDesc: 'Crea tu perfil de coach de skate.',
|
||||
riderCardTitle: 'Carné de Skater — SkateSpots',
|
||||
riderCardDesc: 'Crea tu Licencia de Skater o Carné de Acceso a Parque imprimible de SkateSpots.',
|
||||
editEventDesc: 'Edita tu evento de skate.',
|
||||
createShopTitle: 'Añadir una Tienda de Skate - SkateSpots',
|
||||
createShopDesc: 'Añade tu tienda de skate a la comunidad.',
|
||||
deckCostTitle: 'Calculadora de Coste de Tablas — SkateSpots DIY',
|
||||
deckCostDesc: 'Calcula cuánto cuesta hacer una tabla — mano de obra, equipo, materiales, tiempo de proceso, embalaje y margen — y un precio de venta justo.',
|
||||
pyramidTitle: 'Clasificación Pirámide - SkateSpots',
|
||||
pyramidDesc: 'Principales contribuidores y líderes de la comunidad.',
|
||||
foodTitle: 'Comida Cerca de los Spots - SkateSpots',
|
||||
foodDesc: 'Encuentra restaurantes, cafeterías y opciones de comida cerca de los spots de skate.',
|
||||
createListingTitle: 'Publicar Equipo - SkateSpots',
|
||||
createListingDesc: 'Publica equipo de skate en venta o encuentra el equipo que quieres comprar.',
|
||||
becomeFilmerTitle: 'Ser Filmer - SkateSpots',
|
||||
becomeFilmerDesc: 'Crea tu perfil de filmación de skate.',
|
||||
skatersTitle: 'Skaters - SkateSpots',
|
||||
skatersDesc: 'Descubre skaters de la comunidad SkateSpots. Explora por estilo, postura, nivel y ubicación.',
|
||||
communityStatsTitle: 'Estadísticas de la Comunidad — SkateSpots',
|
||||
communityStatsDesc: 'Métricas en vivo de la comunidad SkateSpots — spots, eventos, coaches, filmers, editores, rutas y crecimiento. Directo desde Nostr.',
|
||||
labTitle: 'The Lab - SkateSpots',
|
||||
labDesc: 'Encuentra coaches, filmers, fotógrafos y editores de vídeo de skate.',
|
||||
stashTitle: 'Mi Stash - SkateSpots',
|
||||
stashDesc: 'Gestiona tu inventario privado de equipo. Controla lo que tienes, lo que quieres vender o intercambiar.',
|
||||
bountyLeaderboardTitle: 'Mapea y Gana - SkateSpots',
|
||||
bountyLeaderboardDesc: 'Mapea spots y tiendas de skate, gana zaps de la comunidad. Mira los principales contribuidores.',
|
||||
spotCollectionsTitle: 'Mis Colecciones de Spots - SkateSpots',
|
||||
spotCollectionsDesc: 'Organiza tus spots de skate favoritos en colecciones personalizadas',
|
||||
mintsTitle: 'Mints de Cashu — SkateSpots',
|
||||
mintsDesc: 'Explora mints de Cashu, revisa su estado y añade uno a tu cartera.',
|
||||
},
|
||||
statusUi: {
|
||||
quickStatus: 'Estado rápido',
|
||||
skating: 'Patinando',
|
||||
|
|
|
|||
|
|
@ -718,7 +718,7 @@ export default function AdminReviewPage() { const { t } = useTranslation();
|
|||
const { user } = useCurrentUser();
|
||||
const [kind, setKind] = useState<QueueKind>('reports');
|
||||
|
||||
useSeoMeta({ title: 'Review queue — SkateSpots' });
|
||||
useSeoMeta({ title: t('seoUi.adminReviewTitle') });
|
||||
|
||||
// Admins only. Everyone else sees a 404 rather than a hint that this exists.
|
||||
if (!isAdminPubkey(user?.pubkey)) return <NotFound />;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { useNavigate, Link } from 'react-router-dom';
|
|||
import { useSeoMeta } from '@unhead/react';
|
||||
import { useLoginActions } from '@/hooks/useLoginActions';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useTranslation } from '@/contexts/language';
|
||||
import {
|
||||
getAmberCallbackResult,
|
||||
getAmberPendingOperationAsync,
|
||||
|
|
@ -28,16 +29,17 @@ import { Button } from '@/components/ui/button';
|
|||
type Status = 'processing' | 'success' | 'error';
|
||||
|
||||
export default function AmberCallbackPage() {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const login = useLoginActions();
|
||||
const { toast } = useToast();
|
||||
const hasProcessed = useRef(false);
|
||||
const [status, setStatus] = useState<Status>('processing');
|
||||
const [message, setMessage] = useState('Completing login with Amber...');
|
||||
const [message, setMessage] = useState(t('miscUi.completingLoginAmber'));
|
||||
|
||||
useSeoMeta({
|
||||
title: 'Signing in with Amber - SkateSpots',
|
||||
description: 'Completing your Amber (NIP-55) login.',
|
||||
title: t('seoUi.amberCallbackTitle'),
|
||||
description: t('seoUi.amberCallbackDesc'),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ const PAY_CHIPS = [
|
|||
export default function AppShopPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'App Shop — SkateSpots',
|
||||
title: t('seoUi.appShopTitle'),
|
||||
description:
|
||||
'SkateSpots merch, paid in sats over Lightning or Cashu. Nothing in stock yet — here is what is coming.',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ function ChipGrid({
|
|||
export default function BecomeBuilderPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Become a Builder - SkateSpots',
|
||||
description: 'List your ramp, park and DIY building services — what you build, materials and scale.',
|
||||
title: t('seoUi.becomeBuilderTitle'),
|
||||
description: t('seoUi.becomeBuilderDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -102,8 +102,8 @@ function OptionChips({
|
|||
export default function BecomeCoachPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Become a Coach - SkateSpots',
|
||||
description: 'Create your skateboarding coach profile.',
|
||||
title: t('seoUi.becomeCoachTitle'),
|
||||
description: t('seoUi.becomeCoachDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ const SKILL_ENTRIES = Object.entries(EDITOR_SKILL_LABELS);
|
|||
export default function BecomeEditorPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Become a Video Editor - SkateSpots',
|
||||
description: 'Create your skateboarding video editor profile on SkateSpots.',
|
||||
title: t('seoUi.becomeEditorTitle'),
|
||||
description: t('seoUi.becomeEditorDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ const SKILL_ENTRIES = Object.entries(FILMING_SKILL_LABELS);
|
|||
export default function BecomeFilmerPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Become a Filmer - SkateSpots',
|
||||
description: 'Create your skateboarding filming profile.',
|
||||
title: t('seoUi.becomeFilmerTitle'),
|
||||
description: t('seoUi.becomeFilmerDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -103,8 +103,8 @@ function ChipGrid({
|
|||
export default function BecomePhotographerPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Become a Photographer - SkateSpots',
|
||||
description: 'Create your skate photography profile — cameras, lenses, lighting and services.',
|
||||
title: t('seoUi.becomePhotographerTitle'),
|
||||
description: t('seoUi.becomePhotographerDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ import { X, Loader2, ArrowLeft, MapPin, PersonStanding, Sparkles, UserRound, Shi
|
|||
export default function BecomeSkaterPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Join the Skater Directory - SkateSpots',
|
||||
description: 'Create your skater profile so the community can find you.',
|
||||
title: t('seoUi.becomeSkaterTitle'),
|
||||
description: t('seoUi.becomeSkaterDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -124,8 +124,8 @@ function LeaderboardSkeleton() {
|
|||
export default function BountyLeaderboardPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Map & Earn - SkateSpots',
|
||||
description: 'Map skate spots and shops, earn zaps from the community. See the top contributors.',
|
||||
title: t('seoUi.bountyLeaderboardTitle'),
|
||||
description: t('seoUi.bountyLeaderboardDesc'),
|
||||
});
|
||||
|
||||
const { user } = useCurrentUser();
|
||||
|
|
|
|||
|
|
@ -179,8 +179,8 @@ function ChartSkeleton() {
|
|||
export default function CommunityStatsPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Community Stats — SkateSpots',
|
||||
description: 'Live community metrics for SkateSpots — spots, events, coaches, filmers, editors, tours and growth over time. Pulled directly from Nostr.',
|
||||
title: t('seoUi.communityStatsTitle'),
|
||||
description: t('seoUi.communityStatsDesc'),
|
||||
});
|
||||
|
||||
const { data: stats, isLoading, isError, isFetching, refetch, dataUpdatedAt } = useGrowthStats();
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ export default function CreateEventPage() {
|
|||
const { t } = useTranslation();
|
||||
|
||||
useSeoMeta({
|
||||
title: 'Create a Skate Event - SkateSpots',
|
||||
description: 'Create a new skateboarding event for the community.',
|
||||
title: t('seoUi.createEventTitle'),
|
||||
description: t('seoUi.createEventDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ import { useTranslation } from '@/contexts/language';
|
|||
export default function CreateListingPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'List Gear - SkateSpots',
|
||||
description: 'List skateboarding gear for sale or find gear you want to buy.',
|
||||
title: t('seoUi.createListingTitle'),
|
||||
description: t('seoUi.createListingDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import { useTranslation } from '@/contexts/language';
|
|||
export default function CreateShopPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Add a Skate Shop - SkateSpots',
|
||||
description: 'Add your skate shop to the community.',
|
||||
title: t('seoUi.createShopTitle'),
|
||||
description: t('seoUi.createShopDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ export default function CreateTourPage({ existing }: { existing?: SkateTour } =
|
|||
|
||||
useSeoMeta({
|
||||
title: isEditing ? 'Edit Tour - SkateSpots' : 'Create a Tour - SkateSpots',
|
||||
description: 'Organize skate tours - local hidden gem tours, national road trips, international adventures, or KOTR-style destruction competitions.',
|
||||
description: t('seoUi.createTourDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ export default function DeckCostPage() {
|
|||
const { t } = useTranslation();
|
||||
|
||||
useSeoMeta({
|
||||
title: 'Deck Cost Calculator — SkateSpots DIY',
|
||||
description: 'Work out what a deck costs to make — labour, equipment, materials, process time, packaging and margin — and a fair selling price.',
|
||||
title: t('seoUi.deckCostTitle'),
|
||||
description: t('seoUi.deckCostDesc'),
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ export default function DeckDesignerPage() {
|
|||
const { user } = useCurrentUser();
|
||||
|
||||
useSeoMeta({
|
||||
title: 'Deck Designer — SkateSpots DIY',
|
||||
description: 'Design a skateboard or longboard outline, then export a printable 1:1 template, SVG or DXF — concave, kicks, wheelbase and truck holes included.',
|
||||
title: t('seoUi.deckDesignerTitle'),
|
||||
description: t('seoUi.deckDesignerDesc'),
|
||||
});
|
||||
|
||||
if (!isAdminPubkey(user?.pubkey)) return <Navigate to="/diy" replace />;
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ export default function DiyPage() {
|
|||
const { t } = useTranslation();
|
||||
|
||||
useSeoMeta({
|
||||
title: 'DIY — Make Your Own | SkateSpots',
|
||||
description: 'Guides, open tools and plans to make your own skateboards, ramps and concrete spots — and the people and places to do it with.',
|
||||
title: t('seoUi.diyTitle'),
|
||||
description: t('seoUi.diyDesc'),
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import { useTranslation } from '@/contexts/language';
|
|||
export default function DonatePage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Donate — SkateSpots',
|
||||
description: 'Support SkateSpots — Lightning, private on-chain (silent payments), or fund the build on Angor.',
|
||||
title: t('seoUi.donateTitle'),
|
||||
description: t('seoUi.donateDesc'),
|
||||
ogTitle: 'Support SkateSpots',
|
||||
ogDescription: 'Keep the map free, ad-free and open-source.',
|
||||
ogImage: 'https://skate-spots.org/images/icon-1024.png',
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ export default function EditEventPage() {
|
|||
|
||||
useSeoMeta({
|
||||
title: event ? `Edit ${event.title} - SkateSpots` : 'Edit Event - SkateSpots',
|
||||
description: 'Edit your skateboarding event.',
|
||||
description: t('seoUi.editEventDesc'),
|
||||
});
|
||||
|
||||
// Initialize form with existing data
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export default function EditShopPage() {
|
|||
|
||||
useSeoMeta({
|
||||
title: shop ? `Edit ${shop.name} - SkateSpots` : 'Edit Shop - SkateSpots',
|
||||
description: 'Edit your skate shop.',
|
||||
description: t('seoUi.editShopDesc'),
|
||||
});
|
||||
|
||||
// Initialize form with existing data
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export default function EditTourPage() {
|
|||
|
||||
useSeoMeta({
|
||||
title: tour?.title ? `Edit ${tour.title} - SkateSpots` : 'Edit Tour - SkateSpots',
|
||||
description: 'Edit your skate tour — update stops, dates and details.',
|
||||
description: t('seoUi.editTourDesc'),
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
|
|
|
|||
|
|
@ -814,8 +814,8 @@ export default function EventsPage() {
|
|||
const { t } = useTranslation();
|
||||
|
||||
useSeoMeta({
|
||||
title: 'Skate Events & Tours - SkateSpots',
|
||||
description: 'Discover skateboarding events, competitions, tours, and sessions near you.',
|
||||
title: t('seoUi.eventsTitle'),
|
||||
description: t('seoUi.eventsDesc'),
|
||||
});
|
||||
|
||||
const { user } = useCurrentUser();
|
||||
|
|
|
|||
|
|
@ -170,8 +170,8 @@ function FoodSpotSkeleton() {
|
|||
export default function FoodPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Food Near Spots - SkateSpots',
|
||||
description: 'Find restaurants, cafés, and food options near skateboarding spots.',
|
||||
title: t('seoUi.foodTitle'),
|
||||
description: t('seoUi.foodDesc'),
|
||||
});
|
||||
|
||||
const { data: spots, isLoading: spotsLoading } = useSkateSpots(50);
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ type TrustFilter = 'all' | 'verified' | 'trusted' | 'following';
|
|||
export default function GearSwapPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Gear Swap - SkateSpots',
|
||||
description: 'Buy & sell used skate gear with other skaters. Decks, trucks, wheels, shoes, and more.',
|
||||
title: t('seoUi.gearSwapTitle'),
|
||||
description: t('seoUi.gearSwapDesc'),
|
||||
});
|
||||
|
||||
const { user } = useCurrentUser();
|
||||
|
|
|
|||
|
|
@ -621,8 +621,9 @@ function Footer() {
|
|||
}
|
||||
|
||||
export default function Index() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'SkateSpots - Discover Skateboarding Locations Worldwide',
|
||||
title: t('seoUi.homeTitle'),
|
||||
description:
|
||||
'Find the best skateboarding spots, connect with fellow skaters, and discover events near you. Built on Nostr for true decentralization.',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1354,8 +1354,8 @@ export default function LabPage() {
|
|||
const { t } = useTranslation();
|
||||
|
||||
useSeoMeta({
|
||||
title: 'The Lab - SkateSpots',
|
||||
description: 'Find skateboarding coaches, filmers, photographers, and video editors.',
|
||||
title: t('seoUi.labTitle'),
|
||||
description: t('seoUi.labDesc'),
|
||||
});
|
||||
|
||||
const { user } = useCurrentUser();
|
||||
|
|
|
|||
|
|
@ -536,8 +536,8 @@ export default function MapPage() {
|
|||
const { t } = useTranslation();
|
||||
|
||||
useSeoMeta({
|
||||
title: 'Skate Spots Map - SkateSpots',
|
||||
description: 'Explore skateboarding spots around the world on our interactive map.',
|
||||
title: t('seoUi.mapTitle'),
|
||||
description: t('seoUi.mapDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import { useTranslation } from '@/contexts/language';
|
|||
export default function MarketplacePage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Marketplace - SkateSpots',
|
||||
description: 'Buy and sell skateboarding gear on the decentralized Plebeian Market.',
|
||||
title: t('seoUi.marketplaceTitle'),
|
||||
description: t('seoUi.marketplaceDesc'),
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -187,8 +187,8 @@ export default function MintsPage() {
|
|||
};
|
||||
|
||||
useSeoMeta({
|
||||
title: 'Cashu Mints — SkateSpots',
|
||||
description: 'Browse Cashu mints, check their health, and add one to your wallet.',
|
||||
title: t('seoUi.mintsTitle'),
|
||||
description: t('seoUi.mintsDesc'),
|
||||
});
|
||||
|
||||
const canAdd = isNativePlatform() && isInitialized && !!coco;
|
||||
|
|
|
|||
|
|
@ -629,8 +629,8 @@ function LiveIssuesSection() {
|
|||
export default function NewsletterPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Newsletter - SkateSpots',
|
||||
description: 'Weekly drops from the SkateSpots community. App updates, new spots, events and the people keeping skateboarding alive.',
|
||||
title: t('seoUi.newsletterTitle'),
|
||||
description: t('seoUi.newsletterDesc'),
|
||||
});
|
||||
|
||||
// Opening the newsletter clears the "News" unread badge in the bell — once
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ function ContributorRow({ pubkey, spots, events, rank }: { pubkey: string; spots
|
|||
export default function PyramidPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Pyramid Rankings - SkateSpots',
|
||||
description: 'Top contributors and community leaders.',
|
||||
title: t('seoUi.pyramidTitle'),
|
||||
description: t('seoUi.pyramidDesc'),
|
||||
});
|
||||
|
||||
const { user } = useCurrentUser();
|
||||
|
|
|
|||
|
|
@ -161,8 +161,8 @@ function BadgeEventRow({ event }: { event: NostrEvent }) {
|
|||
export default function RiderCardPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Skater Card — SkateSpots',
|
||||
description: 'Create your printable SkateSpots Skater License or Park Access Card.',
|
||||
title: t('seoUi.riderCardTitle'),
|
||||
description: t('seoUi.riderCardDesc'),
|
||||
});
|
||||
|
||||
const { user } = useCurrentUser();
|
||||
|
|
|
|||
|
|
@ -135,8 +135,8 @@ function SkaterCardSkeleton() {
|
|||
export default function SkatersPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Skaters - SkateSpots',
|
||||
description: 'Discover skaters in the SkateSpots community. Browse by style, stance, level and location.',
|
||||
title: t('seoUi.skatersTitle'),
|
||||
description: t('seoUi.skatersDesc'),
|
||||
});
|
||||
|
||||
const { data: skaters, isLoading } = useSkaters();
|
||||
|
|
|
|||
|
|
@ -149,8 +149,8 @@ export default function SpotCollectionsPage() {
|
|||
const [editDescription, setEditDescription] = useState('');
|
||||
|
||||
useSeoMeta({
|
||||
title: 'My Spot Collections - SkateSpots',
|
||||
description: 'Organize your favorite skate spots into personalized collections',
|
||||
title: t('seoUi.spotCollectionsTitle'),
|
||||
description: t('seoUi.spotCollectionsDesc'),
|
||||
});
|
||||
|
||||
const handleCreate = async (e: React.FormEvent) => {
|
||||
|
|
|
|||
|
|
@ -650,8 +650,8 @@ function ListAtSpotDialog({ item, open, onOpenChange, onSelectSpot }: {
|
|||
export default function StashPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'My Stash - SkateSpots',
|
||||
description: 'Manage your private gear inventory. Track what you own, what you want to sell or trade.',
|
||||
title: t('seoUi.stashTitle'),
|
||||
description: t('seoUi.stashDesc'),
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -519,8 +519,8 @@ export default function SupportersPage() {
|
|||
: [];
|
||||
|
||||
useSeoMeta({
|
||||
title: 'Supporters - SkateSpots',
|
||||
description: 'The community keeping SkateSpots alive — supporters, collaborators, partners and friends.',
|
||||
title: t('seoUi.supportersTitle'),
|
||||
description: t('seoUi.supportersDesc'),
|
||||
ogTitle: 'Supporters — SkateSpots',
|
||||
ogDescription: 'Built by skaters, funded by skaters. Back the map on Angor or zap it.',
|
||||
ogImage: 'https://skate-spots.org/images/icon-1024.png',
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ export default function TradesPage() {
|
|||
const [revoking, setRevoking] = useState(false);
|
||||
|
||||
useSeoMeta({
|
||||
title: 'My Trades — SkateSpots',
|
||||
description: 'Manage your marketplace trades, confirmations and reputation.',
|
||||
title: t('seoUi.tradesTitle'),
|
||||
description: t('seoUi.tradesDesc'),
|
||||
});
|
||||
|
||||
const handleConfirmSale = async (
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export default function VerifyCardPage() {
|
|||
const { nostr } = useNostr();
|
||||
const parsed = parseNaddr(naddr);
|
||||
|
||||
useSeoMeta({ title: 'Verify — SkateSpots', description: 'Verify a SkateSpots card or access pass.' });
|
||||
useSeoMeta({ title: t('seoUi.verifyCardTitle'), description: t('seoUi.verifyCardDesc') });
|
||||
|
||||
const result = useQuery({
|
||||
queryKey: ['verify-card', naddr],
|
||||
|
|
|
|||
|
|
@ -236,8 +236,8 @@ function NotLoggedIn() {
|
|||
export default function WalletPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Wallet - SkateSpots',
|
||||
description: 'Connect your Lightning wallet to send zaps to skaters and spot creators.',
|
||||
title: t('seoUi.walletTitle'),
|
||||
description: t('seoUi.walletDesc'),
|
||||
});
|
||||
|
||||
const { user } = useCurrentUser();
|
||||
|
|
|
|||
|
|
@ -150,8 +150,8 @@ function RowsSkeleton() {
|
|||
export default function ZapLeaderboardPage() {
|
||||
const { t } = useTranslation();
|
||||
useSeoMeta({
|
||||
title: 'Zap Leaderboards - SkateSpots',
|
||||
description: 'Top zapped skate spots and the community members supporting them.',
|
||||
title: t('seoUi.zapLeaderboardTitle'),
|
||||
description: t('seoUi.zapLeaderboardDesc'),
|
||||
});
|
||||
|
||||
const [range, setRange] = useState<RangeKey>('month');
|
||||
|
|
|
|||
Loading…
Reference in a new issue