feat(i18n): resolve Species/Breed display names via SpeciesTranslation/BreedTranslation
User found "Cat" showing English on a German-locale profile page. Root cause: Species.name/Breed.name are the canonical English values; a SpeciesTranslation/BreedTranslation table + seed data (Hund/Katze/Vogel etc.) already existed in the schema, and PetForm's species/breed picker already used it correctly via an explicit locale input param — but every *display* surface (pet profile, PetCard, Sidebar/MobileNav, search, explore, followers/following lists, mention @-search, health-card) just read the raw untranslated name. Adds `locale` to the tRPC context (createTRPCContext reads the NEXT_LOCALE cookie the same way i18n/request.ts does), so read procedures can resolve translations without every caller needing to pass a locale param. New src/lib/localized-name.ts::pickLocalizedName() does the lookup with a same-shape fallback to the raw name. Updated: pets.ts (list/byId/getProfile/update), search.ts (pets/byOwner), explore.ts (listPets), follows.ts (listFollowers/listFollowing). health-card/[token]/page.tsx (public, unauthenticated, intentionally all-German) resolves with a fixed "de" locale instead of ctx.locale, consistent with its existing hardcoded WeightChart locale. Verified the seed data is actually present in the production DB (SpeciesTranslation has Dog→Hund, Cat→Katze, Bird→Vogel) — this fix is immediately effective on deploy, not blocked on a missing seed run.
This commit is contained in:
1 parent
b7719397e6
commit
25fa2a3bec
10 files changed
+138
-30
No files matched your search
@@ -8,6 +8,7 @@ import { getAvatarUrl } from "@/lib/avatar-url";
|
||||
import { PrintButton } from "@/components/health/PrintButton";
|
||||
import { AutoPrint } from "@/components/health/AutoPrint";
|
||||
import { WeightChart } from "@/components/health/WeightChart";
|
||||
import { pickLocalizedName } from "@/lib/localized-name";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ token: string }>;
|
||||
@@ -41,8 +42,8 @@ export default async function HealthCardPage({ params, searchParams }: PageProps
|
||||
include: {
|
||||
pet: {
|
||||
include: {
|
||||
species: true,
|
||||
breed: true,
|
||||
species: { include: { translations: { where: { locale: "de" } } } },
|
||||
breed: { include: { translations: { where: { locale: "de" } } } },
|
||||
weightLogs: { orderBy: { date: "desc" }, take: 20 },
|
||||
vetVisits: { orderBy: { date: "desc" }, take: 10 },
|
||||
vaccines: { orderBy: { dateGiven: "desc" } },
|
||||
@@ -81,6 +82,8 @@ export default async function HealthCardPage({ params, searchParams }: PageProps
|
||||
|
||||
const { pet } = card;
|
||||
const avatarUrl = getAvatarUrl(pet.avatarKey);
|
||||
const speciesName = pickLocalizedName(pet.species.name, pet.species.translations, "de");
|
||||
const breedName = pet.breed ? pickLocalizedName(pet.breed.name, pet.breed.translations, "de") : null;
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-muted/30">
|
||||
@@ -110,8 +113,8 @@ export default async function HealthCardPage({ params, searchParams }: PageProps
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold">{pet.name}</h1>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<Badge variant="secondary">{pet.species.name}</Badge>
|
||||
{pet.breed && <Badge variant="outline">{pet.breed.name}</Badge>}
|
||||
<Badge variant="secondary">{speciesName}</Badge>
|
||||
{breedName && <Badge variant="outline">{breedName}</Badge>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user