feat(plugin): i18n FR + EN (Phase 4.2)
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.
This commit is contained in:
parent
efeea16467
commit
cf9da94bb5
15 changed files with 454 additions and 116 deletions
|
|
@ -1,38 +1,40 @@
|
|||
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 messages: Record<typeof season, string> = {
|
||||
DRY:
|
||||
"Conditions optimales : fleuves navigables, pistes route en bon état, lever de soleil sur l'eau brûlante.",
|
||||
LOW_WATER:
|
||||
"Étiage en cours : les carbets fleuve uniquement peuvent ne pas être accessibles. Filtre dispo en page recherche.",
|
||||
WET:
|
||||
"Pluies fréquentes : la jungle est dense et vivante, prévoir un véhicule adapté pour les carbets route+fleuve.",
|
||||
};
|
||||
|
||||
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 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`}>
|
||||
<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">{meta.label}</span>
|
||||
<span className="font-semibold uppercase tracking-wider">{label}</span>
|
||||
<span className="hidden text-[var(--color-karbe-bone)]/85 sm:inline">
|
||||
· {messages[season]}
|
||||
· {message}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue