diff --git a/docs/operations.md b/docs/operations.md
index e79cc166b..f8d17317b 100644
--- a/docs/operations.md
+++ b/docs/operations.md
@@ -36,7 +36,7 @@ If Actions jobs fail within 2 to 5 seconds with no runner and no logs, the accou
## Frontend hosting on Vercel
-Vercel builds and serves the frontend from the Git repository. A push to `main` deploys both projects: `debate-navigator` to `https://debateowl.com` (the previous domain, `https://debate.pi-stack.org`, 301s there with the path and query kept; see `vercel.json`), and `debatelab-staging` to `https://debatelab-staging.vercel.app`. Any other branch waits for an explicit preview (see [Opt-in previews](#opt-in-previews)). For a staging-pinned preview on the tailnet, use `npm run dev:preview` (see [development.md](development.md#preview-on-the-tailnet)). The production canary runs after each successful Vercel `Production` deployment of `debate-navigator`.
+Vercel builds and serves the frontend from the Git repository. A push to `main` deploys both projects: `debate-navigator` to `https://debateowl.com` (the previous domain, `https://debate.pi-stack.org`, 301s there with the path and query kept; see `vercel.json`; `https://www.debateowl.com` redirects to the apex through the project's Domains setting, not `vercel.json`, also keeping the path and query), and `debatelab-staging` to `https://debatelab-staging.vercel.app`. Any other branch waits for an explicit preview (see [Opt-in previews](#opt-in-previews)). For a staging-pinned preview on the tailnet, use `npm run dev:preview` (see [development.md](development.md#preview-on-the-tailnet)). The production canary runs after each successful Vercel `Production` deployment of `debate-navigator`.
[`vercel.json`](../vercel.json) owns:
diff --git a/e2e/loading-performance.spec.ts b/e2e/loading-performance.spec.ts
index 101d46f38..74b12e432 100644
--- a/e2e/loading-performance.spec.ts
+++ b/e2e/loading-performance.spec.ts
@@ -87,7 +87,7 @@ test('landing CTA enters the app without replacing the document', async ({ page
await page.goto('/');
await page.evaluate(() => { document.documentElement.dataset.e2eDocument = 'original'; });
const initialDocumentRequests = documentRequests;
- await page.getByRole('link', { name: 'Start trial' }).first().click();
+ await page.getByRole('link', { name: 'Start free trial' }).first().click();
await expect(page).toHaveURL(/\/app$/);
expect(documentRequests).toBe(initialDocumentRequests);
diff --git a/index.html b/index.html
index 36584c3ad..45399ba7b 100644
--- a/index.html
+++ b/index.html
@@ -9,7 +9,7 @@
-
+
{site.product}
diff --git a/src/locales/en.json b/src/locales/en.json
index 5990080fd..b06a60c40 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -15,7 +15,7 @@
"features": "Features",
"pricing": "Pricing",
"howItWorks": "How it works",
- "startTrial": "Start trial",
+ "startTrial": "Start free trial",
"settings": "Settings",
"openMenu": "Open menu",
"closeMenu": "Close menu",
@@ -234,6 +234,7 @@
"loading": "Loading",
"error": "Error",
"logoAlt": "DebateOwl logo",
+ "homeLink": "DebateOwl home",
"skipToContent": "Skip to main content",
"or": "or",
"back": "Back",
@@ -895,7 +896,7 @@
"headline": "{{product}}: AI debate prep and practice",
"subheadline": "Prepare cases and practice rounds with AI.",
"trialBadge": "{{trialDays}}-day free trial",
- "cta": "Start trial",
+ "cta": "Start free trial",
"trustBullet1": "No credit card required",
"trustBullet2": "Cancel anytime",
"preview": {
@@ -1037,7 +1038,7 @@
},
"finalCta": {
"title": "Ready to build your next case?",
- "cta": "Launch DebateOwl"
+ "cta": "Start free trial"
},
"rateLimit": {
"title": "Too many requests"
@@ -2587,44 +2588,44 @@
},
"pageHead": {
"home": {
- "title": "{{brand}} | AI Debate Prep, Cases & Rebuttals",
- "description": "{{product}} is an AI debate prep and practice app for students and debaters: cases, rebuttals, evidence, coaching and timed rounds against an AI opponent."
+ "title": "{{product}}: AI debate prep and practice",
+ "description": "{{product}} helps students and debaters prepare cases, rebuttals and evidence with AI, then practice timed rounds against an AI opponent."
},
"terms": {
"title": "Terms of Service | {{brand}}",
- "description": "The terms for using {{brand}}: accounts, subscriptions and billing, acceptable use, AI-generated content, intellectual property, and liability."
+ "description": "The terms for using {{brand}}, covering accounts, subscriptions and billing, acceptable use, AI-generated content, intellectual property and liability."
},
"privacy": {
"title": "Privacy Policy | {{brand}}",
- "description": "How {{brand}} collects, uses, stores, and shares your information, how AI requests are processed, and the rights you have over your data."
+ "description": "How {{brand}} collects, uses, stores and shares your information, how it processes AI requests, and which rights you have over your data."
},
"sources": {
"title": "Sources | {{brand}}",
- "description": "The sources consulted during the research and development of {{brand}}, listed alphabetically by author surname or institutional name."
+ "description": "The books, articles and institutions consulted while researching and building {{brand}}, listed alphabetically by author or institution name."
},
"notFound": {
"title": "Page not found | {{brand}}",
"description": "This page does not exist on {{brand}}."
},
"tools": {
- "title": "Free Debate Tools: Timer, Motions, Flow Sheets | {{brand}}",
- "description": "Free debate tools that need no account: a format-aware round timer, a practice motion generator, printable flow sheets and a speech time calculator."
+ "title": "Free Debate Tools | {{brand}}",
+ "description": "Free debate tools that need no account: a round timer for every format, a practice motion generator, printable flow sheets and a speech time calculator."
},
"debateTimer": {
- "title": "Free Debate Timer for PF, LD, Policy, BP & World Schools | {{brand}}",
- "description": "A free debate timer with presets for Public Forum, LD, Policy, BP, World Schools and Asian Parliamentary: protected time, POI knocks and prep banks."
+ "title": "Free Debate Timer | {{brand}}",
+ "description": "Free debate timer with presets for Public Forum, LD, Policy, BP, World Schools and Asian Parliamentary, including protected time and POI knocks."
},
"motionGenerator": {
- "title": "Debate Motion Generator: 300 Practice Motions | {{brand}}",
- "description": "Draw a random debate motion, or three for a veto drill, from 300 original practice motions sorted by topic, difficulty and type. THW and Resolved wording."
+ "title": "Debate Motion Generator | {{brand}}",
+ "description": "Free debate motion generator that draws one random motion, or three for a veto drill, from 300 original practice motions sorted by topic and type."
},
"flowSheet": {
- "title": "Printable Debate Flow Sheet Generator | {{brand}}",
- "description": "Print a one-page debate flow sheet with a column for every speech in PF, LD, Policy, BP, World Schools or Asian Parliamentary, on A4 or Letter."
+ "title": "Printable Debate Flow Sheets | {{brand}}",
+ "description": "Free printable debate flow sheets with a column for every speech in PF, LD, Policy, BP, World Schools or Asian Parliamentary, on A4 or Letter."
},
"speechTimeCalculator": {
- "title": "Speech Time Calculator for Debate Speeches | {{brand}}",
- "description": "Paste a speech to see its word count, how long it takes to deliver at slow, average and fast pace, and which debate speech slots it fits. Runs in your browser."
+ "title": "Speech Time Calculator | {{brand}}",
+ "description": "Free speech time calculator that counts the words in a debate speech and shows how long it takes at a slow, average or fast pace."
}
},
"validation": {
diff --git a/src/locales/es.json b/src/locales/es.json
index 52580c016..570d75bc9 100644
--- a/src/locales/es.json
+++ b/src/locales/es.json
@@ -15,7 +15,7 @@
"features": "Funciones",
"pricing": "Precios",
"howItWorks": "Cómo funciona",
- "startTrial": "Prueba gratis",
+ "startTrial": "Comenzar prueba gratis",
"settings": "Ajustes",
"openMenu": "Abrir menú",
"closeMenu": "Cerrar menú",
@@ -234,6 +234,7 @@
"loading": "Cargando",
"error": "Error",
"logoAlt": "Logotipo de DebateOwl",
+ "homeLink": "Inicio de DebateOwl",
"skipToContent": "Saltar al contenido principal",
"or": "o",
"back": "Atrás",
@@ -895,7 +896,7 @@
"headline": "{{product}}: preparación y práctica de debate con IA",
"subheadline": "Prepara casos y practica rondas con IA.",
"trialBadge": "Prueba gratis de {{trialDays}} días",
- "cta": "Prueba gratis",
+ "cta": "Comenzar prueba gratis",
"trustBullet1": "Sin tarjeta de crédito",
"trustBullet2": "Cancela cuando quieras",
"preview": {
@@ -1037,7 +1038,7 @@
},
"finalCta": {
"title": "¿Listo para construir tu próximo caso?",
- "cta": "Lanzar DebateOwl"
+ "cta": "Comenzar prueba gratis"
},
"rateLimit": {
"title": "Demasiadas solicitudes"
@@ -2587,8 +2588,8 @@
},
"pageHead": {
"home": {
- "title": "{{product}} – Preparación y práctica de debate con IA para estudiantes",
- "description": "{{product}} es una app con IA para preparar y practicar debates: casos, refutaciones, evidencia, coaching y rondas cronometradas contra un oponente de IA."
+ "title": "{{product}}: preparación y práctica de debate con IA",
+ "description": "{{product}} ayuda a estudiantes y debatientes a preparar casos, refutaciones y evidencia con IA, y a practicar rondas cronometradas contra un oponente de IA."
},
"terms": {
"title": "Términos del servicio | {{brand}}",
@@ -2607,24 +2608,24 @@
"description": "Esta página no existe en {{brand}}."
},
"tools": {
- "title": "Herramientas de debate gratis: cronómetro, mociones, hojas de flujo | {{brand}}",
- "description": "Herramientas de debate gratis y sin cuenta: cronómetro por formato, generador de mociones, hojas de flujo imprimibles y calculadora de tiempo de discurso."
+ "title": "Herramientas de debate gratis | {{brand}}",
+ "description": "Gratis y sin cuenta: un cronómetro para cada formato, un generador de mociones, hojas de flujo imprimibles y una calculadora de tiempo de discurso."
},
"debateTimer": {
- "title": "Cronómetro de debate gratis para PF, LD, Policy, BP y World Schools | {{brand}}",
- "description": "Cronómetro de debate gratis con ajustes para PF, LD, Policy, BP, World Schools y Asian Parliamentary: tiempo protegido, avisos de POI y preparación."
+ "title": "Cronómetro de debate gratis | {{brand}}",
+ "description": "Cronómetro de debate gratis con ajustes para PF, LD, Policy, BP, World Schools y Asian Parliamentary, con tiempo protegido y avisos de POI."
},
"motionGenerator": {
- "title": "Generador de mociones de debate: 300 mociones de práctica | {{brand}}",
- "description": "Saca una moción de debate al azar, o tres para practicar el veto, de entre 300 mociones originales ordenadas por tema, dificultad y tipo."
+ "title": "Generador de mociones de debate | {{brand}}",
+ "description": "Generador gratis de mociones de debate que saca una moción al azar, o tres para practicar el veto, de 300 mociones originales por tema y tipo."
},
"flowSheet": {
- "title": "Generador de hojas de flujo de debate imprimibles | {{brand}}",
- "description": "Imprime una hoja de flujo de una página con una columna por discurso en PF, LD, Policy, BP, World Schools o Asian Parliamentary, en A4 o Carta."
+ "title": "Hojas de flujo de debate imprimibles | {{brand}}",
+ "description": "Hojas de flujo de debate gratis e imprimibles, con una columna por discurso en PF, LD, Policy, BP, World Schools o Asian Parliamentary, en A4 o Carta."
},
"speechTimeCalculator": {
- "title": "Calculadora de tiempo para discursos de debate | {{brand}}",
- "description": "Pega un discurso para ver cuántas palabras tiene, cuánto dura a ritmo lento, medio o rápido y en qué turnos de debate cabe. Funciona en tu navegador."
+ "title": "Calculadora de tiempo de discurso | {{brand}}",
+ "description": "Calculadora gratis que cuenta las palabras de un discurso de debate y muestra cuánto dura a ritmo lento, medio o rápido y en qué turnos cabe."
}
},
"validation": {
diff --git a/src/locales/hu.json b/src/locales/hu.json
index a8d74a64f..dd30fbab1 100644
--- a/src/locales/hu.json
+++ b/src/locales/hu.json
@@ -15,7 +15,7 @@
"features": "Funkciók",
"pricing": "Árak",
"howItWorks": "Hogyan működik",
- "startTrial": "Próba indítása",
+ "startTrial": "Ingyenes próba indítása",
"settings": "Beállítások",
"openMenu": "Menü megnyitása",
"closeMenu": "Menü bezárása",
@@ -234,6 +234,7 @@
"loading": "Betöltés",
"error": "Hiba",
"logoAlt": "DebateOwl logó",
+ "homeLink": "DebateOwl főoldal",
"skipToContent": "Ugrás a fő tartalomra",
"or": "vagy",
"back": "Vissza",
@@ -895,7 +896,7 @@
"headline": "{{product}}: MI-alapú vitafelkészítés és gyakorlás",
"subheadline": "Készíts eseteket és gyakorolj fordulókat MI-vel.",
"trialBadge": "{{trialDays}} napos ingyenes próba",
- "cta": "Próba indítása",
+ "cta": "Ingyenes próba indítása",
"trustBullet1": "Bankkártya nem szükséges",
"trustBullet2": "Bármikor lemondható",
"preview": {
@@ -1037,7 +1038,7 @@
},
"finalCta": {
"title": "Készen állsz a következő eseted felépítésére?",
- "cta": "DebateOwl indítása"
+ "cta": "Ingyenes próba indítása"
},
"rateLimit": {
"title": "Túl sok kérés"
@@ -2587,8 +2588,8 @@
},
"pageHead": {
"home": {
- "title": "{{product}} – MI-alapú vitafelkészülés és gyakorlás diákoknak",
- "description": "A {{product}} MI-alapú app vitára készülő diákoknak: esetépítés, cáfolatok, bizonyítékok, coaching és időzített gyakorlókörök egy MI-ellenféllel szemben."
+ "title": "{{product}}: MI-alapú vitafelkészülés és gyakorlás",
+ "description": "A {{product}} MI segítségével készít fel diákokat és vitázókat: esetek, cáfolatok és bizonyítékok, majd időzített gyakorlókörök egy MI-ellenféllel."
},
"terms": {
"title": "Felhasználási feltételek | {{brand}}",
@@ -2607,24 +2608,24 @@
"description": "Ez az oldal nem létezik a {{brand}} webhelyén."
},
"tools": {
- "title": "Ingyenes vitaeszközök: időmérő, vitatételek, jegyzetlapok | {{brand}}",
+ "title": "Ingyenes vitaeszközök | {{brand}}",
"description": "Ingyenes, fiók nélkül használható vitaeszközök: formátumhoz igazodó időmérő, vitatétel-generátor, nyomtatható jegyzetlapok és beszédidő-kalkulátor."
},
"debateTimer": {
- "title": "Ingyenes vitaidőmérő PF, LD, Policy, BP és World Schools formátumhoz | {{brand}}",
- "description": "Ingyenes vitaidőmérő PF, LD, Policy, BP, World Schools és Asian Parliamentary beállításokkal: védett idő, POI-jelzés és felkészülési idő."
+ "title": "Ingyenes vitaidőmérő | {{brand}}",
+ "description": "Ingyenes vitaidőmérő PF, LD, Policy, BP, World Schools és Asian Parliamentary beállításokkal, védett idővel, POI-jelzéssel és felkészülési idővel."
},
"motionGenerator": {
- "title": "Vitatétel-generátor: 300 gyakorló vitatétel | {{brand}}",
- "description": "Húzz egy véletlen vitatételt, vagy hármat a vétógyakorláshoz, 300 eredeti gyakorló tételből, téma, nehézség és típus szerint rendezve."
+ "title": "Vitatétel-generátor | {{brand}}",
+ "description": "Ingyenes vitatétel-generátor, amely egy véletlen tételt, vagy vétógyakorláshoz hármat húz 300 eredeti, téma és típus szerint rendezett tételből."
},
"flowSheet": {
- "title": "Nyomtatható vitajegyzetlap-generátor | {{brand}}",
- "description": "Egyoldalas, nyomtatható vitajegyzetlap minden beszédhez külön oszloppal PF, LD, Policy, BP, World Schools vagy Asian Parliamentary formátumhoz."
+ "title": "Nyomtatható vitajegyzetlapok | {{brand}}",
+ "description": "Ingyenes, nyomtatható vitajegyzetlap minden beszédhez külön oszloppal PF, LD, Policy, BP, World Schools vagy Asian Parliamentary formátumhoz."
},
"speechTimeCalculator": {
- "title": "Beszédidő-kalkulátor vitabeszédekhez | {{brand}}",
- "description": "Illessz be egy beszédet, és megmutatjuk a szószámát, hogy lassú, átlagos és gyors tempóban mennyi ideig tart, és mely vitabeszéd-idősávokba fér bele."
+ "title": "Beszédidő-kalkulátor | {{brand}}",
+ "description": "Ingyenes beszédidő-kalkulátor, amely megszámolja egy vitabeszéd szavait, és megmutatja, mennyi ideig tart lassú, átlagos és gyors tempóban."
}
},
"validation": {
diff --git a/src/pages/tools/ToolsHubPage.tsx b/src/pages/tools/ToolsHubPage.tsx
index 1e46cb47c..d6d82a1ff 100644
--- a/src/pages/tools/ToolsHubPage.tsx
+++ b/src/pages/tools/ToolsHubPage.tsx
@@ -39,7 +39,7 @@ export default function ToolsHubPage() {
-
DebateOwl is a paid practice app for debaters: it drafts cases for either side of a motion, suggests rebuttals, and runs sparring rounds against an AI opponent.
+
DebateOwl is an AI debate prep and practice app: it drafts cases for either side of a motion, suggests rebuttals, and runs sparring rounds against an AI opponent.
);
diff --git a/src/pages/tools/localized/copy-es.ts b/src/pages/tools/localized/copy-es.ts
index dd4cb04f5..fbf288ff7 100644
--- a/src/pages/tools/localized/copy-es.ts
+++ b/src/pages/tools/localized/copy-es.ts
@@ -38,7 +38,7 @@ export const COPY_ES: LocalizedToolsCopy = {
faq: [],
cta: {
title: 'Cuando necesitas algo más que un reloj',
- body: '{product} es una app de práctica de pago para debatientes: redacta casos para cualquiera de los dos lados de una moción, sugiere refutaciones y organiza rondas de Sparring contra un oponente de IA.',
+ body: '{product} es una app de preparación y práctica de debate con IA: redacta casos para cualquiera de los dos lados de una moción, sugiere refutaciones y organiza rondas de Sparring contra un oponente de IA.',
},
},
diff --git a/src/pages/tools/localized/copy-hu.ts b/src/pages/tools/localized/copy-hu.ts
index ba4a00178..02d13c327 100644
--- a/src/pages/tools/localized/copy-hu.ts
+++ b/src/pages/tools/localized/copy-hu.ts
@@ -38,7 +38,7 @@ export const COPY_HU: LocalizedToolsCopy = {
faq: [],
cta: {
title: 'Ha már nem csak időmérőre van szükséged',
- body: 'A {product} fizetős gyakorlóalkalmazás vitázóknak: egy tétel bármelyik oldalára megírja az eset vázlatát, cáfolatokat javasol, és Vitapárbaj-fordulókat futtat egy MI-ellenféllel.',
+ body: 'A {product} MI-alapú vitafelkészítő és gyakorlóalkalmazás: egy tétel bármelyik oldalára megírja az eset vázlatát, cáfolatokat javasol, és Vitapárbaj-fordulókat futtat egy MI-ellenféllel.',
},
},
diff --git a/src/prerender/entry.tsx b/src/prerender/entry.tsx
index 0b58c1320..55189c435 100644
--- a/src/prerender/entry.tsx
+++ b/src/prerender/entry.tsx
@@ -170,10 +170,24 @@ function localizedLandingStructuredData(head: PageHead, language: PageLanguage,
};
}
-function legalStructuredData(route: '/terms' | '/privacy', dateKey: string) {
+/** Home, then the page: the trail the guides and tool pages already carry. */
+function breadcrumbList(route: '/terms' | '/privacy' | '/expocit/sources', name: string) {
+ return {
+ '@type': 'BreadcrumbList',
+ itemListElement: [
+ { '@type': 'ListItem', position: 1, name: PRODUCT, item: `${SITE_ORIGIN}/` },
+ { '@type': 'ListItem', position: 2, name, item: `${SITE_ORIGIN}${route}` },
+ ],
+ };
+}
+
+function legalStructuredData(route: '/terms' | '/privacy', page: 'termsPage' | 'privacyPage') {
return {
'@context': 'https://schema.org',
- '@graph': [webPage(route, isoDate(i18n.t(dateKey, { lng: 'en' })))],
+ '@graph': [
+ webPage(route, isoDate(i18n.t(`${page}.date`, { lng: 'en' }))),
+ breadcrumbList(route, i18n.t(`${page}.title`, { lng: 'en' })),
+ ],
};
}
@@ -245,7 +259,7 @@ export async function prerenderPages({ landingModified }: { landingModified?: st
module: 'src/pages/TermsPage.tsx',
head: PAGE_HEADS['/terms'],
body: render('/terms', TermsPage),
- structuredData: legalStructuredData('/terms', 'termsPage.date'),
+ structuredData: legalStructuredData('/terms', 'termsPage'),
},
{
route: '/privacy',
@@ -253,7 +267,7 @@ export async function prerenderPages({ landingModified }: { landingModified?: st
module: 'src/pages/PrivacyPage.tsx',
head: PAGE_HEADS['/privacy'],
body: render('/privacy', PrivacyPage),
- structuredData: legalStructuredData('/privacy', 'privacyPage.date'),
+ structuredData: legalStructuredData('/privacy', 'privacyPage'),
},
// The tool pages render their own JSON-LD in the body.
...TOOL_PAGES.map(({ route, module, Page }) => ({
@@ -270,6 +284,10 @@ export async function prerenderPages({ landingModified }: { landingModified?: st
module: 'src/pages/SourcesPage.tsx',
head: PAGE_HEADS['/expocit/sources'],
body: render('/expocit/sources', SourcesPage),
+ structuredData: {
+ '@context': 'https://schema.org',
+ '@graph': [webPage('/expocit/sources', undefined), breadcrumbList('/expocit/sources', i18n.t('sourcesPage.title'))],
+ },
},
{
route: '*',