Infrastructure i18n légère, sans deps externe : - lib/i18n/types.ts : LOCALES, DEFAULT_LOCALE, cookie name - lib/i18n/server.ts : getLocale (cookie > Accept-Language > FR), t(key) async server-side, dict(locale) - lib/i18n/client.tsx : LocaleProvider + useLocale + useT - messages/fr.json + messages/en.json : ~50 clés pour landing + header + footer - LocaleSwitcher component (cookie + router.refresh) Plugin gated : - Quand i18n-fr-en désactivé, getLocale() force FR. Le switcher ne s'affiche pas dans le hero. Pas d'impact sur le rendu existant. - Quand activé, switcher visible coin haut-droit du hero. Les composants landing/header/footer rendent en FR ou EN selon le cookie utilisateur. Composants i18n-isés : - HeroSection (eyebrow, titre, CTA) - ExperiencesSection (route/fleuve vs expédition, tous les bullets) - HowItWorksSection (3 étapes) - CESection (KPIs + body + CTA) - TestimonialsSection (eyebrow + titre, citations restent en VO) - Footer (taglines, colonnes) - SeasonBanner (3 saisons + messages) - AccessTypeBadge (labels + tooltips) Pour les ContentPage, le champ lang existait déjà. Une suite (PR ultérieure) ajoutera le filtre lang dans getContentPage + seed pages EN.
43 lines
1.6 KiB
TypeScript
43 lines
1.6 KiB
TypeScript
import { isPluginEnabled } from "@/lib/plugins/server";
|
|
import { currentSeason, SEASON_META } from "@/lib/seasonality";
|
|
import { t } from "@/lib/i18n/server";
|
|
|
|
const TONES = {
|
|
ok: "bg-[var(--color-karbe-canopy-700)] text-[var(--color-karbe-bone)]",
|
|
warn: "bg-[var(--color-karbe-laterite-500)] text-[var(--color-karbe-bone)]",
|
|
info: "bg-[var(--color-karbe-maroni-700)] text-[var(--color-karbe-bone)]",
|
|
} as const;
|
|
|
|
const SEASON_KEYS = {
|
|
DRY: { label: "season.dry", message: "season.dry.message" },
|
|
LOW_WATER: { label: "season.lowWater", message: "season.lowWater.message" },
|
|
WET: { label: "season.wet", message: "season.wet.message" },
|
|
} as const;
|
|
|
|
/**
|
|
* Bandeau saison — affiché en haut de la home et de /carbets si le plugin
|
|
* `seasonality` est activé. Server component pur, pas de fetch DB.
|
|
* Texte i18n via t() server-side.
|
|
*/
|
|
export async function SeasonBanner() {
|
|
if (!(await isPluginEnabled("seasonality"))) return null;
|
|
const season = currentSeason();
|
|
const meta = SEASON_META[season];
|
|
const keys = SEASON_KEYS[season];
|
|
const label = await t(keys.label);
|
|
const message = await t(keys.message);
|
|
|
|
return (
|
|
<aside className={`${TONES[meta.tone]} text-xs sm:text-sm`}>
|
|
<div className="mx-auto flex max-w-6xl items-center justify-between gap-3 px-6 py-2 sm:px-8 lg:px-12">
|
|
<span className="flex items-center gap-2">
|
|
<span aria-hidden>{meta.emoji}</span>
|
|
<span className="font-semibold uppercase tracking-wider">{label}</span>
|
|
<span className="hidden text-[var(--color-karbe-bone)]/85 sm:inline">
|
|
· {message}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|