From 738c0e223ff008ae06eee971a6755c3b74e6825f Mon Sep 17 00:00:00 2001 From: "Chuma Mcphoy (We Ahead)" Date: Mon, 3 Mar 2025 12:55:05 +0000 Subject: [PATCH] Merged in feat/LOY-156-localize-user-languages (pull request #1452) feat(LOY-156): Improve language handling and localization in profile page * feat(LOY-156): Improve language handling and localization in profile page * refactor(LOY-156): Improve language display using Intl.DisplayNames * feat(LOY-156): Enhance country display with localized country names * refactor(LOY-156): Move countries data to a dedicated constants file & more type safe country mapping * feat(LOY-156): Update isValidLang to use languageSchema + German translation for membership terms and conditions * chore(LOY-156): language handling in profile component Approved-by: Christian Andolf --- apps/scandic-web/actions/editProfile.ts | 2 +- .../MyPages/myprofile/profile/profile.tsx | 28 +++++++++++++++---- .../TempDesignSystem/Form/Country/index.tsx | 3 +- .../Form/Country => constants}/countries.ts | 0 apps/scandic-web/i18n/dictionaries/de.json | 2 +- .../scandic-web/server/routers/user/output.ts | 3 +- apps/scandic-web/server/routers/user/query.ts | 2 +- apps/scandic-web/utils/countries.ts | 7 +++++ apps/scandic-web/utils/languages.ts | 26 ++++++++--------- 9 files changed, 50 insertions(+), 23 deletions(-) rename apps/scandic-web/{components/TempDesignSystem/Form/Country => constants}/countries.ts (100%) create mode 100644 apps/scandic-web/utils/countries.ts diff --git a/apps/scandic-web/actions/editProfile.ts b/apps/scandic-web/actions/editProfile.ts index e72f8c336..bcc4c0903 100644 --- a/apps/scandic-web/actions/editProfile.ts +++ b/apps/scandic-web/actions/editProfile.ts @@ -2,13 +2,13 @@ import { z } from "zod" +import { countriesMap } from "@/constants/countries" import { ApiLang } from "@/constants/languages" import * as api from "@/lib/api" import { getProfile } from "@/lib/trpc/memoizedRequests" import { protectedServerActionProcedure } from "@/server/trpc" import { editProfileSchema } from "@/components/Forms/Edit/Profile/schema" -import { countriesMap } from "@/components/TempDesignSystem/Form/Country/countries" import { getIntl } from "@/i18n" import { getMembership } from "@/utils/user" import { phoneValidator } from "@/utils/zod/phoneValidator" diff --git a/apps/scandic-web/components/MyPages/myprofile/profile/profile.tsx b/apps/scandic-web/components/MyPages/myprofile/profile/profile.tsx index d48214235..8c2f611e3 100644 --- a/apps/scandic-web/components/MyPages/myprofile/profile/profile.tsx +++ b/apps/scandic-web/components/MyPages/myprofile/profile/profile.tsx @@ -1,4 +1,5 @@ -import { languages, languageSelect } from "@/constants/languages" +import { countriesMap } from "@/constants/countries" +import { Lang, languages } from "@/constants/languages" import { profileEdit } from "@/constants/routes/myPages" import { getProfile } from "@/lib/trpc/memoizedRequests" @@ -20,6 +21,8 @@ import Body from "@/components/TempDesignSystem/Text/Body" import Title from "@/components/TempDesignSystem/Text/Title" import { getIntl } from "@/i18n" import { getLang } from "@/i18n/serverContext" +import { isValidCountry } from "@/utils/countries" +import { isValidLang } from "@/utils/languages" import styles from "./profile.module.css" @@ -40,8 +43,19 @@ export default async function Profile() { addressParts.push(user.address.city) } + const displayNames = { + language: new Intl.DisplayNames([lang], { type: "language" }), + region: new Intl.DisplayNames([lang], { type: "region" }), + } + if (user.address.country) { - addressParts.push(user.address.country) + const countryCode = isValidCountry(user.address.country) + ? countriesMap[user.address.country] + : null + const localizedCountry = countryCode + ? displayNames.region.of(countryCode) + : user.address.country + addressParts.push(localizedCountry) } const addressOutput = @@ -49,8 +63,12 @@ export default async function Profile() { ? addressParts.join(", ") : intl.formatMessage({ id: "N/A" }) - const defaultLanguage = languages[lang] - const language = languageSelect.find((l) => l.value === user.language) + const userLang = isValidLang(user.language) ? user.language : Lang.en + const localizedLanguage = displayNames.language.of(userLang) + const normalizedLanguage = localizedLanguage + ? localizedLanguage.charAt(0).toUpperCase() + localizedLanguage.slice(1) + : languages[userLang] + return ( <>
@@ -96,7 +114,7 @@ export default async function Profile() { {intl.formatMessage({ id: "Language" })} - {language?.label ?? defaultLanguage} + {normalizedLanguage}
diff --git a/apps/scandic-web/components/TempDesignSystem/Form/Country/index.tsx b/apps/scandic-web/components/TempDesignSystem/Form/Country/index.tsx index 320c24bd3..0794be571 100644 --- a/apps/scandic-web/components/TempDesignSystem/Form/Country/index.tsx +++ b/apps/scandic-web/components/TempDesignSystem/Form/Country/index.tsx @@ -12,13 +12,14 @@ import { import { useController, useFormContext } from "react-hook-form" import { useIntl } from "react-intl" +import { countries } from "@/constants/countries" + import Label from "@/components/TempDesignSystem/Form/Label" import SelectChevron from "@/components/TempDesignSystem/Form/SelectChevron" import Body from "@/components/TempDesignSystem/Text/Body" import useLang from "@/hooks/useLang" import ErrorMessage from "../ErrorMessage" -import { countries } from "./countries" import styles from "./country.module.css" diff --git a/apps/scandic-web/components/TempDesignSystem/Form/Country/countries.ts b/apps/scandic-web/constants/countries.ts similarity index 100% rename from apps/scandic-web/components/TempDesignSystem/Form/Country/countries.ts rename to apps/scandic-web/constants/countries.ts diff --git a/apps/scandic-web/i18n/dictionaries/de.json b/apps/scandic-web/i18n/dictionaries/de.json index 0ce0c5dff..cccda507c 100644 --- a/apps/scandic-web/i18n/dictionaries/de.json +++ b/apps/scandic-web/i18n/dictionaries/de.json @@ -391,7 +391,7 @@ "Membership benefits applied": "Membership benefits applied", "Membership cards": "Mitgliedskarten", "Membership no": "Membership no", - "Membership terms and conditions": "Membership terms and conditions", + "Membership terms and conditions": "Allgemeine Mitgliedsbedingungen", "Menu": "Menü", "Menus": "Menüs", "Modify": "Ändern", diff --git a/apps/scandic-web/server/routers/user/output.ts b/apps/scandic-web/server/routers/user/output.ts index 815120881..24d9eb3fb 100644 --- a/apps/scandic-web/server/routers/user/output.ts +++ b/apps/scandic-web/server/routers/user/output.ts @@ -1,6 +1,7 @@ import { z } from "zod" -import { countriesMap } from "@/components/TempDesignSystem/Form/Country/countries" +import { countriesMap } from "@/constants/countries" + import { getMembership } from "@/utils/user" import { imageSchema } from "../hotels/schemas/image" diff --git a/apps/scandic-web/server/routers/user/query.ts b/apps/scandic-web/server/routers/user/query.ts index b2f4721b5..1db4ed0ba 100644 --- a/apps/scandic-web/server/routers/user/query.ts +++ b/apps/scandic-web/server/routers/user/query.ts @@ -1,5 +1,6 @@ import { metrics } from "@opentelemetry/api" +import { countries } from "@/constants/countries" import * as api from "@/lib/api" import { dt } from "@/lib/dt" import { @@ -8,7 +9,6 @@ import { safeProtectedProcedure, } from "@/server/trpc" -import { countries } from "@/components/TempDesignSystem/Form/Country/countries" import { cache } from "@/utils/cache" import * as maskValue from "@/utils/maskValue" import { getMembership, getMembershipCards } from "@/utils/user" diff --git a/apps/scandic-web/utils/countries.ts b/apps/scandic-web/utils/countries.ts new file mode 100644 index 000000000..6d6e408f3 --- /dev/null +++ b/apps/scandic-web/utils/countries.ts @@ -0,0 +1,7 @@ +import { countriesMap } from "@/constants/countries" + +export function isValidCountry( + country: string +): country is keyof typeof countriesMap { + return country in countriesMap +} diff --git a/apps/scandic-web/utils/languages.ts b/apps/scandic-web/utils/languages.ts index 14a83ac11..311fd9a24 100644 --- a/apps/scandic-web/utils/languages.ts +++ b/apps/scandic-web/utils/languages.ts @@ -2,20 +2,20 @@ import { z } from "zod" import { Lang } from "@/constants/languages" -export function findLang(pathname: string) { - const langFromPath = Object.values(Lang).find( - (l) => pathname.startsWith(`/${l}/`) || pathname === `/${l}` - ) - - const parsedLang = languageSchema.safeParse(langFromPath) - if (!parsedLang.success) { - return undefined - } - - return parsedLang.data -} - export const languageSchema = z.preprocess( (arg) => (typeof arg === "string" ? arg.toLowerCase() : arg), z.nativeEnum(Lang) ) + +export function isValidLang(lang?: string): lang is Lang { + const result = languageSchema.safeParse(lang) + return result.success +} + +export function findLang(pathname: string): Lang | undefined { + const langFromPath = Object.values(Lang).find( + (l) => pathname.startsWith(`/${l}/`) || pathname === `/${l}` + ) + + return isValidLang(langFromPath) ? langFromPath : undefined +}