From 3d62c16899ef3889f88d199b38448ba9e1f94f64 Mon Sep 17 00:00:00 2001 From: Linus Flood Date: Mon, 5 Jan 2026 11:33:08 +0000 Subject: [PATCH] Merged in feat/lokalise-sync-260105 (pull request #3387) feat(lokalise): fixed correct message and sync * feat(lokalise): fixed correct message and sync --- apps/partner-sas/i18n/dictionaries/en.json | 366 ++++++++++++++- .../Steps/SelectQuantityStep/index.tsx | 6 +- apps/scandic-web/i18n/dictionaries/en.json | 366 ++++++++++++++- scripts/i18n/lokalise.ts | 420 +++++++++--------- 4 files changed, 937 insertions(+), 221 deletions(-) diff --git a/apps/partner-sas/i18n/dictionaries/en.json b/apps/partner-sas/i18n/dictionaries/en.json index f0e2252da..d02d4d45f 100644 --- a/apps/partner-sas/i18n/dictionaries/en.json +++ b/apps/partner-sas/i18n/dictionaries/en.json @@ -33,6 +33,12 @@ "value": "Reserve with card" } ], + "addAncillary.deliveryDetailsStep.commentLabel": [ + { + "type": 0, + "value": "Is there anything else you would like us to know before your arrival?" + } + ], "addAncillary.deliveryDetailsStep.deliveryTimeDescription": [ { "type": 0, @@ -42,7 +48,7 @@ "addAncillary.deliveryDetailsStep.optionalTextLabel": [ { "type": 0, - "value": "Other Requests" + "value": "Other requests" } ], "addAncillary.selectQuantityStep.breakfastInfoMessage": [ @@ -51,6 +57,20 @@ "value": "Breakfast can only be added for the entire duration of the stay and for all guests." } ], + "addAncillary.selectQuantityStep.costPerUnit": [ + { + "type": 1, + "value": "cost" + }, + { + "type": 0, + "value": "/per " + }, + { + "type": 1, + "value": "unit" + } + ], "addAncillary.selectQuantityStep.insufficientPoints": [ { "type": 0, @@ -81,6 +101,18 @@ "value": "Select quantity" } ], + "addAncillary.selectQuantityStep.selectQuantityTitle": [ + { + "type": 0, + "value": "How would you like to pay?" + } + ], + "addAncillaryFlowModal.addToBooking": [ + { + "type": 0, + "value": "Add to booking" + } + ], "addAncillaryFlowModal.ancillaryAdded": [ { "type": 1, @@ -111,6 +143,16 @@ "value": "Free for kids (under 4)" } ], + "addAncillaryFlowModal.perUnit": [ + { + "type": 0, + "value": "/per " + }, + { + "type": 1, + "value": "unit" + } + ], "addAncillaryFlowModal.pricePerNightPerAdult": [ { "type": 1, @@ -131,6 +173,12 @@ "value": "/night for kids (ages 4–12)" } ], + "addAncillaryFlowModal.proceedToDelivery": [ + { + "type": 0, + "value": "Proceed to delivery" + } + ], "alternativeHotels.title": [ { "type": 0, @@ -147,6 +195,42 @@ "value": "Delivered at:" } ], + "ancillaries.deliveryDetailsStep.changeTime.cta": [ + { + "type": 0, + "value": "Change time" + } + ], + "ancillaries.deliveryDetailsStep.itemTitle": [ + { + "type": 0, + "value": "Your item" + } + ], + "ancillaries.deliveryDetailsStep.select.errorMessage": [ + { + "type": 0, + "value": "Select a time for when you want your extras to be delivered." + } + ], + "ancillaries.deliveryDetailsStep.select.title": [ + { + "type": 0, + "value": "Select time of delivery" + } + ], + "ancillaries.deliveryDetailsStep.specialRequests.cta": [ + { + "type": 0, + "value": "Add special request" + } + ], + "ancillaries.deliveryDetailsStep.specialRequests.title": [ + { + "type": 0, + "value": "Special requests (optional)" + } + ], "ancillaries.unableToDisplayBreakfastPrices": [ { "type": 0, @@ -878,7 +962,7 @@ "bookingWidget.bookingCode.tooltip": [ { "type": 0, - "value": "If you're booking a promotional offer or a Corporate negotiated rate you'll need a special booking code. Don't use any special characters such as (.) (,) (-) (:). If you would like to make a booking with code VOF, please call us +46 8 517 517 20.Save your booking code for the next time you visit the page by ticking the box “Remember”. Don't tick the box if you're using a public computer to avoid unauthorized access to your booking code." + "value": "If you're booking a promotional offer or a Corporate negotiated rate you'll need a special booking code. Don't use any special characters such as (.) (,) (-) (:). If you would like to make a booking with code VOF, please call us +46 8 517 517 20. Save your booking code for the next time you visit the page by ticking the box “Remember”. Don't tick the box if you're using a public computer to avoid unauthorized access to your booking code." } ], "bookingWidget.button.search": [ @@ -1073,6 +1157,12 @@ "value": "A destination or hotel name is needed to be able to search for a hotel room." } ], + "bookingwidget.dropdown.children": [ + { + "type": 0, + "value": "Children (0–12 years)" + } + ], "breadcrumbs.label": [ { "type": 0, @@ -1995,6 +2085,42 @@ "value": "or" } ], + "common.orNumberOfPoints": [ + { + "type": 0, + "value": "or " + }, + { + "offset": 0, + "options": { + "one": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " point" + } + ] + }, + "other": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " points" + } + ] + } + }, + "pluralType": "cardinal", + "type": 6, + "value": "points" + } + ], "common.other": [ { "type": 0, @@ -2025,12 +2151,24 @@ "value": "Password" } ], + "common.paymentCard": [ + { + "type": 0, + "value": "Payment card" + } + ], "common.perAdultNight": [ { "type": 0, "value": "Per adult/night" } ], + "common.person": [ + { + "type": 0, + "value": "person" + } + ], "common.petFriendly": [ { "type": 0, @@ -2116,6 +2254,12 @@ "value": "Remove" } ], + "common.reviewAndConfirm": [ + { + "type": 0, + "value": "Review & Confirm" + } + ], "common.room": [ { "type": 0, @@ -4298,12 +4442,24 @@ "value": "count" } ], + "lightbox.nextImage": [ + { + "type": 0, + "value": "Next image" + } + ], "lightbox.openImage": [ { "type": 0, "value": "Open image" } ], + "lightbox.previousImage": [ + { + "type": 0, + "value": "Previous image" + } + ], "linkEmploymentError.alreadyLinkedHeading": [ { "type": 0, @@ -5623,6 +5779,30 @@ "value": "My membership cards" } ], + "myPages.myStay.ancillaries.insufficientPointsMessage": [ + { + "type": 0, + "value": "You don't have enough points for this item" + } + ], + "myPages.myStay.ancillaries.reachedMaxPointsMessage": [ + { + "type": 0, + "value": "You have reached your points limit." + } + ], + "myPages.myStay.ancillaries.reachedMaxPointsStepperMessage": [ + { + "type": 0, + "value": "You’ve reached your points limit and can’t add more items with points." + } + ], + "myPages.myStay.ancillaries.spendablePointsTitle": [ + { + "type": 0, + "value": "Your spendable points" + } + ], "myPages.nameWithCardMembershipType": [ { "type": 0, @@ -6609,6 +6789,82 @@ "value": " days" } ], + "nextStay.inXMonths": [ + { + "type": 0, + "value": "In " + }, + { + "offset": 0, + "options": { + "one": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " month" + } + ] + }, + "other": { + "value": [ + { + "type": 0, + "value": " " + }, + { + "type": 7 + }, + { + "type": 0, + "value": " months" + } + ] + } + }, + "pluralType": "cardinal", + "type": 6, + "value": "months" + } + ], + "nextStay.inXYears": [ + { + "type": 0, + "value": "In " + }, + { + "offset": 0, + "options": { + "one": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " year" + } + ] + }, + "other": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " years" + } + ] + } + }, + "pluralType": "cardinal", + "type": 6, + "value": "years" + } + ], "nextStay.myStayAt": [ { "type": 0, @@ -7240,6 +7496,50 @@ "value": "expiryDate" } ], + "previousStays.nightsStayed": [ + { + "type": 0, + "value": "Nights stayed" + } + ], + "previousStays.progressAriaLabel": [ + { + "type": 1, + "value": "nightsStayed" + }, + { + "type": 0, + "value": " of " + }, + { + "type": 1, + "value": "maxNights" + }, + { + "type": 0, + "value": " nights stayed towards " + }, + { + "type": 1, + "value": "levelName" + } + ], + "previousStays.sinceDate": [ + { + "type": 0, + "value": "Since " + }, + { + "type": 1, + "value": "date" + } + ], + "previousStays.totalStays": [ + { + "type": 0, + "value": "Total stays" + } + ], "price.numberOfVouchers": [ { "offset": 0, @@ -7904,6 +8204,30 @@ "value": "Menus" } ], + "rewardNights.offerPrice": [ + { + "type": 0, + "value": "Offer price" + } + ], + "rewardNights.stayBetween:": [ + { + "type": 0, + "value": "Stay between:" + } + ], + "rewardNights.table.destination": [ + { + "type": 0, + "value": "Destination" + } + ], + "rewardNights.table.hotel": [ + { + "type": 0, + "value": "Hotel" + } + ], "rewards.active": [ { "type": 0, @@ -8423,7 +8747,7 @@ }, { "type": 0, - "value": "-" + "value": "–" }, { "type": 1, @@ -8899,6 +9223,18 @@ "value": "You have no upcoming stays at the moment" } ], + "stays.previous.title": [ + { + "type": 0, + "value": "Previous stays" + } + ], + "stays.upcoming.title": [ + { + "type": 0, + "value": "Upcoming stays" + } + ], "stays.whereToGoNext": [ { "type": 0, @@ -9042,6 +9378,30 @@ "value": "User not found" } ], + "videoPlayer.mute": [ + { + "type": 0, + "value": "Mute video" + } + ], + "videoPlayer.pause": [ + { + "type": 0, + "value": "Pause video" + } + ], + "videoPlayer.play": [ + { + "type": 0, + "value": "Play video" + } + ], + "videoPlayer.unmute": [ + { + "type": 0, + "value": "Unmute video" + } + ], "webview.genericUserError": [ { "type": 0, diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/Steps/SelectQuantityStep/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/Steps/SelectQuantityStep/index.tsx index 14ef73197..78a929ada 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/Steps/SelectQuantityStep/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/Steps/SelectQuantityStep/index.tsx @@ -150,7 +150,8 @@ function InnerSelectQuantityStep({ cost: intl.formatMessage( { id: "common.numberOfPoints", - defaultMessage: "{points} points", + defaultMessage: + "{points, plural, one {# point} other {# points}}", }, { points: pointsCost } ), @@ -162,7 +163,8 @@ function InnerSelectQuantityStep({ totalCostMessage={intl.formatMessage( { id: "common.numberOfPoints", - defaultMessage: "{points} points", + defaultMessage: + "{points, plural, one {# point} other {# points}}", }, { points: pointsCost * quantity } )} diff --git a/apps/scandic-web/i18n/dictionaries/en.json b/apps/scandic-web/i18n/dictionaries/en.json index f0e2252da..d02d4d45f 100644 --- a/apps/scandic-web/i18n/dictionaries/en.json +++ b/apps/scandic-web/i18n/dictionaries/en.json @@ -33,6 +33,12 @@ "value": "Reserve with card" } ], + "addAncillary.deliveryDetailsStep.commentLabel": [ + { + "type": 0, + "value": "Is there anything else you would like us to know before your arrival?" + } + ], "addAncillary.deliveryDetailsStep.deliveryTimeDescription": [ { "type": 0, @@ -42,7 +48,7 @@ "addAncillary.deliveryDetailsStep.optionalTextLabel": [ { "type": 0, - "value": "Other Requests" + "value": "Other requests" } ], "addAncillary.selectQuantityStep.breakfastInfoMessage": [ @@ -51,6 +57,20 @@ "value": "Breakfast can only be added for the entire duration of the stay and for all guests." } ], + "addAncillary.selectQuantityStep.costPerUnit": [ + { + "type": 1, + "value": "cost" + }, + { + "type": 0, + "value": "/per " + }, + { + "type": 1, + "value": "unit" + } + ], "addAncillary.selectQuantityStep.insufficientPoints": [ { "type": 0, @@ -81,6 +101,18 @@ "value": "Select quantity" } ], + "addAncillary.selectQuantityStep.selectQuantityTitle": [ + { + "type": 0, + "value": "How would you like to pay?" + } + ], + "addAncillaryFlowModal.addToBooking": [ + { + "type": 0, + "value": "Add to booking" + } + ], "addAncillaryFlowModal.ancillaryAdded": [ { "type": 1, @@ -111,6 +143,16 @@ "value": "Free for kids (under 4)" } ], + "addAncillaryFlowModal.perUnit": [ + { + "type": 0, + "value": "/per " + }, + { + "type": 1, + "value": "unit" + } + ], "addAncillaryFlowModal.pricePerNightPerAdult": [ { "type": 1, @@ -131,6 +173,12 @@ "value": "/night for kids (ages 4–12)" } ], + "addAncillaryFlowModal.proceedToDelivery": [ + { + "type": 0, + "value": "Proceed to delivery" + } + ], "alternativeHotels.title": [ { "type": 0, @@ -147,6 +195,42 @@ "value": "Delivered at:" } ], + "ancillaries.deliveryDetailsStep.changeTime.cta": [ + { + "type": 0, + "value": "Change time" + } + ], + "ancillaries.deliveryDetailsStep.itemTitle": [ + { + "type": 0, + "value": "Your item" + } + ], + "ancillaries.deliveryDetailsStep.select.errorMessage": [ + { + "type": 0, + "value": "Select a time for when you want your extras to be delivered." + } + ], + "ancillaries.deliveryDetailsStep.select.title": [ + { + "type": 0, + "value": "Select time of delivery" + } + ], + "ancillaries.deliveryDetailsStep.specialRequests.cta": [ + { + "type": 0, + "value": "Add special request" + } + ], + "ancillaries.deliveryDetailsStep.specialRequests.title": [ + { + "type": 0, + "value": "Special requests (optional)" + } + ], "ancillaries.unableToDisplayBreakfastPrices": [ { "type": 0, @@ -878,7 +962,7 @@ "bookingWidget.bookingCode.tooltip": [ { "type": 0, - "value": "If you're booking a promotional offer or a Corporate negotiated rate you'll need a special booking code. Don't use any special characters such as (.) (,) (-) (:). If you would like to make a booking with code VOF, please call us +46 8 517 517 20.Save your booking code for the next time you visit the page by ticking the box “Remember”. Don't tick the box if you're using a public computer to avoid unauthorized access to your booking code." + "value": "If you're booking a promotional offer or a Corporate negotiated rate you'll need a special booking code. Don't use any special characters such as (.) (,) (-) (:). If you would like to make a booking with code VOF, please call us +46 8 517 517 20. Save your booking code for the next time you visit the page by ticking the box “Remember”. Don't tick the box if you're using a public computer to avoid unauthorized access to your booking code." } ], "bookingWidget.button.search": [ @@ -1073,6 +1157,12 @@ "value": "A destination or hotel name is needed to be able to search for a hotel room." } ], + "bookingwidget.dropdown.children": [ + { + "type": 0, + "value": "Children (0–12 years)" + } + ], "breadcrumbs.label": [ { "type": 0, @@ -1995,6 +2085,42 @@ "value": "or" } ], + "common.orNumberOfPoints": [ + { + "type": 0, + "value": "or " + }, + { + "offset": 0, + "options": { + "one": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " point" + } + ] + }, + "other": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " points" + } + ] + } + }, + "pluralType": "cardinal", + "type": 6, + "value": "points" + } + ], "common.other": [ { "type": 0, @@ -2025,12 +2151,24 @@ "value": "Password" } ], + "common.paymentCard": [ + { + "type": 0, + "value": "Payment card" + } + ], "common.perAdultNight": [ { "type": 0, "value": "Per adult/night" } ], + "common.person": [ + { + "type": 0, + "value": "person" + } + ], "common.petFriendly": [ { "type": 0, @@ -2116,6 +2254,12 @@ "value": "Remove" } ], + "common.reviewAndConfirm": [ + { + "type": 0, + "value": "Review & Confirm" + } + ], "common.room": [ { "type": 0, @@ -4298,12 +4442,24 @@ "value": "count" } ], + "lightbox.nextImage": [ + { + "type": 0, + "value": "Next image" + } + ], "lightbox.openImage": [ { "type": 0, "value": "Open image" } ], + "lightbox.previousImage": [ + { + "type": 0, + "value": "Previous image" + } + ], "linkEmploymentError.alreadyLinkedHeading": [ { "type": 0, @@ -5623,6 +5779,30 @@ "value": "My membership cards" } ], + "myPages.myStay.ancillaries.insufficientPointsMessage": [ + { + "type": 0, + "value": "You don't have enough points for this item" + } + ], + "myPages.myStay.ancillaries.reachedMaxPointsMessage": [ + { + "type": 0, + "value": "You have reached your points limit." + } + ], + "myPages.myStay.ancillaries.reachedMaxPointsStepperMessage": [ + { + "type": 0, + "value": "You’ve reached your points limit and can’t add more items with points." + } + ], + "myPages.myStay.ancillaries.spendablePointsTitle": [ + { + "type": 0, + "value": "Your spendable points" + } + ], "myPages.nameWithCardMembershipType": [ { "type": 0, @@ -6609,6 +6789,82 @@ "value": " days" } ], + "nextStay.inXMonths": [ + { + "type": 0, + "value": "In " + }, + { + "offset": 0, + "options": { + "one": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " month" + } + ] + }, + "other": { + "value": [ + { + "type": 0, + "value": " " + }, + { + "type": 7 + }, + { + "type": 0, + "value": " months" + } + ] + } + }, + "pluralType": "cardinal", + "type": 6, + "value": "months" + } + ], + "nextStay.inXYears": [ + { + "type": 0, + "value": "In " + }, + { + "offset": 0, + "options": { + "one": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " year" + } + ] + }, + "other": { + "value": [ + { + "type": 7 + }, + { + "type": 0, + "value": " years" + } + ] + } + }, + "pluralType": "cardinal", + "type": 6, + "value": "years" + } + ], "nextStay.myStayAt": [ { "type": 0, @@ -7240,6 +7496,50 @@ "value": "expiryDate" } ], + "previousStays.nightsStayed": [ + { + "type": 0, + "value": "Nights stayed" + } + ], + "previousStays.progressAriaLabel": [ + { + "type": 1, + "value": "nightsStayed" + }, + { + "type": 0, + "value": " of " + }, + { + "type": 1, + "value": "maxNights" + }, + { + "type": 0, + "value": " nights stayed towards " + }, + { + "type": 1, + "value": "levelName" + } + ], + "previousStays.sinceDate": [ + { + "type": 0, + "value": "Since " + }, + { + "type": 1, + "value": "date" + } + ], + "previousStays.totalStays": [ + { + "type": 0, + "value": "Total stays" + } + ], "price.numberOfVouchers": [ { "offset": 0, @@ -7904,6 +8204,30 @@ "value": "Menus" } ], + "rewardNights.offerPrice": [ + { + "type": 0, + "value": "Offer price" + } + ], + "rewardNights.stayBetween:": [ + { + "type": 0, + "value": "Stay between:" + } + ], + "rewardNights.table.destination": [ + { + "type": 0, + "value": "Destination" + } + ], + "rewardNights.table.hotel": [ + { + "type": 0, + "value": "Hotel" + } + ], "rewards.active": [ { "type": 0, @@ -8423,7 +8747,7 @@ }, { "type": 0, - "value": "-" + "value": "–" }, { "type": 1, @@ -8899,6 +9223,18 @@ "value": "You have no upcoming stays at the moment" } ], + "stays.previous.title": [ + { + "type": 0, + "value": "Previous stays" + } + ], + "stays.upcoming.title": [ + { + "type": 0, + "value": "Upcoming stays" + } + ], "stays.whereToGoNext": [ { "type": 0, @@ -9042,6 +9378,30 @@ "value": "User not found" } ], + "videoPlayer.mute": [ + { + "type": 0, + "value": "Mute video" + } + ], + "videoPlayer.pause": [ + { + "type": 0, + "value": "Pause video" + } + ], + "videoPlayer.play": [ + { + "type": 0, + "value": "Play video" + } + ], + "videoPlayer.unmute": [ + { + "type": 0, + "value": "Unmute video" + } + ], "webview.genericUserError": [ { "type": 0, diff --git a/scripts/i18n/lokalise.ts b/scripts/i18n/lokalise.ts index cd5b0ca85..3af1c04cf 100644 --- a/scripts/i18n/lokalise.ts +++ b/scripts/i18n/lokalise.ts @@ -15,265 +15,259 @@ const lokaliseLogger = createLogger("lokalise"); let resolvePerf: (value?: unknown) => void; const performanceMetrics = new Promise((resolve) => { - resolvePerf = resolve; + resolvePerf = resolve; }); const perf = new PerformanceObserver((items) => { - const entries = items.getEntries(); - for (const entry of entries) { - if (entry.name === "done") { - // This is the last measure meant for clean up - performance.clearMarks(); - perf.disconnect(); - if (typeof resolvePerf === "function") { - resolvePerf(); - } - } else { - lokaliseLogger.info( - `[metrics] ${entry.name} completed in ${entry.duration} ms` - ); - } + const entries = items.getEntries(); + for (const entry of entries) { + if (entry.name === "done") { + // This is the last measure meant for clean up + performance.clearMarks(); + perf.disconnect(); + if (typeof resolvePerf === "function") { + resolvePerf(); + } + } else { + lokaliseLogger.info( + `[metrics] ${entry.name} completed in ${entry.duration} ms` + ); } - performance.clearMeasures(); + } + performance.clearMeasures(); }); async function waitUntilUploadDone(processId: string) { - return new Promise((resolve, reject) => { - const interval = setInterval(async () => { - try { - performance.mark("waitUntilUploadDoneStart"); + return new Promise((resolve, reject) => { + const interval = setInterval(async () => { + try { + performance.mark("waitUntilUploadDoneStart"); - lokaliseLogger.debug("Checking upload status..."); + lokaliseLogger.debug("Checking upload status..."); - performance.mark("getProcessStart"); - const process = await lokaliseApi - .queuedProcesses() - .get(processId, { - project_id: projectId, - }); - performance.mark("getProcessEnd"); - performance.measure( - "Get Queued Process", - "getProcessStart", - "getProcessEnd" - ); + performance.mark("getProcessStart"); + const process = await lokaliseApi.queuedProcesses().get(processId, { + project_id: projectId, + }); + performance.mark("getProcessEnd"); + performance.measure( + "Get Queued Process", + "getProcessStart", + "getProcessEnd" + ); - lokaliseLogger.debug(`Status: ${process.status}`); + lokaliseLogger.debug(`Status: ${process.status}`); - if (process.status === "finished") { - clearInterval(interval); - performance.mark("waitUntilUploadDoneEnd", { - detail: "success", - }); - performance.measure( - "Wait on upload", - "waitUntilUploadDoneStart", - "waitUntilUploadDoneEnd" - ); - resolve(); - } else if (process.status === "failed") { - throw process; - } - } catch (e) { - clearInterval(interval); - lokaliseLogger.error("An error occurred:", e); - performance.mark("waitUntilUploadDoneEnd", { detail: e }); - performance.measure( - "Wait on upload", - "waitUntilUploadDoneStart", - "waitUntilUploadDoneEnd" - ); - reject(); - } - }, 1000); - }); + if (process.status === "finished") { + clearInterval(interval); + performance.mark("waitUntilUploadDoneEnd", { + detail: "success", + }); + performance.measure( + "Wait on upload", + "waitUntilUploadDoneStart", + "waitUntilUploadDoneEnd" + ); + resolve(); + } else if (process.status === "failed") { + throw process; + } + } catch (e) { + clearInterval(interval); + lokaliseLogger.error("An error occurred:", e); + performance.mark("waitUntilUploadDoneEnd", { detail: e }); + performance.measure( + "Wait on upload", + "waitUntilUploadDoneStart", + "waitUntilUploadDoneEnd" + ); + reject(); + } + }, 1000); + }); } export async function upload(filepath: string) { - perf.observe({ type: "measure" }); + perf.observe({ type: "measure" }); - try { - lokaliseLogger.debug(`Uploading ${filepath}...`); + try { + lokaliseLogger.debug(`Uploading ${filepath}...`); - performance.mark("uploadStart"); + performance.mark("uploadStart"); - performance.mark("sourceFileReadStart"); - const data = await fs.readFile(filepath, "utf8"); - const buff = Buffer.from(data, "utf8"); - const base64 = buff.toString("base64"); - performance.mark("sourceFileReadEnd"); - performance.measure( - "Read source file", - "sourceFileReadStart", - "sourceFileReadEnd" - ); + performance.mark("sourceFileReadStart"); + const data = await fs.readFile(filepath, "utf8"); + const buff = Buffer.from(data, "utf8"); + const base64 = buff.toString("base64"); + performance.mark("sourceFileReadEnd"); + performance.measure( + "Read source file", + "sourceFileReadStart", + "sourceFileReadEnd" + ); - performance.mark("lokaliseUploadInitStart"); - const bgProcess = await lokaliseApi.files().upload(projectId, { - data: base64, - filename: "en.json", - lang_iso: "en", - detect_icu_plurals: true, - format: "json", - convert_placeholders: true, - replace_modified: false, - }); - performance.mark("lokaliseUploadInitEnd"); - performance.measure( - "Upload init", - "lokaliseUploadInitStart", - "lokaliseUploadInitEnd" - ); + performance.mark("lokaliseUploadInitStart"); + const bgProcess = await lokaliseApi.files().upload(projectId, { + data: base64, + filename: "en.json", + lang_iso: "en", + detect_icu_plurals: true, + format: "json", + convert_placeholders: true, + replace_modified: false, + }); + performance.mark("lokaliseUploadInitEnd"); + performance.measure( + "Upload init", + "lokaliseUploadInitStart", + "lokaliseUploadInitEnd" + ); - performance.mark("lokaliseUploadStart"); - await waitUntilUploadDone(bgProcess.process_id); - performance.mark("lokaliseUploadEnd"); - performance.measure( - "Upload transfer", - "lokaliseUploadStart", - "lokaliseUploadEnd" - ); + performance.mark("lokaliseUploadStart"); + await waitUntilUploadDone(bgProcess.process_id); + performance.mark("lokaliseUploadEnd"); + performance.measure( + "Upload transfer", + "lokaliseUploadStart", + "lokaliseUploadEnd" + ); - lokaliseLogger.debug("Upload successful"); - } catch (e) { - lokaliseLogger.error("Upload failed", e); - } finally { - performance.mark("uploadEnd"); + lokaliseLogger.debug("Upload successful"); + } catch (e) { + lokaliseLogger.error("Upload failed", e); + } finally { + performance.mark("uploadEnd"); - performance.measure("Upload operation", "uploadStart", "uploadEnd"); - } + performance.measure("Upload operation", "uploadStart", "uploadEnd"); + } - performance.measure("done"); + performance.measure("done"); - await performanceMetrics; + await performanceMetrics; } export async function download(extractPath: string, all: boolean = false) { - perf.observe({ type: "measure" }); + perf.observe({ type: "measure" }); - try { - lokaliseLogger.debug( - all - ? "Downloading all translations..." - : "Downloading filtered translations..." - ); + try { + lokaliseLogger.debug( + all + ? "Downloading all translations..." + : "Downloading filtered translations..." + ); - performance.mark("downloadStart"); + performance.mark("downloadStart"); - performance.mark("lokaliseDownloadInitStart"); - const downloadResponse = await lokaliseApi.files().download(projectId, { - format: "json_structured", - indentation: "2sp", - placeholder_format: "icu", - plural_format: "icu", - icu_numeric: false, - bundle_structure: "%LANG_ISO%.%FORMAT%", - directory_prefix: "", - filter_data: all ? [] : ["translated", "nonhidden"], - export_empty_as: "skip", - }); + performance.mark("lokaliseDownloadInitStart"); + const downloadResponse = await lokaliseApi.files().download(projectId, { + format: "json_structured", + indentation: "2sp", + placeholder_format: "icu", + plural_format: "icu", + icu_numeric: false, + bundle_structure: "%LANG_ISO%.%FORMAT%", + directory_prefix: "", + filter_data: all ? [] : ["translated", "nonhidden"], + export_empty_as: "skip", + }); - performance.mark("lokaliseDownloadInitEnd"); - performance.measure( - "Download init", - "lokaliseDownloadInitStart", - "lokaliseDownloadInitEnd" - ); + performance.mark("lokaliseDownloadInitEnd"); + performance.measure( + "Download init", + "lokaliseDownloadInitStart", + "lokaliseDownloadInitEnd" + ); - const { bundle_url } = downloadResponse; + const { bundle_url } = downloadResponse; - performance.mark("lokaliseDownloadStart"); - const bundleResponse = await fetch(bundle_url); - performance.mark("lokaliseDownloadEnd"); - performance.measure( - "Download transfer", - "lokaliseDownloadStart", - "lokaliseDownloadEnd" - ); + performance.mark("lokaliseDownloadStart"); + const bundleResponse = await fetch(bundle_url); + performance.mark("lokaliseDownloadEnd"); + performance.measure( + "Download transfer", + "lokaliseDownloadStart", + "lokaliseDownloadEnd" + ); - if (bundleResponse.ok) { - performance.mark("unpackTranslationsStart"); - const arrayBuffer = await bundleResponse.arrayBuffer(); - const buffer = Buffer.from(new Uint8Array(arrayBuffer)); - const zip = new AdmZip(buffer); - zip.extractAllTo(extractPath, true); - performance.mark("unpackTranslationsEnd"); - performance.measure( - "Unpacking translations", - "unpackTranslationsStart", - "unpackTranslationsEnd" - ); + if (bundleResponse.ok) { + performance.mark("unpackTranslationsStart"); + const arrayBuffer = await bundleResponse.arrayBuffer(); + const buffer = Buffer.from(new Uint8Array(arrayBuffer)); + const zip = new AdmZip(buffer); + zip.extractAllTo(extractPath, true); + performance.mark("unpackTranslationsEnd"); + performance.measure( + "Unpacking translations", + "unpackTranslationsStart", + "unpackTranslationsEnd" + ); - lokaliseLogger.debug("Download successful"); - } else { - throw bundleResponse; - } - } catch (e) { - lokaliseLogger.error("Download failed", e); - } finally { - performance.mark("downloadEnd"); - - performance.measure( - "Download operation", - "downloadStart", - "downloadEnd" - ); + lokaliseLogger.debug("Download successful"); + } else { + throw bundleResponse; } + } catch (e) { + lokaliseLogger.error("Download failed", e); + } finally { + performance.mark("downloadEnd"); - performance.measure("done"); + performance.measure("Download operation", "downloadStart", "downloadEnd"); + } - await performanceMetrics; + performance.measure("done"); + + await performanceMetrics; } export async function deleteBulk(keyNames: string[]) { - perf.observe({ type: "measure" }); + perf.observe({ type: "measure" }); - try { - performance.mark("bulkDeleteStart"); + try { + performance.mark("bulkDeleteStart"); - let keysToDelete: number[] = []; - let cursor: string | undefined = undefined; - let hasNext = true; - do { - const keys = await lokaliseApi.keys().list({ - project_id: projectId, - limit: 100, - pagination: "cursor", - cursor, - }); + let keysToDelete: number[] = []; + let cursor: string | undefined = undefined; + let hasNext = true; + do { + const keys = await lokaliseApi.keys().list({ + project_id: projectId, + limit: 100, + pagination: "cursor", + cursor, + }); - cursor = keys.nextCursor ?? undefined; - keys.items.forEach((key) => { - if (key.key_id && key.key_name.web) { - if (keyNames.includes(key.key_name.web)) { - keysToDelete.push(key.key_id); - } - } - }); + cursor = keys.nextCursor ?? undefined; + keys.items.forEach((key) => { + if (key.key_id && key.key_name.web) { + if (keyNames.includes(key.key_name.web)) { + keysToDelete.push(key.key_id); + } + } + }); - if (!keys.hasNextCursor()) { - hasNext = false; - } - } while (hasNext); + if (!keys.hasNextCursor()) { + hasNext = false; + } + } while (hasNext); - const response = await lokaliseApi - .keys() - .bulk_delete(keysToDelete, { project_id: projectId }); + const response = await lokaliseApi + .keys() + .bulk_delete(keysToDelete, { project_id: projectId }); - lokaliseLogger.debug( - `Bulk delete successful, removed ${keysToDelete.length} keys` - ); + lokaliseLogger.debug( + `Bulk delete successful, removed ${keysToDelete.length} keys` + ); - return response; - } catch (e) { - lokaliseLogger.error("Bulk delete failed", e); - } finally { - performance.mark("bulkDeleteEnd"); + return response; + } catch (e) { + lokaliseLogger.error("Bulk delete failed", e); + } finally { + performance.mark("bulkDeleteEnd"); - performance.measure( - "Bulk delete operation", - "bulkDeleteStart", - "bulkDeleteEnd" - ); - } + performance.measure( + "Bulk delete operation", + "bulkDeleteStart", + "bulkDeleteEnd" + ); + } }