mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-23 21:59:28 -05:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b099219244 | |||
| af82329c4a | |||
| cfff6b1495 | |||
| 9bc4e69821 | |||
| 81b1c036f6 | |||
| 635200db78 | |||
| 793320746e | |||
| 6501041a48 | |||
| f5337e77f3 | |||
| 0192c1ed00 | |||
| 2e2b13c36b | |||
| 95dd4404d1 | |||
| 8a9912f839 | |||
| 016dc3d92a | |||
| 3a147a2b09 | |||
| e159b45911 | |||
| 96d14b98f0 | |||
| aa90d9fd1a | |||
| 2ffe79ffd2 | |||
| cffeb0513e | |||
| bc334c24cf | |||
| 077a9934ad | |||
| 1ed8d8076e | |||
| 345b282733 | |||
| c7c30a9d58 | |||
| 08510659de | |||
| f8fa29d56e | |||
| 8b048c3105 | |||
| b2705a4f8f | |||
| e867caa373 | |||
| ff6176df0a | |||
| d0f4228b45 | |||
| de79b58648 | |||
| 04d528b9b8 | |||
| c815b11015 | |||
| 1e7830d850 | |||
| 77cd1e9bd1 | |||
| e665227437 | |||
| 3a802810e3 | |||
| fbbf917093 | |||
| a7e42bfd29 | |||
| 562fdec899 | |||
| 75e71e39bc | |||
| 337aedf463 | |||
| d670d5de31 | |||
| 5ccb4af249 | |||
| 62aa186a81 | |||
| cb094761ca | |||
| f35e54f21d | |||
| f49f40610b | |||
| 9e754bad9c | |||
| 4dcf6fda40 | |||
| 1b8ccd7199 | |||
| 4f9088559f | |||
| 18550f1d11 | |||
| 881cd31f74 | |||
| e00405dca2 |
@@ -32,24 +32,6 @@ CRON_SECRET=
|
|||||||
# Set the minimum log level(debug, info, warn, error, fatal)
|
# Set the minimum log level(debug, info, warn, error, fatal)
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
|
|
||||||
# BullMQ workers require REDIS_URL (for example `redis://localhost:6379`) to be set.
|
|
||||||
# BullMQ worker startup is enabled by default outside tests. Set to 0 to disable.
|
|
||||||
# BULLMQ_WORKER_ENABLED=1
|
|
||||||
# Set to 1 on web/API pods that only enqueue jobs while a separate BullMQ worker deployment consumes them.
|
|
||||||
# BULLMQ_EXTERNAL_WORKER_ENABLED=0
|
|
||||||
|
|
||||||
# Number of BullMQ worker instances started per Formbricks server process.
|
|
||||||
# BULLMQ_WORKER_COUNT=1
|
|
||||||
|
|
||||||
# Number of concurrent jobs each BullMQ worker can process.
|
|
||||||
# BULLMQ_WORKER_CONCURRENCY=1
|
|
||||||
|
|
||||||
# Survey publish/close scheduling is configured with public build-time env vars because the editor UI
|
|
||||||
# also needs to render the selected execution time and timezone.
|
|
||||||
# NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE=Europe/Berlin
|
|
||||||
# NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_HOUR=0
|
|
||||||
# NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_MINUTE=0
|
|
||||||
|
|
||||||
##############
|
##############
|
||||||
# DATABASE #
|
# DATABASE #
|
||||||
##############
|
##############
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
"eslint-plugin-react-refresh": "0.4.26",
|
"eslint-plugin-react-refresh": "0.4.26",
|
||||||
"eslint-plugin-storybook": "10.2.17",
|
"eslint-plugin-storybook": "10.2.17",
|
||||||
"storybook": "10.2.17",
|
"storybook": "10.2.17",
|
||||||
"vite": "7.3.2",
|
"vite": "7.3.1",
|
||||||
"@storybook/addon-docs": "10.2.17"
|
"@storybook/addon-docs": "10.2.17"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -313,15 +313,6 @@ export const MainNavigation = ({
|
|||||||
href: `/workspaces/${workspace.id}/settings/enterprise`,
|
href: `/workspaces/${workspace.id}/settings/enterprise`,
|
||||||
hidden: isFormbricksCloud || isMember,
|
hidden: isFormbricksCloud || isMember,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "feedback-record-directories",
|
|
||||||
label: t("workspace.settings.feedback_record_directories.title"),
|
|
||||||
href: `/workspaces/${workspace.id}/settings/feedback-record-directories`,
|
|
||||||
disabled: isMembershipPending || isMember,
|
|
||||||
disabledMessage: isMembershipPending
|
|
||||||
? t("common.loading")
|
|
||||||
: t("common.you_are_not_authorized_to_perform_this_action"),
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const loadWorkspaces = useCallback(async () => {
|
const loadWorkspaces = useCallback(async () => {
|
||||||
@@ -438,22 +429,16 @@ export const MainNavigation = ({
|
|||||||
: `/workspaces/${workspace.id}/surveys/`;
|
: `/workspaces/${workspace.id}/surveys/`;
|
||||||
|
|
||||||
const handleWorkspaceChange = (workspaceId: string) => {
|
const handleWorkspaceChange = (workspaceId: string) => {
|
||||||
const targetPath =
|
if (workspaceId === workspace.id) return;
|
||||||
workspaceId === workspace.id ? `/workspaces/${workspace.id}/surveys` : `/workspaces/${workspaceId}/`;
|
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
setIsWorkspaceDropdownOpen(false);
|
router.push(`/workspaces/${workspaceId}/`);
|
||||||
router.push(targetPath);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOrganizationChange = (organizationId: string) => {
|
const handleOrganizationChange = (organizationId: string) => {
|
||||||
const targetPath =
|
if (organizationId === organization.id) return;
|
||||||
organizationId === organization.id
|
|
||||||
? `/workspaces/${workspace.id}/settings/general`
|
|
||||||
: `/organizations/${organizationId}/`;
|
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
setIsOrganizationDropdownOpen(false);
|
router.push(`/organizations/${organizationId}/`);
|
||||||
router.push(targetPath);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -510,7 +495,7 @@ export const MainNavigation = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const switcherIconClasses =
|
const switcherIconClasses =
|
||||||
"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-slate-100 text-slate-600";
|
"flex h-9 w-9 items-center justify-center rounded-full bg-slate-100 text-slate-600";
|
||||||
const isInitialWorkspacesLoading =
|
const isInitialWorkspacesLoading =
|
||||||
isWorkspaceDropdownOpen && !hasInitializedWorkspaces && !workspaceLoadError;
|
isWorkspaceDropdownOpen && !hasInitializedWorkspaces && !workspaceLoadError;
|
||||||
|
|
||||||
|
|||||||
+14
-12
@@ -117,12 +117,8 @@ export const OrganizationBreadcrumb = ({
|
|||||||
const workspaceBasePath = `/workspaces/${workspace?.id}`;
|
const workspaceBasePath = `/workspaces/${workspace?.id}`;
|
||||||
|
|
||||||
const handleOrganizationChange = (organizationId: string) => {
|
const handleOrganizationChange = (organizationId: string) => {
|
||||||
|
if (organizationId === currentOrganizationId) return;
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
setIsOrganizationDropdownOpen(false);
|
|
||||||
if (organizationId === currentOrganizationId && currentWorkspaceId) {
|
|
||||||
router.push(`/workspaces/${currentWorkspaceId}/settings/general`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
router.push(`/organizations/${organizationId}/`);
|
router.push(`/organizations/${organizationId}/`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -148,6 +144,12 @@ export const OrganizationBreadcrumb = ({
|
|||||||
label: t("common.members_and_teams"),
|
label: t("common.members_and_teams"),
|
||||||
href: `${workspaceBasePath}/settings/teams`,
|
href: `${workspaceBasePath}/settings/teams`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "feedback-record-directories",
|
||||||
|
label: t("workspace.settings.feedback_record_directories.nav_label"),
|
||||||
|
href: `${workspaceBasePath}/settings/feedback-record-directories`,
|
||||||
|
hidden: isMember,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "api-keys",
|
id: "api-keys",
|
||||||
label: t("common.api_keys"),
|
label: t("common.api_keys"),
|
||||||
@@ -170,19 +172,19 @@ export const OrganizationBreadcrumb = ({
|
|||||||
hidden: !isFormbricksCloud,
|
hidden: !isFormbricksCloud,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "enterprise",
|
id: "feedback-record-directories",
|
||||||
label: t("common.enterprise_license"),
|
label: t("workspace.settings.feedback_record_directories.title"),
|
||||||
href: `${workspaceBasePath}/settings/enterprise`,
|
href: `${workspaceBasePath}/settings/feedback-record-directories`,
|
||||||
hidden: isFormbricksCloud || isMember,
|
|
||||||
disabled: isMembershipPending || isMember,
|
disabled: isMembershipPending || isMember,
|
||||||
disabledMessage: isMembershipPending
|
disabledMessage: isMembershipPending
|
||||||
? t("common.loading")
|
? t("common.loading")
|
||||||
: t("common.you_are_not_authorized_to_perform_this_action"),
|
: t("common.you_are_not_authorized_to_perform_this_action"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "feedback-record-directories",
|
id: "enterprise",
|
||||||
label: t("workspace.settings.feedback_record_directories.title"),
|
label: t("common.enterprise_license"),
|
||||||
href: `${workspaceBasePath}/settings/feedback-record-directories`,
|
href: `${workspaceBasePath}/settings/enterprise`,
|
||||||
|
hidden: isFormbricksCloud || isMember,
|
||||||
disabled: isMembershipPending || isMember,
|
disabled: isMembershipPending || isMember,
|
||||||
disabledMessage: isMembershipPending
|
disabledMessage: isMembershipPending
|
||||||
? t("common.loading")
|
? t("common.loading")
|
||||||
|
|||||||
@@ -158,13 +158,9 @@ export const WorkspaceBreadcrumb = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleWorkspaceChange = (workspaceId: string) => {
|
const handleWorkspaceChange = (workspaceId: string) => {
|
||||||
const targetPath =
|
if (workspaceId === currentWorkspaceId) return;
|
||||||
workspaceId === currentWorkspaceId
|
|
||||||
? `/workspaces/${currentWorkspaceId}/surveys`
|
|
||||||
: `/workspaces/${workspaceId}/`;
|
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
setIsWorkspaceDropdownOpen(false);
|
router.push(`/workspaces/${workspaceId}/`);
|
||||||
router.push(targetPath);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
-51
@@ -1,51 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { CircleSlash2, SmileIcon, StarIcon } from "lucide-react";
|
|
||||||
import { useMemo } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { type TI18nString } from "@formbricks/types/i18n";
|
|
||||||
import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
|
||||||
import { TSurvey, TSurveyElementSummaryCes } from "@formbricks/types/surveys/types";
|
|
||||||
import { RatingLikeSummary } from "./RatingLikeSummary";
|
|
||||||
|
|
||||||
interface CESSummaryProps {
|
|
||||||
elementSummary: TSurveyElementSummaryCes;
|
|
||||||
survey: TSurvey;
|
|
||||||
setFilter: (
|
|
||||||
elementId: string,
|
|
||||||
label: TI18nString,
|
|
||||||
elementType: TSurveyElementTypeEnum,
|
|
||||||
filterValue: string,
|
|
||||||
filterComboBoxValue?: string | string[]
|
|
||||||
) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CESSummary = ({ elementSummary, survey, setFilter }: CESSummaryProps) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const getIconBasedOnScale = useMemo(() => {
|
|
||||||
const scale = elementSummary.element.scale;
|
|
||||||
if (scale === "number") return <CircleSlash2 className="h-4 w-4" />;
|
|
||||||
else if (scale === "star") return <StarIcon fill="rgb(250 204 21)" className="h-4 w-4 text-yellow-400" />;
|
|
||||||
else if (scale === "smiley") return <SmileIcon className="h-4 w-4" />;
|
|
||||||
}, [elementSummary.element.scale]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RatingLikeSummary
|
|
||||||
elementSummary={elementSummary}
|
|
||||||
survey={survey}
|
|
||||||
setFilter={setFilter}
|
|
||||||
additionalInfo={
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<div className="flex items-center space-x-2 rounded-lg bg-slate-100 p-2">
|
|
||||||
{getIconBasedOnScale}
|
|
||||||
<div>
|
|
||||||
{t("workspace.surveys.summary.effort_score")}: {elementSummary.average.toFixed(2)} /{" "}
|
|
||||||
{elementSummary.element.range}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
-72
@@ -1,72 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { CircleSlash2, SmileIcon, StarIcon } from "lucide-react";
|
|
||||||
import { useMemo } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { type TI18nString } from "@formbricks/types/i18n";
|
|
||||||
import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
|
||||||
import { TSurvey, TSurveyElementSummaryCsat } from "@formbricks/types/surveys/types";
|
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/modules/ui/components/tooltip";
|
|
||||||
import { RatingLikeSummary } from "./RatingLikeSummary";
|
|
||||||
import { SatisfactionIndicator } from "./SatisfactionIndicator";
|
|
||||||
|
|
||||||
interface CSATSummaryProps {
|
|
||||||
elementSummary: TSurveyElementSummaryCsat;
|
|
||||||
survey: TSurvey;
|
|
||||||
setFilter: (
|
|
||||||
elementId: string,
|
|
||||||
label: TI18nString,
|
|
||||||
elementType: TSurveyElementTypeEnum,
|
|
||||||
filterValue: string,
|
|
||||||
filterComboBoxValue?: string | string[]
|
|
||||||
) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CSATSummary = ({ elementSummary, survey, setFilter }: CSATSummaryProps) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const getIconBasedOnScale = useMemo(() => {
|
|
||||||
const scale = elementSummary.element.scale;
|
|
||||||
if (scale === "number") return <CircleSlash2 className="h-4 w-4" />;
|
|
||||||
else if (scale === "star") return <StarIcon fill="rgb(250 204 21)" className="h-4 w-4 text-yellow-400" />;
|
|
||||||
else if (scale === "smiley") return <SmileIcon className="h-4 w-4" />;
|
|
||||||
}, [elementSummary.element.scale]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RatingLikeSummary
|
|
||||||
elementSummary={elementSummary}
|
|
||||||
survey={survey}
|
|
||||||
setFilter={setFilter}
|
|
||||||
additionalInfo={
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<div className="flex items-center space-x-2 rounded-lg bg-slate-100 p-2">
|
|
||||||
{getIconBasedOnScale}
|
|
||||||
<div>
|
|
||||||
{t("workspace.surveys.summary.overall")}: {elementSummary.average.toFixed(2)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<TooltipProvider delayDuration={150}>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<div className="flex items-center space-x-2 rounded-lg bg-slate-100 p-2">
|
|
||||||
<SatisfactionIndicator percentage={elementSummary.csat.satisfiedPercentage} />
|
|
||||||
<div>
|
|
||||||
{t("workspace.surveys.summary.csat_satisfied", {
|
|
||||||
percentage: elementSummary.csat.satisfiedPercentage,
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent side="bottom">
|
|
||||||
{t("workspace.surveys.summary.csat_satisfied_tooltip", {
|
|
||||||
percentage: elementSummary.csat.satisfiedPercentage,
|
|
||||||
})}
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
+8
-19
@@ -8,7 +8,7 @@ import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
|||||||
import { TSurvey, TSurveyElementSummaryNps } from "@formbricks/types/surveys/types";
|
import { TSurvey, TSurveyElementSummaryNps } from "@formbricks/types/surveys/types";
|
||||||
import { HalfCircle, ProgressBar } from "@/modules/ui/components/progress-bar";
|
import { HalfCircle, ProgressBar } from "@/modules/ui/components/progress-bar";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/modules/ui/components/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/modules/ui/components/tabs";
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/modules/ui/components/tooltip";
|
import { TooltipProvider } from "@/modules/ui/components/tooltip";
|
||||||
import { convertFloatToNDecimal } from "../lib/utils";
|
import { convertFloatToNDecimal } from "../lib/utils";
|
||||||
import { ClickableBarSegment } from "./ClickableBarSegment";
|
import { ClickableBarSegment } from "./ClickableBarSegment";
|
||||||
import { ElementSummaryHeader } from "./ElementSummaryHeader";
|
import { ElementSummaryHeader } from "./ElementSummaryHeader";
|
||||||
@@ -39,7 +39,6 @@ const calculateNPSOpacity = (rating: number): number => {
|
|||||||
export const NPSSummary = ({ elementSummary, survey, setFilter }: NPSSummaryProps) => {
|
export const NPSSummary = ({ elementSummary, survey, setFilter }: NPSSummaryProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [activeTab, setActiveTab] = useState<"aggregated" | "individual">("aggregated");
|
const [activeTab, setActiveTab] = useState<"aggregated" | "individual">("aggregated");
|
||||||
const promotersPercentage = convertFloatToNDecimal(elementSummary.promoters.percentage, 2);
|
|
||||||
|
|
||||||
const applyFilter = (group: string) => {
|
const applyFilter = (group: string) => {
|
||||||
const filters = {
|
const filters = {
|
||||||
@@ -82,23 +81,13 @@ export const NPSSummary = ({ elementSummary, survey, setFilter }: NPSSummaryProp
|
|||||||
elementSummary={elementSummary}
|
elementSummary={elementSummary}
|
||||||
survey={survey}
|
survey={survey}
|
||||||
additionalInfo={
|
additionalInfo={
|
||||||
<TooltipProvider delayDuration={150}>
|
<div className="flex items-center space-x-2 rounded-lg bg-slate-100 p-2">
|
||||||
<Tooltip>
|
<SatisfactionIndicator percentage={elementSummary.promoters.percentage} />
|
||||||
<TooltipTrigger asChild>
|
<div>
|
||||||
<div className="flex items-center space-x-2 rounded-lg bg-slate-100 p-2">
|
{t("workspace.surveys.summary.promoters")}:{" "}
|
||||||
<SatisfactionIndicator percentage={elementSummary.promoters.percentage} />
|
{convertFloatToNDecimal(elementSummary.promoters.percentage, 2)}%
|
||||||
<div>
|
</div>
|
||||||
{t("workspace.surveys.summary.promoters")}: {promotersPercentage}%
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent side="bottom">
|
|
||||||
{t("workspace.surveys.summary.nps_promoters_tooltip", {
|
|
||||||
percentage: promotersPercentage,
|
|
||||||
})}
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
-214
@@ -1,214 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { BarChart, BarChartHorizontal } from "lucide-react";
|
|
||||||
import { type JSX, useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { type TI18nString } from "@formbricks/types/i18n";
|
|
||||||
import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
|
||||||
import {
|
|
||||||
TSurvey,
|
|
||||||
TSurveyElementSummaryCes,
|
|
||||||
TSurveyElementSummaryCsat,
|
|
||||||
TSurveyElementSummaryRating,
|
|
||||||
} from "@formbricks/types/surveys/types";
|
|
||||||
import { convertFloatToNDecimal } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/lib/utils";
|
|
||||||
import { EmptyState } from "@/modules/ui/components/empty-state";
|
|
||||||
import { ProgressBar } from "@/modules/ui/components/progress-bar";
|
|
||||||
import { RatingResponse } from "@/modules/ui/components/rating-response";
|
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/modules/ui/components/tabs";
|
|
||||||
import { TooltipProvider } from "@/modules/ui/components/tooltip";
|
|
||||||
import { ClickableBarSegment } from "./ClickableBarSegment";
|
|
||||||
import { ElementSummaryHeader } from "./ElementSummaryHeader";
|
|
||||||
import { RatingScaleLegend } from "./RatingScaleLegend";
|
|
||||||
|
|
||||||
type RatingLikeElementSummary =
|
|
||||||
| TSurveyElementSummaryCes
|
|
||||||
| TSurveyElementSummaryCsat
|
|
||||||
| TSurveyElementSummaryRating;
|
|
||||||
|
|
||||||
interface RatingLikeSummaryProps {
|
|
||||||
elementSummary: RatingLikeElementSummary;
|
|
||||||
survey: TSurvey;
|
|
||||||
setFilter: (
|
|
||||||
elementId: string,
|
|
||||||
label: TI18nString,
|
|
||||||
elementType: TSurveyElementTypeEnum,
|
|
||||||
filterValue: string,
|
|
||||||
filterComboBoxValue?: string | string[]
|
|
||||||
) => void;
|
|
||||||
additionalInfo: JSX.Element;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const RatingLikeSummary = ({
|
|
||||||
elementSummary,
|
|
||||||
survey,
|
|
||||||
setFilter,
|
|
||||||
additionalInfo,
|
|
||||||
}: RatingLikeSummaryProps) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [activeTab, setActiveTab] = useState<"aggregated" | "individual">("aggregated");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="rounded-xl border border-slate-200 bg-white shadow-sm">
|
|
||||||
<ElementSummaryHeader elementSummary={elementSummary} survey={survey} additionalInfo={additionalInfo} />
|
|
||||||
|
|
||||||
<Tabs value={activeTab} onValueChange={(value) => setActiveTab(value as "aggregated" | "individual")}>
|
|
||||||
<div className="flex justify-end px-4 md:px-6">
|
|
||||||
<TabsList>
|
|
||||||
<TabsTrigger value="aggregated" icon={<BarChartHorizontal className="h-4 w-4" />}>
|
|
||||||
{t("workspace.surveys.summary.aggregated")}
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="individual" icon={<BarChart className="h-4 w-4" />}>
|
|
||||||
{t("workspace.surveys.summary.individual")}
|
|
||||||
</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<TabsContent value="aggregated" className="mt-4">
|
|
||||||
<div className="px-4 pb-6 pt-4 md:px-6">
|
|
||||||
{elementSummary.responseCount === 0 ? (
|
|
||||||
<>
|
|
||||||
<EmptyState text={t("workspace.surveys.summary.no_responses_found")} variant="simple" />
|
|
||||||
<RatingScaleLegend
|
|
||||||
scale={elementSummary.element.scale}
|
|
||||||
range={elementSummary.element.range}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<TooltipProvider delayDuration={200}>
|
|
||||||
<div className="flex h-12 w-full overflow-hidden rounded-t-lg border border-slate-200">
|
|
||||||
{elementSummary.choices.map((result, index) => {
|
|
||||||
if (result.percentage === 0) return null;
|
|
||||||
|
|
||||||
const range = elementSummary.element.range;
|
|
||||||
const opacity = 0.3 + (result.rating / range) * 0.7;
|
|
||||||
const isFirst = index === 0;
|
|
||||||
const isLast = index === elementSummary.choices.length - 1;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ClickableBarSegment
|
|
||||||
key={result.rating}
|
|
||||||
className="relative h-full cursor-pointer transition-opacity hover:brightness-110"
|
|
||||||
style={{
|
|
||||||
width: `${result.percentage}%`,
|
|
||||||
borderRight: isLast ? "none" : "1px solid rgb(226, 232, 240)",
|
|
||||||
}}
|
|
||||||
onClick={() =>
|
|
||||||
setFilter(
|
|
||||||
elementSummary.element.id,
|
|
||||||
elementSummary.element.headline,
|
|
||||||
elementSummary.element.type,
|
|
||||||
t("workspace.surveys.summary.is_equal_to"),
|
|
||||||
result.rating.toString()
|
|
||||||
)
|
|
||||||
}>
|
|
||||||
<div
|
|
||||||
className={`h-full bg-brand-dark ${isFirst ? "rounded-tl-lg" : ""} ${isLast ? "rounded-tr-lg" : ""}`}
|
|
||||||
style={{ opacity }}
|
|
||||||
/>
|
|
||||||
</ClickableBarSegment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</TooltipProvider>
|
|
||||||
<div className="flex w-full overflow-hidden rounded-b-lg border border-t-0 border-slate-200 bg-slate-50">
|
|
||||||
{elementSummary.choices.map((result, index) => {
|
|
||||||
if (result.percentage === 0) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={result.rating}
|
|
||||||
className="flex flex-col items-center justify-center py-2"
|
|
||||||
style={{
|
|
||||||
width: `${result.percentage}%`,
|
|
||||||
borderRight:
|
|
||||||
index < elementSummary.choices.length - 1
|
|
||||||
? "1px solid rgb(226, 232, 240)"
|
|
||||||
: "none",
|
|
||||||
}}>
|
|
||||||
<div className="mb-1 flex items-center justify-center">
|
|
||||||
<RatingResponse
|
|
||||||
scale={elementSummary.element.scale}
|
|
||||||
answer={result.rating}
|
|
||||||
range={elementSummary.element.range}
|
|
||||||
addColors={false}
|
|
||||||
variant="aggregated"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="text-xs font-medium text-slate-600">
|
|
||||||
{convertFloatToNDecimal(result.percentage, 1)}%
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<RatingScaleLegend
|
|
||||||
scale={elementSummary.element.scale}
|
|
||||||
range={elementSummary.element.range}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</TabsContent>
|
|
||||||
|
|
||||||
<TabsContent value="individual" className="mt-4">
|
|
||||||
<div className="px-4 pb-6 pt-4 md:px-6">
|
|
||||||
<div className="space-y-5 text-sm md:text-base">
|
|
||||||
{elementSummary.choices.map((result) => (
|
|
||||||
<div key={result.rating}>
|
|
||||||
<button
|
|
||||||
className="w-full cursor-pointer hover:opacity-80"
|
|
||||||
onClick={() =>
|
|
||||||
setFilter(
|
|
||||||
elementSummary.element.id,
|
|
||||||
elementSummary.element.headline,
|
|
||||||
elementSummary.element.type,
|
|
||||||
t("workspace.surveys.summary.is_equal_to"),
|
|
||||||
result.rating.toString()
|
|
||||||
)
|
|
||||||
}>
|
|
||||||
<div className="text flex justify-between px-2 pb-2">
|
|
||||||
<div className="mr-8 flex items-center space-x-1">
|
|
||||||
<div className="font-semibold text-slate-700">
|
|
||||||
<RatingResponse
|
|
||||||
scale={elementSummary.element.scale}
|
|
||||||
answer={result.rating}
|
|
||||||
range={elementSummary.element.range}
|
|
||||||
addColors={elementSummary.element.isColorCodingEnabled}
|
|
||||||
variant="individual"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="rounded-lg bg-slate-100 px-2 text-slate-700">
|
|
||||||
{convertFloatToNDecimal(result.percentage, 2)}%
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="flex w-32 items-end justify-end text-slate-600">
|
|
||||||
{t("common.count_responses", { count: result.count })}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<ProgressBar barColor="bg-brand-dark" progress={result.percentage / 100} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
|
||||||
{elementSummary.dismissed && elementSummary.dismissed.count > 0 && (
|
|
||||||
<div className="rounded-b-lg border-t bg-white px-6 py-4">
|
|
||||||
<div key="dismissed">
|
|
||||||
<div className="text flex justify-between px-2">
|
|
||||||
<p className="font-semibold text-slate-700">{t("common.dismissed")}</p>
|
|
||||||
<p className="flex w-32 items-end justify-end text-slate-600">
|
|
||||||
{t("common.count_responses", { count: elementSummary.dismissed.count })}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
+192
-16
@@ -1,12 +1,21 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { CircleSlash2, SmileIcon, StarIcon } from "lucide-react";
|
import { BarChart, BarChartHorizontal, CircleSlash2, SmileIcon, StarIcon } from "lucide-react";
|
||||||
import { useMemo } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { type TI18nString } from "@formbricks/types/i18n";
|
import { type TI18nString } from "@formbricks/types/i18n";
|
||||||
import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
||||||
import { TSurvey, TSurveyElementSummaryRating } from "@formbricks/types/surveys/types";
|
import { TSurvey, TSurveyElementSummaryRating } from "@formbricks/types/surveys/types";
|
||||||
import { RatingLikeSummary } from "./RatingLikeSummary";
|
import { convertFloatToNDecimal } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/lib/utils";
|
||||||
|
import { EmptyState } from "@/modules/ui/components/empty-state";
|
||||||
|
import { ProgressBar } from "@/modules/ui/components/progress-bar";
|
||||||
|
import { RatingResponse } from "@/modules/ui/components/rating-response";
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/modules/ui/components/tabs";
|
||||||
|
import { TooltipProvider } from "@/modules/ui/components/tooltip";
|
||||||
|
import { ClickableBarSegment } from "./ClickableBarSegment";
|
||||||
|
import { ElementSummaryHeader } from "./ElementSummaryHeader";
|
||||||
|
import { RatingScaleLegend } from "./RatingScaleLegend";
|
||||||
|
import { SatisfactionIndicator } from "./SatisfactionIndicator";
|
||||||
|
|
||||||
interface RatingSummaryProps {
|
interface RatingSummaryProps {
|
||||||
elementSummary: TSurveyElementSummaryRating;
|
elementSummary: TSurveyElementSummaryRating;
|
||||||
@@ -22,29 +31,196 @@ interface RatingSummaryProps {
|
|||||||
|
|
||||||
export const RatingSummary = ({ elementSummary, survey, setFilter }: RatingSummaryProps) => {
|
export const RatingSummary = ({ elementSummary, survey, setFilter }: RatingSummaryProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const [activeTab, setActiveTab] = useState<"aggregated" | "individual">("aggregated");
|
||||||
|
|
||||||
const getIconBasedOnScale = useMemo(() => {
|
const getIconBasedOnScale = useMemo(() => {
|
||||||
const scale = elementSummary.element.scale;
|
const scale = elementSummary.element.scale;
|
||||||
if (scale === "number") return <CircleSlash2 className="h-4 w-4" />;
|
if (scale === "number") return <CircleSlash2 className="h-4 w-4" />;
|
||||||
else if (scale === "star") return <StarIcon fill="rgb(250 204 21)" className="h-4 w-4 text-yellow-400" />;
|
else if (scale === "star") return <StarIcon fill="rgb(250 204 21)" className="h-4 w-4 text-yellow-400" />;
|
||||||
else if (scale === "smiley") return <SmileIcon className="h-4 w-4" />;
|
else if (scale === "smiley") return <SmileIcon className="h-4 w-4" />;
|
||||||
}, [elementSummary.element.scale]);
|
}, [elementSummary]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RatingLikeSummary
|
<div className="rounded-xl border border-slate-200 bg-white shadow-sm">
|
||||||
elementSummary={elementSummary}
|
<ElementSummaryHeader
|
||||||
survey={survey}
|
elementSummary={elementSummary}
|
||||||
setFilter={setFilter}
|
survey={survey}
|
||||||
additionalInfo={
|
additionalInfo={
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div className="flex items-center space-x-2 rounded-lg bg-slate-100 p-2">
|
<div className="flex items-center space-x-2 rounded-lg bg-slate-100 p-2">
|
||||||
{getIconBasedOnScale}
|
{getIconBasedOnScale}
|
||||||
<div>
|
<div>
|
||||||
{t("workspace.surveys.summary.overall")}: {elementSummary.average.toFixed(2)}
|
{t("workspace.surveys.summary.overall")}: {elementSummary.average.toFixed(2)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center space-x-2 rounded-lg bg-slate-100 p-2">
|
||||||
|
<SatisfactionIndicator percentage={elementSummary.csat.satisfiedPercentage} />
|
||||||
|
<div>
|
||||||
|
CSAT: {elementSummary.csat.satisfiedPercentage}% {t("workspace.surveys.summary.satisfied")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Tabs value={activeTab} onValueChange={(value) => setActiveTab(value as "aggregated" | "individual")}>
|
||||||
|
<div className="flex justify-end px-4 md:px-6">
|
||||||
|
<TabsList>
|
||||||
|
<TabsTrigger value="aggregated" icon={<BarChartHorizontal className="h-4 w-4" />}>
|
||||||
|
{t("workspace.surveys.summary.aggregated")}
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="individual" icon={<BarChart className="h-4 w-4" />}>
|
||||||
|
{t("workspace.surveys.summary.individual")}
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TabsContent value="aggregated" className="mt-4">
|
||||||
|
<div className="px-4 pb-6 pt-4 md:px-6">
|
||||||
|
{elementSummary.responseCount === 0 ? (
|
||||||
|
<>
|
||||||
|
<EmptyState text={t("workspace.surveys.summary.no_responses_found")} variant="simple" />
|
||||||
|
<RatingScaleLegend
|
||||||
|
scale={elementSummary.element.scale}
|
||||||
|
range={elementSummary.element.range}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<TooltipProvider delayDuration={200}>
|
||||||
|
<div className="flex h-12 w-full overflow-hidden rounded-t-lg border border-slate-200">
|
||||||
|
{elementSummary.choices.map((result, index) => {
|
||||||
|
if (result.percentage === 0) return null;
|
||||||
|
|
||||||
|
const range = elementSummary.element.range;
|
||||||
|
const opacity = 0.3 + (result.rating / range) * 0.8;
|
||||||
|
const isFirst = index === 0;
|
||||||
|
const isLast = index === elementSummary.choices.length - 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ClickableBarSegment
|
||||||
|
key={result.rating}
|
||||||
|
className="relative h-full cursor-pointer transition-opacity hover:brightness-110"
|
||||||
|
style={{
|
||||||
|
width: `${result.percentage}%`,
|
||||||
|
borderRight: isLast ? "none" : "1px solid rgb(226, 232, 240)",
|
||||||
|
}}
|
||||||
|
onClick={() =>
|
||||||
|
setFilter(
|
||||||
|
elementSummary.element.id,
|
||||||
|
elementSummary.element.headline,
|
||||||
|
elementSummary.element.type,
|
||||||
|
t("workspace.surveys.summary.is_equal_to"),
|
||||||
|
result.rating.toString()
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
<div
|
||||||
|
className={`h-full bg-brand-dark ${isFirst ? "rounded-tl-lg" : ""} ${isLast ? "rounded-tr-lg" : ""}`}
|
||||||
|
style={{ opacity }}
|
||||||
|
/>
|
||||||
|
</ClickableBarSegment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</TooltipProvider>
|
||||||
|
<div className="flex w-full overflow-hidden rounded-b-lg border border-t-0 border-slate-200 bg-slate-50">
|
||||||
|
{elementSummary.choices.map((result, index) => {
|
||||||
|
if (result.percentage === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={result.rating}
|
||||||
|
className="flex flex-col items-center justify-center py-2"
|
||||||
|
style={{
|
||||||
|
width: `${result.percentage}%`,
|
||||||
|
borderRight:
|
||||||
|
index < elementSummary.choices.length - 1
|
||||||
|
? "1px solid rgb(226, 232, 240)"
|
||||||
|
: "none",
|
||||||
|
}}>
|
||||||
|
<div className="mb-1 flex items-center justify-center">
|
||||||
|
<RatingResponse
|
||||||
|
scale={elementSummary.element.scale}
|
||||||
|
answer={result.rating}
|
||||||
|
range={elementSummary.element.range}
|
||||||
|
addColors={false}
|
||||||
|
variant="aggregated"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs font-medium text-slate-600">
|
||||||
|
{convertFloatToNDecimal(result.percentage, 1)}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<RatingScaleLegend
|
||||||
|
scale={elementSummary.element.scale}
|
||||||
|
range={elementSummary.element.range}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="individual" className="mt-4">
|
||||||
|
<div className="px-4 pb-6 pt-4 md:px-6">
|
||||||
|
<div className="space-y-5 text-sm md:text-base">
|
||||||
|
{elementSummary.choices.map((result) => (
|
||||||
|
<div key={result.rating}>
|
||||||
|
<button
|
||||||
|
className="w-full cursor-pointer hover:opacity-80"
|
||||||
|
onClick={() =>
|
||||||
|
setFilter(
|
||||||
|
elementSummary.element.id,
|
||||||
|
elementSummary.element.headline,
|
||||||
|
elementSummary.element.type,
|
||||||
|
t("workspace.surveys.summary.is_equal_to"),
|
||||||
|
result.rating.toString()
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
<div className="text flex justify-between px-2 pb-2">
|
||||||
|
<div className="mr-8 flex items-center space-x-1">
|
||||||
|
<div className="font-semibold text-slate-700">
|
||||||
|
<RatingResponse
|
||||||
|
scale={elementSummary.element.scale}
|
||||||
|
answer={result.rating}
|
||||||
|
range={elementSummary.element.range}
|
||||||
|
addColors={elementSummary.element.isColorCodingEnabled}
|
||||||
|
variant="individual"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="rounded-lg bg-slate-100 px-2 text-slate-700">
|
||||||
|
{convertFloatToNDecimal(result.percentage, 2)}%
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="flex w-32 items-end justify-end text-slate-600">
|
||||||
|
{t("common.count_responses", { count: result.count })}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<ProgressBar barColor="bg-brand-dark" progress={result.percentage / 100} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
{elementSummary.dismissed && elementSummary.dismissed.count > 0 && (
|
||||||
|
<div className="rounded-b-lg border-t bg-white px-6 py-4">
|
||||||
|
<div key="dismissed">
|
||||||
|
<div className="text flex justify-between px-2">
|
||||||
|
<p className="font-semibold text-slate-700">{t("common.dismissed")}</p>
|
||||||
|
<p className="flex w-32 items-end justify-end text-slate-600">
|
||||||
|
{t("common.count_responses", { count: elementSummary.dismissed.count })}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
/>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+5
-20
@@ -22,23 +22,8 @@ export const SuccessMessage = ({ survey }: SummaryMetadataProps) => {
|
|||||||
const appSetupCompleted = workspace.appSetupCompleted;
|
const appSetupCompleted = workspace.appSetupCompleted;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const publishSuccessParam = searchParams.get("success");
|
const newSurveyParam = searchParams?.get("success");
|
||||||
const scheduledSuccessParam = searchParams.get("scheduled");
|
if (newSurveyParam && survey && workspace) {
|
||||||
|
|
||||||
if (scheduledSuccessParam) {
|
|
||||||
toast.success(t("workspace.surveys.summary.survey_scheduled_successfully"), {
|
|
||||||
id: "survey-schedule-success-toast",
|
|
||||||
duration: 5000,
|
|
||||||
position: "bottom-right",
|
|
||||||
});
|
|
||||||
|
|
||||||
const url = new URL(globalThis.location.href);
|
|
||||||
url.searchParams.delete("scheduled");
|
|
||||||
globalThis.history.replaceState({}, "", url.toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (publishSuccessParam) {
|
|
||||||
setConfetti(true);
|
setConfetti(true);
|
||||||
toast.success(
|
toast.success(
|
||||||
isAppSurvey && !appSetupCompleted
|
isAppSurvey && !appSetupCompleted
|
||||||
@@ -53,16 +38,16 @@ export const SuccessMessage = ({ survey }: SummaryMetadataProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Remove success param from url
|
// Remove success param from url
|
||||||
const url = new URL(globalThis.location.href);
|
const url = new URL(window.location.href);
|
||||||
url.searchParams.delete("success");
|
url.searchParams.delete("success");
|
||||||
if (survey.type === "link") {
|
if (survey.type === "link") {
|
||||||
// Add share param to url to open share embed modal
|
// Add share param to url to open share embed modal
|
||||||
url.searchParams.set("share", "true");
|
url.searchParams.set("share", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
globalThis.history.replaceState({}, "", url.toString());
|
window.history.replaceState({}, "", url.toString());
|
||||||
}
|
}
|
||||||
}, [appSetupCompleted, isAppSurvey, searchParams, survey.type, t]);
|
}, [workspace, isAppSurvey, searchParams, survey, appSetupCompleted, t]);
|
||||||
|
|
||||||
return <>{confetti && <Confetti />}</>;
|
return <>{confetti && <Confetti />}</>;
|
||||||
};
|
};
|
||||||
|
|||||||
-22
@@ -13,8 +13,6 @@ import {
|
|||||||
SelectedFilterValue,
|
SelectedFilterValue,
|
||||||
useResponseFilter,
|
useResponseFilter,
|
||||||
} from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/components/response-filter-context";
|
} from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/components/response-filter-context";
|
||||||
import { CESSummary } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/components/CESSummary";
|
|
||||||
import { CSATSummary } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/components/CSATSummary";
|
|
||||||
import { CTASummary } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/components/CTASummary";
|
import { CTASummary } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/components/CTASummary";
|
||||||
import { CalSummary } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/components/CalSummary";
|
import { CalSummary } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/components/CalSummary";
|
||||||
import { ConsentSummary } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/components/ConsentSummary";
|
import { ConsentSummary } from "@/app/(app)/workspaces/[workspaceId]/surveys/[surveyId]/(analysis)/summary/components/ConsentSummary";
|
||||||
@@ -158,26 +156,6 @@ export const SummaryList = ({ summary, responseCount, survey, locale }: SummaryL
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (elementSummary.type === TSurveyElementTypeEnum.CSAT) {
|
|
||||||
return (
|
|
||||||
<CSATSummary
|
|
||||||
key={elementSummary.element.id}
|
|
||||||
elementSummary={elementSummary}
|
|
||||||
survey={survey}
|
|
||||||
setFilter={setFilter}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (elementSummary.type === TSurveyElementTypeEnum.CES) {
|
|
||||||
return (
|
|
||||||
<CESSummary
|
|
||||||
key={elementSummary.element.id}
|
|
||||||
elementSummary={elementSummary}
|
|
||||||
survey={survey}
|
|
||||||
setFilter={setFilter}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (elementSummary.type === TSurveyElementTypeEnum.Consent) {
|
if (elementSummary.type === TSurveyElementTypeEnum.Consent) {
|
||||||
return (
|
return (
|
||||||
<ConsentSummary
|
<ConsentSummary
|
||||||
|
|||||||
-608
@@ -4578,611 +4578,3 @@ describe("Cal question type tests", () => {
|
|||||||
expect(summary[0].skipped.count).toBe(1); // Counted as skipped
|
expect(summary[0].skipped.count).toBe(1); // Counted as skipped
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("CSAT question type tests", () => {
|
|
||||||
test("getElementSummary correctly processes CSAT question with valid responses", async () => {
|
|
||||||
const question = {
|
|
||||||
id: "csat-q1",
|
|
||||||
type: TSurveyElementTypeEnum.CSAT,
|
|
||||||
headline: { default: "How satisfied are you?" },
|
|
||||||
required: true,
|
|
||||||
scale: "smiley",
|
|
||||||
range: 5,
|
|
||||||
lowerLabel: { default: "Very unsatisfied" },
|
|
||||||
upperLabel: { default: "Very satisfied" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const survey = {
|
|
||||||
id: "survey-1",
|
|
||||||
blocks: [{ id: "block1", name: "Block 1", elements: [question] }],
|
|
||||||
questions: [],
|
|
||||||
languages: [],
|
|
||||||
welcomeCard: { enabled: false },
|
|
||||||
} as unknown as TSurvey;
|
|
||||||
|
|
||||||
const responses = [
|
|
||||||
{
|
|
||||||
id: "response-1",
|
|
||||||
data: { "csat-q1": 5 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "response-2",
|
|
||||||
data: { "csat-q1": 4 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "response-3",
|
|
||||||
data: { "csat-q1": 2 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "response-4",
|
|
||||||
data: { "csat-q1": 1 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const dropOff = [
|
|
||||||
{ elementId: "csat-q1", impressions: 4, dropOffCount: 0, dropOffPercentage: 0 },
|
|
||||||
] as unknown as TSurveySummary["dropOff"];
|
|
||||||
|
|
||||||
const summary: any = await getElementSummary(
|
|
||||||
survey,
|
|
||||||
getElementsFromBlocks(survey.blocks),
|
|
||||||
responses,
|
|
||||||
dropOff
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(summary).toHaveLength(1);
|
|
||||||
expect(summary[0].type).toBe(TSurveyElementTypeEnum.CSAT);
|
|
||||||
expect(summary[0].responseCount).toBe(4);
|
|
||||||
|
|
||||||
// Average = (5 + 4 + 2 + 1) / 4 = 3.0
|
|
||||||
expect(summary[0].average).toBe(3);
|
|
||||||
|
|
||||||
// CSAT: satisfied = ratings 4 + 5 = 2 out of 4
|
|
||||||
expect(summary[0].csat.satisfiedCount).toBe(2);
|
|
||||||
expect(summary[0].csat.satisfiedPercentage).toBe(50);
|
|
||||||
|
|
||||||
// Verify choice distribution
|
|
||||||
const rating5 = summary[0].choices.find((c: any) => c.rating === 5);
|
|
||||||
expect(rating5.count).toBe(1);
|
|
||||||
expect(rating5.percentage).toBe(25);
|
|
||||||
|
|
||||||
const rating4 = summary[0].choices.find((c: any) => c.rating === 4);
|
|
||||||
expect(rating4.count).toBe(1);
|
|
||||||
expect(rating4.percentage).toBe(25);
|
|
||||||
|
|
||||||
const rating2 = summary[0].choices.find((c: any) => c.rating === 2);
|
|
||||||
expect(rating2.count).toBe(1);
|
|
||||||
expect(rating2.percentage).toBe(25);
|
|
||||||
|
|
||||||
const rating1 = summary[0].choices.find((c: any) => c.rating === 1);
|
|
||||||
expect(rating1.count).toBe(1);
|
|
||||||
expect(rating1.percentage).toBe(25);
|
|
||||||
|
|
||||||
expect(summary[0].dismissed.count).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getElementSummary handles CSAT question with dismissed responses", async () => {
|
|
||||||
const question = {
|
|
||||||
id: "csat-q1",
|
|
||||||
type: TSurveyElementTypeEnum.CSAT,
|
|
||||||
headline: { default: "How satisfied are you?" },
|
|
||||||
required: false,
|
|
||||||
scale: "smiley",
|
|
||||||
range: 5,
|
|
||||||
lowerLabel: { default: "Very unsatisfied" },
|
|
||||||
upperLabel: { default: "Very satisfied" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const survey = {
|
|
||||||
id: "survey-1",
|
|
||||||
blocks: [{ id: "block1", name: "Block 1", elements: [question] }],
|
|
||||||
questions: [],
|
|
||||||
languages: [],
|
|
||||||
welcomeCard: { enabled: false },
|
|
||||||
} as unknown as TSurvey;
|
|
||||||
|
|
||||||
const responses = [
|
|
||||||
{
|
|
||||||
id: "response-1",
|
|
||||||
data: { "csat-q1": 5 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: { "csat-q1": 3 },
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "response-2",
|
|
||||||
data: {},
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: { "csat-q1": 2 },
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "response-3",
|
|
||||||
data: {},
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: { "csat-q1": 4 },
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
] as any;
|
|
||||||
|
|
||||||
const dropOff = [
|
|
||||||
{ elementId: "csat-q1", impressions: 3, dropOffCount: 0, dropOffPercentage: 0 },
|
|
||||||
] as unknown as TSurveySummary["dropOff"];
|
|
||||||
|
|
||||||
const summary: any = await getElementSummary(
|
|
||||||
survey,
|
|
||||||
getElementsFromBlocks(survey.blocks),
|
|
||||||
responses,
|
|
||||||
dropOff
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(summary).toHaveLength(1);
|
|
||||||
expect(summary[0].type).toBe(TSurveyElementTypeEnum.CSAT);
|
|
||||||
expect(summary[0].responseCount).toBe(1);
|
|
||||||
expect(summary[0].average).toBe(5);
|
|
||||||
expect(summary[0].dismissed.count).toBe(2);
|
|
||||||
expect(summary[0].csat.satisfiedCount).toBe(1);
|
|
||||||
expect(summary[0].csat.satisfiedPercentage).toBe(100);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getElementSummary handles CSAT question with no valid responses", async () => {
|
|
||||||
const question = {
|
|
||||||
id: "csat-q1",
|
|
||||||
type: TSurveyElementTypeEnum.CSAT,
|
|
||||||
headline: { default: "How satisfied are you?" },
|
|
||||||
required: true,
|
|
||||||
scale: "smiley",
|
|
||||||
range: 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
const survey = {
|
|
||||||
id: "survey-1",
|
|
||||||
blocks: [{ id: "block1", name: "Block 1", elements: [question] }],
|
|
||||||
questions: [],
|
|
||||||
languages: [],
|
|
||||||
welcomeCard: { enabled: false },
|
|
||||||
} as unknown as TSurvey;
|
|
||||||
|
|
||||||
const responses = [
|
|
||||||
{
|
|
||||||
id: "response-1",
|
|
||||||
data: { "other-q": "value" },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const dropOff = [
|
|
||||||
{ elementId: "csat-q1", impressions: 1, dropOffCount: 1, dropOffPercentage: 100 },
|
|
||||||
] as unknown as TSurveySummary["dropOff"];
|
|
||||||
|
|
||||||
const summary: any = await getElementSummary(
|
|
||||||
survey,
|
|
||||||
getElementsFromBlocks(survey.blocks),
|
|
||||||
responses,
|
|
||||||
dropOff
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(summary).toHaveLength(1);
|
|
||||||
expect(summary[0].type).toBe(TSurveyElementTypeEnum.CSAT);
|
|
||||||
expect(summary[0].responseCount).toBe(0);
|
|
||||||
expect(summary[0].average).toBe(0);
|
|
||||||
expect(summary[0].csat.satisfiedCount).toBe(0);
|
|
||||||
expect(summary[0].csat.satisfiedPercentage).toBe(0);
|
|
||||||
expect(summary[0].choices.every((c: any) => c.count === 0)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getElementSummary CSAT correctly identifies satisfied ratings (4 and 5 only)", async () => {
|
|
||||||
const question = {
|
|
||||||
id: "csat-q1",
|
|
||||||
type: TSurveyElementTypeEnum.CSAT,
|
|
||||||
headline: { default: "How satisfied are you?" },
|
|
||||||
required: true,
|
|
||||||
scale: "smiley",
|
|
||||||
range: 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
const survey = {
|
|
||||||
id: "survey-1",
|
|
||||||
blocks: [{ id: "block1", name: "Block 1", elements: [question] }],
|
|
||||||
questions: [],
|
|
||||||
languages: [],
|
|
||||||
welcomeCard: { enabled: false },
|
|
||||||
} as unknown as TSurvey;
|
|
||||||
|
|
||||||
// 3 satisfied (4,5,5), 2 not satisfied (1,3)
|
|
||||||
const responses = [
|
|
||||||
{
|
|
||||||
id: "r1",
|
|
||||||
data: { "csat-q1": 5 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "r2",
|
|
||||||
data: { "csat-q1": 4 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "r3",
|
|
||||||
data: { "csat-q1": 3 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "r4",
|
|
||||||
data: { "csat-q1": 1 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "r5",
|
|
||||||
data: { "csat-q1": 5 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const dropOff = [
|
|
||||||
{ elementId: "csat-q1", impressions: 5, dropOffCount: 0, dropOffPercentage: 0 },
|
|
||||||
] as unknown as TSurveySummary["dropOff"];
|
|
||||||
|
|
||||||
const summary: any = await getElementSummary(
|
|
||||||
survey,
|
|
||||||
getElementsFromBlocks(survey.blocks),
|
|
||||||
responses,
|
|
||||||
dropOff
|
|
||||||
);
|
|
||||||
|
|
||||||
// satisfied = ratings 4 and 5 = 3 out of 5
|
|
||||||
expect(summary[0].csat.satisfiedCount).toBe(3);
|
|
||||||
expect(summary[0].csat.satisfiedPercentage).toBe(60);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("CES question type tests", () => {
|
|
||||||
test("getElementSummary correctly processes CES question with valid responses (range 5)", async () => {
|
|
||||||
const question = {
|
|
||||||
id: "ces-q1",
|
|
||||||
type: TSurveyElementTypeEnum.CES,
|
|
||||||
headline: { default: "How easy was it?" },
|
|
||||||
required: true,
|
|
||||||
scale: "number",
|
|
||||||
range: 5,
|
|
||||||
lowerLabel: { default: "Very difficult" },
|
|
||||||
upperLabel: { default: "Very easy" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const survey = {
|
|
||||||
id: "survey-1",
|
|
||||||
blocks: [{ id: "block1", name: "Block 1", elements: [question] }],
|
|
||||||
questions: [],
|
|
||||||
languages: [],
|
|
||||||
welcomeCard: { enabled: false },
|
|
||||||
} as unknown as TSurvey;
|
|
||||||
|
|
||||||
const responses = [
|
|
||||||
{
|
|
||||||
id: "response-1",
|
|
||||||
data: { "ces-q1": 5 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "response-2",
|
|
||||||
data: { "ces-q1": 4 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "response-3",
|
|
||||||
data: { "ces-q1": 2 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "response-4",
|
|
||||||
data: { "ces-q1": 3 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const dropOff = [
|
|
||||||
{ elementId: "ces-q1", impressions: 4, dropOffCount: 0, dropOffPercentage: 0 },
|
|
||||||
] as unknown as TSurveySummary["dropOff"];
|
|
||||||
|
|
||||||
const summary: any = await getElementSummary(
|
|
||||||
survey,
|
|
||||||
getElementsFromBlocks(survey.blocks),
|
|
||||||
responses,
|
|
||||||
dropOff
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(summary).toHaveLength(1);
|
|
||||||
expect(summary[0].type).toBe(TSurveyElementTypeEnum.CES);
|
|
||||||
expect(summary[0].responseCount).toBe(4);
|
|
||||||
|
|
||||||
// CES = average = (5 + 4 + 2 + 3) / 4 = 3.5
|
|
||||||
expect(summary[0].average).toBe(3.5);
|
|
||||||
|
|
||||||
// Verify choice distribution
|
|
||||||
const rating5 = summary[0].choices.find((c: any) => c.rating === 5);
|
|
||||||
expect(rating5.count).toBe(1);
|
|
||||||
expect(rating5.percentage).toBe(25);
|
|
||||||
|
|
||||||
const rating4 = summary[0].choices.find((c: any) => c.rating === 4);
|
|
||||||
expect(rating4.count).toBe(1);
|
|
||||||
expect(rating4.percentage).toBe(25);
|
|
||||||
|
|
||||||
const rating3 = summary[0].choices.find((c: any) => c.rating === 3);
|
|
||||||
expect(rating3.count).toBe(1);
|
|
||||||
expect(rating3.percentage).toBe(25);
|
|
||||||
|
|
||||||
const rating2 = summary[0].choices.find((c: any) => c.rating === 2);
|
|
||||||
expect(rating2.count).toBe(1);
|
|
||||||
expect(rating2.percentage).toBe(25);
|
|
||||||
|
|
||||||
expect(summary[0].dismissed.count).toBe(0);
|
|
||||||
|
|
||||||
// CES has no csat field
|
|
||||||
expect(summary[0].csat).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getElementSummary correctly processes CES question with range 7", async () => {
|
|
||||||
const question = {
|
|
||||||
id: "ces-q1",
|
|
||||||
type: TSurveyElementTypeEnum.CES,
|
|
||||||
headline: { default: "How easy was it?" },
|
|
||||||
required: true,
|
|
||||||
scale: "number",
|
|
||||||
range: 7,
|
|
||||||
lowerLabel: { default: "Very difficult" },
|
|
||||||
upperLabel: { default: "Very easy" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const survey = {
|
|
||||||
id: "survey-1",
|
|
||||||
blocks: [{ id: "block1", name: "Block 1", elements: [question] }],
|
|
||||||
questions: [],
|
|
||||||
languages: [],
|
|
||||||
welcomeCard: { enabled: false },
|
|
||||||
} as unknown as TSurvey;
|
|
||||||
|
|
||||||
const responses = [
|
|
||||||
{
|
|
||||||
id: "r1",
|
|
||||||
data: { "ces-q1": 7 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "r2",
|
|
||||||
data: { "ces-q1": 6 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "r3",
|
|
||||||
data: { "ces-q1": 1 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const dropOff = [
|
|
||||||
{ elementId: "ces-q1", impressions: 3, dropOffCount: 0, dropOffPercentage: 0 },
|
|
||||||
] as unknown as TSurveySummary["dropOff"];
|
|
||||||
|
|
||||||
const summary: any = await getElementSummary(
|
|
||||||
survey,
|
|
||||||
getElementsFromBlocks(survey.blocks),
|
|
||||||
responses,
|
|
||||||
dropOff
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(summary).toHaveLength(1);
|
|
||||||
expect(summary[0].type).toBe(TSurveyElementTypeEnum.CES);
|
|
||||||
expect(summary[0].responseCount).toBe(3);
|
|
||||||
|
|
||||||
// CES average = (7 + 6 + 1) / 3 = 4.67
|
|
||||||
expect(summary[0].average).toBe(4.67);
|
|
||||||
|
|
||||||
// Verify 7 choices exist (range 7)
|
|
||||||
expect(summary[0].choices).toHaveLength(7);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getElementSummary handles CES question with dismissed responses", async () => {
|
|
||||||
const question = {
|
|
||||||
id: "ces-q1",
|
|
||||||
type: TSurveyElementTypeEnum.CES,
|
|
||||||
headline: { default: "How easy was it?" },
|
|
||||||
required: false,
|
|
||||||
scale: "number",
|
|
||||||
range: 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
const survey = {
|
|
||||||
id: "survey-1",
|
|
||||||
blocks: [{ id: "block1", name: "Block 1", elements: [question] }],
|
|
||||||
questions: [],
|
|
||||||
languages: [],
|
|
||||||
welcomeCard: { enabled: false },
|
|
||||||
} as unknown as TSurvey;
|
|
||||||
|
|
||||||
const responses = [
|
|
||||||
{
|
|
||||||
id: "response-1",
|
|
||||||
data: { "ces-q1": 3 },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: { "ces-q1": 5 },
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "response-2",
|
|
||||||
data: {},
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: { "ces-q1": 2 },
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
] as any;
|
|
||||||
|
|
||||||
const dropOff = [
|
|
||||||
{ elementId: "ces-q1", impressions: 2, dropOffCount: 0, dropOffPercentage: 0 },
|
|
||||||
] as unknown as TSurveySummary["dropOff"];
|
|
||||||
|
|
||||||
const summary: any = await getElementSummary(
|
|
||||||
survey,
|
|
||||||
getElementsFromBlocks(survey.blocks),
|
|
||||||
responses,
|
|
||||||
dropOff
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(summary).toHaveLength(1);
|
|
||||||
expect(summary[0].type).toBe(TSurveyElementTypeEnum.CES);
|
|
||||||
expect(summary[0].responseCount).toBe(1);
|
|
||||||
expect(summary[0].average).toBe(3);
|
|
||||||
expect(summary[0].dismissed.count).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getElementSummary handles CES question with no valid responses", async () => {
|
|
||||||
const question = {
|
|
||||||
id: "ces-q1",
|
|
||||||
type: TSurveyElementTypeEnum.CES,
|
|
||||||
headline: { default: "How easy was it?" },
|
|
||||||
required: true,
|
|
||||||
scale: "number",
|
|
||||||
range: 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
const survey = {
|
|
||||||
id: "survey-1",
|
|
||||||
blocks: [{ id: "block1", name: "Block 1", elements: [question] }],
|
|
||||||
questions: [],
|
|
||||||
languages: [],
|
|
||||||
welcomeCard: { enabled: false },
|
|
||||||
} as unknown as TSurvey;
|
|
||||||
|
|
||||||
const responses = [
|
|
||||||
{
|
|
||||||
id: "response-1",
|
|
||||||
data: { "other-q": "value" },
|
|
||||||
updatedAt: new Date(),
|
|
||||||
contact: null,
|
|
||||||
contactAttributes: {},
|
|
||||||
language: null,
|
|
||||||
ttc: {},
|
|
||||||
finished: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const dropOff = [
|
|
||||||
{ elementId: "ces-q1", impressions: 1, dropOffCount: 1, dropOffPercentage: 100 },
|
|
||||||
] as unknown as TSurveySummary["dropOff"];
|
|
||||||
|
|
||||||
const summary: any = await getElementSummary(
|
|
||||||
survey,
|
|
||||||
getElementsFromBlocks(survey.blocks),
|
|
||||||
responses,
|
|
||||||
dropOff
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(summary).toHaveLength(1);
|
|
||||||
expect(summary[0].type).toBe(TSurveyElementTypeEnum.CES);
|
|
||||||
expect(summary[0].responseCount).toBe(0);
|
|
||||||
expect(summary[0].average).toBe(0);
|
|
||||||
expect(summary[0].choices.every((c: any) => c.count === 0)).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
+62
-82
@@ -25,6 +25,7 @@ import {
|
|||||||
TSurveyElementSummaryOpenText,
|
TSurveyElementSummaryOpenText,
|
||||||
TSurveyElementSummaryPictureSelection,
|
TSurveyElementSummaryPictureSelection,
|
||||||
TSurveyElementSummaryRanking,
|
TSurveyElementSummaryRanking,
|
||||||
|
TSurveyElementSummaryRating,
|
||||||
TSurveyLanguage,
|
TSurveyLanguage,
|
||||||
TSurveySummary,
|
TSurveySummary,
|
||||||
} from "@formbricks/types/surveys/types";
|
} from "@formbricks/types/surveys/types";
|
||||||
@@ -271,49 +272,6 @@ const checkForI18n = (
|
|||||||
return responseData[id];
|
return responseData[id];
|
||||||
};
|
};
|
||||||
|
|
||||||
const computeNumericScaleStats = (
|
|
||||||
elementId: string,
|
|
||||||
range: number,
|
|
||||||
responses: TSurveySummaryResponse[]
|
|
||||||
): {
|
|
||||||
choices: { rating: number; count: number; percentage: number }[];
|
|
||||||
choiceCountMap: Record<number, number>;
|
|
||||||
totalResponseCount: number;
|
|
||||||
totalRating: number;
|
|
||||||
dismissed: number;
|
|
||||||
average: number;
|
|
||||||
} => {
|
|
||||||
const choiceCountMap: Record<number, number> = {};
|
|
||||||
for (let i = 1; i <= range; i++) {
|
|
||||||
choiceCountMap[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let totalResponseCount = 0;
|
|
||||||
let totalRating = 0;
|
|
||||||
let dismissed = 0;
|
|
||||||
|
|
||||||
responses.forEach((response) => {
|
|
||||||
const answer = response.data[elementId];
|
|
||||||
if (typeof answer === "number") {
|
|
||||||
totalResponseCount++;
|
|
||||||
choiceCountMap[answer]++;
|
|
||||||
totalRating += answer;
|
|
||||||
} else if (response.ttc && response.ttc[elementId] > 0) {
|
|
||||||
dismissed++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const choices = Object.entries(choiceCountMap).map(([label, count]) => ({
|
|
||||||
rating: Number.parseInt(label),
|
|
||||||
count,
|
|
||||||
percentage: totalResponseCount > 0 ? convertFloatTo2Decimal((count / totalResponseCount) * 100) : 0,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const average = totalResponseCount > 0 ? convertFloatTo2Decimal(totalRating / totalResponseCount) : 0;
|
|
||||||
|
|
||||||
return { choices, choiceCountMap, totalResponseCount, totalRating, dismissed, average };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getElementSummary = async (
|
export const getElementSummary = async (
|
||||||
survey: TSurvey,
|
survey: TSurvey,
|
||||||
elements: TSurveyElement[],
|
elements: TSurveyElement[],
|
||||||
@@ -514,16 +472,72 @@ export const getElementSummary = async (
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TSurveyElementTypeEnum.Rating: {
|
case TSurveyElementTypeEnum.Rating: {
|
||||||
const stats = computeNumericScaleStats(element.id, element.range, responses);
|
let values: TSurveyElementSummaryRating["choices"] = [];
|
||||||
|
const choiceCountMap: Record<number, number> = {};
|
||||||
|
const range = element.range;
|
||||||
|
|
||||||
|
for (let i = 1; i <= range; i++) {
|
||||||
|
choiceCountMap[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let totalResponseCount = 0;
|
||||||
|
let totalRating = 0;
|
||||||
|
let dismissed = 0;
|
||||||
|
|
||||||
|
responses.forEach((response) => {
|
||||||
|
const answer = response.data[element.id];
|
||||||
|
if (typeof answer === "number") {
|
||||||
|
totalResponseCount++;
|
||||||
|
choiceCountMap[answer]++;
|
||||||
|
totalRating += answer;
|
||||||
|
} else if (response.ttc && response.ttc[element.id] > 0) {
|
||||||
|
dismissed++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.entries(choiceCountMap).forEach(([label, count]) => {
|
||||||
|
values.push({
|
||||||
|
rating: Number.parseInt(label),
|
||||||
|
count,
|
||||||
|
percentage:
|
||||||
|
totalResponseCount > 0 ? convertFloatTo2Decimal((count / totalResponseCount) * 100) : 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Calculate CSAT based on range
|
||||||
|
let satisfiedCount = 0;
|
||||||
|
if (range === 3) {
|
||||||
|
satisfiedCount = choiceCountMap[3] || 0;
|
||||||
|
} else if (range === 4) {
|
||||||
|
satisfiedCount = (choiceCountMap[3] || 0) + (choiceCountMap[4] || 0);
|
||||||
|
} else if (range === 5) {
|
||||||
|
satisfiedCount = (choiceCountMap[4] || 0) + (choiceCountMap[5] || 0);
|
||||||
|
} else if (range === 6) {
|
||||||
|
satisfiedCount = (choiceCountMap[5] || 0) + (choiceCountMap[6] || 0);
|
||||||
|
} else if (range === 7) {
|
||||||
|
satisfiedCount = (choiceCountMap[6] || 0) + (choiceCountMap[7] || 0);
|
||||||
|
} else if (range === 10) {
|
||||||
|
satisfiedCount = (choiceCountMap[8] || 0) + (choiceCountMap[9] || 0) + (choiceCountMap[10] || 0);
|
||||||
|
}
|
||||||
|
const satisfiedPercentage =
|
||||||
|
totalResponseCount > 0 ? Math.round((satisfiedCount / totalResponseCount) * 100) : 0;
|
||||||
|
|
||||||
summary.push({
|
summary.push({
|
||||||
type: element.type,
|
type: element.type,
|
||||||
element,
|
element,
|
||||||
average: stats.average,
|
average: convertFloatTo2Decimal(totalRating / totalResponseCount) || 0,
|
||||||
responseCount: stats.totalResponseCount,
|
responseCount: totalResponseCount,
|
||||||
choices: stats.choices,
|
choices: values,
|
||||||
dismissed: { count: stats.dismissed },
|
dismissed: {
|
||||||
|
count: dismissed,
|
||||||
|
},
|
||||||
|
csat: {
|
||||||
|
satisfiedCount,
|
||||||
|
satisfiedPercentage,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
values = [];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TSurveyElementTypeEnum.NPS: {
|
case TSurveyElementTypeEnum.NPS: {
|
||||||
@@ -598,40 +612,6 @@ export const getElementSummary = async (
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TSurveyElementTypeEnum.CSAT: {
|
|
||||||
const stats = computeNumericScaleStats(element.id, element.range, responses);
|
|
||||||
|
|
||||||
// CSAT: top 2 ratings out of 5 are "satisfied"
|
|
||||||
const satisfiedCount = (stats.choiceCountMap[4] || 0) + (stats.choiceCountMap[5] || 0);
|
|
||||||
const satisfiedPercentage =
|
|
||||||
stats.totalResponseCount > 0
|
|
||||||
? convertFloatTo2Decimal((satisfiedCount / stats.totalResponseCount) * 100)
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
summary.push({
|
|
||||||
type: element.type,
|
|
||||||
element,
|
|
||||||
average: stats.average,
|
|
||||||
responseCount: stats.totalResponseCount,
|
|
||||||
choices: stats.choices,
|
|
||||||
dismissed: { count: stats.dismissed },
|
|
||||||
csat: { satisfiedCount, satisfiedPercentage },
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TSurveyElementTypeEnum.CES: {
|
|
||||||
const stats = computeNumericScaleStats(element.id, element.range, responses);
|
|
||||||
|
|
||||||
summary.push({
|
|
||||||
type: element.type,
|
|
||||||
element,
|
|
||||||
average: stats.average,
|
|
||||||
responseCount: stats.totalResponseCount,
|
|
||||||
choices: stats.choices,
|
|
||||||
dismissed: { count: stats.dismissed },
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TSurveyElementTypeEnum.CTA: {
|
case TSurveyElementTypeEnum.CTA: {
|
||||||
// Only calculate summary for CTA elements with external buttons (CTR tracking is only meaningful for external links)
|
// Only calculate summary for CTA elements with external buttons (CTR tracking is only meaningful for external links)
|
||||||
if (!element.buttonExternal) {
|
if (!element.buttonExternal) {
|
||||||
|
|||||||
+10
-8
@@ -4,6 +4,7 @@ import { useRouter } from "next/navigation";
|
|||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||||
|
import { useWorkspaceContext } from "@/app/(app)/workspaces/[workspaceId]/context/workspace-context";
|
||||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||||
import { updateSurveyAction } from "@/modules/survey/editor/actions";
|
import { updateSurveyAction } from "@/modules/survey/editor/actions";
|
||||||
import {
|
import {
|
||||||
@@ -21,19 +22,18 @@ interface SurveyStatusDropdownProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SurveyStatusDropdown = ({ updateLocalSurveyStatus, survey }: SurveyStatusDropdownProps) => {
|
export const SurveyStatusDropdown = ({ updateLocalSurveyStatus, survey }: SurveyStatusDropdownProps) => {
|
||||||
|
const { workspace } = useWorkspaceContext();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const isScheduled = survey.status === "paused" && survey.publishOn !== null;
|
|
||||||
|
|
||||||
const handleStatusChange = async (status: TSurvey["status"]) => {
|
const handleStatusChange = async (status: TSurvey["status"]) => {
|
||||||
const updateSurveyActionResponse = await updateSurveyAction({ ...survey, status });
|
const updateSurveyActionResponse = await updateSurveyAction({ ...survey, status });
|
||||||
|
|
||||||
if (updateSurveyActionResponse?.data) {
|
if (updateSurveyActionResponse?.data) {
|
||||||
const { publishOn, status: resultingStatus } = updateSurveyActionResponse.data;
|
const resultingStatus = updateSurveyActionResponse.data.status;
|
||||||
const isResultScheduled = resultingStatus === "paused" && publishOn !== null;
|
|
||||||
const statusToToastMessage: Partial<Record<TSurvey["status"], string>> = {
|
const statusToToastMessage: Partial<Record<TSurvey["status"], string>> = {
|
||||||
inProgress: t("common.survey_live"),
|
inProgress: t("common.survey_live"),
|
||||||
paused: isResultScheduled ? t("common.survey_scheduled") : t("common.survey_paused"),
|
paused: t("common.survey_paused"),
|
||||||
completed: t("common.survey_completed"),
|
completed: t("common.survey_completed"),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -68,10 +68,12 @@ export const SurveyStatusDropdown = ({ updateLocalSurveyStatus, survey }: Survey
|
|||||||
<SelectTrigger className="w-[170px] bg-white md:w-[200px]">
|
<SelectTrigger className="w-[170px] bg-white md:w-[200px]">
|
||||||
<SelectValue>
|
<SelectValue>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<SurveyStatusIndicator status={survey.status} isScheduled={isScheduled} />
|
{(survey.type === "link" || workspace.appSetupCompleted) && (
|
||||||
|
<SurveyStatusIndicator status={survey.status} />
|
||||||
|
)}
|
||||||
<span className="ml-2 text-sm text-slate-700">
|
<span className="ml-2 text-sm text-slate-700">
|
||||||
{survey.status === "inProgress" && t("common.in_progress")}
|
{survey.status === "inProgress" && t("common.in_progress")}
|
||||||
{survey.status === "paused" && (isScheduled ? t("common.scheduled") : t("common.paused"))}
|
{survey.status === "paused" && t("common.paused")}
|
||||||
{survey.status === "completed" && t("common.completed")}
|
{survey.status === "completed" && t("common.completed")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,8 +88,8 @@ export const SurveyStatusDropdown = ({ updateLocalSurveyStatus, survey }: Survey
|
|||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem className="group font-normal hover:text-slate-900" value="paused">
|
<SelectItem className="group font-normal hover:text-slate-900" value="paused">
|
||||||
<div className="flex w-full items-center justify-center gap-2">
|
<div className="flex w-full items-center justify-center gap-2">
|
||||||
<SurveyStatusIndicator status={"paused"} isScheduled={isScheduled} />
|
<SurveyStatusIndicator status={"paused"} />
|
||||||
{isScheduled ? t("common.scheduled") : t("common.paused")}
|
{t("common.paused")}
|
||||||
</div>
|
</div>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem className="group font-normal hover:text-slate-900" value="completed">
|
<SelectItem className="group font-normal hover:text-slate-900" value="completed">
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
import { type ReactNode } from "react";
|
|
||||||
import { SurveysQueryClientProvider } from "./query-client-provider";
|
|
||||||
|
|
||||||
const SurveysLayout = ({ children }: { children: ReactNode }) => {
|
|
||||||
return <SurveysQueryClientProvider>{children}</SurveysQueryClientProvider>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SurveysLayout;
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
||||||
import { type ReactNode, useState } from "react";
|
|
||||||
|
|
||||||
export const SurveysQueryClientProvider = ({ children }: { children: ReactNode }) => {
|
|
||||||
const [queryClient] = useState(() => new QueryClient());
|
|
||||||
|
|
||||||
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
|
||||||
};
|
|
||||||
+3
-13
@@ -9,18 +9,14 @@ import { FeedbackRecordsTable } from "./feedback-records-table";
|
|||||||
|
|
||||||
interface FeedbackRecordsPageClientProps {
|
interface FeedbackRecordsPageClientProps {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
directories: { id: string; name: string }[];
|
|
||||||
initialFrdId: string | null;
|
|
||||||
initialRecords: FeedbackRecordData[];
|
initialRecords: FeedbackRecordData[];
|
||||||
initialNextCursor?: string;
|
frdMap: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FeedbackRecordsPageClient({
|
export function FeedbackRecordsPageClient({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
directories,
|
|
||||||
initialFrdId,
|
|
||||||
initialRecords,
|
initialRecords,
|
||||||
initialNextCursor,
|
frdMap,
|
||||||
}: FeedbackRecordsPageClientProps) {
|
}: FeedbackRecordsPageClientProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -30,13 +26,7 @@ export function FeedbackRecordsPageClient({
|
|||||||
<UnifyConfigNavigation workspaceId={workspaceId} activeId="feedback-records" />
|
<UnifyConfigNavigation workspaceId={workspaceId} activeId="feedback-records" />
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<FeedbackRecordsTable
|
<FeedbackRecordsTable workspaceId={workspaceId} initialRecords={initialRecords} frdMap={frdMap} />
|
||||||
workspaceId={workspaceId}
|
|
||||||
directories={directories}
|
|
||||||
initialFrdId={initialFrdId}
|
|
||||||
initialRecords={initialRecords}
|
|
||||||
initialNextCursor={initialNextCursor}
|
|
||||||
/>
|
|
||||||
</PageContentWrapper>
|
</PageContentWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-122
@@ -9,7 +9,7 @@ import {
|
|||||||
ToggleLeftIcon,
|
ToggleLeftIcon,
|
||||||
TypeIcon,
|
TypeIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useCallback, useState } from "react";
|
import { useState } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { listFeedbackRecordsAction } from "@/lib/connector/actions";
|
import { listFeedbackRecordsAction } from "@/lib/connector/actions";
|
||||||
@@ -18,14 +18,6 @@ import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
|||||||
import type { FeedbackRecordData } from "@/modules/hub/types";
|
import type { FeedbackRecordData } from "@/modules/hub/types";
|
||||||
import { Badge } from "@/modules/ui/components/badge";
|
import { Badge } from "@/modules/ui/components/badge";
|
||||||
import { Button } from "@/modules/ui/components/button";
|
import { Button } from "@/modules/ui/components/button";
|
||||||
import { Label } from "@/modules/ui/components/label";
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/modules/ui/components/select";
|
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/modules/ui/components/tooltip";
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/modules/ui/components/tooltip";
|
||||||
|
|
||||||
const RECORDS_PER_PAGE = 50;
|
const RECORDS_PER_PAGE = 50;
|
||||||
@@ -57,96 +49,41 @@ function truncate(str: string, maxLen: number): string {
|
|||||||
|
|
||||||
interface FeedbackRecordsTableProps {
|
interface FeedbackRecordsTableProps {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
directories: { id: string; name: string }[];
|
|
||||||
initialFrdId: string | null;
|
|
||||||
initialRecords: FeedbackRecordData[];
|
initialRecords: FeedbackRecordData[];
|
||||||
initialNextCursor?: string;
|
frdMap: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FeedbackRecordsTable = ({
|
export const FeedbackRecordsTable = ({ workspaceId, initialRecords, frdMap }: FeedbackRecordsTableProps) => {
|
||||||
workspaceId,
|
|
||||||
directories,
|
|
||||||
initialFrdId,
|
|
||||||
initialRecords,
|
|
||||||
initialNextCursor,
|
|
||||||
}: FeedbackRecordsTableProps) => {
|
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const locale = i18n.resolvedLanguage ?? i18n.language ?? "en-US";
|
|
||||||
const [selectedFrdId, setSelectedFrdId] = useState<string | null>(initialFrdId);
|
|
||||||
const [records, setRecords] = useState<FeedbackRecordData[]>(initialRecords);
|
const [records, setRecords] = useState<FeedbackRecordData[]>(initialRecords);
|
||||||
const [nextCursor, setNextCursor] = useState<string | undefined>(initialNextCursor);
|
|
||||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||||
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const fetchRecords = useCallback(
|
|
||||||
async (frdId: string, cursor: string | undefined, append: boolean): Promise<string | null> => {
|
|
||||||
const setLoading = append ? setIsLoadingMore : setIsRefreshing;
|
|
||||||
setLoading(true);
|
|
||||||
setError(null);
|
|
||||||
|
|
||||||
const result = await listFeedbackRecordsAction({
|
|
||||||
workspaceId,
|
|
||||||
frdId,
|
|
||||||
limit: RECORDS_PER_PAGE,
|
|
||||||
cursor,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result?.data) {
|
|
||||||
const message =
|
|
||||||
getFormattedErrorMessage(result) ?? t("workspace.unify.failed_to_load_feedback_records");
|
|
||||||
setError(message);
|
|
||||||
setLoading(false);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = result.data;
|
|
||||||
setRecords((prev) => (append ? [...prev, ...response.data] : response.data));
|
|
||||||
setNextCursor(response.next_cursor);
|
|
||||||
setLoading(false);
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
[workspaceId, t]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleFrdChange = (frdId: string) => {
|
|
||||||
setSelectedFrdId(frdId);
|
|
||||||
setRecords([]);
|
|
||||||
setNextCursor(undefined);
|
|
||||||
fetchRecords(frdId, undefined, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLoadMore = () => {
|
|
||||||
if (!selectedFrdId) return;
|
|
||||||
fetchRecords(selectedFrdId, nextCursor, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRefresh = async () => {
|
const handleRefresh = async () => {
|
||||||
if (!selectedFrdId || isRefreshing) return;
|
if (isRefreshing) return;
|
||||||
|
setIsRefreshing(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
const toastId = toast.loading(t("workspace.unify.refreshing_feedback_records"));
|
const toastId = toast.loading(t("workspace.unify.refreshing_feedback_records"));
|
||||||
const errorMessage = await fetchRecords(selectedFrdId, undefined, false);
|
|
||||||
if (errorMessage) {
|
const result = await listFeedbackRecordsAction({
|
||||||
toast.error(errorMessage, { id: toastId });
|
workspaceId,
|
||||||
|
limit: RECORDS_PER_PAGE,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result?.data) {
|
||||||
|
toast.error(getFormattedErrorMessage(result) ?? t("workspace.unify.failed_to_load_feedback_records"), {
|
||||||
|
id: toastId,
|
||||||
|
});
|
||||||
|
setIsRefreshing(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setRecords(result.data.data);
|
||||||
|
setIsRefreshing(false);
|
||||||
toast.success(t("workspace.unify.feedback_records_refreshed"), { id: toastId });
|
toast.success(t("workspace.unify.feedback_records_refreshed"), { id: toastId });
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasMore = !!nextCursor;
|
|
||||||
const isEmpty = records.length === 0 && !isRefreshing;
|
|
||||||
const currentFrdName = directories.find((d) => d.id === selectedFrdId)?.name ?? "—";
|
|
||||||
|
|
||||||
if (directories.length === 0) {
|
|
||||||
return (
|
|
||||||
<div className="rounded-xl border border-dashed border-slate-200 bg-slate-50 p-8 text-center">
|
|
||||||
<MessageSquareTextIcon className="mx-auto h-8 w-8 text-slate-400" />
|
|
||||||
<p className="mt-2 text-sm text-slate-500">
|
|
||||||
{t("workspace.unify.no_feedback_record_directory_available")}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="rounded-xl border border-slate-200 bg-white shadow-sm">
|
||||||
@@ -161,35 +98,15 @@ export const FeedbackRecordsTable = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isEmpty = records.length === 0 && !isRefreshing;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex flex-wrap items-end justify-between gap-3">
|
{!isEmpty && (
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex items-center justify-between">
|
||||||
<Label>{t("workspace.unify.feedback_record_directory")}</Label>
|
<p className="text-sm text-slate-500">
|
||||||
{directories.length === 1 ? (
|
{t("workspace.unify.showing_count_loaded", { count: records.length })}
|
||||||
<p className="text-sm font-medium text-slate-900">{currentFrdName}</p>
|
</p>
|
||||||
) : (
|
|
||||||
<Select value={selectedFrdId ?? ""} onValueChange={handleFrdChange}>
|
|
||||||
<SelectTrigger className="min-w-[220px]">
|
|
||||||
<SelectValue placeholder={t("workspace.unify.select_feedback_record_directory")} />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
{directories.map((d) => (
|
|
||||||
<SelectItem key={d.id} value={d.id}>
|
|
||||||
{d.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
{!isEmpty && (
|
|
||||||
<p className="text-sm text-slate-500">
|
|
||||||
{t("workspace.unify.showing_count_loaded", { count: records.length })}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -199,7 +116,7 @@ export const FeedbackRecordsTable = ({
|
|||||||
<RefreshCwIcon className="h-3.5 w-3.5" aria-hidden="true" />
|
<RefreshCwIcon className="h-3.5 w-3.5" aria-hidden="true" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
<div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
@@ -207,6 +124,9 @@ export const FeedbackRecordsTable = ({
|
|||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-slate-200 text-left text-sm text-slate-900 [&>th]:font-semibold">
|
<tr className="border-b border-slate-200 text-left text-sm text-slate-900 [&>th]:font-semibold">
|
||||||
<th className="whitespace-nowrap px-4 py-3">{t("workspace.unify.collected_at")}</th>
|
<th className="whitespace-nowrap px-4 py-3">{t("workspace.unify.collected_at")}</th>
|
||||||
|
<th className="whitespace-nowrap px-4 py-3">
|
||||||
|
{t("workspace.unify.feedback_record_directory")}
|
||||||
|
</th>
|
||||||
<th className="whitespace-nowrap px-4 py-3">{t("workspace.unify.source_type")}</th>
|
<th className="whitespace-nowrap px-4 py-3">{t("workspace.unify.source_type")}</th>
|
||||||
<th className="whitespace-nowrap px-4 py-3">{t("workspace.unify.source_name")}</th>
|
<th className="whitespace-nowrap px-4 py-3">{t("workspace.unify.source_name")}</th>
|
||||||
<th className="whitespace-nowrap px-4 py-3">{t("workspace.unify.field_label")}</th>
|
<th className="whitespace-nowrap px-4 py-3">{t("workspace.unify.field_label")}</th>
|
||||||
@@ -218,7 +138,7 @@ export const FeedbackRecordsTable = ({
|
|||||||
{isEmpty ? (
|
{isEmpty ? (
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={7}>
|
<td colSpan={8}>
|
||||||
<div className="flex h-32 items-center justify-center">
|
<div className="flex h-32 items-center justify-center">
|
||||||
<p className="text-sm text-slate-500">{t("workspace.unify.no_feedback_records")}</p>
|
<p className="text-sm text-slate-500">{t("workspace.unify.no_feedback_records")}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -228,21 +148,19 @@ export const FeedbackRecordsTable = ({
|
|||||||
) : (
|
) : (
|
||||||
<tbody className="divide-y divide-slate-100">
|
<tbody className="divide-y divide-slate-100">
|
||||||
{records.map((record) => (
|
{records.map((record) => (
|
||||||
<FeedbackRecordRow key={record.id} record={record} locale={locale} t={t} />
|
<FeedbackRecordRow
|
||||||
|
key={record.id}
|
||||||
|
record={record}
|
||||||
|
locale={i18n.resolvedLanguage ?? i18n.language ?? "en-US"}
|
||||||
|
frdName={record.tenant_id ? (frdMap[record.tenant_id] ?? "—") : "—"}
|
||||||
|
t={t}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
)}
|
)}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasMore && (
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<Button variant="secondary" size="sm" onClick={handleLoadMore} loading={isLoadingMore}>
|
|
||||||
{t("common.load_more")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -250,10 +168,12 @@ export const FeedbackRecordsTable = ({
|
|||||||
const FeedbackRecordRow = ({
|
const FeedbackRecordRow = ({
|
||||||
record,
|
record,
|
||||||
locale,
|
locale,
|
||||||
|
frdName,
|
||||||
t,
|
t,
|
||||||
}: {
|
}: {
|
||||||
record: FeedbackRecordData;
|
record: FeedbackRecordData;
|
||||||
locale: string;
|
locale: string;
|
||||||
|
frdName: string;
|
||||||
t: TFunction;
|
t: TFunction;
|
||||||
}) => {
|
}) => {
|
||||||
const value = formatValue(record, t, locale);
|
const value = formatValue(record, t, locale);
|
||||||
@@ -264,6 +184,9 @@ const FeedbackRecordRow = ({
|
|||||||
<td className="whitespace-nowrap px-4 py-3 text-slate-500">
|
<td className="whitespace-nowrap px-4 py-3 text-slate-500">
|
||||||
{formatDateTimeForDisplay(new Date(record.collected_at), locale)}
|
{formatDateTimeForDisplay(new Date(record.collected_at), locale)}
|
||||||
</td>
|
</td>
|
||||||
|
<td className="max-w-[200px] truncate px-4 py-3 text-slate-600" title={frdName}>
|
||||||
|
{frdName}
|
||||||
|
</td>
|
||||||
<td className="whitespace-nowrap px-4 py-3">
|
<td className="whitespace-nowrap px-4 py-3">
|
||||||
<Badge text={record.source_type} type="gray" size="tiny" />
|
<Badge text={record.source_type} type="gray" size="tiny" />
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getTranslate } from "@/lingodotdev/server";
|
import { getTranslate } from "@/lingodotdev/server";
|
||||||
import { getFeedbackRecordDirectoriesByWorkspaceId } from "@/modules/ee/feedback-record-directory/lib/feedback-record-directory";
|
import { getFeedbackRecordDirectoriesByWorkspaceId } from "@/modules/ee/feedback-record-directory/lib/feedback-record-directory";
|
||||||
import { FeedbackRecordListResponse } from "@/modules/hub";
|
|
||||||
import { listFeedbackRecords } from "@/modules/hub/service";
|
import { listFeedbackRecords } from "@/modules/hub/service";
|
||||||
import { getWorkspaceAuth } from "@/modules/workspaces/lib/utils";
|
import { getWorkspaceAuth } from "@/modules/workspaces/lib/utils";
|
||||||
import { FeedbackRecordsPageClient } from "./feedback-records-page-client";
|
import { FeedbackRecordsPageClient } from "./feedback-records-page-client";
|
||||||
|
|
||||||
const INITIAL_PAGE_SIZE = 10;
|
const INITIAL_PAGE_SIZE = 50;
|
||||||
|
|
||||||
export default async function UnifyFeedbackRecordsPage(props: {
|
export default async function UnifyFeedbackRecordsPage(props: { params: Promise<{ workspaceId: string }> }) {
|
||||||
readonly params: Promise<{ workspaceId: string }>;
|
|
||||||
}) {
|
|
||||||
const t = await getTranslate();
|
const t = await getTranslate();
|
||||||
const params = await props.params;
|
const params = await props.params;
|
||||||
|
|
||||||
@@ -28,25 +25,21 @@ export default async function UnifyFeedbackRecordsPage(props: {
|
|||||||
|
|
||||||
const frds = await getFeedbackRecordDirectoriesByWorkspaceId(params.workspaceId);
|
const frds = await getFeedbackRecordDirectoriesByWorkspaceId(params.workspaceId);
|
||||||
|
|
||||||
// Preload first FRD's records server-side for fast initial render
|
const results = await Promise.all(
|
||||||
const initialFrdId = frds[0]?.id;
|
frds.map((frd) => listFeedbackRecords({ tenant_id: frd.id, limit: INITIAL_PAGE_SIZE }))
|
||||||
let initialRecords: FeedbackRecordListResponse | null = null;
|
);
|
||||||
|
|
||||||
if (initialFrdId) {
|
// Don't crash if Hub is unreachable — show empty state
|
||||||
const result = await listFeedbackRecords({ tenant_id: initialFrdId, limit: INITIAL_PAGE_SIZE });
|
const successfulResults = results.filter((r) => !r.error);
|
||||||
// Don't crash if Hub is down — show empty state
|
|
||||||
if (!result.error) {
|
const merged = successfulResults
|
||||||
initialRecords = result.data;
|
.flatMap((r) => r.data?.data ?? [])
|
||||||
}
|
.sort((a, b) => (a.collected_at < b.collected_at ? 1 : -1))
|
||||||
}
|
.slice(0, INITIAL_PAGE_SIZE);
|
||||||
|
|
||||||
|
const frdMap = Object.fromEntries(frds.map((f) => [f.id, f.name]));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FeedbackRecordsPageClient
|
<FeedbackRecordsPageClient workspaceId={params.workspaceId} initialRecords={merged} frdMap={frdMap} />
|
||||||
workspaceId={params.workspaceId}
|
|
||||||
directories={frds}
|
|
||||||
initialFrdId={initialFrdId ?? null}
|
|
||||||
initialRecords={initialRecords?.data ?? []}
|
|
||||||
initialNextCursor={initialRecords?.next_cursor}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-111
@@ -25,6 +25,7 @@ import {
|
|||||||
import { TResponse, TResponseMeta } from "@formbricks/types/responses";
|
import { TResponse, TResponseMeta } from "@formbricks/types/responses";
|
||||||
import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
||||||
import { TSurvey, TSurveyQuestionTypeEnum } from "@formbricks/types/surveys/types";
|
import { TSurvey, TSurveyQuestionTypeEnum } from "@formbricks/types/surveys/types";
|
||||||
|
import { TPipelineInput } from "@/app/api/(internal)/pipeline/types/pipelines";
|
||||||
import { writeData as airtableWriteData } from "@/lib/airtable/service";
|
import { writeData as airtableWriteData } from "@/lib/airtable/service";
|
||||||
import { writeData as googleSheetWriteData } from "@/lib/googleSheet/service";
|
import { writeData as googleSheetWriteData } from "@/lib/googleSheet/service";
|
||||||
import { getLocalizedValue } from "@/lib/i18n/utils";
|
import { getLocalizedValue } from "@/lib/i18n/utils";
|
||||||
@@ -34,7 +35,7 @@ import { writeDataToSlack } from "@/lib/slack/service";
|
|||||||
import { getFormattedDateTimeString } from "@/lib/utils/datetime";
|
import { getFormattedDateTimeString } from "@/lib/utils/datetime";
|
||||||
import { parseRecallInfo } from "@/lib/utils/recall";
|
import { parseRecallInfo } from "@/lib/utils/recall";
|
||||||
import { truncateText } from "@/lib/utils/strings";
|
import { truncateText } from "@/lib/utils/strings";
|
||||||
import { handleIntegrations } from "./handle-integrations";
|
import { handleIntegrations } from "./handleIntegrations";
|
||||||
|
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
vi.mock("@/lib/airtable/service");
|
vi.mock("@/lib/airtable/service");
|
||||||
@@ -55,7 +56,6 @@ const questionId2 = "q2";
|
|||||||
const questionId3 = "q3_picture";
|
const questionId3 = "q3_picture";
|
||||||
const hiddenFieldId = "hidden1";
|
const hiddenFieldId = "hidden1";
|
||||||
const variableId = "var1";
|
const variableId = "var1";
|
||||||
type TIntegrationPipelineInput = Parameters<typeof handleIntegrations>[1];
|
|
||||||
|
|
||||||
const mockPipelineInput = {
|
const mockPipelineInput = {
|
||||||
workspaceId: "env1",
|
workspaceId: "env1",
|
||||||
@@ -93,7 +93,7 @@ const mockPipelineInput = {
|
|||||||
},
|
},
|
||||||
ttc: {},
|
ttc: {},
|
||||||
} as unknown as TResponse,
|
} as unknown as TResponse,
|
||||||
} as Parameters<typeof handleIntegrations>[1];
|
} as TPipelineInput;
|
||||||
|
|
||||||
const mockSurvey = {
|
const mockSurvey = {
|
||||||
id: surveyId,
|
id: surveyId,
|
||||||
@@ -442,114 +442,6 @@ describe("handleIntegrations", () => {
|
|||||||
expect(writeNotionData).not.toHaveBeenCalled();
|
expect(writeNotionData).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("maps picture selection URLs without mutating the shared response payload", async () => {
|
|
||||||
vi.mocked(writeNotionData).mockResolvedValue(undefined);
|
|
||||||
const pipelineInput = structuredClone(mockPipelineInput) as TIntegrationPipelineInput;
|
|
||||||
|
|
||||||
await handleIntegrations([mockNotionIntegration], pipelineInput, mockSurvey);
|
|
||||||
|
|
||||||
expect(writeNotionData).toHaveBeenCalledWith(
|
|
||||||
"db1",
|
|
||||||
expect.objectContaining({
|
|
||||||
"Column 3": {
|
|
||||||
url: "http://image.com/1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
mockNotionIntegration.config
|
|
||||||
);
|
|
||||||
expect(pipelineInput.response.data[questionId3]).toEqual(["picChoice1"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("coerces non-string Notion text values and avoids invalid multi-url payloads", async () => {
|
|
||||||
vi.mocked(writeNotionData).mockResolvedValue(undefined);
|
|
||||||
const pipelineInput = structuredClone(mockPipelineInput) as TIntegrationPipelineInput;
|
|
||||||
const pipelineResponseData = pipelineInput.response.data as Record<string, unknown>;
|
|
||||||
pipelineResponseData[questionId1] = 42;
|
|
||||||
pipelineResponseData.objectField = { foo: "bar" };
|
|
||||||
pipelineResponseData.manyUrls = ["https://example.com/a", "https://example.com/b"];
|
|
||||||
|
|
||||||
const notionIntegration = structuredClone(mockNotionIntegration);
|
|
||||||
notionIntegration.config.data[0].mapping = [
|
|
||||||
{
|
|
||||||
element: { id: questionId1, name: "Question 1", type: TSurveyQuestionTypeEnum.OpenText },
|
|
||||||
column: { id: "col_title", name: "Title", type: "title" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: { id: "objectField", name: "Object Field", type: TSurveyQuestionTypeEnum.OpenText },
|
|
||||||
column: { id: "col_rich", name: "Rich", type: "rich_text" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: { id: "manyUrls", name: "Many Urls", type: TSurveyQuestionTypeEnum.OpenText },
|
|
||||||
column: { id: "col_url", name: "Url", type: "url" },
|
|
||||||
},
|
|
||||||
] as TIntegrationNotionConfigData["mapping"];
|
|
||||||
|
|
||||||
await handleIntegrations([notionIntegration], pipelineInput, mockSurvey);
|
|
||||||
|
|
||||||
expect(writeNotionData).toHaveBeenCalledWith(
|
|
||||||
"db1",
|
|
||||||
expect.objectContaining({
|
|
||||||
Rich: {
|
|
||||||
rich_text: [
|
|
||||||
{
|
|
||||||
text: {
|
|
||||||
content: JSON.stringify({ foo: "bar" }),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
Title: {
|
|
||||||
title: [
|
|
||||||
{
|
|
||||||
text: {
|
|
||||||
content: "42",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
Url: {
|
|
||||||
url: null,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
notionIntegration.config
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("sanitizes mixed Notion multi-select values and preserves numeric precision", async () => {
|
|
||||||
vi.mocked(writeNotionData).mockResolvedValue(undefined);
|
|
||||||
const pipelineInput = structuredClone(mockPipelineInput) as TIntegrationPipelineInput;
|
|
||||||
const pipelineResponseData = pipelineInput.response.data as Record<string, unknown>;
|
|
||||||
pipelineResponseData[questionId2] = ["Choice 1", { name: "Choice, 3" }, 42] as unknown as string[];
|
|
||||||
pipelineResponseData.numericField = 3.5;
|
|
||||||
|
|
||||||
const notionIntegration = structuredClone(mockNotionIntegration);
|
|
||||||
notionIntegration.config.data[0].mapping = [
|
|
||||||
{
|
|
||||||
element: { id: questionId2, name: "Question 2", type: TSurveyQuestionTypeEnum.MultipleChoiceMulti },
|
|
||||||
column: { id: "col_multi", name: "Multi", type: "multi_select" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: { id: "numericField", name: "Numeric Field", type: TSurveyQuestionTypeEnum.OpenText },
|
|
||||||
column: { id: "col_number", name: "Number", type: "number" },
|
|
||||||
},
|
|
||||||
] as TIntegrationNotionConfigData["mapping"];
|
|
||||||
|
|
||||||
await handleIntegrations([notionIntegration], pipelineInput, mockSurvey);
|
|
||||||
|
|
||||||
expect(writeNotionData).toHaveBeenCalledWith(
|
|
||||||
"db1",
|
|
||||||
expect.objectContaining({
|
|
||||||
Multi: {
|
|
||||||
multi_select: [{ name: "Choice 1" }, { name: "Choice 3" }],
|
|
||||||
},
|
|
||||||
Number: {
|
|
||||||
number: 3.5,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
notionIntegration.config
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should return error result on failure", async () => {
|
test("should return error result on failure", async () => {
|
||||||
const error = new Error("Notion API error");
|
const error = new Error("Notion API error");
|
||||||
vi.mocked(writeNotionData).mockRejectedValue(error);
|
vi.mocked(writeNotionData).mockRejectedValue(error);
|
||||||
+103
-197
@@ -5,10 +5,11 @@ import { TIntegrationAirtable } from "@formbricks/types/integration/airtable";
|
|||||||
import { TIntegrationGoogleSheets } from "@formbricks/types/integration/google-sheet";
|
import { TIntegrationGoogleSheets } from "@formbricks/types/integration/google-sheet";
|
||||||
import { TIntegrationNotion, TIntegrationNotionConfigData } from "@formbricks/types/integration/notion";
|
import { TIntegrationNotion, TIntegrationNotionConfigData } from "@formbricks/types/integration/notion";
|
||||||
import { TIntegrationSlack } from "@formbricks/types/integration/slack";
|
import { TIntegrationSlack } from "@formbricks/types/integration/slack";
|
||||||
import { TResponse, TResponseDataValue, TResponseMeta } from "@formbricks/types/responses";
|
import { TResponseDataValue, TResponseMeta } from "@formbricks/types/responses";
|
||||||
import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
import { TSurveyElementTypeEnum } from "@formbricks/types/surveys/elements";
|
||||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||||
import { getTextContent } from "@formbricks/types/surveys/validation";
|
import { getTextContent } from "@formbricks/types/surveys/validation";
|
||||||
|
import { TPipelineInput } from "@/app/api/(internal)/pipeline/types/pipelines";
|
||||||
import { writeData as airtableWriteData } from "@/lib/airtable/service";
|
import { writeData as airtableWriteData } from "@/lib/airtable/service";
|
||||||
import { NOTION_RICH_TEXT_LIMIT } from "@/lib/constants";
|
import { NOTION_RICH_TEXT_LIMIT } from "@/lib/constants";
|
||||||
import { writeData } from "@/lib/googleSheet/service";
|
import { writeData } from "@/lib/googleSheet/service";
|
||||||
@@ -22,11 +23,6 @@ import { parseRecallInfo } from "@/lib/utils/recall";
|
|||||||
import { truncateText } from "@/lib/utils/strings";
|
import { truncateText } from "@/lib/utils/strings";
|
||||||
import { resolveStorageUrlAuto } from "@/modules/storage/utils";
|
import { resolveStorageUrlAuto } from "@/modules/storage/utils";
|
||||||
|
|
||||||
type TIntegrationPipelineData = {
|
|
||||||
response: Pick<TResponse, "createdAt" | "data" | "meta" | "variables">;
|
|
||||||
surveyId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const convertMetaObjectToString = (metadata: TResponseMeta): string => {
|
const convertMetaObjectToString = (metadata: TResponseMeta): string => {
|
||||||
let result: string[] = [];
|
let result: string[] = [];
|
||||||
if (metadata.source) result.push(`Source: ${metadata.source}`);
|
if (metadata.source) result.push(`Source: ${metadata.source}`);
|
||||||
@@ -42,38 +38,19 @@ const convertMetaObjectToString = (metadata: TResponseMeta): string => {
|
|||||||
return result.join("\n");
|
return result.join("\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TIntegrationFieldSelection {
|
|
||||||
elementIds: string[];
|
|
||||||
includeCreatedAt: boolean;
|
|
||||||
includeHiddenFields: boolean;
|
|
||||||
includeMetadata: boolean;
|
|
||||||
includeVariables: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const toIntegrationFieldSelection = (config: {
|
|
||||||
elementIds: string[];
|
|
||||||
includeCreatedAt?: boolean | null;
|
|
||||||
includeHiddenFields?: boolean | null;
|
|
||||||
includeMetadata?: boolean | null;
|
|
||||||
includeVariables?: boolean | null;
|
|
||||||
}): TIntegrationFieldSelection => ({
|
|
||||||
elementIds: config.elementIds,
|
|
||||||
includeCreatedAt: Boolean(config.includeCreatedAt),
|
|
||||||
includeHiddenFields: Boolean(config.includeHiddenFields),
|
|
||||||
includeMetadata: Boolean(config.includeMetadata),
|
|
||||||
includeVariables: Boolean(config.includeVariables),
|
|
||||||
});
|
|
||||||
|
|
||||||
const processDataForIntegration = async (
|
const processDataForIntegration = async (
|
||||||
integrationType: TIntegrationType,
|
integrationType: TIntegrationType,
|
||||||
data: TIntegrationPipelineData,
|
data: TPipelineInput,
|
||||||
survey: TSurvey,
|
survey: TSurvey,
|
||||||
selection: TIntegrationFieldSelection
|
includeVariables: boolean,
|
||||||
|
includeMetadata: boolean,
|
||||||
|
includeHiddenFields: boolean,
|
||||||
|
includeCreatedAt: boolean,
|
||||||
|
elementIds: string[]
|
||||||
): Promise<{
|
): Promise<{
|
||||||
responses: string[];
|
responses: string[];
|
||||||
elements: string[];
|
elements: string[];
|
||||||
}> => {
|
}> => {
|
||||||
const { elementIds, includeCreatedAt, includeHiddenFields, includeMetadata, includeVariables } = selection;
|
|
||||||
const ids =
|
const ids =
|
||||||
includeHiddenFields && survey.hiddenFields.fieldIds
|
includeHiddenFields && survey.hiddenFields.fieldIds
|
||||||
? [...elementIds, ...survey.hiddenFields.fieldIds]
|
? [...elementIds, ...survey.hiddenFields.fieldIds]
|
||||||
@@ -107,12 +84,12 @@ const processDataForIntegration = async (
|
|||||||
|
|
||||||
export const handleIntegrations = async (
|
export const handleIntegrations = async (
|
||||||
integrations: TIntegration[],
|
integrations: TIntegration[],
|
||||||
data: TIntegrationPipelineData,
|
data: TPipelineInput,
|
||||||
survey: TSurvey
|
survey: TSurvey
|
||||||
) => {
|
) => {
|
||||||
for (const integration of integrations) {
|
for (const integration of integrations) {
|
||||||
switch (integration.type) {
|
switch (integration.type) {
|
||||||
case "googleSheets": {
|
case "googleSheets":
|
||||||
const googleResult = await handleGoogleSheetsIntegration(
|
const googleResult = await handleGoogleSheetsIntegration(
|
||||||
integration as TIntegrationGoogleSheets,
|
integration as TIntegrationGoogleSheets,
|
||||||
data,
|
data,
|
||||||
@@ -122,15 +99,13 @@ export const handleIntegrations = async (
|
|||||||
logger.error(googleResult.error, "Error in google sheets integration");
|
logger.error(googleResult.error, "Error in google sheets integration");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case "slack":
|
||||||
case "slack": {
|
|
||||||
const slackResult = await handleSlackIntegration(integration as TIntegrationSlack, data, survey);
|
const slackResult = await handleSlackIntegration(integration as TIntegrationSlack, data, survey);
|
||||||
if (!slackResult.ok) {
|
if (!slackResult.ok) {
|
||||||
logger.error(slackResult.error, "Error in slack integration");
|
logger.error(slackResult.error, "Error in slack integration");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case "airtable":
|
||||||
case "airtable": {
|
|
||||||
const airtableResult = await handleAirtableIntegration(
|
const airtableResult = await handleAirtableIntegration(
|
||||||
integration as TIntegrationAirtable,
|
integration as TIntegrationAirtable,
|
||||||
data,
|
data,
|
||||||
@@ -140,21 +115,19 @@ export const handleIntegrations = async (
|
|||||||
logger.error(airtableResult.error, "Error in airtable integration");
|
logger.error(airtableResult.error, "Error in airtable integration");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case "notion":
|
||||||
case "notion": {
|
|
||||||
const notionResult = await handleNotionIntegration(integration as TIntegrationNotion, data, survey);
|
const notionResult = await handleNotionIntegration(integration as TIntegrationNotion, data, survey);
|
||||||
if (!notionResult.ok) {
|
if (!notionResult.ok) {
|
||||||
logger.error(notionResult.error, "Error in notion integration");
|
logger.error(notionResult.error, "Error in notion integration");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAirtableIntegration = async (
|
const handleAirtableIntegration = async (
|
||||||
integration: TIntegrationAirtable,
|
integration: TIntegrationAirtable,
|
||||||
data: TIntegrationPipelineData,
|
data: TPipelineInput,
|
||||||
survey: TSurvey
|
survey: TSurvey
|
||||||
): Promise<Result<void, Error>> => {
|
): Promise<Result<void, Error>> => {
|
||||||
try {
|
try {
|
||||||
@@ -165,7 +138,11 @@ const handleAirtableIntegration = async (
|
|||||||
"airtable",
|
"airtable",
|
||||||
data,
|
data,
|
||||||
survey,
|
survey,
|
||||||
toIntegrationFieldSelection(element)
|
!!element.includeVariables,
|
||||||
|
!!element.includeMetadata,
|
||||||
|
!!element.includeHiddenFields,
|
||||||
|
!!element.includeCreatedAt,
|
||||||
|
element.elementIds
|
||||||
);
|
);
|
||||||
await airtableWriteData(integration.config.key, element, values.responses, values.elements);
|
await airtableWriteData(integration.config.key, element, values.responses, values.elements);
|
||||||
}
|
}
|
||||||
@@ -186,7 +163,7 @@ const handleAirtableIntegration = async (
|
|||||||
|
|
||||||
const handleGoogleSheetsIntegration = async (
|
const handleGoogleSheetsIntegration = async (
|
||||||
integration: TIntegrationGoogleSheets,
|
integration: TIntegrationGoogleSheets,
|
||||||
data: TIntegrationPipelineData,
|
data: TPipelineInput,
|
||||||
survey: TSurvey
|
survey: TSurvey
|
||||||
): Promise<Result<void, Error>> => {
|
): Promise<Result<void, Error>> => {
|
||||||
try {
|
try {
|
||||||
@@ -197,7 +174,11 @@ const handleGoogleSheetsIntegration = async (
|
|||||||
"googleSheets",
|
"googleSheets",
|
||||||
data,
|
data,
|
||||||
survey,
|
survey,
|
||||||
toIntegrationFieldSelection(element)
|
!!element.includeVariables,
|
||||||
|
!!element.includeMetadata,
|
||||||
|
!!element.includeHiddenFields,
|
||||||
|
!!element.includeCreatedAt,
|
||||||
|
element.elementIds
|
||||||
);
|
);
|
||||||
const integrationData = structuredClone(integration);
|
const integrationData = structuredClone(integration);
|
||||||
integrationData.config.data.forEach((data) => {
|
integrationData.config.data.forEach((data) => {
|
||||||
@@ -223,7 +204,7 @@ const handleGoogleSheetsIntegration = async (
|
|||||||
|
|
||||||
const handleSlackIntegration = async (
|
const handleSlackIntegration = async (
|
||||||
integration: TIntegrationSlack,
|
integration: TIntegrationSlack,
|
||||||
data: TIntegrationPipelineData,
|
data: TPipelineInput,
|
||||||
survey: TSurvey
|
survey: TSurvey
|
||||||
): Promise<Result<void, Error>> => {
|
): Promise<Result<void, Error>> => {
|
||||||
try {
|
try {
|
||||||
@@ -234,7 +215,11 @@ const handleSlackIntegration = async (
|
|||||||
"slack",
|
"slack",
|
||||||
data,
|
data,
|
||||||
survey,
|
survey,
|
||||||
toIntegrationFieldSelection(element)
|
!!element.includeVariables,
|
||||||
|
!!element.includeMetadata,
|
||||||
|
!!element.includeHiddenFields,
|
||||||
|
!!element.includeCreatedAt,
|
||||||
|
element.elementIds
|
||||||
);
|
);
|
||||||
await writeDataToSlack(
|
await writeDataToSlack(
|
||||||
integration.config.key,
|
integration.config.key,
|
||||||
@@ -298,7 +283,7 @@ const createEmptyResponseObject = (responseData: Record<string, unknown>): Recor
|
|||||||
|
|
||||||
const extractResponses = async (
|
const extractResponses = async (
|
||||||
integrationType: TIntegrationType,
|
integrationType: TIntegrationType,
|
||||||
pipelineData: TIntegrationPipelineData,
|
pipelineData: TPipelineInput,
|
||||||
elementIds: string[],
|
elementIds: string[],
|
||||||
survey: TSurvey
|
survey: TSurvey
|
||||||
): Promise<{
|
): Promise<{
|
||||||
@@ -344,7 +329,7 @@ const extractResponses = async (
|
|||||||
|
|
||||||
const handleNotionIntegration = async (
|
const handleNotionIntegration = async (
|
||||||
integration: TIntegrationNotion,
|
integration: TIntegrationNotion,
|
||||||
data: TIntegrationPipelineData,
|
data: TPipelineInput,
|
||||||
surveyData: TSurvey
|
surveyData: TSurvey
|
||||||
): Promise<Result<void, Error>> => {
|
): Promise<Result<void, Error>> => {
|
||||||
try {
|
try {
|
||||||
@@ -371,36 +356,27 @@ const handleNotionIntegration = async (
|
|||||||
|
|
||||||
const buildNotionPayloadProperties = (
|
const buildNotionPayloadProperties = (
|
||||||
mapping: TIntegrationNotionConfigData["mapping"],
|
mapping: TIntegrationNotionConfigData["mapping"],
|
||||||
data: TIntegrationPipelineData,
|
data: TPipelineInput,
|
||||||
surveyData: TSurvey
|
surveyData: TSurvey
|
||||||
) => {
|
) => {
|
||||||
const properties: any = {};
|
const properties: any = {};
|
||||||
const normalizedResponses = { ...data.response.data };
|
const responses = data.response.data;
|
||||||
|
|
||||||
const surveyElements = getElementsFromBlocks(surveyData.blocks);
|
const surveyElements = getElementsFromBlocks(surveyData.blocks);
|
||||||
const surveyElementsById = new Map(surveyElements.map((element) => [element.id, element] as const));
|
|
||||||
const pictureSelectionElementIds = new Set(
|
|
||||||
mapping.filter((m) => m.element.type === TSurveyElementTypeEnum.PictureSelection).map((m) => m.element.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
Object.keys(normalizedResponses).forEach((responseKey) => {
|
const mappingElementIds = mapping
|
||||||
if (!pictureSelectionElementIds.has(responseKey)) {
|
.filter((m) => m.element.type === TSurveyElementTypeEnum.PictureSelection)
|
||||||
return;
|
.map((m) => m.element.id);
|
||||||
|
|
||||||
|
Object.keys(responses).forEach((resp) => {
|
||||||
|
if (mappingElementIds.find((elementId) => elementId === resp)) {
|
||||||
|
const selectedChoiceIds = responses[resp] as string[];
|
||||||
|
const pictureElement = surveyElements.find((el) => el.id === resp);
|
||||||
|
|
||||||
|
responses[resp] = (pictureElement as any)?.choices
|
||||||
|
.filter((choice: { id: string; imageUrl: string }) => selectedChoiceIds.includes(choice.id))
|
||||||
|
.map((choice: { id: string; imageUrl: string }) => resolveStorageUrlAuto(choice.imageUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedChoiceIds = normalizedResponses[responseKey];
|
|
||||||
if (!Array.isArray(selectedChoiceIds)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pictureElement = surveyElementsById.get(responseKey);
|
|
||||||
if (pictureElement?.type !== TSurveyElementTypeEnum.PictureSelection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
normalizedResponses[responseKey] = pictureElement.choices
|
|
||||||
.filter((choice) => selectedChoiceIds.includes(choice.id))
|
|
||||||
.map((choice) => resolveStorageUrlAuto(choice.imageUrl));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
mapping.forEach((map) => {
|
mapping.forEach((map) => {
|
||||||
@@ -413,7 +389,7 @@ const buildNotionPayloadProperties = (
|
|||||||
[map.column.type]: getValue(map.column.type, data.response.createdAt) || null,
|
[map.column.type]: getValue(map.column.type, data.response.createdAt) || null,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const value = normalizedResponses[map.element.id];
|
const value = responses[map.element.id];
|
||||||
properties[map.column.name] = {
|
properties[map.column.name] = {
|
||||||
[map.column.type]: getValue(map.column.type, value) || null,
|
[map.column.type]: getValue(map.column.type, value) || null,
|
||||||
};
|
};
|
||||||
@@ -425,130 +401,64 @@ const buildNotionPayloadProperties = (
|
|||||||
|
|
||||||
// notion requires specific payload for each column type
|
// notion requires specific payload for each column type
|
||||||
// * TYPES NOT SUPPORTED BY NOTION API - rollup, created_by, created_time, last_edited_by, or last_edited_time
|
// * TYPES NOT SUPPORTED BY NOTION API - rollup, created_by, created_time, last_edited_by, or last_edited_time
|
||||||
type TNotionValueInput = string | string[] | Date | number | Record<string, string> | undefined;
|
const getValue = (
|
||||||
|
colType: string,
|
||||||
const coerceToNotionString = (
|
value: string | string[] | Date | number | Record<string, string> | undefined
|
||||||
value: TNotionValueInput,
|
) => {
|
||||||
options?: { allowArrays?: boolean }
|
|
||||||
): string | null => {
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
if (!options?.allowArrays) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof Date) {
|
|
||||||
return value.toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === "object") {
|
|
||||||
return JSON.stringify(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return String(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSelectValue = (value: TNotionValueInput) => {
|
|
||||||
if (typeof value !== "string" || value.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: value.replaceAll(",", ""),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getMultiSelectValue = (value: TNotionValueInput) => {
|
|
||||||
if (!Array.isArray(value)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (value as unknown[]).flatMap((entry) => {
|
|
||||||
if (typeof entry === "string") {
|
|
||||||
return [{ name: entry.replaceAll(",", "") }];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
entry &&
|
|
||||||
typeof entry === "object" &&
|
|
||||||
"name" in entry &&
|
|
||||||
typeof (entry as { name?: unknown }).name === "string"
|
|
||||||
) {
|
|
||||||
return [{ name: (entry as { name: string }).name.replaceAll(",", "") }];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getTitleValue = (value: TNotionValueInput) => {
|
|
||||||
const content = coerceToNotionString(value, { allowArrays: true });
|
|
||||||
if (!content) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
text: {
|
|
||||||
content,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const getRichTextValue = (value: TNotionValueInput) => {
|
|
||||||
const content = coerceToNotionString(value, { allowArrays: true });
|
|
||||||
if (!content) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
text: {
|
|
||||||
content:
|
|
||||||
content.length > NOTION_RICH_TEXT_LIMIT ? truncateText(content, NOTION_RICH_TEXT_LIMIT) : content,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const getUrlValue = (value: TNotionValueInput) => {
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
if (value.length !== 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return coerceToNotionString(value[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = coerceToNotionString(value);
|
|
||||||
if (!content) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === "string") {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getValue = (colType: string, value: TNotionValueInput) => {
|
|
||||||
try {
|
try {
|
||||||
switch (colType) {
|
switch (colType) {
|
||||||
case "select":
|
case "select":
|
||||||
return getSelectValue(value);
|
if (!value) return null;
|
||||||
|
if (typeof value === "string") {
|
||||||
|
// Replace commas
|
||||||
|
const sanitizedValue = value.replace(/,/g, "");
|
||||||
|
return {
|
||||||
|
name: sanitizedValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
case "multi_select":
|
case "multi_select":
|
||||||
return getMultiSelectValue(value);
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((v: string) => ({ name: v.replace(/,/g, "") }));
|
||||||
|
}
|
||||||
case "title":
|
case "title":
|
||||||
return getTitleValue(value);
|
return [
|
||||||
|
{
|
||||||
|
text: {
|
||||||
|
content: value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
case "rich_text":
|
case "rich_text":
|
||||||
return getRichTextValue(value);
|
if (typeof value === "string") {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: {
|
||||||
|
content:
|
||||||
|
value.length > NOTION_RICH_TEXT_LIMIT ? truncateText(value, NOTION_RICH_TEXT_LIMIT) : value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
const content = value.join("\n");
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: {
|
||||||
|
content:
|
||||||
|
content.length > NOTION_RICH_TEXT_LIMIT
|
||||||
|
? truncateText(content, NOTION_RICH_TEXT_LIMIT)
|
||||||
|
: content,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: {
|
||||||
|
content: value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
case "status":
|
case "status":
|
||||||
return {
|
return {
|
||||||
name: value,
|
name: value,
|
||||||
@@ -561,16 +471,12 @@ const getValue = (colType: string, value: TNotionValueInput) => {
|
|||||||
};
|
};
|
||||||
case "email":
|
case "email":
|
||||||
return value;
|
return value;
|
||||||
case "number": {
|
case "number":
|
||||||
const numeric = typeof value === "number" ? value : Number(value);
|
return parseInt(value as string);
|
||||||
return Number.isFinite(numeric) ? numeric : null;
|
|
||||||
}
|
|
||||||
case "phone_number":
|
case "phone_number":
|
||||||
return value;
|
return value;
|
||||||
case "url":
|
case "url":
|
||||||
return getUrlValue(value);
|
return typeof value === "string" ? value : (value as string[]).join(", ");
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error, "Payload build failed!");
|
logger.error(error, "Payload build failed!");
|
||||||
@@ -4,6 +4,7 @@ import { v7 as uuidv7 } from "uuid";
|
|||||||
import { prisma } from "@formbricks/database";
|
import { prisma } from "@formbricks/database";
|
||||||
import { logger } from "@formbricks/logger";
|
import { logger } from "@formbricks/logger";
|
||||||
import { ResourceNotFoundError } from "@formbricks/types/errors";
|
import { ResourceNotFoundError } from "@formbricks/types/errors";
|
||||||
|
import { sendTelemetryEvents } from "@/app/api/(internal)/pipeline/lib/telemetry";
|
||||||
import { ZPipelineInput } from "@/app/api/(internal)/pipeline/types/pipelines";
|
import { ZPipelineInput } from "@/app/api/(internal)/pipeline/types/pipelines";
|
||||||
import { responses } from "@/app/lib/api/response";
|
import { responses } from "@/app/lib/api/response";
|
||||||
import { transformErrorToDetails } from "@/app/lib/api/validator";
|
import { transformErrorToDetails } from "@/app/lib/api/validator";
|
||||||
@@ -21,12 +22,11 @@ import { queueAuditEvent } from "@/modules/ee/audit-logs/lib/handler";
|
|||||||
import { TAuditStatus, UNKNOWN_DATA } from "@/modules/ee/audit-logs/types/audit-log";
|
import { TAuditStatus, UNKNOWN_DATA } from "@/modules/ee/audit-logs/types/audit-log";
|
||||||
import { recordResponseCreatedMeterEvent } from "@/modules/ee/billing/lib/metering";
|
import { recordResponseCreatedMeterEvent } from "@/modules/ee/billing/lib/metering";
|
||||||
import { sendResponseFinishedEmail } from "@/modules/email";
|
import { sendResponseFinishedEmail } from "@/modules/email";
|
||||||
import { handleIntegrations } from "@/modules/response-pipeline/lib/handle-integrations";
|
|
||||||
import { captureSurveyResponsePostHogEvent } from "@/modules/response-pipeline/lib/posthog";
|
|
||||||
import { sendTelemetryEvents } from "@/modules/response-pipeline/lib/telemetry";
|
|
||||||
import { resolveStorageUrlsInObject } from "@/modules/storage/utils";
|
import { resolveStorageUrlsInObject } from "@/modules/storage/utils";
|
||||||
import { sendFollowUpsForResponse } from "@/modules/survey/follow-ups/lib/follow-ups";
|
import { sendFollowUpsForResponse } from "@/modules/survey/follow-ups/lib/follow-ups";
|
||||||
import { FollowUpSendError } from "@/modules/survey/follow-ups/types/follow-up";
|
import { FollowUpSendError } from "@/modules/survey/follow-ups/types/follow-up";
|
||||||
|
import { handleIntegrations } from "./lib/handleIntegrations";
|
||||||
|
import { captureSurveyResponsePostHogEvent } from "./lib/posthog";
|
||||||
|
|
||||||
export const POST = async (request: Request) => {
|
export const POST = async (request: Request) => {
|
||||||
const requestHeaders = await headers();
|
const requestHeaders = await headers();
|
||||||
|
|||||||
-98
@@ -1,98 +0,0 @@
|
|||||||
import { Prisma } from "@prisma/client";
|
|
||||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
||||||
import { prisma } from "@formbricks/database";
|
|
||||||
import { DatabaseError, ResourceNotFoundError, ValidationError } from "@formbricks/types/errors";
|
|
||||||
import { validateInputs } from "@/lib/utils/validate";
|
|
||||||
import { getResponseIdByDisplayId } from "./response";
|
|
||||||
|
|
||||||
vi.mock("@/lib/utils/validate", () => ({
|
|
||||||
validateInputs: vi.fn((inputs: [unknown, unknown][]) =>
|
|
||||||
inputs.map((input: [unknown, unknown]) => input[0])
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@formbricks/database", () => ({
|
|
||||||
prisma: {
|
|
||||||
display: {
|
|
||||||
findFirst: vi.fn(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("getResponseIdByDisplayId", () => {
|
|
||||||
const workspaceId = "ws1234567890123456789012";
|
|
||||||
const displayId = "display1234567890123456789";
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns the linked responseId when a response exists", async () => {
|
|
||||||
vi.mocked(prisma.display.findFirst).mockResolvedValue({
|
|
||||||
response: {
|
|
||||||
id: "response123456789012345678",
|
|
||||||
},
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
const result = await getResponseIdByDisplayId(workspaceId, displayId);
|
|
||||||
|
|
||||||
expect(validateInputs).toHaveBeenCalledWith(
|
|
||||||
[workspaceId, expect.any(Object)],
|
|
||||||
[displayId, expect.any(Object)]
|
|
||||||
);
|
|
||||||
expect(prisma.display.findFirst).toHaveBeenCalledWith({
|
|
||||||
where: {
|
|
||||||
id: displayId,
|
|
||||||
survey: {
|
|
||||||
workspaceId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
response: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(result).toEqual({ responseId: "response123456789012345678" });
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns null when the display exists but has no response", async () => {
|
|
||||||
vi.mocked(prisma.display.findFirst).mockResolvedValue({
|
|
||||||
response: null,
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
await expect(getResponseIdByDisplayId(workspaceId, displayId)).resolves.toEqual({
|
|
||||||
responseId: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("throws ResourceNotFoundError when the display does not exist in the workspace", async () => {
|
|
||||||
vi.mocked(prisma.display.findFirst).mockResolvedValue(null);
|
|
||||||
|
|
||||||
await expect(getResponseIdByDisplayId(workspaceId, displayId)).rejects.toThrow(
|
|
||||||
new ResourceNotFoundError("Display", displayId)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("throws ValidationError when input validation fails", async () => {
|
|
||||||
const validationError = new ValidationError("Validation failed");
|
|
||||||
vi.mocked(validateInputs).mockImplementation(() => {
|
|
||||||
throw validationError;
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(getResponseIdByDisplayId(workspaceId, displayId)).rejects.toThrow(ValidationError);
|
|
||||||
expect(prisma.display.findFirst).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("throws DatabaseError on Prisma request errors", async () => {
|
|
||||||
const prismaError = new Prisma.PrismaClientKnownRequestError("Database error", {
|
|
||||||
code: "P2002",
|
|
||||||
clientVersion: "test",
|
|
||||||
});
|
|
||||||
vi.mocked(prisma.display.findFirst).mockRejectedValue(prismaError);
|
|
||||||
|
|
||||||
await expect(getResponseIdByDisplayId(workspaceId, displayId)).rejects.toThrow(DatabaseError);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
-44
@@ -1,44 +0,0 @@
|
|||||||
import { Prisma } from "@prisma/client";
|
|
||||||
import { prisma } from "@formbricks/database";
|
|
||||||
import { ZId } from "@formbricks/types/common";
|
|
||||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
|
|
||||||
import { validateInputs } from "@/lib/utils/validate";
|
|
||||||
|
|
||||||
export const getResponseIdByDisplayId = async (
|
|
||||||
workspaceId: string,
|
|
||||||
displayId: string
|
|
||||||
): Promise<{ responseId: string | null }> => {
|
|
||||||
validateInputs([workspaceId, ZId], [displayId, ZId]);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const display = await prisma.display.findFirst({
|
|
||||||
where: {
|
|
||||||
id: displayId,
|
|
||||||
survey: {
|
|
||||||
workspaceId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
response: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!display) {
|
|
||||||
throw new ResourceNotFoundError("Display", displayId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
responseId: display.response?.id ?? null,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
|
||||||
throw new DatabaseError(error.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import { logger } from "@formbricks/logger";
|
|
||||||
import { ResourceNotFoundError } from "@formbricks/types/errors";
|
|
||||||
import { responses } from "@/app/lib/api/response";
|
|
||||||
import { THandlerParams, withV1ApiWrapper } from "@/app/lib/api/with-api-logging";
|
|
||||||
import { resolveClientApiIds } from "@/lib/utils/resolve-client-id";
|
|
||||||
import { getResponseIdByDisplayId } from "./lib/response";
|
|
||||||
|
|
||||||
export const OPTIONS = async (): Promise<Response> => {
|
|
||||||
return responses.successResponse({}, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const GET = withV1ApiWrapper({
|
|
||||||
handler: async ({
|
|
||||||
req,
|
|
||||||
props,
|
|
||||||
}: THandlerParams<{ params: Promise<{ workspaceId: string; displayId: string }> }>) => {
|
|
||||||
const params = await props.params;
|
|
||||||
|
|
||||||
const resolved = await resolveClientApiIds(params.workspaceId);
|
|
||||||
if (!resolved) {
|
|
||||||
return {
|
|
||||||
response: responses.notFoundResponse("Workspace", params.workspaceId, true),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const { workspaceId } = resolved;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await getResponseIdByDisplayId(workspaceId, params.displayId);
|
|
||||||
|
|
||||||
return {
|
|
||||||
response: responses.successResponse(response, true),
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof ResourceNotFoundError) {
|
|
||||||
return {
|
|
||||||
response: responses.notFoundResponse("Display", params.displayId, true),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.error(
|
|
||||||
{ error, url: req.url, workspaceId, displayId: params.displayId },
|
|
||||||
"Error in GET /api/v1/client/[workspaceId]/displays/[displayId]/response"
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
response: responses.internalServerErrorResponse("Something went wrong. Please try again."),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -33,13 +33,10 @@ vi.mock("@formbricks/logger", () => ({
|
|||||||
vi.mock("./data");
|
vi.mock("./data");
|
||||||
vi.mock("@/app/lib/api/api-backwards-compat", () => ({
|
vi.mock("@/app/lib/api/api-backwards-compat", () => ({
|
||||||
addLegacyProjectOverwritesToList: vi.fn((surveys: unknown[]) =>
|
addLegacyProjectOverwritesToList: vi.fn((surveys: unknown[]) =>
|
||||||
surveys.map((survey) => {
|
surveys.map((s: Record<string, unknown>) => ({
|
||||||
const typedSurvey = survey as Record<string, unknown>;
|
...s,
|
||||||
return {
|
projectOverwrites: s.workspaceOverwrites ?? null,
|
||||||
...typedSurvey,
|
}))
|
||||||
projectOverwrites: typedSurvey.workspaceOverwrites ?? null,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
),
|
),
|
||||||
addLegacyProjectToEnvironmentState: vi.fn((data: Record<string, unknown>) => ({
|
addLegacyProjectToEnvironmentState: vi.fn((data: Record<string, unknown>) => ({
|
||||||
...data,
|
...data,
|
||||||
@@ -132,7 +129,7 @@ const mockActionClasses = [
|
|||||||
description: null,
|
description: null,
|
||||||
type: "code",
|
type: "code",
|
||||||
noCodeConfig: null,
|
noCodeConfig: null,
|
||||||
workspaceId,
|
environmentId: workspaceId,
|
||||||
key: "action1",
|
key: "action1",
|
||||||
},
|
},
|
||||||
] as unknown as TActionClass[];
|
] as unknown as TActionClass[];
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ export const POST = withV1ApiWrapper({
|
|||||||
response: responses.badRequestResponse(
|
response: responses.badRequestResponse(
|
||||||
"Survey is part of another workspace",
|
"Survey is part of another workspace",
|
||||||
{
|
{
|
||||||
|
"survey.workspaceId": survey.workspaceId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -15,14 +15,20 @@ const apiKeySelect = {
|
|||||||
lastUsedAt: true,
|
lastUsedAt: true,
|
||||||
apiKeyWorkspaces: {
|
apiKeyWorkspaces: {
|
||||||
select: {
|
select: {
|
||||||
workspace: {
|
environment: {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
legacyEnvironmentId: true,
|
type: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
updatedAt: true,
|
updatedAt: true,
|
||||||
name: true,
|
workspaceId: true,
|
||||||
appSetupCompleted: true,
|
appSetupCompleted: true,
|
||||||
|
workspace: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
permission: true,
|
permission: true,
|
||||||
@@ -38,13 +44,17 @@ type ApiKeyData = {
|
|||||||
lastUsedAt: Date | null;
|
lastUsedAt: Date | null;
|
||||||
apiKeyWorkspaces: Array<{
|
apiKeyWorkspaces: Array<{
|
||||||
permission: string;
|
permission: string;
|
||||||
workspace: {
|
environment: {
|
||||||
id: string;
|
id: string;
|
||||||
legacyEnvironmentId: string | null;
|
type: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
name: string;
|
workspaceId: string;
|
||||||
appSetupCompleted: boolean;
|
appSetupCompleted: boolean;
|
||||||
|
workspace: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
@@ -106,24 +116,21 @@ const updateApiKeyUsage = async (apiKeyId: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildWorkspaceResponse = (apiKeyData: ApiKeyData) => {
|
const buildEnvironmentResponse = (apiKeyData: ApiKeyData) => {
|
||||||
const workspace = apiKeyData.apiKeyWorkspaces[0].workspace;
|
const env = apiKeyData.apiKeyWorkspaces[0].environment;
|
||||||
return Response.json({
|
return Response.json({
|
||||||
// Keep v1 payload shape stable while sourcing data from workspace.
|
id: env.id,
|
||||||
id: workspace.legacyEnvironmentId ?? workspace.id,
|
type: env.type,
|
||||||
type: "production",
|
createdAt: env.createdAt,
|
||||||
createdAt: workspace.createdAt,
|
updatedAt: env.updatedAt,
|
||||||
updatedAt: workspace.updatedAt,
|
appSetupCompleted: env.appSetupCompleted,
|
||||||
appSetupCompleted: workspace.appSetupCompleted,
|
|
||||||
workspace: {
|
workspace: {
|
||||||
id: workspace.id,
|
id: env.workspaceId,
|
||||||
name: workspace.name,
|
name: env.workspace.name,
|
||||||
},
|
},
|
||||||
// Backwards compat: old consumers expect project fields
|
// Backwards compat: old consumers expect project fields
|
||||||
project: {
|
projectId: env.workspaceId,
|
||||||
id: workspace.id,
|
projectName: env.workspace.name,
|
||||||
name: workspace.name,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -150,12 +157,14 @@ const handleApiKeyAuthentication = async (apiKey: string) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rate limiting for apiKey auth is enforced by Envoy in v5 — see envoy-rate-limit-coverage.ts
|
const rateLimitError = await checkRateLimit(apiKeyData.id);
|
||||||
|
if (rateLimitError) return rateLimitError;
|
||||||
|
|
||||||
if (!isValidApiKeyEnvironment(apiKeyData)) {
|
if (!isValidApiKeyEnvironment(apiKeyData)) {
|
||||||
return responses.badRequestResponse("You can't use this method with this API key");
|
return responses.badRequestResponse("You can't use this method with this API key");
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildWorkspaceResponse(apiKeyData);
|
return buildEnvironmentResponse(apiKeyData);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSessionAuthentication = async () => {
|
const handleSessionAuthentication = async () => {
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ const validateSurvey = async (responseInput: TResponseInput, workspaceId: string
|
|||||||
error: responses.badRequestResponse(
|
error: responses.badRequestResponse(
|
||||||
"Survey is part of another workspace",
|
"Survey is part of another workspace",
|
||||||
{
|
{
|
||||||
|
"survey.workspaceId": survey.workspaceId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -1,16 +1,43 @@
|
|||||||
|
import { Prisma } from "@prisma/client";
|
||||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
import { prisma } from "@formbricks/database";
|
||||||
|
import { logger } from "@formbricks/logger";
|
||||||
|
import { DatabaseError } from "@formbricks/types/errors";
|
||||||
|
import { validateInputs } from "@/lib/utils/validate";
|
||||||
import { deleteSurvey } from "./surveys";
|
import { deleteSurvey } from "./surveys";
|
||||||
|
|
||||||
const { mockDeleteSharedSurvey } = vi.hoisted(() => ({
|
vi.mock("@/lib/utils/validate", () => ({
|
||||||
mockDeleteSharedSurvey: vi.fn(),
|
validateInputs: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
vi.mock("@formbricks/database", () => ({
|
||||||
vi.mock("@/modules/survey/lib/surveys", () => ({
|
prisma: {
|
||||||
deleteSurvey: mockDeleteSharedSurvey,
|
survey: {
|
||||||
|
delete: vi.fn(),
|
||||||
|
},
|
||||||
|
segment: {
|
||||||
|
delete: vi.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
vi.mock("@formbricks/logger", () => ({
|
||||||
|
logger: {
|
||||||
|
error: vi.fn(),
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const surveyId = "clq5n7p1q0000m7z0h5p6g3r2";
|
const surveyId = "clq5n7p1q0000m7z0h5p6g3r2";
|
||||||
const workspaceId = "clq5n7p1q0000m7z0h5p6g3r3";
|
const workspaceId = "clq5n7p1q0000m7z0h5p6g3r3";
|
||||||
|
const segmentId = "clq5n7p1q0000m7z0h5p6g3r4";
|
||||||
|
const actionClassId1 = "clq5n7p1q0000m7z0h5p6g3r5";
|
||||||
|
const actionClassId2 = "clq5n7p1q0000m7z0h5p6g3r6";
|
||||||
|
|
||||||
|
const mockDeletedSurveyAppPrivateSegment = {
|
||||||
|
id: surveyId,
|
||||||
|
workspaceId,
|
||||||
|
type: "app",
|
||||||
|
segment: { id: segmentId, isPrivate: true },
|
||||||
|
triggers: [{ actionClass: { id: actionClassId1 } }, { actionClass: { id: actionClassId2 } }],
|
||||||
|
};
|
||||||
|
|
||||||
const mockDeletedSurveyLink = {
|
const mockDeletedSurveyLink = {
|
||||||
id: surveyId,
|
id: surveyId,
|
||||||
@@ -29,20 +56,66 @@ describe("deleteSurvey", () => {
|
|||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("delegates survey deletion to the shared service", async () => {
|
test("should delete a link survey without a segment and revalidate caches", async () => {
|
||||||
mockDeleteSharedSurvey.mockResolvedValue(mockDeletedSurveyLink);
|
vi.mocked(prisma.survey.delete).mockResolvedValue(mockDeletedSurveyLink as any);
|
||||||
|
|
||||||
const deletedSurvey = await deleteSurvey(surveyId);
|
const deletedSurvey = await deleteSurvey(surveyId);
|
||||||
|
|
||||||
expect(mockDeleteSharedSurvey).toHaveBeenCalledWith(surveyId);
|
expect(validateInputs).toHaveBeenCalledWith([surveyId, expect.any(Object)]);
|
||||||
|
expect(prisma.survey.delete).toHaveBeenCalledWith({
|
||||||
|
where: { id: surveyId },
|
||||||
|
include: {
|
||||||
|
segment: true,
|
||||||
|
triggers: { include: { actionClass: true } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(prisma.segment.delete).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(deletedSurvey).toEqual(mockDeletedSurveyLink);
|
expect(deletedSurvey).toEqual(mockDeletedSurveyLink);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("rethrows shared delete service errors", async () => {
|
test("should handle PrismaClientKnownRequestError during survey deletion", async () => {
|
||||||
|
const prismaError = new Prisma.PrismaClientKnownRequestError("Record not found", {
|
||||||
|
code: "P2025",
|
||||||
|
clientVersion: "4.0.0",
|
||||||
|
});
|
||||||
|
vi.mocked(prisma.survey.delete).mockRejectedValue(prismaError);
|
||||||
|
|
||||||
|
await expect(deleteSurvey(surveyId)).rejects.toThrow(DatabaseError);
|
||||||
|
expect(logger.error).toHaveBeenCalledWith({ error: prismaError, surveyId }, "Error deleting survey");
|
||||||
|
expect(prisma.segment.delete).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should handle PrismaClientKnownRequestError during segment deletion", async () => {
|
||||||
|
const prismaError = new Prisma.PrismaClientKnownRequestError("Foreign key constraint failed", {
|
||||||
|
code: "P2003",
|
||||||
|
clientVersion: "4.0.0",
|
||||||
|
});
|
||||||
|
vi.mocked(prisma.survey.delete).mockResolvedValue(mockDeletedSurveyAppPrivateSegment as any);
|
||||||
|
vi.mocked(prisma.segment.delete).mockRejectedValue(prismaError);
|
||||||
|
|
||||||
|
await expect(deleteSurvey(surveyId)).rejects.toThrow(DatabaseError);
|
||||||
|
expect(logger.error).toHaveBeenCalledWith({ error: prismaError, surveyId }, "Error deleting survey");
|
||||||
|
expect(prisma.segment.delete).toHaveBeenCalledWith({ where: { id: segmentId } });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should handle generic errors during deletion", async () => {
|
||||||
const genericError = new Error("Something went wrong");
|
const genericError = new Error("Something went wrong");
|
||||||
mockDeleteSharedSurvey.mockRejectedValue(genericError);
|
vi.mocked(prisma.survey.delete).mockRejectedValue(genericError);
|
||||||
|
|
||||||
await expect(deleteSurvey(surveyId)).rejects.toThrow(genericError);
|
await expect(deleteSurvey(surveyId)).rejects.toThrow(genericError);
|
||||||
expect(mockDeleteSharedSurvey).toHaveBeenCalledWith(surveyId);
|
expect(logger.error).not.toHaveBeenCalled();
|
||||||
|
expect(prisma.segment.delete).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should throw validation error for invalid surveyId", async () => {
|
||||||
|
const invalidSurveyId = "invalid-id";
|
||||||
|
const validationError = new Error("Validation failed");
|
||||||
|
vi.mocked(validateInputs).mockImplementation(() => {
|
||||||
|
throw validationError;
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(deleteSurvey(invalidSurveyId)).rejects.toThrow(validationError);
|
||||||
|
expect(prisma.survey.delete).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,43 @@
|
|||||||
import { deleteSurvey as deleteSharedSurvey } from "@/modules/survey/lib/surveys";
|
import { Prisma } from "@prisma/client";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { prisma } from "@formbricks/database";
|
||||||
|
import { logger } from "@formbricks/logger";
|
||||||
|
import { DatabaseError } from "@formbricks/types/errors";
|
||||||
|
import { validateInputs } from "@/lib/utils/validate";
|
||||||
|
|
||||||
export const deleteSurvey = async (surveyId: string) => deleteSharedSurvey(surveyId);
|
export const deleteSurvey = async (surveyId: string) => {
|
||||||
|
validateInputs([surveyId, z.cuid2()]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const deletedSurvey = await prisma.survey.delete({
|
||||||
|
where: {
|
||||||
|
id: surveyId,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
segment: true,
|
||||||
|
triggers: {
|
||||||
|
include: {
|
||||||
|
actionClass: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (deletedSurvey.type === "app" && deletedSurvey.segment?.isPrivate) {
|
||||||
|
await prisma.segment.delete({
|
||||||
|
where: {
|
||||||
|
id: deletedSurvey.segment.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return deletedSurvey;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
|
logger.error({ error, surveyId }, "Error deleting survey");
|
||||||
|
throw new DatabaseError(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { logger } from "@formbricks/logger";
|
import { logger } from "@formbricks/logger";
|
||||||
import { TAuthenticationApiKey } from "@formbricks/types/auth";
|
import { TAuthenticationApiKey } from "@formbricks/types/auth";
|
||||||
import { ResourceNotFoundError } from "@formbricks/types/errors";
|
|
||||||
import { ZSurveyUpdateInput } from "@formbricks/types/surveys/types";
|
import { ZSurveyUpdateInput } from "@formbricks/types/surveys/types";
|
||||||
import { handleErrorResponse } from "@/app/api/v1/auth";
|
import { handleErrorResponse } from "@/app/api/v1/auth";
|
||||||
import { deleteSurvey } from "@/app/api/v1/management/surveys/[surveyId]/lib/surveys";
|
import { deleteSurvey } from "@/app/api/v1/management/surveys/[surveyId]/lib/surveys";
|
||||||
@@ -79,12 +78,6 @@ export const GET = withV1ApiWrapper({
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ResourceNotFoundError) {
|
|
||||||
return {
|
|
||||||
response: responses.notFoundResponse("Survey", params.surveyId),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response: handleErrorResponse(error),
|
response: handleErrorResponse(error),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
import { type NextRequest } from "next/server";
|
||||||
|
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
const mocks = vi.hoisted(() => ({
|
||||||
|
applyIPRateLimit: vi.fn(),
|
||||||
|
getWorkspaceState: vi.fn(),
|
||||||
|
resolveClientApiIds: vi.fn(),
|
||||||
|
contextualLoggerError: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/app/api/v1/client/[workspaceId]/environment/lib/environmentState", () => ({
|
||||||
|
getWorkspaceState: mocks.getWorkspaceState,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/lib/utils/resolve-client-id", () => ({
|
||||||
|
resolveClientApiIds: mocks.resolveClientApiIds,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/modules/core/rate-limit/helpers", () => ({
|
||||||
|
applyIPRateLimit: mocks.applyIPRateLimit,
|
||||||
|
applyRateLimit: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/modules/core/rate-limit/rate-limit-configs", () => ({
|
||||||
|
rateLimitConfigs: {
|
||||||
|
api: {
|
||||||
|
client: { windowMs: 60000, max: 100 },
|
||||||
|
v1: { windowMs: 60000, max: 1000 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@sentry/nextjs", () => ({
|
||||||
|
captureException: vi.fn(),
|
||||||
|
withScope: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@formbricks/logger", () => ({
|
||||||
|
logger: {
|
||||||
|
withContext: vi.fn(() => ({
|
||||||
|
error: mocks.contextualLoggerError,
|
||||||
|
warn: vi.fn(),
|
||||||
|
info: vi.fn(),
|
||||||
|
})),
|
||||||
|
error: vi.fn(),
|
||||||
|
warn: vi.fn(),
|
||||||
|
info: vi.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/lib/constants", async (importOriginal) => {
|
||||||
|
const actual = await importOriginal<typeof import("@/lib/constants")>();
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
AUDIT_LOG_ENABLED: false,
|
||||||
|
IS_PRODUCTION: true,
|
||||||
|
SENTRY_DSN: "test-dsn",
|
||||||
|
ENCRYPTION_KEY: "test-key",
|
||||||
|
REDIS_URL: "redis://localhost:6379",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const createMockRequest = (url: string, headers = new Map<string, string>()): NextRequest => {
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
|
||||||
|
return {
|
||||||
|
method: "GET",
|
||||||
|
url,
|
||||||
|
headers: {
|
||||||
|
get: (key: string) => headers.get(key),
|
||||||
|
},
|
||||||
|
nextUrl: {
|
||||||
|
pathname: parsedUrl.pathname,
|
||||||
|
},
|
||||||
|
} as unknown as NextRequest;
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("api/v2 client environment route", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
mocks.applyIPRateLimit.mockResolvedValue(undefined);
|
||||||
|
mocks.resolveClientApiIds.mockResolvedValue({ workspaceId: "ck12345678901234567890123" });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reports v1-backed failures as v2 and keeps the response payload unchanged", async () => {
|
||||||
|
const underlyingError = new Error("Environment load failed");
|
||||||
|
mocks.getWorkspaceState.mockRejectedValue(underlyingError);
|
||||||
|
|
||||||
|
const request = createMockRequest(
|
||||||
|
"https://api.test/api/v2/client/ck12345678901234567890123/environment",
|
||||||
|
new Map([["x-request-id", "req-v2-env"]])
|
||||||
|
);
|
||||||
|
|
||||||
|
const { GET } = await import("../../../../v1/client/[workspaceId]/environment/route");
|
||||||
|
const response = await GET(request, {
|
||||||
|
params: Promise.resolve({
|
||||||
|
workspaceId: "ck12345678901234567890123",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(500);
|
||||||
|
expect(await response.json()).toEqual({
|
||||||
|
code: "internal_server_error",
|
||||||
|
message: "An error occurred while processing your request.",
|
||||||
|
details: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(Sentry.withScope).not.toHaveBeenCalled();
|
||||||
|
expect(Sentry.captureException).toHaveBeenCalledWith(
|
||||||
|
underlyingError,
|
||||||
|
expect.objectContaining({
|
||||||
|
tags: expect.objectContaining({
|
||||||
|
apiVersion: "v2",
|
||||||
|
correlationId: "req-v2-env",
|
||||||
|
method: "GET",
|
||||||
|
path: "/api/v2/client/ck12345678901234567890123/environment",
|
||||||
|
}),
|
||||||
|
extra: expect.objectContaining({
|
||||||
|
error: expect.objectContaining({
|
||||||
|
name: "Error",
|
||||||
|
message: "Environment load failed",
|
||||||
|
}),
|
||||||
|
originalError: expect.objectContaining({
|
||||||
|
name: "Error",
|
||||||
|
message: "Environment load failed",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
contexts: expect.objectContaining({
|
||||||
|
apiRequest: expect.objectContaining({
|
||||||
|
apiVersion: "v2",
|
||||||
|
correlationId: "req-v2-env",
|
||||||
|
method: "GET",
|
||||||
|
path: "/api/v2/client/ck12345678901234567890123/environment",
|
||||||
|
status: 500,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
const mocks = vi.hoisted(() => ({
|
||||||
|
createDisplay: vi.fn(),
|
||||||
|
getIsContactsEnabled: vi.fn(),
|
||||||
|
getOrganizationIdFromWorkspaceId: vi.fn(),
|
||||||
|
reportApiError: vi.fn(),
|
||||||
|
resolveClientApiIds: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./lib/display", () => ({
|
||||||
|
createDisplay: mocks.createDisplay,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/modules/ee/license-check/lib/utils", () => ({
|
||||||
|
getIsContactsEnabled: mocks.getIsContactsEnabled,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/lib/utils/helper", () => ({
|
||||||
|
getOrganizationIdFromWorkspaceId: mocks.getOrganizationIdFromWorkspaceId,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/lib/utils/resolve-client-id", () => ({
|
||||||
|
resolveClientApiIds: mocks.resolveClientApiIds,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/app/lib/api/api-error-reporter", () => ({
|
||||||
|
reportApiError: mocks.reportApiError,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const environmentId = "cld1234567890abcdef123456";
|
||||||
|
const surveyId = "clg123456789012345678901234";
|
||||||
|
|
||||||
|
describe("api/v2 client displays route", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
mocks.resolveClientApiIds.mockResolvedValue({ workspaceId: environmentId });
|
||||||
|
mocks.getOrganizationIdFromWorkspaceId.mockResolvedValue("org_123");
|
||||||
|
mocks.getIsContactsEnabled.mockResolvedValue(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns a v2 bad request response for malformed JSON without reporting an internal error", async () => {
|
||||||
|
const request = new Request(`https://api.test/api/v2/client/${environmentId}/displays`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: "{",
|
||||||
|
});
|
||||||
|
|
||||||
|
const { POST } = await import("./route");
|
||||||
|
const response = await POST(request, {
|
||||||
|
params: Promise.resolve({ workspaceId: environmentId }),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(400);
|
||||||
|
expect(await response.json()).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
code: "bad_request",
|
||||||
|
message: "Invalid JSON in request body",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(mocks.createDisplay).not.toHaveBeenCalled();
|
||||||
|
expect(mocks.reportApiError).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reports unexpected createDisplay failures while keeping the response payload unchanged", async () => {
|
||||||
|
const underlyingError = new Error("display persistence failed");
|
||||||
|
mocks.createDisplay.mockRejectedValue(underlyingError);
|
||||||
|
|
||||||
|
const request = new Request(`https://api.test/api/v2/client/${environmentId}/displays`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
surveyId,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { POST } = await import("./route");
|
||||||
|
const response = await POST(request, {
|
||||||
|
params: Promise.resolve({ workspaceId: environmentId }),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(500);
|
||||||
|
expect(await response.json()).toEqual({
|
||||||
|
code: "internal_server_error",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
details: {},
|
||||||
|
});
|
||||||
|
expect(mocks.reportApiError).toHaveBeenCalledWith({
|
||||||
|
request,
|
||||||
|
status: 500,
|
||||||
|
error: underlyingError,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reports unexpected contact-license lookup failures with the same generic public response", async () => {
|
||||||
|
const underlyingError = new Error("license lookup failed");
|
||||||
|
mocks.getOrganizationIdFromWorkspaceId.mockRejectedValue(underlyingError);
|
||||||
|
|
||||||
|
const request = new Request(`https://api.test/api/v2/client/${environmentId}/displays`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
surveyId,
|
||||||
|
contactId: "clh123456789012345678901234",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { POST } = await import("./route");
|
||||||
|
const response = await POST(request, {
|
||||||
|
params: Promise.resolve({ workspaceId: environmentId }),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(500);
|
||||||
|
expect(await response.json()).toEqual({
|
||||||
|
code: "internal_server_error",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
details: {},
|
||||||
|
});
|
||||||
|
expect(mocks.reportApiError).toHaveBeenCalledWith({
|
||||||
|
request,
|
||||||
|
status: 500,
|
||||||
|
error: underlyingError,
|
||||||
|
});
|
||||||
|
expect(mocks.createDisplay).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,7 +2,7 @@ import { Prisma } from "@prisma/client";
|
|||||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
import { prisma } from "@formbricks/database";
|
import { prisma } from "@formbricks/database";
|
||||||
import { TContactAttributes } from "@formbricks/types/contact-attribute";
|
import { TContactAttributes } from "@formbricks/types/contact-attribute";
|
||||||
import { DatabaseError, ResourceNotFoundError, UniqueConstraintError } from "@formbricks/types/errors";
|
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||||
import { TResponseWithQuotaFull, TSurveyQuota } from "@formbricks/types/quota";
|
import { TResponseWithQuotaFull, TSurveyQuota } from "@formbricks/types/quota";
|
||||||
import { TResponse } from "@formbricks/types/responses";
|
import { TResponse } from "@formbricks/types/responses";
|
||||||
import { TTag } from "@formbricks/types/tags";
|
import { TTag } from "@formbricks/types/tags";
|
||||||
@@ -178,33 +178,9 @@ describe("createResponse V2", () => {
|
|||||||
).rejects.toThrow(ResourceNotFoundError);
|
).rejects.toThrow(ResourceNotFoundError);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should throw UniqueConstraintError on P2002 with singleUseId target", async () => {
|
test("should throw DatabaseError on Prisma known request error", async () => {
|
||||||
const prismaError = new Prisma.PrismaClientKnownRequestError("Unique constraint failed", {
|
|
||||||
code: "P2002",
|
|
||||||
clientVersion: "test",
|
|
||||||
meta: { target: ["surveyId", "singleUseId"] },
|
|
||||||
});
|
|
||||||
vi.mocked(mockTx.response.create).mockRejectedValue(prismaError);
|
|
||||||
await expect(
|
|
||||||
createResponse(mockResponseInput, mockTx as unknown as Prisma.TransactionClient)
|
|
||||||
).rejects.toThrow(UniqueConstraintError);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should throw DatabaseError on P2002 without singleUseId target", async () => {
|
|
||||||
const prismaError = new Prisma.PrismaClientKnownRequestError("Unique constraint failed", {
|
|
||||||
code: "P2002",
|
|
||||||
clientVersion: "test",
|
|
||||||
meta: { target: ["displayId"] },
|
|
||||||
});
|
|
||||||
vi.mocked(mockTx.response.create).mockRejectedValue(prismaError);
|
|
||||||
await expect(
|
|
||||||
createResponse(mockResponseInput, mockTx as unknown as Prisma.TransactionClient)
|
|
||||||
).rejects.toThrow(DatabaseError);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should throw DatabaseError on non-P2002 Prisma known request error", async () => {
|
|
||||||
const prismaError = new Prisma.PrismaClientKnownRequestError("Test Prisma Error", {
|
const prismaError = new Prisma.PrismaClientKnownRequestError("Test Prisma Error", {
|
||||||
code: "P2025",
|
code: "P2002",
|
||||||
clientVersion: "test",
|
clientVersion: "test",
|
||||||
});
|
});
|
||||||
vi.mocked(mockTx.response.create).mockRejectedValue(prismaError);
|
vi.mocked(mockTx.response.create).mockRejectedValue(prismaError);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import "server-only";
|
|||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { prisma } from "@formbricks/database";
|
import { prisma } from "@formbricks/database";
|
||||||
import { TContactAttributes } from "@formbricks/types/contact-attribute";
|
import { TContactAttributes } from "@formbricks/types/contact-attribute";
|
||||||
import { DatabaseError, ResourceNotFoundError, UniqueConstraintError } from "@formbricks/types/errors";
|
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||||
import { TResponseWithQuotaFull } from "@formbricks/types/quota";
|
import { TResponseWithQuotaFull } from "@formbricks/types/quota";
|
||||||
import { TResponse, ZResponseInput } from "@formbricks/types/responses";
|
import { TResponse, ZResponseInput } from "@formbricks/types/responses";
|
||||||
import { TTag } from "@formbricks/types/tags";
|
import { TTag } from "@formbricks/types/tags";
|
||||||
@@ -131,13 +131,6 @@ export const createResponse = async (
|
|||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
if (error.code === "P2002") {
|
|
||||||
const target = (error.meta?.target as string[]) ?? [];
|
|
||||||
if (target?.includes("singleUseId")) {
|
|
||||||
throw new UniqueConstraintError("Response already submitted for this single-use link");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new DatabaseError(error.message);
|
throw new DatabaseError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ const mockSurvey: TSurvey = {
|
|||||||
isCaptureIpEnabled: false,
|
isCaptureIpEnabled: false,
|
||||||
metadata: {},
|
metadata: {},
|
||||||
slug: null,
|
slug: null,
|
||||||
isAutoProgressingEnabled: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockResponseInput: TResponseInputV2 = {
|
const mockResponseInput: TResponseInputV2 = {
|
||||||
@@ -127,6 +126,7 @@ describe("checkSurveyValidity", () => {
|
|||||||
expect(responses.badRequestResponse).toHaveBeenCalledWith(
|
expect(responses.badRequestResponse).toHaveBeenCalledWith(
|
||||||
"Survey is part of another workspace",
|
"Survey is part of another workspace",
|
||||||
{
|
{
|
||||||
|
"survey.workspaceId": "ws-2",
|
||||||
workspaceId: "ws-1",
|
workspaceId: "ws-1",
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export const checkSurveyValidity = async (
|
|||||||
return responses.badRequestResponse(
|
return responses.badRequestResponse(
|
||||||
"Survey is part of another workspace",
|
"Survey is part of another workspace",
|
||||||
{
|
{
|
||||||
|
"survey.workspaceId": survey.workspaceId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
const mocks = vi.hoisted(() => ({
|
||||||
|
checkSurveyValidity: vi.fn(),
|
||||||
|
createResponseWithQuotaEvaluation: vi.fn(),
|
||||||
|
getClientIpFromHeaders: vi.fn(),
|
||||||
|
getIsContactsEnabled: vi.fn(),
|
||||||
|
getOrganizationIdFromWorkspaceId: vi.fn(),
|
||||||
|
getSurvey: vi.fn(),
|
||||||
|
reportApiError: vi.fn(),
|
||||||
|
resolveClientApiIds: vi.fn(),
|
||||||
|
sendToPipeline: vi.fn(),
|
||||||
|
validateResponseData: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/app/api/v2/client/[workspaceId]/responses/lib/utils", () => ({
|
||||||
|
checkSurveyValidity: mocks.checkSurveyValidity,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./lib/response", () => ({
|
||||||
|
createResponseWithQuotaEvaluation: mocks.createResponseWithQuotaEvaluation,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/app/lib/api/api-error-reporter", () => ({
|
||||||
|
reportApiError: mocks.reportApiError,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/app/lib/pipelines", () => ({
|
||||||
|
sendToPipeline: mocks.sendToPipeline,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/lib/survey/service", () => ({
|
||||||
|
getSurvey: mocks.getSurvey,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/lib/utils/client-ip", () => ({
|
||||||
|
getClientIpFromHeaders: mocks.getClientIpFromHeaders,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/lib/utils/helper", () => ({
|
||||||
|
getOrganizationIdFromWorkspaceId: mocks.getOrganizationIdFromWorkspaceId,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/lib/utils/resolve-client-id", () => ({
|
||||||
|
resolveClientApiIds: mocks.resolveClientApiIds,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/modules/api/lib/validation", () => ({
|
||||||
|
formatValidationErrorsForV1Api: vi.fn((errors) => errors),
|
||||||
|
validateResponseData: mocks.validateResponseData,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/modules/ee/license-check/lib/utils", () => ({
|
||||||
|
getIsContactsEnabled: mocks.getIsContactsEnabled,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const environmentId = "cld1234567890abcdef123456";
|
||||||
|
const surveyId = "clg123456789012345678901234";
|
||||||
|
|
||||||
|
describe("api/v2 client responses route", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
mocks.resolveClientApiIds.mockResolvedValue({ workspaceId: environmentId });
|
||||||
|
mocks.checkSurveyValidity.mockResolvedValue(null);
|
||||||
|
mocks.getSurvey.mockResolvedValue({
|
||||||
|
id: surveyId,
|
||||||
|
environmentId,
|
||||||
|
blocks: [],
|
||||||
|
questions: [],
|
||||||
|
isCaptureIpEnabled: false,
|
||||||
|
});
|
||||||
|
mocks.validateResponseData.mockReturnValue(null);
|
||||||
|
mocks.getOrganizationIdFromWorkspaceId.mockResolvedValue("org_123");
|
||||||
|
mocks.getIsContactsEnabled.mockResolvedValue(true);
|
||||||
|
mocks.getClientIpFromHeaders.mockResolvedValue("127.0.0.1");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reports unexpected response creation failures while keeping the public payload generic", async () => {
|
||||||
|
const underlyingError = new Error("response persistence failed");
|
||||||
|
mocks.createResponseWithQuotaEvaluation.mockRejectedValue(underlyingError);
|
||||||
|
|
||||||
|
const request = new Request(`https://api.test/api/v2/client/${environmentId}/responses`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-request-id": "req-v2-response",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
surveyId,
|
||||||
|
finished: false,
|
||||||
|
data: {},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { POST } = await import("./route");
|
||||||
|
const response = await POST(request, {
|
||||||
|
params: Promise.resolve({ workspaceId: environmentId }),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(500);
|
||||||
|
expect(await response.json()).toEqual({
|
||||||
|
code: "internal_server_error",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
details: {},
|
||||||
|
});
|
||||||
|
expect(mocks.reportApiError).toHaveBeenCalledWith({
|
||||||
|
request,
|
||||||
|
status: 500,
|
||||||
|
error: underlyingError,
|
||||||
|
});
|
||||||
|
expect(mocks.sendToPipeline).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reports unexpected pre-persistence failures with the same generic public response", async () => {
|
||||||
|
const underlyingError = new Error("survey lookup failed");
|
||||||
|
mocks.getSurvey.mockRejectedValue(underlyingError);
|
||||||
|
|
||||||
|
const request = new Request(`https://api.test/api/v2/client/${environmentId}/responses`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-request-id": "req-v2-response-pre-check",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
surveyId,
|
||||||
|
finished: false,
|
||||||
|
data: {},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { POST } = await import("./route");
|
||||||
|
const response = await POST(request, {
|
||||||
|
params: Promise.resolve({ workspaceId: environmentId }),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(500);
|
||||||
|
expect(await response.json()).toEqual({
|
||||||
|
code: "internal_server_error",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
details: {},
|
||||||
|
});
|
||||||
|
expect(mocks.reportApiError).toHaveBeenCalledWith({
|
||||||
|
request,
|
||||||
|
status: 500,
|
||||||
|
error: underlyingError,
|
||||||
|
});
|
||||||
|
expect(mocks.createResponseWithQuotaEvaluation).not.toHaveBeenCalled();
|
||||||
|
expect(mocks.sendToPipeline).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { UAParser } from "ua-parser-js";
|
import { UAParser } from "ua-parser-js";
|
||||||
import { InvalidInputError, UniqueConstraintError } from "@formbricks/types/errors";
|
import { InvalidInputError } from "@formbricks/types/errors";
|
||||||
import { TResponseWithQuotaFull } from "@formbricks/types/quota";
|
import { TResponseWithQuotaFull } from "@formbricks/types/quota";
|
||||||
import { checkSurveyValidity } from "@/app/api/v2/client/[workspaceId]/responses/lib/utils";
|
import { checkSurveyValidity } from "@/app/api/v2/client/[workspaceId]/responses/lib/utils";
|
||||||
import { reportApiError } from "@/app/lib/api/api-error-reporter";
|
import { reportApiError } from "@/app/lib/api/api-error-reporter";
|
||||||
@@ -164,10 +164,6 @@ const createResponseForRequest = async ({
|
|||||||
return responses.badRequestResponse(error.message, undefined, true);
|
return responses.badRequestResponse(error.message, undefined, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error instanceof UniqueConstraintError) {
|
|
||||||
return responses.conflictResponse(error.message, undefined, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = getUnexpectedPublicErrorResponse();
|
const response = getUnexpectedPublicErrorResponse();
|
||||||
reportApiError({
|
reportApiError({
|
||||||
request,
|
request,
|
||||||
|
|||||||
@@ -9,22 +9,6 @@ const { mockAuthenticateRequest, mockGetServerSession } = vi.hoisted(() => ({
|
|||||||
mockGetServerSession: vi.fn(),
|
mockGetServerSession: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { mockQueueAuditEvent, mockBuildAuditLogBaseObject } = vi.hoisted(() => ({
|
|
||||||
mockQueueAuditEvent: vi.fn().mockImplementation(async () => undefined),
|
|
||||||
mockBuildAuditLogBaseObject: vi.fn((action: string, targetType: string, apiUrl: string) => ({
|
|
||||||
action,
|
|
||||||
targetType,
|
|
||||||
userId: "unknown",
|
|
||||||
targetId: "unknown",
|
|
||||||
organizationId: "unknown",
|
|
||||||
status: "failure",
|
|
||||||
oldObject: undefined,
|
|
||||||
newObject: undefined,
|
|
||||||
userType: "api",
|
|
||||||
apiUrl,
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("next-auth", () => ({
|
vi.mock("next-auth", () => ({
|
||||||
getServerSession: mockGetServerSession,
|
getServerSession: mockGetServerSession,
|
||||||
}));
|
}));
|
||||||
@@ -41,14 +25,6 @@ vi.mock("@/modules/core/rate-limit/helpers", () => ({
|
|||||||
applyRateLimit: vi.fn().mockResolvedValue(undefined),
|
applyRateLimit: vi.fn().mockResolvedValue(undefined),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("@/modules/ee/audit-logs/lib/handler", () => ({
|
|
||||||
queueAuditEvent: mockQueueAuditEvent,
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/app/lib/api/with-api-logging", () => ({
|
|
||||||
buildAuditLogBaseObject: mockBuildAuditLogBaseObject,
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@formbricks/logger", () => ({
|
vi.mock("@formbricks/logger", () => ({
|
||||||
logger: {
|
logger: {
|
||||||
withContext: vi.fn(() => ({
|
withContext: vi.fn(() => ({
|
||||||
@@ -69,114 +45,6 @@ describe("withV3ApiWrapper", () => {
|
|||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("passes an audit log to the handler and queues success after the response", async () => {
|
|
||||||
const { queueAuditEvent } = await import("@/modules/ee/audit-logs/lib/handler");
|
|
||||||
|
|
||||||
mockGetServerSession.mockResolvedValue({
|
|
||||||
user: { id: "user_1", name: "Test", email: "t@example.com" },
|
|
||||||
expires: "2026-01-01",
|
|
||||||
});
|
|
||||||
|
|
||||||
const handler = vi.fn(async ({ auditLog }) => {
|
|
||||||
expect(auditLog).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
action: "deleted",
|
|
||||||
targetType: "survey",
|
|
||||||
userId: "user_1",
|
|
||||||
userType: "user",
|
|
||||||
status: "failure",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (auditLog) {
|
|
||||||
auditLog.targetId = "survey_1";
|
|
||||||
auditLog.organizationId = "org_1";
|
|
||||||
auditLog.oldObject = { id: "survey_1" };
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.json({ ok: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
const wrapped = withV3ApiWrapper({
|
|
||||||
auth: "both",
|
|
||||||
action: "deleted",
|
|
||||||
targetType: "survey",
|
|
||||||
handler,
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await wrapped(
|
|
||||||
new NextRequest("http://localhost/api/v3/surveys/survey_1", {
|
|
||||||
method: "DELETE",
|
|
||||||
headers: { "x-request-id": "req-audit" },
|
|
||||||
}),
|
|
||||||
{} as never
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(queueAuditEvent).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
action: "deleted",
|
|
||||||
targetType: "survey",
|
|
||||||
targetId: "survey_1",
|
|
||||||
organizationId: "org_1",
|
|
||||||
userId: "user_1",
|
|
||||||
userType: "user",
|
|
||||||
status: "success",
|
|
||||||
oldObject: { id: "survey_1" },
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("queues a failure audit log when the handler returns a non-ok response", async () => {
|
|
||||||
const { queueAuditEvent } = await import("@/modules/ee/audit-logs/lib/handler");
|
|
||||||
|
|
||||||
mockAuthenticateRequest.mockResolvedValue({
|
|
||||||
type: "apiKey",
|
|
||||||
apiKeyId: "key_1",
|
|
||||||
organizationId: "org_1",
|
|
||||||
organizationAccess: { accessControl: { read: true, write: true } },
|
|
||||||
environmentPermissions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const wrapped = withV3ApiWrapper({
|
|
||||||
auth: "both",
|
|
||||||
action: "deleted",
|
|
||||||
targetType: "survey",
|
|
||||||
handler: async ({ auditLog }) => {
|
|
||||||
if (auditLog) {
|
|
||||||
auditLog.targetId = "survey_2";
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response("forbidden", { status: 403 });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await wrapped(
|
|
||||||
new NextRequest("http://localhost/api/v3/surveys/survey_2", {
|
|
||||||
method: "DELETE",
|
|
||||||
headers: {
|
|
||||||
"x-request-id": "req-failure-audit",
|
|
||||||
"x-api-key": "fbk_test",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{} as never
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.status).toBe(403);
|
|
||||||
expect(queueAuditEvent).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
action: "deleted",
|
|
||||||
targetType: "survey",
|
|
||||||
targetId: "survey_2",
|
|
||||||
organizationId: "org_1",
|
|
||||||
userId: "key_1",
|
|
||||||
userType: "api",
|
|
||||||
status: "failure",
|
|
||||||
eventId: "req-failure-audit",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("uses session auth first in both mode and injects request id into plain responses", async () => {
|
test("uses session auth first in both mode and injects request id into plain responses", async () => {
|
||||||
const { applyRateLimit } = await import("@/modules/core/rate-limit/helpers");
|
const { applyRateLimit } = await import("@/modules/core/rate-limit/helpers");
|
||||||
mockGetServerSession.mockResolvedValue({
|
mockGetServerSession.mockResolvedValue({
|
||||||
|
|||||||
@@ -4,13 +4,10 @@ import { z } from "zod";
|
|||||||
import { logger } from "@formbricks/logger";
|
import { logger } from "@formbricks/logger";
|
||||||
import { TooManyRequestsError } from "@formbricks/types/errors";
|
import { TooManyRequestsError } from "@formbricks/types/errors";
|
||||||
import { authenticateRequest } from "@/app/api/v1/auth";
|
import { authenticateRequest } from "@/app/api/v1/auth";
|
||||||
import { buildAuditLogBaseObject } from "@/app/lib/api/with-api-logging";
|
|
||||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||||
import { applyRateLimit } from "@/modules/core/rate-limit/helpers";
|
import { applyRateLimit } from "@/modules/core/rate-limit/helpers";
|
||||||
import { rateLimitConfigs } from "@/modules/core/rate-limit/rate-limit-configs";
|
import { rateLimitConfigs } from "@/modules/core/rate-limit/rate-limit-configs";
|
||||||
import type { TRateLimitConfig } from "@/modules/core/rate-limit/types/rate-limit";
|
import type { TRateLimitConfig } from "@/modules/core/rate-limit/types/rate-limit";
|
||||||
import { queueAuditEvent } from "@/modules/ee/audit-logs/lib/handler";
|
|
||||||
import { TAuditAction, TAuditTarget } from "@/modules/ee/audit-logs/types/audit-log";
|
|
||||||
import {
|
import {
|
||||||
type InvalidParam,
|
type InvalidParam,
|
||||||
problemBadRequest,
|
problemBadRequest,
|
||||||
@@ -18,7 +15,7 @@ import {
|
|||||||
problemTooManyRequests,
|
problemTooManyRequests,
|
||||||
problemUnauthorized,
|
problemUnauthorized,
|
||||||
} from "./response";
|
} from "./response";
|
||||||
import type { TV3AuditLog, TV3Authentication } from "./types";
|
import type { TV3Authentication } from "./types";
|
||||||
|
|
||||||
type TV3Schema = z.ZodTypeAny;
|
type TV3Schema = z.ZodTypeAny;
|
||||||
type MaybePromise<T> = T | Promise<T>;
|
type MaybePromise<T> = T | Promise<T>;
|
||||||
@@ -41,7 +38,6 @@ export type TV3HandlerParams<TParsedInput = Record<string, never>, TProps = unkn
|
|||||||
req: NextRequest;
|
req: NextRequest;
|
||||||
props: TProps;
|
props: TProps;
|
||||||
authentication: TV3Authentication;
|
authentication: TV3Authentication;
|
||||||
auditLog?: TV3AuditLog;
|
|
||||||
parsedInput: TParsedInput;
|
parsedInput: TParsedInput;
|
||||||
requestId: string;
|
requestId: string;
|
||||||
instance: string;
|
instance: string;
|
||||||
@@ -52,8 +48,6 @@ export type TWithV3ApiWrapperParams<S extends TV3Schemas | undefined, TProps = u
|
|||||||
schemas?: S;
|
schemas?: S;
|
||||||
rateLimit?: boolean;
|
rateLimit?: boolean;
|
||||||
customRateLimitConfig?: TRateLimitConfig;
|
customRateLimitConfig?: TRateLimitConfig;
|
||||||
action?: TAuditAction;
|
|
||||||
targetType?: TAuditTarget;
|
|
||||||
handler: (params: TV3HandlerParams<TV3ParsedInput<S>, TProps>) => MaybePromise<Response>;
|
handler: (params: TV3HandlerParams<TV3ParsedInput<S>, TProps>) => MaybePromise<Response>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -299,61 +293,10 @@ async function applyV3RateLimitOrRespond(params: {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildV3AuditLog(
|
|
||||||
authentication: TV3Authentication,
|
|
||||||
action?: TAuditAction,
|
|
||||||
targetType?: TAuditTarget,
|
|
||||||
apiUrl?: string
|
|
||||||
): TV3AuditLog | undefined {
|
|
||||||
if (!authentication || !action || !targetType || !apiUrl) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auditLog = buildAuditLogBaseObject(action, targetType, apiUrl);
|
|
||||||
|
|
||||||
if ("user" in authentication && authentication.user?.id) {
|
|
||||||
auditLog.userId = authentication.user.id;
|
|
||||||
auditLog.userType = "user";
|
|
||||||
} else if ("apiKeyId" in authentication) {
|
|
||||||
auditLog.userId = authentication.apiKeyId;
|
|
||||||
auditLog.userType = "api";
|
|
||||||
auditLog.organizationId = authentication.organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return auditLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function queueV3AuditLog(
|
|
||||||
auditLog: TV3AuditLog | undefined,
|
|
||||||
requestId: string,
|
|
||||||
log: ReturnType<typeof logger.withContext>
|
|
||||||
): Promise<void> {
|
|
||||||
if (!auditLog) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await queueAuditEvent({
|
|
||||||
...auditLog,
|
|
||||||
...(auditLog.status === "failure" ? { eventId: auditLog.eventId ?? requestId } : {}),
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
log.error({ error }, "Failed to queue V3 audit event");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const withV3ApiWrapper = <S extends TV3Schemas | undefined, TProps = unknown>(
|
export const withV3ApiWrapper = <S extends TV3Schemas | undefined, TProps = unknown>(
|
||||||
params: TWithV3ApiWrapperParams<S, TProps>
|
params: TWithV3ApiWrapperParams<S, TProps>
|
||||||
): ((req: NextRequest, props: TProps) => Promise<Response>) => {
|
): ((req: NextRequest, props: TProps) => Promise<Response>) => {
|
||||||
const {
|
const { auth = "both", schemas, rateLimit = true, customRateLimitConfig, handler } = params;
|
||||||
auth = "both",
|
|
||||||
schemas,
|
|
||||||
rateLimit = true,
|
|
||||||
customRateLimitConfig,
|
|
||||||
handler,
|
|
||||||
action,
|
|
||||||
targetType,
|
|
||||||
} = params;
|
|
||||||
|
|
||||||
return async (req: NextRequest, props: TProps): Promise<Response> => {
|
return async (req: NextRequest, props: TProps): Promise<Response> => {
|
||||||
const requestId = req.headers.get("x-request-id") ?? crypto.randomUUID();
|
const requestId = req.headers.get("x-request-id") ?? crypto.randomUUID();
|
||||||
@@ -363,7 +306,6 @@ export const withV3ApiWrapper = <S extends TV3Schemas | undefined, TProps = unkn
|
|||||||
method: req.method,
|
method: req.method,
|
||||||
path: instance,
|
path: instance,
|
||||||
});
|
});
|
||||||
let auditLog: TV3AuditLog | undefined;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const authResult = await authenticateV3RequestOrRespond(req, auth, requestId, instance);
|
const authResult = await authenticateV3RequestOrRespond(req, auth, requestId, instance);
|
||||||
@@ -389,33 +331,17 @@ export const withV3ApiWrapper = <S extends TV3Schemas | undefined, TProps = unkn
|
|||||||
return rateLimitResponse;
|
return rateLimitResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
auditLog = buildV3AuditLog(authResult.authentication, action, targetType, req.url);
|
|
||||||
|
|
||||||
const response = await handler({
|
const response = await handler({
|
||||||
req,
|
req,
|
||||||
props,
|
props,
|
||||||
authentication: authResult.authentication,
|
authentication: authResult.authentication,
|
||||||
auditLog,
|
|
||||||
parsedInput: parsedInputResult.parsedInput,
|
parsedInput: parsedInputResult.parsedInput,
|
||||||
requestId,
|
requestId,
|
||||||
instance,
|
instance,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (auditLog) {
|
|
||||||
if (response.ok) {
|
|
||||||
auditLog.status = "success";
|
|
||||||
} else {
|
|
||||||
auditLog.eventId = requestId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await queueV3AuditLog(auditLog, requestId, log);
|
|
||||||
return ensureRequestIdHeader(response, requestId);
|
return ensureRequestIdHeader(response, requestId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (auditLog) {
|
|
||||||
auditLog.eventId = requestId;
|
|
||||||
await queueV3AuditLog(auditLog, requestId, log);
|
|
||||||
}
|
|
||||||
log.error({ error, statusCode: 500 }, "V3 API unexpected error");
|
log.error({ error, statusCode: 500 }, "V3 API unexpected error");
|
||||||
return problemInternalError(requestId, "An unexpected error occurred.", instance);
|
return problemInternalError(requestId, "An unexpected error occurred.", instance);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
problemTooManyRequests,
|
problemTooManyRequests,
|
||||||
problemUnauthorized,
|
problemUnauthorized,
|
||||||
successListResponse,
|
successListResponse,
|
||||||
successResponse,
|
|
||||||
} from "./response";
|
} from "./response";
|
||||||
|
|
||||||
describe("v3 problem responses", () => {
|
describe("v3 problem responses", () => {
|
||||||
@@ -94,27 +93,3 @@ describe("successListResponse", () => {
|
|||||||
expect(res.headers.get("Cache-Control")).toBe("private, max-age=0");
|
expect(res.headers.get("Cache-Control")).toBe("private, max-age=0");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("successResponse", () => {
|
|
||||||
test("wraps the payload in a data envelope", async () => {
|
|
||||||
const res = successResponse({ id: "survey_1" }, { requestId: "req-success" });
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
expect(res.headers.get("X-Request-Id")).toBe("req-success");
|
|
||||||
expect(res.headers.get("Cache-Control")).toContain("no-store");
|
|
||||||
expect(await res.json()).toEqual({
|
|
||||||
data: { id: "survey_1" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("allows custom status and cache headers", async () => {
|
|
||||||
const res = successResponse(
|
|
||||||
{ ok: true },
|
|
||||||
{
|
|
||||||
cache: "private, max-age=60",
|
|
||||||
status: 202,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
expect(res.status).toBe(202);
|
|
||||||
expect(res.headers.get("Cache-Control")).toBe("private, max-age=60");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -147,27 +147,3 @@ export function successListResponse<T, TMeta extends Record<string, unknown>>(
|
|||||||
}
|
}
|
||||||
return Response.json({ data, meta }, { status: 200, headers });
|
return Response.json({ data, meta }, { status: 200, headers });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function successResponse<T>(
|
|
||||||
data: T,
|
|
||||||
options?: { requestId?: string; cache?: string; status?: number }
|
|
||||||
): Response {
|
|
||||||
const headers: Record<string, string> = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"Cache-Control": options?.cache ?? CACHE_NO_STORE,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options?.requestId) {
|
|
||||||
headers["X-Request-Id"] = options.requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.json(
|
|
||||||
{
|
|
||||||
data,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
status: options?.status ?? 200,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import type { Session } from "next-auth";
|
import type { Session } from "next-auth";
|
||||||
import type { TAuthenticationApiKey } from "@formbricks/types/auth";
|
import type { TAuthenticationApiKey } from "@formbricks/types/auth";
|
||||||
import type { TApiAuditLog } from "@/app/lib/api/with-api-logging";
|
|
||||||
|
|
||||||
export type TV3Authentication = TAuthenticationApiKey | Session | null;
|
export type TV3Authentication = TAuthenticationApiKey | Session | null;
|
||||||
export type TV3AuditLog = TApiAuditLog;
|
|
||||||
|
|||||||
@@ -1,318 +0,0 @@
|
|||||||
import { ApiKeyPermission } from "@prisma/client";
|
|
||||||
import { NextRequest } from "next/server";
|
|
||||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
||||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
|
|
||||||
import { requireV3WorkspaceAccess } from "@/app/api/v3/lib/auth";
|
|
||||||
import { getSurvey } from "@/lib/survey/service";
|
|
||||||
import { deleteSurvey } from "@/modules/survey/lib/surveys";
|
|
||||||
import { DELETE } from "./route";
|
|
||||||
|
|
||||||
const { mockAuthenticateRequest } = vi.hoisted(() => ({
|
|
||||||
mockAuthenticateRequest: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { mockQueueAuditEvent, mockBuildAuditLogBaseObject } = vi.hoisted(() => ({
|
|
||||||
mockQueueAuditEvent: vi.fn().mockImplementation(async () => undefined),
|
|
||||||
mockBuildAuditLogBaseObject: vi.fn((action: string, targetType: string, apiUrl: string) => ({
|
|
||||||
action,
|
|
||||||
targetType,
|
|
||||||
userId: "unknown",
|
|
||||||
targetId: "unknown",
|
|
||||||
organizationId: "unknown",
|
|
||||||
status: "failure",
|
|
||||||
oldObject: undefined,
|
|
||||||
newObject: undefined,
|
|
||||||
userType: "api",
|
|
||||||
apiUrl,
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("next-auth", () => ({
|
|
||||||
getServerSession: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/app/api/v1/auth", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("@/app/api/v1/auth")>();
|
|
||||||
return { ...actual, authenticateRequest: mockAuthenticateRequest };
|
|
||||||
});
|
|
||||||
|
|
||||||
vi.mock("@/modules/core/rate-limit/helpers", () => ({
|
|
||||||
applyRateLimit: vi.fn().mockResolvedValue(undefined),
|
|
||||||
applyIPRateLimit: vi.fn().mockResolvedValue(undefined),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/lib/constants", async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import("@/lib/constants")>();
|
|
||||||
return { ...actual, AUDIT_LOG_ENABLED: false };
|
|
||||||
});
|
|
||||||
|
|
||||||
vi.mock("@/app/api/v3/lib/auth", () => ({
|
|
||||||
requireV3WorkspaceAccess: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/lib/survey/service", () => ({
|
|
||||||
getSurvey: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/modules/survey/lib/surveys", () => ({
|
|
||||||
deleteSurvey: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/modules/ee/audit-logs/lib/handler", () => ({
|
|
||||||
queueAuditEvent: mockQueueAuditEvent,
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/app/lib/api/with-api-logging", () => ({
|
|
||||||
buildAuditLogBaseObject: mockBuildAuditLogBaseObject,
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@formbricks/logger", () => ({
|
|
||||||
logger: {
|
|
||||||
withContext: vi.fn(() => ({
|
|
||||||
warn: vi.fn(),
|
|
||||||
error: vi.fn(),
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const getServerSession = vi.mocked((await import("next-auth")).getServerSession);
|
|
||||||
const queueAuditEvent = vi.mocked((await import("@/modules/ee/audit-logs/lib/handler")).queueAuditEvent);
|
|
||||||
|
|
||||||
const surveyId = "clxx1234567890123456789012";
|
|
||||||
const workspaceId = "clzz9876543210987654321098";
|
|
||||||
|
|
||||||
function createRequest(url: string, requestId?: string, extraHeaders?: Record<string, string>): NextRequest {
|
|
||||||
const headers: Record<string, string> = { ...extraHeaders };
|
|
||||||
if (requestId) {
|
|
||||||
headers["x-request-id"] = requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new NextRequest(url, {
|
|
||||||
method: "DELETE",
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const apiKeyAuth = {
|
|
||||||
type: "apiKey" as const,
|
|
||||||
apiKeyId: "key_1",
|
|
||||||
organizationId: "org_1",
|
|
||||||
organizationAccess: {
|
|
||||||
accessControl: { read: true, write: true },
|
|
||||||
},
|
|
||||||
workspacePermissions: [
|
|
||||||
{
|
|
||||||
workspaceId,
|
|
||||||
workspaceName: "W",
|
|
||||||
permission: ApiKeyPermission.write,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("DELETE /api/v3/surveys/[surveyId]", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.resetAllMocks();
|
|
||||||
getServerSession.mockResolvedValue({
|
|
||||||
user: { id: "user_1", name: "User", email: "u@example.com" },
|
|
||||||
expires: "2026-01-01",
|
|
||||||
} as any);
|
|
||||||
mockAuthenticateRequest.mockResolvedValue(null);
|
|
||||||
vi.mocked(getSurvey).mockResolvedValue({
|
|
||||||
id: surveyId,
|
|
||||||
name: "Delete me",
|
|
||||||
workspaceId: workspaceId,
|
|
||||||
type: "link",
|
|
||||||
status: "draft",
|
|
||||||
createdAt: new Date("2026-04-15T10:00:00.000Z"),
|
|
||||||
updatedAt: new Date("2026-04-15T10:00:00.000Z"),
|
|
||||||
responseCount: 0,
|
|
||||||
creator: { name: "User" },
|
|
||||||
singleUse: null,
|
|
||||||
} as any);
|
|
||||||
vi.mocked(deleteSurvey).mockResolvedValue({
|
|
||||||
id: surveyId,
|
|
||||||
workspaceId,
|
|
||||||
type: "link",
|
|
||||||
segment: null,
|
|
||||||
triggers: [],
|
|
||||||
} as any);
|
|
||||||
vi.mocked(requireV3WorkspaceAccess).mockResolvedValue({
|
|
||||||
workspaceId,
|
|
||||||
organizationId: "org_1",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
vi.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns 401 when no session and no API key", async () => {
|
|
||||||
getServerSession.mockResolvedValue(null);
|
|
||||||
mockAuthenticateRequest.mockResolvedValue(null);
|
|
||||||
|
|
||||||
const res = await DELETE(createRequest(`http://localhost/api/v3/surveys/${surveyId}`), {
|
|
||||||
params: Promise.resolve({ surveyId }),
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
expect(res.status).toBe(401);
|
|
||||||
expect(vi.mocked(getSurvey)).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns 200 with session auth and deletes the survey", async () => {
|
|
||||||
const res = await DELETE(createRequest(`http://localhost/api/v3/surveys/${surveyId}`, "req-delete"), {
|
|
||||||
params: Promise.resolve({ surveyId }),
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
expect(requireV3WorkspaceAccess).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({ user: expect.any(Object) }),
|
|
||||||
workspaceId,
|
|
||||||
"readWrite",
|
|
||||||
"req-delete",
|
|
||||||
`/api/v3/surveys/${surveyId}`
|
|
||||||
);
|
|
||||||
expect(deleteSurvey).toHaveBeenCalledWith(surveyId);
|
|
||||||
expect(await res.json()).toEqual({
|
|
||||||
data: {
|
|
||||||
id: surveyId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns 200 with x-api-key when the key can delete in the survey workspace", async () => {
|
|
||||||
getServerSession.mockResolvedValue(null);
|
|
||||||
mockAuthenticateRequest.mockResolvedValue(apiKeyAuth as any);
|
|
||||||
|
|
||||||
const res = await DELETE(
|
|
||||||
createRequest(`http://localhost/api/v3/surveys/${surveyId}`, "req-api-key", {
|
|
||||||
"x-api-key": "fbk_test",
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
params: Promise.resolve({ surveyId }),
|
|
||||||
} as never
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
expect(requireV3WorkspaceAccess).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({ apiKeyId: "key_1" }),
|
|
||||||
workspaceId,
|
|
||||||
"readWrite",
|
|
||||||
"req-api-key",
|
|
||||||
`/api/v3/surveys/${surveyId}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns 400 when surveyId is invalid", async () => {
|
|
||||||
const res = await DELETE(createRequest("http://localhost/api/v3/surveys/not-a-cuid"), {
|
|
||||||
params: Promise.resolve({ surveyId: "not-a-cuid" }),
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
expect(res.status).toBe(400);
|
|
||||||
expect(vi.mocked(getSurvey)).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns 403 when the survey does not exist", async () => {
|
|
||||||
vi.mocked(getSurvey).mockResolvedValueOnce(null);
|
|
||||||
|
|
||||||
const res = await DELETE(createRequest(`http://localhost/api/v3/surveys/${surveyId}`), {
|
|
||||||
params: Promise.resolve({ surveyId }),
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
expect(res.status).toBe(403);
|
|
||||||
expect(deleteSurvey).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns 403 when the user lacks readWrite workspace access", async () => {
|
|
||||||
vi.mocked(requireV3WorkspaceAccess).mockResolvedValueOnce(
|
|
||||||
new Response(
|
|
||||||
JSON.stringify({
|
|
||||||
title: "Forbidden",
|
|
||||||
status: 403,
|
|
||||||
detail: "You are not authorized to access this resource",
|
|
||||||
requestId: "req-forbidden",
|
|
||||||
}),
|
|
||||||
{ status: 403, headers: { "Content-Type": "application/problem+json" } }
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const res = await DELETE(createRequest(`http://localhost/api/v3/surveys/${surveyId}`, "req-forbidden"), {
|
|
||||||
params: Promise.resolve({ surveyId }),
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
expect(res.status).toBe(403);
|
|
||||||
expect(deleteSurvey).not.toHaveBeenCalled();
|
|
||||||
expect(queueAuditEvent).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
action: "deleted",
|
|
||||||
targetType: "survey",
|
|
||||||
targetId: "unknown",
|
|
||||||
organizationId: "unknown",
|
|
||||||
userId: "user_1",
|
|
||||||
userType: "user",
|
|
||||||
status: "failure",
|
|
||||||
oldObject: undefined,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns 500 when survey deletion fails", async () => {
|
|
||||||
vi.mocked(deleteSurvey).mockRejectedValueOnce(new DatabaseError("db down"));
|
|
||||||
|
|
||||||
const res = await DELETE(createRequest(`http://localhost/api/v3/surveys/${surveyId}`, "req-db"), {
|
|
||||||
params: Promise.resolve({ surveyId }),
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
expect(res.status).toBe(500);
|
|
||||||
const body = await res.json();
|
|
||||||
expect(body.code).toBe("internal_server_error");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns 403 when the survey is deleted after authorization succeeds", async () => {
|
|
||||||
vi.mocked(deleteSurvey).mockRejectedValueOnce(new ResourceNotFoundError("Survey", surveyId));
|
|
||||||
|
|
||||||
const res = await DELETE(createRequest(`http://localhost/api/v3/surveys/${surveyId}`, "req-race"), {
|
|
||||||
params: Promise.resolve({ surveyId }),
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
expect(res.status).toBe(403);
|
|
||||||
const body = await res.json();
|
|
||||||
expect(body.code).toBe("forbidden");
|
|
||||||
expect(queueAuditEvent).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
action: "deleted",
|
|
||||||
targetType: "survey",
|
|
||||||
targetId: surveyId,
|
|
||||||
organizationId: "org_1",
|
|
||||||
userId: "user_1",
|
|
||||||
userType: "user",
|
|
||||||
status: "failure",
|
|
||||||
oldObject: expect.objectContaining({
|
|
||||||
id: surveyId,
|
|
||||||
workspaceId: workspaceId,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("queues an audit log with target, actor, organization, and old object", async () => {
|
|
||||||
await DELETE(createRequest(`http://localhost/api/v3/surveys/${surveyId}`, "req-audit"), {
|
|
||||||
params: Promise.resolve({ surveyId }),
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
expect(queueAuditEvent).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
action: "deleted",
|
|
||||||
targetType: "survey",
|
|
||||||
targetId: surveyId,
|
|
||||||
organizationId: "org_1",
|
|
||||||
userId: "user_1",
|
|
||||||
userType: "user",
|
|
||||||
status: "success",
|
|
||||||
oldObject: expect.objectContaining({
|
|
||||||
id: surveyId,
|
|
||||||
workspaceId: workspaceId,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import { z } from "zod";
|
|
||||||
import { logger } from "@formbricks/logger";
|
|
||||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
|
|
||||||
import { withV3ApiWrapper } from "@/app/api/v3/lib/api-wrapper";
|
|
||||||
import { requireV3WorkspaceAccess } from "@/app/api/v3/lib/auth";
|
|
||||||
import { problemForbidden, problemInternalError, successResponse } from "@/app/api/v3/lib/response";
|
|
||||||
import { getSurvey } from "@/lib/survey/service";
|
|
||||||
import { deleteSurvey } from "@/modules/survey/lib/surveys";
|
|
||||||
|
|
||||||
export const DELETE = withV3ApiWrapper({
|
|
||||||
auth: "both",
|
|
||||||
action: "deleted",
|
|
||||||
targetType: "survey",
|
|
||||||
schemas: {
|
|
||||||
params: z.object({
|
|
||||||
surveyId: z.cuid2(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
handler: async ({ parsedInput, authentication, requestId, instance, auditLog }) => {
|
|
||||||
const surveyId = parsedInput.params.surveyId;
|
|
||||||
const log = logger.withContext({ requestId, surveyId });
|
|
||||||
|
|
||||||
try {
|
|
||||||
const survey = await getSurvey(surveyId);
|
|
||||||
|
|
||||||
if (!survey) {
|
|
||||||
log.warn({ statusCode: 403 }, "Survey not found or not accessible");
|
|
||||||
return problemForbidden(requestId, "You are not authorized to access this resource", instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
const authResult = await requireV3WorkspaceAccess(
|
|
||||||
authentication,
|
|
||||||
survey.workspaceId,
|
|
||||||
"readWrite",
|
|
||||||
requestId,
|
|
||||||
instance
|
|
||||||
);
|
|
||||||
|
|
||||||
if (authResult instanceof Response) {
|
|
||||||
return authResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auditLog) {
|
|
||||||
auditLog.targetId = survey.id;
|
|
||||||
auditLog.organizationId = authResult.organizationId;
|
|
||||||
auditLog.oldObject = survey;
|
|
||||||
}
|
|
||||||
|
|
||||||
const deletedSurvey = await deleteSurvey(surveyId);
|
|
||||||
|
|
||||||
return successResponse(
|
|
||||||
{
|
|
||||||
id: deletedSurvey.id,
|
|
||||||
},
|
|
||||||
{ requestId }
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof ResourceNotFoundError) {
|
|
||||||
log.warn({ errorCode: error.name, statusCode: 403 }, "Survey not found or not accessible");
|
|
||||||
return problemForbidden(requestId, "You are not authorized to access this resource", instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error instanceof DatabaseError) {
|
|
||||||
log.error({ error, statusCode: 500 }, "Database error");
|
|
||||||
return problemInternalError(requestId, "An unexpected error occurred.", instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.error({ error, statusCode: 500 }, "V3 survey delete unexpected error");
|
|
||||||
return problemInternalError(requestId, "An unexpected error occurred.", instance);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -314,8 +314,8 @@ describe("GET /api/v3/surveys", () => {
|
|||||||
const res = await GET(req, {} as any);
|
const res = await GET(req, {} as any);
|
||||||
const body = await res.json();
|
const body = await res.json();
|
||||||
expect(body.data[0]).not.toHaveProperty("blocks");
|
expect(body.data[0]).not.toHaveProperty("blocks");
|
||||||
expect(body.data[0]).not.toHaveProperty("_count");
|
|
||||||
expect(body.data[0]).not.toHaveProperty("singleUse");
|
expect(body.data[0]).not.toHaveProperty("singleUse");
|
||||||
|
expect(body.data[0]).not.toHaveProperty("_count");
|
||||||
expect(body.data[0].id).toBe("s1");
|
expect(body.data[0].id).toBe("s1");
|
||||||
expect(body.data[0].workspaceId).toBe("ws_1");
|
expect(body.data[0].workspaceId).toBe("ws_1");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -93,17 +93,17 @@ describe("parseAndValidateJsonBody", () => {
|
|||||||
request,
|
request,
|
||||||
schema: z.object({
|
schema: z.object({
|
||||||
finished: z.boolean(),
|
finished: z.boolean(),
|
||||||
workspaceId: z.string(),
|
environmentId: z.string(),
|
||||||
}),
|
}),
|
||||||
buildInput: (jsonInput) => ({
|
buildInput: (jsonInput) => ({
|
||||||
...(jsonInput as Record<string, unknown>),
|
...(jsonInput as Record<string, unknown>),
|
||||||
workspaceId: "ws_123",
|
environmentId: "env_123",
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
data: {
|
data: {
|
||||||
workspaceId: "ws_123",
|
environmentId: "env_123",
|
||||||
finished: true,
|
finished: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -339,56 +339,6 @@ describe("API Response Utilities", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("conflictResponse", () => {
|
|
||||||
test("should return a conflict response", () => {
|
|
||||||
const message = "Resource already exists";
|
|
||||||
const details = { field: "singleUseId" };
|
|
||||||
const response = responses.conflictResponse(message, details);
|
|
||||||
|
|
||||||
expect(response.status).toBe(409);
|
|
||||||
|
|
||||||
return response.json().then((body) => {
|
|
||||||
expect(body).toEqual({
|
|
||||||
code: "conflict",
|
|
||||||
message,
|
|
||||||
details,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should handle undefined details", () => {
|
|
||||||
const message = "Resource already exists";
|
|
||||||
const response = responses.conflictResponse(message);
|
|
||||||
|
|
||||||
expect(response.status).toBe(409);
|
|
||||||
|
|
||||||
return response.json().then((body) => {
|
|
||||||
expect(body).toEqual({
|
|
||||||
code: "conflict",
|
|
||||||
message,
|
|
||||||
details: {},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should include CORS headers when cors is true", () => {
|
|
||||||
const message = "Resource already exists";
|
|
||||||
const response = responses.conflictResponse(message, undefined, true);
|
|
||||||
|
|
||||||
expect(response.headers.get("Access-Control-Allow-Origin")).toBe("*");
|
|
||||||
expect(response.headers.get("Access-Control-Allow-Methods")).toBe("GET, POST, PUT, DELETE, OPTIONS");
|
|
||||||
expect(response.headers.get("Access-Control-Allow-Headers")).toBe("Content-Type, Authorization");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should use custom cache control header when provided", () => {
|
|
||||||
const message = "Resource already exists";
|
|
||||||
const customCache = "no-cache";
|
|
||||||
const response = responses.conflictResponse(message, undefined, false, customCache);
|
|
||||||
|
|
||||||
expect(response.headers.get("Cache-Control")).toBe(customCache);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("tooManyRequestsResponse", () => {
|
describe("tooManyRequestsResponse", () => {
|
||||||
test("should return a too many requests response", () => {
|
test("should return a too many requests response", () => {
|
||||||
const message = "Rate limit exceeded";
|
const message = "Rate limit exceeded";
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ interface ApiErrorResponse {
|
|||||||
| "method_not_allowed"
|
| "method_not_allowed"
|
||||||
| "not_authenticated"
|
| "not_authenticated"
|
||||||
| "forbidden"
|
| "forbidden"
|
||||||
| "too_many_requests"
|
| "too_many_requests";
|
||||||
| "conflict";
|
|
||||||
message: string;
|
message: string;
|
||||||
details: {
|
details: {
|
||||||
[key: string]: string | string[] | number | number[] | boolean | boolean[];
|
[key: string]: string | string[] | number | number[] | boolean | boolean[];
|
||||||
@@ -237,30 +236,6 @@ const internalServerErrorResponse = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const conflictResponse = (
|
|
||||||
message: string,
|
|
||||||
details?: { [key: string]: string },
|
|
||||||
cors: boolean = false,
|
|
||||||
cache: string = "private, no-store"
|
|
||||||
) => {
|
|
||||||
const headers = {
|
|
||||||
...(cors && corsHeaders),
|
|
||||||
"Cache-Control": cache,
|
|
||||||
};
|
|
||||||
|
|
||||||
return Response.json(
|
|
||||||
{
|
|
||||||
code: "conflict",
|
|
||||||
message,
|
|
||||||
details: details || {},
|
|
||||||
} as ApiErrorResponse,
|
|
||||||
{
|
|
||||||
status: 409,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const tooManyRequestsResponse = (
|
const tooManyRequestsResponse = (
|
||||||
message: string,
|
message: string,
|
||||||
cors: boolean = false,
|
cors: boolean = false,
|
||||||
@@ -295,5 +270,4 @@ export const responses = {
|
|||||||
successResponse,
|
successResponse,
|
||||||
tooManyRequestsResponse,
|
tooManyRequestsResponse,
|
||||||
forbiddenResponse,
|
forbiddenResponse,
|
||||||
conflictResponse,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,16 +3,9 @@ import { NextRequest } from "next/server";
|
|||||||
import { Mock, beforeEach, describe, expect, test, vi } from "vitest";
|
import { Mock, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
import { logger } from "@formbricks/logger";
|
import { logger } from "@formbricks/logger";
|
||||||
import { TAuthenticationApiKey } from "@formbricks/types/auth";
|
import { TAuthenticationApiKey } from "@formbricks/types/auth";
|
||||||
import type { AuthenticationMethod } from "@/app/middleware/endpoint-validator";
|
import { AuthenticationMethod } from "@/app/middleware/endpoint-validator";
|
||||||
import { responses } from "./response";
|
import { responses } from "./response";
|
||||||
|
|
||||||
const AuthMethod = {
|
|
||||||
ApiKey: "apiKey" as AuthenticationMethod,
|
|
||||||
Session: "session" as AuthenticationMethod,
|
|
||||||
Both: "both" as AuthenticationMethod,
|
|
||||||
None: "none" as AuthenticationMethod,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
vi.mock("@/modules/ee/audit-logs/lib/handler", () => ({
|
vi.mock("@/modules/ee/audit-logs/lib/handler", () => ({
|
||||||
__esModule: true,
|
__esModule: true,
|
||||||
queueAuditEvent: vi.fn(),
|
queueAuditEvent: vi.fn(),
|
||||||
@@ -129,7 +122,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.ApiKey,
|
authenticationMethod: AuthenticationMethod.ApiKey,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
|
|
||||||
@@ -205,7 +198,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.ApiKey,
|
authenticationMethod: AuthenticationMethod.ApiKey,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
|
|
||||||
@@ -251,7 +244,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.ApiKey,
|
authenticationMethod: AuthenticationMethod.ApiKey,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
|
|
||||||
@@ -325,7 +318,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.ApiKey,
|
authenticationMethod: AuthenticationMethod.ApiKey,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
|
|
||||||
@@ -377,7 +370,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.ApiKey,
|
authenticationMethod: AuthenticationMethod.ApiKey,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
|
|
||||||
@@ -432,7 +425,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.ApiKey,
|
authenticationMethod: AuthenticationMethod.ApiKey,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
|
|
||||||
@@ -456,7 +449,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: true, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: true, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: false,
|
isManagementApi: false,
|
||||||
authenticationMethod: AuthMethod.None,
|
authenticationMethod: AuthenticationMethod.None,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
vi.mocked(authenticateRequest).mockResolvedValue(null);
|
vi.mocked(authenticateRequest).mockResolvedValue(null);
|
||||||
@@ -480,90 +473,6 @@ describe("withV1ApiWrapper", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("skips app rate limiting for Envoy-covered client routes", async () => {
|
|
||||||
const { isClientSideApiRoute, isManagementApiRoute, isIntegrationRoute } =
|
|
||||||
await import("@/app/middleware/endpoint-validator");
|
|
||||||
const { authenticateRequest } = await import("@/app/api/v1/auth");
|
|
||||||
const { applyIPRateLimit } = await import("@/modules/core/rate-limit/helpers");
|
|
||||||
|
|
||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: true, isRateLimited: true });
|
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
|
||||||
isManagementApi: false,
|
|
||||||
authenticationMethod: AuthMethod.None,
|
|
||||||
});
|
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
|
||||||
vi.mocked(authenticateRequest).mockResolvedValue(null);
|
|
||||||
vi.mocked(applyIPRateLimit).mockResolvedValue({ allowed: true });
|
|
||||||
|
|
||||||
const handler = vi.fn().mockResolvedValue({
|
|
||||||
response: responses.successResponse({ data: "test" }),
|
|
||||||
});
|
|
||||||
|
|
||||||
const req = createMockRequest({ method: "POST", url: "/api/v1/client/env_123/storage" });
|
|
||||||
const { withV1ApiWrapper } = await import("./with-api-logging");
|
|
||||||
const wrapped = withV1ApiWrapper({ handler });
|
|
||||||
const res = await wrapped(req, undefined);
|
|
||||||
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
expect(applyIPRateLimit).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("keeps app rate limiting for uncovered client routes", async () => {
|
|
||||||
const { isClientSideApiRoute, isManagementApiRoute, isIntegrationRoute } =
|
|
||||||
await import("@/app/middleware/endpoint-validator");
|
|
||||||
const { authenticateRequest } = await import("@/app/api/v1/auth");
|
|
||||||
const { applyIPRateLimit } = await import("@/modules/core/rate-limit/helpers");
|
|
||||||
|
|
||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: true, isRateLimited: true });
|
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
|
||||||
isManagementApi: false,
|
|
||||||
authenticationMethod: AuthMethod.None,
|
|
||||||
});
|
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
|
||||||
vi.mocked(authenticateRequest).mockResolvedValue(null);
|
|
||||||
vi.mocked(applyIPRateLimit).mockResolvedValue({ allowed: true });
|
|
||||||
|
|
||||||
const handler = vi.fn().mockResolvedValue({
|
|
||||||
response: responses.successResponse({ data: "test" }),
|
|
||||||
});
|
|
||||||
|
|
||||||
const req = createMockRequest({ method: "GET", url: "/api/v2/client/env_123/environment" });
|
|
||||||
const { withV1ApiWrapper } = await import("./with-api-logging");
|
|
||||||
const wrapped = withV1ApiWrapper({ handler });
|
|
||||||
const res = await wrapped(req, undefined);
|
|
||||||
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
expect(applyIPRateLimit).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("keeps app rate limiting for uncovered verbs on otherwise covered client paths", async () => {
|
|
||||||
const { isClientSideApiRoute, isManagementApiRoute, isIntegrationRoute } =
|
|
||||||
await import("@/app/middleware/endpoint-validator");
|
|
||||||
const { authenticateRequest } = await import("@/app/api/v1/auth");
|
|
||||||
const { applyIPRateLimit } = await import("@/modules/core/rate-limit/helpers");
|
|
||||||
|
|
||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: true, isRateLimited: true });
|
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
|
||||||
isManagementApi: false,
|
|
||||||
authenticationMethod: AuthMethod.None,
|
|
||||||
});
|
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
|
||||||
vi.mocked(authenticateRequest).mockResolvedValue(null);
|
|
||||||
vi.mocked(applyIPRateLimit).mockResolvedValue({ allowed: true });
|
|
||||||
|
|
||||||
const handler = vi.fn().mockResolvedValue({
|
|
||||||
response: responses.successResponse({ data: "test" }),
|
|
||||||
});
|
|
||||||
|
|
||||||
const req = createMockRequest({ method: "PATCH", url: "/api/v1/client/env_123/environment" });
|
|
||||||
const { withV1ApiWrapper } = await import("./with-api-logging");
|
|
||||||
const wrapped = withV1ApiWrapper({ handler });
|
|
||||||
const res = await wrapped(req, undefined);
|
|
||||||
|
|
||||||
expect(res.status).toBe(200);
|
|
||||||
expect(applyIPRateLimit).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns authentication error for non-client routes without auth", async () => {
|
test("returns authentication error for non-client routes without auth", async () => {
|
||||||
const { isClientSideApiRoute, isManagementApiRoute, isIntegrationRoute } =
|
const { isClientSideApiRoute, isManagementApiRoute, isIntegrationRoute } =
|
||||||
await import("@/app/middleware/endpoint-validator");
|
await import("@/app/middleware/endpoint-validator");
|
||||||
@@ -572,7 +481,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.ApiKey,
|
authenticationMethod: AuthenticationMethod.ApiKey,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
vi.mocked(authenticateRequest).mockResolvedValue(null);
|
vi.mocked(authenticateRequest).mockResolvedValue(null);
|
||||||
@@ -595,7 +504,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.Session,
|
authenticationMethod: AuthenticationMethod.Session,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
vi.mocked(getServerSession).mockResolvedValue(null);
|
vi.mocked(getServerSession).mockResolvedValue(null);
|
||||||
@@ -619,36 +528,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
expect(mockContextualLoggerError).toHaveBeenCalled();
|
expect(mockContextualLoggerError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("keeps app rate limiting for uncovered session-authenticated management routes", async () => {
|
test("handles rate limiting errors", async () => {
|
||||||
const { applyRateLimit } = await import("@/modules/core/rate-limit/helpers");
|
|
||||||
const { isClientSideApiRoute, isManagementApiRoute, isIntegrationRoute } =
|
|
||||||
await import("@/app/middleware/endpoint-validator");
|
|
||||||
const { getServerSession } = await import("next-auth");
|
|
||||||
|
|
||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
|
||||||
isManagementApi: true,
|
|
||||||
authenticationMethod: AuthMethod.Both,
|
|
||||||
});
|
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
|
||||||
vi.mocked(getServerSession).mockResolvedValue({ user: { id: "user-1" } } as any);
|
|
||||||
const rateLimitError = new Error("Rate limit exceeded");
|
|
||||||
rateLimitError.message = "Rate limit exceeded";
|
|
||||||
vi.mocked(applyRateLimit).mockRejectedValue(rateLimitError);
|
|
||||||
|
|
||||||
const handler = vi.fn();
|
|
||||||
const req = createMockRequest({ method: "POST", url: "https://api.test/api/v1/management/storage" });
|
|
||||||
const { withV1ApiWrapper } = await import("./with-api-logging");
|
|
||||||
const customRateLimitConfig = { interval: 60, allowedPerInterval: 5, namespace: "storage:upload" };
|
|
||||||
const wrapped = withV1ApiWrapper({ handler, customRateLimitConfig });
|
|
||||||
const res = await wrapped(req, undefined);
|
|
||||||
|
|
||||||
expect(res.status).toBe(429);
|
|
||||||
expect(handler).not.toHaveBeenCalled();
|
|
||||||
expect(applyRateLimit).toHaveBeenCalledWith(customRateLimitConfig, "user-1");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("skips app rate limiting for Envoy-covered API-key management routes", async () => {
|
|
||||||
const { applyRateLimit } = await import("@/modules/core/rate-limit/helpers");
|
const { applyRateLimit } = await import("@/modules/core/rate-limit/helpers");
|
||||||
const { isClientSideApiRoute, isManagementApiRoute, isIntegrationRoute } =
|
const { isClientSideApiRoute, isManagementApiRoute, isIntegrationRoute } =
|
||||||
await import("@/app/middleware/endpoint-validator");
|
await import("@/app/middleware/endpoint-validator");
|
||||||
@@ -658,22 +538,21 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.ApiKey,
|
authenticationMethod: AuthenticationMethod.ApiKey,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
vi.mocked(applyRateLimit).mockResolvedValue({ allowed: true });
|
const rateLimitError = new Error("Rate limit exceeded");
|
||||||
|
rateLimitError.message = "Rate limit exceeded";
|
||||||
const handler = vi.fn().mockResolvedValue({
|
vi.mocked(applyRateLimit).mockRejectedValue(rateLimitError);
|
||||||
response: responses.successResponse({ data: "test" }),
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const handler = vi.fn();
|
||||||
const req = createMockRequest({ url: V1_MANAGEMENT_SURVEYS_URL });
|
const req = createMockRequest({ url: V1_MANAGEMENT_SURVEYS_URL });
|
||||||
const { withV1ApiWrapper } = await import("./with-api-logging");
|
const { withV1ApiWrapper } = await import("./with-api-logging");
|
||||||
const wrapped = withV1ApiWrapper({ handler });
|
const wrapped = withV1ApiWrapper({ handler });
|
||||||
const res = await wrapped(req, undefined);
|
const res = await wrapped(req, undefined);
|
||||||
|
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(429);
|
||||||
expect(applyRateLimit).not.toHaveBeenCalled();
|
expect(handler).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("skips audit log creation when no action/targetType provided", async () => {
|
test("skips audit log creation when no action/targetType provided", async () => {
|
||||||
@@ -687,7 +566,7 @@ describe("withV1ApiWrapper", () => {
|
|||||||
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
vi.mocked(isClientSideApiRoute).mockReturnValue({ isClientSideApi: false, isRateLimited: true });
|
||||||
vi.mocked(isManagementApiRoute).mockReturnValue({
|
vi.mocked(isManagementApiRoute).mockReturnValue({
|
||||||
isManagementApi: true,
|
isManagementApi: true,
|
||||||
authenticationMethod: AuthMethod.ApiKey,
|
authenticationMethod: AuthenticationMethod.ApiKey,
|
||||||
});
|
});
|
||||||
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
vi.mocked(isIntegrationRoute).mockReturnValue(false);
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ import {
|
|||||||
} from "@/app/middleware/endpoint-validator";
|
} from "@/app/middleware/endpoint-validator";
|
||||||
import { AUDIT_LOG_ENABLED } from "@/lib/constants";
|
import { AUDIT_LOG_ENABLED } from "@/lib/constants";
|
||||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||||
import {
|
|
||||||
TEnvoyRateLimitAuthType,
|
|
||||||
isRouteRateLimitedByEnvoy,
|
|
||||||
} from "@/modules/core/rate-limit/envoy-rate-limit-coverage";
|
|
||||||
import { applyIPRateLimit, applyRateLimit } from "@/modules/core/rate-limit/helpers";
|
import { applyIPRateLimit, applyRateLimit } from "@/modules/core/rate-limit/helpers";
|
||||||
import { rateLimitConfigs } from "@/modules/core/rate-limit/rate-limit-configs";
|
import { rateLimitConfigs } from "@/modules/core/rate-limit/rate-limit-configs";
|
||||||
import { TRateLimitConfig } from "@/modules/core/rate-limit/types/rate-limit";
|
import { TRateLimitConfig } from "@/modules/core/rate-limit/types/rate-limit";
|
||||||
@@ -65,58 +61,29 @@ const applyClientRateLimit = async (customRateLimitConfig?: TRateLimitConfig): P
|
|||||||
await applyIPRateLimit(customRateLimitConfig ?? rateLimitConfigs.api.client);
|
await applyIPRateLimit(customRateLimitConfig ?? rateLimitConfigs.api.client);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEnvoyRateLimitAuthType = (
|
|
||||||
authentication: TApiV1Authentication
|
|
||||||
): TEnvoyRateLimitAuthType | "unknown" => {
|
|
||||||
if (!authentication) {
|
|
||||||
return "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("user" in authentication) {
|
|
||||||
return "session";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("apiKeyId" in authentication) {
|
|
||||||
return "apiKey";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unknown";
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle rate limiting based on authentication and API type
|
* Handle rate limiting based on authentication and API type
|
||||||
*/
|
*/
|
||||||
const handleRateLimiting = async (
|
const handleRateLimiting = async (
|
||||||
req: NextRequest,
|
|
||||||
authentication: TApiV1Authentication,
|
authentication: TApiV1Authentication,
|
||||||
routeType: ApiV1RouteTypeEnum,
|
routeType: ApiV1RouteTypeEnum,
|
||||||
customRateLimitConfig?: TRateLimitConfig
|
customRateLimitConfig?: TRateLimitConfig
|
||||||
): Promise<Response | null> => {
|
): Promise<Response | null> => {
|
||||||
const authType = getEnvoyRateLimitAuthType(authentication);
|
|
||||||
|
|
||||||
if (authType === "unknown") {
|
|
||||||
logger.error({ authentication }, "Unknown authentication type");
|
|
||||||
return responses.internalServerErrorResponse("Invalid authentication configuration");
|
|
||||||
}
|
|
||||||
|
|
||||||
const isEnvoyManagedRateLimit = isRouteRateLimitedByEnvoy({
|
|
||||||
pathname: req.nextUrl.pathname,
|
|
||||||
method: req.method,
|
|
||||||
authType,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (authentication && !isEnvoyManagedRateLimit) {
|
if (authentication) {
|
||||||
if ("user" in authentication) {
|
if ("user" in authentication) {
|
||||||
// Session-based authentication for integration routes
|
// Session-based authentication for integration routes
|
||||||
await applyRateLimit(customRateLimitConfig ?? rateLimitConfigs.api.v1, authentication.user.id);
|
await applyRateLimit(customRateLimitConfig ?? rateLimitConfigs.api.v1, authentication.user.id);
|
||||||
} else if ("apiKeyId" in authentication) {
|
} else if ("apiKeyId" in authentication) {
|
||||||
// API key authentication for general routes
|
// API key authentication for general routes
|
||||||
await applyRateLimit(customRateLimitConfig ?? rateLimitConfigs.api.v1, authentication.apiKeyId);
|
await applyRateLimit(customRateLimitConfig ?? rateLimitConfigs.api.v1, authentication.apiKeyId);
|
||||||
|
} else {
|
||||||
|
logger.error({ authentication }, "Unknown authentication type");
|
||||||
|
return responses.internalServerErrorResponse("Invalid authentication configuration");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (routeType === ApiV1RouteTypeEnum.Client && !isEnvoyManagedRateLimit) {
|
if (routeType === ApiV1RouteTypeEnum.Client) {
|
||||||
await applyClientRateLimit(customRateLimitConfig);
|
await applyClientRateLimit(customRateLimitConfig);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -319,12 +286,7 @@ export const withV1ApiWrapper = <TResult extends { response: Response; error?: u
|
|||||||
|
|
||||||
// === Rate Limiting ===
|
// === Rate Limiting ===
|
||||||
if (isRateLimited) {
|
if (isRateLimited) {
|
||||||
const rateLimitResponse = await handleRateLimiting(
|
const rateLimitResponse = await handleRateLimiting(authentication, routeType, customRateLimitConfig);
|
||||||
req,
|
|
||||||
authentication,
|
|
||||||
routeType,
|
|
||||||
customRateLimitConfig
|
|
||||||
);
|
|
||||||
if (rateLimitResponse) return rateLimitResponse;
|
if (rateLimitResponse) return rateLimitResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ import type { TFunction } from "i18next";
|
|||||||
import type { TSurveyBlock, TSurveyBlockLogic } from "@formbricks/types/surveys/blocks";
|
import type { TSurveyBlock, TSurveyBlockLogic } from "@formbricks/types/surveys/blocks";
|
||||||
import type {
|
import type {
|
||||||
TSurveyCTAElement,
|
TSurveyCTAElement,
|
||||||
TSurveyCesElement,
|
|
||||||
TSurveyConsentElement,
|
TSurveyConsentElement,
|
||||||
TSurveyCsatElement,
|
|
||||||
TSurveyElement,
|
TSurveyElement,
|
||||||
TSurveyMultipleChoiceElement,
|
TSurveyMultipleChoiceElement,
|
||||||
TSurveyNPSElement,
|
TSurveyNPSElement,
|
||||||
@@ -98,8 +96,7 @@ export const buildOpenTextElement = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildScaleElement = <T extends TSurveyRatingElement | TSurveyCsatElement | TSurveyCesElement>({
|
export const buildRatingElement = ({
|
||||||
type,
|
|
||||||
id,
|
id,
|
||||||
headline,
|
headline,
|
||||||
subheader,
|
subheader,
|
||||||
@@ -110,32 +107,6 @@ const buildScaleElement = <T extends TSurveyRatingElement | TSurveyCsatElement |
|
|||||||
required,
|
required,
|
||||||
isColorCodingEnabled = false,
|
isColorCodingEnabled = false,
|
||||||
}: {
|
}: {
|
||||||
type: T["type"];
|
|
||||||
id?: string;
|
|
||||||
headline: string;
|
|
||||||
scale: T["scale"];
|
|
||||||
range: T["range"];
|
|
||||||
lowerLabel?: string;
|
|
||||||
upperLabel?: string;
|
|
||||||
subheader?: string;
|
|
||||||
required?: boolean;
|
|
||||||
isColorCodingEnabled?: boolean;
|
|
||||||
}): T => {
|
|
||||||
return {
|
|
||||||
id: id ?? createId(),
|
|
||||||
type,
|
|
||||||
subheader: subheader ? createI18nString(subheader, []) : undefined,
|
|
||||||
headline: createI18nString(headline, []),
|
|
||||||
scale,
|
|
||||||
range,
|
|
||||||
required: required ?? false,
|
|
||||||
isColorCodingEnabled,
|
|
||||||
lowerLabel: lowerLabel ? createI18nString(lowerLabel, []) : undefined,
|
|
||||||
upperLabel: upperLabel ? createI18nString(upperLabel, []) : undefined,
|
|
||||||
} as T;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const buildRatingElement = (params: {
|
|
||||||
id?: string;
|
id?: string;
|
||||||
headline: string;
|
headline: string;
|
||||||
scale: TSurveyRatingElement["scale"];
|
scale: TSurveyRatingElement["scale"];
|
||||||
@@ -145,8 +116,20 @@ export const buildRatingElement = (params: {
|
|||||||
subheader?: string;
|
subheader?: string;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
isColorCodingEnabled?: boolean;
|
isColorCodingEnabled?: boolean;
|
||||||
}): TSurveyRatingElement =>
|
}): TSurveyRatingElement => {
|
||||||
buildScaleElement<TSurveyRatingElement>({ ...params, type: TSurveyElementTypeEnum.Rating });
|
return {
|
||||||
|
id: id ?? createId(),
|
||||||
|
type: TSurveyElementTypeEnum.Rating,
|
||||||
|
subheader: subheader ? createI18nString(subheader, []) : undefined,
|
||||||
|
headline: createI18nString(headline, []),
|
||||||
|
scale,
|
||||||
|
range,
|
||||||
|
required: required ?? false,
|
||||||
|
isColorCodingEnabled,
|
||||||
|
lowerLabel: lowerLabel ? createI18nString(lowerLabel, []) : undefined,
|
||||||
|
upperLabel: upperLabel ? createI18nString(upperLabel, []) : undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const buildConsentElement = ({
|
export const buildConsentElement = ({
|
||||||
id,
|
id,
|
||||||
@@ -229,38 +212,6 @@ export const buildNPSElement = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buildCsatElement = ({
|
|
||||||
scale = "smiley",
|
|
||||||
...params
|
|
||||||
}: {
|
|
||||||
id?: string;
|
|
||||||
headline: string;
|
|
||||||
scale?: TSurveyCsatElement["scale"];
|
|
||||||
lowerLabel?: string;
|
|
||||||
upperLabel?: string;
|
|
||||||
subheader?: string;
|
|
||||||
required?: boolean;
|
|
||||||
isColorCodingEnabled?: boolean;
|
|
||||||
}): TSurveyCsatElement =>
|
|
||||||
buildScaleElement<TSurveyCsatElement>({ ...params, scale, range: 5, type: TSurveyElementTypeEnum.CSAT });
|
|
||||||
|
|
||||||
export const buildCesElement = ({
|
|
||||||
scale = "number",
|
|
||||||
range = 5,
|
|
||||||
...params
|
|
||||||
}: {
|
|
||||||
id?: string;
|
|
||||||
headline: string;
|
|
||||||
scale?: TSurveyCesElement["scale"];
|
|
||||||
range?: TSurveyCesElement["range"];
|
|
||||||
lowerLabel?: string;
|
|
||||||
upperLabel?: string;
|
|
||||||
subheader?: string;
|
|
||||||
required?: boolean;
|
|
||||||
isColorCodingEnabled?: boolean;
|
|
||||||
}): TSurveyCesElement =>
|
|
||||||
buildScaleElement<TSurveyCesElement>({ ...params, scale, range, type: TSurveyElementTypeEnum.CES });
|
|
||||||
|
|
||||||
// Helper function to create block-level jump logic based on operator
|
// Helper function to create block-level jump logic based on operator
|
||||||
export const createBlockJumpLogic = (
|
export const createBlockJumpLogic = (
|
||||||
sourceElementId: string,
|
sourceElementId: string,
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ const conditionOptions: Record<string, string[]> = {
|
|||||||
multipleChoiceMulti: ["Includes all", "Includes either"],
|
multipleChoiceMulti: ["Includes all", "Includes either"],
|
||||||
nps: ["Is equal to", "Is less than", "Is more than", "Submitted", "Skipped", "Includes either"],
|
nps: ["Is equal to", "Is less than", "Is more than", "Submitted", "Skipped", "Includes either"],
|
||||||
rating: ["Is equal to", "Is less than", "Is more than", "Submitted", "Skipped"],
|
rating: ["Is equal to", "Is less than", "Is more than", "Submitted", "Skipped"],
|
||||||
csat: ["Is equal to", "Is less than", "Is more than", "Submitted", "Skipped"],
|
|
||||||
ces: ["Is equal to", "Is less than", "Is more than", "Submitted", "Skipped"],
|
|
||||||
cta: ["is"],
|
cta: ["is"],
|
||||||
tags: ["is"],
|
tags: ["is"],
|
||||||
languages: ["Equals", "Not equals"],
|
languages: ["Equals", "Not equals"],
|
||||||
@@ -47,8 +45,6 @@ const filterOptions: Record<string, string[]> = {
|
|||||||
openText: ["Filled out", "Skipped"],
|
openText: ["Filled out", "Skipped"],
|
||||||
rating: ["1", "2", "3", "4", "5"],
|
rating: ["1", "2", "3", "4", "5"],
|
||||||
nps: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
|
nps: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
|
||||||
csat: ["1", "2", "3", "4", "5"],
|
|
||||||
ces: ["1", "2", "3", "4", "5", "6", "7"],
|
|
||||||
cta: ["Clicked", "Dismissed"],
|
cta: ["Clicked", "Dismissed"],
|
||||||
tags: ["Applied", "Not applied"],
|
tags: ["Applied", "Not applied"],
|
||||||
consent: ["Accepted", "Dismissed"],
|
consent: ["Accepted", "Dismissed"],
|
||||||
@@ -440,8 +436,6 @@ const processElementFilters = (
|
|||||||
break;
|
break;
|
||||||
case TSurveyElementTypeEnum.NPS:
|
case TSurveyElementTypeEnum.NPS:
|
||||||
case TSurveyElementTypeEnum.Rating:
|
case TSurveyElementTypeEnum.Rating:
|
||||||
case TSurveyElementTypeEnum.CSAT:
|
|
||||||
case TSurveyElementTypeEnum.CES:
|
|
||||||
processNPSRatingFilter(filterType, elementId, filters);
|
processNPSRatingFilter(filterType, elementId, filters);
|
||||||
break;
|
break;
|
||||||
case TSurveyElementTypeEnum.CTA:
|
case TSurveyElementTypeEnum.CTA:
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ import type { TTemplate } from "@formbricks/types/templates";
|
|||||||
import {
|
import {
|
||||||
buildBlock,
|
buildBlock,
|
||||||
buildCTAElement,
|
buildCTAElement,
|
||||||
buildCesElement,
|
|
||||||
buildConsentElement,
|
buildConsentElement,
|
||||||
buildCsatElement,
|
|
||||||
buildMultipleChoiceElement,
|
buildMultipleChoiceElement,
|
||||||
buildNPSElement,
|
buildNPSElement,
|
||||||
buildOpenTextElement,
|
buildOpenTextElement,
|
||||||
@@ -973,13 +971,13 @@ const improveTrialConversion = (t: TFunction): TTemplate => {
|
|||||||
elements: [
|
elements: [
|
||||||
buildOpenTextElement({
|
buildOpenTextElement({
|
||||||
id: reusableElementIds[2],
|
id: reusableElementIds[2],
|
||||||
headline: t("templates.improve_trial_conversion_question_3_headline"),
|
headline: t("templates.improve_trial_conversion_question_2_headline"),
|
||||||
required: true,
|
required: true,
|
||||||
inputType: "text",
|
inputType: "text",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
logic: [createBlockJumpLogic(reusableElementIds[2], block6Id, "isSubmitted")],
|
logic: [createBlockJumpLogic(reusableElementIds[2], block6Id, "isSubmitted")],
|
||||||
buttonLabel: t("templates.improve_trial_conversion_question_3_button_label"),
|
buttonLabel: t("templates.improve_trial_conversion_question_2_button_label"),
|
||||||
t,
|
t,
|
||||||
}),
|
}),
|
||||||
buildBlock({
|
buildBlock({
|
||||||
@@ -1321,7 +1319,8 @@ const employeeSatisfaction = (t: TFunction): TTemplate => {
|
|||||||
buildBlock({
|
buildBlock({
|
||||||
name: t("templates.block_1"),
|
name: t("templates.block_1"),
|
||||||
elements: [
|
elements: [
|
||||||
buildCsatElement({
|
buildRatingElement({
|
||||||
|
range: 5,
|
||||||
scale: "star",
|
scale: "star",
|
||||||
headline: t("templates.employee_satisfaction_question_1_headline"),
|
headline: t("templates.employee_satisfaction_question_1_headline"),
|
||||||
required: true,
|
required: true,
|
||||||
@@ -1648,14 +1647,14 @@ const identifyCustomerGoals = (t: TFunction): TTemplate => {
|
|||||||
elements: [
|
elements: [
|
||||||
buildMultipleChoiceElement({
|
buildMultipleChoiceElement({
|
||||||
type: TSurveyElementTypeEnum.MultipleChoiceSingle,
|
type: TSurveyElementTypeEnum.MultipleChoiceSingle,
|
||||||
headline: t("templates.identify_customer_goals_question_1_headline"),
|
headline: "What's your primary goal for using $[workspaceName]?",
|
||||||
required: true,
|
required: true,
|
||||||
shuffleOption: "none",
|
shuffleOption: "none",
|
||||||
choices: [
|
choices: [
|
||||||
t("templates.identify_customer_goals_question_1_choice_1"),
|
"Understand my user base deeply",
|
||||||
t("templates.identify_customer_goals_question_1_choice_2"),
|
"Identify upselling opportunities",
|
||||||
t("templates.identify_customer_goals_question_1_choice_3"),
|
"Build the best possible product",
|
||||||
t("templates.identify_customer_goals_question_1_choice_4"),
|
"Rule the world to make everyone breakfast brussels sprouts.",
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -2724,7 +2723,7 @@ const customerEffortScore = (t: TFunction): TTemplate => {
|
|||||||
buildBlock({
|
buildBlock({
|
||||||
name: t("templates.block_1"),
|
name: t("templates.block_1"),
|
||||||
elements: [
|
elements: [
|
||||||
buildCesElement({
|
buildRatingElement({
|
||||||
range: 5,
|
range: 5,
|
||||||
scale: "number",
|
scale: "number",
|
||||||
headline: t("templates.customer_effort_score_question_1_headline"),
|
headline: t("templates.customer_effort_score_question_1_headline"),
|
||||||
@@ -3829,8 +3828,9 @@ const improveNewsletterContent = (t: TFunction): TTemplate => {
|
|||||||
buildBlock({
|
buildBlock({
|
||||||
name: t("templates.block_1"),
|
name: t("templates.block_1"),
|
||||||
elements: [
|
elements: [
|
||||||
buildCsatElement({
|
buildRatingElement({
|
||||||
id: reusableElementIds[0],
|
id: reusableElementIds[0],
|
||||||
|
range: 5,
|
||||||
scale: "smiley",
|
scale: "smiley",
|
||||||
headline: t("templates.improve_newsletter_content_question_1_headline"),
|
headline: t("templates.improve_newsletter_content_question_1_headline"),
|
||||||
required: true,
|
required: true,
|
||||||
@@ -4409,7 +4409,8 @@ const longTermRetentionCheckIn = (t: TFunction): TTemplate => {
|
|||||||
buildBlock({
|
buildBlock({
|
||||||
name: t("templates.block_9"),
|
name: t("templates.block_9"),
|
||||||
elements: [
|
elements: [
|
||||||
buildCsatElement({
|
buildRatingElement({
|
||||||
|
range: 5,
|
||||||
scale: "smiley",
|
scale: "smiley",
|
||||||
headline: t("templates.long_term_retention_check_in_question_9_headline"),
|
headline: t("templates.long_term_retention_check_in_question_9_headline"),
|
||||||
required: true,
|
required: true,
|
||||||
@@ -4824,8 +4825,6 @@ export const previewSurvey = (workspaceName: string, t: TFunction): TSurvey => {
|
|||||||
workspaceId: "cmnh38nzx00003b6r3svd9pv2",
|
workspaceId: "cmnh38nzx00003b6r3svd9pv2",
|
||||||
createdBy: "cltwumfbz0000echxysz6ptvq",
|
createdBy: "cltwumfbz0000echxysz6ptvq",
|
||||||
status: "inProgress" as const,
|
status: "inProgress" as const,
|
||||||
publishOn: null,
|
|
||||||
closeOn: null,
|
|
||||||
welcomeCard: {
|
welcomeCard: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
headline: createI18nString(t("templates.preview_survey_welcome_card_headline"), []),
|
headline: createI18nString(t("templates.preview_survey_welcome_card_headline"), []),
|
||||||
|
|||||||
@@ -121,10 +121,13 @@ export const DELETE = async (
|
|||||||
: responses.notAuthenticatedResponse();
|
: responses.notAuthenticatedResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rate limiting for apiKey DELETE is enforced by Envoy in v5 — see envoy-rate-limit-coverage.ts
|
if (authResult.ok) {
|
||||||
if (authResult.ok && authResult.data.authType !== "apiKey") {
|
|
||||||
try {
|
try {
|
||||||
await applyRateLimit(rateLimitConfigs.storage.delete, authResult.data.userId);
|
if (authResult.data.authType === "apiKey") {
|
||||||
|
await applyRateLimit(rateLimitConfigs.storage.delete, authResult.data.apiKeyId);
|
||||||
|
} else {
|
||||||
|
await applyRateLimit(rateLimitConfigs.storage.delete, authResult.data.userId);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return responses.tooManyRequestsResponse(
|
return responses.tooManyRequestsResponse(
|
||||||
error instanceof Error ? error.message : "Unknown error occurred"
|
error instanceof Error ? error.message : "Unknown error occurred"
|
||||||
@@ -139,20 +142,20 @@ export const DELETE = async (
|
|||||||
idParam
|
idParam
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!deleteResult.ok) {
|
const isSuccess = deleteResult.ok;
|
||||||
const { error } = deleteResult;
|
|
||||||
|
|
||||||
logger.error({ error }, "Error deleting file");
|
if (!isSuccess) {
|
||||||
|
logger.error({ error: deleteResult.error }, "Error deleting file");
|
||||||
|
|
||||||
await logFileDeletion({
|
await logFileDeletion({
|
||||||
failureReason: error.code,
|
failureReason: deleteResult.error.code,
|
||||||
accessType,
|
accessType,
|
||||||
userId: session?.user?.id,
|
userId: session?.user?.id,
|
||||||
workspaceId: resolved.workspaceId,
|
workspaceId: resolved.workspaceId,
|
||||||
apiUrl: request.url,
|
apiUrl: request.url,
|
||||||
});
|
});
|
||||||
|
|
||||||
const errorResponse = getErrorResponseFromStorageError(error, { fileName });
|
const errorResponse = getErrorResponseFromStorageError(deleteResult.error, { fileName });
|
||||||
return errorResponse;
|
return errorResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
"ro-RO",
|
"ro-RO",
|
||||||
"ru-RU",
|
"ru-RU",
|
||||||
"sv-SE",
|
"sv-SE",
|
||||||
"tr-TR",
|
|
||||||
"zh-Hans-CN",
|
"zh-Hans-CN",
|
||||||
"zh-Hant-TW"
|
"zh-Hant-TW"
|
||||||
]
|
]
|
||||||
|
|||||||
+34
-251
@@ -98,8 +98,6 @@ checksums:
|
|||||||
common/activity: 1948763de8e531483a798b68195e297e
|
common/activity: 1948763de8e531483a798b68195e297e
|
||||||
common/add: 87c4a663507f2bcbbf79934af8164e13
|
common/add: 87c4a663507f2bcbbf79934af8164e13
|
||||||
common/add_action: 66fefc4dd6a7b939c2224272cf0d2669
|
common/add_action: 66fefc4dd6a7b939c2224272cf0d2669
|
||||||
common/add_charts: c377a42e165e8ab67bfbb8ad72026dd8
|
|
||||||
common/add_existing_chart_description: b1292a1d6df2e03ad7b399689312c37f
|
|
||||||
common/add_filter: ed5d8e9bfcb05cd1e10e4c403befbae6
|
common/add_filter: ed5d8e9bfcb05cd1e10e4c403befbae6
|
||||||
common/add_logo: c8665aa9afd0d5a13528bdc96daefa53
|
common/add_logo: c8665aa9afd0d5a13528bdc96daefa53
|
||||||
common/add_member: 11979625770516ca287e929381778e02
|
common/add_member: 11979625770516ca287e929381778e02
|
||||||
@@ -111,7 +109,6 @@ checksums:
|
|||||||
common/allow: 3e39cc5940255e6bff0fea95c817dd43
|
common/allow: 3e39cc5940255e6bff0fea95c817dd43
|
||||||
common/allow_users_to_exit_by_clicking_outside_the_survey: 1c09db6e85214f1b1c3d4774c4c5cd56
|
common/allow_users_to_exit_by_clicking_outside_the_survey: 1c09db6e85214f1b1c3d4774c4c5cd56
|
||||||
common/an_unknown_error_occurred_while_deleting_table_items: 06be3fd128aeb51eed4fba9a079ecee2
|
common/an_unknown_error_occurred_while_deleting_table_items: 06be3fd128aeb51eed4fba9a079ecee2
|
||||||
common/analysis: 409bac6215382c47e59f5039cc4cdcdd
|
|
||||||
common/and: dc75b95c804b16dc617a5f16f7393bca
|
common/and: dc75b95c804b16dc617a5f16f7393bca
|
||||||
common/anonymous: 77b5222e710cc1dae073dae32309f8ed
|
common/anonymous: 77b5222e710cc1dae073dae32309f8ed
|
||||||
common/api_keys: f961b547cd312cc8b9b79f0c9e0b2cc3
|
common/api_keys: f961b547cd312cc8b9b79f0c9e0b2cc3
|
||||||
@@ -130,9 +127,6 @@ checksums:
|
|||||||
common/centered_modal: 982ff411cb7e91e30300c2ed56b7e507
|
common/centered_modal: 982ff411cb7e91e30300c2ed56b7e507
|
||||||
common/change_organization: 3b2c873962509445ff2cb8cde5ad913b
|
common/change_organization: 3b2c873962509445ff2cb8cde5ad913b
|
||||||
common/change_workspace: 489cbcf7eef9b9b960e426fbf4da318f
|
common/change_workspace: 489cbcf7eef9b9b960e426fbf4da318f
|
||||||
common/chart: 6f4d9c56e45ceb8fc22d2f74454cd813
|
|
||||||
common/charts: 1da4564d89264c89de4ed28d7451b43e
|
|
||||||
common/choice_n: ee41eb382bae7289a221d959f3046965
|
|
||||||
common/choices: 8a7a77a71ec6eebc363c5dc0f8490a4d
|
common/choices: 8a7a77a71ec6eebc363c5dc0f8490a4d
|
||||||
common/choose_organization: a8f5db68012323bfbb1a0ad0fb194603
|
common/choose_organization: a8f5db68012323bfbb1a0ad0fb194603
|
||||||
common/choose_workspace: f9ed22d76c69cc75aa56cf3da3fa6320
|
common/choose_workspace: f9ed22d76c69cc75aa56cf3da3fa6320
|
||||||
@@ -145,9 +139,8 @@ checksums:
|
|||||||
common/close: 2c2e22f8424a1031de89063bd0022e16
|
common/close: 2c2e22f8424a1031de89063bd0022e16
|
||||||
common/code: 343bc5386149b97cece2b093c39034b2
|
common/code: 343bc5386149b97cece2b093c39034b2
|
||||||
common/collapse_rows: 24988527f9180f37aa55d2aa183ccb21
|
common/collapse_rows: 24988527f9180f37aa55d2aa183ccb21
|
||||||
common/column_n: 550955aee6a92d8ccc96989300add693
|
|
||||||
common/completed: 0e4bbce9985f25eb673d9a054c8d5334
|
common/completed: 0e4bbce9985f25eb673d9a054c8d5334
|
||||||
common/configuration: e3ab18ebb36c218cd4897c620f5809ac
|
common/configuration: 923ec0502721489202f6222dd4107163
|
||||||
common/confirm: 90930b51154032f119fa75c1bd422d8b
|
common/confirm: 90930b51154032f119fa75c1bd422d8b
|
||||||
common/connect: 8778ee245078a8be4a2ce855c8c56edc
|
common/connect: 8778ee245078a8be4a2ce855c8c56edc
|
||||||
common/connect_formbricks: a9dd747575e7e035da69251366df6f95
|
common/connect_formbricks: a9dd747575e7e035da69251366df6f95
|
||||||
@@ -176,8 +169,6 @@ checksums:
|
|||||||
common/created_by: 6775c2fa7d495fea48f1ad816daea93b
|
common/created_by: 6775c2fa7d495fea48f1ad816daea93b
|
||||||
common/customer_success: 2b0c99a5f57e1d16cf0a998f9bb116c4
|
common/customer_success: 2b0c99a5f57e1d16cf0a998f9bb116c4
|
||||||
common/dark_overlay: 173e84b526414dbc70dbf9737e443b60
|
common/dark_overlay: 173e84b526414dbc70dbf9737e443b60
|
||||||
common/dashboard: c9380ea68c8c76ea451bd9613329a07c
|
|
||||||
common/dashboards: 4bc47e48559a6b688684dcb7ac4babc9
|
|
||||||
common/date: 56f41c5d30a76295bb087b20b7bee4c3
|
common/date: 56f41c5d30a76295bb087b20b7bee4c3
|
||||||
common/days: c95fe8aedde21a0b5653dbd0b3c58b48
|
common/days: c95fe8aedde21a0b5653dbd0b3c58b48
|
||||||
common/default: d9c6dc5c412fe94143dfd1d332ec81d4
|
common/default: d9c6dc5c412fe94143dfd1d332ec81d4
|
||||||
@@ -205,6 +196,7 @@ checksums:
|
|||||||
common/ending_card: 16d30d3a36472159da8c2dbd374dfe22
|
common/ending_card: 16d30d3a36472159da8c2dbd374dfe22
|
||||||
common/enter_url: 468c2276d0f2cb971ff5a47a20fa4b97
|
common/enter_url: 468c2276d0f2cb971ff5a47a20fa4b97
|
||||||
common/enterprise_license: e81bf506f47968870c7bd07245648a0d
|
common/enterprise_license: e81bf506f47968870c7bd07245648a0d
|
||||||
|
common/environment: 0844e8dc1485339c8de066dc0a9bb6a1
|
||||||
common/error: 3c95bcb32c2104b99a46f5b3dd015248
|
common/error: 3c95bcb32c2104b99a46f5b3dd015248
|
||||||
common/error_component_description: fa9eee04f864c3fe6e6681f716caa015
|
common/error_component_description: fa9eee04f864c3fe6e6681f716caa015
|
||||||
common/error_component_title: ae68fa341a143aaa13a5ea30dd57a63e
|
common/error_component_title: ae68fa341a143aaa13a5ea30dd57a63e
|
||||||
@@ -216,7 +208,6 @@ checksums:
|
|||||||
common/failed_to_load_organizations: 512808a2b674c7c28bca73f8f91fd87e
|
common/failed_to_load_organizations: 512808a2b674c7c28bca73f8f91fd87e
|
||||||
common/failed_to_load_workspaces: 6ee3448097394517dc605074cd4e6ea4
|
common/failed_to_load_workspaces: 6ee3448097394517dc605074cd4e6ea4
|
||||||
common/failed_to_parse_csv: 7a3d675ecbb3d15884faf1006a5752d6
|
common/failed_to_parse_csv: 7a3d675ecbb3d15884faf1006a5752d6
|
||||||
common/field_placeholder: ec26d96643d86da164162204ec6c650f
|
|
||||||
common/filter: 626325a05e4c8800f7ede7012b0cadaf
|
common/filter: 626325a05e4c8800f7ede7012b0cadaf
|
||||||
common/finish: ffa7a10f71182b48fefed7135bee24fa
|
common/finish: ffa7a10f71182b48fefed7135bee24fa
|
||||||
common/first_name: cf040a5d6a9fd696be400380cc99f54b
|
common/first_name: cf040a5d6a9fd696be400380cc99f54b
|
||||||
@@ -228,13 +219,10 @@ checksums:
|
|||||||
common/generate: 0345bf322c191e70d01fd6607ec5c2f8
|
common/generate: 0345bf322c191e70d01fd6607ec5c2f8
|
||||||
common/go_back: b917ea82facb90c88c523b255d29f84b
|
common/go_back: b917ea82facb90c88c523b255d29f84b
|
||||||
common/go_to_dashboard: a6efa97d25e36fedc0af794f6ba610f2
|
common/go_to_dashboard: a6efa97d25e36fedc0af794f6ba610f2
|
||||||
common/headline: 0023cbe059bbadcc77312825cbbce5ac
|
|
||||||
common/hidden: fa290c6ada5869d744ed35e9cca64699
|
common/hidden: fa290c6ada5869d744ed35e9cca64699
|
||||||
common/hidden_field: 3ed5c58d0ed359e558cdf7bd33606d2d
|
common/hidden_field: 3ed5c58d0ed359e558cdf7bd33606d2d
|
||||||
common/hidden_fields: 3de6cfd308293a826cb8679fd1d49972
|
common/hidden_fields: 3de6cfd308293a826cb8679fd1d49972
|
||||||
common/hide: a6088b934651055bb27314d111be510b
|
|
||||||
common/hide_column: 23ce94db148f2d8e4a0923defead6cf1
|
common/hide_column: 23ce94db148f2d8e4a0923defead6cf1
|
||||||
common/html: f750870203043349d570d8f5865ca0f8
|
|
||||||
common/id: c8886d38aeea2ed5f785aba4fc96784b
|
common/id: c8886d38aeea2ed5f785aba4fc96784b
|
||||||
common/image: 048ba7a239de0fbd883ade8558415830
|
common/image: 048ba7a239de0fbd883ade8558415830
|
||||||
common/images: 9305827c28694866f49db42b4c51831f
|
common/images: 9305827c28694866f49db42b4c51831f
|
||||||
@@ -280,9 +268,9 @@ checksums:
|
|||||||
common/mobile_overlay_surveys_look_good: d85169e86077738b9837647bf6d1c7d2
|
common/mobile_overlay_surveys_look_good: d85169e86077738b9837647bf6d1c7d2
|
||||||
common/mobile_overlay_title: 42f52259b7527989fb3a3240f5352a8b
|
common/mobile_overlay_title: 42f52259b7527989fb3a3240f5352a8b
|
||||||
common/months: da74749fbe80394fa0f72973d7b0964a
|
common/months: da74749fbe80394fa0f72973d7b0964a
|
||||||
common/more_options: 53d90eae6a9b0243b5bc043b3d9de169
|
|
||||||
common/move_down: 4f4de55743043355ad4a839aff2c48ff
|
common/move_down: 4f4de55743043355ad4a839aff2c48ff
|
||||||
common/move_up: 69f25b205c677abdb26cbb69d97cd10b
|
common/move_up: 69f25b205c677abdb26cbb69d97cd10b
|
||||||
|
common/multiple_languages: 7d8ddd4b40d32fcd7bd6f7bac6485b1f
|
||||||
common/my_product: ad022177062f9ef6e9acf33b13e889aa
|
common/my_product: ad022177062f9ef6e9acf33b13e889aa
|
||||||
common/name: 9368b5a047572b6051f334af5aa76819
|
common/name: 9368b5a047572b6051f334af5aa76819
|
||||||
common/new: 126d036fae5fb6b629728ecb97e6195b
|
common/new: 126d036fae5fb6b629728ecb97e6195b
|
||||||
@@ -291,7 +279,6 @@ checksums:
|
|||||||
common/no: 8c708225830b06df2d1141c536f2a0d6
|
common/no: 8c708225830b06df2d1141c536f2a0d6
|
||||||
common/no_actions_found: 4d92b789eb121fc76cd6868136dcbcd4
|
common/no_actions_found: 4d92b789eb121fc76cd6868136dcbcd4
|
||||||
common/no_background_image_found: 4108a781a9022c65671a826d4e299d5b
|
common/no_background_image_found: 4108a781a9022c65671a826d4e299d5b
|
||||||
common/no_changes: 17709e3e2fbd133ddb8b3291d13de7f6
|
|
||||||
common/no_code: f602144ab7d28a5b19a446bf74b4dcc4
|
common/no_code: f602144ab7d28a5b19a446bf74b4dcc4
|
||||||
common/no_files_uploaded: c97be829e195a41b2f6b6717b87a232b
|
common/no_files_uploaded: c97be829e195a41b2f6b6717b87a232b
|
||||||
common/no_overlay: 03cde9e91f08e4dd539d788e1e01407f
|
common/no_overlay: 03cde9e91f08e4dd539d788e1e01407f
|
||||||
@@ -299,7 +286,6 @@ checksums:
|
|||||||
common/no_result_found: fedddbc0149972ea072a9e063198a16d
|
common/no_result_found: fedddbc0149972ea072a9e063198a16d
|
||||||
common/no_results: 0e9b73265c6542240f5a3bf6b43e9280
|
common/no_results: 0e9b73265c6542240f5a3bf6b43e9280
|
||||||
common/no_surveys_found: 7b74706fe4f4aacd7d858e19e444fe85
|
common/no_surveys_found: 7b74706fe4f4aacd7d858e19e444fe85
|
||||||
common/no_text_found: 27350f35bdd57b3701c7ec578a1a0e11
|
|
||||||
common/none_of_the_above: e007f0b1e046d5ddbbcfbd87940456ee
|
common/none_of_the_above: e007f0b1e046d5ddbbcfbd87940456ee
|
||||||
common/not_authenticated: fed6c62208524ea6782b5f9c07a95a4f
|
common/not_authenticated: fed6c62208524ea6782b5f9c07a95a4f
|
||||||
common/not_authorized: 4be80383fe1a6f52c61138f1aa8d01d4
|
common/not_authorized: 4be80383fe1a6f52c61138f1aa8d01d4
|
||||||
@@ -314,7 +300,6 @@ checksums:
|
|||||||
common/on: 1929bcf2fba8003c043b446a851bcb4f
|
common/on: 1929bcf2fba8003c043b446a851bcb4f
|
||||||
common/only_one_file_allowed: 171be177f2e96c4bb4c4a47b3bf6c8c9
|
common/only_one_file_allowed: 171be177f2e96c4bb4c4a47b3bf6c8c9
|
||||||
common/only_owners_managers_and_manage_access_members_can_perform_this_action: 3c16fc506e871935f6183793e73b6709
|
common/only_owners_managers_and_manage_access_members_can_perform_this_action: 3c16fc506e871935f6183793e73b6709
|
||||||
common/open_options: a4578c0afbfdf4a76d5952a53085b72a
|
|
||||||
common/option_id: ed21d97b8ab035ba89fb3f5f073229bd
|
common/option_id: ed21d97b8ab035ba89fb3f5f073229bd
|
||||||
common/option_ids: e68c25215ce81ea7ad82ff7be0a0bf2d
|
common/option_ids: e68c25215ce81ea7ad82ff7be0a0bf2d
|
||||||
common/optional: 396fb9a0472daf401c392bdc3e248943
|
common/optional: 396fb9a0472daf401c392bdc3e248943
|
||||||
@@ -324,7 +309,7 @@ checksums:
|
|||||||
common/organization_settings: 11528aa89ae9935e55dcb54478058775
|
common/organization_settings: 11528aa89ae9935e55dcb54478058775
|
||||||
common/other: 79acaa6cd481262bea4e743a422529d2
|
common/other: 79acaa6cd481262bea4e743a422529d2
|
||||||
common/other_filters: 20b09213c131db47eb8b23e72d0c4bea
|
common/other_filters: 20b09213c131db47eb8b23e72d0c4bea
|
||||||
common/other_placeholder: f3a0fa2eaaf75aa92b290449c928c081
|
common/others: 39160224ce0e35eb4eb252c997edf4d8
|
||||||
common/overlay_color: 4b72073285d13fff93d094aabffe05ac
|
common/overlay_color: 4b72073285d13fff93d094aabffe05ac
|
||||||
common/overview: 30c54e4dc4ce599b87d94be34a8617f5
|
common/overview: 30c54e4dc4ce599b87d94be34a8617f5
|
||||||
common/password: 223a61cf906ab9c40d22612c588dff48
|
common/password: 223a61cf906ab9c40d22612c588dff48
|
||||||
@@ -342,8 +327,10 @@ checksums:
|
|||||||
common/please_upgrade_your_plan: 03d54a21ecd27723c72a13644837e5ed
|
common/please_upgrade_your_plan: 03d54a21ecd27723c72a13644837e5ed
|
||||||
common/powered_by_formbricks: 1c3e19894583292bfaf686cac84a4960
|
common/powered_by_formbricks: 1c3e19894583292bfaf686cac84a4960
|
||||||
common/preview: 3173ee1f0f1d4e50665ca4a84c38e15d
|
common/preview: 3173ee1f0f1d4e50665ca4a84c38e15d
|
||||||
|
common/preview_survey: 7409e9c118e3e5d5f2a86201c2b354f2
|
||||||
common/privacy: 7459744a63ef8af4e517a09024bd7c08
|
common/privacy: 7459744a63ef8af4e517a09024bd7c08
|
||||||
common/product_manager: dfeadc96e6d3de22a884ee97974b505e
|
common/product_manager: dfeadc96e6d3de22a884ee97974b505e
|
||||||
|
common/production: 226e0ce83b49700bc1b1c08c4c3ed23a
|
||||||
common/profile: d7878693f91303a438852d617f6d35df
|
common/profile: d7878693f91303a438852d617f6d35df
|
||||||
common/profile_id: 0ef1286cce9d47b148e9a09deccb6655
|
common/profile_id: 0ef1286cce9d47b148e9a09deccb6655
|
||||||
common/progress: dd0200d5849ebb7d64c15098ae91d229
|
common/progress: dd0200d5849ebb7d64c15098ae91d229
|
||||||
@@ -355,7 +342,6 @@ checksums:
|
|||||||
common/quotas_description: a2caa44fa74664b3b6007e813f31a754
|
common/quotas_description: a2caa44fa74664b3b6007e813f31a754
|
||||||
common/read_docs: d06513c266fdd9056e0500eab838ebac
|
common/read_docs: d06513c266fdd9056e0500eab838ebac
|
||||||
common/recipients: f90e7f266be3f5a724858f21a9fd855e
|
common/recipients: f90e7f266be3f5a724858f21a9fd855e
|
||||||
common/refresh: c0aec3f31be4c984bae9a482572d2857
|
|
||||||
common/remove: dba2fe5fe9f83f8078c687f28cba4b52
|
common/remove: dba2fe5fe9f83f8078c687f28cba4b52
|
||||||
common/remove_from_team: 69bcc7a1001c3017f9de578ee22cffd6
|
common/remove_from_team: 69bcc7a1001c3017f9de578ee22cffd6
|
||||||
common/reorder_and_hide_columns: a5e3d7c0c7ef879211d05a37be1c5069
|
common/reorder_and_hide_columns: a5e3d7c0c7ef879211d05a37be1c5069
|
||||||
@@ -369,17 +355,13 @@ checksums:
|
|||||||
common/restart: bab6232e89f24e3129f8e48268739d5b
|
common/restart: bab6232e89f24e3129f8e48268739d5b
|
||||||
common/retry: 6e44d18639560596569a1278f9c83676
|
common/retry: 6e44d18639560596569a1278f9c83676
|
||||||
common/role: 53743bbb6ca938f5b893552e839d067f
|
common/role: 53743bbb6ca938f5b893552e839d067f
|
||||||
common/row_n: eb5bb04b244fadd7a6962aa58bf6bd17
|
|
||||||
common/saas: f01686245bcfb35a3590ab56db677bdb
|
common/saas: f01686245bcfb35a3590ab56db677bdb
|
||||||
common/sales: 38758eb50094cd8190a71fe67be4d647
|
common/sales: 38758eb50094cd8190a71fe67be4d647
|
||||||
common/save: f7a2929f33bc420195e59ac5a8bcd454
|
common/save: f7a2929f33bc420195e59ac5a8bcd454
|
||||||
common/save_as_draft: b1b38812110113627d141db981fb1b12
|
common/save_as_draft: b1b38812110113627d141db981fb1b12
|
||||||
common/save_changes: 53dd9f4f0a4accc822fa5c1f2f6d118a
|
common/save_changes: 53dd9f4f0a4accc822fa5c1f2f6d118a
|
||||||
common/save_without_scheduling: c6595873d611e6d1786fb15281158467
|
|
||||||
common/saving: 27ad05746d65e2f3f17d327eb181725d
|
common/saving: 27ad05746d65e2f3f17d327eb181725d
|
||||||
common/scheduled: 1283929a2810dcf6110765f387dc118e
|
|
||||||
common/search: 49dd6c21604b5e8d4153ff1aff2177e1
|
common/search: 49dd6c21604b5e8d4153ff1aff2177e1
|
||||||
common/search_charts: 51c3934f12f050fb2476d62da335a65c
|
|
||||||
common/security: 4b34923fef858a2b9a4a914c3e822889
|
common/security: 4b34923fef858a2b9a4a914c3e822889
|
||||||
common/segment: e8908115453de180bbda7478ba4c2d50
|
common/segment: e8908115453de180bbda7478ba4c2d50
|
||||||
common/segments: 271db72d5b973fbc5fadab216177eaae
|
common/segments: 271db72d5b973fbc5fadab216177eaae
|
||||||
@@ -411,7 +393,6 @@ checksums:
|
|||||||
common/storage_not_configured: b0c3e339f6d71f23fdd189e7bcb076f6
|
common/storage_not_configured: b0c3e339f6d71f23fdd189e7bcb076f6
|
||||||
common/string: 4ddccc1974775ed7357f9beaf9361cec
|
common/string: 4ddccc1974775ed7357f9beaf9361cec
|
||||||
common/styling: 240fc91eb03c52d46b137f82e7aec2a1
|
common/styling: 240fc91eb03c52d46b137f82e7aec2a1
|
||||||
common/subheader: 73a37d57cb9807e574a42bd0c7e334ed
|
|
||||||
common/submit: 7c91ef5f747eea9f77a9c4f23e19fb2e
|
common/submit: 7c91ef5f747eea9f77a9c4f23e19fb2e
|
||||||
common/summary: 13eb7b8a239fb4702dfdaee69100a220
|
common/summary: 13eb7b8a239fb4702dfdaee69100a220
|
||||||
common/survey: b659d270a53dada994d926e0cc6e9a54
|
common/survey: b659d270a53dada994d926e0cc6e9a54
|
||||||
@@ -420,7 +401,6 @@ checksums:
|
|||||||
common/survey_languages: 93e4a10ab190e6b1e1f7fe5f702df249
|
common/survey_languages: 93e4a10ab190e6b1e1f7fe5f702df249
|
||||||
common/survey_live: d1f370505c67509e7b2759952daba20d
|
common/survey_live: d1f370505c67509e7b2759952daba20d
|
||||||
common/survey_paused: c770d174d6b57e8425a54906a09c8b39
|
common/survey_paused: c770d174d6b57e8425a54906a09c8b39
|
||||||
common/survey_scheduled: 704c5e76b90ea2972ad6cae50f68dcdd
|
|
||||||
common/survey_type: 417fcfecf8eaedefc4f11172426811f9
|
common/survey_type: 417fcfecf8eaedefc4f11172426811f9
|
||||||
common/surveys: 33f68ad4111b32a6361beb9d5c184533
|
common/surveys: 33f68ad4111b32a6361beb9d5c184533
|
||||||
common/table_items_deleted_successfully: 46f29d20b26ecfbaf34d4e7291e88b05
|
common/table_items_deleted_successfully: 46f29d20b26ecfbaf34d4e7291e88b05
|
||||||
@@ -483,6 +463,7 @@ checksums:
|
|||||||
common/workspaces: 8ba082a84aa35cf851af1cf874b853e2
|
common/workspaces: 8ba082a84aa35cf851af1cf874b853e2
|
||||||
common/years: eb4f5fdd2b320bf13e200fd6a6c1abff
|
common/years: eb4f5fdd2b320bf13e200fd6a6c1abff
|
||||||
common/yes: ec580fd11a45779b039466f1e35eed2a
|
common/yes: ec580fd11a45779b039466f1e35eed2a
|
||||||
|
common/you: db2a4a796b70cc1430d1b21f6ffb6dcb
|
||||||
common/you_are_downgraded_to_the_community_edition: e3ae56502ff787109cae0997519f628e
|
common/you_are_downgraded_to_the_community_edition: e3ae56502ff787109cae0997519f628e
|
||||||
common/you_are_not_authorized_to_perform_this_action: 1b3255ab740582ddff016a399f8bf302
|
common/you_are_not_authorized_to_perform_this_action: 1b3255ab740582ddff016a399f8bf302
|
||||||
common/you_have_reached_your_limit_of_workspace_limit: 506a6ee315d9754da7ea26929bc40f52
|
common/you_have_reached_your_limit_of_workspace_limit: 506a6ee315d9754da7ea26929bc40f52
|
||||||
@@ -498,11 +479,11 @@ checksums:
|
|||||||
emails/email_footer_text_2: 6fd719fe916a7155e1b0b88a72420717
|
emails/email_footer_text_2: 6fd719fe916a7155e1b0b88a72420717
|
||||||
emails/email_template_text_1: 86b06d249ef069e0fe2457fe3889c416
|
emails/email_template_text_1: 86b06d249ef069e0fe2457fe3889c416
|
||||||
emails/embed_survey_preview_email_didnt_request: 895b4463965beac0df080ccdef847824
|
emails/embed_survey_preview_email_didnt_request: 895b4463965beac0df080ccdef847824
|
||||||
|
emails/embed_survey_preview_email_environment_id: 4dc6803f9b79c8a4be35a4126a582331
|
||||||
emails/embed_survey_preview_email_fight_spam: 71f345df8d483d5b6c2c6dbab458d0b2
|
emails/embed_survey_preview_email_fight_spam: 71f345df8d483d5b6c2c6dbab458d0b2
|
||||||
emails/embed_survey_preview_email_heading: 2a1982b3aeb91476cefb62554031394a
|
emails/embed_survey_preview_email_heading: 2a1982b3aeb91476cefb62554031394a
|
||||||
emails/embed_survey_preview_email_subject: 3240ad34aac02860909e10187745070e
|
emails/embed_survey_preview_email_subject: 3240ad34aac02860909e10187745070e
|
||||||
emails/embed_survey_preview_email_text: 2eceb6fdedef104db8cfad4de7fdb9aa
|
emails/embed_survey_preview_email_text: 2eceb6fdedef104db8cfad4de7fdb9aa
|
||||||
emails/embed_survey_preview_email_workspace_id: bafef925e1b57b52a69844fdf47aac3c
|
|
||||||
emails/forgot_password_email_change_password: fe6d4ba303b82f4833b3293f0c4e88c0
|
emails/forgot_password_email_change_password: fe6d4ba303b82f4833b3293f0c4e88c0
|
||||||
emails/forgot_password_email_did_not_request: 79d35c3800e23e9d4c95bf33f250104f
|
emails/forgot_password_email_did_not_request: 79d35c3800e23e9d4c95bf33f250104f
|
||||||
emails/forgot_password_email_heading: fe6d4ba303b82f4833b3293f0c4e88c0
|
emails/forgot_password_email_heading: fe6d4ba303b82f4833b3293f0c4e88c0
|
||||||
@@ -589,7 +570,6 @@ checksums:
|
|||||||
s/question_preview: 9d8fbc0150fc10ba851beba2d4f4d9f3
|
s/question_preview: 9d8fbc0150fc10ba851beba2d4f4d9f3
|
||||||
s/response_already_received: 8e7b1a7d6e01a1939bca95285af77a69
|
s/response_already_received: 8e7b1a7d6e01a1939bca95285af77a69
|
||||||
s/response_submitted: d5df62e1db6012bd1283126a8dd7bad6
|
s/response_submitted: d5df62e1db6012bd1283126a8dd7bad6
|
||||||
s/scheduled: 0ec63111fd5efe2ac240912105c5f518
|
|
||||||
s/survey_already_answered_heading: 4783c9c36ad0d4f8eec5dfeb14a04545
|
s/survey_already_answered_heading: 4783c9c36ad0d4f8eec5dfeb14a04545
|
||||||
s/survey_already_answered_subheading: 40cfe7e8680cd4fbb7318a05d3491c78
|
s/survey_already_answered_subheading: 40cfe7e8680cd4fbb7318a05d3491c78
|
||||||
s/survey_sent_to: 192c2b0d27e01c35953b851d3875722e
|
s/survey_sent_to: 192c2b0d27e01c35953b851d3875722e
|
||||||
@@ -715,10 +695,6 @@ checksums:
|
|||||||
templates/career_development_survey_question_6_choice_6: 79acaa6cd481262bea4e743a422529d2
|
templates/career_development_survey_question_6_choice_6: 79acaa6cd481262bea4e743a422529d2
|
||||||
templates/career_development_survey_question_6_headline: 88d2a87cbf2ec21882798890990c2225
|
templates/career_development_survey_question_6_headline: 88d2a87cbf2ec21882798890990c2225
|
||||||
templates/career_development_survey_question_6_subheader: b9b478e967930358b0c74324a7c18fc8
|
templates/career_development_survey_question_6_subheader: b9b478e967930358b0c74324a7c18fc8
|
||||||
templates/ces: 49fc8d0ae7b82f3e7d49922ada7ab7a1
|
|
||||||
templates/ces_description: 66f4aaa7e76fd87d19c4ec3bf71481e0
|
|
||||||
templates/ces_lower_label: c2f05d3610d8879ae503a61d49e32e80
|
|
||||||
templates/ces_upper_label: b88eaddaea17a4f285209c2529a9b8f8
|
|
||||||
templates/cess_survey_name: dd706043a56d66f2895cad743935c5b4
|
templates/cess_survey_name: dd706043a56d66f2895cad743935c5b4
|
||||||
templates/cess_survey_question_1_headline: 70115a7960746a05acef03f815652fc3
|
templates/cess_survey_question_1_headline: 70115a7960746a05acef03f815652fc3
|
||||||
templates/cess_survey_question_1_lower_label: 586eedbc7b53319775e42c7cd4cef4de
|
templates/cess_survey_question_1_lower_label: 586eedbc7b53319775e42c7cd4cef4de
|
||||||
@@ -782,9 +758,7 @@ checksums:
|
|||||||
templates/consent_description: d76e48fb1e8c291b51e783eaf7fc910d
|
templates/consent_description: d76e48fb1e8c291b51e783eaf7fc910d
|
||||||
templates/contact_info: 73913230e8988f5f423e54e0fd43f368
|
templates/contact_info: 73913230e8988f5f423e54e0fd43f368
|
||||||
templates/contact_info_description: 0e8962e628bb0a072a4217ae172db43b
|
templates/contact_info_description: 0e8962e628bb0a072a4217ae172db43b
|
||||||
templates/csat: 6864fe0caad3b052a4ec0837e7b71cee
|
templates/csat_description: 4dd35d7fecfa9fdf47765c7108c3d535
|
||||||
templates/csat_description: 0e64d5594f961e5070a95f715594549e
|
|
||||||
templates/csat_lower_label: 206c68e770b90abd737c8c4cb99aa695
|
|
||||||
templates/csat_name: f216066cef52693bbaa842a3305377c7
|
templates/csat_name: f216066cef52693bbaa842a3305377c7
|
||||||
templates/csat_question_10_headline: b6a9ca9c6c20dced146d817c9a1e9be7
|
templates/csat_question_10_headline: b6a9ca9c6c20dced146d817c9a1e9be7
|
||||||
templates/csat_question_10_placeholder: 37ee9c84f3777b9220d4faec1e1c78ee
|
templates/csat_question_10_placeholder: 37ee9c84f3777b9220d4faec1e1c78ee
|
||||||
@@ -860,7 +834,6 @@ checksums:
|
|||||||
templates/csat_survey_question_2_placeholder: 37ee9c84f3777b9220d4faec1e1c78ee
|
templates/csat_survey_question_2_placeholder: 37ee9c84f3777b9220d4faec1e1c78ee
|
||||||
templates/csat_survey_question_3_headline: 25974b7f1692cad41908fe305830b6c0
|
templates/csat_survey_question_3_headline: 25974b7f1692cad41908fe305830b6c0
|
||||||
templates/csat_survey_question_3_placeholder: 37ee9c84f3777b9220d4faec1e1c78ee
|
templates/csat_survey_question_3_placeholder: 37ee9c84f3777b9220d4faec1e1c78ee
|
||||||
templates/csat_upper_label: a3a49eb9cc86972bce6dc41a107f472d
|
|
||||||
templates/cta_description: bc94a2ddc965b286a8677b0642696c7e
|
templates/cta_description: bc94a2ddc965b286a8677b0642696c7e
|
||||||
templates/custom_survey_description: 0492afdea2ef1bd683eaf48a2bad2caa
|
templates/custom_survey_description: 0492afdea2ef1bd683eaf48a2bad2caa
|
||||||
templates/custom_survey_name: 6fc756927ca9ea22c26368cccd64a67e
|
templates/custom_survey_name: 6fc756927ca9ea22c26368cccd64a67e
|
||||||
@@ -1026,11 +999,6 @@ checksums:
|
|||||||
templates/gauge_feature_satisfaction_question_2_headline: 0fcbefbfcf5c21e42de8a36cb2cad854
|
templates/gauge_feature_satisfaction_question_2_headline: 0fcbefbfcf5c21e42de8a36cb2cad854
|
||||||
templates/identify_customer_goals_description: c30d06df9e5c76334e4c3d470ee6e4d8
|
templates/identify_customer_goals_description: c30d06df9e5c76334e4c3d470ee6e4d8
|
||||||
templates/identify_customer_goals_name: f8123dbfa22e169517a811fae7496595
|
templates/identify_customer_goals_name: f8123dbfa22e169517a811fae7496595
|
||||||
templates/identify_customer_goals_question_1_choice_1: a6803cfbdbd6208eedf5c691f9e106a5
|
|
||||||
templates/identify_customer_goals_question_1_choice_2: 7461749517d62030ec2e3915cf1d223b
|
|
||||||
templates/identify_customer_goals_question_1_choice_3: 725eb3ee0d4f2d229fcf588c21e66a86
|
|
||||||
templates/identify_customer_goals_question_1_choice_4: 3985521036afaf1cbd2bdc7a4d86d351
|
|
||||||
templates/identify_customer_goals_question_1_headline: 45a7347cf3ae2d498a30ca1266898cf8
|
|
||||||
templates/identify_sign_up_barriers_description: 5b2fbee8c425d7a4d0706ec3628cea11
|
templates/identify_sign_up_barriers_description: 5b2fbee8c425d7a4d0706ec3628cea11
|
||||||
templates/identify_sign_up_barriers_name: 3bbc5352dfa7a9c237bc2c6b21b608dd
|
templates/identify_sign_up_barriers_name: 3bbc5352dfa7a9c237bc2c6b21b608dd
|
||||||
templates/identify_sign_up_barriers_question_1_button_label: 080fd22c580f56ffdcea6c3d60448b84
|
templates/identify_sign_up_barriers_question_1_button_label: 080fd22c580f56ffdcea6c3d60448b84
|
||||||
@@ -1105,8 +1073,6 @@ checksums:
|
|||||||
templates/improve_trial_conversion_question_1_subheader: 67c7047ba2365d461df14dbed3f9506d
|
templates/improve_trial_conversion_question_1_subheader: 67c7047ba2365d461df14dbed3f9506d
|
||||||
templates/improve_trial_conversion_question_2_button_label: 89ddbcf710eba274963494f312bdc8a9
|
templates/improve_trial_conversion_question_2_button_label: 89ddbcf710eba274963494f312bdc8a9
|
||||||
templates/improve_trial_conversion_question_2_headline: 54324cd652667183dd3cf647ba72dd07
|
templates/improve_trial_conversion_question_2_headline: 54324cd652667183dd3cf647ba72dd07
|
||||||
templates/improve_trial_conversion_question_3_button_label: 89ddbcf710eba274963494f312bdc8a9
|
|
||||||
templates/improve_trial_conversion_question_3_headline: 8dfe1f843c8de64de7e3fa619b961152
|
|
||||||
templates/improve_trial_conversion_question_4_button_label: d94a6a11cfdf4ebde4c5332e585e2e96
|
templates/improve_trial_conversion_question_4_button_label: d94a6a11cfdf4ebde4c5332e585e2e96
|
||||||
templates/improve_trial_conversion_question_4_headline: 9b07341f65574c4165086ec107cebb45
|
templates/improve_trial_conversion_question_4_headline: 9b07341f65574c4165086ec107cebb45
|
||||||
templates/improve_trial_conversion_question_4_html: 8ce95691eeeae7ad61c4d2f867b918ca
|
templates/improve_trial_conversion_question_4_html: 8ce95691eeeae7ad61c4d2f867b918ca
|
||||||
@@ -1574,6 +1540,7 @@ checksums:
|
|||||||
workspace/actions/this_action_will_be_triggered_when_the_page_is_loaded: 8d28f30cf56f50ea79aef8dd2b02185d
|
workspace/actions/this_action_will_be_triggered_when_the_page_is_loaded: 8d28f30cf56f50ea79aef8dd2b02185d
|
||||||
workspace/actions/this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page: 60230ad129853377af1066e10f3b3c22
|
workspace/actions/this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page: 60230ad129853377af1066e10f3b3c22
|
||||||
workspace/actions/this_action_will_be_triggered_when_the_user_tries_to_leave_the_page: 504fa734659524933e3489823d820265
|
workspace/actions/this_action_will_be_triggered_when_the_user_tries_to_leave_the_page: 504fa734659524933e3489823d820265
|
||||||
|
workspace/actions/this_is_a_code_action_please_make_changes_in_your_code_base: 27e64863fdebca791ca129ac0c3da3d5
|
||||||
workspace/actions/time_in_seconds: 822be76950e5f614ed23f52ba1d4825f
|
workspace/actions/time_in_seconds: 822be76950e5f614ed23f52ba1d4825f
|
||||||
workspace/actions/time_in_seconds_placeholder: e54a4c40e0c6b43fb2e97bd32cab8da8
|
workspace/actions/time_in_seconds_placeholder: e54a4c40e0c6b43fb2e97bd32cab8da8
|
||||||
workspace/actions/time_in_seconds_with_unit: a743b7844c71ddad364a93872682ae9e
|
workspace/actions/time_in_seconds_with_unit: a743b7844c71ddad364a93872682ae9e
|
||||||
@@ -1588,176 +1555,6 @@ checksums:
|
|||||||
workspace/actions/you_can_track_code_action_anywhere_in_your_app_using: 3c0bbf160b8ddbeef142403103b70554
|
workspace/actions/you_can_track_code_action_anywhere_in_your_app_using: 3c0bbf160b8ddbeef142403103b70554
|
||||||
workspace/actions/your_survey_would_be_shown_on_this_url: 766fdeeb52d170c156af5d035a1f8c37
|
workspace/actions/your_survey_would_be_shown_on_this_url: 766fdeeb52d170c156af5d035a1f8c37
|
||||||
workspace/actions/your_survey_would_not_be_shown: af44fe160f449ff9557ebe5d3686832d
|
workspace/actions/your_survey_would_not_be_shown: af44fe160f449ff9557ebe5d3686832d
|
||||||
workspace/analysis/charts/OR: 0208d355f231c386b19390f0bea41b95
|
|
||||||
workspace/analysis/charts/add_chart_to_dashboard: c2a517ada86cdda60e49bec655ca9a6d
|
|
||||||
workspace/analysis/charts/add_chart_to_dashboard_description: 08980a1849757e9aec21fca5881c6be4
|
|
||||||
workspace/analysis/charts/add_filter: ed5d8e9bfcb05cd1e10e4c403befbae6
|
|
||||||
workspace/analysis/charts/add_to_dashboard: 9941c3d30895bb8e25ce8d4e03d33a08
|
|
||||||
workspace/analysis/charts/advanced_chart_builder_config_prompt: c2fe2c1a076f27d3ae62a4db75474b0a
|
|
||||||
workspace/analysis/charts/ai_query_placeholder: 24c3d18f514cb3a9953f04c3b04503a2
|
|
||||||
workspace/analysis/charts/ai_query_section_description: 66d06342f29bf6658793403856521fd7
|
|
||||||
workspace/analysis/charts/ai_query_section_title: c0e450a47af7c2a516b77f73cf54db1b
|
|
||||||
workspace/analysis/charts/and_filter_logic: 53e8eb67a396fcb5e419bb4cbf0008df
|
|
||||||
workspace/analysis/charts/apply_changes: ed3da8072dbd27dc0c959777cdcbebf3
|
|
||||||
workspace/analysis/charts/chart: 6f4d9c56e45ceb8fc22d2f74454cd813
|
|
||||||
workspace/analysis/charts/chart_added_to_dashboard: 7bc429ab605cb89a9232c26be008cc00
|
|
||||||
workspace/analysis/charts/chart_builder_choose_chart_type: 1376de2dcafac573a2df9e4c007b0ec8
|
|
||||||
workspace/analysis/charts/chart_data: 6739a9576b357a58d73ff0c9bf8db0e4
|
|
||||||
workspace/analysis/charts/chart_data_tab: b7b46ab6ce9606032c8f81f6f6afbb9b
|
|
||||||
workspace/analysis/charts/chart_deleted_successfully: 79148f471cd9acc2c8d0d033fb85437e
|
|
||||||
workspace/analysis/charts/chart_deletion_error: 267eb65c168e726075d7cea678dd32e0
|
|
||||||
workspace/analysis/charts/chart_duplicated_successfully: 755c4ce5bf533764d549a53c33e32165
|
|
||||||
workspace/analysis/charts/chart_duplication_error: 90d7166c85188b52f821c9d9f53ff8c4
|
|
||||||
workspace/analysis/charts/chart_name: cdb36e2f121a7b9c28298e15ab8218dc
|
|
||||||
workspace/analysis/charts/chart_name_placeholder: 7370d4f88f27aea337ba1c36465c3f8b
|
|
||||||
workspace/analysis/charts/chart_preview: 1b7faae244d31e43f758f50b94132413
|
|
||||||
workspace/analysis/charts/chart_render_error: 01e9ece0c86a1fedf301afa0dbbf6aeb
|
|
||||||
workspace/analysis/charts/chart_saved_successfully: 2489c853c0b36790e3592ac6ea31cc61
|
|
||||||
workspace/analysis/charts/chart_type_area: 535754c6425f045f17e1dcb551840c93
|
|
||||||
workspace/analysis/charts/chart_type_bar: c11d460595d3ddfe8efd67ac068574c5
|
|
||||||
workspace/analysis/charts/chart_type_big_number: 9d17fb96241507c955dca25e143ae67a
|
|
||||||
workspace/analysis/charts/chart_type_line: f42dd53238ed4d44def306a61d47d5c4
|
|
||||||
workspace/analysis/charts/chart_type_not_supported: 7ff0afc493b36f3f3c12c7c230df9757
|
|
||||||
workspace/analysis/charts/chart_type_pie: 068a797404233ccf68d07ad63af7b50c
|
|
||||||
workspace/analysis/charts/chart_updated_successfully: a2c210523902c726aa1328bbeda0b357
|
|
||||||
workspace/analysis/charts/configure_description: 2939321f78e4ffbc57b4259ddaddb09d
|
|
||||||
workspace/analysis/charts/configure_title: ab767b11da1d386b98b3f634f79d3abe
|
|
||||||
workspace/analysis/charts/configure_type_label: cd13e4b37fb2021af55903e7690a9856
|
|
||||||
workspace/analysis/charts/contains: 06dd606c0a8f81f9a03b414e9ae89440
|
|
||||||
workspace/analysis/charts/create_chart: 636969b904e88bef5c93e859dd8a1656
|
|
||||||
workspace/analysis/charts/create_chart_description: b9680bd8905dea180fa59a86f61de34e
|
|
||||||
workspace/analysis/charts/create_chart_with_ai: b0092b5616015a29dd51fbab49bcd4c4
|
|
||||||
workspace/analysis/charts/custom_range: 99f4d72b64621406acc162cceeb1fed7
|
|
||||||
workspace/analysis/charts/dashboard: c9380ea68c8c76ea451bd9613329a07c
|
|
||||||
workspace/analysis/charts/dashboard_select_placeholder: 9b875f2f10050d650ae63be53fe0d4e8
|
|
||||||
workspace/analysis/charts/data_label: b7b46ab6ce9606032c8f81f6f6afbb9b
|
|
||||||
workspace/analysis/charts/data_source: c29cdd1967a3d1b1a39e91e14469b047
|
|
||||||
workspace/analysis/charts/date_preset_last_30_days: a738894cfc5e592052f1e16787744568
|
|
||||||
workspace/analysis/charts/date_preset_last_7_days: 3631df3109bfecfe358ba15dcf8bd6f5
|
|
||||||
workspace/analysis/charts/date_preset_last_month: 848086395b28875c050d56e3933dae61
|
|
||||||
workspace/analysis/charts/date_preset_this_month: 50845a38865204a97773c44dcd2ebb90
|
|
||||||
workspace/analysis/charts/date_preset_this_quarter: 9c77d94783dff2269c069389122cd7bd
|
|
||||||
workspace/analysis/charts/date_preset_this_year: 1e69651c2ac722f8ce138f43cf2e02f9
|
|
||||||
workspace/analysis/charts/date_preset_today: 142173f9752e18e92109623a3ee68cad
|
|
||||||
workspace/analysis/charts/date_preset_yesterday: eeb58908e68ff96c1b7e8f90e389afb7
|
|
||||||
workspace/analysis/charts/date_range: 9b3aa5954144de586931f60ef9594e99
|
|
||||||
workspace/analysis/charts/delete_chart_confirmation: f7fd7b0a08e81c9b392b08c9c1ad2147
|
|
||||||
workspace/analysis/charts/dimensions: f09d837ac25f58986a769bd48ea15022
|
|
||||||
workspace/analysis/charts/dimensions_toggle_description: 31eb28f3c83c04bbe37799758ca9f595
|
|
||||||
workspace/analysis/charts/edit_chart_description: 822890e4b6068096e2fe8b7b78b4474f
|
|
||||||
workspace/analysis/charts/edit_chart_title: fd3e7f8c53280bfad8f4034c055f4c71
|
|
||||||
workspace/analysis/charts/enable_time_dimension: cfcf0af2d22bccd197319c07680c2cb8
|
|
||||||
workspace/analysis/charts/end_date: acbea5a9fd7a6fadf5aa1b4f47188203
|
|
||||||
workspace/analysis/charts/enter_a_name_for_your_chart: b6e992a23d0628136121ebf26eec4a50
|
|
||||||
workspace/analysis/charts/enter_value: a4554ed67c02872e302b0042724f859d
|
|
||||||
workspace/analysis/charts/equals: 264ec282f7f5b67da622cc37f2b57b8a
|
|
||||||
workspace/analysis/charts/failed_to_add_chart_to_dashboard: 355a5606399edcbb3e6d0ba0b66f12a6
|
|
||||||
workspace/analysis/charts/failed_to_execute_query: d1153133aa4cd3d1cd02e39942413168
|
|
||||||
workspace/analysis/charts/failed_to_load_chart: abea098fbf8e728f95414d3ae8bb63a4
|
|
||||||
workspace/analysis/charts/failed_to_load_chart_data: ea980a6d12b1b1efed90d991dd0dd0fd
|
|
||||||
workspace/analysis/charts/failed_to_save_chart: e237cf1a56a8f9ee30067fdb0757f7c5
|
|
||||||
workspace/analysis/charts/field: cfd632297d7809a3539e90c9cd4728d9
|
|
||||||
workspace/analysis/charts/field_label_average_score: 5b5aa7322549521d1e813b1c8312d443
|
|
||||||
workspace/analysis/charts/field_label_collected_at: b41902ddb4586ba4a4611d726b5014aa
|
|
||||||
workspace/analysis/charts/field_label_count: 9c5848662eb8024ddf360f7e4001a968
|
|
||||||
workspace/analysis/charts/field_label_detractor_count: eedb15bc383eb0f14d43043e6666c62a
|
|
||||||
workspace/analysis/charts/field_label_emotion: eb3a31ead51b5c8a8d365d5f904e9206
|
|
||||||
workspace/analysis/charts/field_label_field_type: 2581066dc304c853a4a817c20996fa08
|
|
||||||
workspace/analysis/charts/field_label_nps_score: 9c8d0b0b460f9689bd66e81d45e0a2df
|
|
||||||
workspace/analysis/charts/field_label_nps_value: cb7404025044400e3d7d5600f3133e4f
|
|
||||||
workspace/analysis/charts/field_label_passive_count: ceb71da8d1382eb2097089dc3ecf76da
|
|
||||||
workspace/analysis/charts/field_label_promoter_count: c393131a4bd3a25bf6b297beed20e34f
|
|
||||||
workspace/analysis/charts/field_label_response_id: 73375099cc976dc7203b8e27f5f709e0
|
|
||||||
workspace/analysis/charts/field_label_sentiment: 9ba5719c80c0136c2d0644217619aff6
|
|
||||||
workspace/analysis/charts/field_label_source_name: 157675beca12efcd8ec512c5256b1a61
|
|
||||||
workspace/analysis/charts/field_label_source_type: d1ff69af76c687eb189db72030717570
|
|
||||||
workspace/analysis/charts/field_label_topic: 7f542b783cd528f00f4f485e35b48dc1
|
|
||||||
workspace/analysis/charts/field_label_user_identifier: b0174469c95038766744fb7e64005aec
|
|
||||||
workspace/analysis/charts/filter_data: 05cc68ed2896feef60bbe3829cd9063d
|
|
||||||
workspace/analysis/charts/filters: acf5accc113ff3c1992688058576732c
|
|
||||||
workspace/analysis/charts/filters_toggle_description: ea18bdb212a6a85620125cab89a4b1c1
|
|
||||||
workspace/analysis/charts/go_to_feedback_record_directories: 1aa0516beef8adbd330cffdcab8b521f
|
|
||||||
workspace/analysis/charts/granularity: 9eb09aef092e7803ce4acb7965cbbaa9
|
|
||||||
workspace/analysis/charts/granularity_day: 47648cd60fc313bc3f05b70357a1d675
|
|
||||||
workspace/analysis/charts/granularity_hour: ec3113f22fc51d01f0c615c5496f8f87
|
|
||||||
workspace/analysis/charts/granularity_month: ae7bef950efc406ff0980affabc1a64c
|
|
||||||
workspace/analysis/charts/granularity_quarter: 7a68ec90d7c90b92b7bb873834a00381
|
|
||||||
workspace/analysis/charts/granularity_week: 436fdd694160827dd6ea4644cdd0a8f8
|
|
||||||
workspace/analysis/charts/granularity_year: ed86f5f60583f9d8ffdbeed306aa0ec7
|
|
||||||
workspace/analysis/charts/greater_than: a4c18b3b45fcaf7c83bf489cf2b506d4
|
|
||||||
workspace/analysis/charts/greater_than_or_equal: d453e26d136847560148168797fece51
|
|
||||||
workspace/analysis/charts/group_by: 3f1cedea7783018ce83f2fab0051a738
|
|
||||||
workspace/analysis/charts/group_by_description: a4a85baaca87c172023cbe87e620118b
|
|
||||||
workspace/analysis/charts/group_data: 55c0035773d8c6b7f4d96363a61cda82
|
|
||||||
workspace/analysis/charts/is_not_set: 906801489132487ef457652af4835142
|
|
||||||
workspace/analysis/charts/is_set: 9850468156356f95884bbaf56b6687aa
|
|
||||||
workspace/analysis/charts/less_than: fb41255dd44bb6de78617b078610c91b
|
|
||||||
workspace/analysis/charts/less_than_or_equal: da4a2816aadf788d33efcdcc3c61802e
|
|
||||||
workspace/analysis/charts/measures: b1e6cf0f356dda0052c4fef4ad4957a2
|
|
||||||
workspace/analysis/charts/no_charts_found: d4a27d5b56e49ebdd38bf28791dbcc42
|
|
||||||
workspace/analysis/charts/no_dashboards_available: f88389b6c5278cfc4d5b360031205dfe
|
|
||||||
workspace/analysis/charts/no_dashboards_create_first: 28ded0d72247191eb23f6f77925df539
|
|
||||||
workspace/analysis/charts/no_data_available: fe1d34a45e22b5611d255b84b2d67232
|
|
||||||
workspace/analysis/charts/no_data_returned: 683acf7b4f3b32aa85fa26f1bb948d4f
|
|
||||||
workspace/analysis/charts/no_data_returned_for_chart: b9ff6c85697c683f40b3d0c05eeb2046
|
|
||||||
workspace/analysis/charts/no_data_source_available: 48179160e288de4a9e00f0bf110a5ced
|
|
||||||
workspace/analysis/charts/no_grouping: e3a6943e61407600cae057e0833a482d
|
|
||||||
workspace/analysis/charts/no_valid_data_to_display: d1ba2b0686520c0a2c62ee73daa1c9c9
|
|
||||||
workspace/analysis/charts/not_contains: 5894f5474271b8902d7892e43500d227
|
|
||||||
workspace/analysis/charts/not_equals: 427715f1ea349965c36f5c628784eb08
|
|
||||||
workspace/analysis/charts/open_chart: bc3bed1517ad63c1bcccfbbc430ab333
|
|
||||||
workspace/analysis/charts/open_options: 2c6a35fec9b9d008e41728594bcd07d7
|
|
||||||
workspace/analysis/charts/or_filter_logic: 0208d355f231c386b19390f0bea41b95
|
|
||||||
workspace/analysis/charts/original: 7e55782bdf7cb49f5616b326c003c278
|
|
||||||
workspace/analysis/charts/please_enter_chart_name: 9258b71b2cb09d22ffe33de1755e7309
|
|
||||||
workspace/analysis/charts/please_enter_filter_values: ca79dfab463a3836863618fd92f82b3e
|
|
||||||
workspace/analysis/charts/please_select_at_least_one_dimension: 32ea97a02bb6826947bb70389d1a6231
|
|
||||||
workspace/analysis/charts/please_select_at_least_one_measure: d4163ede267f71ee65945f453e14ff7b
|
|
||||||
workspace/analysis/charts/please_select_dashboard: 8f062db96f815ed8268584dd8d292fa6
|
|
||||||
workspace/analysis/charts/predefined_measures: 7651141f62c991954edcff70899b2a8b
|
|
||||||
workspace/analysis/charts/preset: a17bb0bf56f3326c9567be3ea896ee19
|
|
||||||
workspace/analysis/charts/query_executed_successfully: 9d6f9dad526fcfe0161757c2d2fe2c69
|
|
||||||
workspace/analysis/charts/reset_to_ai_suggestion: 51ced8dd7c0eea8b7fc4e08b35cfbf30
|
|
||||||
workspace/analysis/charts/save_chart: 2e4505f7bf3d1c35b0b37b1e9d3dc566
|
|
||||||
workspace/analysis/charts/save_chart_dialog_title: 2e4505f7bf3d1c35b0b37b1e9d3dc566
|
|
||||||
workspace/analysis/charts/select_data_source: 983394bc0182b65ec68f713a46b97302
|
|
||||||
workspace/analysis/charts/select_data_source_first: 82a02846de9d6351595c97a0929f3b9a
|
|
||||||
workspace/analysis/charts/select_dimensions: 6d0d038d027ef9e641bf9b7700edac9f
|
|
||||||
workspace/analysis/charts/select_field: 45665a44f7d5707506364f17f28db3bf
|
|
||||||
workspace/analysis/charts/select_measures: c9f101aeb53bf0d4abdd652aaf60a1bf
|
|
||||||
workspace/analysis/charts/select_preset: e68bad9a209a6ca35c62184f1f1d829c
|
|
||||||
workspace/analysis/charts/showing_first_n_of: 4dec3215fd3150a16ad5c72f17ae02bc
|
|
||||||
workspace/analysis/charts/start_date: 881de78c79b56f5ceb9b7103bf23cb2c
|
|
||||||
workspace/analysis/charts/time_dimension: 5c967f2a6a875b00825068df5cb2ef84
|
|
||||||
workspace/analysis/charts/time_dimension_title: 9353ce9a075a0cc8c3ba7dfa9ef19a8d
|
|
||||||
workspace/analysis/charts/time_dimension_toggle_description: 77251d8b3b564390bad8b76f56905190
|
|
||||||
workspace/analysis/dashboards/add_count_charts: b4ee1f29efce0bb380a060e0bc5d64fa
|
|
||||||
workspace/analysis/dashboards/charts_add_failed: c4fda79ede798ab6747a989f083a0947
|
|
||||||
workspace/analysis/dashboards/charts_add_partial_failure: b1a9fc6fe18ab20fe16c16e91a05c195
|
|
||||||
workspace/analysis/dashboards/charts_added_to_dashboard: 917abab80231adf5af51e812352fc77b
|
|
||||||
workspace/analysis/dashboards/charts_load_failed: 190bf9c13d3c3cf18126a263591d6757
|
|
||||||
workspace/analysis/dashboards/create_dashboard: bedb308708fe9c576e161a2fa16d3439
|
|
||||||
workspace/analysis/dashboards/create_dashboard_description: d29f60615f6d8c96cc4265541e75ec26
|
|
||||||
workspace/analysis/dashboards/create_failed: 7b58f15568047a35220b3a47cc3b0f71
|
|
||||||
workspace/analysis/dashboards/create_success: 1fa4dea7702ba03a8a3533295276ff1b
|
|
||||||
workspace/analysis/dashboards/dashboard: c9380ea68c8c76ea451bd9613329a07c
|
|
||||||
workspace/analysis/dashboards/dashboard_delete_confirmation: 468a0fb0e24a985cc47a778b50b334ba
|
|
||||||
workspace/analysis/dashboards/dashboard_name: a2d344bc03f27706b42d7d6a8d0fc752
|
|
||||||
workspace/analysis/dashboards/dashboard_name_placeholder: 02954eeb5671f1c00e3f69b47319916e
|
|
||||||
workspace/analysis/dashboards/dashboard_name_required: 4a56c3ce1d73ad915815f5de4bcff566
|
|
||||||
workspace/analysis/dashboards/dashboard_save_failed: 2b6c7be7947bc7ebb0389b71b5922ba6
|
|
||||||
workspace/analysis/dashboards/dashboard_saved: 6eb27743b6b12d3d0a20b430319890b8
|
|
||||||
workspace/analysis/dashboards/delete_confirmation: 468a0fb0e24a985cc47a778b50b334ba
|
|
||||||
workspace/analysis/dashboards/delete_failed: b108acc28b1f9abcb544a358a958b54b
|
|
||||||
workspace/analysis/dashboards/delete_success: 9d161634daab9ea9d17fbfb413eeeffa
|
|
||||||
workspace/analysis/dashboards/duplicate_failed: 6ebaf8ad373b156f88f1ed79a5efd441
|
|
||||||
workspace/analysis/dashboards/duplicate_success: 37cbb14143776d4c215432673e32ebd9
|
|
||||||
workspace/analysis/dashboards/failed_to_load_chart_data: ea980a6d12b1b1efed90d991dd0dd0fd
|
|
||||||
workspace/analysis/dashboards/no_charts_available_description: 796ed01bcb53f770e5f627002839dcb4
|
|
||||||
workspace/analysis/dashboards/no_charts_to_add_message: ad4cec703aa7d59c407bbb021dce4273
|
|
||||||
workspace/analysis/dashboards/no_dashboards_found: e049ec0356009c3a0aa2c729d916efc6
|
|
||||||
workspace/analysis/dashboards/no_data_message: 464d50cf30281a5b6af2726846eb14b4
|
|
||||||
workspace/analysis/dashboards/please_enter_name: b9211ed8a0882c0e0109beba48685d68
|
|
||||||
workspace/api_keys/add_api_key: 3c7633bae18a6e19af7a5af12f9bc3da
|
workspace/api_keys/add_api_key: 3c7633bae18a6e19af7a5af12f9bc3da
|
||||||
workspace/api_keys/api_key: ce825fec5b3e1f8e27c45b1a63619985
|
workspace/api_keys/api_key: ce825fec5b3e1f8e27c45b1a63619985
|
||||||
workspace/api_keys/api_key_copied_to_clipboard: daeeac786ba09ffa650e206609b88f9c
|
workspace/api_keys/api_key_copied_to_clipboard: daeeac786ba09ffa650e206609b88f9c
|
||||||
@@ -1768,24 +1565,20 @@ checksums:
|
|||||||
workspace/api_keys/api_key_updated: 0e03754eb33742b4ee8d5fdad64c9b3f
|
workspace/api_keys/api_key_updated: 0e03754eb33742b4ee8d5fdad64c9b3f
|
||||||
workspace/api_keys/delete_api_key_confirmation: b2f0342d4e55f0cb244fe121eeeb10a3
|
workspace/api_keys/delete_api_key_confirmation: b2f0342d4e55f0cb244fe121eeeb10a3
|
||||||
workspace/api_keys/duplicate_access: 7ac7ac5ba755ce94e6fc81afa5a21997
|
workspace/api_keys/duplicate_access: 7ac7ac5ba755ce94e6fc81afa5a21997
|
||||||
workspace/api_keys/duplicate_directory_access: e112b756627f0b5e2551451274c3781f
|
|
||||||
workspace/api_keys/feedback_record_directory_access: 51babe735cb94388f68108555814b4f6
|
|
||||||
workspace/api_keys/no_api_keys_yet: 58593ed9f7e507dcd7ca7fe069add599
|
workspace/api_keys/no_api_keys_yet: 58593ed9f7e507dcd7ca7fe069add599
|
||||||
workspace/api_keys/no_directory_permissions_found: ae55b273dd4c71d8431d64d99b39c59f
|
workspace/api_keys/no_env_permissions_found: 97ef49946f3ce15c2ad44dcfd2bce507
|
||||||
workspace/api_keys/no_workspace_permissions_found: 1d719624828a9d3e433cdf6b387549f3
|
|
||||||
workspace/api_keys/organization_access: 96a92fa907b15e0c0e47e33cac15be88
|
workspace/api_keys/organization_access: 96a92fa907b15e0c0e47e33cac15be88
|
||||||
workspace/api_keys/organization_access_description: 773dfeaf6ffbf34dd9a0a3d656a6d83c
|
workspace/api_keys/organization_access_description: 773dfeaf6ffbf34dd9a0a3d656a6d83c
|
||||||
workspace/api_keys/permissions: 2160be68b1d6b6577e64634e9feba2ed
|
workspace/api_keys/permissions: 2160be68b1d6b6577e64634e9feba2ed
|
||||||
workspace/api_keys/secret: f041e5eb96121c8b4f2b8af7e0f83a9b
|
workspace/api_keys/secret: f041e5eb96121c8b4f2b8af7e0f83a9b
|
||||||
workspace/api_keys/unable_to_copy_api_key: 148506832e31d033fa3569ce292d2120
|
|
||||||
workspace/api_keys/unable_to_delete_api_key: 1fd76d9a22c5f5f8c241c4891fca8295
|
workspace/api_keys/unable_to_delete_api_key: 1fd76d9a22c5f5f8c241c4891fca8295
|
||||||
workspace/api_keys/unknown_directory: ed07f55f5dba1f451a45f2cf6e01c9a9
|
|
||||||
workspace/api_keys/unknown_workspace: 4b0df2d07ebc9ab084158b1b9525ae5e
|
|
||||||
workspace/api_keys/workspace_access: b38cb73197ef5f5fa6653b88c68aa0bd
|
workspace/api_keys/workspace_access: b38cb73197ef5f5fa6653b88c68aa0bd
|
||||||
workspace/app-connection/app_connection: 778d2305e1a9c8efe91c2c7b4af37ae4
|
workspace/app-connection/app_connection: 778d2305e1a9c8efe91c2c7b4af37ae4
|
||||||
workspace/app-connection/app_connection_description: dde226414bd2265cbd0daf6635efcfdd
|
workspace/app-connection/app_connection_description: dde226414bd2265cbd0daf6635efcfdd
|
||||||
workspace/app-connection/cache_update_delay_description: 3368e4a8090b7684117a16c94f0c409c
|
workspace/app-connection/cache_update_delay_description: 3368e4a8090b7684117a16c94f0c409c
|
||||||
workspace/app-connection/cache_update_delay_title: 60e4a0fcfbd8850bddf29b5c3f59550c
|
workspace/app-connection/cache_update_delay_title: 60e4a0fcfbd8850bddf29b5c3f59550c
|
||||||
|
workspace/app-connection/environment_id: 49141af65970ea79e22ecedb97ceb2e4
|
||||||
|
workspace/app-connection/environment_id_description: d611755139dbe9865f1436acf6f679be
|
||||||
workspace/app-connection/formbricks_sdk_connected: 29e8a40ad6a7fdb5af5ee9451a70a9aa
|
workspace/app-connection/formbricks_sdk_connected: 29e8a40ad6a7fdb5af5ee9451a70a9aa
|
||||||
workspace/app-connection/formbricks_sdk_not_connected: 557c534e665750978ba6edb0eacb428e
|
workspace/app-connection/formbricks_sdk_not_connected: 557c534e665750978ba6edb0eacb428e
|
||||||
workspace/app-connection/formbricks_sdk_not_connected_description: 4ddbacae084238bd0cefeded0fe9dbb9
|
workspace/app-connection/formbricks_sdk_not_connected_description: 4ddbacae084238bd0cefeded0fe9dbb9
|
||||||
@@ -1794,12 +1587,10 @@ checksums:
|
|||||||
workspace/app-connection/receiving_data: 9f2a48c0b0278861add70b526061264c
|
workspace/app-connection/receiving_data: 9f2a48c0b0278861add70b526061264c
|
||||||
workspace/app-connection/recheck: f95f2bbe6990a123d60255c87bdd59f7
|
workspace/app-connection/recheck: f95f2bbe6990a123d60255c87bdd59f7
|
||||||
workspace/app-connection/sdk_connection_details: 89f2c169fd1604c1df5a834517f1eae1
|
workspace/app-connection/sdk_connection_details: 89f2c169fd1604c1df5a834517f1eae1
|
||||||
workspace/app-connection/sdk_connection_details_description: 2d6824466039672fa002d72da95b4637
|
workspace/app-connection/sdk_connection_details_description: 8e6d79678736819bf2f2940404ba5c3e
|
||||||
workspace/app-connection/setup_alert_description: 6d676044d01dc2147731ffab7df6c259
|
workspace/app-connection/setup_alert_description: 6d676044d01dc2147731ffab7df6c259
|
||||||
workspace/app-connection/setup_alert_title: 9561cca2b391e0df81e8a982921ff2bb
|
workspace/app-connection/setup_alert_title: 9561cca2b391e0df81e8a982921ff2bb
|
||||||
workspace/app-connection/webapp_url: d64d8cc3c4c4ecce780d94755f7e4de9
|
workspace/app-connection/webapp_url: d64d8cc3c4c4ecce780d94755f7e4de9
|
||||||
workspace/app-connection/workspace_id: 49141af65970ea79e22ecedb97ceb2e4
|
|
||||||
workspace/app-connection/workspace_id_description: 77e5219be241e9973741f138787ccbb8
|
|
||||||
workspace/connect/congrats: c2f5b597aabdf298cf9f0452863e2dc6
|
workspace/connect/congrats: c2f5b597aabdf298cf9f0452863e2dc6
|
||||||
workspace/connect/connection_successful_message: fa1f29883e15e8697c6c477bdf5cb645
|
workspace/connect/connection_successful_message: fa1f29883e15e8697c6c477bdf5cb645
|
||||||
workspace/connect/do_it_later: ab4accfbe53d924ab3ffaf9ea78a75f3
|
workspace/connect/do_it_later: ab4accfbe53d924ab3ffaf9ea78a75f3
|
||||||
@@ -1826,10 +1617,10 @@ checksums:
|
|||||||
workspace/contacts/attribute_value_placeholder: 90fb17015de807031304d7a650a6cb8c
|
workspace/contacts/attribute_value_placeholder: 90fb17015de807031304d7a650a6cb8c
|
||||||
workspace/contacts/attributes_msg_attribute_limit_exceeded: a6c430860f307f9cc90c449f96a1284f
|
workspace/contacts/attributes_msg_attribute_limit_exceeded: a6c430860f307f9cc90c449f96a1284f
|
||||||
workspace/contacts/attributes_msg_attribute_type_validation_error: bd70f9773ae873240d4cdb26a662334c
|
workspace/contacts/attributes_msg_attribute_type_validation_error: bd70f9773ae873240d4cdb26a662334c
|
||||||
workspace/contacts/attributes_msg_email_already_exists: 308cf739f7b98a6b2707acf3b658f220
|
workspace/contacts/attributes_msg_email_already_exists: a3ea1265e3db885f53d0e589aecf6260
|
||||||
workspace/contacts/attributes_msg_email_or_userid_required: febc8b0cda4dd45d2c3cdb1ac2d45dcb
|
workspace/contacts/attributes_msg_email_or_userid_required: febc8b0cda4dd45d2c3cdb1ac2d45dcb
|
||||||
workspace/contacts/attributes_msg_new_attribute_created: 5cba6158c4305c05104814ec1479267c
|
workspace/contacts/attributes_msg_new_attribute_created: 5cba6158c4305c05104814ec1479267c
|
||||||
workspace/contacts/attributes_msg_userid_already_exists: 94851fa7f17ffd0da323658dbf6bdd31
|
workspace/contacts/attributes_msg_userid_already_exists: 9c695538befc152806c460f52a73821a
|
||||||
workspace/contacts/contact_deleted_successfully: c5b64a42a50e055f9e27ec49e20e03fa
|
workspace/contacts/contact_deleted_successfully: c5b64a42a50e055f9e27ec49e20e03fa
|
||||||
workspace/contacts/contacts_table_refresh: 6a959475991dd4ab28ad881bae569a09
|
workspace/contacts/contacts_table_refresh: 6a959475991dd4ab28ad881bae569a09
|
||||||
workspace/contacts/contacts_table_refresh_success: 40951396e88e5c8fdafa0b3bb4fadca8
|
workspace/contacts/contacts_table_refresh_success: 40951396e88e5c8fdafa0b3bb4fadca8
|
||||||
@@ -2074,6 +1865,7 @@ checksums:
|
|||||||
workspace/languages/duplicate_language_or_language_id: 0e17e3794b24e2428ca6ffadae0d08f3
|
workspace/languages/duplicate_language_or_language_id: 0e17e3794b24e2428ca6ffadae0d08f3
|
||||||
workspace/languages/edit_languages: c9d36f6b28557cc7d54e87c37dc18fdd
|
workspace/languages/edit_languages: c9d36f6b28557cc7d54e87c37dc18fdd
|
||||||
workspace/languages/identifier: 7d8ade6b85e96216bcd73adeeeeecd8c
|
workspace/languages/identifier: 7d8ade6b85e96216bcd73adeeeeecd8c
|
||||||
|
workspace/languages/incomplete_translations: d82908b5725f18f5849c7876ad497ebc
|
||||||
workspace/languages/language: 277fd1a41cc237a437cd1d5e4a80463b
|
workspace/languages/language: 277fd1a41cc237a437cd1d5e4a80463b
|
||||||
workspace/languages/language_deleted_successfully: 4a805d030491f3fe608d2371b0cfcd83
|
workspace/languages/language_deleted_successfully: 4a805d030491f3fe608d2371b0cfcd83
|
||||||
workspace/languages/languages_updated_successfully: 60de474c99c5059c0458cddd0b016c15
|
workspace/languages/languages_updated_successfully: 60de474c99c5059c0458cddd0b016c15
|
||||||
@@ -2084,6 +1876,7 @@ checksums:
|
|||||||
workspace/languages/remove_language: 1a64563b0f37109f97b78eddd493e381
|
workspace/languages/remove_language: 1a64563b0f37109f97b78eddd493e381
|
||||||
workspace/languages/remove_language_from_surveys_to_remove_it_from_workspace: 61bc96f9db31a29a649cc9ecd684bc39
|
workspace/languages/remove_language_from_surveys_to_remove_it_from_workspace: 61bc96f9db31a29a649cc9ecd684bc39
|
||||||
workspace/languages/search_items: b54b751c8b075200be579d6c8e58096b
|
workspace/languages/search_items: b54b751c8b075200be579d6c8e58096b
|
||||||
|
workspace/languages/translate: 59f9803b27e2030ba7323ed239116cf7
|
||||||
workspace/look/add_background_color: 9be512ee1246e32d3958c56097d202d9
|
workspace/look/add_background_color: 9be512ee1246e32d3958c56097d202d9
|
||||||
workspace/look/add_background_color_description: adb6fcb392862b3d0e9420d9b5405ddb
|
workspace/look/add_background_color_description: adb6fcb392862b3d0e9420d9b5405ddb
|
||||||
workspace/look/advanced_styling_field_border_radius: 63b8f3541a9792d705e67d5aca7b6451
|
workspace/look/advanced_styling_field_border_radius: 63b8f3541a9792d705e67d5aca7b6451
|
||||||
@@ -2600,9 +2393,16 @@ checksums:
|
|||||||
workspace/settings/teams/you_are_a_member: cf5af638d5371c8fbc337e92519e5150
|
workspace/settings/teams/you_are_a_member: cf5af638d5371c8fbc337e92519e5150
|
||||||
workspace/surveys/all_set_time_to_create_first_survey: 21d3bb74c3b9642b3195d17c17346399
|
workspace/surveys/all_set_time_to_create_first_survey: 21d3bb74c3b9642b3195d17c17346399
|
||||||
workspace/surveys/alphabetical: 5fcfeff9c5fd28714f0a390e0ddaaaee
|
workspace/surveys/alphabetical: 5fcfeff9c5fd28714f0a390e0ddaaaee
|
||||||
|
workspace/surveys/copy_survey: de8142b45e7bca61f2dca0069a62b417
|
||||||
|
workspace/surveys/copy_survey_description: b78f714a4a4baae883210b13fb196bd5
|
||||||
|
workspace/surveys/copy_survey_error: 74cab7d84ea8b669e106d4c326cac005
|
||||||
workspace/surveys/copy_survey_link_to_clipboard: 77387e3d3de4be07a2a34963f73cd7e8
|
workspace/surveys/copy_survey_link_to_clipboard: 77387e3d3de4be07a2a34963f73cd7e8
|
||||||
|
workspace/surveys/copy_survey_no_workspaces: 6f4547d91b2c14dad83c44b01df365eb
|
||||||
|
workspace/surveys/copy_survey_partially_success: a436a5fb7167b95c2308794d35aab070
|
||||||
|
workspace/surveys/copy_survey_success: a829e645fe034b3e712d0b8572a5edc4
|
||||||
workspace/surveys/delete_survey_and_responses_warning: 3320c91c1fd27378b7f3d6abc003f2ae
|
workspace/surveys/delete_survey_and_responses_warning: 3320c91c1fd27378b7f3d6abc003f2ae
|
||||||
workspace/surveys/edit/activate_translations: af127c1bed2b47e2012e3a23e489ecb8
|
workspace/surveys/edit/1_choose_the_default_language_for_this_survey: d22759857c1bb3d6b337e8e9d501dad7
|
||||||
|
workspace/surveys/edit/2_activate_translation_for_specific_languages: 9f23cb81ad301073df45ae36f0d94f9e
|
||||||
workspace/surveys/edit/add: 5196f5cd4ba3a6ac8edef91345e17f66
|
workspace/surveys/edit/add: 5196f5cd4ba3a6ac8edef91345e17f66
|
||||||
workspace/surveys/edit/add_a_delay_or_auto_close_the_survey: b5fa358bf3ff324014060eb0baf6dd2f
|
workspace/surveys/edit/add_a_delay_or_auto_close_the_survey: b5fa358bf3ff324014060eb0baf6dd2f
|
||||||
workspace/surveys/edit/add_a_four_digit_pin: 953cb3673d2135923e3b4474d33ffb2c
|
workspace/surveys/edit/add_a_four_digit_pin: 953cb3673d2135923e3b4474d33ffb2c
|
||||||
@@ -2652,7 +2452,7 @@ checksums:
|
|||||||
workspace/surveys/edit/audience: a4d9fab4214a641e2d358fbb28f010e0
|
workspace/surveys/edit/audience: a4d9fab4214a641e2d358fbb28f010e0
|
||||||
workspace/surveys/edit/auto_close_on_inactivity: 093db516799315ccd4242a3675693012
|
workspace/surveys/edit/auto_close_on_inactivity: 093db516799315ccd4242a3675693012
|
||||||
workspace/surveys/edit/auto_progress_rating_and_nps: 76b98e95a5b850850baa0ccc3c7fbf7c
|
workspace/surveys/edit/auto_progress_rating_and_nps: 76b98e95a5b850850baa0ccc3c7fbf7c
|
||||||
workspace/surveys/edit/auto_progress_rating_and_nps_description: 2a992dd8a5b9532f178f9a21881feb9a
|
workspace/surveys/edit/auto_progress_rating_and_nps_description: cbf676789b9f3f47e36bdf35fa58282b
|
||||||
workspace/surveys/edit/auto_save_disabled: f7411fb0dcfb8f7b19b85f0be54f2231
|
workspace/surveys/edit/auto_save_disabled: f7411fb0dcfb8f7b19b85f0be54f2231
|
||||||
workspace/surveys/edit/auto_save_disabled_tooltip: 77322e1e866b7d29f7641a88bbd3b681
|
workspace/surveys/edit/auto_save_disabled_tooltip: 77322e1e866b7d29f7641a88bbd3b681
|
||||||
workspace/surveys/edit/auto_save_on: 1524d466830b00c5d727c701db404963
|
workspace/surveys/edit/auto_save_on: 1524d466830b00c5d727c701db404963
|
||||||
@@ -2698,7 +2498,6 @@ checksums:
|
|||||||
workspace/surveys/edit/caution_text: 3291e962c0e4c4656832837ddc512918
|
workspace/surveys/edit/caution_text: 3291e962c0e4c4656832837ddc512918
|
||||||
workspace/surveys/edit/change_anyway: 6377497d40373f6d0f082670194981ab
|
workspace/surveys/edit/change_anyway: 6377497d40373f6d0f082670194981ab
|
||||||
workspace/surveys/edit/change_background: fa71a993869f7d3ac553c547c12c3e9b
|
workspace/surveys/edit/change_background: fa71a993869f7d3ac553c547c12c3e9b
|
||||||
workspace/surveys/edit/change_default: 6236a6c8a28489ba7c4cad7426806859
|
|
||||||
workspace/surveys/edit/change_question_type: 2d555ae48df8dbedfc6a4e1ad492f4aa
|
workspace/surveys/edit/change_question_type: 2d555ae48df8dbedfc6a4e1ad492f4aa
|
||||||
workspace/surveys/edit/change_survey_type: c26322043a476da6d94adb8b4efe1e93
|
workspace/surveys/edit/change_survey_type: c26322043a476da6d94adb8b4efe1e93
|
||||||
workspace/surveys/edit/change_the_background_to_a_color_image_or_animation: f1b9c9eb61497dd91b2550dd50c77836
|
workspace/surveys/edit/change_the_background_to_a_color_image_or_animation: f1b9c9eb61497dd91b2550dd50c77836
|
||||||
@@ -2710,11 +2509,7 @@ checksums:
|
|||||||
workspace/surveys/edit/choose_the_first_question_on_your_block: bdece06ca04f89d0c445ba1554dd5b80
|
workspace/surveys/edit/choose_the_first_question_on_your_block: bdece06ca04f89d0c445ba1554dd5b80
|
||||||
workspace/surveys/edit/choose_where_to_run_the_survey: ad87bcae97c445f1fd9ac110ea24f117
|
workspace/surveys/edit/choose_where_to_run_the_survey: ad87bcae97c445f1fd9ac110ea24f117
|
||||||
workspace/surveys/edit/city: 1831f32e1babbb29af27fac3053504a2
|
workspace/surveys/edit/city: 1831f32e1babbb29af27fac3053504a2
|
||||||
workspace/surveys/edit/clear_close_on_date: 673ed6940f36b02cf871ffacf034e114
|
|
||||||
workspace/surveys/edit/clear_publish_on_date: fe1ffa08c7b95d1dbd6bb8f89d22760f
|
|
||||||
workspace/surveys/edit/close_survey_on_date: 5588ecb41d245dacfb5f7e1b10a97a3e
|
|
||||||
workspace/surveys/edit/close_survey_on_response_limit: 256d0bccdbcbb3d20e39aabc5b376e5e
|
workspace/surveys/edit/close_survey_on_response_limit: 256d0bccdbcbb3d20e39aabc5b376e5e
|
||||||
workspace/surveys/edit/code: 343bc5386149b97cece2b093c39034b2
|
|
||||||
workspace/surveys/edit/color: 9d53d1d120e8b8954bcae9a322573748
|
workspace/surveys/edit/color: 9d53d1d120e8b8954bcae9a322573748
|
||||||
workspace/surveys/edit/column_used_in_logic_error: deffbd3e8f4bd71a5e522682e8ee60dd
|
workspace/surveys/edit/column_used_in_logic_error: deffbd3e8f4bd71a5e522682e8ee60dd
|
||||||
workspace/surveys/edit/columns: 14896556dc1535d70198854757f704ec
|
workspace/surveys/edit/columns: 14896556dc1535d70198854757f704ec
|
||||||
@@ -2739,7 +2534,6 @@ checksums:
|
|||||||
workspace/surveys/edit/customize_survey_logo: 7f7e26026c88a727228f2d7a00d914e2
|
workspace/surveys/edit/customize_survey_logo: 7f7e26026c88a727228f2d7a00d914e2
|
||||||
workspace/surveys/edit/darken_or_lighten_background_of_your_choice: 304a64a8050ebf501d195e948cd25b6f
|
workspace/surveys/edit/darken_or_lighten_background_of_your_choice: 304a64a8050ebf501d195e948cd25b6f
|
||||||
workspace/surveys/edit/days_before_showing_this_survey_again: 9ee757e5c3a07844b12ceb406dc65b04
|
workspace/surveys/edit/days_before_showing_this_survey_again: 9ee757e5c3a07844b12ceb406dc65b04
|
||||||
workspace/surveys/edit/default_language: 06d01d2598419e36ba97d2d8719f849b
|
|
||||||
workspace/surveys/edit/delete_anyways: cc8683ab625280eefc9776bd381dc2e8
|
workspace/surveys/edit/delete_anyways: cc8683ab625280eefc9776bd381dc2e8
|
||||||
workspace/surveys/edit/delete_block: c00617cb0724557e486304276063807a
|
workspace/surveys/edit/delete_block: c00617cb0724557e486304276063807a
|
||||||
workspace/surveys/edit/delete_choice: fd750208d414b9ad8c980c161a0199e1
|
workspace/surveys/edit/delete_choice: fd750208d414b9ad8c980c161a0199e1
|
||||||
@@ -2759,6 +2553,7 @@ checksums:
|
|||||||
workspace/surveys/edit/duplicate_question: 910751de01fdd327165968214717711b
|
workspace/surveys/edit/duplicate_question: 910751de01fdd327165968214717711b
|
||||||
workspace/surveys/edit/edit_link: 40ba9e15beac77a46c5baf30be84ac54
|
workspace/surveys/edit/edit_link: 40ba9e15beac77a46c5baf30be84ac54
|
||||||
workspace/surveys/edit/edit_recall: 38a4a7378d02453e35d06f2532eef318
|
workspace/surveys/edit/edit_recall: 38a4a7378d02453e35d06f2532eef318
|
||||||
|
workspace/surveys/edit/edit_translations: 2b21bea4b53e88342559272701e9fbf3
|
||||||
workspace/surveys/edit/element_not_found: 196777ff6811dd177971ffc8e27a72c1
|
workspace/surveys/edit/element_not_found: 196777ff6811dd177971ffc8e27a72c1
|
||||||
workspace/surveys/edit/enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey: c70466147d49dcbb3686452f35c46428
|
workspace/surveys/edit/enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey: c70466147d49dcbb3686452f35c46428
|
||||||
workspace/surveys/edit/enable_recaptcha_to_protect_your_survey_from_spam: 4483a5763718d201ac97caa1e1216e13
|
workspace/surveys/edit/enable_recaptcha_to_protect_your_survey_from_spam: 4483a5763718d201ac97caa1e1216e13
|
||||||
@@ -2894,13 +2689,11 @@ checksums:
|
|||||||
workspace/surveys/edit/long_answer: 3a97f8d2e90aba6e679917a0c5670c53
|
workspace/surveys/edit/long_answer: 3a97f8d2e90aba6e679917a0c5670c53
|
||||||
workspace/surveys/edit/long_answer_toggle_description: 86bcdfeb74d9825c2f2d5a215e92d111
|
workspace/surveys/edit/long_answer_toggle_description: 86bcdfeb74d9825c2f2d5a215e92d111
|
||||||
workspace/surveys/edit/lower_label: 45985bca022d4370bd6e013af75d5160
|
workspace/surveys/edit/lower_label: 45985bca022d4370bd6e013af75d5160
|
||||||
workspace/surveys/edit/manage_languages: fe82303bc27b55ccfc076b527b185e39
|
workspace/surveys/edit/manage_languages: 9c56d5afee8a73dfc283a452470f3a10
|
||||||
workspace/surveys/edit/manage_translations: 09b01c5c251e6dbc3dc6cd8b33fb6301
|
|
||||||
workspace/surveys/edit/matrix_all_fields: 187240509163b2f52a400a565e57c67f
|
workspace/surveys/edit/matrix_all_fields: 187240509163b2f52a400a565e57c67f
|
||||||
workspace/surveys/edit/matrix_rows: 8f41f34e6ca28221cf1ebd948af4c151
|
workspace/surveys/edit/matrix_rows: 8f41f34e6ca28221cf1ebd948af4c151
|
||||||
workspace/surveys/edit/max_file_size: 3d35a22048f4d22e24da698fb5fb77d7
|
workspace/surveys/edit/max_file_size: 3d35a22048f4d22e24da698fb5fb77d7
|
||||||
workspace/surveys/edit/max_file_size_limit_is: 78998639cde3587cecb272ba47e05f9e
|
workspace/surveys/edit/max_file_size_limit_is: 78998639cde3587cecb272ba47e05f9e
|
||||||
workspace/surveys/edit/missing_first: a0c8802636ade7bac86a0dacba00b8d4
|
|
||||||
workspace/surveys/edit/move_question_to_block: e8d7ef1e2f727921cb7f5788849492ad
|
workspace/surveys/edit/move_question_to_block: e8d7ef1e2f727921cb7f5788849492ad
|
||||||
workspace/surveys/edit/multiply: 89a0bb629167f97750ae1645a46ced0d
|
workspace/surveys/edit/multiply: 89a0bb629167f97750ae1645a46ced0d
|
||||||
workspace/surveys/edit/needed_for_self_hosted_cal_com_instance: d241e72f0332177d32ce6c35070757dc
|
workspace/surveys/edit/needed_for_self_hosted_cal_com_instance: d241e72f0332177d32ce6c35070757dc
|
||||||
@@ -2908,7 +2701,7 @@ checksums:
|
|||||||
workspace/surveys/edit/next_button_label: 39f1e82ae1dea5e400e8ed7c98c6ad9c
|
workspace/surveys/edit/next_button_label: 39f1e82ae1dea5e400e8ed7c98c6ad9c
|
||||||
workspace/surveys/edit/no_hidden_fields_yet_add_first_one_below: 9cc6cab3a6a42dbf835215897b5b8516
|
workspace/surveys/edit/no_hidden_fields_yet_add_first_one_below: 9cc6cab3a6a42dbf835215897b5b8516
|
||||||
workspace/surveys/edit/no_images_found_for: 7dabcbcc7084f59c6ec0971895dfcd29
|
workspace/surveys/edit/no_images_found_for: 7dabcbcc7084f59c6ec0971895dfcd29
|
||||||
workspace/surveys/edit/no_languages_found_add_first_one_to_get_started: 4e66397232da6a463708220dc020bf42
|
workspace/surveys/edit/no_languages_found_add_first_one_to_get_started: 22d7782c8504daf693cab3cf7135d6e3
|
||||||
workspace/surveys/edit/no_option_found: a1a3aa7e6c13b6bb8df20a1a104c7c04
|
workspace/surveys/edit/no_option_found: a1a3aa7e6c13b6bb8df20a1a104c7c04
|
||||||
workspace/surveys/edit/no_recall_items_found: 729e2b02e412cdc79f5ad94b1918620c
|
workspace/surveys/edit/no_recall_items_found: 729e2b02e412cdc79f5ad94b1918620c
|
||||||
workspace/surveys/edit/no_variables_yet_add_first_one_below: c8704b9ebc9c26c0e9dd50c099ba88cd
|
workspace/surveys/edit/no_variables_yet_add_first_one_below: c8704b9ebc9c26c0e9dd50c099ba88cd
|
||||||
@@ -2935,14 +2728,12 @@ checksums:
|
|||||||
workspace/surveys/edit/please_enter_a_valid_url: 25d43dfb802c31cb59dc88453ea72fc4
|
workspace/surveys/edit/please_enter_a_valid_url: 25d43dfb802c31cb59dc88453ea72fc4
|
||||||
workspace/surveys/edit/please_set_a_survey_trigger: 0358142df37dd1724f629008a1db453a
|
workspace/surveys/edit/please_set_a_survey_trigger: 0358142df37dd1724f629008a1db453a
|
||||||
workspace/surveys/edit/please_specify: e1faa6cd085144f7339c7e74dc6fb366
|
workspace/surveys/edit/please_specify: e1faa6cd085144f7339c7e74dc6fb366
|
||||||
workspace/surveys/edit/present_your_survey_in_multiple_languages: 37f28b0a092d68322fedbc2e0c221ef3
|
|
||||||
workspace/surveys/edit/prevent_double_submission: afc502baa2da81d9c9618da1c3b5a57a
|
workspace/surveys/edit/prevent_double_submission: afc502baa2da81d9c9618da1c3b5a57a
|
||||||
workspace/surveys/edit/prevent_double_submission_description: ef7d2aa22d43bdc6ccebb076c6aa9ce5
|
workspace/surveys/edit/prevent_double_submission_description: ef7d2aa22d43bdc6ccebb076c6aa9ce5
|
||||||
workspace/surveys/edit/progress_saved: d7bfc189571f08bbb4d0240cb9363ffa
|
workspace/surveys/edit/progress_saved: d7bfc189571f08bbb4d0240cb9363ffa
|
||||||
workspace/surveys/edit/protect_survey_with_pin: 16d1925b6a5770f7423772d6d9a8291a
|
workspace/surveys/edit/protect_survey_with_pin: 16d1925b6a5770f7423772d6d9a8291a
|
||||||
workspace/surveys/edit/protect_survey_with_pin_description: 0e55d19b6f3578b1024e03606172a5d2
|
workspace/surveys/edit/protect_survey_with_pin_description: 0e55d19b6f3578b1024e03606172a5d2
|
||||||
workspace/surveys/edit/publish: 4aa95ba4793bb293e771bd73b4f87c0f
|
workspace/surveys/edit/publish: 4aa95ba4793bb293e771bd73b4f87c0f
|
||||||
workspace/surveys/edit/publish_survey_on_date: 3167951ef991b911d2e2abb102842452
|
|
||||||
workspace/surveys/edit/question: 0576462ce60d4263d7c482463fcc9547
|
workspace/surveys/edit/question: 0576462ce60d4263d7c482463fcc9547
|
||||||
workspace/surveys/edit/question_deleted: ecdeb22b81ae2d732656a7742c1eec7b
|
workspace/surveys/edit/question_deleted: ecdeb22b81ae2d732656a7742c1eec7b
|
||||||
workspace/surveys/edit/question_duplicated: 3f02439fd0a8b818bc84c1b1b473898c
|
workspace/surveys/edit/question_duplicated: 3f02439fd0a8b818bc84c1b1b473898c
|
||||||
@@ -3011,7 +2802,6 @@ checksums:
|
|||||||
workspace/surveys/edit/rows: 8f41f34e6ca28221cf1ebd948af4c151
|
workspace/surveys/edit/rows: 8f41f34e6ca28221cf1ebd948af4c151
|
||||||
workspace/surveys/edit/save_and_close: 6ede705b3f82f30269ff3054a5049e34
|
workspace/surveys/edit/save_and_close: 6ede705b3f82f30269ff3054a5049e34
|
||||||
workspace/surveys/edit/scale: 5f55a30a5bdf8f331b56bad9c073473c
|
workspace/surveys/edit/scale: 5f55a30a5bdf8f331b56bad9c073473c
|
||||||
workspace/surveys/edit/schedule_survey: aa9d0a74a96c325e3202bf1efbc4611a
|
|
||||||
workspace/surveys/edit/search_for_images: 8b1bc3561d126cc49a1ee185c07e7aaf
|
workspace/surveys/edit/search_for_images: 8b1bc3561d126cc49a1ee185c07e7aaf
|
||||||
workspace/surveys/edit/seconds_after_trigger_the_survey_will_be_closed_if_no_response: 3584be059fe152e93895ef9885f8e8a7
|
workspace/surveys/edit/seconds_after_trigger_the_survey_will_be_closed_if_no_response: 3584be059fe152e93895ef9885f8e8a7
|
||||||
workspace/surveys/edit/seconds_before_showing_the_survey: 4b03756dd5f06df732bf62b2c7968b82
|
workspace/surveys/edit/seconds_before_showing_the_survey: 4b03756dd5f06df732bf62b2c7968b82
|
||||||
@@ -3027,7 +2817,6 @@ checksums:
|
|||||||
workspace/surveys/edit/seven_points: 4ead50fdfda45e8710767e1b1a84bf42
|
workspace/surveys/edit/seven_points: 4ead50fdfda45e8710767e1b1a84bf42
|
||||||
workspace/surveys/edit/show_block_settings: bad99d99c9908874e45f5c350a88cc79
|
workspace/surveys/edit/show_block_settings: bad99d99c9908874e45f5c350a88cc79
|
||||||
workspace/surveys/edit/show_button: 6b364aac9d7ac71f34a438607c9693bc
|
workspace/surveys/edit/show_button: 6b364aac9d7ac71f34a438607c9693bc
|
||||||
workspace/surveys/edit/show_in_order: 15784a59572eb8a6dba6b918c31a9493
|
|
||||||
workspace/surveys/edit/show_language_switch: b6915a7f26d7079f2d4d844d74440413
|
workspace/surveys/edit/show_language_switch: b6915a7f26d7079f2d4d844d74440413
|
||||||
workspace/surveys/edit/show_multiple_times: 05239c532c9c05ef5d2990ba6ce12f60
|
workspace/surveys/edit/show_multiple_times: 05239c532c9c05ef5d2990ba6ce12f60
|
||||||
workspace/surveys/edit/show_only_once: 31858baf60ebcf193c7e35d9084af0af
|
workspace/surveys/edit/show_only_once: 31858baf60ebcf193c7e35d9084af0af
|
||||||
@@ -3059,8 +2848,7 @@ checksums:
|
|||||||
workspace/surveys/edit/survey_preview: 33644451073149383d3ace08be930739
|
workspace/surveys/edit/survey_preview: 33644451073149383d3ace08be930739
|
||||||
workspace/surveys/edit/survey_styling: 7f96d6563e934e65687b74374a33b1dc
|
workspace/surveys/edit/survey_styling: 7f96d6563e934e65687b74374a33b1dc
|
||||||
workspace/surveys/edit/survey_trigger: f0c7014a684ca566698b87074fad5579
|
workspace/surveys/edit/survey_trigger: f0c7014a684ca566698b87074fad5579
|
||||||
workspace/surveys/edit/survey_will_be_closed_at_midnight_cet: d0a6307e352b3b54fb30d6166201db1f
|
workspace/surveys/edit/switch_multi_language_on_to_get_started: cca0ef91ee49095da30cd1e3f26c406f
|
||||||
workspace/surveys/edit/survey_will_be_published_at_midnight_cet: d6906ffe76f24b13dab15c50bc24e1a7
|
|
||||||
workspace/surveys/edit/target_block_not_found: 0a0c401017ab32364fec2fcbf815d832
|
workspace/surveys/edit/target_block_not_found: 0a0c401017ab32364fec2fcbf815d832
|
||||||
workspace/surveys/edit/targeted: ca615f1fc3b490d5a2187b27fb4a2073
|
workspace/surveys/edit/targeted: ca615f1fc3b490d5a2187b27fb4a2073
|
||||||
workspace/surveys/edit/ten_points: a1317b82003859f77fb3138c55450d63
|
workspace/surveys/edit/ten_points: a1317b82003859f77fb3138c55450d63
|
||||||
@@ -3068,11 +2856,9 @@ checksums:
|
|||||||
workspace/surveys/edit/the_survey_will_be_shown_once_even_if_person_doesnt_respond: e45beba7ae126775f4966776c982a3b4
|
workspace/surveys/edit/the_survey_will_be_shown_once_even_if_person_doesnt_respond: e45beba7ae126775f4966776c982a3b4
|
||||||
workspace/surveys/edit/then: 5e941fb7dd51a18651fcfb865edd5ba6
|
workspace/surveys/edit/then: 5e941fb7dd51a18651fcfb865edd5ba6
|
||||||
workspace/surveys/edit/this_action_will_remove_all_the_translations_from_this_survey: 3340c89696f10bdc01b9a1047ff0b987
|
workspace/surveys/edit/this_action_will_remove_all_the_translations_from_this_survey: 3340c89696f10bdc01b9a1047ff0b987
|
||||||
workspace/surveys/edit/this_will_remove_the_language_and_all_its_translations: 6a71ae70abbd61f13f15323d825a47f6
|
|
||||||
workspace/surveys/edit/three_points: d7f299aec752d7d690ef0ab6373327ae
|
workspace/surveys/edit/three_points: d7f299aec752d7d690ef0ab6373327ae
|
||||||
workspace/surveys/edit/times: 5ab156c13df6bfd75c0b17ad0a92c78a
|
workspace/surveys/edit/times: 5ab156c13df6bfd75c0b17ad0a92c78a
|
||||||
workspace/surveys/edit/to_keep_the_placement_over_all_surveys_consistent_you_can: 7a078e6a39d4c30b465137d2b6ef3e67
|
workspace/surveys/edit/to_keep_the_placement_over_all_surveys_consistent_you_can: 7a078e6a39d4c30b465137d2b6ef3e67
|
||||||
workspace/surveys/edit/translated: 5b9d805410310b726f12bacb06da44e3
|
|
||||||
workspace/surveys/edit/trigger_survey_when_one_of_the_actions_is_fired: 8570291668ec9879d204f10e861112db
|
workspace/surveys/edit/trigger_survey_when_one_of_the_actions_is_fired: 8570291668ec9879d204f10e861112db
|
||||||
workspace/surveys/edit/try_lollipop_or_mountain: c550a0f07b3ae40a237e30a4314a249c
|
workspace/surveys/edit/try_lollipop_or_mountain: c550a0f07b3ae40a237e30a4314a249c
|
||||||
workspace/surveys/edit/type_field_id: 714b845806236bb8a9d6a09933b836e9
|
workspace/surveys/edit/type_field_id: 714b845806236bb8a9d6a09933b836e9
|
||||||
@@ -3145,7 +2931,6 @@ checksums:
|
|||||||
workspace/surveys/edit/verify_email_before_submission_description: 434ab3ee6134367513b633a9d4f7d772
|
workspace/surveys/edit/verify_email_before_submission_description: 434ab3ee6134367513b633a9d4f7d772
|
||||||
workspace/surveys/edit/visibility_and_recontact: c27cb4ff3a4262266902a335c3ad5d84
|
workspace/surveys/edit/visibility_and_recontact: c27cb4ff3a4262266902a335c3ad5d84
|
||||||
workspace/surveys/edit/visibility_and_recontact_description: 2969ab679e1f6111dd96e95cee26e219
|
workspace/surveys/edit/visibility_and_recontact_description: 2969ab679e1f6111dd96e95cee26e219
|
||||||
workspace/surveys/edit/visible: 54ea1310fe55664c24a712eb17070fbd
|
|
||||||
workspace/surveys/edit/wait: 014d18ade977bf08d75b995076596708
|
workspace/surveys/edit/wait: 014d18ade977bf08d75b995076596708
|
||||||
workspace/surveys/edit/wait_a_few_seconds_after_the_trigger_before_showing_the_survey: 13d5521cf73be5afeba71f5db5847919
|
workspace/surveys/edit/wait_a_few_seconds_after_the_trigger_before_showing_the_survey: 13d5521cf73be5afeba71f5db5847919
|
||||||
workspace/surveys/edit/waiting_time_across_surveys: 6873c18d51830e2cadef67cce6a2c95c
|
workspace/surveys/edit/waiting_time_across_surveys: 6873c18d51830e2cadef67cce6a2c95c
|
||||||
@@ -3321,8 +3106,6 @@ checksums:
|
|||||||
workspace/surveys/summary/configure_alerts: 05cc642cd9398034d7e68589d22d97cf
|
workspace/surveys/summary/configure_alerts: 05cc642cd9398034d7e68589d22d97cf
|
||||||
workspace/surveys/summary/congrats: 378f06fe96289e527153f8201088ff74
|
workspace/surveys/summary/congrats: 378f06fe96289e527153f8201088ff74
|
||||||
workspace/surveys/summary/connect_your_website_or_app_with_formbricks_to_get_started: d24183c86d08b16d58daa8ad887b2837
|
workspace/surveys/summary/connect_your_website_or_app_with_formbricks_to_get_started: d24183c86d08b16d58daa8ad887b2837
|
||||||
workspace/surveys/summary/csat_satisfied: 4d6121afdc705a70465a230d6d1f6217
|
|
||||||
workspace/surveys/summary/csat_satisfied_tooltip: 3a69a76559a40fbbdff14525d83b459c
|
|
||||||
workspace/surveys/summary/current_count: 6a3e59de8559e88e991e0aeafa9cfeec
|
workspace/surveys/summary/current_count: 6a3e59de8559e88e991e0aeafa9cfeec
|
||||||
workspace/surveys/summary/custom_range: 9bc7e02a890644b13b5c0b0bdd96c165
|
workspace/surveys/summary/custom_range: 9bc7e02a890644b13b5c0b0bdd96c165
|
||||||
workspace/surveys/summary/delete_all_existing_responses_and_displays: e346bcbdb1e0dfbce5925e19fdf0cc78
|
workspace/surveys/summary/delete_all_existing_responses_and_displays: e346bcbdb1e0dfbce5925e19fdf0cc78
|
||||||
@@ -3330,7 +3113,7 @@ checksums:
|
|||||||
workspace/surveys/summary/downloading_qr_code: 3c46bf636e617848a4fca9b6c5b51dac
|
workspace/surveys/summary/downloading_qr_code: 3c46bf636e617848a4fca9b6c5b51dac
|
||||||
workspace/surveys/summary/drop_offs: 605ee950f82110132d6c5780926af109
|
workspace/surveys/summary/drop_offs: 605ee950f82110132d6c5780926af109
|
||||||
workspace/surveys/summary/drop_offs_tooltip: 2a01683380be45f17636365886cf3452
|
workspace/surveys/summary/drop_offs_tooltip: 2a01683380be45f17636365886cf3452
|
||||||
workspace/surveys/summary/effort_score: b79157d02a8ead85459c158272951ab5
|
workspace/surveys/summary/failed_to_copy_link: 4e891c757c80e770674e8e74d1c08487
|
||||||
workspace/surveys/summary/filter_added_successfully: e247f65020cd87454bcec0da6f0fd034
|
workspace/surveys/summary/filter_added_successfully: e247f65020cd87454bcec0da6f0fd034
|
||||||
workspace/surveys/summary/filter_updated_successfully: 01146bc7e6394e271836be2f1b3a257b
|
workspace/surveys/summary/filter_updated_successfully: 01146bc7e6394e271836be2f1b3a257b
|
||||||
workspace/surveys/summary/filtered_responses_csv: aad66a98be6a09cac8bef9e4db4a75cf
|
workspace/surveys/summary/filtered_responses_csv: aad66a98be6a09cac8bef9e4db4a75cf
|
||||||
@@ -3380,7 +3163,6 @@ checksums:
|
|||||||
workspace/surveys/summary/limit: 347051f1a068e01e8c4e4f6744d8e727
|
workspace/surveys/summary/limit: 347051f1a068e01e8c4e4f6744d8e727
|
||||||
workspace/surveys/summary/no_identified_impressions: c3bc42e6feb9010ced905ded51c5afc4
|
workspace/surveys/summary/no_identified_impressions: c3bc42e6feb9010ced905ded51c5afc4
|
||||||
workspace/surveys/summary/no_responses_found: f10190cffdda4ca1bed479acbb89b13f
|
workspace/surveys/summary/no_responses_found: f10190cffdda4ca1bed479acbb89b13f
|
||||||
workspace/surveys/summary/nps_promoters_tooltip: dea6a683c0c36189e325656d5a7596b8
|
|
||||||
workspace/surveys/summary/other_values_found: 48a74ee68c05f7fb162072b50c683b6a
|
workspace/surveys/summary/other_values_found: 48a74ee68c05f7fb162072b50c683b6a
|
||||||
workspace/surveys/summary/overall: 6c6d6533013d4739766af84b2871bca6
|
workspace/surveys/summary/overall: 6c6d6533013d4739766af84b2871bca6
|
||||||
workspace/surveys/summary/promoters: 41fbb8d0439227661253a82fda39f521
|
workspace/surveys/summary/promoters: 41fbb8d0439227661253a82fda39f521
|
||||||
@@ -3393,6 +3175,7 @@ checksums:
|
|||||||
workspace/surveys/summary/quotas_completed_tooltip: ec5c4dc67eda27c06764354f695db613
|
workspace/surveys/summary/quotas_completed_tooltip: ec5c4dc67eda27c06764354f695db613
|
||||||
workspace/surveys/summary/reset_survey: 8c88ddb81f5f787d183d2e7cb43e7c64
|
workspace/surveys/summary/reset_survey: 8c88ddb81f5f787d183d2e7cb43e7c64
|
||||||
workspace/surveys/summary/reset_survey_warning: 6b44be171d7e2716f234387b100b173d
|
workspace/surveys/summary/reset_survey_warning: 6b44be171d7e2716f234387b100b173d
|
||||||
|
workspace/surveys/summary/satisfied: 4d542ba354b85e644acbca5691d2ce45
|
||||||
workspace/surveys/summary/selected_responses_csv: 9cef3faccd54d4f24647791e6359db90
|
workspace/surveys/summary/selected_responses_csv: 9cef3faccd54d4f24647791e6359db90
|
||||||
workspace/surveys/summary/selected_responses_excel: a0ade8b2658e887a4a3f2ad3bdb0c686
|
workspace/surveys/summary/selected_responses_excel: a0ade8b2658e887a4a3f2ad3bdb0c686
|
||||||
workspace/surveys/summary/setup_integrations: 70de06d73be671a0cd58a3fd4fa62e53
|
workspace/surveys/summary/setup_integrations: 70de06d73be671a0cd58a3fd4fa62e53
|
||||||
@@ -3402,7 +3185,6 @@ checksums:
|
|||||||
workspace/surveys/summary/starts_tooltip: 0a7dd01320490dbbea923053fa1ccad6
|
workspace/surveys/summary/starts_tooltip: 0a7dd01320490dbbea923053fa1ccad6
|
||||||
workspace/surveys/summary/survey_reset_successfully: f53db36a28980ef4766215cf13f01e51
|
workspace/surveys/summary/survey_reset_successfully: f53db36a28980ef4766215cf13f01e51
|
||||||
workspace/surveys/summary/survey_results: b7d86f636beaee2b4d5746bdda058d07
|
workspace/surveys/summary/survey_results: b7d86f636beaee2b4d5746bdda058d07
|
||||||
workspace/surveys/summary/survey_scheduled_successfully: b5f39d8dc0c203466a0ffb5fa60163e8
|
|
||||||
workspace/surveys/summary/this_month: 50845a38865204a97773c44dcd2ebb90
|
workspace/surveys/summary/this_month: 50845a38865204a97773c44dcd2ebb90
|
||||||
workspace/surveys/summary/this_quarter: 9c77d94783dff2269c069389122cd7bd
|
workspace/surveys/summary/this_quarter: 9c77d94783dff2269c069389122cd7bd
|
||||||
workspace/surveys/summary/this_year: 1e69651c2ac722f8ce138f43cf2e02f9
|
workspace/surveys/summary/this_year: 1e69651c2ac722f8ce138f43cf2e02f9
|
||||||
@@ -3416,6 +3198,7 @@ checksums:
|
|||||||
workspace/surveys/summary/youre_not_plugged_in_yet: f19da3cd474b9a3cf28e956fd811fb00
|
workspace/surveys/summary/youre_not_plugged_in_yet: f19da3cd474b9a3cf28e956fd811fb00
|
||||||
workspace/surveys/survey_deleted_successfully: a6b654cc914b344a4475fd2fd4a98cc5
|
workspace/surveys/survey_deleted_successfully: a6b654cc914b344a4475fd2fd4a98cc5
|
||||||
workspace/surveys/survey_duplicated_successfully: 91e244f1e7a33640bb4817166a01ff46
|
workspace/surveys/survey_duplicated_successfully: 91e244f1e7a33640bb4817166a01ff46
|
||||||
|
workspace/surveys/survey_duplication_error: 35994330aed844ce37d8b4f09df24581
|
||||||
workspace/surveys/templates/all_channels: 6be67a82fc7326dc2304b23ab3348b87
|
workspace/surveys/templates/all_channels: 6be67a82fc7326dc2304b23ab3348b87
|
||||||
workspace/surveys/templates/all_industries: c7354412fe34585526ff2232aadace41
|
workspace/surveys/templates/all_industries: c7354412fe34585526ff2232aadace41
|
||||||
workspace/surveys/templates/all_roles: 6582ccd0a2349c162a7ae1574cdf76be
|
workspace/surveys/templates/all_roles: 6582ccd0a2349c162a7ae1574cdf76be
|
||||||
|
|||||||
@@ -1,370 +0,0 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
||||||
|
|
||||||
const mockStartJobsRuntime = vi.fn();
|
|
||||||
const mockRemoveRecurringSurveySchedulingJobSchedule = vi.fn();
|
|
||||||
const mockUpsertRecurringSurveySchedulingJobSchedule = vi.fn();
|
|
||||||
const mockDebug = vi.fn();
|
|
||||||
const mockError = vi.fn();
|
|
||||||
const mockWarn = vi.fn();
|
|
||||||
const mockGetJobsQueueingConfig = vi.fn();
|
|
||||||
const mockGetJobsWorkerBootstrapConfig = vi.fn();
|
|
||||||
const mockProcessResponsePipelineJob = vi.fn();
|
|
||||||
const mockProcessSurveySchedulingJob = vi.fn();
|
|
||||||
const TEST_TIMEOUT_MS = 15_000;
|
|
||||||
|
|
||||||
const slowTest = (name: string, fn: () => Promise<void>): void => {
|
|
||||||
test(name, fn, TEST_TIMEOUT_MS);
|
|
||||||
};
|
|
||||||
|
|
||||||
vi.mock("@formbricks/jobs", () => ({
|
|
||||||
removeRecurringSurveySchedulingJobSchedule: mockRemoveRecurringSurveySchedulingJobSchedule,
|
|
||||||
startJobsRuntime: mockStartJobsRuntime,
|
|
||||||
upsertRecurringSurveySchedulingJobSchedule: mockUpsertRecurringSurveySchedulingJobSchedule,
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/lib/jobs/config", () => ({
|
|
||||||
getJobsQueueingConfig: mockGetJobsQueueingConfig,
|
|
||||||
getJobsWorkerBootstrapConfig: mockGetJobsWorkerBootstrapConfig,
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@formbricks/logger", () => ({
|
|
||||||
logger: {
|
|
||||||
debug: mockDebug,
|
|
||||||
error: mockError,
|
|
||||||
info: vi.fn(),
|
|
||||||
warn: mockWarn,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/modules/response-pipeline/lib/process-response-pipeline-job", () => ({
|
|
||||||
processResponsePipelineJob: mockProcessResponsePipelineJob,
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/modules/survey/scheduling/lib/process-survey-scheduling-job", () => ({
|
|
||||||
processSurveySchedulingJob: mockProcessSurveySchedulingJob,
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("instrumentation-jobs", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.resetModules();
|
|
||||||
vi.clearAllMocks();
|
|
||||||
vi.useFakeTimers();
|
|
||||||
mockRemoveRecurringSurveySchedulingJobSchedule.mockResolvedValue(true);
|
|
||||||
mockGetJobsQueueingConfig.mockReturnValue({
|
|
||||||
enabled: false,
|
|
||||||
redisUrl: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const { resetJobsWorkerRegistrationForTests } = await import("./instrumentation-jobs");
|
|
||||||
await resetJobsWorkerRegistrationForTests();
|
|
||||||
vi.useRealTimers();
|
|
||||||
});
|
|
||||||
|
|
||||||
slowTest("skips worker startup when disabled", async () => {
|
|
||||||
mockGetJobsWorkerBootstrapConfig.mockReturnValue({
|
|
||||||
enabled: false,
|
|
||||||
runtimeOptions: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { registerJobsWorker } = await import("./instrumentation-jobs");
|
|
||||||
const result = await registerJobsWorker();
|
|
||||||
|
|
||||||
expect(result).toBeNull();
|
|
||||||
expect(mockStartJobsRuntime).not.toHaveBeenCalled();
|
|
||||||
expect(mockUpsertRecurringSurveySchedulingJobSchedule).not.toHaveBeenCalled();
|
|
||||||
expect(mockDebug).toHaveBeenCalledWith("BullMQ worker startup skipped");
|
|
||||||
});
|
|
||||||
|
|
||||||
slowTest("starts the worker once and registers handlers", async () => {
|
|
||||||
const mockRuntime = {
|
|
||||||
close: vi.fn().mockResolvedValue(undefined),
|
|
||||||
};
|
|
||||||
const mockExistingOverride = vi.fn();
|
|
||||||
|
|
||||||
mockGetJobsWorkerBootstrapConfig.mockReturnValue({
|
|
||||||
enabled: true,
|
|
||||||
runtimeOptions: {
|
|
||||||
concurrency: 4,
|
|
||||||
jobHandlerOverrides: {
|
|
||||||
"test-log.process": mockExistingOverride,
|
|
||||||
},
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
workerCount: 2,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
mockStartJobsRuntime.mockResolvedValue(mockRuntime);
|
|
||||||
const { registerJobsWorker } = await import("./instrumentation-jobs");
|
|
||||||
const first = await registerJobsWorker();
|
|
||||||
const second = await registerJobsWorker();
|
|
||||||
|
|
||||||
expect(first).toBe(mockRuntime);
|
|
||||||
expect(second).toBe(mockRuntime);
|
|
||||||
expect(mockStartJobsRuntime).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockStartJobsRuntime).toHaveBeenCalledWith({
|
|
||||||
concurrency: 4,
|
|
||||||
jobHandlerOverrides: {
|
|
||||||
"response-pipeline.process": expect.any(Function),
|
|
||||||
"survey-scheduling.reconcile": expect.any(Function),
|
|
||||||
"test-log.process": mockExistingOverride,
|
|
||||||
},
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
workerCount: 2,
|
|
||||||
});
|
|
||||||
const overrides = mockStartJobsRuntime.mock.calls[0]?.[0]?.jobHandlerOverrides;
|
|
||||||
const responsePipelineOverride = overrides?.["response-pipeline.process"];
|
|
||||||
const surveySchedulingOverride = overrides?.["survey-scheduling.reconcile"];
|
|
||||||
|
|
||||||
await responsePipelineOverride?.(
|
|
||||||
{
|
|
||||||
workspaceId: "ws_123",
|
|
||||||
event: "responseCreated",
|
|
||||||
response: { id: "res_123" },
|
|
||||||
surveyId: "survey_123",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
attempt: 1,
|
|
||||||
jobId: "job_123",
|
|
||||||
jobName: "response-pipeline.process",
|
|
||||||
maxAttempts: 3,
|
|
||||||
queueName: "background-jobs",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
await surveySchedulingOverride?.(
|
|
||||||
{
|
|
||||||
scope: "global",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
attempt: 1,
|
|
||||||
jobId: "job_456",
|
|
||||||
jobName: "survey-scheduling.reconcile",
|
|
||||||
maxAttempts: 3,
|
|
||||||
queueName: "background-jobs",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(mockProcessResponsePipelineJob).toHaveBeenCalledWith(
|
|
||||||
{
|
|
||||||
workspaceId: "ws_123",
|
|
||||||
event: "responseCreated",
|
|
||||||
response: { id: "res_123" },
|
|
||||||
surveyId: "survey_123",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
attempt: 1,
|
|
||||||
jobId: "job_123",
|
|
||||||
jobName: "response-pipeline.process",
|
|
||||||
maxAttempts: 3,
|
|
||||||
queueName: "background-jobs",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
expect(mockProcessSurveySchedulingJob).toHaveBeenCalledWith(
|
|
||||||
{
|
|
||||||
scope: "global",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
attempt: 1,
|
|
||||||
jobId: "job_456",
|
|
||||||
jobName: "survey-scheduling.reconcile",
|
|
||||||
maxAttempts: 3,
|
|
||||||
queueName: "background-jobs",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
slowTest("reuses the in-flight startup promise", async () => {
|
|
||||||
const mockRuntime = {
|
|
||||||
close: vi.fn().mockResolvedValue(undefined),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockGetJobsWorkerBootstrapConfig.mockReturnValue({
|
|
||||||
enabled: true,
|
|
||||||
runtimeOptions: {
|
|
||||||
concurrency: 2,
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
workerCount: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let resolveRuntime: ((value: typeof mockRuntime) => void) | undefined;
|
|
||||||
mockStartJobsRuntime.mockReturnValue(
|
|
||||||
new Promise((resolve) => {
|
|
||||||
resolveRuntime = resolve;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const { registerJobsWorker } = await import("./instrumentation-jobs");
|
|
||||||
const firstPromise = registerJobsWorker();
|
|
||||||
const secondPromise = registerJobsWorker();
|
|
||||||
|
|
||||||
expect(mockStartJobsRuntime).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
resolveRuntime?.(mockRuntime);
|
|
||||||
|
|
||||||
await expect(firstPromise).resolves.toBe(mockRuntime);
|
|
||||||
await expect(secondPromise).resolves.toBe(mockRuntime);
|
|
||||||
});
|
|
||||||
|
|
||||||
slowTest("logs and rethrows startup failures", async () => {
|
|
||||||
const startupError = new Error("startup failed");
|
|
||||||
|
|
||||||
mockGetJobsWorkerBootstrapConfig.mockReturnValue({
|
|
||||||
enabled: true,
|
|
||||||
runtimeOptions: {
|
|
||||||
concurrency: 1,
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
workerCount: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
mockStartJobsRuntime.mockRejectedValue(startupError);
|
|
||||||
|
|
||||||
const { registerJobsWorker } = await import("./instrumentation-jobs");
|
|
||||||
|
|
||||||
await expect(registerJobsWorker()).rejects.toThrow("startup failed");
|
|
||||||
expect(mockError).toHaveBeenCalledWith({ err: startupError }, "BullMQ worker registration failed");
|
|
||||||
expect(mockWarn).toHaveBeenCalledWith(
|
|
||||||
{ retryDelayMs: 30_000 },
|
|
||||||
"BullMQ worker registration retry scheduled"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
slowTest("retries worker startup after a transient failure", async () => {
|
|
||||||
const startupError = new Error("startup failed");
|
|
||||||
const recoveredRuntime = {
|
|
||||||
close: vi.fn().mockResolvedValue(undefined),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockGetJobsWorkerBootstrapConfig.mockReturnValue({
|
|
||||||
enabled: true,
|
|
||||||
runtimeOptions: {
|
|
||||||
concurrency: 1,
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
workerCount: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
mockStartJobsRuntime.mockRejectedValueOnce(startupError).mockResolvedValueOnce(recoveredRuntime);
|
|
||||||
const { registerJobsWorker } = await import("./instrumentation-jobs");
|
|
||||||
|
|
||||||
await expect(registerJobsWorker()).rejects.toThrow("startup failed");
|
|
||||||
|
|
||||||
await vi.advanceTimersByTimeAsync(30_000);
|
|
||||||
|
|
||||||
expect(mockStartJobsRuntime).toHaveBeenCalledTimes(2);
|
|
||||||
await expect(registerJobsWorker()).resolves.toBe(recoveredRuntime);
|
|
||||||
});
|
|
||||||
|
|
||||||
slowTest(
|
|
||||||
"registers recurring schedules once when queueing is enabled without an in-process worker",
|
|
||||||
async () => {
|
|
||||||
mockGetJobsQueueingConfig.mockReturnValue({
|
|
||||||
enabled: true,
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
});
|
|
||||||
mockGetJobsWorkerBootstrapConfig.mockReturnValue({
|
|
||||||
enabled: false,
|
|
||||||
runtimeOptions: null,
|
|
||||||
});
|
|
||||||
mockUpsertRecurringSurveySchedulingJobSchedule.mockResolvedValue({
|
|
||||||
id: "schedule-job-1",
|
|
||||||
name: "survey-scheduling.reconcile",
|
|
||||||
queueName: "background-jobs",
|
|
||||||
});
|
|
||||||
|
|
||||||
const { registerRecurringJobs } = await import("./instrumentation-jobs");
|
|
||||||
const { SURVEY_SCHEDULING_DAILY_CRON_PATTERN, SURVEY_SCHEDULING_TIME_ZONE } =
|
|
||||||
await import("@/modules/survey/scheduling/lib/constants");
|
|
||||||
|
|
||||||
await registerRecurringJobs();
|
|
||||||
await registerRecurringJobs();
|
|
||||||
|
|
||||||
expect(mockStartJobsRuntime).not.toHaveBeenCalled();
|
|
||||||
expect(mockRemoveRecurringSurveySchedulingJobSchedule).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockRemoveRecurringSurveySchedulingJobSchedule).toHaveBeenCalledWith({
|
|
||||||
scheduleId: "daily-survey-scheduling",
|
|
||||||
scope: "global",
|
|
||||||
});
|
|
||||||
expect(mockUpsertRecurringSurveySchedulingJobSchedule).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockUpsertRecurringSurveySchedulingJobSchedule).toHaveBeenCalledWith(
|
|
||||||
{
|
|
||||||
scheduleId: "daily-survey-scheduling",
|
|
||||||
scope: "global",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cronPattern: SURVEY_SCHEDULING_DAILY_CRON_PATTERN,
|
|
||||||
kind: "cron",
|
|
||||||
timeZone: SURVEY_SCHEDULING_TIME_ZONE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scope: "global",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
slowTest("retries recurring schedule registration after a transient failure", async () => {
|
|
||||||
const scheduleError = new Error("schedule failed");
|
|
||||||
|
|
||||||
mockGetJobsQueueingConfig.mockReturnValue({
|
|
||||||
enabled: true,
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
});
|
|
||||||
mockUpsertRecurringSurveySchedulingJobSchedule
|
|
||||||
.mockRejectedValueOnce(scheduleError)
|
|
||||||
.mockResolvedValueOnce({
|
|
||||||
id: "schedule-job-1",
|
|
||||||
name: "survey-scheduling.reconcile",
|
|
||||||
queueName: "background-jobs",
|
|
||||||
});
|
|
||||||
|
|
||||||
const { registerRecurringJobs } = await import("./instrumentation-jobs");
|
|
||||||
|
|
||||||
await expect(registerRecurringJobs()).rejects.toThrow("schedule failed");
|
|
||||||
expect(mockError).toHaveBeenCalledWith(
|
|
||||||
{ err: scheduleError },
|
|
||||||
"BullMQ recurring job registration failed"
|
|
||||||
);
|
|
||||||
expect(mockWarn).toHaveBeenCalledWith(
|
|
||||||
{ retryDelayMs: 30_000 },
|
|
||||||
"BullMQ recurring job registration retry scheduled"
|
|
||||||
);
|
|
||||||
|
|
||||||
await vi.advanceTimersByTimeAsync(30_000);
|
|
||||||
|
|
||||||
expect(mockUpsertRecurringSurveySchedulingJobSchedule).toHaveBeenCalledTimes(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
slowTest("clears registration state even when reset close fails", async () => {
|
|
||||||
const failingRuntime = {
|
|
||||||
close: vi.fn().mockRejectedValue(new Error("close failed")),
|
|
||||||
};
|
|
||||||
const nextRuntime = {
|
|
||||||
close: vi.fn().mockResolvedValue(undefined),
|
|
||||||
};
|
|
||||||
|
|
||||||
mockGetJobsWorkerBootstrapConfig.mockReturnValue({
|
|
||||||
enabled: true,
|
|
||||||
runtimeOptions: {
|
|
||||||
concurrency: 1,
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
workerCount: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
mockStartJobsRuntime.mockResolvedValueOnce(failingRuntime).mockResolvedValueOnce(nextRuntime);
|
|
||||||
const { registerJobsWorker, resetJobsWorkerRegistrationForTests } =
|
|
||||||
await import("./instrumentation-jobs");
|
|
||||||
|
|
||||||
await expect(registerJobsWorker()).resolves.toBe(failingRuntime);
|
|
||||||
await expect(resetJobsWorkerRegistrationForTests()).resolves.toBeUndefined();
|
|
||||||
await expect(registerJobsWorker()).resolves.toBe(nextRuntime);
|
|
||||||
|
|
||||||
expect(mockStartJobsRuntime).toHaveBeenCalledTimes(2);
|
|
||||||
expect(mockError).toHaveBeenCalledWith(
|
|
||||||
{ err: expect.any(Error) },
|
|
||||||
"BullMQ worker test reset close failed"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
import {
|
|
||||||
type JobHandlerOverrides,
|
|
||||||
type JobsRuntimeHandle,
|
|
||||||
type TResponsePipelineJobData,
|
|
||||||
type TSurveySchedulingJobData,
|
|
||||||
removeRecurringSurveySchedulingJobSchedule,
|
|
||||||
startJobsRuntime,
|
|
||||||
upsertRecurringSurveySchedulingJobSchedule,
|
|
||||||
} from "@formbricks/jobs";
|
|
||||||
import { logger } from "@formbricks/logger";
|
|
||||||
import { getJobsQueueingConfig, getJobsWorkerBootstrapConfig } from "@/lib/jobs/config";
|
|
||||||
import { processResponsePipelineJob } from "@/modules/response-pipeline/lib/process-response-pipeline-job";
|
|
||||||
import {
|
|
||||||
SURVEY_SCHEDULING_DAILY_CRON_PATTERN,
|
|
||||||
SURVEY_SCHEDULING_DAILY_SCHEDULE_ID,
|
|
||||||
SURVEY_SCHEDULING_GLOBAL_SCOPE,
|
|
||||||
SURVEY_SCHEDULING_TIME_ZONE,
|
|
||||||
} from "@/modules/survey/scheduling/lib/constants";
|
|
||||||
import { processSurveySchedulingJob } from "@/modules/survey/scheduling/lib/process-survey-scheduling-job";
|
|
||||||
|
|
||||||
const WORKER_STARTUP_RETRY_DELAY_MS = 30_000;
|
|
||||||
|
|
||||||
type TJobsRuntimeGlobal = typeof globalThis & {
|
|
||||||
formbricksJobsRecurringRegistration: Promise<void> | undefined;
|
|
||||||
formbricksJobsRecurringRegistered: boolean | undefined;
|
|
||||||
formbricksJobsRecurringRetryTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
||||||
formbricksJobsRuntime: JobsRuntimeHandle | undefined;
|
|
||||||
formbricksJobsRuntimeInitializing: Promise<JobsRuntimeHandle> | undefined;
|
|
||||||
formbricksJobsRuntimeRetryTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
const globalForJobsRuntime = globalThis as TJobsRuntimeGlobal;
|
|
||||||
const RESPONSE_PIPELINE_JOB_NAME = "response-pipeline.process";
|
|
||||||
const SURVEY_SCHEDULING_JOB_NAME = "survey-scheduling.reconcile";
|
|
||||||
const responsePipelineJobHandler: NonNullable<JobHandlerOverrides[string]> = async (data, context) => {
|
|
||||||
await processResponsePipelineJob(data as TResponsePipelineJobData, context);
|
|
||||||
};
|
|
||||||
const surveySchedulingJobHandler: NonNullable<JobHandlerOverrides[string]> = async (data, context) => {
|
|
||||||
await processSurveySchedulingJob(data as TSurveySchedulingJobData, context);
|
|
||||||
};
|
|
||||||
|
|
||||||
const registerSurveySchedulingSchedule = async (): Promise<void> => {
|
|
||||||
await removeRecurringSurveySchedulingJobSchedule({
|
|
||||||
scheduleId: SURVEY_SCHEDULING_DAILY_SCHEDULE_ID,
|
|
||||||
scope: SURVEY_SCHEDULING_GLOBAL_SCOPE,
|
|
||||||
});
|
|
||||||
|
|
||||||
await upsertRecurringSurveySchedulingJobSchedule(
|
|
||||||
{
|
|
||||||
scheduleId: SURVEY_SCHEDULING_DAILY_SCHEDULE_ID,
|
|
||||||
scope: SURVEY_SCHEDULING_GLOBAL_SCOPE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cronPattern: SURVEY_SCHEDULING_DAILY_CRON_PATTERN,
|
|
||||||
kind: "cron",
|
|
||||||
timeZone: SURVEY_SCHEDULING_TIME_ZONE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scope: SURVEY_SCHEDULING_GLOBAL_SCOPE,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const clearRecurringJobsRetryTimeout = (): void => {
|
|
||||||
if (globalForJobsRuntime.formbricksJobsRecurringRetryTimeout) {
|
|
||||||
clearTimeout(globalForJobsRuntime.formbricksJobsRecurringRetryTimeout);
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRetryTimeout = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const scheduleRecurringJobsRetry = (): void => {
|
|
||||||
if (
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRegistered ||
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRegistration ||
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRetryTimeout
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRetryTimeout = setTimeout(() => {
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRetryTimeout = undefined;
|
|
||||||
void registerRecurringJobs().catch(() => undefined);
|
|
||||||
}, WORKER_STARTUP_RETRY_DELAY_MS);
|
|
||||||
|
|
||||||
logger.warn(
|
|
||||||
{ retryDelayMs: WORKER_STARTUP_RETRY_DELAY_MS },
|
|
||||||
"BullMQ recurring job registration retry scheduled"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const clearJobsWorkerRetryTimeout = (): void => {
|
|
||||||
if (globalForJobsRuntime.formbricksJobsRuntimeRetryTimeout) {
|
|
||||||
clearTimeout(globalForJobsRuntime.formbricksJobsRuntimeRetryTimeout);
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeRetryTimeout = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const scheduleJobsWorkerRetry = (): void => {
|
|
||||||
if (
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntime ||
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeInitializing ||
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeRetryTimeout
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeRetryTimeout = setTimeout(() => {
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeRetryTimeout = undefined;
|
|
||||||
void registerJobsWorker().catch(() => undefined);
|
|
||||||
}, WORKER_STARTUP_RETRY_DELAY_MS);
|
|
||||||
|
|
||||||
logger.warn({ retryDelayMs: WORKER_STARTUP_RETRY_DELAY_MS }, "BullMQ worker registration retry scheduled");
|
|
||||||
};
|
|
||||||
|
|
||||||
export const registerRecurringJobs = async (): Promise<void> => {
|
|
||||||
const jobsQueueingConfig = getJobsQueueingConfig();
|
|
||||||
|
|
||||||
if (!jobsQueueingConfig.enabled || !jobsQueueingConfig.redisUrl) {
|
|
||||||
clearRecurringJobsRetryTimeout();
|
|
||||||
logger.debug("BullMQ recurring job registration skipped");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (globalForJobsRuntime.formbricksJobsRecurringRegistered) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (globalForJobsRuntime.formbricksJobsRecurringRegistration) {
|
|
||||||
return await globalForJobsRuntime.formbricksJobsRecurringRegistration;
|
|
||||||
}
|
|
||||||
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRegistration = (async () => {
|
|
||||||
await registerSurveySchedulingSchedule();
|
|
||||||
clearRecurringJobsRetryTimeout();
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRegistered = true;
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRegistration = undefined;
|
|
||||||
})();
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await globalForJobsRuntime.formbricksJobsRecurringRegistration;
|
|
||||||
} catch (error) {
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRegistration = undefined;
|
|
||||||
logger.error({ err: error }, "BullMQ recurring job registration failed");
|
|
||||||
scheduleRecurringJobsRetry();
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const registerJobsWorker = async (): Promise<JobsRuntimeHandle | null> => {
|
|
||||||
const jobsWorkerBootstrapConfig = getJobsWorkerBootstrapConfig();
|
|
||||||
|
|
||||||
if (!jobsWorkerBootstrapConfig.enabled || !jobsWorkerBootstrapConfig.runtimeOptions) {
|
|
||||||
clearJobsWorkerRetryTimeout();
|
|
||||||
logger.debug("BullMQ worker startup skipped");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (globalForJobsRuntime.formbricksJobsRuntime) {
|
|
||||||
return globalForJobsRuntime.formbricksJobsRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (globalForJobsRuntime.formbricksJobsRuntimeInitializing) {
|
|
||||||
return await globalForJobsRuntime.formbricksJobsRuntimeInitializing;
|
|
||||||
}
|
|
||||||
|
|
||||||
const runtimeOptions = jobsWorkerBootstrapConfig.runtimeOptions;
|
|
||||||
const jobHandlerOverrides: JobHandlerOverrides = runtimeOptions.jobHandlerOverrides
|
|
||||||
? {
|
|
||||||
...runtimeOptions.jobHandlerOverrides,
|
|
||||||
[RESPONSE_PIPELINE_JOB_NAME]: responsePipelineJobHandler,
|
|
||||||
[SURVEY_SCHEDULING_JOB_NAME]: surveySchedulingJobHandler,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
[RESPONSE_PIPELINE_JOB_NAME]: responsePipelineJobHandler,
|
|
||||||
[SURVEY_SCHEDULING_JOB_NAME]: surveySchedulingJobHandler,
|
|
||||||
};
|
|
||||||
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeInitializing = (async () => {
|
|
||||||
const runtime = await startJobsRuntime({
|
|
||||||
...runtimeOptions,
|
|
||||||
jobHandlerOverrides,
|
|
||||||
});
|
|
||||||
|
|
||||||
clearJobsWorkerRetryTimeout();
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntime = runtime;
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeInitializing = undefined;
|
|
||||||
return runtime;
|
|
||||||
})();
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await globalForJobsRuntime.formbricksJobsRuntimeInitializing;
|
|
||||||
} catch (error) {
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeInitializing = undefined;
|
|
||||||
logger.error({ err: error }, "BullMQ worker registration failed");
|
|
||||||
scheduleJobsWorkerRetry();
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const resetJobsWorkerRegistrationForTests = async (): Promise<void> => {
|
|
||||||
const runtime = globalForJobsRuntime.formbricksJobsRuntime;
|
|
||||||
const initializing = globalForJobsRuntime.formbricksJobsRuntimeInitializing;
|
|
||||||
clearRecurringJobsRetryTimeout();
|
|
||||||
clearJobsWorkerRetryTimeout();
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRegistered = undefined;
|
|
||||||
globalForJobsRuntime.formbricksJobsRecurringRegistration = undefined;
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntime = undefined;
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeInitializing = undefined;
|
|
||||||
|
|
||||||
const runtimesToClose = new Set<JobsRuntimeHandle>();
|
|
||||||
|
|
||||||
if (runtime) {
|
|
||||||
runtimesToClose.add(runtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initializing) {
|
|
||||||
try {
|
|
||||||
const initializedRuntime = await initializing;
|
|
||||||
runtimesToClose.add(initializedRuntime);
|
|
||||||
} catch {
|
|
||||||
// Startup failures are already surfaced by the test that triggered them.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (globalForJobsRuntime.formbricksJobsRuntime) {
|
|
||||||
runtimesToClose.add(globalForJobsRuntime.formbricksJobsRuntime);
|
|
||||||
}
|
|
||||||
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntime = undefined;
|
|
||||||
globalForJobsRuntime.formbricksJobsRuntimeInitializing = undefined;
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
[...runtimesToClose].map(async (runtimeHandle) => {
|
|
||||||
try {
|
|
||||||
await runtimeHandle.close();
|
|
||||||
} catch (error) {
|
|
||||||
logger.error({ err: error }, "BullMQ worker test reset close failed");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
||||||
|
|
||||||
const mockRegisterJobsWorker = vi.fn();
|
|
||||||
const mockRegisterRecurringJobs = vi.fn();
|
|
||||||
|
|
||||||
vi.mock("@sentry/nextjs", () => ({
|
|
||||||
captureRequestError: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/lib/constants", () => ({
|
|
||||||
IS_PRODUCTION: false,
|
|
||||||
PROMETHEUS_ENABLED: false,
|
|
||||||
SENTRY_DSN: undefined,
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("./instrumentation-jobs", () => ({
|
|
||||||
registerRecurringJobs: mockRegisterRecurringJobs,
|
|
||||||
registerJobsWorker: mockRegisterJobsWorker,
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("instrumentation register", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.resetModules();
|
|
||||||
vi.clearAllMocks();
|
|
||||||
process.env.NEXT_RUNTIME = "nodejs";
|
|
||||||
delete process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
||||||
});
|
|
||||||
|
|
||||||
test("does not block Next.js boot on BullMQ worker startup", async () => {
|
|
||||||
mockRegisterRecurringJobs.mockReturnValue(new Promise(() => undefined));
|
|
||||||
mockRegisterJobsWorker.mockReturnValue(new Promise(() => undefined));
|
|
||||||
|
|
||||||
const { register } = await import("./instrumentation");
|
|
||||||
|
|
||||||
await expect(register()).resolves.toBeUndefined();
|
|
||||||
expect(mockRegisterRecurringJobs).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockRegisterJobsWorker).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("swallows BullMQ worker startup rejections after triggering background registration", async () => {
|
|
||||||
mockRegisterRecurringJobs.mockRejectedValue(new Error("schedule failed"));
|
|
||||||
mockRegisterJobsWorker.mockRejectedValue(new Error("startup failed"));
|
|
||||||
|
|
||||||
const { register } = await import("./instrumentation");
|
|
||||||
|
|
||||||
await expect(register()).resolves.toBeUndefined();
|
|
||||||
await Promise.resolve();
|
|
||||||
|
|
||||||
expect(mockRegisterRecurringJobs).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockRegisterJobsWorker).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
import { type Instrumentation } from "next";
|
import { type Instrumentation } from "next";
|
||||||
import { logger } from "@formbricks/logger";
|
|
||||||
import { isExpectedError } from "@formbricks/types/errors";
|
import { isExpectedError } from "@formbricks/types/errors";
|
||||||
import { IS_PRODUCTION, PROMETHEUS_ENABLED, SENTRY_DSN } from "@/lib/constants";
|
import { IS_PRODUCTION, PROMETHEUS_ENABLED, SENTRY_DSN } from "@/lib/constants";
|
||||||
|
|
||||||
@@ -22,25 +21,6 @@ export const register = async () => {
|
|||||||
if (PROMETHEUS_ENABLED || process.env.OTEL_EXPORTER_OTLP_ENDPOINT) {
|
if (PROMETHEUS_ENABLED || process.env.OTEL_EXPORTER_OTLP_ENDPOINT) {
|
||||||
await import("./instrumentation-node");
|
await import("./instrumentation-node");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip runtime-only BullMQ bootstrapping during production builds.
|
|
||||||
// eslint-disable-next-line turbo/no-undeclared-env-vars -- NEXT_PHASE is a next.js env variable
|
|
||||||
if (process.env.NEXT_PHASE !== "phase-production-build") {
|
|
||||||
try {
|
|
||||||
const { registerJobsWorker, registerRecurringJobs } = await import("./instrumentation-jobs");
|
|
||||||
void registerRecurringJobs().catch((error: unknown) => {
|
|
||||||
logger.error(
|
|
||||||
{ err: error },
|
|
||||||
"BullMQ recurring job registration failed during Next.js instrumentation"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
void registerJobsWorker().catch((error: unknown) => {
|
|
||||||
logger.error({ err: error }, "BullMQ worker registration failed during Next.js instrumentation");
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
logger.error({ err: error }, "BullMQ instrumentation import failed during Next.js instrumentation");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Sentry init loads after OTEL to avoid TracerProvider conflicts
|
// Sentry init loads after OTEL to avoid TracerProvider conflicts
|
||||||
// Sentry tracing is disabled (tracesSampleRate: 0) -- SigNoz handles distributed tracing
|
// Sentry tracing is disabled (tracesSampleRate: 0) -- SigNoz handles distributed tracing
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe("ActionClass Service", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("getActionClasses", () => {
|
describe("getActionClasses", () => {
|
||||||
test("should return action classes for workspace", async () => {
|
test("should return action classes for environment", async () => {
|
||||||
const mockActionClasses: TActionClass[] = [
|
const mockActionClasses: TActionClass[] = [
|
||||||
{
|
{
|
||||||
id: "id1",
|
id: "id1",
|
||||||
@@ -41,15 +41,15 @@ describe("ActionClass Service", () => {
|
|||||||
type: "code",
|
type: "code",
|
||||||
key: "key1",
|
key: "key1",
|
||||||
noCodeConfig: null,
|
noCodeConfig: null,
|
||||||
workspaceId: "ws1",
|
workspaceId: "env1",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
vi.mocked(prisma.actionClass.findMany).mockResolvedValue(mockActionClasses);
|
vi.mocked(prisma.actionClass.findMany).mockResolvedValue(mockActionClasses);
|
||||||
|
|
||||||
const result = await getActionClasses("ws1");
|
const result = await getActionClasses("env1");
|
||||||
expect(result).toEqual(mockActionClasses);
|
expect(result).toEqual(mockActionClasses);
|
||||||
expect(prisma.actionClass.findMany).toHaveBeenCalledWith({
|
expect(prisma.actionClass.findMany).toHaveBeenCalledWith({
|
||||||
where: { workspaceId: "ws1" },
|
where: { workspaceId: "env1" },
|
||||||
select: expect.any(Object),
|
select: expect.any(Object),
|
||||||
take: undefined,
|
take: undefined,
|
||||||
skip: undefined,
|
skip: undefined,
|
||||||
@@ -59,7 +59,7 @@ describe("ActionClass Service", () => {
|
|||||||
|
|
||||||
test("should throw DatabaseError when prisma throws", async () => {
|
test("should throw DatabaseError when prisma throws", async () => {
|
||||||
vi.mocked(prisma.actionClass.findMany).mockRejectedValue(new Error("fail"));
|
vi.mocked(prisma.actionClass.findMany).mockRejectedValue(new Error("fail"));
|
||||||
await expect(getActionClasses("ws1")).rejects.toThrow(DatabaseError);
|
await expect(getActionClasses("env1")).rejects.toThrow(DatabaseError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -78,15 +78,15 @@ describe("ActionClass Service", () => {
|
|||||||
elementSelector: { cssSelector: "button" },
|
elementSelector: { cssSelector: "button" },
|
||||||
urlFilters: [],
|
urlFilters: [],
|
||||||
},
|
},
|
||||||
workspaceId: "ws2",
|
workspaceId: "env2",
|
||||||
};
|
};
|
||||||
if (!prisma.actionClass.findFirst) prisma.actionClass.findFirst = vi.fn();
|
if (!prisma.actionClass.findFirst) prisma.actionClass.findFirst = vi.fn();
|
||||||
vi.mocked(prisma.actionClass.findFirst).mockResolvedValue(mockActionClass);
|
vi.mocked(prisma.actionClass.findFirst).mockResolvedValue(mockActionClass);
|
||||||
|
|
||||||
const result = await getActionClassByWorkspaceIdAndName("ws2", "Action 2");
|
const result = await getActionClassByWorkspaceIdAndName("env2", "Action 2");
|
||||||
expect(result).toEqual(mockActionClass);
|
expect(result).toEqual(mockActionClass);
|
||||||
expect(prisma.actionClass.findFirst).toHaveBeenCalledWith({
|
expect(prisma.actionClass.findFirst).toHaveBeenCalledWith({
|
||||||
where: { name: "Action 2", workspaceId: "ws2" },
|
where: { name: "Action 2", workspaceId: "env2" },
|
||||||
select: expect.any(Object),
|
select: expect.any(Object),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -94,14 +94,14 @@ describe("ActionClass Service", () => {
|
|||||||
test("should return null when not found", async () => {
|
test("should return null when not found", async () => {
|
||||||
if (!prisma.actionClass.findFirst) prisma.actionClass.findFirst = vi.fn();
|
if (!prisma.actionClass.findFirst) prisma.actionClass.findFirst = vi.fn();
|
||||||
vi.mocked(prisma.actionClass.findFirst).mockResolvedValue(null);
|
vi.mocked(prisma.actionClass.findFirst).mockResolvedValue(null);
|
||||||
const result = await getActionClassByWorkspaceIdAndName("ws2", "Action 2");
|
const result = await getActionClassByWorkspaceIdAndName("env2", "Action 2");
|
||||||
expect(result).toBeNull();
|
expect(result).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should throw DatabaseError when prisma throws", async () => {
|
test("should throw DatabaseError when prisma throws", async () => {
|
||||||
if (!prisma.actionClass.findFirst) prisma.actionClass.findFirst = vi.fn();
|
if (!prisma.actionClass.findFirst) prisma.actionClass.findFirst = vi.fn();
|
||||||
vi.mocked(prisma.actionClass.findFirst).mockRejectedValue(new Error("fail"));
|
vi.mocked(prisma.actionClass.findFirst).mockRejectedValue(new Error("fail"));
|
||||||
await expect(getActionClassByWorkspaceIdAndName("ws2", "Action 2")).rejects.toThrow(DatabaseError);
|
await expect(getActionClassByWorkspaceIdAndName("env2", "Action 2")).rejects.toThrow(DatabaseError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ describe("ActionClass Service", () => {
|
|||||||
type: "code",
|
type: "code",
|
||||||
key: "key3",
|
key: "key3",
|
||||||
noCodeConfig: null,
|
noCodeConfig: null,
|
||||||
workspaceId: "ws3",
|
workspaceId: "env3",
|
||||||
};
|
};
|
||||||
if (!prisma.actionClass.findUnique) prisma.actionClass.findUnique = vi.fn();
|
if (!prisma.actionClass.findUnique) prisma.actionClass.findUnique = vi.fn();
|
||||||
vi.mocked(prisma.actionClass.findUnique).mockResolvedValue(mockActionClass);
|
vi.mocked(prisma.actionClass.findUnique).mockResolvedValue(mockActionClass);
|
||||||
|
|||||||
+18
-32
@@ -11,8 +11,6 @@ import {
|
|||||||
verifyPassword,
|
verifyPassword,
|
||||||
} from "./auth";
|
} from "./auth";
|
||||||
|
|
||||||
const PASSWORD_TEST_TIMEOUT_MS = 30_000;
|
|
||||||
|
|
||||||
// Mock prisma
|
// Mock prisma
|
||||||
vi.mock("@formbricks/database", () => ({
|
vi.mock("@formbricks/database", () => ({
|
||||||
prisma: {
|
prisma: {
|
||||||
@@ -23,38 +21,26 @@ vi.mock("@formbricks/database", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
describe("Password Management", () => {
|
describe("Password Management", () => {
|
||||||
test(
|
test("hashPassword should hash a password", async () => {
|
||||||
"hashPassword should hash a password",
|
const password = "testPassword123";
|
||||||
async () => {
|
const hashedPassword = await hashPassword(password);
|
||||||
const password = "testPassword123";
|
expect(hashedPassword).toBeDefined();
|
||||||
const hashedPassword = await hashPassword(password);
|
expect(hashedPassword).not.toBe(password);
|
||||||
expect(hashedPassword).toBeDefined();
|
});
|
||||||
expect(hashedPassword).not.toBe(password);
|
|
||||||
},
|
|
||||||
PASSWORD_TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
test("verifyPassword should verify a correct password", async () => {
|
||||||
"verifyPassword should verify a correct password",
|
const password = "testPassword123";
|
||||||
async () => {
|
const hashedPassword = await hashPassword(password);
|
||||||
const password = "testPassword123";
|
const isValid = await verifyPassword(password, hashedPassword);
|
||||||
const hashedPassword = await hashPassword(password);
|
expect(isValid).toBe(true);
|
||||||
const isValid = await verifyPassword(password, hashedPassword);
|
});
|
||||||
expect(isValid).toBe(true);
|
|
||||||
},
|
|
||||||
PASSWORD_TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
test("verifyPassword should reject an incorrect password", async () => {
|
||||||
"verifyPassword should reject an incorrect password",
|
const password = "testPassword123";
|
||||||
async () => {
|
const hashedPassword = await hashPassword(password);
|
||||||
const password = "testPassword123";
|
const isValid = await verifyPassword("wrongPassword", hashedPassword);
|
||||||
const hashedPassword = await hashPassword(password);
|
expect(isValid).toBe(false);
|
||||||
const isValid = await verifyPassword("wrongPassword", hashedPassword);
|
});
|
||||||
expect(isValid).toBe(false);
|
|
||||||
},
|
|
||||||
PASSWORD_TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Organization Access", () => {
|
describe("Organization Access", () => {
|
||||||
|
|||||||
@@ -467,7 +467,6 @@ export const importCsvDataAction = authenticatedActionClient
|
|||||||
|
|
||||||
const ZListFeedbackRecordsAction = z.object({
|
const ZListFeedbackRecordsAction = z.object({
|
||||||
workspaceId: ZId,
|
workspaceId: ZId,
|
||||||
frdId: ZId,
|
|
||||||
limit: z.number().min(1).max(1000).optional(),
|
limit: z.number().min(1).max(1000).optional(),
|
||||||
cursor: z.string().optional(),
|
cursor: z.string().optional(),
|
||||||
sourceType: z.string().optional(),
|
sourceType: z.string().optional(),
|
||||||
@@ -505,28 +504,38 @@ export const listFeedbackRecordsAction = authenticatedActionClient
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify FRD belongs to workspace's accessible FRDs
|
// tenant_id = FRD id. Fan out across all FRDs assigned to this workspace, merge + sort desc.
|
||||||
const frds = await getFeedbackRecordDirectoriesByWorkspaceId(parsedInput.workspaceId);
|
const frds = await getFeedbackRecordDirectoriesByWorkspaceId(parsedInput.workspaceId);
|
||||||
if (!frds.some((f) => f.id === parsedInput.frdId)) {
|
if (frds.length === 0) {
|
||||||
throw new Error("Feedback record directory not accessible");
|
return { data: [], limit: parsedInput.limit ?? 50 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const params: FeedbackRecordListParams = {
|
const perFrdLimit = parsedInput.limit ?? 50;
|
||||||
tenant_id: parsedInput.frdId,
|
const baseParams = {
|
||||||
limit: parsedInput.limit ?? 50,
|
limit: perFrdLimit,
|
||||||
|
...(parsedInput.sourceType ? { source_type: parsedInput.sourceType } : {}),
|
||||||
|
...(parsedInput.fieldType ? { field_type: parsedInput.fieldType } : {}),
|
||||||
|
...(parsedInput.since ? { since: parsedInput.since } : {}),
|
||||||
|
...(parsedInput.until ? { until: parsedInput.until } : {}),
|
||||||
};
|
};
|
||||||
if (parsedInput.cursor) params.cursor = parsedInput.cursor;
|
|
||||||
if (parsedInput.sourceType) params.source_type = parsedInput.sourceType;
|
|
||||||
if (parsedInput.fieldType) params.field_type = parsedInput.fieldType;
|
|
||||||
if (parsedInput.since) params.since = parsedInput.since;
|
|
||||||
if (parsedInput.until) params.until = parsedInput.until;
|
|
||||||
|
|
||||||
const result = await listFeedbackRecords(params);
|
const results = await Promise.all(
|
||||||
if (result.error || !result.data) {
|
frds.map((frd) =>
|
||||||
logger.warn({ error: result.error }, "Failed to list feedback records");
|
listFeedbackRecords({ ...baseParams, tenant_id: frd.id } as FeedbackRecordListParams)
|
||||||
throw new Error(result.error?.message ?? "Failed to load feedback records");
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const errored = results.find((r) => r.error);
|
||||||
|
if (errored?.error) {
|
||||||
|
logger.warn({ error: errored.error }, "Failed to list feedback records");
|
||||||
|
throw new Error(errored.error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.data;
|
const merged = results
|
||||||
|
.flatMap((r) => r.data?.data ?? [])
|
||||||
|
.sort((a, b) => (a.collected_at < b.collected_at ? 1 : -1))
|
||||||
|
.slice(0, perFrdLimit);
|
||||||
|
|
||||||
|
return { data: merged, limit: perFrdLimit };
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -185,7 +185,6 @@ export const AVAILABLE_LOCALES: TUserLocale[] = [
|
|||||||
"ro-RO",
|
"ro-RO",
|
||||||
"ru-RU",
|
"ru-RU",
|
||||||
"sv-SE",
|
"sv-SE",
|
||||||
"tr-TR",
|
|
||||||
"zh-Hans-CN",
|
"zh-Hans-CN",
|
||||||
"zh-Hant-TW",
|
"zh-Hant-TW",
|
||||||
];
|
];
|
||||||
|
|||||||
+30
-48
@@ -14,8 +14,6 @@ import {
|
|||||||
verifySecret,
|
verifySecret,
|
||||||
} from "./crypto";
|
} from "./crypto";
|
||||||
|
|
||||||
const SECRET_HASH_TEST_TIMEOUT_MS = 45_000;
|
|
||||||
|
|
||||||
// Unmock crypto for these tests since we want to test the actual crypto functions
|
// Unmock crypto for these tests since we want to test the actual crypto functions
|
||||||
vi.unmock("crypto");
|
vi.unmock("crypto");
|
||||||
|
|
||||||
@@ -28,61 +26,45 @@ vi.mock("@formbricks/logger", () => ({
|
|||||||
|
|
||||||
describe("Crypto Utils", () => {
|
describe("Crypto Utils", () => {
|
||||||
describe("hashSecret and verifySecret", () => {
|
describe("hashSecret and verifySecret", () => {
|
||||||
test(
|
test("should hash and verify secrets correctly", async () => {
|
||||||
"should hash and verify secrets correctly",
|
const secret = "test-secret-123";
|
||||||
async () => {
|
const hash = await hashSecret(secret);
|
||||||
const secret = "test-secret-123";
|
|
||||||
const hash = await hashSecret(secret);
|
|
||||||
|
|
||||||
expect(hash).toMatch(/^\$2[aby]\$\d+\$[./A-Za-z0-9]{53}$/);
|
expect(hash).toMatch(/^\$2[aby]\$\d+\$[./A-Za-z0-9]{53}$/);
|
||||||
|
|
||||||
const isValid = await verifySecret(secret, hash);
|
const isValid = await verifySecret(secret, hash);
|
||||||
expect(isValid).toBe(true);
|
expect(isValid).toBe(true);
|
||||||
},
|
});
|
||||||
SECRET_HASH_TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
test("should reject wrong secrets", async () => {
|
||||||
"should reject wrong secrets",
|
const secret = "test-secret-123";
|
||||||
async () => {
|
const wrongSecret = "wrong-secret";
|
||||||
const secret = "test-secret-123";
|
const hash = await hashSecret(secret);
|
||||||
const wrongSecret = "wrong-secret";
|
|
||||||
const hash = await hashSecret(secret);
|
|
||||||
|
|
||||||
const isValid = await verifySecret(wrongSecret, hash);
|
const isValid = await verifySecret(wrongSecret, hash);
|
||||||
expect(isValid).toBe(false);
|
expect(isValid).toBe(false);
|
||||||
},
|
});
|
||||||
SECRET_HASH_TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
test("should generate different hashes for the same secret (due to salt)", async () => {
|
||||||
"should generate different hashes for the same secret (due to salt)",
|
const secret = "test-secret-123";
|
||||||
async () => {
|
const hash1 = await hashSecret(secret);
|
||||||
const secret = "test-secret-123";
|
const hash2 = await hashSecret(secret);
|
||||||
const hash1 = await hashSecret(secret);
|
|
||||||
const hash2 = await hashSecret(secret);
|
|
||||||
|
|
||||||
expect(hash1).not.toBe(hash2);
|
expect(hash1).not.toBe(hash2);
|
||||||
|
|
||||||
// But both should verify correctly
|
// But both should verify correctly
|
||||||
expect(await verifySecret(secret, hash1)).toBe(true);
|
expect(await verifySecret(secret, hash1)).toBe(true);
|
||||||
expect(await verifySecret(secret, hash2)).toBe(true);
|
expect(await verifySecret(secret, hash2)).toBe(true);
|
||||||
},
|
}, 15000);
|
||||||
SECRET_HASH_TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
test("should use custom cost factor", async () => {
|
||||||
"should use custom cost factor",
|
const secret = "test-secret-123";
|
||||||
async () => {
|
const hash = await hashSecret(secret, 10);
|
||||||
const secret = "test-secret-123";
|
|
||||||
const hash = await hashSecret(secret, 10);
|
|
||||||
|
|
||||||
// Verify the cost factor is in the hash
|
// Verify the cost factor is in the hash
|
||||||
expect(hash).toMatch(/^\$2[aby]\$10\$/);
|
expect(hash).toMatch(/^\$2[aby]\$10\$/);
|
||||||
expect(await verifySecret(secret, hash)).toBe(true);
|
expect(await verifySecret(secret, hash)).toBe(true);
|
||||||
},
|
});
|
||||||
SECRET_HASH_TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test("should return false for invalid hash format", async () => {
|
test("should return false for invalid hash format", async () => {
|
||||||
const secret = "test-secret-123";
|
const secret = "test-secret-123";
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ const setTestEnv = (overrides: Record<string, string | undefined> = {}) => {
|
|||||||
NODE_ENV: "test",
|
NODE_ENV: "test",
|
||||||
DATABASE_URL: "https://example.com/db",
|
DATABASE_URL: "https://example.com/db",
|
||||||
ENCRYPTION_KEY: "12345678901234567890123456789012",
|
ENCRYPTION_KEY: "12345678901234567890123456789012",
|
||||||
HUB_API_URL: "https://hub.formbricks.local",
|
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -22,22 +21,13 @@ describe("env", () => {
|
|||||||
process.env = ORIGINAL_ENV;
|
process.env = ORIGINAL_ENV;
|
||||||
});
|
});
|
||||||
|
|
||||||
test("allows ambient DEBUG values from external tooling", async () => {
|
|
||||||
setTestEnv({
|
|
||||||
DEBUG: "pnpm:*",
|
|
||||||
});
|
|
||||||
|
|
||||||
const { env } = await import("./env");
|
|
||||||
|
|
||||||
expect(env.DEBUG).toBe("pnpm:*");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("uses the default password reset token lifetime when env var is not set", async () => {
|
test("uses the default password reset token lifetime when env var is not set", async () => {
|
||||||
setTestEnv({
|
setTestEnv({
|
||||||
PASSWORD_RESET_TOKEN_LIFETIME_MINUTES: undefined,
|
PASSWORD_RESET_TOKEN_LIFETIME_MINUTES: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { env } = await import("./env");
|
const { env } = await import("./env");
|
||||||
|
|
||||||
expect(env.PASSWORD_RESET_TOKEN_LIFETIME_MINUTES).toBe(30);
|
expect(env.PASSWORD_RESET_TOKEN_LIFETIME_MINUTES).toBe(30);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,58 +67,6 @@ describe("env", () => {
|
|||||||
expect(env.DEBUG_SHOW_RESET_LINK).toBe("1");
|
expect(env.DEBUG_SHOW_RESET_LINK).toBe("1");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("uses the default survey scheduling configuration when env vars are not set", async () => {
|
|
||||||
setTestEnv({
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_HOUR: undefined,
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_MINUTE: undefined,
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { env } = await import("./env");
|
|
||||||
|
|
||||||
expect(env.NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE).toBe("Europe/Berlin");
|
|
||||||
expect(env.NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_HOUR).toBe(0);
|
|
||||||
expect(env.NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_MINUTE).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("uses the configured survey scheduling configuration", async () => {
|
|
||||||
setTestEnv({
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_HOUR: "18",
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_MINUTE: "45",
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE: "America/New_York",
|
|
||||||
});
|
|
||||||
|
|
||||||
const { env } = await import("./env");
|
|
||||||
|
|
||||||
expect(env.NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE).toBe("America/New_York");
|
|
||||||
expect(env.NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_HOUR).toBe(18);
|
|
||||||
expect(env.NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_MINUTE).toBe(45);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("fails to load when the survey scheduling timezone is invalid", async () => {
|
|
||||||
setTestEnv({
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE: "Mars/OlympusMons",
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(import("./env")).rejects.toThrow("Invalid environment variables");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("fails to load when the survey scheduling hour is out of range", async () => {
|
|
||||||
setTestEnv({
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_HOUR: "24",
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(import("./env")).rejects.toThrow("Invalid environment variables");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("fails to load when the survey scheduling minute is out of range", async () => {
|
|
||||||
setTestEnv({
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_MINUTE: "60",
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(import("./env")).rejects.toThrow("Invalid environment variables");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("fails to load when DEBUG_SHOW_RESET_LINK is invalid", async () => {
|
test("fails to load when DEBUG_SHOW_RESET_LINK is invalid", async () => {
|
||||||
setTestEnv({
|
setTestEnv({
|
||||||
DEBUG_SHOW_RESET_LINK: "true",
|
DEBUG_SHOW_RESET_LINK: "true",
|
||||||
|
|||||||
+1
-35
@@ -107,22 +107,6 @@ const validateActiveAIProviderConfiguration = (values: TAIConfigurationEnv, ctx:
|
|||||||
providerValidators[values.AI_PROVIDER](values, ctx);
|
providerValidators[values.AI_PROVIDER](values, ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isValidIanaTimeZone = (value: string): boolean => {
|
|
||||||
try {
|
|
||||||
new Intl.DateTimeFormat("en-US", { timeZone: value });
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ZSurveySchedulingTimeZone = z.string().trim().min(1).refine(isValidIanaTimeZone, {
|
|
||||||
message: "NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE must be a valid IANA time zone",
|
|
||||||
});
|
|
||||||
|
|
||||||
const ZSurveySchedulingLocalHour = z.coerce.number().int().min(0).max(23);
|
|
||||||
const ZSurveySchedulingLocalMinute = z.coerce.number().int().min(0).max(59);
|
|
||||||
|
|
||||||
const parsedEnv = createEnv({
|
const parsedEnv = createEnv({
|
||||||
/*
|
/*
|
||||||
* Serverside Environment variables, not available on the client.
|
* Serverside Environment variables, not available on the client.
|
||||||
@@ -140,16 +124,10 @@ const parsedEnv = createEnv({
|
|||||||
BREVO_LIST_ID: z.string().optional(),
|
BREVO_LIST_ID: z.string().optional(),
|
||||||
DATABASE_URL: z.url(),
|
DATABASE_URL: z.url(),
|
||||||
DANGEROUSLY_ALLOW_WEBHOOK_INTERNAL_URLS: z.enum(["1", "0"]).optional(),
|
DANGEROUSLY_ALLOW_WEBHOOK_INTERNAL_URLS: z.enum(["1", "0"]).optional(),
|
||||||
|
DEBUG: z.enum(["1", "0"]).optional(),
|
||||||
DEBUG_SHOW_RESET_LINK: z.enum(["1", "0"]).optional(),
|
DEBUG_SHOW_RESET_LINK: z.enum(["1", "0"]).optional(),
|
||||||
// DEBUG is a common ambient env var in CI/tooling, so we accept arbitrary strings here
|
|
||||||
// and only treat "1" as enabling Formbricks-specific debug behavior downstream.
|
|
||||||
DEBUG: z.string().optional(),
|
|
||||||
AUTH_DEFAULT_TEAM_ID: z.string().optional(),
|
AUTH_DEFAULT_TEAM_ID: z.string().optional(),
|
||||||
AUTH_SKIP_INVITE_FOR_SSO: z.enum(["1", "0"]).optional(),
|
AUTH_SKIP_INVITE_FOR_SSO: z.enum(["1", "0"]).optional(),
|
||||||
BULLMQ_WORKER_CONCURRENCY: z.coerce.number().int().min(1).optional(),
|
|
||||||
BULLMQ_WORKER_COUNT: z.coerce.number().int().min(1).optional(),
|
|
||||||
BULLMQ_EXTERNAL_WORKER_ENABLED: z.enum(["1", "0"]).optional(),
|
|
||||||
BULLMQ_WORKER_ENABLED: z.enum(["1", "0"]).optional(),
|
|
||||||
E2E_TESTING: z.enum(["1", "0"]).optional(),
|
E2E_TESTING: z.enum(["1", "0"]).optional(),
|
||||||
EMAIL_AUTH_DISABLED: z.enum(["1", "0"]).optional(),
|
EMAIL_AUTH_DISABLED: z.enum(["1", "0"]).optional(),
|
||||||
EMAIL_VERIFICATION_DISABLED: z.enum(["1", "0"]).optional(),
|
EMAIL_VERIFICATION_DISABLED: z.enum(["1", "0"]).optional(),
|
||||||
@@ -273,11 +251,6 @@ const parsedEnv = createEnv({
|
|||||||
.optional(),
|
.optional(),
|
||||||
SENTRY_ENVIRONMENT: z.string().optional(),
|
SENTRY_ENVIRONMENT: z.string().optional(),
|
||||||
},
|
},
|
||||||
client: {
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE: ZSurveySchedulingTimeZone.optional().default("Europe/Berlin"),
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_HOUR: ZSurveySchedulingLocalHour.optional().default(0),
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_MINUTE: ZSurveySchedulingLocalMinute.optional().default(0),
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Due to how Next.js bundles environment variables on Edge and Client,
|
* Due to how Next.js bundles environment variables on Edge and Client,
|
||||||
@@ -301,10 +274,6 @@ const parsedEnv = createEnv({
|
|||||||
DEBUG_SHOW_RESET_LINK: process.env.DEBUG_SHOW_RESET_LINK,
|
DEBUG_SHOW_RESET_LINK: process.env.DEBUG_SHOW_RESET_LINK,
|
||||||
AUTH_DEFAULT_TEAM_ID: process.env.AUTH_SSO_DEFAULT_TEAM_ID,
|
AUTH_DEFAULT_TEAM_ID: process.env.AUTH_SSO_DEFAULT_TEAM_ID,
|
||||||
AUTH_SKIP_INVITE_FOR_SSO: process.env.AUTH_SKIP_INVITE_FOR_SSO,
|
AUTH_SKIP_INVITE_FOR_SSO: process.env.AUTH_SKIP_INVITE_FOR_SSO,
|
||||||
BULLMQ_EXTERNAL_WORKER_ENABLED: process.env.BULLMQ_EXTERNAL_WORKER_ENABLED,
|
|
||||||
BULLMQ_WORKER_CONCURRENCY: process.env.BULLMQ_WORKER_CONCURRENCY,
|
|
||||||
BULLMQ_WORKER_COUNT: process.env.BULLMQ_WORKER_COUNT,
|
|
||||||
BULLMQ_WORKER_ENABLED: process.env.BULLMQ_WORKER_ENABLED,
|
|
||||||
E2E_TESTING: process.env.E2E_TESTING,
|
E2E_TESTING: process.env.E2E_TESTING,
|
||||||
EMAIL_AUTH_DISABLED: process.env.EMAIL_AUTH_DISABLED,
|
EMAIL_AUTH_DISABLED: process.env.EMAIL_AUTH_DISABLED,
|
||||||
EMAIL_VERIFICATION_DISABLED: process.env.EMAIL_VERIFICATION_DISABLED,
|
EMAIL_VERIFICATION_DISABLED: process.env.EMAIL_VERIFICATION_DISABLED,
|
||||||
@@ -346,9 +315,6 @@ const parsedEnv = createEnv({
|
|||||||
MAIL_FROM_NAME: process.env.MAIL_FROM_NAME,
|
MAIL_FROM_NAME: process.env.MAIL_FROM_NAME,
|
||||||
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
|
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
|
||||||
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
|
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_HOUR: process.env.NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_HOUR,
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_MINUTE: process.env.NEXT_PUBLIC_SURVEY_SCHEDULING_LOCAL_MINUTE,
|
|
||||||
NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE: process.env.NEXT_PUBLIC_SURVEY_SCHEDULING_TIME_ZONE,
|
|
||||||
SENTRY_DSN: process.env.SENTRY_DSN,
|
SENTRY_DSN: process.env.SENTRY_DSN,
|
||||||
NOTION_OAUTH_CLIENT_ID: process.env.NOTION_OAUTH_CLIENT_ID,
|
NOTION_OAUTH_CLIENT_ID: process.env.NOTION_OAUTH_CLIENT_ID,
|
||||||
NOTION_OAUTH_CLIENT_SECRET: process.env.NOTION_OAUTH_CLIENT_SECRET,
|
NOTION_OAUTH_CLIENT_SECRET: process.env.NOTION_OAUTH_CLIENT_SECRET,
|
||||||
|
|||||||
@@ -213,13 +213,6 @@ export const appLanguages = [
|
|||||||
native: "Svenska",
|
native: "Svenska",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
code: "tr-TR",
|
|
||||||
label: {
|
|
||||||
"en-US": "Turkish",
|
|
||||||
native: "Türkçe",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
code: "zh-Hans-CN",
|
code: "zh-Hans-CN",
|
||||||
label: {
|
label: {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ describe("Integration Service", () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
test("should get all integrations for a workspace", async () => {
|
test("should get all integrations for an environment", async () => {
|
||||||
vi.mocked(prisma.integration.findMany).mockResolvedValue(mockIntegrations);
|
vi.mocked(prisma.integration.findMany).mockResolvedValue(mockIntegrations);
|
||||||
|
|
||||||
const result = await getIntegrations(mockWorkspaceId);
|
const result = await getIntegrations(mockWorkspaceId);
|
||||||
|
|||||||
@@ -1,180 +0,0 @@
|
|||||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
||||||
|
|
||||||
const TEST_TIMEOUT_MS = 15_000;
|
|
||||||
|
|
||||||
describe("jobs runtime config", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.resetModules();
|
|
||||||
});
|
|
||||||
|
|
||||||
test(
|
|
||||||
"defaults to one worker with concurrency one outside tests",
|
|
||||||
async () => {
|
|
||||||
vi.doMock("@/lib/env", () => ({
|
|
||||||
env: {
|
|
||||||
BULLMQ_EXTERNAL_WORKER_ENABLED: undefined,
|
|
||||||
BULLMQ_WORKER_CONCURRENCY: undefined,
|
|
||||||
BULLMQ_WORKER_COUNT: undefined,
|
|
||||||
BULLMQ_WORKER_ENABLED: undefined,
|
|
||||||
NODE_ENV: "development",
|
|
||||||
REDIS_URL: "redis://localhost:6379",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { getJobsQueueingConfig, getJobsWorkerBootstrapConfig } = await import("./config");
|
|
||||||
|
|
||||||
expect(getJobsWorkerBootstrapConfig()).toEqual({
|
|
||||||
enabled: true,
|
|
||||||
runtimeOptions: {
|
|
||||||
concurrency: 1,
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
workerCount: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(getJobsQueueingConfig()).toEqual({
|
|
||||||
enabled: true,
|
|
||||||
redisUrl: "redis://localhost:6379",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
|
||||||
"disables the worker by default in tests",
|
|
||||||
async () => {
|
|
||||||
vi.doMock("@/lib/env", () => ({
|
|
||||||
env: {
|
|
||||||
BULLMQ_EXTERNAL_WORKER_ENABLED: undefined,
|
|
||||||
BULLMQ_WORKER_CONCURRENCY: undefined,
|
|
||||||
BULLMQ_WORKER_COUNT: undefined,
|
|
||||||
BULLMQ_WORKER_ENABLED: undefined,
|
|
||||||
NODE_ENV: "test",
|
|
||||||
REDIS_URL: undefined,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { getJobsQueueingConfig, getJobsWorkerBootstrapConfig } = await import("./config");
|
|
||||||
|
|
||||||
expect(getJobsWorkerBootstrapConfig()).toEqual({
|
|
||||||
enabled: false,
|
|
||||||
runtimeOptions: null,
|
|
||||||
});
|
|
||||||
expect(getJobsQueueingConfig()).toEqual({
|
|
||||||
enabled: false,
|
|
||||||
redisUrl: null,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
|
||||||
"uses explicit worker tuning overrides",
|
|
||||||
async () => {
|
|
||||||
vi.doMock("@/lib/env", () => ({
|
|
||||||
env: {
|
|
||||||
BULLMQ_EXTERNAL_WORKER_ENABLED: undefined,
|
|
||||||
BULLMQ_WORKER_CONCURRENCY: 6,
|
|
||||||
BULLMQ_WORKER_COUNT: 3,
|
|
||||||
BULLMQ_WORKER_ENABLED: "1",
|
|
||||||
NODE_ENV: "production",
|
|
||||||
REDIS_URL: "redis://cache.internal:6379",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { getJobsQueueingConfig, getJobsWorkerBootstrapConfig } = await import("./config");
|
|
||||||
|
|
||||||
expect(getJobsWorkerBootstrapConfig()).toEqual({
|
|
||||||
enabled: true,
|
|
||||||
runtimeOptions: {
|
|
||||||
concurrency: 6,
|
|
||||||
redisUrl: "redis://cache.internal:6379",
|
|
||||||
workerCount: 3,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(getJobsQueueingConfig()).toEqual({
|
|
||||||
enabled: true,
|
|
||||||
redisUrl: "redis://cache.internal:6379",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
|
||||||
"disables queueing when no BullMQ consumer is configured",
|
|
||||||
async () => {
|
|
||||||
vi.doMock("@/lib/env", () => ({
|
|
||||||
env: {
|
|
||||||
BULLMQ_EXTERNAL_WORKER_ENABLED: undefined,
|
|
||||||
BULLMQ_WORKER_CONCURRENCY: 6,
|
|
||||||
BULLMQ_WORKER_COUNT: 3,
|
|
||||||
BULLMQ_WORKER_ENABLED: "0",
|
|
||||||
NODE_ENV: "production",
|
|
||||||
REDIS_URL: "redis://cache.internal:6379",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { getJobsQueueingConfig, getJobsWorkerBootstrapConfig } = await import("./config");
|
|
||||||
|
|
||||||
expect(getJobsWorkerBootstrapConfig()).toEqual({
|
|
||||||
enabled: false,
|
|
||||||
runtimeOptions: null,
|
|
||||||
});
|
|
||||||
expect(getJobsQueueingConfig()).toEqual({
|
|
||||||
enabled: false,
|
|
||||||
redisUrl: null,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
|
||||||
"keeps queueing enabled when an external BullMQ worker is configured",
|
|
||||||
async () => {
|
|
||||||
vi.doMock("@/lib/env", () => ({
|
|
||||||
env: {
|
|
||||||
BULLMQ_EXTERNAL_WORKER_ENABLED: "1",
|
|
||||||
BULLMQ_WORKER_CONCURRENCY: 6,
|
|
||||||
BULLMQ_WORKER_COUNT: 3,
|
|
||||||
BULLMQ_WORKER_ENABLED: "0",
|
|
||||||
NODE_ENV: "production",
|
|
||||||
REDIS_URL: "redis://cache.internal:6379",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { getJobsQueueingConfig, getJobsWorkerBootstrapConfig } = await import("./config");
|
|
||||||
|
|
||||||
expect(getJobsWorkerBootstrapConfig()).toEqual({
|
|
||||||
enabled: false,
|
|
||||||
runtimeOptions: null,
|
|
||||||
});
|
|
||||||
expect(getJobsQueueingConfig()).toEqual({
|
|
||||||
enabled: true,
|
|
||||||
redisUrl: "redis://cache.internal:6379",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
|
||||||
"throws when the worker is enabled without a redis url",
|
|
||||||
async () => {
|
|
||||||
vi.doMock("@/lib/env", () => ({
|
|
||||||
env: {
|
|
||||||
BULLMQ_EXTERNAL_WORKER_ENABLED: undefined,
|
|
||||||
BULLMQ_WORKER_CONCURRENCY: 2,
|
|
||||||
BULLMQ_WORKER_COUNT: 1,
|
|
||||||
BULLMQ_WORKER_ENABLED: "1",
|
|
||||||
NODE_ENV: "production",
|
|
||||||
REDIS_URL: undefined,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { getJobsWorkerBootstrapConfig } = await import("./config");
|
|
||||||
|
|
||||||
expect(() => getJobsWorkerBootstrapConfig()).toThrow(
|
|
||||||
"REDIS_URL is required to start the BullMQ worker"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import "server-only";
|
|
||||||
import type { JobsRuntimeOptions } from "@formbricks/jobs";
|
|
||||||
import { env } from "@/lib/env";
|
|
||||||
|
|
||||||
const DEFAULT_BULLMQ_WORKER_CONCURRENCY = 1;
|
|
||||||
const DEFAULT_BULLMQ_WORKER_COUNT = 1;
|
|
||||||
|
|
||||||
export interface JobsWorkerBootstrapConfig {
|
|
||||||
enabled: boolean;
|
|
||||||
runtimeOptions: JobsRuntimeOptions | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface JobsQueueingConfig {
|
|
||||||
enabled: boolean;
|
|
||||||
redisUrl: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const BULLMQ_WORKER_CONCURRENCY = env.BULLMQ_WORKER_CONCURRENCY ?? DEFAULT_BULLMQ_WORKER_CONCURRENCY;
|
|
||||||
export const BULLMQ_WORKER_COUNT = env.BULLMQ_WORKER_COUNT ?? DEFAULT_BULLMQ_WORKER_COUNT;
|
|
||||||
|
|
||||||
const getBullMqWorkerEnabled = (): boolean => {
|
|
||||||
if (env.BULLMQ_WORKER_ENABLED !== undefined) {
|
|
||||||
return env.BULLMQ_WORKER_ENABLED === "1";
|
|
||||||
}
|
|
||||||
|
|
||||||
return env.NODE_ENV !== "test";
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BULLMQ_WORKER_ENABLED = getBullMqWorkerEnabled();
|
|
||||||
export const BULLMQ_EXTERNAL_WORKER_ENABLED = env.BULLMQ_EXTERNAL_WORKER_ENABLED === "1";
|
|
||||||
|
|
||||||
const hasBullMqConsumer = (): boolean => BULLMQ_WORKER_ENABLED || BULLMQ_EXTERNAL_WORKER_ENABLED;
|
|
||||||
|
|
||||||
export const getJobsQueueingConfig = (): JobsQueueingConfig => {
|
|
||||||
if (!env.REDIS_URL || !hasBullMqConsumer()) {
|
|
||||||
return {
|
|
||||||
enabled: false,
|
|
||||||
redisUrl: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
enabled: true,
|
|
||||||
redisUrl: env.REDIS_URL,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getJobsWorkerBootstrapConfig = (): JobsWorkerBootstrapConfig => {
|
|
||||||
if (!BULLMQ_WORKER_ENABLED) {
|
|
||||||
return {
|
|
||||||
enabled: false,
|
|
||||||
runtimeOptions: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!env.REDIS_URL) {
|
|
||||||
throw new Error("REDIS_URL is required to start the BullMQ worker");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
enabled: true,
|
|
||||||
runtimeOptions: {
|
|
||||||
concurrency: BULLMQ_WORKER_CONCURRENCY,
|
|
||||||
redisUrl: env.REDIS_URL,
|
|
||||||
workerCount: BULLMQ_WORKER_COUNT,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -93,14 +93,6 @@ export const getResponseContact = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapResponsePrismaToResponse = (
|
|
||||||
responsePrisma: Prisma.ResponseGetPayload<{ select: typeof responseSelection }>
|
|
||||||
): TResponse => ({
|
|
||||||
...responsePrisma,
|
|
||||||
contact: getResponseContact(responsePrisma),
|
|
||||||
tags: responsePrisma.tags.map((tagPrisma: { tag: TTag }) => tagPrisma.tag),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const getResponsesByContactId = reactCache(
|
export const getResponsesByContactId = reactCache(
|
||||||
async (contactId: string, page?: number): Promise<TResponseWithQuotas[]> => {
|
async (contactId: string, page?: number): Promise<TResponseWithQuotas[]> => {
|
||||||
validateInputs([contactId, ZId], [page, ZOptionalNumber]);
|
validateInputs([contactId, ZId], [page, ZOptionalNumber]);
|
||||||
@@ -180,7 +172,13 @@ export const getResponseBySingleUseId = reactCache(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapResponsePrismaToResponse(responsePrisma);
|
const response: TResponse = {
|
||||||
|
...responsePrisma,
|
||||||
|
contact: getResponseContact(responsePrisma),
|
||||||
|
tags: responsePrisma.tags.map((tagPrisma: { tag: TTag }) => tagPrisma.tag),
|
||||||
|
};
|
||||||
|
|
||||||
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
throw new DatabaseError(error.message);
|
throw new DatabaseError(error.message);
|
||||||
@@ -206,7 +204,13 @@ export const getResponse = reactCache(async (responseId: string): Promise<TRespo
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapResponsePrismaToResponse(responsePrisma);
|
const response: TResponse = {
|
||||||
|
...responsePrisma,
|
||||||
|
contact: getResponseContact(responsePrisma),
|
||||||
|
tags: responsePrisma.tags.map((tagPrisma: { tag: TTag }) => tagPrisma.tag),
|
||||||
|
};
|
||||||
|
|
||||||
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
throw new DatabaseError(error.message);
|
throw new DatabaseError(error.message);
|
||||||
@@ -216,31 +220,6 @@ export const getResponse = reactCache(async (responseId: string): Promise<TRespo
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getResponseSnapshotForPipeline = async (responseId: string): Promise<TResponse | null> => {
|
|
||||||
validateInputs([responseId, ZId]);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const responsePrisma = await prisma.response.findUnique({
|
|
||||||
where: {
|
|
||||||
id: responseId,
|
|
||||||
},
|
|
||||||
select: responseSelection,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!responsePrisma) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapResponsePrismaToResponse(responsePrisma);
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
|
||||||
throw new DatabaseError(error.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getResponseFilteringValues = reactCache(async (surveyId: string) => {
|
export const getResponseFilteringValues = reactCache(async (surveyId: string) => {
|
||||||
validateInputs([surveyId, ZId]);
|
validateInputs([surveyId, ZId]);
|
||||||
|
|
||||||
|
|||||||
@@ -186,8 +186,6 @@ const baseSurveyProperties = {
|
|||||||
autoClose: 10,
|
autoClose: 10,
|
||||||
delay: 0,
|
delay: 0,
|
||||||
autoComplete: 7,
|
autoComplete: 7,
|
||||||
publishOn: null,
|
|
||||||
closeOn: null,
|
|
||||||
redirectUrl: "https://github.com/formbricks/formbricks",
|
redirectUrl: "https://github.com/formbricks/formbricks",
|
||||||
recontactDays: 3,
|
recontactDays: 3,
|
||||||
displayLimit: 3,
|
displayLimit: 3,
|
||||||
|
|||||||
@@ -1,379 +0,0 @@
|
|||||||
import { prisma } from "@/lib/__mocks__/database";
|
|
||||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
||||||
import { ValidationError } from "@formbricks/types/errors";
|
|
||||||
import { getActionClasses } from "@/lib/actionClass/service";
|
|
||||||
import { getOrganizationByWorkspaceId } from "@/lib/organization/service";
|
|
||||||
import {
|
|
||||||
createSurveyInput,
|
|
||||||
mockActionClass,
|
|
||||||
mockSurveyOutput,
|
|
||||||
updateSurveyInput,
|
|
||||||
} from "./__mock__/survey.mock";
|
|
||||||
import { createSurvey, updateSurveyInternal } from "./service";
|
|
||||||
|
|
||||||
const { mockQueueAuditEventWithoutRequest } = vi.hoisted(() => ({
|
|
||||||
mockQueueAuditEventWithoutRequest: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/lib/actionClass/service", () => ({
|
|
||||||
getActionClasses: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/lib/organization/service", () => ({
|
|
||||||
getOrganizationByWorkspaceId: vi.fn(),
|
|
||||||
subscribeOrganizationMembersToSurveyResponses: vi.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock("@/modules/ee/audit-logs/lib/handler", () => ({
|
|
||||||
queueAuditEventWithoutRequest: mockQueueAuditEventWithoutRequest,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const createSchedulingCandidate = ({
|
|
||||||
id = updateSurveyInput.id,
|
|
||||||
closeOn,
|
|
||||||
publishOn,
|
|
||||||
status,
|
|
||||||
workspaceId = updateSurveyInput.workspaceId,
|
|
||||||
}: {
|
|
||||||
id?: string;
|
|
||||||
closeOn: Date | null;
|
|
||||||
publishOn: Date | null;
|
|
||||||
status: "draft" | "paused" | "inProgress";
|
|
||||||
workspaceId?: string;
|
|
||||||
}) => ({
|
|
||||||
id,
|
|
||||||
closeOn,
|
|
||||||
publishOn,
|
|
||||||
status,
|
|
||||||
workspace: {
|
|
||||||
organizationId: "org123",
|
|
||||||
},
|
|
||||||
workspaceId,
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("survey service scheduling", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.clearAllMocks();
|
|
||||||
vi.useFakeTimers();
|
|
||||||
vi.setSystemTime(new Date("2026-04-17T12:30:00.000Z"));
|
|
||||||
vi.mocked(getActionClasses).mockResolvedValue([mockActionClass] as never);
|
|
||||||
vi.mocked(getOrganizationByWorkspaceId).mockResolvedValue({ id: "org123" } as never);
|
|
||||||
mockQueueAuditEventWithoutRequest.mockResolvedValue(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
vi.useRealTimers();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("manual publish clears publishOn", async () => {
|
|
||||||
const scheduledPublishSelection = new Date(Date.UTC(2026, 3, 20, 12, 0, 0));
|
|
||||||
prisma.survey.findUnique.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
publishOn: scheduledPublishSelection,
|
|
||||||
status: "draft",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.update.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
publishOn: null,
|
|
||||||
status: "inProgress",
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
await updateSurveyInternal(
|
|
||||||
{
|
|
||||||
...updateSurveyInput,
|
|
||||||
publishOn: scheduledPublishSelection,
|
|
||||||
status: "inProgress",
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(prisma.survey.update).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: expect.objectContaining({
|
|
||||||
publishOn: null,
|
|
||||||
status: "inProgress",
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("manual paused status clears closeOn", async () => {
|
|
||||||
const scheduledCloseSelection = new Date(Date.UTC(2026, 3, 20, 12, 0, 0));
|
|
||||||
prisma.survey.findUnique.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
closeOn: scheduledCloseSelection,
|
|
||||||
status: "inProgress",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.update.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
closeOn: null,
|
|
||||||
status: "paused",
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
await updateSurveyInternal(
|
|
||||||
{
|
|
||||||
...updateSurveyInput,
|
|
||||||
closeOn: scheduledCloseSelection,
|
|
||||||
status: "paused",
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(prisma.survey.update).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: expect.objectContaining({
|
|
||||||
closeOn: null,
|
|
||||||
status: "paused",
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("scheduling from draft keeps closeOn when publishOn is set", async () => {
|
|
||||||
const scheduledPublishSelection = new Date(Date.UTC(2026, 3, 20, 12, 0, 0));
|
|
||||||
const scheduledCloseSelection = new Date(Date.UTC(2026, 3, 21, 12, 0, 0));
|
|
||||||
const normalizedPublishOn = new Date("2026-04-19T22:00:00.000Z");
|
|
||||||
const normalizedCloseOn = new Date("2026-04-20T22:00:00.000Z");
|
|
||||||
|
|
||||||
prisma.survey.findUnique.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
closeOn: null,
|
|
||||||
publishOn: null,
|
|
||||||
status: "draft",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.update.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
closeOn: normalizedCloseOn,
|
|
||||||
publishOn: normalizedPublishOn,
|
|
||||||
status: "paused",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.findMany.mockResolvedValueOnce([] as never).mockResolvedValueOnce([] as never);
|
|
||||||
|
|
||||||
await updateSurveyInternal(
|
|
||||||
{
|
|
||||||
...updateSurveyInput,
|
|
||||||
closeOn: scheduledCloseSelection,
|
|
||||||
publishOn: scheduledPublishSelection,
|
|
||||||
status: "paused",
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(prisma.survey.update).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: expect.objectContaining({
|
|
||||||
closeOn: normalizedCloseOn,
|
|
||||||
publishOn: normalizedPublishOn,
|
|
||||||
status: "paused",
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("manual completion clears both scheduling dates", async () => {
|
|
||||||
const scheduledSelection = new Date(Date.UTC(2026, 3, 20, 12, 0, 0));
|
|
||||||
prisma.survey.findUnique.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
closeOn: scheduledSelection,
|
|
||||||
publishOn: scheduledSelection,
|
|
||||||
status: "inProgress",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.update.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
closeOn: null,
|
|
||||||
publishOn: null,
|
|
||||||
status: "completed",
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
await updateSurveyInternal(
|
|
||||||
{
|
|
||||||
...updateSurveyInput,
|
|
||||||
closeOn: scheduledSelection,
|
|
||||||
publishOn: scheduledSelection,
|
|
||||||
status: "completed",
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(prisma.survey.update).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: expect.objectContaining({
|
|
||||||
closeOn: null,
|
|
||||||
publishOn: null,
|
|
||||||
status: "completed",
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("saving a due publish schedule catches up immediately for paused surveys", async () => {
|
|
||||||
const dueSelection = new Date(Date.UTC(2026, 3, 17, 12, 0, 0));
|
|
||||||
const normalizedDuePublishOn = new Date("2026-04-16T22:00:00.000Z");
|
|
||||||
|
|
||||||
prisma.survey.findUnique
|
|
||||||
.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
publishOn: null,
|
|
||||||
status: "paused",
|
|
||||||
} as never)
|
|
||||||
.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
publishOn: null,
|
|
||||||
status: "inProgress",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.update.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
publishOn: normalizedDuePublishOn,
|
|
||||||
status: "paused",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.findMany
|
|
||||||
.mockResolvedValueOnce([
|
|
||||||
createSchedulingCandidate({
|
|
||||||
closeOn: null,
|
|
||||||
publishOn: normalizedDuePublishOn,
|
|
||||||
status: "paused",
|
|
||||||
}),
|
|
||||||
] as never)
|
|
||||||
.mockResolvedValueOnce([] as never);
|
|
||||||
prisma.survey.updateMany.mockResolvedValueOnce({ count: 1 } as never);
|
|
||||||
|
|
||||||
const updatedSurvey = await updateSurveyInternal(
|
|
||||||
{
|
|
||||||
...updateSurveyInput,
|
|
||||||
publishOn: dueSelection,
|
|
||||||
status: "paused",
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(updatedSurvey.status).toBe("inProgress");
|
|
||||||
expect(prisma.survey.update).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: expect.objectContaining({
|
|
||||||
publishOn: normalizedDuePublishOn,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
expect(mockQueueAuditEventWithoutRequest).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("saving a due publish schedule in draft does not auto-publish", async () => {
|
|
||||||
const dueSelection = new Date(Date.UTC(2026, 3, 17, 12, 0, 0));
|
|
||||||
const normalizedDuePublishOn = new Date("2026-04-16T22:00:00.000Z");
|
|
||||||
|
|
||||||
prisma.survey.findUnique.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
publishOn: null,
|
|
||||||
status: "draft",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.update.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
publishOn: normalizedDuePublishOn,
|
|
||||||
status: "draft",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.findMany.mockResolvedValueOnce([] as never).mockResolvedValueOnce([] as never);
|
|
||||||
|
|
||||||
const updatedSurvey = await updateSurveyInternal(
|
|
||||||
{
|
|
||||||
...updateSurveyInput,
|
|
||||||
publishOn: dueSelection,
|
|
||||||
status: "draft",
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(updatedSurvey.status).toBe("draft");
|
|
||||||
expect(prisma.survey.updateMany).not.toHaveBeenCalled();
|
|
||||||
expect(mockQueueAuditEventWithoutRequest).toHaveBeenCalledTimes(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("creating a paused survey with a due publish schedule catches up immediately", async () => {
|
|
||||||
const dueSelection = new Date(Date.UTC(2026, 3, 17, 12, 0, 0));
|
|
||||||
const normalizedDuePublishOn = new Date("2026-04-16T22:00:00.000Z");
|
|
||||||
|
|
||||||
prisma.survey.create.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
publishOn: normalizedDuePublishOn,
|
|
||||||
status: "paused",
|
|
||||||
type: "link",
|
|
||||||
} as never);
|
|
||||||
prisma.survey.findMany
|
|
||||||
.mockResolvedValueOnce([
|
|
||||||
createSchedulingCandidate({
|
|
||||||
closeOn: null,
|
|
||||||
publishOn: normalizedDuePublishOn,
|
|
||||||
status: "paused",
|
|
||||||
}),
|
|
||||||
] as never)
|
|
||||||
.mockResolvedValueOnce([] as never);
|
|
||||||
prisma.survey.updateMany.mockResolvedValueOnce({ count: 1 } as never);
|
|
||||||
prisma.survey.findUnique.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
publishOn: null,
|
|
||||||
status: "inProgress",
|
|
||||||
type: "link",
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
const createdSurvey = await createSurvey(updateSurveyInput.workspaceId, {
|
|
||||||
...createSurveyInput,
|
|
||||||
name: "Scheduled survey",
|
|
||||||
publishOn: dueSelection,
|
|
||||||
status: "paused",
|
|
||||||
type: "link",
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(createdSurvey.status).toBe("inProgress");
|
|
||||||
expect(prisma.survey.create).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: expect.objectContaining({
|
|
||||||
publishOn: normalizedDuePublishOn,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
expect(mockQueueAuditEventWithoutRequest).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("same-day publish and close is rejected", async () => {
|
|
||||||
const sameDaySelection = new Date(Date.UTC(2026, 3, 17, 12, 0, 0));
|
|
||||||
|
|
||||||
prisma.survey.findUnique.mockResolvedValueOnce({
|
|
||||||
...mockSurveyOutput,
|
|
||||||
closeOn: null,
|
|
||||||
publishOn: null,
|
|
||||||
status: "paused",
|
|
||||||
} as never);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
updateSurveyInternal(
|
|
||||||
{
|
|
||||||
...updateSurveyInput,
|
|
||||||
closeOn: sameDaySelection,
|
|
||||||
publishOn: sameDaySelection,
|
|
||||||
status: "paused",
|
|
||||||
},
|
|
||||||
true
|
|
||||||
)
|
|
||||||
).rejects.toThrow(ValidationError);
|
|
||||||
|
|
||||||
expect(prisma.survey.update).not.toHaveBeenCalled();
|
|
||||||
expect(mockQueueAuditEventWithoutRequest).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("creating a survey with the same publish and close date is rejected", async () => {
|
|
||||||
const sameDaySelection = new Date(Date.UTC(2026, 3, 17, 12, 0, 0));
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
createSurvey(updateSurveyInput.workspaceId, {
|
|
||||||
...createSurveyInput,
|
|
||||||
closeOn: sameDaySelection,
|
|
||||||
name: "Scheduled survey",
|
|
||||||
publishOn: sameDaySelection,
|
|
||||||
status: "paused",
|
|
||||||
type: "link",
|
|
||||||
})
|
|
||||||
).rejects.toThrow(ValidationError);
|
|
||||||
|
|
||||||
expect(prisma.survey.create).not.toHaveBeenCalled();
|
|
||||||
expect(mockQueueAuditEventWithoutRequest).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -5,12 +5,7 @@ import { testInputValidation } from "vitestSetup";
|
|||||||
import { PrismaErrorType } from "@formbricks/database/types/error";
|
import { PrismaErrorType } from "@formbricks/database/types/error";
|
||||||
import { TSurveyFollowUp } from "@formbricks/database/types/survey-follow-up";
|
import { TSurveyFollowUp } from "@formbricks/database/types/survey-follow-up";
|
||||||
import { TActionClass } from "@formbricks/types/action-classes";
|
import { TActionClass } from "@formbricks/types/action-classes";
|
||||||
import {
|
import { DatabaseError, InvalidInputError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||||
DatabaseError,
|
|
||||||
InvalidInputError,
|
|
||||||
ResourceNotFoundError,
|
|
||||||
ValidationError,
|
|
||||||
} from "@formbricks/types/errors";
|
|
||||||
import { TSegment } from "@formbricks/types/segment";
|
import { TSegment } from "@formbricks/types/segment";
|
||||||
import { TSurvey, TSurveyCreateInput, TSurveyQuestionTypeEnum } from "@formbricks/types/surveys/types";
|
import { TSurvey, TSurveyCreateInput, TSurveyQuestionTypeEnum } from "@formbricks/types/surveys/types";
|
||||||
import { getActionClasses } from "@/lib/actionClass/service";
|
import { getActionClasses } from "@/lib/actionClass/service";
|
||||||
@@ -19,7 +14,6 @@ import {
|
|||||||
subscribeOrganizationMembersToSurveyResponses,
|
subscribeOrganizationMembersToSurveyResponses,
|
||||||
} from "@/lib/organization/service";
|
} from "@/lib/organization/service";
|
||||||
import { evaluateLogic } from "@/lib/surveyLogic/utils";
|
import { evaluateLogic } from "@/lib/surveyLogic/utils";
|
||||||
import { handleTriggerUpdates } from "@/modules/survey/lib/trigger-updates";
|
|
||||||
import {
|
import {
|
||||||
mockActionClass,
|
mockActionClass,
|
||||||
mockId,
|
mockId,
|
||||||
@@ -36,13 +30,12 @@ import {
|
|||||||
getSurveys,
|
getSurveys,
|
||||||
getSurveysByActionClassId,
|
getSurveysByActionClassId,
|
||||||
getSurveysBySegmentId,
|
getSurveysBySegmentId,
|
||||||
|
handleTriggerUpdates,
|
||||||
loadNewSegmentInSurvey,
|
loadNewSegmentInSurvey,
|
||||||
updateSurvey,
|
updateSurvey,
|
||||||
updateSurveyInternal,
|
updateSurveyInternal,
|
||||||
} from "./service";
|
} from "./service";
|
||||||
|
|
||||||
const SURVEY_SERVICE_TEST_TIMEOUT_MS = 30_000;
|
|
||||||
|
|
||||||
// Mock organization service
|
// Mock organization service
|
||||||
vi.mock("@/lib/organization/service", () => ({
|
vi.mock("@/lib/organization/service", () => ({
|
||||||
getOrganizationByWorkspaceId: vi.fn().mockResolvedValue({
|
getOrganizationByWorkspaceId: vi.fn().mockResolvedValue({
|
||||||
@@ -322,13 +315,7 @@ describe("Tests for updateSurvey", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("Sad Path", () => {
|
describe("Sad Path", () => {
|
||||||
test(
|
testInputValidation(updateSurvey, "123#");
|
||||||
"throws a ValidationError if the inputs are invalid",
|
|
||||||
async () => {
|
|
||||||
await expect(updateSurvey("123#" as unknown as TSurvey)).rejects.toThrow(ValidationError);
|
|
||||||
},
|
|
||||||
SURVEY_SERVICE_TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
|
|
||||||
test("Throws ResourceNotFoundError if the survey does not exist", async () => {
|
test("Throws ResourceNotFoundError if the survey does not exist", async () => {
|
||||||
prisma.survey.findUnique.mockRejectedValueOnce(
|
prisma.survey.findUnique.mockRejectedValueOnce(
|
||||||
@@ -359,12 +346,12 @@ describe("Tests for updateSurvey", () => {
|
|||||||
|
|
||||||
describe("Tests for getSurveyCount service", () => {
|
describe("Tests for getSurveyCount service", () => {
|
||||||
describe("Happy Path", () => {
|
describe("Happy Path", () => {
|
||||||
test("Counts the total number of surveys for a given workspace ID", async () => {
|
test("Counts the total number of surveys for a given environment ID", async () => {
|
||||||
const count = await getSurveyCount(mockId);
|
const count = await getSurveyCount(mockId);
|
||||||
expect(count).toEqual(1);
|
expect(count).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Returns zero count when there are no surveys for a given workspace ID", async () => {
|
test("Returns zero count when there are no surveys for a given environment ID", async () => {
|
||||||
prisma.survey.count.mockResolvedValue(0);
|
prisma.survey.count.mockResolvedValue(0);
|
||||||
const count = await getSurveyCount(mockId);
|
const count = await getSurveyCount(mockId);
|
||||||
expect(count).toEqual(0);
|
expect(count).toEqual(0);
|
||||||
@@ -644,6 +631,7 @@ describe("Tests for createSurvey", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.mocked(getActionClasses).mockResolvedValue(mockActionClasses as TActionClass[]);
|
vi.mocked(getActionClasses).mockResolvedValue(mockActionClasses as TActionClass[]);
|
||||||
|
// environment model removed - no mock needed
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Happy Path", () => {
|
describe("Happy Path", () => {
|
||||||
@@ -1019,25 +1007,21 @@ describe("updateSurveyDraftAction", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("Sad Path", () => {
|
describe("Sad Path", () => {
|
||||||
test(
|
test("should reject publishing survey with incomplete translations", async () => {
|
||||||
"should reject publishing survey with incomplete translations",
|
// Create a draft with missing translations
|
||||||
async () => {
|
const incompleteSurvey = {
|
||||||
// Create a draft with missing translations
|
...updateSurveyInput,
|
||||||
const incompleteSurvey = {
|
questions: [
|
||||||
...updateSurveyInput,
|
{
|
||||||
questions: [
|
id: "q1",
|
||||||
{
|
type: TSurveyQuestionTypeEnum.OpenText,
|
||||||
id: "q1",
|
// Missing headline
|
||||||
type: TSurveyQuestionTypeEnum.OpenText,
|
},
|
||||||
// Missing headline
|
],
|
||||||
},
|
} as unknown as TSurvey;
|
||||||
],
|
|
||||||
} as unknown as TSurvey;
|
|
||||||
|
|
||||||
// Expect validation error (skipValidation = false)
|
// Expect validation error (skipValidation = false)
|
||||||
await expect(updateSurveyInternal(incompleteSurvey, false)).rejects.toThrow();
|
await expect(updateSurveyInternal(incompleteSurvey, false)).rejects.toThrow();
|
||||||
},
|
});
|
||||||
SURVEY_SERVICE_TEST_TIMEOUT_MS
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+118
-134
@@ -1,5 +1,5 @@
|
|||||||
import "server-only";
|
import "server-only";
|
||||||
import { Prisma } from "@prisma/client";
|
import { ActionClass, Prisma } from "@prisma/client";
|
||||||
import { cache as reactCache } from "react";
|
import { cache as reactCache } from "react";
|
||||||
import { prisma } from "@formbricks/database";
|
import { prisma } from "@formbricks/database";
|
||||||
import { logger } from "@formbricks/logger";
|
import { logger } from "@formbricks/logger";
|
||||||
@@ -11,12 +11,7 @@ import {
|
|||||||
getOrganizationByWorkspaceId,
|
getOrganizationByWorkspaceId,
|
||||||
subscribeOrganizationMembersToSurveyResponses,
|
subscribeOrganizationMembersToSurveyResponses,
|
||||||
} from "@/lib/organization/service";
|
} from "@/lib/organization/service";
|
||||||
import { handleTriggerUpdates } from "@/modules/survey/lib/trigger-updates";
|
import { TriggerUpdate } from "@/modules/survey/editor/types/survey-trigger";
|
||||||
import {
|
|
||||||
isSurveySchedulingDue,
|
|
||||||
normalizeSurveyScheduling,
|
|
||||||
reconcileDueSurveySchedules,
|
|
||||||
} from "@/modules/survey/scheduling/lib/survey-scheduling";
|
|
||||||
import { getActionClasses } from "../actionClass/service";
|
import { getActionClasses } from "../actionClass/service";
|
||||||
import { ITEMS_PER_PAGE } from "../constants";
|
import { ITEMS_PER_PAGE } from "../constants";
|
||||||
import { validateInputs } from "../utils/validate";
|
import { validateInputs } from "../utils/validate";
|
||||||
@@ -50,8 +45,6 @@ export const selectSurvey = {
|
|||||||
delay: true,
|
delay: true,
|
||||||
displayPercentage: true,
|
displayPercentage: true,
|
||||||
autoComplete: true,
|
autoComplete: true,
|
||||||
publishOn: true,
|
|
||||||
closeOn: true,
|
|
||||||
isVerifyEmailEnabled: true,
|
isVerifyEmailEnabled: true,
|
||||||
isSingleResponsePerEmailEnabled: true,
|
isSingleResponsePerEmailEnabled: true,
|
||||||
isBackButtonHidden: true,
|
isBackButtonHidden: true,
|
||||||
@@ -114,45 +107,74 @@ export const selectSurvey = {
|
|||||||
slug: true,
|
slug: true,
|
||||||
} satisfies Prisma.SurveySelect;
|
} satisfies Prisma.SurveySelect;
|
||||||
|
|
||||||
const reconcilePersistedSurveySchedulingIfDue = async ({
|
const getTriggerIds = (triggers: TSurvey["triggers"]): string[] | null => {
|
||||||
logSource,
|
if (!triggers) return null;
|
||||||
survey,
|
if (!Array.isArray(triggers)) {
|
||||||
workspaceId,
|
throw new InvalidInputError("Invalid trigger id");
|
||||||
}: {
|
|
||||||
logSource: "survey-create" | "survey-update";
|
|
||||||
survey: TSurvey;
|
|
||||||
workspaceId: string;
|
|
||||||
}): Promise<TSurvey> => {
|
|
||||||
const now = new Date();
|
|
||||||
|
|
||||||
if (!isSurveySchedulingDue(survey, now)) {
|
|
||||||
return survey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const reconciliationResult = await reconcileDueSurveySchedules({
|
return triggers.map((trigger) => {
|
||||||
logContext: {
|
const actionClassId = trigger?.actionClass?.id;
|
||||||
source: logSource,
|
if (typeof actionClassId !== "string") {
|
||||||
surveyId: survey.id,
|
throw new InvalidInputError("Invalid trigger id");
|
||||||
workspaceId,
|
}
|
||||||
},
|
return actionClassId;
|
||||||
now,
|
});
|
||||||
surveyId: survey.id,
|
};
|
||||||
|
|
||||||
|
export const checkTriggersValidity = (triggers: TSurvey["triggers"], actionClasses: ActionClass[]) => {
|
||||||
|
const triggerIds = getTriggerIds(triggers);
|
||||||
|
if (!triggerIds) return;
|
||||||
|
|
||||||
|
// check if all the triggers are valid
|
||||||
|
triggerIds.forEach((triggerId) => {
|
||||||
|
if (!actionClasses.find((actionClass) => actionClass.id === triggerId)) {
|
||||||
|
throw new InvalidInputError("Invalid trigger id");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!reconciliationResult.surveyUpdated) {
|
if (new Set(triggerIds).size !== triggerIds.length) {
|
||||||
return survey;
|
throw new InvalidInputError("Duplicate trigger id");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleTriggerUpdates = (
|
||||||
|
updatedTriggers: TSurvey["triggers"],
|
||||||
|
currentTriggers: TSurvey["triggers"],
|
||||||
|
actionClasses: ActionClass[]
|
||||||
|
) => {
|
||||||
|
const updatedTriggerIds = getTriggerIds(updatedTriggers);
|
||||||
|
if (!updatedTriggerIds) return {};
|
||||||
|
|
||||||
|
checkTriggersValidity(updatedTriggers, actionClasses);
|
||||||
|
|
||||||
|
const currentTriggerIds = getTriggerIds(currentTriggers) ?? [];
|
||||||
|
|
||||||
|
// added triggers are triggers that are not in the current triggers and are there in the new triggers
|
||||||
|
const addedTriggerIds = updatedTriggerIds.filter((triggerId) => !currentTriggerIds.includes(triggerId));
|
||||||
|
|
||||||
|
// deleted triggers are triggers that are not in the new triggers and are there in the current triggers
|
||||||
|
const deletedTriggerIds = currentTriggerIds.filter((triggerId) => !updatedTriggerIds.includes(triggerId));
|
||||||
|
|
||||||
|
// Construct the triggers update object
|
||||||
|
const triggersUpdate: TriggerUpdate = {};
|
||||||
|
|
||||||
|
if (addedTriggerIds.length > 0) {
|
||||||
|
triggersUpdate.create = addedTriggerIds.map((triggerId) => ({
|
||||||
|
actionClassId: triggerId,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const reconciledSurvey = await prisma.survey.findUnique({
|
if (deletedTriggerIds.length > 0) {
|
||||||
where: { id: survey.id },
|
// disconnect the public triggers from the survey
|
||||||
select: selectSurvey,
|
triggersUpdate.deleteMany = {
|
||||||
});
|
actionClassId: {
|
||||||
|
in: deletedTriggerIds,
|
||||||
if (!reconciledSurvey) {
|
},
|
||||||
throw new ResourceNotFoundError("Survey", survey.id);
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return transformPrismaSurvey<TSurvey>(reconciledSurvey);
|
return triggersUpdate;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSurvey = reactCache(async (surveyId: string): Promise<TSurvey | null> => {
|
export const getSurvey = reactCache(async (surveyId: string): Promise<TSurvey | null> => {
|
||||||
@@ -515,16 +537,12 @@ export const updateSurveyInternal = async (
|
|||||||
data.blocks = stripIsDraftFromBlocks(updatedSurvey.blocks);
|
data.blocks = stripIsDraftFromBlocks(updatedSurvey.blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedScheduling = normalizeSurveyScheduling({
|
const organization = await getOrganizationByWorkspaceId(updatedSurvey.workspaceId);
|
||||||
currentStatus: currentSurvey.status,
|
if (!organization) {
|
||||||
closeOn: surveyData.closeOn,
|
throw new ResourceNotFoundError("Organization", null);
|
||||||
publishOn: surveyData.publishOn,
|
}
|
||||||
status: updatedSurvey.status,
|
|
||||||
});
|
|
||||||
|
|
||||||
surveyData.updatedAt = new Date();
|
surveyData.updatedAt = new Date();
|
||||||
surveyData.publishOn = normalizedScheduling.publishOn;
|
|
||||||
surveyData.closeOn = normalizedScheduling.closeOn;
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
...surveyData,
|
...surveyData,
|
||||||
@@ -533,17 +551,28 @@ export const updateSurveyInternal = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
delete data.createdBy;
|
delete data.createdBy;
|
||||||
const persistedSurvey = await prisma.survey.update({
|
const prismaSurvey = await prisma.survey.update({
|
||||||
where: { id: surveyId },
|
where: { id: surveyId },
|
||||||
data,
|
data,
|
||||||
select: selectSurvey,
|
select: selectSurvey,
|
||||||
});
|
});
|
||||||
|
|
||||||
return await reconcilePersistedSurveySchedulingIfDue({
|
let surveySegment: TSegment | null = null;
|
||||||
logSource: "survey-update",
|
if (prismaSurvey.segment) {
|
||||||
survey: transformPrismaSurvey<TSurvey>(persistedSurvey),
|
surveySegment = {
|
||||||
workspaceId: updatedSurvey.workspaceId,
|
...prismaSurvey.segment,
|
||||||
});
|
surveys: prismaSurvey.segment.surveys.map((survey) => survey.id),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const modifiedSurvey: TSurvey = {
|
||||||
|
...prismaSurvey, // Properties from prismaSurvey
|
||||||
|
displayPercentage: Number(prismaSurvey.displayPercentage) || null,
|
||||||
|
segment: surveySegment,
|
||||||
|
customHeadScriptsMode: prismaSurvey.customHeadScriptsMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
return modifiedSurvey;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error, "Error updating survey");
|
logger.error(error, "Error updating survey");
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
@@ -563,63 +592,6 @@ export const updateSurveyDraft = async (updatedSurvey: TSurvey): Promise<TSurvey
|
|||||||
return updateSurveyInternal(updatedSurvey, true);
|
return updateSurveyInternal(updatedSurvey, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const attachSurveyCreatorToCreateData = (
|
|
||||||
data: Omit<Prisma.SurveyCreateInput, "workspace">,
|
|
||||||
createdBy?: string | null
|
|
||||||
): Omit<Prisma.SurveyCreateInput, "workspace"> => {
|
|
||||||
if (!createdBy) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
creator: {
|
|
||||||
connect: {
|
|
||||||
id: createdBy,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const attachSurveyFollowUpsToCreateData = (
|
|
||||||
data: Omit<Prisma.SurveyCreateInput, "workspace">,
|
|
||||||
followUps?: TSurveyCreateInput["followUps"]
|
|
||||||
): Omit<Prisma.SurveyCreateInput, "workspace"> => {
|
|
||||||
const { followUps: _, ...dataWithoutFollowUps } = data;
|
|
||||||
|
|
||||||
if (!followUps?.length) {
|
|
||||||
return dataWithoutFollowUps;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...dataWithoutFollowUps,
|
|
||||||
followUps: {
|
|
||||||
create: followUps.map((followUp) => ({
|
|
||||||
name: followUp.name,
|
|
||||||
trigger: followUp.trigger,
|
|
||||||
action: followUp.action,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateSurveyCreateDataMedia = (
|
|
||||||
data: Omit<Prisma.SurveyCreateInput, "workspace">
|
|
||||||
): Omit<Prisma.SurveyCreateInput, "workspace"> => {
|
|
||||||
if (data.questions) {
|
|
||||||
checkForInvalidImagesInQuestions(data.questions);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.blocks?.length) {
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
blocks: validateMediaAndPrepareBlocks(data.blocks),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createSurvey = async (workspaceId: string, surveyBody: TSurveyCreateInput): Promise<TSurvey> => {
|
export const createSurvey = async (workspaceId: string, surveyBody: TSurveyCreateInput): Promise<TSurvey> => {
|
||||||
const [parsedWorkspaceId, parsedSurveyBody] = validateInputs(
|
const [parsedWorkspaceId, parsedSurveyBody] = validateInputs(
|
||||||
[workspaceId, ZId],
|
[workspaceId, ZId],
|
||||||
@@ -628,37 +600,55 @@ export const createSurvey = async (workspaceId: string, surveyBody: TSurveyCreat
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { createdBy, languages, ...restSurveyBody } = parsedSurveyBody;
|
const { createdBy, languages, ...restSurveyBody } = parsedSurveyBody;
|
||||||
const normalizedCloseOn = restSurveyBody.closeOn instanceof Date ? restSurveyBody.closeOn : null;
|
|
||||||
const normalizedPublishOn = restSurveyBody.publishOn instanceof Date ? restSurveyBody.publishOn : null;
|
|
||||||
|
|
||||||
const actionClasses = await getActionClasses(parsedWorkspaceId);
|
const actionClasses = await getActionClasses(parsedWorkspaceId);
|
||||||
|
|
||||||
const baseData: Omit<Prisma.SurveyCreateInput, "workspace"> = {
|
let data: Omit<Prisma.SurveyCreateInput, "workspace"> = {
|
||||||
...restSurveyBody,
|
...restSurveyBody,
|
||||||
...normalizeSurveyScheduling({
|
|
||||||
closeOn: normalizedCloseOn,
|
|
||||||
publishOn: normalizedPublishOn,
|
|
||||||
status: restSurveyBody.status ?? "draft",
|
|
||||||
}),
|
|
||||||
// @ts-expect-error - languages would be undefined in case of empty array
|
// @ts-expect-error - languages would be undefined in case of empty array
|
||||||
languages: languages?.length ? languages : undefined,
|
languages: languages?.length ? languages : undefined,
|
||||||
triggers: restSurveyBody.triggers
|
triggers: restSurveyBody.triggers
|
||||||
? handleTriggerUpdates(restSurveyBody.triggers, [], actionClasses)
|
? // @ts-expect-error - triggers' createdAt and updatedAt are actually dates
|
||||||
|
handleTriggerUpdates(restSurveyBody.triggers, [], actionClasses)
|
||||||
: undefined,
|
: undefined,
|
||||||
attributeFilters: undefined,
|
attributeFilters: undefined,
|
||||||
};
|
};
|
||||||
const data = validateSurveyCreateDataMedia(
|
|
||||||
attachSurveyFollowUpsToCreateData(
|
if (createdBy) {
|
||||||
attachSurveyCreatorToCreateData(baseData, createdBy),
|
data.creator = {
|
||||||
restSurveyBody.followUps
|
connect: {
|
||||||
)
|
id: createdBy,
|
||||||
);
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const organization = await getOrganizationByWorkspaceId(parsedWorkspaceId);
|
const organization = await getOrganizationByWorkspaceId(parsedWorkspaceId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new ResourceNotFoundError("Organization", null);
|
throw new ResourceNotFoundError("Organization", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Survey follow-ups
|
||||||
|
if (restSurveyBody.followUps?.length) {
|
||||||
|
data.followUps = {
|
||||||
|
create: restSurveyBody.followUps.map((followUp) => ({
|
||||||
|
name: followUp.name,
|
||||||
|
trigger: followUp.trigger,
|
||||||
|
action: followUp.action,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
delete data.followUps;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.questions) {
|
||||||
|
checkForInvalidImagesInQuestions(data.questions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and prepare blocks for persistence
|
||||||
|
if (data.blocks && data.blocks.length > 0) {
|
||||||
|
data.blocks = validateMediaAndPrepareBlocks(data.blocks);
|
||||||
|
}
|
||||||
|
|
||||||
const survey = await prisma.survey.create({
|
const survey = await prisma.survey.create({
|
||||||
data: {
|
data: {
|
||||||
...data,
|
...data,
|
||||||
@@ -712,17 +702,11 @@ export const createSurvey = async (workspaceId: string, surveyBody: TSurveyCreat
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const reconciledSurvey = await reconcilePersistedSurveySchedulingIfDue({
|
|
||||||
logSource: "survey-create",
|
|
||||||
survey: transformedSurvey,
|
|
||||||
workspaceId: parsedWorkspaceId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (createdBy) {
|
if (createdBy) {
|
||||||
await subscribeOrganizationMembersToSurveyResponses(reconciledSurvey.id, createdBy, organization.id);
|
await subscribeOrganizationMembersToSurveyResponses(survey.id, createdBy, organization.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return reconciledSurvey;
|
return transformedSurvey;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
logger.error(error, "Error creating survey");
|
logger.error(error, "Error creating survey");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { type Locale, formatDistance } from "date-fns";
|
import { type Locale, formatDistance } from "date-fns";
|
||||||
import { de, enUS, es, fr, hu, ja, nl, pt, ptBR, ro, ru, sv, tr, zhCN, zhTW } from "date-fns/locale";
|
import { de, enUS, es, fr, hu, ja, nl, pt, ptBR, ro, ru, sv, zhCN, zhTW } from "date-fns/locale";
|
||||||
import { TUserLocale } from "@formbricks/types/user";
|
import { TUserLocale } from "@formbricks/types/user";
|
||||||
import { formatDateForDisplay } from "./utils/datetime";
|
import { formatDateForDisplay } from "./utils/datetime";
|
||||||
|
|
||||||
@@ -17,7 +17,6 @@ const TIME_SINCE_LOCALES: Record<TUserLocale, Locale> = {
|
|||||||
"ro-RO": ro,
|
"ro-RO": ro,
|
||||||
"ru-RU": ru,
|
"ru-RU": ru,
|
||||||
"sv-SE": sv,
|
"sv-SE": sv,
|
||||||
"tr-TR": tr,
|
|
||||||
"zh-Hans-CN": zhCN,
|
"zh-Hans-CN": zhCN,
|
||||||
"zh-Hant-TW": zhTW,
|
"zh-Hant-TW": zhTW,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const findRecallInfoById = (text: string, id: string): string | null => {
|
|||||||
return match ? match[0] : null;
|
return match ? match[0] : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRecallItemLabel = <T extends TSurvey>(
|
const getRecallItemLabel = <T extends TSurvey>(
|
||||||
recallItemId: string,
|
recallItemId: string,
|
||||||
survey: T,
|
survey: T,
|
||||||
languageCode: string
|
languageCode: string
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, test } from "vitest";
|
import { describe, expect, test } from "vitest";
|
||||||
import { isSafeIdentifier, toSafeIdentifier } from "./safe-identifier";
|
import { isSafeIdentifier } from "./safe-identifier";
|
||||||
|
|
||||||
describe("safe-identifier", () => {
|
describe("safe-identifier", () => {
|
||||||
describe("isSafeIdentifier", () => {
|
describe("isSafeIdentifier", () => {
|
||||||
@@ -32,23 +32,4 @@ describe("safe-identifier", () => {
|
|||||||
expect(isSafeIdentifier("")).toBe(false);
|
expect(isSafeIdentifier("")).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("toSafeIdentifier", () => {
|
|
||||||
test("normalizes free-form labels into safe identifiers", () => {
|
|
||||||
expect(toSafeIdentifier("Date of Birth")).toBe("date_of_birth");
|
|
||||||
expect(toSafeIdentifier("Customer-ID")).toBe("customer_id");
|
|
||||||
expect(toSafeIdentifier(" Preferred Language ")).toBe("preferred_language");
|
|
||||||
expect(toSafeIdentifier("city__name")).toBe("city_name");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("strips invalid leading characters until first lowercase letter", () => {
|
|
||||||
expect(toSafeIdentifier("123 Date")).toBe("date");
|
|
||||||
expect(toSafeIdentifier("__name")).toBe("name");
|
|
||||||
expect(toSafeIdentifier("99")).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("keeps already safe identifiers unchanged", () => {
|
|
||||||
expect(toSafeIdentifier("country_code")).toBe("country_code");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,44 +12,6 @@ export const isSafeIdentifier = (value: string): boolean => {
|
|||||||
return /^[a-z0-9_]+$/.test(value);
|
return /^[a-z0-9_]+$/.test(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a free-form string to a safe identifier candidate.
|
|
||||||
* The output only contains lowercase letters, numbers, and underscores.
|
|
||||||
* It also ensures the identifier starts with a lowercase letter by stripping invalid leading chars.
|
|
||||||
*/
|
|
||||||
export const toSafeIdentifier = (value: string): string => {
|
|
||||||
const normalized = value.trim().toLowerCase();
|
|
||||||
let safeIdentifier = "";
|
|
||||||
let shouldInsertUnderscore = false;
|
|
||||||
|
|
||||||
for (const char of normalized) {
|
|
||||||
const isLowercaseLetter = char >= "a" && char <= "z";
|
|
||||||
const isDigit = char >= "0" && char <= "9";
|
|
||||||
|
|
||||||
if (isLowercaseLetter || isDigit) {
|
|
||||||
if (shouldInsertUnderscore && safeIdentifier.length > 0) {
|
|
||||||
safeIdentifier += "_";
|
|
||||||
}
|
|
||||||
safeIdentifier += char;
|
|
||||||
shouldInsertUnderscore = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (safeIdentifier.length > 0) {
|
|
||||||
shouldInsertUnderscore = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < safeIdentifier.length; i++) {
|
|
||||||
const char = safeIdentifier[i];
|
|
||||||
if (char >= "a" && char <= "z") {
|
|
||||||
return safeIdentifier.slice(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a snake_case string to Title Case for display as a label.
|
* Converts a snake_case string to Title Case for display as a label.
|
||||||
* Example: "job_description" -> "Job Description"
|
* Example: "job_description" -> "Job Description"
|
||||||
|
|||||||
+103
-137
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Workspace wechseln",
|
"change_workspace": "Workspace wechseln",
|
||||||
"chart": "Diagramm",
|
"chart": "Diagramm",
|
||||||
"charts": "Diagramme",
|
"charts": "Diagramme",
|
||||||
"choice_n": "Auswahl {{n}}",
|
|
||||||
"choices": "Entscheidungen",
|
"choices": "Entscheidungen",
|
||||||
"choose_organization": "Organisation auswählen",
|
"choose_organization": "Organisation auswählen",
|
||||||
"choose_workspace": "Projekt auswählen",
|
"choose_workspace": "Projekt auswählen",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"code": "Code",
|
"code": "Code",
|
||||||
"collapse_rows": "Zeilen einklappen",
|
"collapse_rows": "Zeilen einklappen",
|
||||||
"column_n": "Spalte {{n}}",
|
|
||||||
"completed": "Abgeschlossen",
|
"completed": "Abgeschlossen",
|
||||||
"configuration": "Konfigurieren",
|
"configuration": "Konfiguration",
|
||||||
"confirm": "Bestätigen",
|
"confirm": "Bestätigen",
|
||||||
"connect": "Verbinden",
|
"connect": "Verbinden",
|
||||||
"connect_formbricks": "Formbricks verbinden",
|
"connect_formbricks": "Formbricks verbinden",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Abschlusskarte",
|
"ending_card": "Abschlusskarte",
|
||||||
"enter_url": "URL eingeben",
|
"enter_url": "URL eingeben",
|
||||||
"enterprise_license": "Enterprise-Lizenz",
|
"enterprise_license": "Enterprise-Lizenz",
|
||||||
|
"environment": "Umgebung",
|
||||||
"error": "Fehler",
|
"error": "Fehler",
|
||||||
"error_component_description": "Diese Ressource existiert nicht oder du hast nicht die erforderlichen Rechte, um darauf zuzugreifen.",
|
"error_component_description": "Diese Ressource existiert nicht oder du hast nicht die erforderlichen Rechte, um darauf zuzugreifen.",
|
||||||
"error_component_title": "Fehler beim Laden der Ressourcen",
|
"error_component_title": "Fehler beim Laden der Ressourcen",
|
||||||
@@ -239,11 +238,10 @@
|
|||||||
"error_rate_limit_description": "Maximale Anzahl an Anfragen erreicht. Bitte versuche es später erneut.",
|
"error_rate_limit_description": "Maximale Anzahl an Anfragen erreicht. Bitte versuche es später erneut.",
|
||||||
"error_rate_limit_title": "Rate-Limit überschritten",
|
"error_rate_limit_title": "Rate-Limit überschritten",
|
||||||
"expand_rows": "Zeilen erweitern",
|
"expand_rows": "Zeilen erweitern",
|
||||||
"failed_to_copy_to_clipboard": "Fehler beim Kopieren in die Zwischenablage",
|
"failed_to_copy_to_clipboard": "Kopieren in die Zwischenablage fehlgeschlagen",
|
||||||
"failed_to_load_organizations": "Fehler beim Laden der Organisationen",
|
"failed_to_load_organizations": "Laden der Organisationen fehlgeschlagen",
|
||||||
"failed_to_load_workspaces": "Projekte konnten nicht geladen werden",
|
"failed_to_load_workspaces": "Laden der Arbeitsbereiche fehlgeschlagen",
|
||||||
"failed_to_parse_csv": "CSV-Analyse fehlgeschlagen",
|
"failed_to_parse_csv": "CSV-Analyse fehlgeschlagen",
|
||||||
"field_placeholder": "{{field}}-Platzhalter",
|
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"finish": "Fertig",
|
"finish": "Fertig",
|
||||||
"first_name": "Vorname",
|
"first_name": "Vorname",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Generieren",
|
"generate": "Generieren",
|
||||||
"go_back": "Geh zurück",
|
"go_back": "Geh zurück",
|
||||||
"go_to_dashboard": "Zum Dashboard gehen",
|
"go_to_dashboard": "Zum Dashboard gehen",
|
||||||
"headline": "Überschrift",
|
|
||||||
"hidden": "Versteckt",
|
"hidden": "Versteckt",
|
||||||
"hidden_field": "Verstecktes Feld",
|
"hidden_field": "Verstecktes Feld",
|
||||||
"hidden_fields": "Versteckte Felder",
|
"hidden_fields": "Versteckte Felder",
|
||||||
"hide": "Ausblenden",
|
"hide": "Ausblenden",
|
||||||
"hide_column": "Spalte ausblenden",
|
"hide_column": "Spalte ausblenden",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "Bild",
|
"image": "Bild",
|
||||||
"images": "Bilder",
|
"images": "Bilder",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "Weitere Optionen",
|
"more_options": "Weitere Optionen",
|
||||||
"move_down": "Nach unten bewegen",
|
"move_down": "Nach unten bewegen",
|
||||||
"move_up": "Nach oben bewegen",
|
"move_up": "Nach oben bewegen",
|
||||||
|
"multiple_languages": "Mehrsprachigkeit",
|
||||||
"my_product": "mein Produkt",
|
"my_product": "mein Produkt",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"new": "Neu",
|
"new": "Neu",
|
||||||
@@ -326,8 +323,7 @@
|
|||||||
"no_result_found": "Kein Ergebnis gefunden",
|
"no_result_found": "Kein Ergebnis gefunden",
|
||||||
"no_results": "Keine Ergebnisse",
|
"no_results": "Keine Ergebnisse",
|
||||||
"no_surveys_found": "Keine Umfragen gefunden.",
|
"no_surveys_found": "Keine Umfragen gefunden.",
|
||||||
"no_text_found": "Kein Text gefunden",
|
"none_of_the_above": "Nichts davon",
|
||||||
"none_of_the_above": "Keine der oben genannten Optionen",
|
|
||||||
"not_authenticated": "Du bist nicht authentifiziert, um diese Aktion durchzuführen.",
|
"not_authenticated": "Du bist nicht authentifiziert, um diese Aktion durchzuführen.",
|
||||||
"not_authorized": "Nicht autorisiert",
|
"not_authorized": "Nicht autorisiert",
|
||||||
"not_connected": "Nicht verbunden",
|
"not_connected": "Nicht verbunden",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Organisationseinstellungen",
|
"organization_settings": "Organisationseinstellungen",
|
||||||
"other": "Sonstiges",
|
"other": "Sonstiges",
|
||||||
"other_filters": "Weitere Filter",
|
"other_filters": "Weitere Filter",
|
||||||
"other_placeholder": "Sonstiger Platzhalter",
|
"others": "Andere",
|
||||||
"overlay_color": "Overlay-Farbe",
|
"overlay_color": "Overlay-Farbe",
|
||||||
"overview": "Übersicht",
|
"overview": "Übersicht",
|
||||||
"password": "Passwort",
|
"password": "Passwort",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Bitte upgrade deinen Plan",
|
"please_upgrade_your_plan": "Bitte upgrade deinen Plan",
|
||||||
"powered_by_formbricks": "Powered by Formbricks",
|
"powered_by_formbricks": "Powered by Formbricks",
|
||||||
"preview": "Vorschau",
|
"preview": "Vorschau",
|
||||||
"privacy": "Datenschutz",
|
"preview_survey": "Umfrage-Vorschau",
|
||||||
|
"privacy": "Datenschutzerklärung",
|
||||||
"product_manager": "Produktmanager",
|
"product_manager": "Produktmanager",
|
||||||
|
"production": "Produktion",
|
||||||
"profile": "Profil",
|
"profile": "Profil",
|
||||||
"profile_id": "Profil-ID",
|
"profile_id": "Profil-ID",
|
||||||
"progress": "Fortschritt",
|
"progress": "Fortschritt",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Neu starten",
|
"restart": "Neu starten",
|
||||||
"retry": "Erneut versuchen",
|
"retry": "Erneut versuchen",
|
||||||
"role": "Rolle",
|
"role": "Rolle",
|
||||||
"row_n": "Zeile {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Vertrieb",
|
"sales": "Vertrieb",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"save_as_draft": "Als Entwurf speichern",
|
"save_as_draft": "Als Entwurf speichern",
|
||||||
"save_changes": "Änderungen speichern",
|
"save_changes": "Änderungen speichern",
|
||||||
"save_without_scheduling": "Ohne Planung speichern",
|
|
||||||
"saving": "Speichert",
|
"saving": "Speichert",
|
||||||
"scheduled": "Geplant",
|
|
||||||
"search": "Suchen",
|
"search": "Suchen",
|
||||||
"search_charts": "Diagramme durchsuchen...",
|
"search_charts": "Diagramme durchsuchen...",
|
||||||
"security": "Sicherheit",
|
"security": "Sicherheit",
|
||||||
@@ -438,8 +433,7 @@
|
|||||||
"storage_not_configured": "Dateispeicher nicht eingerichtet, Uploads werden wahrscheinlich fehlschlagen",
|
"storage_not_configured": "Dateispeicher nicht eingerichtet, Uploads werden wahrscheinlich fehlschlagen",
|
||||||
"string": "Text",
|
"string": "Text",
|
||||||
"styling": "Styling",
|
"styling": "Styling",
|
||||||
"subheader": "Unterüberschrift",
|
"submit": "Absenden",
|
||||||
"submit": "Abschicken",
|
|
||||||
"summary": "Zusammenfassung",
|
"summary": "Zusammenfassung",
|
||||||
"survey": "Umfrage",
|
"survey": "Umfrage",
|
||||||
"survey_completed": "Umfrage abgeschlossen.",
|
"survey_completed": "Umfrage abgeschlossen.",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Umfragesprachen",
|
"survey_languages": "Umfragesprachen",
|
||||||
"survey_live": "Umfrage live",
|
"survey_live": "Umfrage live",
|
||||||
"survey_paused": "Umfrage pausiert.",
|
"survey_paused": "Umfrage pausiert.",
|
||||||
"survey_scheduled": "Umfrage geplant.",
|
|
||||||
"survey_type": "Umfragetyp",
|
"survey_type": "Umfragetyp",
|
||||||
"surveys": "Umfragen",
|
"surveys": "Umfragen",
|
||||||
"table_items_deleted_successfully": "{type}s erfolgreich gelöscht",
|
"table_items_deleted_successfully": "{type}s erfolgreich gelöscht",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Projekte",
|
"workspaces": "Projekte",
|
||||||
"years": "Jahre",
|
"years": "Jahre",
|
||||||
"yes": "Ja",
|
"yes": "Ja",
|
||||||
|
"you": "Du",
|
||||||
"you_are_downgraded_to_the_community_edition": "Du wurdest auf die Community Edition herabgestuft.",
|
"you_are_downgraded_to_the_community_edition": "Du wurdest auf die Community Edition herabgestuft.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "Du bist nicht berechtigt, diese Aktion durchzuführen.",
|
"you_are_not_authorized_to_perform_this_action": "Du bist nicht berechtigt, diese Aktion durchzuführen.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Du hast dein Limit von {workspaceLimit} Workspaces erreicht.",
|
"you_have_reached_your_limit_of_workspace_limit": "Du hast dein Limit von {workspaceLimit} Workspaces erreicht.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "Dein Formbricks-Team",
|
"email_footer_text_2": "Dein Formbricks-Team",
|
||||||
"email_template_text_1": "Diese E-Mail wurde über Formbricks versendet.",
|
"email_template_text_1": "Diese E-Mail wurde über Formbricks versendet.",
|
||||||
"embed_survey_preview_email_didnt_request": "Nicht angefordert?",
|
"embed_survey_preview_email_didnt_request": "Nicht angefordert?",
|
||||||
|
"embed_survey_preview_email_environment_id": "Umgebungs-ID",
|
||||||
"embed_survey_preview_email_fight_spam": "Hilf uns, Spam zu bekämpfen und leite diese E-Mail an hola@formbricks.com weiter",
|
"embed_survey_preview_email_fight_spam": "Hilf uns, Spam zu bekämpfen und leite diese E-Mail an hola@formbricks.com weiter",
|
||||||
"embed_survey_preview_email_heading": "E-Mail-Einbettung Vorschau",
|
"embed_survey_preview_email_heading": "E-Mail-Einbettung Vorschau",
|
||||||
"embed_survey_preview_email_subject": "Formbricks E-Mail-Umfrage Vorschau",
|
"embed_survey_preview_email_subject": "Formbricks E-Mail-Umfrage Vorschau",
|
||||||
"embed_survey_preview_email_text": "So sieht das Code-Snippet eingebettet in einer E-Mail aus:",
|
"embed_survey_preview_email_text": "So sieht das Code-Snippet eingebettet in einer E-Mail aus:",
|
||||||
"embed_survey_preview_email_workspace_id": "Workspace-ID",
|
|
||||||
"forgot_password_email_change_password": "Passwort ändern",
|
"forgot_password_email_change_password": "Passwort ändern",
|
||||||
"forgot_password_email_did_not_request": "Falls Du das nicht angefordert hast, kannst Du diese E-Mail einfach ignorieren.",
|
"forgot_password_email_did_not_request": "Falls Du das nicht angefordert hast, kannst Du diese E-Mail einfach ignorieren.",
|
||||||
"forgot_password_email_heading": "Passwort ändern",
|
"forgot_password_email_heading": "Passwort ändern",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Fragenvorschau",
|
"question_preview": "Fragenvorschau",
|
||||||
"response_already_received": "Wir haben bereits eine Antwort für diese E-Mail-Adresse erhalten.",
|
"response_already_received": "Wir haben bereits eine Antwort für diese E-Mail-Adresse erhalten.",
|
||||||
"response_submitted": "Es existiert bereits eine Antwort, die mit dieser Umfrage und diesem Kontakt verknüpft ist",
|
"response_submitted": "Es existiert bereits eine Antwort, die mit dieser Umfrage und diesem Kontakt verknüpft ist",
|
||||||
"scheduled": "Diese Umfrage ist geplant und wird bald live gehen.",
|
|
||||||
"survey_already_answered_heading": "Die Umfrage wurde bereits beantwortet.",
|
"survey_already_answered_heading": "Die Umfrage wurde bereits beantwortet.",
|
||||||
"survey_already_answered_subheading": "Du kannst diesen Link nur einmal verwenden.",
|
"survey_already_answered_subheading": "Du kannst diesen Link nur einmal verwenden.",
|
||||||
"survey_sent_to": "Umfrage gesendet an {email}",
|
"survey_sent_to": "Umfrage gesendet an {email}",
|
||||||
@@ -769,15 +762,11 @@
|
|||||||
"career_development_survey_question_6_choice_1": "Einzelner Mitarbeiter",
|
"career_development_survey_question_6_choice_1": "Einzelner Mitarbeiter",
|
||||||
"career_development_survey_question_6_choice_2": "Manager",
|
"career_development_survey_question_6_choice_2": "Manager",
|
||||||
"career_development_survey_question_6_choice_3": "Senior Manager",
|
"career_development_survey_question_6_choice_3": "Senior Manager",
|
||||||
"career_development_survey_question_6_choice_4": "Vizepräsident",
|
"career_development_survey_question_6_choice_4": "Vice President",
|
||||||
"career_development_survey_question_6_choice_5": "Geschäftsführung",
|
"career_development_survey_question_6_choice_5": "Führungskraft",
|
||||||
"career_development_survey_question_6_choice_6": "Andere",
|
"career_development_survey_question_6_choice_6": "Sonstiges",
|
||||||
"career_development_survey_question_6_headline": "Was beschreibt deine aktuelle Position am besten?",
|
"career_development_survey_question_6_headline": "Welche der folgenden Optionen beschreibt deine aktuelle Jobstufe am besten?",
|
||||||
"career_development_survey_question_6_subheader": "Bitte wähle eine der folgenden Optionen",
|
"career_development_survey_question_6_subheader": "Bitte wähle eine der folgenden Optionen:",
|
||||||
"ces": "Kundenaufwand (CES)",
|
|
||||||
"ces_description": "Customer Effort Score messen (1-5 oder 1-7)",
|
|
||||||
"ces_lower_label": "Sehr schwierig",
|
|
||||||
"ces_upper_label": "Sehr einfach",
|
|
||||||
"cess_survey_name": "CES-Umfrage",
|
"cess_survey_name": "CES-Umfrage",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] macht es mir leicht, [ZIEL HINZUFÜGEN]",
|
"cess_survey_question_1_headline": "$[workspaceName] macht es mir leicht, [ZIEL HINZUFÜGEN]",
|
||||||
"cess_survey_question_1_lower_label": "Stimme überhaupt nicht zu",
|
"cess_survey_question_1_lower_label": "Stimme überhaupt nicht zu",
|
||||||
@@ -837,13 +826,11 @@
|
|||||||
"collect_feedback_question_6_headline": "Wie hast du von uns erfahren?",
|
"collect_feedback_question_6_headline": "Wie hast du von uns erfahren?",
|
||||||
"collect_feedback_question_7_headline": "Zum Abschluss würden wir gerne auf dein Feedback antworten. Bitte teile deine E-Mail-Adresse:",
|
"collect_feedback_question_7_headline": "Zum Abschluss würden wir gerne auf dein Feedback antworten. Bitte teile deine E-Mail-Adresse:",
|
||||||
"collect_feedback_question_7_placeholder": "beispiel@email.com",
|
"collect_feedback_question_7_placeholder": "beispiel@email.com",
|
||||||
"consent": "Zustimmung",
|
"consent": "Einwilligung",
|
||||||
"consent_description": "Bitte um Zustimmung zu den Bedingungen, Konditionen oder der Datennutzung",
|
"consent_description": "Bitte um Zustimmung zu Bedingungen, Konditionen oder Datennutzung",
|
||||||
"contact_info": "Kontaktinfo",
|
"contact_info": "Kontaktdaten",
|
||||||
"contact_info_description": "Bitte nach Name, Nachname, E-Mail, Telefonnummer und Firma gemeinsam fragen",
|
"contact_info_description": "Frage nach Vorname, Nachname, E-Mail, Telefonnummer und Firma zusammen",
|
||||||
"csat": "Kundenzufriedenheit (CSAT)",
|
"csat_description": "Miss die Kundenzufriedenheit (CSAT) für dein Produkt oder deine Dienstleistung.",
|
||||||
"csat_description": "Customer Satisfaction Score messen (1-5)",
|
|
||||||
"csat_lower_label": "Sehr unzufrieden",
|
|
||||||
"csat_name": "Kundenzufriedenheitswert (CSAT)",
|
"csat_name": "Kundenzufriedenheitswert (CSAT)",
|
||||||
"csat_question_10_headline": "Hast du noch weitere Anmerkungen, Fragen oder Anliegen?",
|
"csat_question_10_headline": "Hast du noch weitere Anmerkungen, Fragen oder Anliegen?",
|
||||||
"csat_question_10_placeholder": "Gib hier deine Antwort ein…",
|
"csat_question_10_placeholder": "Gib hier deine Antwort ein…",
|
||||||
@@ -916,11 +903,10 @@
|
|||||||
"csat_survey_question_1_lower_label": "Äußerst unzufrieden",
|
"csat_survey_question_1_lower_label": "Äußerst unzufrieden",
|
||||||
"csat_survey_question_1_upper_label": "Äußerst zufrieden",
|
"csat_survey_question_1_upper_label": "Äußerst zufrieden",
|
||||||
"csat_survey_question_2_headline": "Super! Gibt es etwas, das wir tun können, um deine Erfahrung zu verbessern?",
|
"csat_survey_question_2_headline": "Super! Gibt es etwas, das wir tun können, um deine Erfahrung zu verbessern?",
|
||||||
"csat_survey_question_2_placeholder": "Tippe deine Antwort hier...",
|
"csat_survey_question_2_placeholder": "Gib hier deine Antwort ein…",
|
||||||
"csat_survey_question_3_headline": "Ugh, sorry! Können wir irgendwas tun, um deine Erfahrung zu verbessern?",
|
"csat_survey_question_3_headline": "Oh je, tut uns leid! Gibt es etwas, das wir tun können, um deine Erfahrung zu verbessern?",
|
||||||
"csat_survey_question_3_placeholder": "Tippe deine Antwort hier...",
|
"csat_survey_question_3_placeholder": "Gib hier deine Antwort ein…",
|
||||||
"csat_upper_label": "Sehr zufrieden",
|
"cta_description": "Zeige Informationen an und fordere Nutzer zu einer bestimmten Aktion auf",
|
||||||
"cta_description": "Information anzeigen und Benutzer auffordern, eine bestimmte Aktion auszuführen",
|
|
||||||
"custom_survey_description": "Erstelle eine Umfrage ohne Vorlage.",
|
"custom_survey_description": "Erstelle eine Umfrage ohne Vorlage.",
|
||||||
"custom_survey_name": "Von Grund auf neu beginnen",
|
"custom_survey_name": "Von Grund auf neu beginnen",
|
||||||
"custom_survey_question_1_headline": "Was möchtest du wissen?",
|
"custom_survey_question_1_headline": "Was möchtest du wissen?",
|
||||||
@@ -1085,17 +1071,12 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "Was könnten wir besser machen?",
|
"gauge_feature_satisfaction_question_2_headline": "Was könnten wir besser machen?",
|
||||||
"identify_customer_goals_description": "Verstehe besser, ob deine Botschaft die richtigen Erwartungen an den Wert deines Produkts weckt.",
|
"identify_customer_goals_description": "Verstehe besser, ob deine Botschaft die richtigen Erwartungen an den Wert deines Produkts weckt.",
|
||||||
"identify_customer_goals_name": "Kundenziele identifizieren",
|
"identify_customer_goals_name": "Kundenziele identifizieren",
|
||||||
"identify_customer_goals_question_1_choice_1": "Meine Nutzerbasis tiefgehend verstehen",
|
"identify_sign_up_barriers_description": "Biete einen Rabatt an, um Einblicke in Anmeldehürden zu erhalten.",
|
||||||
"identify_customer_goals_question_1_choice_2": "Upselling-Möglichkeiten erkennen",
|
"identify_sign_up_barriers_name": "Anmeldehürden identifizieren",
|
||||||
"identify_customer_goals_question_1_choice_3": "Das bestmögliche Produkt entwickeln",
|
"identify_sign_up_barriers_question_1_button_label": "10 % Rabatt sichern",
|
||||||
"identify_customer_goals_question_1_choice_4": "Die Welt beherrschen, damit alle zum Frühstück Rosenkohl essen",
|
"identify_sign_up_barriers_question_1_headline": "Beantworte diese kurze Umfrage und erhalte 10 % Rabatt!",
|
||||||
"identify_customer_goals_question_1_headline": "Was ist dein Hauptziel bei der Nutzung von $[workspaceName]?",
|
"identify_sign_up_barriers_question_1_html": "Du überlegst anscheinend, dich anzumelden. Beantworte vier Fragen und erhalte 10 % Rabatt auf jeden Plan.",
|
||||||
"identify_sign_up_barriers_description": "Biete einen Rabatt an, um Einblicke in Anmeldebarrieren zu gewinnen.",
|
"identify_sign_up_barriers_question_2_headline": "Wie wahrscheinlich ist es, dass du dich bei $[workspaceName] anmeldest?",
|
||||||
"identify_sign_up_barriers_name": "Identifiziere Anmeldebarrieren",
|
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Erhalte 10% Rabatt",
|
|
||||||
"identify_sign_up_barriers_question_1_headline": "Beantworte diese kurze Umfrage, erhalte 10% Rabatt!",
|
|
||||||
"identify_sign_up_barriers_question_1_html": "Du scheinst darüber nachzudenken, Dich anzumelden. Beantworte vier Fragen und erhalte 10% Rabatt auf jeden Plan.",
|
|
||||||
"identify_sign_up_barriers_question_2_headline": "Wie wahrscheinlich ist es, dass du dich für $[workspaceName] anmeldest?",
|
|
||||||
"identify_sign_up_barriers_question_2_lower_label": "Überhaupt nicht wahrscheinlich",
|
"identify_sign_up_barriers_question_2_lower_label": "Überhaupt nicht wahrscheinlich",
|
||||||
"identify_sign_up_barriers_question_2_upper_label": "Sehr wahrscheinlich",
|
"identify_sign_up_barriers_question_2_upper_label": "Sehr wahrscheinlich",
|
||||||
"identify_sign_up_barriers_question_3_choice_1_label": "Hat vielleicht nicht das, was ich suche",
|
"identify_sign_up_barriers_question_3_choice_1_label": "Hat vielleicht nicht das, was ich suche",
|
||||||
@@ -1163,16 +1144,14 @@
|
|||||||
"improve_trial_conversion_question_1_headline": "Warum hast du deine Testphase beendet?",
|
"improve_trial_conversion_question_1_headline": "Warum hast du deine Testphase beendet?",
|
||||||
"improve_trial_conversion_question_1_subheader": "Hilf uns, dich besser zu verstehen:",
|
"improve_trial_conversion_question_1_subheader": "Hilf uns, dich besser zu verstehen:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Weiter",
|
"improve_trial_conversion_question_2_button_label": "Weiter",
|
||||||
"improve_trial_conversion_question_2_headline": "Schade. Was war das größte Problem bei der Nutzung von $[workspaceName]?",
|
"improve_trial_conversion_question_2_headline": "Schade! Was war das größte Problem bei der Nutzung von $[workspaceName]?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Weiter",
|
"improve_trial_conversion_question_4_button_label": "20% Rabatt sichern",
|
||||||
"improve_trial_conversion_question_3_headline": "Was hast du von $[workspaceName] erwartet?",
|
"improve_trial_conversion_question_4_headline": "Schade! Hol dir 20% Rabatt auf das erste Jahr.",
|
||||||
"improve_trial_conversion_question_4_button_label": "Erhalte 20% Rabatt",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Wir bieten dir gerne 20% Rabatt auf einen Jahresplan an.</span></p>",
|
||||||
"improve_trial_conversion_question_4_headline": "Das tut mir leid zu hören! Erhalte 20% Rabatt im ersten Jahr.",
|
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Wir freuen uns, dir einen 20% Rabatt auf einen Jahresplan anzubieten.</span></p>",
|
|
||||||
"improve_trial_conversion_question_5_button_label": "Weiter",
|
"improve_trial_conversion_question_5_button_label": "Weiter",
|
||||||
"improve_trial_conversion_question_5_headline": "Was möchtest Du erreichen?",
|
"improve_trial_conversion_question_5_headline": "Was möchtest du erreichen?",
|
||||||
"improve_trial_conversion_question_5_subheader": "Bitte wähle eine der folgenden Optionen:",
|
"improve_trial_conversion_question_5_subheader": "Bitte wähle eine der folgenden Optionen:",
|
||||||
"improve_trial_conversion_question_6_headline": "Wie löst Du dein Problem heutzutage?",
|
"improve_trial_conversion_question_6_headline": "Wie löst du dein Problem aktuell?",
|
||||||
"improve_trial_conversion_question_6_subheader": "Bitte nenne alternative Lösungen:",
|
"improve_trial_conversion_question_6_subheader": "Bitte nenne alternative Lösungen:",
|
||||||
"integration_setup_survey_description": "Bewerte, wie einfach Nutzer Integrationen zu deinem Produkt hinzufügen können. Finde blinde Flecken.",
|
"integration_setup_survey_description": "Bewerte, wie einfach Nutzer Integrationen zu deinem Produkt hinzufügen können. Finde blinde Flecken.",
|
||||||
"integration_setup_survey_name": "Umfrage zur Integration-Nutzung",
|
"integration_setup_survey_name": "Umfrage zur Integration-Nutzung",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Diese Aktion wird ausgelöst, wenn die Seite geladen wird.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Diese Aktion wird ausgelöst, wenn die Seite geladen wird.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Diese Aktion wird ausgelöst, wenn der Nutzer 50 % der Seite scrollt.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Diese Aktion wird ausgelöst, wenn der Nutzer 50 % der Seite scrollt.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Diese Aktion wird ausgelöst, wenn der Nutzer versucht, die Seite zu verlassen.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Diese Aktion wird ausgelöst, wenn der Nutzer versucht, die Seite zu verlassen.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Das ist eine Code-Aktion. Bitte nimm die Änderungen in deiner Code-Basis vor.",
|
||||||
"time_in_seconds": "Zeit in Sekunden",
|
"time_in_seconds": "Zeit in Sekunden",
|
||||||
"time_in_seconds_placeholder": "z. B. 10",
|
"time_in_seconds_placeholder": "z. B. 10",
|
||||||
"time_in_seconds_with_unit": "{seconds}s",
|
"time_in_seconds_with_unit": "{seconds}s",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "API-Schlüssel aktualisiert",
|
"api_key_updated": "API-Schlüssel aktualisiert",
|
||||||
"delete_api_key_confirmation": "Alle Anwendungen, die diesen Schlüssel verwenden, können nicht mehr auf deine Formbricks-Daten zugreifen.",
|
"delete_api_key_confirmation": "Alle Anwendungen, die diesen Schlüssel verwenden, können nicht mehr auf deine Formbricks-Daten zugreifen.",
|
||||||
"duplicate_access": "Doppelter Workspace-Zugriff ist nicht erlaubt",
|
"duplicate_access": "Doppelter Workspace-Zugriff ist nicht erlaubt",
|
||||||
"duplicate_directory_access": "Doppelter Zugriff auf Feedback-Datensatz-Verzeichnis nicht erlaubt",
|
|
||||||
"feedback_record_directory_access": "Zugriff auf Feedback-Datensatz-Verzeichnis",
|
|
||||||
"no_api_keys_yet": "Du hast noch keine API-Schlüssel",
|
"no_api_keys_yet": "Du hast noch keine API-Schlüssel",
|
||||||
"no_directory_permissions_found": "Keine Berechtigungen für Feedback-Datensatz-Verzeichnis gefunden",
|
"no_env_permissions_found": "Keine Umgebungsberechtigungen gefunden",
|
||||||
"no_workspace_permissions_found": "Keine Workspace-Berechtigungen gefunden",
|
|
||||||
"organization_access": "Organisations-Zugriff",
|
"organization_access": "Organisations-Zugriff",
|
||||||
"organization_access_description": "Wähle Lese- oder Schreibrechte für organisationsweite Ressourcen aus.",
|
"organization_access_description": "Wähle Lese- oder Schreibrechte für organisationsweite Ressourcen aus.",
|
||||||
"permissions": "Berechtigungen",
|
"permissions": "Berechtigungen",
|
||||||
"secret": "Geheimnis",
|
"secret": "Geheimnis",
|
||||||
"unable_to_copy_api_key": "API-Schlüssel konnte nicht kopiert werden",
|
|
||||||
"unable_to_delete_api_key": "API-Schlüssel konnte nicht gelöscht werden",
|
"unable_to_delete_api_key": "API-Schlüssel konnte nicht gelöscht werden",
|
||||||
"unknown_directory": "Unbekanntes Verzeichnis",
|
|
||||||
"unknown_workspace": "Unbekannter Arbeitsbereich",
|
|
||||||
"workspace_access": "Workspace-Zugriff"
|
"workspace_access": "Workspace-Zugriff"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Verbinde deine App oder Website mit Formbricks.",
|
"app_connection_description": "Verbinde deine App oder Website mit Formbricks.",
|
||||||
"cache_update_delay_description": "Wenn du Aktualisierungen an Umfragen, Kontakten, Aktionen oder anderen Daten vornimmst, kann es bis zu 1 Minute dauern, bis diese Änderungen in deiner lokalen App mit dem Formbricks SDK sichtbar werden.",
|
"cache_update_delay_description": "Wenn du Aktualisierungen an Umfragen, Kontakten, Aktionen oder anderen Daten vornimmst, kann es bis zu 1 Minute dauern, bis diese Änderungen in deiner lokalen App mit dem Formbricks SDK sichtbar werden.",
|
||||||
"cache_update_delay_title": "Änderungen werden nach ~1 Minute durch Caching übernommen",
|
"cache_update_delay_title": "Änderungen werden nach ~1 Minute durch Caching übernommen",
|
||||||
|
"environment_id": "Deine Workspace-ID",
|
||||||
|
"environment_id_description": "Diese ID identifiziert diesen Formbricks-Workspace eindeutig.",
|
||||||
"formbricks_sdk_connected": "Formbricks SDK ist verbunden",
|
"formbricks_sdk_connected": "Formbricks SDK ist verbunden",
|
||||||
"formbricks_sdk_not_connected": "Formbricks SDK ist noch nicht verbunden.",
|
"formbricks_sdk_not_connected": "Formbricks SDK ist noch nicht verbunden.",
|
||||||
"formbricks_sdk_not_connected_description": "Füge das Formbricks SDK zu deiner Website oder App hinzu, um es mit Formbricks zu verbinden",
|
"formbricks_sdk_not_connected_description": "Füge das Formbricks SDK zu deiner Website oder App hinzu, um es mit Formbricks zu verbinden",
|
||||||
@@ -1869,9 +1845,7 @@
|
|||||||
"sdk_connection_details_description": "Deine einzigartige Workspace-ID und SDK-Verbindungs-URL zur Integration von Formbricks in deine Anwendung.",
|
"sdk_connection_details_description": "Deine einzigartige Workspace-ID und SDK-Verbindungs-URL zur Integration von Formbricks in deine Anwendung.",
|
||||||
"setup_alert_description": "Folge dieser Schritt-für-Schritt-Anleitung, um deine App oder Website in unter 5 Minuten zu verbinden.",
|
"setup_alert_description": "Folge dieser Schritt-für-Schritt-Anleitung, um deine App oder Website in unter 5 Minuten zu verbinden.",
|
||||||
"setup_alert_title": "So verbindest du dich",
|
"setup_alert_title": "So verbindest du dich",
|
||||||
"webapp_url": "SDK-Verbindungs-URL",
|
"webapp_url": "SDK-Verbindungs-URL"
|
||||||
"workspace_id": "Deine Workspace-ID",
|
|
||||||
"workspace_id_description": "Diese ID identifiziert diesen Formbricks-Workspace eindeutig."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Glückwunsch!",
|
"congrats": "Glückwunsch!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Attributwert",
|
"attribute_value_placeholder": "Attributwert",
|
||||||
"attributes_msg_attribute_limit_exceeded": "{count} neue(s) Attribut(e) konnten nicht erstellt werden, da das Maximum von {limit} Attributklassen überschritten würde. Bestehende Attribute wurden erfolgreich aktualisiert.",
|
"attributes_msg_attribute_limit_exceeded": "{count} neue(s) Attribut(e) konnten nicht erstellt werden, da das Maximum von {limit} Attributklassen überschritten würde. Bestehende Attribute wurden erfolgreich aktualisiert.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (Attribut \"{key}\" hat dataType: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (Attribut \"{key}\" hat dataType: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "Die E-Mail-Adresse existiert bereits für diesen Workspace und wurde nicht aktualisiert.",
|
"attributes_msg_email_already_exists": "Die E-Mail-Adresse existiert bereits für diese Umgebung und wurde nicht aktualisiert.",
|
||||||
"attributes_msg_email_or_userid_required": "Entweder E-Mail oder Benutzer-ID ist erforderlich. Die bestehenden Werte wurden beibehalten.",
|
"attributes_msg_email_or_userid_required": "Entweder E-Mail oder Benutzer-ID ist erforderlich. Die bestehenden Werte wurden beibehalten.",
|
||||||
"attributes_msg_new_attribute_created": "Neues Attribut \"{key}\" mit Typ \"{dataType}\" erstellt",
|
"attributes_msg_new_attribute_created": "Neues Attribut \"{key}\" mit Typ \"{dataType}\" erstellt",
|
||||||
"attributes_msg_userid_already_exists": "Die Benutzer-ID existiert bereits für diesen Workspace und wurde nicht aktualisiert.",
|
"attributes_msg_userid_already_exists": "Die Benutzer-ID existiert bereits für diese Umgebung und wurde nicht aktualisiert.",
|
||||||
"contact_deleted_successfully": "Kontakt erfolgreich gelöscht",
|
"contact_deleted_successfully": "Kontakt erfolgreich gelöscht",
|
||||||
"contacts_table_refresh": "Kontakte aktualisieren",
|
"contacts_table_refresh": "Kontakte aktualisieren",
|
||||||
"contacts_table_refresh_success": "Kontakte erfolgreich aktualisiert",
|
"contacts_table_refresh_success": "Kontakte erfolgreich aktualisiert",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Doppelte Sprache oder Sprach-ID",
|
"duplicate_language_or_language_id": "Doppelte Sprache oder Sprach-ID",
|
||||||
"edit_languages": "Sprachen bearbeiten",
|
"edit_languages": "Sprachen bearbeiten",
|
||||||
"identifier": "Kennung (ISO)",
|
"identifier": "Kennung (ISO)",
|
||||||
|
"incomplete_translations": "Unvollständige Übersetzungen",
|
||||||
"language": "Sprache",
|
"language": "Sprache",
|
||||||
"language_deleted_successfully": "Sprache erfolgreich gelöscht",
|
"language_deleted_successfully": "Sprache erfolgreich gelöscht",
|
||||||
"languages_updated_successfully": "Sprachen erfolgreich aktualisiert",
|
"languages_updated_successfully": "Sprachen erfolgreich aktualisiert",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Bitte wähle eine Sprache aus",
|
"please_select_a_language": "Bitte wähle eine Sprache aus",
|
||||||
"remove_language": "Sprache entfernen",
|
"remove_language": "Sprache entfernen",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Bitte entferne die Sprache aus diesen Umfragen, um sie aus dem Workspace zu entfernen.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Bitte entferne die Sprache aus diesen Umfragen, um sie aus dem Workspace zu entfernen.",
|
||||||
"search_items": "Elemente suchen"
|
"search_items": "Elemente durchsuchen",
|
||||||
|
"translate": "Übersetzen"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Hintergrundfarbe hinzufügen",
|
"add_background_color": "Hintergrundfarbe hinzufügen",
|
||||||
@@ -2717,15 +2693,22 @@
|
|||||||
},
|
},
|
||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "Alles klar! Zeit, deine erste Umfrage zu erstellen",
|
"all_set_time_to_create_first_survey": "Alles klar! Zeit, deine erste Umfrage zu erstellen",
|
||||||
"alphabetical": "alphabetisch",
|
"alphabetical": "Alphabetisch",
|
||||||
|
"copy_survey": "Umfrage kopieren",
|
||||||
|
"copy_survey_description": "Kopiere diese Umfrage in einen anderen Workspace",
|
||||||
|
"copy_survey_error": "Kopieren der Umfrage fehlgeschlagen",
|
||||||
"copy_survey_link_to_clipboard": "Umfragelink in die Zwischenablage kopieren",
|
"copy_survey_link_to_clipboard": "Umfragelink in die Zwischenablage kopieren",
|
||||||
"delete_survey_and_responses_warning": "Bist Du sicher, dass Du diese Umfrage und alle ihre Antworten löschen möchtest?",
|
"copy_survey_no_workspaces": "Es gibt keine anderen Workspaces, in die diese Umfrage kopiert werden kann.",
|
||||||
|
"copy_survey_partially_success": "{success} Umfragen erfolgreich kopiert, {error} fehlgeschlagen.",
|
||||||
|
"copy_survey_success": "Umfrage erfolgreich kopiert",
|
||||||
|
"delete_survey_and_responses_warning": "Bist du sicher, dass du diese Umfrage und alle zugehörigen Antworten löschen möchtest?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Übersetzungen aktivieren",
|
"1_choose_the_default_language_for_this_survey": "1. Wähle die Standardsprache für diese Umfrage:",
|
||||||
"add": "+ hinzufügen",
|
"2_activate_translation_for_specific_languages": "2. Aktiviere die Übersetzung für bestimmte Sprachen:",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Füge eine Verzögerung hinzu oder schließe die Umfrage automatisch.",
|
"add": "Hinzufügen +",
|
||||||
"add_a_four_digit_pin": "Füge eine vierstellige PIN hinzu",
|
"add_a_delay_or_auto_close_the_survey": "Verzögerung hinzufügen oder Umfrage automatisch schließen",
|
||||||
"add_a_variable_to_calculate": "Variable hinzufügen",
|
"add_a_four_digit_pin": "Vierstellige PIN hinzufügen",
|
||||||
|
"add_a_variable_to_calculate": "Variable zur Berechnung hinzufügen",
|
||||||
"add_action_below": "Aktion unten hinzufügen",
|
"add_action_below": "Aktion unten hinzufügen",
|
||||||
"add_block": "Block hinzufügen",
|
"add_block": "Block hinzufügen",
|
||||||
"add_choice_below": "Auswahl unten hinzufügen",
|
"add_choice_below": "Auswahl unten hinzufügen",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Publikum",
|
"audience": "Publikum",
|
||||||
"auto_close_on_inactivity": "Automatisches Schließen bei Inaktivität",
|
"auto_close_on_inactivity": "Automatisches Schließen bei Inaktivität",
|
||||||
"auto_progress_rating_and_nps": "Bewertungs- und NPS-Fragen automatisch fortsetzen",
|
"auto_progress_rating_and_nps": "Bewertungs- und NPS-Fragen automatisch fortsetzen",
|
||||||
"auto_progress_rating_and_nps_description": "Automatisches Fortschreiten bei Ein-Fragen-Blöcken. Pflichtfragen blenden „Weiter“ aus, außer wenn „Sonstiges“ ausgewählt ist.",
|
"auto_progress_rating_and_nps_description": "Fahre automatisch fort, sobald Befragte eine Antwort bei Bewertungs- oder NPS-Fragen auswählen. Dies gilt nur für Blöcke mit einer einzelnen Frage. Bei Pflichtfragen wird die Weiter-Schaltfläche ausgeblendet; bei optionalen Fragen bleibt sie zum Überspringen sichtbar.",
|
||||||
"auto_save_disabled": "Automatisches Speichern deaktiviert",
|
"auto_save_disabled": "Automatisches Speichern deaktiviert",
|
||||||
"auto_save_disabled_tooltip": "Deine Umfrage wird nur im Entwurfsmodus automatisch gespeichert. So wird sichergestellt, dass öffentliche Umfragen nicht versehentlich aktualisiert werden.",
|
"auto_save_disabled_tooltip": "Deine Umfrage wird nur im Entwurfsmodus automatisch gespeichert. So wird sichergestellt, dass öffentliche Umfragen nicht versehentlich aktualisiert werden.",
|
||||||
"auto_save_on": "Automatisches Speichern an",
|
"auto_save_on": "Automatisches Speichern an",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "Änderungen führen zu Inkonsistenzen",
|
"caution_text": "Änderungen führen zu Inkonsistenzen",
|
||||||
"change_anyway": "Trotzdem ändern",
|
"change_anyway": "Trotzdem ändern",
|
||||||
"change_background": "Hintergrund ändern",
|
"change_background": "Hintergrund ändern",
|
||||||
"change_default": "Standard ändern",
|
|
||||||
"change_question_type": "Fragetyp ändern",
|
"change_question_type": "Fragetyp ändern",
|
||||||
"change_survey_type": "Wechsel des Umfragetyps wirkt sich auf bestehenden Zugriff aus",
|
"change_survey_type": "Wechsel des Umfragetyps wirkt sich auf bestehenden Zugriff aus",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Ändere den Hintergrund in eine Farbe, ein Bild oder eine Animation.",
|
"change_the_background_to_a_color_image_or_animation": "Ändere den Hintergrund in eine Farbe, ein Bild oder eine Animation.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Wähle die erste Frage in Deinem Block",
|
"choose_the_first_question_on_your_block": "Wähle die erste Frage in Deinem Block",
|
||||||
"choose_where_to_run_the_survey": "Wähle aus, wo die Umfrage ausgeführt werden soll.",
|
"choose_where_to_run_the_survey": "Wähle aus, wo die Umfrage ausgeführt werden soll.",
|
||||||
"city": "Stadt",
|
"city": "Stadt",
|
||||||
"clear_close_on_date": "Pausierungsdatum loeschen",
|
"close_survey_on_response_limit": "Umfrage bei Erreichen der Antwortgrenze schließen",
|
||||||
"clear_publish_on_date": "Veroeffentlichungsdatum loeschen",
|
|
||||||
"close_survey_on_date": "Pausierungsdatum",
|
|
||||||
"close_survey_on_response_limit": "Umfrage bei Erreichen des Antwortlimits schließen",
|
|
||||||
"code": "Code",
|
|
||||||
"color": "Farbe",
|
"color": "Farbe",
|
||||||
"column_used_in_logic_error": "Diese Spalte wird in der Logik von Frage {questionIndex} verwendet. Bitte entferne sie zuerst aus der Logik.",
|
"column_used_in_logic_error": "Diese Spalte wird in der Logik von Frage {questionIndex} verwendet. Bitte entferne sie zuerst aus der Logik.",
|
||||||
"columns": "Spalten",
|
"columns": "Spalten",
|
||||||
@@ -2855,10 +2833,9 @@
|
|||||||
"css_selector": "CSS-Selektor",
|
"css_selector": "CSS-Selektor",
|
||||||
"cta_button_label": "„CTA“-Button-Beschriftung",
|
"cta_button_label": "„CTA“-Button-Beschriftung",
|
||||||
"custom_hostname": "Benutzerdefinierter Hostname",
|
"custom_hostname": "Benutzerdefinierter Hostname",
|
||||||
"customize_survey_logo": "Umfragelogo anpassen",
|
"customize_survey_logo": "Umfrage-Logo anpassen",
|
||||||
"darken_or_lighten_background_of_your_choice": "Hintergrund deiner Wahl abdunkeln oder aufhellen.",
|
"darken_or_lighten_background_of_your_choice": "Verdunkle oder erhelle den Hintergrund deiner Wahl.",
|
||||||
"days_before_showing_this_survey_again": "oder mehr Tage müssen zwischen der zuletzt angezeigten Umfrage und der Anzeige dieser Umfrage vergehen.",
|
"days_before_showing_this_survey_again": "oder mehr Tage zwischen der zuletzt angezeigten Umfrage und dem erneuten Anzeigen dieser Umfrage vergehen müssen.",
|
||||||
"default_language": "Standardsprache",
|
|
||||||
"delete_anyways": "Trotzdem löschen",
|
"delete_anyways": "Trotzdem löschen",
|
||||||
"delete_block": "Block löschen",
|
"delete_block": "Block löschen",
|
||||||
"delete_choice": "Auswahl löschen",
|
"delete_choice": "Auswahl löschen",
|
||||||
@@ -2876,8 +2853,9 @@
|
|||||||
"dropdown": "Dropdown",
|
"dropdown": "Dropdown",
|
||||||
"duplicate_block": "Block duplizieren",
|
"duplicate_block": "Block duplizieren",
|
||||||
"duplicate_question": "Frage duplizieren",
|
"duplicate_question": "Frage duplizieren",
|
||||||
"edit_link": "Bearbeitungslink",
|
"edit_link": "Link bearbeiten",
|
||||||
"edit_recall": "Erinnerung bearbeiten",
|
"edit_recall": "Recall bearbeiten",
|
||||||
|
"edit_translations": "{lang}-Übersetzungen bearbeiten",
|
||||||
"element_not_found": "Frage nicht gefunden",
|
"element_not_found": "Frage nicht gefunden",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Erlaube Teilnehmenden, die Sprache jederzeit zu wechseln. Mindestens 2 aktive Sprachen erforderlich.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Erlaube Teilnehmenden, die Sprache jederzeit zu wechseln. Mindestens 2 aktive Sprachen erforderlich.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "Der Spam-Schutz nutzt reCAPTCHA v3, um Spam-Antworten herauszufiltern.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "Der Spam-Schutz nutzt reCAPTCHA v3, um Spam-Antworten herauszufiltern.",
|
||||||
@@ -3014,20 +2992,18 @@
|
|||||||
"long_answer_toggle_description": "Erlaube Befragten, längere, mehrzeilige Antworten zu schreiben.",
|
"long_answer_toggle_description": "Erlaube Befragten, längere, mehrzeilige Antworten zu schreiben.",
|
||||||
"lower_label": "Untere Beschriftung",
|
"lower_label": "Untere Beschriftung",
|
||||||
"manage_languages": "Sprachen verwalten",
|
"manage_languages": "Sprachen verwalten",
|
||||||
"manage_translations": "Übersetzungen verwalten",
|
|
||||||
"matrix_all_fields": "Alle Felder",
|
"matrix_all_fields": "Alle Felder",
|
||||||
"matrix_rows": "Zeilen",
|
"matrix_rows": "Zeilen",
|
||||||
"max_file_size": "Maximale Dateigröße",
|
"max_file_size": "Maximale Dateigröße",
|
||||||
"max_file_size_limit_is": "Die maximale Dateigrößenbeschränkung beträgt",
|
"max_file_size_limit_is": "Die maximale Dateigröße beträgt",
|
||||||
"missing_first": "Fehlende zuerst",
|
|
||||||
"move_question_to_block": "Frage in Block verschieben",
|
"move_question_to_block": "Frage in Block verschieben",
|
||||||
"multiply": "Multiplizieren *",
|
"multiply": "Multiplizieren *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Erforderlich für eine selbst gehostete Cal.com-Instanz",
|
"needed_for_self_hosted_cal_com_instance": "Erforderlich für eine selbst gehostete Cal.com-Instanz",
|
||||||
"next_block": "Nächster Block",
|
"next_block": "Nächster Block",
|
||||||
"next_button_label": "Beschriftung der Schaltfläche \"Weiter\"",
|
"next_button_label": "Beschriftung für \"Weiter\"-Button",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Noch keine versteckten Felder. Füge das erste unten hinzu.",
|
"no_hidden_fields_yet_add_first_one_below": "Noch keine versteckten Felder vorhanden. Füge unten das erste hinzu.",
|
||||||
"no_images_found_for": "Keine Bilder gefunden für ''{query}\"",
|
"no_images_found_for": "Keine Bilder gefunden für \"{query}\"",
|
||||||
"no_languages_found_add_first_one_to_get_started": "In diesem Workspace wurden keine Umfragesprachen gefunden. Bitte füge eine hinzu, um zu starten.",
|
"no_languages_found_add_first_one_to_get_started": "Keine Sprachen gefunden. Füge die erste hinzu, um loszulegen.",
|
||||||
"no_option_found": "Keine Option gefunden",
|
"no_option_found": "Keine Option gefunden",
|
||||||
"no_recall_items_found": "Keine Wiederholungselemente gefunden",
|
"no_recall_items_found": "Keine Wiederholungselemente gefunden",
|
||||||
"no_variables_yet_add_first_one_below": "Noch keine Variablen vorhanden. Füge unten die erste hinzu.",
|
"no_variables_yet_add_first_one_below": "Noch keine Variablen vorhanden. Füge unten die erste hinzu.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Bitte gib eine gültige URL ein (z. B. https://example.com)",
|
"please_enter_a_valid_url": "Bitte gib eine gültige URL ein (z. B. https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Bitte lege einen Umfrage-Trigger fest",
|
"please_set_a_survey_trigger": "Bitte lege einen Umfrage-Trigger fest",
|
||||||
"please_specify": "Bitte angeben",
|
"please_specify": "Bitte angeben",
|
||||||
"present_your_survey_in_multiple_languages": "Präsentiere deine Umfrage in mehreren Sprachen",
|
"prevent_double_submission": "Doppelte Einreichung verhindern",
|
||||||
"prevent_double_submission": "Doppeltes Anbschicken verhindern",
|
"prevent_double_submission_description": "Nur 1 Antwort pro E-Mail-Adresse zulassen",
|
||||||
"prevent_double_submission_description": "Nur eine Antwort pro E-Mail-Adresse zulassen (beta)",
|
|
||||||
"progress_saved": "Fortschritt gespeichert",
|
"progress_saved": "Fortschritt gespeichert",
|
||||||
"protect_survey_with_pin": "Umfrage mit PIN schützen",
|
"protect_survey_with_pin": "Umfrage mit PIN schützen",
|
||||||
"protect_survey_with_pin_description": "Nur Nutzer mit der PIN können auf die Umfrage zugreifen.",
|
"protect_survey_with_pin_description": "Nur Nutzer mit der PIN können auf die Umfrage zugreifen.",
|
||||||
"publish": "Veröffentlichen",
|
"publish": "Veröffentlichen",
|
||||||
"publish_survey_on_date": "Veroeffentlichungsdatum",
|
|
||||||
"question": "Frage",
|
"question": "Frage",
|
||||||
"question_deleted": "Frage gelöscht.",
|
"question_deleted": "Frage gelöscht.",
|
||||||
"question_duplicated": "Frage dupliziert.",
|
"question_duplicated": "Frage dupliziert.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Zeilen",
|
"rows": "Zeilen",
|
||||||
"save_and_close": "Speichern & Schließen",
|
"save_and_close": "Speichern & Schließen",
|
||||||
"scale": "Skala",
|
"scale": "Skala",
|
||||||
"schedule_survey": "Umfrage planen",
|
|
||||||
"search_for_images": "Nach Bildern suchen",
|
"search_for_images": "Nach Bildern suchen",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "Sekunden nach dem Auslösen wird die Umfrage geschlossen, wenn keine Antwort erfolgt",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "Sekunden nach dem Auslösen wird die Umfrage geschlossen, wenn keine Antwort erfolgt",
|
||||||
"seconds_before_showing_the_survey": "Sekunden vor dem Anzeigen der Umfrage.",
|
"seconds_before_showing_the_survey": "Sekunden vor dem Anzeigen der Umfrage.",
|
||||||
@@ -3148,9 +3121,8 @@
|
|||||||
"seven_points": "7 Punkte",
|
"seven_points": "7 Punkte",
|
||||||
"show_block_settings": "Block-Einstellungen anzeigen",
|
"show_block_settings": "Block-Einstellungen anzeigen",
|
||||||
"show_button": "Button anzeigen",
|
"show_button": "Button anzeigen",
|
||||||
"show_in_order": "In Reihenfolge anzeigen",
|
"show_language_switch": "Sprachumschalter anzeigen",
|
||||||
"show_language_switch": "Sprachwechsel anzeigen",
|
"show_multiple_times": "Eine begrenzte Anzahl von Malen anzeigen",
|
||||||
"show_multiple_times": "Begrenzte Anzahl von Malen anzeigen",
|
|
||||||
"show_only_once": "Nur einmal anzeigen",
|
"show_only_once": "Nur einmal anzeigen",
|
||||||
"show_question_settings": "Frage-Einstellungen anzeigen",
|
"show_question_settings": "Frage-Einstellungen anzeigen",
|
||||||
"show_survey_maximum_of": "Umfrage maximal anzeigen",
|
"show_survey_maximum_of": "Umfrage maximal anzeigen",
|
||||||
@@ -3174,14 +3146,13 @@
|
|||||||
"subtract": "Subtrahieren -",
|
"subtract": "Subtrahieren -",
|
||||||
"survey_closed_message_heading_required": "Füge eine Überschrift zur benutzerdefinierten Nachricht für geschlossene Umfragen hinzu.",
|
"survey_closed_message_heading_required": "Füge eine Überschrift zur benutzerdefinierten Nachricht für geschlossene Umfragen hinzu.",
|
||||||
"survey_completed_heading": "Umfrage abgeschlossen",
|
"survey_completed_heading": "Umfrage abgeschlossen",
|
||||||
"survey_completed_subheading": "Diese kostenlose und quelloffene Umfrage wurde geschlossen",
|
"survey_completed_subheading": "Diese kostenlose & quelloffene Umfrage wurde geschlossen",
|
||||||
"survey_display_settings": "Einstellungen zur Anzeige der Umfrage",
|
"survey_display_settings": "Umfrage-Anzeigeeinstellungen",
|
||||||
"survey_placement": "Platzierung der Umfrage",
|
"survey_placement": "Umfrage-Platzierung",
|
||||||
"survey_preview": "Umfragevorschau 👀",
|
"survey_preview": "Umfrage-Vorschau 👀",
|
||||||
"survey_styling": "Umfrage Styling",
|
"survey_styling": "Umfrage-Styling",
|
||||||
"survey_trigger": "Auslöser der Umfrage",
|
"survey_trigger": "Umfrage-Auslöser",
|
||||||
"survey_will_be_closed_at_midnight_cet": "Die Umfrage wird am ausgewählten Datum um {time} in der Zeitzone {timeZone} geschlossen",
|
"switch_multi_language_on_to_get_started": "Schalte Mehrsprachigkeit ein, um loszulegen 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "Die Umfrage wird am ausgewählten Datum um {time} in der Zeitzone {timeZone} veröffentlicht",
|
|
||||||
"target_block_not_found": "Zielblock nicht gefunden",
|
"target_block_not_found": "Zielblock nicht gefunden",
|
||||||
"targeted": "Gezielt",
|
"targeted": "Gezielt",
|
||||||
"ten_points": "10 Punkte",
|
"ten_points": "10 Punkte",
|
||||||
@@ -3189,13 +3160,11 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Zeige ein einziges Mal, auch wenn sie nicht antworten.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Zeige ein einziges Mal, auch wenn sie nicht antworten.",
|
||||||
"then": "Dann",
|
"then": "Dann",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Diese Aktion entfernt alle Übersetzungen aus dieser Umfrage.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Diese Aktion entfernt alle Übersetzungen aus dieser Umfrage.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Dies entfernt diese Sprache und alle zugehörigen Übersetzungen aus dieser Umfrage. Diese Aktion kann nicht rückgängig gemacht werden.",
|
|
||||||
"three_points": "3 Punkte",
|
"three_points": "3 Punkte",
|
||||||
"times": "Zeiten",
|
"times": "Mal",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Um die Platzierung über alle Umfragen hinweg konsistent zu halten, kannst du",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Um die Platzierung über alle Umfragen hinweg einheitlich zu halten, kannst du",
|
||||||
"translated": "Übersetzt",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Umfrage auslösen, wenn eine der Aktionen ausgeführt wird…",
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Umfrage auslösen, wenn eine der Aktionen ausgeführt wird...",
|
"try_lollipop_or_mountain": "Probiere „Lutscher“ oder „Berg“…",
|
||||||
"try_lollipop_or_mountain": "Versuch 'Lolli' oder 'Berge'...",
|
|
||||||
"type_field_id": "Feld-ID eingeben",
|
"type_field_id": "Feld-ID eingeben",
|
||||||
"underline": "Unterstreichen",
|
"underline": "Unterstreichen",
|
||||||
"unlock_targeting_description": "Richte dich an bestimmte Nutzergruppen basierend auf Attributen oder Geräteinformationen",
|
"unlock_targeting_description": "Richte dich an bestimmte Nutzergruppen basierend auf Attributen oder Geräteinformationen",
|
||||||
@@ -3267,9 +3236,8 @@
|
|||||||
"verify_email_before_submission": "E-Mail vor dem Absenden verifizieren",
|
"verify_email_before_submission": "E-Mail vor dem Absenden verifizieren",
|
||||||
"verify_email_before_submission_description": "Lass nur Personen mit einer echten E-Mail-Adresse antworten.",
|
"verify_email_before_submission_description": "Lass nur Personen mit einer echten E-Mail-Adresse antworten.",
|
||||||
"visibility_and_recontact": "Sichtbarkeit & erneute Kontaktaufnahme",
|
"visibility_and_recontact": "Sichtbarkeit & erneute Kontaktaufnahme",
|
||||||
"visibility_and_recontact_description": "Steuern Sie, wann diese Umfrage erscheinen kann und wie oft sie erneut erscheinen kann.",
|
"visibility_and_recontact_description": "Steuere, wann diese Umfrage erscheinen kann und wie oft sie erneut angezeigt werden kann.",
|
||||||
"visible": "Sichtbar",
|
"wait": "Warten",
|
||||||
"wait": "Warte",
|
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Warte ein paar Sekunden nach dem Auslöser, bevor Du die Umfrage anzeigst",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Warte ein paar Sekunden nach dem Auslöser, bevor Du die Umfrage anzeigst",
|
||||||
"waiting_time_across_surveys": "Abkühlphase (umfrageübergreifend)",
|
"waiting_time_across_surveys": "Abkühlphase (umfrageübergreifend)",
|
||||||
"waiting_time_across_surveys_description": "Um Umfragemüdigkeit zu vermeiden, wähle aus, wie diese Umfrage mit der arbeitsbereichsweiten Abkühlphase interagiert.",
|
"waiting_time_across_surveys_description": "Um Umfragemüdigkeit zu vermeiden, wähle aus, wie diese Umfrage mit der arbeitsbereichsweiten Abkühlphase interagiert.",
|
||||||
@@ -3470,16 +3438,14 @@
|
|||||||
"configure_alerts": "Benachrichtigungen konfigurieren",
|
"configure_alerts": "Benachrichtigungen konfigurieren",
|
||||||
"congrats": "Glückwunsch! Deine Umfrage ist live.",
|
"congrats": "Glückwunsch! Deine Umfrage ist live.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Verbinde deine Website oder App mit Formbricks, um loszulegen.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Verbinde deine Website oder App mit Formbricks, um loszulegen.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% Zufrieden",
|
"current_count": "Aktueller Zählerstand",
|
||||||
"csat_satisfied_tooltip": "{percentage}% der Befragten haben eine Bewertung von 4 oder 5 gegeben (CSAT).",
|
"custom_range": "Benutzerdefinierter Zeitraum…",
|
||||||
"current_count": "Aktuelle Anzahl",
|
"delete_all_existing_responses_and_displays": "Alle vorhandenen Antworten und Anzeigen löschen",
|
||||||
"custom_range": "Benutzerdefinierter Bereich...",
|
"download_qr_code": "QR-Code herunterladen",
|
||||||
"delete_all_existing_responses_and_displays": "Alle bestehenden Antworten und Anzeigen löschen",
|
|
||||||
"download_qr_code": "QR Code herunterladen",
|
|
||||||
"downloading_qr_code": "QR-Code wird heruntergeladen",
|
"downloading_qr_code": "QR-Code wird heruntergeladen",
|
||||||
"drop_offs": "Drop-Off Rate",
|
"drop_offs": "Abbrüche",
|
||||||
"drop_offs_tooltip": "So oft wurde die Umfrage gestartet, aber nicht abgeschlossen.",
|
"drop_offs_tooltip": "Anzahl der begonnenen, aber nicht abgeschlossenen Umfragen.",
|
||||||
"effort_score": "Aufwandswert",
|
"failed_to_copy_link": "Link konnte nicht kopiert werden",
|
||||||
"filter_added_successfully": "Filter erfolgreich hinzugefügt",
|
"filter_added_successfully": "Filter erfolgreich hinzugefügt",
|
||||||
"filter_updated_successfully": "Filter erfolgreich aktualisiert",
|
"filter_updated_successfully": "Filter erfolgreich aktualisiert",
|
||||||
"filtered_responses_csv": "Gefilterte Antworten (CSV)",
|
"filtered_responses_csv": "Gefilterte Antworten (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Limit",
|
"limit": "Limit",
|
||||||
"no_identified_impressions": "Keine Impressionen von identifizierten Kontakten",
|
"no_identified_impressions": "Keine Impressionen von identifizierten Kontakten",
|
||||||
"no_responses_found": "Keine Antworten gefunden",
|
"no_responses_found": "Keine Antworten gefunden",
|
||||||
"nps_promoters_tooltip": "{percentage}% der Befragten haben eine Bewertung von 9 oder 10 gegeben (NPS-Promotoren).",
|
|
||||||
"other_values_found": "Andere Werte gefunden",
|
"other_values_found": "Andere Werte gefunden",
|
||||||
"overall": "Gesamt",
|
"overall": "Gesamt",
|
||||||
"promoters": "Promotoren",
|
"promoters": "Promotoren",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "Die Anzahl der von den Befragten abgeschlossenen Quoten.",
|
"quotas_completed_tooltip": "Die Anzahl der von den Befragten abgeschlossenen Quoten.",
|
||||||
"reset_survey": "Umfrage zurücksetzen",
|
"reset_survey": "Umfrage zurücksetzen",
|
||||||
"reset_survey_warning": "Das Zurücksetzen einer Umfrage entfernt alle Antworten und Anzeigen, die mit dieser Umfrage verbunden sind. Dies kann nicht rückgängig gemacht werden.",
|
"reset_survey_warning": "Das Zurücksetzen einer Umfrage entfernt alle Antworten und Anzeigen, die mit dieser Umfrage verbunden sind. Dies kann nicht rückgängig gemacht werden.",
|
||||||
|
"satisfied": "Zufrieden",
|
||||||
"selected_responses_csv": "Ausgewählte Antworten (CSV)",
|
"selected_responses_csv": "Ausgewählte Antworten (CSV)",
|
||||||
"selected_responses_excel": "Ausgewählte Antworten (Excel)",
|
"selected_responses_excel": "Ausgewählte Antworten (Excel)",
|
||||||
"setup_integrations": "Integrationen einrichten",
|
"setup_integrations": "Integrationen einrichten",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Anzahl der Male, wie oft die Umfrage gestartet wurde.",
|
"starts_tooltip": "Anzahl der Male, wie oft die Umfrage gestartet wurde.",
|
||||||
"survey_reset_successfully": "Umfrage erfolgreich zurückgesetzt. {responseCount} Antworten und {displayCount} Anzeigen wurden gelöscht.",
|
"survey_reset_successfully": "Umfrage erfolgreich zurückgesetzt. {responseCount} Antworten und {displayCount} Anzeigen wurden gelöscht.",
|
||||||
"survey_results": "Ergebnisse von {surveyName}",
|
"survey_results": "Ergebnisse von {surveyName}",
|
||||||
"survey_scheduled_successfully": "Umfrage erfolgreich geplant",
|
|
||||||
"this_month": "Diesen Monat",
|
"this_month": "Diesen Monat",
|
||||||
"this_quarter": "Dieses Quartal",
|
"this_quarter": "Dieses Quartal",
|
||||||
"this_year": "Dieses Jahr",
|
"this_year": "Dieses Jahr",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "Umfrage erfolgreich gelöscht",
|
"survey_deleted_successfully": "Umfrage erfolgreich gelöscht",
|
||||||
"survey_duplicated_successfully": "Umfrage erfolgreich dupliziert",
|
"survey_duplicated_successfully": "Umfrage erfolgreich dupliziert",
|
||||||
|
"survey_duplication_error": "Umfrage konnte nicht dupliziert werden.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Alle Kanäle",
|
"all_channels": "Alle Kanäle",
|
||||||
"all_industries": "Alle Branchen",
|
"all_industries": "Alle Branchen",
|
||||||
|
|||||||
+35
-69
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Change workspace",
|
"change_workspace": "Change workspace",
|
||||||
"chart": "Chart",
|
"chart": "Chart",
|
||||||
"charts": "Charts",
|
"charts": "Charts",
|
||||||
"choice_n": "Choice {{n}}",
|
|
||||||
"choices": "Choices",
|
"choices": "Choices",
|
||||||
"choose_organization": "Choose organization",
|
"choose_organization": "Choose organization",
|
||||||
"choose_workspace": "Choose workspace",
|
"choose_workspace": "Choose workspace",
|
||||||
@@ -172,7 +171,6 @@
|
|||||||
"close": "Close",
|
"close": "Close",
|
||||||
"code": "Code",
|
"code": "Code",
|
||||||
"collapse_rows": "Collapse rows",
|
"collapse_rows": "Collapse rows",
|
||||||
"column_n": "Column {{n}}",
|
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"configuration": "Configure",
|
"configuration": "Configure",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Ending card",
|
"ending_card": "Ending card",
|
||||||
"enter_url": "Enter URL",
|
"enter_url": "Enter URL",
|
||||||
"enterprise_license": "Enterprise License",
|
"enterprise_license": "Enterprise License",
|
||||||
|
"environment": "Environment",
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
"error_component_description": "This resource does not exist or you do not have the necessary rights to access it.",
|
"error_component_description": "This resource does not exist or you do not have the necessary rights to access it.",
|
||||||
"error_component_title": "Error loading resources",
|
"error_component_title": "Error loading resources",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Failed to load organizations",
|
"failed_to_load_organizations": "Failed to load organizations",
|
||||||
"failed_to_load_workspaces": "Failed to load workspaces",
|
"failed_to_load_workspaces": "Failed to load workspaces",
|
||||||
"failed_to_parse_csv": "Failed to parse CSV",
|
"failed_to_parse_csv": "Failed to parse CSV",
|
||||||
"field_placeholder": "{{field}} Placeholder",
|
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"finish": "Finish",
|
"finish": "Finish",
|
||||||
"first_name": "First Name",
|
"first_name": "First Name",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Generate",
|
"generate": "Generate",
|
||||||
"go_back": "Go Back",
|
"go_back": "Go Back",
|
||||||
"go_to_dashboard": "Go to Dashboard",
|
"go_to_dashboard": "Go to Dashboard",
|
||||||
"headline": "Headline",
|
|
||||||
"hidden": "Hidden",
|
"hidden": "Hidden",
|
||||||
"hidden_field": "Hidden field",
|
"hidden_field": "Hidden field",
|
||||||
"hidden_fields": "Hidden fields",
|
"hidden_fields": "Hidden fields",
|
||||||
"hide": "Hide",
|
"hide": "Hide",
|
||||||
"hide_column": "Hide column",
|
"hide_column": "Hide column",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
"images": "Images",
|
"images": "Images",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "More options",
|
"more_options": "More options",
|
||||||
"move_down": "Move down",
|
"move_down": "Move down",
|
||||||
"move_up": "Move up",
|
"move_up": "Move up",
|
||||||
|
"multiple_languages": "Multiple languages",
|
||||||
"my_product": "my Product",
|
"my_product": "my Product",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"new": "New",
|
"new": "New",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "No result found",
|
"no_result_found": "No result found",
|
||||||
"no_results": "No results",
|
"no_results": "No results",
|
||||||
"no_surveys_found": "No surveys found.",
|
"no_surveys_found": "No surveys found.",
|
||||||
"no_text_found": "No text found",
|
|
||||||
"none_of_the_above": "None of the above",
|
"none_of_the_above": "None of the above",
|
||||||
"not_authenticated": "You are not authenticated to perform this action.",
|
"not_authenticated": "You are not authenticated to perform this action.",
|
||||||
"not_authorized": "Not authorized",
|
"not_authorized": "Not authorized",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Organization settings",
|
"organization_settings": "Organization settings",
|
||||||
"other": "Other",
|
"other": "Other",
|
||||||
"other_filters": "Other Filters",
|
"other_filters": "Other Filters",
|
||||||
"other_placeholder": "Other Placeholder",
|
"others": "Others",
|
||||||
"overlay_color": "Overlay color",
|
"overlay_color": "Overlay color",
|
||||||
"overview": "Overview",
|
"overview": "Overview",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Please upgrade your plan",
|
"please_upgrade_your_plan": "Please upgrade your plan",
|
||||||
"powered_by_formbricks": "Powered by Formbricks",
|
"powered_by_formbricks": "Powered by Formbricks",
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
|
"preview_survey": "Preview Survey",
|
||||||
"privacy": "Privacy Policy",
|
"privacy": "Privacy Policy",
|
||||||
"product_manager": "Product Manager",
|
"product_manager": "Product Manager",
|
||||||
|
"production": "Production",
|
||||||
"profile": "Profile",
|
"profile": "Profile",
|
||||||
"profile_id": "Profile ID",
|
"profile_id": "Profile ID",
|
||||||
"progress": "Progress",
|
"progress": "Progress",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Restart",
|
"restart": "Restart",
|
||||||
"retry": "Retry",
|
"retry": "Retry",
|
||||||
"role": "Role",
|
"role": "Role",
|
||||||
"row_n": "Row {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Sales",
|
"sales": "Sales",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"save_as_draft": "Save as draft",
|
"save_as_draft": "Save as draft",
|
||||||
"save_changes": "Save changes",
|
"save_changes": "Save changes",
|
||||||
"save_without_scheduling": "Save without scheduling",
|
|
||||||
"saving": "Saving",
|
"saving": "Saving",
|
||||||
"scheduled": "Scheduled",
|
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
"search_charts": "Search charts...",
|
"search_charts": "Search charts...",
|
||||||
"security": "Security",
|
"security": "Security",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "File storage not set up, uploads will likely fail",
|
"storage_not_configured": "File storage not set up, uploads will likely fail",
|
||||||
"string": "Text",
|
"string": "Text",
|
||||||
"styling": "Styling",
|
"styling": "Styling",
|
||||||
"subheader": "Subheader",
|
|
||||||
"submit": "Submit",
|
"submit": "Submit",
|
||||||
"summary": "Summary",
|
"summary": "Summary",
|
||||||
"survey": "Survey",
|
"survey": "Survey",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Survey Languages",
|
"survey_languages": "Survey Languages",
|
||||||
"survey_live": "Survey live",
|
"survey_live": "Survey live",
|
||||||
"survey_paused": "Survey paused.",
|
"survey_paused": "Survey paused.",
|
||||||
"survey_scheduled": "Survey scheduled.",
|
|
||||||
"survey_type": "Survey Type",
|
"survey_type": "Survey Type",
|
||||||
"surveys": "Surveys",
|
"surveys": "Surveys",
|
||||||
"table_items_deleted_successfully": "{type}s deleted successfully",
|
"table_items_deleted_successfully": "{type}s deleted successfully",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Workspaces",
|
"workspaces": "Workspaces",
|
||||||
"years": "years",
|
"years": "years",
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
|
"you": "You",
|
||||||
"you_are_downgraded_to_the_community_edition": "You are downgraded to the Community Edition.",
|
"you_are_downgraded_to_the_community_edition": "You are downgraded to the Community Edition.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "You are not authorized to perform this action.",
|
"you_are_not_authorized_to_perform_this_action": "You are not authorized to perform this action.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "You have reached your limit of {workspaceLimit} workspaces.",
|
"you_have_reached_your_limit_of_workspace_limit": "You have reached your limit of {workspaceLimit} workspaces.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "The Formbricks Team",
|
"email_footer_text_2": "The Formbricks Team",
|
||||||
"email_template_text_1": "This email was sent via Formbricks.",
|
"email_template_text_1": "This email was sent via Formbricks.",
|
||||||
"embed_survey_preview_email_didnt_request": "Did not request this?",
|
"embed_survey_preview_email_didnt_request": "Did not request this?",
|
||||||
|
"embed_survey_preview_email_environment_id": "Environment ID",
|
||||||
"embed_survey_preview_email_fight_spam": "Help us fight spam and forward this mail to hola@formbricks.com",
|
"embed_survey_preview_email_fight_spam": "Help us fight spam and forward this mail to hola@formbricks.com",
|
||||||
"embed_survey_preview_email_heading": "Preview Email Embed",
|
"embed_survey_preview_email_heading": "Preview Email Embed",
|
||||||
"embed_survey_preview_email_subject": "Formbricks Email Survey Preview",
|
"embed_survey_preview_email_subject": "Formbricks Email Survey Preview",
|
||||||
"embed_survey_preview_email_text": "This is how the code snippet looks embedded into an email:",
|
"embed_survey_preview_email_text": "This is how the code snippet looks embedded into an email:",
|
||||||
"embed_survey_preview_email_workspace_id": "Workspace ID",
|
|
||||||
"forgot_password_email_change_password": "Change password",
|
"forgot_password_email_change_password": "Change password",
|
||||||
"forgot_password_email_did_not_request": "If you did not request this, please ignore this email.",
|
"forgot_password_email_did_not_request": "If you did not request this, please ignore this email.",
|
||||||
"forgot_password_email_heading": "Change password",
|
"forgot_password_email_heading": "Change password",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Question Preview",
|
"question_preview": "Question Preview",
|
||||||
"response_already_received": "We already received a response for this email address.",
|
"response_already_received": "We already received a response for this email address.",
|
||||||
"response_submitted": "A response linked to this survey and contact already exists",
|
"response_submitted": "A response linked to this survey and contact already exists",
|
||||||
"scheduled": "This survey is scheduled to go live soon.",
|
|
||||||
"survey_already_answered_heading": "The survey has already been answered.",
|
"survey_already_answered_heading": "The survey has already been answered.",
|
||||||
"survey_already_answered_subheading": "You can only use this link once.",
|
"survey_already_answered_subheading": "You can only use this link once.",
|
||||||
"survey_sent_to": "Survey sent to {email}",
|
"survey_sent_to": "Survey sent to {email}",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Other",
|
"career_development_survey_question_6_choice_6": "Other",
|
||||||
"career_development_survey_question_6_headline": "Which of the following best describes your current job level?",
|
"career_development_survey_question_6_headline": "Which of the following best describes your current job level?",
|
||||||
"career_development_survey_question_6_subheader": "Please select one of the following options:",
|
"career_development_survey_question_6_subheader": "Please select one of the following options:",
|
||||||
"ces": "Customer Effort (CES)",
|
|
||||||
"ces_description": "Measure Customer Effort Score (1-5 or 1-7)",
|
|
||||||
"ces_lower_label": "Very difficult",
|
|
||||||
"ces_upper_label": "Very easy",
|
|
||||||
"cess_survey_name": "CES Survey",
|
"cess_survey_name": "CES Survey",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] makes it easy for me to [ADD GOAL]",
|
"cess_survey_question_1_headline": "$[workspaceName] makes it easy for me to [ADD GOAL]",
|
||||||
"cess_survey_question_1_lower_label": "Strongly disagree",
|
"cess_survey_question_1_lower_label": "Strongly disagree",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Ask to agree to terms, conditions, or data usage",
|
"consent_description": "Ask to agree to terms, conditions, or data usage",
|
||||||
"contact_info": "Contact Info",
|
"contact_info": "Contact Info",
|
||||||
"contact_info_description": "Ask for name, surname, email, phone number and company jointly",
|
"contact_info_description": "Ask for name, surname, email, phone number and company jointly",
|
||||||
"csat": "Customer Satisfaction (CSAT)",
|
"csat_description": "Measure the Customer Satisfaction Score of your product or service.",
|
||||||
"csat_description": "Measure Customer Satisfaction Score (1-5)",
|
|
||||||
"csat_lower_label": "Very unsatisfied",
|
|
||||||
"csat_name": "Customer Satisfaction Score (CSAT)",
|
"csat_name": "Customer Satisfaction Score (CSAT)",
|
||||||
"csat_question_10_headline": "Do you have any other comments, questions or concerns?",
|
"csat_question_10_headline": "Do you have any other comments, questions or concerns?",
|
||||||
"csat_question_10_placeholder": "Type your answer here…",
|
"csat_question_10_placeholder": "Type your answer here…",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Type your answer here…",
|
"csat_survey_question_2_placeholder": "Type your answer here…",
|
||||||
"csat_survey_question_3_headline": "Ugh, sorry! Is there anything we can do to improve your experience?",
|
"csat_survey_question_3_headline": "Ugh, sorry! Is there anything we can do to improve your experience?",
|
||||||
"csat_survey_question_3_placeholder": "Type your answer here…",
|
"csat_survey_question_3_placeholder": "Type your answer here…",
|
||||||
"csat_upper_label": "Very satisfied",
|
|
||||||
"cta_description": "Display information and prompt users to take a specific action",
|
"cta_description": "Display information and prompt users to take a specific action",
|
||||||
"custom_survey_description": "Create a survey without template.",
|
"custom_survey_description": "Create a survey without template.",
|
||||||
"custom_survey_name": "Start from scratch",
|
"custom_survey_name": "Start from scratch",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "What is one thing we could do better?",
|
"gauge_feature_satisfaction_question_2_headline": "What is one thing we could do better?",
|
||||||
"identify_customer_goals_description": "Better understand if your messaging creates the right expectations of the value your product provides.",
|
"identify_customer_goals_description": "Better understand if your messaging creates the right expectations of the value your product provides.",
|
||||||
"identify_customer_goals_name": "Identify Customer Goals",
|
"identify_customer_goals_name": "Identify Customer Goals",
|
||||||
"identify_customer_goals_question_1_choice_1": "Understand my user base deeply",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Identify upselling opportunities",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "Build the best possible product",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "Rule the world to make everyone breakfast brussels sprouts",
|
|
||||||
"identify_customer_goals_question_1_headline": "What is your primary goal for using $[workspaceName]?",
|
|
||||||
"identify_sign_up_barriers_description": "Offer a discount to gather insights about sign up barriers.",
|
"identify_sign_up_barriers_description": "Offer a discount to gather insights about sign up barriers.",
|
||||||
"identify_sign_up_barriers_name": "Identify Sign Up Barriers",
|
"identify_sign_up_barriers_name": "Identify Sign Up Barriers",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Get 10% discount",
|
"identify_sign_up_barriers_question_1_button_label": "Get 10% discount",
|
||||||
@@ -1164,8 +1145,6 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Help us understand you better:",
|
"improve_trial_conversion_question_1_subheader": "Help us understand you better:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Next",
|
"improve_trial_conversion_question_2_button_label": "Next",
|
||||||
"improve_trial_conversion_question_2_headline": "Sorry to hear. What was the biggest problem using $[workspaceName]?",
|
"improve_trial_conversion_question_2_headline": "Sorry to hear. What was the biggest problem using $[workspaceName]?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Next",
|
|
||||||
"improve_trial_conversion_question_3_headline": "What did you expect $[workspaceName] to do?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "Get 20% off",
|
"improve_trial_conversion_question_4_button_label": "Get 20% off",
|
||||||
"improve_trial_conversion_question_4_headline": "Sorry to hear! Get 20% off the first year.",
|
"improve_trial_conversion_question_4_headline": "Sorry to hear! Get 20% off the first year.",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We are happy to offer you a 20% discount on a yearly plan.</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We are happy to offer you a 20% discount on a yearly plan.</span></p>",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "This action will be triggered when the page is loaded.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "This action will be triggered when the page is loaded.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "This action will be triggered when the user scrolls 50% of the page.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "This action will be triggered when the user scrolls 50% of the page.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "This action will be triggered when the user tries to leave the page.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "This action will be triggered when the user tries to leave the page.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "This is a code action. Please make changes in your code base.",
|
||||||
"time_in_seconds": "Time in seconds",
|
"time_in_seconds": "Time in seconds",
|
||||||
"time_in_seconds_placeholder": "e.g. 10",
|
"time_in_seconds_placeholder": "e.g. 10",
|
||||||
"time_in_seconds_with_unit": "{seconds}s",
|
"time_in_seconds_with_unit": "{seconds}s",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "API Key updated",
|
"api_key_updated": "API Key updated",
|
||||||
"delete_api_key_confirmation": "Any applications using this key will no longer be able to access your Formbricks data.",
|
"delete_api_key_confirmation": "Any applications using this key will no longer be able to access your Formbricks data.",
|
||||||
"duplicate_access": "Duplicate workspace access not allowed",
|
"duplicate_access": "Duplicate workspace access not allowed",
|
||||||
"duplicate_directory_access": "Duplicate feedback record directory access not allowed",
|
|
||||||
"feedback_record_directory_access": "Feedback Record Directory Access",
|
|
||||||
"no_api_keys_yet": "You do not have any API keys yet",
|
"no_api_keys_yet": "You do not have any API keys yet",
|
||||||
"no_directory_permissions_found": "No feedback record directory permissions found",
|
"no_env_permissions_found": "No environment permissions found",
|
||||||
"no_workspace_permissions_found": "No Workspace permissions found",
|
|
||||||
"organization_access": "Organization Access",
|
"organization_access": "Organization Access",
|
||||||
"organization_access_description": "Select read or write privileges for organization-wide resources.",
|
"organization_access_description": "Select read or write privileges for organization-wide resources.",
|
||||||
"permissions": "Permissions",
|
"permissions": "Permissions",
|
||||||
"secret": "Secret",
|
"secret": "Secret",
|
||||||
"unable_to_copy_api_key": "Unable to copy API key",
|
|
||||||
"unable_to_delete_api_key": "Unable to delete API Key",
|
"unable_to_delete_api_key": "Unable to delete API Key",
|
||||||
"unknown_directory": "Unknown directory",
|
|
||||||
"unknown_workspace": "Unknown workspace",
|
|
||||||
"workspace_access": "Workspace Access"
|
"workspace_access": "Workspace Access"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Connect your app or website to Formbricks.",
|
"app_connection_description": "Connect your app or website to Formbricks.",
|
||||||
"cache_update_delay_description": "When you make updates to surveys, contacts, actions, or other data, it can take up to 1 minute for those changes to appear in your local app running the Formbricks SDK.",
|
"cache_update_delay_description": "When you make updates to surveys, contacts, actions, or other data, it can take up to 1 minute for those changes to appear in your local app running the Formbricks SDK.",
|
||||||
"cache_update_delay_title": "Changes will be reflected after ~1 minute due to caching",
|
"cache_update_delay_title": "Changes will be reflected after ~1 minute due to caching",
|
||||||
|
"environment_id": "Your Workspace ID",
|
||||||
|
"environment_id_description": "This id uniquely identifies this Formbricks workspace.",
|
||||||
"formbricks_sdk_connected": "Formbricks SDK is connected",
|
"formbricks_sdk_connected": "Formbricks SDK is connected",
|
||||||
"formbricks_sdk_not_connected": "Formbricks SDK is not yet connected.",
|
"formbricks_sdk_not_connected": "Formbricks SDK is not yet connected.",
|
||||||
"formbricks_sdk_not_connected_description": "Add the Formbricks SDK to your website or app to connect it with Formbricks",
|
"formbricks_sdk_not_connected_description": "Add the Formbricks SDK to your website or app to connect it with Formbricks",
|
||||||
@@ -1866,12 +1842,10 @@
|
|||||||
"receiving_data": "Receiving data 💃🕺",
|
"receiving_data": "Receiving data 💃🕺",
|
||||||
"recheck": "Re-check",
|
"recheck": "Re-check",
|
||||||
"sdk_connection_details": "SDK Connection Details",
|
"sdk_connection_details": "SDK Connection Details",
|
||||||
"sdk_connection_details_description": "Your unique Workspace ID and SDK connection URL for integrating Formbricks with your application.",
|
"sdk_connection_details_description": "Your unique workspace ID and SDK connection URL for integrating Formbricks with your application.",
|
||||||
"setup_alert_description": "Follow this step-by-step tutorial to connect your app or website in under 5 minutes.",
|
"setup_alert_description": "Follow this step-by-step tutorial to connect your app or website in under 5 minutes.",
|
||||||
"setup_alert_title": "How to connect",
|
"setup_alert_title": "How to connect",
|
||||||
"webapp_url": "SDK Connection URL",
|
"webapp_url": "SDK Connection URL"
|
||||||
"workspace_id": "Your Workspace ID",
|
|
||||||
"workspace_id_description": "This id uniquely identifies this Formbricks Workspace."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Congrats!",
|
"congrats": "Congrats!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Attribute Value",
|
"attribute_value_placeholder": "Attribute Value",
|
||||||
"attributes_msg_attribute_limit_exceeded": "Could not create {count} new attribute(s) as it would exceed the maximum limit of {limit} attribute classes. Existing attributes were updated successfully.",
|
"attributes_msg_attribute_limit_exceeded": "Could not create {count} new attribute(s) as it would exceed the maximum limit of {limit} attribute classes. Existing attributes were updated successfully.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (attribute “{key}” has dataType: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (attribute “{key}” has dataType: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "The email already exists for this Workspace and was not updated.",
|
"attributes_msg_email_already_exists": "The email already exists for this environment and was not updated.",
|
||||||
"attributes_msg_email_or_userid_required": "Either email or user ID is required. The existing values were preserved.",
|
"attributes_msg_email_or_userid_required": "Either email or user ID is required. The existing values were preserved.",
|
||||||
"attributes_msg_new_attribute_created": "Created new attribute “{key}” with type “{dataType}”",
|
"attributes_msg_new_attribute_created": "Created new attribute “{key}” with type “{dataType}”",
|
||||||
"attributes_msg_userid_already_exists": "The user ID already exists for this Workspace and was not updated.",
|
"attributes_msg_userid_already_exists": "The user ID already exists for this environment and was not updated.",
|
||||||
"contact_deleted_successfully": "Contact deleted successfully",
|
"contact_deleted_successfully": "Contact deleted successfully",
|
||||||
"contacts_table_refresh": "Refresh contacts",
|
"contacts_table_refresh": "Refresh contacts",
|
||||||
"contacts_table_refresh_success": "Contacts refreshed successfully",
|
"contacts_table_refresh_success": "Contacts refreshed successfully",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Duplicate language or language ID",
|
"duplicate_language_or_language_id": "Duplicate language or language ID",
|
||||||
"edit_languages": "Edit languages",
|
"edit_languages": "Edit languages",
|
||||||
"identifier": "Identifier (ISO)",
|
"identifier": "Identifier (ISO)",
|
||||||
|
"incomplete_translations": "Incomplete translations",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"language_deleted_successfully": "Language deleted successfully",
|
"language_deleted_successfully": "Language deleted successfully",
|
||||||
"languages_updated_successfully": "Languages updated successfully",
|
"languages_updated_successfully": "Languages updated successfully",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Please select a language",
|
"please_select_a_language": "Please select a language",
|
||||||
"remove_language": "Remove Language",
|
"remove_language": "Remove Language",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Please remove the language from these surveys in order to remove it from the workspace.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Please remove the language from these surveys in order to remove it from the workspace.",
|
||||||
"search_items": "Search items"
|
"search_items": "Search items",
|
||||||
|
"translate": "Translate"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Add background color",
|
"add_background_color": "Add background color",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "You are all set! Time to create your first survey",
|
"all_set_time_to_create_first_survey": "You are all set! Time to create your first survey",
|
||||||
"alphabetical": "Alphabetical",
|
"alphabetical": "Alphabetical",
|
||||||
|
"copy_survey": "Copy survey",
|
||||||
|
"copy_survey_description": "Copy this survey to another workspace",
|
||||||
|
"copy_survey_error": "Failed to copy survey",
|
||||||
"copy_survey_link_to_clipboard": "Copy survey link to clipboard",
|
"copy_survey_link_to_clipboard": "Copy survey link to clipboard",
|
||||||
|
"copy_survey_no_workspaces": "There are no other workspaces to copy this survey to.",
|
||||||
|
"copy_survey_partially_success": "{success} surveys copied successfully, {error} failed.",
|
||||||
|
"copy_survey_success": "Survey copied successfully",
|
||||||
"delete_survey_and_responses_warning": "Are you sure you want to delete this survey and all of its responses?",
|
"delete_survey_and_responses_warning": "Are you sure you want to delete this survey and all of its responses?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Activate translations",
|
"1_choose_the_default_language_for_this_survey": "1. Choose the default language for this survey:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Activate translation for specific languages:",
|
||||||
"add": "Add +",
|
"add": "Add +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Add a delay or auto-close the survey",
|
"add_a_delay_or_auto_close_the_survey": "Add a delay or auto-close the survey",
|
||||||
"add_a_four_digit_pin": "Add a four digit PIN",
|
"add_a_four_digit_pin": "Add a four digit PIN",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Audience",
|
"audience": "Audience",
|
||||||
"auto_close_on_inactivity": "Auto close on inactivity",
|
"auto_close_on_inactivity": "Auto close on inactivity",
|
||||||
"auto_progress_rating_and_nps": "Auto-progress rating and NPS questions",
|
"auto_progress_rating_and_nps": "Auto-progress rating and NPS questions",
|
||||||
"auto_progress_rating_and_nps_description": "Auto-advance in single-question blocks. Required questions hide Next, except when \"Other\" is selected.",
|
"auto_progress_rating_and_nps_description": "Automatically advance when respondents select an answer on rating or NPS questions. This only applies to single-question blocks. Required questions hide the Next button; optional questions still show it for skipping.",
|
||||||
"auto_save_disabled": "Auto-save disabled",
|
"auto_save_disabled": "Auto-save disabled",
|
||||||
"auto_save_disabled_tooltip": "Your survey is only auto-saved when in draft. This assures public surveys are not unintentionally updated.",
|
"auto_save_disabled_tooltip": "Your survey is only auto-saved when in draft. This assures public surveys are not unintentionally updated.",
|
||||||
"auto_save_on": "Auto-save on",
|
"auto_save_on": "Auto-save on",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "Changes will lead to inconsistencies",
|
"caution_text": "Changes will lead to inconsistencies",
|
||||||
"change_anyway": "Change anyway",
|
"change_anyway": "Change anyway",
|
||||||
"change_background": "Change background",
|
"change_background": "Change background",
|
||||||
"change_default": "Change default",
|
|
||||||
"change_question_type": "Change question type",
|
"change_question_type": "Change question type",
|
||||||
"change_survey_type": "Switching survey type affects existing access",
|
"change_survey_type": "Switching survey type affects existing access",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Change the background to a color, image or animation.",
|
"change_the_background_to_a_color_image_or_animation": "Change the background to a color, image or animation.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Choose the first question on your Block",
|
"choose_the_first_question_on_your_block": "Choose the first question on your Block",
|
||||||
"choose_where_to_run_the_survey": "Choose where to run the survey.",
|
"choose_where_to_run_the_survey": "Choose where to run the survey.",
|
||||||
"city": "City",
|
"city": "City",
|
||||||
"clear_close_on_date": "Clear close on date",
|
|
||||||
"clear_publish_on_date": "Clear publish on date",
|
|
||||||
"close_survey_on_date": "Close survey on date",
|
|
||||||
"close_survey_on_response_limit": "Close survey on response limit",
|
"close_survey_on_response_limit": "Close survey on response limit",
|
||||||
"code": "Code",
|
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"column_used_in_logic_error": "This column is used in logic of question {questionIndex}. Please remove it from logic first.",
|
"column_used_in_logic_error": "This column is used in logic of question {questionIndex}. Please remove it from logic first.",
|
||||||
"columns": "Columns",
|
"columns": "Columns",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "Customize the survey logo",
|
"customize_survey_logo": "Customize the survey logo",
|
||||||
"darken_or_lighten_background_of_your_choice": "Darken or lighten background of your choice.",
|
"darken_or_lighten_background_of_your_choice": "Darken or lighten background of your choice.",
|
||||||
"days_before_showing_this_survey_again": "or more days to pass between the last shown survey and showing this survey.",
|
"days_before_showing_this_survey_again": "or more days to pass between the last shown survey and showing this survey.",
|
||||||
"default_language": "Default language",
|
|
||||||
"delete_anyways": "Delete anyways",
|
"delete_anyways": "Delete anyways",
|
||||||
"delete_block": "Delete block",
|
"delete_block": "Delete block",
|
||||||
"delete_choice": "Delete choice",
|
"delete_choice": "Delete choice",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Duplicate question",
|
"duplicate_question": "Duplicate question",
|
||||||
"edit_link": "Edit link",
|
"edit_link": "Edit link",
|
||||||
"edit_recall": "Edit Recall",
|
"edit_recall": "Edit Recall",
|
||||||
|
"edit_translations": "Edit {lang} translations",
|
||||||
"element_not_found": "Question not found",
|
"element_not_found": "Question not found",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Allow respondents to switch language at any time. Needs min. 2 active languages.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Allow respondents to switch language at any time. Needs min. 2 active languages.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "Spam protection uses reCAPTCHA v3 to filter out the spam responses.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "Spam protection uses reCAPTCHA v3 to filter out the spam responses.",
|
||||||
@@ -3013,13 +2991,11 @@
|
|||||||
"long_answer": "Long answer",
|
"long_answer": "Long answer",
|
||||||
"long_answer_toggle_description": "Allow respondents to write longer, multi-line answers.",
|
"long_answer_toggle_description": "Allow respondents to write longer, multi-line answers.",
|
||||||
"lower_label": "Lower Label",
|
"lower_label": "Lower Label",
|
||||||
"manage_languages": "Manage languages",
|
"manage_languages": "Manage Languages",
|
||||||
"manage_translations": "Manage translations",
|
|
||||||
"matrix_all_fields": "All fields",
|
"matrix_all_fields": "All fields",
|
||||||
"matrix_rows": "Rows",
|
"matrix_rows": "Rows",
|
||||||
"max_file_size": "Max file size",
|
"max_file_size": "Max file size",
|
||||||
"max_file_size_limit_is": "Max file size limit is",
|
"max_file_size_limit_is": "Max file size limit is",
|
||||||
"missing_first": "Missing first",
|
|
||||||
"move_question_to_block": "Move question to block",
|
"move_question_to_block": "Move question to block",
|
||||||
"multiply": "Multiply *",
|
"multiply": "Multiply *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Needed for a self-hosted Cal.com instance",
|
"needed_for_self_hosted_cal_com_instance": "Needed for a self-hosted Cal.com instance",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "“Next” button label",
|
"next_button_label": "“Next” button label",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "No hidden fields yet. Add the first one below.",
|
"no_hidden_fields_yet_add_first_one_below": "No hidden fields yet. Add the first one below.",
|
||||||
"no_images_found_for": "No images found for “{query}”",
|
"no_images_found_for": "No images found for “{query}”",
|
||||||
"no_languages_found_add_first_one_to_get_started": "No survey languages found in this workspace. Please add one to get started.",
|
"no_languages_found_add_first_one_to_get_started": "No languages found. Add the first one to get started.",
|
||||||
"no_option_found": "No option found",
|
"no_option_found": "No option found",
|
||||||
"no_recall_items_found": "No recall items found",
|
"no_recall_items_found": "No recall items found",
|
||||||
"no_variables_yet_add_first_one_below": "No variables yet. Add the first one below.",
|
"no_variables_yet_add_first_one_below": "No variables yet. Add the first one below.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Please enter a valid URL (e.g., https://example.com)",
|
"please_enter_a_valid_url": "Please enter a valid URL (e.g., https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Please set a survey trigger",
|
"please_set_a_survey_trigger": "Please set a survey trigger",
|
||||||
"please_specify": "Please specify",
|
"please_specify": "Please specify",
|
||||||
"present_your_survey_in_multiple_languages": "Present your survey in multiple languages",
|
|
||||||
"prevent_double_submission": "Prevent double submission",
|
"prevent_double_submission": "Prevent double submission",
|
||||||
"prevent_double_submission_description": "Only allow 1 response per email address",
|
"prevent_double_submission_description": "Only allow 1 response per email address",
|
||||||
"progress_saved": "Progress saved",
|
"progress_saved": "Progress saved",
|
||||||
"protect_survey_with_pin": "Protect survey with a PIN",
|
"protect_survey_with_pin": "Protect survey with a PIN",
|
||||||
"protect_survey_with_pin_description": "Only users who have the PIN can access the survey.",
|
"protect_survey_with_pin_description": "Only users who have the PIN can access the survey.",
|
||||||
"publish": "Publish",
|
"publish": "Publish",
|
||||||
"publish_survey_on_date": "Publish survey on date",
|
|
||||||
"question": "Question",
|
"question": "Question",
|
||||||
"question_deleted": "Question deleted.",
|
"question_deleted": "Question deleted.",
|
||||||
"question_duplicated": "Question duplicated.",
|
"question_duplicated": "Question duplicated.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Rows",
|
"rows": "Rows",
|
||||||
"save_and_close": "Save & Close",
|
"save_and_close": "Save & Close",
|
||||||
"scale": "Scale",
|
"scale": "Scale",
|
||||||
"schedule_survey": "Schedule survey",
|
|
||||||
"search_for_images": "Search for images",
|
"search_for_images": "Search for images",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "seconds after trigger the survey will be closed if no response",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "seconds after trigger the survey will be closed if no response",
|
||||||
"seconds_before_showing_the_survey": "seconds before showing the survey.",
|
"seconds_before_showing_the_survey": "seconds before showing the survey.",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 points",
|
"seven_points": "7 points",
|
||||||
"show_block_settings": "Show Block settings",
|
"show_block_settings": "Show Block settings",
|
||||||
"show_button": "Show Button",
|
"show_button": "Show Button",
|
||||||
"show_in_order": "Show in order",
|
|
||||||
"show_language_switch": "Show language switch",
|
"show_language_switch": "Show language switch",
|
||||||
"show_multiple_times": "Show a limited number of times",
|
"show_multiple_times": "Show a limited number of times",
|
||||||
"show_only_once": "Show only once",
|
"show_only_once": "Show only once",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Survey Preview 👀",
|
"survey_preview": "Survey Preview 👀",
|
||||||
"survey_styling": "Survey styling",
|
"survey_styling": "Survey styling",
|
||||||
"survey_trigger": "Survey Trigger",
|
"survey_trigger": "Survey Trigger",
|
||||||
"survey_will_be_closed_at_midnight_cet": "Survey will be closed at {time} in the {timeZone} timezone on the selected date",
|
"switch_multi_language_on_to_get_started": "Switch multi-language on to get started 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "Survey will be published at {time} in the {timeZone} timezone on the selected date",
|
|
||||||
"target_block_not_found": "Target block not found",
|
"target_block_not_found": "Target block not found",
|
||||||
"targeted": "Targeted",
|
"targeted": "Targeted",
|
||||||
"ten_points": "10 points",
|
"ten_points": "10 points",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Show a single time, even if they do not respond.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Show a single time, even if they do not respond.",
|
||||||
"then": "Then",
|
"then": "Then",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "This action will remove all the translations from this survey.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "This action will remove all the translations from this survey.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "This will remove this language and all its translations from this survey. This action cannot be undone.",
|
|
||||||
"three_points": "3 points",
|
"three_points": "3 points",
|
||||||
"times": "times",
|
"times": "times",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "To keep the placement over all surveys consistent, you can",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "To keep the placement over all surveys consistent, you can",
|
||||||
"translated": "Translated",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Trigger survey when one of the actions is fired…",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Trigger survey when one of the actions is fired…",
|
||||||
"try_lollipop_or_mountain": "Try “lollipop” or “mountain”…",
|
"try_lollipop_or_mountain": "Try “lollipop” or “mountain”…",
|
||||||
"type_field_id": "Type field id",
|
"type_field_id": "Type field id",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Only let people with a real email respond.",
|
"verify_email_before_submission_description": "Only let people with a real email respond.",
|
||||||
"visibility_and_recontact": "Visibility & Recontact",
|
"visibility_and_recontact": "Visibility & Recontact",
|
||||||
"visibility_and_recontact_description": "Control when this survey can appear and how often it can reappear.",
|
"visibility_and_recontact_description": "Control when this survey can appear and how often it can reappear.",
|
||||||
"visible": "Visible",
|
|
||||||
"wait": "Wait",
|
"wait": "Wait",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Wait a few seconds after the trigger before showing the survey",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Wait a few seconds after the trigger before showing the survey",
|
||||||
"waiting_time_across_surveys": "Cooldown Period (across surveys)",
|
"waiting_time_across_surveys": "Cooldown Period (across surveys)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Configure alerts",
|
"configure_alerts": "Configure alerts",
|
||||||
"congrats": "Congrats! Your survey is live.",
|
"congrats": "Congrats! Your survey is live.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Connect your website or app with Formbricks to get started.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Connect your website or app with Formbricks to get started.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% Satisfied",
|
|
||||||
"csat_satisfied_tooltip": "{percentage}% of respondents gave a rating of 4 or 5 (CSAT).",
|
|
||||||
"current_count": "Current count",
|
"current_count": "Current count",
|
||||||
"custom_range": "Custom range…",
|
"custom_range": "Custom range…",
|
||||||
"delete_all_existing_responses_and_displays": "Delete all existing responses and displays",
|
"delete_all_existing_responses_and_displays": "Delete all existing responses and displays",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "Downloading QR code",
|
"downloading_qr_code": "Downloading QR code",
|
||||||
"drop_offs": "Drop-Offs",
|
"drop_offs": "Drop-Offs",
|
||||||
"drop_offs_tooltip": "Number of times the survey has been started but not completed.",
|
"drop_offs_tooltip": "Number of times the survey has been started but not completed.",
|
||||||
"effort_score": "Effort Score",
|
"failed_to_copy_link": "Failed to copy link",
|
||||||
"filter_added_successfully": "Filter added successfully",
|
"filter_added_successfully": "Filter added successfully",
|
||||||
"filter_updated_successfully": "Filter updated successfully",
|
"filter_updated_successfully": "Filter updated successfully",
|
||||||
"filtered_responses_csv": "Filtered responses (CSV)",
|
"filtered_responses_csv": "Filtered responses (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Limit",
|
"limit": "Limit",
|
||||||
"no_identified_impressions": "No impressions from identified contacts",
|
"no_identified_impressions": "No impressions from identified contacts",
|
||||||
"no_responses_found": "No responses found",
|
"no_responses_found": "No responses found",
|
||||||
"nps_promoters_tooltip": "{percentage}% of respondents gave a rating of 9 or 10 (NPS promoters).",
|
|
||||||
"other_values_found": "Other values found",
|
"other_values_found": "Other values found",
|
||||||
"overall": "Overall",
|
"overall": "Overall",
|
||||||
"promoters": "Promoters",
|
"promoters": "Promoters",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "The number of quotas completed by the respondents.",
|
"quotas_completed_tooltip": "The number of quotas completed by the respondents.",
|
||||||
"reset_survey": "Reset survey",
|
"reset_survey": "Reset survey",
|
||||||
"reset_survey_warning": "Resetting a survey removes all responses and displays associated with this survey. This cannot be undone.",
|
"reset_survey_warning": "Resetting a survey removes all responses and displays associated with this survey. This cannot be undone.",
|
||||||
|
"satisfied": "Satisfied",
|
||||||
"selected_responses_csv": "Selected responses (CSV)",
|
"selected_responses_csv": "Selected responses (CSV)",
|
||||||
"selected_responses_excel": "Selected responses (Excel)",
|
"selected_responses_excel": "Selected responses (Excel)",
|
||||||
"setup_integrations": "Setup integrations",
|
"setup_integrations": "Setup integrations",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Number of times the survey has been started.",
|
"starts_tooltip": "Number of times the survey has been started.",
|
||||||
"survey_reset_successfully": "Survey reset successfully. {responseCount} responses and {displayCount} displays were deleted.",
|
"survey_reset_successfully": "Survey reset successfully. {responseCount} responses and {displayCount} displays were deleted.",
|
||||||
"survey_results": "{surveyName} Results",
|
"survey_results": "{surveyName} Results",
|
||||||
"survey_scheduled_successfully": "Survey scheduled successfully",
|
|
||||||
"this_month": "This month",
|
"this_month": "This month",
|
||||||
"this_quarter": "This quarter",
|
"this_quarter": "This quarter",
|
||||||
"this_year": "This year",
|
"this_year": "This year",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "Survey deleted successfully",
|
"survey_deleted_successfully": "Survey deleted successfully",
|
||||||
"survey_duplicated_successfully": "Survey duplicated successfully",
|
"survey_duplicated_successfully": "Survey duplicated successfully",
|
||||||
|
"survey_duplication_error": "Failed to duplicate the survey.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "All channels",
|
"all_channels": "All channels",
|
||||||
"all_industries": "All industries",
|
"all_industries": "All industries",
|
||||||
|
|||||||
+35
-69
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Cambiar espacio de trabajo",
|
"change_workspace": "Cambiar espacio de trabajo",
|
||||||
"chart": "Gráfico",
|
"chart": "Gráfico",
|
||||||
"charts": "Gráficos",
|
"charts": "Gráficos",
|
||||||
"choice_n": "Opción {{n}}",
|
|
||||||
"choices": "Opciones",
|
"choices": "Opciones",
|
||||||
"choose_organization": "Elegir organización",
|
"choose_organization": "Elegir organización",
|
||||||
"choose_workspace": "Elegir proyecto",
|
"choose_workspace": "Elegir proyecto",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Cerrar",
|
"close": "Cerrar",
|
||||||
"code": "Código",
|
"code": "Código",
|
||||||
"collapse_rows": "Contraer filas",
|
"collapse_rows": "Contraer filas",
|
||||||
"column_n": "Columna {{n}}",
|
|
||||||
"completed": "Completado",
|
"completed": "Completado",
|
||||||
"configuration": "Configurar",
|
"configuration": "Configuración",
|
||||||
"confirm": "Confirmar",
|
"confirm": "Confirmar",
|
||||||
"connect": "Conectar",
|
"connect": "Conectar",
|
||||||
"connect_formbricks": "Conectar Formbricks",
|
"connect_formbricks": "Conectar Formbricks",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Tarjeta final",
|
"ending_card": "Tarjeta final",
|
||||||
"enter_url": "Introducir URL",
|
"enter_url": "Introducir URL",
|
||||||
"enterprise_license": "Licencia empresarial",
|
"enterprise_license": "Licencia empresarial",
|
||||||
|
"environment": "Entorno",
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
"error_component_description": "Este recurso no existe o no tienes los derechos necesarios para acceder a él.",
|
"error_component_description": "Este recurso no existe o no tienes los derechos necesarios para acceder a él.",
|
||||||
"error_component_title": "Error al cargar recursos",
|
"error_component_title": "Error al cargar recursos",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Error al cargar organizaciones",
|
"failed_to_load_organizations": "Error al cargar organizaciones",
|
||||||
"failed_to_load_workspaces": "Error al cargar los proyectos",
|
"failed_to_load_workspaces": "Error al cargar los proyectos",
|
||||||
"failed_to_parse_csv": "Error al analizar el CSV",
|
"failed_to_parse_csv": "Error al analizar el CSV",
|
||||||
"field_placeholder": "Marcador de posición de {{field}}",
|
|
||||||
"filter": "Filtro",
|
"filter": "Filtro",
|
||||||
"finish": "Finalizar",
|
"finish": "Finalizar",
|
||||||
"first_name": "Nombre",
|
"first_name": "Nombre",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Generar",
|
"generate": "Generar",
|
||||||
"go_back": "Volver",
|
"go_back": "Volver",
|
||||||
"go_to_dashboard": "Ir al panel de control",
|
"go_to_dashboard": "Ir al panel de control",
|
||||||
"headline": "Titular",
|
|
||||||
"hidden": "Oculto",
|
"hidden": "Oculto",
|
||||||
"hidden_field": "Campo oculto",
|
"hidden_field": "Campo oculto",
|
||||||
"hidden_fields": "Campos ocultos",
|
"hidden_fields": "Campos ocultos",
|
||||||
"hide": "Ocultar",
|
"hide": "Ocultar",
|
||||||
"hide_column": "Ocultar columna",
|
"hide_column": "Ocultar columna",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "Imagen",
|
"image": "Imagen",
|
||||||
"images": "Imágenes",
|
"images": "Imágenes",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "Más opciones",
|
"more_options": "Más opciones",
|
||||||
"move_down": "Mover hacia abajo",
|
"move_down": "Mover hacia abajo",
|
||||||
"move_up": "Mover hacia arriba",
|
"move_up": "Mover hacia arriba",
|
||||||
|
"multiple_languages": "Múltiples idiomas",
|
||||||
"my_product": "mi producto",
|
"my_product": "mi producto",
|
||||||
"name": "Nombre",
|
"name": "Nombre",
|
||||||
"new": "Nuevo",
|
"new": "Nuevo",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "No se encontró resultado",
|
"no_result_found": "No se encontró resultado",
|
||||||
"no_results": "Sin resultados",
|
"no_results": "Sin resultados",
|
||||||
"no_surveys_found": "No se encontraron encuestas.",
|
"no_surveys_found": "No se encontraron encuestas.",
|
||||||
"no_text_found": "No se encontró texto",
|
|
||||||
"none_of_the_above": "Ninguna de las anteriores",
|
"none_of_the_above": "Ninguna de las anteriores",
|
||||||
"not_authenticated": "No estás autenticado para realizar esta acción.",
|
"not_authenticated": "No estás autenticado para realizar esta acción.",
|
||||||
"not_authorized": "No autorizado",
|
"not_authorized": "No autorizado",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Ajustes de la organización",
|
"organization_settings": "Ajustes de la organización",
|
||||||
"other": "Otro",
|
"other": "Otro",
|
||||||
"other_filters": "Otros Filtros",
|
"other_filters": "Otros Filtros",
|
||||||
"other_placeholder": "Otro marcador de posición",
|
"others": "Otros",
|
||||||
"overlay_color": "Color de superposición",
|
"overlay_color": "Color de superposición",
|
||||||
"overview": "Resumen",
|
"overview": "Resumen",
|
||||||
"password": "Contraseña",
|
"password": "Contraseña",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Por favor, actualiza tu plan",
|
"please_upgrade_your_plan": "Por favor, actualiza tu plan",
|
||||||
"powered_by_formbricks": "Desarrollado por Formbricks",
|
"powered_by_formbricks": "Desarrollado por Formbricks",
|
||||||
"preview": "Vista previa",
|
"preview": "Vista previa",
|
||||||
|
"preview_survey": "Vista previa de la encuesta",
|
||||||
"privacy": "Política de privacidad",
|
"privacy": "Política de privacidad",
|
||||||
"product_manager": "Gestor de producto",
|
"product_manager": "Gestor de producto",
|
||||||
|
"production": "Producción",
|
||||||
"profile": "Perfil",
|
"profile": "Perfil",
|
||||||
"profile_id": "ID de perfil",
|
"profile_id": "ID de perfil",
|
||||||
"progress": "Progreso",
|
"progress": "Progreso",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Reiniciar",
|
"restart": "Reiniciar",
|
||||||
"retry": "Reintentar",
|
"retry": "Reintentar",
|
||||||
"role": "Rol",
|
"role": "Rol",
|
||||||
"row_n": "Fila {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Ventas",
|
"sales": "Ventas",
|
||||||
"save": "Guardar",
|
"save": "Guardar",
|
||||||
"save_as_draft": "Guardar como borrador",
|
"save_as_draft": "Guardar como borrador",
|
||||||
"save_changes": "Guardar cambios",
|
"save_changes": "Guardar cambios",
|
||||||
"save_without_scheduling": "Guardar sin programar",
|
|
||||||
"saving": "Guardando",
|
"saving": "Guardando",
|
||||||
"scheduled": "Programada",
|
|
||||||
"search": "Buscar",
|
"search": "Buscar",
|
||||||
"search_charts": "Buscar gráficos...",
|
"search_charts": "Buscar gráficos...",
|
||||||
"security": "Seguridad",
|
"security": "Seguridad",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "Almacenamiento de archivos no configurado, es probable que fallen las subidas",
|
"storage_not_configured": "Almacenamiento de archivos no configurado, es probable que fallen las subidas",
|
||||||
"string": "Texto",
|
"string": "Texto",
|
||||||
"styling": "Estilo",
|
"styling": "Estilo",
|
||||||
"subheader": "Subtítulo",
|
|
||||||
"submit": "Enviar",
|
"submit": "Enviar",
|
||||||
"summary": "Resumen",
|
"summary": "Resumen",
|
||||||
"survey": "Encuesta",
|
"survey": "Encuesta",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Idiomas de la encuesta",
|
"survey_languages": "Idiomas de la encuesta",
|
||||||
"survey_live": "Encuesta activa",
|
"survey_live": "Encuesta activa",
|
||||||
"survey_paused": "Encuesta pausada.",
|
"survey_paused": "Encuesta pausada.",
|
||||||
"survey_scheduled": "Encuesta programada.",
|
|
||||||
"survey_type": "Tipo de encuesta",
|
"survey_type": "Tipo de encuesta",
|
||||||
"surveys": "Encuestas",
|
"surveys": "Encuestas",
|
||||||
"table_items_deleted_successfully": "{type}s eliminados correctamente",
|
"table_items_deleted_successfully": "{type}s eliminados correctamente",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Proyectos",
|
"workspaces": "Proyectos",
|
||||||
"years": "años",
|
"years": "años",
|
||||||
"yes": "Sí",
|
"yes": "Sí",
|
||||||
|
"you": "Tú",
|
||||||
"you_are_downgraded_to_the_community_edition": "Has sido degradado a la edición Community.",
|
"you_are_downgraded_to_the_community_edition": "Has sido degradado a la edición Community.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "No tienes autorización para realizar esta acción.",
|
"you_are_not_authorized_to_perform_this_action": "No tienes autorización para realizar esta acción.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Has alcanzado tu límite de {workspaceLimit} espacios de trabajo.",
|
"you_have_reached_your_limit_of_workspace_limit": "Has alcanzado tu límite de {workspaceLimit} espacios de trabajo.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "El equipo de Formbricks",
|
"email_footer_text_2": "El equipo de Formbricks",
|
||||||
"email_template_text_1": "Este correo electrónico fue enviado a través de Formbricks.",
|
"email_template_text_1": "Este correo electrónico fue enviado a través de Formbricks.",
|
||||||
"embed_survey_preview_email_didnt_request": "¿No lo has solicitado?",
|
"embed_survey_preview_email_didnt_request": "¿No lo has solicitado?",
|
||||||
|
"embed_survey_preview_email_environment_id": "ID de entorno",
|
||||||
"embed_survey_preview_email_fight_spam": "Ayúdanos a combatir el spam y reenvía este correo a hola@formbricks.com",
|
"embed_survey_preview_email_fight_spam": "Ayúdanos a combatir el spam y reenvía este correo a hola@formbricks.com",
|
||||||
"embed_survey_preview_email_heading": "Vista previa del correo electrónico incrustado",
|
"embed_survey_preview_email_heading": "Vista previa del correo electrónico incrustado",
|
||||||
"embed_survey_preview_email_subject": "Vista previa de la encuesta por correo electrónico de Formbricks",
|
"embed_survey_preview_email_subject": "Vista previa de la encuesta por correo electrónico de Formbricks",
|
||||||
"embed_survey_preview_email_text": "Así es como se ve el fragmento de código incrustado en un correo electrónico:",
|
"embed_survey_preview_email_text": "Así es como se ve el fragmento de código incrustado en un correo electrónico:",
|
||||||
"embed_survey_preview_email_workspace_id": "ID del espacio de trabajo",
|
|
||||||
"forgot_password_email_change_password": "Cambiar contraseña",
|
"forgot_password_email_change_password": "Cambiar contraseña",
|
||||||
"forgot_password_email_did_not_request": "Si no has solicitado esto, por favor ignora este correo electrónico.",
|
"forgot_password_email_did_not_request": "Si no has solicitado esto, por favor ignora este correo electrónico.",
|
||||||
"forgot_password_email_heading": "Cambiar contraseña",
|
"forgot_password_email_heading": "Cambiar contraseña",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Vista previa de la pregunta",
|
"question_preview": "Vista previa de la pregunta",
|
||||||
"response_already_received": "Ya hemos recibido una respuesta para esta dirección de correo electrónico.",
|
"response_already_received": "Ya hemos recibido una respuesta para esta dirección de correo electrónico.",
|
||||||
"response_submitted": "Ya existe una respuesta vinculada a esta encuesta y contacto",
|
"response_submitted": "Ya existe una respuesta vinculada a esta encuesta y contacto",
|
||||||
"scheduled": "Esta encuesta está programada para publicarse pronto.",
|
|
||||||
"survey_already_answered_heading": "La encuesta ya ha sido respondida.",
|
"survey_already_answered_heading": "La encuesta ya ha sido respondida.",
|
||||||
"survey_already_answered_subheading": "Solo puedes usar este enlace una vez.",
|
"survey_already_answered_subheading": "Solo puedes usar este enlace una vez.",
|
||||||
"survey_sent_to": "Encuesta enviada a {email}",
|
"survey_sent_to": "Encuesta enviada a {email}",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Otro",
|
"career_development_survey_question_6_choice_6": "Otro",
|
||||||
"career_development_survey_question_6_headline": "¿Cuál de las siguientes opciones describe mejor tu nivel de trabajo actual?",
|
"career_development_survey_question_6_headline": "¿Cuál de las siguientes opciones describe mejor tu nivel de trabajo actual?",
|
||||||
"career_development_survey_question_6_subheader": "Por favor, selecciona una de las siguientes opciones",
|
"career_development_survey_question_6_subheader": "Por favor, selecciona una de las siguientes opciones",
|
||||||
"ces": "Esfuerzo del Cliente (CES)",
|
|
||||||
"ces_description": "Mide la Puntuación de Esfuerzo del Cliente (1-5 o 1-7)",
|
|
||||||
"ces_lower_label": "Muy difícil",
|
|
||||||
"ces_upper_label": "Muy fácil",
|
|
||||||
"cess_survey_name": "Encuesta CES",
|
"cess_survey_name": "Encuesta CES",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] me facilita [AÑADIR OBJETIVO]",
|
"cess_survey_question_1_headline": "$[workspaceName] me facilita [AÑADIR OBJETIVO]",
|
||||||
"cess_survey_question_1_lower_label": "Totalmente en desacuerdo",
|
"cess_survey_question_1_lower_label": "Totalmente en desacuerdo",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Solicitar aceptación de términos, condiciones o uso de datos",
|
"consent_description": "Solicitar aceptación de términos, condiciones o uso de datos",
|
||||||
"contact_info": "Información de contacto",
|
"contact_info": "Información de contacto",
|
||||||
"contact_info_description": "Solicitar nombre, apellidos, correo electrónico, número de teléfono y empresa conjuntamente",
|
"contact_info_description": "Solicitar nombre, apellidos, correo electrónico, número de teléfono y empresa conjuntamente",
|
||||||
"csat": "Satisfacción del Cliente (CSAT)",
|
"csat_description": "Mide el índice de satisfacción del cliente de tu producto o servicio.",
|
||||||
"csat_description": "Mide la Puntuación de Satisfacción del Cliente (1-5)",
|
|
||||||
"csat_lower_label": "Muy insatisfecho",
|
|
||||||
"csat_name": "Índice de satisfacción del cliente (CSAT)",
|
"csat_name": "Índice de satisfacción del cliente (CSAT)",
|
||||||
"csat_question_10_headline": "¿Tienes algún otro comentario, pregunta o inquietud?",
|
"csat_question_10_headline": "¿Tienes algún otro comentario, pregunta o inquietud?",
|
||||||
"csat_question_10_placeholder": "Escribe tu respuesta aquí...",
|
"csat_question_10_placeholder": "Escribe tu respuesta aquí...",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Escribe tu respuesta aquí...",
|
"csat_survey_question_2_placeholder": "Escribe tu respuesta aquí...",
|
||||||
"csat_survey_question_3_headline": "Vaya, ¡lo sentimos! ¿Hay algo que podamos hacer para mejorar tu experiencia?",
|
"csat_survey_question_3_headline": "Vaya, ¡lo sentimos! ¿Hay algo que podamos hacer para mejorar tu experiencia?",
|
||||||
"csat_survey_question_3_placeholder": "Escribe tu respuesta aquí...",
|
"csat_survey_question_3_placeholder": "Escribe tu respuesta aquí...",
|
||||||
"csat_upper_label": "Muy satisfecho",
|
|
||||||
"cta_description": "Muestra información y anima a los usuarios a realizar una acción específica",
|
"cta_description": "Muestra información y anima a los usuarios a realizar una acción específica",
|
||||||
"custom_survey_description": "Crea una encuesta sin plantilla.",
|
"custom_survey_description": "Crea una encuesta sin plantilla.",
|
||||||
"custom_survey_name": "Empezar desde cero",
|
"custom_survey_name": "Empezar desde cero",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "¿Qué es una cosa que podríamos mejorar?",
|
"gauge_feature_satisfaction_question_2_headline": "¿Qué es una cosa que podríamos mejorar?",
|
||||||
"identify_customer_goals_description": "Comprende mejor si tus mensajes crean las expectativas correctas sobre el valor que proporciona tu producto.",
|
"identify_customer_goals_description": "Comprende mejor si tus mensajes crean las expectativas correctas sobre el valor que proporciona tu producto.",
|
||||||
"identify_customer_goals_name": "Identificar objetivos del cliente",
|
"identify_customer_goals_name": "Identificar objetivos del cliente",
|
||||||
"identify_customer_goals_question_1_choice_1": "Conocer a fondo mi base de usuarios",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Identificar oportunidades de venta adicional",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "Construir el mejor producto posible",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "Dominar el mundo para hacer que todos desayunen coles de Bruselas",
|
|
||||||
"identify_customer_goals_question_1_headline": "¿Cuál es tu objetivo principal al usar $[workspaceName]?",
|
|
||||||
"identify_sign_up_barriers_description": "Ofrece un descuento para obtener información sobre las barreras de registro.",
|
"identify_sign_up_barriers_description": "Ofrece un descuento para obtener información sobre las barreras de registro.",
|
||||||
"identify_sign_up_barriers_name": "Identificar barreras de registro",
|
"identify_sign_up_barriers_name": "Identificar barreras de registro",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Obtener 10 % de descuento",
|
"identify_sign_up_barriers_question_1_button_label": "Obtener 10 % de descuento",
|
||||||
@@ -1164,8 +1145,6 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Ayúdanos a entenderte mejor:",
|
"improve_trial_conversion_question_1_subheader": "Ayúdanos a entenderte mejor:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Siguiente",
|
"improve_trial_conversion_question_2_button_label": "Siguiente",
|
||||||
"improve_trial_conversion_question_2_headline": "Lamentamos oírlo. ¿Cuál fue el mayor problema al usar $[workspaceName]?",
|
"improve_trial_conversion_question_2_headline": "Lamentamos oírlo. ¿Cuál fue el mayor problema al usar $[workspaceName]?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Siguiente",
|
|
||||||
"improve_trial_conversion_question_3_headline": "¿Qué esperabas que hiciera $[workspaceName]?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "Obtener 20 % de descuento",
|
"improve_trial_conversion_question_4_button_label": "Obtener 20 % de descuento",
|
||||||
"improve_trial_conversion_question_4_headline": "¡Sentimos oírlo! Obtén un 20 % de descuento en el primer año.",
|
"improve_trial_conversion_question_4_headline": "¡Sentimos oírlo! Obtén un 20 % de descuento en el primer año.",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Nos complace ofrecerte un 20 % de descuento en un plan anual.</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Nos complace ofrecerte un 20 % de descuento en un plan anual.</span></p>",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Esta acción se activará cuando se cargue la página.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Esta acción se activará cuando se cargue la página.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Esta acción se activará cuando el usuario desplace el 50 % de la página.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Esta acción se activará cuando el usuario desplace el 50 % de la página.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Esta acción se activará cuando el usuario intente abandonar la página.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Esta acción se activará cuando el usuario intente abandonar la página.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Esta es una acción de código. Por favor, realiza cambios en tu base de código.",
|
||||||
"time_in_seconds": "Tiempo en segundos",
|
"time_in_seconds": "Tiempo en segundos",
|
||||||
"time_in_seconds_placeholder": "p. ej. 10",
|
"time_in_seconds_placeholder": "p. ej. 10",
|
||||||
"time_in_seconds_with_unit": "{seconds}s",
|
"time_in_seconds_with_unit": "{seconds}s",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "Clave API actualizada",
|
"api_key_updated": "Clave API actualizada",
|
||||||
"delete_api_key_confirmation": "Cualquier aplicación que use esta clave ya no podrá acceder a tus datos de Formbricks.",
|
"delete_api_key_confirmation": "Cualquier aplicación que use esta clave ya no podrá acceder a tus datos de Formbricks.",
|
||||||
"duplicate_access": "No se permite el acceso duplicado al espacio de trabajo",
|
"duplicate_access": "No se permite el acceso duplicado al espacio de trabajo",
|
||||||
"duplicate_directory_access": "No se permite el acceso duplicado al directorio de registros de feedback",
|
|
||||||
"feedback_record_directory_access": "Acceso al Directorio de Registros de Feedback",
|
|
||||||
"no_api_keys_yet": "Aún no tienes ninguna clave API",
|
"no_api_keys_yet": "Aún no tienes ninguna clave API",
|
||||||
"no_directory_permissions_found": "No se encontraron permisos de directorio de registros de feedback",
|
"no_env_permissions_found": "No se encontraron permisos de entorno",
|
||||||
"no_workspace_permissions_found": "No se encontraron permisos del espacio de trabajo",
|
|
||||||
"organization_access": "Acceso a la organización",
|
"organization_access": "Acceso a la organización",
|
||||||
"organization_access_description": "Selecciona privilegios de lectura o escritura para recursos de toda la organización.",
|
"organization_access_description": "Selecciona privilegios de lectura o escritura para recursos de toda la organización.",
|
||||||
"permissions": "Permisos",
|
"permissions": "Permisos",
|
||||||
"secret": "Secreto",
|
"secret": "Secreto",
|
||||||
"unable_to_copy_api_key": "No se puede copiar la clave de API",
|
|
||||||
"unable_to_delete_api_key": "No se puede eliminar la clave API",
|
"unable_to_delete_api_key": "No se puede eliminar la clave API",
|
||||||
"unknown_directory": "Directorio desconocido",
|
|
||||||
"unknown_workspace": "Espacio de trabajo desconocido",
|
|
||||||
"workspace_access": "Acceso al espacio de trabajo"
|
"workspace_access": "Acceso al espacio de trabajo"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Conecta tu aplicación o sitio web a Formbricks.",
|
"app_connection_description": "Conecta tu aplicación o sitio web a Formbricks.",
|
||||||
"cache_update_delay_description": "Cuando realizas actualizaciones en encuestas, contactos, acciones u otros datos, puede tardar hasta 1 minuto en que esos cambios aparezcan en tu aplicación local que ejecuta el SDK de Formbricks.",
|
"cache_update_delay_description": "Cuando realizas actualizaciones en encuestas, contactos, acciones u otros datos, puede tardar hasta 1 minuto en que esos cambios aparezcan en tu aplicación local que ejecuta el SDK de Formbricks.",
|
||||||
"cache_update_delay_title": "Los cambios se reflejarán después de ~1 minuto debido al almacenamiento en caché",
|
"cache_update_delay_title": "Los cambios se reflejarán después de ~1 minuto debido al almacenamiento en caché",
|
||||||
|
"environment_id": "ID de tu espacio de trabajo",
|
||||||
|
"environment_id_description": "Este ID identifica de forma única este espacio de trabajo de Formbricks.",
|
||||||
"formbricks_sdk_connected": "El SDK de Formbricks está conectado",
|
"formbricks_sdk_connected": "El SDK de Formbricks está conectado",
|
||||||
"formbricks_sdk_not_connected": "El SDK de Formbricks aún no está conectado.",
|
"formbricks_sdk_not_connected": "El SDK de Formbricks aún no está conectado.",
|
||||||
"formbricks_sdk_not_connected_description": "Añade el SDK de Formbricks a tu sitio web o aplicación para conectarlo con Formbricks",
|
"formbricks_sdk_not_connected_description": "Añade el SDK de Formbricks a tu sitio web o aplicación para conectarlo con Formbricks",
|
||||||
@@ -1866,12 +1842,10 @@
|
|||||||
"receiving_data": "Recibiendo datos 💃🕺",
|
"receiving_data": "Recibiendo datos 💃🕺",
|
||||||
"recheck": "Volver a comprobar",
|
"recheck": "Volver a comprobar",
|
||||||
"sdk_connection_details": "Detalles de conexión del SDK",
|
"sdk_connection_details": "Detalles de conexión del SDK",
|
||||||
"sdk_connection_details_description": "Tu ID único de espacio de trabajo y URL de conexión del SDK para integrar Formbricks con tu aplicación.",
|
"sdk_connection_details_description": "Tu ID de espacio de trabajo único y la URL de conexión del SDK para integrar Formbricks con tu aplicación.",
|
||||||
"setup_alert_description": "Sigue este tutorial paso a paso para conectar tu aplicación o sitio web en menos de 5 minutos.",
|
"setup_alert_description": "Sigue este tutorial paso a paso para conectar tu aplicación o sitio web en menos de 5 minutos.",
|
||||||
"setup_alert_title": "Cómo conectar",
|
"setup_alert_title": "Cómo conectar",
|
||||||
"webapp_url": "URL de conexión del SDK",
|
"webapp_url": "URL de conexión del SDK"
|
||||||
"workspace_id": "ID de tu espacio de trabajo",
|
|
||||||
"workspace_id_description": "Este ID identifica de forma única este espacio de trabajo de Formbricks."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "¡Enhorabuena!",
|
"congrats": "¡Enhorabuena!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Valor del atributo",
|
"attribute_value_placeholder": "Valor del atributo",
|
||||||
"attributes_msg_attribute_limit_exceeded": "No se pudieron crear {count} atributo(s) nuevo(s) ya que se excedería el límite máximo de {limit} clases de atributos. Los atributos existentes se actualizaron correctamente.",
|
"attributes_msg_attribute_limit_exceeded": "No se pudieron crear {count} atributo(s) nuevo(s) ya que se excedería el límite máximo de {limit} clases de atributos. Los atributos existentes se actualizaron correctamente.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (el atributo “{key}” tiene dataType: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (el atributo “{key}” tiene dataType: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "El correo electrónico ya existe para este espacio de trabajo y no se actualizó.",
|
"attributes_msg_email_already_exists": "El email ya existe para este entorno y no se actualizó.",
|
||||||
"attributes_msg_email_or_userid_required": "Se requiere el correo electrónico o el ID de usuario. Se conservaron los valores existentes.",
|
"attributes_msg_email_or_userid_required": "Se requiere el correo electrónico o el ID de usuario. Se conservaron los valores existentes.",
|
||||||
"attributes_msg_new_attribute_created": "Se creó el atributo nuevo “{key}” con el tipo “{dataType}”",
|
"attributes_msg_new_attribute_created": "Se creó el atributo nuevo “{key}” con el tipo “{dataType}”",
|
||||||
"attributes_msg_userid_already_exists": "El ID de usuario ya existe para este espacio de trabajo y no se actualizó.",
|
"attributes_msg_userid_already_exists": "El ID de usuario ya existe para este entorno y no se actualizó.",
|
||||||
"contact_deleted_successfully": "Contacto eliminado correctamente",
|
"contact_deleted_successfully": "Contacto eliminado correctamente",
|
||||||
"contacts_table_refresh": "Actualizar contactos",
|
"contacts_table_refresh": "Actualizar contactos",
|
||||||
"contacts_table_refresh_success": "Contactos actualizados correctamente",
|
"contacts_table_refresh_success": "Contactos actualizados correctamente",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Idioma o ID de idioma duplicado",
|
"duplicate_language_or_language_id": "Idioma o ID de idioma duplicado",
|
||||||
"edit_languages": "Editar idiomas",
|
"edit_languages": "Editar idiomas",
|
||||||
"identifier": "Identificador (ISO)",
|
"identifier": "Identificador (ISO)",
|
||||||
|
"incomplete_translations": "Traducciones incompletas",
|
||||||
"language": "Idioma",
|
"language": "Idioma",
|
||||||
"language_deleted_successfully": "Idioma eliminado correctamente",
|
"language_deleted_successfully": "Idioma eliminado correctamente",
|
||||||
"languages_updated_successfully": "Idiomas actualizados correctamente",
|
"languages_updated_successfully": "Idiomas actualizados correctamente",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Por favor, selecciona un idioma",
|
"please_select_a_language": "Por favor, selecciona un idioma",
|
||||||
"remove_language": "Eliminar idioma",
|
"remove_language": "Eliminar idioma",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Por favor, elimina el idioma de estas encuestas para poder eliminarlo del espacio de trabajo.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Por favor, elimina el idioma de estas encuestas para poder eliminarlo del espacio de trabajo.",
|
||||||
"search_items": "Buscar elementos"
|
"search_items": "Buscar elementos",
|
||||||
|
"translate": "Traducir"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Añadir color de fondo",
|
"add_background_color": "Añadir color de fondo",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "¡Todo listo! Es hora de crear tu primera encuesta",
|
"all_set_time_to_create_first_survey": "¡Todo listo! Es hora de crear tu primera encuesta",
|
||||||
"alphabetical": "Alfabético",
|
"alphabetical": "Alfabético",
|
||||||
|
"copy_survey": "Copiar encuesta",
|
||||||
|
"copy_survey_description": "Copia esta encuesta a otro espacio de trabajo",
|
||||||
|
"copy_survey_error": "Error al copiar la encuesta",
|
||||||
"copy_survey_link_to_clipboard": "Copiar enlace de la encuesta al portapapeles",
|
"copy_survey_link_to_clipboard": "Copiar enlace de la encuesta al portapapeles",
|
||||||
|
"copy_survey_no_workspaces": "No hay otros espacios de trabajo a los que copiar esta encuesta.",
|
||||||
|
"copy_survey_partially_success": "{success} encuestas copiadas correctamente, {error} fallidas.",
|
||||||
|
"copy_survey_success": "¡Encuesta copiada correctamente!",
|
||||||
"delete_survey_and_responses_warning": "¿Estás seguro de que quieres eliminar esta encuesta y todas sus respuestas?",
|
"delete_survey_and_responses_warning": "¿Estás seguro de que quieres eliminar esta encuesta y todas sus respuestas?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Activar traducciones",
|
"1_choose_the_default_language_for_this_survey": "1. Elige el idioma predeterminado para esta encuesta:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Activa la traducción para idiomas específicos:",
|
||||||
"add": "Añadir +",
|
"add": "Añadir +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Añadir un retraso o cerrar automáticamente la encuesta",
|
"add_a_delay_or_auto_close_the_survey": "Añadir un retraso o cerrar automáticamente la encuesta",
|
||||||
"add_a_four_digit_pin": "Añadir un PIN de cuatro dígitos",
|
"add_a_four_digit_pin": "Añadir un PIN de cuatro dígitos",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Audiencia",
|
"audience": "Audiencia",
|
||||||
"auto_close_on_inactivity": "Cierre automático por inactividad",
|
"auto_close_on_inactivity": "Cierre automático por inactividad",
|
||||||
"auto_progress_rating_and_nps": "Avanzar automáticamente en preguntas de valoración y NPS",
|
"auto_progress_rating_and_nps": "Avanzar automáticamente en preguntas de valoración y NPS",
|
||||||
"auto_progress_rating_and_nps_description": "Avance automático en bloques de una sola pregunta. Las preguntas obligatorias ocultan el botón Siguiente, excepto cuando se selecciona \"Otro\".",
|
"auto_progress_rating_and_nps_description": "Avanza automáticamente cuando los encuestados seleccionen una respuesta en preguntas de valoración o NPS. Esto solo se aplica a bloques de una sola pregunta. Las preguntas obligatorias ocultan el botón Siguiente; las preguntas opcionales aún lo muestran para omitirlas.",
|
||||||
"auto_save_disabled": "Guardado automático desactivado",
|
"auto_save_disabled": "Guardado automático desactivado",
|
||||||
"auto_save_disabled_tooltip": "Su encuesta solo se guarda automáticamente cuando está en borrador. Esto asegura que las encuestas públicas no se actualicen involuntariamente.",
|
"auto_save_disabled_tooltip": "Su encuesta solo se guarda automáticamente cuando está en borrador. Esto asegura que las encuestas públicas no se actualicen involuntariamente.",
|
||||||
"auto_save_on": "Guardado automático activado",
|
"auto_save_on": "Guardado automático activado",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "Los cambios provocarán inconsistencias",
|
"caution_text": "Los cambios provocarán inconsistencias",
|
||||||
"change_anyway": "Cambiar de todos modos",
|
"change_anyway": "Cambiar de todos modos",
|
||||||
"change_background": "Cambiar fondo",
|
"change_background": "Cambiar fondo",
|
||||||
"change_default": "Cambiar predeterminado",
|
|
||||||
"change_question_type": "Cambiar tipo de pregunta",
|
"change_question_type": "Cambiar tipo de pregunta",
|
||||||
"change_survey_type": "Cambiar el tipo de encuesta afecta al acceso existente",
|
"change_survey_type": "Cambiar el tipo de encuesta afecta al acceso existente",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Cambiar el fondo a un color, imagen o animación.",
|
"change_the_background_to_a_color_image_or_animation": "Cambiar el fondo a un color, imagen o animación.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Elige la primera pregunta en tu bloque",
|
"choose_the_first_question_on_your_block": "Elige la primera pregunta en tu bloque",
|
||||||
"choose_where_to_run_the_survey": "Elige dónde ejecutar la encuesta.",
|
"choose_where_to_run_the_survey": "Elige dónde ejecutar la encuesta.",
|
||||||
"city": "Ciudad",
|
"city": "Ciudad",
|
||||||
"clear_close_on_date": "Borrar fecha de pausa",
|
|
||||||
"clear_publish_on_date": "Borrar fecha de publicación",
|
|
||||||
"close_survey_on_date": "Fecha de pausa",
|
|
||||||
"close_survey_on_response_limit": "Cerrar encuesta al alcanzar el límite de respuestas",
|
"close_survey_on_response_limit": "Cerrar encuesta al alcanzar el límite de respuestas",
|
||||||
"code": "Código",
|
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"column_used_in_logic_error": "Esta columna se usa en la lógica de la pregunta {questionIndex}. Por favor, elimínala de la lógica primero.",
|
"column_used_in_logic_error": "Esta columna se usa en la lógica de la pregunta {questionIndex}. Por favor, elimínala de la lógica primero.",
|
||||||
"columns": "Columnas",
|
"columns": "Columnas",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "Personalizar el logotipo de la encuesta",
|
"customize_survey_logo": "Personalizar el logotipo de la encuesta",
|
||||||
"darken_or_lighten_background_of_your_choice": "Oscurece o aclara el fondo de tu elección.",
|
"darken_or_lighten_background_of_your_choice": "Oscurece o aclara el fondo de tu elección.",
|
||||||
"days_before_showing_this_survey_again": "o más días deben transcurrir entre la última encuesta mostrada y la visualización de esta encuesta.",
|
"days_before_showing_this_survey_again": "o más días deben transcurrir entre la última encuesta mostrada y la visualización de esta encuesta.",
|
||||||
"default_language": "Idioma predeterminado",
|
|
||||||
"delete_anyways": "Eliminar de todos modos",
|
"delete_anyways": "Eliminar de todos modos",
|
||||||
"delete_block": "Eliminar bloque",
|
"delete_block": "Eliminar bloque",
|
||||||
"delete_choice": "Eliminar opción",
|
"delete_choice": "Eliminar opción",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Duplicar pregunta",
|
"duplicate_question": "Duplicar pregunta",
|
||||||
"edit_link": "Editar enlace",
|
"edit_link": "Editar enlace",
|
||||||
"edit_recall": "Editar recuperación",
|
"edit_recall": "Editar recuperación",
|
||||||
|
"edit_translations": "Editar traducciones de {lang}",
|
||||||
"element_not_found": "Pregunta no encontrada",
|
"element_not_found": "Pregunta no encontrada",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permitir a los participantes cambiar el idioma de la encuesta en cualquier momento durante la encuesta.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permitir a los participantes cambiar el idioma de la encuesta en cualquier momento durante la encuesta.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "La protección contra spam utiliza reCAPTCHA v3 para filtrar las respuestas spam.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "La protección contra spam utiliza reCAPTCHA v3 para filtrar las respuestas spam.",
|
||||||
@@ -3014,12 +2992,10 @@
|
|||||||
"long_answer_toggle_description": "Permitir a los encuestados escribir respuestas más largas y de varias líneas.",
|
"long_answer_toggle_description": "Permitir a los encuestados escribir respuestas más largas y de varias líneas.",
|
||||||
"lower_label": "Etiqueta inferior",
|
"lower_label": "Etiqueta inferior",
|
||||||
"manage_languages": "Gestionar idiomas",
|
"manage_languages": "Gestionar idiomas",
|
||||||
"manage_translations": "Gestionar traducciones",
|
|
||||||
"matrix_all_fields": "Todos los campos",
|
"matrix_all_fields": "Todos los campos",
|
||||||
"matrix_rows": "Filas",
|
"matrix_rows": "Filas",
|
||||||
"max_file_size": "Tamaño máximo de archivo",
|
"max_file_size": "Tamaño máximo de archivo",
|
||||||
"max_file_size_limit_is": "El límite de tamaño máximo de archivo es",
|
"max_file_size_limit_is": "El límite de tamaño máximo de archivo es",
|
||||||
"missing_first": "Faltantes primero",
|
|
||||||
"move_question_to_block": "Mover pregunta al bloque",
|
"move_question_to_block": "Mover pregunta al bloque",
|
||||||
"multiply": "Multiplicar *",
|
"multiply": "Multiplicar *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Necesario para una instancia Cal.com autohospedada",
|
"needed_for_self_hosted_cal_com_instance": "Necesario para una instancia Cal.com autohospedada",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "Etiqueta del botón \"Siguiente\"",
|
"next_button_label": "Etiqueta del botón \"Siguiente\"",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Aún no hay campos ocultos. Añade el primero a continuación.",
|
"no_hidden_fields_yet_add_first_one_below": "Aún no hay campos ocultos. Añade el primero a continuación.",
|
||||||
"no_images_found_for": "No se encontraron imágenes para ''{query}\"",
|
"no_images_found_for": "No se encontraron imágenes para ''{query}\"",
|
||||||
"no_languages_found_add_first_one_to_get_started": "No se encontraron idiomas de encuesta en este espacio de trabajo. Por favor, añade uno para comenzar.",
|
"no_languages_found_add_first_one_to_get_started": "No se encontraron idiomas. Añade el primero para comenzar.",
|
||||||
"no_option_found": "No se encontró ninguna opción",
|
"no_option_found": "No se encontró ninguna opción",
|
||||||
"no_recall_items_found": "No se encontraron elementos de recuperación",
|
"no_recall_items_found": "No se encontraron elementos de recuperación",
|
||||||
"no_variables_yet_add_first_one_below": "No hay variables todavía. Añade la primera a continuación.",
|
"no_variables_yet_add_first_one_below": "No hay variables todavía. Añade la primera a continuación.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Por favor, introduce una URL válida (p. ej., https://example.com)",
|
"please_enter_a_valid_url": "Por favor, introduce una URL válida (p. ej., https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Establece un disparador de encuesta",
|
"please_set_a_survey_trigger": "Establece un disparador de encuesta",
|
||||||
"please_specify": "Por favor, especifica",
|
"please_specify": "Por favor, especifica",
|
||||||
"present_your_survey_in_multiple_languages": "Presenta tu encuesta en varios idiomas",
|
|
||||||
"prevent_double_submission": "Evitar envío duplicado",
|
"prevent_double_submission": "Evitar envío duplicado",
|
||||||
"prevent_double_submission_description": "Permitir solo 1 respuesta por dirección de correo electrónico",
|
"prevent_double_submission_description": "Permitir solo 1 respuesta por dirección de correo electrónico",
|
||||||
"progress_saved": "Progreso guardado",
|
"progress_saved": "Progreso guardado",
|
||||||
"protect_survey_with_pin": "Proteger encuesta con un PIN",
|
"protect_survey_with_pin": "Proteger encuesta con un PIN",
|
||||||
"protect_survey_with_pin_description": "Solo los usuarios que tengan el PIN pueden acceder a la encuesta.",
|
"protect_survey_with_pin_description": "Solo los usuarios que tengan el PIN pueden acceder a la encuesta.",
|
||||||
"publish": "Publicar",
|
"publish": "Publicar",
|
||||||
"publish_survey_on_date": "Fecha de publicación",
|
|
||||||
"question": "Pregunta",
|
"question": "Pregunta",
|
||||||
"question_deleted": "Pregunta eliminada.",
|
"question_deleted": "Pregunta eliminada.",
|
||||||
"question_duplicated": "Pregunta duplicada.",
|
"question_duplicated": "Pregunta duplicada.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Filas",
|
"rows": "Filas",
|
||||||
"save_and_close": "Guardar y cerrar",
|
"save_and_close": "Guardar y cerrar",
|
||||||
"scale": "Escala",
|
"scale": "Escala",
|
||||||
"schedule_survey": "Programar encuesta",
|
|
||||||
"search_for_images": "Buscar imágenes",
|
"search_for_images": "Buscar imágenes",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "segundos después de activarse, la encuesta se cerrará si no hay respuesta",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "segundos después de activarse, la encuesta se cerrará si no hay respuesta",
|
||||||
"seconds_before_showing_the_survey": "segundos antes de mostrar la encuesta.",
|
"seconds_before_showing_the_survey": "segundos antes de mostrar la encuesta.",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 puntos",
|
"seven_points": "7 puntos",
|
||||||
"show_block_settings": "Mostrar ajustes del bloque",
|
"show_block_settings": "Mostrar ajustes del bloque",
|
||||||
"show_button": "Mostrar botón",
|
"show_button": "Mostrar botón",
|
||||||
"show_in_order": "Mostrar en orden",
|
|
||||||
"show_language_switch": "Mostrar cambio de idioma",
|
"show_language_switch": "Mostrar cambio de idioma",
|
||||||
"show_multiple_times": "Mostrar un número limitado de veces",
|
"show_multiple_times": "Mostrar un número limitado de veces",
|
||||||
"show_only_once": "Mostrar solo una vez",
|
"show_only_once": "Mostrar solo una vez",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Vista previa de la encuesta 👀",
|
"survey_preview": "Vista previa de la encuesta 👀",
|
||||||
"survey_styling": "Estilo del formulario",
|
"survey_styling": "Estilo del formulario",
|
||||||
"survey_trigger": "Activador de la encuesta",
|
"survey_trigger": "Activador de la encuesta",
|
||||||
"survey_will_be_closed_at_midnight_cet": "La encuesta se cerrará a las {time} en la zona horaria {timeZone} en la fecha seleccionada",
|
"switch_multi_language_on_to_get_started": "Activa el modo multiidioma para comenzar 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "La encuesta se publicará a las {time} en la zona horaria {timeZone} en la fecha seleccionada",
|
|
||||||
"target_block_not_found": "Bloque objetivo no encontrado",
|
"target_block_not_found": "Bloque objetivo no encontrado",
|
||||||
"targeted": "Dirigido",
|
"targeted": "Dirigido",
|
||||||
"ten_points": "10 puntos",
|
"ten_points": "10 puntos",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Mostrar una sola vez, incluso si no responden.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Mostrar una sola vez, incluso si no responden.",
|
||||||
"then": "Entonces",
|
"then": "Entonces",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Esta acción eliminará todas las traducciones de esta encuesta.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Esta acción eliminará todas las traducciones de esta encuesta.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Esto eliminará este idioma y todas sus traducciones de esta encuesta. Esta acción no se puede deshacer.",
|
|
||||||
"three_points": "3 puntos",
|
"three_points": "3 puntos",
|
||||||
"times": "veces",
|
"times": "veces",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Para mantener la ubicación coherente en todas las encuestas, puedes",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Para mantener la ubicación coherente en todas las encuestas, puedes",
|
||||||
"translated": "Traducido",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Activar encuesta cuando se dispare una de las acciones...",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Activar encuesta cuando se dispare una de las acciones...",
|
||||||
"try_lollipop_or_mountain": "Prueba 'piruleta' o 'montaña'...",
|
"try_lollipop_or_mountain": "Prueba 'piruleta' o 'montaña'...",
|
||||||
"type_field_id": "Escribe el id del campo",
|
"type_field_id": "Escribe el id del campo",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Solo permite responder a personas con un correo electrónico real.",
|
"verify_email_before_submission_description": "Solo permite responder a personas con un correo electrónico real.",
|
||||||
"visibility_and_recontact": "Visibilidad y recontacto",
|
"visibility_and_recontact": "Visibilidad y recontacto",
|
||||||
"visibility_and_recontact_description": "Controla cuándo puede aparecer esta encuesta y con qué frecuencia puede volver a aparecer.",
|
"visibility_and_recontact_description": "Controla cuándo puede aparecer esta encuesta y con qué frecuencia puede volver a aparecer.",
|
||||||
"visible": "Visible",
|
|
||||||
"wait": "Esperar",
|
"wait": "Esperar",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Esperar unos segundos después del disparador antes de mostrar la encuesta",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Esperar unos segundos después del disparador antes de mostrar la encuesta",
|
||||||
"waiting_time_across_surveys": "Periodo de espera (entre encuestas)",
|
"waiting_time_across_surveys": "Periodo de espera (entre encuestas)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Configurar alertas",
|
"configure_alerts": "Configurar alertas",
|
||||||
"congrats": "¡Enhorabuena! Tu encuesta está activa.",
|
"congrats": "¡Enhorabuena! Tu encuesta está activa.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Conecta tu sitio web o aplicación con Formbricks para comenzar.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Conecta tu sitio web o aplicación con Formbricks para comenzar.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% Satisfechos",
|
|
||||||
"csat_satisfied_tooltip": "El {percentage}% de los encuestados dieron una puntuación de 4 o 5 (CSAT).",
|
|
||||||
"current_count": "Recuento actual",
|
"current_count": "Recuento actual",
|
||||||
"custom_range": "Rango personalizado...",
|
"custom_range": "Rango personalizado...",
|
||||||
"delete_all_existing_responses_and_displays": "Eliminar todas las respuestas y visualizaciones existentes",
|
"delete_all_existing_responses_and_displays": "Eliminar todas las respuestas y visualizaciones existentes",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "Descargando código QR",
|
"downloading_qr_code": "Descargando código QR",
|
||||||
"drop_offs": "Abandonos",
|
"drop_offs": "Abandonos",
|
||||||
"drop_offs_tooltip": "Número de veces que se ha iniciado la encuesta pero no se ha completado.",
|
"drop_offs_tooltip": "Número de veces que se ha iniciado la encuesta pero no se ha completado.",
|
||||||
"effort_score": "Puntuación de Esfuerzo",
|
"failed_to_copy_link": "Error al copiar el enlace",
|
||||||
"filter_added_successfully": "Filtro añadido correctamente",
|
"filter_added_successfully": "Filtro añadido correctamente",
|
||||||
"filter_updated_successfully": "Filtro actualizado correctamente",
|
"filter_updated_successfully": "Filtro actualizado correctamente",
|
||||||
"filtered_responses_csv": "Respuestas filtradas (CSV)",
|
"filtered_responses_csv": "Respuestas filtradas (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Límite",
|
"limit": "Límite",
|
||||||
"no_identified_impressions": "No hay impresiones de contactos identificados",
|
"no_identified_impressions": "No hay impresiones de contactos identificados",
|
||||||
"no_responses_found": "No se han encontrado respuestas",
|
"no_responses_found": "No se han encontrado respuestas",
|
||||||
"nps_promoters_tooltip": "El {percentage}% de los encuestados dieron una puntuación de 9 o 10 (promotores NPS).",
|
|
||||||
"other_values_found": "Otros valores encontrados",
|
"other_values_found": "Otros valores encontrados",
|
||||||
"overall": "General",
|
"overall": "General",
|
||||||
"promoters": "Promotores",
|
"promoters": "Promotores",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "El número de cuotas completadas por los encuestados.",
|
"quotas_completed_tooltip": "El número de cuotas completadas por los encuestados.",
|
||||||
"reset_survey": "Reiniciar encuesta",
|
"reset_survey": "Reiniciar encuesta",
|
||||||
"reset_survey_warning": "Reiniciar una encuesta elimina todas las respuestas y visualizaciones asociadas a esta encuesta. Esto no se puede deshacer.",
|
"reset_survey_warning": "Reiniciar una encuesta elimina todas las respuestas y visualizaciones asociadas a esta encuesta. Esto no se puede deshacer.",
|
||||||
|
"satisfied": "Satisfecho",
|
||||||
"selected_responses_csv": "Respuestas seleccionadas (CSV)",
|
"selected_responses_csv": "Respuestas seleccionadas (CSV)",
|
||||||
"selected_responses_excel": "Respuestas seleccionadas (Excel)",
|
"selected_responses_excel": "Respuestas seleccionadas (Excel)",
|
||||||
"setup_integrations": "Configurar integraciones",
|
"setup_integrations": "Configurar integraciones",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Número de veces que se ha iniciado la encuesta.",
|
"starts_tooltip": "Número de veces que se ha iniciado la encuesta.",
|
||||||
"survey_reset_successfully": "¡Encuesta restablecida correctamente! Se eliminaron {responseCount} respuestas y {displayCount} visualizaciones.",
|
"survey_reset_successfully": "¡Encuesta restablecida correctamente! Se eliminaron {responseCount} respuestas y {displayCount} visualizaciones.",
|
||||||
"survey_results": "Resultados de {surveyName}",
|
"survey_results": "Resultados de {surveyName}",
|
||||||
"survey_scheduled_successfully": "Encuesta programada correctamente",
|
|
||||||
"this_month": "Este mes",
|
"this_month": "Este mes",
|
||||||
"this_quarter": "Este trimestre",
|
"this_quarter": "Este trimestre",
|
||||||
"this_year": "Este año",
|
"this_year": "Este año",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "¡Encuesta eliminada correctamente!",
|
"survey_deleted_successfully": "¡Encuesta eliminada correctamente!",
|
||||||
"survey_duplicated_successfully": "Encuesta duplicada correctamente.",
|
"survey_duplicated_successfully": "Encuesta duplicada correctamente.",
|
||||||
|
"survey_duplication_error": "Error al duplicar la encuesta.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Todos los canales",
|
"all_channels": "Todos los canales",
|
||||||
"all_industries": "Todas las industrias",
|
"all_industries": "Todas las industrias",
|
||||||
|
|||||||
+35
-69
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Changer d'espace de travail",
|
"change_workspace": "Changer d'espace de travail",
|
||||||
"chart": "Graphique",
|
"chart": "Graphique",
|
||||||
"charts": "Graphiques",
|
"charts": "Graphiques",
|
||||||
"choice_n": "Choix {{n}}",
|
|
||||||
"choices": "Choix",
|
"choices": "Choix",
|
||||||
"choose_organization": "Choisir l'organisation",
|
"choose_organization": "Choisir l'organisation",
|
||||||
"choose_workspace": "Choisir un projet",
|
"choose_workspace": "Choisir un projet",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Fermer",
|
"close": "Fermer",
|
||||||
"code": "Code",
|
"code": "Code",
|
||||||
"collapse_rows": "Réduire les lignes",
|
"collapse_rows": "Réduire les lignes",
|
||||||
"column_n": "Colonne {{n}}",
|
|
||||||
"completed": "Terminé",
|
"completed": "Terminé",
|
||||||
"configuration": "Configurer",
|
"configuration": "Configuration",
|
||||||
"confirm": "Confirmer",
|
"confirm": "Confirmer",
|
||||||
"connect": "Connecter",
|
"connect": "Connecter",
|
||||||
"connect_formbricks": "Connecter Formbricks",
|
"connect_formbricks": "Connecter Formbricks",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Carte de fin",
|
"ending_card": "Carte de fin",
|
||||||
"enter_url": "Saisir l'URL",
|
"enter_url": "Saisir l'URL",
|
||||||
"enterprise_license": "Licence d'entreprise",
|
"enterprise_license": "Licence d'entreprise",
|
||||||
|
"environment": "Environnement",
|
||||||
"error": "Erreur",
|
"error": "Erreur",
|
||||||
"error_component_description": "Cette ressource n'existe pas ou vous n'avez pas les droits nécessaires pour y accéder.",
|
"error_component_description": "Cette ressource n'existe pas ou vous n'avez pas les droits nécessaires pour y accéder.",
|
||||||
"error_component_title": "Erreur de chargement des ressources",
|
"error_component_title": "Erreur de chargement des ressources",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Échec du chargement des organisations",
|
"failed_to_load_organizations": "Échec du chargement des organisations",
|
||||||
"failed_to_load_workspaces": "Échec du chargement des projets",
|
"failed_to_load_workspaces": "Échec du chargement des projets",
|
||||||
"failed_to_parse_csv": "Échec de l'analyse du CSV",
|
"failed_to_parse_csv": "Échec de l'analyse du CSV",
|
||||||
"field_placeholder": "Espace réservé {{field}}",
|
|
||||||
"filter": "Filtre",
|
"filter": "Filtre",
|
||||||
"finish": "Terminer",
|
"finish": "Terminer",
|
||||||
"first_name": "Prénom",
|
"first_name": "Prénom",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Générer",
|
"generate": "Générer",
|
||||||
"go_back": "Retourner",
|
"go_back": "Retourner",
|
||||||
"go_to_dashboard": "Aller au tableau de bord",
|
"go_to_dashboard": "Aller au tableau de bord",
|
||||||
"headline": "Titre principal",
|
|
||||||
"hidden": "Caché",
|
"hidden": "Caché",
|
||||||
"hidden_field": "Champ caché",
|
"hidden_field": "Champ caché",
|
||||||
"hidden_fields": "Champs cachés",
|
"hidden_fields": "Champs cachés",
|
||||||
"hide": "Masquer",
|
"hide": "Masquer",
|
||||||
"hide_column": "Cacher la colonne",
|
"hide_column": "Cacher la colonne",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
"images": "Images",
|
"images": "Images",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "Plus d'options",
|
"more_options": "Plus d'options",
|
||||||
"move_down": "Déplacer vers le bas",
|
"move_down": "Déplacer vers le bas",
|
||||||
"move_up": "Déplacer vers le haut",
|
"move_up": "Déplacer vers le haut",
|
||||||
|
"multiple_languages": "Plusieurs langues",
|
||||||
"my_product": "mon produit",
|
"my_product": "mon produit",
|
||||||
"name": "Nom",
|
"name": "Nom",
|
||||||
"new": "Nouveau",
|
"new": "Nouveau",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "Aucun résultat trouvé",
|
"no_result_found": "Aucun résultat trouvé",
|
||||||
"no_results": "Aucun résultat",
|
"no_results": "Aucun résultat",
|
||||||
"no_surveys_found": "Aucun sondage trouvé.",
|
"no_surveys_found": "Aucun sondage trouvé.",
|
||||||
"no_text_found": "Aucun texte trouvé",
|
|
||||||
"none_of_the_above": "Aucun des éléments ci-dessus",
|
"none_of_the_above": "Aucun des éléments ci-dessus",
|
||||||
"not_authenticated": "Vous n'êtes pas authentifié pour effectuer cette action.",
|
"not_authenticated": "Vous n'êtes pas authentifié pour effectuer cette action.",
|
||||||
"not_authorized": "Non autorisé",
|
"not_authorized": "Non autorisé",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Paramètres de l'organisation",
|
"organization_settings": "Paramètres de l'organisation",
|
||||||
"other": "Autre",
|
"other": "Autre",
|
||||||
"other_filters": "Autres filtres",
|
"other_filters": "Autres filtres",
|
||||||
"other_placeholder": "Autre espace réservé",
|
"others": "Autres",
|
||||||
"overlay_color": "Couleur de superposition",
|
"overlay_color": "Couleur de superposition",
|
||||||
"overview": "Aperçu",
|
"overview": "Aperçu",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Veuillez mettre à niveau votre plan",
|
"please_upgrade_your_plan": "Veuillez mettre à niveau votre plan",
|
||||||
"powered_by_formbricks": "Propulsé par Formbricks",
|
"powered_by_formbricks": "Propulsé par Formbricks",
|
||||||
"preview": "Aperçu",
|
"preview": "Aperçu",
|
||||||
|
"preview_survey": "Aperçu de l'enquête",
|
||||||
"privacy": "Politique de confidentialité",
|
"privacy": "Politique de confidentialité",
|
||||||
"product_manager": "Chef de produit",
|
"product_manager": "Chef de produit",
|
||||||
|
"production": "Production",
|
||||||
"profile": "Profil",
|
"profile": "Profil",
|
||||||
"profile_id": "Identifiant de profil",
|
"profile_id": "Identifiant de profil",
|
||||||
"progress": "Progression",
|
"progress": "Progression",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Recommencer",
|
"restart": "Recommencer",
|
||||||
"retry": "Réessayer",
|
"retry": "Réessayer",
|
||||||
"role": "Rôle",
|
"role": "Rôle",
|
||||||
"row_n": "Ligne {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Ventes",
|
"sales": "Ventes",
|
||||||
"save": "Enregistrer",
|
"save": "Enregistrer",
|
||||||
"save_as_draft": "Enregistrer comme brouillon",
|
"save_as_draft": "Enregistrer comme brouillon",
|
||||||
"save_changes": "Enregistrer les modifications",
|
"save_changes": "Enregistrer les modifications",
|
||||||
"save_without_scheduling": "Enregistrer sans planification",
|
|
||||||
"saving": "Sauvegarder",
|
"saving": "Sauvegarder",
|
||||||
"scheduled": "Planifié",
|
|
||||||
"search": "Recherche",
|
"search": "Recherche",
|
||||||
"search_charts": "Rechercher des graphiques...",
|
"search_charts": "Rechercher des graphiques...",
|
||||||
"security": "Sécurité",
|
"security": "Sécurité",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "Stockage de fichiers non configuré, les téléchargements risquent d'échouer",
|
"storage_not_configured": "Stockage de fichiers non configuré, les téléchargements risquent d'échouer",
|
||||||
"string": "Texte",
|
"string": "Texte",
|
||||||
"styling": "Style",
|
"styling": "Style",
|
||||||
"subheader": "Sous-titre",
|
|
||||||
"submit": "Soumettre",
|
"submit": "Soumettre",
|
||||||
"summary": "Résumé",
|
"summary": "Résumé",
|
||||||
"survey": "Enquête",
|
"survey": "Enquête",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Langues de l'enquête",
|
"survey_languages": "Langues de l'enquête",
|
||||||
"survey_live": "Sondage en direct",
|
"survey_live": "Sondage en direct",
|
||||||
"survey_paused": "Sondage en pause.",
|
"survey_paused": "Sondage en pause.",
|
||||||
"survey_scheduled": "Enquête planifiée.",
|
|
||||||
"survey_type": "Type de sondage",
|
"survey_type": "Type de sondage",
|
||||||
"surveys": "Enquêtes",
|
"surveys": "Enquêtes",
|
||||||
"table_items_deleted_successfully": "{type}s supprimés avec succès",
|
"table_items_deleted_successfully": "{type}s supprimés avec succès",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Projets",
|
"workspaces": "Projets",
|
||||||
"years": "années",
|
"years": "années",
|
||||||
"yes": "Oui",
|
"yes": "Oui",
|
||||||
|
"you": "Vous",
|
||||||
"you_are_downgraded_to_the_community_edition": "Vous êtes rétrogradé à l'édition communautaire.",
|
"you_are_downgraded_to_the_community_edition": "Vous êtes rétrogradé à l'édition communautaire.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "Vous n'êtes pas autorisé à effectuer cette action.",
|
"you_are_not_authorized_to_perform_this_action": "Vous n'êtes pas autorisé à effectuer cette action.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Vous avez atteint votre limite de {workspaceLimit} espaces de travail.",
|
"you_have_reached_your_limit_of_workspace_limit": "Vous avez atteint votre limite de {workspaceLimit} espaces de travail.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "L'équipe Formbricks",
|
"email_footer_text_2": "L'équipe Formbricks",
|
||||||
"email_template_text_1": "Cet e-mail a été envoyé via Formbricks.",
|
"email_template_text_1": "Cet e-mail a été envoyé via Formbricks.",
|
||||||
"embed_survey_preview_email_didnt_request": "Vous n'avez pas demandé cela ?",
|
"embed_survey_preview_email_didnt_request": "Vous n'avez pas demandé cela ?",
|
||||||
|
"embed_survey_preview_email_environment_id": "ID d'environnement",
|
||||||
"embed_survey_preview_email_fight_spam": "Aidez-nous à lutter contre le spam et transférez ce mail à hola@formbricks.com.",
|
"embed_survey_preview_email_fight_spam": "Aidez-nous à lutter contre le spam et transférez ce mail à hola@formbricks.com.",
|
||||||
"embed_survey_preview_email_heading": "Aperçu de l'email intégré",
|
"embed_survey_preview_email_heading": "Aperçu de l'email intégré",
|
||||||
"embed_survey_preview_email_subject": "Aperçu du sondage par e-mail Formbricks",
|
"embed_survey_preview_email_subject": "Aperçu du sondage par e-mail Formbricks",
|
||||||
"embed_survey_preview_email_text": "C'est ainsi que le code s'affiche intégré dans un e-mail :",
|
"embed_survey_preview_email_text": "C'est ainsi que le code s'affiche intégré dans un e-mail :",
|
||||||
"embed_survey_preview_email_workspace_id": "ID de l'espace de travail",
|
|
||||||
"forgot_password_email_change_password": "Changer le mot de passe",
|
"forgot_password_email_change_password": "Changer le mot de passe",
|
||||||
"forgot_password_email_did_not_request": "Si vous n'avez pas demandé cela, veuillez ignorer cet e-mail.",
|
"forgot_password_email_did_not_request": "Si vous n'avez pas demandé cela, veuillez ignorer cet e-mail.",
|
||||||
"forgot_password_email_heading": "Changer le mot de passe",
|
"forgot_password_email_heading": "Changer le mot de passe",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Aperçu de la question",
|
"question_preview": "Aperçu de la question",
|
||||||
"response_already_received": "Nous avons déjà reçu une réponse pour cette adresse e-mail.",
|
"response_already_received": "Nous avons déjà reçu une réponse pour cette adresse e-mail.",
|
||||||
"response_submitted": "Une réponse liée à cette enquête et à ce contact existe déjà",
|
"response_submitted": "Une réponse liée à cette enquête et à ce contact existe déjà",
|
||||||
"scheduled": "Cette enquête est planifiée pour être mise en ligne prochainement.",
|
|
||||||
"survey_already_answered_heading": "L'enquête a déjà été répondue.",
|
"survey_already_answered_heading": "L'enquête a déjà été répondue.",
|
||||||
"survey_already_answered_subheading": "Vous ne pouvez utiliser ce lien qu'une seule fois.",
|
"survey_already_answered_subheading": "Vous ne pouvez utiliser ce lien qu'une seule fois.",
|
||||||
"survey_sent_to": "Enquête envoyée à {email}",
|
"survey_sent_to": "Enquête envoyée à {email}",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Autre",
|
"career_development_survey_question_6_choice_6": "Autre",
|
||||||
"career_development_survey_question_6_headline": "Lequel des éléments suivants décrit le mieux votre niveau de poste actuel ?",
|
"career_development_survey_question_6_headline": "Lequel des éléments suivants décrit le mieux votre niveau de poste actuel ?",
|
||||||
"career_development_survey_question_6_subheader": "Veuillez sélectionner l'une des options suivantes.",
|
"career_development_survey_question_6_subheader": "Veuillez sélectionner l'une des options suivantes.",
|
||||||
"ces": "Effort Client (CES)",
|
|
||||||
"ces_description": "Mesurer le score d'effort client (1-5 ou 1-7)",
|
|
||||||
"ces_lower_label": "Très difficile",
|
|
||||||
"ces_upper_label": "Très facile",
|
|
||||||
"cess_survey_name": "Sondage CES",
|
"cess_survey_name": "Sondage CES",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] me facilite la tâche pour [AJOUTER L'OBJECTIF]",
|
"cess_survey_question_1_headline": "$[workspaceName] me facilite la tâche pour [AJOUTER L'OBJECTIF]",
|
||||||
"cess_survey_question_1_lower_label": "Pas du tout d'accord",
|
"cess_survey_question_1_lower_label": "Pas du tout d'accord",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Demander d'accepter les termes, conditions ou l'utilisation des données",
|
"consent_description": "Demander d'accepter les termes, conditions ou l'utilisation des données",
|
||||||
"contact_info": "Informations de contact",
|
"contact_info": "Informations de contact",
|
||||||
"contact_info_description": "Demandez le nom, le prénom, l'email, le numéro de téléphone et l'entreprise ensemble.",
|
"contact_info_description": "Demandez le nom, le prénom, l'email, le numéro de téléphone et l'entreprise ensemble.",
|
||||||
"csat": "Satisfaction Client (CSAT)",
|
"csat_description": "Mesurez le score de satisfaction client de votre produit ou service.",
|
||||||
"csat_description": "Mesurer le score de satisfaction client (1-5)",
|
|
||||||
"csat_lower_label": "Très insatisfait",
|
|
||||||
"csat_name": "Score de Satisfaction Client (CSAT)",
|
"csat_name": "Score de Satisfaction Client (CSAT)",
|
||||||
"csat_question_10_headline": "Avez-vous d'autres commentaires, questions ou préoccupations ?",
|
"csat_question_10_headline": "Avez-vous d'autres commentaires, questions ou préoccupations ?",
|
||||||
"csat_question_10_placeholder": "Entrez votre réponse ici...",
|
"csat_question_10_placeholder": "Entrez votre réponse ici...",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Entrez votre réponse ici...",
|
"csat_survey_question_2_placeholder": "Entrez votre réponse ici...",
|
||||||
"csat_survey_question_3_headline": "Ah, désolé ! Y a-t-il quelque chose que nous puissions faire pour améliorer votre expérience ?",
|
"csat_survey_question_3_headline": "Ah, désolé ! Y a-t-il quelque chose que nous puissions faire pour améliorer votre expérience ?",
|
||||||
"csat_survey_question_3_placeholder": "Entrez votre réponse ici...",
|
"csat_survey_question_3_placeholder": "Entrez votre réponse ici...",
|
||||||
"csat_upper_label": "Très satisfait",
|
|
||||||
"cta_description": "Afficher des informations et inciter les utilisateurs à effectuer une action spécifique",
|
"cta_description": "Afficher des informations et inciter les utilisateurs à effectuer une action spécifique",
|
||||||
"custom_survey_description": "Créez une enquête sans utiliser de modèle.",
|
"custom_survey_description": "Créez une enquête sans utiliser de modèle.",
|
||||||
"custom_survey_name": "Tout créer moi-même",
|
"custom_survey_name": "Tout créer moi-même",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "Quelle est une chose que nous pourrions améliorer ?",
|
"gauge_feature_satisfaction_question_2_headline": "Quelle est une chose que nous pourrions améliorer ?",
|
||||||
"identify_customer_goals_description": "Mieux comprendre si votre message crée les bonnes attentes quant à la valeur que votre produit apporte.",
|
"identify_customer_goals_description": "Mieux comprendre si votre message crée les bonnes attentes quant à la valeur que votre produit apporte.",
|
||||||
"identify_customer_goals_name": "Identifier les objectifs des clients",
|
"identify_customer_goals_name": "Identifier les objectifs des clients",
|
||||||
"identify_customer_goals_question_1_choice_1": "Comprendre ma base d'utilisateurs en profondeur",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Identifier les opportunités de vente incitative",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "Créer le meilleur produit possible",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "Conquérir le monde pour imposer les choux de Bruxelles au petit-déjeuner",
|
|
||||||
"identify_customer_goals_question_1_headline": "Quel est ton objectif principal en utilisant $[workspaceName] ?",
|
|
||||||
"identify_sign_up_barriers_description": "Offrir une remise pour recueillir des informations sur les obstacles à l'inscription.",
|
"identify_sign_up_barriers_description": "Offrir une remise pour recueillir des informations sur les obstacles à l'inscription.",
|
||||||
"identify_sign_up_barriers_name": "Identifier les obstacles à l'inscription",
|
"identify_sign_up_barriers_name": "Identifier les obstacles à l'inscription",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Obtenez 10 % de réduction",
|
"identify_sign_up_barriers_question_1_button_label": "Obtenez 10 % de réduction",
|
||||||
@@ -1164,8 +1145,6 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Aidez-nous à mieux vous comprendre :",
|
"improve_trial_conversion_question_1_subheader": "Aidez-nous à mieux vous comprendre :",
|
||||||
"improve_trial_conversion_question_2_button_label": "Suivant",
|
"improve_trial_conversion_question_2_button_label": "Suivant",
|
||||||
"improve_trial_conversion_question_2_headline": "Désolé d'apprendre ça. Quel a été le plus gros problème lors de l'utilisation de $[workspaceName] ?",
|
"improve_trial_conversion_question_2_headline": "Désolé d'apprendre ça. Quel a été le plus gros problème lors de l'utilisation de $[workspaceName] ?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Suivant",
|
|
||||||
"improve_trial_conversion_question_3_headline": "Qu'est-ce que tu t'attendais à ce que $[workspaceName] fasse ?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "Obtenez 20 % de réduction",
|
"improve_trial_conversion_question_4_button_label": "Obtenez 20 % de réduction",
|
||||||
"improve_trial_conversion_question_4_headline": "Désolé d'apprendre cela ! Bénéficiez de 20 % de réduction sur la première année.",
|
"improve_trial_conversion_question_4_headline": "Désolé d'apprendre cela ! Bénéficiez de 20 % de réduction sur la première année.",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Nous sommes heureux de vous offrir une remise de 20 % sur un plan annuel.</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Nous sommes heureux de vous offrir une remise de 20 % sur un plan annuel.</span></p>",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Cette action se déclenche quand une page est chargée.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Cette action se déclenche quand une page est chargée.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Cette action se déclenche quand un utilisateur consulte 50 % d'une page.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Cette action se déclenche quand un utilisateur consulte 50 % d'une page.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Cette action se déclenche quand un utilisateur tente de quitter une page.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Cette action se déclenche quand un utilisateur tente de quitter une page.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Ceci est une action de code. Veuillez apporter des modifications à votre base de code.",
|
||||||
"time_in_seconds": "Temps en secondes",
|
"time_in_seconds": "Temps en secondes",
|
||||||
"time_in_seconds_placeholder": "par ex. 10",
|
"time_in_seconds_placeholder": "par ex. 10",
|
||||||
"time_in_seconds_with_unit": "{seconds} s",
|
"time_in_seconds_with_unit": "{seconds} s",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "Clé API mise à jour",
|
"api_key_updated": "Clé API mise à jour",
|
||||||
"delete_api_key_confirmation": "Toute application utilisant cette clé ne pourra plus accéder à vos données Formbricks.",
|
"delete_api_key_confirmation": "Toute application utilisant cette clé ne pourra plus accéder à vos données Formbricks.",
|
||||||
"duplicate_access": "Accès en double à l'espace de travail non autorisé",
|
"duplicate_access": "Accès en double à l'espace de travail non autorisé",
|
||||||
"duplicate_directory_access": "L'accès en double au répertoire d'enregistrement de commentaires n'est pas autorisé",
|
|
||||||
"feedback_record_directory_access": "Accès au répertoire d'enregistrement de commentaires",
|
|
||||||
"no_api_keys_yet": "Vous n'avez pas encore de clés API",
|
"no_api_keys_yet": "Vous n'avez pas encore de clés API",
|
||||||
"no_directory_permissions_found": "Aucune autorisation de répertoire d'enregistrement de commentaires trouvée",
|
"no_env_permissions_found": "Aucune permission d'environnement trouvée",
|
||||||
"no_workspace_permissions_found": "Aucune autorisation d'espace de travail trouvée",
|
|
||||||
"organization_access": "Accès à l'organisation",
|
"organization_access": "Accès à l'organisation",
|
||||||
"organization_access_description": "Sélectionnez les privilèges de lecture ou d'écriture pour les ressources à l'échelle de l'organisation.",
|
"organization_access_description": "Sélectionnez les privilèges de lecture ou d'écriture pour les ressources à l'échelle de l'organisation.",
|
||||||
"permissions": "Permissions",
|
"permissions": "Permissions",
|
||||||
"secret": "Secret",
|
"secret": "Secret",
|
||||||
"unable_to_copy_api_key": "Impossible de copier la clé API",
|
|
||||||
"unable_to_delete_api_key": "Impossible de supprimer la clé API",
|
"unable_to_delete_api_key": "Impossible de supprimer la clé API",
|
||||||
"unknown_directory": "Répertoire inconnu",
|
|
||||||
"unknown_workspace": "Espace de travail inconnu",
|
|
||||||
"workspace_access": "Accès à l'espace de travail"
|
"workspace_access": "Accès à l'espace de travail"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Connectez votre application ou votre site web à Formbricks.",
|
"app_connection_description": "Connectez votre application ou votre site web à Formbricks.",
|
||||||
"cache_update_delay_description": "Lorsque vous effectuez des mises à jour de sondages, de contacts, d'actions ou d'autres données, il peut falloir jusqu'à 1 minute pour que ces modifications apparaissent dans votre application locale exécutant le SDK Formbricks.",
|
"cache_update_delay_description": "Lorsque vous effectuez des mises à jour de sondages, de contacts, d'actions ou d'autres données, il peut falloir jusqu'à 1 minute pour que ces modifications apparaissent dans votre application locale exécutant le SDK Formbricks.",
|
||||||
"cache_update_delay_title": "Les modifications seront reflétées après environ 1 minute en raison de la mise en cache",
|
"cache_update_delay_title": "Les modifications seront reflétées après environ 1 minute en raison de la mise en cache",
|
||||||
|
"environment_id": "ID de votre espace de travail",
|
||||||
|
"environment_id_description": "Cet identifiant identifie de manière unique cet espace de travail Formbricks.",
|
||||||
"formbricks_sdk_connected": "Le SDK Formbricks est connecté",
|
"formbricks_sdk_connected": "Le SDK Formbricks est connecté",
|
||||||
"formbricks_sdk_not_connected": "Le SDK Formbricks n'est pas encore connecté.",
|
"formbricks_sdk_not_connected": "Le SDK Formbricks n'est pas encore connecté.",
|
||||||
"formbricks_sdk_not_connected_description": "Ajoutez le SDK Formbricks à votre site web ou à votre application pour le connecter à Formbricks",
|
"formbricks_sdk_not_connected_description": "Ajoutez le SDK Formbricks à votre site web ou à votre application pour le connecter à Formbricks",
|
||||||
@@ -1866,12 +1842,10 @@
|
|||||||
"receiving_data": "Réception des données 💃🕺",
|
"receiving_data": "Réception des données 💃🕺",
|
||||||
"recheck": "Revérifier",
|
"recheck": "Revérifier",
|
||||||
"sdk_connection_details": "Détails de connexion du SDK",
|
"sdk_connection_details": "Détails de connexion du SDK",
|
||||||
"sdk_connection_details_description": "Ton ID d'espace de travail unique et l'URL de connexion SDK pour intégrer Formbricks à ton application.",
|
"sdk_connection_details_description": "Votre ID d'espace de travail unique et l'URL de connexion SDK pour intégrer Formbricks à votre application.",
|
||||||
"setup_alert_description": "Suivez ce tutoriel étape par étape pour connecter votre application ou votre site web en moins de 5 minutes.",
|
"setup_alert_description": "Suivez ce tutoriel étape par étape pour connecter votre application ou votre site web en moins de 5 minutes.",
|
||||||
"setup_alert_title": "Comment se connecter",
|
"setup_alert_title": "Comment se connecter",
|
||||||
"webapp_url": "URL de connexion SDK",
|
"webapp_url": "URL de connexion SDK"
|
||||||
"workspace_id": "ID de votre espace de travail",
|
|
||||||
"workspace_id_description": "Cet identifiant identifie de manière unique cet espace de travail Formbricks."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Félicitations !",
|
"congrats": "Félicitations !",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Valeur d'attribut",
|
"attribute_value_placeholder": "Valeur d'attribut",
|
||||||
"attributes_msg_attribute_limit_exceeded": "Impossible de créer {count, plural, one {# nouvel attribut} other {# nouveaux attributs}} car cela dépasserait la limite maximale de {limit} classes d'attributs. Les attributs existants ont été mis à jour avec succès.",
|
"attributes_msg_attribute_limit_exceeded": "Impossible de créer {count, plural, one {# nouvel attribut} other {# nouveaux attributs}} car cela dépasserait la limite maximale de {limit} classes d'attributs. Les attributs existants ont été mis à jour avec succès.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (l'attribut “{key}” a le type de données : {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (l'attribut “{key}” a le type de données : {dataType})",
|
||||||
"attributes_msg_email_already_exists": "L'adresse e-mail existe déjà pour cet espace de travail et n'a pas été mise à jour.",
|
"attributes_msg_email_already_exists": "L'adresse e-mail existe déjà pour cet environnement et n'a pas été mise à jour.",
|
||||||
"attributes_msg_email_or_userid_required": "L'e-mail ou l'identifiant utilisateur est requis. Les valeurs existantes ont été conservées.",
|
"attributes_msg_email_or_userid_required": "L'e-mail ou l'identifiant utilisateur est requis. Les valeurs existantes ont été conservées.",
|
||||||
"attributes_msg_new_attribute_created": "Nouvel attribut “{key}” créé avec le type “{dataType}”",
|
"attributes_msg_new_attribute_created": "Nouvel attribut “{key}” créé avec le type “{dataType}”",
|
||||||
"attributes_msg_userid_already_exists": "L'ID utilisateur existe déjà pour cet espace de travail et n'a pas été mis à jour.",
|
"attributes_msg_userid_already_exists": "L'identifiant utilisateur existe déjà pour cet environnement et n'a pas été mis à jour.",
|
||||||
"contact_deleted_successfully": "Contact supprimé avec succès",
|
"contact_deleted_successfully": "Contact supprimé avec succès",
|
||||||
"contacts_table_refresh": "Actualiser les contacts",
|
"contacts_table_refresh": "Actualiser les contacts",
|
||||||
"contacts_table_refresh_success": "Contacts rafraîchis avec succès",
|
"contacts_table_refresh_success": "Contacts rafraîchis avec succès",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Langue ou identifiant de langue en double",
|
"duplicate_language_or_language_id": "Langue ou identifiant de langue en double",
|
||||||
"edit_languages": "Modifier les langues",
|
"edit_languages": "Modifier les langues",
|
||||||
"identifier": "Identifiant (ISO)",
|
"identifier": "Identifiant (ISO)",
|
||||||
|
"incomplete_translations": "Traductions incomplètes",
|
||||||
"language": "Langue",
|
"language": "Langue",
|
||||||
"language_deleted_successfully": "Langue supprimée avec succès",
|
"language_deleted_successfully": "Langue supprimée avec succès",
|
||||||
"languages_updated_successfully": "Langues mises à jour avec succès",
|
"languages_updated_successfully": "Langues mises à jour avec succès",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Veuillez sélectionner une langue",
|
"please_select_a_language": "Veuillez sélectionner une langue",
|
||||||
"remove_language": "Supprimer la langue",
|
"remove_language": "Supprimer la langue",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Veuillez supprimer la langue de ces sondages afin de la retirer de l'espace de travail.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Veuillez supprimer la langue de ces sondages afin de la retirer de l'espace de travail.",
|
||||||
"search_items": "Rechercher des éléments"
|
"search_items": "Rechercher des éléments",
|
||||||
|
"translate": "Traduire"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Ajouter une couleur d'arrière-plan",
|
"add_background_color": "Ajouter une couleur d'arrière-plan",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "Vous êtes prêt ! Il est temps de créer votre première enquête.",
|
"all_set_time_to_create_first_survey": "Vous êtes prêt ! Il est temps de créer votre première enquête.",
|
||||||
"alphabetical": "Alphabétique",
|
"alphabetical": "Alphabétique",
|
||||||
|
"copy_survey": "Copier l'enquête",
|
||||||
|
"copy_survey_description": "Copier ce sondage vers un autre espace de travail",
|
||||||
|
"copy_survey_error": "Échec de la copie du sondage",
|
||||||
"copy_survey_link_to_clipboard": "Copier le lien du sondage dans le presse-papiers",
|
"copy_survey_link_to_clipboard": "Copier le lien du sondage dans le presse-papiers",
|
||||||
|
"copy_survey_no_workspaces": "Il n'y a aucun autre espace de travail vers lequel copier ce sondage.",
|
||||||
|
"copy_survey_partially_success": "{success} enquêtes copiées avec succès, {error} échouées.",
|
||||||
|
"copy_survey_success": "Enquête copiée avec succès !",
|
||||||
"delete_survey_and_responses_warning": "Êtes-vous sûr de vouloir supprimer cette enquête et toutes ses réponses?",
|
"delete_survey_and_responses_warning": "Êtes-vous sûr de vouloir supprimer cette enquête et toutes ses réponses?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Activer les traductions",
|
"1_choose_the_default_language_for_this_survey": "1. Choisissez la langue par défaut pour ce sondage :",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Activer la traduction pour des langues spécifiques:",
|
||||||
"add": "Ajouter +",
|
"add": "Ajouter +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Ajouter un délai ou fermer automatiquement l'enquête",
|
"add_a_delay_or_auto_close_the_survey": "Ajouter un délai ou fermer automatiquement l'enquête",
|
||||||
"add_a_four_digit_pin": "Ajoutez un code PIN à quatre chiffres.",
|
"add_a_four_digit_pin": "Ajoutez un code PIN à quatre chiffres.",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Public",
|
"audience": "Public",
|
||||||
"auto_close_on_inactivity": "Fermeture automatique en cas d'inactivité",
|
"auto_close_on_inactivity": "Fermeture automatique en cas d'inactivité",
|
||||||
"auto_progress_rating_and_nps": "Progression automatique pour les questions d'évaluation et NPS",
|
"auto_progress_rating_and_nps": "Progression automatique pour les questions d'évaluation et NPS",
|
||||||
"auto_progress_rating_and_nps_description": "Passage automatique pour les blocs à question unique. Les questions obligatoires masquent le bouton Suivant, sauf lorsque « Autre » est sélectionné.",
|
"auto_progress_rating_and_nps_description": "Passe automatiquement à la question suivante lorsque les répondants sélectionnent une réponse aux questions d'évaluation ou NPS. Cela s'applique uniquement aux blocs à question unique. Les questions obligatoires masquent le bouton Suivant ; les questions facultatives l'affichent toujours pour permettre de passer la question.",
|
||||||
"auto_save_disabled": "Sauvegarde automatique désactivée",
|
"auto_save_disabled": "Sauvegarde automatique désactivée",
|
||||||
"auto_save_disabled_tooltip": "Votre sondage n'est sauvegardé automatiquement que lorsqu'il est en brouillon. Cela garantit que les sondages publics ne sont pas mis à jour involontairement.",
|
"auto_save_disabled_tooltip": "Votre sondage n'est sauvegardé automatiquement que lorsqu'il est en brouillon. Cela garantit que les sondages publics ne sont pas mis à jour involontairement.",
|
||||||
"auto_save_on": "Sauvegarde automatique activée",
|
"auto_save_on": "Sauvegarde automatique activée",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "Les changements entraîneront des incohérences.",
|
"caution_text": "Les changements entraîneront des incohérences.",
|
||||||
"change_anyway": "Changer de toute façon",
|
"change_anyway": "Changer de toute façon",
|
||||||
"change_background": "Changer l'arrière-plan",
|
"change_background": "Changer l'arrière-plan",
|
||||||
"change_default": "Modifier la langue par défaut",
|
|
||||||
"change_question_type": "Changer le type de question",
|
"change_question_type": "Changer le type de question",
|
||||||
"change_survey_type": "Le changement de type de sondage affecte l'accès existant",
|
"change_survey_type": "Le changement de type de sondage affecte l'accès existant",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Changez l'arrière-plan en une couleur, une image ou une animation.",
|
"change_the_background_to_a_color_image_or_animation": "Changez l'arrière-plan en une couleur, une image ou une animation.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Choisissez la première question de votre bloc",
|
"choose_the_first_question_on_your_block": "Choisissez la première question de votre bloc",
|
||||||
"choose_where_to_run_the_survey": "Choisissez où réaliser l'enquête.",
|
"choose_where_to_run_the_survey": "Choisissez où réaliser l'enquête.",
|
||||||
"city": "Ville",
|
"city": "Ville",
|
||||||
"clear_close_on_date": "Effacer la date de mise en pause",
|
|
||||||
"clear_publish_on_date": "Effacer la date de publication",
|
|
||||||
"close_survey_on_date": "Date de mise en pause",
|
|
||||||
"close_survey_on_response_limit": "Fermer l'enquête sur la limite de réponse",
|
"close_survey_on_response_limit": "Fermer l'enquête sur la limite de réponse",
|
||||||
"code": "Code",
|
|
||||||
"color": "Couleur",
|
"color": "Couleur",
|
||||||
"column_used_in_logic_error": "Cette colonne est utilisée dans la logique de la question {questionIndex}. Veuillez d'abord la supprimer de la logique.",
|
"column_used_in_logic_error": "Cette colonne est utilisée dans la logique de la question {questionIndex}. Veuillez d'abord la supprimer de la logique.",
|
||||||
"columns": "Colonnes",
|
"columns": "Colonnes",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "Personnaliser le logo de l'enquête",
|
"customize_survey_logo": "Personnaliser le logo de l'enquête",
|
||||||
"darken_or_lighten_background_of_your_choice": "Assombrir ou éclaircir l'arrière-plan de votre choix.",
|
"darken_or_lighten_background_of_your_choice": "Assombrir ou éclaircir l'arrière-plan de votre choix.",
|
||||||
"days_before_showing_this_survey_again": "ou plus de jours doivent s'écouler entre le dernier sondage affiché et l'affichage de ce sondage.",
|
"days_before_showing_this_survey_again": "ou plus de jours doivent s'écouler entre le dernier sondage affiché et l'affichage de ce sondage.",
|
||||||
"default_language": "Langue par défaut",
|
|
||||||
"delete_anyways": "Supprimer quand même",
|
"delete_anyways": "Supprimer quand même",
|
||||||
"delete_block": "Supprimer le bloc",
|
"delete_block": "Supprimer le bloc",
|
||||||
"delete_choice": "Supprimer l'option",
|
"delete_choice": "Supprimer l'option",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Dupliquer la question",
|
"duplicate_question": "Dupliquer la question",
|
||||||
"edit_link": "Modifier le lien",
|
"edit_link": "Modifier le lien",
|
||||||
"edit_recall": "Modifier le rappel",
|
"edit_recall": "Modifier le rappel",
|
||||||
|
"edit_translations": "Modifier les traductions {lang}",
|
||||||
"element_not_found": "Question non trouvée",
|
"element_not_found": "Question non trouvée",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permettre aux répondants de changer de langue à tout moment. Nécessite au moins 2 langues actives.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permettre aux répondants de changer de langue à tout moment. Nécessite au moins 2 langues actives.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "La protection contre le spam utilise reCAPTCHA v3 pour filtrer les réponses indésirables.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "La protection contre le spam utilise reCAPTCHA v3 pour filtrer les réponses indésirables.",
|
||||||
@@ -3014,12 +2992,10 @@
|
|||||||
"long_answer_toggle_description": "Permettre aux répondants d'écrire des réponses plus longues et sur plusieurs lignes.",
|
"long_answer_toggle_description": "Permettre aux répondants d'écrire des réponses plus longues et sur plusieurs lignes.",
|
||||||
"lower_label": "Étiquette inférieure",
|
"lower_label": "Étiquette inférieure",
|
||||||
"manage_languages": "Gérer les langues",
|
"manage_languages": "Gérer les langues",
|
||||||
"manage_translations": "Gérer les traductions",
|
|
||||||
"matrix_all_fields": "Tous les champs",
|
"matrix_all_fields": "Tous les champs",
|
||||||
"matrix_rows": "Lignes",
|
"matrix_rows": "Lignes",
|
||||||
"max_file_size": "Taille maximale du fichier",
|
"max_file_size": "Taille maximale du fichier",
|
||||||
"max_file_size_limit_is": "La limite de taille maximale du fichier est",
|
"max_file_size_limit_is": "La limite de taille maximale du fichier est",
|
||||||
"missing_first": "Manquantes en premier",
|
|
||||||
"move_question_to_block": "Déplacer la question vers le bloc",
|
"move_question_to_block": "Déplacer la question vers le bloc",
|
||||||
"multiply": "Multiplier *",
|
"multiply": "Multiplier *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Nécessaire pour une instance Cal.com auto-hébergée",
|
"needed_for_self_hosted_cal_com_instance": "Nécessaire pour une instance Cal.com auto-hébergée",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "Libellé du bouton « Suivant »",
|
"next_button_label": "Libellé du bouton « Suivant »",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Aucun champ caché pour le moment. Ajoutez le premier ci-dessous.",
|
"no_hidden_fields_yet_add_first_one_below": "Aucun champ caché pour le moment. Ajoutez le premier ci-dessous.",
|
||||||
"no_images_found_for": "Aucune image trouvée pour ''{query}\"",
|
"no_images_found_for": "Aucune image trouvée pour ''{query}\"",
|
||||||
"no_languages_found_add_first_one_to_get_started": "Aucune langue d'enquête trouvée dans cet espace de travail. Veuillez en ajouter une pour commencer.",
|
"no_languages_found_add_first_one_to_get_started": "Aucune langue trouvée. Ajoutez la première pour commencer.",
|
||||||
"no_option_found": "Aucune option trouvée",
|
"no_option_found": "Aucune option trouvée",
|
||||||
"no_recall_items_found": "Aucun élément de rappel trouvé",
|
"no_recall_items_found": "Aucun élément de rappel trouvé",
|
||||||
"no_variables_yet_add_first_one_below": "Aucune variable pour le moment. Ajoutez la première ci-dessous.",
|
"no_variables_yet_add_first_one_below": "Aucune variable pour le moment. Ajoutez la première ci-dessous.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Veuillez entrer une URL valide (par exemple, https://example.com)",
|
"please_enter_a_valid_url": "Veuillez entrer une URL valide (par exemple, https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Veuillez définir un déclencheur d'enquête.",
|
"please_set_a_survey_trigger": "Veuillez définir un déclencheur d'enquête.",
|
||||||
"please_specify": "Veuillez préciser",
|
"please_specify": "Veuillez préciser",
|
||||||
"present_your_survey_in_multiple_languages": "Présente ton questionnaire dans plusieurs langues",
|
|
||||||
"prevent_double_submission": "Empêcher la double soumission",
|
"prevent_double_submission": "Empêcher la double soumission",
|
||||||
"prevent_double_submission_description": "Autoriser uniquement 1 réponse par adresse e-mail",
|
"prevent_double_submission_description": "Autoriser uniquement 1 réponse par adresse e-mail",
|
||||||
"progress_saved": "Progression enregistrée",
|
"progress_saved": "Progression enregistrée",
|
||||||
"protect_survey_with_pin": "Protéger l'enquête par un code PIN",
|
"protect_survey_with_pin": "Protéger l'enquête par un code PIN",
|
||||||
"protect_survey_with_pin_description": "Seules les personnes ayant le code PIN peuvent accéder à l'enquête.",
|
"protect_survey_with_pin_description": "Seules les personnes ayant le code PIN peuvent accéder à l'enquête.",
|
||||||
"publish": "Publier",
|
"publish": "Publier",
|
||||||
"publish_survey_on_date": "Date de publication",
|
|
||||||
"question": "Question",
|
"question": "Question",
|
||||||
"question_deleted": "Question supprimée.",
|
"question_deleted": "Question supprimée.",
|
||||||
"question_duplicated": "Question dupliquée.",
|
"question_duplicated": "Question dupliquée.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Lignes",
|
"rows": "Lignes",
|
||||||
"save_and_close": "Enregistrer et fermer",
|
"save_and_close": "Enregistrer et fermer",
|
||||||
"scale": "Échelle",
|
"scale": "Échelle",
|
||||||
"schedule_survey": "Planifier l'enquête",
|
|
||||||
"search_for_images": "Rechercher des images",
|
"search_for_images": "Rechercher des images",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "Les secondes après le déclenchement, l'enquête sera fermée si aucune réponse n'est donnée.",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "Les secondes après le déclenchement, l'enquête sera fermée si aucune réponse n'est donnée.",
|
||||||
"seconds_before_showing_the_survey": "secondes avant de montrer l'enquête.",
|
"seconds_before_showing_the_survey": "secondes avant de montrer l'enquête.",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 points",
|
"seven_points": "7 points",
|
||||||
"show_block_settings": "Afficher les paramètres du bloc",
|
"show_block_settings": "Afficher les paramètres du bloc",
|
||||||
"show_button": "Afficher le bouton",
|
"show_button": "Afficher le bouton",
|
||||||
"show_in_order": "Afficher dans l'ordre",
|
|
||||||
"show_language_switch": "Afficher le changement de langue",
|
"show_language_switch": "Afficher le changement de langue",
|
||||||
"show_multiple_times": "Afficher un nombre limité de fois",
|
"show_multiple_times": "Afficher un nombre limité de fois",
|
||||||
"show_only_once": "Afficher une seule fois",
|
"show_only_once": "Afficher une seule fois",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Aperçu du sondage 👀",
|
"survey_preview": "Aperçu du sondage 👀",
|
||||||
"survey_styling": "Style de formulaire",
|
"survey_styling": "Style de formulaire",
|
||||||
"survey_trigger": "Déclencheur d'enquête",
|
"survey_trigger": "Déclencheur d'enquête",
|
||||||
"survey_will_be_closed_at_midnight_cet": "L'enquête sera fermée à {time} dans le fuseau horaire {timeZone} à la date sélectionnée",
|
"switch_multi_language_on_to_get_started": "Activez le mode multilingue pour commencer 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "L'enquête sera publiée à {time} dans le fuseau horaire {timeZone} à la date sélectionnée",
|
|
||||||
"target_block_not_found": "Bloc cible non trouvé",
|
"target_block_not_found": "Bloc cible non trouvé",
|
||||||
"targeted": "Ciblé",
|
"targeted": "Ciblé",
|
||||||
"ten_points": "10 points",
|
"ten_points": "10 points",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Afficher une seule fois, même si la personne ne répond pas.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Afficher une seule fois, même si la personne ne répond pas.",
|
||||||
"then": "Alors",
|
"then": "Alors",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Cette action supprimera toutes les traductions de cette enquête.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Cette action supprimera toutes les traductions de cette enquête.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Cela supprimera cette langue et toutes ses traductions de ce questionnaire. Cette action est irréversible.",
|
|
||||||
"three_points": "3 points",
|
"three_points": "3 points",
|
||||||
"times": "fois",
|
"times": "fois",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Pour maintenir la cohérence du placement sur tous les sondages, vous pouvez",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Pour maintenir la cohérence du placement sur tous les sondages, vous pouvez",
|
||||||
"translated": "Traduit",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Déclencher l'enquête lorsqu'une des actions est déclenchée...",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Déclencher l'enquête lorsqu'une des actions est déclenchée...",
|
||||||
"try_lollipop_or_mountain": "Essayez 'sucette' ou 'montagne'...",
|
"try_lollipop_or_mountain": "Essayez 'sucette' ou 'montagne'...",
|
||||||
"type_field_id": "Identifiant de champ de type",
|
"type_field_id": "Identifiant de champ de type",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Ne laissez répondre que les personnes ayant une véritable adresse e-mail.",
|
"verify_email_before_submission_description": "Ne laissez répondre que les personnes ayant une véritable adresse e-mail.",
|
||||||
"visibility_and_recontact": "Visibilité et recontact",
|
"visibility_and_recontact": "Visibilité et recontact",
|
||||||
"visibility_and_recontact_description": "Contrôlez quand cette enquête peut apparaître et à quelle fréquence elle peut réapparaître.",
|
"visibility_and_recontact_description": "Contrôlez quand cette enquête peut apparaître et à quelle fréquence elle peut réapparaître.",
|
||||||
"visible": "Visible",
|
|
||||||
"wait": "Attendre",
|
"wait": "Attendre",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Attendez quelques secondes après le déclencheur avant de montrer l'enquête.",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Attendez quelques secondes après le déclencheur avant de montrer l'enquête.",
|
||||||
"waiting_time_across_surveys": "Période de refroidissement (entre les sondages)",
|
"waiting_time_across_surveys": "Période de refroidissement (entre les sondages)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Configurer les alertes",
|
"configure_alerts": "Configurer les alertes",
|
||||||
"congrats": "Félicitations ! Votre enquête est en ligne.",
|
"congrats": "Félicitations ! Votre enquête est en ligne.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Connectez votre site web ou votre application à Formbricks pour commencer.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Connectez votre site web ou votre application à Formbricks pour commencer.",
|
||||||
"csat_satisfied": "CSAT : {percentage} % Satisfaits",
|
|
||||||
"csat_satisfied_tooltip": "{percentage} % des répondants ont donné une note de 4 ou 5 (CSAT).",
|
|
||||||
"current_count": "Nombre actuel",
|
"current_count": "Nombre actuel",
|
||||||
"custom_range": "Plage personnalisée...",
|
"custom_range": "Plage personnalisée...",
|
||||||
"delete_all_existing_responses_and_displays": "Supprimer toutes les réponses existantes et les affichages",
|
"delete_all_existing_responses_and_displays": "Supprimer toutes les réponses existantes et les affichages",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "Téléchargement du code QR",
|
"downloading_qr_code": "Téléchargement du code QR",
|
||||||
"drop_offs": "Dépôts",
|
"drop_offs": "Dépôts",
|
||||||
"drop_offs_tooltip": "Nombre de fois que l'enquête a été commencée mais non terminée.",
|
"drop_offs_tooltip": "Nombre de fois que l'enquête a été commencée mais non terminée.",
|
||||||
"effort_score": "Score d'effort",
|
"failed_to_copy_link": "Échec de la copie du lien",
|
||||||
"filter_added_successfully": "Filtre ajouté avec succès",
|
"filter_added_successfully": "Filtre ajouté avec succès",
|
||||||
"filter_updated_successfully": "Filtre mis à jour avec succès",
|
"filter_updated_successfully": "Filtre mis à jour avec succès",
|
||||||
"filtered_responses_csv": "Réponses filtrées (CSV)",
|
"filtered_responses_csv": "Réponses filtrées (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Limite",
|
"limit": "Limite",
|
||||||
"no_identified_impressions": "Aucune impression des contacts identifiés",
|
"no_identified_impressions": "Aucune impression des contacts identifiés",
|
||||||
"no_responses_found": "Aucune réponse trouvée",
|
"no_responses_found": "Aucune réponse trouvée",
|
||||||
"nps_promoters_tooltip": "{percentage} % des répondants ont donné une note de 9 ou 10 (promoteurs NPS).",
|
|
||||||
"other_values_found": "D'autres valeurs trouvées",
|
"other_values_found": "D'autres valeurs trouvées",
|
||||||
"overall": "Globalement",
|
"overall": "Globalement",
|
||||||
"promoters": "Promoteurs",
|
"promoters": "Promoteurs",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "Le nombre de quotas complétés par les répondants.",
|
"quotas_completed_tooltip": "Le nombre de quotas complétés par les répondants.",
|
||||||
"reset_survey": "Réinitialiser l'enquête",
|
"reset_survey": "Réinitialiser l'enquête",
|
||||||
"reset_survey_warning": "Réinitialiser un sondage supprime toutes les réponses et les affichages associés à ce sondage. Cela ne peut pas être annulé.",
|
"reset_survey_warning": "Réinitialiser un sondage supprime toutes les réponses et les affichages associés à ce sondage. Cela ne peut pas être annulé.",
|
||||||
|
"satisfied": "Satisfait",
|
||||||
"selected_responses_csv": "Réponses sélectionnées (CSV)",
|
"selected_responses_csv": "Réponses sélectionnées (CSV)",
|
||||||
"selected_responses_excel": "Réponses sélectionnées (Excel)",
|
"selected_responses_excel": "Réponses sélectionnées (Excel)",
|
||||||
"setup_integrations": "Configurer les intégrations",
|
"setup_integrations": "Configurer les intégrations",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Nombre de fois que l'enquête a été commencée.",
|
"starts_tooltip": "Nombre de fois que l'enquête a été commencée.",
|
||||||
"survey_reset_successfully": "Réinitialisation du sondage réussie ! {responseCount} réponses et {displayCount} affichages ont été supprimés.",
|
"survey_reset_successfully": "Réinitialisation du sondage réussie ! {responseCount} réponses et {displayCount} affichages ont été supprimés.",
|
||||||
"survey_results": "Résultats de {surveyName}",
|
"survey_results": "Résultats de {surveyName}",
|
||||||
"survey_scheduled_successfully": "Enquête planifiée avec succès",
|
|
||||||
"this_month": "Ce mois-ci",
|
"this_month": "Ce mois-ci",
|
||||||
"this_quarter": "Ce trimestre",
|
"this_quarter": "Ce trimestre",
|
||||||
"this_year": "Cette année",
|
"this_year": "Cette année",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "Enquête supprimée avec succès !",
|
"survey_deleted_successfully": "Enquête supprimée avec succès !",
|
||||||
"survey_duplicated_successfully": "Enquête dupliquée avec succès.",
|
"survey_duplicated_successfully": "Enquête dupliquée avec succès.",
|
||||||
|
"survey_duplication_error": "Échec de la duplication de l'enquête.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Tous les canaux",
|
"all_channels": "Tous les canaux",
|
||||||
"all_industries": "Tous les secteurs",
|
"all_industries": "Tous les secteurs",
|
||||||
|
|||||||
+36
-70
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Munkaterület módosítása",
|
"change_workspace": "Munkaterület módosítása",
|
||||||
"chart": "Diagram",
|
"chart": "Diagram",
|
||||||
"charts": "Diagramok",
|
"charts": "Diagramok",
|
||||||
"choice_n": "{{n}}. választás",
|
|
||||||
"choices": "Választási lehetőségek",
|
"choices": "Választási lehetőségek",
|
||||||
"choose_organization": "Szervezet kiválasztása",
|
"choose_organization": "Szervezet kiválasztása",
|
||||||
"choose_workspace": "Munkaterület kiválasztása",
|
"choose_workspace": "Munkaterület kiválasztása",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Bezárás",
|
"close": "Bezárás",
|
||||||
"code": "Kód",
|
"code": "Kód",
|
||||||
"collapse_rows": "Sorok összecsukása",
|
"collapse_rows": "Sorok összecsukása",
|
||||||
"column_n": "{{n}}. oszlop",
|
|
||||||
"completed": "Befejezve",
|
"completed": "Befejezve",
|
||||||
"configuration": "Konfigurálás",
|
"configuration": "Konfiguráció",
|
||||||
"confirm": "Megerősítés",
|
"confirm": "Megerősítés",
|
||||||
"connect": "Kapcsolódás",
|
"connect": "Kapcsolódás",
|
||||||
"connect_formbricks": "Kapcsolódás a Formbrickshez",
|
"connect_formbricks": "Kapcsolódás a Formbrickshez",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Befejező kártya",
|
"ending_card": "Befejező kártya",
|
||||||
"enter_url": "URL megadása",
|
"enter_url": "URL megadása",
|
||||||
"enterprise_license": "Vállalati licenc",
|
"enterprise_license": "Vállalati licenc",
|
||||||
|
"environment": "Környezet",
|
||||||
"error": "Hiba",
|
"error": "Hiba",
|
||||||
"error_component_description": "Ez az erőforrás nem létezik, vagy nem rendelkezik a hozzáféréshez szükséges jogosultságokkal.",
|
"error_component_description": "Ez az erőforrás nem létezik, vagy nem rendelkezik a hozzáféréshez szükséges jogosultságokkal.",
|
||||||
"error_component_title": "Hiba az erőforrások betöltésekor",
|
"error_component_title": "Hiba az erőforrások betöltésekor",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Nem sikerült betölteni a szervezeteket",
|
"failed_to_load_organizations": "Nem sikerült betölteni a szervezeteket",
|
||||||
"failed_to_load_workspaces": "Nem sikerült a munkaterületek betöltése",
|
"failed_to_load_workspaces": "Nem sikerült a munkaterületek betöltése",
|
||||||
"failed_to_parse_csv": "A CSV elemzése sikertelen",
|
"failed_to_parse_csv": "A CSV elemzése sikertelen",
|
||||||
"field_placeholder": "{{field}} helyőrző",
|
|
||||||
"filter": "Szűrő",
|
"filter": "Szűrő",
|
||||||
"finish": "Befejezés",
|
"finish": "Befejezés",
|
||||||
"first_name": "Keresztnév",
|
"first_name": "Keresztnév",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Előállítás",
|
"generate": "Előállítás",
|
||||||
"go_back": "Vissza",
|
"go_back": "Vissza",
|
||||||
"go_to_dashboard": "Ugrás a vezérlőpultra",
|
"go_to_dashboard": "Ugrás a vezérlőpultra",
|
||||||
"headline": "Címsor",
|
|
||||||
"hidden": "Rejtett",
|
"hidden": "Rejtett",
|
||||||
"hidden_field": "Rejtett mező",
|
"hidden_field": "Rejtett mező",
|
||||||
"hidden_fields": "Rejtett mezők",
|
"hidden_fields": "Rejtett mezők",
|
||||||
"hide": "Elrejtés",
|
"hide": "Elrejtés",
|
||||||
"hide_column": "Oszlop elrejtése",
|
"hide_column": "Oszlop elrejtése",
|
||||||
"html": "HTML",
|
|
||||||
"id": "Azonosító",
|
"id": "Azonosító",
|
||||||
"image": "Kép",
|
"image": "Kép",
|
||||||
"images": "Képek",
|
"images": "Képek",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "További lehetőségek",
|
"more_options": "További lehetőségek",
|
||||||
"move_down": "Mozgatás le",
|
"move_down": "Mozgatás le",
|
||||||
"move_up": "Mozgatás fel",
|
"move_up": "Mozgatás fel",
|
||||||
|
"multiple_languages": "Több nyelv",
|
||||||
"my_product": "saját termék",
|
"my_product": "saját termék",
|
||||||
"name": "Név",
|
"name": "Név",
|
||||||
"new": "Új",
|
"new": "Új",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "Nem található eredmény",
|
"no_result_found": "Nem található eredmény",
|
||||||
"no_results": "Nincs találat",
|
"no_results": "Nincs találat",
|
||||||
"no_surveys_found": "Nem találhatók kérdőívek.",
|
"no_surveys_found": "Nem találhatók kérdőívek.",
|
||||||
"no_text_found": "Nem található szöveg",
|
|
||||||
"none_of_the_above": "A fentiek közül egyik sem",
|
"none_of_the_above": "A fentiek közül egyik sem",
|
||||||
"not_authenticated": "Nincs jogosultsága ennek a műveletnek a végrehajtásához.",
|
"not_authenticated": "Nincs jogosultsága ennek a műveletnek a végrehajtásához.",
|
||||||
"not_authorized": "Nincs felhatalmazva",
|
"not_authorized": "Nincs felhatalmazva",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Szervezet beállításai",
|
"organization_settings": "Szervezet beállításai",
|
||||||
"other": "Egyéb",
|
"other": "Egyéb",
|
||||||
"other_filters": "Egyéb szűrők",
|
"other_filters": "Egyéb szűrők",
|
||||||
"other_placeholder": "Egyéb helyőrző",
|
"others": "Mások",
|
||||||
"overlay_color": "Rávetítés színe",
|
"overlay_color": "Rávetítés színe",
|
||||||
"overview": "Áttekintés",
|
"overview": "Áttekintés",
|
||||||
"password": "Jelszó",
|
"password": "Jelszó",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Váltson magasabb csomagra",
|
"please_upgrade_your_plan": "Váltson magasabb csomagra",
|
||||||
"powered_by_formbricks": "A gépházban: Formbricks",
|
"powered_by_formbricks": "A gépházban: Formbricks",
|
||||||
"preview": "Előnézet",
|
"preview": "Előnézet",
|
||||||
|
"preview_survey": "Kérdőív előnézete",
|
||||||
"privacy": "Adatvédelmi irányelvek",
|
"privacy": "Adatvédelmi irányelvek",
|
||||||
"product_manager": "Termékmenedzser",
|
"product_manager": "Termékmenedzser",
|
||||||
|
"production": "Produktív",
|
||||||
"profile": "Profil",
|
"profile": "Profil",
|
||||||
"profile_id": "Profilazonosító",
|
"profile_id": "Profilazonosító",
|
||||||
"progress": "Folyamat",
|
"progress": "Folyamat",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Újraindítás",
|
"restart": "Újraindítás",
|
||||||
"retry": "Újra",
|
"retry": "Újra",
|
||||||
"role": "Szerep",
|
"role": "Szerep",
|
||||||
"row_n": "{{n}}. sor",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Értékesítés",
|
"sales": "Értékesítés",
|
||||||
"save": "Mentés",
|
"save": "Mentés",
|
||||||
"save_as_draft": "Mentés piszkozatként",
|
"save_as_draft": "Mentés piszkozatként",
|
||||||
"save_changes": "Változtatások mentése",
|
"save_changes": "Változtatások mentése",
|
||||||
"save_without_scheduling": "Mentés ütemezés nélkül",
|
|
||||||
"saving": "Mentés",
|
"saving": "Mentés",
|
||||||
"scheduled": "Ütemezve",
|
|
||||||
"search": "Keresés",
|
"search": "Keresés",
|
||||||
"search_charts": "Diagramok keresése...",
|
"search_charts": "Diagramok keresése...",
|
||||||
"security": "Biztonság",
|
"security": "Biztonság",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "A fájltároló nincs beállítva, a feltöltések valószínűleg sikertelenek lesznek",
|
"storage_not_configured": "A fájltároló nincs beállítva, a feltöltések valószínűleg sikertelenek lesznek",
|
||||||
"string": "Szöveg",
|
"string": "Szöveg",
|
||||||
"styling": "Stíluskészítés",
|
"styling": "Stíluskészítés",
|
||||||
"subheader": "Alcím",
|
|
||||||
"submit": "Elküldés",
|
"submit": "Elküldés",
|
||||||
"summary": "Összegzés",
|
"summary": "Összegzés",
|
||||||
"survey": "Kérdőív",
|
"survey": "Kérdőív",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Kérdőív nyelvei",
|
"survey_languages": "Kérdőív nyelvei",
|
||||||
"survey_live": "A kérdőív élő",
|
"survey_live": "A kérdőív élő",
|
||||||
"survey_paused": "A kérdőív szüneteltetve.",
|
"survey_paused": "A kérdőív szüneteltetve.",
|
||||||
"survey_scheduled": "A felmérés ütemezve lett.",
|
|
||||||
"survey_type": "Kérdőív típusa",
|
"survey_type": "Kérdőív típusa",
|
||||||
"surveys": "Kérdőívek",
|
"surveys": "Kérdőívek",
|
||||||
"table_items_deleted_successfully": "{type}s sikeresen törölve",
|
"table_items_deleted_successfully": "{type}s sikeresen törölve",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Munkaterületek",
|
"workspaces": "Munkaterületek",
|
||||||
"years": "év",
|
"years": "év",
|
||||||
"yes": "Igen",
|
"yes": "Igen",
|
||||||
|
"you": "Ön",
|
||||||
"you_are_downgraded_to_the_community_edition": "Visszaváltott a közösségi kiadásra.",
|
"you_are_downgraded_to_the_community_edition": "Visszaváltott a közösségi kiadásra.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "Nincs felhatalmazva ennek a műveletnek a végrehajtásához.",
|
"you_are_not_authorized_to_perform_this_action": "Nincs felhatalmazva ennek a műveletnek a végrehajtásához.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Elérte a munkaterületek {workspaceLimit} darabos korlátját.",
|
"you_have_reached_your_limit_of_workspace_limit": "Elérte a munkaterületek {workspaceLimit} darabos korlátját.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "A Formbricks csapata",
|
"email_footer_text_2": "A Formbricks csapata",
|
||||||
"email_template_text_1": "Ez az e-mail a Formbricks által lett elküldve.",
|
"email_template_text_1": "Ez az e-mail a Formbricks által lett elküldve.",
|
||||||
"embed_survey_preview_email_didnt_request": "Nem kérte ezt?",
|
"embed_survey_preview_email_didnt_request": "Nem kérte ezt?",
|
||||||
|
"embed_survey_preview_email_environment_id": "Környezeti azonosító",
|
||||||
"embed_survey_preview_email_fight_spam": "Segítsen nekünk a levélszemét elleni küzdelemben, és továbbítsa ezt a levelet a hola@formbricks.com címre.",
|
"embed_survey_preview_email_fight_spam": "Segítsen nekünk a levélszemét elleni küzdelemben, és továbbítsa ezt a levelet a hola@formbricks.com címre.",
|
||||||
"embed_survey_preview_email_heading": "Beágyazott e-mail előnézete",
|
"embed_survey_preview_email_heading": "Beágyazott e-mail előnézete",
|
||||||
"embed_survey_preview_email_subject": "Formbricks e-mail-kérdőív előnézet",
|
"embed_survey_preview_email_subject": "Formbricks e-mail-kérdőív előnézet",
|
||||||
"embed_survey_preview_email_text": "Így néz ki a kódrészlet egy e-mailbe ágyazva:",
|
"embed_survey_preview_email_text": "Így néz ki a kódrészlet egy e-mailbe ágyazva:",
|
||||||
"embed_survey_preview_email_workspace_id": "Munkaterület azonosító",
|
|
||||||
"forgot_password_email_change_password": "Jelszó megváltoztatása",
|
"forgot_password_email_change_password": "Jelszó megváltoztatása",
|
||||||
"forgot_password_email_did_not_request": "Ha Ön nem kérte ezt, akkor hagyja figyelmen kívül ezt a levelet.",
|
"forgot_password_email_did_not_request": "Ha Ön nem kérte ezt, akkor hagyja figyelmen kívül ezt a levelet.",
|
||||||
"forgot_password_email_heading": "Jelszó megváltoztatása",
|
"forgot_password_email_heading": "Jelszó megváltoztatása",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Kérdés előnézete",
|
"question_preview": "Kérdés előnézete",
|
||||||
"response_already_received": "Már kaptunk választ erről az e-mail-címről.",
|
"response_already_received": "Már kaptunk választ erről az e-mail-címről.",
|
||||||
"response_submitted": "Ehhez a kérdőívhez és partnerhez kapcsolódó válasz már létezik",
|
"response_submitted": "Ehhez a kérdőívhez és partnerhez kapcsolódó válasz már létezik",
|
||||||
"scheduled": "Ez a felmérés hamarosan ütemezetten elindul.",
|
|
||||||
"survey_already_answered_heading": "A kérdőív már meg lett válaszolva.",
|
"survey_already_answered_heading": "A kérdőív már meg lett válaszolva.",
|
||||||
"survey_already_answered_subheading": "Ezt a hivatkozást csak egyszer használhatja.",
|
"survey_already_answered_subheading": "Ezt a hivatkozást csak egyszer használhatja.",
|
||||||
"survey_sent_to": "A kérdőív elküldve a(z) {email} e-mail-címre",
|
"survey_sent_to": "A kérdőív elküldve a(z) {email} e-mail-címre",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Egyéb",
|
"career_development_survey_question_6_choice_6": "Egyéb",
|
||||||
"career_development_survey_question_6_headline": "Az alábbiak közül melyik írja le legjobban a jelenlegi munkája szintjét?",
|
"career_development_survey_question_6_headline": "Az alábbiak közül melyik írja le legjobban a jelenlegi munkája szintjét?",
|
||||||
"career_development_survey_question_6_subheader": "Válassza ki a következő lehetőségek egyikét:",
|
"career_development_survey_question_6_subheader": "Válassza ki a következő lehetőségek egyikét:",
|
||||||
"ces": "Ügyfél Erőfeszítés (CES)",
|
|
||||||
"ces_description": "Ügyfél Erőfeszítési Pontszám mérése (1-5 vagy 1-7)",
|
|
||||||
"ces_lower_label": "Rendkívül nehéz",
|
|
||||||
"ces_upper_label": "Rendkívül könnyű",
|
|
||||||
"cess_survey_name": "Ügyfél-erőfeszítési pontszám kérdőív",
|
"cess_survey_name": "Ügyfél-erőfeszítési pontszám kérdőív",
|
||||||
"cess_survey_question_1_headline": "A(z) $[workspaceName] megkönnyíti számomra a következő cél elérését: [CÉL HOZZÁADÁSA]",
|
"cess_survey_question_1_headline": "A(z) $[workspaceName] megkönnyíti számomra a következő cél elérését: [CÉL HOZZÁADÁSA]",
|
||||||
"cess_survey_question_1_lower_label": "Egyáltalán nem értek egyet",
|
"cess_survey_question_1_lower_label": "Egyáltalán nem értek egyet",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Felhasználási feltételek vagy adatfelhasználás elfogadásának kérése",
|
"consent_description": "Felhasználási feltételek vagy adatfelhasználás elfogadásának kérése",
|
||||||
"contact_info": "Kapcsolatfelvételi információk",
|
"contact_info": "Kapcsolatfelvételi információk",
|
||||||
"contact_info_description": "Név, vezetéknév, e-mail-cím, telefonszám és vállalat együttes megadásának kérése",
|
"contact_info_description": "Név, vezetéknév, e-mail-cím, telefonszám és vállalat együttes megadásának kérése",
|
||||||
"csat": "Ügyfél Elégedettség (CSAT)",
|
"csat_description": "A termék vagy szolgáltatás ügyfél-elégedettségi pontszámának mérése.",
|
||||||
"csat_description": "Ügyfél Elégedettségi Pontszám mérése (1-5)",
|
|
||||||
"csat_lower_label": "Rendkívül elégedetlen",
|
|
||||||
"csat_name": "Ügyfél-elégedettségi pontszám (CSAT)",
|
"csat_name": "Ügyfél-elégedettségi pontszám (CSAT)",
|
||||||
"csat_question_10_headline": "Van még egyéb megjegyzése, kérdése vagy aggálya?",
|
"csat_question_10_headline": "Van még egyéb megjegyzése, kérdése vagy aggálya?",
|
||||||
"csat_question_10_placeholder": "Írja be ide a válaszát…",
|
"csat_question_10_placeholder": "Írja be ide a válaszát…",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Írja be ide a válaszát…",
|
"csat_survey_question_2_placeholder": "Írja be ide a válaszát…",
|
||||||
"csat_survey_question_3_headline": "Jaj, bocsánat! Tehetünk valamit, amivel javíthatnánk az élményén?",
|
"csat_survey_question_3_headline": "Jaj, bocsánat! Tehetünk valamit, amivel javíthatnánk az élményén?",
|
||||||
"csat_survey_question_3_placeholder": "Írja be ide a válaszát…",
|
"csat_survey_question_3_placeholder": "Írja be ide a válaszát…",
|
||||||
"csat_upper_label": "Rendkívül elégedett",
|
|
||||||
"cta_description": "Információk megjelenítése és a felhasználók felkérése egy bizonyos művelet elvégzésére",
|
"cta_description": "Információk megjelenítése és a felhasználók felkérése egy bizonyos művelet elvégzésére",
|
||||||
"custom_survey_description": "Kérdőív létrehozása sablon nélkül.",
|
"custom_survey_description": "Kérdőív létrehozása sablon nélkül.",
|
||||||
"custom_survey_name": "Kezdés a semmiből",
|
"custom_survey_name": "Kezdés a semmiből",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "Mi az egyetlen dolog, amelyet jobban csinálhatnánk?",
|
"gauge_feature_satisfaction_question_2_headline": "Mi az egyetlen dolog, amelyet jobban csinálhatnánk?",
|
||||||
"identify_customer_goals_description": "Jobban megérteni, hogy az üzenetei a termék által nyújtott érték megfelelő elvárásait keltik-e.",
|
"identify_customer_goals_description": "Jobban megérteni, hogy az üzenetei a termék által nyújtott érték megfelelő elvárásait keltik-e.",
|
||||||
"identify_customer_goals_name": "Ügyfélcélok azonosítása",
|
"identify_customer_goals_name": "Ügyfélcélok azonosítása",
|
||||||
"identify_customer_goals_question_1_choice_1": "Felhasználói bázis mélyreható megértése",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Felárképzési lehetőségek azonosítása",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "A lehető legjobb termék kifejlesztése",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "A világ meghódítása, hogy mindenki reggeli kelbimbót egyék",
|
|
||||||
"identify_customer_goals_question_1_headline": "Mi az Ön elsődleges célja a(z) $[workspaceName] használatával?",
|
|
||||||
"identify_sign_up_barriers_description": "Kedvezmény felajánlása a regisztrációs akadályokkal kapcsolatos tapasztalatok gyűjtéséhez.",
|
"identify_sign_up_barriers_description": "Kedvezmény felajánlása a regisztrációs akadályokkal kapcsolatos tapasztalatok gyűjtéséhez.",
|
||||||
"identify_sign_up_barriers_name": "Regisztrációs akadályok azonosítása",
|
"identify_sign_up_barriers_name": "Regisztrációs akadályok azonosítása",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "10% kedvezmény",
|
"identify_sign_up_barriers_question_1_button_label": "10% kedvezmény",
|
||||||
@@ -1164,14 +1145,12 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Segítsen nekünk jobban megérteni Önt:",
|
"improve_trial_conversion_question_1_subheader": "Segítsen nekünk jobban megérteni Önt:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Következő",
|
"improve_trial_conversion_question_2_button_label": "Következő",
|
||||||
"improve_trial_conversion_question_2_headline": "Sajnáljuk. Mi volt a legnagyobb probléma a $[workspaceName] használata során?",
|
"improve_trial_conversion_question_2_headline": "Sajnáljuk. Mi volt a legnagyobb probléma a $[workspaceName] használata során?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Tovább",
|
|
||||||
"improve_trial_conversion_question_3_headline": "Mire számított a(z) $[workspaceName] kapcsán?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "20% kedvezmény",
|
"improve_trial_conversion_question_4_button_label": "20% kedvezmény",
|
||||||
"improve_trial_conversion_question_4_headline": "Sajnálattal halljuk! 20% kedvezményt kap az első évre.",
|
"improve_trial_conversion_question_4_headline": "Sajnálattal halljuk! 20% kedvezményt kap az első évre.",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Boldogan felajánlunk 20% kedvezményt az éves csomagra.</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Boldogan felajánlunk 20% kedvezményt az éves csomagra.</span></p>",
|
||||||
"improve_trial_conversion_question_5_button_label": "Következő",
|
"improve_trial_conversion_question_5_button_label": "Következő",
|
||||||
"improve_trial_conversion_question_5_headline": "Mit szeretne elérni?",
|
"improve_trial_conversion_question_5_headline": "Mit szeretne elérni?",
|
||||||
"improve_trial_conversion_question_5_subheader": "Kérem, válasszon egyet a következő lehetőségek közül:",
|
"improve_trial_conversion_question_5_subheader": "Válassza ki a következő lehetőségek egyikét:",
|
||||||
"improve_trial_conversion_question_6_headline": "Hogyan oldja meg a problémáját most?",
|
"improve_trial_conversion_question_6_headline": "Hogyan oldja meg a problémáját most?",
|
||||||
"improve_trial_conversion_question_6_subheader": "Nevezzen meg alternatív megoldásokat:",
|
"improve_trial_conversion_question_6_subheader": "Nevezzen meg alternatív megoldásokat:",
|
||||||
"integration_setup_survey_description": "Annak kiértékelése, hogy a felhasználók mennyire könnyen tudnak integrációkat hozzáadni a termékéhez. A vakfoltok megtalálása.",
|
"integration_setup_survey_description": "Annak kiértékelése, hogy a felhasználók mennyire könnyen tudnak integrációkat hozzáadni a termékéhez. A vakfoltok megtalálása.",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Ez a művelet akkor lesz aktiválva, ha az oldal betöltődik.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Ez a művelet akkor lesz aktiválva, ha az oldal betöltődik.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Ez a művelet akkor lesz aktiválva, ha a felhasználó az oldal 50%-áig görget.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Ez a művelet akkor lesz aktiválva, ha a felhasználó az oldal 50%-áig görget.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Ez a művelet akkor lesz aktiválva, ha a felhasználó megpróbálja elhagyni az oldalt.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Ez a művelet akkor lesz aktiválva, ha a felhasználó megpróbálja elhagyni az oldalt.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Ez egy kódművelet. A változtatásokat a kódbázisban hajtsa végre.",
|
||||||
"time_in_seconds": "Idő másodpercben",
|
"time_in_seconds": "Idő másodpercben",
|
||||||
"time_in_seconds_placeholder": "például 10",
|
"time_in_seconds_placeholder": "például 10",
|
||||||
"time_in_seconds_with_unit": "{seconds} mp",
|
"time_in_seconds_with_unit": "{seconds} mp",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "API-kulcs frissítve",
|
"api_key_updated": "API-kulcs frissítve",
|
||||||
"delete_api_key_confirmation": "Az ezt a kulcsot használó bármely alkalmazás többé nem fog tudni hozzáférni a Formbricks adataihoz.",
|
"delete_api_key_confirmation": "Az ezt a kulcsot használó bármely alkalmazás többé nem fog tudni hozzáférni a Formbricks adataihoz.",
|
||||||
"duplicate_access": "A kettőzött munkaterület-hozzáférés nem engedélyezett",
|
"duplicate_access": "A kettőzött munkaterület-hozzáférés nem engedélyezett",
|
||||||
"duplicate_directory_access": "A duplikált visszajelzési rekord könyvtár hozzáférése nem engedélyezett",
|
|
||||||
"feedback_record_directory_access": "Visszajelzési Rekord Könyvtár Hozzáférés",
|
|
||||||
"no_api_keys_yet": "Még nincs semmilyen API-kulcsa",
|
"no_api_keys_yet": "Még nincs semmilyen API-kulcsa",
|
||||||
"no_directory_permissions_found": "Nem találhatók visszajelzési rekord könyvtár jogosultságok",
|
"no_env_permissions_found": "Nem találhatók környezetjogosultságok",
|
||||||
"no_workspace_permissions_found": "Nem találhatók munkaterület-jogosultságok",
|
|
||||||
"organization_access": "Szervezeti hozzáférés",
|
"organization_access": "Szervezeti hozzáférés",
|
||||||
"organization_access_description": "Olvasási vagy írási jogosultságok kiválasztása a teljes szervezetre vonatkozó erőforrásokhoz.",
|
"organization_access_description": "Olvasási vagy írási jogosultságok kiválasztása a teljes szervezetre vonatkozó erőforrásokhoz.",
|
||||||
"permissions": "Jogosultságok",
|
"permissions": "Jogosultságok",
|
||||||
"secret": "Titok",
|
"secret": "Titok",
|
||||||
"unable_to_copy_api_key": "Az API kulcs másolása nem lehetséges",
|
|
||||||
"unable_to_delete_api_key": "Nem lehet törölni az API-kulcsot",
|
"unable_to_delete_api_key": "Nem lehet törölni az API-kulcsot",
|
||||||
"unknown_directory": "Ismeretlen könyvtár",
|
|
||||||
"unknown_workspace": "Ismeretlen munkaterület",
|
|
||||||
"workspace_access": "Munkaterület-hozzáférés"
|
"workspace_access": "Munkaterület-hozzáférés"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Alkalmazás vagy webhely csatlakoztatása a Formbrickshez.",
|
"app_connection_description": "Alkalmazás vagy webhely csatlakoztatása a Formbrickshez.",
|
||||||
"cache_update_delay_description": "Ha frissítéseket hajt végre a kérdőíveken, partnereken, műveleteken vagy egyéb adatokon, akkor akár 1 percet is igénybe vehet, mire azok a változtatások megjelennek a Formbricks SDK-t futtató helyi alkalmazásban.",
|
"cache_update_delay_description": "Ha frissítéseket hajt végre a kérdőíveken, partnereken, műveleteken vagy egyéb adatokon, akkor akár 1 percet is igénybe vehet, mire azok a változtatások megjelennek a Formbricks SDK-t futtató helyi alkalmazásban.",
|
||||||
"cache_update_delay_title": "A változtatások körülbelül 1 perc múlva jelennek meg a gyorsítótárazás miatt",
|
"cache_update_delay_title": "A változtatások körülbelül 1 perc múlva jelennek meg a gyorsítótárazás miatt",
|
||||||
|
"environment_id": "Az Ön munkaterület-azonosítója",
|
||||||
|
"environment_id_description": "Ez az azonosító egyedileg azonosítja ezt a Formbricks munkaterületet.",
|
||||||
"formbricks_sdk_connected": "A Formbricks SDK csatlakoztatva van",
|
"formbricks_sdk_connected": "A Formbricks SDK csatlakoztatva van",
|
||||||
"formbricks_sdk_not_connected": "A Formbricks SDK még nincs csatlakoztatva.",
|
"formbricks_sdk_not_connected": "A Formbricks SDK még nincs csatlakoztatva.",
|
||||||
"formbricks_sdk_not_connected_description": "Adja hozzá a Formbricks SDK-t a webhelyéhez vagy az alkalmazásához, hogy összekapcsolja azt a Formbricks platformmal",
|
"formbricks_sdk_not_connected_description": "Adja hozzá a Formbricks SDK-t a webhelyéhez vagy az alkalmazásához, hogy összekapcsolja azt a Formbricks platformmal",
|
||||||
@@ -1866,12 +1842,10 @@
|
|||||||
"receiving_data": "Adatok fogadása 💃🕺",
|
"receiving_data": "Adatok fogadása 💃🕺",
|
||||||
"recheck": "Újraellenőrzés",
|
"recheck": "Újraellenőrzés",
|
||||||
"sdk_connection_details": "SDK-kapcsolat részletei",
|
"sdk_connection_details": "SDK-kapcsolat részletei",
|
||||||
"sdk_connection_details_description": "Az Ön egyedi munkaterület-azonosítója és SDK kapcsolati URL-je a Formbricks alkalmazásával való integrációhoz.",
|
"sdk_connection_details_description": "Az Ön egyedi munkaterület-azonosítója és SDK kapcsolati URL-címe a Formbricks alkalmazásával való integrációhoz.",
|
||||||
"setup_alert_description": "Kövesse ezt a léptékenkénti oktatóanyagot, hogy 5 perc alatt csatlakoztassa az alkalmazását vagy a webhelyét.",
|
"setup_alert_description": "Kövesse ezt a léptékenkénti oktatóanyagot, hogy 5 perc alatt csatlakoztassa az alkalmazását vagy a webhelyét.",
|
||||||
"setup_alert_title": "Hogyan kell kapcsolódni",
|
"setup_alert_title": "Hogyan kell kapcsolódni",
|
||||||
"webapp_url": "SDK-kapcsolati URL",
|
"webapp_url": "SDK-kapcsolati URL"
|
||||||
"workspace_id": "Az Ön munkaterület-azonosítója",
|
|
||||||
"workspace_id_description": "Ez az azonosító egyedileg azonosítja ezt a Formbricks munkaterületet."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Gratulálunk!",
|
"congrats": "Gratulálunk!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Attribútum értéke",
|
"attribute_value_placeholder": "Attribútum értéke",
|
||||||
"attributes_msg_attribute_limit_exceeded": "Nem sikerült létrehozni {count} új attribútumot, mivel túllépte volna a(z) {limit} attribútumosztályból álló legnagyobb korlátot. A meglévő attribútumok sikeresen frissítve lettek.",
|
"attributes_msg_attribute_limit_exceeded": "Nem sikerült létrehozni {count} új attribútumot, mivel túllépte volna a(z) {limit} attribútumosztályból álló legnagyobb korlátot. A meglévő attribútumok sikeresen frissítve lettek.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (a(z) “{key}” attribútum a következő adattípussal rendelkezik: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (a(z) “{key}” attribútum a következő adattípussal rendelkezik: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "Az e-mail cím már létezik ehhez a munkaterülethez, és nem lett frissítve.",
|
"attributes_msg_email_already_exists": "Az e-mail-cím már létezik ennél a környezetnél, és nem lett frissítve.",
|
||||||
"attributes_msg_email_or_userid_required": "Vagy e-mail-cím, vagy felhasználó-azonosító szükséges. A meglévő értékek megmaradtak.",
|
"attributes_msg_email_or_userid_required": "Vagy e-mail-cím, vagy felhasználó-azonosító szükséges. A meglévő értékek megmaradtak.",
|
||||||
"attributes_msg_new_attribute_created": "Az új „{dataType}” típusú „{key}” attribútum létrehozva",
|
"attributes_msg_new_attribute_created": "Az új „{dataType}” típusú „{key}” attribútum létrehozva",
|
||||||
"attributes_msg_userid_already_exists": "A felhasználói azonosító már létezik ehhez a munkaterülethez, és nem lett frissítve.",
|
"attributes_msg_userid_already_exists": "A felhasználó-azonosító már létezik ennél a környezetnél, és nem lett frissítve.",
|
||||||
"contact_deleted_successfully": "A partner sikeresen törölve",
|
"contact_deleted_successfully": "A partner sikeresen törölve",
|
||||||
"contacts_table_refresh": "Partnerek frissítése",
|
"contacts_table_refresh": "Partnerek frissítése",
|
||||||
"contacts_table_refresh_success": "A partnerek sikeresen frissítve",
|
"contacts_table_refresh_success": "A partnerek sikeresen frissítve",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Kettőzött nyelv vagy nyelvazonosító",
|
"duplicate_language_or_language_id": "Kettőzött nyelv vagy nyelvazonosító",
|
||||||
"edit_languages": "Nyelvek szerkesztése",
|
"edit_languages": "Nyelvek szerkesztése",
|
||||||
"identifier": "Azonosító (ISO)",
|
"identifier": "Azonosító (ISO)",
|
||||||
|
"incomplete_translations": "Befejezetlen fordítások",
|
||||||
"language": "Nyelv",
|
"language": "Nyelv",
|
||||||
"language_deleted_successfully": "A nyelv sikeresen törölve",
|
"language_deleted_successfully": "A nyelv sikeresen törölve",
|
||||||
"languages_updated_successfully": "A nyelvek sikeresen frissítve",
|
"languages_updated_successfully": "A nyelvek sikeresen frissítve",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Válasszon egy nyelvet",
|
"please_select_a_language": "Válasszon egy nyelvet",
|
||||||
"remove_language": "Nyelv eltávolítása",
|
"remove_language": "Nyelv eltávolítása",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Távolítsa el a nyelvet ezekből a kérdőívekből, hogy eltávolítsa azt a munkaterületről.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Távolítsa el a nyelvet ezekből a kérdőívekből, hogy eltávolítsa azt a munkaterületről.",
|
||||||
"search_items": "Elemek keresése"
|
"search_items": "Elemek keresése",
|
||||||
|
"translate": "Fordítás"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Háttérszín hozzáadása",
|
"add_background_color": "Háttérszín hozzáadása",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "Mindent beállított! Ideje létrehozni az első kérdőívet",
|
"all_set_time_to_create_first_survey": "Mindent beállított! Ideje létrehozni az első kérdőívet",
|
||||||
"alphabetical": "Ábécé-sorrend",
|
"alphabetical": "Ábécé-sorrend",
|
||||||
|
"copy_survey": "Kérdőív másolása",
|
||||||
|
"copy_survey_description": "Másolja át ezt a felmérést egy másik munkaterületre",
|
||||||
|
"copy_survey_error": "Nem sikerült másolni a kérdőívet",
|
||||||
"copy_survey_link_to_clipboard": "Kérdőív hivatkozásának másolása a vágólapra",
|
"copy_survey_link_to_clipboard": "Kérdőív hivatkozásának másolása a vágólapra",
|
||||||
|
"copy_survey_no_workspaces": "Nincsenek más munkaterületek, amelyekre átmásolhatná ezt a felmérést.",
|
||||||
|
"copy_survey_partially_success": "{success} kérdőív sikeresen másolva, {error} sikertelen.",
|
||||||
|
"copy_survey_success": "A kérdőív sikeresen másolva",
|
||||||
"delete_survey_and_responses_warning": "Biztosan törölni szeretné ezt a kérdőívet és az összes válaszát?",
|
"delete_survey_and_responses_warning": "Biztosan törölni szeretné ezt a kérdőívet és az összes válaszát?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Fordítások aktiválása",
|
"1_choose_the_default_language_for_this_survey": "1. Válassza ki a kérdőív alapértelmezett nyelvét:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Aktiválja a fordítást bizonyos nyelvekhez:",
|
||||||
"add": "Hozzáadás +",
|
"add": "Hozzáadás +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Késleltetés hozzáadása vagy a kérdőív automatikus lezárása",
|
"add_a_delay_or_auto_close_the_survey": "Késleltetés hozzáadása vagy a kérdőív automatikus lezárása",
|
||||||
"add_a_four_digit_pin": "Négy számjegyű PIN-kód hozzáadása",
|
"add_a_four_digit_pin": "Négy számjegyű PIN-kód hozzáadása",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Közönség",
|
"audience": "Közönség",
|
||||||
"auto_close_on_inactivity": "Automatikus lezárás tétlenségnél",
|
"auto_close_on_inactivity": "Automatikus lezárás tétlenségnél",
|
||||||
"auto_progress_rating_and_nps": "Automatikus továbblépés értékelési és NPS kérdéseknél",
|
"auto_progress_rating_and_nps": "Automatikus továbblépés értékelési és NPS kérdéseknél",
|
||||||
"auto_progress_rating_and_nps_description": "Automatikus továbblépés egyetlen kérdést tartalmazó blokkokban. A kötelező kérdések elrejtik a Tovább gombot, kivéve amikor az \"Egyéb\" opció van kiválasztva.",
|
"auto_progress_rating_and_nps_description": "Automatikus továbblépés, amikor a válaszadók kiválasztanak egy választ az értékelési vagy NPS kérdéseknél. Ez csak az egykérdéses blokkokra vonatkozik. A kötelező kérdések elrejtik a Tovább gombot; az opcionális kérdések továbbra is megjelenítik azt a kihagyás lehetősége érdekében.",
|
||||||
"auto_save_disabled": "Az automatikus mentés letiltva",
|
"auto_save_disabled": "Az automatikus mentés letiltva",
|
||||||
"auto_save_disabled_tooltip": "A kérdőív csak akkor kerül automatikusan mentésre, ha piszkozatban van. Ez biztosítja, hogy a nyilvános kérdőívek ne legyenek véletlenül frissítve.",
|
"auto_save_disabled_tooltip": "A kérdőív csak akkor kerül automatikusan mentésre, ha piszkozatban van. Ez biztosítja, hogy a nyilvános kérdőívek ne legyenek véletlenül frissítve.",
|
||||||
"auto_save_on": "Automatikus mentés bekapcsolva",
|
"auto_save_on": "Automatikus mentés bekapcsolva",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "A változtatások következetlenségekhez vezetnek",
|
"caution_text": "A változtatások következetlenségekhez vezetnek",
|
||||||
"change_anyway": "Változtatás mindenképp",
|
"change_anyway": "Változtatás mindenképp",
|
||||||
"change_background": "Háttér megváltoztatása",
|
"change_background": "Háttér megváltoztatása",
|
||||||
"change_default": "Alapértelmezett módosítása",
|
|
||||||
"change_question_type": "Kérdés típusának megváltoztatása",
|
"change_question_type": "Kérdés típusának megváltoztatása",
|
||||||
"change_survey_type": "A kérdőív típusának megváltoztatása befolyásolja a meglévő hozzáférést",
|
"change_survey_type": "A kérdőív típusának megváltoztatása befolyásolja a meglévő hozzáférést",
|
||||||
"change_the_background_to_a_color_image_or_animation": "A háttér megváltoztatása színre, képre vagy animációra.",
|
"change_the_background_to_a_color_image_or_animation": "A háttér megváltoztatása színre, képre vagy animációra.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Az első kérdés kiválasztása a blokkban",
|
"choose_the_first_question_on_your_block": "Az első kérdés kiválasztása a blokkban",
|
||||||
"choose_where_to_run_the_survey": "Annak kiválasztása, hogy hol fusson a kérdőív.",
|
"choose_where_to_run_the_survey": "Annak kiválasztása, hogy hol fusson a kérdőív.",
|
||||||
"city": "Város",
|
"city": "Város",
|
||||||
"clear_close_on_date": "Szüneteltetési dátum törlése",
|
|
||||||
"clear_publish_on_date": "Közzétételi dátum törlése",
|
|
||||||
"close_survey_on_date": "Szüneteltetés dátuma",
|
|
||||||
"close_survey_on_response_limit": "Kérdőív lezárása a válaszkorlátnál",
|
"close_survey_on_response_limit": "Kérdőív lezárása a válaszkorlátnál",
|
||||||
"code": "Kód",
|
|
||||||
"color": "Szín",
|
"color": "Szín",
|
||||||
"column_used_in_logic_error": "Ez az oszlop használatban van a(z) {questionIndex}. kérdés logikájában. Először távolítsa el a logikából.",
|
"column_used_in_logic_error": "Ez az oszlop használatban van a(z) {questionIndex}. kérdés logikájában. Először távolítsa el a logikából.",
|
||||||
"columns": "Oszlopok",
|
"columns": "Oszlopok",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "A kérdőív logójának személyre szabása",
|
"customize_survey_logo": "A kérdőív logójának személyre szabása",
|
||||||
"darken_or_lighten_background_of_your_choice": "A választási lehetőség hátterének sötétítése vagy világosítása.",
|
"darken_or_lighten_background_of_your_choice": "A választási lehetőség hátterének sötétítése vagy világosítása.",
|
||||||
"days_before_showing_this_survey_again": "vagy több napnak kell eltelnie az utolsó megjelenített kérdőív és ezen kérdőív megjelenése között.",
|
"days_before_showing_this_survey_again": "vagy több napnak kell eltelnie az utolsó megjelenített kérdőív és ezen kérdőív megjelenése között.",
|
||||||
"default_language": "Alapértelmezett nyelv",
|
|
||||||
"delete_anyways": "Törlés mindenképp",
|
"delete_anyways": "Törlés mindenképp",
|
||||||
"delete_block": "Blokk törlése",
|
"delete_block": "Blokk törlése",
|
||||||
"delete_choice": "Választási lehetőség törlése",
|
"delete_choice": "Választási lehetőség törlése",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Kérdés kettőzése",
|
"duplicate_question": "Kérdés kettőzése",
|
||||||
"edit_link": "Hivatkozás szerkesztése",
|
"edit_link": "Hivatkozás szerkesztése",
|
||||||
"edit_recall": "Visszahívás szerkesztése",
|
"edit_recall": "Visszahívás szerkesztése",
|
||||||
|
"edit_translations": "{lang} fordítások szerkesztése",
|
||||||
"element_not_found": "A kérdés nem található",
|
"element_not_found": "A kérdés nem található",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Lehetővé tétel a válaszadóknak, hogy bármikor nyelvet váltsanak. Legalább 2 aktív nyelvet igényel.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Lehetővé tétel a válaszadóknak, hogy bármikor nyelvet váltsanak. Legalább 2 aktív nyelvet igényel.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "A szemét elleni védekezés a reCAPTCHA v3-at használja a kéretlen válaszok kiszűréséhez.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "A szemét elleni védekezés a reCAPTCHA v3-at használja a kéretlen válaszok kiszűréséhez.",
|
||||||
@@ -3014,12 +2992,10 @@
|
|||||||
"long_answer_toggle_description": "Lehetővé tétel a válaszadóknak, hogy hosszabb, többsoros válaszokat írjanak.",
|
"long_answer_toggle_description": "Lehetővé tétel a válaszadóknak, hogy hosszabb, többsoros válaszokat írjanak.",
|
||||||
"lower_label": "Alsó címke",
|
"lower_label": "Alsó címke",
|
||||||
"manage_languages": "Nyelvek kezelése",
|
"manage_languages": "Nyelvek kezelése",
|
||||||
"manage_translations": "Fordítások kezelése",
|
|
||||||
"matrix_all_fields": "Összes mező",
|
"matrix_all_fields": "Összes mező",
|
||||||
"matrix_rows": "Sorok",
|
"matrix_rows": "Sorok",
|
||||||
"max_file_size": "Legnagyobb fájlméret",
|
"max_file_size": "Legnagyobb fájlméret",
|
||||||
"max_file_size_limit_is": "A legnagyobb fájlméretkorlát",
|
"max_file_size_limit_is": "A legnagyobb fájlméretkorlát",
|
||||||
"missing_first": "Hiányzók először",
|
|
||||||
"move_question_to_block": "Kérdés áthelyezése egy blokkba",
|
"move_question_to_block": "Kérdés áthelyezése egy blokkba",
|
||||||
"multiply": "Szorzás *",
|
"multiply": "Szorzás *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Saját üzemeltetésű Cal.com-példányhoz szükséges",
|
"needed_for_self_hosted_cal_com_instance": "Saját üzemeltetésű Cal.com-példányhoz szükséges",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "A „Következő” gomb címkéje",
|
"next_button_label": "A „Következő” gomb címkéje",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Még nincsenek rejtett mezők. Adja hozzá az elsőt lent.",
|
"no_hidden_fields_yet_add_first_one_below": "Még nincsenek rejtett mezők. Adja hozzá az elsőt lent.",
|
||||||
"no_images_found_for": "Nem találhatók képek a(z) „{query}” lekérdezéshez",
|
"no_images_found_for": "Nem találhatók képek a(z) „{query}” lekérdezéshez",
|
||||||
"no_languages_found_add_first_one_to_get_started": "Nem található felmérési nyelv ebben a munkaterületen. Kérem, adjon hozzá egyet a kezdéshez.",
|
"no_languages_found_add_first_one_to_get_started": "Nem találhatók nyelvek. Adja hozzá az elsőt a kezdéshez.",
|
||||||
"no_option_found": "Nem található lehetőség",
|
"no_option_found": "Nem található lehetőség",
|
||||||
"no_recall_items_found": "Nem találhatók visszahívási elemek",
|
"no_recall_items_found": "Nem találhatók visszahívási elemek",
|
||||||
"no_variables_yet_add_first_one_below": "Még nincsenek változók. Adja hozzá az elsőt lent.",
|
"no_variables_yet_add_first_one_below": "Még nincsenek változók. Adja hozzá az elsőt lent.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Adjon meg egy érvényes URL-t (például https://example.com)",
|
"please_enter_a_valid_url": "Adjon meg egy érvényes URL-t (például https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Állítson be kérdőív-aktiválót",
|
"please_set_a_survey_trigger": "Állítson be kérdőív-aktiválót",
|
||||||
"please_specify": "Adja meg",
|
"please_specify": "Adja meg",
|
||||||
"present_your_survey_in_multiple_languages": "Mutassa be felmérését több nyelven",
|
|
||||||
"prevent_double_submission": "Kettős beküldés megakadályozása",
|
"prevent_double_submission": "Kettős beküldés megakadályozása",
|
||||||
"prevent_double_submission_description": "E-mail-címenként csak 1 válasz engedélyezése",
|
"prevent_double_submission_description": "E-mail-címenként csak 1 válasz engedélyezése",
|
||||||
"progress_saved": "Folyamat elmentve",
|
"progress_saved": "Folyamat elmentve",
|
||||||
"protect_survey_with_pin": "Kérdőív megvédése PIN-kóddal",
|
"protect_survey_with_pin": "Kérdőív megvédése PIN-kóddal",
|
||||||
"protect_survey_with_pin_description": "Csak a PIN-kóddal rendelkező felhasználók férhetnek hozzá a kérdőívhez.",
|
"protect_survey_with_pin_description": "Csak a PIN-kóddal rendelkező felhasználók férhetnek hozzá a kérdőívhez.",
|
||||||
"publish": "Közzététel",
|
"publish": "Közzététel",
|
||||||
"publish_survey_on_date": "Közzététel dátuma",
|
|
||||||
"question": "Kérdés",
|
"question": "Kérdés",
|
||||||
"question_deleted": "Kérdés törölve.",
|
"question_deleted": "Kérdés törölve.",
|
||||||
"question_duplicated": "Kérdés megkettőzve.",
|
"question_duplicated": "Kérdés megkettőzve.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Sorok",
|
"rows": "Sorok",
|
||||||
"save_and_close": "Mentés és bezárás",
|
"save_and_close": "Mentés és bezárás",
|
||||||
"scale": "Méretezés",
|
"scale": "Méretezés",
|
||||||
"schedule_survey": "Felmérés ütemezése",
|
|
||||||
"search_for_images": "Képek keresése",
|
"search_for_images": "Képek keresése",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "másodperccel az aktiváló után a kérdőív le lesz zárva, ha nincs válasz",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "másodperccel az aktiváló után a kérdőív le lesz zárva, ha nincs válasz",
|
||||||
"seconds_before_showing_the_survey": "másodperc a kérdőív megjelenítése előtt.",
|
"seconds_before_showing_the_survey": "másodperc a kérdőív megjelenítése előtt.",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 pont",
|
"seven_points": "7 pont",
|
||||||
"show_block_settings": "Blokkbeállítások megjelenítése",
|
"show_block_settings": "Blokkbeállítások megjelenítése",
|
||||||
"show_button": "Gomb megjelenítése",
|
"show_button": "Gomb megjelenítése",
|
||||||
"show_in_order": "Sorrendben megjelenítés",
|
|
||||||
"show_language_switch": "Nyelvválasztó megjelenítése",
|
"show_language_switch": "Nyelvválasztó megjelenítése",
|
||||||
"show_multiple_times": "Megjelenítés korlátozott számú alkalommal",
|
"show_multiple_times": "Megjelenítés korlátozott számú alkalommal",
|
||||||
"show_only_once": "Megjelenítés csak egyszer",
|
"show_only_once": "Megjelenítés csak egyszer",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Kérdőív előnézete 👀",
|
"survey_preview": "Kérdőív előnézete 👀",
|
||||||
"survey_styling": "Kérdőív stílusának beállítása",
|
"survey_styling": "Kérdőív stílusának beállítása",
|
||||||
"survey_trigger": "Kérdőív aktiválója",
|
"survey_trigger": "Kérdőív aktiválója",
|
||||||
"survey_will_be_closed_at_midnight_cet": "A felmérés lezárásra kerül {time} időpontban a {timeZone} időzónában a kiválasztott napon",
|
"switch_multi_language_on_to_get_started": "Kapcsolja be a többnyelvűséget a kezdéshez 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "A felmérés közzétételre kerül {time} időpontban a {timeZone} időzónában a kiválasztott napon",
|
|
||||||
"target_block_not_found": "A célblokk nem található",
|
"target_block_not_found": "A célblokk nem található",
|
||||||
"targeted": "Célzott",
|
"targeted": "Célzott",
|
||||||
"ten_points": "10 pont",
|
"ten_points": "10 pont",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Megjelenítés egyetlen alkalommal, még akkor is, ha nem válaszolnak.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Megjelenítés egyetlen alkalommal, még akkor is, ha nem válaszolnak.",
|
||||||
"then": "Azután",
|
"then": "Azután",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Ez a művelet eltávolítja az összes fordítást ebből a kérdőívből.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Ez a művelet eltávolítja az összes fordítást ebből a kérdőívből.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Ez eltávolítja ezt a nyelvet és az összes fordítását ebből a felmérésből. Ez a művelet nem vonható vissza.",
|
|
||||||
"three_points": "3 pont",
|
"three_points": "3 pont",
|
||||||
"times": "alkalom",
|
"times": "alkalom",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Ahhoz, hogy következetesen megtartsa az elhelyezést az összes kérdőívnél, az alábbiakat teheti:",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Ahhoz, hogy következetesen megtartsa az elhelyezést az összes kérdőívnél, az alábbiakat teheti:",
|
||||||
"translated": "Lefordítva",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "A kérdőív aktiválása, ha a műveletek egyikét elindítják…",
|
"trigger_survey_when_one_of_the_actions_is_fired": "A kérdőív aktiválása, ha a műveletek egyikét elindítják…",
|
||||||
"try_lollipop_or_mountain": "A „nyalóka” vagy „hegy” kipróbálása…",
|
"try_lollipop_or_mountain": "A „nyalóka” vagy „hegy” kipróbálása…",
|
||||||
"type_field_id": "Mezőazonosító beírása",
|
"type_field_id": "Mezőazonosító beírása",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Csak valódi e-mail-címmel rendelkező személyek válaszolhassanak.",
|
"verify_email_before_submission_description": "Csak valódi e-mail-címmel rendelkező személyek válaszolhassanak.",
|
||||||
"visibility_and_recontact": "Láthatóság és újbóli kapcsolatfelvétel",
|
"visibility_and_recontact": "Láthatóság és újbóli kapcsolatfelvétel",
|
||||||
"visibility_and_recontact_description": "Annak vezérlése, hogy ez a kérdőív mikor jelenhet meg és milyen gyakran jelenhet meg újra.",
|
"visibility_and_recontact_description": "Annak vezérlése, hogy ez a kérdőív mikor jelenhet meg és milyen gyakran jelenhet meg újra.",
|
||||||
"visible": "Látható",
|
|
||||||
"wait": "Várakozás",
|
"wait": "Várakozás",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Várakozás néhány másodpercig az aktiválás után, mielőtt megjelenítené a kérdőívet",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Várakozás néhány másodpercig az aktiválás után, mielőtt megjelenítené a kérdőívet",
|
||||||
"waiting_time_across_surveys": "Várakozási időszak (kérdőívek között)",
|
"waiting_time_across_surveys": "Várakozási időszak (kérdőívek között)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Riasztások beállítása",
|
"configure_alerts": "Riasztások beállítása",
|
||||||
"congrats": "Gratulálunk! A kérdőíve élő.",
|
"congrats": "Gratulálunk! A kérdőíve élő.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "A webhelye vagy alkalmazása csatlakoztatása a Formbrickshez a kezdéshez.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "A webhelye vagy alkalmazása csatlakoztatása a Formbrickshez a kezdéshez.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% elégedett",
|
|
||||||
"csat_satisfied_tooltip": "A válaszadók {percentage}%-a 4-es vagy 5-ös értékelést adott (CSAT).",
|
|
||||||
"current_count": "Jelenlegi darabszám",
|
"current_count": "Jelenlegi darabszám",
|
||||||
"custom_range": "Egyéni tartomány…",
|
"custom_range": "Egyéni tartomány…",
|
||||||
"delete_all_existing_responses_and_displays": "Az összes meglévő válasz és megjelenítés törlése",
|
"delete_all_existing_responses_and_displays": "Az összes meglévő válasz és megjelenítés törlése",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "QR-kód letöltése",
|
"downloading_qr_code": "QR-kód letöltése",
|
||||||
"drop_offs": "Megszakítások",
|
"drop_offs": "Megszakítások",
|
||||||
"drop_offs_tooltip": "A kérdőív elkezdési, de be nem fejezési alkalmainak száma.",
|
"drop_offs_tooltip": "A kérdőív elkezdési, de be nem fejezési alkalmainak száma.",
|
||||||
"effort_score": "Erőfeszítési Pontszám",
|
"failed_to_copy_link": "Nem sikerült a hivatkozás másolása",
|
||||||
"filter_added_successfully": "A szűrő sikeresen hozzáadva",
|
"filter_added_successfully": "A szűrő sikeresen hozzáadva",
|
||||||
"filter_updated_successfully": "A szűrő sikeresen frissítve",
|
"filter_updated_successfully": "A szűrő sikeresen frissítve",
|
||||||
"filtered_responses_csv": "Szűrt válaszok (CSV)",
|
"filtered_responses_csv": "Szűrt válaszok (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Korlát",
|
"limit": "Korlát",
|
||||||
"no_identified_impressions": "Nincsenek azonosított partnerektől származó megtekintések",
|
"no_identified_impressions": "Nincsenek azonosított partnerektől származó megtekintések",
|
||||||
"no_responses_found": "Nem találhatók válaszok",
|
"no_responses_found": "Nem találhatók válaszok",
|
||||||
"nps_promoters_tooltip": "A válaszadók {percentage}%-a 9-es vagy 10-es értékelést adott (NPS promoters).",
|
|
||||||
"other_values_found": "Más értékek találhatók",
|
"other_values_found": "Más értékek találhatók",
|
||||||
"overall": "Összesen",
|
"overall": "Összesen",
|
||||||
"promoters": "Népszerűsítők",
|
"promoters": "Népszerűsítők",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "A válaszadók által teljesített kvóták száma.",
|
"quotas_completed_tooltip": "A válaszadók által teljesített kvóták száma.",
|
||||||
"reset_survey": "Kérdőív visszaállítása",
|
"reset_survey": "Kérdőív visszaállítása",
|
||||||
"reset_survey_warning": "Egy kérdőív visszaállítása eltávolítja a kérdőívhez hozzárendelt összes választ és megjelenítést. Ezt nem lehet visszavonni.",
|
"reset_survey_warning": "Egy kérdőív visszaállítása eltávolítja a kérdőívhez hozzárendelt összes választ és megjelenítést. Ezt nem lehet visszavonni.",
|
||||||
|
"satisfied": "Elégedett",
|
||||||
"selected_responses_csv": "Kijelölt válaszok (CSV)",
|
"selected_responses_csv": "Kijelölt válaszok (CSV)",
|
||||||
"selected_responses_excel": "Kijelölt válaszok (Excel)",
|
"selected_responses_excel": "Kijelölt válaszok (Excel)",
|
||||||
"setup_integrations": "Integrációk beállítása",
|
"setup_integrations": "Integrációk beállítása",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "A kérdőív elkezdési alkalmainak száma.",
|
"starts_tooltip": "A kérdőív elkezdési alkalmainak száma.",
|
||||||
"survey_reset_successfully": "A kérdőív sikeresen visszaállítva. {responseCount} válasz és {displayCount} megjelenítés lett törölve.",
|
"survey_reset_successfully": "A kérdőív sikeresen visszaállítva. {responseCount} válasz és {displayCount} megjelenítés lett törölve.",
|
||||||
"survey_results": "{surveyName} eredményei",
|
"survey_results": "{surveyName} eredményei",
|
||||||
"survey_scheduled_successfully": "A felmérés sikeresen ütemezve lett",
|
|
||||||
"this_month": "Ez a hónap",
|
"this_month": "Ez a hónap",
|
||||||
"this_quarter": "Ez a negyedév",
|
"this_quarter": "Ez a negyedév",
|
||||||
"this_year": "Ez az év",
|
"this_year": "Ez az év",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "A kérdőív sikeresen törölve",
|
"survey_deleted_successfully": "A kérdőív sikeresen törölve",
|
||||||
"survey_duplicated_successfully": "A kérdőív sikeresen megkettőzve",
|
"survey_duplicated_successfully": "A kérdőív sikeresen megkettőzve",
|
||||||
|
"survey_duplication_error": "Nem sikerült megkettőzni a kérdőívet.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Összes csatorna",
|
"all_channels": "Összes csatorna",
|
||||||
"all_industries": "Összes iparág",
|
"all_industries": "Összes iparág",
|
||||||
|
|||||||
+34
-68
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "ワークスペースを変更",
|
"change_workspace": "ワークスペースを変更",
|
||||||
"chart": "チャート",
|
"chart": "チャート",
|
||||||
"charts": "チャート",
|
"charts": "チャート",
|
||||||
"choice_n": "選択肢 {{n}}",
|
|
||||||
"choices": "選択肢",
|
"choices": "選択肢",
|
||||||
"choose_organization": "組織を選択",
|
"choose_organization": "組織を選択",
|
||||||
"choose_workspace": "ワークスペースを選択",
|
"choose_workspace": "ワークスペースを選択",
|
||||||
@@ -172,7 +171,6 @@
|
|||||||
"close": "閉じる",
|
"close": "閉じる",
|
||||||
"code": "コード",
|
"code": "コード",
|
||||||
"collapse_rows": "行を非表示",
|
"collapse_rows": "行を非表示",
|
||||||
"column_n": "列 {{n}}",
|
|
||||||
"completed": "完了",
|
"completed": "完了",
|
||||||
"configuration": "設定",
|
"configuration": "設定",
|
||||||
"confirm": "確認",
|
"confirm": "確認",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "終了カード",
|
"ending_card": "終了カード",
|
||||||
"enter_url": "URLを入力",
|
"enter_url": "URLを入力",
|
||||||
"enterprise_license": "エンタープライズライセンス",
|
"enterprise_license": "エンタープライズライセンス",
|
||||||
|
"environment": "環境",
|
||||||
"error": "エラー",
|
"error": "エラー",
|
||||||
"error_component_description": "この リソース は 存在 しない か、アクセス する ための 必要な 権限 が ありません。",
|
"error_component_description": "この リソース は 存在 しない か、アクセス する ための 必要な 権限 が ありません。",
|
||||||
"error_component_title": "リソース の 読み込み エラー",
|
"error_component_title": "リソース の 読み込み エラー",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "組織の読み込みに失敗しました",
|
"failed_to_load_organizations": "組織の読み込みに失敗しました",
|
||||||
"failed_to_load_workspaces": "ワークスペースの読み込みに失敗しました",
|
"failed_to_load_workspaces": "ワークスペースの読み込みに失敗しました",
|
||||||
"failed_to_parse_csv": "CSVの解析に失敗しました",
|
"failed_to_parse_csv": "CSVの解析に失敗しました",
|
||||||
"field_placeholder": "{{field}} プレースホルダー",
|
|
||||||
"filter": "フィルター",
|
"filter": "フィルター",
|
||||||
"finish": "完了",
|
"finish": "完了",
|
||||||
"first_name": "名",
|
"first_name": "名",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "生成",
|
"generate": "生成",
|
||||||
"go_back": "戻る",
|
"go_back": "戻る",
|
||||||
"go_to_dashboard": "ダッシュボードへ移動",
|
"go_to_dashboard": "ダッシュボードへ移動",
|
||||||
"headline": "見出し",
|
|
||||||
"hidden": "非表示",
|
"hidden": "非表示",
|
||||||
"hidden_field": "非表示フィールド",
|
"hidden_field": "非表示フィールド",
|
||||||
"hidden_fields": "非表示フィールド",
|
"hidden_fields": "非表示フィールド",
|
||||||
"hide": "非表示",
|
"hide": "非表示",
|
||||||
"hide_column": "列を非表示",
|
"hide_column": "列を非表示",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "画像",
|
"image": "画像",
|
||||||
"images": "画像",
|
"images": "画像",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "その他のオプション",
|
"more_options": "その他のオプション",
|
||||||
"move_down": "下に移動",
|
"move_down": "下に移動",
|
||||||
"move_up": "上に移動",
|
"move_up": "上に移動",
|
||||||
|
"multiple_languages": "多言語",
|
||||||
"my_product": "マイプロダクト",
|
"my_product": "マイプロダクト",
|
||||||
"name": "名前",
|
"name": "名前",
|
||||||
"new": "新規",
|
"new": "新規",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "結果が見つかりません",
|
"no_result_found": "結果が見つかりません",
|
||||||
"no_results": "結果なし",
|
"no_results": "結果なし",
|
||||||
"no_surveys_found": "フォームが見つかりません。",
|
"no_surveys_found": "フォームが見つかりません。",
|
||||||
"no_text_found": "テキストが見つかりません",
|
|
||||||
"none_of_the_above": "いずれも該当しません",
|
"none_of_the_above": "いずれも該当しません",
|
||||||
"not_authenticated": "このアクションを実行するための認証がされていません。",
|
"not_authenticated": "このアクションを実行するための認証がされていません。",
|
||||||
"not_authorized": "権限がありません",
|
"not_authorized": "権限がありません",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "組織設定",
|
"organization_settings": "組織設定",
|
||||||
"other": "その他",
|
"other": "その他",
|
||||||
"other_filters": "その他のフィルター",
|
"other_filters": "その他のフィルター",
|
||||||
"other_placeholder": "その他のプレースホルダー",
|
"others": "その他",
|
||||||
"overlay_color": "オーバーレイの色",
|
"overlay_color": "オーバーレイの色",
|
||||||
"overview": "概要",
|
"overview": "概要",
|
||||||
"password": "パスワード",
|
"password": "パスワード",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "プランをアップグレードしてください",
|
"please_upgrade_your_plan": "プランをアップグレードしてください",
|
||||||
"powered_by_formbricks": "Powered by Formbricks",
|
"powered_by_formbricks": "Powered by Formbricks",
|
||||||
"preview": "プレビュー",
|
"preview": "プレビュー",
|
||||||
|
"preview_survey": "フォームをプレビュー",
|
||||||
"privacy": "プライバシーポリシー",
|
"privacy": "プライバシーポリシー",
|
||||||
"product_manager": "プロダクトマネージャー",
|
"product_manager": "プロダクトマネージャー",
|
||||||
|
"production": "本番",
|
||||||
"profile": "プロフィール",
|
"profile": "プロフィール",
|
||||||
"profile_id": "プロフィールID",
|
"profile_id": "プロフィールID",
|
||||||
"progress": "進捗",
|
"progress": "進捗",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "再開",
|
"restart": "再開",
|
||||||
"retry": "再試行",
|
"retry": "再試行",
|
||||||
"role": "役割",
|
"role": "役割",
|
||||||
"row_n": "行 {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "セールス",
|
"sales": "セールス",
|
||||||
"save": "保存",
|
"save": "保存",
|
||||||
"save_as_draft": "下書きとして保存",
|
"save_as_draft": "下書きとして保存",
|
||||||
"save_changes": "変更を保存",
|
"save_changes": "変更を保存",
|
||||||
"save_without_scheduling": "スケジュールせずに保存",
|
|
||||||
"saving": "保存中",
|
"saving": "保存中",
|
||||||
"scheduled": "予定済み",
|
|
||||||
"search": "検索",
|
"search": "検索",
|
||||||
"search_charts": "グラフを検索...",
|
"search_charts": "グラフを検索...",
|
||||||
"security": "セキュリティ",
|
"security": "セキュリティ",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "ファイルストレージが設定されていないため、アップロードは失敗する可能性があります",
|
"storage_not_configured": "ファイルストレージが設定されていないため、アップロードは失敗する可能性があります",
|
||||||
"string": "テキスト",
|
"string": "テキスト",
|
||||||
"styling": "スタイル",
|
"styling": "スタイル",
|
||||||
"subheader": "小見出し",
|
|
||||||
"submit": "送信",
|
"submit": "送信",
|
||||||
"summary": "概要",
|
"summary": "概要",
|
||||||
"survey": "フォーム",
|
"survey": "フォーム",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "フォームの言語",
|
"survey_languages": "フォームの言語",
|
||||||
"survey_live": "フォーム公開中",
|
"survey_live": "フォーム公開中",
|
||||||
"survey_paused": "フォームは一時停止中です。",
|
"survey_paused": "フォームは一時停止中です。",
|
||||||
"survey_scheduled": "アンケートが予定されました。",
|
|
||||||
"survey_type": "フォームの種類",
|
"survey_type": "フォームの種類",
|
||||||
"surveys": "フォーム",
|
"surveys": "フォーム",
|
||||||
"table_items_deleted_successfully": "{type}を正常に削除しました",
|
"table_items_deleted_successfully": "{type}を正常に削除しました",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "ワークスペース",
|
"workspaces": "ワークスペース",
|
||||||
"years": "年",
|
"years": "年",
|
||||||
"yes": "はい",
|
"yes": "はい",
|
||||||
|
"you": "あなた",
|
||||||
"you_are_downgraded_to_the_community_edition": "コミュニティ版にダウングレードされました。",
|
"you_are_downgraded_to_the_community_edition": "コミュニティ版にダウングレードされました。",
|
||||||
"you_are_not_authorized_to_perform_this_action": "このアクションを実行する権限がありません。",
|
"you_are_not_authorized_to_perform_this_action": "このアクションを実行する権限がありません。",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "ワークスペースの上限である{workspaceLimit}件に達しました。",
|
"you_have_reached_your_limit_of_workspace_limit": "ワークスペースの上限である{workspaceLimit}件に達しました。",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "Formbricksチーム",
|
"email_footer_text_2": "Formbricksチーム",
|
||||||
"email_template_text_1": "このメールはFormbricks経由で送信されました。",
|
"email_template_text_1": "このメールはFormbricks経由で送信されました。",
|
||||||
"embed_survey_preview_email_didnt_request": "これをリクエストしていませんか?",
|
"embed_survey_preview_email_didnt_request": "これをリクエストしていませんか?",
|
||||||
|
"embed_survey_preview_email_environment_id": "環境ID",
|
||||||
"embed_survey_preview_email_fight_spam": "スパム対策にご協力ください。このメールを hola@formbricks.com に転送してください",
|
"embed_survey_preview_email_fight_spam": "スパム対策にご協力ください。このメールを hola@formbricks.com に転送してください",
|
||||||
"embed_survey_preview_email_heading": "メール埋め込みプレビュー",
|
"embed_survey_preview_email_heading": "メール埋め込みプレビュー",
|
||||||
"embed_survey_preview_email_subject": "Formbricks メールフォームプレビュー",
|
"embed_survey_preview_email_subject": "Formbricks メールフォームプレビュー",
|
||||||
"embed_survey_preview_email_text": "以下は、メールに埋め込まれたコードスニペットの見た目です。",
|
"embed_survey_preview_email_text": "以下は、メールに埋め込まれたコードスニペットの見た目です。",
|
||||||
"embed_survey_preview_email_workspace_id": "ワークスペースID",
|
|
||||||
"forgot_password_email_change_password": "パスワードを変更",
|
"forgot_password_email_change_password": "パスワードを変更",
|
||||||
"forgot_password_email_did_not_request": "このリクエストに心当たりのない場合は、このメールを無視してください。",
|
"forgot_password_email_did_not_request": "このリクエストに心当たりのない場合は、このメールを無視してください。",
|
||||||
"forgot_password_email_heading": "パスワードを変更",
|
"forgot_password_email_heading": "パスワードを変更",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "質問プレビュー",
|
"question_preview": "質問プレビュー",
|
||||||
"response_already_received": "このメールアドレスの回答はすでに受け付けています。",
|
"response_already_received": "このメールアドレスの回答はすでに受け付けています。",
|
||||||
"response_submitted": "このフォームと連絡先にリンクされた回答がすでに存在します",
|
"response_submitted": "このフォームと連絡先にリンクされた回答がすでに存在します",
|
||||||
"scheduled": "このアンケートはまもなく公開予定です。",
|
|
||||||
"survey_already_answered_heading": "このフォームはすでに回答されています。",
|
"survey_already_answered_heading": "このフォームはすでに回答されています。",
|
||||||
"survey_already_answered_subheading": "このリンクは一度だけしか使用できません。",
|
"survey_already_answered_subheading": "このリンクは一度だけしか使用できません。",
|
||||||
"survey_sent_to": "{email} にフォームを送信しました",
|
"survey_sent_to": "{email} にフォームを送信しました",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "その他",
|
"career_development_survey_question_6_choice_6": "その他",
|
||||||
"career_development_survey_question_6_headline": "あなたの現在の役職に最も近いものは何ですか?",
|
"career_development_survey_question_6_headline": "あなたの現在の役職に最も近いものは何ですか?",
|
||||||
"career_development_survey_question_6_subheader": "以下のオプションから一つ選択してください",
|
"career_development_survey_question_6_subheader": "以下のオプションから一つ選択してください",
|
||||||
"ces": "顧客努力指標(CES)",
|
|
||||||
"ces_description": "顧客努力スコアを測定します(1-5または1-7)",
|
|
||||||
"ces_lower_label": "非常に難しい",
|
|
||||||
"ces_upper_label": "非常に簡単",
|
|
||||||
"cess_survey_name": "CESアンケート",
|
"cess_survey_name": "CESアンケート",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName]を使うと、[目標を追加]することが簡単にできます",
|
"cess_survey_question_1_headline": "$[workspaceName]を使うと、[目標を追加]することが簡単にできます",
|
||||||
"cess_survey_question_1_lower_label": "全くそう思わない",
|
"cess_survey_question_1_lower_label": "全くそう思わない",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "規約、条件、またはデータ使用に同意を求める",
|
"consent_description": "規約、条件、またはデータ使用に同意を求める",
|
||||||
"contact_info": "連絡先情報",
|
"contact_info": "連絡先情報",
|
||||||
"contact_info_description": "名前、苗字、メール、電話番号、会社をまとめて尋ねる",
|
"contact_info_description": "名前、苗字、メール、電話番号、会社をまとめて尋ねる",
|
||||||
"csat": "顧客満足度(CSAT)",
|
"csat_description": "あなたの製品やサービスの顧客満足度(CSAT)を測定する。",
|
||||||
"csat_description": "顧客満足度スコアを測定します(1-5)",
|
|
||||||
"csat_lower_label": "非常に不満",
|
|
||||||
"csat_name": "顧客満足度(CSAT)",
|
"csat_name": "顧客満足度(CSAT)",
|
||||||
"csat_question_10_headline": "他に何かコメント、質問、懸念はありますか?",
|
"csat_question_10_headline": "他に何かコメント、質問、懸念はありますか?",
|
||||||
"csat_question_10_placeholder": "ここに回答を入力してください...",
|
"csat_question_10_placeholder": "ここに回答を入力してください...",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "ここに回答を入力してください...",
|
"csat_survey_question_2_placeholder": "ここに回答を入力してください...",
|
||||||
"csat_survey_question_3_headline": "申し訳ありません!体験を改善するために何かできることはありますか?",
|
"csat_survey_question_3_headline": "申し訳ありません!体験を改善するために何かできることはありますか?",
|
||||||
"csat_survey_question_3_placeholder": "ここに回答を入力してください...",
|
"csat_survey_question_3_placeholder": "ここに回答を入力してください...",
|
||||||
"csat_upper_label": "非常に満足",
|
|
||||||
"cta_description": "情報を表示し、特定の行動を促す",
|
"cta_description": "情報を表示し、特定の行動を促す",
|
||||||
"custom_survey_description": "テンプレートを使わずにアンケートを作成する。",
|
"custom_survey_description": "テンプレートを使わずにアンケートを作成する。",
|
||||||
"custom_survey_name": "最初から始める",
|
"custom_survey_name": "最初から始める",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "私たちがもっとうまくできることは何ですか?",
|
"gauge_feature_satisfaction_question_2_headline": "私たちがもっとうまくできることは何ですか?",
|
||||||
"identify_customer_goals_description": "あなたのメッセージが製品の価値に対する正しい期待を抱かせているかどうかをよりよく理解する。",
|
"identify_customer_goals_description": "あなたのメッセージが製品の価値に対する正しい期待を抱かせているかどうかをよりよく理解する。",
|
||||||
"identify_customer_goals_name": "顧客目標の特定",
|
"identify_customer_goals_name": "顧客目標の特定",
|
||||||
"identify_customer_goals_question_1_choice_1": "ユーザーベースを深く理解する",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "アップセルの機会を特定する",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "最高の製品を構築する",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "世界を支配してみんなに朝食の芽キャベツを食べさせる",
|
|
||||||
"identify_customer_goals_question_1_headline": "$[workspaceName]を使用する主な目的は何ですか?",
|
|
||||||
"identify_sign_up_barriers_description": "サインアップの障壁に関する洞察を得るために割引を提供する。",
|
"identify_sign_up_barriers_description": "サインアップの障壁に関する洞察を得るために割引を提供する。",
|
||||||
"identify_sign_up_barriers_name": "サインアップの障壁を特定する",
|
"identify_sign_up_barriers_name": "サインアップの障壁を特定する",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "10%割引を取得",
|
"identify_sign_up_barriers_question_1_button_label": "10%割引を取得",
|
||||||
@@ -1164,14 +1145,12 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "私たちをよりよく理解するためにお手伝いください:",
|
"improve_trial_conversion_question_1_subheader": "私たちをよりよく理解するためにお手伝いください:",
|
||||||
"improve_trial_conversion_question_2_button_label": "次へ",
|
"improve_trial_conversion_question_2_button_label": "次へ",
|
||||||
"improve_trial_conversion_question_2_headline": "残念です。$[workspaceName]を使う上で一番の問題は何でしたか?",
|
"improve_trial_conversion_question_2_headline": "残念です。$[workspaceName]を使う上で一番の問題は何でしたか?",
|
||||||
"improve_trial_conversion_question_3_button_label": "次へ",
|
|
||||||
"improve_trial_conversion_question_3_headline": "$[workspaceName]に何を期待していましたか?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "20%オフを取得",
|
"improve_trial_conversion_question_4_button_label": "20%オフを取得",
|
||||||
"improve_trial_conversion_question_4_headline": "残念です!初年度20%オフをゲット。",
|
"improve_trial_conversion_question_4_headline": "残念です!初年度20%オフをゲット。",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>年間プランで20%の割引を提供させていただきます。</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>年間プランで20%の割引を提供させていただきます。</span></p>",
|
||||||
"improve_trial_conversion_question_5_button_label": "次へ",
|
"improve_trial_conversion_question_5_button_label": "次へ",
|
||||||
"improve_trial_conversion_question_5_headline": "何を達成したいですか?",
|
"improve_trial_conversion_question_5_headline": "何を達成したいですか?",
|
||||||
"improve_trial_conversion_question_5_subheader": "以下のオプションから1つ選択してください:",
|
"improve_trial_conversion_question_5_subheader": "以下のオプションから一つ選択してください:",
|
||||||
"improve_trial_conversion_question_6_headline": "今、問題をどのように解決していますか?",
|
"improve_trial_conversion_question_6_headline": "今、問題をどのように解決していますか?",
|
||||||
"improve_trial_conversion_question_6_subheader": "代替ソリューションを挙げてください:",
|
"improve_trial_conversion_question_6_subheader": "代替ソリューションを挙げてください:",
|
||||||
"integration_setup_survey_description": "ユーザーが製品に統合を追加するのがどれだけ簡単かを評価する。盲点を見つける。",
|
"integration_setup_survey_description": "ユーザーが製品に統合を追加するのがどれだけ簡単かを評価する。盲点を見つける。",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "このアクションは、ページが読み込まれたときにトリガーされます。",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "このアクションは、ページが読み込まれたときにトリガーされます。",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "このアクションは、ユーザーがページの50%をスクロールしたときにトリガーされます。",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "このアクションは、ユーザーがページの50%をスクロールしたときにトリガーされます。",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "このアクションは、ユーザーがページを離れようとしたときにトリガーされます。",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "このアクションは、ユーザーがページを離れようとしたときにトリガーされます。",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "これはコードアクションです。コードベースで変更を行ってください。",
|
||||||
"time_in_seconds": "秒数",
|
"time_in_seconds": "秒数",
|
||||||
"time_in_seconds_placeholder": "例: 10",
|
"time_in_seconds_placeholder": "例: 10",
|
||||||
"time_in_seconds_with_unit": "{seconds}秒",
|
"time_in_seconds_with_unit": "{seconds}秒",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "APIキーを更新しました",
|
"api_key_updated": "APIキーを更新しました",
|
||||||
"delete_api_key_confirmation": "このキーを使用しているアプリケーションは、Formbricksデータにアクセスできなくなります。",
|
"delete_api_key_confirmation": "このキーを使用しているアプリケーションは、Formbricksデータにアクセスできなくなります。",
|
||||||
"duplicate_access": "ワークスペースへの重複アクセスは許可されていません",
|
"duplicate_access": "ワークスペースへの重複アクセスは許可されていません",
|
||||||
"duplicate_directory_access": "重複したフィードバックレコードディレクトリへのアクセスは許可されていません",
|
|
||||||
"feedback_record_directory_access": "フィードバックレコードディレクトリへのアクセス",
|
|
||||||
"no_api_keys_yet": "まだAPIキーがありません",
|
"no_api_keys_yet": "まだAPIキーがありません",
|
||||||
"no_directory_permissions_found": "フィードバックレコードディレクトリの権限が見つかりません",
|
"no_env_permissions_found": "環境の権限が見つかりません",
|
||||||
"no_workspace_permissions_found": "ワークスペースの権限が見つかりません",
|
|
||||||
"organization_access": "組織アクセス",
|
"organization_access": "組織アクセス",
|
||||||
"organization_access_description": "組織全体のリソースに対する読み取りまたは書き込み権限を選択してください。",
|
"organization_access_description": "組織全体のリソースに対する読み取りまたは書き込み権限を選択してください。",
|
||||||
"permissions": "権限",
|
"permissions": "権限",
|
||||||
"secret": "シークレット",
|
"secret": "シークレット",
|
||||||
"unable_to_copy_api_key": "APIキーをコピーできません",
|
|
||||||
"unable_to_delete_api_key": "APIキーを削除できません",
|
"unable_to_delete_api_key": "APIキーを削除できません",
|
||||||
"unknown_directory": "不明なディレクトリ",
|
|
||||||
"unknown_workspace": "不明なワークスペース",
|
|
||||||
"workspace_access": "ワークスペースアクセス"
|
"workspace_access": "ワークスペースアクセス"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "アプリやウェブサイトをFormbricksに接続します。",
|
"app_connection_description": "アプリやウェブサイトをFormbricksに接続します。",
|
||||||
"cache_update_delay_description": "アンケート、連絡先、アクション、その他のデータを更新した場合、Formbricks SDKを実行しているローカルアプリに変更が反映されるまで最大1分かかることがあります。",
|
"cache_update_delay_description": "アンケート、連絡先、アクション、その他のデータを更新した場合、Formbricks SDKを実行しているローカルアプリに変更が反映されるまで最大1分かかることがあります。",
|
||||||
"cache_update_delay_title": "キャッシュにより変更は約1分後に反映されます",
|
"cache_update_delay_title": "キャッシュにより変更は約1分後に反映されます",
|
||||||
|
"environment_id": "ワークスペースID",
|
||||||
|
"environment_id_description": "このIDは、このFormbricksワークスペースを一意に識別します。",
|
||||||
"formbricks_sdk_connected": "Formbricks SDKは接続されています",
|
"formbricks_sdk_connected": "Formbricks SDKは接続されています",
|
||||||
"formbricks_sdk_not_connected": "Formbricks SDKはまだ接続されていません。",
|
"formbricks_sdk_not_connected": "Formbricks SDKはまだ接続されていません。",
|
||||||
"formbricks_sdk_not_connected_description": "ウェブサイトやアプリにFormbricks SDKを追加してFormbricksと接続してください",
|
"formbricks_sdk_not_connected_description": "ウェブサイトやアプリにFormbricks SDKを追加してFormbricksと接続してください",
|
||||||
@@ -1869,9 +1845,7 @@
|
|||||||
"sdk_connection_details_description": "アプリケーションとFormbricksを統合するための固有のワークスペースIDとSDK接続URLです。",
|
"sdk_connection_details_description": "アプリケーションとFormbricksを統合するための固有のワークスペースIDとSDK接続URLです。",
|
||||||
"setup_alert_description": "このステップバイステップのチュートリアルに従って、5分以内にアプリやウェブサイトを接続してください。",
|
"setup_alert_description": "このステップバイステップのチュートリアルに従って、5分以内にアプリやウェブサイトを接続してください。",
|
||||||
"setup_alert_title": "接続方法",
|
"setup_alert_title": "接続方法",
|
||||||
"webapp_url": "SDK接続URL",
|
"webapp_url": "SDK接続URL"
|
||||||
"workspace_id": "ワークスペースID",
|
|
||||||
"workspace_id_description": "このIDは、このFormbricksワークスペースを一意に識別します。"
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "おめでとうございます!",
|
"congrats": "おめでとうございます!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "属性値",
|
"attribute_value_placeholder": "属性値",
|
||||||
"attributes_msg_attribute_limit_exceeded": "最大制限の{limit}個の属性クラスを超えるため、{count}個の新しい属性を作成できませんでした。既存の属性は正常に更新されました。",
|
"attributes_msg_attribute_limit_exceeded": "最大制限の{limit}個の属性クラスを超えるため、{count}個の新しい属性を作成できませんでした。既存の属性は正常に更新されました。",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error}(属性“{key}”のデータ型:{dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error}(属性“{key}”のデータ型:{dataType})",
|
||||||
"attributes_msg_email_already_exists": "このワークスペースには既にメールアドレスが存在するため、更新されませんでした。",
|
"attributes_msg_email_already_exists": "このメールアドレスはこの環境に既に存在するため、更新されませんでした。",
|
||||||
"attributes_msg_email_or_userid_required": "メールアドレスまたはユーザーIDのいずれかが必要です。既存の値は保持されました。",
|
"attributes_msg_email_or_userid_required": "メールアドレスまたはユーザーIDのいずれかが必要です。既存の値は保持されました。",
|
||||||
"attributes_msg_new_attribute_created": "新しい属性“{key}”を型“{dataType}”で作成しました",
|
"attributes_msg_new_attribute_created": "新しい属性“{key}”を型“{dataType}”で作成しました",
|
||||||
"attributes_msg_userid_already_exists": "このワークスペースには既にユーザーIDが存在するため、更新されませんでした。",
|
"attributes_msg_userid_already_exists": "この環境にはすでにユーザーIDが存在するため、更新されませんでした。",
|
||||||
"contact_deleted_successfully": "連絡先を正常に削除しました",
|
"contact_deleted_successfully": "連絡先を正常に削除しました",
|
||||||
"contacts_table_refresh": "連絡先を更新",
|
"contacts_table_refresh": "連絡先を更新",
|
||||||
"contacts_table_refresh_success": "連絡先を正常に更新しました",
|
"contacts_table_refresh_success": "連絡先を正常に更新しました",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "重複する言語または言語ID",
|
"duplicate_language_or_language_id": "重複する言語または言語ID",
|
||||||
"edit_languages": "言語を編集",
|
"edit_languages": "言語を編集",
|
||||||
"identifier": "識別子(ISO)",
|
"identifier": "識別子(ISO)",
|
||||||
|
"incomplete_translations": "未完了の翻訳",
|
||||||
"language": "言語",
|
"language": "言語",
|
||||||
"language_deleted_successfully": "言語を正常に削除しました",
|
"language_deleted_successfully": "言語を正常に削除しました",
|
||||||
"languages_updated_successfully": "言語を正常に更新しました",
|
"languages_updated_successfully": "言語を正常に更新しました",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "言語を選択してください",
|
"please_select_a_language": "言語を選択してください",
|
||||||
"remove_language": "言語を削除",
|
"remove_language": "言語を削除",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "ワークスペースから削除するには、これらのフォームから言語を削除してください。",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "ワークスペースから削除するには、これらのフォームから言語を削除してください。",
|
||||||
"search_items": "アイテムを検索"
|
"search_items": "アイテムを検索",
|
||||||
|
"translate": "翻訳"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "背景色を追加",
|
"add_background_color": "背景色を追加",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "すべての準備が整いました!最初のフォームを作成しましょう",
|
"all_set_time_to_create_first_survey": "すべての準備が整いました!最初のフォームを作成しましょう",
|
||||||
"alphabetical": "アルファベット順",
|
"alphabetical": "アルファベット順",
|
||||||
|
"copy_survey": "フォームをコピー",
|
||||||
|
"copy_survey_description": "このアンケートを別のワークスペースにコピー",
|
||||||
|
"copy_survey_error": "フォームのコピーに失敗しました",
|
||||||
"copy_survey_link_to_clipboard": "フォームのリンクをクリップボードにコピー",
|
"copy_survey_link_to_clipboard": "フォームのリンクをクリップボードにコピー",
|
||||||
|
"copy_survey_no_workspaces": "このアンケートをコピーできる他のワークスペースがありません。",
|
||||||
|
"copy_survey_partially_success": "{success} 個のフォームが正常にコピーされ、{error} 個が失敗しました。",
|
||||||
|
"copy_survey_success": "フォームを正常にコピーしました!",
|
||||||
"delete_survey_and_responses_warning": "本当にこのフォームとすべての回答を削除しますか?",
|
"delete_survey_and_responses_warning": "本当にこのフォームとすべての回答を削除しますか?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "翻訳を有効化",
|
"1_choose_the_default_language_for_this_survey": "1. このフォームのデフォルト言語を選択してください:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. 特定の言語の翻訳を有効にしてください:",
|
||||||
"add": "追加 +",
|
"add": "追加 +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "遅延を追加するか、フォームを自動的に閉じる",
|
"add_a_delay_or_auto_close_the_survey": "遅延を追加するか、フォームを自動的に閉じる",
|
||||||
"add_a_four_digit_pin": "4桁のPINを追加",
|
"add_a_four_digit_pin": "4桁のPINを追加",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "オーディエンス",
|
"audience": "オーディエンス",
|
||||||
"auto_close_on_inactivity": "非アクティブ時に自動閉鎖",
|
"auto_close_on_inactivity": "非アクティブ時に自動閉鎖",
|
||||||
"auto_progress_rating_and_nps": "評価とNPSの質問を自動進行",
|
"auto_progress_rating_and_nps": "評価とNPSの質問を自動進行",
|
||||||
"auto_progress_rating_and_nps_description": "単一質問ブロックでは自動的に次へ進みます。必須質問では「次へ」ボタンが非表示になりますが、「その他」が選択された場合は表示されます。",
|
"auto_progress_rating_and_nps_description": "評価またはNPSの質問で回答者が選択肢を選んだ際に自動的に次へ進みます。これは単一質問ブロックにのみ適用されます。必須の質問では「次へ」ボタンが非表示になり、任意の質問ではスキップ用に引き続き表示されます。",
|
||||||
"auto_save_disabled": "自動保存が無効",
|
"auto_save_disabled": "自動保存が無効",
|
||||||
"auto_save_disabled_tooltip": "アンケートは下書き状態の時のみ自動保存されます。これにより、公開中のアンケートが意図せず更新されることを防ぎます。",
|
"auto_save_disabled_tooltip": "アンケートは下書き状態の時のみ自動保存されます。これにより、公開中のアンケートが意図せず更新されることを防ぎます。",
|
||||||
"auto_save_on": "自動保存オン",
|
"auto_save_on": "自動保存オン",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "変更は不整合を引き起こします",
|
"caution_text": "変更は不整合を引き起こします",
|
||||||
"change_anyway": "とにかく変更",
|
"change_anyway": "とにかく変更",
|
||||||
"change_background": "背景を変更",
|
"change_background": "背景を変更",
|
||||||
"change_default": "デフォルトを変更",
|
|
||||||
"change_question_type": "質問の種類を変更",
|
"change_question_type": "質問の種類を変更",
|
||||||
"change_survey_type": "フォームの種類を変更すると、既存のアクセスに影響します",
|
"change_survey_type": "フォームの種類を変更すると、既存のアクセスに影響します",
|
||||||
"change_the_background_to_a_color_image_or_animation": "背景を色、画像、またはアニメーションに変更します。",
|
"change_the_background_to_a_color_image_or_animation": "背景を色、画像、またはアニメーションに変更します。",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "ブロックの最初の質問を選択してください",
|
"choose_the_first_question_on_your_block": "ブロックの最初の質問を選択してください",
|
||||||
"choose_where_to_run_the_survey": "フォームを実行する場所を選択してください。",
|
"choose_where_to_run_the_survey": "フォームを実行する場所を選択してください。",
|
||||||
"city": "市区町村",
|
"city": "市区町村",
|
||||||
"clear_close_on_date": "停止日をクリア",
|
|
||||||
"clear_publish_on_date": "公開日をクリア",
|
|
||||||
"close_survey_on_date": "停止日",
|
|
||||||
"close_survey_on_response_limit": "回答数の上限でフォームを閉じる",
|
"close_survey_on_response_limit": "回答数の上限でフォームを閉じる",
|
||||||
"code": "コード",
|
|
||||||
"color": "色",
|
"color": "色",
|
||||||
"column_used_in_logic_error": "この列は質問 {questionIndex} のロジックで使用されています。まず、ロジックから削除してください。",
|
"column_used_in_logic_error": "この列は質問 {questionIndex} のロジックで使用されています。まず、ロジックから削除してください。",
|
||||||
"columns": "列",
|
"columns": "列",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "アンケートのロゴをカスタマイズする",
|
"customize_survey_logo": "アンケートのロゴをカスタマイズする",
|
||||||
"darken_or_lighten_background_of_your_choice": "お好みの背景を暗くしたり明るくしたりします。",
|
"darken_or_lighten_background_of_your_choice": "お好みの背景を暗くしたり明るくしたりします。",
|
||||||
"days_before_showing_this_survey_again": "最後に表示されたアンケートとこのアンケートを表示するまでに、この日数以上の期間を空ける必要があります。",
|
"days_before_showing_this_survey_again": "最後に表示されたアンケートとこのアンケートを表示するまでに、この日数以上の期間を空ける必要があります。",
|
||||||
"default_language": "デフォルト言語",
|
|
||||||
"delete_anyways": "削除する",
|
"delete_anyways": "削除する",
|
||||||
"delete_block": "ブロックを削除",
|
"delete_block": "ブロックを削除",
|
||||||
"delete_choice": "選択肢を削除",
|
"delete_choice": "選択肢を削除",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "質問を複製",
|
"duplicate_question": "質問を複製",
|
||||||
"edit_link": "編集 リンク",
|
"edit_link": "編集 リンク",
|
||||||
"edit_recall": "リコールを編集",
|
"edit_recall": "リコールを編集",
|
||||||
|
"edit_translations": "{lang} 翻訳を編集",
|
||||||
"element_not_found": "質問が見つかりません",
|
"element_not_found": "質問が見つかりません",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "回答者がいつでも言語を切り替えられるようにします。最低2つのアクティブな言語が必要です。",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "回答者がいつでも言語を切り替えられるようにします。最低2つのアクティブな言語が必要です。",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "スパム対策はreCAPTCHA v3を使用してスパム回答をフィルタリングします。",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "スパム対策はreCAPTCHA v3を使用してスパム回答をフィルタリングします。",
|
||||||
@@ -3014,12 +2992,10 @@
|
|||||||
"long_answer_toggle_description": "回答者が長文の複数行の回答を書けるようにします。",
|
"long_answer_toggle_description": "回答者が長文の複数行の回答を書けるようにします。",
|
||||||
"lower_label": "下限ラベル",
|
"lower_label": "下限ラベル",
|
||||||
"manage_languages": "言語を管理",
|
"manage_languages": "言語を管理",
|
||||||
"manage_translations": "翻訳を管理",
|
|
||||||
"matrix_all_fields": "すべてのフィールド",
|
"matrix_all_fields": "すべてのフィールド",
|
||||||
"matrix_rows": "行",
|
"matrix_rows": "行",
|
||||||
"max_file_size": "最大ファイルサイズ",
|
"max_file_size": "最大ファイルサイズ",
|
||||||
"max_file_size_limit_is": "最大ファイルサイズの上限は",
|
"max_file_size_limit_is": "最大ファイルサイズの上限は",
|
||||||
"missing_first": "未翻訳を優先",
|
|
||||||
"move_question_to_block": "質問をブロックに移動",
|
"move_question_to_block": "質問をブロックに移動",
|
||||||
"multiply": "乗算 *",
|
"multiply": "乗算 *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "セルフホストのCal.comインスタンスに必要",
|
"needed_for_self_hosted_cal_com_instance": "セルフホストのCal.comインスタンスに必要",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "「次へ」ボタンのラベル",
|
"next_button_label": "「次へ」ボタンのラベル",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "まだ非表示フィールドがありません。以下で最初のものを追加してください。",
|
"no_hidden_fields_yet_add_first_one_below": "まだ非表示フィールドがありません。以下で最初のものを追加してください。",
|
||||||
"no_images_found_for": "''{query}'' の画像が見つかりません",
|
"no_images_found_for": "''{query}'' の画像が見つかりません",
|
||||||
"no_languages_found_add_first_one_to_get_started": "このワークスペースにはアンケート言語が見つかりません。開始するには言語を追加してください。",
|
"no_languages_found_add_first_one_to_get_started": "言語が見つかりません。始めるには、最初のものを追加してください。",
|
||||||
"no_option_found": "オプションが見つかりません",
|
"no_option_found": "オプションが見つかりません",
|
||||||
"no_recall_items_found": "リコール項目が見つかりません",
|
"no_recall_items_found": "リコール項目が見つかりません",
|
||||||
"no_variables_yet_add_first_one_below": "まだ変数がありません。以下で最初のものを追加してください。",
|
"no_variables_yet_add_first_one_below": "まだ変数がありません。以下で最初のものを追加してください。",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "有効な URL を入力してください (例:https://example.com)",
|
"please_enter_a_valid_url": "有効な URL を入力してください (例:https://example.com)",
|
||||||
"please_set_a_survey_trigger": "フォームのトリガーを設定してください",
|
"please_set_a_survey_trigger": "フォームのトリガーを設定してください",
|
||||||
"please_specify": "具体的に指定してください",
|
"please_specify": "具体的に指定してください",
|
||||||
"present_your_survey_in_multiple_languages": "アンケートを複数の言語で表示",
|
|
||||||
"prevent_double_submission": "二重送信を防ぐ",
|
"prevent_double_submission": "二重送信を防ぐ",
|
||||||
"prevent_double_submission_description": "メールアドレスごとに1つの回答のみを許可する",
|
"prevent_double_submission_description": "メールアドレスごとに1つの回答のみを許可する",
|
||||||
"progress_saved": "進捗を保存しました",
|
"progress_saved": "進捗を保存しました",
|
||||||
"protect_survey_with_pin": "PINでフォームを保護",
|
"protect_survey_with_pin": "PINでフォームを保護",
|
||||||
"protect_survey_with_pin_description": "PINを持つユーザーのみがフォームにアクセスできます。",
|
"protect_survey_with_pin_description": "PINを持つユーザーのみがフォームにアクセスできます。",
|
||||||
"publish": "公開",
|
"publish": "公開",
|
||||||
"publish_survey_on_date": "公開日",
|
|
||||||
"question": "質問",
|
"question": "質問",
|
||||||
"question_deleted": "質問を削除しました。",
|
"question_deleted": "質問を削除しました。",
|
||||||
"question_duplicated": "質問を複製しました。",
|
"question_duplicated": "質問を複製しました。",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "行",
|
"rows": "行",
|
||||||
"save_and_close": "保存して閉じる",
|
"save_and_close": "保存して閉じる",
|
||||||
"scale": "尺度",
|
"scale": "尺度",
|
||||||
"schedule_survey": "アンケートをスケジュール",
|
|
||||||
"search_for_images": "画像を検索",
|
"search_for_images": "画像を検索",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "トリガーから数秒後に回答がない場合、フォームは閉じられます",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "トリガーから数秒後に回答がない場合、フォームは閉じられます",
|
||||||
"seconds_before_showing_the_survey": "秒後にフォームを表示します。",
|
"seconds_before_showing_the_survey": "秒後にフォームを表示します。",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7点",
|
"seven_points": "7点",
|
||||||
"show_block_settings": "ブロック設定を表示",
|
"show_block_settings": "ブロック設定を表示",
|
||||||
"show_button": "ボタンを表示",
|
"show_button": "ボタンを表示",
|
||||||
"show_in_order": "順番に表示",
|
|
||||||
"show_language_switch": "言語切り替えを表示",
|
"show_language_switch": "言語切り替えを表示",
|
||||||
"show_multiple_times": "限られた回数表示する",
|
"show_multiple_times": "限られた回数表示する",
|
||||||
"show_only_once": "一度だけ表示",
|
"show_only_once": "一度だけ表示",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "アンケートプレビュー 👀",
|
"survey_preview": "アンケートプレビュー 👀",
|
||||||
"survey_styling": "フォームのスタイル",
|
"survey_styling": "フォームのスタイル",
|
||||||
"survey_trigger": "フォームのトリガー",
|
"survey_trigger": "フォームのトリガー",
|
||||||
"survey_will_be_closed_at_midnight_cet": "選択した日付の{timeZone}タイムゾーンの{time}にアンケートが終了します",
|
"switch_multi_language_on_to_get_started": "多言語機能をオンにして開始 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "選択した日付の{timeZone}タイムゾーンの{time}にアンケートが公開されます",
|
|
||||||
"target_block_not_found": "対象ブロックが見つかりません",
|
"target_block_not_found": "対象ブロックが見つかりません",
|
||||||
"targeted": "ターゲット",
|
"targeted": "ターゲット",
|
||||||
"ten_points": "10点",
|
"ten_points": "10点",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "回答がなくても1回だけ表示します。",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "回答がなくても1回だけ表示します。",
|
||||||
"then": "その後",
|
"then": "その後",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "このアクションは、このフォームからすべての翻訳を削除します。",
|
"this_action_will_remove_all_the_translations_from_this_survey": "このアクションは、このフォームからすべての翻訳を削除します。",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "この言語とすべての翻訳がこのアンケートから削除されます。この操作は元に戻せません。",
|
|
||||||
"three_points": "3点",
|
"three_points": "3点",
|
||||||
"times": "回",
|
"times": "回",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "すべてのフォームの配置を一貫させるために、",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "すべてのフォームの配置を一貫させるために、",
|
||||||
"translated": "翻訳済み",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "以下のアクションのいずれかが発火したときにフォームをトリガーします...",
|
"trigger_survey_when_one_of_the_actions_is_fired": "以下のアクションのいずれかが発火したときにフォームをトリガーします...",
|
||||||
"try_lollipop_or_mountain": "「lollipop」や「mountain」を試してみてください...",
|
"try_lollipop_or_mountain": "「lollipop」や「mountain」を試してみてください...",
|
||||||
"type_field_id": "フィールドIDを入力",
|
"type_field_id": "フィールドIDを入力",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "有効なメールアドレスを持つ人のみが回答できるようにする",
|
"verify_email_before_submission_description": "有効なメールアドレスを持つ人のみが回答できるようにする",
|
||||||
"visibility_and_recontact": "表示と再接触",
|
"visibility_and_recontact": "表示と再接触",
|
||||||
"visibility_and_recontact_description": "このフォームがいつ表示され、どのくらいの頻度で再表示できるかをコントロールします。",
|
"visibility_and_recontact_description": "このフォームがいつ表示され、どのくらいの頻度で再表示できるかをコントロールします。",
|
||||||
"visible": "表示",
|
|
||||||
"wait": "待つ",
|
"wait": "待つ",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "トリガーから数秒待ってからフォームを表示します",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "トリガーから数秒待ってからフォームを表示します",
|
||||||
"waiting_time_across_surveys": "クールダウン期間(アンケート全体)",
|
"waiting_time_across_surveys": "クールダウン期間(アンケート全体)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "アラートを設定",
|
"configure_alerts": "アラートを設定",
|
||||||
"congrats": "おめでとうございます!フォームが公開されました。",
|
"congrats": "おめでとうございます!フォームが公開されました。",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "始めるには、ウェブサイトやアプリをFormbricksに接続してください。",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "始めるには、ウェブサイトやアプリをFormbricksに接続してください。",
|
||||||
"csat_satisfied": "CSAT: 満足度 {percentage}%",
|
|
||||||
"csat_satisfied_tooltip": "回答者の{percentage}%が4または5の評価をしました(CSAT)。",
|
|
||||||
"current_count": "現在の件数",
|
"current_count": "現在の件数",
|
||||||
"custom_range": "カスタム範囲...",
|
"custom_range": "カスタム範囲...",
|
||||||
"delete_all_existing_responses_and_displays": "既存のすべての回答と表示を削除",
|
"delete_all_existing_responses_and_displays": "既存のすべての回答と表示を削除",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "QRコードをダウンロード中",
|
"downloading_qr_code": "QRコードをダウンロード中",
|
||||||
"drop_offs": "離脱",
|
"drop_offs": "離脱",
|
||||||
"drop_offs_tooltip": "フォームが開始されたが完了しなかった回数。",
|
"drop_offs_tooltip": "フォームが開始されたが完了しなかった回数。",
|
||||||
"effort_score": "エフォートスコア",
|
"failed_to_copy_link": "リンクのコピーに失敗しました",
|
||||||
"filter_added_successfully": "フィルターを正常に追加しました",
|
"filter_added_successfully": "フィルターを正常に追加しました",
|
||||||
"filter_updated_successfully": "フィルターを正常に更新しました",
|
"filter_updated_successfully": "フィルターを正常に更新しました",
|
||||||
"filtered_responses_csv": "フィルター済み回答 (CSV)",
|
"filtered_responses_csv": "フィルター済み回答 (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "制限",
|
"limit": "制限",
|
||||||
"no_identified_impressions": "識別済みコンタクトからのインプレッションはありません",
|
"no_identified_impressions": "識別済みコンタクトからのインプレッションはありません",
|
||||||
"no_responses_found": "回答が見つかりません",
|
"no_responses_found": "回答が見つかりません",
|
||||||
"nps_promoters_tooltip": "回答者の{percentage}%が9または10の評価をしました(NPSプロモーター)。",
|
|
||||||
"other_values_found": "他の値が見つかりました",
|
"other_values_found": "他の値が見つかりました",
|
||||||
"overall": "全体",
|
"overall": "全体",
|
||||||
"promoters": "推奨者",
|
"promoters": "推奨者",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "回答者 によって 完了 した 定員 の 数。",
|
"quotas_completed_tooltip": "回答者 によって 完了 した 定員 の 数。",
|
||||||
"reset_survey": "フォームをリセット",
|
"reset_survey": "フォームをリセット",
|
||||||
"reset_survey_warning": "フォームをリセットすると、このフォームに関連付けられているすべての回答と表示が削除されます。この操作は元に戻せません。",
|
"reset_survey_warning": "フォームをリセットすると、このフォームに関連付けられているすべての回答と表示が削除されます。この操作は元に戻せません。",
|
||||||
|
"satisfied": "満足",
|
||||||
"selected_responses_csv": "選択した回答 (CSV)",
|
"selected_responses_csv": "選択した回答 (CSV)",
|
||||||
"selected_responses_excel": "選択した回答 (Excel)",
|
"selected_responses_excel": "選択した回答 (Excel)",
|
||||||
"setup_integrations": "連携を設定",
|
"setup_integrations": "連携を設定",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "フォームが開始された回数。",
|
"starts_tooltip": "フォームが開始された回数。",
|
||||||
"survey_reset_successfully": "フォームを正常にリセットしました!{responseCount} 件の回答と {displayCount} 件の表示が削除されました。",
|
"survey_reset_successfully": "フォームを正常にリセットしました!{responseCount} 件の回答と {displayCount} 件の表示が削除されました。",
|
||||||
"survey_results": "{surveyName}の結果",
|
"survey_results": "{surveyName}の結果",
|
||||||
"survey_scheduled_successfully": "アンケートのスケジュール設定が完了しました",
|
|
||||||
"this_month": "今月",
|
"this_month": "今月",
|
||||||
"this_quarter": "今四半期",
|
"this_quarter": "今四半期",
|
||||||
"this_year": "今年",
|
"this_year": "今年",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "フォームを正常に削除しました!",
|
"survey_deleted_successfully": "フォームを正常に削除しました!",
|
||||||
"survey_duplicated_successfully": "フォームを正常に複製しました。",
|
"survey_duplicated_successfully": "フォームを正常に複製しました。",
|
||||||
|
"survey_duplication_error": "フォームの複製に失敗しました。",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "すべてのチャネル",
|
"all_channels": "すべてのチャネル",
|
||||||
"all_industries": "すべての業界",
|
"all_industries": "すべての業界",
|
||||||
|
|||||||
+36
-70
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Werkruimte wijzigen",
|
"change_workspace": "Werkruimte wijzigen",
|
||||||
"chart": "Grafiek",
|
"chart": "Grafiek",
|
||||||
"charts": "Grafieken",
|
"charts": "Grafieken",
|
||||||
"choice_n": "Keuze {{n}}",
|
|
||||||
"choices": "Keuzes",
|
"choices": "Keuzes",
|
||||||
"choose_organization": "Kies organisatie",
|
"choose_organization": "Kies organisatie",
|
||||||
"choose_workspace": "Kies werkruimte",
|
"choose_workspace": "Kies werkruimte",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Dichtbij",
|
"close": "Dichtbij",
|
||||||
"code": "Code",
|
"code": "Code",
|
||||||
"collapse_rows": "Rijen samenvouwen",
|
"collapse_rows": "Rijen samenvouwen",
|
||||||
"column_n": "Kolom {{n}}",
|
|
||||||
"completed": "Voltooid",
|
"completed": "Voltooid",
|
||||||
"configuration": "Configureren",
|
"configuration": "Configuratie",
|
||||||
"confirm": "Bevestigen",
|
"confirm": "Bevestigen",
|
||||||
"connect": "Verbinden",
|
"connect": "Verbinden",
|
||||||
"connect_formbricks": "Sluit Formbricks aan",
|
"connect_formbricks": "Sluit Formbricks aan",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Einde kaart",
|
"ending_card": "Einde kaart",
|
||||||
"enter_url": "URL invoeren",
|
"enter_url": "URL invoeren",
|
||||||
"enterprise_license": "Enterprise-licentie",
|
"enterprise_license": "Enterprise-licentie",
|
||||||
|
"environment": "Omgeving",
|
||||||
"error": "Fout",
|
"error": "Fout",
|
||||||
"error_component_description": "Deze bron bestaat niet of u beschikt niet over de benodigde toegangsrechten.",
|
"error_component_description": "Deze bron bestaat niet of u beschikt niet over de benodigde toegangsrechten.",
|
||||||
"error_component_title": "Fout bij het laden van bronnen",
|
"error_component_title": "Fout bij het laden van bronnen",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Laden van organisaties mislukt",
|
"failed_to_load_organizations": "Laden van organisaties mislukt",
|
||||||
"failed_to_load_workspaces": "Laden van werkruimtes mislukt",
|
"failed_to_load_workspaces": "Laden van werkruimtes mislukt",
|
||||||
"failed_to_parse_csv": "Kan CSV niet verwerken",
|
"failed_to_parse_csv": "Kan CSV niet verwerken",
|
||||||
"field_placeholder": "Tijdelijke aanduiding voor {{field}}",
|
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"finish": "Finish",
|
"finish": "Finish",
|
||||||
"first_name": "Voornaam",
|
"first_name": "Voornaam",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Genereren",
|
"generate": "Genereren",
|
||||||
"go_back": "Ga terug",
|
"go_back": "Ga terug",
|
||||||
"go_to_dashboard": "Ga naar Dashboard",
|
"go_to_dashboard": "Ga naar Dashboard",
|
||||||
"headline": "Kop",
|
|
||||||
"hidden": "Verborgen",
|
"hidden": "Verborgen",
|
||||||
"hidden_field": "Verborgen veld",
|
"hidden_field": "Verborgen veld",
|
||||||
"hidden_fields": "Verborgen velden",
|
"hidden_fields": "Verborgen velden",
|
||||||
"hide": "Verbergen",
|
"hide": "Verbergen",
|
||||||
"hide_column": "Kolom verbergen",
|
"hide_column": "Kolom verbergen",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "Afbeelding",
|
"image": "Afbeelding",
|
||||||
"images": "Afbeeldingen",
|
"images": "Afbeeldingen",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "Meer opties",
|
"more_options": "Meer opties",
|
||||||
"move_down": "Ga naar beneden",
|
"move_down": "Ga naar beneden",
|
||||||
"move_up": "Ga omhoog",
|
"move_up": "Ga omhoog",
|
||||||
|
"multiple_languages": "Meerdere talen",
|
||||||
"my_product": "mijn product",
|
"my_product": "mijn product",
|
||||||
"name": "Naam",
|
"name": "Naam",
|
||||||
"new": "Nieuw",
|
"new": "Nieuw",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "Geen resultaat gevonden",
|
"no_result_found": "Geen resultaat gevonden",
|
||||||
"no_results": "Geen resultaten",
|
"no_results": "Geen resultaten",
|
||||||
"no_surveys_found": "Geen enquêtes gevonden.",
|
"no_surveys_found": "Geen enquêtes gevonden.",
|
||||||
"no_text_found": "Geen tekst gevonden",
|
|
||||||
"none_of_the_above": "Geen van bovenstaande",
|
"none_of_the_above": "Geen van bovenstaande",
|
||||||
"not_authenticated": "U bent niet geverifieerd om deze actie uit te voeren.",
|
"not_authenticated": "U bent niet geverifieerd om deze actie uit te voeren.",
|
||||||
"not_authorized": "Niet geautoriseerd",
|
"not_authorized": "Niet geautoriseerd",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Organisatie-instellingen",
|
"organization_settings": "Organisatie-instellingen",
|
||||||
"other": "Ander",
|
"other": "Ander",
|
||||||
"other_filters": "Overige filters",
|
"other_filters": "Overige filters",
|
||||||
"other_placeholder": "Andere tijdelijke aanduiding",
|
"others": "Anderen",
|
||||||
"overlay_color": "Overlaykleur",
|
"overlay_color": "Overlaykleur",
|
||||||
"overview": "Overzicht",
|
"overview": "Overzicht",
|
||||||
"password": "Wachtwoord",
|
"password": "Wachtwoord",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Upgrade je abonnement",
|
"please_upgrade_your_plan": "Upgrade je abonnement",
|
||||||
"powered_by_formbricks": "Mogelijk gemaakt door Formbricks",
|
"powered_by_formbricks": "Mogelijk gemaakt door Formbricks",
|
||||||
"preview": "Voorbeeld",
|
"preview": "Voorbeeld",
|
||||||
|
"preview_survey": "Voorbeeld van enquête",
|
||||||
"privacy": "Privacybeleid",
|
"privacy": "Privacybeleid",
|
||||||
"product_manager": "Productmanager",
|
"product_manager": "Productmanager",
|
||||||
|
"production": "Productie",
|
||||||
"profile": "Profiel",
|
"profile": "Profiel",
|
||||||
"profile_id": "Profiel-ID",
|
"profile_id": "Profiel-ID",
|
||||||
"progress": "Voortgang",
|
"progress": "Voortgang",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Opnieuw opstarten",
|
"restart": "Opnieuw opstarten",
|
||||||
"retry": "Opnieuw proberen",
|
"retry": "Opnieuw proberen",
|
||||||
"role": "Rol",
|
"role": "Rol",
|
||||||
"row_n": "Rij {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Verkoop",
|
"sales": "Verkoop",
|
||||||
"save": "Redden",
|
"save": "Redden",
|
||||||
"save_as_draft": "Opslaan als concept",
|
"save_as_draft": "Opslaan als concept",
|
||||||
"save_changes": "Wijzigingen opslaan",
|
"save_changes": "Wijzigingen opslaan",
|
||||||
"save_without_scheduling": "Opslaan zonder planning",
|
|
||||||
"saving": "Besparing",
|
"saving": "Besparing",
|
||||||
"scheduled": "Gepland",
|
|
||||||
"search": "Zoekopdracht",
|
"search": "Zoekopdracht",
|
||||||
"search_charts": "Zoek grafieken...",
|
"search_charts": "Zoek grafieken...",
|
||||||
"security": "Beveiliging",
|
"security": "Beveiliging",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "Bestandsopslag is niet ingesteld, uploads zullen waarschijnlijk mislukken",
|
"storage_not_configured": "Bestandsopslag is niet ingesteld, uploads zullen waarschijnlijk mislukken",
|
||||||
"string": "Tekst",
|
"string": "Tekst",
|
||||||
"styling": "Styling",
|
"styling": "Styling",
|
||||||
"subheader": "Subkop",
|
|
||||||
"submit": "Indienen",
|
"submit": "Indienen",
|
||||||
"summary": "Samenvatting",
|
"summary": "Samenvatting",
|
||||||
"survey": "Vragenlijst",
|
"survey": "Vragenlijst",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Enquêtetalen",
|
"survey_languages": "Enquêtetalen",
|
||||||
"survey_live": "Enquête live",
|
"survey_live": "Enquête live",
|
||||||
"survey_paused": "Enquête onderbroken.",
|
"survey_paused": "Enquête onderbroken.",
|
||||||
"survey_scheduled": "Enquête gepland.",
|
|
||||||
"survey_type": "Enquêtetype",
|
"survey_type": "Enquêtetype",
|
||||||
"surveys": "Enquêtes",
|
"surveys": "Enquêtes",
|
||||||
"table_items_deleted_successfully": "{type}s is succesvol verwijderd",
|
"table_items_deleted_successfully": "{type}s is succesvol verwijderd",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Werkruimtes",
|
"workspaces": "Werkruimtes",
|
||||||
"years": "jaren",
|
"years": "jaren",
|
||||||
"yes": "Ja",
|
"yes": "Ja",
|
||||||
|
"you": "Jij",
|
||||||
"you_are_downgraded_to_the_community_edition": "Je bent gedowngraded naar de Community-editie.",
|
"you_are_downgraded_to_the_community_edition": "Je bent gedowngraded naar de Community-editie.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "U bent niet geautoriseerd om deze actie uit te voeren.",
|
"you_are_not_authorized_to_perform_this_action": "U bent niet geautoriseerd om deze actie uit te voeren.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Je hebt je limiet van {workspaceLimit} workspaces bereikt.",
|
"you_have_reached_your_limit_of_workspace_limit": "Je hebt je limiet van {workspaceLimit} workspaces bereikt.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "Het Formbricks-team",
|
"email_footer_text_2": "Het Formbricks-team",
|
||||||
"email_template_text_1": "Deze e-mail is verzonden via Formbricks.",
|
"email_template_text_1": "Deze e-mail is verzonden via Formbricks.",
|
||||||
"embed_survey_preview_email_didnt_request": "Heeft u dit niet aangevraagd?",
|
"embed_survey_preview_email_didnt_request": "Heeft u dit niet aangevraagd?",
|
||||||
|
"embed_survey_preview_email_environment_id": "Omgevings-ID",
|
||||||
"embed_survey_preview_email_fight_spam": "Help ons spam te bestrijden en stuur deze mail door naar hola@formbricks.com",
|
"embed_survey_preview_email_fight_spam": "Help ons spam te bestrijden en stuur deze mail door naar hola@formbricks.com",
|
||||||
"embed_survey_preview_email_heading": "Voorbeeld van e-mail insluiten",
|
"embed_survey_preview_email_heading": "Voorbeeld van e-mail insluiten",
|
||||||
"embed_survey_preview_email_subject": "Formbricks e-mailenquêtevoorbeeld",
|
"embed_survey_preview_email_subject": "Formbricks e-mailenquêtevoorbeeld",
|
||||||
"embed_survey_preview_email_text": "Zo ziet het codefragment eruit als het is ingebed in een e-mail:",
|
"embed_survey_preview_email_text": "Zo ziet het codefragment eruit als het is ingebed in een e-mail:",
|
||||||
"embed_survey_preview_email_workspace_id": "Workspace-ID",
|
|
||||||
"forgot_password_email_change_password": "Wachtwoord wijzigen",
|
"forgot_password_email_change_password": "Wachtwoord wijzigen",
|
||||||
"forgot_password_email_did_not_request": "Als u dit niet heeft aangevraagd, kunt u deze e-mail negeren.",
|
"forgot_password_email_did_not_request": "Als u dit niet heeft aangevraagd, kunt u deze e-mail negeren.",
|
||||||
"forgot_password_email_heading": "Wachtwoord wijzigen",
|
"forgot_password_email_heading": "Wachtwoord wijzigen",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Vraagvoorbeeld",
|
"question_preview": "Vraagvoorbeeld",
|
||||||
"response_already_received": "We hebben al een reactie ontvangen op dit e-mailadres.",
|
"response_already_received": "We hebben al een reactie ontvangen op dit e-mailadres.",
|
||||||
"response_submitted": "Er bestaat al een reactie gekoppeld aan deze enquête en contact",
|
"response_submitted": "Er bestaat al een reactie gekoppeld aan deze enquête en contact",
|
||||||
"scheduled": "Deze enquête is gepland om binnenkort live te gaan.",
|
|
||||||
"survey_already_answered_heading": "De enquête is al beantwoord.",
|
"survey_already_answered_heading": "De enquête is al beantwoord.",
|
||||||
"survey_already_answered_subheading": "U kunt deze link slechts één keer gebruiken.",
|
"survey_already_answered_subheading": "U kunt deze link slechts één keer gebruiken.",
|
||||||
"survey_sent_to": "Enquête verzonden naar {email}",
|
"survey_sent_to": "Enquête verzonden naar {email}",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Ander",
|
"career_development_survey_question_6_choice_6": "Ander",
|
||||||
"career_development_survey_question_6_headline": "Welke van de volgende omschrijvingen beschrijft het beste uw huidige functieniveau?",
|
"career_development_survey_question_6_headline": "Welke van de volgende omschrijvingen beschrijft het beste uw huidige functieniveau?",
|
||||||
"career_development_survey_question_6_subheader": "Selecteer een van de volgende opties",
|
"career_development_survey_question_6_subheader": "Selecteer een van de volgende opties",
|
||||||
"ces": "Klantinspanning (CES)",
|
|
||||||
"ces_description": "Meet de Customer Effort Score (1-5 of 1-7)",
|
|
||||||
"ces_lower_label": "Heel moeilijk",
|
|
||||||
"ces_upper_label": "Heel makkelijk",
|
|
||||||
"cess_survey_name": "CES-enquête",
|
"cess_survey_name": "CES-enquête",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] maakt het makkelijk voor mij om [VOEG DOEL TOE]",
|
"cess_survey_question_1_headline": "$[workspaceName] maakt het makkelijk voor mij om [VOEG DOEL TOE]",
|
||||||
"cess_survey_question_1_lower_label": "Sterk mee oneens",
|
"cess_survey_question_1_lower_label": "Sterk mee oneens",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Vraag om akkoord te gaan met de algemene voorwaarden of het datagebruik",
|
"consent_description": "Vraag om akkoord te gaan met de algemene voorwaarden of het datagebruik",
|
||||||
"contact_info": "Contactgegevens",
|
"contact_info": "Contactgegevens",
|
||||||
"contact_info_description": "Vraag gezamenlijk naar naam, achternaam, e-mailadres, telefoonnummer en bedrijf",
|
"contact_info_description": "Vraag gezamenlijk naar naam, achternaam, e-mailadres, telefoonnummer en bedrijf",
|
||||||
"csat": "Klanttevredenheid (CSAT)",
|
"csat_description": "Meet de klanttevredenheidsscore van uw product of dienst.",
|
||||||
"csat_description": "Meet de Customer Satisfaction Score (1-5)",
|
|
||||||
"csat_lower_label": "Heel ontevreden",
|
|
||||||
"csat_name": "Klanttevredenheidsscore (CSAT)",
|
"csat_name": "Klanttevredenheidsscore (CSAT)",
|
||||||
"csat_question_10_headline": "Heeft u nog andere opmerkingen, vragen of opmerkingen?",
|
"csat_question_10_headline": "Heeft u nog andere opmerkingen, vragen of opmerkingen?",
|
||||||
"csat_question_10_placeholder": "Typ hier uw antwoord...",
|
"csat_question_10_placeholder": "Typ hier uw antwoord...",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Typ hier uw antwoord...",
|
"csat_survey_question_2_placeholder": "Typ hier uw antwoord...",
|
||||||
"csat_survey_question_3_headline": "Euh, sorry! Kunnen we iets doen om uw ervaring te verbeteren?",
|
"csat_survey_question_3_headline": "Euh, sorry! Kunnen we iets doen om uw ervaring te verbeteren?",
|
||||||
"csat_survey_question_3_placeholder": "Typ hier uw antwoord...",
|
"csat_survey_question_3_placeholder": "Typ hier uw antwoord...",
|
||||||
"csat_upper_label": "Heel tevreden",
|
|
||||||
"cta_description": "Geef informatie weer en vraag gebruikers om een specifieke actie te ondernemen",
|
"cta_description": "Geef informatie weer en vraag gebruikers om een specifieke actie te ondernemen",
|
||||||
"custom_survey_description": "Maak een enquête zonder sjabloon.",
|
"custom_survey_description": "Maak een enquête zonder sjabloon.",
|
||||||
"custom_survey_name": "Begin helemaal opnieuw",
|
"custom_survey_name": "Begin helemaal opnieuw",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "Wat kunnen we beter doen?",
|
"gauge_feature_satisfaction_question_2_headline": "Wat kunnen we beter doen?",
|
||||||
"identify_customer_goals_description": "Begrijp beter of uw boodschap de juiste verwachtingen wekt van de waarde die uw product biedt.",
|
"identify_customer_goals_description": "Begrijp beter of uw boodschap de juiste verwachtingen wekt van de waarde die uw product biedt.",
|
||||||
"identify_customer_goals_name": "Identificeer klantdoelen",
|
"identify_customer_goals_name": "Identificeer klantdoelen",
|
||||||
"identify_customer_goals_question_1_choice_1": "Mijn gebruikersbestand grondig begrijpen",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Upsellmogelijkheden identificeren",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "Het best mogelijke product bouwen",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "De wereld regeren om iedereen spruitjes als ontbijt te laten eten",
|
|
||||||
"identify_customer_goals_question_1_headline": "Wat is je belangrijkste doel voor het gebruik van $[workspaceName]?",
|
|
||||||
"identify_sign_up_barriers_description": "Bied een korting aan om inzicht te krijgen in de aanmeldingsbarrières.",
|
"identify_sign_up_barriers_description": "Bied een korting aan om inzicht te krijgen in de aanmeldingsbarrières.",
|
||||||
"identify_sign_up_barriers_name": "Identificeer aanmeldingsbarrières",
|
"identify_sign_up_barriers_name": "Identificeer aanmeldingsbarrières",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Krijg 10% korting",
|
"identify_sign_up_barriers_question_1_button_label": "Krijg 10% korting",
|
||||||
@@ -1164,8 +1145,6 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Help ons u beter te begrijpen:",
|
"improve_trial_conversion_question_1_subheader": "Help ons u beter te begrijpen:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Volgende",
|
"improve_trial_conversion_question_2_button_label": "Volgende",
|
||||||
"improve_trial_conversion_question_2_headline": "Wat vervelend om te horen. Wat was het grootste probleem bij het gebruiken van $[workspaceName]?",
|
"improve_trial_conversion_question_2_headline": "Wat vervelend om te horen. Wat was het grootste probleem bij het gebruiken van $[workspaceName]?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Volgende",
|
|
||||||
"improve_trial_conversion_question_3_headline": "Wat verwachtte je dat $[workspaceName] zou doen?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "Krijg 20% korting",
|
"improve_trial_conversion_question_4_button_label": "Krijg 20% korting",
|
||||||
"improve_trial_conversion_question_4_headline": "Sorry om te horen! Krijg het eerste jaar 20% korting.",
|
"improve_trial_conversion_question_4_headline": "Sorry om te horen! Krijg het eerste jaar 20% korting.",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We bieden u graag 20% korting op een jaarabonnement.</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>We bieden u graag 20% korting op een jaarabonnement.</span></p>",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Deze actie wordt geactiveerd wanneer de pagina wordt geladen.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Deze actie wordt geactiveerd wanneer de pagina wordt geladen.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Deze actie wordt geactiveerd wanneer de gebruiker 50% van de pagina scrollt.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Deze actie wordt geactiveerd wanneer de gebruiker 50% van de pagina scrollt.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Deze actie wordt geactiveerd wanneer de gebruiker de pagina probeert te verlaten.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Deze actie wordt geactiveerd wanneer de gebruiker de pagina probeert te verlaten.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Dit is een codeactie. Breng wijzigingen aan in uw codebasis.",
|
||||||
"time_in_seconds": "Tijd in seconden",
|
"time_in_seconds": "Tijd in seconden",
|
||||||
"time_in_seconds_placeholder": "bijv. 10",
|
"time_in_seconds_placeholder": "bijv. 10",
|
||||||
"time_in_seconds_with_unit": "{seconds}s",
|
"time_in_seconds_with_unit": "{seconds}s",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "API-sleutel bijgewerkt",
|
"api_key_updated": "API-sleutel bijgewerkt",
|
||||||
"delete_api_key_confirmation": "Alle applicaties die deze sleutel gebruiken, hebben geen toegang meer tot uw Formbricks-gegevens.",
|
"delete_api_key_confirmation": "Alle applicaties die deze sleutel gebruiken, hebben geen toegang meer tot uw Formbricks-gegevens.",
|
||||||
"duplicate_access": "Dubbele workspace-toegang niet toegestaan",
|
"duplicate_access": "Dubbele workspace-toegang niet toegestaan",
|
||||||
"duplicate_directory_access": "Duplicate toegang tot feedbackrecordmap niet toegestaan",
|
|
||||||
"feedback_record_directory_access": "Toegang tot Feedbackrecordmap",
|
|
||||||
"no_api_keys_yet": "U heeft nog geen API-sleutels",
|
"no_api_keys_yet": "U heeft nog geen API-sleutels",
|
||||||
"no_directory_permissions_found": "Geen machtigingen voor feedbackrecordmap gevonden",
|
"no_env_permissions_found": "Geen omgevingsmachtigingen gevonden",
|
||||||
"no_workspace_permissions_found": "Geen Workspace-rechten gevonden",
|
|
||||||
"organization_access": "Organisatietoegang",
|
"organization_access": "Organisatietoegang",
|
||||||
"organization_access_description": "Selecteer lees- of schrijfrechten voor organisatiebrede bronnen.",
|
"organization_access_description": "Selecteer lees- of schrijfrechten voor organisatiebrede bronnen.",
|
||||||
"permissions": "Machtigingen",
|
"permissions": "Machtigingen",
|
||||||
"secret": "Geheim",
|
"secret": "Geheim",
|
||||||
"unable_to_copy_api_key": "Kan API-sleutel niet kopiëren",
|
|
||||||
"unable_to_delete_api_key": "Kan API-sleutel niet verwijderen",
|
"unable_to_delete_api_key": "Kan API-sleutel niet verwijderen",
|
||||||
"unknown_directory": "Onbekende map",
|
|
||||||
"unknown_workspace": "Onbekende workspace",
|
|
||||||
"workspace_access": "Workspace-toegang"
|
"workspace_access": "Workspace-toegang"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Verbind uw app of website met Formbricks.",
|
"app_connection_description": "Verbind uw app of website met Formbricks.",
|
||||||
"cache_update_delay_description": "Wanneer u wijzigingen aanbrengt in enquêtes, contacten, acties of andere gegevens, kan het tot 1 minuut duren voordat deze wijzigingen verschijnen in uw lokale app die de Formbricks SDK gebruikt.",
|
"cache_update_delay_description": "Wanneer u wijzigingen aanbrengt in enquêtes, contacten, acties of andere gegevens, kan het tot 1 minuut duren voordat deze wijzigingen verschijnen in uw lokale app die de Formbricks SDK gebruikt.",
|
||||||
"cache_update_delay_title": "Wijzigingen worden na ~1 minuut weergegeven vanwege caching",
|
"cache_update_delay_title": "Wijzigingen worden na ~1 minuut weergegeven vanwege caching",
|
||||||
|
"environment_id": "Jouw Werkruimte-ID",
|
||||||
|
"environment_id_description": "Dit ID identificeert deze Formbricks-werkruimte op unieke wijze.",
|
||||||
"formbricks_sdk_connected": "Formbricks SDK is verbonden",
|
"formbricks_sdk_connected": "Formbricks SDK is verbonden",
|
||||||
"formbricks_sdk_not_connected": "Formbricks SDK is nog niet verbonden.",
|
"formbricks_sdk_not_connected": "Formbricks SDK is nog niet verbonden.",
|
||||||
"formbricks_sdk_not_connected_description": "Voeg de Formbricks SDK toe aan uw website of app om deze te verbinden met Formbricks",
|
"formbricks_sdk_not_connected_description": "Voeg de Formbricks SDK toe aan uw website of app om deze te verbinden met Formbricks",
|
||||||
@@ -1866,12 +1842,10 @@
|
|||||||
"receiving_data": "Gegevens ontvangen 💃🕺",
|
"receiving_data": "Gegevens ontvangen 💃🕺",
|
||||||
"recheck": "Opnieuw controleren",
|
"recheck": "Opnieuw controleren",
|
||||||
"sdk_connection_details": "SDK-verbindingsgegevens",
|
"sdk_connection_details": "SDK-verbindingsgegevens",
|
||||||
"sdk_connection_details_description": "Je unieke Workspace-ID en SDK-verbindings-URL om Formbricks te integreren met je applicatie.",
|
"sdk_connection_details_description": "Jouw unieke werkruimte-ID en SDK-verbindings-URL voor het integreren van Formbricks met je applicatie.",
|
||||||
"setup_alert_description": "Volg deze stapsgewijze handleiding om uw app of website in minder dan 5 minuten te verbinden.",
|
"setup_alert_description": "Volg deze stapsgewijze handleiding om uw app of website in minder dan 5 minuten te verbinden.",
|
||||||
"setup_alert_title": "Hoe te verbinden",
|
"setup_alert_title": "Hoe te verbinden",
|
||||||
"webapp_url": "SDK-verbindings-URL",
|
"webapp_url": "SDK-verbindings-URL"
|
||||||
"workspace_id": "Jouw Werkruimte-ID",
|
|
||||||
"workspace_id_description": "Dit ID identificeert deze Formbricks Workspace op unieke wijze."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Gefeliciteerd!",
|
"congrats": "Gefeliciteerd!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Attribuutwaarde",
|
"attribute_value_placeholder": "Attribuutwaarde",
|
||||||
"attributes_msg_attribute_limit_exceeded": "Kon {count} nieuwe attribu(u)t(en) niet aanmaken omdat dit de maximale limiet van {limit} attribuutklassen zou overschrijden. Bestaande attributen zijn succesvol bijgewerkt.",
|
"attributes_msg_attribute_limit_exceeded": "Kon {count} nieuwe attribu(u)t(en) niet aanmaken omdat dit de maximale limiet van {limit} attribuutklassen zou overschrijden. Bestaande attributen zijn succesvol bijgewerkt.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (attribuut “{key}” heeft dataType: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (attribuut “{key}” heeft dataType: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "Het e-mailadres bestaat al voor deze Workspace en is niet bijgewerkt.",
|
"attributes_msg_email_already_exists": "Het e-mailadres bestaat al voor deze omgeving en is niet bijgewerkt.",
|
||||||
"attributes_msg_email_or_userid_required": "E-mail of gebruikers-ID is vereist. De bestaande waarden zijn behouden.",
|
"attributes_msg_email_or_userid_required": "E-mail of gebruikers-ID is vereist. De bestaande waarden zijn behouden.",
|
||||||
"attributes_msg_new_attribute_created": "Nieuw attribuut “{key}” aangemaakt met type “{dataType}”",
|
"attributes_msg_new_attribute_created": "Nieuw attribuut “{key}” aangemaakt met type “{dataType}”",
|
||||||
"attributes_msg_userid_already_exists": "De gebruikers-ID bestaat al voor deze Workspace en is niet bijgewerkt.",
|
"attributes_msg_userid_already_exists": "De gebruikers-ID bestaat al voor deze omgeving en is niet bijgewerkt.",
|
||||||
"contact_deleted_successfully": "Contact succesvol verwijderd",
|
"contact_deleted_successfully": "Contact succesvol verwijderd",
|
||||||
"contacts_table_refresh": "Vernieuw contacten",
|
"contacts_table_refresh": "Vernieuw contacten",
|
||||||
"contacts_table_refresh_success": "Contacten zijn vernieuwd",
|
"contacts_table_refresh_success": "Contacten zijn vernieuwd",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Dubbele taal of taal-ID",
|
"duplicate_language_or_language_id": "Dubbele taal of taal-ID",
|
||||||
"edit_languages": "Talen bewerken",
|
"edit_languages": "Talen bewerken",
|
||||||
"identifier": "Identifier (ISO)",
|
"identifier": "Identifier (ISO)",
|
||||||
|
"incomplete_translations": "Onvolledige vertalingen",
|
||||||
"language": "Taal",
|
"language": "Taal",
|
||||||
"language_deleted_successfully": "Taal succesvol verwijderd",
|
"language_deleted_successfully": "Taal succesvol verwijderd",
|
||||||
"languages_updated_successfully": "Talen succesvol bijgewerkt",
|
"languages_updated_successfully": "Talen succesvol bijgewerkt",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Selecteer een taal",
|
"please_select_a_language": "Selecteer een taal",
|
||||||
"remove_language": "Taal verwijderen",
|
"remove_language": "Taal verwijderen",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Verwijder de taal uit deze enquêtes om deze uit de werkruimte te verwijderen.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Verwijder de taal uit deze enquêtes om deze uit de werkruimte te verwijderen.",
|
||||||
"search_items": "Items zoeken"
|
"search_items": "Items zoeken",
|
||||||
|
"translate": "Vertalen"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Achtergrondkleur toevoegen",
|
"add_background_color": "Achtergrondkleur toevoegen",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "Je bent helemaal klaar! Tijd om uw eerste enquête te maken",
|
"all_set_time_to_create_first_survey": "Je bent helemaal klaar! Tijd om uw eerste enquête te maken",
|
||||||
"alphabetical": "Alfabetisch",
|
"alphabetical": "Alfabetisch",
|
||||||
|
"copy_survey": "Kopieer enquête",
|
||||||
|
"copy_survey_description": "Kopieer deze enquête naar een andere werkruimte",
|
||||||
|
"copy_survey_error": "Het kopiëren van de enquête is mislukt",
|
||||||
"copy_survey_link_to_clipboard": "Kopieer de enquêtelink naar het klembord",
|
"copy_survey_link_to_clipboard": "Kopieer de enquêtelink naar het klembord",
|
||||||
|
"copy_survey_no_workspaces": "Er zijn geen andere werkruimtes om deze enquête naartoe te kopiëren.",
|
||||||
|
"copy_survey_partially_success": "{success} enquêtes zijn succesvol gekopieerd, {error} is mislukt.",
|
||||||
|
"copy_survey_success": "Enquête succesvol gekopieerd!",
|
||||||
"delete_survey_and_responses_warning": "Weet u zeker dat u deze enquête en alle antwoorden erop wilt verwijderen?",
|
"delete_survey_and_responses_warning": "Weet u zeker dat u deze enquête en alle antwoorden erop wilt verwijderen?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Vertalingen activeren",
|
"1_choose_the_default_language_for_this_survey": "1. Kies de standaardtaal voor deze enquête:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Activeer vertaling voor specifieke talen:",
|
||||||
"add": "Voeg + toe",
|
"add": "Voeg + toe",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Voeg een vertraging toe of sluit de enquête automatisch",
|
"add_a_delay_or_auto_close_the_survey": "Voeg een vertraging toe of sluit de enquête automatisch",
|
||||||
"add_a_four_digit_pin": "Voeg een viercijferige pincode toe",
|
"add_a_four_digit_pin": "Voeg een viercijferige pincode toe",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Publiek",
|
"audience": "Publiek",
|
||||||
"auto_close_on_inactivity": "Automatisch sluiten bij inactiviteit",
|
"auto_close_on_inactivity": "Automatisch sluiten bij inactiviteit",
|
||||||
"auto_progress_rating_and_nps": "Automatisch doorgaan bij beoordelings- en NPS-vragen",
|
"auto_progress_rating_and_nps": "Automatisch doorgaan bij beoordelings- en NPS-vragen",
|
||||||
"auto_progress_rating_and_nps_description": "Automatisch doorgaan bij blokken met één vraag. Verplichte vragen verbergen Volgende, behalve wanneer \"Anders\" is geselecteerd.",
|
"auto_progress_rating_and_nps_description": "Ga automatisch verder wanneer respondenten een antwoord selecteren bij beoordelings- of NPS-vragen. Dit geldt alleen voor blokken met één vraag. Bij verplichte vragen wordt de Volgende-knop verborgen; bij optionele vragen blijft deze zichtbaar om de vraag over te slaan.",
|
||||||
"auto_save_disabled": "Automatisch opslaan uitgeschakeld",
|
"auto_save_disabled": "Automatisch opslaan uitgeschakeld",
|
||||||
"auto_save_disabled_tooltip": "Uw enquête wordt alleen automatisch opgeslagen wanneer deze een concept is. Dit zorgt ervoor dat openbare enquêtes niet onbedoeld worden bijgewerkt.",
|
"auto_save_disabled_tooltip": "Uw enquête wordt alleen automatisch opgeslagen wanneer deze een concept is. Dit zorgt ervoor dat openbare enquêtes niet onbedoeld worden bijgewerkt.",
|
||||||
"auto_save_on": "Automatisch opslaan aan",
|
"auto_save_on": "Automatisch opslaan aan",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "Veranderingen zullen tot inconsistenties leiden",
|
"caution_text": "Veranderingen zullen tot inconsistenties leiden",
|
||||||
"change_anyway": "Hoe dan ook veranderen",
|
"change_anyway": "Hoe dan ook veranderen",
|
||||||
"change_background": "Achtergrond wijzigen",
|
"change_background": "Achtergrond wijzigen",
|
||||||
"change_default": "Standaard wijzigen",
|
|
||||||
"change_question_type": "Vraagtype wijzigen",
|
"change_question_type": "Vraagtype wijzigen",
|
||||||
"change_survey_type": "Als u van enquêtetype verandert, heeft dit invloed op de bestaande toegang",
|
"change_survey_type": "Als u van enquêtetype verandert, heeft dit invloed op de bestaande toegang",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Verander de achtergrond in een kleur, afbeelding of animatie.",
|
"change_the_background_to_a_color_image_or_animation": "Verander de achtergrond in een kleur, afbeelding of animatie.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Kies de eerste vraag in je blok",
|
"choose_the_first_question_on_your_block": "Kies de eerste vraag in je blok",
|
||||||
"choose_where_to_run_the_survey": "Kies waar u de enquête wilt uitvoeren.",
|
"choose_where_to_run_the_survey": "Kies waar u de enquête wilt uitvoeren.",
|
||||||
"city": "Stad",
|
"city": "Stad",
|
||||||
"clear_close_on_date": "Pauzedatum wissen",
|
|
||||||
"clear_publish_on_date": "Publicatiedatum wissen",
|
|
||||||
"close_survey_on_date": "Pauzedatum",
|
|
||||||
"close_survey_on_response_limit": "Sluit enquête over responslimiet",
|
"close_survey_on_response_limit": "Sluit enquête over responslimiet",
|
||||||
"code": "Code",
|
|
||||||
"color": "Kleur",
|
"color": "Kleur",
|
||||||
"column_used_in_logic_error": "Deze kolom wordt gebruikt in de logica van vraag {questionIndex}. Verwijder het eerst uit de logica.",
|
"column_used_in_logic_error": "Deze kolom wordt gebruikt in de logica van vraag {questionIndex}. Verwijder het eerst uit de logica.",
|
||||||
"columns": "Kolommen",
|
"columns": "Kolommen",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "Pas het enquêtelogo aan",
|
"customize_survey_logo": "Pas het enquêtelogo aan",
|
||||||
"darken_or_lighten_background_of_your_choice": "Maak de achtergrond naar keuze donkerder of lichter.",
|
"darken_or_lighten_background_of_your_choice": "Maak de achtergrond naar keuze donkerder of lichter.",
|
||||||
"days_before_showing_this_survey_again": "of meer dagen moeten verstrijken tussen de laatst getoonde enquête en het tonen van deze enquête.",
|
"days_before_showing_this_survey_again": "of meer dagen moeten verstrijken tussen de laatst getoonde enquête en het tonen van deze enquête.",
|
||||||
"default_language": "Standaardtaal",
|
|
||||||
"delete_anyways": "Toch verwijderen",
|
"delete_anyways": "Toch verwijderen",
|
||||||
"delete_block": "Blok verwijderen",
|
"delete_block": "Blok verwijderen",
|
||||||
"delete_choice": "Keuze verwijderen",
|
"delete_choice": "Keuze verwijderen",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Vraag dupliceren",
|
"duplicate_question": "Vraag dupliceren",
|
||||||
"edit_link": "Link bewerken",
|
"edit_link": "Link bewerken",
|
||||||
"edit_recall": "Bewerken Terugroepen",
|
"edit_recall": "Bewerken Terugroepen",
|
||||||
|
"edit_translations": "Bewerk {lang} vertalingen",
|
||||||
"element_not_found": "Vraag niet gevonden",
|
"element_not_found": "Vraag niet gevonden",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Sta respondenten toe om op elk moment van taal te wisselen. Vereist min. 2 actieve talen.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Sta respondenten toe om op elk moment van taal te wisselen. Vereist min. 2 actieve talen.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "Spambeveiliging maakt gebruik van reCAPTCHA v3 om de spamreacties eruit te filteren.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "Spambeveiliging maakt gebruik van reCAPTCHA v3 om de spamreacties eruit te filteren.",
|
||||||
@@ -3013,13 +2991,11 @@
|
|||||||
"long_answer": "Lang antwoord",
|
"long_answer": "Lang antwoord",
|
||||||
"long_answer_toggle_description": "Sta respondenten toe om langere antwoorden met meerdere regels te schrijven.",
|
"long_answer_toggle_description": "Sta respondenten toe om langere antwoorden met meerdere regels te schrijven.",
|
||||||
"lower_label": "Lager etiket",
|
"lower_label": "Lager etiket",
|
||||||
"manage_languages": "Talen beheren",
|
"manage_languages": "Beheer talen",
|
||||||
"manage_translations": "Vertalingen beheren",
|
|
||||||
"matrix_all_fields": "Alle velden",
|
"matrix_all_fields": "Alle velden",
|
||||||
"matrix_rows": "Rijen",
|
"matrix_rows": "Rijen",
|
||||||
"max_file_size": "Maximale bestandsgrootte",
|
"max_file_size": "Maximale bestandsgrootte",
|
||||||
"max_file_size_limit_is": "Maximale bestandsgroottelimiet is",
|
"max_file_size_limit_is": "Maximale bestandsgroottelimiet is",
|
||||||
"missing_first": "Ontbrekende eerst",
|
|
||||||
"move_question_to_block": "Vraag naar blok verplaatsen",
|
"move_question_to_block": "Vraag naar blok verplaatsen",
|
||||||
"multiply": "Vermenigvuldig *",
|
"multiply": "Vermenigvuldig *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Nodig voor een zelf-gehoste Cal.com-instantie",
|
"needed_for_self_hosted_cal_com_instance": "Nodig voor een zelf-gehoste Cal.com-instantie",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "Knoplabel 'Volgende'",
|
"next_button_label": "Knoplabel 'Volgende'",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Nog geen verborgen velden. Voeg de eerste hieronder toe.",
|
"no_hidden_fields_yet_add_first_one_below": "Nog geen verborgen velden. Voeg de eerste hieronder toe.",
|
||||||
"no_images_found_for": "Geen afbeeldingen gevonden voor ''{query}'",
|
"no_images_found_for": "Geen afbeeldingen gevonden voor ''{query}'",
|
||||||
"no_languages_found_add_first_one_to_get_started": "Geen enquêtetalen gevonden in deze workspace. Voeg er een toe om te beginnen.",
|
"no_languages_found_add_first_one_to_get_started": "Geen talen gevonden. Voeg de eerste toe om aan de slag te gaan.",
|
||||||
"no_option_found": "Geen optie gevonden",
|
"no_option_found": "Geen optie gevonden",
|
||||||
"no_recall_items_found": "Geen recall-items gevonden",
|
"no_recall_items_found": "Geen recall-items gevonden",
|
||||||
"no_variables_yet_add_first_one_below": "Nog geen variabelen. Voeg de eerste hieronder toe.",
|
"no_variables_yet_add_first_one_below": "Nog geen variabelen. Voeg de eerste hieronder toe.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Voer een geldige URL in (bijvoorbeeld https://example.com)",
|
"please_enter_a_valid_url": "Voer een geldige URL in (bijvoorbeeld https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Stel een enquêtetrigger in",
|
"please_set_a_survey_trigger": "Stel een enquêtetrigger in",
|
||||||
"please_specify": "Gelieve te specificeren",
|
"please_specify": "Gelieve te specificeren",
|
||||||
"present_your_survey_in_multiple_languages": "Toon je enquête in meerdere talen",
|
|
||||||
"prevent_double_submission": "Voorkom dubbele indiening",
|
"prevent_double_submission": "Voorkom dubbele indiening",
|
||||||
"prevent_double_submission_description": "Er is slechts 1 reactie per e-mailadres toegestaan",
|
"prevent_double_submission_description": "Er is slechts 1 reactie per e-mailadres toegestaan",
|
||||||
"progress_saved": "Voortgang opgeslagen",
|
"progress_saved": "Voortgang opgeslagen",
|
||||||
"protect_survey_with_pin": "Beveilig onderzoek met een pincode",
|
"protect_survey_with_pin": "Beveilig onderzoek met een pincode",
|
||||||
"protect_survey_with_pin_description": "Alleen gebruikers die de pincode hebben, hebben toegang tot de enquête.",
|
"protect_survey_with_pin_description": "Alleen gebruikers die de pincode hebben, hebben toegang tot de enquête.",
|
||||||
"publish": "Publiceren",
|
"publish": "Publiceren",
|
||||||
"publish_survey_on_date": "Publicatiedatum",
|
|
||||||
"question": "Vraag",
|
"question": "Vraag",
|
||||||
"question_deleted": "Vraag verwijderd.",
|
"question_deleted": "Vraag verwijderd.",
|
||||||
"question_duplicated": "Vraag dubbel gesteld.",
|
"question_duplicated": "Vraag dubbel gesteld.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Rijen",
|
"rows": "Rijen",
|
||||||
"save_and_close": "Opslaan en sluiten",
|
"save_and_close": "Opslaan en sluiten",
|
||||||
"scale": "Schaal",
|
"scale": "Schaal",
|
||||||
"schedule_survey": "Enquête inplannen",
|
|
||||||
"search_for_images": "Zoek naar afbeeldingen",
|
"search_for_images": "Zoek naar afbeeldingen",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "seconden na trigger wordt de enquête gesloten als er geen reactie is",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "seconden na trigger wordt de enquête gesloten als er geen reactie is",
|
||||||
"seconds_before_showing_the_survey": "seconden voordat de enquête wordt weergegeven.",
|
"seconds_before_showing_the_survey": "seconden voordat de enquête wordt weergegeven.",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 punten",
|
"seven_points": "7 punten",
|
||||||
"show_block_settings": "Blokinstellingen tonen",
|
"show_block_settings": "Blokinstellingen tonen",
|
||||||
"show_button": "Toon knop",
|
"show_button": "Toon knop",
|
||||||
"show_in_order": "Toon op volgorde",
|
|
||||||
"show_language_switch": "Toon taalwissel",
|
"show_language_switch": "Toon taalwissel",
|
||||||
"show_multiple_times": "Toon een beperkt aantal keren",
|
"show_multiple_times": "Toon een beperkt aantal keren",
|
||||||
"show_only_once": "Slechts één keer weergeven",
|
"show_only_once": "Slechts één keer weergeven",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Enquêtevoorbeeld 👀",
|
"survey_preview": "Enquêtevoorbeeld 👀",
|
||||||
"survey_styling": "Vorm styling",
|
"survey_styling": "Vorm styling",
|
||||||
"survey_trigger": "Enquêtetrigger",
|
"survey_trigger": "Enquêtetrigger",
|
||||||
"survey_will_be_closed_at_midnight_cet": "De enquête wordt gesloten om {time} in de tijdzone {timeZone} op de geselecteerde datum",
|
"switch_multi_language_on_to_get_started": "Schakel meertaligheid in om te beginnen 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "De enquête wordt gepubliceerd om {time} in de tijdzone {timeZone} op de geselecteerde datum",
|
|
||||||
"target_block_not_found": "Doelblok niet gevonden",
|
"target_block_not_found": "Doelblok niet gevonden",
|
||||||
"targeted": "Gericht",
|
"targeted": "Gericht",
|
||||||
"ten_points": "10 punten",
|
"ten_points": "10 punten",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Toon één keer, zelfs als ze niet reageren.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Toon één keer, zelfs als ze niet reageren.",
|
||||||
"then": "Dan",
|
"then": "Dan",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Met deze actie worden alle vertalingen uit deze enquête verwijderd.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Met deze actie worden alle vertalingen uit deze enquête verwijderd.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Dit verwijdert deze taal en alle vertalingen uit deze enquête. Deze actie kan niet ongedaan worden gemaakt.",
|
|
||||||
"three_points": "3 punten",
|
"three_points": "3 punten",
|
||||||
"times": "keer",
|
"times": "keer",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Om de plaatsing over alle enquêtes consistent te houden, kunt u dat doen",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Om de plaatsing over alle enquêtes consistent te houden, kunt u dat doen",
|
||||||
"translated": "Vertaald",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Enquête activeren wanneer een van de acties wordt afgevuurd...",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Enquête activeren wanneer een van de acties wordt afgevuurd...",
|
||||||
"try_lollipop_or_mountain": "Probeer 'lollipop' of 'berg'...",
|
"try_lollipop_or_mountain": "Probeer 'lollipop' of 'berg'...",
|
||||||
"type_field_id": "Typ veld-ID",
|
"type_field_id": "Typ veld-ID",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Laat alleen mensen met een echte e-mail reageren.",
|
"verify_email_before_submission_description": "Laat alleen mensen met een echte e-mail reageren.",
|
||||||
"visibility_and_recontact": "Zichtbaarheid & opnieuw contact",
|
"visibility_and_recontact": "Zichtbaarheid & opnieuw contact",
|
||||||
"visibility_and_recontact_description": "Bepaal wanneer deze enquête kan verschijnen en hoe vaak deze opnieuw kan verschijnen.",
|
"visibility_and_recontact_description": "Bepaal wanneer deze enquête kan verschijnen en hoe vaak deze opnieuw kan verschijnen.",
|
||||||
"visible": "Zichtbaar",
|
|
||||||
"wait": "Wachten",
|
"wait": "Wachten",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Wacht een paar seconden na de trigger voordat u de enquête weergeeft",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Wacht een paar seconden na de trigger voordat u de enquête weergeeft",
|
||||||
"waiting_time_across_surveys": "Afkoelperiode (voor alle enquêtes)",
|
"waiting_time_across_surveys": "Afkoelperiode (voor alle enquêtes)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Configureer waarschuwingen",
|
"configure_alerts": "Configureer waarschuwingen",
|
||||||
"congrats": "Gefeliciteerd! Uw enquête is live.",
|
"congrats": "Gefeliciteerd! Uw enquête is live.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Verbind uw website of app met Formbricks om aan de slag te gaan.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Verbind uw website of app met Formbricks om aan de slag te gaan.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% Tevreden",
|
|
||||||
"csat_satisfied_tooltip": "{percentage}% van de respondenten gaf een beoordeling van 4 of 5 (CSAT).",
|
|
||||||
"current_count": "Huidige telling",
|
"current_count": "Huidige telling",
|
||||||
"custom_range": "Aangepast bereik...",
|
"custom_range": "Aangepast bereik...",
|
||||||
"delete_all_existing_responses_and_displays": "Verwijder alle bestaande reacties en displays",
|
"delete_all_existing_responses_and_displays": "Verwijder alle bestaande reacties en displays",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "QR-code downloaden",
|
"downloading_qr_code": "QR-code downloaden",
|
||||||
"drop_offs": "Drop-offs",
|
"drop_offs": "Drop-offs",
|
||||||
"drop_offs_tooltip": "Aantal keren dat de enquête is gestart maar niet is voltooid.",
|
"drop_offs_tooltip": "Aantal keren dat de enquête is gestart maar niet is voltooid.",
|
||||||
"effort_score": "Inspanningsscore",
|
"failed_to_copy_link": "Kan de link niet kopiëren",
|
||||||
"filter_added_successfully": "Filter succesvol toegevoegd",
|
"filter_added_successfully": "Filter succesvol toegevoegd",
|
||||||
"filter_updated_successfully": "Filter succesvol bijgewerkt",
|
"filter_updated_successfully": "Filter succesvol bijgewerkt",
|
||||||
"filtered_responses_csv": "Gefilterde reacties (CSV)",
|
"filtered_responses_csv": "Gefilterde reacties (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Beperken",
|
"limit": "Beperken",
|
||||||
"no_identified_impressions": "Geen weergaven van geïdentificeerde contacten",
|
"no_identified_impressions": "Geen weergaven van geïdentificeerde contacten",
|
||||||
"no_responses_found": "Geen reacties gevonden",
|
"no_responses_found": "Geen reacties gevonden",
|
||||||
"nps_promoters_tooltip": "{percentage}% van de respondenten gaf een beoordeling van 9 of 10 (NPS promoters).",
|
|
||||||
"other_values_found": "Andere waarden gevonden",
|
"other_values_found": "Andere waarden gevonden",
|
||||||
"overall": "Algemeen",
|
"overall": "Algemeen",
|
||||||
"promoters": "Promoters",
|
"promoters": "Promoters",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "Het aantal quota dat door de respondenten is voltooid.",
|
"quotas_completed_tooltip": "Het aantal quota dat door de respondenten is voltooid.",
|
||||||
"reset_survey": "Enquête opnieuw instellen",
|
"reset_survey": "Enquête opnieuw instellen",
|
||||||
"reset_survey_warning": "Als u een enquête opnieuw instelt, worden alle reacties en weergaven verwijderd die aan deze enquête zijn gekoppeld. Dit kan niet ongedaan worden gemaakt.",
|
"reset_survey_warning": "Als u een enquête opnieuw instelt, worden alle reacties en weergaven verwijderd die aan deze enquête zijn gekoppeld. Dit kan niet ongedaan worden gemaakt.",
|
||||||
|
"satisfied": "Tevreden",
|
||||||
"selected_responses_csv": "Geselecteerde reacties (CSV)",
|
"selected_responses_csv": "Geselecteerde reacties (CSV)",
|
||||||
"selected_responses_excel": "Geselecteerde antwoorden (Excel)",
|
"selected_responses_excel": "Geselecteerde antwoorden (Excel)",
|
||||||
"setup_integrations": "Integraties instellen",
|
"setup_integrations": "Integraties instellen",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Aantal keren dat de enquête is gestart.",
|
"starts_tooltip": "Aantal keren dat de enquête is gestart.",
|
||||||
"survey_reset_successfully": "Enquête opnieuw ingesteld! {responseCount} reacties en {displayCount} displays zijn verwijderd.",
|
"survey_reset_successfully": "Enquête opnieuw ingesteld! {responseCount} reacties en {displayCount} displays zijn verwijderd.",
|
||||||
"survey_results": "Resultaten van {surveyName}",
|
"survey_results": "Resultaten van {surveyName}",
|
||||||
"survey_scheduled_successfully": "Enquête succesvol gepland",
|
|
||||||
"this_month": "Deze maand",
|
"this_month": "Deze maand",
|
||||||
"this_quarter": "Dit kwartaal",
|
"this_quarter": "Dit kwartaal",
|
||||||
"this_year": "Dit jaar",
|
"this_year": "Dit jaar",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "Enquête succesvol verwijderd!",
|
"survey_deleted_successfully": "Enquête succesvol verwijderd!",
|
||||||
"survey_duplicated_successfully": "Enquête is succesvol gedupliceerd.",
|
"survey_duplicated_successfully": "Enquête is succesvol gedupliceerd.",
|
||||||
|
"survey_duplication_error": "Het is niet gelukt de enquête te dupliceren.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Alle kanalen",
|
"all_channels": "Alle kanalen",
|
||||||
"all_industries": "Alle industrieën",
|
"all_industries": "Alle industrieën",
|
||||||
|
|||||||
+37
-71
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Alterar espaço de trabalho",
|
"change_workspace": "Alterar espaço de trabalho",
|
||||||
"chart": "Gráfico",
|
"chart": "Gráfico",
|
||||||
"charts": "Gráficos",
|
"charts": "Gráficos",
|
||||||
"choice_n": "Escolha {{n}}",
|
|
||||||
"choices": "Escolhas",
|
"choices": "Escolhas",
|
||||||
"choose_organization": "Escolher organização",
|
"choose_organization": "Escolher organização",
|
||||||
"choose_workspace": "Escolher projeto",
|
"choose_workspace": "Escolher projeto",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Fechar",
|
"close": "Fechar",
|
||||||
"code": "Código",
|
"code": "Código",
|
||||||
"collapse_rows": "Recolher linhas",
|
"collapse_rows": "Recolher linhas",
|
||||||
"column_n": "Coluna {{n}}",
|
|
||||||
"completed": "Concluído",
|
"completed": "Concluído",
|
||||||
"configuration": "Configurar",
|
"configuration": "Configuração",
|
||||||
"confirm": "Confirmar",
|
"confirm": "Confirmar",
|
||||||
"connect": "Conectar",
|
"connect": "Conectar",
|
||||||
"connect_formbricks": "Conectar Formbricks",
|
"connect_formbricks": "Conectar Formbricks",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Cartão de encerramento",
|
"ending_card": "Cartão de encerramento",
|
||||||
"enter_url": "Inserir URL",
|
"enter_url": "Inserir URL",
|
||||||
"enterprise_license": "Licença Empresarial",
|
"enterprise_license": "Licença Empresarial",
|
||||||
|
"environment": "Ambiente",
|
||||||
"error": "Erro",
|
"error": "Erro",
|
||||||
"error_component_description": "Esse recurso não existe ou você não tem permissão para acessá-lo.",
|
"error_component_description": "Esse recurso não existe ou você não tem permissão para acessá-lo.",
|
||||||
"error_component_title": "Erro ao carregar recursos",
|
"error_component_title": "Erro ao carregar recursos",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Falha ao carregar organizações",
|
"failed_to_load_organizations": "Falha ao carregar organizações",
|
||||||
"failed_to_load_workspaces": "Falha ao carregar projetos",
|
"failed_to_load_workspaces": "Falha ao carregar projetos",
|
||||||
"failed_to_parse_csv": "Falha ao analisar CSV",
|
"failed_to_parse_csv": "Falha ao analisar CSV",
|
||||||
"field_placeholder": "Espaço reservado de {{field}}",
|
|
||||||
"filter": "Filtro",
|
"filter": "Filtro",
|
||||||
"finish": "Terminar",
|
"finish": "Terminar",
|
||||||
"first_name": "Primeiro nome",
|
"first_name": "Primeiro nome",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Gerar",
|
"generate": "Gerar",
|
||||||
"go_back": "Voltar",
|
"go_back": "Voltar",
|
||||||
"go_to_dashboard": "Ir para o Painel",
|
"go_to_dashboard": "Ir para o Painel",
|
||||||
"headline": "Título",
|
|
||||||
"hidden": "Escondido",
|
"hidden": "Escondido",
|
||||||
"hidden_field": "Campo oculto",
|
"hidden_field": "Campo oculto",
|
||||||
"hidden_fields": "Campos ocultos",
|
"hidden_fields": "Campos ocultos",
|
||||||
"hide": "Ocultar",
|
"hide": "Ocultar",
|
||||||
"hide_column": "Ocultar coluna",
|
"hide_column": "Ocultar coluna",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "imagem",
|
"image": "imagem",
|
||||||
"images": "Imagens",
|
"images": "Imagens",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "Mais opções",
|
"more_options": "Mais opções",
|
||||||
"move_down": "Descer",
|
"move_down": "Descer",
|
||||||
"move_up": "Subir",
|
"move_up": "Subir",
|
||||||
|
"multiple_languages": "Vários idiomas",
|
||||||
"my_product": "meu produto",
|
"my_product": "meu produto",
|
||||||
"name": "Nome",
|
"name": "Nome",
|
||||||
"new": "Novo",
|
"new": "Novo",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "Nenhum resultado encontrado",
|
"no_result_found": "Nenhum resultado encontrado",
|
||||||
"no_results": "Nenhum resultado",
|
"no_results": "Nenhum resultado",
|
||||||
"no_surveys_found": "Não foram encontradas pesquisas.",
|
"no_surveys_found": "Não foram encontradas pesquisas.",
|
||||||
"no_text_found": "Nenhum texto encontrado",
|
|
||||||
"none_of_the_above": "Nenhuma das opções acima",
|
"none_of_the_above": "Nenhuma das opções acima",
|
||||||
"not_authenticated": "Você não está autenticado para realizar essa ação.",
|
"not_authenticated": "Você não está autenticado para realizar essa ação.",
|
||||||
"not_authorized": "Não autorizado",
|
"not_authorized": "Não autorizado",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Configurações da Organização",
|
"organization_settings": "Configurações da Organização",
|
||||||
"other": "outro",
|
"other": "outro",
|
||||||
"other_filters": "Outros Filtros",
|
"other_filters": "Outros Filtros",
|
||||||
"other_placeholder": "Outro espaço reservado",
|
"others": "Outros",
|
||||||
"overlay_color": "Cor da sobreposição",
|
"overlay_color": "Cor da sobreposição",
|
||||||
"overview": "Visão Geral",
|
"overview": "Visão Geral",
|
||||||
"password": "Senha",
|
"password": "Senha",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Por favor, atualize seu plano",
|
"please_upgrade_your_plan": "Por favor, atualize seu plano",
|
||||||
"powered_by_formbricks": "Desenvolvido por Formbricks",
|
"powered_by_formbricks": "Desenvolvido por Formbricks",
|
||||||
"preview": "Prévia",
|
"preview": "Prévia",
|
||||||
|
"preview_survey": "Prévia da Pesquisa",
|
||||||
"privacy": "Política de Privacidade",
|
"privacy": "Política de Privacidade",
|
||||||
"product_manager": "Gerente de Produto",
|
"product_manager": "Gerente de Produto",
|
||||||
|
"production": "Produção",
|
||||||
"profile": "Perfil",
|
"profile": "Perfil",
|
||||||
"profile_id": "ID de Perfil",
|
"profile_id": "ID de Perfil",
|
||||||
"progress": "Progresso",
|
"progress": "Progresso",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Reiniciar",
|
"restart": "Reiniciar",
|
||||||
"retry": "Tentar novamente",
|
"retry": "Tentar novamente",
|
||||||
"role": "Rolê",
|
"role": "Rolê",
|
||||||
"row_n": "Linha {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "vendas",
|
"sales": "vendas",
|
||||||
"save": "Salvar",
|
"save": "Salvar",
|
||||||
"save_as_draft": "Salvar como rascunho",
|
"save_as_draft": "Salvar como rascunho",
|
||||||
"save_changes": "Salvar alterações",
|
"save_changes": "Salvar alterações",
|
||||||
"save_without_scheduling": "Salvar sem agendar",
|
|
||||||
"saving": "Salvando",
|
"saving": "Salvando",
|
||||||
"scheduled": "Agendada",
|
|
||||||
"search": "Buscar",
|
"search": "Buscar",
|
||||||
"search_charts": "Pesquisar gráficos...",
|
"search_charts": "Pesquisar gráficos...",
|
||||||
"security": "Segurança",
|
"security": "Segurança",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "Armazenamento de arquivos não configurado, uploads provavelmente falharão",
|
"storage_not_configured": "Armazenamento de arquivos não configurado, uploads provavelmente falharão",
|
||||||
"string": "Texto",
|
"string": "Texto",
|
||||||
"styling": "Estilização",
|
"styling": "Estilização",
|
||||||
"subheader": "Subtítulo",
|
|
||||||
"submit": "Enviar",
|
"submit": "Enviar",
|
||||||
"summary": "Resumo",
|
"summary": "Resumo",
|
||||||
"survey": "Pesquisa",
|
"survey": "Pesquisa",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Idiomas da Pesquisa",
|
"survey_languages": "Idiomas da Pesquisa",
|
||||||
"survey_live": "Pesquisa ao vivo",
|
"survey_live": "Pesquisa ao vivo",
|
||||||
"survey_paused": "Pesquisa pausada.",
|
"survey_paused": "Pesquisa pausada.",
|
||||||
"survey_scheduled": "Pesquisa agendada.",
|
|
||||||
"survey_type": "Tipo de Pesquisa",
|
"survey_type": "Tipo de Pesquisa",
|
||||||
"surveys": "Pesquisas",
|
"surveys": "Pesquisas",
|
||||||
"table_items_deleted_successfully": "{type}s deletados com sucesso",
|
"table_items_deleted_successfully": "{type}s deletados com sucesso",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Projetos",
|
"workspaces": "Projetos",
|
||||||
"years": "anos",
|
"years": "anos",
|
||||||
"yes": "Sim",
|
"yes": "Sim",
|
||||||
|
"you": "Você",
|
||||||
"you_are_downgraded_to_the_community_edition": "Você foi rebaixado para a Edição Comunitária.",
|
"you_are_downgraded_to_the_community_edition": "Você foi rebaixado para a Edição Comunitária.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "Você não tem autorização para realizar essa ação.",
|
"you_are_not_authorized_to_perform_this_action": "Você não tem autorização para realizar essa ação.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Você atingiu o limite de {workspaceLimit} espaços de trabalho.",
|
"you_have_reached_your_limit_of_workspace_limit": "Você atingiu o limite de {workspaceLimit} espaços de trabalho.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "O time Formbricks",
|
"email_footer_text_2": "O time Formbricks",
|
||||||
"email_template_text_1": "Este e-mail foi enviado através do Formbricks.",
|
"email_template_text_1": "Este e-mail foi enviado através do Formbricks.",
|
||||||
"embed_survey_preview_email_didnt_request": "Não pediu isso?",
|
"embed_survey_preview_email_didnt_request": "Não pediu isso?",
|
||||||
|
"embed_survey_preview_email_environment_id": "ID do Ambiente",
|
||||||
"embed_survey_preview_email_fight_spam": "Ajude a gente a combater spam e encaminhe este e-mail para hola@formbricks.com",
|
"embed_survey_preview_email_fight_spam": "Ajude a gente a combater spam e encaminhe este e-mail para hola@formbricks.com",
|
||||||
"embed_survey_preview_email_heading": "Pré-visualizar Incorporação de Email",
|
"embed_survey_preview_email_heading": "Pré-visualizar Incorporação de Email",
|
||||||
"embed_survey_preview_email_subject": "Prévia da pesquisa por e-mail do Formbricks",
|
"embed_survey_preview_email_subject": "Prévia da pesquisa por e-mail do Formbricks",
|
||||||
"embed_survey_preview_email_text": "É assim que o trecho de código fica embutido em um e-mail:",
|
"embed_survey_preview_email_text": "É assim que o trecho de código fica embutido em um e-mail:",
|
||||||
"embed_survey_preview_email_workspace_id": "ID do Workspace",
|
|
||||||
"forgot_password_email_change_password": "Mudar senha",
|
"forgot_password_email_change_password": "Mudar senha",
|
||||||
"forgot_password_email_did_not_request": "Se você não solicitou isso, por favor ignore este e-mail.",
|
"forgot_password_email_did_not_request": "Se você não solicitou isso, por favor ignore este e-mail.",
|
||||||
"forgot_password_email_heading": "Mudar senha",
|
"forgot_password_email_heading": "Mudar senha",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Prévia da Pergunta",
|
"question_preview": "Prévia da Pergunta",
|
||||||
"response_already_received": "Já recebemos uma resposta para este endereço de email.",
|
"response_already_received": "Já recebemos uma resposta para este endereço de email.",
|
||||||
"response_submitted": "Já existe uma resposta vinculada a esta pesquisa e contato",
|
"response_submitted": "Já existe uma resposta vinculada a esta pesquisa e contato",
|
||||||
"scheduled": "Esta pesquisa está programada para entrar no ar em breve.",
|
|
||||||
"survey_already_answered_heading": "A pesquisa já foi respondida.",
|
"survey_already_answered_heading": "A pesquisa já foi respondida.",
|
||||||
"survey_already_answered_subheading": "Você só pode usar esse link uma vez.",
|
"survey_already_answered_subheading": "Você só pode usar esse link uma vez.",
|
||||||
"survey_sent_to": "Pesquisa enviada para {email}",
|
"survey_sent_to": "Pesquisa enviada para {email}",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Outro",
|
"career_development_survey_question_6_choice_6": "Outro",
|
||||||
"career_development_survey_question_6_headline": "O que melhor descreve seu cargo atual?",
|
"career_development_survey_question_6_headline": "O que melhor descreve seu cargo atual?",
|
||||||
"career_development_survey_question_6_subheader": "Por favor, escolha uma das opções a seguir",
|
"career_development_survey_question_6_subheader": "Por favor, escolha uma das opções a seguir",
|
||||||
"ces": "Esforço do Cliente (CES)",
|
|
||||||
"ces_description": "Meça o Índice de Esforço do Cliente (1-5 ou 1-7)",
|
|
||||||
"ces_lower_label": "Muito difícil",
|
|
||||||
"ces_upper_label": "Muito fácil",
|
|
||||||
"cess_survey_name": "Pesquisa CES",
|
"cess_survey_name": "Pesquisa CES",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] facilita para eu [ADICIONAR OBJETIVO]",
|
"cess_survey_question_1_headline": "$[workspaceName] facilita para eu [ADICIONAR OBJETIVO]",
|
||||||
"cess_survey_question_1_lower_label": "Discordar veementemente",
|
"cess_survey_question_1_lower_label": "Discordar veementemente",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Pedir para concordar com os termos, condições ou uso de dados",
|
"consent_description": "Pedir para concordar com os termos, condições ou uso de dados",
|
||||||
"contact_info": "Informações de Contato",
|
"contact_info": "Informações de Contato",
|
||||||
"contact_info_description": "Peça nome, sobrenome, e-mail, telefone e empresa juntos",
|
"contact_info_description": "Peça nome, sobrenome, e-mail, telefone e empresa juntos",
|
||||||
"csat": "Satisfação do Cliente (CSAT)",
|
"csat_description": "Mede o Índice de Satisfação do Cliente do seu produto ou serviço.",
|
||||||
"csat_description": "Meça o Índice de Satisfação do Cliente (1-5)",
|
|
||||||
"csat_lower_label": "Muito insatisfeito",
|
|
||||||
"csat_name": "Pontuação de Satisfação do Cliente (CSAT)",
|
"csat_name": "Pontuação de Satisfação do Cliente (CSAT)",
|
||||||
"csat_question_10_headline": "Você tem mais algum comentário, pergunta ou preocupação?",
|
"csat_question_10_headline": "Você tem mais algum comentário, pergunta ou preocupação?",
|
||||||
"csat_question_10_placeholder": "Digite sua resposta aqui...",
|
"csat_question_10_placeholder": "Digite sua resposta aqui...",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Digite sua resposta aqui...",
|
"csat_survey_question_2_placeholder": "Digite sua resposta aqui...",
|
||||||
"csat_survey_question_3_headline": "Ah, foi mal! Tem algo que a gente possa fazer pra melhorar sua experiência?",
|
"csat_survey_question_3_headline": "Ah, foi mal! Tem algo que a gente possa fazer pra melhorar sua experiência?",
|
||||||
"csat_survey_question_3_placeholder": "Digite sua resposta aqui...",
|
"csat_survey_question_3_placeholder": "Digite sua resposta aqui...",
|
||||||
"csat_upper_label": "Muito satisfeito",
|
|
||||||
"cta_description": "Mostrar informações e pedir para os usuários tomarem uma ação específica",
|
"cta_description": "Mostrar informações e pedir para os usuários tomarem uma ação específica",
|
||||||
"custom_survey_description": "Crie uma pesquisa sem modelo.",
|
"custom_survey_description": "Crie uma pesquisa sem modelo.",
|
||||||
"custom_survey_name": "Começar do zero",
|
"custom_survey_name": "Começar do zero",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "O que a gente poderia melhorar?",
|
"gauge_feature_satisfaction_question_2_headline": "O que a gente poderia melhorar?",
|
||||||
"identify_customer_goals_description": "Entenda melhor se sua mensagem cria as expectativas certas sobre o valor que seu produto oferece.",
|
"identify_customer_goals_description": "Entenda melhor se sua mensagem cria as expectativas certas sobre o valor que seu produto oferece.",
|
||||||
"identify_customer_goals_name": "Identificar Objetivos do Cliente",
|
"identify_customer_goals_name": "Identificar Objetivos do Cliente",
|
||||||
"identify_customer_goals_question_1_choice_1": "Entender profundamente minha base de usuários",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Identificar oportunidades de upsell",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "Construir o melhor produto possível",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "Dominar o mundo para fazer com que todos comam couve de Bruxelas no café da manhã",
|
|
||||||
"identify_customer_goals_question_1_headline": "Qual é o seu objetivo principal ao usar $[workspaceName]?",
|
|
||||||
"identify_sign_up_barriers_description": "Ofereça um desconto pra entender melhor as barreiras de cadastro.",
|
"identify_sign_up_barriers_description": "Ofereça um desconto pra entender melhor as barreiras de cadastro.",
|
||||||
"identify_sign_up_barriers_name": "Identificar Barreiras de Cadastro",
|
"identify_sign_up_barriers_name": "Identificar Barreiras de Cadastro",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Ganhe 10% de desconto",
|
"identify_sign_up_barriers_question_1_button_label": "Ganhe 10% de desconto",
|
||||||
@@ -1164,14 +1145,12 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Ajuda a gente a te entender melhor:",
|
"improve_trial_conversion_question_1_subheader": "Ajuda a gente a te entender melhor:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Próximo",
|
"improve_trial_conversion_question_2_button_label": "Próximo",
|
||||||
"improve_trial_conversion_question_2_headline": "Que pena. Qual foi o maior problema ao usar o $[workspaceName]?",
|
"improve_trial_conversion_question_2_headline": "Que pena. Qual foi o maior problema ao usar o $[workspaceName]?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Próximo",
|
|
||||||
"improve_trial_conversion_question_3_headline": "O que você esperava que $[workspaceName] fizesse?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "Ganhe 20% de desconto",
|
"improve_trial_conversion_question_4_button_label": "Ganhe 20% de desconto",
|
||||||
"improve_trial_conversion_question_4_headline": "Que pena ouvir isso! Ganhe 20% de desconto no primeiro ano.",
|
"improve_trial_conversion_question_4_headline": "Que pena ouvir isso! Ganhe 20% de desconto no primeiro ano.",
|
||||||
"improve_trial_conversion_question_4_html": "Estamos felizes em te oferecer um desconto de 20% no plano anual.",
|
"improve_trial_conversion_question_4_html": "Estamos felizes em te oferecer um desconto de 20% no plano anual.",
|
||||||
"improve_trial_conversion_question_5_button_label": "Próximo",
|
"improve_trial_conversion_question_5_button_label": "Próximo",
|
||||||
"improve_trial_conversion_question_5_headline": "O que você gostaria de alcançar?",
|
"improve_trial_conversion_question_5_headline": "O que você gostaria de alcançar?",
|
||||||
"improve_trial_conversion_question_5_subheader": "Por favor, selecione uma das seguintes opções:",
|
"improve_trial_conversion_question_5_subheader": "Por favor, escolha uma das opções a seguir:",
|
||||||
"improve_trial_conversion_question_6_headline": "Como você tá resolvendo seu problema agora?",
|
"improve_trial_conversion_question_6_headline": "Como você tá resolvendo seu problema agora?",
|
||||||
"improve_trial_conversion_question_6_subheader": "Por favor, nomeie soluções alternativas:",
|
"improve_trial_conversion_question_6_subheader": "Por favor, nomeie soluções alternativas:",
|
||||||
"integration_setup_survey_description": "Avalie quão fácil é para os usuários adicionarem integrações ao seu produto. Encontre pontos cegos.",
|
"integration_setup_survey_description": "Avalie quão fácil é para os usuários adicionarem integrações ao seu produto. Encontre pontos cegos.",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Essa ação vai ser disparada quando a página carregar.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Essa ação vai ser disparada quando a página carregar.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Essa ação vai ser acionada quando o usuário rolar 50% da página.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Essa ação vai ser acionada quando o usuário rolar 50% da página.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Essa ação será acionada quando o usuário tentar sair da página.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Essa ação será acionada quando o usuário tentar sair da página.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Esta é uma ação de código. Por favor, faça alterações na sua base de código.",
|
||||||
"time_in_seconds": "Tempo em segundos",
|
"time_in_seconds": "Tempo em segundos",
|
||||||
"time_in_seconds_placeholder": "ex: 10",
|
"time_in_seconds_placeholder": "ex: 10",
|
||||||
"time_in_seconds_with_unit": "{seconds}s",
|
"time_in_seconds_with_unit": "{seconds}s",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "Chave de API atualizada",
|
"api_key_updated": "Chave de API atualizada",
|
||||||
"delete_api_key_confirmation": "Quaisquer aplicativos que usem esta chave não poderão mais acessar seus dados do Formbricks.",
|
"delete_api_key_confirmation": "Quaisquer aplicativos que usem esta chave não poderão mais acessar seus dados do Formbricks.",
|
||||||
"duplicate_access": "Acesso duplicado ao workspace não permitido",
|
"duplicate_access": "Acesso duplicado ao workspace não permitido",
|
||||||
"duplicate_directory_access": "Acesso duplicado ao diretório de registros de feedback não permitido",
|
|
||||||
"feedback_record_directory_access": "Acesso ao Diretório de Registros de Feedback",
|
|
||||||
"no_api_keys_yet": "Você ainda não tem nenhuma chave de API",
|
"no_api_keys_yet": "Você ainda não tem nenhuma chave de API",
|
||||||
"no_directory_permissions_found": "Nenhuma permissão de diretório de registros de feedback encontrada",
|
"no_env_permissions_found": "Nenhuma permissão de ambiente encontrada",
|
||||||
"no_workspace_permissions_found": "Nenhuma permissão de Workspace encontrada",
|
|
||||||
"organization_access": "Acesso à organização",
|
"organization_access": "Acesso à organização",
|
||||||
"organization_access_description": "Selecione privilégios de leitura ou escrita para recursos de toda a organização.",
|
"organization_access_description": "Selecione privilégios de leitura ou escrita para recursos de toda a organização.",
|
||||||
"permissions": "Permissões",
|
"permissions": "Permissões",
|
||||||
"secret": "Segredo",
|
"secret": "Segredo",
|
||||||
"unable_to_copy_api_key": "Não foi possível copiar a chave de API",
|
|
||||||
"unable_to_delete_api_key": "Não foi possível excluir a chave de API",
|
"unable_to_delete_api_key": "Não foi possível excluir a chave de API",
|
||||||
"unknown_directory": "Diretório desconhecido",
|
|
||||||
"unknown_workspace": "Workspace desconhecido",
|
|
||||||
"workspace_access": "Acesso ao workspace"
|
"workspace_access": "Acesso ao workspace"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Conecte seu app ou site ao Formbricks.",
|
"app_connection_description": "Conecte seu app ou site ao Formbricks.",
|
||||||
"cache_update_delay_description": "Quando você faz atualizações em pesquisas, contatos, ações ou outros dados, pode levar até 1 minuto para que essas alterações apareçam no seu app local executando o SDK do Formbricks.",
|
"cache_update_delay_description": "Quando você faz atualizações em pesquisas, contatos, ações ou outros dados, pode levar até 1 minuto para que essas alterações apareçam no seu app local executando o SDK do Formbricks.",
|
||||||
"cache_update_delay_title": "As alterações serão refletidas após ~1 minuto devido ao cache",
|
"cache_update_delay_title": "As alterações serão refletidas após ~1 minuto devido ao cache",
|
||||||
|
"environment_id": "ID do seu Workspace",
|
||||||
|
"environment_id_description": "Este ID identifica exclusivamente este workspace do Formbricks.",
|
||||||
"formbricks_sdk_connected": "O SDK do Formbricks está conectado",
|
"formbricks_sdk_connected": "O SDK do Formbricks está conectado",
|
||||||
"formbricks_sdk_not_connected": "O SDK do Formbricks ainda não está conectado.",
|
"formbricks_sdk_not_connected": "O SDK do Formbricks ainda não está conectado.",
|
||||||
"formbricks_sdk_not_connected_description": "Adicione o SDK do Formbricks ao seu site ou app para conectá-lo ao Formbricks",
|
"formbricks_sdk_not_connected_description": "Adicione o SDK do Formbricks ao seu site ou app para conectá-lo ao Formbricks",
|
||||||
@@ -1866,12 +1842,10 @@
|
|||||||
"receiving_data": "Recebendo dados 💃🕺",
|
"receiving_data": "Recebendo dados 💃🕺",
|
||||||
"recheck": "Verificar novamente",
|
"recheck": "Verificar novamente",
|
||||||
"sdk_connection_details": "Detalhes da conexão do SDK",
|
"sdk_connection_details": "Detalhes da conexão do SDK",
|
||||||
"sdk_connection_details_description": "Seu ID exclusivo de Workspace e URL de conexão SDK para integrar o Formbricks com sua aplicação.",
|
"sdk_connection_details_description": "O ID único do seu workspace e a URL de conexão do SDK para integrar o Formbricks com sua aplicação.",
|
||||||
"setup_alert_description": "Siga este tutorial passo a passo para conectar seu app ou site em menos de 5 minutos.",
|
"setup_alert_description": "Siga este tutorial passo a passo para conectar seu app ou site em menos de 5 minutos.",
|
||||||
"setup_alert_title": "Como conectar",
|
"setup_alert_title": "Como conectar",
|
||||||
"webapp_url": "URL de conexão do SDK",
|
"webapp_url": "URL de conexão do SDK"
|
||||||
"workspace_id": "ID do seu Workspace",
|
|
||||||
"workspace_id_description": "Este ID identifica exclusivamente este Workspace do Formbricks."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Parabéns!",
|
"congrats": "Parabéns!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Valor do atributo",
|
"attribute_value_placeholder": "Valor do atributo",
|
||||||
"attributes_msg_attribute_limit_exceeded": "Não foi possível criar {count} novo(s) atributo(s), pois excederia o limite máximo de {limit} classes de atributos. Os atributos existentes foram atualizados com sucesso.",
|
"attributes_msg_attribute_limit_exceeded": "Não foi possível criar {count} novo(s) atributo(s), pois excederia o limite máximo de {limit} classes de atributos. Os atributos existentes foram atualizados com sucesso.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (o atributo “{key}” tem dataType: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (o atributo “{key}” tem dataType: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "O e-mail já existe para este Workspace e não foi atualizado.",
|
"attributes_msg_email_already_exists": "O e-mail já existe para este ambiente e não foi atualizado.",
|
||||||
"attributes_msg_email_or_userid_required": "E-mail ou ID de usuário é obrigatório. Os valores existentes foram preservados.",
|
"attributes_msg_email_or_userid_required": "E-mail ou ID de usuário é obrigatório. Os valores existentes foram preservados.",
|
||||||
"attributes_msg_new_attribute_created": "Novo atributo “{key}” criado com tipo “{dataType}”",
|
"attributes_msg_new_attribute_created": "Novo atributo “{key}” criado com tipo “{dataType}”",
|
||||||
"attributes_msg_userid_already_exists": "O ID de usuário já existe para este Workspace e não foi atualizado.",
|
"attributes_msg_userid_already_exists": "O ID de usuário já existe para este ambiente e não foi atualizado.",
|
||||||
"contact_deleted_successfully": "Contato excluído com sucesso",
|
"contact_deleted_successfully": "Contato excluído com sucesso",
|
||||||
"contacts_table_refresh": "Atualizar contatos",
|
"contacts_table_refresh": "Atualizar contatos",
|
||||||
"contacts_table_refresh_success": "Contatos atualizados com sucesso",
|
"contacts_table_refresh_success": "Contatos atualizados com sucesso",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Idioma ou ID de idioma duplicado",
|
"duplicate_language_or_language_id": "Idioma ou ID de idioma duplicado",
|
||||||
"edit_languages": "Editar idiomas",
|
"edit_languages": "Editar idiomas",
|
||||||
"identifier": "Identificador (ISO)",
|
"identifier": "Identificador (ISO)",
|
||||||
|
"incomplete_translations": "Traduções incompletas",
|
||||||
"language": "Idioma",
|
"language": "Idioma",
|
||||||
"language_deleted_successfully": "Idioma excluído com sucesso",
|
"language_deleted_successfully": "Idioma excluído com sucesso",
|
||||||
"languages_updated_successfully": "Idiomas atualizados com sucesso",
|
"languages_updated_successfully": "Idiomas atualizados com sucesso",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Por favor, selecione um idioma",
|
"please_select_a_language": "Por favor, selecione um idioma",
|
||||||
"remove_language": "Remover idioma",
|
"remove_language": "Remover idioma",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Por favor, remova o idioma dessas pesquisas para removê-lo do workspace.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Por favor, remova o idioma dessas pesquisas para removê-lo do workspace.",
|
||||||
"search_items": "Buscar itens"
|
"search_items": "Buscar itens",
|
||||||
|
"translate": "Traduzir"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Adicionar cor de fundo",
|
"add_background_color": "Adicionar cor de fundo",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "Tá tudo pronto! Hora de criar sua primeira pesquisa",
|
"all_set_time_to_create_first_survey": "Tá tudo pronto! Hora de criar sua primeira pesquisa",
|
||||||
"alphabetical": "alfabético",
|
"alphabetical": "alfabético",
|
||||||
|
"copy_survey": "Copiar pesquisa",
|
||||||
|
"copy_survey_description": "Copie esta pesquisa para outro workspace",
|
||||||
|
"copy_survey_error": "Falha ao copiar pesquisa",
|
||||||
"copy_survey_link_to_clipboard": "Copiar link da pesquisa para a área de transferência",
|
"copy_survey_link_to_clipboard": "Copiar link da pesquisa para a área de transferência",
|
||||||
|
"copy_survey_no_workspaces": "Não há outros workspaces para copiar esta pesquisa.",
|
||||||
|
"copy_survey_partially_success": "{success} pesquisas copiadas com sucesso, {error} falharam.",
|
||||||
|
"copy_survey_success": "Pesquisa copiada com sucesso!",
|
||||||
"delete_survey_and_responses_warning": "Você tem certeza de que quer deletar essa pesquisa e todas as suas respostas?",
|
"delete_survey_and_responses_warning": "Você tem certeza de que quer deletar essa pesquisa e todas as suas respostas?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Ativar traduções",
|
"1_choose_the_default_language_for_this_survey": "1. Escolha o idioma padrão para essa pesquisa:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Ativar tradução para idiomas específicos:",
|
||||||
"add": "Adicionar +",
|
"add": "Adicionar +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Adicione um atraso ou feche a pesquisa automaticamente",
|
"add_a_delay_or_auto_close_the_survey": "Adicione um atraso ou feche a pesquisa automaticamente",
|
||||||
"add_a_four_digit_pin": "Adicione um PIN de quatro dígitos",
|
"add_a_four_digit_pin": "Adicione um PIN de quatro dígitos",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Público",
|
"audience": "Público",
|
||||||
"auto_close_on_inactivity": "Fechar automaticamente por inatividade",
|
"auto_close_on_inactivity": "Fechar automaticamente por inatividade",
|
||||||
"auto_progress_rating_and_nps": "Avançar automaticamente em perguntas de avaliação e NPS",
|
"auto_progress_rating_and_nps": "Avançar automaticamente em perguntas de avaliação e NPS",
|
||||||
"auto_progress_rating_and_nps_description": "Avançar automaticamente em blocos de pergunta única. Perguntas obrigatórias ocultam o botão Próximo, exceto quando \"Outro\" é selecionado.",
|
"auto_progress_rating_and_nps_description": "Avança automaticamente quando os respondentes selecionam uma resposta em perguntas de avaliação ou NPS. Isso se aplica apenas a blocos com uma única pergunta. Perguntas obrigatórias ocultam o botão Próximo; perguntas opcionais ainda o exibem para permitir pular.",
|
||||||
"auto_save_disabled": "Salvamento automático desativado",
|
"auto_save_disabled": "Salvamento automático desativado",
|
||||||
"auto_save_disabled_tooltip": "Sua pesquisa só é salva automaticamente quando está em rascunho. Isso garante que pesquisas públicas não sejam atualizadas involuntariamente.",
|
"auto_save_disabled_tooltip": "Sua pesquisa só é salva automaticamente quando está em rascunho. Isso garante que pesquisas públicas não sejam atualizadas involuntariamente.",
|
||||||
"auto_save_on": "Salvamento automático ativado",
|
"auto_save_on": "Salvamento automático ativado",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "Mudanças vão levar a inconsistências",
|
"caution_text": "Mudanças vão levar a inconsistências",
|
||||||
"change_anyway": "Mudar mesmo assim",
|
"change_anyway": "Mudar mesmo assim",
|
||||||
"change_background": "Mudar fundo",
|
"change_background": "Mudar fundo",
|
||||||
"change_default": "Alterar padrão",
|
|
||||||
"change_question_type": "Mudar tipo de pergunta",
|
"change_question_type": "Mudar tipo de pergunta",
|
||||||
"change_survey_type": "Alterar o tipo de pesquisa afeta o acesso existente",
|
"change_survey_type": "Alterar o tipo de pesquisa afeta o acesso existente",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Mude o fundo para uma cor, imagem ou animação.",
|
"change_the_background_to_a_color_image_or_animation": "Mude o fundo para uma cor, imagem ou animação.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Escolha a primeira pergunta do seu bloco",
|
"choose_the_first_question_on_your_block": "Escolha a primeira pergunta do seu bloco",
|
||||||
"choose_where_to_run_the_survey": "Escolha onde realizar a pesquisa.",
|
"choose_where_to_run_the_survey": "Escolha onde realizar a pesquisa.",
|
||||||
"city": "cidade",
|
"city": "cidade",
|
||||||
"clear_close_on_date": "Limpar data de pausa",
|
|
||||||
"clear_publish_on_date": "Limpar data de publicação",
|
|
||||||
"close_survey_on_date": "Data de pausa",
|
|
||||||
"close_survey_on_response_limit": "Fechar pesquisa ao atingir limite de respostas",
|
"close_survey_on_response_limit": "Fechar pesquisa ao atingir limite de respostas",
|
||||||
"code": "Código",
|
|
||||||
"color": "cor",
|
"color": "cor",
|
||||||
"column_used_in_logic_error": "Esta coluna é usada na lógica da pergunta {questionIndex}. Por favor, remova-a da lógica primeiro.",
|
"column_used_in_logic_error": "Esta coluna é usada na lógica da pergunta {questionIndex}. Por favor, remova-a da lógica primeiro.",
|
||||||
"columns": "colunas",
|
"columns": "colunas",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "Personalizar o logo da pesquisa",
|
"customize_survey_logo": "Personalizar o logo da pesquisa",
|
||||||
"darken_or_lighten_background_of_your_choice": "Escureça ou clareie o fundo da sua escolha.",
|
"darken_or_lighten_background_of_your_choice": "Escureça ou clareie o fundo da sua escolha.",
|
||||||
"days_before_showing_this_survey_again": "ou mais dias devem passar entre a última pesquisa exibida e a exibição desta pesquisa.",
|
"days_before_showing_this_survey_again": "ou mais dias devem passar entre a última pesquisa exibida e a exibição desta pesquisa.",
|
||||||
"default_language": "Idioma padrão",
|
|
||||||
"delete_anyways": "Excluir mesmo assim",
|
"delete_anyways": "Excluir mesmo assim",
|
||||||
"delete_block": "Excluir bloco",
|
"delete_block": "Excluir bloco",
|
||||||
"delete_choice": "Deletar opção",
|
"delete_choice": "Deletar opção",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Duplicar pergunta",
|
"duplicate_question": "Duplicar pergunta",
|
||||||
"edit_link": "Editar link",
|
"edit_link": "Editar link",
|
||||||
"edit_recall": "Editar Lembrete",
|
"edit_recall": "Editar Lembrete",
|
||||||
|
"edit_translations": "Editar traduções de {lang}",
|
||||||
"element_not_found": "Pergunta não encontrada",
|
"element_not_found": "Pergunta não encontrada",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permitir que os respondentes alterem o idioma a qualquer momento. Necessita de no mínimo 2 idiomas ativos.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permitir que os respondentes alterem o idioma a qualquer momento. Necessita de no mínimo 2 idiomas ativos.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "A proteção contra spam usa o reCAPTCHA v3 para filtrar as respostas de spam.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "A proteção contra spam usa o reCAPTCHA v3 para filtrar as respostas de spam.",
|
||||||
@@ -3013,13 +2991,11 @@
|
|||||||
"long_answer": "resposta longa",
|
"long_answer": "resposta longa",
|
||||||
"long_answer_toggle_description": "Permitir que os respondentes escrevam respostas mais longas e com várias linhas.",
|
"long_answer_toggle_description": "Permitir que os respondentes escrevam respostas mais longas e com várias linhas.",
|
||||||
"lower_label": "Etiqueta Inferior",
|
"lower_label": "Etiqueta Inferior",
|
||||||
"manage_languages": "Gerenciar idiomas",
|
"manage_languages": "Gerenciar Idiomas",
|
||||||
"manage_translations": "Gerenciar traduções",
|
|
||||||
"matrix_all_fields": "Todos os campos",
|
"matrix_all_fields": "Todos os campos",
|
||||||
"matrix_rows": "Linhas",
|
"matrix_rows": "Linhas",
|
||||||
"max_file_size": "Tamanho máximo do arquivo",
|
"max_file_size": "Tamanho máximo do arquivo",
|
||||||
"max_file_size_limit_is": "O limite de tamanho máximo do arquivo é",
|
"max_file_size_limit_is": "O limite de tamanho máximo do arquivo é",
|
||||||
"missing_first": "Faltantes primeiro",
|
|
||||||
"move_question_to_block": "Mover pergunta para o bloco",
|
"move_question_to_block": "Mover pergunta para o bloco",
|
||||||
"multiply": "Multiplicar *",
|
"multiply": "Multiplicar *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Necessário para uma instância auto-hospedada do Cal.com",
|
"needed_for_self_hosted_cal_com_instance": "Necessário para uma instância auto-hospedada do Cal.com",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "Próximo",
|
"next_button_label": "Próximo",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Ainda não há campos ocultos. Adicione o primeiro abaixo.",
|
"no_hidden_fields_yet_add_first_one_below": "Ainda não há campos ocultos. Adicione o primeiro abaixo.",
|
||||||
"no_images_found_for": "Nenhuma imagem encontrada para ''{query}\"",
|
"no_images_found_for": "Nenhuma imagem encontrada para ''{query}\"",
|
||||||
"no_languages_found_add_first_one_to_get_started": "Nenhum idioma de pesquisa encontrado neste workspace. Por favor, adicione um para começar.",
|
"no_languages_found_add_first_one_to_get_started": "Nenhum idioma encontrado. Adicione o primeiro para começar.",
|
||||||
"no_option_found": "Nenhuma opção encontrada",
|
"no_option_found": "Nenhuma opção encontrada",
|
||||||
"no_recall_items_found": "Nenhum item de recuperação encontrado",
|
"no_recall_items_found": "Nenhum item de recuperação encontrado",
|
||||||
"no_variables_yet_add_first_one_below": "Ainda não há variáveis. Adicione a primeira abaixo.",
|
"no_variables_yet_add_first_one_below": "Ainda não há variáveis. Adicione a primeira abaixo.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Por favor, insira uma URL válida (ex.: https://example.com)",
|
"please_enter_a_valid_url": "Por favor, insira uma URL válida (ex.: https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Por favor, configure um gatilho para a pesquisa",
|
"please_set_a_survey_trigger": "Por favor, configure um gatilho para a pesquisa",
|
||||||
"please_specify": "Por favor, especifique",
|
"please_specify": "Por favor, especifique",
|
||||||
"present_your_survey_in_multiple_languages": "Apresente sua pesquisa em vários idiomas",
|
|
||||||
"prevent_double_submission": "Evitar envio duplicado",
|
"prevent_double_submission": "Evitar envio duplicado",
|
||||||
"prevent_double_submission_description": "Permitir apenas 1 resposta por endereço de email",
|
"prevent_double_submission_description": "Permitir apenas 1 resposta por endereço de email",
|
||||||
"progress_saved": "Progresso salvo",
|
"progress_saved": "Progresso salvo",
|
||||||
"protect_survey_with_pin": "Proteger pesquisa com um PIN",
|
"protect_survey_with_pin": "Proteger pesquisa com um PIN",
|
||||||
"protect_survey_with_pin_description": "Somente usuários que têm o PIN podem acessar a pesquisa.",
|
"protect_survey_with_pin_description": "Somente usuários que têm o PIN podem acessar a pesquisa.",
|
||||||
"publish": "Publicar",
|
"publish": "Publicar",
|
||||||
"publish_survey_on_date": "Data de publicação",
|
|
||||||
"question": "Pergunta",
|
"question": "Pergunta",
|
||||||
"question_deleted": "Pergunta deletada.",
|
"question_deleted": "Pergunta deletada.",
|
||||||
"question_duplicated": "Pergunta duplicada.",
|
"question_duplicated": "Pergunta duplicada.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "linhas",
|
"rows": "linhas",
|
||||||
"save_and_close": "Salvar e Fechar",
|
"save_and_close": "Salvar e Fechar",
|
||||||
"scale": "escala",
|
"scale": "escala",
|
||||||
"schedule_survey": "Agendar pesquisa",
|
|
||||||
"search_for_images": "Buscar imagens",
|
"search_for_images": "Buscar imagens",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "segundos após acionar, a pesquisa será encerrada se não houver resposta",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "segundos após acionar, a pesquisa será encerrada se não houver resposta",
|
||||||
"seconds_before_showing_the_survey": "segundos antes de mostrar a pesquisa.",
|
"seconds_before_showing_the_survey": "segundos antes de mostrar a pesquisa.",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 pontos",
|
"seven_points": "7 pontos",
|
||||||
"show_block_settings": "Mostrar configurações do bloco",
|
"show_block_settings": "Mostrar configurações do bloco",
|
||||||
"show_button": "Mostrar Botão",
|
"show_button": "Mostrar Botão",
|
||||||
"show_in_order": "Mostrar em ordem",
|
|
||||||
"show_language_switch": "Mostrar troca de idioma",
|
"show_language_switch": "Mostrar troca de idioma",
|
||||||
"show_multiple_times": "Mostrar um número limitado de vezes",
|
"show_multiple_times": "Mostrar um número limitado de vezes",
|
||||||
"show_only_once": "Mostrar só uma vez",
|
"show_only_once": "Mostrar só uma vez",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Prévia da pesquisa 👀",
|
"survey_preview": "Prévia da pesquisa 👀",
|
||||||
"survey_styling": "Estilização de Formulários",
|
"survey_styling": "Estilização de Formulários",
|
||||||
"survey_trigger": "Gatilho de Pesquisa",
|
"survey_trigger": "Gatilho de Pesquisa",
|
||||||
"survey_will_be_closed_at_midnight_cet": "A pesquisa será encerrada às {time} no fuso horário {timeZone} na data selecionada",
|
"switch_multi_language_on_to_get_started": "Ative o modo multilíngue para começar 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "A pesquisa será publicada às {time} no fuso horário {timeZone} na data selecionada",
|
|
||||||
"target_block_not_found": "Bloco de destino não encontrado",
|
"target_block_not_found": "Bloco de destino não encontrado",
|
||||||
"targeted": "direcionado",
|
"targeted": "direcionado",
|
||||||
"ten_points": "10 pontos",
|
"ten_points": "10 pontos",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Mostrar uma única vez, mesmo que não respondam.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Mostrar uma única vez, mesmo que não respondam.",
|
||||||
"then": "Então",
|
"then": "Então",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Essa ação vai remover todas as traduções dessa pesquisa.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Essa ação vai remover todas as traduções dessa pesquisa.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Isso removerá este idioma e todas as suas traduções desta pesquisa. Esta ação não pode ser desfeita.",
|
|
||||||
"three_points": "3 pontos",
|
"three_points": "3 pontos",
|
||||||
"times": "times",
|
"times": "times",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Para manter a colocação consistente em todas as pesquisas, você pode",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Para manter a colocação consistente em todas as pesquisas, você pode",
|
||||||
"translated": "Traduzido",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Disparar pesquisa quando uma das ações for executada...",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Disparar pesquisa quando uma das ações for executada...",
|
||||||
"try_lollipop_or_mountain": "Tenta 'pirulito' ou 'montanha'...",
|
"try_lollipop_or_mountain": "Tenta 'pirulito' ou 'montanha'...",
|
||||||
"type_field_id": "Digite o id do campo",
|
"type_field_id": "Digite o id do campo",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Deixe só quem tem um email real responder.",
|
"verify_email_before_submission_description": "Deixe só quem tem um email real responder.",
|
||||||
"visibility_and_recontact": "Visibilidade e recontato",
|
"visibility_and_recontact": "Visibilidade e recontato",
|
||||||
"visibility_and_recontact_description": "Controle quando esta pesquisa pode aparecer e com que frequência pode reaparecer.",
|
"visibility_and_recontact_description": "Controle quando esta pesquisa pode aparecer e com que frequência pode reaparecer.",
|
||||||
"visible": "Visível",
|
|
||||||
"wait": "Espera",
|
"wait": "Espera",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Espera alguns segundos depois do gatilho antes de mostrar a pesquisa",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Espera alguns segundos depois do gatilho antes de mostrar a pesquisa",
|
||||||
"waiting_time_across_surveys": "Período de espera (entre pesquisas)",
|
"waiting_time_across_surveys": "Período de espera (entre pesquisas)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Configurar alertas",
|
"configure_alerts": "Configurar alertas",
|
||||||
"congrats": "Parabéns! Sua pesquisa está no ar.",
|
"congrats": "Parabéns! Sua pesquisa está no ar.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Conecte seu site ou app com o Formbricks para começar.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Conecte seu site ou app com o Formbricks para começar.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% Satisfeitos",
|
|
||||||
"csat_satisfied_tooltip": "{percentage}% dos entrevistados deram uma nota de 4 ou 5 (CSAT).",
|
|
||||||
"current_count": "Contagem Atual",
|
"current_count": "Contagem Atual",
|
||||||
"custom_range": "Intervalo personalizado...",
|
"custom_range": "Intervalo personalizado...",
|
||||||
"delete_all_existing_responses_and_displays": "Excluir todas as respostas e exibições existentes",
|
"delete_all_existing_responses_and_displays": "Excluir todas as respostas e exibições existentes",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "Baixando código QR",
|
"downloading_qr_code": "Baixando código QR",
|
||||||
"drop_offs": "Pontos de Entrega",
|
"drop_offs": "Pontos de Entrega",
|
||||||
"drop_offs_tooltip": "Número de vezes que a pesquisa foi iniciada mas não concluída.",
|
"drop_offs_tooltip": "Número de vezes que a pesquisa foi iniciada mas não concluída.",
|
||||||
"effort_score": "Índice de Esforço",
|
"failed_to_copy_link": "Falha ao copiar link",
|
||||||
"filter_added_successfully": "Filtro adicionado com sucesso",
|
"filter_added_successfully": "Filtro adicionado com sucesso",
|
||||||
"filter_updated_successfully": "Filtro atualizado com sucesso",
|
"filter_updated_successfully": "Filtro atualizado com sucesso",
|
||||||
"filtered_responses_csv": "Respostas filtradas (CSV)",
|
"filtered_responses_csv": "Respostas filtradas (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Limite",
|
"limit": "Limite",
|
||||||
"no_identified_impressions": "Nenhuma impressão de contatos identificados",
|
"no_identified_impressions": "Nenhuma impressão de contatos identificados",
|
||||||
"no_responses_found": "Nenhuma resposta encontrada",
|
"no_responses_found": "Nenhuma resposta encontrada",
|
||||||
"nps_promoters_tooltip": "{percentage}% dos entrevistados deram uma nota de 9 ou 10 (promotores NPS).",
|
|
||||||
"other_values_found": "Outros valores encontrados",
|
"other_values_found": "Outros valores encontrados",
|
||||||
"overall": "No geral",
|
"overall": "No geral",
|
||||||
"promoters": "Promotores",
|
"promoters": "Promotores",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "Número de cotas preenchidas pelos respondentes.",
|
"quotas_completed_tooltip": "Número de cotas preenchidas pelos respondentes.",
|
||||||
"reset_survey": "Redefinir pesquisa",
|
"reset_survey": "Redefinir pesquisa",
|
||||||
"reset_survey_warning": "Redefinir uma pesquisa remove todas as respostas e exibições associadas a esta pesquisa. Isto não pode ser desfeito.",
|
"reset_survey_warning": "Redefinir uma pesquisa remove todas as respostas e exibições associadas a esta pesquisa. Isto não pode ser desfeito.",
|
||||||
|
"satisfied": "Satisfeito",
|
||||||
"selected_responses_csv": "Respostas selecionadas (CSV)",
|
"selected_responses_csv": "Respostas selecionadas (CSV)",
|
||||||
"selected_responses_excel": "Respostas selecionadas (Excel)",
|
"selected_responses_excel": "Respostas selecionadas (Excel)",
|
||||||
"setup_integrations": "Configurar integrações",
|
"setup_integrations": "Configurar integrações",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Número de vezes que a pesquisa foi iniciada.",
|
"starts_tooltip": "Número de vezes que a pesquisa foi iniciada.",
|
||||||
"survey_reset_successfully": "Pesquisa redefinida com sucesso! {responseCount} respostas e {displayCount} exibições foram deletadas.",
|
"survey_reset_successfully": "Pesquisa redefinida com sucesso! {responseCount} respostas e {displayCount} exibições foram deletadas.",
|
||||||
"survey_results": "Resultados de {surveyName}",
|
"survey_results": "Resultados de {surveyName}",
|
||||||
"survey_scheduled_successfully": "Pesquisa agendada com sucesso",
|
|
||||||
"this_month": "Este mês",
|
"this_month": "Este mês",
|
||||||
"this_quarter": "Este trimestre",
|
"this_quarter": "Este trimestre",
|
||||||
"this_year": "Este ano",
|
"this_year": "Este ano",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "Pesquisa deletada com sucesso!",
|
"survey_deleted_successfully": "Pesquisa deletada com sucesso!",
|
||||||
"survey_duplicated_successfully": "Pesquisa duplicada com sucesso.",
|
"survey_duplicated_successfully": "Pesquisa duplicada com sucesso.",
|
||||||
|
"survey_duplication_error": "Falha ao duplicar a pesquisa.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Todos os canais",
|
"all_channels": "Todos os canais",
|
||||||
"all_industries": "Todas as indústrias",
|
"all_industries": "Todas as indústrias",
|
||||||
|
|||||||
+36
-70
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Alterar espaço de trabalho",
|
"change_workspace": "Alterar espaço de trabalho",
|
||||||
"chart": "Gráfico",
|
"chart": "Gráfico",
|
||||||
"charts": "Gráficos",
|
"charts": "Gráficos",
|
||||||
"choice_n": "Escolha {{n}}",
|
|
||||||
"choices": "Escolhas",
|
"choices": "Escolhas",
|
||||||
"choose_organization": "Escolher organização",
|
"choose_organization": "Escolher organização",
|
||||||
"choose_workspace": "Escolher projeto",
|
"choose_workspace": "Escolher projeto",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Fechar",
|
"close": "Fechar",
|
||||||
"code": "Código",
|
"code": "Código",
|
||||||
"collapse_rows": "Recolher linhas",
|
"collapse_rows": "Recolher linhas",
|
||||||
"column_n": "Coluna {{n}}",
|
|
||||||
"completed": "Concluído",
|
"completed": "Concluído",
|
||||||
"configuration": "Configurar",
|
"configuration": "Configuração",
|
||||||
"confirm": "Confirmar",
|
"confirm": "Confirmar",
|
||||||
"connect": "Conectar",
|
"connect": "Conectar",
|
||||||
"connect_formbricks": "Ligar Formbricks",
|
"connect_formbricks": "Ligar Formbricks",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Cartão de encerramento",
|
"ending_card": "Cartão de encerramento",
|
||||||
"enter_url": "Introduzir URL",
|
"enter_url": "Introduzir URL",
|
||||||
"enterprise_license": "Licença Enterprise",
|
"enterprise_license": "Licença Enterprise",
|
||||||
|
"environment": "Ambiente",
|
||||||
"error": "Erro",
|
"error": "Erro",
|
||||||
"error_component_description": "Este recurso não existe ou não tem os direitos necessários para aceder a ele.",
|
"error_component_description": "Este recurso não existe ou não tem os direitos necessários para aceder a ele.",
|
||||||
"error_component_title": "Erro ao carregar recursos",
|
"error_component_title": "Erro ao carregar recursos",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Falha ao carregar organizações",
|
"failed_to_load_organizations": "Falha ao carregar organizações",
|
||||||
"failed_to_load_workspaces": "Falha ao carregar projetos",
|
"failed_to_load_workspaces": "Falha ao carregar projetos",
|
||||||
"failed_to_parse_csv": "Falha ao analisar o CSV",
|
"failed_to_parse_csv": "Falha ao analisar o CSV",
|
||||||
"field_placeholder": "Espaço reservado de {{field}}",
|
|
||||||
"filter": "Filtro",
|
"filter": "Filtro",
|
||||||
"finish": "Concluir",
|
"finish": "Concluir",
|
||||||
"first_name": "Primeiro nome",
|
"first_name": "Primeiro nome",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Gerar",
|
"generate": "Gerar",
|
||||||
"go_back": "Voltar",
|
"go_back": "Voltar",
|
||||||
"go_to_dashboard": "Ir para o Painel",
|
"go_to_dashboard": "Ir para o Painel",
|
||||||
"headline": "Título",
|
|
||||||
"hidden": "Oculto",
|
"hidden": "Oculto",
|
||||||
"hidden_field": "Campo oculto",
|
"hidden_field": "Campo oculto",
|
||||||
"hidden_fields": "Campos ocultos",
|
"hidden_fields": "Campos ocultos",
|
||||||
"hide": "Ocultar",
|
"hide": "Ocultar",
|
||||||
"hide_column": "Ocultar coluna",
|
"hide_column": "Ocultar coluna",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "Imagem",
|
"image": "Imagem",
|
||||||
"images": "Imagens",
|
"images": "Imagens",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "Mais opções",
|
"more_options": "Mais opções",
|
||||||
"move_down": "Mover para baixo",
|
"move_down": "Mover para baixo",
|
||||||
"move_up": "Mover para cima",
|
"move_up": "Mover para cima",
|
||||||
|
"multiple_languages": "Várias línguas",
|
||||||
"my_product": "o meu produto",
|
"my_product": "o meu produto",
|
||||||
"name": "Nome",
|
"name": "Nome",
|
||||||
"new": "Novo",
|
"new": "Novo",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "Nenhum resultado encontrado",
|
"no_result_found": "Nenhum resultado encontrado",
|
||||||
"no_results": "Nenhum resultado",
|
"no_results": "Nenhum resultado",
|
||||||
"no_surveys_found": "Nenhum inquérito encontrado.",
|
"no_surveys_found": "Nenhum inquérito encontrado.",
|
||||||
"no_text_found": "Nenhum texto encontrado",
|
|
||||||
"none_of_the_above": "Nenhuma das opções acima",
|
"none_of_the_above": "Nenhuma das opções acima",
|
||||||
"not_authenticated": "Não está autenticado para realizar esta ação.",
|
"not_authenticated": "Não está autenticado para realizar esta ação.",
|
||||||
"not_authorized": "Não autorizado",
|
"not_authorized": "Não autorizado",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Configurações da Organização",
|
"organization_settings": "Configurações da Organização",
|
||||||
"other": "Outro",
|
"other": "Outro",
|
||||||
"other_filters": "Outros Filtros",
|
"other_filters": "Outros Filtros",
|
||||||
"other_placeholder": "Outro espaço reservado",
|
"others": "Outros",
|
||||||
"overlay_color": "Cor da sobreposição",
|
"overlay_color": "Cor da sobreposição",
|
||||||
"overview": "Visão geral",
|
"overview": "Visão geral",
|
||||||
"password": "Palavra-passe",
|
"password": "Palavra-passe",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Por favor, atualize o seu plano",
|
"please_upgrade_your_plan": "Por favor, atualize o seu plano",
|
||||||
"powered_by_formbricks": "Desenvolvido por Formbricks",
|
"powered_by_formbricks": "Desenvolvido por Formbricks",
|
||||||
"preview": "Pré-visualização",
|
"preview": "Pré-visualização",
|
||||||
|
"preview_survey": "Pré-visualização do inquérito",
|
||||||
"privacy": "Política de Privacidade",
|
"privacy": "Política de Privacidade",
|
||||||
"product_manager": "Gestor de Produto",
|
"product_manager": "Gestor de Produto",
|
||||||
|
"production": "Produção",
|
||||||
"profile": "Perfil",
|
"profile": "Perfil",
|
||||||
"profile_id": "ID do Perfil",
|
"profile_id": "ID do Perfil",
|
||||||
"progress": "Progresso",
|
"progress": "Progresso",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Reiniciar",
|
"restart": "Reiniciar",
|
||||||
"retry": "Tentar novamente",
|
"retry": "Tentar novamente",
|
||||||
"role": "Função",
|
"role": "Função",
|
||||||
"row_n": "Linha {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Vendas",
|
"sales": "Vendas",
|
||||||
"save": "Guardar",
|
"save": "Guardar",
|
||||||
"save_as_draft": "Guardar como rascunho",
|
"save_as_draft": "Guardar como rascunho",
|
||||||
"save_changes": "Guardar alterações",
|
"save_changes": "Guardar alterações",
|
||||||
"save_without_scheduling": "Guardar sem agendar",
|
|
||||||
"saving": "Guardando",
|
"saving": "Guardando",
|
||||||
"scheduled": "Agendado",
|
|
||||||
"search": "Procurar",
|
"search": "Procurar",
|
||||||
"search_charts": "Pesquisar gráficos...",
|
"search_charts": "Pesquisar gráficos...",
|
||||||
"security": "Segurança",
|
"security": "Segurança",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "Armazenamento de ficheiros não configurado, uploads provavelmente falharão",
|
"storage_not_configured": "Armazenamento de ficheiros não configurado, uploads provavelmente falharão",
|
||||||
"string": "Texto",
|
"string": "Texto",
|
||||||
"styling": "Estilo",
|
"styling": "Estilo",
|
||||||
"subheader": "Subtítulo",
|
|
||||||
"submit": "Submeter",
|
"submit": "Submeter",
|
||||||
"summary": "Resumo",
|
"summary": "Resumo",
|
||||||
"survey": "Inquérito",
|
"survey": "Inquérito",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Idiomas da Pesquisa",
|
"survey_languages": "Idiomas da Pesquisa",
|
||||||
"survey_live": "Inquérito ao vivo",
|
"survey_live": "Inquérito ao vivo",
|
||||||
"survey_paused": "Inquérito pausado.",
|
"survey_paused": "Inquérito pausado.",
|
||||||
"survey_scheduled": "Inquérito agendado.",
|
|
||||||
"survey_type": "Tipo de Inquérito",
|
"survey_type": "Tipo de Inquérito",
|
||||||
"surveys": "Inquéritos",
|
"surveys": "Inquéritos",
|
||||||
"table_items_deleted_successfully": "{type}s eliminados com sucesso",
|
"table_items_deleted_successfully": "{type}s eliminados com sucesso",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Projetos",
|
"workspaces": "Projetos",
|
||||||
"years": "anos",
|
"years": "anos",
|
||||||
"yes": "Sim",
|
"yes": "Sim",
|
||||||
|
"you": "Você",
|
||||||
"you_are_downgraded_to_the_community_edition": "Foi rebaixado para a Edição Comunitária.",
|
"you_are_downgraded_to_the_community_edition": "Foi rebaixado para a Edição Comunitária.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "Não está autorizado a realizar esta ação.",
|
"you_are_not_authorized_to_perform_this_action": "Não está autorizado a realizar esta ação.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Atingiste o teu limite de {workspaceLimit} espaços de trabalho.",
|
"you_have_reached_your_limit_of_workspace_limit": "Atingiste o teu limite de {workspaceLimit} espaços de trabalho.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "A Equipa Formbricks",
|
"email_footer_text_2": "A Equipa Formbricks",
|
||||||
"email_template_text_1": "Este email foi enviado via Formbricks.",
|
"email_template_text_1": "Este email foi enviado via Formbricks.",
|
||||||
"embed_survey_preview_email_didnt_request": "Não pediu isto?",
|
"embed_survey_preview_email_didnt_request": "Não pediu isto?",
|
||||||
|
"embed_survey_preview_email_environment_id": "ID do Ambiente",
|
||||||
"embed_survey_preview_email_fight_spam": "Ajude-nos a combater o spam e encaminhe este e-mail para hola@formbricks.com",
|
"embed_survey_preview_email_fight_spam": "Ajude-nos a combater o spam e encaminhe este e-mail para hola@formbricks.com",
|
||||||
"embed_survey_preview_email_heading": "Pré-visualizar Incorporação de Email",
|
"embed_survey_preview_email_heading": "Pré-visualizar Incorporação de Email",
|
||||||
"embed_survey_preview_email_subject": "Pré-visualização da Pesquisa de E-mail do Formbricks",
|
"embed_survey_preview_email_subject": "Pré-visualização da Pesquisa de E-mail do Formbricks",
|
||||||
"embed_survey_preview_email_text": "É assim que o trecho de código aparece incorporado num email:",
|
"embed_survey_preview_email_text": "É assim que o trecho de código aparece incorporado num email:",
|
||||||
"embed_survey_preview_email_workspace_id": "ID do Espaço de Trabalho",
|
|
||||||
"forgot_password_email_change_password": "Alterar palavra-passe",
|
"forgot_password_email_change_password": "Alterar palavra-passe",
|
||||||
"forgot_password_email_did_not_request": "Se não solicitou isto, por favor ignore este email.",
|
"forgot_password_email_did_not_request": "Se não solicitou isto, por favor ignore este email.",
|
||||||
"forgot_password_email_heading": "Alterar palavra-passe",
|
"forgot_password_email_heading": "Alterar palavra-passe",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Pré-visualização da Pergunta",
|
"question_preview": "Pré-visualização da Pergunta",
|
||||||
"response_already_received": "Já recebemos uma resposta para este endereço de email.",
|
"response_already_received": "Já recebemos uma resposta para este endereço de email.",
|
||||||
"response_submitted": "Já existe uma resposta associada a este inquérito e contacto",
|
"response_submitted": "Já existe uma resposta associada a este inquérito e contacto",
|
||||||
"scheduled": "Este inquérito está agendado para ser publicado em breve.",
|
|
||||||
"survey_already_answered_heading": "O inquérito já foi respondido.",
|
"survey_already_answered_heading": "O inquérito já foi respondido.",
|
||||||
"survey_already_answered_subheading": "Só pode usar este link uma vez.",
|
"survey_already_answered_subheading": "Só pode usar este link uma vez.",
|
||||||
"survey_sent_to": "Inquérito enviado para {email}",
|
"survey_sent_to": "Inquérito enviado para {email}",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Outro",
|
"career_development_survey_question_6_choice_6": "Outro",
|
||||||
"career_development_survey_question_6_headline": "Qual das seguintes opções descreve melhor o seu nível de emprego atual?",
|
"career_development_survey_question_6_headline": "Qual das seguintes opções descreve melhor o seu nível de emprego atual?",
|
||||||
"career_development_survey_question_6_subheader": "Por favor, selecione uma das seguintes",
|
"career_development_survey_question_6_subheader": "Por favor, selecione uma das seguintes",
|
||||||
"ces": "Esforço do Cliente (CES)",
|
|
||||||
"ces_description": "Mede a Pontuação de Esforço do Cliente (1-5 ou 1-7)",
|
|
||||||
"ces_lower_label": "Muito difícil",
|
|
||||||
"ces_upper_label": "Muito fácil",
|
|
||||||
"cess_survey_name": "Inquérito CES",
|
"cess_survey_name": "Inquérito CES",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] facilita-me [ADICIONAR OBJETIVO]",
|
"cess_survey_question_1_headline": "$[workspaceName] facilita-me [ADICIONAR OBJETIVO]",
|
||||||
"cess_survey_question_1_lower_label": "Discordo totalmente",
|
"cess_survey_question_1_lower_label": "Discordo totalmente",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Pedir para concordar com os termos, condições ou uso de dados",
|
"consent_description": "Pedir para concordar com os termos, condições ou uso de dados",
|
||||||
"contact_info": "Informações de Contacto",
|
"contact_info": "Informações de Contacto",
|
||||||
"contact_info_description": "Peça nome, apelido, email, número de telefone e empresa em conjunto",
|
"contact_info_description": "Peça nome, apelido, email, número de telefone e empresa em conjunto",
|
||||||
"csat": "Satisfação do Cliente (CSAT)",
|
"csat_description": "Meça o Customer Satisfaction Score do seu produto ou serviço.",
|
||||||
"csat_description": "Mede a Pontuação de Satisfação do Cliente (1-5)",
|
|
||||||
"csat_lower_label": "Muito insatisfeito",
|
|
||||||
"csat_name": "Customer Satisfaction Score (CSAT)",
|
"csat_name": "Customer Satisfaction Score (CSAT)",
|
||||||
"csat_question_10_headline": "Tem mais algum comentário, pergunta ou preocupação?",
|
"csat_question_10_headline": "Tem mais algum comentário, pergunta ou preocupação?",
|
||||||
"csat_question_10_placeholder": "Escreva a sua resposta aqui...",
|
"csat_question_10_placeholder": "Escreva a sua resposta aqui...",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Escreva a sua resposta aqui...",
|
"csat_survey_question_2_placeholder": "Escreva a sua resposta aqui...",
|
||||||
"csat_survey_question_3_headline": "Oh, desculpe! Há algo que possamos fazer para melhorar a sua experiência?",
|
"csat_survey_question_3_headline": "Oh, desculpe! Há algo que possamos fazer para melhorar a sua experiência?",
|
||||||
"csat_survey_question_3_placeholder": "Escreva a sua resposta aqui...",
|
"csat_survey_question_3_placeholder": "Escreva a sua resposta aqui...",
|
||||||
"csat_upper_label": "Muito satisfeito",
|
|
||||||
"cta_description": "Exibir informações e solicitar aos utilizadores que tomem uma ação específica",
|
"cta_description": "Exibir informações e solicitar aos utilizadores que tomem uma ação específica",
|
||||||
"custom_survey_description": "Crie um inquérito sem modelo.",
|
"custom_survey_description": "Crie um inquérito sem modelo.",
|
||||||
"custom_survey_name": "Começar do zero",
|
"custom_survey_name": "Começar do zero",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "O que é uma coisa que poderíamos fazer melhor?",
|
"gauge_feature_satisfaction_question_2_headline": "O que é uma coisa que poderíamos fazer melhor?",
|
||||||
"identify_customer_goals_description": "Compreenda melhor se a sua mensagem cria as expectativas certas sobre o valor que o seu produto oferece.",
|
"identify_customer_goals_description": "Compreenda melhor se a sua mensagem cria as expectativas certas sobre o valor que o seu produto oferece.",
|
||||||
"identify_customer_goals_name": "Identificar Objetivos do Cliente",
|
"identify_customer_goals_name": "Identificar Objetivos do Cliente",
|
||||||
"identify_customer_goals_question_1_choice_1": "Compreender profundamente a minha base de utilizadores",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Identificar oportunidades de upselling",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "Construir o melhor produto possível",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "Dominar o mundo para fazer couves de Bruxelas ao pequeno-almoço para todos",
|
|
||||||
"identify_customer_goals_question_1_headline": "Qual é o teu objetivo principal ao usar $[workspaceName]?",
|
|
||||||
"identify_sign_up_barriers_description": "Ofereça um desconto para obter informações sobre as barreiras de inscrição.",
|
"identify_sign_up_barriers_description": "Ofereça um desconto para obter informações sobre as barreiras de inscrição.",
|
||||||
"identify_sign_up_barriers_name": "Identificar Barreiras de Inscrição",
|
"identify_sign_up_barriers_name": "Identificar Barreiras de Inscrição",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Obtenha 10% de desconto",
|
"identify_sign_up_barriers_question_1_button_label": "Obtenha 10% de desconto",
|
||||||
@@ -1164,8 +1145,6 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Ajude-nos a compreendê-lo melhor:",
|
"improve_trial_conversion_question_1_subheader": "Ajude-nos a compreendê-lo melhor:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Seguinte",
|
"improve_trial_conversion_question_2_button_label": "Seguinte",
|
||||||
"improve_trial_conversion_question_2_headline": "Lamentamos saber. Qual foi o maior problema ao usar o $[workspaceName]?",
|
"improve_trial_conversion_question_2_headline": "Lamentamos saber. Qual foi o maior problema ao usar o $[workspaceName]?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Seguinte",
|
|
||||||
"improve_trial_conversion_question_3_headline": "O que esperavas que $[workspaceName] fizesse?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "Obtenha 20% de desconto",
|
"improve_trial_conversion_question_4_button_label": "Obtenha 20% de desconto",
|
||||||
"improve_trial_conversion_question_4_headline": "Lamentamos saber! Obtenha 20% de desconto no primeiro ano.",
|
"improve_trial_conversion_question_4_headline": "Lamentamos saber! Obtenha 20% de desconto no primeiro ano.",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Estamos felizes por lhe oferecer um desconto de 20% num plano anual.</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Estamos felizes por lhe oferecer um desconto de 20% num plano anual.</span></p>",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Esta ação será desencadeada quando a página for carregada.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Esta ação será desencadeada quando a página for carregada.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Esta ação será desencadeada quando o utilizador rolar 50% da página.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Esta ação será desencadeada quando o utilizador rolar 50% da página.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Esta ação será desencadeada quando o utilizador tentar sair da página.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Esta ação será desencadeada quando o utilizador tentar sair da página.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Esta é uma ação de código. Por favor, faça alterações na sua base de código.",
|
||||||
"time_in_seconds": "Tempo em segundos",
|
"time_in_seconds": "Tempo em segundos",
|
||||||
"time_in_seconds_placeholder": "ex. 10",
|
"time_in_seconds_placeholder": "ex. 10",
|
||||||
"time_in_seconds_with_unit": "{seconds}s",
|
"time_in_seconds_with_unit": "{seconds}s",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "Chave API atualizada",
|
"api_key_updated": "Chave API atualizada",
|
||||||
"delete_api_key_confirmation": "Quaisquer aplicações que utilizem esta chave deixarão de poder aceder aos seus dados Formbricks.",
|
"delete_api_key_confirmation": "Quaisquer aplicações que utilizem esta chave deixarão de poder aceder aos seus dados Formbricks.",
|
||||||
"duplicate_access": "Acesso duplicado ao workspace não permitido",
|
"duplicate_access": "Acesso duplicado ao workspace não permitido",
|
||||||
"duplicate_directory_access": "Não é permitido o acesso duplicado ao diretório de registos de feedback",
|
|
||||||
"feedback_record_directory_access": "Acesso ao Diretório de Registos de Feedback",
|
|
||||||
"no_api_keys_yet": "Ainda não tem nenhuma chave de API",
|
"no_api_keys_yet": "Ainda não tem nenhuma chave de API",
|
||||||
"no_directory_permissions_found": "Não foram encontradas permissões para o diretório de registos de feedback",
|
"no_env_permissions_found": "Nenhuma permissão de ambiente encontrada",
|
||||||
"no_workspace_permissions_found": "Não foram encontradas permissões de Espaço de Trabalho",
|
|
||||||
"organization_access": "Acesso à organização",
|
"organization_access": "Acesso à organização",
|
||||||
"organization_access_description": "Selecione privilégios de leitura ou escrita para recursos de toda a organização.",
|
"organization_access_description": "Selecione privilégios de leitura ou escrita para recursos de toda a organização.",
|
||||||
"permissions": "Permissões",
|
"permissions": "Permissões",
|
||||||
"secret": "Segredo",
|
"secret": "Segredo",
|
||||||
"unable_to_copy_api_key": "Não foi possível copiar a chave API",
|
|
||||||
"unable_to_delete_api_key": "Não foi possível eliminar a chave de API",
|
"unable_to_delete_api_key": "Não foi possível eliminar a chave de API",
|
||||||
"unknown_directory": "Diretório desconhecido",
|
|
||||||
"unknown_workspace": "Área de trabalho desconhecida",
|
|
||||||
"workspace_access": "Acesso ao workspace"
|
"workspace_access": "Acesso ao workspace"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Ligue a sua aplicação ou website ao Formbricks.",
|
"app_connection_description": "Ligue a sua aplicação ou website ao Formbricks.",
|
||||||
"cache_update_delay_description": "Quando faz atualizações a inquéritos, contactos, ações ou outros dados, pode demorar até 1 minuto para que essas alterações apareçam na sua aplicação local que executa o SDK do Formbricks.",
|
"cache_update_delay_description": "Quando faz atualizações a inquéritos, contactos, ações ou outros dados, pode demorar até 1 minuto para que essas alterações apareçam na sua aplicação local que executa o SDK do Formbricks.",
|
||||||
"cache_update_delay_title": "As alterações serão refletidas após ~1 minuto devido ao caching",
|
"cache_update_delay_title": "As alterações serão refletidas após ~1 minuto devido ao caching",
|
||||||
|
"environment_id": "O teu ID do Espaço de Trabalho",
|
||||||
|
"environment_id_description": "Este ID identifica de forma única este espaço de trabalho do Formbricks.",
|
||||||
"formbricks_sdk_connected": "O SDK do Formbricks está conectado",
|
"formbricks_sdk_connected": "O SDK do Formbricks está conectado",
|
||||||
"formbricks_sdk_not_connected": "O SDK do Formbricks ainda não está conectado.",
|
"formbricks_sdk_not_connected": "O SDK do Formbricks ainda não está conectado.",
|
||||||
"formbricks_sdk_not_connected_description": "Adicione o SDK do Formbricks ao seu website ou aplicação para o conectar ao Formbricks",
|
"formbricks_sdk_not_connected_description": "Adicione o SDK do Formbricks ao seu website ou aplicação para o conectar ao Formbricks",
|
||||||
@@ -1866,12 +1842,10 @@
|
|||||||
"receiving_data": "A receber dados 💃🕺",
|
"receiving_data": "A receber dados 💃🕺",
|
||||||
"recheck": "Verificar novamente",
|
"recheck": "Verificar novamente",
|
||||||
"sdk_connection_details": "Detalhes da ligação do SDK",
|
"sdk_connection_details": "Detalhes da ligação do SDK",
|
||||||
"sdk_connection_details_description": "O teu ID único de Espaço de Trabalho e URL de conexão SDK para integrar o Formbricks com a tua aplicação.",
|
"sdk_connection_details_description": "O teu ID único do espaço de trabalho e o URL de ligação do SDK para integrares o Formbricks com a tua aplicação.",
|
||||||
"setup_alert_description": "Siga este tutorial passo a passo para conectar a sua aplicação ou website em menos de 5 minutos.",
|
"setup_alert_description": "Siga este tutorial passo a passo para conectar a sua aplicação ou website em menos de 5 minutos.",
|
||||||
"setup_alert_title": "Como conectar",
|
"setup_alert_title": "Como conectar",
|
||||||
"webapp_url": "URL de conexão SDK",
|
"webapp_url": "URL de conexão SDK"
|
||||||
"workspace_id": "O teu ID do Espaço de Trabalho",
|
|
||||||
"workspace_id_description": "Este ID identifica exclusivamente este Espaço de Trabalho Formbricks."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Parabéns!",
|
"congrats": "Parabéns!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Valor do atributo",
|
"attribute_value_placeholder": "Valor do atributo",
|
||||||
"attributes_msg_attribute_limit_exceeded": "Não foi possível criar {count} novo(s) atributo(s), pois excederia o limite máximo de {limit} classes de atributos. Os atributos existentes foram atualizados com sucesso.",
|
"attributes_msg_attribute_limit_exceeded": "Não foi possível criar {count} novo(s) atributo(s), pois excederia o limite máximo de {limit} classes de atributos. Os atributos existentes foram atualizados com sucesso.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (o atributo “{key}” tem dataType: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (o atributo “{key}” tem dataType: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "O e-mail já existe para este Espaço de Trabalho e não foi atualizado.",
|
"attributes_msg_email_already_exists": "O email já existe para este ambiente e não foi atualizado.",
|
||||||
"attributes_msg_email_or_userid_required": "É necessário um email ou ID de utilizador. Os valores existentes foram preservados.",
|
"attributes_msg_email_or_userid_required": "É necessário um email ou ID de utilizador. Os valores existentes foram preservados.",
|
||||||
"attributes_msg_new_attribute_created": "Criado novo atributo “{key}” com tipo “{dataType}”",
|
"attributes_msg_new_attribute_created": "Criado novo atributo “{key}” com tipo “{dataType}”",
|
||||||
"attributes_msg_userid_already_exists": "O ID de utilizador já existe para este Espaço de Trabalho e não foi atualizado.",
|
"attributes_msg_userid_already_exists": "O ID de utilizador já existe para este ambiente e não foi atualizado.",
|
||||||
"contact_deleted_successfully": "Contacto eliminado com sucesso",
|
"contact_deleted_successfully": "Contacto eliminado com sucesso",
|
||||||
"contacts_table_refresh": "Atualizar contactos",
|
"contacts_table_refresh": "Atualizar contactos",
|
||||||
"contacts_table_refresh_success": "Contactos atualizados com sucesso",
|
"contacts_table_refresh_success": "Contactos atualizados com sucesso",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Idioma ou ID de idioma duplicado",
|
"duplicate_language_or_language_id": "Idioma ou ID de idioma duplicado",
|
||||||
"edit_languages": "Editar idiomas",
|
"edit_languages": "Editar idiomas",
|
||||||
"identifier": "Identificador (ISO)",
|
"identifier": "Identificador (ISO)",
|
||||||
|
"incomplete_translations": "Traduções incompletas",
|
||||||
"language": "Idioma",
|
"language": "Idioma",
|
||||||
"language_deleted_successfully": "Idioma eliminado com sucesso",
|
"language_deleted_successfully": "Idioma eliminado com sucesso",
|
||||||
"languages_updated_successfully": "Idiomas atualizados com sucesso",
|
"languages_updated_successfully": "Idiomas atualizados com sucesso",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Por favor, selecione um idioma",
|
"please_select_a_language": "Por favor, selecione um idioma",
|
||||||
"remove_language": "Remover idioma",
|
"remove_language": "Remover idioma",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Por favor, remova o idioma destes inquéritos para o poder remover do espaço de trabalho.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Por favor, remova o idioma destes inquéritos para o poder remover do espaço de trabalho.",
|
||||||
"search_items": "Pesquisar itens"
|
"search_items": "Pesquisar itens",
|
||||||
|
"translate": "Traduzir"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Adicionar cor de fundo",
|
"add_background_color": "Adicionar cor de fundo",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "Está tudo pronto! Hora de criar o seu primeiro inquérito",
|
"all_set_time_to_create_first_survey": "Está tudo pronto! Hora de criar o seu primeiro inquérito",
|
||||||
"alphabetical": "Alfabética",
|
"alphabetical": "Alfabética",
|
||||||
|
"copy_survey": "Copiar inquérito",
|
||||||
|
"copy_survey_description": "Copiar este inquérito para outro espaço de trabalho",
|
||||||
|
"copy_survey_error": "Falha ao copiar inquérito",
|
||||||
"copy_survey_link_to_clipboard": "Copiar link do inquérito para a área de transferência",
|
"copy_survey_link_to_clipboard": "Copiar link do inquérito para a área de transferência",
|
||||||
|
"copy_survey_no_workspaces": "Não existem outros espaços de trabalho para onde copiar este inquérito.",
|
||||||
|
"copy_survey_partially_success": "{success} inquéritos copiados com sucesso, {error} falharam.",
|
||||||
|
"copy_survey_success": "Inquérito copiado com sucesso!",
|
||||||
"delete_survey_and_responses_warning": "Tem a certeza de que deseja eliminar este inquérito e todas as suas respostas?",
|
"delete_survey_and_responses_warning": "Tem a certeza de que deseja eliminar este inquérito e todas as suas respostas?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Ativar traduções",
|
"1_choose_the_default_language_for_this_survey": "1. Escolha o idioma padrão para este inquérito:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Ativar tradução para idiomas específicos:",
|
||||||
"add": "Adicionar +",
|
"add": "Adicionar +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Adicionar um atraso ou fechar automaticamente o inquérito",
|
"add_a_delay_or_auto_close_the_survey": "Adicionar um atraso ou fechar automaticamente o inquérito",
|
||||||
"add_a_four_digit_pin": "Adicione um PIN de quatro dígitos",
|
"add_a_four_digit_pin": "Adicione um PIN de quatro dígitos",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Público",
|
"audience": "Público",
|
||||||
"auto_close_on_inactivity": "Fechar automaticamente por inatividade",
|
"auto_close_on_inactivity": "Fechar automaticamente por inatividade",
|
||||||
"auto_progress_rating_and_nps": "Avançar automaticamente em perguntas de classificação e NPS",
|
"auto_progress_rating_and_nps": "Avançar automaticamente em perguntas de classificação e NPS",
|
||||||
"auto_progress_rating_and_nps_description": "Avançar automaticamente em blocos de pergunta única. Perguntas obrigatórias ocultam o botão Seguinte, exceto quando \"Outro\" está selecionado.",
|
"auto_progress_rating_and_nps_description": "Avança automaticamente quando os inquiridos selecionam uma resposta em perguntas de classificação ou NPS. Isto aplica-se apenas a blocos com uma única pergunta. Perguntas obrigatórias ocultam o botão Seguinte; perguntas opcionais continuam a mostrá-lo para permitir saltar.",
|
||||||
"auto_save_disabled": "Guardar automático desativado",
|
"auto_save_disabled": "Guardar automático desativado",
|
||||||
"auto_save_disabled_tooltip": "O seu inquérito só é guardado automaticamente quando está em rascunho. Isto garante que os inquéritos públicos não sejam atualizados involuntariamente.",
|
"auto_save_disabled_tooltip": "O seu inquérito só é guardado automaticamente quando está em rascunho. Isto garante que os inquéritos públicos não sejam atualizados involuntariamente.",
|
||||||
"auto_save_on": "Guardar automático ativado",
|
"auto_save_on": "Guardar automático ativado",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "As alterações levarão a inconsistências",
|
"caution_text": "As alterações levarão a inconsistências",
|
||||||
"change_anyway": "Alterar mesmo assim",
|
"change_anyway": "Alterar mesmo assim",
|
||||||
"change_background": "Alterar fundo",
|
"change_background": "Alterar fundo",
|
||||||
"change_default": "Alterar predefinição",
|
|
||||||
"change_question_type": "Alterar tipo de pergunta",
|
"change_question_type": "Alterar tipo de pergunta",
|
||||||
"change_survey_type": "Alterar o tipo de inquérito afeta o acesso existente",
|
"change_survey_type": "Alterar o tipo de inquérito afeta o acesso existente",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Altere o fundo para uma cor, imagem ou animação",
|
"change_the_background_to_a_color_image_or_animation": "Altere o fundo para uma cor, imagem ou animação",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Escolha a primeira pergunta no seu bloco",
|
"choose_the_first_question_on_your_block": "Escolha a primeira pergunta no seu bloco",
|
||||||
"choose_where_to_run_the_survey": "Escolha onde realizar o inquérito.",
|
"choose_where_to_run_the_survey": "Escolha onde realizar o inquérito.",
|
||||||
"city": "Cidade",
|
"city": "Cidade",
|
||||||
"clear_close_on_date": "Limpar data de pausa",
|
|
||||||
"clear_publish_on_date": "Limpar data de publicação",
|
|
||||||
"close_survey_on_date": "Data de pausa",
|
|
||||||
"close_survey_on_response_limit": "Fechar inquérito no limite de respostas",
|
"close_survey_on_response_limit": "Fechar inquérito no limite de respostas",
|
||||||
"code": "Código",
|
|
||||||
"color": "Cor",
|
"color": "Cor",
|
||||||
"column_used_in_logic_error": "Esta coluna é usada na lógica da pergunta {questionIndex}. Por favor, remova-a da lógica primeiro.",
|
"column_used_in_logic_error": "Esta coluna é usada na lógica da pergunta {questionIndex}. Por favor, remova-a da lógica primeiro.",
|
||||||
"columns": "Colunas",
|
"columns": "Colunas",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "Personalizar o logótipo do inquérito",
|
"customize_survey_logo": "Personalizar o logótipo do inquérito",
|
||||||
"darken_or_lighten_background_of_your_choice": "Escurecer ou clarear o fundo da sua escolha.",
|
"darken_or_lighten_background_of_your_choice": "Escurecer ou clarear o fundo da sua escolha.",
|
||||||
"days_before_showing_this_survey_again": "ou mais dias a decorrer entre o último inquérito apresentado e a apresentação deste inquérito.",
|
"days_before_showing_this_survey_again": "ou mais dias a decorrer entre o último inquérito apresentado e a apresentação deste inquérito.",
|
||||||
"default_language": "Idioma predefinido",
|
|
||||||
"delete_anyways": "Eliminar mesmo assim",
|
"delete_anyways": "Eliminar mesmo assim",
|
||||||
"delete_block": "Eliminar bloco",
|
"delete_block": "Eliminar bloco",
|
||||||
"delete_choice": "Eliminar escolha",
|
"delete_choice": "Eliminar escolha",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Duplicar pergunta",
|
"duplicate_question": "Duplicar pergunta",
|
||||||
"edit_link": "Editar link",
|
"edit_link": "Editar link",
|
||||||
"edit_recall": "Editar Lembrete",
|
"edit_recall": "Editar Lembrete",
|
||||||
|
"edit_translations": "Editar traduções {lang}",
|
||||||
"element_not_found": "Pergunta não encontrada",
|
"element_not_found": "Pergunta não encontrada",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permitir que os inquiridos mudem de idioma a qualquer momento. Necessita de pelo menos 2 idiomas ativos.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permitir que os inquiridos mudem de idioma a qualquer momento. Necessita de pelo menos 2 idiomas ativos.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "A proteção contra spam usa o reCAPTCHA v3 para filtrar as respostas de spam.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "A proteção contra spam usa o reCAPTCHA v3 para filtrar as respostas de spam.",
|
||||||
@@ -3013,13 +2991,11 @@
|
|||||||
"long_answer": "Resposta longa",
|
"long_answer": "Resposta longa",
|
||||||
"long_answer_toggle_description": "Permitir que os inquiridos escrevam respostas mais longas e com várias linhas.",
|
"long_answer_toggle_description": "Permitir que os inquiridos escrevam respostas mais longas e com várias linhas.",
|
||||||
"lower_label": "Etiqueta Inferior",
|
"lower_label": "Etiqueta Inferior",
|
||||||
"manage_languages": "Gerir idiomas",
|
"manage_languages": "Gerir Idiomas",
|
||||||
"manage_translations": "Gerir traduções",
|
|
||||||
"matrix_all_fields": "Todos os campos",
|
"matrix_all_fields": "Todos os campos",
|
||||||
"matrix_rows": "Linhas",
|
"matrix_rows": "Linhas",
|
||||||
"max_file_size": "Tamanho máximo de ficheiro",
|
"max_file_size": "Tamanho máximo de ficheiro",
|
||||||
"max_file_size_limit_is": "O limite de tamanho máximo de ficheiro é",
|
"max_file_size_limit_is": "O limite de tamanho máximo de ficheiro é",
|
||||||
"missing_first": "Em falta primeiro",
|
|
||||||
"move_question_to_block": "Mover pergunta para o bloco",
|
"move_question_to_block": "Mover pergunta para o bloco",
|
||||||
"multiply": "Multiplicar *",
|
"multiply": "Multiplicar *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Necessário para uma instância auto-hospedada do Cal.com",
|
"needed_for_self_hosted_cal_com_instance": "Necessário para uma instância auto-hospedada do Cal.com",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "Rótulo do botão \"Seguinte\"",
|
"next_button_label": "Rótulo do botão \"Seguinte\"",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Ainda não há campos ocultos. Adicione o primeiro abaixo.",
|
"no_hidden_fields_yet_add_first_one_below": "Ainda não há campos ocultos. Adicione o primeiro abaixo.",
|
||||||
"no_images_found_for": "Não foram encontradas imagens para ''{query}\"",
|
"no_images_found_for": "Não foram encontradas imagens para ''{query}\"",
|
||||||
"no_languages_found_add_first_one_to_get_started": "Não foram encontrados idiomas de inquérito nesta área de trabalho. Por favor, adicione um para começar.",
|
"no_languages_found_add_first_one_to_get_started": "Nenhuma língua encontrada. Adicione a primeira para começar.",
|
||||||
"no_option_found": "Nenhuma opção encontrada",
|
"no_option_found": "Nenhuma opção encontrada",
|
||||||
"no_recall_items_found": "Nenhum item de recuperação encontrado",
|
"no_recall_items_found": "Nenhum item de recuperação encontrado",
|
||||||
"no_variables_yet_add_first_one_below": "Ainda não há variáveis. Adicione a primeira abaixo.",
|
"no_variables_yet_add_first_one_below": "Ainda não há variáveis. Adicione a primeira abaixo.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Por favor, insira um URL válido (por exemplo, https://example.com)",
|
"please_enter_a_valid_url": "Por favor, insira um URL válido (por exemplo, https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Por favor, defina um desencadeador de inquérito",
|
"please_set_a_survey_trigger": "Por favor, defina um desencadeador de inquérito",
|
||||||
"please_specify": "Por favor, especifique",
|
"please_specify": "Por favor, especifique",
|
||||||
"present_your_survey_in_multiple_languages": "Apresenta o teu inquérito em vários idiomas",
|
|
||||||
"prevent_double_submission": "Impedir submissão dupla",
|
"prevent_double_submission": "Impedir submissão dupla",
|
||||||
"prevent_double_submission_description": "Permitir apenas 1 resposta por endereço de email",
|
"prevent_double_submission_description": "Permitir apenas 1 resposta por endereço de email",
|
||||||
"progress_saved": "Progresso guardado",
|
"progress_saved": "Progresso guardado",
|
||||||
"protect_survey_with_pin": "Proteger inquérito com um PIN",
|
"protect_survey_with_pin": "Proteger inquérito com um PIN",
|
||||||
"protect_survey_with_pin_description": "Apenas utilizadores com o PIN podem aceder ao inquérito.",
|
"protect_survey_with_pin_description": "Apenas utilizadores com o PIN podem aceder ao inquérito.",
|
||||||
"publish": "Publicar",
|
"publish": "Publicar",
|
||||||
"publish_survey_on_date": "Data de publicação",
|
|
||||||
"question": "Pergunta",
|
"question": "Pergunta",
|
||||||
"question_deleted": "Pergunta eliminada.",
|
"question_deleted": "Pergunta eliminada.",
|
||||||
"question_duplicated": "Pergunta duplicada.",
|
"question_duplicated": "Pergunta duplicada.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Linhas",
|
"rows": "Linhas",
|
||||||
"save_and_close": "Guardar e Fechar",
|
"save_and_close": "Guardar e Fechar",
|
||||||
"scale": "Escala",
|
"scale": "Escala",
|
||||||
"schedule_survey": "Agendar inquérito",
|
|
||||||
"search_for_images": "Procurar imagens",
|
"search_for_images": "Procurar imagens",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "segundos após o acionamento o inquérito será fechado se não houver resposta",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "segundos após o acionamento o inquérito será fechado se não houver resposta",
|
||||||
"seconds_before_showing_the_survey": "segundos antes de mostrar o inquérito.",
|
"seconds_before_showing_the_survey": "segundos antes de mostrar o inquérito.",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 pontos",
|
"seven_points": "7 pontos",
|
||||||
"show_block_settings": "Mostrar definições do bloco",
|
"show_block_settings": "Mostrar definições do bloco",
|
||||||
"show_button": "Mostrar Botão",
|
"show_button": "Mostrar Botão",
|
||||||
"show_in_order": "Mostrar por ordem",
|
|
||||||
"show_language_switch": "Mostrar alternador de idioma",
|
"show_language_switch": "Mostrar alternador de idioma",
|
||||||
"show_multiple_times": "Mostrar um número limitado de vezes",
|
"show_multiple_times": "Mostrar um número limitado de vezes",
|
||||||
"show_only_once": "Mostrar apenas uma vez",
|
"show_only_once": "Mostrar apenas uma vez",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Pré-visualização do questionário 👀",
|
"survey_preview": "Pré-visualização do questionário 👀",
|
||||||
"survey_styling": "Estilo do formulário",
|
"survey_styling": "Estilo do formulário",
|
||||||
"survey_trigger": "Desencadeador de Inquérito",
|
"survey_trigger": "Desencadeador de Inquérito",
|
||||||
"survey_will_be_closed_at_midnight_cet": "O inquérito será encerrado às {time} no fuso horário {timeZone} na data selecionada",
|
"switch_multi_language_on_to_get_started": "Ative o modo multilingue para começar 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "O inquérito será publicado às {time} no fuso horário {timeZone} na data selecionada",
|
|
||||||
"target_block_not_found": "Bloco de destino não encontrado",
|
"target_block_not_found": "Bloco de destino não encontrado",
|
||||||
"targeted": "Alvo",
|
"targeted": "Alvo",
|
||||||
"ten_points": "10 pontos",
|
"ten_points": "10 pontos",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Mostrar uma única vez, mesmo que não respondam.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Mostrar uma única vez, mesmo que não respondam.",
|
||||||
"then": "Então",
|
"then": "Então",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Esta ação irá remover todas as traduções deste inquérito.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Esta ação irá remover todas as traduções deste inquérito.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Isto irá remover este idioma e todas as suas traduções deste inquérito. Esta ação não pode ser revertida.",
|
|
||||||
"three_points": "3 pontos",
|
"three_points": "3 pontos",
|
||||||
"times": "tempos",
|
"times": "tempos",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Para manter a colocação consistente em todos os questionários, pode",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Para manter a colocação consistente em todos os questionários, pode",
|
||||||
"translated": "Traduzido",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Desencadear inquérito quando uma das ações for disparada...",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Desencadear inquérito quando uma das ações for disparada...",
|
||||||
"try_lollipop_or_mountain": "Experimente 'cão' ou 'planta'...",
|
"try_lollipop_or_mountain": "Experimente 'cão' ou 'planta'...",
|
||||||
"type_field_id": "Escreva o id do campo",
|
"type_field_id": "Escreva o id do campo",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Permitir apenas que pessoas com um email real respondam.",
|
"verify_email_before_submission_description": "Permitir apenas que pessoas com um email real respondam.",
|
||||||
"visibility_and_recontact": "Visibilidade e Recontacto",
|
"visibility_and_recontact": "Visibilidade e Recontacto",
|
||||||
"visibility_and_recontact_description": "Controlar quando este inquérito pode aparecer e com que frequência pode reaparecer.",
|
"visibility_and_recontact_description": "Controlar quando este inquérito pode aparecer e com que frequência pode reaparecer.",
|
||||||
"visible": "Visível",
|
|
||||||
"wait": "Aguardar",
|
"wait": "Aguardar",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Aguarde alguns segundos após o gatilho antes de mostrar o inquérito",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Aguarde alguns segundos após o gatilho antes de mostrar o inquérito",
|
||||||
"waiting_time_across_surveys": "Período de espera (entre inquéritos)",
|
"waiting_time_across_surveys": "Período de espera (entre inquéritos)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Configurar alertas",
|
"configure_alerts": "Configurar alertas",
|
||||||
"congrats": "Parabéns! O seu inquérito está ativo.",
|
"congrats": "Parabéns! O seu inquérito está ativo.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Ligue o seu website ou aplicação ao Formbricks para começar.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Ligue o seu website ou aplicação ao Formbricks para começar.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% Satisfeitos",
|
|
||||||
"csat_satisfied_tooltip": "{percentage}% dos inquiridos deram uma classificação de 4 ou 5 (CSAT).",
|
|
||||||
"current_count": "Contagem atual",
|
"current_count": "Contagem atual",
|
||||||
"custom_range": "Intervalo personalizado...",
|
"custom_range": "Intervalo personalizado...",
|
||||||
"delete_all_existing_responses_and_displays": "Excluir todas as respostas existentes e exibições",
|
"delete_all_existing_responses_and_displays": "Excluir todas as respostas existentes e exibições",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "A transferir código QR",
|
"downloading_qr_code": "A transferir código QR",
|
||||||
"drop_offs": "Desistências",
|
"drop_offs": "Desistências",
|
||||||
"drop_offs_tooltip": "Número de vezes que o inquérito foi iniciado mas não concluído.",
|
"drop_offs_tooltip": "Número de vezes que o inquérito foi iniciado mas não concluído.",
|
||||||
"effort_score": "Pontuação de Esforço",
|
"failed_to_copy_link": "Falha ao copiar link",
|
||||||
"filter_added_successfully": "Filtro adicionado com sucesso",
|
"filter_added_successfully": "Filtro adicionado com sucesso",
|
||||||
"filter_updated_successfully": "Filtro atualizado com sucesso",
|
"filter_updated_successfully": "Filtro atualizado com sucesso",
|
||||||
"filtered_responses_csv": "Respostas filtradas (CSV)",
|
"filtered_responses_csv": "Respostas filtradas (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Limite",
|
"limit": "Limite",
|
||||||
"no_identified_impressions": "Sem impressões de contactos identificados",
|
"no_identified_impressions": "Sem impressões de contactos identificados",
|
||||||
"no_responses_found": "Nenhuma resposta encontrada",
|
"no_responses_found": "Nenhuma resposta encontrada",
|
||||||
"nps_promoters_tooltip": "{percentage}% dos inquiridos deram uma classificação de 9 ou 10 (promotores NPS).",
|
|
||||||
"other_values_found": "Outros valores encontrados",
|
"other_values_found": "Outros valores encontrados",
|
||||||
"overall": "Geral",
|
"overall": "Geral",
|
||||||
"promoters": "Promotores",
|
"promoters": "Promotores",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "O número de quotas concluídas pelos respondentes.",
|
"quotas_completed_tooltip": "O número de quotas concluídas pelos respondentes.",
|
||||||
"reset_survey": "Reiniciar inquérito",
|
"reset_survey": "Reiniciar inquérito",
|
||||||
"reset_survey_warning": "Repor um inquérito remove todas as respostas e visualizações associadas a este inquérito. Isto não pode ser desfeito.",
|
"reset_survey_warning": "Repor um inquérito remove todas as respostas e visualizações associadas a este inquérito. Isto não pode ser desfeito.",
|
||||||
|
"satisfied": "Satisfeito",
|
||||||
"selected_responses_csv": "Respostas selecionadas (CSV)",
|
"selected_responses_csv": "Respostas selecionadas (CSV)",
|
||||||
"selected_responses_excel": "Respostas selecionadas (Excel)",
|
"selected_responses_excel": "Respostas selecionadas (Excel)",
|
||||||
"setup_integrations": "Configurar integrações",
|
"setup_integrations": "Configurar integrações",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Número de vezes que o inquérito foi iniciado.",
|
"starts_tooltip": "Número de vezes que o inquérito foi iniciado.",
|
||||||
"survey_reset_successfully": "Inquérito reiniciado com sucesso! {responseCount} respostas e {displayCount} exibições foram eliminadas.",
|
"survey_reset_successfully": "Inquérito reiniciado com sucesso! {responseCount} respostas e {displayCount} exibições foram eliminadas.",
|
||||||
"survey_results": "Resultados de {surveyName}",
|
"survey_results": "Resultados de {surveyName}",
|
||||||
"survey_scheduled_successfully": "Inquérito agendado com sucesso",
|
|
||||||
"this_month": "Este mês",
|
"this_month": "Este mês",
|
||||||
"this_quarter": "Este trimestre",
|
"this_quarter": "Este trimestre",
|
||||||
"this_year": "Este ano",
|
"this_year": "Este ano",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "Inquérito eliminado com sucesso!",
|
"survey_deleted_successfully": "Inquérito eliminado com sucesso!",
|
||||||
"survey_duplicated_successfully": "Inquérito duplicado com sucesso.",
|
"survey_duplicated_successfully": "Inquérito duplicado com sucesso.",
|
||||||
|
"survey_duplication_error": "Falha ao duplicar o inquérito.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Todos os canais",
|
"all_channels": "Todos os canais",
|
||||||
"all_industries": "Todas as indústrias",
|
"all_industries": "Todas as indústrias",
|
||||||
|
|||||||
+37
-71
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Schimbă spațiul de lucru",
|
"change_workspace": "Schimbă spațiul de lucru",
|
||||||
"chart": "Grafic",
|
"chart": "Grafic",
|
||||||
"charts": "Grafice",
|
"charts": "Grafice",
|
||||||
"choice_n": "Opțiunea {{n}}",
|
|
||||||
"choices": "Alegeri",
|
"choices": "Alegeri",
|
||||||
"choose_organization": "Alege organizația",
|
"choose_organization": "Alege organizația",
|
||||||
"choose_workspace": "Alege workspace",
|
"choose_workspace": "Alege workspace",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Închide",
|
"close": "Închide",
|
||||||
"code": "Cod",
|
"code": "Cod",
|
||||||
"collapse_rows": "Restrânge rânduri",
|
"collapse_rows": "Restrânge rânduri",
|
||||||
"column_n": "Coloana {{n}}",
|
|
||||||
"completed": "Completat",
|
"completed": "Completat",
|
||||||
"configuration": "Configurează",
|
"configuration": "Configurare",
|
||||||
"confirm": "Confirmare",
|
"confirm": "Confirmare",
|
||||||
"connect": "Conectează",
|
"connect": "Conectează",
|
||||||
"connect_formbricks": "Conectează Formbricks",
|
"connect_formbricks": "Conectează Formbricks",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Cardul de finalizare",
|
"ending_card": "Cardul de finalizare",
|
||||||
"enter_url": "Introduceți URL-ul",
|
"enter_url": "Introduceți URL-ul",
|
||||||
"enterprise_license": "Licență Întreprindere",
|
"enterprise_license": "Licență Întreprindere",
|
||||||
|
"environment": "Mediu",
|
||||||
"error": "Eroare",
|
"error": "Eroare",
|
||||||
"error_component_description": "Această resursă nu există sau nu aveți drepturile necesare pentru a o accesa.",
|
"error_component_description": "Această resursă nu există sau nu aveți drepturile necesare pentru a o accesa.",
|
||||||
"error_component_title": "Eroare la încărcarea resurselor",
|
"error_component_title": "Eroare la încărcarea resurselor",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Nu s-a reușit încărcarea organizațiilor",
|
"failed_to_load_organizations": "Nu s-a reușit încărcarea organizațiilor",
|
||||||
"failed_to_load_workspaces": "Nu s-au putut încărca workspaces",
|
"failed_to_load_workspaces": "Nu s-au putut încărca workspaces",
|
||||||
"failed_to_parse_csv": "Nu s-a putut procesa fișierul CSV",
|
"failed_to_parse_csv": "Nu s-a putut procesa fișierul CSV",
|
||||||
"field_placeholder": "Substituent {{field}}",
|
|
||||||
"filter": "Filtru",
|
"filter": "Filtru",
|
||||||
"finish": "Finalizează",
|
"finish": "Finalizează",
|
||||||
"first_name": "Prenume",
|
"first_name": "Prenume",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Generează",
|
"generate": "Generează",
|
||||||
"go_back": "Înapoi",
|
"go_back": "Înapoi",
|
||||||
"go_to_dashboard": "Mergi la Tablou de Bord",
|
"go_to_dashboard": "Mergi la Tablou de Bord",
|
||||||
"headline": "Titlu",
|
|
||||||
"hidden": "Ascuns",
|
"hidden": "Ascuns",
|
||||||
"hidden_field": "Câmp ascuns",
|
"hidden_field": "Câmp ascuns",
|
||||||
"hidden_fields": "Câmpuri ascunse",
|
"hidden_fields": "Câmpuri ascunse",
|
||||||
"hide": "Ascunde",
|
"hide": "Ascunde",
|
||||||
"hide_column": "Ascunde coloana",
|
"hide_column": "Ascunde coloana",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "Imagine",
|
"image": "Imagine",
|
||||||
"images": "Imagini",
|
"images": "Imagini",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "Mai multe opțiuni",
|
"more_options": "Mai multe opțiuni",
|
||||||
"move_down": "Mută în jos",
|
"move_down": "Mută în jos",
|
||||||
"move_up": "Mută sus",
|
"move_up": "Mută sus",
|
||||||
|
"multiple_languages": "Mai multe limbi",
|
||||||
"my_product": "produsul meu",
|
"my_product": "produsul meu",
|
||||||
"name": "Nume",
|
"name": "Nume",
|
||||||
"new": "Nou",
|
"new": "Nou",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "Niciun rezultat găsit",
|
"no_result_found": "Niciun rezultat găsit",
|
||||||
"no_results": "Nicio rezultat",
|
"no_results": "Nicio rezultat",
|
||||||
"no_surveys_found": "Nu au fost găsite sondaje.",
|
"no_surveys_found": "Nu au fost găsite sondaje.",
|
||||||
"no_text_found": "Niciun text găsit",
|
|
||||||
"none_of_the_above": "Niciuna dintre cele de mai sus",
|
"none_of_the_above": "Niciuna dintre cele de mai sus",
|
||||||
"not_authenticated": "Nu sunteți autentificat pentru a efectua această acțiune.",
|
"not_authenticated": "Nu sunteți autentificat pentru a efectua această acțiune.",
|
||||||
"not_authorized": "Neautorizat",
|
"not_authorized": "Neautorizat",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Setări Organizație",
|
"organization_settings": "Setări Organizație",
|
||||||
"other": "Altele",
|
"other": "Altele",
|
||||||
"other_filters": "Alte Filtre",
|
"other_filters": "Alte Filtre",
|
||||||
"other_placeholder": "Alt substituent",
|
"others": "Altele",
|
||||||
"overlay_color": "Culoare overlay",
|
"overlay_color": "Culoare overlay",
|
||||||
"overview": "Prezentare generală",
|
"overview": "Prezentare generală",
|
||||||
"password": "Parolă",
|
"password": "Parolă",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Vă rugăm să faceți upgrade la planul dumneavoastră",
|
"please_upgrade_your_plan": "Vă rugăm să faceți upgrade la planul dumneavoastră",
|
||||||
"powered_by_formbricks": "Oferit de Formbricks",
|
"powered_by_formbricks": "Oferit de Formbricks",
|
||||||
"preview": "Previzualizare",
|
"preview": "Previzualizare",
|
||||||
|
"preview_survey": "Previzualizare Chestionar",
|
||||||
"privacy": "Politica de Confidențialitate",
|
"privacy": "Politica de Confidențialitate",
|
||||||
"product_manager": "Manager de Produs",
|
"product_manager": "Manager de Produs",
|
||||||
|
"production": "Producție",
|
||||||
"profile": "Profil",
|
"profile": "Profil",
|
||||||
"profile_id": "ID Profil",
|
"profile_id": "ID Profil",
|
||||||
"progress": "Progres",
|
"progress": "Progres",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Repornește",
|
"restart": "Repornește",
|
||||||
"retry": "Reîncearcă",
|
"retry": "Reîncearcă",
|
||||||
"role": "Rolul",
|
"role": "Rolul",
|
||||||
"row_n": "Rândul {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Vânzări",
|
"sales": "Vânzări",
|
||||||
"save": "Salvează",
|
"save": "Salvează",
|
||||||
"save_as_draft": "Salvați ca schiță",
|
"save_as_draft": "Salvați ca schiță",
|
||||||
"save_changes": "Salvează modificările",
|
"save_changes": "Salvează modificările",
|
||||||
"save_without_scheduling": "Salvează fără programare",
|
|
||||||
"saving": "Salvare",
|
"saving": "Salvare",
|
||||||
"scheduled": "Programat",
|
|
||||||
"search": "Căutare",
|
"search": "Căutare",
|
||||||
"search_charts": "Caută grafice...",
|
"search_charts": "Caută grafice...",
|
||||||
"security": "Securitate",
|
"security": "Securitate",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "Stocarea fișierelor neconfigurată, upload-urile vor eșua probabil",
|
"storage_not_configured": "Stocarea fișierelor neconfigurată, upload-urile vor eșua probabil",
|
||||||
"string": "Text",
|
"string": "Text",
|
||||||
"styling": "Stilizare",
|
"styling": "Stilizare",
|
||||||
"subheader": "Subtitlu",
|
|
||||||
"submit": "Trimite",
|
"submit": "Trimite",
|
||||||
"summary": "Sumar",
|
"summary": "Sumar",
|
||||||
"survey": "Chestionar",
|
"survey": "Chestionar",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Limbi chestionar",
|
"survey_languages": "Limbi chestionar",
|
||||||
"survey_live": "Chestionar activ",
|
"survey_live": "Chestionar activ",
|
||||||
"survey_paused": "Chestionar oprit.",
|
"survey_paused": "Chestionar oprit.",
|
||||||
"survey_scheduled": "Sondaj programat.",
|
|
||||||
"survey_type": "Tip Chestionar",
|
"survey_type": "Tip Chestionar",
|
||||||
"surveys": "Sondaje",
|
"surveys": "Sondaje",
|
||||||
"table_items_deleted_successfully": "\"{type} șterse cu succes\"",
|
"table_items_deleted_successfully": "\"{type} șterse cu succes\"",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Workspaces",
|
"workspaces": "Workspaces",
|
||||||
"years": "ani",
|
"years": "ani",
|
||||||
"yes": "Da",
|
"yes": "Da",
|
||||||
|
"you": "Tu",
|
||||||
"you_are_downgraded_to_the_community_edition": "Ai fost retrogradat la ediția Community.",
|
"you_are_downgraded_to_the_community_edition": "Ai fost retrogradat la ediția Community.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "Nu sunteți autorizat să efectuați această acțiune.",
|
"you_are_not_authorized_to_perform_this_action": "Nu sunteți autorizat să efectuați această acțiune.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Ai atins limita de {workspaceLimit} spații de lucru.",
|
"you_have_reached_your_limit_of_workspace_limit": "Ai atins limita de {workspaceLimit} spații de lucru.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "Echipa Formbricks",
|
"email_footer_text_2": "Echipa Formbricks",
|
||||||
"email_template_text_1": "Acest email a fost trimis prin Formbricks.",
|
"email_template_text_1": "Acest email a fost trimis prin Formbricks.",
|
||||||
"embed_survey_preview_email_didnt_request": "Nu ați solicitat asta?",
|
"embed_survey_preview_email_didnt_request": "Nu ați solicitat asta?",
|
||||||
|
"embed_survey_preview_email_environment_id": "ID de mediu",
|
||||||
"embed_survey_preview_email_fight_spam": "Ajută-ne să combatem spam-ul și trimite acest e-mail la hola@formbricks.com",
|
"embed_survey_preview_email_fight_spam": "Ajută-ne să combatem spam-ul și trimite acest e-mail la hola@formbricks.com",
|
||||||
"embed_survey_preview_email_heading": "Previzualizare încorporare email",
|
"embed_survey_preview_email_heading": "Previzualizare încorporare email",
|
||||||
"embed_survey_preview_email_subject": "Previzualizare chestionar email Formbricks",
|
"embed_survey_preview_email_subject": "Previzualizare chestionar email Formbricks",
|
||||||
"embed_survey_preview_email_text": "Așa arată fragmentul de cod încorporat într-un email:",
|
"embed_survey_preview_email_text": "Așa arată fragmentul de cod încorporat într-un email:",
|
||||||
"embed_survey_preview_email_workspace_id": "ID Workspace",
|
|
||||||
"forgot_password_email_change_password": "Schimbați parola",
|
"forgot_password_email_change_password": "Schimbați parola",
|
||||||
"forgot_password_email_did_not_request": "Dacă nu ați solicitat acest lucru, vă rugăm să ignorați acest email.",
|
"forgot_password_email_did_not_request": "Dacă nu ați solicitat acest lucru, vă rugăm să ignorați acest email.",
|
||||||
"forgot_password_email_heading": "Schimbați parola",
|
"forgot_password_email_heading": "Schimbați parola",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Previzualizare Întrebare",
|
"question_preview": "Previzualizare Întrebare",
|
||||||
"response_already_received": "Am primit deja un răspuns pentru această adresă de email.",
|
"response_already_received": "Am primit deja un răspuns pentru această adresă de email.",
|
||||||
"response_submitted": "Un răspuns legat de acest chestionar și contact există deja",
|
"response_submitted": "Un răspuns legat de acest chestionar și contact există deja",
|
||||||
"scheduled": "Acest sondaj este programat să devină activ în curând.",
|
|
||||||
"survey_already_answered_heading": "Sondajul a fost deja completat.",
|
"survey_already_answered_heading": "Sondajul a fost deja completat.",
|
||||||
"survey_already_answered_subheading": "Puteți folosi acest link doar o dată.",
|
"survey_already_answered_subheading": "Puteți folosi acest link doar o dată.",
|
||||||
"survey_sent_to": "Chestionar trimis către {email}",
|
"survey_sent_to": "Chestionar trimis către {email}",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Altele",
|
"career_development_survey_question_6_choice_6": "Altele",
|
||||||
"career_development_survey_question_6_headline": "Care dintre următoarele descrie cel mai bine nivelul actual al locului tău de muncă?",
|
"career_development_survey_question_6_headline": "Care dintre următoarele descrie cel mai bine nivelul actual al locului tău de muncă?",
|
||||||
"career_development_survey_question_6_subheader": "Vă rugăm să selectați una dintre următoarele",
|
"career_development_survey_question_6_subheader": "Vă rugăm să selectați una dintre următoarele",
|
||||||
"ces": "Efort client (CES)",
|
|
||||||
"ces_description": "Măsoară scorul de efort al clientului (1-5 sau 1-7)",
|
|
||||||
"ces_lower_label": "Foarte dificil",
|
|
||||||
"ces_upper_label": "Foarte ușor",
|
|
||||||
"cess_survey_name": "Chestionar CES",
|
"cess_survey_name": "Chestionar CES",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] îmi facilitează [ADAUGĂ OBIECTIV]",
|
"cess_survey_question_1_headline": "$[workspaceName] îmi facilitează [ADAUGĂ OBIECTIV]",
|
||||||
"cess_survey_question_1_lower_label": "Nu sunt deloc de acord",
|
"cess_survey_question_1_lower_label": "Nu sunt deloc de acord",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Cereți să fiți de acord cu termenii, condițiile sau utilizarea datelor",
|
"consent_description": "Cereți să fiți de acord cu termenii, condițiile sau utilizarea datelor",
|
||||||
"contact_info": "Informații de contact",
|
"contact_info": "Informații de contact",
|
||||||
"contact_info_description": "Solicitați numele, prenumele, emailul, numărul de telefon și compania împreună",
|
"contact_info_description": "Solicitați numele, prenumele, emailul, numărul de telefon și compania împreună",
|
||||||
"csat": "Satisfacție client (CSAT)",
|
"csat_description": "Măsurați Scorul de Satisfacție a Clientului al produsului sau serviciului dumneavoastră.",
|
||||||
"csat_description": "Măsoară scorul de satisfacție al clientului (1-5)",
|
|
||||||
"csat_lower_label": "Foarte nemulțumit",
|
|
||||||
"csat_name": "Scorul de Satisfacție a Clientului (CSAT)",
|
"csat_name": "Scorul de Satisfacție a Clientului (CSAT)",
|
||||||
"csat_question_10_headline": "Aveți alte comentarii, întrebări sau preocupări?",
|
"csat_question_10_headline": "Aveți alte comentarii, întrebări sau preocupări?",
|
||||||
"csat_question_10_placeholder": "Tastează răspunsul aici...",
|
"csat_question_10_placeholder": "Tastează răspunsul aici...",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Tastează răspunsul aici...",
|
"csat_survey_question_2_placeholder": "Tastează răspunsul aici...",
|
||||||
"csat_survey_question_3_headline": "Of, îmi pare rău! Există ceva ce putem face pentru a-ți îmbunătăți experiența?",
|
"csat_survey_question_3_headline": "Of, îmi pare rău! Există ceva ce putem face pentru a-ți îmbunătăți experiența?",
|
||||||
"csat_survey_question_3_placeholder": "Tastează răspunsul aici...",
|
"csat_survey_question_3_placeholder": "Tastează răspunsul aici...",
|
||||||
"csat_upper_label": "Foarte mulțumit",
|
|
||||||
"cta_description": "Afișează informații și solicită utilizatorilor să ia o acțiune specifică",
|
"cta_description": "Afișează informații și solicită utilizatorilor să ia o acțiune specifică",
|
||||||
"custom_survey_description": "Creează un sondaj fără șablon.",
|
"custom_survey_description": "Creează un sondaj fără șablon.",
|
||||||
"custom_survey_name": "Începe de la zero",
|
"custom_survey_name": "Începe de la zero",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "Care este acel lucru pe care l-am putea îmbunătăți?",
|
"gauge_feature_satisfaction_question_2_headline": "Care este acel lucru pe care l-am putea îmbunătăți?",
|
||||||
"identify_customer_goals_description": "Înțelegeți mai bine dacă mesajele voastre creează așteptările corecte privind valoarea pe care o oferă produsul vostru.",
|
"identify_customer_goals_description": "Înțelegeți mai bine dacă mesajele voastre creează așteptările corecte privind valoarea pe care o oferă produsul vostru.",
|
||||||
"identify_customer_goals_name": "Identifică Obiectivele Clienților",
|
"identify_customer_goals_name": "Identifică Obiectivele Clienților",
|
||||||
"identify_customer_goals_question_1_choice_1": "Să înțeleg în profunzime baza mea de utilizatori",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Să identific oportunități de upselling",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "Să construiesc cel mai bun produs posibil",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "Să cuceresc lumea pentru a face tuturor micul dejun cu varză de Bruxelles",
|
|
||||||
"identify_customer_goals_question_1_headline": "Care este obiectivul tău principal pentru utilizarea $[workspaceName]?",
|
|
||||||
"identify_sign_up_barriers_description": "Oferiți o reducere pentru a obține informații despre barierele de înscriere.",
|
"identify_sign_up_barriers_description": "Oferiți o reducere pentru a obține informații despre barierele de înscriere.",
|
||||||
"identify_sign_up_barriers_name": "Identificați barierele de înscriere",
|
"identify_sign_up_barriers_name": "Identificați barierele de înscriere",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Obține reducere de 10%",
|
"identify_sign_up_barriers_question_1_button_label": "Obține reducere de 10%",
|
||||||
@@ -1164,14 +1145,12 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Ajută-ne să te înțelegem mai bine:",
|
"improve_trial_conversion_question_1_subheader": "Ajută-ne să te înțelegem mai bine:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Următorul",
|
"improve_trial_conversion_question_2_button_label": "Următorul",
|
||||||
"improve_trial_conversion_question_2_headline": "Ne pare rău să auzim asta. Care a fost cea mai mare problemă în folosirea $[workspaceName]?",
|
"improve_trial_conversion_question_2_headline": "Ne pare rău să auzim asta. Care a fost cea mai mare problemă în folosirea $[workspaceName]?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Următorul",
|
|
||||||
"improve_trial_conversion_question_3_headline": "Ce te-ai așteptat să facă $[workspaceName]?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "Obțineți 20% reducere",
|
"improve_trial_conversion_question_4_button_label": "Obțineți 20% reducere",
|
||||||
"improve_trial_conversion_question_4_headline": "Ne pare rău să auzim asta! Obțineți 20% reducere în primul an.",
|
"improve_trial_conversion_question_4_headline": "Ne pare rău să auzim asta! Obțineți 20% reducere în primul an.",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Suntem bucuroși să vă oferim o reducere de 20% la un plan anual.</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Suntem bucuroși să vă oferim o reducere de 20% la un plan anual.</span></p>",
|
||||||
"improve_trial_conversion_question_5_button_label": "Următorul",
|
"improve_trial_conversion_question_5_button_label": "Următorul",
|
||||||
"improve_trial_conversion_question_5_headline": "Ce ați dori să obțineți?",
|
"improve_trial_conversion_question_5_headline": "Ce ați dori să obțineți?",
|
||||||
"improve_trial_conversion_question_5_subheader": "Te rugăm să selectezi una dintre următoarele opțiuni:",
|
"improve_trial_conversion_question_5_subheader": "Vă rugăm să selectați una dintre următoarele opțiuni:",
|
||||||
"improve_trial_conversion_question_6_headline": "Cum rezolvați acum problema dumneavoastră?",
|
"improve_trial_conversion_question_6_headline": "Cum rezolvați acum problema dumneavoastră?",
|
||||||
"improve_trial_conversion_question_6_subheader": "Vă rugăm să numiți soluțiile alternative:",
|
"improve_trial_conversion_question_6_subheader": "Vă rugăm să numiți soluțiile alternative:",
|
||||||
"integration_setup_survey_description": "Evaluați cât de ușor pot utilizatorii să adauge integrări la produsul dvs. Identificați punctele oarbe.",
|
"integration_setup_survey_description": "Evaluați cât de ușor pot utilizatorii să adauge integrări la produsul dvs. Identificați punctele oarbe.",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Această acțiune va fi declanșată atunci când pagina este încărcată.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Această acțiune va fi declanșată atunci când pagina este încărcată.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Această acțiune va fi declanșată atunci când utilizatorul derulează 50% din pagină.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Această acțiune va fi declanșată atunci când utilizatorul derulează 50% din pagină.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Această acțiune va fi declanșată atunci când utilizatorul încearcă să părăsească pagina.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Această acțiune va fi declanșată atunci când utilizatorul încearcă să părăsească pagina.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Aceasta este o acțiune de cod. Vă rugăm să faceți modificări în baza dvs. de cod.",
|
||||||
"time_in_seconds": "Timp în secunde",
|
"time_in_seconds": "Timp în secunde",
|
||||||
"time_in_seconds_placeholder": "ex. 10",
|
"time_in_seconds_placeholder": "ex. 10",
|
||||||
"time_in_seconds_with_unit": "{seconds}s",
|
"time_in_seconds_with_unit": "{seconds}s",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "Cheie API actualizată",
|
"api_key_updated": "Cheie API actualizată",
|
||||||
"delete_api_key_confirmation": "Orice aplicație care folosește această cheie nu va mai putea accesa datele dumneavoastră Formbricks.",
|
"delete_api_key_confirmation": "Orice aplicație care folosește această cheie nu va mai putea accesa datele dumneavoastră Formbricks.",
|
||||||
"duplicate_access": "Acces duplicat la spațiul de lucru nu este permis",
|
"duplicate_access": "Acces duplicat la spațiul de lucru nu este permis",
|
||||||
"duplicate_directory_access": "Accesul duplicat la directorul de înregistrări de feedback nu este permis",
|
|
||||||
"feedback_record_directory_access": "Acces la Directorul de Înregistrări de Feedback",
|
|
||||||
"no_api_keys_yet": "Nu ai încă nicio cheie API",
|
"no_api_keys_yet": "Nu ai încă nicio cheie API",
|
||||||
"no_directory_permissions_found": "Nu s-au găsit permisiuni pentru directorul de înregistrări de feedback",
|
"no_env_permissions_found": "Nu s-au găsit permisiuni pentru mediu",
|
||||||
"no_workspace_permissions_found": "Nu s-au găsit permisiuni pentru Workspace",
|
|
||||||
"organization_access": "Acces organizație",
|
"organization_access": "Acces organizație",
|
||||||
"organization_access_description": "Selectează privilegii de citire sau scriere pentru resursele la nivel de organizație.",
|
"organization_access_description": "Selectează privilegii de citire sau scriere pentru resursele la nivel de organizație.",
|
||||||
"permissions": "Permisiuni",
|
"permissions": "Permisiuni",
|
||||||
"secret": "Secret",
|
"secret": "Secret",
|
||||||
"unable_to_copy_api_key": "Nu se poate copia cheia API",
|
|
||||||
"unable_to_delete_api_key": "Nu se poate șterge cheia API",
|
"unable_to_delete_api_key": "Nu se poate șterge cheia API",
|
||||||
"unknown_directory": "Director necunoscut",
|
|
||||||
"unknown_workspace": "Spațiu de lucru necunoscut",
|
|
||||||
"workspace_access": "Acces spațiu de lucru"
|
"workspace_access": "Acces spațiu de lucru"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Conectează-ți aplicația sau site-ul la Formbricks.",
|
"app_connection_description": "Conectează-ți aplicația sau site-ul la Formbricks.",
|
||||||
"cache_update_delay_description": "Când faci actualizări la sondaje, contacte, acțiuni sau alte date, poate dura până la 1 minut până când aceste modificări apar în aplicația ta locală care rulează SDK-ul Formbricks.",
|
"cache_update_delay_description": "Când faci actualizări la sondaje, contacte, acțiuni sau alte date, poate dura până la 1 minut până când aceste modificări apar în aplicația ta locală care rulează SDK-ul Formbricks.",
|
||||||
"cache_update_delay_title": "Modificările vor fi vizibile după aproximativ 1 minut din cauza cache-ului",
|
"cache_update_delay_title": "Modificările vor fi vizibile după aproximativ 1 minut din cauza cache-ului",
|
||||||
|
"environment_id": "ID-ul spațiului tău de lucru",
|
||||||
|
"environment_id_description": "Acest ID identifică în mod unic acest spațiu de lucru Formbricks.",
|
||||||
"formbricks_sdk_connected": "SDK Formbricks este conectat",
|
"formbricks_sdk_connected": "SDK Formbricks este conectat",
|
||||||
"formbricks_sdk_not_connected": "SDK Formbricks nu este încă conectat.",
|
"formbricks_sdk_not_connected": "SDK Formbricks nu este încă conectat.",
|
||||||
"formbricks_sdk_not_connected_description": "Adaugă SDK-ul Formbricks pe site-ul sau în aplicația ta pentru a-l conecta cu Formbricks",
|
"formbricks_sdk_not_connected_description": "Adaugă SDK-ul Formbricks pe site-ul sau în aplicația ta pentru a-l conecta cu Formbricks",
|
||||||
@@ -1866,12 +1842,10 @@
|
|||||||
"receiving_data": "Date primite 💃🕺",
|
"receiving_data": "Date primite 💃🕺",
|
||||||
"recheck": "Verifică din nou",
|
"recheck": "Verifică din nou",
|
||||||
"sdk_connection_details": "Detalii conexiune SDK",
|
"sdk_connection_details": "Detalii conexiune SDK",
|
||||||
"sdk_connection_details_description": "ID-ul unic al Workspace-ului tău și URL-ul de conexiune SDK pentru integrarea Formbricks cu aplicația ta.",
|
"sdk_connection_details_description": "ID-ul unic al spațiului tău de lucru și URL-ul de conectare SDK pentru integrarea Formbricks cu aplicația ta.",
|
||||||
"setup_alert_description": "Urmează acest tutorial pas cu pas pentru a-ți conecta aplicația sau site-ul în mai puțin de 5 minute.",
|
"setup_alert_description": "Urmează acest tutorial pas cu pas pentru a-ți conecta aplicația sau site-ul în mai puțin de 5 minute.",
|
||||||
"setup_alert_title": "Cum se conectează",
|
"setup_alert_title": "Cum se conectează",
|
||||||
"webapp_url": "URL de conectare SDK",
|
"webapp_url": "URL de conectare SDK"
|
||||||
"workspace_id": "ID-ul spațiului tău de lucru",
|
|
||||||
"workspace_id_description": "Acest ID identifică în mod unic acest Workspace Formbricks."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Felicitări!",
|
"congrats": "Felicitări!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Valoare atribut",
|
"attribute_value_placeholder": "Valoare atribut",
|
||||||
"attributes_msg_attribute_limit_exceeded": "Nu s-au putut crea {count, plural, one {1 atribut nou} few {# atribute noi} other {# de atribute noi}} deoarece s-ar depăși limita maximă de {limit, plural, one {1 clasă de atribute} few {# clase de atribute} other {# de clase de atribute}}. Atributele existente au fost actualizate cu succes.",
|
"attributes_msg_attribute_limit_exceeded": "Nu s-au putut crea {count, plural, one {1 atribut nou} few {# atribute noi} other {# de atribute noi}} deoarece s-ar depăși limita maximă de {limit, plural, one {1 clasă de atribute} few {# clase de atribute} other {# de clase de atribute}}. Atributele existente au fost actualizate cu succes.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (atributul „{key}” are tipul de date: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (atributul „{key}” are tipul de date: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "Adresa de email există deja pentru acest Workspace și nu a fost actualizată.",
|
"attributes_msg_email_already_exists": "Emailul există deja pentru acest mediu și nu a fost actualizat.",
|
||||||
"attributes_msg_email_or_userid_required": "Este necesar fie un email, fie un ID de utilizator. Valorile existente au fost păstrate.",
|
"attributes_msg_email_or_userid_required": "Este necesar fie un email, fie un ID de utilizator. Valorile existente au fost păstrate.",
|
||||||
"attributes_msg_new_attribute_created": "A fost creat un nou atribut „{key}” cu tipul „{dataType}”",
|
"attributes_msg_new_attribute_created": "A fost creat un nou atribut „{key}” cu tipul „{dataType}”",
|
||||||
"attributes_msg_userid_already_exists": "ID-ul utilizatorului există deja pentru acest Workspace și nu a fost actualizat.",
|
"attributes_msg_userid_already_exists": "ID-ul de utilizator există deja pentru acest mediu și nu a fost actualizat.",
|
||||||
"contact_deleted_successfully": "Contact șters cu succes",
|
"contact_deleted_successfully": "Contact șters cu succes",
|
||||||
"contacts_table_refresh": "Reîmprospătare contacte",
|
"contacts_table_refresh": "Reîmprospătare contacte",
|
||||||
"contacts_table_refresh_success": "Contactele au fost actualizate cu succes",
|
"contacts_table_refresh_success": "Contactele au fost actualizate cu succes",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Limbă sau ID de limbă duplicat",
|
"duplicate_language_or_language_id": "Limbă sau ID de limbă duplicat",
|
||||||
"edit_languages": "Editați limbile",
|
"edit_languages": "Editați limbile",
|
||||||
"identifier": "Identificator (ISO)",
|
"identifier": "Identificator (ISO)",
|
||||||
|
"incomplete_translations": "Traduceri incomplete",
|
||||||
"language": "Limba",
|
"language": "Limba",
|
||||||
"language_deleted_successfully": "Limba a fost ștearsă cu succes",
|
"language_deleted_successfully": "Limba a fost ștearsă cu succes",
|
||||||
"languages_updated_successfully": "Limbile au fost actualizate cu succes",
|
"languages_updated_successfully": "Limbile au fost actualizate cu succes",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Vă rugăm să selectați o limbă",
|
"please_select_a_language": "Vă rugăm să selectați o limbă",
|
||||||
"remove_language": "Eliminați limba",
|
"remove_language": "Eliminați limba",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Vă rugăm să eliminați limba din aceste sondaje pentru a o elimina din spațiul de lucru.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Vă rugăm să eliminați limba din aceste sondaje pentru a o elimina din spațiul de lucru.",
|
||||||
"search_items": "Căutați elemente"
|
"search_items": "Căutați elemente",
|
||||||
|
"translate": "Traduceți"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Adăugați culoare de fundal",
|
"add_background_color": "Adăugați culoare de fundal",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "Ești gata! Este timpul să creezi primul tău chestionar",
|
"all_set_time_to_create_first_survey": "Ești gata! Este timpul să creezi primul tău chestionar",
|
||||||
"alphabetical": "Alfabetic",
|
"alphabetical": "Alfabetic",
|
||||||
|
"copy_survey": "Copiază sondajul",
|
||||||
|
"copy_survey_description": "Copiază acest sondaj într-un alt spațiu de lucru",
|
||||||
|
"copy_survey_error": "Nu s-a putut copia sondajul",
|
||||||
"copy_survey_link_to_clipboard": "Copiază linkul chestionarului în clipboard",
|
"copy_survey_link_to_clipboard": "Copiază linkul chestionarului în clipboard",
|
||||||
|
"copy_survey_no_workspaces": "Nu există alte spații de lucru în care să copiezi acest sondaj.",
|
||||||
|
"copy_survey_partially_success": "\"{success} sondaje copiate cu succes, {error} eșuate.\"",
|
||||||
|
"copy_survey_success": "\"Sondaj copiat cu succes!\"",
|
||||||
"delete_survey_and_responses_warning": "Sigur doriți să ștergeți acest sondaj și toate răspunsurile sale?",
|
"delete_survey_and_responses_warning": "Sigur doriți să ștergeți acest sondaj și toate răspunsurile sale?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Activează traducerile",
|
"1_choose_the_default_language_for_this_survey": "1. Alege limba implicită pentru acest sondaj:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Activați traducerea pentru anumite limbi:",
|
||||||
"add": "Adaugă +",
|
"add": "Adaugă +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Adăugați o întârziere sau închideți automat sondajul",
|
"add_a_delay_or_auto_close_the_survey": "Adăugați o întârziere sau închideți automat sondajul",
|
||||||
"add_a_four_digit_pin": "Adăugați un cod PIN din patru cifre",
|
"add_a_four_digit_pin": "Adăugați un cod PIN din patru cifre",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Public",
|
"audience": "Public",
|
||||||
"auto_close_on_inactivity": "Închidere automată la inactivitate",
|
"auto_close_on_inactivity": "Închidere automată la inactivitate",
|
||||||
"auto_progress_rating_and_nps": "Avansare automată pentru întrebări de rating și NPS",
|
"auto_progress_rating_and_nps": "Avansare automată pentru întrebări de rating și NPS",
|
||||||
"auto_progress_rating_and_nps_description": "Avansare automată în blocurile cu o singură întrebare. Întrebările obligatorii ascund butonul Următorul, cu excepția situației în care este selectată opțiunea „Altele“.",
|
"auto_progress_rating_and_nps_description": "Avansează automat când respondenții selectează un răspuns la întrebările de rating sau NPS. Aceasta se aplică doar blocurilor cu o singură întrebare. Întrebările obligatorii ascund butonul Următorul; întrebările opționale îl afișează în continuare pentru a permite omiterea.",
|
||||||
"auto_save_disabled": "Salvare automată dezactivată",
|
"auto_save_disabled": "Salvare automată dezactivată",
|
||||||
"auto_save_disabled_tooltip": "Chestionarul dvs. este salvat automat doar când este în ciornă. Acest lucru asigură că sondajele publice nu sunt actualizate neintenționat.",
|
"auto_save_disabled_tooltip": "Chestionarul dvs. este salvat automat doar când este în ciornă. Acest lucru asigură că sondajele publice nu sunt actualizate neintenționat.",
|
||||||
"auto_save_on": "Salvare automată activată",
|
"auto_save_on": "Salvare automată activată",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "Schimbările vor duce la inconsecvențe",
|
"caution_text": "Schimbările vor duce la inconsecvențe",
|
||||||
"change_anyway": "Schimbă oricum",
|
"change_anyway": "Schimbă oricum",
|
||||||
"change_background": "Schimbați fundalul",
|
"change_background": "Schimbați fundalul",
|
||||||
"change_default": "Schimbă implicit",
|
|
||||||
"change_question_type": "Schimbă tipul întrebării",
|
"change_question_type": "Schimbă tipul întrebării",
|
||||||
"change_survey_type": "Schimbarea tipului chestionarului afectează accesul existent",
|
"change_survey_type": "Schimbarea tipului chestionarului afectează accesul existent",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Schimbați fundalul cu o culoare, imagine sau animație.",
|
"change_the_background_to_a_color_image_or_animation": "Schimbați fundalul cu o culoare, imagine sau animație.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Alege prima întrebare din blocul tău",
|
"choose_the_first_question_on_your_block": "Alege prima întrebare din blocul tău",
|
||||||
"choose_where_to_run_the_survey": "Alegeți unde să rulați chestionarul.",
|
"choose_where_to_run_the_survey": "Alegeți unde să rulați chestionarul.",
|
||||||
"city": "Oraș",
|
"city": "Oraș",
|
||||||
"clear_close_on_date": "Șterge data pauzei",
|
|
||||||
"clear_publish_on_date": "Șterge data publicării",
|
|
||||||
"close_survey_on_date": "Data pauzei",
|
|
||||||
"close_survey_on_response_limit": "Închideți sondajul la limită de răspunsuri",
|
"close_survey_on_response_limit": "Închideți sondajul la limită de răspunsuri",
|
||||||
"code": "Cod",
|
|
||||||
"color": "Culoare",
|
"color": "Culoare",
|
||||||
"column_used_in_logic_error": "Această coloană este folosită în logica întrebării {questionIndex}. Vă rugăm să o eliminați din logică mai întâi.",
|
"column_used_in_logic_error": "Această coloană este folosită în logica întrebării {questionIndex}. Vă rugăm să o eliminați din logică mai întâi.",
|
||||||
"columns": "Coloane",
|
"columns": "Coloane",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "Personalizează logo-ul chestionarului",
|
"customize_survey_logo": "Personalizează logo-ul chestionarului",
|
||||||
"darken_or_lighten_background_of_your_choice": "Întunecați sau luminați fundalul după preferințe.",
|
"darken_or_lighten_background_of_your_choice": "Întunecați sau luminați fundalul după preferințe.",
|
||||||
"days_before_showing_this_survey_again": "sau mai multe zile să treacă între ultima afișare a sondajului și afișarea acestui sondaj.",
|
"days_before_showing_this_survey_again": "sau mai multe zile să treacă între ultima afișare a sondajului și afișarea acestui sondaj.",
|
||||||
"default_language": "Limba implicită",
|
|
||||||
"delete_anyways": "Șterge oricum",
|
"delete_anyways": "Șterge oricum",
|
||||||
"delete_block": "Șterge blocul",
|
"delete_block": "Șterge blocul",
|
||||||
"delete_choice": "Șterge alegerea",
|
"delete_choice": "Șterge alegerea",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Duplică întrebarea",
|
"duplicate_question": "Duplică întrebarea",
|
||||||
"edit_link": "Editare legătură",
|
"edit_link": "Editare legătură",
|
||||||
"edit_recall": "Editează Referințele",
|
"edit_recall": "Editează Referințele",
|
||||||
|
"edit_translations": "Editează traducerile {lang}",
|
||||||
"element_not_found": "Întrebarea nu a fost găsită",
|
"element_not_found": "Întrebarea nu a fost găsită",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permite respondenților să schimbe limba în orice moment. Necesită minimum 2 limbi active.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Permite respondenților să schimbe limba în orice moment. Necesită minimum 2 limbi active.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "Protecția împotriva spamului folosește reCAPTCHA v3 pentru a filtra răspunsurile de spam.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "Protecția împotriva spamului folosește reCAPTCHA v3 pentru a filtra răspunsurile de spam.",
|
||||||
@@ -3013,13 +2991,11 @@
|
|||||||
"long_answer": "Răspuns lung",
|
"long_answer": "Răspuns lung",
|
||||||
"long_answer_toggle_description": "Permite respondenților să scrie răspunsuri mai lungi, pe mai multe rânduri.",
|
"long_answer_toggle_description": "Permite respondenților să scrie răspunsuri mai lungi, pe mai multe rânduri.",
|
||||||
"lower_label": "Etichetă inferioară",
|
"lower_label": "Etichetă inferioară",
|
||||||
"manage_languages": "Gestionează limbile",
|
"manage_languages": "Gestionați limbile",
|
||||||
"manage_translations": "Gestionează traducerile",
|
|
||||||
"matrix_all_fields": "Toate câmpurile",
|
"matrix_all_fields": "Toate câmpurile",
|
||||||
"matrix_rows": "Rânduri",
|
"matrix_rows": "Rânduri",
|
||||||
"max_file_size": "Dimensiune maximă fișier",
|
"max_file_size": "Dimensiune maximă fișier",
|
||||||
"max_file_size_limit_is": "Limita maximă pentru dimensiunea fișierului este",
|
"max_file_size_limit_is": "Limita maximă pentru dimensiunea fișierului este",
|
||||||
"missing_first": "Lipsă întâi",
|
|
||||||
"move_question_to_block": "Mută întrebarea în bloc",
|
"move_question_to_block": "Mută întrebarea în bloc",
|
||||||
"multiply": "Multiplicare",
|
"multiply": "Multiplicare",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Necesar pentru un exemplu autogăzduit Cal.com",
|
"needed_for_self_hosted_cal_com_instance": "Necesar pentru un exemplu autogăzduit Cal.com",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "Etichetă buton \"Următorul\"",
|
"next_button_label": "Etichetă buton \"Următorul\"",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Nu există încă câmpuri ascunse. Adăugați primul mai jos.",
|
"no_hidden_fields_yet_add_first_one_below": "Nu există încă câmpuri ascunse. Adăugați primul mai jos.",
|
||||||
"no_images_found_for": "Nicio imagine găsită pentru ''{query}\"",
|
"no_images_found_for": "Nicio imagine găsită pentru ''{query}\"",
|
||||||
"no_languages_found_add_first_one_to_get_started": "Nu s-au găsit limbi pentru chestionare în acest spațiu de lucru. Te rugăm să adaugi una pentru a începe.",
|
"no_languages_found_add_first_one_to_get_started": "Nu s-au găsit limbi. Adaugă prima pentru a începe.",
|
||||||
"no_option_found": "Nicio opțiune găsită",
|
"no_option_found": "Nicio opțiune găsită",
|
||||||
"no_recall_items_found": "Nu au fost găsite elemente de reamintire",
|
"no_recall_items_found": "Nu au fost găsite elemente de reamintire",
|
||||||
"no_variables_yet_add_first_one_below": "Nu există variabile încă. Adăugați prima mai jos.",
|
"no_variables_yet_add_first_one_below": "Nu există variabile încă. Adăugați prima mai jos.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Vă rugăm să introduceți un URL valid (de exemplu, https://example.com)",
|
"please_enter_a_valid_url": "Vă rugăm să introduceți un URL valid (de exemplu, https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Vă rugăm să setați un declanșator sondaj",
|
"please_set_a_survey_trigger": "Vă rugăm să setați un declanșator sondaj",
|
||||||
"please_specify": "Vă rugăm să specificați",
|
"please_specify": "Vă rugăm să specificați",
|
||||||
"present_your_survey_in_multiple_languages": "Prezintă chestionarul tău în mai multe limbi",
|
|
||||||
"prevent_double_submission": "Prevenire trimitere dublă",
|
"prevent_double_submission": "Prevenire trimitere dublă",
|
||||||
"prevent_double_submission_description": "Permite doar 1 răspuns per adresă de email.",
|
"prevent_double_submission_description": "Permite doar 1 răspuns per adresă de email.",
|
||||||
"progress_saved": "Progres salvat",
|
"progress_saved": "Progres salvat",
|
||||||
"protect_survey_with_pin": "Protejați sondajul cu un PIN",
|
"protect_survey_with_pin": "Protejați sondajul cu un PIN",
|
||||||
"protect_survey_with_pin_description": "Doar utilizatorii care cunosc PIN-ul pot accesa sondajul.",
|
"protect_survey_with_pin_description": "Doar utilizatorii care cunosc PIN-ul pot accesa sondajul.",
|
||||||
"publish": "Publică",
|
"publish": "Publică",
|
||||||
"publish_survey_on_date": "Data publicării",
|
|
||||||
"question": "Întrebare",
|
"question": "Întrebare",
|
||||||
"question_deleted": "Întrebare ștearsă.",
|
"question_deleted": "Întrebare ștearsă.",
|
||||||
"question_duplicated": "Întrebare duplicată.",
|
"question_duplicated": "Întrebare duplicată.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Rânduri",
|
"rows": "Rânduri",
|
||||||
"save_and_close": "Salvează & Închide",
|
"save_and_close": "Salvează & Închide",
|
||||||
"scale": "Scală",
|
"scale": "Scală",
|
||||||
"schedule_survey": "Programează sondajul",
|
|
||||||
"search_for_images": "Căutare de imagini",
|
"search_for_images": "Căutare de imagini",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "secunde după declanșare sondajul va fi închis dacă nu există niciun răspuns",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "secunde după declanșare sondajul va fi închis dacă nu există niciun răspuns",
|
||||||
"seconds_before_showing_the_survey": "secunde înainte de afișarea sondajului",
|
"seconds_before_showing_the_survey": "secunde înainte de afișarea sondajului",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 puncte",
|
"seven_points": "7 puncte",
|
||||||
"show_block_settings": "Afișează setările blocului",
|
"show_block_settings": "Afișează setările blocului",
|
||||||
"show_button": "Afișează butonul",
|
"show_button": "Afișează butonul",
|
||||||
"show_in_order": "Afișează în ordine",
|
|
||||||
"show_language_switch": "Afișează comutatorul de limbă",
|
"show_language_switch": "Afișează comutatorul de limbă",
|
||||||
"show_multiple_times": "Afișează de mai multe ori",
|
"show_multiple_times": "Afișează de mai multe ori",
|
||||||
"show_only_once": "Afișează doar o dată",
|
"show_only_once": "Afișează doar o dată",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Previzualizare chestionar 👀",
|
"survey_preview": "Previzualizare chestionar 👀",
|
||||||
"survey_styling": "Stilizare formular",
|
"survey_styling": "Stilizare formular",
|
||||||
"survey_trigger": "Declanșator sondaj",
|
"survey_trigger": "Declanșator sondaj",
|
||||||
"survey_will_be_closed_at_midnight_cet": "Sondajul va fi închis la {time} în fusul orar {timeZone} în data selectată",
|
"switch_multi_language_on_to_get_started": "Activați opțiunea multi-limbă pentru a începe 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "Sondajul va fi publicat la {time} în fusul orar {timeZone} în data selectată",
|
|
||||||
"target_block_not_found": "Blocul țintă nu a fost găsit",
|
"target_block_not_found": "Blocul țintă nu a fost găsit",
|
||||||
"targeted": "Ţintite",
|
"targeted": "Ţintite",
|
||||||
"ten_points": "10 puncte",
|
"ten_points": "10 puncte",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Afișează o singură dată, chiar dacă persoana nu răspunde.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Afișează o singură dată, chiar dacă persoana nu răspunde.",
|
||||||
"then": "Apoi",
|
"then": "Apoi",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Această acțiune va elimina toate traducerile din acest sondaj.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Această acțiune va elimina toate traducerile din acest sondaj.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Aceasta va elimina această limbă și toate traducerile ei din acest chestionar. Această acțiune nu poate fi anulată.",
|
|
||||||
"three_points": "3 puncte",
|
"three_points": "3 puncte",
|
||||||
"times": "ori",
|
"times": "ori",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Pentru a menține amplasarea consecventă pentru toate sondajele, puteți",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Pentru a menține amplasarea consecventă pentru toate sondajele, puteți",
|
||||||
"translated": "Tradus",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Declanșați sondajul atunci când una dintre acțiuni este realizată...",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Declanșați sondajul atunci când una dintre acțiuni este realizată...",
|
||||||
"try_lollipop_or_mountain": "Încercați „lollipop” sau „mountain”...",
|
"try_lollipop_or_mountain": "Încercați „lollipop” sau „mountain”...",
|
||||||
"type_field_id": "ID câmp tip",
|
"type_field_id": "ID câmp tip",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Permite doar persoanelor cu un email real să răspundă.",
|
"verify_email_before_submission_description": "Permite doar persoanelor cu un email real să răspundă.",
|
||||||
"visibility_and_recontact": "Vizibilitate și recontactare",
|
"visibility_and_recontact": "Vizibilitate și recontactare",
|
||||||
"visibility_and_recontact_description": "Controlează când poate apărea acest sondaj și cât de des poate reapărea.",
|
"visibility_and_recontact_description": "Controlează când poate apărea acest sondaj și cât de des poate reapărea.",
|
||||||
"visible": "Vizibil",
|
|
||||||
"wait": "Așteptați",
|
"wait": "Așteptați",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Așteptați câteva secunde după declanșare înainte de a afișa sondajul",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Așteptați câteva secunde după declanșare înainte de a afișa sondajul",
|
||||||
"waiting_time_across_surveys": "Perioadă de răcire (între sondaje)",
|
"waiting_time_across_surveys": "Perioadă de răcire (între sondaje)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Configurează alertele",
|
"configure_alerts": "Configurează alertele",
|
||||||
"congrats": "Felicitări! Sondajul dumneavoastră este activ.",
|
"congrats": "Felicitări! Sondajul dumneavoastră este activ.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Conectează-ți site-ul sau aplicația cu Formbricks pentru a începe.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Conectează-ți site-ul sau aplicația cu Formbricks pentru a începe.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% Mulțumiți",
|
|
||||||
"csat_satisfied_tooltip": "{percentage}% dintre respondenți au acordat o evaluare de 4 sau 5 (CSAT).",
|
|
||||||
"current_count": "Număr curent",
|
"current_count": "Număr curent",
|
||||||
"custom_range": "Interval personalizat...",
|
"custom_range": "Interval personalizat...",
|
||||||
"delete_all_existing_responses_and_displays": "Șterge toate răspunsurile și afișările existente",
|
"delete_all_existing_responses_and_displays": "Șterge toate răspunsurile și afișările existente",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "Se descarcă codul QR",
|
"downloading_qr_code": "Se descarcă codul QR",
|
||||||
"drop_offs": "Renunțări",
|
"drop_offs": "Renunțări",
|
||||||
"drop_offs_tooltip": "Număr de ori când sondajul a fost început dar nu a fost finalizat.",
|
"drop_offs_tooltip": "Număr de ori când sondajul a fost început dar nu a fost finalizat.",
|
||||||
"effort_score": "Scor de efort",
|
"failed_to_copy_link": "Nu s-a putut copia legătura",
|
||||||
"filter_added_successfully": "Filtru adăugat cu succes",
|
"filter_added_successfully": "Filtru adăugat cu succes",
|
||||||
"filter_updated_successfully": "Filtru actualizat cu succes",
|
"filter_updated_successfully": "Filtru actualizat cu succes",
|
||||||
"filtered_responses_csv": "Răspunsuri filtrate (CSV)",
|
"filtered_responses_csv": "Răspunsuri filtrate (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Limită",
|
"limit": "Limită",
|
||||||
"no_identified_impressions": "Nicio impresie de la contactele identificate",
|
"no_identified_impressions": "Nicio impresie de la contactele identificate",
|
||||||
"no_responses_found": "Nu s-au găsit răspunsuri",
|
"no_responses_found": "Nu s-au găsit răspunsuri",
|
||||||
"nps_promoters_tooltip": "{percentage}% dintre respondenți au acordat o evaluare de 9 sau 10 (promotori NPS).",
|
|
||||||
"other_values_found": "Alte valori găsite",
|
"other_values_found": "Alte valori găsite",
|
||||||
"overall": "General",
|
"overall": "General",
|
||||||
"promoters": "Promotori",
|
"promoters": "Promotori",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "Numărul de cote completate de respondenți.",
|
"quotas_completed_tooltip": "Numărul de cote completate de respondenți.",
|
||||||
"reset_survey": "Resetează chestionarul",
|
"reset_survey": "Resetează chestionarul",
|
||||||
"reset_survey_warning": "Resetarea unui sondaj elimină toate răspunsurile și afișajele asociate cu acest sondaj. Aceasta nu poate fi anulată.",
|
"reset_survey_warning": "Resetarea unui sondaj elimină toate răspunsurile și afișajele asociate cu acest sondaj. Aceasta nu poate fi anulată.",
|
||||||
|
"satisfied": "Mulțumit",
|
||||||
"selected_responses_csv": "Răspunsuri selectate (CSV)",
|
"selected_responses_csv": "Răspunsuri selectate (CSV)",
|
||||||
"selected_responses_excel": "Răspunsuri selectate (Excel)",
|
"selected_responses_excel": "Răspunsuri selectate (Excel)",
|
||||||
"setup_integrations": "Configurare integrare",
|
"setup_integrations": "Configurare integrare",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Număr de ori când sondajul a fost început.",
|
"starts_tooltip": "Număr de ori când sondajul a fost început.",
|
||||||
"survey_reset_successfully": "Resetarea chestionarului realizată cu succes! Au fost șterse {responseCount} răspunsuri și {displayCount} afișări.",
|
"survey_reset_successfully": "Resetarea chestionarului realizată cu succes! Au fost șterse {responseCount} răspunsuri și {displayCount} afișări.",
|
||||||
"survey_results": "Rezultatele {surveyName}",
|
"survey_results": "Rezultatele {surveyName}",
|
||||||
"survey_scheduled_successfully": "Sondaj programat cu succes",
|
|
||||||
"this_month": "Luna aceasta",
|
"this_month": "Luna aceasta",
|
||||||
"this_quarter": "Trimestrul acesta",
|
"this_quarter": "Trimestrul acesta",
|
||||||
"this_year": "Anul acesta",
|
"this_year": "Anul acesta",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "\"Sondaj șters cu succes!\"",
|
"survey_deleted_successfully": "\"Sondaj șters cu succes!\"",
|
||||||
"survey_duplicated_successfully": "\"Sondaj duplicat cu succes!\"",
|
"survey_duplicated_successfully": "\"Sondaj duplicat cu succes!\"",
|
||||||
|
"survey_duplication_error": "Eșec la duplicarea sondajului.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Toate canalele",
|
"all_channels": "Toate canalele",
|
||||||
"all_industries": "Toate industriile",
|
"all_industries": "Toate industriile",
|
||||||
|
|||||||
+36
-70
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Сменить рабочее пространство",
|
"change_workspace": "Сменить рабочее пространство",
|
||||||
"chart": "График",
|
"chart": "График",
|
||||||
"charts": "Графики",
|
"charts": "Графики",
|
||||||
"choice_n": "Вариант {{n}}",
|
|
||||||
"choices": "Варианты",
|
"choices": "Варианты",
|
||||||
"choose_organization": "Выберите организацию",
|
"choose_organization": "Выберите организацию",
|
||||||
"choose_workspace": "Выбрать рабочее пространство",
|
"choose_workspace": "Выбрать рабочее пространство",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Закрыть",
|
"close": "Закрыть",
|
||||||
"code": "Код",
|
"code": "Код",
|
||||||
"collapse_rows": "Свернуть строки",
|
"collapse_rows": "Свернуть строки",
|
||||||
"column_n": "Колонка {{n}}",
|
|
||||||
"completed": "Завершено",
|
"completed": "Завершено",
|
||||||
"configuration": "Настроить",
|
"configuration": "Конфигурация",
|
||||||
"confirm": "Подтвердить",
|
"confirm": "Подтвердить",
|
||||||
"connect": "Подключить",
|
"connect": "Подключить",
|
||||||
"connect_formbricks": "Подключить Formbricks",
|
"connect_formbricks": "Подключить Formbricks",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Завершающая карточка",
|
"ending_card": "Завершающая карточка",
|
||||||
"enter_url": "Введите URL",
|
"enter_url": "Введите URL",
|
||||||
"enterprise_license": "Корпоративная лицензия",
|
"enterprise_license": "Корпоративная лицензия",
|
||||||
|
"environment": "Окружение",
|
||||||
"error": "Ошибка",
|
"error": "Ошибка",
|
||||||
"error_component_description": "Этот ресурс не существует или у вас нет необходимых прав для доступа к нему.",
|
"error_component_description": "Этот ресурс не существует или у вас нет необходимых прав для доступа к нему.",
|
||||||
"error_component_title": "Ошибка загрузки ресурсов",
|
"error_component_title": "Ошибка загрузки ресурсов",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Не удалось загрузить организации",
|
"failed_to_load_organizations": "Не удалось загрузить организации",
|
||||||
"failed_to_load_workspaces": "Не удалось загрузить рабочие пространства",
|
"failed_to_load_workspaces": "Не удалось загрузить рабочие пространства",
|
||||||
"failed_to_parse_csv": "Не удалось обработать CSV",
|
"failed_to_parse_csv": "Не удалось обработать CSV",
|
||||||
"field_placeholder": "Заполнитель {{field}}",
|
|
||||||
"filter": "Фильтр",
|
"filter": "Фильтр",
|
||||||
"finish": "Завершить",
|
"finish": "Завершить",
|
||||||
"first_name": "Имя",
|
"first_name": "Имя",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Сгенерировать",
|
"generate": "Сгенерировать",
|
||||||
"go_back": "Назад",
|
"go_back": "Назад",
|
||||||
"go_to_dashboard": "Перейти к панели управления",
|
"go_to_dashboard": "Перейти к панели управления",
|
||||||
"headline": "Заголовок",
|
|
||||||
"hidden": "Скрыто",
|
"hidden": "Скрыто",
|
||||||
"hidden_field": "Скрытое поле",
|
"hidden_field": "Скрытое поле",
|
||||||
"hidden_fields": "Скрытые поля",
|
"hidden_fields": "Скрытые поля",
|
||||||
"hide": "Скрыть",
|
"hide": "Скрыть",
|
||||||
"hide_column": "Скрыть столбец",
|
"hide_column": "Скрыть столбец",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "Изображение",
|
"image": "Изображение",
|
||||||
"images": "Изображения",
|
"images": "Изображения",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "Дополнительные опции",
|
"more_options": "Дополнительные опции",
|
||||||
"move_down": "Переместить вниз",
|
"move_down": "Переместить вниз",
|
||||||
"move_up": "Переместить вверх",
|
"move_up": "Переместить вверх",
|
||||||
|
"multiple_languages": "Несколько языков",
|
||||||
"my_product": "мой продукт",
|
"my_product": "мой продукт",
|
||||||
"name": "Имя",
|
"name": "Имя",
|
||||||
"new": "Новый",
|
"new": "Новый",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "Результат не найден",
|
"no_result_found": "Результат не найден",
|
||||||
"no_results": "Нет результатов",
|
"no_results": "Нет результатов",
|
||||||
"no_surveys_found": "Опросы не найдены.",
|
"no_surveys_found": "Опросы не найдены.",
|
||||||
"no_text_found": "Текст не найден",
|
|
||||||
"none_of_the_above": "Ничего из вышеперечисленного",
|
"none_of_the_above": "Ничего из вышеперечисленного",
|
||||||
"not_authenticated": "У вас нет прав для выполнения этого действия.",
|
"not_authenticated": "У вас нет прав для выполнения этого действия.",
|
||||||
"not_authorized": "Нет доступа",
|
"not_authorized": "Нет доступа",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Настройки организации",
|
"organization_settings": "Настройки организации",
|
||||||
"other": "Другое",
|
"other": "Другое",
|
||||||
"other_filters": "Другие фильтры",
|
"other_filters": "Другие фильтры",
|
||||||
"other_placeholder": "Другой заполнитель",
|
"others": "Другие",
|
||||||
"overlay_color": "Цвет наложения",
|
"overlay_color": "Цвет наложения",
|
||||||
"overview": "Обзор",
|
"overview": "Обзор",
|
||||||
"password": "Пароль",
|
"password": "Пароль",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Пожалуйста, обновите ваш тарифный план",
|
"please_upgrade_your_plan": "Пожалуйста, обновите ваш тарифный план",
|
||||||
"powered_by_formbricks": "Работает на Formbricks",
|
"powered_by_formbricks": "Работает на Formbricks",
|
||||||
"preview": "Предпросмотр",
|
"preview": "Предпросмотр",
|
||||||
|
"preview_survey": "Предпросмотр опроса",
|
||||||
"privacy": "Политика конфиденциальности",
|
"privacy": "Политика конфиденциальности",
|
||||||
"product_manager": "Менеджер продукта",
|
"product_manager": "Менеджер продукта",
|
||||||
|
"production": "Продакшн",
|
||||||
"profile": "Профиль",
|
"profile": "Профиль",
|
||||||
"profile_id": "ID профиля",
|
"profile_id": "ID профиля",
|
||||||
"progress": "Прогресс",
|
"progress": "Прогресс",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Перезапустить",
|
"restart": "Перезапустить",
|
||||||
"retry": "Повторить",
|
"retry": "Повторить",
|
||||||
"role": "Роль",
|
"role": "Роль",
|
||||||
"row_n": "Строка {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Продажи",
|
"sales": "Продажи",
|
||||||
"save": "Сохранить",
|
"save": "Сохранить",
|
||||||
"save_as_draft": "Сохранить как черновик",
|
"save_as_draft": "Сохранить как черновик",
|
||||||
"save_changes": "Сохранить изменения",
|
"save_changes": "Сохранить изменения",
|
||||||
"save_without_scheduling": "Сохранить без планирования",
|
|
||||||
"saving": "Сохранение",
|
"saving": "Сохранение",
|
||||||
"scheduled": "Запланировано",
|
|
||||||
"search": "Поиск",
|
"search": "Поиск",
|
||||||
"search_charts": "Поиск графиков...",
|
"search_charts": "Поиск графиков...",
|
||||||
"security": "Безопасность",
|
"security": "Безопасность",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "Хранилище файлов не настроено, загрузка, скорее всего, не удастся",
|
"storage_not_configured": "Хранилище файлов не настроено, загрузка, скорее всего, не удастся",
|
||||||
"string": "Текст",
|
"string": "Текст",
|
||||||
"styling": "Стилизация",
|
"styling": "Стилизация",
|
||||||
"subheader": "Подзаголовок",
|
|
||||||
"submit": "Отправить",
|
"submit": "Отправить",
|
||||||
"summary": "Сводка",
|
"summary": "Сводка",
|
||||||
"survey": "Опрос",
|
"survey": "Опрос",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Языки опроса",
|
"survey_languages": "Языки опроса",
|
||||||
"survey_live": "Опрос активен",
|
"survey_live": "Опрос активен",
|
||||||
"survey_paused": "Опрос приостановлен.",
|
"survey_paused": "Опрос приостановлен.",
|
||||||
"survey_scheduled": "Опрос запланирован.",
|
|
||||||
"survey_type": "Тип опроса",
|
"survey_type": "Тип опроса",
|
||||||
"surveys": "Опросы",
|
"surveys": "Опросы",
|
||||||
"table_items_deleted_successfully": "{type} успешно удалены",
|
"table_items_deleted_successfully": "{type} успешно удалены",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Рабочие пространства",
|
"workspaces": "Рабочие пространства",
|
||||||
"years": "годы",
|
"years": "годы",
|
||||||
"yes": "Да",
|
"yes": "Да",
|
||||||
|
"you": "Вы",
|
||||||
"you_are_downgraded_to_the_community_edition": "Ваша версия понижена до Community Edition.",
|
"you_are_downgraded_to_the_community_edition": "Ваша версия понижена до Community Edition.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "У вас нет прав для выполнения этого действия.",
|
"you_are_not_authorized_to_perform_this_action": "У вас нет прав для выполнения этого действия.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Вы достигли лимита в {workspaceLimit} рабочих пространств.",
|
"you_have_reached_your_limit_of_workspace_limit": "Вы достигли лимита в {workspaceLimit} рабочих пространств.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "Команда Formbricks",
|
"email_footer_text_2": "Команда Formbricks",
|
||||||
"email_template_text_1": "Это письмо отправлено через Formbricks.",
|
"email_template_text_1": "Это письмо отправлено через Formbricks.",
|
||||||
"embed_survey_preview_email_didnt_request": "Вы не запрашивали это?",
|
"embed_survey_preview_email_didnt_request": "Вы не запрашивали это?",
|
||||||
|
"embed_survey_preview_email_environment_id": "ID окружения",
|
||||||
"embed_survey_preview_email_fight_spam": "Помогите нам бороться со спамом — перешлите это письмо на hola@formbricks.com",
|
"embed_survey_preview_email_fight_spam": "Помогите нам бороться со спамом — перешлите это письмо на hola@formbricks.com",
|
||||||
"embed_survey_preview_email_heading": "Встраиваемый предпросмотр письма",
|
"embed_survey_preview_email_heading": "Встраиваемый предпросмотр письма",
|
||||||
"embed_survey_preview_email_subject": "Предпросмотр email-опроса Formbricks",
|
"embed_survey_preview_email_subject": "Предпросмотр email-опроса Formbricks",
|
||||||
"embed_survey_preview_email_text": "Вот как выглядит фрагмент кода, встроенный в письмо:",
|
"embed_survey_preview_email_text": "Вот как выглядит фрагмент кода, встроенный в письмо:",
|
||||||
"embed_survey_preview_email_workspace_id": "ID рабочего пространства",
|
|
||||||
"forgot_password_email_change_password": "Сменить пароль",
|
"forgot_password_email_change_password": "Сменить пароль",
|
||||||
"forgot_password_email_did_not_request": "Если вы не запрашивали это, просто проигнорируйте это письмо.",
|
"forgot_password_email_did_not_request": "Если вы не запрашивали это, просто проигнорируйте это письмо.",
|
||||||
"forgot_password_email_heading": "Сменить пароль",
|
"forgot_password_email_heading": "Сменить пароль",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Предпросмотр вопроса",
|
"question_preview": "Предпросмотр вопроса",
|
||||||
"response_already_received": "Мы уже получили ответ для этого адреса электронной почты.",
|
"response_already_received": "Мы уже получили ответ для этого адреса электронной почты.",
|
||||||
"response_submitted": "Ответ, связанный с этим опросом и контактом, уже существует",
|
"response_submitted": "Ответ, связанный с этим опросом и контактом, уже существует",
|
||||||
"scheduled": "Этот опрос скоро будет запущен.",
|
|
||||||
"survey_already_answered_heading": "Опрос уже был пройден.",
|
"survey_already_answered_heading": "Опрос уже был пройден.",
|
||||||
"survey_already_answered_subheading": "Вы можете использовать эту ссылку только один раз.",
|
"survey_already_answered_subheading": "Вы можете использовать эту ссылку только один раз.",
|
||||||
"survey_sent_to": "Опрос отправлен на {email}",
|
"survey_sent_to": "Опрос отправлен на {email}",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Другое",
|
"career_development_survey_question_6_choice_6": "Другое",
|
||||||
"career_development_survey_question_6_headline": "Какой из следующих вариантов лучше всего описывает ваш текущий уровень должности?",
|
"career_development_survey_question_6_headline": "Какой из следующих вариантов лучше всего описывает ваш текущий уровень должности?",
|
||||||
"career_development_survey_question_6_subheader": "Пожалуйста, выберите один из следующих вариантов",
|
"career_development_survey_question_6_subheader": "Пожалуйста, выберите один из следующих вариантов",
|
||||||
"ces": "Усилия клиента (CES)",
|
|
||||||
"ces_description": "Измерьте оценку усилий клиента (1-5 или 1-7)",
|
|
||||||
"ces_lower_label": "Очень сложно",
|
|
||||||
"ces_upper_label": "Очень легко",
|
|
||||||
"cess_survey_name": "Опрос CES",
|
"cess_survey_name": "Опрос CES",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] помогает мне легко [ДОБАВИТЬ ЦЕЛЬ]",
|
"cess_survey_question_1_headline": "$[workspaceName] помогает мне легко [ДОБАВИТЬ ЦЕЛЬ]",
|
||||||
"cess_survey_question_1_lower_label": "Совершенно не согласен",
|
"cess_survey_question_1_lower_label": "Совершенно не согласен",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Запросить согласие с условиями, правилами или использованием данных",
|
"consent_description": "Запросить согласие с условиями, правилами или использованием данных",
|
||||||
"contact_info": "Контактная информация",
|
"contact_info": "Контактная информация",
|
||||||
"contact_info_description": "Запросите имя, фамилию, адрес электронной почты, номер телефона и компанию вместе",
|
"contact_info_description": "Запросите имя, фамилию, адрес электронной почты, номер телефона и компанию вместе",
|
||||||
"csat": "Удовлетворённость клиента (CSAT)",
|
"csat_description": "Измерьте индекс удовлетворённости клиентов вашим продуктом или услугой.",
|
||||||
"csat_description": "Измерьте оценку удовлетворённости клиента (1-5)",
|
|
||||||
"csat_lower_label": "Очень недоволен",
|
|
||||||
"csat_name": "Индекс удовлетворённости клиентов (CSAT)",
|
"csat_name": "Индекс удовлетворённости клиентов (CSAT)",
|
||||||
"csat_question_10_headline": "Есть ли у вас другие комментарии, вопросы или замечания?",
|
"csat_question_10_headline": "Есть ли у вас другие комментарии, вопросы или замечания?",
|
||||||
"csat_question_10_placeholder": "Введите ваш ответ здесь...",
|
"csat_question_10_placeholder": "Введите ваш ответ здесь...",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Введите ваш ответ здесь...",
|
"csat_survey_question_2_placeholder": "Введите ваш ответ здесь...",
|
||||||
"csat_survey_question_3_headline": "Ой, извините! Что мы можем сделать, чтобы улучшить ваш опыт?",
|
"csat_survey_question_3_headline": "Ой, извините! Что мы можем сделать, чтобы улучшить ваш опыт?",
|
||||||
"csat_survey_question_3_placeholder": "Введите ваш ответ здесь...",
|
"csat_survey_question_3_placeholder": "Введите ваш ответ здесь...",
|
||||||
"csat_upper_label": "Очень доволен",
|
|
||||||
"cta_description": "Показывайте информацию и побуждайте пользователей к определённому действию",
|
"cta_description": "Показывайте информацию и побуждайте пользователей к определённому действию",
|
||||||
"custom_survey_description": "Создайте опрос без шаблона.",
|
"custom_survey_description": "Создайте опрос без шаблона.",
|
||||||
"custom_survey_name": "Начать с нуля",
|
"custom_survey_name": "Начать с нуля",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "Что мы могли бы сделать лучше?",
|
"gauge_feature_satisfaction_question_2_headline": "Что мы могли бы сделать лучше?",
|
||||||
"identify_customer_goals_description": "Лучше понять, создают ли ваши сообщения правильные ожидания относительно ценности вашего продукта.",
|
"identify_customer_goals_description": "Лучше понять, создают ли ваши сообщения правильные ожидания относительно ценности вашего продукта.",
|
||||||
"identify_customer_goals_name": "Определение целей клиента",
|
"identify_customer_goals_name": "Определение целей клиента",
|
||||||
"identify_customer_goals_question_1_choice_1": "Глубоко понимать свою аудиторию",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Находить возможности для допродаж",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "Создавать лучший продукт",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "Захватить мир и заставить всех есть брюссельскую капусту на завтрак",
|
|
||||||
"identify_customer_goals_question_1_headline": "Какова твоя основная цель использования $[workspaceName]?",
|
|
||||||
"identify_sign_up_barriers_description": "Предложите скидку, чтобы узнать, что мешает регистрации.",
|
"identify_sign_up_barriers_description": "Предложите скидку, чтобы узнать, что мешает регистрации.",
|
||||||
"identify_sign_up_barriers_name": "Определение барьеров регистрации",
|
"identify_sign_up_barriers_name": "Определение барьеров регистрации",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Получить скидку 10%",
|
"identify_sign_up_barriers_question_1_button_label": "Получить скидку 10%",
|
||||||
@@ -1164,14 +1145,12 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Помогите нам лучше вас понять:",
|
"improve_trial_conversion_question_1_subheader": "Помогите нам лучше вас понять:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Далее",
|
"improve_trial_conversion_question_2_button_label": "Далее",
|
||||||
"improve_trial_conversion_question_2_headline": "Жаль это слышать. Какая была самая большая проблема при использовании $[workspaceName]?",
|
"improve_trial_conversion_question_2_headline": "Жаль это слышать. Какая была самая большая проблема при использовании $[workspaceName]?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Далее",
|
|
||||||
"improve_trial_conversion_question_3_headline": "Что ты ожидал от $[workspaceName]?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "Получить скидку 20%",
|
"improve_trial_conversion_question_4_button_label": "Получить скидку 20%",
|
||||||
"improve_trial_conversion_question_4_headline": "Жаль это слышать! Получите 20% скидку на первый год.",
|
"improve_trial_conversion_question_4_headline": "Жаль это слышать! Получите 20% скидку на первый год.",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Мы рады предложить вам скидку 20% на годовой тариф.</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Мы рады предложить вам скидку 20% на годовой тариф.</span></p>",
|
||||||
"improve_trial_conversion_question_5_button_label": "Далее",
|
"improve_trial_conversion_question_5_button_label": "Далее",
|
||||||
"improve_trial_conversion_question_5_headline": "Чего бы вы хотели достичь?",
|
"improve_trial_conversion_question_5_headline": "Чего бы вы хотели достичь?",
|
||||||
"improve_trial_conversion_question_5_subheader": "Пожалуйста, выбери один из следующих вариантов:",
|
"improve_trial_conversion_question_5_subheader": "Пожалуйста, выберите один из следующих вариантов:",
|
||||||
"improve_trial_conversion_question_6_headline": "Как вы сейчас решаете свою проблему?",
|
"improve_trial_conversion_question_6_headline": "Как вы сейчас решаете свою проблему?",
|
||||||
"improve_trial_conversion_question_6_subheader": "Пожалуйста, укажите альтернативные решения:",
|
"improve_trial_conversion_question_6_subheader": "Пожалуйста, укажите альтернативные решения:",
|
||||||
"integration_setup_survey_description": "Оцените, насколько легко пользователи могут добавлять интеграции в ваш продукт. Найдите слабые места.",
|
"integration_setup_survey_description": "Оцените, насколько легко пользователи могут добавлять интеграции в ваш продукт. Найдите слабые места.",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Это действие будет выполнено при загрузке страницы.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Это действие будет выполнено при загрузке страницы.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Это действие будет выполнено, когда пользователь прокрутит 50% страницы.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Это действие будет выполнено, когда пользователь прокрутит 50% страницы.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Это действие будет выполнено, когда пользователь попытается покинуть страницу.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Это действие будет выполнено, когда пользователь попытается покинуть страницу.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Это действие с кодом. Пожалуйста, внесите изменения в ваш код.",
|
||||||
"time_in_seconds": "Время в секундах",
|
"time_in_seconds": "Время в секундах",
|
||||||
"time_in_seconds_placeholder": "например, 10",
|
"time_in_seconds_placeholder": "например, 10",
|
||||||
"time_in_seconds_with_unit": "{seconds} с",
|
"time_in_seconds_with_unit": "{seconds} с",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "API-ключ обновлён",
|
"api_key_updated": "API-ключ обновлён",
|
||||||
"delete_api_key_confirmation": "Любые приложения, использующие этот ключ, больше не смогут получить доступ к вашим данным Formbricks.",
|
"delete_api_key_confirmation": "Любые приложения, использующие этот ключ, больше не смогут получить доступ к вашим данным Formbricks.",
|
||||||
"duplicate_access": "Дублированный доступ к рабочему пространству не разрешён",
|
"duplicate_access": "Дублированный доступ к рабочему пространству не разрешён",
|
||||||
"duplicate_directory_access": "Дублирующий доступ к каталогу записей обратной связи запрещен",
|
|
||||||
"feedback_record_directory_access": "Доступ к каталогу записей обратной связи",
|
|
||||||
"no_api_keys_yet": "У вас ещё нет API-ключей",
|
"no_api_keys_yet": "У вас ещё нет API-ключей",
|
||||||
"no_directory_permissions_found": "Разрешения для каталога записей обратной связи не найдены",
|
"no_env_permissions_found": "Права доступа к окружению не найдены",
|
||||||
"no_workspace_permissions_found": "Разрешения для рабочего пространства не найдены",
|
|
||||||
"organization_access": "Доступ к организации",
|
"organization_access": "Доступ к организации",
|
||||||
"organization_access_description": "Выберите права на чтение или запись для ресурсов всей организации.",
|
"organization_access_description": "Выберите права на чтение или запись для ресурсов всей организации.",
|
||||||
"permissions": "Права доступа",
|
"permissions": "Права доступа",
|
||||||
"secret": "Секрет",
|
"secret": "Секрет",
|
||||||
"unable_to_copy_api_key": "Не удалось скопировать API-ключ",
|
|
||||||
"unable_to_delete_api_key": "Не удалось удалить API-ключ",
|
"unable_to_delete_api_key": "Не удалось удалить API-ключ",
|
||||||
"unknown_directory": "Неизвестный каталог",
|
|
||||||
"unknown_workspace": "Неизвестное рабочее пространство",
|
|
||||||
"workspace_access": "Доступ к рабочему пространству"
|
"workspace_access": "Доступ к рабочему пространству"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Подключите ваше приложение или сайт к Formbricks.",
|
"app_connection_description": "Подключите ваше приложение или сайт к Formbricks.",
|
||||||
"cache_update_delay_description": "Когда вы обновляете опросы, контакты, действия или другие данные, изменения могут появиться в вашем локальном приложении с Formbricks SDK с задержкой до 1 минуты.",
|
"cache_update_delay_description": "Когда вы обновляете опросы, контакты, действия или другие данные, изменения могут появиться в вашем локальном приложении с Formbricks SDK с задержкой до 1 минуты.",
|
||||||
"cache_update_delay_title": "Изменения отразятся примерно через 1 минуту из-за кэширования",
|
"cache_update_delay_title": "Изменения отразятся примерно через 1 минуту из-за кэширования",
|
||||||
|
"environment_id": "ID вашего рабочего пространства",
|
||||||
|
"environment_id_description": "Этот идентификатор уникально определяет данное рабочее пространство Formbricks.",
|
||||||
"formbricks_sdk_connected": "Formbricks SDK подключён",
|
"formbricks_sdk_connected": "Formbricks SDK подключён",
|
||||||
"formbricks_sdk_not_connected": "Formbricks SDK ещё не подключён.",
|
"formbricks_sdk_not_connected": "Formbricks SDK ещё не подключён.",
|
||||||
"formbricks_sdk_not_connected_description": "Добавьте SDK Formbricks на ваш сайт или в приложение, чтобы подключить его к Formbricks",
|
"formbricks_sdk_not_connected_description": "Добавьте SDK Formbricks на ваш сайт или в приложение, чтобы подключить его к Formbricks",
|
||||||
@@ -1866,12 +1842,10 @@
|
|||||||
"receiving_data": "Получение данных 💃🕺",
|
"receiving_data": "Получение данных 💃🕺",
|
||||||
"recheck": "Проверить ещё раз",
|
"recheck": "Проверить ещё раз",
|
||||||
"sdk_connection_details": "Детали подключения SDK",
|
"sdk_connection_details": "Детали подключения SDK",
|
||||||
"sdk_connection_details_description": "Уникальный ID рабочего пространства и URL подключения SDK для интеграции Formbricks с вашим приложением.",
|
"sdk_connection_details_description": "Уникальный ID вашего рабочего пространства и URL подключения SDK для интеграции Formbricks с вашим приложением.",
|
||||||
"setup_alert_description": "Следуйте этому пошаговому руководству, чтобы подключить приложение или сайт менее чем за 5 минут.",
|
"setup_alert_description": "Следуйте этому пошаговому руководству, чтобы подключить приложение или сайт менее чем за 5 минут.",
|
||||||
"setup_alert_title": "Как подключить",
|
"setup_alert_title": "Как подключить",
|
||||||
"webapp_url": "URL подключения SDK",
|
"webapp_url": "URL подключения SDK"
|
||||||
"workspace_id": "ID вашего рабочего пространства",
|
|
||||||
"workspace_id_description": "Этот ID уникально идентифицирует данное рабочее пространство Formbricks."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Поздравляем!",
|
"congrats": "Поздравляем!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Значение атрибута",
|
"attribute_value_placeholder": "Значение атрибута",
|
||||||
"attributes_msg_attribute_limit_exceeded": "Не удалось создать {count} новых атрибута, так как это превысит максимальное количество классов атрибутов: {limit}. Существующие атрибуты были успешно обновлены.",
|
"attributes_msg_attribute_limit_exceeded": "Не удалось создать {count} новых атрибута, так как это превысит максимальное количество классов атрибутов: {limit}. Существующие атрибуты были успешно обновлены.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (атрибут «{key}» имеет тип данных: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (атрибут «{key}» имеет тип данных: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "Этот адрес электронной почты уже существует для данного рабочего пространства и не был обновлен.",
|
"attributes_msg_email_already_exists": "Этот email уже существует в данной среде и не был обновлён.",
|
||||||
"attributes_msg_email_or_userid_required": "Требуется либо email, либо user ID. Существующие значения были сохранены.",
|
"attributes_msg_email_or_userid_required": "Требуется либо email, либо user ID. Существующие значения были сохранены.",
|
||||||
"attributes_msg_new_attribute_created": "Создан новый атрибут «{key}» с типом «{dataType}»",
|
"attributes_msg_new_attribute_created": "Создан новый атрибут «{key}» с типом «{dataType}»",
|
||||||
"attributes_msg_userid_already_exists": "Этот ID пользователя уже существует для данного рабочего пространства и не был обновлен.",
|
"attributes_msg_userid_already_exists": "Этот user ID уже существует в данной среде и не был обновлён.",
|
||||||
"contact_deleted_successfully": "Контакт успешно удалён",
|
"contact_deleted_successfully": "Контакт успешно удалён",
|
||||||
"contacts_table_refresh": "Обновить контакты",
|
"contacts_table_refresh": "Обновить контакты",
|
||||||
"contacts_table_refresh_success": "Контакты успешно обновлены",
|
"contacts_table_refresh_success": "Контакты успешно обновлены",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Дублирующийся язык или идентификатор языка",
|
"duplicate_language_or_language_id": "Дублирующийся язык или идентификатор языка",
|
||||||
"edit_languages": "Редактировать языки",
|
"edit_languages": "Редактировать языки",
|
||||||
"identifier": "Идентификатор (ISO)",
|
"identifier": "Идентификатор (ISO)",
|
||||||
|
"incomplete_translations": "Неполные переводы",
|
||||||
"language": "Язык",
|
"language": "Язык",
|
||||||
"language_deleted_successfully": "Язык успешно удалён",
|
"language_deleted_successfully": "Язык успешно удалён",
|
||||||
"languages_updated_successfully": "Языки успешно обновлены",
|
"languages_updated_successfully": "Языки успешно обновлены",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Пожалуйста, выберите язык",
|
"please_select_a_language": "Пожалуйста, выберите язык",
|
||||||
"remove_language": "Удалить язык",
|
"remove_language": "Удалить язык",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Пожалуйста, удалите язык из этих опросов, чтобы удалить его из рабочей области.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Пожалуйста, удалите язык из этих опросов, чтобы удалить его из рабочей области.",
|
||||||
"search_items": "Поиск элементов"
|
"search_items": "Поиск элементов",
|
||||||
|
"translate": "Перевести"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Добавить цвет фона",
|
"add_background_color": "Добавить цвет фона",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "Всё готово! Пора создать первый опрос",
|
"all_set_time_to_create_first_survey": "Всё готово! Пора создать первый опрос",
|
||||||
"alphabetical": "По алфавиту",
|
"alphabetical": "По алфавиту",
|
||||||
|
"copy_survey": "Копировать опрос",
|
||||||
|
"copy_survey_description": "Скопировать этот опрос в другое рабочее пространство",
|
||||||
|
"copy_survey_error": "Не удалось скопировать опрос",
|
||||||
"copy_survey_link_to_clipboard": "Скопировать ссылку на опрос в буфер обмена",
|
"copy_survey_link_to_clipboard": "Скопировать ссылку на опрос в буфер обмена",
|
||||||
|
"copy_survey_no_workspaces": "Нет других рабочих пространств, в которые можно скопировать этот опрос.",
|
||||||
|
"copy_survey_partially_success": "Успешно скопировано опросов: {success}, не удалось: {error}.",
|
||||||
|
"copy_survey_success": "Опрос успешно скопирован!",
|
||||||
"delete_survey_and_responses_warning": "Вы уверены, что хотите удалить этот опрос и все его ответы?",
|
"delete_survey_and_responses_warning": "Вы уверены, что хотите удалить этот опрос и все его ответы?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Активировать переводы",
|
"1_choose_the_default_language_for_this_survey": "1. Выберите язык по умолчанию для этого опроса:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Активируйте перевод для выбранных языков:",
|
||||||
"add": "Добавить +",
|
"add": "Добавить +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Добавить задержку или автоматически закрыть опрос",
|
"add_a_delay_or_auto_close_the_survey": "Добавить задержку или автоматически закрыть опрос",
|
||||||
"add_a_four_digit_pin": "Добавить четырёхзначный PIN-код",
|
"add_a_four_digit_pin": "Добавить четырёхзначный PIN-код",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Аудитория",
|
"audience": "Аудитория",
|
||||||
"auto_close_on_inactivity": "Автоматически закрывать при бездействии",
|
"auto_close_on_inactivity": "Автоматически закрывать при бездействии",
|
||||||
"auto_progress_rating_and_nps": "Автоматический переход для вопросов с оценкой и NPS",
|
"auto_progress_rating_and_nps": "Автоматический переход для вопросов с оценкой и NPS",
|
||||||
"auto_progress_rating_and_nps_description": "Автопереход в блоках с одним вопросом. Обязательные вопросы скрывают кнопку «Далее», кроме случаев выбора «Другое».",
|
"auto_progress_rating_and_nps_description": "Автоматически переходить к следующему шагу, когда респонденты выбирают ответ в вопросах с оценкой или NPS. Это применяется только к блокам с одним вопросом. В обязательных вопросах кнопка «Далее» скрыта; в необязательных вопросах она остается видимой для пропуска.",
|
||||||
"auto_save_disabled": "Автосохранение отключено",
|
"auto_save_disabled": "Автосохранение отключено",
|
||||||
"auto_save_disabled_tooltip": "Ваш опрос автоматически сохраняется только в режиме черновика. Это гарантирует, что публичные опросы не будут случайно обновлены.",
|
"auto_save_disabled_tooltip": "Ваш опрос автоматически сохраняется только в режиме черновика. Это гарантирует, что публичные опросы не будут случайно обновлены.",
|
||||||
"auto_save_on": "Автосохранение включено",
|
"auto_save_on": "Автосохранение включено",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "Изменения приведут к несоответствиям",
|
"caution_text": "Изменения приведут к несоответствиям",
|
||||||
"change_anyway": "Всё равно изменить",
|
"change_anyway": "Всё равно изменить",
|
||||||
"change_background": "Изменить фон",
|
"change_background": "Изменить фон",
|
||||||
"change_default": "Изменить по умолчанию",
|
|
||||||
"change_question_type": "Изменить тип вопроса",
|
"change_question_type": "Изменить тип вопроса",
|
||||||
"change_survey_type": "Смена типа опроса влияет на существующий доступ",
|
"change_survey_type": "Смена типа опроса влияет на существующий доступ",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Изменить фон на цвет, изображение или анимацию.",
|
"change_the_background_to_a_color_image_or_animation": "Изменить фон на цвет, изображение или анимацию.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Выберите первый вопрос в вашем блоке",
|
"choose_the_first_question_on_your_block": "Выберите первый вопрос в вашем блоке",
|
||||||
"choose_where_to_run_the_survey": "Выберите, где запускать опрос.",
|
"choose_where_to_run_the_survey": "Выберите, где запускать опрос.",
|
||||||
"city": "Город",
|
"city": "Город",
|
||||||
"clear_close_on_date": "Очистить дату приостановки",
|
|
||||||
"clear_publish_on_date": "Очистить дату публикации",
|
|
||||||
"close_survey_on_date": "Дата приостановки",
|
|
||||||
"close_survey_on_response_limit": "Закрыть опрос при достижении лимита ответов",
|
"close_survey_on_response_limit": "Закрыть опрос при достижении лимита ответов",
|
||||||
"code": "Код",
|
|
||||||
"color": "Цвет",
|
"color": "Цвет",
|
||||||
"column_used_in_logic_error": "Этот столбец используется в логике вопроса {questionIndex}. Пожалуйста, сначала удалите его из логики.",
|
"column_used_in_logic_error": "Этот столбец используется в логике вопроса {questionIndex}. Пожалуйста, сначала удалите его из логики.",
|
||||||
"columns": "Столбцы",
|
"columns": "Столбцы",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "Настроить логотип опроса",
|
"customize_survey_logo": "Настроить логотип опроса",
|
||||||
"darken_or_lighten_background_of_your_choice": "Затемните или осветлите выбранный фон.",
|
"darken_or_lighten_background_of_your_choice": "Затемните или осветлите выбранный фон.",
|
||||||
"days_before_showing_this_survey_again": "или больше дней должно пройти между последним показом опроса и показом этого опроса.",
|
"days_before_showing_this_survey_again": "или больше дней должно пройти между последним показом опроса и показом этого опроса.",
|
||||||
"default_language": "Язык по умолчанию",
|
|
||||||
"delete_anyways": "Удалить в любом случае",
|
"delete_anyways": "Удалить в любом случае",
|
||||||
"delete_block": "Удалить блок",
|
"delete_block": "Удалить блок",
|
||||||
"delete_choice": "Удалить вариант",
|
"delete_choice": "Удалить вариант",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Дублировать вопрос",
|
"duplicate_question": "Дублировать вопрос",
|
||||||
"edit_link": "Редактировать ссылку",
|
"edit_link": "Редактировать ссылку",
|
||||||
"edit_recall": "Редактировать напоминание",
|
"edit_recall": "Редактировать напоминание",
|
||||||
|
"edit_translations": "Редактировать переводы на {lang}",
|
||||||
"element_not_found": "Вопрос не найден",
|
"element_not_found": "Вопрос не найден",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Разрешить респондентам менять язык опроса в любое время. Требуется минимум 2 активных языка.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Разрешить респондентам менять язык опроса в любое время. Требуется минимум 2 активных языка.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "Для защиты от спама используется reCAPTCHA v3, чтобы отфильтровывать спам-ответы.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "Для защиты от спама используется reCAPTCHA v3, чтобы отфильтровывать спам-ответы.",
|
||||||
@@ -3014,12 +2992,10 @@
|
|||||||
"long_answer_toggle_description": "Позволить респондентам писать более длинные, многострочные ответы.",
|
"long_answer_toggle_description": "Позволить респондентам писать более длинные, многострочные ответы.",
|
||||||
"lower_label": "Нижняя метка",
|
"lower_label": "Нижняя метка",
|
||||||
"manage_languages": "Управление языками",
|
"manage_languages": "Управление языками",
|
||||||
"manage_translations": "Управление переводами",
|
|
||||||
"matrix_all_fields": "Все поля",
|
"matrix_all_fields": "Все поля",
|
||||||
"matrix_rows": "Строки",
|
"matrix_rows": "Строки",
|
||||||
"max_file_size": "Максимальный размер файла",
|
"max_file_size": "Максимальный размер файла",
|
||||||
"max_file_size_limit_is": "Ограничение максимального размера файла",
|
"max_file_size_limit_is": "Ограничение максимального размера файла",
|
||||||
"missing_first": "Сначала отсутствующие",
|
|
||||||
"move_question_to_block": "Переместить вопрос в блок",
|
"move_question_to_block": "Переместить вопрос в блок",
|
||||||
"multiply": "Умножить *",
|
"multiply": "Умножить *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Требуется для самостоятельного размещения Cal.com",
|
"needed_for_self_hosted_cal_com_instance": "Требуется для самостоятельного размещения Cal.com",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "Метка кнопки «Далее»",
|
"next_button_label": "Метка кнопки «Далее»",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Скрытых полей пока нет. Добавьте первое ниже.",
|
"no_hidden_fields_yet_add_first_one_below": "Скрытых полей пока нет. Добавьте первое ниже.",
|
||||||
"no_images_found_for": "Изображения не найдены для «{query}»",
|
"no_images_found_for": "Изображения не найдены для «{query}»",
|
||||||
"no_languages_found_add_first_one_to_get_started": "В этом рабочем пространстве не найдено языков опроса. Добавь язык, чтобы начать работу.",
|
"no_languages_found_add_first_one_to_get_started": "Языки не найдены. Добавьте первый, чтобы начать.",
|
||||||
"no_option_found": "Вариант не найден",
|
"no_option_found": "Вариант не найден",
|
||||||
"no_recall_items_found": "Не найдено ни одного элемента для напоминания",
|
"no_recall_items_found": "Не найдено ни одного элемента для напоминания",
|
||||||
"no_variables_yet_add_first_one_below": "Пока нет переменных. Добавьте первую ниже.",
|
"no_variables_yet_add_first_one_below": "Пока нет переменных. Добавьте первую ниже.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Пожалуйста, введите корректный URL (например, https://example.com)",
|
"please_enter_a_valid_url": "Пожалуйста, введите корректный URL (например, https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Пожалуйста, установите триггер опроса",
|
"please_set_a_survey_trigger": "Пожалуйста, установите триггер опроса",
|
||||||
"please_specify": "Пожалуйста, уточните",
|
"please_specify": "Пожалуйста, уточните",
|
||||||
"present_your_survey_in_multiple_languages": "Представьте свой опрос на нескольких языках",
|
|
||||||
"prevent_double_submission": "Предотвратить повторную отправку",
|
"prevent_double_submission": "Предотвратить повторную отправку",
|
||||||
"prevent_double_submission_description": "Разрешить только 1 ответ на один адрес электронной почты",
|
"prevent_double_submission_description": "Разрешить только 1 ответ на один адрес электронной почты",
|
||||||
"progress_saved": "Прогресс сохранён",
|
"progress_saved": "Прогресс сохранён",
|
||||||
"protect_survey_with_pin": "Защитить опрос с помощью PIN-кода",
|
"protect_survey_with_pin": "Защитить опрос с помощью PIN-кода",
|
||||||
"protect_survey_with_pin_description": "Только пользователи, у которых есть PIN-код, могут получить доступ к опросу.",
|
"protect_survey_with_pin_description": "Только пользователи, у которых есть PIN-код, могут получить доступ к опросу.",
|
||||||
"publish": "Опубликовать",
|
"publish": "Опубликовать",
|
||||||
"publish_survey_on_date": "Дата публикации",
|
|
||||||
"question": "Вопрос",
|
"question": "Вопрос",
|
||||||
"question_deleted": "Вопрос удалён.",
|
"question_deleted": "Вопрос удалён.",
|
||||||
"question_duplicated": "Вопрос дублирован.",
|
"question_duplicated": "Вопрос дублирован.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Строки",
|
"rows": "Строки",
|
||||||
"save_and_close": "Сохранить и закрыть",
|
"save_and_close": "Сохранить и закрыть",
|
||||||
"scale": "Шкала",
|
"scale": "Шкала",
|
||||||
"schedule_survey": "Запланировать опрос",
|
|
||||||
"search_for_images": "Поиск изображений",
|
"search_for_images": "Поиск изображений",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "секунд после запуска — опрос будет закрыт, если не будет ответа",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "секунд после запуска — опрос будет закрыт, если не будет ответа",
|
||||||
"seconds_before_showing_the_survey": "секунд до показа опроса.",
|
"seconds_before_showing_the_survey": "секунд до показа опроса.",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 баллов",
|
"seven_points": "7 баллов",
|
||||||
"show_block_settings": "Показать настройки блока",
|
"show_block_settings": "Показать настройки блока",
|
||||||
"show_button": "Показать кнопку",
|
"show_button": "Показать кнопку",
|
||||||
"show_in_order": "Показать по порядку",
|
|
||||||
"show_language_switch": "Показать переключатель языка",
|
"show_language_switch": "Показать переключатель языка",
|
||||||
"show_multiple_times": "Показать ограниченное количество раз",
|
"show_multiple_times": "Показать ограниченное количество раз",
|
||||||
"show_only_once": "Показать только один раз",
|
"show_only_once": "Показать только один раз",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Предпросмотр опроса 👀",
|
"survey_preview": "Предпросмотр опроса 👀",
|
||||||
"survey_styling": "Оформление формы",
|
"survey_styling": "Оформление формы",
|
||||||
"survey_trigger": "Триггер опроса",
|
"survey_trigger": "Триггер опроса",
|
||||||
"survey_will_be_closed_at_midnight_cet": "Опрос будет закрыт в {time} по часовому поясу {timeZone} в выбранную дату",
|
"switch_multi_language_on_to_get_started": "Включите многоязычный режим, чтобы начать 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "Опрос будет опубликован в {time} по часовому поясу {timeZone} в выбранную дату",
|
|
||||||
"target_block_not_found": "Целевой блок не найден",
|
"target_block_not_found": "Целевой блок не найден",
|
||||||
"targeted": "Нацелен",
|
"targeted": "Нацелен",
|
||||||
"ten_points": "10 баллов",
|
"ten_points": "10 баллов",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Показать один раз, даже если не будет ответа.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Показать один раз, даже если не будет ответа.",
|
||||||
"then": "Затем",
|
"then": "Затем",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Это действие удалит все переводы из этого опроса.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Это действие удалит все переводы из этого опроса.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Это удалит данный язык и все его переводы из этого опроса. Это действие нельзя отменить.",
|
|
||||||
"three_points": "3 балла",
|
"three_points": "3 балла",
|
||||||
"times": "раз",
|
"times": "раз",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Чтобы сохранить единое расположение во всех опросах, вы можете",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "Чтобы сохранить единое расположение во всех опросах, вы можете",
|
||||||
"translated": "Переведено",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Запустить опрос при выполнении одного из действий...",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Запустить опрос при выполнении одного из действий...",
|
||||||
"try_lollipop_or_mountain": "Попробуйте «lollipop» или «mountain»...",
|
"try_lollipop_or_mountain": "Попробуйте «lollipop» или «mountain»...",
|
||||||
"type_field_id": "Введите id поля",
|
"type_field_id": "Введите id поля",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Разрешить отвечать только пользователям с реальным email.",
|
"verify_email_before_submission_description": "Разрешить отвечать только пользователям с реальным email.",
|
||||||
"visibility_and_recontact": "Видимость и повторный контакт",
|
"visibility_and_recontact": "Видимость и повторный контакт",
|
||||||
"visibility_and_recontact_description": "Управляйте, когда этот опрос может появляться и как часто он может повторяться.",
|
"visibility_and_recontact_description": "Управляйте, когда этот опрос может появляться и как часто он может повторяться.",
|
||||||
"visible": "Видимый",
|
|
||||||
"wait": "Ожидание",
|
"wait": "Ожидание",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Подождите несколько секунд после срабатывания триггера перед показом опроса",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Подождите несколько секунд после срабатывания триггера перед показом опроса",
|
||||||
"waiting_time_across_surveys": "Период ожидания (между опросами)",
|
"waiting_time_across_surveys": "Период ожидания (между опросами)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Настроить оповещения",
|
"configure_alerts": "Настроить оповещения",
|
||||||
"congrats": "Поздравляем! Ваш опрос опубликован.",
|
"congrats": "Поздравляем! Ваш опрос опубликован.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Подключите ваш сайт или приложение к Formbricks, чтобы начать.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Подключите ваш сайт или приложение к Formbricks, чтобы начать.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% удовлетворены",
|
|
||||||
"csat_satisfied_tooltip": "{percentage}% респондентов дали оценку 4 или 5 (CSAT).",
|
|
||||||
"current_count": "Текущее количество",
|
"current_count": "Текущее количество",
|
||||||
"custom_range": "Произвольный диапазон...",
|
"custom_range": "Произвольный диапазон...",
|
||||||
"delete_all_existing_responses_and_displays": "Удалить все существующие ответы и отображения",
|
"delete_all_existing_responses_and_displays": "Удалить все существующие ответы и отображения",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "Скачивание QR-кода",
|
"downloading_qr_code": "Скачивание QR-кода",
|
||||||
"drop_offs": "Прерывания",
|
"drop_offs": "Прерывания",
|
||||||
"drop_offs_tooltip": "Количество раз, когда опрос был начат, но не завершён.",
|
"drop_offs_tooltip": "Количество раз, когда опрос был начат, но не завершён.",
|
||||||
"effort_score": "Оценка усилий",
|
"failed_to_copy_link": "Не удалось скопировать ссылку",
|
||||||
"filter_added_successfully": "Фильтр успешно добавлен",
|
"filter_added_successfully": "Фильтр успешно добавлен",
|
||||||
"filter_updated_successfully": "Фильтр успешно обновлён",
|
"filter_updated_successfully": "Фильтр успешно обновлён",
|
||||||
"filtered_responses_csv": "Отфильтрованные ответы (CSV)",
|
"filtered_responses_csv": "Отфильтрованные ответы (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Лимит",
|
"limit": "Лимит",
|
||||||
"no_identified_impressions": "Нет показов от идентифицированных контактов",
|
"no_identified_impressions": "Нет показов от идентифицированных контактов",
|
||||||
"no_responses_found": "Ответы не найдены",
|
"no_responses_found": "Ответы не найдены",
|
||||||
"nps_promoters_tooltip": "{percentage}% респондентов дали оценку 9 или 10 (промоутеры NPS).",
|
|
||||||
"other_values_found": "Найдены другие значения",
|
"other_values_found": "Найдены другие значения",
|
||||||
"overall": "В целом",
|
"overall": "В целом",
|
||||||
"promoters": "Сторонники",
|
"promoters": "Сторонники",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "Количество квот, выполненных респондентами.",
|
"quotas_completed_tooltip": "Количество квот, выполненных респондентами.",
|
||||||
"reset_survey": "Сбросить опрос",
|
"reset_survey": "Сбросить опрос",
|
||||||
"reset_survey_warning": "Сброс опроса удаляет все ответы и связанные с этим опросом отображения. Это действие необратимо.",
|
"reset_survey_warning": "Сброс опроса удаляет все ответы и связанные с этим опросом отображения. Это действие необратимо.",
|
||||||
|
"satisfied": "Доволен",
|
||||||
"selected_responses_csv": "Выбранные ответы (CSV)",
|
"selected_responses_csv": "Выбранные ответы (CSV)",
|
||||||
"selected_responses_excel": "Выбранные ответы (Excel)",
|
"selected_responses_excel": "Выбранные ответы (Excel)",
|
||||||
"setup_integrations": "Настроить интеграции",
|
"setup_integrations": "Настроить интеграции",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Количество запусков опроса.",
|
"starts_tooltip": "Количество запусков опроса.",
|
||||||
"survey_reset_successfully": "Опрос успешно сброшен! {responseCount} ответов и {displayCount} показов были удалены.",
|
"survey_reset_successfully": "Опрос успешно сброшен! {responseCount} ответов и {displayCount} показов были удалены.",
|
||||||
"survey_results": "Результаты {surveyName}",
|
"survey_results": "Результаты {surveyName}",
|
||||||
"survey_scheduled_successfully": "Опрос успешно запланирован",
|
|
||||||
"this_month": "В этом месяце",
|
"this_month": "В этом месяце",
|
||||||
"this_quarter": "В этом квартале",
|
"this_quarter": "В этом квартале",
|
||||||
"this_year": "В этом году",
|
"this_year": "В этом году",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "Опрос успешно удалён!",
|
"survey_deleted_successfully": "Опрос успешно удалён!",
|
||||||
"survey_duplicated_successfully": "Опрос успешно продублирован.",
|
"survey_duplicated_successfully": "Опрос успешно продублирован.",
|
||||||
|
"survey_duplication_error": "Не удалось продублировать опрос.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Все каналы",
|
"all_channels": "Все каналы",
|
||||||
"all_industries": "Все отрасли",
|
"all_industries": "Все отрасли",
|
||||||
|
|||||||
+34
-68
@@ -159,7 +159,6 @@
|
|||||||
"change_workspace": "Byt arbetsyta",
|
"change_workspace": "Byt arbetsyta",
|
||||||
"chart": "Diagram",
|
"chart": "Diagram",
|
||||||
"charts": "Diagram",
|
"charts": "Diagram",
|
||||||
"choice_n": "Val {{n}}",
|
|
||||||
"choices": "Val",
|
"choices": "Val",
|
||||||
"choose_organization": "Välj organisation",
|
"choose_organization": "Välj organisation",
|
||||||
"choose_workspace": "Välj arbetsyta",
|
"choose_workspace": "Välj arbetsyta",
|
||||||
@@ -172,9 +171,8 @@
|
|||||||
"close": "Stäng",
|
"close": "Stäng",
|
||||||
"code": "Kod",
|
"code": "Kod",
|
||||||
"collapse_rows": "Dölj rader",
|
"collapse_rows": "Dölj rader",
|
||||||
"column_n": "Kolumn {{n}}",
|
|
||||||
"completed": "Slutförd",
|
"completed": "Slutförd",
|
||||||
"configuration": "Konfigurera",
|
"configuration": "Konfiguration",
|
||||||
"confirm": "Bekräfta",
|
"confirm": "Bekräfta",
|
||||||
"connect": "Anslut",
|
"connect": "Anslut",
|
||||||
"connect_formbricks": "Anslut Formbricks",
|
"connect_formbricks": "Anslut Formbricks",
|
||||||
@@ -232,6 +230,7 @@
|
|||||||
"ending_card": "Avslutningskort",
|
"ending_card": "Avslutningskort",
|
||||||
"enter_url": "Ange URL",
|
"enter_url": "Ange URL",
|
||||||
"enterprise_license": "Företagslicens",
|
"enterprise_license": "Företagslicens",
|
||||||
|
"environment": "Miljö",
|
||||||
"error": "Fel",
|
"error": "Fel",
|
||||||
"error_component_description": "Denna resurs finns inte eller så har du inte de nödvändiga rättigheterna för att komma åt den.",
|
"error_component_description": "Denna resurs finns inte eller så har du inte de nödvändiga rättigheterna för att komma åt den.",
|
||||||
"error_component_title": "Fel vid laddning av resurser",
|
"error_component_title": "Fel vid laddning av resurser",
|
||||||
@@ -243,7 +242,6 @@
|
|||||||
"failed_to_load_organizations": "Misslyckades att ladda organisationer",
|
"failed_to_load_organizations": "Misslyckades att ladda organisationer",
|
||||||
"failed_to_load_workspaces": "Det gick inte att ladda arbetsytor",
|
"failed_to_load_workspaces": "Det gick inte att ladda arbetsytor",
|
||||||
"failed_to_parse_csv": "Det gick inte att tolka CSV-filen",
|
"failed_to_parse_csv": "Det gick inte att tolka CSV-filen",
|
||||||
"field_placeholder": "Platshållare för {{field}}",
|
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"finish": "Slutför",
|
"finish": "Slutför",
|
||||||
"first_name": "Förnamn",
|
"first_name": "Förnamn",
|
||||||
@@ -255,13 +253,11 @@
|
|||||||
"generate": "Generera",
|
"generate": "Generera",
|
||||||
"go_back": "Gå tillbaka",
|
"go_back": "Gå tillbaka",
|
||||||
"go_to_dashboard": "Gå till instrumentpanelen",
|
"go_to_dashboard": "Gå till instrumentpanelen",
|
||||||
"headline": "Rubrik",
|
|
||||||
"hidden": "Dold",
|
"hidden": "Dold",
|
||||||
"hidden_field": "Dolt fält",
|
"hidden_field": "Dolt fält",
|
||||||
"hidden_fields": "Dolda fält",
|
"hidden_fields": "Dolda fält",
|
||||||
"hide": "Dölj",
|
"hide": "Dölj",
|
||||||
"hide_column": "Dölj kolumn",
|
"hide_column": "Dölj kolumn",
|
||||||
"html": "HTML",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"image": "Bild",
|
"image": "Bild",
|
||||||
"images": "Bilder",
|
"images": "Bilder",
|
||||||
@@ -310,6 +306,7 @@
|
|||||||
"more_options": "Fler alternativ",
|
"more_options": "Fler alternativ",
|
||||||
"move_down": "Flytta ner",
|
"move_down": "Flytta ner",
|
||||||
"move_up": "Flytta upp",
|
"move_up": "Flytta upp",
|
||||||
|
"multiple_languages": "Flera språk",
|
||||||
"my_product": "min produkt",
|
"my_product": "min produkt",
|
||||||
"name": "Namn",
|
"name": "Namn",
|
||||||
"new": "Ny",
|
"new": "Ny",
|
||||||
@@ -326,7 +323,6 @@
|
|||||||
"no_result_found": "Inget resultat hittades",
|
"no_result_found": "Inget resultat hittades",
|
||||||
"no_results": "Inga resultat",
|
"no_results": "Inga resultat",
|
||||||
"no_surveys_found": "Inga enkäter hittades.",
|
"no_surveys_found": "Inga enkäter hittades.",
|
||||||
"no_text_found": "Ingen text hittades",
|
|
||||||
"none_of_the_above": "Inget av ovanstående",
|
"none_of_the_above": "Inget av ovanstående",
|
||||||
"not_authenticated": "Du är inte autentiserad för att utföra denna åtgärd.",
|
"not_authenticated": "Du är inte autentiserad för att utföra denna åtgärd.",
|
||||||
"not_authorized": "Ej behörig",
|
"not_authorized": "Ej behörig",
|
||||||
@@ -351,7 +347,7 @@
|
|||||||
"organization_settings": "Organisationsinställningar",
|
"organization_settings": "Organisationsinställningar",
|
||||||
"other": "Annat",
|
"other": "Annat",
|
||||||
"other_filters": "Andra filter",
|
"other_filters": "Andra filter",
|
||||||
"other_placeholder": "Annan platshållare",
|
"others": "Andra",
|
||||||
"overlay_color": "Overlay-färg",
|
"overlay_color": "Overlay-färg",
|
||||||
"overview": "Översikt",
|
"overview": "Översikt",
|
||||||
"password": "Lösenord",
|
"password": "Lösenord",
|
||||||
@@ -369,8 +365,10 @@
|
|||||||
"please_upgrade_your_plan": "Vänligen uppgradera din plan",
|
"please_upgrade_your_plan": "Vänligen uppgradera din plan",
|
||||||
"powered_by_formbricks": "Drivs av Formbricks",
|
"powered_by_formbricks": "Drivs av Formbricks",
|
||||||
"preview": "Förhandsgranska",
|
"preview": "Förhandsgranska",
|
||||||
|
"preview_survey": "Förhandsgranska enkät",
|
||||||
"privacy": "Integritetspolicy",
|
"privacy": "Integritetspolicy",
|
||||||
"product_manager": "Produktchef",
|
"product_manager": "Produktchef",
|
||||||
|
"production": "Produktion",
|
||||||
"profile": "Profil",
|
"profile": "Profil",
|
||||||
"profile_id": "Profil-ID",
|
"profile_id": "Profil-ID",
|
||||||
"progress": "Framsteg",
|
"progress": "Framsteg",
|
||||||
@@ -396,15 +394,12 @@
|
|||||||
"restart": "Starta om",
|
"restart": "Starta om",
|
||||||
"retry": "Försök igen",
|
"retry": "Försök igen",
|
||||||
"role": "Roll",
|
"role": "Roll",
|
||||||
"row_n": "Rad {{n}}",
|
|
||||||
"saas": "SaaS",
|
"saas": "SaaS",
|
||||||
"sales": "Försäljning",
|
"sales": "Försäljning",
|
||||||
"save": "Spara",
|
"save": "Spara",
|
||||||
"save_as_draft": "Spara som utkast",
|
"save_as_draft": "Spara som utkast",
|
||||||
"save_changes": "Spara ändringar",
|
"save_changes": "Spara ändringar",
|
||||||
"save_without_scheduling": "Spara utan schemaläggning",
|
|
||||||
"saving": "Sparar",
|
"saving": "Sparar",
|
||||||
"scheduled": "Schemalagd",
|
|
||||||
"search": "Sök",
|
"search": "Sök",
|
||||||
"search_charts": "Sök diagram...",
|
"search_charts": "Sök diagram...",
|
||||||
"security": "Säkerhet",
|
"security": "Säkerhet",
|
||||||
@@ -438,7 +433,6 @@
|
|||||||
"storage_not_configured": "Fillagring är inte konfigurerad, uppladdningar kommer sannolikt att misslyckas",
|
"storage_not_configured": "Fillagring är inte konfigurerad, uppladdningar kommer sannolikt att misslyckas",
|
||||||
"string": "Text",
|
"string": "Text",
|
||||||
"styling": "Styling",
|
"styling": "Styling",
|
||||||
"subheader": "Underrubrik",
|
|
||||||
"submit": "Skicka",
|
"submit": "Skicka",
|
||||||
"summary": "Sammanfattning",
|
"summary": "Sammanfattning",
|
||||||
"survey": "Enkät",
|
"survey": "Enkät",
|
||||||
@@ -447,7 +441,6 @@
|
|||||||
"survey_languages": "Enkätspråk",
|
"survey_languages": "Enkätspråk",
|
||||||
"survey_live": "Enkät live",
|
"survey_live": "Enkät live",
|
||||||
"survey_paused": "Enkät pausad.",
|
"survey_paused": "Enkät pausad.",
|
||||||
"survey_scheduled": "Undersökning schemalagd.",
|
|
||||||
"survey_type": "Enkättyp",
|
"survey_type": "Enkättyp",
|
||||||
"surveys": "Enkäter",
|
"surveys": "Enkäter",
|
||||||
"table_items_deleted_successfully": "{type} borttagna",
|
"table_items_deleted_successfully": "{type} borttagna",
|
||||||
@@ -510,6 +503,7 @@
|
|||||||
"workspaces": "Arbetsytor",
|
"workspaces": "Arbetsytor",
|
||||||
"years": "år",
|
"years": "år",
|
||||||
"yes": "Ja",
|
"yes": "Ja",
|
||||||
|
"you": "Du",
|
||||||
"you_are_downgraded_to_the_community_edition": "Du har nedgraderats till Community Edition.",
|
"you_are_downgraded_to_the_community_edition": "Du har nedgraderats till Community Edition.",
|
||||||
"you_are_not_authorized_to_perform_this_action": "Du har inte behörighet att utföra denna åtgärd.",
|
"you_are_not_authorized_to_perform_this_action": "Du har inte behörighet att utföra denna åtgärd.",
|
||||||
"you_have_reached_your_limit_of_workspace_limit": "Du har nått din gräns på {workspaceLimit} arbetsytor.",
|
"you_have_reached_your_limit_of_workspace_limit": "Du har nått din gräns på {workspaceLimit} arbetsytor.",
|
||||||
@@ -527,11 +521,11 @@
|
|||||||
"email_footer_text_2": "Formbricks-teamet",
|
"email_footer_text_2": "Formbricks-teamet",
|
||||||
"email_template_text_1": "Detta e-postmeddelande skickades via Formbricks.",
|
"email_template_text_1": "Detta e-postmeddelande skickades via Formbricks.",
|
||||||
"embed_survey_preview_email_didnt_request": "Begärde du inte detta?",
|
"embed_survey_preview_email_didnt_request": "Begärde du inte detta?",
|
||||||
|
"embed_survey_preview_email_environment_id": "Miljö-ID",
|
||||||
"embed_survey_preview_email_fight_spam": "Hjälp oss bekämpa spam och vidarebefordra detta meddelande till hola@formbricks.com",
|
"embed_survey_preview_email_fight_spam": "Hjälp oss bekämpa spam och vidarebefordra detta meddelande till hola@formbricks.com",
|
||||||
"embed_survey_preview_email_heading": "Förhandsgranska e-postinbäddning",
|
"embed_survey_preview_email_heading": "Förhandsgranska e-postinbäddning",
|
||||||
"embed_survey_preview_email_subject": "Formbricks förhandsgranskning av e-postenkät",
|
"embed_survey_preview_email_subject": "Formbricks förhandsgranskning av e-postenkät",
|
||||||
"embed_survey_preview_email_text": "Så här ser kodsnutten ut inbäddad i ett e-postmeddelande:",
|
"embed_survey_preview_email_text": "Så här ser kodsnutten ut inbäddad i ett e-postmeddelande:",
|
||||||
"embed_survey_preview_email_workspace_id": "Arbetsyte-ID",
|
|
||||||
"forgot_password_email_change_password": "Ändra lösenord",
|
"forgot_password_email_change_password": "Ändra lösenord",
|
||||||
"forgot_password_email_did_not_request": "Om du inte begärde detta, vänligen ignorera detta e-postmeddelande.",
|
"forgot_password_email_did_not_request": "Om du inte begärde detta, vänligen ignorera detta e-postmeddelande.",
|
||||||
"forgot_password_email_heading": "Ändra lösenord",
|
"forgot_password_email_heading": "Ändra lösenord",
|
||||||
@@ -634,7 +628,6 @@
|
|||||||
"question_preview": "Frågeförhandsgranskning",
|
"question_preview": "Frågeförhandsgranskning",
|
||||||
"response_already_received": "Vi har redan fått ett svar för denna e-postadress.",
|
"response_already_received": "Vi har redan fått ett svar för denna e-postadress.",
|
||||||
"response_submitted": "Ett svar kopplat till denna enkät och kontakt finns redan",
|
"response_submitted": "Ett svar kopplat till denna enkät och kontakt finns redan",
|
||||||
"scheduled": "Den här undersökningen är schemalagd att publiceras snart.",
|
|
||||||
"survey_already_answered_heading": "Enkäten har redan besvarats.",
|
"survey_already_answered_heading": "Enkäten har redan besvarats.",
|
||||||
"survey_already_answered_subheading": "Du kan endast använda denna länk en gång.",
|
"survey_already_answered_subheading": "Du kan endast använda denna länk en gång.",
|
||||||
"survey_sent_to": "Enkät skickad till {email}",
|
"survey_sent_to": "Enkät skickad till {email}",
|
||||||
@@ -774,10 +767,6 @@
|
|||||||
"career_development_survey_question_6_choice_6": "Annat",
|
"career_development_survey_question_6_choice_6": "Annat",
|
||||||
"career_development_survey_question_6_headline": "Vilket av följande beskriver bäst din nuvarande jobbnivå?",
|
"career_development_survey_question_6_headline": "Vilket av följande beskriver bäst din nuvarande jobbnivå?",
|
||||||
"career_development_survey_question_6_subheader": "Vänligen välj ett av följande",
|
"career_development_survey_question_6_subheader": "Vänligen välj ett av följande",
|
||||||
"ces": "Kundansträngning (CES)",
|
|
||||||
"ces_description": "Mät Customer Effort Score (1-5 eller 1-7)",
|
|
||||||
"ces_lower_label": "Mycket svårt",
|
|
||||||
"ces_upper_label": "Mycket lätt",
|
|
||||||
"cess_survey_name": "CES-enkät",
|
"cess_survey_name": "CES-enkät",
|
||||||
"cess_survey_question_1_headline": "$[workspaceName] gör det enkelt för mig att [LÄGG TILL MÅL]",
|
"cess_survey_question_1_headline": "$[workspaceName] gör det enkelt för mig att [LÄGG TILL MÅL]",
|
||||||
"cess_survey_question_1_lower_label": "Håller inte alls med",
|
"cess_survey_question_1_lower_label": "Håller inte alls med",
|
||||||
@@ -841,9 +830,7 @@
|
|||||||
"consent_description": "Be om godkännande av villkor, bestämmelser eller dataanvändning",
|
"consent_description": "Be om godkännande av villkor, bestämmelser eller dataanvändning",
|
||||||
"contact_info": "Kontaktinfo",
|
"contact_info": "Kontaktinfo",
|
||||||
"contact_info_description": "Fråga efter namn, efternamn, e-post, telefonnummer och företag tillsammans",
|
"contact_info_description": "Fråga efter namn, efternamn, e-post, telefonnummer och företag tillsammans",
|
||||||
"csat": "Kundnöjdhet (CSAT)",
|
"csat_description": "Mät kundnöjdhetspoängen för din produkt eller tjänst.",
|
||||||
"csat_description": "Mät Customer Satisfaction Score (1-5)",
|
|
||||||
"csat_lower_label": "Mycket missnöjd",
|
|
||||||
"csat_name": "Kundnöjdhetspoäng (CSAT)",
|
"csat_name": "Kundnöjdhetspoäng (CSAT)",
|
||||||
"csat_question_10_headline": "Har du några andra kommentarer, frågor eller funderingar?",
|
"csat_question_10_headline": "Har du några andra kommentarer, frågor eller funderingar?",
|
||||||
"csat_question_10_placeholder": "Skriv ditt svar här...",
|
"csat_question_10_placeholder": "Skriv ditt svar här...",
|
||||||
@@ -919,7 +906,6 @@
|
|||||||
"csat_survey_question_2_placeholder": "Skriv ditt svar här...",
|
"csat_survey_question_2_placeholder": "Skriv ditt svar här...",
|
||||||
"csat_survey_question_3_headline": "Aj, förlåt! Finns det något vi kan göra för att förbättra din upplevelse?",
|
"csat_survey_question_3_headline": "Aj, förlåt! Finns det något vi kan göra för att förbättra din upplevelse?",
|
||||||
"csat_survey_question_3_placeholder": "Skriv ditt svar här...",
|
"csat_survey_question_3_placeholder": "Skriv ditt svar här...",
|
||||||
"csat_upper_label": "Mycket nöjd",
|
|
||||||
"cta_description": "Visa information och uppmana användare att vidta en specifik åtgärd",
|
"cta_description": "Visa information och uppmana användare att vidta en specifik åtgärd",
|
||||||
"custom_survey_description": "Skapa en enkät utan mall.",
|
"custom_survey_description": "Skapa en enkät utan mall.",
|
||||||
"custom_survey_name": "Börja från början",
|
"custom_survey_name": "Börja från början",
|
||||||
@@ -1085,11 +1071,6 @@
|
|||||||
"gauge_feature_satisfaction_question_2_headline": "Vad är en sak vi kunde göra bättre?",
|
"gauge_feature_satisfaction_question_2_headline": "Vad är en sak vi kunde göra bättre?",
|
||||||
"identify_customer_goals_description": "Förstå bättre om din kommunikation skapar rätt förväntningar på värdet din produkt ger.",
|
"identify_customer_goals_description": "Förstå bättre om din kommunikation skapar rätt förväntningar på värdet din produkt ger.",
|
||||||
"identify_customer_goals_name": "Identifiera kundmål",
|
"identify_customer_goals_name": "Identifiera kundmål",
|
||||||
"identify_customer_goals_question_1_choice_1": "Förstå min användarbas på djupet",
|
|
||||||
"identify_customer_goals_question_1_choice_2": "Identifiera möjligheter för merförsäljning",
|
|
||||||
"identify_customer_goals_question_1_choice_3": "Bygga bästa möjliga produkt",
|
|
||||||
"identify_customer_goals_question_1_choice_4": "Härska över världen för att få alla att äta brysselkål till frukost",
|
|
||||||
"identify_customer_goals_question_1_headline": "Vad är ditt främsta mål med att använda $[workspaceName]?",
|
|
||||||
"identify_sign_up_barriers_description": "Erbjud en rabatt för att samla insikter om registreringshinder.",
|
"identify_sign_up_barriers_description": "Erbjud en rabatt för att samla insikter om registreringshinder.",
|
||||||
"identify_sign_up_barriers_name": "Identifiera registreringshinder",
|
"identify_sign_up_barriers_name": "Identifiera registreringshinder",
|
||||||
"identify_sign_up_barriers_question_1_button_label": "Få 10% rabatt",
|
"identify_sign_up_barriers_question_1_button_label": "Få 10% rabatt",
|
||||||
@@ -1164,8 +1145,6 @@
|
|||||||
"improve_trial_conversion_question_1_subheader": "Hjälp oss förstå dig bättre:",
|
"improve_trial_conversion_question_1_subheader": "Hjälp oss förstå dig bättre:",
|
||||||
"improve_trial_conversion_question_2_button_label": "Nästa",
|
"improve_trial_conversion_question_2_button_label": "Nästa",
|
||||||
"improve_trial_conversion_question_2_headline": "Tråkigt att höra. Vad var det största problemet med att använda $[workspaceName]?",
|
"improve_trial_conversion_question_2_headline": "Tråkigt att höra. Vad var det största problemet med att använda $[workspaceName]?",
|
||||||
"improve_trial_conversion_question_3_button_label": "Nästa",
|
|
||||||
"improve_trial_conversion_question_3_headline": "Vad förväntade du dig att $[workspaceName] skulle göra?",
|
|
||||||
"improve_trial_conversion_question_4_button_label": "Få 20% rabatt",
|
"improve_trial_conversion_question_4_button_label": "Få 20% rabatt",
|
||||||
"improve_trial_conversion_question_4_headline": "Tråkigt att höra! Få 20% rabatt första året.",
|
"improve_trial_conversion_question_4_headline": "Tråkigt att höra! Få 20% rabatt första året.",
|
||||||
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Vi erbjuder dig gärna 20% rabatt på en årsplan.</span></p>",
|
"improve_trial_conversion_question_4_html": "<p class=\"fb-editor-paragraph\" dir=\"ltr\"><span>Vi erbjuder dig gärna 20% rabatt på en årsplan.</span></p>",
|
||||||
@@ -1636,6 +1615,7 @@
|
|||||||
"this_action_will_be_triggered_when_the_page_is_loaded": "Denna åtgärd utlöses när sidan laddas.",
|
"this_action_will_be_triggered_when_the_page_is_loaded": "Denna åtgärd utlöses när sidan laddas.",
|
||||||
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Denna åtgärd utlöses när användaren scrollar 50% av sidan.",
|
"this_action_will_be_triggered_when_the_user_scrolls_50_percent_of_the_page": "Denna åtgärd utlöses när användaren scrollar 50% av sidan.",
|
||||||
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Denna åtgärd utlöses när användaren försöker lämna sidan.",
|
"this_action_will_be_triggered_when_the_user_tries_to_leave_the_page": "Denna åtgärd utlöses när användaren försöker lämna sidan.",
|
||||||
|
"this_is_a_code_action_please_make_changes_in_your_code_base": "Detta är en kodåtgärd. Vänligen gör ändringar i din kodbas.",
|
||||||
"time_in_seconds": "Tid i sekunder",
|
"time_in_seconds": "Tid i sekunder",
|
||||||
"time_in_seconds_placeholder": "t.ex. 10",
|
"time_in_seconds_placeholder": "t.ex. 10",
|
||||||
"time_in_seconds_with_unit": "{seconds}s",
|
"time_in_seconds_with_unit": "{seconds}s",
|
||||||
@@ -1838,19 +1818,13 @@
|
|||||||
"api_key_updated": "API-nyckel uppdaterad",
|
"api_key_updated": "API-nyckel uppdaterad",
|
||||||
"delete_api_key_confirmation": "Alla applikationer som använder denna nyckel kommer inte längre att kunna komma åt din Formbricks-data.",
|
"delete_api_key_confirmation": "Alla applikationer som använder denna nyckel kommer inte längre att kunna komma åt din Formbricks-data.",
|
||||||
"duplicate_access": "Duplicerad arbetsyteåtkomst är inte tillåten",
|
"duplicate_access": "Duplicerad arbetsyteåtkomst är inte tillåten",
|
||||||
"duplicate_directory_access": "Duplicerad åtkomst till feedbackpostkatalog är inte tillåten",
|
|
||||||
"feedback_record_directory_access": "Åtkomst till feedbackpostkatalog",
|
|
||||||
"no_api_keys_yet": "Du har inga API-nycklar ännu",
|
"no_api_keys_yet": "Du har inga API-nycklar ännu",
|
||||||
"no_directory_permissions_found": "Inga behörigheter för feedbackpostkatalog hittades",
|
"no_env_permissions_found": "Inga miljöbehörigheter hittades",
|
||||||
"no_workspace_permissions_found": "Inga behörigheter för arbetsytan hittades",
|
|
||||||
"organization_access": "Organisationsåtkomst",
|
"organization_access": "Organisationsåtkomst",
|
||||||
"organization_access_description": "Välj läs- eller skrivbehörighet för resurser på organisationsnivå.",
|
"organization_access_description": "Välj läs- eller skrivbehörighet för resurser på organisationsnivå.",
|
||||||
"permissions": "Behörigheter",
|
"permissions": "Behörigheter",
|
||||||
"secret": "Hemlig",
|
"secret": "Hemlig",
|
||||||
"unable_to_copy_api_key": "Kunde inte kopiera API-nyckel",
|
|
||||||
"unable_to_delete_api_key": "Det gick inte att radera API-nyckeln",
|
"unable_to_delete_api_key": "Det gick inte att radera API-nyckeln",
|
||||||
"unknown_directory": "Okänd katalog",
|
|
||||||
"unknown_workspace": "Okänd arbetsyta",
|
|
||||||
"workspace_access": "Arbetsyteåtkomst"
|
"workspace_access": "Arbetsyteåtkomst"
|
||||||
},
|
},
|
||||||
"app-connection": {
|
"app-connection": {
|
||||||
@@ -1858,6 +1832,8 @@
|
|||||||
"app_connection_description": "Anslut din app eller webbplats till Formbricks.",
|
"app_connection_description": "Anslut din app eller webbplats till Formbricks.",
|
||||||
"cache_update_delay_description": "När du gör uppdateringar av undersökningar, kontakter, åtgärder eller annan data kan det ta upp till 1 minut innan ändringarna syns i din lokala app som kör Formbricks SDK.",
|
"cache_update_delay_description": "När du gör uppdateringar av undersökningar, kontakter, åtgärder eller annan data kan det ta upp till 1 minut innan ändringarna syns i din lokala app som kör Formbricks SDK.",
|
||||||
"cache_update_delay_title": "Ändringar syns efter cirka 1 minut på grund av cachelagring",
|
"cache_update_delay_title": "Ändringar syns efter cirka 1 minut på grund av cachelagring",
|
||||||
|
"environment_id": "Ditt arbetsyte-ID",
|
||||||
|
"environment_id_description": "Detta ID identifierar unikt den här Formbricks-arbetsytan.",
|
||||||
"formbricks_sdk_connected": "Formbricks SDK är anslutet",
|
"formbricks_sdk_connected": "Formbricks SDK är anslutet",
|
||||||
"formbricks_sdk_not_connected": "Formbricks SDK är ännu inte anslutet.",
|
"formbricks_sdk_not_connected": "Formbricks SDK är ännu inte anslutet.",
|
||||||
"formbricks_sdk_not_connected_description": "Lägg till Formbricks SDK på din webbplats eller i din app för att ansluta den till Formbricks",
|
"formbricks_sdk_not_connected_description": "Lägg till Formbricks SDK på din webbplats eller i din app för att ansluta den till Formbricks",
|
||||||
@@ -1869,9 +1845,7 @@
|
|||||||
"sdk_connection_details_description": "Ditt unika arbetsyte-ID och SDK-anslutnings-URL för att integrera Formbricks med din applikation.",
|
"sdk_connection_details_description": "Ditt unika arbetsyte-ID och SDK-anslutnings-URL för att integrera Formbricks med din applikation.",
|
||||||
"setup_alert_description": "Följ denna steg-för-steg-guide för att ansluta din app eller webbplats på under 5 minuter.",
|
"setup_alert_description": "Följ denna steg-för-steg-guide för att ansluta din app eller webbplats på under 5 minuter.",
|
||||||
"setup_alert_title": "Så här ansluter du",
|
"setup_alert_title": "Så här ansluter du",
|
||||||
"webapp_url": "SDK-anslutnings-URL",
|
"webapp_url": "SDK-anslutnings-URL"
|
||||||
"workspace_id": "Ditt arbetsyte-ID",
|
|
||||||
"workspace_id_description": "Detta ID identifierar unikt denna Formbricks-arbetsyta."
|
|
||||||
},
|
},
|
||||||
"connect": {
|
"connect": {
|
||||||
"congrats": "Grattis!",
|
"congrats": "Grattis!",
|
||||||
@@ -1902,10 +1876,10 @@
|
|||||||
"attribute_value_placeholder": "Attributvärde",
|
"attribute_value_placeholder": "Attributvärde",
|
||||||
"attributes_msg_attribute_limit_exceeded": "Kunde inte skapa {count} nya attribut eftersom det skulle överskrida maxgränsen på {limit} attributklasser. Befintliga attribut uppdaterades utan problem.",
|
"attributes_msg_attribute_limit_exceeded": "Kunde inte skapa {count} nya attribut eftersom det skulle överskrida maxgränsen på {limit} attributklasser. Befintliga attribut uppdaterades utan problem.",
|
||||||
"attributes_msg_attribute_type_validation_error": "{error} (attributet ”{key}” har datatyp: {dataType})",
|
"attributes_msg_attribute_type_validation_error": "{error} (attributet ”{key}” har datatyp: {dataType})",
|
||||||
"attributes_msg_email_already_exists": "E-postadressen finns redan för denna arbetsyta och uppdaterades inte.",
|
"attributes_msg_email_already_exists": "E-postadressen finns redan för den här miljön och uppdaterades inte.",
|
||||||
"attributes_msg_email_or_userid_required": "Antingen e-post eller användar-ID krävs. De befintliga värdena har bevarats.",
|
"attributes_msg_email_or_userid_required": "Antingen e-post eller användar-ID krävs. De befintliga värdena har bevarats.",
|
||||||
"attributes_msg_new_attribute_created": "Nytt attribut ”{key}” med typen ”{dataType}” har skapats",
|
"attributes_msg_new_attribute_created": "Nytt attribut ”{key}” med typen ”{dataType}” har skapats",
|
||||||
"attributes_msg_userid_already_exists": "Användar-ID:t finns redan för denna arbetsyta och uppdaterades inte.",
|
"attributes_msg_userid_already_exists": "Användar-ID finns redan för denna miljö och uppdaterades inte.",
|
||||||
"contact_deleted_successfully": "Kontakt borttagen",
|
"contact_deleted_successfully": "Kontakt borttagen",
|
||||||
"contacts_table_refresh": "Uppdatera kontakter",
|
"contacts_table_refresh": "Uppdatera kontakter",
|
||||||
"contacts_table_refresh_success": "Kontakter uppdaterade",
|
"contacts_table_refresh_success": "Kontakter uppdaterade",
|
||||||
@@ -2166,6 +2140,7 @@
|
|||||||
"duplicate_language_or_language_id": "Duplicerat språk eller språk-ID",
|
"duplicate_language_or_language_id": "Duplicerat språk eller språk-ID",
|
||||||
"edit_languages": "Redigera språk",
|
"edit_languages": "Redigera språk",
|
||||||
"identifier": "Identifierare (ISO)",
|
"identifier": "Identifierare (ISO)",
|
||||||
|
"incomplete_translations": "Ofullständiga översättningar",
|
||||||
"language": "Språk",
|
"language": "Språk",
|
||||||
"language_deleted_successfully": "Språket har tagits bort",
|
"language_deleted_successfully": "Språket har tagits bort",
|
||||||
"languages_updated_successfully": "Språken har uppdaterats",
|
"languages_updated_successfully": "Språken har uppdaterats",
|
||||||
@@ -2175,7 +2150,8 @@
|
|||||||
"please_select_a_language": "Vänligen välj ett språk",
|
"please_select_a_language": "Vänligen välj ett språk",
|
||||||
"remove_language": "Ta bort språk",
|
"remove_language": "Ta bort språk",
|
||||||
"remove_language_from_surveys_to_remove_it_from_workspace": "Ta bort språket från dessa enkäter för att kunna ta bort det från arbetsytan.",
|
"remove_language_from_surveys_to_remove_it_from_workspace": "Ta bort språket från dessa enkäter för att kunna ta bort det från arbetsytan.",
|
||||||
"search_items": "Sök objekt"
|
"search_items": "Sök objekt",
|
||||||
|
"translate": "Översätt"
|
||||||
},
|
},
|
||||||
"look": {
|
"look": {
|
||||||
"add_background_color": "Lägg till bakgrundsfärg",
|
"add_background_color": "Lägg till bakgrundsfärg",
|
||||||
@@ -2718,10 +2694,17 @@
|
|||||||
"surveys": {
|
"surveys": {
|
||||||
"all_set_time_to_create_first_survey": "Allt klart! Dags att skapa din första enkät",
|
"all_set_time_to_create_first_survey": "Allt klart! Dags att skapa din första enkät",
|
||||||
"alphabetical": "Alfabetisk",
|
"alphabetical": "Alfabetisk",
|
||||||
|
"copy_survey": "Kopiera enkät",
|
||||||
|
"copy_survey_description": "Kopiera den här undersökningen till en annan arbetsyta",
|
||||||
|
"copy_survey_error": "Misslyckades med att kopiera enkät",
|
||||||
"copy_survey_link_to_clipboard": "Kopiera enkätlänk till urklipp",
|
"copy_survey_link_to_clipboard": "Kopiera enkätlänk till urklipp",
|
||||||
|
"copy_survey_no_workspaces": "Det finns inga andra arbetsytor att kopiera den här undersökningen till.",
|
||||||
|
"copy_survey_partially_success": "{success} enkäter kopierade, {error} misslyckades.",
|
||||||
|
"copy_survey_success": "Enkät kopierad!",
|
||||||
"delete_survey_and_responses_warning": "Är du säker på att du vill ta bort denna enkät och alla dess svar?",
|
"delete_survey_and_responses_warning": "Är du säker på att du vill ta bort denna enkät och alla dess svar?",
|
||||||
"edit": {
|
"edit": {
|
||||||
"activate_translations": "Aktivera översättningar",
|
"1_choose_the_default_language_for_this_survey": "1. Välj standardspråk för denna enkät:",
|
||||||
|
"2_activate_translation_for_specific_languages": "2. Aktivera översättning för specifika språk:",
|
||||||
"add": "Lägg till +",
|
"add": "Lägg till +",
|
||||||
"add_a_delay_or_auto_close_the_survey": "Lägg till fördröjning eller stäng enkäten automatiskt",
|
"add_a_delay_or_auto_close_the_survey": "Lägg till fördröjning eller stäng enkäten automatiskt",
|
||||||
"add_a_four_digit_pin": "Lägg till en fyrsiffrig PIN",
|
"add_a_four_digit_pin": "Lägg till en fyrsiffrig PIN",
|
||||||
@@ -2771,7 +2754,7 @@
|
|||||||
"audience": "Målgrupp",
|
"audience": "Målgrupp",
|
||||||
"auto_close_on_inactivity": "Stäng automatiskt vid inaktivitet",
|
"auto_close_on_inactivity": "Stäng automatiskt vid inaktivitet",
|
||||||
"auto_progress_rating_and_nps": "Gå vidare automatiskt vid betygs- och NPS-frågor",
|
"auto_progress_rating_and_nps": "Gå vidare automatiskt vid betygs- och NPS-frågor",
|
||||||
"auto_progress_rating_and_nps_description": "Gå automatiskt vidare i frågeblock med en enda fråga. Obligatoriska frågor döljer Nästa-knappen, förutom när \"Annat\" är valt.",
|
"auto_progress_rating_and_nps_description": "Gå automatiskt vidare när respondenter väljer ett svar på betygs- eller NPS-frågor. Detta gäller endast block med en enda fråga. Obligatoriska frågor döljer Nästa-knappen; valfria frågor visar den fortfarande för att kunna hoppas över.",
|
||||||
"auto_save_disabled": "Automatisk sparning inaktiverad",
|
"auto_save_disabled": "Automatisk sparning inaktiverad",
|
||||||
"auto_save_disabled_tooltip": "Din enkät sparas endast automatiskt när den är ett utkast. Detta säkerställer att publika enkäter inte uppdateras oavsiktligt.",
|
"auto_save_disabled_tooltip": "Din enkät sparas endast automatiskt när den är ett utkast. Detta säkerställer att publika enkäter inte uppdateras oavsiktligt.",
|
||||||
"auto_save_on": "Automatisk sparning på",
|
"auto_save_on": "Automatisk sparning på",
|
||||||
@@ -2817,7 +2800,6 @@
|
|||||||
"caution_text": "Ändringar kommer att leda till inkonsekvenser",
|
"caution_text": "Ändringar kommer att leda till inkonsekvenser",
|
||||||
"change_anyway": "Ändra ändå",
|
"change_anyway": "Ändra ändå",
|
||||||
"change_background": "Ändra bakgrund",
|
"change_background": "Ändra bakgrund",
|
||||||
"change_default": "Ändra standard",
|
|
||||||
"change_question_type": "Ändra frågetyp",
|
"change_question_type": "Ändra frågetyp",
|
||||||
"change_survey_type": "Byte av enkättyp påverkar befintlig åtkomst",
|
"change_survey_type": "Byte av enkättyp påverkar befintlig åtkomst",
|
||||||
"change_the_background_to_a_color_image_or_animation": "Ändra bakgrunden till en färg, bild eller animering.",
|
"change_the_background_to_a_color_image_or_animation": "Ändra bakgrunden till en färg, bild eller animering.",
|
||||||
@@ -2829,11 +2811,7 @@
|
|||||||
"choose_the_first_question_on_your_block": "Välj den första frågan i ditt block",
|
"choose_the_first_question_on_your_block": "Välj den första frågan i ditt block",
|
||||||
"choose_where_to_run_the_survey": "Välj var enkäten ska köras.",
|
"choose_where_to_run_the_survey": "Välj var enkäten ska köras.",
|
||||||
"city": "Stad",
|
"city": "Stad",
|
||||||
"clear_close_on_date": "Rensa pausdatum",
|
|
||||||
"clear_publish_on_date": "Rensa publiceringsdatum",
|
|
||||||
"close_survey_on_date": "Pausdatum",
|
|
||||||
"close_survey_on_response_limit": "Stäng enkät vid svarsgräns",
|
"close_survey_on_response_limit": "Stäng enkät vid svarsgräns",
|
||||||
"code": "Kod",
|
|
||||||
"color": "Färg",
|
"color": "Färg",
|
||||||
"column_used_in_logic_error": "Denna kolumn används i logiken för fråga {questionIndex}. Vänligen ta bort den från logiken först.",
|
"column_used_in_logic_error": "Denna kolumn används i logiken för fråga {questionIndex}. Vänligen ta bort den från logiken först.",
|
||||||
"columns": "Kolumner",
|
"columns": "Kolumner",
|
||||||
@@ -2858,7 +2836,6 @@
|
|||||||
"customize_survey_logo": "Anpassa undersökningens logotyp",
|
"customize_survey_logo": "Anpassa undersökningens logotyp",
|
||||||
"darken_or_lighten_background_of_your_choice": "Gör bakgrunden mörkare eller ljusare efter eget val.",
|
"darken_or_lighten_background_of_your_choice": "Gör bakgrunden mörkare eller ljusare efter eget val.",
|
||||||
"days_before_showing_this_survey_again": "eller fler dagar måste gå mellan den senaste visade enkäten och att visa denna enkät.",
|
"days_before_showing_this_survey_again": "eller fler dagar måste gå mellan den senaste visade enkäten och att visa denna enkät.",
|
||||||
"default_language": "Standardspråk",
|
|
||||||
"delete_anyways": "Ta bort ändå",
|
"delete_anyways": "Ta bort ändå",
|
||||||
"delete_block": "Ta bort block",
|
"delete_block": "Ta bort block",
|
||||||
"delete_choice": "Ta bort val",
|
"delete_choice": "Ta bort val",
|
||||||
@@ -2878,6 +2855,7 @@
|
|||||||
"duplicate_question": "Duplicera fråga",
|
"duplicate_question": "Duplicera fråga",
|
||||||
"edit_link": "Redigera länk",
|
"edit_link": "Redigera länk",
|
||||||
"edit_recall": "Redigera återkallning",
|
"edit_recall": "Redigera återkallning",
|
||||||
|
"edit_translations": "Redigera {lang} översättningar",
|
||||||
"element_not_found": "Fråga hittades inte",
|
"element_not_found": "Fråga hittades inte",
|
||||||
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Tillåt respondenter att byta språk när som helst. Kräver minst 2 aktiva språk.",
|
"enable_participants_to_switch_the_survey_language_at_any_point_during_the_survey": "Tillåt respondenter att byta språk när som helst. Kräver minst 2 aktiva språk.",
|
||||||
"enable_recaptcha_to_protect_your_survey_from_spam": "Spamskydd använder reCAPTCHA v3 för att filtrera bort spam-svar.",
|
"enable_recaptcha_to_protect_your_survey_from_spam": "Spamskydd använder reCAPTCHA v3 för att filtrera bort spam-svar.",
|
||||||
@@ -3014,12 +2992,10 @@
|
|||||||
"long_answer_toggle_description": "Tillåt respondenter att skriva längre svar på flera rader.",
|
"long_answer_toggle_description": "Tillåt respondenter att skriva längre svar på flera rader.",
|
||||||
"lower_label": "Lägre etikett",
|
"lower_label": "Lägre etikett",
|
||||||
"manage_languages": "Hantera språk",
|
"manage_languages": "Hantera språk",
|
||||||
"manage_translations": "Hantera översättningar",
|
|
||||||
"matrix_all_fields": "Alla fält",
|
"matrix_all_fields": "Alla fält",
|
||||||
"matrix_rows": "Rader",
|
"matrix_rows": "Rader",
|
||||||
"max_file_size": "Max filstorlek",
|
"max_file_size": "Max filstorlek",
|
||||||
"max_file_size_limit_is": "Maximal filstorleksgräns är",
|
"max_file_size_limit_is": "Maximal filstorleksgräns är",
|
||||||
"missing_first": "Saknade först",
|
|
||||||
"move_question_to_block": "Flytta fråga till block",
|
"move_question_to_block": "Flytta fråga till block",
|
||||||
"multiply": "Multiplicera *",
|
"multiply": "Multiplicera *",
|
||||||
"needed_for_self_hosted_cal_com_instance": "Behövs för en självhostad Cal.com-instans",
|
"needed_for_self_hosted_cal_com_instance": "Behövs för en självhostad Cal.com-instans",
|
||||||
@@ -3027,7 +3003,7 @@
|
|||||||
"next_button_label": "\"Nästa\"-knappetikett",
|
"next_button_label": "\"Nästa\"-knappetikett",
|
||||||
"no_hidden_fields_yet_add_first_one_below": "Inga dolda fält ännu. Lägg till det första nedan.",
|
"no_hidden_fields_yet_add_first_one_below": "Inga dolda fält ännu. Lägg till det första nedan.",
|
||||||
"no_images_found_for": "Inga bilder hittades för ''{query}\"",
|
"no_images_found_for": "Inga bilder hittades för ''{query}\"",
|
||||||
"no_languages_found_add_first_one_to_get_started": "Inga undersökningsspråk hittades i den här arbetsytan. Vänligen lägg till ett för att komma igång.",
|
"no_languages_found_add_first_one_to_get_started": "Inga språk hittades. Lägg till det första för att komma igång.",
|
||||||
"no_option_found": "Inget alternativ hittat",
|
"no_option_found": "Inget alternativ hittat",
|
||||||
"no_recall_items_found": "Inga återkallningsobjekt hittades",
|
"no_recall_items_found": "Inga återkallningsobjekt hittades",
|
||||||
"no_variables_yet_add_first_one_below": "Inga variabler ännu. Lägg till den första nedan.",
|
"no_variables_yet_add_first_one_below": "Inga variabler ännu. Lägg till den första nedan.",
|
||||||
@@ -3054,14 +3030,12 @@
|
|||||||
"please_enter_a_valid_url": "Vänligen ange en giltig URL (t.ex. https://example.com)",
|
"please_enter_a_valid_url": "Vänligen ange en giltig URL (t.ex. https://example.com)",
|
||||||
"please_set_a_survey_trigger": "Vänligen ställ in en enkätutlösare",
|
"please_set_a_survey_trigger": "Vänligen ställ in en enkätutlösare",
|
||||||
"please_specify": "Vänligen specificera",
|
"please_specify": "Vänligen specificera",
|
||||||
"present_your_survey_in_multiple_languages": "Presentera din enkät på flera språk",
|
|
||||||
"prevent_double_submission": "Förhindra dubbelinskickning",
|
"prevent_double_submission": "Förhindra dubbelinskickning",
|
||||||
"prevent_double_submission_description": "Tillåt endast 1 svar per e-postadress",
|
"prevent_double_submission_description": "Tillåt endast 1 svar per e-postadress",
|
||||||
"progress_saved": "Framsteg sparade",
|
"progress_saved": "Framsteg sparade",
|
||||||
"protect_survey_with_pin": "Skydda enkäten med en PIN",
|
"protect_survey_with_pin": "Skydda enkäten med en PIN",
|
||||||
"protect_survey_with_pin_description": "Endast användare som har PIN-koden kan komma åt enkäten.",
|
"protect_survey_with_pin_description": "Endast användare som har PIN-koden kan komma åt enkäten.",
|
||||||
"publish": "Publicera",
|
"publish": "Publicera",
|
||||||
"publish_survey_on_date": "Publiceringsdatum",
|
|
||||||
"question": "Fråga",
|
"question": "Fråga",
|
||||||
"question_deleted": "Fråga borttagen.",
|
"question_deleted": "Fråga borttagen.",
|
||||||
"question_duplicated": "Fråga duplicerad.",
|
"question_duplicated": "Fråga duplicerad.",
|
||||||
@@ -3132,7 +3106,6 @@
|
|||||||
"rows": "Rader",
|
"rows": "Rader",
|
||||||
"save_and_close": "Spara och stäng",
|
"save_and_close": "Spara och stäng",
|
||||||
"scale": "Skala",
|
"scale": "Skala",
|
||||||
"schedule_survey": "Schemalägg undersökning",
|
|
||||||
"search_for_images": "Sök efter bilder",
|
"search_for_images": "Sök efter bilder",
|
||||||
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "sekunder efter utlösning stängs enkäten om inget svar",
|
"seconds_after_trigger_the_survey_will_be_closed_if_no_response": "sekunder efter utlösning stängs enkäten om inget svar",
|
||||||
"seconds_before_showing_the_survey": "sekunder innan enkäten visas.",
|
"seconds_before_showing_the_survey": "sekunder innan enkäten visas.",
|
||||||
@@ -3148,7 +3121,6 @@
|
|||||||
"seven_points": "7 poäng",
|
"seven_points": "7 poäng",
|
||||||
"show_block_settings": "Visa blockinställningar",
|
"show_block_settings": "Visa blockinställningar",
|
||||||
"show_button": "Visa knapp",
|
"show_button": "Visa knapp",
|
||||||
"show_in_order": "Visa i ordning",
|
|
||||||
"show_language_switch": "Visa språkväxlare",
|
"show_language_switch": "Visa språkväxlare",
|
||||||
"show_multiple_times": "Visa ett begränsat antal gånger",
|
"show_multiple_times": "Visa ett begränsat antal gånger",
|
||||||
"show_only_once": "Visa endast en gång",
|
"show_only_once": "Visa endast en gång",
|
||||||
@@ -3180,8 +3152,7 @@
|
|||||||
"survey_preview": "Enkätförhandsgranskning 👀",
|
"survey_preview": "Enkätförhandsgranskning 👀",
|
||||||
"survey_styling": "Formulärstil",
|
"survey_styling": "Formulärstil",
|
||||||
"survey_trigger": "Enkätutlösare",
|
"survey_trigger": "Enkätutlösare",
|
||||||
"survey_will_be_closed_at_midnight_cet": "Enkäten stängs klockan {time} i tidszonen {timeZone} på det valda datumet",
|
"switch_multi_language_on_to_get_started": "Slå på flerspråkighet för att komma igång 👉",
|
||||||
"survey_will_be_published_at_midnight_cet": "Enkäten publiceras klockan {time} i tidszonen {timeZone} på det valda datumet",
|
|
||||||
"target_block_not_found": "Målblock hittades inte",
|
"target_block_not_found": "Målblock hittades inte",
|
||||||
"targeted": "Riktad",
|
"targeted": "Riktad",
|
||||||
"ten_points": "10 poäng",
|
"ten_points": "10 poäng",
|
||||||
@@ -3189,11 +3160,9 @@
|
|||||||
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Visa en enda gång, även om de inte svarar.",
|
"the_survey_will_be_shown_once_even_if_person_doesnt_respond": "Visa en enda gång, även om de inte svarar.",
|
||||||
"then": "Sedan",
|
"then": "Sedan",
|
||||||
"this_action_will_remove_all_the_translations_from_this_survey": "Denna åtgärd kommer att ta bort alla översättningar från denna enkät.",
|
"this_action_will_remove_all_the_translations_from_this_survey": "Denna åtgärd kommer att ta bort alla översättningar från denna enkät.",
|
||||||
"this_will_remove_the_language_and_all_its_translations": "Detta tar bort språket och alla dess översättningar från denna enkät. Denna åtgärd kan inte ångras.",
|
|
||||||
"three_points": "3 poäng",
|
"three_points": "3 poäng",
|
||||||
"times": "gånger",
|
"times": "gånger",
|
||||||
"to_keep_the_placement_over_all_surveys_consistent_you_can": "För att hålla placeringen konsekvent över alla enkäter kan du",
|
"to_keep_the_placement_over_all_surveys_consistent_you_can": "För att hålla placeringen konsekvent över alla enkäter kan du",
|
||||||
"translated": "Översatt",
|
|
||||||
"trigger_survey_when_one_of_the_actions_is_fired": "Utlös enkät när en av åtgärderna aktiveras...",
|
"trigger_survey_when_one_of_the_actions_is_fired": "Utlös enkät när en av åtgärderna aktiveras...",
|
||||||
"try_lollipop_or_mountain": "Prova 'lollipop' eller 'mountain'...",
|
"try_lollipop_or_mountain": "Prova 'lollipop' eller 'mountain'...",
|
||||||
"type_field_id": "Skriv fält-ID",
|
"type_field_id": "Skriv fält-ID",
|
||||||
@@ -3268,7 +3237,6 @@
|
|||||||
"verify_email_before_submission_description": "Låt endast personer med en riktig e-post svara.",
|
"verify_email_before_submission_description": "Låt endast personer med en riktig e-post svara.",
|
||||||
"visibility_and_recontact": "Synlighet och återkontakt",
|
"visibility_and_recontact": "Synlighet och återkontakt",
|
||||||
"visibility_and_recontact_description": "Kontrollera när denna enkät kan visas och hur ofta den kan visas igen.",
|
"visibility_and_recontact_description": "Kontrollera när denna enkät kan visas och hur ofta den kan visas igen.",
|
||||||
"visible": "Synlig",
|
|
||||||
"wait": "Vänta",
|
"wait": "Vänta",
|
||||||
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Vänta några sekunder efter utlösningen innan enkäten visas",
|
"wait_a_few_seconds_after_the_trigger_before_showing_the_survey": "Vänta några sekunder efter utlösningen innan enkäten visas",
|
||||||
"waiting_time_across_surveys": "Väntetid (mellan enkäter)",
|
"waiting_time_across_surveys": "Väntetid (mellan enkäter)",
|
||||||
@@ -3470,8 +3438,6 @@
|
|||||||
"configure_alerts": "Konfigurera aviseringar",
|
"configure_alerts": "Konfigurera aviseringar",
|
||||||
"congrats": "Grattis! Din enkät är live.",
|
"congrats": "Grattis! Din enkät är live.",
|
||||||
"connect_your_website_or_app_with_formbricks_to_get_started": "Anslut din webbplats eller app med Formbricks för att komma igång.",
|
"connect_your_website_or_app_with_formbricks_to_get_started": "Anslut din webbplats eller app med Formbricks för att komma igång.",
|
||||||
"csat_satisfied": "CSAT: {percentage}% Nöjda",
|
|
||||||
"csat_satisfied_tooltip": "{percentage}% av respondenterna gav ett betyg på 4 eller 5 (CSAT).",
|
|
||||||
"current_count": "Nuvarande antal",
|
"current_count": "Nuvarande antal",
|
||||||
"custom_range": "Anpassat intervall...",
|
"custom_range": "Anpassat intervall...",
|
||||||
"delete_all_existing_responses_and_displays": "Ta bort alla befintliga svar och visningar",
|
"delete_all_existing_responses_and_displays": "Ta bort alla befintliga svar och visningar",
|
||||||
@@ -3479,7 +3445,7 @@
|
|||||||
"downloading_qr_code": "Laddar ner QR-kod",
|
"downloading_qr_code": "Laddar ner QR-kod",
|
||||||
"drop_offs": "Avhopp",
|
"drop_offs": "Avhopp",
|
||||||
"drop_offs_tooltip": "Antal gånger enkäten har startats men inte slutförts.",
|
"drop_offs_tooltip": "Antal gånger enkäten har startats men inte slutförts.",
|
||||||
"effort_score": "Ansträngningspoäng",
|
"failed_to_copy_link": "Misslyckades med att kopiera länk",
|
||||||
"filter_added_successfully": "Filter tillagt",
|
"filter_added_successfully": "Filter tillagt",
|
||||||
"filter_updated_successfully": "Filter uppdaterat",
|
"filter_updated_successfully": "Filter uppdaterat",
|
||||||
"filtered_responses_csv": "Filtrerade svar (CSV)",
|
"filtered_responses_csv": "Filtrerade svar (CSV)",
|
||||||
@@ -3531,7 +3497,6 @@
|
|||||||
"limit": "Gräns",
|
"limit": "Gräns",
|
||||||
"no_identified_impressions": "Inga visningar från identifierade kontakter",
|
"no_identified_impressions": "Inga visningar från identifierade kontakter",
|
||||||
"no_responses_found": "Inga svar hittades",
|
"no_responses_found": "Inga svar hittades",
|
||||||
"nps_promoters_tooltip": "{percentage}% av respondenterna gav ett betyg på 9 eller 10 (NPS-ambassadörer).",
|
|
||||||
"other_values_found": "Andra värden hittades",
|
"other_values_found": "Andra värden hittades",
|
||||||
"overall": "Övergripande",
|
"overall": "Övergripande",
|
||||||
"promoters": "Ambassadörer",
|
"promoters": "Ambassadörer",
|
||||||
@@ -3544,6 +3509,7 @@
|
|||||||
"quotas_completed_tooltip": "Antalet kvoter som slutförts av respondenterna.",
|
"quotas_completed_tooltip": "Antalet kvoter som slutförts av respondenterna.",
|
||||||
"reset_survey": "Återställ enkät",
|
"reset_survey": "Återställ enkät",
|
||||||
"reset_survey_warning": "Att återställa en enkät tar bort alla svar och visningar kopplade till denna enkät. Detta kan inte ångras.",
|
"reset_survey_warning": "Att återställa en enkät tar bort alla svar och visningar kopplade till denna enkät. Detta kan inte ångras.",
|
||||||
|
"satisfied": "Nöjd",
|
||||||
"selected_responses_csv": "Valda svar (CSV)",
|
"selected_responses_csv": "Valda svar (CSV)",
|
||||||
"selected_responses_excel": "Valda svar (Excel)",
|
"selected_responses_excel": "Valda svar (Excel)",
|
||||||
"setup_integrations": "Konfigurera integrationer",
|
"setup_integrations": "Konfigurera integrationer",
|
||||||
@@ -3553,7 +3519,6 @@
|
|||||||
"starts_tooltip": "Antal gånger enkäten har startats.",
|
"starts_tooltip": "Antal gånger enkäten har startats.",
|
||||||
"survey_reset_successfully": "Enkät återställd! {responseCount} svar och {displayCount} visningar togs bort.",
|
"survey_reset_successfully": "Enkät återställd! {responseCount} svar och {displayCount} visningar togs bort.",
|
||||||
"survey_results": "Resultat för {surveyName}",
|
"survey_results": "Resultat för {surveyName}",
|
||||||
"survey_scheduled_successfully": "Undersökning schemalagd",
|
|
||||||
"this_month": "Denna månad",
|
"this_month": "Denna månad",
|
||||||
"this_quarter": "Detta kvartal",
|
"this_quarter": "Detta kvartal",
|
||||||
"this_year": "Detta år",
|
"this_year": "Detta år",
|
||||||
@@ -3568,6 +3533,7 @@
|
|||||||
},
|
},
|
||||||
"survey_deleted_successfully": "Enkät borttagen!",
|
"survey_deleted_successfully": "Enkät borttagen!",
|
||||||
"survey_duplicated_successfully": "Enkät duplicerad.",
|
"survey_duplicated_successfully": "Enkät duplicerad.",
|
||||||
|
"survey_duplication_error": "Misslyckades med att duplicera enkäten.",
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_channels": "Alla kanaler",
|
"all_channels": "Alla kanaler",
|
||||||
"all_industries": "Alla branscher",
|
"all_industries": "Alla branscher",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user