diff --git a/CHANGELOG.md b/CHANGELOG.md
index d2d8a65..f01686b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,11 @@
All notable changes to Epicure are documented here. This file is mirrored in-app at `/changelog` (and in the admin dashboard) via `apps/web/lib/changelog.ts` — update both together.
+## 0.48.2 — 2026-07-18 11:15
+
+### Fixed
+- Marketing site's language switcher no longer uses emoji flags (inconsistent rendering across OS/browsers) — now inline SVG flags in a proper dropdown menu. Home page's feature grid also got a 9th highlight (personalized recommendations) so the last row isn't left half-empty.
+
## 0.48.1 — 2026-07-18 11:00
### Added
diff --git a/apps/web/app/(marketing)/page.tsx b/apps/web/app/(marketing)/page.tsx
index 600ae62..6c8e311 100644
--- a/apps/web/app/(marketing)/page.tsx
+++ b/apps/web/app/(marketing)/page.tsx
@@ -7,7 +7,7 @@ import { getEffectiveMarketingLocale } from "@/lib/marketing-locale";
import { isSignupsDisabled } from "@/lib/site-settings";
import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
-import { Sparkles, Calendar, Package, MessageCircle, Users, ChefHat, Utensils, Wand2 } from "lucide-react";
+import { Sparkles, Calendar, Package, MessageCircle, Users, ChefHat, Utensils, Wand2, Sparkle } from "lucide-react";
const HIGHLIGHTS = [
{ icon: Sparkles, key: "ai" },
@@ -18,6 +18,7 @@ const HIGHLIGHTS = [
{ icon: Wand2, key: "variations" },
{ icon: Users, key: "social" },
{ icon: ChefHat, key: "batchCook" },
+ { icon: Sparkle, key: "recommendations" },
] as const;
export default async function MarketingHomePage() {
diff --git a/apps/web/components/marketing/flag-icons.tsx b/apps/web/components/marketing/flag-icons.tsx
new file mode 100644
index 0000000..aedb35d
--- /dev/null
+++ b/apps/web/components/marketing/flag-icons.tsx
@@ -0,0 +1,24 @@
+// Minimal inline SVG flags — no emoji (inconsistent rendering across
+// OS/browsers) and no new dependency for just two supported locales.
+
+export function FlagGB({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+export function FlagFR({ className }: { className?: string }) {
+ return (
+
+ );
+}
diff --git a/apps/web/components/marketing/language-switcher.tsx b/apps/web/components/marketing/language-switcher.tsx
index 727a311..e973ed1 100644
--- a/apps/web/components/marketing/language-switcher.tsx
+++ b/apps/web/components/marketing/language-switcher.tsx
@@ -1,12 +1,20 @@
"use client";
import { useRouter } from "next/navigation";
+import { Check, Globe } from "lucide-react";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
import { MARKETING_LOCALE_COOKIE } from "@/lib/marketing-locale-cookie";
import type { Locale } from "@/lib/i18n/provider";
+import { FlagGB, FlagFR } from "./flag-icons";
-const OPTIONS: { code: Locale; flag: string; label: string }[] = [
- { code: "en", flag: "🇬🇧", label: "English" },
- { code: "fr", flag: "🇫🇷", label: "Français" },
+const OPTIONS: { code: Locale; Flag: typeof FlagGB; label: string }[] = [
+ { code: "en", Flag: FlagGB, label: "English" },
+ { code: "fr", Flag: FlagFR, label: "Français" },
];
// Plain module-level function, not part of the component body — setting a
@@ -26,6 +34,7 @@ function setMarketingLocaleCookie(code: Locale) {
*/
export function LanguageSwitcher({ current }: { current: Locale }) {
const router = useRouter();
+ const CurrentFlag = OPTIONS.find((o) => o.code === current)?.Flag ?? Globe;
function select(code: Locale) {
if (code === current) return;
@@ -34,22 +43,22 @@ export function LanguageSwitcher({ current }: { current: Locale }) {
}
return (
-
- {OPTIONS.map(({ code, flag, label }) => (
-
- ))}
-
+
+
+
+
+
+ {OPTIONS.map(({ code, Flag, label }) => (
+ select(code)} className="gap-2">
+
+ {label}
+ {current === code && }
+
+ ))}
+
+
);
}
diff --git a/apps/web/lib/changelog.ts b/apps/web/lib/changelog.ts
index 16bacc4..fb49558 100644
--- a/apps/web/lib/changelog.ts
+++ b/apps/web/lib/changelog.ts
@@ -1,5 +1,5 @@
// Mirrors CHANGELOG.md at the repo root — update both together.
-export const APP_VERSION = "0.48.1";
+export const APP_VERSION = "0.48.2";
export type ChangelogEntry = {
version: string;
@@ -11,6 +11,13 @@ export type ChangelogEntry = {
};
export const CHANGELOG: ChangelogEntry[] = [
+ {
+ version: "0.48.2",
+ date: "2026-07-18 11:15",
+ fixed: [
+ "Marketing site's language switcher no longer uses emoji flags (inconsistent rendering across OS/browsers) — now inline SVG flags in a proper dropdown menu. Home page's feature grid also got a 9th highlight (personalized recommendations) so the last row isn't left half-empty.",
+ ],
+ },
{
version: "0.48.1",
date: "2026-07-18 11:00",
diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json
index fae612e..6fec1a1 100644
--- a/apps/web/messages/en.json
+++ b/apps/web/messages/en.json
@@ -30,7 +30,8 @@
"cookMode": { "title": "Hands-free cook mode", "description": "A distraction-free, step-by-step view for actually cooking — large text, timers, no scrolling with messy hands." },
"variations": { "title": "Recipe variations", "description": "Ask for a dietary twist, an ingredient swap, or a whole new spin on a recipe — AI proposes a variation, you decide whether to keep it." },
"social": { "title": "Share & discover", "description": "Follow other cooks, rate and comment on recipes, and control exactly who can see yours." },
- "batchCook": { "title": "Batch cooking", "description": "Cook once, eat all week — dedicated batch-cook planning with fridge/freezer guidance." }
+ "batchCook": { "title": "Batch cooking", "description": "Cook once, eat all week — dedicated batch-cook planning with fridge/freezer guidance." },
+ "recommendations": { "title": "Personalized recommendations", "description": "A For You feed ranked from what you've favorited and rated, plus meal/drink pairing suggestions for any recipe." }
}
},
"features": {
diff --git a/apps/web/messages/fr.json b/apps/web/messages/fr.json
index a58f40a..c973e9d 100644
--- a/apps/web/messages/fr.json
+++ b/apps/web/messages/fr.json
@@ -30,7 +30,8 @@
"cookMode": { "title": "Mode cuisine mains libres", "description": "Une vue étape par étape sans distraction pour cuisiner — grand texte, minuteurs intégrés, pas besoin de scroller les mains sales." },
"variations": { "title": "Variations de recette", "description": "Demandez une variante diététique, un remplacement d'ingrédient, ou une toute nouvelle interprétation — l'IA propose une variation, vous décidez de la garder." },
"social": { "title": "Partager & découvrir", "description": "Suivez d'autres cuisiniers, notez et commentez les recettes, et contrôlez précisément qui peut voir les vôtres." },
- "batchCook": { "title": "Cuisine en lots", "description": "Cuisinez une fois, mangez toute la semaine — planification dédiée avec conseils de conservation au frigo/congélateur." }
+ "batchCook": { "title": "Cuisine en lots", "description": "Cuisinez une fois, mangez toute la semaine — planification dédiée avec conseils de conservation au frigo/congélateur." },
+ "recommendations": { "title": "Recommandations personnalisées", "description": "Un fil « Pour vous » classé selon vos favoris et vos notes, plus des suggestions d'accords repas/boisson pour chaque recette." }
}
},
"features": {
diff --git a/apps/web/package.json b/apps/web/package.json
index 8589260..26296a4 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -1,6 +1,6 @@
{
"name": "@epicure/web",
- "version": "0.48.1",
+ "version": "0.48.2",
"private": true,
"scripts": {
"dev": "next dev",
diff --git a/package.json b/package.json
index c83edbc..a67abeb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "epicure",
- "version": "0.48.1",
+ "version": "0.48.2",
"private": true,
"scripts": {
"dev": "pnpm --filter web dev",