Merged in feat/lokalise-rebuild (pull request #2993)

Feat/lokalise rebuild

* chore(lokalise): update translation ids

* chore(lokalise): easier to switch between projects

* chore(lokalise): update translation ids

* .

* .

* .

* .

* .

* .

* chore(lokalise): update translation ids

* chore(lokalise): update translation ids

* .

* .

* .

* chore(lokalise): update translation ids

* chore(lokalise): update translation ids

* .

* .

* chore(lokalise): update translation ids

* chore(lokalise): update translation ids

* chore(lokalise): new translations

* merge

* switch to errors for missing id's

* merge

* sync translations


Approved-by: Linus Flood
This commit is contained in:
Joakim Jäderberg
2025-10-22 11:00:03 +00:00
parent bdfe2ab213
commit aafad9781f
499 changed files with 93363 additions and 99164 deletions

View File

@@ -1,54 +0,0 @@
import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget"
import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { bookingFlowConfig } from "@/constants/bookingFlowConfig"
import { serverClient } from "@/lib/trpc"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import { ClientComponent } from "../../../components/ClientComponent"
type SearchParams<S = object> = {
searchParams: Promise<S & { [key: string]: string }>
}
export default async function Debug(props: SearchParams) {
const searchParams = await props.searchParams
const intl = await getIntl()
const lang = await getLang()
const caller = await serverClient()
const destinations = await caller.autocomplete.destinations({
lang,
includeTypes: ["hotels"],
query: "Göteborg",
})
const hotel = destinations.hits.hotels[0].name
const booking = parseBookingWidgetSearchParams(searchParams)
return (
<div style={{ padding: "20px" }}>
<Typography>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
<p>from booking-flow package:</p>
</Typography>
<BookingWidget booking={booking} lang={lang} config={bookingFlowConfig} />
<hr />
<Typography variant="Title/Decorative/lg">
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
<p>hello world with data: {hotel}</p>
</Typography>
<Typography>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
<p>
translated:
{intl.formatMessage({ defaultMessage: "Map of the city" })}
</p>
</Typography>
<hr />
<ClientComponent />
</div>
)
}

View File

@@ -36,6 +36,7 @@ export async function generateMetadata({
const title = intl.formatMessage( const title = intl.formatMessage(
{ {
id: "alternativeHotels.title",
defaultMessage: "Alternatives for {value}", defaultMessage: "Alternatives for {value}",
}, },
{ {

View File

@@ -36,6 +36,7 @@ export async function generateMetadata({
const title = intl.formatMessage( const title = intl.formatMessage(
{ {
id: "alternativeHotels.title",
defaultMessage: "Alternatives for {value}", defaultMessage: "Alternatives for {value}",
}, },
{ {

View File

@@ -1,27 +0,0 @@
/* eslint-disable formatjs/no-literal-string-in-jsx */
"use client"
import { useIntl } from "react-intl"
import { Lang } from "@scandic-hotels/common/constants/language"
import { trpc } from "@scandic-hotels/trpc/client"
export function ClientComponent() {
const intl = useIntl()
const { data, isLoading } = trpc.autocomplete.destinations.useQuery({
lang: Lang.en,
includeTypes: ["hotels"],
query: "Malmö",
})
return (
<div>
<p>client component</p>
<p>Data: {JSON.stringify(data?.hits?.hotels[0]?.name)}</p>
<p>Is loading: {isLoading ? "Yes" : "No"}</p>
<p>Translated text: </p>
{intl.formatMessage({
defaultMessage: "All-day breakfast",
})}
</div>
)
}

View File

@@ -33,6 +33,7 @@ export async function Footer() {
<p> <p>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "footer.copyright",
defaultMessage: defaultMessage:
"© {currentYear} Scandic Hotels all rights reserved", "© {currentYear} Scandic Hotels all rights reserved",
}, },

View File

@@ -180,6 +180,7 @@ function LanguageSwitcherContent({
<Typography variant={"Title/Subtitle/md"}> <Typography variant={"Title/Subtitle/md"}>
<h3 className={styles.title}> <h3 className={styles.title}>
{intl.formatMessage({ {intl.formatMessage({
id: "common.selectYourLanguage",
defaultMessage: "Select your language", defaultMessage: "Select your language",
})} })}
</h3> </h3>

View File

@@ -38,17 +38,26 @@ export function FooterMenu() {
href={routeToScandicWeb(customerService)[lang]} href={routeToScandicWeb(customerService)[lang]}
className={styles.link} className={styles.link}
> >
{intl.formatMessage({ defaultMessage: "Contact us" })} {intl.formatMessage({
id: "common.contactUs",
defaultMessage: "Contact us",
})}
</Link> </Link>
</Typography> </Typography>
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<Link href={routeToScandicWeb(faq)[lang]} className={styles.link}> <Link href={routeToScandicWeb(faq)[lang]} className={styles.link}>
{intl.formatMessage({ defaultMessage: "FAQ" })} {intl.formatMessage({
id: "common.faq",
defaultMessage: "FAQ",
})}
</Link> </Link>
</Typography> </Typography>
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<Link href={routeToScandicWeb(rates)[lang]} className={styles.link}> <Link href={routeToScandicWeb(rates)[lang]} className={styles.link}>
{intl.formatMessage({ defaultMessage: "Rates" })} {intl.formatMessage({
id: "partnerSas.footer.rates",
defaultMessage: "Rates",
})}
</Link> </Link>
</Typography> </Typography>
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
@@ -56,7 +65,10 @@ export function FooterMenu() {
href={routeToScandicWeb(policies)[lang]} href={routeToScandicWeb(policies)[lang]}
className={styles.link} className={styles.link}
> >
{intl.formatMessage({ defaultMessage: "Policies" })} {intl.formatMessage({
id: "partnerSas.footer.policies",
defaultMessage: "Policies",
})}
</Link> </Link>
</Typography> </Typography>
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
@@ -64,7 +76,10 @@ export function FooterMenu() {
href={routeToScandicWeb(sasEuroBonus)[lang]} href={routeToScandicWeb(sasEuroBonus)[lang]}
className={styles.link} className={styles.link}
> >
{intl.formatMessage({ defaultMessage: "SAS EuroBonus" })} {intl.formatMessage({
id: "partnerSas.sasEuroBonus",
defaultMessage: "SAS EuroBonus",
})}
</Link> </Link>
</Typography> </Typography>
</div> </div>

View File

@@ -14,9 +14,11 @@ export function MobileMenu({ children }: React.PropsWithChildren) {
const intl = useIntl() const intl = useIntl()
const closeMsg = intl.formatMessage({ const closeMsg = intl.formatMessage({
id: "header.closeMenu",
defaultMessage: "Close menu", defaultMessage: "Close menu",
}) })
const openMsg = intl.formatMessage({ const openMsg = intl.formatMessage({
id: "header.openMenu",
defaultMessage: "Open menu", defaultMessage: "Open menu",
}) })
@@ -41,6 +43,7 @@ export function MobileMenu({ children }: React.PropsWithChildren) {
<Dialog <Dialog
className={styles.dialog} className={styles.dialog}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "header.menu",
defaultMessage: "Menu", defaultMessage: "Menu",
})} })}
> >

View File

@@ -38,7 +38,10 @@ export function NavigationMenu({ isMobile = false }: { isMobile?: boolean }) {
{isMobile ? null : ( {isMobile ? null : (
<MaterialIcon icon="call" size={16} color={"CurrentColor"} /> <MaterialIcon icon="call" size={16} color={"CurrentColor"} />
)} )}
{intl.formatMessage({ defaultMessage: "Contact us" })} {intl.formatMessage({
id: "common.contactUs",
defaultMessage: "Contact us",
})}
</Link> </Link>
</Typography> </Typography>

View File

@@ -65,7 +65,12 @@ export function UserMenu({ isMobile = false }: { isMobile?: boolean }) {
: "Body/Supporting text (caption)/smRegular" : "Body/Supporting text (caption)/smRegular"
} }
> >
<span>{intl.formatMessage({ defaultMessage: "Log in" })}</span> <span>
{intl.formatMessage({
id: "partnerSas.menu.login",
defaultMessage: "Log in",
})}
</span>
</Typography> </Typography>
)} )}
</a> </a>
@@ -102,6 +107,7 @@ export function UserMenu({ isMobile = false }: { isMobile?: boolean }) {
type="button" type="button"
className={styles.closeModalBtn} className={styles.closeModalBtn}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "header.closeMenu",
defaultMessage: "Close menu", defaultMessage: "Close menu",
})} })}
onPress={close} onPress={close}
@@ -158,7 +164,10 @@ function UserMenuContent({
<Typography variant={"Title/Subtitle/md"}> <Typography variant={"Title/Subtitle/md"}>
<h3> <h3>
{intl.formatMessage( {intl.formatMessage(
{ defaultMessage: `Hi {fName} {lName}!` }, {
id: "partnerSas.mobileMenu.greeting",
defaultMessage: `Hi {fName} {lName}!`,
},
{ fName: firstName, lName: lastName } { fName: firstName, lName: lastName }
)} )}
</h3> </h3>
@@ -166,7 +175,12 @@ function UserMenuContent({
)} )}
<p className={styles.pointsDetails}> <p className={styles.pointsDetails}>
<Typography variant="Title/Overline/sm"> <Typography variant="Title/Overline/sm">
<span>{intl.formatMessage({ defaultMessage: "EB Points" })}</span> <span>
{intl.formatMessage({
id: "partnerSas.menu.ebPointsTitle",
defaultMessage: "EB Points",
})}
</span>
</Typography> </Typography>
<Typography variant="Title/Overline/sm"> <Typography variant="Title/Overline/sm">
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
@@ -176,6 +190,7 @@ function UserMenuContent({
<span> <span>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "partnerSas.menu.ebPoints",
defaultMessage: "{points} points", defaultMessage: "{points} points",
}, },
{ {
@@ -190,7 +205,10 @@ function UserMenuContent({
<Typography variant={"Link/md"} className={styles.logoutLink}> <Typography variant={"Link/md"} className={styles.logoutLink}>
{/* Link triggers rsc which doesn't reload complete page and shows logged in even after logout */} {/* Link triggers rsc which doesn't reload complete page and shows logged in even after logout */}
<a href={`/${lang}/logout`}> <a href={`/${lang}/logout`}>
{intl.formatMessage({ defaultMessage: "Log out" })} {intl.formatMessage({
id: "common.logOut",
defaultMessage: "Log out",
})}
</a> </a>
</Typography> </Typography>
</> </>

View File

@@ -100,7 +100,7 @@ export default defineConfig([
"formatjs/no-multiple-whitespaces": ["error"], "formatjs/no-multiple-whitespaces": ["error"],
"formatjs/no-multiple-plurals": ["error"], "formatjs/no-multiple-plurals": ["error"],
"formatjs/no-invalid-icu": ["error"], "formatjs/no-invalid-icu": ["error"],
"formatjs/no-id": ["error"], "formatjs/enforce-id": ["error"],
"formatjs/no-complex-selectors": ["error"], "formatjs/no-complex-selectors": ["error"],
"formatjs/no-useless-message": ["error"], "formatjs/no-useless-message": ["error"],
"formatjs/prefer-pound-in-plural": ["error"], "formatjs/prefer-pound-in-plural": ["error"],

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
{ {
"WcBpRV": [ "selectRate.roomSizeMinToMax": [
{ {
"type": 1, "type": 1,
"value": "roomSizeMin" "value": "roomSizeMin"

File diff suppressed because it is too large Load Diff

View File

@@ -63,6 +63,7 @@ export const editProfile = protectedServerActionProcedure
message: issue.message, message: issue.message,
})), })),
message: intl.formatMessage({ message: intl.formatMessage({
id: "editProfile.validationErrorMessage",
defaultMessage: defaultMessage:
"An error occurred when trying to update your profile.", "An error occurred when trying to update your profile.",
}), }),
@@ -84,6 +85,7 @@ export const editProfile = protectedServerActionProcedure
data: input, data: input,
issues: [], issues: [],
message: intl.formatMessage({ message: intl.formatMessage({
id: "editProfile.validationErrorMessage",
defaultMessage: defaultMessage:
"An error occurred when trying to update your profile.", "An error occurred when trying to update your profile.",
}), }),
@@ -143,6 +145,7 @@ export const editProfile = protectedServerActionProcedure
return { return {
data: input, data: input,
message: intl.formatMessage({ message: intl.formatMessage({
id: "editProfile.successMessage",
defaultMessage: "Successfully updated profile!", defaultMessage: "Successfully updated profile!",
}), }),
status: Status.success, status: Status.success,
@@ -179,6 +182,7 @@ export const editProfile = protectedServerActionProcedure
data: input, data: input,
issues: [], issues: [],
message: intl.formatMessage({ message: intl.formatMessage({
id: "editProfile.validationErrorMessage",
defaultMessage: defaultMessage:
"An error occurred when trying to update your profile.", "An error occurred when trying to update your profile.",
}), }),
@@ -216,6 +220,7 @@ export const editProfile = protectedServerActionProcedure
message: issue.message, message: issue.message,
})), })),
message: intl.formatMessage({ message: intl.formatMessage({
id: "editProfile.validationErrorMessage",
defaultMessage: defaultMessage:
"An error occurred when trying to update your profile.", "An error occurred when trying to update your profile.",
}), }),
@@ -226,6 +231,7 @@ export const editProfile = protectedServerActionProcedure
return { return {
data: validatedData.data, data: validatedData.data,
message: intl.formatMessage({ message: intl.formatMessage({
id: "editProfile.successMessage",
defaultMessage: "Successfully updated profile!", defaultMessage: "Successfully updated profile!",
}), }),
status: Status.success, status: Status.success,

View File

@@ -25,6 +25,7 @@ export default function Error({
<strong> <strong>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "myPages.breadcrumbsError",
defaultMessage: "Breadcrumbs failed for this page ({errorId})", defaultMessage: "Breadcrumbs failed for this page ({errorId})",
}, },
{ {

View File

@@ -25,6 +25,7 @@ export default function Error({
<strong> <strong>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "myPages.errorLoadingPage",
defaultMessage: "Error loading this page ({errorId})", defaultMessage: "Error loading this page ({errorId})",
}, },
{ {

View File

@@ -64,6 +64,7 @@ export default async function MyPages({}: PageArgs<
) : ( ) : (
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "myPages.missingContent",
defaultMessage: "No content published", defaultMessage: "No content published",
})} })}
</p> </p>

View File

@@ -28,6 +28,7 @@ export default function Error({
<strong> <strong>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "destinationOverviewPage.errorOccurred",
defaultMessage: "An error occurred ({errorId})", defaultMessage: "An error occurred ({errorId})",
}, },
{ {

View File

@@ -38,6 +38,7 @@ export async function generateMetadata({
const title = intl.formatMessage( const title = intl.formatMessage(
{ {
id: "alternativeHotels.title",
defaultMessage: "Alternatives for {value}", defaultMessage: "Alternatives for {value}",
}, },
{ {

View File

@@ -40,6 +40,7 @@ export async function generateMetadata({
const title = intl.formatMessage( const title = intl.formatMessage(
{ {
id: "alternativeHotels.title",
defaultMessage: "Alternatives for {value}", defaultMessage: "Alternatives for {value}",
}, },
{ {

View File

@@ -17,6 +17,9 @@ export async function generateMetadata() {
const intl = await getIntl() const intl = await getIntl()
return { return {
title: intl.formatMessage({ defaultMessage: "Find booking" }), title: intl.formatMessage({
id: "booking.findBooking",
defaultMessage: "Find booking",
}),
} }
} }

View File

@@ -63,6 +63,7 @@ export default function Error({
<section className={styles.layout}> <section className={styles.layout}>
<div className={styles.content}> <div className={styles.content}>
{intl.formatMessage({ {intl.formatMessage({
id: "errorMessage.somethingWentWrong",
defaultMessage: "Something went wrong!", defaultMessage: "Something went wrong!",
})} })}
{env.NEXT_PUBLIC_NODE_ENV === "development" && ( {env.NEXT_PUBLIC_NODE_ENV === "development" && (

View File

@@ -47,6 +47,7 @@ export default function LinkEmploymentErrorPage() {
/> />
<span className={styles.navBackText}> <span className={styles.navBackText}>
{intl.formatMessage({ {intl.formatMessage({
id: "common.goBack",
defaultMessage: "Go back", defaultMessage: "Go back",
})} })}
</span> </span>
@@ -69,6 +70,7 @@ export default function LinkEmploymentErrorPage() {
<Typography variant="Title/Subtitle/md"> <Typography variant="Title/Subtitle/md">
<h3> <h3>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEmploymentError.contactHeading",
defaultMessage: "Contact our member service", defaultMessage: "Contact our member service",
})} })}
</h3> </h3>
@@ -102,9 +104,11 @@ export default function LinkEmploymentErrorPage() {
const getErrorContent = (error: string | null, intl: IntlShape) => { const getErrorContent = (error: string | null, intl: IntlShape) => {
const defaultErrorContent = { const defaultErrorContent = {
heading: intl.formatMessage({ heading: intl.formatMessage({
id: "linkEmploymentError.genericHeading",
defaultMessage: "Your account could not be connected", defaultMessage: "Your account could not be connected",
}), }),
message: intl.formatMessage({ message: intl.formatMessage({
id: "linkEmploymentError.genericMessage",
defaultMessage: defaultMessage:
"We couldn't connect your accounts. Please contact us and we'll help you resolve this.", "We couldn't connect your accounts. Please contact us and we'll help you resolve this.",
}), }),
@@ -114,9 +118,11 @@ const getErrorContent = (error: string | null, intl: IntlShape) => {
case "unable_to_verify_employee_id": case "unable_to_verify_employee_id":
return { return {
heading: intl.formatMessage({ heading: intl.formatMessage({
id: "linkEmploymentError.notEligibleHeading",
defaultMessage: "You're not eligible for employee benefits", defaultMessage: "You're not eligible for employee benefits",
}), }),
message: intl.formatMessage({ message: intl.formatMessage({
id: "linkEmploymentError.notEligibleMessage",
defaultMessage: defaultMessage:
"This may be because your employment has not yet started, has ended, or you are a consultant. If you believe this is an error, please contact us for assistance.", "This may be because your employment has not yet started, has ended, or you are a consultant. If you believe this is an error, please contact us for assistance.",
}), }),
@@ -124,10 +130,12 @@ const getErrorContent = (error: string | null, intl: IntlShape) => {
case "employee_id_already_linked": case "employee_id_already_linked":
return { return {
heading: intl.formatMessage({ heading: intl.formatMessage({
id: "linkEmploymentError.alreadyLinkedHeading",
defaultMessage: defaultMessage:
"Employee number already linked to another Scandic Friends membership.", "Employee number already linked to another Scandic Friends membership.",
}), }),
message: intl.formatMessage({ message: intl.formatMessage({
id: "linkEmploymentError.alreadyLinkedMessage",
defaultMessage: defaultMessage:
"If you believe this is an error, please contact us for assistance.", "If you believe this is an error, please contact us for assistance.",
}), }),

View File

@@ -25,6 +25,7 @@ export function AlreadyLinkedError() {
<Typography variant="Title/Subtitle/lg"> <Typography variant="Title/Subtitle/lg">
<h1> <h1>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.alreadyLinkedHeading",
defaultMessage: defaultMessage:
"Your Scandic Friends and SAS EuroBonus accounts are already connected", "Your Scandic Friends and SAS EuroBonus accounts are already connected",
})} })}
@@ -33,6 +34,7 @@ export function AlreadyLinkedError() {
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.alreadyLinkedMessage",
defaultMessage: defaultMessage:
"Great news! You can go straight to My Pages to explore all your perks and rewards!", "Great news! You can go straight to My Pages to explore all your perks and rewards!",
})} })}
@@ -46,6 +48,7 @@ export function AlreadyLinkedError() {
size={"Large"} size={"Large"}
> >
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.viewLinkedAccountsButton",
defaultMessage: "View your linked accounts", defaultMessage: "View your linked accounts",
})} })}
</ButtonLink> </ButtonLink>

View File

@@ -26,6 +26,7 @@ export function DateOfBirthError() {
<Typography variant="Title/Subtitle/lg"> <Typography variant="Title/Subtitle/lg">
<h1> <h1>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.dateOfBirthErrorHeading",
defaultMessage: "Date of birth not matching", defaultMessage: "Date of birth not matching",
})} })}
</h1> </h1>
@@ -33,6 +34,7 @@ export function DateOfBirthError() {
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.couldntConnectAccountsErrorMessage",
defaultMessage: defaultMessage:
"We couldnt connect your accounts. Please contact us and well help you resolve this.", "We couldnt connect your accounts. Please contact us and well help you resolve this.",
})} })}
@@ -41,6 +43,7 @@ export function DateOfBirthError() {
<Button theme="base" asChild> <Button theme="base" asChild>
<Link href={profile[lang]}> <Link href={profile[lang]}>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.viewYourDetailsButton",
defaultMessage: "View your details", defaultMessage: "View your details",
})} })}
</Link> </Link>

View File

@@ -19,6 +19,7 @@ export function SASModalDivider() {
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<span> <span>
{intl.formatMessage({ {intl.formatMessage({
id: "common.or",
defaultMessage: "or", defaultMessage: "or",
})} })}
</span> </span>
@@ -31,6 +32,7 @@ export function SASModalContactBlock() {
const intl = useIntl() const intl = useIntl()
const phone = intl.formatMessage({ const phone = intl.formatMessage({
id: "linkEuroBonusAccount.contactPhoneNumber",
defaultMessage: "+46 8 517 517 00", defaultMessage: "+46 8 517 517 00",
}) })
@@ -39,6 +41,7 @@ export function SASModalContactBlock() {
<Typography variant="Title/Subtitle/md"> <Typography variant="Title/Subtitle/md">
<h4 className={styles.contactBlockTitle}> <h4 className={styles.contactBlockTitle}>
{intl.formatMessage({ {intl.formatMessage({
id: "common.contactUs",
defaultMessage: "Contact us", defaultMessage: "Contact us",
})} })}
</h4> </h4>

View File

@@ -13,6 +13,7 @@ export function TooManyCodesError() {
return ( return (
<GenericError <GenericError
title={intl.formatMessage({ title={intl.formatMessage({
id: "linkEuroBonusAccount.tooManyCodesErrorHeading",
defaultMessage: "Youve requested too many codes", defaultMessage: "Youve requested too many codes",
})} })}
variant="info" variant="info"
@@ -20,12 +21,14 @@ export function TooManyCodesError() {
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.tooManyFailedAttemptsErrorMessage",
defaultMessage: "Please wait 1 hour before trying again.", defaultMessage: "Please wait 1 hour before trying again.",
})} })}
</p> </p>
</Typography> </Typography>
<Button theme="base" disabled> <Button theme="base" disabled>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.sendNewCodeButton",
defaultMessage: "Send new code", defaultMessage: "Send new code",
})} })}
</Button> </Button>

View File

@@ -13,6 +13,7 @@ export function TooManyFailedAttemptsError() {
return ( return (
<GenericError <GenericError
title={intl.formatMessage({ title={intl.formatMessage({
id: "linkEuroBonusAccount.tooManyFailedAttemptsErrorHeading",
defaultMessage: "Too many failed attempts.", defaultMessage: "Too many failed attempts.",
})} })}
variant="info" variant="info"
@@ -20,12 +21,14 @@ export function TooManyFailedAttemptsError() {
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.tooManyFailedAttemptsErrorMessage",
defaultMessage: "Please wait 1 hour before trying again.", defaultMessage: "Please wait 1 hour before trying again.",
})} })}
</p> </p>
</Typography> </Typography>
<Button theme="base" disabled> <Button theme="base" disabled>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.sendNewCodeButton",
defaultMessage: "Send new code", defaultMessage: "Send new code",
})} })}
</Button> </Button>

View File

@@ -13,12 +13,14 @@ export function UnlinkError() {
return ( return (
<GenericError <GenericError
title={intl.formatMessage({ title={intl.formatMessage({
id: "unlinkEuroBonusAccount.errorHeading",
defaultMessage: "We could not unlink your accounts", defaultMessage: "We could not unlink your accounts",
})} })}
> >
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "unlinkEuroBonusAccount.errorMessage",
defaultMessage: defaultMessage:
"We couldnt unlink your accounts. Please contact us and well help you resolve this.", "We couldnt unlink your accounts. Please contact us and well help you resolve this.",
})} })}

View File

@@ -27,12 +27,14 @@ export default function Error({
return ( return (
<GenericError <GenericError
title={intl.formatMessage({ title={intl.formatMessage({
id: "linkEuroBonusAccount.genericErrorHeading",
defaultMessage: "Something went wrong", defaultMessage: "Something went wrong",
})} })}
> >
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.genericErrorMessage",
defaultMessage: "Please try again later", defaultMessage: "Please try again later",
})} })}
</p> </p>

View File

@@ -13,9 +13,10 @@ import { UnlinkError } from "../components/UnlinkError"
import type { LangParams, PageArgs, SearchParams } from "@/types/params" import type { LangParams, PageArgs, SearchParams } from "@/types/params"
export default async function Page( export default async function Page(
props: PageArgs<LangParams> & SearchParams<{ errorCode?: "dateOfBirthMismatch" }> props: PageArgs<LangParams> &
SearchParams<{ errorCode?: "dateOfBirthMismatch" }>
) { ) {
const searchParams = await props.searchParams; const searchParams = await props.searchParams
const intl = await getIntl() const intl = await getIntl()
const { errorCode } = searchParams const { errorCode } = searchParams
@@ -43,12 +44,14 @@ export default async function Page(
return ( return (
<GenericError <GenericError
title={intl.formatMessage({ title={intl.formatMessage({
id: "linkEuroBonusAccount.genericErrorTitle",
defaultMessage: "We could not connect your accounts", defaultMessage: "We could not connect your accounts",
})} })}
> >
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.couldntConnectAccountsErrorMessage",
defaultMessage: defaultMessage:
"We couldnt connect your accounts. Please contact us and well help you resolve this.", "We couldnt connect your accounts. Please contact us and well help you resolve this.",
})} })}

View File

@@ -33,11 +33,13 @@ export default async function SasXScandicLayout(
<ArrowLeft height={20} width={20} /> <ArrowLeft height={20} width={20} />
<span className={styles.long}> <span className={styles.long}>
{intl.formatMessage({ {intl.formatMessage({
id: "header.backToScandicHotelsCom",
defaultMessage: "Back to scandichotels.com", defaultMessage: "Back to scandichotels.com",
})} })}
</span> </span>
<span className={styles.short}> <span className={styles.short}>
{intl.formatMessage({ {intl.formatMessage({
id: "common.back",
defaultMessage: "Back", defaultMessage: "Back",
})} })}
</span> </span>
@@ -55,6 +57,7 @@ async function MainMenuLogo() {
return ( return (
<Logo <Logo
alt={intl.formatMessage({ alt={intl.formatMessage({
id: "header.backToScandicHotelsCom",
defaultMessage: "Back to scandichotels.com", defaultMessage: "Back to scandichotels.com",
})} })}
/> />

View File

@@ -62,6 +62,7 @@ export function LinkAccountForm({
<Typography variant="Title/Subtitle/lg"> <Typography variant="Title/Subtitle/lg">
<h3> <h3>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.linkYourAccountsTitle",
defaultMessage: "Link your accounts", defaultMessage: "Link your accounts",
})} })}
</h3> </h3>
@@ -73,6 +74,7 @@ export function LinkAccountForm({
{userDateOfBirth {userDateOfBirth
? intl.formatMessage( ? intl.formatMessage(
{ {
id: "linkEuroBonusAccount.birthDate",
defaultMessage: defaultMessage:
"Birth date: {dateOfBirth, date, ::MMMM d yyyy}", "Birth date: {dateOfBirth, date, ::MMMM d yyyy}",
}, },
@@ -81,6 +83,7 @@ export function LinkAccountForm({
} }
) )
: intl.formatMessage({ : intl.formatMessage({
id: "linkEuroBonusAccount.birthDateMissing",
defaultMessage: "Birth date is missing", defaultMessage: "Birth date is missing",
})} })}
</p> </p>
@@ -88,6 +91,7 @@ export function LinkAccountForm({
<Typography variant="Label/xsRegular"> <Typography variant="Label/xsRegular">
<p className={styles.dateOfBirthDescription}> <p className={styles.dateOfBirthDescription}>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.birthDateDescription",
defaultMessage: defaultMessage:
"We require your birth date in order to link your Scandic Friends account with your SAS EuroBonus account. Please check that it is correct.", "We require your birth date in order to link your Scandic Friends account with your SAS EuroBonus account. Please check that it is correct.",
})} })}
@@ -100,6 +104,7 @@ export function LinkAccountForm({
textDecoration="underline" textDecoration="underline"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.editPersonalDetailsLink",
defaultMessage: "Edit your personal details", defaultMessage: "Edit your personal details",
})} })}
@@ -113,6 +118,7 @@ export function LinkAccountForm({
required: { required: {
value: true, value: true,
message: intl.formatMessage({ message: intl.formatMessage({
id: "common.mustAcceptTermsError",
defaultMessage: "You must accept the terms and conditions", defaultMessage: "You must accept the terms and conditions",
}), }),
}, },
@@ -122,6 +128,7 @@ export function LinkAccountForm({
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "booking.acceptBookingTerms",
defaultMessage: "I accept the booking and cancellation terms", defaultMessage: "I accept the booking and cancellation terms",
})} })}
</p> </p>
@@ -131,6 +138,7 @@ export function LinkAccountForm({
<p className={styles.termsDescription}> <p className={styles.termsDescription}>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "linkEuroBonusAccount.termsAndConditionsDescription",
defaultMessage: defaultMessage:
"By linking your accounts you accept the <sasScandicTermsAndConditionsLink>Terms & Conditions for Scandic Friends and SAS EuroBonus Account Linking</sasScandicTermsAndConditionsLink>.", "By linking your accounts you accept the <sasScandicTermsAndConditionsLink>Terms & Conditions for Scandic Friends and SAS EuroBonus Account Linking</sasScandicTermsAndConditionsLink>.",
}, },
@@ -158,6 +166,7 @@ export function LinkAccountForm({
disabled={isPending || disableSubmit} disabled={isPending || disableSubmit}
> >
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.linkMyAccountsButton",
defaultMessage: "Link my accounts", defaultMessage: "Link my accounts",
})} })}
</Button> </Button>

View File

@@ -26,6 +26,7 @@ export default async function SASxScandicLinkPage(props: PageArgs<LangParams>) {
<Typography variant="Title/Subtitle/lg"> <Typography variant="Title/Subtitle/lg">
<h1> <h1>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.successTitle",
defaultMessage: "Your accounts are linked", defaultMessage: "Your accounts are linked",
})} })}
</h1> </h1>
@@ -34,6 +35,7 @@ export default async function SASxScandicLinkPage(props: PageArgs<LangParams>) {
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.successMessage",
defaultMessage: "We successfully connected your accounts!", defaultMessage: "We successfully connected your accounts!",
})} })}
</p> </p>
@@ -41,6 +43,7 @@ export default async function SASxScandicLinkPage(props: PageArgs<LangParams>) {
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.redirectMyPagesMessage",
defaultMessage: "Redirecting you to My Pages.", defaultMessage: "Redirecting you to My Pages.",
})} })}
</p> </p>

View File

@@ -54,14 +54,17 @@ export default async function SASxScandicLoginPage(
const intentDescriptions: Record<Intent, string> = { const intentDescriptions: Record<Intent, string> = {
link: intl.formatMessage({ link: intl.formatMessage({
id: "linkEuroBonusAccount.loginRequired",
defaultMessage: defaultMessage:
"Log in to your SAS EuroBonus account to confirm account linking.", "Log in to your SAS EuroBonus account to confirm account linking.",
}), }),
unlink: intl.formatMessage({ unlink: intl.formatMessage({
id: "unlinkEuroBonusAccount.loginRequired",
defaultMessage: defaultMessage:
"Log in to your SAS EuroBonus account to confirm account unlinking.", "Log in to your SAS EuroBonus account to confirm account unlinking.",
}), }),
transfer: intl.formatMessage({ transfer: intl.formatMessage({
id: "transferEuroBonusPoints.loginRequired",
defaultMessage: defaultMessage:
"In order to exchange your points, we'll ask you to sign in to your SAS EuroBonus account.", "In order to exchange your points, we'll ask you to sign in to your SAS EuroBonus account.",
}), }),
@@ -80,6 +83,7 @@ export default async function SASxScandicLoginPage(
<Typography variant="Title/Subtitle/lg"> <Typography variant="Title/Subtitle/lg">
<h1> <h1>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.redirectingToSAS",
defaultMessage: "Redirecting you to SAS", defaultMessage: "Redirecting you to SAS",
})} })}
</h1> </h1>
@@ -92,6 +96,7 @@ export default async function SASxScandicLoginPage(
<Footnote textAlign="center"> <Footnote textAlign="center">
{intl.formatMessage( {intl.formatMessage(
{ {
id: "linkEuroBonusAccount.manualRedirectLinkMessage",
defaultMessage: defaultMessage:
"If you are not redirected automatically, please <loginLink>click here</loginLink>.", "If you are not redirected automatically, please <loginLink>click here</loginLink>.",
}, },

View File

@@ -56,6 +56,7 @@ export default function OneTimePasswordForm({
const cause = requestOtp.error?.data?.cause as RequestOtpError const cause = requestOtp.error?.data?.cause as RequestOtpError
const title = intl.formatMessage({ const title = intl.formatMessage({
id: "linkEuroBonusAccount.oneTimePasswordGenericError",
defaultMessage: "Error requesting OTP", defaultMessage: "Error requesting OTP",
}) })
const body = getRequestErrorBody(intl, cause?.errorCode) const body = getRequestErrorBody(intl, cause?.errorCode)
@@ -123,10 +124,12 @@ export default function OneTimePasswordForm({
const errorMessages: Record<OtpError, ReactNode> = { const errorMessages: Record<OtpError, ReactNode> = {
invalidCode: intl.formatMessage({ invalidCode: intl.formatMessage({
id: "linkEuroBonusAccount.invalidOtpCodeMessage",
defaultMessage: "The code you've entered is incorrect.", defaultMessage: "The code you've entered is incorrect.",
}), }),
expiredCode: intl.formatMessage( expiredCode: intl.formatMessage(
{ {
id: "linkEuroBonusAccount.expiredOtpCodeMessage",
defaultMessage: defaultMessage:
"This code has expired. <resendOtpLink>Send new code.</resendOtpLink>", "This code has expired. <resendOtpLink>Send new code.</resendOtpLink>",
}, },
@@ -188,6 +191,7 @@ export default function OneTimePasswordForm({
<p> <p>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "linkEuroBonusAccount.didNotReceiveCodeMessage",
defaultMessage: defaultMessage:
"Didn't receive a code? <resendOtpLink>Resend code</resendOtpLink>", "Didn't receive a code? <resendOtpLink>Resend code</resendOtpLink>",
}, },
@@ -226,10 +230,12 @@ const getRequestErrorBody = (
switch (errorCode) { switch (errorCode) {
case "TOO_MANY_REQUESTS": case "TOO_MANY_REQUESTS":
return intl.formatMessage({ return intl.formatMessage({
id: "linkEuroBonusAccount.tooManyOtpRequestsMessage",
defaultMessage: "Too many requests. Please try again later.", defaultMessage: "Too many requests. Please try again later.",
}) })
default: default:
return intl.formatMessage({ return intl.formatMessage({
id: "linkEuroBonusAccount.requestOtpGenericErrorMessage",
defaultMessage: "An error occurred while requesting a new OTP", defaultMessage: "An error occurred while requesting a new OTP",
}) })
} }

View File

@@ -15,6 +15,7 @@ export default function Loading() {
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.loadingMessage",
defaultMessage: "Hang tight...", defaultMessage: "Hang tight...",
})} })}
</p> </p>

View File

@@ -115,6 +115,7 @@ export default async function SASxScandicOneTimePasswordPage(
const intentDescriptions: Record<Intent, ReactNode> = { const intentDescriptions: Record<Intent, ReactNode> = {
link: intl.formatMessage( link: intl.formatMessage(
{ {
id: "linkEuroBonusAccount.oneTimePasswordInputDescription",
defaultMessage: defaultMessage:
"Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to confirm your account linking.", "Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to confirm your account linking.",
}, },
@@ -122,6 +123,7 @@ export default async function SASxScandicOneTimePasswordPage(
), ),
unlink: intl.formatMessage( unlink: intl.formatMessage(
{ {
id: "unlinkEuroBonusAccount.oneTimePasswordInputDescription",
defaultMessage: defaultMessage:
"Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to unlink your accounts.", "Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to unlink your accounts.",
}, },
@@ -129,6 +131,7 @@ export default async function SASxScandicOneTimePasswordPage(
), ),
transfer: intl.formatMessage( transfer: intl.formatMessage(
{ {
id: "transferEuroBonusPoints.oneTimePasswordInputDescription",
defaultMessage: defaultMessage:
"Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to transfer your points.", "Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to transfer your points.",
}, },
@@ -139,10 +142,12 @@ export default async function SASxScandicOneTimePasswordPage(
return ( return (
<OneTimePasswordForm <OneTimePasswordForm
heading={intl.formatMessage({ heading={intl.formatMessage({
id: "linkEuroBonusAccount.oneTimePasswordHeading",
defaultMessage: "Verification code", defaultMessage: "Verification code",
})} })}
ingress={intentDescriptions[intent]} ingress={intentDescriptions[intent]}
footnote={intl.formatMessage({ footnote={intl.formatMessage({
id: "linkEuroBonusAccount.oneTimePasswordDescription",
defaultMessage: "This verification is needed for additional security.", defaultMessage: "This verification is needed for additional security.",
})} })}
otpLength={6} otpLength={6}

View File

@@ -48,6 +48,7 @@ export default async function SASxScandicTransferSuccessPage(
<Typography variant="Title/Subtitle/lg"> <Typography variant="Title/Subtitle/lg">
<h1> <h1>
{intl.formatMessage({ {intl.formatMessage({
id: "transferEuroBonusPoints.successMessage",
defaultMessage: "Point exchange completed!", defaultMessage: "Point exchange completed!",
})} })}
</h1> </h1>
@@ -62,6 +63,7 @@ export default async function SASxScandicTransferSuccessPage(
> >
<Link href={partnerSas[params.lang]} color="none"> <Link href={partnerSas[params.lang]} color="none">
{intl.formatMessage({ {intl.formatMessage({
id: "transferEuroBonusPoints.backToMyPagesButton",
defaultMessage: "Go back to My Pages", defaultMessage: "Go back to My Pages",
})} })}
</Link> </Link>
@@ -91,6 +93,7 @@ async function TransactionCard({
<Typography variant="Title/Subtitle/md"> <Typography variant="Title/Subtitle/md">
<h2> <h2>
{intl.formatMessage({ {intl.formatMessage({
id: "transferEuroBonusPoints.transactionTitle",
defaultMessage: "Your transaction", defaultMessage: "Your transaction",
})} })}
</h2> </h2>
@@ -100,6 +103,7 @@ async function TransactionCard({
<Typography variant="Title/Overline/sm"> <Typography variant="Title/Overline/sm">
<h3> <h3>
{intl.formatMessage({ {intl.formatMessage({
id: "transferEuroBonusPoints.pointsAddedTitle",
defaultMessage: "Points added", defaultMessage: "Points added",
})} })}
</h3> </h3>
@@ -113,6 +117,7 @@ async function TransactionCard({
<Typography variant="Title/Overline/sm"> <Typography variant="Title/Overline/sm">
<h3> <h3>
{intl.formatMessage({ {intl.formatMessage({
id: "transferEuroBonusPoints.newTotalTitle",
defaultMessage: "Your new total", defaultMessage: "Your new total",
})} })}
</h3> </h3>
@@ -128,6 +133,7 @@ async function TransactionCard({
<Typography variant="Body/Paragraph/mdBold"> <Typography variant="Body/Paragraph/mdBold">
<h3> <h3>
{intl.formatMessage({ {intl.formatMessage({
id: "transferEuroBonusPoints.bonusNightAvailableTitle",
defaultMessage: "You have enough points for a reward night!", defaultMessage: "You have enough points for a reward night!",
})} })}
</h3> </h3>
@@ -135,6 +141,7 @@ async function TransactionCard({
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "transferEuroBonusPoints.bonusNightAvailableDescription",
defaultMessage: defaultMessage:
"Redeem your points for cozy stays, delicious meals at our restaurants, or hotel extras to elevate your stay!", "Redeem your points for cozy stays, delicious meals at our restaurants, or hotel extras to elevate your stay!",
})} })}
@@ -152,6 +159,7 @@ async function TransactionCard({
{/* TODO correct link */} {/* TODO correct link */}
<Link href={hotelreservation(lang)} color="none"> <Link href={hotelreservation(lang)} color="none">
{intl.formatMessage({ {intl.formatMessage({
id: "transferEuroBonusPoints.bookNowButton",
defaultMessage: "Book now", defaultMessage: "Book now",
})} })}
{ {
@@ -183,6 +191,7 @@ async function TotalPoints() {
{"= "} {"= "}
{intl.formatMessage( {intl.formatMessage(
{ {
id: "transferEuroBonusPoints.pointsResultText",
defaultMessage: "{points, number} points", defaultMessage: "{points, number} points",
}, },
{ {

View File

@@ -28,6 +28,7 @@ export default async function SASxScandicUnlinkSuccessPage(
<Typography variant="Title/Subtitle/lg"> <Typography variant="Title/Subtitle/lg">
<h1> <h1>
{intl.formatMessage({ {intl.formatMessage({
id: "unlinkEuroBonusAccount.successTitle",
defaultMessage: "Your accounts are now unlinked", defaultMessage: "Your accounts are now unlinked",
})} })}
</h1> </h1>
@@ -36,6 +37,7 @@ export default async function SASxScandicUnlinkSuccessPage(
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "linkEuroBonusAccount.redirectMyPagesMessage",
defaultMessage: "Redirecting you to My Pages.", defaultMessage: "Redirecting you to My Pages.",
})} })}
</p> </p>

View File

@@ -24,6 +24,7 @@ export default async function Layout(
return ( return (
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "webview.missingUserError",
defaultMessage: "Error: No user could be loaded", defaultMessage: "Error: No user could be loaded",
})} })}
</p> </p>
@@ -46,6 +47,7 @@ export default async function Layout(
return ( return (
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "webview.userNotFoundError",
defaultMessage: "Error: user not found", defaultMessage: "Error: user not found",
})} })}
</p> </p>
@@ -54,6 +56,7 @@ export default async function Layout(
return ( return (
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "webview.genericUserError",
defaultMessage: "Unknown error occurred loading user", defaultMessage: "Unknown error occurred loading user",
})} })}
</p> </p>

View File

@@ -83,17 +83,20 @@ export default function CampaignHotelListingClient({
} }
let buttonText = intl.formatMessage({ let buttonText = intl.formatMessage({
id: "common.showMore",
defaultMessage: "Show more", defaultMessage: "Show more",
}) })
let iconDirection: MaterialIconProps["icon"] = "keyboard_arrow_down" let iconDirection: MaterialIconProps["icon"] = "keyboard_arrow_down"
if (visibleCount === activeHotels.length) { if (visibleCount === activeHotels.length) {
buttonText = intl.formatMessage({ buttonText = intl.formatMessage({
id: "common.showLess",
defaultMessage: "Show less", defaultMessage: "Show less",
}) })
iconDirection = "keyboard_arrow_up" iconDirection = "keyboard_arrow_up"
} else if (canShowAll) { } else if (canShowAll) {
buttonText = intl.formatMessage({ buttonText = intl.formatMessage({
id: "common.showAll",
defaultMessage: "Show all", defaultMessage: "Show all",
}) })
} }

View File

@@ -40,6 +40,7 @@ export default function HotelListingItem({
sizes="(min-width: 768px) 450px, 100vw" sizes="(min-width: 768px) 450px, 100vw"
title={intl.formatMessage( title={intl.formatMessage(
{ {
id: "common.imageGalleryWithTitle",
defaultMessage: "{title} - Image gallery", defaultMessage: "{title} - Image gallery",
}, },
{ title: hotel.name } { title: hotel.name }
@@ -77,6 +78,7 @@ export default function HotelListingItem({
<span> <span>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "common.kmToCityCenter",
defaultMessage: "{number} km to city center", defaultMessage: "{number} km to city center",
}, },
{ {
@@ -121,6 +123,7 @@ export default function HotelListingItem({
typography="Body/Supporting text (caption)/smBold" typography="Body/Supporting text (caption)/smBold"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "destination.seeHotelDetails",
defaultMessage: "See hotel details", defaultMessage: "See hotel details",
})} })}
</ButtonLink> </ButtonLink>

View File

@@ -46,13 +46,15 @@ export default async function CampaignHotelListing({
const sortItems: HotelSortItem[] = [ const sortItems: HotelSortItem[] = [
{ {
label: intl.formatMessage({ label: intl.formatMessage({
id: "common.name",
defaultMessage: "Name", defaultMessage: "Name",
}), }),
value: HotelSortOption.Name, value: HotelSortOption.Name,
}, },
{ {
label: intl.formatMessage({ label: intl.formatMessage({
defaultMessage: "Tripadvisor rating", id: "common.tripAdvisorRating",
defaultMessage: "TripAdvisor rating",
}), }),
value: HotelSortOption.TripAdvisorRating, value: HotelSortOption.TripAdvisorRating,
}, },

View File

@@ -15,6 +15,7 @@ export default async function HowItWorks({ dynamic_content }: HowItWorksProps) {
<section className={styles.container}> <section className={styles.container}>
<Title level="h3"> <Title level="h3">
{intl.formatMessage({ {intl.formatMessage({
id: "common.howItWorks",
defaultMessage: "How it works", defaultMessage: "How it works",
})} })}
</Title> </Title>

View File

@@ -34,9 +34,11 @@ export default function Filter({
items={countryFilters} items={countryFilters}
defaultSelectedKey={""} defaultSelectedKey={""}
label={intl.formatMessage({ label={intl.formatMessage({
id: "common.country",
defaultMessage: "Country", defaultMessage: "Country",
})} })}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "common.country",
defaultMessage: "Country", defaultMessage: "Country",
})} })}
name="country" name="country"
@@ -46,9 +48,11 @@ export default function Filter({
items={cityFilters} items={cityFilters}
defaultSelectedKey={""} defaultSelectedKey={""}
label={intl.formatMessage({ label={intl.formatMessage({
id: "jobylonFeed.cityFilterLabel",
defaultMessage: "Location (shown in local language)", defaultMessage: "Location (shown in local language)",
})} })}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "jobylonFeed.cityFilterLabel",
defaultMessage: "Location (shown in local language)", defaultMessage: "Location (shown in local language)",
})} })}
name="city" name="city"
@@ -58,9 +62,11 @@ export default function Filter({
items={departmentFilters} items={departmentFilters}
defaultSelectedKey={""} defaultSelectedKey={""}
label={intl.formatMessage({ label={intl.formatMessage({
id: "jobylonFeed.departmentFilterLabel",
defaultMessage: "Hotel or office", defaultMessage: "Hotel or office",
})} })}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "jobylonFeed.departmentFilterLabel",
defaultMessage: "Hotel or office", defaultMessage: "Hotel or office",
})} })}
name="department" name="department"
@@ -70,9 +76,11 @@ export default function Filter({
items={categoryFilters} items={categoryFilters}
defaultSelectedKey={""} defaultSelectedKey={""}
label={intl.formatMessage({ label={intl.formatMessage({
id: "jobylonFeed.categoryFilterLabel",
defaultMessage: "Category", defaultMessage: "Category",
})} })}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "jobylonFeed.categoryFilterLabel",
defaultMessage: "Category", defaultMessage: "Category",
})} })}
name="category" name="category"

View File

@@ -33,6 +33,7 @@ export default function JobList({ allJobs }: JobListProps) {
const countryFilters = [ const countryFilters = [
{ {
label: intl.formatMessage({ label: intl.formatMessage({
id: "jobylonFeed.allCountriesFilter",
defaultMessage: "All countries", defaultMessage: "All countries",
}), }),
value: "", value: "",
@@ -42,6 +43,7 @@ export default function JobList({ allJobs }: JobListProps) {
const cityFilters = [ const cityFilters = [
{ {
label: intl.formatMessage({ label: intl.formatMessage({
id: "jobylonFeed.allLocationsFilter",
defaultMessage: "All locations", defaultMessage: "All locations",
}), }),
value: "", value: "",
@@ -51,6 +53,7 @@ export default function JobList({ allJobs }: JobListProps) {
const departmentFilters = [ const departmentFilters = [
{ {
label: intl.formatMessage({ label: intl.formatMessage({
id: "jobylonFeed.allDepartmentsFilter",
defaultMessage: "All hotels and offices", defaultMessage: "All hotels and offices",
}), }),
value: "", value: "",
@@ -60,6 +63,7 @@ export default function JobList({ allJobs }: JobListProps) {
const categoryFilters = [ const categoryFilters = [
{ {
label: intl.formatMessage({ label: intl.formatMessage({
id: "jobylonFeed.allCategoriesFilter",
defaultMessage: "All categories", defaultMessage: "All categories",
}), }),
value: "", value: "",
@@ -79,6 +83,7 @@ export default function JobList({ allJobs }: JobListProps) {
<Subtitle type="two"> <Subtitle type="two">
{intl.formatMessage( {intl.formatMessage(
{ {
id: "jobylonFeed.resultCount",
defaultMessage: "{count, plural, one {# Result} other {# Results}}", defaultMessage: "{count, plural, one {# Result} other {# Results}}",
}, },
{ count: state.jobs.length } { count: state.jobs.length }

View File

@@ -24,11 +24,13 @@ export default function JobylonCard({ job }: JobylonCardProps) {
const deadlineText = job.toDate const deadlineText = job.toDate
? intl.formatMessage( ? intl.formatMessage(
{ {
id: "jobylonFeed.card.deadlineText",
defaultMessage: "Deadline: {date}", defaultMessage: "Deadline: {date}",
}, },
{ date: dt(job.toDate).locale(lang).format("Do MMMM") } { date: dt(job.toDate).locale(lang).format("Do MMMM") }
) )
: intl.formatMessage({ : intl.formatMessage({
id: "jobylonFeed.card.openForApplication",
defaultMessage: "Open for application", defaultMessage: "Open for application",
}) })
@@ -57,6 +59,7 @@ export default function JobylonCard({ job }: JobylonCardProps) {
> >
<a href={job.url} target="_blank" rel="noopener noreferrer"> <a href={job.url} target="_blank" rel="noopener noreferrer">
{intl.formatMessage({ {intl.formatMessage({
id: "jobylonFeed.card.viewAndApplyButton",
defaultMessage: "View & apply", defaultMessage: "View & apply",
})} })}
<MaterialIcon icon="open_in_new" size={20} /> <MaterialIcon icon="open_in_new" size={20} />

View File

@@ -39,6 +39,7 @@ async function LevelCard({ level }: LevelCardProps) {
let pointsMsg: React.ReactNode = intl.formatMessage( let pointsMsg: React.ReactNode = intl.formatMessage(
{ {
id: "common.pointsAmountPoints",
defaultMessage: "{pointsAmount, number} points", defaultMessage: "{pointsAmount, number} points",
}, },
{ pointsAmount: level.required_points } { pointsAmount: level.required_points }
@@ -47,6 +48,7 @@ async function LevelCard({ level }: LevelCardProps) {
if (level.required_nights) { if (level.required_nights) {
pointsMsg = intl.formatMessage( pointsMsg = intl.formatMessage(
{ {
id: "loyaltyLevelsBlock.pointsOrNights",
defaultMessage: defaultMessage:
"{pointsAmount, number} points <highlight>or {nightsAmount, number} nights</highlight>", "{pointsAmount, number} points <highlight>or {nightsAmount, number} nights</highlight>",
}, },
@@ -68,6 +70,7 @@ async function LevelCard({ level }: LevelCardProps) {
> >
{intl.formatMessage( {intl.formatMessage(
{ {
id: "common.membershipLevelWithValue",
defaultMessage: "Level {level}", defaultMessage: "Level {level}",
}, },
{ level: level.user_facing_tag } { level: level.user_facing_tag }

View File

@@ -28,6 +28,7 @@ export function CookieConsentButton() {
className={styles.cookieConsentButton} className={styles.cookieConsentButton}
> >
{intl.formatMessage({ {intl.formatMessage({
id: "cookieConsent.manageCookiesButton",
defaultMessage: "Manage cookies", defaultMessage: "Manage cookies",
})} })}
<MaterialIcon icon="chevron_right" size={24} color="CurrentColor" /> <MaterialIcon icon="chevron_right" size={24} color="CurrentColor" />

View File

@@ -18,27 +18,35 @@ export default async function MyPagesOverviewShortcuts() {
const MyPagesLinkTranslationMap: Record<MyPagesLinkKey, string> = { const MyPagesLinkTranslationMap: Record<MyPagesLinkKey, string> = {
overview: intl.formatMessage({ overview: intl.formatMessage({
id: "common.overview",
defaultMessage: "Overview", defaultMessage: "Overview",
}), }),
points: intl.formatMessage({ points: intl.formatMessage({
id: "common.myPoints",
defaultMessage: "My points", defaultMessage: "My points",
}), }),
stays: intl.formatMessage({ stays: intl.formatMessage({
id: "common.myStays",
defaultMessage: "My stays", defaultMessage: "My stays",
}), }),
benefits: intl.formatMessage({ benefits: intl.formatMessage({
id: "common.myBenefits",
defaultMessage: "My benefits", defaultMessage: "My benefits",
}), }),
partnerSas: intl.formatMessage({ partnerSas: intl.formatMessage({
id: "partnerSas.sasEuroBonus",
defaultMessage: "SAS EuroBonus", defaultMessage: "SAS EuroBonus",
}), }),
teamMemberCard: intl.formatMessage({ teamMemberCard: intl.formatMessage({
id: "common.teamMemberCard",
defaultMessage: "Team Member Card", defaultMessage: "Team Member Card",
}), }),
scandicFriends: intl.formatMessage({ scandicFriends: intl.formatMessage({
id: "common.aboutScandicFriends",
defaultMessage: "About Scandic Friends", defaultMessage: "About Scandic Friends",
}), }),
profile: intl.formatMessage({ profile: intl.formatMessage({
id: "common.myProfile",
defaultMessage: "My profile", defaultMessage: "My profile",
}), }),
} }
@@ -82,14 +90,26 @@ export default async function MyPagesOverviewShortcuts() {
})), })),
{ {
openInNewTab: false, openInNewTab: false,
text: intl.formatMessage({ defaultMessage: "Partner benefits" }), text: intl.formatMessage({
title: intl.formatMessage({ defaultMessage: "Partner benefits" }), id: "myPagesOverviewShortcuts.partnerBenefits",
defaultMessage: "Partner benefits",
}),
title: intl.formatMessage({
id: "myPagesOverviewShortcuts.partnerBenefits",
defaultMessage: "Partner benefits",
}),
url: webHrefs.partners[lang], url: webHrefs.partners[lang],
}, },
{ {
openInNewTab: false, openInNewTab: false,
text: intl.formatMessage({ defaultMessage: "Scandic Friends FAQ" }), text: intl.formatMessage({
title: intl.formatMessage({ defaultMessage: "Scandic Friends FAQ" }), id: "common.scandicFriendsFaq",
defaultMessage: "Scandic Friends FAQ",
}),
title: intl.formatMessage({
id: "common.scandicFriendsFaq",
defaultMessage: "Scandic Friends FAQ",
}),
url: webHrefs.faq[lang], url: webHrefs.faq[lang],
}, },
] ]
@@ -103,6 +123,7 @@ export default async function MyPagesOverviewShortcuts() {
<div className={styles.column}> <div className={styles.column}>
<SectionHeader <SectionHeader
title={intl.formatMessage({ title={intl.formatMessage({
id: "myPagesOverviewShortcuts.yourMembership",
defaultMessage: "Your membership", defaultMessage: "Your membership",
})} })}
headingAs="h4" headingAs="h4"
@@ -116,6 +137,7 @@ export default async function MyPagesOverviewShortcuts() {
<div className={styles.column}> <div className={styles.column}>
<SectionHeader <SectionHeader
title={intl.formatMessage({ title={intl.formatMessage({
id: "myPagesOverviewShortcuts.scandicFriendsLinks",
defaultMessage: "Scandic Friends Links", defaultMessage: "Scandic Friends Links",
})} })}
headingAs="h4" headingAs="h4"

View File

@@ -18,12 +18,14 @@ export default function CopyButton({ membershipNumber }: CopyButtonProps) {
navigator.clipboard.writeText(membershipNumber) navigator.clipboard.writeText(membershipNumber)
toast.success( toast.success(
intl.formatMessage({ intl.formatMessage({
id: "myPages.membershipIdCopied",
defaultMessage: "Membership ID copied to clipboard", defaultMessage: "Membership ID copied to clipboard",
}) })
) )
} catch { } catch {
toast.error( toast.error(
intl.formatMessage({ intl.formatMessage({
id: "errorMessage.copyFailed",
defaultMessage: "Failed to copy", defaultMessage: "Failed to copy",
}) })
) )

View File

@@ -21,6 +21,7 @@ export default async function MembershipNumber({
<div className={classNames}> <div className={classNames}>
<Caption color="pale"> <Caption color="pale">
{intl.formatMessage({ {intl.formatMessage({
id: "overview.membershipNumber.label",
defaultMessage: "Membership ID:", defaultMessage: "Membership ID:",
})} })}
</Caption> </Caption>
@@ -29,6 +30,7 @@ export default async function MembershipNumber({
<code data-hj-suppress> <code data-hj-suppress>
{membership?.membershipNumber ?? {membership?.membershipNumber ??
intl.formatMessage({ intl.formatMessage({
id: "common.NA",
defaultMessage: "N/A", defaultMessage: "N/A",
})} })}
</code> </code>

View File

@@ -24,13 +24,12 @@ export default async function Friend({
const isHighestLevel = isHighestMembership(membership.membershipLevel) const isHighestLevel = isHighestMembership(membership.membershipLevel)
const lvlMessageHighest = intl.formatMessage({ const lvlMessageHighest = intl.formatMessage({
id: "overview.friend.highestLevel",
defaultMessage: "Highest level", defaultMessage: "Highest level",
}) })
const lvlMessageLevel = intl.formatMessage( const lvlMessageLevel = intl.formatMessage(
{ { id: "common.membershipLevelWithValue", defaultMessage: "Level {level}" },
defaultMessage: "Level {level}",
},
{ level: membershipLevels[membership.membershipLevel] } { level: membershipLevels[membership.membershipLevel] }
) )

View File

@@ -28,6 +28,7 @@ export default async function SasBoostStatus({
const sasBoostExpiryText = intl.formatMessage( const sasBoostExpiryText = intl.formatMessage(
{ {
id: "membershipOverViewCard.sasBoostedUntilDate",
defaultMessage: "Boosted by SAS until {date}", defaultMessage: "Boosted by SAS until {date}",
}, },
{ {

View File

@@ -32,7 +32,7 @@ export default async function MembershipOverviewCard({
const pointsToSpendText = const pointsToSpendText =
typeof user.membership.currentPoints === "number" typeof user.membership.currentPoints === "number"
? intl.formatNumber(user.membership.currentPoints) ? intl.formatNumber(user.membership.currentPoints)
: intl.formatMessage({ defaultMessage: "N/A" }) : intl.formatMessage({ id: "common.NA", defaultMessage: "N/A" })
const sasMembership = user.loyalty const sasMembership = user.loyalty
? getEurobonusMembership(user.loyalty) ? getEurobonusMembership(user.loyalty)
@@ -53,6 +53,7 @@ export default async function MembershipOverviewCard({
<h2 className={styles.levelText} id="membership-level"> <h2 className={styles.levelText} id="membership-level">
{intl.formatMessage( {intl.formatMessage(
{ {
id: "common.membershipLevelWithValue",
defaultMessage: "Level {level}", defaultMessage: "Level {level}",
}, },
{ level: membershipLevels[user.membership.membershipLevel] } { level: membershipLevels[user.membership.membershipLevel] }
@@ -79,6 +80,7 @@ export default async function MembershipOverviewCard({
<Typography variant="Title/Overline/sm"> <Typography variant="Title/Overline/sm">
<h3 className={styles.pointsLabel}> <h3 className={styles.pointsLabel}>
{intl.formatMessage({ {intl.formatMessage({
id: "common.pointsToSpend",
defaultMessage: "Points to spend", defaultMessage: "Points to spend",
})} })}
</h3> </h3>

View File

@@ -26,6 +26,7 @@ export default async function ExpiringPoints({ user }: UserProps) {
<Body color="white" textTransform="bold" textAlign="center"> <Body color="white" textTransform="bold" textAlign="center">
{intl.formatMessage( {intl.formatMessage(
{ {
id: "overview.stats.expiringPoints",
defaultMessage: "{points} spendable points expiring by {date}", defaultMessage: "{points} spendable points expiring by {date}",
}, },
{ {

View File

@@ -28,9 +28,11 @@ export default async function Points({ user }: UserProps) {
<PointsColumn <PointsColumn
value={membership?.currentPoints} value={membership?.currentPoints}
title={intl.formatMessage({ title={intl.formatMessage({
id: "stats.points.yourPointsToSpend",
defaultMessage: "Your points to spend", defaultMessage: "Your points to spend",
})} })}
subtitle={intl.formatMessage({ subtitle={intl.formatMessage({
id: "stats.points.asOfToday",
defaultMessage: "as of today", defaultMessage: "as of today",
})} })}
/> />
@@ -38,10 +40,12 @@ export default async function Points({ user }: UserProps) {
<PointsColumn <PointsColumn
value={membership?.pointsRequiredToNextlevel} value={membership?.pointsRequiredToNextlevel}
title={intl.formatMessage({ title={intl.formatMessage({
id: "stats.points.pointsNeededToLevelUp",
defaultMessage: "Points needed to level up", defaultMessage: "Points needed to level up",
})} })}
subtitle={intl.formatMessage( subtitle={intl.formatMessage(
{ {
id: "stats.points.nextLevel",
defaultMessage: "next level: {nextLevel}", defaultMessage: "next level: {nextLevel}",
}, },
{ nextLevel: nextLevel.name } { nextLevel: nextLevel.name }

View File

@@ -34,6 +34,7 @@ export default async function UserBaseInfo({ user }: UserBaseInfoProps) {
<Typography variant="Body/Supporting text (caption)/smBold"> <Typography variant="Body/Supporting text (caption)/smBold">
<span> <span>
{intl.formatMessage({ {intl.formatMessage({
id: "overview.membershipNumber.label",
defaultMessage: "Membership ID:", defaultMessage: "Membership ID:",
})} })}
</span> </span>
@@ -46,6 +47,7 @@ export default async function UserBaseInfo({ user }: UserBaseInfoProps) {
<Typography variant="Body/Supporting text (caption)/smBold"> <Typography variant="Body/Supporting text (caption)/smBold">
<span className={styles.noMembership}> <span className={styles.noMembership}>
{intl.formatMessage({ {intl.formatMessage({
id: "common.NA",
defaultMessage: "N/A", defaultMessage: "N/A",
})} })}
</span> </span>

View File

@@ -55,6 +55,7 @@ export default async function Overview({
<> <>
<MaterialIcon icon="id_card" size={24} color="CurrentColor" /> <MaterialIcon icon="id_card" size={24} color="CurrentColor" />
{intl.formatMessage({ {intl.formatMessage({
id: "dtmc.showTeamMemberCard",
defaultMessage: "Show Team Member Card", defaultMessage: "Show Team Member Card",
})} })}
</> </>

View File

@@ -98,10 +98,12 @@ export default function OverviewTableClient({
/> />
<DeprecatedSelect <DeprecatedSelect
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "common.level",
defaultMessage: "Level", defaultMessage: "Level",
})} })}
name={`reward` + column} name={`reward` + column}
label={intl.formatMessage({ label={intl.formatMessage({
id: "common.level",
defaultMessage: "Level", defaultMessage: "Level",
})} })}
items={levelOptions} items={levelOptions}
@@ -137,10 +139,12 @@ export default function OverviewTableClient({
return ( return (
<DeprecatedSelect <DeprecatedSelect
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "common.level",
defaultMessage: "Level", defaultMessage: "Level",
})} })}
name={`reward` + column} name={`reward` + column}
label={intl.formatMessage({ label={intl.formatMessage({
id: "common.level",
defaultMessage: "Level", defaultMessage: "Level",
})} })}
items={levelOptions} items={levelOptions}

View File

@@ -13,6 +13,7 @@ export default function LevelSummary({
const pointsMsg: React.ReactNode = level.required_nights const pointsMsg: React.ReactNode = level.required_nights
? intl.formatMessage( ? intl.formatMessage(
{ {
id: "overviewTable.levelSummary.pointsOrNights",
defaultMessage: defaultMessage:
"{pointsAmount, number} points or {nightsAmount, number} nights", "{pointsAmount, number} points or {nightsAmount, number} nights",
}, },
@@ -23,6 +24,7 @@ export default function LevelSummary({
) )
: intl.formatMessage( : intl.formatMessage(
{ {
id: "common.pointsAmountPoints",
defaultMessage: "{pointsAmount, number} points", defaultMessage: "{pointsAmount, number} points",
}, },
{ pointsAmount: level.required_points } { pointsAmount: level.required_points }

View File

@@ -14,6 +14,7 @@ export default function YourLevel() {
textAlign={"center"} textAlign={"center"}
> >
{intl.formatMessage({ {intl.formatMessage({
id: "overviewTable.yourLevel",
defaultMessage: "Your level", defaultMessage: "Your level",
})} })}
</BiroScript> </BiroScript>

View File

@@ -21,6 +21,7 @@ export default function ClaimPoints() {
<Typography variant="Body/Supporting text (caption)/smRegular"> <Typography variant="Body/Supporting text (caption)/smRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "points.claimPoints.missingPreviousStay",
defaultMessage: "Missing a previous stay?", defaultMessage: "Missing a previous stay?",
})} })}
</p> </p>
@@ -32,7 +33,10 @@ export default function ClaimPoints() {
size="Small" size="Small"
typography="Body/Supporting text (caption)/smBold" typography="Body/Supporting text (caption)/smBold"
> >
{intl.formatMessage({ defaultMessage: "Claim points" })} {intl.formatMessage({
id: "points.claimPoints.cta",
defaultMessage: "Claim points",
})}
<MaterialIcon icon="open_in_new" size={20} color="CurrentColor" /> <MaterialIcon icon="open_in_new" size={20} color="CurrentColor" />
</ButtonLink> </ButtonLink>
</div> </div>

View File

@@ -36,6 +36,7 @@ export default function AwardPoints({
{isCalculated {isCalculated
? intl.formatNumber(awardPoints) ? intl.formatNumber(awardPoints)
: intl.formatMessage({ : intl.formatMessage({
id: "earnAndBurn.awardPoints.pointsBeingCalculated",
defaultMessage: "Points being calculated", defaultMessage: "Points being calculated",
})} })}
</span> </span>

View File

@@ -25,6 +25,7 @@ export default function Row({ transaction }: RowProps) {
const nightsMsg = intl.formatMessage( const nightsMsg = intl.formatMessage(
{ {
id: "booking.numberOfNights",
defaultMessage: "{totalNights, plural, one {# night} other {# nights}}", defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
}, },
{ {
@@ -34,7 +35,10 @@ export default function Row({ transaction }: RowProps) {
let description = let description =
transaction.confirmationNumber === "non-transactional" && transaction.confirmationNumber === "non-transactional" &&
transaction.nights === 0 transaction.nights === 0
? intl.formatMessage({ defaultMessage: "Points activity" }) ? intl.formatMessage({
id: "earnAndBurn.journeyTable.pointsActivity",
defaultMessage: "Points activity",
})
: transaction.hotelName && transaction.city : transaction.hotelName && transaction.city
? `${transaction.hotelName}, ${transaction.city} ${nightsMsg}` ? `${transaction.hotelName}, ${transaction.city} ${nightsMsg}`
: `${nightsMsg}` : `${nightsMsg}`
@@ -44,37 +48,44 @@ export default function Row({ transaction }: RowProps) {
case Transactions.rewardType.stayAdj: case Transactions.rewardType.stayAdj:
if (transaction.hotelId === "ORS") { if (transaction.hotelId === "ORS") {
description = intl.formatMessage({ description = intl.formatMessage({
id: "earnAndBurn.journeyTable.formerScandicHotel",
defaultMessage: "Former Scandic Hotel", defaultMessage: "Former Scandic Hotel",
}) })
} }
if (transaction.confirmationNumber === "BALFWD") { if (transaction.confirmationNumber === "BALFWD") {
description = intl.formatMessage({ description = intl.formatMessage({
id: "earnAndBurn.journeyTable.pointsEarnedPriorMay2021",
defaultMessage: "Points earned prior to May 1, 2021", defaultMessage: "Points earned prior to May 1, 2021",
}) })
} }
break break
case Transactions.rewardType.ancillary: case Transactions.rewardType.ancillary:
description = intl.formatMessage({ description = intl.formatMessage({
id: "earnAndBurn.journeyTable.extrasToBooking",
defaultMessage: "Extras to your booking", defaultMessage: "Extras to your booking",
}) })
break break
case Transactions.rewardType.enrollment: case Transactions.rewardType.enrollment:
description = intl.formatMessage({ description = intl.formatMessage({
id: "earnAndBurn.journeyTable.signUpBonus",
defaultMessage: "Sign up bonus", defaultMessage: "Sign up bonus",
}) })
break break
case Transactions.rewardType.mastercard_points: case Transactions.rewardType.mastercard_points:
description = intl.formatMessage({ description = intl.formatMessage({
id: "earnAndBurn.journeyTable.scandicFriendsMastercard",
defaultMessage: "Scandic Friends Mastercard", defaultMessage: "Scandic Friends Mastercard",
}) })
break break
case Transactions.rewardType.tui_points: case Transactions.rewardType.tui_points:
description = intl.formatMessage({ description = intl.formatMessage({
id: "earnAndBurn.journeyTable.tuiPoints",
defaultMessage: "TUI Points", defaultMessage: "TUI Points",
}) })
case Transactions.rewardType.pointShop: case Transactions.rewardType.pointShop:
description = intl.formatMessage({ description = intl.formatMessage({
id: "earnAndBurn.journeyTable.pointShop",
defaultMessage: "Scandic Friends Point Shop", defaultMessage: "Scandic Friends Point Shop",
}) })
break break

View File

@@ -16,15 +16,19 @@ export default function ClientTable({ transactions }: ClientTableProps) {
const tableHeadings = [ const tableHeadings = [
intl.formatMessage({ intl.formatMessage({
id: "common.points",
defaultMessage: "Points", defaultMessage: "Points",
}), }),
intl.formatMessage({ intl.formatMessage({
id: "earnAndBurn.journeyTable.description",
defaultMessage: "Description", defaultMessage: "Description",
}), }),
intl.formatMessage({ intl.formatMessage({
id: "earnAndBurn.journeyTable.bookingNumberReference",
defaultMessage: "Booking number / Reference", defaultMessage: "Booking number / Reference",
}), }),
intl.formatMessage({ intl.formatMessage({
id: "earnAndBurn.journeyTable.date",
defaultMessage: "Date", defaultMessage: "Date",
}), }),
] ]
@@ -55,6 +59,7 @@ export default function ClientTable({ transactions }: ClientTableProps) {
<Table.TR className={styles.placeholder}> <Table.TR className={styles.placeholder}>
<Table.TD colSpan={tableHeadings.length}> <Table.TD colSpan={tableHeadings.length}>
{intl.formatMessage({ {intl.formatMessage({
id: "earnAndBurn.journeyTable.noTransactions",
defaultMessage: "No transactions available", defaultMessage: "No transactions available",
})} })}
</Table.TD> </Table.TD>

View File

@@ -22,10 +22,9 @@ export default function ExpiringPointsTable({
const expiration = dt(expirationDate).locale(lang).format("DD MMM YYYY") const expiration = dt(expirationDate).locale(lang).format("DD MMM YYYY")
const tableHeadings = [ const tableHeadings = [
intl.formatMessage({ id: "common.points", defaultMessage: "Points" }),
intl.formatMessage({ intl.formatMessage({
defaultMessage: "Points", id: "points.expiringPointsTable.expirationDate",
}),
intl.formatMessage({
defaultMessage: "Expiration Date", defaultMessage: "Expiration Date",
}), }),
] ]

View File

@@ -32,11 +32,14 @@ export default function ExpiringPointsSeeAllButton({
typography="Body/Paragraph/mdBold" typography="Body/Paragraph/mdBold"
onPress={() => setIsOpen(true)} onPress={() => setIsOpen(true)}
> >
{intl.formatMessage({ defaultMessage: "See all" })} {intl.formatMessage({ id: "common.seeAll", defaultMessage: "See all" })}
<MaterialIcon icon="chevron_right" color="CurrentColor" /> <MaterialIcon icon="chevron_right" color="CurrentColor" />
</Button> </Button>
<SidePeekSelfControlled <SidePeekSelfControlled
title={intl.formatMessage({ defaultMessage: "Expiring points" })} title={intl.formatMessage({
id: "points.pointsToSpendCard.expiringPointsTitle",
defaultMessage: "Expiring points",
})}
isOpen={isOpen} isOpen={isOpen}
onClose={() => setIsOpen(false)} onClose={() => setIsOpen(false)}
> >
@@ -44,6 +47,7 @@ export default function ExpiringPointsSeeAllButton({
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "points.pointsToSpendCard.expiringPointsInfo",
defaultMessage: defaultMessage:
"Points expire three years after they are earned, on the last day of that month. Expiring points do not affect your level.", "Points expire three years after they are earned, on the last day of that month. Expiring points do not affect your level.",
})} })}

View File

@@ -38,6 +38,7 @@
.pointsLabel { .pointsLabel {
color: var(--Text-Brand-OnPrimary-1-Heading); color: var(--Text-Brand-OnPrimary-1-Heading);
text-transform: capitalize;
} }
.description { .description {

View File

@@ -52,6 +52,7 @@ export default async function PointsToSpendCard({
<Typography variant="Title/xs"> <Typography variant="Title/xs">
<h2 id="points-to-spend-card-title" className={styles.title}> <h2 id="points-to-spend-card-title" className={styles.title}>
{intl.formatMessage({ {intl.formatMessage({
id: "common.pointsToSpend",
defaultMessage: "Points to spend", defaultMessage: "Points to spend",
})} })}
</h2> </h2>
@@ -66,6 +67,7 @@ export default async function PointsToSpendCard({
<Typography variant="Title/Overline/sm"> <Typography variant="Title/Overline/sm">
<span className={styles.pointsLabel}> <span className={styles.pointsLabel}>
{intl.formatMessage({ {intl.formatMessage({
id: "common.points",
defaultMessage: "Points", defaultMessage: "Points",
})} })}
</span> </span>
@@ -75,6 +77,7 @@ export default async function PointsToSpendCard({
{hasPointsToSpend && ( {hasPointsToSpend && (
<ButtonLink href={spendPoints[lang]} target="_blank" variant="Text"> <ButtonLink href={spendPoints[lang]} target="_blank" variant="Text">
{intl.formatMessage({ {intl.formatMessage({
id: "points.pointsToSpendCard.howToSpendCta",
defaultMessage: "How to spend points", defaultMessage: "How to spend points",
})} })}
<MaterialIcon <MaterialIcon
@@ -91,6 +94,7 @@ export default async function PointsToSpendCard({
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p className={styles.descriptionText}> <p className={styles.descriptionText}>
{intl.formatMessage({ {intl.formatMessage({
id: "points.pointsToSpendCard.description",
defaultMessage: defaultMessage:
"Earn points by staying at Scandic. Turn your points into free nights and memorable experiences.", "Earn points by staying at Scandic. Turn your points into free nights and memorable experiences.",
})} })}
@@ -108,6 +112,7 @@ export default async function PointsToSpendCard({
<p className={styles.expiringPoints}> <p className={styles.expiringPoints}>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "points.pointsToSpendCard.expiringPointsText",
defaultMessage: "{expiringPoints} points expiring", defaultMessage: "{expiringPoints} points expiring",
}, },
{ {

View File

@@ -24,6 +24,7 @@ export function getExpiryLabel(
if (daysUntilExpiry <= DAYS_UNTIL_EXPIRY_WARNING) { if (daysUntilExpiry <= DAYS_UNTIL_EXPIRY_WARNING) {
return intl.formatMessage( return intl.formatMessage(
{ {
id: "points.pointsToSpendCard.inDays",
defaultMessage: "In {days} days", defaultMessage: "In {days} days",
}, },
{ {
@@ -33,6 +34,7 @@ export function getExpiryLabel(
} else { } else {
return intl.formatMessage( return intl.formatMessage(
{ {
id: "points.pointsToSpendCard.onDate",
defaultMessage: "on {expiryDate}", defaultMessage: "on {expiryDate}",
}, },
{ {

View File

@@ -50,6 +50,7 @@ export default async function NextLevelRewardsBlock({
<Chip> <Chip>
<Lock height={16} /> <Lock height={16} />
{intl.formatMessage({ {intl.formatMessage({
id: "rewards.nextLevel.levelUpToUnlock",
defaultMessage: "Level up to unlock", defaultMessage: "Level up to unlock",
})} })}
</Chip> </Chip>
@@ -57,6 +58,7 @@ export default async function NextLevelRewardsBlock({
<Body color="peach50" textAlign="center"> <Body color="peach50" textAlign="center">
{intl.formatMessage( {intl.formatMessage(
{ {
id: "rewards.nextLevel.asOurLevel",
defaultMessage: "As our {level}", defaultMessage: "As our {level}",
}, },
{ level: nextLevelRewards.level?.name } { level: nextLevelRewards.level?.name }

View File

@@ -27,6 +27,7 @@ export default function ActiveRedeemedBadge() {
</motion.div> </motion.div>
<Caption> <Caption>
{intl.formatMessage({ {intl.formatMessage({
id: "rewards.active",
defaultMessage: "Active", defaultMessage: "Active",
})} })}
</Caption> </Caption>

View File

@@ -17,16 +17,19 @@ export function ConfirmClose({ close }: { close: () => void }) {
<div className={styles.modalContent}> <div className={styles.modalContent}>
<Title level="h3" textAlign="center" textTransform="regular"> <Title level="h3" textAlign="center" textTransform="regular">
{intl.formatMessage({ {intl.formatMessage({
id: "redeem.confirmClose.title",
defaultMessage: "If you close this your benefit will be removed", defaultMessage: "If you close this your benefit will be removed",
})} })}
</Title> </Title>
<Body> <Body>
{intl.formatMessage({ {intl.formatMessage({
id: "redeem.confirmClose.question",
defaultMessage: "Have you showed this benefit to the hotel staff?", defaultMessage: "Have you showed this benefit to the hotel staff?",
})} })}
</Body> </Body>
<Body> <Body>
{intl.formatMessage({ {intl.formatMessage({
id: "redeem.confirmClose.info",
defaultMessage: defaultMessage:
"If not, please go back and do so before you close this. Once you close this your benefit will be void and removed from My Benefits.", "If not, please go back and do so before you close this. Once you close this your benefit will be void and removed from My Benefits.",
})} })}
@@ -39,11 +42,13 @@ export function ConfirmClose({ close }: { close: () => void }) {
theme="base" theme="base"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "redeem.confirmClose.goBack",
defaultMessage: "No, go back", defaultMessage: "No, go back",
})} })}
</Button> </Button>
<Button onClick={close} intent="secondary" theme="base"> <Button onClick={close} intent="secondary" theme="base">
{intl.formatMessage({ {intl.formatMessage({
id: "redeem.confirmClose.confirm",
defaultMessage: "Yes, close and remove benefit", defaultMessage: "Yes, close and remove benefit",
})} })}
</Button> </Button>

View File

@@ -29,6 +29,7 @@ export default function Campaign({ reward }: { reward: Campaign }) {
<div className={styles.rewardBadge}> <div className={styles.rewardBadge}>
<Caption textAlign="center" color="uiTextHighContrast" type="bold"> <Caption textAlign="center" color="uiTextHighContrast" type="bold">
{intl.formatMessage({ {intl.formatMessage({
id: "redeemFlow.promoCode",
defaultMessage: "Promo code", defaultMessage: "Promo code",
})} })}
</Caption> </Caption>
@@ -44,12 +45,14 @@ export default function Campaign({ reward }: { reward: Campaign }) {
navigator.clipboard.writeText(reward.operaRewardId) navigator.clipboard.writeText(reward.operaRewardId)
toast.success( toast.success(
intl.formatMessage({ intl.formatMessage({
id: "redeemFlow.copiedToClipboard",
defaultMessage: "Copied to clipboard", defaultMessage: "Copied to clipboard",
}) })
) )
} catch { } catch {
toast.error( toast.error(
intl.formatMessage({ intl.formatMessage({
id: "errorMessage.copyFailed",
defaultMessage: "Failed to copy", defaultMessage: "Failed to copy",
}) })
) )
@@ -63,6 +66,7 @@ export default function Campaign({ reward }: { reward: Campaign }) {
> >
<MaterialIcon icon="content_copy" color="CurrentColor" /> <MaterialIcon icon="content_copy" color="CurrentColor" />
{intl.formatMessage({ {intl.formatMessage({
id: "redeemFlow.copyPromotionCode",
defaultMessage: "Copy promotion code", defaultMessage: "Copy promotion code",
})} })}
</Button> </Button>

View File

@@ -88,6 +88,7 @@ export default function Tier({
theme="base" theme="base"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "redeemFlow.redeemBenefit",
defaultMessage: "Redeem benefit", defaultMessage: "Redeem benefit",
})} })}
</Button> </Button>
@@ -103,6 +104,7 @@ export default function Tier({
theme="base" theme="base"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "redeemFlow.yesRedeem",
defaultMessage: "Yes, redeem", defaultMessage: "Yes, redeem",
})} })}
</Button> </Button>
@@ -112,6 +114,7 @@ export default function Tier({
theme="base" theme="base"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "common.goBack",
defaultMessage: "Go back", defaultMessage: "Go back",
})} })}
</Button> </Button>

View File

@@ -16,6 +16,7 @@ export default function MembershipNumberBadge({
<Caption textAlign="center" color="uiTextHighContrast"> <Caption textAlign="center" color="uiTextHighContrast">
{intl.formatMessage( {intl.formatMessage(
{ {
id: "rewards.membershipId",
defaultMessage: "Membership ID: {id}", defaultMessage: "Membership ID: {id}",
}, },
{ id: membershipNumber } { id: membershipNumber }

View File

@@ -23,6 +23,7 @@ export default function TimedRedeemedBadge() {
<MaterialIcon icon="check_circle" color="Icon/Feedback/Success" /> <MaterialIcon icon="check_circle" color="Icon/Feedback/Success" />
<Caption> <Caption>
{intl.formatMessage({ {intl.formatMessage({
id: "rewards.redeemed.validThrough",
defaultMessage: "Redeemed & valid through:", defaultMessage: "Redeemed & valid through:",
})} })}
</Caption> </Caption>

View File

@@ -78,9 +78,11 @@ export default function Redeem({ reward, membershipNumber }: RedeemProps) {
> >
{reward.redeemLocation === "Non-redeemable" {reward.redeemLocation === "Non-redeemable"
? intl.formatMessage({ ? intl.formatMessage({
id: "rewards.howToUse",
defaultMessage: "How to use", defaultMessage: "How to use",
}) })
: intl.formatMessage({ : intl.formatMessage({
id: "common.open",
defaultMessage: "Open", defaultMessage: "Open",
})} })}
</Button> </Button>

View File

@@ -23,14 +23,17 @@ export default function ScriptedRewardText({
} }
case "Campaign": case "Campaign":
return intl.formatMessage({ return intl.formatMessage({
id: "booking.campaign",
defaultMessage: "Campaign", defaultMessage: "Campaign",
}) })
case "Surprise": case "Surprise":
return intl.formatMessage({ return intl.formatMessage({
id: "rewards.surprise",
defaultMessage: "Surprise!", defaultMessage: "Surprise!",
}) })
case "Member-voucher": case "Member-voucher":
return intl.formatMessage({ return intl.formatMessage({
id: "rewards.voucher",
defaultMessage: "Voucher", defaultMessage: "Voucher",
}) })
default: default:

View File

@@ -28,12 +28,14 @@ export default async function SASLinkAccountBanner(
} }
const headingText = intl.formatMessage({ const headingText = intl.formatMessage({
id: "sas.linkAccountBanner.earnFlightsWithNights",
defaultMessage: "Earn flights with nights", defaultMessage: "Earn flights with nights",
}) })
const buttonText = const buttonText =
props.link?.text || props.link?.text ||
intl.formatMessage({ intl.formatMessage({
id: "sas.linkAccountBanner.readMoreAndLinkAccounts",
defaultMessage: "Read more and link accounts", defaultMessage: "Read more and link accounts",
}) })
@@ -41,6 +43,7 @@ export default async function SASLinkAccountBanner(
return ( return (
<span key="scandic-friends" className={styles.brandName}> <span key="scandic-friends" className={styles.brandName}>
{intl.formatMessage({ {intl.formatMessage({
id: "common.scandicFriends",
defaultMessage: "Scandic Friends", defaultMessage: "Scandic Friends",
})} })}
</span> </span>
@@ -51,6 +54,7 @@ export default async function SASLinkAccountBanner(
return ( return (
<span key="sas-eurobonus" className={styles.brandName}> <span key="sas-eurobonus" className={styles.brandName}>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.sasEuroBonus",
defaultMessage: "SAS EuroBonus", defaultMessage: "SAS EuroBonus",
})} })}
</span> </span>
@@ -59,6 +63,7 @@ export default async function SASLinkAccountBanner(
const descriptionText = intl.formatMessage( const descriptionText = intl.formatMessage(
{ {
id: "sas.linkAccountBanner.description",
defaultMessage: defaultMessage:
"Link your <scandicFriends></scandicFriends> and <sasEuroBonus></sasEuroBonus> accounts to earn, use and exchange points between memberships", "Link your <scandicFriends></scandicFriends> and <sasEuroBonus></sasEuroBonus> accounts to earn, use and exchange points between memberships",
}, },

View File

@@ -17,22 +17,27 @@ export function UnlinkSAS() {
return ( return (
<Dialog <Dialog
titleText={intl.formatMessage({ titleText={intl.formatMessage({
id: "partnerSas.unlinkAccount",
defaultMessage: "Are you sure you want to unlink your account?", defaultMessage: "Are you sure you want to unlink your account?",
})} })}
bodyText={intl.formatMessage({ bodyText={intl.formatMessage({
id: "partnerSas.unlinkAccountWarning",
defaultMessage: defaultMessage:
"This will remove any membership level upgrades gained from the linking. You can re-link your accounts again in 30 days.", "This will remove any membership level upgrades gained from the linking. You can re-link your accounts again in 30 days.",
})} })}
cancelButtonText={intl.formatMessage({ cancelButtonText={intl.formatMessage({
id: "common.goBack",
defaultMessage: "Go back", defaultMessage: "Go back",
})} })}
proceedText={intl.formatMessage({ proceedText={intl.formatMessage({
id: "partnerSas.yesUnlinkAccount",
defaultMessage: "Yes, unlink my accounts", defaultMessage: "Yes, unlink my accounts",
})} })}
proceedHref={`/${params.lang}/sas-x-scandic/login?intent=unlink`} proceedHref={`/${params.lang}/sas-x-scandic/login?intent=unlink`}
trigger={ trigger={
<Button intent="text" theme="base"> <Button intent="text" theme="base">
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.unlinkAccounts",
defaultMessage: "Unlink accounts", defaultMessage: "Unlink accounts",
})} })}
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" /> <MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />

View File

@@ -52,6 +52,7 @@ export default async function SASLinkedAccount({
<p className={styles.caption}> <p className={styles.caption}>
<MaterialIcon icon="info" size={20} /> <MaterialIcon icon="info" size={20} />
{intl.formatMessage({ {intl.formatMessage({
id: "sas.linkedAccounts.changeDelayInfo",
defaultMessage: defaultMessage:
"Changes in your level match can take up to 24 hours to be displayed.", "Changes in your level match can take up to 24 hours to be displayed.",
})} })}
@@ -96,12 +97,14 @@ async function MatchedAccountInfo() {
<div className={styles.stack}> <div className={styles.stack}>
<Label> <Label>
{intl.formatMessage({ {intl.formatMessage({
id: "sas.linkedAccounts.linkedAccount",
defaultMessage: "Linked account", defaultMessage: "Linked account",
})} })}
</Label> </Label>
<Typography variant="Body/Paragraph/mdBold"> <Typography variant="Body/Paragraph/mdBold">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.sasEuroBonus",
defaultMessage: "SAS EuroBonus", defaultMessage: "SAS EuroBonus",
})} })}
</p> </p>
@@ -110,6 +113,7 @@ async function MatchedAccountInfo() {
<div className={styles.stack}> <div className={styles.stack}>
<Label> <Label>
{intl.formatMessage({ {intl.formatMessage({
id: "common.level",
defaultMessage: "Level", defaultMessage: "Level",
})} })}
</Label> </Label>
@@ -120,6 +124,7 @@ async function MatchedAccountInfo() {
<div className={cx(styles.stack, styles.accountMemberNumber)}> <div className={cx(styles.stack, styles.accountMemberNumber)}>
<Label> <Label>
{intl.formatMessage({ {intl.formatMessage({
id: "common.membershipId",
defaultMessage: "Membership ID", defaultMessage: "Membership ID",
})} })}
</Label> </Label>
@@ -154,12 +159,14 @@ async function MatchedAccountInfoSkeleton() {
<div className={styles.stack}> <div className={styles.stack}>
<Label> <Label>
{intl.formatMessage({ {intl.formatMessage({
id: "sas.linkedAccounts.linkedAccount",
defaultMessage: "Linked account", defaultMessage: "Linked account",
})} })}
</Label> </Label>
<Typography variant="Body/Paragraph/mdBold"> <Typography variant="Body/Paragraph/mdBold">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.sasEuroBonus",
defaultMessage: "SAS EuroBonus", defaultMessage: "SAS EuroBonus",
})} })}
</p> </p>
@@ -168,6 +175,7 @@ async function MatchedAccountInfoSkeleton() {
<div className={styles.stack}> <div className={styles.stack}>
<Label> <Label>
{intl.formatMessage({ {intl.formatMessage({
id: "common.level",
defaultMessage: "Level", defaultMessage: "Level",
})} })}
</Label> </Label>
@@ -176,6 +184,7 @@ async function MatchedAccountInfoSkeleton() {
<div className={cx(styles.stack, styles.accountMemberNumber)}> <div className={cx(styles.stack, styles.accountMemberNumber)}>
<Label> <Label>
{intl.formatMessage({ {intl.formatMessage({
id: "common.membershipId",
defaultMessage: "Membership ID", defaultMessage: "Membership ID",
})} })}
</Label> </Label>
@@ -219,6 +228,7 @@ async function TierMatchMessage({
const messageMap: Record<MatchState, ReactNode> = { const messageMap: Record<MatchState, ReactNode> = {
boostedBySAS: intl.formatMessage( boostedBySAS: intl.formatMessage(
{ {
id: "sas.linkedAccounts.euroBonusSasUpgradedText",
defaultMessage: defaultMessage:
"<sasMark>EuroBonus {sasLevelName}</sasMark> has upgraded your Scandic Friends level to <scandicMark>{scandicLevelName}</scandicMark>.", "<sasMark>EuroBonus {sasLevelName}</sasMark> has upgraded your Scandic Friends level to <scandicMark>{scandicLevelName}</scandicMark>.",
}, },
@@ -226,6 +236,7 @@ async function TierMatchMessage({
), ),
boostedByScandic: intl.formatMessage( boostedByScandic: intl.formatMessage(
{ {
id: "sas.linkedAccounts.scandicFriendsUpgradedText",
defaultMessage: defaultMessage:
"Your Scandic Friends level <scandicMark>{scandicLevelName}</scandicMark> has upgraded you to <sasMark>EuroBonus {sasLevelName}</sasMark>.", "Your Scandic Friends level <scandicMark>{scandicLevelName}</scandicMark> has upgraded you to <sasMark>EuroBonus {sasLevelName}</sasMark>.",
}, },
@@ -233,6 +244,7 @@ async function TierMatchMessage({
), ),
noBoost: intl.formatMessage( noBoost: intl.formatMessage(
{ {
id: "sas.linkedAccounts.euroBonusSasText",
defaultMessage: defaultMessage:
"<sasMark>EuroBonus {sasLevelName}</sasMark> and <scandicMark>{scandicLevelName}</scandicMark> are equally matched. Level up in one of your memberships to qualify for an upgrade!", "<sasMark>EuroBonus {sasLevelName}</sasMark> and <scandicMark>{scandicLevelName}</scandicMark> are equally matched. Level up in one of your memberships to qualify for an upgrade!",
}, },
@@ -250,6 +262,7 @@ async function TierMatchMessage({
<div className={styles.stack}> <div className={styles.stack}>
<Label> <Label>
{intl.formatMessage({ {intl.formatMessage({
id: "sas.linkedAccounts.levelMatchStatus",
defaultMessage: "Level match status", defaultMessage: "Level match status",
})} })}
</Label> </Label>
@@ -270,6 +283,7 @@ async function TierMatchMessageSkeleton() {
<div className={styles.stack}> <div className={styles.stack}>
<Label> <Label>
{intl.formatMessage({ {intl.formatMessage({
id: "sas.linkedAccounts.levelMatchStatus",
defaultMessage: "Level match status", defaultMessage: "Level match status",
})} })}
</Label> </Label>
@@ -307,6 +321,7 @@ async function TierMatchExpiration({
<div className={cx(styles.stack, styles.textRight)}> <div className={cx(styles.stack, styles.textRight)}>
<Label> <Label>
{intl.formatMessage({ {intl.formatMessage({
id: "sas.linkedAccounts.upgradeValidUntil",
defaultMessage: "Upgrade valid until", defaultMessage: "Upgrade valid until",
})} })}
</Label> </Label>

View File

@@ -80,6 +80,7 @@ async function TransferPointsFormContent({
<Typography variant="Tag/sm"> <Typography variant="Tag/sm">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.exchangeFrom",
defaultMessage: "Exchange from", defaultMessage: "Exchange from",
})} })}
</p> </p>
@@ -89,6 +90,7 @@ async function TransferPointsFormContent({
<Typography variant="Title/Subtitle/md"> <Typography variant="Title/Subtitle/md">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.sasEuroBonus",
defaultMessage: "SAS EuroBonus", defaultMessage: "SAS EuroBonus",
})} })}
</p> </p>
@@ -98,6 +100,7 @@ async function TransferPointsFormContent({
<Typography variant="Tag/sm"> <Typography variant="Tag/sm">
<p className={styles.balanceLabel}> <p className={styles.balanceLabel}>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.balance",
defaultMessage: "Balance", defaultMessage: "Balance",
})} })}
</p> </p>
@@ -113,6 +116,7 @@ async function TransferPointsFormContent({
<p> <p>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "partnerSas.pointsWithValue",
defaultMessage: "{points, number} p", defaultMessage: "{points, number} p",
}, },
{ points: sasPoints } { points: sasPoints }
@@ -127,6 +131,7 @@ async function TransferPointsFormContent({
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.noPointsToTransfer",
defaultMessage: "You have no points to transfer.", defaultMessage: "You have no points to transfer.",
})} })}
</p> </p>
@@ -140,6 +145,7 @@ async function TransferPointsFormContent({
<Typography variant="Tag/sm"> <Typography variant="Tag/sm">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.exchangeTo",
defaultMessage: "Exchange to", defaultMessage: "Exchange to",
})} })}
</p> </p>
@@ -148,6 +154,7 @@ async function TransferPointsFormContent({
<Typography variant="Title/Subtitle/md"> <Typography variant="Title/Subtitle/md">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "common.scandicFriends",
defaultMessage: "Scandic Friends", defaultMessage: "Scandic Friends",
})} })}
</p> </p>
@@ -157,6 +164,7 @@ async function TransferPointsFormContent({
<Typography variant="Tag/sm"> <Typography variant="Tag/sm">
<p className={styles.balanceLabel}> <p className={styles.balanceLabel}>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.balance",
defaultMessage: "Balance", defaultMessage: "Balance",
})} })}
</p> </p>
@@ -172,6 +180,7 @@ async function TransferPointsFormContent({
<p> <p>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "partnerSas.pointsWithValue",
defaultMessage: "{points, number} p", defaultMessage: "{points, number} p",
}, },
{ points: scandicPoints } { points: scandicPoints }
@@ -191,6 +200,7 @@ async function TransferPointsFormContent({
<Typography variant="Body/Supporting text (caption)/smRegular"> <Typography variant="Body/Supporting text (caption)/smRegular">
<p style={{ color: "var(--Text-Tertiary)" }}> <p style={{ color: "var(--Text-Tertiary)" }}>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.exchangedPointsNotLevelQualifying",
defaultMessage: "Exchanged points will not be level-qualifying.", defaultMessage: "Exchanged points will not be level-qualifying.",
})} })}
</p> </p>

View File

@@ -67,6 +67,7 @@ export function TransferPointsFormClient({
// Set max value to 1 if sasPoints is 0 since slider requires a range // Set max value to 1 if sasPoints is 0 since slider requires a range
maxValue={hasNoSasPoints ? 1 : sasPoints} maxValue={hasNoSasPoints ? 1 : sasPoints}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "partnerSas.ebPointsToExchange",
defaultMessage: "EB points to exchange", defaultMessage: "EB points to exchange",
})} })}
formatOptions={{ formatOptions={{
@@ -88,6 +89,7 @@ export function TransferPointsFormClient({
<TextField type="number" isDisabled={disabled}> <TextField type="number" isDisabled={disabled}>
<Input <Input
label={intl.formatMessage({ label={intl.formatMessage({
id: "partnerSas.ebPointsToExchange",
defaultMessage: "EB points to exchange", defaultMessage: "EB points to exchange",
})} })}
type="number" type="number"
@@ -109,6 +111,7 @@ export function TransferPointsFormClient({
<p className={styles.conversionRate}> <p className={styles.conversionRate}>
{/* TODO maybe dynamic string based on exchange rate */} {/* TODO maybe dynamic string based on exchange rate */}
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.conversionRateInfo",
defaultMessage: "1 EuroBonus point = 2 Scandic Friends points", defaultMessage: "1 EuroBonus point = 2 Scandic Friends points",
})} })}
</p> </p>
@@ -117,6 +120,7 @@ export function TransferPointsFormClient({
<Typography variant="Label/xsRegular"> <Typography variant="Label/xsRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.sfPointsToReceive",
defaultMessage: "SF points to receive", defaultMessage: "SF points to receive",
})} })}
</p> </p>
@@ -183,6 +187,7 @@ function ConfirmModal({
disabled={disabled} disabled={disabled}
> >
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.exchangePoints",
defaultMessage: "Exchange points", defaultMessage: "Exchange points",
})} })}
</Button> </Button>
@@ -197,6 +202,7 @@ function ConfirmModal({
<Typography variant="Title/Subtitle/lg"> <Typography variant="Title/Subtitle/lg">
<h3> <h3>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.proceedWithPointExchange",
defaultMessage: "Proceed with point exchange?", defaultMessage: "Proceed with point exchange?",
})} })}
</h3> </h3>
@@ -205,6 +211,7 @@ function ConfirmModal({
<Typography variant="Body/Paragraph/mdRegular"> <Typography variant="Body/Paragraph/mdRegular">
<p> <p>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.youAreAboutToExchange",
defaultMessage: "You are about to exchange:", defaultMessage: "You are about to exchange:",
})} })}
</p> </p>
@@ -213,6 +220,7 @@ function ConfirmModal({
<p> <p>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "partnerSas.exchangePointsDetails",
defaultMessage: defaultMessage:
"<bold>{sasPoints, number} EuroBonus points</bold> to <bold>{scandicPoints, number} Scandic Friends points</bold>", "<bold>{sasPoints, number} EuroBonus points</bold> to <bold>{scandicPoints, number} Scandic Friends points</bold>",
}, },
@@ -232,6 +240,7 @@ function ConfirmModal({
<Typography variant="Body/Supporting text (caption)/smRegular"> <Typography variant="Body/Supporting text (caption)/smRegular">
<p className={styles.expiryText}> <p className={styles.expiryText}>
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.exchangePointsExpiry",
defaultMessage: defaultMessage:
"Your exchanged points will retain their original expiry date with a maximum validity of 12 months.", "Your exchanged points will retain their original expiry date with a maximum validity of 12 months.",
})} })}
@@ -245,6 +254,7 @@ function ConfirmModal({
color="none" color="none"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "partnerSas.yesIWantToExchangeMyPoints",
defaultMessage: "Yes, I want to exchange my points", defaultMessage: "Yes, I want to exchange my points",
})} })}
</Link> </Link>
@@ -256,6 +266,7 @@ function ConfirmModal({
onClick={() => handleToggle(false)} onClick={() => handleToggle(false)}
> >
{intl.formatMessage({ {intl.formatMessage({
id: "common.cancel",
defaultMessage: "Cancel", defaultMessage: "Cancel",
})} })}
</Button> </Button>

View File

@@ -24,10 +24,12 @@ export default async function EmptyUpcomingStaysBlock() {
textAlign="center" textAlign="center"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "stays.noUpcomingStays",
defaultMessage: "You have no upcoming stays.", defaultMessage: "You have no upcoming stays.",
})} })}
<span className={styles.burgundyTitle}> <span className={styles.burgundyTitle}>
{intl.formatMessage({ {intl.formatMessage({
id: "stays.whereToGoNext",
defaultMessage: "Where should you go next?", defaultMessage: "Where should you go next?",
})} })}
</span> </span>
@@ -39,6 +41,7 @@ export default async function EmptyUpcomingStaysBlock() {
color="Text/Interactive/Secondary" color="Text/Interactive/Secondary"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "stays.getInspired",
defaultMessage: "Get inspired", defaultMessage: "Get inspired",
})} })}
<MaterialIcon icon="arrow_forward" color="CurrentColor" /> <MaterialIcon icon="arrow_forward" color="CurrentColor" />

View File

@@ -30,6 +30,7 @@ export default function ShowMoreButton({
color="CurrentColor" color="CurrentColor"
/> />
{intl.formatMessage({ {intl.formatMessage({
id: "common.showMore",
defaultMessage: "Show more", defaultMessage: "Show more",
})} })}
</Button> </Button>

View File

@@ -27,6 +27,7 @@ export default async function HotelListingItem({
url: hotelData.meetingUrl, url: hotelData.meetingUrl,
openInNewTab: true, openInNewTab: true,
text: intl.formatMessage({ text: intl.formatMessage({
id: "meetingPackage.bookAMeeting",
defaultMessage: "Book a meeting", defaultMessage: "Book a meeting",
}), }),
} }
@@ -34,6 +35,7 @@ export default async function HotelListingItem({
url: hotelData.url, url: hotelData.url,
openInNewTab: false, openInNewTab: false,
text: intl.formatMessage({ text: intl.formatMessage({
id: "destination.seeHotelDetails",
defaultMessage: "See hotel details", defaultMessage: "See hotel details",
}), }),
} }
@@ -61,6 +63,7 @@ export default async function HotelListingItem({
<span> <span>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "common.kmToCityCenter",
defaultMessage: "{number} km to city center", defaultMessage: "{number} km to city center",
}, },
{ {

View File

@@ -26,6 +26,7 @@ export function CarouselPrevious({ className }: CarouselButtonProps) {
style="Elevated" style="Elevated"
onPress={scrollPrev} onPress={scrollPrev}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "carousel.previousSlide",
defaultMessage: "Previous slide", defaultMessage: "Previous slide",
})} })}
> >
@@ -49,6 +50,7 @@ export function CarouselNext({ className }: CarouselButtonProps) {
style="Elevated" style="Elevated"
onPress={scrollNext} onPress={scrollNext}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
id: "carousel.nextSlide",
defaultMessage: "Next slide", defaultMessage: "Next slide",
})} })}
> >

View File

@@ -18,7 +18,10 @@ export default async function TopCampaign({ topCampaign }: TopCampaignProps) {
const intl = await getIntl() const intl = await getIntl()
const { campaign, heading } = topCampaign const { campaign, heading } = topCampaign
const buttonData = { const buttonData = {
cta: intl.formatMessage({ defaultMessage: "Explore the offer" }), cta: intl.formatMessage({
id: "campaign.exploreTheOffer",
defaultMessage: "Explore the offer",
}),
url: `/${lang}${campaign.url}`, url: `/${lang}${campaign.url}`,
} }
@@ -34,6 +37,7 @@ export default async function TopCampaign({ topCampaign }: TopCampaignProps) {
heading={ heading={
campaign.hotel_listing.heading || campaign.hotel_listing.heading ||
intl.formatMessage({ intl.formatMessage({
id: "campaignPage.hotelsIncludedInOffer",
defaultMessage: "Hotels included in this offer", defaultMessage: "Hotels included in this offer",
}) })
} }

View File

@@ -26,9 +26,11 @@ export default function HotelListContent({
<Alert <Alert
type={AlertTypeEnum.Info} type={AlertTypeEnum.Info}
heading={intl.formatMessage({ heading={intl.formatMessage({
id: "filter.noMatchingHotelsFound",
defaultMessage: "No matching hotels found", defaultMessage: "No matching hotels found",
})} })}
text={intl.formatMessage({ text={intl.formatMessage({
id: "filter.noMatchingHotelsFoundDescription",
defaultMessage: defaultMessage:
"It looks like no hotels match your filters. Try adjusting your search to find the perfect stay.", "It looks like no hotels match your filters. Try adjusting your search to find the perfect stay.",
})} })}

View File

@@ -73,6 +73,7 @@ export default function HotelList() {
<p> <p>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "destinationPage.hotelsCount",
defaultMessage: "{count} hotels", defaultMessage: "{count} hotels",
}, },
{ count: visibleHotels.length } { count: visibleHotels.length }

View File

@@ -73,6 +73,7 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) {
sizes="(min-width: 768px) 700px, 100vw" sizes="(min-width: 768px) 700px, 100vw"
title={intl.formatMessage( title={intl.formatMessage(
{ {
id: "common.imageGalleryWithTitle",
defaultMessage: "{title} - Image gallery", defaultMessage: "{title} - Image gallery",
}, },
{ title: hotel.name } { title: hotel.name }
@@ -111,6 +112,7 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) {
<span> <span>
{intl.formatMessage( {intl.formatMessage(
{ {
id: "common.kmToCityCenter",
defaultMessage: "{number} km to city center", defaultMessage: "{number} km to city center",
}, },
{ {
@@ -149,6 +151,7 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) {
typography="Body/Paragraph/mdBold" typography="Body/Paragraph/mdBold"
> >
{intl.formatMessage({ {intl.formatMessage({
id: "destination.seeHotelDetails",
defaultMessage: "See hotel details", defaultMessage: "See hotel details",
})} })}
</ButtonLink> </ButtonLink>

View File

@@ -69,7 +69,10 @@ export default function CityMap({
> >
<MaterialIcon icon="arrow_back" color="CurrentColor" size={24} /> <MaterialIcon icon="arrow_back" color="CurrentColor" size={24} />
<span> <span>
{intl.formatMessage({ defaultMessage: "Back to cities" })} {intl.formatMessage({
id: "destination.backToCities",
defaultMessage: "Back to cities",
})}
</span> </span>
</Button> </Button>
) : null} ) : null}

Some files were not shown because too many files have changed in this diff Show More