feat(i18n): translate hardcoded strings across print, public recipe, and recipe management UI
Wires dozens of components and server pages to next-intl instead of hardcoded English text, and adds a lightweight getMessages/formatMessage helper for server components (print pages, public recipe page, cook metadata) since next-intl/server isn't wired into this app's routing. Backfills missing en/fr message keys that existing code already referenced but fr.json lacked.
This commit is contained in:
@@ -8,6 +8,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Flame, Clock, ChefHat, Search, Sparkles, Wand2, ArrowRight } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import type { RecipeResult as ExploreRecipeResult } from "@/app/(app)/explore/page";
|
||||
|
||||
const DIFFICULTY_COLORS: Record<string, string> = {
|
||||
@@ -100,6 +101,8 @@ type Props = {
|
||||
export function ExplorePageContent({ trending, recent, initialQuery }: Props) {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const t = useTranslations("explore");
|
||||
const tCommon = useTranslations("common");
|
||||
|
||||
const [inputValue, setInputValue] = useState(initialQuery);
|
||||
const [query, setQuery] = useState(initialQuery);
|
||||
@@ -243,7 +246,7 @@ export function ExplorePageContent({ trending, recent, initialQuery }: Props) {
|
||||
ref={inputRef}
|
||||
value={inputValue}
|
||||
onChange={(e) => handleInputChange(e.target.value)}
|
||||
placeholder="Search public recipes…"
|
||||
placeholder={t("searchPlaceholder")}
|
||||
className="pl-10 h-12 text-base"
|
||||
autoFocus={!!initialQuery}
|
||||
/>
|
||||
@@ -253,7 +256,7 @@ export function ExplorePageContent({ trending, recent, initialQuery }: Props) {
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<Select value={difficulty} onValueChange={handleDifficultyChange}>
|
||||
<SelectTrigger className="w-40">
|
||||
<SelectValue placeholder="Difficulty" />
|
||||
<SelectValue placeholder={tCommon("difficulty")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="any">Any difficulty</SelectItem>
|
||||
@@ -265,7 +268,7 @@ export function ExplorePageContent({ trending, recent, initialQuery }: Props) {
|
||||
<Input
|
||||
type="number"
|
||||
min={1}
|
||||
placeholder="Max minutes"
|
||||
placeholder={t("maxMinutes")}
|
||||
value={maxMins}
|
||||
onChange={(e) => handleMaxMinsChange(e.target.value)}
|
||||
className="w-36"
|
||||
@@ -342,7 +345,7 @@ export function ExplorePageContent({ trending, recent, initialQuery }: Props) {
|
||||
<Input
|
||||
value={ideasPrompt}
|
||||
onChange={(e) => setIdeasPrompt(e.target.value)}
|
||||
placeholder="e.g. quick weeknight dinners, Italian comfort food…"
|
||||
placeholder={t("aiSearchPlaceholder")}
|
||||
className="bg-background"
|
||||
/>
|
||||
<Button type="submit" disabled={ideasLoading} variant="secondary" className="shrink-0">
|
||||
|
||||
Reference in New Issue
Block a user