Merged in feat/SW-431-payment-flow (pull request #635)

Feat/SW-431 payment flow

* feat(SW-431): Update mock hotel data

* feat(SW-431): Added route handler and trpc routes

* feat(SW-431): List payment methods and handle booking status and redirection

* feat(SW-431): Updated booking page to poll for booking status

* feat(SW-431): Updated create booking contract

* feat(SW-431): small fix

* fix(SW-431): Added intl string and sorted dictionaries

* fix(SW-431): Changes from PR

* fix(SW-431): fixes from PR

* fix(SW-431): add todo comments

* fix(SW-431): update schema prop


Approved-by: Simon.Emanuelsson
This commit is contained in:
Tobias Johansson
2024-10-04 09:37:09 +00:00
parent 105f721dc9
commit 4103e3fb37
26 changed files with 711 additions and 287 deletions

View File

@@ -1,6 +1,6 @@
import { notFound } from "next/navigation"
import { serverClient } from "@/lib/trpc/server" import { serverClient } from "@/lib/trpc/server"
import { getHotelDataSchema } from "@/server/routers/hotels/output"
import tempHotelData from "@/server/routers/hotels/tempHotelData.json"
import HotelSelectionHeader from "@/components/HotelReservation/HotelSelectionHeader" import HotelSelectionHeader from "@/components/HotelReservation/HotelSelectionHeader"
import BedSelection from "@/components/HotelReservation/SelectRate/BedSelection" import BedSelection from "@/components/HotelReservation/SelectRate/BedSelection"
@@ -80,12 +80,19 @@ export default async function SectionsPage({
}: PageArgs<LangParams & { section: string }, SectionPageProps>) { }: PageArgs<LangParams & { section: string }, SectionPageProps>) {
setLang(params.lang) setLang(params.lang)
// TODO: Use real endpoint. const hotel = await serverClient().hotel.hotelData.get({
const hotel = getHotelDataSchema.parse(tempHotelData) hotelId: "811",
language: params.lang,
})
if (!hotel) {
// TODO: handle case with hotel missing
return notFound()
}
const rooms = await serverClient().hotel.rates.get({ const rooms = await serverClient().hotel.rates.get({
// TODO: pass the correct hotel ID and all other parameters that should be included in the search // TODO: pass the correct hotel ID and all other parameters that should be included in the search
hotelId: "1", hotelId: hotel.data.id,
}) })
const intl = await getIntl() const intl = await getIntl()
@@ -170,7 +177,9 @@ export default async function SectionsPage({
header={intl.formatMessage({ id: "Payment info" })} header={intl.formatMessage({ id: "Payment info" })}
path={`payment?${currentSearchParams}`} path={`payment?${currentSearchParams}`}
> >
{params.section === "payment" && <Payment />} {params.section === "payment" && (
<Payment hotel={hotel.data.attributes} />
)}
</SectionAccordion> </SectionAccordion>
</div> </div>
<div className={styles.summary}> <div className={styles.summary}>

View File

@@ -0,0 +1,5 @@
import LoadingSpinner from "@/components/LoadingSpinner"
export default function Loading() {
return <LoadingSpinner />
}

View File

@@ -1,20 +1,67 @@
"use client"
import { useMemo } from "react"
import {
BOOKING_CONFIRMATION_NUMBER,
BookingStatusEnum,
} from "@/constants/booking"
import IntroSection from "@/components/HotelReservation/BookingConfirmation/IntroSection" import IntroSection from "@/components/HotelReservation/BookingConfirmation/IntroSection"
import StaySection from "@/components/HotelReservation/BookingConfirmation/StaySection" import StaySection from "@/components/HotelReservation/BookingConfirmation/StaySection"
import SummarySection from "@/components/HotelReservation/BookingConfirmation/SummarySection" import SummarySection from "@/components/HotelReservation/BookingConfirmation/SummarySection"
import { tempConfirmationData } from "@/components/HotelReservation/BookingConfirmation/tempConfirmationData" import { tempConfirmationData } from "@/components/HotelReservation/BookingConfirmation/tempConfirmationData"
import LoadingSpinner from "@/components/LoadingSpinner"
import { useHandleBookingStatus } from "@/hooks/booking/useHandleBookingStatus"
import styles from "./page.module.css" import styles from "./page.module.css"
const maxRetries = 10
const retryInterval = 2000
export default function BookingConfirmationPage() { export default function BookingConfirmationPage() {
const { email, hotel, stay, summary } = tempConfirmationData const { email, hotel, stay, summary } = tempConfirmationData
return ( const confirmationNumber = useMemo(() => {
<main className={styles.main}> if (typeof window === "undefined") return ""
<section className={styles.section}>
<IntroSection email={email} /> const storedConfirmationNumber = sessionStorage.getItem(
<StaySection hotel={hotel} stay={stay} /> BOOKING_CONFIRMATION_NUMBER
<SummarySection summary={summary} /> )
</section> // TODO: cleanup stored values
</main> // sessionStorage.removeItem(BOOKING_CONFIRMATION_NUMBER)
return storedConfirmationNumber
}, [])
const bookingStatus = useHandleBookingStatus(
confirmationNumber,
BookingStatusEnum.BookingCompleted,
maxRetries,
retryInterval
) )
if (
confirmationNumber === null ||
bookingStatus.isError ||
(bookingStatus.isFetched && !bookingStatus.data)
) {
// TODO: handle error
throw new Error("Error fetching booking status")
}
if (
bookingStatus.data?.reservationStatus === BookingStatusEnum.BookingCompleted
) {
return (
<main className={styles.main}>
<section className={styles.section}>
<IntroSection email={email} />
<StaySection hotel={hotel} stay={stay} />
<SummarySection summary={summary} />
</section>
</main>
)
}
return <LoadingSpinner />
} }

View File

@@ -0,0 +1,37 @@
import { NextRequest, NextResponse } from "next/server"
import { env } from "process"
import { Lang } from "@/constants/languages"
import {
bookingConfirmation,
payment,
} from "@/constants/routes/hotelReservation"
export async function GET(
request: NextRequest,
{ params }: { params: { lang: string; status: string } }
): Promise<NextResponse> {
console.log(`[payment-callback] callback started`)
const lang = params.lang as Lang
const status = params.status
const returnUrl = new URL(`${env.PUBLIC_URL}/${payment[lang]}`)
if (status === "success") {
const confirmationUrl = new URL(
`${env.PUBLIC_URL}/${bookingConfirmation[lang]}`
)
console.log(`[payment-callback] redirecting to: ${confirmationUrl}`)
return NextResponse.redirect(confirmationUrl)
}
if (status === "cancel") {
returnUrl.searchParams.set("cancel", "true")
}
if (status === "error") {
returnUrl.searchParams.set("error", "true")
}
console.log(`[payment-callback] redirecting to: ${returnUrl}`)
return NextResponse.redirect(returnUrl)
}

View File

@@ -1,16 +1,17 @@
import { useIntl } from "react-intl"
import Button from "@/components/TempDesignSystem/Button" import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link" import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body" import Body from "@/components/TempDesignSystem/Text/Body"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import Title from "@/components/TempDesignSystem/Text/Title" import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import styles from "./introSection.module.css" import styles from "./introSection.module.css"
import { IntroSectionProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation" import { IntroSectionProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
export default async function IntroSection({ email }: IntroSectionProps) { export default function IntroSection({ email }: IntroSectionProps) {
const intl = await getIntl() const intl = useIntl()
return ( return (
<section className={styles.section}> <section className={styles.section}>

View File

@@ -1,16 +1,17 @@
import { useIntl } from "react-intl"
import { ArrowRightIcon, ScandicLogoIcon } from "@/components/Icons" import { ArrowRightIcon, ScandicLogoIcon } from "@/components/Icons"
import Image from "@/components/Image" import Image from "@/components/Image"
import Body from "@/components/TempDesignSystem/Text/Body" import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption" import Caption from "@/components/TempDesignSystem/Text/Caption"
import Title from "@/components/TempDesignSystem/Text/Title" import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import styles from "./staySection.module.css" import styles from "./staySection.module.css"
import { StaySectionProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation" import { StaySectionProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
export default async function StaySection({ hotel, stay }: StaySectionProps) { export default function StaySection({ hotel, stay }: StaySectionProps) {
const intl = await getIntl() const intl = useIntl()
const nightsText = const nightsText =
stay.nights > 1 stay.nights > 1

View File

@@ -1,13 +1,14 @@
import { useIntl } from "react-intl"
import Caption from "@/components/TempDesignSystem/Text/Caption" import Caption from "@/components/TempDesignSystem/Text/Caption"
import Title from "@/components/TempDesignSystem/Text/Title" import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import styles from "./summarySection.module.css" import styles from "./summarySection.module.css"
import { SummarySectionProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation" import { SummarySectionProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
export default async function SummarySection({ summary }: SummarySectionProps) { export default function SummarySection({ summary }: SummarySectionProps) {
const intl = await getIntl() const intl = useIntl()
const roomType = `${intl.formatMessage({ id: "Type of room" })}: ${summary.roomType}` const roomType = `${intl.formatMessage({ id: "Type of room" })}: ${summary.roomType}`
const bedType = `${intl.formatMessage({ id: "Type of bed" })}: ${summary.bedType}` const bedType = `${intl.formatMessage({ id: "Type of bed" })}: ${summary.bedType}`
const breakfast = `${intl.formatMessage({ id: "Breakfast" })}: ${summary.breakfast}` const breakfast = `${intl.formatMessage({ id: "Breakfast" })}: ${summary.breakfast}`

View File

@@ -1,62 +1,161 @@
"use client" "use client"
import { useRouter } from "next/navigation"
import { useEffect, useState } from "react"
import { useIntl } from "react-intl"
import {
BOOKING_CONFIRMATION_NUMBER,
BookingStatusEnum,
} from "@/constants/booking"
import { trpc } from "@/lib/trpc/client" import { trpc } from "@/lib/trpc/client"
import LoadingSpinner from "@/components/LoadingSpinner"
import Button from "@/components/TempDesignSystem/Button" import Button from "@/components/TempDesignSystem/Button"
import { toast } from "@/components/TempDesignSystem/Toasts"
import { useHandleBookingStatus } from "@/hooks/booking/useHandleBookingStatus"
import useLang from "@/hooks/useLang"
import styles from "./payment.module.css"
import { PaymentProps } from "@/types/components/hotelReservation/selectRate/section"
const maxRetries = 40
const retryInterval = 2000
export default function Payment({ hotel }: PaymentProps) {
const router = useRouter()
const lang = useLang()
const intl = useIntl()
const [confirmationNumber, setConfirmationNumber] = useState<string>("")
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState<string>("")
export default function Payment() {
const initiateBooking = trpc.booking.booking.create.useMutation({ const initiateBooking = trpc.booking.booking.create.useMutation({
onSuccess: (result) => { onSuccess: (result) => {
// TODO: Handle success, poll for payment link and redirect the user to the payment if (result?.confirmationNumber) {
console.log("Res", result) // Planet doesn't support query params so we have to store values in session storage
sessionStorage.setItem(
BOOKING_CONFIRMATION_NUMBER,
result.confirmationNumber
)
setConfirmationNumber(result.confirmationNumber)
} else {
// TODO: add proper error message
toast.error("Failed to create booking")
}
}, },
onError: () => { onError: (error) => {
// TODO: Handle error console.error("Error", error)
console.log("Error") // TODO: add proper error message
toast.error("Failed to create booking")
}, },
}) })
return ( const bookingStatus = useHandleBookingStatus(
<Button confirmationNumber,
onClick={() => BookingStatusEnum.PaymentRegistered,
// TODO: Use real values maxRetries,
initiateBooking.mutate({ retryInterval
hotelId: "811", )
checkInDate: "2024-12-10",
checkOutDate: "2024-12-11", useEffect(() => {
rooms: [ if (bookingStatus?.data?.paymentUrl) {
{ router.push(bookingStatus.data.paymentUrl)
adults: 1, }
children: 0, }, [bookingStatus, router])
rateCode: "SAVEEU",
roomTypeCode: "QC", function handleSubmit() {
guest: { initiateBooking.mutate({
title: "Mr", hotelId: hotel.operaId,
firstName: "Test", checkInDate: "2024-12-10",
lastName: "User", checkOutDate: "2024-12-11",
email: "test.user@scandichotels.com", rooms: [
phoneCountryCodePrefix: "string", {
phoneNumber: "string", adults: 1,
countryCode: "string", childrenAges: [],
}, rateCode: "SAVEEU",
smsConfirmationRequested: true, roomTypeCode: "QC",
}, guest: {
], title: "Mr",
payment: { firstName: "Test",
cardHolder: { lastName: "User",
Email: "test.user@scandichotels.com", email: "test.user@scandichotels.com",
Name: "Test User", phoneCountryCodePrefix: "string",
PhoneCountryCode: "", phoneNumber: "string",
PhoneSubscriber: "", countryCode: "string",
},
success: "success/handle",
error: "error/handle",
cancel: "cancel/handle",
}, },
}) packages: {
} breakfast: true,
> allergyFriendly: true,
Create booking petFriendly: true,
</Button> accessibility: true,
},
smsConfirmationRequested: true,
},
],
payment: {
paymentMethod: selectedPaymentMethod,
cardHolder: {
email: "test.user@scandichotels.com",
name: "Test User",
phoneCountryCode: "",
phoneSubscriber: "",
},
success: `api/web/payment-callback/${lang}/success`,
error: `api/web/payment-callback/${lang}/error`,
cancel: `api/web/payment-callback/${lang}/cancel`,
},
})
}
if (
initiateBooking.isPending ||
(confirmationNumber && !bookingStatus.data?.paymentUrl)
) {
return <LoadingSpinner />
}
return (
<div>
<div>
<div className={styles.paymentItemContainer}>
<button
className={styles.paymentItem}
onClick={() => setSelectedPaymentMethod("card")}
>
<input
type="radio"
name="payment-method"
id="card"
value="card"
checked={selectedPaymentMethod === "card"}
/>
<label htmlFor="card">card</label>
</button>
{hotel.merchantInformationData.alternatePaymentOptions.map(
(paymentOption) => (
<button
key={paymentOption}
className={styles.paymentItem}
onClick={() => setSelectedPaymentMethod(paymentOption)}
>
<input
type="radio"
name="payment-method"
id={paymentOption}
value={paymentOption}
checked={selectedPaymentMethod === paymentOption}
/>
<label htmlFor={paymentOption}>{paymentOption}</label>
</button>
)
)}
</div>
</div>
<Button disabled={!selectedPaymentMethod} onClick={handleSubmit}>
{intl.formatMessage({ id: "Complete booking & go to payment" })}
</Button>
</div>
) )
} }

View File

@@ -0,0 +1,18 @@
.paymentItemContainer {
max-width: 480px;
display: flex;
flex-direction: column;
gap: var(--Spacing-x1);
padding-bottom: var(--Spacing-x4);
}
.paymentItem {
background-color: var(--Base-Background-Normal);
padding: var(--Spacing-x3);
border: 1px solid var(--Base-Border-Normal);
border-radius: var(--Corner-radius-Medium);
display: flex;
align-items: center;
gap: var(--Spacing-x2);
cursor: pointer;
}

7
constants/booking.ts Normal file
View File

@@ -0,0 +1,7 @@
export enum BookingStatusEnum {
CreatedInOhip = "CreatedInOhip",
PaymentRegistered = "PaymentRegistered",
BookingCompleted = "BookingCompleted",
}
export const BOOKING_CONFIRMATION_NUMBER = "bookingConfirmationNumber"

View File

@@ -28,4 +28,24 @@ export const selectHotelMap = {
de: `${selectHotel.de}/map`, de: `${selectHotel.de}/map`,
} }
/** @type {import('@/types/routes').LangRoute} */
export const payment = {
en: `${hotelReservation.en}/payment`,
sv: `${hotelReservation.sv}/betalning`,
no: `${hotelReservation.no}/betaling`,
fi: `${hotelReservation.fi}/maksu`,
da: `${hotelReservation.da}/payment`,
de: `${hotelReservation.de}/bezahlung`,
}
/** @type {import('@/types/routes').LangRoute} */
export const bookingConfirmation = {
en: `${hotelReservation.en}/booking-confirmation`,
sv: `${hotelReservation.sv}/bokningsbekraftelse`,
no: `${hotelReservation.no}/booking-confirmation`,
fi: `${hotelReservation.fi}/varausvahvistus`,
da: `${hotelReservation.da}/booking-confirmation`,
de: `${hotelReservation.de}/buchungsbesttigung`,
}
export const bookingFlow = [...Object.values(hotelReservation)] export const bookingFlow = [...Object.values(hotelReservation)]

View File

@@ -0,0 +1,35 @@
"use client"
import { BookingStatusEnum } from "@/constants/booking"
import { trpc } from "@/lib/trpc/client"
export function useHandleBookingStatus(
confirmationNumber: string | null,
expectedStatus: BookingStatusEnum,
maxRetries: number,
retryInterval: number
) {
const query = trpc.booking.status.useQuery(
{ confirmationNumber: confirmationNumber ?? "" },
{
enabled: !!confirmationNumber,
refetchInterval: (query) => {
if (query.state.error || query.state.dataUpdateCount >= maxRetries) {
return false
}
if (query.state.data?.reservationStatus === expectedStatus) {
return false
}
return retryInterval
},
refetchIntervalInBackground: true,
refetchOnWindowFocus: false,
refetchOnMount: false,
retry: false,
}
)
return query
}

View File

@@ -14,6 +14,7 @@
"Any changes you've made will be lost.": "Alle ændringer, du har foretaget, går tabt.", "Any changes you've made will be lost.": "Alle ændringer, du har foretaget, går tabt.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Er du sikker på, at du vil fjerne kortet, der slutter me {lastFourDigits} fra din medlemsprofil?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Er du sikker på, at du vil fjerne kortet, der slutter me {lastFourDigits} fra din medlemsprofil?",
"Arrival date": "Ankomstdato", "Arrival date": "Ankomstdato",
"as of today": "fra idag",
"As our": "Som vores {level}", "As our": "Som vores {level}",
"As our Close Friend": "Som vores nære ven", "As our Close Friend": "Som vores nære ven",
"At latest": "Senest", "At latest": "Senest",
@@ -23,14 +24,16 @@
"Bed type": "Seng type", "Bed type": "Seng type",
"Book": "Book", "Book": "Book",
"Book reward night": "Book bonusnat", "Book reward night": "Book bonusnat",
"Code / Voucher": "Bookingkoder / voucher",
"Booking number": "Bookingnummer", "Booking number": "Bookingnummer",
"booking.nights": "{totalNights, plural, one {# nat} other {# nætter}}",
"Breakfast": "Morgenmad", "Breakfast": "Morgenmad",
"Breakfast excluded": "Morgenmad ikke inkluderet", "Breakfast excluded": "Morgenmad ikke inkluderet",
"Breakfast included": "Morgenmad inkluderet", "Breakfast included": "Morgenmad inkluderet",
"Bus terminal": "Busstation", "Bus terminal": "Busstation",
"Business": "Forretning", "Business": "Forretning",
"by": "inden",
"Cancel": "Afbestille", "Cancel": "Afbestille",
"characters": "tegn",
"Check in": "Check ind", "Check in": "Check ind",
"Check out": "Check ud", "Check out": "Check ud",
"Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Tjek de kreditkort, der er gemt på din profil. Betal med et gemt kort, når du er logget ind for en mere jævn weboplevelse.", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Tjek de kreditkort, der er gemt på din profil. Betal med et gemt kort, når du er logget ind for en mere jævn weboplevelse.",
@@ -45,8 +48,10 @@
"Close menu": "Luk menu", "Close menu": "Luk menu",
"Close my pages menu": "Luk mine sider menu", "Close my pages menu": "Luk mine sider menu",
"Close the map": "Luk kortet", "Close the map": "Luk kortet",
"Code / Voucher": "Bookingkoder / voucher",
"Coming up": "Er lige om hjørnet", "Coming up": "Er lige om hjørnet",
"Compare all levels": "Sammenlign alle niveauer", "Compare all levels": "Sammenlign alle niveauer",
"Complete booking & go to payment": "Udfyld booking & gå til betaling",
"Contact us": "Kontakt os", "Contact us": "Kontakt os",
"Continue": "Blive ved", "Continue": "Blive ved",
"Copyright all rights reserved": "Scandic AB Alle rettigheder forbeholdes", "Copyright all rights reserved": "Scandic AB Alle rettigheder forbeholdes",
@@ -72,9 +77,9 @@
"Explore all levels and benefits": "Udforsk alle niveauer og fordele", "Explore all levels and benefits": "Udforsk alle niveauer og fordele",
"Explore nearby": "Udforsk i nærheden", "Explore nearby": "Udforsk i nærheden",
"Extras to your booking": "Tillæg til din booking", "Extras to your booking": "Tillæg til din booking",
"FAQ": "Ofte stillede spørgsmål",
"Failed to delete credit card, please try again later.": "Kunne ikke slette kreditkort. Prøv venligst igen senere.", "Failed to delete credit card, please try again later.": "Kunne ikke slette kreditkort. Prøv venligst igen senere.",
"Fair": "Messe", "Fair": "Messe",
"FAQ": "Ofte stillede spørgsmål",
"Find booking": "Find booking", "Find booking": "Find booking",
"Find hotels": "Find hotel", "Find hotels": "Find hotel",
"Flexibility": "Fleksibilitet", "Flexibility": "Fleksibilitet",
@@ -85,17 +90,22 @@
"Get inspired": "Bliv inspireret", "Get inspired": "Bliv inspireret",
"Go back to edit": "Gå tilbage til redigering", "Go back to edit": "Gå tilbage til redigering",
"Go back to overview": "Gå tilbage til oversigten", "Go back to overview": "Gå tilbage til oversigten",
"Guests & Rooms": "Gæster & værelser",
"Hi": "Hei", "Hi": "Hei",
"Highest level": "Højeste niveau", "Highest level": "Højeste niveau",
"Hospital": "Hospital", "Hospital": "Hospital",
"Hotel": "Hotel", "Hotel": "Hotel",
"Hotel facilities": "Hotel faciliteter", "Hotel facilities": "Hotel faciliteter",
"Hotel surroundings": "Hotel omgivelser", "Hotel surroundings": "Hotel omgivelser",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "personer",
"hotelPages.rooms.roomCard.seeRoomDetails": "Se værelsesdetaljer",
"Hotels": "Hoteller", "Hotels": "Hoteller",
"How do you want to sleep?": "Hvordan vil du sove?", "How do you want to sleep?": "Hvordan vil du sove?",
"How it works": "Hvordan det virker", "How it works": "Hvordan det virker",
"Image gallery": "Billedgalleri", "Image gallery": "Billedgalleri",
"Join Scandic Friends": "Tilmeld dig Scandic Friends", "Join Scandic Friends": "Tilmeld dig Scandic Friends",
"km to city center": "km til byens centrum",
"Language": "Sprog", "Language": "Sprog",
"Latest searches": "Seneste søgninger", "Latest searches": "Seneste søgninger",
"Level": "Niveau", "Level": "Niveau",
@@ -122,9 +132,9 @@
"Member price": "Medlemspris", "Member price": "Medlemspris",
"Member price from": "Medlemspris fra", "Member price from": "Medlemspris fra",
"Members": "Medlemmer", "Members": "Medlemmer",
"Membership cards": "Medlemskort",
"Membership ID": "Medlems-id", "Membership ID": "Medlems-id",
"Membership ID copied to clipboard": "Medlems-ID kopieret til udklipsholder", "Membership ID copied to clipboard": "Medlems-ID kopieret til udklipsholder",
"Membership cards": "Medlemskort",
"Menu": "Menu", "Menu": "Menu",
"Modify": "Ændre", "Modify": "Ændre",
"Month": "Måned", "Month": "Måned",
@@ -139,6 +149,9 @@
"Nearby companies": "Nærliggende virksomheder", "Nearby companies": "Nærliggende virksomheder",
"New password": "Nyt kodeord", "New password": "Nyt kodeord",
"Next": "Næste", "Next": "Næste",
"next level:": "Næste niveau:",
"night": "nat",
"nights": "nætter",
"Nights needed to level up": "Nætter nødvendige for at komme i niveau", "Nights needed to level up": "Nætter nødvendige for at komme i niveau",
"No content published": "Intet indhold offentliggjort", "No content published": "Intet indhold offentliggjort",
"No matching location found": "Der blev ikke fundet nogen matchende placering", "No matching location found": "Der blev ikke fundet nogen matchende placering",
@@ -149,11 +162,13 @@
"Non-refundable": "Ikke-refunderbart", "Non-refundable": "Ikke-refunderbart",
"Not found": "Ikke fundet", "Not found": "Ikke fundet",
"Nr night, nr adult": "{nights, number} nat, {adults, number} voksen", "Nr night, nr adult": "{nights, number} nat, {adults, number} voksen",
"number": "nummer",
"On your journey": "På din rejse", "On your journey": "På din rejse",
"Open": "Åben", "Open": "Åben",
"Open language menu": "Åbn sprogmenuen", "Open language menu": "Åbn sprogmenuen",
"Open menu": "Åbn menuen", "Open menu": "Åbn menuen",
"Open my pages menu": "Åbn mine sider menuen", "Open my pages menu": "Åbn mine sider menuen",
"or": "eller",
"Overview": "Oversigt", "Overview": "Oversigt",
"Parking": "Parkering", "Parking": "Parkering",
"Parking / Garage": "Parkering / Garage", "Parking / Garage": "Parkering / Garage",
@@ -165,6 +180,7 @@
"Phone is required": "Telefonnummer er påkrævet", "Phone is required": "Telefonnummer er påkrævet",
"Phone number": "Telefonnummer", "Phone number": "Telefonnummer",
"Please enter a valid phone number": "Indtast venligst et gyldigt telefonnummer", "Please enter a valid phone number": "Indtast venligst et gyldigt telefonnummer",
"points": "Point",
"Points": "Point", "Points": "Point",
"Points being calculated": "Point udregnes", "Points being calculated": "Point udregnes",
"Points earned prior to May 1, 2021": "Point optjent inden 1. maj 2021", "Points earned prior to May 1, 2021": "Point optjent inden 1. maj 2021",
@@ -183,7 +199,6 @@
"Room & Terms": "Værelse & Vilkår", "Room & Terms": "Værelse & Vilkår",
"Room facilities": "Værelsesfaciliteter", "Room facilities": "Værelsesfaciliteter",
"Rooms": "Værelser", "Rooms": "Værelser",
"Guests & Rooms": "Gæster & værelser",
"Save": "Gemme", "Save": "Gemme",
"Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Mastercard": "Scandic Friends Mastercard",
"Scandic Friends Point Shop": "Scandic Friends Point Shop", "Scandic Friends Point Shop": "Scandic Friends Point Shop",
@@ -208,25 +223,29 @@
"Something went wrong and we couldn't add your card. Please try again later.": "Noget gik galt, og vi kunne ikke tilføje dit kort. Prøv venligst igen senere.", "Something went wrong and we couldn't add your card. Please try again later.": "Noget gik galt, og vi kunne ikke tilføje dit kort. Prøv venligst igen senere.",
"Something went wrong and we couldn't remove your card. Please try again later.": "Noget gik galt, og vi kunne ikke fjerne dit kort. Prøv venligst igen senere.", "Something went wrong and we couldn't remove your card. Please try again later.": "Noget gik galt, og vi kunne ikke fjerne dit kort. Prøv venligst igen senere.",
"Something went wrong!": "Noget gik galt!", "Something went wrong!": "Noget gik galt!",
"special character": "speciel karakter",
"spendable points expiring by": "{points} Brugbare point udløber den {date}",
"Sports": "Sport", "Sports": "Sport",
"Standard price": "Standardpris", "Standard price": "Standardpris",
"Street": "Gade", "Street": "Gade",
"Successfully updated profile!": "Profilen er opdateret med succes!", "Successfully updated profile!": "Profilen er opdateret med succes!",
"Summary": "Opsummering", "Summary": "Opsummering",
"TUI Points": "TUI Points",
"Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Fortæl os, hvilke oplysninger og opdateringer du gerne vil modtage, og hvordan, ved at klikke på linket nedenfor.", "Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Fortæl os, hvilke oplysninger og opdateringer du gerne vil modtage, og hvordan, ved at klikke på linket nedenfor.",
"Thank you": "Tak", "Thank you": "Tak",
"Theatre": "Teater", "Theatre": "Teater",
"There are no transactions to display": "Der er ingen transaktioner at vise", "There are no transactions to display": "Der er ingen transaktioner at vise",
"Things nearby HOTEL_NAME": "Ting i nærheden af {hotelName}", "Things nearby HOTEL_NAME": "Ting i nærheden af {hotelName}",
"to": "til",
"Total Points": "Samlet antal point", "Total Points": "Samlet antal point",
"Tourist": "Turist", "Tourist": "Turist",
"Transaction date": "Overførselsdato", "Transaction date": "Overførselsdato",
"Transactions": "Transaktioner", "Transactions": "Transaktioner",
"Transportations": "Transport", "Transportations": "Transport",
"Tripadvisor reviews": "{rating} ({count} anmeldelser på Tripadvisor)", "Tripadvisor reviews": "{rating} ({count} anmeldelser på Tripadvisor)",
"TUI Points": "TUI Points",
"Type of bed": "Sengtype", "Type of bed": "Sengtype",
"Type of room": "Værelsestype", "Type of room": "Værelsestype",
"uppercase letter": "stort bogstav",
"Use bonus cheque": "Brug Bonus Cheque", "Use bonus cheque": "Brug Bonus Cheque",
"User information": "Brugeroplysninger", "User information": "Brugeroplysninger",
"View as list": "Vis som liste", "View as list": "Vis som liste",
@@ -252,9 +271,9 @@
"You canceled adding a new credit card.": "Du har annulleret tilføjelsen af et nyt kreditkort.", "You canceled adding a new credit card.": "Du har annulleret tilføjelsen af et nyt kreditkort.",
"You have no previous stays.": "Du har ingen tidligere ophold.", "You have no previous stays.": "Du har ingen tidligere ophold.",
"You have no upcoming stays.": "Du har ingen kommende ophold.", "You have no upcoming stays.": "Du har ingen kommende ophold.",
"Your Challenges Conquer & Earn!": "Dine udfordringer Overvind og tjen!",
"Your card was successfully removed!": "Dit kort blev fjernet!", "Your card was successfully removed!": "Dit kort blev fjernet!",
"Your card was successfully saved!": "Dit kort blev gemt!", "Your card was successfully saved!": "Dit kort blev gemt!",
"Your Challenges Conquer & Earn!": "Dine udfordringer Overvind og tjen!",
"Your current level": "Dit nuværende niveau", "Your current level": "Dit nuværende niveau",
"Your details": "Dine oplysninger", "Your details": "Dine oplysninger",
"Your level": "Dit niveau", "Your level": "Dit niveau",
@@ -262,23 +281,5 @@
"Zip code": "Postnummer", "Zip code": "Postnummer",
"Zoo": "Zoo", "Zoo": "Zoo",
"Zoom in": "Zoom ind", "Zoom in": "Zoom ind",
"Zoom out": "Zoom ud", "Zoom out": "Zoom ud"
"as of today": "pr. dags dato",
"booking.nights": "{totalNights, plural, one {# nat} other {# nætter}}",
"by": "inden",
"characters": "tegn",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "personer",
"hotelPages.rooms.roomCard.seeRoomDetails": "Se værelsesdetaljer",
"km to city center": "km til byens centrum",
"next level:": "Næste niveau:",
"night": "nat",
"nights": "nætter",
"number": "nummer",
"or": "eller",
"points": "Point",
"special character": "speciel karakter",
"spendable points expiring by": "{points} Brugbare point udløber den {date}",
"to": "til",
"uppercase letter": "stort bogstav"
} }

View File

@@ -14,6 +14,7 @@
"Any changes you've made will be lost.": "Alle Änderungen, die Sie vorgenommen haben, gehen verloren.", "Any changes you've made will be lost.": "Alle Änderungen, die Sie vorgenommen haben, gehen verloren.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Möchten Sie die Karte mit der Endung {lastFourDigits} wirklich aus Ihrem Mitgliedsprofil entfernen?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Möchten Sie die Karte mit der Endung {lastFourDigits} wirklich aus Ihrem Mitgliedsprofil entfernen?",
"Arrival date": "Ankunftsdatum", "Arrival date": "Ankunftsdatum",
"as of today": "Stand heute",
"As our": "Als unser {level}", "As our": "Als unser {level}",
"As our Close Friend": "Als unser enger Freund", "As our Close Friend": "Als unser enger Freund",
"At latest": "Spätestens", "At latest": "Spätestens",
@@ -23,14 +24,16 @@
"Bed type": "Bettentyp", "Bed type": "Bettentyp",
"Book": "Buchen", "Book": "Buchen",
"Book reward night": "Bonusnacht buchen", "Book reward night": "Bonusnacht buchen",
"Code / Voucher": "Buchungscodes / Gutscheine",
"Booking number": "Buchungsnummer", "Booking number": "Buchungsnummer",
"booking.nights": "{totalNights, plural, one {# nacht} other {# Nächte}}",
"Breakfast": "Frühstück", "Breakfast": "Frühstück",
"Breakfast excluded": "Frühstück nicht inbegriffen", "Breakfast excluded": "Frühstück nicht inbegriffen",
"Breakfast included": "Frühstück inbegriffen", "Breakfast included": "Frühstück inbegriffen",
"Bus terminal": "Busbahnhof", "Bus terminal": "Busbahnhof",
"Business": "Geschäft", "Business": "Geschäft",
"by": "bis",
"Cancel": "Stornieren", "Cancel": "Stornieren",
"characters": "figuren",
"Check in": "Einchecken", "Check in": "Einchecken",
"Check out": "Auschecken", "Check out": "Auschecken",
"Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Sehen Sie sich die in Ihrem Profil gespeicherten Kreditkarten an. Bezahlen Sie mit einer gespeicherten Karte, wenn Sie angemeldet sind, für ein reibungsloseres Web-Erlebnis.", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Sehen Sie sich die in Ihrem Profil gespeicherten Kreditkarten an. Bezahlen Sie mit einer gespeicherten Karte, wenn Sie angemeldet sind, für ein reibungsloseres Web-Erlebnis.",
@@ -45,8 +48,10 @@
"Close menu": "Menü schließen", "Close menu": "Menü schließen",
"Close my pages menu": "Meine Seiten Menü schließen", "Close my pages menu": "Meine Seiten Menü schließen",
"Close the map": "Karte schließen", "Close the map": "Karte schließen",
"Code / Voucher": "Buchungscodes / Gutscheine",
"Coming up": "Demnächst", "Coming up": "Demnächst",
"Compare all levels": "Vergleichen Sie alle Levels", "Compare all levels": "Vergleichen Sie alle Levels",
"Complete booking & go to payment": "Buchung abschließen & zur Bezahlung gehen",
"Contact us": "Kontaktieren Sie uns", "Contact us": "Kontaktieren Sie uns",
"Continue": "Weitermachen", "Continue": "Weitermachen",
"Copyright all rights reserved": "Scandic AB Alle Rechte vorbehalten", "Copyright all rights reserved": "Scandic AB Alle Rechte vorbehalten",
@@ -72,9 +77,9 @@
"Explore all levels and benefits": "Entdecken Sie alle Levels und Vorteile", "Explore all levels and benefits": "Entdecken Sie alle Levels und Vorteile",
"Explore nearby": "Erkunden Sie die Umgebung", "Explore nearby": "Erkunden Sie die Umgebung",
"Extras to your booking": "Extras zu Ihrer Buchung", "Extras to your booking": "Extras zu Ihrer Buchung",
"FAQ": "Häufig gestellte Fragen",
"Failed to delete credit card, please try again later.": "Kreditkarte konnte nicht gelöscht werden. Bitte versuchen Sie es später noch einmal.", "Failed to delete credit card, please try again later.": "Kreditkarte konnte nicht gelöscht werden. Bitte versuchen Sie es später noch einmal.",
"Fair": "Messe", "Fair": "Messe",
"FAQ": "Häufig gestellte Fragen",
"Find booking": "Buchung finden", "Find booking": "Buchung finden",
"Find hotels": "Hotels finden", "Find hotels": "Hotels finden",
"Flexibility": "Flexibilität", "Flexibility": "Flexibilität",
@@ -85,17 +90,22 @@
"Get inspired": "Lassen Sie sich inspieren", "Get inspired": "Lassen Sie sich inspieren",
"Go back to edit": "Zurück zum Bearbeiten", "Go back to edit": "Zurück zum Bearbeiten",
"Go back to overview": "Zurück zur Übersicht", "Go back to overview": "Zurück zur Übersicht",
"Guests & Rooms": "Gäste & Zimmer",
"Hi": "Hallo", "Hi": "Hallo",
"Highest level": "Höchstes Level", "Highest level": "Höchstes Level",
"Hospital": "Krankenhaus", "Hospital": "Krankenhaus",
"Hotel": "Hotel", "Hotel": "Hotel",
"Hotel facilities": "Hotel-Infos", "Hotel facilities": "Hotel-Infos",
"Hotel surroundings": "Umgebung des Hotels", "Hotel surroundings": "Umgebung des Hotels",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "personen",
"hotelPages.rooms.roomCard.seeRoomDetails": "Zimmerdetails ansehen",
"Hotels": "Hotels", "Hotels": "Hotels",
"How do you want to sleep?": "Wie möchtest du schlafen?", "How do you want to sleep?": "Wie möchtest du schlafen?",
"How it works": "Wie es funktioniert", "How it works": "Wie es funktioniert",
"Image gallery": "Bildergalerie", "Image gallery": "Bildergalerie",
"Join Scandic Friends": "Treten Sie Scandic Friends bei", "Join Scandic Friends": "Treten Sie Scandic Friends bei",
"km to city center": "km bis zum Stadtzentrum",
"Language": "Sprache", "Language": "Sprache",
"Latest searches": "Letzte Suchanfragen", "Latest searches": "Letzte Suchanfragen",
"Level": "Level", "Level": "Level",
@@ -122,9 +132,9 @@
"Member price": "Mitgliederpreis", "Member price": "Mitgliederpreis",
"Member price from": "Mitgliederpreis ab", "Member price from": "Mitgliederpreis ab",
"Members": "Mitglieder", "Members": "Mitglieder",
"Membership cards": "Mitgliedskarten",
"Membership ID": "Mitglieds-ID", "Membership ID": "Mitglieds-ID",
"Membership ID copied to clipboard": "Mitglieds-ID in die Zwischenablage kopiert", "Membership ID copied to clipboard": "Mitglieds-ID in die Zwischenablage kopiert",
"Membership cards": "Mitgliedskarten",
"Menu": "Menu", "Menu": "Menu",
"Modify": "Ändern", "Modify": "Ändern",
"Month": "Monat", "Month": "Monat",
@@ -139,6 +149,9 @@
"Nearby companies": "Nahe gelegene Unternehmen", "Nearby companies": "Nahe gelegene Unternehmen",
"New password": "Neues Kennwort", "New password": "Neues Kennwort",
"Next": "Nächste", "Next": "Nächste",
"next level:": "Nächstes Level:",
"night": "nacht",
"nights": "Nächte",
"Nights needed to level up": "Nächte, die zum Levelaufstieg benötigt werden", "Nights needed to level up": "Nächte, die zum Levelaufstieg benötigt werden",
"No content published": "Kein Inhalt veröffentlicht", "No content published": "Kein Inhalt veröffentlicht",
"No matching location found": "Kein passender Standort gefunden", "No matching location found": "Kein passender Standort gefunden",
@@ -149,11 +162,13 @@
"Non-refundable": "Nicht erstattungsfähig", "Non-refundable": "Nicht erstattungsfähig",
"Not found": "Nicht gefunden", "Not found": "Nicht gefunden",
"Nr night, nr adult": "{nights, number} Nacht, {adults, number} Erwachsener", "Nr night, nr adult": "{nights, number} Nacht, {adults, number} Erwachsener",
"number": "nummer",
"On your journey": "Auf deiner Reise", "On your journey": "Auf deiner Reise",
"Open": "Offen", "Open": "Offen",
"Open language menu": "Sprachmenü öffnen", "Open language menu": "Sprachmenü öffnen",
"Open menu": "Menü öffnen", "Open menu": "Menü öffnen",
"Open my pages menu": "Meine Seiten Menü öffnen", "Open my pages menu": "Meine Seiten Menü öffnen",
"or": "oder",
"Overview": "Übersicht", "Overview": "Übersicht",
"Parking": "Parken", "Parking": "Parken",
"Parking / Garage": "Parken / Garage", "Parking / Garage": "Parken / Garage",
@@ -164,6 +179,7 @@
"Phone is required": "Telefon ist erforderlich", "Phone is required": "Telefon ist erforderlich",
"Phone number": "Telefonnummer", "Phone number": "Telefonnummer",
"Please enter a valid phone number": "Bitte geben Sie eine gültige Telefonnummer ein", "Please enter a valid phone number": "Bitte geben Sie eine gültige Telefonnummer ein",
"points": "Punkte",
"Points": "Punkte", "Points": "Punkte",
"Points being calculated": "Punkte werden berechnet", "Points being calculated": "Punkte werden berechnet",
"Points earned prior to May 1, 2021": "Zusammengeführte Punkte vor dem 1. Mai 2021", "Points earned prior to May 1, 2021": "Zusammengeführte Punkte vor dem 1. Mai 2021",
@@ -182,7 +198,6 @@
"Room & Terms": "Zimmer & Bedingungen", "Room & Terms": "Zimmer & Bedingungen",
"Room facilities": "Zimmerausstattung", "Room facilities": "Zimmerausstattung",
"Rooms": "Räume", "Rooms": "Räume",
"Guests & Rooms": "Gäste & Zimmer",
"Save": "Speichern", "Save": "Speichern",
"Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Mastercard": "Scandic Friends Mastercard",
"Scandic Friends Point Shop": "Scandic Friends Point Shop", "Scandic Friends Point Shop": "Scandic Friends Point Shop",
@@ -207,25 +222,29 @@
"Something went wrong and we couldn't add your card. Please try again later.": "Ein Fehler ist aufgetreten und wir konnten Ihre Karte nicht hinzufügen. Bitte versuchen Sie es später erneut.", "Something went wrong and we couldn't add your card. Please try again later.": "Ein Fehler ist aufgetreten und wir konnten Ihre Karte nicht hinzufügen. Bitte versuchen Sie es später erneut.",
"Something went wrong and we couldn't remove your card. Please try again later.": "Ein Fehler ist aufgetreten und wir konnten Ihre Karte nicht entfernen. Bitte versuchen Sie es später noch einmal.", "Something went wrong and we couldn't remove your card. Please try again later.": "Ein Fehler ist aufgetreten und wir konnten Ihre Karte nicht entfernen. Bitte versuchen Sie es später noch einmal.",
"Something went wrong!": "Etwas ist schief gelaufen!", "Something went wrong!": "Etwas ist schief gelaufen!",
"special character": "sonderzeichen",
"spendable points expiring by": "{points} Einlösbare punkte verfallen bis zum {date}",
"Sports": "Sport", "Sports": "Sport",
"Standard price": "Standardpreis", "Standard price": "Standardpreis",
"Street": "Straße", "Street": "Straße",
"Successfully updated profile!": "Profil erfolgreich aktualisiert!", "Successfully updated profile!": "Profil erfolgreich aktualisiert!",
"Summary": "Zusammenfassung", "Summary": "Zusammenfassung",
"TUI Points": "TUI Points",
"Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Teilen Sie uns mit, welche Informationen und Updates Sie wie erhalten möchten, indem Sie auf den unten stehenden Link klicken.", "Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Teilen Sie uns mit, welche Informationen und Updates Sie wie erhalten möchten, indem Sie auf den unten stehenden Link klicken.",
"Thank you": "Danke", "Thank you": "Danke",
"Theatre": "Theater", "Theatre": "Theater",
"There are no transactions to display": "Es sind keine Transaktionen zum Anzeigen vorhanden", "There are no transactions to display": "Es sind keine Transaktionen zum Anzeigen vorhanden",
"Things nearby HOTEL_NAME": "Dinge in der Nähe von {hotelName}", "Things nearby HOTEL_NAME": "Dinge in der Nähe von {hotelName}",
"to": "zu",
"Total Points": "Gesamtpunktzahl", "Total Points": "Gesamtpunktzahl",
"Tourist": "Tourist", "Tourist": "Tourist",
"Transaction date": "Transaktionsdatum", "Transaction date": "Transaktionsdatum",
"Transactions": "Transaktionen", "Transactions": "Transaktionen",
"Transportations": "Transportmittel", "Transportations": "Transportmittel",
"Tripadvisor reviews": "{rating} ({count} Bewertungen auf Tripadvisor)", "Tripadvisor reviews": "{rating} ({count} Bewertungen auf Tripadvisor)",
"TUI Points": "TUI Points",
"Type of bed": "Bettentyp", "Type of bed": "Bettentyp",
"Type of room": "Zimmerart", "Type of room": "Zimmerart",
"uppercase letter": "großbuchstabe",
"Use bonus cheque": "Bonusscheck nutzen", "Use bonus cheque": "Bonusscheck nutzen",
"User information": "Nutzerinformation", "User information": "Nutzerinformation",
"View as list": "Als Liste anzeigen", "View as list": "Als Liste anzeigen",
@@ -251,9 +270,9 @@
"You canceled adding a new credit card.": "Sie haben das Hinzufügen einer neuen Kreditkarte abgebrochen.", "You canceled adding a new credit card.": "Sie haben das Hinzufügen einer neuen Kreditkarte abgebrochen.",
"You have no previous stays.": "Sie haben keine vorherigen Aufenthalte.", "You have no previous stays.": "Sie haben keine vorherigen Aufenthalte.",
"You have no upcoming stays.": "Sie haben keine bevorstehenden Aufenthalte.", "You have no upcoming stays.": "Sie haben keine bevorstehenden Aufenthalte.",
"Your Challenges Conquer & Earn!": "Meistern Sie Ihre Herausforderungen und verdienen Sie Geld!",
"Your card was successfully removed!": "Ihre Karte wurde erfolgreich entfernt!", "Your card was successfully removed!": "Ihre Karte wurde erfolgreich entfernt!",
"Your card was successfully saved!": "Ihre Karte wurde erfolgreich gespeichert!", "Your card was successfully saved!": "Ihre Karte wurde erfolgreich gespeichert!",
"Your Challenges Conquer & Earn!": "Meistern Sie Ihre Herausforderungen und verdienen Sie Geld!",
"Your current level": "Ihr aktuelles Level", "Your current level": "Ihr aktuelles Level",
"Your details": "Ihre Angaben", "Your details": "Ihre Angaben",
"Your level": "Dein level", "Your level": "Dein level",
@@ -261,23 +280,5 @@
"Zip code": "PLZ", "Zip code": "PLZ",
"Zoo": "Zoo", "Zoo": "Zoo",
"Zoom in": "Vergrößern", "Zoom in": "Vergrößern",
"Zoom out": "Verkleinern", "Zoom out": "Verkleinern"
"as of today": "Stand heute", }
"booking.nights": "{totalNights, plural, one {# nacht} other {# Nächte}}",
"by": "bis",
"characters": "figuren",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "personen",
"hotelPages.rooms.roomCard.seeRoomDetails": "Zimmerdetails ansehen",
"km to city center": "km bis zum Stadtzentrum",
"next level:": "Nächstes Level:",
"night": "nacht",
"nights": "Nächte",
"number": "nummer",
"or": "oder",
"points": "Punkte",
"special character": "sonderzeichen",
"spendable points expiring by": "{points} Einlösbare punkte verfallen bis zum {date}",
"to": "zu",
"uppercase letter": "großbuchstabe"
}

View File

@@ -14,6 +14,7 @@
"Any changes you've made will be lost.": "Any changes you've made will be lost.", "Any changes you've made will be lost.": "Any changes you've made will be lost.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?",
"Arrival date": "Arrival date", "Arrival date": "Arrival date",
"as of today": "as of today",
"As our": "As our {level}", "As our": "As our {level}",
"As our Close Friend": "As our Close Friend", "As our Close Friend": "As our Close Friend",
"At latest": "At latest", "At latest": "At latest",
@@ -23,14 +24,18 @@
"Bed type": "Bed type", "Bed type": "Bed type",
"Book": "Book", "Book": "Book",
"Book reward night": "Book reward night", "Book reward night": "Book reward night",
"Code / Voucher": "Code / Voucher",
"Booking number": "Booking number", "Booking number": "Booking number",
"booking.adults": "{totalAdults, plural, one {# adult} other {# adults}}",
"booking.nights": "{totalNights, plural, one {# night} other {# nights}}",
"booking.rooms": "{totalRooms, plural, one {# room} other {# rooms}}",
"Breakfast": "Breakfast", "Breakfast": "Breakfast",
"Breakfast excluded": "Breakfast excluded", "Breakfast excluded": "Breakfast excluded",
"Breakfast included": "Breakfast included", "Breakfast included": "Breakfast included",
"Bus terminal": "Bus terminal", "Bus terminal": "Bus terminal",
"Business": "Business", "Business": "Business",
"by": "by",
"Cancel": "Cancel", "Cancel": "Cancel",
"characters": "characters",
"Check in": "Check in", "Check in": "Check in",
"Check out": "Check out", "Check out": "Check out",
"Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.",
@@ -45,8 +50,10 @@
"Close menu": "Close menu", "Close menu": "Close menu",
"Close my pages menu": "Close my pages menu", "Close my pages menu": "Close my pages menu",
"Close the map": "Close the map", "Close the map": "Close the map",
"Code / Voucher": "Code / Voucher",
"Coming up": "Coming up", "Coming up": "Coming up",
"Compare all levels": "Compare all levels", "Compare all levels": "Compare all levels",
"Complete booking & go to payment": "Complete booking & go to payment",
"Contact us": "Contact us", "Contact us": "Contact us",
"Continue": "Continue", "Continue": "Continue",
"Copyright all rights reserved": "Scandic AB All rights reserved", "Copyright all rights reserved": "Scandic AB All rights reserved",
@@ -59,8 +66,8 @@
"Date of Birth": "Date of Birth", "Date of Birth": "Date of Birth",
"Day": "Day", "Day": "Day",
"Description": "Description", "Description": "Description",
"Destinations & hotels": "Destinations & hotels",
"Destination": "Destination", "Destination": "Destination",
"Destinations & hotels": "Destinations & hotels",
"Discard changes": "Discard changes", "Discard changes": "Discard changes",
"Discard unsaved changes?": "Discard unsaved changes?", "Discard unsaved changes?": "Discard unsaved changes?",
"Distance to city centre": "{number}km to city centre", "Distance to city centre": "{number}km to city centre",
@@ -73,9 +80,9 @@
"Explore all levels and benefits": "Explore all levels and benefits", "Explore all levels and benefits": "Explore all levels and benefits",
"Explore nearby": "Explore nearby", "Explore nearby": "Explore nearby",
"Extras to your booking": "Extras to your booking", "Extras to your booking": "Extras to your booking",
"FAQ": "FAQ",
"Failed to delete credit card, please try again later.": "Failed to delete credit card, please try again later.", "Failed to delete credit card, please try again later.": "Failed to delete credit card, please try again later.",
"Fair": "Fair", "Fair": "Fair",
"FAQ": "FAQ",
"Find booking": "Find booking", "Find booking": "Find booking",
"Find hotels": "Find hotels", "Find hotels": "Find hotels",
"Flexibility": "Flexibility", "Flexibility": "Flexibility",
@@ -86,17 +93,22 @@
"Get inspired": "Get inspired", "Get inspired": "Get inspired",
"Go back to edit": "Go back to edit", "Go back to edit": "Go back to edit",
"Go back to overview": "Go back to overview", "Go back to overview": "Go back to overview",
"Guests & Rooms": "Guests & Rooms",
"Hi": "Hi", "Hi": "Hi",
"Highest level": "Highest level", "Highest level": "Highest level",
"Hospital": "Hospital", "Hospital": "Hospital",
"Hotel": "Hotel", "Hotel": "Hotel",
"Hotel facilities": "Hotel facilities", "Hotel facilities": "Hotel facilities",
"Hotel surroundings": "Hotel surroundings", "Hotel surroundings": "Hotel surroundings",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "persons",
"hotelPages.rooms.roomCard.seeRoomDetails": "See room details",
"Hotels": "Hotels", "Hotels": "Hotels",
"How do you want to sleep?": "How do you want to sleep?", "How do you want to sleep?": "How do you want to sleep?",
"How it works": "How it works", "How it works": "How it works",
"Image gallery": "Image gallery", "Image gallery": "Image gallery",
"Join Scandic Friends": "Join Scandic Friends", "Join Scandic Friends": "Join Scandic Friends",
"km to city center": "km to city center",
"Language": "Language", "Language": "Language",
"Latest searches": "Latest searches", "Latest searches": "Latest searches",
"Level": "Level", "Level": "Level",
@@ -123,9 +135,9 @@
"Member price": "Member price", "Member price": "Member price",
"Member price from": "Member price from", "Member price from": "Member price from",
"Members": "Members", "Members": "Members",
"Membership cards": "Membership cards",
"Membership ID": "Membership ID", "Membership ID": "Membership ID",
"Membership ID copied to clipboard": "Membership ID copied to clipboard", "Membership ID copied to clipboard": "Membership ID copied to clipboard",
"Membership cards": "Membership cards",
"Menu": "Menu", "Menu": "Menu",
"Modify": "Modify", "Modify": "Modify",
"Month": "Month", "Month": "Month",
@@ -140,6 +152,9 @@
"Nearby companies": "Nearby companies", "Nearby companies": "Nearby companies",
"New password": "New password", "New password": "New password",
"Next": "Next", "Next": "Next",
"next level:": "next level:",
"night": "night",
"nights": "nights",
"Nights needed to level up": "Nights needed to level up", "Nights needed to level up": "Nights needed to level up",
"No content published": "No content published", "No content published": "No content published",
"No matching location found": "No matching location found", "No matching location found": "No matching location found",
@@ -150,11 +165,13 @@
"Non-refundable": "Non-refundable", "Non-refundable": "Non-refundable",
"Not found": "Not found", "Not found": "Not found",
"Nr night, nr adult": "{nights, number} night, {adults, number} adult", "Nr night, nr adult": "{nights, number} night, {adults, number} adult",
"number": "number",
"On your journey": "On your journey", "On your journey": "On your journey",
"Open": "Open", "Open": "Open",
"Open language menu": "Open language menu", "Open language menu": "Open language menu",
"Open menu": "Open menu", "Open menu": "Open menu",
"Open my pages menu": "Open my pages menu", "Open my pages menu": "Open my pages menu",
"or": "or",
"Overview": "Overview", "Overview": "Overview",
"Parking": "Parking", "Parking": "Parking",
"Parking / Garage": "Parking / Garage", "Parking / Garage": "Parking / Garage",
@@ -166,6 +183,7 @@
"Phone is required": "Phone is required", "Phone is required": "Phone is required",
"Phone number": "Phone number", "Phone number": "Phone number",
"Please enter a valid phone number": "Please enter a valid phone number", "Please enter a valid phone number": "Please enter a valid phone number",
"points": "Points",
"Points": "Points", "Points": "Points",
"Points being calculated": "Points being calculated", "Points being calculated": "Points being calculated",
"Points earned prior to May 1, 2021": "Points earned prior to May 1, 2021", "Points earned prior to May 1, 2021": "Points earned prior to May 1, 2021",
@@ -184,12 +202,11 @@
"Room & Terms": "Room & Terms", "Room & Terms": "Room & Terms",
"Room facilities": "Room facilities", "Room facilities": "Room facilities",
"Rooms": "Rooms", "Rooms": "Rooms",
"Guests & Rooms": "Guests & Rooms",
"Save": "Save", "Save": "Save",
"Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Mastercard": "Scandic Friends Mastercard",
"Scandic Friends Point Shop": "Scandic Friends Point Shop", "Scandic Friends Point Shop": "Scandic Friends Point Shop",
"See all photos": "See all photos",
"Search": "Search", "Search": "Search",
"See all photos": "See all photos",
"See hotel details": "See hotel details", "See hotel details": "See hotel details",
"See room details": "See room details", "See room details": "See room details",
"See rooms": "See rooms", "See rooms": "See rooms",
@@ -210,25 +227,29 @@
"Something went wrong and we couldn't add your card. Please try again later.": "Something went wrong and we couldn't add your card. Please try again later.", "Something went wrong and we couldn't add your card. Please try again later.": "Something went wrong and we couldn't add your card. Please try again later.",
"Something went wrong and we couldn't remove your card. Please try again later.": "Something went wrong and we couldn't remove your card. Please try again later.", "Something went wrong and we couldn't remove your card. Please try again later.": "Something went wrong and we couldn't remove your card. Please try again later.",
"Something went wrong!": "Something went wrong!", "Something went wrong!": "Something went wrong!",
"special character": "special character",
"spendable points expiring by": "{points} spendable points expiring by {date}",
"Sports": "Sports", "Sports": "Sports",
"Standard price": "Standard price", "Standard price": "Standard price",
"Street": "Street", "Street": "Street",
"Successfully updated profile!": "Successfully updated profile!", "Successfully updated profile!": "Successfully updated profile!",
"Summary": "Summary", "Summary": "Summary",
"TUI Points": "TUI Points",
"Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Tell us what information and updates you'd like to receive, and how, by clicking the link below.", "Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Tell us what information and updates you'd like to receive, and how, by clicking the link below.",
"Thank you": "Thank you", "Thank you": "Thank you",
"Theatre": "Theatre", "Theatre": "Theatre",
"There are no transactions to display": "There are no transactions to display", "There are no transactions to display": "There are no transactions to display",
"Things nearby HOTEL_NAME": "Things nearby {hotelName}", "Things nearby HOTEL_NAME": "Things nearby {hotelName}",
"to": "to",
"Total Points": "Total Points", "Total Points": "Total Points",
"Tourist": "Tourist", "Tourist": "Tourist",
"Transaction date": "Transaction date", "Transaction date": "Transaction date",
"Transactions": "Transactions", "Transactions": "Transactions",
"Transportations": "Transportations", "Transportations": "Transportations",
"Tripadvisor reviews": "{rating} ({count} reviews on Tripadvisor)", "Tripadvisor reviews": "{rating} ({count} reviews on Tripadvisor)",
"TUI Points": "TUI Points",
"Type of bed": "Type of bed", "Type of bed": "Type of bed",
"Type of room": "Type of room", "Type of room": "Type of room",
"uppercase letter": "uppercase letter",
"Use bonus cheque": "Use bonus cheque", "Use bonus cheque": "Use bonus cheque",
"User information": "User information", "User information": "User information",
"View as list": "View as list", "View as list": "View as list",
@@ -254,9 +275,9 @@
"You canceled adding a new credit card.": "You canceled adding a new credit card.", "You canceled adding a new credit card.": "You canceled adding a new credit card.",
"You have no previous stays.": "You have no previous stays.", "You have no previous stays.": "You have no previous stays.",
"You have no upcoming stays.": "You have no upcoming stays.", "You have no upcoming stays.": "You have no upcoming stays.",
"Your Challenges Conquer & Earn!": "Your Challenges Conquer & Earn!",
"Your card was successfully removed!": "Your card was successfully removed!", "Your card was successfully removed!": "Your card was successfully removed!",
"Your card was successfully saved!": "Your card was successfully saved!", "Your card was successfully saved!": "Your card was successfully saved!",
"Your Challenges Conquer & Earn!": "Your Challenges Conquer & Earn!",
"Your current level": "Your current level", "Your current level": "Your current level",
"Your details": "Your details", "Your details": "Your details",
"Your level": "Your level", "Your level": "Your level",
@@ -264,25 +285,5 @@
"Zip code": "Zip code", "Zip code": "Zip code",
"Zoo": "Zoo", "Zoo": "Zoo",
"Zoom in": "Zoom in", "Zoom in": "Zoom in",
"Zoom out": "Zoom out", "Zoom out": "Zoom out"
"as of today": "as of today", }
"booking.adults": "{totalAdults, plural, one {# adult} other {# adults}}",
"booking.nights": "{totalNights, plural, one {# night} other {# nights}}",
"booking.rooms": "{totalRooms, plural, one {# room} other {# rooms}}",
"by": "by",
"characters": "characters",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "persons",
"hotelPages.rooms.roomCard.seeRoomDetails": "See room details",
"km to city center": "km to city center",
"next level:": "next level:",
"night": "night",
"nights": "nights",
"number": "number",
"or": "or",
"points": "Points",
"special character": "special character",
"spendable points expiring by": "{points} spendable points expiring by {date}",
"to": "to",
"uppercase letter": "uppercase letter"
}

View File

@@ -14,6 +14,7 @@
"Any changes you've made will be lost.": "Kaikki tekemäsi muutokset menetetään.", "Any changes you've made will be lost.": "Kaikki tekemäsi muutokset menetetään.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Haluatko varmasti poistaa kortin, joka päättyy numeroon {lastFourDigits} jäsenprofiilistasi?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Haluatko varmasti poistaa kortin, joka päättyy numeroon {lastFourDigits} jäsenprofiilistasi?",
"Arrival date": "Saapumispäivä", "Arrival date": "Saapumispäivä",
"as of today": "tänään",
"As our": "{level}-etu", "As our": "{level}-etu",
"As our Close Friend": "Läheisenä ystävänämme", "As our Close Friend": "Läheisenä ystävänämme",
"At latest": "Viimeistään", "At latest": "Viimeistään",
@@ -24,12 +25,15 @@
"Book": "Varaa", "Book": "Varaa",
"Book reward night": "Kirjapalkinto-ilta", "Book reward night": "Kirjapalkinto-ilta",
"Booking number": "Varausnumero", "Booking number": "Varausnumero",
"booking.nights": "{totalNights, plural, one {# yö} other {# yötä}}",
"Breakfast": "Aamiainen", "Breakfast": "Aamiainen",
"Breakfast excluded": "Aamiainen ei sisälly", "Breakfast excluded": "Aamiainen ei sisälly",
"Breakfast included": "Aamiainen sisältyy", "Breakfast included": "Aamiainen sisältyy",
"Bus terminal": "Bussiasema", "Bus terminal": "Bussiasema",
"Business": "Business", "Business": "Business",
"by": "mennessä",
"Cancel": "Peruuttaa", "Cancel": "Peruuttaa",
"characters": "hahmoja",
"Check in": "Sisäänkirjautuminen", "Check in": "Sisäänkirjautuminen",
"Check out": "Uloskirjautuminen", "Check out": "Uloskirjautuminen",
"Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Tarkista profiiliisi tallennetut luottokortit. Maksa tallennetulla kortilla kirjautuneena, jotta verkkokokemus on sujuvampi.", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Tarkista profiiliisi tallennetut luottokortit. Maksa tallennetulla kortilla kirjautuneena, jotta verkkokokemus on sujuvampi.",
@@ -47,6 +51,7 @@
"Code / Voucher": "Varauskoodit / kupongit", "Code / Voucher": "Varauskoodit / kupongit",
"Coming up": "Tulossa", "Coming up": "Tulossa",
"Compare all levels": "Vertaa kaikkia tasoja", "Compare all levels": "Vertaa kaikkia tasoja",
"Complete booking & go to payment": "Täydennä varaus & siirry maksamaan",
"Contact us": "Ota meihin yhteyttä", "Contact us": "Ota meihin yhteyttä",
"Continue": "Jatkaa", "Continue": "Jatkaa",
"Copyright all rights reserved": "Scandic AB Kaikki oikeudet pidätetään", "Copyright all rights reserved": "Scandic AB Kaikki oikeudet pidätetään",
@@ -72,9 +77,9 @@
"Explore all levels and benefits": "Tutustu kaikkiin tasoihin ja etuihin", "Explore all levels and benefits": "Tutustu kaikkiin tasoihin ja etuihin",
"Explore nearby": "Tutustu lähialueeseen", "Explore nearby": "Tutustu lähialueeseen",
"Extras to your booking": "Varauksessa lisäpalveluita", "Extras to your booking": "Varauksessa lisäpalveluita",
"FAQ": "UKK",
"Failed to delete credit card, please try again later.": "Luottokortin poistaminen epäonnistui, yritä myöhemmin uudelleen.", "Failed to delete credit card, please try again later.": "Luottokortin poistaminen epäonnistui, yritä myöhemmin uudelleen.",
"Fair": "Messukeskus", "Fair": "Messukeskus",
"FAQ": "UKK",
"Find booking": "Etsi varaus", "Find booking": "Etsi varaus",
"Find hotels": "Etsi hotelleja", "Find hotels": "Etsi hotelleja",
"Flexibility": "Joustavuus", "Flexibility": "Joustavuus",
@@ -92,11 +97,15 @@
"Hotel": "Hotelli", "Hotel": "Hotelli",
"Hotel facilities": "Hotellin palvelut", "Hotel facilities": "Hotellin palvelut",
"Hotel surroundings": "Hotellin ympäristö", "Hotel surroundings": "Hotellin ympäristö",
"hotelPages.rooms.roomCard.person": "henkilö",
"hotelPages.rooms.roomCard.persons": "Henkilöä",
"hotelPages.rooms.roomCard.seeRoomDetails": "Katso huoneen tiedot",
"Hotels": "Hotellit", "Hotels": "Hotellit",
"How do you want to sleep?": "Kuinka haluat nukkua?", "How do you want to sleep?": "Kuinka haluat nukkua?",
"How it works": "Kuinka se toimii", "How it works": "Kuinka se toimii",
"Image gallery": "Kuvagalleria", "Image gallery": "Kuvagalleria",
"Join Scandic Friends": "Liity jäseneksi", "Join Scandic Friends": "Liity jäseneksi",
"km to city center": "km keskustaan",
"Language": "Kieli", "Language": "Kieli",
"Latest searches": "Viimeisimmät haut", "Latest searches": "Viimeisimmät haut",
"Level": "Level", "Level": "Level",
@@ -123,9 +132,9 @@
"Member price": "Jäsenhinta", "Member price": "Jäsenhinta",
"Member price from": "Jäsenhinta alkaen", "Member price from": "Jäsenhinta alkaen",
"Members": "Jäsenet", "Members": "Jäsenet",
"Membership cards": "Jäsenkortit",
"Membership ID": "Jäsentunnus", "Membership ID": "Jäsentunnus",
"Membership ID copied to clipboard": "Jäsenyystunnus kopioitu leikepöydälle", "Membership ID copied to clipboard": "Jäsenyystunnus kopioitu leikepöydälle",
"Membership cards": "Jäsenkortit",
"Menu": "Valikko", "Menu": "Valikko",
"Modify": "Muokkaa", "Modify": "Muokkaa",
"Month": "Kuukausi", "Month": "Kuukausi",
@@ -140,6 +149,9 @@
"Nearby companies": "Läheiset yritykset", "Nearby companies": "Läheiset yritykset",
"New password": "Uusi salasana", "New password": "Uusi salasana",
"Next": "Seuraava", "Next": "Seuraava",
"next level:": "pistettä tasolle:",
"night": "yö",
"nights": "yötä",
"Nights needed to level up": "Yöt, joita tarvitaan tasolle", "Nights needed to level up": "Yöt, joita tarvitaan tasolle",
"No content published": "Ei julkaistua sisältöä", "No content published": "Ei julkaistua sisältöä",
"No matching location found": "Vastaavaa sijaintia ei löytynyt", "No matching location found": "Vastaavaa sijaintia ei löytynyt",
@@ -150,11 +162,13 @@
"Non-refundable": "Ei palautettavissa", "Non-refundable": "Ei palautettavissa",
"Not found": "Ei löydetty", "Not found": "Ei löydetty",
"Nr night, nr adult": "{nights, number} yö, {adults, number} aikuinen", "Nr night, nr adult": "{nights, number} yö, {adults, number} aikuinen",
"number": "määrä",
"On your journey": "Matkallasi", "On your journey": "Matkallasi",
"Open": "Avata", "Open": "Avata",
"Open language menu": "Avaa kielivalikko", "Open language menu": "Avaa kielivalikko",
"Open menu": "Avaa valikko", "Open menu": "Avaa valikko",
"Open my pages menu": "Avaa omat sivut -valikko", "Open my pages menu": "Avaa omat sivut -valikko",
"or": "tai",
"Overview": "Yleiskatsaus", "Overview": "Yleiskatsaus",
"Parking": "Pysäköinti", "Parking": "Pysäköinti",
"Parking / Garage": "Pysäköinti / Autotalli", "Parking / Garage": "Pysäköinti / Autotalli",
@@ -166,6 +180,7 @@
"Phone is required": "Puhelin vaaditaan", "Phone is required": "Puhelin vaaditaan",
"Phone number": "Puhelinnumero", "Phone number": "Puhelinnumero",
"Please enter a valid phone number": "Ole hyvä ja näppäile voimassaoleva puhelinnumero", "Please enter a valid phone number": "Ole hyvä ja näppäile voimassaoleva puhelinnumero",
"points": "pistettä",
"Points": "Pisteet", "Points": "Pisteet",
"Points being calculated": "Pisteitä lasketaan", "Points being calculated": "Pisteitä lasketaan",
"Points earned prior to May 1, 2021": "Pisteet, jotka ansaittu ennen 1.5.2021", "Points earned prior to May 1, 2021": "Pisteet, jotka ansaittu ennen 1.5.2021",
@@ -208,25 +223,29 @@
"Something went wrong and we couldn't add your card. Please try again later.": "Jotain meni pieleen, emmekä voineet lisätä korttiasi. Yritä myöhemmin uudelleen.", "Something went wrong and we couldn't add your card. Please try again later.": "Jotain meni pieleen, emmekä voineet lisätä korttiasi. Yritä myöhemmin uudelleen.",
"Something went wrong and we couldn't remove your card. Please try again later.": "Jotain meni pieleen, emmekä voineet poistaa korttiasi. Yritä myöhemmin uudelleen.", "Something went wrong and we couldn't remove your card. Please try again later.": "Jotain meni pieleen, emmekä voineet poistaa korttiasi. Yritä myöhemmin uudelleen.",
"Something went wrong!": "Jotain meni pieleen!", "Something went wrong!": "Jotain meni pieleen!",
"special character": "erikoishahmo",
"spendable points expiring by": "{points} pistettä vanhenee {date} mennessä",
"Sports": "Urheilu", "Sports": "Urheilu",
"Standard price": "Normaali hinta", "Standard price": "Normaali hinta",
"Street": "Katu", "Street": "Katu",
"Successfully updated profile!": "Profiilin päivitys onnistui!", "Successfully updated profile!": "Profiilin päivitys onnistui!",
"Summary": "Yhteenveto", "Summary": "Yhteenveto",
"TUI Points": "TUI Points",
"Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Kerro meille, mitä tietoja ja päivityksiä haluat saada ja miten, napsauttamalla alla olevaa linkkiä.", "Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Kerro meille, mitä tietoja ja päivityksiä haluat saada ja miten, napsauttamalla alla olevaa linkkiä.",
"Thank you": "Kiitos", "Thank you": "Kiitos",
"Theatre": "Teatteri", "Theatre": "Teatteri",
"There are no transactions to display": "Näytettäviä tapahtumia ei ole", "There are no transactions to display": "Näytettäviä tapahtumia ei ole",
"Things nearby HOTEL_NAME": "Lähellä olevia asioita {hotelName}", "Things nearby HOTEL_NAME": "Lähellä olevia asioita {hotelName}",
"to": "to",
"Total Points": "Kokonaispisteet", "Total Points": "Kokonaispisteet",
"Tourist": "Turisti", "Tourist": "Turisti",
"Transaction date": "Tapahtuman päivämäärä", "Transaction date": "Tapahtuman päivämäärä",
"Transactions": "Tapahtumat", "Transactions": "Tapahtumat",
"Transportations": "Kuljetukset", "Transportations": "Kuljetukset",
"Tripadvisor reviews": "{rating} ({count} arvostelua TripAdvisorissa)", "Tripadvisor reviews": "{rating} ({count} arvostelua TripAdvisorissa)",
"TUI Points": "TUI Points",
"Type of bed": "Vuodetyyppi", "Type of bed": "Vuodetyyppi",
"Type of room": "Huonetyyppi", "Type of room": "Huonetyyppi",
"uppercase letter": "iso kirjain",
"Use bonus cheque": "Käytä bonussekkiä", "Use bonus cheque": "Käytä bonussekkiä",
"User information": "Käyttäjän tiedot", "User information": "Käyttäjän tiedot",
"View as list": "Näytä listana", "View as list": "Näytä listana",
@@ -252,9 +271,9 @@
"You canceled adding a new credit card.": "Peruutit uuden luottokortin lisäämisen.", "You canceled adding a new credit card.": "Peruutit uuden luottokortin lisäämisen.",
"You have no previous stays.": "Sinulla ei ole aiempia majoituksia.", "You have no previous stays.": "Sinulla ei ole aiempia majoituksia.",
"You have no upcoming stays.": "Sinulla ei ole tulevia majoituksia.", "You have no upcoming stays.": "Sinulla ei ole tulevia majoituksia.",
"Your Challenges Conquer & Earn!": "Voita ja ansaitse haasteesi!",
"Your card was successfully removed!": "Korttisi poistettiin onnistuneesti!", "Your card was successfully removed!": "Korttisi poistettiin onnistuneesti!",
"Your card was successfully saved!": "Korttisi tallennettu onnistuneesti!", "Your card was successfully saved!": "Korttisi tallennettu onnistuneesti!",
"Your Challenges Conquer & Earn!": "Voita ja ansaitse haasteesi!",
"Your current level": "Nykyinen tasosi", "Your current level": "Nykyinen tasosi",
"Your details": "Tietosi", "Your details": "Tietosi",
"Your level": "Tasosi", "Your level": "Tasosi",
@@ -262,23 +281,5 @@
"Zip code": "Postinumero", "Zip code": "Postinumero",
"Zoo": "Eläintarha", "Zoo": "Eläintarha",
"Zoom in": "Lähennä", "Zoom in": "Lähennä",
"Zoom out": "Loitonna", "Zoom out": "Loitonna"
"as of today": "tänään", }
"booking.nights": "{totalNights, plural, one {# yö} other {# yötä}}",
"by": "mennessä",
"characters": "hahmoja",
"hotelPages.rooms.roomCard.person": "henkilö",
"hotelPages.rooms.roomCard.persons": "Henkilöä",
"hotelPages.rooms.roomCard.seeRoomDetails": "Katso huoneen tiedot",
"km to city center": "km keskustaan",
"next level:": "pistettä tasolle:",
"night": "yö",
"nights": "yötä",
"number": "määrä",
"or": "tai",
"points": "pistettä",
"special character": "erikoishahmo",
"spendable points expiring by": "{points} pistettä vanhenee {date} mennessä",
"to": "to",
"uppercase letter": "iso kirjain"
}

View File

@@ -14,6 +14,7 @@
"Any changes you've made will be lost.": "Eventuelle endringer du har gjort, går tapt.", "Any changes you've made will be lost.": "Eventuelle endringer du har gjort, går tapt.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Er du sikker på at du vil fjerne kortet som slutter på {lastFourDigits} fra medlemsprofilen din?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Er du sikker på at du vil fjerne kortet som slutter på {lastFourDigits} fra medlemsprofilen din?",
"Arrival date": "Ankomstdato", "Arrival date": "Ankomstdato",
"as of today": "per idag",
"As our": "Som vår {level}", "As our": "Som vår {level}",
"As our Close Friend": "Som vår nære venn", "As our Close Friend": "Som vår nære venn",
"At latest": "Senest", "At latest": "Senest",
@@ -23,14 +24,16 @@
"Bed type": "Seng type", "Bed type": "Seng type",
"Book": "Bestill", "Book": "Bestill",
"Book reward night": "Bestill belønningskveld", "Book reward night": "Bestill belønningskveld",
"Code / Voucher": "Bestillingskoder / kuponger",
"Booking number": "Bestillingsnummer", "Booking number": "Bestillingsnummer",
"booking.nights": "{totalNights, plural, one {# natt} other {# netter}}",
"Breakfast": "Frokost", "Breakfast": "Frokost",
"Breakfast excluded": "Frokost ekskludert", "Breakfast excluded": "Frokost ekskludert",
"Breakfast included": "Frokost inkludert", "Breakfast included": "Frokost inkludert",
"Bus terminal": "Bussterminal", "Bus terminal": "Bussterminal",
"Business": "Forretnings", "Business": "Forretnings",
"by": "innen",
"Cancel": "Avbryt", "Cancel": "Avbryt",
"characters": "tegn",
"Check in": "Sjekk inn", "Check in": "Sjekk inn",
"Check out": "Sjekk ut", "Check out": "Sjekk ut",
"Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Sjekk ut kredittkortene som er lagret på profilen din. Betal med et lagret kort når du er pålogget for en jevnere nettopplevelse.", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Sjekk ut kredittkortene som er lagret på profilen din. Betal med et lagret kort når du er pålogget for en jevnere nettopplevelse.",
@@ -45,8 +48,10 @@
"Close menu": "Lukk meny", "Close menu": "Lukk meny",
"Close my pages menu": "Lukk mine sidermenyn", "Close my pages menu": "Lukk mine sidermenyn",
"Close the map": "Lukk kartet", "Close the map": "Lukk kartet",
"Code / Voucher": "Bestillingskoder / kuponger",
"Coming up": "Kommer opp", "Coming up": "Kommer opp",
"Compare all levels": "Sammenlign alle nivåer", "Compare all levels": "Sammenlign alle nivåer",
"Complete booking & go to payment": "Fullfør bestilling & gå til betaling",
"Contact us": "Kontakt oss", "Contact us": "Kontakt oss",
"Continue": "Fortsette", "Continue": "Fortsette",
"Copyright all rights reserved": "Scandic AB Alle rettigheter forbeholdt", "Copyright all rights reserved": "Scandic AB Alle rettigheter forbeholdt",
@@ -72,9 +77,9 @@
"Explore all levels and benefits": "Utforsk alle nivåer og fordeler", "Explore all levels and benefits": "Utforsk alle nivåer og fordeler",
"Explore nearby": "Utforsk i nærheten", "Explore nearby": "Utforsk i nærheten",
"Extras to your booking": "Tilvalg til bestillingen din", "Extras to your booking": "Tilvalg til bestillingen din",
"FAQ": "FAQ",
"Failed to delete credit card, please try again later.": "Kunne ikke slette kredittkortet, prøv igjen senere.", "Failed to delete credit card, please try again later.": "Kunne ikke slette kredittkortet, prøv igjen senere.",
"Fair": "Messe", "Fair": "Messe",
"FAQ": "FAQ",
"Find booking": "Finn booking", "Find booking": "Finn booking",
"Find hotels": "Finn hotell", "Find hotels": "Finn hotell",
"Flexibility": "Fleksibilitet", "Flexibility": "Fleksibilitet",
@@ -85,17 +90,22 @@
"Get inspired": "Bli inspirert", "Get inspired": "Bli inspirert",
"Go back to edit": "Gå tilbake til redigering", "Go back to edit": "Gå tilbake til redigering",
"Go back to overview": "Gå tilbake til oversikten", "Go back to overview": "Gå tilbake til oversikten",
"Guests & Rooms": "Gjester & rom",
"Hi": "Hei", "Hi": "Hei",
"Highest level": "Høyeste nivå", "Highest level": "Høyeste nivå",
"Hospital": "Sykehus", "Hospital": "Sykehus",
"Hotel": "Hotel", "Hotel": "Hotel",
"Hotel facilities": "Hotelfaciliteter", "Hotel facilities": "Hotelfaciliteter",
"Hotel surroundings": "Hotellomgivelser", "Hotel surroundings": "Hotellomgivelser",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "personer",
"hotelPages.rooms.roomCard.seeRoomDetails": "Se detaljer om rommet",
"Hotels": "Hoteller", "Hotels": "Hoteller",
"How do you want to sleep?": "Hvordan vil du sove?", "How do you want to sleep?": "Hvordan vil du sove?",
"How it works": "Hvordan det fungerer", "How it works": "Hvordan det fungerer",
"Image gallery": "Bildegalleri", "Image gallery": "Bildegalleri",
"Join Scandic Friends": "Bli med i Scandic Friends", "Join Scandic Friends": "Bli med i Scandic Friends",
"km to city center": "km til sentrum",
"Language": "Språk", "Language": "Språk",
"Latest searches": "Siste søk", "Latest searches": "Siste søk",
"Level": "Nivå", "Level": "Nivå",
@@ -122,9 +132,9 @@
"Member price": "Medlemspris", "Member price": "Medlemspris",
"Member price from": "Medlemspris fra", "Member price from": "Medlemspris fra",
"Members": "Medlemmer", "Members": "Medlemmer",
"Membership cards": "Medlemskort",
"Membership ID": "Medlems-ID", "Membership ID": "Medlems-ID",
"Membership ID copied to clipboard": "Medlems-ID kopiert til utklippstavlen", "Membership ID copied to clipboard": "Medlems-ID kopiert til utklippstavlen",
"Membership cards": "Medlemskort",
"Menu": "Menu", "Menu": "Menu",
"Modify": "Endre", "Modify": "Endre",
"Month": "Måned", "Month": "Måned",
@@ -139,6 +149,9 @@
"Nearby companies": "Nærliggende selskaper", "Nearby companies": "Nærliggende selskaper",
"New password": "Nytt passord", "New password": "Nytt passord",
"Next": "Neste", "Next": "Neste",
"next level:": "Neste nivå:",
"night": "natt",
"nights": "netter",
"Nights needed to level up": "Netter som trengs for å komme opp i nivå", "Nights needed to level up": "Netter som trengs for å komme opp i nivå",
"No content published": "Ingen innhold publisert", "No content published": "Ingen innhold publisert",
"No matching location found": "Fant ingen samsvarende plassering", "No matching location found": "Fant ingen samsvarende plassering",
@@ -149,11 +162,13 @@
"Non-refundable": "Ikke-refunderbart", "Non-refundable": "Ikke-refunderbart",
"Not found": "Ikke funnet", "Not found": "Ikke funnet",
"Nr night, nr adult": "{nights, number} natt, {adults, number} voksen", "Nr night, nr adult": "{nights, number} natt, {adults, number} voksen",
"number": "antall",
"On your journey": "På reisen din", "On your journey": "På reisen din",
"Open": "Åpen", "Open": "Åpen",
"Open language menu": "Åpne språkmenyen", "Open language menu": "Åpne språkmenyen",
"Open menu": "Åpne menyen", "Open menu": "Åpne menyen",
"Open my pages menu": "Åpne mine sider menyen", "Open my pages menu": "Åpne mine sider menyen",
"or": "eller",
"Overview": "Oversikt", "Overview": "Oversikt",
"Parking": "Parkering", "Parking": "Parkering",
"Parking / Garage": "Parkering / Garasje", "Parking / Garage": "Parkering / Garasje",
@@ -165,6 +180,7 @@
"Phone is required": "Telefon kreves", "Phone is required": "Telefon kreves",
"Phone number": "Telefonnummer", "Phone number": "Telefonnummer",
"Please enter a valid phone number": "Vennligst oppgi et gyldig telefonnummer", "Please enter a valid phone number": "Vennligst oppgi et gyldig telefonnummer",
"points": "poeng",
"Points": "Poeng", "Points": "Poeng",
"Points being calculated": "Poeng beregnes", "Points being calculated": "Poeng beregnes",
"Points earned prior to May 1, 2021": "Opptjente poeng før 1. mai 2021", "Points earned prior to May 1, 2021": "Opptjente poeng før 1. mai 2021",
@@ -183,7 +199,6 @@
"Room & Terms": "Rom & Vilkår", "Room & Terms": "Rom & Vilkår",
"Room facilities": "Romfasiliteter", "Room facilities": "Romfasiliteter",
"Rooms": "Rom", "Rooms": "Rom",
"Guests & Rooms": "Gjester & rom",
"Save": "Lagre", "Save": "Lagre",
"Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Mastercard": "Scandic Friends Mastercard",
"Scandic Friends Point Shop": "Scandic Friends Point Shop", "Scandic Friends Point Shop": "Scandic Friends Point Shop",
@@ -208,25 +223,29 @@
"Something went wrong and we couldn't add your card. Please try again later.": "Noe gikk galt, og vi kunne ikke legge til kortet ditt. Prøv igjen senere.", "Something went wrong and we couldn't add your card. Please try again later.": "Noe gikk galt, og vi kunne ikke legge til kortet ditt. Prøv igjen senere.",
"Something went wrong and we couldn't remove your card. Please try again later.": "Noe gikk galt, og vi kunne ikke fjerne kortet ditt. Vennligst prøv igjen senere.", "Something went wrong and we couldn't remove your card. Please try again later.": "Noe gikk galt, og vi kunne ikke fjerne kortet ditt. Vennligst prøv igjen senere.",
"Something went wrong!": "Noe gikk galt!", "Something went wrong!": "Noe gikk galt!",
"special character": "spesiell karakter",
"spendable points expiring by": "{points} Brukbare poeng utløper innen {date}",
"Sports": "Sport", "Sports": "Sport",
"Standard price": "Standardpris", "Standard price": "Standardpris",
"Street": "Gate", "Street": "Gate",
"Successfully updated profile!": "Vellykket oppdatert profil!", "Successfully updated profile!": "Vellykket oppdatert profil!",
"Summary": "Sammendrag", "Summary": "Sammendrag",
"TUI Points": "TUI Points",
"Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Fortell oss hvilken informasjon og hvilke oppdateringer du ønsker å motta, og hvordan, ved å klikke på lenken nedenfor.", "Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Fortell oss hvilken informasjon og hvilke oppdateringer du ønsker å motta, og hvordan, ved å klikke på lenken nedenfor.",
"Thank you": "Takk", "Thank you": "Takk",
"Theatre": "Teater", "Theatre": "Teater",
"There are no transactions to display": "Det er ingen transaksjoner å vise", "There are no transactions to display": "Det er ingen transaksjoner å vise",
"Things nearby HOTEL_NAME": "Ting i nærheten av {hotelName}", "Things nearby HOTEL_NAME": "Ting i nærheten av {hotelName}",
"to": "til",
"Total Points": "Totale poeng", "Total Points": "Totale poeng",
"Tourist": "Turist", "Tourist": "Turist",
"Transaction date": "Transaksjonsdato", "Transaction date": "Transaksjonsdato",
"Transactions": "Transaksjoner", "Transactions": "Transaksjoner",
"Transportations": "Transport", "Transportations": "Transport",
"Tripadvisor reviews": "{rating} ({count} anmeldelser på Tripadvisor)", "Tripadvisor reviews": "{rating} ({count} anmeldelser på Tripadvisor)",
"TUI Points": "TUI Points",
"Type of bed": "Sengtype", "Type of bed": "Sengtype",
"Type of room": "Romtype", "Type of room": "Romtype",
"uppercase letter": "stor bokstav",
"Use bonus cheque": "Bruk bonussjekk", "Use bonus cheque": "Bruk bonussjekk",
"User information": "Brukerinformasjon", "User information": "Brukerinformasjon",
"View as list": "Vis som liste", "View as list": "Vis som liste",
@@ -252,9 +271,9 @@
"You canceled adding a new credit card.": "Du kansellerte å legge til et nytt kredittkort.", "You canceled adding a new credit card.": "Du kansellerte å legge til et nytt kredittkort.",
"You have no previous stays.": "Du har ingen tidligere opphold.", "You have no previous stays.": "Du har ingen tidligere opphold.",
"You have no upcoming stays.": "Du har ingen kommende opphold.", "You have no upcoming stays.": "Du har ingen kommende opphold.",
"Your Challenges Conquer & Earn!": "Dine utfordringer Erobre og tjen!",
"Your card was successfully removed!": "Kortet ditt ble fjernet!", "Your card was successfully removed!": "Kortet ditt ble fjernet!",
"Your card was successfully saved!": "Kortet ditt ble lagret!", "Your card was successfully saved!": "Kortet ditt ble lagret!",
"Your Challenges Conquer & Earn!": "Dine utfordringer Erobre og tjen!",
"Your current level": "Ditt nåværende nivå", "Your current level": "Ditt nåværende nivå",
"Your details": "Dine detaljer", "Your details": "Dine detaljer",
"Your level": "Ditt nivå", "Your level": "Ditt nivå",
@@ -262,23 +281,5 @@
"Zip code": "Post kode", "Zip code": "Post kode",
"Zoo": "Dyrehage", "Zoo": "Dyrehage",
"Zoom in": "Zoom inn", "Zoom in": "Zoom inn",
"Zoom out": "Zoom ut", "Zoom out": "Zoom ut"
"as of today": "per i dag",
"booking.nights": "{totalNights, plural, one {# natt} other {# netter}}",
"by": "innen",
"characters": "tegn",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "personer",
"hotelPages.rooms.roomCard.seeRoomDetails": "Se detaljer om rommet",
"km to city center": "km til sentrum",
"next level:": "Neste nivå:",
"night": "natt",
"nights": "netter",
"number": "antall",
"or": "eller",
"points": "poeng",
"special character": "spesiell karakter",
"spendable points expiring by": "{points} Brukbare poeng utløper innen {date}",
"to": "til",
"uppercase letter": "stor bokstav"
} }

View File

@@ -14,6 +14,7 @@
"Any changes you've made will be lost.": "Alla ändringar du har gjort kommer att gå förlorade.", "Any changes you've made will be lost.": "Alla ändringar du har gjort kommer att gå förlorade.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Är du säker på att du vill ta bort kortet som slutar med {lastFourDigits} från din medlemsprofil?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Är du säker på att du vill ta bort kortet som slutar med {lastFourDigits} från din medlemsprofil?",
"Arrival date": "Ankomstdatum", "Arrival date": "Ankomstdatum",
"as of today": "från och med idag",
"As our": "Som vår {level}", "As our": "Som vår {level}",
"As our Close Friend": "Som vår nära vän", "As our Close Friend": "Som vår nära vän",
"At latest": "Senast", "At latest": "Senast",
@@ -23,14 +24,16 @@
"Bed type": "Sängtyp", "Bed type": "Sängtyp",
"Book": "Boka", "Book": "Boka",
"Book reward night": "Boka frinatt", "Book reward night": "Boka frinatt",
"Code / Voucher": "Bokningskoder / kuponger",
"Booking number": "Bokningsnummer", "Booking number": "Bokningsnummer",
"booking.nights": "{totalNights, plural, one {# natt} other {# nätter}}",
"Breakfast": "Frukost", "Breakfast": "Frukost",
"Breakfast excluded": "Frukost ingår ej", "Breakfast excluded": "Frukost ingår ej",
"Breakfast included": "Frukost ingår", "Breakfast included": "Frukost ingår",
"Bus terminal": "Bussterminal", "Bus terminal": "Bussterminal",
"Business": "Business", "Business": "Business",
"by": "innan",
"Cancel": "Avbryt", "Cancel": "Avbryt",
"characters": "tecken",
"Check in": "Checka in", "Check in": "Checka in",
"Check out": "Checka ut", "Check out": "Checka ut",
"Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Kolla in kreditkorten som sparats i din profil. Betala med ett sparat kort när du är inloggad för en smidigare webbupplevelse.", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Kolla in kreditkorten som sparats i din profil. Betala med ett sparat kort när du är inloggad för en smidigare webbupplevelse.",
@@ -45,8 +48,10 @@
"Close menu": "Stäng menyn", "Close menu": "Stäng menyn",
"Close my pages menu": "Stäng mina sidor menyn", "Close my pages menu": "Stäng mina sidor menyn",
"Close the map": "Stäng kartan", "Close the map": "Stäng kartan",
"Code / Voucher": "Bokningskoder / kuponger",
"Coming up": "Kommer härnäst", "Coming up": "Kommer härnäst",
"Compare all levels": "Jämför alla nivåer", "Compare all levels": "Jämför alla nivåer",
"Complete booking & go to payment": "Fullför bokning & gå till betalning",
"Contact us": "Kontakta oss", "Contact us": "Kontakta oss",
"Continue": "Fortsätt", "Continue": "Fortsätt",
"Copyright all rights reserved": "Scandic AB Alla rättigheter förbehålls", "Copyright all rights reserved": "Scandic AB Alla rättigheter förbehålls",
@@ -72,9 +77,9 @@
"Explore all levels and benefits": "Utforska alla nivåer och fördelar", "Explore all levels and benefits": "Utforska alla nivåer och fördelar",
"Explore nearby": "Utforska i närheten", "Explore nearby": "Utforska i närheten",
"Extras to your booking": "Extra tillval till din bokning", "Extras to your booking": "Extra tillval till din bokning",
"FAQ": "FAQ",
"Failed to delete credit card, please try again later.": "Det gick inte att ta bort kreditkortet, försök igen senare.", "Failed to delete credit card, please try again later.": "Det gick inte att ta bort kreditkortet, försök igen senare.",
"Fair": "Mässa", "Fair": "Mässa",
"FAQ": "FAQ",
"Find booking": "Hitta bokning", "Find booking": "Hitta bokning",
"Find hotels": "Hitta hotell", "Find hotels": "Hitta hotell",
"Flexibility": "Flexibilitet", "Flexibility": "Flexibilitet",
@@ -85,17 +90,22 @@
"Get inspired": "Bli inspirerad", "Get inspired": "Bli inspirerad",
"Go back to edit": "Gå tillbaka till redigeringen", "Go back to edit": "Gå tillbaka till redigeringen",
"Go back to overview": "Gå tillbaka till översikten", "Go back to overview": "Gå tillbaka till översikten",
"Guests & Rooms": "Gäster & rum",
"Hi": "Hej", "Hi": "Hej",
"Highest level": "Högsta nivå", "Highest level": "Högsta nivå",
"Hospital": "Sjukhus", "Hospital": "Sjukhus",
"Hotel": "Hotell", "Hotel": "Hotell",
"Hotel facilities": "Hotellfaciliteter", "Hotel facilities": "Hotellfaciliteter",
"Hotel surroundings": "Hotellomgivning", "Hotel surroundings": "Hotellomgivning",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "personer",
"hotelPages.rooms.roomCard.seeRoomDetails": "Se information om rummet",
"Hotels": "Hotell", "Hotels": "Hotell",
"How do you want to sleep?": "Hur vill du sova?", "How do you want to sleep?": "Hur vill du sova?",
"How it works": "Hur det fungerar", "How it works": "Hur det fungerar",
"Image gallery": "Bildgalleri", "Image gallery": "Bildgalleri",
"Join Scandic Friends": "Gå med i Scandic Friends", "Join Scandic Friends": "Gå med i Scandic Friends",
"km to city center": "km till stadens centrum",
"Language": "Språk", "Language": "Språk",
"Latest searches": "Senaste sökningarna", "Latest searches": "Senaste sökningarna",
"Level": "Nivå", "Level": "Nivå",
@@ -122,9 +132,9 @@
"Member price": "Medlemspris", "Member price": "Medlemspris",
"Member price from": "Medlemspris från", "Member price from": "Medlemspris från",
"Members": "Medlemmar", "Members": "Medlemmar",
"Membership cards": "Medlemskort",
"Membership ID": "Medlems-ID", "Membership ID": "Medlems-ID",
"Membership ID copied to clipboard": "Medlems-ID kopierat till urklipp", "Membership ID copied to clipboard": "Medlems-ID kopierat till urklipp",
"Membership cards": "Medlemskort",
"Menu": "Meny", "Menu": "Meny",
"Modify": "Ändra", "Modify": "Ändra",
"Month": "Månad", "Month": "Månad",
@@ -139,6 +149,9 @@
"Nearby companies": "Närliggande företag", "Nearby companies": "Närliggande företag",
"New password": "Nytt lösenord", "New password": "Nytt lösenord",
"Next": "Nästa", "Next": "Nästa",
"next level:": "Nästa nivå:",
"night": "natt",
"nights": "nätter",
"Nights needed to level up": "Nätter som behövs för att gå upp i nivå", "Nights needed to level up": "Nätter som behövs för att gå upp i nivå",
"No content published": "Inget innehåll publicerat", "No content published": "Inget innehåll publicerat",
"No matching location found": "Ingen matchande plats hittades", "No matching location found": "Ingen matchande plats hittades",
@@ -149,11 +162,13 @@
"Non-refundable": "Ej återbetalningsbar", "Non-refundable": "Ej återbetalningsbar",
"Not found": "Hittades inte", "Not found": "Hittades inte",
"Nr night, nr adult": "{nights, number} natt, {adults, number} vuxen", "Nr night, nr adult": "{nights, number} natt, {adults, number} vuxen",
"number": "nummer",
"On your journey": "På din resa", "On your journey": "På din resa",
"Open": "Öppna", "Open": "Öppna",
"Open language menu": "Öppna språkmenyn", "Open language menu": "Öppna språkmenyn",
"Open menu": "Öppna menyn", "Open menu": "Öppna menyn",
"Open my pages menu": "Öppna mina sidor menyn", "Open my pages menu": "Öppna mina sidor menyn",
"or": "eller",
"Overview": "Översikt", "Overview": "Översikt",
"Parking": "Parkering", "Parking": "Parkering",
"Parking / Garage": "Parkering / Garage", "Parking / Garage": "Parkering / Garage",
@@ -165,6 +180,7 @@
"Phone is required": "Telefonnummer är obligatorisk", "Phone is required": "Telefonnummer är obligatorisk",
"Phone number": "Telefonnummer", "Phone number": "Telefonnummer",
"Please enter a valid phone number": "Var vänlig och ange ett giltigt telefonnummer", "Please enter a valid phone number": "Var vänlig och ange ett giltigt telefonnummer",
"points": "poäng",
"Points": "Poäng", "Points": "Poäng",
"Points being calculated": "Poäng beräknas", "Points being calculated": "Poäng beräknas",
"Points earned prior to May 1, 2021": "Intjänade poäng före den 1 maj 2021", "Points earned prior to May 1, 2021": "Intjänade poäng före den 1 maj 2021",
@@ -183,7 +199,6 @@
"Room & Terms": "Rum & Villkor", "Room & Terms": "Rum & Villkor",
"Room facilities": "Rumfaciliteter", "Room facilities": "Rumfaciliteter",
"Rooms": "Rum", "Rooms": "Rum",
"Guests & Rooms": "Gäster & rum",
"Save": "Spara", "Save": "Spara",
"Scandic Friends Mastercard": "Scandic Friends Mastercard", "Scandic Friends Mastercard": "Scandic Friends Mastercard",
"Scandic Friends Point Shop": "Scandic Friends Point Shop", "Scandic Friends Point Shop": "Scandic Friends Point Shop",
@@ -208,25 +223,29 @@
"Something went wrong and we couldn't add your card. Please try again later.": "Något gick fel och vi kunde inte lägga till ditt kort. Försök igen senare.", "Something went wrong and we couldn't add your card. Please try again later.": "Något gick fel och vi kunde inte lägga till ditt kort. Försök igen senare.",
"Something went wrong and we couldn't remove your card. Please try again later.": "Något gick fel och vi kunde inte ta bort ditt kort. Försök igen senare.", "Something went wrong and we couldn't remove your card. Please try again later.": "Något gick fel och vi kunde inte ta bort ditt kort. Försök igen senare.",
"Something went wrong!": "Något gick fel!", "Something went wrong!": "Något gick fel!",
"special character": "speciell karaktär",
"spendable points expiring by": "{points} poäng förfaller {date}",
"Sports": "Sport", "Sports": "Sport",
"Standard price": "Standardpris", "Standard price": "Standardpris",
"Street": "Gata", "Street": "Gata",
"Successfully updated profile!": "Profilen har uppdaterats framgångsrikt!", "Successfully updated profile!": "Profilen har uppdaterats framgångsrikt!",
"Summary": "Sammanfattning", "Summary": "Sammanfattning",
"TUI Points": "TUI Points",
"Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Berätta för oss vilken information och vilka uppdateringar du vill få och hur genom att klicka på länken nedan.", "Tell us what information and updates you'd like to receive, and how, by clicking the link below.": "Berätta för oss vilken information och vilka uppdateringar du vill få och hur genom att klicka på länken nedan.",
"Thank you": "Tack", "Thank you": "Tack",
"Theatre": "Teater", "Theatre": "Teater",
"There are no transactions to display": "Det finns inga transaktioner att visa", "There are no transactions to display": "Det finns inga transaktioner att visa",
"Things nearby HOTEL_NAME": "Saker i närheten av {hotelName}", "Things nearby HOTEL_NAME": "Saker i närheten av {hotelName}",
"to": "till",
"Total Points": "Poäng totalt", "Total Points": "Poäng totalt",
"Tourist": "Turist", "Tourist": "Turist",
"Transaction date": "Transaktionsdatum", "Transaction date": "Transaktionsdatum",
"Transactions": "Transaktioner", "Transactions": "Transaktioner",
"Transportations": "Transport", "Transportations": "Transport",
"Tripadvisor reviews": "{rating} ({count} recensioner på Tripadvisor)", "Tripadvisor reviews": "{rating} ({count} recensioner på Tripadvisor)",
"TUI Points": "TUI Points",
"Type of bed": "Sängtyp", "Type of bed": "Sängtyp",
"Type of room": "Rumstyp", "Type of room": "Rumstyp",
"uppercase letter": "stor bokstav",
"Use bonus cheque": "Use bonus cheque", "Use bonus cheque": "Use bonus cheque",
"User information": "Användarinformation", "User information": "Användarinformation",
"View as list": "Visa som lista", "View as list": "Visa som lista",
@@ -252,9 +271,9 @@
"You canceled adding a new credit card.": "Du avbröt att lägga till ett nytt kreditkort.", "You canceled adding a new credit card.": "Du avbröt att lägga till ett nytt kreditkort.",
"You have no previous stays.": "Du har inga tidigare vistelser.", "You have no previous stays.": "Du har inga tidigare vistelser.",
"You have no upcoming stays.": "Du har inga planerade resor.", "You have no upcoming stays.": "Du har inga planerade resor.",
"Your Challenges Conquer & Earn!": "Dina utmaningar Erövra och tjäna!",
"Your card was successfully removed!": "Ditt kort har tagits bort!", "Your card was successfully removed!": "Ditt kort har tagits bort!",
"Your card was successfully saved!": "Ditt kort har sparats!", "Your card was successfully saved!": "Ditt kort har sparats!",
"Your Challenges Conquer & Earn!": "Dina utmaningar Erövra och tjäna!",
"Your current level": "Din nuvarande nivå", "Your current level": "Din nuvarande nivå",
"Your details": "Dina uppgifter", "Your details": "Dina uppgifter",
"Your level": "Din nivå", "Your level": "Din nivå",
@@ -262,23 +281,5 @@
"Zip code": "Postnummer", "Zip code": "Postnummer",
"Zoo": "Djurpark", "Zoo": "Djurpark",
"Zoom in": "Zooma in", "Zoom in": "Zooma in",
"Zoom out": "Zooma ut", "Zoom out": "Zooma ut"
"as of today": "per idag",
"booking.nights": "{totalNights, plural, one {# natt} other {# nätter}}",
"by": "innan",
"characters": "tecken",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "personer",
"hotelPages.rooms.roomCard.seeRoomDetails": "Se information om rummet",
"km to city center": "km till stadens centrum",
"next level:": "Nästa nivå:",
"night": "natt",
"nights": "nätter",
"number": "nummer",
"or": "eller",
"points": "poäng",
"special character": "speciell karaktär",
"spendable points expiring by": "{points} poäng förfaller {date}",
"to": "till",
"uppercase letter": "stor bokstav"
} }

View File

@@ -1,5 +1,9 @@
import { mergeRouters } from "@/server/trpc" import { mergeRouters } from "@/server/trpc"
import { bookingMutationRouter } from "./mutation" import { bookingMutationRouter } from "./mutation"
import { bookingQueryRouter } from "./query"
export const bookingRouter = mergeRouters(bookingMutationRouter) export const bookingRouter = mergeRouters(
bookingMutationRouter,
bookingQueryRouter
)

View File

@@ -1,38 +1,68 @@
import { z } from "zod" import { z } from "zod"
// Query const roomsSchema = z.array(
z.object({
adults: z.number().int().nonnegative(),
childrenAges: z
.array(
z.object({
age: z.number().int().nonnegative(),
bedType: z.string(),
})
)
.default([]),
rateCode: z.string(),
roomTypeCode: z.string(),
guest: z.object({
title: z.string(),
firstName: z.string(),
lastName: z.string(),
email: z.string().email(),
phoneCountryCodePrefix: z.string(),
phoneNumber: z.string(),
countryCode: z.string(),
membershipNumber: z.string().optional(),
}),
smsConfirmationRequested: z.boolean(),
packages: z.object({
breakfast: z.boolean(),
allergyFriendly: z.boolean(),
petFriendly: z.boolean(),
accessibility: z.boolean(),
}),
})
)
const paymentSchema = z.object({
paymentMethod: z.string(),
card: z
.object({
alias: z.string(),
expiryDate: z.string(),
cardType: z.string(),
})
.optional(),
cardHolder: z.object({
email: z.string().email(),
name: z.string(),
phoneCountryCode: z.string(),
phoneSubscriber: z.string(),
}),
success: z.string(),
error: z.string(),
cancel: z.string(),
})
// Mutation // Mutation
export const createBookingInput = z.object({ export const createBookingInput = z.object({
hotelId: z.string(), hotelId: z.string(),
checkInDate: z.string(), checkInDate: z.string(),
checkOutDate: z.string(), checkOutDate: z.string(),
rooms: z.array( rooms: roomsSchema,
z.object({ payment: paymentSchema,
adults: z.number().int().nonnegative(), })
children: z.number().int().nonnegative(),
rateCode: z.string(), // Query
roomTypeCode: z.string(), export const getBookingStatusInput = z.object({
guest: z.object({ confirmationNumber: z.string(),
title: z.string(),
firstName: z.string(),
lastName: z.string(),
email: z.string().email(),
phoneCountryCodePrefix: z.string(),
phoneNumber: z.string(),
countryCode: z.string(),
}),
smsConfirmationRequested: z.boolean(),
})
),
payment: z.object({
cardHolder: z.object({
Email: z.string().email(),
Name: z.string(),
PhoneCountryCode: z.string(),
PhoneSubscriber: z.string(),
}),
success: z.string(),
error: z.string(),
cancel: z.string(),
}),
}) })

View File

@@ -2,7 +2,7 @@ import { metrics } from "@opentelemetry/api"
import * as api from "@/lib/api" import * as api from "@/lib/api"
import { getVerifiedUser } from "@/server/routers/user/query" import { getVerifiedUser } from "@/server/routers/user/query"
import { router, safeProtectedProcedure } from "@/server/trpc" import { bookingServiceProcedure, router } from "@/server/trpc"
import { getMembership } from "@/utils/user" import { getMembership } from "@/utils/user"
@@ -36,13 +36,15 @@ async function getMembershipNumber(
export const bookingMutationRouter = router({ export const bookingMutationRouter = router({
booking: router({ booking: router({
create: safeProtectedProcedure create: bookingServiceProcedure
.input(createBookingInput) .input(createBookingInput)
.mutation(async function ({ ctx, input }) { .mutation(async function ({ ctx, input }) {
const { checkInDate, checkOutDate, hotelId } = input const { checkInDate, checkOutDate, hotelId } = input
// TODO: add support for user token OR service token in procedure
// then we can fetch membership number if user token exists
const loggingAttributes = { const loggingAttributes = {
membershipNumber: await getMembershipNumber(ctx.session), // membershipNumber: await getMembershipNumber(ctx.session),
checkInDate, checkInDate,
checkOutDate, checkOutDate,
hotelId, hotelId,
@@ -56,11 +58,10 @@ export const bookingMutationRouter = router({
query: loggingAttributes, query: loggingAttributes,
}) })
) )
const headers = ctx.session const headers = {
? { Authorization: `Bearer ${ctx.serviceToken}`,
Authorization: `Bearer ${ctx.session?.token.access_token}`, }
}
: undefined
const apiResponse = await api.post(api.endpoints.v1.booking, { const apiResponse = await api.post(api.endpoints.v1.booking, {
headers, headers,
body: input, body: input,

View File

@@ -5,9 +5,9 @@ export const createBookingSchema = z
data: z.object({ data: z.object({
attributes: z.object({ attributes: z.object({
confirmationNumber: z.string(), confirmationNumber: z.string(),
cancellationNumber: z.string().nullable(), cancellationNumber: z.string().optional(),
reservationStatus: z.string(), reservationStatus: z.string(),
paymentUrl: z.string().nullable(), paymentUrl: z.string().optional(),
}), }),
type: z.string(), type: z.string(),
id: z.string(), id: z.string(),

View File

@@ -0,0 +1,85 @@
import { metrics } from "@opentelemetry/api"
import * as api from "@/lib/api"
import { badRequestError, serverErrorByStatus } from "@/server/errors/trpc"
import { bookingServiceProcedure, router } from "@/server/trpc"
import { getBookingStatusInput } from "./input"
import { createBookingSchema } from "./output"
const meter = metrics.getMeter("trpc.booking")
const getBookingStatusCounter = meter.createCounter("trpc.booking.status")
const getBookingStatusSuccessCounter = meter.createCounter(
"trpc.booking.status-success"
)
const getBookingStatusFailCounter = meter.createCounter(
"trpc.booking.status-fail"
)
export const bookingQueryRouter = router({
status: bookingServiceProcedure
.input(getBookingStatusInput)
.query(async function ({ ctx, input }) {
const { confirmationNumber } = input
getBookingStatusCounter.add(1, { confirmationNumber })
const apiResponse = await api.get(
`${api.endpoints.v1.booking}/${confirmationNumber}/status`,
{
headers: {
Authorization: `Bearer ${ctx.serviceToken}`,
},
}
)
if (!apiResponse.ok) {
const responseMessage = await apiResponse.text()
getBookingStatusFailCounter.add(1, {
confirmationNumber,
error_type: "http_error",
error: responseMessage,
})
console.error(
"api.booking.status error",
JSON.stringify({
query: { confirmationNumber },
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text: responseMessage,
},
})
)
throw serverErrorByStatus(apiResponse.status, apiResponse)
}
const apiJson = await apiResponse.json()
const verifiedData = createBookingSchema.safeParse(apiJson)
if (!verifiedData.success) {
getBookingStatusFailCounter.add(1, {
confirmationNumber,
error_type: "validation_error",
error: JSON.stringify(verifiedData.error),
})
console.error(
"api.booking.status validation error",
JSON.stringify({
query: { confirmationNumber },
error: verifiedData.error,
})
)
throw badRequestError()
}
getBookingStatusSuccessCounter.add(1, { confirmationNumber })
console.info(
"api.booking.status success",
JSON.stringify({
query: { confirmationNumber },
})
)
return verifiedData.data
}),
})

View File

@@ -436,6 +436,22 @@ export const roomSchema = z.object({
type: z.enum(["roomcategories"]), type: z.enum(["roomcategories"]),
}) })
const merchantInformationSchema = z.object({
webMerchantId: z.string(),
cards: z.record(z.string(), z.boolean()).transform((val) => {
return Object.entries(val)
.filter(([_, enabled]) => enabled)
.map(([key]) => key)
}),
alternatePaymentOptions: z
.record(z.string(), z.boolean())
.transform((val) => {
return Object.entries(val)
.filter(([_, enabled]) => enabled)
.map(([key]) => key)
}),
})
// NOTE: Find schema at: https://aks-test.scandichotels.com/hotel/swagger/v1/index.html // NOTE: Find schema at: https://aks-test.scandichotels.com/hotel/swagger/v1/index.html
export const getHotelDataSchema = z.object({ export const getHotelDataSchema = z.object({
data: z.object({ data: z.object({
@@ -471,6 +487,7 @@ export const getHotelDataSchema = z.object({
hotelContent: hotelContentSchema, hotelContent: hotelContentSchema,
detailedFacilities: z.array(detailedFacilitySchema), detailedFacilities: z.array(detailedFacilitySchema),
healthFacilities: z.array(healthFacilitySchema), healthFacilities: z.array(healthFacilitySchema),
merchantInformationData: merchantInformationSchema,
rewardNight: rewardNightSchema, rewardNight: rewardNightSchema,
pointsOfInterest: z pointsOfInterest: z
.array(pointOfInterestSchema) .array(pointOfInterestSchema)

View File

@@ -121,29 +121,24 @@ export const safeProtectedProcedure = t.procedure.use(async function (opts) {
}) })
}) })
export const profileServiceProcedure = t.procedure.use(async (opts) => { function createServiceProcedure(serviceName: string) {
const { access_token } = await fetchServiceToken(["profile"]) return t.procedure.use(async (opts) => {
if (!access_token) { const { access_token } = await fetchServiceToken([serviceName])
throw internalServerError("Failed to obtain profile service token") if (!access_token) {
} throw internalServerError(`Failed to obtain ${serviceName} service token`)
return opts.next({ }
ctx: { return opts.next({
serviceToken: access_token, ctx: {
}, serviceToken: access_token,
},
})
}) })
}) }
export const bookingServiceProcedure = createServiceProcedure("booking")
export const hotelServiceProcedure = createServiceProcedure("hotel")
export const profileServiceProcedure = createServiceProcedure("profile")
export const hotelServiceProcedure = t.procedure.use(async (opts) => {
const { access_token } = await fetchServiceToken(["hotel"])
if (!access_token) {
throw internalServerError("Failed to obtain hotel service token")
}
return opts.next({
ctx: {
serviceToken: access_token,
},
})
})
export const serverActionProcedure = t.procedure.experimental_caller( export const serverActionProcedure = t.procedure.experimental_caller(
experimental_nextAppDirCaller({ experimental_nextAppDirCaller({
createContext, createContext,

View File

@@ -1,5 +1,7 @@
import { Rate } from "@/server/routers/hotels/output" import { Rate } from "@/server/routers/hotels/output"
import { Hotel } from "@/types/hotel"
export interface SectionProps { export interface SectionProps {
nextPath: string nextPath: string
} }
@@ -33,6 +35,10 @@ export interface RoomSelectionProps extends SectionProps {
export interface DetailsProps extends SectionProps {} export interface DetailsProps extends SectionProps {}
export interface PaymentProps {
hotel: Hotel
}
export interface SectionPageProps { export interface SectionPageProps {
breakfast?: string breakfast?: string
bed?: string bed?: string