Compare commits

...

5 Commits

Author SHA1 Message Date
review-agent-prime[bot] 3768055a6a Edit packages/lib/i18n/utils.ts 2024-03-20 07:23:35 +00:00
Dhruwang 74a21f03f2 tweaks 2024-03-20 12:48:31 +05:30
Dhruwang c148e3bd74 added data-migration2 2024-03-20 11:48:39 +05:30
Dhruwang f27f55a655 fix: validation and tweaks 2024-03-19 18:59:12 +05:30
Dhruwang d7237b81da fix: translate survey function 2024-03-19 18:00:51 +05:30
7 changed files with 409 additions and 254 deletions
@@ -237,7 +237,7 @@ export default function MultipleChoiceMultiForm({
{question.choices && {question.choices &&
question.choices.map((choice, choiceIdx) => ( question.choices.map((choice, choiceIdx) => (
<div key={choiceIdx} className="inline-flex w-full items-center"> <div key={choiceIdx} className="inline-flex w-full items-center">
<div className="w-full space-x-2"> <div className="flex w-full space-x-2">
<QuestionFormInput <QuestionFormInput
key={choice.id} key={choice.id}
id={`choice-${choiceIdx}`} id={`choice-${choiceIdx}`}
@@ -63,7 +63,7 @@ const validationRules = {
]; ];
for (const field of fieldsToValidate) { for (const field of fieldsToValidate) {
if (question[field] && question[field][defaultLanguageCode]) { if (question[field] && typeof question[field][defaultLanguageCode] !== "undefined") {
isValid = isValid =
isValid && isLabelValidForAllLanguages(question[field], languages) && isValidCTADismissLabel; isValid && isLabelValidForAllLanguages(question[field], languages) && isValidCTADismissLabel;
} }
@@ -0,0 +1,49 @@
// migration script to translate surveys where thankYouCard buttonLabel is a string or question subheaders are strings
import { PrismaClient } from "@prisma/client";
import { hasStringSubheaders, translateSurvey } from "./lib/i18n";
const prisma = new PrismaClient();
async function main() {
await prisma.$transaction(
async (tx) => {
// Translate Surveys
const surveys = await tx.survey.findMany({
select: {
id: true,
questions: true,
thankYouCard: true,
welcomeCard: true,
},
});
if (!surveys) {
// stop the migration if there are no surveys
return;
}
for (const survey of surveys) {
if (typeof survey.thankYouCard.buttonLabel === "string" || hasStringSubheaders(survey.questions)) {
const translatedSurvey = translateSurvey(survey, []);
// Save the translated survey
await tx.survey.update({
where: { id: survey.id },
data: { ...translatedSurvey },
});
}
}
},
{
timeout: 50000,
}
);
}
main()
.catch(async (e) => {
console.error(e);
process.exit(1);
})
.finally(async () => await prisma.$disconnect());
@@ -1,13 +1,35 @@
import {
TLegacySurveyChoice,
TLegacySurveyQuestion,
TLegacySurveyThankYouCard,
TLegacySurveyWelcomeCard,
} from "@formbricks/types/LegacySurvey";
import { TLanguage } from "@formbricks/types/product"; import { TLanguage } from "@formbricks/types/product";
import { import {
TI18nString, TI18nString,
TSurveyCTAQuestion, TSurveyCTAQuestion,
TSurveyChoice,
TSurveyConsentQuestion, TSurveyConsentQuestion,
TSurveyMultipleChoiceSingleQuestion,
TSurveyNPSQuestion, TSurveyNPSQuestion,
TSurveyOpenTextQuestion, TSurveyOpenTextQuestion,
TSurveyQuestions,
TSurveyRatingQuestion, TSurveyRatingQuestion,
TSurveyThankYouCard, TSurveyThankYouCard,
TSurveyWelcomeCard, TSurveyWelcomeCard,
ZSurveyCTAQuestion,
ZSurveyCalQuestion,
ZSurveyConsentQuestion,
ZSurveyFileUploadQuestion,
ZSurveyMultipleChoiceMultiQuestion,
ZSurveyMultipleChoiceSingleQuestion,
ZSurveyNPSQuestion,
ZSurveyOpenTextQuestion,
ZSurveyPictureSelectionQuestion,
ZSurveyQuestion,
ZSurveyRatingQuestion,
ZSurveyThankYouCard,
ZSurveyWelcomeCard,
} from "@formbricks/types/surveys"; } from "@formbricks/types/surveys";
import { TSurvey, TSurveyMultipleChoiceMultiQuestion, TSurveyQuestion } from "@formbricks/types/surveys"; import { TSurvey, TSurveyMultipleChoiceMultiQuestion, TSurveyQuestion } from "@formbricks/types/surveys";
@@ -49,120 +71,176 @@ export const createI18nString = (text: string | TI18nString, languages: string[]
}; };
// Function to translate a choice label // Function to translate a choice label
const translateChoice = (choice: any, languages: string[]) => { const translateChoice = (choice: TSurveyChoice | TLegacySurveyChoice, languages: string[]): TSurveyChoice => {
// Assuming choice is a simple object and choice.label is a string. if (typeof choice.label === "string") {
return { return {
...choice, ...choice,
label: createI18nString(choice.label, languages), label: createI18nString(choice.label, languages),
}; };
} else {
return {
...choice,
label: choice.label,
};
}
}; };
export const translateWelcomeCard = ( export const translateWelcomeCard = (
welcomeCard: TSurveyWelcomeCard, welcomeCard: TSurveyWelcomeCard | TLegacySurveyWelcomeCard,
languages: string[] languages: string[]
): TSurveyWelcomeCard => { ): TSurveyWelcomeCard => {
const clonedWelcomeCard = structuredClone(welcomeCard); const clonedWelcomeCard = structuredClone(welcomeCard);
clonedWelcomeCard.headline = createI18nString(welcomeCard.headline, languages); if (typeof welcomeCard.headline === "string") {
clonedWelcomeCard.html = createI18nString(welcomeCard.html ?? "", languages); clonedWelcomeCard.headline = createI18nString(welcomeCard.headline ?? "", languages);
if (clonedWelcomeCard.buttonLabel) { }
clonedWelcomeCard.buttonLabel = createI18nString(clonedWelcomeCard.buttonLabel, languages); if (typeof welcomeCard.html === "string") {
clonedWelcomeCard.html = createI18nString(welcomeCard.html ?? "", languages);
}
if (typeof welcomeCard.buttonLabel === "string") {
clonedWelcomeCard.buttonLabel = createI18nString(clonedWelcomeCard.buttonLabel ?? "", languages);
} }
return clonedWelcomeCard; return ZSurveyWelcomeCard.parse(clonedWelcomeCard);
}; };
const translateThankYouCard = ( const translateThankYouCard = (
thankYouCard: TSurveyThankYouCard, thankYouCard: TSurveyThankYouCard | TLegacySurveyThankYouCard,
languages: string[] languages: string[]
): TSurveyThankYouCard => { ): TSurveyThankYouCard => {
const clonedThankYouCard = structuredClone(thankYouCard); const clonedThankYouCard = structuredClone(thankYouCard);
clonedThankYouCard.headline = createI18nString(
thankYouCard.headline ? thankYouCard.headline : "", if (typeof thankYouCard.headline === "string") {
languages clonedThankYouCard.headline = createI18nString(thankYouCard.headline ?? "", languages);
);
if (clonedThankYouCard.subheader) {
clonedThankYouCard.subheader = createI18nString(
thankYouCard.subheader ? thankYouCard.subheader : "",
languages
);
} }
return clonedThankYouCard; if (typeof thankYouCard.subheader === "string") {
clonedThankYouCard.subheader = createI18nString(thankYouCard.subheader ?? "", languages);
}
if (typeof clonedThankYouCard.buttonLabel === "string") {
clonedThankYouCard.buttonLabel = createI18nString(thankYouCard.buttonLabel ?? "", languages);
}
return ZSurveyThankYouCard.parse(clonedThankYouCard);
}; };
// Function that will translate a single question // Function that will translate a single question
const translateQuestion = (question: TSurveyQuestion, languages: string[]) => { const translateQuestion = (
question: TLegacySurveyQuestion | TSurveyQuestion,
languages: string[]
): TSurveyQuestion => {
// Clone the question to avoid mutating the original // Clone the question to avoid mutating the original
const clonedQuestion = structuredClone(question); const clonedQuestion = structuredClone(question);
clonedQuestion.headline = createI18nString(question.headline, languages); //common question properties
if (clonedQuestion.subheader) { if (typeof question.headline === "string") {
clonedQuestion.headline = createI18nString(question.headline ?? "", languages);
}
if (typeof question.subheader === "string") {
clonedQuestion.subheader = createI18nString(question.subheader ?? "", languages); clonedQuestion.subheader = createI18nString(question.subheader ?? "", languages);
} }
if (clonedQuestion.buttonLabel) { if (typeof question.buttonLabel === "string") {
clonedQuestion.buttonLabel = createI18nString(question.buttonLabel ?? "", languages); clonedQuestion.buttonLabel = createI18nString(question.buttonLabel ?? "", languages);
} }
if (clonedQuestion.backButtonLabel) { if (typeof question.backButtonLabel === "string") {
clonedQuestion.backButtonLabel = createI18nString(question.backButtonLabel ?? "", languages); clonedQuestion.backButtonLabel = createI18nString(question.backButtonLabel ?? "", languages);
} }
if (question.type === "multipleChoiceSingle" || question.type === "multipleChoiceMulti") { switch (question.type) {
(clonedQuestion as TSurveyMultipleChoiceMultiQuestion | TSurveyMultipleChoiceMultiQuestion).choices = case "openText":
question.choices.map((choice) => translateChoice(structuredClone(choice), languages)); if (typeof question.placeholder === "string") {
( (clonedQuestion as TSurveyOpenTextQuestion).placeholder = createI18nString(
clonedQuestion as TSurveyMultipleChoiceMultiQuestion | TSurveyMultipleChoiceMultiQuestion question.placeholder ?? "",
).otherOptionPlaceholder = question.otherOptionPlaceholder languages
? createI18nString(question.otherOptionPlaceholder, languages) );
: undefined; }
} return ZSurveyOpenTextQuestion.parse(clonedQuestion);
if (question.type === "openText") {
(clonedQuestion as TSurveyOpenTextQuestion).placeholder = createI18nString(
question.placeholder ?? "",
languages
);
}
if (question.type === "cta") {
if (question.dismissButtonLabel) {
(clonedQuestion as TSurveyCTAQuestion).dismissButtonLabel = createI18nString(
question.dismissButtonLabel,
languages
);
}
if (question.html) {
(clonedQuestion as TSurveyCTAQuestion).html = createI18nString(question.html, languages);
}
}
if (question.type === "consent") {
if (question.html) {
(clonedQuestion as TSurveyConsentQuestion).html = createI18nString(question.html, languages);
}
if (question.label) { case "multipleChoiceSingle":
(clonedQuestion as TSurveyConsentQuestion).label = createI18nString(question.label, languages); case "multipleChoiceMulti":
} (clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion).choices =
question.choices.map((choice) => {
return translateChoice(choice, languages);
});
if (
typeof (clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion)
.otherOptionPlaceholder === "string"
) {
(
clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion
).otherOptionPlaceholder = createI18nString(question.otherOptionPlaceholder ?? "", languages);
}
if (question.type === "multipleChoiceSingle") {
return ZSurveyMultipleChoiceSingleQuestion.parse(clonedQuestion);
} else return ZSurveyMultipleChoiceMultiQuestion.parse(clonedQuestion);
case "cta":
if (typeof question.dismissButtonLabel === "string") {
(clonedQuestion as TSurveyCTAQuestion).dismissButtonLabel = createI18nString(
question.dismissButtonLabel ?? "",
languages
);
}
if (typeof question.html === "string") {
(clonedQuestion as TSurveyCTAQuestion).html = createI18nString(question.html ?? "", languages);
}
return ZSurveyCTAQuestion.parse(clonedQuestion);
case "consent":
if (typeof question.html === "string") {
(clonedQuestion as TSurveyConsentQuestion).html = createI18nString(question.html ?? "", languages);
}
if (typeof question.label === "string") {
(clonedQuestion as TSurveyConsentQuestion).label = createI18nString(question.label ?? "", languages);
}
return ZSurveyConsentQuestion.parse(clonedQuestion);
case "nps":
if (typeof question.lowerLabel === "string") {
(clonedQuestion as TSurveyNPSQuestion).lowerLabel = createI18nString(
question.lowerLabel ?? "",
languages
);
}
if (typeof question.upperLabel === "string") {
(clonedQuestion as TSurveyNPSQuestion).upperLabel = createI18nString(
question.upperLabel ?? "",
languages
);
}
return ZSurveyNPSQuestion.parse(clonedQuestion);
case "rating":
if (typeof question.lowerLabel === "string") {
(clonedQuestion as TSurveyRatingQuestion).lowerLabel = createI18nString(
question.lowerLabel ?? "",
languages
);
}
if (typeof question.upperLabel === "string") {
(clonedQuestion as TSurveyRatingQuestion).upperLabel = createI18nString(
question.upperLabel ?? "",
languages
);
}
return ZSurveyRatingQuestion.parse(clonedQuestion);
case "fileUpload":
return ZSurveyFileUploadQuestion.parse(clonedQuestion);
case "pictureSelection":
return ZSurveyPictureSelectionQuestion.parse(clonedQuestion);
case "cal":
return ZSurveyCalQuestion.parse(clonedQuestion);
default:
return ZSurveyQuestion.parse(clonedQuestion);
} }
if (question.type === "nps") {
(clonedQuestion as TSurveyNPSQuestion).lowerLabel = createI18nString(
question.lowerLabel ?? "",
languages
);
(clonedQuestion as TSurveyNPSQuestion).upperLabel = createI18nString(
question.upperLabel ?? "",
languages
);
}
if (question.type === "rating") {
(clonedQuestion as TSurveyRatingQuestion).lowerLabel = createI18nString(
question.lowerLabel ?? "",
languages
);
(clonedQuestion as TSurveyRatingQuestion).upperLabel = createI18nString(
question.upperLabel ?? "",
languages
);
}
return clonedQuestion;
}; };
export const extractLanguageIds = (languages: TLanguage[]): string[] => { export const extractLanguageIds = (languages: TLanguage[]): string[] => {
@@ -188,3 +266,12 @@ export const translateSurvey = (
thankYouCard: translatedThankYouCard, thankYouCard: translatedThankYouCard,
}; };
}; };
export const hasStringSubheaders = (questions: TSurveyQuestions): boolean => {
for (const question of questions) {
if (typeof question.subheader === "string") {
return true;
}
}
return false;
};
+2 -1
View File
@@ -24,7 +24,8 @@
"post-install": "pnpm generate", "post-install": "pnpm generate",
"predev": "pnpm generate", "predev": "pnpm generate",
"data-migration:v1.6": "ts-node ./migrations/20240207041922_advanced_targeting/data-migration.ts", "data-migration:v1.6": "ts-node ./migrations/20240207041922_advanced_targeting/data-migration.ts",
"data-migration:mls": "ts-node ./migrations/20240318050527_add_languages_and_survey_languages/data-migration.ts" "data-migration:mls": "ts-node ./migrations/20240318050527_add_languages_and_survey_languages/data-migration.ts",
"data-migration2:mls": "ts-node ./migrations/20240318050527_add_languages_and_survey_languages/data-migration2.ts"
}, },
"dependencies": { "dependencies": {
"@prisma/client": "^5.11.0", "@prisma/client": "^5.11.0",
+187 -144
View File
@@ -1,16 +1,40 @@
import {
TLegacySurveyChoice,
TLegacySurveyQuestion,
TLegacySurveyThankYouCard,
TLegacySurveyWelcomeCard,
} from "@formbricks/types/LegacySurvey";
import { TLanguage } from "@formbricks/types/product";
import { import {
TI18nString, TI18nString,
TSurvey,
TSurveyCTAQuestion, TSurveyCTAQuestion,
TSurveyChoice,
TSurveyConsentQuestion, TSurveyConsentQuestion,
TSurveyLanguage, TSurveyMultipleChoiceSingleQuestion,
TSurveyMultipleChoiceMultiQuestion,
TSurveyNPSQuestion, TSurveyNPSQuestion,
TSurveyOpenTextQuestion, TSurveyOpenTextQuestion,
TSurveyQuestion,
TSurveyRatingQuestion, TSurveyRatingQuestion,
TSurveyThankYouCard, TSurveyThankYouCard,
TSurveyWelcomeCard, TSurveyWelcomeCard,
ZSurveyCTAQuestion,
ZSurveyCalQuestion,
ZSurveyConsentQuestion,
ZSurveyFileUploadQuestion,
ZSurveyMultipleChoiceMultiQuestion,
ZSurveyMultipleChoiceSingleQuestion,
ZSurveyNPSQuestion,
ZSurveyOpenTextQuestion,
ZSurveyPictureSelectionQuestion,
ZSurveyQuestion,
ZSurveyRatingQuestion,
ZSurveyThankYouCard,
ZSurveyWelcomeCard,
} from "@formbricks/types/surveys";
import {
TSurvey,
TSurveyLanguage,
TSurveyMultipleChoiceMultiQuestion,
TSurveyQuestion,
} from "@formbricks/types/surveys"; } from "@formbricks/types/surveys";
// Helper function to create an i18nString from a regular string. // Helper function to create an i18nString from a regular string.
@@ -92,180 +116,199 @@ export const getEnabledLanguages = (surveyLanguages: TSurveyLanguage[]) => {
return surveyLanguages.filter((surveyLanguage) => surveyLanguage.enabled); return surveyLanguages.filter((surveyLanguage) => surveyLanguage.enabled);
}; };
// LGEGACY const translateChoice = (choice: TSurveyChoice | TLegacySurveyChoice, languages: string[]): TSurveyChoice => {
// Helper function to maintain backwards compatibility for old survey objects before Multi Language if (typeof choice.label === "string") {
export const translateWelcomeCard = ( return {
welcomeCard: TSurveyWelcomeCard, ...choice,
languages: string[], label: createI18nString(choice.label, languages),
targetLanguageCode?: string };
): TSurveyWelcomeCard => { } else {
const clonedWelcomeCard = structuredClone(welcomeCard); return {
if (welcomeCard.headline) { ...choice,
clonedWelcomeCard.headline = createI18nString(welcomeCard.headline, languages, targetLanguageCode); label: choice.label,
};
} }
if (welcomeCard.html) {
clonedWelcomeCard.html = createI18nString(welcomeCard.html, languages, targetLanguageCode);
}
if (clonedWelcomeCard.buttonLabel) {
clonedWelcomeCard.buttonLabel = createI18nString(
clonedWelcomeCard.buttonLabel,
languages,
targetLanguageCode
);
}
return clonedWelcomeCard;
}; };
// LGEGACY // LGEGACY
// Helper function to maintain backwards compatibility for old survey objects before Multi Language // Helper function to maintain backwards compatibility for old survey objects before Multi Language
export const translateThankYouCard = ( export const translateWelcomeCard = (
thankYouCard: TSurveyThankYouCard, welcomeCard: TSurveyWelcomeCard | TLegacySurveyWelcomeCard,
languages: string[], languages: string[]
targetLanguageCode?: string ): TSurveyWelcomeCard => {
): TSurveyThankYouCard => { const clonedWelcomeCard = structuredClone(welcomeCard);
const clonedThankYouCard = structuredClone(thankYouCard); if (typeof welcomeCard.headline === "string") {
if (thankYouCard.headline) { clonedWelcomeCard.headline = createI18nString(welcomeCard.headline ?? "", languages);
clonedThankYouCard.headline = createI18nString(thankYouCard.headline, languages, targetLanguageCode);
} }
if (thankYouCard.subheader) { if (typeof welcomeCard.html === "string") {
clonedThankYouCard.subheader = createI18nString(thankYouCard.subheader, languages, targetLanguageCode); clonedWelcomeCard.html = createI18nString(welcomeCard.html ?? "", languages);
} }
if (thankYouCard.buttonLabel) { if (typeof welcomeCard.buttonLabel === "string") {
clonedThankYouCard.buttonLabel = createI18nString( clonedWelcomeCard.buttonLabel = createI18nString(clonedWelcomeCard.buttonLabel ?? "", languages);
thankYouCard.buttonLabel,
languages,
targetLanguageCode
);
} }
return clonedThankYouCard; return ZSurveyWelcomeCard.parse(clonedWelcomeCard);
};
// LGEGACY
// Helper function to maintain backwards compatibility for old survey objects before Multi Language
const translateThankYouCard = (
thankYouCard: TSurveyThankYouCard | TLegacySurveyThankYouCard,
languages: string[]
): TSurveyThankYouCard => {
const clonedThankYouCard = structuredClone(thankYouCard);
if (typeof thankYouCard.headline === "string") {
clonedThankYouCard.headline = createI18nString(thankYouCard.headline ?? "", languages);
}
if (typeof thankYouCard.subheader === "string") {
clonedThankYouCard.subheader = createI18nString(thankYouCard.subheader ?? "", languages);
}
if (typeof clonedThankYouCard.buttonLabel === "string") {
clonedThankYouCard.buttonLabel = createI18nString(thankYouCard.buttonLabel ?? "", languages);
}
return ZSurveyThankYouCard.parse(clonedThankYouCard);
}; };
// LGEGACY // LGEGACY
// Helper function to maintain backwards compatibility for old survey objects before Multi Language // Helper function to maintain backwards compatibility for old survey objects before Multi Language
export const translateQuestion = ( export const translateQuestion = (
question: TSurveyQuestion, question: TLegacySurveyQuestion | TSurveyQuestion,
languages: string[], languages: string[]
targetLanguageCode?: string ): TSurveyQuestion => {
) => {
// Clone the question to avoid mutating the original // Clone the question to avoid mutating the original
const clonedQuestion = structuredClone(question); const clonedQuestion = structuredClone(question);
clonedQuestion.headline = createI18nString(question.headline, languages, targetLanguageCode); //common question properties
if (clonedQuestion.subheader) { if (typeof question.headline === "string") {
clonedQuestion.subheader = createI18nString(question.subheader ?? "", languages, targetLanguageCode); clonedQuestion.headline = createI18nString(question.headline ?? "", languages);
} }
if (clonedQuestion.buttonLabel) { if (typeof question.subheader === "string") {
clonedQuestion.buttonLabel = createI18nString(question.buttonLabel ?? "", languages, targetLanguageCode); clonedQuestion.subheader = createI18nString(question.subheader ?? "", languages);
} }
if (clonedQuestion.backButtonLabel) { if (typeof question.buttonLabel === "string") {
clonedQuestion.backButtonLabel = createI18nString( clonedQuestion.buttonLabel = createI18nString(question.buttonLabel ?? "", languages);
question.backButtonLabel ?? "",
languages,
targetLanguageCode
);
} }
if (question.type === "multipleChoiceSingle" || question.type === "multipleChoiceMulti") { if (typeof question.backButtonLabel === "string") {
(clonedQuestion as TSurveyMultipleChoiceMultiQuestion | TSurveyMultipleChoiceMultiQuestion).choices = clonedQuestion.backButtonLabel = createI18nString(question.backButtonLabel ?? "", languages);
question.choices.map((choice) => ({
...choice,
label: createI18nString(choice.label, languages, targetLanguageCode),
}));
(
clonedQuestion as TSurveyMultipleChoiceMultiQuestion | TSurveyMultipleChoiceMultiQuestion
).otherOptionPlaceholder = question.otherOptionPlaceholder
? createI18nString(question.otherOptionPlaceholder, languages, targetLanguageCode)
: undefined;
} }
if (question.type === "openText") {
if (question.placeholder) {
(clonedQuestion as TSurveyOpenTextQuestion).placeholder = createI18nString(
question.placeholder,
languages,
targetLanguageCode
);
}
}
if (question.type === "cta") {
if (question.dismissButtonLabel) {
(clonedQuestion as TSurveyCTAQuestion).dismissButtonLabel = createI18nString(
question.dismissButtonLabel,
languages,
targetLanguageCode
);
}
if (question.html) {
(clonedQuestion as TSurveyCTAQuestion).html = createI18nString(
question.html,
languages,
targetLanguageCode
);
}
}
if (question.type === "consent") {
if (question.html) {
(clonedQuestion as TSurveyConsentQuestion).html = createI18nString(
question.html,
languages,
targetLanguageCode
);
}
if (question.label) { const questionTypeHandlers = {
(clonedQuestion as TSurveyConsentQuestion).label = createI18nString( "openText": handleOpenTextQuestion,
question.label, "multipleChoiceSingle": handleMultipleChoiceSingleQuestion,
languages, "multipleChoiceMulti": handleMultipleChoiceMultiQuestion,
targetLanguageCode // ...
); };
}
const handler = questionTypeHandlers[question.type];
if (handler) {
return handler(question, languages);
} }
if (question.type === "nps") { }
(clonedQuestion as TSurveyNPSQuestion).lowerLabel = createI18nString( (clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion).choices =
question.lowerLabel ?? "", question.choices.map((choice) => {
languages, return translateChoice(choice, languages);
targetLanguageCode });
); if (
(clonedQuestion as TSurveyNPSQuestion).upperLabel = createI18nString( typeof (clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion)
question.upperLabel ?? "", .otherOptionPlaceholder === "string"
languages, ) {
targetLanguageCode (
); clonedQuestion as TSurveyMultipleChoiceSingleQuestion | TSurveyMultipleChoiceMultiQuestion
).otherOptionPlaceholder = createI18nString(question.otherOptionPlaceholder ?? "", languages);
}
if (question.type === "multipleChoiceSingle") {
return ZSurveyMultipleChoiceSingleQuestion.parse(clonedQuestion);
} else return ZSurveyMultipleChoiceMultiQuestion.parse(clonedQuestion);
case "cta":
if (typeof question.dismissButtonLabel === "string") {
(clonedQuestion as TSurveyCTAQuestion).dismissButtonLabel = createI18nString(
question.dismissButtonLabel ?? "",
languages
);
}
if (typeof question.html === "string") {
(clonedQuestion as TSurveyCTAQuestion).html = createI18nString(question.html ?? "", languages);
}
return ZSurveyCTAQuestion.parse(clonedQuestion);
case "consent":
if (typeof question.html === "string") {
(clonedQuestion as TSurveyConsentQuestion).html = createI18nString(question.html ?? "", languages);
}
if (typeof question.label === "string") {
(clonedQuestion as TSurveyConsentQuestion).label = createI18nString(question.label ?? "", languages);
}
return ZSurveyConsentQuestion.parse(clonedQuestion);
case "nps":
if (typeof question.lowerLabel === "string") {
(clonedQuestion as TSurveyNPSQuestion).lowerLabel = createI18nString(
question.lowerLabel ?? "",
languages
);
}
if (typeof question.upperLabel === "string") {
(clonedQuestion as TSurveyNPSQuestion).upperLabel = createI18nString(
question.upperLabel ?? "",
languages
);
}
return ZSurveyNPSQuestion.parse(clonedQuestion);
case "rating":
if (typeof question.lowerLabel === "string") {
(clonedQuestion as TSurveyRatingQuestion).lowerLabel = createI18nString(
question.lowerLabel ?? "",
languages
);
}
if (typeof question.upperLabel === "string") {
(clonedQuestion as TSurveyRatingQuestion).upperLabel = createI18nString(
question.upperLabel ?? "",
languages
);
}
return ZSurveyRatingQuestion.parse(clonedQuestion);
case "fileUpload":
return ZSurveyFileUploadQuestion.parse(clonedQuestion);
case "pictureSelection":
return ZSurveyPictureSelectionQuestion.parse(clonedQuestion);
case "cal":
return ZSurveyCalQuestion.parse(clonedQuestion);
default:
return ZSurveyQuestion.parse(clonedQuestion);
} }
if (question.type === "rating") { };
(clonedQuestion as TSurveyRatingQuestion).lowerLabel = createI18nString(
question.lowerLabel ?? "", export const extractLanguageIds = (languages: TLanguage[]): string[] => {
languages, return languages.map((language) => language.id);
targetLanguageCode
);
(clonedQuestion as TSurveyRatingQuestion).upperLabel = createI18nString(
question.upperLabel ?? "",
languages,
targetLanguageCode
);
}
return clonedQuestion;
}; };
// LGEGACY // LGEGACY
// Helper function to maintain backwards compatibility for old survey objects before Multi Language // Helper function to maintain backwards compatibility for old survey objects before Multi Language
export const translateSurvey = ( export const translateSurvey = (
survey: TSurvey, survey: Pick<TSurvey, "questions" | "welcomeCard" | "thankYouCard">,
surveyLanguages: TSurveyLanguage[], surveyLanguages: TLanguage[]
targetLanguageCode?: string ): Pick<TSurvey, "questions" | "welcomeCard" | "thankYouCard"> => {
): TSurvey => { const languages = extractLanguageIds(surveyLanguages);
const languages = extractLanguageCodes(surveyLanguages);
const translatedQuestions = survey.questions.map((question) => { const translatedQuestions = survey.questions.map((question) => {
return translateQuestion(question, languages, targetLanguageCode); return translateQuestion(question, languages);
}); });
const translatedWelcomeCard = const translatedWelcomeCard = translateWelcomeCard(survey.welcomeCard, languages);
survey.welcomeCard && translateWelcomeCard(survey.welcomeCard, languages, targetLanguageCode); const translatedThankYouCard = translateThankYouCard(survey.thankYouCard, languages);
const translatedThankYouCard =
survey.thankYouCard && translateThankYouCard(survey.thankYouCard, languages, targetLanguageCode);
const translatedSurvey = structuredClone(survey); const translatedSurvey = structuredClone(survey);
return { return {
...translatedSurvey, ...translatedSurvey,
-25
View File
@@ -19,7 +19,6 @@ import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
import { displayCache } from "../display/cache"; import { displayCache } from "../display/cache";
import { getDisplaysByPersonId } from "../display/service"; import { getDisplaysByPersonId } from "../display/service";
import { reverseTranslateSurvey } from "../i18n/reverseTranslation"; import { reverseTranslateSurvey } from "../i18n/reverseTranslation";
import { translateSurvey } from "../i18n/utils";
import { personCache } from "../person/cache"; import { personCache } from "../person/cache";
import { getPerson } from "../person/service"; import { getPerson } from "../person/service";
import { productCache } from "../product/cache"; import { productCache } from "../product/cache";
@@ -366,30 +365,6 @@ export const transformToLegacySurvey = async (
return formatDateFields(transformedSurvey, ZLegacySurvey); return formatDateFields(transformedSurvey, ZLegacySurvey);
}; };
export const transformSurveyToSpecificLanguage = async (
survey: TSurvey,
targetLanguageCode?: string
): Promise<TSurvey> => {
// if target language code is not available, it will be transformed to default language
const transformedSurvey = await unstable_cache(
async () => {
if (!survey.languages || survey.languages.length === 0) {
//survey do not have any translations
return survey;
}
return translateSurvey(survey, [], targetLanguageCode);
},
[`transformSurveyToSpecificLanguage-${survey}-${targetLanguageCode}`],
{
tags: [surveyCache.tag.byId(survey.id)],
revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
// since the unstable_cache function does not support deserialization of dates, we need to manually deserialize them
// https://github.com/vercel/next.js/issues/51613
return formatDateFields(transformedSurvey, ZSurvey);
};
export const getSurveyCount = async (environmentId: string): Promise<number> => { export const getSurveyCount = async (environmentId: string): Promise<number> => {
const count = await unstable_cache( const count = await unstable_cache(
async () => { async () => {