fix(i18n): prepare for Lokalise

This commit is contained in:
Michael Zetterberg
2025-01-03 14:54:46 +01:00
parent cbc17e2c5b
commit d2ce9c0d7c
120 changed files with 1703 additions and 1042 deletions

View File

@@ -24,12 +24,10 @@ export default function BedTypeInfo({ hasMultipleBedTypes }: BedTypeInfoProps) {
id: "Extra bed will be provided additionally",
})
const combinedStr = `${availabilityText}. ${extraBedText}`
if (hasMultipleBedTypes && hasChildWithExtraBed) {
return (
<Body>
{availabilityText}. {extraBedText}
</Body>
)
return <Body>{combinedStr}</Body>
}
if (hasMultipleBedTypes) {

View File

@@ -90,7 +90,9 @@ export default function Breakfast({ packages }: BreakfastProps) {
subtitle={
pkg.code === BreakfastPackageEnum.FREE_MEMBER_BREAKFAST
? intl.formatMessage<React.ReactNode>(
{ id: "breakfast.price.free" },
{
id: "<strikethrough>{amount}</strikethrough> <free>0 {currency}</free>/night per adult",
},
{
amount: formatPrice(
intl,
@@ -103,7 +105,7 @@ export default function Breakfast({ packages }: BreakfastProps) {
}
)
: intl.formatMessage(
{ id: "breakfast.price" },
{ id: "{amount}/night per adult" },
{
amount: formatPrice(
intl,

View File

@@ -89,10 +89,10 @@ export default function JoinScandicFriendsCard({
<Footnote color="uiTextPlaceholder">
{intl.formatMessage<React.ReactNode>(
{
id: "signup.terms",
id: "By signing up you accept the Scandic Friends <termsAndConditionsLink>Terms and Conditions</termsAndConditionsLink>. Your membership is valid until further notice, and you can terminate your membership at any time by sending an email to Scandic's customer service",
},
{
termsLink: (str) => (
termsAndConditionsLink: (str) => (
<Link
variant="default"
textDecoration="underline"

View File

@@ -57,7 +57,7 @@ export default function MemberPriceModal({
)}
</div>
<Button intent="primary" theme="base" onClick={() => setIsOpen(false)}>
OK
{intl.formatMessage({ id: "OK" })}
</Button>
</div>
</Modal>

View File

@@ -12,7 +12,6 @@ import useLang from "@/hooks/useLang"
import styles from "./signup.module.css"
export default function Signup({ name }: { name: string }) {
const lang = useLang()
const intl = useIntl()
const [isJoinChecked, setIsJoinChecked] = useState(false)
@@ -35,7 +34,9 @@ export default function Signup({ name }: { name: string }) {
<div className={styles.dateField}>
<header>
<Caption type="bold">
{intl.formatMessage({ id: "Birth date" })} *
<span className={styles.required}>
{intl.formatMessage({ id: "Birth date" })}
</span>
</Caption>
</header>
<DateSelect name="dateOfBirth" registerOptions={{ required: true }} />

View File

@@ -13,3 +13,7 @@
display: grid;
gap: var(--Spacing-x1);
}
.required:after {
content: " *";
}

View File

@@ -15,6 +15,9 @@ export default async function HotelHeader({ hotelData }: HotelHeaderProps) {
const hotel = hotelData.data.attributes
const image = hotel.hotelContent?.images
const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}`
return (
<header className={styles.header}>
<Image
@@ -30,14 +33,12 @@ export default async function HotelHeader({ hotelData }: HotelHeaderProps) {
<Title as="h1" level="h1" color="white" className={styles.title}>
{hotel.name}
</Title>
<address className={styles.address}>
<Caption color="white">
{hotel.address.streetAddress}, {hotel.address.city}
</Caption>
<div className={styles.address}>
<Caption color="white">{addressStr}</Caption>
<Caption color="white"></Caption>
<Caption color="white">
{intl.formatMessage(
{ id: "Distance in km to city centre" },
{ id: "{number} km to city centre" },
{
number: getSingleDecimal(
hotel.location.distanceToCentre / 1000
@@ -45,7 +46,7 @@ export default async function HotelHeader({ hotelData }: HotelHeaderProps) {
}
)}
</Caption>
</address>
</div>
</div>
<ToggleSidePeek hotelId={hotel.operaId} />
</div>

View File

@@ -160,7 +160,7 @@ export default function PaymentClient({
(errorMessage: string) => {
toast.error(
intl.formatMessage({
id: "payment.error.failed",
id: "We had an issue processing your booking. Please try again. No charges have been made.",
})
)
const currentPaymentMethod = methods.getValues("paymentMethod")
@@ -312,10 +312,6 @@ export default function PaymentClient({
return <LoadingSpinner />
}
const guaranteeing = intl.formatMessage({ id: "guaranteeing" })
const paying = intl.formatMessage({ id: "paying" })
const paymentVerb = mustBeGuaranteed ? guaranteeing : paying
return (
<>
<FormProvider {...methods}>
@@ -387,11 +383,10 @@ export default function PaymentClient({
<Caption>
{intl.formatMessage<React.ReactNode>(
{
id: "booking.terms",
id: "By paying with any of the payment methods available, I accept the terms for this booking and the general <termsAndConditionsLink>Terms & Conditions</termsAndConditionsLink>, and understand that Scandic will process my personal data for this booking in accordance with <privacyPolicyLink>Scandic's Privacy policy</privacyPolicyLink>. I also accept that Scandic require a valid credit card during my visit in case anything is left unpaid.",
},
{
paymentVerb,
termsLink: (str) => (
termsAndConditionsLink: (str) => (
<Link
className={styles.link}
variant="underscored"
@@ -401,7 +396,7 @@ export default function PaymentClient({
{str}
</Link>
),
privacyLink: (str) => (
privacyPolicyLink: (str) => (
<Link
className={styles.link}
variant="underscored"

View File

@@ -53,7 +53,7 @@ export default function PriceChangeDialog({
<br />
<span className={styles.oldPrice}>
{formatPrice(intl, oldPrice, currency)}
</span>{" "}
</span>
<strong className={styles.newPrice}>
{formatPrice(intl, newPrice, currency)}
</strong>

View File

@@ -28,7 +28,7 @@ export default function ToggleSidePeek({
intent="text"
wrapping
>
{intl.formatMessage({ id: "See room details" })}{" "}
{intl.formatMessage({ id: "See room details" })}
<ChevronRight height="14" />
</Button>
)

View File

@@ -47,8 +47,16 @@ export default function SelectedRoom({
className={styles.description}
color="uiTextHighContrast"
>
{room.roomType}{" "}
<span className={styles.rate}>{rateDescription}</span>
{intl.formatMessage<React.ReactNode>(
{ id: "{roomType} <rate>{rateDescription}</rate>" },
{
roomType: room.roomType,
rateDescription,
rate: (str) => {
return <span className={styles.rate}>{str}</span>
},
}
)}
</Subtitle>
<Link
className={styles.button}

View File

@@ -55,7 +55,7 @@ export default function SummaryBottomSheet({ children }: PropsWithChildren) {
onClick={toggleSummaryOpen}
className={styles.priceDetailsButton}
>
<Caption>{intl.formatMessage({ id: "Total price" })}:</Caption>
<Caption>{intl.formatMessage({ id: "Total price" })}</Caption>
<Subtitle>
{formatPrice(
intl,

View File

@@ -104,10 +104,17 @@ export default function PriceDetailsTable({
<TableSection>
<TableSectionHeader title={intl.formatMessage({ id: "Breakfast" })} />
<Row
label={intl.formatMessage(
{ id: "booking.adults.breakfasts" },
{ totalAdults: adults, totalBreakfasts: nights.length }
)}
label={`${intl.formatMessage(
{
id: "{totalAdults, plural, one {# voksen} other {# voksne}}",
},
{ totalAdults: adults }
)}, ${intl.formatMessage(
{
id: "{totalBreakfasts, plural, one {# morgenmad} other {# morgenmad}}",
},
{ totalBreakfasts: nights.length }
)}`}
value={formatPrice(
intl,
parseInt(breakfast.localPrice.totalPrice),
@@ -116,13 +123,17 @@ export default function PriceDetailsTable({
/>
{children?.length ? (
<Row
label={intl.formatMessage(
{ id: "booking.children.breakfasts" },
label={`${intl.formatMessage(
{
totalChildren: children.length,
totalBreakfasts: nights.length,
}
)}
id: "{totalChildren, plural, one {# child} other {# children}}",
},
{ totalChildren: children.length }
)}, ${intl.formatMessage(
{
id: "{totalBreakfasts, plural, one {# breakfast} other {# breakfasts}}",
},
{ totalBreakfasts: nights.length }
)}`}
value={formatPrice(intl, 0, breakfast.localPrice.currency)}
/>
) : null}
@@ -131,17 +142,17 @@ export default function PriceDetailsTable({
<TableSection>
<TableSectionHeader title={intl.formatMessage({ id: "Total" })} />
<Row
label={intl.formatMessage({ id: "booking.vat.excl" })}
label={intl.formatMessage({ id: "Price excluding VAT" })}
value={formatPrice(intl, priceExclVat, totalPrice.local.currency)}
/>
<Row
label={intl.formatMessage({ id: "booking.vat" }, { vat })}
label={intl.formatMessage({ id: "VAT {vat}%" }, { vat })}
value={formatPrice(intl, vatAmount, totalPrice.local.currency)}
/>
<tr className={styles.row}>
<td>
<Body textTransform="bold">
{intl.formatMessage({ id: "booking.vat.incl" })}
{intl.formatMessage({ id: "Price including VAT" })}
</Body>
</td>
<td className={styles.price}>

View File

@@ -107,7 +107,7 @@ export default function SummaryUI({
const diff = dt(booking.toDate).diff(booking.fromDate, "days")
const nights = intl.formatMessage(
{ id: "booking.nights" },
{ id: "{totalNights, plural, one {# night} other {# nights}}" },
{ totalNights: diff }
)
@@ -123,6 +123,22 @@ export default function SummaryUI({
}
}
const adultsMsg = intl.formatMessage(
{ id: "{totalAdults, plural, one {# adult} other {# adults}}" },
{ totalAdults: adults }
)
const guestsParts = [adultsMsg]
if (children?.length) {
const childrenMsg = intl.formatMessage(
{
id: "{totalChildren, plural, one {# child} other {# children}}",
},
{ totalChildren: children.length }
)
guestsParts.push(childrenMsg)
}
return (
<section className={styles.summary}>
<header className={styles.header}>
@@ -157,17 +173,7 @@ export default function SummaryUI({
</Body>
</div>
<Caption color="uiTextMediumContrast">
{`${intl.formatMessage(
{ id: "booking.adults" },
{ totalAdults: adults }
)}${
children?.length
? `, ${intl.formatMessage(
{ id: "booking.children" },
{ totalChildren: children.length }
)}`
: ""
}`}
{guestsParts.join(", ")}
</Caption>
<Caption color="uiTextMediumContrast">{cancellationText}</Caption>
<Modal
@@ -231,7 +237,10 @@ export default function SummaryUI({
<div className={styles.entry}>
<div>
<Body color="uiTextHighContrast">
{`${intl.formatMessage({ id: "Crib (child)" })} × ${childBedCrib}`}
{intl.formatMessage(
{ id: "Crib (child) × {count}" },
{ count: childBedCrib }
)}
</Body>
<Caption color="uiTextMediumContrast">
{intl.formatMessage({ id: "Based on availability" })}
@@ -246,7 +255,12 @@ export default function SummaryUI({
<div className={styles.entry}>
<div>
<Body color="uiTextHighContrast">
{`${intl.formatMessage({ id: "Extra bed (child)" })} × ${childBedExtraBed}`}
{intl.formatMessage(
{ id: "Extra bed (child) × {count}" },
{
count: childBedExtraBed,
}
)}
</Body>
</div>
<Body color="uiTextHighContrast">
@@ -278,7 +292,9 @@ export default function SummaryUI({
<div className={styles.entry}>
<Caption color="uiTextMediumContrast">
{intl.formatMessage(
{ id: "booking.adults" },
{
id: "{totalAdults, plural, one {# adult} other {# adults}}",
},
{ totalAdults: adults }
)}
</Caption>
@@ -294,7 +310,9 @@ export default function SummaryUI({
<div className={styles.entry}>
<Caption color="uiTextMediumContrast">
{intl.formatMessage(
{ id: "booking.children" },
{
id: "{totalChildren, plural, one {# child} other {# children}}",
},
{ totalChildren: children.length }
)}
</Caption>
@@ -345,11 +363,15 @@ export default function SummaryUI({
</Body>
{totalPrice.requested && (
<Caption color="uiTextMediumContrast">
{intl.formatMessage({ id: "Approx." })}{" "}
{formatPrice(
intl,
totalPrice.requested.price,
totalPrice.requested.currency
{intl.formatMessage(
{ id: "Approx. {value}" },
{
value: formatPrice(
intl,
totalPrice.requested.price,
totalPrice.requested.currency
),
}
)}
</Caption>
)}