fix(i18n): translate remaining recipe card/detail strings, localize AI responses
Recipe cards, the recipe detail page, and meal planner still rendered raw
"{n} servings"/"{n}m cook"/"{n} srv" text and untranslated difficulty labels
outside the earlier i18n pass. Also wires the user's locale into AI features
that previously always answered in English regardless of app language:
recipe chat, ingredient substitution, recipe ideas, and generate-from-idea.
The recipe-language picker in the AI generate dialog now defaults to the
user's locale instead of always defaulting to English.
This commit is contained in:
@@ -43,8 +43,12 @@ type RecipeIdea = {
|
||||
};
|
||||
|
||||
function RecipeCard({ recipe }: { recipe: ExploreRecipeResult | SearchRecipeResult }) {
|
||||
const t = useTranslations("recipe");
|
||||
const totalMins = (recipe.prepMins ?? 0) + (recipe.cookMins ?? 0);
|
||||
const description = "description" in recipe ? recipe.description : null;
|
||||
const difficultyLabel = recipe.difficulty === "easy" || recipe.difficulty === "medium" || recipe.difficulty === "hard"
|
||||
? t(`difficulty.${recipe.difficulty}`)
|
||||
: recipe.difficulty;
|
||||
return (
|
||||
<Link
|
||||
href={`/recipes/${recipe.id}`}
|
||||
@@ -59,7 +63,7 @@ function RecipeCard({ recipe }: { recipe: ExploreRecipeResult | SearchRecipeResu
|
||||
variant="secondary"
|
||||
className={`shrink-0 capitalize text-xs ${DIFFICULTY_COLORS[recipe.difficulty] ?? ""}`}
|
||||
>
|
||||
{recipe.difficulty}
|
||||
{difficultyLabel}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
@@ -70,7 +74,7 @@ function RecipeCard({ recipe }: { recipe: ExploreRecipeResult | SearchRecipeResu
|
||||
{totalMins > 0 && (
|
||||
<span className="flex items-center gap-1">
|
||||
<Clock className="h-3.5 w-3.5" />
|
||||
{totalMins}m
|
||||
{t("total", { mins: totalMins })}
|
||||
</span>
|
||||
)}
|
||||
{recipe.authorName && (
|
||||
@@ -103,6 +107,7 @@ export function ExplorePageContent({ trending, recent, initialQuery }: Props) {
|
||||
const searchParams = useSearchParams();
|
||||
const t = useTranslations("explore");
|
||||
const tCommon = useTranslations("common");
|
||||
const tRecipe = useTranslations("recipe");
|
||||
|
||||
const [inputValue, setInputValue] = useState(initialQuery);
|
||||
const [query, setQuery] = useState(initialQuery);
|
||||
@@ -388,7 +393,7 @@ export function ExplorePageContent({ trending, recent, initialQuery }: Props) {
|
||||
variant="secondary"
|
||||
className={`shrink-0 capitalize text-xs ${DIFFICULTY_COLORS[idea.difficulty] ?? ""}`}
|
||||
>
|
||||
{idea.difficulty}
|
||||
{tRecipe(`difficulty.${idea.difficulty}`)}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground line-clamp-2 flex-1">{idea.description}</p>
|
||||
@@ -398,7 +403,7 @@ export function ExplorePageContent({ trending, recent, initialQuery }: Props) {
|
||||
))}
|
||||
{idea.totalMins && (
|
||||
<Badge variant="outline" className="text-xs flex items-center gap-1">
|
||||
<Clock className="h-3 w-3" />{idea.totalMins}m
|
||||
<Clock className="h-3 w-3" />{tRecipe("total", { mins: idea.totalMins })}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user