diff --git a/apps/landing/astro.config.mjs b/apps/landing/astro.config.mjs index c7d057e..a841fa5 100644 --- a/apps/landing/astro.config.mjs +++ b/apps/landing/astro.config.mjs @@ -23,6 +23,15 @@ export default defineConfig({ adapter: node({ mode: "standalone", }), + i18n: { + // FR par défaut, EN sous /en/* — `prefixDefaultLocale: false` garde + // les URLs FR canoniques à la racine pour ne pas casser le SEO existant. + defaultLocale: "fr", + locales: ["fr", "en"], + routing: { + prefixDefaultLocale: false, + }, + }, integrations: [ react(), ], diff --git a/apps/landing/src/components/SiteFooter.tsx b/apps/landing/src/components/SiteFooter.tsx index 8b1e03e..b95221b 100644 --- a/apps/landing/src/components/SiteFooter.tsx +++ b/apps/landing/src/components/SiteFooter.tsx @@ -1,39 +1,44 @@ import { Brand } from "@rubis/ui"; +import { getTranslations, type Locale } from "../i18n"; const CURRENT_YEAR = new Date().getFullYear(); +type SiteFooterProps = { + locale?: Locale; +}; + /** * Footer public commun à toutes les pages rubis.pro/*. * Liens légaux + tagline. Pas de réseaux sociaux V1. */ -export function SiteFooter() { +export function SiteFooter({ locale = "fr" }: SiteFooterProps) { + const t = getTranslations(locale); + const prefix = locale === "fr" ? "" : "/en"; + return ( diff --git a/apps/landing/src/components/SiteHeader.tsx b/apps/landing/src/components/SiteHeader.tsx index a7fd11a..d46d0d1 100644 --- a/apps/landing/src/components/SiteHeader.tsx +++ b/apps/landing/src/components/SiteHeader.tsx @@ -1,4 +1,5 @@ import { Brand, Button, cn } from "@rubis/ui"; +import { getTranslations, getAlternateUrl, type Locale } from "../i18n"; const APP_URL = "https://app.rubis.pro"; @@ -6,18 +7,29 @@ type SiteHeaderProps = { /** Si true, fond opaque + bordure (utile sur les pages blog où on n'a pas de hero). Sinon transparent + sticky-blur. */ solid?: boolean; className?: string; + locale?: Locale; + /** Path courant — sert à construire le lien switcher vers la locale alternative. */ + currentPath?: string; }; /** - * Header public commun à toutes les pages rubis.pro/* : - * - lockup brand → / - * - liens nav (Tarifs, Blog) - * - CTA "Essai gratuit 30 j" → app.rubis.pro - * - * Sticky avec backdrop-blur quand le header est posé sur un hero (transparent), - * solid+bordure sur les pages secondaires (blog, légal). + * Header public commun à toutes les pages rubis.pro/*. + * Reçoit la locale via Layout.astro, expose un switcher FR/EN qui préserve + * la page courante. */ -export function SiteHeader({ solid = false, className }: SiteHeaderProps) { +export function SiteHeader({ + solid = false, + className, + locale = "fr", + currentPath = "/", +}: SiteHeaderProps) { + const t = getTranslations(locale); + const target: Locale = locale === "fr" ? "en" : "fr"; + const altUrl = getAlternateUrl(currentPath, target); + const homeHref = locale === "fr" ? "/" : "/en/"; + const pricingHref = locale === "fr" ? "/#pricing" : "/en/#pricing"; + const blogHref = locale === "fr" ? "/blog" : "/en/blog"; + return (
- + -
diff --git a/apps/landing/src/components/sections/AutoBanking.tsx b/apps/landing/src/components/sections/AutoBanking.tsx index c19bd24..038b92c 100644 --- a/apps/landing/src/components/sections/AutoBanking.tsx +++ b/apps/landing/src/components/sections/AutoBanking.tsx @@ -1,76 +1,68 @@ import { CheckCircle2, ShieldCheck, Sparkles, Building2 } from "lucide-react"; +import { getTranslations, type Locale } from "../../i18n"; + +type AutoBankingProps = { + locale?: Locale; +}; + +export function AutoBanking({ locale = "fr" }: AutoBankingProps) { + const t = getTranslations(locale).autoBanking; -/** - * Section "Mode automatique — bientôt" : annonce la connexion bancaire - * en lecture seule via Powens (AISP). Désactivée par défaut sur l'app - * en attendant l'agrément KYC Powens prod. La landing communique - * pendant la fenêtre. - * - * Style : carte cream avec accent rubis, illustration mock à droite, - * 4 bénéfices clés, note conformité DSP2 / lecture seule. - */ -export function AutoBanking() { return (
- {/* Colonne texte */}

- Plus jamais besoin de répondre{" "} - « C'est payé ». + {t.title_a} + {t.title_em} + {t.title_b}

-

- Connectez votre compte bancaire en lecture seule. Rubis détecte - automatiquement les virements de vos clients, marque les - factures payées et envoie le mot de remerciement. Vous ne - répondez plus à rien. -

+

{t.body}

    - Détection en temps réel via Powens - (agréé AISP par l'ACPR). + {t.benefit1_bold} + {t.benefit1_rest} - Toutes les banques françaises — - pro ou perso, neo ou traditionnelles. + {t.benefit2_bold} + {t.benefit2_rest} - Mode validation ou auto-pilote{" "} - — vous choisissez si Rubis attend votre OK ou marque - payée tout seul. + {t.benefit3_bold} + {t.benefit3_rest} - Lecture seule. Aucun déplacement - de fonds possible, jamais. Révocable en un clic. + {t.benefit4_bold} + {t.benefit4_rest}

- {/* Colonne illustration : email "Paiement détecté" */}
- +
@@ -92,18 +84,13 @@ function Benefit({ children }: { children: React.ReactNode }) { ); } -/** - * Mock d'email "Paiement détecté" — illustre le résultat concret de la - * feature. Reprend les codes du ThankYouWidget de HowItWorks pour la - * cohérence visuelle (carte blanche, en-tête expéditeur avec gem ◆, - * badge rubis-glow). - */ -function DetectedPaymentMock() { +function DetectedPaymentMock({ locale }: { locale: Locale }) { + const t = getTranslations(locale).autoBanking; + const amount = locale === "fr" ? "4 189,40 €" : "€4,189.40"; return (